diff options
author | Mike Rapoport <mike@compulab.co.il> | 2007-09-23 15:59:26 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-10-15 18:53:57 +0100 |
commit | 3696a8a426f8caebd97463e9b5cf9f06c1c36759 (patch) | |
tree | 217d5ef3219b335f72360cfa7f0f1731443b09bb /arch/arm/mach-pxa | |
parent | 3e0cc7ee045fb53e8215fed7442455c0cee0ee93 (diff) |
[ARM] 4576/1: CM-X270 machine support
This patch provides core support for CM-X270 platform.
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-pxa')
-rw-r--r-- | arch/arm/mach-pxa/Kconfig | 5 | ||||
-rw-r--r-- | arch/arm/mach-pxa/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/mach-pxa/cm-x270-pci.c | 218 | ||||
-rw-r--r-- | arch/arm/mach-pxa/cm-x270-pci.h | 13 | ||||
-rw-r--r-- | arch/arm/mach-pxa/cm-x270.c | 645 |
5 files changed, 887 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index e895188cadc..656d49661a2 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -63,6 +63,11 @@ config MACH_ZYLONITE bool "PXA3xx Development Platform" select PXA3xx +config MACH_ARMCORE + bool "CompuLab CM-X270 modules" + select PXA27x + select IWMMXT + endchoice if PXA_SHARPSL diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index bfdd0c5fcd7..4263527e512 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -29,6 +29,8 @@ ifeq ($(CONFIG_MACH_ZYLONITE),y) obj-$(CONFIG_CPU_PXA320) += zylonite_pxa320.o endif +obj-$(CONFIG_MACH_ARMCORE) += cm-x270.o + # Support for blinky lights led-y := leds.o led-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o @@ -45,3 +47,7 @@ obj-$(CONFIG_PXA_SSP) += ssp.o ifeq ($(CONFIG_PXA27x),y) obj-$(CONFIG_PM) += standby.o endif + +ifeq ($(CONFIG_PCI),y) +obj-$(CONFIG_MACH_ARMCORE) += cm-x270-pci.o +endif diff --git a/arch/arm/mach-pxa/cm-x270-pci.c b/arch/arm/mach-pxa/cm-x270-pci.c new file mode 100644 index 00000000000..878d3b9b863 --- /dev/null +++ b/arch/arm/mach-pxa/cm-x270-pci.c @@ -0,0 +1,218 @@ +/* + * linux/arch/arm/mach-pxa/cm-x270-pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + * + * Copyright (C) 2007 Compulab, Ltd. + * Mike Rapoport <mike@compulab.co.il> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/irq.h> + +#include <asm/mach/pci.h> +#include <asm/arch/cm-x270.h> +#include <asm/arch/pxa-regs.h> +#include <asm/mach-types.h> + +#include <asm/hardware/it8152.h> + +unsigned long it8152_base_address = CMX270_IT8152_VIRT; + +/* + * Only first 64MB of memory can be accessed via PCI. + * We use GFP_DMA to allocate safe buffers to do map/unmap. + * This is really ugly and we need a better way of specifying + * DMA-capable regions of memory. + */ +void __init cmx270_pci_adjust_zones(int node, unsigned long *zone_size, + unsigned long *zhole_size) +{ + unsigned int sz = SZ_64M >> PAGE_SHIFT; + + printk(KERN_INFO "Adjusting zones for CM-x270\n"); + + /* + * Only adjust if > 64M on current system + */ + if (node || (zone_size[0] <= sz)) + return; + + zone_size[1] = zone_size[0] - sz; + zone_size[0] = sz; + zhole_size[1] = zhole_size[0]; + zhole_size[0] = 0; +} + +static void cmx270_it8152_irq_demux(unsigned int irq, struct irq_desc *desc) +{ + /* clear our parent irq */ + GEDR(GPIO_IT8152_IRQ) = GPIO_bit(GPIO_IT8152_IRQ); + + it8152_irq_demux(irq, desc); +} + +void __cmx270_pci_init_irq(void) +{ + it8152_init_irq(); + pxa_gpio_mode(IRQ_TO_GPIO(GPIO_IT8152_IRQ)); + set_irq_type(IRQ_GPIO(GPIO_IT8152_IRQ), IRQT_RISING); + + set_irq_chained_handler(IRQ_GPIO(GPIO_IT8152_IRQ), + cmx270_it8152_irq_demux); +} + +#ifdef CONFIG_PM +static unsigned long sleep_save_ite[10]; + +void __cmx270_pci_suspend(void) +{ + /* save ITE state */ + sleep_save_ite[0] = __raw_readl(IT8152_INTC_PDCNIMR); + sleep_save_ite[1] = __raw_readl(IT8152_INTC_LPCNIMR); + sleep_save_ite[2] = __raw_readl(IT8152_INTC_LPNIAR); + + /* Clear ITE IRQ's */ + __raw_writel((0), IT8152_INTC_PDCNIRR); + __raw_writel((0), IT8152_INTC_LPCNIRR); +} + +void __cmx270_pci_resume(void) +{ + /* restore IT8152 state */ + __raw_writel((sleep_save_ite[0]), IT8152_INTC_PDCNIMR); + __raw_writel((sleep_save_ite[1]), IT8152_INTC_LPCNIMR); + __raw_writel((sleep_save_ite[2]), IT8152_INTC_LPNIAR); +} +#else +void cmx270_pci_suspend(void) {} +void cmx270_pci_resume(void) {} +#endif + +/* PCI IRQ mapping*/ +static int __init cmx270_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + + printk(KERN_DEBUG "===> %s: %s slot=%x, pin=%x\n", __FUNCTION__, + pci_name(dev), slot, pin); + + irq = it8152_pci_map_irq(dev, slot, pin); + if (irq) + return irq; + + /* + Here comes the ugly part. The routing is baseboard specific, + but defining a platform for each possible base of CM-x270 is + unrealistic. Here we keep mapping for ATXBase and SB-x270. + */ + /* ATXBASE PCI slot */ + if (slot == 7) + return IT8152_PCI_INTA; + + /* ATXBase/SB-x270 CardBus */ + if (slot == 8 || slot == 0) + return IT8152_PCI_INTB; + + /* ATXBase Ethernet */ + if (slot == 9) + return IT8152_PCI_INTA; + + /* SB-x270 Ethernet */ + if (slot == 16) + return IT8152_PCI_INTA; + + /* PC104+ interrupt routing */ + if ((slot == 17) || (slot == 19)) + return IT8152_PCI_INTA; + if ((slot == 18) || (slot == 20)) + return IT8152_PCI_INTB; + + return(0); +} + +static struct pci_bus * __init +cmx270_pci_scan_bus(int nr, struct pci_sys_data *sys) +{ + printk(KERN_INFO "Initializing CM-X270 PCI subsystem\n"); + + __raw_writel(0x800, IT8152_PCI_CFG_ADDR); + if (__raw_readl(IT8152_PCI_CFG_DATA) == 0x81521283) { + printk(KERN_INFO "PCI Bridge found.\n"); + + /* set PCI I/O base at 0 */ + writel(0x848, IT8152_PCI_CFG_ADDR); + writel(0, IT8152_PCI_CFG_DATA); + + /* set PCI memory base at 0 */ + writel(0x840, IT8152_PCI_CFG_ADDR); + writel(0, IT8152_PCI_CFG_DATA); + + writel(0x20, IT8152_GPIO_GPDR); + + /* CardBus Controller on ATXbase baseboard */ + writel(0x4000, IT8152_PCI_CFG_ADDR); + if (readl(IT8152_PCI_CFG_DATA) == 0xAC51104C) { + printk(KERN_INFO "CardBus Bridge found.\n"); + + /* Configure socket 0 */ + writel(0x408C, IT8152_PCI_CFG_ADDR); + writel(0x1022, IT8152_PCI_CFG_DATA); + + writel(0x4080, IT8152_PCI_CFG_ADDR); + writel(0x3844d060, IT8152_PCI_CFG_DATA); + + writel(0x4090, IT8152_PCI_CFG_ADDR); + writel(((readl(IT8152_PCI_CFG_DATA) & 0xffff) | + 0x60440000), + IT8152_PCI_CFG_DATA); + + writel(0x4018, IT8152_PCI_CFG_ADDR); + writel(0xb0000000, IT8152_PCI_CFG_DATA); + + /* Configure socket 1 */ + writel(0x418C, IT8152_PCI_CFG_ADDR); + writel(0x1022, IT8152_PCI_CFG_DATA); + + writel(0x4180, IT8152_PCI_CFG_ADDR); + writel(0x3844d060, IT8152_PCI_CFG_DATA); + + writel(0x4190, IT8152_PCI_CFG_ADDR); + writel(((readl(IT8152_PCI_CFG_DATA) & 0xffff) | + 0x60440000), + IT8152_PCI_CFG_DATA); + + writel(0x4118, IT8152_PCI_CFG_ADDR); + writel(0xb0000000, IT8152_PCI_CFG_DATA); + } + } + return it8152_pci_scan_bus(nr, sys); +} + +static struct hw_pci cmx270_pci __initdata = { + .swizzle = pci_std_swizzle, + .map_irq = cmx270_pci_map_irq, + .nr_controllers = 1, + .setup = it8152_pci_setup, + .scan = cmx270_pci_scan_bus, +}; + +static int __init cmx270_init_pci(void) +{ + if (machine_is_armcore()) + pci_common_init(&cmx270_pci); + + return 0; +} + +subsys_initcall(cmx270_init_pci); diff --git a/arch/arm/mach-pxa/cm-x270-pci.h b/arch/arm/mach-pxa/cm-x270-pci.h new file mode 100644 index 00000000000..ffe37b66f9a --- /dev/null +++ b/arch/arm/mach-pxa/cm-x270-pci.h @@ -0,0 +1,13 @@ +extern void __cmx270_pci_init_irq(void); +extern void __cmx270_pci_suspend(void); +extern void __cmx270_pci_resume(void); + +#ifdef CONFIG_PCI +#define cmx270_pci_init_irq __cmx270_pci_init_irq +#define cmx270_pci_suspend __cmx270_pci_suspend +#define cmx270_pci_resume __cmx270_pci_resume +#else +#define cmx270_pci_init_irq() do {} while (0) +#define cmx270_pci_suspend() do {} while (0) +#define cmx270_pci_resume() do {} while (0) +#endif diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c new file mode 100644 index 00000000000..177664ccb2e --- /dev/null +++ b/arch/arm/mach-pxa/cm-x270.c @@ -0,0 +1,645 @@ +/* + * linux/arch/arm/mach-pxa/cm-x270.c + * + * Copyright (C) 2007 CompuLab, Ltd. + * Mike Rapoport <mike@compulab.co.il> + * + * 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/types.h> +#include <linux/pm.h> +#include <linux/fb.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <linux/sysdev.h> +#include <linux/io.h> +#include <linux/delay.h> + +#include <linux/dm9000.h> +#include <linux/rtc-v3020.h> +#include <linux/serial_8250.h> + +#include <video/mbxfb.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> +#include <asm/mach/map.h> + +#include <asm/arch/pxa-regs.h> +#include <asm/arch/pxafb.h> +#include <asm/arch/ohci.h> +#include <asm/arch/mmc.h> +#include <asm/arch/bitfield.h> +#include <asm/arch/cm-x270.h> + +#include <asm/hardware/it8152.h> + +#include "generic.h" +#include "cm-x270-pci.h" + +#define RTC_PHYS_BASE (PXA_CS1_PHYS + (5 << 22)) +#define DM9000_PHYS_BASE (PXA_CS1_PHYS + (6 << 22)) + +static struct resource cmx270_dm9k_resource[] = { + [0] = { + .start = DM9000_PHYS_BASE, + .end = DM9000_PHYS_BASE + 4, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DM9000_PHYS_BASE + 8, + .end = DM9000_PHYS_BASE + 8 + 500, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = CMX270_ETHIRQ, + .end = CMX270_ETHIRQ, + .flags = IORESOURCE_IRQ, + } +}; + +/* for the moment we limit ourselves to 32bit IO until some + * better IO routines can be written and tested + */ +static struct dm9000_plat_data cmx270_dm9k_platdata = { + .flags = DM9000_PLATF_32BITONLY, +}; + +/* Ethernet device */ +static struct platform_device cmx270_device_dm9k = { + .name = "dm9000", + .id = 0, + .num_resources = ARRAY_SIZE(cmx270_dm9k_resource), + .resource = cmx270_dm9k_resource, + .dev = { + .platform_data = &cmx270_dm9k_platdata, + } +}; + +/* audio device */ +static struct platform_device cmx270_audio_device = { + .name = "pxa2xx-ac97", + .id = -1, +}; + +/* touchscreen controller */ +static struct platform_device cmx270_ts_device = { + .name = "ucb1400_ts", + .id = -1, +}; + +/* RTC */ +static struct resource cmx270_v3020_resource[] = { + [0] = { + .start = RTC_PHYS_BASE, + .end = RTC_PHYS_BASE + 4, + .flags = IORESOURCE_MEM, + }, +}; + +struct v3020_platform_data cmx270_v3020_pdata = { + .leftshift = 16, +}; + +static struct platform_device cmx270_rtc_device = { + .name = "v3020", + .num_resources = ARRAY_SIZE(cmx270_v3020_resource), + .resource = cmx270_v3020_resource, + .id = -1, + .dev = { + .platform_data = &cmx270_v3020_pdata, + } +}; + +/* + * CM-X270 LEDs + */ +static struct platform_device cmx270_led_device = { + .name = "cm-x270-led", + .id = -1, +}; + +/* 2700G graphics */ +static u64 fb_dma_mask = ~(u64)0; + +static struct resource cmx270_2700G_resource[] = { + /* frame buffer memory including ODFB and External SDRAM */ + [0] = { + .start = MARATHON_PHYS, + .end = MARATHON_PHYS + 0x02000000, + .flags = IORESOURCE_MEM, + }, + /* Marathon registers */ + [1] = { + .start = MARATHON_PHYS + 0x03fe0000, + .end = MARATHON_PHYS + 0x03ffffff, + .flags = IORESOURCE_MEM, + }, +}; + +static unsigned long save_lcd_regs[10]; + +static int cmx270_marathon_probe(struct fb_info *fb) +{ + /* save PXA-270 pin settings before enabling 2700G */ + save_lcd_regs[0] = GPDR1; + save_lcd_regs[1] = GPDR2; + save_lcd_regs[2] = GAFR1_U; + save_lcd_regs[3] = GAFR2_L; + save_lcd_regs[4] = GAFR2_U; + + /* Disable PXA-270 on-chip controller driving pins */ + GPDR1 &= ~(0xfc000000); + GPDR2 &= ~(0x00c03fff); + GAFR1_U &= ~(0xfff00000); + GAFR2_L &= ~(0x0fffffff); + GAFR2_U &= ~(0x0000f000); + return 0; +} + +static int cmx270_marathon_remove(struct fb_info *fb) +{ + GPDR1 = save_lcd_regs[0]; + GPDR2 = save_lcd_regs[1]; + GAFR1_U = save_lcd_regs[2]; + GAFR2_L = save_lcd_regs[3]; + GAFR2_U = save_lcd_regs[4]; + return 0; +} + +static struct mbxfb_platform_data cmx270_2700G_data = { + .xres = { + .min = 240, + .max = 1200, + .defval = 640, + }, + .yres = { + .min = 240, + .max = 1200, + .defval = 480, + }, + .bpp = { + .min = 16, + .max = 32, + .defval = 16, + }, + .memsize = 8*1024*1024, + .probe = cmx270_marathon_probe, + .remove = cmx270_marathon_remove, +}; + +static struct platform_device cmx270_2700G = { + .name = "mbx-fb", + .dev = { + .platform_data = &cmx270_2700G_data, + .dma_mask = &fb_dma_mask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(cmx270_2700G_resource), + .resource = cmx270_2700G_resource, + .id = -1, +}; + +static u64 ata_dma_mask = ~(u64)0; + +static struct platform_device cmx270_ata = { + .name = "pata_cm_x270", + .id = -1, + .dev = { + .dma_mask = &ata_dma_mask, + .coherent_dma_mask = 0xffffffff, + }, +}; + +/* platform devices */ +static struct platform_device *platform_devices[] __initdata = { + &cmx270_device_dm9k, + &cmx270_audio_device, + &cmx270_rtc_device, + &cmx270_2700G, + &cmx270_led_device, + &cmx270_ts_device, + &cmx270_ata, +}; + +/* Map PCI companion and IDE/General Purpose CS statically */ +static struct map_desc cmx270_io_desc[] __initdata = { + [0] = { /* IDE/general purpose space */ + .virtual = CMX270_IDE104_VIRT, + .pfn = __phys_to_pfn(CMX270_IDE104_PHYS), + .length = SZ_64M - SZ_8M, + .type = MT_DEVICE + }, + [1] = { /* PCI bridge */ + .virtual = CMX270_IT8152_VIRT, + .pfn = __phys_to_pfn(CMX270_IT8152_PHYS), + .length = SZ_64M, + .type = MT_DEVICE + }, +}; + +/* + Display definitions + keep these for backwards compatibility, although symbolic names (as + e.g. in lpd270.c) looks better +*/ +#define MTYPE_STN320x240 0 +#define MTYPE_TFT640x480 1 +#define MTYPE_CRT640x480 2 +#define MTYPE_CRT800x600 3 +#define MTYPE_TFT320x240 6 +#define MTYPE_STN640x480 7 + +static struct pxafb_mode_info generic_stn_320x240_mode = { + .pixclock = 76923, + .bpp = 8, + .xres = 320, + .yres = 240, + .hsync_len = 3, + .vsync_len = 2, + .left_margin = 3, + .upper_margin = 0, + .right_margin = 3, + .lower_margin = 0, + .sync = (FB_SYNC_HOR_HIGH_ACT | + FB_SYNC_VERT_HIGH_ACT), + .cmap_greyscale = 0, +}; + +static struct pxafb_mach_info generic_stn_320x240 = { + .modes = &generic_stn_320x240_mode, + .num_modes = 1, + .lccr0 = 0, + .lccr3 = (LCCR3_PixClkDiv(0x03) | + LCCR3_Acb(0xff) | + LCCR3_PCP), + .cmap_inverse = 0, + .cmap_static = 0, +}; + +static struct pxafb_mode_info generic_tft_640x480_mode = { + .pixclock = 38461, + .bpp = 8, + .xres = 640, + .yres = 480, + .hsync_len = 60, + .vsync_len = 2, + .left_margin = 70, + .upper_margin = 10, + .right_margin = 70, + .lower_margin = 5, + .sync = 0, + .cmap_greyscale = 0, +}; + +static struct pxafb_mach_info generic_tft_640x480 = { + .modes = &generic_tft_640x480_mode, + .num_modes = 1, + .lccr0 = (LCCR0_PAS), + .lccr3 = (LCCR3_PixClkDiv(0x01) | + LCCR3_Acb(0xff) | + LCCR3_PCP), + .cmap_inverse = 0, + .cmap_static = 0, +}; + +static struct pxafb_mode_info generic_crt_640x480_mode = { + .pixclock = 38461, + .bpp = 8, + .xres = 640, + .yres = 480, + .hsync_len = 63, + .vsync_len = 2, + .left_margin = 81, + .upper_margin = 33, + .right_margin = 16, + .lower_margin = 10, + .sync = (FB_SYNC_HOR_HIGH_ACT | + FB_SYNC_VERT_HIGH_ACT), + .cmap_greyscale = 0, +}; + +static struct pxafb_mach_info generic_crt_640x480 = { + .modes = &generic_crt_640x480_mode, + .num_modes = 1, + .lccr0 = (LCCR0_PAS), + .lccr3 = (LCCR3_PixClkDiv(0x01) | + LCCR3_Acb(0xff)), + .cmap_inverse = 0, + .cmap_static = 0, +}; + +static struct pxafb_mode_info generic_crt_800x600_mode = { + .pixclock = 28846, + .bpp = 8, + .xres = 800, + .yres = 600, + .hsync_len = 63, + .vsync_len = 2, + .left_margin = 26, + .upper_margin = 21, + .right_margin = 26, + .lower_margin = 11, + .sync = (FB_SYNC_HOR_HIGH_ACT | + FB_SYNC_VERT_HIGH_ACT), + .cmap_greyscale = 0, +}; + +static struct pxafb_mach_info generic_crt_800x600 = { + .modes = &generic_crt_800x600_mode, + .num_modes = 1, + .lccr0 = (LCCR0_PAS), + .lccr3 = (LCCR3_PixClkDiv(0x02) | + LCCR3_Acb(0xff)), + .cmap_inverse = 0, + .cmap_static = 0, +}; + +static struct pxafb_mode_info generic_tft_320x240_mode = { + .pixclock = 134615, + .bpp = 16, + .xres = 320, + .yres = 240, + .hsync_len = 63, + .vsync_len = 7, + .left_margin = 75, + .upper_margin = 0, + .right_margin = 15, + .lower_margin = 15, + .sync = 0, + .cmap_greyscale = 0, +}; + +static struct pxafb_mach_info generic_tft_320x240 = { + .modes = &generic_tft_320x240_mode, + .num_modes = 1, + .lccr0 = (LCCR0_PAS), + .lccr3 = (LCCR3_PixClkDiv(0x06) | + LCCR3_Acb(0xff) | + LCCR3_PCP), + .cmap_inverse = 0, + .cmap_static = 0, +}; + +static struct pxafb_mode_info generic_stn_640x480_mode = { + .pixclock = 57692, + .bpp = 8, + .xres = 640, + .yres = 480, + .hsync_len = 4, + .vsync_len = 2, + .left_margin = 10, + .upper_margin = 5, + .right_margin = 10, + .lower_margin = 5, + .sync = (FB_SYNC_HOR_HIGH_ACT | + FB_SYNC_VERT_HIGH_ACT), + .cmap_greyscale = 0, +}; + +static struct pxafb_mach_info generic_stn_640x480 = { + .modes = &generic_stn_640x480_mode, + .num_modes = 1, + .lccr0 = 0, + .lccr3 = (LCCR3_PixClkDiv(0x02) | + LCCR3_Acb(0xff)), + .cmap_inverse = 0, + .cmap_static = 0, +}; + +static struct pxafb_mach_info *cmx270_display = &generic_crt_640x480; + +static int __init cmx270_set_display(char *str) +{ + int disp_type = simple_strtol(str, NULL, 0); + switch (disp_type) { + case MTYPE_STN320x240: + cmx270_display = &generic_stn_320x240; + break; + case MTYPE_TFT640x480: + cmx270_display = &generic_tft_640x480; + break; + case MTYPE_CRT640x480: + cmx270_display = &generic_crt_640x480; + break; + case MTYPE_CRT800x600: + cmx270_display = &generic_crt_800x600; + break; + case MTYPE_TFT320x240: + cmx270_display = &generic_tft_320x240; + break; + case MTYPE_STN640x480: + cmx270_display = &generic_stn_640x480; + break; + default: /* fallback to CRT 640x480 */ + cmx270_display = &generic_crt_640x480; + break; + } + return 1; +} + +/* + This should be done really early to get proper configuration for + frame buffer. + Indeed, pxafb parameters can be used istead, but CM-X270 bootloader + has limitied line length for kernel command line, and also it will + break compatibitlty with proprietary releases already in field. +*/ +__setup("monitor=", cmx270_set_display); + +/* PXA27x OHCI controller setup */ +static int cmx270_ohci_init(struct device *dev) +{ + /* Set the Power Control Polarity Low */ + UHCHR = (UHCHR | UHCHR_PCPL) & + ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE); + + return 0; +} + +static struct pxaohci_platform_data cmx270_ohci_platform_data = { + .port_mode = PMM_PERPORT_MODE, + .init = cmx270_ohci_init, +}; + + +static int cmx270_mci_init(struct device *dev, + irq_handler_t cmx270_detect_int, + void *data) +{ + int err; + + /* + * setup GPIO for PXA27x MMC controller + */ + pxa_gpio_mode(GPIO32_MMCCLK_MD); + pxa_gpio_mode(GPIO112_MMCCMD_MD); + pxa_gpio_mode(GPIO92_MMCDAT0_MD); + pxa_gpio_mode(GPIO109_MMCDAT1_MD); + pxa_gpio_mode(GPIO110_MMCDAT2_MD); + pxa_gpio_mode(GPIO111_MMCDAT3_MD); + + /* SB-X270 uses GPIO105 as SD power enable */ + pxa_gpio_mode(105 | GPIO_OUT); + + /* card detect IRQ on GPIO 83 */ + pxa_gpio_mode(IRQ_TO_GPIO(CMX270_MMC_IRQ)); + set_irq_type(CMX270_MMC_IRQ, IRQT_FALLING); + + err = request_irq(CMX270_MMC_IRQ, cmx270_detect_int, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "MMC card detect", data); + if (err) { + printk(KERN_ERR "cmx270_mci_init: MMC/SD: can't" + " request MMC card detect IRQ\n"); + return -1; + } + + return 0; +} + +static void cmx270_mci_setpower(struct device *dev, unsigned int vdd) +{ + struct pxamci_platform_data *p_d = dev->platform_data; + + if ((1 << vdd) & p_d->ocr_mask) { + printk(KERN_DEBUG "%s: on\n", __FUNCTION__); + GPCR(105) = GPIO_bit(105); + } else { + GPSR(105) = GPIO_bit(105); + printk(KERN_DEBUG "%s: off\n", __FUNCTION__); + } +} + +static void cmx270_mci_exit(struct device *dev, void *data) +{ + free_irq(CMX270_MMC_IRQ, data); +} + +static struct pxamci_platform_data cmx270_mci_platform_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = cmx270_mci_init, + .setpower = cmx270_mci_setpower, + .exit = cmx270_mci_exit, +}; + +#ifdef CONFIG_PM +static unsigned long sleep_save_msc[10]; + +static int cmx270_suspend(struct sys_device *dev, pm_message_t state) +{ + cmx270_pci_suspend(); + + /* save MSC registers */ + sleep_save_msc[0] = MSC0; + sleep_save_msc[1] = MSC1; + sleep_save_msc[2] = MSC2; + + /* setup power saving mode registers */ + PCFR = 0x0; + PSLR = 0xff400000; + PMCR = 0x00000005; + PWER = 0x80000000; + PFER = 0x00000000; + PRER = 0x00000000; + PGSR0 = 0xC0018800; + PGSR1 = 0x004F0002; + PGSR2 = 0x6021C000; + PGSR3 = 0x00020000; + + return 0; +} + +static int cmx270_resume(struct sys_device *dev) +{ + cmx270_pci_resume(); + + /* restore MSC registers */ + MSC0 = sleep_save_msc[0]; + MSC1 = sleep_save_msc[1]; + MSC2 = sleep_save_msc[2]; + + return 0; +} + +static struct sysdev_class cmx270_pm_sysclass = { + set_kset_name("pm"), + .resume = cmx270_resume, + .suspend = cmx270_suspend, +}; + +static struct sys_device cmx270_pm_device = { + .cls = &cmx270_pm_sysclass, +}; + +static int __init cmx270_pm_init(void) +{ + int error; + error = sysdev_class_register(&cmx270_pm_sysclass); + if (error == 0) + error = sysdev_register(&cmx270_pm_device); + return error; +} +#else +static int __init cmx270_pm_init(void) { return 0; } +#endif + +static void __init cmx270_init(void) +{ + cmx270_pm_init(); + + set_pxa_fb_info(cmx270_display); + + /* register CM-X270 platform devices */ + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + + /* set MCI and OHCI platform parameters */ + pxa_set_mci_info(&cmx270_mci_platform_data); + pxa_set_ohci_info(&cmx270_ohci_platform_data); + + /* This enables the STUART */ + pxa_gpio_mode(GPIO46_STRXD_MD); + pxa_gpio_mode(GPIO47_STTXD_MD); + + /* This enables the BTUART */ + pxa_gpio_mode(GPIO42_BTRXD_MD); + pxa_gpio_mode(GPIO43_BTTXD_MD); + pxa_gpio_mode(GPIO44_BTCTS_MD); + pxa_gpio_mode(GPIO45_BTRTS_MD); +} + +static void __init cmx270_init_irq(void) +{ + pxa27x_init_irq(); + + + cmx270_pci_init_irq(); + + /* Setup interrupt for dm9000 */ + pxa_gpio_mode(IRQ_TO_GPIO(CMX270_ETHIRQ)); + set_irq_type(CMX270_ETHIRQ, IRQT_RISING); + + /* Setup interrupt for 2700G */ + pxa_gpio_mode(IRQ_TO_GPIO(CMX270_GFXIRQ)); + set_irq_type(CMX270_GFXIRQ, IRQT_FALLING); +} + +static void __init cmx270_map_io(void) +{ + pxa_map_io(); + iotable_init(cmx270_io_desc, ARRAY_SIZE(cmx270_io_desc)); +} + + +MACHINE_START(ARMCORE, "Compulab CM-x270") + .boot_params = 0xa0000100, + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .map_io = cmx270_map_io, + .init_irq = cmx270_init_irq, + .timer = &pxa_timer, + .init_machine = cmx270_init, +MACHINE_END |