Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / board-qemu / slof / fdt.fs
1 \ *****************************************************************************
2 \ * Copyright (c) 2011 IBM Corporation
3 \ * All rights reserved.
4 \ * This program and the accompanying materials
5 \ * are made available under the terms of the BSD License
6 \ * which accompanies this distribution, and is available at
7 \ * http://www.opensource.org/licenses/bsd-license.php
8 \ *
9 \ * Contributors:
10 \ *     IBM Corporation - initial implementation
11 \ ****************************************************************************/
12
13 0 VALUE fdt-debug
14 TRUE VALUE fdt-cas-fix?
15
16 \ Bail out if no fdt
17 fdt-start 0 = IF -1 throw THEN
18
19 struct
20   4 field >fdth_magic
21   4 field >fdth_tsize
22   4 field >fdth_struct_off
23   4 field >fdth_string_off
24   4 field >fdth_rsvmap_off
25   4 field >fdth_version
26   4 field >fdth_compat_vers
27   4 field >fdth_boot_cpu
28   4 field >fdth_string_size
29   4 field >fdth_struct_size
30 drop
31
32 h# d00dfeed constant OF_DT_HEADER
33 h#        1 constant OF_DT_BEGIN_NODE
34 h#        2 constant OF_DT_END_NODE
35 h#        3 constant OF_DT_PROP
36 h#        4 constant OF_DT_NOP
37 h#        9 constant OF_DT_END
38
39 \ Create some variables early
40 0 value fdt-start-addr
41 0 value fdt-struct
42 0 value fdt-strings
43
44 : fdt-init ( fdt-start -- )
45     dup to fdt-start-addr
46     dup dup >fdth_struct_off l@ + to fdt-struct
47     dup dup >fdth_string_off l@ + to fdt-strings
48     drop
49 ;
50 fdt-start fdt-init
51
52 \ Dump fdt header for all to see and check FDT validity
53 : fdt-check-header ( -- )
54     fdt-start-addr dup 0 = IF
55         ." No flat device tree !" cr drop -1 throw EXIT THEN
56     hex
57     fdt-debug IF
58         ." Flat device tree header at 0x" dup . s" :" type cr
59         ."  magic            : 0x" dup >fdth_magic l@ . cr
60         ."  total size       : 0x" dup >fdth_tsize l@ . cr
61         ."  offset to struct : 0x" dup >fdth_struct_off l@ . cr
62         ."  offset to strings: 0x" dup >fdth_string_off l@ . cr
63         ."  offset to rsvmap : 0x" dup >fdth_rsvmap_off l@ . cr
64         ."  version          : " dup >fdth_version l@ decimal . hex cr
65         ."  last compat vers : " dup >fdth_compat_vers l@ decimal . hex cr
66         dup >fdth_version l@ 2 >= IF
67             ."  boot CPU         : 0x" dup >fdth_boot_cpu l@ . cr
68         THEN
69         dup >fdth_version l@ 3 >= IF
70             ."  strings size     : 0x" dup >fdth_string_size l@ . cr
71         THEN
72         dup >fdth_version l@ 17 >= IF
73             ."  struct size      : 0x" dup >fdth_struct_size l@ . cr
74         THEN
75     THEN
76     dup >fdth_magic l@ OF_DT_HEADER <> IF
77         ." Flat device tree has incorrect magic value !" cr
78         drop -1 throw EXIT
79     THEN
80     dup >fdth_version l@ 10 < IF
81         ." Flat device tree has usupported version !" cr
82         drop -1 throw EXIT
83     THEN
84
85     drop
86 ;
87 fdt-check-header
88
89 \ Fetch next tag, skip nops and increment address
90 : fdt-next-tag ( addr -- nextaddr tag )
91   0                             ( dummy tag on stack for loop )
92   BEGIN
93     drop                        ( drop previous tag )
94     dup l@                      ( read new tag )
95     swap 4 + swap               ( increment addr )
96   dup OF_DT_NOP <> UNTIL        ( loop until not nop )
97 ;
98
99 \ Parse unit name and advance addr
100 : fdt-fetch-unit ( addr -- addr $name )
101   dup from-cstring             \  get string size
102   2dup + 1 + 3 + fffffffc and -rot
103 ;
104
105 \ Update unit with information from the reg property...
106 \ ... this is required for the PCI nodes for example.
107 : fdt-reg-unit ( prop-addr prop-len -- )
108       decode-phys               ( prop-addr' prop-len' phys.lo ... phys.hi )
109       set-unit                  ( prop-addr' prop-len' )
110       2drop
111 ;
112
113 \ Lookup a string by index
114 : fdt-fetch-string ( index -- str-addr str-len )  
115   fdt-strings + dup from-cstring
116 ;
117
118 : fdt-create-dec  s" decode-unit" $CREATE , DOES> @ hex64-decode-unit ;
119 : fdt-create-enc  s" encode-unit" $CREATE , DOES> @ hex64-encode-unit ;
120
121 \ Check whether array contains an zero-terminated ASCII string:
122 : fdt-prop-is-string?  ( addr len -- string? )
123    dup 1 < IF 2drop FALSE EXIT THEN                \ Check for valid length
124    1-
125    2dup + c@ 0<> IF 2drop FALSE EXIT THEN          \ Check zero-termination
126    test-string
127 ;
128
129 \ Encode fdt property to OF property
130 : fdt-encode-prop  ( addr len -- )
131    2dup fdt-prop-is-string? IF
132       1- encode-string
133    ELSE
134       encode-bytes
135    THEN
136 ;
137
138 \ Method to unflatten a node
139 : fdt-unflatten-node ( start -- end )
140   \ this can and will recurse
141   recursive
142
143   \ Get & check first tag of node ( addr -- addr)
144   fdt-next-tag dup OF_DT_BEGIN_NODE <> IF
145     s" Weird tag 0x" type . " at start of node" type cr
146     -1 throw
147   THEN drop
148
149   new-device
150
151   \ Parse name, split unit address
152   fdt-fetch-unit
153   dup 0 = IF drop drop " /" THEN
154   40 left-parse-string
155   \ Set name
156   device-name
157
158   \ Set preliminary unit address - might get overwritten by reg property
159   dup IF
160      " #address-cells" get-parent get-package-property IF
161         2drop
162      ELSE
163         decode-int nip nip
164         hex-decode-unit
165         set-unit
166      THEN
167   ELSE 2drop THEN
168
169   \ Iterate sub tags
170   BEGIN
171     fdt-next-tag dup OF_DT_END_NODE <>
172   WHILE
173     dup OF_DT_PROP = IF
174       \ Found property
175       drop dup                  ( drop tag, dup addr     : a1 a1 )
176       dup l@ dup rot 4 +        ( fetch size, stack is   : a1 s s a2)
177       dup l@ swap 4 +           ( fetch nameid, stack is : a1 s s i a3 )
178       rot                       ( we now have: a1 s i a3 s )
179       fdt-encode-prop rot       ( a1 s pa ps i)
180       fdt-fetch-string          ( a1 s pa ps na ns )
181       2dup s" reg" str= IF
182           2swap 2dup fdt-reg-unit 2swap
183       THEN
184       property
185       + 8 + 3 + fffffffc and
186     ELSE dup OF_DT_BEGIN_NODE = IF
187       drop                      ( drop tag )
188       4 -
189       fdt-unflatten-node
190     ELSE
191       drop -1 throw
192     THEN THEN
193   REPEAT drop \ drop tag
194
195   \ Create encode/decode unit
196   " #address-cells" get-node get-package-property IF ELSE
197     decode-int dup fdt-create-dec fdt-create-enc 2drop
198   THEN
199
200   finish-device  
201 ;
202
203 \ Start unflattening
204 : fdt-unflatten-tree
205     fdt-debug IF
206         ." Unflattening device tree..." cr THEN
207     fdt-struct fdt-unflatten-node drop
208     fdt-debug IF
209         ." Done !" cr THEN
210 ;
211 fdt-unflatten-tree
212
213 \ Find memory size
214 : fdt-parse-memory
215     \ XXX FIXME Handle more than one memory node, and deal
216     \     with RMA vs. full access
217     " /memory@0" find-device
218     " reg" get-node get-package-property IF throw -1 THEN
219
220     \ XXX FIXME Assume one entry only in "reg" property for now
221     decode-phys 2drop decode-phys
222     my-#address-cells 1 > IF 20 << or THEN
223     
224     fdt-debug IF
225         dup ." Memory size: " . cr
226     THEN
227     \ claim.fs already released the memory between 0 and MIN-RAM-SIZE,
228     \ so we've got only to release the remaining memory now:
229     MIN-RAM-SIZE swap MIN-RAM-SIZE - release
230     2drop device-end
231 ;
232 fdt-parse-memory
233
234
235 \ Claim fdt memory and reserve map
236 : fdt-claim-reserve
237     fdt-start-addr
238     dup dup >fdth_tsize l@ 0 claim drop
239     dup >fdth_rsvmap_off l@ +
240     BEGIN
241         dup dup x@ swap 8 + x@
242         dup 0 <>
243     WHILE
244         fdt-debug IF
245             2dup swap ." Reserve map entry: " . ." : " . cr
246         THEN
247         0 claim drop
248         10 +
249     REPEAT drop drop drop
250 ;
251 fdt-claim-reserve 
252
253
254 \ The following functions are use to replace the FDT phandle and
255 \ linux,phandle properties with our own OF1275 phandles...
256
257 \ This is used to check whether we successfully replaced a phandle value
258 0 VALUE (fdt-phandle-replaced)
259
260 \ Replace phandle value in "interrupt-map" property
261 : fdt-replace-interrupt-map  ( old new prop-addr prop-len -- old new )
262    BEGIN
263       dup                    ( old new prop-addr prop-len prop-len )
264    WHILE
265       \ This is a little bit ugly ... we're accessing the property at
266       \ hard-coded offsets instead of analyzing it completely...
267       swap dup 10 +          ( old new prop-len prop-addr prop-addr+10 )
268       dup l@ 5 pick = IF
269           \ it matches the old phandle value!
270           3 pick swap l!
271           TRUE TO (fdt-phandle-replaced)
272       ELSE
273           drop
274       THEN
275       ( old new prop-len prop-addr )
276       1c + swap 1c -
277       ( old new new-prop-addr new-prop-len )
278    REPEAT
279    2drop
280 ;
281
282 \ Replace one FDT phandle "old" with a OF1275 phandle "new" in the
283 \ whole tree:
284 : fdt-replace-all-phandles ( old new node -- )
285    \ ." Replacing in " dup node>path type cr
286    >r
287    s" interrupt-map" r@ get-property 0= IF
288       ( old new prop-addr prop-len  R: node )
289       fdt-replace-interrupt-map
290    THEN
291    s" interrupt-parent" r@ get-property 0= IF
292       ( old new prop-addr prop-len  R: node )
293       decode-int -rot 2drop                  ( old new val  R: node )
294       2 pick = IF                            ( old new      R: node )
295          dup encode-int s" interrupt-parent" r@ set-property
296          TRUE TO (fdt-phandle-replaced)
297       THEN
298    THEN
299    \ ... add more properties that have to be fixed here ...
300    r>
301    \ Now recurse over all child nodes:       ( old new node )
302    child BEGIN
303       dup
304    WHILE
305       3dup RECURSE
306       PEER
307    REPEAT
308    3drop
309 ;
310
311 \ Check whether a node has "phandle" or "linux,phandle" properties
312 \ and replace them:
313 : fdt-fix-node-phandle  ( node -- )
314    >r
315    FALSE TO (fdt-phandle-replaced)
316    s" phandle" r@ get-property 0= IF
317       decode-int                       ( p-addr2 p-len2 val )
318       \ ." found phandle: " dup . cr
319       r@ s" /" find-node               ( p-addr2 p-len2 val node root )  
320       fdt-replace-all-phandles         ( p-addr2 p-len2 )
321       2drop
322       (fdt-phandle-replaced) IF
323          r@ set-node
324          s" phandle" delete-property
325          s" linux,phandle" delete-property
326       ELSE
327          diagnostic-mode? IF
328             cr ." Warning: Did not replace phandle in " r@ node>path type cr
329          THEN
330       THEN
331    THEN
332    r> drop
333 ;
334
335 \ Recursively walk through all nodes to fix their phandles:
336 : fdt-fix-phandles  ( node -- )
337    \ ." fixing phandles of " dup node>path type cr
338    dup fdt-fix-node-phandle
339    child BEGIN
340       dup
341    WHILE
342       dup RECURSE
343       PEER
344    REPEAT
345    drop
346    device-end
347 ;
348
349 : fdt-create-cas-node ( name  -- )
350     2dup
351     2dup " memory@" find-substr 0 = IF
352         fdt-debug IF ." Creating memory@ " cr THEN
353         new-device
354         2dup " @" find-substr nip device-name       \ Parse the node name
355         2dup
356         2dup " @" find-substr rot over + 1 + -rot - 1 - \ Jump to addr afte "@"
357         parse-2int nip xlsplit set-unit                 \ Parse and set unit
358         finish-device
359     ELSE
360         2dup " ibm,dynamic-reconfiguration-memory" find-substr 0 = IF
361             fdt-debug IF  ." Creating ibm,dynamic-reconfiguration-memory " cr THEN
362             new-device
363             device-name
364             finish-device
365         ELSE
366             2drop 2drop
367             false to fdt-cas-fix?
368             ." Node not supported " cr
369             EXIT
370         THEN
371     THEN
372
373     find-node ?dup 0 <> IF set-node THEN
374 ;
375
376 : fdt-fix-cas-node ( start -- end )
377     recursive
378     fdt-next-tag dup OF_DT_BEGIN_NODE <> IF
379         ." Error " cr
380         false to fdt-cas-fix?
381         EXIT
382     THEN drop
383     fdt-fetch-unit
384     dup 0 = IF drop drop " /" THEN
385     40 left-parse-string
386     2swap ?dup 0 <> IF
387         nip
388         1 + + \ Add the string len +@
389     ELSE
390         drop
391     THEN
392     fdt-debug IF ." Setting node: " 2dup type cr THEN
393     2dup find-node ?dup 0 <> IF
394         set-node 2drop
395     ELSE
396         fdt-debug IF ." Node not found, creating " 2dup type cr THEN
397         fdt-create-cas-node
398     THEN
399     fdt-debug IF ." Current  now: " pwd cr THEN
400     BEGIN
401         fdt-next-tag dup OF_DT_END_NODE <>
402     WHILE
403         dup OF_DT_PROP = IF
404             fdt-debug IF ." Found property " cr THEN
405             drop dup            ( drop tag, dup addr     : a1 a1 )
406             dup l@ dup rot 4 +  ( fetch size, stack is   : a1 s s a2)
407             dup l@ swap 4 +     ( fetch nameid, stack is : a1 s s i a3 )
408             rot                 ( we now have: a1 s i a3 s )
409             fdt-encode-prop rot ( a1 s pa ps i)
410             fdt-fetch-string            ( a1 s pa ps na ns )
411             property
412             fdt-debug IF ." Setting property done " cr THEN
413             + 8 + 3 + fffffffc and
414         ELSE dup OF_DT_BEGIN_NODE = IF
415                 drop                    ( drop tag )
416                 4 -
417                 fdt-fix-cas-node
418                 get-parent set-node
419                 fdt-debug IF ." Returning back " pwd cr THEN
420             ELSE
421                 ." Error " cr
422                 drop
423                 false to fdt-cas-fix?
424                 EXIT
425             THEN
426         THEN
427     REPEAT
428     drop \ drop tag
429 ;
430
431 : fdt-fix-cas-success
432     fdt-cas-fix?
433 ;
434
435 s" /" find-node fdt-fix-phandles