1. A memory controller comprising: a command FIFO (first-in first-out memory) configured to convey commands to a memory; a data queue coupled to receive data read from the memory; and a register configured to provide a value indicative of a number of cycles of a first clock signal after which data is valid subsequent to a command being written into the command FIFO; wherein, the memory controller is configured to, during a startup routine: convey a read command to the memory; compare data received by the data queue to a known data pattern after a specified number of cycles of the first clock signal have elapsed subsequent to writing the read command to the command FIFO, the specified number indicated by a first value stored in the register; decrement the first value and repeat conveying and comparing if the data received matches the data pattern; attempt one or more additional reads, without decrementing the first value, if the data received does not match the data pattern; and program a second value into the register, the second value being a memory read latency value expressed as a number of cycles of the first clock signal, wherein the second value is based on a lowest number of cycles of the first clock signal at which the data received matches the data pattern.