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/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <stand.h> 34 #include <fdt_platform.h> 35 36 #include "glue.h" 37 38 #define STR(number) #number 39 #define STRINGIFY(number) STR(number) 40 41 static int 42 fdt_platform_load_from_ubenv(const char *var) 43 { 44 struct fdt_header *hdr; 45 const char *s; 46 char *p; 47 48 s = ub_env_get(var); 49 if (s == NULL || *s == '\0') 50 return (1); 51 52 hdr = (struct fdt_header *)strtoul(s, &p, 16); 53 if (*p != '\0') 54 return (1); 55 56 if (fdt_load_dtb_addr(hdr) == 0) { 57 printf("Using DTB provided by U-Boot at " 58 "address %p.\n", hdr); 59 return (0); 60 } 61 62 return (1); 63 } 64 65 #define FDT_DTB_PADSZ 1024 66 67 int 68 fdt_platform_load_dtb(void) 69 { 70 struct fdt_header *hdr; 71 const char *s; 72 char *p; 73 int rv; 74 75 /* 76 * If the U-boot environment contains a variable giving the address of a 77 * valid blob in memory, use it. The U-boot README says the right 78 * variable for fdt data loaded into ram is fdt_addr_r, so try that 79 * first. Board vendors also use both fdtaddr and fdt_addr names. 80 */ 81 if ((rv = fdt_platform_load_from_ubenv("fdt_addr_r")) == 0) 82 goto exit; 83 if ((rv = fdt_platform_load_from_ubenv("fdt_addr")) == 0) 84 goto exit; 85 if ((rv = fdt_platform_load_from_ubenv("fdtaddr")) == 0) 86 goto exit; 87 88 rv = 1; 89 90 /* 91 * Try to get FDT filename first from loader env and then from u-boot env 92 */ 93 s = getenv("fdt_file"); 94 if (s == NULL) 95 s = ub_env_get("fdtfile"); 96 if (s == NULL) 97 s = ub_env_get("fdt_file"); 98 if (s != NULL && *s != '\0') { 99 if (fdt_load_dtb_file(s) == 0) { 100 printf("Loaded DTB from file '%s'.\n", s); 101 rv = 0; 102 goto exit; 103 } 104 } 105 106 exit: 107 return (rv); 108 } 109 110 void 111 fdt_platform_load_overlays(void) 112 { 113 114 fdt_load_dtb_overlays(ub_env_get("fdt_overlays")); 115 } 116 117 void 118 fdt_platform_fixups(void) 119 { 120 static struct fdt_mem_region regions[UB_MAX_MR]; 121 const char *env, *str; 122 char *end, *ethstr; 123 int eth_no, i, len, n; 124 struct sys_info *si; 125 126 env = NULL; 127 eth_no = 0; 128 ethstr = NULL; 129 130 /* Apply overlays before anything else */ 131 if (fdt_apply_overlays() > 0) 132 fdt_pad_dtb(FDT_DTB_PADSZ); 133 134 /* Acquire sys_info */ 135 si = ub_get_sys_info(); 136 137 while ((env = ub_env_enum(env)) != NULL) { 138 if (strncmp(env, "eth", 3) == 0 && 139 strncmp(env + (strlen(env) - 4), "addr", 4) == 0) { 140 /* 141 * Handle Ethernet addrs: parse uboot env eth%daddr 142 */ 143 144 if (!eth_no) { 145 /* 146 * Check how many chars we will need to store 147 * maximal eth iface number. 148 */ 149 len = strlen(STRINGIFY(TMP_MAX_ETH)) + 150 strlen("ethernet") + 1; 151 152 /* 153 * Reserve mem for string "ethernet" and len 154 * chars for iface no. 155 */ 156 ethstr = (char *)malloc(len * sizeof(char)); 157 bzero(ethstr, len * sizeof(char)); 158 strcpy(ethstr, "ethernet0"); 159 } 160 161 /* Extract interface number */ 162 i = strtol(env + 3, &end, 10); 163 if (end == (env + 3)) 164 /* 'ethaddr' means interface 0 address */ 165 n = 0; 166 else 167 n = i; 168 169 if (n > TMP_MAX_ETH) 170 continue; 171 172 str = ub_env_get(env); 173 174 if (n != 0) { 175 /* 176 * Find the length of the interface id by 177 * taking in to account the first 3 and 178 * last 4 characters. 179 */ 180 i = strlen(env) - 7; 181 strncpy(ethstr + 8, env + 3, i); 182 } 183 184 /* Modify blob */ 185 fdt_fixup_ethernet(str, ethstr, len); 186 187 /* Clear ethernet..XXXX.. string */ 188 bzero(ethstr + 8, len - 8); 189 190 if (n + 1 > eth_no) 191 eth_no = n + 1; 192 } else if (strcmp(env, "consoledev") == 0) { 193 str = ub_env_get(env); 194 fdt_fixup_stdout(str); 195 } 196 } 197 198 /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ 199 fdt_fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); 200 201 /* Extract the DRAM regions into fdt_mem_region format. */ 202 for (i = 0, n = 0; i < si->mr_no && n < nitems(regions); i++) { 203 if (si->mr[i].flags == MR_ATTR_DRAM) { 204 regions[n].start = si->mr[i].start; 205 regions[n].size = si->mr[i].size; 206 n++; 207 } 208 } 209 210 /* Fixup memory regions */ 211 fdt_fixup_memory(regions, n); 212 } 213