- patches.apparmor/remove_suid_new_case_in_2.6.22.diff: Merge fix.
[linux-flexiantxendom0-3.2.10.git] / arch / avr32 / mach-at32ap / at32ap7000.c
index 472703f..1d2bf34 100644 (file)
@@ -6,6 +6,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <asm/arch/portmux.h>
 #include <asm/arch/sm.h>
 
+#include <video/atmel_lcdc.h>
+
 #include "clock.h"
+#include "hmatrix.h"
 #include "pio.h"
 #include "sm.h"
 
@@ -416,7 +420,15 @@ struct platform_device at32_sm_device = {
        .resource       = sm_resource,
        .num_resources  = ARRAY_SIZE(sm_resource),
 };
-DEV_CLK(pclk, at32_sm, pbb, 0);
+static struct clk at32_sm_pclk = {
+       .name           = "pclk",
+       .dev            = &at32_sm_device.dev,
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .users          = 1,
+       .index          = 0,
+};
 
 static struct resource intc0_resource[] = {
        PBMEM(0xfff00400),
@@ -442,6 +454,7 @@ static struct clk hramc_clk = {
        .mode           = hsb_clk_mode,
        .get_rate       = hsb_clk_get_rate,
        .users          = 1,
+       .index          = 3,
 };
 
 static struct resource smc0_resource[] = {
@@ -467,6 +480,57 @@ static struct clk pico_clk = {
 };
 
 /* --------------------------------------------------------------------
+ * HMATRIX
+ * -------------------------------------------------------------------- */
+
+static struct clk hmatrix_clk = {
+       .name           = "hmatrix_clk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 2,
+       .users          = 1,
+};
+#define HMATRIX_BASE   ((void __iomem *)0xfff00800)
+
+#define hmatrix_readl(reg)                                     \
+       __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
+#define hmatrix_writel(reg,value)                              \
+       __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
+
+/*
+ * Set bits in the HMATRIX Special Function Register (SFR) used by the
+ * External Bus Interface (EBI). This can be used to enable special
+ * features like CompactFlash support, NAND Flash support, etc. on
+ * certain chipselects.
+ */
+static inline void set_ebi_sfr_bits(u32 mask)
+{
+       u32 sfr;
+
+       clk_enable(&hmatrix_clk);
+       sfr = hmatrix_readl(SFR4);
+       sfr |= mask;
+       hmatrix_writel(SFR4, sfr);
+       clk_disable(&hmatrix_clk);
+}
+
+/* --------------------------------------------------------------------
+ *  System Timer/Counter (TC)
+ * -------------------------------------------------------------------- */
+static struct resource at32_systc0_resource[] = {
+       PBMEM(0xfff00c00),
+       IRQ(22),
+};
+struct platform_device at32_systc0_device = {
+       .name           = "systc",
+       .id             = 0,
+       .resource       = at32_systc0_resource,
+       .num_resources  = ARRAY_SIZE(at32_systc0_resource),
+};
+DEV_CLK(pclk, at32_systc0, pbb, 3);
+
+/* --------------------------------------------------------------------
  *  PIO
  * -------------------------------------------------------------------- */
 
@@ -514,6 +578,8 @@ void __init at32_add_system_devices(void)
        platform_device_register(&smc0_device);
        platform_device_register(&pdc_device);
 
+       platform_device_register(&at32_systc0_device);
+
        platform_device_register(&pio0_device);
        platform_device_register(&pio1_device);
        platform_device_register(&pio2_device);
@@ -818,20 +884,26 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
 /* --------------------------------------------------------------------
  *  LCDC
  * -------------------------------------------------------------------- */
-static struct lcdc_platform_data lcdc0_data;
-static struct resource lcdc0_resource[] = {
+static struct atmel_lcdfb_info atmel_lcdfb0_data;
+static struct resource atmel_lcdfb0_resource[] = {
        {
                .start          = 0xff000000,
                .end            = 0xff000fff,
                .flags          = IORESOURCE_MEM,
        },
        IRQ(1),
+       {
+               /* Placeholder for pre-allocated fb memory */
+               .start          = 0x00000000,
+               .end            = 0x00000000,
+               .flags          = 0,
+       },
 };
-DEFINE_DEV_DATA(lcdc, 0);
-DEV_CLK(hclk, lcdc0, hsb, 7);
-static struct clk lcdc0_pixclk = {
-       .name           = "pixclk",
-       .dev            = &lcdc0_device.dev,
+DEFINE_DEV_DATA(atmel_lcdfb, 0);
+DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
+static struct clk atmel_lcdfb0_pixclk = {
+       .name           = "lcdc_clk",
+       .dev            = &atmel_lcdfb0_device.dev,
        .mode           = genclk_mode,
        .get_rate       = genclk_get_rate,
        .set_rate       = genclk_set_rate,
@@ -840,13 +912,34 @@ static struct clk lcdc0_pixclk = {
 };
 
 struct platform_device *__init
-at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
+                    unsigned long fbmem_start, unsigned long fbmem_len)
 {
        struct platform_device *pdev;
+       struct atmel_lcdfb_info *info;
+       struct fb_monspecs *monspecs;
+       struct fb_videomode *modedb;
+       unsigned int modedb_size;
+
+       /*
+        * Do a deep copy of the fb data, monspecs and modedb. Make
+        * sure all allocations are done before setting up the
+        * portmux.
+        */
+       monspecs = kmemdup(data->default_monspecs,
+                          sizeof(struct fb_monspecs), GFP_KERNEL);
+       if (!monspecs)
+               return NULL;
+
+       modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
+       modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
+       if (!modedb)
+               goto err_dup_modedb;
+       monspecs->modedb = modedb;
 
        switch (id) {
        case 0:
-               pdev = &lcdc0_device;
+               pdev = &atmel_lcdfb0_device;
                select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
                select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
                select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
@@ -879,19 +972,32 @@ at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
                select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
                select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
 
-               clk_set_parent(&lcdc0_pixclk, &pll0);
-               clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0));
+               clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
+               clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
                break;
 
        default:
-               return NULL;
+               goto err_invalid_id;
        }
 
-       memcpy(pdev->dev.platform_data, data,
-              sizeof(struct lcdc_platform_data));
+       if (fbmem_len) {
+               pdev->resource[2].start = fbmem_start;
+               pdev->resource[2].end = fbmem_start + fbmem_len - 1;
+               pdev->resource[2].flags = IORESOURCE_MEM;
+       }
+
+       info = pdev->dev.platform_data;
+       memcpy(info, data, sizeof(struct atmel_lcdfb_info));
+       info->default_monspecs = monspecs;
 
        platform_device_register(pdev);
        return pdev;
+
+err_invalid_id:
+       kfree(modedb);
+err_dup_modedb:
+       kfree(monspecs);
+       return NULL;
 }
 
 /* --------------------------------------------------------------------
@@ -950,6 +1056,7 @@ struct clk *at32_clock_list[] = {
        &pbb_clk,
        &at32_sm_pclk,
        &at32_intc0_pclk,
+       &hmatrix_clk,
        &ebi_clk,
        &hramc_clk,
        &smc0_pclk,
@@ -962,6 +1069,7 @@ struct clk *at32_clock_list[] = {
        &pio2_mck,
        &pio3_mck,
        &pio4_mck,
+       &at32_systc0_pclk,
        &atmel_usart0_usart,
        &atmel_usart1_usart,
        &atmel_usart2_usart,
@@ -972,8 +1080,8 @@ struct clk *at32_clock_list[] = {
        &macb1_pclk,
        &atmel_spi0_spi_clk,
        &atmel_spi1_spi_clk,
-       &lcdc0_hclk,
-       &lcdc0_pixclk,
+       &atmel_lcdfb0_hck1,
+       &atmel_lcdfb0_pixclk,
        &gclk0,
        &gclk1,
        &gclk2,
@@ -1012,7 +1120,7 @@ void __init at32_clock_init(void)
        genclk_init_parent(&gclk2);
        genclk_init_parent(&gclk3);
        genclk_init_parent(&gclk4);
-       genclk_init_parent(&lcdc0_pixclk);
+       genclk_init_parent(&atmel_lcdfb0_pixclk);
 
        /*
         * Turn on all clocks that have at least one user already, and
@@ -1024,6 +1132,9 @@ void __init at32_clock_init(void)
        for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
                struct clk *clk = at32_clock_list[i];
 
+               if (clk->users == 0)
+                       continue;
+
                if (clk->mode == &cpu_clk_mode)
                        cpu_mask |= 1 << clk->index;
                else if (clk->mode == &hsb_clk_mode)