Joseph Smith wrote:
<snip>
I really, _REALLY_ don't like this, even if it does work. Reading from spd byte 31 gives you the bank size, in units of 4mb, for both sides of an asymetrical dimm. Please look at the spd spec (Intel or Jedec) to see what you need to do to read it, it's a bit odd. You need to figure out how many places the 1 is shifted, the number of places * 4mb is the size of the bank, if the banks are asymetrical the smaller size is side2. And if you do decide to use it anyways, please add the original copyright holder, I think this is from e7501?
Your right, I don't really feel the above method is necessary. The only problem is this with Byte 31:
# Banks Density of Bank 1 Density of bank 2 Byte 31 contents 1 32MByte N/A 0000 1000 2 32MByte 32MBbyte 0000 1000 2 32MByte 16MByte 0000 1100
You can see Byte 31 contents are going to be the same when the density is the same no matter how many banks it has. Could this potentially give a false reading?? You could also use Byte 5 to determine the banks. Could we say something like; if byte 5 has 1 bank than byte 31 is correct and if byte 5 has 2 banks to muliply byte 31 by 2?? But what about the third example above when you have more than 1 bank and the densities are different??
Below is a simple example. There are better/faster ways to do it, but this should just work. Also, coding style is probably very broken, blame that on Thunderbird.
int i, spd_byte_31, spd_byte_5; spd_byte_31 = smbus_read_byte(device, 31); //please rename device to dimm spd_byte_5 = smbus_read_byte(device, 5);
for (i = 8; i >= 0; i--) { /* Find the larger value. The larger side is always side1 */ if (spd_byte_31 & (1 << i) == (1 << i)) { sz.side1 = i; break; } }
/* Set to 0 in case it's single sided */ sz.side2 = 0;
/* Test if it's a dual-sided dimm */ if (spd_byte_5 > 1) { /* Test to see if there's a second value, if so it's asymmetrical */ if (spd_byte_31 != (1 << i)) { /* Find the second value, picking up where we left off */ /* i-- done initially to make sure we don't get the same value again */ for (i--; i >= 0; i--) { if (spd_byte_31 == (1 << i) { sz.side2 = i; break; } } /* If not, it's symmetrical */ else { sz.side2 = sz.side1; } return sz; //sizes are now in units of 4mb, so 1 = 4mb, 2 = 8mb, etc. }
BTW, this has finally made me see the correlation that the i810 uses! Expect a patch sometime for some major cleanup.
static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask) { int i; int cum;
for(i = cum = 0; i < DIMM_SOCKETS; i++) { struct dimm_size sz; if (dimm_mask & (1 << i)) { sz = spd_get_dimm_size(ctrl->channel0[i]); /* WISHLIST: would be nice to display it as decimal? */ print_debug("DIMM is "); print_debug_hex8(sz.side1); print_debug(" On Side 1\r\n"); print_debug("DIMM is "); print_debug_hex8(sz.side2); print_debug(" On Side 2\r\n"); /* Set the row offset, in KBytes (should this be * Kbits?). Note that this offset is the start of the * next row. */ row_offset = ((sz.side1 + sz.side2) * 1024);
If you're still in the initial testing stages, try to get one single-sided dimm working first. Also, if you have a dual-sided dimm, row_offset needs to be the address at the second side (as far as I know), so only sz.side1 * 1024. This might be chip-dependent, board-dependent, or I might be completely wrong...
My test board has 128MB on-board, Remember this is a set-top-box. To the registry, with the stock bios it shows up as a sindle sided so-dimm in socket 2. Initially I could just hardcode alot of this but I would like to make it versitial and have the ability to use socket 1 also. Alot of Laptops use this chip also, so this could open up LinuxBios to that front.
Does that dimm provide spd data? lm-sensors dimms-detect.pl should tell you from userspace, or else dump_spd_data from linuxbios. If not, ignore it completely for now, just act like it doesn't exist and hardcode it in later. If so, use that as your test dimm/slot. I suspect it's probably the former. Once you have one dimm working, try for another. Going for both the first time through would take a lot of luck.
-Corey