1 /*
2  *   Creation Date: <2003/11/18 14:55:05 samuel>
3  *   Time-stamp: <2004/03/27 02:03:55 samuel>
4  *
5  *	<tree.c>
6  *
7  *	device tree setup
8  *
9  *   Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
10  *
11  *   This program is free software; you can redistribute it and/or
12  *   modify it under the terms of the GNU General Public License
13  *   version 2
14  *
15  */
16 
17 #include "config.h"
18 #include "libopenbios/bindings.h"
19 #include "mol/mol.h"
20 #include "mol/prom.h"
21 
22 
23 /************************************************************************/
24 /*	copy device tree						*/
25 /************************************************************************/
26 
27 static void
copy_node(mol_phandle_t molph)28 copy_node( mol_phandle_t molph )
29 {
30 	char name[40], path[80];
31 	int exists;
32 	phandle_t ph;
33 
34 	if( !molph )
35 		return;
36 
37 	prom_package_to_path( molph, path, sizeof(path) );
38 
39 	/* don't copy /options node */
40 	if( !strcmp("/options", path) ) {
41 		copy_node( prom_peer(molph) );
42 		return;
43 	}
44 
45 	exists = 1;
46 	if( !(ph=find_dev(path)) ) {
47 		exists = 0;
48 		fword("new-device");
49 		ph = get_cur_dev();
50 	}
51 	activate_dev( ph );
52 
53 	name[0] = 0;
54 	while( prom_next_prop(molph, name, name) > 0 ) {
55 		int len = prom_get_prop_len( molph, name );
56 		char *p;
57 #if 0
58 		if( len > 0x1000 ) {
59 			printk("prop to large (%d)\n", len );
60 			continue;
61 		}
62 #endif
63 		/* don't copy /chosen/{stdin,stdout} (XXX: ugly hack...) */
64 		if( !strcmp("/chosen", path) )
65 			if( !strcmp("stdio", name) || !strcmp("stdout", name) )
66 				continue;
67 
68 		p = malloc( len );
69 		prom_get_prop( molph, name, p, len );
70 		set_property( ph, name, p, len );
71 		free( p );
72 	}
73 
74 	set_int_property( ph, "MOL,phandle", molph );
75 	copy_node( prom_child(molph) );
76 
77 	if( !exists )
78 		fword("finish-device");
79 	else
80 		activate_device("..");
81 
82 	copy_node( prom_peer(molph) );
83 }
84 
85 
86 
87 /************************************************************************/
88 /*	device tree cloning and tweaking				*/
89 /************************************************************************/
90 
91 static phandle_t
translate_molph(mol_phandle_t molph)92 translate_molph( mol_phandle_t molph )
93 {
94 	static mol_phandle_t cached_molph;
95 	static phandle_t cached_ph;
96 	phandle_t ph=0;
97 
98 	if( cached_molph == molph )
99 		return cached_ph;
100 
101 	while( (ph=dt_iterate(ph)) )
102 		if( get_int_property(ph, "MOL,phandle", NULL) == molph )
103 			break;
104 	cached_molph = molph;
105 	cached_ph = ph;
106 
107 	if( !ph )
108 		printk("failed to translate molph\n");
109 	return ph;
110 }
111 
112 static void
fix_phandles(void)113 fix_phandles( void )
114 {
115 	static char *pnames[] = { "interrupt-parent", "interrupt-controller", NULL } ;
116 	int len, *map;
117 	phandle_t ph=0;
118 	char **pp;
119 
120 	while( (ph=dt_iterate(ph)) ) {
121 		for( pp=pnames; *pp; pp++ ) {
122 			phandle_t *p = (phandle_t*)get_property( ph, *pp, &len );
123 			if( len == 4 )
124 				*p = translate_molph( *(int*)p );
125 		}
126 
127 		/* need to fix interrupt map properties too */
128 		if( (map=(int*)get_property(ph, "interrupt-map", &len)) ) {
129 			int i, acells = get_int_property(ph, "#address-cells", NULL);
130 			int icells = get_int_property(ph, "#interrupt-cells", NULL);
131 
132 			len /= sizeof(int);
133 			for( i=0; i<len; i++ ) {
134 				phandle_t ch_ph;
135 				int ch_acells, ch_icells;
136 
137 				i += acells + icells;
138 				if( !(ch_ph=translate_molph(map[i])) )
139 					break;
140 				map[i] = (int)ch_ph;
141 				ch_acells = get_int_property(ch_ph, "#address-cells", NULL);
142 				ch_icells = get_int_property(ch_ph, "#interrupt-cells", NULL);
143 				i += ch_acells + icells;
144 			}
145 			if( i != len )
146 				printk("interrupt map fixing failure\n");
147 		}
148 	}
149 	/* delete MOL,phandle properties */
150 	for( ph=0; (ph=dt_iterate(ph)) ; ) {
151 		push_str("MOL,phandle");
152 		PUSH_ph(ph);
153 		fword("(delete-property)");
154 	}
155 	fword("device-end");
156 }
157 
158 void
devtree_init(void)159 devtree_init( void )
160 {
161 	activate_device("/");
162 	copy_node( prom_peer(0) );
163 	fix_phandles();
164 	fword("tree-fixes");
165 }
166