1273934Sandrew/*- 2273934Sandrew * Copyright (c) 2009-2010 The FreeBSD Foundation 3273934Sandrew * All rights reserved. 4273934Sandrew * 5273934Sandrew * This software was developed by Semihalf under sponsorship from 6273934Sandrew * the FreeBSD Foundation. 7273934Sandrew * 8273934Sandrew * Redistribution and use in source and binary forms, with or without 9273934Sandrew * modification, are permitted provided that the following conditions 10273934Sandrew * are met: 11273934Sandrew * 1. Redistributions of source code must retain the above copyright 12273934Sandrew * notice, this list of conditions and the following disclaimer. 13273934Sandrew * 2. Redistributions in binary form must reproduce the above copyright 14273934Sandrew * notice, this list of conditions and the following disclaimer in the 15273934Sandrew * documentation and/or other materials provided with the distribution. 16273934Sandrew * 17273934Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18273934Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19273934Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20273934Sandrew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21273934Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22273934Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23273934Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24273934Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25273934Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26273934Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27273934Sandrew * SUCH DAMAGE. 28273934Sandrew */ 29273934Sandrew 30273934Sandrew#include <sys/cdefs.h> 31273934Sandrew__FBSDID("$FreeBSD$"); 32273934Sandrew 33273934Sandrew#include <sys/param.h> 34273934Sandrew#include <stand.h> 35273934Sandrew#include <fdt_platform.h> 36273934Sandrew 37273934Sandrew#include "glue.h" 38273934Sandrew 39273934Sandrew#define STR(number) #number 40273934Sandrew#define STRINGIFY(number) STR(number) 41273934Sandrew 42273934Sandrewint 43273934Sandrewfdt_platform_load_dtb(void) 44273934Sandrew{ 45273934Sandrew struct fdt_header *hdr; 46273934Sandrew const char *s; 47273934Sandrew char *p; 48273934Sandrew 49273934Sandrew /* 50273934Sandrew * If the U-boot environment contains a variable giving the address of a 51273934Sandrew * valid blob in memory, use it. The U-boot README says the right 52273934Sandrew * variable for fdt data loaded into ram is fdt_addr_r, so try that 53273934Sandrew * first. Board vendors also use both fdtaddr and fdt_addr names. 54273934Sandrew */ 55273934Sandrew s = ub_env_get("fdt_addr_r"); 56273934Sandrew if (s == NULL) 57273934Sandrew s = ub_env_get("fdtaddr"); 58273934Sandrew if (s == NULL) 59273934Sandrew s = ub_env_get("fdt_addr"); 60273934Sandrew if (s != NULL && *s != '\0') { 61273934Sandrew hdr = (struct fdt_header *)strtoul(s, &p, 16); 62273934Sandrew if (*p == '\0') { 63273934Sandrew if (fdt_load_dtb_addr(hdr) == 0) { 64273934Sandrew printf("Using DTB provided by U-Boot at " 65273934Sandrew "address %p.\n", hdr); 66273934Sandrew return (0); 67273934Sandrew } 68273934Sandrew } 69273934Sandrew } 70273934Sandrew 71273934Sandrew /* 72273934Sandrew * If the U-boot environment contains a variable giving the name of a 73273934Sandrew * file, use it if we can load and validate it. 74273934Sandrew */ 75273934Sandrew s = ub_env_get("fdtfile"); 76273934Sandrew if (s == NULL) 77273934Sandrew s = ub_env_get("fdt_file"); 78273934Sandrew if (s != NULL && *s != '\0') { 79273934Sandrew if (fdt_load_dtb_file(s) == 0) { 80273934Sandrew printf("Loaded DTB from file '%s'.\n", s); 81273934Sandrew return (0); 82273934Sandrew } 83273934Sandrew } 84273934Sandrew 85273934Sandrew return (1); 86273934Sandrew} 87273934Sandrew 88273934Sandrewvoid 89273934Sandrewfdt_platform_fixups(void) 90273934Sandrew{ 91283409Sian static struct fdt_mem_region regions[UB_MAX_MR]; 92273934Sandrew const char *env, *str; 93273934Sandrew char *end, *ethstr; 94273934Sandrew int eth_no, i, len, n; 95273934Sandrew struct sys_info *si; 96273934Sandrew 97273934Sandrew env = NULL; 98273934Sandrew eth_no = 0; 99273934Sandrew ethstr = NULL; 100273934Sandrew 101273934Sandrew /* Acquire sys_info */ 102273934Sandrew si = ub_get_sys_info(); 103273934Sandrew 104273934Sandrew while ((env = ub_env_enum(env)) != NULL) { 105273934Sandrew if (strncmp(env, "eth", 3) == 0 && 106273934Sandrew strncmp(env + (strlen(env) - 4), "addr", 4) == 0) { 107273934Sandrew /* 108273934Sandrew * Handle Ethernet addrs: parse uboot env eth%daddr 109273934Sandrew */ 110273934Sandrew 111273934Sandrew if (!eth_no) { 112273934Sandrew /* 113273934Sandrew * Check how many chars we will need to store 114273934Sandrew * maximal eth iface number. 115273934Sandrew */ 116273934Sandrew len = strlen(STRINGIFY(TMP_MAX_ETH)) + 117273934Sandrew strlen("ethernet") + 1; 118273934Sandrew 119273934Sandrew /* 120273934Sandrew * Reserve mem for string "ethernet" and len 121273934Sandrew * chars for iface no. 122273934Sandrew */ 123273934Sandrew ethstr = (char *)malloc(len * sizeof(char)); 124273934Sandrew bzero(ethstr, len * sizeof(char)); 125273934Sandrew strcpy(ethstr, "ethernet0"); 126273934Sandrew } 127273934Sandrew 128273934Sandrew /* Extract interface number */ 129273934Sandrew i = strtol(env + 3, &end, 10); 130273934Sandrew if (end == (env + 3)) 131273934Sandrew /* 'ethaddr' means interface 0 address */ 132273934Sandrew n = 0; 133273934Sandrew else 134273934Sandrew n = i; 135273934Sandrew 136273934Sandrew if (n > TMP_MAX_ETH) 137273934Sandrew continue; 138273934Sandrew 139273934Sandrew str = ub_env_get(env); 140273934Sandrew 141273934Sandrew if (n != 0) { 142273934Sandrew /* 143273934Sandrew * Find the lenght of the interface id by 144273934Sandrew * taking in to account the first 3 and 145273934Sandrew * last 4 characters. 146273934Sandrew */ 147273934Sandrew i = strlen(env) - 7; 148273934Sandrew strncpy(ethstr + 8, env + 3, i); 149273934Sandrew } 150273934Sandrew 151273934Sandrew /* Modify blob */ 152273934Sandrew fdt_fixup_ethernet(str, ethstr, len); 153273934Sandrew 154273934Sandrew /* Clear ethernet..XXXX.. string */ 155273934Sandrew bzero(ethstr + 8, len - 8); 156273934Sandrew 157273934Sandrew if (n + 1 > eth_no) 158273934Sandrew eth_no = n + 1; 159273934Sandrew } else if (strcmp(env, "consoledev") == 0) { 160273934Sandrew str = ub_env_get(env); 161273934Sandrew fdt_fixup_stdout(str); 162273934Sandrew } 163273934Sandrew } 164273934Sandrew 165273934Sandrew /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ 166273934Sandrew fdt_fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); 167273934Sandrew 168283409Sian /* Extract the DRAM regions into fdt_mem_region format. */ 169283409Sian for (i = 0, n = 0; i < si->mr_no && n < nitems(regions); i++) { 170283409Sian if (si->mr[i].flags == MR_ATTR_DRAM) { 171283409Sian regions[n].start = si->mr[i].start; 172283409Sian regions[n].size = si->mr[i].size; 173283409Sian n++; 174273934Sandrew } 175273934Sandrew } 176273934Sandrew 177273934Sandrew /* Fixup memory regions */ 178283409Sian fdt_fixup_memory(regions, n); 179273934Sandrew} 180