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