Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6.git] / arch / mips / txx9 / generic / setup.c
index 7b5705d..95184a0 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/arch/mips/txx9/generic/setup.c
- *
  * Based on linux/arch/mips/txx9/rbtx4938/setup.c,
  *         and RBTX49xx patch from CELF patch archive.
  *
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/mtd/physmap.h>
+#include <linux/leds.h>
+#include <linux/sysdev.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 #include <asm/reboot.h>
+#include <asm/r4kcache.h>
+#include <asm/sections.h>
 #include <asm/txx9/generic.h>
 #include <asm/txx9/pci.h>
+#include <asm/txx9tmr.h>
+#include <asm/txx9/ndfmc.h>
+#include <asm/txx9/dmac.h>
 #ifdef CONFIG_CPU_TX49XX
 #include <asm/txx9/tx4938.h>
 #endif
@@ -52,6 +59,7 @@ txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size)
                txx9_ce_res[i].name = txx9_ce_res_name[i];
        }
 
+       txx9_pcode = pcode;
        sprintf(txx9_pcode_str, "TX%x", pcode);
        if (base) {
                txx9_reg_res.start = base & 0xfffffffffULL;
@@ -65,14 +73,19 @@ unsigned int txx9_master_clock;
 unsigned int txx9_cpu_clock;
 unsigned int txx9_gbus_clock;
 
+#ifdef CONFIG_CPU_TX39XX
+/* don't enable by default - see errata */
+int txx9_ccfg_toeon __initdata;
+#else
 int txx9_ccfg_toeon __initdata = 1;
+#endif
 
 /* Minimum CLK support */
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
        if (!strcmp(id, "spi-baseclk"))
-               return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 4);
+               return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 2);
        if (!strcmp(id, "imbus_clk"))
                return (struct clk *)((unsigned long)txx9_gbus_clock / 2);
        return ERR_PTR(-ENOENT);
@@ -117,39 +130,223 @@ int irq_to_gpio(unsigned irq)
 EXPORT_SYMBOL(irq_to_gpio);
 #endif
 
-extern struct txx9_board_vec jmr3927_vec;
-extern struct txx9_board_vec rbtx4927_vec;
-extern struct txx9_board_vec rbtx4937_vec;
-extern struct txx9_board_vec rbtx4938_vec;
+#define BOARD_VEC(board)       extern struct txx9_board_vec board;
+#include <asm/txx9/boards.h>
+#undef BOARD_VEC
 
 struct txx9_board_vec *txx9_board_vec __initdata;
 static char txx9_system_type[32];
 
-void __init prom_init_cmdline(void)
+static struct txx9_board_vec *board_vecs[] __initdata = {
+#define BOARD_VEC(board)       &board,
+#include <asm/txx9/boards.h>
+#undef BOARD_VEC
+};
+
+static struct txx9_board_vec *__init find_board_byname(const char *name)
+{
+       int i;
+
+       /* search board_vecs table */
+       for (i = 0; i < ARRAY_SIZE(board_vecs); i++) {
+               if (strstr(board_vecs[i]->system, name))
+                       return board_vecs[i];
+       }
+       return NULL;
+}
+
+static void __init prom_init_cmdline(void)
 {
-       int argc = (int)fw_arg0;
-       char **argv = (char **)fw_arg1;
+       int argc;
+       int *argv32;
        int i;                  /* Always ignore the "-c" at argv[0] */
-#ifdef CONFIG_64BIT
-       char *fixed_argv[32];
-       for (i = 0; i < argc; i++)
-               fixed_argv[i] = (char *)(long)(*((__s32 *)argv + i));
-       argv = fixed_argv;
-#endif
 
-       /* ignore all built-in args if any f/w args given */
-       if (argc > 1)
-               *arcs_cmdline = '\0';
+       if (fw_arg0 >= CKSEG0 || fw_arg1 < CKSEG0) {
+               /*
+                * argc is not a valid number, or argv32 is not a valid
+                * pointer
+                */
+               argc = 0;
+               argv32 = NULL;
+       } else {
+               argc = (int)fw_arg0;
+               argv32 = (int *)fw_arg1;
+       }
+
+       arcs_cmdline[0] = '\0';
 
        for (i = 1; i < argc; i++) {
+               char *str = (char *)(long)argv32[i];
                if (i != 1)
                        strcat(arcs_cmdline, " ");
-               strcat(arcs_cmdline, argv[i]);
+               if (strchr(str, ' ')) {
+                       strcat(arcs_cmdline, "\"");
+                       strcat(arcs_cmdline, str);
+                       strcat(arcs_cmdline, "\"");
+               } else
+                       strcat(arcs_cmdline, str);
        }
 }
 
