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 5526375..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.
  *
@@ -24,6 +22,7 @@
 #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>
@@ -32,6 +31,8 @@
 #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
@@ -84,7 +85,7 @@ int txx9_ccfg_toeon __initdata = 1;
 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);
@@ -156,25 +157,22 @@ static struct txx9_board_vec *__init find_board_byname(const char *name)
 
 static void __init prom_init_cmdline(void)
 {
-       int argc = (int)fw_arg0;
-       int *argv32 = (int *)fw_arg1;
+       int argc;
+       int *argv32;
        int i;                  /* Always ignore the "-c" at argv[0] */
-       char builtin[CL_SIZE];
-
-       /* ignore all built-in args if any f/w args given */
-       /*
-        * But if built-in strings was started with '+', append them
-        * to command line args.  If built-in was started with '-',
-        * ignore all f/w args.
-        */
-       builtin[0] = '\0';
-       if (arcs_cmdline[0] == '+')
-               strcpy(builtin, arcs_cmdline + 1);
-       else if (arcs_cmdline[0] == '-') {
-               strcpy(builtin, arcs_cmdline + 1);
+
+       if (fw_arg0 >= CKSEG0 || fw_arg1 < CKSEG0) {
+               /*
+                * argc is not a valid number, or argv32 is not a valid
+                * pointer
+                */
                argc = 0;
-       } else if (argc <= 1)
-               strcpy(builtin, arcs_cmdline);
+               argv32 = NULL;
+       } else {
+               argc = (int)fw_arg0;
+               argv32 = (int *)fw_arg1;
+       }
+
        arcs_cmdline[0] = '\0';
 
        for (i = 1; i < argc; i++) {
@@ -188,12 +186,6 @@ static void __init prom_init_cmdline(void)
                } else
                        strcat(arcs_cmdline, str);
        }
-       /* append saved builtin args */
-       if (builtin[0]) {
-               if (arcs_cmdline[0])
-                       strcat(arcs_cmdline, " ");
-               strcat(arcs_cmdline, builtin);
-       }
 }
 
 static int txx9_ic_disable __initdata;
@@ -302,7 +294,7 @@ static inline void txx9_cache_fixup(void)
 
 static void __init preprocess_cmdline(void)
 {
-       char cmdline[CL_SIZE];
+       static char cmdline[COMMAND_LINE_SIZE] __initdata;
        char *s;
 
        strcpy(cmdline, arcs_cmdline);
@@ -407,17 +399,14 @@ const char *get_system_type(void)
        return txx9_system_type;
 }
 
-char * __init prom_getcmdline(void)
-{
-       return &(arcs_cmdline[0]);
-}
-
 const char *__init prom_getenv(const char *name)
 {
-       const s32 *str = (const s32 *)fw_arg2;
+       const s32 *str;
 
-       if (!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))
@@ -622,6 +611,21 @@ 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)
@@ -662,6 +666,26 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
 #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);
 
@@ -732,7 +756,7 @@ void __init txx9_iocled_init(unsigned long baseaddr,
                return;
        iocled->mmioaddr = ioremap(baseaddr, 1);
        if (!iocled->mmioaddr)
-               return;
+               goto out_free;
        iocled->chip.get = txx9_iocled_get;
        iocled->chip.set = txx9_iocled_set;
        iocled->chip.direction_input = txx9_iocled_dir_in;
@@ -741,13 +765,13 @@ void __init txx9_iocled_init(unsigned long baseaddr,
        iocled->chip.base = basenum;
        iocled->chip.ngpio = num;
        if (gpiochip_add(&iocled->chip))
-               return;
+               goto out_unmap;
        if (basenum < 0)
                basenum = iocled->chip.base;
 
        pdev = platform_device_alloc("leds-gpio", basenum);
        if (!pdev)
-               return;
+               goto out_gpio;
        iocled->pdata.num_leds = num;
        iocled->pdata.leds = iocled->leds;
        for (i = 0; i < num; i++) {
@@ -762,7 +786,17 @@ void __init txx9_iocled_init(unsigned long baseaddr,
        }
        pdev->dev.platform_data = &iocled->pdata;
        if (platform_device_add(pdev))
-               platform_device_put(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,
@@ -771,3 +805,177 @@ void __init txx9_iocled_init(unsigned long baseaddr,
 {
 }
 #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);
+       }
+}