qemu/hw/omap_i2c.c
<<
>>
Prefs
   1/*
   2 * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
   3 *
   4 * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation; either version 2 of
   9 * the License, or (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along
  17 * with this program; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include "hw.h"
  20#include "i2c.h"
  21#include "omap.h"
  22
  23struct omap_i2c_s {
  24    qemu_irq irq;
  25    qemu_irq drq[2];
  26    i2c_bus *bus;
  27
  28    uint8_t revision;
  29    uint8_t mask;
  30    uint16_t stat;
  31    uint16_t dma;
  32    uint16_t count;
  33    int count_cur;
  34    uint32_t fifo;
  35    int rxlen;
  36    int txlen;
  37    uint16_t control;
  38    uint16_t addr[2];
  39    uint8_t divider;
  40    uint8_t times[2];
  41    uint16_t test;
  42};
  43
  44#define OMAP2_INTR_REV  0x34
  45#define OMAP2_GC_REV    0x34
  46
  47static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
  48{
  49    qemu_set_irq(s->irq, s->stat & s->mask);
  50    if ((s->dma >> 15) & 1)                                     /* RDMA_EN */
  51        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);            /* RRDY */
  52    if ((s->dma >> 7) & 1)                                      /* XDMA_EN */
  53        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);            /* XRDY */
  54}
  55
  56static void omap_i2c_fifo_run(struct omap_i2c_s *s)
  57{
  58    int ack = 1;
  59
  60    if (!i2c_bus_busy(s->bus))
  61        return;
  62
  63    if ((s->control >> 2) & 1) {                                /* RM */
  64        if ((s->control >> 1) & 1) {                            /* STP */
  65            i2c_end_transfer(s->bus);
  66            s->control &= ~(1 << 1);                            /* STP */
  67            s->count_cur = s->count;
  68            s->txlen = 0;
  69        } else if ((s->control >> 9) & 1) {                     /* TRX */
  70            while (ack && s->txlen)
  71                ack = (i2c_send(s->bus,
  72                                        (s->fifo >> ((-- s->txlen) << 3)) &
  73                                        0xff) >= 0);
  74            s->stat |= 1 << 4;                                  /* XRDY */
  75        } else {
  76            while (s->rxlen < 4)
  77                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
  78            s->stat |= 1 << 3;                                  /* RRDY */
  79        }
  80    } else {
  81        if ((s->control >> 9) & 1) {                            /* TRX */
  82            while (ack && s->count_cur && s->txlen) {
  83                ack = (i2c_send(s->bus,
  84                                        (s->fifo >> ((-- s->txlen) << 3)) &
  85                                        0xff) >= 0);
  86                s->count_cur --;
  87            }
  88            if (ack && s->count_cur)
  89                s->stat |= 1 << 4;                              /* XRDY */
  90            else
  91                s->stat &= ~(1 << 4);                           /* XRDY */
  92            if (!s->count_cur) {
  93                s->stat |= 1 << 2;                              /* ARDY */
  94                s->control &= ~(1 << 10);                       /* MST */
  95            }
  96        } else {
  97            while (s->count_cur && s->rxlen < 4) {
  98                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
  99                s->count_cur --;
 100            }
 101            if (s->rxlen)
 102                s->stat |= 1 << 3;                              /* RRDY */
 103            else
 104                s->stat &= ~(1 << 3);                           /* RRDY */
 105        }
 106        if (!s->count_cur) {
 107            if ((s->control >> 1) & 1) {                        /* STP */
 108                i2c_end_transfer(s->bus);
 109                s->control &= ~(1 << 1);                        /* STP */
 110                s->count_cur = s->count;
 111                s->txlen = 0;
 112            } else {
 113                s->stat |= 1 << 2;                              /* ARDY */
 114                s->control &= ~(1 << 10);                       /* MST */
 115            }
 116        }
 117    }
 118
 119    s->stat |= (!ack) << 1;                                     /* NACK */
 120    if (!ack)
 121        s->control &= ~(1 << 1);                                /* STP */
 122}
 123
 124void omap_i2c_reset(struct omap_i2c_s *s)
 125{
 126    s->mask = 0;
 127    s->stat = 0;
 128    s->dma = 0;
 129    s->count = 0;
 130    s->count_cur = 0;
 131    s->fifo = 0;
 132    s->rxlen = 0;
 133    s->txlen = 0;
 134    s->control = 0;
 135    s->addr[0] = 0;
 136    s->addr[1] = 0;
 137    s->divider = 0;
 138    s->times[0] = 0;
 139    s->times[1] = 0;
 140    s->test = 0;
 141}
 142
 143static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
 144{
 145    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
 146    int offset = addr & OMAP_MPUI_REG_MASK;
 147    uint16_t ret;
 148
 149    switch (offset) {
 150    case 0x00:  /* I2C_REV */
 151        return s->revision;                                     /* REV */
 152
 153    case 0x04:  /* I2C_IE */
 154        return s->mask;
 155
 156    case 0x08:  /* I2C_STAT */
 157        return s->stat | (i2c_bus_busy(s->bus) << 12);
 158
 159    case 0x0c:  /* I2C_IV */
 160        if (s->revision >= OMAP2_INTR_REV)
 161            break;
 162        ret = ffs(s->stat & s->mask);
 163        if (ret)
 164            s->stat ^= 1 << (ret - 1);
 165        omap_i2c_interrupts_update(s);
 166        return ret;
 167
 168    case 0x10:  /* I2C_SYSS */
 169        return (s->control >> 15) & 1;                          /* I2C_EN */
 170
 171    case 0x14:  /* I2C_BUF */
 172        return s->dma;
 173
 174    case 0x18:  /* I2C_CNT */
 175        return s->count_cur;                                    /* DCOUNT */
 176
 177    case 0x1c:  /* I2C_DATA */
 178        ret = 0;
 179        if (s->control & (1 << 14)) {                           /* BE */
 180            ret |= ((s->fifo >> 0) & 0xff) << 8;
 181            ret |= ((s->fifo >> 8) & 0xff) << 0;
 182        } else {
 183            ret |= ((s->fifo >> 8) & 0xff) << 8;
 184            ret |= ((s->fifo >> 0) & 0xff) << 0;
 185        }
 186        if (s->rxlen == 1) {
 187            s->stat |= 1 << 15;                                 /* SBD */
 188            s->rxlen = 0;
 189        } else if (s->rxlen > 1) {
 190            if (s->rxlen > 2)
 191                s->fifo >>= 16;
 192            s->rxlen -= 2;
 193        } else {
 194            /* XXX: remote access (qualifier) error - what's that?  */
 195        }
 196        if (!s->rxlen) {
 197            s->stat &= ~(1 << 3);                               /* RRDY */
 198            if (((s->control >> 10) & 1) &&                     /* MST */
 199                            ((~s->control >> 9) & 1)) {         /* TRX */
 200                s->stat |= 1 << 2;                              /* ARDY */
 201                s->control &= ~(1 << 10);                       /* MST */
 202            }
 203        }
 204        s->stat &= ~(1 << 11);                                  /* ROVR */
 205        omap_i2c_fifo_run(s);
 206        omap_i2c_interrupts_update(s);
 207        return ret;
 208
 209    case 0x20:  /* I2C_SYSC */
 210        return 0;
 211
 212    case 0x24:  /* I2C_CON */
 213        return s->control;
 214
 215    case 0x28:  /* I2C_OA */
 216        return s->addr[0];
 217
 218    case 0x2c:  /* I2C_SA */
 219        return s->addr[1];
 220
 221    case 0x30:  /* I2C_PSC */
 222        return s->divider;
 223
 224    case 0x34:  /* I2C_SCLL */
 225        return s->times[0];
 226
 227    case 0x38:  /* I2C_SCLH */
 228        return s->times[1];
 229
 230    case 0x3c:  /* I2C_SYSTEST */
 231        if (s->test & (1 << 15)) {                              /* ST_EN */
 232            s->test ^= 0xa;
 233            return s->test;
 234        } else
 235            return s->test & ~0x300f;
 236    }
 237
 238    OMAP_BAD_REG(addr);
 239    return 0;
 240}
 241
 242static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
 243                uint32_t value)
 244{
 245    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
 246    int offset = addr & OMAP_MPUI_REG_MASK;
 247    int nack;
 248
 249    switch (offset) {
 250    case 0x00:  /* I2C_REV */
 251    case 0x0c:  /* I2C_IV */
 252    case 0x10:  /* I2C_SYSS */
 253        OMAP_RO_REG(addr);
 254        return;
 255
 256    case 0x04:  /* I2C_IE */
 257        s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
 258        break;
 259
 260    case 0x08:  /* I2C_STAT */
 261        if (s->revision < OMAP2_INTR_REV) {
 262            OMAP_RO_REG(addr);
 263            return;
 264        }
 265
 266        /* RRDY and XRDY are reset by hardware. (in all versions???) */
 267        s->stat &= ~(value & 0x27);
 268        omap_i2c_interrupts_update(s);
 269        break;
 270
 271    case 0x14:  /* I2C_BUF */
 272        s->dma = value & 0x8080;
 273        if (value & (1 << 15))                                  /* RDMA_EN */
 274            s->mask &= ~(1 << 3);                               /* RRDY_IE */
 275        if (value & (1 << 7))                                   /* XDMA_EN */
 276            s->mask &= ~(1 << 4);                               /* XRDY_IE */
 277        break;
 278
 279    case 0x18:  /* I2C_CNT */
 280        s->count = value;                                       /* DCOUNT */
 281        break;
 282
 283    case 0x1c:  /* I2C_DATA */
 284        if (s->txlen > 2) {
 285            /* XXX: remote access (qualifier) error - what's that?  */
 286            break;
 287        }
 288        s->fifo <<= 16;
 289        s->txlen += 2;
 290        if (s->control & (1 << 14)) {                           /* BE */
 291            s->fifo |= ((value >> 8) & 0xff) << 8;
 292            s->fifo |= ((value >> 0) & 0xff) << 0;
 293        } else {
 294            s->fifo |= ((value >> 0) & 0xff) << 8;
 295            s->fifo |= ((value >> 8) & 0xff) << 0;
 296        }
 297        s->stat &= ~(1 << 10);                                  /* XUDF */
 298        if (s->txlen > 2)
 299            s->stat &= ~(1 << 4);                               /* XRDY */
 300        omap_i2c_fifo_run(s);
 301        omap_i2c_interrupts_update(s);
 302        break;
 303
 304    case 0x20:  /* I2C_SYSC */
 305        if (s->revision < OMAP2_INTR_REV) {
 306            OMAP_BAD_REG(addr);
 307            return;
 308        }
 309
 310        if (value & 2)
 311            omap_i2c_reset(s);
 312        break;
 313
 314    case 0x24:  /* I2C_CON */
 315        s->control = value & 0xcf87;
 316        if (~value & (1 << 15)) {                               /* I2C_EN */
 317            if (s->revision < OMAP2_INTR_REV)
 318                omap_i2c_reset(s);
 319            break;
 320        }
 321        if ((value & (1 << 15)) && !(value & (1 << 10))) {      /* MST */
 322            fprintf(stderr, "%s: I^2C slave mode not supported\n",
 323                            __FUNCTION__);
 324            break;
 325        }
 326        if ((value & (1 << 15)) && value & (1 << 8)) {          /* XA */
 327            fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
 328                            __FUNCTION__);
 329            break;
 330        }
 331        if ((value & (1 << 15)) && value & (1 << 0)) {          /* STT */
 332            nack = !!i2c_start_transfer(s->bus, s->addr[1],     /* SA */
 333                            (~value >> 9) & 1);                 /* TRX */
 334            s->stat |= nack << 1;                               /* NACK */
 335            s->control &= ~(1 << 0);                            /* STT */
 336            s->fifo = 0;
 337            if (nack)
 338                s->control &= ~(1 << 1);                        /* STP */
 339            else {
 340                s->count_cur = s->count;
 341                omap_i2c_fifo_run(s);
 342            }
 343            omap_i2c_interrupts_update(s);
 344        }
 345        break;
 346
 347    case 0x28:  /* I2C_OA */
 348        s->addr[0] = value & 0x3ff;
 349        break;
 350
 351    case 0x2c:  /* I2C_SA */
 352        s->addr[1] = value & 0x3ff;
 353        break;
 354
 355    case 0x30:  /* I2C_PSC */
 356        s->divider = value;
 357        break;
 358
 359    case 0x34:  /* I2C_SCLL */
 360        s->times[0] = value;
 361        break;
 362
 363    case 0x38:  /* I2C_SCLH */
 364        s->times[1] = value;
 365        break;
 366
 367    case 0x3c:  /* I2C_SYSTEST */
 368        s->test = value & 0xf80f;
 369        if (value & (1 << 11))                                  /* SBB */
 370            if (s->revision >= OMAP2_INTR_REV) {
 371                s->stat |= 0x3f;
 372                omap_i2c_interrupts_update(s);
 373            }
 374        if (value & (1 << 15))                                  /* ST_EN */
 375            fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
 376        break;
 377
 378    default:
 379        OMAP_BAD_REG(addr);
 380        return;
 381    }
 382}
 383
 384static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
 385                uint32_t value)
 386{
 387    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
 388    int offset = addr & OMAP_MPUI_REG_MASK;
 389
 390    switch (offset) {
 391    case 0x1c:  /* I2C_DATA */
 392        if (s->txlen > 2) {
 393            /* XXX: remote access (qualifier) error - what's that?  */
 394            break;
 395        }
 396        s->fifo <<= 8;
 397        s->txlen += 1;
 398        s->fifo |= value & 0xff;
 399        s->stat &= ~(1 << 10);                                  /* XUDF */
 400        if (s->txlen > 2)
 401            s->stat &= ~(1 << 4);                               /* XRDY */
 402        omap_i2c_fifo_run(s);
 403        omap_i2c_interrupts_update(s);
 404        break;
 405
 406    default:
 407        OMAP_BAD_REG(addr);
 408        return;
 409    }
 410}
 411
 412static CPUReadMemoryFunc * const omap_i2c_readfn[] = {
 413    omap_badwidth_read16,
 414    omap_i2c_read,
 415    omap_badwidth_read16,
 416};
 417
 418static CPUWriteMemoryFunc * const omap_i2c_writefn[] = {
 419    omap_i2c_writeb,    /* Only the last fifo write can be 8 bit.  */
 420    omap_i2c_write,
 421    omap_badwidth_write16,
 422};
 423
 424struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
 425                qemu_irq irq, qemu_irq *dma, omap_clk clk)
 426{
 427    int iomemtype;
 428    struct omap_i2c_s *s = (struct omap_i2c_s *)
 429            qemu_mallocz(sizeof(struct omap_i2c_s));
 430
 431    /* TODO: set a value greater or equal to real hardware */
 432    s->revision = 0x11;
 433    s->irq = irq;
 434    s->drq[0] = dma[0];
 435    s->drq[1] = dma[1];
 436    s->bus = i2c_init_bus(NULL, "i2c");
 437    omap_i2c_reset(s);
 438
 439    iomemtype = cpu_register_io_memory(omap_i2c_readfn,
 440                    omap_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
 441    cpu_register_physical_memory(base, 0x800, iomemtype);
 442
 443    return s;
 444}
 445
 446struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
 447                qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
 448{
 449    int iomemtype;
 450    struct omap_i2c_s *s = (struct omap_i2c_s *)
 451            qemu_mallocz(sizeof(struct omap_i2c_s));
 452
 453    s->revision = 0x34;
 454    s->irq = irq;
 455    s->drq[0] = dma[0];
 456    s->drq[1] = dma[1];
 457    s->bus = i2c_init_bus(NULL, "i2c");
 458    omap_i2c_reset(s);
 459
 460    iomemtype = l4_register_io_memory(omap_i2c_readfn,
 461                    omap_i2c_writefn, s);
 462    omap_l4_attach(ta, 0, iomemtype);
 463
 464    return s;
 465}
 466
 467i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
 468{
 469    return s->bus;
 470}
 471