We run into the same problem on ARM systems, but they tend to be much more forgiving when using cache as RAM. Generally there is a bit you can flip (either in memory-mapped IO or as a coprocessor instruction) to turn cache into RAM, which is how most ARM boot roms work.
Furthermore, most embedded platforms simply hardcode the timing values for the variety of RAM that they put down on the board. Since you know that the RAM, CPU, and board won't change, you can calibrate once and be done with it.
For Novena, we support swapping DDR3 modules, so we need to recalibrate on every boot. We're not so restricted, since we have a good 128k (or 256k) of on-chip cache-as-RAM, so we just do it all in C. Of course it starts out with reading the RAM configuration out of the SPD chip on the module, but timing calibration must be completed regardless. If you're curious, the code we use to do this is available at https://github.com/xobs/u-boot-novena-spl/blob/u-boot-spl-no...
Furthermore, most embedded platforms simply hardcode the timing values for the variety of RAM that they put down on the board. Since you know that the RAM, CPU, and board won't change, you can calibrate once and be done with it.
For Novena, we support swapping DDR3 modules, so we need to recalibrate on every boot. We're not so restricted, since we have a good 128k (or 256k) of on-chip cache-as-RAM, so we just do it all in C. Of course it starts out with reading the RAM configuration out of the SPD chip on the module, but timing calibration must be completed regardless. If you're curious, the code we use to do this is available at https://github.com/xobs/u-boot-novena-spl/blob/u-boot-spl-no...