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" 32e938ba0cSShreyas B. Prabhu #include "hw/boards.h" 331de7afc9SPaolo Bonzini #include "qemu/log.h" 34022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 35ab3dd749SPhilippe Mathieu-Daudé #include "qemu/error-report.h" 36008ff9d7Sj_mayer 37a0557225SBALATON Zoltan /*#define DEBUG_UIC*/ 38d12d51d5Saliguori 39d12d51d5Saliguori #ifdef DEBUG_UIC 4093fcfe39Saliguori # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) 41d12d51d5Saliguori #else 42d12d51d5Saliguori # define LOG_UIC(...) do { } while (0) 43d12d51d5Saliguori #endif 44d12d51d5Saliguori 451bba0dc9SAndreas Färber static void ppc4xx_reset(void *opaque) 461bba0dc9SAndreas Färber { 4790cb09d9SAndreas Färber PowerPCCPU *cpu = opaque; 481bba0dc9SAndreas Färber 4990cb09d9SAndreas Färber cpu_reset(CPU(cpu)); 501bba0dc9SAndreas Färber } 511bba0dc9SAndreas Färber 52008ff9d7Sj_mayer /*****************************************************************************/ 5360b14d95SStefan Weil /* Generic PowerPC 4xx processor instantiation */ 549391b8c5SIgor Mammedov PowerPCCPU *ppc4xx_init(const char *cpu_type, 55c227f099SAnthony Liguori clk_setup_t *cpu_clk, clk_setup_t *tb_clk, 56008ff9d7Sj_mayer uint32_t sysclk) 57008ff9d7Sj_mayer { 5857274713SAndreas Färber PowerPCCPU *cpu; 59e2684c0bSAndreas Färber CPUPPCState *env; 60008ff9d7Sj_mayer 61008ff9d7Sj_mayer /* init CPUs */ 629391b8c5SIgor Mammedov cpu = POWERPC_CPU(cpu_create(cpu_type)); 6357274713SAndreas Färber env = &cpu->env; 6457274713SAndreas Färber 65008ff9d7Sj_mayer cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ 66008ff9d7Sj_mayer cpu_clk->opaque = env; 67008ff9d7Sj_mayer /* Set time-base frequency to sysclk */ 68ddd1055bSFabien Chouteau tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT); 69008ff9d7Sj_mayer tb_clk->opaque = env; 70008ff9d7Sj_mayer ppc_dcr_init(env, NULL, NULL); 71008ff9d7Sj_mayer /* Register qemu callbacks */ 7290cb09d9SAndreas Färber qemu_register_reset(ppc4xx_reset, cpu); 73008ff9d7Sj_mayer 742f9859fbSAndreas Färber return cpu; 75008ff9d7Sj_mayer } 76008ff9d7Sj_mayer 77008ff9d7Sj_mayer /*****************************************************************************/ 78008ff9d7Sj_mayer /* "Universal" Interrupt controller */ 79008ff9d7Sj_mayer enum { 80008ff9d7Sj_mayer DCR_UICSR = 0x000, 81008ff9d7Sj_mayer DCR_UICSRS = 0x001, 82008ff9d7Sj_mayer DCR_UICER = 0x002, 83008ff9d7Sj_mayer DCR_UICCR = 0x003, 84008ff9d7Sj_mayer DCR_UICPR = 0x004, 85008ff9d7Sj_mayer DCR_UICTR = 0x005, 86008ff9d7Sj_mayer DCR_UICMSR = 0x006, 87008ff9d7Sj_mayer DCR_UICVR = 0x007, 88008ff9d7Sj_mayer DCR_UICVCR = 0x008, 89008ff9d7Sj_mayer DCR_UICMAX = 0x009, 90008ff9d7Sj_mayer }; 91008ff9d7Sj_mayer 92008ff9d7Sj_mayer #define UIC_MAX_IRQ 32 93c227f099SAnthony Liguori typedef struct ppcuic_t ppcuic_t; 94c227f099SAnthony Liguori struct ppcuic_t { 95008ff9d7Sj_mayer uint32_t dcr_base; 96008ff9d7Sj_mayer int use_vectors; 974c54e875Saurel32 uint32_t level; /* Remembers the state of level-triggered interrupts. */ 98008ff9d7Sj_mayer uint32_t uicsr; /* Status register */ 99008ff9d7Sj_mayer uint32_t uicer; /* Enable register */ 100008ff9d7Sj_mayer uint32_t uiccr; /* Critical register */ 101008ff9d7Sj_mayer uint32_t uicpr; /* Polarity register */ 102008ff9d7Sj_mayer uint32_t uictr; /* Triggering register */ 103008ff9d7Sj_mayer uint32_t uicvcr; /* Vector configuration register */ 104008ff9d7Sj_mayer uint32_t uicvr; 105008ff9d7Sj_mayer qemu_irq *irqs; 106008ff9d7Sj_mayer }; 107008ff9d7Sj_mayer 108c227f099SAnthony Liguori static void ppcuic_trigger_irq (ppcuic_t *uic) 109008ff9d7Sj_mayer { 110008ff9d7Sj_mayer uint32_t ir, cr; 111008ff9d7Sj_mayer int start, end, inc, i; 112008ff9d7Sj_mayer 113008ff9d7Sj_mayer /* Trigger interrupt if any is pending */ 114008ff9d7Sj_mayer ir = uic->uicsr & uic->uicer & (~uic->uiccr); 115008ff9d7Sj_mayer cr = uic->uicsr & uic->uicer & uic->uiccr; 116d12d51d5Saliguori LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32 117aae9366aSj_mayer " uiccr %08" PRIx32 "\n" 118aae9366aSj_mayer " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", 119aae9366aSj_mayer __func__, uic->uicsr, uic->uicer, uic->uiccr, 120008ff9d7Sj_mayer uic->uicsr & uic->uicer, ir, cr); 121008ff9d7Sj_mayer if (ir != 0x0000000) { 122d12d51d5Saliguori LOG_UIC("Raise UIC interrupt\n"); 123008ff9d7Sj_mayer qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); 124008ff9d7Sj_mayer } else { 125d12d51d5Saliguori LOG_UIC("Lower UIC interrupt\n"); 126008ff9d7Sj_mayer qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); 127008ff9d7Sj_mayer } 128008ff9d7Sj_mayer /* Trigger critical interrupt if any is pending and update vector */ 129008ff9d7Sj_mayer if (cr != 0x0000000) { 130008ff9d7Sj_mayer qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); 131008ff9d7Sj_mayer if (uic->use_vectors) { 132008ff9d7Sj_mayer /* Compute critical IRQ vector */ 133008ff9d7Sj_mayer if (uic->uicvcr & 1) { 134008ff9d7Sj_mayer start = 31; 135008ff9d7Sj_mayer end = 0; 136008ff9d7Sj_mayer inc = -1; 137008ff9d7Sj_mayer } else { 138008ff9d7Sj_mayer start = 0; 139008ff9d7Sj_mayer end = 31; 140008ff9d7Sj_mayer inc = 1; 141008ff9d7Sj_mayer } 142008ff9d7Sj_mayer uic->uicvr = uic->uicvcr & 0xFFFFFFFC; 143008ff9d7Sj_mayer for (i = start; i <= end; i += inc) { 144008ff9d7Sj_mayer if (cr & (1 << i)) { 145008ff9d7Sj_mayer uic->uicvr += (i - start) * 512 * inc; 146008ff9d7Sj_mayer break; 147008ff9d7Sj_mayer } 148008ff9d7Sj_mayer } 149008ff9d7Sj_mayer } 150d12d51d5Saliguori LOG_UIC("Raise UIC critical interrupt - " 151aae9366aSj_mayer "vector %08" PRIx32 "\n", uic->uicvr); 152008ff9d7Sj_mayer } else { 153d12d51d5Saliguori LOG_UIC("Lower UIC critical interrupt\n"); 154008ff9d7Sj_mayer qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); 155008ff9d7Sj_mayer uic->uicvr = 0x00000000; 156008ff9d7Sj_mayer } 157008ff9d7Sj_mayer } 158008ff9d7Sj_mayer 159008ff9d7Sj_mayer static void ppcuic_set_irq (void *opaque, int irq_num, int level) 160008ff9d7Sj_mayer { 161c227f099SAnthony Liguori ppcuic_t *uic; 162008ff9d7Sj_mayer uint32_t mask, sr; 163008ff9d7Sj_mayer 164008ff9d7Sj_mayer uic = opaque; 165a1f7f97bSPeter Maydell mask = 1U << (31-irq_num); 166d12d51d5Saliguori LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32 167aae9366aSj_mayer " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", 168aae9366aSj_mayer __func__, irq_num, level, 169008ff9d7Sj_mayer uic->uicsr, mask, uic->uicsr & mask, level << irq_num); 170008ff9d7Sj_mayer if (irq_num < 0 || irq_num > 31) 171008ff9d7Sj_mayer return; 172008ff9d7Sj_mayer sr = uic->uicsr; 17350bf72b3Saurel32 174008ff9d7Sj_mayer /* Update status register */ 175008ff9d7Sj_mayer if (uic->uictr & mask) { 176008ff9d7Sj_mayer /* Edge sensitive interrupt */ 177008ff9d7Sj_mayer if (level == 1) 178008ff9d7Sj_mayer uic->uicsr |= mask; 179008ff9d7Sj_mayer } else { 180008ff9d7Sj_mayer /* Level sensitive interrupt */ 1814c54e875Saurel32 if (level == 1) { 182008ff9d7Sj_mayer uic->uicsr |= mask; 1834c54e875Saurel32 uic->level |= mask; 1844c54e875Saurel32 } else { 185008ff9d7Sj_mayer uic->uicsr &= ~mask; 1864c54e875Saurel32 uic->level &= ~mask; 1874c54e875Saurel32 } 188008ff9d7Sj_mayer } 189d12d51d5Saliguori LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => " 190aae9366aSj_mayer "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); 191008ff9d7Sj_mayer if (sr != uic->uicsr) 192008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 193008ff9d7Sj_mayer } 194008ff9d7Sj_mayer 19573b01960SAlexander Graf static uint32_t dcr_read_uic (void *opaque, int dcrn) 196008ff9d7Sj_mayer { 197c227f099SAnthony Liguori ppcuic_t *uic; 19873b01960SAlexander Graf uint32_t ret; 199008ff9d7Sj_mayer 200008ff9d7Sj_mayer uic = opaque; 201008ff9d7Sj_mayer dcrn -= uic->dcr_base; 202008ff9d7Sj_mayer switch (dcrn) { 203008ff9d7Sj_mayer case DCR_UICSR: 204008ff9d7Sj_mayer case DCR_UICSRS: 205008ff9d7Sj_mayer ret = uic->uicsr; 206008ff9d7Sj_mayer break; 207008ff9d7Sj_mayer case DCR_UICER: 208008ff9d7Sj_mayer ret = uic->uicer; 209008ff9d7Sj_mayer break; 210008ff9d7Sj_mayer case DCR_UICCR: 211008ff9d7Sj_mayer ret = uic->uiccr; 212008ff9d7Sj_mayer break; 213008ff9d7Sj_mayer case DCR_UICPR: 214008ff9d7Sj_mayer ret = uic->uicpr; 215008ff9d7Sj_mayer break; 216008ff9d7Sj_mayer case DCR_UICTR: 217008ff9d7Sj_mayer ret = uic->uictr; 218008ff9d7Sj_mayer break; 219008ff9d7Sj_mayer case DCR_UICMSR: 220008ff9d7Sj_mayer ret = uic->uicsr & uic->uicer; 221008ff9d7Sj_mayer break; 222008ff9d7Sj_mayer case DCR_UICVR: 223008ff9d7Sj_mayer if (!uic->use_vectors) 224008ff9d7Sj_mayer goto no_read; 225008ff9d7Sj_mayer ret = uic->uicvr; 226008ff9d7Sj_mayer break; 227008ff9d7Sj_mayer case DCR_UICVCR: 228008ff9d7Sj_mayer if (!uic->use_vectors) 229008ff9d7Sj_mayer goto no_read; 230008ff9d7Sj_mayer ret = uic->uicvcr; 231008ff9d7Sj_mayer break; 232008ff9d7Sj_mayer default: 233008ff9d7Sj_mayer no_read: 234008ff9d7Sj_mayer ret = 0x00000000; 235008ff9d7Sj_mayer break; 236008ff9d7Sj_mayer } 237008ff9d7Sj_mayer 238008ff9d7Sj_mayer return ret; 239008ff9d7Sj_mayer } 240008ff9d7Sj_mayer 24173b01960SAlexander Graf static void dcr_write_uic (void *opaque, int dcrn, uint32_t val) 242008ff9d7Sj_mayer { 243c227f099SAnthony Liguori ppcuic_t *uic; 244008ff9d7Sj_mayer 245008ff9d7Sj_mayer uic = opaque; 246008ff9d7Sj_mayer dcrn -= uic->dcr_base; 24773b01960SAlexander Graf LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val); 248008ff9d7Sj_mayer switch (dcrn) { 249008ff9d7Sj_mayer case DCR_UICSR: 250008ff9d7Sj_mayer uic->uicsr &= ~val; 2514c54e875Saurel32 uic->uicsr |= uic->level; 252008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 253008ff9d7Sj_mayer break; 254008ff9d7Sj_mayer case DCR_UICSRS: 255008ff9d7Sj_mayer uic->uicsr |= val; 256008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 257008ff9d7Sj_mayer break; 258008ff9d7Sj_mayer case DCR_UICER: 259008ff9d7Sj_mayer uic->uicer = val; 260008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 261008ff9d7Sj_mayer break; 262008ff9d7Sj_mayer case DCR_UICCR: 263008ff9d7Sj_mayer uic->uiccr = val; 264008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 265008ff9d7Sj_mayer break; 266008ff9d7Sj_mayer case DCR_UICPR: 267008ff9d7Sj_mayer uic->uicpr = val; 268008ff9d7Sj_mayer break; 269008ff9d7Sj_mayer case DCR_UICTR: 270008ff9d7Sj_mayer uic->uictr = val; 271008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 272008ff9d7Sj_mayer break; 273008ff9d7Sj_mayer case DCR_UICMSR: 274008ff9d7Sj_mayer break; 275008ff9d7Sj_mayer case DCR_UICVR: 276008ff9d7Sj_mayer break; 277008ff9d7Sj_mayer case DCR_UICVCR: 278008ff9d7Sj_mayer uic->uicvcr = val & 0xFFFFFFFD; 279008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 280008ff9d7Sj_mayer break; 281008ff9d7Sj_mayer } 282008ff9d7Sj_mayer } 283008ff9d7Sj_mayer 284008ff9d7Sj_mayer static void ppcuic_reset (void *opaque) 285008ff9d7Sj_mayer { 286c227f099SAnthony Liguori ppcuic_t *uic; 287008ff9d7Sj_mayer 288008ff9d7Sj_mayer uic = opaque; 289008ff9d7Sj_mayer uic->uiccr = 0x00000000; 290008ff9d7Sj_mayer uic->uicer = 0x00000000; 291008ff9d7Sj_mayer uic->uicpr = 0x00000000; 292008ff9d7Sj_mayer uic->uicsr = 0x00000000; 293008ff9d7Sj_mayer uic->uictr = 0x00000000; 294008ff9d7Sj_mayer if (uic->use_vectors) { 295008ff9d7Sj_mayer uic->uicvcr = 0x00000000; 296008ff9d7Sj_mayer uic->uicvr = 0x0000000; 297008ff9d7Sj_mayer } 298008ff9d7Sj_mayer } 299008ff9d7Sj_mayer 300e2684c0bSAndreas Färber qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs, 301008ff9d7Sj_mayer uint32_t dcr_base, int has_ssr, int has_vr) 302008ff9d7Sj_mayer { 303c227f099SAnthony Liguori ppcuic_t *uic; 304008ff9d7Sj_mayer int i; 305008ff9d7Sj_mayer 3067267c094SAnthony Liguori uic = g_malloc0(sizeof(ppcuic_t)); 307008ff9d7Sj_mayer uic->dcr_base = dcr_base; 308008ff9d7Sj_mayer uic->irqs = irqs; 309008ff9d7Sj_mayer if (has_vr) 310008ff9d7Sj_mayer uic->use_vectors = 1; 311008ff9d7Sj_mayer for (i = 0; i < DCR_UICMAX; i++) { 312008ff9d7Sj_mayer ppc_dcr_register(env, dcr_base + i, uic, 313008ff9d7Sj_mayer &dcr_read_uic, &dcr_write_uic); 314008ff9d7Sj_mayer } 315a08d4367SJan Kiszka qemu_register_reset(ppcuic_reset, uic); 316008ff9d7Sj_mayer 317008ff9d7Sj_mayer return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); 318008ff9d7Sj_mayer } 31961b24405Saurel32 32061b24405Saurel32 /*****************************************************************************/ 32161b24405Saurel32 /* SDRAM controller */ 322c227f099SAnthony Liguori typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; 323c227f099SAnthony Liguori struct ppc4xx_sdram_t { 32461b24405Saurel32 uint32_t addr; 32561b24405Saurel32 int nbanks; 326b6dcbe08SAvi Kivity MemoryRegion containers[4]; /* used for clipping */ 327b6dcbe08SAvi Kivity MemoryRegion *ram_memories; 328a8170e5eSAvi Kivity hwaddr ram_bases[4]; 329a8170e5eSAvi Kivity hwaddr ram_sizes[4]; 33061b24405Saurel32 uint32_t besr0; 33161b24405Saurel32 uint32_t besr1; 33261b24405Saurel32 uint32_t bear; 33361b24405Saurel32 uint32_t cfg; 33461b24405Saurel32 uint32_t status; 33561b24405Saurel32 uint32_t rtr; 33661b24405Saurel32 uint32_t pmit; 33761b24405Saurel32 uint32_t bcr[4]; 33861b24405Saurel32 uint32_t tr; 33961b24405Saurel32 uint32_t ecccfg; 34061b24405Saurel32 uint32_t eccesr; 34161b24405Saurel32 qemu_irq irq; 34261b24405Saurel32 }; 34361b24405Saurel32 34461b24405Saurel32 enum { 34561b24405Saurel32 SDRAM0_CFGADDR = 0x010, 34661b24405Saurel32 SDRAM0_CFGDATA = 0x011, 34761b24405Saurel32 }; 34861b24405Saurel32 34961b24405Saurel32 /* XXX: TOFIX: some patches have made this code become inconsistent: 350a8170e5eSAvi Kivity * there are type inconsistencies, mixing hwaddr, target_ulong 35161b24405Saurel32 * and uint32_t 35261b24405Saurel32 */ 353a8170e5eSAvi Kivity static uint32_t sdram_bcr (hwaddr ram_base, 354a8170e5eSAvi Kivity hwaddr ram_size) 35561b24405Saurel32 { 35661b24405Saurel32 uint32_t bcr; 35761b24405Saurel32 35861b24405Saurel32 switch (ram_size) { 359ab3dd749SPhilippe Mathieu-Daudé case 4 * MiB: 36061b24405Saurel32 bcr = 0x00000000; 36161b24405Saurel32 break; 362ab3dd749SPhilippe Mathieu-Daudé case 8 * MiB: 36361b24405Saurel32 bcr = 0x00020000; 36461b24405Saurel32 break; 365ab3dd749SPhilippe Mathieu-Daudé case 16 * MiB: 36661b24405Saurel32 bcr = 0x00040000; 36761b24405Saurel32 break; 368ab3dd749SPhilippe Mathieu-Daudé case 32 * MiB: 36961b24405Saurel32 bcr = 0x00060000; 37061b24405Saurel32 break; 371ab3dd749SPhilippe Mathieu-Daudé case 64 * MiB: 37261b24405Saurel32 bcr = 0x00080000; 37361b24405Saurel32 break; 374ab3dd749SPhilippe Mathieu-Daudé case 128 * MiB: 37561b24405Saurel32 bcr = 0x000A0000; 37661b24405Saurel32 break; 377ab3dd749SPhilippe Mathieu-Daudé case 256 * MiB: 37861b24405Saurel32 bcr = 0x000C0000; 37961b24405Saurel32 break; 38061b24405Saurel32 default: 38190e189ecSBlue Swirl printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__, 38290e189ecSBlue Swirl ram_size); 38361b24405Saurel32 return 0x00000000; 38461b24405Saurel32 } 38561b24405Saurel32 bcr |= ram_base & 0xFF800000; 38661b24405Saurel32 bcr |= 1; 38761b24405Saurel32 38861b24405Saurel32 return bcr; 38961b24405Saurel32 } 39061b24405Saurel32 391a8170e5eSAvi Kivity static inline hwaddr sdram_base(uint32_t bcr) 39261b24405Saurel32 { 39361b24405Saurel32 return bcr & 0xFF800000; 39461b24405Saurel32 } 39561b24405Saurel32 39661b24405Saurel32 static target_ulong sdram_size (uint32_t bcr) 39761b24405Saurel32 { 39861b24405Saurel32 target_ulong size; 39961b24405Saurel32 int sh; 40061b24405Saurel32 40161b24405Saurel32 sh = (bcr >> 17) & 0x7; 40261b24405Saurel32 if (sh == 7) 40361b24405Saurel32 size = -1; 40461b24405Saurel32 else 405ab3dd749SPhilippe Mathieu-Daudé size = (4 * MiB) << sh; 40661b24405Saurel32 40761b24405Saurel32 return size; 40861b24405Saurel32 } 40961b24405Saurel32 41070812bf7SBALATON Zoltan static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i, 41170812bf7SBALATON Zoltan uint32_t bcr, int enabled) 41261b24405Saurel32 { 41370812bf7SBALATON Zoltan if (sdram->bcr[i] & 0x00000001) { 41461b24405Saurel32 /* Unmap RAM */ 41561b24405Saurel32 #ifdef DEBUG_SDRAM 41690e189ecSBlue Swirl printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", 41770812bf7SBALATON Zoltan __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); 41861b24405Saurel32 #endif 419b6dcbe08SAvi Kivity memory_region_del_subregion(get_system_memory(), 42070812bf7SBALATON Zoltan &sdram->containers[i]); 42170812bf7SBALATON Zoltan memory_region_del_subregion(&sdram->containers[i], 42270812bf7SBALATON Zoltan &sdram->ram_memories[i]); 42370812bf7SBALATON Zoltan object_unparent(OBJECT(&sdram->containers[i])); 42461b24405Saurel32 } 42570812bf7SBALATON Zoltan sdram->bcr[i] = 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 43170812bf7SBALATON Zoltan memory_region_init(&sdram->containers[i], NULL, "sdram-containers", 432b6dcbe08SAvi Kivity sdram_size(bcr)); 43370812bf7SBALATON Zoltan memory_region_add_subregion(&sdram->containers[i], 0, 43470812bf7SBALATON Zoltan &sdram->ram_memories[i]); 435b6dcbe08SAvi Kivity memory_region_add_subregion(get_system_memory(), 436b6dcbe08SAvi Kivity sdram_base(bcr), 43770812bf7SBALATON Zoltan &sdram->containers[i]); 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) { 44770812bf7SBALATON Zoltan sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], 44870812bf7SBALATON Zoltan sdram->ram_sizes[i]), 1); 44961b24405Saurel32 } else { 45070812bf7SBALATON Zoltan sdram_set_bcr(sdram, i, 0x00000000, 0); 45161b24405Saurel32 } 45261b24405Saurel32 } 45361b24405Saurel32 } 45461b24405Saurel32 455c227f099SAnthony Liguori static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) 45661b24405Saurel32 { 45761b24405Saurel32 int i; 45861b24405Saurel32 45961b24405Saurel32 for (i = 0; i < sdram->nbanks; i++) { 46061b24405Saurel32 #ifdef DEBUG_SDRAM 46190e189ecSBlue Swirl printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", 46261b24405Saurel32 __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); 46361b24405Saurel32 #endif 464b6dcbe08SAvi Kivity memory_region_del_subregion(get_system_memory(), 465b6dcbe08SAvi Kivity &sdram->ram_memories[i]); 46661b24405Saurel32 } 46761b24405Saurel32 } 46861b24405Saurel32 46973b01960SAlexander Graf static uint32_t dcr_read_sdram (void *opaque, int dcrn) 47061b24405Saurel32 { 471c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 47273b01960SAlexander Graf uint32_t ret; 47361b24405Saurel32 47461b24405Saurel32 sdram = opaque; 47561b24405Saurel32 switch (dcrn) { 47661b24405Saurel32 case SDRAM0_CFGADDR: 47761b24405Saurel32 ret = sdram->addr; 47861b24405Saurel32 break; 47961b24405Saurel32 case SDRAM0_CFGDATA: 48061b24405Saurel32 switch (sdram->addr) { 48161b24405Saurel32 case 0x00: /* SDRAM_BESR0 */ 48261b24405Saurel32 ret = sdram->besr0; 48361b24405Saurel32 break; 48461b24405Saurel32 case 0x08: /* SDRAM_BESR1 */ 48561b24405Saurel32 ret = sdram->besr1; 48661b24405Saurel32 break; 48761b24405Saurel32 case 0x10: /* SDRAM_BEAR */ 48861b24405Saurel32 ret = sdram->bear; 48961b24405Saurel32 break; 49061b24405Saurel32 case 0x20: /* SDRAM_CFG */ 49161b24405Saurel32 ret = sdram->cfg; 49261b24405Saurel32 break; 49361b24405Saurel32 case 0x24: /* SDRAM_STATUS */ 49461b24405Saurel32 ret = sdram->status; 49561b24405Saurel32 break; 49661b24405Saurel32 case 0x30: /* SDRAM_RTR */ 49761b24405Saurel32 ret = sdram->rtr; 49861b24405Saurel32 break; 49961b24405Saurel32 case 0x34: /* SDRAM_PMIT */ 50061b24405Saurel32 ret = sdram->pmit; 50161b24405Saurel32 break; 50261b24405Saurel32 case 0x40: /* SDRAM_B0CR */ 50361b24405Saurel32 ret = sdram->bcr[0]; 50461b24405Saurel32 break; 50561b24405Saurel32 case 0x44: /* SDRAM_B1CR */ 50661b24405Saurel32 ret = sdram->bcr[1]; 50761b24405Saurel32 break; 50861b24405Saurel32 case 0x48: /* SDRAM_B2CR */ 50961b24405Saurel32 ret = sdram->bcr[2]; 51061b24405Saurel32 break; 51161b24405Saurel32 case 0x4C: /* SDRAM_B3CR */ 51261b24405Saurel32 ret = sdram->bcr[3]; 51361b24405Saurel32 break; 51461b24405Saurel32 case 0x80: /* SDRAM_TR */ 51561b24405Saurel32 ret = -1; /* ? */ 51661b24405Saurel32 break; 51761b24405Saurel32 case 0x94: /* SDRAM_ECCCFG */ 51861b24405Saurel32 ret = sdram->ecccfg; 51961b24405Saurel32 break; 52061b24405Saurel32 case 0x98: /* SDRAM_ECCESR */ 52161b24405Saurel32 ret = sdram->eccesr; 52261b24405Saurel32 break; 52361b24405Saurel32 default: /* Error */ 52461b24405Saurel32 ret = -1; 52561b24405Saurel32 break; 52661b24405Saurel32 } 52761b24405Saurel32 break; 52861b24405Saurel32 default: 52961b24405Saurel32 /* Avoid gcc warning */ 53061b24405Saurel32 ret = 0x00000000; 53161b24405Saurel32 break; 53261b24405Saurel32 } 53361b24405Saurel32 53461b24405Saurel32 return ret; 53561b24405Saurel32 } 53661b24405Saurel32 53773b01960SAlexander Graf static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) 53861b24405Saurel32 { 539c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 54061b24405Saurel32 54161b24405Saurel32 sdram = opaque; 54261b24405Saurel32 switch (dcrn) { 54361b24405Saurel32 case SDRAM0_CFGADDR: 54461b24405Saurel32 sdram->addr = val; 54561b24405Saurel32 break; 54661b24405Saurel32 case SDRAM0_CFGDATA: 54761b24405Saurel32 switch (sdram->addr) { 54861b24405Saurel32 case 0x00: /* SDRAM_BESR0 */ 54961b24405Saurel32 sdram->besr0 &= ~val; 55061b24405Saurel32 break; 55161b24405Saurel32 case 0x08: /* SDRAM_BESR1 */ 55261b24405Saurel32 sdram->besr1 &= ~val; 55361b24405Saurel32 break; 55461b24405Saurel32 case 0x10: /* SDRAM_BEAR */ 55561b24405Saurel32 sdram->bear = val; 55661b24405Saurel32 break; 55761b24405Saurel32 case 0x20: /* SDRAM_CFG */ 55861b24405Saurel32 val &= 0xFFE00000; 55961b24405Saurel32 if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { 56061b24405Saurel32 #ifdef DEBUG_SDRAM 56161b24405Saurel32 printf("%s: enable SDRAM controller\n", __func__); 56261b24405Saurel32 #endif 56361b24405Saurel32 /* validate all RAM mappings */ 56461b24405Saurel32 sdram_map_bcr(sdram); 56561b24405Saurel32 sdram->status &= ~0x80000000; 56661b24405Saurel32 } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { 56761b24405Saurel32 #ifdef DEBUG_SDRAM 56861b24405Saurel32 printf("%s: disable SDRAM controller\n", __func__); 56961b24405Saurel32 #endif 57061b24405Saurel32 /* invalidate all RAM mappings */ 57161b24405Saurel32 sdram_unmap_bcr(sdram); 57261b24405Saurel32 sdram->status |= 0x80000000; 57361b24405Saurel32 } 57461b24405Saurel32 if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) 57561b24405Saurel32 sdram->status |= 0x40000000; 57661b24405Saurel32 else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) 57761b24405Saurel32 sdram->status &= ~0x40000000; 57861b24405Saurel32 sdram->cfg = val; 57961b24405Saurel32 break; 58061b24405Saurel32 case 0x24: /* SDRAM_STATUS */ 58161b24405Saurel32 /* Read-only register */ 58261b24405Saurel32 break; 58361b24405Saurel32 case 0x30: /* SDRAM_RTR */ 58461b24405Saurel32 sdram->rtr = val & 0x3FF80000; 58561b24405Saurel32 break; 58661b24405Saurel32 case 0x34: /* SDRAM_PMIT */ 58761b24405Saurel32 sdram->pmit = (val & 0xF8000000) | 0x07C00000; 58861b24405Saurel32 break; 58961b24405Saurel32 case 0x40: /* SDRAM_B0CR */ 59070812bf7SBALATON Zoltan sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000); 59161b24405Saurel32 break; 59261b24405Saurel32 case 0x44: /* SDRAM_B1CR */ 59370812bf7SBALATON Zoltan sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000); 59461b24405Saurel32 break; 59561b24405Saurel32 case 0x48: /* SDRAM_B2CR */ 59670812bf7SBALATON Zoltan sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000); 59761b24405Saurel32 break; 59861b24405Saurel32 case 0x4C: /* SDRAM_B3CR */ 59970812bf7SBALATON Zoltan sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000); 60061b24405Saurel32 break; 60161b24405Saurel32 case 0x80: /* SDRAM_TR */ 60261b24405Saurel32 sdram->tr = val & 0x018FC01F; 60361b24405Saurel32 break; 60461b24405Saurel32 case 0x94: /* SDRAM_ECCCFG */ 60561b24405Saurel32 sdram->ecccfg = val & 0x00F00000; 60661b24405Saurel32 break; 60761b24405Saurel32 case 0x98: /* SDRAM_ECCESR */ 60861b24405Saurel32 val &= 0xFFF0F000; 60961b24405Saurel32 if (sdram->eccesr == 0 && val != 0) 61061b24405Saurel32 qemu_irq_raise(sdram->irq); 61161b24405Saurel32 else if (sdram->eccesr != 0 && val == 0) 61261b24405Saurel32 qemu_irq_lower(sdram->irq); 61361b24405Saurel32 sdram->eccesr = val; 61461b24405Saurel32 break; 61561b24405Saurel32 default: /* Error */ 61661b24405Saurel32 break; 61761b24405Saurel32 } 61861b24405Saurel32 break; 61961b24405Saurel32 } 62061b24405Saurel32 } 62161b24405Saurel32 62261b24405Saurel32 static void sdram_reset (void *opaque) 62361b24405Saurel32 { 624c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 62561b24405Saurel32 62661b24405Saurel32 sdram = opaque; 62761b24405Saurel32 sdram->addr = 0x00000000; 62861b24405Saurel32 sdram->bear = 0x00000000; 62961b24405Saurel32 sdram->besr0 = 0x00000000; /* No error */ 63061b24405Saurel32 sdram->besr1 = 0x00000000; /* No error */ 63161b24405Saurel32 sdram->cfg = 0x00000000; 63261b24405Saurel32 sdram->ecccfg = 0x00000000; /* No ECC */ 63361b24405Saurel32 sdram->eccesr = 0x00000000; /* No error */ 63461b24405Saurel32 sdram->pmit = 0x07C00000; 63561b24405Saurel32 sdram->rtr = 0x05F00000; 63661b24405Saurel32 sdram->tr = 0x00854009; 63761b24405Saurel32 /* We pre-initialize RAM banks */ 63861b24405Saurel32 sdram->status = 0x00000000; 63961b24405Saurel32 sdram->cfg = 0x00800000; 64061b24405Saurel32 } 64161b24405Saurel32 642e2684c0bSAndreas Färber void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, 643b6dcbe08SAvi Kivity MemoryRegion *ram_memories, 644a8170e5eSAvi Kivity hwaddr *ram_bases, 645a8170e5eSAvi Kivity hwaddr *ram_sizes, 64661b24405Saurel32 int do_init) 64761b24405Saurel32 { 648c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 64961b24405Saurel32 6507267c094SAnthony Liguori sdram = g_malloc0(sizeof(ppc4xx_sdram_t)); 65161b24405Saurel32 sdram->irq = irq; 65261b24405Saurel32 sdram->nbanks = nbanks; 653b6dcbe08SAvi Kivity sdram->ram_memories = ram_memories; 654a8170e5eSAvi Kivity memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); 65561b24405Saurel32 memcpy(sdram->ram_bases, ram_bases, 656a8170e5eSAvi Kivity nbanks * sizeof(hwaddr)); 657a8170e5eSAvi Kivity memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); 65861b24405Saurel32 memcpy(sdram->ram_sizes, ram_sizes, 659a8170e5eSAvi Kivity nbanks * sizeof(hwaddr)); 660a08d4367SJan Kiszka qemu_register_reset(&sdram_reset, sdram); 66161b24405Saurel32 ppc_dcr_register(env, SDRAM0_CFGADDR, 66261b24405Saurel32 sdram, &dcr_read_sdram, &dcr_write_sdram); 66361b24405Saurel32 ppc_dcr_register(env, SDRAM0_CFGDATA, 66461b24405Saurel32 sdram, &dcr_read_sdram, &dcr_write_sdram); 66561b24405Saurel32 if (do_init) 66661b24405Saurel32 sdram_map_bcr(sdram); 66761b24405Saurel32 } 668b7da58fdSaurel32 669b7da58fdSaurel32 /* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory. 670b7da58fdSaurel32 * 671*a0258e4aSIgor Mammedov * sdram_bank_sizes[] must be in descending order, that is sizes[i] > sizes[i+1] 672*a0258e4aSIgor Mammedov * and must be 0-terminated. 673b7da58fdSaurel32 * 674b7da58fdSaurel32 * The 4xx SDRAM controller supports a small number of banks, and each bank 675b7da58fdSaurel32 * must be one of a small set of sizes. The number of banks and the supported 676b7da58fdSaurel32 * sizes varies by SoC. */ 677*a0258e4aSIgor Mammedov void ppc4xx_sdram_banks(ram_addr_t ram_size, int nr_banks, 678b6dcbe08SAvi Kivity MemoryRegion ram_memories[], 679*a0258e4aSIgor Mammedov hwaddr ram_bases[], hwaddr ram_sizes[], 6807d8ccf58SBALATON Zoltan const ram_addr_t sdram_bank_sizes[]) 681b7da58fdSaurel32 { 682e206ad48SHu Tao MemoryRegion *ram = g_malloc0(sizeof(*ram)); 683c227f099SAnthony Liguori ram_addr_t size_left = ram_size; 684b6dcbe08SAvi Kivity ram_addr_t base = 0; 6857d8ccf58SBALATON Zoltan ram_addr_t bank_size; 686*a0258e4aSIgor Mammedov int last_bank = 0; 687b7da58fdSaurel32 int i; 688b7da58fdSaurel32 int j; 689b7da58fdSaurel32 690b7da58fdSaurel32 for (i = 0; i < nr_banks; i++) { 691b7da58fdSaurel32 for (j = 0; sdram_bank_sizes[j] != 0; j++) { 692e206ad48SHu Tao bank_size = sdram_bank_sizes[j]; 6935c130f65Spbrook if (bank_size <= size_left) { 694*a0258e4aSIgor Mammedov ram_bases[i] = base; 695*a0258e4aSIgor Mammedov ram_sizes[i] = bank_size; 696*a0258e4aSIgor Mammedov base += bank_size; 6975c130f65Spbrook size_left -= bank_size; 698*a0258e4aSIgor Mammedov last_bank = i; 699*a0258e4aSIgor Mammedov break; 700b7da58fdSaurel32 } 701b7da58fdSaurel32 } 7025c130f65Spbrook if (!size_left) { 703b7da58fdSaurel32 /* No need to use the remaining banks. */ 704b7da58fdSaurel32 break; 705b7da58fdSaurel32 } 706b7da58fdSaurel32 } 707b7da58fdSaurel32 708e206ad48SHu Tao if (size_left) { 709*a0258e4aSIgor Mammedov ram_addr_t used_size = ram_size - size_left; 710*a0258e4aSIgor Mammedov GString *s = g_string_new(NULL); 711*a0258e4aSIgor Mammedov 712*a0258e4aSIgor Mammedov for (i = 0; sdram_bank_sizes[i]; i++) { 713*a0258e4aSIgor Mammedov g_string_append_printf(s, "%" PRIi64 "%s", 714*a0258e4aSIgor Mammedov sdram_bank_sizes[i] / MiB, 715*a0258e4aSIgor Mammedov sdram_bank_sizes[i + 1] ? " ," : ""); 716*a0258e4aSIgor Mammedov } 717*a0258e4aSIgor Mammedov error_report("Max %d banks of %s MB DIMM/bank supported", 718*a0258e4aSIgor Mammedov nr_banks, s->str); 719*a0258e4aSIgor Mammedov error_report("Possible valid RAM size: %" PRIi64, 720*a0258e4aSIgor Mammedov used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB); 721*a0258e4aSIgor Mammedov 722*a0258e4aSIgor Mammedov g_string_free(s, true); 723*a0258e4aSIgor Mammedov exit(EXIT_FAILURE); 724e206ad48SHu Tao } 725e206ad48SHu Tao 726e206ad48SHu Tao memory_region_allocate_system_memory(ram, NULL, "ppc4xx.sdram", ram_size); 727e206ad48SHu Tao 728*a0258e4aSIgor Mammedov for (i = 0; i <= last_bank; i++) { 729e206ad48SHu Tao char name[32]; 730e206ad48SHu Tao snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); 731e206ad48SHu Tao memory_region_init_alias(&ram_memories[i], NULL, name, ram, 732*a0258e4aSIgor Mammedov ram_bases[i], ram_sizes[i]); 733e206ad48SHu Tao } 734e206ad48SHu Tao } 735517284a7SBALATON Zoltan 736517284a7SBALATON Zoltan /*****************************************************************************/ 737517284a7SBALATON Zoltan /* MAL */ 73804534280SBALATON Zoltan 739517284a7SBALATON Zoltan enum { 740517284a7SBALATON Zoltan MAL0_CFG = 0x180, 741517284a7SBALATON Zoltan MAL0_ESR = 0x181, 742517284a7SBALATON Zoltan MAL0_IER = 0x182, 743517284a7SBALATON Zoltan MAL0_TXCASR = 0x184, 744517284a7SBALATON Zoltan MAL0_TXCARR = 0x185, 745517284a7SBALATON Zoltan MAL0_TXEOBISR = 0x186, 746517284a7SBALATON Zoltan MAL0_TXDEIR = 0x187, 747517284a7SBALATON Zoltan MAL0_RXCASR = 0x190, 748517284a7SBALATON Zoltan MAL0_RXCARR = 0x191, 749517284a7SBALATON Zoltan MAL0_RXEOBISR = 0x192, 750517284a7SBALATON Zoltan MAL0_RXDEIR = 0x193, 751517284a7SBALATON Zoltan MAL0_TXCTP0R = 0x1A0, 752517284a7SBALATON Zoltan MAL0_RXCTP0R = 0x1C0, 753517284a7SBALATON Zoltan MAL0_RCBS0 = 0x1E0, 754517284a7SBALATON Zoltan MAL0_RCBS1 = 0x1E1, 755517284a7SBALATON Zoltan }; 756517284a7SBALATON Zoltan 75704534280SBALATON Zoltan typedef struct ppc4xx_mal_t ppc4xx_mal_t; 75804534280SBALATON Zoltan struct ppc4xx_mal_t { 759517284a7SBALATON Zoltan qemu_irq irqs[4]; 760517284a7SBALATON Zoltan uint32_t cfg; 761517284a7SBALATON Zoltan uint32_t esr; 762517284a7SBALATON Zoltan uint32_t ier; 763517284a7SBALATON Zoltan uint32_t txcasr; 764517284a7SBALATON Zoltan uint32_t txcarr; 765517284a7SBALATON Zoltan uint32_t txeobisr; 766517284a7SBALATON Zoltan uint32_t txdeir; 767517284a7SBALATON Zoltan uint32_t rxcasr; 768517284a7SBALATON Zoltan uint32_t rxcarr; 769517284a7SBALATON Zoltan uint32_t rxeobisr; 770517284a7SBALATON Zoltan uint32_t rxdeir; 77104534280SBALATON Zoltan uint32_t *txctpr; 77204534280SBALATON Zoltan uint32_t *rxctpr; 77304534280SBALATON Zoltan uint32_t *rcbs; 77404534280SBALATON Zoltan uint8_t txcnum; 77504534280SBALATON Zoltan uint8_t rxcnum; 776517284a7SBALATON Zoltan }; 777517284a7SBALATON Zoltan 77804534280SBALATON Zoltan static void ppc4xx_mal_reset(void *opaque) 77904534280SBALATON Zoltan { 78004534280SBALATON Zoltan ppc4xx_mal_t *mal; 78104534280SBALATON Zoltan 78204534280SBALATON Zoltan mal = opaque; 78304534280SBALATON Zoltan mal->cfg = 0x0007C000; 78404534280SBALATON Zoltan mal->esr = 0x00000000; 78504534280SBALATON Zoltan mal->ier = 0x00000000; 78604534280SBALATON Zoltan mal->rxcasr = 0x00000000; 78704534280SBALATON Zoltan mal->rxdeir = 0x00000000; 78804534280SBALATON Zoltan mal->rxeobisr = 0x00000000; 78904534280SBALATON Zoltan mal->txcasr = 0x00000000; 79004534280SBALATON Zoltan mal->txdeir = 0x00000000; 79104534280SBALATON Zoltan mal->txeobisr = 0x00000000; 79204534280SBALATON Zoltan } 793517284a7SBALATON Zoltan 794517284a7SBALATON Zoltan static uint32_t dcr_read_mal(void *opaque, int dcrn) 795517284a7SBALATON Zoltan { 79604534280SBALATON Zoltan ppc4xx_mal_t *mal; 797517284a7SBALATON Zoltan uint32_t ret; 798517284a7SBALATON Zoltan 799517284a7SBALATON Zoltan mal = opaque; 800517284a7SBALATON Zoltan switch (dcrn) { 801517284a7SBALATON Zoltan case MAL0_CFG: 802517284a7SBALATON Zoltan ret = mal->cfg; 803517284a7SBALATON Zoltan break; 804517284a7SBALATON Zoltan case MAL0_ESR: 805517284a7SBALATON Zoltan ret = mal->esr; 806517284a7SBALATON Zoltan break; 807517284a7SBALATON Zoltan case MAL0_IER: 808517284a7SBALATON Zoltan ret = mal->ier; 809517284a7SBALATON Zoltan break; 810517284a7SBALATON Zoltan case MAL0_TXCASR: 811517284a7SBALATON Zoltan ret = mal->txcasr; 812517284a7SBALATON Zoltan break; 813517284a7SBALATON Zoltan case MAL0_TXCARR: 814517284a7SBALATON Zoltan ret = mal->txcarr; 815517284a7SBALATON Zoltan break; 816517284a7SBALATON Zoltan case MAL0_TXEOBISR: 817517284a7SBALATON Zoltan ret = mal->txeobisr; 818517284a7SBALATON Zoltan break; 819517284a7SBALATON Zoltan case MAL0_TXDEIR: 820517284a7SBALATON Zoltan ret = mal->txdeir; 821517284a7SBALATON Zoltan break; 822517284a7SBALATON Zoltan case MAL0_RXCASR: 823517284a7SBALATON Zoltan ret = mal->rxcasr; 824517284a7SBALATON Zoltan break; 825517284a7SBALATON Zoltan case MAL0_RXCARR: 826517284a7SBALATON Zoltan ret = mal->rxcarr; 827517284a7SBALATON Zoltan break; 828517284a7SBALATON Zoltan case MAL0_RXEOBISR: 829517284a7SBALATON Zoltan ret = mal->rxeobisr; 830517284a7SBALATON Zoltan break; 831517284a7SBALATON Zoltan case MAL0_RXDEIR: 832517284a7SBALATON Zoltan ret = mal->rxdeir; 833517284a7SBALATON Zoltan break; 834517284a7SBALATON Zoltan default: 835517284a7SBALATON Zoltan ret = 0; 836517284a7SBALATON Zoltan break; 837517284a7SBALATON Zoltan } 83804534280SBALATON Zoltan if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { 83904534280SBALATON Zoltan ret = mal->txctpr[dcrn - MAL0_TXCTP0R]; 84004534280SBALATON Zoltan } 84104534280SBALATON Zoltan if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { 84204534280SBALATON Zoltan ret = mal->rxctpr[dcrn - MAL0_RXCTP0R]; 84304534280SBALATON Zoltan } 84404534280SBALATON Zoltan if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { 84504534280SBALATON Zoltan ret = mal->rcbs[dcrn - MAL0_RCBS0]; 84604534280SBALATON Zoltan } 847517284a7SBALATON Zoltan 848517284a7SBALATON Zoltan return ret; 849517284a7SBALATON Zoltan } 850517284a7SBALATON Zoltan 851517284a7SBALATON Zoltan static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) 852517284a7SBALATON Zoltan { 85304534280SBALATON Zoltan ppc4xx_mal_t *mal; 854517284a7SBALATON Zoltan 855517284a7SBALATON Zoltan mal = opaque; 856517284a7SBALATON Zoltan switch (dcrn) { 857517284a7SBALATON Zoltan case MAL0_CFG: 858517284a7SBALATON Zoltan if (val & 0x80000000) { 85904534280SBALATON Zoltan ppc4xx_mal_reset(mal); 860517284a7SBALATON Zoltan } 861517284a7SBALATON Zoltan mal->cfg = val & 0x00FFC087; 862517284a7SBALATON Zoltan break; 863517284a7SBALATON Zoltan case MAL0_ESR: 864517284a7SBALATON Zoltan /* Read/clear */ 865517284a7SBALATON Zoltan mal->esr &= ~val; 866517284a7SBALATON Zoltan break; 867517284a7SBALATON Zoltan case MAL0_IER: 868517284a7SBALATON Zoltan mal->ier = val & 0x0000001F; 869517284a7SBALATON Zoltan break; 870517284a7SBALATON Zoltan case MAL0_TXCASR: 871517284a7SBALATON Zoltan mal->txcasr = val & 0xF0000000; 872517284a7SBALATON Zoltan break; 873517284a7SBALATON Zoltan case MAL0_TXCARR: 874517284a7SBALATON Zoltan mal->txcarr = val & 0xF0000000; 875517284a7SBALATON Zoltan break; 876517284a7SBALATON Zoltan case MAL0_TXEOBISR: 877517284a7SBALATON Zoltan /* Read/clear */ 878517284a7SBALATON Zoltan mal->txeobisr &= ~val; 879517284a7SBALATON Zoltan break; 880517284a7SBALATON Zoltan case MAL0_TXDEIR: 881517284a7SBALATON Zoltan /* Read/clear */ 882517284a7SBALATON Zoltan mal->txdeir &= ~val; 883517284a7SBALATON Zoltan break; 884517284a7SBALATON Zoltan case MAL0_RXCASR: 885517284a7SBALATON Zoltan mal->rxcasr = val & 0xC0000000; 886517284a7SBALATON Zoltan break; 887517284a7SBALATON Zoltan case MAL0_RXCARR: 888517284a7SBALATON Zoltan mal->rxcarr = val & 0xC0000000; 889517284a7SBALATON Zoltan break; 890517284a7SBALATON Zoltan case MAL0_RXEOBISR: 891517284a7SBALATON Zoltan /* Read/clear */ 892517284a7SBALATON Zoltan mal->rxeobisr &= ~val; 893517284a7SBALATON Zoltan break; 894517284a7SBALATON Zoltan case MAL0_RXDEIR: 895517284a7SBALATON Zoltan /* Read/clear */ 896517284a7SBALATON Zoltan mal->rxdeir &= ~val; 897517284a7SBALATON Zoltan break; 89804534280SBALATON Zoltan } 89904534280SBALATON Zoltan if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { 90004534280SBALATON Zoltan mal->txctpr[dcrn - MAL0_TXCTP0R] = val; 90104534280SBALATON Zoltan } 90204534280SBALATON Zoltan if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { 90304534280SBALATON Zoltan mal->rxctpr[dcrn - MAL0_RXCTP0R] = val; 90404534280SBALATON Zoltan } 90504534280SBALATON Zoltan if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { 90604534280SBALATON Zoltan mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF; 907517284a7SBALATON Zoltan } 908517284a7SBALATON Zoltan } 909517284a7SBALATON Zoltan 91004534280SBALATON Zoltan void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, 91104534280SBALATON Zoltan qemu_irq irqs[4]) 912517284a7SBALATON Zoltan { 91304534280SBALATON Zoltan ppc4xx_mal_t *mal; 914517284a7SBALATON Zoltan int i; 915517284a7SBALATON Zoltan 91604534280SBALATON Zoltan assert(txcnum <= 32 && rxcnum <= 32); 91704534280SBALATON Zoltan mal = g_malloc0(sizeof(*mal)); 91804534280SBALATON Zoltan mal->txcnum = txcnum; 91904534280SBALATON Zoltan mal->rxcnum = rxcnum; 92004534280SBALATON Zoltan mal->txctpr = g_new0(uint32_t, txcnum); 92104534280SBALATON Zoltan mal->rxctpr = g_new0(uint32_t, rxcnum); 92204534280SBALATON Zoltan mal->rcbs = g_new0(uint32_t, rxcnum); 923517284a7SBALATON Zoltan for (i = 0; i < 4; i++) { 924517284a7SBALATON Zoltan mal->irqs[i] = irqs[i]; 925517284a7SBALATON Zoltan } 92604534280SBALATON Zoltan qemu_register_reset(&ppc4xx_mal_reset, mal); 927517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_CFG, 928517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 929517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_ESR, 930517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 931517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_IER, 932517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 933517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCASR, 934517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 935517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCARR, 936517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 937517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXEOBISR, 938517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 939517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXDEIR, 940517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 941517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCASR, 942517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 943517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCARR, 944517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 945517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXEOBISR, 946517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 947517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXDEIR, 948517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 94904534280SBALATON Zoltan for (i = 0; i < txcnum; i++) { 95004534280SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCTP0R + i, 951517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 95204534280SBALATON Zoltan } 95304534280SBALATON Zoltan for (i = 0; i < rxcnum; i++) { 95404534280SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCTP0R + i, 955517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 95604534280SBALATON Zoltan } 95704534280SBALATON Zoltan for (i = 0; i < rxcnum; i++) { 95804534280SBALATON Zoltan ppc_dcr_register(env, MAL0_RCBS0 + i, 959517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 96004534280SBALATON Zoltan } 961517284a7SBALATON Zoltan } 962