symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/omap_i2c.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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
       
    17  * along with this program; if not, write to the Free Software
       
    18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       
    19  * MA 02111-1307 USA
       
    20  */
       
    21 #include "hw.h"
       
    22 #include "i2c.h"
       
    23 #include "omap.h"
       
    24 
       
    25 struct omap_i2c_s {
       
    26     qemu_irq irq;
       
    27     qemu_irq drq[2];
       
    28     i2c_slave slave;
       
    29     i2c_bus *bus;
       
    30 
       
    31     uint8_t revision;
       
    32     uint8_t mask;
       
    33     uint16_t stat;
       
    34     uint16_t dma;
       
    35     uint16_t count;
       
    36     int count_cur;
       
    37     uint32_t fifo;
       
    38     int rxlen;
       
    39     int txlen;
       
    40     uint16_t control;
       
    41     uint16_t addr[2];
       
    42     uint8_t divider;
       
    43     uint8_t times[2];
       
    44     uint16_t test;
       
    45 };
       
    46 
       
    47 #define OMAP2_INTR_REV	0x34
       
    48 #define OMAP2_GC_REV	0x34
       
    49 
       
    50 static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
       
    51 {
       
    52     qemu_set_irq(s->irq, s->stat & s->mask);
       
    53     if ((s->dma >> 15) & 1)					/* RDMA_EN */
       
    54         qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);		/* RRDY */
       
    55     if ((s->dma >> 7) & 1)					/* XDMA_EN */
       
    56         qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);		/* XRDY */
       
    57 }
       
    58 
       
    59 /* These are only stubs now.  */
       
    60 static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event)
       
    61 {
       
    62     struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
       
    63 
       
    64     if ((~s->control >> 15) & 1)				/* I2C_EN */
       
    65         return;
       
    66 
       
    67     switch (event) {
       
    68     case I2C_START_SEND:
       
    69     case I2C_START_RECV:
       
    70         s->stat |= 1 << 9;					/* AAS */
       
    71         break;
       
    72     case I2C_FINISH:
       
    73         s->stat |= 1 << 2;					/* ARDY */
       
    74         break;
       
    75     case I2C_NACK:
       
    76         s->stat |= 1 << 1;					/* NACK */
       
    77         break;
       
    78     }
       
    79 
       
    80     omap_i2c_interrupts_update(s);
       
    81 }
       
    82 
       
    83 static int omap_i2c_rx(i2c_slave *i2c)
       
    84 {
       
    85     struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
       
    86     uint8_t ret = 0;
       
    87 
       
    88     if ((~s->control >> 15) & 1)				/* I2C_EN */
       
    89         return -1;
       
    90 
       
    91     if (s->txlen)
       
    92         ret = s->fifo >> ((-- s->txlen) << 3) & 0xff;
       
    93     else
       
    94         s->stat |= 1 << 10;					/* XUDF */
       
    95     s->stat |= 1 << 4;						/* XRDY */
       
    96 
       
    97     omap_i2c_interrupts_update(s);
       
    98     return ret;
       
    99 }
       
   100 
       
   101 static int omap_i2c_tx(i2c_slave *i2c, uint8_t data)
       
   102 {
       
   103     struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
       
   104 
       
   105     if ((~s->control >> 15) & 1)				/* I2C_EN */
       
   106         return 1;
       
   107 
       
   108     if (s->rxlen < 4)
       
   109         s->fifo |= data << ((s->rxlen ++) << 3);
       
   110     else
       
   111         s->stat |= 1 << 11;					/* ROVR */
       
   112     s->stat |= 1 << 3;						/* RRDY */
       
   113 
       
   114     omap_i2c_interrupts_update(s);
       
   115     return 1;
       
   116 }
       
   117 
       
   118 static void omap_i2c_fifo_run(struct omap_i2c_s *s)
       
   119 {
       
   120     int ack = 1;
       
   121 
       
   122     if (!i2c_bus_busy(s->bus))
       
   123         return;
       
   124 
       
   125     if ((s->control >> 2) & 1) {				/* RM */
       
   126         if ((s->control >> 1) & 1) {				/* STP */
       
   127             i2c_end_transfer(s->bus);
       
   128             s->control &= ~(1 << 1);				/* STP */
       
   129             s->count_cur = s->count;
       
   130             s->txlen = 0;
       
   131         } else if ((s->control >> 9) & 1) {			/* TRX */
       
   132             while (ack && s->txlen)
       
   133                 ack = (i2c_send(s->bus,
       
   134                                         (s->fifo >> ((-- s->txlen) << 3)) &
       
   135                                         0xff) >= 0);
       
   136             s->stat |= 1 << 4;					/* XRDY */
       
   137         } else {
       
   138             while (s->rxlen < 4)
       
   139                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
       
   140             s->stat |= 1 << 3;					/* RRDY */
       
   141         }
       
   142     } else {
       
   143         if ((s->control >> 9) & 1) {				/* TRX */
       
   144             while (ack && s->count_cur && s->txlen) {
       
   145                 ack = (i2c_send(s->bus,
       
   146                                         (s->fifo >> ((-- s->txlen) << 3)) &
       
   147                                         0xff) >= 0);
       
   148                 s->count_cur --;
       
   149             }
       
   150             if (ack && s->count_cur)
       
   151                 s->stat |= 1 << 4;				/* XRDY */
       
   152             else
       
   153                 s->stat &= ~(1 << 4);				/* XRDY */
       
   154             if (!s->count_cur) {
       
   155                 s->stat |= 1 << 2;				/* ARDY */
       
   156                 s->control &= ~(1 << 10);			/* MST */
       
   157             }
       
   158         } else {
       
   159             while (s->count_cur && s->rxlen < 4) {
       
   160                 s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
       
   161                 s->count_cur --;
       
   162             }
       
   163             if (s->rxlen)
       
   164                 s->stat |= 1 << 3;				/* RRDY */
       
   165             else
       
   166                 s->stat &= ~(1 << 3);				/* RRDY */
       
   167         }
       
   168         if (!s->count_cur) {
       
   169             if ((s->control >> 1) & 1) {			/* STP */
       
   170                 i2c_end_transfer(s->bus);
       
   171                 s->control &= ~(1 << 1);			/* STP */
       
   172                 s->count_cur = s->count;
       
   173                 s->txlen = 0;
       
   174             } else {
       
   175                 s->stat |= 1 << 2;				/* ARDY */
       
   176                 s->control &= ~(1 << 10);			/* MST */
       
   177             }
       
   178         }
       
   179     }
       
   180 
       
   181     s->stat |= (!ack) << 1;					/* NACK */
       
   182     if (!ack)
       
   183         s->control &= ~(1 << 1);				/* STP */
       
   184 }
       
   185 
       
   186 void omap_i2c_reset(struct omap_i2c_s *s)
       
   187 {
       
   188     s->mask = 0;
       
   189     s->stat = 0;
       
   190     s->dma = 0;
       
   191     s->count = 0;
       
   192     s->count_cur = 0;
       
   193     s->fifo = 0;
       
   194     s->rxlen = 0;
       
   195     s->txlen = 0;
       
   196     s->control = 0;
       
   197     s->addr[0] = 0;
       
   198     s->addr[1] = 0;
       
   199     s->divider = 0;
       
   200     s->times[0] = 0;
       
   201     s->times[1] = 0;
       
   202     s->test = 0;
       
   203 }
       
   204 
       
   205 static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
       
   206 {
       
   207     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
       
   208     int offset = addr & OMAP_MPUI_REG_MASK;
       
   209     uint16_t ret;
       
   210 
       
   211     switch (offset) {
       
   212     case 0x00:	/* I2C_REV */
       
   213         return s->revision;					/* REV */
       
   214 
       
   215     case 0x04:	/* I2C_IE */
       
   216         return s->mask;
       
   217 
       
   218     case 0x08:	/* I2C_STAT */
       
   219         return s->stat | (i2c_bus_busy(s->bus) << 12);
       
   220 
       
   221     case 0x0c:	/* I2C_IV */
       
   222         if (s->revision >= OMAP2_INTR_REV)
       
   223             break;
       
   224         ret = ffs(s->stat & s->mask);
       
   225         if (ret)
       
   226             s->stat ^= 1 << (ret - 1);
       
   227         omap_i2c_interrupts_update(s);
       
   228         return ret;
       
   229 
       
   230     case 0x10:	/* I2C_SYSS */
       
   231         return (s->control >> 15) & 1;				/* I2C_EN */
       
   232 
       
   233     case 0x14:	/* I2C_BUF */
       
   234         return s->dma;
       
   235 
       
   236     case 0x18:	/* I2C_CNT */
       
   237         return s->count_cur;					/* DCOUNT */
       
   238 
       
   239     case 0x1c:	/* I2C_DATA */
       
   240         ret = 0;
       
   241         if (s->control & (1 << 14)) {				/* BE */
       
   242             ret |= ((s->fifo >> 0) & 0xff) << 8;
       
   243             ret |= ((s->fifo >> 8) & 0xff) << 0;
       
   244         } else {
       
   245             ret |= ((s->fifo >> 8) & 0xff) << 8;
       
   246             ret |= ((s->fifo >> 0) & 0xff) << 0;
       
   247         }
       
   248         if (s->rxlen == 1) {
       
   249             s->stat |= 1 << 15;					/* SBD */
       
   250             s->rxlen = 0;
       
   251         } else if (s->rxlen > 1) {
       
   252             if (s->rxlen > 2)
       
   253                 s->fifo >>= 16;
       
   254             s->rxlen -= 2;
       
   255         } else
       
   256             /* XXX: remote access (qualifier) error - what's that?  */;
       
   257         if (!s->rxlen) {
       
   258             s->stat &= ~(1 << 3);				/* RRDY */
       
   259             if (((s->control >> 10) & 1) &&			/* MST */
       
   260                             ((~s->control >> 9) & 1)) {		/* TRX */
       
   261                 s->stat |= 1 << 2;				/* ARDY */
       
   262                 s->control &= ~(1 << 10);			/* MST */
       
   263             }
       
   264         }
       
   265         s->stat &= ~(1 << 11);					/* ROVR */
       
   266         omap_i2c_fifo_run(s);
       
   267         omap_i2c_interrupts_update(s);
       
   268         return ret;
       
   269 
       
   270     case 0x20:	/* I2C_SYSC */
       
   271         return 0;
       
   272 
       
   273     case 0x24:	/* I2C_CON */
       
   274         return s->control;
       
   275 
       
   276     case 0x28:	/* I2C_OA */
       
   277         return s->addr[0];
       
   278 
       
   279     case 0x2c:	/* I2C_SA */
       
   280         return s->addr[1];
       
   281 
       
   282     case 0x30:	/* I2C_PSC */
       
   283         return s->divider;
       
   284 
       
   285     case 0x34:	/* I2C_SCLL */
       
   286         return s->times[0];
       
   287 
       
   288     case 0x38:	/* I2C_SCLH */
       
   289         return s->times[1];
       
   290 
       
   291     case 0x3c:	/* I2C_SYSTEST */
       
   292         if (s->test & (1 << 15)) {				/* ST_EN */
       
   293             s->test ^= 0xa;
       
   294             return s->test;
       
   295         } else
       
   296             return s->test & ~0x300f;
       
   297     }
       
   298 
       
   299     OMAP_BAD_REG(addr);
       
   300     return 0;
       
   301 }
       
   302 
       
   303 static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
       
   304                 uint32_t value)
       
   305 {
       
   306     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
       
   307     int offset = addr & OMAP_MPUI_REG_MASK;
       
   308     int nack;
       
   309 
       
   310     switch (offset) {
       
   311     case 0x00:	/* I2C_REV */
       
   312     case 0x0c:	/* I2C_IV */
       
   313     case 0x10:	/* I2C_SYSS */
       
   314         OMAP_RO_REG(addr);
       
   315         return;
       
   316 
       
   317     case 0x04:	/* I2C_IE */
       
   318         s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
       
   319         break;
       
   320 
       
   321     case 0x08:	/* I2C_STAT */
       
   322         if (s->revision < OMAP2_INTR_REV) {
       
   323             OMAP_RO_REG(addr);
       
   324             return;
       
   325         }
       
   326 
       
   327         /* RRDY and XRDY are reset by hardware. (in all versions???) */
       
   328         s->stat &= ~(value & 0x27);
       
   329         omap_i2c_interrupts_update(s);
       
   330         break;
       
   331 
       
   332     case 0x14:	/* I2C_BUF */
       
   333         s->dma = value & 0x8080;
       
   334         if (value & (1 << 15))					/* RDMA_EN */
       
   335             s->mask &= ~(1 << 3);				/* RRDY_IE */
       
   336         if (value & (1 << 7))					/* XDMA_EN */
       
   337             s->mask &= ~(1 << 4);				/* XRDY_IE */
       
   338         break;
       
   339 
       
   340     case 0x18:	/* I2C_CNT */
       
   341         s->count = value;					/* DCOUNT */
       
   342         break;
       
   343 
       
   344     case 0x1c:	/* I2C_DATA */
       
   345         if (s->txlen > 2) {
       
   346             /* XXX: remote access (qualifier) error - what's that?  */
       
   347             break;
       
   348         }
       
   349         s->fifo <<= 16;
       
   350         s->txlen += 2;
       
   351         if (s->control & (1 << 14)) {				/* BE */
       
   352             s->fifo |= ((value >> 8) & 0xff) << 8;
       
   353             s->fifo |= ((value >> 0) & 0xff) << 0;
       
   354         } else {
       
   355             s->fifo |= ((value >> 0) & 0xff) << 8;
       
   356             s->fifo |= ((value >> 8) & 0xff) << 0;
       
   357         }
       
   358         s->stat &= ~(1 << 10);					/* XUDF */
       
   359         if (s->txlen > 2)
       
   360             s->stat &= ~(1 << 4);				/* XRDY */
       
   361         omap_i2c_fifo_run(s);
       
   362         omap_i2c_interrupts_update(s);
       
   363         break;
       
   364 
       
   365     case 0x20:	/* I2C_SYSC */
       
   366         if (s->revision < OMAP2_INTR_REV) {
       
   367             OMAP_BAD_REG(addr);
       
   368             return;
       
   369         }
       
   370 
       
   371         if (value & 2)
       
   372             omap_i2c_reset(s);
       
   373         break;
       
   374 
       
   375     case 0x24:	/* I2C_CON */
       
   376         s->control = value & 0xcf87;
       
   377         if (~value & (1 << 15)) {				/* I2C_EN */
       
   378             if (s->revision < OMAP2_INTR_REV)
       
   379                 omap_i2c_reset(s);
       
   380             break;
       
   381         }
       
   382         if ((value & (1 << 15)) && !(value & (1 << 10))) {	/* MST */
       
   383             fprintf(stderr, "%s: I^2C slave mode not supported\n",
       
   384                             __FUNCTION__);
       
   385             break;
       
   386         }
       
   387         if ((value & (1 << 15)) && value & (1 << 8)) {		/* XA */
       
   388             fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
       
   389                             __FUNCTION__);
       
   390             break;
       
   391         }
       
   392         if ((value & (1 << 15)) && value & (1 << 0)) {		/* STT */
       
   393             nack = !!i2c_start_transfer(s->bus, s->addr[1],	/* SA */
       
   394                             (~value >> 9) & 1);			/* TRX */
       
   395             s->stat |= nack << 1;				/* NACK */
       
   396             s->control &= ~(1 << 0);				/* STT */
       
   397             s->fifo = 0;
       
   398             if (nack)
       
   399                 s->control &= ~(1 << 1);			/* STP */
       
   400             else {
       
   401                 s->count_cur = s->count;
       
   402                 omap_i2c_fifo_run(s);
       
   403             }
       
   404             omap_i2c_interrupts_update(s);
       
   405         }
       
   406         break;
       
   407 
       
   408     case 0x28:	/* I2C_OA */
       
   409         s->addr[0] = value & 0x3ff;
       
   410         i2c_set_slave_address(&s->slave, value & 0x7f);
       
   411         break;
       
   412 
       
   413     case 0x2c:	/* I2C_SA */
       
   414         s->addr[1] = value & 0x3ff;
       
   415         break;
       
   416 
       
   417     case 0x30:	/* I2C_PSC */
       
   418         s->divider = value;
       
   419         break;
       
   420 
       
   421     case 0x34:	/* I2C_SCLL */
       
   422         s->times[0] = value;
       
   423         break;
       
   424 
       
   425     case 0x38:	/* I2C_SCLH */
       
   426         s->times[1] = value;
       
   427         break;
       
   428 
       
   429     case 0x3c:	/* I2C_SYSTEST */
       
   430         s->test = value & 0xf80f;
       
   431         if (value & (1 << 11))					/* SBB */
       
   432             if (s->revision >= OMAP2_INTR_REV) {
       
   433                 s->stat |= 0x3f;
       
   434                 omap_i2c_interrupts_update(s);
       
   435             }
       
   436         if (value & (1 << 15))					/* ST_EN */
       
   437             fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
       
   438         break;
       
   439 
       
   440     default:
       
   441         OMAP_BAD_REG(addr);
       
   442         return;
       
   443     }
       
   444 }
       
   445 
       
   446 static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
       
   447                 uint32_t value)
       
   448 {
       
   449     struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
       
   450     int offset = addr & OMAP_MPUI_REG_MASK;
       
   451 
       
   452     switch (offset) {
       
   453     case 0x1c:	/* I2C_DATA */
       
   454         if (s->txlen > 2) {
       
   455             /* XXX: remote access (qualifier) error - what's that?  */
       
   456             break;
       
   457         }
       
   458         s->fifo <<= 8;
       
   459         s->txlen += 1;
       
   460         s->fifo |= value & 0xff;
       
   461         s->stat &= ~(1 << 10);					/* XUDF */
       
   462         if (s->txlen > 2)
       
   463             s->stat &= ~(1 << 4);				/* XRDY */
       
   464         omap_i2c_fifo_run(s);
       
   465         omap_i2c_interrupts_update(s);
       
   466         break;
       
   467 
       
   468     default:
       
   469         OMAP_BAD_REG(addr);
       
   470         return;
       
   471     }
       
   472 }
       
   473 
       
   474 static CPUReadMemoryFunc *omap_i2c_readfn[] = {
       
   475     omap_badwidth_read16,
       
   476     omap_i2c_read,
       
   477     omap_badwidth_read16,
       
   478 };
       
   479 
       
   480 static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
       
   481     omap_i2c_writeb,	/* Only the last fifo write can be 8 bit.  */
       
   482     omap_i2c_write,
       
   483     omap_badwidth_write16,
       
   484 };
       
   485 
       
   486 struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
       
   487                 qemu_irq irq, qemu_irq *dma, omap_clk clk)
       
   488 {
       
   489     int iomemtype;
       
   490     struct omap_i2c_s *s = (struct omap_i2c_s *)
       
   491             qemu_mallocz(sizeof(struct omap_i2c_s));
       
   492 
       
   493     /* TODO: set a value greater or equal to real hardware */
       
   494     s->revision = 0x11;
       
   495     s->irq = irq;
       
   496     s->drq[0] = dma[0];
       
   497     s->drq[1] = dma[1];
       
   498     s->slave.event = omap_i2c_event;
       
   499     s->slave.recv = omap_i2c_rx;
       
   500     s->slave.send = omap_i2c_tx;
       
   501     s->bus = i2c_init_bus();
       
   502     omap_i2c_reset(s);
       
   503 
       
   504     iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
       
   505                     omap_i2c_writefn, s);
       
   506     cpu_register_physical_memory(base, 0x800, iomemtype);
       
   507 
       
   508     return s;
       
   509 }
       
   510 
       
   511 struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
       
   512                 qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
       
   513 {
       
   514     int iomemtype;
       
   515     struct omap_i2c_s *s = (struct omap_i2c_s *)
       
   516             qemu_mallocz(sizeof(struct omap_i2c_s));
       
   517 
       
   518     s->revision = 0x34;
       
   519     s->irq = irq;
       
   520     s->drq[0] = dma[0];
       
   521     s->drq[1] = dma[1];
       
   522     s->slave.event = omap_i2c_event;
       
   523     s->slave.recv = omap_i2c_rx;
       
   524     s->slave.send = omap_i2c_tx;
       
   525     s->bus = i2c_init_bus();
       
   526     omap_i2c_reset(s);
       
   527 
       
   528     iomemtype = l4_register_io_memory(0, omap_i2c_readfn,
       
   529                     omap_i2c_writefn, s);
       
   530     omap_l4_attach(ta, 0, iomemtype);
       
   531 
       
   532     return s;
       
   533 }
       
   534 
       
   535 i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
       
   536 {
       
   537     return s->bus;
       
   538 }