I2C overhaul part 3: "we finally figured out NCR NVRAM" edition

This commit is contained in:
RichardG867
2020-11-21 01:36:33 -03:00
parent cf2dba5838
commit d5867928d6
8 changed files with 214 additions and 235 deletions

View File

@@ -103,13 +103,16 @@ gl518sm_i2c_read(void *bus, uint8_t addr, void *priv)
uint16_t read = gl518sm_read(dev, dev->addr_register); uint16_t read = gl518sm_read(dev, dev->addr_register);
uint8_t ret = 0; uint8_t ret = 0;
if (dev->i2c_state == 0)
dev->i2c_state = 1;
if ((dev->i2c_state == 1) && (dev->addr_register >= 0x07) && (dev->addr_register <= 0x0c)) { /* two-byte registers: read MSB first */ if ((dev->i2c_state == 1) && (dev->addr_register >= 0x07) && (dev->addr_register <= 0x0c)) { /* two-byte registers: read MSB first */
dev->i2c_state = 2; dev->i2c_state = 2;
ret = read >> 8; ret = read >> 8;
} else } else {
ret = read; ret = read;
dev->addr_register++; dev->addr_register++;
}
return ret; return ret;
} }
@@ -178,6 +181,7 @@ gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
break; break;
default: default:
dev->i2c_state = 3;
return 0; return 0;
} }

View File

@@ -35,7 +35,7 @@ static uint8_t lm75_i2c_read(void *bus, uint8_t addr, void *priv);
static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv);
static void lm75_reset(lm75_t *dev); static void lm75_reset(lm75_t *dev);
#define ENABLE_LM75_LOG 1
#ifdef ENABLE_LM75_LOG #ifdef ENABLE_LM75_LOG
int lm75_do_log = ENABLE_LM75_LOG; int lm75_do_log = ENABLE_LM75_LOG;
@@ -86,9 +86,21 @@ lm75_i2c_read(void *bus, uint8_t addr, void *priv)
lm75_t *dev = (lm75_t *) priv; lm75_t *dev = (lm75_t *) priv;
uint8_t ret = 0; uint8_t ret = 0;
if (dev->i2c_state == 0)
dev->i2c_state = 1;
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register);
ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
} else {
switch (dev->addr_register & 0x3) { switch (dev->addr_register & 0x3) {
case 0x0: /* temperature */ case 0x0: /* temperature */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x1 : 0x0); ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x0 : 0x1);
break; break;
case 0x1: /* configuration */ case 0x1: /* configuration */
@@ -96,12 +108,16 @@ lm75_i2c_read(void *bus, uint8_t addr, void *priv)
break; break;
case 0x2: /* Thyst */ case 0x2: /* Thyst */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x4 : 0x3); ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x3 : 0x4);
break; break;
case 0x3: /* Tos */ case 0x3: /* Tos */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x6 : 0x5); ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x5 : 0x6);
break; break;
} }
}
if (++dev->i2c_state > 2)
dev->i2c_state = 2;
return ret; return ret;
} }
@@ -112,15 +128,7 @@ lm75_read(lm75_t *dev, uint8_t reg)
{ {
uint8_t ret; uint8_t ret;
/* The AS99127F hardware monitor uses the addresses of its LM75 devices if ((reg & 0x7) == 0x0) /* temperature high byte */
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg);
ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
} else if ((reg & 0x7) == 0x0) /* temperature high byte */
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8; ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8;
else if ((reg & 0x7) == 0x1) /* temperature low byte */ else if ((reg & 0x7) == 0x1) /* temperature low byte */
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]); ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]);
@@ -145,9 +153,19 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
return 1; return 1;
} }
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, data);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
return 1;
} else {
switch (dev->addr_register & 0x3) { switch (dev->addr_register & 0x3) {
case 0x0: /* temperature */ case 0x0: /* temperature */
lm75_write(dev, (dev->i2c_state == 1) ? 0x1 : 0x0, data); lm75_write(dev, (dev->i2c_state == 1) ? 0x0 : 0x1, data);
break; break;
case 0x1: /* configuration */ case 0x1: /* configuration */
@@ -155,12 +173,16 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
break; break;
case 0x2: /* Thyst */ case 0x2: /* Thyst */
lm75_write(dev, (dev->i2c_state == 1) ? 0x4 : 0x3, data); lm75_write(dev, (dev->i2c_state == 1) ? 0x3 : 0x4, data);
break; break;
case 0x3: /* Tos */ case 0x3: /* Tos */
lm75_write(dev, (dev->i2c_state == 1) ? 0x6 : 0x5, data); lm75_write(dev, (dev->i2c_state == 1) ? 0x5 : 0x6, data);
break; break;
} }
}
if (++dev->i2c_state > 2)
dev->i2c_state = 2;
return 1; return 1;
} }
@@ -171,17 +193,6 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val)
{ {
lm75_log("LM75: write(%02X, %02X)\n", reg, val); lm75_log("LM75: write(%02X, %02X)\n", reg, val);
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, val);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
return 1;
}
uint8_t reg_idx = (reg & 0x7); uint8_t reg_idx = (reg & 0x7);
if ((reg_idx <= 0x1) || (reg_idx == 0x7)) if ((reg_idx <= 0x1) || (reg_idx == 0x7))

