Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / ppc / mol / tree.c
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
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
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
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
159 devtree_init( void )
160 {
161         activate_device("/");
162         copy_node( prom_peer(0) );
163         fix_phandles();
164         fword("tree-fixes");
165 }