xref: /openbmc/u-boot/common/splash_source.c (revision 870dd309)
1 /*
2  * (C) Copyright 2014 CompuLab, Ltd. <www.compulab.co.il>
3  *
4  * Authors: Igor Grinberg <grinberg@compulab.co.il>
5  *
6  * SPDX-License-Identifier:	GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <nand.h>
11 #include <errno.h>
12 #include <splash.h>
13 #include <spi_flash.h>
14 #include <spi.h>
15 #include <bmp_layout.h>
16 #include <fs.h>
17 
18 DECLARE_GLOBAL_DATA_PTR;
19 
20 #ifdef CONFIG_SPI_FLASH
21 static struct spi_flash *sf;
22 static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
23 {
24 	if (!sf) {
25 		sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
26 				     CONFIG_SF_DEFAULT_CS,
27 				     CONFIG_SF_DEFAULT_SPEED,
28 				     CONFIG_SF_DEFAULT_MODE);
29 		if (!sf)
30 			return -ENODEV;
31 	}
32 
33 	return spi_flash_read(sf, offset, read_size, (void *)bmp_load_addr);
34 }
35 #else
36 static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
37 {
38 	debug("%s: sf support not available\n", __func__);
39 	return -ENOSYS;
40 }
41 #endif
42 
43 #ifdef CONFIG_CMD_NAND
44 static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
45 {
46 	return nand_read_skip_bad(&nand_info[nand_curr_device], offset,
47 				  &read_size, NULL,
48 				  nand_info[nand_curr_device].size,
49 				  (u_char *)bmp_load_addr);
50 }
51 #else
52 static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
53 {
54 	debug("%s: nand support not available\n", __func__);
55 	return -ENOSYS;
56 }
57 #endif
58 
59 static int splash_storage_read_raw(struct splash_location *location,
60 			       u32 bmp_load_addr, size_t read_size)
61 {
62 	u32 offset;
63 
64 	if (!location)
65 		return -EINVAL;
66 
67 	offset = location->offset;
68 	switch (location->storage) {
69 	case SPLASH_STORAGE_NAND:
70 		return splash_nand_read_raw(bmp_load_addr, offset, read_size);
71 	case SPLASH_STORAGE_SF:
72 		return splash_sf_read_raw(bmp_load_addr, offset, read_size);
73 	default:
74 		printf("Unknown splash location\n");
75 	}
76 
77 	return -EINVAL;
78 }
79 
80 static int splash_load_raw(struct splash_location *location, u32 bmp_load_addr)
81 {
82 	struct bmp_header *bmp_hdr;
83 	int res;
84 	size_t bmp_size, bmp_header_size = sizeof(struct bmp_header);
85 
86 	if (bmp_load_addr + bmp_header_size >= gd->start_addr_sp)
87 		goto splash_address_too_high;
88 
89 	res = splash_storage_read_raw(location, bmp_load_addr, bmp_header_size);
90 	if (res < 0)
91 		return res;
92 
93 	bmp_hdr = (struct bmp_header *)bmp_load_addr;
94 	bmp_size = le32_to_cpu(bmp_hdr->file_size);
95 
96 	if (bmp_load_addr + bmp_size >= gd->start_addr_sp)
97 		goto splash_address_too_high;
98 
99 	return splash_storage_read_raw(location, bmp_load_addr, bmp_size);
100 
101 splash_address_too_high:
102 	printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
103 
104 	return -EFAULT;
105 }
106 
107 static int splash_select_fs_dev(struct splash_location *location)
108 {
109 	int res;
110 
111 	switch (location->storage) {
112 	case SPLASH_STORAGE_MMC:
113 		res = fs_set_blk_dev("mmc", location->devpart, FS_TYPE_ANY);
114 		break;
115 	default:
116 		printf("Error: unsupported location storage.\n");
117 		return -ENODEV;
118 	}
119 
120 	if (res)
121 		printf("Error: could not access storage.\n");
122 
123 	return res;
124 }
125 
126 #define SPLASH_SOURCE_DEFAULT_FILE_NAME		"splash.bmp"
127 
128 static int splash_load_fs(struct splash_location *location, u32 bmp_load_addr)
129 {
130 	int res;
131 	loff_t bmp_size;
132 	char *splash_file;
133 
134 	splash_file = getenv("splashfile");
135 	if (!splash_file)
136 		splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
137 
138 	res = splash_select_fs_dev(location);
139 	if (res)
140 		return res;
141 
142 	res = fs_size(splash_file, &bmp_size);
143 	if (res) {
144 		printf("Error (%d): cannot determine file size\n", res);
145 		return res;
146 	}
147 
148 	if (bmp_load_addr + bmp_size >= gd->start_addr_sp) {
149 		printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
150 		return -EFAULT;
151 	}
152 
153 	splash_select_fs_dev(location);
154 	return fs_read(splash_file, bmp_load_addr, 0, 0, NULL);
155 }
156 
157 /**
158  * select_splash_location - return the splash location based on board support
159  *			    and env variable "splashsource".
160  *
161  * @locations:		An array of supported splash locations.
162  * @size:		Size of splash_locations array.
163  *
164  * @return: If a null set of splash locations is given, or
165  *	    splashsource env variable is set to unsupported value
166  *			return NULL.
167  *	    If splashsource env variable is not defined
168  *			return the first entry in splash_locations as default.
169  *	    If splashsource env variable contains a supported value
170  *			return the location selected by splashsource.
171  */
172 static struct splash_location *select_splash_location(
173 			    struct splash_location *locations, uint size)
174 {
175 	int i;
176 	char *env_splashsource;
177 
178 	if (!locations || size == 0)
179 		return NULL;
180 
181 	env_splashsource = getenv("splashsource");
182 	if (env_splashsource == NULL)
183 		return &locations[0];
184 
185 	for (i = 0; i < size; i++) {
186 		if (!strcmp(locations[i].name, env_splashsource))
187 			return &locations[i];
188 	}
189 
190 	printf("splashsource env variable set to unsupported value\n");
191 	return NULL;
192 }
193 
194 /**
195  * splash_source_load - load splash image from a supported location.
196  *
197  * Select a splash image location based on the value of splashsource environment
198  * variable and the board supported splash source locations, and load a
199  * splashimage to the address pointed to by splashimage environment variable.
200  *
201  * @locations:		An array of supported splash locations.
202  * @size:		Size of splash_locations array.
203  *
204  * @return: 0 on success, negative value on failure.
205  */
206 int splash_source_load(struct splash_location *locations, uint size)
207 {
208 	struct splash_location *splash_location;
209 	char *env_splashimage_value;
210 	u32 bmp_load_addr;
211 
212 	env_splashimage_value = getenv("splashimage");
213 	if (env_splashimage_value == NULL)
214 		return -ENOENT;
215 
216 	bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16);
217 	if (bmp_load_addr == 0) {
218 		printf("Error: bad splashimage address specified\n");
219 		return -EFAULT;
220 	}
221 
222 	splash_location = select_splash_location(locations, size);
223 	if (!splash_location)
224 		return -EINVAL;
225 
226 	if (splash_location->flags & SPLASH_STORAGE_RAW)
227 		return splash_load_raw(splash_location, bmp_load_addr);
228 	else if (splash_location->flags & SPLASH_STORAGE_FS)
229 		return splash_load_fs(splash_location, bmp_load_addr);
230 
231 	return -EINVAL;
232 }
233