qemu/hw/core/remote-port-gpio.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013 Xilinx Inc
   3 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   4 * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
   5 *
   6 * This code is licensed under the GNU GPL.
   7 */
   8
   9#include "qemu/osdep.h"
  10#include "hw/sysbus.h"
  11#include "sysemu/sysemu.h"
  12#include "sysemu/dma.h"
  13#include "qemu/log.h"
  14#include "qapi/qmp/qerror.h"
  15#include "qapi/error.h"
  16#include "hw/qdev.h"
  17
  18#include "hw/fdt_generic_util.h"
  19
  20#include "hw/remote-port-proto.h"
  21#include "hw/remote-port-device.h"
  22
  23#define TYPE_REMOTE_PORT_GPIO "remote-port-gpio"
  24#define REMOTE_PORT_GPIO(obj) \
  25        OBJECT_CHECK(RemotePortGPIO, (obj), TYPE_REMOTE_PORT_GPIO)
  26
  27#define MAX_GPIOS 164
  28#define CACHE_INVALID -1
  29
  30typedef struct RemotePortGPIO {
  31    /* private */
  32    SysBusDevice parent;
  33    /* public */
  34
  35    int8_t cache[MAX_GPIOS];
  36    uint32_t num_gpios;
  37    qemu_irq *gpio_out;
  38    uint16_t cell_offset_irq_num;
  39
  40    uint64_t current_id;
  41
  42    uint32_t rp_dev;
  43    struct RemotePort *rp;
  44} RemotePortGPIO;
  45
  46static void rp_gpio_handler(void *opaque, int irq, int level)
  47{
  48    RemotePortGPIO *s = opaque;
  49    struct rp_pkt pkt;
  50    size_t len;
  51    int64_t clk;
  52
  53    /* If we hit the cache, return early.  */
  54    if (s->cache[irq] != CACHE_INVALID && s->cache[irq] == level) {
  55        return;
  56    }
  57    /* Update the cache and update the remote peer.  */
  58    s->cache[irq] = level;
  59
  60    clk = rp_normalized_vmclk(s->rp);
  61    len = rp_encode_interrupt(s->current_id++, s->rp_dev, &pkt.interrupt, clk,
  62                              irq, 0, level);
  63    rp_write(s->rp, (void *)&pkt, len);
  64}
  65
  66static void rp_gpio_interrupt(RemotePortDevice *s, struct rp_pkt *pkt)
  67{
  68    RemotePortGPIO *rpg = REMOTE_PORT_GPIO(s);
  69
  70    qemu_set_irq(rpg->gpio_out[pkt->interrupt.line], pkt->interrupt.val);
  71}
  72
  73static void rp_gpio_reset(DeviceState *dev)
  74{
  75    RemotePortGPIO *s = REMOTE_PORT_GPIO(dev);
  76
  77    /* Mark as invalid.  */
  78    memset(s->cache, CACHE_INVALID, s->num_gpios);
  79}
  80
  81static void rp_gpio_realize(DeviceState *dev, Error **errp)
  82{
  83    RemotePortGPIO *s = REMOTE_PORT_GPIO(dev);
  84    unsigned int i;
  85
  86    s->gpio_out = g_new0(qemu_irq, s->num_gpios);
  87    qdev_init_gpio_out(dev, s->gpio_out, s->num_gpios);
  88    qdev_init_gpio_in(dev, rp_gpio_handler, s->num_gpios);
  89
  90    for (i = 0; i < s->num_gpios; i++) {
  91        sysbus_init_irq(SYS_BUS_DEVICE(s), &s->gpio_out[i]);
  92    }
  93}
  94
  95static void rp_gpio_init(Object *obj)
  96{
  97    RemotePortGPIO *rpms = REMOTE_PORT_GPIO(obj);
  98
  99    object_property_add_link(obj, "rp-adaptor0", "remote-port",
 100                             (Object **)&rpms->rp,
 101                             qdev_prop_allow_set_link_before_realize,
 102                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
 103                             &error_abort);
 104}
 105
 106static Property rp_properties[] = {
 107    DEFINE_PROP_UINT32("rp-chan0", RemotePortGPIO, rp_dev, 0),
 108    DEFINE_PROP_UINT32("num-gpios", RemotePortGPIO, num_gpios, 16),
 109    DEFINE_PROP_UINT16("cell-offset-irq-num", RemotePortGPIO,
 110                       cell_offset_irq_num, 0),
 111    DEFINE_PROP_END_OF_LIST(),
 112};
 113
 114static int rp_fdt_get_irq(FDTGenericIntc *obj, qemu_irq *irqs,
 115                          uint32_t *cells, int ncells, int max,
 116                          Error **errp)
 117{
 118    RemotePortGPIO *s = REMOTE_PORT_GPIO(obj);
 119
 120    if (cells[s->cell_offset_irq_num] >= s->num_gpios) {
 121        error_setg(errp, "RP-GPIO was setup for %u interrupts: index %"
 122                   PRIu32 " requested", s->num_gpios,
 123                   cells[s->cell_offset_irq_num]);
 124        return 0;
 125    }
 126
 127    (*irqs) = qdev_get_gpio_in(DEVICE(obj), cells[s->cell_offset_irq_num]);
 128    return 1;
 129};
 130
 131static void rp_gpio_class_init(ObjectClass *oc, void *data)
 132{
 133    RemotePortDeviceClass *rpdc = REMOTE_PORT_DEVICE_CLASS(oc);
 134    DeviceClass *dc = DEVICE_CLASS(oc);
 135    FDTGenericIntcClass *fgic = FDT_GENERIC_INTC_CLASS(oc);
 136
 137    rpdc->ops[RP_CMD_interrupt] = rp_gpio_interrupt;
 138    dc->reset = rp_gpio_reset;
 139    dc->realize = rp_gpio_realize;
 140    dc->props = rp_properties;
 141    fgic->get_irq = rp_fdt_get_irq;
 142}
 143
 144static const TypeInfo rp_info = {
 145    .name          = TYPE_REMOTE_PORT_GPIO,
 146    .parent        = TYPE_SYS_BUS_DEVICE,
 147    .instance_size = sizeof(RemotePortGPIO),
 148    .instance_init = rp_gpio_init,
 149    .class_init    = rp_gpio_class_init,
 150    .interfaces    = (InterfaceInfo[]) {
 151        { TYPE_REMOTE_PORT_DEVICE },
 152        { TYPE_FDT_GENERIC_INTC },
 153        { },
 154    },
 155};
 156
 157static void rp_register_types(void)
 158{
 159    type_register_static(&rp_info);
 160}
 161
 162type_init(rp_register_types)
 163