diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /arch/arm/mach-integrator | |
Diffstat (limited to 'arch/arm/mach-integrator')
22 files changed, 3625 insertions, 0 deletions
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig new file mode 100644 index 00000000..abeff255 --- /dev/null +++ b/arch/arm/mach-integrator/Kconfig @@ -0,0 +1,43 @@ +if ARCH_INTEGRATOR + +menu "Integrator Options" + +config ARCH_INTEGRATOR_AP + bool "Support Integrator/AP and Integrator/PP2 platforms" + select CLKSRC_MMIO + select MIGHT_HAVE_PCI + select SERIAL_AMBA_PL010 + select SERIAL_AMBA_PL010_CONSOLE + select SOC_BUS + help + Include support for the ARM(R) Integrator/AP and + Integrator/PP2 platforms. + +config ARCH_INTEGRATOR_CP + bool "Support Integrator/CP platform" + select ARCH_CINTEGRATOR + select ARM_TIMER_SP804 + select PLAT_VERSATILE_CLCD + select SERIAL_AMBA_PL011 + select SERIAL_AMBA_PL011_CONSOLE + select SOC_BUS + help + Include support for the ARM(R) Integrator CP platform. + +config ARCH_CINTEGRATOR + bool + +config INTEGRATOR_IMPD1 + tristate "Include support for Integrator/IM-PD1" + depends on ARCH_INTEGRATOR_AP + help + The IM-PD1 is an add-on logic module for the Integrator which + allows ARM(R) Ltd PrimeCells to be developed and evaluated. + The IM-PD1 can be found on the Integrator/PP2 platform. + + To compile this driver as a module, choose M here: the + module will be called impd1. + +endmenu + +endif diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile new file mode 100644 index 00000000..d14d6b76 --- /dev/null +++ b/arch/arm/mach-integrator/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y := core.o lm.o leds.o +obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o +obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o + +obj-$(CONFIG_PCI) += pci_v3.o pci.o +obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o diff --git a/arch/arm/mach-integrator/Makefile.boot b/arch/arm/mach-integrator/Makefile.boot new file mode 100644 index 00000000..ff0a4b5b --- /dev/null +++ b/arch/arm/mach-integrator/Makefile.boot @@ -0,0 +1,4 @@ + zreladdr-y += 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 + diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h new file mode 100644 index 00000000..72516658 --- /dev/null +++ b/arch/arm/mach-integrator/common.h @@ -0,0 +1,7 @@ +#include <linux/amba/serial.h> +extern struct amba_pl010_data ap_uart_data; +void integrator_init_early(void); +int integrator_init(bool is_cp); +void integrator_reserve(void); +void integrator_restart(char, const char *); +void integrator_init_sysfs(struct device *parent, u32 id); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c new file mode 100644 index 00000000..81461d21 --- /dev/null +++ b/arch/arm/mach-integrator/core.c @@ -0,0 +1,220 @@ +/* + * linux/arch/arm/mach-integrator/core.c + * + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/export.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/memblock.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/amba/bus.h> +#include <linux/amba/serial.h> +#include <linux/io.h> +#include <linux/stat.h> + +#include <mach/hardware.h> +#include <mach/platform.h> +#include <mach/cm.h> +#include <mach/irqs.h> + +#include <asm/mach-types.h> +#include <asm/mach/time.h> +#include <asm/pgtable.h> + +#include "common.h" + +#ifdef CONFIG_ATAGS + +#define INTEGRATOR_RTC_IRQ { IRQ_RTCINT } +#define INTEGRATOR_UART0_IRQ { IRQ_UARTINT0 } +#define INTEGRATOR_UART1_IRQ { IRQ_UARTINT1 } +#define KMI0_IRQ { IRQ_KMIINT0 } +#define KMI1_IRQ { IRQ_KMIINT1 } + +static AMBA_APB_DEVICE(rtc, "rtc", 0, + INTEGRATOR_RTC_BASE, INTEGRATOR_RTC_IRQ, NULL); + +static AMBA_APB_DEVICE(uart0, "uart0", 0, + INTEGRATOR_UART0_BASE, INTEGRATOR_UART0_IRQ, NULL); + +static AMBA_APB_DEVICE(uart1, "uart1", 0, + INTEGRATOR_UART1_BASE, INTEGRATOR_UART1_IRQ, NULL); + +static AMBA_APB_DEVICE(kmi0, "kmi0", 0, KMI0_BASE, KMI0_IRQ, NULL); +static AMBA_APB_DEVICE(kmi1, "kmi1", 0, KMI1_BASE, KMI1_IRQ, NULL); + +static struct amba_device *amba_devs[] __initdata = { + &rtc_device, + &uart0_device, + &uart1_device, + &kmi0_device, + &kmi1_device, +}; + +int __init integrator_init(bool is_cp) +{ + int i; + + /* + * The Integrator/AP lacks necessary AMBA PrimeCell IDs, so we need to + * hard-code them. The Integator/CP and forward have proper cell IDs. + * Else we leave them undefined to the bus driver can autoprobe them. + */ + if (!is_cp && IS_ENABLED(CONFIG_ARCH_INTEGRATOR_AP)) { + rtc_device.periphid = 0x00041030; + uart0_device.periphid = 0x00041010; + uart1_device.periphid = 0x00041010; + kmi0_device.periphid = 0x00041050; + kmi1_device.periphid = 0x00041050; + uart0_device.dev.platform_data = &ap_uart_data; + uart1_device.dev.platform_data = &ap_uart_data; + } + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + struct amba_device *d = amba_devs[i]; + amba_device_register(d, &iomem_resource); + } + + return 0; +} + +#endif + +static DEFINE_RAW_SPINLOCK(cm_lock); + +/** + * cm_control - update the CM_CTRL register. + * @mask: bits to change + * @set: bits to set + */ +void cm_control(u32 mask, u32 set) +{ + unsigned long flags; + u32 val; + + raw_spin_lock_irqsave(&cm_lock, flags); + val = readl(CM_CTRL) & ~mask; + writel(val | set, CM_CTRL); + raw_spin_unlock_irqrestore(&cm_lock, flags); +} + +EXPORT_SYMBOL(cm_control); + +/* + * We need to stop things allocating the low memory; ideally we need a + * better implementation of GFP_DMA which does not assume that DMA-able + * memory starts at zero. + */ +void __init integrator_reserve(void) +{ + memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); +} + +/* + * To reset, we hit the on-board reset register in the system FPGA + */ +void integrator_restart(char mode, const char *cmd) +{ + cm_control(CM_CTRL_RESET, CM_CTRL_RESET); +} + +static u32 integrator_id; + +static ssize_t intcp_get_manf(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%02x\n", integrator_id >> 24); +} + +static struct device_attribute intcp_manf_attr = + __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL); + +static ssize_t intcp_get_arch(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const char *arch; + + switch ((integrator_id >> 16) & 0xff) { + case 0x00: + arch = "ASB little-endian"; + break; + case 0x01: + arch = "AHB little-endian"; + break; + case 0x03: + arch = "AHB-Lite system bus, bi-endian"; + break; + case 0x04: + arch = "AHB"; + break; + default: + arch = "Unknown"; + break; + } + + return sprintf(buf, "%s\n", arch); +} + +static struct device_attribute intcp_arch_attr = + __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL); + +static ssize_t intcp_get_fpga(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const char *fpga; + + switch ((integrator_id >> 12) & 0xf) { + case 0x01: + fpga = "XC4062"; + break; + case 0x02: + fpga = "XC4085"; + break; + case 0x04: + fpga = "EPM7256AE (Altera PLD)"; + break; + default: + fpga = "Unknown"; + break; + } + + return sprintf(buf, "%s\n", fpga); +} + +static struct device_attribute intcp_fpga_attr = + __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL); + +static ssize_t intcp_get_build(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF); +} + +static struct device_attribute intcp_build_attr = + __ATTR(build, S_IRUGO, intcp_get_build, NULL); + + + +void integrator_init_sysfs(struct device *parent, u32 id) +{ + integrator_id = id; + device_create_file(parent, &intcp_manf_attr); + device_create_file(parent, &intcp_arch_attr); + device_create_file(parent, &intcp_fpga_attr); + device_create_file(parent, &intcp_build_attr); +} diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c new file mode 100644 index 00000000..9f82f9dc --- /dev/null +++ b/arch/arm/mach-integrator/impd1.c @@ -0,0 +1,409 @@ +/* + * linux/arch/arm/mach-integrator/impd1.c + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file provides the core support for the IM-PD1 module. + * + * Module / boot parameters. + * lmid=n impd1.lmid=n - set the logic module position in stack to 'n' + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/amba/bus.h> +#include <linux/amba/clcd.h> +#include <linux/io.h> +#include <linux/platform_data/clk-integrator.h> +#include <linux/slab.h> + +#include <mach/lm.h> +#include <mach/impd1.h> +#include <asm/sizes.h> + +static int module_id; + +module_param_named(lmid, module_id, int, 0444); +MODULE_PARM_DESC(lmid, "logic module stack position"); + +struct impd1_module { + void __iomem *base; +}; + +void impd1_tweak_control(struct device *dev, u32 mask, u32 val) +{ + struct impd1_module *impd1 = dev_get_drvdata(dev); + u32 cur; + + val &= mask; + cur = readl(impd1->base + IMPD1_CTRL) & ~mask; + writel(cur | val, impd1->base + IMPD1_CTRL); +} + +EXPORT_SYMBOL(impd1_tweak_control); + +/* + * CLCD support + */ +#define PANEL PROSPECTOR + +#define LTM10C209 1 +#define PROSPECTOR 2 +#define SVGA 3 +#define VGA 4 + +#if PANEL == VGA +#define PANELTYPE vga +static struct clcd_panel vga = { + .mode = { + .name = "VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD | TIM2_IPC, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .caps = CLCD_CAP_5551, + .connector = IMPD1_CTRL_DISP_VGA, + .bpp = 16, + .grayscale = 0, +}; + +#elif PANEL == SVGA +#define PANELTYPE svga +static struct clcd_panel svga = { + .mode = { + .name = "SVGA", + .refresh = 0, + .xres = 800, + .yres = 600, + .pixclock = 27778, + .left_margin = 20, + .right_margin = 20, + .upper_margin = 5, + .lower_margin = 5, + .hsync_len = 164, + .vsync_len = 62, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .connector = IMPD1_CTRL_DISP_VGA, + .caps = CLCD_CAP_5551, + .bpp = 16, + .grayscale = 0, +}; + +#elif PANEL == PROSPECTOR +#define PANELTYPE prospector +static struct clcd_panel prospector = { + .mode = { + .name = "PROSPECTOR", + .refresh = 0, + .xres = 640, + .yres = 480, + .pixclock = 40000, + .left_margin = 33, + .right_margin = 64, + .upper_margin = 36, + .lower_margin = 7, + .hsync_len = 64, + .vsync_len = 25, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .caps = CLCD_CAP_5551, + .fixedtimings = 1, + .connector = IMPD1_CTRL_DISP_LCD, + .bpp = 16, + .grayscale = 0, +}; + +#elif PANEL == LTM10C209 +#define PANELTYPE ltm10c209 +/* + * Untested. + */ +static struct clcd_panel ltm10c209 = { + .mode = { + .name = "LTM10C209", + .refresh = 0, + .xres = 640, + .yres = 480, + .pixclock = 40000, + .left_margin = 20, + .right_margin = 20, + .upper_margin = 19, + .lower_margin = 19, + .hsync_len = 20, + .vsync_len = 10, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD, + .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .caps = CLCD_CAP_5551, + .fixedtimings = 1, + .connector = IMPD1_CTRL_DISP_LCD, + .bpp = 16, + .grayscale = 0, +}; +#endif + +/* + * Disable all display connectors on the interface module. + */ +static void impd1fb_clcd_disable(struct clcd_fb *fb) +{ + impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, 0); +} + +/* + * Enable the relevant connector on the interface module. + */ +static void impd1fb_clcd_enable(struct clcd_fb *fb) +{ + impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, + fb->panel->connector | IMPD1_CTRL_DISP_ENABLE); +} + +static int impd1fb_clcd_setup(struct clcd_fb *fb) +{ + unsigned long framebase = fb->dev->res.start + 0x01000000; + unsigned long framesize = SZ_1M; + int ret = 0; + + fb->panel = &PANELTYPE; + + if (!request_mem_region(framebase, framesize, "clcd framebuffer")) { + printk(KERN_ERR "IM-PD1: unable to reserve framebuffer\n"); + return -EBUSY; + } + + fb->fb.screen_base = ioremap(framebase, framesize); + if (!fb->fb.screen_base) { + printk(KERN_ERR "IM-PD1: unable to map framebuffer\n"); + ret = -ENOMEM; + goto free_buffer; + } + + fb->fb.fix.smem_start = framebase; + fb->fb.fix.smem_len = framesize; + + return 0; + + free_buffer: + release_mem_region(framebase, framesize); + return ret; +} + +static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) +{ + unsigned long start, size; + + start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT); + size = vma->vm_end - vma->vm_start; + + return remap_pfn_range(vma, vma->vm_start, start, size, + vma->vm_page_prot); +} + +static void impd1fb_clcd_remove(struct clcd_fb *fb) +{ + iounmap(fb->fb.screen_base); + release_mem_region(fb->fb.fix.smem_start, fb->fb.fix.smem_len); +} + +static struct clcd_board impd1_clcd_data = { + .name = "IM-PD/1", + .caps = CLCD_CAP_5551 | CLCD_CAP_888, + .check = clcdfb_check, + .decode = clcdfb_decode, + .disable = impd1fb_clcd_disable, + .enable = impd1fb_clcd_enable, + .setup = impd1fb_clcd_setup, + .mmap = impd1fb_clcd_mmap, + .remove = impd1fb_clcd_remove, +}; + +struct impd1_device { + unsigned long offset; + unsigned int irq[2]; + unsigned int id; + void *platform_data; +}; + +static struct impd1_device impd1_devs[] = { + { + .offset = 0x03000000, + .id = 0x00041190, + }, { + .offset = 0x00100000, + .irq = { 1 }, + .id = 0x00141011, + }, { + .offset = 0x00200000, + .irq = { 2 }, + .id = 0x00141011, + }, { + .offset = 0x00300000, + .irq = { 3 }, + .id = 0x00041022, + }, { + .offset = 0x00400000, + .irq = { 4 }, + .id = 0x00041061, + }, { + .offset = 0x00500000, + .irq = { 5 }, + .id = 0x00041061, + }, { + .offset = 0x00600000, + .irq = { 6 }, + .id = 0x00041130, + }, { + .offset = 0x00700000, + .irq = { 7, 8 }, + .id = 0x00041181, + }, { + .offset = 0x00800000, + .irq = { 9 }, + .id = 0x00041041, + }, { + .offset = 0x01000000, + .irq = { 11 }, + .id = 0x00041110, + .platform_data = &impd1_clcd_data, + } +}; + +static int impd1_probe(struct lm_device *dev) +{ + struct impd1_module *impd1; + int i, ret; + + if (dev->id != module_id) + return -EINVAL; + + if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers")) + return -EBUSY; + + impd1 = kzalloc(sizeof(struct impd1_module), GFP_KERNEL); + if (!impd1) { + ret = -ENOMEM; + goto release_lm; + } + + impd1->base = ioremap(dev->resource.start, SZ_4K); + if (!impd1->base) { + ret = -ENOMEM; + goto free_impd1; + } + + lm_set_drvdata(dev, impd1); + + printk("IM-PD1 found at 0x%08lx\n", + (unsigned long)dev->resource.start); + + integrator_impd1_clk_init(impd1->base, dev->id); + + for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) { + struct impd1_device *idev = impd1_devs + i; + struct amba_device *d; + unsigned long pc_base; + char devname[32]; + + pc_base = dev->resource.start + idev->offset; + snprintf(devname, 32, "lm%x:%5.5lx", dev->id, idev->offset >> 12); + d = amba_ahb_device_add_res(&dev->dev, devname, pc_base, SZ_4K, + dev->irq, dev->irq, + idev->platform_data, idev->id, + &dev->resource); + if (IS_ERR(d)) { + dev_err(&dev->dev, "unable to register device: %ld\n", PTR_ERR(d)); + continue; + } + } + + return 0; + + free_impd1: + if (impd1 && impd1->base) + iounmap(impd1->base); + kfree(impd1); + release_lm: + release_mem_region(dev->resource.start, SZ_4K); + return ret; +} + +static int impd1_remove_one(struct device *dev, void *data) +{ + device_unregister(dev); + return 0; +} + +static void impd1_remove(struct lm_device *dev) +{ + struct impd1_module *impd1 = lm_get_drvdata(dev); + + device_for_each_child(&dev->dev, NULL, impd1_remove_one); + integrator_impd1_clk_exit(dev->id); + + lm_set_drvdata(dev, NULL); + + iounmap(impd1->base); + kfree(impd1); + release_mem_region(dev->resource.start, SZ_4K); +} + +static struct lm_driver impd1_driver = { + .drv = { + .name = "impd1", + }, + .probe = impd1_probe, + .remove = impd1_remove, +}; + +static int __init impd1_init(void) +{ + return lm_driver_register(&impd1_driver); +} + +static void __exit impd1_exit(void) +{ + lm_driver_unregister(&impd1_driver); +} + +module_init(impd1_init); +module_exit(impd1_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Integrator/IM-PD1 logic module core driver"); +MODULE_AUTHOR("Deep Blue Solutions Ltd"); diff --git a/arch/arm/mach-integrator/include/mach/cm.h b/arch/arm/mach-integrator/include/mach/cm.h new file mode 100644 index 00000000..202e6a57 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/cm.h @@ -0,0 +1,38 @@ +/* + * update the core module control register. + */ +void cm_control(u32, u32); + +#define CM_CTRL __io_address(INTEGRATOR_HDR_CTRL) + +#define CM_CTRL_LED (1 << 0) +#define CM_CTRL_nMBDET (1 << 1) +#define CM_CTRL_REMAP (1 << 2) +#define CM_CTRL_RESET (1 << 3) + +/* + * Integrator/AP,PP2 specific + */ +#define CM_CTRL_HIGHVECTORS (1 << 4) +#define CM_CTRL_BIGENDIAN (1 << 5) +#define CM_CTRL_FASTBUS (1 << 6) +#define CM_CTRL_SYNC (1 << 7) + +/* + * ARM926/946/966 Integrator/CP specific + */ +#define CM_CTRL_LCDBIASEN (1 << 8) +#define CM_CTRL_LCDBIASUP (1 << 9) +#define CM_CTRL_LCDBIASDN (1 << 10) +#define CM_CTRL_LCDMUXSEL_MASK (7 << 11) +#define CM_CTRL_LCDMUXSEL_GENLCD (1 << 11) +#define CM_CTRL_LCDMUXSEL_VGA565_TFT555 (2 << 11) +#define CM_CTRL_LCDMUXSEL_SHARPLCD (3 << 11) +#define CM_CTRL_LCDMUXSEL_VGA555_TFT555 (4 << 11) +#define CM_CTRL_LCDEN0 (1 << 14) +#define CM_CTRL_LCDEN1 (1 << 15) +#define CM_CTRL_STATIC1 (1 << 16) +#define CM_CTRL_STATIC2 (1 << 17) +#define CM_CTRL_STATIC (1 << 18) +#define CM_CTRL_n24BITEN (1 << 19) +#define CM_CTRL_EBIWP (1 << 20) diff --git a/arch/arm/mach-integrator/include/mach/debug-macro.S b/arch/arm/mach-integrator/include/mach/debug-macro.S new file mode 100644 index 00000000..411b1160 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/debug-macro.S @@ -0,0 +1,20 @@ +/* arch/arm/mach-integrator/include/mach/debug-macro.S + * + * Debugging macro include header + * + * Copyright (C) 1994-1999 Russell King + * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks + * + * 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. + * +*/ + + .macro addruart, rp, rv, tmp + mov \rp, #0x16000000 @ physical base address + mov \rv, #0xf0000000 @ virtual base + add \rv, \rv, #0x16000000 >> 4 + .endm + +#include <asm/hardware/debug-pl01x.S> diff --git a/arch/arm/mach-integrator/include/mach/hardware.h b/arch/arm/mach-integrator/include/mach/hardware.h new file mode 100644 index 00000000..65fed7c0 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/hardware.h @@ -0,0 +1,45 @@ +/* + * arch/arm/mach-integrator/include/mach/hardware.h + * + * This file contains the hardware definitions of the Integrator. + * + * Copyright (C) 1999 ARM Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include <asm/sizes.h> + +/* + * Where in virtual memory the IO devices (timers, system controllers + * and so on) + */ +#define IO_BASE 0xF0000000 // VA of IO +#define IO_SIZE 0x0B000000 // How much? +#define IO_START INTEGRATOR_HDR_BASE // PA of IO + +/* macro to get at IO space when running virtually */ +#ifdef CONFIG_MMU +#define IO_ADDRESS(x) (((x) & 0x000fffff) | (((x) >> 4) & 0x0ff00000) | IO_BASE) +#else +#define IO_ADDRESS(x) (x) +#endif + +#define __io_address(n) ((void __iomem *)IO_ADDRESS(n)) + +#endif + diff --git a/arch/arm/mach-integrator/include/mach/impd1.h b/arch/arm/mach-integrator/include/mach/impd1.h new file mode 100644 index 00000000..d75de4b1 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/impd1.h @@ -0,0 +1,18 @@ +#define IMPD1_OSC1 0x00 +#define IMPD1_OSC2 0x04 +#define IMPD1_LOCK 0x08 +#define IMPD1_LEDS 0x0c +#define IMPD1_INT 0x10 +#define IMPD1_SW 0x14 +#define IMPD1_CTRL 0x18 + +#define IMPD1_CTRL_DISP_LCD (0 << 0) +#define IMPD1_CTRL_DISP_VGA (1 << 0) +#define IMPD1_CTRL_DISP_LCD1 (2 << 0) +#define IMPD1_CTRL_DISP_ENABLE (1 << 2) +#define IMPD1_CTRL_DISP_MASK (7 << 0) + +struct device; + +void impd1_tweak_control(struct device *dev, u32 mask, u32 val); + diff --git a/arch/arm/mach-integrator/include/mach/irqs.h b/arch/arm/mach-integrator/include/mach/irqs.h new file mode 100644 index 00000000..eff0adad --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/irqs.h @@ -0,0 +1,81 @@ +/* + * arch/arm/mach-integrator/include/mach/irqs.h + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Interrupt numbers, all of the above are just static reservations + * used so they can be encoded into device resources. They will finally + * be done away with when switching to device tree. + */ +#define IRQ_PIC_START 64 +#define IRQ_SOFTINT (IRQ_PIC_START+0) +#define IRQ_UARTINT0 (IRQ_PIC_START+1) +#define IRQ_UARTINT1 (IRQ_PIC_START+2) +#define IRQ_KMIINT0 (IRQ_PIC_START+3) +#define IRQ_KMIINT1 (IRQ_PIC_START+4) +#define IRQ_TIMERINT0 (IRQ_PIC_START+5) +#define IRQ_TIMERINT1 (IRQ_PIC_START+6) +#define IRQ_TIMERINT2 (IRQ_PIC_START+7) +#define IRQ_RTCINT (IRQ_PIC_START+8) +#define IRQ_AP_EXPINT0 (IRQ_PIC_START+9) +#define IRQ_AP_EXPINT1 (IRQ_PIC_START+10) +#define IRQ_AP_EXPINT2 (IRQ_PIC_START+11) +#define IRQ_AP_EXPINT3 (IRQ_PIC_START+12) +#define IRQ_AP_PCIINT0 (IRQ_PIC_START+13) +#define IRQ_AP_PCIINT1 (IRQ_PIC_START+14) +#define IRQ_AP_PCIINT2 (IRQ_PIC_START+15) +#define IRQ_AP_PCIINT3 (IRQ_PIC_START+16) +#define IRQ_AP_V3INT (IRQ_PIC_START+17) +#define IRQ_AP_CPINT0 (IRQ_PIC_START+18) +#define IRQ_AP_CPINT1 (IRQ_PIC_START+19) +#define IRQ_AP_LBUSTIMEOUT (IRQ_PIC_START+20) +#define IRQ_AP_APCINT (IRQ_PIC_START+21) +#define IRQ_CP_CLCDCINT (IRQ_PIC_START+22) +#define IRQ_CP_MMCIINT0 (IRQ_PIC_START+23) +#define IRQ_CP_MMCIINT1 (IRQ_PIC_START+24) +#define IRQ_CP_AACIINT (IRQ_PIC_START+25) +#define IRQ_CP_CPPLDINT (IRQ_PIC_START+26) +#define IRQ_CP_ETHINT (IRQ_PIC_START+27) +#define IRQ_CP_TSPENINT (IRQ_PIC_START+28) +#define IRQ_PIC_END (IRQ_PIC_START+28) + +#define IRQ_CIC_START (IRQ_PIC_END+1) +#define IRQ_CM_SOFTINT (IRQ_CIC_START+0) +#define IRQ_CM_COMMRX (IRQ_CIC_START+1) +#define IRQ_CM_COMMTX (IRQ_CIC_START+2) +#define IRQ_CIC_END (IRQ_CIC_START+2) + +/* + * IntegratorCP only + */ +#define IRQ_SIC_START (IRQ_CIC_END+1) +#define IRQ_SIC_CP_SOFTINT (IRQ_SIC_START+0) +#define IRQ_SIC_CP_RI0 (IRQ_SIC_START+1) +#define IRQ_SIC_CP_RI1 (IRQ_SIC_START+2) +#define IRQ_SIC_CP_CARDIN (IRQ_SIC_START+3) +#define IRQ_SIC_CP_LMINT0 (IRQ_SIC_START+4) +#define IRQ_SIC_CP_LMINT1 (IRQ_SIC_START+5) +#define IRQ_SIC_CP_LMINT2 (IRQ_SIC_START+6) +#define IRQ_SIC_CP_LMINT3 (IRQ_SIC_START+7) +#define IRQ_SIC_CP_LMINT4 (IRQ_SIC_START+8) +#define IRQ_SIC_CP_LMINT5 (IRQ_SIC_START+9) +#define IRQ_SIC_CP_LMINT6 (IRQ_SIC_START+10) +#define IRQ_SIC_CP_LMINT7 (IRQ_SIC_START+11) +#define IRQ_SIC_END (IRQ_SIC_START+11) diff --git a/arch/arm/mach-integrator/include/mach/lm.h b/arch/arm/mach-integrator/include/mach/lm.h new file mode 100644 index 00000000..28186b6f --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/lm.h @@ -0,0 +1,23 @@ + +struct lm_device { + struct device dev; + struct resource resource; + unsigned int irq; + unsigned int id; +}; + +struct lm_driver { + struct device_driver drv; + int (*probe)(struct lm_device *); + void (*remove)(struct lm_device *); + int (*suspend)(struct lm_device *, pm_message_t); + int (*resume)(struct lm_device *); +}; + +int lm_driver_register(struct lm_driver *drv); +void lm_driver_unregister(struct lm_driver *drv); + +int lm_device_register(struct lm_device *dev); + +#define lm_get_drvdata(lm) dev_get_drvdata(&(lm)->dev) +#define lm_set_drvdata(lm,d) dev_set_drvdata(&(lm)->dev, d) diff --git a/arch/arm/mach-integrator/include/mach/memory.h b/arch/arm/mach-integrator/include/mach/memory.h new file mode 100644 index 00000000..334d5e27 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/memory.h @@ -0,0 +1,34 @@ +/* + * arch/arm/mach-integrator/include/mach/memory.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/* + * Physical DRAM offset. + */ +#define PLAT_PHYS_OFFSET UL(0x00000000) + +#define BUS_OFFSET UL(0x80000000) +#define __virt_to_bus(x) ((x) - PAGE_OFFSET + BUS_OFFSET) +#define __bus_to_virt(x) ((x) - BUS_OFFSET + PAGE_OFFSET) +#define __pfn_to_bus(x) (__pfn_to_phys(x) + (BUS_OFFSET - PHYS_OFFSET)) +#define __bus_to_pfn(x) __phys_to_pfn((x) - (BUS_OFFSET - PHYS_OFFSET)) + +#endif diff --git a/arch/arm/mach-integrator/include/mach/platform.h b/arch/arm/mach-integrator/include/mach/platform.h new file mode 100644 index 00000000..be5859ef --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/platform.h @@ -0,0 +1,405 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/************************************************************************** + * * Copyright © ARM Limited 1998. All rights reserved. + * ***********************************************************************/ +/* ************************************************************************ + * + * Integrator address map + * + * ***********************************************************************/ + +#ifndef __address_h +#define __address_h 1 + +/* ======================================================================== + * Integrator definitions + * ======================================================================== + * ------------------------------------------------------------------------ + * Memory definitions + * ------------------------------------------------------------------------ + * Integrator memory map + * + */ +#define INTEGRATOR_BOOT_ROM_LO 0x00000000 +#define INTEGRATOR_BOOT_ROM_HI 0x20000000 +#define INTEGRATOR_BOOT_ROM_BASE INTEGRATOR_BOOT_ROM_HI /* Normal position */ +#define INTEGRATOR_BOOT_ROM_SIZE SZ_512K + +/* + * New Core Modules have different amounts of SSRAM, the amount of SSRAM + * fitted can be found in HDR_STAT. + * + * The symbol INTEGRATOR_SSRAM_SIZE is kept, however this now refers to + * the minimum amount of SSRAM fitted on any core module. + * + * New Core Modules also alias the SSRAM. + * + */ +#define INTEGRATOR_SSRAM_BASE 0x00000000 +#define INTEGRATOR_SSRAM_ALIAS_BASE 0x10800000 +#define INTEGRATOR_SSRAM_SIZE SZ_256K + +#define INTEGRATOR_FLASH_BASE 0x24000000 +#define INTEGRATOR_FLASH_SIZE SZ_32M + +#define INTEGRATOR_MBRD_SSRAM_BASE 0x28000000 +#define INTEGRATOR_MBRD_SSRAM_SIZE SZ_512K + +/* + * SDRAM is a SIMM therefore the size is not known. + * + */ +#define INTEGRATOR_SDRAM_BASE 0x00040000 + +#define INTEGRATOR_SDRAM_ALIAS_BASE 0x80000000 +#define INTEGRATOR_HDR0_SDRAM_BASE 0x80000000 +#define INTEGRATOR_HDR1_SDRAM_BASE 0x90000000 +#define INTEGRATOR_HDR2_SDRAM_BASE 0xA0000000 +#define INTEGRATOR_HDR3_SDRAM_BASE 0xB0000000 + +/* + * Logic expansion modules + * + */ +#define INTEGRATOR_LOGIC_MODULES_BASE 0xC0000000 +#define INTEGRATOR_LOGIC_MODULE0_BASE 0xC0000000 +#define INTEGRATOR_LOGIC_MODULE1_BASE 0xD0000000 +#define INTEGRATOR_LOGIC_MODULE2_BASE 0xE0000000 +#define INTEGRATOR_LOGIC_MODULE3_BASE 0xF0000000 + +/* ------------------------------------------------------------------------ + * Integrator header card registers + * ------------------------------------------------------------------------ + * + */ +#define INTEGRATOR_HDR_ID_OFFSET 0x00 +#define INTEGRATOR_HDR_PROC_OFFSET 0x04 +#define INTEGRATOR_HDR_OSC_OFFSET 0x08 +#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C +#define INTEGRATOR_HDR_STAT_OFFSET 0x10 +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 +#define INTEGRATOR_HDR_SDRAM_OFFSET 0x20 +#define INTEGRATOR_HDR_INIT_OFFSET 0x24 /* CM9x6 */ +#define INTEGRATOR_HDR_IC_OFFSET 0x40 +#define INTEGRATOR_HDR_SPDBASE_OFFSET 0x100 +#define INTEGRATOR_HDR_SPDTOP_OFFSET 0x200 + +#define INTEGRATOR_HDR_BASE 0x10000000 +#define INTEGRATOR_HDR_ID (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_ID_OFFSET) +#define INTEGRATOR_HDR_PROC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_PROC_OFFSET) +#define INTEGRATOR_HDR_OSC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_OSC_OFFSET) +#define INTEGRATOR_HDR_CTRL (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_CTRL_OFFSET) +#define INTEGRATOR_HDR_STAT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_STAT_OFFSET) +#define INTEGRATOR_HDR_LOCK (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_LOCK_OFFSET) +#define INTEGRATOR_HDR_SDRAM (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SDRAM_OFFSET) +#define INTEGRATOR_HDR_INIT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_INIT_OFFSET) +#define INTEGRATOR_HDR_IC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_IC_OFFSET) +#define INTEGRATOR_HDR_SPDBASE (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDBASE_OFFSET) +#define INTEGRATOR_HDR_SPDTOP (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDTOP_OFFSET) + +#define INTEGRATOR_HDR_CTRL_LED 0x01 +#define INTEGRATOR_HDR_CTRL_MBRD_DETECH 0x02 +#define INTEGRATOR_HDR_CTRL_REMAP 0x04 +#define INTEGRATOR_HDR_CTRL_RESET 0x08 +#define INTEGRATOR_HDR_CTRL_HIGHVECTORS 0x10 +#define INTEGRATOR_HDR_CTRL_BIG_ENDIAN 0x20 +#define INTEGRATOR_HDR_CTRL_FASTBUS 0x40 +#define INTEGRATOR_HDR_CTRL_SYNC 0x80 + +#define INTEGRATOR_HDR_OSC_CORE_10MHz 0x102 +#define INTEGRATOR_HDR_OSC_CORE_15MHz 0x107 +#define INTEGRATOR_HDR_OSC_CORE_20MHz 0x10C +#define INTEGRATOR_HDR_OSC_CORE_25MHz 0x111 +#define INTEGRATOR_HDR_OSC_CORE_30MHz 0x116 +#define INTEGRATOR_HDR_OSC_CORE_35MHz 0x11B +#define INTEGRATOR_HDR_OSC_CORE_40MHz 0x120 +#define INTEGRATOR_HDR_OSC_CORE_45MHz 0x125 +#define INTEGRATOR_HDR_OSC_CORE_50MHz 0x12A +#define INTEGRATOR_HDR_OSC_CORE_55MHz 0x12F +#define INTEGRATOR_HDR_OSC_CORE_60MHz 0x134 +#define INTEGRATOR_HDR_OSC_CORE_65MHz 0x139 +#define INTEGRATOR_HDR_OSC_CORE_70MHz 0x13E +#define INTEGRATOR_HDR_OSC_CORE_75MHz 0x143 +#define INTEGRATOR_HDR_OSC_CORE_80MHz 0x148 +#define INTEGRATOR_HDR_OSC_CORE_85MHz 0x14D +#define INTEGRATOR_HDR_OSC_CORE_90MHz 0x152 +#define INTEGRATOR_HDR_OSC_CORE_95MHz 0x157 +#define INTEGRATOR_HDR_OSC_CORE_100MHz 0x15C +#define INTEGRATOR_HDR_OSC_CORE_105MHz 0x161 +#define INTEGRATOR_HDR_OSC_CORE_110MHz 0x166 +#define INTEGRATOR_HDR_OSC_CORE_115MHz 0x16B +#define INTEGRATOR_HDR_OSC_CORE_120MHz 0x170 +#define INTEGRATOR_HDR_OSC_CORE_125MHz 0x175 +#define INTEGRATOR_HDR_OSC_CORE_130MHz 0x17A +#define INTEGRATOR_HDR_OSC_CORE_135MHz 0x17F +#define INTEGRATOR_HDR_OSC_CORE_140MHz 0x184 +#define INTEGRATOR_HDR_OSC_CORE_145MHz 0x189 +#define INTEGRATOR_HDR_OSC_CORE_150MHz 0x18E +#define INTEGRATOR_HDR_OSC_CORE_155MHz 0x193 +#define INTEGRATOR_HDR_OSC_CORE_160MHz 0x198 +#define INTEGRATOR_HDR_OSC_CORE_MASK 0x7FF + +#define INTEGRATOR_HDR_OSC_MEM_10MHz 0x10C000 +#define INTEGRATOR_HDR_OSC_MEM_15MHz 0x116000 +#define INTEGRATOR_HDR_OSC_MEM_20MHz 0x120000 +#define INTEGRATOR_HDR_OSC_MEM_25MHz 0x12A000 +#define INTEGRATOR_HDR_OSC_MEM_30MHz 0x134000 +#define INTEGRATOR_HDR_OSC_MEM_33MHz 0x13A000 +#define INTEGRATOR_HDR_OSC_MEM_40MHz 0x148000 +#define INTEGRATOR_HDR_OSC_MEM_50MHz 0x15C000 +#define INTEGRATOR_HDR_OSC_MEM_60MHz 0x170000 +#define INTEGRATOR_HDR_OSC_MEM_66MHz 0x17C000 +#define INTEGRATOR_HDR_OSC_MEM_MASK 0x7FF000 + +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM7x0 0x0 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x0 0x0800000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x6 0x1000000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM10x00 0x1800000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_MASK 0x1800000 + +#define INTEGRATOR_HDR_SDRAM_SPD_OK (1 << 5) + + +/* ------------------------------------------------------------------------ + * Integrator system registers + * ------------------------------------------------------------------------ + * + */ + +/* + * System Controller + * + */ +#define INTEGRATOR_SC_ID_OFFSET 0x00 +#define INTEGRATOR_SC_OSC_OFFSET 0x04 +#define INTEGRATOR_SC_CTRLS_OFFSET 0x08 +#define INTEGRATOR_SC_CTRLC_OFFSET 0x0C +#define INTEGRATOR_SC_DEC_OFFSET 0x10 +#define INTEGRATOR_SC_ARB_OFFSET 0x14 +#define INTEGRATOR_SC_LOCK_OFFSET 0x1C + +#define INTEGRATOR_SC_BASE 0x11000000 +#define INTEGRATOR_SC_ID (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ID_OFFSET) +#define INTEGRATOR_SC_OSC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_OSC_OFFSET) +#define INTEGRATOR_SC_CTRLS (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET) +#define INTEGRATOR_SC_CTRLC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET) +#define INTEGRATOR_SC_DEC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_DEC_OFFSET) +#define INTEGRATOR_SC_ARB (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ARB_OFFSET) +#define INTEGRATOR_SC_PCIENABLE (INTEGRATOR_SC_BASE + INTEGRATOR_SC_PCIENABLE_OFFSET) +#define INTEGRATOR_SC_LOCK (INTEGRATOR_SC_BASE + INTEGRATOR_SC_LOCK_OFFSET) + +#define INTEGRATOR_SC_OSC_SYS_10MHz 0x20 +#define INTEGRATOR_SC_OSC_SYS_15MHz 0x34 +#define INTEGRATOR_SC_OSC_SYS_20MHz 0x48 +#define INTEGRATOR_SC_OSC_SYS_25MHz 0x5C +#define INTEGRATOR_SC_OSC_SYS_33MHz 0x7C +#define INTEGRATOR_SC_OSC_SYS_MASK 0xFF + +#define INTEGRATOR_SC_OSC_PCI_25MHz 0x100 +#define INTEGRATOR_SC_OSC_PCI_33MHz 0x0 +#define INTEGRATOR_SC_OSC_PCI_MASK 0x100 + +#define INTEGRATOR_SC_CTRL_SOFTRST (1 << 0) +#define INTEGRATOR_SC_CTRL_nFLVPPEN (1 << 1) +#define INTEGRATOR_SC_CTRL_nFLWP (1 << 2) +#define INTEGRATOR_SC_CTRL_URTS0 (1 << 4) +#define INTEGRATOR_SC_CTRL_UDTR0 (1 << 5) +#define INTEGRATOR_SC_CTRL_URTS1 (1 << 6) +#define INTEGRATOR_SC_CTRL_UDTR1 (1 << 7) + +/* + * External Bus Interface + * + */ +#define INTEGRATOR_EBI_BASE 0x12000000 + +#define INTEGRATOR_EBI_CSR0_OFFSET 0x00 +#define INTEGRATOR_EBI_CSR1_OFFSET 0x04 +#define INTEGRATOR_EBI_CSR2_OFFSET 0x08 +#define INTEGRATOR_EBI_CSR3_OFFSET 0x0C +#define INTEGRATOR_EBI_LOCK_OFFSET 0x20 + +#define INTEGRATOR_EBI_CSR0 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR0_OFFSET) +#define INTEGRATOR_EBI_CSR1 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET) +#define INTEGRATOR_EBI_CSR2 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR2_OFFSET) +#define INTEGRATOR_EBI_CSR3 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR3_OFFSET) +#define INTEGRATOR_EBI_LOCK (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET) + +#define INTEGRATOR_EBI_8_BIT 0x00 +#define INTEGRATOR_EBI_16_BIT 0x01 +#define INTEGRATOR_EBI_32_BIT 0x02 +#define INTEGRATOR_EBI_WRITE_ENABLE 0x04 +#define INTEGRATOR_EBI_SYNC 0x08 +#define INTEGRATOR_EBI_WS_2 0x00 +#define INTEGRATOR_EBI_WS_3 0x10 +#define INTEGRATOR_EBI_WS_4 0x20 +#define INTEGRATOR_EBI_WS_5 0x30 +#define INTEGRATOR_EBI_WS_6 0x40 +#define INTEGRATOR_EBI_WS_7 0x50 +#define INTEGRATOR_EBI_WS_8 0x60 +#define INTEGRATOR_EBI_WS_9 0x70 +#define INTEGRATOR_EBI_WS_10 0x80 +#define INTEGRATOR_EBI_WS_11 0x90 +#define INTEGRATOR_EBI_WS_12 0xA0 +#define INTEGRATOR_EBI_WS_13 0xB0 +#define INTEGRATOR_EBI_WS_14 0xC0 +#define INTEGRATOR_EBI_WS_15 0xD0 +#define INTEGRATOR_EBI_WS_16 0xE0 +#define INTEGRATOR_EBI_WS_17 0xF0 + + +#define INTEGRATOR_CT_BASE 0x13000000 /* Counter/Timers */ +#define INTEGRATOR_IC_BASE 0x14000000 /* Interrupt Controller */ +#define INTEGRATOR_RTC_BASE 0x15000000 /* Real Time Clock */ +#define INTEGRATOR_UART0_BASE 0x16000000 /* UART 0 */ +#define INTEGRATOR_UART1_BASE 0x17000000 /* UART 1 */ +#define INTEGRATOR_KBD_BASE 0x18000000 /* Keyboard */ +#define INTEGRATOR_MOUSE_BASE 0x19000000 /* Mouse */ + +/* + * LED's & Switches + * + */ +#define INTEGRATOR_DBG_ALPHA_OFFSET 0x00 +#define INTEGRATOR_DBG_LEDS_OFFSET 0x04 +#define INTEGRATOR_DBG_SWITCH_OFFSET 0x08 + +#define INTEGRATOR_DBG_BASE 0x1A000000 +#define INTEGRATOR_DBG_ALPHA (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_ALPHA_OFFSET) +#define INTEGRATOR_DBG_LEDS (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_LEDS_OFFSET) +#define INTEGRATOR_DBG_SWITCH (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_SWITCH_OFFSET) + +#define INTEGRATOR_AP_GPIO_BASE 0x1B000000 /* GPIO */ + +#define INTEGRATOR_CP_MMC_BASE 0x1C000000 /* MMC */ +#define INTEGRATOR_CP_AACI_BASE 0x1D000000 /* AACI */ +#define INTEGRATOR_CP_ETH_BASE 0xC8000000 /* Ethernet */ +#define INTEGRATOR_CP_GPIO_BASE 0xC9000000 /* GPIO */ +#define INTEGRATOR_CP_SIC_BASE 0xCA000000 /* SIC */ +#define INTEGRATOR_CP_CTL_BASE 0xCB000000 /* CP system control */ + +/* ------------------------------------------------------------------------ + * KMI keyboard/mouse definitions + * ------------------------------------------------------------------------ + */ +/* PS2 Keyboard interface */ +#define KMI0_BASE INTEGRATOR_KBD_BASE + +/* PS2 Mouse interface */ +#define KMI1_BASE INTEGRATOR_MOUSE_BASE + +/* KMI definitions are now in include/asm-arm/hardware/amba_kmi.h -- rmk */ + +/* ------------------------------------------------------------------------ + * Where in the memory map does PCI live? + * ------------------------------------------------------------------------ + * This represents a fairly liberal usage of address space. Even though + * the V3 only has two windows (therefore we need to map stuff on the fly), + * we maintain the same addresses, even if they're not mapped. + * + */ +#define PHYS_PCI_MEM_BASE 0x40000000 /* 512M to xxx */ +/* unused 256M from A0000000-AFFFFFFF might be used for I2O ??? + */ +#define PHYS_PCI_IO_BASE 0x60000000 /* 16M to xxx */ +/* unused (128-16)M from B1000000-B7FFFFFF + */ +#define PHYS_PCI_CONFIG_BASE 0x61000000 /* 16M to xxx */ +/* unused ((128-16)M - 64K) from XXX + */ +#define PHYS_PCI_V3_BASE 0x62000000 + +#define PCI_MEMORY_VADDR IOMEM(0xe8000000) +#define PCI_CONFIG_VADDR IOMEM(0xec000000) +#define PCI_V3_VADDR IOMEM(0xed000000) + +/* ------------------------------------------------------------------------ + * Integrator Interrupt Controllers + * ------------------------------------------------------------------------ + * + * Offsets from interrupt controller base + * + * System Controller interrupt controller base is + * + * INTEGRATOR_IC_BASE + (header_number << 6) + * + * Core Module interrupt controller base is + * + * INTEGRATOR_HDR_IC + * + */ +#define IRQ_STATUS 0 +#define IRQ_RAW_STATUS 0x04 +#define IRQ_ENABLE 0x08 +#define IRQ_ENABLE_SET 0x08 +#define IRQ_ENABLE_CLEAR 0x0C + +#define INT_SOFT_SET 0x10 +#define INT_SOFT_CLEAR 0x14 + +#define FIQ_STATUS 0x20 +#define FIQ_RAW_STATUS 0x24 +#define FIQ_ENABLE 0x28 +#define FIQ_ENABLE_SET 0x28 +#define FIQ_ENABLE_CLEAR 0x2C + + +/* ------------------------------------------------------------------------ + * Interrupts + * ------------------------------------------------------------------------ + * + * + * Each Core Module has two interrupts controllers, one on the core module + * itself and one in the system controller on the motherboard. The + * READ_INT macro in target.s reads both interrupt controllers and returns + * a 32 bit bitmask, bits 0 to 23 are interrupts from the system controller + * and bits 24 to 31 are from the core module. + * + * The following definitions relate to the bitmask returned by READ_INT. + * + */ + +/* ------------------------------------------------------------------------ + * LED's + * ------------------------------------------------------------------------ + * + */ +#define GREEN_LED 0x01 +#define YELLOW_LED 0x02 +#define RED_LED 0x04 +#define GREEN_LED_2 0x08 +#define ALL_LEDS 0x0F + +#define LED_BANK INTEGRATOR_DBG_LEDS + +/* + * Timer definitions + * + * Only use timer 1 & 2 + * (both run at 24MHz and will need the clock divider set to 16). + * + * Timer 0 runs at bus frequency + */ + +#define INTEGRATOR_TIMER0_BASE INTEGRATOR_CT_BASE +#define INTEGRATOR_TIMER1_BASE (INTEGRATOR_CT_BASE + 0x100) +#define INTEGRATOR_TIMER2_BASE (INTEGRATOR_CT_BASE + 0x200) + +#define INTEGRATOR_CSR_BASE 0x10000000 +#define INTEGRATOR_CSR_SIZE 0x10000000 + +#endif diff --git a/arch/arm/mach-integrator/include/mach/timex.h b/arch/arm/mach-integrator/include/mach/timex.h new file mode 100644 index 00000000..1dcb4202 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/timex.h @@ -0,0 +1,26 @@ +/* + * arch/arm/mach-integrator/include/mach/timex.h + * + * Integrator architecture timex specifications + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * ?? + */ +#define CLOCK_TICK_RATE (50000000 / 16) diff --git a/arch/arm/mach-integrator/include/mach/uncompress.h b/arch/arm/mach-integrator/include/mach/uncompress.h new file mode 100644 index 00000000..8f3cc995 --- /dev/null +++ b/arch/arm/mach-integrator/include/mach/uncompress.h @@ -0,0 +1,48 @@ +/* + * arch/arm/mach-integrator/include/mach/uncompress.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define AMBA_UART_DR (*(volatile unsigned char *)0x16000000) +#define AMBA_UART_LCRH (*(volatile unsigned char *)0x16000008) +#define AMBA_UART_LCRM (*(volatile unsigned char *)0x1600000c) +#define AMBA_UART_LCRL (*(volatile unsigned char *)0x16000010) +#define AMBA_UART_CR (*(volatile unsigned char *)0x16000014) +#define AMBA_UART_FR (*(volatile unsigned char *)0x16000018) + +/* + * This does not append a newline + */ +static void putc(int c) +{ + while (AMBA_UART_FR & (1 << 5)) + barrier(); + + AMBA_UART_DR = c; +} + +static inline void flush(void) +{ + while (AMBA_UART_FR & (1 << 3)) + barrier(); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c new file mode 100644 index 00000000..b23c8e4f --- /dev/null +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -0,0 +1,714 @@ +/* + * linux/arch/arm/mach-integrator/integrator_ap.c + * + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/syscore_ops.h> +#include <linux/amba/bus.h> +#include <linux/amba/kmi.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irqchip/versatile-fpga.h> +#include <linux/mtd/physmap.h> +#include <linux/clk.h> +#include <linux/platform_data/clk-integrator.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/stat.h> +#include <linux/sys_soc.h> +#include <linux/termios.h> +#include <video/vga.h> + +#include <mach/hardware.h> +#include <mach/platform.h> +#include <asm/hardware/arm_timer.h> +#include <asm/setup.h> +#include <asm/param.h> /* HZ */ +#include <asm/mach-types.h> +#include <asm/sched_clock.h> + +#include <mach/lm.h> +#include <mach/irqs.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> +#include <asm/mach/pci.h> +#include <asm/mach/time.h> + +#include "common.h" + +/* Base address to the AP system controller */ +void __iomem *ap_syscon_base; + +/* + * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx + * is the (PA >> 12). + * + * Setup a VA for the Integrator interrupt controller (for header #0, + * just for now). + */ +#define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE) +#define VA_EBI_BASE __io_address(INTEGRATOR_EBI_BASE) +#define VA_CMIC_BASE __io_address(INTEGRATOR_HDR_IC) + +/* + * Logical Physical + * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M) + * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M) + * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k) + * fee00000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M) + * ef000000 Cache flush + * f1000000 10000000 Core module registers + * f1100000 11000000 System controller registers + * f1200000 12000000 EBI registers + * f1300000 13000000 Counter/Timer + * f1400000 14000000 Interrupt controller + * f1600000 16000000 UART 0 + * f1700000 17000000 UART 1 + * f1a00000 1a000000 Debug LEDs + * f1b00000 1b000000 GPIO + */ + +static struct map_desc ap_io_desc[] __initdata __maybe_unused = { + { + .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_AP_GPIO_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_AP_GPIO_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = (unsigned long)PCI_MEMORY_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_MEM_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = (unsigned long)PCI_CONFIG_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = (unsigned long)PCI_V3_VADDR, + .pfn = __phys_to_pfn(PHYS_PCI_V3_BASE), + .length = SZ_64K, + .type = MT_DEVICE + } +}; + +static void __init ap_map_io(void) +{ + iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc)); + vga_base = (unsigned long)PCI_MEMORY_VADDR; + pci_map_io_early(__phys_to_pfn(PHYS_PCI_IO_BASE)); +} + +#ifdef CONFIG_PM +static unsigned long ic_irq_enable; + +static int irq_suspend(void) +{ + ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE); + return 0; +} + +static void irq_resume(void) +{ + /* disable all irq sources */ + writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); + writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); + writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); + + writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET); +} +#else +#define irq_suspend NULL +#define irq_resume NULL +#endif + +static struct syscore_ops irq_syscore_ops = { + .suspend = irq_suspend, + .resume = irq_resume, +}; + +static int __init irq_syscore_init(void) +{ + register_syscore_ops(&irq_syscore_ops); + + return 0; +} + +device_initcall(irq_syscore_init); + +/* + * Flash handling. + */ +#define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET) +#define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET) + +static int ap_flash_init(struct platform_device *dev) +{ + u32 tmp; + + writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, + ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); + + tmp = readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE; + writel(tmp, EBI_CSR1); + + if (!(readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) { + writel(0xa05f, EBI_LOCK); + writel(tmp, EBI_CSR1); + writel(0, EBI_LOCK); + } + return 0; +} + +static void ap_flash_exit(struct platform_device *dev) +{ + u32 tmp; + + writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, + ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); + + tmp = readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE; + writel(tmp, EBI_CSR1); + + if (readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) { + writel(0xa05f, EBI_LOCK); + writel(tmp, EBI_CSR1); + writel(0, EBI_LOCK); + } +} + +static void ap_flash_set_vpp(struct platform_device *pdev, int on) +{ + if (on) + writel(INTEGRATOR_SC_CTRL_nFLVPPEN, + ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET); + else + writel(INTEGRATOR_SC_CTRL_nFLVPPEN, + ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); +} + +static struct physmap_flash_data ap_flash_data = { + .width = 4, + .init = ap_flash_init, + .exit = ap_flash_exit, + .set_vpp = ap_flash_set_vpp, +}; + +/* + * For the PL010 found in the Integrator/AP some of the UART control is + * implemented in the system controller and accessed using a callback + * from the driver. + */ +static void integrator_uart_set_mctrl(struct amba_device *dev, + void __iomem *base, unsigned int mctrl) +{ + unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask; + u32 phybase = dev->res.start; + + if (phybase == INTEGRATOR_UART0_BASE) { + /* UART0 */ + rts_mask = 1 << 4; + dtr_mask = 1 << 5; + } else { + /* UART1 */ + rts_mask = 1 << 6; + dtr_mask = 1 << 7; + } + + if (mctrl & TIOCM_RTS) + ctrlc |= rts_mask; + else + ctrls |= rts_mask; + + if (mctrl & TIOCM_DTR) + ctrlc |= dtr_mask; + else + ctrls |= dtr_mask; + + __raw_writel(ctrls, ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET); + __raw_writel(ctrlc, ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); +} + +struct amba_pl010_data ap_uart_data = { + .set_mctrl = integrator_uart_set_mctrl, +}; + +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE) +#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE) +#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE) + +static unsigned long timer_reload; + +static u32 notrace integrator_read_sched_clock(void) +{ + return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE); +} + +static void integrator_clocksource_init(unsigned long inrate, + void __iomem *base) +{ + u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; + unsigned long rate = inrate; + + if (rate >= 1500000) { + rate /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + + writel(0xffff, base + TIMER_LOAD); + writel(ctrl, base + TIMER_CTRL); + + clocksource_mmio_init(base + TIMER_VALUE, "timer2", + rate, 200, 16, clocksource_mmio_readl_down); + setup_sched_clock(integrator_read_sched_clock, 16, rate); +} + +static void __iomem * clkevt_base; + +/* + * IRQ handler for the timer + */ +static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + /* clear the interrupt */ + writel(1, clkevt_base + TIMER_INTCLR); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; + + /* Disable timer */ + writel(ctrl, clkevt_base + TIMER_CTRL); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* Enable the timer and start the periodic tick */ + writel(timer_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Leave the timer disabled, .set_next_event will enable it */ + ctrl &= ~TIMER_CTRL_PERIODIC; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_RESUME: + default: + /* Just leave in disabled state */ + break; + } + +} + +static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) +{ + unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + + writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + writel(next, clkevt_base + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device integrator_clockevent = { + .name = "timer1", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = clkevt_set_mode, + .set_next_event = clkevt_set_next_event, + .rating = 300, +}; + +static struct irqaction integrator_timer_irq = { + .name = "timer", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = integrator_timer_interrupt, + .dev_id = &integrator_clockevent, +}; + +static void integrator_clockevent_init(unsigned long inrate, + void __iomem *base, int irq) +{ + unsigned long rate = inrate; + unsigned int ctrl = 0; + + clkevt_base = base; + /* Calculate and program a divisor */ + if (rate > 0x100000 * HZ) { + rate /= 256; + ctrl |= TIMER_CTRL_DIV256; + } else if (rate > 0x10000 * HZ) { + rate /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + timer_reload = rate / HZ; + writel(ctrl, clkevt_base + TIMER_CTRL); + + setup_irq(irq, &integrator_timer_irq); + clockevents_config_and_register(&integrator_clockevent, + rate, + 1, + 0xffffU); +} + +void __init ap_init_early(void) +{ +} + +#ifdef CONFIG_OF + +static void __init ap_of_timer_init(void) +{ + struct device_node *node; + const char *path; + void __iomem *base; + int err; + int irq; + struct clk *clk; + unsigned long rate; + + clk = clk_get_sys("ap_timer", NULL); + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + + err = of_property_read_string(of_aliases, + "arm,timer-primary", &path); + if (WARN_ON(err)) + return; + node = of_find_node_by_path(path); + base = of_iomap(node, 0); + if (WARN_ON(!base)) + return; + writel(0, base + TIMER_CTRL); + integrator_clocksource_init(rate, base); + + err = of_property_read_string(of_aliases, + "arm,timer-secondary", &path); + if (WARN_ON(err)) + return; + node = of_find_node_by_path(path); + base = of_iomap(node, 0); + if (WARN_ON(!base)) + return; + irq = irq_of_parse_and_map(node, 0); + writel(0, base + TIMER_CTRL); + integrator_clockevent_init(rate, base, irq); +} + +static const struct of_device_id fpga_irq_of_match[] __initconst = { + { .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, }, + { /* Sentinel */ } +}; + +static void __init ap_init_irq_of(void) +{ + /* disable core module IRQs */ + writel(0xffffffffU, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); + of_irq_init(fpga_irq_of_match); + integrator_clk_init(false); +} + +/* For the Device Tree, add in the UART callbacks as AUXDATA */ +static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE, + "rtc", NULL), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE, + "uart0", &ap_uart_data), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE, + "uart1", &ap_uart_data), + OF_DEV_AUXDATA("arm,primecell", KMI0_BASE, + "kmi0", NULL), + OF_DEV_AUXDATA("arm,primecell", KMI1_BASE, + "kmi1", NULL), + OF_DEV_AUXDATA("cfi-flash", INTEGRATOR_FLASH_BASE, + "physmap-flash", &ap_flash_data), + { /* sentinel */ }, +}; + +static void __init ap_init_of(void) +{ + unsigned long sc_dec; + struct device_node *root; + struct device_node *syscon; + struct device *parent; + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + u32 ap_sc_id; + int err; + int i; + + /* Here we create an SoC device for the root node */ + root = of_find_node_by_path("/"); + if (!root) + return; + syscon = of_find_node_by_path("/syscon"); + if (!syscon) + return; + + ap_syscon_base = of_iomap(syscon, 0); + if (!ap_syscon_base) + return; + + ap_sc_id = readl(ap_syscon_base); + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return; + + err = of_property_read_string(root, "compatible", + &soc_dev_attr->soc_id); + if (err) + return; + err = of_property_read_string(root, "model", &soc_dev_attr->machine); + if (err) + return; + soc_dev_attr->family = "Integrator"; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", + 'A' + (ap_sc_id & 0x0f)); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr); + return; + } + + parent = soc_device_to_device(soc_dev); + integrator_init_sysfs(parent, ap_sc_id); + + of_platform_populate(root, of_default_bus_match_table, + ap_auxdata_lookup, parent); + + sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET); + for (i = 0; i < 4; i++) { + struct lm_device *lmdev; + + if ((sc_dec & (16 << i)) == 0) + continue; + + lmdev = kzalloc(sizeof(struct lm_device), GFP_KERNEL); + if (!lmdev) + continue; + + lmdev->resource.start = 0xc0000000 + 0x10000000 * i; + lmdev->resource.end = lmdev->resource.start + 0x0fffffff; + lmdev->resource.flags = IORESOURCE_MEM; + lmdev->irq = IRQ_AP_EXPINT0 + i; + lmdev->id = i; + + lm_device_register(lmdev); + } +} + +static const char * ap_dt_board_compat[] = { + "arm,integrator-ap", + NULL, +}; + +DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") + .reserve = integrator_reserve, + .map_io = ap_map_io, + .init_early = ap_init_early, + .init_irq = ap_init_irq_of, + .handle_irq = fpga_handle_irq, + .init_time = ap_of_timer_init, + .init_machine = ap_init_of, + .restart = integrator_restart, + .dt_compat = ap_dt_board_compat, +MACHINE_END + +#endif + +#ifdef CONFIG_ATAGS + +/* + * For the ATAG boot some static mappings are needed. This will + * go away with the ATAG support down the road. + */ + +static struct map_desc ap_io_desc_atag[] __initdata = { + { + .virtual = IO_ADDRESS(INTEGRATOR_SC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_SC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, +}; + +static void __init ap_map_io_atag(void) +{ + iotable_init(ap_io_desc_atag, ARRAY_SIZE(ap_io_desc_atag)); + ap_map_io(); +} + +/* + * This is where non-devicetree initialization code is collected and stashed + * for eventual deletion. + */ + +static struct resource cfi_flash_resource = { + .start = INTEGRATOR_FLASH_BASE, + .end = INTEGRATOR_FLASH_BASE + INTEGRATOR_FLASH_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device cfi_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &ap_flash_data, + }, + .num_resources = 1, + .resource = &cfi_flash_resource, +}; + +static void __init ap_timer_init(void) +{ + struct clk *clk; + unsigned long rate; + + clk = clk_get_sys("ap_timer", NULL); + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + + writel(0, TIMER0_VA_BASE + TIMER_CTRL); + writel(0, TIMER1_VA_BASE + TIMER_CTRL); + writel(0, TIMER2_VA_BASE + TIMER_CTRL); + + integrator_clocksource_init(rate, (void __iomem *)TIMER2_VA_BASE); + integrator_clockevent_init(rate, (void __iomem *)TIMER1_VA_BASE, + IRQ_TIMERINT1); +} + +#define INTEGRATOR_SC_VALID_INT 0x003fffff + +static void __init ap_init_irq(void) +{ + /* Disable all interrupts initially. */ + /* Do the core module ones */ + writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); + + /* do the header card stuff next */ + writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); + writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); + + fpga_irq_init(VA_IC_BASE, "SC", IRQ_PIC_START, + -1, INTEGRATOR_SC_VALID_INT, NULL); + integrator_clk_init(false); +} + +static void __init ap_init(void) +{ + unsigned long sc_dec; + int i; + + platform_device_register(&cfi_flash_device); + + ap_syscon_base = __io_address(INTEGRATOR_SC_BASE); + sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET); + for (i = 0; i < 4; i++) { + struct lm_device *lmdev; + + if ((sc_dec & (16 << i)) == 0) + continue; + + lmdev = kzalloc(sizeof(struct lm_device), GFP_KERNEL); + if (!lmdev) + continue; + + lmdev->resource.start = 0xc0000000 + 0x10000000 * i; + lmdev->resource.end = lmdev->resource.start + 0x0fffffff; + lmdev->resource.flags = IORESOURCE_MEM; + lmdev->irq = IRQ_AP_EXPINT0 + i; + lmdev->id = i; + + lm_device_register(lmdev); + } + + integrator_init(false); +} + +MACHINE_START(INTEGRATOR, "ARM-Integrator") + /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ + .atag_offset = 0x100, + .reserve = integrator_reserve, + .map_io = ap_map_io_atag, + .init_early = ap_init_early, + .init_irq = ap_init_irq, + .handle_irq = fpga_handle_irq, + .init_time = ap_timer_init, + .init_machine = ap_init, + .restart = integrator_restart, +MACHINE_END + +#endif diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c new file mode 100644 index 00000000..2f4c9248 --- /dev/null +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -0,0 +1,529 @@ +/* + * linux/arch/arm/mach-integrator/integrator_cp.c + * + * Copyright (C) 2003 Deep Blue Solutions Ltd + * + * 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. + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/string.h> +#include <linux/device.h> +#include <linux/amba/bus.h> +#include <linux/amba/kmi.h> +#include <linux/amba/clcd.h> +#include <linux/amba/mmci.h> +#include <linux/io.h> +#include <linux/irqchip/versatile-fpga.h> +#include <linux/gfp.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_data/clk-integrator.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/sys_soc.h> + +#include <mach/hardware.h> +#include <mach/platform.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/hardware/arm_timer.h> +#include <asm/hardware/icst.h> + +#include <mach/cm.h> +#include <mach/lm.h> +#include <mach/irqs.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> + +#include <asm/hardware/timer-sp.h> + +#include <plat/clcd.h> +#include <plat/sched_clock.h> + +#include "common.h" + +/* Base address to the CP controller */ +static void __iomem *intcp_con_base; + +#define INTCP_PA_FLASH_BASE 0x24000000 + +#define INTCP_PA_CLCD_BASE 0xc0000000 + +#define INTCP_FLASHPROG 0x04 +#define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0) +#define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1) + +/* + * Logical Physical + * f1000000 10000000 Core module registers + * f1100000 11000000 System controller registers + * f1200000 12000000 EBI registers + * f1300000 13000000 Counter/Timer + * f1400000 14000000 Interrupt controller + * f1600000 16000000 UART 0 + * f1700000 17000000 UART 1 + * f1a00000 1a000000 Debug LEDs + * fc900000 c9000000 GPIO + * fca00000 ca000000 SIC + * fcb00000 cb000000 CP system control + */ + +static struct map_desc intcp_io_desc[] __initdata __maybe_unused = { + { + .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_CP_GPIO_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_GPIO_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + } +}; + +static void __init intcp_map_io(void) +{ + iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); +} + +/* + * Flash handling. + */ +static int intcp_flash_init(struct platform_device *dev) +{ + u32 val; + + val = readl(intcp_con_base + INTCP_FLASHPROG); + val |= CINTEGRATOR_FLASHPROG_FLWREN; + writel(val, intcp_con_base + INTCP_FLASHPROG); + + return 0; +} + +static void intcp_flash_exit(struct platform_device *dev) +{ + u32 val; + + val = readl(intcp_con_base + INTCP_FLASHPROG); + val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN); + writel(val, intcp_con_base + INTCP_FLASHPROG); +} + +static void intcp_flash_set_vpp(struct platform_device *pdev, int on) +{ + u32 val; + + val = readl(intcp_con_base + INTCP_FLASHPROG); + if (on) + val |= CINTEGRATOR_FLASHPROG_FLVPPEN; + else + val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN; + writel(val, intcp_con_base + INTCP_FLASHPROG); +} + +static struct physmap_flash_data intcp_flash_data = { + .width = 4, + .init = intcp_flash_init, + .exit = intcp_flash_exit, + .set_vpp = intcp_flash_set_vpp, +}; + +/* + * It seems that the card insertion interrupt remains active after + * we've acknowledged it. We therefore ignore the interrupt, and + * rely on reading it from the SIC. This also means that we must + * clear the latched interrupt. + */ +static unsigned int mmc_status(struct device *dev) +{ + unsigned int status = readl(__io_address(0xca000000 + 4)); + writel(8, intcp_con_base + 8); + + return status & 8; +} + +static struct mmci_platform_data mmc_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, + .gpio_wp = -1, + .gpio_cd = -1, +}; + +/* + * CLCD support + */ +/* + * Ensure VGA is selected. + */ +static void cp_clcd_enable(struct clcd_fb *fb) +{ + struct fb_var_screeninfo *var = &fb->fb.var; + u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2 + | CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1; + + if (var->bits_per_pixel <= 8 || + (var->bits_per_pixel == 16 && var->green.length == 5)) + /* Pseudocolor, RGB555, BGR555 */ + val |= CM_CTRL_LCDMUXSEL_VGA555_TFT555; + else if (fb->fb.var.bits_per_pixel <= 16) + /* truecolor RGB565 */ + val |= CM_CTRL_LCDMUXSEL_VGA565_TFT555; + else + val = 0; /* no idea for this, don't trust the docs */ + + cm_control(CM_CTRL_LCDMUXSEL_MASK| + CM_CTRL_LCDEN0| + CM_CTRL_LCDEN1| + CM_CTRL_STATIC1| + CM_CTRL_STATIC2| + CM_CTRL_STATIC| + CM_CTRL_n24BITEN, val); +} + +static int cp_clcd_setup(struct clcd_fb *fb) +{ + fb->panel = versatile_clcd_get_panel("VGA"); + if (!fb->panel) + return -EINVAL; + + return versatile_clcd_setup_dma(fb, SZ_1M); +} + +static struct clcd_board clcd_data = { + .name = "Integrator/CP", + .caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 | CLCD_CAP_888, + .check = clcdfb_check, + .decode = clcdfb_decode, + .enable = cp_clcd_enable, + .setup = cp_clcd_setup, + .mmap = versatile_clcd_mmap_dma, + .remove = versatile_clcd_remove_dma, +}; + +#define REFCOUNTER (__io_address(INTEGRATOR_HDR_BASE) + 0x28) + +static void __init intcp_init_early(void) +{ +#ifdef CONFIG_PLAT_VERSATILE_SCHED_CLOCK + versatile_sched_clock_init(REFCOUNTER, 24000000); +#endif +} + +#ifdef CONFIG_OF +static const struct of_device_id fpga_irq_of_match[] __initconst = { + { .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, }, + { /* Sentinel */ } +}; + +static void __init intcp_init_irq_of(void) +{ + of_irq_init(fpga_irq_of_match); + integrator_clk_init(true); +} + +/* + * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA + * and enforce the bus names since these are used for clock lookups. + */ +static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE, + "rtc", NULL), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE, + "uart0", NULL), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE, + "uart1", NULL), + OF_DEV_AUXDATA("arm,primecell", KMI0_BASE, + "kmi0", NULL), + OF_DEV_AUXDATA("arm,primecell", KMI1_BASE, + "kmi1", NULL), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE, + "mmci", &mmc_data), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_AACI_BASE, + "aaci", &mmc_data), + OF_DEV_AUXDATA("arm,primecell", INTCP_PA_CLCD_BASE, + "clcd", &clcd_data), + OF_DEV_AUXDATA("cfi-flash", INTCP_PA_FLASH_BASE, + "physmap-flash", &intcp_flash_data), + { /* sentinel */ }, +}; + +static void __init intcp_init_of(void) +{ + struct device_node *root; + struct device_node *cpcon; + struct device *parent; + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + u32 intcp_sc_id; + int err; + + /* Here we create an SoC device for the root node */ + root = of_find_node_by_path("/"); + if (!root) + return; + cpcon = of_find_node_by_path("/cpcon"); + if (!cpcon) + return; + + intcp_con_base = of_iomap(cpcon, 0); + if (!intcp_con_base) + return; + + intcp_sc_id = readl(intcp_con_base); + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return; + + err = of_property_read_string(root, "compatible", + &soc_dev_attr->soc_id); + if (err) + return; + err = of_property_read_string(root, "model", &soc_dev_attr->machine); + if (err) + return; + soc_dev_attr->family = "Integrator"; + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", + 'A' + (intcp_sc_id & 0x0f)); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr); + return; + } + + parent = soc_device_to_device(soc_dev); + integrator_init_sysfs(parent, intcp_sc_id); + of_platform_populate(root, of_default_bus_match_table, + intcp_auxdata_lookup, parent); +} + +static const char * intcp_dt_board_compat[] = { + "arm,integrator-cp", + NULL, +}; + +DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") + .reserve = integrator_reserve, + .map_io = intcp_map_io, + .init_early = intcp_init_early, + .init_irq = intcp_init_irq_of, + .handle_irq = fpga_handle_irq, + .init_machine = intcp_init_of, + .restart = integrator_restart, + .dt_compat = intcp_dt_board_compat, +MACHINE_END + +#endif + +#ifdef CONFIG_ATAGS + +/* + * For the ATAG boot some static mappings are needed. This will + * go away with the ATAG support down the road. + */ + +static struct map_desc intcp_io_desc_atag[] __initdata = { + { + .virtual = IO_ADDRESS(INTEGRATOR_CP_CTL_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_CTL_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, +}; + +static void __init intcp_map_io_atag(void) +{ + iotable_init(intcp_io_desc_atag, ARRAY_SIZE(intcp_io_desc_atag)); + intcp_con_base = __io_address(INTEGRATOR_CP_CTL_BASE); + intcp_map_io(); +} + + +/* + * This is where non-devicetree initialization code is collected and stashed + * for eventual deletion. + */ + +#define INTCP_FLASH_SIZE SZ_32M + +static struct resource intcp_flash_resource = { + .start = INTCP_PA_FLASH_BASE, + .end = INTCP_PA_FLASH_BASE + INTCP_FLASH_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device intcp_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &intcp_flash_data, + }, + .num_resources = 1, + .resource = &intcp_flash_resource, +}; + +#define INTCP_ETH_SIZE 0x10 + +static struct resource smc91x_resources[] = { + [0] = { + .start = INTEGRATOR_CP_ETH_BASE, + .end = INTEGRATOR_CP_ETH_BASE + INTCP_ETH_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_CP_ETHINT, + .end = IRQ_CP_ETHINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *intcp_devs[] __initdata = { + &intcp_flash_device, + &smc91x_device, +}; + +#define INTCP_VA_CIC_BASE __io_address(INTEGRATOR_HDR_BASE + 0x40) +#define INTCP_VA_PIC_BASE __io_address(INTEGRATOR_IC_BASE) +#define INTCP_VA_SIC_BASE __io_address(INTEGRATOR_CP_SIC_BASE) + +static void __init intcp_init_irq(void) +{ + u32 pic_mask, cic_mask, sic_mask; + + /* These masks are for the HW IRQ registers */ + pic_mask = ~((~0u) << (11 - 0)); + pic_mask |= (~((~0u) << (29 - 22))) << 22; + cic_mask = ~((~0u) << (1 + IRQ_CIC_END - IRQ_CIC_START)); + sic_mask = ~((~0u) << (1 + IRQ_SIC_END - IRQ_SIC_START)); + + /* + * Disable all interrupt sources + */ + writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR); + writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR); + writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR); + writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR); + writel(sic_mask, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); + writel(sic_mask, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR); + + fpga_irq_init(INTCP_VA_PIC_BASE, "PIC", IRQ_PIC_START, + -1, pic_mask, NULL); + + fpga_irq_init(INTCP_VA_CIC_BASE, "CIC", IRQ_CIC_START, + -1, cic_mask, NULL); + + fpga_irq_init(INTCP_VA_SIC_BASE, "SIC", IRQ_SIC_START, + IRQ_CP_CPPLDINT, sic_mask, NULL); + + integrator_clk_init(true); +} + +#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE) +#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE) +#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE) + +static void __init cp_timer_init(void) +{ + writel(0, TIMER0_VA_BASE + TIMER_CTRL); + writel(0, TIMER1_VA_BASE + TIMER_CTRL); + writel(0, TIMER2_VA_BASE + TIMER_CTRL); + + sp804_clocksource_init(TIMER2_VA_BASE, "timer2"); + sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1, "timer1"); +} + +#define INTEGRATOR_CP_MMC_IRQS { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 } +#define INTEGRATOR_CP_AACI_IRQS { IRQ_CP_AACIINT } + +static AMBA_APB_DEVICE(mmc, "mmci", 0, INTEGRATOR_CP_MMC_BASE, + INTEGRATOR_CP_MMC_IRQS, &mmc_data); + +static AMBA_APB_DEVICE(aaci, "aaci", 0, INTEGRATOR_CP_AACI_BASE, + INTEGRATOR_CP_AACI_IRQS, NULL); + +static AMBA_AHB_DEVICE(clcd, "clcd", 0, INTCP_PA_CLCD_BASE, + { IRQ_CP_CLCDCINT }, &clcd_data); + +static struct amba_device *amba_devs[] __initdata = { + &mmc_device, + &aaci_device, + &clcd_device, +}; + +static void __init intcp_init(void) +{ + int i; + + platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs)); + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + struct amba_device *d = amba_devs[i]; + amba_device_register(d, &iomem_resource); + } + integrator_init(true); +} + +MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") + /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ + .atag_offset = 0x100, + .reserve = integrator_reserve, + .map_io = intcp_map_io_atag, + .init_early = intcp_init_early, + .init_irq = intcp_init_irq, + .handle_irq = fpga_handle_irq, + .init_time = cp_timer_init, + .init_machine = intcp_init, + .restart = integrator_restart, +MACHINE_END + +#endif diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c new file mode 100644 index 00000000..7a7f6d32 --- /dev/null +++ b/arch/arm/mach-integrator/leds.c @@ -0,0 +1,125 @@ +/* + * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard + * Based on Versatile and RealView machine LED code + * + * License terms: GNU General Public License (GPL) version 2 + * Author: Bryan Wu <bryan.wu@canonical.com> + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> + +#include <mach/cm.h> +#include <mach/hardware.h> +#include <mach/platform.h> + +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) + +#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE) +#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET) + +struct integrator_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} integrator_leds[] = { + { "integrator:green0", "heartbeat", }, + { "integrator:yellow", }, + { "integrator:red", }, + { "integrator:green1", }, + { "integrator:core_module", "cpu0", }, +}; + +static void integrator_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct integrator_led *led = container_of(cdev, + struct integrator_led, cdev); + u32 reg = __raw_readl(LEDREG); + + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; + + while (__raw_readl(ALPHA_REG) & 1) + cpu_relax(); + + __raw_writel(reg, LEDREG); +} + +static enum led_brightness integrator_led_get(struct led_classdev *cdev) +{ + struct integrator_led *led = container_of(cdev, + struct integrator_led, cdev); + u32 reg = __raw_readl(LEDREG); + + return (reg & led->mask) ? LED_FULL : LED_OFF; +} + +static void cm_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + if (b != LED_OFF) + cm_control(CM_CTRL_LED, CM_CTRL_LED); + else + cm_control(CM_CTRL_LED, 0); +} + +static enum led_brightness cm_led_get(struct led_classdev *cdev) +{ + u32 reg = readl(CM_CTRL); + + return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF; +} + +static int __init integrator_leds_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) { + struct integrator_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + + led->cdev.name = integrator_leds[i].name; + + if (i == 4) { /* Setting for LED in core module */ + led->cdev.brightness_set = cm_led_set; + led->cdev.brightness_get = cm_led_get; + } else { + led->cdev.brightness_set = integrator_led_set; + led->cdev.brightness_get = integrator_led_get; + } + + led->cdev.default_trigger = integrator_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(integrator_leds_init); +#endif diff --git a/arch/arm/mach-integrator/lm.c b/arch/arm/mach-integrator/lm.c new file mode 100644 index 00000000..f52c7af3 --- /dev/null +++ b/arch/arm/mach-integrator/lm.c @@ -0,0 +1,99 @@ +/* + * linux/arch/arm/mach-integrator/lm.c + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/slab.h> + +#include <mach/lm.h> + +#define to_lm_device(d) container_of(d, struct lm_device, dev) +#define to_lm_driver(d) container_of(d, struct lm_driver, drv) + +static int lm_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static int lm_bus_probe(struct device *dev) +{ + struct lm_device *lmdev = to_lm_device(dev); + struct lm_driver *lmdrv = to_lm_driver(dev->driver); + + return lmdrv->probe(lmdev); +} + +static int lm_bus_remove(struct device *dev) +{ + struct lm_device *lmdev = to_lm_device(dev); + struct lm_driver *lmdrv = to_lm_driver(dev->driver); + + if (lmdrv->remove) + lmdrv->remove(lmdev); + return 0; +} + +static struct bus_type lm_bustype = { + .name = "logicmodule", + .match = lm_match, + .probe = lm_bus_probe, + .remove = lm_bus_remove, +// .suspend = lm_bus_suspend, +// .resume = lm_bus_resume, +}; + +static int __init lm_init(void) +{ + return bus_register(&lm_bustype); +} + +postcore_initcall(lm_init); + +int lm_driver_register(struct lm_driver *drv) +{ + drv->drv.bus = &lm_bustype; + return driver_register(&drv->drv); +} + +void lm_driver_unregister(struct lm_driver *drv) +{ + driver_unregister(&drv->drv); +} + +static void lm_device_release(struct device *dev) +{ + struct lm_device *d = to_lm_device(dev); + + kfree(d); +} + +int lm_device_register(struct lm_device *dev) +{ + int ret; + + dev->dev.release = lm_device_release; + dev->dev.bus = &lm_bustype; + + ret = dev_set_name(&dev->dev, "lm%d", dev->id); + if (ret) + return ret; + dev->resource.name = dev_name(&dev->dev); + + ret = request_resource(&iomem_resource, &dev->resource); + if (ret == 0) { + ret = device_register(&dev->dev); + if (ret) + release_resource(&dev->resource); + } + return ret; +} + +EXPORT_SYMBOL(lm_driver_register); +EXPORT_SYMBOL(lm_driver_unregister); diff --git a/arch/arm/mach-integrator/pci.c b/arch/arm/mach-integrator/pci.c new file mode 100644 index 00000000..6c1667e7 --- /dev/null +++ b/arch/arm/mach-integrator/pci.c @@ -0,0 +1,113 @@ +/* + * linux/arch/arm/mach-integrator/pci-integrator.c + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * PCI functions for Integrator + */ +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/init.h> + +#include <asm/mach/pci.h> +#include <asm/mach-types.h> + +#include <mach/irqs.h> + +/* + * A small note about bridges and interrupts. The DECchip 21050 (and + * later) adheres to the PCI-PCI bridge specification. This says that + * the interrupts on the other side of a bridge are swizzled in the + * following manner: + * + * Dev Interrupt Interrupt + * Pin on Pin on + * Device Connector + * + * 4 A A + * B B + * C C + * D D + * + * 5 A B + * B C + * C D + * D A + * + * 6 A C + * B D + * C A + * D B + * + * 7 A D + * B A + * C B + * D C + * + * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. + * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 + */ + +/* + * This routine handles multiple bridges. + */ +static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp) +{ + if (*pinp == 0) + *pinp = 1; + + return pci_common_swizzle(dev, pinp); +} + +static int irq_tab[4] __initdata = { + IRQ_AP_PCIINT0, IRQ_AP_PCIINT1, IRQ_AP_PCIINT2, IRQ_AP_PCIINT3 +}; + +/* + * map the specified device/slot/pin to an IRQ. This works out such + * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1. + */ +static int __init integrator_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int intnr = ((slot - 9) + (pin - 1)) & 3; + + return irq_tab[intnr]; +} + +extern void pci_v3_init(void *); + +static struct hw_pci integrator_pci __initdata = { + .swizzle = integrator_swizzle, + .map_irq = integrator_map_irq, + .setup = pci_v3_setup, + .nr_controllers = 1, + .ops = &pci_v3_ops, + .preinit = pci_v3_preinit, + .postinit = pci_v3_postinit, +}; + +static int __init integrator_pci_init(void) +{ + if (machine_is_integrator()) + pci_common_init(&integrator_pci); + return 0; +} + +subsys_initcall(integrator_pci_init); diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c new file mode 100644 index 00000000..e7fcea7f --- /dev/null +++ b/arch/arm/mach-integrator/pci_v3.c @@ -0,0 +1,612 @@ +/* + * linux/arch/arm/mach-integrator/pci_v3.c + * + * PCI functions for V3 host PCI bridge + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000-2001 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/platform.h> +#include <mach/irqs.h> + +#include <asm/signal.h> +#include <asm/mach/pci.h> +#include <asm/irq_regs.h> + +#include <asm/hardware/pci_v3.h> + +/* + * The V3 PCI interface chip in Integrator provides several windows from + * local bus memory into the PCI memory areas. Unfortunately, there + * are not really enough windows for our usage, therefore we reuse + * one of the windows for access to PCI configuration space. The + * memory map is as follows: + * + * Local Bus Memory Usage + * + * 40000000 - 4FFFFFFF PCI memory. 256M non-prefetchable + * 50000000 - 5FFFFFFF PCI memory. 256M prefetchable + * 60000000 - 60FFFFFF PCI IO. 16M + * 61000000 - 61FFFFFF PCI Configuration. 16M + * + * There are three V3 windows, each described by a pair of V3 registers. + * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2. + * Base0 and Base1 can be used for any type of PCI memory access. Base2 + * can be used either for PCI I/O or for I20 accesses. By default, uHAL + * uses this only for PCI IO space. + * + * Normally these spaces are mapped using the following base registers: + * + * Usage Local Bus Memory Base/Map registers used + * + * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0 + * Mem 50000000 - 5FFFFFFF LB_BASE1/LB_MAP1 + * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2 + * Cfg 61000000 - 61FFFFFF + * + * This means that I20 and PCI configuration space accesses will fail. + * When PCI configuration accesses are needed (via the uHAL PCI + * configuration space primitives) we must remap the spaces as follows: + * + * Usage Local Bus Memory Base/Map registers used + * + * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0 + * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0 + * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2 + * Cfg 61000000 - 61FFFFFF LB_BASE1/LB_MAP1 + * + * To make this work, the code depends on overlapping windows working. + * The V3 chip translates an address by checking its range within + * each of the BASE/MAP pairs in turn (in ascending register number + * order). It will use the first matching pair. So, for example, + * if the same address is mapped by both LB_BASE0/LB_MAP0 and + * LB_BASE1/LB_MAP1, the V3 will use the translation from + * LB_BASE0/LB_MAP0. + * + * To allow PCI Configuration space access, the code enlarges the + * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M. This occludes + * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can + * be remapped for use by configuration cycles. + * + * At the end of the PCI Configuration space accesses, + * LB_BASE1/LB_MAP1 is reset to map PCI Memory. Finally the window + * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to + * reveal the now restored LB_BASE1/LB_MAP1 window. + * + * NOTE: We do not set up I2O mapping. I suspect that this is only + * for an intelligent (target) device. Using I2O disables most of + * the mappings into PCI memory. + */ + +// V3 access routines +#define v3_writeb(o,v) __raw_writeb(v, PCI_V3_VADDR + (unsigned int)(o)) +#define v3_readb(o) (__raw_readb(PCI_V3_VADDR + (unsigned int)(o))) + +#define v3_writew(o,v) __raw_writew(v, PCI_V3_VADDR + (unsigned int)(o)) +#define v3_readw(o) (__raw_readw(PCI_V3_VADDR + (unsigned int)(o))) + +#define v3_writel(o,v) __raw_writel(v, PCI_V3_VADDR + (unsigned int)(o)) +#define v3_readl(o) (__raw_readl(PCI_V3_VADDR + (unsigned int)(o))) + +/*============================================================================ + * + * routine: uHALir_PCIMakeConfigAddress() + * + * parameters: bus = which bus + * device = which device + * function = which function + * offset = configuration space register we are interested in + * + * description: this routine will generate a platform dependent config + * address. + * + * calls: none + * + * returns: configuration address to play on the PCI bus + * + * To generate the appropriate PCI configuration cycles in the PCI + * configuration address space, you present the V3 with the following pattern + * (which is very nearly a type 1 (except that the lower two bits are 00 and + * not 01). In order for this mapping to work you need to set up one of + * the local to PCI aperatures to 16Mbytes in length translating to + * PCI configuration space starting at 0x0000.0000. + * + * PCI configuration cycles look like this: + * + * Type 0: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:11 Device select bit. + * 10:8 Function number + * 7:2 Register number + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + */ +static DEFINE_RAW_SPINLOCK(v3_lock); + +#define PCI_BUS_NONMEM_START 0x00000000 +#define PCI_BUS_NONMEM_SIZE SZ_256M + +#define PCI_BUS_PREMEM_START PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE +#define PCI_BUS_PREMEM_SIZE SZ_256M + +#if PCI_BUS_NONMEM_START & 0x000fffff +#error PCI_BUS_NONMEM_START must be megabyte aligned +#endif +#if PCI_BUS_PREMEM_START & 0x000fffff +#error PCI_BUS_PREMEM_START must be megabyte aligned +#endif + +#undef V3_LB_BASE_PREFETCH +#define V3_LB_BASE_PREFETCH 0 + +static void __iomem *v3_open_config_window(struct pci_bus *bus, + unsigned int devfn, int offset) +{ + unsigned int address, mapaddress, busnr; + + busnr = bus->number; + + /* + * Trap out illegal values + */ + BUG_ON(offset > 255); + BUG_ON(busnr > 255); + BUG_ON(devfn > 255); + + if (busnr == 0) { + int slot = PCI_SLOT(devfn); + + /* + * local bus segment so need a type 0 config cycle + * + * build the PCI configuration "address" with one-hot in + * A31-A11 + * + * mapaddress: + * 3:1 = config cycle (101) + * 0 = PCI A1 & A0 are 0 (0) + */ + address = PCI_FUNC(devfn) << 8; + mapaddress = V3_LB_MAP_TYPE_CONFIG; + + if (slot > 12) + /* + * high order bits are handled by the MAP register + */ + mapaddress |= 1 << (slot - 5); + else + /* + * low order bits handled directly in the address + */ + address |= 1 << (slot + 11); + } else { + /* + * not the local bus segment so need a type 1 config cycle + * + * address: + * 23:16 = bus number + * 15:11 = slot number (7:3 of devfn) + * 10:8 = func number (2:0 of devfn) + * + * mapaddress: + * 3:1 = config cycle (101) + * 0 = PCI A1 & A0 from host bus (1) + */ + mapaddress = V3_LB_MAP_TYPE_CONFIG | V3_LB_MAP_AD_LOW_EN; + address = (busnr << 16) | (devfn << 8); + } + + /* + * Set up base0 to see all 512Mbytes of memory space (not + * prefetchable), this frees up base1 for re-use by + * configuration memory + */ + v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) | + V3_LB_BASE_ADR_SIZE_512MB | V3_LB_BASE_ENABLE); + + /* + * Set up base1/map1 to point into configuration space. + */ + v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_CONFIG_BASE) | + V3_LB_BASE_ADR_SIZE_16MB | V3_LB_BASE_ENABLE); + v3_writew(V3_LB_MAP1, mapaddress); + + return PCI_CONFIG_VADDR + address + offset; +} + +static void v3_close_config_window(void) +{ + /* + * Reassign base1 for use by prefetchable PCI memory + */ + v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) | + V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH | + V3_LB_BASE_ENABLE); + v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) | + V3_LB_MAP_TYPE_MEM_MULTIPLE); + + /* + * And shrink base0 back to a 256M window (NOTE: MAP0 already correct) + */ + v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) | + V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE); +} + +static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *val) +{ + void __iomem *addr; + unsigned long flags; + u32 v; + + raw_spin_lock_irqsave(&v3_lock, flags); + addr = v3_open_config_window(bus, devfn, where); + + switch (size) { + case 1: + v = __raw_readb(addr); + break; + + case 2: + v = __raw_readw(addr); + break; + + default: + v = __raw_readl(addr); + break; + } + + v3_close_config_window(); + raw_spin_unlock_irqrestore(&v3_lock, flags); + + *val = v; + return PCIBIOS_SUCCESSFUL; +} + +static int v3_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + void __iomem *addr; + unsigned long flags; + + raw_spin_lock_irqsave(&v3_lock, flags); + addr = v3_open_config_window(bus, devfn, where); + + switch (size) { + case 1: + __raw_writeb((u8)val, addr); + __raw_readb(addr); + break; + + case 2: + __raw_writew((u16)val, addr); + __raw_readw(addr); + break; + + case 4: + __raw_writel(val, addr); + __raw_readl(addr); + break; + } + + v3_close_config_window(); + raw_spin_unlock_irqrestore(&v3_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops pci_v3_ops = { + .read = v3_read_config, + .write = v3_write_config, +}; + +static struct resource non_mem = { + .name = "PCI non-prefetchable", + .start = PHYS_PCI_MEM_BASE + PCI_BUS_NONMEM_START, + .end = PHYS_PCI_MEM_BASE + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource pre_mem = { + .name = "PCI prefetchable", + .start = PHYS_PCI_MEM_BASE + PCI_BUS_PREMEM_START, + .end = PHYS_PCI_MEM_BASE + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1, + .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH, +}; + +static int __init pci_v3_setup_resources(struct pci_sys_data *sys) +{ + if (request_resource(&iomem_resource, &non_mem)) { + printk(KERN_ERR "PCI: unable to allocate non-prefetchable " + "memory region\n"); + return -EBUSY; + } + if (request_resource(&iomem_resource, &pre_mem)) { + release_resource(&non_mem); + printk(KERN_ERR "PCI: unable to allocate prefetchable " + "memory region\n"); + return -EBUSY; + } + + /* + * the mem resource for this bus + * the prefetch mem resource for this bus + */ + pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset); + pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset); + + return 1; +} + +/* + * These don't seem to be implemented on the Integrator I have, which + * means I can't get additional information on the reason for the pm2fb + * problems. I suppose I'll just have to mind-meld with the machine. ;) + */ +static void __iomem *ap_syscon_base; +#define INTEGRATOR_SC_PCIENABLE_OFFSET 0x18 +#define INTEGRATOR_SC_LBFADDR_OFFSET 0x20 +#define INTEGRATOR_SC_LBFCODE_OFFSET 0x24 + +static int +v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + unsigned long instr = *(unsigned long *)pc; +#if 0 + char buf[128]; + + sprintf(buf, "V3 fault: addr 0x%08lx, FSR 0x%03x, PC 0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", + addr, fsr, pc, instr, __raw_readl(ap_syscon_base + INTEGRATOR_SC_LBFADDR_OFFSET), __raw_readl(ap_syscon_base + INTEGRATOR_SC_LBFCODE_OFFSET) & 255, + v3_readb(V3_LB_ISTAT)); + printk(KERN_DEBUG "%s", buf); +#endif + + v3_writeb(V3_LB_ISTAT, 0); + __raw_writel(3, ap_syscon_base + INTEGRATOR_SC_PCIENABLE_OFFSET); + + /* + * If the instruction being executed was a read, + * make it look like it read all-ones. + */ + if ((instr & 0x0c100000) == 0x04100000) { + int reg = (instr >> 12) & 15; + unsigned long val; + + if (instr & 0x00400000) + val = 255; + else + val = -1; + + regs->uregs[reg] = val; + regs->ARM_pc += 4; + return 0; + } + + if ((instr & 0x0e100090) == 0x00100090) { + int reg = (instr >> 12) & 15; + + regs->uregs[reg] = -1; + regs->ARM_pc += 4; + return 0; + } + + return 1; +} + +static irqreturn_t v3_irq(int dummy, void *devid) +{ +#ifdef CONFIG_DEBUG_LL + struct pt_regs *regs = get_irq_regs(); + unsigned long pc = instruction_pointer(regs); + unsigned long instr = *(unsigned long *)pc; + char buf[128]; + extern void printascii(const char *); + + sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x " + "ISTAT=%02x\n", IRQ_AP_V3INT, pc, instr, + __raw_readl(ap_syscon_base + INTEGRATOR_SC_LBFADDR_OFFSET), + __raw_readl(ap_syscon_base + INTEGRATOR_SC_LBFCODE_OFFSET) & 255, + v3_readb(V3_LB_ISTAT)); + printascii(buf); +#endif + + v3_writew(V3_PCI_STAT, 0xf000); + v3_writeb(V3_LB_ISTAT, 0); + __raw_writel(3, ap_syscon_base + INTEGRATOR_SC_PCIENABLE_OFFSET); + +#ifdef CONFIG_DEBUG_LL + /* + * If the instruction being executed was a read, + * make it look like it read all-ones. + */ + if ((instr & 0x0c100000) == 0x04100000) { + int reg = (instr >> 16) & 15; + sprintf(buf, " reg%d = %08lx\n", reg, regs->uregs[reg]); + printascii(buf); + } +#endif + return IRQ_HANDLED; +} + +int __init pci_v3_setup(int nr, struct pci_sys_data *sys) +{ + int ret = 0; + + if (!ap_syscon_base) + return -EINVAL; + + if (nr == 0) { + sys->mem_offset = PHYS_PCI_MEM_BASE; + ret = pci_v3_setup_resources(sys); + } + + return ret; +} + +/* + * V3_LB_BASE? - local bus address + * V3_LB_MAP? - pci bus address + */ +void __init pci_v3_preinit(void) +{ + unsigned long flags; + unsigned int temp; + int ret; + + /* Remap the Integrator system controller */ + ap_syscon_base = ioremap(INTEGRATOR_SC_BASE, 0x100); + if (!ap_syscon_base) { + pr_err("unable to remap the AP syscon for PCIv3\n"); + return; + } + + pcibios_min_mem = 0x00100000; + + /* + * Hook in our fault handler for PCI errors + */ + hook_fault_code(4, v3_pci_fault, SIGBUS, 0, "external abort on linefetch"); + hook_fault_code(6, v3_pci_fault, SIGBUS, 0, "external abort on linefetch"); + hook_fault_code(8, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); + hook_fault_code(10, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); + + raw_spin_lock_irqsave(&v3_lock, flags); + + /* + * Unlock V3 registers, but only if they were previously locked. + */ + if (v3_readw(V3_SYSTEM) & V3_SYSTEM_M_LOCK) + v3_writew(V3_SYSTEM, 0xa05f); + + /* + * Setup window 0 - PCI non-prefetchable memory + * Local: 0x40000000 Bus: 0x00000000 Size: 256MB + */ + v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) | + V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE); + v3_writew(V3_LB_MAP0, v3_addr_to_lb_map(PCI_BUS_NONMEM_START) | + V3_LB_MAP_TYPE_MEM); + + /* + * Setup window 1 - PCI prefetchable memory + * Local: 0x50000000 Bus: 0x10000000 Size: 256MB + */ + v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) | + V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH | + V3_LB_BASE_ENABLE); + v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) | + V3_LB_MAP_TYPE_MEM_MULTIPLE); + + /* + * Setup window 2 - PCI IO + */ + v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(PHYS_PCI_IO_BASE) | + V3_LB_BASE_ENABLE); + v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0)); + + /* + * Disable PCI to host IO cycles + */ + temp = v3_readw(V3_PCI_CFG) & ~V3_PCI_CFG_M_I2O_EN; + temp |= V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS; + v3_writew(V3_PCI_CFG, temp); + + printk(KERN_DEBUG "FIFO_CFG: %04x FIFO_PRIO: %04x\n", + v3_readw(V3_FIFO_CFG), v3_readw(V3_FIFO_PRIORITY)); + + /* + * Set the V3 FIFO such that writes have higher priority than + * reads, and local bus write causes local bus read fifo flush. + * Same for PCI. + */ + v3_writew(V3_FIFO_PRIORITY, 0x0a0a); + + /* + * Re-lock the system register. + */ + temp = v3_readw(V3_SYSTEM) | V3_SYSTEM_M_LOCK; + v3_writew(V3_SYSTEM, temp); + + /* + * Clear any error conditions, and enable write errors. + */ + v3_writeb(V3_LB_ISTAT, 0); + v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10)); + v3_writeb(V3_LB_IMASK, 0x28); + __raw_writel(3, ap_syscon_base + INTEGRATOR_SC_PCIENABLE_OFFSET); + + /* + * Grab the PCI error interrupt. + */ + ret = request_irq(IRQ_AP_V3INT, v3_irq, 0, "V3", NULL); + if (ret) + printk(KERN_ERR "PCI: unable to grab PCI error " + "interrupt: %d\n", ret); + + raw_spin_unlock_irqrestore(&v3_lock, flags); +} + +void __init pci_v3_postinit(void) +{ + unsigned int pci_cmd; + + pci_cmd = PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; + + v3_writew(V3_PCI_CMD, pci_cmd); + + v3_writeb(V3_LB_ISTAT, ~0x40); + v3_writeb(V3_LB_IMASK, 0x68); + +#if 0 + ret = request_irq(IRQ_AP_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL); + if (ret) + printk(KERN_ERR "PCI: unable to grab local bus timeout " + "interrupt: %d\n", ret); +#endif + + register_isa_ports(PHYS_PCI_MEM_BASE, PHYS_PCI_IO_BASE, 0); +} |
