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