Revision 2d08cc7c hw/omap2.c

b/hw/omap2.c
29 29
#include "soc_dma.h"
30 30
#include "audio/audio.h"
31 31

  
32
/* Multichannel SPI */
33
struct omap_mcspi_s {
34
    qemu_irq irq;
35
    int chnum;
36

  
37
    uint32_t sysconfig;
38
    uint32_t systest;
39
    uint32_t irqst;
40
    uint32_t irqen;
41
    uint32_t wken;
42
    uint32_t control;
43

  
44
    struct omap_mcspi_ch_s {
45
        qemu_irq txdrq;
46
        qemu_irq rxdrq;
47
        uint32_t (*txrx)(void *opaque, uint32_t, int);
48
        void *opaque;
49

  
50
        uint32_t tx;
51
        uint32_t rx;
52

  
53
        uint32_t config;
54
        uint32_t status;
55
        uint32_t control;
56
    } ch[4];
57
};
58

  
59
static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
60
{
61
    qemu_set_irq(s->irq, s->irqst & s->irqen);
62
}
63

  
64
static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
65
{
66
    qemu_set_irq(ch->txdrq,
67
                    (ch->control & 1) &&		/* EN */
68
                    (ch->config & (1 << 14)) &&		/* DMAW */
69
                    (ch->status & (1 << 1)) &&		/* TXS */
70
                    ((ch->config >> 12) & 3) != 1);	/* TRM */
71
    qemu_set_irq(ch->rxdrq,
72
                    (ch->control & 1) &&		/* EN */
73
                    (ch->config & (1 << 15)) &&		/* DMAW */
74
                    (ch->status & (1 << 0)) &&		/* RXS */
75
                    ((ch->config >> 12) & 3) != 2);	/* TRM */
76
}
77

  
78
static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
79
{
80
    struct omap_mcspi_ch_s *ch = s->ch + chnum;
81

  
82
    if (!(ch->control & 1))				/* EN */
83
        return;
84
    if ((ch->status & (1 << 0)) &&			/* RXS */
85
                    ((ch->config >> 12) & 3) != 2 &&	/* TRM */
86
                    !(ch->config & (1 << 19)))		/* TURBO */
87
        goto intr_update;
88
    if ((ch->status & (1 << 1)) &&			/* TXS */
89
                    ((ch->config >> 12) & 3) != 1)	/* TRM */
90
        goto intr_update;
91

  
92
    if (!(s->control & 1) ||				/* SINGLE */
93
                    (ch->config & (1 << 20))) {		/* FORCE */
94
        if (ch->txrx)
95
            ch->rx = ch->txrx(ch->opaque, ch->tx,	/* WL */
96
                            1 + (0x1f & (ch->config >> 7)));
97
    }
98

  
99
    ch->tx = 0;
100
    ch->status |= 1 << 2;				/* EOT */
101
    ch->status |= 1 << 1;				/* TXS */
102
    if (((ch->config >> 12) & 3) != 2)			/* TRM */
103
        ch->status |= 1 << 0;				/* RXS */
104

  
105
intr_update:
106
    if ((ch->status & (1 << 0)) &&			/* RXS */
107
                    ((ch->config >> 12) & 3) != 2 &&	/* TRM */
108
                    !(ch->config & (1 << 19)))		/* TURBO */
109
        s->irqst |= 1 << (2 + 4 * chnum);		/* RX_FULL */
110
    if ((ch->status & (1 << 1)) &&			/* TXS */
111
                    ((ch->config >> 12) & 3) != 1)	/* TRM */
112
        s->irqst |= 1 << (0 + 4 * chnum);		/* TX_EMPTY */
113
    omap_mcspi_interrupt_update(s);
114
    omap_mcspi_dmarequest_update(ch);
115
}
116

  
117
static void omap_mcspi_reset(struct omap_mcspi_s *s)
118
{
119
    int ch;
120

  
121
    s->sysconfig = 0;
122
    s->systest = 0;
123
    s->irqst = 0;
124
    s->irqen = 0;
125
    s->wken = 0;
126
    s->control = 4;
127

  
128
    for (ch = 0; ch < 4; ch ++) {
129
        s->ch[ch].config = 0x060000;
130
        s->ch[ch].status = 2;				/* TXS */
131
        s->ch[ch].control = 0;
132

  
133
        omap_mcspi_dmarequest_update(s->ch + ch);
134
    }
135

  
136
    omap_mcspi_interrupt_update(s);
137
}
138

  
139
static uint32_t omap_mcspi_read(void *opaque, target_phys_addr_t addr)
140
{
141
    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
142
    int ch = 0;
143
    uint32_t ret;
144

  
145
    switch (addr) {
146
    case 0x00:	/* MCSPI_REVISION */
147
        return 0x91;
148

  
149
    case 0x10:	/* MCSPI_SYSCONFIG */
150
        return s->sysconfig;
151

  
152
    case 0x14:	/* MCSPI_SYSSTATUS */
153
        return 1;					/* RESETDONE */
154

  
155
    case 0x18:	/* MCSPI_IRQSTATUS */
156
        return s->irqst;
157

  
158
    case 0x1c:	/* MCSPI_IRQENABLE */
159
        return s->irqen;
160

  
161
    case 0x20:	/* MCSPI_WAKEUPENABLE */
162
        return s->wken;
163

  
164
    case 0x24:	/* MCSPI_SYST */
165
        return s->systest;
166

  
167
    case 0x28:	/* MCSPI_MODULCTRL */
168
        return s->control;
169

  
170
    case 0x68: ch ++;
171
    case 0x54: ch ++;
172
    case 0x40: ch ++;
173
    case 0x2c:	/* MCSPI_CHCONF */
174
        return s->ch[ch].config;
175

  
176
    case 0x6c: ch ++;
177
    case 0x58: ch ++;
178
    case 0x44: ch ++;
179
    case 0x30:	/* MCSPI_CHSTAT */
180
        return s->ch[ch].status;
181

  
182
    case 0x70: ch ++;
183
    case 0x5c: ch ++;
184
    case 0x48: ch ++;
185
    case 0x34:	/* MCSPI_CHCTRL */
186
        return s->ch[ch].control;
187

  
188
    case 0x74: ch ++;
189
    case 0x60: ch ++;
190
    case 0x4c: ch ++;
191
    case 0x38:	/* MCSPI_TX */
192
        return s->ch[ch].tx;
193

  
194
    case 0x78: ch ++;
195
    case 0x64: ch ++;
196
    case 0x50: ch ++;
197
    case 0x3c:	/* MCSPI_RX */
198
        s->ch[ch].status &= ~(1 << 0);			/* RXS */
199
        ret = s->ch[ch].rx;
200
        omap_mcspi_transfer_run(s, ch);
201
        return ret;
202
    }
203

  
204
    OMAP_BAD_REG(addr);
205
    return 0;
206
}
207

  
208
static void omap_mcspi_write(void *opaque, target_phys_addr_t addr,
209
                uint32_t value)
