xref: /qemu/hw/arm/pxa2xx.c (revision 607ef570)
1dd285b06SPaolo Bonzini /*
2dd285b06SPaolo Bonzini  * Intel XScale PXA255/270 processor support.
3dd285b06SPaolo Bonzini  *
4dd285b06SPaolo Bonzini  * Copyright (c) 2006 Openedhand Ltd.
5dd285b06SPaolo Bonzini  * Written by Andrzej Zaborowski <balrog@zabor.org>
6dd285b06SPaolo Bonzini  *
7dd285b06SPaolo Bonzini  * This code is licensed under the GPL.
8dd285b06SPaolo Bonzini  */
9dd285b06SPaolo Bonzini 
1012b16722SPeter Maydell #include "qemu/osdep.h"
11c0dbca36SAlistair Francis #include "qemu/error-report.h"
120b8fa32fSMarkus Armbruster #include "qemu/module.h"
13da34e65cSMarkus Armbruster #include "qapi/error.h"
14abf8361cSPhilippe Mathieu-Daudé #include "exec/address-spaces.h"
154771d756SPaolo Bonzini #include "cpu.h"
16dd285b06SPaolo Bonzini #include "hw/sysbus.h"
17d6454270SMarkus Armbruster #include "migration/vmstate.h"
180d09e41aSPaolo Bonzini #include "hw/arm/pxa.h"
19dd285b06SPaolo Bonzini #include "sysemu/sysemu.h"
200d09e41aSPaolo Bonzini #include "hw/char/serial.h"
210d09e41aSPaolo Bonzini #include "hw/i2c/i2c.h"
2264552b6bSMarkus Armbruster #include "hw/irq.h"
23a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
24ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
258fd06719SAlistair Francis #include "hw/ssi/ssi.h"
26d7ebca74SPhilippe Mathieu-Daudé #include "hw/sd/sd.h"
274d43a603SMarc-André Lureau #include "chardev/char-fe.h"
28dd285b06SPaolo Bonzini #include "sysemu/blockdev.h"
29a82929a2SThomas Huth #include "sysemu/qtest.h"
302f93d8b0SPeter Maydell #include "sysemu/rtc.h"
31f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
32fc417e5bSPhilippe Mathieu-Daudé #include "qemu/log.h"
33db1015e9SEduardo Habkost #include "qom/object.h"
34cf7c6d10SRichard Henderson #include "target/arm/cpregs.h"
35dd285b06SPaolo Bonzini 
36dd285b06SPaolo Bonzini static struct {
37dd285b06SPaolo Bonzini     hwaddr io_base;
38dd285b06SPaolo Bonzini     int irqn;
39dd285b06SPaolo Bonzini } pxa255_serial[] = {
40dd285b06SPaolo Bonzini     { 0x40100000, PXA2XX_PIC_FFUART },
41dd285b06SPaolo Bonzini     { 0x40200000, PXA2XX_PIC_BTUART },
42dd285b06SPaolo Bonzini     { 0x40700000, PXA2XX_PIC_STUART },
43dd285b06SPaolo Bonzini     { 0x41600000, PXA25X_PIC_HWUART },
44dd285b06SPaolo Bonzini     { 0, 0 }
45dd285b06SPaolo Bonzini }, pxa270_serial[] = {
46dd285b06SPaolo Bonzini     { 0x40100000, PXA2XX_PIC_FFUART },
47dd285b06SPaolo Bonzini     { 0x40200000, PXA2XX_PIC_BTUART },
48dd285b06SPaolo Bonzini     { 0x40700000, PXA2XX_PIC_STUART },
49dd285b06SPaolo Bonzini     { 0, 0 }
50dd285b06SPaolo Bonzini };
51dd285b06SPaolo Bonzini 
52dd285b06SPaolo Bonzini typedef struct PXASSPDef {
53dd285b06SPaolo Bonzini     hwaddr io_base;
54dd285b06SPaolo Bonzini     int irqn;
55dd285b06SPaolo Bonzini } PXASSPDef;
56dd285b06SPaolo Bonzini 
57dd285b06SPaolo Bonzini #if 0
58dd285b06SPaolo Bonzini static PXASSPDef pxa250_ssp[] = {
59dd285b06SPaolo Bonzini     { 0x41000000, PXA2XX_PIC_SSP },
60dd285b06SPaolo Bonzini     { 0, 0 }
61dd285b06SPaolo Bonzini };
62dd285b06SPaolo Bonzini #endif
63dd285b06SPaolo Bonzini 
64dd285b06SPaolo Bonzini static PXASSPDef pxa255_ssp[] = {
65dd285b06SPaolo Bonzini     { 0x41000000, PXA2XX_PIC_SSP },
66dd285b06SPaolo Bonzini     { 0x41400000, PXA25X_PIC_NSSP },
67dd285b06SPaolo Bonzini     { 0, 0 }
68dd285b06SPaolo Bonzini };
69dd285b06SPaolo Bonzini 
70dd285b06SPaolo Bonzini #if 0
71dd285b06SPaolo Bonzini static PXASSPDef pxa26x_ssp[] = {
72dd285b06SPaolo Bonzini     { 0x41000000, PXA2XX_PIC_SSP },
73dd285b06SPaolo Bonzini     { 0x41400000, PXA25X_PIC_NSSP },
74dd285b06SPaolo Bonzini     { 0x41500000, PXA26X_PIC_ASSP },
75dd285b06SPaolo Bonzini     { 0, 0 }
76dd285b06SPaolo Bonzini };
77dd285b06SPaolo Bonzini #endif
78dd285b06SPaolo Bonzini 
79dd285b06SPaolo Bonzini static PXASSPDef pxa27x_ssp[] = {
80dd285b06SPaolo Bonzini     { 0x41000000, PXA2XX_PIC_SSP },
81dd285b06SPaolo Bonzini     { 0x41700000, PXA27X_PIC_SSP2 },
82dd285b06SPaolo Bonzini     { 0x41900000, PXA2XX_PIC_SSP3 },
83dd285b06SPaolo Bonzini     { 0, 0 }
84dd285b06SPaolo Bonzini };
85dd285b06SPaolo Bonzini 
86dd285b06SPaolo Bonzini #define PMCR	0x00	/* Power Manager Control register */
87dd285b06SPaolo Bonzini #define PSSR	0x04	/* Power Manager Sleep Status register */
88dd285b06SPaolo Bonzini #define PSPR	0x08	/* Power Manager Scratch-Pad register */
89dd285b06SPaolo Bonzini #define PWER	0x0c	/* Power Manager Wake-Up Enable register */
90dd285b06SPaolo Bonzini #define PRER	0x10	/* Power Manager Rising-Edge Detect Enable register */
91dd285b06SPaolo Bonzini #define PFER	0x14	/* Power Manager Falling-Edge Detect Enable register */
92dd285b06SPaolo Bonzini #define PEDR	0x18	/* Power Manager Edge-Detect Status register */
93dd285b06SPaolo Bonzini #define PCFR	0x1c	/* Power Manager General Configuration register */
94dd285b06SPaolo Bonzini #define PGSR0	0x20	/* Power Manager GPIO Sleep-State register 0 */
95dd285b06SPaolo Bonzini #define PGSR1	0x24	/* Power Manager GPIO Sleep-State register 1 */
96dd285b06SPaolo Bonzini #define PGSR2	0x28	/* Power Manager GPIO Sleep-State register 2 */
97dd285b06SPaolo Bonzini #define PGSR3	0x2c	/* Power Manager GPIO Sleep-State register 3 */
98dd285b06SPaolo Bonzini #define RCSR	0x30	/* Reset Controller Status register */
99dd285b06SPaolo Bonzini #define PSLR	0x34	/* Power Manager Sleep Configuration register */
100dd285b06SPaolo Bonzini #define PTSR	0x38	/* Power Manager Standby Configuration register */
101dd285b06SPaolo Bonzini #define PVCR	0x40	/* Power Manager Voltage Change Control register */
102dd285b06SPaolo Bonzini #define PUCR	0x4c	/* Power Manager USIM Card Control/Status register */
103dd285b06SPaolo Bonzini #define PKWR	0x50	/* Power Manager Keyboard Wake-Up Enable register */
104dd285b06SPaolo Bonzini #define PKSR	0x54	/* Power Manager Keyboard Level-Detect Status */
105dd285b06SPaolo Bonzini #define PCMD0	0x80	/* Power Manager I2C Command register File 0 */
106dd285b06SPaolo Bonzini #define PCMD31	0xfc	/* Power Manager I2C Command register File 31 */
107dd285b06SPaolo Bonzini 
pxa2xx_pm_read(void * opaque,hwaddr addr,unsigned size)108dd285b06SPaolo Bonzini static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr,
109dd285b06SPaolo Bonzini                                unsigned size)
110dd285b06SPaolo Bonzini {
111dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *) opaque;
112dd285b06SPaolo Bonzini 
113dd285b06SPaolo Bonzini     switch (addr) {
114dd285b06SPaolo Bonzini     case PMCR ... PCMD31:
115dd285b06SPaolo Bonzini         if (addr & 3)
116dd285b06SPaolo Bonzini             goto fail;
117dd285b06SPaolo Bonzini 
118dd285b06SPaolo Bonzini         return s->pm_regs[addr >> 2];
119dd285b06SPaolo Bonzini     default:
120dd285b06SPaolo Bonzini     fail:
121fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
122fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
123fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
124dd285b06SPaolo Bonzini         break;
125dd285b06SPaolo Bonzini     }
126dd285b06SPaolo Bonzini     return 0;
127dd285b06SPaolo Bonzini }
128dd285b06SPaolo Bonzini 
pxa2xx_pm_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)129dd285b06SPaolo Bonzini static void pxa2xx_pm_write(void *opaque, hwaddr addr,
130dd285b06SPaolo Bonzini                             uint64_t value, unsigned size)
131dd285b06SPaolo Bonzini {
132dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *) opaque;
133dd285b06SPaolo Bonzini 
134dd285b06SPaolo Bonzini     switch (addr) {
135dd285b06SPaolo Bonzini     case PMCR:
136dd285b06SPaolo Bonzini         /* Clear the write-one-to-clear bits... */
137dd285b06SPaolo Bonzini         s->pm_regs[addr >> 2] &= ~(value & 0x2a);
138dd285b06SPaolo Bonzini         /* ...and set the plain r/w bits */
139dd285b06SPaolo Bonzini         s->pm_regs[addr >> 2] &= ~0x15;
140dd285b06SPaolo Bonzini         s->pm_regs[addr >> 2] |= value & 0x15;
141dd285b06SPaolo Bonzini         break;
142dd285b06SPaolo Bonzini 
143dd285b06SPaolo Bonzini     case PSSR:	/* Read-clean registers */
144dd285b06SPaolo Bonzini     case RCSR:
145dd285b06SPaolo Bonzini     case PKSR:
146dd285b06SPaolo Bonzini         s->pm_regs[addr >> 2] &= ~value;
147dd285b06SPaolo Bonzini         break;
148dd285b06SPaolo Bonzini 
149dd285b06SPaolo Bonzini     default:	/* Read-write registers */
150dd285b06SPaolo Bonzini         if (!(addr & 3)) {
151dd285b06SPaolo Bonzini             s->pm_regs[addr >> 2] = value;
152dd285b06SPaolo Bonzini             break;
153dd285b06SPaolo Bonzini         }
154fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
155fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
156fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
157dd285b06SPaolo Bonzini         break;
158dd285b06SPaolo Bonzini     }
159dd285b06SPaolo Bonzini }
160dd285b06SPaolo Bonzini 
161dd285b06SPaolo Bonzini static const MemoryRegionOps pxa2xx_pm_ops = {
162dd285b06SPaolo Bonzini     .read = pxa2xx_pm_read,
163dd285b06SPaolo Bonzini     .write = pxa2xx_pm_write,
164dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
165dd285b06SPaolo Bonzini };
166dd285b06SPaolo Bonzini 
167dd285b06SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_pm = {
168dd285b06SPaolo Bonzini     .name = "pxa2xx_pm",
169dd285b06SPaolo Bonzini     .version_id = 0,
170dd285b06SPaolo Bonzini     .minimum_version_id = 0,
171*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
172dd285b06SPaolo Bonzini         VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
173dd285b06SPaolo Bonzini         VMSTATE_END_OF_LIST()
174dd285b06SPaolo Bonzini     }
175dd285b06SPaolo Bonzini };
176dd285b06SPaolo Bonzini 
177dd285b06SPaolo Bonzini #define CCCR	0x00	/* Core Clock Configuration register */
178dd285b06SPaolo Bonzini #define CKEN	0x04	/* Clock Enable register */
179dd285b06SPaolo Bonzini #define OSCC	0x08	/* Oscillator Configuration register */
180dd285b06SPaolo Bonzini #define CCSR	0x0c	/* Core Clock Status register */
181dd285b06SPaolo Bonzini 
pxa2xx_cm_read(void * opaque,hwaddr addr,unsigned size)182dd285b06SPaolo Bonzini static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr,
183dd285b06SPaolo Bonzini                                unsigned size)
184dd285b06SPaolo Bonzini {
185dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *) opaque;
186dd285b06SPaolo Bonzini 
187dd285b06SPaolo Bonzini     switch (addr) {
188dd285b06SPaolo Bonzini     case CCCR:
189dd285b06SPaolo Bonzini     case CKEN:
190dd285b06SPaolo Bonzini     case OSCC:
191dd285b06SPaolo Bonzini         return s->cm_regs[addr >> 2];
192dd285b06SPaolo Bonzini 
193dd285b06SPaolo Bonzini     case CCSR:
194dd285b06SPaolo Bonzini         return s->cm_regs[CCCR >> 2] | (3 << 28);
195dd285b06SPaolo Bonzini 
196dd285b06SPaolo Bonzini     default:
197fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
198fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
199fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
200dd285b06SPaolo Bonzini         break;
201dd285b06SPaolo Bonzini     }
202dd285b06SPaolo Bonzini     return 0;
203dd285b06SPaolo Bonzini }
204dd285b06SPaolo Bonzini 
pxa2xx_cm_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)205dd285b06SPaolo Bonzini static void pxa2xx_cm_write(void *opaque, hwaddr addr,
206dd285b06SPaolo Bonzini                             uint64_t value, unsigned size)
207dd285b06SPaolo Bonzini {
208dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *) opaque;
209dd285b06SPaolo Bonzini 
210dd285b06SPaolo Bonzini     switch (addr) {
211dd285b06SPaolo Bonzini     case CCCR:
212dd285b06SPaolo Bonzini     case CKEN:
213dd285b06SPaolo Bonzini         s->cm_regs[addr >> 2] = value;
214dd285b06SPaolo Bonzini         break;
215dd285b06SPaolo Bonzini 
216dd285b06SPaolo Bonzini     case OSCC:
217dd285b06SPaolo Bonzini         s->cm_regs[addr >> 2] &= ~0x6c;
218dd285b06SPaolo Bonzini         s->cm_regs[addr >> 2] |= value & 0x6e;
219dd285b06SPaolo Bonzini         if ((value >> 1) & 1)			/* OON */
220dd285b06SPaolo Bonzini             s->cm_regs[addr >> 2] |= 1 << 0;	/* Oscillator is now stable */
221dd285b06SPaolo Bonzini         break;
222dd285b06SPaolo Bonzini 
223dd285b06SPaolo Bonzini     default:
224fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
225fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
226fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
227dd285b06SPaolo Bonzini         break;
228dd285b06SPaolo Bonzini     }
229dd285b06SPaolo Bonzini }
230dd285b06SPaolo Bonzini 
231dd285b06SPaolo Bonzini static const MemoryRegionOps pxa2xx_cm_ops = {
232dd285b06SPaolo Bonzini     .read = pxa2xx_cm_read,
233dd285b06SPaolo Bonzini     .write = pxa2xx_cm_write,
234dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
235dd285b06SPaolo Bonzini };
236dd285b06SPaolo Bonzini 
237dd285b06SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_cm = {
238dd285b06SPaolo Bonzini     .name = "pxa2xx_cm",
239dd285b06SPaolo Bonzini     .version_id = 0,
240dd285b06SPaolo Bonzini     .minimum_version_id = 0,
241*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
242dd285b06SPaolo Bonzini         VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
243dd285b06SPaolo Bonzini         VMSTATE_UINT32(clkcfg, PXA2xxState),
244dd285b06SPaolo Bonzini         VMSTATE_UINT32(pmnc, PXA2xxState),
245dd285b06SPaolo Bonzini         VMSTATE_END_OF_LIST()
246dd285b06SPaolo Bonzini     }
247dd285b06SPaolo Bonzini };
248dd285b06SPaolo Bonzini 
pxa2xx_clkcfg_read(CPUARMState * env,const ARMCPRegInfo * ri)249c4241c7dSPeter Maydell static uint64_t pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri)
250dd285b06SPaolo Bonzini {
251dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *)ri->opaque;
252c4241c7dSPeter Maydell     return s->clkcfg;
253dd285b06SPaolo Bonzini }
254dd285b06SPaolo Bonzini 
pxa2xx_clkcfg_write(CPUARMState * env,const ARMCPRegInfo * ri,uint64_t value)255c4241c7dSPeter Maydell static void pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
256dd285b06SPaolo Bonzini                                 uint64_t value)
257dd285b06SPaolo Bonzini {
258dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *)ri->opaque;
259dd285b06SPaolo Bonzini     s->clkcfg = value & 0xf;
260dd285b06SPaolo Bonzini     if (value & 2) {
261dd285b06SPaolo Bonzini         printf("%s: CPU frequency change attempt\n", __func__);
262dd285b06SPaolo Bonzini     }
263dd285b06SPaolo Bonzini }
264dd285b06SPaolo Bonzini 
pxa2xx_pwrmode_write(CPUARMState * env,const ARMCPRegInfo * ri,uint64_t value)265c4241c7dSPeter Maydell static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
266dd285b06SPaolo Bonzini                                  uint64_t value)
267dd285b06SPaolo Bonzini {
268dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *)ri->opaque;
269dd285b06SPaolo Bonzini     static const char *pwrmode[8] = {
270dd285b06SPaolo Bonzini         "Normal", "Idle", "Deep-idle", "Standby",
271dd285b06SPaolo Bonzini         "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
272dd285b06SPaolo Bonzini     };
273dd285b06SPaolo Bonzini 
274dd285b06SPaolo Bonzini     if (value & 8) {
275dd285b06SPaolo Bonzini         printf("%s: CPU voltage change attempt\n", __func__);
276dd285b06SPaolo Bonzini     }
277dd285b06SPaolo Bonzini     switch (value & 7) {
278dd285b06SPaolo Bonzini     case 0:
279dd285b06SPaolo Bonzini         /* Do nothing */
280dd285b06SPaolo Bonzini         break;
281dd285b06SPaolo Bonzini 
282dd285b06SPaolo Bonzini     case 1:
283dd285b06SPaolo Bonzini         /* Idle */
28443a32ed6SPeter Maydell         if (!(s->cm_regs[CCCR >> 2] & (1U << 31))) { /* CPDIS */
285c3affe56SAndreas Färber             cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
286dd285b06SPaolo Bonzini             break;
287dd285b06SPaolo Bonzini         }
288dd285b06SPaolo Bonzini         /* Fall through.  */
289dd285b06SPaolo Bonzini 
290dd285b06SPaolo Bonzini     case 2:
291dd285b06SPaolo Bonzini         /* Deep-Idle */
292c3affe56SAndreas Färber         cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
293dd285b06SPaolo Bonzini         s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
294dd285b06SPaolo Bonzini         goto message;
295dd285b06SPaolo Bonzini 
296dd285b06SPaolo Bonzini     case 3:
2974cc35614SPeter Maydell         s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
2984cc35614SPeter Maydell         s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
299137feaa9SFabian Aggeler         s->cpu->env.cp15.sctlr_ns = 0;
3007ebd5f2eSSergey Fedorov         s->cpu->env.cp15.cpacr_el1 = 0;
3017dd8c9afSFabian Aggeler         s->cpu->env.cp15.ttbr0_el[1] = 0;
3020c17d68cSFabian Aggeler         s->cpu->env.cp15.dacr_ns = 0;
303dd285b06SPaolo Bonzini         s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
304dd285b06SPaolo Bonzini         s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
305dd285b06SPaolo Bonzini 
306dd285b06SPaolo Bonzini         /*
307dd285b06SPaolo Bonzini          * The scratch-pad register is almost universally used
308dd285b06SPaolo Bonzini          * for storing the return address on suspend.  For the
309dd285b06SPaolo Bonzini          * lack of a resuming bootloader, perform a jump
310dd285b06SPaolo Bonzini          * directly to that address.
311dd285b06SPaolo Bonzini          */
312dd285b06SPaolo Bonzini         memset(s->cpu->env.regs, 0, 4 * 15);
313dd285b06SPaolo Bonzini         s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2];
314dd285b06SPaolo Bonzini 
315dd285b06SPaolo Bonzini #if 0
316dd285b06SPaolo Bonzini         buffer = 0xe59ff000; /* ldr     pc, [pc, #0] */
317dd285b06SPaolo Bonzini         cpu_physical_memory_write(0, &buffer, 4);
318dd285b06SPaolo Bonzini         buffer = s->pm_regs[PSPR >> 2];
319dd285b06SPaolo Bonzini         cpu_physical_memory_write(8, &buffer, 4);
320dd285b06SPaolo Bonzini #endif
321dd285b06SPaolo Bonzini 
322dd285b06SPaolo Bonzini         /* Suspend */
3234917cf44SAndreas Färber         cpu_interrupt(current_cpu, CPU_INTERRUPT_HALT);
324dd285b06SPaolo Bonzini 
325dd285b06SPaolo Bonzini         goto message;
326dd285b06SPaolo Bonzini 
327dd285b06SPaolo Bonzini     default:
328dd285b06SPaolo Bonzini     message:
329dd285b06SPaolo Bonzini         printf("%s: machine entered %s mode\n", __func__,
330dd285b06SPaolo Bonzini                pwrmode[value & 7]);
331dd285b06SPaolo Bonzini     }
332dd285b06SPaolo Bonzini }
333dd285b06SPaolo Bonzini 
pxa2xx_cppmnc_read(CPUARMState * env,const ARMCPRegInfo * ri)334c4241c7dSPeter Maydell static uint64_t pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri)
335dd285b06SPaolo Bonzini {
336dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *)ri->opaque;
337c4241c7dSPeter Maydell     return s->pmnc;
338dd285b06SPaolo Bonzini }
339dd285b06SPaolo Bonzini 
pxa2xx_cppmnc_write(CPUARMState * env,const ARMCPRegInfo * ri,uint64_t value)340c4241c7dSPeter Maydell static void pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
341dd285b06SPaolo Bonzini                                 uint64_t value)
342dd285b06SPaolo Bonzini {
343dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *)ri->opaque;
344dd285b06SPaolo Bonzini     s->pmnc = value;
345dd285b06SPaolo Bonzini }
346dd285b06SPaolo Bonzini 
pxa2xx_cpccnt_read(CPUARMState * env,const ARMCPRegInfo * ri)347c4241c7dSPeter Maydell static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
348dd285b06SPaolo Bonzini {
349dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *)ri->opaque;
350dd285b06SPaolo Bonzini     if (s->pmnc & 1) {
351c4241c7dSPeter Maydell         return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
352dd285b06SPaolo Bonzini     } else {
353dd285b06SPaolo Bonzini         return 0;
354dd285b06SPaolo Bonzini     }
355c4241c7dSPeter Maydell }
356dd285b06SPaolo Bonzini 
357dd285b06SPaolo Bonzini static const ARMCPRegInfo pxa_cp_reginfo[] = {
358dd285b06SPaolo Bonzini     /* cp14 crm==1: perf registers */
359dd285b06SPaolo Bonzini     { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0,
36014c3032aSPeter Maydell       .access = PL1_RW, .type = ARM_CP_IO,
361dd285b06SPaolo Bonzini       .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write },
362dd285b06SPaolo Bonzini     { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
36314c3032aSPeter Maydell       .access = PL1_RW, .type = ARM_CP_IO,
364dd285b06SPaolo Bonzini       .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore },
365dd285b06SPaolo Bonzini     { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0,
366dd285b06SPaolo Bonzini       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
367dd285b06SPaolo Bonzini     { .name = "CPFLAG", .cp = 14, .crn = 5, .crm = 1, .opc1 = 0, .opc2 = 0,
368dd285b06SPaolo Bonzini       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
369dd285b06SPaolo Bonzini     { .name = "CPEVTSEL", .cp = 14, .crn = 8, .crm = 1, .opc1 = 0, .opc2 = 0,
370dd285b06SPaolo Bonzini       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
371dd285b06SPaolo Bonzini     /* cp14 crm==2: performance count registers */
372dd285b06SPaolo Bonzini     { .name = "CPPMN0", .cp = 14, .crn = 0, .crm = 2, .opc1 = 0, .opc2 = 0,
373dd285b06SPaolo Bonzini       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
374dd285b06SPaolo Bonzini     { .name = "CPPMN1", .cp = 14, .crn = 1, .crm = 2, .opc1 = 0, .opc2 = 0,
375dd285b06SPaolo Bonzini       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
376dd285b06SPaolo Bonzini     { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0,
377dd285b06SPaolo Bonzini       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
378dd285b06SPaolo Bonzini     { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0,
379dd285b06SPaolo Bonzini       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
380dd285b06SPaolo Bonzini     /* cp14 crn==6: CLKCFG */
381dd285b06SPaolo Bonzini     { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
38214c3032aSPeter Maydell       .access = PL1_RW, .type = ARM_CP_IO,
383dd285b06SPaolo Bonzini       .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write },
384dd285b06SPaolo Bonzini     /* cp14 crn==7: PWRMODE */
385dd285b06SPaolo Bonzini     { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0,
38614c3032aSPeter Maydell       .access = PL1_RW, .type = ARM_CP_IO,
387dd285b06SPaolo Bonzini       .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write },
388dd285b06SPaolo Bonzini };
389dd285b06SPaolo Bonzini 
pxa2xx_setup_cp14(PXA2xxState * s)390dd285b06SPaolo Bonzini static void pxa2xx_setup_cp14(PXA2xxState *s)
391dd285b06SPaolo Bonzini {
392dd285b06SPaolo Bonzini     define_arm_cp_regs_with_opaque(s->cpu, pxa_cp_reginfo, s);
393dd285b06SPaolo Bonzini }
394dd285b06SPaolo Bonzini 
395dd285b06SPaolo Bonzini #define MDCNFG		0x00	/* SDRAM Configuration register */
396dd285b06SPaolo Bonzini #define MDREFR		0x04	/* SDRAM Refresh Control register */
397dd285b06SPaolo Bonzini #define MSC0		0x08	/* Static Memory Control register 0 */
398dd285b06SPaolo Bonzini #define MSC1		0x0c	/* Static Memory Control register 1 */
399dd285b06SPaolo Bonzini #define MSC2		0x10	/* Static Memory Control register 2 */
400dd285b06SPaolo Bonzini #define MECR		0x14	/* Expansion Memory Bus Config register */
401dd285b06SPaolo Bonzini #define SXCNFG		0x1c	/* Synchronous Static Memory Config register */
402dd285b06SPaolo Bonzini #define MCMEM0		0x28	/* PC Card Memory Socket 0 Timing register */
403dd285b06SPaolo Bonzini #define MCMEM1		0x2c	/* PC Card Memory Socket 1 Timing register */
404dd285b06SPaolo Bonzini #define MCATT0		0x30	/* PC Card Attribute Socket 0 register */
405dd285b06SPaolo Bonzini #define MCATT1		0x34	/* PC Card Attribute Socket 1 register */
406dd285b06SPaolo Bonzini #define MCIO0		0x38	/* PC Card I/O Socket 0 Timing register */
407dd285b06SPaolo Bonzini #define MCIO1		0x3c	/* PC Card I/O Socket 1 Timing register */
408dd285b06SPaolo Bonzini #define MDMRS		0x40	/* SDRAM Mode Register Set Config register */
409dd285b06SPaolo Bonzini #define BOOT_DEF	0x44	/* Boot-time Default Configuration register */
410dd285b06SPaolo Bonzini #define ARB_CNTL	0x48	/* Arbiter Control register */
411dd285b06SPaolo Bonzini #define BSCNTR0		0x4c	/* Memory Buffer Strength Control register 0 */
412dd285b06SPaolo Bonzini #define BSCNTR1		0x50	/* Memory Buffer Strength Control register 1 */
413dd285b06SPaolo Bonzini #define LCDBSCNTR	0x54	/* LCD Buffer Strength Control register */
414dd285b06SPaolo Bonzini #define MDMRSLP		0x58	/* Low Power SDRAM Mode Set Config register */
415dd285b06SPaolo Bonzini #define BSCNTR2		0x5c	/* Memory Buffer Strength Control register 2 */
416dd285b06SPaolo Bonzini #define BSCNTR3		0x60	/* Memory Buffer Strength Control register 3 */
417dd285b06SPaolo Bonzini #define SA1110		0x64	/* SA-1110 Memory Compatibility register */
418dd285b06SPaolo Bonzini 
pxa2xx_mm_read(void * opaque,hwaddr addr,unsigned size)419dd285b06SPaolo Bonzini static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr,
420dd285b06SPaolo Bonzini                                unsigned size)
421dd285b06SPaolo Bonzini {
422dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *) opaque;
423dd285b06SPaolo Bonzini 
424dd285b06SPaolo Bonzini     switch (addr) {
425dd285b06SPaolo Bonzini     case MDCNFG ... SA1110:
426dd285b06SPaolo Bonzini         if ((addr & 3) == 0)
427dd285b06SPaolo Bonzini             return s->mm_regs[addr >> 2];
428edd7541bSPaolo Bonzini         /* fall through */
429dd285b06SPaolo Bonzini     default:
430fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
431fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
432fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
433dd285b06SPaolo Bonzini         break;
434dd285b06SPaolo Bonzini     }
435dd285b06SPaolo Bonzini     return 0;
436dd285b06SPaolo Bonzini }
437dd285b06SPaolo Bonzini 
pxa2xx_mm_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)438dd285b06SPaolo Bonzini static void pxa2xx_mm_write(void *opaque, hwaddr addr,
439dd285b06SPaolo Bonzini                             uint64_t value, unsigned size)
440dd285b06SPaolo Bonzini {
441dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *) opaque;
442dd285b06SPaolo Bonzini 
443dd285b06SPaolo Bonzini     switch (addr) {
444dd285b06SPaolo Bonzini     case MDCNFG ... SA1110:
445dd285b06SPaolo Bonzini         if ((addr & 3) == 0) {
446dd285b06SPaolo Bonzini             s->mm_regs[addr >> 2] = value;
447dd285b06SPaolo Bonzini             break;
448dd285b06SPaolo Bonzini         }
4495ace4cc0SThomas Huth         /* fallthrough */
450dd285b06SPaolo Bonzini     default:
451fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
452fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
453fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
454dd285b06SPaolo Bonzini         break;
455dd285b06SPaolo Bonzini     }
456dd285b06SPaolo Bonzini }
457dd285b06SPaolo Bonzini 
458dd285b06SPaolo Bonzini static const MemoryRegionOps pxa2xx_mm_ops = {
459dd285b06SPaolo Bonzini     .read = pxa2xx_mm_read,
460dd285b06SPaolo Bonzini     .write = pxa2xx_mm_write,
461dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
462dd285b06SPaolo Bonzini };
463dd285b06SPaolo Bonzini 
464dd285b06SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_mm = {
465dd285b06SPaolo Bonzini     .name = "pxa2xx_mm",
466dd285b06SPaolo Bonzini     .version_id = 0,
467dd285b06SPaolo Bonzini     .minimum_version_id = 0,
468*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
469dd285b06SPaolo Bonzini         VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
470dd285b06SPaolo Bonzini         VMSTATE_END_OF_LIST()
471dd285b06SPaolo Bonzini     }
472dd285b06SPaolo Bonzini };
473dd285b06SPaolo Bonzini 
47412a82804SAndreas Färber #define TYPE_PXA2XX_SSP "pxa2xx-ssp"
4758063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxSSPState, PXA2XX_SSP)
47612a82804SAndreas Färber 
477dd285b06SPaolo Bonzini /* Synchronous Serial Ports */
478db1015e9SEduardo Habkost struct PXA2xxSSPState {
47912a82804SAndreas Färber     /*< private >*/
48012a82804SAndreas Färber     SysBusDevice parent_obj;
48112a82804SAndreas Färber     /*< public >*/
48212a82804SAndreas Färber 
483dd285b06SPaolo Bonzini     MemoryRegion iomem;
484dd285b06SPaolo Bonzini     qemu_irq irq;
4858e079cafSPeter Maydell     uint32_t enable;
486dd285b06SPaolo Bonzini     SSIBus *bus;
487dd285b06SPaolo Bonzini 
488dd285b06SPaolo Bonzini     uint32_t sscr[2];
489dd285b06SPaolo Bonzini     uint32_t sspsp;
490dd285b06SPaolo Bonzini     uint32_t ssto;
491dd285b06SPaolo Bonzini     uint32_t ssitr;
492dd285b06SPaolo Bonzini     uint32_t sssr;
493dd285b06SPaolo Bonzini     uint8_t sstsa;
494dd285b06SPaolo Bonzini     uint8_t ssrsa;
495dd285b06SPaolo Bonzini     uint8_t ssacd;
496dd285b06SPaolo Bonzini 
497dd285b06SPaolo Bonzini     uint32_t rx_fifo[16];
4988e079cafSPeter Maydell     uint32_t rx_level;
4998e079cafSPeter Maydell     uint32_t rx_start;
500db1015e9SEduardo Habkost };
501dd285b06SPaolo Bonzini 
pxa2xx_ssp_vmstate_validate(void * opaque,int version_id)5028e079cafSPeter Maydell static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id)
5038e079cafSPeter Maydell {
5048e079cafSPeter Maydell     PXA2xxSSPState *s = opaque;
5058e079cafSPeter Maydell 
5068e079cafSPeter Maydell     return s->rx_start < sizeof(s->rx_fifo);
5078e079cafSPeter Maydell }
5088e079cafSPeter Maydell 
5098e079cafSPeter Maydell static const VMStateDescription vmstate_pxa2xx_ssp = {
5108e079cafSPeter Maydell     .name = "pxa2xx-ssp",
5118e079cafSPeter Maydell     .version_id = 1,
5128e079cafSPeter Maydell     .minimum_version_id = 1,
513*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
5148e079cafSPeter Maydell         VMSTATE_UINT32(enable, PXA2xxSSPState),
5158e079cafSPeter Maydell         VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2),
5168e079cafSPeter Maydell         VMSTATE_UINT32(sspsp, PXA2xxSSPState),
5178e079cafSPeter Maydell         VMSTATE_UINT32(ssto, PXA2xxSSPState),
5188e079cafSPeter Maydell         VMSTATE_UINT32(ssitr, PXA2xxSSPState),
5198e079cafSPeter Maydell         VMSTATE_UINT32(sssr, PXA2xxSSPState),
5208e079cafSPeter Maydell         VMSTATE_UINT8(sstsa, PXA2xxSSPState),
5218e079cafSPeter Maydell         VMSTATE_UINT8(ssrsa, PXA2xxSSPState),
5228e079cafSPeter Maydell         VMSTATE_UINT8(ssacd, PXA2xxSSPState),
5238e079cafSPeter Maydell         VMSTATE_UINT32(rx_level, PXA2xxSSPState),
5248e079cafSPeter Maydell         VMSTATE_UINT32(rx_start, PXA2xxSSPState),
5258e079cafSPeter Maydell         VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate),
5268e079cafSPeter Maydell         VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16),
5278e079cafSPeter Maydell         VMSTATE_END_OF_LIST()
5288e079cafSPeter Maydell     }
5298e079cafSPeter Maydell };
5308e079cafSPeter Maydell 
531dd285b06SPaolo Bonzini #define SSCR0	0x00	/* SSP Control register 0 */
532dd285b06SPaolo Bonzini #define SSCR1	0x04	/* SSP Control register 1 */
533dd285b06SPaolo Bonzini #define SSSR	0x08	/* SSP Status register */
534dd285b06SPaolo Bonzini #define SSITR	0x0c	/* SSP Interrupt Test register */
535dd285b06SPaolo Bonzini #define SSDR	0x10	/* SSP Data register */
536dd285b06SPaolo Bonzini #define SSTO	0x28	/* SSP Time-Out register */
537dd285b06SPaolo Bonzini #define SSPSP	0x2c	/* SSP Programmable Serial Protocol register */
538dd285b06SPaolo Bonzini #define SSTSA	0x30	/* SSP TX Time Slot Active register */
539dd285b06SPaolo Bonzini #define SSRSA	0x34	/* SSP RX Time Slot Active register */
540dd285b06SPaolo Bonzini #define SSTSS	0x38	/* SSP Time Slot Status register */
541dd285b06SPaolo Bonzini #define SSACD	0x3c	/* SSP Audio Clock Divider register */
542dd285b06SPaolo Bonzini 
543dd285b06SPaolo Bonzini /* Bitfields for above registers */
544dd285b06SPaolo Bonzini #define SSCR0_SPI(x)	(((x) & 0x30) == 0x00)
545dd285b06SPaolo Bonzini #define SSCR0_SSP(x)	(((x) & 0x30) == 0x10)
546dd285b06SPaolo Bonzini #define SSCR0_UWIRE(x)	(((x) & 0x30) == 0x20)
547dd285b06SPaolo Bonzini #define SSCR0_PSP(x)	(((x) & 0x30) == 0x30)
548dd285b06SPaolo Bonzini #define SSCR0_SSE	(1 << 7)
549dd285b06SPaolo Bonzini #define SSCR0_RIM	(1 << 22)
550dd285b06SPaolo Bonzini #define SSCR0_TIM	(1 << 23)
55143a32ed6SPeter Maydell #define SSCR0_MOD       (1U << 31)
552dd285b06SPaolo Bonzini #define SSCR0_DSS(x)	(((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
553dd285b06SPaolo Bonzini #define SSCR1_RIE	(1 << 0)
554dd285b06SPaolo Bonzini #define SSCR1_TIE	(1 << 1)
555dd285b06SPaolo Bonzini #define SSCR1_LBM	(1 << 2)
556dd285b06SPaolo Bonzini #define SSCR1_MWDS	(1 << 5)
557dd285b06SPaolo Bonzini #define SSCR1_TFT(x)	((((x) >> 6) & 0xf) + 1)
558dd285b06SPaolo Bonzini #define SSCR1_RFT(x)	((((x) >> 10) & 0xf) + 1)
559dd285b06SPaolo Bonzini #define SSCR1_EFWR	(1 << 14)
560dd285b06SPaolo Bonzini #define SSCR1_PINTE	(1 << 18)
561dd285b06SPaolo Bonzini #define SSCR1_TINTE	(1 << 19)
562dd285b06SPaolo Bonzini #define SSCR1_RSRE	(1 << 20)
563dd285b06SPaolo Bonzini #define SSCR1_TSRE	(1 << 21)
564dd285b06SPaolo Bonzini #define SSCR1_EBCEI	(1 << 29)
565dd285b06SPaolo Bonzini #define SSITR_INT	(7 << 5)
566dd285b06SPaolo Bonzini #define SSSR_TNF	(1 << 2)
567dd285b06SPaolo Bonzini #define SSSR_RNE	(1 << 3)
568dd285b06SPaolo Bonzini #define SSSR_TFS	(1 << 5)
569dd285b06SPaolo Bonzini #define SSSR_RFS	(1 << 6)
570dd285b06SPaolo Bonzini #define SSSR_ROR	(1 << 7)
571dd285b06SPaolo Bonzini #define SSSR_PINT	(1 << 18)
572dd285b06SPaolo Bonzini #define SSSR_TINT	(1 << 19)
573dd285b06SPaolo Bonzini #define SSSR_EOC	(1 << 20)
574dd285b06SPaolo Bonzini #define SSSR_TUR	(1 << 21)
575dd285b06SPaolo Bonzini #define SSSR_BCE	(1 << 23)
576dd285b06SPaolo Bonzini #define SSSR_RW		0x00bc0080
577dd285b06SPaolo Bonzini 
pxa2xx_ssp_int_update(PXA2xxSSPState * s)578dd285b06SPaolo Bonzini static void pxa2xx_ssp_int_update(PXA2xxSSPState *s)
579dd285b06SPaolo Bonzini {
580dd285b06SPaolo Bonzini     int level = 0;
581dd285b06SPaolo Bonzini 
582dd285b06SPaolo Bonzini     level |= s->ssitr & SSITR_INT;
583dd285b06SPaolo Bonzini     level |= (s->sssr & SSSR_BCE)  &&  (s->sscr[1] & SSCR1_EBCEI);
584dd285b06SPaolo Bonzini     level |= (s->sssr & SSSR_TUR)  && !(s->sscr[0] & SSCR0_TIM);
585dd285b06SPaolo Bonzini     level |= (s->sssr & SSSR_EOC)  &&  (s->sssr & (SSSR_TINT | SSSR_PINT));
586dd285b06SPaolo Bonzini     level |= (s->sssr & SSSR_TINT) &&  (s->sscr[1] & SSCR1_TINTE);
587dd285b06SPaolo Bonzini     level |= (s->sssr & SSSR_PINT) &&  (s->sscr[1] & SSCR1_PINTE);
588dd285b06SPaolo Bonzini     level |= (s->sssr & SSSR_ROR)  && !(s->sscr[0] & SSCR0_RIM);
589dd285b06SPaolo Bonzini     level |= (s->sssr & SSSR_RFS)  &&  (s->sscr[1] & SSCR1_RIE);
590dd285b06SPaolo Bonzini     level |= (s->sssr & SSSR_TFS)  &&  (s->sscr[1] & SSCR1_TIE);
591dd285b06SPaolo Bonzini     qemu_set_irq(s->irq, !!level);
592dd285b06SPaolo Bonzini }
593dd285b06SPaolo Bonzini 
pxa2xx_ssp_fifo_update(PXA2xxSSPState * s)594dd285b06SPaolo Bonzini static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
595dd285b06SPaolo Bonzini {
596dd285b06SPaolo Bonzini     s->sssr &= ~(0xf << 12);	/* Clear RFL */
597dd285b06SPaolo Bonzini     s->sssr &= ~(0xf << 8);	/* Clear TFL */
598dd285b06SPaolo Bonzini     s->sssr &= ~SSSR_TFS;
599dd285b06SPaolo Bonzini     s->sssr &= ~SSSR_TNF;
600dd285b06SPaolo Bonzini     if (s->enable) {
601dd285b06SPaolo Bonzini         s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
602dd285b06SPaolo Bonzini         if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
603dd285b06SPaolo Bonzini             s->sssr |= SSSR_RFS;
604dd285b06SPaolo Bonzini         else
605dd285b06SPaolo Bonzini             s->sssr &= ~SSSR_RFS;
606dd285b06SPaolo Bonzini         if (s->rx_level)
607dd285b06SPaolo Bonzini             s->sssr |= SSSR_RNE;
608dd285b06SPaolo Bonzini         else
609dd285b06SPaolo Bonzini             s->sssr &= ~SSSR_RNE;
610dd285b06SPaolo Bonzini         /* TX FIFO is never filled, so it is always in underrun
611dd285b06SPaolo Bonzini            condition if SSP is enabled */
612dd285b06SPaolo Bonzini         s->sssr |= SSSR_TFS;
613dd285b06SPaolo Bonzini         s->sssr |= SSSR_TNF;
614dd285b06SPaolo Bonzini     }
615dd285b06SPaolo Bonzini 
616dd285b06SPaolo Bonzini     pxa2xx_ssp_int_update(s);
617dd285b06SPaolo Bonzini }
618dd285b06SPaolo Bonzini 
pxa2xx_ssp_read(void * opaque,hwaddr addr,unsigned size)619dd285b06SPaolo Bonzini static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr,
620dd285b06SPaolo Bonzini                                 unsigned size)
621dd285b06SPaolo Bonzini {
622dd285b06SPaolo Bonzini     PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
623dd285b06SPaolo Bonzini     uint32_t retval;
624dd285b06SPaolo Bonzini 
625dd285b06SPaolo Bonzini     switch (addr) {
626dd285b06SPaolo Bonzini     case SSCR0:
627dd285b06SPaolo Bonzini         return s->sscr[0];
628dd285b06SPaolo Bonzini     case SSCR1:
629dd285b06SPaolo Bonzini         return s->sscr[1];
630dd285b06SPaolo Bonzini     case SSPSP:
631dd285b06SPaolo Bonzini         return s->sspsp;
632dd285b06SPaolo Bonzini     case SSTO:
633dd285b06SPaolo Bonzini         return s->ssto;
634dd285b06SPaolo Bonzini     case SSITR:
635dd285b06SPaolo Bonzini         return s->ssitr;
636dd285b06SPaolo Bonzini     case SSSR:
637dd285b06SPaolo Bonzini         return s->sssr | s->ssitr;
638dd285b06SPaolo Bonzini     case SSDR:
639dd285b06SPaolo Bonzini         if (!s->enable)
640dd285b06SPaolo Bonzini             return 0xffffffff;
641dd285b06SPaolo Bonzini         if (s->rx_level < 1) {
642a89f364aSAlistair Francis             printf("%s: SSP Rx Underrun\n", __func__);
643dd285b06SPaolo Bonzini             return 0xffffffff;
644dd285b06SPaolo Bonzini         }
645dd285b06SPaolo Bonzini         s->rx_level --;
646dd285b06SPaolo Bonzini         retval = s->rx_fifo[s->rx_start ++];
647dd285b06SPaolo Bonzini         s->rx_start &= 0xf;
648dd285b06SPaolo Bonzini         pxa2xx_ssp_fifo_update(s);
649dd285b06SPaolo Bonzini         return retval;
650dd285b06SPaolo Bonzini     case SSTSA:
651dd285b06SPaolo Bonzini         return s->sstsa;
652dd285b06SPaolo Bonzini     case SSRSA:
653dd285b06SPaolo Bonzini         return s->ssrsa;
654dd285b06SPaolo Bonzini     case SSTSS:
655dd285b06SPaolo Bonzini         return 0;
656dd285b06SPaolo Bonzini     case SSACD:
657dd285b06SPaolo Bonzini         return s->ssacd;
658dd285b06SPaolo Bonzini     default:
659fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
660fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
661fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
662dd285b06SPaolo Bonzini         break;
663dd285b06SPaolo Bonzini     }
664dd285b06SPaolo Bonzini     return 0;
665dd285b06SPaolo Bonzini }
666dd285b06SPaolo Bonzini 
pxa2xx_ssp_write(void * opaque,hwaddr addr,uint64_t value64,unsigned size)667dd285b06SPaolo Bonzini static void pxa2xx_ssp_write(void *opaque, hwaddr addr,
668dd285b06SPaolo Bonzini                              uint64_t value64, unsigned size)
669dd285b06SPaolo Bonzini {
670dd285b06SPaolo Bonzini     PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
671dd285b06SPaolo Bonzini     uint32_t value = value64;
672dd285b06SPaolo Bonzini 
673dd285b06SPaolo Bonzini     switch (addr) {
674dd285b06SPaolo Bonzini     case SSCR0:
675dd285b06SPaolo Bonzini         s->sscr[0] = value & 0xc7ffffff;
676dd285b06SPaolo Bonzini         s->enable = value & SSCR0_SSE;
677dd285b06SPaolo Bonzini         if (value & SSCR0_MOD)
678a89f364aSAlistair Francis             printf("%s: Attempt to use network mode\n", __func__);
679dd285b06SPaolo Bonzini         if (s->enable && SSCR0_DSS(value) < 4)
68098554b3bSAlexChen             printf("%s: Wrong data size: %u bits\n", __func__,
681dd285b06SPaolo Bonzini                             SSCR0_DSS(value));
682dd285b06SPaolo Bonzini         if (!(value & SSCR0_SSE)) {
683dd285b06SPaolo Bonzini             s->sssr = 0;
684dd285b06SPaolo Bonzini             s->ssitr = 0;
685dd285b06SPaolo Bonzini             s->rx_level = 0;
686dd285b06SPaolo Bonzini         }
687dd285b06SPaolo Bonzini         pxa2xx_ssp_fifo_update(s);
688dd285b06SPaolo Bonzini         break;
689dd285b06SPaolo Bonzini 
690dd285b06SPaolo Bonzini     case SSCR1:
691dd285b06SPaolo Bonzini         s->sscr[1] = value;
692dd285b06SPaolo Bonzini         if (value & (SSCR1_LBM | SSCR1_EFWR))
693a89f364aSAlistair Francis             printf("%s: Attempt to use SSP test mode\n", __func__);
694dd285b06SPaolo Bonzini         pxa2xx_ssp_fifo_update(s);
695dd285b06SPaolo Bonzini         break;
696dd285b06SPaolo Bonzini 
697dd285b06SPaolo Bonzini     case SSPSP:
698dd285b06SPaolo Bonzini         s->sspsp = value;
699dd285b06SPaolo Bonzini         break;
700dd285b06SPaolo Bonzini 
701dd285b06SPaolo Bonzini     case SSTO:
702dd285b06SPaolo Bonzini         s->ssto = value;
703dd285b06SPaolo Bonzini         break;
704dd285b06SPaolo Bonzini 
705dd285b06SPaolo Bonzini     case SSITR:
706dd285b06SPaolo Bonzini         s->ssitr = value & SSITR_INT;
707dd285b06SPaolo Bonzini         pxa2xx_ssp_int_update(s);
708dd285b06SPaolo Bonzini         break;
709dd285b06SPaolo Bonzini 
710dd285b06SPaolo Bonzini     case SSSR:
711dd285b06SPaolo Bonzini         s->sssr &= ~(value & SSSR_RW);
712dd285b06SPaolo Bonzini         pxa2xx_ssp_int_update(s);
713dd285b06SPaolo Bonzini         break;
714dd285b06SPaolo Bonzini 
715dd285b06SPaolo Bonzini     case SSDR:
716dd285b06SPaolo Bonzini         if (SSCR0_UWIRE(s->sscr[0])) {
717dd285b06SPaolo Bonzini             if (s->sscr[1] & SSCR1_MWDS)
718dd285b06SPaolo Bonzini                 value &= 0xffff;
719dd285b06SPaolo Bonzini             else
720dd285b06SPaolo Bonzini                 value &= 0xff;
721dd285b06SPaolo Bonzini         } else
722dd285b06SPaolo Bonzini             /* Note how 32bits overflow does no harm here */
723dd285b06SPaolo Bonzini             value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
724dd285b06SPaolo Bonzini 
725dd285b06SPaolo Bonzini         /* Data goes from here to the Tx FIFO and is shifted out from
726dd285b06SPaolo Bonzini          * there directly to the slave, no need to buffer it.
727dd285b06SPaolo Bonzini          */
728dd285b06SPaolo Bonzini         if (s->enable) {
729dd285b06SPaolo Bonzini             uint32_t readval;
730dd285b06SPaolo Bonzini             readval = ssi_transfer(s->bus, value);
731dd285b06SPaolo Bonzini             if (s->rx_level < 0x10) {
732dd285b06SPaolo Bonzini                 s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval;
733dd285b06SPaolo Bonzini             } else {
734dd285b06SPaolo Bonzini                 s->sssr |= SSSR_ROR;
735dd285b06SPaolo Bonzini             }
736dd285b06SPaolo Bonzini         }
737dd285b06SPaolo Bonzini         pxa2xx_ssp_fifo_update(s);
738dd285b06SPaolo Bonzini         break;
739dd285b06SPaolo Bonzini 
740dd285b06SPaolo Bonzini     case SSTSA:
741dd285b06SPaolo Bonzini         s->sstsa = value;
742dd285b06SPaolo Bonzini         break;
743dd285b06SPaolo Bonzini 
744dd285b06SPaolo Bonzini     case SSRSA:
745dd285b06SPaolo Bonzini         s->ssrsa = value;
746dd285b06SPaolo Bonzini         break;
747dd285b06SPaolo Bonzini 
748dd285b06SPaolo Bonzini     case SSACD:
749dd285b06SPaolo Bonzini         s->ssacd = value;
750dd285b06SPaolo Bonzini         break;
751dd285b06SPaolo Bonzini 
752dd285b06SPaolo Bonzini     default:
753fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
754fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
755fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
756dd285b06SPaolo Bonzini         break;
757dd285b06SPaolo Bonzini     }
758dd285b06SPaolo Bonzini }
759dd285b06SPaolo Bonzini 
760dd285b06SPaolo Bonzini static const MemoryRegionOps pxa2xx_ssp_ops = {
761dd285b06SPaolo Bonzini     .read = pxa2xx_ssp_read,
762dd285b06SPaolo Bonzini     .write = pxa2xx_ssp_write,
763dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
764dd285b06SPaolo Bonzini };
765dd285b06SPaolo Bonzini 
pxa2xx_ssp_reset(DeviceState * d)766ce320346SPeter Maydell static void pxa2xx_ssp_reset(DeviceState *d)
767ce320346SPeter Maydell {
768ce320346SPeter Maydell     PXA2xxSSPState *s = PXA2XX_SSP(d);
769ce320346SPeter Maydell 
770ce320346SPeter Maydell     s->enable = 0;
771ce320346SPeter Maydell     s->sscr[0] = s->sscr[1] = 0;
772ce320346SPeter Maydell     s->sspsp = 0;
773ce320346SPeter Maydell     s->ssto = 0;
774ce320346SPeter Maydell     s->ssitr = 0;
775ce320346SPeter Maydell     s->sssr = 0;
776ce320346SPeter Maydell     s->sstsa = 0;
777ce320346SPeter Maydell     s->ssrsa = 0;
778ce320346SPeter Maydell     s->ssacd = 0;
779ce320346SPeter Maydell     s->rx_start = s->rx_level = 0;
780ce320346SPeter Maydell }
781ce320346SPeter Maydell 
pxa2xx_ssp_init(Object * obj)7820493a139SSuramya Shah static void pxa2xx_ssp_init(Object *obj)
783dd285b06SPaolo Bonzini {
7840493a139SSuramya Shah     DeviceState *dev = DEVICE(obj);
7850493a139SSuramya Shah     PXA2xxSSPState *s = PXA2XX_SSP(obj);
7860493a139SSuramya Shah     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
78712a82804SAndreas Färber     sysbus_init_irq(sbd, &s->irq);
788dd285b06SPaolo Bonzini 
7890493a139SSuramya Shah     memory_region_init_io(&s->iomem, obj, &pxa2xx_ssp_ops, s,
79064bde0f3SPaolo Bonzini                           "pxa2xx-ssp", 0x1000);
79112a82804SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
792dd285b06SPaolo Bonzini 
79312a82804SAndreas Färber     s->bus = ssi_create_bus(dev, "ssi");
794dd285b06SPaolo Bonzini }
795dd285b06SPaolo Bonzini 
796dd285b06SPaolo Bonzini /* Real-Time Clock */
797dd285b06SPaolo Bonzini #define RCNR		0x00	/* RTC Counter register */
798dd285b06SPaolo Bonzini #define RTAR		0x04	/* RTC Alarm register */
799dd285b06SPaolo Bonzini #define RTSR		0x08	/* RTC Status register */
800dd285b06SPaolo Bonzini #define RTTR		0x0c	/* RTC Timer Trim register */
801dd285b06SPaolo Bonzini #define RDCR		0x10	/* RTC Day Counter register */
802dd285b06SPaolo Bonzini #define RYCR		0x14	/* RTC Year Counter register */
803dd285b06SPaolo Bonzini #define RDAR1		0x18	/* RTC Wristwatch Day Alarm register 1 */
804dd285b06SPaolo Bonzini #define RYAR1		0x1c	/* RTC Wristwatch Year Alarm register 1 */
805dd285b06SPaolo Bonzini #define RDAR2		0x20	/* RTC Wristwatch Day Alarm register 2 */
806dd285b06SPaolo Bonzini #define RYAR2		0x24	/* RTC Wristwatch Year Alarm register 2 */
807dd285b06SPaolo Bonzini #define SWCR		0x28	/* RTC Stopwatch Counter register */
808dd285b06SPaolo Bonzini #define SWAR1		0x2c	/* RTC Stopwatch Alarm register 1 */
809dd285b06SPaolo Bonzini #define SWAR2		0x30	/* RTC Stopwatch Alarm register 2 */
810dd285b06SPaolo Bonzini #define RTCPICR		0x34	/* RTC Periodic Interrupt Counter register */
811dd285b06SPaolo Bonzini #define PIAR		0x38	/* RTC Periodic Interrupt Alarm register */
812dd285b06SPaolo Bonzini 
813548c6f18SAndreas Färber #define TYPE_PXA2XX_RTC "pxa2xx_rtc"
8148063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxRTCState, PXA2XX_RTC)
815548c6f18SAndreas Färber 
816db1015e9SEduardo Habkost struct PXA2xxRTCState {
817548c6f18SAndreas Färber     /*< private >*/
818548c6f18SAndreas Färber     SysBusDevice parent_obj;
819548c6f18SAndreas Färber     /*< public >*/
820548c6f18SAndreas Färber 
821dd285b06SPaolo Bonzini     MemoryRegion iomem;
822dd285b06SPaolo Bonzini     uint32_t rttr;
823dd285b06SPaolo Bonzini     uint32_t rtsr;
824dd285b06SPaolo Bonzini     uint32_t rtar;
825dd285b06SPaolo Bonzini     uint32_t rdar1;
826dd285b06SPaolo Bonzini     uint32_t rdar2;
827dd285b06SPaolo Bonzini     uint32_t ryar1;
828dd285b06SPaolo Bonzini     uint32_t ryar2;
829dd285b06SPaolo Bonzini     uint32_t swar1;
830dd285b06SPaolo Bonzini     uint32_t swar2;
831dd285b06SPaolo Bonzini     uint32_t piar;
832dd285b06SPaolo Bonzini     uint32_t last_rcnr;
833dd285b06SPaolo Bonzini     uint32_t last_rdcr;
834dd285b06SPaolo Bonzini     uint32_t last_rycr;
835dd285b06SPaolo Bonzini     uint32_t last_swcr;
836dd285b06SPaolo Bonzini     uint32_t last_rtcpicr;
837dd285b06SPaolo Bonzini     int64_t last_hz;
838dd285b06SPaolo Bonzini     int64_t last_sw;
839dd285b06SPaolo Bonzini     int64_t last_pi;
840dd285b06SPaolo Bonzini     QEMUTimer *rtc_hz;
841dd285b06SPaolo Bonzini     QEMUTimer *rtc_rdal1;
842dd285b06SPaolo Bonzini     QEMUTimer *rtc_rdal2;
843dd285b06SPaolo Bonzini     QEMUTimer *rtc_swal1;
844dd285b06SPaolo Bonzini     QEMUTimer *rtc_swal2;
845dd285b06SPaolo Bonzini     QEMUTimer *rtc_pi;
846dd285b06SPaolo Bonzini     qemu_irq rtc_irq;
847db1015e9SEduardo Habkost };
848dd285b06SPaolo Bonzini 
pxa2xx_rtc_int_update(PXA2xxRTCState * s)849dd285b06SPaolo Bonzini static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s)
850dd285b06SPaolo Bonzini {
851dd285b06SPaolo Bonzini     qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553));
852dd285b06SPaolo Bonzini }
853dd285b06SPaolo Bonzini 
pxa2xx_rtc_hzupdate(PXA2xxRTCState * s)854dd285b06SPaolo Bonzini static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s)
855dd285b06SPaolo Bonzini {
856884f17c2SAlex Bligh     int64_t rt = qemu_clock_get_ms(rtc_clock);
857dd285b06SPaolo Bonzini     s->last_rcnr += ((rt - s->last_hz) << 15) /
858dd285b06SPaolo Bonzini             (1000 * ((s->rttr & 0xffff) + 1));
859dd285b06SPaolo Bonzini     s->last_rdcr += ((rt - s->last_hz) << 15) /
860dd285b06SPaolo Bonzini             (1000 * ((s->rttr & 0xffff) + 1));
861dd285b06SPaolo Bonzini     s->last_hz = rt;
862dd285b06SPaolo Bonzini }
863dd285b06SPaolo Bonzini 
pxa2xx_rtc_swupdate(PXA2xxRTCState * s)864dd285b06SPaolo Bonzini static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s)
865dd285b06SPaolo Bonzini {
866884f17c2SAlex Bligh     int64_t rt = qemu_clock_get_ms(rtc_clock);
867dd285b06SPaolo Bonzini     if (s->rtsr & (1 << 12))
868dd285b06SPaolo Bonzini         s->last_swcr += (rt - s->last_sw) / 10;
869dd285b06SPaolo Bonzini     s->last_sw = rt;
870dd285b06SPaolo Bonzini }
871dd285b06SPaolo Bonzini 
pxa2xx_rtc_piupdate(PXA2xxRTCState * s)872dd285b06SPaolo Bonzini static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s)
873dd285b06SPaolo Bonzini {
874884f17c2SAlex Bligh     int64_t rt = qemu_clock_get_ms(rtc_clock);
875dd285b06SPaolo Bonzini     if (s->rtsr & (1 << 15))
876dd285b06SPaolo Bonzini         s->last_swcr += rt - s->last_pi;
877dd285b06SPaolo Bonzini     s->last_pi = rt;
878dd285b06SPaolo Bonzini }
879dd285b06SPaolo Bonzini 
pxa2xx_rtc_alarm_update(PXA2xxRTCState * s,uint32_t rtsr)880dd285b06SPaolo Bonzini static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s,
881dd285b06SPaolo Bonzini                 uint32_t rtsr)
882dd285b06SPaolo Bonzini {
883dd285b06SPaolo Bonzini     if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
884bc72ad67SAlex Bligh         timer_mod(s->rtc_hz, s->last_hz +
885dd285b06SPaolo Bonzini                 (((s->rtar - s->last_rcnr) * 1000 *
886dd285b06SPaolo Bonzini                   ((s->rttr & 0xffff) + 1)) >> 15));
887dd285b06SPaolo Bonzini     else
888bc72ad67SAlex Bligh         timer_del(s->rtc_hz);
889dd285b06SPaolo Bonzini 
890dd285b06SPaolo Bonzini     if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
891bc72ad67SAlex Bligh         timer_mod(s->rtc_rdal1, s->last_hz +
892dd285b06SPaolo Bonzini                 (((s->rdar1 - s->last_rdcr) * 1000 *
893dd285b06SPaolo Bonzini                   ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
894dd285b06SPaolo Bonzini     else
895bc72ad67SAlex Bligh         timer_del(s->rtc_rdal1);
896dd285b06SPaolo Bonzini 
897dd285b06SPaolo Bonzini     if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
898bc72ad67SAlex Bligh         timer_mod(s->rtc_rdal2, s->last_hz +
899dd285b06SPaolo Bonzini                 (((s->rdar2 - s->last_rdcr) * 1000 *
900dd285b06SPaolo Bonzini                   ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
901dd285b06SPaolo Bonzini     else
902bc72ad67SAlex Bligh         timer_del(s->rtc_rdal2);
903dd285b06SPaolo Bonzini 
904dd285b06SPaolo Bonzini     if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
905bc72ad67SAlex Bligh         timer_mod(s->rtc_swal1, s->last_sw +
906dd285b06SPaolo Bonzini                         (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
907dd285b06SPaolo Bonzini     else
908bc72ad67SAlex Bligh         timer_del(s->rtc_swal1);
909dd285b06SPaolo Bonzini 
910dd285b06SPaolo Bonzini     if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
911bc72ad67SAlex Bligh         timer_mod(s->rtc_swal2, s->last_sw +
912dd285b06SPaolo Bonzini                         (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
913dd285b06SPaolo Bonzini     else
914bc72ad67SAlex Bligh         timer_del(s->rtc_swal2);
915dd285b06SPaolo Bonzini 
916dd285b06SPaolo Bonzini     if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
917bc72ad67SAlex Bligh         timer_mod(s->rtc_pi, s->last_pi +
918dd285b06SPaolo Bonzini                         (s->piar & 0xffff) - s->last_rtcpicr);
919dd285b06SPaolo Bonzini     else
920bc72ad67SAlex Bligh         timer_del(s->rtc_pi);
921dd285b06SPaolo Bonzini }
922dd285b06SPaolo Bonzini 
pxa2xx_rtc_hz_tick(void * opaque)923dd285b06SPaolo Bonzini static inline void pxa2xx_rtc_hz_tick(void *opaque)
924dd285b06SPaolo Bonzini {
925dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
926dd285b06SPaolo Bonzini     s->rtsr |= (1 << 0);
927dd285b06SPaolo Bonzini     pxa2xx_rtc_alarm_update(s, s->rtsr);
928dd285b06SPaolo Bonzini     pxa2xx_rtc_int_update(s);
929dd285b06SPaolo Bonzini }
930dd285b06SPaolo Bonzini 
pxa2xx_rtc_rdal1_tick(void * opaque)931dd285b06SPaolo Bonzini static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
932dd285b06SPaolo Bonzini {
933dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
934dd285b06SPaolo Bonzini     s->rtsr |= (1 << 4);
935dd285b06SPaolo Bonzini     pxa2xx_rtc_alarm_update(s, s->rtsr);
936dd285b06SPaolo Bonzini     pxa2xx_rtc_int_update(s);
937dd285b06SPaolo Bonzini }
938dd285b06SPaolo Bonzini 
pxa2xx_rtc_rdal2_tick(void * opaque)939dd285b06SPaolo Bonzini static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
940dd285b06SPaolo Bonzini {
941dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
942dd285b06SPaolo Bonzini     s->rtsr |= (1 << 6);
943dd285b06SPaolo Bonzini     pxa2xx_rtc_alarm_update(s, s->rtsr);
944dd285b06SPaolo Bonzini     pxa2xx_rtc_int_update(s);
945dd285b06SPaolo Bonzini }
946dd285b06SPaolo Bonzini 
pxa2xx_rtc_swal1_tick(void * opaque)947dd285b06SPaolo Bonzini static inline void pxa2xx_rtc_swal1_tick(void *opaque)
948dd285b06SPaolo Bonzini {
949dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
950dd285b06SPaolo Bonzini     s->rtsr |= (1 << 8);
951dd285b06SPaolo Bonzini     pxa2xx_rtc_alarm_update(s, s->rtsr);
952dd285b06SPaolo Bonzini     pxa2xx_rtc_int_update(s);
953dd285b06SPaolo Bonzini }
954dd285b06SPaolo Bonzini 
pxa2xx_rtc_swal2_tick(void * opaque)955dd285b06SPaolo Bonzini static inline void pxa2xx_rtc_swal2_tick(void *opaque)
956dd285b06SPaolo Bonzini {
957dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
958dd285b06SPaolo Bonzini     s->rtsr |= (1 << 10);
959dd285b06SPaolo Bonzini     pxa2xx_rtc_alarm_update(s, s->rtsr);
960dd285b06SPaolo Bonzini     pxa2xx_rtc_int_update(s);
961dd285b06SPaolo Bonzini }
962dd285b06SPaolo Bonzini 
pxa2xx_rtc_pi_tick(void * opaque)963dd285b06SPaolo Bonzini static inline void pxa2xx_rtc_pi_tick(void *opaque)
964dd285b06SPaolo Bonzini {
965dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
966dd285b06SPaolo Bonzini     s->rtsr |= (1 << 13);
967dd285b06SPaolo Bonzini     pxa2xx_rtc_piupdate(s);
968dd285b06SPaolo Bonzini     s->last_rtcpicr = 0;
969dd285b06SPaolo Bonzini     pxa2xx_rtc_alarm_update(s, s->rtsr);
970dd285b06SPaolo Bonzini     pxa2xx_rtc_int_update(s);
971dd285b06SPaolo Bonzini }
972dd285b06SPaolo Bonzini 
pxa2xx_rtc_read(void * opaque,hwaddr addr,unsigned size)973dd285b06SPaolo Bonzini static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr,
974dd285b06SPaolo Bonzini                                 unsigned size)
975dd285b06SPaolo Bonzini {
976dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
977dd285b06SPaolo Bonzini 
978dd285b06SPaolo Bonzini     switch (addr) {
979dd285b06SPaolo Bonzini     case RTTR:
980dd285b06SPaolo Bonzini         return s->rttr;
981dd285b06SPaolo Bonzini     case RTSR:
982dd285b06SPaolo Bonzini         return s->rtsr;
983dd285b06SPaolo Bonzini     case RTAR:
984dd285b06SPaolo Bonzini         return s->rtar;
985dd285b06SPaolo Bonzini     case RDAR1:
986dd285b06SPaolo Bonzini         return s->rdar1;
987dd285b06SPaolo Bonzini     case RDAR2:
988dd285b06SPaolo Bonzini         return s->rdar2;
989dd285b06SPaolo Bonzini     case RYAR1:
990dd285b06SPaolo Bonzini         return s->ryar1;
991dd285b06SPaolo Bonzini     case RYAR2:
992dd285b06SPaolo Bonzini         return s->ryar2;
993dd285b06SPaolo Bonzini     case SWAR1:
994dd285b06SPaolo Bonzini         return s->swar1;
995dd285b06SPaolo Bonzini     case SWAR2:
996dd285b06SPaolo Bonzini         return s->swar2;
997dd285b06SPaolo Bonzini     case PIAR:
998dd285b06SPaolo Bonzini         return s->piar;
999dd285b06SPaolo Bonzini     case RCNR:
1000884f17c2SAlex Bligh         return s->last_rcnr +
1001884f17c2SAlex Bligh             ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
1002dd285b06SPaolo Bonzini             (1000 * ((s->rttr & 0xffff) + 1));
1003dd285b06SPaolo Bonzini     case RDCR:
1004884f17c2SAlex Bligh         return s->last_rdcr +
1005884f17c2SAlex Bligh             ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
1006dd285b06SPaolo Bonzini             (1000 * ((s->rttr & 0xffff) + 1));
1007dd285b06SPaolo Bonzini     case RYCR:
1008dd285b06SPaolo Bonzini         return s->last_rycr;
1009dd285b06SPaolo Bonzini     case SWCR:
1010dd285b06SPaolo Bonzini         if (s->rtsr & (1 << 12))
1011884f17c2SAlex Bligh             return s->last_swcr +
1012884f17c2SAlex Bligh                 (qemu_clock_get_ms(rtc_clock) - s->last_sw) / 10;
1013dd285b06SPaolo Bonzini         else
1014dd285b06SPaolo Bonzini             return s->last_swcr;
1015dd285b06SPaolo Bonzini     default:
1016fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
1017fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
1018fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
1019dd285b06SPaolo Bonzini         break;
1020dd285b06SPaolo Bonzini     }
1021dd285b06SPaolo Bonzini     return 0;
1022dd285b06SPaolo Bonzini }
1023dd285b06SPaolo Bonzini 
pxa2xx_rtc_write(void * opaque,hwaddr addr,uint64_t value64,unsigned size)1024dd285b06SPaolo Bonzini static void pxa2xx_rtc_write(void *opaque, hwaddr addr,
1025dd285b06SPaolo Bonzini                              uint64_t value64, unsigned size)
1026dd285b06SPaolo Bonzini {
1027dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
1028dd285b06SPaolo Bonzini     uint32_t value = value64;
1029dd285b06SPaolo Bonzini 
1030dd285b06SPaolo Bonzini     switch (addr) {
1031dd285b06SPaolo Bonzini     case RTTR:
103243a32ed6SPeter Maydell         if (!(s->rttr & (1U << 31))) {
1033dd285b06SPaolo Bonzini             pxa2xx_rtc_hzupdate(s);
1034dd285b06SPaolo Bonzini             s->rttr = value;
1035dd285b06SPaolo Bonzini             pxa2xx_rtc_alarm_update(s, s->rtsr);
1036dd285b06SPaolo Bonzini         }
1037dd285b06SPaolo Bonzini         break;
1038dd285b06SPaolo Bonzini 
1039dd285b06SPaolo Bonzini     case RTSR:
1040dd285b06SPaolo Bonzini         if ((s->rtsr ^ value) & (1 << 15))
1041dd285b06SPaolo Bonzini             pxa2xx_rtc_piupdate(s);
1042dd285b06SPaolo Bonzini 
1043dd285b06SPaolo Bonzini         if ((s->rtsr ^ value) & (1 << 12))
1044dd285b06SPaolo Bonzini             pxa2xx_rtc_swupdate(s);
1045dd285b06SPaolo Bonzini 
1046dd285b06SPaolo Bonzini         if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
1047dd285b06SPaolo Bonzini             pxa2xx_rtc_alarm_update(s, value);
1048dd285b06SPaolo Bonzini 
1049dd285b06SPaolo Bonzini         s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
1050dd285b06SPaolo Bonzini         pxa2xx_rtc_int_update(s);
1051dd285b06SPaolo Bonzini         break;
1052dd285b06SPaolo Bonzini 
1053dd285b06SPaolo Bonzini     case RTAR:
1054dd285b06SPaolo Bonzini         s->rtar = value;
1055dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1056dd285b06SPaolo Bonzini         break;
1057dd285b06SPaolo Bonzini 
1058dd285b06SPaolo Bonzini     case RDAR1:
1059dd285b06SPaolo Bonzini         s->rdar1 = value;
1060dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1061dd285b06SPaolo Bonzini         break;
1062dd285b06SPaolo Bonzini 
1063dd285b06SPaolo Bonzini     case RDAR2:
1064dd285b06SPaolo Bonzini         s->rdar2 = value;
1065dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1066dd285b06SPaolo Bonzini         break;
1067dd285b06SPaolo Bonzini 
1068dd285b06SPaolo Bonzini     case RYAR1:
1069dd285b06SPaolo Bonzini         s->ryar1 = value;
1070dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1071dd285b06SPaolo Bonzini         break;
1072dd285b06SPaolo Bonzini 
1073dd285b06SPaolo Bonzini     case RYAR2:
1074dd285b06SPaolo Bonzini         s->ryar2 = value;
1075dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1076dd285b06SPaolo Bonzini         break;
1077dd285b06SPaolo Bonzini 
1078dd285b06SPaolo Bonzini     case SWAR1:
1079dd285b06SPaolo Bonzini         pxa2xx_rtc_swupdate(s);
1080dd285b06SPaolo Bonzini         s->swar1 = value;
1081dd285b06SPaolo Bonzini         s->last_swcr = 0;
1082dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1083dd285b06SPaolo Bonzini         break;
1084dd285b06SPaolo Bonzini 
1085dd285b06SPaolo Bonzini     case SWAR2:
1086dd285b06SPaolo Bonzini         s->swar2 = value;
1087dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1088dd285b06SPaolo Bonzini         break;
1089dd285b06SPaolo Bonzini 
1090dd285b06SPaolo Bonzini     case PIAR:
1091dd285b06SPaolo Bonzini         s->piar = value;
1092dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1093dd285b06SPaolo Bonzini         break;
1094dd285b06SPaolo Bonzini 
1095dd285b06SPaolo Bonzini     case RCNR:
1096dd285b06SPaolo Bonzini         pxa2xx_rtc_hzupdate(s);
1097dd285b06SPaolo Bonzini         s->last_rcnr = value;
1098dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1099dd285b06SPaolo Bonzini         break;
1100dd285b06SPaolo Bonzini 
1101dd285b06SPaolo Bonzini     case RDCR:
1102dd285b06SPaolo Bonzini         pxa2xx_rtc_hzupdate(s);
1103dd285b06SPaolo Bonzini         s->last_rdcr = value;
1104dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1105dd285b06SPaolo Bonzini         break;
1106dd285b06SPaolo Bonzini 
1107dd285b06SPaolo Bonzini     case RYCR:
1108dd285b06SPaolo Bonzini         s->last_rycr = value;
1109dd285b06SPaolo Bonzini         break;
1110dd285b06SPaolo Bonzini 
1111dd285b06SPaolo Bonzini     case SWCR:
1112dd285b06SPaolo Bonzini         pxa2xx_rtc_swupdate(s);
1113dd285b06SPaolo Bonzini         s->last_swcr = value;
1114dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1115dd285b06SPaolo Bonzini         break;
1116dd285b06SPaolo Bonzini 
1117dd285b06SPaolo Bonzini     case RTCPICR:
1118dd285b06SPaolo Bonzini         pxa2xx_rtc_piupdate(s);
1119dd285b06SPaolo Bonzini         s->last_rtcpicr = value & 0xffff;
1120dd285b06SPaolo Bonzini         pxa2xx_rtc_alarm_update(s, s->rtsr);
1121dd285b06SPaolo Bonzini         break;
1122dd285b06SPaolo Bonzini 
1123dd285b06SPaolo Bonzini     default:
1124fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
1125fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
1126fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
1127dd285b06SPaolo Bonzini     }
1128dd285b06SPaolo Bonzini }
1129dd285b06SPaolo Bonzini 
1130dd285b06SPaolo Bonzini static const MemoryRegionOps pxa2xx_rtc_ops = {
1131dd285b06SPaolo Bonzini     .read = pxa2xx_rtc_read,
1132dd285b06SPaolo Bonzini     .write = pxa2xx_rtc_write,
1133dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1134dd285b06SPaolo Bonzini };
1135dd285b06SPaolo Bonzini 
pxa2xx_rtc_init(Object * obj)113616fb31a3Sxiaoqiang.zhao static void pxa2xx_rtc_init(Object *obj)
1137dd285b06SPaolo Bonzini {
113816fb31a3Sxiaoqiang.zhao     PXA2xxRTCState *s = PXA2XX_RTC(obj);
113916fb31a3Sxiaoqiang.zhao     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
1140dd285b06SPaolo Bonzini     struct tm tm;
1141dd285b06SPaolo Bonzini     int wom;
1142dd285b06SPaolo Bonzini 
1143dd285b06SPaolo Bonzini     s->rttr = 0x7fff;
1144dd285b06SPaolo Bonzini     s->rtsr = 0;
1145dd285b06SPaolo Bonzini 
1146dd285b06SPaolo Bonzini     qemu_get_timedate(&tm, 0);
1147dd285b06SPaolo Bonzini     wom = ((tm.tm_mday - 1) / 7) + 1;
1148dd285b06SPaolo Bonzini 
1149dd285b06SPaolo Bonzini     s->last_rcnr = (uint32_t) mktimegm(&tm);
1150dd285b06SPaolo Bonzini     s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) |
1151dd285b06SPaolo Bonzini             (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec;
1152dd285b06SPaolo Bonzini     s->last_rycr = ((tm.tm_year + 1900) << 9) |
1153dd285b06SPaolo Bonzini             ((tm.tm_mon + 1) << 5) | tm.tm_mday;
1154dd285b06SPaolo Bonzini     s->last_swcr = (tm.tm_hour << 19) |
1155dd285b06SPaolo Bonzini             (tm.tm_min << 13) | (tm.tm_sec << 7);
1156dd285b06SPaolo Bonzini     s->last_rtcpicr = 0;
1157884f17c2SAlex Bligh     s->last_hz = s->last_sw = s->last_pi = qemu_clock_get_ms(rtc_clock);
1158dd285b06SPaolo Bonzini 
11591afaadb5SPan Nengyuan     sysbus_init_irq(dev, &s->rtc_irq);
11601afaadb5SPan Nengyuan 
11611afaadb5SPan Nengyuan     memory_region_init_io(&s->iomem, obj, &pxa2xx_rtc_ops, s,
11621afaadb5SPan Nengyuan                           "pxa2xx-rtc", 0x10000);
11631afaadb5SPan Nengyuan     sysbus_init_mmio(dev, &s->iomem);
11641afaadb5SPan Nengyuan }
11651afaadb5SPan Nengyuan 
pxa2xx_rtc_realize(DeviceState * dev,Error ** errp)11661afaadb5SPan Nengyuan static void pxa2xx_rtc_realize(DeviceState *dev, Error **errp)
11671afaadb5SPan Nengyuan {
11681afaadb5SPan Nengyuan     PXA2xxRTCState *s = PXA2XX_RTC(dev);
1169884f17c2SAlex Bligh     s->rtc_hz    = timer_new_ms(rtc_clock, pxa2xx_rtc_hz_tick,    s);
1170884f17c2SAlex Bligh     s->rtc_rdal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s);
1171884f17c2SAlex Bligh     s->rtc_rdal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s);
1172884f17c2SAlex Bligh     s->rtc_swal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s);
1173884f17c2SAlex Bligh     s->rtc_swal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s);
1174884f17c2SAlex Bligh     s->rtc_pi    = timer_new_ms(rtc_clock, pxa2xx_rtc_pi_tick,    s);
1175dd285b06SPaolo Bonzini }
1176dd285b06SPaolo Bonzini 
pxa2xx_rtc_pre_save(void * opaque)117744b1ff31SDr. David Alan Gilbert static int pxa2xx_rtc_pre_save(void *opaque)
1178dd285b06SPaolo Bonzini {
1179dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
1180dd285b06SPaolo Bonzini 
1181dd285b06SPaolo Bonzini     pxa2xx_rtc_hzupdate(s);
1182dd285b06SPaolo Bonzini     pxa2xx_rtc_piupdate(s);
1183dd285b06SPaolo Bonzini     pxa2xx_rtc_swupdate(s);
118444b1ff31SDr. David Alan Gilbert 
118544b1ff31SDr. David Alan Gilbert     return 0;
1186dd285b06SPaolo Bonzini }
1187dd285b06SPaolo Bonzini 
pxa2xx_rtc_post_load(void * opaque,int version_id)1188dd285b06SPaolo Bonzini static int pxa2xx_rtc_post_load(void *opaque, int version_id)
1189dd285b06SPaolo Bonzini {
1190dd285b06SPaolo Bonzini     PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
1191dd285b06SPaolo Bonzini 
1192dd285b06SPaolo Bonzini     pxa2xx_rtc_alarm_update(s, s->rtsr);
1193dd285b06SPaolo Bonzini 
1194dd285b06SPaolo Bonzini     return 0;
1195dd285b06SPaolo Bonzini }
1196dd285b06SPaolo Bonzini 
1197dd285b06SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
1198dd285b06SPaolo Bonzini     .name = "pxa2xx_rtc",
1199dd285b06SPaolo Bonzini     .version_id = 0,
1200dd285b06SPaolo Bonzini     .minimum_version_id = 0,
1201dd285b06SPaolo Bonzini     .pre_save = pxa2xx_rtc_pre_save,
1202dd285b06SPaolo Bonzini     .post_load = pxa2xx_rtc_post_load,
1203*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
1204dd285b06SPaolo Bonzini         VMSTATE_UINT32(rttr, PXA2xxRTCState),
1205dd285b06SPaolo Bonzini         VMSTATE_UINT32(rtsr, PXA2xxRTCState),
1206dd285b06SPaolo Bonzini         VMSTATE_UINT32(rtar, PXA2xxRTCState),
1207dd285b06SPaolo Bonzini         VMSTATE_UINT32(rdar1, PXA2xxRTCState),
1208dd285b06SPaolo Bonzini         VMSTATE_UINT32(rdar2, PXA2xxRTCState),
1209dd285b06SPaolo Bonzini         VMSTATE_UINT32(ryar1, PXA2xxRTCState),
1210dd285b06SPaolo Bonzini         VMSTATE_UINT32(ryar2, PXA2xxRTCState),
1211dd285b06SPaolo Bonzini         VMSTATE_UINT32(swar1, PXA2xxRTCState),
1212dd285b06SPaolo Bonzini         VMSTATE_UINT32(swar2, PXA2xxRTCState),
1213dd285b06SPaolo Bonzini         VMSTATE_UINT32(piar, PXA2xxRTCState),
1214dd285b06SPaolo Bonzini         VMSTATE_UINT32(last_rcnr, PXA2xxRTCState),
1215dd285b06SPaolo Bonzini         VMSTATE_UINT32(last_rdcr, PXA2xxRTCState),
1216dd285b06SPaolo Bonzini         VMSTATE_UINT32(last_rycr, PXA2xxRTCState),
1217dd285b06SPaolo Bonzini         VMSTATE_UINT32(last_swcr, PXA2xxRTCState),
1218dd285b06SPaolo Bonzini         VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState),
1219dd285b06SPaolo Bonzini         VMSTATE_INT64(last_hz, PXA2xxRTCState),
1220dd285b06SPaolo Bonzini         VMSTATE_INT64(last_sw, PXA2xxRTCState),
1221dd285b06SPaolo Bonzini         VMSTATE_INT64(last_pi, PXA2xxRTCState),
1222dd285b06SPaolo Bonzini         VMSTATE_END_OF_LIST(),
1223dd285b06SPaolo Bonzini     },
1224dd285b06SPaolo Bonzini };
1225dd285b06SPaolo Bonzini 
pxa2xx_rtc_sysbus_class_init(ObjectClass * klass,void * data)1226dd285b06SPaolo Bonzini static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data)
1227dd285b06SPaolo Bonzini {
1228dd285b06SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
1229dd285b06SPaolo Bonzini 
1230dd285b06SPaolo Bonzini     dc->desc = "PXA2xx RTC Controller";
1231dd285b06SPaolo Bonzini     dc->vmsd = &vmstate_pxa2xx_rtc_regs;
12321afaadb5SPan Nengyuan     dc->realize = pxa2xx_rtc_realize;
1233dd285b06SPaolo Bonzini }
1234dd285b06SPaolo Bonzini 
1235dd285b06SPaolo Bonzini static const TypeInfo pxa2xx_rtc_sysbus_info = {
1236548c6f18SAndreas Färber     .name          = TYPE_PXA2XX_RTC,
1237dd285b06SPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
1238dd285b06SPaolo Bonzini     .instance_size = sizeof(PXA2xxRTCState),
123916fb31a3Sxiaoqiang.zhao     .instance_init = pxa2xx_rtc_init,
1240dd285b06SPaolo Bonzini     .class_init    = pxa2xx_rtc_sysbus_class_init,
1241dd285b06SPaolo Bonzini };
1242dd285b06SPaolo Bonzini 
1243dd285b06SPaolo Bonzini /* I2C Interface */
124496dca6b9SAndreas Färber 
124596dca6b9SAndreas Färber #define TYPE_PXA2XX_I2C_SLAVE "pxa2xx-i2c-slave"
12468063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxI2CSlaveState, PXA2XX_I2C_SLAVE)
124796dca6b9SAndreas Färber 
1248db1015e9SEduardo Habkost struct PXA2xxI2CSlaveState {
124996dca6b9SAndreas Färber     I2CSlave parent_obj;
125096dca6b9SAndreas Färber 
1251dd285b06SPaolo Bonzini     PXA2xxI2CState *host;
1252db1015e9SEduardo Habkost };
1253dd285b06SPaolo Bonzini 
1254dd285b06SPaolo Bonzini struct PXA2xxI2CState {
12555354c21eSAndreas Färber     /*< private >*/
12565354c21eSAndreas Färber     SysBusDevice parent_obj;
12575354c21eSAndreas Färber     /*< public >*/
12585354c21eSAndreas Färber 
1259dd285b06SPaolo Bonzini     MemoryRegion iomem;
1260dd285b06SPaolo Bonzini     PXA2xxI2CSlaveState *slave;
1261a5c82852SAndreas Färber     I2CBus *bus;
1262dd285b06SPaolo Bonzini     qemu_irq irq;
1263dd285b06SPaolo Bonzini     uint32_t offset;
1264dd285b06SPaolo Bonzini     uint32_t region_size;
1265dd285b06SPaolo Bonzini 
1266dd285b06SPaolo Bonzini     uint16_t control;
1267dd285b06SPaolo Bonzini     uint16_t status;
1268dd285b06SPaolo Bonzini     uint8_t ibmr;
1269dd285b06SPaolo Bonzini     uint8_t data;
1270dd285b06SPaolo Bonzini };
1271dd285b06SPaolo Bonzini 
1272dd285b06SPaolo Bonzini #define IBMR	0x80	/* I2C Bus Monitor register */
1273dd285b06SPaolo Bonzini #define IDBR	0x88	/* I2C Data Buffer register */
1274dd285b06SPaolo Bonzini #define ICR	0x90	/* I2C Control register */
1275dd285b06SPaolo Bonzini #define ISR	0x98	/* I2C Status register */
1276dd285b06SPaolo Bonzini #define ISAR	0xa0	/* I2C Slave Address register */
1277dd285b06SPaolo Bonzini 
pxa2xx_i2c_update(PXA2xxI2CState * s)1278dd285b06SPaolo Bonzini static void pxa2xx_i2c_update(PXA2xxI2CState *s)
1279dd285b06SPaolo Bonzini {
1280dd285b06SPaolo Bonzini     uint16_t level = 0;
1281dd285b06SPaolo Bonzini     level |= s->status & s->control & (1 << 10);		/* BED */
1282dd285b06SPaolo Bonzini     level |= (s->status & (1 << 7)) && (s->control & (1 << 9));	/* IRF */
1283dd285b06SPaolo Bonzini     level |= (s->status & (1 << 6)) && (s->control & (1 << 8));	/* ITE */
1284dd285b06SPaolo Bonzini     level |= s->status & (1 << 9);				/* SAD */
1285dd285b06SPaolo Bonzini     qemu_set_irq(s->irq, !!level);
1286dd285b06SPaolo Bonzini }
1287dd285b06SPaolo Bonzini 
1288dd285b06SPaolo Bonzini /* These are only stubs now.  */
pxa2xx_i2c_event(I2CSlave * i2c,enum i2c_event event)1289d307c28cSCorey Minyard static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
1290dd285b06SPaolo Bonzini {
129196dca6b9SAndreas Färber     PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
1292dd285b06SPaolo Bonzini     PXA2xxI2CState *s = slave->host;
1293dd285b06SPaolo Bonzini 
1294dd285b06SPaolo Bonzini     switch (event) {
1295dd285b06SPaolo Bonzini     case I2C_START_SEND:
1296dd285b06SPaolo Bonzini         s->status |= (1 << 9);				/* set SAD */
1297dd285b06SPaolo Bonzini         s->status &= ~(1 << 0);				/* clear RWM */
1298dd285b06SPaolo Bonzini         break;
1299dd285b06SPaolo Bonzini     case I2C_START_RECV:
1300dd285b06SPaolo Bonzini         s->status |= (1 << 9);				/* set SAD */
1301dd285b06SPaolo Bonzini         s->status |= 1 << 0;				/* set RWM */
1302dd285b06SPaolo Bonzini         break;
1303dd285b06SPaolo Bonzini     case I2C_FINISH:
1304dd285b06SPaolo Bonzini         s->status |= (1 << 4);				/* set SSD */
1305dd285b06SPaolo Bonzini         break;
1306dd285b06SPaolo Bonzini     case I2C_NACK:
1307dd285b06SPaolo Bonzini         s->status |= 1 << 1;				/* set ACKNAK */
1308dd285b06SPaolo Bonzini         break;
1309a78e9839SKlaus Jensen     default:
1310a78e9839SKlaus Jensen         return -1;
1311dd285b06SPaolo Bonzini     }
1312dd285b06SPaolo Bonzini     pxa2xx_i2c_update(s);
1313d307c28cSCorey Minyard 
1314d307c28cSCorey Minyard     return 0;
1315dd285b06SPaolo Bonzini }
1316dd285b06SPaolo Bonzini 
pxa2xx_i2c_rx(I2CSlave * i2c)13172ac4c5f4SCorey Minyard static uint8_t pxa2xx_i2c_rx(I2CSlave *i2c)
1318dd285b06SPaolo Bonzini {
131996dca6b9SAndreas Färber     PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
1320dd285b06SPaolo Bonzini     PXA2xxI2CState *s = slave->host;
132196dca6b9SAndreas Färber 
132296dca6b9SAndreas Färber     if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
1323dd285b06SPaolo Bonzini         return 0;
132496dca6b9SAndreas Färber     }
1325dd285b06SPaolo Bonzini 
1326dd285b06SPaolo Bonzini     if (s->status & (1 << 0)) {			/* RWM */
1327dd285b06SPaolo Bonzini         s->status |= 1 << 6;			/* set ITE */
1328dd285b06SPaolo Bonzini     }
1329dd285b06SPaolo Bonzini     pxa2xx_i2c_update(s);
1330dd285b06SPaolo Bonzini 
1331dd285b06SPaolo Bonzini     return s->data;
1332dd285b06SPaolo Bonzini }
1333dd285b06SPaolo Bonzini 
pxa2xx_i2c_tx(I2CSlave * i2c,uint8_t data)1334dd285b06SPaolo Bonzini static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
1335dd285b06SPaolo Bonzini {
133696dca6b9SAndreas Färber     PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
1337dd285b06SPaolo Bonzini     PXA2xxI2CState *s = slave->host;
133896dca6b9SAndreas Färber 
133996dca6b9SAndreas Färber     if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
1340dd285b06SPaolo Bonzini         return 1;
134196dca6b9SAndreas Färber     }
1342dd285b06SPaolo Bonzini 
1343dd285b06SPaolo Bonzini     if (!(s->status & (1 << 0))) {		/* RWM */
1344dd285b06SPaolo Bonzini         s->status |= 1 << 7;			/* set IRF */
1345dd285b06SPaolo Bonzini         s->data = data;
1346dd285b06SPaolo Bonzini     }
1347dd285b06SPaolo Bonzini     pxa2xx_i2c_update(s);
1348dd285b06SPaolo Bonzini 
1349dd285b06SPaolo Bonzini     return 1;
1350dd285b06SPaolo Bonzini }
1351dd285b06SPaolo Bonzini 
pxa2xx_i2c_read(void * opaque,hwaddr addr,unsigned size)1352dd285b06SPaolo Bonzini static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr,
1353dd285b06SPaolo Bonzini                                 unsigned size)
1354dd285b06SPaolo Bonzini {
1355dd285b06SPaolo Bonzini     PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
135696dca6b9SAndreas Färber     I2CSlave *slave;
1357dd285b06SPaolo Bonzini 
1358dd285b06SPaolo Bonzini     addr -= s->offset;
1359dd285b06SPaolo Bonzini     switch (addr) {
1360dd285b06SPaolo Bonzini     case ICR:
1361dd285b06SPaolo Bonzini         return s->control;
1362dd285b06SPaolo Bonzini     case ISR:
1363dd285b06SPaolo Bonzini         return s->status | (i2c_bus_busy(s->bus) << 2);
1364dd285b06SPaolo Bonzini     case ISAR:
136596dca6b9SAndreas Färber         slave = I2C_SLAVE(s->slave);
136696dca6b9SAndreas Färber         return slave->address;
1367dd285b06SPaolo Bonzini     case IDBR:
1368dd285b06SPaolo Bonzini         return s->data;
1369dd285b06SPaolo Bonzini     case IBMR:
1370dd285b06SPaolo Bonzini         if (s->status & (1 << 2))
1371dd285b06SPaolo Bonzini             s->ibmr ^= 3;	/* Fake SCL and SDA pin changes */
1372dd285b06SPaolo Bonzini         else
1373dd285b06SPaolo Bonzini             s->ibmr = 0;
1374dd285b06SPaolo Bonzini         return s->ibmr;
1375dd285b06SPaolo Bonzini     default:
1376fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
1377fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
1378fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
1379dd285b06SPaolo Bonzini         break;
1380dd285b06SPaolo Bonzini     }
1381dd285b06SPaolo Bonzini     return 0;
1382dd285b06SPaolo Bonzini }
1383dd285b06SPaolo Bonzini 
pxa2xx_i2c_write(void * opaque,hwaddr addr,uint64_t value64,unsigned size)1384dd285b06SPaolo Bonzini static void pxa2xx_i2c_write(void *opaque, hwaddr addr,
1385dd285b06SPaolo Bonzini                              uint64_t value64, unsigned size)
1386dd285b06SPaolo Bonzini {
1387dd285b06SPaolo Bonzini     PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
1388dd285b06SPaolo Bonzini     uint32_t value = value64;
1389dd285b06SPaolo Bonzini     int ack;
1390dd285b06SPaolo Bonzini 
1391dd285b06SPaolo Bonzini     addr -= s->offset;
1392dd285b06SPaolo Bonzini     switch (addr) {
1393dd285b06SPaolo Bonzini     case ICR:
1394dd285b06SPaolo Bonzini         s->control = value & 0xfff7;
1395dd285b06SPaolo Bonzini         if ((value & (1 << 3)) && (value & (1 << 6))) {	/* TB and IUE */
1396dd285b06SPaolo Bonzini             /* TODO: slave mode */
1397dd285b06SPaolo Bonzini             if (value & (1 << 0)) {			/* START condition */
1398dd285b06SPaolo Bonzini                 if (s->data & 1)
1399dd285b06SPaolo Bonzini                     s->status |= 1 << 0;		/* set RWM */
1400dd285b06SPaolo Bonzini                 else
1401dd285b06SPaolo Bonzini                     s->status &= ~(1 << 0);		/* clear RWM */
1402dd285b06SPaolo Bonzini                 ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1);
1403dd285b06SPaolo Bonzini             } else {
1404dd285b06SPaolo Bonzini                 if (s->status & (1 << 0)) {		/* RWM */
1405dd285b06SPaolo Bonzini                     s->data = i2c_recv(s->bus);
1406dd285b06SPaolo Bonzini                     if (value & (1 << 2))		/* ACKNAK */
1407dd285b06SPaolo Bonzini                         i2c_nack(s->bus);
1408dd285b06SPaolo Bonzini                     ack = 1;
1409dd285b06SPaolo Bonzini                 } else
1410dd285b06SPaolo Bonzini                     ack = !i2c_send(s->bus, s->data);
1411dd285b06SPaolo Bonzini             }
1412dd285b06SPaolo Bonzini 
1413dd285b06SPaolo Bonzini             if (value & (1 << 1))			/* STOP condition */
1414dd285b06SPaolo Bonzini                 i2c_end_transfer(s->bus);
1415dd285b06SPaolo Bonzini 
1416dd285b06SPaolo Bonzini             if (ack) {
1417dd285b06SPaolo Bonzini                 if (value & (1 << 0))			/* START condition */
1418dd285b06SPaolo Bonzini                     s->status |= 1 << 6;		/* set ITE */
1419dd285b06SPaolo Bonzini                 else
1420dd285b06SPaolo Bonzini                     if (s->status & (1 << 0))		/* RWM */
1421dd285b06SPaolo Bonzini                         s->status |= 1 << 7;		/* set IRF */
1422dd285b06SPaolo Bonzini                     else
1423dd285b06SPaolo Bonzini                         s->status |= 1 << 6;		/* set ITE */
1424dd285b06SPaolo Bonzini                 s->status &= ~(1 << 1);			/* clear ACKNAK */
1425dd285b06SPaolo Bonzini             } else {
1426dd285b06SPaolo Bonzini                 s->status |= 1 << 6;			/* set ITE */
1427dd285b06SPaolo Bonzini                 s->status |= 1 << 10;			/* set BED */
1428dd285b06SPaolo Bonzini                 s->status |= 1 << 1;			/* set ACKNAK */
1429dd285b06SPaolo Bonzini             }
1430dd285b06SPaolo Bonzini         }
1431dd285b06SPaolo Bonzini         if (!(value & (1 << 3)) && (value & (1 << 6)))	/* !TB and IUE */
1432dd285b06SPaolo Bonzini             if (value & (1 << 4))			/* MA */
1433dd285b06SPaolo Bonzini                 i2c_end_transfer(s->bus);
1434dd285b06SPaolo Bonzini         pxa2xx_i2c_update(s);
1435dd285b06SPaolo Bonzini         break;
1436dd285b06SPaolo Bonzini 
1437dd285b06SPaolo Bonzini     case ISR:
1438dd285b06SPaolo Bonzini         s->status &= ~(value & 0x07f0);
1439dd285b06SPaolo Bonzini         pxa2xx_i2c_update(s);
1440dd285b06SPaolo Bonzini         break;
1441dd285b06SPaolo Bonzini 
1442dd285b06SPaolo Bonzini     case ISAR:
1443c8665a59SPhilippe Mathieu-Daudé         i2c_slave_set_address(I2C_SLAVE(s->slave), value & 0x7f);
1444dd285b06SPaolo Bonzini         break;
1445dd285b06SPaolo Bonzini 
1446dd285b06SPaolo Bonzini     case IDBR:
1447dd285b06SPaolo Bonzini         s->data = value & 0xff;
1448dd285b06SPaolo Bonzini         break;
1449dd285b06SPaolo Bonzini 
1450dd285b06SPaolo Bonzini     default:
1451fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
1452fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
1453fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
1454dd285b06SPaolo Bonzini     }
1455dd285b06SPaolo Bonzini }
1456dd285b06SPaolo Bonzini 
1457dd285b06SPaolo Bonzini static const MemoryRegionOps pxa2xx_i2c_ops = {
1458dd285b06SPaolo Bonzini     .read = pxa2xx_i2c_read,
1459dd285b06SPaolo Bonzini     .write = pxa2xx_i2c_write,
1460dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1461dd285b06SPaolo Bonzini };
1462dd285b06SPaolo Bonzini 
1463dd285b06SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
1464dd285b06SPaolo Bonzini     .name = "pxa2xx_i2c_slave",
1465dd285b06SPaolo Bonzini     .version_id = 1,
1466dd285b06SPaolo Bonzini     .minimum_version_id = 1,
1467*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
146896dca6b9SAndreas Färber         VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState),
1469dd285b06SPaolo Bonzini         VMSTATE_END_OF_LIST()
1470dd285b06SPaolo Bonzini     }
1471dd285b06SPaolo Bonzini };
1472dd285b06SPaolo Bonzini 
1473dd285b06SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_i2c = {
1474dd285b06SPaolo Bonzini     .name = "pxa2xx_i2c",
1475dd285b06SPaolo Bonzini     .version_id = 1,
1476dd285b06SPaolo Bonzini     .minimum_version_id = 1,
1477*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
1478dd285b06SPaolo Bonzini         VMSTATE_UINT16(control, PXA2xxI2CState),
1479dd285b06SPaolo Bonzini         VMSTATE_UINT16(status, PXA2xxI2CState),
1480dd285b06SPaolo Bonzini         VMSTATE_UINT8(ibmr, PXA2xxI2CState),
1481dd285b06SPaolo Bonzini         VMSTATE_UINT8(data, PXA2xxI2CState),
1482dd285b06SPaolo Bonzini         VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
148320bcf73fSPeter Maydell                                vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState),
1484dd285b06SPaolo Bonzini         VMSTATE_END_OF_LIST()
1485dd285b06SPaolo Bonzini     }
1486dd285b06SPaolo Bonzini };
1487dd285b06SPaolo Bonzini 
pxa2xx_i2c_slave_class_init(ObjectClass * klass,void * data)1488dd285b06SPaolo Bonzini static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
1489dd285b06SPaolo Bonzini {
1490dd285b06SPaolo Bonzini     I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1491dd285b06SPaolo Bonzini 
1492dd285b06SPaolo Bonzini     k->event = pxa2xx_i2c_event;
1493dd285b06SPaolo Bonzini     k->recv = pxa2xx_i2c_rx;
1494dd285b06SPaolo Bonzini     k->send = pxa2xx_i2c_tx;
1495dd285b06SPaolo Bonzini }
1496dd285b06SPaolo Bonzini 
1497dd285b06SPaolo Bonzini static const TypeInfo pxa2xx_i2c_slave_info = {
149896dca6b9SAndreas Färber     .name          = TYPE_PXA2XX_I2C_SLAVE,
1499dd285b06SPaolo Bonzini     .parent        = TYPE_I2C_SLAVE,
1500dd285b06SPaolo Bonzini     .instance_size = sizeof(PXA2xxI2CSlaveState),
1501dd285b06SPaolo Bonzini     .class_init    = pxa2xx_i2c_slave_class_init,
1502dd285b06SPaolo Bonzini };
1503dd285b06SPaolo Bonzini 
pxa2xx_i2c_init(hwaddr base,qemu_irq irq,uint32_t region_size)1504dd285b06SPaolo Bonzini PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
1505dd285b06SPaolo Bonzini                 qemu_irq irq, uint32_t region_size)
1506dd285b06SPaolo Bonzini {
1507dd285b06SPaolo Bonzini     DeviceState *dev;
1508dd285b06SPaolo Bonzini     SysBusDevice *i2c_dev;
1509dd285b06SPaolo Bonzini     PXA2xxI2CState *s;
1510a5c82852SAndreas Färber     I2CBus *i2cbus;
1511dd285b06SPaolo Bonzini 
15123e80f690SMarkus Armbruster     dev = qdev_new(TYPE_PXA2XX_I2C);
15135354c21eSAndreas Färber     qdev_prop_set_uint32(dev, "size", region_size + 1);
15145354c21eSAndreas Färber     qdev_prop_set_uint32(dev, "offset", base & region_size);
1515dd285b06SPaolo Bonzini 
1516bf348bf9SPhilippe Mathieu-Daudé     /* FIXME: Should the slave device really be on a separate bus?  */
1517bf348bf9SPhilippe Mathieu-Daudé     i2cbus = i2c_init_bus(dev, "dummy");
1518bf348bf9SPhilippe Mathieu-Daudé 
15195354c21eSAndreas Färber     i2c_dev = SYS_BUS_DEVICE(dev);
15203c6ef471SMarkus Armbruster     sysbus_realize_and_unref(i2c_dev, &error_fatal);
1521dd285b06SPaolo Bonzini     sysbus_mmio_map(i2c_dev, 0, base & ~region_size);
1522dd285b06SPaolo Bonzini     sysbus_connect_irq(i2c_dev, 0, irq);
1523dd285b06SPaolo Bonzini 
15245354c21eSAndreas Färber     s = PXA2XX_I2C(i2c_dev);
15251373b15bSPhilippe Mathieu-Daudé     s->slave = PXA2XX_I2C_SLAVE(i2c_slave_create_simple(i2cbus,
15261373b15bSPhilippe Mathieu-Daudé                                                         TYPE_PXA2XX_I2C_SLAVE,
15271373b15bSPhilippe Mathieu-Daudé                                                         0));
1528dd285b06SPaolo Bonzini     s->slave->host = s;
1529dd285b06SPaolo Bonzini 
1530dd285b06SPaolo Bonzini     return s;
1531dd285b06SPaolo Bonzini }
1532dd285b06SPaolo Bonzini 
pxa2xx_i2c_initfn(Object * obj)153316fb31a3Sxiaoqiang.zhao static void pxa2xx_i2c_initfn(Object *obj)
1534dd285b06SPaolo Bonzini {
153516fb31a3Sxiaoqiang.zhao     DeviceState *dev = DEVICE(obj);
153616fb31a3Sxiaoqiang.zhao     PXA2xxI2CState *s = PXA2XX_I2C(obj);
153716fb31a3Sxiaoqiang.zhao     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1538dd285b06SPaolo Bonzini 
153908426da7SVijay Kumar B     s->bus = i2c_init_bus(dev, NULL);
1540dd285b06SPaolo Bonzini 
154116fb31a3Sxiaoqiang.zhao     memory_region_init_io(&s->iomem, obj, &pxa2xx_i2c_ops, s,
154264bde0f3SPaolo Bonzini                           "pxa2xx-i2c", s->region_size);
15435354c21eSAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
15445354c21eSAndreas Färber     sysbus_init_irq(sbd, &s->irq);
1545dd285b06SPaolo Bonzini }
1546dd285b06SPaolo Bonzini 
pxa2xx_i2c_bus(PXA2xxI2CState * s)1547a5c82852SAndreas Färber I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
1548dd285b06SPaolo Bonzini {
1549dd285b06SPaolo Bonzini     return s->bus;
1550dd285b06SPaolo Bonzini }
1551dd285b06SPaolo Bonzini 
1552dd285b06SPaolo Bonzini static Property pxa2xx_i2c_properties[] = {
1553dd285b06SPaolo Bonzini     DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
1554dd285b06SPaolo Bonzini     DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
1555dd285b06SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
1556dd285b06SPaolo Bonzini };
1557dd285b06SPaolo Bonzini 
pxa2xx_i2c_class_init(ObjectClass * klass,void * data)1558dd285b06SPaolo Bonzini static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data)
1559dd285b06SPaolo Bonzini {
1560dd285b06SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
1561dd285b06SPaolo Bonzini 
1562dd285b06SPaolo Bonzini     dc->desc = "PXA2xx I2C Bus Controller";
1563dd285b06SPaolo Bonzini     dc->vmsd = &vmstate_pxa2xx_i2c;
15644f67d30bSMarc-André Lureau     device_class_set_props(dc, pxa2xx_i2c_properties);
1565dd285b06SPaolo Bonzini }
1566dd285b06SPaolo Bonzini 
1567dd285b06SPaolo Bonzini static const TypeInfo pxa2xx_i2c_info = {
15685354c21eSAndreas Färber     .name          = TYPE_PXA2XX_I2C,
1569dd285b06SPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
1570dd285b06SPaolo Bonzini     .instance_size = sizeof(PXA2xxI2CState),
157116fb31a3Sxiaoqiang.zhao     .instance_init = pxa2xx_i2c_initfn,
1572dd285b06SPaolo Bonzini     .class_init    = pxa2xx_i2c_class_init,
1573dd285b06SPaolo Bonzini };
1574dd285b06SPaolo Bonzini 
1575dd285b06SPaolo Bonzini /* PXA Inter-IC Sound Controller */
pxa2xx_i2s_reset(PXA2xxI2SState * i2s)1576dd285b06SPaolo Bonzini static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s)
1577dd285b06SPaolo Bonzini {
1578dd285b06SPaolo Bonzini     i2s->rx_len = 0;
1579dd285b06SPaolo Bonzini     i2s->tx_len = 0;
1580dd285b06SPaolo Bonzini     i2s->fifo_len = 0;
1581dd285b06SPaolo Bonzini     i2s->clk = 0x1a;
1582dd285b06SPaolo Bonzini     i2s->control[0] = 0x00;
1583dd285b06SPaolo Bonzini     i2s->control[1] = 0x00;
1584dd285b06SPaolo Bonzini     i2s->status = 0x00;
1585dd285b06SPaolo Bonzini     i2s->mask = 0x00;
1586dd285b06SPaolo Bonzini }
1587dd285b06SPaolo Bonzini 
1588dd285b06SPaolo Bonzini #define SACR_TFTH(val)	((val >> 8) & 0xf)
1589dd285b06SPaolo Bonzini #define SACR_RFTH(val)	((val >> 12) & 0xf)
1590dd285b06SPaolo Bonzini #define SACR_DREC(val)	(val & (1 << 3))
1591dd285b06SPaolo Bonzini #define SACR_DPRL(val)	(val & (1 << 4))
1592dd285b06SPaolo Bonzini 
pxa2xx_i2s_update(PXA2xxI2SState * i2s)1593dd285b06SPaolo Bonzini static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s)
1594dd285b06SPaolo Bonzini {
1595dd285b06SPaolo Bonzini     int rfs, tfs;
1596dd285b06SPaolo Bonzini     rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
1597dd285b06SPaolo Bonzini             !SACR_DREC(i2s->control[1]);
1598dd285b06SPaolo Bonzini     tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
1599dd285b06SPaolo Bonzini             i2s->enable && !SACR_DPRL(i2s->control[1]);
1600dd285b06SPaolo Bonzini 
1601dd285b06SPaolo Bonzini     qemu_set_irq(i2s->rx_dma, rfs);
1602dd285b06SPaolo Bonzini     qemu_set_irq(i2s->tx_dma, tfs);
1603dd285b06SPaolo Bonzini 
1604dd285b06SPaolo Bonzini     i2s->status &= 0xe0;
1605dd285b06SPaolo Bonzini     if (i2s->fifo_len < 16 || !i2s->enable)
1606dd285b06SPaolo Bonzini         i2s->status |= 1 << 0;			/* TNF */
1607dd285b06SPaolo Bonzini     if (i2s->rx_len)
1608dd285b06SPaolo Bonzini         i2s->status |= 1 << 1;			/* RNE */
1609dd285b06SPaolo Bonzini     if (i2s->enable)
1610dd285b06SPaolo Bonzini         i2s->status |= 1 << 2;			/* BSY */
1611dd285b06SPaolo Bonzini     if (tfs)
1612dd285b06SPaolo Bonzini         i2s->status |= 1 << 3;			/* TFS */
1613dd285b06SPaolo Bonzini     if (rfs)
1614dd285b06SPaolo Bonzini         i2s->status |= 1 << 4;			/* RFS */
1615dd285b06SPaolo Bonzini     if (!(i2s->tx_len && i2s->enable))
1616dd285b06SPaolo Bonzini         i2s->status |= i2s->fifo_len << 8;	/* TFL */
1617dd285b06SPaolo Bonzini     i2s->status |= MAX(i2s->rx_len, 0xf) << 12;	/* RFL */
1618dd285b06SPaolo Bonzini 
1619dd285b06SPaolo Bonzini     qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
1620dd285b06SPaolo Bonzini }
1621dd285b06SPaolo Bonzini 
1622dd285b06SPaolo Bonzini #define SACR0	0x00	/* Serial Audio Global Control register */
1623dd285b06SPaolo Bonzini #define SACR1	0x04	/* Serial Audio I2S/MSB-Justified Control register */
1624dd285b06SPaolo Bonzini #define SASR0	0x0c	/* Serial Audio Interface and FIFO Status register */
1625dd285b06SPaolo Bonzini #define SAIMR	0x14	/* Serial Audio Interrupt Mask register */
1626dd285b06SPaolo Bonzini #define SAICR	0x18	/* Serial Audio Interrupt Clear register */
1627dd285b06SPaolo Bonzini #define SADIV	0x60	/* Serial Audio Clock Divider register */
1628dd285b06SPaolo Bonzini #define SADR	0x80	/* Serial Audio Data register */
1629dd285b06SPaolo Bonzini 
pxa2xx_i2s_read(void * opaque,hwaddr addr,unsigned size)1630dd285b06SPaolo Bonzini static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr,
1631dd285b06SPaolo Bonzini                                 unsigned size)
1632dd285b06SPaolo Bonzini {
1633dd285b06SPaolo Bonzini     PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
1634dd285b06SPaolo Bonzini 
1635dd285b06SPaolo Bonzini     switch (addr) {
1636dd285b06SPaolo Bonzini     case SACR0:
1637dd285b06SPaolo Bonzini         return s->control[0];
1638dd285b06SPaolo Bonzini     case SACR1:
1639dd285b06SPaolo Bonzini         return s->control[1];
1640dd285b06SPaolo Bonzini     case SASR0:
1641dd285b06SPaolo Bonzini         return s->status;
1642dd285b06SPaolo Bonzini     case SAIMR:
1643dd285b06SPaolo Bonzini         return s->mask;
1644dd285b06SPaolo Bonzini     case SAICR:
1645dd285b06SPaolo Bonzini         return 0;
1646dd285b06SPaolo Bonzini     case SADIV:
1647dd285b06SPaolo Bonzini         return s->clk;
1648dd285b06SPaolo Bonzini     case SADR:
1649dd285b06SPaolo Bonzini         if (s->rx_len > 0) {
1650dd285b06SPaolo Bonzini             s->rx_len --;
1651dd285b06SPaolo Bonzini             pxa2xx_i2s_update(s);
1652dd285b06SPaolo Bonzini             return s->codec_in(s->opaque);
1653dd285b06SPaolo Bonzini         }
1654dd285b06SPaolo Bonzini         return 0;
1655dd285b06SPaolo Bonzini     default:
1656fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
1657fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
1658fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
1659dd285b06SPaolo Bonzini         break;
1660dd285b06SPaolo Bonzini     }
1661dd285b06SPaolo Bonzini     return 0;
1662dd285b06SPaolo Bonzini }
1663dd285b06SPaolo Bonzini 
pxa2xx_i2s_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)1664dd285b06SPaolo Bonzini static void pxa2xx_i2s_write(void *opaque, hwaddr addr,
1665dd285b06SPaolo Bonzini                              uint64_t value, unsigned size)
1666dd285b06SPaolo Bonzini {
1667dd285b06SPaolo Bonzini     PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
1668dd285b06SPaolo Bonzini     uint32_t *sample;
1669dd285b06SPaolo Bonzini 
1670dd285b06SPaolo Bonzini     switch (addr) {
1671dd285b06SPaolo Bonzini     case SACR0:
1672dd285b06SPaolo Bonzini         if (value & (1 << 3))				/* RST */
1673dd285b06SPaolo Bonzini             pxa2xx_i2s_reset(s);
1674dd285b06SPaolo Bonzini         s->control[0] = value & 0xff3d;
1675dd285b06SPaolo Bonzini         if (!s->enable && (value & 1) && s->tx_len) {	/* ENB */
1676dd285b06SPaolo Bonzini             for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
1677dd285b06SPaolo Bonzini                 s->codec_out(s->opaque, *sample);
1678dd285b06SPaolo Bonzini             s->status &= ~(1 << 7);			/* I2SOFF */
1679dd285b06SPaolo Bonzini         }
1680dd285b06SPaolo Bonzini         if (value & (1 << 4))				/* EFWR */
1681a89f364aSAlistair Francis             printf("%s: Attempt to use special function\n", __func__);
1682dd285b06SPaolo Bonzini         s->enable = (value & 9) == 1;			/* ENB && !RST*/
1683dd285b06SPaolo Bonzini         pxa2xx_i2s_update(s);
1684dd285b06SPaolo Bonzini         break;
1685dd285b06SPaolo Bonzini     case SACR1:
1686dd285b06SPaolo Bonzini         s->control[1] = value & 0x0039;
1687dd285b06SPaolo Bonzini         if (value & (1 << 5))				/* ENLBF */
1688a89f364aSAlistair Francis             printf("%s: Attempt to use loopback function\n", __func__);
1689dd285b06SPaolo Bonzini         if (value & (1 << 4))				/* DPRL */
1690dd285b06SPaolo Bonzini             s->fifo_len = 0;
1691dd285b06SPaolo Bonzini         pxa2xx_i2s_update(s);
1692dd285b06SPaolo Bonzini         break;
1693dd285b06SPaolo Bonzini     case SAIMR:
1694dd285b06SPaolo Bonzini         s->mask = value & 0x0078;
1695dd285b06SPaolo Bonzini         pxa2xx_i2s_update(s);
1696dd285b06SPaolo Bonzini         break;
1697dd285b06SPaolo Bonzini     case SAICR:
1698dd285b06SPaolo Bonzini         s->status &= ~(value & (3 << 5));
1699dd285b06SPaolo Bonzini         pxa2xx_i2s_update(s);
1700dd285b06SPaolo Bonzini         break;
1701dd285b06SPaolo Bonzini     case SADIV:
1702dd285b06SPaolo Bonzini         s->clk = value & 0x007f;
1703dd285b06SPaolo Bonzini         break;
1704dd285b06SPaolo Bonzini     case SADR:
1705dd285b06SPaolo Bonzini         if (s->tx_len && s->enable) {
1706dd285b06SPaolo Bonzini             s->tx_len --;
1707dd285b06SPaolo Bonzini             pxa2xx_i2s_update(s);
1708dd285b06SPaolo Bonzini             s->codec_out(s->opaque, value);
1709dd285b06SPaolo Bonzini         } else if (s->fifo_len < 16) {
1710dd285b06SPaolo Bonzini             s->fifo[s->fifo_len ++] = value;
1711dd285b06SPaolo Bonzini             pxa2xx_i2s_update(s);
1712dd285b06SPaolo Bonzini         }
1713dd285b06SPaolo Bonzini         break;
1714dd285b06SPaolo Bonzini     default:
1715fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
1716fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
1717fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
1718dd285b06SPaolo Bonzini     }
1719dd285b06SPaolo Bonzini }
1720dd285b06SPaolo Bonzini 
1721dd285b06SPaolo Bonzini static const MemoryRegionOps pxa2xx_i2s_ops = {
1722dd285b06SPaolo Bonzini     .read = pxa2xx_i2s_read,
1723dd285b06SPaolo Bonzini     .write = pxa2xx_i2s_write,
1724dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1725dd285b06SPaolo Bonzini };
1726dd285b06SPaolo Bonzini 
1727dd285b06SPaolo Bonzini static const VMStateDescription vmstate_pxa2xx_i2s = {
1728dd285b06SPaolo Bonzini     .name = "pxa2xx_i2s",
1729dd285b06SPaolo Bonzini     .version_id = 0,
1730dd285b06SPaolo Bonzini     .minimum_version_id = 0,
1731*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
1732dd285b06SPaolo Bonzini         VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
1733dd285b06SPaolo Bonzini         VMSTATE_UINT32(status, PXA2xxI2SState),
1734dd285b06SPaolo Bonzini         VMSTATE_UINT32(mask, PXA2xxI2SState),
1735dd285b06SPaolo Bonzini         VMSTATE_UINT32(clk, PXA2xxI2SState),
1736dd285b06SPaolo Bonzini         VMSTATE_INT32(enable, PXA2xxI2SState),
1737dd285b06SPaolo Bonzini         VMSTATE_INT32(rx_len, PXA2xxI2SState),
1738dd285b06SPaolo Bonzini         VMSTATE_INT32(tx_len, PXA2xxI2SState),
1739dd285b06SPaolo Bonzini         VMSTATE_INT32(fifo_len, PXA2xxI2SState),
1740dd285b06SPaolo Bonzini         VMSTATE_END_OF_LIST()
1741dd285b06SPaolo Bonzini     }
1742dd285b06SPaolo Bonzini };
1743dd285b06SPaolo Bonzini 
pxa2xx_i2s_data_req(void * opaque,int tx,int rx)1744dd285b06SPaolo Bonzini static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
1745dd285b06SPaolo Bonzini {
1746dd285b06SPaolo Bonzini     PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
1747dd285b06SPaolo Bonzini     uint32_t *sample;
1748dd285b06SPaolo Bonzini 
1749dd285b06SPaolo Bonzini     /* Signal FIFO errors */
1750dd285b06SPaolo Bonzini     if (s->enable && s->tx_len)
1751dd285b06SPaolo Bonzini         s->status |= 1 << 5;		/* TUR */
1752dd285b06SPaolo Bonzini     if (s->enable && s->rx_len)
1753dd285b06SPaolo Bonzini         s->status |= 1 << 6;		/* ROR */
1754dd285b06SPaolo Bonzini 
1755dd285b06SPaolo Bonzini     /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
1756dd285b06SPaolo Bonzini      * handle the cases where it makes a difference.  */
1757dd285b06SPaolo Bonzini     s->tx_len = tx - s->fifo_len;
1758dd285b06SPaolo Bonzini     s->rx_len = rx;
1759dd285b06SPaolo Bonzini     /* Note that is s->codec_out wasn't set, we wouldn't get called.  */
1760dd285b06SPaolo Bonzini     if (s->enable)
1761dd285b06SPaolo Bonzini         for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
1762dd285b06SPaolo Bonzini             s->codec_out(s->opaque, *sample);
1763dd285b06SPaolo Bonzini     pxa2xx_i2s_update(s);
1764dd285b06SPaolo Bonzini }
1765dd285b06SPaolo Bonzini 
pxa2xx_i2s_init(MemoryRegion * sysmem,hwaddr base,qemu_irq irq,qemu_irq rx_dma,qemu_irq tx_dma)1766dd285b06SPaolo Bonzini static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
1767dd285b06SPaolo Bonzini                 hwaddr base,
1768dd285b06SPaolo Bonzini                 qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
1769dd285b06SPaolo Bonzini {
1770b45c03f5SMarkus Armbruster     PXA2xxI2SState *s = g_new0(PXA2xxI2SState, 1);
1771dd285b06SPaolo Bonzini 
1772dd285b06SPaolo Bonzini     s->irq = irq;
1773dd285b06SPaolo Bonzini     s->rx_dma = rx_dma;
1774dd285b06SPaolo Bonzini     s->tx_dma = tx_dma;
1775dd285b06SPaolo Bonzini     s->data_req = pxa2xx_i2s_data_req;
1776dd285b06SPaolo Bonzini 
1777dd285b06SPaolo Bonzini     pxa2xx_i2s_reset(s);
1778dd285b06SPaolo Bonzini 
17792c9b15caSPaolo Bonzini     memory_region_init_io(&s->iomem, NULL, &pxa2xx_i2s_ops, s,
1780dd285b06SPaolo Bonzini                           "pxa2xx-i2s", 0x100000);
1781dd285b06SPaolo Bonzini     memory_region_add_subregion(sysmem, base, &s->iomem);
1782dd285b06SPaolo Bonzini 
1783dd285b06SPaolo Bonzini     vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s);
1784dd285b06SPaolo Bonzini 
1785dd285b06SPaolo Bonzini     return s;
1786dd285b06SPaolo Bonzini }
1787dd285b06SPaolo Bonzini 
1788dd285b06SPaolo Bonzini /* PXA Fast Infra-red Communications Port */
1789dd285b06SPaolo Bonzini struct PXA2xxFIrState {
17901fd9f2dfSPeter Maydell     /*< private >*/
17911fd9f2dfSPeter Maydell     SysBusDevice parent_obj;
17921fd9f2dfSPeter Maydell     /*< public >*/
17931fd9f2dfSPeter Maydell 
1794dd285b06SPaolo Bonzini     MemoryRegion iomem;
1795dd285b06SPaolo Bonzini     qemu_irq irq;
1796dd285b06SPaolo Bonzini     qemu_irq rx_dma;
1797dd285b06SPaolo Bonzini     qemu_irq tx_dma;
17981fd9f2dfSPeter Maydell     uint32_t enable;
1799becdfa00SMarc-André Lureau     CharBackend chr;
1800dd285b06SPaolo Bonzini 
1801dd285b06SPaolo Bonzini     uint8_t control[3];
1802dd285b06SPaolo Bonzini     uint8_t status[2];
1803dd285b06SPaolo Bonzini 
18041fd9f2dfSPeter Maydell     uint32_t rx_len;
18051fd9f2dfSPeter Maydell     uint32_t rx_start;
1806dd285b06SPaolo Bonzini     uint8_t rx_fifo[64];
1807dd285b06SPaolo Bonzini };
1808dd285b06SPaolo Bonzini 
pxa2xx_fir_reset(DeviceState * d)18091fd9f2dfSPeter Maydell static void pxa2xx_fir_reset(DeviceState *d)
1810dd285b06SPaolo Bonzini {
18111fd9f2dfSPeter Maydell     PXA2xxFIrState *s = PXA2XX_FIR(d);
18121fd9f2dfSPeter Maydell 
1813dd285b06SPaolo Bonzini     s->control[0] = 0x00;
1814dd285b06SPaolo Bonzini     s->control[1] = 0x00;
1815dd285b06SPaolo Bonzini     s->control[2] = 0x00;
1816dd285b06SPaolo Bonzini     s->status[0] = 0x00;
1817dd285b06SPaolo Bonzini     s->status[1] = 0x00;
1818dd285b06SPaolo Bonzini     s->enable = 0;
1819dd285b06SPaolo Bonzini }
1820dd285b06SPaolo Bonzini 
pxa2xx_fir_update(PXA2xxFIrState * s)1821dd285b06SPaolo Bonzini static inline void pxa2xx_fir_update(PXA2xxFIrState *s)
1822dd285b06SPaolo Bonzini {
1823dd285b06SPaolo Bonzini     static const int tresh[4] = { 8, 16, 32, 0 };
1824dd285b06SPaolo Bonzini     int intr = 0;
1825dd285b06SPaolo Bonzini     if ((s->control[0] & (1 << 4)) &&			/* RXE */
1826dd285b06SPaolo Bonzini                     s->rx_len >= tresh[s->control[2] & 3])	/* TRIG */
1827dd285b06SPaolo Bonzini         s->status[0] |= 1 << 4;				/* RFS */
1828dd285b06SPaolo Bonzini     else
1829dd285b06SPaolo Bonzini         s->status[0] &= ~(1 << 4);			/* RFS */
1830dd285b06SPaolo Bonzini     if (s->control[0] & (1 << 3))			/* TXE */
1831dd285b06SPaolo Bonzini         s->status[0] |= 1 << 3;				/* TFS */
1832dd285b06SPaolo Bonzini     else
1833dd285b06SPaolo Bonzini         s->status[0] &= ~(1 << 3);			/* TFS */
1834dd285b06SPaolo Bonzini     if (s->rx_len)
1835dd285b06SPaolo Bonzini         s->status[1] |= 1 << 2;				/* RNE */
1836dd285b06SPaolo Bonzini     else
1837dd285b06SPaolo Bonzini         s->status[1] &= ~(1 << 2);			/* RNE */
1838dd285b06SPaolo Bonzini     if (s->control[0] & (1 << 4))			/* RXE */
1839dd285b06SPaolo Bonzini         s->status[1] |= 1 << 0;				/* RSY */
1840dd285b06SPaolo Bonzini     else
1841dd285b06SPaolo Bonzini         s->status[1] &= ~(1 << 0);			/* RSY */
1842dd285b06SPaolo Bonzini 
1843dd285b06SPaolo Bonzini     intr |= (s->control[0] & (1 << 5)) &&		/* RIE */
1844dd285b06SPaolo Bonzini             (s->status[0] & (1 << 4));			/* RFS */
1845dd285b06SPaolo Bonzini     intr |= (s->control[0] & (1 << 6)) &&		/* TIE */
1846dd285b06SPaolo Bonzini             (s->status[0] & (1 << 3));			/* TFS */
1847dd285b06SPaolo Bonzini     intr |= (s->control[2] & (1 << 4)) &&		/* TRAIL */
1848dd285b06SPaolo Bonzini             (s->status[0] & (1 << 6));			/* EOC */
1849dd285b06SPaolo Bonzini     intr |= (s->control[0] & (1 << 2)) &&		/* TUS */
1850dd285b06SPaolo Bonzini             (s->status[0] & (1 << 1));			/* TUR */
1851dd285b06SPaolo Bonzini     intr |= s->status[0] & 0x25;			/* FRE, RAB, EIF */
1852dd285b06SPaolo Bonzini 
1853dd285b06SPaolo Bonzini     qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1);
1854dd285b06SPaolo Bonzini     qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1);
1855dd285b06SPaolo Bonzini 
1856dd285b06SPaolo Bonzini     qemu_set_irq(s->irq, intr && s->enable);
1857dd285b06SPaolo Bonzini }
1858dd285b06SPaolo Bonzini 
1859dd285b06SPaolo Bonzini #define ICCR0	0x00	/* FICP Control register 0 */
1860dd285b06SPaolo Bonzini #define ICCR1	0x04	/* FICP Control register 1 */
1861dd285b06SPaolo Bonzini #define ICCR2	0x08	/* FICP Control register 2 */
1862dd285b06SPaolo Bonzini #define ICDR	0x0c	/* FICP Data register */
1863dd285b06SPaolo Bonzini #define ICSR0	0x14	/* FICP Status register 0 */
1864dd285b06SPaolo Bonzini #define ICSR1	0x18	/* FICP Status register 1 */
1865dd285b06SPaolo Bonzini #define ICFOR	0x1c	/* FICP FIFO Occupancy Status register */
1866dd285b06SPaolo Bonzini 
pxa2xx_fir_read(void * opaque,hwaddr addr,unsigned size)1867dd285b06SPaolo Bonzini static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr,
1868dd285b06SPaolo Bonzini                                 unsigned size)
1869dd285b06SPaolo Bonzini {
1870dd285b06SPaolo Bonzini     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
1871dd285b06SPaolo Bonzini     uint8_t ret;
1872dd285b06SPaolo Bonzini 
1873dd285b06SPaolo Bonzini     switch (addr) {
1874dd285b06SPaolo Bonzini     case ICCR0:
1875dd285b06SPaolo Bonzini         return s->control[0];
1876dd285b06SPaolo Bonzini     case ICCR1:
1877dd285b06SPaolo Bonzini         return s->control[1];
1878dd285b06SPaolo Bonzini     case ICCR2:
1879dd285b06SPaolo Bonzini         return s->control[2];
1880dd285b06SPaolo Bonzini     case ICDR:
1881dd285b06SPaolo Bonzini         s->status[0] &= ~0x01;
1882dd285b06SPaolo Bonzini         s->status[1] &= ~0x72;
1883dd285b06SPaolo Bonzini         if (s->rx_len) {
1884dd285b06SPaolo Bonzini             s->rx_len --;
1885dd285b06SPaolo Bonzini             ret = s->rx_fifo[s->rx_start ++];
1886dd285b06SPaolo Bonzini             s->rx_start &= 63;
1887dd285b06SPaolo Bonzini             pxa2xx_fir_update(s);
1888dd285b06SPaolo Bonzini             return ret;
1889dd285b06SPaolo Bonzini         }
1890a89f364aSAlistair Francis         printf("%s: Rx FIFO underrun.\n", __func__);
1891dd285b06SPaolo Bonzini         break;
1892dd285b06SPaolo Bonzini     case ICSR0:
1893dd285b06SPaolo Bonzini         return s->status[0];
1894dd285b06SPaolo Bonzini     case ICSR1:
1895dd285b06SPaolo Bonzini         return s->status[1] | (1 << 3);			/* TNF */
1896dd285b06SPaolo Bonzini     case ICFOR:
1897dd285b06SPaolo Bonzini         return s->rx_len;
1898dd285b06SPaolo Bonzini     default:
1899fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
1900fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
1901fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
1902dd285b06SPaolo Bonzini         break;
1903dd285b06SPaolo Bonzini     }
1904dd285b06SPaolo Bonzini     return 0;
1905dd285b06SPaolo Bonzini }
1906dd285b06SPaolo Bonzini 
pxa2xx_fir_write(void * opaque,hwaddr addr,uint64_t value64,unsigned size)1907dd285b06SPaolo Bonzini static void pxa2xx_fir_write(void *opaque, hwaddr addr,
1908dd285b06SPaolo Bonzini                              uint64_t value64, unsigned size)
1909dd285b06SPaolo Bonzini {
1910dd285b06SPaolo Bonzini     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
1911dd285b06SPaolo Bonzini     uint32_t value = value64;
1912dd285b06SPaolo Bonzini     uint8_t ch;
1913dd285b06SPaolo Bonzini 
1914dd285b06SPaolo Bonzini     switch (addr) {
1915dd285b06SPaolo Bonzini     case ICCR0:
1916dd285b06SPaolo Bonzini         s->control[0] = value;
1917dd285b06SPaolo Bonzini         if (!(value & (1 << 4)))			/* RXE */
1918dd285b06SPaolo Bonzini             s->rx_len = s->rx_start = 0;
1919dd285b06SPaolo Bonzini         if (!(value & (1 << 3))) {                      /* TXE */
1920dd285b06SPaolo Bonzini             /* Nop */
1921dd285b06SPaolo Bonzini         }
1922dd285b06SPaolo Bonzini         s->enable = value & 1;				/* ITR */
1923dd285b06SPaolo Bonzini         if (!s->enable)
1924dd285b06SPaolo Bonzini             s->status[0] = 0;
1925dd285b06SPaolo Bonzini         pxa2xx_fir_update(s);
1926dd285b06SPaolo Bonzini         break;
1927dd285b06SPaolo Bonzini     case ICCR1:
1928dd285b06SPaolo Bonzini         s->control[1] = value;
1929dd285b06SPaolo Bonzini         break;
1930dd285b06SPaolo Bonzini     case ICCR2:
1931dd285b06SPaolo Bonzini         s->control[2] = value & 0x3f;
1932dd285b06SPaolo Bonzini         pxa2xx_fir_update(s);
1933dd285b06SPaolo Bonzini         break;
1934dd285b06SPaolo Bonzini     case ICDR:
1935becdfa00SMarc-André Lureau         if (s->control[2] & (1 << 2)) { /* TXP */
1936dd285b06SPaolo Bonzini             ch = value;
1937becdfa00SMarc-André Lureau         } else {
1938dd285b06SPaolo Bonzini             ch = ~value;
1939becdfa00SMarc-André Lureau         }
1940fa394ed6SMarc-André Lureau         if (s->enable && (s->control[0] & (1 << 3))) { /* TXE */
19416ab3fc32SDaniel P. Berrange             /* XXX this blocks entire thread. Rewrite to use
19426ab3fc32SDaniel P. Berrange              * qemu_chr_fe_write and background I/O callbacks */
19435345fdb4SMarc-André Lureau             qemu_chr_fe_write_all(&s->chr, &ch, 1);
1944becdfa00SMarc-André Lureau         }
1945dd285b06SPaolo Bonzini         break;
1946dd285b06SPaolo Bonzini     case ICSR0:
1947dd285b06SPaolo Bonzini         s->status[0] &= ~(value & 0x66);
1948dd285b06SPaolo Bonzini         pxa2xx_fir_update(s);
1949dd285b06SPaolo Bonzini         break;
1950dd285b06SPaolo Bonzini     case ICFOR:
1951dd285b06SPaolo Bonzini         break;
1952dd285b06SPaolo Bonzini     default:
1953fc417e5bSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
1954fc417e5bSPhilippe Mathieu-Daudé                       "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
1955fc417e5bSPhilippe Mathieu-Daudé                       __func__, addr);
1956dd285b06SPaolo Bonzini     }
1957dd285b06SPaolo Bonzini }
1958dd285b06SPaolo Bonzini 
1959dd285b06SPaolo Bonzini static const MemoryRegionOps pxa2xx_fir_ops = {
1960dd285b06SPaolo Bonzini     .read = pxa2xx_fir_read,
1961dd285b06SPaolo Bonzini     .write = pxa2xx_fir_write,
1962dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1963dd285b06SPaolo Bonzini };
1964dd285b06SPaolo Bonzini 
pxa2xx_fir_is_empty(void * opaque)1965dd285b06SPaolo Bonzini static int pxa2xx_fir_is_empty(void *opaque)
1966dd285b06SPaolo Bonzini {
1967dd285b06SPaolo Bonzini     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
1968dd285b06SPaolo Bonzini     return (s->rx_len < 64);
1969dd285b06SPaolo Bonzini }
1970dd285b06SPaolo Bonzini 
pxa2xx_fir_rx(void * opaque,const uint8_t * buf,int size)1971dd285b06SPaolo Bonzini static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
1972dd285b06SPaolo Bonzini {
1973dd285b06SPaolo Bonzini     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
1974dd285b06SPaolo Bonzini     if (!(s->control[0] & (1 << 4)))			/* RXE */
1975dd285b06SPaolo Bonzini         return;
1976dd285b06SPaolo Bonzini 
1977dd285b06SPaolo Bonzini     while (size --) {
1978dd285b06SPaolo Bonzini         s->status[1] |= 1 << 4;				/* EOF */
1979dd285b06SPaolo Bonzini         if (s->rx_len >= 64) {
1980dd285b06SPaolo Bonzini             s->status[1] |= 1 << 6;			/* ROR */
1981dd285b06SPaolo Bonzini             break;
1982dd285b06SPaolo Bonzini         }
1983dd285b06SPaolo Bonzini 
1984dd285b06SPaolo Bonzini         if (s->control[2] & (1 << 3))			/* RXP */
1985dd285b06SPaolo Bonzini             s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
1986dd285b06SPaolo Bonzini         else
1987dd285b06SPaolo Bonzini             s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
1988dd285b06SPaolo Bonzini     }
1989dd285b06SPaolo Bonzini 
1990dd285b06SPaolo Bonzini     pxa2xx_fir_update(s);
1991dd285b06SPaolo Bonzini }
1992dd285b06SPaolo Bonzini 
pxa2xx_fir_event(void * opaque,QEMUChrEvent event)1993083b266fSPhilippe Mathieu-Daudé static void pxa2xx_fir_event(void *opaque, QEMUChrEvent event)
1994dd285b06SPaolo Bonzini {
1995dd285b06SPaolo Bonzini }
1996dd285b06SPaolo Bonzini 
pxa2xx_fir_instance_init(Object * obj)19971fd9f2dfSPeter Maydell static void pxa2xx_fir_instance_init(Object *obj)
1998dd285b06SPaolo Bonzini {
19991fd9f2dfSPeter Maydell     PXA2xxFIrState *s = PXA2XX_FIR(obj);
20001fd9f2dfSPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
2001dd285b06SPaolo Bonzini 
200281e0ab48SPaolo Bonzini     memory_region_init_io(&s->iomem, obj, &pxa2xx_fir_ops, s,
20031fd9f2dfSPeter Maydell                           "pxa2xx-fir", 0x1000);
20041fd9f2dfSPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
20051fd9f2dfSPeter Maydell     sysbus_init_irq(sbd, &s->irq);
20061fd9f2dfSPeter Maydell     sysbus_init_irq(sbd, &s->rx_dma);
20071fd9f2dfSPeter Maydell     sysbus_init_irq(sbd, &s->tx_dma);
2008dd285b06SPaolo Bonzini }
2009dd285b06SPaolo Bonzini 
pxa2xx_fir_realize(DeviceState * dev,Error ** errp)20101fd9f2dfSPeter Maydell static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
2011dd285b06SPaolo Bonzini {
20121fd9f2dfSPeter Maydell     PXA2xxFIrState *s = PXA2XX_FIR(dev);
2013dd285b06SPaolo Bonzini 
20145345fdb4SMarc-André Lureau     qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
201581517ba3SAnton Nefedov                              pxa2xx_fir_rx, pxa2xx_fir_event, NULL, s, NULL,
201681517ba3SAnton Nefedov                              true);
2017dd285b06SPaolo Bonzini }
20181fd9f2dfSPeter Maydell 
pxa2xx_fir_vmstate_validate(void * opaque,int version_id)20191fd9f2dfSPeter Maydell static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
20201fd9f2dfSPeter Maydell {
20211fd9f2dfSPeter Maydell     PXA2xxFIrState *s = opaque;
20221fd9f2dfSPeter Maydell 
20238e079cafSPeter Maydell     return s->rx_start < ARRAY_SIZE(s->rx_fifo);
20241fd9f2dfSPeter Maydell }
20251fd9f2dfSPeter Maydell 
20261fd9f2dfSPeter Maydell static const VMStateDescription pxa2xx_fir_vmsd = {
20271fd9f2dfSPeter Maydell     .name = "pxa2xx-fir",
20281fd9f2dfSPeter Maydell     .version_id = 1,
20291fd9f2dfSPeter Maydell     .minimum_version_id = 1,
2030*607ef570SRichard Henderson     .fields = (const VMStateField[]) {
20311fd9f2dfSPeter Maydell         VMSTATE_UINT32(enable, PXA2xxFIrState),
20321fd9f2dfSPeter Maydell         VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3),
20331fd9f2dfSPeter Maydell         VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2),
20341fd9f2dfSPeter Maydell         VMSTATE_UINT32(rx_len, PXA2xxFIrState),
20351fd9f2dfSPeter Maydell         VMSTATE_UINT32(rx_start, PXA2xxFIrState),
20361fd9f2dfSPeter Maydell         VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate),
20371fd9f2dfSPeter Maydell         VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64),
20381fd9f2dfSPeter Maydell         VMSTATE_END_OF_LIST()
20391fd9f2dfSPeter Maydell     }
20401fd9f2dfSPeter Maydell };
20411fd9f2dfSPeter Maydell 
20421fd9f2dfSPeter Maydell static Property pxa2xx_fir_properties[] = {
20431fd9f2dfSPeter Maydell     DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr),
20441fd9f2dfSPeter Maydell     DEFINE_PROP_END_OF_LIST(),
20451fd9f2dfSPeter Maydell };
20461fd9f2dfSPeter Maydell 
pxa2xx_fir_class_init(ObjectClass * klass,void * data)20471fd9f2dfSPeter Maydell static void pxa2xx_fir_class_init(ObjectClass *klass, void *data)
20481fd9f2dfSPeter Maydell {
20491fd9f2dfSPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
20501fd9f2dfSPeter Maydell 
20511fd9f2dfSPeter Maydell     dc->realize = pxa2xx_fir_realize;
20521fd9f2dfSPeter Maydell     dc->vmsd = &pxa2xx_fir_vmsd;
20534f67d30bSMarc-André Lureau     device_class_set_props(dc, pxa2xx_fir_properties);
20541fd9f2dfSPeter Maydell     dc->reset = pxa2xx_fir_reset;
20551fd9f2dfSPeter Maydell }
20561fd9f2dfSPeter Maydell 
20571fd9f2dfSPeter Maydell static const TypeInfo pxa2xx_fir_info = {
20581fd9f2dfSPeter Maydell     .name = TYPE_PXA2XX_FIR,
20591fd9f2dfSPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
20601fd9f2dfSPeter Maydell     .instance_size = sizeof(PXA2xxFIrState),
20611fd9f2dfSPeter Maydell     .class_init = pxa2xx_fir_class_init,
20621fd9f2dfSPeter Maydell     .instance_init = pxa2xx_fir_instance_init,
20631fd9f2dfSPeter Maydell };
2064dd285b06SPaolo Bonzini 
pxa2xx_fir_init(MemoryRegion * sysmem,hwaddr base,qemu_irq irq,qemu_irq rx_dma,qemu_irq tx_dma,Chardev * chr)2065dd285b06SPaolo Bonzini static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
2066dd285b06SPaolo Bonzini                                        hwaddr base,
20671fd9f2dfSPeter Maydell                                        qemu_irq irq, qemu_irq rx_dma,
20681fd9f2dfSPeter Maydell                                        qemu_irq tx_dma,
20690ec7b3e7SMarc-André Lureau                                        Chardev *chr)
2070dd285b06SPaolo Bonzini {
20711fd9f2dfSPeter Maydell     DeviceState *dev;
20721fd9f2dfSPeter Maydell     SysBusDevice *sbd;
2073dd285b06SPaolo Bonzini 
20743e80f690SMarkus Armbruster     dev = qdev_new(TYPE_PXA2XX_FIR);
20751fd9f2dfSPeter Maydell     qdev_prop_set_chr(dev, "chardev", chr);
20761fd9f2dfSPeter Maydell     sbd = SYS_BUS_DEVICE(dev);
20773c6ef471SMarkus Armbruster     sysbus_realize_and_unref(sbd, &error_fatal);
20781fd9f2dfSPeter Maydell     sysbus_mmio_map(sbd, 0, base);
20791fd9f2dfSPeter Maydell     sysbus_connect_irq(sbd, 0, irq);
20801fd9f2dfSPeter Maydell     sysbus_connect_irq(sbd, 1, rx_dma);
20811fd9f2dfSPeter Maydell     sysbus_connect_irq(sbd, 2, tx_dma);
20821fd9f2dfSPeter Maydell     return PXA2XX_FIR(dev);
2083dd285b06SPaolo Bonzini }
2084dd285b06SPaolo Bonzini 
pxa2xx_reset(void * opaque,int line,int level)2085dd285b06SPaolo Bonzini static void pxa2xx_reset(void *opaque, int line, int level)
2086dd285b06SPaolo Bonzini {
2087dd285b06SPaolo Bonzini     PXA2xxState *s = (PXA2xxState *) opaque;
2088dd285b06SPaolo Bonzini 
2089dd285b06SPaolo Bonzini     if (level && (s->pm_regs[PCFR >> 2] & 0x10)) {	/* GPR_EN */
2090dd285b06SPaolo Bonzini         cpu_reset(CPU(s->cpu));
2091dd285b06SPaolo Bonzini         /* TODO: reset peripherals */
2092dd285b06SPaolo Bonzini     }
2093dd285b06SPaolo Bonzini }
2094dd285b06SPaolo Bonzini 
2095dd285b06SPaolo Bonzini /* Initialise a PXA270 integrated chip (ARM based core).  */
pxa270_init(unsigned int sdram_size,const char * cpu_type)20962990bf5dSPhilippe Mathieu-Daudé PXA2xxState *pxa270_init(unsigned int sdram_size, const char *cpu_type)
2097dd285b06SPaolo Bonzini {
20982990bf5dSPhilippe Mathieu-Daudé     MemoryRegion *address_space = get_system_memory();
2099dd285b06SPaolo Bonzini     PXA2xxState *s;
2100dd285b06SPaolo Bonzini     int i;
2101dd285b06SPaolo Bonzini     DriveInfo *dinfo;
2102b45c03f5SMarkus Armbruster     s = g_new0(PXA2xxState, 1);
2103dd285b06SPaolo Bonzini 
2104ba1ba5ccSIgor Mammedov     if (strncmp(cpu_type, "pxa27", 5)) {
2105c0dbca36SAlistair Francis         error_report("Machine requires a PXA27x processor");
2106dd285b06SPaolo Bonzini         exit(1);
2107dd285b06SPaolo Bonzini     }
2108dd285b06SPaolo Bonzini 
2109ba1ba5ccSIgor Mammedov     s->cpu = ARM_CPU(cpu_create(cpu_type));
2110f3c7d038SAndreas Färber     s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
2111dd285b06SPaolo Bonzini 
2112dd285b06SPaolo Bonzini     /* SDRAM & Internal Memory Storage */
211398a99ce0SPeter Maydell     memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size,
2114f8ed85acSMarkus Armbruster                            &error_fatal);
2115dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
211698a99ce0SPeter Maydell     memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000,
2117f8ed85acSMarkus Armbruster                            &error_fatal);
2118dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
2119dd285b06SPaolo Bonzini                                 &s->internal);
2120dd285b06SPaolo Bonzini 
2121dd285b06SPaolo Bonzini     s->pic = pxa2xx_pic_init(0x40d00000, s->cpu);
2122dd285b06SPaolo Bonzini 
2123dd285b06SPaolo Bonzini     s->dma = pxa27x_dma_init(0x40000000,
2124dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
2125dd285b06SPaolo Bonzini 
2126dd285b06SPaolo Bonzini     sysbus_create_varargs("pxa27x-timer", 0x40a00000,
2127dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
2128dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
2129dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
2130dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
2131dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11),
2132dd285b06SPaolo Bonzini                     NULL);
2133dd285b06SPaolo Bonzini 
2134dd285b06SPaolo Bonzini     s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121);
2135dd285b06SPaolo Bonzini 
2136fa1d36dfSMarkus Armbruster     s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
2137dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
2138dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
2139dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
2140d7ebca74SPhilippe Mathieu-Daudé     dinfo = drive_get(IF_SD, 0, 0);
2141d7ebca74SPhilippe Mathieu-Daudé     if (dinfo) {
2142d7ebca74SPhilippe Mathieu-Daudé         DeviceState *carddev;
2143d7ebca74SPhilippe Mathieu-Daudé 
2144d7ebca74SPhilippe Mathieu-Daudé         /* Create and plug in the sd card */
2145d7ebca74SPhilippe Mathieu-Daudé         carddev = qdev_new(TYPE_SD_CARD);
2146d7ebca74SPhilippe Mathieu-Daudé         qdev_prop_set_drive_err(carddev, "drive",
2147d7ebca74SPhilippe Mathieu-Daudé                                 blk_by_legacy_dinfo(dinfo), &error_fatal);
2148d7ebca74SPhilippe Mathieu-Daudé         qdev_realize_and_unref(carddev, qdev_get_child_bus(DEVICE(s->mmc),
2149d7ebca74SPhilippe Mathieu-Daudé                                                            "sd-bus"),
2150d7ebca74SPhilippe Mathieu-Daudé                                &error_fatal);
2151d7ebca74SPhilippe Mathieu-Daudé     } else if (!qtest_enabled()) {
2152d7ebca74SPhilippe Mathieu-Daudé         warn_report("missing SecureDigital device");
2153d7ebca74SPhilippe Mathieu-Daudé     }
2154dd285b06SPaolo Bonzini 
2155dd285b06SPaolo Bonzini     for (i = 0; pxa270_serial[i].io_base; i++) {
21569bca0edbSPeter Maydell         if (serial_hd(i)) {
2157dd285b06SPaolo Bonzini             serial_mm_init(address_space, pxa270_serial[i].io_base, 2,
2158dd285b06SPaolo Bonzini                            qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
21599bca0edbSPeter Maydell                            14857000 / 16, serial_hd(i),
2160dd285b06SPaolo Bonzini                            DEVICE_NATIVE_ENDIAN);
2161dd285b06SPaolo Bonzini         } else {
2162dd285b06SPaolo Bonzini             break;
2163dd285b06SPaolo Bonzini         }
2164dd285b06SPaolo Bonzini     }
21659bca0edbSPeter Maydell     if (serial_hd(i))
2166dd285b06SPaolo Bonzini         s->fir = pxa2xx_fir_init(address_space, 0x40800000,
2167dd285b06SPaolo Bonzini                         qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
2168dd285b06SPaolo Bonzini                         qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
2169dd285b06SPaolo Bonzini                         qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
21709bca0edbSPeter Maydell                         serial_hd(i));
2171dd285b06SPaolo Bonzini 
2172dd285b06SPaolo Bonzini     s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000,
2173dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
2174dd285b06SPaolo Bonzini 
2175dd285b06SPaolo Bonzini     s->cm_base = 0x41300000;
2176dd285b06SPaolo Bonzini     s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
2177dd285b06SPaolo Bonzini     s->clkcfg = 0x00000009;		/* Turbo mode active */
21782c9b15caSPaolo Bonzini     memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
2179dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
2180dd285b06SPaolo Bonzini     vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
2181dd285b06SPaolo Bonzini 
2182dd285b06SPaolo Bonzini     pxa2xx_setup_cp14(s);
2183dd285b06SPaolo Bonzini 
2184dd285b06SPaolo Bonzini     s->mm_base = 0x48000000;
2185dd285b06SPaolo Bonzini     s->mm_regs[MDMRS >> 2] = 0x00020002;
2186dd285b06SPaolo Bonzini     s->mm_regs[MDREFR >> 2] = 0x03ca4000;
2187dd285b06SPaolo Bonzini     s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
21882c9b15caSPaolo Bonzini     memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
2189dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
2190dd285b06SPaolo Bonzini     vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
2191dd285b06SPaolo Bonzini 
2192dd285b06SPaolo Bonzini     s->pm_base = 0x40f00000;
21932c9b15caSPaolo Bonzini     memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
2194dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
2195dd285b06SPaolo Bonzini     vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
2196dd285b06SPaolo Bonzini 
2197dd285b06SPaolo Bonzini     for (i = 0; pxa27x_ssp[i].io_base; i ++);
2198b45c03f5SMarkus Armbruster     s->ssp = g_new0(SSIBus *, i);
2199dd285b06SPaolo Bonzini     for (i = 0; pxa27x_ssp[i].io_base; i ++) {
2200dd285b06SPaolo Bonzini         DeviceState *dev;
220112a82804SAndreas Färber         dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base,
2202dd285b06SPaolo Bonzini                         qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn));
2203dd285b06SPaolo Bonzini         s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
2204dd285b06SPaolo Bonzini     }
2205dd285b06SPaolo Bonzini 
2206dd285b06SPaolo Bonzini     sysbus_create_simple("sysbus-ohci", 0x4c000000,
2207dd285b06SPaolo Bonzini                          qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
2208dd285b06SPaolo Bonzini 
2209cbf08c18SPhilippe Mathieu-Daudé     s->pcmcia[0] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
2210cbf08c18SPhilippe Mathieu-Daudé                                                       0x20000000, NULL));
2211cbf08c18SPhilippe Mathieu-Daudé     s->pcmcia[1] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
2212cbf08c18SPhilippe Mathieu-Daudé                                                       0x30000000, NULL));
2213dd285b06SPaolo Bonzini 
2214548c6f18SAndreas Färber     sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000,
2215dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
2216dd285b06SPaolo Bonzini 
2217dd285b06SPaolo Bonzini     s->i2c[0] = pxa2xx_i2c_init(0x40301600,
2218dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
2219dd285b06SPaolo Bonzini     s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
2220dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
2221dd285b06SPaolo Bonzini 
2222dd285b06SPaolo Bonzini     s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
2223dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
2224dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
2225dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
2226dd285b06SPaolo Bonzini 
2227dd285b06SPaolo Bonzini     s->kp = pxa27x_keypad_init(address_space, 0x41500000,
2228dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD));
2229dd285b06SPaolo Bonzini 
2230dd285b06SPaolo Bonzini     /* GPIO1 resets the processor */
2231dd285b06SPaolo Bonzini     /* The handler can be overridden by board-specific code */
2232dd285b06SPaolo Bonzini     qdev_connect_gpio_out(s->gpio, 1, s->reset);
2233dd285b06SPaolo Bonzini     return s;
2234dd285b06SPaolo Bonzini }
2235dd285b06SPaolo Bonzini 
2236dd285b06SPaolo Bonzini /* Initialise a PXA255 integrated chip (ARM based core).  */
pxa255_init(unsigned int sdram_size)2237abf8361cSPhilippe Mathieu-Daudé PXA2xxState *pxa255_init(unsigned int sdram_size)
2238dd285b06SPaolo Bonzini {
2239abf8361cSPhilippe Mathieu-Daudé     MemoryRegion *address_space = get_system_memory();
2240dd285b06SPaolo Bonzini     PXA2xxState *s;
2241dd285b06SPaolo Bonzini     int i;
2242dd285b06SPaolo Bonzini     DriveInfo *dinfo;
2243dd285b06SPaolo Bonzini 
2244b45c03f5SMarkus Armbruster     s = g_new0(PXA2xxState, 1);
2245dd285b06SPaolo Bonzini 
2246ba1ba5ccSIgor Mammedov     s->cpu = ARM_CPU(cpu_create(ARM_CPU_TYPE_NAME("pxa255")));
2247f3c7d038SAndreas Färber     s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
2248dd285b06SPaolo Bonzini 
2249dd285b06SPaolo Bonzini     /* SDRAM & Internal Memory Storage */
225098a99ce0SPeter Maydell     memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size,
2251f8ed85acSMarkus Armbruster                            &error_fatal);
2252dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
225398a99ce0SPeter Maydell     memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
2254f8ed85acSMarkus Armbruster                            PXA2XX_INTERNAL_SIZE, &error_fatal);
2255dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
2256dd285b06SPaolo Bonzini                                 &s->internal);
2257dd285b06SPaolo Bonzini 
2258dd285b06SPaolo Bonzini     s->pic = pxa2xx_pic_init(0x40d00000, s->cpu);
2259dd285b06SPaolo Bonzini 
2260dd285b06SPaolo Bonzini     s->dma = pxa255_dma_init(0x40000000,
2261dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
2262dd285b06SPaolo Bonzini 
2263dd285b06SPaolo Bonzini     sysbus_create_varargs("pxa25x-timer", 0x40a00000,
2264dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
2265dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
2266dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
2267dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
2268dd285b06SPaolo Bonzini                     NULL);
2269dd285b06SPaolo Bonzini 
2270dd285b06SPaolo Bonzini     s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85);
2271dd285b06SPaolo Bonzini 
2272fa1d36dfSMarkus Armbruster     s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
2273dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
2274dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
2275dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
2276d7ebca74SPhilippe Mathieu-Daudé     dinfo = drive_get(IF_SD, 0, 0);
2277d7ebca74SPhilippe Mathieu-Daudé     if (dinfo) {
2278d7ebca74SPhilippe Mathieu-Daudé         DeviceState *carddev;
2279d7ebca74SPhilippe Mathieu-Daudé 
2280d7ebca74SPhilippe Mathieu-Daudé         /* Create and plug in the sd card */
2281d7ebca74SPhilippe Mathieu-Daudé         carddev = qdev_new(TYPE_SD_CARD);
2282d7ebca74SPhilippe Mathieu-Daudé         qdev_prop_set_drive_err(carddev, "drive",
2283d7ebca74SPhilippe Mathieu-Daudé                                 blk_by_legacy_dinfo(dinfo), &error_fatal);
2284d7ebca74SPhilippe Mathieu-Daudé         qdev_realize_and_unref(carddev, qdev_get_child_bus(DEVICE(s->mmc),
2285d7ebca74SPhilippe Mathieu-Daudé                                                            "sd-bus"),
2286d7ebca74SPhilippe Mathieu-Daudé                                &error_fatal);
2287d7ebca74SPhilippe Mathieu-Daudé     } else if (!qtest_enabled()) {
2288d7ebca74SPhilippe Mathieu-Daudé         warn_report("missing SecureDigital device");
2289d7ebca74SPhilippe Mathieu-Daudé     }
2290dd285b06SPaolo Bonzini 
2291dd285b06SPaolo Bonzini     for (i = 0; pxa255_serial[i].io_base; i++) {
22929bca0edbSPeter Maydell         if (serial_hd(i)) {
2293dd285b06SPaolo Bonzini             serial_mm_init(address_space, pxa255_serial[i].io_base, 2,
2294dd285b06SPaolo Bonzini                            qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
22959bca0edbSPeter Maydell                            14745600 / 16, serial_hd(i),
2296dd285b06SPaolo Bonzini                            DEVICE_NATIVE_ENDIAN);
2297dd285b06SPaolo Bonzini         } else {
2298dd285b06SPaolo Bonzini             break;
2299dd285b06SPaolo Bonzini         }
2300dd285b06SPaolo Bonzini     }
23019bca0edbSPeter Maydell     if (serial_hd(i))
2302dd285b06SPaolo Bonzini         s->fir = pxa2xx_fir_init(address_space, 0x40800000,
2303dd285b06SPaolo Bonzini                         qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
2304dd285b06SPaolo Bonzini                         qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
2305dd285b06SPaolo Bonzini                         qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
23069bca0edbSPeter Maydell                         serial_hd(i));
2307dd285b06SPaolo Bonzini 
2308dd285b06SPaolo Bonzini     s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000,
2309dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
2310dd285b06SPaolo Bonzini 
2311dd285b06SPaolo Bonzini     s->cm_base = 0x41300000;
2312e9aff986SGuenter Roeck     s->cm_regs[CCCR >> 2] = 0x00000121;         /* from datasheet */
2313e9aff986SGuenter Roeck     s->cm_regs[CKEN >> 2] = 0x00017def;         /* from datasheet */
2314e9aff986SGuenter Roeck 
2315dd285b06SPaolo Bonzini     s->clkcfg = 0x00000009;		/* Turbo mode active */
23162c9b15caSPaolo Bonzini     memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
2317dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
2318dd285b06SPaolo Bonzini     vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
2319dd285b06SPaolo Bonzini 
2320dd285b06SPaolo Bonzini     pxa2xx_setup_cp14(s);
2321dd285b06SPaolo Bonzini 
2322dd285b06SPaolo Bonzini     s->mm_base = 0x48000000;
2323dd285b06SPaolo Bonzini     s->mm_regs[MDMRS >> 2] = 0x00020002;
2324dd285b06SPaolo Bonzini     s->mm_regs[MDREFR >> 2] = 0x03ca4000;
2325dd285b06SPaolo Bonzini     s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
23262c9b15caSPaolo Bonzini     memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
2327dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
2328dd285b06SPaolo Bonzini     vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
2329dd285b06SPaolo Bonzini 
2330dd285b06SPaolo Bonzini     s->pm_base = 0x40f00000;
23312c9b15caSPaolo Bonzini     memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
2332dd285b06SPaolo Bonzini     memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
2333dd285b06SPaolo Bonzini     vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
2334dd285b06SPaolo Bonzini 
2335dd285b06SPaolo Bonzini     for (i = 0; pxa255_ssp[i].io_base; i ++);
2336b45c03f5SMarkus Armbruster     s->ssp = g_new0(SSIBus *, i);
2337dd285b06SPaolo Bonzini     for (i = 0; pxa255_ssp[i].io_base; i ++) {
2338dd285b06SPaolo Bonzini         DeviceState *dev;
233912a82804SAndreas Färber         dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base,
2340dd285b06SPaolo Bonzini                         qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn));
2341dd285b06SPaolo Bonzini         s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
2342dd285b06SPaolo Bonzini     }
2343dd285b06SPaolo Bonzini 
2344cbf08c18SPhilippe Mathieu-Daudé     s->pcmcia[0] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
2345cbf08c18SPhilippe Mathieu-Daudé                                                       0x20000000, NULL));
2346cbf08c18SPhilippe Mathieu-Daudé     s->pcmcia[1] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
2347cbf08c18SPhilippe Mathieu-Daudé                                                       0x30000000, NULL));
2348dd285b06SPaolo Bonzini 
2349548c6f18SAndreas Färber     sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000,
2350dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
2351dd285b06SPaolo Bonzini 
2352dd285b06SPaolo Bonzini     s->i2c[0] = pxa2xx_i2c_init(0x40301600,
2353dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
2354dd285b06SPaolo Bonzini     s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
2355dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
2356dd285b06SPaolo Bonzini 
2357dd285b06SPaolo Bonzini     s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
2358dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
2359dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
2360dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
2361dd285b06SPaolo Bonzini 
2362dd285b06SPaolo Bonzini     /* GPIO1 resets the processor */
2363dd285b06SPaolo Bonzini     /* The handler can be overridden by board-specific code */
2364dd285b06SPaolo Bonzini     qdev_connect_gpio_out(s->gpio, 1, s->reset);
2365dd285b06SPaolo Bonzini     return s;
2366dd285b06SPaolo Bonzini }
2367dd285b06SPaolo Bonzini 
pxa2xx_ssp_class_init(ObjectClass * klass,void * data)2368dd285b06SPaolo Bonzini static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
2369dd285b06SPaolo Bonzini {
2370ce320346SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
2371dd285b06SPaolo Bonzini 
2372ce320346SPeter Maydell     dc->reset = pxa2xx_ssp_reset;
23738e079cafSPeter Maydell     dc->vmsd = &vmstate_pxa2xx_ssp;
2374dd285b06SPaolo Bonzini }
2375dd285b06SPaolo Bonzini 
2376dd285b06SPaolo Bonzini static const TypeInfo pxa2xx_ssp_info = {
237712a82804SAndreas Färber     .name          = TYPE_PXA2XX_SSP,
2378dd285b06SPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
2379dd285b06SPaolo Bonzini     .instance_size = sizeof(PXA2xxSSPState),
23800493a139SSuramya Shah     .instance_init = pxa2xx_ssp_init,
2381dd285b06SPaolo Bonzini     .class_init    = pxa2xx_ssp_class_init,
2382dd285b06SPaolo Bonzini };
2383dd285b06SPaolo Bonzini 
pxa2xx_register_types(void)2384dd285b06SPaolo Bonzini static void pxa2xx_register_types(void)
2385dd285b06SPaolo Bonzini {
2386dd285b06SPaolo Bonzini     type_register_static(&pxa2xx_i2c_slave_info);
2387dd285b06SPaolo Bonzini     type_register_static(&pxa2xx_ssp_info);
2388dd285b06SPaolo Bonzini     type_register_static(&pxa2xx_i2c_info);
2389dd285b06SPaolo Bonzini     type_register_static(&pxa2xx_rtc_sysbus_info);
23901fd9f2dfSPeter Maydell     type_register_static(&pxa2xx_fir_info);
2391dd285b06SPaolo Bonzini }
2392dd285b06SPaolo Bonzini 
2393dd285b06SPaolo Bonzini type_init(pxa2xx_register_types)
2394