1
From db7d87a6729ef795bdd00ae78f7c501e48a6e140 Mon Sep 17 00:00:00 2001
2
From: Peter Maydell <peter.maydell@linaro.org>
3
Date: Mon, 18 Feb 2013 16:58:26 +0000
4
Subject: [PATCH 18/71] omap_i2c: support different FIFO sizes
6
Support FIFO size settable via a device property, rather
7
than a fixed 4 byte FIFO. This is needed for OMAP3.
9
hw/i2c/omap_i2c.c | 242 +++++++++++++++++++++++++++++++-----------------------
10
1 file changed, 138 insertions(+), 104 deletions(-)
12
diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c
13
index 7d47dc7..c054815 100644
14
--- a/hw/i2c/omap_i2c.c
15
+++ b/hw/i2c/omap_i2c.c
17
#define TYPE_OMAP_I2C "omap_i2c"
18
#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
20
+#define I2C_MAX_FIFO_SIZE (1 << 6)
21
+#define I2C_FIFO_SIZE_MASK ((I2C_MAX_FIFO_SIZE) - 1)
23
typedef struct OMAPI2CState {
24
SysBusDevice parent_obj;
26
@@ -33,6 +36,7 @@ typedef struct OMAPI2CState {
34
@@ -41,14 +45,14 @@ typedef struct OMAPI2CState {
48
+ uint8_t fifo[I2C_MAX_FIFO_SIZE];
51
/* I2C controller revision register values */
52
@@ -68,7 +72,7 @@ static void omap_i2c_interrupts_update(OMAPI2CState *s)
54
static void omap_i2c_fifo_run(OMAPI2CState *s)
59
if (!i2c_bus_busy(s->bus))
61
@@ -78,53 +82,68 @@ static void omap_i2c_fifo_run(OMAPI2CState *s)
62
i2c_end_transfer(s->bus);
63
s->control &= ~(1 << 1); /* STP */
64
s->count_cur = s->count;
67
} else if ((s->control >> 9) & 1) { /* TRX */
68
- while (ack && s->txlen)
69
- ack = (i2c_send(s->bus,
70
- (s->fifo >> ((-- s->txlen) << 3)) &
72
+ while (ack && s->fifolen) {
73
+ ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
74
+ s->fifostart &= I2C_FIFO_SIZE_MASK;
78
s->stat |= 1 << 4; /* XRDY */
80
- while (s->rxlen < 4)
81
- s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
82
+ for (i = 0; i < 4; i++)
83
+ s->fifo[(s->fifostart + i) & I2C_FIFO_SIZE_MASK] =
86
s->stat |= 1 << 3; /* RRDY */
89
if ((s->control >> 9) & 1) { /* TRX */
90
- while (ack && s->count_cur && s->txlen) {
91
- ack = (i2c_send(s->bus,
92
- (s->fifo >> ((-- s->txlen) << 3)) &
95
+ for (; ack && s->count_cur && s->fifolen; s->count_cur--) {
96
+ ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
97
+ s->fifostart &= I2C_FIFO_SIZE_MASK;
100
- if (ack && s->count_cur)
101
+ s->stat &= ~0x4410; /* XDR | XUDF | XRDY */
102
+ if (ack && s->count_cur) { /* send more? */
103
+ /* we know that FIFO is empty */
104
+ if (s->revision < OMAP3_INTR_REV)
105
+ s->stat |= 1 << 4; /* XRDY */
107
+ if (s->count_cur > (s->dma & 0x3f)) /* XTRSH */
108
s->stat |= 1 << 4; /* XRDY */
110
- s->stat &= ~(1 << 4); /* XRDY */
111
- if (!s->count_cur) {
112
- s->stat |= 1 << 2; /* ARDY */
113
- s->control &= ~(1 << 10); /* MST */
114
+ s->stat |= 1 << 14; /* XDR */
117
- while (s->count_cur && s->rxlen < 4) {
118
- s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
122
+ if (!s->count_cur) /* everything sent? */
123
+ s->stat |= 1 << 2; /* ARDY */
124
+ } else { /* !TRX */
125
+ for (; s->count_cur && s->fifolen < s->fifosize; s->count_cur--) {
126
+ i = i2c_recv(s->bus);
127
+ if (i < 0) break; /* stop receiving if nothing to receive */
128
+ s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
129
+ (uint8_t)(i & 0xff);
131
+ s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
133
+ if (s->revision < OMAP3_INTR_REV)
134
+ s->stat |= 1 << 3; /* RRDY */
136
+ if (s->fifolen > ((s->dma >> 8) & 0x3f)) /* RTRSH */
137
s->stat |= 1 << 3; /* RRDY */
139
- s->stat &= ~(1 << 3); /* RRDY */
140
+ s->stat |= 1 << 13; /* RDR */
142
+ } else if (!s->count_cur && (s->control & 2)) /* STP */
143
+ s->stat |= 1 << 2; /* ARDY */
146
if ((s->control >> 1) & 1) { /* STP */
147
i2c_end_transfer(s->bus);
148
- s->control &= ~(1 << 1); /* STP */
149
+ s->control &= ~0x0602; /* MST | TRX | STP */
150
s->count_cur = s->count;
153
- s->stat |= 1 << 2; /* ARDY */
154
- s->control &= ~(1 << 10); /* MST */
158
@@ -143,9 +162,8 @@ static void omap_i2c_reset(DeviceState *dev)
170
@@ -191,32 +209,41 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
172
case 0x1c: /* I2C_DATA */
174
- if (s->control & (1 << 14)) { /* BE */
175
- ret |= ((s->fifo >> 0) & 0xff) << 8;
176
- ret |= ((s->fifo >> 8) & 0xff) << 0;
178
- ret |= ((s->fifo >> 8) & 0xff) << 8;
179
- ret |= ((s->fifo >> 0) & 0xff) << 0;
181
- if (s->rxlen == 1) {
182
- s->stat |= 1 << 15; /* SBD */
184
- } else if (s->rxlen > 1) {
189
- /* XXX: remote access (qualifier) error - what's that? */
192
- s->stat &= ~(1 << 3); /* RRDY */
193
- if (((s->control >> 10) & 1) && /* MST */
194
- ((~s->control >> 9) & 1)) { /* TRX */
195
- s->stat |= 1 << 2; /* ARDY */
196
- s->control &= ~(1 << 10); /* MST */
198
+ if (s->revision < OMAP3_INTR_REV) {
199
+ if (s->control & (1 << 14)) /* BE */
200
+ ret = (((uint16_t)s->fifo[s->fifostart]) << 8)
201
+ | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
203
+ ret = (((uint16_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8)
204
+ | s->fifo[s->fifostart];
205
+ s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
206
+ if (s->fifolen == 1) {
207
+ s->stat |= 1 << 15; /* SBD */
212
+ s->stat &= ~(1 << 3); /* RRDY */
213
+ s->stat |= 1 << 2; /* ARDY */
216
+ s->stat &= ~(1 << 7); /* AERR */
217
+ ret = s->fifo[s->fifostart++];
218
+ s->fifostart &= I2C_FIFO_SIZE_MASK;
219
+ if (--s->fifolen) {
220
+ if (s->fifolen <= ((s->dma >> 8) & 0x3f)) {
221
+ s->stat &= ~(1 << 3); /* RRDY */
222
+ s->stat |= 1 << 13; /* RDR */
225
+ s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
226
+ s->stat |= 1 << 2; /* ARDY */
230
- s->stat &= ~(1 << 11); /* ROVR */
231
+ s->stat &= ~(1 << 11); /* ROVR */
232
+ } else if (s->revision >= OMAP3_INTR_REV)
233
+ s->stat |= (1 << 7); /* AERR */
234
omap_i2c_fifo_run(s);
235
omap_i2c_interrupts_update(s);
237
@@ -296,22 +323,31 @@ static void omap_i2c_write(void *opaque, hwaddr addr,
240
case 0x1c: /* I2C_DATA */
241
- if (s->txlen > 2) {
242
- /* XXX: remote access (qualifier) error - what's that? */
247
- if (s->control & (1 << 14)) { /* BE */
248
- s->fifo |= ((value >> 8) & 0xff) << 8;
249
- s->fifo |= ((value >> 0) & 0xff) << 0;
250
+ if (s->revision < OMAP3_INTR_REV) {
251
+ if (s->fifolen > 2) {
252
+ /* XXX: remote access (qualifier) error - what's that? */
255
+ if (s->control & (1 << 14)) { /* BE */
256
+ s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
257
+ (uint8_t)((value >> 8) & 0xff);
258
+ s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
259
+ (uint8_t)(value & 0xff);
261
+ s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
262
+ (uint8_t)(value & 0xff);
263
+ s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
264
+ (uint8_t)((value >> 8) & 0xff);
267
- s->fifo |= ((value >> 0) & 0xff) << 8;
268
- s->fifo |= ((value >> 8) & 0xff) << 0;
269
+ if (s->fifolen < s->fifosize) {
270
+ s->stat &= ~(1 << 7); /* AERR */
271
+ s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
272
+ (uint8_t)(value & 0xff);
274
+ s->stat |= (1 << 7); /* AERR */
276
s->stat &= ~(1 << 10); /* XUDF */
278
- s->stat &= ~(1 << 4); /* XRDY */
279
omap_i2c_fifo_run(s);
280
omap_i2c_interrupts_update(s);
282
@@ -335,29 +371,25 @@ static void omap_i2c_write(void *opaque, hwaddr addr,
286
- if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */
287
- fprintf(stderr, "%s: I^2C slave mode not supported\n",
291
- if ((value & (1 << 15)) && value & (1 << 8)) { /* XA */
292
- fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
296
- if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */
297
- nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */
298
- (~value >> 9) & 1); /* TRX */
299
- s->stat |= nack << 1; /* NACK */
300
- s->control &= ~(1 << 0); /* STT */
303
- s->control &= ~(1 << 1); /* STP */
305
+ if ((value & (1 << 10))) { /* MST */
306
+ if (value & 1) { /* STT */
307
+ nack = !!i2c_start_transfer(s->bus, s->addr[1], /*SA*/
308
+ (~value >> 9) & 1); /* TRX */
309
+ s->stat |= nack << 1; /* NACK */
310
+ s->control &= ~(1 << 0); /* STT */
313
+ s->control &= ~(1 << 1); /* STP */
315
+ s->count_cur = s->count;
316
+ omap_i2c_fifo_run(s);
318
+ omap_i2c_interrupts_update(s);
319
+ } else if (value & 2) { /* STP, but not STT */
320
+ i2c_end_transfer(s->bus);
321
+ s->control &= ~0x0602; /* MST | TRX | STP */
322
s->count_cur = s->count;
323
- omap_i2c_fifo_run(s);
325
- omap_i2c_interrupts_update(s);
329
@@ -406,23 +438,24 @@ static void omap_i2c_writeb(void *opaque, hwaddr addr,
332
case 0x1c: /* I2C_DATA */
333
- if (s->txlen > 2) {
334
+ if (s->revision < OMAP3_INTR_REV && s->fifolen > 2) {
335
/* XXX: remote access (qualifier) error - what's that? */
340
- s->fifo |= value & 0xff;
341
- s->stat &= ~(1 << 10); /* XUDF */
343
- s->stat &= ~(1 << 4); /* XRDY */
344
- omap_i2c_fifo_run(s);
345
+ if (s->fifolen < s->fifosize) {
346
+ s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
347
+ (uint8_t)(value & 0xff);
348
+ if (s->revision >= OMAP3_INTR_REV)
349
+ s->stat &= ~(1 << 7); /* AERR */
350
+ s->stat &= ~(1 << 10); /* XUDF */
351
+ omap_i2c_fifo_run(s);
352
+ } else if (s->revision >= OMAP3_INTR_REV)
353
+ s->stat |= (1 << 7); /* AERR */
354
omap_i2c_interrupts_update(s);
364
@@ -466,6 +499,7 @@ static int omap_i2c_init(SysBusDevice *sbd)
366
static Property omap_i2c_properties[] = {
367
DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
368
+ DEFINE_PROP_UINT32("fifo-size", OMAPI2CState, fifosize, 4),
369
DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
370
DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
371
DEFINE_PROP_END_OF_LIST(),