DDC/I2C/SMBus overhaul (incomplete, commit for the night)
This commit is contained in:
472
src/mem/spd.c
472
src/mem/spd.c
@@ -23,7 +23,7 @@
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/smbus.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/spd.h>
|
||||
#include <86box/version.h>
|
||||
#include <86box/machine.h>
|
||||
@@ -37,11 +37,6 @@ spd_t *spd_devices[SPD_MAX_SLOTS];
|
||||
uint8_t spd_data[SPD_MAX_SLOTS][SPD_DATA_SIZE];
|
||||
|
||||
|
||||
static uint8_t spd_read_byte(uint8_t addr, void *priv);
|
||||
static uint8_t spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static void spd_write_byte(uint8_t addr, uint8_t val, void *priv);
|
||||
|
||||
|
||||
#ifdef ENABLE_SPD_LOG
|
||||
int spd_do_log = ENABLE_SPD_LOG;
|
||||
|
||||
@@ -52,9 +47,9 @@ spd_log(const char *fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (spd_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -63,15 +58,7 @@ spd_log(const char *fmt, ...)
|
||||
|
||||
|
||||
uint8_t
|
||||
spd_read_byte(uint8_t addr, void *priv)
|
||||
{
|
||||
spd_t *dev = (spd_t *) priv;
|
||||
return spd_read_byte_cmd(addr, dev->addr_register, priv);
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
spd_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
spd_t *dev = (spd_t *) priv;
|
||||
uint8_t ret = *(spd_data[dev->slot] + cmd);
|
||||
@@ -80,26 +67,33 @@ spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
}
|
||||
|
||||
|
||||
uint16_t
|
||||
spd_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
uint8_t
|
||||
spd_read_byte(void *bus, uint8_t addr, void *priv)
|
||||
{
|
||||
return (spd_read_byte_cmd(addr, cmd + 1, priv) << 8) | spd_read_byte_cmd(addr, cmd, priv);
|
||||
spd_t *dev = (spd_t *) priv;
|
||||
return spd_read_byte_cmd(bus, addr, dev->addr_register, priv);
|
||||
}
|
||||
|
||||
|
||||
uint16_t
|
||||
spd_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
return (spd_read_byte_cmd(bus, addr, cmd + 1, priv) << 8) | spd_read_byte_cmd(bus, addr, cmd, priv);
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
spd_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv)
|
||||
spd_read_block_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv)
|
||||
{
|
||||
uint8_t read = 0;
|
||||
for (uint8_t i = cmd; i < len && i < SPD_DATA_SIZE; i++) {
|
||||
data[read++] = spd_read_byte_cmd(addr, i, priv);
|
||||
}
|
||||
for (uint8_t i = cmd; (i < len) && (i < SPD_DATA_SIZE); i++)
|
||||
data[read++] = spd_read_byte_cmd(bus, addr, i, priv);
|
||||
return read;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
spd_write_byte(uint8_t addr, uint8_t val, void *priv)
|
||||
spd_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
spd_t *dev = (spd_t *) priv;
|
||||
dev->addr_register = val;
|
||||
@@ -111,12 +105,12 @@ spd_close(void *priv)
|
||||
{
|
||||
spd_t *dev = (spd_t *) priv;
|
||||
|
||||
spd_log("SPD: closing slot %d (SMBus %02Xh)\n", dev->slot, SPD_BASE_ADDR + dev->slot);
|
||||
spd_log("SPD: closing slot %d (SMBus %02X)\n", dev->slot, SPD_BASE_ADDR + dev->slot);
|
||||
|
||||
smbus_removehandler(SPD_BASE_ADDR + dev->slot, 1,
|
||||
spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
|
||||
spd_write_byte, NULL, NULL, NULL,
|
||||
dev);
|
||||
i2c_removehandler(i2c_smbus, SPD_BASE_ADDR + dev->slot, 1,
|
||||
NULL, spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
|
||||
NULL, spd_write_byte, NULL, NULL, NULL,
|
||||
dev);
|
||||
|
||||
spd_present = 0;
|
||||
|
||||
@@ -129,12 +123,12 @@ spd_init(const device_t *info)
|
||||
{
|
||||
spd_t *dev = spd_devices[info->local];
|
||||
|
||||
spd_log("SPD: initializing slot %d (SMBus %02Xh)\n", dev->slot, SPD_BASE_ADDR + dev->slot);
|
||||
spd_log("SPD: initializing slot %d (SMBus %02X)\n", dev->slot, SPD_BASE_ADDR + dev->slot);
|
||||
|
||||
smbus_sethandler(SPD_BASE_ADDR + dev->slot, 1,
|
||||
spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
|
||||
spd_write_byte, NULL, NULL, NULL,
|
||||
dev);
|
||||
i2c_sethandler(i2c_smbus, SPD_BASE_ADDR + dev->slot, 1,
|
||||
NULL, spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
|
||||
NULL, spd_write_byte, NULL, NULL, NULL,
|
||||
dev);
|
||||
|
||||
spd_present = 1;
|
||||
|
||||
@@ -147,7 +141,7 @@ log2_ui16(uint16_t i)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
while ((i >>= 1))
|
||||
ret++;
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -170,63 +164,63 @@ spd_populate(uint16_t *vslots, uint8_t slot_count, uint16_t total_size, uint16_t
|
||||
/* populate vslots with modules in power-of-2 capacities */
|
||||
memset(vslots, 0x00, SPD_MAX_SLOTS << 1);
|
||||
for (vslot = 0; vslot < slot_count && total_size; vslot++) {
|
||||
/* populate slot */
|
||||
vslots[vslot] = (1 << log2_ui16(MIN(total_size, max_module_size)));
|
||||
if (total_size >= vslots[vslot]) {
|
||||
spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]);
|
||||
total_size -= vslots[vslot];
|
||||
} else {
|
||||
vslots[vslot] = 0;
|
||||
break;
|
||||
}
|
||||
/* populate slot */
|
||||
vslots[vslot] = 1 << log2_ui16(MIN(total_size, max_module_size));
|
||||
if (total_size >= vslots[vslot]) {
|
||||
spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]);
|
||||
total_size -= vslots[vslot];
|
||||
} else {
|
||||
vslots[vslot] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* did we populate all the RAM? */
|
||||
if (total_size) {
|
||||
/* work backwards to add the missing RAM as asymmetric modules if possible */
|
||||
if (enable_asym) {
|
||||
vslot = slot_count - 1;
|
||||
do {
|
||||
asym = (1 << log2_ui16(MIN(total_size, vslots[vslot])));
|
||||
if (vslots[vslot] + asym <= max_module_size) {
|
||||
vslots[vslot] += asym;
|
||||
total_size -= asym;
|
||||
}
|
||||
} while ((vslot-- > 0) && total_size);
|
||||
}
|
||||
/* work backwards to add the missing RAM as asymmetric modules if possible */
|
||||
if (enable_asym) {
|
||||
vslot = slot_count - 1;
|
||||
do {
|
||||
asym = (1 << log2_ui16(MIN(total_size, vslots[vslot])));
|
||||
if (vslots[vslot] + asym <= max_module_size) {
|
||||
vslots[vslot] += asym;
|
||||
total_size -= asym;
|
||||
}
|
||||
} while ((vslot-- > 0) && total_size);
|
||||
}
|
||||
|
||||
if (total_size) /* still not enough */
|
||||
spd_log("SPD: not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size);
|
||||
if (total_size) /* still not enough */
|
||||
spd_log("SPD: not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size);
|
||||
}
|
||||
|
||||
/* populate empty vslots by splitting modules... */
|
||||
split = (total_size == 0); /* ...if possible */
|
||||
while (split) {
|
||||
/* look for a module to split */
|
||||
split = 0;
|
||||
for (vslot = 0; vslot < slot_count; vslot++) {
|
||||
if ((vslots[vslot] < (min_module_size << 1)) || (vslots[vslot] != (1 << log2_ui16(vslots[vslot]))))
|
||||
continue; /* no module here, module is too small to be split, or asymmetric module */
|
||||
/* look for a module to split */
|
||||
split = 0;
|
||||
for (vslot = 0; vslot < slot_count; vslot++) {
|
||||
if ((vslots[vslot] < (min_module_size << 1)) || (vslots[vslot] != (1 << log2_ui16(vslots[vslot]))))
|
||||
continue; /* no module here, module is too small to be split, or asymmetric module */
|
||||
|
||||
/* find next empty vslot */
|
||||
next_empty_vslot = 0;
|
||||
for (i = vslot + 1; i < slot_count && !next_empty_vslot; i++) {
|
||||
if (!vslots[i])
|
||||
next_empty_vslot = i;
|
||||
}
|
||||
if (!next_empty_vslot)
|
||||
break; /* no empty vslots left */
|
||||
/* find next empty vslot */
|
||||
next_empty_vslot = 0;
|
||||
for (i = vslot + 1; i < slot_count && !next_empty_vslot; i++) {
|
||||
if (!vslots[i])
|
||||
next_empty_vslot = i;
|
||||
}
|
||||
if (!next_empty_vslot)
|
||||
break; /* no empty vslots left */
|
||||
|
||||
/* split the module into its own vslot and the next empty vslot */
|
||||
spd_log("SPD: splitting vslot %d (%d MB) into %d and %d (%d MB each)\n", vslot, vslots[vslot], vslot, next_empty_vslot, (vslots[vslot] >> 1));
|
||||
vslots[vslot] = vslots[next_empty_vslot] = (vslots[vslot] >> 1);
|
||||
split = 1;
|
||||
break;
|
||||
}
|
||||
/* split the module into its own vslot and the next empty vslot */
|
||||
spd_log("SPD: splitting vslot %d (%d MB) into %d and %d (%d MB each)\n", vslot, vslots[vslot], vslot, next_empty_vslot, vslots[vslot] >> 1);
|
||||
vslots[vslot] = vslots[next_empty_vslot] = vslots[vslot] >> 1;
|
||||
split = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* sort vslots by descending capacity if any were split */
|
||||
if (split)
|
||||
qsort(vslots, slot_count, sizeof(uint16_t), comp_ui16_rev);
|
||||
/* sort vslots by descending capacity if any were split */
|
||||
if (split)
|
||||
qsort(vslots, slot_count, sizeof(uint16_t), comp_ui16_rev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,27 +236,27 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
|
||||
|
||||
/* determine the minimum module size for this RAM type */
|
||||
switch (ram_type) {
|
||||
case SPD_TYPE_FPM:
|
||||
case SPD_TYPE_EDO:
|
||||
min_module_size = SPD_MIN_SIZE_EDO;
|
||||
break;
|
||||
case SPD_TYPE_FPM:
|
||||
case SPD_TYPE_EDO:
|
||||
min_module_size = SPD_MIN_SIZE_EDO;
|
||||
break;
|
||||
|
||||
case SPD_TYPE_SDRAM:
|
||||
min_module_size = SPD_MIN_SIZE_SDRAM;
|
||||
break;
|
||||
case SPD_TYPE_SDRAM:
|
||||
min_module_size = SPD_MIN_SIZE_SDRAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
spd_log("SPD: unknown RAM type 0x%02X\n", ram_type);
|
||||
return;
|
||||
spd_log("SPD: unknown RAM type %02X\n", ram_type);
|
||||
return;
|
||||
}
|
||||
|
||||
/* count how many (real) slots are enabled */
|
||||
slot_count = 0;
|
||||
for (slot = 0; slot < SPD_MAX_SLOTS; slot++) {
|
||||
vslots[slot] = 0;
|
||||
if (slot_mask & (1 << slot)) {
|
||||
slot_count++;
|
||||
}
|
||||
vslots[slot] = 0;
|
||||
if (slot_mask & (1 << slot)) {
|
||||
slot_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* populate vslots */
|
||||
@@ -271,134 +265,134 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
|
||||
/* register SPD devices and populate their data according to the vslots */
|
||||
vslot = 0;
|
||||
for (slot = 0; slot < SPD_MAX_SLOTS && vslots[vslot]; slot++) {
|
||||
if (!(slot_mask & (1 << slot)))
|
||||
continue; /* slot disabled */
|
||||
if (!(slot_mask & (1 << slot)))
|
||||
continue; /* slot disabled */
|
||||
|
||||
info = (device_t *) malloc(sizeof(device_t));
|
||||
memset(info, 0, sizeof(device_t));
|
||||
info->name = "Serial Presence Detect ROM";
|
||||
info->local = slot;
|
||||
info->init = spd_init;
|
||||
info->close = spd_close;
|
||||
info = (device_t *) malloc(sizeof(device_t));
|
||||
memset(info, 0, sizeof(device_t));
|
||||
info->name = "Serial Presence Detect ROM";
|
||||
info->local = slot;
|
||||
info->init = spd_init;
|
||||
info->close = spd_close;
|
||||
|
||||
spd_devices[slot] = (spd_t *) malloc(sizeof(spd_t));
|
||||
memset(spd_devices[slot], 0, sizeof(spd_t));
|
||||
spd_devices[slot]->info = info;
|
||||
spd_devices[slot]->slot = slot;
|
||||
spd_devices[slot]->size = vslots[vslot];
|
||||
spd_devices[slot] = (spd_t *) malloc(sizeof(spd_t));
|
||||
memset(spd_devices[slot], 0, sizeof(spd_t));
|
||||
spd_devices[slot]->info = info;
|
||||
spd_devices[slot]->slot = slot;
|
||||
spd_devices[slot]->size = vslots[vslot];
|
||||
|
||||
/* determine the second row size, from which the first row size can be obtained */
|
||||
asym = (vslots[vslot] - (1 << log2_ui16(vslots[vslot]))); /* separate the powers of 2 */
|
||||
if (!asym) /* is the module asymmetric? */
|
||||
asym = (vslots[vslot] >> 1); /* symmetric, therefore divide by 2 */
|
||||
/* determine the second row size, from which the first row size can be obtained */
|
||||
asym = vslots[vslot] - (1 << log2_ui16(vslots[vslot])); /* separate the powers of 2 */
|
||||
if (!asym) /* is the module asymmetric? */
|
||||
asym = vslots[vslot] >> 1; /* symmetric, therefore divide by 2 */
|
||||
|
||||
spd_devices[slot]->row1 = (vslots[vslot] - asym);
|
||||
spd_devices[slot]->row2 = asym;
|
||||
spd_devices[slot]->row1 = vslots[vslot] - asym;
|
||||
spd_devices[slot]->row2 = asym;
|
||||
|
||||
spd_log("SPD: registering slot %d = vslot %d = %d MB (%d/%d)\n", slot, vslot, vslots[vslot], spd_devices[slot]->row1, spd_devices[slot]->row2);
|
||||
spd_log("SPD: registering slot %d = vslot %d = %d MB (%d/%d)\n", slot, vslot, vslots[vslot], spd_devices[slot]->row1, spd_devices[slot]->row2);
|
||||
|
||||
switch (ram_type) {
|
||||
case SPD_TYPE_FPM:
|
||||
case SPD_TYPE_EDO:
|
||||
edo_data = (spd_edo_t *) &spd_data[slot];
|
||||
memset(edo_data, 0, sizeof(spd_edo_t));
|
||||
switch (ram_type) {
|
||||
case SPD_TYPE_FPM:
|
||||
case SPD_TYPE_EDO:
|
||||
edo_data = (spd_edo_t *) &spd_data[slot];
|
||||
memset(edo_data, 0, sizeof(spd_edo_t));
|
||||
|
||||
/* EDO SPD is specified by JEDEC and present in some modules, but
|
||||
most utilities cannot interpret it correctly. SIV32 at least gets
|
||||
the module capacities right, so it was used as a reference here. */
|
||||
edo_data->bytes_used = 0x80;
|
||||
edo_data->spd_size = 0x08;
|
||||
edo_data->mem_type = ram_type;
|
||||
edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */
|
||||
edo_data->col_bits = 9;
|
||||
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */
|
||||
edo_data->row_bits |= (SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row2)) << 4); /* second row, if different from first */
|
||||
edo_data->col_bits |= (9 << 4); /* same as first row, but just in case */
|
||||
}
|
||||
edo_data->banks = 2;
|
||||
edo_data->data_width_lsb = 64;
|
||||
edo_data->signal_level = SPD_SIGNAL_LVTTL;
|
||||
edo_data->trac = 50;
|
||||
edo_data->tcac = 13;
|
||||
edo_data->refresh_rate = SPD_REFRESH_NORMAL;
|
||||
edo_data->dram_width = 8;
|
||||
/* EDO SPD is specified by JEDEC and present in some modules, but
|
||||
most utilities cannot interpret it correctly. SIV32 at least gets
|
||||
the module capacities right, so it was used as a reference here. */
|
||||
edo_data->bytes_used = 0x80;
|
||||
edo_data->spd_size = 0x08;
|
||||
edo_data->mem_type = ram_type;
|
||||
edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */
|
||||
edo_data->col_bits = 9;
|
||||
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */
|
||||
edo_data->row_bits |= SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row2)) << 4; /* second row, if different from first */
|
||||
edo_data->col_bits |= 9 << 4; /* same as first row, but just in case */
|
||||
}
|
||||
edo_data->banks = 2;
|
||||
edo_data->data_width_lsb = 64;
|
||||
edo_data->signal_level = SPD_SIGNAL_LVTTL;
|
||||
edo_data->trac = 50;
|
||||
edo_data->tcac = 13;
|
||||
edo_data->refresh_rate = SPD_REFRESH_NORMAL;
|
||||
edo_data->dram_width = 8;
|
||||
|
||||
edo_data->spd_rev = 0x12;
|
||||
sprintf(edo_data->part_no, EMU_NAME "-%s-%03dM", (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", vslots[vslot]);
|
||||
for (i = strlen(edo_data->part_no); i < sizeof(edo_data->part_no); i++)
|
||||
edo_data->part_no[i] = ' '; /* part number should be space-padded */
|
||||
edo_data->rev_code[0] = BCD8(EMU_VERSION_MAJ);
|
||||
edo_data->rev_code[1] = BCD8(EMU_VERSION_MIN);
|
||||
edo_data->mfg_year = 20;
|
||||
edo_data->mfg_week = 17;
|
||||
edo_data->spd_rev = 0x12;
|
||||
sprintf(edo_data->part_no, EMU_NAME "-%s-%03dM", (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", vslots[vslot]);
|
||||
for (i = strlen(edo_data->part_no); i < sizeof(edo_data->part_no); i++)
|
||||
edo_data->part_no[i] = ' '; /* part number should be space-padded */
|
||||
edo_data->rev_code[0] = BCD8(EMU_VERSION_MAJ);
|
||||
edo_data->rev_code[1] = BCD8(EMU_VERSION_MIN);
|
||||
edo_data->mfg_year = 20;
|
||||
edo_data->mfg_week = 17;
|
||||
|
||||
for (i = 0; i < 63; i++)
|
||||
edo_data->checksum += spd_data[slot][i];
|
||||
for (i = 0; i < 129; i++)
|
||||
edo_data->checksum2 += spd_data[slot][i];
|
||||
break;
|
||||
for (i = 0; i < 63; i++)
|
||||
edo_data->checksum += spd_data[slot][i];
|
||||
for (i = 0; i < 129; i++)
|
||||
edo_data->checksum2 += spd_data[slot][i];
|
||||
break;
|
||||
|
||||
case SPD_TYPE_SDRAM:
|
||||
sdram_data = (spd_sdram_t *) &spd_data[slot];
|
||||
memset(sdram_data, 0, sizeof(spd_sdram_t));
|
||||
case SPD_TYPE_SDRAM:
|
||||
sdram_data = (spd_sdram_t *) &spd_data[slot];
|
||||
memset(sdram_data, 0, sizeof(spd_sdram_t));
|
||||
|
||||
sdram_data->bytes_used = 0x80;
|
||||
sdram_data->spd_size = 0x08;
|
||||
sdram_data->mem_type = ram_type;
|
||||
sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */
|
||||
sdram_data->col_bits = 9;
|
||||
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */
|
||||
sdram_data->row_bits |= (SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row2)) << 4); /* second row, if different from first */
|
||||
sdram_data->col_bits |= (9 << 4); /* same as first row, but just in case */
|
||||
}
|
||||
sdram_data->rows = 2;
|
||||
sdram_data->data_width_lsb = 64;
|
||||
sdram_data->signal_level = SPD_SIGNAL_LVTTL;
|
||||
sdram_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */
|
||||
sdram_data->tac = 0x10;
|
||||
sdram_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL;
|
||||
sdram_data->sdram_width = 8;
|
||||
sdram_data->tccd = 1;
|
||||
sdram_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8;
|
||||
sdram_data->banks = 4;
|
||||
sdram_data->cas = 0x1c; /* CAS 5/4/3 supported */
|
||||
sdram_data->cslat = sdram_data->we = 0x7f;
|
||||
sdram_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST;
|
||||
sdram_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */
|
||||
sdram_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */
|
||||
sdram_data->tac2 = sdram_data->tac3 = 0x10;
|
||||
sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1;
|
||||
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) {
|
||||
/* Utilities interpret bank_density a bit differently on asymmetric modules. */
|
||||
sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 2)); /* first row */
|
||||
sdram_data->bank_density |= (1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2)); /* second row */
|
||||
} else {
|
||||
sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1)); /* symmetric module = only one bit is set */
|
||||
}
|
||||
sdram_data->ca_setup = sdram_data->data_setup = 0x15;
|
||||
sdram_data->ca_hold = sdram_data->data_hold = 0x08;
|
||||
sdram_data->bytes_used = 0x80;
|
||||
sdram_data->spd_size = 0x08;
|
||||
sdram_data->mem_type = ram_type;
|
||||
sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */
|
||||
sdram_data->col_bits = 9;
|
||||
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */
|
||||
sdram_data->row_bits |= SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row2)) << 4; /* second row, if different from first */
|
||||
sdram_data->col_bits |= 9 << 4; /* same as first row, but just in case */
|
||||
}
|
||||
sdram_data->rows = 2;
|
||||
sdram_data->data_width_lsb = 64;
|
||||
sdram_data->signal_level = SPD_SIGNAL_LVTTL;
|
||||
sdram_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */
|
||||
sdram_data->tac = 0x10;
|
||||
sdram_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL;
|
||||
sdram_data->sdram_width = 8;
|
||||
sdram_data->tccd = 1;
|
||||
sdram_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8;
|
||||
sdram_data->banks = 4;
|
||||
sdram_data->cas = 0x1c; /* CAS 5/4/3 supported */
|
||||
sdram_data->cslat = sdram_data->we = 0x7f;
|
||||
sdram_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST;
|
||||
sdram_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */
|
||||
sdram_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */
|
||||
sdram_data->tac2 = sdram_data->tac3 = 0x10;
|
||||
sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1;
|
||||
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) {
|
||||
/* Utilities interpret bank_density a bit differently on asymmetric modules. */
|
||||
sdram_data->bank_density = 1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 2); /* first row */
|
||||
sdram_data->bank_density |= 1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2); /* second row */
|
||||
} else {
|
||||
sdram_data->bank_density = 1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1); /* symmetric module = only one bit is set */
|
||||
}
|
||||
sdram_data->ca_setup = sdram_data->data_setup = 0x15;
|
||||
sdram_data->ca_hold = sdram_data->data_hold = 0x08;
|
||||
|
||||
sdram_data->spd_rev = 0x12;
|
||||
sprintf(sdram_data->part_no, EMU_NAME "-SDR-%03dM", vslots[vslot]);
|
||||
for (i = strlen(sdram_data->part_no); i < sizeof(sdram_data->part_no); i++)
|
||||
sdram_data->part_no[i] = ' '; /* part number should be space-padded */
|
||||
sdram_data->rev_code[0] = BCD8(EMU_VERSION_MAJ);
|
||||
sdram_data->rev_code[1] = BCD8(EMU_VERSION_MIN);
|
||||
sdram_data->mfg_year = 20;
|
||||
sdram_data->mfg_week = 13;
|
||||
sdram_data->spd_rev = 0x12;
|
||||
sprintf(sdram_data->part_no, EMU_NAME "-SDR-%03dM", vslots[vslot]);
|
||||
for (i = strlen(sdram_data->part_no); i < sizeof(sdram_data->part_no); i++)
|
||||
sdram_data->part_no[i] = ' '; /* part number should be space-padded */
|
||||
sdram_data->rev_code[0] = BCD8(EMU_VERSION_MAJ);
|
||||
sdram_data->rev_code[1] = BCD8(EMU_VERSION_MIN);
|
||||
sdram_data->mfg_year = 20;
|
||||
sdram_data->mfg_week = 13;
|
||||
|
||||
sdram_data->freq = 100;
|
||||
sdram_data->features = 0xFF;
|
||||
sdram_data->freq = 100;
|
||||
sdram_data->features = 0xFF;
|
||||
|
||||
for (i = 0; i < 63; i++)
|
||||
sdram_data->checksum += spd_data[slot][i];
|
||||
for (i = 0; i < 129; i++)
|
||||
sdram_data->checksum2 += spd_data[slot][i];
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < 63; i++)
|
||||
sdram_data->checksum += spd_data[slot][i];
|
||||
for (i = 0; i < 129; i++)
|
||||
sdram_data->checksum2 += spd_data[slot][i];
|
||||
break;
|
||||
}
|
||||
|
||||
device_add(info);
|
||||
vslot++;
|
||||
device_add(info);
|
||||
vslot++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,49 +405,49 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit
|
||||
|
||||
/* Special case for VIA Apollo Pro family, which jumps from 5F to 56. */
|
||||
if (reg_max < reg_min) {
|
||||
apollo = reg_max;
|
||||
reg_max = reg_min + 7;
|
||||
apollo = reg_max;
|
||||
reg_max = reg_min + 7;
|
||||
}
|
||||
|
||||
/* No SPD: split SIMMs into pairs as if they were "DIMM"s. */
|
||||
if (!spd_present) {
|
||||
dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */
|
||||
spd_populate(vslots, dimm, (mem_size >> 10), drb_unit, 1 << (log2_ui16(machines[machine].max_ram / dimm)), 0);
|
||||
dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */
|
||||
spd_populate(vslots, dimm, mem_size >> 10, drb_unit, 1 << (log2_ui16(machines[machine].max_ram / dimm)), 0);
|
||||
}
|
||||
|
||||
/* Write DRBs for each row. */
|
||||
spd_log("Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit);
|
||||
for (row = 0; row <= (reg_max - reg_min); row++) {
|
||||
dimm = (row >> 1);
|
||||
size = 0;
|
||||
dimm = (row >> 1);
|
||||
size = 0;
|
||||
|
||||
if (spd_present) {
|
||||
/* SPD enabled: use SPD info for this slot, if present. */
|
||||
if (spd_devices[dimm]) {
|
||||
if (spd_devices[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */
|
||||
size = ((row & 1) ? 0 : drb_unit);
|
||||
else
|
||||
size = ((row & 1) ? spd_devices[dimm]->row2 : spd_devices[dimm]->row1);
|
||||
}
|
||||
} else {
|
||||
/* No SPD: use the values calculated above. */
|
||||
size = (vslots[dimm] >> 1);
|
||||
}
|
||||
if (spd_present) {
|
||||
/* SPD enabled: use SPD info for this slot, if present. */
|
||||
if (spd_devices[dimm]) {
|
||||
if (spd_devices[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */
|
||||
size = (row & 1) ? 0 : drb_unit;
|
||||
else
|
||||
size = (row & 1) ? spd_devices[dimm]->row2 : spd_devices[dimm]->row1;
|
||||
}
|
||||
} else {
|
||||
/* No SPD: use the values calculated above. */
|
||||
size = (vslots[dimm] >> 1);
|
||||
}
|
||||
|
||||
/* Determine the DRB register to write. */
|
||||
drb = reg_min + row;
|
||||
if ((apollo) && ((drb & 0xf) < 0xa))
|
||||
drb = apollo + (drb & 0xf);
|
||||
/* Determine the DRB register to write. */
|
||||
drb = reg_min + row;
|
||||
if (apollo && ((drb & 0xf) < 0xa))
|
||||
drb = apollo + (drb & 0xf);
|
||||
|
||||
/* Write DRB register, adding the previous DRB's value. */
|
||||
if (row == 0)
|
||||
regs[drb] = 0;
|
||||
else if ((apollo) && (drb == apollo))
|
||||
regs[drb] = regs[drb | 0xf]; /* 5F comes before 56 */
|
||||
else
|
||||
regs[drb] = regs[drb - 1];
|
||||
if (size)
|
||||
regs[drb] += (size / drb_unit); /* this will intentionally overflow on 440GX with 2 GB */
|
||||
spd_log("DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]);
|
||||
/* Write DRB register, adding the previous DRB's value. */
|
||||
if (row == 0)
|
||||
regs[drb] = 0;
|
||||
else if ((apollo) && (drb == apollo))
|
||||
regs[drb] = regs[drb | 0xf]; /* 5F comes before 56 */
|
||||
else
|
||||
regs[drb] = regs[drb - 1];
|
||||
if (size)
|
||||
regs[drb] += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */
|
||||
spd_log("DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user