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" 25*ab3dd749SPhilippe 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" 33*ab3dd749SPhilippe Mathieu-Daudé #include "qemu/error-report.h" 34008ff9d7Sj_mayer 35008ff9d7Sj_mayer #define DEBUG_UIC 36008ff9d7Sj_mayer 37d12d51d5Saliguori 38d12d51d5Saliguori #ifdef DEBUG_UIC 3993fcfe39Saliguori # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) 40d12d51d5Saliguori #else 41d12d51d5Saliguori # define LOG_UIC(...) do { } while (0) 42d12d51d5Saliguori #endif 43d12d51d5Saliguori 441bba0dc9SAndreas Färber static void ppc4xx_reset(void *opaque) 451bba0dc9SAndreas Färber { 4690cb09d9SAndreas Färber PowerPCCPU *cpu = opaque; 471bba0dc9SAndreas Färber 4890cb09d9SAndreas Färber cpu_reset(CPU(cpu)); 491bba0dc9SAndreas Färber } 501bba0dc9SAndreas Färber 51008ff9d7Sj_mayer /*****************************************************************************/ 5260b14d95SStefan Weil /* Generic PowerPC 4xx processor instantiation */ 539391b8c5SIgor Mammedov PowerPCCPU *ppc4xx_init(const char *cpu_type, 54c227f099SAnthony Liguori clk_setup_t *cpu_clk, clk_setup_t *tb_clk, 55008ff9d7Sj_mayer uint32_t sysclk) 56008ff9d7Sj_mayer { 5757274713SAndreas Färber PowerPCCPU *cpu; 58e2684c0bSAndreas Färber CPUPPCState *env; 59008ff9d7Sj_mayer 60008ff9d7Sj_mayer /* init CPUs */ 619391b8c5SIgor Mammedov cpu = POWERPC_CPU(cpu_create(cpu_type)); 6257274713SAndreas Färber env = &cpu->env; 6357274713SAndreas Färber 64008ff9d7Sj_mayer cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ 65008ff9d7Sj_mayer cpu_clk->opaque = env; 66008ff9d7Sj_mayer /* Set time-base frequency to sysclk */ 67ddd1055bSFabien Chouteau tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT); 68008ff9d7Sj_mayer tb_clk->opaque = env; 69008ff9d7Sj_mayer ppc_dcr_init(env, NULL, NULL); 70008ff9d7Sj_mayer /* Register qemu callbacks */ 7190cb09d9SAndreas Färber qemu_register_reset(ppc4xx_reset, cpu); 72008ff9d7Sj_mayer 732f9859fbSAndreas Färber return cpu; 74008ff9d7Sj_mayer } 75008ff9d7Sj_mayer 76008ff9d7Sj_mayer /*****************************************************************************/ 77008ff9d7Sj_mayer /* "Universal" Interrupt controller */ 78008ff9d7Sj_mayer enum { 79008ff9d7Sj_mayer DCR_UICSR = 0x000, 80008ff9d7Sj_mayer DCR_UICSRS = 0x001, 81008ff9d7Sj_mayer DCR_UICER = 0x002, 82008ff9d7Sj_mayer DCR_UICCR = 0x003, 83008ff9d7Sj_mayer DCR_UICPR = 0x004, 84008ff9d7Sj_mayer DCR_UICTR = 0x005, 85008ff9d7Sj_mayer DCR_UICMSR = 0x006, 86008ff9d7Sj_mayer DCR_UICVR = 0x007, 87008ff9d7Sj_mayer DCR_UICVCR = 0x008, 88008ff9d7Sj_mayer DCR_UICMAX = 0x009, 89008ff9d7Sj_mayer }; 90008ff9d7Sj_mayer 91008ff9d7Sj_mayer #define UIC_MAX_IRQ 32 92c227f099SAnthony Liguori typedef struct ppcuic_t ppcuic_t; 93c227f099SAnthony Liguori struct ppcuic_t { 94008ff9d7Sj_mayer uint32_t dcr_base; 95008ff9d7Sj_mayer int use_vectors; 964c54e875Saurel32 uint32_t level; /* Remembers the state of level-triggered interrupts. */ 97008ff9d7Sj_mayer uint32_t uicsr; /* Status register */ 98008ff9d7Sj_mayer uint32_t uicer; /* Enable register */ 99008ff9d7Sj_mayer uint32_t uiccr; /* Critical register */ 100008ff9d7Sj_mayer uint32_t uicpr; /* Polarity register */ 101008ff9d7Sj_mayer uint32_t uictr; /* Triggering register */ 102008ff9d7Sj_mayer uint32_t uicvcr; /* Vector configuration register */ 103008ff9d7Sj_mayer uint32_t uicvr; 104008ff9d7Sj_mayer qemu_irq *irqs; 105008ff9d7Sj_mayer }; 106008ff9d7Sj_mayer 107c227f099SAnthony Liguori static void ppcuic_trigger_irq (ppcuic_t *uic) 108008ff9d7Sj_mayer { 109008ff9d7Sj_mayer uint32_t ir, cr; 110008ff9d7Sj_mayer int start, end, inc, i; 111008ff9d7Sj_mayer 112008ff9d7Sj_mayer /* Trigger interrupt if any is pending */ 113008ff9d7Sj_mayer ir = uic->uicsr & uic->uicer & (~uic->uiccr); 114008ff9d7Sj_mayer cr = uic->uicsr & uic->uicer & uic->uiccr; 115d12d51d5Saliguori LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32 116aae9366aSj_mayer " uiccr %08" PRIx32 "\n" 117aae9366aSj_mayer " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", 118aae9366aSj_mayer __func__, uic->uicsr, uic->uicer, uic->uiccr, 119008ff9d7Sj_mayer uic->uicsr & uic->uicer, ir, cr); 120008ff9d7Sj_mayer if (ir != 0x0000000) { 121d12d51d5Saliguori LOG_UIC("Raise UIC interrupt\n"); 122008ff9d7Sj_mayer qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); 123008ff9d7Sj_mayer } else { 124d12d51d5Saliguori LOG_UIC("Lower UIC interrupt\n"); 125008ff9d7Sj_mayer qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); 126008ff9d7Sj_mayer } 127008ff9d7Sj_mayer /* Trigger critical interrupt if any is pending and update vector */ 128008ff9d7Sj_mayer if (cr != 0x0000000) { 129008ff9d7Sj_mayer qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); 130008ff9d7Sj_mayer if (uic->use_vectors) { 131008ff9d7Sj_mayer /* Compute critical IRQ vector */ 132008ff9d7Sj_mayer if (uic->uicvcr & 1) { 133008ff9d7Sj_mayer start = 31; 134008ff9d7Sj_mayer end = 0; 135008ff9d7Sj_mayer inc = -1; 136008ff9d7Sj_mayer } else { 137008ff9d7Sj_mayer start = 0; 138008ff9d7Sj_mayer end = 31; 139008ff9d7Sj_mayer inc = 1; 140008ff9d7Sj_mayer } 141008ff9d7Sj_mayer uic->uicvr = uic->uicvcr & 0xFFFFFFFC; 142008ff9d7Sj_mayer for (i = start; i <= end; i += inc) { 143008ff9d7Sj_mayer if (cr & (1 << i)) { 144008ff9d7Sj_mayer uic->uicvr += (i - start) * 512 * inc; 145008ff9d7Sj_mayer break; 146008ff9d7Sj_mayer } 147008ff9d7Sj_mayer } 148008ff9d7Sj_mayer } 149d12d51d5Saliguori LOG_UIC("Raise UIC critical interrupt - " 150aae9366aSj_mayer "vector %08" PRIx32 "\n", uic->uicvr); 151008ff9d7Sj_mayer } else { 152d12d51d5Saliguori LOG_UIC("Lower UIC critical interrupt\n"); 153008ff9d7Sj_mayer qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); 154008ff9d7Sj_mayer uic->uicvr = 0x00000000; 155008ff9d7Sj_mayer } 156008ff9d7Sj_mayer } 157008ff9d7Sj_mayer 158008ff9d7Sj_mayer static void ppcuic_set_irq (void *opaque, int irq_num, int level) 159008ff9d7Sj_mayer { 160c227f099SAnthony Liguori ppcuic_t *uic; 161008ff9d7Sj_mayer uint32_t mask, sr; 162008ff9d7Sj_mayer 163008ff9d7Sj_mayer uic = opaque; 164a1f7f97bSPeter Maydell mask = 1U << (31-irq_num); 165d12d51d5Saliguori LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32 166aae9366aSj_mayer " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", 167aae9366aSj_mayer __func__, irq_num, level, 168008ff9d7Sj_mayer uic->uicsr, mask, uic->uicsr & mask, level << irq_num); 169008ff9d7Sj_mayer if (irq_num < 0 || irq_num > 31) 170008ff9d7Sj_mayer return; 171008ff9d7Sj_mayer sr = uic->uicsr; 17250bf72b3Saurel32 173008ff9d7Sj_mayer /* Update status register */ 174008ff9d7Sj_mayer if (uic->uictr & mask) { 175008ff9d7Sj_mayer /* Edge sensitive interrupt */ 176008ff9d7Sj_mayer if (level == 1) 177008ff9d7Sj_mayer uic->uicsr |= mask; 178008ff9d7Sj_mayer } else { 179008ff9d7Sj_mayer /* Level sensitive interrupt */ 1804c54e875Saurel32 if (level == 1) { 181008ff9d7Sj_mayer uic->uicsr |= mask; 1824c54e875Saurel32 uic->level |= mask; 1834c54e875Saurel32 } else { 184008ff9d7Sj_mayer uic->uicsr &= ~mask; 1854c54e875Saurel32 uic->level &= ~mask; 1864c54e875Saurel32 } 187008ff9d7Sj_mayer } 188d12d51d5Saliguori LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => " 189aae9366aSj_mayer "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); 190008ff9d7Sj_mayer if (sr != uic->uicsr) 191008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 192008ff9d7Sj_mayer } 193008ff9d7Sj_mayer 19473b01960SAlexander Graf static uint32_t dcr_read_uic (void *opaque, int dcrn) 195008ff9d7Sj_mayer { 196c227f099SAnthony Liguori ppcuic_t *uic; 19773b01960SAlexander Graf uint32_t ret; 198008ff9d7Sj_mayer 199008ff9d7Sj_mayer uic = opaque; 200008ff9d7Sj_mayer dcrn -= uic->dcr_base; 201008ff9d7Sj_mayer switch (dcrn) { 202008ff9d7Sj_mayer case DCR_UICSR: 203008ff9d7Sj_mayer case DCR_UICSRS: 204008ff9d7Sj_mayer ret = uic->uicsr; 205008ff9d7Sj_mayer break; 206008ff9d7Sj_mayer case DCR_UICER: 207008ff9d7Sj_mayer ret = uic->uicer; 208008ff9d7Sj_mayer break; 209008ff9d7Sj_mayer case DCR_UICCR: 210008ff9d7Sj_mayer ret = uic->uiccr; 211008ff9d7Sj_mayer break; 212008ff9d7Sj_mayer case DCR_UICPR: 213008ff9d7Sj_mayer ret = uic->uicpr; 214008ff9d7Sj_mayer break; 215008ff9d7Sj_mayer case DCR_UICTR: 216008ff9d7Sj_mayer ret = uic->uictr; 217008ff9d7Sj_mayer break; 218008ff9d7Sj_mayer case DCR_UICMSR: 219008ff9d7Sj_mayer ret = uic->uicsr & uic->uicer; 220008ff9d7Sj_mayer break; 221008ff9d7Sj_mayer case DCR_UICVR: 222008ff9d7Sj_mayer if (!uic->use_vectors) 223008ff9d7Sj_mayer goto no_read; 224008ff9d7Sj_mayer ret = uic->uicvr; 225008ff9d7Sj_mayer break; 226008ff9d7Sj_mayer case DCR_UICVCR: 227008ff9d7Sj_mayer if (!uic->use_vectors) 228008ff9d7Sj_mayer goto no_read; 229008ff9d7Sj_mayer ret = uic->uicvcr; 230008ff9d7Sj_mayer break; 231008ff9d7Sj_mayer default: 232008ff9d7Sj_mayer no_read: 233008ff9d7Sj_mayer ret = 0x00000000; 234008ff9d7Sj_mayer break; 235008ff9d7Sj_mayer } 236008ff9d7Sj_mayer 237008ff9d7Sj_mayer return ret; 238008ff9d7Sj_mayer } 239008ff9d7Sj_mayer 24073b01960SAlexander Graf static void dcr_write_uic (void *opaque, int dcrn, uint32_t val) 241008ff9d7Sj_mayer { 242c227f099SAnthony Liguori ppcuic_t *uic; 243008ff9d7Sj_mayer 244008ff9d7Sj_mayer uic = opaque; 245008ff9d7Sj_mayer dcrn -= uic->dcr_base; 24673b01960SAlexander Graf LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val); 247008ff9d7Sj_mayer switch (dcrn) { 248008ff9d7Sj_mayer case DCR_UICSR: 249008ff9d7Sj_mayer uic->uicsr &= ~val; 2504c54e875Saurel32 uic->uicsr |= uic->level; 251008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 252008ff9d7Sj_mayer break; 253008ff9d7Sj_mayer case DCR_UICSRS: 254008ff9d7Sj_mayer uic->uicsr |= val; 255008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 256008ff9d7Sj_mayer break; 257008ff9d7Sj_mayer case DCR_UICER: 258008ff9d7Sj_mayer uic->uicer = val; 259008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 260008ff9d7Sj_mayer break; 261008ff9d7Sj_mayer case DCR_UICCR: 262008ff9d7Sj_mayer uic->uiccr = val; 263008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 264008ff9d7Sj_mayer break; 265008ff9d7Sj_mayer case DCR_UICPR: 266008ff9d7Sj_mayer uic->uicpr = val; 267008ff9d7Sj_mayer break; 268008ff9d7Sj_mayer case DCR_UICTR: 269008ff9d7Sj_mayer uic->uictr = val; 270008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 271008ff9d7Sj_mayer break; 272008ff9d7Sj_mayer case DCR_UICMSR: 273008ff9d7Sj_mayer break; 274008ff9d7Sj_mayer case DCR_UICVR: 275008ff9d7Sj_mayer break; 276008ff9d7Sj_mayer case DCR_UICVCR: 277008ff9d7Sj_mayer uic->uicvcr = val & 0xFFFFFFFD; 278008ff9d7Sj_mayer ppcuic_trigger_irq(uic); 279008ff9d7Sj_mayer break; 280008ff9d7Sj_mayer } 281008ff9d7Sj_mayer } 282008ff9d7Sj_mayer 283008ff9d7Sj_mayer static void ppcuic_reset (void *opaque) 284008ff9d7Sj_mayer { 285c227f099SAnthony Liguori ppcuic_t *uic; 286008ff9d7Sj_mayer 287008ff9d7Sj_mayer uic = opaque; 288008ff9d7Sj_mayer uic->uiccr = 0x00000000; 289008ff9d7Sj_mayer uic->uicer = 0x00000000; 290008ff9d7Sj_mayer uic->uicpr = 0x00000000; 291008ff9d7Sj_mayer uic->uicsr = 0x00000000; 292008ff9d7Sj_mayer uic->uictr = 0x00000000; 293008ff9d7Sj_mayer if (uic->use_vectors) { 294008ff9d7Sj_mayer uic->uicvcr = 0x00000000; 295008ff9d7Sj_mayer uic->uicvr = 0x0000000; 296008ff9d7Sj_mayer } 297008ff9d7Sj_mayer } 298008ff9d7Sj_mayer 299e2684c0bSAndreas Färber qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs, 300008ff9d7Sj_mayer uint32_t dcr_base, int has_ssr, int has_vr) 301008ff9d7Sj_mayer { 302c227f099SAnthony Liguori ppcuic_t *uic; 303008ff9d7Sj_mayer int i; 304008ff9d7Sj_mayer 3057267c094SAnthony Liguori uic = g_malloc0(sizeof(ppcuic_t)); 306008ff9d7Sj_mayer uic->dcr_base = dcr_base; 307008ff9d7Sj_mayer uic->irqs = irqs; 308008ff9d7Sj_mayer if (has_vr) 309008ff9d7Sj_mayer uic->use_vectors = 1; 310008ff9d7Sj_mayer for (i = 0; i < DCR_UICMAX; i++) { 311008ff9d7Sj_mayer ppc_dcr_register(env, dcr_base + i, uic, 312008ff9d7Sj_mayer &dcr_read_uic, &dcr_write_uic); 313008ff9d7Sj_mayer } 314a08d4367SJan Kiszka qemu_register_reset(ppcuic_reset, uic); 315008ff9d7Sj_mayer 316008ff9d7Sj_mayer return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); 317008ff9d7Sj_mayer } 31861b24405Saurel32 31961b24405Saurel32 /*****************************************************************************/ 32061b24405Saurel32 /* SDRAM controller */ 321c227f099SAnthony Liguori typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; 322c227f099SAnthony Liguori struct ppc4xx_sdram_t { 32361b24405Saurel32 uint32_t addr; 32461b24405Saurel32 int nbanks; 325b6dcbe08SAvi Kivity MemoryRegion containers[4]; /* used for clipping */ 326b6dcbe08SAvi Kivity MemoryRegion *ram_memories; 327a8170e5eSAvi Kivity hwaddr ram_bases[4]; 328a8170e5eSAvi Kivity hwaddr ram_sizes[4]; 32961b24405Saurel32 uint32_t besr0; 33061b24405Saurel32 uint32_t besr1; 33161b24405Saurel32 uint32_t bear; 33261b24405Saurel32 uint32_t cfg; 33361b24405Saurel32 uint32_t status; 33461b24405Saurel32 uint32_t rtr; 33561b24405Saurel32 uint32_t pmit; 33661b24405Saurel32 uint32_t bcr[4]; 33761b24405Saurel32 uint32_t tr; 33861b24405Saurel32 uint32_t ecccfg; 33961b24405Saurel32 uint32_t eccesr; 34061b24405Saurel32 qemu_irq irq; 34161b24405Saurel32 }; 34261b24405Saurel32 34361b24405Saurel32 enum { 34461b24405Saurel32 SDRAM0_CFGADDR = 0x010, 34561b24405Saurel32 SDRAM0_CFGDATA = 0x011, 34661b24405Saurel32 }; 34761b24405Saurel32 34861b24405Saurel32 /* XXX: TOFIX: some patches have made this code become inconsistent: 349a8170e5eSAvi Kivity * there are type inconsistencies, mixing hwaddr, target_ulong 35061b24405Saurel32 * and uint32_t 35161b24405Saurel32 */ 352a8170e5eSAvi Kivity static uint32_t sdram_bcr (hwaddr ram_base, 353a8170e5eSAvi Kivity hwaddr ram_size) 35461b24405Saurel32 { 35561b24405Saurel32 uint32_t bcr; 35661b24405Saurel32 35761b24405Saurel32 switch (ram_size) { 358*ab3dd749SPhilippe Mathieu-Daudé case 4 * MiB: 35961b24405Saurel32 bcr = 0x00000000; 36061b24405Saurel32 break; 361*ab3dd749SPhilippe Mathieu-Daudé case 8 * MiB: 36261b24405Saurel32 bcr = 0x00020000; 36361b24405Saurel32 break; 364*ab3dd749SPhilippe Mathieu-Daudé case 16 * MiB: 36561b24405Saurel32 bcr = 0x00040000; 36661b24405Saurel32 break; 367*ab3dd749SPhilippe Mathieu-Daudé case 32 * MiB: 36861b24405Saurel32 bcr = 0x00060000; 36961b24405Saurel32 break; 370*ab3dd749SPhilippe Mathieu-Daudé case 64 * MiB: 37161b24405Saurel32 bcr = 0x00080000; 37261b24405Saurel32 break; 373*ab3dd749SPhilippe Mathieu-Daudé case 128 * MiB: 37461b24405Saurel32 bcr = 0x000A0000; 37561b24405Saurel32 break; 376*ab3dd749SPhilippe Mathieu-Daudé case 256 * MiB: 37761b24405Saurel32 bcr = 0x000C0000; 37861b24405Saurel32 break; 37961b24405Saurel32 default: 38090e189ecSBlue Swirl printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__, 38190e189ecSBlue Swirl ram_size); 38261b24405Saurel32 return 0x00000000; 38361b24405Saurel32 } 38461b24405Saurel32 bcr |= ram_base & 0xFF800000; 38561b24405Saurel32 bcr |= 1; 38661b24405Saurel32 38761b24405Saurel32 return bcr; 38861b24405Saurel32 } 38961b24405Saurel32 390a8170e5eSAvi Kivity static inline hwaddr sdram_base(uint32_t bcr) 39161b24405Saurel32 { 39261b24405Saurel32 return bcr & 0xFF800000; 39361b24405Saurel32 } 39461b24405Saurel32 39561b24405Saurel32 static target_ulong sdram_size (uint32_t bcr) 39661b24405Saurel32 { 39761b24405Saurel32 target_ulong size; 39861b24405Saurel32 int sh; 39961b24405Saurel32 40061b24405Saurel32 sh = (bcr >> 17) & 0x7; 40161b24405Saurel32 if (sh == 7) 40261b24405Saurel32 size = -1; 40361b24405Saurel32 else 404*ab3dd749SPhilippe Mathieu-Daudé size = (4 * MiB) << sh; 40561b24405Saurel32 40661b24405Saurel32 return size; 40761b24405Saurel32 } 40861b24405Saurel32 409b6dcbe08SAvi Kivity static void sdram_set_bcr(ppc4xx_sdram_t *sdram, 410b6dcbe08SAvi Kivity uint32_t *bcrp, uint32_t bcr, int enabled) 41161b24405Saurel32 { 412b6dcbe08SAvi Kivity unsigned n = bcrp - sdram->bcr; 413b6dcbe08SAvi Kivity 41461b24405Saurel32 if (*bcrp & 0x00000001) { 41561b24405Saurel32 /* Unmap RAM */ 41661b24405Saurel32 #ifdef DEBUG_SDRAM 41790e189ecSBlue Swirl printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", 41861b24405Saurel32 __func__, sdram_base(*bcrp), sdram_size(*bcrp)); 41961b24405Saurel32 #endif 420b6dcbe08SAvi Kivity memory_region_del_subregion(get_system_memory(), 421b6dcbe08SAvi Kivity &sdram->containers[n]); 422b6dcbe08SAvi Kivity memory_region_del_subregion(&sdram->containers[n], 423b6dcbe08SAvi Kivity &sdram->ram_memories[n]); 424d8d95814SPaolo Bonzini object_unparent(OBJECT(&sdram->containers[n])); 42561b24405Saurel32 } 42661b24405Saurel32 *bcrp = bcr & 0xFFDEE001; 42761b24405Saurel32 if (enabled && (bcr & 0x00000001)) { 42861b24405Saurel32 #ifdef DEBUG_SDRAM 42990e189ecSBlue Swirl printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", 43061b24405Saurel32 __func__, sdram_base(bcr), sdram_size(bcr)); 43161b24405Saurel32 #endif 4322c9b15caSPaolo Bonzini memory_region_init(&sdram->containers[n], NULL, "sdram-containers", 433b6dcbe08SAvi Kivity sdram_size(bcr)); 434b6dcbe08SAvi Kivity memory_region_add_subregion(&sdram->containers[n], 0, 435b6dcbe08SAvi Kivity &sdram->ram_memories[n]); 436b6dcbe08SAvi Kivity memory_region_add_subregion(get_system_memory(), 437b6dcbe08SAvi Kivity sdram_base(bcr), 438b6dcbe08SAvi Kivity &sdram->containers[n]); 43961b24405Saurel32 } 44061b24405Saurel32 } 44161b24405Saurel32 442c227f099SAnthony Liguori static void sdram_map_bcr (ppc4xx_sdram_t *sdram) 44361b24405Saurel32 { 44461b24405Saurel32 int i; 44561b24405Saurel32 44661b24405Saurel32 for (i = 0; i < sdram->nbanks; i++) { 44761b24405Saurel32 if (sdram->ram_sizes[i] != 0) { 448b6dcbe08SAvi Kivity sdram_set_bcr(sdram, 449b6dcbe08SAvi Kivity &sdram->bcr[i], 45061b24405Saurel32 sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]), 45161b24405Saurel32 1); 45261b24405Saurel32 } else { 453b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0); 45461b24405Saurel32 } 45561b24405Saurel32 } 45661b24405Saurel32 } 45761b24405Saurel32 458c227f099SAnthony Liguori static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) 45961b24405Saurel32 { 46061b24405Saurel32 int i; 46161b24405Saurel32 46261b24405Saurel32 for (i = 0; i < sdram->nbanks; i++) { 46361b24405Saurel32 #ifdef DEBUG_SDRAM 46490e189ecSBlue Swirl printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", 46561b24405Saurel32 __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); 46661b24405Saurel32 #endif 467b6dcbe08SAvi Kivity memory_region_del_subregion(get_system_memory(), 468b6dcbe08SAvi Kivity &sdram->ram_memories[i]); 46961b24405Saurel32 } 47061b24405Saurel32 } 47161b24405Saurel32 47273b01960SAlexander Graf static uint32_t dcr_read_sdram (void *opaque, int dcrn) 47361b24405Saurel32 { 474c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 47573b01960SAlexander Graf uint32_t ret; 47661b24405Saurel32 47761b24405Saurel32 sdram = opaque; 47861b24405Saurel32 switch (dcrn) { 47961b24405Saurel32 case SDRAM0_CFGADDR: 48061b24405Saurel32 ret = sdram->addr; 48161b24405Saurel32 break; 48261b24405Saurel32 case SDRAM0_CFGDATA: 48361b24405Saurel32 switch (sdram->addr) { 48461b24405Saurel32 case 0x00: /* SDRAM_BESR0 */ 48561b24405Saurel32 ret = sdram->besr0; 48661b24405Saurel32 break; 48761b24405Saurel32 case 0x08: /* SDRAM_BESR1 */ 48861b24405Saurel32 ret = sdram->besr1; 48961b24405Saurel32 break; 49061b24405Saurel32 case 0x10: /* SDRAM_BEAR */ 49161b24405Saurel32 ret = sdram->bear; 49261b24405Saurel32 break; 49361b24405Saurel32 case 0x20: /* SDRAM_CFG */ 49461b24405Saurel32 ret = sdram->cfg; 49561b24405Saurel32 break; 49661b24405Saurel32 case 0x24: /* SDRAM_STATUS */ 49761b24405Saurel32 ret = sdram->status; 49861b24405Saurel32 break; 49961b24405Saurel32 case 0x30: /* SDRAM_RTR */ 50061b24405Saurel32 ret = sdram->rtr; 50161b24405Saurel32 break; 50261b24405Saurel32 case 0x34: /* SDRAM_PMIT */ 50361b24405Saurel32 ret = sdram->pmit; 50461b24405Saurel32 break; 50561b24405Saurel32 case 0x40: /* SDRAM_B0CR */ 50661b24405Saurel32 ret = sdram->bcr[0]; 50761b24405Saurel32 break; 50861b24405Saurel32 case 0x44: /* SDRAM_B1CR */ 50961b24405Saurel32 ret = sdram->bcr[1]; 51061b24405Saurel32 break; 51161b24405Saurel32 case 0x48: /* SDRAM_B2CR */ 51261b24405Saurel32 ret = sdram->bcr[2]; 51361b24405Saurel32 break; 51461b24405Saurel32 case 0x4C: /* SDRAM_B3CR */ 51561b24405Saurel32 ret = sdram->bcr[3]; 51661b24405Saurel32 break; 51761b24405Saurel32 case 0x80: /* SDRAM_TR */ 51861b24405Saurel32 ret = -1; /* ? */ 51961b24405Saurel32 break; 52061b24405Saurel32 case 0x94: /* SDRAM_ECCCFG */ 52161b24405Saurel32 ret = sdram->ecccfg; 52261b24405Saurel32 break; 52361b24405Saurel32 case 0x98: /* SDRAM_ECCESR */ 52461b24405Saurel32 ret = sdram->eccesr; 52561b24405Saurel32 break; 52661b24405Saurel32 default: /* Error */ 52761b24405Saurel32 ret = -1; 52861b24405Saurel32 break; 52961b24405Saurel32 } 53061b24405Saurel32 break; 53161b24405Saurel32 default: 53261b24405Saurel32 /* Avoid gcc warning */ 53361b24405Saurel32 ret = 0x00000000; 53461b24405Saurel32 break; 53561b24405Saurel32 } 53661b24405Saurel32 53761b24405Saurel32 return ret; 53861b24405Saurel32 } 53961b24405Saurel32 54073b01960SAlexander Graf static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) 54161b24405Saurel32 { 542c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 54361b24405Saurel32 54461b24405Saurel32 sdram = opaque; 54561b24405Saurel32 switch (dcrn) { 54661b24405Saurel32 case SDRAM0_CFGADDR: 54761b24405Saurel32 sdram->addr = val; 54861b24405Saurel32 break; 54961b24405Saurel32 case SDRAM0_CFGDATA: 55061b24405Saurel32 switch (sdram->addr) { 55161b24405Saurel32 case 0x00: /* SDRAM_BESR0 */ 55261b24405Saurel32 sdram->besr0 &= ~val; 55361b24405Saurel32 break; 55461b24405Saurel32 case 0x08: /* SDRAM_BESR1 */ 55561b24405Saurel32 sdram->besr1 &= ~val; 55661b24405Saurel32 break; 55761b24405Saurel32 case 0x10: /* SDRAM_BEAR */ 55861b24405Saurel32 sdram->bear = val; 55961b24405Saurel32 break; 56061b24405Saurel32 case 0x20: /* SDRAM_CFG */ 56161b24405Saurel32 val &= 0xFFE00000; 56261b24405Saurel32 if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { 56361b24405Saurel32 #ifdef DEBUG_SDRAM 56461b24405Saurel32 printf("%s: enable SDRAM controller\n", __func__); 56561b24405Saurel32 #endif 56661b24405Saurel32 /* validate all RAM mappings */ 56761b24405Saurel32 sdram_map_bcr(sdram); 56861b24405Saurel32 sdram->status &= ~0x80000000; 56961b24405Saurel32 } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { 57061b24405Saurel32 #ifdef DEBUG_SDRAM 57161b24405Saurel32 printf("%s: disable SDRAM controller\n", __func__); 57261b24405Saurel32 #endif 57361b24405Saurel32 /* invalidate all RAM mappings */ 57461b24405Saurel32 sdram_unmap_bcr(sdram); 57561b24405Saurel32 sdram->status |= 0x80000000; 57661b24405Saurel32 } 57761b24405Saurel32 if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) 57861b24405Saurel32 sdram->status |= 0x40000000; 57961b24405Saurel32 else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) 58061b24405Saurel32 sdram->status &= ~0x40000000; 58161b24405Saurel32 sdram->cfg = val; 58261b24405Saurel32 break; 58361b24405Saurel32 case 0x24: /* SDRAM_STATUS */ 58461b24405Saurel32 /* Read-only register */ 58561b24405Saurel32 break; 58661b24405Saurel32 case 0x30: /* SDRAM_RTR */ 58761b24405Saurel32 sdram->rtr = val & 0x3FF80000; 58861b24405Saurel32 break; 58961b24405Saurel32 case 0x34: /* SDRAM_PMIT */ 59061b24405Saurel32 sdram->pmit = (val & 0xF8000000) | 0x07C00000; 59161b24405Saurel32 break; 59261b24405Saurel32 case 0x40: /* SDRAM_B0CR */ 593b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000); 59461b24405Saurel32 break; 59561b24405Saurel32 case 0x44: /* SDRAM_B1CR */ 596b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000); 59761b24405Saurel32 break; 59861b24405Saurel32 case 0x48: /* SDRAM_B2CR */ 599b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000); 60061b24405Saurel32 break; 60161b24405Saurel32 case 0x4C: /* SDRAM_B3CR */ 602b6dcbe08SAvi Kivity sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000); 60361b24405Saurel32 break; 60461b24405Saurel32 case 0x80: /* SDRAM_TR */ 60561b24405Saurel32 sdram->tr = val & 0x018FC01F; 60661b24405Saurel32 break; 60761b24405Saurel32 case 0x94: /* SDRAM_ECCCFG */ 60861b24405Saurel32 sdram->ecccfg = val & 0x00F00000; 60961b24405Saurel32 break; 61061b24405Saurel32 case 0x98: /* SDRAM_ECCESR */ 61161b24405Saurel32 val &= 0xFFF0F000; 61261b24405Saurel32 if (sdram->eccesr == 0 && val != 0) 61361b24405Saurel32 qemu_irq_raise(sdram->irq); 61461b24405Saurel32 else if (sdram->eccesr != 0 && val == 0) 61561b24405Saurel32 qemu_irq_lower(sdram->irq); 61661b24405Saurel32 sdram->eccesr = val; 61761b24405Saurel32 break; 61861b24405Saurel32 default: /* Error */ 61961b24405Saurel32 break; 62061b24405Saurel32 } 62161b24405Saurel32 break; 62261b24405Saurel32 } 62361b24405Saurel32 } 62461b24405Saurel32 62561b24405Saurel32 static void sdram_reset (void *opaque) 62661b24405Saurel32 { 627c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 62861b24405Saurel32 62961b24405Saurel32 sdram = opaque; 63061b24405Saurel32 sdram->addr = 0x00000000; 63161b24405Saurel32 sdram->bear = 0x00000000; 63261b24405Saurel32 sdram->besr0 = 0x00000000; /* No error */ 63361b24405Saurel32 sdram->besr1 = 0x00000000; /* No error */ 63461b24405Saurel32 sdram->cfg = 0x00000000; 63561b24405Saurel32 sdram->ecccfg = 0x00000000; /* No ECC */ 63661b24405Saurel32 sdram->eccesr = 0x00000000; /* No error */ 63761b24405Saurel32 sdram->pmit = 0x07C00000; 63861b24405Saurel32 sdram->rtr = 0x05F00000; 63961b24405Saurel32 sdram->tr = 0x00854009; 64061b24405Saurel32 /* We pre-initialize RAM banks */ 64161b24405Saurel32 sdram->status = 0x00000000; 64261b24405Saurel32 sdram->cfg = 0x00800000; 64361b24405Saurel32 } 64461b24405Saurel32 645e2684c0bSAndreas Färber void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, 646b6dcbe08SAvi Kivity MemoryRegion *ram_memories, 647a8170e5eSAvi Kivity hwaddr *ram_bases, 648a8170e5eSAvi Kivity hwaddr *ram_sizes, 64961b24405Saurel32 int do_init) 65061b24405Saurel32 { 651c227f099SAnthony Liguori ppc4xx_sdram_t *sdram; 65261b24405Saurel32 6537267c094SAnthony Liguori sdram = g_malloc0(sizeof(ppc4xx_sdram_t)); 65461b24405Saurel32 sdram->irq = irq; 65561b24405Saurel32 sdram->nbanks = nbanks; 656b6dcbe08SAvi Kivity sdram->ram_memories = ram_memories; 657a8170e5eSAvi Kivity memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); 65861b24405Saurel32 memcpy(sdram->ram_bases, ram_bases, 659a8170e5eSAvi Kivity nbanks * sizeof(hwaddr)); 660a8170e5eSAvi Kivity memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); 66161b24405Saurel32 memcpy(sdram->ram_sizes, ram_sizes, 662a8170e5eSAvi Kivity nbanks * sizeof(hwaddr)); 663a08d4367SJan Kiszka qemu_register_reset(&sdram_reset, sdram); 66461b24405Saurel32 ppc_dcr_register(env, SDRAM0_CFGADDR, 66561b24405Saurel32 sdram, &dcr_read_sdram, &dcr_write_sdram); 66661b24405Saurel32 ppc_dcr_register(env, SDRAM0_CFGDATA, 66761b24405Saurel32 sdram, &dcr_read_sdram, &dcr_write_sdram); 66861b24405Saurel32 if (do_init) 66961b24405Saurel32 sdram_map_bcr(sdram); 67061b24405Saurel32 } 671b7da58fdSaurel32 672b7da58fdSaurel32 /* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory. 673b7da58fdSaurel32 * 674b7da58fdSaurel32 * sdram_bank_sizes[] must be 0-terminated. 675b7da58fdSaurel32 * 676b7da58fdSaurel32 * The 4xx SDRAM controller supports a small number of banks, and each bank 677b7da58fdSaurel32 * must be one of a small set of sizes. The number of banks and the supported 678b7da58fdSaurel32 * sizes varies by SoC. */ 679c227f099SAnthony Liguori ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, 680b6dcbe08SAvi Kivity MemoryRegion ram_memories[], 681a8170e5eSAvi Kivity hwaddr ram_bases[], 682a8170e5eSAvi Kivity hwaddr ram_sizes[], 683b7da58fdSaurel32 const unsigned int sdram_bank_sizes[]) 684b7da58fdSaurel32 { 685e206ad48SHu Tao MemoryRegion *ram = g_malloc0(sizeof(*ram)); 686c227f099SAnthony Liguori ram_addr_t size_left = ram_size; 687b6dcbe08SAvi Kivity ram_addr_t base = 0; 688e206ad48SHu Tao unsigned int bank_size; 689b7da58fdSaurel32 int i; 690b7da58fdSaurel32 int j; 691b7da58fdSaurel32 692b7da58fdSaurel32 for (i = 0; i < nr_banks; i++) { 693b7da58fdSaurel32 for (j = 0; sdram_bank_sizes[j] != 0; j++) { 694e206ad48SHu Tao bank_size = sdram_bank_sizes[j]; 6955c130f65Spbrook if (bank_size <= size_left) { 6965c130f65Spbrook size_left -= bank_size; 697b7da58fdSaurel32 } 698b7da58fdSaurel32 } 6995c130f65Spbrook if (!size_left) { 700b7da58fdSaurel32 /* No need to use the remaining banks. */ 701b7da58fdSaurel32 break; 702b7da58fdSaurel32 } 703b7da58fdSaurel32 } 704b7da58fdSaurel32 7055c130f65Spbrook ram_size -= size_left; 706e206ad48SHu Tao if (size_left) { 707*ab3dd749SPhilippe Mathieu-Daudé error_report("Truncating memory to %" PRId64 " MiB to fit SDRAM" 708*ab3dd749SPhilippe Mathieu-Daudé " controller limits", ram_size / MiB); 709e206ad48SHu Tao } 710e206ad48SHu Tao 711e206ad48SHu Tao memory_region_allocate_system_memory(ram, NULL, "ppc4xx.sdram", ram_size); 712e206ad48SHu Tao 713e206ad48SHu Tao size_left = ram_size; 714e206ad48SHu Tao for (i = 0; i < nr_banks && size_left; i++) { 715e206ad48SHu Tao for (j = 0; sdram_bank_sizes[j] != 0; j++) { 716e206ad48SHu Tao bank_size = sdram_bank_sizes[j]; 717e206ad48SHu Tao 718e206ad48SHu Tao if (bank_size <= size_left) { 719e206ad48SHu Tao char name[32]; 720e206ad48SHu Tao snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); 721e206ad48SHu Tao memory_region_init_alias(&ram_memories[i], NULL, name, ram, 722e206ad48SHu Tao base, bank_size); 723e206ad48SHu Tao ram_bases[i] = base; 724e206ad48SHu Tao ram_sizes[i] = bank_size; 725e206ad48SHu Tao base += bank_size; 726e206ad48SHu Tao size_left -= bank_size; 727e206ad48SHu Tao break; 728e206ad48SHu Tao } 729e206ad48SHu Tao } 730e206ad48SHu Tao } 731b7da58fdSaurel32 7325c130f65Spbrook return ram_size; 733b7da58fdSaurel32 } 734517284a7SBALATON Zoltan 735517284a7SBALATON Zoltan /*****************************************************************************/ 736517284a7SBALATON Zoltan /* MAL */ 73704534280SBALATON Zoltan 738517284a7SBALATON Zoltan enum { 739517284a7SBALATON Zoltan MAL0_CFG = 0x180, 740517284a7SBALATON Zoltan MAL0_ESR = 0x181, 741517284a7SBALATON Zoltan MAL0_IER = 0x182, 742517284a7SBALATON Zoltan MAL0_TXCASR = 0x184, 743517284a7SBALATON Zoltan MAL0_TXCARR = 0x185, 744517284a7SBALATON Zoltan MAL0_TXEOBISR = 0x186, 745517284a7SBALATON Zoltan MAL0_TXDEIR = 0x187, 746517284a7SBALATON Zoltan MAL0_RXCASR = 0x190, 747517284a7SBALATON Zoltan MAL0_RXCARR = 0x191, 748517284a7SBALATON Zoltan MAL0_RXEOBISR = 0x192, 749517284a7SBALATON Zoltan MAL0_RXDEIR = 0x193, 750517284a7SBALATON Zoltan MAL0_TXCTP0R = 0x1A0, 751517284a7SBALATON Zoltan MAL0_RXCTP0R = 0x1C0, 752517284a7SBALATON Zoltan MAL0_RCBS0 = 0x1E0, 753517284a7SBALATON Zoltan MAL0_RCBS1 = 0x1E1, 754517284a7SBALATON Zoltan }; 755517284a7SBALATON Zoltan 75604534280SBALATON Zoltan typedef struct ppc4xx_mal_t ppc4xx_mal_t; 75704534280SBALATON Zoltan struct ppc4xx_mal_t { 758517284a7SBALATON Zoltan qemu_irq irqs[4]; 759517284a7SBALATON Zoltan uint32_t cfg; 760517284a7SBALATON Zoltan uint32_t esr; 761517284a7SBALATON Zoltan uint32_t ier; 762517284a7SBALATON Zoltan uint32_t txcasr; 763517284a7SBALATON Zoltan uint32_t txcarr; 764517284a7SBALATON Zoltan uint32_t txeobisr; 765517284a7SBALATON Zoltan uint32_t txdeir; 766517284a7SBALATON Zoltan uint32_t rxcasr; 767517284a7SBALATON Zoltan uint32_t rxcarr; 768517284a7SBALATON Zoltan uint32_t rxeobisr; 769517284a7SBALATON Zoltan uint32_t rxdeir; 77004534280SBALATON Zoltan uint32_t *txctpr; 77104534280SBALATON Zoltan uint32_t *rxctpr; 77204534280SBALATON Zoltan uint32_t *rcbs; 77304534280SBALATON Zoltan uint8_t txcnum; 77404534280SBALATON Zoltan uint8_t rxcnum; 775517284a7SBALATON Zoltan }; 776517284a7SBALATON Zoltan 77704534280SBALATON Zoltan static void ppc4xx_mal_reset(void *opaque) 77804534280SBALATON Zoltan { 77904534280SBALATON Zoltan ppc4xx_mal_t *mal; 78004534280SBALATON Zoltan 78104534280SBALATON Zoltan mal = opaque; 78204534280SBALATON Zoltan mal->cfg = 0x0007C000; 78304534280SBALATON Zoltan mal->esr = 0x00000000; 78404534280SBALATON Zoltan mal->ier = 0x00000000; 78504534280SBALATON Zoltan mal->rxcasr = 0x00000000; 78604534280SBALATON Zoltan mal->rxdeir = 0x00000000; 78704534280SBALATON Zoltan mal->rxeobisr = 0x00000000; 78804534280SBALATON Zoltan mal->txcasr = 0x00000000; 78904534280SBALATON Zoltan mal->txdeir = 0x00000000; 79004534280SBALATON Zoltan mal->txeobisr = 0x00000000; 79104534280SBALATON Zoltan } 792517284a7SBALATON Zoltan 793517284a7SBALATON Zoltan static uint32_t dcr_read_mal(void *opaque, int dcrn) 794517284a7SBALATON Zoltan { 79504534280SBALATON Zoltan ppc4xx_mal_t *mal; 796517284a7SBALATON Zoltan uint32_t ret; 797517284a7SBALATON Zoltan 798517284a7SBALATON Zoltan mal = opaque; 799517284a7SBALATON Zoltan switch (dcrn) { 800517284a7SBALATON Zoltan case MAL0_CFG: 801517284a7SBALATON Zoltan ret = mal->cfg; 802517284a7SBALATON Zoltan break; 803517284a7SBALATON Zoltan case MAL0_ESR: 804517284a7SBALATON Zoltan ret = mal->esr; 805517284a7SBALATON Zoltan break; 806517284a7SBALATON Zoltan case MAL0_IER: 807517284a7SBALATON Zoltan ret = mal->ier; 808517284a7SBALATON Zoltan break; 809517284a7SBALATON Zoltan case MAL0_TXCASR: 810517284a7SBALATON Zoltan ret = mal->txcasr; 811517284a7SBALATON Zoltan break; 812517284a7SBALATON Zoltan case MAL0_TXCARR: 813517284a7SBALATON Zoltan ret = mal->txcarr; 814517284a7SBALATON Zoltan break; 815517284a7SBALATON Zoltan case MAL0_TXEOBISR: 816517284a7SBALATON Zoltan ret = mal->txeobisr; 817517284a7SBALATON Zoltan break; 818517284a7SBALATON Zoltan case MAL0_TXDEIR: 819517284a7SBALATON Zoltan ret = mal->txdeir; 820517284a7SBALATON Zoltan break; 821517284a7SBALATON Zoltan case MAL0_RXCASR: 822517284a7SBALATON Zoltan ret = mal->rxcasr; 823517284a7SBALATON Zoltan break; 824517284a7SBALATON Zoltan case MAL0_RXCARR: 825517284a7SBALATON Zoltan ret = mal->rxcarr; 826517284a7SBALATON Zoltan break; 827517284a7SBALATON Zoltan case MAL0_RXEOBISR: 828517284a7SBALATON Zoltan ret = mal->rxeobisr; 829517284a7SBALATON Zoltan break; 830517284a7SBALATON Zoltan case MAL0_RXDEIR: 831517284a7SBALATON Zoltan ret = mal->rxdeir; 832517284a7SBALATON Zoltan break; 833517284a7SBALATON Zoltan default: 834517284a7SBALATON Zoltan ret = 0; 835517284a7SBALATON Zoltan break; 836517284a7SBALATON Zoltan } 83704534280SBALATON Zoltan if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { 83804534280SBALATON Zoltan ret = mal->txctpr[dcrn - MAL0_TXCTP0R]; 83904534280SBALATON Zoltan } 84004534280SBALATON Zoltan if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { 84104534280SBALATON Zoltan ret = mal->rxctpr[dcrn - MAL0_RXCTP0R]; 84204534280SBALATON Zoltan } 84304534280SBALATON Zoltan if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { 84404534280SBALATON Zoltan ret = mal->rcbs[dcrn - MAL0_RCBS0]; 84504534280SBALATON Zoltan } 846517284a7SBALATON Zoltan 847517284a7SBALATON Zoltan return ret; 848517284a7SBALATON Zoltan } 849517284a7SBALATON Zoltan 850517284a7SBALATON Zoltan static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) 851517284a7SBALATON Zoltan { 85204534280SBALATON Zoltan ppc4xx_mal_t *mal; 853517284a7SBALATON Zoltan 854517284a7SBALATON Zoltan mal = opaque; 855517284a7SBALATON Zoltan switch (dcrn) { 856517284a7SBALATON Zoltan case MAL0_CFG: 857517284a7SBALATON Zoltan if (val & 0x80000000) { 85804534280SBALATON Zoltan ppc4xx_mal_reset(mal); 859517284a7SBALATON Zoltan } 860517284a7SBALATON Zoltan mal->cfg = val & 0x00FFC087; 861517284a7SBALATON Zoltan break; 862517284a7SBALATON Zoltan case MAL0_ESR: 863517284a7SBALATON Zoltan /* Read/clear */ 864517284a7SBALATON Zoltan mal->esr &= ~val; 865517284a7SBALATON Zoltan break; 866517284a7SBALATON Zoltan case MAL0_IER: 867517284a7SBALATON Zoltan mal->ier = val & 0x0000001F; 868517284a7SBALATON Zoltan break; 869517284a7SBALATON Zoltan case MAL0_TXCASR: 870517284a7SBALATON Zoltan mal->txcasr = val & 0xF0000000; 871517284a7SBALATON Zoltan break; 872517284a7SBALATON Zoltan case MAL0_TXCARR: 873517284a7SBALATON Zoltan mal->txcarr = val & 0xF0000000; 874517284a7SBALATON Zoltan break; 875517284a7SBALATON Zoltan case MAL0_TXEOBISR: 876517284a7SBALATON Zoltan /* Read/clear */ 877517284a7SBALATON Zoltan mal->txeobisr &= ~val; 878517284a7SBALATON Zoltan break; 879517284a7SBALATON Zoltan case MAL0_TXDEIR: 880517284a7SBALATON Zoltan /* Read/clear */ 881517284a7SBALATON Zoltan mal->txdeir &= ~val; 882517284a7SBALATON Zoltan break; 883517284a7SBALATON Zoltan case MAL0_RXCASR: 884517284a7SBALATON Zoltan mal->rxcasr = val & 0xC0000000; 885517284a7SBALATON Zoltan break; 886517284a7SBALATON Zoltan case MAL0_RXCARR: 887517284a7SBALATON Zoltan mal->rxcarr = val & 0xC0000000; 888517284a7SBALATON Zoltan break; 889517284a7SBALATON Zoltan case MAL0_RXEOBISR: 890517284a7SBALATON Zoltan /* Read/clear */ 891517284a7SBALATON Zoltan mal->rxeobisr &= ~val; 892517284a7SBALATON Zoltan break; 893517284a7SBALATON Zoltan case MAL0_RXDEIR: 894517284a7SBALATON Zoltan /* Read/clear */ 895517284a7SBALATON Zoltan mal->rxdeir &= ~val; 896517284a7SBALATON Zoltan break; 89704534280SBALATON Zoltan } 89804534280SBALATON Zoltan if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) { 89904534280SBALATON Zoltan mal->txctpr[dcrn - MAL0_TXCTP0R] = val; 90004534280SBALATON Zoltan } 90104534280SBALATON Zoltan if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) { 90204534280SBALATON Zoltan mal->rxctpr[dcrn - MAL0_RXCTP0R] = val; 90304534280SBALATON Zoltan } 90404534280SBALATON Zoltan if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) { 90504534280SBALATON Zoltan mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF; 906517284a7SBALATON Zoltan } 907517284a7SBALATON Zoltan } 908517284a7SBALATON Zoltan 90904534280SBALATON Zoltan void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, 91004534280SBALATON Zoltan qemu_irq irqs[4]) 911517284a7SBALATON Zoltan { 91204534280SBALATON Zoltan ppc4xx_mal_t *mal; 913517284a7SBALATON Zoltan int i; 914517284a7SBALATON Zoltan 91504534280SBALATON Zoltan assert(txcnum <= 32 && rxcnum <= 32); 91604534280SBALATON Zoltan mal = g_malloc0(sizeof(*mal)); 91704534280SBALATON Zoltan mal->txcnum = txcnum; 91804534280SBALATON Zoltan mal->rxcnum = rxcnum; 91904534280SBALATON Zoltan mal->txctpr = g_new0(uint32_t, txcnum); 92004534280SBALATON Zoltan mal->rxctpr = g_new0(uint32_t, rxcnum); 92104534280SBALATON Zoltan mal->rcbs = g_new0(uint32_t, rxcnum); 922517284a7SBALATON Zoltan for (i = 0; i < 4; i++) { 923517284a7SBALATON Zoltan mal->irqs[i] = irqs[i]; 924517284a7SBALATON Zoltan } 92504534280SBALATON Zoltan qemu_register_reset(&ppc4xx_mal_reset, mal); 926517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_CFG, 927517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 928517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_ESR, 929517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 930517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_IER, 931517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 932517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCASR, 933517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 934517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCARR, 935517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 936517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXEOBISR, 937517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 938517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_TXDEIR, 939517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 940517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCASR, 941517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 942517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCARR, 943517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 944517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXEOBISR, 945517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 946517284a7SBALATON Zoltan ppc_dcr_register(env, MAL0_RXDEIR, 947517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 94804534280SBALATON Zoltan for (i = 0; i < txcnum; i++) { 94904534280SBALATON Zoltan ppc_dcr_register(env, MAL0_TXCTP0R + i, 950517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 95104534280SBALATON Zoltan } 95204534280SBALATON Zoltan for (i = 0; i < rxcnum; i++) { 95304534280SBALATON Zoltan ppc_dcr_register(env, MAL0_RXCTP0R + i, 954517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 95504534280SBALATON Zoltan } 95604534280SBALATON Zoltan for (i = 0; i < rxcnum; i++) { 95704534280SBALATON Zoltan ppc_dcr_register(env, MAL0_RCBS0 + i, 958517284a7SBALATON Zoltan mal, &dcr_read_mal, &dcr_write_mal); 95904534280SBALATON Zoltan } 960517284a7SBALATON Zoltan } 961