X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=arch%2Farm%2Fmach-realview%2Fcore.c;h=ac504745fed1a0c3772e8e07ee559ea8fe0459c0;hb=39c0cb02db5b8fdfac76d506b7a008b70bc960e9;hp=61d70218f1e8adc60aee99d0e044700cb2fe6fd2;hpb=193c3cc12583344be01206078d9ad3fec5dbc397;p=safe%2Fjmp%2Flinux-2.6 diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 61d7021..ac50474 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -25,29 +25,59 @@ #include #include #include - +#include +#include +#include +#include +#include +#include + +#include #include -#include -#include +#include #include #include +#include #include #include #include #include #include -#include #include -#include #include +#include +#include + #include "core.h" #include "clock.h" #define REALVIEW_REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET) +/* used by entry-macro.S and platsmp.c */ +void __iomem *gic_cpu_base_addr; + +#ifdef CONFIG_ZONE_DMA +/* + * Adjust the zones if there are restrictions for DMA access. + */ +void __init realview_adjust_zones(int node, unsigned long *size, + unsigned long *hole) +{ + unsigned long dma_size = SZ_256M >> PAGE_SHIFT; + + if (!machine_is_realview_pbx() || node || (size[0] <= dma_size)) + return; + + size[ZONE_NORMAL] = size[0] - dma_size; + size[ZONE_DMA] = dma_size; + hole[ZONE_NORMAL] = hole[0]; + hole[ZONE_DMA] = 0; +} +#endif + /* * This is the RealView sched_clock implementation. This has * a resolution of 41.7ns, and a maximum value of about 179s. @@ -105,40 +135,81 @@ static struct flash_platform_data realview_flash_data = { .set_vpp = realview_flash_set_vpp, }; -static struct resource realview_flash_resource = { - .start = REALVIEW_FLASH_BASE, - .end = REALVIEW_FLASH_BASE + REALVIEW_FLASH_SIZE, - .flags = IORESOURCE_MEM, -}; - struct platform_device realview_flash_device = { .name = "armflash", .id = 0, .dev = { .platform_data = &realview_flash_data, }, - .num_resources = 1, - .resource = &realview_flash_resource, }; -static struct resource realview_smc91x_resources[] = { +int realview_flash_register(struct resource *res, u32 num) +{ + realview_flash_device.resource = res; + realview_flash_device.num_resources = num; + return platform_device_register(&realview_flash_device); +} + +static struct smsc911x_platform_config smsc911x_config = { + .flags = SMSC911X_USE_32BIT, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + +static struct platform_device realview_eth_device = { + .name = "smsc911x", + .id = 0, + .num_resources = 2, +}; + +int realview_eth_register(const char *name, struct resource *res) +{ + if (name) + realview_eth_device.name = name; + realview_eth_device.resource = res; + if (strcmp(realview_eth_device.name, "smsc911x") == 0) + realview_eth_device.dev.platform_data = &smsc911x_config; + + return platform_device_register(&realview_eth_device); +} + +struct platform_device realview_usb_device = { + .name = "isp1760", + .num_resources = 2, +}; + +int realview_usb_register(struct resource *res) +{ + realview_usb_device.resource = res; + return platform_device_register(&realview_usb_device); +} + +static struct pata_platform_info pata_platform_data = { + .ioport_shift = 1, +}; + +static struct resource pata_resources[] = { [0] = { - .start = REALVIEW_ETH_BASE, - .end = REALVIEW_ETH_BASE + SZ_64K - 1, + .start = REALVIEW_CF_BASE, + .end = REALVIEW_CF_BASE + 0xff, .flags = IORESOURCE_MEM, }, [1] = { - .start = IRQ_ETH, - .end = IRQ_ETH, - .flags = IORESOURCE_IRQ, + .start = REALVIEW_CF_BASE + 0x100, + .end = REALVIEW_CF_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, }, }; -struct platform_device realview_smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(realview_smc91x_resources), - .resource = realview_smc91x_resources, +struct platform_device realview_cf_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(pata_resources), + .resource = pata_resources, + .dev = { + .platform_data = &pata_platform_data, + }, }; static struct resource realview_i2c_resource = { @@ -149,13 +220,29 @@ static struct resource realview_i2c_resource = { struct platform_device realview_i2c_device = { .name = "versatile-i2c", - .id = -1, + .id = 0, .num_resources = 1, .resource = &realview_i2c_resource, }; +static struct i2c_board_info realview_i2c_board_info[] = { + { + I2C_BOARD_INFO("ds1338", 0xd0 >> 1), + }, +}; + +static int __init realview_i2c_init(void) +{ + return i2c_register_board_info(0, realview_i2c_board_info, + ARRAY_SIZE(realview_i2c_board_info)); +} +arch_initcall(realview_i2c_init); + #define REALVIEW_SYSMCI (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET) +/* + * This is only used if GPIOLIB support is disabled + */ static unsigned int realview_mmc_status(struct device *dev) { struct amba_device *adev = container_of(dev, struct amba_device, dev); @@ -169,20 +256,24 @@ static unsigned int realview_mmc_status(struct device *dev) return readl(REALVIEW_SYSMCI) & mask; } -struct mmc_platform_data realview_mmc0_plat_data = { +struct mmci_platform_data realview_mmc0_plat_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = realview_mmc_status, + .gpio_wp = 17, + .gpio_cd = 16, }; -struct mmc_platform_data realview_mmc1_plat_data = { +struct mmci_platform_data realview_mmc1_plat_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = realview_mmc_status, + .gpio_wp = 19, + .gpio_cd = 18, }; /* * Clock handling */ -static const struct icst307_params realview_oscvco_params = { +static const struct icst_params realview_oscvco_params = { .ref = 24000, .vco_max = 200000, .vd_min = 4 + 8, @@ -191,12 +282,17 @@ static const struct icst307_params realview_oscvco_params = { .rd_max = 127 + 2, }; -static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco) +static void realview_oscvco_set(struct clk *clk, struct icst_vco vco) { void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET; - void __iomem *sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET; + void __iomem *sys_osc; u32 val; + if (machine_is_realview_pb1176()) + sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC0_OFFSET; + else + sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET; + val = readl(sys_osc) & ~0x7ffff; val |= vco.v | (vco.r << 9) | (vco.s << 16); @@ -205,13 +301,57 @@ static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco) writel(0, sys_lock); } -struct clk realview_clcd_clk = { - .name = "CLCDCLK", +static struct clk oscvco_clk = { .params = &realview_oscvco_params, .setvco = realview_oscvco_set, }; /* + * These are fixed clocks. + */ +static struct clk ref24_clk = { + .rate = 24000000, +}; + +static struct clk_lookup lookups[] = { + { /* UART0 */ + .dev_id = "dev:uart0", + .clk = &ref24_clk, + }, { /* UART1 */ + .dev_id = "dev:uart1", + .clk = &ref24_clk, + }, { /* UART2 */ + .dev_id = "dev:uart2", + .clk = &ref24_clk, + }, { /* UART3 */ + .dev_id = "fpga:uart3", + .clk = &ref24_clk, + }, { /* KMI0 */ + .dev_id = "fpga:kmi0", + .clk = &ref24_clk, + }, { /* KMI1 */ + .dev_id = "fpga:kmi1", + .clk = &ref24_clk, + }, { /* MMC0 */ + .dev_id = "fpga:mmc0", + .clk = &ref24_clk, + }, { /* EB:CLCD */ + .dev_id = "dev:clcd", + .clk = &oscvco_clk, + }, { /* PB:CLCD */ + .dev_id = "issp:clcd", + .clk = &oscvco_clk, + } +}; + +static int __init clk_init(void) +{ + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + return 0; +} +arch_initcall(clk_init); + +/* * CLCD support. */ #define SYS_CLCD_NLCDIOON (1 << 2) @@ -243,7 +383,30 @@ static struct clcd_panel vga = { .width = -1, .height = -1, .tim2 = TIM2_BCD | TIM2_IPC, - .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), + .bpp = 16, +}; + +static struct clcd_panel xvga = { + .mode = { + .name = "XVGA", + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 15748, + .left_margin = 152, + .right_margin = 48, + .upper_margin = 23, + .lower_margin = 3, + .hsync_len = 104, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD | TIM2_IPC, + .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), .bpp = 16, }; @@ -266,7 +429,7 @@ static struct clcd_panel sanyo_3_8_in = { .width = -1, .height = -1, .tim2 = TIM2_BCD, - .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), .bpp = 16, }; @@ -289,7 +452,7 @@ static struct clcd_panel sanyo_2_5_in = { .width = -1, .height = -1, .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC, - .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), .bpp = 16, }; @@ -312,7 +475,7 @@ static struct clcd_panel epson_2_2_in = { .width = -1, .height = -1, .tim2 = TIM2_BCD | TIM2_IPC, - .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), + .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), .bpp = 16, }; @@ -325,9 +488,15 @@ static struct clcd_panel epson_2_2_in = { static struct clcd_panel *realview_clcd_panel(void) { void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET; - struct clcd_panel *panel = &vga; + struct clcd_panel *vga_panel; + struct clcd_panel *panel; u32 val; + if (machine_is_realview_eb()) + vga_panel = &vga; + else + vga_panel = &xvga; + val = readl(sys_clcd) & SYS_CLCD_ID_MASK; if (val == SYS_CLCD_ID_SANYO_3_8) panel = &sanyo_3_8_in; @@ -336,11 +505,11 @@ static struct clcd_panel *realview_clcd_panel(void) else if (val == SYS_CLCD_ID_EPSON_2_2) panel = &epson_2_2_in; else if (val == SYS_CLCD_ID_VGA) - panel = &vga; + panel = vga_panel; else { printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n", val); - panel = &vga; + panel = vga_panel; } return panel; @@ -375,16 +544,22 @@ static void realview_clcd_enable(struct clcd_fb *fb) writel(val, sys_clcd); } -static unsigned long framesize = SZ_1M; - static int realview_clcd_setup(struct clcd_fb *fb) { + unsigned long framesize; dma_addr_t dma; + if (machine_is_realview_eb()) + /* VGA, 16bpp */ + framesize = 640 * 480 * 2; + else + /* XVGA, 16bpp */ + framesize = 1024 * 768 * 2; + fb->panel = realview_clcd_panel(); fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, - &dma, GFP_KERNEL); + &dma, GFP_KERNEL | GFP_DMA); if (!fb->fb.screen_base) { printk(KERN_ERR "CLCD: unable to map framebuffer\n"); return -ENOMEM; @@ -428,21 +603,22 @@ void realview_leds_event(led_event_t ledevt) { unsigned long flags; u32 val; + u32 led = 1 << smp_processor_id(); local_irq_save(flags); val = readl(VA_LEDS_BASE); switch (ledevt) { case led_idle_start: - val = val & ~REALVIEW_SYS_LED0; + val = val & ~led; break; case led_idle_end: - val = val | REALVIEW_SYS_LED0; + val = val | led; break; case led_timer: - val = val ^ REALVIEW_SYS_LED1; + val = val ^ REALVIEW_SYS_LED7; break; case led_halted: @@ -461,10 +637,10 @@ void realview_leds_event(led_event_t ledevt) /* * Where is the timer (VA)? */ -#define TIMER0_VA_BASE __io_address(REALVIEW_TIMER0_1_BASE) -#define TIMER1_VA_BASE (__io_address(REALVIEW_TIMER0_1_BASE) + 0x20) -#define TIMER2_VA_BASE __io_address(REALVIEW_TIMER2_3_BASE) -#define TIMER3_VA_BASE (__io_address(REALVIEW_TIMER2_3_BASE) + 0x20) +void __iomem *timer0_va_base; +void __iomem *timer1_va_base; +void __iomem *timer2_va_base; +void __iomem *timer3_va_base; /* * How long is the timer interval? @@ -484,45 +660,64 @@ void realview_leds_event(led_event_t ledevt) #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) #endif -/* - * Returns number of ms since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() - */ -static unsigned long realview_gettimeoffset(void) +static void timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) { - unsigned long ticks1, ticks2, status; + unsigned long ctrl; - /* - * Get the current number of ticks. Note that there is a race - * condition between us reading the timer and checking for - * an interrupt. We get around this by ensuring that the - * counter has not reloaded between our two reads. - */ - ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; - do { - ticks1 = ticks2; - status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET) - + ((IRQ_TIMERINT0_1 >> 5) << 2)); - ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; - } while (ticks2 > ticks1); + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(TIMER_RELOAD, timer0_va_base + TIMER_LOAD); - /* - * Number of ticks since last interrupt. - */ - ticks1 = TIMER_RELOAD - ticks2; + ctrl = TIMER_CTRL_PERIODIC; + ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE; + break; + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl = TIMER_CTRL_ONESHOT; + ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE; + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + ctrl = 0; + } - /* - * Interrupt pending? If so, we've reloaded once already. - * - * FIXME: Need to check this is effectively timer 0 that expires - */ - if (status & IRQMASK_TIMERINT0_1) - ticks1 += TIMER_RELOAD; + writel(ctrl, timer0_va_base + TIMER_CTRL); +} - /* - * Convert the ticks to usecs - */ - return TICKS2USECS(ticks1); +static int timer_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + unsigned long ctrl = readl(timer0_va_base + TIMER_CTRL); + + writel(evt, timer0_va_base + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, timer0_va_base + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device timer0_clockevent = { + .name = "timer0", + .shift = 32, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = timer_set_mode, + .set_next_event = timer_set_next_event, + .rating = 300, + .cpumask = cpu_all_mask, +}; + +static void __init realview_clockevents_init(unsigned int timer_irq) +{ + timer0_clockevent.irq = timer_irq; + timer0_clockevent.mult = + div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift); + timer0_clockevent.max_delta_ns = + clockevent_delta2ns(0xffffffff, &timer0_clockevent); + timer0_clockevent.min_delta_ns = + clockevent_delta2ns(0xf, &timer0_clockevent); + + clockevents_register_device(&timer0_clockevent); } /* @@ -530,15 +725,12 @@ static unsigned long realview_gettimeoffset(void) */ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) { - // ...clear the interrupt - writel(1, TIMER0_VA_BASE + TIMER_INTCLR); + struct clock_event_device *evt = &timer0_clockevent; - timer_tick(); + /* clear the interrupt */ + writel(1, timer0_va_base + TIMER_INTCLR); -#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) - smp_send_timer(); - update_process_times(user_mode(get_irq_regs())); -#endif + evt->event_handler(evt); return IRQ_HANDLED; } @@ -549,10 +741,38 @@ static struct irqaction realview_timer_irq = { .handler = realview_timer_interrupt, }; +static cycle_t realview_get_cycles(struct clocksource *cs) +{ + return ~readl(timer3_va_base + TIMER_VALUE); +} + +static struct clocksource clocksource_realview = { + .name = "timer3", + .rating = 200, + .read = realview_get_cycles, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init realview_clocksource_init(void) +{ + /* setup timer 0 as free-running clocksource */ + writel(0, timer3_va_base + TIMER_CTRL); + writel(0xffffffff, timer3_va_base + TIMER_LOAD); + writel(0xffffffff, timer3_va_base + TIMER_VALUE); + writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, + timer3_va_base + TIMER_CTRL); + + clocksource_realview.mult = + clocksource_khz2mult(1000, clocksource_realview.shift); + clocksource_register(&clocksource_realview); +} + /* - * Set up timer interrupt, and return the current time in seconds. + * Set up the clock source and clock events devices */ -static void __init realview_timer_init(void) +void __init realview_timer_init(unsigned int timer_irq) { u32 val; @@ -571,23 +791,37 @@ static void __init realview_timer_init(void) /* * Initialise to a known state (all timers off) */ - writel(0, TIMER0_VA_BASE + TIMER_CTRL); - writel(0, TIMER1_VA_BASE + TIMER_CTRL); - writel(0, TIMER2_VA_BASE + TIMER_CTRL); - writel(0, TIMER3_VA_BASE + TIMER_CTRL); - - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); - writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | - TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); + writel(0, timer0_va_base + TIMER_CTRL); + writel(0, timer1_va_base + TIMER_CTRL); + writel(0, timer2_va_base + TIMER_CTRL); + writel(0, timer3_va_base + TIMER_CTRL); /* * Make irqs happen for the system timer */ - setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); + setup_irq(timer_irq, &realview_timer_irq); + + realview_clocksource_init(); + realview_clockevents_init(timer_irq); } -struct sys_timer realview_timer = { - .init = realview_timer_init, - .offset = realview_gettimeoffset, -}; +/* + * Setup the memory banks. + */ +void realview_fixup(struct machine_desc *mdesc, struct tag *tags, char **from, + struct meminfo *meminfo) +{ + /* + * Most RealView platforms have 512MB contiguous RAM at 0x70000000. + * Half of this is mirrored at 0. + */ +#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET + meminfo->bank[0].start = 0x70000000; + meminfo->bank[0].size = SZ_512M; + meminfo->nr_banks = 1; +#else + meminfo->bank[0].start = 0; + meminfo->bank[0].size = SZ_256M; + meminfo->nr_banks = 1; +#endif +}