diff options
Diffstat (limited to 'arch/arm/mach-ep93xx')
39 files changed, 3535 insertions, 1650 deletions
diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig index 56bddcef690..bec570ae649 100644 --- a/arch/arm/mach-ep93xx/Kconfig +++ b/arch/arm/mach-ep93xx/Kconfig @@ -2,6 +2,12 @@ if ARCH_EP93XX menu "Cirrus EP93xx Implementation Options" +config EP93XX_SOC_COMMON + bool + default y + select SOC_BUS + select LEDS_GPIO_REGISTER + config CRUNCH bool "Support for MaverickCrunch" help @@ -9,104 +15,185 @@ config CRUNCH comment "EP93xx Platforms" +choice + prompt "EP93xx first SDRAM bank selection" + default EP93XX_SDCE3_SYNC_PHYS_OFFSET + +config EP93XX_SDCE3_SYNC_PHYS_OFFSET + bool "0x00000000 - SDCE3/SyncBoot" + help + Select this option if you want support for EP93xx boards with the + first SDRAM bank at 0x00000000. + +config EP93XX_SDCE0_PHYS_OFFSET + bool "0xc0000000 - SDCEO" + help + Select this option if you want support for EP93xx boards with the + first SDRAM bank at 0xc0000000. + +config EP93XX_SDCE1_PHYS_OFFSET + bool "0xd0000000 - SDCE1" + help + Select this option if you want support for EP93xx boards with the + first SDRAM bank at 0xd0000000. + +config EP93XX_SDCE2_PHYS_OFFSET + bool "0xe0000000 - SDCE2" + help + Select this option if you want support for EP93xx boards with the + first SDRAM bank at 0xe0000000. + +config EP93XX_SDCE3_ASYNC_PHYS_OFFSET + bool "0xf0000000 - SDCE3/AsyncBoot" + help + Select this option if you want support for EP93xx boards with the + first SDRAM bank at 0xf0000000. + +endchoice + config MACH_ADSSPHERE bool "Support ADS Sphere" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET help Say 'Y' here if you want your kernel to support the ADS Sphere board. +config MACH_EDB93XX + bool + +config MACH_EDB9301 + bool "Support Cirrus Logic EDB9301" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX + help + Say 'Y' here if you want your kernel to support the Cirrus + Logic EDB9301 Evaluation Board. + config MACH_EDB9302 bool "Support Cirrus Logic EDB9302" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9302 Evaluation Board. config MACH_EDB9302A bool "Support Cirrus Logic EDB9302A" + depends on EP93XX_SDCE0_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9302A Evaluation Board. config MACH_EDB9307 bool "Support Cirrus Logic EDB9307" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9307 Evaluation Board. config MACH_EDB9307A bool "Support Cirrus Logic EDB9307A" + depends on EP93XX_SDCE0_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9307A Evaluation Board. config MACH_EDB9312 bool "Support Cirrus Logic EDB9312" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9312 Evaluation Board. config MACH_EDB9315 bool "Support Cirrus Logic EDB9315" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9315 Evaluation Board. config MACH_EDB9315A bool "Support Cirrus Logic EDB9315A" + depends on EP93XX_SDCE0_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9315A Evaluation Board. config MACH_GESBC9312 + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET bool "Support Glomation GESBC-9312-sx" help Say 'Y' here if you want your kernel to support the Glomation GESBC-9312-sx board. config MACH_MICRO9 - bool - default n + bool config MACH_MICRO9H - bool "Support Contec Hypercontrol Micro9-H" - select MACH_MICRO9 - help - Say 'Y' here if you want your kernel to support the - Contec Hypercontrol Micro9-H board. + bool "Support Contec Micro9-High" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Micro9-High board. config MACH_MICRO9M - bool "Support Contec Hypercontrol Micro9-M" - select MACH_MICRO9 - help - Say 'Y' here if you want your kernel to support the - Contec Hypercontrol Micro9-M board. + bool "Support Contec Micro9-Mid" + depends on EP93XX_SDCE3_ASYNC_PHYS_OFFSET + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Micro9-Mid board. config MACH_MICRO9L - bool "Support Contec Hypercontrol Micro9-L" - select MACH_MICRO9 - help - Say 'Y' here if you want your kernel to support the - Contec Hypercontrol Micro9-L board. + bool "Support Contec Micro9-Lite" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Micro9-Lite board. + +config MACH_MICRO9S + bool "Support Contec Micro9-Slim" + depends on EP93XX_SDCE3_ASYNC_PHYS_OFFSET + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Micro9-Slim board. + +config MACH_SIM_ONE + bool "Support Simplemachines Sim.One board" + depends on EP93XX_SDCE0_PHYS_OFFSET + help + Say 'Y' here if you want your kernel to support the + Simplemachines Sim.One board. + +config MACH_SNAPPER_CL15 + bool "Support Bluewater Systems Snapper CL15 Module" + depends on EP93XX_SDCE0_PHYS_OFFSET + help + Say 'Y' here if you want your kernel to support the Bluewater + Systems Snapper CL15 Module. config MACH_TS72XX bool "Support Technologic Systems TS-72xx SBC" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET help Say 'Y' here if you want your kernel to support the Technologic Systems TS-72xx board. -choice - prompt "Select a UART for early kernel messages" - -config EP93XX_EARLY_UART1 - bool "UART1" - -config EP93XX_EARLY_UART2 - bool "UART2" - -config EP93XX_EARLY_UART3 - bool "UART3" - -endchoice +config MACH_VISION_EP9307 + bool "Support Vision Engraving Systems EP9307 SoM" + depends on EP93XX_SDCE0_PHYS_OFFSET + help + Say 'Y' here if you want your kernel to support the + Vision Engraving Systems EP9307 SoM. endmenu diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile index 944e42d5164..0dc51f9462d 100644 --- a/arch/arm/mach-ep93xx/Makefile +++ b/arch/arm/mach-ep93xx/Makefile @@ -1,19 +1,21 @@ # # Makefile for the linux kernel. # -obj-y := core.o clock.o gpio.o +obj-y := core.o clock.o obj-m := obj-n := obj- := +obj-$(CONFIG_EP93XX_DMA) += dma.o + +obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o +AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 + obj-$(CONFIG_MACH_ADSSPHERE) += adssphere.o -obj-$(CONFIG_MACH_EDB9302) += edb9302.o -obj-$(CONFIG_MACH_EDB9302A) += edb9302a.o -obj-$(CONFIG_MACH_EDB9307) += edb9307.o -obj-$(CONFIG_MACH_EDB9307A) += edb9307a.o -obj-$(CONFIG_MACH_EDB9312) += edb9312.o -obj-$(CONFIG_MACH_EDB9315) += edb9315.o -obj-$(CONFIG_MACH_EDB9315A) += edb9315a.o +obj-$(CONFIG_MACH_EDB93XX) += edb93xx.o obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o obj-$(CONFIG_MACH_MICRO9) += micro9.o +obj-$(CONFIG_MACH_SIM_ONE) += simone.o +obj-$(CONFIG_MACH_SNAPPER_CL15) += snappercl15.o obj-$(CONFIG_MACH_TS72XX) += ts72xx.o +obj-$(CONFIG_MACH_VISION_EP9307)+= vision_ep9307.o diff --git a/arch/arm/mach-ep93xx/Makefile.boot b/arch/arm/mach-ep93xx/Makefile.boot index d5561ad15ba..d3113a71cb4 100644 --- a/arch/arm/mach-ep93xx/Makefile.boot +++ b/arch/arm/mach-ep93xx/Makefile.boot @@ -1,2 +1,14 @@ - zreladdr-y := 0x00008000 -params_phys-y := 0x00000100 + zreladdr-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) += 0x00008000 +params_phys-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) := 0x00000100 + + zreladdr-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) += 0xc0008000 +params_phys-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) := 0xc0000100 + + zreladdr-$(CONFIG_EP93XX_SDCE1_PHYS_OFFSET) += 0xd0008000 +params_phys-$(CONFIG_EP93XX_SDCE1_PHYS_OFFSET) := 0xd0000100 + + zreladdr-$(CONFIG_EP93XX_SDCE2_PHYS_OFFSET) += 0xe0008000 +params_phys-$(CONFIG_EP93XX_SDCE2_PHYS_OFFSET) := 0xe0000100 + + zreladdr-$(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET) += 0xf0008000 +params_phys-$(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET) := 0xf0000100 diff --git a/arch/arm/mach-ep93xx/adssphere.c b/arch/arm/mach-ep93xx/adssphere.c index 3fbd9b0fbe2..bda6c3a5c92 100644 --- a/arch/arm/mach-ep93xx/adssphere.c +++ b/arch/arm/mach-ep93xx/adssphere.c @@ -12,57 +12,34 @@ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> #include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> +#include <linux/sizes.h> + #include <mach/hardware.h> + #include <asm/mach-types.h> #include <asm/mach/arch.h> -static struct physmap_flash_data adssphere_flash_data = { - .width = 4, -}; - -static struct resource adssphere_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device adssphere_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &adssphere_flash_data, - }, - .num_resources = 1, - .resource = &adssphere_flash_resource, -}; +#include "soc.h" -static struct ep93xx_eth_data adssphere_eth_data = { +static struct ep93xx_eth_data __initdata adssphere_eth_data = { .phy_id = 1, }; static void __init adssphere_init_machine(void) { ep93xx_init_devices(); - platform_device_register(&adssphere_flash); - + ep93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M); ep93xx_register_eth(&adssphere_eth_data, 1); } MACHINE_START(ADSSPHERE, "ADS Sphere board") /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + .atag_offset = 0x100, .map_io = ep93xx_map_io, .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, + .init_time = ep93xx_timer_init, .init_machine = adssphere_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 96049283a10..39ef3b61391 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -10,83 +10,471 @@ * your option) any later version. */ +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/module.h> #include <linux/string.h> #include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/clkdev.h> -#include <asm/clkdev.h> -#include <asm/div64.h> #include <mach/hardware.h> +#include <asm/div64.h> + +#include "soc.h" + struct clk { + struct clk *parent; unsigned long rate; int users; - u32 enable_reg; + int sw_locked; + void __iomem *enable_reg; u32 enable_mask; + + unsigned long (*get_rate)(struct clk *clk); + int (*set_rate)(struct clk *clk, unsigned long rate); }; -static struct clk clk_uart = { - .rate = 14745600, + +static unsigned long get_uart_rate(struct clk *clk); + +static int set_keytchclk_rate(struct clk *clk, unsigned long rate); +static int set_div_rate(struct clk *clk, unsigned long rate); +static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate); +static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate); + +static struct clk clk_xtali = { + .rate = EP93XX_EXT_CLK_RATE, +}; +static struct clk clk_uart1 = { + .parent = &clk_xtali, + .sw_locked = 1, + .enable_reg = EP93XX_SYSCON_DEVCFG, + .enable_mask = EP93XX_SYSCON_DEVCFG_U1EN, + .get_rate = get_uart_rate, +}; +static struct clk clk_uart2 = { + .parent = &clk_xtali, + .sw_locked = 1, + .enable_reg = EP93XX_SYSCON_DEVCFG, + .enable_mask = EP93XX_SYSCON_DEVCFG_U2EN, + .get_rate = get_uart_rate, +}; +static struct clk clk_uart3 = { + .parent = &clk_xtali, + .sw_locked = 1, + .enable_reg = EP93XX_SYSCON_DEVCFG, + .enable_mask = EP93XX_SYSCON_DEVCFG_U3EN, + .get_rate = get_uart_rate, +}; +static struct clk clk_pll1 = { + .parent = &clk_xtali, +}; +static struct clk clk_f = { + .parent = &clk_pll1, +}; +static struct clk clk_h = { + .parent = &clk_pll1, +}; +static struct clk clk_p = { + .parent = &clk_pll1, +}; +static struct clk clk_pll2 = { + .parent = &clk_xtali, }; -static struct clk clk_pll1; -static struct clk clk_f; -static struct clk clk_h; -static struct clk clk_p; -static struct clk clk_pll2; static struct clk clk_usb_host = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, + .parent = &clk_pll2, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN, +}; +static struct clk clk_keypad = { + .parent = &clk_xtali, + .sw_locked = 1, + .enable_reg = EP93XX_SYSCON_KEYTCHCLKDIV, + .enable_mask = EP93XX_SYSCON_KEYTCHCLKDIV_KEN, + .set_rate = set_keytchclk_rate, +}; +static struct clk clk_spi = { + .parent = &clk_xtali, + .rate = EP93XX_EXT_CLK_RATE, +}; +static struct clk clk_pwm = { + .parent = &clk_xtali, + .rate = EP93XX_EXT_CLK_RATE, +}; + +static struct clk clk_video = { + .sw_locked = 1, + .enable_reg = EP93XX_SYSCON_VIDCLKDIV, + .enable_mask = EP93XX_SYSCON_CLKDIV_ENABLE, + .set_rate = set_div_rate, +}; + +static struct clk clk_i2s_mclk = { + .sw_locked = 1, + .enable_reg = EP93XX_SYSCON_I2SCLKDIV, + .enable_mask = EP93XX_SYSCON_CLKDIV_ENABLE, + .set_rate = set_div_rate, +}; + +static struct clk clk_i2s_sclk = { + .sw_locked = 1, + .parent = &clk_i2s_mclk, + .enable_reg = EP93XX_SYSCON_I2SCLKDIV, + .enable_mask = EP93XX_SYSCON_I2SCLKDIV_SENA, + .set_rate = set_i2s_sclk_rate, +}; + +static struct clk clk_i2s_lrclk = { + .sw_locked = 1, + .parent = &clk_i2s_sclk, + .enable_reg = EP93XX_SYSCON_I2SCLKDIV, + .enable_mask = EP93XX_SYSCON_I2SCLKDIV_SENA, + .set_rate = set_i2s_lrclk_rate, +}; + +/* DMA Clocks */ +static struct clk clk_m2p0 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P0, +}; +static struct clk clk_m2p1 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P1, +}; +static struct clk clk_m2p2 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P2, +}; +static struct clk clk_m2p3 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P3, +}; +static struct clk clk_m2p4 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P4, +}; +static struct clk clk_m2p5 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P5, +}; +static struct clk clk_m2p6 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P6, +}; +static struct clk clk_m2p7 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P7, +}; +static struct clk clk_m2p8 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P8, +}; +static struct clk clk_m2p9 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P9, +}; +static struct clk clk_m2m0 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M0, +}; +static struct clk clk_m2m1 = { + .parent = &clk_h, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M1, }; #define INIT_CK(dev,con,ck) \ { .dev_id = dev, .con_id = con, .clk = ck } static struct clk_lookup clocks[] = { - INIT_CK("apb:uart1", NULL, &clk_uart), - INIT_CK("apb:uart2", NULL, &clk_uart), - INIT_CK("apb:uart3", NULL, &clk_uart), - INIT_CK(NULL, "pll1", &clk_pll1), - INIT_CK(NULL, "fclk", &clk_f), - INIT_CK(NULL, "hclk", &clk_h), - INIT_CK(NULL, "pclk", &clk_p), - INIT_CK(NULL, "pll2", &clk_pll2), - INIT_CK(NULL, "usb_host", &clk_usb_host), + INIT_CK(NULL, "xtali", &clk_xtali), + INIT_CK("apb:uart1", NULL, &clk_uart1), + INIT_CK("apb:uart2", NULL, &clk_uart2), + INIT_CK("apb:uart3", NULL, &clk_uart3), + INIT_CK(NULL, "pll1", &clk_pll1), + INIT_CK(NULL, "fclk", &clk_f), + INIT_CK(NULL, "hclk", &clk_h), + INIT_CK(NULL, "apb_pclk", &clk_p), + INIT_CK(NULL, "pll2", &clk_pll2), + INIT_CK("ohci-platform", NULL, &clk_usb_host), + INIT_CK("ep93xx-keypad", NULL, &clk_keypad), + INIT_CK("ep93xx-fb", NULL, &clk_video), + INIT_CK("ep93xx-spi.0", NULL, &clk_spi), + INIT_CK("ep93xx-i2s", "mclk", &clk_i2s_mclk), + INIT_CK("ep93xx-i2s", "sclk", &clk_i2s_sclk), + INIT_CK("ep93xx-i2s", "lrclk", &clk_i2s_lrclk), + INIT_CK(NULL, "pwm_clk", &clk_pwm), + INIT_CK(NULL, "m2p0", &clk_m2p0), + INIT_CK(NULL, "m2p1", &clk_m2p1), + INIT_CK(NULL, "m2p2", &clk_m2p2), + INIT_CK(NULL, "m2p3", &clk_m2p3), + INIT_CK(NULL, "m2p4", &clk_m2p4), + INIT_CK(NULL, "m2p5", &clk_m2p5), + INIT_CK(NULL, "m2p6", &clk_m2p6), + INIT_CK(NULL, "m2p7", &clk_m2p7), + INIT_CK(NULL, "m2p8", &clk_m2p8), + INIT_CK(NULL, "m2p9", &clk_m2p9), + INIT_CK(NULL, "m2m0", &clk_m2m0), + INIT_CK(NULL, "m2m1", &clk_m2m1), }; +static DEFINE_SPINLOCK(clk_lock); -int clk_enable(struct clk *clk) +static void __clk_enable(struct clk *clk) { - if (!clk->users++ && clk->enable_reg) { - u32 value; + if (!clk->users++) { + if (clk->parent) + __clk_enable(clk->parent); + + if (clk->enable_reg) { + u32 v; - value = __raw_readl(clk->enable_reg); - __raw_writel(value | clk->enable_mask, clk->enable_reg); + v = __raw_readl(clk->enable_reg); + v |= clk->enable_mask; + if (clk->sw_locked) + ep93xx_syscon_swlocked_write(v, clk->enable_reg); + else + __raw_writel(v, clk->enable_reg); + } } +} + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + if (!clk) + return -EINVAL; + + spin_lock_irqsave(&clk_lock, flags); + __clk_enable(clk); + spin_unlock_irqrestore(&clk_lock, flags); return 0; } EXPORT_SYMBOL(clk_enable); -void clk_disable(struct clk *clk) +static void __clk_disable(struct clk *clk) { - if (!--clk->users && clk->enable_reg) { - u32 value; + if (!--clk->users) { + if (clk->enable_reg) { + u32 v; - value = __raw_readl(clk->enable_reg); - __raw_writel(value & ~clk->enable_mask, clk->enable_reg); + v = __raw_readl(clk->enable_reg); + v &= ~clk->enable_mask; + if (clk->sw_locked) + ep93xx_syscon_swlocked_write(v, clk->enable_reg); + else + __raw_writel(v, clk->enable_reg); + } + + if (clk->parent) + __clk_disable(clk->parent); } } + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + if (!clk) + return; + + spin_lock_irqsave(&clk_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(&clk_lock, flags); +} EXPORT_SYMBOL(clk_disable); +static unsigned long get_uart_rate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent); + u32 value; + + value = __raw_readl(EP93XX_SYSCON_PWRCNT); + if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD) + return rate; + else + return rate / 2; +} + unsigned long clk_get_rate(struct clk *clk) { + if (clk->get_rate) + return clk->get_rate(clk); + return clk->rate; } EXPORT_SYMBOL(clk_get_rate); +static int set_keytchclk_rate(struct clk *clk, unsigned long rate) +{ + u32 val; + u32 div_bit; + + val = __raw_readl(clk->enable_reg); + + /* + * The Key Matrix and ADC clocks are configured using the same + * System Controller register. The clock used will be either + * 1/4 or 1/16 the external clock rate depending on the + * EP93XX_SYSCON_KEYTCHCLKDIV_KDIV/EP93XX_SYSCON_KEYTCHCLKDIV_ADIV + * bit being set or cleared. + */ + div_bit = clk->enable_mask >> 15; + + if (rate == EP93XX_KEYTCHCLK_DIV4) + val |= div_bit; + else if (rate == EP93XX_KEYTCHCLK_DIV16) + val &= ~div_bit; + else + return -EINVAL; + + ep93xx_syscon_swlocked_write(val, clk->enable_reg); + clk->rate = rate; + return 0; +} + +static int calc_clk_div(struct clk *clk, unsigned long rate, + int *psel, int *esel, int *pdiv, int *div) +{ + struct clk *mclk; + unsigned long max_rate, actual_rate, mclk_rate, rate_err = -1; + int i, found = 0, __div = 0, __pdiv = 0; + + /* Don't exceed the maximum rate */ + max_rate = max3(clk_pll1.rate / 4, clk_pll2.rate / 4, clk_xtali.rate / 4); + rate = min(rate, max_rate); + + /* + * Try the two pll's and the external clock + * Because the valid predividers are 2, 2.5 and 3, we multiply + * all the clocks by 2 to avoid floating point math. + * + * This is based on the algorithm in the ep93xx raster guide: + * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf + * + */ + for (i = 0; i < 3; i++) { + if (i == 0) + mclk = &clk_xtali; + else if (i == 1) + mclk = &clk_pll1; + else + mclk = &clk_pll2; + mclk_rate = mclk->rate * 2; + + /* Try each predivider value */ + for (__pdiv = 4; __pdiv <= 6; __pdiv++) { + __div = mclk_rate / (rate * __pdiv); + if (__div < 2 || __div > 127) + continue; + + actual_rate = mclk_rate / (__pdiv * __div); + + if (!found || abs(actual_rate - rate) < rate_err) { + *pdiv = __pdiv - 3; + *div = __div; + *psel = (i == 2); + *esel = (i != 0); + clk->parent = mclk; + clk->rate = actual_rate; + rate_err = abs(actual_rate - rate); + found = 1; + } + } + } + + if (!found) + return -EINVAL; + + return 0; +} + +static int set_div_rate(struct clk *clk, unsigned long rate) +{ + int err, psel = 0, esel = 0, pdiv = 0, div = 0; + u32 val; + + err = calc_clk_div(clk, rate, &psel, &esel, &pdiv, &div); + if (err) + return err; + + /* Clear the esel, psel, pdiv and div bits */ + val = __raw_readl(clk->enable_reg); + val &= ~0x7fff; + + /* Set the new esel, psel, pdiv and div bits for the new clock rate */ + val |= (esel ? EP93XX_SYSCON_CLKDIV_ESEL : 0) | + (psel ? EP93XX_SYSCON_CLKDIV_PSEL : 0) | + (pdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | div; + ep93xx_syscon_swlocked_write(val, clk->enable_reg); + return 0; +} + +static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate) +{ + unsigned val = __raw_readl(clk->enable_reg); + + if (rate == clk_i2s_mclk.rate / 2) + ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV, + clk->enable_reg); + else if (rate == clk_i2s_mclk.rate / 4) + ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV, + clk->enable_reg); + else + return -EINVAL; + + clk_i2s_sclk.rate = rate; + return 0; +} + +static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate) +{ + unsigned val = __raw_readl(clk->enable_reg) & + ~EP93XX_I2SCLKDIV_LRDIV_MASK; + + if (rate == clk_i2s_sclk.rate / 32) + ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32, + clk->enable_reg); + else if (rate == clk_i2s_sclk.rate / 64) + ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64, + clk->enable_reg); + else if (rate == clk_i2s_sclk.rate / 128) + ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128, + clk->enable_reg); + else + return -EINVAL; + + clk_i2s_lrclk.rate = rate; + return 0; +} + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + if (clk->set_rate) + return clk->set_rate(clk, rate); + + return -EINVAL; +} +EXPORT_SYMBOL(clk_set_rate); + static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; @@ -100,7 +488,7 @@ static unsigned long calc_pll_rate(u32 config_word) unsigned long long rate; int i; - rate = 14745600; + rate = clk_xtali.rate; rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ @@ -110,39 +498,66 @@ static unsigned long calc_pll_rate(u32 config_word) return (unsigned long)rate; } +static void __init ep93xx_dma_clock_init(void) +{ + clk_m2p0.rate = clk_h.rate; + clk_m2p1.rate = clk_h.rate; + clk_m2p2.rate = clk_h.rate; + clk_m2p3.rate = clk_h.rate; + clk_m2p4.rate = clk_h.rate; + clk_m2p5.rate = clk_h.rate; + clk_m2p6.rate = clk_h.rate; + clk_m2p7.rate = clk_h.rate; + clk_m2p8.rate = clk_h.rate; + clk_m2p9.rate = clk_h.rate; + clk_m2m0.rate = clk_h.rate; + clk_m2m1.rate = clk_h.rate; +} + static int __init ep93xx_clock_init(void) { u32 value; - int i; - value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); - if (!(value & 0x00800000)) { /* PLL1 bypassed? */ - clk_pll1.rate = 14745600; - } else { + /* Determine the bootloader configured pll1 rate */ + value = __raw_readl(EP93XX_SYSCON_CLKSET1); + if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1)) + clk_pll1.rate = clk_xtali.rate; + else clk_pll1.rate = calc_pll_rate(value); - } + + /* Initialize the pll1 derived clocks */ clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7]; clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7]; clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3]; + ep93xx_dma_clock_init(); - value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); - if (!(value & 0x00080000)) { /* PLL2 bypassed? */ - clk_pll2.rate = 14745600; - } else if (value & 0x00040000) { /* PLL2 enabled? */ + /* Determine the bootloader configured pll2 rate */ + value = __raw_readl(EP93XX_SYSCON_CLKSET2); + if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2)) + clk_pll2.rate = clk_xtali.rate; + else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN) clk_pll2.rate = calc_pll_rate(value); - } else { + else clk_pll2.rate = 0; - } + + /* Initialize the pll2 derived clocks */ clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1); - printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n", + /* + * EP93xx SSP clock rate was doubled in version E2. For more information + * see: + * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf + */ + if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2) + clk_spi.rate /= 2; + + pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n", clk_pll1.rate / 1000000, clk_pll2.rate / 1000000); - printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", + pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", clk_f.rate / 1000000, clk_h.rate / 1000000, clk_p.rate / 1000000); - for (i = 0; i < ARRAY_SIZE(clocks); i++) - clkdev_add(&clocks[i]); + clkdev_add_table(clocks, ARRAY_SIZE(clocks)); return 0; } -arch_initcall(ep93xx_clock_init); +postcore_initcall(ep93xx_clock_init); diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 6d9152de607..0e571f1749d 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -14,45 +14,42 @@ * your option) any later version. */ +#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/sched.h> +#include <linux/platform_device.h> #include <linux/interrupt.h> -#include <linux/serial.h> -#include <linux/tty.h> -#include <linux/bitops.h> -#include <linux/serial_8250.h> -#include <linux/serial_core.h> -#include <linux/device.h> -#include <linux/mm.h> #include <linux/dma-mapping.h> -#include <linux/time.h> +#include <linux/sys_soc.h> #include <linux/timex.h> -#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/leds.h> #include <linux/termios.h> #include <linux/amba/bus.h> #include <linux/amba/serial.h> -#include <linux/io.h> +#include <linux/mtd/physmap.h> #include <linux/i2c.h> #include <linux/i2c-gpio.h> +#include <linux/spi/spi.h> +#include <linux/export.h> +#include <linux/irqchip/arm-vic.h> +#include <linux/reboot.h> +#include <linux/usb/ohci_pdriver.h> -#include <asm/types.h> -#include <asm/setup.h> -#include <asm/memory.h> #include <mach/hardware.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/tlbflush.h> -#include <asm/pgtable.h> +#include <linux/platform_data/video-ep93xx.h> +#include <linux/platform_data/keypad-ep93xx.h> +#include <linux/platform_data/spi-ep93xx.h> +#include <mach/gpio-ep93xx.h> +#include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/time.h> -#include <asm/mach/irq.h> -#include <mach/gpio.h> - -#include <asm/hardware/vic.h> +#include "soc.h" /************************************************************************* * Static I/O mappings that are needed for all EP93xx platforms @@ -96,13 +93,40 @@ void __init ep93xx_map_io(void) * to use this timer for something else. We also use timer 4 for keeping * track of lost jiffies. */ -static unsigned int last_jiffy_time; +#define EP93XX_TIMER_REG(x) (EP93XX_TIMER_BASE + (x)) +#define EP93XX_TIMER1_LOAD EP93XX_TIMER_REG(0x00) +#define EP93XX_TIMER1_VALUE EP93XX_TIMER_REG(0x04) +#define EP93XX_TIMER1_CONTROL EP93XX_TIMER_REG(0x08) +#define EP93XX_TIMER123_CONTROL_ENABLE (1 << 7) +#define EP93XX_TIMER123_CONTROL_MODE (1 << 6) +#define EP93XX_TIMER123_CONTROL_CLKSEL (1 << 3) +#define EP93XX_TIMER1_CLEAR EP93XX_TIMER_REG(0x0c) +#define EP93XX_TIMER2_LOAD EP93XX_TIMER_REG(0x20) +#define EP93XX_TIMER2_VALUE EP93XX_TIMER_REG(0x24) +#define EP93XX_TIMER2_CONTROL EP93XX_TIMER_REG(0x28) +#define EP93XX_TIMER2_CLEAR EP93XX_TIMER_REG(0x2c) +#define EP93XX_TIMER4_VALUE_LOW EP93XX_TIMER_REG(0x60) +#define EP93XX_TIMER4_VALUE_HIGH EP93XX_TIMER_REG(0x64) +#define EP93XX_TIMER4_VALUE_HIGH_ENABLE (1 << 8) +#define EP93XX_TIMER3_LOAD EP93XX_TIMER_REG(0x80) +#define EP93XX_TIMER3_VALUE EP93XX_TIMER_REG(0x84) +#define EP93XX_TIMER3_CONTROL EP93XX_TIMER_REG(0x88) +#define EP93XX_TIMER3_CLEAR EP93XX_TIMER_REG(0x8c) + +#define EP93XX_TIMER123_CLOCK 508469 +#define EP93XX_TIMER4_CLOCK 983040 + +#define TIMER1_RELOAD ((EP93XX_TIMER123_CLOCK / HZ) - 1) +#define TIMER4_TICKS_PER_JIFFY DIV_ROUND_CLOSEST(EP93XX_TIMER4_CLOCK, HZ) -#define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ) +static unsigned int last_jiffy_time; -static int ep93xx_timer_interrupt(int irq, void *dev_id) +static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id) { + /* Writing any value clears the timer interrupt */ __raw_writel(1, EP93XX_TIMER1_CLEAR); + + /* Recover lost jiffies */ while ((signed long) (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time) >= TIMER4_TICKS_PER_JIFFY) { @@ -115,443 +139,911 @@ static int ep93xx_timer_interrupt(int irq, void *dev_id) static struct irqaction ep93xx_timer_irq = { .name = "ep93xx timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = ep93xx_timer_interrupt, }; -static void __init ep93xx_timer_init(void) +static u32 ep93xx_gettimeoffset(void) { - /* Enable periodic HZ timer. */ - __raw_writel(0x48, EP93XX_TIMER1_CONTROL); - __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD); - __raw_writel(0xc8, EP93XX_TIMER1_CONTROL); + int offset; - /* Enable lost jiffy timer. */ - __raw_writel(0x100, EP93XX_TIMER4_VALUE_HIGH); + offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time; - setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq); + /* + * Timer 4 is based on a 983.04 kHz reference clock, + * so dividing by 983040 gives the fraction of a second, + * so dividing by 0.983040 converts to uS. + * Refactor the calculation to avoid overflow. + * Finally, multiply by 1000 to give nS. + */ + return (offset + (53 * offset / 3072)) * 1000; } -static unsigned long ep93xx_gettimeoffset(void) +void __init ep93xx_timer_init(void) { - int offset; + u32 tmode = EP93XX_TIMER123_CONTROL_MODE | + EP93XX_TIMER123_CONTROL_CLKSEL; - offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time; + arch_gettimeoffset = ep93xx_gettimeoffset; + + /* Enable periodic HZ timer. */ + __raw_writel(tmode, EP93XX_TIMER1_CONTROL); + __raw_writel(TIMER1_RELOAD, EP93XX_TIMER1_LOAD); + __raw_writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE, + EP93XX_TIMER1_CONTROL); - /* Calculate (1000000 / 983040) * offset. */ - return offset + (53 * offset / 3072); + /* Enable lost jiffy timer. */ + __raw_writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE, + EP93XX_TIMER4_VALUE_HIGH); + + setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq); } -struct sys_timer ep93xx_timer = { - .init = ep93xx_timer_init, - .offset = ep93xx_gettimeoffset, -}; + +/************************************************************************* + * EP93xx IRQ handling + *************************************************************************/ +void __init ep93xx_init_irq(void) +{ + vic_init(EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0); + vic_init(EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0); +} /************************************************************************* - * GPIO handling for EP93xx + * EP93xx System Controller Software Locked register handling *************************************************************************/ -static unsigned char gpio_int_unmasked[3]; -static unsigned char gpio_int_enabled[3]; -static unsigned char gpio_int_type1[3]; -static unsigned char gpio_int_type2[3]; -static unsigned char gpio_int_debouce[3]; -/* Port ordering is: A B F */ -static const u8 int_type1_register_offset[3] = { 0x90, 0xac, 0x4c }; -static const u8 int_type2_register_offset[3] = { 0x94, 0xb0, 0x50 }; -static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 }; -static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x58 }; -static const u8 int_debounce_register_offset[3] = { 0xa8, 0xc4, 0x64 }; +/* + * syscon_swlock prevents anything else from writing to the syscon + * block while a software locked register is being written. + */ +static DEFINE_SPINLOCK(syscon_swlock); -void ep93xx_gpio_update_int_params(unsigned port) +void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg) { - BUG_ON(port > 2); + unsigned long flags; + + spin_lock_irqsave(&syscon_swlock, flags); - __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); + __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); + __raw_writel(val, reg); - __raw_writeb(gpio_int_type2[port], - EP93XX_GPIO_REG(int_type2_register_offset[port])); + spin_unlock_irqrestore(&syscon_swlock, flags); +} - __raw_writeb(gpio_int_type1[port], - EP93XX_GPIO_REG(int_type1_register_offset[port])); +void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits) +{ + unsigned long flags; + unsigned int val; - __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], - EP93XX_GPIO_REG(int_en_register_offset[port])); + spin_lock_irqsave(&syscon_swlock, flags); + + val = __raw_readl(EP93XX_SYSCON_DEVCFG); + val &= ~clear_bits; + val |= set_bits; + __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); + __raw_writel(val, EP93XX_SYSCON_DEVCFG); + + spin_unlock_irqrestore(&syscon_swlock, flags); } -void ep93xx_gpio_int_mask(unsigned line) +/** + * ep93xx_chip_revision() - returns the EP93xx chip revision + * + * See <mach/platform.h> for more information. + */ +unsigned int ep93xx_chip_revision(void) { - gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7)); + unsigned int v; + + v = __raw_readl(EP93XX_SYSCON_SYSCFG); + v &= EP93XX_SYSCON_SYSCFG_REV_MASK; + v >>= EP93XX_SYSCON_SYSCFG_REV_SHIFT; + return v; } +EXPORT_SYMBOL_GPL(ep93xx_chip_revision); + +/************************************************************************* + * EP93xx GPIO + *************************************************************************/ +static struct resource ep93xx_gpio_resource[] = { + DEFINE_RES_MEM(EP93XX_GPIO_PHYS_BASE, 0xcc), +}; -void ep93xx_gpio_int_debounce(unsigned int irq, int enable) +static struct platform_device ep93xx_gpio_device = { + .name = "gpio-ep93xx", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_gpio_resource), + .resource = ep93xx_gpio_resource, +}; + +/************************************************************************* + * EP93xx peripheral handling + *************************************************************************/ +#define EP93XX_UART_MCR_OFFSET (0x0100) + +static void ep93xx_uart_set_mctrl(struct amba_device *dev, + void __iomem *base, unsigned int mctrl) { - int line = irq_to_gpio(irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); + unsigned int mcr; - if (enable) - gpio_int_debouce[port] |= port_mask; - else - gpio_int_debouce[port] &= ~port_mask; + mcr = 0; + if (mctrl & TIOCM_RTS) + mcr |= 2; + if (mctrl & TIOCM_DTR) + mcr |= 1; - __raw_writeb(gpio_int_debouce[port], - EP93XX_GPIO_REG(int_debounce_register_offset[port])); + __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); } -EXPORT_SYMBOL(ep93xx_gpio_int_debounce); + +static struct amba_pl010_data ep93xx_uart_data = { + .set_mctrl = ep93xx_uart_set_mctrl, +}; + +static AMBA_APB_DEVICE(uart1, "apb:uart1", 0x00041010, EP93XX_UART1_PHYS_BASE, + { IRQ_EP93XX_UART1 }, &ep93xx_uart_data); + +static AMBA_APB_DEVICE(uart2, "apb:uart2", 0x00041010, EP93XX_UART2_PHYS_BASE, + { IRQ_EP93XX_UART2 }, NULL); + +static AMBA_APB_DEVICE(uart3, "apb:uart3", 0x00041010, EP93XX_UART3_PHYS_BASE, + { IRQ_EP93XX_UART3 }, &ep93xx_uart_data); + +static struct resource ep93xx_rtc_resource[] = { + DEFINE_RES_MEM(EP93XX_RTC_PHYS_BASE, 0x10c), +}; + +static struct platform_device ep93xx_rtc_device = { + .name = "ep93xx-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_rtc_resource), + .resource = ep93xx_rtc_resource, +}; /************************************************************************* - * EP93xx IRQ handling + * EP93xx OHCI USB Host *************************************************************************/ -static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - unsigned char status; - int i; - status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) { - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; - generic_handle_irq(gpio_irq); - } - } +static struct clk *ep93xx_ohci_host_clock; - status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) { - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; - desc = irq_desc + gpio_irq; - generic_handle_irq(gpio_irq); - } +static int ep93xx_ohci_power_on(struct platform_device *pdev) +{ + if (!ep93xx_ohci_host_clock) { + ep93xx_ohci_host_clock = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ep93xx_ohci_host_clock)) + return PTR_ERR(ep93xx_ohci_host_clock); } + + return clk_enable(ep93xx_ohci_host_clock); } -static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ep93xx_ohci_power_off(struct platform_device *pdev) { - /* - * map discontiguous hw irq range to continous sw irq range: - * - * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) - */ - int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; - - generic_handle_irq(gpio_irq); + clk_disable(ep93xx_ohci_host_clock); } -static void ep93xx_gpio_irq_ack(unsigned int irq) +static struct usb_ohci_pdata ep93xx_ohci_pdata = { + .power_on = ep93xx_ohci_power_on, + .power_off = ep93xx_ohci_power_off, + .power_suspend = ep93xx_ohci_power_off, +}; + +static struct resource ep93xx_ohci_resources[] = { + DEFINE_RES_MEM(EP93XX_USB_PHYS_BASE, 0x1000), + DEFINE_RES_IRQ(IRQ_EP93XX_USB), +}; + +static u64 ep93xx_ohci_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device ep93xx_ohci_device = { + .name = "ohci-platform", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_ohci_resources), + .resource = ep93xx_ohci_resources, + .dev = { + .dma_mask = &ep93xx_ohci_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &ep93xx_ohci_pdata, + }, +}; + +/************************************************************************* + * EP93xx physmap'ed flash + *************************************************************************/ +static struct physmap_flash_data ep93xx_flash_data; + +static struct resource ep93xx_flash_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ep93xx_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &ep93xx_flash_data, + }, + .num_resources = 1, + .resource = &ep93xx_flash_resource, +}; + +/** + * ep93xx_register_flash() - Register the external flash device. + * @width: bank width in octets + * @start: resource start address + * @size: resource size + */ +void __init ep93xx_register_flash(unsigned int width, + resource_size_t start, resource_size_t size) { - int line = irq_to_gpio(irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); + ep93xx_flash_data.width = width; - if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { - gpio_int_type2[port] ^= port_mask; /* switch edge direction */ - ep93xx_gpio_update_int_params(port); - } + ep93xx_flash_resource.start = start; + ep93xx_flash_resource.end = start + size - 1; - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + platform_device_register(&ep93xx_flash); } -static void ep93xx_gpio_irq_mask_ack(unsigned int irq) -{ - int line = irq_to_gpio(irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); - if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) - gpio_int_type2[port] ^= port_mask; /* switch edge direction */ +/************************************************************************* + * EP93xx ethernet peripheral handling + *************************************************************************/ +static struct ep93xx_eth_data ep93xx_eth_data; + +static struct resource ep93xx_eth_resource[] = { + DEFINE_RES_MEM(EP93XX_ETHERNET_PHYS_BASE, 0x10000), + DEFINE_RES_IRQ(IRQ_EP93XX_ETHERNET), +}; - gpio_int_unmasked[port] &= ~port_mask; - ep93xx_gpio_update_int_params(port); +static u64 ep93xx_eth_dma_mask = DMA_BIT_MASK(32); - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); -} +static struct platform_device ep93xx_eth_device = { + .name = "ep93xx-eth", + .id = -1, + .dev = { + .platform_data = &ep93xx_eth_data, + .coherent_dma_mask = DMA_BIT_MASK(32), + .dma_mask = &ep93xx_eth_dma_mask, + }, + .num_resources = ARRAY_SIZE(ep93xx_eth_resource), + .resource = ep93xx_eth_resource, +}; -static void ep93xx_gpio_irq_mask(unsigned int irq) +/** + * ep93xx_register_eth - Register the built-in ethernet platform device. + * @data: platform specific ethernet configuration (__initdata) + * @copy_addr: flag indicating that the MAC address should be copied + * from the IndAd registers (as programmed by the bootloader) + */ +void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr) { - int line = irq_to_gpio(irq); - int port = line >> 3; + if (copy_addr) + memcpy_fromio(data->dev_addr, EP93XX_ETHERNET_BASE + 0x50, 6); - gpio_int_unmasked[port] &= ~(1 << (line & 7)); - ep93xx_gpio_update_int_params(port); + ep93xx_eth_data = *data; + platform_device_register(&ep93xx_eth_device); } -static void ep93xx_gpio_irq_unmask(unsigned int irq) + +/************************************************************************* + * EP93xx i2c peripheral handling + *************************************************************************/ +static struct i2c_gpio_platform_data ep93xx_i2c_data; + +static struct platform_device ep93xx_i2c_device = { + .name = "i2c-gpio", + .id = 0, + .dev = { + .platform_data = &ep93xx_i2c_data, + }, +}; + +/** + * ep93xx_register_i2c - Register the i2c platform device. + * @data: platform specific i2c-gpio configuration (__initdata) + * @devices: platform specific i2c bus device information (__initdata) + * @num: the number of devices on the i2c bus + */ +void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data, + struct i2c_board_info *devices, int num) { - int line = irq_to_gpio(irq); - int port = line >> 3; + /* + * Set the EEPROM interface pin drive type control. + * Defines the driver type for the EECLK and EEDAT pins as either + * open drain, which will require an external pull-up, or a normal + * CMOS driver. + */ + if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT) + pr_warning("sda != EEDAT, open drain has no effect\n"); + if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK) + pr_warning("scl != EECLK, open drain has no effect\n"); - gpio_int_unmasked[port] |= 1 << (line & 7); - ep93xx_gpio_update_int_params(port); + __raw_writel((data->sda_is_open_drain << 1) | + (data->scl_is_open_drain << 0), + EP93XX_GPIO_EEDRIVE); + + ep93xx_i2c_data = *data; + i2c_register_board_info(0, devices, num); + platform_device_register(&ep93xx_i2c_device); } +/************************************************************************* + * EP93xx SPI peripheral handling + *************************************************************************/ +static struct ep93xx_spi_info ep93xx_spi_master_data; -/* - * gpio_int_type1 controls whether the interrupt is level (0) or - * edge (1) triggered, while gpio_int_type2 controls whether it - * triggers on low/falling (0) or high/rising (1). - */ -static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) -{ - struct irq_desc *desc = irq_desc + irq; - const int gpio = irq_to_gpio(irq); - const int port = gpio >> 3; - const int port_mask = 1 << (gpio & 7); - - gpio_direction_input(gpio); - - switch (type) { - case IRQ_TYPE_EDGE_RISING: - gpio_int_type1[port] |= port_mask; - gpio_int_type2[port] |= port_mask; - desc->handle_irq = handle_edge_irq; - break; - case IRQ_TYPE_EDGE_FALLING: - gpio_int_type1[port] |= port_mask; - gpio_int_type2[port] &= ~port_mask; - desc->handle_irq = handle_edge_irq; - break; - case IRQ_TYPE_LEVEL_HIGH: - gpio_int_type1[port] &= ~port_mask; - gpio_int_type2[port] |= port_mask; - desc->handle_irq = handle_level_irq; - break; - case IRQ_TYPE_LEVEL_LOW: - gpio_int_type1[port] &= ~port_mask; - gpio_int_type2[port] &= ~port_mask; - desc->handle_irq = handle_level_irq; - break; - case IRQ_TYPE_EDGE_BOTH: - gpio_int_type1[port] |= port_mask; - /* set initial polarity based on current input level */ - if (gpio_get_value(gpio)) - gpio_int_type2[port] &= ~port_mask; /* falling */ - else - gpio_int_type2[port] |= port_mask; /* rising */ - desc->handle_irq = handle_edge_irq; - break; - default: - pr_err("ep93xx: failed to set irq type %d for gpio %d\n", - type, gpio); - return -EINVAL; - } +static struct resource ep93xx_spi_resources[] = { + DEFINE_RES_MEM(EP93XX_SPI_PHYS_BASE, 0x18), + DEFINE_RES_IRQ(IRQ_EP93XX_SSP), +}; - gpio_int_enabled[port] |= port_mask; +static u64 ep93xx_spi_dma_mask = DMA_BIT_MASK(32); - desc->status &= ~IRQ_TYPE_SENSE_MASK; - desc->status |= type & IRQ_TYPE_SENSE_MASK; +static struct platform_device ep93xx_spi_device = { + .name = "ep93xx-spi", + .id = 0, + .dev = { + .platform_data = &ep93xx_spi_master_data, + .coherent_dma_mask = DMA_BIT_MASK(32), + .dma_mask = &ep93xx_spi_dma_mask, + }, + .num_resources = ARRAY_SIZE(ep93xx_spi_resources), + .resource = ep93xx_spi_resources, +}; - ep93xx_gpio_update_int_params(port); +/** + * ep93xx_register_spi() - registers spi platform device + * @info: ep93xx board specific spi master info (__initdata) + * @devices: SPI devices to register (__initdata) + * @num: number of SPI devices to register + * + * This function registers platform device for the EP93xx SPI controller and + * also makes sure that SPI pins are muxed so that I2S is not using those pins. + */ +void __init ep93xx_register_spi(struct ep93xx_spi_info *info, + struct spi_board_info *devices, int num) +{ + /* + * When SPI is used, we need to make sure that I2S is muxed off from + * SPI pins. + */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP); - return 0; + ep93xx_spi_master_data = *info; + spi_register_board_info(devices, num); + platform_device_register(&ep93xx_spi_device); } -static struct irq_chip ep93xx_gpio_irq_chip = { - .name = "GPIO", - .ack = ep93xx_gpio_irq_ack, - .mask_ack = ep93xx_gpio_irq_mask_ack, - .mask = ep93xx_gpio_irq_mask, - .unmask = ep93xx_gpio_irq_unmask, - .set_type = ep93xx_gpio_irq_type, +/************************************************************************* + * EP93xx LEDs + *************************************************************************/ +static const struct gpio_led ep93xx_led_pins[] __initconst = { + { + .name = "platform:grled", + .gpio = EP93XX_GPIO_LINE_GRLED, + }, { + .name = "platform:rdled", + .gpio = EP93XX_GPIO_LINE_RDLED, + }, }; +static const struct gpio_led_platform_data ep93xx_led_data __initconst = { + .num_leds = ARRAY_SIZE(ep93xx_led_pins), + .leds = ep93xx_led_pins, +}; -void __init ep93xx_init_irq(void) +/************************************************************************* + * EP93xx pwm peripheral handling + *************************************************************************/ +static struct resource ep93xx_pwm0_resource[] = { + DEFINE_RES_MEM(EP93XX_PWM_PHYS_BASE, 0x10), +}; + +static struct platform_device ep93xx_pwm0_device = { + .name = "ep93xx-pwm", + .id = 0, + .num_resources = ARRAY_SIZE(ep93xx_pwm0_resource), + .resource = ep93xx_pwm0_resource, +}; + +static struct resource ep93xx_pwm1_resource[] = { + DEFINE_RES_MEM(EP93XX_PWM_PHYS_BASE + 0x20, 0x10), +}; + +static struct platform_device ep93xx_pwm1_device = { + .name = "ep93xx-pwm", + .id = 1, + .num_resources = ARRAY_SIZE(ep93xx_pwm1_resource), + .resource = ep93xx_pwm1_resource, +}; + +void __init ep93xx_register_pwm(int pwm0, int pwm1) { - int gpio_irq; + if (pwm0) + platform_device_register(&ep93xx_pwm0_device); - vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK); - vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK); + /* NOTE: EP9307 does not have PWMOUT1 (pin EGPIO14) */ + if (pwm1) + platform_device_register(&ep93xx_pwm1_device); +} - for (gpio_irq = gpio_to_irq(0); - gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { - set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip); - set_irq_handler(gpio_irq, handle_level_irq); - set_irq_flags(gpio_irq, IRQF_VALID); +int ep93xx_pwm_acquire_gpio(struct platform_device *pdev) +{ + int err; + + if (pdev->id == 0) { + err = 0; + } else if (pdev->id == 1) { + err = gpio_request(EP93XX_GPIO_LINE_EGPIO14, + dev_name(&pdev->dev)); + if (err) + return err; + err = gpio_direction_output(EP93XX_GPIO_LINE_EGPIO14, 0); + if (err) + goto fail; + + /* PWM 1 output on EGPIO[14] */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_PONG); + } else { + err = -ENODEV; } - set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler); - set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler); + return err; + +fail: + gpio_free(EP93XX_GPIO_LINE_EGPIO14); + return err; } +EXPORT_SYMBOL(ep93xx_pwm_acquire_gpio); + +void ep93xx_pwm_release_gpio(struct platform_device *pdev) +{ + if (pdev->id == 1) { + gpio_direction_input(EP93XX_GPIO_LINE_EGPIO14); + gpio_free(EP93XX_GPIO_LINE_EGPIO14); + + /* EGPIO[14] used for GPIO */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_PONG); + } +} +EXPORT_SYMBOL(ep93xx_pwm_release_gpio); /************************************************************************* - * EP93xx peripheral handling + * EP93xx video peripheral handling *************************************************************************/ -#define EP93XX_UART_MCR_OFFSET (0x0100) +static struct ep93xxfb_mach_info ep93xxfb_data; -static void ep93xx_uart_set_mctrl(struct amba_device *dev, - void __iomem *base, unsigned int mctrl) -{ - unsigned int mcr; +static struct resource ep93xx_fb_resource[] = { + DEFINE_RES_MEM(EP93XX_RASTER_PHYS_BASE, 0x800), +}; - mcr = 0; - if (!(mctrl & TIOCM_RTS)) - mcr |= 2; - if (!(mctrl & TIOCM_DTR)) - mcr |= 1; +static struct platform_device ep93xx_fb_device = { + .name = "ep93xx-fb", + .id = -1, + .dev = { + .platform_data = &ep93xxfb_data, + .coherent_dma_mask = DMA_BIT_MASK(32), + .dma_mask = &ep93xx_fb_device.dev.coherent_dma_mask, + }, + .num_resources = ARRAY_SIZE(ep93xx_fb_resource), + .resource = ep93xx_fb_resource, +}; - __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); -} +/* The backlight use a single register in the framebuffer's register space */ +#define EP93XX_RASTER_REG_BRIGHTNESS 0x20 -static struct amba_pl010_data ep93xx_uart_data = { - .set_mctrl = ep93xx_uart_set_mctrl, +static struct resource ep93xx_bl_resources[] = { + DEFINE_RES_MEM(EP93XX_RASTER_PHYS_BASE + + EP93XX_RASTER_REG_BRIGHTNESS, 0x04), }; -static struct amba_device uart1_device = { - .dev = { - .init_name = "apb:uart1", - .platform_data = &ep93xx_uart_data, - }, - .res = { - .start = EP93XX_UART1_PHYS_BASE, - .end = EP93XX_UART1_PHYS_BASE + 0x0fff, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_EP93XX_UART1, NO_IRQ }, - .periphid = 0x00041010, +static struct platform_device ep93xx_bl_device = { + .name = "ep93xx-bl", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_bl_resources), + .resource = ep93xx_bl_resources, }; -static struct amba_device uart2_device = { - .dev = { - .init_name = "apb:uart2", - .platform_data = &ep93xx_uart_data, - }, - .res = { - .start = EP93XX_UART2_PHYS_BASE, - .end = EP93XX_UART2_PHYS_BASE + 0x0fff, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_EP93XX_UART2, NO_IRQ }, - .periphid = 0x00041010, +/** + * ep93xx_register_fb - Register the framebuffer platform device. + * @data: platform specific framebuffer configuration (__initdata) + */ +void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data) +{ + ep93xxfb_data = *data; + platform_device_register(&ep93xx_fb_device); + platform_device_register(&ep93xx_bl_device); +} + + +/************************************************************************* + * EP93xx matrix keypad peripheral handling + *************************************************************************/ +static struct ep93xx_keypad_platform_data ep93xx_keypad_data; + +static struct resource ep93xx_keypad_resource[] = { + DEFINE_RES_MEM(EP93XX_KEY_MATRIX_PHYS_BASE, 0x0c), + DEFINE_RES_IRQ(IRQ_EP93XX_KEY), }; -static struct amba_device uart3_device = { +static struct platform_device ep93xx_keypad_device = { + .name = "ep93xx-keypad", + .id = -1, .dev = { - .init_name = "apb:uart3", - .platform_data = &ep93xx_uart_data, + .platform_data = &ep93xx_keypad_data, }, - .res = { - .start = EP93XX_UART3_PHYS_BASE, - .end = EP93XX_UART3_PHYS_BASE + 0x0fff, - .flags = IORESOURCE_MEM, - }, - .irq = { IRQ_EP93XX_UART3, NO_IRQ }, - .periphid = 0x00041010, + .num_resources = ARRAY_SIZE(ep93xx_keypad_resource), + .resource = ep93xx_keypad_resource, }; +/** + * ep93xx_register_keypad - Register the keypad platform device. + * @data: platform specific keypad configuration (__initdata) + */ +void __init ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data) +{ + ep93xx_keypad_data = *data; + platform_device_register(&ep93xx_keypad_device); +} -static struct platform_device ep93xx_rtc_device = { - .name = "ep93xx-rtc", - .id = -1, - .num_resources = 0, +int ep93xx_keypad_acquire_gpio(struct platform_device *pdev) +{ + int err; + int i; + + for (i = 0; i < 8; i++) { + err = gpio_request(EP93XX_GPIO_LINE_C(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_c; + err = gpio_request(EP93XX_GPIO_LINE_D(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_d; + } + + /* Enable the keypad controller; GPIO ports C and D used for keypad */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_KEYS | + EP93XX_SYSCON_DEVCFG_GONK); + + return 0; + +fail_gpio_d: + gpio_free(EP93XX_GPIO_LINE_C(i)); +fail_gpio_c: + for (--i; i >= 0; --i) { + gpio_free(EP93XX_GPIO_LINE_C(i)); + gpio_free(EP93XX_GPIO_LINE_D(i)); + } + return err; +} +EXPORT_SYMBOL(ep93xx_keypad_acquire_gpio); + +void ep93xx_keypad_release_gpio(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < 8; i++) { + gpio_free(EP93XX_GPIO_LINE_C(i)); + gpio_free(EP93XX_GPIO_LINE_D(i)); + } + + /* Disable the keypad controller; GPIO ports C and D used for GPIO */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | + EP93XX_SYSCON_DEVCFG_GONK); +} +EXPORT_SYMBOL(ep93xx_keypad_release_gpio); + +/************************************************************************* + * EP93xx I2S audio peripheral handling + *************************************************************************/ +static struct resource ep93xx_i2s_resource[] = { + DEFINE_RES_MEM(EP93XX_I2S_PHYS_BASE, 0x100), }; +static struct platform_device ep93xx_i2s_device = { + .name = "ep93xx-i2s", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_i2s_resource), + .resource = ep93xx_i2s_resource, +}; -static struct resource ep93xx_ohci_resources[] = { - [0] = { - .start = EP93XX_USB_PHYS_BASE, - .end = EP93XX_USB_PHYS_BASE + 0x0fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_EP93XX_USB, - .end = IRQ_EP93XX_USB, - .flags = IORESOURCE_IRQ, - }, +static struct platform_device ep93xx_pcm_device = { + .name = "ep93xx-pcm-audio", + .id = -1, }; +void __init ep93xx_register_i2s(void) +{ + platform_device_register(&ep93xx_i2s_device); + platform_device_register(&ep93xx_pcm_device); +} + +#define EP93XX_SYSCON_DEVCFG_I2S_MASK (EP93XX_SYSCON_DEVCFG_I2SONSSP | \ + EP93XX_SYSCON_DEVCFG_I2SONAC97) -static struct platform_device ep93xx_ohci_device = { - .name = "ep93xx-ohci", +#define EP93XX_I2SCLKDIV_MASK (EP93XX_SYSCON_I2SCLKDIV_ORIDE | \ + EP93XX_SYSCON_I2SCLKDIV_SPOL) + +int ep93xx_i2s_acquire(void) +{ + unsigned val; + + ep93xx_devcfg_set_clear(EP93XX_SYSCON_DEVCFG_I2SONAC97, + EP93XX_SYSCON_DEVCFG_I2S_MASK); + + /* + * This is potentially racy with the clock api for i2s_mclk, sclk and + * lrclk. Since the i2s driver is the only user of those clocks we + * rely on it to prevent parallel use of this function and the + * clock api for the i2s clocks. + */ + val = __raw_readl(EP93XX_SYSCON_I2SCLKDIV); + val &= ~EP93XX_I2SCLKDIV_MASK; + val |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL; + ep93xx_syscon_swlocked_write(val, EP93XX_SYSCON_I2SCLKDIV); + + return 0; +} +EXPORT_SYMBOL(ep93xx_i2s_acquire); + +void ep93xx_i2s_release(void) +{ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK); +} +EXPORT_SYMBOL(ep93xx_i2s_release); + +/************************************************************************* + * EP93xx AC97 audio peripheral handling + *************************************************************************/ +static struct resource ep93xx_ac97_resources[] = { + DEFINE_RES_MEM(EP93XX_AAC_PHYS_BASE, 0xac), + DEFINE_RES_IRQ(IRQ_EP93XX_AACINTR), +}; + +static struct platform_device ep93xx_ac97_device = { + .name = "ep93xx-ac97", .id = -1, - .dev = { - .dma_mask = &ep93xx_ohci_device.dev.coherent_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(ep93xx_ohci_resources), - .resource = ep93xx_ohci_resources, + .num_resources = ARRAY_SIZE(ep93xx_ac97_resources), + .resource = ep93xx_ac97_resources, }; -static struct ep93xx_eth_data ep93xx_eth_data; +void __init ep93xx_register_ac97(void) +{ + /* + * Make sure that the AC97 pins are not used by I2S. + */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97); -static struct resource ep93xx_eth_resource[] = { - { - .start = EP93XX_ETHERNET_PHYS_BASE, - .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_EP93XX_ETHERNET, - .end = IRQ_EP93XX_ETHERNET, - .flags = IORESOURCE_IRQ, - } + platform_device_register(&ep93xx_ac97_device); + platform_device_register(&ep93xx_pcm_device); +} + +/************************************************************************* + * EP93xx Watchdog + *************************************************************************/ +static struct resource ep93xx_wdt_resources[] = { + DEFINE_RES_MEM(EP93XX_WATCHDOG_PHYS_BASE, 0x08), }; -static struct platform_device ep93xx_eth_device = { - .name = "ep93xx-eth", +static struct platform_device ep93xx_wdt_device = { + .name = "ep93xx-wdt", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_wdt_resources), + .resource = ep93xx_wdt_resources, +}; + +/************************************************************************* + * EP93xx IDE + *************************************************************************/ +static struct resource ep93xx_ide_resources[] = { + DEFINE_RES_MEM(EP93XX_IDE_PHYS_BASE, 0x38), + DEFINE_RES_IRQ(IRQ_EP93XX_EXT3), +}; + +static struct platform_device ep93xx_ide_device = { + .name = "ep93xx-ide", .id = -1, .dev = { - .platform_data = &ep93xx_eth_data, + .dma_mask = &ep93xx_ide_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), }, - .num_resources = ARRAY_SIZE(ep93xx_eth_resource), - .resource = ep93xx_eth_resource, + .num_resources = ARRAY_SIZE(ep93xx_ide_resources), + .resource = ep93xx_ide_resources, }; -void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr) +void __init ep93xx_register_ide(void) +{ + platform_device_register(&ep93xx_ide_device); +} + +int ep93xx_ide_acquire_gpio(struct platform_device *pdev) { - if (copy_addr) { - memcpy(data->dev_addr, - (void *)(EP93XX_ETHERNET_BASE + 0x50), 6); + int err; + int i; + + err = gpio_request(EP93XX_GPIO_LINE_EGPIO2, dev_name(&pdev->dev)); + if (err) + return err; + err = gpio_request(EP93XX_GPIO_LINE_EGPIO15, dev_name(&pdev->dev)); + if (err) + goto fail_egpio15; + for (i = 2; i < 8; i++) { + err = gpio_request(EP93XX_GPIO_LINE_E(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_e; + } + for (i = 4; i < 8; i++) { + err = gpio_request(EP93XX_GPIO_LINE_G(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_g; + } + for (i = 0; i < 8; i++) { + err = gpio_request(EP93XX_GPIO_LINE_H(i), dev_name(&pdev->dev)); + if (err) + goto fail_gpio_h; } - ep93xx_eth_data = *data; - platform_device_register(&ep93xx_eth_device); + /* GPIO ports E[7:2], G[7:4] and H used by IDE */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_EONIDE | + EP93XX_SYSCON_DEVCFG_GONIDE | + EP93XX_SYSCON_DEVCFG_HONIDE); + return 0; + +fail_gpio_h: + for (--i; i >= 0; --i) + gpio_free(EP93XX_GPIO_LINE_H(i)); + i = 8; +fail_gpio_g: + for (--i; i >= 4; --i) + gpio_free(EP93XX_GPIO_LINE_G(i)); + i = 8; +fail_gpio_e: + for (--i; i >= 2; --i) + gpio_free(EP93XX_GPIO_LINE_E(i)); + gpio_free(EP93XX_GPIO_LINE_EGPIO15); +fail_egpio15: + gpio_free(EP93XX_GPIO_LINE_EGPIO2); + return err; } +EXPORT_SYMBOL(ep93xx_ide_acquire_gpio); -static struct i2c_gpio_platform_data ep93xx_i2c_data = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .sda_is_open_drain = 0, - .scl_pin = EP93XX_GPIO_LINE_EECLK, - .scl_is_open_drain = 0, - .udelay = 2, -}; +void ep93xx_ide_release_gpio(struct platform_device *pdev) +{ + int i; -static struct platform_device ep93xx_i2c_device = { - .name = "i2c-gpio", - .id = 0, - .dev.platform_data = &ep93xx_i2c_data, -}; + for (i = 2; i < 8; i++) + gpio_free(EP93XX_GPIO_LINE_E(i)); + for (i = 4; i < 8; i++) + gpio_free(EP93XX_GPIO_LINE_G(i)); + for (i = 0; i < 8; i++) + gpio_free(EP93XX_GPIO_LINE_H(i)); + gpio_free(EP93XX_GPIO_LINE_EGPIO15); + gpio_free(EP93XX_GPIO_LINE_EGPIO2); + + + /* GPIO ports E[7:2], G[7:4] and H used by GPIO */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_EONIDE | + EP93XX_SYSCON_DEVCFG_GONIDE | + EP93XX_SYSCON_DEVCFG_HONIDE); +} +EXPORT_SYMBOL(ep93xx_ide_release_gpio); + +/************************************************************************* + * EP93xx Security peripheral + *************************************************************************/ -void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num) +/* + * The Maverick Key is 256 bits of micro fuses blown at the factory during + * manufacturing to uniquely identify a part. + * + * See: http://arm.cirrus.com/forum/viewtopic.php?t=486&highlight=maverick+key + */ +#define EP93XX_SECURITY_REG(x) (EP93XX_SECURITY_BASE + (x)) +#define EP93XX_SECURITY_SECFLG EP93XX_SECURITY_REG(0x2400) +#define EP93XX_SECURITY_FUSEFLG EP93XX_SECURITY_REG(0x2410) +#define EP93XX_SECURITY_UNIQID EP93XX_SECURITY_REG(0x2440) +#define EP93XX_SECURITY_UNIQCHK EP93XX_SECURITY_REG(0x2450) +#define EP93XX_SECURITY_UNIQVAL EP93XX_SECURITY_REG(0x2460) +#define EP93XX_SECURITY_SECID1 EP93XX_SECURITY_REG(0x2500) +#define EP93XX_SECURITY_SECID2 EP93XX_SECURITY_REG(0x2504) +#define EP93XX_SECURITY_SECCHK1 EP93XX_SECURITY_REG(0x2520) +#define EP93XX_SECURITY_SECCHK2 EP93XX_SECURITY_REG(0x2524) +#define EP93XX_SECURITY_UNIQID2 EP93XX_SECURITY_REG(0x2700) +#define EP93XX_SECURITY_UNIQID3 EP93XX_SECURITY_REG(0x2704) +#define EP93XX_SECURITY_UNIQID4 EP93XX_SECURITY_REG(0x2708) +#define EP93XX_SECURITY_UNIQID5 EP93XX_SECURITY_REG(0x270c) + +static char ep93xx_soc_id[33]; + +static const char __init *ep93xx_get_soc_id(void) { - i2c_register_board_info(0, devices, num); - platform_device_register(&ep93xx_i2c_device); + unsigned int id, id2, id3, id4, id5; + + if (__raw_readl(EP93XX_SECURITY_UNIQVAL) != 1) + return "bad Hamming code"; + + id = __raw_readl(EP93XX_SECURITY_UNIQID); + id2 = __raw_readl(EP93XX_SECURITY_UNIQID2); + id3 = __raw_readl(EP93XX_SECURITY_UNIQID3); + id4 = __raw_readl(EP93XX_SECURITY_UNIQID4); + id5 = __raw_readl(EP93XX_SECURITY_UNIQID5); + + if (id != id2) + return "invalid"; + + snprintf(ep93xx_soc_id, sizeof(ep93xx_soc_id), + "%08x%08x%08x%08x", id2, id3, id4, id5); + + return ep93xx_soc_id; } -extern void ep93xx_gpio_init(void); +static const char __init *ep93xx_get_soc_rev(void) +{ + int rev = ep93xx_chip_revision(); + + switch (rev) { + case EP93XX_CHIP_REV_D0: + return "D0"; + case EP93XX_CHIP_REV_D1: + return "D1"; + case EP93XX_CHIP_REV_E0: + return "E0"; + case EP93XX_CHIP_REV_E1: + return "E1"; + case EP93XX_CHIP_REV_E2: + return "E2"; + default: + return "unknown"; + } +} -void __init ep93xx_init_devices(void) +static const char __init *ep93xx_get_machine_name(void) { - unsigned int v; + return kasprintf(GFP_KERNEL,"%s", machine_desc->name); +} - /* - * Disallow access to MaverickCrunch initially. - */ - v = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG); - v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE; - __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); - __raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG); +static struct device __init *ep93xx_init_soc(void) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return NULL; + + soc_dev_attr->machine = ep93xx_get_machine_name(); + soc_dev_attr->family = "Cirrus Logic EP93xx"; + soc_dev_attr->revision = ep93xx_get_soc_rev(); + soc_dev_attr->soc_id = ep93xx_get_soc_id(); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->machine); + kfree(soc_dev_attr); + return NULL; + } + + return soc_device_to_device(soc_dev); +} + +struct device __init *ep93xx_init_devices(void) +{ + struct device *parent; + + /* Disallow access to MaverickCrunch initially */ + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA); + + /* Default all ports to GPIO */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | + EP93XX_SYSCON_DEVCFG_GONK | + EP93XX_SYSCON_DEVCFG_EONIDE | + EP93XX_SYSCON_DEVCFG_GONIDE | + EP93XX_SYSCON_DEVCFG_HONIDE); + + parent = ep93xx_init_soc(); - ep93xx_gpio_init(); + /* Get the GPIO working early, other devices need it */ + platform_device_register(&ep93xx_gpio_device); amba_device_register(&uart1_device, &iomem_resource); amba_device_register(&uart2_device, &iomem_resource); @@ -559,4 +1051,26 @@ void __init ep93xx_init_devices(void) platform_device_register(&ep93xx_rtc_device); platform_device_register(&ep93xx_ohci_device); + platform_device_register(&ep93xx_wdt_device); + + gpio_led_register_device(-1, &ep93xx_led_data); + + return parent; +} + +void ep93xx_restart(enum reboot_mode mode, const char *cmd) +{ + /* + * Set then clear the SWRST bit to initiate a software reset + */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_SWRST); + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_SWRST); + + while (1) + ; +} + +void __init ep93xx_init_late(void) +{ + crunch_init(); } diff --git a/arch/arm/mach-ep93xx/crunch-bits.S b/arch/arm/mach-ep93xx/crunch-bits.S new file mode 100644 index 00000000000..e96923a3017 --- /dev/null +++ b/arch/arm/mach-ep93xx/crunch-bits.S @@ -0,0 +1,313 @@ +/* + * arch/arm/kernel/crunch-bits.S + * Cirrus MaverickCrunch context switching and handling + * + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + * + * Shamelessly stolen from the iWMMXt code by Nicolas Pitre, which is + * Copyright (c) 2003-2004, MontaVista Software, Inc. + * + * 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/linkage.h> +#include <asm/ptrace.h> +#include <asm/thread_info.h> +#include <asm/asm-offsets.h> +#include <asm/assembler.h> +#include <mach/ep93xx-regs.h> + +/* + * We can't use hex constants here due to a bug in gas. + */ +#define CRUNCH_MVDX0 0 +#define CRUNCH_MVDX1 8 +#define CRUNCH_MVDX2 16 +#define CRUNCH_MVDX3 24 +#define CRUNCH_MVDX4 32 +#define CRUNCH_MVDX5 40 +#define CRUNCH_MVDX6 48 +#define CRUNCH_MVDX7 56 +#define CRUNCH_MVDX8 64 +#define CRUNCH_MVDX9 72 +#define CRUNCH_MVDX10 80 +#define CRUNCH_MVDX11 88 +#define CRUNCH_MVDX12 96 +#define CRUNCH_MVDX13 104 +#define CRUNCH_MVDX14 112 +#define CRUNCH_MVDX15 120 +#define CRUNCH_MVAX0L 128 +#define CRUNCH_MVAX0M 132 +#define CRUNCH_MVAX0H 136 +#define CRUNCH_MVAX1L 140 +#define CRUNCH_MVAX1M 144 +#define CRUNCH_MVAX1H 148 +#define CRUNCH_MVAX2L 152 +#define CRUNCH_MVAX2M 156 +#define CRUNCH_MVAX2H 160 +#define CRUNCH_MVAX3L 164 +#define CRUNCH_MVAX3M 168 +#define CRUNCH_MVAX3H 172 +#define CRUNCH_DSPSC 176 + +#define CRUNCH_SIZE 184 + + .text + +/* + * Lazy switching of crunch coprocessor context + * + * r10 = struct thread_info pointer + * r9 = ret_from_exception + * lr = undefined instr exit + * + * called from prefetch exception handler with interrupts enabled + */ +ENTRY(crunch_task_enable) + inc_preempt_count r10, r3 + + ldr r8, =(EP93XX_APB_VIRT_BASE + 0x00130000) @ syscon addr + + ldr r1, [r8, #0x80] + tst r1, #0x00800000 @ access to crunch enabled? + bne 2f @ if so no business here + mov r3, #0xaa @ unlock syscon swlock + str r3, [r8, #0xc0] + orr r1, r1, #0x00800000 @ enable access to crunch + str r1, [r8, #0x80] + + ldr r3, =crunch_owner + add r0, r10, #TI_CRUNCH_STATE @ get task crunch save area + ldr r2, [sp, #60] @ current task pc value + ldr r1, [r3] @ get current crunch owner + str r0, [r3] @ this task now owns crunch + sub r2, r2, #4 @ adjust pc back + str r2, [sp, #60] + + ldr r2, [r8, #0x80] + mov r2, r2 @ flush out enable (@@@) + + teq r1, #0 @ test for last ownership + mov lr, r9 @ normal exit from exception + beq crunch_load @ no owner, skip save + +crunch_save: + cfstr64 mvdx0, [r1, #CRUNCH_MVDX0] @ save 64b registers + cfstr64 mvdx1, [r1, #CRUNCH_MVDX1] + cfstr64 mvdx2, [r1, #CRUNCH_MVDX2] + cfstr64 mvdx3, [r1, #CRUNCH_MVDX3] + cfstr64 mvdx4, [r1, #CRUNCH_MVDX4] + cfstr64 mvdx5, [r1, #CRUNCH_MVDX5] + cfstr64 mvdx6, [r1, #CRUNCH_MVDX6] + cfstr64 mvdx7, [r1, #CRUNCH_MVDX7] + cfstr64 mvdx8, [r1, #CRUNCH_MVDX8] + cfstr64 mvdx9, [r1, #CRUNCH_MVDX9] + cfstr64 mvdx10, [r1, #CRUNCH_MVDX10] + cfstr64 mvdx11, [r1, #CRUNCH_MVDX11] + cfstr64 mvdx12, [r1, #CRUNCH_MVDX12] + cfstr64 mvdx13, [r1, #CRUNCH_MVDX13] + cfstr64 mvdx14, [r1, #CRUNCH_MVDX14] + cfstr64 mvdx15, [r1, #CRUNCH_MVDX15] + +#ifdef __ARMEB__ +#error fix me for ARMEB +#endif + + cfmv32al mvfx0, mvax0 @ save 72b accumulators + cfstr32 mvfx0, [r1, #CRUNCH_MVAX0L] + cfmv32am mvfx0, mvax0 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX0M] + cfmv32ah mvfx0, mvax0 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX0H] + cfmv32al mvfx0, mvax1 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX1L] + cfmv32am mvfx0, mvax1 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX1M] + cfmv32ah mvfx0, mvax1 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX1H] + cfmv32al mvfx0, mvax2 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX2L] + cfmv32am mvfx0, mvax2 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX2M] + cfmv32ah mvfx0, mvax2 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX2H] + cfmv32al mvfx0, mvax3 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX3L] + cfmv32am mvfx0, mvax3 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX3M] + cfmv32ah mvfx0, mvax3 + cfstr32 mvfx0, [r1, #CRUNCH_MVAX3H] + + cfmv32sc mvdx0, dspsc @ save status word + cfstr64 mvdx0, [r1, #CRUNCH_DSPSC] + + teq r0, #0 @ anything to load? + cfldr64eq mvdx0, [r1, #CRUNCH_MVDX0] @ mvdx0 was clobbered + beq 1f + +crunch_load: + cfldr64 mvdx0, [r0, #CRUNCH_DSPSC] @ load status word + cfmvsc32 dspsc, mvdx0 + + cfldr32 mvfx0, [r0, #CRUNCH_MVAX0L] @ load 72b accumulators + cfmval32 mvax0, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX0M] + cfmvam32 mvax0, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX0H] + cfmvah32 mvax0, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX1L] + cfmval32 mvax1, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX1M] + cfmvam32 mvax1, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX1H] + cfmvah32 mvax1, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX2L] + cfmval32 mvax2, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX2M] + cfmvam32 mvax2, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX2H] + cfmvah32 mvax2, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX3L] + cfmval32 mvax3, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX3M] + cfmvam32 mvax3, mvfx0 + cfldr32 mvfx0, [r0, #CRUNCH_MVAX3H] + cfmvah32 mvax3, mvfx0 + + cfldr64 mvdx0, [r0, #CRUNCH_MVDX0] @ load 64b registers + cfldr64 mvdx1, [r0, #CRUNCH_MVDX1] + cfldr64 mvdx2, [r0, #CRUNCH_MVDX2] + cfldr64 mvdx3, [r0, #CRUNCH_MVDX3] + cfldr64 mvdx4, [r0, #CRUNCH_MVDX4] + cfldr64 mvdx5, [r0, #CRUNCH_MVDX5] + cfldr64 mvdx6, [r0, #CRUNCH_MVDX6] + cfldr64 mvdx7, [r0, #CRUNCH_MVDX7] + cfldr64 mvdx8, [r0, #CRUNCH_MVDX8] + cfldr64 mvdx9, [r0, #CRUNCH_MVDX9] + cfldr64 mvdx10, [r0, #CRUNCH_MVDX10] + cfldr64 mvdx11, [r0, #CRUNCH_MVDX11] + cfldr64 mvdx12, [r0, #CRUNCH_MVDX12] + cfldr64 mvdx13, [r0, #CRUNCH_MVDX13] + cfldr64 mvdx14, [r0, #CRUNCH_MVDX14] + cfldr64 mvdx15, [r0, #CRUNCH_MVDX15] + +1: +#ifdef CONFIG_PREEMPT_COUNT + get_thread_info r10 +#endif +2: dec_preempt_count r10, r3 + mov pc, lr + +/* + * Back up crunch regs to save area and disable access to them + * (mainly for gdb or sleep mode usage) + * + * r0 = struct thread_info pointer of target task or NULL for any + */ +ENTRY(crunch_task_disable) + stmfd sp!, {r4, r5, lr} + + mrs ip, cpsr + orr r2, ip, #PSR_I_BIT @ disable interrupts + msr cpsr_c, r2 + + ldr r4, =(EP93XX_APB_VIRT_BASE + 0x00130000) @ syscon addr + + ldr r3, =crunch_owner + add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area + ldr r1, [r3] @ get current crunch owner + teq r1, #0 @ any current owner? + beq 1f @ no: quit + teq r0, #0 @ any owner? + teqne r1, r2 @ or specified one? + bne 1f @ no: quit + + ldr r5, [r4, #0x80] @ enable access to crunch + mov r2, #0xaa + str r2, [r4, #0xc0] + orr r5, r5, #0x00800000 + str r5, [r4, #0x80] + + mov r0, #0 @ nothing to load + str r0, [r3] @ no more current owner + ldr r2, [r4, #0x80] @ flush out enable (@@@) + mov r2, r2 + bl crunch_save + + mov r2, #0xaa @ disable access to crunch + str r2, [r4, #0xc0] + bic r5, r5, #0x00800000 + str r5, [r4, #0x80] + ldr r5, [r4, #0x80] @ flush out enable (@@@) + mov r5, r5 + +1: msr cpsr_c, ip @ restore interrupt mode + ldmfd sp!, {r4, r5, pc} + +/* + * Copy crunch state to given memory address + * + * r0 = struct thread_info pointer of target task + * r1 = memory address where to store crunch state + * + * this is called mainly in the creation of signal stack frames + */ +ENTRY(crunch_task_copy) + mrs ip, cpsr + orr r2, ip, #PSR_I_BIT @ disable interrupts + msr cpsr_c, r2 + + ldr r3, =crunch_owner + add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area + ldr r3, [r3] @ get current crunch owner + teq r2, r3 @ does this task own it... + beq 1f + + @ current crunch values are in the task save area + msr cpsr_c, ip @ restore interrupt mode + mov r0, r1 + mov r1, r2 + mov r2, #CRUNCH_SIZE + b memcpy + +1: @ this task owns crunch regs -- grab a copy from there + mov r0, #0 @ nothing to load + mov r3, lr @ preserve return address + bl crunch_save + msr cpsr_c, ip @ restore interrupt mode + mov pc, r3 + +/* + * Restore crunch state from given memory address + * + * r0 = struct thread_info pointer of target task + * r1 = memory address where to get crunch state from + * + * this is used to restore crunch state when unwinding a signal stack frame + */ +ENTRY(crunch_task_restore) + mrs ip, cpsr + orr r2, ip, #PSR_I_BIT @ disable interrupts + msr cpsr_c, r2 + + ldr r3, =crunch_owner + add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area + ldr r3, [r3] @ get current crunch owner + teq r2, r3 @ does this task own it... + beq 1f + + @ this task doesn't own crunch regs -- use its save area + msr cpsr_c, ip @ restore interrupt mode + mov r0, r2 + mov r2, #CRUNCH_SIZE + b memcpy + +1: @ this task owns crunch regs -- load them directly + mov r0, r1 + mov r1, #0 @ nothing to save + mov r3, lr @ preserve return address + bl crunch_load + msr cpsr_c, ip @ restore interrupt mode + mov pc, r3 diff --git a/arch/arm/mach-ep93xx/crunch.c b/arch/arm/mach-ep93xx/crunch.c new file mode 100644 index 00000000000..a4a2ab9648c --- /dev/null +++ b/arch/arm/mach-ep93xx/crunch.c @@ -0,0 +1,88 @@ +/* + * arch/arm/kernel/crunch.c + * Cirrus MaverickCrunch context switching and handling + * + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + * + * 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/types.h> +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/io.h> + +#include <asm/thread_notify.h> + +#include "soc.h" + +struct crunch_state *crunch_owner; + +void crunch_task_release(struct thread_info *thread) +{ + local_irq_disable(); + if (crunch_owner == &thread->crunchstate) + crunch_owner = NULL; + local_irq_enable(); +} + +static int crunch_enabled(u32 devcfg) +{ + return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA); +} + +static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t) +{ + struct thread_info *thread = (struct thread_info *)t; + struct crunch_state *crunch_state; + u32 devcfg; + + crunch_state = &thread->crunchstate; + + switch (cmd) { + case THREAD_NOTIFY_FLUSH: + memset(crunch_state, 0, sizeof(*crunch_state)); + + /* + * FALLTHROUGH: Ensure we don't try to overwrite our newly + * initialised state information on the first fault. + */ + + case THREAD_NOTIFY_EXIT: + crunch_task_release(thread); + break; + + case THREAD_NOTIFY_SWITCH: + devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG); + if (crunch_enabled(devcfg) || crunch_owner == crunch_state) { + /* + * We don't use ep93xx_syscon_swlocked_write() here + * because we are on the context switch path and + * preemption is already disabled. + */ + devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA; + __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); + __raw_writel(devcfg, EP93XX_SYSCON_DEVCFG); + } + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block crunch_notifier_block = { + .notifier_call = crunch_do, +}; + +int __init crunch_init(void) +{ + thread_register_notifier(&crunch_notifier_block); + elf_hwcap |= HWCAP_CRUNCH; + + return 0; +} diff --git a/arch/arm/mach-ep93xx/dma.c b/arch/arm/mach-ep93xx/dma.c new file mode 100644 index 00000000000..d8bfd02f504 --- /dev/null +++ b/arch/arm/mach-ep93xx/dma.c @@ -0,0 +1,110 @@ +/* + * arch/arm/mach-ep93xx/dma.c + * + * Platform support code for the EP93xx dmaengine driver. + * + * Copyright (C) 2011 Mika Westerberg + * + * This work is based on the original dma-m2p implementation with + * following copyrights: + * + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + * Copyright (C) 2006 Applied Data Systems + * Copyright (C) 2009 Ryan Mallon <rmallon@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <linux/platform_data/dma-ep93xx.h> +#include <mach/hardware.h> + +#include "soc.h" + +#define DMA_CHANNEL(_name, _base, _irq) \ + { .name = (_name), .base = (_base), .irq = (_irq) } + +/* + * DMA M2P channels. + * + * On the EP93xx chip the following peripherals my be allocated to the 10 + * Memory to Internal Peripheral (M2P) channels (5 transmit + 5 receive). + * + * I2S contains 3 Tx and 3 Rx DMA Channels + * AAC contains 3 Tx and 3 Rx DMA Channels + * UART1 contains 1 Tx and 1 Rx DMA Channels + * UART2 contains 1 Tx and 1 Rx DMA Channels + * UART3 contains 1 Tx and 1 Rx DMA Channels + * IrDA contains 1 Tx and 1 Rx DMA Channels + * + * Registers are mapped statically in ep93xx_map_io(). + */ +static struct ep93xx_dma_chan_data ep93xx_dma_m2p_channels[] = { + DMA_CHANNEL("m2p0", EP93XX_DMA_BASE + 0x0000, IRQ_EP93XX_DMAM2P0), + DMA_CHANNEL("m2p1", EP93XX_DMA_BASE + 0x0040, IRQ_EP93XX_DMAM2P1), + DMA_CHANNEL("m2p2", EP93XX_DMA_BASE + 0x0080, IRQ_EP93XX_DMAM2P2), + DMA_CHANNEL("m2p3", EP93XX_DMA_BASE + 0x00c0, IRQ_EP93XX_DMAM2P3), + DMA_CHANNEL("m2p4", EP93XX_DMA_BASE + 0x0240, IRQ_EP93XX_DMAM2P4), + DMA_CHANNEL("m2p5", EP93XX_DMA_BASE + 0x0200, IRQ_EP93XX_DMAM2P5), + DMA_CHANNEL("m2p6", EP93XX_DMA_BASE + 0x02c0, IRQ_EP93XX_DMAM2P6), + DMA_CHANNEL("m2p7", EP93XX_DMA_BASE + 0x0280, IRQ_EP93XX_DMAM2P7), + DMA_CHANNEL("m2p8", EP93XX_DMA_BASE + 0x0340, IRQ_EP93XX_DMAM2P8), + DMA_CHANNEL("m2p9", EP93XX_DMA_BASE + 0x0300, IRQ_EP93XX_DMAM2P9), +}; + +static struct ep93xx_dma_platform_data ep93xx_dma_m2p_data = { + .channels = ep93xx_dma_m2p_channels, + .num_channels = ARRAY_SIZE(ep93xx_dma_m2p_channels), +}; + +static struct platform_device ep93xx_dma_m2p_device = { + .name = "ep93xx-dma-m2p", + .id = -1, + .dev = { + .platform_data = &ep93xx_dma_m2p_data, + }, +}; + +/* + * DMA M2M channels. + * + * There are 2 M2M channels which support memcpy/memset and in addition simple + * hardware requests from/to SSP and IDE. We do not implement an external + * hardware requests. + * + * Registers are mapped statically in ep93xx_map_io(). + */ +static struct ep93xx_dma_chan_data ep93xx_dma_m2m_channels[] = { + DMA_CHANNEL("m2m0", EP93XX_DMA_BASE + 0x0100, IRQ_EP93XX_DMAM2M0), + DMA_CHANNEL("m2m1", EP93XX_DMA_BASE + 0x0140, IRQ_EP93XX_DMAM2M1), +}; + +static struct ep93xx_dma_platform_data ep93xx_dma_m2m_data = { + .channels = ep93xx_dma_m2m_channels, + .num_channels = ARRAY_SIZE(ep93xx_dma_m2m_channels), +}; + +static struct platform_device ep93xx_dma_m2m_device = { + .name = "ep93xx-dma-m2m", + .id = -1, + .dev = { + .platform_data = &ep93xx_dma_m2m_data, + }, +}; + +static int __init ep93xx_dma_init(void) +{ + platform_device_register(&ep93xx_dma_m2p_device); + platform_device_register(&ep93xx_dma_m2m_device); + return 0; +} +arch_initcall(ep93xx_dma_init); diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c deleted file mode 100644 index 8bf8d7c78f1..00000000000 --- a/arch/arm/mach-ep93xx/edb9302.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9302.c - * Cirrus Logic EDB9302 support. - * - * Copyright (C) 2006 George Kashperko <george@chas.com.ua> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> - -static struct physmap_flash_data edb9302_flash_data = { - .width = 2, -}; - -static struct resource edb9302_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9302_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9302_flash_data, - }, - .num_resources = 1, - .resource = &edb9302_flash_resource, -}; - -static struct ep93xx_eth_data edb9302_eth_data = { - .phy_id = 1, -}; - -static void __init edb9302_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9302_flash); - - ep93xx_register_eth(&edb9302_eth_data, 1); -} - -MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board") - /* Maintainer: George Kashperko <george@chas.com.ua> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9302_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9302a.c b/arch/arm/mach-ep93xx/edb9302a.c deleted file mode 100644 index a352c57c7b4..00000000000 --- a/arch/arm/mach-ep93xx/edb9302a.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9302a.c - * Cirrus Logic EDB9302A support. - * - * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> - -static struct physmap_flash_data edb9302a_flash_data = { - .width = 2, -}; - -static struct resource edb9302a_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9302a_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9302a_flash_data, - }, - .num_resources = 1, - .resource = &edb9302a_flash_resource, -}; - -static struct ep93xx_eth_data edb9302a_eth_data = { - .phy_id = 1, -}; - -static void __init edb9302a_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9302a_flash); - - ep93xx_register_eth(&edb9302a_eth_data, 1); -} - -MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board") - /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9302a_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9307.c b/arch/arm/mach-ep93xx/edb9307.c deleted file mode 100644 index 5ab22f63a4e..00000000000 --- a/arch/arm/mach-ep93xx/edb9307.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9307.c - * Cirrus Logic EDB9307 support. - * - * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> - -static struct physmap_flash_data edb9307_flash_data = { - .width = 4, -}; - -static struct resource edb9307_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9307_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9307_flash_data, - }, - .num_resources = 1, - .resource = &edb9307_flash_resource, -}; - -static struct ep93xx_eth_data edb9307_eth_data = { - .phy_id = 1, -}; - -static void __init edb9307_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9307_flash); - - ep93xx_register_eth(&edb9307_eth_data, 1); -} - -MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board") - /* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9307_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9307a.c b/arch/arm/mach-ep93xx/edb9307a.c deleted file mode 100644 index 5b5c22b681b..00000000000 --- a/arch/arm/mach-ep93xx/edb9307a.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9307a.c - * Cirrus Logic EDB9307A support. - * - * Copyright (C) 2008 H Hartley Sweeten <hsweeten@visionengravers.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> - -static struct physmap_flash_data edb9307a_flash_data = { - .width = 2, -}; - -static struct resource edb9307a_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9307a_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9307a_flash_data, - }, - .num_resources = 1, - .resource = &edb9307a_flash_resource, -}; - -static struct ep93xx_eth_data edb9307a_eth_data = { - .phy_id = 1, -}; - -static void __init edb9307a_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9307a_flash); - - ep93xx_register_eth(&edb9307a_eth_data, 1); -} - -MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board") - /* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9307a_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c deleted file mode 100644 index d7179f66d80..00000000000 --- a/arch/arm/mach-ep93xx/edb9312.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9312.c - * Cirrus Logic EDB9312 support. - * - * Copyright (C) 2006 Infosys Technologies Limited - * Toufeeq Hussain <toufeeq_hussain@infosys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> - -static struct physmap_flash_data edb9312_flash_data = { - .width = 4, -}; - -static struct resource edb9312_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9312_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9312_flash_data, - }, - .num_resources = 1, - .resource = &edb9312_flash_resource, -}; - -static struct ep93xx_eth_data edb9312_eth_data = { - .phy_id = 1, -}; - -static void __init edb9312_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9312_flash); - - ep93xx_register_eth(&edb9312_eth_data, 1); -} - -MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board") - /* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9312_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c deleted file mode 100644 index 025af6eaca1..00000000000 --- a/arch/arm/mach-ep93xx/edb9315.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9315.c - * Cirrus Logic EDB9315 support. - * - * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> - -static struct physmap_flash_data edb9315_flash_data = { - .width = 4, -}; - -static struct resource edb9315_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9315_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9315_flash_data, - }, - .num_resources = 1, - .resource = &edb9315_flash_resource, -}; - -static struct ep93xx_eth_data edb9315_eth_data = { - .phy_id = 1, -}; - -static void __init edb9315_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9315_flash); - - ep93xx_register_eth(&edb9315_eth_data, 1); -} - -MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board") - /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9315_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c deleted file mode 100644 index 4c9cc8a39f5..00000000000 --- a/arch/arm/mach-ep93xx/edb9315a.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9315a.c - * Cirrus Logic EDB9315A support. - * - * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> - -static struct physmap_flash_data edb9315a_flash_data = { - .width = 2, -}; - -static struct resource edb9315a_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9315a_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9315a_flash_data, - }, - .num_resources = 1, - .resource = &edb9315a_flash_resource, -}; - -static struct ep93xx_eth_data edb9315a_eth_data = { - .phy_id = 1, -}; - -static void __init edb9315a_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9315a_flash); - - ep93xx_register_eth(&edb9315a_eth_data, 1); -} - -MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board") - /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9315a_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c new file mode 100644 index 00000000000..27b14ae92c7 --- /dev/null +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -0,0 +1,374 @@ +/* + * arch/arm/mach-ep93xx/edb93xx.c + * Cirrus Logic EDB93xx Development Board support. + * + * EDB93XX, EDB9301, EDB9307A + * Copyright (C) 2008-2009 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * EDB9302 + * Copyright (C) 2006 George Kashperko <george@chas.com.ua> + * + * EDB9302A, EDB9315, EDB9315A + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + * + * EDB9307 + * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> + * + * EDB9312 + * Copyright (C) 2006 Infosys Technologies Limited + * Toufeeq Hussain <toufeeq_hussain@infosys.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/i2c-gpio.h> +#include <linux/spi/spi.h> + +#include <sound/cs4271.h> + +#include <mach/hardware.h> +#include <linux/platform_data/video-ep93xx.h> +#include <linux/platform_data/spi-ep93xx.h> +#include <mach/gpio-ep93xx.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include "soc.h" + +static void __init edb93xx_register_flash(void) +{ + if (machine_is_edb9307() || machine_is_edb9312() || + machine_is_edb9315()) { + ep93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M); + } else { + ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M); + } +} + +static struct ep93xx_eth_data __initdata edb93xx_eth_data = { + .phy_id = 1, +}; + + +/************************************************************************* + * EDB93xx i2c peripheral handling + *************************************************************************/ +static struct i2c_gpio_platform_data __initdata edb93xx_i2c_gpio_data = { + .sda_pin = EP93XX_GPIO_LINE_EEDAT, + .sda_is_open_drain = 0, + .scl_pin = EP93XX_GPIO_LINE_EECLK, + .scl_is_open_drain = 0, + .udelay = 0, /* default to 100 kHz */ + .timeout = 0, /* default to 100 ms */ +}; + +static struct i2c_board_info __initdata edb93xxa_i2c_board_info[] = { + { + I2C_BOARD_INFO("isl1208", 0x6f), + }, +}; + +static struct i2c_board_info __initdata edb93xx_i2c_board_info[] = { + { + I2C_BOARD_INFO("ds1337", 0x68), + }, +}; + +static void __init edb93xx_register_i2c(void) +{ + if (machine_is_edb9302a() || machine_is_edb9307a() || + machine_is_edb9315a()) { + ep93xx_register_i2c(&edb93xx_i2c_gpio_data, + edb93xxa_i2c_board_info, + ARRAY_SIZE(edb93xxa_i2c_board_info)); + } else if (machine_is_edb9302() || machine_is_edb9307() + || machine_is_edb9312() || machine_is_edb9315()) { + ep93xx_register_i2c(&edb93xx_i2c_gpio_data, + edb93xx_i2c_board_info, + ARRAY_SIZE(edb93xx_i2c_board_info)); + } +} + + +/************************************************************************* + * EDB93xx SPI peripheral handling + *************************************************************************/ +static struct cs4271_platform_data edb93xx_cs4271_data = { + .gpio_nreset = -EINVAL, /* filled in later */ +}; + +static int edb93xx_cs4271_hw_setup(struct spi_device *spi) +{ + return gpio_request_one(EP93XX_GPIO_LINE_EGPIO6, + GPIOF_OUT_INIT_HIGH, spi->modalias); +} + +static void edb93xx_cs4271_hw_cleanup(struct spi_device *spi) +{ + gpio_free(EP93XX_GPIO_LINE_EGPIO6); +} + +static void edb93xx_cs4271_hw_cs_control(struct spi_device *spi, int value) +{ + gpio_set_value(EP93XX_GPIO_LINE_EGPIO6, value); +} + +static struct ep93xx_spi_chip_ops edb93xx_cs4271_hw = { + .setup = edb93xx_cs4271_hw_setup, + .cleanup = edb93xx_cs4271_hw_cleanup, + .cs_control = edb93xx_cs4271_hw_cs_control, +}; + +static struct spi_board_info edb93xx_spi_board_info[] __initdata = { + { + .modalias = "cs4271", + .platform_data = &edb93xx_cs4271_data, + .controller_data = &edb93xx_cs4271_hw, + .max_speed_hz = 6000000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_3, + }, +}; + +static struct ep93xx_spi_info edb93xx_spi_info __initdata = { + .num_chipselect = ARRAY_SIZE(edb93xx_spi_board_info), +}; + +static void __init edb93xx_register_spi(void) +{ + if (machine_is_edb9301() || machine_is_edb9302()) + edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_EGPIO1; + else if (machine_is_edb9302a() || machine_is_edb9307a()) + edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_H(2); + else if (machine_is_edb9315a()) + edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_EGPIO14; + + ep93xx_register_spi(&edb93xx_spi_info, edb93xx_spi_board_info, + ARRAY_SIZE(edb93xx_spi_board_info)); +} + + +/************************************************************************* + * EDB93xx I2S + *************************************************************************/ +static struct platform_device edb93xx_audio_device = { + .name = "edb93xx-audio", + .id = -1, +}; + +static int __init edb93xx_has_audio(void) +{ + return (machine_is_edb9301() || machine_is_edb9302() || + machine_is_edb9302a() || machine_is_edb9307a() || + machine_is_edb9315a()); +} + +static void __init edb93xx_register_i2s(void) +{ + if (edb93xx_has_audio()) { + ep93xx_register_i2s(); + platform_device_register(&edb93xx_audio_device); + } +} + + +/************************************************************************* + * EDB93xx pwm + *************************************************************************/ +static void __init edb93xx_register_pwm(void) +{ + if (machine_is_edb9301() || + machine_is_edb9302() || machine_is_edb9302a()) { + /* EP9301 and EP9302 only have pwm.1 (EGPIO14) */ + ep93xx_register_pwm(0, 1); + } else if (machine_is_edb9307() || machine_is_edb9307a()) { + /* EP9307 only has pwm.0 (PWMOUT) */ + ep93xx_register_pwm(1, 0); + } else { + /* EP9312 and EP9315 have both */ + ep93xx_register_pwm(1, 1); + } +} + + +/************************************************************************* + * EDB93xx framebuffer + *************************************************************************/ +static struct ep93xxfb_mach_info __initdata edb93xxfb_info = { + .num_modes = EP93XXFB_USE_MODEDB, + .bpp = 16, + .flags = 0, +}; + +static int __init edb93xx_has_fb(void) +{ + /* These platforms have an ep93xx with video capability */ + return machine_is_edb9307() || machine_is_edb9307a() || + machine_is_edb9312() || machine_is_edb9315() || + machine_is_edb9315a(); +} + +static void __init edb93xx_register_fb(void) +{ + if (!edb93xx_has_fb()) + return; + + if (machine_is_edb9307a() || machine_is_edb9315a()) + edb93xxfb_info.flags |= EP93XXFB_USE_SDCSN0; + else + edb93xxfb_info.flags |= EP93XXFB_USE_SDCSN3; + + ep93xx_register_fb(&edb93xxfb_info); +} + + +/************************************************************************* + * EDB93xx IDE + *************************************************************************/ +static int __init edb93xx_has_ide(void) +{ + /* + * Although EDB9312 and EDB9315 do have IDE capability, they have + * INTRQ line wired as pull-up, which makes using IDE interface + * problematic. + */ + return machine_is_edb9312() || machine_is_edb9315() || + machine_is_edb9315a(); +} + +static void __init edb93xx_register_ide(void) +{ + if (!edb93xx_has_ide()) + return; + + ep93xx_register_ide(); +} + + +static void __init edb93xx_init_machine(void) +{ + ep93xx_init_devices(); + edb93xx_register_flash(); + ep93xx_register_eth(&edb93xx_eth_data, 1); + edb93xx_register_i2c(); + edb93xx_register_spi(); + edb93xx_register_i2s(); + edb93xx_register_pwm(); + edb93xx_register_fb(); + edb93xx_register_ide(); +} + + +#ifdef CONFIG_MACH_EDB9301 +MACHINE_START(EDB9301, "Cirrus Logic EDB9301 Evaluation Board") + /* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9302 +MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board") + /* Maintainer: George Kashperko <george@chas.com.ua> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9302A +MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board") + /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9307 +MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board") + /* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9307A +MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board") + /* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9312 +MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board") + /* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9315 +MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board") + /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9315A +MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board") + /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c index 3bad500b71b..0cca5b18330 100644 --- a/arch/arm/mach-ep93xx/gesbc9312.c +++ b/arch/arm/mach-ep93xx/gesbc9312.c @@ -12,57 +12,34 @@ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> #include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/i2c.h> +#include <linux/sizes.h> + #include <mach/hardware.h> + #include <asm/mach-types.h> #include <asm/mach/arch.h> -static struct physmap_flash_data gesbc9312_flash_data = { - .width = 4, -}; - -static struct resource gesbc9312_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_8M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device gesbc9312_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &gesbc9312_flash_data, - }, - .num_resources = 1, - .resource = &gesbc9312_flash_resource, -}; +#include "soc.h" -static struct ep93xx_eth_data gesbc9312_eth_data = { +static struct ep93xx_eth_data __initdata gesbc9312_eth_data = { .phy_id = 1, }; static void __init gesbc9312_init_machine(void) { ep93xx_init_devices(); - platform_device_register(&gesbc9312_flash); - + ep93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_8M); ep93xx_register_eth(&gesbc9312_eth_data, 0); } MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx") /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + .atag_offset = 0x100, .map_io = ep93xx_map_io, .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, + .init_time = ep93xx_timer_init, .init_machine = gesbc9312_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c deleted file mode 100644 index 482cf3d2fbc..00000000000 --- a/arch/arm/mach-ep93xx/gpio.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * linux/arch/arm/mach-ep93xx/gpio.c - * - * Generic EP93xx GPIO handling - * - * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.com> - * - * Based on code originally from: - * linux/arch/arm/mach-ep93xx/core.c - * - * 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/init.h> -#include <linux/module.h> -#include <linux/seq_file.h> -#include <linux/io.h> - -#include <mach/ep93xx-regs.h> -#include <asm/gpio.h> - -struct ep93xx_gpio_chip { - struct gpio_chip chip; - - unsigned int data_reg; - unsigned int data_dir_reg; -}; - -#define to_ep93xx_gpio_chip(c) container_of(c, struct ep93xx_gpio_chip, chip) - -/* From core.c */ -extern void ep93xx_gpio_int_mask(unsigned line); -extern void ep93xx_gpio_update_int_params(unsigned port); - -static int ep93xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); - unsigned long flags; - u8 v; - - local_irq_save(flags); - v = __raw_readb(ep93xx_chip->data_dir_reg); - v &= ~(1 << offset); - __raw_writeb(v, ep93xx_chip->data_dir_reg); - local_irq_restore(flags); - - return 0; -} - -static int ep93xx_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int val) -{ - struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); - unsigned long flags; - int line; - u8 v; - - local_irq_save(flags); - - /* Set the value */ - v = __raw_readb(ep93xx_chip->data_reg); - if (val) - v |= (1 << offset); - else - v &= ~(1 << offset); - __raw_writeb(v, ep93xx_chip->data_reg); - - /* Drive as an output */ - line = chip->base + offset; - if (line <= EP93XX_GPIO_LINE_MAX_IRQ) { - /* Ports A/B/F */ - ep93xx_gpio_int_mask(line); - ep93xx_gpio_update_int_params(line >> 3); - } - - v = __raw_readb(ep93xx_chip->data_dir_reg); - v |= (1 << offset); - __raw_writeb(v, ep93xx_chip->data_dir_reg); - - local_irq_restore(flags); - - return 0; -} - -static int ep93xx_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); - - return !!(__raw_readb(ep93xx_chip->data_reg) & (1 << offset)); -} - -static void ep93xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) -{ - struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); - unsigned long flags; - u8 v; - - local_irq_save(flags); - v = __raw_readb(ep93xx_chip->data_reg); - if (val) - v |= (1 << offset); - else - v &= ~(1 << offset); - __raw_writeb(v, ep93xx_chip->data_reg); - local_irq_restore(flags); -} - -static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) -{ - struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip); - u8 data_reg, data_dir_reg; - int i; - - data_reg = __raw_readb(ep93xx_chip->data_reg); - data_dir_reg = __raw_readb(ep93xx_chip->data_dir_reg); - - for (i = 0; i < chip->ngpio; i++) - seq_printf(s, "GPIO %s%d: %s %s\n", chip->label, i, - (data_reg & (1 << i)) ? "set" : "clear", - (data_dir_reg & (1 << i)) ? "out" : "in"); -} - -#define EP93XX_GPIO_BANK(name, dr, ddr, base_gpio) \ - { \ - .chip = { \ - .label = name, \ - .direction_input = ep93xx_gpio_direction_input, \ - .direction_output = ep93xx_gpio_direction_output, \ - .get = ep93xx_gpio_get, \ - .set = ep93xx_gpio_set, \ - .dbg_show = ep93xx_gpio_dbg_show, \ - .base = base_gpio, \ - .ngpio = 8, \ - }, \ - .data_reg = EP93XX_GPIO_REG(dr), \ - .data_dir_reg = EP93XX_GPIO_REG(ddr), \ - } - -static struct ep93xx_gpio_chip ep93xx_gpio_banks[] = { - EP93XX_GPIO_BANK("A", 0x00, 0x10, 0), - EP93XX_GPIO_BANK("B", 0x04, 0x14, 8), - EP93XX_GPIO_BANK("C", 0x08, 0x18, 40), - EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24), - EP93XX_GPIO_BANK("E", 0x20, 0x24, 32), - EP93XX_GPIO_BANK("F", 0x30, 0x34, 16), - EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48), - EP93XX_GPIO_BANK("H", 0x40, 0x44, 56), -}; - -void __init ep93xx_gpio_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) - gpiochip_add(&ep93xx_gpio_banks[i].chip); -} diff --git a/arch/arm/mach-ep93xx/include/mach/clkdev.h b/arch/arm/mach-ep93xx/include/mach/clkdev.h deleted file mode 100644 index 04b37a89801..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/clkdev.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_MACH_CLKDEV_H -#define __ASM_MACH_CLKDEV_H - -#define __clk_get(clk) ({ 1; }) -#define __clk_put(clk) do { } while (0) - -#endif diff --git a/arch/arm/mach-ep93xx/include/mach/debug-macro.S b/arch/arm/mach-ep93xx/include/mach/debug-macro.S deleted file mode 100644 index 802858bc809..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/debug-macro.S +++ /dev/null @@ -1,22 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/debug-macro.S - * Debugging macro include header - * - * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ -#include <mach/ep93xx-regs.h> - - .macro addruart,rx - mrc p15, 0, \rx, c1, c0 - tst \rx, #1 @ MMU enabled? - ldreq \rx, =EP93XX_APB_PHYS_BASE @ Physical base - ldrne \rx, =EP93XX_APB_VIRT_BASE @ virtual base - orr \rx, \rx, #0x000c0000 - .endm - -#include <asm/hardware/debug-pl01x.S> diff --git a/arch/arm/mach-ep93xx/include/mach/entry-macro.S b/arch/arm/mach-ep93xx/include/mach/entry-macro.S deleted file mode 100644 index 96b85e2c2c0..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/entry-macro.S +++ /dev/null @@ -1,59 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/entry-macro.S - * IRQ demultiplexing for EP93xx - * - * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ -#include <mach/ep93xx-regs.h> - - .macro disable_fiq - .endm - - .macro get_irqnr_preamble, base, tmp - .endm - - .macro arch_ret_to_user, tmp1, tmp2 - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \base, =(EP93XX_AHB_VIRT_BASE) - orr \base, \base, #0x000b0000 - mov \irqnr, #0 - ldr \irqstat, [\base] @ lower 32 interrupts - cmp \irqstat, #0 - bne 1001f - - eor \base, \base, #0x00070000 - ldr \irqstat, [\base] @ upper 32 interrupts - cmp \irqstat, #0 - beq 1002f - mov \irqnr, #0x20 - -1001: - movs \tmp, \irqstat, lsl #16 - movne \irqstat, \tmp - addeq \irqnr, \irqnr, #16 - - movs \tmp, \irqstat, lsl #8 - movne \irqstat, \tmp - addeq \irqnr, \irqnr, #8 - - movs \tmp, \irqstat, lsl #4 - movne \irqstat, \tmp - addeq \irqnr, \irqnr, #4 - - movs \tmp, \irqstat, lsl #2 - movne \irqstat, \tmp - addeq \irqnr, \irqnr, #2 - - movs \tmp, \irqstat, lsl #1 - addeq \irqnr, \irqnr, #1 - orrs \base, \base, #1 - -1002: - .endm diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h index 22d6c9a6e4c..c64d7424660 100644 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h @@ -6,40 +6,6 @@ #define __ASM_ARCH_EP93XX_REGS_H /* - * EP93xx Physical Memory Map: - * - * The ASDO pin is sampled at system reset to select a synchronous or - * asynchronous boot configuration. When ASDO is "1" (i.e. pulled-up) - * the synchronous boot mode is selected. When ASDO is "0" (i.e - * pulled-down) the asynchronous boot mode is selected. - * - * In synchronous boot mode nSDCE3 is decoded starting at physical address - * 0x00000000 and nCS0 is decoded starting at 0xf0000000. For asynchronous - * boot mode they are swapped with nCS0 decoded at 0x00000000 ann nSDCE3 - * decoded at 0xf0000000. - * - * There is known errata for the EP93xx dealing with External Memory - * Configurations. Please refer to "AN273: EP93xx Silicon Rev E Design - * Guidelines" for more information. This document can be found at: - * - * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf - */ - -#define EP93XX_CS0_PHYS_BASE_ASYNC 0x00000000 /* ASDO Pin = 0 */ -#define EP93XX_SDCE3_PHYS_BASE_SYNC 0x00000000 /* ASDO Pin = 1 */ -#define EP93XX_CS1_PHYS_BASE 0x10000000 -#define EP93XX_CS2_PHYS_BASE 0x20000000 -#define EP93XX_CS3_PHYS_BASE 0x30000000 -#define EP93XX_PCMCIA_PHYS_BASE 0x40000000 -#define EP93XX_CS6_PHYS_BASE 0x60000000 -#define EP93XX_CS7_PHYS_BASE 0x70000000 -#define EP93XX_SDCE0_PHYS_BASE 0xc0000000 -#define EP93XX_SDCE1_PHYS_BASE 0xd0000000 -#define EP93XX_SDCE2_PHYS_BASE 0xe0000000 -#define EP93XX_SDCE3_PHYS_BASE_ASYNC 0xf0000000 /* ASDO Pin = 0 */ -#define EP93XX_CS0_PHYS_BASE_SYNC 0xf0000000 /* ASDO Pin = 1 */ - -/* * EP93xx linux memory map: * * virt phys size @@ -52,116 +18,24 @@ #define EP93XX_AHB_VIRT_BASE 0xfef00000 #define EP93XX_AHB_SIZE 0x00100000 +#define EP93XX_AHB_PHYS(x) (EP93XX_AHB_PHYS_BASE + (x)) +#define EP93XX_AHB_IOMEM(x) IOMEM(EP93XX_AHB_VIRT_BASE + (x)) + #define EP93XX_APB_PHYS_BASE 0x80800000 #define EP93XX_APB_VIRT_BASE 0xfed00000 #define EP93XX_APB_SIZE 0x00200000 +#define EP93XX_APB_PHYS(x) (EP93XX_APB_PHYS_BASE + (x)) +#define EP93XX_APB_IOMEM(x) IOMEM(EP93XX_APB_VIRT_BASE + (x)) -/* AHB peripherals */ -#define EP93XX_DMA_BASE (EP93XX_AHB_VIRT_BASE + 0x00000000) - -#define EP93XX_ETHERNET_BASE (EP93XX_AHB_VIRT_BASE + 0x00010000) -#define EP93XX_ETHERNET_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00010000) - -#define EP93XX_USB_BASE (EP93XX_AHB_VIRT_BASE + 0x00020000) -#define EP93XX_USB_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00020000) - -#define EP93XX_RASTER_BASE (EP93XX_AHB_VIRT_BASE + 0x00030000) - -#define EP93XX_GRAPHICS_ACCEL_BASE (EP93XX_AHB_VIRT_BASE + 0x00040000) - -#define EP93XX_SDRAM_CONTROLLER_BASE (EP93XX_AHB_VIRT_BASE + 0x00060000) - -#define EP93XX_PCMCIA_CONTROLLER_BASE (EP93XX_AHB_VIRT_BASE + 0x00080000) - -#define EP93XX_BOOT_ROM_BASE (EP93XX_AHB_VIRT_BASE + 0x00090000) - -#define EP93XX_IDE_BASE (EP93XX_AHB_VIRT_BASE + 0x000a0000) - -#define EP93XX_VIC1_BASE (EP93XX_AHB_VIRT_BASE + 0x000b0000) - -#define EP93XX_VIC2_BASE (EP93XX_AHB_VIRT_BASE + 0x000c0000) - - -/* APB peripherals */ -#define EP93XX_TIMER_BASE (EP93XX_APB_VIRT_BASE + 0x00010000) -#define EP93XX_TIMER_REG(x) (EP93XX_TIMER_BASE + (x)) -#define EP93XX_TIMER1_LOAD EP93XX_TIMER_REG(0x00) -#define EP93XX_TIMER1_VALUE EP93XX_TIMER_REG(0x04) -#define EP93XX_TIMER1_CONTROL EP93XX_TIMER_REG(0x08) -#define EP93XX_TIMER1_CLEAR EP93XX_TIMER_REG(0x0c) -#define EP93XX_TIMER2_LOAD EP93XX_TIMER_REG(0x20) -#define EP93XX_TIMER2_VALUE EP93XX_TIMER_REG(0x24) -#define EP93XX_TIMER2_CONTROL EP93XX_TIMER_REG(0x28) -#define EP93XX_TIMER2_CLEAR EP93XX_TIMER_REG(0x2c) -#define EP93XX_TIMER4_VALUE_LOW EP93XX_TIMER_REG(0x60) -#define EP93XX_TIMER4_VALUE_HIGH EP93XX_TIMER_REG(0x64) -#define EP93XX_TIMER3_LOAD EP93XX_TIMER_REG(0x80) -#define EP93XX_TIMER3_VALUE EP93XX_TIMER_REG(0x84) -#define EP93XX_TIMER3_CONTROL EP93XX_TIMER_REG(0x88) -#define EP93XX_TIMER3_CLEAR EP93XX_TIMER_REG(0x8c) - -#define EP93XX_I2S_BASE (EP93XX_APB_VIRT_BASE + 0x00020000) - -#define EP93XX_SECURITY_BASE (EP93XX_APB_VIRT_BASE + 0x00030000) - -#define EP93XX_GPIO_BASE (EP93XX_APB_VIRT_BASE + 0x00040000) -#define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x)) -#define EP93XX_GPIO_F_INT_TYPE1 EP93XX_GPIO_REG(0x4c) -#define EP93XX_GPIO_F_INT_TYPE2 EP93XX_GPIO_REG(0x50) -#define EP93XX_GPIO_F_INT_ACK EP93XX_GPIO_REG(0x54) -#define EP93XX_GPIO_F_INT_ENABLE EP93XX_GPIO_REG(0x58) -#define EP93XX_GPIO_F_INT_STATUS EP93XX_GPIO_REG(0x5c) -#define EP93XX_GPIO_A_INT_TYPE1 EP93XX_GPIO_REG(0x90) -#define EP93XX_GPIO_A_INT_TYPE2 EP93XX_GPIO_REG(0x94) -#define EP93XX_GPIO_A_INT_ACK EP93XX_GPIO_REG(0x98) -#define EP93XX_GPIO_A_INT_ENABLE EP93XX_GPIO_REG(0x9c) -#define EP93XX_GPIO_A_INT_STATUS EP93XX_GPIO_REG(0xa0) -#define EP93XX_GPIO_B_INT_TYPE1 EP93XX_GPIO_REG(0xac) -#define EP93XX_GPIO_B_INT_TYPE2 EP93XX_GPIO_REG(0xb0) -#define EP93XX_GPIO_B_INT_ACK EP93XX_GPIO_REG(0xb4) -#define EP93XX_GPIO_B_INT_ENABLE EP93XX_GPIO_REG(0xb8) -#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc) - -#define EP93XX_AAC_BASE (EP93XX_APB_VIRT_BASE + 0x00080000) - -#define EP93XX_SPI_BASE (EP93XX_APB_VIRT_BASE + 0x000a0000) - -#define EP93XX_IRDA_BASE (EP93XX_APB_VIRT_BASE + 0x000b0000) - -#define EP93XX_UART1_BASE (EP93XX_APB_VIRT_BASE + 0x000c0000) -#define EP93XX_UART1_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000c0000) - -#define EP93XX_UART2_BASE (EP93XX_APB_VIRT_BASE + 0x000d0000) -#define EP93XX_UART2_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000d0000) - -#define EP93XX_UART3_BASE (EP93XX_APB_VIRT_BASE + 0x000e0000) -#define EP93XX_UART3_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000e0000) - -#define EP93XX_KEY_MATRIX_BASE (EP93XX_APB_VIRT_BASE + 0x000f0000) - -#define EP93XX_ADC_BASE (EP93XX_APB_VIRT_BASE + 0x00100000) -#define EP93XX_TOUCHSCREEN_BASE (EP93XX_APB_VIRT_BASE + 0x00100000) - -#define EP93XX_PWM_BASE (EP93XX_APB_VIRT_BASE + 0x00110000) - -#define EP93XX_RTC_BASE (EP93XX_APB_VIRT_BASE + 0x00120000) - -#define EP93XX_SYSCON_BASE (EP93XX_APB_VIRT_BASE + 0x00130000) -#define EP93XX_SYSCON_REG(x) (EP93XX_SYSCON_BASE + (x)) -#define EP93XX_SYSCON_POWER_STATE EP93XX_SYSCON_REG(0x00) -#define EP93XX_SYSCON_CLOCK_CONTROL EP93XX_SYSCON_REG(0x04) -#define EP93XX_SYSCON_CLOCK_UARTBAUD 0x20000000 -#define EP93XX_SYSCON_CLOCK_USH_EN 0x10000000 -#define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08) -#define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c) -#define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20) -#define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24) -#define EP93XX_SYSCON_DEVICE_CONFIG EP93XX_SYSCON_REG(0x80) -#define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE 0x00800000 -#define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0) +/* APB UARTs */ +#define EP93XX_UART1_PHYS_BASE EP93XX_APB_PHYS(0x000c0000) +#define EP93XX_UART1_BASE EP93XX_APB_IOMEM(0x000c0000) -#define EP93XX_WATCHDOG_BASE (EP93XX_APB_VIRT_BASE + 0x00140000) +#define EP93XX_UART2_PHYS_BASE EP93XX_APB_PHYS(0x000d0000) +#define EP93XX_UART2_BASE EP93XX_APB_IOMEM(0x000d0000) +#define EP93XX_UART3_PHYS_BASE EP93XX_APB_PHYS(0x000e0000) +#define EP93XX_UART3_BASE EP93XX_APB_IOMEM(0x000e0000) #endif diff --git a/arch/arm/mach-ep93xx/include/mach/gpio.h b/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h index 0a1498ae899..6d7c571a519 100644 --- a/arch/arm/mach-ep93xx/include/mach/gpio.h +++ b/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h @@ -1,9 +1,17 @@ -/* - * arch/arm/mach-ep93xx/include/mach/gpio.h - */ +/* Include file for the EP93XX GPIO controller machine specifics */ -#ifndef __ASM_ARCH_GPIO_H -#define __ASM_ARCH_GPIO_H +#ifndef __GPIO_EP93XX_H +#define __GPIO_EP93XX_H + +#include <mach/ep93xx-regs.h> + +#define EP93XX_GPIO_PHYS_BASE EP93XX_APB_PHYS(0x00040000) +#define EP93XX_GPIO_BASE EP93XX_APB_IOMEM(0x00040000) +#define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x)) +#define EP93XX_GPIO_F_INT_STATUS EP93XX_GPIO_REG(0x5c) +#define EP93XX_GPIO_A_INT_STATUS EP93XX_GPIO_REG(0xa0) +#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc) +#define EP93XX_GPIO_EEDRIVE EP93XX_GPIO_REG(0xc8) /* GPIO port A. */ #define EP93XX_GPIO_LINE_A(x) ((x) + 0) @@ -99,32 +107,4 @@ /* maximum value for irq capable line identifiers */ #define EP93XX_GPIO_LINE_MAX_IRQ EP93XX_GPIO_LINE_F(7) -extern void ep93xx_gpio_int_debounce(unsigned int irq, int enable); - -/* new generic GPIO API - see Documentation/gpio.txt */ - -#include <asm-generic/gpio.h> - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep - -/* - * Map GPIO A0..A7 (0..7) to irq 64..71, - * B0..B7 (7..15) to irq 72..79, and - * F0..F7 (16..24) to irq 80..87. - */ -static inline int gpio_to_irq(unsigned gpio) -{ - if (gpio <= EP93XX_GPIO_LINE_MAX_IRQ) - return 64 + gpio; - - return -EINVAL; -} - -static inline int irq_to_gpio(unsigned irq) -{ - return irq - gpio_to_irq(0); -} - -#endif +#endif /* __GPIO_EP93XX_H */ diff --git a/arch/arm/mach-ep93xx/include/mach/hardware.h b/arch/arm/mach-ep93xx/include/mach/hardware.h index 2866297310b..efcd47815a9 100644 --- a/arch/arm/mach-ep93xx/include/mach/hardware.h +++ b/arch/arm/mach-ep93xx/include/mach/hardware.h @@ -1,15 +1,24 @@ /* * arch/arm/mach-ep93xx/include/mach/hardware.h */ + #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H -#include "ep93xx-regs.h" - -#define pcibios_assign_all_busses() 0 +#include <mach/platform.h> -#include "platform.h" +/* + * The EP93xx has two external crystal oscillators. To generate the + * required high-frequency clocks, the processor uses two phase-locked- + * loops (PLLs) to multiply the incoming external clock signal to much + * higher frequencies that are then divided down by programmable dividers + * to produce the needed clocks. The PLLs operate independently of one + * another. + */ +#define EP93XX_EXT_CLK_RATE 14745600 +#define EP93XX_EXT_RTC_RATE 32768 -#include "ts72xx.h" +#define EP93XX_KEYTCHCLK_DIV4 (EP93XX_EXT_CLK_RATE / 4) +#define EP93XX_KEYTCHCLK_DIV16 (EP93XX_EXT_CLK_RATE / 16) #endif diff --git a/arch/arm/mach-ep93xx/include/mach/io.h b/arch/arm/mach-ep93xx/include/mach/io.h deleted file mode 100644 index fd5f081cc8b..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/io.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/io.h - */ - -#define IO_SPACE_LIMIT 0xffffffff - -#define __io(p) __typesafe_io(p) -#define __mem_pci(p) (p) diff --git a/arch/arm/mach-ep93xx/include/mach/memory.h b/arch/arm/mach-ep93xx/include/mach/memory.h index 5c80c3c8158..c9400cf0051 100644 --- a/arch/arm/mach-ep93xx/include/mach/memory.h +++ b/arch/arm/mach-ep93xx/include/mach/memory.h @@ -5,6 +5,18 @@ #ifndef __ASM_ARCH_MEMORY_H #define __ASM_ARCH_MEMORY_H -#define PHYS_OFFSET UL(0x00000000) +#if defined(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) +#define PLAT_PHYS_OFFSET UL(0x00000000) +#elif defined(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) +#define PLAT_PHYS_OFFSET UL(0xc0000000) +#elif defined(CONFIG_EP93XX_SDCE1_PHYS_OFFSET) +#define PLAT_PHYS_OFFSET UL(0xd0000000) +#elif defined(CONFIG_EP93XX_SDCE2_PHYS_OFFSET) +#define PLAT_PHYS_OFFSET UL(0xe0000000) +#elif defined(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET) +#define PLAT_PHYS_OFFSET UL(0xf0000000) +#else +#error "Kconfig bug: No EP93xx PHYS_OFFSET set" +#endif #endif diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index 05f0f4f2f3c..4c0bbd97f74 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h @@ -4,7 +4,16 @@ #ifndef __ASSEMBLY__ +#include <linux/reboot.h> + +struct device; +struct i2c_gpio_platform_data; struct i2c_board_info; +struct spi_board_info; +struct platform_device; +struct ep93xxfb_mach_info; +struct ep93xx_keypad_platform_data; +struct ep93xx_spi_info; struct ep93xx_eth_data { @@ -14,10 +23,48 @@ struct ep93xx_eth_data void ep93xx_map_io(void); void ep93xx_init_irq(void); -void ep93xx_init_time(unsigned long); + +#define EP93XX_CHIP_REV_D0 3 +#define EP93XX_CHIP_REV_D1 4 +#define EP93XX_CHIP_REV_E0 5 +#define EP93XX_CHIP_REV_E1 6 +#define EP93XX_CHIP_REV_E2 7 + +unsigned int ep93xx_chip_revision(void); + +void ep93xx_register_flash(unsigned int width, + resource_size_t start, resource_size_t size); + void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr); -void ep93xx_register_i2c(struct i2c_board_info *devices, int num); -void ep93xx_init_devices(void); -extern struct sys_timer ep93xx_timer; +void ep93xx_register_i2c(struct i2c_gpio_platform_data *data, + struct i2c_board_info *devices, int num); +void ep93xx_register_spi(struct ep93xx_spi_info *info, + struct spi_board_info *devices, int num); +void ep93xx_register_fb(struct ep93xxfb_mach_info *data); +void ep93xx_register_pwm(int pwm0, int pwm1); +int ep93xx_pwm_acquire_gpio(struct platform_device *pdev); +void ep93xx_pwm_release_gpio(struct platform_device *pdev); +void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data); +int ep93xx_keypad_acquire_gpio(struct platform_device *pdev); +void ep93xx_keypad_release_gpio(struct platform_device *pdev); +void ep93xx_register_i2s(void); +int ep93xx_i2s_acquire(void); +void ep93xx_i2s_release(void); +void ep93xx_register_ac97(void); +void ep93xx_register_ide(void); +int ep93xx_ide_acquire_gpio(struct platform_device *pdev); +void ep93xx_ide_release_gpio(struct platform_device *pdev); + +struct device *ep93xx_init_devices(void); +extern void ep93xx_timer_init(void); + +void ep93xx_restart(enum reboot_mode, const char *); +void ep93xx_init_late(void); + +#ifdef CONFIG_CRUNCH +int crunch_init(void); +#else +static inline int crunch_init(void) { return 0; } +#endif #endif diff --git a/arch/arm/mach-ep93xx/include/mach/system.h b/arch/arm/mach-ep93xx/include/mach/system.h deleted file mode 100644 index 67789d0f329..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/system.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/system.h - */ - -#include <mach/hardware.h> - -static inline void arch_idle(void) -{ - cpu_do_idle(); -} - -static inline void arch_reset(char mode) -{ - u32 devicecfg; - - local_irq_disable(); - - devicecfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG); - __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); - __raw_writel(devicecfg | 0x80000000, EP93XX_SYSCON_DEVICE_CONFIG); - __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); - __raw_writel(devicecfg & ~0x80000000, EP93XX_SYSCON_DEVICE_CONFIG); - - while (1) - ; -} diff --git a/arch/arm/mach-ep93xx/include/mach/timex.h b/arch/arm/mach-ep93xx/include/mach/timex.h deleted file mode 100644 index 6b3503b01fa..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/timex.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/timex.h - */ - -#define CLOCK_TICK_RATE 983040 diff --git a/arch/arm/mach-ep93xx/include/mach/uncompress.h b/arch/arm/mach-ep93xx/include/mach/uncompress.h index 16026c2b1c8..03c42e5400d 100644 --- a/arch/arm/mach-ep93xx/include/mach/uncompress.h +++ b/arch/arm/mach-ep93xx/include/mach/uncompress.h @@ -31,26 +31,16 @@ static void __raw_writel(unsigned int value, unsigned int ptr) *((volatile unsigned int *)ptr) = value; } -#if defined(CONFIG_EP93XX_EARLY_UART1) -#define UART_BASE EP93XX_UART1_PHYS_BASE -#elif defined(CONFIG_EP93XX_EARLY_UART2) -#define UART_BASE EP93XX_UART2_PHYS_BASE -#elif defined(CONFIG_EP93XX_EARLY_UART3) -#define UART_BASE EP93XX_UART3_PHYS_BASE -#else -#define UART_BASE EP93XX_UART1_PHYS_BASE -#endif - -#define PHYS_UART_DATA (UART_BASE + 0x00) -#define PHYS_UART_FLAG (UART_BASE + 0x18) +#define PHYS_UART_DATA (CONFIG_DEBUG_UART_PHYS + 0x00) +#define PHYS_UART_FLAG (CONFIG_DEBUG_UART_PHYS + 0x18) #define UART_FLAG_TXFF 0x20 static inline void putc(int c) { int i; - for (i = 0; i < 1000; i++) { - /* Transmit fifo not full? */ + for (i = 0; i < 10000; i++) { + /* Transmit fifo not full? */ if (!(__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF)) break; } @@ -90,5 +80,3 @@ static void arch_decomp_setup(void) { ethernet_reset(); } - -#define arch_decomp_wdog() diff --git a/arch/arm/mach-ep93xx/include/mach/vmalloc.h b/arch/arm/mach-ep93xx/include/mach/vmalloc.h deleted file mode 100644 index aed21cd3fe2..00000000000 --- a/arch/arm/mach-ep93xx/include/mach/vmalloc.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * arch/arm/mach-ep93xx/include/mach/vmalloc.h - */ - -#define VMALLOC_END 0xfe800000 diff --git a/arch/arm/mach-ep93xx/micro9.c b/arch/arm/mach-ep93xx/micro9.c index 15d6815d78c..373583c2982 100644 --- a/arch/arm/mach-ep93xx/micro9.c +++ b/arch/arm/mach-ep93xx/micro9.c @@ -2,127 +2,127 @@ * linux/arch/arm/mach-ep93xx/micro9.c * * Copyright (C) 2006 Contec Steuerungstechnik & Automation GmbH - * Manfred Gruber <manfred.gruber@contec.at> + * Manfred Gruber <m.gruber@tirol.com> + * Copyright (C) 2009 Contec Steuerungstechnik & Automation GmbH + * Hubert Feurstein <hubert.feurstein@contec.at> * * 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/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> #include <linux/kernel.h> -#include <linux/mm.h> +#include <linux/init.h> #include <linux/platform_device.h> -#include <linux/sched.h> #include <linux/io.h> -#include <linux/i2c.h> -#include <linux/mtd/physmap.h> #include <mach/hardware.h> -#include <asm/mach/arch.h> #include <asm/mach-types.h> +#include <asm/mach/arch.h> -static struct ep93xx_eth_data micro9_eth_data = { - .phy_id = 0x1f, -}; +#include "soc.h" -static void __init micro9_init(void) +/************************************************************************* + * Micro9 NOR Flash + * + * Micro9-High has up to 64MB of 32-bit flash on CS1 + * Micro9-Mid has up to 64MB of either 32-bit or 16-bit flash on CS1 + * Micro9-Lite uses a separate MTD map driver for flash support + * Micro9-Slim has up to 64MB of either 32-bit or 16-bit flash on CS1 + *************************************************************************/ +static unsigned int __init micro9_detect_bootwidth(void) { - ep93xx_register_eth(µ9_eth_data, 1); + u32 v; + + /* Detect the bus width of the external flash memory */ + v = __raw_readl(EP93XX_SYSCON_SYSCFG); + if (v & EP93XX_SYSCON_SYSCFG_LCSN7) + return 4; /* 32-bit */ + else + return 2; /* 16-bit */ } -/* - * Micro9-H - */ -#ifdef CONFIG_MACH_MICRO9H -static struct physmap_flash_data micro9h_flash_data = { - .width = 4, -}; +static void __init micro9_register_flash(void) +{ + unsigned int width; + + if (machine_is_micro9()) + width = 4; + else if (machine_is_micro9m() || machine_is_micro9s()) + width = micro9_detect_bootwidth(); + else + width = 0; + + if (width) + ep93xx_register_flash(width, EP93XX_CS1_PHYS_BASE, SZ_64M); +} -static struct resource micro9h_flash_resource = { - .start = EP93XX_CS1_PHYS_BASE, - .end = EP93XX_CS1_PHYS_BASE + SZ_64M - 1, - .flags = IORESOURCE_MEM, -}; -static struct platform_device micro9h_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = µ9h_flash_data, - }, - .num_resources = 1, - .resource = µ9h_flash_resource, +/************************************************************************* + * Micro9 Ethernet + *************************************************************************/ +static struct ep93xx_eth_data __initdata micro9_eth_data = { + .phy_id = 0x1f, }; -static void __init micro9h_init(void) -{ - platform_device_register(µ9h_flash); -} -static void __init micro9h_init_machine(void) +static void __init micro9_init_machine(void) { ep93xx_init_devices(); - micro9_init(); - micro9h_init(); + ep93xx_register_eth(µ9_eth_data, 1); + micro9_register_flash(); } -MACHINE_START(MICRO9, "Contec Hypercontrol Micro9-H") - /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + +#ifdef CONFIG_MACH_MICRO9H +MACHINE_START(MICRO9, "Contec Micro9-High") + /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */ + .atag_offset = 0x100, .map_io = ep93xx_map_io, .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = micro9h_init_machine, + .init_time = ep93xx_timer_init, + .init_machine = micro9_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, MACHINE_END #endif -/* - * Micro9-M - */ #ifdef CONFIG_MACH_MICRO9M -static void __init micro9m_init_machine(void) -{ - ep93xx_init_devices(); - micro9_init(); -} - -MACHINE_START(MICRO9M, "Contec Hypercontrol Micro9-M") - /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, +MACHINE_START(MICRO9M, "Contec Micro9-Mid") + /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */ + .atag_offset = 0x100, .map_io = ep93xx_map_io, .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = micro9m_init_machine, + .init_time = ep93xx_timer_init, + .init_machine = micro9_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, MACHINE_END #endif -/* - * Micro9-L - */ #ifdef CONFIG_MACH_MICRO9L -static void __init micro9l_init_machine(void) -{ - ep93xx_init_devices(); - micro9_init(); -} - -MACHINE_START(MICRO9L, "Contec Hypercontrol Micro9-L") - /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, +MACHINE_START(MICRO9L, "Contec Micro9-Lite") + /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */ + .atag_offset = 0x100, .map_io = ep93xx_map_io, .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = micro9l_init_machine, + .init_time = ep93xx_timer_init, + .init_machine = micro9_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, MACHINE_END #endif +#ifdef CONFIG_MACH_MICRO9S +MACHINE_START(MICRO9S, "Contec Micro9-Slim") + /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = micro9_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END +#endif diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c new file mode 100644 index 00000000000..36f22c1a31f --- /dev/null +++ b/arch/arm/mach-ep93xx/simone.c @@ -0,0 +1,89 @@ +/* + * arch/arm/mach-ep93xx/simone.c + * Simplemachines Sim.One support. + * + * Copyright (C) 2010 Ryan Mallon + * + * Based on the 2.6.24.7 support: + * Copyright (C) 2009 Simplemachines + * MMC support by Peter Ivanov <ivanovp@gmail.com>, 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/i2c-gpio.h> + +#include <mach/hardware.h> +#include <linux/platform_data/video-ep93xx.h> +#include <mach/gpio-ep93xx.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include "soc.h" + +static struct ep93xx_eth_data __initdata simone_eth_data = { + .phy_id = 1, +}; + +static struct ep93xxfb_mach_info __initdata simone_fb_info = { + .num_modes = EP93XXFB_USE_MODEDB, + .bpp = 16, + .flags = EP93XXFB_USE_SDCSN0 | EP93XXFB_PCLK_FALLING, +}; + +static struct i2c_gpio_platform_data __initdata simone_i2c_gpio_data = { + .sda_pin = EP93XX_GPIO_LINE_EEDAT, + .sda_is_open_drain = 0, + .scl_pin = EP93XX_GPIO_LINE_EECLK, + .scl_is_open_drain = 0, + .udelay = 0, + .timeout = 0, +}; + +static struct i2c_board_info __initdata simone_i2c_board_info[] = { + { + I2C_BOARD_INFO("ds1337", 0x68), + }, +}; + +static struct platform_device simone_audio_device = { + .name = "simone-audio", + .id = -1, +}; + +static void __init simone_register_audio(void) +{ + ep93xx_register_ac97(); + platform_device_register(&simone_audio_device); +} + +static void __init simone_init_machine(void) +{ + ep93xx_init_devices(); + ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_8M); + ep93xx_register_eth(&simone_eth_data, 1); + ep93xx_register_fb(&simone_fb_info); + ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info, + ARRAY_SIZE(simone_i2c_board_info)); + simone_register_audio(); +} + +MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board") + /* Maintainer: Ryan Mallon */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = simone_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c new file mode 100644 index 00000000000..aa86f86638d --- /dev/null +++ b/arch/arm/mach-ep93xx/snappercl15.c @@ -0,0 +1,182 @@ +/* + * arch/arm/mach-ep93xx/snappercl15.c + * Bluewater Systems Snapper CL15 system module + * + * Copyright (C) 2009 Bluewater Systems Ltd + * Author: Ryan Mallon + * + * NAND code adapted from driver by: + * Andre Renaud <andre@bluewatersys.com> + * James R. McKaskill + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + */ + +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/i2c-gpio.h> +#include <linux/fb.h> + +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand.h> + +#include <mach/hardware.h> +#include <linux/platform_data/video-ep93xx.h> +#include <mach/gpio-ep93xx.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include "soc.h" + +#define SNAPPERCL15_NAND_BASE (EP93XX_CS7_PHYS_BASE + SZ_16M) + +#define SNAPPERCL15_NAND_WPN (1 << 8) /* Write protect (active low) */ +#define SNAPPERCL15_NAND_ALE (1 << 9) /* Address latch */ +#define SNAPPERCL15_NAND_CLE (1 << 10) /* Command latch */ +#define SNAPPERCL15_NAND_CEN (1 << 11) /* Chip enable (active low) */ +#define SNAPPERCL15_NAND_RDY (1 << 14) /* Device ready */ + +#define NAND_CTRL_ADDR(chip) (chip->IO_ADDR_W + 0x40) + +static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + static u16 nand_state = SNAPPERCL15_NAND_WPN; + u16 set; + + if (ctrl & NAND_CTRL_CHANGE) { + set = SNAPPERCL15_NAND_CEN | SNAPPERCL15_NAND_WPN; + + if (ctrl & NAND_NCE) + set &= ~SNAPPERCL15_NAND_CEN; + if (ctrl & NAND_CLE) + set |= SNAPPERCL15_NAND_CLE; + if (ctrl & NAND_ALE) + set |= SNAPPERCL15_NAND_ALE; + + nand_state &= ~(SNAPPERCL15_NAND_CEN | + SNAPPERCL15_NAND_CLE | + SNAPPERCL15_NAND_ALE); + nand_state |= set; + __raw_writew(nand_state, NAND_CTRL_ADDR(chip)); + } + + if (cmd != NAND_CMD_NONE) + __raw_writew((cmd & 0xff) | nand_state, chip->IO_ADDR_W); +} + +static int snappercl15_nand_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + + return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY); +} + +static struct mtd_partition snappercl15_nand_parts[] = { + { + .name = "Kernel", + .offset = 0, + .size = SZ_2M, + }, + { + .name = "Filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct platform_nand_data snappercl15_nand_data = { + .chip = { + .nr_chips = 1, + .partitions = snappercl15_nand_parts, + .nr_partitions = ARRAY_SIZE(snappercl15_nand_parts), + .chip_delay = 25, + }, + .ctrl = { + .dev_ready = snappercl15_nand_dev_ready, + .cmd_ctrl = snappercl15_nand_cmd_ctrl, + }, +}; + +static struct resource snappercl15_nand_resource[] = { + { + .start = SNAPPERCL15_NAND_BASE, + .end = SNAPPERCL15_NAND_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device snappercl15_nand_device = { + .name = "gen_nand", + .id = -1, + .dev.platform_data = &snappercl15_nand_data, + .resource = snappercl15_nand_resource, + .num_resources = ARRAY_SIZE(snappercl15_nand_resource), +}; + +static struct ep93xx_eth_data __initdata snappercl15_eth_data = { + .phy_id = 1, +}; + +static struct i2c_gpio_platform_data __initdata snappercl15_i2c_gpio_data = { + .sda_pin = EP93XX_GPIO_LINE_EEDAT, + .sda_is_open_drain = 0, + .scl_pin = EP93XX_GPIO_LINE_EECLK, + .scl_is_open_drain = 0, + .udelay = 0, + .timeout = 0, +}; + +static struct i2c_board_info __initdata snappercl15_i2c_data[] = { + { + /* Audio codec */ + I2C_BOARD_INFO("tlv320aic23", 0x1a), + }, +}; + +static struct ep93xxfb_mach_info __initdata snappercl15_fb_info = { + .num_modes = EP93XXFB_USE_MODEDB, + .bpp = 16, +}; + +static struct platform_device snappercl15_audio_device = { + .name = "snappercl15-audio", + .id = -1, +}; + +static void __init snappercl15_register_audio(void) +{ + ep93xx_register_i2s(); + platform_device_register(&snappercl15_audio_device); +} + +static void __init snappercl15_init_machine(void) +{ + ep93xx_init_devices(); + ep93xx_register_eth(&snappercl15_eth_data, 1); + ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data, + ARRAY_SIZE(snappercl15_i2c_data)); + ep93xx_register_fb(&snappercl15_fb_info); + snappercl15_register_audio(); + platform_device_register(&snappercl15_nand_device); +} + +MACHINE_START(SNAPPER_CL15, "Bluewater Systems Snapper CL15") + /* Maintainer: Ryan Mallon */ + .atag_offset = 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = snappercl15_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END diff --git a/arch/arm/mach-ep93xx/soc.h b/arch/arm/mach-ep93xx/soc.h new file mode 100644 index 00000000000..7bf7ff8beae --- /dev/null +++ b/arch/arm/mach-ep93xx/soc.h @@ -0,0 +1,214 @@ +/* + * arch/arm/mach-ep93xx/soc.h + * + * Copyright (C) 2012 Open Kernel Labs <www.ok-labs.com> + * Copyright (C) 2012 Ryan Mallon <rmallon@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#ifndef _EP93XX_SOC_H +#define _EP93XX_SOC_H + +#include <mach/ep93xx-regs.h> + +/* + * EP93xx Physical Memory Map: + * + * The ASDO pin is sampled at system reset to select a synchronous or + * asynchronous boot configuration. When ASDO is "1" (i.e. pulled-up) + * the synchronous boot mode is selected. When ASDO is "0" (i.e + * pulled-down) the asynchronous boot mode is selected. + * + * In synchronous boot mode nSDCE3 is decoded starting at physical address + * 0x00000000 and nCS0 is decoded starting at 0xf0000000. For asynchronous + * boot mode they are swapped with nCS0 decoded at 0x00000000 ann nSDCE3 + * decoded at 0xf0000000. + * + * There is known errata for the EP93xx dealing with External Memory + * Configurations. Please refer to "AN273: EP93xx Silicon Rev E Design + * Guidelines" for more information. This document can be found at: + * + * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf + */ + +#define EP93XX_CS0_PHYS_BASE_ASYNC 0x00000000 /* ASDO Pin = 0 */ +#define EP93XX_SDCE3_PHYS_BASE_SYNC 0x00000000 /* ASDO Pin = 1 */ +#define EP93XX_CS1_PHYS_BASE 0x10000000 +#define EP93XX_CS2_PHYS_BASE 0x20000000 +#define EP93XX_CS3_PHYS_BASE 0x30000000 +#define EP93XX_PCMCIA_PHYS_BASE 0x40000000 +#define EP93XX_CS6_PHYS_BASE 0x60000000 +#define EP93XX_CS7_PHYS_BASE 0x70000000 +#define EP93XX_SDCE0_PHYS_BASE 0xc0000000 +#define EP93XX_SDCE1_PHYS_BASE 0xd0000000 +#define EP93XX_SDCE2_PHYS_BASE 0xe0000000 +#define EP93XX_SDCE3_PHYS_BASE_ASYNC 0xf0000000 /* ASDO Pin = 0 */ +#define EP93XX_CS0_PHYS_BASE_SYNC 0xf0000000 /* ASDO Pin = 1 */ + +/* AHB peripherals */ +#define EP93XX_DMA_BASE EP93XX_AHB_IOMEM(0x00000000) + +#define EP93XX_ETHERNET_PHYS_BASE EP93XX_AHB_PHYS(0x00010000) +#define EP93XX_ETHERNET_BASE EP93XX_AHB_IOMEM(0x00010000) + +#define EP93XX_USB_PHYS_BASE EP93XX_AHB_PHYS(0x00020000) +#define EP93XX_USB_BASE EP93XX_AHB_IOMEM(0x00020000) + +#define EP93XX_RASTER_PHYS_BASE EP93XX_AHB_PHYS(0x00030000) +#define EP93XX_RASTER_BASE EP93XX_AHB_IOMEM(0x00030000) + +#define EP93XX_GRAPHICS_ACCEL_BASE EP93XX_AHB_IOMEM(0x00040000) + +#define EP93XX_SDRAM_CONTROLLER_BASE EP93XX_AHB_IOMEM(0x00060000) + +#define EP93XX_PCMCIA_CONTROLLER_BASE EP93XX_AHB_IOMEM(0x00080000) + +#define EP93XX_BOOT_ROM_BASE EP93XX_AHB_IOMEM(0x00090000) + +#define EP93XX_IDE_PHYS_BASE EP93XX_AHB_PHYS(0x000a0000) +#define EP93XX_IDE_BASE EP93XX_AHB_IOMEM(0x000a0000) + +#define EP93XX_VIC1_BASE EP93XX_AHB_IOMEM(0x000b0000) + +#define EP93XX_VIC2_BASE EP93XX_AHB_IOMEM(0x000c0000) + +/* APB peripherals */ +#define EP93XX_TIMER_BASE EP93XX_APB_IOMEM(0x00010000) + +#define EP93XX_I2S_PHYS_BASE EP93XX_APB_PHYS(0x00020000) +#define EP93XX_I2S_BASE EP93XX_APB_IOMEM(0x00020000) + +#define EP93XX_SECURITY_BASE EP93XX_APB_IOMEM(0x00030000) + +#define EP93XX_AAC_PHYS_BASE EP93XX_APB_PHYS(0x00080000) +#define EP93XX_AAC_BASE EP93XX_APB_IOMEM(0x00080000) + +#define EP93XX_SPI_PHYS_BASE EP93XX_APB_PHYS(0x000a0000) +#define EP93XX_SPI_BASE EP93XX_APB_IOMEM(0x000a0000) + +#define EP93XX_IRDA_BASE EP93XX_APB_IOMEM(0x000b0000) + +#define EP93XX_KEY_MATRIX_PHYS_BASE EP93XX_APB_PHYS(0x000f0000) +#define EP93XX_KEY_MATRIX_BASE EP93XX_APB_IOMEM(0x000f0000) + +#define EP93XX_ADC_BASE EP93XX_APB_IOMEM(0x00100000) +#define EP93XX_TOUCHSCREEN_BASE EP93XX_APB_IOMEM(0x00100000) + +#define EP93XX_PWM_PHYS_BASE EP93XX_APB_PHYS(0x00110000) +#define EP93XX_PWM_BASE EP93XX_APB_IOMEM(0x00110000) + +#define EP93XX_RTC_PHYS_BASE EP93XX_APB_PHYS(0x00120000) +#define EP93XX_RTC_BASE EP93XX_APB_IOMEM(0x00120000) + +#define EP93XX_WATCHDOG_PHYS_BASE EP93XX_APB_PHYS(0x00140000) +#define EP93XX_WATCHDOG_BASE EP93XX_APB_IOMEM(0x00140000) + +/* System controller */ +#define EP93XX_SYSCON_BASE EP93XX_APB_IOMEM(0x00130000) +#define EP93XX_SYSCON_REG(x) (EP93XX_SYSCON_BASE + (x)) +#define EP93XX_SYSCON_POWER_STATE EP93XX_SYSCON_REG(0x00) +#define EP93XX_SYSCON_PWRCNT EP93XX_SYSCON_REG(0x04) +#define EP93XX_SYSCON_PWRCNT_FIR_EN (1<<31) +#define EP93XX_SYSCON_PWRCNT_UARTBAUD (1<<29) +#define EP93XX_SYSCON_PWRCNT_USH_EN (1<<28) +#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 (1<<27) +#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 (1<<26) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 (1<<25) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 (1<<24) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 (1<<23) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 (1<<22) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 (1<<21) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 (1<<20) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 (1<<19) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 (1<<18) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 (1<<17) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 (1<<16) +#define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08) +#define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c) +#define EP93XX_SYSCON_CLKSET1 EP93XX_SYSCON_REG(0x20) +#define EP93XX_SYSCON_CLKSET1_NBYP1 (1<<23) +#define EP93XX_SYSCON_CLKSET2 EP93XX_SYSCON_REG(0x24) +#define EP93XX_SYSCON_CLKSET2_NBYP2 (1<<19) +#define EP93XX_SYSCON_CLKSET2_PLL2_EN (1<<18) +#define EP93XX_SYSCON_DEVCFG EP93XX_SYSCON_REG(0x80) +#define EP93XX_SYSCON_DEVCFG_SWRST (1<<31) +#define EP93XX_SYSCON_DEVCFG_D1ONG (1<<30) +#define EP93XX_SYSCON_DEVCFG_D0ONG (1<<29) +#define EP93XX_SYSCON_DEVCFG_IONU2 (1<<28) +#define EP93XX_SYSCON_DEVCFG_GONK (1<<27) +#define EP93XX_SYSCON_DEVCFG_TONG (1<<26) +#define EP93XX_SYSCON_DEVCFG_MONG (1<<25) +#define EP93XX_SYSCON_DEVCFG_U3EN (1<<24) +#define EP93XX_SYSCON_DEVCFG_CPENA (1<<23) +#define EP93XX_SYSCON_DEVCFG_A2ONG (1<<22) +#define EP93XX_SYSCON_DEVCFG_A1ONG (1<<21) +#define EP93XX_SYSCON_DEVCFG_U2EN (1<<20) +#define EP93XX_SYSCON_DEVCFG_EXVC (1<<19) +#define EP93XX_SYSCON_DEVCFG_U1EN (1<<18) +#define EP93XX_SYSCON_DEVCFG_TIN (1<<17) +#define EP93XX_SYSCON_DEVCFG_HC3IN (1<<15) +#define EP93XX_SYSCON_DEVCFG_HC3EN (1<<14) +#define EP93XX_SYSCON_DEVCFG_HC1IN (1<<13) +#define EP93XX_SYSCON_DEVCFG_HC1EN (1<<12) +#define EP93XX_SYSCON_DEVCFG_HONIDE (1<<11) +#define EP93XX_SYSCON_DEVCFG_GONIDE (1<<10) +#define EP93XX_SYSCON_DEVCFG_PONG (1<<9) +#define EP93XX_SYSCON_DEVCFG_EONIDE (1<<8) +#define EP93XX_SYSCON_DEVCFG_I2SONSSP (1<<7) +#define EP93XX_SYSCON_DEVCFG_I2SONAC97 (1<<6) +#define EP93XX_SYSCON_DEVCFG_RASONP3 (1<<4) +#define EP93XX_SYSCON_DEVCFG_RAS (1<<3) +#define EP93XX_SYSCON_DEVCFG_ADCPD (1<<2) +#define EP93XX_SYSCON_DEVCFG_KEYS (1<<1) +#define EP93XX_SYSCON_DEVCFG_SHENA (1<<0) +#define EP93XX_SYSCON_VIDCLKDIV EP93XX_SYSCON_REG(0x84) +#define EP93XX_SYSCON_CLKDIV_ENABLE (1<<15) +#define EP93XX_SYSCON_CLKDIV_ESEL (1<<14) +#define EP93XX_SYSCON_CLKDIV_PSEL (1<<13) +#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8 +#define EP93XX_SYSCON_I2SCLKDIV EP93XX_SYSCON_REG(0x8c) +#define EP93XX_SYSCON_I2SCLKDIV_SENA (1<<31) +#define EP93XX_SYSCON_I2SCLKDIV_ORIDE (1<<29) +#define EP93XX_SYSCON_I2SCLKDIV_SPOL (1<<19) +#define EP93XX_I2SCLKDIV_SDIV (1 << 16) +#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17) +#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17) +#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17) +#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17) +#define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90) +#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31) +#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16) +#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN (1<<15) +#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV (1<<0) +#define EP93XX_SYSCON_SYSCFG EP93XX_SYSCON_REG(0x9c) +#define EP93XX_SYSCON_SYSCFG_REV_MASK (0xf0000000) +#define EP93XX_SYSCON_SYSCFG_REV_SHIFT (28) +#define EP93XX_SYSCON_SYSCFG_SBOOT (1<<8) +#define EP93XX_SYSCON_SYSCFG_LCSN7 (1<<7) +#define EP93XX_SYSCON_SYSCFG_LCSN6 (1<<6) +#define EP93XX_SYSCON_SYSCFG_LASDO (1<<5) +#define EP93XX_SYSCON_SYSCFG_LEEDA (1<<4) +#define EP93XX_SYSCON_SYSCFG_LEECLK (1<<3) +#define EP93XX_SYSCON_SYSCFG_LCSN2 (1<<1) +#define EP93XX_SYSCON_SYSCFG_LCSN1 (1<<0) +#define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0) + +/* EP93xx System Controller software locked register write */ +void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg); +void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits); + +static inline void ep93xx_devcfg_set_bits(unsigned int bits) +{ + ep93xx_devcfg_set_clear(bits, 0x00); +} + +static inline void ep93xx_devcfg_clear_bits(unsigned int bits) +{ + ep93xx_devcfg_set_clear(0x00, bits); +} + +#endif /* _EP93XX_SOC_H */ diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 7ee024d3482..61f4b5dc4d7 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -10,128 +10,176 @@ * your option) any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/init.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mtd/physmap.h> #include <linux/platform_device.h> -#include <linux/m48t86.h> #include <linux/io.h> -#include <linux/i2c.h> +#include <linux/m48t86.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + #include <mach/hardware.h> + #include <asm/mach-types.h> -#include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/mach/arch.h> + +#include "soc.h" +#include "ts72xx.h" static struct map_desc ts72xx_io_desc[] __initdata = { { - .virtual = TS72XX_MODEL_VIRT_BASE, + .virtual = (unsigned long)TS72XX_MODEL_VIRT_BASE, .pfn = __phys_to_pfn(TS72XX_MODEL_PHYS_BASE), .length = TS72XX_MODEL_SIZE, .type = MT_DEVICE, }, { - .virtual = TS72XX_OPTIONS_VIRT_BASE, + .virtual = (unsigned long)TS72XX_OPTIONS_VIRT_BASE, .pfn = __phys_to_pfn(TS72XX_OPTIONS_PHYS_BASE), .length = TS72XX_OPTIONS_SIZE, .type = MT_DEVICE, }, { - .virtual = TS72XX_OPTIONS2_VIRT_BASE, + .virtual = (unsigned long)TS72XX_OPTIONS2_VIRT_BASE, .pfn = __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE), .length = TS72XX_OPTIONS2_SIZE, .type = MT_DEVICE, }, { - .virtual = TS72XX_RTC_INDEX_VIRT_BASE, + .virtual = (unsigned long)TS72XX_RTC_INDEX_VIRT_BASE, .pfn = __phys_to_pfn(TS72XX_RTC_INDEX_PHYS_BASE), .length = TS72XX_RTC_INDEX_SIZE, .type = MT_DEVICE, }, { - .virtual = TS72XX_RTC_DATA_VIRT_BASE, + .virtual = (unsigned long)TS72XX_RTC_DATA_VIRT_BASE, .pfn = __phys_to_pfn(TS72XX_RTC_DATA_PHYS_BASE), .length = TS72XX_RTC_DATA_SIZE, .type = MT_DEVICE, } }; -static struct map_desc ts72xx_nand_io_desc[] __initdata = { - { - .virtual = TS72XX_NAND_DATA_VIRT_BASE, - .pfn = __phys_to_pfn(TS72XX_NAND1_DATA_PHYS_BASE), - .length = TS72XX_NAND_DATA_SIZE, - .type = MT_DEVICE, - }, { - .virtual = TS72XX_NAND_CONTROL_VIRT_BASE, - .pfn = __phys_to_pfn(TS72XX_NAND1_CONTROL_PHYS_BASE), - .length = TS72XX_NAND_CONTROL_SIZE, - .type = MT_DEVICE, - }, { - .virtual = TS72XX_NAND_BUSY_VIRT_BASE, - .pfn = __phys_to_pfn(TS72XX_NAND1_BUSY_PHYS_BASE), - .length = TS72XX_NAND_BUSY_SIZE, - .type = MT_DEVICE, - } -}; - -static struct map_desc ts72xx_alternate_nand_io_desc[] __initdata = { - { - .virtual = TS72XX_NAND_DATA_VIRT_BASE, - .pfn = __phys_to_pfn(TS72XX_NAND2_DATA_PHYS_BASE), - .length = TS72XX_NAND_DATA_SIZE, - .type = MT_DEVICE, - }, { - .virtual = TS72XX_NAND_CONTROL_VIRT_BASE, - .pfn = __phys_to_pfn(TS72XX_NAND2_CONTROL_PHYS_BASE), - .length = TS72XX_NAND_CONTROL_SIZE, - .type = MT_DEVICE, - }, { - .virtual = TS72XX_NAND_BUSY_VIRT_BASE, - .pfn = __phys_to_pfn(TS72XX_NAND2_BUSY_PHYS_BASE), - .length = TS72XX_NAND_BUSY_SIZE, - .type = MT_DEVICE, - } -}; - static void __init ts72xx_map_io(void) { ep93xx_map_io(); iotable_init(ts72xx_io_desc, ARRAY_SIZE(ts72xx_io_desc)); +} - /* - * The TS-7200 has NOR flash, the other models have NAND flash. - */ - if (!board_is_ts7200()) { - if (is_ts9420_installed()) { - iotable_init(ts72xx_alternate_nand_io_desc, - ARRAY_SIZE(ts72xx_alternate_nand_io_desc)); - } else { - iotable_init(ts72xx_nand_io_desc, - ARRAY_SIZE(ts72xx_nand_io_desc)); - } + +/************************************************************************* + * NAND flash + *************************************************************************/ +#define TS72XX_NAND_CONTROL_ADDR_LINE 22 /* 0xN0400000 */ +#define TS72XX_NAND_BUSY_ADDR_LINE 23 /* 0xN0800000 */ + +static void ts72xx_nand_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + void __iomem *addr = chip->IO_ADDR_R; + unsigned char bits; + + addr += (1 << TS72XX_NAND_CONTROL_ADDR_LINE); + + bits = __raw_readb(addr) & ~0x07; + bits |= (ctrl & NAND_NCE) << 2; /* bit 0 -> bit 2 */ + bits |= (ctrl & NAND_CLE); /* bit 1 -> bit 1 */ + bits |= (ctrl & NAND_ALE) >> 2; /* bit 2 -> bit 0 */ + + __raw_writeb(bits, addr); } + + if (cmd != NAND_CMD_NONE) + __raw_writeb(cmd, chip->IO_ADDR_W); } -static struct physmap_flash_data ts72xx_flash_data = { - .width = 1, +static int ts72xx_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + void __iomem *addr = chip->IO_ADDR_R; + + addr += (1 << TS72XX_NAND_BUSY_ADDR_LINE); + + return !!(__raw_readb(addr) & 0x20); +} + +#define TS72XX_BOOTROM_PART_SIZE (SZ_16K) +#define TS72XX_REDBOOT_PART_SIZE (SZ_2M + SZ_1M) + +static struct mtd_partition ts72xx_nand_parts[] = { + { + .name = "TS-BOOTROM", + .offset = 0, + .size = TS72XX_BOOTROM_PART_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "Linux", + .offset = MTDPART_OFS_RETAIN, + .size = TS72XX_REDBOOT_PART_SIZE, + /* leave so much for last partition */ + }, { + .name = "RedBoot", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, }; -static struct resource ts72xx_flash_resource = { - .start = TS72XX_NOR_PHYS_BASE, - .end = TS72XX_NOR_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, +static struct platform_nand_data ts72xx_nand_data = { + .chip = { + .nr_chips = 1, + .chip_offset = 0, + .chip_delay = 15, + .partitions = ts72xx_nand_parts, + .nr_partitions = ARRAY_SIZE(ts72xx_nand_parts), + }, + .ctrl = { + .cmd_ctrl = ts72xx_nand_hwcontrol, + .dev_ready = ts72xx_nand_device_ready, + }, }; -static struct platform_device ts72xx_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &ts72xx_flash_data, +static struct resource ts72xx_nand_resource[] = { + { + .start = 0, /* filled in later */ + .end = 0, /* filled in later */ + .flags = IORESOURCE_MEM, }, - .num_resources = 1, - .resource = &ts72xx_flash_resource, }; +static struct platform_device ts72xx_nand_flash = { + .name = "gen_nand", + .id = -1, + .dev.platform_data = &ts72xx_nand_data, + .resource = ts72xx_nand_resource, + .num_resources = ARRAY_SIZE(ts72xx_nand_resource), +}; + + +static void __init ts72xx_register_flash(void) +{ + /* + * TS7200 has NOR flash all other TS72xx board have NAND flash. + */ + if (board_is_ts7200()) { + ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M); + } else { + resource_size_t start; + + if (is_ts9420_installed()) + start = EP93XX_CS7_PHYS_BASE; + else + start = EP93XX_CS6_PHYS_BASE; + + ts72xx_nand_resource[0].start = start; + ts72xx_nand_resource[0].end = start + SZ_16M - 1; + + platform_device_register(&ts72xx_nand_flash); + } +} + + static unsigned char ts72xx_rtc_readbyte(unsigned long addr) { __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE); @@ -158,27 +206,47 @@ static struct platform_device ts72xx_rtc_device = { .num_resources = 0, }; -static struct ep93xx_eth_data ts72xx_eth_data = { +static struct resource ts72xx_wdt_resources[] = { + { + .start = TS72XX_WDT_CONTROL_PHYS_BASE, + .end = TS72XX_WDT_CONTROL_PHYS_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = TS72XX_WDT_FEED_PHYS_BASE, + .end = TS72XX_WDT_FEED_PHYS_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ts72xx_wdt_device = { + .name = "ts72xx-wdt", + .id = -1, + .num_resources = ARRAY_SIZE(ts72xx_wdt_resources), + .resource = ts72xx_wdt_resources, +}; + +static struct ep93xx_eth_data __initdata ts72xx_eth_data = { .phy_id = 1, }; static void __init ts72xx_init_machine(void) { ep93xx_init_devices(); - if (board_is_ts7200()) - platform_device_register(&ts72xx_flash); + ts72xx_register_flash(); platform_device_register(&ts72xx_rtc_device); + platform_device_register(&ts72xx_wdt_device); ep93xx_register_eth(&ts72xx_eth_data, 1); } MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + .atag_offset = 0x100, .map_io = ts72xx_map_io, .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, + .init_time = ep93xx_timer_init, .init_machine = ts72xx_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/ts72xx.h index 34ddec081c4..071feaa30ad 100644 --- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h +++ b/arch/arm/mach-ep93xx/ts72xx.h @@ -6,27 +6,27 @@ * TS72xx memory map: * * virt phys size - * febff000 22000000 4K model number register + * febff000 22000000 4K model number register (bits 0-2) * febfe000 22400000 4K options register * febfd000 22800000 4K options register #2 - * febfc000 [67]0000000 4K NAND data register - * febfb000 [67]0400000 4K NAND control register - * febfa000 [67]0800000 4K NAND busy register * febf9000 10800000 4K TS-5620 RTC index register * febf8000 11700000 4K TS-5620 RTC data register */ #define TS72XX_MODEL_PHYS_BASE 0x22000000 -#define TS72XX_MODEL_VIRT_BASE 0xfebff000 +#define TS72XX_MODEL_VIRT_BASE IOMEM(0xfebff000) #define TS72XX_MODEL_SIZE 0x00001000 #define TS72XX_MODEL_TS7200 0x00 #define TS72XX_MODEL_TS7250 0x01 #define TS72XX_MODEL_TS7260 0x02 +#define TS72XX_MODEL_TS7300 0x03 +#define TS72XX_MODEL_TS7400 0x04 +#define TS72XX_MODEL_MASK 0x07 #define TS72XX_OPTIONS_PHYS_BASE 0x22400000 -#define TS72XX_OPTIONS_VIRT_BASE 0xfebfe000 +#define TS72XX_OPTIONS_VIRT_BASE IOMEM(0xfebfe000) #define TS72XX_OPTIONS_SIZE 0x00001000 #define TS72XX_OPTIONS_COM2_RS485 0x02 @@ -34,57 +34,54 @@ #define TS72XX_OPTIONS2_PHYS_BASE 0x22800000 -#define TS72XX_OPTIONS2_VIRT_BASE 0xfebfd000 +#define TS72XX_OPTIONS2_VIRT_BASE IOMEM(0xfebfd000) #define TS72XX_OPTIONS2_SIZE 0x00001000 #define TS72XX_OPTIONS2_TS9420 0x04 #define TS72XX_OPTIONS2_TS9420_BOOT 0x02 -#define TS72XX_NOR_PHYS_BASE 0x60000000 -#define TS72XX_NOR2_PHYS_BASE 0x62000000 - -#define TS72XX_NAND1_DATA_PHYS_BASE 0x60000000 -#define TS72XX_NAND2_DATA_PHYS_BASE 0x70000000 -#define TS72XX_NAND_DATA_VIRT_BASE 0xfebfc000 -#define TS72XX_NAND_DATA_SIZE 0x00001000 - -#define TS72XX_NAND1_CONTROL_PHYS_BASE 0x60400000 -#define TS72XX_NAND2_CONTROL_PHYS_BASE 0x70400000 -#define TS72XX_NAND_CONTROL_VIRT_BASE 0xfebfb000 -#define TS72XX_NAND_CONTROL_SIZE 0x00001000 - -#define TS72XX_NAND1_BUSY_PHYS_BASE 0x60800000 -#define TS72XX_NAND2_BUSY_PHYS_BASE 0x70800000 -#define TS72XX_NAND_BUSY_VIRT_BASE 0xfebfa000 -#define TS72XX_NAND_BUSY_SIZE 0x00001000 - - -#define TS72XX_RTC_INDEX_VIRT_BASE 0xfebf9000 +#define TS72XX_RTC_INDEX_VIRT_BASE IOMEM(0xfebf9000) #define TS72XX_RTC_INDEX_PHYS_BASE 0x10800000 #define TS72XX_RTC_INDEX_SIZE 0x00001000 -#define TS72XX_RTC_DATA_VIRT_BASE 0xfebf8000 +#define TS72XX_RTC_DATA_VIRT_BASE IOMEM(0xfebf8000) #define TS72XX_RTC_DATA_PHYS_BASE 0x11700000 #define TS72XX_RTC_DATA_SIZE 0x00001000 +#define TS72XX_WDT_CONTROL_PHYS_BASE 0x23800000 +#define TS72XX_WDT_FEED_PHYS_BASE 0x23c00000 #ifndef __ASSEMBLY__ -#include <linux/io.h> + +static inline int ts72xx_model(void) +{ + return __raw_readb(TS72XX_MODEL_VIRT_BASE) & TS72XX_MODEL_MASK; +} static inline int board_is_ts7200(void) { - return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7200; + return ts72xx_model() == TS72XX_MODEL_TS7200; } static inline int board_is_ts7250(void) { - return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7250; + return ts72xx_model() == TS72XX_MODEL_TS7250; } static inline int board_is_ts7260(void) { - return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7260; + return ts72xx_model() == TS72XX_MODEL_TS7260; +} + +static inline int board_is_ts7300(void) +{ + return ts72xx_model() == TS72XX_MODEL_TS7300; +} + +static inline int board_is_ts7400(void) +{ + return ts72xx_model() == TS72XX_MODEL_TS7400; } static inline int is_max197_installed(void) diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c new file mode 100644 index 00000000000..6bc1c181581 --- /dev/null +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -0,0 +1,323 @@ +/* + * arch/arm/mach-ep93xx/vision_ep9307.c + * Vision Engraving Systems EP9307 SoM support. + * + * Copyright (C) 2008-2011 Vision Engraving Systems + * H Hartley Sweeten <hsweeten@visionengravers.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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/fb.h> +#include <linux/io.h> +#include <linux/mtd/partitions.h> +#include <linux/i2c.h> +#include <linux/i2c-gpio.h> +#include <linux/platform_data/pca953x.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/spi/mmc_spi.h> +#include <linux/mmc/host.h> + +#include <mach/hardware.h> +#include <linux/platform_data/video-ep93xx.h> +#include <linux/platform_data/spi-ep93xx.h> +#include <mach/gpio-ep93xx.h> + +#include <asm/mach-types.h> +#include <asm/mach/map.h> +#include <asm/mach/arch.h> + +#include "soc.h" + +/************************************************************************* + * Static I/O mappings for the FPGA + *************************************************************************/ +#define VISION_PHYS_BASE EP93XX_CS7_PHYS_BASE +#define VISION_VIRT_BASE 0xfebff000 + +static struct map_desc vision_io_desc[] __initdata = { + { + .virtual = VISION_VIRT_BASE, + .pfn = __phys_to_pfn(VISION_PHYS_BASE), + .length = SZ_4K, + .type = MT_DEVICE, + }, +}; + +static void __init vision_map_io(void) +{ + ep93xx_map_io(); + + iotable_init(vision_io_desc, ARRAY_SIZE(vision_io_desc)); +} + +/************************************************************************* + * Ethernet + *************************************************************************/ +static struct ep93xx_eth_data vision_eth_data __initdata = { + .phy_id = 1, +}; + +/************************************************************************* + * Framebuffer + *************************************************************************/ +#define VISION_LCD_ENABLE EP93XX_GPIO_LINE_EGPIO1 + +static int vision_lcd_setup(struct platform_device *pdev) +{ + int err; + + err = gpio_request_one(VISION_LCD_ENABLE, GPIOF_INIT_HIGH, + dev_name(&pdev->dev)); + if (err) + return err; + + ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_RAS | + EP93XX_SYSCON_DEVCFG_RASONP3 | + EP93XX_SYSCON_DEVCFG_EXVC); + + return 0; +} + +static void vision_lcd_teardown(struct platform_device *pdev) +{ + gpio_free(VISION_LCD_ENABLE); +} + +static void vision_lcd_blank(int blank_mode, struct fb_info *info) +{ + if (blank_mode) + gpio_set_value(VISION_LCD_ENABLE, 0); + else + gpio_set_value(VISION_LCD_ENABLE, 1); +} + +static struct ep93xxfb_mach_info ep93xxfb_info __initdata = { + .num_modes = EP93XXFB_USE_MODEDB, + .bpp = 16, + .flags = EP93XXFB_USE_SDCSN0 | EP93XXFB_PCLK_FALLING, + .setup = vision_lcd_setup, + .teardown = vision_lcd_teardown, + .blank = vision_lcd_blank, +}; + + +/************************************************************************* + * GPIO Expanders + *************************************************************************/ +#define PCA9539_74_GPIO_BASE (EP93XX_GPIO_LINE_MAX + 1) +#define PCA9539_75_GPIO_BASE (PCA9539_74_GPIO_BASE + 16) +#define PCA9539_76_GPIO_BASE (PCA9539_75_GPIO_BASE + 16) +#define PCA9539_77_GPIO_BASE (PCA9539_76_GPIO_BASE + 16) + +static struct pca953x_platform_data pca953x_74_gpio_data = { + .gpio_base = PCA9539_74_GPIO_BASE, + .irq_base = EP93XX_BOARD_IRQ(0), +}; + +static struct pca953x_platform_data pca953x_75_gpio_data = { + .gpio_base = PCA9539_75_GPIO_BASE, + .irq_base = -1, +}; + +static struct pca953x_platform_data pca953x_76_gpio_data = { + .gpio_base = PCA9539_76_GPIO_BASE, + .irq_base = -1, +}; + +static struct pca953x_platform_data pca953x_77_gpio_data = { + .gpio_base = PCA9539_77_GPIO_BASE, + .irq_base = -1, +}; + +/************************************************************************* + * I2C Bus + *************************************************************************/ +static struct i2c_gpio_platform_data vision_i2c_gpio_data __initdata = { + .sda_pin = EP93XX_GPIO_LINE_EEDAT, + .scl_pin = EP93XX_GPIO_LINE_EECLK, +}; + +static struct i2c_board_info vision_i2c_info[] __initdata = { + { + I2C_BOARD_INFO("isl1208", 0x6f), + .irq = IRQ_EP93XX_EXT1, + }, { + I2C_BOARD_INFO("pca9539", 0x74), + .platform_data = &pca953x_74_gpio_data, + }, { + I2C_BOARD_INFO("pca9539", 0x75), + .platform_data = &pca953x_75_gpio_data, + }, { + I2C_BOARD_INFO("pca9539", 0x76), + .platform_data = &pca953x_76_gpio_data, + }, { + I2C_BOARD_INFO("pca9539", 0x77), + .platform_data = &pca953x_77_gpio_data, + }, +}; + +/************************************************************************* + * SPI Flash + *************************************************************************/ +#define VISION_SPI_FLASH_CS EP93XX_GPIO_LINE_EGPIO7 + +static struct mtd_partition vision_spi_flash_partitions[] = { + { + .name = "SPI bootstrap", + .offset = 0, + .size = SZ_4K, + }, { + .name = "Bootstrap config", + .offset = MTDPART_OFS_APPEND, + .size = SZ_4K, + }, { + .name = "System config", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data vision_spi_flash_data = { + .name = "SPI Flash", + .parts = vision_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(vision_spi_flash_partitions), +}; + +static int vision_spi_flash_hw_setup(struct spi_device *spi) +{ + return gpio_request_one(VISION_SPI_FLASH_CS, GPIOF_INIT_HIGH, + spi->modalias); +} + +static void vision_spi_flash_hw_cleanup(struct spi_device *spi) +{ + gpio_free(VISION_SPI_FLASH_CS); +} + +static void vision_spi_flash_hw_cs_control(struct spi_device *spi, int value) +{ + gpio_set_value(VISION_SPI_FLASH_CS, value); +} + +static struct ep93xx_spi_chip_ops vision_spi_flash_hw = { + .setup = vision_spi_flash_hw_setup, + .cleanup = vision_spi_flash_hw_cleanup, + .cs_control = vision_spi_flash_hw_cs_control, +}; + +/************************************************************************* + * SPI SD/MMC host + *************************************************************************/ +#define VISION_SPI_MMC_CS EP93XX_GPIO_LINE_G(2) +#define VISION_SPI_MMC_WP EP93XX_GPIO_LINE_F(0) +#define VISION_SPI_MMC_CD EP93XX_GPIO_LINE_EGPIO15 + +static struct mmc_spi_platform_data vision_spi_mmc_data = { + .detect_delay = 100, + .powerup_msecs = 100, + .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, + .flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO, + .cd_gpio = VISION_SPI_MMC_CD, + .cd_debounce = 1, + .ro_gpio = VISION_SPI_MMC_WP, + .caps2 = MMC_CAP2_RO_ACTIVE_HIGH, +}; + +static int vision_spi_mmc_hw_setup(struct spi_device *spi) +{ + return gpio_request_one(VISION_SPI_MMC_CS, GPIOF_INIT_HIGH, + spi->modalias); +} + +static void vision_spi_mmc_hw_cleanup(struct spi_device *spi) +{ + gpio_free(VISION_SPI_MMC_CS); +} + +static void vision_spi_mmc_hw_cs_control(struct spi_device *spi, int value) +{ + gpio_set_value(VISION_SPI_MMC_CS, value); +} + +static struct ep93xx_spi_chip_ops vision_spi_mmc_hw = { + .setup = vision_spi_mmc_hw_setup, + .cleanup = vision_spi_mmc_hw_cleanup, + .cs_control = vision_spi_mmc_hw_cs_control, +}; + +/************************************************************************* + * SPI Bus + *************************************************************************/ +static struct spi_board_info vision_spi_board_info[] __initdata = { + { + .modalias = "sst25l", + .platform_data = &vision_spi_flash_data, + .controller_data = &vision_spi_flash_hw, + .max_speed_hz = 20000000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_3, + }, { + .modalias = "mmc_spi", + .platform_data = &vision_spi_mmc_data, + .controller_data = &vision_spi_mmc_hw, + .max_speed_hz = 20000000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_3, + }, +}; + +static struct ep93xx_spi_info vision_spi_master __initdata = { + .num_chipselect = ARRAY_SIZE(vision_spi_board_info), +}; + +/************************************************************************* + * Machine Initialization + *************************************************************************/ +static void __init vision_init_machine(void) +{ + ep93xx_init_devices(); + ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_64M); + ep93xx_register_eth(&vision_eth_data, 1); + ep93xx_register_fb(&ep93xxfb_info); + ep93xx_register_pwm(1, 0); + + /* + * Request the gpio expander's interrupt gpio line now to prevent + * the kernel from doing a WARN in gpiolib:gpio_ensure_requested(). + */ + if (gpio_request_one(EP93XX_GPIO_LINE_F(7), GPIOF_DIR_IN, + "pca9539:74")) + pr_warn("cannot request interrupt gpio for pca9539:74\n"); + + vision_i2c_info[1].irq = gpio_to_irq(EP93XX_GPIO_LINE_F(7)); + + ep93xx_register_i2c(&vision_i2c_gpio_data, vision_i2c_info, + ARRAY_SIZE(vision_i2c_info)); + ep93xx_register_spi(&vision_spi_master, vision_spi_board_info, + ARRAY_SIZE(vision_spi_board_info)); +} + +MACHINE_START(VISION_EP9307, "Vision Engraving Systems EP9307") + /* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */ + .atag_offset = 0x100, + .map_io = vision_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = vision_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END |
