mpc85xx: add SPI kernel loader for TP-Link TL-WDR4900 v1
[openwrt/staging/ansuel.git] / target / linux / mpc85xx / image / spi-loader / loader.c
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
4 */
5
6 #include <image.h>
7 #include <init.h>
8 #include <spi.h>
9 #include <spi-nor.h>
10 #include <stdio.h>
11 #include <string.h>
12
13 static bool check_image_header(const image_header_t *header)
14 {
15 if (header->ih_magic != cpu_to_be32(IH_MAGIC_OKLI)) {
16 puts("Invalid image magic\n");
17 return false;
18 }
19
20 if (header->ih_comp != cpu_to_be32(IH_COMP_NONE)) {
21 puts("Unsupported compressed image\n");
22 return false;
23 }
24
25 return true;
26 }
27
28 static uint32_t do_load(void)
29 {
30 image_header_t header;
31 uint32_t ih_size, ih_load, ih_ep;
32
33 if (spi_nor_read_id())
34 return UINT32_MAX;
35
36 puts("Reading image header...\n");
37 if (spi_nor_read_data(&header, CONFIG_IMAGE_OFFSET, sizeof(header)))
38 return UINT32_MAX;
39
40 if (!check_image_header(&header))
41 return UINT32_MAX;
42
43 header.ih_name[sizeof(header.ih_name) - 1] = 0;
44 ih_size = be32_to_cpu(header.ih_size);
45 ih_load = be32_to_cpu(header.ih_load);
46 ih_ep = be32_to_cpu(header.ih_ep);
47
48 put_with_label("Image Name: ", puts, (const char *)header.ih_name);
49 put_with_label("Data Size: ", put_u32, ih_size);
50 put_with_label("Load Address: ", put_u32, ih_load);
51 put_with_label("Entry Point: ", put_u32, ih_ep);
52
53 puts("Reading image data...\n");
54 void *loadaddr = (void *)ih_load;
55 if (spi_nor_read_data(loadaddr, CONFIG_IMAGE_OFFSET + sizeof(header),
56 ih_size))
57 return false;
58
59 flush_cache(loadaddr, ih_size);
60
61 return ih_ep;
62 }
63
64 static void enter_image(uint32_t addr)
65 {
66 typedef void (*entry_t)(void);
67 entry_t entry = (entry_t)addr;
68
69 puts("Starting image...\n");
70 entry();
71 }
72
73 static void load(void)
74 {
75 uint32_t addr;
76 int ret;
77
78 ret = spi_init(0, CONFIG_SPI_MAX_HZ, SPI_MODE_0);
79 if (ret) {
80 puts("Failed to initialize SPI controller\n");
81 return;
82 }
83
84 ret = spi_claim_bus();
85 if (ret) {
86 puts("Failed to enable SPI controller\n");
87 return;
88 }
89
90 addr = do_load();
91
92 spi_release_bus();
93
94 if (addr != UINT32_MAX)
95 enter_image(addr);
96 }
97
98 void start(void)
99 {
100 serial_console_init();
101 puts("=== " CONFIG_PROGRAM_NAME " ===\n");
102
103 load();
104
105 puts("Halting execution.\n");
106 while (true) {}
107 }