* 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/config.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/sysdev.h>
#include <linux/interrupt.h>
-
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/smsc911x.h>
+#include <linux/ata_platform.h>
+#include <linux/amba/mmci.h>
+#include <linux/gfp.h>
+
+#include <asm/clkdev.h>
#include <asm/system.h>
-#include <asm/hardware.h>
-#include <asm/io.h>
+#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/leds.h>
#include <asm/mach-types.h>
-#include <asm/hardware/amba.h>
-#include <asm/hardware/amba_clcd.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst307.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
#include <asm/mach/map.h>
-#include <asm/mach/mmc.h>
#include <asm/hardware/gic.h>
+#include <mach/platform.h>
+#include <mach/irqs.h>
+
#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.
.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",
+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 = {
+ .start = REALVIEW_I2C_BASE,
+ .end = REALVIEW_I2C_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+struct platform_device realview_i2c_device = {
+ .name = "versatile-i2c",
.id = 0,
- .num_resources = ARRAY_SIZE(realview_smc91x_resources),
- .resource = realview_smc91x_resources,
+ .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);
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,
};
/*
static void realview_oscvco_set(struct clk *clk, struct icst307_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_OSC1_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);
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_MODE_MASK (3 << 0)
-#define SYS_CLCD_MODE_888 (0 << 0)
-#define SYS_CLCD_MODE_5551 (1 << 0)
-#define SYS_CLCD_MODE_565_RLSB (2 << 0)
-#define SYS_CLCD_MODE_565_BLSB (3 << 0)
#define SYS_CLCD_NLCDIOON (1 << 2)
#define SYS_CLCD_VDDPOSSWITCH (1 << 3)
#define SYS_CLCD_PWR3V5SWITCH (1 << 4)
.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,
};
.width = -1,
.height = -1,
.tim2 = TIM2_BCD,
- .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+ .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
.bpp = 16,
};
.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,
};
.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 *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;
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;
void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
u32 val;
- val = readl(sys_clcd);
- val &= ~SYS_CLCD_MODE_MASK;
-
- switch (fb->fb.var.green.length) {
- case 5:
- val |= SYS_CLCD_MODE_5551;
- break;
- case 6:
- val |= SYS_CLCD_MODE_565_RLSB;
- break;
- case 8:
- val |= SYS_CLCD_MODE_888;
- break;
- }
-
- /*
- * Set the MUX
- */
- writel(val, sys_clcd);
-
/*
- * And now enable the PSUs
+ * Enable the PSUs
*/
+ val = readl(sys_clcd);
val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
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;
{
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:
/*
* 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?
#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);
}
/*
* IRQ handler for the timer
*/
-static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
-
- // ...clear the interrupt
- writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
-
- timer_tick(regs);
+ struct clock_event_device *evt = &timer0_clockevent;
-#ifdef CONFIG_SMP
- smp_send_timer();
- update_process_times(user_mode(regs));
-#endif
+ /* clear the interrupt */
+ writel(1, timer0_va_base + TIMER_INTCLR);
- write_sequnlock(&xtime_lock);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct irqaction realview_timer_irq = {
.name = "RealView Timer Tick",
- .flags = SA_INTERRUPT | SA_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.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;
/*
* 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
+}