XO 4 Memory Test

Jump to: navigation, search

The following information is only needed for debugging the timing parameters for a new DDR3 DRAM for the XO-4 laptop.

Memory Configuration

You will need a serial cable attached to the laptop's host serial port. Hold down the "rotate" key (near the screen) while booting the laptop, in order to stop the boot in CForth. You should see something like:

CForth built 2012-08-16 02:20 from commit e000ecca...
Skipping OFW

Some versions of OFW (Q7A00 through Q7A06) automatically initialize the memory controllers before providing the prompt. You cannot change timing parameters using these versions. More details below.

CForth has a table with most of the memory configuration parameters loaded in memory, which you can modify. You can see a listing of this table using the ".table" command. The first column is the actual address in memory of that row of the table. The second column is the value being written to a configuration register. The third column is the offset, relative to the memory controller base address, of the configuration register being written.

ok .table
d100dbc0 :    e0001       10
d100dbc8 :    42530       20
d100dbd0 :        0       30
d100dbd8 : 911403cf       80
d100dbe0 : 64660784       84
d100dbe8 : c2004453       88
d100dbf0 : 34f4a187       8c
d100dbf8 :    f20c1       90
d100dc00 :  4040200       94
d100dc08 :     5501       98
d100dc10 :        0       50
d100dc18 :        0       54
d100dc20 : 20c08009       58
d100dc28 :      201       5c
d100dc30 :  200000a       60
d100dc38 :        0       64
d100dc40 :        0       68
d100dc48 :   300008      240
d100dc50 : 80000000      24c
d100dc58 :     31d8      23c
d100dc60 : 20004055      220
d100dc68 : 1ff84a79      230
d100dc70 :  ff00a70      234
d100dc78 :       a7      238
d100dc80 : f0210000      248
d100dc88 :        0      300
d100dc90 :     1080      304
d100dc98 :        1      300
d100dca0 :     1080      304
d100dca8 :        2      300
d100dcb0 :     1080      304
d100dcb8 :        3      300
d100dcc0 :     1080      304
d100dcc8 :      100      380
d100dcd0 :      200      390
d100dcd8 :      101      380
d100dce0 :      200      390
d100dce8 :      102      380
d100dcf0 :      200      390
d100dcf8 :      103      380
d100dd00 :      200      390

The offset is relative to the memory controller base address which is 0xd001.0000 for memory controller 0 and 0xd000.0000 for memory controller 1. The table values are first written to memory controller 0, then its DLL is initialized, and then the process is repeated for memory controller 1. Finally, the interleave is configured by writing to the DDR_ILV_CTRL register at 0xd4282ca0 . See the Forth word "init-dram" for details (cforth/src/app/arm-xo-cl4/initdram.fth). It is usually called indirectly, by calling late-init.


After modifying the table, you can initialize the memory using the "late-init" (this calls init-dram after setting the freqs). You can then either test the memory or start OFW using the "ofw" command.

The memory may only be initialized once. late-init (init-dram) only works the first time (it doesn't even try after that). To test a different memory configuration you need to power cycle the laptop.

Some versions of OFW (Q7A00 through Q7A06) automatically initialize the memory controllers before providing the prompt. You do not need to type the late-init command with them. Typing it will have no effect. You cannot change timing parameters using these versions. Address mapping and interleave, however, may still be changed.

Testing 1Gb DDR3 Parts

One example of this is testing a particular new 1Gb DDR3 part, instead of the 2Gb parts the above table was generated for. To do this, first modify the relevant parts of the table (the first two entries):

ok  d0001 d100dbc0 l!
ok  42430 d100dbc8 l!

Then initialize both DRAM controllers using late-init. Don't forget to set the interleave to something smaller than the amount of memory. And then you can start OFW and boot Linux. This will need to be repeated on each boot.

ok  late-init
ok  2 d4282ca0 l!
ok  ofw

Direct mucking about

If you are just modifying an address mapping, interleave, or invalidating a chip select to disable a controller, you can directly modify the memory controller and CPU control registers even if the memory controllers have already been initialized.

You can modify memory controller registers using the mc! (write) and mc@ (read) commands in CForth:

value offset memory_controller mc!
offset memory_controller mc@

These take an argument of 0 or 1 to identify the memory controller.

Single Memory Controller

Starting with Q7A07, late-init uses a variable ( #mcs ) to determine how many memory controllers to initialize.

You can configure your laptop to use a single memory controller (the default is two) by setting this variable to 1 before booting. Stop in CForth by holding down the rotate key before powering up the laptop, then on the serial console type:

ok  1 to #mcs
ok  late-init ofw

Boot should proceed normally, but with half as much memory as is normal.


The memory interleave register (DDR_INTERLEAVE_CONTROL) determines the boundary upon which memory controllers are interleaved in the address space. It is located at address 0xD4282CA0. It is a bit field set to zero to disable interleave (not recommended when using two controllers). Bit 0 selects interleaving on a 4KB boundary, bit 1 interleaving on a 16KB boundary, bit 2 a 64 KB boundary, bit 3 a 256 KB boundary, bit 4 a 1024KB boundary, bit 5 a 512 MB boundary, and bit 6 a 1 GB boundary.

For example, to change the system to interleave between memory controllers on a 256KB boundary, type:

ok  8 d4282ca0 l!

And to disable one of the memory controllers, type:

ok  0 d4282ca0 l!
ok  0 10 0 mc!

This sets the interleave to zero, then disables memory controller 0.

SP Memory Addressing

Beware that CForth runs on the SoCs security processor (SP), using physical addressing. The SP's memory addressing is a little strange relative to OFW's physical addressing running on the main core(s), listed as DRAM address:

DRAM address SP address
0x0000.0000 0x0000.0000 (if TCM is off; memory inaccessible via SP address 0 with TCM on)
0x0000.0000 0x1000.0000
0x1000.0000 0x2000.0000
0x2000.0000 0x3000.0000
0x3000.0000 inaccessible

Memory Test Commands

If using a version of CForth which doesn't automatically init the memory (i.e.: a version later than Q7A06), if you run a memory test without first initializing the memory using late-init, the processor will silently hang.

Canned Test Commands

Command Stack Description
memtest ( ) Runs a random-pattern test (see below) and reports the result
memtest-start ( -- address ) Value containing the start address for memtest
memtest-length ( -- length ) Value containing the length for memtest
2000.0000 to memtest-start Change the memtest start address
1000.0000 to memtest-length Change the memtest length

Test Primitives for Detailed Debugging

In the following commands, if an error is encountered, the returns value is the address where the error occurred. If no error is encountered the returned error address is -1 (0xFFFFFFFF).

Command Stack Description
lfill ( address length value -- ) Fill memory range with 32-bit value
lcheck ( address length value -- error_address ) Check the result of lfill
inc-fill (address length -- ) Fill memory range with data=address
inc-check (address length -- error_address ) Check the result of inc-fill
random-fill ( address length -- ) Fill memory range with psuedorandom data using a pseudorandom access order
random-check ( address length -- error_address ) Check the result of random-fill

lfill/lcheck are good for fast bit-level verification.

inc-fill/inc-check are good for checking addressing.

random-fill/random-check are somewhat slower. They are good for thorough checkout, but if there are problems, it can be difficult to determine the exact problem syndrome, since the test pattern is not easily recognizable.

For example, to test the lower 1 MB of memory:

ok  0 100000 random-fill
ok  0 100000 random-check .