Merge branch 'master' of git://www.denx.de/git/u-boot-imx
[platform/kernel/u-boot.git] / common / splash_source.c
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
17 DECLARE_GLOBAL_DATA_PTR;
18
19 #ifdef CONFIG_SPI_FLASH
20 static struct spi_flash *sf;
21 static int splash_sf_read(u32 bmp_load_addr, int offset, size_t read_size)
22 {
23         if (!sf) {
24                 sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
25                                      CONFIG_SF_DEFAULT_CS,
26                                      CONFIG_SF_DEFAULT_SPEED,
27                                      CONFIG_SF_DEFAULT_MODE);
28                 if (!sf)
29                         return -ENODEV;
30         }
31
32         return spi_flash_read(sf, offset, read_size, (void *)bmp_load_addr);
33 }
34 #else
35 static int splash_sf_read(u32 bmp_load_addr, int offset, size_t read_size)
36 {
37         debug("%s: sf support not available\n", __func__);
38         return -ENOSYS;
39 }
40 #endif
41
42 #ifdef CONFIG_CMD_NAND
43 static int splash_nand_read(u32 bmp_load_addr, int offset, size_t read_size)
44 {
45         return nand_read_skip_bad(&nand_info[nand_curr_device], offset,
46                                   &read_size, NULL,
47                                   nand_info[nand_curr_device].size,
48                                   (u_char *)bmp_load_addr);
49 }
50 #else
51 static int splash_nand_read(u32 bmp_load_addr, int offset, size_t read_size)
52 {
53         debug("%s: nand support not available\n", __func__);
54         return -ENOSYS;
55 }
56 #endif
57
58 static int splash_storage_read(struct splash_location *location,
59                                u32 bmp_load_addr, size_t read_size)
60 {
61         u32 offset;
62
63         if (!location)
64                 return -EINVAL;
65
66         offset = location->offset;
67         switch (location->storage) {
68         case SPLASH_STORAGE_NAND:
69                 return splash_nand_read(bmp_load_addr, offset, read_size);
70         case SPLASH_STORAGE_SF:
71                 return splash_sf_read(bmp_load_addr, offset, read_size);
72         default:
73                 printf("Unknown splash location\n");
74         }
75
76         return -EINVAL;
77 }
78
79 static int splash_load_raw(struct splash_location *location, u32 bmp_load_addr)
80 {
81         struct bmp_header *bmp_hdr;
82         int res;
83         size_t bmp_size, bmp_header_size = sizeof(struct bmp_header);
84
85         if (bmp_load_addr + bmp_header_size >= gd->start_addr_sp)
86                 goto splash_address_too_high;
87
88         res = splash_storage_read(location, bmp_load_addr, bmp_header_size);
89         if (res < 0)
90                 return res;
91
92         bmp_hdr = (struct bmp_header *)bmp_load_addr;
93         bmp_size = le32_to_cpu(bmp_hdr->file_size);
94
95         if (bmp_load_addr + bmp_size >= gd->start_addr_sp)
96                 goto splash_address_too_high;
97
98         return splash_storage_read(location, bmp_load_addr, bmp_size);
99
100 splash_address_too_high:
101         printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
102
103         return -EFAULT;
104 }
105
106 /**
107  * select_splash_location - return the splash location based on board support
108  *                          and env variable "splashsource".
109  *
110  * @locations:          An array of supported splash locations.
111  * @size:               Size of splash_locations array.
112  *
113  * @return: If a null set of splash locations is given, or
114  *          splashsource env variable is set to unsupported value
115  *                      return NULL.
116  *          If splashsource env variable is not defined
117  *                      return the first entry in splash_locations as default.
118  *          If splashsource env variable contains a supported value
119  *                      return the location selected by splashsource.
120  */
121 static struct splash_location *select_splash_location(
122                             struct splash_location *locations, uint size)
123 {
124         int i;
125         char *env_splashsource;
126
127         if (!locations || size == 0)
128                 return NULL;
129
130         env_splashsource = getenv("splashsource");
131         if (env_splashsource == NULL)
132                 return &locations[0];
133
134         for (i = 0; i < size; i++) {
135                 if (!strcmp(locations[i].name, env_splashsource))
136                         return &locations[i];
137         }
138
139         printf("splashsource env variable set to unsupported value\n");
140         return NULL;
141 }
142
143 /**
144  * splash_source_load - load splash image from a supported location.
145  *
146  * Select a splash image location based on the value of splashsource environment
147  * variable and the board supported splash source locations, and load a
148  * splashimage to the address pointed to by splashimage environment variable.
149  *
150  * @locations:          An array of supported splash locations.
151  * @size:               Size of splash_locations array.
152  *
153  * @return: 0 on success, negative value on failure.
154  */
155 int splash_source_load(struct splash_location *locations, uint size)
156 {
157         struct splash_location *splash_location;
158         char *env_splashimage_value;
159         u32 bmp_load_addr;
160
161         env_splashimage_value = getenv("splashimage");
162         if (env_splashimage_value == NULL)
163                 return -ENOENT;
164
165         bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16);
166         if (bmp_load_addr == 0) {
167                 printf("Error: bad splashimage address specified\n");
168                 return -EFAULT;
169         }
170
171         splash_location = select_splash_location(locations, size);
172         if (!splash_location)
173                 return -EINVAL;
174
175         return splash_load_raw(splash_location, bmp_load_addr);
176 }