diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ac6aff4..975b525 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -46,6 +46,18 @@ select CPU_ARM920T select GENERIC_GPIO +config ARCH_HIGHBANK + bool "Calxeda Highbank" + select HAS_DEBUG_LL + select HAS_POWEROFF + select ARCH_HAS_L2X0 + select CPU_V7 + select ARM_AMBA + select AMBA_SP804 + select CLKDEV_LOOKUP + select COMMON_CLK + select GPIOLIB + config ARCH_IMX bool "Freescale iMX-based" select GENERIC_GPIO @@ -114,6 +126,7 @@ source arch/arm/mach-bcm2835/Kconfig source arch/arm/mach-clps711x/Kconfig source arch/arm/mach-ep93xx/Kconfig +source arch/arm/mach-highbank/Kconfig source arch/arm/mach-imx/Kconfig source arch/arm/mach-mxs/Kconfig source arch/arm/mach-netx/Kconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index fcb2969..decab1a 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -55,6 +55,7 @@ machine-$(CONFIG_ARCH_BCM2835) := bcm2835 machine-$(CONFIG_ARCH_CLPS711X) := clps711x machine-$(CONFIG_ARCH_EP93XX) := ep93xx +machine-$(CONFIG_ARCH_HIGHBANK) := highbank machine-$(CONFIG_ARCH_IMX) := imx machine-$(CONFIG_ARCH_MXS) := mxs machine-$(CONFIG_ARCH_NOMADIK) := nomadik @@ -98,6 +99,7 @@ board-$(CONFIG_MACH_FREESCALE_MX25_3STACK) := freescale-mx25-3-stack board-$(CONFIG_MACH_FREESCALE_MX35_3STACK) := freescale-mx35-3-stack board-$(CONFIG_MACH_GE863) := telit-evk-pro3 +board-$(CONFIG_MACH_HIGHBANK) := highbank board-$(CONFIG_MACH_IMX21ADS) := imx21ads board-$(CONFIG_MACH_IMX27ADS) := imx27ads board-$(CONFIG_MACH_IMX233_OLINUXINO) := imx233-olinuxino diff --git a/arch/arm/boards/highbank/Makefile b/arch/arm/boards/highbank/Makefile new file mode 100644 index 0000000..98921a4 --- /dev/null +++ b/arch/arm/boards/highbank/Makefile @@ -0,0 +1,4 @@ +obj-y += init.o + +obj-y += lowlevel.o +pbl-y += lowlevel.o diff --git a/arch/arm/boards/highbank/config.h b/arch/arm/boards/highbank/config.h new file mode 100644 index 0000000..25bb18f --- /dev/null +++ b/arch/arm/boards/highbank/config.h @@ -0,0 +1,5 @@ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/highbank/env/bin/init_board b/arch/arm/boards/highbank/env/bin/init_board new file mode 100644 index 0000000..610db15 --- /dev/null +++ b/arch/arm/boards/highbank/env/bin/init_board @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -e /dev/dtb ] +then + oftree -l /dev/dtb + oftree -p +fi diff --git a/arch/arm/boards/highbank/env/config b/arch/arm/boards/highbank/env/config new file mode 100644 index 0000000..1bb2c49 --- /dev/null +++ b/arch/arm/boards/highbank/env/config @@ -0,0 +1,33 @@ +#!/bin/sh + +# use 'dhcp' to do dhcp in barebox and in kernel +# use 'none' if you want to skip kernel ip autoconfiguration +ip=dhcp +global.dhcp.vendor_id=barebox-highbank + +# or set your networking parameters here +#eth0.ipaddr=a.b.c.d +#eth0.netmask=a.b.c.d +#eth0.gateway=a.b.c.d +#eth0.serverip=a.b.c.d + +# can be either 'nfs', 'tftp' or 'nor' +kernel_loc=tftp +# can be either 'net', 'nor' or 'initrd' +rootfs_loc=initrd + +# can be either 'jffs2' or 'ubifs' +rootfs_type=ubifs +rootfsimage=root.$rootfs_type + +kernelimage=zImage +#kernelimage=uImage +#kernelimage=Image +#kernelimage=Image.lzo + +autoboot_timeout=3 + +bootargs="console=ttyAMA0,115200n8 CONSOLE=/dev/ttyAMA0" + +# set a fancy prompt (if support is compiled in) +PS1="\e[1;31m[barebox@\h]:\w\e[0m\n# " diff --git a/arch/arm/boards/highbank/init.c b/arch/arm/boards/highbank/init.c new file mode 100644 index 0000000..e36674f --- /dev/null +++ b/arch/arm/boards/highbank/init.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 only + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FIRMWARE_DTB_BASE 0x1000 + +#define HB_OPP_VERSION 0 + +struct fdt_header *fdt = NULL; + +static int hb_fixup(struct fdt_header *fdt) +{ + u32 reg = readl(sregs_base + HB_SREG_A9_PWRDOM_DATA); + u32 *opp_table = (u32 *)HB_SYSRAM_OPP_TABLE_BASE; + u32 dtb_table[2*10]; + u32 i; + u32 num_opps; + __be32 latency; + + if (!(reg & HB_PWRDOM_STAT_SATA)) + do_fixup_by_compatible_string(fdt, "calxeda,hb-ahci", "status", + "disabled", 1); + + if (!(reg & HB_PWRDOM_STAT_EMMC)) + do_fixup_by_compatible_string(fdt, "calxeda,hb-sdhci", "status", + "disabled", 1); + + if ((opp_table[0] >> 16) != HB_OPP_VERSION) + return 0; + + num_opps = opp_table[0] & 0xff; + + for (i = 0; i < num_opps; i++) { + dtb_table[2 * i] = cpu_to_be32(opp_table[3 + 3 * i]); + dtb_table[2 * i + 1] = cpu_to_be32(opp_table[2 + 3 * i]); + } + + latency = cpu_to_be32(opp_table[1]); + + fdt_find_and_setprop(fdt, "/cpus/cpu@0", "transition-latency", + &latency, 4, 1); + fdt_find_and_setprop(fdt, "/cpus/cpu@0", "operating-points", + dtb_table, 8 * num_opps, 1); + + return 0; +} + +static int highbank_mem_init(void) +{ + struct device_node *np; + int ret; + + /* load by the firmware at 0x1000 */ + fdt = IOMEM(FIRMWARE_DTB_BASE); + + ret = of_unflatten_dtb(fdt); + if (ret) { + pr_warn("no dtb found at 0x1000 use default configuration\n"); + fdt = NULL; + goto not_found; + } + + np = of_find_node_by_path("/memory"); + if (!np) { + pr_warn("no memory node use default configuration\n"); + goto not_found; + } + + ret = of_add_memory(np, true); + if (ret) { + pr_warn("memory node: probe failed use default configuration\n"); + goto not_found; + } + + pr_info("highbank: dtb probed memory size\n"); + + return 0; +not_found: + highbank_add_ddram(4089 << 20); + return 0; +} +mem_initcall(highbank_mem_init); + +static int highbank_devices_init(void) +{ + of_register_fixup(hb_fixup); + if (!fdt) { + highbank_register_gpio(0); + highbank_register_gpio(1); + highbank_register_gpio(2); + highbank_register_gpio(3); + highbank_register_ahci(); + highbank_register_xgmac(0); + highbank_register_xgmac(1); + } else { + fdt = of_get_fixed_tree(fdt); + add_mem_device("dtb", (unsigned long)fdt, fdt_totalsize(fdt), + IORESOURCE_MEM_WRITEABLE); + devfs_add_partition("ram0", FIRMWARE_DTB_BASE, SZ_64K, DEVFS_PARTITION_FIXED, "firmware-dtb"); + } + + armlinux_set_bootparams((void *)(0x00000100)); + + devfs_add_partition("nvram", 0x00000, SZ_16K, DEVFS_PARTITION_FIXED, "env0"); + + return 0; +} +device_initcall(highbank_devices_init); + +static int highbank_console_init(void) +{ + highbank_register_uart(); + + return 0; +} +console_initcall(highbank_console_init); diff --git a/arch/arm/boards/highbank/lowlevel.c b/arch/arm/boards/highbank/lowlevel.c new file mode 100644 index 0000000..b862a1f --- /dev/null +++ b/arch/arm/boards/highbank/lowlevel.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 only + */ + +#include +#include +#include +#include +#include + +void __naked barebox_arm_reset_vector(void) +{ + arm_cpu_lowlevel_init(); + barebox_arm_entry(0x00000000, SZ_512M, 0); +} diff --git a/arch/arm/configs/highbank_defconfig b/arch/arm/configs/highbank_defconfig new file mode 100644 index 0000000..b034ed1 --- /dev/null +++ b/arch/arm/configs/highbank_defconfig @@ -0,0 +1,62 @@ +CONFIG_ARCH_HIGHBANK=y +CONFIG_AEABI=y +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_PBL_IMAGE=y +CONFIG_MMU=y +CONFIG_MALLOC_SIZE=0xa00000 +CONFIG_MALLOC_TLSF=y +CONFIG_PROMPT="vexpress: " +CONFIG_LONGHELP=y +CONFIG_GLOB=y +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_MENU=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/highbank/env" +CONFIG_CMD_EDIT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_MENU=y +CONFIG_CMD_MENU_MANAGEMENT=y +CONFIG_CMD_PASSWD=y +CONFIG_CMD_TFTP=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_LOADB=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTU is not set +CONFIG_CMD_RESET=y +CONFIG_CMD_POWEROFF=y +CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y +CONFIG_CMD_OFTREE_PROBE=y +CONFIG_CMD_MTEST=y +CONFIG_CMD_MTEST_ALTERNATIVE=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_UNCOMPRESS=y +CONFIG_CMD_CLK=y +CONFIG_NET=y +CONFIG_NET_DHCP=y +CONFIG_NET_NFS=y +CONFIG_NET_PING=y +CONFIG_NET_NETCONSOLE=y +CONFIG_NET_RESOLV=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_DRIVER_NET_CALXEDA_XGMAC=y +# CONFIG_SPI is not set +CONFIG_DISK=y +CONFIG_DISK_AHCI=y +CONFIG_GPIO_PL061=y +CONFIG_FS_TFTP=y +CONFIG_SHA1=y +CONFIG_SHA256=y diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig new file mode 100644 index 0000000..47c6405 --- /dev/null +++ b/arch/arm/mach-highbank/Kconfig @@ -0,0 +1,18 @@ +if ARCH_HIGHBANK + +config ARCH_TEXT_BASE + hex + default 0x03f00000 + +config BOARDINFO + default "Calxeda Highbank" if MACH_HIGHBANK + +choice + prompt "Calxeda Board type" + +config MACH_HIGHBANK + bool "Calxeda Highbank" + +endchoice + +endif diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile new file mode 100644 index 0000000..6a7330f --- /dev/null +++ b/arch/arm/mach-highbank/Makefile @@ -0,0 +1,4 @@ +obj-y += core.o +obj-y += devices.o +obj-y += reset.o +obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o smc.o diff --git a/arch/arm/mach-highbank/cache-l2x0.c b/arch/arm/mach-highbank/cache-l2x0.c new file mode 100644 index 0000000..f1e39dc --- /dev/null +++ b/arch/arm/mach-highbank/cache-l2x0.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * 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; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include + +#include +#include + +#include "core.h" + +static void highbank_l2x0_disable(void) +{ + /* Disable PL310 L2 Cache controller */ + highbank_smc1(0x102, 0x0); +} + +static int highbank_l2x0_init(void) +{ + /* Enable PL310 L2 Cache controller */ + highbank_smc1(0x102, 0x1); + l2x0_init(IOMEM(0xfff12000), 0, ~0UL); + outer_cache.disable = highbank_l2x0_disable; + + return 0; +} +postmmu_initcall(highbank_l2x0_init); diff --git a/arch/arm/mach-highbank/core.c b/arch/arm/mach-highbank/core.c new file mode 100644 index 0000000..967d13f --- /dev/null +++ b/arch/arm/mach-highbank/core.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 only + */ + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +void __iomem *sregs_base = IOMEM(HB_SREG_A9_BASE); + +static void highbank_clk_init(void) +{ + struct clk *clk; + + clk = clk_fixed("dummy_apb_pclk", 0); + clk_register_clkdev(clk, "apb_pclk", NULL); + + clk = clk_fixed("pclk", 150000000); + clk_register_clkdev(clk, NULL, "sp804"); + clk_register_clkdev(clk, NULL, "uart-pl011"); +} + +static void highbank_sp804_init(void) +{ + amba_apb_device_add(NULL, "sp804", DEVICE_ID_SINGLE, 0xfff34000, 4096, NULL, 0); +} + +static int highbank_init(void) +{ + highbank_clk_init(); + highbank_sp804_init(); + + return 0; +} +postcore_initcall(highbank_init); diff --git a/arch/arm/mach-highbank/core.h b/arch/arm/mach-highbank/core.h new file mode 100644 index 0000000..e3f19b2 --- /dev/null +++ b/arch/arm/mach-highbank/core.h @@ -0,0 +1,2 @@ + +extern void highbank_smc1(int fn, int arg); diff --git a/arch/arm/mach-highbank/devices.c b/arch/arm/mach-highbank/devices.c new file mode 100644 index 0000000..6d75864 --- /dev/null +++ b/arch/arm/mach-highbank/devices.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 only + */ + +#include +#include + +#include + +#include + +#include + +void highbank_add_ddram(u32 size) +{ + arm_add_mem_device("ram1", 0x00000000, size); + add_mem_device("nvram", 0xfff88000, SZ_32K, IORESOURCE_MEM_WRITEABLE); +} + +void highbank_register_uart(void) +{ + amba_apb_device_add(NULL, "uart-pl011", DEVICE_ID_SINGLE, 0xfff36000, 4096, NULL, 0); +} + +void highbank_register_ahci(void) +{ + add_generic_device("ahci", DEVICE_ID_SINGLE, NULL, 0xffe08000, + 0x10000, IORESOURCE_MEM, NULL); +} + +void highbank_register_xgmac(unsigned id) +{ + resource_size_t start; + + switch (id) { + case 0: + start = 0xfff50000; + break; + case 1: + start = 0xfff51000; + break; + default: + return; + } + + add_generic_device("hb-xgmac", id, NULL, start, 0x1000, + IORESOURCE_MEM, NULL); +} + +void highbank_register_gpio(unsigned id) +{ + resource_size_t start; + + switch (id) { + case 0: + start = 0xfff30000; + break; + case 1: + start = 0xfff31000; + break; + case 2: + start = 0xfff32000; + break; + case 3: + start = 0xfff33000; + break; + default: + return; + } + + amba_apb_device_add(NULL, "pl061_gpio", id, start, 0x1000, NULL, 0); +} diff --git a/arch/arm/mach-highbank/include/mach/clkdev.h b/arch/arm/mach-highbank/include/mach/clkdev.h new file mode 100644 index 0000000..04b37a8 --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/clkdev.h @@ -0,0 +1,7 @@ +#ifndef __ASM_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif diff --git a/arch/arm/mach-highbank/include/mach/debug_ll.h b/arch/arm/mach-highbank/include/mach/debug_ll.h new file mode 100644 index 0000000..4cdbb3c --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/debug_ll.h @@ -0,0 +1,26 @@ +/* + * Copyright 2013 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 only + */ + +#ifndef __MACH_DEBUG_LL_H__ +#define __MACH_DEBUG_LL_H__ + +#include +#include + +#define UART_BASE 0xfff36000 + +static inline void PUTC_LL(char c) +{ + /* Wait until there is space in the FIFO */ + while (readl(UART_BASE + UART01x_FR) & UART01x_FR_TXFF); + + /* Send the character */ + writel(c, UART_BASE + UART01x_DR); + + /* Wait to make sure it hits the line, in case we die too soon. */ + while (readl(UART_BASE + UART01x_FR) & UART01x_FR_TXFF); +} +#endif diff --git a/arch/arm/mach-highbank/include/mach/devices.h b/arch/arm/mach-highbank/include/mach/devices.h new file mode 100644 index 0000000..2cf2b61 --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/devices.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 only + */ + +#ifndef __ASM_ARCH_DEVICES_H__ +#define __ASM_ARCH_DEVICES_H__ + +void highbank_add_ddram(u32 size); + +void highbank_register_uart(void); +void highbank_register_ahci(void); +void highbank_register_xgmac(unsigned id); +void highbank_register_gpio(unsigned id); + +#endif /* __ASM_ARCH_DEVICES_H__ */ diff --git a/arch/arm/mach-highbank/include/mach/gpio.h b/arch/arm/mach-highbank/include/mach/gpio.h new file mode 100644 index 0000000..306ab4c --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/gpio.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-highbank/include/mach/hardware.h b/arch/arm/mach-highbank/include/mach/hardware.h new file mode 100644 index 0000000..db7fff2 --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/hardware.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2010-2011 Calxeda, Inc + * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 only + */ + +#ifndef __MACH_HARDWARE_H__ +#define __MACH_HARDWARE_H__ + +#define HB_SREG_A9_BASE 0xfff3c000 +#define HB_SYSRAM_OPP_TABLE_BASE 0xfff8f000 + +#endif /* __MACH_HARDWARE_H__ */ diff --git a/arch/arm/mach-highbank/include/mach/sysregs.h b/arch/arm/mach-highbank/include/mach/sysregs.h new file mode 100644 index 0000000..2f058f2 --- /dev/null +++ b/arch/arm/mach-highbank/include/mach/sysregs.h @@ -0,0 +1,57 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#ifndef _MACH_HIGHBANK__SYSREGS_H_ +#define _MACH_HIGHBANK__SYSREGS_H_ + +#include + +extern void __iomem *sregs_base; + +#define HB_SREG_A9_PWR_REQ 0xf00 +#define HB_SREG_A9_BOOT_STAT 0xf04 +#define HB_SREG_A9_BOOT_DATA 0xf08 +#define HB_SREG_A9_PWRDOM_DATA 0xf20 + +#define HB_PWRDOM_STAT_SATA 0x80000000 +#define HB_PWRDOM_STAT_PCI 0x40000000 +#define HB_PWRDOM_STAT_EMMC 0x20000000 + +#define HB_PWR_SUSPEND 0 +#define HB_PWR_SOFT_RESET 1 +#define HB_PWR_HARD_RESET 2 +#define HB_PWR_SHUTDOWN 3 + +static inline void hingbank_set_pwr_suspend(void) +{ + writel(HB_PWR_SUSPEND, sregs_base + HB_SREG_A9_PWR_REQ); +} + +static inline void hingbank_set_pwr_shutdown(void) +{ + writel(HB_PWR_SHUTDOWN, sregs_base + HB_SREG_A9_PWR_REQ); +} + +static inline void hingbank_set_pwr_soft_reset(void) +{ + writel(HB_PWR_SOFT_RESET, sregs_base + HB_SREG_A9_PWR_REQ); +} + +static inline void hingbank_set_pwr_hard_reset(void) +{ + writel(HB_PWR_HARD_RESET, sregs_base + HB_SREG_A9_PWR_REQ); +} + +#endif diff --git a/arch/arm/mach-highbank/reset.c b/arch/arm/mach-highbank/reset.c new file mode 100644 index 0000000..b9664e4 --- /dev/null +++ b/arch/arm/mach-highbank/reset.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 only + */ + +#include +#include + +#include +#include + +void __noreturn reset_cpu(ulong addr) +{ + hingbank_set_pwr_hard_reset(); + asm(" wfi"); + + while(1); +} + +void __noreturn poweroff() +{ + shutdown_barebox(); + + hingbank_set_pwr_shutdown(); + asm(" wfi"); + + while(1); +} diff --git a/arch/arm/mach-highbank/smc.S b/arch/arm/mach-highbank/smc.S new file mode 100644 index 0000000..b2118b4 --- /dev/null +++ b/arch/arm/mach-highbank/smc.S @@ -0,0 +1,27 @@ +/* + * Copied from omap44xx-smc.S Copyright (C) 2010 Texas Instruments, Inc. + * Copyright 2012 Calxeda, Inc. + * + * This program is free software,you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +/* + * This is common routine to manage secure monitor API + * used to modify the PL310 secure registers. + * 'r0' contains the value to be modified and 'r12' contains + * the monitor API number. + * Function signature : void highbank_smc1(u32 fn, u32 arg) + */ + +ENTRY(highbank_smc1) + stmfd sp!, {r4-r11, lr} + mov r12, r0 + mov r0, r1 + dsb + smc #0 + ldmfd sp!, {r4-r11, pc} +ENDPROC(highbank_smc1) diff --git a/common/oftree.c b/common/oftree.c index 6b20cdb..82e5ddd 100644 --- a/common/oftree.c +++ b/common/oftree.c @@ -229,6 +229,33 @@ do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create); } +void do_fixup_by_compatible(struct fdt_header *fdt, const char *compatible, + const char *prop, const void *val, int len, int create) +{ + int off = -1; + + off = fdt_node_offset_by_compatible(fdt, -1, compatible); + while (off != -FDT_ERR_NOTFOUND) { + if (create || (fdt_get_property(fdt, off, prop, 0) != NULL)) + fdt_setprop(fdt, off, prop, val, len); + off = fdt_node_offset_by_compatible(fdt, off, compatible); + } +} + +void do_fixup_by_compatible_u32(struct fdt_header *fdt, const char *compatible, + const char *prop, u32 val, int create) +{ + val = cpu_to_fdt32(val); + do_fixup_by_compatible(fdt, compatible, prop, &val, 4, create); +} + +void do_fixup_by_compatible_string(struct fdt_header *fdt, const char *compatible, + const char *prop, const char *val, int create) +{ + do_fixup_by_compatible(fdt, compatible, prop, val, strlen(val) + 1, + create); +} + int fdt_get_path_or_create(struct fdt_header *fdt, const char *path) { int nodeoffset; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index cf6ceee..bcf245d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -27,6 +27,9 @@ source "drivers/net/phy/Kconfig" +config DRIVER_NET_CALXEDA_XGMAC + bool "Calxeda xgmac" + config DRIVER_NET_CS8900 bool "cs8900 ethernet driver" depends on HAS_CS8900 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6e1aeaa..42136f8 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_DRIVER_NET_CALXEDA_XGMAC) += xgmac.o obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o obj-$(CONFIG_DRIVER_NET_CPSW) += cpsw.o obj-$(CONFIG_DRIVER_NET_SMC911X) += smc911x.o diff --git a/drivers/net/xgmac.c b/drivers/net/xgmac.c new file mode 100644 index 0000000..203e682 --- /dev/null +++ b/drivers/net/xgmac.c @@ -0,0 +1,740 @@ +/* + * Copyright 2010-2011 Calxeda, 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. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TX_NUM_DESC 1 +#define RX_NUM_DESC 32 + +#define ETH_BUF_SZ 2048 +#define TX_BUF_SZ (ETH_BUF_SZ * TX_NUM_DESC) +#define RX_BUF_SZ (ETH_BUF_SZ * RX_NUM_DESC) + +/* XGMAC Register definitions */ +#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */ +#define XGMAC_FRAME_FILTER 0x00000004 /* MAC Frame Filter */ +#define XGMAC_FLOW_CTRL 0x00000018 /* MAC Flow Control */ +#define XGMAC_VLAN_TAG 0x0000001C /* VLAN Tags */ +#define XGMAC_VERSION 0x00000020 /* Version */ +#define XGMAC_VLAN_INCL 0x00000024 /* VLAN tag for tx frames */ +#define XGMAC_LPI_CTRL 0x00000028 /* LPI Control and Status */ +#define XGMAC_LPI_TIMER 0x0000002C /* LPI Timers Control */ +#define XGMAC_TX_PACE 0x00000030 /* Transmit Pace and Stretch */ +#define XGMAC_VLAN_HASH 0x00000034 /* VLAN Hash Table */ +#define XGMAC_DEBUG 0x00000038 /* Debug */ +#define XGMAC_INT_STAT 0x0000003C /* Interrupt and Control */ +#define XGMAC_ADDR_HIGH(reg) (0x00000040 + ((reg) * 8)) +#define XGMAC_ADDR_LOW(reg) (0x00000044 + ((reg) * 8)) +#define XGMAC_HASH(n) (0x00000300 + (n) * 4) /* HASH table regs */ +#define XGMAC_NUM_HASH 16 +#define XGMAC_OMR 0x00000400 +#define XGMAC_REMOTE_WAKE 0x00000700 /* Remote Wake-Up Frm Filter */ +#define XGMAC_PMT 0x00000704 /* PMT Control and Status */ +#define XGMAC_MMC_CTRL 0x00000800 /* XGMAC MMC Control */ +#define XGMAC_MMC_INTR_RX 0x00000804 /* Recieve Interrupt */ +#define XGMAC_MMC_INTR_TX 0x00000808 /* Transmit Interrupt */ +#define XGMAC_MMC_INTR_MASK_RX 0x0000080c /* Recieve Interrupt Mask */ +#define XGMAC_MMC_INTR_MASK_TX 0x00000810 /* Transmit Interrupt Mask */ + + +/* Hardware TX Statistics Counters */ +#define XGMAC_MMC_TXOCTET_GB_LO 0x00000814 +#define XGMAC_MMC_TXOCTET_GB_HI 0x00000818 +#define XGMAC_MMC_TXFRAME_GB_LO 0x0000081C +#define XGMAC_MMC_TXFRAME_GB_HI 0x00000820 +#define XGMAC_MMC_TXBCFRAME_G 0x00000824 +#define XGMAC_MMC_TXMCFRAME_G 0x0000082C +#define XGMAC_MMC_TXUCFRAME_GB 0x00000864 +#define XGMAC_MMC_TXMCFRAME_GB 0x0000086C +#define XGMAC_MMC_TXBCFRAME_GB 0x00000874 +#define XGMAC_MMC_TXUNDERFLOW 0x0000087C +#define XGMAC_MMC_TXOCTET_G_LO 0x00000884 +#define XGMAC_MMC_TXOCTET_G_HI 0x00000888 +#define XGMAC_MMC_TXFRAME_G_LO 0x0000088C +#define XGMAC_MMC_TXFRAME_G_HI 0x00000890 +#define XGMAC_MMC_TXPAUSEFRAME 0x00000894 +#define XGMAC_MMC_TXVLANFRAME 0x0000089C + +/* Hardware RX Statistics Counters */ +#define XGMAC_MMC_RXFRAME_GB_LO 0x00000900 +#define XGMAC_MMC_RXFRAME_GB_HI 0x00000904 +#define XGMAC_MMC_RXOCTET_GB_LO 0x00000908 +#define XGMAC_MMC_RXOCTET_GB_HI 0x0000090C +#define XGMAC_MMC_RXOCTET_G_LO 0x00000910 +#define XGMAC_MMC_RXOCTET_G_HI 0x00000914 +#define XGMAC_MMC_RXBCFRAME_G 0x00000918 +#define XGMAC_MMC_RXMCFRAME_G 0x00000920 +#define XGMAC_MMC_RXCRCERR 0x00000928 +#define XGMAC_MMC_RXRUNT 0x00000930 +#define XGMAC_MMC_RXJABBER 0x00000934 +#define XGMAC_MMC_RXUCFRAME_G 0x00000970 +#define XGMAC_MMC_RXLENGTHERR 0x00000978 +#define XGMAC_MMC_RXPAUSEFRAME 0x00000988 +#define XGMAC_MMC_RXOVERFLOW 0x00000990 +#define XGMAC_MMC_RXVLANFRAME 0x00000998 +#define XGMAC_MMC_RXWATCHDOG 0x000009a0 + +/* DMA Control and Status Registers */ +#define XGMAC_DMA_BUS_MODE 0x00000f00 /* Bus Mode */ +#define XGMAC_DMA_TX_POLL 0x00000f04 /* Transmit Poll Demand */ +#define XGMAC_DMA_RX_POLL 0x00000f08 /* Received Poll Demand */ +#define XGMAC_DMA_RX_BASE_ADDR 0x00000f0c /* Receive List Base */ +#define XGMAC_DMA_TX_BASE_ADDR 0x00000f10 /* Transmit List Base */ +#define XGMAC_DMA_STATUS 0x00000f14 /* Status Register */ +#define XGMAC_DMA_CONTROL 0x00000f18 /* Ctrl (Operational Mode) */ +#define XGMAC_DMA_INTR_ENA 0x00000f1c /* Interrupt Enable */ +#define XGMAC_DMA_MISS_FRAME_CTR 0x00000f20 /* Missed Frame Counter */ +#define XGMAC_DMA_RI_WDOG_TIMER 0x00000f24 /* RX Intr Watchdog Timer */ +#define XGMAC_DMA_AXI_BUS 0x00000f28 /* AXI Bus Mode */ +#define XGMAC_DMA_AXI_STATUS 0x00000f2C /* AXI Status */ +#define XGMAC_DMA_HW_FEATURE 0x00000f58 /* Enabled Hardware Features */ + +#define XGMAC_ADDR_AE 0x80000000 +#define XGMAC_MAX_FILTER_ADDR 31 + +/* PMT Control and Status */ +#define XGMAC_PMT_POINTER_RESET 0x80000000 +#define XGMAC_PMT_GLBL_UNICAST 0x00000200 +#define XGMAC_PMT_WAKEUP_RX_FRM 0x00000040 +#define XGMAC_PMT_MAGIC_PKT 0x00000020 +#define XGMAC_PMT_WAKEUP_FRM_EN 0x00000004 +#define XGMAC_PMT_MAGIC_PKT_EN 0x00000002 +#define XGMAC_PMT_POWERDOWN 0x00000001 + +#define XGMAC_CONTROL_SPD 0x40000000 /* Speed control */ +#define XGMAC_CONTROL_SPD_MASK 0x60000000 +#define XGMAC_CONTROL_SPD_1G 0x60000000 +#define XGMAC_CONTROL_SPD_2_5G 0x40000000 +#define XGMAC_CONTROL_SPD_10G 0x00000000 +#define XGMAC_CONTROL_SARC 0x10000000 /* Source Addr Insert/Replace */ +#define XGMAC_CONTROL_SARK_MASK 0x18000000 +#define XGMAC_CONTROL_CAR 0x04000000 /* CRC Addition/Replacement */ +#define XGMAC_CONTROL_CAR_MASK 0x06000000 +#define XGMAC_CONTROL_DP 0x01000000 /* Disable Padding */ +#define XGMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on rx */ +#define XGMAC_CONTROL_JD 0x00400000 /* Jabber disable */ +#define XGMAC_CONTROL_JE 0x00100000 /* Jumbo frame */ +#define XGMAC_CONTROL_LM 0x00001000 /* Loop-back mode */ +#define XGMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */ +#define XGMAC_CONTROL_ACS 0x00000080 /* Automatic Pad/FCS Strip */ +#define XGMAC_CONTROL_DDIC 0x00000010 /* Disable Deficit Idle Count */ +#define XGMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */ +#define XGMAC_CONTROL_RE 0x00000004 /* Receiver Enable */ + +/* XGMAC Frame Filter defines */ +#define XGMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */ +#define XGMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */ +#define XGMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */ +#define XGMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */ +#define XGMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */ +#define XGMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */ +#define XGMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */ +#define XGMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */ +#define XGMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */ +#define XGMAC_FRAME_FILTER_VHF 0x00000800 /* VLAN Hash Filter */ +#define XGMAC_FRAME_FILTER_VPF 0x00001000 /* VLAN Perfect Filter */ +#define XGMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */ + +#define FIFO_MINUS_1K 0x0 +#define FIFO_MINUS_2K 0x1 +#define FIFO_MINUS_3K 0x2 +#define FIFO_MINUS_4K 0x3 +#define FIFO_MINUS_6K 0x4 +#define FIFO_MINUS_8K 0x5 +#define FIFO_MINUS_12K 0x6 +#define FIFO_MINUS_16K 0x7 + +/* XGMAC FLOW CTRL defines */ +#define XGMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */ +#define XGMAC_FLOW_CTRL_PT_SHIFT 16 +#define XGMAC_FLOW_CTRL_DZQP 0x00000080 /* Disable Zero-Quanta Phase */ +#define XGMAC_FLOW_CTRL_PLT 0x00000020 /* Pause Low Threshhold */ +#define XGMAC_FLOW_CTRL_PLT_SHIFT 4 +#define XGMAC_FLOW_CTRL_PLT_MASK 0x00000030 /* PLT MASK */ +#define XGMAC_FLOW_CTRL_UP 0x00000008 /* Unicast Pause Frame Detect */ +#define XGMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */ +#define XGMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */ +#define XGMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */ + +/* XGMAC_INT_STAT reg */ +#define XGMAC_INT_STAT_PMT 0x0080 /* PMT Interrupt Status */ +#define XGMAC_INT_STAT_LPI 0x0040 /* LPI Interrupt Status */ + +/* DMA Bus Mode register defines */ +#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */ +#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */ +#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */ +#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */ + +/* Programmable burst length */ +#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */ +#define DMA_BUS_MODE_PBL_SHIFT 8 +#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */ +#define DMA_BUS_MODE_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */ +#define DMA_BUS_MODE_RPBL_SHIFT 17 +#define DMA_BUS_MODE_USP 0x00800000 +#define DMA_BUS_MODE_8PBL 0x01000000 +#define DMA_BUS_MODE_AAL 0x02000000 + +#define DMA_AXIMODE_ENLPI 0x80000000 +#define DMA_AXIMODE_MGK 0x40000000 +#define DMA_AXIMODE_WROSR 0x00100000 +#define DMA_AXIMODE_WROSR_MASK 0x00F00000 +#define DMA_AXIMODE_WROSR_SHIFT 20 +#define DMA_AXIMODE_RDOSR 0x00010000 +#define DMA_AXIMODE_RDOSR_MASK 0x000F0000 +#define DMA_AXIMODE_RDOSR_SHIFT 16 +#define DMA_AXIMODE_AAL 0x00001000 +#define DMA_AXIMODE_BLEN256 0x00000080 +#define DMA_AXIMODE_BLEN128 0x00000040 +#define DMA_AXIMODE_BLEN64 0x00000020 +#define DMA_AXIMODE_BLEN32 0x00000010 +#define DMA_AXIMODE_BLEN16 0x00000008 +#define DMA_AXIMODE_BLEN8 0x00000004 +#define DMA_AXIMODE_BLEN4 0x00000002 +#define DMA_AXIMODE_UNDEF 0x00000001 + +/* DMA Bus Mode register defines */ +#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */ +#define DMA_BUS_PR_RATIO_SHIFT 14 +#define DMA_BUS_FB 0x00010000 /* Fixed Burst */ + +/* DMA Control register defines */ +#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ +#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */ +#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */ + +/* DMA Normal interrupt */ +#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */ +#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */ +#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */ +#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */ +#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */ +#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */ +#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */ +#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */ +#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */ +#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */ +#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */ +#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavail */ +#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */ +#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */ + +#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \ + DMA_INTR_ENA_TUE) + +#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \ + DMA_INTR_ENA_RWE | DMA_INTR_ENA_RSE | \ + DMA_INTR_ENA_RUE | DMA_INTR_ENA_UNE | \ + DMA_INTR_ENA_OVE | DMA_INTR_ENA_TJE | \ + DMA_INTR_ENA_TSE) + +/* DMA default interrupt mask */ +#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL) + +/* DMA Status register defines */ +#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ +#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */ +#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ +#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ +#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ +#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ +#define DMA_STATUS_TS_SHIFT 20 +#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ +#define DMA_STATUS_RS_SHIFT 17 +#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ +#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ +#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ +#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */ +#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */ +#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */ +#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */ +#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */ +#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */ +#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */ +#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */ +#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavail */ +#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */ +#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */ + +/* Common MAC defines */ +#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */ +#define MAC_ENABLE_RX 0x00000004 /* Receiver Enable */ + +/* XGMAC Operation Mode Register */ +#define XGMAC_OMR_TSF 0x00200000 /* TX FIFO Store and Forward */ +#define XGMAC_OMR_FTF 0x00100000 /* Flush Transmit FIFO */ +#define XGMAC_OMR_TTC 0x00020000 /* Transmit Threshhold Ctrl */ +#define XGMAC_OMR_TTC_SHIFT 16 +#define XGMAC_OMR_TTC_MASK 0x00030000 +#define XGMAC_OMR_RFD 0x00006000 /* FC Deactivation Threshhold */ +#define XGMAC_OMR_RFD_SHIFT 12 +#define XGMAC_OMR_RFD_MASK 0x00007000 /* FC Deact Threshhold MASK */ +#define XGMAC_OMR_RFA 0x00000600 /* FC Activation Threshhold */ +#define XGMAC_OMR_RFA_SHIFT 9 +#define XGMAC_OMR_RFA_MASK 0x00000E00 /* FC Act Threshhold MASK */ +#define XGMAC_OMR_EFC 0x00000100 /* Enable Hardware FC */ +#define XGMAC_OMR_FEF 0x00000080 /* Forward Error Frames */ +#define XGMAC_OMR_DT 0x00000040 /* Drop TCP/IP csum Errors */ +#define XGMAC_OMR_RSF 0x00000020 /* RX FIFO Store and Forward */ +#define XGMAC_OMR_RTC_256 0x00000018 /* RX Threshhold Ctrl */ +#define XGMAC_OMR_RTC_MASK 0x00000018 /* RX Threshhold Ctrl MASK */ + +/* XGMAC HW Features Register */ +#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* TX Checksum offload */ + +#define XGMAC_MMC_CTRL_CNT_FRZ 0x00000008 + +/* XGMAC Descriptor Defines */ +#define MAX_DESC_BUF_SZ (0x2000 - 8) + +#define RXDESC_EXT_STATUS 0x00000001 +#define RXDESC_CRC_ERR 0x00000002 +#define RXDESC_RX_ERR 0x00000008 +#define RXDESC_RX_WDOG 0x00000010 +#define RXDESC_FRAME_TYPE 0x00000020 +#define RXDESC_GIANT_FRAME 0x00000080 +#define RXDESC_LAST_SEG 0x00000100 +#define RXDESC_FIRST_SEG 0x00000200 +#define RXDESC_VLAN_FRAME 0x00000400 +#define RXDESC_OVERFLOW_ERR 0x00000800 +#define RXDESC_LENGTH_ERR 0x00001000 +#define RXDESC_SA_FILTER_FAIL 0x00002000 +#define RXDESC_DESCRIPTOR_ERR 0x00004000 +#define RXDESC_ERROR_SUMMARY 0x00008000 +#define RXDESC_FRAME_LEN_OFFSET 16 +#define RXDESC_FRAME_LEN_MASK 0x3fff0000 +#define RXDESC_DA_FILTER_FAIL 0x40000000 + +#define RXDESC1_END_RING 0x00008000 + +#define RXDESC_IP_PAYLOAD_MASK 0x00000003 +#define RXDESC_IP_PAYLOAD_UDP 0x00000001 +#define RXDESC_IP_PAYLOAD_TCP 0x00000002 +#define RXDESC_IP_PAYLOAD_ICMP 0x00000003 +#define RXDESC_IP_HEADER_ERR 0x00000008 +#define RXDESC_IP_PAYLOAD_ERR 0x00000010 +#define RXDESC_IPV4_PACKET 0x00000040 +#define RXDESC_IPV6_PACKET 0x00000080 +#define TXDESC_UNDERFLOW_ERR 0x00000001 +#define TXDESC_JABBER_TIMEOUT 0x00000002 +#define TXDESC_LOCAL_FAULT 0x00000004 +#define TXDESC_REMOTE_FAULT 0x00000008 +#define TXDESC_VLAN_FRAME 0x00000010 +#define TXDESC_FRAME_FLUSHED 0x00000020 +#define TXDESC_IP_HEADER_ERR 0x00000040 +#define TXDESC_PAYLOAD_CSUM_ERR 0x00000080 +#define TXDESC_ERROR_SUMMARY 0x00008000 +#define TXDESC_SA_CTRL_INSERT 0x00040000 +#define TXDESC_SA_CTRL_REPLACE 0x00080000 +#define TXDESC_2ND_ADDR_CHAINED 0x00100000 +#define TXDESC_END_RING 0x00200000 +#define TXDESC_CSUM_IP 0x00400000 +#define TXDESC_CSUM_IP_PAYLD 0x00800000 +#define TXDESC_CSUM_ALL 0x00C00000 +#define TXDESC_CRC_EN_REPLACE 0x01000000 +#define TXDESC_CRC_EN_APPEND 0x02000000 +#define TXDESC_DISABLE_PAD 0x04000000 +#define TXDESC_FIRST_SEG 0x10000000 +#define TXDESC_LAST_SEG 0x20000000 +#define TXDESC_INTERRUPT 0x40000000 + +#define DESC_OWN 0x80000000 +#define DESC_BUFFER1_SZ_MASK 0x00001fff +#define DESC_BUFFER2_SZ_MASK 0x1fff0000 +#define DESC_BUFFER2_SZ_OFFSET 16 + +struct xgmac_dma_desc { + __le32 flags; + __le32 buf_size; + __le32 buf1_addr; /* Buffer 1 Address Pointer */ + __le32 buf2_addr; /* Buffer 2 Address Pointer */ + __le32 ext_status; + __le32 res[3]; +}; + +struct xgmac_priv { + struct xgmac_dma_desc *rx_chain; + struct xgmac_dma_desc *tx_chain; + char *rxbuffer; + + u32 tx_currdesc; + u32 rx_currdesc; + + void __iomem *base; + + struct eth_device edev; + struct device_d *dev; +}; + +/* XGMAC Descriptor Access Helpers */ +static inline void desc_set_buf_len(struct xgmac_dma_desc *p, u32 buf_sz) +{ + if (buf_sz > MAX_DESC_BUF_SZ) + p->buf_size = cpu_to_le32(MAX_DESC_BUF_SZ | + (buf_sz - MAX_DESC_BUF_SZ) << DESC_BUFFER2_SZ_OFFSET); + else + p->buf_size = cpu_to_le32(buf_sz); +} + +static inline int desc_get_buf_len(struct xgmac_dma_desc *p) +{ + u32 len = le32_to_cpu(p->buf_size); + return (len & DESC_BUFFER1_SZ_MASK) + + ((len & DESC_BUFFER2_SZ_MASK) >> DESC_BUFFER2_SZ_OFFSET); +} + +static inline void desc_init_rx_desc(struct xgmac_dma_desc *p, int ring_size, + int buf_sz) +{ + struct xgmac_dma_desc *end = p + ring_size - 1; + + memset(p, 0, sizeof(*p) * ring_size); + + for (; p <= end; p++) + desc_set_buf_len(p, buf_sz); + + end->buf_size |= cpu_to_le32(RXDESC1_END_RING); +} + +static inline void desc_init_tx_desc(struct xgmac_dma_desc *p, u32 ring_size) +{ + memset(p, 0, sizeof(*p) * ring_size); + p[ring_size - 1].flags = cpu_to_le32(TXDESC_END_RING); +} + +static inline int desc_get_owner(struct xgmac_dma_desc *p) +{ + return le32_to_cpu(p->flags) & DESC_OWN; +} + +static inline void desc_set_rx_owner(struct xgmac_dma_desc *p) +{ + /* Clear all fields and set the owner */ + p->flags = cpu_to_le32(DESC_OWN); +} + +static inline void desc_set_tx_owner(struct xgmac_dma_desc *p, u32 flags) +{ + u32 tmpflags = le32_to_cpu(p->flags); + tmpflags &= TXDESC_END_RING; + tmpflags |= flags | DESC_OWN; + p->flags = cpu_to_le32(tmpflags); +} + +static inline void *desc_get_buf_addr(struct xgmac_dma_desc *p) +{ + return (void *)le32_to_cpu(p->buf1_addr); +} + +static inline void desc_set_buf_addr(struct xgmac_dma_desc *p, + void *paddr, int len) +{ + p->buf1_addr = cpu_to_le32(paddr); + if (len > MAX_DESC_BUF_SZ) + p->buf2_addr = cpu_to_le32(paddr + MAX_DESC_BUF_SZ); +} + +static inline void desc_set_buf_addr_and_size(struct xgmac_dma_desc *p, + void *paddr, int len) +{ + desc_set_buf_len(p, len); + desc_set_buf_addr(p, paddr, len); +} + +static inline int desc_get_rx_frame_len(struct xgmac_dma_desc *p) +{ + u32 data = le32_to_cpu(p->flags); + u32 len = (data & RXDESC_FRAME_LEN_MASK) >> RXDESC_FRAME_LEN_OFFSET; + if (data & RXDESC_FRAME_TYPE) + len -= 4; + + return len; +} + +/* + * Initialize a descriptor ring. Calxeda XGMAC is configured to use + * advanced descriptors. + */ + +static void init_rx_desc(struct xgmac_priv *priv) +{ + struct xgmac_dma_desc *rxdesc = priv->rx_chain; + void *rxbuffer = priv->rxbuffer; + int i; + + desc_init_rx_desc(rxdesc, RX_NUM_DESC, ETH_BUF_SZ); + writel((ulong)rxdesc, priv->base + XGMAC_DMA_RX_BASE_ADDR); + + for (i = 0; i < RX_NUM_DESC; i++) { + desc_set_buf_addr(rxdesc + i, rxbuffer + (i * ETH_BUF_SZ), + ETH_BUF_SZ); + desc_set_rx_owner(rxdesc + i); + } +} + +static void init_tx_desc(struct xgmac_priv *priv) +{ + desc_init_tx_desc(priv->tx_chain, TX_NUM_DESC); + writel((ulong)priv->tx_chain, priv->base + XGMAC_DMA_TX_BASE_ADDR); +} + +static int xgmac_reset(struct eth_device *dev) +{ + struct xgmac_priv *priv = dev->priv; + int ret; + u32 value; + + value = readl(priv->base + XGMAC_CONTROL) & XGMAC_CONTROL_SPD_MASK; + + writel(DMA_BUS_MODE_SFT_RESET, priv->base + XGMAC_DMA_BUS_MODE); + + ret = wait_on_timeout(100 * MSECOND, + !(readl(priv->base + XGMAC_DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)); + + writel(value, priv->base + XGMAC_CONTROL); + + return ret; +} + +static int xgmac_open(struct eth_device *edev) +{ + struct xgmac_priv *priv = edev->priv; + int value; + int ret; + + ret = xgmac_reset(edev); + if (ret) + return ret; + + /* set the AXI bus modes */ + value = DMA_BUS_MODE_ATDS | + (16 << DMA_BUS_MODE_PBL_SHIFT) | + DMA_BUS_MODE_FB | DMA_BUS_MODE_AAL; + writel(value, priv->base + XGMAC_DMA_BUS_MODE); + + value = DMA_AXIMODE_AAL | DMA_AXIMODE_BLEN16 | + DMA_AXIMODE_BLEN8 | DMA_AXIMODE_BLEN4; + writel(value, priv->base + XGMAC_DMA_AXI_BUS); + + /* set flow control parameters and store and forward mode */ + value = (FIFO_MINUS_12K << XGMAC_OMR_RFD_SHIFT) | + (FIFO_MINUS_4K << XGMAC_OMR_RFA_SHIFT) | + XGMAC_OMR_EFC | XGMAC_OMR_TSF | XGMAC_OMR_RSF; + writel(value, priv->base + XGMAC_OMR); + + /* enable pause frames */ + value = (1024 << XGMAC_FLOW_CTRL_PT_SHIFT) | + (1 << XGMAC_FLOW_CTRL_PLT_SHIFT) | + XGMAC_FLOW_CTRL_UP | XGMAC_FLOW_CTRL_RFE | XGMAC_FLOW_CTRL_TFE; + writel(value, priv->base + XGMAC_FLOW_CTRL); + + /* Initialize the descriptor chains */ + init_rx_desc(priv); + init_tx_desc(priv); + + /* must set to 0, or when started up will cause issues */ + priv->tx_currdesc = 0; + priv->rx_currdesc = 0; + + /* set default core values */ + value = readl(priv->base + XGMAC_CONTROL); + value &= XGMAC_CONTROL_SPD_MASK; + value |= XGMAC_CONTROL_DDIC | XGMAC_CONTROL_ACS | + XGMAC_CONTROL_IPC | XGMAC_CONTROL_CAR; + + /* Everything is ready enable both mac and DMA */ + value |= XGMAC_CONTROL_RE | XGMAC_CONTROL_TE; + writel(value, priv->base + XGMAC_CONTROL); + + value = readl(priv->base + XGMAC_DMA_CONTROL); + value |= DMA_CONTROL_SR | DMA_CONTROL_ST; + writel(value, priv->base + XGMAC_DMA_CONTROL); + + return 0; +} + +static int xgmac_send(struct eth_device *edev, void *packet, int length) +{ + struct xgmac_priv *priv = edev->priv; + u32 currdesc = priv->tx_currdesc; + struct xgmac_dma_desc *txdesc = &priv->tx_chain[currdesc]; + int ret; + + dma_flush_range((ulong) packet, (ulong)packet + length); + desc_set_buf_addr_and_size(txdesc, packet, length); + desc_set_tx_owner(txdesc, TXDESC_FIRST_SEG | + TXDESC_LAST_SEG | TXDESC_CRC_EN_APPEND); + + /* write poll demand */ + writel(1, priv->base + XGMAC_DMA_TX_POLL); + + ret = wait_on_timeout(1 * SECOND, !desc_get_owner(txdesc)); + if (ret) { + dev_err(priv->dev, "TX timeout\n"); + return ret; + } + + priv->tx_currdesc = (currdesc + 1) & (TX_NUM_DESC - 1); + return 0; +} + +static int xgmac_recv(struct eth_device *edev) +{ + struct xgmac_priv *priv = edev->priv; + u32 currdesc = priv->rx_currdesc; + struct xgmac_dma_desc *rxdesc = &priv->rx_chain[currdesc]; + int length = 0; + + /* check if the host has the desc */ + if (desc_get_owner(rxdesc)) + return -1; /* something bad happened */ + + length = desc_get_rx_frame_len(rxdesc); + + net_receive(desc_get_buf_addr(rxdesc), length); + + /* set descriptor back to owned by XGMAC */ + desc_set_rx_owner(rxdesc); + writel(1, priv->base + XGMAC_DMA_RX_POLL); + + priv->rx_currdesc = (currdesc + 1) & (RX_NUM_DESC - 1); + + return length; +} + +static void xgmac_halt(struct eth_device *edev) +{ + struct xgmac_priv *priv = edev->priv; + int value; + + /* Disable TX/RX */ + value = readl(priv->base + XGMAC_CONTROL); + value &= ~(XGMAC_CONTROL_RE | XGMAC_CONTROL_TE); + writel(value, priv->base + XGMAC_CONTROL); + + /* Disable DMA */ + value = readl(priv->base + XGMAC_DMA_CONTROL); + value &= ~(DMA_CONTROL_SR | DMA_CONTROL_ST); + writel(value, priv->base + XGMAC_DMA_CONTROL); + + /* must set to 0, or when started up will cause issues */ + priv->tx_currdesc = 0; + priv->rx_currdesc = 0; +} + +static int xgmac_get_ethaddr(struct eth_device *edev, unsigned char *addr) +{ + struct xgmac_priv *priv = edev->priv; + u32 hi_addr, lo_addr; + + /* Read the MAC address from the hardware */ + hi_addr = readl(priv->base + XGMAC_ADDR_HIGH(0)); + lo_addr = readl(priv->base + XGMAC_ADDR_LOW(0)); + + /* Extract the MAC address from the high and low words */ + addr[0] = lo_addr & 0xff; + addr[1] = (lo_addr >> 8) & 0xff; + addr[2] = (lo_addr >> 16) & 0xff; + addr[3] = (lo_addr >> 24) & 0xff; + addr[4] = hi_addr & 0xff; + addr[5] = (hi_addr >> 8) & 0xff; + + return 0; +} + +static int xgmac_set_ethaddr(struct eth_device *dev, unsigned char *addr) +{ + struct xgmac_priv *priv = dev->priv; + u32 data; + + data = (addr[5] << 8) | addr[4]; + writel(data, priv->base + XGMAC_ADDR_HIGH(0)); + data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + writel(data, priv->base + XGMAC_ADDR_LOW(0)); + + return 0; +} + +static int hb_xgmac_probe(struct device_d *dev) +{ + struct eth_device *edev; + struct xgmac_priv *priv; + void __iomem *base; + + base = dev_request_mem_region(dev, 0); + + /* check hardware version */ + if (readl(base + XGMAC_VERSION) != 0x1012) + return -EINVAL; + + priv = xzalloc(sizeof(*priv)); + + priv->dev = dev; + priv->base = base; + + priv->rxbuffer = dma_alloc_coherent(RX_BUF_SZ); + priv->rx_chain = dma_alloc_coherent(RX_NUM_DESC * sizeof(struct xgmac_dma_desc)); + priv->tx_chain = dma_alloc_coherent(TX_NUM_DESC * sizeof(struct xgmac_dma_desc)); + + edev = &priv->edev; + edev->priv = priv; + + edev->open = xgmac_open; + edev->send = xgmac_send; + edev->recv = xgmac_recv; + edev->halt = xgmac_halt; + edev->get_ethaddr = xgmac_get_ethaddr; + edev->set_ethaddr = xgmac_set_ethaddr; + edev->parent = dev; + + eth_register(edev); + + return 0; +} + +static __maybe_unused struct of_device_id xgmac_dt_ids[] = { + { + .compatible = "calxeda,hb-xgmac", + }, { + /* sentinel */ + } +}; + +static struct driver_d hb_xgmac_driver = { + .name = "hb-xgmac", + .probe = hb_xgmac_probe, + .of_compatible = DRV_OF_COMPAT(xgmac_dt_ids), +}; + +static int hb_xgmac_driver_init(void) +{ + debug("%s\n", __func__); + return platform_driver_register(&hb_xgmac_driver); +} +device_initcall(hb_xgmac_driver_init); diff --git a/drivers/of/base.c b/drivers/of/base.c index 1f32bfb..fd9b8e1 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -734,18 +734,26 @@ return of_read_number(p, s); } -static int of_add_memory(struct device_node *node) +int of_add_memory(struct device_node *node, bool dump) { int na, nc; const __be32 *reg, *endp; - int len, r = 0; + int len, r = 0, ret; static char str[6]; + const char *device_type; + + ret = of_property_read_string(node, "device_type", &device_type); + if (ret) + return -ENXIO; + + if (strcmp(device_type, "memory")) + return -ENXIO; of_bus_count_cells(node, &na, &nc); reg = of_get_property(node, "reg", &len); if (!reg) - return 0; + return -EINVAL; endp = reg + (len / sizeof(__be32)); @@ -762,6 +770,9 @@ barebox_add_memory_bank(str, base, size); + if (dump) + pr_info("%s: %s: 0x%llx@0x%llx\n", node->name, str, size, base); + r++; } @@ -770,7 +781,7 @@ static int add_of_device_resource(struct device_node *node) { - struct property *reg, *type; + struct property *reg; u64 address, size; struct resource *res; struct device_d *dev; @@ -783,9 +794,9 @@ list_add_tail(&node->phandles, &phandle_list); } - type = of_find_property(node, "device_type"); - if (type) - return of_add_memory(node); + ret = of_add_memory(node, false); + if (ret != -ENXIO) + return ret; reg = of_find_property(node, "reg"); if (!reg) diff --git a/include/of.h b/include/of.h index d413d72..95d9702 100644 --- a/include/of.h +++ b/include/of.h @@ -17,6 +17,12 @@ const void *val, int len, int create); void do_fixup_by_path_u32(struct fdt_header *fdt, const char *path, const char *prop, u32 val, int create); +void do_fixup_by_compatible(struct fdt_header *fdt, const char *compatible, + const char *prop, const void *val, int len, int create); +void do_fixup_by_compatible_u32(struct fdt_header *fdt, const char *compatible, + const char *prop, u32 val, int create); +void do_fixup_by_compatible_string(struct fdt_header *fdt, const char *compatible, + const char *prop, const char *val, int create); int fdt_get_path_or_create(struct fdt_header *fdt, const char *path); #ifdef CONFIG_FDT int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force); @@ -132,6 +138,7 @@ int of_device_is_stdout_path(struct device_d *dev); const char *of_get_model(void); void *of_flatten_dtb(void); +int of_add_memory(struct device_node *node, bool dump); #else static inline int of_parse_partitions(const char *cdevname, struct device_node *node) @@ -163,6 +170,11 @@ { return NULL; } + +static inline int of_add_memory(struct device_node *node, bool dump) +{ + return -EINVAL; +} #endif #endif /* __OF_H */