1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2017 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <common.h>
8 #include <log.h>
9 #include <linux/libfdt.h>
10 #include <dm/of_access.h>
11 #include <dm/of_extra.h>
12 #include <dm/ofnode.h>
13 
ofnode_read_fmap_entry(ofnode node,struct fmap_entry * entry)14 int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry)
15 {
16 	const char *prop;
17 	ofnode subnode;
18 
19 	if (ofnode_read_u32(node, "image-pos", &entry->offset)) {
20 		debug("Node '%s' has bad/missing 'image-pos' property\n",
21 		      ofnode_get_name(node));
22 		return log_msg_ret("image-pos", -ENOENT);
23 	}
24 	if (ofnode_read_u32(node, "size", &entry->length)) {
25 		debug("Node '%s' has bad/missing 'size' property\n",
26 		      ofnode_get_name(node));
27 		return log_msg_ret("size", -ENOENT);
28 	}
29 	entry->used = ofnode_read_s32_default(node, "used", entry->length);
30 	prop = ofnode_read_string(node, "compress");
31 	if (prop) {
32 		if (!strcmp(prop, "lz4"))
33 			entry->compress_algo = FMAP_COMPRESS_LZ4;
34 		else if (!strcmp(prop, "lzma"))
35 			entry->compress_algo = FMAP_COMPRESS_LZMA;
36 		else
37 			return log_msg_ret("compression algo", -EINVAL);
38 	} else {
39 		entry->compress_algo = FMAP_COMPRESS_NONE;
40 	}
41 	entry->unc_length = ofnode_read_s32_default(node, "uncomp-size",
42 						    entry->length);
43 	subnode = ofnode_find_subnode(node, "hash");
44 	if (ofnode_valid(subnode)) {
45 		prop = ofnode_read_prop(subnode, "value", &entry->hash_size);
46 
47 		/* Assume it is sha256 */
48 		entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
49 		entry->hash = (uint8_t *)prop;
50 	}
51 
52 	return 0;
53 }
54 
ofnode_decode_region(ofnode node,const char * prop_name,fdt_addr_t * basep,fdt_size_t * sizep)55 int ofnode_decode_region(ofnode node, const char *prop_name, fdt_addr_t *basep,
56 			 fdt_size_t *sizep)
57 {
58 	const fdt_addr_t *cell;
59 	int len;
60 
61 	debug("%s: %s: %s\n", __func__, ofnode_get_name(node), prop_name);
62 	cell = ofnode_get_property(node, prop_name, &len);
63 	if (!cell || (len < sizeof(fdt_addr_t) * 2)) {
64 		debug("cell=%p, len=%d\n", cell, len);
65 		return -1;
66 	}
67 
68 	*basep = fdt_addr_to_cpu(*cell);
69 	*sizep = fdt_size_to_cpu(cell[1]);
70 	debug("%s: base=%08lx, size=%lx\n", __func__, (ulong)*basep,
71 	      (ulong)*sizep);
72 
73 	return 0;
74 }
75 
ofnode_decode_memory_region(ofnode config_node,const char * mem_type,const char * suffix,fdt_addr_t * basep,fdt_size_t * sizep)76 int ofnode_decode_memory_region(ofnode config_node, const char *mem_type,
77 				const char *suffix, fdt_addr_t *basep,
78 				fdt_size_t *sizep)
79 {
80 	char prop_name[50];
81 	const char *mem;
82 	fdt_size_t size, offset_size;
83 	fdt_addr_t base, offset;
84 	ofnode node;
85 
86 	if (!ofnode_valid(config_node)) {
87 		config_node = ofnode_path("/config");
88 		if (!ofnode_valid(config_node)) {
89 			debug("%s: Cannot find /config node\n", __func__);
90 			return -ENOENT;
91 		}
92 	}
93 	if (!suffix)
94 		suffix = "";
95 
96 	snprintf(prop_name, sizeof(prop_name), "%s-memory%s", mem_type,
97 		 suffix);
98 	mem = ofnode_read_string(config_node, prop_name);
99 	if (!mem) {
100 		debug("%s: No memory type for '%s', using /memory\n", __func__,
101 		      prop_name);
102 		mem = "/memory";
103 	}
104 
105 	node = ofnode_path(mem);
106 	if (!ofnode_valid(node)) {
107 		debug("%s: Failed to find node '%s'\n", __func__, mem);
108 		return -ENOENT;
109 	}
110 
111 	/*
112 	 * Not strictly correct - the memory may have multiple banks. We just
113 	 * use the first
114 	 */
115 	if (ofnode_decode_region(node, "reg", &base, &size)) {
116 		debug("%s: Failed to decode memory region %s\n", __func__,
117 		      mem);
118 		return -EINVAL;
119 	}
120 
121 	snprintf(prop_name, sizeof(prop_name), "%s-offset%s", mem_type,
122 		 suffix);
123 	if (ofnode_decode_region(config_node, prop_name, &offset,
124 				 &offset_size)) {
125 		debug("%s: Failed to decode memory region '%s'\n", __func__,
126 		      prop_name);
127 		return -EINVAL;
128 	}
129 
130 	*basep = base + offset;
131 	*sizep = offset_size;
132 
133 	return 0;
134 }
135 
ofnode_phy_is_fixed_link(ofnode eth_node,ofnode * phy_node)136 bool ofnode_phy_is_fixed_link(ofnode eth_node, ofnode *phy_node)
137 {
138 	ofnode node, subnode;
139 	int len;
140 
141 	subnode = ofnode_find_subnode(eth_node, "fixed-link");
142 	if (ofnode_valid(subnode)) {
143 		/* new binding */
144 		node = subnode;
145 	} else if (ofnode_get_property(eth_node, "fixed-link", &len) &&
146 		   len == (5 * sizeof(__be32))) {
147 		/* old binding */
148 		node = eth_node;
149 	} else {
150 		return false;
151 	}
152 
153 	if (phy_node)
154 		*phy_node = node;
155 
156 	return true;
157 }
158