Merge branch 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-3.10.git] / arch / arm / mach-shmobile / setup-r8a7740.c
index 986dca6..78948a9 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
+#include <linux/dma-mapping.h>
+#include <mach/dma-register.h>
 #include <mach/r8a7740.h>
+#include <mach/pm-rmobile.h>
+#include <mach/common.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
+#include <asm/mach/map.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc r8a7740_io_desc[] __initdata = {
+        /*
+         * for CPGA/INTC/PFC
+         * 0xe6000000-0xefffffff -> 0xe6000000-0xefffffff
+         */
+       {
+               .virtual        = 0xe6000000,
+               .pfn            = __phys_to_pfn(0xe6000000),
+               .length         = 160 << 20,
+               .type           = MT_DEVICE_NONSHARED
+       },
+#ifdef CONFIG_CACHE_L2X0
+       /*
+        * for l2x0_init()
+        * 0xf0100000-0xf0101000 -> 0xf0002000-0xf0003000
+        */
+       {
+               .virtual        = 0xf0002000,
+               .pfn            = __phys_to_pfn(0xf0100000),
+               .length         = PAGE_SIZE,
+               .type           = MT_DEVICE_NONSHARED
+       },
+#endif
+};
+
+void __init r8a7740_map_io(void)
+{
+       iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc));
+
+       /*
+        * DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
+        * enough to allocate the frame buffer memory.
+        */
+       init_consistent_dma_size(12 << 20);
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -235,6 +281,272 @@ static struct platform_device *r8a7740_early_devices[] __initdata = {
        &cmt10_device,
 };
 
