diff options
author | Max Filippov | 2012-11-05 07:37:14 +0400 |
---|---|---|
committer | Chris Zankel | 2012-12-18 21:10:24 -0800 |
commit | 0d456bad36d42d16022be045c8a53ddbb59ee478 (patch) | |
tree | 3c135bfcf37d6ccf45fd9ac4f739df95e181d416 /arch/xtensa/platforms/xtfpga/setup.c | |
parent | da844a81779e2bb263eca4ecb1046541fdb11cf8 (diff) |
xtensa: add support for the XTFPGA boards
The Avnet LX60/LX110/LX200 board is an FPGA board that can be configured with
an Xtensa processor and an OpenCores Ethernet device.
Signed-off-by: Chris Zankel <chris@zankel.net>
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'arch/xtensa/platforms/xtfpga/setup.c')
-rw-r--r-- | arch/xtensa/platforms/xtfpga/setup.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c new file mode 100644 index 000000000000..71d61ca6a4af --- /dev/null +++ b/arch/xtensa/platforms/xtfpga/setup.c @@ -0,0 +1,269 @@ +/* + * + * arch/xtensa/platform/xtavnet/setup.c + * + * ... + * + * Authors: Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com> + * + * Copyright 2001 - 2006 Tensilica Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/of.h> + +#include <asm/timex.h> +#include <asm/processor.h> +#include <asm/platform.h> +#include <asm/bootparam.h> +#include <platform/lcd.h> + +void platform_halt(void) +{ + lcd_disp_at_pos(" HALT ", 0); + local_irq_disable(); + while (1) + cpu_relax(); +} + +void platform_power_off(void) +{ + lcd_disp_at_pos("POWEROFF", 0); + local_irq_disable(); + while (1) + cpu_relax(); +} + +void platform_restart(void) +{ + /* Flush and reset the mmu, simulate a processor reset, and + * jump to the reset vector. */ + + + __asm__ __volatile__ ("movi a2, 15\n\t" + "wsr a2, icountlevel\n\t" + "movi a2, 0\n\t" + "wsr a2, icount\n\t" + "wsr a2, ibreakenable\n\t" + "wsr a2, lcount\n\t" + "movi a2, 0x1f\n\t" + "wsr a2, ps\n\t" + "isync\n\t" + "jx %0\n\t" + : + : "a" (XCHAL_RESET_VECTOR_VADDR) + : "a2" + ); + + /* control never gets here */ +} + +void __init platform_setup(char **cmdline) +{ +} + +#ifdef CONFIG_OF + +static void __init update_clock_frequency(struct device_node *node) +{ + struct property *newfreq; + u32 freq; + + if (!of_property_read_u32(node, "clock-frequency", &freq) && + freq != 0) + return; + + newfreq = kzalloc(sizeof(*newfreq) + sizeof(u32), GFP_KERNEL); + if (!newfreq) + return; + newfreq->value = newfreq + 1; + newfreq->length = sizeof(freq); + newfreq->name = kstrdup("clock-frequency", GFP_KERNEL); + if (!newfreq->name) { + kfree(newfreq); + return; + } + + *(u32 *)newfreq->value = cpu_to_be32(*(u32 *)XTFPGA_CLKFRQ_VADDR); + prom_update_property(node, newfreq); +} + +static int __init machine_setup(void) +{ + struct device_node *serial = NULL; + + while ((serial = of_find_compatible_node(serial, NULL, "ns16550a"))) + update_clock_frequency(serial); + return 0; +} +arch_initcall(machine_setup); + +#endif + +/* early initialization */ + +void __init platform_init(bp_tag_t *first) +{ +} + +/* Heartbeat. */ + +void platform_heartbeat(void) +{ +} + +#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT + +void platform_calibrate_ccount(void) +{ + long clk_freq = 0; +#ifdef CONFIG_OF + struct device_node *cpu = + of_find_compatible_node(NULL, NULL, "xtensa,cpu"); + if (cpu) { + u32 freq; + update_clock_frequency(cpu); + if (!of_property_read_u32(cpu, "clock-frequency", &freq)) + clk_freq = freq; + } +#endif + if (!clk_freq) + clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR; + + ccount_per_jiffy = clk_freq / HZ; + nsec_per_ccount = 1000000000UL / clk_freq; +} + +#endif + +#ifndef CONFIG_OF + +#include <linux/serial_8250.h> +#include <linux/if.h> +#include <net/ethoc.h> + +/*---------------------------------------------------------------------------- + * Ethernet -- OpenCores Ethernet MAC (ethoc driver) + */ + +static struct resource ethoc_res[] __initdata = { + [0] = { /* register space */ + .start = OETH_REGS_PADDR, + .end = OETH_REGS_PADDR + OETH_REGS_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { /* buffer space */ + .start = OETH_SRAMBUFF_PADDR, + .end = OETH_SRAMBUFF_PADDR + OETH_SRAMBUFF_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { /* IRQ number */ + .start = OETH_IRQ, + .end = OETH_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct ethoc_platform_data ethoc_pdata __initdata = { + /* + * The MAC address for these boards is 00:50:c2:13:6f:xx. + * The last byte (here as zero) is read from the DIP switches on the + * board. + */ + .hwaddr = { 0x00, 0x50, 0xc2, 0x13, 0x6f, 0 }, + .phy_id = -1, +}; + +static struct platform_device ethoc_device __initdata = { + .name = "ethoc", + .id = -1, + .num_resources = ARRAY_SIZE(ethoc_res), + .resource = ethoc_res, + .dev = { + .platform_data = ðoc_pdata, + }, +}; + +/*---------------------------------------------------------------------------- + * UART + */ + +static struct resource serial_resource __initdata = { + .start = DUART16552_PADDR, + .end = DUART16552_PADDR + 0x1f, + .flags = IORESOURCE_MEM, +}; + +static struct plat_serial8250_port serial_platform_data[] __initdata = { + [0] = { + .mapbase = DUART16552_PADDR, + .irq = DUART16552_INTNUM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM32, + .regshift = 2, + .uartclk = 0, /* set in xtavnet_init() */ + }, + { }, +}; + +static struct platform_device xtavnet_uart __initdata = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_platform_data, + }, + .num_resources = 1, + .resource = &serial_resource, +}; + +/* platform devices */ +static struct platform_device *platform_devices[] __initdata = { + ðoc_device, + &xtavnet_uart, +}; + + +static int __init xtavnet_init(void) +{ + /* Ethernet MAC address. */ + ethoc_pdata.hwaddr[5] = *(u32 *)DIP_SWITCHES_VADDR; + + /* Clock rate varies among FPGA bitstreams; board specific FPGA register + * reports the actual clock rate. + */ + serial_platform_data[0].uartclk = *(long *)XTFPGA_CLKFRQ_VADDR; + + + /* register platform devices */ + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + + /* ETHOC driver is a bit quiet; at least display Ethernet MAC, so user + * knows whether they set it correctly on the DIP switches. + */ + pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr); + + return 0; +} + +/* + * Register to be done during do_initcalls(). + */ +arch_initcall(xtavnet_init); + +#endif /* CONFIG_OF */ |