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