qemu/hw/ppc/ppc4xx_devs.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC 4xx embedded processors shared devices emulation
   3 *
   4 * Copyright (c) 2007 Jocelyn Mayer
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qemu/units.h"
  27#include "sysemu/reset.h"
  28#include "cpu.h"
  29#include "hw/irq.h"
  30#include "hw/ppc/ppc.h"
  31#include "hw/ppc/ppc4xx.h"
  32#include "hw/intc/ppc-uic.h"
  33#include "hw/qdev-properties.h"
  34#include "qemu/log.h"
  35#include "exec/address-spaces.h"
  36#include "qemu/error-report.h"
  37#include "qapi/error.h"
  38
  39/*#define DEBUG_UIC*/
  40
  41#ifdef DEBUG_UIC
  42#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
  43#else
  44#  define LOG_UIC(...) do { } while (0)
  45#endif
  46
  47static void ppc4xx_reset(void *opaque)
  48{
  49    PowerPCCPU *cpu = opaque;
  50
  51    cpu_reset(CPU(cpu));
  52}
  53
  54/*****************************************************************************/
  55/* Generic PowerPC 4xx processor instantiation */
  56PowerPCCPU *ppc4xx_init(const char *cpu_type,
  57                        clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
  58                        uint32_t sysclk)
  59{
  60    PowerPCCPU *cpu;
  61    CPUPPCState *env;
  62
  63    /* init CPUs */
  64    cpu = POWERPC_CPU(cpu_create(cpu_type));
  65    env = &cpu->env;
  66
  67    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
  68    cpu_clk->opaque = env;
  69    /* Set time-base frequency to sysclk */
  70    tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
  71    tb_clk->opaque = env;
  72    ppc_dcr_init(env, NULL, NULL);
  73    /* Register qemu callbacks */
  74    qemu_register_reset(ppc4xx_reset, cpu);
  75
  76    return cpu;
  77}
  78
  79/*****************************************************************************/
  80/* SDRAM controller */
  81typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
  82struct ppc4xx_sdram_t {
  83    uint32_t addr;
  84    int nbanks;
  85    MemoryRegion containers[4]; /* used for clipping */
  86    MemoryRegion *ram_memories;
  87    hwaddr ram_bases[4];
  88    hwaddr ram_sizes[4];
  89    uint32_t besr0;
  90    uint32_t besr1;
  91    uint32_t bear;
  92    uint32_t cfg;
  93    uint32_t status;
  94    uint32_t rtr;
  95    uint32_t pmit;
  96    uint32_t bcr[4];
  97    uint32_t tr;
  98    uint32_t ecccfg;
  99    uint32_t eccesr;
 100    qemu_irq irq;
 101};
 102
 103enum {
 104    SDRAM0_CFGADDR = 0x010,
 105    SDRAM0_CFGDATA = 0x011,
 106};
 107
 108/* XXX: TOFIX: some patches have made this code become inconsistent:
 109 *      there are type inconsistencies, mixing hwaddr, target_ulong
 110 *      and uint32_t
 111 */
 112static uint32_t sdram_bcr (hwaddr ram_base,
 113                           hwaddr ram_size)
 114{
 115    uint32_t bcr;
 116
 117    switch (ram_size) {
 118    case 4 * MiB:
 119        bcr = 0x00000000;
 120        break;
 121    case 8 * MiB:
 122        bcr = 0x00020000;
 123        break;
 124    case 16 * MiB:
 125        bcr = 0x00040000;
 126        break;
 127    case 32 * MiB:
 128        bcr = 0x00060000;
 129        break;
 130    case 64 * MiB:
 131        bcr = 0x00080000;
 132        break;
 133    case 128 * MiB:
 134        bcr = 0x000A0000;
 135        break;
 136    case 256 * MiB:
 137        bcr = 0x000C0000;
 138        break;
 139    default:
 140        printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__,
 141               ram_size);
 142        return 0x00000000;
 143    }
 144    bcr |= ram_base & 0xFF800000;
 145    bcr |= 1;
 146
 147    return bcr;
 148}
 149
 150static inline hwaddr sdram_base(uint32_t bcr)
 151{
 152    return bcr & 0xFF800000;
 153}
 154
 155static target_ulong sdram_size (uint32_t bcr)
 156{
 157    target_ulong size;
 158    int sh;
 159
 160    sh = (bcr >> 17) & 0x7;
 161    if (sh == 7)
 162        size = -1;
 163    else
 164        size = (4 * MiB) << sh;
 165
 166    return size;
 167}
 168
 169static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i,
 170                          uint32_t bcr, int enabled)
 171{
 172    if (sdram->bcr[i] & 0x00000001) {
 173        /* Unmap RAM */
 174#ifdef DEBUG_SDRAM
 175        printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
 176               __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
 177#endif
 178        memory_region_del_subregion(get_system_memory(),
 179                                    &sdram->containers[i]);
 180        memory_region_del_subregion(&sdram->containers[i],
 181                                    &sdram->ram_memories[i]);
 182        object_unparent(OBJECT(&sdram->containers[i]));
 183    }
 184    sdram->bcr[i] = bcr & 0xFFDEE001;
 185    if (enabled && (bcr & 0x00000001)) {
 186#ifdef DEBUG_SDRAM
 187        printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
 188               __func__, sdram_base(bcr), sdram_size(bcr));
 189#endif
 190        memory_region_init(&sdram->containers[i], NULL, "sdram-containers",
 191                           sdram_size(bcr));
 192        memory_region_add_subregion(&sdram->containers[i], 0,
 193                                    &sdram->ram_memories[i]);
 194        memory_region_add_subregion(get_system_memory(),
 195                                    sdram_base(bcr),
 196                                    &sdram->containers[i]);
 197    }
 198}
 199
 200static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
 201{
 202    int i;
 203
 204    for (i = 0; i < sdram->nbanks; i++) {
 205        if (sdram->ram_sizes[i] != 0) {
 206            sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i],
 207                                              sdram->ram_sizes[i]), 1);
 208        } else {
 209            sdram_set_bcr(sdram, i, 0x00000000, 0);
 210        }
 211    }
 212}
 213
 214static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
 215{
 216    int i;
 217
 218    for (i = 0; i < sdram->nbanks; i++) {
 219#ifdef DEBUG_SDRAM
 220        printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
 221               __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
 222#endif
 223        memory_region_del_subregion(get_system_memory(),
 224                                    &sdram->ram_memories[i]);
 225    }
 226}
 227
 228static uint32_t dcr_read_sdram (void *opaque, int dcrn)
 229{
 230    ppc4xx_sdram_t *sdram;
 231    uint32_t ret;
 232
 233    sdram = opaque;
 234    switch (dcrn) {
 235    case SDRAM0_CFGADDR:
 236        ret = sdram->addr;
 237        break;
 238    case SDRAM0_CFGDATA:
 239        switch (sdram->addr) {
 240        case 0x00: /* SDRAM_BESR0 */
 241            ret = sdram->besr0;
 242            break;
 243        case 0x08: /* SDRAM_BESR1 */
 244            ret = sdram->besr1;
 245            break;
 246        case 0x10: /* SDRAM_BEAR */
 247            ret = sdram->bear;
 248            break;
 249        case 0x20: /* SDRAM_CFG */
 250            ret = sdram->cfg;
 251            break;
 252        case 0x24: /* SDRAM_STATUS */
 253            ret = sdram->status;
 254            break;
 255        case 0x30: /* SDRAM_RTR */
 256            ret = sdram->rtr;
 257            break;
 258        case 0x34: /* SDRAM_PMIT */
 259            ret = sdram->pmit;
 260            break;
 261        case 0x40: /* SDRAM_B0CR */
 262            ret = sdram->bcr[0];
 263            break;
 264        case 0x44: /* SDRAM_B1CR */
 265            ret = sdram->bcr[1];
 266            break;
 267        case 0x48: /* SDRAM_B2CR */
 268            ret = sdram->bcr[2];
 269            break;
 270        case 0x4C: /* SDRAM_B3CR */
 271            ret = sdram->bcr[3];
 272            break;
 273        case 0x80: /* SDRAM_TR */
 274            ret = -1; /* ? */
 275            break;
 276        case 0x94: /* SDRAM_ECCCFG */
 277            ret = sdram->ecccfg;
 278            break;
 279        case 0x98: /* SDRAM_ECCESR */
 280            ret = sdram->eccesr;
 281            break;
 282        default: /* Error */
 283            ret = -1;
 284            break;
 285        }
 286        break;
 287    default:
 288        /* Avoid gcc warning */
 289        ret = 0x00000000;
 290        break;
 291    }
 292
 293    return ret;
 294}
 295
 296static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
 297{
 298    ppc4xx_sdram_t *sdram;
 299
 300    sdram = opaque;
 301    switch (dcrn) {
 302    case SDRAM0_CFGADDR:
 303        sdram->addr = val;
 304        break;
 305    case SDRAM0_CFGDATA:
 306        switch (sdram->addr) {
 307        case 0x00: /* SDRAM_BESR0 */
 308            sdram->besr0 &= ~val;
 309            break;
 310        case 0x08: /* SDRAM_BESR1 */
 311            sdram->besr1 &= ~val;
 312            break;
 313        case 0x10: /* SDRAM_BEAR */
 314            sdram->bear = val;
 315            break;
 316        case 0x20: /* SDRAM_CFG */
 317            val &= 0xFFE00000;
 318            if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
 319#ifdef DEBUG_SDRAM
 320                printf("%s: enable SDRAM controller\n", __func__);
 321#endif
 322                /* validate all RAM mappings */
 323                sdram_map_bcr(sdram);
 324                sdram->status &= ~0x80000000;
 325            } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
 326#ifdef DEBUG_SDRAM
 327                printf("%s: disable SDRAM controller\n", __func__);
 328#endif
 329                /* invalidate all RAM mappings */
 330                sdram_unmap_bcr(sdram);
 331                sdram->status |= 0x80000000;
 332            }
 333            if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
 334                sdram->status |= 0x40000000;
 335            else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
 336                sdram->status &= ~0x40000000;
 337            sdram->cfg = val;
 338            break;
 339        case 0x24: /* SDRAM_STATUS */
 340            /* Read-only register */
 341            break;
 342        case 0x30: /* SDRAM_RTR */
 343            sdram->rtr = val & 0x3FF80000;
 344            break;
 345        case 0x34: /* SDRAM_PMIT */
 346            sdram->pmit = (val & 0xF8000000) | 0x07C00000;
 347            break;
 348        case 0x40: /* SDRAM_B0CR */
 349            sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000);
 350            break;
 351        case 0x44: /* SDRAM_B1CR */
 352            sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000);
 353            break;
 354        case 0x48: /* SDRAM_B2CR */
 355            sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000);
 356            break;
 357        case 0x4C: /* SDRAM_B3CR */
 358            sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000);
 359            break;
 360        case 0x80: /* SDRAM_TR */
 361            sdram->tr = val & 0x018FC01F;
 362            break;
 363        case 0x94: /* SDRAM_ECCCFG */
 364            sdram->ecccfg = val & 0x00F00000;
 365            break;
 366        case 0x98: /* SDRAM_ECCESR */
 367            val &= 0xFFF0F000;
 368            if (sdram->eccesr == 0 && val != 0)
 369                qemu_irq_raise(sdram->irq);
 370            else if (sdram->eccesr != 0 && val == 0)
 371                qemu_irq_lower(sdram->irq);
 372            sdram->eccesr = val;
 373            break;
 374        default: /* Error */
 375            break;
 376        }
 377        break;
 378    }
 379}
 380
 381static void sdram_reset (void *opaque)
 382{
 383    ppc4xx_sdram_t *sdram;
 384
 385    sdram = opaque;
 386    sdram->addr = 0x00000000;
 387    sdram->bear = 0x00000000;
 388    sdram->besr0 = 0x00000000; /* No error */
 389    sdram->besr1 = 0x00000000; /* No error */
 390    sdram->cfg = 0x00000000;
 391    sdram->ecccfg = 0x00000000; /* No ECC */
 392    sdram->eccesr = 0x00000000; /* No error */
 393    sdram->pmit = 0x07C00000;
 394    sdram->rtr = 0x05F00000;
 395    sdram->tr = 0x00854009;
 396    /* We pre-initialize RAM banks */
 397    sdram->status = 0x00000000;
 398    sdram->cfg = 0x00800000;
 399}
 400
 401void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
 402                        MemoryRegion *ram_memories,
 403                        hwaddr *ram_bases,
 404                        hwaddr *ram_sizes,
 405                        int do_init)
 406{
 407    ppc4xx_sdram_t *sdram;
 408
 409    sdram = g_malloc0(sizeof(ppc4xx_sdram_t));
 410    sdram->irq = irq;
 411    sdram->nbanks = nbanks;
 412    sdram->ram_memories = ram_memories;
 413    memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr));
 414    memcpy(sdram->ram_bases, ram_bases,
 415           nbanks * sizeof(hwaddr));
 416    memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr));
 417    memcpy(sdram->ram_sizes, ram_sizes,
 418           nbanks * sizeof(hwaddr));
 419    qemu_register_reset(&sdram_reset, sdram);
 420    ppc_dcr_register(env, SDRAM0_CFGADDR,
 421                     sdram, &dcr_read_sdram, &dcr_write_sdram);
 422    ppc_dcr_register(env, SDRAM0_CFGDATA,
 423                     sdram, &dcr_read_sdram, &dcr_write_sdram);
 424    if (do_init)
 425        sdram_map_bcr(sdram);
 426}
 427
 428/*
 429 * Split RAM between SDRAM banks.
 430 *
 431 * sdram_bank_sizes[] must be in descending order, that is sizes[i] > sizes[i+1]
 432 * and must be 0-terminated.
 433 *
 434 * The 4xx SDRAM controller supports a small number of banks, and each bank
 435 * must be one of a small set of sizes. The number of banks and the supported
 436 * sizes varies by SoC.
 437 */
 438void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
 439                        MemoryRegion ram_memories[],
 440                        hwaddr ram_bases[], hwaddr ram_sizes[],
 441                        const ram_addr_t sdram_bank_sizes[])
 442{
 443    ram_addr_t size_left = memory_region_size(ram);
 444    ram_addr_t base = 0;
 445    ram_addr_t bank_size;
 446    int i;
 447    int j;
 448
 449    for (i = 0; i < nr_banks; i++) {
 450        for (j = 0; sdram_bank_sizes[j] != 0; j++) {
 451            bank_size = sdram_bank_sizes[j];
 452            if (bank_size <= size_left) {
 453                char name[32];
 454
 455                ram_bases[i] = base;
 456                ram_sizes[i] = bank_size;
 457                base += bank_size;
 458                size_left -= bank_size;
 459                snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
 460                memory_region_init_alias(&ram_memories[i], NULL, name, ram,
 461                                         ram_bases[i], ram_sizes[i]);
 462                break;
 463            }
 464        }
 465        if (!size_left) {
 466            /* No need to use the remaining banks. */
 467            break;
 468        }
 469    }
 470
 471    if (size_left) {
 472        ram_addr_t used_size = memory_region_size(ram) - size_left;
 473        GString *s = g_string_new(NULL);
 474
 475        for (i = 0; sdram_bank_sizes[i]; i++) {
 476            g_string_append_printf(s, "%" PRIi64 "%s",
 477                                   sdram_bank_sizes[i] / MiB,
 478                                   sdram_bank_sizes[i + 1] ? ", " : "");
 479        }
 480        error_report("at most %d bank%s of %s MiB each supported",
 481                     nr_banks, nr_banks == 1 ? "" : "s", s->str);
 482        error_printf("Possible valid RAM size: %" PRIi64 " MiB \n",
 483            used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB);
 484
 485        g_string_free(s, true);
 486        exit(EXIT_FAILURE);
 487    }
 488}
 489
 490/*****************************************************************************/
 491/* MAL */
 492
 493enum {
 494    MAL0_CFG      = 0x180,
 495    MAL0_ESR      = 0x181,
 496    MAL0_IER      = 0x182,
 497    MAL0_TXCASR   = 0x184,
 498    MAL0_TXCARR   = 0x185,
 499    MAL0_TXEOBISR = 0x186,
 500    MAL0_TXDEIR   = 0x187,
 501    MAL0_RXCASR   = 0x190,
 502    MAL0_RXCARR   = 0x191,
 503    MAL0_RXEOBISR = 0x192,
 504    MAL0_RXDEIR   = 0x193,
 505    MAL0_TXCTP0R  = 0x1A0,
 506    MAL0_RXCTP0R  = 0x1C0,
 507    MAL0_RCBS0    = 0x1E0,
 508    MAL0_RCBS1    = 0x1E1,
 509};
 510
 511typedef struct ppc4xx_mal_t ppc4xx_mal_t;
 512struct ppc4xx_mal_t {
 513    qemu_irq irqs[4];
 514    uint32_t cfg;
 515    uint32_t esr;
 516    uint32_t ier;
 517    uint32_t txcasr;
 518    uint32_t txcarr;
 519    uint32_t txeobisr;
 520    uint32_t txdeir;
 521    uint32_t rxcasr;
 522    uint32_t rxcarr;
 523    uint32_t rxeobisr;
 524    uint32_t rxdeir;
 525    uint32_t *txctpr;
 526    uint32_t *rxctpr;
 527    uint32_t *rcbs;
 528    uint8_t  txcnum;
 529    uint8_t  rxcnum;
 530};
 531
 532static void ppc4xx_mal_reset(void *opaque)
 533{
 534    ppc4xx_mal_t *mal;
 535
 536    mal = opaque;
 537    mal->cfg = 0x0007C000;
 538    mal->esr = 0x00000000;
 539    mal->ier = 0x00000000;
 540    mal->rxcasr = 0x00000000;
 541    mal->rxdeir = 0x00000000;
 542    mal->rxeobisr = 0x00000000;
 543    mal->txcasr = 0x00000000;
 544    mal->txdeir = 0x00000000;
 545    mal->txeobisr = 0x00000000;
 546}
 547
 548static uint32_t dcr_read_mal(void *opaque, int dcrn)
 549{
 550    ppc4xx_mal_t *mal;
 551    uint32_t ret;
 552
 553    mal = opaque;
 554    switch (dcrn) {
 555    case MAL0_CFG:
 556        ret = mal->cfg;
 557        break;
 558    case MAL0_ESR:
 559        ret = mal->esr;
 560        break;
 561    case MAL0_IER:
 562        ret = mal->ier;
 563        break;
 564    case MAL0_TXCASR:
 565        ret = mal->txcasr;
 566        break;
 567    case MAL0_TXCARR:
 568        ret = mal->txcarr;
 569        break;
 570    case MAL0_TXEOBISR:
 571        ret = mal->txeobisr;
 572        break;
 573    case MAL0_TXDEIR:
 574        ret = mal->txdeir;
 575        break;
 576    case MAL0_RXCASR:
 577        ret = mal->rxcasr;
 578        break;
 579    case MAL0_RXCARR:
 580        ret = mal->rxcarr;
 581        break;
 582    case MAL0_RXEOBISR:
 583        ret = mal->rxeobisr;
 584        break;
 585    case MAL0_RXDEIR:
 586        ret = mal->rxdeir;
 587        break;
 588    default:
 589        ret = 0;
 590        break;
 591    }
 592    if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) {
 593        ret = mal->txctpr[dcrn - MAL0_TXCTP0R];
 594    }
 595    if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) {
 596        ret = mal->rxctpr[dcrn - MAL0_RXCTP0R];
 597    }
 598    if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) {
 599        ret = mal->rcbs[dcrn - MAL0_RCBS0];
 600    }
 601
 602    return ret;
 603}
 604
 605static void dcr_write_mal(void *opaque, int dcrn, uint32_t val)
 606{
 607    ppc4xx_mal_t *mal;
 608
 609    mal = opaque;
 610    switch (dcrn) {
 611    case MAL0_CFG:
 612        if (val & 0x80000000) {
 613            ppc4xx_mal_reset(mal);
 614        }
 615        mal->cfg = val & 0x00FFC087;
 616        break;
 617    case MAL0_ESR:
 618        /* Read/clear */
 619        mal->esr &= ~val;
 620        break;
 621    case MAL0_IER:
 622        mal->ier = val & 0x0000001F;
 623        break;
 624    case MAL0_TXCASR:
 625        mal->txcasr = val & 0xF0000000;
 626        break;
 627    case MAL0_TXCARR:
 628        mal->txcarr = val & 0xF0000000;
 629        break;
 630    case MAL0_TXEOBISR:
 631        /* Read/clear */
 632        mal->txeobisr &= ~val;
 633        break;
 634    case MAL0_TXDEIR:
 635        /* Read/clear */
 636        mal->txdeir &= ~val;
 637        break;
 638    case MAL0_RXCASR:
 639        mal->rxcasr = val & 0xC0000000;
 640        break;
 641    case MAL0_RXCARR:
 642        mal->rxcarr = val & 0xC0000000;
 643        break;
 644    case MAL0_RXEOBISR:
 645        /* Read/clear */
 646        mal->rxeobisr &= ~val;
 647        break;
 648    case MAL0_RXDEIR:
 649        /* Read/clear */
 650        mal->rxdeir &= ~val;
 651        break;
 652    }
 653    if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) {
 654        mal->txctpr[dcrn - MAL0_TXCTP0R] = val;
 655    }
 656    if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) {
 657        mal->rxctpr[dcrn - MAL0_RXCTP0R] = val;
 658    }
 659    if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) {
 660        mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF;
 661    }
 662}
 663
 664void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum,
 665                     qemu_irq irqs[4])
 666{
 667    ppc4xx_mal_t *mal;
 668    int i;
 669
 670    assert(txcnum <= 32 && rxcnum <= 32);
 671    mal = g_malloc0(sizeof(*mal));
 672    mal->txcnum = txcnum;
 673    mal->rxcnum = rxcnum;
 674    mal->txctpr = g_new0(uint32_t, txcnum);
 675    mal->rxctpr = g_new0(uint32_t, rxcnum);
 676    mal->rcbs = g_new0(uint32_t, rxcnum);
 677    for (i = 0; i < 4; i++) {
 678        mal->irqs[i] = irqs[i];
 679    }
 680    qemu_register_reset(&ppc4xx_mal_reset, mal);
 681    ppc_dcr_register(env, MAL0_CFG,
 682                     mal, &dcr_read_mal, &dcr_write_mal);
 683    ppc_dcr_register(env, MAL0_ESR,
 684                     mal, &dcr_read_mal, &dcr_write_mal);
 685    ppc_dcr_register(env, MAL0_IER,
 686                     mal, &dcr_read_mal, &dcr_write_mal);
 687    ppc_dcr_register(env, MAL0_TXCASR,
 688                     mal, &dcr_read_mal, &dcr_write_mal);
 689    ppc_dcr_register(env, MAL0_TXCARR,
 690                     mal, &dcr_read_mal, &dcr_write_mal);
 691    ppc_dcr_register(env, MAL0_TXEOBISR,
 692                     mal, &dcr_read_mal, &dcr_write_mal);
 693    ppc_dcr_register(env, MAL0_TXDEIR,
 694                     mal, &dcr_read_mal, &dcr_write_mal);
 695    ppc_dcr_register(env, MAL0_RXCASR,
 696                     mal, &dcr_read_mal, &dcr_write_mal);
 697    ppc_dcr_register(env, MAL0_RXCARR,
 698                     mal, &dcr_read_mal, &dcr_write_mal);
 699    ppc_dcr_register(env, MAL0_RXEOBISR,
 700                     mal, &dcr_read_mal, &dcr_write_mal);
 701    ppc_dcr_register(env, MAL0_RXDEIR,
 702                     mal, &dcr_read_mal, &dcr_write_mal);
 703    for (i = 0; i < txcnum; i++) {
 704        ppc_dcr_register(env, MAL0_TXCTP0R + i,
 705                         mal, &dcr_read_mal, &dcr_write_mal);
 706    }
 707    for (i = 0; i < rxcnum; i++) {
 708        ppc_dcr_register(env, MAL0_RXCTP0R + i,
 709                         mal, &dcr_read_mal, &dcr_write_mal);
 710    }
 711    for (i = 0; i < rxcnum; i++) {
 712        ppc_dcr_register(env, MAL0_RCBS0 + i,
 713                         mal, &dcr_read_mal, &dcr_write_mal);
 714    }
 715}
 716