+/* DMA */
+static const struct sh_dmae_slave_config r8a7740_dmae_slaves[] = {
+       {
+               .slave_id       = SHDMA_SLAVE_SDHI0_TX,
+               .addr           = 0xe6850030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_RX,
+               .addr           = 0xe6850030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc2,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_TX,
+               .addr           = 0xe6860030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc9,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_RX,
+               .addr           = 0xe6860030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xca,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI2_TX,
+               .addr           = 0xe6870030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xcd,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI2_RX,
+               .addr           = 0xe6870030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xce,
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSIA_TX,
+               .addr           = 0xfe1f0024,
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xb1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSIA_RX,
+               .addr           = 0xfe1f0020,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xb2,
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSIB_TX,
+               .addr           = 0xfe1f0064,
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xb5,
+       },
+};
+
+#define DMA_CHANNEL(a, b, c)                   \
+{                                              \
+       .offset         = a,                    \
+       .dmars          = b,                    \
+       .dmars_bit      = c,                    \
+       .chclr_offset   = (0x220 - 0x20) + a    \
+}
+
+static const struct sh_dmae_channel r8a7740_dmae_channels[] = {
+       DMA_CHANNEL(0x00, 0, 0),
+       DMA_CHANNEL(0x10, 0, 8),
+       DMA_CHANNEL(0x20, 4, 0),
+       DMA_CHANNEL(0x30, 4, 8),
+       DMA_CHANNEL(0x50, 8, 0),
+       DMA_CHANNEL(0x60, 8, 8),
+};
+
+static struct sh_dmae_pdata dma_platform_data = {
+       .slave          = r8a7740_dmae_slaves,
+       .slave_num      = ARRAY_SIZE(r8a7740_dmae_slaves),
+       .channel        = r8a7740_dmae_channels,
+       .channel_num    = ARRAY_SIZE(r8a7740_dmae_channels),
+       .ts_low_shift   = TS_LOW_SHIFT,
+       .ts_low_mask    = TS_LOW_BIT << TS_LOW_SHIFT,
+       .ts_high_shift  = TS_HI_SHIFT,
+       .ts_high_mask   = TS_HI_BIT << TS_HI_SHIFT,
+       .ts_shift       = dma_ts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_ts_shift),
+       .dmaor_init     = DMAOR_DME,
+       .chclr_present  = 1,
+};
+
+/* Resource order important! */
+static struct resource r8a7740_dmae0_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xfe008020,
+               .end    = 0xfe00828f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMARSx */
+               .start  = 0xfe009000,
+               .end    = 0xfe00900b,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "error_irq",
+               .start  = evt2irq(0x20c0),
+               .end    = evt2irq(0x20c0),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-5 */
+               .start  = evt2irq(0x2000),
+               .end    = evt2irq(0x20a0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+/* Resource order important! */
+static struct resource r8a7740_dmae1_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xfe018020,
+               .end    = 0xfe01828f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMARSx */
+               .start  = 0xfe019000,
+               .end    = 0xfe01900b,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "error_irq",
+               .start  = evt2irq(0x21c0),
+               .end    = evt2irq(0x21c0),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-5 */
+               .start  = evt2irq(0x2100),
+               .end    = evt2irq(0x21a0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+/* Resource order important! */
+static struct resource r8a7740_dmae2_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xfe028020,
+               .end    = 0xfe02828f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMARSx */
+               .start  = 0xfe029000,
+               .end    = 0xfe02900b,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "error_irq",
+               .start  = evt2irq(0x22c0),
+               .end    = evt2irq(0x22c0),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-5 */
+               .start  = evt2irq(0x2200),
+               .end    = evt2irq(0x22a0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dma0_device = {
+       .name           = "sh-dma-engine",
+       .id             = 0,
+       .resource       = r8a7740_dmae0_resources,
+       .num_resources  = ARRAY_SIZE(r8a7740_dmae0_resources),
+       .dev            = {
+               .platform_data  = &dma_platform_data,
+       },
+};
+
+static struct platform_device dma1_device = {
+       .name           = "sh-dma-engine",
+       .id             = 1,
+       .resource       = r8a7740_dmae1_resources,
+       .num_resources  = ARRAY_SIZE(r8a7740_dmae1_resources),
+       .dev            = {
+               .platform_data  = &dma_platform_data,
+       },
+};
+
+static struct platform_device dma2_device = {
+       .name           = "sh-dma-engine",
+       .id             = 2,
+       .resource       = r8a7740_dmae2_resources,
+       .num_resources  = ARRAY_SIZE(r8a7740_dmae2_resources),
+       .dev            = {
+               .platform_data  = &dma_platform_data,
+       },
+};
+
+/* USB-DMAC */
+static const struct sh_dmae_channel r8a7740_usb_dma_channels[] = {
+       {
+               .offset = 0,
+       }, {
+               .offset = 0x20,
+       },
+};
+
+static const struct sh_dmae_slave_config r8a7740_usb_dma_slaves[] = {
+       {
+               .slave_id       = SHDMA_SLAVE_USBHS_TX,
+               .chcr           = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE),
+       }, {
+               .slave_id       = SHDMA_SLAVE_USBHS_RX,
+               .chcr           = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE),
+       },
+};
+
+static struct sh_dmae_pdata usb_dma_platform_data = {
+       .slave          = r8a7740_usb_dma_slaves,
+       .slave_num      = ARRAY_SIZE(r8a7740_usb_dma_slaves),
+       .channel        = r8a7740_usb_dma_channels,
+       .channel_num    = ARRAY_SIZE(r8a7740_usb_dma_channels),
+       .ts_low_shift   = USBTS_LOW_SHIFT,
+       .ts_low_mask    = USBTS_LOW_BIT << USBTS_LOW_SHIFT,
+       .ts_high_shift  = USBTS_HI_SHIFT,
+       .ts_high_mask   = USBTS_HI_BIT << USBTS_HI_SHIFT,
+       .ts_shift       = dma_usbts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_usbts_shift),
+       .dmaor_init     = DMAOR_DME,
+       .chcr_offset    = 0x14,
+       .chcr_ie_bit    = 1 << 5,
+       .dmaor_is_32bit = 1,
+       .needs_tend_set = 1,
+       .no_dmars       = 1,
+       .slave_only     = 1,
+};
+
+static struct resource r8a7740_usb_dma_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xe68a0020,
+               .end    = 0xe68a0064 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* VCR/SWR/DMICR */
+               .start  = 0xe68a0000,
+               .end    = 0xe68a0014 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* IRQ for channels */
+               .start  = evt2irq(0x0a00),
+               .end    = evt2irq(0x0a00),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usb_dma_device = {
+       .name           = "sh-dma-engine",
+       .id             = 3,
+       .resource       = r8a7740_usb_dma_resources,
+       .num_resources  = ARRAY_SIZE(r8a7740_usb_dma_resources),
+       .dev            = {
+               .platform_data  = &usb_dma_platform_data,
+       },
+};
+
 /* I2C */
 static struct resource i2c0_resources[] = {
        [0] = {
@@ -281,8 +593,30 @@ static struct platform_device i2c1_device = {
 static struct platform_device *r8a7740_late_devices[] __initdata = {
        &i2c0_device,
        &i2c1_device,
+       &dma0_device,
+       &dma1_device,
+       &dma2_device,
+       &usb_dma_device,
 };
 
+/*
+ * r8a7740 chip has lasting errata on MERAM buffer.
+ * this is work-around for it.
+ * see
+ *     "Media RAM (MERAM)" on r8a7740 documentation
+ */
+#define MEBUFCNTR      0xFE950098
+void r8a7740_meram_workaround(void)
+{
+       void __iomem *reg;
+
+       reg = ioremap_nocache(MEBUFCNTR, 4);
+       if (reg) {
+               iowrite32(0x01600164, reg);
+               iounmap(reg);
+       }
+}
+
 #define ICCR   0x0004
 #define ICSTART        0x0070
 
@@ -316,19 +650,19 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev)
        i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10);
        i2c_read(reg, ICSTART); /* dummy read */
 
-       mdelay(100);
+       udelay(10);
 
        i2c_write(reg, ICCR, 0x01);
-       i2c_read(reg, ICCR);
        i2c_write(reg, ICSTART, 0x00);
-       i2c_read(reg, ICSTART);
+
+       udelay(10);
 
        i2c_write(reg, ICCR, 0x10);
-       mdelay(100);
+       udelay(10);
        i2c_write(reg, ICCR, 0x00);
-       mdelay(100);
+       udelay(10);
        i2c_write(reg, ICCR, 0x10);
-       mdelay(100);
+       udelay(10);
 
        iounmap(reg);
 }
