Try editing/clearing the DDR3 in the debugger. Read back with the Z80 hex display. Re-check after a Z80 write and block write fill.
Single-byte edits by the Z80 (POKE-ing individual bytes) works without error and is reflected correctly by the debugger and DDR3 RAM (viewed by the Z80).
A block copy (using LDIR) seems to have worked just fine as well, copying 256 bytes of data from the uCOM's memory to the GPU.
This just leaves the 'block clear' routine the bootstrap and DMI uses to clear out the first page of GPU RAM before setting up...
I've just tried to clear the first page of GPU memory and the page is corrupted again, but now I know what's going on. I've tested my theory in code and it's confirmed what I thought: it's not LDIR itself, but the way I'm using it to clear the screen and the underlying issue with DDR3 reads. When my driver clears the screen it uses a technique for faster clearing of the RAM block - instead of loading 0x00 into the accumulator and writing that value to every byte required to clear the screen, I'm using a trick with LDIR that writes 0x00 to the first byte (hence the first byte is always 0x00 at C000), then uses LDIR to copy that byte to the next memory position, increments both pointers (source and target), then copies the 0x00 from the new position to the next position and so on.
Problem is, writing the first byte is fine as we've seen, but when LDIR copies that byte to the next position, could it be hitting the cache miss problem and getting a value of 0xB0 back instead of 0x00? Once it's got 0xB0, it writes it to position 2, then moves on and copies 0xB0 to position 3 and so on, resulting in a page of 0xB0s with an 0x00 at the start.
I've replaced the 'block clear' routine with a slower one that just writes the value (0x00 in the case of a block clear) to every byte in the specified range, so it doesn't rely on reading back the value written and bad values can't be introduced due to cache misses.
This has fixed the corrupted screen every time I've tried it. I'm now getting valid screen displays and stable DMI and CP/M screen output.