/* * See file CREDITS for list of people who contributed to this * project. * * 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 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. * */ #include #include #include #include #include #include #include #include "eth_firmware.h" struct fw_header { unsigned int magic; unsigned int type; unsigned int version; unsigned int table_size; unsigned int reserved[4]; } __attribute__((packed)); static int xc_check_ptr(int xcno, unsigned long adr, unsigned int size) { if (adr >= NETX_PA_XMAC(xcno) && adr + size < NETX_PA_XMAC(xcno) + XMAC_MEM_SIZE) return 0; if (adr >= NETX_PA_XPEC(xcno) && adr + size < NETX_PA_XPEC(xcno) + XPEC_MEM_SIZE) return 0; printf("%s: illegal pointer 0x%08lx\n", __func__ ,adr); return -1; } static int xc_patch(int xcno, const u32 *patch, int count) { unsigned int adr, val; int i; for (i = 0; i < count; i++) { adr = *patch++; val = *patch++; if (xc_check_ptr(xcno, adr, 1) < 0) return -1; writel(val, adr); } return 0; } static void memset32(void *s, int c, int n) { int i; u32 *t = s; for (i = 0; i < (n >> 2); i++) *t++ = 0; } static void memcpy32(void *trg, const void *src, int size) { int i; u32 *t = trg; const u32 *s = src; for (i = 0; i < (size >> 2); i++) *t++ = *s++; } int loadxc(int xcno) { /* stop xmac / xpec */ XMAC_REG(xcno, XMAC_RPU_HOLD_PC) = RPU_HOLD_PC; XMAC_REG(xcno, XMAC_TPU_HOLD_PC) = TPU_HOLD_PC; XPEC_REG(xcno, XPEC_XPU_HOLD_PC) = XPU_HOLD_PC; XPEC_REG(xcno, XPEC_PC) = 0; /* load firmware */ memset32((void*)NETX_PA_XPEC(xcno) + XPEC_RAM_START, 0, 0x2000); memset32((void*)NETX_PA_XMAC(xcno), 0, 0x800); /* can't use barebox memcpy here, we need 32bit accesses */ if (xcno == 0) { memcpy32((void*)(NETX_PA_XMAC(xcno) + XMAC_RPU_PROGRAM_START), rpu_eth0, sizeof(rpu_eth0)); memcpy32((void*)(NETX_PA_XMAC(xcno) + XMAC_TPU_PROGRAM_START), tpu_eth0, sizeof(tpu_eth0)); memcpy32((void*)NETX_PA_XPEC(xcno) + XPEC_RAM_START, xpec_eth0_mac, sizeof(xpec_eth0_mac)); xc_patch(xcno, rpu_eth0_patch, ARRAY_SIZE(rpu_eth0_patch) >> 1); xc_patch(xcno, tpu_eth0_patch, ARRAY_SIZE(tpu_eth0_patch) >> 1); xc_patch(xcno, xpec_eth0_mac_patch, ARRAY_SIZE(xpec_eth0_mac_patch) >> 1); } else { memcpy32((void*)(NETX_PA_XMAC(xcno) + XMAC_RPU_PROGRAM_START), rpu_eth1, sizeof(rpu_eth1)); memcpy32((void*)(NETX_PA_XMAC(xcno) + XMAC_TPU_PROGRAM_START), tpu_eth1, sizeof(tpu_eth1)); memcpy32((void*)NETX_PA_XPEC(xcno) + XPEC_RAM_START, xpec_eth1_mac, sizeof(xpec_eth1_mac)); xc_patch(xcno, rpu_eth1_patch, ARRAY_SIZE(rpu_eth1_patch) >> 1); xc_patch(xcno, tpu_eth1_patch, ARRAY_SIZE(tpu_eth1_patch) >> 1); xc_patch(xcno, xpec_eth1_mac_patch, ARRAY_SIZE(xpec_eth1_mac_patch) >> 1); } /* start xmac / xpec */ XPEC_REG(xcno, XPEC_XPU_HOLD_PC) = 0; XMAC_REG(xcno, XMAC_TPU_HOLD_PC) = 0; XMAC_REG(xcno, XMAC_RPU_HOLD_PC) = 0; return 0; } static int do_loadxc(int argc, char *argv[]) { int xcno; if (argc < 2) goto failure; xcno = simple_strtoul(argv[1], NULL, 16); printf("loading xc%d\n",xcno); /* There is a bug in the netx internal firmware. For now we have to call this twice */ loadxc(xcno); loadxc(xcno); return 0; failure: return COMMAND_ERROR_USAGE; } BAREBOX_CMD_START(loadxc) .cmd = do_loadxc, BAREBOX_CMD_DESC("load XMAC/XPEC engine with ethernet firmware") BAREBOX_CMD_GROUP(CMD_GRP_NET) BAREBOX_CMD_END static void __noreturn netx_restart_soc(struct restart_handler *rst) { SYSTEM_REG(SYSTEM_RES_CR) = 0x01000008; /* Not reached */ hang(); } static int restart_register_feature(void) { restart_handler_register_fn(netx_restart_soc); return 0; } coredevice_initcall(restart_register_feature);