1 /*
2 * Copyright (c) 2014-2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <lk/debug.h>
12 #include <lk/trace.h>
13 #include <lk/init.h>
14 #include <lib/bootargs.h>
15 #include <lib/bootimage.h>
16 #include <lib/ptable.h>
17 #include <lib/sysparam.h>
18 #include <lib/watchdog.h>
19 #include <dev/spiflash.h>
20 #include <kernel/vm.h>
21 #include <kernel/thread.h>
22
23 #include <platform/gem.h>
24 #include <platform/fpga.h>
25
26 #if WITH_LIB_MINIP
27 #include <lib/minip.h>
28 #endif
29
30 #define BLOCK_DEVICE_NAME "spi0"
31
zynq_common_target_init(uint level)32 static void zynq_common_target_init(uint level) {
33 status_t err;
34
35 /* zybo has a spiflash on qspi */
36 spiflash_detect();
37
38 bdev_t *spi = bio_open(BLOCK_DEVICE_NAME);
39 if (spi) {
40 /* find or create a partition table at the start of flash */
41 if (ptable_scan(BLOCK_DEVICE_NAME, 0) < 0) {
42 ptable_create_default(BLOCK_DEVICE_NAME, 0);
43 }
44
45 struct ptable_entry entry = { 0 };
46
47 /* find and recover sysparams */
48 if (ptable_find("sysparam", &entry) < 0) {
49 /* didn't find sysparam partition, create it */
50 ptable_add("sysparam", 0x1000, 0);
51 ptable_find("sysparam", &entry);
52 }
53
54 if (entry.length > 0) {
55 sysparam_scan(spi, entry.offset, entry.length);
56
57 #if SYSPARAM_ALLOW_WRITE
58 /* for testing purposes, put at least one sysparam value in */
59 if (sysparam_add("dummy", "value", sizeof("value")) >= 0) {
60 sysparam_write();
61 }
62 #endif
63
64 #if LK_DEBUGLEVEL > 1
65 sysparam_dump(true);
66 #endif
67 }
68
69 /* create bootloader partition if it does not exist */
70 ptable_add("bootloader", 0x40000, 0);
71
72 #if LK_DEBUGLEVEL > 1
73 printf("flash partition table:\n");
74 ptable_dump();
75 #endif
76 }
77
78 /* recover boot arguments */
79 const char *cmdline = bootargs_get_command_line();
80 if (cmdline) {
81 printf("lk command line: '%s'\n", cmdline);
82 }
83
84 /* see if we came from a bootimage */
85 const char *device;
86 uint64_t bootimage_phys;
87 size_t bootimage_size;
88 if (bootargs_get_bootimage_pointer(&bootimage_phys, &bootimage_size, &device) >= 0) {
89 bootimage_t *bi = NULL;
90 bool put_bio_memmap = false;
91
92 printf("our bootimage is at device '%s', phys 0x%llx, size %zx\n", device, bootimage_phys, bootimage_size);
93
94 /* if the bootimage we came from is in physical memory, find it */
95 if (!strcmp(device, "pmem")) {
96 void *ptr = paddr_to_kvaddr(bootimage_phys);
97 if (ptr) {
98 bootimage_open(ptr, bootimage_size, &bi);
99 }
100 } else if (!strcmp(device, BLOCK_DEVICE_NAME)) {
101 /* we were loaded from spi flash, go look at it to see if we can find it */
102 if (spi) {
103 void *ptr = 0;
104 err = bio_ioctl(spi, BIO_IOCTL_GET_MEM_MAP, (void *)&ptr);
105 if (err >= 0) {
106 put_bio_memmap = true;
107 ptr = (uint8_t *)ptr + bootimage_phys;
108 bootimage_open(ptr, bootimage_size, &bi);
109 }
110 }
111 }
112
113 /* did we find the bootimage? */
114 if (bi) {
115 /* we have a valid bootimage, find the fpga section */
116 const void *fpga_ptr;
117 size_t fpga_len;
118
119 if (bootimage_get_file_section(bi, TYPE_FPGA_IMAGE, &fpga_ptr, &fpga_len) >= 0) {
120 /* we have a fpga image */
121
122 /* lookup the physical address of the bitfile */
123 paddr_t pa = vaddr_to_paddr((void *)fpga_ptr);
124 if (pa != 0) {
125 /* program the fpga with it*/
126 printf("loading fpga image at %p (phys 0x%lx), len %zx\n", fpga_ptr, pa, fpga_len);
127 zynq_reset_fpga();
128 err = zynq_program_fpga(pa, fpga_len);
129 if (err < 0) {
130 printf("error %d loading fpga\n", err);
131 }
132 printf("fpga image loaded\n");
133 }
134 }
135 }
136
137 /* if we memory mapped it, put the block device back to block mode */
138 if (put_bio_memmap) {
139 /* HACK: for completely non-obvious reasons, need to sleep here for a little bit.
140 * Experimentally it was found that if fetching the fpga image out of qspi flash,
141 * for a period of time after the transfer is complete, there appears to be stray
142 * AXI bus transactions that cause the system to hang if immediately after
143 * programming the qspi memory aperture is destroyed.
144 */
145 thread_sleep(10);
146
147 bio_ioctl(spi, BIO_IOCTL_PUT_MEM_MAP, NULL);
148 }
149 }
150
151 #if WITH_LIB_MINIP
152 /* pull some network stack related params out of the sysparam block */
153 uint8_t mac_addr[6];
154 uint32_t ip_addr = IPV4_NONE;
155 uint32_t ip_mask = IPV4_NONE;
156 uint32_t ip_gateway = IPV4_NONE;
157
158 if (sysparam_read("net0.mac_addr", mac_addr, sizeof(mac_addr)) < (ssize_t)sizeof(mac_addr)) {
159 /* couldn't find eth address, make up a random one */
160 for (size_t i = 0; i < sizeof(mac_addr); i++) {
161 mac_addr[i] = rand() & 0xff;
162 }
163
164 /* unicast and locally administered */
165 mac_addr[0] &= ~(1<<0);
166 mac_addr[0] |= (1<<1);
167 }
168
169 uint8_t use_dhcp = 0;
170 sysparam_read("net0.use_dhcp", &use_dhcp, sizeof(use_dhcp));
171 sysparam_read("net0.ip_addr", &ip_addr, sizeof(ip_addr));
172 sysparam_read("net0.ip_mask", &ip_mask, sizeof(ip_mask));
173 sysparam_read("net0.ip_gateway", &ip_gateway, sizeof(ip_gateway));
174
175 minip_set_macaddr(mac_addr);
176 gem_set_macaddr(mac_addr);
177
178 if (!use_dhcp && ip_addr != IPV4_NONE) {
179 minip_init(gem_send_raw_pkt, NULL, ip_addr, ip_mask, ip_gateway);
180 } else {
181 /* Configure IP stack and hook to the driver */
182 minip_init_dhcp(gem_send_raw_pkt, NULL);
183 }
184 gem_set_callback(minip_rx_driver_callback);
185 #endif
186 }
187
188 /* init after target_init() */
189 LK_INIT_HOOK(app_zynq_common, &zynq_common_target_init, LK_INIT_LEVEL_TARGET);
190
191 /* watchdog setup, as early as possible */
zynq_watchdog_init(uint level)192 static void zynq_watchdog_init(uint level) {
193 /* start the watchdog timer */
194 watchdog_hw_set_enabled(true);
195 }
196
197 LK_INIT_HOOK(app_zynq_common_watchdog, &zynq_watchdog_init, LK_INIT_LEVEL_KERNEL);
198
199