blob: bd94a1b78408a575da840e515d3e39ebc807c260 [file] [log] [blame]
\ *****************************************************************************
\ * Copyright (c) 2011 IBM Corporation
\ * All rights reserved.
\ * This program and the accompanying materials
\ * are made available under the terms of the BSD License
\ * which accompanies this distribution, and is available at
\ * http://www.opensource.org/licenses/bsd-license.php
\ *
\ * Contributors:
\ * IBM Corporation - initial implementation
\ ****************************************************************************/
0 VALUE fdt-debug
TRUE VALUE fdt-cas-fix?
\ Bail out if no fdt
fdt-start 0 = IF -1 throw THEN
struct
4 field >fdth_magic
4 field >fdth_tsize
4 field >fdth_struct_off
4 field >fdth_string_off
4 field >fdth_rsvmap_off
4 field >fdth_version
4 field >fdth_compat_vers
4 field >fdth_boot_cpu
4 field >fdth_string_size
4 field >fdth_struct_size
drop
h# d00dfeed constant OF_DT_HEADER
h# 1 constant OF_DT_BEGIN_NODE
h# 2 constant OF_DT_END_NODE
h# 3 constant OF_DT_PROP
h# 4 constant OF_DT_NOP
h# 9 constant OF_DT_END
\ Create some variables early
0 value fdt-start-addr
0 value fdt-struct
0 value fdt-strings
: fdt-init ( fdt-start -- )
dup to fdt-start-addr
dup dup >fdth_struct_off l@ + to fdt-struct
dup dup >fdth_string_off l@ + to fdt-strings
drop
;
fdt-start fdt-init
\ Dump fdt header for all to see and check FDT validity
: fdt-check-header ( -- )
fdt-start-addr dup 0 = IF
." No flat device tree !" cr drop -1 throw EXIT THEN
hex
fdt-debug IF
." Flat device tree header at 0x" dup . s" :" type cr
." magic : 0x" dup >fdth_magic l@ . cr
." total size : 0x" dup >fdth_tsize l@ . cr
." offset to struct : 0x" dup >fdth_struct_off l@ . cr
." offset to strings: 0x" dup >fdth_string_off l@ . cr
." offset to rsvmap : 0x" dup >fdth_rsvmap_off l@ . cr
." version : " dup >fdth_version l@ decimal . hex cr
." last compat vers : " dup >fdth_compat_vers l@ decimal . hex cr
dup >fdth_version l@ 2 >= IF
." boot CPU : 0x" dup >fdth_boot_cpu l@ . cr
THEN
dup >fdth_version l@ 3 >= IF
." strings size : 0x" dup >fdth_string_size l@ . cr
THEN
dup >fdth_version l@ 17 >= IF
." struct size : 0x" dup >fdth_struct_size l@ . cr
THEN
THEN
dup >fdth_magic l@ OF_DT_HEADER <> IF
." Flat device tree has incorrect magic value !" cr
drop -1 throw EXIT
THEN
dup >fdth_version l@ 10 < IF
." Flat device tree has usupported version !" cr
drop -1 throw EXIT
THEN
drop
;
fdt-check-header
\ Fetch next tag, skip nops and increment address
: fdt-next-tag ( addr -- nextaddr tag )
0 ( dummy tag on stack for loop )
BEGIN
drop ( drop previous tag )
dup l@ ( read new tag )
swap 4 + swap ( increment addr )
dup OF_DT_NOP <> UNTIL ( loop until not nop )
;
\ Parse unit name and advance addr
: fdt-fetch-unit ( addr -- addr $name )
dup from-cstring \ get string size
2dup + 1 + 3 + fffffffc and -rot
;
\ Update unit with information from the reg property...
\ ... this is required for the PCI nodes for example.
: fdt-reg-unit ( prop-addr prop-len -- )
decode-phys ( prop-addr' prop-len' phys.lo ... phys.hi )
set-unit ( prop-addr' prop-len' )
2drop
;
\ Lookup a string by index
: fdt-fetch-string ( index -- str-addr str-len )
fdt-strings + dup from-cstring
;
: fdt-create-dec s" decode-unit" $CREATE , DOES> @ hex64-decode-unit ;
: fdt-create-enc s" encode-unit" $CREATE , DOES> @ hex64-encode-unit ;
\ Check whether array contains an zero-terminated ASCII string:
: fdt-prop-is-string? ( addr len -- string? )
dup 1 < IF 2drop FALSE EXIT THEN \ Check for valid length
1-
2dup + c@ 0<> IF 2drop FALSE EXIT THEN \ Check zero-termination
test-string
;
\ Encode fdt property to OF property
: fdt-encode-prop ( addr len -- )
2dup fdt-prop-is-string? IF
1- encode-string
ELSE
encode-bytes
THEN
;
\ Method to unflatten a node
: fdt-unflatten-node ( start -- end )
\ this can and will recurse
recursive
\ Get & check first tag of node ( addr -- addr)
fdt-next-tag dup OF_DT_BEGIN_NODE <> IF
s" Weird tag 0x" type . " at start of node" type cr
-1 throw
THEN drop
new-device
\ Parse name, split unit address
fdt-fetch-unit
dup 0 = IF drop drop " /" THEN
40 left-parse-string
\ Set name
device-name
\ Set preliminary unit address - might get overwritten by reg property
dup IF
" #address-cells" get-parent get-package-property IF
2drop
ELSE
decode-int nip nip
hex-decode-unit
set-unit
THEN
ELSE 2drop THEN
\ Iterate sub tags
BEGIN
fdt-next-tag dup OF_DT_END_NODE <>
WHILE
dup OF_DT_PROP = IF
\ Found property
drop dup ( drop tag, dup addr : a1 a1 )
dup l@ dup rot 4 + ( fetch size, stack is : a1 s s a2)
dup l@ swap 4 + ( fetch nameid, stack is : a1 s s i a3 )
rot ( we now have: a1 s i a3 s )
fdt-encode-prop rot ( a1 s pa ps i)
fdt-fetch-string ( a1 s pa ps na ns )
2dup s" reg" str= IF
2swap 2dup fdt-reg-unit 2swap
THEN
property
+ 8 + 3 + fffffffc and
ELSE dup OF_DT_BEGIN_NODE = IF
drop ( drop tag )
4 -
fdt-unflatten-node
ELSE
drop -1 throw
THEN THEN
REPEAT drop \ drop tag
\ Create encode/decode unit
" #address-cells" get-node get-package-property IF ELSE
decode-int dup fdt-create-dec fdt-create-enc 2drop
THEN
finish-device
;
\ Start unflattening
: fdt-unflatten-tree
fdt-debug IF
." Unflattening device tree..." cr THEN
fdt-struct fdt-unflatten-node drop
fdt-debug IF
." Done !" cr THEN
;
fdt-unflatten-tree
\ Find memory size
: fdt-parse-memory
\ XXX FIXME Handle more than one memory node, and deal
\ with RMA vs. full access
" /memory@0" find-device
" reg" get-node get-package-property IF throw -1 THEN
\ XXX FIXME Assume one entry only in "reg" property for now
decode-phys 2drop decode-phys
my-#address-cells 1 > IF 20 << or THEN
fdt-debug IF
dup ." Memory size: " . cr
THEN
\ claim.fs already released the memory between 0 and MIN-RAM-SIZE,
\ so we've got only to release the remaining memory now:
MIN-RAM-SIZE swap MIN-RAM-SIZE - release
2drop device-end
;
fdt-parse-memory
\ Claim fdt memory and reserve map
: fdt-claim-reserve
fdt-start-addr
dup dup >fdth_tsize l@ 0 claim drop
dup >fdth_rsvmap_off l@ +
BEGIN
dup dup x@ swap 8 + x@
dup 0 <>
WHILE
fdt-debug IF
2dup swap ." Reserve map entry: " . ." : " . cr
THEN
0 claim drop
10 +
REPEAT drop drop drop
;
fdt-claim-reserve
\ The following functions are use to replace the FDT phandle and
\ linux,phandle properties with our own OF1275 phandles...
\ This is used to check whether we successfully replaced a phandle value
0 VALUE (fdt-phandle-replaced)
\ Replace phandle value in "interrupt-map" property
: fdt-replace-interrupt-map ( old new prop-addr prop-len -- old new )
BEGIN
dup ( old new prop-addr prop-len prop-len )
WHILE
\ This is a little bit ugly ... we're accessing the property at
\ hard-coded offsets instead of analyzing it completely...
swap dup 10 + ( old new prop-len prop-addr prop-addr+10 )
dup l@ 5 pick = IF
\ it matches the old phandle value!
3 pick swap l!
TRUE TO (fdt-phandle-replaced)
ELSE
drop
THEN
( old new prop-len prop-addr )
1c + swap 1c -
( old new new-prop-addr new-prop-len )
REPEAT
2drop
;
\ Replace one FDT phandle "old" with a OF1275 phandle "new" in the
\ whole tree:
: fdt-replace-all-phandles ( old new node -- )
\ ." Replacing in " dup node>path type cr
>r
s" interrupt-map" r@ get-property 0= IF
( old new prop-addr prop-len R: node )
fdt-replace-interrupt-map
THEN
s" interrupt-parent" r@ get-property 0= IF
( old new prop-addr prop-len R: node )
decode-int -rot 2drop ( old new val R: node )
2 pick = IF ( old new R: node )
dup encode-int s" interrupt-parent" r@ set-property
TRUE TO (fdt-phandle-replaced)
THEN
THEN
\ ... add more properties that have to be fixed here ...
r>
\ Now recurse over all child nodes: ( old new node )
child BEGIN
dup
WHILE
3dup RECURSE
PEER
REPEAT
3drop
;
\ Check whether a node has "phandle" or "linux,phandle" properties
\ and replace them:
: fdt-fix-node-phandle ( node -- )
>r
FALSE TO (fdt-phandle-replaced)
s" phandle" r@ get-property 0= IF
decode-int ( p-addr2 p-len2 val )
\ ." found phandle: " dup . cr
r@ s" /" find-node ( p-addr2 p-len2 val node root )
fdt-replace-all-phandles ( p-addr2 p-len2 )
2drop
(fdt-phandle-replaced) IF
r@ set-node
s" phandle" delete-property
s" linux,phandle" delete-property
ELSE
diagnostic-mode? IF
cr ." Warning: Did not replace phandle in " r@ node>path type cr
THEN
THEN
THEN
r> drop
;
\ Recursively walk through all nodes to fix their phandles:
: fdt-fix-phandles ( node -- )
\ ." fixing phandles of " dup node>path type cr
dup fdt-fix-node-phandle
child BEGIN
dup
WHILE
dup RECURSE
PEER
REPEAT
drop
device-end
;
: fdt-fix-cas-node ( start -- end )
recursive
fdt-next-tag dup OF_DT_BEGIN_NODE <> IF
." Error " cr
false to fdt-cas-fix?
EXIT
THEN drop
fdt-fetch-unit
dup 0 = IF drop drop " /" THEN
40 left-parse-string
2swap ?dup 0 <> IF
nip
1 + + \ Add the string len +@
ELSE
drop
THEN
fdt-debug IF ." Setting node: " 2dup type cr THEN
find-node ?dup 0 <> IF
set-node
ELSE
." Node not found " cr
false to fdt-cas-fix?
EXIT
THEN
fdt-debug IF ." Current now: " pwd cr THEN
BEGIN
fdt-next-tag dup OF_DT_END_NODE <>
WHILE
dup OF_DT_PROP = IF
fdt-debug IF ." Found property " cr THEN
drop dup ( drop tag, dup addr : a1 a1 )
dup l@ dup rot 4 + ( fetch size, stack is : a1 s s a2)
dup l@ swap 4 + ( fetch nameid, stack is : a1 s s i a3 )
rot ( we now have: a1 s i a3 s )
fdt-encode-prop rot ( a1 s pa ps i)
fdt-fetch-string ( a1 s pa ps na ns )
property
fdt-debug IF ." Setting property done " cr THEN
+ 8 + 3 + fffffffc and
ELSE dup OF_DT_BEGIN_NODE = IF
drop ( drop tag )
4 -
fdt-fix-cas-node
get-parent set-node
fdt-debug IF ." Returning back " pwd cr THEN
ELSE
." Error " cr
drop
false to fdt-cas-fix?
EXIT
THEN
THEN
REPEAT
drop \ drop tag
;
: fdt-fix-cas-success
fdt-cas-fix?
;
s" /" find-node fdt-fix-phandles