Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Max Filippov and committed by
Chris Zankel
0d456bad da844a81

+472
+9
arch/xtensa/Kconfig
··· 151 151 select SERIAL_CONSOLE 152 152 select NO_IOPORT 153 153 154 + config XTENSA_PLATFORM_XTFPGA 155 + bool "XTFPGA" 156 + select SERIAL_CONSOLE 157 + select ETHOC 158 + select XTENSA_CALIBRATE_CCOUNT 159 + help 160 + XTFPGA is the name of Tensilica board family (LX60, LX110, LX200, ML605). 161 + This hardware is capable of running a full Linux distribution. 162 + 154 163 endchoice 155 164 156 165
+1
arch/xtensa/Makefile
··· 38 38 platform-$(CONFIG_XTENSA_PLATFORM_XT2000) := xt2000 39 39 platform-$(CONFIG_XTENSA_PLATFORM_ISS) := iss 40 40 platform-$(CONFIG_XTENSA_PLATFORM_S6105) := s6105 41 + platform-$(CONFIG_XTENSA_PLATFORM_XTFPGA) := xtfpga 41 42 42 43 PLATFORM = $(platform-y) 43 44 export PLATFORM
+1
arch/xtensa/boot/Makefile
··· 23 23 24 24 bootdir-$(CONFIG_XTENSA_PLATFORM_ISS) += boot-elf 25 25 bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf boot-uboot 26 + bootdir-$(CONFIG_XTENSA_PLATFORM_XTFPGA) += boot-redboot boot-elf boot-uboot 26 27 27 28 28 29 BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB)).dtb.o
+9
arch/xtensa/platforms/xtfpga/Makefile
··· 1 + # Makefile for the Tensilica xtavnet Emulation Board 2 + # 3 + # Note! Dependencies are done automagically by 'make dep', which also 4 + # removes any old dependencies. DON'T put your own dependencies here 5 + # unless it's something special (ie not a .c file). 6 + # 7 + # Note 2! The CFLAGS definitions are in the main makefile... 8 + 9 + obj-y = setup.o lcd.o
+69
arch/xtensa/platforms/xtfpga/include/platform/hardware.h
··· 1 + /* 2 + * arch/xtensa/platform/xtavnet/include/platform/hardware.h 3 + * 4 + * This file is subject to the terms and conditions of the GNU General Public 5 + * License. See the file "COPYING" in the main directory of this archive 6 + * for more details. 7 + * 8 + * Copyright (C) 2006 Tensilica Inc. 9 + */ 10 + 11 + /* 12 + * This file contains the hardware configuration of the XTAVNET boards. 13 + */ 14 + 15 + #ifndef __XTENSA_XTAVNET_HARDWARE_H 16 + #define __XTENSA_XTAVNET_HARDWARE_H 17 + 18 + /* By default NO_IRQ is defined to 0 in Linux, but we use the 19 + interrupt 0 for UART... */ 20 + #define NO_IRQ -1 21 + 22 + /* Memory configuration. */ 23 + 24 + #define PLATFORM_DEFAULT_MEM_START 0x00000000 25 + #define PLATFORM_DEFAULT_MEM_SIZE 0x04000000 26 + 27 + /* Interrupt configuration. */ 28 + 29 + #define PLATFORM_NR_IRQS 10 30 + 31 + /* Default assignment of LX60 devices to external interrupts. */ 32 + 33 + #ifdef CONFIG_ARCH_HAS_SMP 34 + #define DUART16552_INTNUM XCHAL_EXTINT3_NUM 35 + #define OETH_IRQ XCHAL_EXTINT4_NUM 36 + #else 37 + #define DUART16552_INTNUM XCHAL_EXTINT0_NUM 38 + #define OETH_IRQ XCHAL_EXTINT1_NUM 39 + #endif 40 + 41 + /* 42 + * Device addresses and parameters. 43 + */ 44 + 45 + /* UART */ 46 + #define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020) 47 + /* LCD instruction and data addresses. */ 48 + #define LCD_INSTR_ADDR ((char *)IOADDR(0x0D040000)) 49 + #define LCD_DATA_ADDR ((char *)IOADDR(0x0D040004)) 50 + 51 + /* Misc. */ 52 + #define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000) 53 + /* Clock frequency in Hz (read-only): */ 54 + #define XTFPGA_CLKFRQ_VADDR (XTFPGA_FPGAREGS_VADDR + 0x04) 55 + /* Setting of 8 DIP switches: */ 56 + #define DIP_SWITCHES_VADDR (XTFPGA_FPGAREGS_VADDR + 0x0C) 57 + /* Software reset (write 0xdead): */ 58 + #define XTFPGA_SWRST_VADDR (XTFPGA_FPGAREGS_VADDR + 0x10) 59 + 60 + /* OpenCores Ethernet controller: */ 61 + /* regs + RX/TX descriptors */ 62 + #define OETH_REGS_PADDR (XCHAL_KIO_PADDR + 0x0D030000) 63 + #define OETH_REGS_SIZE 0x1000 64 + #define OETH_SRAMBUFF_PADDR (XCHAL_KIO_PADDR + 0x0D800000) 65 + 66 + /* 5*rx buffs + 5*tx buffs */ 67 + #define OETH_SRAMBUFF_SIZE (5 * 0x600 + 5 * 0x600) 68 + 69 + #endif /* __XTENSA_XTAVNET_HARDWARE_H */
+20
arch/xtensa/platforms/xtfpga/include/platform/lcd.h
··· 1 + /* 2 + * arch/xtensa/platform/xtavnet/include/platform/lcd.h 3 + * 4 + * This file is subject to the terms and conditions of the GNU General Public 5 + * License. See the file "COPYING" in the main directory of this archive 6 + * for more details. 7 + * 8 + * Copyright (C) 2001, 2006 Tensilica Inc. 9 + */ 10 + 11 + #ifndef __XTENSA_XTAVNET_LCD_H 12 + #define __XTENSA_XTAVNET_LCD_H 13 + 14 + /* Display string STR at position POS on the LCD. */ 15 + void lcd_disp_at_pos(char *str, unsigned char pos); 16 + 17 + /* Shift the contents of the LCD display left or right. */ 18 + void lcd_shiftleft(void); 19 + void lcd_shiftright(void); 20 + #endif
+18
arch/xtensa/platforms/xtfpga/include/platform/serial.h
··· 1 + /* 2 + * arch/xtensa/platform/xtavnet/include/platform/serial.h 3 + * 4 + * This file is subject to the terms and conditions of the GNU General Public 5 + * License. See the file "COPYING" in the main directory of this archive 6 + * for more details. 7 + * 8 + * Copyright (C) 2001, 2006 Tensilica Inc. 9 + */ 10 + 11 + #ifndef __ASM_XTENSA_XTAVNET_SERIAL_H 12 + #define __ASM_XTENSA_XTAVNET_SERIAL_H 13 + 14 + #include <platform/hardware.h> 15 + 16 + #define BASE_BAUD (*(long *)XTFPGA_CLKFRQ_VADDR / 16) 17 + 18 + #endif /* __ASM_XTENSA_XTAVNET_SERIAL_H */
+76
arch/xtensa/platforms/xtfpga/lcd.c
··· 1 + /* 2 + * Driver for the LCD display on the Tensilica LX60 Board. 3 + * 4 + * This file is subject to the terms and conditions of the GNU General Public 5 + * License. See the file "COPYING" in the main directory of this archive 6 + * for more details. 7 + * 8 + * Copyright (C) 2001, 2006 Tensilica Inc. 9 + */ 10 + 11 + /* 12 + * 13 + * FIXME: this code is from the examples from the LX60 user guide. 14 + * 15 + * The lcd_pause function does busy waiting, which is probably not 16 + * great. Maybe the code could be changed to use kernel timers, or 17 + * change the hardware to not need to wait. 18 + */ 19 + 20 + #include <linux/init.h> 21 + #include <linux/io.h> 22 + 23 + #include <platform/hardware.h> 24 + #include <platform/lcd.h> 25 + #include <linux/delay.h> 26 + 27 + #define LCD_PAUSE_ITERATIONS 4000 28 + #define LCD_CLEAR 0x1 29 + #define LCD_DISPLAY_ON 0xc 30 + 31 + /* 8bit and 2 lines display */ 32 + #define LCD_DISPLAY_MODE8BIT 0x38 33 + #define LCD_DISPLAY_POS 0x80 34 + #define LCD_SHIFT_LEFT 0x18 35 + #define LCD_SHIFT_RIGHT 0x1c 36 + 37 + static int __init lcd_init(void) 38 + { 39 + *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; 40 + mdelay(5); 41 + *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; 42 + udelay(200); 43 + *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; 44 + udelay(50); 45 + *LCD_INSTR_ADDR = LCD_DISPLAY_ON; 46 + udelay(50); 47 + *LCD_INSTR_ADDR = LCD_CLEAR; 48 + mdelay(10); 49 + lcd_disp_at_pos("XTENSA LINUX", 0); 50 + return 0; 51 + } 52 + 53 + void lcd_disp_at_pos(char *str, unsigned char pos) 54 + { 55 + *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos; 56 + udelay(100); 57 + while (*str != 0) { 58 + *LCD_DATA_ADDR = *str; 59 + udelay(200); 60 + str++; 61 + } 62 + } 63 + 64 + void lcd_shiftleft(void) 65 + { 66 + *LCD_INSTR_ADDR = LCD_SHIFT_LEFT; 67 + udelay(50); 68 + } 69 + 70 + void lcd_shiftright(void) 71 + { 72 + *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT; 73 + udelay(50); 74 + } 75 + 76 + arch_initcall(lcd_init);
+269
arch/xtensa/platforms/xtfpga/setup.c
··· 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 + 36 + void platform_halt(void) 37 + { 38 + lcd_disp_at_pos(" HALT ", 0); 39 + local_irq_disable(); 40 + while (1) 41 + cpu_relax(); 42 + } 43 + 44 + void platform_power_off(void) 45 + { 46 + lcd_disp_at_pos("POWEROFF", 0); 47 + local_irq_disable(); 48 + while (1) 49 + cpu_relax(); 50 + } 51 + 52 + void platform_restart(void) 53 + { 54 + /* Flush and reset the mmu, simulate a processor reset, and 55 + * jump to the reset vector. */ 56 + 57 + 58 + __asm__ __volatile__ ("movi a2, 15\n\t" 59 + "wsr a2, icountlevel\n\t" 60 + "movi a2, 0\n\t" 61 + "wsr a2, icount\n\t" 62 + "wsr a2, ibreakenable\n\t" 63 + "wsr a2, lcount\n\t" 64 + "movi a2, 0x1f\n\t" 65 + "wsr a2, ps\n\t" 66 + "isync\n\t" 67 + "jx %0\n\t" 68 + : 69 + : "a" (XCHAL_RESET_VECTOR_VADDR) 70 + : "a2" 71 + ); 72 + 73 + /* control never gets here */ 74 + } 75 + 76 + void __init platform_setup(char **cmdline) 77 + { 78 + } 79 + 80 + #ifdef CONFIG_OF 81 + 82 + static void __init update_clock_frequency(struct device_node *node) 83 + { 84 + struct property *newfreq; 85 + u32 freq; 86 + 87 + if (!of_property_read_u32(node, "clock-frequency", &freq) && 88 + freq != 0) 89 + return; 90 + 91 + newfreq = kzalloc(sizeof(*newfreq) + sizeof(u32), GFP_KERNEL); 92 + if (!newfreq) 93 + return; 94 + newfreq->value = newfreq + 1; 95 + newfreq->length = sizeof(freq); 96 + newfreq->name = kstrdup("clock-frequency", GFP_KERNEL); 97 + if (!newfreq->name) { 98 + kfree(newfreq); 99 + return; 100 + } 101 + 102 + *(u32 *)newfreq->value = cpu_to_be32(*(u32 *)XTFPGA_CLKFRQ_VADDR); 103 + prom_update_property(node, newfreq); 104 + } 105 + 106 + static int __init machine_setup(void) 107 + { 108 + struct device_node *serial = NULL; 109 + 110 + while ((serial = of_find_compatible_node(serial, NULL, "ns16550a"))) 111 + update_clock_frequency(serial); 112 + return 0; 113 + } 114 + arch_initcall(machine_setup); 115 + 116 + #endif 117 + 118 + /* early initialization */ 119 + 120 + void __init platform_init(bp_tag_t *first) 121 + { 122 + } 123 + 124 + /* Heartbeat. */ 125 + 126 + void platform_heartbeat(void) 127 + { 128 + } 129 + 130 + #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT 131 + 132 + void platform_calibrate_ccount(void) 133 + { 134 + long clk_freq = 0; 135 + #ifdef CONFIG_OF 136 + struct device_node *cpu = 137 + of_find_compatible_node(NULL, NULL, "xtensa,cpu"); 138 + if (cpu) { 139 + u32 freq; 140 + update_clock_frequency(cpu); 141 + if (!of_property_read_u32(cpu, "clock-frequency", &freq)) 142 + clk_freq = freq; 143 + } 144 + #endif 145 + if (!clk_freq) 146 + clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR; 147 + 148 + ccount_per_jiffy = clk_freq / HZ; 149 + nsec_per_ccount = 1000000000UL / clk_freq; 150 + } 151 + 152 + #endif 153 + 154 + #ifndef CONFIG_OF 155 + 156 + #include <linux/serial_8250.h> 157 + #include <linux/if.h> 158 + #include <net/ethoc.h> 159 + 160 + /*---------------------------------------------------------------------------- 161 + * Ethernet -- OpenCores Ethernet MAC (ethoc driver) 162 + */ 163 + 164 + static struct resource ethoc_res[] __initdata = { 165 + [0] = { /* register space */ 166 + .start = OETH_REGS_PADDR, 167 + .end = OETH_REGS_PADDR + OETH_REGS_SIZE - 1, 168 + .flags = IORESOURCE_MEM, 169 + }, 170 + [1] = { /* buffer space */ 171 + .start = OETH_SRAMBUFF_PADDR, 172 + .end = OETH_SRAMBUFF_PADDR + OETH_SRAMBUFF_SIZE - 1, 173 + .flags = IORESOURCE_MEM, 174 + }, 175 + [2] = { /* IRQ number */ 176 + .start = OETH_IRQ, 177 + .end = OETH_IRQ, 178 + .flags = IORESOURCE_IRQ, 179 + }, 180 + }; 181 + 182 + static struct ethoc_platform_data ethoc_pdata __initdata = { 183 + /* 184 + * The MAC address for these boards is 00:50:c2:13:6f:xx. 185 + * The last byte (here as zero) is read from the DIP switches on the 186 + * board. 187 + */ 188 + .hwaddr = { 0x00, 0x50, 0xc2, 0x13, 0x6f, 0 }, 189 + .phy_id = -1, 190 + }; 191 + 192 + static struct platform_device ethoc_device __initdata = { 193 + .name = "ethoc", 194 + .id = -1, 195 + .num_resources = ARRAY_SIZE(ethoc_res), 196 + .resource = ethoc_res, 197 + .dev = { 198 + .platform_data = &ethoc_pdata, 199 + }, 200 + }; 201 + 202 + /*---------------------------------------------------------------------------- 203 + * UART 204 + */ 205 + 206 + static struct resource serial_resource __initdata = { 207 + .start = DUART16552_PADDR, 208 + .end = DUART16552_PADDR + 0x1f, 209 + .flags = IORESOURCE_MEM, 210 + }; 211 + 212 + static struct plat_serial8250_port serial_platform_data[] __initdata = { 213 + [0] = { 214 + .mapbase = DUART16552_PADDR, 215 + .irq = DUART16552_INTNUM, 216 + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | 217 + UPF_IOREMAP, 218 + .iotype = UPIO_MEM32, 219 + .regshift = 2, 220 + .uartclk = 0, /* set in xtavnet_init() */ 221 + }, 222 + { }, 223 + }; 224 + 225 + static struct platform_device xtavnet_uart __initdata = { 226 + .name = "serial8250", 227 + .id = PLAT8250_DEV_PLATFORM, 228 + .dev = { 229 + .platform_data = serial_platform_data, 230 + }, 231 + .num_resources = 1, 232 + .resource = &serial_resource, 233 + }; 234 + 235 + /* platform devices */ 236 + static struct platform_device *platform_devices[] __initdata = { 237 + &ethoc_device, 238 + &xtavnet_uart, 239 + }; 240 + 241 + 242 + static int __init xtavnet_init(void) 243 + { 244 + /* Ethernet MAC address. */ 245 + ethoc_pdata.hwaddr[5] = *(u32 *)DIP_SWITCHES_VADDR; 246 + 247 + /* Clock rate varies among FPGA bitstreams; board specific FPGA register 248 + * reports the actual clock rate. 249 + */ 250 + serial_platform_data[0].uartclk = *(long *)XTFPGA_CLKFRQ_VADDR; 251 + 252 + 253 + /* register platform devices */ 254 + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); 255 + 256 + /* ETHOC driver is a bit quiet; at least display Ethernet MAC, so user 257 + * knows whether they set it correctly on the DIP switches. 258 + */ 259 + pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr); 260 + 261 + return 0; 262 + } 263 + 264 + /* 265 + * Register to be done during do_initcalls(). 266 + */ 267 + arch_initcall(xtavnet_init); 268 + 269 + #endif /* CONFIG_OF */