-void __init prom_init(void)
+static int txx9_ic_disable __initdata;
+static int txx9_dc_disable __initdata;
+
+#if defined(CONFIG_CPU_TX49XX)
+/* flush all cache on very early stage (before 4k_cache_init) */
+static void __init early_flush_dcache(void)
+{
+       unsigned int conf = read_c0_config();
+       unsigned int dc_size = 1 << (12 + ((conf & CONF_DC) >> 6));
+       unsigned int linesz = 32;
+       unsigned long addr, end;
+
+       end = INDEX_BASE + dc_size / 4;
+       /* 4way, waybit=0 */
+       for (addr = INDEX_BASE; addr < end; addr += linesz) {
+               cache_op(Index_Writeback_Inv_D, addr | 0);
+               cache_op(Index_Writeback_Inv_D, addr | 1);
+               cache_op(Index_Writeback_Inv_D, addr | 2);
+               cache_op(Index_Writeback_Inv_D, addr | 3);
+       }
+}
+
+static void __init txx9_cache_fixup(void)
+{
+       unsigned int conf;
+
+       conf = read_c0_config();
+       /* flush and disable */
+       if (txx9_ic_disable) {
+               conf |= TX49_CONF_IC;
+               write_c0_config(conf);
+       }
+       if (txx9_dc_disable) {
+               early_flush_dcache();
+               conf |= TX49_CONF_DC;
+               write_c0_config(conf);
+       }
+
+       /* enable cache */
+       conf = read_c0_config();
+       if (!txx9_ic_disable)
+               conf &= ~TX49_CONF_IC;
+       if (!txx9_dc_disable)
+               conf &= ~TX49_CONF_DC;
+       write_c0_config(conf);
+
+       if (conf & TX49_CONF_IC)
+               pr_info("TX49XX I-Cache disabled.\n");
+       if (conf & TX49_CONF_DC)
+               pr_info("TX49XX D-Cache disabled.\n");
+}
+#elif defined(CONFIG_CPU_TX39XX)
+/* flush all cache on very early stage (before tx39_cache_init) */
+static void __init early_flush_dcache(void)
+{
+       unsigned int conf = read_c0_config();
+       unsigned int dc_size = 1 << (10 + ((conf & TX39_CONF_DCS_MASK) >>
+                                          TX39_CONF_DCS_SHIFT));
+       unsigned int linesz = 16;
+       unsigned long addr, end;
+
+       end = INDEX_BASE + dc_size / 2;
+       /* 2way, waybit=0 */
+       for (addr = INDEX_BASE; addr < end; addr += linesz) {
+               cache_op(Index_Writeback_Inv_D, addr | 0);
+               cache_op(Index_Writeback_Inv_D, addr | 1);
+       }
+}
+
+static void __init txx9_cache_fixup(void)
+{
+       unsigned int conf;
+
+       conf = read_c0_config();
+       /* flush and disable */
+       if (txx9_ic_disable) {
+               conf &= ~TX39_CONF_ICE;
+               write_c0_config(conf);
+       }
+       if (txx9_dc_disable) {
+               early_flush_dcache();
+               conf &= ~TX39_CONF_DCE;
+               write_c0_config(conf);
+       }
+
+       /* enable cache */
+       conf = read_c0_config();
+       if (!txx9_ic_disable)
+               conf |= TX39_CONF_ICE;
+       if (!txx9_dc_disable)
+               conf |= TX39_CONF_DCE;
+       write_c0_config(conf);
+
+       if (!(conf & TX39_CONF_ICE))
+               pr_info("TX39XX I-Cache disabled.\n");
+       if (!(conf & TX39_CONF_DCE))
+               pr_info("TX39XX D-Cache disabled.\n");
+}
+#else
+static inline void txx9_cache_fixup(void)
+{
+}
+#endif
+
+static void __init preprocess_cmdline(void)
+{
+       static char cmdline[COMMAND_LINE_SIZE] __initdata;
+       char *s;
+
+       strcpy(cmdline, arcs_cmdline);
+       s = cmdline;
+       arcs_cmdline[0] = '\0';
+       while (s && *s) {
+               char *str = strsep(&s, " ");
+               if (strncmp(str, "board=", 6) == 0) {
+                       txx9_board_vec = find_board_byname(str + 6);
+                       continue;
+               } else if (strncmp(str, "masterclk=", 10) == 0) {
+                       unsigned long val;
+                       if (strict_strtoul(str + 10, 10, &val) == 0)
+                               txx9_master_clock = val;
+                       continue;
+               } else if (strcmp(str, "icdisable") == 0) {
+                       txx9_ic_disable = 1;
+                       continue;
+               } else if (strcmp(str, "dcdisable") == 0) {
+                       txx9_dc_disable = 1;
+                       continue;
+               } else if (strcmp(str, "toeoff") == 0) {
+                       txx9_ccfg_toeon = 0;
+                       continue;
+               } else if (strcmp(str, "toeon") == 0) {
+                       txx9_ccfg_toeon = 1;
+                       continue;
+               }
+               if (arcs_cmdline[0])
+                       strcat(arcs_cmdline, " ");
+               strcat(arcs_cmdline, str);
+       }
+
+       txx9_cache_fixup();
+}
+
+static void __init select_board(void)
 {
+       const char *envstr;
+
+       /* first, determine by "board=" argument in preprocess_cmdline() */
+       if (txx9_board_vec)
+               return;
+       /* next, determine by "board" envvar */
+       envstr = prom_getenv("board");
+       if (envstr) {
+               txx9_board_vec = find_board_byname(envstr);
+               if (txx9_board_vec)
+                       return;
+       }
+
+       /* select "default" board */
 #ifdef CONFIG_CPU_TX39XX
        txx9_board_vec = &jmr3927_vec;
 #endif
@@ -168,8 +365,20 @@ void __init prom_init(void)
                txx9_board_vec = &rbtx4938_vec;
                break;
 #endif
+#ifdef CONFIG_TOSHIBA_RBTX4939
+       case 0x4939:
+               txx9_board_vec = &rbtx4939_vec;
+               break;
+#endif
        }
 #endif