@@ -339,14 +673,93 @@ void __init r8a7740_add_standard_devices(void)
        r8a7740_i2c_workaround(&i2c0_device);
        r8a7740_i2c_workaround(&i2c1_device);
 
+       /* PM domain */
+       rmobile_init_pm_domain(&r8a7740_pd_a4s);
+       rmobile_init_pm_domain(&r8a7740_pd_a3sp);
+       rmobile_init_pm_domain(&r8a7740_pd_a4lc);
+
+       rmobile_pm_add_subdomain(&r8a7740_pd_a4s, &r8a7740_pd_a3sp);
+
+       /* add devices */
        platform_add_devices(r8a7740_early_devices,
                            ARRAY_SIZE(r8a7740_early_devices));
        platform_add_devices(r8a7740_late_devices,
                             ARRAY_SIZE(r8a7740_late_devices));
+
+       /* add devices to PM domain  */
+
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif0_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif1_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif2_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif3_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif4_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif5_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif6_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif7_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scifb_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &i2c1_device);
+}
+
+static void __init r8a7740_earlytimer_init(void)
+{
+       r8a7740_clock_init(0);
+       shmobile_earlytimer_init();
 }
 
 void __init r8a7740_add_early_devices(void)
 {
        early_platform_add_devices(r8a7740_early_devices,
                                   ARRAY_SIZE(r8a7740_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
+
+       /* override timer setup with soc-specific code */
+       shmobile_timer.init = r8a7740_earlytimer_init;
+}
+
+#ifdef CONFIG_USE_OF
+
+void __init r8a7740_add_early_devices_dt(void)
+{
+       shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */
+
+       early_platform_add_devices(r8a7740_early_devices,
+                                  ARRAY_SIZE(r8a7740_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
 }
+
+static const struct of_dev_auxdata r8a7740_auxdata_lookup[] __initconst = {
+       { }
+};
+
+void __init r8a7740_add_standard_devices_dt(void)
+{
+       /* clocks are setup late during boot in the case of DT */
+       r8a7740_clock_init(0);
+
+       platform_add_devices(r8a7740_early_devices,
+                           ARRAY_SIZE(r8a7740_early_devices));
+
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            r8a7740_auxdata_lookup, NULL);
+}
+
+static const char *r8a7740_boards_compat_dt[] __initdata = {
+       "renesas,r8a7740",
+       NULL,
+};
+
+DT_MACHINE_START(SH7372_DT, "Generic R8A7740 (Flattened Device Tree)")
+       .map_io         = r8a7740_map_io,
+       .init_early     = r8a7740_add_early_devices_dt,
+       .init_irq       = r8a7740_init_irq,
+       .handle_irq     = shmobile_handle_irq_intc,
+       .init_machine   = r8a7740_add_standard_devices_dt,
+       .timer          = &shmobile_timer,
+       .dt_compat      = r8a7740_boards_compat_dt,
+MACHINE_END
+
+#endif /* CONFIG_USE_OF */