xref: /qemu/hw/ppc/ppc4xx_devs.c (revision 2d54aaf121d7a94a57b05059b15e9cbe670734a2)
1008ff9d7Sj_mayer /*
2008ff9d7Sj_mayer  * QEMU PowerPC 4xx embedded processors shared devices emulation
3008ff9d7Sj_mayer  *
4008ff9d7Sj_mayer  * Copyright (c) 2007 Jocelyn Mayer
5008ff9d7Sj_mayer  *
6008ff9d7Sj_mayer  * Permission is hereby granted, free of charge, to any person obtaining a copy
7008ff9d7Sj_mayer  * of this software and associated documentation files (the "Software"), to deal
8008ff9d7Sj_mayer  * in the Software without restriction, including without limitation the rights
9008ff9d7Sj_mayer  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10008ff9d7Sj_mayer  * copies of the Software, and to permit persons to whom the Software is
11008ff9d7Sj_mayer  * furnished to do so, subject to the following conditions:
12008ff9d7Sj_mayer  *
13008ff9d7Sj_mayer  * The above copyright notice and this permission notice shall be included in
14008ff9d7Sj_mayer  * all copies or substantial portions of the Software.
15008ff9d7Sj_mayer  *
16008ff9d7Sj_mayer  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17008ff9d7Sj_mayer  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18008ff9d7Sj_mayer  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19008ff9d7Sj_mayer  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20008ff9d7Sj_mayer  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21008ff9d7Sj_mayer  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22008ff9d7Sj_mayer  * THE SOFTWARE.
23008ff9d7Sj_mayer  */
2471e8a915SMarkus Armbruster 
250d75590dSPeter Maydell #include "qemu/osdep.h"
26ab3dd749SPhilippe Mathieu-Daudé #include "qemu/units.h"
2771e8a915SMarkus Armbruster #include "sysemu/reset.h"
2833c11879SPaolo Bonzini #include "cpu.h"
2964552b6bSMarkus Armbruster #include "hw/irq.h"
300d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
310d09e41aSPaolo Bonzini #include "hw/ppc/ppc4xx.h"
3234d0831fSPeter Maydell #include "hw/intc/ppc-uic.h"
3334d0831fSPeter Maydell #include "hw/qdev-properties.h"
341de7afc9SPaolo Bonzini #include "qemu/log.h"
35022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
36ab3dd749SPhilippe Mathieu-Daudé #include "qemu/error-report.h"
3734d0831fSPeter Maydell #include "qapi/error.h"
38b3b5c5d3SCédric Le Goater #include "trace.h"
39d12d51d5Saliguori 
40008ff9d7Sj_mayer /*****************************************************************************/
4161b24405Saurel32 /* SDRAM controller */
42c227f099SAnthony Liguori typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
43c227f099SAnthony Liguori struct ppc4xx_sdram_t {
4461b24405Saurel32     uint32_t addr;
4561b24405Saurel32     int nbanks;
46b6dcbe08SAvi Kivity     MemoryRegion containers[4]; /* used for clipping */
47b6dcbe08SAvi Kivity     MemoryRegion *ram_memories;
48a8170e5eSAvi Kivity     hwaddr ram_bases[4];
49a8170e5eSAvi Kivity     hwaddr ram_sizes[4];
5061b24405Saurel32     uint32_t besr0;
5161b24405Saurel32     uint32_t besr1;
5261b24405Saurel32     uint32_t bear;
5361b24405Saurel32     uint32_t cfg;
5461b24405Saurel32     uint32_t status;
5561b24405Saurel32     uint32_t rtr;
5661b24405Saurel32     uint32_t pmit;
5761b24405Saurel32     uint32_t bcr[4];
5861b24405Saurel32     uint32_t tr;
5961b24405Saurel32     uint32_t ecccfg;
6061b24405Saurel32     uint32_t eccesr;
6161b24405Saurel32     qemu_irq irq;
6261b24405Saurel32 };
6361b24405Saurel32 
6461b24405Saurel32 enum {
6561b24405Saurel32     SDRAM0_CFGADDR = 0x010,
6661b24405Saurel32     SDRAM0_CFGDATA = 0x011,
6761b24405Saurel32 };
6861b24405Saurel32 
6961b24405Saurel32 /* XXX: TOFIX: some patches have made this code become inconsistent:
70a8170e5eSAvi Kivity  *      there are type inconsistencies, mixing hwaddr, target_ulong
7161b24405Saurel32  *      and uint32_t
7261b24405Saurel32  */
73a8170e5eSAvi Kivity static uint32_t sdram_bcr (hwaddr ram_base,
74a8170e5eSAvi Kivity                            hwaddr ram_size)
7561b24405Saurel32 {
7661b24405Saurel32     uint32_t bcr;
7761b24405Saurel32 
7861b24405Saurel32     switch (ram_size) {
79ab3dd749SPhilippe Mathieu-Daudé     case 4 * MiB:
8061b24405Saurel32         bcr = 0x00000000;
8161b24405Saurel32         break;
82ab3dd749SPhilippe Mathieu-Daudé     case 8 * MiB:
8361b24405Saurel32         bcr = 0x00020000;
8461b24405Saurel32         break;
85ab3dd749SPhilippe Mathieu-Daudé     case 16 * MiB:
8661b24405Saurel32         bcr = 0x00040000;
8761b24405Saurel32         break;
88ab3dd749SPhilippe Mathieu-Daudé     case 32 * MiB:
8961b24405Saurel32         bcr = 0x00060000;
9061b24405Saurel32         break;
91ab3dd749SPhilippe Mathieu-Daudé     case 64 * MiB:
9261b24405Saurel32         bcr = 0x00080000;
9361b24405Saurel32         break;
94ab3dd749SPhilippe Mathieu-Daudé     case 128 * MiB:
9561b24405Saurel32         bcr = 0x000A0000;
9661b24405Saurel32         break;
97ab3dd749SPhilippe Mathieu-Daudé     case 256 * MiB:
9861b24405Saurel32         bcr = 0x000C0000;
9961b24405Saurel32         break;
10061b24405Saurel32     default:
101b3b5c5d3SCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR,
102b3b5c5d3SCédric Le Goater                       "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__,
10390e189ecSBlue Swirl                       ram_size);
10461b24405Saurel32         return 0x00000000;
10561b24405Saurel32     }
10661b24405Saurel32     bcr |= ram_base & 0xFF800000;
10761b24405Saurel32     bcr |= 1;
10861b24405Saurel32 
10961b24405Saurel32     return bcr;
11061b24405Saurel32 }
11161b24405Saurel32 
112a8170e5eSAvi Kivity static inline hwaddr sdram_base(uint32_t bcr)
11361b24405Saurel32 {
11461b24405Saurel32     return bcr & 0xFF800000;
11561b24405Saurel32 }
11661b24405Saurel32 
11761b24405Saurel32 static target_ulong sdram_size (uint32_t bcr)
11861b24405Saurel32 {
11961b24405Saurel32     target_ulong size;
12061b24405Saurel32     int sh;
12161b24405Saurel32 
12261b24405Saurel32     sh = (bcr >> 17) & 0x7;
12361b24405Saurel32     if (sh == 7)
12461b24405Saurel32         size = -1;
12561b24405Saurel32     else
126ab3dd749SPhilippe Mathieu-Daudé         size = (4 * MiB) << sh;
12761b24405Saurel32 
12861b24405Saurel32     return size;
12961b24405Saurel32 }
13061b24405Saurel32 
13170812bf7SBALATON Zoltan static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i,
13270812bf7SBALATON Zoltan                           uint32_t bcr, int enabled)
13361b24405Saurel32 {
13470812bf7SBALATON Zoltan     if (sdram->bcr[i] & 0x00000001) {
13561b24405Saurel32         /* Unmap RAM */
136b3b5c5d3SCédric Le Goater         trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]),
137b3b5c5d3SCédric Le Goater                                  sdram_size(sdram->bcr[i]));
138b6dcbe08SAvi Kivity         memory_region_del_subregion(get_system_memory(),
13970812bf7SBALATON Zoltan                                     &sdram->containers[i]);
14070812bf7SBALATON Zoltan         memory_region_del_subregion(&sdram->containers[i],
14170812bf7SBALATON Zoltan                                     &sdram->ram_memories[i]);
14270812bf7SBALATON Zoltan         object_unparent(OBJECT(&sdram->containers[i]));
14361b24405Saurel32     }
14470812bf7SBALATON Zoltan     sdram->bcr[i] = bcr & 0xFFDEE001;
14561b24405Saurel32     if (enabled && (bcr & 0x00000001)) {
146b3b5c5d3SCédric Le Goater         trace_ppc4xx_sdram_unmap(sdram_base(bcr), sdram_size(bcr));
14770812bf7SBALATON Zoltan         memory_region_init(&sdram->containers[i], NULL, "sdram-containers",
148b6dcbe08SAvi Kivity                            sdram_size(bcr));
14970812bf7SBALATON Zoltan         memory_region_add_subregion(&sdram->containers[i], 0,
15070812bf7SBALATON Zoltan                                     &sdram->ram_memories[i]);
151b6dcbe08SAvi Kivity         memory_region_add_subregion(get_system_memory(),
152b6dcbe08SAvi Kivity                                     sdram_base(bcr),
15370812bf7SBALATON Zoltan                                     &sdram->containers[i]);
15461b24405Saurel32     }
15561b24405Saurel32 }
15661b24405Saurel32 
157c227f099SAnthony Liguori static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
15861b24405Saurel32 {
15961b24405Saurel32     int i;
16061b24405Saurel32 
16161b24405Saurel32     for (i = 0; i < sdram->nbanks; i++) {
16261b24405Saurel32         if (sdram->ram_sizes[i] != 0) {
16370812bf7SBALATON Zoltan             sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i],
16470812bf7SBALATON Zoltan                                               sdram->ram_sizes[i]), 1);
16561b24405Saurel32         } else {
16670812bf7SBALATON Zoltan             sdram_set_bcr(sdram, i, 0x00000000, 0);
16761b24405Saurel32         }
16861b24405Saurel32     }
16961b24405Saurel32 }
17061b24405Saurel32 
171c227f099SAnthony Liguori static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
17261b24405Saurel32 {
17361b24405Saurel32     int i;
17461b24405Saurel32 
17561b24405Saurel32     for (i = 0; i < sdram->nbanks; i++) {
176b3b5c5d3SCédric Le Goater         trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]),
177b3b5c5d3SCédric Le Goater                                  sdram_size(sdram->bcr[i]));
178b6dcbe08SAvi Kivity         memory_region_del_subregion(get_system_memory(),
179b6dcbe08SAvi Kivity                                     &sdram->ram_memories[i]);
18061b24405Saurel32     }
18161b24405Saurel32 }
18261b24405Saurel32 
18373b01960SAlexander Graf static uint32_t dcr_read_sdram (void *opaque, int dcrn)
18461b24405Saurel32 {
185c227f099SAnthony Liguori     ppc4xx_sdram_t *sdram;
18673b01960SAlexander Graf     uint32_t ret;
18761b24405Saurel32 
18861b24405Saurel32     sdram = opaque;
18961b24405Saurel32     switch (dcrn) {
19061b24405Saurel32     case SDRAM0_CFGADDR:
19161b24405Saurel32         ret = sdram->addr;
19261b24405Saurel32         break;
19361b24405Saurel32     case SDRAM0_CFGDATA:
19461b24405Saurel32         switch (sdram->addr) {
19561b24405Saurel32         case 0x00: /* SDRAM_BESR0 */
19661b24405Saurel32             ret = sdram->besr0;
19761b24405Saurel32             break;
19861b24405Saurel32         case 0x08: /* SDRAM_BESR1 */
19961b24405Saurel32             ret = sdram->besr1;
20061b24405Saurel32             break;
20161b24405Saurel32         case 0x10: /* SDRAM_BEAR */
20261b24405Saurel32             ret = sdram->bear;
20361b24405Saurel32             break;
20461b24405Saurel32         case 0x20: /* SDRAM_CFG */
20561b24405Saurel32             ret = sdram->cfg;
20661b24405Saurel32             break;
20761b24405Saurel32         case 0x24: /* SDRAM_STATUS */
20861b24405Saurel32             ret = sdram->status;
20961b24405Saurel32             break;
21061b24405Saurel32         case 0x30: /* SDRAM_RTR */
21161b24405Saurel32             ret = sdram->rtr;
21261b24405Saurel32             break;
21361b24405Saurel32         case 0x34: /* SDRAM_PMIT */
21461b24405Saurel32             ret = sdram->pmit;
21561b24405Saurel32             break;
21661b24405Saurel32         case 0x40: /* SDRAM_B0CR */
21761b24405Saurel32             ret = sdram->bcr[0];
21861b24405Saurel32             break;
21961b24405Saurel32         case 0x44: /* SDRAM_B1CR */
22061b24405Saurel32             ret = sdram->bcr[1];
22161b24405Saurel32             break;
22261b24405Saurel32         case 0x48: /* SDRAM_B2CR */
22361b24405Saurel32             ret = sdram->bcr[2];
22461b24405Saurel32             break;
22561b24405Saurel32         case 0x4C: /* SDRAM_B3CR */
22661b24405Saurel32             ret = sdram->bcr[3];
22761b24405Saurel32             break;
22861b24405Saurel32         case 0x80: /* SDRAM_TR */
22961b24405Saurel32             ret = -1; /* ? */
23061b24405Saurel32             break;
23161b24405Saurel32         case 0x94: /* SDRAM_ECCCFG */
23261b24405Saurel32             ret = sdram->ecccfg;
23361b24405Saurel32             break;
23461b24405Saurel32         case 0x98: /* SDRAM_ECCESR */
23561b24405Saurel32             ret = sdram->eccesr;
23661b24405Saurel32             break;
23761b24405Saurel32         default: /* Error */
23861b24405Saurel32             ret = -1;
23961b24405Saurel32             break;
24061b24405Saurel32         }
24161b24405Saurel32         break;
24261b24405Saurel32     default:
24361b24405Saurel32         /* Avoid gcc warning */
24461b24405Saurel32         ret = 0x00000000;
24561b24405Saurel32         break;
24661b24405Saurel32     }
24761b24405Saurel32 
24861b24405Saurel32     return ret;
24961b24405Saurel32 }
25061b24405Saurel32 
25173b01960SAlexander Graf static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
25261b24405Saurel32 {
253c227f099SAnthony Liguori     ppc4xx_sdram_t *sdram;
25461b24405Saurel32 
25561b24405Saurel32     sdram = opaque;
25661b24405Saurel32     switch (dcrn) {
25761b24405Saurel32     case SDRAM0_CFGADDR:
25861b24405Saurel32         sdram->addr = val;
25961b24405Saurel32         break;
26061b24405Saurel32     case SDRAM0_CFGDATA:
26161b24405Saurel32         switch (sdram->addr) {
26261b24405Saurel32         case 0x00: /* SDRAM_BESR0 */
26361b24405Saurel32             sdram->besr0 &= ~val;
26461b24405Saurel32             break;
26561b24405Saurel32         case 0x08: /* SDRAM_BESR1 */
26661b24405Saurel32             sdram->besr1 &= ~val;
26761b24405Saurel32             break;
26861b24405Saurel32         case 0x10: /* SDRAM_BEAR */
26961b24405Saurel32             sdram->bear = val;
27061b24405Saurel32             break;
27161b24405Saurel32         case 0x20: /* SDRAM_CFG */
27261b24405Saurel32             val &= 0xFFE00000;
27361b24405Saurel32             if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
274b3b5c5d3SCédric Le Goater                 trace_ppc4xx_sdram_enable("enable");
27561b24405Saurel32                 /* validate all RAM mappings */
27661b24405Saurel32                 sdram_map_bcr(sdram);
27761b24405Saurel32                 sdram->status &= ~0x80000000;
27861b24405Saurel32             } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
279b3b5c5d3SCédric Le Goater                 trace_ppc4xx_sdram_enable("disable");
28061b24405Saurel32                 /* invalidate all RAM mappings */
28161b24405Saurel32                 sdram_unmap_bcr(sdram);
28261b24405Saurel32                 sdram->status |= 0x80000000;
28361b24405Saurel32             }
28461b24405Saurel32             if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
28561b24405Saurel32                 sdram->status |= 0x40000000;
28661b24405Saurel32             else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
28761b24405Saurel32                 sdram->status &= ~0x40000000;
28861b24405Saurel32             sdram->cfg = val;
28961b24405Saurel32             break;
29061b24405Saurel32         case 0x24: /* SDRAM_STATUS */
29161b24405Saurel32             /* Read-only register */
29261b24405Saurel32             break;
29361b24405Saurel32         case 0x30: /* SDRAM_RTR */
29461b24405Saurel32             sdram->rtr = val & 0x3FF80000;
29561b24405Saurel32             break;
29661b24405Saurel32         case 0x34: /* SDRAM_PMIT */
29761b24405Saurel32             sdram->pmit = (val & 0xF8000000) | 0x07C00000;
29861b24405Saurel32             break;
29961b24405Saurel32         case 0x40: /* SDRAM_B0CR */
30070812bf7SBALATON Zoltan             sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000);
30161b24405Saurel32             break;
30261b24405Saurel32         case 0x44: /* SDRAM_B1CR */
30370812bf7SBALATON Zoltan             sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000);
30461b24405Saurel32             break;
30561b24405Saurel32         case 0x48: /* SDRAM_B2CR */
30670812bf7SBALATON Zoltan             sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000);
30761b24405Saurel32             break;
30861b24405Saurel32         case 0x4C: /* SDRAM_B3CR */
30970812bf7SBALATON Zoltan             sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000);
31061b24405Saurel32             break;
31161b24405Saurel32         case 0x80: /* SDRAM_TR */
31261b24405Saurel32             sdram->tr = val & 0x018FC01F;
31361b24405Saurel32             break;
31461b24405Saurel32         case 0x94: /* SDRAM_ECCCFG */
31561b24405Saurel32             sdram->ecccfg = val & 0x00F00000;
31661b24405Saurel32             break;
31761b24405Saurel32         case 0x98: /* SDRAM_ECCESR */
31861b24405Saurel32             val &= 0xFFF0F000;
31961b24405Saurel32             if (sdram->eccesr == 0 && val != 0)
32061b24405Saurel32                 qemu_irq_raise(sdram->irq);
32161b24405Saurel32             else if (sdram->eccesr != 0 && val == 0)
32261b24405Saurel32                 qemu_irq_lower(sdram->irq);
32361b24405Saurel32             sdram->eccesr = val;
32461b24405Saurel32             break;
32561b24405Saurel32         default: /* Error */
32661b24405Saurel32             break;
32761b24405Saurel32         }
32861b24405Saurel32         break;
32961b24405Saurel32     }
33061b24405Saurel32 }
33161b24405Saurel32 
33261b24405Saurel32 static void sdram_reset (void *opaque)
33361b24405Saurel32 {
334c227f099SAnthony Liguori     ppc4xx_sdram_t *sdram;
33561b24405Saurel32 
33661b24405Saurel32     sdram = opaque;
33761b24405Saurel32     sdram->addr = 0x00000000;
33861b24405Saurel32     sdram->bear = 0x00000000;
33961b24405Saurel32     sdram->besr0 = 0x00000000; /* No error */
34061b24405Saurel32     sdram->besr1 = 0x00000000; /* No error */
34161b24405Saurel32     sdram->cfg = 0x00000000;
34261b24405Saurel32     sdram->ecccfg = 0x00000000; /* No ECC */
34361b24405Saurel32     sdram->eccesr = 0x00000000; /* No error */
34461b24405Saurel32     sdram->pmit = 0x07C00000;
34561b24405Saurel32     sdram->rtr = 0x05F00000;
34661b24405Saurel32     sdram->tr = 0x00854009;
34761b24405Saurel32     /* We pre-initialize RAM banks */
34861b24405Saurel32     sdram->status = 0x00000000;
34961b24405Saurel32     sdram->cfg = 0x00800000;
35061b24405Saurel32 }
35161b24405Saurel32 
352e2684c0bSAndreas Färber void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
353b6dcbe08SAvi Kivity                         MemoryRegion *ram_memories,
354a8170e5eSAvi Kivity                         hwaddr *ram_bases,
355a8170e5eSAvi Kivity                         hwaddr *ram_sizes,
35661b24405Saurel32                         int do_init)
35761b24405Saurel32 {
358c227f099SAnthony Liguori     ppc4xx_sdram_t *sdram;
35961b24405Saurel32 
360b21e2380SMarkus Armbruster     sdram = g_new0(ppc4xx_sdram_t, 1);
36161b24405Saurel32     sdram->irq = irq;
36261b24405Saurel32     sdram->nbanks = nbanks;
363b6dcbe08SAvi Kivity     sdram->ram_memories = ram_memories;
364a8170e5eSAvi Kivity     memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr));
36561b24405Saurel32     memcpy(sdram->ram_bases, ram_bases,
366a8170e5eSAvi Kivity            nbanks * sizeof(hwaddr));
367a8170e5eSAvi Kivity     memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr));
36861b24405Saurel32     memcpy(sdram->ram_sizes, ram_sizes,
369a8170e5eSAvi Kivity            nbanks * sizeof(hwaddr));
370a08d4367SJan Kiszka     qemu_register_reset(&sdram_reset, sdram);
37161b24405Saurel32     ppc_dcr_register(env, SDRAM0_CFGADDR,
37261b24405Saurel32                      sdram, &dcr_read_sdram, &dcr_write_sdram);
37361b24405Saurel32     ppc_dcr_register(env, SDRAM0_CFGDATA,
37461b24405Saurel32                      sdram, &dcr_read_sdram, &dcr_write_sdram);
37561b24405Saurel32     if (do_init)
37661b24405Saurel32         sdram_map_bcr(sdram);
37761b24405Saurel32 }
378b7da58fdSaurel32 
379b28f0188SIgor Mammedov /*
380b28f0188SIgor Mammedov  * Split RAM between SDRAM banks.
381b7da58fdSaurel32  *
382a0258e4aSIgor Mammedov  * sdram_bank_sizes[] must be in descending order, that is sizes[i] > sizes[i+1]
383a0258e4aSIgor Mammedov  * and must be 0-terminated.
384b7da58fdSaurel32  *
385b7da58fdSaurel32  * The 4xx SDRAM controller supports a small number of banks, and each bank
386b7da58fdSaurel32  * must be one of a small set of sizes. The number of banks and the supported
387b28f0188SIgor Mammedov  * sizes varies by SoC.
388b28f0188SIgor Mammedov  */
389b28f0188SIgor Mammedov void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
390b6dcbe08SAvi Kivity                         MemoryRegion ram_memories[],
391a0258e4aSIgor Mammedov                         hwaddr ram_bases[], hwaddr ram_sizes[],
3927d8ccf58SBALATON Zoltan                         const ram_addr_t sdram_bank_sizes[])
393b7da58fdSaurel32 {
394b28f0188SIgor Mammedov     ram_addr_t size_left = memory_region_size(ram);
395b6dcbe08SAvi Kivity     ram_addr_t base = 0;
3967d8ccf58SBALATON Zoltan     ram_addr_t bank_size;
397b7da58fdSaurel32     int i;
398b7da58fdSaurel32     int j;
399b7da58fdSaurel32 
400b7da58fdSaurel32     for (i = 0; i < nr_banks; i++) {
401b7da58fdSaurel32         for (j = 0; sdram_bank_sizes[j] != 0; j++) {
402e206ad48SHu Tao             bank_size = sdram_bank_sizes[j];
4035c130f65Spbrook             if (bank_size <= size_left) {
404b28f0188SIgor Mammedov                 char name[32];
405b28f0188SIgor Mammedov 
406a0258e4aSIgor Mammedov                 ram_bases[i] = base;
407a0258e4aSIgor Mammedov                 ram_sizes[i] = bank_size;
408a0258e4aSIgor Mammedov                 base += bank_size;
4095c130f65Spbrook                 size_left -= bank_size;
410b28f0188SIgor Mammedov                 snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
411b28f0188SIgor Mammedov                 memory_region_init_alias(&ram_memories[i], NULL, name, ram,
412b28f0188SIgor Mammedov                                          ram_bases[i], ram_sizes[i]);
413a0258e4aSIgor Mammedov                 break;
414b7da58fdSaurel32             }
415b7da58fdSaurel32         }
4165c130f65Spbrook         if (!size_left) {
417b7da58fdSaurel32             /* No need to use the remaining banks. */
418b7da58fdSaurel32             break;
419b7da58fdSaurel32         }
420b7da58fdSaurel32     }
421b7da58fdSaurel32 
422e206ad48SHu Tao     if (size_left) {
423b28f0188SIgor Mammedov         ram_addr_t used_size = memory_region_size(ram) - size_left;
424a0258e4aSIgor Mammedov         GString *s = g_string_new(NULL);
425a0258e4aSIgor Mammedov 
426a0258e4aSIgor Mammedov         for (i = 0; sdram_bank_sizes[i]; i++) {
427a0258e4aSIgor Mammedov             g_string_append_printf(s, "%" PRIi64 "%s",
428a0258e4aSIgor Mammedov                                    sdram_bank_sizes[i] / MiB,
429a0258e4aSIgor Mammedov                                    sdram_bank_sizes[i + 1] ? ", " : "");
430a0258e4aSIgor Mammedov         }
4310f1eddf5SMarkus Armbruster         error_report("at most %d bank%s of %s MiB each supported",
4320f1eddf5SMarkus Armbruster                      nr_banks, nr_banks == 1 ? "" : "s", s->str);
4330f1eddf5SMarkus Armbruster         error_printf("Possible valid RAM size: %" PRIi64 " MiB \n",
434a0258e4aSIgor Mammedov             used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB);
435a0258e4aSIgor Mammedov 
436a0258e4aSIgor Mammedov         g_string_free(s, true);
437a0258e4aSIgor Mammedov         exit(EXIT_FAILURE);
438e206ad48SHu Tao     }
439e206ad48SHu Tao }
440517284a7SBALATON Zoltan 
441517284a7SBALATON Zoltan /*****************************************************************************/
442517284a7SBALATON Zoltan /* MAL */
44304534280SBALATON Zoltan 
444517284a7SBALATON Zoltan enum {
445517284a7SBALATON Zoltan     MAL0_CFG      = 0x180,
446517284a7SBALATON Zoltan     MAL0_ESR      = 0x181,
447517284a7SBALATON Zoltan     MAL0_IER      = 0x182,
448517284a7SBALATON Zoltan     MAL0_TXCASR   = 0x184,
449517284a7SBALATON Zoltan     MAL0_TXCARR   = 0x185,
450517284a7SBALATON Zoltan     MAL0_TXEOBISR = 0x186,
451517284a7SBALATON Zoltan     MAL0_TXDEIR   = 0x187,
452517284a7SBALATON Zoltan     MAL0_RXCASR   = 0x190,
453517284a7SBALATON Zoltan     MAL0_RXCARR   = 0x191,
454517284a7SBALATON Zoltan     MAL0_RXEOBISR = 0x192,
455517284a7SBALATON Zoltan     MAL0_RXDEIR   = 0x193,
456517284a7SBALATON Zoltan     MAL0_TXCTP0R  = 0x1A0,
457517284a7SBALATON Zoltan     MAL0_RXCTP0R  = 0x1C0,
458517284a7SBALATON Zoltan     MAL0_RCBS0    = 0x1E0,
459517284a7SBALATON Zoltan     MAL0_RCBS1    = 0x1E1,
460517284a7SBALATON Zoltan };
461517284a7SBALATON Zoltan 
462da116a8aSCédric Le Goater static void ppc4xx_mal_reset(DeviceState *dev)
46304534280SBALATON Zoltan {
464da116a8aSCédric Le Goater     Ppc4xxMalState *mal = PPC4xx_MAL(dev);
46504534280SBALATON Zoltan 
46604534280SBALATON Zoltan     mal->cfg = 0x0007C000;
46704534280SBALATON Zoltan     mal->esr = 0x00000000;
46804534280SBALATON Zoltan     mal->ier = 0x00000000;
46904534280SBALATON Zoltan     mal->rxcasr = 0x00000000;
47004534280SBALATON Zoltan     mal->rxdeir = 0x00000000;
47104534280SBALATON Zoltan     mal->rxeobisr = 0x00000000;
47204534280SBALATON Zoltan     mal->txcasr = 0x00000000;
47304534280SBALATON Zoltan     mal->txdeir = 0x00000000;
47404534280SBALATON Zoltan     mal->txeobisr = 0x00000000;
47504534280SBALATON Zoltan }
476517284a7SBALATON Zoltan 
477517284a7SBALATON Zoltan static uint32_t dcr_read_mal(void *opaque, int dcrn)
478517284a7SBALATON Zoltan {
479da116a8aSCédric Le Goater     Ppc4xxMalState *mal = opaque;
480517284a7SBALATON Zoltan     uint32_t ret;
481517284a7SBALATON Zoltan 
482517284a7SBALATON Zoltan     switch (dcrn) {
483517284a7SBALATON Zoltan     case MAL0_CFG:
484517284a7SBALATON Zoltan         ret = mal->cfg;
485517284a7SBALATON Zoltan         break;
486517284a7SBALATON Zoltan     case MAL0_ESR:
487517284a7SBALATON Zoltan         ret = mal->esr;
488517284a7SBALATON Zoltan         break;
489517284a7SBALATON Zoltan     case MAL0_IER:
490517284a7SBALATON Zoltan         ret = mal->ier;
491517284a7SBALATON Zoltan         break;
492517284a7SBALATON Zoltan     case MAL0_TXCASR:
493517284a7SBALATON Zoltan         ret = mal->txcasr;
494517284a7SBALATON Zoltan         break;
495517284a7SBALATON Zoltan     case MAL0_TXCARR:
496517284a7SBALATON Zoltan         ret = mal->txcarr;
497517284a7SBALATON Zoltan         break;
498517284a7SBALATON Zoltan     case MAL0_TXEOBISR:
499517284a7SBALATON Zoltan         ret = mal->txeobisr;
500517284a7SBALATON Zoltan         break;
501517284a7SBALATON Zoltan     case MAL0_TXDEIR:
502517284a7SBALATON Zoltan         ret = mal->txdeir;
503517284a7SBALATON Zoltan         break;
504517284a7SBALATON Zoltan     case MAL0_RXCASR:
505517284a7SBALATON Zoltan         ret = mal->rxcasr;
506517284a7SBALATON Zoltan         break;
507517284a7SBALATON Zoltan     case MAL0_RXCARR:
508517284a7SBALATON Zoltan         ret = mal->rxcarr;
509517284a7SBALATON Zoltan         break;
510517284a7SBALATON Zoltan     case MAL0_RXEOBISR:
511517284a7SBALATON Zoltan         ret = mal->rxeobisr;
512517284a7SBALATON Zoltan         break;
513517284a7SBALATON Zoltan     case MAL0_RXDEIR:
514517284a7SBALATON Zoltan         ret = mal->rxdeir;
515517284a7SBALATON Zoltan         break;
516517284a7SBALATON Zoltan     default:
517517284a7SBALATON Zoltan         ret = 0;
518517284a7SBALATON Zoltan         break;
519517284a7SBALATON Zoltan     }
52004534280SBALATON Zoltan     if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) {
52104534280SBALATON Zoltan         ret = mal->txctpr[dcrn - MAL0_TXCTP0R];
52204534280SBALATON Zoltan     }
52304534280SBALATON Zoltan     if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) {
52404534280SBALATON Zoltan         ret = mal->rxctpr[dcrn - MAL0_RXCTP0R];
52504534280SBALATON Zoltan     }
52604534280SBALATON Zoltan     if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) {
52704534280SBALATON Zoltan         ret = mal->rcbs[dcrn - MAL0_RCBS0];
52804534280SBALATON Zoltan     }
529517284a7SBALATON Zoltan 
530517284a7SBALATON Zoltan     return ret;
531517284a7SBALATON Zoltan }
532517284a7SBALATON Zoltan 
533517284a7SBALATON Zoltan static void dcr_write_mal(void *opaque, int dcrn, uint32_t val)
534517284a7SBALATON Zoltan {
535da116a8aSCédric Le Goater     Ppc4xxMalState *mal = opaque;
536517284a7SBALATON Zoltan 
537517284a7SBALATON Zoltan     switch (dcrn) {
538517284a7SBALATON Zoltan     case MAL0_CFG:
539517284a7SBALATON Zoltan         if (val & 0x80000000) {
540da116a8aSCédric Le Goater             ppc4xx_mal_reset(DEVICE(mal));
541517284a7SBALATON Zoltan         }
542517284a7SBALATON Zoltan         mal->cfg = val & 0x00FFC087;
543517284a7SBALATON Zoltan         break;
544517284a7SBALATON Zoltan     case MAL0_ESR:
545517284a7SBALATON Zoltan         /* Read/clear */
546517284a7SBALATON Zoltan         mal->esr &= ~val;
547517284a7SBALATON Zoltan         break;
548517284a7SBALATON Zoltan     case MAL0_IER:
549517284a7SBALATON Zoltan         mal->ier = val & 0x0000001F;
550517284a7SBALATON Zoltan         break;
551517284a7SBALATON Zoltan     case MAL0_TXCASR:
552517284a7SBALATON Zoltan         mal->txcasr = val & 0xF0000000;
553517284a7SBALATON Zoltan         break;
554517284a7SBALATON Zoltan     case MAL0_TXCARR:
555517284a7SBALATON Zoltan         mal->txcarr = val & 0xF0000000;
556517284a7SBALATON Zoltan         break;
557517284a7SBALATON Zoltan     case MAL0_TXEOBISR:
558517284a7SBALATON Zoltan         /* Read/clear */
559517284a7SBALATON Zoltan         mal->txeobisr &= ~val;
560517284a7SBALATON Zoltan         break;
561517284a7SBALATON Zoltan     case MAL0_TXDEIR:
562517284a7SBALATON Zoltan         /* Read/clear */
563517284a7SBALATON Zoltan         mal->txdeir &= ~val;
564517284a7SBALATON Zoltan         break;
565517284a7SBALATON Zoltan     case MAL0_RXCASR:
566517284a7SBALATON Zoltan         mal->rxcasr = val & 0xC0000000;
567517284a7SBALATON Zoltan         break;
568517284a7SBALATON Zoltan     case MAL0_RXCARR:
569517284a7SBALATON Zoltan         mal->rxcarr = val & 0xC0000000;
570517284a7SBALATON Zoltan         break;
571517284a7SBALATON Zoltan     case MAL0_RXEOBISR:
572517284a7SBALATON Zoltan         /* Read/clear */
573517284a7SBALATON Zoltan         mal->rxeobisr &= ~val;
574517284a7SBALATON Zoltan         break;
575517284a7SBALATON Zoltan     case MAL0_RXDEIR:
576517284a7SBALATON Zoltan         /* Read/clear */
577517284a7SBALATON Zoltan         mal->rxdeir &= ~val;
578517284a7SBALATON Zoltan         break;
57904534280SBALATON Zoltan     }
58004534280SBALATON Zoltan     if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) {
58104534280SBALATON Zoltan         mal->txctpr[dcrn - MAL0_TXCTP0R] = val;
58204534280SBALATON Zoltan     }
58304534280SBALATON Zoltan     if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) {
58404534280SBALATON Zoltan         mal->rxctpr[dcrn - MAL0_RXCTP0R] = val;
58504534280SBALATON Zoltan     }
58604534280SBALATON Zoltan     if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) {
58704534280SBALATON Zoltan         mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF;
588517284a7SBALATON Zoltan     }
589517284a7SBALATON Zoltan }
590517284a7SBALATON Zoltan 
591da116a8aSCédric Le Goater static void ppc4xx_mal_realize(DeviceState *dev, Error **errp)
592517284a7SBALATON Zoltan {
593da116a8aSCédric Le Goater     Ppc4xxMalState *mal = PPC4xx_MAL(dev);
594da116a8aSCédric Le Goater     Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
595517284a7SBALATON Zoltan     int i;
596517284a7SBALATON Zoltan 
597da116a8aSCédric Le Goater     if (mal->txcnum > 32 || mal->rxcnum > 32) {
598da116a8aSCédric Le Goater         error_setg(errp, "invalid TXC/RXC number");
599da116a8aSCédric Le Goater         return;
600517284a7SBALATON Zoltan     }
601da116a8aSCédric Le Goater 
602da116a8aSCédric Le Goater     mal->txctpr = g_new0(uint32_t, mal->txcnum);
603da116a8aSCédric Le Goater     mal->rxctpr = g_new0(uint32_t, mal->rxcnum);
604da116a8aSCédric Le Goater     mal->rcbs = g_new0(uint32_t, mal->rxcnum);
605da116a8aSCédric Le Goater 
606da116a8aSCédric Le Goater     for (i = 0; i < ARRAY_SIZE(mal->irqs); i++) {
607da116a8aSCédric Le Goater         sysbus_init_irq(SYS_BUS_DEVICE(dev), &mal->irqs[i]);
608da116a8aSCédric Le Goater     }
609da116a8aSCédric Le Goater 
610da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_CFG, mal, &dcr_read_mal, &dcr_write_mal);
611da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_ESR, mal, &dcr_read_mal, &dcr_write_mal);
612da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_IER, mal, &dcr_read_mal, &dcr_write_mal);
613da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_TXCASR, mal, &dcr_read_mal, &dcr_write_mal);
614da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_TXCARR, mal, &dcr_read_mal, &dcr_write_mal);
615da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_TXEOBISR, mal, &dcr_read_mal, &dcr_write_mal);
616da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_TXDEIR, mal, &dcr_read_mal, &dcr_write_mal);
617da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_RXCASR, mal, &dcr_read_mal, &dcr_write_mal);
618da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_RXCARR, mal, &dcr_read_mal, &dcr_write_mal);
619da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_RXEOBISR, mal, &dcr_read_mal, &dcr_write_mal);
620da116a8aSCédric Le Goater     ppc4xx_dcr_register(dcr, MAL0_RXDEIR, mal, &dcr_read_mal, &dcr_write_mal);
621da116a8aSCédric Le Goater     for (i = 0; i < mal->txcnum; i++) {
622da116a8aSCédric Le Goater         ppc4xx_dcr_register(dcr, MAL0_TXCTP0R + i,
623517284a7SBALATON Zoltan                             mal, &dcr_read_mal, &dcr_write_mal);
62404534280SBALATON Zoltan     }
625da116a8aSCédric Le Goater     for (i = 0; i < mal->rxcnum; i++) {
626da116a8aSCédric Le Goater         ppc4xx_dcr_register(dcr, MAL0_RXCTP0R + i,
627517284a7SBALATON Zoltan                             mal, &dcr_read_mal, &dcr_write_mal);
62804534280SBALATON Zoltan     }
629da116a8aSCédric Le Goater     for (i = 0; i < mal->rxcnum; i++) {
630da116a8aSCédric Le Goater         ppc4xx_dcr_register(dcr, MAL0_RCBS0 + i,
631517284a7SBALATON Zoltan                             mal, &dcr_read_mal, &dcr_write_mal);
63204534280SBALATON Zoltan     }
633517284a7SBALATON Zoltan }
634629cae61SCédric Le Goater 
635da116a8aSCédric Le Goater static void ppc4xx_mal_finalize(Object *obj)
636da116a8aSCédric Le Goater {
637da116a8aSCédric Le Goater     Ppc4xxMalState *mal = PPC4xx_MAL(obj);
638da116a8aSCédric Le Goater 
639da116a8aSCédric Le Goater     g_free(mal->rcbs);
640da116a8aSCédric Le Goater     g_free(mal->rxctpr);
641da116a8aSCédric Le Goater     g_free(mal->txctpr);
642da116a8aSCédric Le Goater }
643da116a8aSCédric Le Goater 
644da116a8aSCédric Le Goater static Property ppc4xx_mal_properties[] = {
645da116a8aSCédric Le Goater     DEFINE_PROP_UINT8("txc-num", Ppc4xxMalState, txcnum, 0),
646da116a8aSCédric Le Goater     DEFINE_PROP_UINT8("rxc-num", Ppc4xxMalState, rxcnum, 0),
647da116a8aSCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
648da116a8aSCédric Le Goater };
649da116a8aSCédric Le Goater 
650da116a8aSCédric Le Goater static void ppc4xx_mal_class_init(ObjectClass *oc, void *data)
651da116a8aSCédric Le Goater {
652da116a8aSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
653da116a8aSCédric Le Goater 
654da116a8aSCédric Le Goater     dc->realize = ppc4xx_mal_realize;
655da116a8aSCédric Le Goater     dc->reset = ppc4xx_mal_reset;
656da116a8aSCédric Le Goater     /* Reason: only works as function of a ppc4xx SoC */
657da116a8aSCédric Le Goater     dc->user_creatable = false;
658da116a8aSCédric Le Goater     device_class_set_props(dc, ppc4xx_mal_properties);
659da116a8aSCédric Le Goater }
660da116a8aSCédric Le Goater 
661*2d54aaf1SBALATON Zoltan /*****************************************************************************/
662*2d54aaf1SBALATON Zoltan /* Peripheral local bus arbitrer */
663*2d54aaf1SBALATON Zoltan enum {
664*2d54aaf1SBALATON Zoltan     PLB3A0_ACR = 0x077,
665*2d54aaf1SBALATON Zoltan     PLB4A0_ACR = 0x081,
666*2d54aaf1SBALATON Zoltan     PLB0_BESR  = 0x084,
667*2d54aaf1SBALATON Zoltan     PLB0_BEAR  = 0x086,
668*2d54aaf1SBALATON Zoltan     PLB0_ACR   = 0x087,
669*2d54aaf1SBALATON Zoltan     PLB4A1_ACR = 0x089,
670*2d54aaf1SBALATON Zoltan };
671*2d54aaf1SBALATON Zoltan 
672*2d54aaf1SBALATON Zoltan static uint32_t dcr_read_plb(void *opaque, int dcrn)
673*2d54aaf1SBALATON Zoltan {
674*2d54aaf1SBALATON Zoltan     Ppc405PlbState *plb = opaque;
675*2d54aaf1SBALATON Zoltan     uint32_t ret;
676*2d54aaf1SBALATON Zoltan 
677*2d54aaf1SBALATON Zoltan     switch (dcrn) {
678*2d54aaf1SBALATON Zoltan     case PLB0_ACR:
679*2d54aaf1SBALATON Zoltan         ret = plb->acr;
680*2d54aaf1SBALATON Zoltan         break;
681*2d54aaf1SBALATON Zoltan     case PLB0_BEAR:
682*2d54aaf1SBALATON Zoltan         ret = plb->bear;
683*2d54aaf1SBALATON Zoltan         break;
684*2d54aaf1SBALATON Zoltan     case PLB0_BESR:
685*2d54aaf1SBALATON Zoltan         ret = plb->besr;
686*2d54aaf1SBALATON Zoltan         break;
687*2d54aaf1SBALATON Zoltan     default:
688*2d54aaf1SBALATON Zoltan         /* Avoid gcc warning */
689*2d54aaf1SBALATON Zoltan         ret = 0;
690*2d54aaf1SBALATON Zoltan         break;
691*2d54aaf1SBALATON Zoltan     }
692*2d54aaf1SBALATON Zoltan 
693*2d54aaf1SBALATON Zoltan     return ret;
694*2d54aaf1SBALATON Zoltan }
695*2d54aaf1SBALATON Zoltan 
696*2d54aaf1SBALATON Zoltan static void dcr_write_plb(void *opaque, int dcrn, uint32_t val)
697*2d54aaf1SBALATON Zoltan {
698*2d54aaf1SBALATON Zoltan     Ppc405PlbState *plb = opaque;
699*2d54aaf1SBALATON Zoltan 
700*2d54aaf1SBALATON Zoltan     switch (dcrn) {
701*2d54aaf1SBALATON Zoltan     case PLB0_ACR:
702*2d54aaf1SBALATON Zoltan         /*
703*2d54aaf1SBALATON Zoltan          * We don't care about the actual parameters written as
704*2d54aaf1SBALATON Zoltan          * we don't manage any priorities on the bus
705*2d54aaf1SBALATON Zoltan          */
706*2d54aaf1SBALATON Zoltan         plb->acr = val & 0xF8000000;
707*2d54aaf1SBALATON Zoltan         break;
708*2d54aaf1SBALATON Zoltan     case PLB0_BEAR:
709*2d54aaf1SBALATON Zoltan         /* Read only */
710*2d54aaf1SBALATON Zoltan         break;
711*2d54aaf1SBALATON Zoltan     case PLB0_BESR:
712*2d54aaf1SBALATON Zoltan         /* Write-clear */
713*2d54aaf1SBALATON Zoltan         plb->besr &= ~val;
714*2d54aaf1SBALATON Zoltan         break;
715*2d54aaf1SBALATON Zoltan     }
716*2d54aaf1SBALATON Zoltan }
717*2d54aaf1SBALATON Zoltan 
718*2d54aaf1SBALATON Zoltan static void ppc405_plb_reset(DeviceState *dev)
719*2d54aaf1SBALATON Zoltan {
720*2d54aaf1SBALATON Zoltan     Ppc405PlbState *plb = PPC405_PLB(dev);
721*2d54aaf1SBALATON Zoltan 
722*2d54aaf1SBALATON Zoltan     plb->acr = 0x00000000;
723*2d54aaf1SBALATON Zoltan     plb->bear = 0x00000000;
724*2d54aaf1SBALATON Zoltan     plb->besr = 0x00000000;
725*2d54aaf1SBALATON Zoltan }
726*2d54aaf1SBALATON Zoltan 
727*2d54aaf1SBALATON Zoltan static void ppc405_plb_realize(DeviceState *dev, Error **errp)
728*2d54aaf1SBALATON Zoltan {
729*2d54aaf1SBALATON Zoltan     Ppc405PlbState *plb = PPC405_PLB(dev);
730*2d54aaf1SBALATON Zoltan     Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
731*2d54aaf1SBALATON Zoltan 
732*2d54aaf1SBALATON Zoltan     ppc4xx_dcr_register(dcr, PLB3A0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
733*2d54aaf1SBALATON Zoltan     ppc4xx_dcr_register(dcr, PLB4A0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
734*2d54aaf1SBALATON Zoltan     ppc4xx_dcr_register(dcr, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
735*2d54aaf1SBALATON Zoltan     ppc4xx_dcr_register(dcr, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
736*2d54aaf1SBALATON Zoltan     ppc4xx_dcr_register(dcr, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
737*2d54aaf1SBALATON Zoltan     ppc4xx_dcr_register(dcr, PLB4A1_ACR, plb, &dcr_read_plb, &dcr_write_plb);
738*2d54aaf1SBALATON Zoltan }
739*2d54aaf1SBALATON Zoltan 
740*2d54aaf1SBALATON Zoltan static void ppc405_plb_class_init(ObjectClass *oc, void *data)
741*2d54aaf1SBALATON Zoltan {
742*2d54aaf1SBALATON Zoltan     DeviceClass *dc = DEVICE_CLASS(oc);
743*2d54aaf1SBALATON Zoltan 
744*2d54aaf1SBALATON Zoltan     dc->realize = ppc405_plb_realize;
745*2d54aaf1SBALATON Zoltan     dc->reset = ppc405_plb_reset;
746*2d54aaf1SBALATON Zoltan     /* Reason: only works as function of a ppc4xx SoC */
747*2d54aaf1SBALATON Zoltan     dc->user_creatable = false;
748*2d54aaf1SBALATON Zoltan }
749*2d54aaf1SBALATON Zoltan 
750629cae61SCédric Le Goater /* PPC4xx_DCR_DEVICE */
751629cae61SCédric Le Goater 
752629cae61SCédric Le Goater void ppc4xx_dcr_register(Ppc4xxDcrDeviceState *dev, int dcrn, void *opaque,
753629cae61SCédric Le Goater                          dcr_read_cb dcr_read, dcr_write_cb dcr_write)
754629cae61SCédric Le Goater {
755629cae61SCédric Le Goater     assert(dev->cpu);
756629cae61SCédric Le Goater     ppc_dcr_register(&dev->cpu->env, dcrn, opaque, dcr_read, dcr_write);
757629cae61SCédric Le Goater }
758629cae61SCédric Le Goater 
759629cae61SCédric Le Goater bool ppc4xx_dcr_realize(Ppc4xxDcrDeviceState *dev, PowerPCCPU *cpu,
760629cae61SCédric Le Goater                         Error **errp)
761629cae61SCédric Le Goater {
762629cae61SCédric Le Goater     object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_abort);
763629cae61SCédric Le Goater     return sysbus_realize(SYS_BUS_DEVICE(dev), errp);
764629cae61SCédric Le Goater }
765629cae61SCédric Le Goater 
766629cae61SCédric Le Goater static Property ppc4xx_dcr_properties[] = {
767629cae61SCédric Le Goater     DEFINE_PROP_LINK("cpu", Ppc4xxDcrDeviceState, cpu, TYPE_POWERPC_CPU,
768629cae61SCédric Le Goater                      PowerPCCPU *),
769629cae61SCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
770629cae61SCédric Le Goater };
771629cae61SCédric Le Goater 
772629cae61SCédric Le Goater static void ppc4xx_dcr_class_init(ObjectClass *oc, void *data)
773629cae61SCédric Le Goater {
774629cae61SCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
775629cae61SCédric Le Goater 
776629cae61SCédric Le Goater     device_class_set_props(dc, ppc4xx_dcr_properties);
777629cae61SCédric Le Goater }
778629cae61SCédric Le Goater 
779629cae61SCédric Le Goater static const TypeInfo ppc4xx_types[] = {
780629cae61SCédric Le Goater     {
781da116a8aSCédric Le Goater         .name           = TYPE_PPC4xx_MAL,
782da116a8aSCédric Le Goater         .parent         = TYPE_PPC4xx_DCR_DEVICE,
783da116a8aSCédric Le Goater         .instance_size  = sizeof(Ppc4xxMalState),
784da116a8aSCédric Le Goater         .instance_finalize = ppc4xx_mal_finalize,
785da116a8aSCédric Le Goater         .class_init     = ppc4xx_mal_class_init,
786da116a8aSCédric Le Goater     }, {
787*2d54aaf1SBALATON Zoltan         .name           = TYPE_PPC405_PLB,
788*2d54aaf1SBALATON Zoltan         .parent         = TYPE_PPC4xx_DCR_DEVICE,
789*2d54aaf1SBALATON Zoltan         .instance_size  = sizeof(Ppc405PlbState),
790*2d54aaf1SBALATON Zoltan         .class_init     = ppc405_plb_class_init,
791*2d54aaf1SBALATON Zoltan     }, {
792629cae61SCédric Le Goater         .name           = TYPE_PPC4xx_DCR_DEVICE,
793629cae61SCédric Le Goater         .parent         = TYPE_SYS_BUS_DEVICE,
794629cae61SCédric Le Goater         .instance_size  = sizeof(Ppc4xxDcrDeviceState),
795629cae61SCédric Le Goater         .class_init     = ppc4xx_dcr_class_init,
796629cae61SCédric Le Goater         .abstract       = true,
797629cae61SCédric Le Goater     }
798629cae61SCédric Le Goater };
799629cae61SCédric Le Goater 
800629cae61SCédric Le Goater DEFINE_TYPES(ppc4xx_types)
801