210
{
211
    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
212
    int ch = 0;
213

  
214
    switch (addr) {
215
    case 0x00:	/* MCSPI_REVISION */
216
    case 0x14:	/* MCSPI_SYSSTATUS */
217
    case 0x30:	/* MCSPI_CHSTAT0 */
218
    case 0x3c:	/* MCSPI_RX0 */
219
    case 0x44:	/* MCSPI_CHSTAT1 */
220
    case 0x50:	/* MCSPI_RX1 */
221
    case 0x58:	/* MCSPI_CHSTAT2 */
222
    case 0x64:	/* MCSPI_RX2 */
223
    case 0x6c:	/* MCSPI_CHSTAT3 */
224
    case 0x78:	/* MCSPI_RX3 */
225
        OMAP_RO_REG(addr);
226
        return;
227

  
228
    case 0x10:	/* MCSPI_SYSCONFIG */
229
        if (value & (1 << 1))				/* SOFTRESET */
230
            omap_mcspi_reset(s);
231
        s->sysconfig = value & 0x31d;
232
        break;
233

  
234
    case 0x18:	/* MCSPI_IRQSTATUS */
235
        if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
236
            s->irqst &= ~value;
237
            omap_mcspi_interrupt_update(s);
238
        }
239
        break;
240

  
241
    case 0x1c:	/* MCSPI_IRQENABLE */
242
        s->irqen = value & 0x1777f;
243
        omap_mcspi_interrupt_update(s);
244
        break;
245

  
246
    case 0x20:	/* MCSPI_WAKEUPENABLE */
247
        s->wken = value & 1;
248
        break;
249

  
250
    case 0x24:	/* MCSPI_SYST */
251
        if (s->control & (1 << 3))			/* SYSTEM_TEST */
252
            if (value & (1 << 11)) {			/* SSB */
253
                s->irqst |= 0x1777f;
254
                omap_mcspi_interrupt_update(s);
255
            }
256
        s->systest = value & 0xfff;
257
        break;
258

  
259
    case 0x28:	/* MCSPI_MODULCTRL */
260
        if (value & (1 << 3))				/* SYSTEM_TEST */
261
            if (s->systest & (1 << 11)) {		/* SSB */
262
                s->irqst |= 0x1777f;
263
                omap_mcspi_interrupt_update(s);
264
            }
265
        s->control = value & 0xf;
266
        break;
267

  
268
    case 0x68: ch ++;
269
    case 0x54: ch ++;
270
    case 0x40: ch ++;
271
    case 0x2c:	/* MCSPI_CHCONF */
272
        if ((value ^ s->ch[ch].config) & (3 << 14))	/* DMAR | DMAW */
273
            omap_mcspi_dmarequest_update(s->ch + ch);
274
        if (((value >> 12) & 3) == 3)			/* TRM */
275
            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
276
        if (((value >> 7) & 0x1f) < 3)			/* WL */
277
            fprintf(stderr, "%s: invalid WL value (%i)\n",
278
                            __FUNCTION__, (value >> 7) & 0x1f);
279
        s->ch[ch].config = value & 0x7fffff;
280
        break;
281

  
282
    case 0x70: ch ++;
283
    case 0x5c: ch ++;
284
    case 0x48: ch ++;
285
    case 0x34:	/* MCSPI_CHCTRL */
286
        if (value & ~s->ch[ch].control & 1) {		/* EN */
287
            s->ch[ch].control |= 1;
288
            omap_mcspi_transfer_run(s, ch);
289
        } else
290
            s->ch[ch].control = value & 1;
291
        break;
292

  
293
    case 0x74: ch ++;
294
    case 0x60: ch ++;
295
    case 0x4c: ch ++;
296
    case 0x38:	/* MCSPI_TX */
297
        s->ch[ch].tx = value;
298
        s->ch[ch].status &= ~(1 << 1);			/* TXS */
299
        omap_mcspi_transfer_run(s, ch);
300
        break;
301

  
302
    default:
303
        OMAP_BAD_REG(addr);
304
        return;
305
    }
