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