linux/arch/xtensa/platforms/xtfpga/setup.c
<<
>>
Prefs
   1/*
   2 *
   3 * arch/xtensa/platform/xtavnet/setup.c
   4 *
   5 * ...
   6 *
   7 * Authors:     Chris Zankel <chris@zankel.net>
   8 *              Joe Taylor <joe@tensilica.com>
   9 *
  10 * Copyright 2001 - 2006 Tensilica Inc.
  11 *
  12 * This program is free software; you can redistribute  it and/or modify it
  13 * under  the terms of  the GNU General  Public License as published by the
  14 * Free Software Foundation;  either version 2 of the  License, or (at your
  15 * option) any later version.
  16 *
  17 */
  18#include <linux/stddef.h>
  19#include <linux/kernel.h>
  20#include <linux/init.h>
  21#include <linux/errno.h>
  22#include <linux/reboot.h>
  23#include <linux/kdev_t.h>
  24#include <linux/types.h>
  25#include <linux/major.h>
  26#include <linux/console.h>
  27#include <linux/delay.h>
  28#include <linux/of.h>
  29
  30#include <asm/timex.h>
  31#include <asm/processor.h>
  32#include <asm/platform.h>
  33#include <asm/bootparam.h>
  34#include <platform/lcd.h>
  35#include <platform/hardware.h>
  36
  37void platform_halt(void)
  38{
  39        lcd_disp_at_pos(" HALT ", 0);
  40        local_irq_disable();
  41        while (1)
  42                cpu_relax();
  43}
  44
  45void platform_power_off(void)
  46{
  47        lcd_disp_at_pos("POWEROFF", 0);
  48        local_irq_disable();
  49        while (1)
  50                cpu_relax();
  51}
  52
  53void platform_restart(void)
  54{
  55        /* Flush and reset the mmu, simulate a processor reset, and
  56         * jump to the reset vector. */
  57
  58
  59        __asm__ __volatile__ ("movi     a2, 15\n\t"
  60                              "wsr      a2, icountlevel\n\t"
  61                              "movi     a2, 0\n\t"
  62                              "wsr      a2, icount\n\t"
  63#if XCHAL_NUM_IBREAK > 0
  64                              "wsr      a2, ibreakenable\n\t"
  65#endif
  66#if XCHAL_HAVE_LOOPS
  67                              "wsr      a2, lcount\n\t"
  68#endif
  69                              "movi     a2, 0x1f\n\t"
  70                              "wsr      a2, ps\n\t"
  71                              "isync\n\t"
  72                              "jx       %0\n\t"
  73                              :
  74                              : "a" (XCHAL_RESET_VECTOR_VADDR)
  75                              : "a2"
  76                              );
  77
  78        /* control never gets here */
  79}
  80
  81void __init platform_setup(char **cmdline)
  82{
  83}
  84
  85#ifdef CONFIG_OF
  86
  87static void __init update_clock_frequency(struct device_node *node)
  88{
  89        struct property *newfreq;
  90        u32 freq;
  91
  92        if (!of_property_read_u32(node, "clock-frequency", &freq) && freq != 0)
  93                return;
  94
  95        newfreq = kzalloc(sizeof(*newfreq) + sizeof(u32), GFP_KERNEL);
  96        if (!newfreq)
  97                return;
  98        newfreq->value = newfreq + 1;
  99        newfreq->length = sizeof(freq);
 100        newfreq->name = kstrdup("clock-frequency", GFP_KERNEL);
 101        if (!newfreq->name) {
 102                kfree(newfreq);
 103                return;
 104        }
 105
 106        *(u32 *)newfreq->value = cpu_to_be32(*(u32 *)XTFPGA_CLKFRQ_VADDR);
 107        of_update_property(node, newfreq);
 108}
 109
 110#define MAC_LEN 6
 111static void __init update_local_mac(struct device_node *node)
 112{
 113        struct property *newmac;
 114        const u8* macaddr;
 115        int prop_len;
 116
 117        macaddr = of_get_property(node, "local-mac-address", &prop_len);
 118        if (macaddr == NULL || prop_len != MAC_LEN)
 119                return;
 120
 121        newmac = kzalloc(sizeof(*newmac) + MAC_LEN, GFP_KERNEL);
 122        if (newmac == NULL)
 123                return;
 124
 125        newmac->value = newmac + 1;
 126        newmac->length = MAC_LEN;
 127        newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
 128        if (newmac->name == NULL) {
 129                kfree(newmac);
 130                return;
 131        }
 132
 133        memcpy(newmac->value, macaddr, MAC_LEN);
 134        ((u8*)newmac->value)[5] = (*(u32*)DIP_SWITCHES_VADDR) & 0x3f;
 135        of_update_property(node, newmac);
 136}
 137
 138static int __init machine_setup(void)
 139{
 140        struct device_node *clock;
 141        struct device_node *eth = NULL;
 142
 143        for_each_node_by_name(clock, "main-oscillator")
 144                update_clock_frequency(clock);
 145
 146        if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
 147                update_local_mac(eth);
 148        return 0;
 149}
 150arch_initcall(machine_setup);
 151
 152#endif
 153
 154/* early initialization */
 155
 156void __init platform_init(bp_tag_t *first)
 157{
 158}
 159
 160/* Heartbeat. */
 161
 162void platform_heartbeat(void)
 163{
 164}
 165
 166#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 167
 168void __init platform_calibrate_ccount(void)
 169{
 170        long clk_freq = 0;
 171#ifdef CONFIG_OF
 172        struct device_node *cpu =
 173                of_find_compatible_node(NULL, NULL, "cdns,xtensa-cpu");
 174        if (cpu) {
 175                u32 freq;
 176                update_clock_frequency(cpu);
 177                if (!of_property_read_u32(cpu, "clock-frequency", &freq))
 178                        clk_freq = freq;
 179        }
 180#endif
 181        if (!clk_freq)
 182                clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR;
 183
 184        ccount_freq = clk_freq;
 185}
 186
 187#endif
 188
 189#ifndef CONFIG_OF
 190
 191#include <linux/serial_8250.h>
 192#include <linux/if.h>
 193#include <net/ethoc.h>
 194#include <linux/usb/c67x00.h>
 195
 196/*----------------------------------------------------------------------------
 197 *  Ethernet -- OpenCores Ethernet MAC (ethoc driver)
 198 */
 199
 200static struct resource ethoc_res[] = {
 201        [0] = { /* register space */
 202                .start = OETH_REGS_PADDR,
 203                .end   = OETH_REGS_PADDR + OETH_REGS_SIZE - 1,
 204                .flags = IORESOURCE_MEM,
 205        },
 206        [1] = { /* buffer space */
 207                .start = OETH_SRAMBUFF_PADDR,
 208                .end   = OETH_SRAMBUFF_PADDR + OETH_SRAMBUFF_SIZE - 1,
 209                .flags = IORESOURCE_MEM,
 210        },
 211        [2] = { /* IRQ number */
 212                .start = OETH_IRQ,
 213                .end   = OETH_IRQ,
 214                .flags = IORESOURCE_IRQ,
 215        },
 216};
 217
 218static struct ethoc_platform_data ethoc_pdata = {
 219        /*
 220         * The MAC address for these boards is 00:50:c2:13:6f:xx.
 221         * The last byte (here as zero) is read from the DIP switches on the
 222         * board.
 223         */
 224        .hwaddr = { 0x00, 0x50, 0xc2, 0x13, 0x6f, 0 },
 225        .phy_id = -1,
 226        .big_endian = XCHAL_HAVE_BE,
 227};
 228
 229static struct platform_device ethoc_device = {
 230        .name = "ethoc",
 231        .id = -1,
 232        .num_resources = ARRAY_SIZE(ethoc_res),
 233        .resource = ethoc_res,
 234        .dev = {
 235                .platform_data = &ethoc_pdata,
 236        },
 237};
 238
 239/*----------------------------------------------------------------------------
 240 *  USB Host/Device -- Cypress CY7C67300
 241 */
 242
 243static struct resource c67x00_res[] = {
 244        [0] = { /* register space */
 245                .start = C67X00_PADDR,
 246                .end   = C67X00_PADDR + C67X00_SIZE - 1,
 247                .flags = IORESOURCE_MEM,
 248        },
 249        [1] = { /* IRQ number */
 250                .start = C67X00_IRQ,
 251                .end   = C67X00_IRQ,
 252                .flags = IORESOURCE_IRQ,
 253        },
 254};
 255
 256static struct c67x00_platform_data c67x00_pdata = {
 257        .sie_config = C67X00_SIE1_HOST | C67X00_SIE2_UNUSED,
 258        .hpi_regstep = 4,
 259};
 260
 261static struct platform_device c67x00_device = {
 262        .name = "c67x00",
 263        .id = -1,
 264        .num_resources = ARRAY_SIZE(c67x00_res),
 265        .resource = c67x00_res,
 266        .dev = {
 267                .platform_data = &c67x00_pdata,
 268        },
 269};
 270
 271/*----------------------------------------------------------------------------
 272 *  UART
 273 */
 274
 275static struct resource serial_resource = {
 276        .start  = DUART16552_PADDR,
 277        .end    = DUART16552_PADDR + 0x1f,
 278        .flags  = IORESOURCE_MEM,
 279};
 280
 281static struct plat_serial8250_port serial_platform_data[] = {
 282        [0] = {
 283                .mapbase        = DUART16552_PADDR,
 284                .irq            = DUART16552_INTNUM,
 285                .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
 286                                  UPF_IOREMAP,
 287                .iotype         = XCHAL_HAVE_BE ? UPIO_MEM32BE : UPIO_MEM32,
 288                .regshift       = 2,
 289                .uartclk        = 0,    /* set in xtavnet_init() */
 290        },
 291        { },
 292};
 293
 294static struct platform_device xtavnet_uart = {
 295        .name           = "serial8250",
 296        .id             = PLAT8250_DEV_PLATFORM,
 297        .dev            = {
 298                .platform_data  = serial_platform_data,
 299        },
 300        .num_resources  = 1,
 301        .resource       = &serial_resource,
 302};
 303
 304/* platform devices */
 305static struct platform_device *platform_devices[] __initdata = {
 306        &ethoc_device,
 307        &c67x00_device,
 308        &xtavnet_uart,
 309};
 310
 311
 312static int __init xtavnet_init(void)
 313{
 314        /* Ethernet MAC address.  */
 315        ethoc_pdata.hwaddr[5] = *(u32 *)DIP_SWITCHES_VADDR;
 316
 317        /* Clock rate varies among FPGA bitstreams; board specific FPGA register
 318         * reports the actual clock rate.
 319         */
 320        serial_platform_data[0].uartclk = *(long *)XTFPGA_CLKFRQ_VADDR;
 321
 322
 323        /* register platform devices */
 324        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 325
 326        /* ETHOC driver is a bit quiet; at least display Ethernet MAC, so user
 327         * knows whether they set it correctly on the DIP switches.
 328         */
 329        pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr);
 330        ethoc_pdata.eth_clkfreq = *(long *)XTFPGA_CLKFRQ_VADDR;
 331
 332        return 0;
 333}
 334
 335/*
 336 * Register to be done during do_initcalls().
 337 */
 338arch_initcall(xtavnet_init);
 339
 340#endif /* CONFIG_OF */
 341