xref: /qemu/hw/misc/mps2-scc.c (revision 2a5ee4e1)
1dd73185bSPeter Maydell /*
2dd73185bSPeter Maydell  * ARM MPS2 SCC emulation
3dd73185bSPeter Maydell  *
4dd73185bSPeter Maydell  * Copyright (c) 2017 Linaro Limited
5dd73185bSPeter Maydell  * Written by Peter Maydell
6dd73185bSPeter Maydell  *
7dd73185bSPeter Maydell  *  This program is free software; you can redistribute it and/or modify
8dd73185bSPeter Maydell  *  it under the terms of the GNU General Public License version 2 or
9dd73185bSPeter Maydell  *  (at your option) any later version.
10dd73185bSPeter Maydell  */
11dd73185bSPeter Maydell 
12dd73185bSPeter Maydell /* This is a model of the SCC (Serial Communication Controller)
13dd73185bSPeter Maydell  * found in the FPGA images of MPS2 development boards.
14dd73185bSPeter Maydell  *
15dd73185bSPeter Maydell  * Documentation of it can be found in the MPS2 TRM:
1650b52b18SPeter Maydell  * https://developer.arm.com/documentation/100112/latest/
17dd73185bSPeter Maydell  * and also in the Application Notes documenting individual FPGA images.
18dd73185bSPeter Maydell  */
19dd73185bSPeter Maydell 
20dd73185bSPeter Maydell #include "qemu/osdep.h"
21dd73185bSPeter Maydell #include "qemu/log.h"
220b8fa32fSMarkus Armbruster #include "qemu/module.h"
23435db7ebSPhilippe Mathieu-Daudé #include "qemu/bitops.h"
24dd73185bSPeter Maydell #include "trace.h"
25dd73185bSPeter Maydell #include "hw/sysbus.h"
265bddf92eSPeter Maydell #include "hw/irq.h"
27d6454270SMarkus Armbruster #include "migration/vmstate.h"
28dd73185bSPeter Maydell #include "hw/registerfields.h"
29dd73185bSPeter Maydell #include "hw/misc/mps2-scc.h"
30435db7ebSPhilippe Mathieu-Daudé #include "hw/misc/led.h"
31a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
32dd73185bSPeter Maydell 
33dd73185bSPeter Maydell REG32(CFG0, 0)
34dd73185bSPeter Maydell REG32(CFG1, 4)
358e4b4c1cSPeter Maydell REG32(CFG2, 8)
36dd73185bSPeter Maydell REG32(CFG3, 0xc)
37dd73185bSPeter Maydell REG32(CFG4, 0x10)
388e4b4c1cSPeter Maydell REG32(CFG5, 0x14)
398e4b4c1cSPeter Maydell REG32(CFG6, 0x18)
40*2a5ee4e1SPeter Maydell REG32(CFG7, 0x1c)
41dd73185bSPeter Maydell REG32(CFGDATA_RTN, 0xa0)
42dd73185bSPeter Maydell REG32(CFGDATA_OUT, 0xa4)
43dd73185bSPeter Maydell REG32(CFGCTRL, 0xa8)
44dd73185bSPeter Maydell     FIELD(CFGCTRL, DEVICE, 0, 12)
45dd73185bSPeter Maydell     FIELD(CFGCTRL, RES1, 12, 8)
46dd73185bSPeter Maydell     FIELD(CFGCTRL, FUNCTION, 20, 6)
47dd73185bSPeter Maydell     FIELD(CFGCTRL, RES2, 26, 4)
48dd73185bSPeter Maydell     FIELD(CFGCTRL, WRITE, 30, 1)
49dd73185bSPeter Maydell     FIELD(CFGCTRL, START, 31, 1)
50dd73185bSPeter Maydell REG32(CFGSTAT, 0xac)
51dd73185bSPeter Maydell     FIELD(CFGSTAT, DONE, 0, 1)
52dd73185bSPeter Maydell     FIELD(CFGSTAT, ERROR, 1, 1)
53dd73185bSPeter Maydell REG32(DLL, 0x100)
54dd73185bSPeter Maydell REG32(AID, 0xFF8)
55dd73185bSPeter Maydell REG32(ID, 0xFFC)
56dd73185bSPeter Maydell 
scc_partno(MPS2SCC * s)578e4b4c1cSPeter Maydell static int scc_partno(MPS2SCC *s)
588e4b4c1cSPeter Maydell {
598e4b4c1cSPeter Maydell     /* Return the partno field of the SCC_ID (0x524, 0x511, etc) */
608e4b4c1cSPeter Maydell     return extract32(s->id, 4, 8);
618e4b4c1cSPeter Maydell }
628e4b4c1cSPeter Maydell 
635f3bbbdbSPeter Maydell /* Is CFG_REG2 present? */
have_cfg2(MPS2SCC * s)645f3bbbdbSPeter Maydell static bool have_cfg2(MPS2SCC *s)
655f3bbbdbSPeter Maydell {
66*2a5ee4e1SPeter Maydell     return scc_partno(s) == 0x524 || scc_partno(s) == 0x547 ||
67*2a5ee4e1SPeter Maydell         scc_partno(s) == 0x536;
685f3bbbdbSPeter Maydell }
695f3bbbdbSPeter Maydell 
705f3bbbdbSPeter Maydell /* Is CFG_REG3 present? */
have_cfg3(MPS2SCC * s)715f3bbbdbSPeter Maydell static bool have_cfg3(MPS2SCC *s)
725f3bbbdbSPeter Maydell {
73*2a5ee4e1SPeter Maydell     return scc_partno(s) != 0x524 && scc_partno(s) != 0x547 &&
74*2a5ee4e1SPeter Maydell         scc_partno(s) != 0x536;
755f3bbbdbSPeter Maydell }
765f3bbbdbSPeter Maydell 
775f3bbbdbSPeter Maydell /* Is CFG_REG5 present? */
have_cfg5(MPS2SCC * s)785f3bbbdbSPeter Maydell static bool have_cfg5(MPS2SCC *s)
795f3bbbdbSPeter Maydell {
80*2a5ee4e1SPeter Maydell     return scc_partno(s) == 0x524 || scc_partno(s) == 0x547 ||
81*2a5ee4e1SPeter Maydell         scc_partno(s) == 0x536;
825f3bbbdbSPeter Maydell }
835f3bbbdbSPeter Maydell 
845f3bbbdbSPeter Maydell /* Is CFG_REG6 present? */
have_cfg6(MPS2SCC * s)855f3bbbdbSPeter Maydell static bool have_cfg6(MPS2SCC *s)
865f3bbbdbSPeter Maydell {
87*2a5ee4e1SPeter Maydell     return scc_partno(s) == 0x524 || scc_partno(s) == 0x536;
88*2a5ee4e1SPeter Maydell }
89*2a5ee4e1SPeter Maydell 
90*2a5ee4e1SPeter Maydell /* Is CFG_REG7 present? */
have_cfg7(MPS2SCC * s)91*2a5ee4e1SPeter Maydell static bool have_cfg7(MPS2SCC *s)
92*2a5ee4e1SPeter Maydell {
93*2a5ee4e1SPeter Maydell     return scc_partno(s) == 0x536;
94*2a5ee4e1SPeter Maydell }
95*2a5ee4e1SPeter Maydell 
96*2a5ee4e1SPeter Maydell /* Does CFG_REG0 drive the 'remap' GPIO output? */
cfg0_is_remap(MPS2SCC * s)97*2a5ee4e1SPeter Maydell static bool cfg0_is_remap(MPS2SCC *s)
98*2a5ee4e1SPeter Maydell {
99*2a5ee4e1SPeter Maydell     return scc_partno(s) != 0x536;
100*2a5ee4e1SPeter Maydell }
101*2a5ee4e1SPeter Maydell 
102*2a5ee4e1SPeter Maydell /* Is CFG_REG1 driving a set of LEDs? */
cfg1_is_leds(MPS2SCC * s)103*2a5ee4e1SPeter Maydell static bool cfg1_is_leds(MPS2SCC *s)
104*2a5ee4e1SPeter Maydell {
105*2a5ee4e1SPeter Maydell     return scc_partno(s) != 0x536;
1065f3bbbdbSPeter Maydell }
1075f3bbbdbSPeter Maydell 
108dd73185bSPeter Maydell /* Handle a write via the SYS_CFG channel to the specified function/device.
109dd73185bSPeter Maydell  * Return false on error (reported to guest via SYS_CFGCTRL ERROR bit).
110dd73185bSPeter Maydell  */
scc_cfg_write(MPS2SCC * s,unsigned function,unsigned device,uint32_t value)111dd73185bSPeter Maydell static bool scc_cfg_write(MPS2SCC *s, unsigned function,
112dd73185bSPeter Maydell                           unsigned device, uint32_t value)
113dd73185bSPeter Maydell {
114dd73185bSPeter Maydell     trace_mps2_scc_cfg_write(function, device, value);
115dd73185bSPeter Maydell 
1164fb013afSPeter Maydell     if (function != 1 || device >= s->num_oscclk) {
117dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
118dd73185bSPeter Maydell                       "MPS2 SCC config write: bad function %d device %d\n",
119dd73185bSPeter Maydell                       function, device);
120dd73185bSPeter Maydell         return false;
121dd73185bSPeter Maydell     }
122dd73185bSPeter Maydell 
123dd73185bSPeter Maydell     s->oscclk[device] = value;
124dd73185bSPeter Maydell     return true;
125dd73185bSPeter Maydell }
126dd73185bSPeter Maydell 
127dd73185bSPeter Maydell /* Handle a read via the SYS_CFG channel to the specified function/device.
128dd73185bSPeter Maydell  * Return false on error (reported to guest via SYS_CFGCTRL ERROR bit),
129dd73185bSPeter Maydell  * or set *value on success.
130dd73185bSPeter Maydell  */
scc_cfg_read(MPS2SCC * s,unsigned function,unsigned device,uint32_t * value)131dd73185bSPeter Maydell static bool scc_cfg_read(MPS2SCC *s, unsigned function,
132dd73185bSPeter Maydell                          unsigned device, uint32_t *value)
133dd73185bSPeter Maydell {
1344fb013afSPeter Maydell     if (function != 1 || device >= s->num_oscclk) {
135dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
136dd73185bSPeter Maydell                       "MPS2 SCC config read: bad function %d device %d\n",
137dd73185bSPeter Maydell                       function, device);
138dd73185bSPeter Maydell         return false;
139dd73185bSPeter Maydell     }
140dd73185bSPeter Maydell 
141dd73185bSPeter Maydell     *value = s->oscclk[device];
142dd73185bSPeter Maydell 
143dd73185bSPeter Maydell     trace_mps2_scc_cfg_read(function, device, *value);
144dd73185bSPeter Maydell     return true;
145dd73185bSPeter Maydell }
146dd73185bSPeter Maydell 
mps2_scc_read(void * opaque,hwaddr offset,unsigned size)147dd73185bSPeter Maydell static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
148dd73185bSPeter Maydell {
149dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(opaque);
150dd73185bSPeter Maydell     uint64_t r;
151dd73185bSPeter Maydell 
152dd73185bSPeter Maydell     switch (offset) {
153dd73185bSPeter Maydell     case A_CFG0:
154dd73185bSPeter Maydell         r = s->cfg0;
155dd73185bSPeter Maydell         break;
156dd73185bSPeter Maydell     case A_CFG1:
157dd73185bSPeter Maydell         r = s->cfg1;
158dd73185bSPeter Maydell         break;
1598e4b4c1cSPeter Maydell     case A_CFG2:
1605f3bbbdbSPeter Maydell         if (!have_cfg2(s)) {
1618e4b4c1cSPeter Maydell             goto bad_offset;
1628e4b4c1cSPeter Maydell         }
1638e4b4c1cSPeter Maydell         r = s->cfg2;
1648e4b4c1cSPeter Maydell         break;
165dd73185bSPeter Maydell     case A_CFG3:
1665f3bbbdbSPeter Maydell         if (!have_cfg3(s)) {
1678e4b4c1cSPeter Maydell             goto bad_offset;
1688e4b4c1cSPeter Maydell         }
169*2a5ee4e1SPeter Maydell         /*
170*2a5ee4e1SPeter Maydell          * These are user-settable DIP switches on the board. We don't
171dd73185bSPeter Maydell          * model that, so just return zeroes.
172*2a5ee4e1SPeter Maydell          *
173*2a5ee4e1SPeter Maydell          * TODO: for AN536 this is MCC_MSB_ADDR "additional MCC addressing
174*2a5ee4e1SPeter Maydell          * bits". These change which part of the DDR4 the motherboard
175*2a5ee4e1SPeter Maydell          * configuration controller can see in its memory map (see the
176*2a5ee4e1SPeter Maydell          * appnote section 2.4). QEMU doesn't model the MCC at all, so these
177*2a5ee4e1SPeter Maydell          * bits are not interesting to us; read-as-zero is as good as anything
178*2a5ee4e1SPeter Maydell          * else.
179dd73185bSPeter Maydell          */
180dd73185bSPeter Maydell         r = 0;
181dd73185bSPeter Maydell         break;
182dd73185bSPeter Maydell     case A_CFG4:
183dd73185bSPeter Maydell         r = s->cfg4;
184dd73185bSPeter Maydell         break;
1858e4b4c1cSPeter Maydell     case A_CFG5:
1865f3bbbdbSPeter Maydell         if (!have_cfg5(s)) {
1878e4b4c1cSPeter Maydell             goto bad_offset;
1888e4b4c1cSPeter Maydell         }
1898e4b4c1cSPeter Maydell         r = s->cfg5;
1908e4b4c1cSPeter Maydell         break;
1918e4b4c1cSPeter Maydell     case A_CFG6:
1925f3bbbdbSPeter Maydell         if (!have_cfg6(s)) {
1938e4b4c1cSPeter Maydell             goto bad_offset;
1948e4b4c1cSPeter Maydell         }
1958e4b4c1cSPeter Maydell         r = s->cfg6;
1968e4b4c1cSPeter Maydell         break;
197*2a5ee4e1SPeter Maydell     case A_CFG7:
198*2a5ee4e1SPeter Maydell         if (!have_cfg7(s)) {
199*2a5ee4e1SPeter Maydell             goto bad_offset;
200*2a5ee4e1SPeter Maydell         }
201*2a5ee4e1SPeter Maydell         r = s->cfg7;
202*2a5ee4e1SPeter Maydell         break;
203dd73185bSPeter Maydell     case A_CFGDATA_RTN:
204dd73185bSPeter Maydell         r = s->cfgdata_rtn;
205dd73185bSPeter Maydell         break;
206dd73185bSPeter Maydell     case A_CFGDATA_OUT:
207dd73185bSPeter Maydell         r = s->cfgdata_out;
208dd73185bSPeter Maydell         break;
209dd73185bSPeter Maydell     case A_CFGCTRL:
210dd73185bSPeter Maydell         r = s->cfgctrl;
211dd73185bSPeter Maydell         break;
212dd73185bSPeter Maydell     case A_CFGSTAT:
213dd73185bSPeter Maydell         r = s->cfgstat;
214dd73185bSPeter Maydell         break;
215dd73185bSPeter Maydell     case A_DLL:
216dd73185bSPeter Maydell         r = s->dll;
217dd73185bSPeter Maydell         break;
218dd73185bSPeter Maydell     case A_AID:
219dd73185bSPeter Maydell         r = s->aid;
220dd73185bSPeter Maydell         break;
221dd73185bSPeter Maydell     case A_ID:
222dd73185bSPeter Maydell         r = s->id;
223dd73185bSPeter Maydell         break;
224dd73185bSPeter Maydell     default:
2258e4b4c1cSPeter Maydell     bad_offset:
226dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
227dd73185bSPeter Maydell                       "MPS2 SCC read: bad offset %x\n", (int) offset);
228dd73185bSPeter Maydell         r = 0;
229dd73185bSPeter Maydell         break;
230dd73185bSPeter Maydell     }
231dd73185bSPeter Maydell 
232dd73185bSPeter Maydell     trace_mps2_scc_read(offset, r, size);
233dd73185bSPeter Maydell     return r;
234dd73185bSPeter Maydell }
235dd73185bSPeter Maydell 
mps2_scc_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)236dd73185bSPeter Maydell static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
237dd73185bSPeter Maydell                            unsigned size)
238dd73185bSPeter Maydell {
239dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(opaque);
240dd73185bSPeter Maydell 
241dd73185bSPeter Maydell     trace_mps2_scc_write(offset, value, size);
242dd73185bSPeter Maydell 
243dd73185bSPeter Maydell     switch (offset) {
244dd73185bSPeter Maydell     case A_CFG0:
2456ac80818SPeter Maydell         /*
2465bddf92eSPeter Maydell          * On some boards bit 0 controls board-specific remapping;
2475bddf92eSPeter Maydell          * we always reflect bit 0 in the 'remap' GPIO output line,
2485bddf92eSPeter Maydell          * and let the board wire it up or not as it chooses.
2495bddf92eSPeter Maydell          * TODO on some boards bit 1 is CPU_WAIT.
250*2a5ee4e1SPeter Maydell          *
251*2a5ee4e1SPeter Maydell          * TODO: on the AN536 this register controls reset and halt
252*2a5ee4e1SPeter Maydell          * for both CPUs. For the moment we don't implement this, so the
253*2a5ee4e1SPeter Maydell          * register just reads as written.
2546ac80818SPeter Maydell          */
255dd73185bSPeter Maydell         s->cfg0 = value;
256*2a5ee4e1SPeter Maydell         if (cfg0_is_remap(s)) {
2575bddf92eSPeter Maydell             qemu_set_irq(s->remap, s->cfg0 & 1);
258*2a5ee4e1SPeter Maydell         }
259dd73185bSPeter Maydell         break;
260dd73185bSPeter Maydell     case A_CFG1:
261dd73185bSPeter Maydell         s->cfg1 = value;
262*2a5ee4e1SPeter Maydell         /*
263*2a5ee4e1SPeter Maydell          * On most boards this register drives LEDs.
264*2a5ee4e1SPeter Maydell          *
265*2a5ee4e1SPeter Maydell          * TODO: for AN536 this controls whether flash and ATCM are
266*2a5ee4e1SPeter Maydell          * enabled or disabled on reset. QEMU doesn't model this, and
267*2a5ee4e1SPeter Maydell          * always wires up RAM in the ATCM area and ROM in the flash area.
268*2a5ee4e1SPeter Maydell          */
269*2a5ee4e1SPeter Maydell         if (cfg1_is_leds(s)) {
270435db7ebSPhilippe Mathieu-Daudé             for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) {
271435db7ebSPhilippe Mathieu-Daudé                 led_set_state(s->led[i], extract32(value, i, 1));
272435db7ebSPhilippe Mathieu-Daudé             }
273*2a5ee4e1SPeter Maydell         }
274dd73185bSPeter Maydell         break;
2758e4b4c1cSPeter Maydell     case A_CFG2:
2765f3bbbdbSPeter Maydell         if (!have_cfg2(s)) {
2778e4b4c1cSPeter Maydell             goto bad_offset;
2788e4b4c1cSPeter Maydell         }
279*2a5ee4e1SPeter Maydell         /* AN524, AN536: QSPI Select signal */
2808e4b4c1cSPeter Maydell         s->cfg2 = value;
2818e4b4c1cSPeter Maydell         break;
2828e4b4c1cSPeter Maydell     case A_CFG5:
2835f3bbbdbSPeter Maydell         if (!have_cfg5(s)) {
2848e4b4c1cSPeter Maydell             goto bad_offset;
2858e4b4c1cSPeter Maydell         }
286*2a5ee4e1SPeter Maydell         /* AN524, AN536: ACLK frequency in Hz */
2878e4b4c1cSPeter Maydell         s->cfg5 = value;
2888e4b4c1cSPeter Maydell         break;
2898e4b4c1cSPeter Maydell     case A_CFG6:
2905f3bbbdbSPeter Maydell         if (!have_cfg6(s)) {
2918e4b4c1cSPeter Maydell             goto bad_offset;
2928e4b4c1cSPeter Maydell         }
2938e4b4c1cSPeter Maydell         /* AN524: Clock divider for BRAM */
294*2a5ee4e1SPeter Maydell         /* AN536: Core 0 vector table base address */
295*2a5ee4e1SPeter Maydell         s->cfg6 = value;
296*2a5ee4e1SPeter Maydell         break;
297*2a5ee4e1SPeter Maydell     case A_CFG7:
298*2a5ee4e1SPeter Maydell         if (!have_cfg7(s)) {
299*2a5ee4e1SPeter Maydell             goto bad_offset;
300*2a5ee4e1SPeter Maydell         }
301*2a5ee4e1SPeter Maydell         /* AN536: Core 1 vector table base address */
3028e4b4c1cSPeter Maydell         s->cfg6 = value;
3038e4b4c1cSPeter Maydell         break;
304dd73185bSPeter Maydell     case A_CFGDATA_OUT:
305dd73185bSPeter Maydell         s->cfgdata_out = value;
306dd73185bSPeter Maydell         break;
307dd73185bSPeter Maydell     case A_CFGCTRL:
308dd73185bSPeter Maydell         /* Writing to CFGCTRL clears SYS_CFGSTAT */
309dd73185bSPeter Maydell         s->cfgstat = 0;
310dd73185bSPeter Maydell         s->cfgctrl = value & ~(R_CFGCTRL_RES1_MASK |
311dd73185bSPeter Maydell                                R_CFGCTRL_RES2_MASK |
312dd73185bSPeter Maydell                                R_CFGCTRL_START_MASK);
313dd73185bSPeter Maydell 
314dd73185bSPeter Maydell         if (value & R_CFGCTRL_START_MASK) {
315dd73185bSPeter Maydell             /* Start bit set -- do a read or write (instantaneously) */
316dd73185bSPeter Maydell             int device = extract32(s->cfgctrl, R_CFGCTRL_DEVICE_SHIFT,
317dd73185bSPeter Maydell                                    R_CFGCTRL_DEVICE_LENGTH);
318dd73185bSPeter Maydell             int function = extract32(s->cfgctrl, R_CFGCTRL_FUNCTION_SHIFT,
319dd73185bSPeter Maydell                                      R_CFGCTRL_FUNCTION_LENGTH);
320dd73185bSPeter Maydell 
321dd73185bSPeter Maydell             s->cfgstat = R_CFGSTAT_DONE_MASK;
322dd73185bSPeter Maydell             if (s->cfgctrl & R_CFGCTRL_WRITE_MASK) {
323dd73185bSPeter Maydell                 if (!scc_cfg_write(s, function, device, s->cfgdata_out)) {
324dd73185bSPeter Maydell                     s->cfgstat |= R_CFGSTAT_ERROR_MASK;
325dd73185bSPeter Maydell                 }
326dd73185bSPeter Maydell             } else {
327dd73185bSPeter Maydell                 uint32_t result;
328dd73185bSPeter Maydell                 if (!scc_cfg_read(s, function, device, &result)) {
329dd73185bSPeter Maydell                     s->cfgstat |= R_CFGSTAT_ERROR_MASK;
330dd73185bSPeter Maydell                 } else {
331dd73185bSPeter Maydell                     s->cfgdata_rtn = result;
332dd73185bSPeter Maydell                 }
333dd73185bSPeter Maydell             }
334dd73185bSPeter Maydell         }
335dd73185bSPeter Maydell         break;
336dd73185bSPeter Maydell     case A_DLL:
337dd73185bSPeter Maydell         /* DLL stands for Digital Locked Loop.
338dd73185bSPeter Maydell          * Bits [31:24] (DLL_LOCK_MASK) are writable, and indicate a
339dd73185bSPeter Maydell          * mask of which of the DLL_LOCKED bits [16:23] should be ORed
340dd73185bSPeter Maydell          * together to determine the ALL_UNMASKED_DLLS_LOCKED bit [0].
341dd73185bSPeter Maydell          * For QEMU, our DLLs are always locked, so we can leave bit 0
342dd73185bSPeter Maydell          * as 1 always and don't need to recalculate it.
343dd73185bSPeter Maydell          */
344dd73185bSPeter Maydell         s->dll = deposit32(s->dll, 24, 8, extract32(value, 24, 8));
345dd73185bSPeter Maydell         break;
346dd73185bSPeter Maydell     default:
3478e4b4c1cSPeter Maydell     bad_offset:
348dd73185bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
349dd73185bSPeter Maydell                       "MPS2 SCC write: bad offset 0x%x\n", (int) offset);
350dd73185bSPeter Maydell         break;
351dd73185bSPeter Maydell     }
352dd73185bSPeter Maydell }
353dd73185bSPeter Maydell 
354dd73185bSPeter Maydell static const MemoryRegionOps mps2_scc_ops = {
355dd73185bSPeter Maydell     .read = mps2_scc_read,
356dd73185bSPeter Maydell     .write = mps2_scc_write,
357dd73185bSPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
358dd73185bSPeter Maydell };
359dd73185bSPeter Maydell 
mps2_scc_reset(DeviceState * dev)360dd73185bSPeter Maydell static void mps2_scc_reset(DeviceState *dev)
361dd73185bSPeter Maydell {
362dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(dev);
363dd73185bSPeter Maydell     int i;
364dd73185bSPeter Maydell 
365dd73185bSPeter Maydell     trace_mps2_scc_reset();
3665bddf92eSPeter Maydell     s->cfg0 = s->cfg0_reset;
367dd73185bSPeter Maydell     s->cfg1 = 0;
3688e4b4c1cSPeter Maydell     s->cfg2 = 0;
3698e4b4c1cSPeter Maydell     s->cfg5 = 0;
3708e4b4c1cSPeter Maydell     s->cfg6 = 0;
371dd73185bSPeter Maydell     s->cfgdata_rtn = 0;
372dd73185bSPeter Maydell     s->cfgdata_out = 0;
373dd73185bSPeter Maydell     s->cfgctrl = 0x100000;
374dd73185bSPeter Maydell     s->cfgstat = 0;
375dd73185bSPeter Maydell     s->dll = 0xffff0001;
3764fb013afSPeter Maydell     for (i = 0; i < s->num_oscclk; i++) {
377dd73185bSPeter Maydell         s->oscclk[i] = s->oscclk_reset[i];
378dd73185bSPeter Maydell     }
379435db7ebSPhilippe Mathieu-Daudé     for (i = 0; i < ARRAY_SIZE(s->led); i++) {
380435db7ebSPhilippe Mathieu-Daudé         device_cold_reset(DEVICE(s->led[i]));
381435db7ebSPhilippe Mathieu-Daudé     }
382dd73185bSPeter Maydell }
383dd73185bSPeter Maydell 
mps2_scc_init(Object * obj)384dd73185bSPeter Maydell static void mps2_scc_init(Object *obj)
385dd73185bSPeter Maydell {
386dd73185bSPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
387dd73185bSPeter Maydell     MPS2SCC *s = MPS2_SCC(obj);
388dd73185bSPeter Maydell 
389dd73185bSPeter Maydell     memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000);
390dd73185bSPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
3915bddf92eSPeter Maydell     qdev_init_gpio_out_named(DEVICE(obj), &s->remap, "remap", 1);
392dd73185bSPeter Maydell }
393dd73185bSPeter Maydell 
mps2_scc_realize(DeviceState * dev,Error ** errp)394dd73185bSPeter Maydell static void mps2_scc_realize(DeviceState *dev, Error **errp)
395dd73185bSPeter Maydell {
396435db7ebSPhilippe Mathieu-Daudé     MPS2SCC *s = MPS2_SCC(dev);
397435db7ebSPhilippe Mathieu-Daudé 
398435db7ebSPhilippe Mathieu-Daudé     for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) {
399435db7ebSPhilippe Mathieu-Daudé         char *name = g_strdup_printf("SCC LED%zu", i);
400435db7ebSPhilippe Mathieu-Daudé         s->led[i] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
401435db7ebSPhilippe Mathieu-Daudé                                       LED_COLOR_GREEN, name);
402435db7ebSPhilippe Mathieu-Daudé         g_free(name);
403435db7ebSPhilippe Mathieu-Daudé     }
4044fb013afSPeter Maydell 
4054fb013afSPeter Maydell     s->oscclk = g_new0(uint32_t, s->num_oscclk);
406dd73185bSPeter Maydell }
407dd73185bSPeter Maydell 
mps2_scc_finalize(Object * obj)408896dd6ffSPhilippe Mathieu-Daudé static void mps2_scc_finalize(Object *obj)
409896dd6ffSPhilippe Mathieu-Daudé {
410896dd6ffSPhilippe Mathieu-Daudé     MPS2SCC *s = MPS2_SCC(obj);
411896dd6ffSPhilippe Mathieu-Daudé 
412896dd6ffSPhilippe Mathieu-Daudé     g_free(s->oscclk_reset);
413896dd6ffSPhilippe Mathieu-Daudé }
414896dd6ffSPhilippe Mathieu-Daudé 
cfg7_needed(void * opaque)415*2a5ee4e1SPeter Maydell static bool cfg7_needed(void *opaque)
416*2a5ee4e1SPeter Maydell {
417*2a5ee4e1SPeter Maydell     MPS2SCC *s = opaque;
418*2a5ee4e1SPeter Maydell 
419*2a5ee4e1SPeter Maydell     return have_cfg7(s);
420*2a5ee4e1SPeter Maydell }
421*2a5ee4e1SPeter Maydell 
422*2a5ee4e1SPeter Maydell static const VMStateDescription vmstate_cfg7 = {
423*2a5ee4e1SPeter Maydell     .name = "mps2-scc/cfg7",
424*2a5ee4e1SPeter Maydell     .version_id = 1,
425*2a5ee4e1SPeter Maydell     .minimum_version_id = 1,
426*2a5ee4e1SPeter Maydell     .needed = cfg7_needed,
427*2a5ee4e1SPeter Maydell     .fields = (const VMStateField[]) {
428*2a5ee4e1SPeter Maydell         VMSTATE_UINT32(cfg7, MPS2SCC),
429*2a5ee4e1SPeter Maydell         VMSTATE_END_OF_LIST()
430*2a5ee4e1SPeter Maydell     }
431*2a5ee4e1SPeter Maydell };
432*2a5ee4e1SPeter Maydell 
433dd73185bSPeter Maydell static const VMStateDescription mps2_scc_vmstate = {
434dd73185bSPeter Maydell     .name = "mps2-scc",
4358e4b4c1cSPeter Maydell     .version_id = 3,
4368e4b4c1cSPeter Maydell     .minimum_version_id = 3,
437e4ea952fSRichard Henderson     .fields = (const VMStateField[]) {
438dd73185bSPeter Maydell         VMSTATE_UINT32(cfg0, MPS2SCC),
439dd73185bSPeter Maydell         VMSTATE_UINT32(cfg1, MPS2SCC),
4408e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg2, MPS2SCC),
4418e4b4c1cSPeter Maydell         /* cfg3, cfg4 are read-only so need not be migrated */
4428e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg5, MPS2SCC),
4438e4b4c1cSPeter Maydell         VMSTATE_UINT32(cfg6, MPS2SCC),
444dd73185bSPeter Maydell         VMSTATE_UINT32(cfgdata_rtn, MPS2SCC),
445dd73185bSPeter Maydell         VMSTATE_UINT32(cfgdata_out, MPS2SCC),
446dd73185bSPeter Maydell         VMSTATE_UINT32(cfgctrl, MPS2SCC),
447dd73185bSPeter Maydell         VMSTATE_UINT32(cfgstat, MPS2SCC),
448dd73185bSPeter Maydell         VMSTATE_UINT32(dll, MPS2SCC),
4494fb013afSPeter Maydell         VMSTATE_VARRAY_UINT32(oscclk, MPS2SCC, num_oscclk,
4504fb013afSPeter Maydell                               0, vmstate_info_uint32, uint32_t),
451dd73185bSPeter Maydell         VMSTATE_END_OF_LIST()
452*2a5ee4e1SPeter Maydell     },
453*2a5ee4e1SPeter Maydell     .subsections = (const VMStateDescription * const []) {
454*2a5ee4e1SPeter Maydell         &vmstate_cfg7,
455*2a5ee4e1SPeter Maydell         NULL
456dd73185bSPeter Maydell     }
457dd73185bSPeter Maydell };
458dd73185bSPeter Maydell 
459dd73185bSPeter Maydell static Property mps2_scc_properties[] = {
460dd73185bSPeter Maydell     /* Values for various read-only ID registers (which are specific
461dd73185bSPeter Maydell      * to the board model or FPGA image)
462dd73185bSPeter Maydell      */
46389cbc377SPhilippe Mathieu-Daudé     DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0),
464dd73185bSPeter Maydell     DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0),
46589cbc377SPhilippe Mathieu-Daudé     DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0),
4665bddf92eSPeter Maydell     /* Reset value for CFG0 register */
4675bddf92eSPeter Maydell     DEFINE_PROP_UINT32("scc-cfg0", MPS2SCC, cfg0_reset, 0),
4684fb013afSPeter Maydell     /*
4694fb013afSPeter Maydell      * These are the initial settings for the source clocks on the board.
470dd73185bSPeter Maydell      * In hardware they can be configured via a config file read by the
471dd73185bSPeter Maydell      * motherboard configuration controller to suit the FPGA image.
472dd73185bSPeter Maydell      */
4734fb013afSPeter Maydell     DEFINE_PROP_ARRAY("oscclk", MPS2SCC, num_oscclk, oscclk_reset,
4744fb013afSPeter Maydell                       qdev_prop_uint32, uint32_t),
475dd73185bSPeter Maydell     DEFINE_PROP_END_OF_LIST(),
476dd73185bSPeter Maydell };
477dd73185bSPeter Maydell 
mps2_scc_class_init(ObjectClass * klass,void * data)478dd73185bSPeter Maydell static void mps2_scc_class_init(ObjectClass *klass, void *data)
479dd73185bSPeter Maydell {
480dd73185bSPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
481dd73185bSPeter Maydell 
482dd73185bSPeter Maydell     dc->realize = mps2_scc_realize;
483dd73185bSPeter Maydell     dc->vmsd = &mps2_scc_vmstate;
484dd73185bSPeter Maydell     dc->reset = mps2_scc_reset;
4854f67d30bSMarc-André Lureau     device_class_set_props(dc, mps2_scc_properties);
486dd73185bSPeter Maydell }
487dd73185bSPeter Maydell 
488dd73185bSPeter Maydell static const TypeInfo mps2_scc_info = {
489dd73185bSPeter Maydell     .name = TYPE_MPS2_SCC,
490dd73185bSPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
491dd73185bSPeter Maydell     .instance_size = sizeof(MPS2SCC),
492dd73185bSPeter Maydell     .instance_init = mps2_scc_init,
493896dd6ffSPhilippe Mathieu-Daudé     .instance_finalize = mps2_scc_finalize,
494dd73185bSPeter Maydell     .class_init = mps2_scc_class_init,
495dd73185bSPeter Maydell };
496dd73185bSPeter Maydell 
mps2_scc_register_types(void)497dd73185bSPeter Maydell static void mps2_scc_register_types(void)
498dd73185bSPeter Maydell {
499dd73185bSPeter Maydell     type_register_static(&mps2_scc_info);
500dd73185bSPeter Maydell }
501dd73185bSPeter Maydell 
502dd73185bSPeter Maydell type_init(mps2_scc_register_types);
503