@@ -29,7 +29,10 @@ struct MPS2SCC {
uint32_t cfg0;
uint32_t cfg1;
+ uint32_t cfg2;
uint32_t cfg4;
+ uint32_t cfg5;
+ uint32_t cfg6;
uint32_t cfgdata_rtn;
uint32_t cfgdata_out;
uint32_t cfgctrl;
@@ -31,8 +31,11 @@
REG32(CFG0, 0)
REG32(CFG1, 4)
+REG32(CFG2, 8)
REG32(CFG3, 0xc)
REG32(CFG4, 0x10)
+REG32(CFG5, 0x14)
+REG32(CFG6, 0x18)
REG32(CFGDATA_RTN, 0xa0)
REG32(CFGDATA_OUT, 0xa4)
REG32(CFGCTRL, 0xa8)
@@ -49,6 +52,12 @@ REG32(DLL, 0x100)
REG32(AID, 0xFF8)
REG32(ID, 0xFFC)
+static int scc_partno(MPS2SCC *s)
+{
+ /* Return the partno field of the SCC_ID (0x524, 0x511, etc) */
+ return extract32(s->id, 4, 8);
+}
+
/* Handle a write via the SYS_CFG channel to the specified function/device.
* Return false on error (reported to guest via SYS_CFGCTRL ERROR bit).
*/
@@ -100,7 +109,18 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
case A_CFG1:
r = s->cfg1;
break;
+ case A_CFG2:
+ if (scc_partno(s) != 0x524) {
+ /* CFG2 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg2;
+ break;
case A_CFG3:
+ if (scc_partno(s) == 0x524) {
+ /* CFG3 reserved on AN524 */
+ goto bad_offset;
+ }
/* These are user-settable DIP switches on the board. We don't
* model that, so just return zeroes.
*/
@@ -109,6 +129,20 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
case A_CFG4:
r = s->cfg4;
break;
+ case A_CFG5:
+ if (scc_partno(s) != 0x524) {
+ /* CFG5 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg5;
+ break;
+ case A_CFG6:
+ if (scc_partno(s) != 0x524) {
+ /* CFG6 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg6;
+ break;
case A_CFGDATA_RTN:
r = s->cfgdata_rtn;
break;
@@ -131,6 +165,7 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
r = s->id;
break;
default:
+ bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC read: bad offset %x\n", (int) offset);
r = 0;
@@ -159,6 +194,30 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
led_set_state(s->led[i], extract32(value, i, 1));
}
break;
+ case A_CFG2:
+ if (scc_partno(s) != 0x524) {
+ /* CFG2 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: QSPI Select signal */
+ s->cfg2 = value;
+ break;
+ case A_CFG5:
+ if (scc_partno(s) != 0x524) {
+ /* CFG5 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: ACLK frequency in Hz */
+ s->cfg5 = value;
+ break;
+ case A_CFG6:
+ if (scc_partno(s) != 0x524) {
+ /* CFG6 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: Clock divider for BRAM */
+ s->cfg6 = value;
+ break;
case A_CFGDATA_OUT:
s->cfgdata_out = value;
break;
@@ -202,6 +261,7 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
s->dll = deposit32(s->dll, 24, 8, extract32(value, 24, 8));
break;
default:
+ bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC write: bad offset 0x%x\n", (int) offset);
break;
@@ -222,6 +282,9 @@ static void mps2_scc_reset(DeviceState *dev)
trace_mps2_scc_reset();
s->cfg0 = 0;
s->cfg1 = 0;
+ s->cfg2 = 0;
+ s->cfg5 = 0;
+ s->cfg6 = 0;
s->cfgdata_rtn = 0;
s->cfgdata_out = 0;
s->cfgctrl = 0x100000;
@@ -260,11 +323,15 @@ static void mps2_scc_realize(DeviceState *dev, Error **errp)
static const VMStateDescription mps2_scc_vmstate = {
.name = "mps2-scc",
- .version_id = 2,
- .minimum_version_id = 2,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cfg0, MPS2SCC),
VMSTATE_UINT32(cfg1, MPS2SCC),
+ VMSTATE_UINT32(cfg2, MPS2SCC),
+ /* cfg3, cfg4 are read-only so need not be migrated */
+ VMSTATE_UINT32(cfg5, MPS2SCC),
+ VMSTATE_UINT32(cfg6, MPS2SCC),
VMSTATE_UINT32(cfgdata_rtn, MPS2SCC),
VMSTATE_UINT32(cfgdata_out, MPS2SCC),
VMSTATE_UINT32(cfgctrl, MPS2SCC),