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 */ 240d75590dSPeter Maydell #include "qemu/osdep.h" 25ab3dd749SPhilippe Mathieu-Daudé #include "qemu/units.h" 2633c11879SPaolo Bonzini #include "cpu.h" 2783c9f4caSPaolo Bonzini #include "hw/hw.h" 280d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 290d09e41aSPaolo Bonzini #include "hw/ppc/ppc4xx.h" 30e938ba0cSShreyas B. Prabhu #include "hw/boards.h" 311de7afc9SPaolo Bonzini #include "qemu/log.h" 32022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 33ab3dd749SPhilippe Mathieu-Daudé #include "qemu/error-report.h" 34008ff9d7Sj_mayer 35a0557225SBALATON Zoltan /*#define DEBUG_UIC*/ 36d12d51d5Saliguori 37d12d51d5Saliguori #ifdef DEBUG_UIC 3893fcfe39Saliguori # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) 39d12d51d5Saliguori #else 40d12d51d5Saliguori # define LOG_UIC(...) do { } while (0) 41d12d51d5Saliguori #endif 42d12d51d5Saliguori 431bba0dc9SAndreas Färber static void ppc4xx_reset(void *opaque) 441bba0dc9SAndreas Färber { 4590cb09d9SAndreas Färber PowerPCCPU *cpu = opaque; 461bba0dc9SAndreas Färber 4790cb09d9SAndreas Färber cpu_reset(CPU(cpu)); 481bba0dc9SAndreas Färber } 491bba0dc9SAndreas Färber 50008ff9d7Sj_mayer /*****************************************************************************/ 5160b14d95SStefan Weil /* Generic PowerPC 4xx processor instantiation */ 529391b8c5SIgor Mammedov PowerPCCPU *ppc4xx_init(const char *cpu_type, 53c227f099SAnthony Liguori clk_setup_t *cpu_clk, clk_setup_t *tb_clk, 54008ff9d7Sj_mayer uint32_t sysclk) 55008ff9d7Sj_mayer { 5657274713SAndreas Färber PowerPCCPU *cpu; 57e2684c0bSAndreas Färber CPUPPCState *env; 58008ff9d7Sj_mayer 59008ff9d7Sj_mayer /* init CPUs */ 609391b8c5SIgor Mammedov cpu = POWERPC_CPU(cpu_create(cpu_type)); 6157274713SAndreas Färber env = &cpu->env; 6257274713SAndreas Färber 63008ff9d7Sj_mayer cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ 64008ff9d7Sj_mayer cpu_clk->opaque = env; 65008ff9d7Sj_mayer /* Set time-base frequency to sysclk */ 66ddd1055bSFabien Chouteau tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT); 67008ff9d7Sj_mayer tb_clk->opaque = env; 68008ff9d7Sj_mayer ppc_dcr_init(env, NULL, NULL); 69008ff9d7Sj_mayer /* Register qemu callbacks */ 7090cb09d9SAndreas Färber qemu_register_reset(ppc4xx_reset, cpu); 71008ff9d7Sj_mayer 722f9859fbSAndreas Färber return cpu; 73008ff9d7Sj_mayer } 74008ff9d7Sj_mayer 75008ff9d7Sj_mayer /*****************************************************************************/ 76008ff9d7Sj_mayer /* "Universal" Interrupt controller */ 77008ff9d7Sj_mayer enum { 78008ff9d7Sj_mayer DCR_UICSR = 0x000, 79008ff9d7Sj_mayer DCR_UICSRS = 0x001, 80008ff9d7Sj_mayer DCR_UICER = 0x002, 81008ff9d7Sj_mayer DCR_UICCR = 0x003, 82008ff9d7Sj_mayer DCR_UICPR = 0x004, 83008ff9d7Sj_mayer DCR_UICTR = 0x005, 84008ff9d7Sj_mayer DCR_UICMSR = 0x006, 85008ff9d7Sj_mayer DCR_UICVR = 0x007, 86008ff9d7Sj_mayer DCR_UICVCR = 0x008, 87008ff9d7Sj_mayer DCR_UICMAX = 0x009, 88008ff9d7Sj_mayer }; 89008ff9d7Sj_mayer 90008ff9d7Sj_mayer #define UIC_MAX_IRQ 32 91c227f099SAnthony Liguori typedef struct ppcuic_t ppcuic_t; 92c227f099SAnthony Liguori struct ppcuic_t { 93008ff9d7Sj_mayer uint32_t dcr_base; 94008ff9d7Sj_mayer int use_vectors; 954c54e875Saurel32 uint32_t level; /* Remembers the state of level-triggered interrupts. */ 96008ff9d7Sj_mayer uint32_t uicsr; /* Status register */ 97008ff9d7Sj_mayer uint32_t uicer; /* Enable register */ 98008ff9d7Sj_mayer uint32_t uiccr; /* Critical register */ 99008ff9d7Sj_mayer uint32_t uicpr; /* Polarity register */ 100008ff9d7Sj_mayer uint32_t uictr; /* Triggering register */ 101008ff9d7Sj_mayer uint32_t uicvcr; /* Vector configuration register */ 102008ff9d7Sj_mayer uint32_t uicvr; 103008ff9d7Sj_mayer qemu_irq *irqs; 104008ff9d7Sj_mayer }; 105008ff9d7Sj_mayer 106c227f099SAnthony Liguori static void ppcuic_trigger_irq (ppcuic_t *uic) 107008ff9d7Sj_mayer { 108008ff9d7Sj_mayer uint32_t ir, cr; 109008ff9d7Sj_mayer int start, end, inc, i; 110008ff9d7Sj_mayer 111008ff9d7Sj_mayer /* Trigger interrupt if any is pending */ 112008ff9d7Sj_mayer ir = uic->uicsr & uic->uicer & (~uic->uiccr); 113008ff9d7Sj_mayer cr = uic->uicsr & uic->uicer & uic->uiccr; 114d12d51d5Saliguori LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32 115aae9366aSj_mayer " uiccr %08" PRIx32 "\n" 116aae9366aSj_mayer " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", 117aae9366aSj_mayer __func__, uic->uicsr, uic->uicer, uic->uiccr, 118008ff9d7Sj_mayer uic->uicsr & uic->uicer, ir, cr); 119008ff9d7Sj_mayer if (ir != 0x0000000) { 120d12d51d5Saliguori LOG_UIC("Raise UIC interrupt\n"); 121008ff9d7Sj_mayer qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); 122008ff9d7Sj_mayer } else { 123d12d51d5Saliguori LOG_UIC("Lower UIC interrupt\n"); 124008ff9d7Sj_mayer qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); 125008ff9d7Sj_mayer } 126008ff9d7Sj_mayer /* Trigger critical interrupt if any is pending and update vector */ 127008ff9d7Sj_mayer if (cr != 0x0000000) { 128008ff9d7Sj_mayer qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); 129008ff9d7Sj_mayer if (uic->use_vectors) { 130008ff9d7Sj_mayer /* Compute critical IRQ vector */ 131008ff9d7Sj_mayer if (uic->uicvcr & 1) { 132008ff9d7Sj_mayer start = 31; 133008ff9d7Sj_mayer end = 0; 134008ff9d7Sj_mayer inc = -1; 135008ff9d7Sj_mayer } else { 136008ff9d7Sj_mayer start = 0; 137008ff9d7Sj_mayer end = 31; 138008ff9d7Sj_mayer inc = 1; 139008ff9d7Sj_mayer } 140008ff9d7Sj_mayer uic->uicvr = uic->uicvcr & 0xFFFFFFFC; 141008ff9d7Sj_mayer for (i = start; i <= end; i += inc) { 142008ff9d7Sj_mayer if (cr & (1 << i)) { 143008ff9d7Sj_mayer uic->uicvr += (i - start) * 512 * inc; 144008ff9d7Sj_mayer break; 145008ff9d7Sj_mayer } 146008ff9d7Sj_mayer } 147008ff9d7Sj_mayer } 148d12d51d5Saliguori LOG_UIC("Raise UIC critical interrupt - " 149aae9366aSj_mayer "vector %08" PRIx32 "\n", uic->uicvr); 150008ff9d7Sj_mayer } else { 151d12d51d5Saliguori LOG_UIC("Lower UIC critical interrupt\n"); 152008ff9d7Sj_mayer qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); 153008ff9d7Sj_mayer uic->uicvr = 0x00000000; 154008ff9d7Sj_mayer } 155008ff9d7Sj_mayer } 156008ff9d7Sj_mayer 157008ff9d7Sj_mayer static void ppcuic_set_irq (void *opaque, int irq_num, int level) 158008ff9d7Sj_mayer { 159c227f099SAnthony Liguori ppcuic_t *uic; 160008ff9d7Sj_mayer uint32_t mask, sr; 161008ff9d7Sj_mayer 162008ff9d7Sj_mayer uic = opaque; 163a1f7f97bSPeter Maydell mask = 1U << (31-irq_num); 164d12d51d5Saliguori LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32 165aae9366aSj_mayer " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", 166aae9366aSj_mayer __func__, irq_num, level, 167008ff9d7Sj_mayer uic->uicsr, mask, uic->uicsr & mask, level << irq_num); 168008ff9d7Sj_mayer if (irq_num < 0 || irq_num > 31) 169008ff9d7Sj_mayer return; 170008ff9d7Sj_mayer sr = uic->uicsr; 17150bf72b3Saurel32 172008ff9d7Sj_mayer /* Update status register */ 173008ff9d7Sj_mayer if (uic->uictr & mask) { 174008ff9d7Sj_mayer /* Edge sensitive interrupt */ 175008ff9d7Sj_mayer if (level == 1) 176008ff9d7Sj_mayer uic->uicsr |= mask; 177008ff9d7Sj_mayer } else { 178008ff9d7Sj_mayer /* Level sensitive interrupt */ 1794c54e875Saurel32 if (level == 1) { 180008ff9d7Sj_mayer uic->uicsr |= mask; 1814c54e875Saurel32 uic->level |= mask; 1824c54e875Saurel32 } else { 183008ff9d7Sj_mayer uic->uicsr &= ~mask; 1844c54e875Saurel32 uic->level &= ~mask; 1854c54e875Saurel32 } 186008ff9d7Sj_mayer } 187d12d51d5Saliguori LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => " 188aae9366aSj_mayer "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); 189008ff9d7Sj_mayer if (sr != uic->uicsr) 190008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 191008ff9d7Sj_mayer } 192008ff9d7Sj_mayer 19373b01960SAlexander Graf static uint32_t dcr_read_uic (void *opaque, int dcrn) 194008ff9d7Sj_mayer { 195c227f099SAnthony Liguori ppcuic_t *uic; 19673b01960SAlexander Graf uint32_t ret; 197008ff9d7Sj_mayer 198008ff9d7Sj_mayer uic = opaque; 199008ff9d7Sj_mayer dcrn -= uic->dcr_base; 200008ff9d7Sj_mayer switch (dcrn) { 201008ff9d7Sj_mayer case DCR_UICSR: 202008ff9d7Sj_mayer case DCR_UICSRS: 203008ff9d7Sj_mayer ret = uic->uicsr; 204008ff9d7Sj_mayer break; 205008ff9d7Sj_mayer case DCR_UICER: 206008ff9d7Sj_mayer ret = uic->uicer; 207008ff9d7Sj_mayer break; 208008ff9d7Sj_mayer case DCR_UICCR: 209008ff9d7Sj_mayer ret = uic->uiccr; 210008ff9d7Sj_mayer break; 211008ff9d7Sj_mayer case DCR_UICPR: 212008ff9d7Sj_mayer ret = uic->uicpr; 213008ff9d7Sj_mayer break; 214008ff9d7Sj_mayer case DCR_UICTR: 215008ff9d7Sj_mayer ret = uic->uictr; 216008ff9d7Sj_mayer break; 217008ff9d7Sj_mayer case DCR_UICMSR: 218008ff9d7Sj_mayer ret = uic->uicsr & uic->uicer; 219008ff9d7Sj_mayer break; 220008ff9d7Sj_mayer case DCR_UICVR: 221008ff9d7Sj_mayer if (!uic->use_vectors) 222008ff9d7Sj_mayer goto no_read; 223008ff9d7Sj_mayer ret = uic->uicvr; 224008ff9d7Sj_mayer break; 225008ff9d7Sj_mayer case DCR_UICVCR: 226008ff9d7Sj_mayer if (!uic->use_vectors) 227008ff9d7Sj_mayer goto no_read; 228008ff9d7Sj_mayer ret = uic->uicvcr; 229008ff9d7Sj_mayer break; 230008ff9d7Sj_mayer default: 231008ff9d7Sj_mayer no_read: 232008ff9d7Sj_mayer ret = 0x00000000; 233008ff9d7Sj_mayer break; 234008ff9d7Sj_mayer } 235008ff9d7Sj_mayer 236008ff9d7Sj_mayer return ret; 237008ff9d7Sj_mayer } 238008ff9d7Sj_mayer 23973b01960SAlexander Graf static void dcr_write_uic (void *opaque, int dcrn, uint32_t val) 240008ff9d7Sj_mayer { 241c227f099SAnthony Liguori ppcuic_t *uic; 242008ff9d7Sj_mayer 243008ff9d7Sj_mayer uic = opaque; 244008ff9d7Sj_mayer dcrn -= uic->dcr_base; 24573b01960SAlexander Graf LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val); 246008ff9d7Sj_mayer switch (dcrn) { 247008ff9d7Sj_mayer case DCR_UICSR: 248008ff9d7Sj_mayer uic->uicsr &= ~val; 2494c54e875Saurel32 uic->uicsr |= uic->level; 250008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 251008ff9d7Sj_mayer break; 252008ff9d7Sj_mayer case DCR_UICSRS: 253008ff9d7Sj_mayer uic->uicsr |= val; 254008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 255008ff9d7Sj_mayer break; 256008ff9d7Sj_mayer case DCR_UICER: 257008ff9d7Sj_mayer uic->uicer = val; 258008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 259008ff9d7Sj_mayer break; 260008ff9d7Sj_mayer case DCR_UICCR: 261008ff9d7Sj_mayer uic->uiccr = val; 262008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 263008ff9d7Sj_mayer break; 264008ff9d7Sj_mayer case DCR_UICPR: 265008ff9d7Sj_mayer uic->uicpr = val; 266008ff9d7Sj_mayer break; 267008ff9d7Sj_mayer case DCR_UICTR: 268008ff9d7Sj_mayer uic->uictr = val; 269008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 270008ff9d7Sj_mayer break; 271008ff9d7Sj_mayer case DCR_UICMSR: 272008ff9d7Sj_mayer break; 273008ff9d7Sj_mayer case DCR_UICVR: 274008ff9d7Sj_mayer break; 275008ff9d7Sj_mayer case DCR_UICVCR: 276008ff9d7Sj_mayer uic->uicvcr = val & 0xFFFFFFFD; 277008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 278008ff9d7Sj_mayer break; 279008ff9d7Sj_mayer } 280008ff9d7Sj_mayer } 281008ff9d7Sj_mayer 282008ff9d7Sj_mayer static void ppcuic_reset (void *opaque) 283008ff9d7Sj_mayer { 284c227f099SAnthony Liguori ppcuic_t *uic; 285008ff9d7Sj_mayer 286008ff9d7Sj_mayer uic = opaque; 287008ff9d7Sj_mayer uic->uiccr = 0x00000000; 288008ff9d7Sj_mayer uic->uicer = 0x00000000; 289008ff9d7Sj_mayer uic->uicpr = 0x00000000; 290008ff9d7Sj_mayer uic->uicsr = 0x00000000; 291008ff9d7Sj_mayer uic->uictr = 0x00000000; 292008ff9d7Sj_mayer if (uic->use_vectors) { 293008ff9d7Sj_mayer uic->uicvcr = 0x00000000; 294008ff9d7Sj_mayer uic->uicvr = 0x0000000; 295008ff9d7Sj_mayer } 296008ff9d7Sj_mayer } 297008ff9d7Sj_mayer 298e2684c0bSAndreas Färber qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs, 299008ff9d7Sj_mayer uint32_t dcr_base, int has_ssr, int has_vr) 300008ff9d7Sj_mayer { 301c227f099SAnthony Liguori ppcuic_t *uic; 302008ff9d7Sj_mayer int i; 303008ff9d7Sj_mayer 3047267c094SAnthony Liguori uic = g_malloc0(sizeof(ppcuic_t)); 305008ff9d7Sj_mayer uic->dcr_base = dcr_base; 306008ff9d7Sj_mayer uic->irqs = irqs; 307008ff9d7Sj_mayer if (has_vr) 308008ff9d7Sj_mayer uic->use_vectors = 1; 309008ff9d7Sj_mayer for (i = 0; i < DCR_UICMAX; i++) { 310008ff9d7Sj_mayer ppc_dcr_register(env, dcr_base + i, uic, 311008ff9d7Sj_mayer &dcr_read_uic, &dcr_write_uic); 312008ff9d7Sj_mayer } 313a08d4367SJan Kiszka qemu_register_reset(ppcuic_reset, uic); 314008ff9d7Sj_mayer 315008ff9d7Sj_mayer return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); 316008ff9d7Sj_mayer } 31761b24405Saurel32 31861b24405Saurel32 /*****************************************************************************/ 31961b24405Saurel32 /* SDRAM controller */ 320c227f099SAnthony Liguori typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; 321c227f099SAnthony Liguori struct ppc4xx_sdram_t { 32261b24405Saurel32 uint32_t addr; 32361b24405Saurel32 int nbanks; 324b6dcbe08SAvi Kivity MemoryRegion containers[4]; /* used for clipping */ 325b6dcbe08SAvi Kivity MemoryRegion *ram_memories; 326a8170e5eSAvi Kivity hwaddr ram_bases[4]; 327a8170e5eSAvi Kivity hwaddr ram_sizes[4]; 32861b24405Saurel32 uint32_t besr0; 32961b24405Saurel32 uint32_t besr1; 33061b24405Saurel32 uint32_t bear; 33161b24405Saurel32 uint32_t cfg; 33261b24405Saurel32 uint32_t status; 33361b24405Saurel32 uint32_t rtr; 33461b24405Saurel32 uint32_t pmit; 33561b24405Saurel32 uint32_t bcr[4]; 33661b24405Saurel32 uint32_t tr; 33761b24405Saurel32 uint32_t ecccfg; 33861b24405Saurel32 uint32_t eccesr; 33961b24405Saurel32 qemu_irq irq; 34061b24405Saurel32 }; 34161b24405Saurel32 34261b24405Saurel32 enum { 34361b24405Saurel32 SDRAM0_CFGADDR = 0x010, 34461b24405Saurel32 SDRAM0_CFGDATA = 0x011, 34561b24405Saurel32 }; 34661b24405Saurel32 34761b24405Saurel32 /* XXX: TOFIX: some patches have made this code become inconsistent: 348a8170e5eSAvi Kivity * there are type inconsistencies, mixing hwaddr, target_ulong 34961b24405Saurel32 * and uint32_t 35061b24405Saurel32 */ 351a8170e5eSAvi Kivity static uint32_t sdram_bcr (hwaddr ram_base, 352a8170e5eSAvi Kivity hwaddr ram_size) 35361b24405Saurel32 { 35461b24405Saurel32 uint32_t bcr; 35561b24405Saurel32 35661b24405Saurel32 switch (ram_size) { 357ab3dd749SPhilippe Mathieu-Daudé case 4 * MiB: 35861b24405Saurel32 bcr = 0x00000000; 35961b24405Saurel32 break; 360ab3dd749SPhilippe Mathieu-Daudé case 8 * MiB: 36161b24405Saurel32 bcr = 0x00020000; 36261b24405Saurel32 break; 363ab3dd749SPhilippe Mathieu-Daudé case 16 * MiB: 36461b24405Saurel32 bcr = 0x00040000; 36561b24405Saurel32 break; 366ab3dd749SPhilippe Mathieu-Daudé case 32 * MiB: 36761b24405Saurel32 bcr = 0x00060000; 36861b24405Saurel32 break; 369ab3dd749SPhilippe Mathieu-Daudé case 64 * MiB: 37061b24405Saurel32 bcr = 0x00080000; 37161b24405Saurel32 break; 372ab3dd749SPhilippe Mathieu-Daudé case 128 * MiB: 37361b24405Saurel32 bcr = 0x000A0000; 37461b24405Saurel32 break; 375ab3dd749SPhilippe Mathieu-Daudé case 256 * MiB: 37661b24405Saurel32 bcr = 0x000C0000; 37761b24405Saurel32 break; 37861b24405Saurel32 default: 37990e189ecSBlue Swirl printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__, 38090e189ecSBlue Swirl ram_size); 38161b24405Saurel32 return 0x00000000; 38261b24405Saurel32 } 38361b24405Saurel32 bcr |= ram_base & 0xFF800000; 38461b24405Saurel32 bcr |= 1; 38561b24405Saurel32 38661b24405Saurel32 return bcr; 38761b24405Saurel32 } 38861b24405Saurel32 389a8170e5eSAvi Kivity static inline hwaddr sdram_base(uint32_t bcr) 39061b24405Saurel32 { 39161b24405Saurel32 return bcr & 0xFF800000; 39261b24405Saurel32 } 39361b24405Saurel32 39461b24405Saurel32 static target_ulong sdram_size (uint32_t bcr) 39561b24405Saurel32 { 39661b24405Saurel32 target_ulong size; 39761b24405Saurel32 int sh; 39861b24405Saurel32 39961b24405Saurel32 sh = (bcr >> 17) & 0x7; 40061b24405Saurel32 if (sh == 7) 40161b24405Saurel32 size = -1; 40261b24405Saurel32 else 403ab3dd749SPhilippe Mathieu-Daudé size = (4 * MiB) << sh; 40461b24405Saurel32 40561b24405Saurel32 return size; 40661b24405Saurel32 } 40761b24405Saurel32 408b6dcbe08SAvi Kivity static void sdram_set_bcr(ppc4xx_sdram_t *sdram, 409b6dcbe08SAvi Kivity uint32_t *bcrp, uint32_t bcr, int enabled) 41061b24405Saurel32 { 411b6dcbe08SAvi Kivity unsigned n = bcrp - sdram->bcr; 412b6dcbe08SAvi Kivity 41361b24405Saurel32 if (*bcrp & 0x00000001) { 41461b24405Saurel32 /* Unmap RAM */ 41561b24405Saurel32 #ifdef DEBUG_SDRAM 41690e189ecSBlue Swirl printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", 41761b24405Saurel32 __func__, sdram_base(*bcrp), sdram_size(*bcrp)); 41861b24405Saurel32 #endif 419b6dcbe08SAvi Kivity memory_region_del_subregion(get_system_memory(), 420b6dcbe08SAvi Kivity &sdram->containers[n]); 421b6dcbe08SAvi Kivity memory_region_del_subregion(&sdram->containers[n], 422b6dcbe08SAvi Kivity &sdram->ram_memories[n]); 423d8d95814SPaolo Bonzini object_unparent(OBJECT(&sdram->containers[n])); 42461b24405Saurel32 } 42561b24405Saurel32 *bcrp = bcr & 0xFFDEE001; 42661b24405Saurel32 if (enabled && (bcr & 0x00000001)) { 42761b24405Saurel32 #ifdef DEBUG_SDRAM 42890e189ecSBlue Swirl printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", 42961b24405Saurel32 __func__, sdram_base(bcr), sdram_size(bcr)); 43061b24405Saurel32 #endif 4312c9b15caSPaolo Bonzini memory_region_init(&sdram->containers[n], NULL, "sdram-containers", 432b6dcbe08SAvi Kivity sdram_size(bcr)); 433b6dcbe08SAvi Kivity memory_region_add_subregion(&sdram->containers[n], 0, 434b6dcbe08SAvi Kivity &sdram->ram_memories[n]); 435b6dcbe08SAvi Kivity memory_region_add_subregion(get_system_memory(), 436b6dcbe08SAvi Kivity sdram_base(bcr), 437b6dcbe08SAvi Kivity &sdram->containers[n]); 43861b24405Saurel32 } 43961b24405Saurel32 } 44061b24405Saurel32 441c227f099SAnthony Liguori static void sdram_map_bcr (ppc4xx_sdram_t *sdram) 44261b24405Saurel32 { 44361b24405Saurel32 int i; 44461b24405Saurel32 44561b24405Saurel32 for (i = 0; i < sdram->nbanks; i++) { 44661b24405Saurel32 if (sdram->ram_sizes[i] != 0) { 447b6dcbe08SAvi Kivity sdram_set_bcr(sdram, 448b6dcbe08SAvi Kivity &sdram->bcr[i], 44961b24405Saurel32 sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]), 45061b24405Saurel32 1); 45161b24405Saurel32 } else { 452b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0); 45361b24405Saurel32 } 45461b24405Saurel32 } 45561b24405Saurel32 } 45661b24405Saurel32 457c227f099SAnthony Liguori static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) 45861b24405Saurel32 { 45961b24405Saurel32 int i; 46061b24405Saurel32 46161b24405Saurel32 for (i = 0; i < sdram->nbanks; i++) { 46261b24405Saurel32 #ifdef DEBUG_SDRAM 46390e189ecSBlue Swirl printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", 46461b24405Saurel32 __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); 46561b24405Saurel32 #endif 466b6dcbe08SAvi Kivity memory_region_del_subregion(get_system_memory(), 467b6dcbe08SAvi Kivity &sdram->ram_memories[i]); 46861b24405Saurel32 } 46961b24405Saurel32 } 47061b24405Saurel32 47173b01960SAlexander Graf static uint32_t dcr_read_sdram (void *opaque, int dcrn) 47261b24405Saurel32 { 473c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 47473b01960SAlexander Graf uint32_t ret; 47561b24405Saurel32 47661b24405Saurel32 sdram = opaque; 47761b24405Saurel32 switch (dcrn) { 47861b24405Saurel32 case SDRAM0_CFGADDR: 47961b24405Saurel32 ret = sdram->addr; 48061b24405Saurel32 break; 48161b24405Saurel32 case SDRAM0_CFGDATA: 48261b24405Saurel32 switch (sdram->addr) { 48361b24405Saurel32 case 0x00: /* SDRAM_BESR0 */ 48461b24405Saurel32 ret = sdram->besr0; 48561b24405Saurel32 break; 48661b24405Saurel32 case 0x08: /* SDRAM_BESR1 */ 48761b24405Saurel32 ret = sdram->besr1; 48861b24405Saurel32 break; 48961b24405Saurel32 case 0x10: /* SDRAM_BEAR */ 49061b24405Saurel32 ret = sdram->bear; 49161b24405Saurel32 break; 49261b24405Saurel32 case 0x20: /* SDRAM_CFG */ 49361b24405Saurel32 ret = sdram->cfg; 49461b24405Saurel32 break; 49561b24405Saurel32 case 0x24: /* SDRAM_STATUS */ 49661b24405Saurel32 ret = sdram->status; 49761b24405Saurel32 break; 49861b24405Saurel32 case 0x30: /* SDRAM_RTR */ 49961b24405Saurel32 ret = sdram->rtr; 50061b24405Saurel32 break; 50161b24405Saurel32 case 0x34: /* SDRAM_PMIT */ 50261b24405Saurel32 ret = sdram->pmit; 50361b24405Saurel32 break; 50461b24405Saurel32 case 0x40: /* SDRAM_B0CR */ 50561b24405Saurel32 ret = sdram->bcr[0]; 50661b24405Saurel32 break; 50761b24405Saurel32 case 0x44: /* SDRAM_B1CR */ 50861b24405Saurel32 ret = sdram->bcr[1]; 50961b24405Saurel32 break; 51061b24405Saurel32 case 0x48: /* SDRAM_B2CR */ 51161b24405Saurel32 ret = sdram->bcr[2]; 51261b24405Saurel32 break; 51361b24405Saurel32 case 0x4C: /* SDRAM_B3CR */ 51461b24405Saurel32 ret = sdram->bcr[3]; 51561b24405Saurel32 break; 51661b24405Saurel32 case 0x80: /* SDRAM_TR */ 51761b24405Saurel32 ret = -1; /* ? */ 51861b24405Saurel32 break; 51961b24405Saurel32 case 0x94: /* SDRAM_ECCCFG */ 52061b24405Saurel32 ret = sdram->ecccfg; 52161b24405Saurel32 break; 52261b24405Saurel32 case 0x98: /* SDRAM_ECCESR */ 52361b24405Saurel32 ret = sdram->eccesr; 52461b24405Saurel32 break; 52561b24405Saurel32 default: /* Error */ 52661b24405Saurel32 ret = -1; 52761b24405Saurel32 break; 52861b24405Saurel32 } 52961b24405Saurel32 break; 53061b24405Saurel32 default: 53161b24405Saurel32 /* Avoid gcc warning */ 53261b24405Saurel32 ret = 0x00000000; 53361b24405Saurel32 break; 53461b24405Saurel32 } 53561b24405Saurel32 53661b24405Saurel32 return ret; 53761b24405Saurel32 } 53861b24405Saurel32 53973b01960SAlexander Graf static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) 54061b24405Saurel32 { 541c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 54261b24405Saurel32 54361b24405Saurel32 sdram = opaque; 54461b24405Saurel32 switch (dcrn) { 54561b24405Saurel32 case SDRAM0_CFGADDR: 54661b24405Saurel32 sdram->addr = val; 54761b24405Saurel32 break; 54861b24405Saurel32 case SDRAM0_CFGDATA: 54961b24405Saurel32 switch (sdram->addr) { 55061b24405Saurel32 case 0x00: /* SDRAM_BESR0 */ 55161b24405Saurel32 sdram->besr0 &= ~val; 55261b24405Saurel32 break; 55361b24405Saurel32 case 0x08: /* SDRAM_BESR1 */ 55461b24405Saurel32 sdram->besr1 &= ~val; 55561b24405Saurel32 break; 55661b24405Saurel32 case 0x10: /* SDRAM_BEAR */ 55761b24405Saurel32 sdram->bear = val; 55861b24405Saurel32 break; 55961b24405Saurel32 case 0x20: /* SDRAM_CFG */ 56061b24405Saurel32 val &= 0xFFE00000; 56161b24405Saurel32 if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { 56261b24405Saurel32 #ifdef DEBUG_SDRAM 56361b24405Saurel32 printf("%s: enable SDRAM controller\n", __func__); 56461b24405Saurel32 #endif 56561b24405Saurel32 /* validate all RAM mappings */ 56661b24405Saurel32 sdram_map_bcr(sdram); 56761b24405Saurel32 sdram->status &= ~0x80000000; 56861b24405Saurel32 } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { 56961b24405Saurel32 #ifdef DEBUG_SDRAM 57061b24405Saurel32 printf("%s: disable SDRAM controller\n", __func__); 57161b24405Saurel32 #endif 57261b24405Saurel32 /* invalidate all RAM mappings */ 57361b24405Saurel32 sdram_unmap_bcr(sdram); 57461b24405Saurel32 sdram->status |= 0x80000000; 57561b24405Saurel32 } 57661b24405Saurel32 if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) 57761b24405Saurel32 sdram->status |= 0x40000000; 57861b24405Saurel32 else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) 57961b24405Saurel32 sdram->status &= ~0x40000000; 58061b24405Saurel32 sdram->cfg = val; 58161b24405Saurel32 break; 58261b24405Saurel32 case 0x24: /* SDRAM_STATUS */ 58361b24405Saurel32 /* Read-only register */ 58461b24405Saurel32 break; 58561b24405Saurel32 case 0x30: /* SDRAM_RTR */ 58661b24405Saurel32 sdram->rtr = val & 0x3FF80000; 58761b24405Saurel32 break; 58861b24405Saurel32 case 0x34: /* SDRAM_PMIT */ 58961b24405Saurel32 sdram->pmit = (val & 0xF8000000) | 0x07C00000; 59061b24405Saurel32 break; 59161b24405Saurel32 case 0x40: /* SDRAM_B0CR */ 592b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000); 59361b24405Saurel32 break; 59461b24405Saurel32 case 0x44: /* SDRAM_B1CR */ 595b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000); 59661b24405Saurel32 break; 59761b24405Saurel32 case 0x48: /* SDRAM_B2CR */ 598b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000); 59961b24405Saurel32 break; 60061b24405Saurel32 case 0x4C: /* SDRAM_B3CR */ 601b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000); 60261b24405Saurel32 break; 60361b24405Saurel32 case 0x80: /* SDRAM_TR */ 60461b24405Saurel32 sdram->tr = val & 0x018FC01F; 60561b24405Saurel32 break; 60661b24405Saurel32 case 0x94: /* SDRAM_ECCCFG */ 60761b24405Saurel32 sdram->ecccfg = val & 0x00F00000; 60861b24405Saurel32 break; 60961b24405Saurel32 case 0x98: /* SDRAM_ECCESR */ 61061b24405Saurel32 val &= 0xFFF0F000; 61161b24405Saurel32 if (sdram->eccesr == 0 && val != 0) 61261b24405Saurel32 qemu_irq_raise(sdram->irq); 61361b24405Saurel32 else if (sdram->eccesr != 0 && val == 0) 61461b24405Saurel32 qemu_irq_lower(sdram->irq); 61561b24405Saurel32 sdram->eccesr = val; 61661b24405Saurel32 break; 61761b24405Saurel32 default: /* Error */ 61861b24405Saurel32 break; 61961b24405Saurel32 } 62061b24405Saurel32 break; 62161b24405Saurel32 } 62261b24405Saurel32 } 62361b24405Saurel32 62461b24405Saurel32 static void sdram_reset (void *opaque) 62561b24405Saurel32 { 626c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 62761b24405Saurel32 62861b24405Saurel32 sdram = opaque; 62961b24405Saurel32 sdram->addr = 0x00000000; 63061b24405Saurel32 sdram->bear = 0x00000000; 63161b24405Saurel32 sdram->besr0 = 0x00000000; /* No error */ 63261b24405Saurel32 sdram->besr1 = 0x00000000; /* No error */ 63361b24405Saurel32 sdram->cfg = 0x00000000; 63461b24405Saurel32 sdram->ecccfg = 0x00000000; /* No ECC */ 63561b24405Saurel32 sdram->eccesr = 0x00000000; /* No error */ 63661b24405Saurel32 sdram->pmit = 0x07C00000; 63761b24405Saurel32 sdram->rtr = 0x05F00000; 63861b24405Saurel32 sdram->tr = 0x00854009; 63961b24405Saurel32 /* We pre-initialize RAM banks */ 64061b24405Saurel32 sdram->status = 0x00000000; 64161b24405Saurel32 sdram->cfg = 0x00800000; 64261b24405Saurel32 } 64361b24405Saurel32 644e2684c0bSAndreas Färber void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, 645b6dcbe08SAvi Kivity MemoryRegion *ram_memories, 646a8170e5eSAvi Kivity hwaddr *ram_bases, 647a8170e5eSAvi Kivity hwaddr *ram_sizes, 64861b24405Saurel32 int do_init) 64961b24405Saurel32 { 650c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 65161b24405Saurel32 6527267c094SAnthony Liguori sdram = g_malloc0(sizeof(ppc4xx_sdram_t)); 65361b24405Saurel32 sdram->irq = irq; 65461b24405Saurel32 sdram->nbanks = nbanks; 655b6dcbe08SAvi Kivity sdram->ram_memories = ram_memories; 656a8170e5eSAvi Kivity memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); 65761b24405Saurel32 memcpy(sdram->ram_bases, ram_bases, 658a8170e5eSAvi Kivity nbanks * sizeof(hwaddr)); 659a8170e5eSAvi Kivity memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); 66061b24405Saurel32 memcpy(sdram->ram_sizes, ram_sizes, 661a8170e5eSAvi Kivity nbanks * sizeof(hwaddr)); 662a08d4367SJan Kiszka qemu_register_reset(&sdram_reset, sdram); 66361b24405Saurel32 ppc_dcr_register(env, SDRAM0_CFGADDR, 66461b24405Saurel32 sdram, &dcr_read_sdram, &dcr_write_sdram); 66561b24405Saurel32 ppc_dcr_register(env, SDRAM0_CFGDATA, 66661b24405Saurel32 sdram, &dcr_read_sdram, &dcr_write_sdram); 66761b24405Saurel32 if (do_init) 66861b24405Saurel32 sdram_map_bcr(sdram); 66961b24405Saurel32 } 670b7da58fdSaurel32 671b7da58fdSaurel32 /* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory. 672b7da58fdSaurel32 * 673b7da58fdSaurel32 * sdram_bank_sizes[] must be 0-terminated. 674b7da58fdSaurel32 * 675b7da58fdSaurel32 * The 4xx SDRAM controller supports a small number of banks, and each bank 676b7da58fdSaurel32 * must be one of a small set of sizes. The number of banks and the supported 677b7da58fdSaurel32 * sizes varies by SoC. */ 678c227f099SAnthony Liguori ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, 679b6dcbe08SAvi Kivity MemoryRegion ram_memories[], 680a8170e5eSAvi Kivity hwaddr ram_bases[], 681a8170e5eSAvi Kivity hwaddr ram_sizes[], 682*7d8ccf58SBALATON Zoltan const ram_addr_t sdram_bank_sizes[]) 683b7da58fdSaurel32 { 684e206ad48SHu Tao MemoryRegion *ram = g_malloc0(sizeof(*ram)); 685c227f099SAnthony Liguori ram_addr_t size_left = ram_size; 686b6dcbe08SAvi Kivity ram_addr_t base = 0; 687*7d8ccf58SBALATON Zoltan ram_addr_t bank_size; 688b7da58fdSaurel32 int i; 689b7da58fdSaurel32 int j; 690b7da58fdSaurel32 691b7da58fdSaurel32 for (i = 0; i < nr_banks; i++) { 692b7da58fdSaurel32 for (j = 0; sdram_bank_sizes[j] != 0; j++) { 693e206ad48SHu Tao bank_size = sdram_bank_sizes[j]; 6945c130f65Spbrook if (bank_size <= size_left) { 6955c130f65Spbrook size_left -= bank_size; 696b7da58fdSaurel32 } 697b7da58fdSaurel32 } 6985c130f65Spbrook if (!size_left) { 699b7da58fdSaurel32 /* No need to use the remaining banks. */ 700b7da58fdSaurel32 break; 701b7da58fdSaurel32 } 702b7da58fdSaurel32 } 703b7da58fdSaurel32 7045c130f65Spbrook ram_size -= size_left; 705e206ad48SHu Tao if (size_left) { 706ab3dd749SPhilippe Mathieu-Daudé error_report("Truncating memory to %" PRId64 " MiB to fit SDRAM" 707ab3dd749SPhilippe Mathieu-Daudé " controller limits", ram_size / MiB); 708e206ad48SHu Tao } 709e206ad48SHu Tao 710e206ad48SHu Tao memory_region_allocate_system_memory(ram, NULL, "ppc4xx.sdram", ram_size); 711e206ad48SHu Tao 712e206ad48SHu Tao size_left = ram_size; 713e206ad48SHu Tao for (i = 0; i < nr_banks && size_left; i++) { 714e206ad48SHu Tao for (j = 0; sdram_bank_sizes[j] != 0; j++) { 715e206ad48SHu Tao bank_size = sdram_bank_sizes[j]; 716e206ad48SHu Tao 717e206ad48SHu Tao if (bank_size <= size_left) { 718e206ad48SHu Tao char name[32]; 719e206ad48SHu Tao snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); 720e206ad48SHu Tao memory_region_init_alias(&ram_memories[i], NULL, name, ram, 721e206ad48SHu Tao base, bank_size); 722e206ad48SHu Tao ram_bases[i] = base; 723e206ad48SHu Tao ram_sizes[i] = bank_size; 724e206ad48SHu Tao base += bank_size; 725e206ad48SHu Tao size_left -= bank_size; 726e206ad48SHu Tao break; 727e206ad48SHu Tao } 728e206ad48SHu Tao } 729e206ad48SHu Tao } 730b7da58fdSaurel32 7315c130f65Spbrook return ram_size; 732b7da58fdSaurel32 } 733517284a7SBALATON Zoltan 734517284a7SBALATON Zoltan /*****************************************************************************/ 735517284a7SBALATON Zoltan /* MAL */ 73604534280SBALATON Zoltan 737517284a7SBALATON Zoltan enum { 738517284a7SBALATON Zoltan MAL0_CFG = 0x180, 739517284a7SBALATON Zoltan MAL0_ESR = 0x181, 740517284a7SBALATON Zoltan MAL0_IER = 0x182, 741517284a7SBALATON Zoltan MAL0_TXCASR = 0x184, 742517284a7SBALATON Zoltan MAL0_TXCARR = 0x185, 743517284a7SBALATON Zoltan MAL0_TXEOBISR = 0x186, 744517284a7SBALATON Zoltan MAL0_TXDEIR = 0x187, 745517284a7SBALATON Zoltan MAL0_RXCASR = 0x190, 746517284a7SBALATON Zoltan MAL0_RXCARR = 0x191, 747517284a7SBALATON Zoltan MAL0_RXEOBISR = 0x192, 748517284a7SBALATON Zoltan MAL0_RXDEIR = 0x193, 749517284a7SBALATON Zoltan MAL0_TXCTP0R = 0x1A0, 750517284a7SBALATON Zoltan MAL0_RXCTP0R = 0x1C0, 751517284a7SBALATON Zoltan MAL0_RCBS0 = 0x1E0, 752517284a7SBALATON Zoltan MAL0_RCBS1 = 0x1E1, 753517284a7SBALATON Zoltan }; 754517284a7SBALATON Zoltan 75504534280SBALATON Zoltan typedef struct ppc4xx_mal_t ppc4xx_mal_t; 75604534280SBALATON Zoltan struct ppc4xx_mal_t { 757517284a7SBALATON Zoltan qemu_irq irqs[4]; 758517284a7SBALATON Zoltan uint32_t cfg; 759517284a7SBALATON Zoltan uint32_t esr; 760517284a7SBALATON Zoltan uint32_t ier; 761517284a7SBALATON Zoltan uint32_t txcasr; 762517284a7SBALATON Zoltan uint32_t txcarr; 763517284a7SBALATON Zoltan uint32_t txeobisr; 764517284a7SBALATON Zoltan uint32_t txdeir; 765517284a7SBALATON Zoltan uint32_t rxcasr; 766517284a7SBALATON Zoltan uint32_t rxcarr; 767517284a7SBALATON Zoltan uint32_t rxeobisr; 768517284a7SBALATON Zoltan uint32_t rxdeir; 76904534280SBALATON Zoltan uint32_t *txctpr; 77004534280SBALATON Zoltan uint32_t *rxctpr; 77104534280SBALATON Zoltan uint32_t *rcbs; 77204534280SBALATON Zoltan uint8_t txcnum; 77304534280SBALATON Zoltan uint8_t rxcnum; 774517284a7SBALATON Zoltan }; 775517284a7SBALATON Zoltan 77604534280SBALATON Zoltan static void ppc4xx_mal_reset(void *opaque) 77704534280SBALATON Zoltan { 77804534280SBALATON Zoltan ppc4xx_mal_t *mal; 77904534280SBALATON Zoltan 78004534280SBALATON Zoltan mal = opaque; 78104534280SBALATON Zoltan mal->cfg = 0x0007C000; 78204534280SBALATON Zoltan mal->esr = 0x00000000; 78304534280SBALATON Zoltan mal->ier = 0x00000000; 78404534280SBALATON Zoltan mal->rxcasr = 0x00000000; 78504534280SBALATON Zoltan mal->rxdeir = 0x00000000; 78604534280SBALATON Zoltan mal->rxeobisr = 0x00000000; 78704534280SBALATON Zoltan mal->txcasr = 0x00000000; 78804534280SBALATON Zoltan mal->txdeir = 0x00000000; 78904534280SBALATON Zoltan mal->txeobisr = 0x00000000; 79004534280SBALATON Zoltan } 791517284a7SBALATON Zoltan 792517284a7SBALATON Zoltan static uint32_t dcr_read_mal(void *opaque, int dcrn) 793517284a7SBALATON Zoltan { 79404534280SBALATON Zoltan ppc4xx_mal_t *mal; 795517284a7SBALATON Zoltan uint32_t ret; 796517284a7SBALATON Zoltan 797517284a7SBALATON Zoltan mal = opaque; 798517284a7SBALATON Zoltan switch (dcrn) { 799517284a7SBALATON Zoltan case MAL0_CFG: 800517284a7SBALATON Zoltan ret = mal->cfg; 801517284a7SBALATON Zoltan break; 802517284a7SBALATON Zoltan case MAL0_ESR: 803517284a7SBALATON Zoltan ret = mal->esr; 804517284a7SBALATON Zoltan break; 805517284a7SBALATON Zoltan case MAL0_IER: 806517284a7SBALATON Zoltan ret = mal->ier; 807517284a7SBALATON Zoltan break; 808517284a7SBALATON Zoltan case MAL0_TXCASR: 809517284a7SBALATON Zoltan ret = mal->txcasr; 810517284a7SBALATON Zoltan break; 811517284a7SBALATON Zoltan case MAL0_TXCARR: 812517284a7SBALATON Zoltan ret = mal->txcarr; 813517284a7SBALATON Zoltan break; 814517284a7SBALATON Zoltan case MAL0_TXEOBISR: 815517284a7SBALATON Zoltan ret = mal->txeobisr; 816517284a7SBALATON Zoltan break; 817517284a7SBALATON Zoltan case MAL0_TXDEIR: 818517284a7SBALATON Zoltan ret = mal->txdeir; 819517284a7SBALATON Zoltan break; 820517284a7SBALATON Zoltan case MAL0_RXCASR: 821517284a7SBALATON Zoltan ret = mal->rxcasr; 822517284a7SBALATON Zoltan break; 823517284a7SBALATON Zoltan case MAL0_RXCARR: 824517284a7SBALATON Zoltan ret = mal->rxcarr; 825517284a7SBALATON Zoltan break; 826517284a7SBALATON Zoltan case MAL0_RXEOBISR: 827517284a7SBALATON Zoltan ret = mal->rxeobisr; 828517284a7SBALATON Zoltan break; 829517284a7SBALATON Zoltan case MAL0_RXDEIR: 830517284a7SBALATON Zoltan ret = mal->rxdeir; 831517284a7SBALATON Zoltan break; 832517284a7SBALATON Zoltan default: 833517284a7SBALATON Zoltan ret = 0; 834517284a7SBALATON Zoltan break; 835517284a7SBALATON Zoltan } 83604534280SBALATON Zoltan if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { 83704534280SBALATON Zoltan ret = mal->txctpr[dcrn - MAL0_TXCTP0R]; 83804534280SBALATON Zoltan } 83904534280SBALATON Zoltan if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { 84004534280SBALATON Zoltan ret = mal->rxctpr[dcrn - MAL0_RXCTP0R]; 84104534280SBALATON Zoltan } 84204534280SBALATON Zoltan if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { 84304534280SBALATON Zoltan ret = mal->rcbs[dcrn - MAL0_RCBS0]; 84404534280SBALATON Zoltan } 845517284a7SBALATON Zoltan 846517284a7SBALATON Zoltan return ret; 847517284a7SBALATON Zoltan } 848517284a7SBALATON Zoltan 849517284a7SBALATON Zoltan static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) 850517284a7SBALATON Zoltan { 85104534280SBALATON Zoltan ppc4xx_mal_t *mal; 852517284a7SBALATON Zoltan 853517284a7SBALATON Zoltan mal = opaque; 854517284a7SBALATON Zoltan switch (dcrn) { 855517284a7SBALATON Zoltan case MAL0_CFG: 856517284a7SBALATON Zoltan if (val & 0x80000000) { 85704534280SBALATON Zoltan ppc4xx_mal_reset(mal); 858517284a7SBALATON Zoltan } 859517284a7SBALATON Zoltan mal->cfg = val & 0x00FFC087; 860517284a7SBALATON Zoltan break; 861517284a7SBALATON Zoltan case MAL0_ESR: 862517284a7SBALATON Zoltan /* Read/clear */ 863517284a7SBALATON Zoltan mal->esr &= ~val; 864517284a7SBALATON Zoltan break; 865517284a7SBALATON Zoltan case MAL0_IER: 866517284a7SBALATON Zoltan mal->ier = val & 0x0000001F; 867517284a7SBALATON Zoltan break; 868517284a7SBALATON Zoltan case MAL0_TXCASR: 869517284a7SBALATON Zoltan mal->txcasr = val & 0xF0000000; 870517284a7SBALATON Zoltan break; 871517284a7SBALATON Zoltan case MAL0_TXCARR: 872517284a7SBALATON Zoltan mal->txcarr = val & 0xF0000000; 873517284a7SBALATON Zoltan break; 874517284a7SBALATON Zoltan case MAL0_TXEOBISR: 875517284a7SBALATON Zoltan /* Read/clear */ 876517284a7SBALATON Zoltan mal->txeobisr &= ~val; 877517284a7SBALATON Zoltan break; 878517284a7SBALATON Zoltan case MAL0_TXDEIR: 879517284a7SBALATON Zoltan /* Read/clear */ 880517284a7SBALATON Zoltan mal->txdeir &= ~val; 881517284a7SBALATON Zoltan break; 882517284a7SBALATON Zoltan case MAL0_RXCASR: 883517284a7SBALATON Zoltan mal->rxcasr = val & 0xC0000000; 884517284a7SBALATON Zoltan break; 885517284a7SBALATON Zoltan case MAL0_RXCARR: 886517284a7SBALATON Zoltan mal->rxcarr = val & 0xC0000000; 887517284a7SBALATON Zoltan break; 888517284a7SBALATON Zoltan case MAL0_RXEOBISR: 889517284a7SBALATON Zoltan /* Read/clear */ 890517284a7SBALATON Zoltan mal->rxeobisr &= ~val; 891517284a7SBALATON Zoltan break; 892517284a7SBALATON Zoltan case MAL0_RXDEIR: 893517284a7SBALATON Zoltan /* Read/clear */ 894517284a7SBALATON Zoltan mal->rxdeir &= ~val; 895517284a7SBALATON Zoltan break; 89604534280SBALATON Zoltan } 89704534280SBALATON Zoltan if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { 89804534280SBALATON Zoltan mal->txctpr[dcrn - MAL0_TXCTP0R] = val; 89904534280SBALATON Zoltan } 90004534280SBALATON Zoltan if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { 90104534280SBALATON Zoltan mal->rxctpr[dcrn - MAL0_RXCTP0R] = val; 90204534280SBALATON Zoltan } 90304534280SBALATON Zoltan if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { 90404534280SBALATON Zoltan mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF; 905517284a7SBALATON Zoltan } 906517284a7SBALATON Zoltan } 907517284a7SBALATON Zoltan 90804534280SBALATON Zoltan void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, 90904534280SBALATON Zoltan qemu_irq irqs[4]) 910517284a7SBALATON Zoltan { 91104534280SBALATON Zoltan ppc4xx_mal_t *mal; 912517284a7SBALATON Zoltan int i; 913517284a7SBALATON Zoltan 91404534280SBALATON Zoltan assert(txcnum <= 32 && rxcnum <= 32); 91504534280SBALATON Zoltan mal = g_malloc0(sizeof(*mal)); 91604534280SBALATON Zoltan mal->txcnum = txcnum; 91704534280SBALATON Zoltan mal->rxcnum = rxcnum; 91804534280SBALATON Zoltan mal->txctpr = g_new0(uint32_t, txcnum); 91904534280SBALATON Zoltan mal->rxctpr = g_new0(uint32_t, rxcnum); 92004534280SBALATON Zoltan mal->rcbs = g_new0(uint32_t, rxcnum); 921517284a7SBALATON Zoltan for (i = 0; i < 4; i++) { 922517284a7SBALATON Zoltan mal->irqs[i] = irqs[i]; 923517284a7SBALATON Zoltan } 92404534280SBALATON Zoltan qemu_register_reset(&ppc4xx_mal_reset, mal); 925517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_CFG, 926517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 927517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_ESR, 928517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 929517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_IER, 930517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 931517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCASR, 932517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 933517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCARR, 934517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 935517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXEOBISR, 936517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 937517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXDEIR, 938517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 939517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCASR, 940517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 941517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCARR, 942517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 943517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXEOBISR, 944517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 945517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXDEIR, 946517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 94704534280SBALATON Zoltan for (i = 0; i < txcnum; i++) { 94804534280SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCTP0R + i, 949517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 95004534280SBALATON Zoltan } 95104534280SBALATON Zoltan for (i = 0; i < rxcnum; i++) { 95204534280SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCTP0R + i, 953517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 95404534280SBALATON Zoltan } 95504534280SBALATON Zoltan for (i = 0; i < rxcnum; i++) { 95604534280SBALATON Zoltan ppc_dcr_register(env, MAL0_RCBS0 + i, 957517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 95804534280SBALATON Zoltan } 959517284a7SBALATON Zoltan } 960