[U-Boot-Users] [PATCH] Fix "i2c sdram" command for DDR2 DIMMs
Jerry Van Baren
gerald.vanbaren at ge.com
Fri Jan 11 14:35:23 CET 2008
Larry Johnson wrote:
> Many of the SPD bytes for DDR2 SDRAM are not interpreted correctly by the
> "i2c sdram" command. This patch provides correct alternative
> interpretations when DDR2 memory is detected.
>
> Signed-off-by: Larry Johnson <lrj at acm.org>
Thanks for adding the DDR2 decoding, it is very valuable.
[snip]
> common/cmd_i2c.c | 615 +++++++++++++++++++++++++++++++++++++++++++-----------
> 1 files changed, 496 insertions(+), 119 deletions(-)
[snip]
> +
> + switch (type) {
> + case DDR2:
> + puts ("CAS latency(s) ");
> + if (data[18] & 0x83) puts (" TBD");
> + if (data[18] & 0x40) puts (" 6");
> + if (data[18] & 0x20) puts (" 5");
> + if (data[18] & 0x10) puts (" 4");
> + if (data[18] & 0x08) puts (" 3");
> + if (data[18] & 0x04) puts (" 2");
> + putc ('\n');
> + break;
> + default:
> + puts ("CAS latency(s) ");
> + if (data[18] & 0x80) puts (" TBD");
> + if (data[18] & 0x40) puts (" 7");
> + if (data[18] & 0x20) puts (" 6");
> + if (data[18] & 0x10) puts (" 5");
> + if (data[18] & 0x08) puts (" 4");
> + if (data[18] & 0x04) puts (" 3");
> + if (data[18] & 0x02) puts (" 2");
> + if (data[18] & 0x01) puts (" 1");
> + putc ('\n');
> + break;
> + }
> +
> + if (DDR2 != type) {
> + puts ("CS latency(s) ");
> + if (data[19] & 0x80) puts (" TBD");
> + if (data[19] & 0x40) puts (" 6");
> + if (data[19] & 0x20) puts (" 5");
> + if (data[19] & 0x10) puts (" 4");
> + if (data[19] & 0x08) puts (" 3");
> + if (data[19] & 0x04) puts (" 2");
> + if (data[19] & 0x02) puts (" 1");
> + if (data[19] & 0x01) puts (" 0");
> + putc ('\n');
> + }
> +
> + if (DDR2 != type) {
> + puts ("WE latency(s) ");
> + if (data[20] & 0x80) puts (" TBD");
> + if (data[20] & 0x40) puts (" 6");
> + if (data[20] & 0x20) puts (" 5");
> + if (data[20] & 0x10) puts (" 4");
> + if (data[20] & 0x08) puts (" 3");
> + if (data[20] & 0x04) puts (" 2");
> + if (data[20] & 0x02) puts (" 1");
> + if (data[20] & 0x01) puts (" 0");
> + putc ('\n');
> + }
I don't know if it is worth the effort in terms of code size weighed
against obscuring the actual code, but there are a lot of bit decoding
to strings going on (and, yes, if you look at the history, it is
probably my fault). The following concept should work...
static char *decodeDDR2[] = {
" TBD",
" TBD",
" 2",
" 3",
" 4",
" 5",
" 6",
" TBD",
};
static char *decode06[] = {
" 0",
" 1",
" 2",
" 3",
" 4",
" 5",
" 6",
" TBD",
};
static char *decode17[] = {
" 1",
" 2",
" 3",
" 4",
" 5",
" 6",
" 7",
" TBD",
};
void decodebits(int n, char *str[])
{
int j, k;
for (k = 0, j = 0x80; j != 0; j >> 1, k++) {
if (n & j)
puts(str[k]);
}
}
...and then the example usage would be:
if (DDR2 != type) {
puts ("WE latency(s) ");
bits2string(data[20], decode06);
putc ('\n');
}
If we aren't concerned with TBDs for undefined bits, the above lists
could be condensed into one list that is " 0" through " 8" - one decode
is 1..8 which could be handled with a decode of 0..7 and a shift.
If you think the decodebits() decoding is worth while, I would strongly
advocate dropping the "TBDs" and do the following:
static char *decode08[] = {
" 0",
" 1",
" 2",
" 3",
" 4",
" 5",
" 6",
" 7",
" 8",
};
Example for 1..8 decoding:
default:
puts ("CAS latency(s) ");
decodebits((int)data[18] << 1, decode08);
putc ('\n');
break;
There are a couple of decodes that '0' means one thing and '1' means
another (handled by if/else statements) that the above decode wouldn't
handle (could, but the penalty would probably be bigger than the gain).
[snip]
> + switch (type) {
> + case DDR2:
> + if (data[22] & 0x80) puts (" TBD (bit 7)\n");
> + if (data[22] & 0x40) puts (" TBD (bit 6)\n");
> + if (data[22] & 0x20) puts (" TBD (bit 5)\n");
> + if (data[22] & 0x10) puts (" TBD (bit 4)\n");
> + if (data[22] & 0x08) puts (" TBD (bit 3)\n");
> + if (data[22] & 0x04)
> + puts (" Supports parital array self refresh\n");
Typo: "partial"
[snip]
> + switch (type) {
> + case DDR2:
> + printf("SDRAM cycle time (2nd highest CAS latency) %d.",
> + (data[23] >> 4) & 0x0F);
> +
> + switch (data[23] & 0x0F) {
> + case 0x0:
> + case 0x1:
> + case 0x2:
> + case 0x3:
> + case 0x4:
> + case 0x5:
> + case 0x6:
> + case 0x7:
> + case 0x8:
> + case 0x9:
> + printf("%d ns\n", data[23] & 0x0F);
> + break;
> + case 0xA:
> + puts("25 ns\n");
> + break;
> + case 0xB:
> + puts("33 ns\n");
> + break;
> + case 0xC:
> + puts("66 ns\n");
> + break;
> + case 0xD:
> + puts("75 ns\n");
> + break;
> + default:
> + puts("?? ns\n");
> + break;
We saw this code before, could refactor into a subroutine that does the
decoding and printing.
[snip]
> + switch (type) {
> + case DDR2:
> + printf("SDRAM cycle time (3rd highest CAS latency) %d.",
> + (data[25] >> 4) & 0x0F);
> +
> + switch (data[25] & 0x0F) {
> + case 0x0:
> + case 0x1:
> + case 0x2:
> + case 0x3:
> + case 0x4:
> + case 0x5:
> + case 0x6:
> + case 0x7:
> + case 0x8:
> + case 0x9:
> + printf("%d ns\n", data[25] & 0x0F);
> + break;
> + case 0xA:
> + puts("25 ns\n");
> + break;
> + case 0xB:
> + puts("33 ns\n");
> + break;
> + case 0xC:
> + puts("66 ns\n");
> + break;
> + case 0xD:
> + puts("75 ns\n");
> + break;
> + default:
> + puts("?? ns\n");
> + break;
> + }
> + break;
Hey, deja vue all over again. :-)
[snip]
> + switch (type) {
> + case DDR2:
> + printf("Minimum row precharge %d", data[27] >> 2);
> + switch (data[27] & 0x03) {
> + case 0x0: puts(".00 ns\n"); break;
> + case 0x1: puts(".25 ns\n"); break;
> + case 0x2: puts(".50 ns\n"); break;
> + case 0x3: puts(".75 ns\n"); break;
> + }
> + break;
> + default:
> + printf("Minimum row precharge %d nS\n", data[27]);
> + break;
> + }
> +
> + switch (type) {
> + case DDR2:
> + printf("Row active to row active min %d", data[28] >> 2);
> + switch (data[28] & 0x03) {
> + case 0x0: puts(".00 ns\n"); break;
> + case 0x1: puts(".25 ns\n"); break;
> + case 0x2: puts(".50 ns\n"); break;
> + case 0x3: puts(".75 ns\n"); break;
> + }
> + break;
> + default:
> + printf("Row active to row active min %d nS\n", data[28]);
> + break;
> + }
> +
> + switch (type) {
> + case DDR2:
> + printf("RAS to CAS delay min %d", data[29] >> 2);
> + switch (data[29] & 0x03) {
> + case 0x0: puts(".00 ns\n"); break;
> + case 0x1: puts(".25 ns\n"); break;
> + case 0x2: puts(".50 ns\n"); break;
> + case 0x3: puts(".75 ns\n"); break;
> + }
> + break;
Hmm, another troika that could be refactored into a helper subroutine.
On second thought, this is probably not worth a helper routine (too
trivial?): replacing the switch statements with arithmetic is going to
be slightly less speed efficient, but quite a bit more code efficient:
printf(".%02d ns\n", (data[29] & 0x03) * 25);
[snip]
Thanks again,
gvb
More information about the U-Boot
mailing list