version: update to 20200717
[SLOF.git] / 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 constant /fdth
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@ 11 >= 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 : (fdt-replace-phandles) ( old new propname propnamelen node -- )
283     get-property IF 2drop EXIT THEN
284     BEGIN
285         dup
286     WHILE                   ( old new prop-addr prop-len )
287         over l@
288         4 pick = IF
289             2 pick 2 pick l! \ replace old with new in place
290             TRUE TO (fdt-phandle-replaced)
291         THEN
292         4 - swap 4 + swap
293     REPEAT
294     2drop 2drop
295 ;
296
297 \ Replace one phandle "old" with a phandle "new" in "node" and recursively
298 \ in its child nodes:
299 : fdt-replace-all-phandles ( old new node -- )
300    \ ." Replacing in " dup node>path type cr
301    >r
302    s" interrupt-map" r@ get-property 0= IF
303       ( old new prop-addr prop-len  R: node )
304       fdt-replace-interrupt-map
305    THEN
306
307    2dup s" interrupt-parent" r@ (fdt-replace-phandles)
308    2dup s" ibm,gpu" r@ (fdt-replace-phandles)
309    2dup s" ibm,npu" r@ (fdt-replace-phandles)
310    2dup s" ibm,nvlink" r@ (fdt-replace-phandles)
311    2dup s" memory-region" r@ (fdt-replace-phandles)
312
313    \ ... add more properties that have to be fixed here ...
314    r>
315    \ Now recurse over all child nodes:       ( old new node )
316    child BEGIN
317       dup
318    WHILE
319       3dup RECURSE
320       PEER
321    REPEAT
322    3drop
323 ;
324
325 \ Replace one FDT phandle "val" with a OF1275 phandle "node" in the
326 \ whole tree:
327 : fdt-update-phandle ( val node -- )
328    >r
329    FALSE TO (fdt-phandle-replaced)
330    r@ s" /" find-node               ( val node root )
331    fdt-replace-all-phandles
332    (fdt-phandle-replaced) IF
333       r@ set-node
334       s" phandle" delete-property
335       s" linux,phandle" delete-property
336    ELSE
337       diagnostic-mode? IF
338          cr ." Warning: Did not replace phandle in " r@ node>path type cr
339       THEN
340    THEN
341 r> drop
342 ;
343
344 \ Check whether a node has "phandle" or "linux,phandle" properties
345 \ and replace them:
346 : fdt-fix-node-phandle  ( node -- )
347    >r
348    s" phandle" r@ get-property 0= IF
349       decode-int nip nip
350       \ ." found phandle: " dup . cr
351       r@ fdt-update-phandle
352    THEN
353    r> drop
354 ;
355
356 \ Recursively walk through all nodes to fix their phandles:
357 : fdt-fix-phandles  ( node -- )
358    \ ." fixing phandles of " dup node>path type cr
359    dup fdt-fix-node-phandle
360    child BEGIN
361       dup
362    WHILE
363       dup RECURSE
364       PEER
365    REPEAT
366    drop
367    device-end
368 ;
369
370 : fdt-create-cas-node ( name  -- )
371     2dup
372     2dup " memory@" find-substr 0 = IF
373         fdt-debug IF ." Creating memory@ " cr THEN
374         new-device
375         2dup " @" find-substr nip device-name       \ Parse the node name
376         2dup
377         2dup " @" find-substr rot over + 1 + -rot - 1 - \ Jump to addr afte "@"
378         parse-2int nip xlsplit set-unit                 \ Parse and set unit
379         finish-device
380     ELSE
381         2dup " ibm,dynamic-reconfiguration-memory" find-substr 0 = IF
382             fdt-debug IF  ." Creating ibm,dynamic-reconfiguration-memory " cr THEN
383             new-device
384             device-name
385             finish-device
386         ELSE
387             2drop 2drop
388             false to fdt-cas-fix?
389             ." Node not supported " cr
390             EXIT
391         THEN
392     THEN
393
394     find-node ?dup 0 <> IF set-node THEN
395 ;
396
397 : fdt-fix-cas-node ( start -- end )
398     recursive
399     fdt-next-tag dup OF_DT_BEGIN_NODE <> IF
400         ." Error " cr
401         false to fdt-cas-fix?
402         EXIT
403     THEN drop
404     fdt-fetch-unit
405     dup 0 = IF drop drop " /" THEN
406     40 left-parse-string
407     2swap ?dup 0 <> IF
408         nip
409         1 + + \ Add the string len +@
410     ELSE
411         drop
412     THEN
413     fdt-debug IF ." Setting node: " 2dup type cr THEN
414     2dup find-node ?dup 0 <> IF
415         set-node 2drop
416     ELSE
417         fdt-debug IF ." Node not found, creating " 2dup type cr THEN
418         fdt-create-cas-node
419     THEN
420     fdt-debug IF ." Current  now: " pwd cr THEN
421     BEGIN
422         fdt-next-tag dup OF_DT_END_NODE <>
423     WHILE
424         dup OF_DT_PROP = IF
425             fdt-debug IF ." Found property " cr THEN
426             drop dup            ( drop tag, dup addr     : a1 a1 )
427             dup l@ dup rot 4 +  ( fetch size, stack is   : a1 s s a2)
428             dup l@ swap 4 +     ( fetch nameid, stack is : a1 s s i a3 )
429             rot                 ( we now have: a1 s i a3 s )
430             fdt-encode-prop rot ( a1 s pa ps i)
431             fdt-fetch-string            ( a1 s pa ps na ns )
432             property
433             fdt-debug IF ." Setting property done " cr THEN
434             + 8 + 3 + fffffffc and
435         ELSE dup OF_DT_BEGIN_NODE = IF
436                 drop                    ( drop tag )
437                 4 -
438                 fdt-fix-cas-node
439                 get-parent set-node
440                 fdt-debug IF ." Returning back " pwd cr THEN
441             ELSE
442                 ." Error " cr
443                 drop
444                 false to fdt-cas-fix?
445                 EXIT
446             THEN
447         THEN
448     REPEAT
449     drop \ drop tag
450 ;
451
452 : fdt-fix-cas-success
453     fdt-cas-fix?
454 ;
455
456 s" /" find-node fdt-fix-phandles