linux/arch/mips/txx9/generic/setup.c
<<
>>
Prefs
   1/*
   2 * Based on linux/arch/mips/txx9/rbtx4938/setup.c,
   3 *          and RBTX49xx patch from CELF patch archive.
   4 *
   5 * 2003-2005 (c) MontaVista Software, Inc.
   6 * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
   7 *
   8 * This file is subject to the terms and conditions of the GNU General Public
   9 * License.  See the file "COPYING" in the main directory of this archive
  10 * for more details.
  11 */
  12#include <linux/init.h>
  13#include <linux/kernel.h>
  14#include <linux/types.h>
  15#include <linux/interrupt.h>
  16#include <linux/string.h>
  17#include <linux/module.h>
  18#include <linux/clk.h>
  19#include <linux/err.h>
  20#include <linux/gpio.h>
  21#include <linux/platform_device.h>
  22#include <linux/serial_core.h>
  23#include <linux/mtd/physmap.h>
  24#include <linux/leds.h>
  25#include <linux/sysdev.h>
  26#include <asm/bootinfo.h>
  27#include <asm/time.h>
  28#include <asm/reboot.h>
  29#include <asm/r4kcache.h>
  30#include <asm/sections.h>
  31#include <asm/txx9/generic.h>
  32#include <asm/txx9/pci.h>
  33#include <asm/txx9tmr.h>
  34#include <asm/txx9/ndfmc.h>
  35#include <asm/txx9/dmac.h>
  36#ifdef CONFIG_CPU_TX49XX
  37#include <asm/txx9/tx4938.h>
  38#endif
  39
  40/* EBUSC settings of TX4927, etc. */
  41struct resource txx9_ce_res[8];
  42static char txx9_ce_res_name[8][4];     /* "CEn" */
  43
  44/* pcode, internal register */
  45unsigned int txx9_pcode;
  46char txx9_pcode_str[8];
  47static struct resource txx9_reg_res = {
  48        .name = txx9_pcode_str,
  49        .flags = IORESOURCE_MEM,
  50};
  51void __init
  52txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size)
  53{
  54        int i;
  55
  56        for (i = 0; i < ARRAY_SIZE(txx9_ce_res); i++) {
  57                sprintf(txx9_ce_res_name[i], "CE%d", i);
  58                txx9_ce_res[i].flags = IORESOURCE_MEM;
  59                txx9_ce_res[i].name = txx9_ce_res_name[i];
  60        }
  61
  62        txx9_pcode = pcode;
  63        sprintf(txx9_pcode_str, "TX%x", pcode);
  64        if (base) {
  65                txx9_reg_res.start = base & 0xfffffffffULL;
  66                txx9_reg_res.end = (base & 0xfffffffffULL) + (size - 1);
  67                request_resource(&iomem_resource, &txx9_reg_res);
  68        }
  69}
  70
  71/* clocks */
  72unsigned int txx9_master_clock;
  73unsigned int txx9_cpu_clock;
  74unsigned int txx9_gbus_clock;
  75
  76#ifdef CONFIG_CPU_TX39XX
  77/* don't enable by default - see errata */
  78int txx9_ccfg_toeon __initdata;
  79#else
  80int txx9_ccfg_toeon __initdata = 1;
  81#endif
  82
  83/* Minimum CLK support */
  84
  85struct clk *clk_get(struct device *dev, const char *id)
  86{
  87        if (!strcmp(id, "spi-baseclk"))
  88                return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 2);
  89        if (!strcmp(id, "imbus_clk"))
  90                return (struct clk *)((unsigned long)txx9_gbus_clock / 2);
  91        return ERR_PTR(-ENOENT);
  92}
  93EXPORT_SYMBOL(clk_get);
  94
  95int clk_enable(struct clk *clk)
  96{
  97        return 0;
  98}
  99EXPORT_SYMBOL(clk_enable);
 100
 101void clk_disable(struct clk *clk)
 102{
 103}
 104EXPORT_SYMBOL(clk_disable);
 105
 106unsigned long clk_get_rate(struct clk *clk)
 107{
 108        return (unsigned long)clk;
 109}
 110EXPORT_SYMBOL(clk_get_rate);
 111
 112void clk_put(struct clk *clk)
 113{
 114}
 115EXPORT_SYMBOL(clk_put);
 116
 117/* GPIO support */
 118
 119#ifdef CONFIG_GENERIC_GPIO
 120int gpio_to_irq(unsigned gpio)
 121{
 122        return -EINVAL;
 123}
 124EXPORT_SYMBOL(gpio_to_irq);
 125
 126int irq_to_gpio(unsigned irq)
 127{
 128        return -EINVAL;
 129}
 130EXPORT_SYMBOL(irq_to_gpio);
 131#endif
 132
 133#define BOARD_VEC(board)        extern struct txx9_board_vec board;
 134#include <asm/txx9/boards.h>
 135#undef BOARD_VEC
 136
 137struct txx9_board_vec *txx9_board_vec __initdata;
 138static char txx9_system_type[32];
 139
 140static struct txx9_board_vec *board_vecs[] __initdata = {
 141#define BOARD_VEC(board)        &board,
 142#include <asm/txx9/boards.h>
 143#undef BOARD_VEC
 144};
 145
 146static struct txx9_board_vec *__init find_board_byname(const char *name)
 147{
 148        int i;
 149
 150        /* search board_vecs table */
 151        for (i = 0; i < ARRAY_SIZE(board_vecs); i++) {
 152                if (strstr(board_vecs[i]->system, name))
 153                        return board_vecs[i];
 154        }
 155        return NULL;
 156}
 157
 158static void __init prom_init_cmdline(void)
 159{
 160        int argc;
 161        int *argv32;
 162        int i;                  /* Always ignore the "-c" at argv[0] */
 163        static char builtin[CL_SIZE] __initdata;
 164
 165        if (fw_arg0 >= CKSEG0 || fw_arg1 < CKSEG0) {
 166                /*
 167                 * argc is not a valid number, or argv32 is not a valid
 168                 * pointer
 169                 */
 170                argc = 0;
 171                argv32 = NULL;
 172        } else {
 173                argc = (int)fw_arg0;
 174                argv32 = (int *)fw_arg1;
 175        }
 176
 177        /* ignore all built-in args if any f/w args given */
 178        /*
 179         * But if built-in strings was started with '+', append them
 180         * to command line args.  If built-in was started with '-',
 181         * ignore all f/w args.
 182         */
 183        builtin[0] = '\0';
 184        if (arcs_cmdline[0] == '+')
 185                strcpy(builtin, arcs_cmdline + 1);
 186        else if (arcs_cmdline[0] == '-') {
 187                strcpy(builtin, arcs_cmdline + 1);
 188                argc = 0;
 189        } else if (argc <= 1)
 190                strcpy(builtin, arcs_cmdline);
 191        arcs_cmdline[0] = '\0';
 192
 193        for (i = 1; i < argc; i++) {
 194                char *str = (char *)(long)argv32[i];
 195                if (i != 1)
 196                        strcat(arcs_cmdline, " ");
 197                if (strchr(str, ' ')) {
 198                        strcat(arcs_cmdline, "\"");
 199                        strcat(arcs_cmdline, str);
 200                        strcat(arcs_cmdline, "\"");
 201                } else
 202                        strcat(arcs_cmdline, str);
 203        }
 204        /* append saved builtin args */
 205        if (builtin[0]) {
 206                if (arcs_cmdline[0])
 207                        strcat(arcs_cmdline, " ");
 208                strcat(arcs_cmdline, builtin);
 209        }
 210}
 211
 212static int txx9_ic_disable __initdata;
 213static int txx9_dc_disable __initdata;
 214
 215#if defined(CONFIG_CPU_TX49XX)
 216/* flush all cache on very early stage (before 4k_cache_init) */
 217static void __init early_flush_dcache(void)
 218{
 219        unsigned int conf = read_c0_config();
 220        unsigned int dc_size = 1 << (12 + ((conf & CONF_DC) >> 6));
 221        unsigned int linesz = 32;
 222        unsigned long addr, end;
 223
 224        end = INDEX_BASE + dc_size / 4;
 225        /* 4way, waybit=0 */
 226        for (addr = INDEX_BASE; addr < end; addr += linesz) {
 227                cache_op(Index_Writeback_Inv_D, addr | 0);
 228                cache_op(Index_Writeback_Inv_D, addr | 1);
 229                cache_op(Index_Writeback_Inv_D, addr | 2);
 230                cache_op(Index_Writeback_Inv_D, addr | 3);
 231        }
 232}
 233
 234static void __init txx9_cache_fixup(void)
 235{
 236        unsigned int conf;
 237
 238        conf = read_c0_config();
 239        /* flush and disable */
 240        if (txx9_ic_disable) {
 241                conf |= TX49_CONF_IC;
 242                write_c0_config(conf);
 243        }
 244        if (txx9_dc_disable) {
 245                early_flush_dcache();
 246                conf |= TX49_CONF_DC;
 247                write_c0_config(conf);
 248        }
 249
 250        /* enable cache */
 251        conf = read_c0_config();
 252        if (!txx9_ic_disable)
 253                conf &= ~TX49_CONF_IC;
 254        if (!txx9_dc_disable)
 255                conf &= ~TX49_CONF_DC;
 256        write_c0_config(conf);
 257
 258        if (conf & TX49_CONF_IC)
 259                pr_info("TX49XX I-Cache disabled.\n");
 260        if (conf & TX49_CONF_DC)
 261                pr_info("TX49XX D-Cache disabled.\n");
 262}
 263#elif defined(CONFIG_CPU_TX39XX)
 264/* flush all cache on very early stage (before tx39_cache_init) */
 265static void __init early_flush_dcache(void)
 266{
 267        unsigned int conf = read_c0_config();
 268        unsigned int dc_size = 1 << (10 + ((conf & TX39_CONF_DCS_MASK) >>
 269                                           TX39_CONF_DCS_SHIFT));
 270        unsigned int linesz = 16;
 271        unsigned long addr, end;
 272
 273        end = INDEX_BASE + dc_size / 2;
 274        /* 2way, waybit=0 */
 275        for (addr = INDEX_BASE; addr < end; addr += linesz) {
 276                cache_op(Index_Writeback_Inv_D, addr | 0);
 277                cache_op(Index_Writeback_Inv_D, addr | 1);
 278        }
 279}
 280
 281static void __init txx9_cache_fixup(void)
 282{
 283        unsigned int conf;
 284
 285        conf = read_c0_config();
 286        /* flush and disable */
 287        if (txx9_ic_disable) {
 288                conf &= ~TX39_CONF_ICE;
 289                write_c0_config(conf);
 290        }
 291        if (txx9_dc_disable) {
 292                early_flush_dcache();
 293                conf &= ~TX39_CONF_DCE;
 294                write_c0_config(conf);
 295        }
 296
 297        /* enable cache */
 298        conf = read_c0_config();
 299        if (!txx9_ic_disable)
 300                conf |= TX39_CONF_ICE;
 301        if (!txx9_dc_disable)
 302                conf |= TX39_CONF_DCE;
 303        write_c0_config(conf);
 304
 305        if (!(conf & TX39_CONF_ICE))
 306                pr_info("TX39XX I-Cache disabled.\n");
 307        if (!(conf & TX39_CONF_DCE))
 308                pr_info("TX39XX D-Cache disabled.\n");
 309}
 310#else
 311static inline void txx9_cache_fixup(void)
 312{
 313}
 314#endif
 315
 316static void __init preprocess_cmdline(void)
 317{
 318        static char cmdline[CL_SIZE] __initdata;
 319        char *s;
 320
 321        strcpy(cmdline, arcs_cmdline);
 322        s = cmdline;
 323        arcs_cmdline[0] = '\0';
 324        while (s && *s) {
 325                char *str = strsep(&s, " ");
 326                if (strncmp(str, "board=", 6) == 0) {
 327                        txx9_board_vec = find_board_byname(str + 6);
 328                        continue;
 329                } else if (strncmp(str, "masterclk=", 10) == 0) {
 330                        unsigned long val;
 331                        if (strict_strtoul(str + 10, 10, &val) == 0)
 332                                txx9_master_clock = val;
 333                        continue;
 334                } else if (strcmp(str, "icdisable") == 0) {
 335                        txx9_ic_disable = 1;
 336                        continue;
 337                } else if (strcmp(str, "dcdisable") == 0) {
 338                        txx9_dc_disable = 1;
 339                        continue;
 340                } else if (strcmp(str, "toeoff") == 0) {
 341                        txx9_ccfg_toeon = 0;
 342                        continue;
 343                } else if (strcmp(str, "toeon") == 0) {
 344                        txx9_ccfg_toeon = 1;
 345                        continue;
 346                }
 347                if (arcs_cmdline[0])
 348                        strcat(arcs_cmdline, " ");
 349                strcat(arcs_cmdline, str);
 350        }
 351
 352        txx9_cache_fixup();
 353}
 354
 355static void __init select_board(void)
 356{
 357        const char *envstr;
 358
 359        /* first, determine by "board=" argument in preprocess_cmdline() */
 360        if (txx9_board_vec)
 361                return;
 362        /* next, determine by "board" envvar */
 363        envstr = prom_getenv("board");
 364        if (envstr) {
 365                txx9_board_vec = find_board_byname(envstr);
 366                if (txx9_board_vec)
 367                        return;
 368        }
 369
 370        /* select "default" board */
 371#ifdef CONFIG_CPU_TX39XX
 372        txx9_board_vec = &jmr3927_vec;
 373#endif
 374#ifdef CONFIG_CPU_TX49XX
 375        switch (TX4938_REV_PCODE()) {
 376#ifdef CONFIG_TOSHIBA_RBTX4927
 377        case 0x4927:
 378                txx9_board_vec = &rbtx4927_vec;
 379                break;
 380        case 0x4937:
 381                txx9_board_vec = &rbtx4937_vec;
 382                break;
 383#endif
 384#ifdef CONFIG_TOSHIBA_RBTX4938
 385        case 0x4938:
 386                txx9_board_vec = &rbtx4938_vec;
 387                break;
 388#endif
 389#ifdef CONFIG_TOSHIBA_RBTX4939
 390        case 0x4939:
 391                txx9_board_vec = &rbtx4939_vec;
 392                break;
 393#endif
 394        }
 395#endif
 396}
 397
 398void __init prom_init(void)
 399{
 400        prom_init_cmdline();
 401        preprocess_cmdline();
 402        select_board();
 403
 404        strcpy(txx9_system_type, txx9_board_vec->system);
 405
 406        txx9_board_vec->prom_init();
 407}
 408
 409void __init prom_free_prom_memory(void)
 410{
 411        unsigned long saddr = PAGE_SIZE;
 412        unsigned long eaddr = __pa_symbol(&_text);
 413
 414        if (saddr < eaddr)
 415                free_init_pages("prom memory", saddr, eaddr);
 416}
 417
 418const char *get_system_type(void)
 419{
 420        return txx9_system_type;
 421}
 422
 423char * __init prom_getcmdline(void)
 424{
 425        return &(arcs_cmdline[0]);
 426}
 427
 428const char *__init prom_getenv(const char *name)
 429{
 430        const s32 *str;
 431
 432        if (fw_arg2 < CKSEG0)
 433                return NULL;
 434
 435        str = (const s32 *)fw_arg2;
 436        /* YAMON style ("name", "value" pairs) */
 437        while (str[0] && str[1]) {
 438                if (!strcmp((const char *)(unsigned long)str[0], name))
 439                        return (const char *)(unsigned long)str[1];
 440                str += 2;
 441        }
 442        return NULL;
 443}
 444
 445static void __noreturn txx9_machine_halt(void)
 446{
 447        local_irq_disable();
 448        clear_c0_status(ST0_IM);
 449        while (1) {
 450                if (cpu_wait) {
 451                        (*cpu_wait)();
 452                        if (cpu_has_counter) {
 453                                /*
 454                                 * Clear counter interrupt while it
 455                                 * breaks WAIT instruction even if
 456                                 * masked.
 457                                 */
 458                                write_c0_compare(0);
 459                        }
 460                }
 461        }
 462}
 463
 464/* Watchdog support */
 465void __init txx9_wdt_init(unsigned long base)
 466{
 467        struct resource res = {
 468                .start  = base,
 469                .end    = base + 0x100 - 1,
 470                .flags  = IORESOURCE_MEM,
 471        };
 472        platform_device_register_simple("txx9wdt", -1, &res, 1);
 473}
 474
 475void txx9_wdt_now(unsigned long base)
 476{
 477        struct txx9_tmr_reg __iomem *tmrptr =
 478                ioremap(base, sizeof(struct txx9_tmr_reg));
 479        /* disable watch dog timer */
 480        __raw_writel(TXx9_TMWTMR_WDIS | TXx9_TMWTMR_TWC, &tmrptr->wtmr);
 481        __raw_writel(0, &tmrptr->tcr);
 482        /* kick watchdog */
 483        __raw_writel(TXx9_TMWTMR_TWIE, &tmrptr->wtmr);
 484        __raw_writel(1, &tmrptr->cpra); /* immediate */
 485        __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
 486                     &tmrptr->tcr);
 487}
 488
 489/* SPI support */
 490void __init txx9_spi_init(int busid, unsigned long base, int irq)
 491{
 492        struct resource res[] = {
 493                {
 494                        .start  = base,
 495                        .end    = base + 0x20 - 1,
 496                        .flags  = IORESOURCE_MEM,
 497                }, {
 498                        .start  = irq,
 499                        .flags  = IORESOURCE_IRQ,
 500                },
 501        };
 502        platform_device_register_simple("spi_txx9", busid,
 503                                        res, ARRAY_SIZE(res));
 504}
 505
 506void __init txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr)
 507{
 508        struct platform_device *pdev =
 509                platform_device_alloc("tc35815-mac", id);
 510        if (!pdev ||
 511            platform_device_add_data(pdev, ethaddr, 6) ||
 512            platform_device_add(pdev))
 513                platform_device_put(pdev);
 514}
 515
 516void __init txx9_sio_init(unsigned long baseaddr, int irq,
 517                          unsigned int line, unsigned int sclk, int nocts)
 518{
 519#ifdef CONFIG_SERIAL_TXX9
 520        struct uart_port req;
 521
 522        memset(&req, 0, sizeof(req));
 523        req.line = line;
 524        req.iotype = UPIO_MEM;
 525        req.membase = ioremap(baseaddr, 0x24);
 526        req.mapbase = baseaddr;
 527        req.irq = irq;
 528        if (!nocts)
 529                req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
 530        if (sclk) {
 531                req.flags |= UPF_MAGIC_MULTIPLIER /*USE_SCLK*/;
 532                req.uartclk = sclk;
 533        } else
 534                req.uartclk = TXX9_IMCLK;
 535        early_serial_txx9_setup(&req);
 536#endif /* CONFIG_SERIAL_TXX9 */
 537}
 538
 539#ifdef CONFIG_EARLY_PRINTK
 540static void __init null_prom_putchar(char c)
 541{
 542}
 543void (*txx9_prom_putchar)(char c) __initdata = null_prom_putchar;
 544
 545void __init prom_putchar(char c)
 546{
 547        txx9_prom_putchar(c);
 548}
 549
 550static void __iomem *early_txx9_sio_port;
 551
 552static void __init early_txx9_sio_putchar(char c)
 553{
 554#define TXX9_SICISR     0x0c
 555#define TXX9_SITFIFO    0x1c
 556#define TXX9_SICISR_TXALS       0x00000002
 557        while (!(__raw_readl(early_txx9_sio_port + TXX9_SICISR) &
 558                 TXX9_SICISR_TXALS))
 559                ;
 560        __raw_writel(c, early_txx9_sio_port + TXX9_SITFIFO);
 561}
 562
 563void __init txx9_sio_putchar_init(unsigned long baseaddr)
 564{
 565        early_txx9_sio_port = ioremap(baseaddr, 0x24);
 566        txx9_prom_putchar = early_txx9_sio_putchar;
 567}
 568#endif /* CONFIG_EARLY_PRINTK */
 569
 570/* wrappers */
 571void __init plat_mem_setup(void)
 572{
 573        ioport_resource.start = 0;
 574        ioport_resource.end = ~0UL;     /* no limit */
 575        iomem_resource.start = 0;
 576        iomem_resource.end = ~0UL;      /* no limit */
 577
 578        /* fallback restart/halt routines */
 579        _machine_restart = (void (*)(char *))txx9_machine_halt;
 580        _machine_halt = txx9_machine_halt;
 581        pm_power_off = txx9_machine_halt;
 582
 583#ifdef CONFIG_PCI
 584        pcibios_plat_setup = txx9_pcibios_setup;
 585#endif
 586        txx9_board_vec->mem_setup();
 587}
 588
 589void __init arch_init_irq(void)
 590{
 591        txx9_board_vec->irq_setup();
 592}
 593
 594void __init plat_time_init(void)
 595{
 596#ifdef CONFIG_CPU_TX49XX
 597        mips_hpt_frequency = txx9_cpu_clock / 2;
 598#endif
 599        txx9_board_vec->time_init();
 600}
 601
 602static int __init _txx9_arch_init(void)
 603{
 604        if (txx9_board_vec->arch_init)
 605                txx9_board_vec->arch_init();
 606        return 0;
 607}
 608arch_initcall(_txx9_arch_init);
 609
 610static int __init _txx9_device_init(void)
 611{
 612        if (txx9_board_vec->device_init)
 613                txx9_board_vec->device_init();
 614        return 0;
 615}
 616device_initcall(_txx9_device_init);
 617
 618int (*txx9_irq_dispatch)(int pending);
 619asmlinkage void plat_irq_dispatch(void)
 620{
 621        int pending = read_c0_status() & read_c0_cause() & ST0_IM;
 622        int irq = txx9_irq_dispatch(pending);
 623
 624        if (likely(irq >= 0))
 625                do_IRQ(irq);
 626        else
 627                spurious_interrupt();
 628}
 629
 630/* see include/asm-mips/mach-tx39xx/mangle-port.h, for example. */
 631#ifdef NEEDS_TXX9_SWIZZLE_ADDR_B
 632static unsigned long __swizzle_addr_none(unsigned long port)
 633{
 634        return port;
 635}
 636unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none;
 637EXPORT_SYMBOL(__swizzle_addr_b);
 638#endif
 639
 640#ifdef NEEDS_TXX9_IOSWABW
 641static u16 ioswabw_default(volatile u16 *a, u16 x)
 642{
 643        return le16_to_cpu(x);
 644}
 645static u16 __mem_ioswabw_default(volatile u16 *a, u16 x)
 646{
 647        return x;
 648}
 649u16 (*ioswabw)(volatile u16 *a, u16 x) = ioswabw_default;
 650EXPORT_SYMBOL(ioswabw);
 651u16 (*__mem_ioswabw)(volatile u16 *a, u16 x) = __mem_ioswabw_default;
 652EXPORT_SYMBOL(__mem_ioswabw);
 653#endif
 654
 655void __init txx9_physmap_flash_init(int no, unsigned long addr,
 656                                    unsigned long size,
 657                                    const struct physmap_flash_data *pdata)
 658{
 659#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 660        struct resource res = {
 661                .start = addr,
 662                .end = addr + size - 1,
 663                .flags = IORESOURCE_MEM,
 664        };
 665        struct platform_device *pdev;
 666#ifdef CONFIG_MTD_PARTITIONS
 667        static struct mtd_partition parts[2];
 668        struct physmap_flash_data pdata_part;
 669
 670        /* If this area contained boot area, make separate partition */
 671        if (pdata->nr_parts == 0 && !pdata->parts &&
 672            addr < 0x1fc00000 && addr + size > 0x1fc00000 &&
 673            !parts[0].name) {
 674                parts[0].name = "boot";
 675                parts[0].offset = 0x1fc00000 - addr;
 676                parts[0].size = addr + size - 0x1fc00000;
 677                parts[1].name = "user";
 678                parts[1].offset = 0;
 679                parts[1].size = 0x1fc00000 - addr;
 680                pdata_part = *pdata;
 681                pdata_part.nr_parts = ARRAY_SIZE(parts);
 682                pdata_part.parts = parts;
 683                pdata = &pdata_part;
 684        }
 685#endif
 686        pdev = platform_device_alloc("physmap-flash", no);
 687        if (!pdev ||
 688            platform_device_add_resources(pdev, &res, 1) ||
 689            platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
 690            platform_device_add(pdev))
 691                platform_device_put(pdev);
 692#endif
 693}
 694
 695void __init txx9_ndfmc_init(unsigned long baseaddr,
 696                            const struct txx9ndfmc_platform_data *pdata)
 697{
 698#if defined(CONFIG_MTD_NAND_TXX9NDFMC) || \
 699        defined(CONFIG_MTD_NAND_TXX9NDFMC_MODULE)
 700        struct resource res = {
 701                .start = baseaddr,
 702                .end = baseaddr + 0x1000 - 1,
 703                .flags = IORESOURCE_MEM,
 704        };
 705        struct platform_device *pdev = platform_device_alloc("txx9ndfmc", -1);
 706
 707        if (!pdev ||
 708            platform_device_add_resources(pdev, &res, 1) ||
 709            platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
 710            platform_device_add(pdev))
 711                platform_device_put(pdev);
 712#endif
 713}
 714
 715#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
 716static DEFINE_SPINLOCK(txx9_iocled_lock);
 717
 718#define TXX9_IOCLED_MAXLEDS 8
 719
 720struct txx9_iocled_data {
 721        struct gpio_chip chip;
 722        u8 cur_val;
 723        void __iomem *mmioaddr;
 724        struct gpio_led_platform_data pdata;
 725        struct gpio_led leds[TXX9_IOCLED_MAXLEDS];
 726        char names[TXX9_IOCLED_MAXLEDS][32];
 727};
 728
 729static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset)
 730{
 731        struct txx9_iocled_data *data =
 732                container_of(chip, struct txx9_iocled_data, chip);
 733        return data->cur_val & (1 << offset);
 734}
 735
 736static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset,
 737                            int value)
 738{
 739        struct txx9_iocled_data *data =
 740                container_of(chip, struct txx9_iocled_data, chip);
 741        unsigned long flags;
 742        spin_lock_irqsave(&txx9_iocled_lock, flags);
 743        if (value)
 744                data->cur_val |= 1 << offset;
 745        else
 746                data->cur_val &= ~(1 << offset);
 747        writeb(data->cur_val, data->mmioaddr);
 748        mmiowb();
 749        spin_unlock_irqrestore(&txx9_iocled_lock, flags);
 750}
 751
 752static int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset)
 753{
 754        return 0;
 755}
 756
 757static int txx9_iocled_dir_out(struct gpio_chip *chip, unsigned int offset,
 758                               int value)
 759{
 760        txx9_iocled_set(chip, offset, value);
 761        return 0;
 762}
 763
 764void __init txx9_iocled_init(unsigned long baseaddr,
 765                             int basenum, unsigned int num, int lowactive,
 766                             const char *color, char **deftriggers)
 767{
 768        struct txx9_iocled_data *iocled;
 769        struct platform_device *pdev;
 770        int i;
 771        static char *default_triggers[] __initdata = {
 772                "heartbeat",
 773                "ide-disk",
 774                "nand-disk",
 775                NULL,
 776        };
 777
 778        if (!deftriggers)
 779                deftriggers = default_triggers;
 780        iocled = kzalloc(sizeof(*iocled), GFP_KERNEL);
 781        if (!iocled)
 782                return;
 783        iocled->mmioaddr = ioremap(baseaddr, 1);
 784        if (!iocled->mmioaddr)
 785                goto out_free;
 786        iocled->chip.get = txx9_iocled_get;
 787        iocled->chip.set = txx9_iocled_set;
 788        iocled->chip.direction_input = txx9_iocled_dir_in;
 789        iocled->chip.direction_output = txx9_iocled_dir_out;
 790        iocled->chip.label = "iocled";
 791        iocled->chip.base = basenum;
 792        iocled->chip.ngpio = num;
 793        if (gpiochip_add(&iocled->chip))
 794                goto out_unmap;
 795        if (basenum < 0)
 796                basenum = iocled->chip.base;
 797
 798        pdev = platform_device_alloc("leds-gpio", basenum);
 799        if (!pdev)
 800                goto out_gpio;
 801        iocled->pdata.num_leds = num;
 802        iocled->pdata.leds = iocled->leds;
 803        for (i = 0; i < num; i++) {
 804                struct gpio_led *led = &iocled->leds[i];
 805                snprintf(iocled->names[i], sizeof(iocled->names[i]),
 806                         "iocled:%s:%u", color, i);
 807                led->name = iocled->names[i];
 808                led->gpio = basenum + i;
 809                led->active_low = lowactive;
 810                if (deftriggers && *deftriggers)
 811                        led->default_trigger = *deftriggers++;
 812        }
 813        pdev->dev.platform_data = &iocled->pdata;
 814        if (platform_device_add(pdev))
 815                goto out_pdev;
 816        return;
 817out_pdev:
 818        platform_device_put(pdev);
 819out_gpio:
 820        if (gpiochip_remove(&iocled->chip))
 821                return;
 822out_unmap:
 823        iounmap(iocled->mmioaddr);
 824out_free:
 825        kfree(iocled);
 826}
 827#else /* CONFIG_LEDS_GPIO */
 828void __init txx9_iocled_init(unsigned long baseaddr,
 829                             int basenum, unsigned int num, int lowactive,
 830                             const char *color, char **deftriggers)
 831{
 832}
 833#endif /* CONFIG_LEDS_GPIO */
 834
 835void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq,
 836                           const struct txx9dmac_platform_data *pdata)
 837{
 838#if defined(CONFIG_TXX9_DMAC) || defined(CONFIG_TXX9_DMAC_MODULE)
 839        struct resource res[] = {
 840                {
 841                        .start = baseaddr,
 842                        .end = baseaddr + 0x800 - 1,
 843                        .flags = IORESOURCE_MEM,
 844#ifndef CONFIG_MACH_TX49XX
 845                }, {
 846                        .start = irq,
 847                        .flags = IORESOURCE_IRQ,
 848#endif
 849                }
 850        };
 851#ifdef CONFIG_MACH_TX49XX
 852        struct resource chan_res[] = {
 853                {
 854                        .flags = IORESOURCE_IRQ,
 855                }
 856        };
 857#endif
 858        struct platform_device *pdev = platform_device_alloc("txx9dmac", id);
 859        struct txx9dmac_chan_platform_data cpdata;
 860        int i;
 861
 862        if (!pdev ||
 863            platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
 864            platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
 865            platform_device_add(pdev)) {
 866                platform_device_put(pdev);
 867                return;
 868        }
 869        memset(&cpdata, 0, sizeof(cpdata));
 870        cpdata.dmac_dev = pdev;
 871        for (i = 0; i < TXX9_DMA_MAX_NR_CHANNELS; i++) {
 872#ifdef CONFIG_MACH_TX49XX
 873                chan_res[0].start = irq + i;
 874#endif
 875                pdev = platform_device_alloc("txx9dmac-chan",
 876                                             id * TXX9_DMA_MAX_NR_CHANNELS + i);
 877                if (!pdev ||
 878#ifdef CONFIG_MACH_TX49XX
 879                    platform_device_add_resources(pdev, chan_res,
 880                                                  ARRAY_SIZE(chan_res)) ||
 881#endif
 882                    platform_device_add_data(pdev, &cpdata, sizeof(cpdata)) ||
 883                    platform_device_add(pdev))
 884                        platform_device_put(pdev);
 885        }
 886#endif
 887}
 888
 889void __init txx9_aclc_init(unsigned long baseaddr, int irq,
 890                           unsigned int dmac_id,
 891                           unsigned int dma_chan_out,
 892                           unsigned int dma_chan_in)
 893{
 894#if defined(CONFIG_SND_SOC_TXX9ACLC) || \
 895        defined(CONFIG_SND_SOC_TXX9ACLC_MODULE)
 896        unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS;
 897        struct resource res[] = {
 898                {
 899                        .start = baseaddr,
 900                        .end = baseaddr + 0x100 - 1,
 901                        .flags = IORESOURCE_MEM,
 902                }, {
 903                        .start = irq,
 904                        .flags = IORESOURCE_IRQ,
 905                }, {
 906                        .name = "txx9dmac-chan",
 907                        .start = dma_base + dma_chan_out,
 908                        .flags = IORESOURCE_DMA,
 909                }, {
 910                        .name = "txx9dmac-chan",
 911                        .start = dma_base + dma_chan_in,
 912                        .flags = IORESOURCE_DMA,
 913                }
 914        };
 915        struct platform_device *pdev =
 916                platform_device_alloc("txx9aclc-ac97", -1);
 917
 918        if (!pdev ||
 919            platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
 920            platform_device_add(pdev))
 921                platform_device_put(pdev);
 922#endif
 923}
 924
 925static struct sysdev_class txx9_sramc_sysdev_class;
 926
 927struct txx9_sramc_sysdev {
 928        struct sys_device dev;
 929        struct bin_attribute bindata_attr;
 930        void __iomem *base;
 931};
 932
 933static ssize_t txx9_sram_read(struct kobject *kobj,
 934                              struct bin_attribute *bin_attr,
 935                              char *buf, loff_t pos, size_t size)
 936{
 937        struct txx9_sramc_sysdev *dev = bin_attr->private;
 938        size_t ramsize = bin_attr->size;
 939
 940        if (pos >= ramsize)
 941                return 0;
 942        if (pos + size > ramsize)
 943                size = ramsize - pos;
 944        memcpy_fromio(buf, dev->base + pos, size);
 945        return size;
 946}
 947
 948static ssize_t txx9_sram_write(struct kobject *kobj,
 949                               struct bin_attribute *bin_attr,
 950                               char *buf, loff_t pos, size_t size)
 951{
 952        struct txx9_sramc_sysdev *dev = bin_attr->private;
 953        size_t ramsize = bin_attr->size;
 954
 955        if (pos >= ramsize)
 956                return 0;
 957        if (pos + size > ramsize)
 958                size = ramsize - pos;
 959        memcpy_toio(dev->base + pos, buf, size);
 960        return size;
 961}
 962
 963void __init txx9_sramc_init(struct resource *r)
 964{
 965        struct txx9_sramc_sysdev *dev;
 966        size_t size;
 967        int err;
 968
 969        if (!txx9_sramc_sysdev_class.name) {
 970                txx9_sramc_sysdev_class.name = "txx9_sram";
 971                err = sysdev_class_register(&txx9_sramc_sysdev_class);
 972                if (err) {
 973                        txx9_sramc_sysdev_class.name = NULL;
 974                        return;
 975                }
 976        }
 977        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 978        if (!dev)
 979                return;
 980        size = resource_size(r);
 981        dev->base = ioremap(r->start, size);
 982        if (!dev->base)
 983                goto exit;
 984        dev->dev.cls = &txx9_sramc_sysdev_class;
 985        dev->bindata_attr.attr.name = "bindata";
 986        dev->bindata_attr.attr.mode = S_IRUSR | S_IWUSR;
 987        dev->bindata_attr.read = txx9_sram_read;
 988        dev->bindata_attr.write = txx9_sram_write;
 989        dev->bindata_attr.size = size;
 990        dev->bindata_attr.private = dev;
 991        err = sysdev_register(&dev->dev);
 992        if (err)
 993                goto exit;
 994        err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr);
 995        if (err) {
 996                sysdev_unregister(&dev->dev);
 997                goto exit;
 998        }
 999        return;
1000exit:
1001        if (dev) {
1002                if (dev->base)
1003                        iounmap(dev->base);
1004                kfree(dev);
1005        }
1006}
1007