+}
+
+void __init prom_init(void)
+{
+       prom_init_cmdline();
+       preprocess_cmdline();
+       select_board();
 
        strcpy(txx9_system_type, txx9_board_vec->system);
 
@@ -178,6 +387,11 @@ void __init prom_init(void)
 
 void __init prom_free_prom_memory(void)
 {
+       unsigned long saddr = PAGE_SIZE;
+       unsigned long eaddr = __pa_symbol(&_text);
+
+       if (saddr < eaddr)
+               free_init_pages("prom memory", saddr, eaddr);
 }
 
 const char *get_system_type(void)
@@ -185,9 +399,21 @@ const char *get_system_type(void)
        return txx9_system_type;
 }
 
-char * __init prom_getcmdline(void)
+const char *__init prom_getenv(const char *name)
 {
-       return &(arcs_cmdline[0]);
+       const s32 *str;
+
+       if (fw_arg2 < CKSEG0)
+               return NULL;
+
+       str = (const s32 *)fw_arg2;
+       /* YAMON style ("name", "value" pairs) */
+       while (str[0] && str[1]) {
+               if (!strcmp((const char *)(unsigned long)str[0], name))
+                       return (const char *)(unsigned long)str[1];
+               str += 2;
+       }
+       return NULL;
 }
 
 static void __noreturn txx9_machine_halt(void)
@@ -220,6 +446,101 @@ void __init txx9_wdt_init(unsigned long base)
        platform_device_register_simple("txx9wdt", -1, &res, 1);
 }
 