306
}
307

  
308
static CPUReadMemoryFunc * const omap_mcspi_readfn[] = {
309
    omap_badwidth_read32,
310
    omap_badwidth_read32,
311
    omap_mcspi_read,
312
};
313

  
314
static CPUWriteMemoryFunc * const omap_mcspi_writefn[] = {
315
    omap_badwidth_write32,
316
    omap_badwidth_write32,
317
    omap_mcspi_write,
318
};
319

  
320
struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
321
                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
322
{
323
    int iomemtype;
324
    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
325
            qemu_mallocz(sizeof(struct omap_mcspi_s));
326
    struct omap_mcspi_ch_s *ch = s->ch;
327

  
328
    s->irq = irq;
329
    s->chnum = chnum;
330
    while (chnum --) {
331
        ch->txdrq = *drq ++;
332
        ch->rxdrq = *drq ++;
333
        ch ++;
334
    }
335
    omap_mcspi_reset(s);
336

  
337
    iomemtype = l4_register_io_memory(omap_mcspi_readfn,
338
                    omap_mcspi_writefn, s);
339
    omap_l4_attach(ta, 0, iomemtype);
340

  
341
    return s;
342
}
343

  
344
void omap_mcspi_attach(struct omap_mcspi_s *s,
345
                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
346
                int chipselect)
347
{
348
    if (chipselect < 0 || chipselect >= s->chnum)
349
        hw_error("%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
350

  
351
    s->ch[chipselect].txrx = txrx;
352
    s->ch[chipselect].opaque = opaque;
353
}
354

  
355 32
/* Enhanced Audio Controller (CODEC only) */
356 33
struct omap_eac_s {
357 34
    qemu_irq irq;

Also available in: Unified diff