1 /*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * 4 * This software was developed by Semihalf under sponsorship from 5 * the FreeBSD Foundation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <stand.h> 31 #include <fdt_platform.h> 32 33 #include "glue.h" 34 35 #define STR(number) #number 36 #define STRINGIFY(number) STR(number) 37 38 static int 39 fdt_platform_load_from_ubenv(const char *var) 40 { 41 struct fdt_header *hdr; 42 const char *s; 43 char *p; 44 45 s = ub_env_get(var); 46 if (s == NULL || *s == '\0') 47 return (1); 48 49 hdr = (struct fdt_header *)strtoul(s, &p, 16); 50 if (*p != '\0') 51 return (1); 52 53 if (fdt_load_dtb_addr(hdr) == 0) { 54 printf("Using DTB provided by U-Boot at " 55 "address %p.\n", hdr); 56 return (0); 57 } 58 59 return (1); 60 } 61 62 #define FDT_DTB_PADSZ 1024 63 64 int 65 fdt_platform_load_dtb(void) 66 { 67 struct fdt_header *hdr; 68 const char *s; 69 char *p; 70 int rv; 71 72 /* 73 * If the U-boot environment contains a variable giving the address of a 74 * valid blob in memory, use it. The U-boot README says the right 75 * variable for fdt data loaded into ram is fdt_addr_r, so try that 76 * first. Board vendors also use both fdtaddr and fdt_addr names. 77 */ 78 if ((rv = fdt_platform_load_from_ubenv("fdt_addr_r")) == 0) 79 goto exit; 80 if ((rv = fdt_platform_load_from_ubenv("fdt_addr")) == 0) 81 goto exit; 82 if ((rv = fdt_platform_load_from_ubenv("fdtaddr")) == 0) 83 goto exit; 84 85 rv = 1; 86 87 /* 88 * Try to get FDT filename first from loader env and then from u-boot env 89 */ 90 s = getenv("fdt_file"); 91 if (s == NULL) 92 s = ub_env_get("fdtfile"); 93 if (s == NULL) 94 s = ub_env_get("fdt_file"); 95 if (s != NULL && *s != '\0') { 96 if (fdt_load_dtb_file(s) == 0) { 97 printf("Loaded DTB from file '%s'.\n", s); 98 rv = 0; 99 goto exit; 100 } 101 } 102 103 exit: 104 return (rv); 105 } 106 107 void 108 fdt_platform_load_overlays(void) 109 { 110 111 fdt_load_dtb_overlays(ub_env_get("fdt_overlays")); 112 } 113 114 void 115 fdt_platform_fixups(void) 116 { 117 static struct fdt_mem_region regions[UB_MAX_MR]; 118 const char *env, *str; 119 char *end, *ethstr; 120 int eth_no, i, len, n; 121 struct sys_info *si; 122 123 env = NULL; 124 eth_no = 0; 125 ethstr = NULL; 126 127 /* Apply overlays before anything else */ 128 if (fdt_apply_overlays() > 0) 129 fdt_pad_dtb(FDT_DTB_PADSZ); 130 131 /* Acquire sys_info */ 132 si = ub_get_sys_info(); 133 134 while ((env = ub_env_enum(env)) != NULL) { 135 if (strncmp(env, "eth", 3) == 0 && 136 strncmp(env + (strlen(env) - 4), "addr", 4) == 0) { 137 /* 138 * Handle Ethernet addrs: parse uboot env eth%daddr 139 */ 140 141 if (!eth_no) { 142 /* 143 * Check how many chars we will need to store 144 * maximal eth iface number. 145 */ 146 len = strlen(STRINGIFY(TMP_MAX_ETH)) + 147 strlen("ethernet") + 1; 148 149 /* 150 * Reserve mem for string "ethernet" and len 151 * chars for iface no. 152 */ 153 ethstr = (char *)malloc(len * sizeof(char)); 154 bzero(ethstr, len * sizeof(char)); 155 strcpy(ethstr, "ethernet0"); 156 } 157 158 /* Extract interface number */ 159 i = strtol(env + 3, &end, 10); 160 if (end == (env + 3)) 161 /* 'ethaddr' means interface 0 address */ 162 n = 0; 163 else 164 n = i; 165 166 if (n > TMP_MAX_ETH) 167 continue; 168 169 str = ub_env_get(env); 170 171 if (n != 0) { 172 /* 173 * Find the length of the interface id by 174 * taking in to account the first 3 and 175 * last 4 characters. 176 */ 177 i = strlen(env) - 7; 178 strncpy(ethstr + 8, env + 3, i); 179 } 180 181 /* Modify blob */ 182 fdt_fixup_ethernet(str, ethstr, len); 183 184 /* Clear ethernet..XXXX.. string */ 185 bzero(ethstr + 8, len - 8); 186 187 if (n + 1 > eth_no) 188 eth_no = n + 1; 189 } else if (strcmp(env, "consoledev") == 0) { 190 str = ub_env_get(env); 191 fdt_fixup_stdout(str); 192 } 193 } 194 195 /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ 196 fdt_fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); 197 198 /* Extract the DRAM regions into fdt_mem_region format. */ 199 for (i = 0, n = 0; i < si->mr_no && n < nitems(regions); i++) { 200 if (si->mr[i].flags == MR_ATTR_DRAM) { 201 regions[n].start = si->mr[i].start; 202 regions[n].size = si->mr[i].size; 203 n++; 204 } 205 } 206 207 /* Fixup memory regions */ 208 fdt_fixup_memory(regions, n); 209 } 210