qemu/hw/i2c/cadence_i2c.c
<<
>>
Prefs
   1/*
   2 *  Cadence I2C controller
   3 *
   4 *  Copyright (C) 2012 Xilinx Inc.
   5 *  Copyright (C) 2012 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
   6 *
   7 *  This program is free software; you can redistribute it and/or modify it
   8 *  under the terms of the GNU General Public License as published by the
   9 *  Free Software Foundation; either version 2 of the License, or
  10 *  (at your option) any later version.
  11 *
  12 *  This program is distributed in the hope that it will be useful, but WITHOUT
  13 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  15 *  for more details.
  16 *
  17 *  You should have received a copy of the GNU General Public License along
  18 *  with this program; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "qemu/bitops.h"
  23#include "qemu/timer.h"
  24#include "hw/sysbus.h"
  25#include "hw/i2c/i2c.h"
  26#include "qemu/fifo.h"
  27#include "qemu/log.h"
  28
  29#define TYPE_CADENCE_I2C                  "cdns.i2c-r1p10"
  30#define CADENCE_I2C(obj)                  \
  31    OBJECT_CHECK(CadenceI2CState, (obj), TYPE_CADENCE_I2C)
  32
  33/* Cadence I2C memory map */
  34#define R_CONTROL                            (0x00 / 4)
  35#define CONTROL_DIV_A_SHIFT                  14
  36#define CONTROL_DIV_A_WIDTH                  2
  37#define CONTROL_DIV_B_SHIFT                  8
  38#define CONTROL_DIV_B_WIDTH                  6
  39#define CONTROL_CLR_FIFO                     (1 << 6)
  40#define CONTROL_SLVMON                       (1 << 5)
  41#define CONTROL_HOLD                         (1 << 4)
  42#define CONTROL_ACKEN                        (1 << 3)
  43#define CONTROL_NEA                          (1 << 2)
  44#define CONTROL_MS                           (1 << 1)
  45#define CONTROL_RW                           (1 << 0)
  46#define R_STATUS                             (0x04 / 4)
  47#define STATUS_BA                            (1 << 8)
  48#define STATUS_RXOVF                         (1 << 7)
  49#define STATUS_TXDV                          (1 << 6)
  50#define STATUS_RXDV                          (1 << 5)
  51#define STATUS_RXRW                          (1 << 3)
  52#define R_ADDRESS                            (0x08 / 4)
  53#define R_DATA                               (0x0C / 4)
  54#define R_ISR                                (0x10 / 4)
  55#define ISR_RX_UNF                           (1 << 7)
  56#define ISR_TX_OVF                           (1 << 6)
  57#define ISR_RX_OVF                           (1 << 5)
  58#define ISR_SLV_RDY                          (1 << 4)
  59#define ISR_TO                               (1 << 3)
  60#define ISR_NACK                             (1 << 2)
  61#define ISR_DATA                             (1 << 1)
  62#define ISR_COMP                             (1 << 0)
  63#define R_TRANSFER_SIZE                      (0x14 / 4)
  64#define R_SLAVE_MON_PAUSE                    (0x18 / 4)
  65#define R_TIME_OUT                           (0x1c / 4)
  66#define R_INTRPT_MASK                        (0x20 / 4)
  67#define R_INTRPT_ENABLE                      (0x24 / 4)
  68#define R_INTRPT_DISABLE                     (0x28 / 4)
  69#define R_MAX                                (R_INTRPT_DISABLE + 1)
  70
  71/* Just approximate for the moment */
  72
  73#define NS_PER_PCLK 10ull
  74
  75/* FIXME: this struct defintion is generic, may belong in bitops or somewhere
  76 * like that
  77 */
  78
  79typedef struct CadenceI2CRegInfo {
  80    const char *name;
  81    uint32_t ro;
  82    uint32_t wtc;
  83    uint32_t reset;
  84    int width;
  85}  CadenceI2CRegInfo;
  86
  87static const CadenceI2CRegInfo cadence_i2c_reg_info[] = {
  88    [R_CONTROL]        = {.name = "CONTROL", .width = 16,
  89                          .ro = CONTROL_CLR_FIFO | (1 << 7) },
  90    [R_STATUS]         = {.name = "STATUS", .width = 9, .ro = ~0 },
  91    [R_ADDRESS]        = {.name = "ADDRESS", .width = 10 },
  92    [R_DATA]           = {.name = "DATA", .width = 8 },
  93    [R_ISR]            = {.name = "ISR", .width = 10, .wtc = 0x2FF,
  94                          .ro = 0x100 },
  95    [R_TRANSFER_SIZE]  = {.name = "TRANSFER_SIZE", .width = 8 },
  96    [R_SLAVE_MON_PAUSE] = {.name = "SLAVE_MON_PAUSE", .width = 8 },
  97    [R_TIME_OUT]        = {.name = "TIME_OUT", .width = 8},
  98    [R_INTRPT_MASK]    = {.name = "INTRPT_MASK", .width = 10, .ro = ~0,
  99                          .reset = 0x2FF },
 100    [R_INTRPT_ENABLE]  = {.name = "INTRPT_ENABLE", .width = 10, .wtc = ~0 },
 101    [R_INTRPT_DISABLE] = {.name = "INTRPT_DISABLE", .width = 10, .wtc = ~0 },
 102};
 103
 104#ifndef CADENCE_I2C_DEBUG
 105#define CADENCE_I2C_DEBUG 0
 106#endif
 107#define DB_PRINT(fmt, args...) do {\
 108    if (CADENCE_I2C_DEBUG) {\
 109        fprintf(stderr, "CADENCE_I2C: %s:" fmt, __func__, ## args);\
 110    } \
 111} while (0);
 112
 113#define FIFO_WIDTH 16
 114
 115typedef struct CadenceI2CState {
 116    SysBusDevice busdev;
 117    MemoryRegion iomem;
 118    I2CBus *bus;
 119    qemu_irq irq;
 120
 121    QEMUTimer *transfer_timer;
 122
 123    bool rw;
 124
 125    Fifo fifo;
 126    uint32_t regs[R_MAX];
 127} CadenceI2CState;
 128
 129static inline bool cadence_i2c_has_work(CadenceI2CState *s)
 130{
 131    if (!(s->regs[R_STATUS] & STATUS_BA)) {
 132        return false;
 133    }
 134
 135    if (!(s->regs[R_CONTROL] & CONTROL_RW)) { /* write */
 136        if (!(s->regs[R_CONTROL] & CONTROL_HOLD)) {
 137            return true;
 138        }
 139        return !fifo_is_empty(&s->fifo);
 140    } else {
 141        if ((s->regs[R_CONTROL] & CONTROL_HOLD)) {
 142            return !fifo_is_full(&s->fifo) && s->regs[R_TRANSFER_SIZE];
 143        }
 144        return true;
 145    }
 146}
 147
 148static inline void cadence_i2c_update_status(CadenceI2CState *s)
 149{
 150    if (cadence_i2c_has_work(s)) {
 151        uint64_t delay = NS_PER_PCLK;
 152        delay *= extract32(s->regs[R_CONTROL], CONTROL_DIV_A_SHIFT,
 153                           CONTROL_DIV_A_WIDTH) + 1;
 154        delay *= extract32(s->regs[R_CONTROL], CONTROL_DIV_B_SHIFT,
 155                           CONTROL_DIV_B_WIDTH) + 1;
 156        delay *= 10; /* 8 bits + ACK/NACK, approximate as 10 cycles/op */
 157        DB_PRINT("scheduling transfer operation with delay of %lldns\n",
 158                 (unsigned long long)delay);
 159        timer_mod(s->transfer_timer,
 160                  qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + delay);
 161    }
 162
 163    DB_PRINT("irq state: %d\n", !!(s->regs[R_ISR] & ~s->regs[R_INTRPT_MASK]));
 164    qemu_set_irq(s->irq, !!(s->regs[R_ISR] & ~s->regs[R_INTRPT_MASK]));
 165}
 166
 167static void cadence_i2c_do_stop(CadenceI2CState *s)
 168{
 169        if (!(s->regs[R_CONTROL] & CONTROL_HOLD) &&
 170                (s->regs[R_STATUS] & STATUS_BA)) {
 171            DB_PRINT("sending stop condition\n");
 172            i2c_end_transfer(s->bus);
 173            s->regs[R_STATUS] &= ~STATUS_BA;
 174        }
 175}
 176
 177static void cadence_i2c_do_txrx(void *opaque)
 178{
 179    CadenceI2CState *s = opaque;
 180
 181    if (!!(s->regs[R_CONTROL] & CONTROL_RW) != s->rw) {
 182        return;
 183    }
 184
 185    DB_PRINT("doing transfer at time %llx\n",
 186             (unsigned long long)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 187    if (!(s->regs[R_CONTROL] & CONTROL_RW)) { /* write */
 188        if (fifo_is_empty(&s->fifo)) {
 189            cadence_i2c_do_stop(s);
 190        } else {
 191            uint8_t t = fifo_pop8(&s->fifo);
 192            if (i2c_send(s->bus, t)) {
 193                s->regs[R_ISR] |= ISR_NACK;
 194            }
 195            if (fifo_is_empty(&s->fifo)) {
 196                s->regs[R_ISR] |= ISR_COMP;
 197            }
 198            if (s->regs[R_TRANSFER_SIZE]) {
 199                s->regs[R_TRANSFER_SIZE]--;
 200            }
 201            if (s->fifo.num <= 2) {
 202                s->regs[R_ISR] |= ISR_DATA;
 203            }
 204        }
 205    } else { /* read */
 206        /* noting to transfer? - stop */
 207        if (!s->regs[R_TRANSFER_SIZE]) {
 208            cadence_i2c_do_stop(s);
 209            DB_PRINT("stopping read transfer\n");
 210        /* fifo full without hold - overflow */
 211        } else if (fifo_is_full(&s->fifo) &&
 212                   !(s->regs[R_CONTROL] & CONTROL_HOLD)) {
 213            i2c_recv(s->bus);
 214            s->regs[R_ISR] |= ISR_RX_OVF;
 215            s->regs[R_STATUS] |= STATUS_RXOVF;
 216            DB_PRINT("nacking becuase the fifo is full!\n");
 217            i2c_nack(s->bus);
 218            cadence_i2c_do_stop(s);
 219        /* fifo not full - do a byte sucessfully */
 220        } else if (!fifo_is_full(&s->fifo)) {
 221            uint8_t r = i2c_recv(s->bus);
 222            DB_PRINT("receiving from I2C bus: %02x\n", r);
 223            fifo_push8(&s->fifo, r);
 224            s->regs[R_STATUS] |= STATUS_RXDV;
 225            if (s->fifo.num >= FIFO_WIDTH - 2) {
 226                s->regs[R_ISR] |= ISR_DATA;
 227            }
 228            if (!(s->regs[R_CONTROL] & CONTROL_ACKEN)) {
 229                i2c_nack(s->bus);
 230            }
 231            s->regs[R_TRANSFER_SIZE]--;
 232            if (!s->regs[R_TRANSFER_SIZE]) {
 233                DB_PRINT("Nacking last byte of read transaction\n");
 234                i2c_nack(s->bus);
 235                s->regs[R_ISR] |= ISR_COMP;
 236            }
 237        }
 238        /* fallthrough with no action if fifo full with HOLD==1 */
 239    }
 240
 241    cadence_i2c_update_status(s);
 242}
 243
 244static inline void cadence_i2c_check_reg_access(hwaddr offset, uint32_t val,
 245                                                bool rnw)
 246{
 247    if (!cadence_i2c_reg_info[offset >> 2].name) {
 248        qemu_log_mask(LOG_UNIMP, "cadence i2c: %s offset %x\n",
 249                      rnw ? "read from" : "write to", (unsigned)offset);
 250        DB_PRINT("%s offset %x\n",
 251                      rnw ? "read from" : "write to", (unsigned)offset);
 252    } else {
 253        DB_PRINT("%s %s [%#02x] %s %#08x\n", rnw ? "read" : "write",
 254                 cadence_i2c_reg_info[offset >> 2].name, (unsigned) offset,
 255                 rnw ? "->" : "<-", val);
 256    }
 257}
 258
 259static uint64_t cadence_i2c_read(void *opaque, hwaddr offset,
 260                                 unsigned size)
 261{
 262    CadenceI2CState *s = (CadenceI2CState *)opaque;
 263    const CadenceI2CRegInfo *info = &cadence_i2c_reg_info[offset >> 2];
 264    uint32_t ret = s->regs[offset >> 2];
 265
 266    cadence_i2c_check_reg_access(offset, ret, true);
 267    if (!info->name) {
 268        return 0;
 269    }
 270    ret &= (1ull << info->width) - 1;
 271
 272    if (offset >> 2 == R_DATA) {
 273        if (fifo_is_empty(&s->fifo)) {
 274            s->regs[R_ISR] |= ISR_RX_UNF;
 275        } else {
 276            s->regs[R_STATUS] &= ~STATUS_RXOVF;
 277            ret = fifo_pop8(&s->fifo);
 278            if (fifo_is_empty(&s->fifo)) {
 279                s->regs[R_STATUS] &= ~STATUS_RXDV;
 280            }
 281        }
 282        cadence_i2c_update_status(s);
 283    }
 284    return ret;
 285}
 286
 287static void cadence_i2c_write(void *opaque, hwaddr offset,
 288                              uint64_t value, unsigned size)
 289{
 290    CadenceI2CState *s = (CadenceI2CState *)opaque;
 291    const CadenceI2CRegInfo *info = &cadence_i2c_reg_info[offset >> 2];
 292    uint32_t new_value = value;
 293    uint32_t ro_mask;
 294
 295    cadence_i2c_check_reg_access(offset, value, false);
 296    if (!info->name) {
 297        return;
 298    }
 299    offset >>= 2;
 300    assert(!(info->wtc & info->ro));
 301    /* preserve read-only and write to clear bits */
 302    ro_mask = info->ro | info->wtc | ~((1ull << info->width) - 1);
 303    new_value &= ~ro_mask;
 304    new_value |= ro_mask & s->regs[offset];
 305    /* do write to clear */
 306    new_value &= ~(value & info->wtc);
 307    s->regs[offset] = new_value;
 308
 309    switch (offset) {
 310    case R_CONTROL:
 311        if (value & CONTROL_CLR_FIFO) {
 312            DB_PRINT("clearing fifo\n");
 313            s->regs[R_TRANSFER_SIZE] = 0;
 314            s->regs[R_STATUS] &= ~STATUS_RXOVF;
 315            fifo_reset(&s->fifo);
 316        }
 317        if (!(value & CONTROL_HOLD)) {
 318            bool idle = s->regs[R_CONTROL] & CONTROL_RW ?
 319                        !s->regs[R_TRANSFER_SIZE] : fifo_is_empty(&s->fifo);
 320            if (idle) {
 321                cadence_i2c_do_stop(s);
 322            }
 323        }
 324        break;
 325    case R_ADDRESS:
 326        s->rw = s->regs[R_CONTROL] & CONTROL_RW;
 327        if (!(s->regs[R_CONTROL] & CONTROL_NEA)) {
 328            qemu_log_mask(LOG_UNIMP, "cadence i2c: 10 bit addressing selected "
 329                          "(unimplmented)");
 330        }
 331        if (i2c_start_transfer(s->bus, new_value & 0x7f,
 332                               s->regs[R_CONTROL] & CONTROL_RW)) {
 333            DB_PRINT("No match for device 0x%x\n", new_value);
 334        } else {
 335            DB_PRINT("device 0x%x probe success\n", new_value);
 336            if (s->regs[R_CONTROL] & CONTROL_SLVMON) {
 337                /* Set "device found" in slave monitor mode */
 338                s->regs[R_ISR] |= ISR_SLV_RDY;
 339            } else {
 340                s->regs[R_STATUS] |= STATUS_BA;
 341            }
 342        }
 343        break;
 344    case R_DATA:
 345        if (fifo_is_full(&s->fifo)) {
 346            s->regs[R_ISR] |= ISR_TX_OVF;
 347        } else {
 348            s->regs[R_TRANSFER_SIZE]++;
 349            fifo_push8(&s->fifo, new_value);
 350        }
 351        break;
 352    case R_INTRPT_ENABLE:
 353        s->regs[R_INTRPT_MASK] &= ~value;
 354        break;
 355    case R_INTRPT_DISABLE:
 356        s->regs[R_INTRPT_MASK] |= value;
 357        break;
 358    }
 359    cadence_i2c_update_status(s);
 360}
 361
 362static const MemoryRegionOps cadence_i2c_ops = {
 363    .read = cadence_i2c_read,
 364    .write = cadence_i2c_write,
 365    .endianness = DEVICE_NATIVE_ENDIAN,
 366};
 367
 368static const VMStateDescription cadence_i2c_vmstate = {
 369    .name = TYPE_CADENCE_I2C,
 370    .version_id = 1,
 371    .minimum_version_id = 1,
 372    .fields = (VMStateField[]) {
 373        VMSTATE_FIFO(fifo, CadenceI2CState),
 374        VMSTATE_UINT32_ARRAY(regs, CadenceI2CState, R_MAX),
 375        VMSTATE_TIMER_PTR(transfer_timer, CadenceI2CState),
 376        VMSTATE_END_OF_LIST()
 377    }
 378};
 379
 380static void cadence_i2c_reset(DeviceState *d)
 381{
 382    CadenceI2CState *s = CADENCE_I2C(d);
 383    int i;
 384
 385    timer_del(s->transfer_timer);
 386    for (i = 0; i < R_MAX; ++i) {
 387        s->regs[i] = cadence_i2c_reg_info[i].name ?
 388                cadence_i2c_reg_info[i].reset : 0;
 389    }
 390    fifo_reset(&s->fifo);
 391}
 392
 393static void cadence_i2c_realize(DeviceState *dev, Error **errp)
 394{
 395    CadenceI2CState *s = CADENCE_I2C(dev);
 396    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 397
 398    memory_region_init_io(&s->iomem, OBJECT(dev), &cadence_i2c_ops, s,
 399                          TYPE_CADENCE_I2C, R_MAX * 4);
 400    sysbus_init_mmio(sbd, &s->iomem);
 401    sysbus_init_irq(sbd, &s->irq);
 402
 403    s->bus = i2c_init_bus(dev, "i2c");
 404
 405    s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cadence_i2c_do_txrx,
 406                                     s);
 407
 408    fifo_create8(&s->fifo, FIFO_WIDTH);
 409}
 410
 411static void cadence_i2c_class_init(ObjectClass *klass, void *data)
 412{
 413    DeviceClass *dc = DEVICE_CLASS(klass);
 414
 415    dc->vmsd = &cadence_i2c_vmstate;
 416    dc->reset = cadence_i2c_reset;
 417    dc->realize = cadence_i2c_realize;
 418}
 419
 420static const TypeInfo cadence_i2c_type_info = {
 421    .name = TYPE_CADENCE_I2C,
 422    .parent = TYPE_SYS_BUS_DEVICE,
 423    .instance_size = sizeof(CadenceI2CState),
 424    .class_init = cadence_i2c_class_init,
 425};
 426
 427static void cadence_i2c_register_types(void)
 428{
 429    type_register_static(&cadence_i2c_type_info);
 430}
 431
 432type_init(cadence_i2c_register_types)
 433