/* * Copyright (c) 2014-2015 Travis Geiselbrecht * * Use of this source code is governed by a MIT-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/MIT */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if WITH_LIB_MINIP #include #endif #define BLOCK_DEVICE_NAME "spi0" static void zynq_common_target_init(uint level) { status_t err; /* zybo has a spiflash on qspi */ spiflash_detect(); bdev_t *spi = bio_open(BLOCK_DEVICE_NAME); if (spi) { /* find or create a partition table at the start of flash */ if (ptable_scan(BLOCK_DEVICE_NAME, 0) < 0) { ptable_create_default(BLOCK_DEVICE_NAME, 0); } struct ptable_entry entry = { 0 }; /* find and recover sysparams */ if (ptable_find("sysparam", &entry) < 0) { /* didn't find sysparam partition, create it */ ptable_add("sysparam", 0x1000, 0); ptable_find("sysparam", &entry); } if (entry.length > 0) { sysparam_scan(spi, entry.offset, entry.length); #if SYSPARAM_ALLOW_WRITE /* for testing purposes, put at least one sysparam value in */ if (sysparam_add("dummy", "value", sizeof("value")) >= 0) { sysparam_write(); } #endif #if LK_DEBUGLEVEL > 1 sysparam_dump(true); #endif } /* create bootloader partition if it does not exist */ ptable_add("bootloader", 0x40000, 0); #if LK_DEBUGLEVEL > 1 printf("flash partition table:\n"); ptable_dump(); #endif } /* recover boot arguments */ const char *cmdline = bootargs_get_command_line(); if (cmdline) { printf("lk command line: '%s'\n", cmdline); } /* see if we came from a bootimage */ const char *device; uint64_t bootimage_phys; size_t bootimage_size; if (bootargs_get_bootimage_pointer(&bootimage_phys, &bootimage_size, &device) >= 0) { bootimage_t *bi = NULL; bool put_bio_memmap = false; printf("our bootimage is at device '%s', phys 0x%llx, size %zx\n", device, bootimage_phys, bootimage_size); /* if the bootimage we came from is in physical memory, find it */ if (!strcmp(device, "pmem")) { void *ptr = paddr_to_kvaddr(bootimage_phys); if (ptr) { bootimage_open(ptr, bootimage_size, &bi); } } else if (!strcmp(device, BLOCK_DEVICE_NAME)) { /* we were loaded from spi flash, go look at it to see if we can find it */ if (spi) { void *ptr = 0; err = bio_ioctl(spi, BIO_IOCTL_GET_MEM_MAP, (void *)&ptr); if (err >= 0) { put_bio_memmap = true; ptr = (uint8_t *)ptr + bootimage_phys; bootimage_open(ptr, bootimage_size, &bi); } } } /* did we find the bootimage? */ if (bi) { /* we have a valid bootimage, find the fpga section */ const void *fpga_ptr; size_t fpga_len; if (bootimage_get_file_section(bi, TYPE_FPGA_IMAGE, &fpga_ptr, &fpga_len) >= 0) { /* we have a fpga image */ /* lookup the physical address of the bitfile */ paddr_t pa = vaddr_to_paddr((void *)fpga_ptr); if (pa != 0) { /* program the fpga with it*/ printf("loading fpga image at %p (phys 0x%lx), len %zx\n", fpga_ptr, pa, fpga_len); zynq_reset_fpga(); err = zynq_program_fpga(pa, fpga_len); if (err < 0) { printf("error %d loading fpga\n", err); } printf("fpga image loaded\n"); } } } /* if we memory mapped it, put the block device back to block mode */ if (put_bio_memmap) { /* HACK: for completely non-obvious reasons, need to sleep here for a little bit. * Experimentally it was found that if fetching the fpga image out of qspi flash, * for a period of time after the transfer is complete, there appears to be stray * AXI bus transactions that cause the system to hang if immediately after * programming the qspi memory aperture is destroyed. */ thread_sleep(10); bio_ioctl(spi, BIO_IOCTL_PUT_MEM_MAP, NULL); } } #if WITH_LIB_MINIP /* pull some network stack related params out of the sysparam block */ uint8_t mac_addr[6]; uint32_t ip_addr = IPV4_NONE; uint32_t ip_mask = IPV4_NONE; uint32_t ip_gateway = IPV4_NONE; if (sysparam_read("net0.mac_addr", mac_addr, sizeof(mac_addr)) < (ssize_t)sizeof(mac_addr)) { /* couldn't find eth address, make up a random one */ for (size_t i = 0; i < sizeof(mac_addr); i++) { mac_addr[i] = rand() & 0xff; } /* unicast and locally administered */ mac_addr[0] &= ~(1<<0); mac_addr[0] |= (1<<1); } uint8_t use_dhcp = 0; sysparam_read("net0.use_dhcp", &use_dhcp, sizeof(use_dhcp)); sysparam_read("net0.ip_addr", &ip_addr, sizeof(ip_addr)); sysparam_read("net0.ip_mask", &ip_mask, sizeof(ip_mask)); sysparam_read("net0.ip_gateway", &ip_gateway, sizeof(ip_gateway)); gem_set_macaddr(mac_addr); minip_set_eth(gem_send_raw_pkt, NULL, mac_addr); if (!use_dhcp && ip_addr != IPV4_NONE) { minip_start_static(ip_addr, ip_mask, ip_gateway); } else { /* Configure IP stack and hook to the driver */ minip_start_dhcp(); } gem_set_callback(minip_rx_driver_callback); #endif } /* init after target_init() */ LK_INIT_HOOK(app_zynq_common, &zynq_common_target_init, LK_INIT_LEVEL_TARGET); /* watchdog setup, as early as possible */ static void zynq_watchdog_init(uint level) { /* start the watchdog timer */ watchdog_hw_set_enabled(true); } LK_INIT_HOOK(app_zynq_common_watchdog, &zynq_watchdog_init, LK_INIT_LEVEL_KERNEL);