* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "hw.h"
-#include "sun4m.h"
-#include "sysemu.h"
+
+#include "sysbus.h"
//#define DEBUG_ECC
#ifdef DEBUG_ECC
-#define DPRINTF(fmt, args...) \
- do { printf("ECC: " fmt , ##args); } while (0)
+#define DPRINTF(fmt, ...) \
+ do { printf("ECC: " fmt , ## __VA_ARGS__); } while (0)
#else
-#define DPRINTF(fmt, args...)
+#define DPRINTF(fmt, ...)
#endif
/* There are 3 versions of this chip used in SMP sun4m systems:
* MCC (version 0, implementation 0) SS-600MP
* EMC (version 0, implementation 1) SS-10
* SMC (version 0, implementation 2) SS-10SX and SS-20
+ *
+ * Chipset docs:
+ * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
+ * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
*/
+#define ECC_MCC 0x00000000
+#define ECC_EMC 0x10000000
+#define ECC_SMC 0x20000000
+
/* Register indexes */
#define ECC_MER 0 /* Memory Enable Register */
#define ECC_MDR 1 /* Memory Delay Register */
#define ECC_MER_MRR5 0x00000080 /* SIMM 5 */
#define ECC_MER_MRR6 0x00000100 /* SIMM 6 */
#define ECC_MER_MRR7 0x00000200 /* SIMM 7 */
-#define ECC_MER_REU 0x00000200 /* Memory Refresh Enable (600MP) */
+#define ECC_MER_REU 0x00000100 /* Memory Refresh Enable (600MP) */
#define ECC_MER_MRR 0x000003fc /* MRR mask */
-#define ECC_MEM_A 0x00000400 /* Memory controller addr map select */
+#define ECC_MER_A 0x00000400 /* Memory controller addr map select */
#define ECC_MER_DCI 0x00000800 /* Disables Coherent Invalidate ACK */
#define ECC_MER_VER 0x0f000000 /* Version */
#define ECC_MER_IMPL 0xf0000000 /* Implementation */
+#define ECC_MER_MASK_0 0x00000103 /* Version 0 (MCC) mask */
+#define ECC_MER_MASK_1 0x00000bff /* Version 1 (EMC) mask */
+#define ECC_MER_MASK_2 0x00000bff /* Version 2 (SMC) mask */
/* ECC memory delay register */
#define ECC_MDR_RRI 0x000003ff /* Refresh Request Interval */
#define ECC_DIAG_MASK (ECC_DIAG_SIZE - 1)
typedef struct ECCState {
+ SysBusDevice busdev;
qemu_irq irq;
uint32_t regs[ECC_NREGS];
uint8_t diag[ECC_DIAG_SIZE];
+ uint32_t version;
} ECCState;
static void ecc_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
switch (addr >> 2) {
case ECC_MER:
- s->regs[ECC_MER] = (s->regs[ECC_MER] & (ECC_MER_VER | ECC_MER_IMPL)) |
- (val & ~(ECC_MER_VER | ECC_MER_IMPL));
+ if (s->version == ECC_MCC)
+ s->regs[ECC_MER] = (val & ECC_MER_MASK_0);
+ else if (s->version == ECC_EMC)
+ s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1);
+ else if (s->version == ECC_SMC)
+ s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2);
DPRINTF("Write memory enable %08x\n", val);
break;
case ECC_MDR:
break;
case ECC_MFSR:
s->regs[ECC_MFSR] = val;
+ qemu_irq_lower(s->irq);
DPRINTF("Write memory fault status %08x\n", val);
break;
case ECC_VCR:
break;
case ECC_DR:
s->regs[ECC_DR] = val;
- DPRINTF("Write diagnosiic %08x\n", val);
+ DPRINTF("Write diagnostic %08x\n", val);
break;
case ECC_ECR0:
s->regs[ECC_ECR0] = val;
return ret;
}
-static CPUReadMemoryFunc *ecc_mem_read[3] = {
+static CPUReadMemoryFunc * const ecc_mem_read[3] = {
NULL,
NULL,
ecc_mem_readl,
};
-static CPUWriteMemoryFunc *ecc_mem_write[3] = {
+static CPUWriteMemoryFunc * const ecc_mem_write[3] = {
NULL,
NULL,
ecc_mem_writel,
return ret;
}
-static CPUReadMemoryFunc *ecc_diag_mem_read[3] = {
+static CPUReadMemoryFunc * const ecc_diag_mem_read[3] = {
ecc_diag_mem_readb,
NULL,
NULL,
};
-static CPUWriteMemoryFunc *ecc_diag_mem_write[3] = {
+static CPUWriteMemoryFunc * const ecc_diag_mem_write[3] = {
ecc_diag_mem_writeb,
NULL,
NULL,
};
-static int ecc_load(QEMUFile *f, void *opaque, int version_id)
-{
- ECCState *s = opaque;
- int i;
-
- if (version_id != 2)
- return -EINVAL;
-
- for (i = 0; i < ECC_NREGS; i++)
- qemu_get_be32s(f, &s->regs[i]);
-
- for (i = 0; i < ECC_DIAG_SIZE; i++)
- qemu_get_8s(f, &s->diag[i]);
-
- return 0;
-}
-
-static void ecc_save(QEMUFile *f, void *opaque)
-{
- ECCState *s = opaque;
- int i;
-
- for (i = 0; i < ECC_NREGS; i++)
- qemu_put_be32s(f, &s->regs[i]);
-
- for (i = 0; i < ECC_DIAG_SIZE; i++)
- qemu_put_8s(f, &s->diag[i]);
-}
+static const VMStateDescription vmstate_ecc = {
+ .name ="ECC",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .minimum_version_id_old = 3,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS),
+ VMSTATE_BUFFER(diag, ECCState),
+ VMSTATE_UINT32(version, ECCState),
+ VMSTATE_END_OF_LIST()
+ }
+};
-static void ecc_reset(void *opaque)
+static void ecc_reset(DeviceState *d)
{
- ECCState *s = opaque;
+ ECCState *s = container_of(d, ECCState, busdev.qdev);
- s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL);
- s->regs[ECC_MER] |= ECC_MER_MRR;
+ if (s->version == ECC_MCC)
+ s->regs[ECC_MER] &= ECC_MER_REU;
+ else
+ s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL | ECC_MER_MRR |
+ ECC_MER_DCI);
s->regs[ECC_MDR] = 0x20;
s->regs[ECC_MFSR] = 0;
s->regs[ECC_VCR] = 0;
s->regs[ECC_ECR1] = 0;
}
-void * ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version)
+static int ecc_init1(SysBusDevice *dev)
{
int ecc_io_memory;
- ECCState *s;
+ ECCState *s = FROM_SYSBUS(ECCState, dev);
- s = qemu_mallocz(sizeof(ECCState));
- if (!s)
- return NULL;
+ sysbus_init_irq(dev, &s->irq);
+ s->regs[0] = s->version;
+ ecc_io_memory = cpu_register_io_memory(ecc_mem_read, ecc_mem_write, s);
+ sysbus_init_mmio(dev, ECC_SIZE, ecc_io_memory);
- s->regs[0] = version;
- s->irq = irq;
-
- ecc_io_memory = cpu_register_io_memory(0, ecc_mem_read, ecc_mem_write, s);
- cpu_register_physical_memory(base, ECC_SIZE, ecc_io_memory);
- if (version == 0) { // SS-600MP only
- ecc_io_memory = cpu_register_io_memory(0, ecc_diag_mem_read,
+ if (s->version == ECC_MCC) { // SS-600MP only
+ ecc_io_memory = cpu_register_io_memory(ecc_diag_mem_read,
ecc_diag_mem_write, s);
- cpu_register_physical_memory(base + 0x1000, ECC_DIAG_SIZE,
- ecc_io_memory);
+ sysbus_init_mmio(dev, ECC_DIAG_SIZE, ecc_io_memory);
}
- register_savevm("ECC", base, 2, ecc_save, ecc_load, s);
- qemu_register_reset(ecc_reset, s);
- ecc_reset(s);
- return s;
+
+ return 0;
}
+
+static SysBusDeviceInfo ecc_info = {
+ .init = ecc_init1,
+ .qdev.name = "eccmemctl",
+ .qdev.size = sizeof(ECCState),
+ .qdev.vmsd = &vmstate_ecc,
+ .qdev.reset = ecc_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_HEX32("version", ECCState, version, -1),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+
+static void ecc_register_devices(void)
+{
+ sysbus_register_withprop(&ecc_info);
+}
+
+device_init(ecc_register_devices)