+void txx9_wdt_now(unsigned long base)
+{
+       struct txx9_tmr_reg __iomem *tmrptr =
+               ioremap(base, sizeof(struct txx9_tmr_reg));
+       /* disable watch dog timer */
+       __raw_writel(TXx9_TMWTMR_WDIS | TXx9_TMWTMR_TWC, &tmrptr->wtmr);
+       __raw_writel(0, &tmrptr->tcr);
+       /* kick watchdog */
+       __raw_writel(TXx9_TMWTMR_TWIE, &tmrptr->wtmr);
+       __raw_writel(1, &tmrptr->cpra); /* immediate */
+       __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
+                    &tmrptr->tcr);
+}
+
+/* SPI support */
+void __init txx9_spi_init(int busid, unsigned long base, int irq)
+{
+       struct resource res[] = {
+               {
+                       .start  = base,
+                       .end    = base + 0x20 - 1,
+                       .flags  = IORESOURCE_MEM,
+               }, {
+                       .start  = irq,
+                       .flags  = IORESOURCE_IRQ,
+               },
+       };
+       platform_device_register_simple("spi_txx9", busid,
+                                       res, ARRAY_SIZE(res));
+}
+
+void __init txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr)
+{
+       struct platform_device *pdev =
+               platform_device_alloc("tc35815-mac", id);
+       if (!pdev ||
+           platform_device_add_data(pdev, ethaddr, 6) ||
+           platform_device_add(pdev))
+               platform_device_put(pdev);
+}
+
+void __init txx9_sio_init(unsigned long baseaddr, int irq,
+                         unsigned int line, unsigned int sclk, int nocts)
+{
+#ifdef CONFIG_SERIAL_TXX9
+       struct uart_port req;
+
+       memset(&req, 0, sizeof(req));
+       req.line = line;
+       req.iotype = UPIO_MEM;
+       req.membase = ioremap(baseaddr, 0x24);
+       req.mapbase = baseaddr;
+       req.irq = irq;
+       if (!nocts)
+               req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
+       if (sclk) {
+               req.flags |= UPF_MAGIC_MULTIPLIER /*USE_SCLK*/;
+               req.uartclk = sclk;
+       } else
+               req.uartclk = TXX9_IMCLK;
+       early_serial_txx9_setup(&req);
+#endif /* CONFIG_SERIAL_TXX9 */
+}
+
+#ifdef CONFIG_EARLY_PRINTK
+static void __init null_prom_putchar(char c)
+{
+}
+void (*txx9_prom_putchar)(char c) __initdata = null_prom_putchar;
+
+void __init prom_putchar(char c)
+{
+       txx9_prom_putchar(c);
+}
+
+static void __iomem *early_txx9_sio_port;
+
+static void __init early_txx9_sio_putchar(char c)
+{
+#define TXX9_SICISR    0x0c
+#define TXX9_SITFIFO   0x1c
+#define TXX9_SICISR_TXALS      0x00000002
+       while (!(__raw_readl(early_txx9_sio_port + TXX9_SICISR) &
+                TXX9_SICISR_TXALS))
+               ;
+       __raw_writel(c, early_txx9_sio_port + TXX9_SITFIFO);
+}
+
+void __init txx9_sio_putchar_init(unsigned long baseaddr)
+{
+       early_txx9_sio_port = ioremap(baseaddr, 0x24);
+       txx9_prom_putchar = early_txx9_sio_putchar;
+}
+#endif /* CONFIG_EARLY_PRINTK */
+
 /* wrappers */
 void __init plat_mem_setup(void)
 {
@@ -246,6 +567,9 @@ void __init arch_init_irq(void)
 
 void __init plat_time_init(void)
 {
+#ifdef CONFIG_CPU_TX49XX
+       mips_hpt_frequency = txx9_cpu_clock / 2;
+#endif
        txx9_board_vec->time_init();
 }
 
@@ -286,3 +610,372 @@ static unsigned long __swizzle_addr_none(unsigned long port)
 unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none;
 EXPORT_SYMBOL(__swizzle_addr_b);
 #endif
+
+#ifdef NEEDS_TXX9_IOSWABW
+static u16 ioswabw_default(volatile u16 *a, u16 x)
+{
+       return le16_to_cpu(x);
+}
+static u16 __mem_ioswabw_default(volatile u16 *a, u16 x)
+{
+       return x;
+}
+u16 (*ioswabw)(volatile u16 *a, u16 x) = ioswabw_default;
+EXPORT_SYMBOL(ioswabw);
+u16 (*__mem_ioswabw)(volatile u16 *a, u16 x) = __mem_ioswabw_default;
+EXPORT_SYMBOL(__mem_ioswabw);
+#endif
+
+void __init txx9_physmap_flash_init(int no, unsigned long addr,
+                                   unsigned long size,
+                                   const struct physmap_flash_data *pdata)
+{
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+       struct resource res = {
+               .start = addr,
+               .end = addr + size - 1,
+               .flags = IORESOURCE_MEM,
+       };
+       struct platform_device *pdev;
+#ifdef CONFIG_MTD_PARTITIONS
+       static struct mtd_partition parts[2];
+       struct physmap_flash_data pdata_part;
+
+       /* If this area contained boot area, make separate partition */
+       if (pdata->nr_parts == 0 && !pdata->parts &&
+           addr < 0x1fc00000 && addr + size > 0x1fc00000 &&
+           !parts[0].name) {
+               parts[0].name = "boot";
+               parts[0].offset = 0x1fc00000 - addr;
+               parts[0].size = addr + size - 0x1fc00000;
+               parts[1].name = "user";
+               parts[1].offset = 0;
+               parts[1].size = 0x1fc00000 - addr;
+               pdata_part = *pdata;
+               pdata_part.nr_parts = ARRAY_SIZE(parts);
+               pdata_part.parts = parts;
+               pdata = &pdata_part;
+       }
+#endif
+       pdev = platform_device_alloc("physmap-flash", no);
+       if (!pdev ||
+           platform_device_add_resources(pdev, &res, 1) ||
+           platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
+           platform_device_add(pdev))
+               platform_device_put(pdev);
+#endif
+}
+
+void __init txx9_ndfmc_init(unsigned long baseaddr,
+                           const struct txx9ndfmc_platform_data *pdata)
+{
+#if defined(CONFIG_MTD_NAND_TXX9NDFMC) || \
+       defined(CONFIG_MTD_NAND_TXX9NDFMC_MODULE)
+       struct resource res = {
+               .start = baseaddr,
+               .end = baseaddr + 0x1000 - 1,
+               .flags = IORESOURCE_MEM,
+       };
+       struct platform_device *pdev = platform_device_alloc("txx9ndfmc", -1);
+
+       if (!pdev ||
+           platform_device_add_resources(pdev, &res, 1) ||
+           platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
+           platform_device_add(pdev))
+               platform_device_put(pdev);
+#endif
+}
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static DEFINE_SPINLOCK(txx9_iocled_lock);
+
+#define TXX9_IOCLED_MAXLEDS 8
+
+struct txx9_iocled_data {
+       struct gpio_chip chip;
+       u8 cur_val;
+       void __iomem *mmioaddr;
+       struct gpio_led_platform_data pdata;
+       struct gpio_led leds[TXX9_IOCLED_MAXLEDS];
+       char names[TXX9_IOCLED_MAXLEDS][32];
+};
+
+static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct txx9_iocled_data *data =
+               container_of(chip, struct txx9_iocled_data, chip);
+       return data->cur_val & (1 << offset);
+}
+
+static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset,
+                           int value)
+{
+       struct txx9_iocled_data *data =
+               container_of(chip, struct txx9_iocled_data, chip);
+       unsigned long flags;
+       spin_lock_irqsave(&txx9_iocled_lock, flags);
+       if (value)
+               data->cur_val |= 1 << offset;
+       else
+               data->cur_val &= ~(1 << offset);
+       writeb(data->cur_val, data->mmioaddr);
+       mmiowb();
+       spin_unlock_irqrestore(&txx9_iocled_lock, flags);
+}
+
+static int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset)
+{
+       return 0;
+}
+
+static int txx9_iocled_dir_out(struct gpio_chip *chip, unsigned int offset,
+                              int value)
+{
+       txx9_iocled_set(chip, offset, value);
+       return 0;
+}
+
+void __init txx9_iocled_init(unsigned long baseaddr,
+                            int basenum, unsigned int num, int lowactive,
+                            const char *color, char **deftriggers)
+{
+       struct txx9_iocled_data *iocled;
+       struct platform_device *pdev;
+       int i;
+       static char *default_triggers[] __initdata = {
+               "heartbeat",
+               "ide-disk",
+               "nand-disk",
+               NULL,
+       };
+
+       if (!deftriggers)
+               deftriggers = default_triggers;
+       iocled = kzalloc(sizeof(*iocled), GFP_KERNEL);
+       if (!iocled)
+               return;
+       iocled->mmioaddr = ioremap(baseaddr, 1);
+       if (!iocled->mmioaddr)
+               goto out_free;
+       iocled->chip.get = txx9_iocled_get;
+       iocled->chip.set = txx9_iocled_set;
+       iocled->chip.direction_input = txx9_iocled_dir_in;
+       iocled->chip.direction_output = txx9_iocled_dir_out;
+       iocled->chip.label = "iocled";
+       iocled->chip.base = basenum;
+       iocled->chip.ngpio = num;
+       if (gpiochip_add(&iocled->chip))
+               goto out_unmap;
+       if (basenum < 0)
+               basenum = iocled->chip.base;
+
+       pdev = platform_device_alloc("leds-gpio", basenum);
+       if (!pdev)
+               goto out_gpio;
+       iocled->pdata.num_leds = num;
+       iocled->pdata.leds = iocled->leds;
+       for (i = 0; i < num; i++) {
+               struct gpio_led *led = &iocled->leds[i];
+               snprintf(iocled->names[i], sizeof(iocled->names[i]),
+                        "iocled:%s:%u", color, i);
+               led->name = iocled->names[i];
+               led->gpio = basenum + i;
+               led->active_low = lowactive;
+               if (deftriggers && *deftriggers)
+                       led->default_trigger = *deftriggers++;
+       }
+       pdev->dev.platform_data = &iocled->pdata;
+       if (platform_device_add(pdev))
+               goto out_pdev;
+       return;
+out_pdev:
+       platform_device_put(pdev);
+out_gpio:
+       if (gpiochip_remove(&iocled->chip))
+               return;
+out_unmap:
+       iounmap(iocled->mmioaddr);
+out_free:
+       kfree(iocled);
+}
+#else /* CONFIG_LEDS_GPIO */
+void __init txx9_iocled_init(unsigned long baseaddr,
+                            int basenum, unsigned int num, int lowactive,
+                            const char *color, char **deftriggers)
+{
+}
+#endif /* CONFIG_LEDS_GPIO */
+
+void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq,
+                          const struct txx9dmac_platform_data *pdata)
+{
+#if defined(CONFIG_TXX9_DMAC) || defined(CONFIG_TXX9_DMAC_MODULE)
+       struct resource res[] = {
+               {
+                       .start = baseaddr,
+                       .end = baseaddr + 0x800 - 1,
+                       .flags = IORESOURCE_MEM,
+#ifndef CONFIG_MACH_TX49XX
+               }, {
+                       .start = irq,
+                       .flags = IORESOURCE_IRQ,
+#endif
+               }
+       };
+#ifdef CONFIG_MACH_TX49XX
+       struct resource chan_res[] = {
+               {
+                       .flags = IORESOURCE_IRQ,
+               }
+       };
+#endif
+       struct platform_device *pdev = platform_device_alloc("txx9dmac", id);
+       struct txx9dmac_chan_platform_data cpdata;
+       int i;
+
+       if (!pdev ||
+           platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
+           platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
+           platform_device_add(pdev)) {
+               platform_device_put(pdev);
+               return;
+       }
+       memset(&cpdata, 0, sizeof(cpdata));
+       cpdata.dmac_dev = pdev;
+       for (i = 0; i < TXX9_DMA_MAX_NR_CHANNELS; i++) {
+#ifdef CONFIG_MACH_TX49XX
+               chan_res[0].start = irq + i;
+#endif
+               pdev = platform_device_alloc("txx9dmac-chan",
+                                            id * TXX9_DMA_MAX_NR_CHANNELS + i);
+               if (!pdev ||
+#ifdef CONFIG_MACH_TX49XX
+                   platform_device_add_resources(pdev, chan_res,
+                                                 ARRAY_SIZE(chan_res)) ||
+#endif
+                   platform_device_add_data(pdev, &cpdata, sizeof(cpdata)) ||
+                   platform_device_add(pdev))
+                       platform_device_put(pdev);
+       }
+#endif
+}
+
+void __init txx9_aclc_init(unsigned long baseaddr, int irq,
+                          unsigned int dmac_id,
+                          unsigned int dma_chan_out,
+                          unsigned int dma_chan_in)
+{
+#if defined(CONFIG_SND_SOC_TXX9ACLC) || \
+       defined(CONFIG_SND_SOC_TXX9ACLC_MODULE)
+       unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS;
+       struct resource res[] = {
+               {
+                       .start = baseaddr,
+                       .end = baseaddr + 0x100 - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = irq,
+                       .flags = IORESOURCE_IRQ,
+               }, {
+                       .name = "txx9dmac-chan",
+                       .start = dma_base + dma_chan_out,
+                       .flags = IORESOURCE_DMA,
+               }, {
+                       .name = "txx9dmac-chan",
+                       .start = dma_base + dma_chan_in,
+                       .flags = IORESOURCE_DMA,
+               }
+       };
+       struct platform_device *pdev =
+               platform_device_alloc("txx9aclc-ac97", -1);
+
+       if (!pdev ||
+           platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
+           platform_device_add(pdev))
+               platform_device_put(pdev);
+#endif
+}
+
+static struct sysdev_class txx9_sramc_sysdev_class;
+
+struct txx9_sramc_sysdev {
+       struct sys_device dev;
+       struct bin_attribute bindata_attr;
+       void __iomem *base;
+};
+
+static ssize_t txx9_sram_read(struct kobject *kobj,
+                             struct bin_attribute *bin_attr,
+                             char *buf, loff_t pos, size_t size)
+{
+       struct txx9_sramc_sysdev *dev = bin_attr->private;
+       size_t ramsize = bin_attr->size;
+
+       if (pos >= ramsize)
+               return 0;
+       if (pos + size > ramsize)
+               size = ramsize - pos;
+       memcpy_fromio(buf, dev->base + pos, size);
+       return size;
+}
+
+static ssize_t txx9_sram_write(struct kobject *kobj,
+                              struct bin_attribute *bin_attr,
+                              char *buf, loff_t pos, size_t size)
+{
+       struct txx9_sramc_sysdev *dev = bin_attr->private;
+       size_t ramsize = bin_attr->size;
+
+       if (pos >= ramsize)
+               return 0;
+       if (pos + size > ramsize)
+               size = ramsize - pos;
+       memcpy_toio(dev->base + pos, buf, size);
+       return size;
+}
+
+void __init txx9_sramc_init(struct resource *r)
+{
+       struct txx9_sramc_sysdev *dev;
+       size_t size;
+       int err;
+
+       if (!txx9_sramc_sysdev_class.name) {
+               txx9_sramc_sysdev_class.name = "txx9_sram";
+               err = sysdev_class_register(&txx9_sramc_sysdev_class);
+               if (err) {
+                       txx9_sramc_sysdev_class.name = NULL;
+                       return;
+               }
+       }
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return;
+       size = resource_size(r);
+       dev->base = ioremap(r->start, size);
+       if (!dev->base)
+               goto exit;
+       dev->dev.cls = &txx9_sramc_sysdev_class;
+       sysfs_bin_attr_init(&dev->bindata_attr);
+       dev->bindata_attr.attr.name = "bindata";
+       dev->bindata_attr.attr.mode = S_IRUSR | S_IWUSR;
+       dev->bindata_attr.read = txx9_sram_read;
+       dev->bindata_attr.write = txx9_sram_write;
+       dev->bindata_attr.size = size;
+       dev->bindata_attr.private = dev;
+       err = sysdev_register(&dev->dev);
+       if (err)
+               goto exit;
+       err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr);
+       if (err) {
+               sysdev_unregister(&dev->dev);
+               goto exit;
+       }
+       return;
+exit:
+       if (dev) {
+               if (dev->base)
+                       iounmap(dev->base);
+               kfree(dev);
+       }
+}