aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-versatile/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-versatile/core.c')
-rw-r--r--arch/arm/mach-versatile/core.c816
1 files changed, 310 insertions, 506 deletions
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index e13be7c444c..be83ba25f81 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -22,35 +22,41 @@
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/cnt32_to_63.h>
+#include <linux/amba/pl022.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-vic.h>
+#include <linux/irqchip/versatile-fpga.h>
+#include <linux/gfp.h>
+#include <linux/clkdev.h>
+#include <linux/mtd/physmap.h>
+#include <linux/bitops.h>
+#include <linux/reboot.h>
-#include <asm/clkdev.h>
-#include <asm/system.h>
-#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/leds.h>
#include <asm/hardware/arm_timer.h>
-#include <asm/hardware/icst307.h>
-#include <asm/hardware/vic.h>
+#include <asm/hardware/icst.h>
#include <asm/mach-types.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 <mach/hardware.h>
+#include <mach/platform.h>
+#include <asm/hardware/timer-sp.h>
+
+#include <plat/clcd.h>
+#include <plat/sched_clock.h>
#include "core.h"
-#include "clock.h"
/*
* All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
@@ -58,79 +64,59 @@
*
* Setup a VA for the Versatile Vectored Interrupt Controller.
*/
-#define __io_address(n) __io(IO_ADDRESS(n))
#define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE)
#define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE)
-static void sic_mask_irq(unsigned int irq)
-{
- irq -= IRQ_SIC_START;
- writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
-}
-
-static void sic_unmask_irq(unsigned int irq)
-{
- irq -= IRQ_SIC_START;
- writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET);
-}
-
-static struct irq_chip sic_chip = {
- .name = "SIC",
- .ack = sic_mask_irq,
- .mask = sic_mask_irq,
- .unmask = sic_unmask_irq,
-};
-
-static void
-sic_handle_irq(unsigned int irq, struct irq_desc *desc)
-{
- unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS);
-
- if (status == 0) {
- do_bad_IRQ(irq, desc);
- return;
- }
-
- do {
- irq = ffs(status) - 1;
- status &= ~(1 << irq);
-
- irq += IRQ_SIC_START;
-
- generic_handle_irq(irq);
- } while (status);
-}
-
+/* These PIC IRQs are valid in each configuration */
+#define PIC_VALID_ALL BIT(SIC_INT_KMI0) | BIT(SIC_INT_KMI1) | \
+ BIT(SIC_INT_SCI3) | BIT(SIC_INT_UART3) | \
+ BIT(SIC_INT_CLCD) | BIT(SIC_INT_TOUCH) | \
+ BIT(SIC_INT_KEYPAD) | BIT(SIC_INT_DoC) | \
+ BIT(SIC_INT_USB) | BIT(SIC_INT_PCI0) | \
+ BIT(SIC_INT_PCI1) | BIT(SIC_INT_PCI2) | \
+ BIT(SIC_INT_PCI3)
#if 1
#define IRQ_MMCI0A IRQ_VICSOURCE22
#define IRQ_AACI IRQ_VICSOURCE24
#define IRQ_ETH IRQ_VICSOURCE25
#define PIC_MASK 0xFFD00000
+#define PIC_VALID PIC_VALID_ALL
#else
#define IRQ_MMCI0A IRQ_SIC_MMCI0A
#define IRQ_AACI IRQ_SIC_AACI
#define IRQ_ETH IRQ_SIC_ETH
#define PIC_MASK 0
+#define PIC_VALID PIC_VALID_ALL | BIT(SIC_INT_MMCI0A) | \
+ BIT(SIC_INT_MMCI1A) | BIT(SIC_INT_AACI) | \
+ BIT(SIC_INT_ETH)
#endif
+/* Lookup table for finding a DT node that represents the vic instance */
+static const struct of_device_id vic_of_match[] __initconst = {
+ { .compatible = "arm,versatile-vic", },
+ {}
+};
+
+static const struct of_device_id sic_of_match[] __initconst = {
+ { .compatible = "arm,versatile-sic", },
+ {}
+};
+
void __init versatile_init_irq(void)
{
- unsigned int i;
+ struct device_node *np;
- vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0);
+ np = of_find_matching_node_by_address(NULL, vic_of_match,
+ VERSATILE_VIC_BASE);
+ __vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np);
- set_irq_chained_handler(IRQ_VICSOURCE31, sic_handle_irq);
-
- /* Do second interrupt controller */
writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
- for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) {
- if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) {
- set_irq_chip(i, &sic_chip);
- set_irq_handler(i, handle_level_irq);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- }
- }
+ np = of_find_matching_node_by_address(NULL, sic_of_match,
+ VERSATILE_SIC_BASE);
+
+ fpga_irq_init(VA_SIC_BASE, "SIC", IRQ_SIC_START,
+ IRQ_VICSOURCE31, PIC_VALID, np);
/*
* Interrupts on secondary controller from 0 to 8 are routed to
@@ -142,7 +128,7 @@ void __init versatile_init_irq(void)
writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE);
}
-static struct map_desc versatile_io_desc[] __initdata = {
+static struct map_desc versatile_io_desc[] __initdata __maybe_unused = {
{
.virtual = IO_ADDRESS(VERSATILE_SYS_BASE),
.pfn = __phys_to_pfn(VERSATILE_SYS_BASE),
@@ -166,11 +152,6 @@ static struct map_desc versatile_io_desc[] __initdata = {
},
#ifdef CONFIG_MACH_VERSATILE_AB
{
- .virtual = IO_ADDRESS(VERSATILE_GPIO0_BASE),
- .pfn = __phys_to_pfn(VERSATILE_GPIO0_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
.virtual = IO_ADDRESS(VERSATILE_IB2_BASE),
.pfn = __phys_to_pfn(VERSATILE_IB2_BASE),
.length = SZ_64M,
@@ -202,24 +183,6 @@ static struct map_desc versatile_io_desc[] __initdata = {
.length = VERSATILE_PCI_CFG_BASE_SIZE,
.type = MT_DEVICE
},
-#if 0
- {
- .virtual = VERSATILE_PCI_VIRT_MEM_BASE0,
- .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE0),
- .length = SZ_16M,
- .type = MT_DEVICE
- }, {
- .virtual = VERSATILE_PCI_VIRT_MEM_BASE1,
- .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE1),
- .length = SZ_16M,
- .type = MT_DEVICE
- }, {
- .virtual = VERSATILE_PCI_VIRT_MEM_BASE2,
- .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE2),
- .length = SZ_16M,
- .type = MT_DEVICE
- },
-#endif
#endif
};
@@ -228,51 +191,10 @@ void __init versatile_map_io(void)
iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc));
}
-#define VERSATILE_REFCOUNTER (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET)
-
-/*
- * This is the Versatile sched_clock implementation. This has
- * a resolution of 41.7ns, and a maximum value of about 35583 days.
- *
- * The return value is guaranteed to be monotonic in that range as
- * long as there is always less than 89 seconds between successive
- * calls to this function.
- */
-unsigned long long sched_clock(void)
-{
- unsigned long long v = cnt32_to_63(readl(VERSATILE_REFCOUNTER));
-
- /* the <<1 gets rid of the cnt_32_to_63 top bit saving on a bic insn */
- v *= 125<<1;
- do_div(v, 3<<1);
-
- return v;
-}
-
#define VERSATILE_FLASHCTRL (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET)
-static int versatile_flash_init(void)
-{
- u32 val;
-
- val = __raw_readl(VERSATILE_FLASHCTRL);
- val &= ~VERSATILE_FLASHPROG_FLVPPEN;
- __raw_writel(val, VERSATILE_FLASHCTRL);
-
- return 0;
-}
-
-static void versatile_flash_exit(void)
-{
- u32 val;
-
- val = __raw_readl(VERSATILE_FLASHCTRL);
- val &= ~VERSATILE_FLASHPROG_FLVPPEN;
- __raw_writel(val, VERSATILE_FLASHCTRL);
-}
-
-static void versatile_flash_set_vpp(int on)
+static void versatile_flash_set_vpp(struct platform_device *pdev, int on)
{
u32 val;
@@ -284,11 +206,8 @@ static void versatile_flash_set_vpp(int on)
__raw_writel(val, VERSATILE_FLASHCTRL);
}
-static struct flash_platform_data versatile_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data versatile_flash_data = {
.width = 4,
- .init = versatile_flash_init,
- .exit = versatile_flash_exit,
.set_vpp = versatile_flash_set_vpp,
};
@@ -299,7 +218,7 @@ static struct resource versatile_flash_resource = {
};
static struct platform_device versatile_flash_device = {
- .name = "armflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &versatile_flash_data,
@@ -376,36 +295,73 @@ static struct mmci_platform_data mmc0_plat_data = {
.gpio_cd = -1,
};
+static struct resource char_lcd_resources[] = {
+ {
+ .start = VERSATILE_CHAR_LCD_BASE,
+ .end = (VERSATILE_CHAR_LCD_BASE + SZ_4K - 1),
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device char_lcd_device = {
+ .name = "arm-charlcd",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(char_lcd_resources),
+ .resource = char_lcd_resources,
+};
+
+static struct resource leds_resources[] = {
+ {
+ .start = VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET,
+ .end = VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET + 4,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device leds_device = {
+ .name = "versatile-leds",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(leds_resources),
+ .resource = leds_resources,
+};
+
/*
* Clock handling
*/
-static const struct icst307_params versatile_oscvco_params = {
- .ref = 24000,
- .vco_max = 200000,
+static const struct icst_params versatile_oscvco_params = {
+ .ref = 24000000,
+ .vco_max = ICST307_VCO_MAX,
+ .vco_min = ICST307_VCO_MIN,
.vd_min = 4 + 8,
.vd_max = 511 + 8,
.rd_min = 1 + 2,
.rd_max = 127 + 2,
+ .s2div = icst307_s2div,
+ .idx2s = icst307_idx2s,
};
-static void versatile_oscvco_set(struct clk *clk, struct icst307_vco vco)
+static void versatile_oscvco_set(struct clk *clk, struct icst_vco vco)
{
- void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
- void __iomem *sys_lock = sys + VERSATILE_SYS_LOCK_OFFSET;
+ void __iomem *sys_lock = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LOCK_OFFSET;
u32 val;
- val = readl(sys + clk->oscoff) & ~0x7ffff;
+ val = readl(clk->vcoreg) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
writel(0xa05f, sys_lock);
- writel(val, sys + clk->oscoff);
+ writel(val, clk->vcoreg);
writel(0, sys_lock);
}
+static const struct clk_ops osc4_clk_ops = {
+ .round = icst_clk_round,
+ .set = icst_clk_set,
+ .setvco = versatile_oscvco_set,
+};
+
static struct clk osc4_clk = {
+ .ops = &osc4_clk_ops,
.params = &versatile_oscvco_params,
- .oscoff = VERSATILE_SYS_OSCCLCD_OFFSET,
- .setvco = versatile_oscvco_set,
};
/*
@@ -415,8 +371,17 @@ static struct clk ref24_clk = {
.rate = 24000000,
};
+static struct clk sp804_clk = {
+ .rate = 1000000,
+};
+
+static struct clk dummy_apb_pclk;
+
static struct clk_lookup lookups[] = {
- { /* UART0 */
+ { /* AMBA bus clock */
+ .con_id = "apb_pclk",
+ .clk = &dummy_apb_pclk,
+ }, { /* UART0 */
.dev_id = "dev:f1",
.clk = &ref24_clk,
}, { /* UART1 */
@@ -440,10 +405,16 @@ static struct clk_lookup lookups[] = {
}, { /* MMC1 */
.dev_id = "fpga:0b",
.clk = &ref24_clk,
+ }, { /* SSP */
+ .dev_id = "dev:f4",
+ .clk = &ref24_clk,
}, { /* CLCD */
.dev_id = "dev:20",
.clk = &osc4_clk,
- }
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .clk = &sp804_clk,
+ },
};
/*
@@ -464,127 +435,7 @@ static struct clk_lookup lookups[] = {
#define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8)
#define SYS_CLCD_ID_VGA (0x1f << 8)
-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),
- .bpp = 16,
-};
-
-static struct clcd_panel sanyo_3_8_in = {
- .mode = {
- .name = "Sanyo QVGA",
- .refresh = 116,
- .xres = 320,
- .yres = 240,
- .pixclock = 100000,
- .left_margin = 6,
- .right_margin = 6,
- .upper_margin = 5,
- .lower_margin = 5,
- .hsync_len = 6,
- .vsync_len = 6,
- .sync = 0,
- .vmode = FB_VMODE_NONINTERLACED,
- },
- .width = -1,
- .height = -1,
- .tim2 = TIM2_BCD,
- .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
- .bpp = 16,
-};
-
-static struct clcd_panel sanyo_2_5_in = {
- .mode = {
- .name = "Sanyo QVGA Portrait",
- .refresh = 116,
- .xres = 240,
- .yres = 320,
- .pixclock = 100000,
- .left_margin = 20,
- .right_margin = 10,
- .upper_margin = 2,
- .lower_margin = 2,
- .hsync_len = 10,
- .vsync_len = 2,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED,
- },
- .width = -1,
- .height = -1,
- .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC,
- .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
- .bpp = 16,
-};
-
-static struct clcd_panel epson_2_2_in = {
- .mode = {
- .name = "Epson QCIF",
- .refresh = 390,
- .xres = 176,
- .yres = 220,
- .pixclock = 62500,
- .left_margin = 3,
- .right_margin = 2,
- .upper_margin = 1,
- .lower_margin = 0,
- .hsync_len = 3,
- .vsync_len = 2,
- .sync = 0,
- .vmode = FB_VMODE_NONINTERLACED,
- },
- .width = -1,
- .height = -1,
- .tim2 = TIM2_BCD | TIM2_IPC,
- .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
- .bpp = 16,
-};
-
-/*
- * Detect which LCD panel is connected, and return the appropriate
- * clcd_panel structure. Note: we do not have any information on
- * the required timings for the 8.4in panel, so we presently assume
- * VGA timings.
- */
-static struct clcd_panel *versatile_clcd_panel(void)
-{
- void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
- struct clcd_panel *panel = &vga;
- u32 val;
-
- 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_SANYO_2_5)
- panel = &sanyo_2_5_in;
- else if (val == SYS_CLCD_ID_EPSON_2_2)
- panel = &epson_2_2_in;
- else if (val == SYS_CLCD_ID_VGA)
- panel = &vga;
- else {
- printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
- val);
- panel = &vga;
- }
-
- return panel;
-}
+static bool is_sanyo_2_5_lcd;
/*
* Disable all display connectors on the interface module.
@@ -602,7 +453,7 @@ static void versatile_clcd_disable(struct clcd_fb *fb)
/*
* If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off
*/
- if (machine_is_versatile_ab() && fb->panel == &sanyo_2_5_in) {
+ if (machine_is_versatile_ab() && is_sanyo_2_5_lcd) {
void __iomem *versatile_ib2_ctrl = __io_address(VERSATILE_IB2_CTRL);
unsigned long ctrl;
@@ -618,18 +469,22 @@ static void versatile_clcd_disable(struct clcd_fb *fb)
*/
static void versatile_clcd_enable(struct clcd_fb *fb)
{
+ struct fb_var_screeninfo *var = &fb->fb.var;
void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
u32 val;
val = readl(sys_clcd);
val &= ~SYS_CLCD_MODE_MASK;
- switch (fb->fb.var.green.length) {
+ switch (var->green.length) {
case 5:
val |= SYS_CLCD_MODE_5551;
break;
case 6:
- val |= SYS_CLCD_MODE_565_RLSB;
+ if (var->red.offset == 0)
+ val |= SYS_CLCD_MODE_565_RLSB;
+ else
+ val |= SYS_CLCD_MODE_565_BLSB;
break;
case 8:
val |= SYS_CLCD_MODE_888;
@@ -651,7 +506,7 @@ static void versatile_clcd_enable(struct clcd_fb *fb)
/*
* If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on
*/
- if (machine_is_versatile_ab() && fb->panel == &sanyo_2_5_in) {
+ if (machine_is_versatile_ab() && is_sanyo_2_5_lcd) {
void __iomem *versatile_ib2_ctrl = __io_address(VERSATILE_IB2_CTRL);
unsigned long ctrl;
@@ -662,50 +517,62 @@ static void versatile_clcd_enable(struct clcd_fb *fb)
#endif
}
-static unsigned long framesize = SZ_1M;
-
+/*
+ * Detect which LCD panel is connected, and return the appropriate
+ * clcd_panel structure. Note: we do not have any information on
+ * the required timings for the 8.4in panel, so we presently assume
+ * VGA timings.
+ */
static int versatile_clcd_setup(struct clcd_fb *fb)
{
- dma_addr_t dma;
+ void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
+ const char *panel_name;
+ u32 val;
- fb->panel = versatile_clcd_panel();
+ is_sanyo_2_5_lcd = false;
- fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
- &dma, GFP_KERNEL);
- if (!fb->fb.screen_base) {
- printk(KERN_ERR "CLCD: unable to map framebuffer\n");
- return -ENOMEM;
+ val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
+ if (val == SYS_CLCD_ID_SANYO_3_8)
+ panel_name = "Sanyo TM38QV67A02A";
+ else if (val == SYS_CLCD_ID_SANYO_2_5) {
+ panel_name = "Sanyo QVGA Portrait";
+ is_sanyo_2_5_lcd = true;
+ } else if (val == SYS_CLCD_ID_EPSON_2_2)
+ panel_name = "Epson L2F50113T00";
+ else if (val == SYS_CLCD_ID_VGA)
+ panel_name = "VGA";
+ else {
+ printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
+ val);
+ panel_name = "VGA";
}
- fb->fb.fix.smem_start = dma;
- fb->fb.fix.smem_len = framesize;
+ fb->panel = versatile_clcd_get_panel(panel_name);
+ if (!fb->panel)
+ return -EINVAL;
- return 0;
+ return versatile_clcd_setup_dma(fb, SZ_1M);
}
-static int versatile_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
{
- return dma_mmap_writecombine(&fb->dev->dev, vma,
- fb->fb.screen_base,
- fb->fb.fix.smem_start,
- fb->fb.fix.smem_len);
-}
+ clcdfb_decode(fb, regs);
-static void versatile_clcd_remove(struct clcd_fb *fb)
-{
- dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
- fb->fb.screen_base, fb->fb.fix.smem_start);
+ /* Always clear BGR for RGB565: we do the routing externally */
+ if (fb->fb.var.green.length == 6)
+ regs->cntl &= ~CNTL_BGR;
}
static struct clcd_board clcd_plat_data = {
.name = "Versatile",
+ .caps = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
.check = clcdfb_check,
- .decode = clcdfb_decode,
+ .decode = versatile_clcd_decode,
.disable = versatile_clcd_disable,
.enable = versatile_clcd_enable,
.setup = versatile_clcd_setup,
- .mmap = versatile_clcd_mmap,
- .remove = versatile_clcd_remove,
+ .mmap = versatile_clcd_mmap_dma,
+ .remove = versatile_clcd_remove_dma,
};
static struct pl061_platform_data gpio0_plat_data = {
@@ -718,76 +585,78 @@ static struct pl061_platform_data gpio1_plat_data = {
.irq_base = IRQ_GPIO1_START,
};
-#define AACI_IRQ { IRQ_AACI, NO_IRQ }
-#define AACI_DMA { 0x80, 0x81 }
+static struct pl061_platform_data gpio2_plat_data = {
+ .gpio_base = 16,
+ .irq_base = IRQ_GPIO2_START,
+};
+
+static struct pl061_platform_data gpio3_plat_data = {
+ .gpio_base = 24,
+ .irq_base = IRQ_GPIO3_START,
+};
+
+static struct pl022_ssp_controller ssp0_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 0,
+ .num_chipselect = 1,
+};
+
+#define AACI_IRQ { IRQ_AACI }
#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
-#define MMCI0_DMA { 0x84, 0 }
-#define KMI0_IRQ { IRQ_SIC_KMI0, NO_IRQ }
-#define KMI0_DMA { 0, 0 }
-#define KMI1_IRQ { IRQ_SIC_KMI1, NO_IRQ }
-#define KMI1_DMA { 0, 0 }
+#define KMI0_IRQ { IRQ_SIC_KMI0 }
+#define KMI1_IRQ { IRQ_SIC_KMI1 }
/*
* These devices are connected directly to the multi-layer AHB switch
*/
-#define SMC_IRQ { NO_IRQ, NO_IRQ }
-#define SMC_DMA { 0, 0 }
-#define MPMC_IRQ { NO_IRQ, NO_IRQ }
-#define MPMC_DMA { 0, 0 }
-#define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ }
-#define CLCD_DMA { 0, 0 }
-#define DMAC_IRQ { IRQ_DMAINT, NO_IRQ }
-#define DMAC_DMA { 0, 0 }
+#define SMC_IRQ { }
+#define MPMC_IRQ { }
+#define CLCD_IRQ { IRQ_CLCDINT }
+#define DMAC_IRQ { IRQ_DMAINT }
/*
* These devices are connected via the core APB bridge
*/
-#define SCTL_IRQ { NO_IRQ, NO_IRQ }
-#define SCTL_DMA { 0, 0 }
-#define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ }
-#define WATCHDOG_DMA { 0, 0 }
-#define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ }
-#define GPIO0_DMA { 0, 0 }
-#define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ }
-#define GPIO1_DMA { 0, 0 }
-#define RTC_IRQ { IRQ_RTCINT, NO_IRQ }
-#define RTC_DMA { 0, 0 }
+#define SCTL_IRQ { }
+#define WATCHDOG_IRQ { IRQ_WDOGINT }
+#define GPIO0_IRQ { IRQ_GPIOINT0 }
+#define GPIO1_IRQ { IRQ_GPIOINT1 }
+#define GPIO2_IRQ { IRQ_GPIOINT2 }
+#define GPIO3_IRQ { IRQ_GPIOINT3 }
+#define RTC_IRQ { IRQ_RTCINT }
/*
* These devices are connected via the DMA APB bridge
*/
-#define SCI_IRQ { IRQ_SCIINT, NO_IRQ }
-#define SCI_DMA { 7, 6 }
-#define UART0_IRQ { IRQ_UARTINT0, NO_IRQ }
-#define UART0_DMA { 15, 14 }
-#define UART1_IRQ { IRQ_UARTINT1, NO_IRQ }
-#define UART1_DMA { 13, 12 }
-#define UART2_IRQ { IRQ_UARTINT2, NO_IRQ }
-#define UART2_DMA { 11, 10 }
-#define SSP_IRQ { IRQ_SSPINT, NO_IRQ }
-#define SSP_DMA { 9, 8 }
+#define SCI_IRQ { IRQ_SCIINT }
+#define UART0_IRQ { IRQ_UARTINT0 }
+#define UART1_IRQ { IRQ_UARTINT1 }
+#define UART2_IRQ { IRQ_UARTINT2 }
+#define SSP_IRQ { IRQ_SSPINT }
/* FPGA Primecells */
-AMBA_DEVICE(aaci, "fpga:04", AACI, NULL);
-AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data);
-AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL);
-AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL);
+APB_DEVICE(aaci, "fpga:04", AACI, NULL);
+APB_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data);
+APB_DEVICE(kmi0, "fpga:06", KMI0, NULL);
+APB_DEVICE(kmi1, "fpga:07", KMI1, NULL);
/* DevChip Primecells */
-AMBA_DEVICE(smc, "dev:00", SMC, NULL);
-AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL);
-AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data);
-AMBA_DEVICE(dmac, "dev:30", DMAC, NULL);
-AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL);
-AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4", GPIO0, &gpio0_plat_data);
-AMBA_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
-AMBA_DEVICE(rtc, "dev:e8", RTC, NULL);
-AMBA_DEVICE(sci0, "dev:f0", SCI, NULL);
-AMBA_DEVICE(uart0, "dev:f1", UART0, NULL);
-AMBA_DEVICE(uart1, "dev:f2", UART1, NULL);
-AMBA_DEVICE(uart2, "dev:f3", UART2, NULL);
-AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL);
+AHB_DEVICE(smc, "dev:00", SMC, NULL);
+AHB_DEVICE(mpmc, "dev:10", MPMC, NULL);
+AHB_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data);
+AHB_DEVICE(dmac, "dev:30", DMAC, NULL);
+APB_DEVICE(sctl, "dev:e0", SCTL, NULL);
+APB_DEVICE(wdog, "dev:e1", WATCHDOG, NULL);
+APB_DEVICE(gpio0, "dev:e4", GPIO0, &gpio0_plat_data);
+APB_DEVICE(gpio1, "dev:e5", GPIO1, &gpio1_plat_data);
+APB_DEVICE(gpio2, "dev:e6", GPIO2, &gpio2_plat_data);
+APB_DEVICE(gpio3, "dev:e7", GPIO3, &gpio3_plat_data);
+APB_DEVICE(rtc, "dev:e8", RTC, NULL);
+APB_DEVICE(sci0, "dev:f0", SCI, NULL);
+APB_DEVICE(uart0, "dev:f1", UART0, NULL);
+APB_DEVICE(uart1, "dev:f2", UART1, NULL);
+APB_DEVICE(uart2, "dev:f3", UART2, NULL);
+APB_DEVICE(ssp0, "dev:f4", SSP, &ssp0_plat_data);
static struct amba_device *amba_devs[] __initdata = {
&dmac_device,
@@ -801,6 +670,8 @@ static struct amba_device *amba_devs[] __initdata = {
&wdog_device,
&gpio0_device,
&gpio1_device,
+ &gpio2_device,
+ &gpio3_device,
&rtc_device,
&sci0_device,
&ssp0_device,
@@ -810,6 +681,53 @@ static struct amba_device *amba_devs[] __initdata = {
&kmi1_device,
};
+#ifdef CONFIG_OF
+/*
+ * Lookup table for attaching a specific name and platform_data pointer to
+ * devices as they get created by of_platform_populate(). Ideally this table
+ * would not exist, but the current clock implementation depends on some devices
+ * having a specific name.
+ */
+struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI0_BASE, "fpga:06", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI1_BASE, "fpga:07", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART3_BASE, "fpga:09", NULL),
+ /* FIXME: this is buggy, the platform data is needed for this MMC instance too */
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", NULL),
+
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART0_BASE, "dev:f1", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART1_BASE, "dev:f2", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART2_BASE, "dev:f3", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_SSP_BASE, "dev:f4", &ssp0_plat_data),
+
+#if 0
+ /*
+ * These entries are unnecessary because no clocks referencing
+ * them. I've left them in for now as place holders in case
+ * any of them need to be added back, but they should be
+ * removed before actually committing this patch. --gcl
+ */
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_AACI_BASE, "fpga:04", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI1_BASE, "fpga:0a", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_SMC_BASE, "dev:00", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_MPMC_BASE, "dev:10", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_DMAC_BASE, "dev:30", NULL),
+
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCTL_BASE, "dev:e0", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_WATCHDOG_BASE, "dev:e1", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO0_BASE, "dev:e4", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO1_BASE, "dev:e5", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO2_BASE, "dev:e6", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO3_BASE, "dev:e7", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_RTC_BASE, "dev:e8", NULL),
+ OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI_BASE, "dev:f0", NULL),
+#endif
+ {}
+};
+#endif
+
#ifdef CONFIG_LEDS
#define VA_LEDS_BASE (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
@@ -847,25 +765,57 @@ static void versatile_leds_event(led_event_t ledevt)
}
#endif /* CONFIG_LEDS */
+void versatile_restart(enum reboot_mode mode, const char *cmd)
+{
+ void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
+ u32 val;
+
+ val = __raw_readl(sys + VERSATILE_SYS_RESETCTL_OFFSET);
+ val |= 0x105;
+
+ __raw_writel(0xa05f, sys + VERSATILE_SYS_LOCK_OFFSET);
+ __raw_writel(val, sys + VERSATILE_SYS_RESETCTL_OFFSET);
+ __raw_writel(0, sys + VERSATILE_SYS_LOCK_OFFSET);
+}
+
+/* Early initializations */
+void __init versatile_init_early(void)
+{
+ u32 val;
+ void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
+
+ osc4_clk.vcoreg = sys + VERSATILE_SYS_OSCCLCD_OFFSET;
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+ versatile_sched_clock_init(sys + VERSATILE_SYS_24MHz_OFFSET, 24000000);
+
+ /*
+ * set clock frequency:
+ * VERSATILE_REFCLK is 32KHz
+ * VERSATILE_TIMCLK is 1MHz
+ */
+ val = readl(__io_address(VERSATILE_SCTL_BASE));
+ writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
+ __io_address(VERSATILE_SCTL_BASE));
+}
+
void __init versatile_init(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
-
platform_device_register(&versatile_flash_device);
platform_device_register(&versatile_i2c_device);
platform_device_register(&smc91x_device);
+ platform_device_register(&char_lcd_device);
+ platform_device_register(&leds_device);
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
}
-
-#ifdef CONFIG_LEDS
- leds_event = versatile_leds_event;
-#endif
}
/*
@@ -875,139 +825,12 @@ void __init versatile_init(void)
#define TIMER1_VA_BASE (__io_address(VERSATILE_TIMER0_1_BASE) + 0x20)
#define TIMER2_VA_BASE __io_address(VERSATILE_TIMER2_3_BASE)
#define TIMER3_VA_BASE (__io_address(VERSATILE_TIMER2_3_BASE) + 0x20)
-#define VA_IC_BASE __io_address(VERSATILE_VIC_BASE)
-
-/*
- * How long is the timer interval?
- */
-#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
-#if TIMER_INTERVAL >= 0x100000
-#define TIMER_RELOAD (TIMER_INTERVAL >> 8)
-#define TIMER_DIVISOR (TIMER_CTRL_DIV256)
-#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
-#elif TIMER_INTERVAL >= 0x10000
-#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
-#define TIMER_DIVISOR (TIMER_CTRL_DIV16)
-#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
-#else
-#define TIMER_RELOAD (TIMER_INTERVAL)
-#define TIMER_DIVISOR (TIMER_CTRL_DIV1)
-#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
-#endif
-
-static void timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- unsigned long ctrl;
-
- switch(mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
-
- 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;
- }
-
- writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
-}
-
-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,
-};
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = &timer0_clockevent;
-
- writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction versatile_timer_irq = {
- .name = "Versatile Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = versatile_timer_interrupt,
-};
-
-static cycle_t versatile_get_cycles(struct clocksource *cs)
-{
- return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
-}
-
-static struct clocksource clocksource_versatile = {
- .name = "timer3",
- .rating = 200,
- .read = versatile_get_cycles,
- .mask = CLOCKSOURCE_MASK(32),
- .shift = 20,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init versatile_clocksource_init(void)
-{
- /* setup timer3 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_versatile.mult =
- clocksource_khz2mult(1000, clocksource_versatile.shift);
- clocksource_register(&clocksource_versatile);
-
- return 0;
-}
/*
* Set up timer interrupt, and return the current time in seconds.
*/
-static void __init versatile_timer_init(void)
+void __init versatile_timer_init(void)
{
- u32 val;
-
- /*
- * set clock frequency:
- * VERSATILE_REFCLK is 32KHz
- * VERSATILE_TIMCLK is 1MHz
- */
- val = readl(__io_address(VERSATILE_SCTL_BASE));
- writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
- __io_address(VERSATILE_SCTL_BASE));
/*
* Initialise to a known state (all timers off)
@@ -1017,25 +840,6 @@ static void __init versatile_timer_init(void)
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, &versatile_timer_irq);
-
- versatile_clocksource_init();
-
- 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);
-
- timer0_clockevent.cpumask = cpumask_of(0);
- clockevents_register_device(&timer0_clockevent);
+ sp804_clocksource_init(TIMER3_VA_BASE, "timer3");
+ sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0");
}
-
-struct sys_timer versatile_timer = {
- .init = versatile_timer_init,
-};
-