qemu/hw/dma/pl080.c
<<
>>
Prefs
   1/*
   2 * Arm PrimeCell PL080/PL081 DMA controller
   3 *
   4 * Copyright (c) 2006 CodeSourcery.
   5 * Written by Paul Brook
   6 *
   7 * This code is licensed under the GPL.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "hw/sysbus.h"
  12#include "exec/address-spaces.h"
  13#include "qemu/log.h"
  14#include "qemu/module.h"
  15#include "hw/dma/pl080.h"
  16#include "qapi/error.h"
  17
  18#define PL080_CONF_E    0x1
  19#define PL080_CONF_M1   0x2
  20#define PL080_CONF_M2   0x4
  21
  22#define PL080_CCONF_H   0x40000
  23#define PL080_CCONF_A   0x20000
  24#define PL080_CCONF_L   0x10000
  25#define PL080_CCONF_ITC 0x08000
  26#define PL080_CCONF_IE  0x04000
  27#define PL080_CCONF_E   0x00001
  28
  29#define PL080_CCTRL_I   0x80000000
  30#define PL080_CCTRL_DI  0x08000000
  31#define PL080_CCTRL_SI  0x04000000
  32#define PL080_CCTRL_D   0x02000000
  33#define PL080_CCTRL_S   0x01000000
  34
  35static const VMStateDescription vmstate_pl080_channel = {
  36    .name = "pl080_channel",
  37    .version_id = 1,
  38    .minimum_version_id = 1,
  39    .fields = (VMStateField[]) {
  40        VMSTATE_UINT32(src, pl080_channel),
  41        VMSTATE_UINT32(dest, pl080_channel),
  42        VMSTATE_UINT32(lli, pl080_channel),
  43        VMSTATE_UINT32(ctrl, pl080_channel),
  44        VMSTATE_UINT32(conf, pl080_channel),
  45        VMSTATE_END_OF_LIST()
  46    }
  47};
  48
  49static const VMStateDescription vmstate_pl080 = {
  50    .name = "pl080",
  51    .version_id = 1,
  52    .minimum_version_id = 1,
  53    .fields = (VMStateField[]) {
  54        VMSTATE_UINT8(tc_int, PL080State),
  55        VMSTATE_UINT8(tc_mask, PL080State),
  56        VMSTATE_UINT8(err_int, PL080State),
  57        VMSTATE_UINT8(err_mask, PL080State),
  58        VMSTATE_UINT32(conf, PL080State),
  59        VMSTATE_UINT32(sync, PL080State),
  60        VMSTATE_UINT32(req_single, PL080State),
  61        VMSTATE_UINT32(req_burst, PL080State),
  62        VMSTATE_UINT8(tc_int, PL080State),
  63        VMSTATE_UINT8(tc_int, PL080State),
  64        VMSTATE_UINT8(tc_int, PL080State),
  65        VMSTATE_STRUCT_ARRAY(chan, PL080State, PL080_MAX_CHANNELS,
  66                             1, vmstate_pl080_channel, pl080_channel),
  67        VMSTATE_INT32(running, PL080State),
  68        VMSTATE_END_OF_LIST()
  69    }
  70};
  71
  72static const unsigned char pl080_id[] =
  73{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
  74
  75static const unsigned char pl081_id[] =
  76{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
  77
  78static void pl080_update(PL080State *s)
  79{
  80    bool tclevel = (s->tc_int & s->tc_mask);
  81    bool errlevel = (s->err_int & s->err_mask);
  82
  83    qemu_set_irq(s->interr, errlevel);
  84    qemu_set_irq(s->inttc, tclevel);
  85    qemu_set_irq(s->irq, errlevel || tclevel);
  86}
  87
  88static void pl080_run(PL080State *s)
  89{
  90    int c;
  91    int flow;
  92    pl080_channel *ch;
  93    int swidth;
  94    int dwidth;
  95    int xsize;
  96    int n;
  97    int src_id;
  98    int dest_id;
  99    int size;
 100    uint8_t buff[4];
 101    uint32_t req;
 102
 103    s->tc_mask = 0;
 104    for (c = 0; c < s->nchannels; c++) {
 105        if (s->chan[c].conf & PL080_CCONF_ITC)
 106            s->tc_mask |= 1 << c;
 107        if (s->chan[c].conf & PL080_CCONF_IE)
 108            s->err_mask |= 1 << c;
 109    }
 110
 111    if ((s->conf & PL080_CONF_E) == 0)
 112        return;
 113
 114    /* If we are already in the middle of a DMA operation then indicate that
 115       there may be new DMA requests and return immediately.  */
 116    if (s->running) {
 117        s->running++;
 118        return;
 119    }
 120    s->running = 1;
 121    while (s->running) {
 122        for (c = 0; c < s->nchannels; c++) {
 123            ch = &s->chan[c];
 124again:
 125            /* Test if thiws channel has any pending DMA requests.  */
 126            if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
 127                    != PL080_CCONF_E)
 128                continue;
 129            flow = (ch->conf >> 11) & 7;
 130            if (flow >= 4) {
 131                hw_error(
 132                    "pl080_run: Peripheral flow control not implemented\n");
 133            }
 134            src_id = (ch->conf >> 1) & 0x1f;
 135            dest_id = (ch->conf >> 6) & 0x1f;
 136            size = ch->ctrl & 0xfff;
 137            req = s->req_single | s->req_burst;
 138            switch (flow) {
 139            case 0:
 140                break;
 141            case 1:
 142                if ((req & (1u << dest_id)) == 0)
 143                    size = 0;
 144                break;
 145            case 2:
 146                if ((req & (1u << src_id)) == 0)
 147                    size = 0;
 148                break;
 149            case 3:
 150                if ((req & (1u << src_id)) == 0
 151                        || (req & (1u << dest_id)) == 0)
 152                    size = 0;
 153                break;
 154            }
 155            if (!size)
 156                continue;
 157
 158            /* Transfer one element.  */
 159            /* ??? Should transfer multiple elements for a burst request.  */
 160            /* ??? Unclear what the proper behavior is when source and
 161               destination widths are different.  */
 162            swidth = 1 << ((ch->ctrl >> 18) & 7);
 163            dwidth = 1 << ((ch->ctrl >> 21) & 7);
 164            for (n = 0; n < dwidth; n+= swidth) {
 165                address_space_read(&s->downstream_as, ch->src,
 166                                   MEMTXATTRS_UNSPECIFIED, buff + n, swidth);
 167                if (ch->ctrl & PL080_CCTRL_SI)
 168                    ch->src += swidth;
 169            }
 170            xsize = (dwidth < swidth) ? swidth : dwidth;
 171            /* ??? This may pad the value incorrectly for dwidth < 32.  */
 172            for (n = 0; n < xsize; n += dwidth) {
 173                address_space_write(&s->downstream_as, ch->dest + n,
 174                                    MEMTXATTRS_UNSPECIFIED, buff + n, dwidth);
 175                if (ch->ctrl & PL080_CCTRL_DI)
 176                    ch->dest += swidth;
 177            }
 178
 179            size--;
 180            ch->ctrl = (ch->ctrl & 0xfffff000) | size;
 181            if (size == 0) {
 182                /* Transfer complete.  */
 183                if (ch->lli) {
 184                    ch->src = address_space_ldl_le(&s->downstream_as,
 185                                                   ch->lli,
 186                                                   MEMTXATTRS_UNSPECIFIED,
 187                                                   NULL);
 188                    ch->dest = address_space_ldl_le(&s->downstream_as,
 189                                                    ch->lli + 4,
 190                                                    MEMTXATTRS_UNSPECIFIED,
 191                                                    NULL);
 192                    ch->ctrl = address_space_ldl_le(&s->downstream_as,
 193                                                    ch->lli + 12,
 194                                                    MEMTXATTRS_UNSPECIFIED,
 195                                                    NULL);
 196                    ch->lli = address_space_ldl_le(&s->downstream_as,
 197                                                   ch->lli + 8,
 198                                                   MEMTXATTRS_UNSPECIFIED,
 199                                                   NULL);
 200                } else {
 201                    ch->conf &= ~PL080_CCONF_E;
 202                }
 203                if (ch->ctrl & PL080_CCTRL_I) {
 204                    s->tc_int |= 1 << c;
 205                }
 206            }
 207            goto again;
 208        }
 209        if (--s->running)
 210            s->running = 1;
 211    }
 212}
 213
 214static uint64_t pl080_read(void *opaque, hwaddr offset,
 215                           unsigned size)
 216{
 217    PL080State *s = (PL080State *)opaque;
 218    uint32_t i;
 219    uint32_t mask;
 220
 221    if (offset >= 0xfe0 && offset < 0x1000) {
 222        if (s->nchannels == 8) {
 223            return pl080_id[(offset - 0xfe0) >> 2];
 224        } else {
 225            return pl081_id[(offset - 0xfe0) >> 2];
 226        }
 227    }
 228    if (offset >= 0x100 && offset < 0x200) {
 229        i = (offset & 0xe0) >> 5;
 230        if (i >= s->nchannels)
 231            goto bad_offset;
 232        switch ((offset >> 2) & 7) {
 233        case 0: /* SrcAddr */
 234            return s->chan[i].src;
 235        case 1: /* DestAddr */
 236            return s->chan[i].dest;
 237        case 2: /* LLI */
 238            return s->chan[i].lli;
 239        case 3: /* Control */
 240            return s->chan[i].ctrl;
 241        case 4: /* Configuration */
 242            return s->chan[i].conf;
 243        default:
 244            goto bad_offset;
 245        }
 246    }
 247    switch (offset >> 2) {
 248    case 0: /* IntStatus */
 249        return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
 250    case 1: /* IntTCStatus */
 251        return (s->tc_int & s->tc_mask);
 252    case 3: /* IntErrorStatus */
 253        return (s->err_int & s->err_mask);
 254    case 5: /* RawIntTCStatus */
 255        return s->tc_int;
 256    case 6: /* RawIntErrorStatus */
 257        return s->err_int;
 258    case 7: /* EnbldChns */
 259        mask = 0;
 260        for (i = 0; i < s->nchannels; i++) {
 261            if (s->chan[i].conf & PL080_CCONF_E)
 262                mask |= 1 << i;
 263        }
 264        return mask;
 265    case 8: /* SoftBReq */
 266    case 9: /* SoftSReq */
 267    case 10: /* SoftLBReq */
 268    case 11: /* SoftLSReq */
 269        /* ??? Implement these. */
 270        return 0;
 271    case 12: /* Configuration */
 272        return s->conf;
 273    case 13: /* Sync */
 274        return s->sync;
 275    default:
 276    bad_offset:
 277        qemu_log_mask(LOG_GUEST_ERROR,
 278                      "pl080_read: Bad offset %x\n", (int)offset);
 279        return 0;
 280    }
 281}
 282
 283static void pl080_write(void *opaque, hwaddr offset,
 284                        uint64_t value, unsigned size)
 285{
 286    PL080State *s = (PL080State *)opaque;
 287    int i;
 288
 289    if (offset >= 0x100 && offset < 0x200) {
 290        i = (offset & 0xe0) >> 5;
 291        if (i >= s->nchannels)
 292            goto bad_offset;
 293        switch ((offset >> 2) & 7) {
 294        case 0: /* SrcAddr */
 295            s->chan[i].src = value;
 296            break;
 297        case 1: /* DestAddr */
 298            s->chan[i].dest = value;
 299            break;
 300        case 2: /* LLI */
 301            s->chan[i].lli = value;
 302            break;
 303        case 3: /* Control */
 304            s->chan[i].ctrl = value;
 305            break;
 306        case 4: /* Configuration */
 307            s->chan[i].conf = value;
 308            pl080_run(s);
 309            break;
 310        }
 311        return;
 312    }
 313    switch (offset >> 2) {
 314    case 2: /* IntTCClear */
 315        s->tc_int &= ~value;
 316        break;
 317    case 4: /* IntErrorClear */
 318        s->err_int &= ~value;
 319        break;
 320    case 8: /* SoftBReq */
 321    case 9: /* SoftSReq */
 322    case 10: /* SoftLBReq */
 323    case 11: /* SoftLSReq */
 324        /* ??? Implement these.  */
 325        qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n");
 326        break;
 327    case 12: /* Configuration */
 328        s->conf = value;
 329        if (s->conf & (PL080_CONF_M1 | PL080_CONF_M2)) {
 330            qemu_log_mask(LOG_UNIMP,
 331                          "pl080_write: Big-endian DMA not implemented\n");
 332        }
 333        pl080_run(s);
 334        break;
 335    case 13: /* Sync */
 336        s->sync = value;
 337        break;
 338    default:
 339    bad_offset:
 340        qemu_log_mask(LOG_GUEST_ERROR,
 341                      "pl080_write: Bad offset %x\n", (int)offset);
 342    }
 343    pl080_update(s);
 344}
 345
 346static const MemoryRegionOps pl080_ops = {
 347    .read = pl080_read,
 348    .write = pl080_write,
 349    .endianness = DEVICE_NATIVE_ENDIAN,
 350};
 351
 352static void pl080_reset(DeviceState *dev)
 353{
 354    PL080State *s = PL080(dev);
 355    int i;
 356
 357    s->tc_int = 0;
 358    s->tc_mask = 0;
 359    s->err_int = 0;
 360    s->err_mask = 0;
 361    s->conf = 0;
 362    s->sync = 0;
 363    s->req_single = 0;
 364    s->req_burst = 0;
 365    s->running = 0;
 366
 367    for (i = 0; i < s->nchannels; i++) {
 368        s->chan[i].src = 0;
 369        s->chan[i].dest = 0;
 370        s->chan[i].lli = 0;
 371        s->chan[i].ctrl = 0;
 372        s->chan[i].conf = 0;
 373    }
 374}
 375
 376static void pl080_init(Object *obj)
 377{
 378    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 379    PL080State *s = PL080(obj);
 380
 381    memory_region_init_io(&s->iomem, OBJECT(s), &pl080_ops, s, "pl080", 0x1000);
 382    sysbus_init_mmio(sbd, &s->iomem);
 383    sysbus_init_irq(sbd, &s->irq);
 384    sysbus_init_irq(sbd, &s->interr);
 385    sysbus_init_irq(sbd, &s->inttc);
 386    s->nchannels = 8;
 387}
 388
 389static void pl080_realize(DeviceState *dev, Error **errp)
 390{
 391    PL080State *s = PL080(dev);
 392
 393    if (!s->downstream) {
 394        error_setg(errp, "PL080 'downstream' link not set");
 395        return;
 396    }
 397
 398    address_space_init(&s->downstream_as, s->downstream, "pl080-downstream");
 399}
 400
 401static void pl081_init(Object *obj)
 402{
 403    PL080State *s = PL080(obj);
 404
 405    s->nchannels = 2;
 406}
 407
 408static Property pl080_properties[] = {
 409    DEFINE_PROP_LINK("downstream", PL080State, downstream,
 410                     TYPE_MEMORY_REGION, MemoryRegion *),
 411    DEFINE_PROP_END_OF_LIST(),
 412};
 413
 414static void pl080_class_init(ObjectClass *oc, void *data)
 415{
 416    DeviceClass *dc = DEVICE_CLASS(oc);
 417
 418    dc->vmsd = &vmstate_pl080;
 419    dc->realize = pl080_realize;
 420    dc->props = pl080_properties;
 421    dc->reset = pl080_reset;
 422}
 423
 424static const TypeInfo pl080_info = {
 425    .name          = TYPE_PL080,
 426    .parent        = TYPE_SYS_BUS_DEVICE,
 427    .instance_size = sizeof(PL080State),
 428    .instance_init = pl080_init,
 429    .class_init    = pl080_class_init,
 430};
 431
 432static const TypeInfo pl081_info = {
 433    .name          = TYPE_PL081,
 434    .parent        = TYPE_PL080,
 435    .instance_init = pl081_init,
 436};
 437
 438/* The PL080 and PL081 are the same except for the number of channels
 439   they implement (8 and 2 respectively).  */
 440static void pl080_register_types(void)
 441{
 442    type_register_static(&pl080_info);
 443    type_register_static(&pl081_info);
 444}
 445
 446type_init(pl080_register_types)
 447