qemu/hw/misc/pmc_sbi.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the PMC SBI
   3 *
   4 * Copyright (c) 2020 Xilinx Inc
   5 *
   6 * This code is licensed under the GNU GPL.
   7 */
   8#include "qemu/osdep.h"
   9#include "hw/sysbus.h"
  10#include "chardev/char.h"
  11#include "chardev/char-fe.h"
  12#include "migration/vmstate.h"
  13#include "hw/qdev-properties.h"
  14#include "hw/register.h"
  15#include "hw/irq.h"
  16#include "qemu/fifo.h"
  17#include "hw/remote-port-proto.h"
  18#include "hw/remote-port-device.h"
  19#include "hw/stream.h"
  20#include "qemu/log.h"
  21#include "hw/fdt_generic_util.h"
  22
  23REG32(SBI_MODE, 0x0)
  24    FIELD(SBI_MODE, JTAG, 1, 1)
  25    FIELD(SBI_MODE, SELECT, 0, 1)
  26REG32(SBI_CTRL, 0x4)
  27    FIELD(SBI_CTRL, APB_ERR_RES, 5, 1)
  28    FIELD(SBI_CTRL, INTERFACE, 2, 3)
  29    FIELD(SBI_CTRL, SOFT_RST, 1, 1)
  30    FIELD(SBI_CTRL, ENABLE, 0, 1)
  31REG32(SMAP_CTRL, 0x8)
  32    FIELD(SMAP_CTRL, BURST_SIZE, 1, 2)
  33    FIELD(SMAP_CTRL, MODE, 0, 1)
  34REG32(SBI_IRQ_STATUS, 0x300)
  35    FIELD(SBI_IRQ_STATUS, DATA_RDY, 2, 1)
  36    FIELD(SBI_IRQ_STATUS, SMAP_ABORT, 1, 1)
  37    FIELD(SBI_IRQ_STATUS, INV_APB, 0, 1)
  38REG32(SBI_IRQ_MASK, 0x304)
  39    FIELD(SBI_IRQ_MASK, DATA_RDY, 2, 1)
  40    FIELD(SBI_IRQ_MASK, SMAP_ABORT, 1, 1)
  41    FIELD(SBI_IRQ_MASK, INV_APB, 0, 1)
  42REG32(SBI_IRQ_ENABLE, 0x308)
  43    FIELD(SBI_IRQ_ENABLE, DATA_RDY, 2, 1)
  44    FIELD(SBI_IRQ_ENABLE, SMAP_ABORT, 1, 1)
  45    FIELD(SBI_IRQ_ENABLE, INV_APB, 0, 1)
  46REG32(SBI_IRQ_DISABLE, 0x30c)
  47    FIELD(SBI_IRQ_DISABLE, DATA_RDY, 2, 1)
  48    FIELD(SBI_IRQ_DISABLE, SMAP_ABORT, 1, 1)
  49    FIELD(SBI_IRQ_DISABLE, INV_APB, 0, 1)
  50REG32(SBI_IRQ_TRIGGER, 0x310)
  51    FIELD(SBI_IRQ_TRIGGER, DATA_RDY, 2, 1)
  52    FIELD(SBI_IRQ_TRIGGER, SMAP_ABORT, 1, 1)
  53    FIELD(SBI_IRQ_TRIGGER, INV_APB, 0, 1)
  54REG32(SBI_RAM, 0x500)
  55    FIELD(SBI_RAM, EMASA, 6, 1)
  56    FIELD(SBI_RAM, EMAB, 3, 3)
  57    FIELD(SBI_RAM, EMAA, 0, 3)
  58REG32(SBI_ECO, 0x1000)
  59
  60#define R_MAX (R_SBI_ECO + 1)
  61
  62#define SMAP_INTERFACE      0
  63#define JTAG_INTERFACE      1
  64#define AXI_SLAVE_INTERFACE 2
  65
  66#define SBI_DATA_LOADING_MODE 0
  67#define SBI_READ_BACK_MODE    1
  68
  69#define SMAP_NORMAL_MODE 0
  70#define SMAP_BURST_MODE  1
  71
  72#define SMAP_CS_B    1
  73#define SMAP_RDWR_B  0
  74
  75#define TYPE_SBI "pmc.slave-boot"
  76
  77#define SBI(obj) \
  78    OBJECT_CHECK(SlaveBootInt, (obj), TYPE_SBI)
  79
  80#ifndef SBI_ERR_DEBUG
  81#define SBI_ERR_DEBUG 0
  82#endif
  83
  84#define DPRINT(args, ...) \
  85    do { \
  86        if (SBI_ERR_DEBUG) { \
  87            fprintf(stderr, args, ## __VA_ARGS__); \
  88        } \
  89    } while (0)
  90
  91#define IF_BURST(pnum) \
  92    (ARRAY_FIELD_EX32(s->regs, SMAP_CTRL, MODE) == SMAP_BURST_MODE && \
  93     ARRAY_FIELD_EX32(s->regs, SBI_CTRL, INTERFACE) == SMAP_INTERFACE && \
  94     (pnum >= (1 << ARRAY_FIELD_EX32(s->regs, SMAP_CTRL, BURST_SIZE)) * 1024))
  95
  96#define IF_NON_BURST(pnum) \
  97    ((ARRAY_FIELD_EX32(s->regs, SMAP_CTRL, MODE) == SMAP_NORMAL_MODE) && \
  98     (pnum >= 4))
  99
 100#define SMAP_BURST_SIZE(s) \
 101        ((1 << ARRAY_FIELD_EX32(s->regs, SMAP_CTRL, BURST_SIZE)) * 1024)
 102
 103typedef struct SlaveBootInt {
 104    SysBusDevice parent_obj;
 105
 106    StreamSlave *tx_dev;
 107    Fifo fifo;
 108    qemu_irq irq;
 109    StreamCanPushNotifyFn notify;
 110    void *notify_opaque;
 111    MemoryRegion iomem;
 112    uint32_t regs[R_MAX];
 113    RegisterInfo regs_info[R_MAX];
 114    int BusWidthDetectCounter;
 115
 116    /* Select Map */
 117    uint8_t cs;           /* active low */
 118    uint8_t busy_line;    /* active high */
 119    uint8_t rdwr;         /* 0: data load
 120                           * 1: read-back */
 121    CharBackend chr; /* Data bus */
 122    qemu_irq smap_busy;
 123} SlaveBootInt;
 124
 125static int sbi_can_receive_from_dma(SlaveBootInt *s)
 126{
 127    if (!ARRAY_FIELD_EX32(s->regs, SBI_MODE, SELECT)) {
 128        return 1;
 129    }
 130
 131    if (IF_BURST(fifo_num_free(&s->fifo))) {
 132        return 0;
 133    }
 134
 135    if (IF_NON_BURST(fifo_num_free(&s->fifo))) {
 136        return 0;
 137    }
 138
 139    return 1;
 140}
 141
 142static void sbi_update_irq(SlaveBootInt *s)
 143{
 144    bool pending;
 145
 146    if (IF_BURST(s->fifo.num)) {
 147        ARRAY_FIELD_DP32(s->regs, SBI_IRQ_STATUS, DATA_RDY, 1);
 148    }
 149
 150    if (IF_NON_BURST(s->fifo.num)) {
 151        ARRAY_FIELD_DP32(s->regs, SBI_IRQ_STATUS, DATA_RDY, 1);
 152    }
 153    pending = !!(s->regs[R_SBI_IRQ_STATUS] & ~s->regs[R_SBI_IRQ_MASK]);
 154    qemu_set_irq(s->irq, pending);
 155}
 156
 157static void ss_update_busy_line(SlaveBootInt *s)
 158{
 159    uint32_t num = fifo_num_free(&s->fifo);
 160
 161    if (!ARRAY_FIELD_EX32(s->regs, SBI_CTRL, ENABLE)) {
 162        s->busy_line = 1;
 163        goto update_busy;
 164    }
 165
 166    if (ARRAY_FIELD_EX32(s->regs, SMAP_CTRL, MODE) == SMAP_BURST_MODE) {
 167        if (ARRAY_FIELD_EX32(s->regs, SBI_MODE, SELECT)
 168            == SBI_DATA_LOADING_MODE) {
 169            s->busy_line = (num >= SMAP_BURST_SIZE(s)) ? 0 : 1;
 170        } else {
 171            /* Read Back Mode */
 172            s->busy_line = (s->fifo.num >= SMAP_BURST_SIZE(s)) ?
 173                        0 : 1;
 174            if (s->notify) {
 175                s->notify(s->notify_opaque);
 176            }
 177        }
 178    } else {
 179        /* Normal Mode: Busy Line status changes for availablity of 4byte
 180         * data/free-space while data-load/read-back
 181         */
 182        if (ARRAY_FIELD_EX32(s->regs, SBI_MODE, SELECT)
 183            == SBI_DATA_LOADING_MODE) {
 184            s->busy_line = num >= 4 ? 0 : 1;
 185        } else {
 186            s->busy_line = s->fifo.num >= 4 ? 0 : 1;
 187            if (s->notify) {
 188                s->notify(s->notify_opaque);
 189            }
 190        }
 191    }
 192update_busy:
 193    /* FIXME: Update only if SMAP interface selected*/
 194    qemu_set_irq(s->smap_busy, s->busy_line);
 195}
 196
 197static void ss_stream_out(SlaveBootInt *s);
 198static void smap_data_rdwr(SlaveBootInt *s)
 199{
 200    if (!s->cs) {
 201        if (!s->rdwr) {
 202            qemu_chr_fe_accept_input(&s->chr);
 203        } else {
 204            ss_stream_out(s);
 205        }
 206    }
 207
 208    ss_update_busy_line(s);
 209    sbi_update_irq(s);
 210}
 211
 212static void ss_reset(DeviceState *);
 213
 214static void sbi_ctrl_postw(RegisterInfo *reg, uint64_t val64)
 215{
 216    SlaveBootInt *s = SBI(reg->opaque);
 217    uint32_t val = val64;
 218
 219    if (val & R_SBI_CTRL_SOFT_RST_MASK) {
 220        ss_reset(DEVICE(s));
 221        ARRAY_FIELD_DP32(s->regs, SBI_CTRL, SOFT_RST, 0);
 222    }
 223
 224    ss_update_busy_line(s);
 225}
 226
 227static uint64_t sbi_mode_prew(RegisterInfo *reg, uint64_t val64)
 228{
 229    SlaveBootInt *s = SBI(reg->opaque);
 230    uint32_t val = val64;
 231
 232    if (!s->cs) {
 233        if ((s->regs[R_SBI_MODE] & R_SBI_MODE_SELECT_MASK) ^
 234            (val & R_SBI_MODE_SELECT_MASK) && s->smap_busy) {
 235            DPRINT("Warning: Changing SBI mode when cs is asserted\n");
 236        }
 237    }
 238
 239    if (!s->smap_busy) {
 240        s->rdwr = FIELD_EX32(val, SBI_MODE, SELECT);
 241    }
 242    return val64;
 243}
 244
 245static uint64_t sbi_irq_enable_prew(RegisterInfo *reg, uint64_t val64)
 246{
 247
 248    SlaveBootInt *s = SBI(reg->opaque);
 249    uint32_t val = val64;
 250
 251    s->regs[R_SBI_IRQ_MASK] &= ~val;
 252    return 0;
 253}
 254
 255static uint64_t sbi_irq_disable_prew(RegisterInfo *reg, uint64_t val64)
 256{
 257    SlaveBootInt *s = SBI(reg->opaque);
 258    uint32_t val = val64;
 259
 260    s->regs[R_SBI_IRQ_MASK] |= val;
 261    return 0;
 262}
 263
 264static uint64_t sbi_irq_trigger_prew(RegisterInfo *reg, uint64_t val64)
 265{
 266    SlaveBootInt *s = SBI(reg->opaque);
 267    uint32_t val = val64;
 268
 269    s->regs[R_SBI_IRQ_STATUS] |= val;
 270    return 0;
 271}
 272
 273static void ss_stream_notify(void *opaque)
 274{
 275    SlaveBootInt *s = SBI(opaque);
 276    uint32_t num = 0;
 277    uint8_t *data;
 278
 279    while (stream_can_push(s->tx_dev, ss_stream_notify, s)) {
 280        if (fifo_is_empty(&s->fifo) || fifo_num_used(&s->fifo) < 4) {
 281            break;
 282        }
 283        /* num is equal to number of bytes read as its a fifo of width 1byte.
 284         * the same dosent holds good if width is grater than 1 byte
 285         */
 286        data = (uint8_t *) fifo_pop_buf(&s->fifo,
 287                        4, &num);
 288
 289        stream_push(s->tx_dev, data, num, false);
 290    }
 291    ss_update_busy_line(s);
 292    sbi_update_irq(s);
 293}
 294
 295static void ss_stream_out(SlaveBootInt *s)
 296{
 297    uint8_t *data;
 298    uint32_t len;
 299
 300    if (!ARRAY_FIELD_EX32(s->regs, SBI_MODE, SELECT)) {
 301        return;
 302    }
 303
 304    /*FIXME: Impement JTAG, AXI interface */
 305    while (!s->cs && s->rdwr) {
 306        if (IF_BURST(s->fifo.num)) {
 307            data = (uint8_t *) fifo_pop_buf(&s->fifo,
 308                        SMAP_BURST_SIZE(s),
 309                        &len);
 310            qemu_chr_fe_write(&s->chr, data, len);
 311        }
 312
 313        if (IF_NON_BURST(s->fifo.num)) {
 314            data = (uint8_t *) fifo_pop_buf(&s->fifo, 4, &len);
 315            qemu_chr_fe_write(&s->chr, data, len);
 316        }
 317
 318        ss_update_busy_line(s);
 319        if (s->busy_line) {
 320            break;
 321        }
 322    }
 323}
 324
 325static bool ss_stream_can_push(StreamSlave *obj,
 326                StreamCanPushNotifyFn notify,
 327                void *notify_opaque)
 328{
 329    SlaveBootInt *s = SBI(obj);
 330    /* FIXME: Check for SMAP mode
 331     *        Add AXI Slave interface
 332     *        Add JTAG Interface
 333     */
 334
 335    if (!s->smap_busy) {
 336        smap_data_rdwr(s);
 337    }
 338    if (sbi_can_receive_from_dma(s)) {
 339        /* return false and store the notify opts */
 340        s->notify = notify;
 341        s->notify_opaque = notify_opaque;
 342        return false;
 343    } else {
 344        /* Read to receive */
 345        s->notify = NULL;
 346        s->notify_opaque = NULL;
 347        return true;
 348    }
 349}
 350
 351static size_t ss_stream_push(StreamSlave *obj, uint8_t *buf, size_t len,
 352                             bool eop)
 353{
 354    SlaveBootInt *s = SBI(obj);
 355    uint32_t free = fifo_num_free(&s->fifo);
 356
 357    /* FIXME: Implement Other Interfaces mentioned above */
 358    fifo_push_all(&s->fifo, buf, free);
 359    ss_update_busy_line(s);
 360    sbi_update_irq(s);
 361    return free > len ? len : free;
 362}
 363
 364/*** Chardev Stream handlers */
 365static int ss_sbi_can_receive(void *opaque)
 366{
 367    SlaveBootInt *s = SBI(opaque);
 368    uint32_t num = fifo_num_free(&s->fifo);
 369    uint32_t recvb = 0;
 370
 371    if (s->cs || s->rdwr) {
 372        /* Data lines are in tristate when cs is high or
 373         * Master is in Read back mode
 374         * */
 375        return 0;
 376    }
 377
 378    /* Check for Busy Line
 379     * Check on Fifo Space
 380     */
 381    if (ARRAY_FIELD_EX32(s->regs, SBI_CTRL, ENABLE) &&
 382        !ARRAY_FIELD_EX32(s->regs, SBI_MODE, SELECT)) {
 383        if (IF_BURST(num)) {
 384            recvb = (1 << ARRAY_FIELD_EX32(s->regs, SMAP_CTRL, BURST_SIZE)) *
 385                     1024;
 386        } else if (num >= 4) {
 387            recvb = 4;
 388        }
 389        /* if busy line is low */
 390        if (!s->busy_line) {
 391            return recvb;
 392        }
 393    }
 394    return 0;
 395}
 396
 397static void ss_sbi_receive(void *opaque, const uint8_t *buf, int size)
 398{
 399    SlaveBootInt *s = SBI(opaque);
 400    uint32_t free = fifo_num_free(&s->fifo);
 401
 402    while (s->BusWidthDetectCounter < 16) {
 403        /* First 16 bytes are used by harware for input port width
 404         * detection. We dont need to do that, so discard without
 405         * copying them to buffer
 406         */
 407        s->BusWidthDetectCounter++;
 408        buf++;
 409        size--;
 410        if (!size) {
 411            break;
 412        }
 413    }
 414
 415    DPRINT("%s: Payload of size: %d recv\n", __func__, size);
 416    if (size <= free) {
 417        fifo_push_all(&s->fifo, buf, size);
 418        if (IF_BURST(free)) {
 419            ss_stream_notify(s);
 420            ARRAY_FIELD_DP32(s->regs, SBI_IRQ_STATUS, DATA_RDY, 1);
 421        }
 422
 423        if (IF_NON_BURST(free)) {
 424            ss_stream_notify(s);
 425            ARRAY_FIELD_DP32(s->regs, SBI_IRQ_STATUS, DATA_RDY, 1);
 426        }
 427    }
 428
 429    ss_update_busy_line(s);
 430    sbi_update_irq(s);
 431}
 432/***/
 433
 434static void smap_update(void *opaque, int n, int level)
 435{
 436    SlaveBootInt *s = SBI(opaque);
 437    switch (n) {
 438    case SMAP_CS_B:
 439        s->cs = level;
 440        break;
 441    case SMAP_RDWR_B:
 442        if (!s->cs && (s->rdwr ^ level)) {
 443            ARRAY_FIELD_DP32(s->regs, SBI_IRQ_STATUS, SMAP_ABORT, 1);
 444        }
 445        s->rdwr = level;
 446        break;
 447    };
 448    smap_data_rdwr(s);
 449}
 450
 451static RegisterAccessInfo slave_boot_regs_info[] = {
 452    {   .name = "SBI_MODE",  .addr = A_SBI_MODE,
 453        .reset = 0x2,
 454        .rsvd = 0xfffffffe,
 455        .pre_write = sbi_mode_prew,
 456    },{ .name = "SBI_CTRL",  .addr = A_SBI_CTRL,
 457        .reset = 0x20,
 458        .rsvd = 0xffffffc0,
 459        .post_write = sbi_ctrl_postw,
 460    },{ .name = "SMAP_CTRL",  .addr = A_SMAP_CTRL,
 461        .rsvd = 0xfffffff8,
 462    },{ .name = "SBI_IRQ_STATUS",  .addr = A_SBI_IRQ_STATUS,
 463        .rsvd = 0xfffffff8,
 464        .w1c = 0x7,
 465    },{ .name = "SBI_IRQ_MASK",  .addr = A_SBI_IRQ_MASK,
 466        .reset = 0x7,
 467        .rsvd = 0xfffffff8,
 468        .ro = 0x7,
 469    },{ .name = "SBI_IRQ_ENABLE",  .addr = A_SBI_IRQ_ENABLE,
 470        .rsvd = 0xfffffff8,
 471        .pre_write = sbi_irq_enable_prew,
 472    },{ .name = "SBI_IRQ_DISABLE",  .addr = A_SBI_IRQ_DISABLE,
 473        .rsvd = 0xfffffff8,
 474        .pre_write = sbi_irq_disable_prew,
 475    },{ .name = "SBI_IRQ_TRIGGER",  .addr = A_SBI_IRQ_TRIGGER,
 476        .rsvd = 0xfffffff8,
 477        .pre_write = sbi_irq_trigger_prew,
 478    },{ .name = "SBI_RAM",  .addr = A_SBI_RAM,
 479        .reset = 0x5b,
 480        .rsvd = 0xffffff80,
 481    },{ .name = "SBI_ECO",  .addr = A_SBI_ECO,
 482    }
 483};
 484
 485static void sbi_write(void *opaque, hwaddr addr, uint64_t value,
 486                      unsigned size)
 487{
 488    RegisterInfoArray *reg_array = opaque;
 489    SlaveBootInt *s = SBI(reg_array->r[0]->opaque);
 490
 491    register_write_memory(opaque, addr, value, size);
 492    smap_data_rdwr(s);
 493}
 494
 495static const MemoryRegionOps ss_ops = {
 496    .read = register_read_memory,
 497    .write = sbi_write,
 498    .endianness = DEVICE_LITTLE_ENDIAN,
 499    .valid = {
 500        .min_access_size = 4,
 501        .max_access_size = 4
 502    }
 503};
 504
 505static void ss_realize(DeviceState *dev, Error **errp)
 506{
 507    SlaveBootInt *s = SBI(dev);
 508    const char *port_name;
 509    Chardev *chr;
 510
 511    port_name = g_strdup("smap_busy_b");
 512    qdev_init_gpio_out_named(dev, &s->smap_busy, port_name, 1);
 513    g_free((gpointer) port_name);
 514
 515    port_name = g_strdup("smap_in_b");
 516    qdev_init_gpio_in_named(dev, smap_update, port_name, 2);
 517    g_free((gpointer) port_name);
 518
 519    chr = qemu_chr_find("sbi");
 520    qdev_prop_set_chr(dev, "chardev", chr);
 521    if (!qemu_chr_fe_get_driver(&s->chr)) {
 522        DPRINT("SBI interface not connected\n");
 523    } else {
 524        qemu_chr_fe_set_handlers(&s->chr, ss_sbi_can_receive, ss_sbi_receive,
 525                                 NULL, NULL, s, NULL, true);
 526    }
 527
 528    fifo_create8(&s->fifo, 1024 * 4);
 529}
 530
 531static void ss_reset(DeviceState *dev)
 532{
 533    SlaveBootInt *s = SBI(dev);
 534    uint32_t i;
 535
 536    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 537        register_reset(&s->regs_info[i]);
 538    }
 539    fifo_reset(&s->fifo);
 540    s->busy_line = 1;
 541    qemu_set_irq(s->smap_busy, s->busy_line);
 542    ss_update_busy_line(s);
 543    sbi_update_irq(s);
 544    /* Note : cs always 0 when rp is not connected
 545     * i.e slave always respond to master data irrespective of
 546     * master state
 547     *
 548     * as rdwr is also 0, initial state of sbi is data load. Hack this bit
 549     * to become 1, when sbi changes to write mode. So, its assumed in
 550     * non remote-port model master should expect data when slave wishes
 551     * to send.
 552     */
 553}
 554
 555static void ss_init(Object *obj)
 556{
 557    SlaveBootInt *s = SBI(obj);
 558    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 559    RegisterInfoArray *reg_array;
 560
 561    object_property_add_link(obj, "stream-connected-sbi", TYPE_STREAM_SLAVE,
 562                             (Object **)&s->tx_dev,
 563                             qdev_prop_allow_set_link_before_realize,
 564                             OBJ_PROP_LINK_STRONG);
 565
 566    memory_region_init(&s->iomem, obj, TYPE_SBI, R_MAX * 4);
 567    reg_array =
 568        register_init_block32(DEVICE(obj), slave_boot_regs_info,
 569                              ARRAY_SIZE(slave_boot_regs_info),
 570                              s->regs_info, s->regs,
 571                              &ss_ops,
 572                              false,
 573                              R_MAX * 4);
 574    memory_region_add_subregion(&s->iomem,
 575                                0x0,
 576                                &reg_array->mem);
 577
 578    sysbus_init_mmio(sbd, &s->iomem);
 579    sysbus_init_irq(sbd, &s->irq);
 580}
 581
 582static const FDTGenericGPIOSet sbi_controller_gpios[] = {
 583    {
 584        .names = &fdt_generic_gpio_name_set_gpio,
 585        .gpios = (FDTGenericGPIOConnection []) {
 586            { .name = "smap_busy_b", .fdt_index = 0,
 587              .range = 1},
 588            { },
 589        },
 590    },
 591    { },
 592};
 593
 594static const FDTGenericGPIOSet sbi_client_gpios[] = {
 595    {
 596        .names = &fdt_generic_gpio_name_set_gpio,
 597        .gpios = (FDTGenericGPIOConnection []) {
 598           { .name = "smap_in_b", .fdt_index = 0,
 599             .range = 2},
 600           { },
 601        },
 602    },
 603    { },
 604};
 605
 606static Property sbi_props[] = {
 607        DEFINE_PROP_CHR("chardev", SlaveBootInt, chr),
 608        DEFINE_PROP_END_OF_LIST(),
 609};
 610
 611static void ss_class_init(ObjectClass *klass, void *data)
 612{
 613    DeviceClass *dc = DEVICE_CLASS(klass);
 614    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
 615    FDTGenericGPIOClass *fggc = FDT_GENERIC_GPIO_CLASS(klass);
 616    dc->realize = ss_realize;
 617    dc->reset = ss_reset;
 618    device_class_set_props(dc, sbi_props);
 619    ssc->push = ss_stream_push;
 620    ssc->can_push = ss_stream_can_push;
 621    fggc->controller_gpios = sbi_controller_gpios;
 622    fggc->client_gpios = sbi_client_gpios;
 623}
 624
 625static TypeInfo ss_info = {
 626    .name = TYPE_SBI,
 627    .parent = TYPE_SYS_BUS_DEVICE,
 628    .instance_size = sizeof(SlaveBootInt),
 629    .instance_init = ss_init,
 630    .class_init = ss_class_init,
 631    .interfaces = (InterfaceInfo[]) {
 632        { TYPE_STREAM_SLAVE },
 633        { TYPE_FDT_GENERIC_GPIO},
 634        {}
 635    }
 636};
 637
 638static void ss_register(void)
 639{
 640    type_register_static(&ss_info);
 641}
 642
 643type_init(ss_register)
 644