View File

@@ -69,7 +69,7 @@ static uint8_t lm78_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank); static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank);
static void lm78_reset(lm78_t *dev, uint8_t initialization); static void lm78_reset(lm78_t *dev, uint8_t initialization);
#define ENABLE_LM78_LOG 1
#ifdef ENABLE_LM78_LOG #ifdef ENABLE_LM78_LOG
int lm78_do_log = ENABLE_LM78_LOG; int lm78_do_log = ENABLE_LM78_LOG;

View File

@@ -194,6 +194,8 @@ i2c_has_device(void *bus_handle, uint8_t addr)
if (!bus) if (!bus)
return 0; return 0;
i2c_log("I2C: has_device(%s, %02X) = %d\n", bus->name, addr, !!bus->devices[addr]);
return(!!bus->devices[addr]); return(!!bus->devices[addr]);
} }

View File

@@ -6,7 +6,7 @@
* *
* This file is part of the 86Box distribution. * This file is part of the 86Box distribution.
* *
* Emulation of the AT24Cxx series of I2C EEPROMs. * Emulation of the 24Cxx series of I2C EEPROMs.
* *
* *
* *
@@ -27,22 +27,42 @@
typedef struct { typedef struct {
void *i2c; void *i2c;
uint8_t addr; uint8_t addr, *data, writable;
uint8_t *data;
uint8_t writable;
uint16_t addr_mask; uint16_t addr_mask, addr_register;
uint8_t addr_register;
uint8_t i2c_state; uint8_t i2c_state;
} i2c_eeprom_t; } i2c_eeprom_t;
#define ENABLE_I2C_EEPROM_LOG 1
#ifdef ENABLE_I2C_EEPROM_LOG
int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG;
static void
i2c_eeprom_log(const char *fmt, ...)
{
va_list ap;
if (i2c_eeprom_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define i2c_eeprom_log(fmt, ...)
#endif
void void
i2c_eeprom_start(void *bus, uint8_t addr, void *priv) i2c_eeprom_start(void *bus, uint8_t addr, void *priv)
{ {
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
i2c_eeprom_log("I2C EEPROM: start()\n");
dev->i2c_state = 0; dev->i2c_state = 0;
dev->addr_register = (addr << 8) & dev->addr_mask;
} }
@@ -50,8 +70,13 @@ uint8_t
i2c_eeprom_read(void *bus, uint8_t addr, void *priv) i2c_eeprom_read(void *bus, uint8_t addr, void *priv)
{ {
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
uint8_t ret = dev->data[dev->addr_register];
return dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask]; i2c_eeprom_log("I2C EEPROM: read(%04X) = %02X\n", dev->addr_register, ret);
if (++dev->addr_register > dev->addr_mask) /* roll-over */
dev->addr_register = 0;
return ret;
} }
@@ -62,11 +87,16 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv)
if (dev->i2c_state == 0) { if (dev->i2c_state == 0) {
dev->i2c_state = 1; dev->i2c_state = 1;
dev->addr_register = data; dev->addr_register = ((addr << 8) | data) & dev->addr_mask;
} else if (dev->writable) i2c_eeprom_log("I2C EEPROM: write(address, %04X)\n", dev->addr_register);
dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask] = data; } else {
else i2c_eeprom_log("I2C EEPROM: write(%04X, %02X) = %s\n", dev->addr_register, data, dev->writable ? "accepted" : "blocked");
return 0; if (dev->writable)
dev->data[dev->addr_register] = data;
if (++dev->addr_register > dev->addr_mask) /* roll-over */
dev->addr_register = 0;
return dev->writable;
}
return 1; return 1;
} }
@@ -78,6 +108,8 @@ i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t w
i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t)); i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t));
memset(dev, 0, sizeof(i2c_eeprom_t)); memset(dev, 0, sizeof(i2c_eeprom_t));
i2c_eeprom_log("I2C EEPROM: init(%02X, %d, %d)\n", addr, size, writable);
dev->i2c = i2c; dev->i2c = i2c;
dev->addr = addr; dev->addr = addr;
dev->data = data; dev->data = data;
@@ -96,6 +128,8 @@ i2c_eeprom_close(void *dev_handle)
{ {
i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle; i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle;
i2c_eeprom_log("I2C EEPROM: close()\n");
i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev);
free(dev); free(dev);

View File

@@ -52,19 +52,43 @@ enum {
}; };
typedef struct { typedef struct {
char *bus_name;
void *i2c; void *i2c;
uint8_t scl, sda, state, slave_state, slave_addr, uint8_t scl, sda, state, slave_state, slave_addr,
slave_rw, last_sda, pos, transmit, byte; slave_rw, last_sda, pos, transmit, byte;
} i2c_gpio_t; } i2c_gpio_t;
#ifdef ENABLE_I2C_GPIO_LOG
int i2c_gpio_do_log = ENABLE_I2C_GPIO_LOG;
static void
i2c_gpio_log(int level, const char *fmt, ...)
{
va_list ap;
if (i2c_gpio_do_log >= level) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define i2c_gpio_log(fmt, ...)
#endif
void * void *
i2c_gpio_init(char *bus_name) i2c_gpio_init(char *bus_name)
{ {
i2c_gpio_t *dev = (i2c_gpio_t *) malloc(sizeof(i2c_gpio_t)); i2c_gpio_t *dev = (i2c_gpio_t *) malloc(sizeof(i2c_gpio_t));
memset(dev, 0, sizeof(i2c_gpio_t)); memset(dev, 0, sizeof(i2c_gpio_t));
dev->i2c = i2c_addbus(bus_name); i2c_gpio_log(1, "I2C GPIO %s: init()\n", bus_name);
dev->bus_name = bus_name;
dev->i2c = i2c_addbus(dev->bus_name);
dev->scl = dev->sda = 1; dev->scl = dev->sda = 1;
dev->slave_addr = 0xff; dev->slave_addr = 0xff;
@@ -77,6 +101,8 @@ i2c_gpio_close(void *dev_handle)
{ {
i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle;
i2c_gpio_log(1, "I2C GPIO %s: close()\n", dev->bus_name);
i2c_removebus(dev->i2c); i2c_removebus(dev->i2c);
free(dev); free(dev);
@@ -87,6 +113,7 @@ void
i2c_gpio_next_byte(i2c_gpio_t *dev) i2c_gpio_next_byte(i2c_gpio_t *dev)
{ {
dev->byte = i2c_read(dev->i2c, dev->slave_addr); dev->byte = i2c_read(dev->i2c, dev->slave_addr);
i2c_gpio_log(1, "I2C GPIO %s: next_byte() = %02X\n", dev->bus_name, dev->byte);
} }
@@ -101,6 +128,8 @@ i2c_gpio_write(i2c_gpio_t *dev)
dev->slave_addr = dev->byte >> 1; dev->slave_addr = dev->byte >> 1;
dev->slave_rw = dev->byte & 1; dev->slave_rw = dev->byte & 1;
i2c_gpio_log(1, "I2C GPIO %s: Initiating transfer to address %02X rw %d\n", dev->bus_name, dev->slave_addr, dev->slave_rw);
if (!i2c_has_device(dev->i2c, dev->slave_addr)) { if (!i2c_has_device(dev->i2c, dev->slave_addr)) {
dev->slave_state = SLAVE_INVALID; dev->slave_state = SLAVE_INVALID;
break; break;
@@ -120,11 +149,13 @@ i2c_gpio_write(i2c_gpio_t *dev)
break; break;
case SLAVE_RECEIVEADDR: case SLAVE_RECEIVEADDR:
i2c_gpio_log(1, "I2C GPIO %s: Receiving address %02X\n", dev->bus_name, dev->byte);
i2c_write(dev->i2c, dev->slave_addr, dev->byte); i2c_write(dev->i2c, dev->slave_addr, dev->byte);
dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA; dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA;
break; break;
case SLAVE_RECEIVEDATA: case SLAVE_RECEIVEDATA:
i2c_gpio_log(1, "I2C GPIO %s: Receiving data %02X\n", dev->bus_name, dev->byte);
i2c_write(dev->i2c, dev->slave_addr, dev->byte); i2c_write(dev->i2c, dev->slave_addr, dev->byte);
break; break;
} }
@@ -134,6 +165,9 @@ i2c_gpio_write(i2c_gpio_t *dev)
void void
i2c_gpio_stop(i2c_gpio_t *dev) i2c_gpio_stop(i2c_gpio_t *dev)
{ {
i2c_gpio_log(1, "I2C GPIO %s: Stopping transfer\n", dev->bus_name);
if (dev->slave_addr != 0xff)
i2c_stop(dev->i2c, dev->slave_addr); i2c_stop(dev->i2c, dev->slave_addr);
dev->slave_addr = 0xff; dev->slave_addr = 0xff;
@@ -149,7 +183,9 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
switch (dev->state) { switch (dev->state) {
case I2C_IDLE: case I2C_IDLE:
if (dev->scl && scl && dev->last_sda && !sda) { /* start bit */ /* !dev->scl check breaks NCR SDMS. */
if (/*!dev->scl &&*/ scl && dev->last_sda && !sda) { /* start bit */
i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from IDLE)\n", dev->bus_name);
dev->state = I2C_RECEIVE; dev->state = I2C_RECEIVE;
dev->pos = 0; dev->pos = 0;
} }
@@ -173,9 +209,11 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
} }
} else if (dev->scl && scl) { } else if (dev->scl && scl) {
if (sda && !dev->last_sda) { /* stop bit */ if (sda && !dev->last_sda) { /* stop bit */
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from RECEIVE)\n", dev->bus_name);
dev->state = I2C_IDLE; dev->state = I2C_IDLE;
i2c_gpio_stop(dev); i2c_gpio_stop(dev);
} else if (!sda && dev->last_sda) { /* start bit */ } else if (!sda && dev->last_sda) { /* start bit */
i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from RECEIVE)\n", dev->bus_name);
dev->pos = 0; dev->pos = 0;
dev->slave_state = SLAVE_IDLE; dev->slave_state = SLAVE_IDLE;
} }
@@ -184,6 +222,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
case I2C_ACKNOWLEDGE: case I2C_ACKNOWLEDGE:
if (!dev->scl && scl) { if (!dev->scl && scl) {
i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer\n", dev->bus_name);
sda = 0; sda = 0;
dev->pos = 0; dev->pos = 0;
dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT; dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT;
@@ -193,12 +232,14 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
case I2C_TRANSACKNOWLEDGE: case I2C_TRANSACKNOWLEDGE:
if (!dev->scl && scl) { if (!dev->scl && scl) {
if (sda) { /* not acknowledged; must be end of transfer */ if (sda) { /* not acknowledged; must be end of transfer */
i2c_gpio_log(2, "I2C GPIO %s: End of transfer\n", dev->bus_name);
dev->state = I2C_IDLE; dev->state = I2C_IDLE;
i2c_gpio_stop(dev); i2c_gpio_stop(dev);
} else { /* next byte to transfer */ } else { /* next byte to transfer */
dev->state = I2C_TRANSMIT_START; dev->state = I2C_TRANSMIT_START;
i2c_gpio_next_byte(dev); i2c_gpio_next_byte(dev);
dev->pos = 0; dev->pos = 0;
i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte);
} }
} }
break; break;
@@ -208,8 +249,10 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
if (dev->last_sda && !sda) { /* start bit */ if (dev->last_sda && !sda) { /* start bit */
i2c_gpio_next_byte(dev); i2c_gpio_next_byte(dev);
dev->pos = 0; dev->pos = 0;
i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte);
} }
if (!dev->last_sda && sda) { /* stop bit */ if (!dev->last_sda && sda) { /* stop bit */
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_WAIT)\n", dev->bus_name);
dev->state = I2C_IDLE; dev->state = I2C_IDLE;
i2c_gpio_stop(dev); i2c_gpio_stop(dev);
} }
@@ -220,6 +263,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
if (!dev->scl && scl) if (!dev->scl && scl)
dev->state = I2C_TRANSMIT; dev->state = I2C_TRANSMIT;
if (dev->scl && scl && !dev->last_sda && sda) { /* stop bit */ if (dev->scl && scl && !dev->last_sda && sda) { /* stop bit */
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_START)\n", dev->bus_name);
dev->state = I2C_IDLE; dev->state = I2C_IDLE;
i2c_gpio_stop(dev); i2c_gpio_stop(dev);
} }
@@ -228,13 +272,18 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
case I2C_TRANSMIT: case I2C_TRANSMIT:
if (!dev->scl && scl) { if (!dev->scl && scl) {
dev->scl = scl; dev->scl = scl;
if (!dev->pos)
i2c_gpio_log(2, "I2C GPIO %s: Transmit byte %02X\n", dev->bus_name, dev->byte);
dev->sda = sda = dev->byte & 0x80; dev->sda = sda = dev->byte & 0x80;
i2c_gpio_log(2, "I2C GPIO %s: Transmit bit %02X %d\n", dev->bus_name, dev->byte, dev->pos);
dev->byte <<= 1; dev->byte <<= 1;
dev->pos++; dev->pos++;
return; return;
} }
if (dev->scl && !scl && (dev->pos == 8)) if (dev->scl && !scl && (dev->pos == 8)) {
dev->state = I2C_TRANSACKNOWLEDGE; dev->state = I2C_TRANSACKNOWLEDGE;
i2c_gpio_log(2, "I2C GPIO %s: Acknowledge mode\n", dev->bus_name);
}
break; break;
} }

