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