/*-1* Copyright (c) 2009-2010 The FreeBSD Foundation2*3* This software was developed by Semihalf under sponsorship from4* the FreeBSD Foundation.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/param.h>29#include <stand.h>30#include <fdt_platform.h>3132#include "glue.h"3334#define STR(number) #number35#define STRINGIFY(number) STR(number)3637static int38fdt_platform_load_from_ubenv(const char *var)39{40struct fdt_header *hdr;41const char *s;42char *p;4344s = ub_env_get(var);45if (s == NULL || *s == '\0')46return (1);4748hdr = (struct fdt_header *)strtoul(s, &p, 16);49if (*p != '\0')50return (1);5152if (fdt_load_dtb_addr(hdr) == 0) {53printf("Using DTB provided by U-Boot at "54"address %p.\n", hdr);55return (0);56}5758return (1);59}6061#define FDT_DTB_PADSZ 10246263int64fdt_platform_load_dtb(void)65{66struct fdt_header *hdr;67const char *s;68char *p;69int rv;7071/*72* If the U-boot environment contains a variable giving the address of a73* valid blob in memory, use it. The U-boot README says the right74* variable for fdt data loaded into ram is fdt_addr_r, so try that75* first. Board vendors also use both fdtaddr and fdt_addr names.76*/77if ((rv = fdt_platform_load_from_ubenv("fdt_addr_r")) == 0)78goto exit;79if ((rv = fdt_platform_load_from_ubenv("fdt_addr")) == 0)80goto exit;81if ((rv = fdt_platform_load_from_ubenv("fdtaddr")) == 0)82goto exit;8384rv = 1;8586/*87* Try to get FDT filename first from loader env and then from u-boot env88*/89s = getenv("fdt_file");90if (s == NULL)91s = ub_env_get("fdtfile");92if (s == NULL)93s = ub_env_get("fdt_file");94if (s != NULL && *s != '\0') {95if (fdt_load_dtb_file(s) == 0) {96printf("Loaded DTB from file '%s'.\n", s);97rv = 0;98goto exit;99}100}101102exit:103return (rv);104}105106void107fdt_platform_load_overlays(void)108{109110fdt_load_dtb_overlays(ub_env_get("fdt_overlays"));111}112113void114fdt_platform_fixups(void)115{116static struct fdt_mem_region regions[UB_MAX_MR];117const char *env, *str;118char *end, *ethstr;119int eth_no, i, len, n;120struct sys_info *si;121122env = NULL;123eth_no = 0;124ethstr = NULL;125126/* Apply overlays before anything else */127if (fdt_apply_overlays() > 0)128fdt_pad_dtb(FDT_DTB_PADSZ);129130/* Acquire sys_info */131si = ub_get_sys_info();132133while ((env = ub_env_enum(env)) != NULL) {134if (strncmp(env, "eth", 3) == 0 &&135strncmp(env + (strlen(env) - 4), "addr", 4) == 0) {136/*137* Handle Ethernet addrs: parse uboot env eth%daddr138*/139140if (!eth_no) {141/*142* Check how many chars we will need to store143* maximal eth iface number.144*/145len = strlen(STRINGIFY(TMP_MAX_ETH)) +146strlen("ethernet") + 1;147148/*149* Reserve mem for string "ethernet" and len150* chars for iface no.151*/152ethstr = (char *)malloc(len * sizeof(char));153bzero(ethstr, len * sizeof(char));154strcpy(ethstr, "ethernet0");155}156157/* Extract interface number */158i = strtol(env + 3, &end, 10);159if (end == (env + 3))160/* 'ethaddr' means interface 0 address */161n = 0;162else163n = i;164165if (n > TMP_MAX_ETH)166continue;167168str = ub_env_get(env);169170if (n != 0) {171/*172* Find the length of the interface id by173* taking in to account the first 3 and174* last 4 characters.175*/176i = strlen(env) - 7;177strncpy(ethstr + 8, env + 3, i);178}179180/* Modify blob */181fdt_fixup_ethernet(str, ethstr, len);182183/* Clear ethernet..XXXX.. string */184bzero(ethstr + 8, len - 8);185186if (n + 1 > eth_no)187eth_no = n + 1;188} else if (strcmp(env, "consoledev") == 0) {189str = ub_env_get(env);190fdt_fixup_stdout(str);191}192}193194/* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */195fdt_fixup_cpubusfreqs(si->clk_cpu, si->clk_bus);196197/* Extract the DRAM regions into fdt_mem_region format. */198for (i = 0, n = 0; i < si->mr_no && n < nitems(regions); i++) {199if (si->mr[i].flags == MR_ATTR_DRAM) {200regions[n].start = si->mr[i].start;201regions[n].size = si->mr[i].size;202n++;203}204}205206/* Fixup memory regions */207fdt_fixup_memory(regions, n);208}209210211