View File

@@ -43,6 +43,7 @@
#include <86box/device.h> #include <86box/device.h>
#include <86box/nvr.h> #include <86box/nvr.h>
#include <86box/plat.h> #include <86box/plat.h>
#include <86box/i2c.h>
#include <86box/scsi.h> #include <86box/scsi.h>
#include <86box/scsi_device.h> #include <86box/scsi_device.h>
#include <86box/scsi_ncr53c8xx.h> #include <86box/scsi_ncr53c8xx.h>
@@ -225,14 +226,8 @@ typedef struct {
int msg_action; int msg_action;
int msg_len; int msg_len;
uint8_t msg[NCR_MAX_MSGIN_LEN]; uint8_t msg[NCR_MAX_MSGIN_LEN];
#ifdef USE_NVRAM uint8_t nvram[2048]; /* 24C16 EEPROM (16 kbit) */
uint16_t nvram; void *i2c, *eeprom;
uint8_t nvram_t;
uint8_t nvram_op;
uint8_t nvram_param;
uint8_t nvram_start;
uint8_t nvram_index;
#endif
uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */ uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */
/* 0 if SCRIPTS are running or stopped. /* 0 if SCRIPTS are running or stopped.
* 1 if a Wait Reselect instruction has been issued. * 1 if a Wait Reselect instruction has been issued.
@@ -434,10 +429,7 @@ ncr53c8xx_soft_reset(ncr53c8xx_t *dev)
dev->gpreg = 0; dev->gpreg = 0;
dev->slpar = 0; dev->slpar = 0;
dev->sstop = 1; dev->sstop = 1;
dev->gpcntl = 0x0f; dev->gpcntl = 0x03;
#ifdef USE_NVRAM
dev->nvram_t = dev->nvram_index = 0;
#endif
if (dev->chip >= CHIP_825) { if (dev->chip >= CHIP_825) {
/* This *IS* a wide SCSI controller, so reset all SCSI /* This *IS* a wide SCSI controller, so reset all SCSI
@@ -1452,146 +1444,22 @@ ncr53c8xx_callback(void *p)
} }
#ifdef USE_NVRAM
static void static void
ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save) ncr53c8xx_eeprom(ncr53c8xx_t *dev, uint8_t save)
{ {
FILE *f; FILE *f;
f = nvr_fopen(dev->nvr_path, save ? L"wb": L"rb");
if (f) {
if (save) if (save)
f = nvr_fopen(dev->nvr_path, L"wb"); fwrite(&dev->nvram, sizeof(dev->nvram), 1, f);
else else
f = nvr_fopen(dev->nvr_path, L"rb"); fread(&dev->nvram, sizeof(dev->nvram), 1, f);
if (f)
{
if (save) {
fwrite((uint8_t *) &dev->nvram, 1, 1, f);
fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f);
} else {
fread((uint8_t *) &dev->nvram, 1, 1, f);
fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f);
}
fclose(f); fclose(f);
f = NULL;
} }
} }
#define ADDRESS_LENGTH 9
#define ADDRESS_END (ADDRESS_LENGTH + 2)
#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2)
#define ADDRESS_MASK 0x3f
#define DATA_LENGTH 8
#define DATA_START (ADDRESS_END + 1)
#define DATA_END (ADDRESS_END + DATA_LENGTH)
static void
ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val)
{
uint8_t temp, old = dev->nvram_t;
dev->nvram_t = val & 0x03;
if (val & 0x02) {
if (!dev->nvram_index) {
/* First signal clocked in after clock is high, start bit. */
dev->nvram_start = 1;
ncr53c8xx_log("[W] Serial EEPROM: Start bit\n");
dev->nvram_op = 0;
} else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) {
if (!dev->nvram_start)
return;
dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1);
if (dev->nvram_index == 2) {
// ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op);
dev->nvram_param = 0;
}
} else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) {
if (!dev->nvram_start)
return;
dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3);
if (dev->nvram_index < ADDRESS_END) {
dev->nvram_index++;
return;
}
switch (dev->nvram_op) {
case 0x00:
temp = dev->nvram_param >> ADDRESS_SHIFT;
switch(temp) {
case 0x00:
ncr53c8xx_log("[W] Serial EEPROM: EWDS\n");
break;
case 0x01:
ncr53c8xx_log("[W] Serial EEPROM: WRAL\n");
break;
case 0x02:
ncr53c8xx_log("[W] Serial EEPROM: ERAL\n");
break;
case 0x03:
ncr53c8xx_log("[W] Serial EEPROM: EWEN\n");
break;
default:
ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n");
break;
}
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
return;
case 0x01:
ncr53c8xx_log("[W] Serial EEPROM: WRITE\n");
break;
case 0x02:
ncr53c8xx_log("[W] Serial EEPROM: READ\n");
break;
case 0x03:
ncr53c8xx_log("[W] Serial EEPROM: ERASE\n");
break;
default:
ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n");
break;
}
} else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) {
if (!dev->nvram_start)
return;
if (dev->nvram_index == DATA_END) {
ncr53c8xx_log("[W] Serial EEPROM: Data end\n");
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
return;
}
}
dev->nvram_index++;
}
}
static uint8_t
ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev)
{
uint8_t temp = 0;
if (dev->gpreg & 0x02) {
if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) {
if (!dev->nvram_start)
return temp;
dev->nvram_index++;
if (dev->nvram_index == DATA_END) {
ncr53c8xx_log("[R] Serial EEPROM: Data end\n");
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
return temp;
}
}
}
return temp;
}
#endif
static void static void
ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val)
{ {
@@ -1659,12 +1527,8 @@ ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val)
break; break;
case 0x07: /* GPREG */ case 0x07: /* GPREG */
ncr53c8xx_log("NCR 810: GPREG write %02X\n", val); ncr53c8xx_log("NCR 810: GPREG write %02X\n", val);
tmp = dev->gpreg; dev->gpreg = val;
dev->gpreg = val & 0xfe; i2c_gpio_set(dev->i2c, !!(dev->gpreg & 0x02), !!(dev->gpreg & 0x01));
#ifdef USE_NVRAM
if ((dev->gpcntl & 0xc3) == 0x00)
ncr53c8xx_serial_eeprom_write(dev, val & 0x03);
#endif
break; break;
case 0x08: /* SFBR */ case 0x08: /* SFBR */
/* The CPU is not allowed to write to this register. However the /* The CPU is not allowed to write to this register. However the
@@ -1893,13 +1757,18 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset)
ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid); ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid);
return dev->sdid; return dev->sdid;
case 0x07: /* GPREG */ case 0x07: /* GPREG */
#ifdef USE_NVRAM tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1f;
tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e; if ((dev->gpcntl & 0x41) == 0x01) {
if ((dev->gpcntl & 0xc3) == 0x01) tmp &= 0xfe;
tmp |= ncr53c8xx_serial_eeprom_read(dev); if (i2c_gpio_get_sda(dev->i2c))
#else tmp |= 0x01;
tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01; }
#endif if ((dev->gpcntl & 0x82) == 0x02) {
tmp &= 0xfd;
if (i2c_gpio_get_scl(dev->i2c))
tmp |= 0x02;
}
ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp); ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp);
return tmp; return tmp;
case 0x08: /* Revision ID */ case 0x08: /* Revision ID */
@@ -2695,10 +2564,11 @@ ncr53c8xx_init(const device_t *info)
dev->nvr_path = L"ncr53c810.nvr"; dev->nvr_path = L"ncr53c810.nvr";
} }
#ifdef USE_NVRAM dev->i2c = i2c_gpio_init("nvr_ncr53c8xx");
dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->nvram, sizeof(dev->nvram), 1);
/* Load the serial EEPROM. */ /* Load the serial EEPROM. */
ncr53c8xx_eeprom(dev, 0); ncr53c8xx_eeprom(dev, 0);
#endif
ncr53c8xx_soft_reset(dev); ncr53c8xx_soft_reset(dev);
@@ -2714,6 +2584,15 @@ ncr53c8xx_close(void *priv)
ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; ncr53c8xx_t *dev = (ncr53c8xx_t *)priv;
if (dev) { if (dev) {
/* Save the serial EEPROM. */
ncr53c8xx_eeprom(dev, 1);
if (dev->eeprom)
i2c_eeprom_close(dev->eeprom);
if (dev->i2c)
i2c_gpio_close(dev->i2c);
free(dev); free(dev);
dev = NULL; dev = NULL;
} }

View File

@@ -38,7 +38,7 @@ static uint8_t edid_data[128] = {
0x08, /* Analog input, separate sync */ 0x08, /* Analog input, separate sync */
34, 0, /* Landscape, 4:3 */ 34, 0, /* Landscape, 4:3 */
0, /* Gamma */ 0, /* Gamma */
0x08, /* RGB colour */ 0x08, /* RGB color */
0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */ 0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */
0xff, 0xff, 0xff, /* Established timing bitmap */ 0xff, 0xff, 0xff, /* Established timing bitmap */