1aacf8895SPaolo Bonzini /*
2aacf8895SPaolo Bonzini * StrongARM SA-1100/SA-1110 emulation
3aacf8895SPaolo Bonzini *
4aacf8895SPaolo Bonzini * Copyright (C) 2011 Dmitry Eremin-Solenikov
5aacf8895SPaolo Bonzini *
6aacf8895SPaolo Bonzini * Largely based on StrongARM emulation:
7aacf8895SPaolo Bonzini * Copyright (c) 2006 Openedhand Ltd.
8aacf8895SPaolo Bonzini * Written by Andrzej Zaborowski <balrog@zabor.org>
9aacf8895SPaolo Bonzini *
10aacf8895SPaolo Bonzini * UART code based on QEMU 16550A UART emulation
11aacf8895SPaolo Bonzini * Copyright (c) 2003-2004 Fabrice Bellard
12aacf8895SPaolo Bonzini * Copyright (c) 2008 Citrix Systems, Inc.
13aacf8895SPaolo Bonzini *
14aacf8895SPaolo Bonzini * This program is free software; you can redistribute it and/or modify
15aacf8895SPaolo Bonzini * it under the terms of the GNU General Public License version 2 as
16aacf8895SPaolo Bonzini * published by the Free Software Foundation.
17aacf8895SPaolo Bonzini *
18aacf8895SPaolo Bonzini * This program is distributed in the hope that it will be useful,
19aacf8895SPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
20aacf8895SPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21aacf8895SPaolo Bonzini * GNU General Public License for more details.
22aacf8895SPaolo Bonzini *
23aacf8895SPaolo Bonzini * You should have received a copy of the GNU General Public License along
24aacf8895SPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>.
25aacf8895SPaolo Bonzini *
26aacf8895SPaolo Bonzini * Contributions after 2012-01-13 are licensed under the terms of the
27aacf8895SPaolo Bonzini * GNU GPL, version 2 or (at your option) any later version.
28aacf8895SPaolo Bonzini */
29c8623c02SDirk Müller
3012b16722SPeter Maydell #include "qemu/osdep.h"
3164552b6bSMarkus Armbruster #include "hw/irq.h"
32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
33ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
34aacf8895SPaolo Bonzini #include "hw/sysbus.h"
35d6454270SMarkus Armbruster #include "migration/vmstate.h"
3647b43a1fSPaolo Bonzini #include "strongarm.h"
37aacf8895SPaolo Bonzini #include "qemu/error-report.h"
3812ec8bd5SPeter Maydell #include "hw/arm/boot.h"
394d43a603SMarc-André Lureau #include "chardev/char-fe.h"
407566c6efSMarc-André Lureau #include "chardev/char-serial.h"
41aacf8895SPaolo Bonzini #include "sysemu/sysemu.h"
422f93d8b0SPeter Maydell #include "sysemu/rtc.h"
438fd06719SAlistair Francis #include "hw/ssi/ssi.h"
443e80f690SMarkus Armbruster #include "qapi/error.h"
45f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
4603dd024fSPaolo Bonzini #include "qemu/log.h"
47db1015e9SEduardo Habkost #include "qom/object.h"
48d780d056SPhilippe Mathieu-Daudé #include "target/arm/cpu-qom.h"
495e5deca1SManos Pitsidianakis #include "trace.h"
50aacf8895SPaolo Bonzini
51aacf8895SPaolo Bonzini /*
52aacf8895SPaolo Bonzini TODO
53aacf8895SPaolo Bonzini - Implement cp15, c14 ?
54aacf8895SPaolo Bonzini - Implement cp15, c15 !!! (idle used in L)
55aacf8895SPaolo Bonzini - Implement idle mode handling/DIM
56aacf8895SPaolo Bonzini - Implement sleep mode/Wake sources
57aacf8895SPaolo Bonzini - Implement reset control
58aacf8895SPaolo Bonzini - Implement memory control regs
59aacf8895SPaolo Bonzini - PCMCIA handling
60aacf8895SPaolo Bonzini - Maybe support MBGNT/MBREQ
61aacf8895SPaolo Bonzini - DMA channels
62aacf8895SPaolo Bonzini - GPCLK
63aacf8895SPaolo Bonzini - IrDA
64aacf8895SPaolo Bonzini - MCP
65aacf8895SPaolo Bonzini - Enhance UART with modem signals
66aacf8895SPaolo Bonzini */
67aacf8895SPaolo Bonzini
68aacf8895SPaolo Bonzini static struct {
69aacf8895SPaolo Bonzini hwaddr io_base;
70aacf8895SPaolo Bonzini int irq;
71aacf8895SPaolo Bonzini } sa_serial[] = {
72aacf8895SPaolo Bonzini { 0x80010000, SA_PIC_UART1 },
73aacf8895SPaolo Bonzini { 0x80030000, SA_PIC_UART2 },
74aacf8895SPaolo Bonzini { 0x80050000, SA_PIC_UART3 },
75aacf8895SPaolo Bonzini { 0, 0 }
76aacf8895SPaolo Bonzini };
77aacf8895SPaolo Bonzini
78aacf8895SPaolo Bonzini /* Interrupt Controller */
7974e075f6SAndreas Färber
8074e075f6SAndreas Färber #define TYPE_STRONGARM_PIC "strongarm_pic"
818063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(StrongARMPICState, STRONGARM_PIC)
8274e075f6SAndreas Färber
83db1015e9SEduardo Habkost struct StrongARMPICState {
8474e075f6SAndreas Färber SysBusDevice parent_obj;
8574e075f6SAndreas Färber
86aacf8895SPaolo Bonzini MemoryRegion iomem;
87aacf8895SPaolo Bonzini qemu_irq irq;
88aacf8895SPaolo Bonzini qemu_irq fiq;
89aacf8895SPaolo Bonzini
90aacf8895SPaolo Bonzini uint32_t pending;
91aacf8895SPaolo Bonzini uint32_t enabled;
92aacf8895SPaolo Bonzini uint32_t is_fiq;
93aacf8895SPaolo Bonzini uint32_t int_idle;
94db1015e9SEduardo Habkost };
95aacf8895SPaolo Bonzini
96aacf8895SPaolo Bonzini #define ICIP 0x00
97aacf8895SPaolo Bonzini #define ICMR 0x04
98aacf8895SPaolo Bonzini #define ICLR 0x08
99aacf8895SPaolo Bonzini #define ICFP 0x10
100aacf8895SPaolo Bonzini #define ICPR 0x20
101aacf8895SPaolo Bonzini #define ICCR 0x0c
102aacf8895SPaolo Bonzini
103aacf8895SPaolo Bonzini #define SA_PIC_SRCS 32
104aacf8895SPaolo Bonzini
105aacf8895SPaolo Bonzini
strongarm_pic_update(void * opaque)106aacf8895SPaolo Bonzini static void strongarm_pic_update(void *opaque)
107aacf8895SPaolo Bonzini {
108aacf8895SPaolo Bonzini StrongARMPICState *s = opaque;
109aacf8895SPaolo Bonzini
110aacf8895SPaolo Bonzini /* FIXME: reflect DIM */
111aacf8895SPaolo Bonzini qemu_set_irq(s->fiq, s->pending & s->enabled & s->is_fiq);
112aacf8895SPaolo Bonzini qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq);
113aacf8895SPaolo Bonzini }
114aacf8895SPaolo Bonzini
strongarm_pic_set_irq(void * opaque,int irq,int level)115aacf8895SPaolo Bonzini static void strongarm_pic_set_irq(void *opaque, int irq, int level)
116aacf8895SPaolo Bonzini {
117aacf8895SPaolo Bonzini StrongARMPICState *s = opaque;
118aacf8895SPaolo Bonzini
119aacf8895SPaolo Bonzini if (level) {
120aacf8895SPaolo Bonzini s->pending |= 1 << irq;
121aacf8895SPaolo Bonzini } else {
122aacf8895SPaolo Bonzini s->pending &= ~(1 << irq);
123aacf8895SPaolo Bonzini }
124aacf8895SPaolo Bonzini
125aacf8895SPaolo Bonzini strongarm_pic_update(s);
126aacf8895SPaolo Bonzini }
127aacf8895SPaolo Bonzini
strongarm_pic_mem_read(void * opaque,hwaddr offset,unsigned size)128aacf8895SPaolo Bonzini static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset,
129aacf8895SPaolo Bonzini unsigned size)
130aacf8895SPaolo Bonzini {
131aacf8895SPaolo Bonzini StrongARMPICState *s = opaque;
132aacf8895SPaolo Bonzini
133aacf8895SPaolo Bonzini switch (offset) {
134aacf8895SPaolo Bonzini case ICIP:
135aacf8895SPaolo Bonzini return s->pending & ~s->is_fiq & s->enabled;
136aacf8895SPaolo Bonzini case ICMR:
137aacf8895SPaolo Bonzini return s->enabled;
138aacf8895SPaolo Bonzini case ICLR:
139aacf8895SPaolo Bonzini return s->is_fiq;
140aacf8895SPaolo Bonzini case ICCR:
141aacf8895SPaolo Bonzini return s->int_idle == 0;
142aacf8895SPaolo Bonzini case ICFP:
143aacf8895SPaolo Bonzini return s->pending & s->is_fiq & s->enabled;
144aacf8895SPaolo Bonzini case ICPR:
145aacf8895SPaolo Bonzini return s->pending;
146aacf8895SPaolo Bonzini default:
1475e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
1485e5deca1SManos Pitsidianakis "%s: Bad register offset 0x"HWADDR_FMT_plx"\n",
149aacf8895SPaolo Bonzini __func__, offset);
150aacf8895SPaolo Bonzini return 0;
151aacf8895SPaolo Bonzini }
152aacf8895SPaolo Bonzini }
153aacf8895SPaolo Bonzini
strongarm_pic_mem_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)154aacf8895SPaolo Bonzini static void strongarm_pic_mem_write(void *opaque, hwaddr offset,
155aacf8895SPaolo Bonzini uint64_t value, unsigned size)
156aacf8895SPaolo Bonzini {
157aacf8895SPaolo Bonzini StrongARMPICState *s = opaque;
158aacf8895SPaolo Bonzini
159aacf8895SPaolo Bonzini switch (offset) {
160aacf8895SPaolo Bonzini case ICMR:
161aacf8895SPaolo Bonzini s->enabled = value;
162aacf8895SPaolo Bonzini break;
163aacf8895SPaolo Bonzini case ICLR:
164aacf8895SPaolo Bonzini s->is_fiq = value;
165aacf8895SPaolo Bonzini break;
166aacf8895SPaolo Bonzini case ICCR:
167aacf8895SPaolo Bonzini s->int_idle = (value & 1) ? 0 : ~0;
168aacf8895SPaolo Bonzini break;
169aacf8895SPaolo Bonzini default:
1705e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
1715e5deca1SManos Pitsidianakis "%s: Bad register offset 0x"HWADDR_FMT_plx"\n",
172aacf8895SPaolo Bonzini __func__, offset);
173aacf8895SPaolo Bonzini break;
174aacf8895SPaolo Bonzini }
175aacf8895SPaolo Bonzini strongarm_pic_update(s);
176aacf8895SPaolo Bonzini }
177aacf8895SPaolo Bonzini
178aacf8895SPaolo Bonzini static const MemoryRegionOps strongarm_pic_ops = {
179aacf8895SPaolo Bonzini .read = strongarm_pic_mem_read,
180aacf8895SPaolo Bonzini .write = strongarm_pic_mem_write,
181aacf8895SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
182aacf8895SPaolo Bonzini };
183aacf8895SPaolo Bonzini
strongarm_pic_initfn(Object * obj)1845a67508cSxiaoqiang.zhao static void strongarm_pic_initfn(Object *obj)
185aacf8895SPaolo Bonzini {
1865a67508cSxiaoqiang.zhao DeviceState *dev = DEVICE(obj);
1875a67508cSxiaoqiang.zhao StrongARMPICState *s = STRONGARM_PIC(obj);
1885a67508cSxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
189aacf8895SPaolo Bonzini
19074e075f6SAndreas Färber qdev_init_gpio_in(dev, strongarm_pic_set_irq, SA_PIC_SRCS);
1915a67508cSxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &strongarm_pic_ops, s,
19264bde0f3SPaolo Bonzini "pic", 0x1000);
19374e075f6SAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
19474e075f6SAndreas Färber sysbus_init_irq(sbd, &s->irq);
19574e075f6SAndreas Färber sysbus_init_irq(sbd, &s->fiq);
196aacf8895SPaolo Bonzini }
197aacf8895SPaolo Bonzini
strongarm_pic_post_load(void * opaque,int version_id)198aacf8895SPaolo Bonzini static int strongarm_pic_post_load(void *opaque, int version_id)
199aacf8895SPaolo Bonzini {
200aacf8895SPaolo Bonzini strongarm_pic_update(opaque);
201aacf8895SPaolo Bonzini return 0;
202aacf8895SPaolo Bonzini }
203aacf8895SPaolo Bonzini
204cfa52e09SPhilippe Mathieu-Daudé static const VMStateDescription vmstate_strongarm_pic_regs = {
205aacf8895SPaolo Bonzini .name = "strongarm_pic",
206aacf8895SPaolo Bonzini .version_id = 0,
207aacf8895SPaolo Bonzini .minimum_version_id = 0,
208aacf8895SPaolo Bonzini .post_load = strongarm_pic_post_load,
209607ef570SRichard Henderson .fields = (const VMStateField[]) {
210aacf8895SPaolo Bonzini VMSTATE_UINT32(pending, StrongARMPICState),
211aacf8895SPaolo Bonzini VMSTATE_UINT32(enabled, StrongARMPICState),
212aacf8895SPaolo Bonzini VMSTATE_UINT32(is_fiq, StrongARMPICState),
213aacf8895SPaolo Bonzini VMSTATE_UINT32(int_idle, StrongARMPICState),
214aacf8895SPaolo Bonzini VMSTATE_END_OF_LIST(),
215aacf8895SPaolo Bonzini },
216aacf8895SPaolo Bonzini };
217aacf8895SPaolo Bonzini
strongarm_pic_class_init(ObjectClass * klass,void * data)218aacf8895SPaolo Bonzini static void strongarm_pic_class_init(ObjectClass *klass, void *data)
219aacf8895SPaolo Bonzini {
220aacf8895SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
221aacf8895SPaolo Bonzini
222aacf8895SPaolo Bonzini dc->desc = "StrongARM PIC";
223aacf8895SPaolo Bonzini dc->vmsd = &vmstate_strongarm_pic_regs;
224aacf8895SPaolo Bonzini }
225aacf8895SPaolo Bonzini
226aacf8895SPaolo Bonzini static const TypeInfo strongarm_pic_info = {
22774e075f6SAndreas Färber .name = TYPE_STRONGARM_PIC,
228aacf8895SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
229aacf8895SPaolo Bonzini .instance_size = sizeof(StrongARMPICState),
2305a67508cSxiaoqiang.zhao .instance_init = strongarm_pic_initfn,
231aacf8895SPaolo Bonzini .class_init = strongarm_pic_class_init,
232aacf8895SPaolo Bonzini };
233aacf8895SPaolo Bonzini
234aacf8895SPaolo Bonzini /* Real-Time Clock */
235aacf8895SPaolo Bonzini #define RTAR 0x00 /* RTC Alarm register */
236aacf8895SPaolo Bonzini #define RCNR 0x04 /* RTC Counter register */
237aacf8895SPaolo Bonzini #define RTTR 0x08 /* RTC Timer Trim register */
238aacf8895SPaolo Bonzini #define RTSR 0x10 /* RTC Status register */
239aacf8895SPaolo Bonzini
240aacf8895SPaolo Bonzini #define RTSR_AL (1 << 0) /* RTC Alarm detected */
241aacf8895SPaolo Bonzini #define RTSR_HZ (1 << 1) /* RTC 1Hz detected */
242aacf8895SPaolo Bonzini #define RTSR_ALE (1 << 2) /* RTC Alarm enable */
243aacf8895SPaolo Bonzini #define RTSR_HZE (1 << 3) /* RTC 1Hz enable */
244aacf8895SPaolo Bonzini
245aacf8895SPaolo Bonzini /* 16 LSB of RTTR are clockdiv for internal trim logic,
246aacf8895SPaolo Bonzini * trim delete isn't emulated, so
247aacf8895SPaolo Bonzini * f = 32 768 / (RTTR_trim + 1) */
248aacf8895SPaolo Bonzini
2494e002105SAndreas Färber #define TYPE_STRONGARM_RTC "strongarm-rtc"
2508063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(StrongARMRTCState, STRONGARM_RTC)
2514e002105SAndreas Färber
252db1015e9SEduardo Habkost struct StrongARMRTCState {
2534e002105SAndreas Färber SysBusDevice parent_obj;
2544e002105SAndreas Färber
255aacf8895SPaolo Bonzini MemoryRegion iomem;
256aacf8895SPaolo Bonzini uint32_t rttr;
257aacf8895SPaolo Bonzini uint32_t rtsr;
258aacf8895SPaolo Bonzini uint32_t rtar;
259aacf8895SPaolo Bonzini uint32_t last_rcnr;
260aacf8895SPaolo Bonzini int64_t last_hz;
261aacf8895SPaolo Bonzini QEMUTimer *rtc_alarm;
262aacf8895SPaolo Bonzini QEMUTimer *rtc_hz;
263aacf8895SPaolo Bonzini qemu_irq rtc_irq;
264aacf8895SPaolo Bonzini qemu_irq rtc_hz_irq;
265db1015e9SEduardo Habkost };
266aacf8895SPaolo Bonzini
strongarm_rtc_int_update(StrongARMRTCState * s)267aacf8895SPaolo Bonzini static inline void strongarm_rtc_int_update(StrongARMRTCState *s)
268aacf8895SPaolo Bonzini {
269aacf8895SPaolo Bonzini qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL);
270aacf8895SPaolo Bonzini qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ);
271aacf8895SPaolo Bonzini }
272aacf8895SPaolo Bonzini
strongarm_rtc_hzupdate(StrongARMRTCState * s)273aacf8895SPaolo Bonzini static void strongarm_rtc_hzupdate(StrongARMRTCState *s)
274aacf8895SPaolo Bonzini {
275884f17c2SAlex Bligh int64_t rt = qemu_clock_get_ms(rtc_clock);
276aacf8895SPaolo Bonzini s->last_rcnr += ((rt - s->last_hz) << 15) /
277aacf8895SPaolo Bonzini (1000 * ((s->rttr & 0xffff) + 1));
278aacf8895SPaolo Bonzini s->last_hz = rt;
279aacf8895SPaolo Bonzini }
280aacf8895SPaolo Bonzini
strongarm_rtc_timer_update(StrongARMRTCState * s)281aacf8895SPaolo Bonzini static inline void strongarm_rtc_timer_update(StrongARMRTCState *s)
282aacf8895SPaolo Bonzini {
283aacf8895SPaolo Bonzini if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) {
284bc72ad67SAlex Bligh timer_mod(s->rtc_hz, s->last_hz + 1000);
285aacf8895SPaolo Bonzini } else {
286bc72ad67SAlex Bligh timer_del(s->rtc_hz);
287aacf8895SPaolo Bonzini }
288aacf8895SPaolo Bonzini
289aacf8895SPaolo Bonzini if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) {
290bc72ad67SAlex Bligh timer_mod(s->rtc_alarm, s->last_hz +
291aacf8895SPaolo Bonzini (((s->rtar - s->last_rcnr) * 1000 *
292aacf8895SPaolo Bonzini ((s->rttr & 0xffff) + 1)) >> 15));
293aacf8895SPaolo Bonzini } else {
294bc72ad67SAlex Bligh timer_del(s->rtc_alarm);
295aacf8895SPaolo Bonzini }
296aacf8895SPaolo Bonzini }
297aacf8895SPaolo Bonzini
strongarm_rtc_alarm_tick(void * opaque)298aacf8895SPaolo Bonzini static inline void strongarm_rtc_alarm_tick(void *opaque)
299aacf8895SPaolo Bonzini {
300aacf8895SPaolo Bonzini StrongARMRTCState *s = opaque;
301aacf8895SPaolo Bonzini s->rtsr |= RTSR_AL;
302aacf8895SPaolo Bonzini strongarm_rtc_timer_update(s);
303aacf8895SPaolo Bonzini strongarm_rtc_int_update(s);
304aacf8895SPaolo Bonzini }
305aacf8895SPaolo Bonzini
strongarm_rtc_hz_tick(void * opaque)306aacf8895SPaolo Bonzini static inline void strongarm_rtc_hz_tick(void *opaque)
307aacf8895SPaolo Bonzini {
308aacf8895SPaolo Bonzini StrongARMRTCState *s = opaque;
309aacf8895SPaolo Bonzini s->rtsr |= RTSR_HZ;
310aacf8895SPaolo Bonzini strongarm_rtc_timer_update(s);
311aacf8895SPaolo Bonzini strongarm_rtc_int_update(s);
312aacf8895SPaolo Bonzini }
313aacf8895SPaolo Bonzini
strongarm_rtc_read(void * opaque,hwaddr addr,unsigned size)314aacf8895SPaolo Bonzini static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr,
315aacf8895SPaolo Bonzini unsigned size)
316aacf8895SPaolo Bonzini {
317aacf8895SPaolo Bonzini StrongARMRTCState *s = opaque;
318aacf8895SPaolo Bonzini
319aacf8895SPaolo Bonzini switch (addr) {
320aacf8895SPaolo Bonzini case RTTR:
321aacf8895SPaolo Bonzini return s->rttr;
322aacf8895SPaolo Bonzini case RTSR:
323aacf8895SPaolo Bonzini return s->rtsr;
324aacf8895SPaolo Bonzini case RTAR:
325aacf8895SPaolo Bonzini return s->rtar;
326aacf8895SPaolo Bonzini case RCNR:
327aacf8895SPaolo Bonzini return s->last_rcnr +
328884f17c2SAlex Bligh ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
329aacf8895SPaolo Bonzini (1000 * ((s->rttr & 0xffff) + 1));
330aacf8895SPaolo Bonzini default:
3315e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
3325e5deca1SManos Pitsidianakis "%s: Bad rtc register read 0x"HWADDR_FMT_plx"\n",
3335e5deca1SManos Pitsidianakis __func__, addr);
334aacf8895SPaolo Bonzini return 0;
335aacf8895SPaolo Bonzini }
336aacf8895SPaolo Bonzini }
337aacf8895SPaolo Bonzini
strongarm_rtc_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)338aacf8895SPaolo Bonzini static void strongarm_rtc_write(void *opaque, hwaddr addr,
339aacf8895SPaolo Bonzini uint64_t value, unsigned size)
340aacf8895SPaolo Bonzini {
341aacf8895SPaolo Bonzini StrongARMRTCState *s = opaque;
342aacf8895SPaolo Bonzini uint32_t old_rtsr;
343aacf8895SPaolo Bonzini
344aacf8895SPaolo Bonzini switch (addr) {
345aacf8895SPaolo Bonzini case RTTR:
346aacf8895SPaolo Bonzini strongarm_rtc_hzupdate(s);
347aacf8895SPaolo Bonzini s->rttr = value;
348aacf8895SPaolo Bonzini strongarm_rtc_timer_update(s);
349aacf8895SPaolo Bonzini break;
350aacf8895SPaolo Bonzini
351aacf8895SPaolo Bonzini case RTSR:
352aacf8895SPaolo Bonzini old_rtsr = s->rtsr;
353aacf8895SPaolo Bonzini s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) |
354aacf8895SPaolo Bonzini (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ)));
355aacf8895SPaolo Bonzini
356aacf8895SPaolo Bonzini if (s->rtsr != old_rtsr) {
357aacf8895SPaolo Bonzini strongarm_rtc_timer_update(s);
358aacf8895SPaolo Bonzini }
359aacf8895SPaolo Bonzini
360aacf8895SPaolo Bonzini strongarm_rtc_int_update(s);
361aacf8895SPaolo Bonzini break;
362aacf8895SPaolo Bonzini
363aacf8895SPaolo Bonzini case RTAR:
364aacf8895SPaolo Bonzini s->rtar = value;
365aacf8895SPaolo Bonzini strongarm_rtc_timer_update(s);
366aacf8895SPaolo Bonzini break;
367aacf8895SPaolo Bonzini
368aacf8895SPaolo Bonzini case RCNR:
369aacf8895SPaolo Bonzini strongarm_rtc_hzupdate(s);
370aacf8895SPaolo Bonzini s->last_rcnr = value;
371aacf8895SPaolo Bonzini strongarm_rtc_timer_update(s);
372aacf8895SPaolo Bonzini break;
373aacf8895SPaolo Bonzini
374aacf8895SPaolo Bonzini default:
3755e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
3765e5deca1SManos Pitsidianakis "%s: Bad rtc register write 0x"HWADDR_FMT_plx"\n",
3775e5deca1SManos Pitsidianakis __func__, addr);
378aacf8895SPaolo Bonzini }
379aacf8895SPaolo Bonzini }
380aacf8895SPaolo Bonzini
381aacf8895SPaolo Bonzini static const MemoryRegionOps strongarm_rtc_ops = {
382aacf8895SPaolo Bonzini .read = strongarm_rtc_read,
383aacf8895SPaolo Bonzini .write = strongarm_rtc_write,
384aacf8895SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
385aacf8895SPaolo Bonzini };
386aacf8895SPaolo Bonzini
strongarm_rtc_init(Object * obj)3875a67508cSxiaoqiang.zhao static void strongarm_rtc_init(Object *obj)
388aacf8895SPaolo Bonzini {
3895a67508cSxiaoqiang.zhao StrongARMRTCState *s = STRONGARM_RTC(obj);
3905a67508cSxiaoqiang.zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj);
391aacf8895SPaolo Bonzini struct tm tm;
392aacf8895SPaolo Bonzini
393aacf8895SPaolo Bonzini s->rttr = 0x0;
394aacf8895SPaolo Bonzini s->rtsr = 0;
395aacf8895SPaolo Bonzini
396aacf8895SPaolo Bonzini qemu_get_timedate(&tm, 0);
397aacf8895SPaolo Bonzini
398aacf8895SPaolo Bonzini s->last_rcnr = (uint32_t) mktimegm(&tm);
399884f17c2SAlex Bligh s->last_hz = qemu_clock_get_ms(rtc_clock);
400aacf8895SPaolo Bonzini
401aacf8895SPaolo Bonzini sysbus_init_irq(dev, &s->rtc_irq);
402aacf8895SPaolo Bonzini sysbus_init_irq(dev, &s->rtc_hz_irq);
403aacf8895SPaolo Bonzini
4045a67508cSxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &strongarm_rtc_ops, s,
40564bde0f3SPaolo Bonzini "rtc", 0x10000);
406aacf8895SPaolo Bonzini sysbus_init_mmio(dev, &s->iomem);
407aacf8895SPaolo Bonzini }
408aacf8895SPaolo Bonzini
strongarm_rtc_realize(DeviceState * dev,Error ** errp)409efb27a49SPan Nengyuan static void strongarm_rtc_realize(DeviceState *dev, Error **errp)
410efb27a49SPan Nengyuan {
411efb27a49SPan Nengyuan StrongARMRTCState *s = STRONGARM_RTC(dev);
412efb27a49SPan Nengyuan s->rtc_alarm = timer_new_ms(rtc_clock, strongarm_rtc_alarm_tick, s);
413efb27a49SPan Nengyuan s->rtc_hz = timer_new_ms(rtc_clock, strongarm_rtc_hz_tick, s);
414efb27a49SPan Nengyuan }
415efb27a49SPan Nengyuan
strongarm_rtc_pre_save(void * opaque)41644b1ff31SDr. David Alan Gilbert static int strongarm_rtc_pre_save(void *opaque)
417aacf8895SPaolo Bonzini {
418aacf8895SPaolo Bonzini StrongARMRTCState *s = opaque;
419aacf8895SPaolo Bonzini
420aacf8895SPaolo Bonzini strongarm_rtc_hzupdate(s);
42144b1ff31SDr. David Alan Gilbert
42244b1ff31SDr. David Alan Gilbert return 0;
423aacf8895SPaolo Bonzini }
424aacf8895SPaolo Bonzini
strongarm_rtc_post_load(void * opaque,int version_id)425aacf8895SPaolo Bonzini static int strongarm_rtc_post_load(void *opaque, int version_id)
426aacf8895SPaolo Bonzini {
427aacf8895SPaolo Bonzini StrongARMRTCState *s = opaque;
428aacf8895SPaolo Bonzini
429aacf8895SPaolo Bonzini strongarm_rtc_timer_update(s);
430aacf8895SPaolo Bonzini strongarm_rtc_int_update(s);
431aacf8895SPaolo Bonzini
432aacf8895SPaolo Bonzini return 0;
433aacf8895SPaolo Bonzini }
434aacf8895SPaolo Bonzini
435aacf8895SPaolo Bonzini static const VMStateDescription vmstate_strongarm_rtc_regs = {
436aacf8895SPaolo Bonzini .name = "strongarm-rtc",
437aacf8895SPaolo Bonzini .version_id = 0,
438aacf8895SPaolo Bonzini .minimum_version_id = 0,
439aacf8895SPaolo Bonzini .pre_save = strongarm_rtc_pre_save,
440aacf8895SPaolo Bonzini .post_load = strongarm_rtc_post_load,
441607ef570SRichard Henderson .fields = (const VMStateField[]) {
442aacf8895SPaolo Bonzini VMSTATE_UINT32(rttr, StrongARMRTCState),
443aacf8895SPaolo Bonzini VMSTATE_UINT32(rtsr, StrongARMRTCState),
444aacf8895SPaolo Bonzini VMSTATE_UINT32(rtar, StrongARMRTCState),
445aacf8895SPaolo Bonzini VMSTATE_UINT32(last_rcnr, StrongARMRTCState),
446aacf8895SPaolo Bonzini VMSTATE_INT64(last_hz, StrongARMRTCState),
447aacf8895SPaolo Bonzini VMSTATE_END_OF_LIST(),
448aacf8895SPaolo Bonzini },
449aacf8895SPaolo Bonzini };
450aacf8895SPaolo Bonzini
strongarm_rtc_sysbus_class_init(ObjectClass * klass,void * data)451aacf8895SPaolo Bonzini static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data)
452aacf8895SPaolo Bonzini {
453aacf8895SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
454aacf8895SPaolo Bonzini
455aacf8895SPaolo Bonzini dc->desc = "StrongARM RTC Controller";
456aacf8895SPaolo Bonzini dc->vmsd = &vmstate_strongarm_rtc_regs;
457efb27a49SPan Nengyuan dc->realize = strongarm_rtc_realize;
458aacf8895SPaolo Bonzini }
459aacf8895SPaolo Bonzini
460aacf8895SPaolo Bonzini static const TypeInfo strongarm_rtc_sysbus_info = {
4614e002105SAndreas Färber .name = TYPE_STRONGARM_RTC,
462aacf8895SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
463aacf8895SPaolo Bonzini .instance_size = sizeof(StrongARMRTCState),
4645a67508cSxiaoqiang.zhao .instance_init = strongarm_rtc_init,
465aacf8895SPaolo Bonzini .class_init = strongarm_rtc_sysbus_class_init,
466aacf8895SPaolo Bonzini };
467aacf8895SPaolo Bonzini
468aacf8895SPaolo Bonzini /* GPIO */
469aacf8895SPaolo Bonzini #define GPLR 0x00
470aacf8895SPaolo Bonzini #define GPDR 0x04
471aacf8895SPaolo Bonzini #define GPSR 0x08
472aacf8895SPaolo Bonzini #define GPCR 0x0c
473aacf8895SPaolo Bonzini #define GRER 0x10
474aacf8895SPaolo Bonzini #define GFER 0x14
475aacf8895SPaolo Bonzini #define GEDR 0x18
476aacf8895SPaolo Bonzini #define GAFR 0x1c
477aacf8895SPaolo Bonzini
478f55beb84SAndreas Färber #define TYPE_STRONGARM_GPIO "strongarm-gpio"
4798063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(StrongARMGPIOInfo, STRONGARM_GPIO)
480f55beb84SAndreas Färber
481aacf8895SPaolo Bonzini struct StrongARMGPIOInfo {
482aacf8895SPaolo Bonzini SysBusDevice busdev;
483aacf8895SPaolo Bonzini MemoryRegion iomem;
484aacf8895SPaolo Bonzini qemu_irq handler[28];
485aacf8895SPaolo Bonzini qemu_irq irqs[11];
486aacf8895SPaolo Bonzini qemu_irq irqX;
487aacf8895SPaolo Bonzini
488aacf8895SPaolo Bonzini uint32_t ilevel;
489aacf8895SPaolo Bonzini uint32_t olevel;
490aacf8895SPaolo Bonzini uint32_t dir;
491aacf8895SPaolo Bonzini uint32_t rising;
492aacf8895SPaolo Bonzini uint32_t falling;
493aacf8895SPaolo Bonzini uint32_t status;
494aacf8895SPaolo Bonzini uint32_t gafr;
495aacf8895SPaolo Bonzini
496aacf8895SPaolo Bonzini uint32_t prev_level;
497aacf8895SPaolo Bonzini };
498aacf8895SPaolo Bonzini
499aacf8895SPaolo Bonzini
strongarm_gpio_irq_update(StrongARMGPIOInfo * s)500aacf8895SPaolo Bonzini static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s)
501aacf8895SPaolo Bonzini {
502aacf8895SPaolo Bonzini int i;
503aacf8895SPaolo Bonzini for (i = 0; i < 11; i++) {
504aacf8895SPaolo Bonzini qemu_set_irq(s->irqs[i], s->status & (1 << i));
505aacf8895SPaolo Bonzini }
506aacf8895SPaolo Bonzini
507aacf8895SPaolo Bonzini qemu_set_irq(s->irqX, (s->status & ~0x7ff));
508aacf8895SPaolo Bonzini }
509aacf8895SPaolo Bonzini
strongarm_gpio_set(void * opaque,int line,int level)510aacf8895SPaolo Bonzini static void strongarm_gpio_set(void *opaque, int line, int level)
511aacf8895SPaolo Bonzini {
512aacf8895SPaolo Bonzini StrongARMGPIOInfo *s = opaque;
513aacf8895SPaolo Bonzini uint32_t mask;
514aacf8895SPaolo Bonzini
515aacf8895SPaolo Bonzini mask = 1 << line;
516aacf8895SPaolo Bonzini
517aacf8895SPaolo Bonzini if (level) {
518aacf8895SPaolo Bonzini s->status |= s->rising & mask &
519aacf8895SPaolo Bonzini ~s->ilevel & ~s->dir;
520aacf8895SPaolo Bonzini s->ilevel |= mask;
521aacf8895SPaolo Bonzini } else {
522aacf8895SPaolo Bonzini s->status |= s->falling & mask &
523aacf8895SPaolo Bonzini s->ilevel & ~s->dir;
524aacf8895SPaolo Bonzini s->ilevel &= ~mask;
525aacf8895SPaolo Bonzini }
526aacf8895SPaolo Bonzini
527aacf8895SPaolo Bonzini if (s->status & mask) {
528aacf8895SPaolo Bonzini strongarm_gpio_irq_update(s);
529aacf8895SPaolo Bonzini }
530aacf8895SPaolo Bonzini }
531aacf8895SPaolo Bonzini
strongarm_gpio_handler_update(StrongARMGPIOInfo * s)532aacf8895SPaolo Bonzini static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s)
533aacf8895SPaolo Bonzini {
534aacf8895SPaolo Bonzini uint32_t level, diff;
535aacf8895SPaolo Bonzini int bit;
536aacf8895SPaolo Bonzini
537aacf8895SPaolo Bonzini level = s->olevel & s->dir;
538aacf8895SPaolo Bonzini
539aacf8895SPaolo Bonzini for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
540786a4ea8SStefan Hajnoczi bit = ctz32(diff);
541aacf8895SPaolo Bonzini qemu_set_irq(s->handler[bit], (level >> bit) & 1);
542aacf8895SPaolo Bonzini }
543aacf8895SPaolo Bonzini
544aacf8895SPaolo Bonzini s->prev_level = level;
545aacf8895SPaolo Bonzini }
546aacf8895SPaolo Bonzini
strongarm_gpio_read(void * opaque,hwaddr offset,unsigned size)547aacf8895SPaolo Bonzini static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset,
548aacf8895SPaolo Bonzini unsigned size)
549aacf8895SPaolo Bonzini {
550aacf8895SPaolo Bonzini StrongARMGPIOInfo *s = opaque;
551aacf8895SPaolo Bonzini
552aacf8895SPaolo Bonzini switch (offset) {
553aacf8895SPaolo Bonzini case GPDR: /* GPIO Pin-Direction registers */
554aacf8895SPaolo Bonzini return s->dir;
555aacf8895SPaolo Bonzini
556aacf8895SPaolo Bonzini case GPSR: /* GPIO Pin-Output Set registers */
55792335a0dSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
5585e5deca1SManos Pitsidianakis "%s: read from write only register GPSR\n", __func__);
55992335a0dSPeter Maydell return 0;
560aacf8895SPaolo Bonzini
561aacf8895SPaolo Bonzini case GPCR: /* GPIO Pin-Output Clear registers */
56292335a0dSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
5635e5deca1SManos Pitsidianakis "%s: read from write only register GPCR\n", __func__);
56492335a0dSPeter Maydell return 0;
565aacf8895SPaolo Bonzini
566aacf8895SPaolo Bonzini case GRER: /* GPIO Rising-Edge Detect Enable registers */
567aacf8895SPaolo Bonzini return s->rising;
568aacf8895SPaolo Bonzini
569aacf8895SPaolo Bonzini case GFER: /* GPIO Falling-Edge Detect Enable registers */
570aacf8895SPaolo Bonzini return s->falling;
571aacf8895SPaolo Bonzini
572aacf8895SPaolo Bonzini case GAFR: /* GPIO Alternate Function registers */
573aacf8895SPaolo Bonzini return s->gafr;
574aacf8895SPaolo Bonzini
575aacf8895SPaolo Bonzini case GPLR: /* GPIO Pin-Level registers */
576aacf8895SPaolo Bonzini return (s->olevel & s->dir) |
577aacf8895SPaolo Bonzini (s->ilevel & ~s->dir);
578aacf8895SPaolo Bonzini
579aacf8895SPaolo Bonzini case GEDR: /* GPIO Edge Detect Status registers */
580aacf8895SPaolo Bonzini return s->status;
581aacf8895SPaolo Bonzini
582aacf8895SPaolo Bonzini default:
5835e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
5845e5deca1SManos Pitsidianakis "%s: Bad gpio read offset 0x"HWADDR_FMT_plx"\n",
5855e5deca1SManos Pitsidianakis __func__, offset);
586aacf8895SPaolo Bonzini }
587aacf8895SPaolo Bonzini
588aacf8895SPaolo Bonzini return 0;
589aacf8895SPaolo Bonzini }
590aacf8895SPaolo Bonzini
strongarm_gpio_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)591aacf8895SPaolo Bonzini static void strongarm_gpio_write(void *opaque, hwaddr offset,
592aacf8895SPaolo Bonzini uint64_t value, unsigned size)
593aacf8895SPaolo Bonzini {
594aacf8895SPaolo Bonzini StrongARMGPIOInfo *s = opaque;
595aacf8895SPaolo Bonzini
596aacf8895SPaolo Bonzini switch (offset) {
597aacf8895SPaolo Bonzini case GPDR: /* GPIO Pin-Direction registers */
5989a93b2faSPrasad J Pandit s->dir = value & 0x0fffffff;
599aacf8895SPaolo Bonzini strongarm_gpio_handler_update(s);
600aacf8895SPaolo Bonzini break;
601aacf8895SPaolo Bonzini
602aacf8895SPaolo Bonzini case GPSR: /* GPIO Pin-Output Set registers */
6039a93b2faSPrasad J Pandit s->olevel |= value & 0x0fffffff;
604aacf8895SPaolo Bonzini strongarm_gpio_handler_update(s);
605aacf8895SPaolo Bonzini break;
606aacf8895SPaolo Bonzini
607aacf8895SPaolo Bonzini case GPCR: /* GPIO Pin-Output Clear registers */
608aacf8895SPaolo Bonzini s->olevel &= ~value;
609aacf8895SPaolo Bonzini strongarm_gpio_handler_update(s);
610aacf8895SPaolo Bonzini break;
611aacf8895SPaolo Bonzini
612aacf8895SPaolo Bonzini case GRER: /* GPIO Rising-Edge Detect Enable registers */
613aacf8895SPaolo Bonzini s->rising = value;
614aacf8895SPaolo Bonzini break;
615aacf8895SPaolo Bonzini
616aacf8895SPaolo Bonzini case GFER: /* GPIO Falling-Edge Detect Enable registers */
617aacf8895SPaolo Bonzini s->falling = value;
618aacf8895SPaolo Bonzini break;
619aacf8895SPaolo Bonzini
620aacf8895SPaolo Bonzini case GAFR: /* GPIO Alternate Function registers */
621aacf8895SPaolo Bonzini s->gafr = value;
622aacf8895SPaolo Bonzini break;
623aacf8895SPaolo Bonzini
624aacf8895SPaolo Bonzini case GEDR: /* GPIO Edge Detect Status registers */
625aacf8895SPaolo Bonzini s->status &= ~value;
626aacf8895SPaolo Bonzini strongarm_gpio_irq_update(s);
627aacf8895SPaolo Bonzini break;
628aacf8895SPaolo Bonzini
629aacf8895SPaolo Bonzini default:
6305e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
6315e5deca1SManos Pitsidianakis "%s: Bad write offset 0x"HWADDR_FMT_plx"\n",
6325e5deca1SManos Pitsidianakis __func__, offset);
633aacf8895SPaolo Bonzini }
634aacf8895SPaolo Bonzini }
635aacf8895SPaolo Bonzini
636aacf8895SPaolo Bonzini static const MemoryRegionOps strongarm_gpio_ops = {
637aacf8895SPaolo Bonzini .read = strongarm_gpio_read,
638aacf8895SPaolo Bonzini .write = strongarm_gpio_write,
639aacf8895SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
640aacf8895SPaolo Bonzini };
641aacf8895SPaolo Bonzini
strongarm_gpio_init(hwaddr base,DeviceState * pic)642aacf8895SPaolo Bonzini static DeviceState *strongarm_gpio_init(hwaddr base,
643aacf8895SPaolo Bonzini DeviceState *pic)
644aacf8895SPaolo Bonzini {
645aacf8895SPaolo Bonzini DeviceState *dev;
646aacf8895SPaolo Bonzini int i;
647aacf8895SPaolo Bonzini
6483e80f690SMarkus Armbruster dev = qdev_new(TYPE_STRONGARM_GPIO);
6493c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
650aacf8895SPaolo Bonzini
651aacf8895SPaolo Bonzini sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
652aacf8895SPaolo Bonzini for (i = 0; i < 12; i++)
653aacf8895SPaolo Bonzini sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
654aacf8895SPaolo Bonzini qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i));
655aacf8895SPaolo Bonzini
656aacf8895SPaolo Bonzini return dev;
657aacf8895SPaolo Bonzini }
658aacf8895SPaolo Bonzini
strongarm_gpio_initfn(Object * obj)6595a67508cSxiaoqiang.zhao static void strongarm_gpio_initfn(Object *obj)
660aacf8895SPaolo Bonzini {
6615a67508cSxiaoqiang.zhao DeviceState *dev = DEVICE(obj);
6625a67508cSxiaoqiang.zhao StrongARMGPIOInfo *s = STRONGARM_GPIO(obj);
6635a67508cSxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
664aacf8895SPaolo Bonzini int i;
665aacf8895SPaolo Bonzini
666f55beb84SAndreas Färber qdev_init_gpio_in(dev, strongarm_gpio_set, 28);
667f55beb84SAndreas Färber qdev_init_gpio_out(dev, s->handler, 28);
668aacf8895SPaolo Bonzini
6695a67508cSxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &strongarm_gpio_ops, s,
67064bde0f3SPaolo Bonzini "gpio", 0x1000);
671aacf8895SPaolo Bonzini
672f55beb84SAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
673aacf8895SPaolo Bonzini for (i = 0; i < 11; i++) {
674f55beb84SAndreas Färber sysbus_init_irq(sbd, &s->irqs[i]);
675aacf8895SPaolo Bonzini }
676f55beb84SAndreas Färber sysbus_init_irq(sbd, &s->irqX);
677aacf8895SPaolo Bonzini }
678aacf8895SPaolo Bonzini
679aacf8895SPaolo Bonzini static const VMStateDescription vmstate_strongarm_gpio_regs = {
680aacf8895SPaolo Bonzini .name = "strongarm-gpio",
681aacf8895SPaolo Bonzini .version_id = 0,
682aacf8895SPaolo Bonzini .minimum_version_id = 0,
683607ef570SRichard Henderson .fields = (const VMStateField[]) {
684aacf8895SPaolo Bonzini VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
685aacf8895SPaolo Bonzini VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
686aacf8895SPaolo Bonzini VMSTATE_UINT32(dir, StrongARMGPIOInfo),
687aacf8895SPaolo Bonzini VMSTATE_UINT32(rising, StrongARMGPIOInfo),
688aacf8895SPaolo Bonzini VMSTATE_UINT32(falling, StrongARMGPIOInfo),
689aacf8895SPaolo Bonzini VMSTATE_UINT32(status, StrongARMGPIOInfo),
690aacf8895SPaolo Bonzini VMSTATE_UINT32(gafr, StrongARMGPIOInfo),
691ed657d71SPeter Maydell VMSTATE_UINT32(prev_level, StrongARMGPIOInfo),
692aacf8895SPaolo Bonzini VMSTATE_END_OF_LIST(),
693aacf8895SPaolo Bonzini },
694aacf8895SPaolo Bonzini };
695aacf8895SPaolo Bonzini
strongarm_gpio_class_init(ObjectClass * klass,void * data)696aacf8895SPaolo Bonzini static void strongarm_gpio_class_init(ObjectClass *klass, void *data)
697aacf8895SPaolo Bonzini {
698aacf8895SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
699aacf8895SPaolo Bonzini
700aacf8895SPaolo Bonzini dc->desc = "StrongARM GPIO controller";
701ed657d71SPeter Maydell dc->vmsd = &vmstate_strongarm_gpio_regs;
702aacf8895SPaolo Bonzini }
703aacf8895SPaolo Bonzini
704aacf8895SPaolo Bonzini static const TypeInfo strongarm_gpio_info = {
705f55beb84SAndreas Färber .name = TYPE_STRONGARM_GPIO,
706aacf8895SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
707aacf8895SPaolo Bonzini .instance_size = sizeof(StrongARMGPIOInfo),
7085a67508cSxiaoqiang.zhao .instance_init = strongarm_gpio_initfn,
709aacf8895SPaolo Bonzini .class_init = strongarm_gpio_class_init,
710aacf8895SPaolo Bonzini };
711aacf8895SPaolo Bonzini
712aacf8895SPaolo Bonzini /* Peripheral Pin Controller */
713aacf8895SPaolo Bonzini #define PPDR 0x00
714aacf8895SPaolo Bonzini #define PPSR 0x04
715aacf8895SPaolo Bonzini #define PPAR 0x08
716aacf8895SPaolo Bonzini #define PSDR 0x0c
717aacf8895SPaolo Bonzini #define PPFR 0x10
718aacf8895SPaolo Bonzini
719c71e6732SAndreas Färber #define TYPE_STRONGARM_PPC "strongarm-ppc"
7208063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(StrongARMPPCInfo, STRONGARM_PPC)
721c71e6732SAndreas Färber
722aacf8895SPaolo Bonzini struct StrongARMPPCInfo {
723c71e6732SAndreas Färber SysBusDevice parent_obj;
724c71e6732SAndreas Färber
725aacf8895SPaolo Bonzini MemoryRegion iomem;
726aacf8895SPaolo Bonzini qemu_irq handler[28];
727aacf8895SPaolo Bonzini
728aacf8895SPaolo Bonzini uint32_t ilevel;
729aacf8895SPaolo Bonzini uint32_t olevel;
730aacf8895SPaolo Bonzini uint32_t dir;
731aacf8895SPaolo Bonzini uint32_t ppar;
732aacf8895SPaolo Bonzini uint32_t psdr;
733aacf8895SPaolo Bonzini uint32_t ppfr;
734aacf8895SPaolo Bonzini
735aacf8895SPaolo Bonzini uint32_t prev_level;
736aacf8895SPaolo Bonzini };
737aacf8895SPaolo Bonzini
strongarm_ppc_set(void * opaque,int line,int level)738aacf8895SPaolo Bonzini static void strongarm_ppc_set(void *opaque, int line, int level)
739aacf8895SPaolo Bonzini {
740aacf8895SPaolo Bonzini StrongARMPPCInfo *s = opaque;
741aacf8895SPaolo Bonzini
742aacf8895SPaolo Bonzini if (level) {
743aacf8895SPaolo Bonzini s->ilevel |= 1 << line;
744aacf8895SPaolo Bonzini } else {
745aacf8895SPaolo Bonzini s->ilevel &= ~(1 << line);
746aacf8895SPaolo Bonzini }
747aacf8895SPaolo Bonzini }
748aacf8895SPaolo Bonzini
strongarm_ppc_handler_update(StrongARMPPCInfo * s)749aacf8895SPaolo Bonzini static void strongarm_ppc_handler_update(StrongARMPPCInfo *s)
750aacf8895SPaolo Bonzini {
751aacf8895SPaolo Bonzini uint32_t level, diff;
752aacf8895SPaolo Bonzini int bit;
753aacf8895SPaolo Bonzini
754aacf8895SPaolo Bonzini level = s->olevel & s->dir;
755aacf8895SPaolo Bonzini
756aacf8895SPaolo Bonzini for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
757786a4ea8SStefan Hajnoczi bit = ctz32(diff);
758aacf8895SPaolo Bonzini qemu_set_irq(s->handler[bit], (level >> bit) & 1);
759aacf8895SPaolo Bonzini }
760aacf8895SPaolo Bonzini
761aacf8895SPaolo Bonzini s->prev_level = level;
762aacf8895SPaolo Bonzini }
763aacf8895SPaolo Bonzini
strongarm_ppc_read(void * opaque,hwaddr offset,unsigned size)764aacf8895SPaolo Bonzini static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset,
765aacf8895SPaolo Bonzini unsigned size)
766aacf8895SPaolo Bonzini {
767aacf8895SPaolo Bonzini StrongARMPPCInfo *s = opaque;
768aacf8895SPaolo Bonzini
769aacf8895SPaolo Bonzini switch (offset) {
770aacf8895SPaolo Bonzini case PPDR: /* PPC Pin Direction registers */
771aacf8895SPaolo Bonzini return s->dir | ~0x3fffff;
772aacf8895SPaolo Bonzini
773aacf8895SPaolo Bonzini case PPSR: /* PPC Pin State registers */
774aacf8895SPaolo Bonzini return (s->olevel & s->dir) |
775aacf8895SPaolo Bonzini (s->ilevel & ~s->dir) |
776aacf8895SPaolo Bonzini ~0x3fffff;
777aacf8895SPaolo Bonzini
778aacf8895SPaolo Bonzini case PPAR:
779aacf8895SPaolo Bonzini return s->ppar | ~0x41000;
780aacf8895SPaolo Bonzini
781aacf8895SPaolo Bonzini case PSDR:
782aacf8895SPaolo Bonzini return s->psdr;
783aacf8895SPaolo Bonzini
784aacf8895SPaolo Bonzini case PPFR:
785aacf8895SPaolo Bonzini return s->ppfr | ~0x7f001;
786aacf8895SPaolo Bonzini
787aacf8895SPaolo Bonzini default:
7885e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
7895e5deca1SManos Pitsidianakis "%s: Bad ppc read offset 0x"HWADDR_FMT_plx "\n",
7905e5deca1SManos Pitsidianakis __func__, offset);
791aacf8895SPaolo Bonzini }
792aacf8895SPaolo Bonzini
793aacf8895SPaolo Bonzini return 0;
794aacf8895SPaolo Bonzini }
795aacf8895SPaolo Bonzini
strongarm_ppc_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)796aacf8895SPaolo Bonzini static void strongarm_ppc_write(void *opaque, hwaddr offset,
797aacf8895SPaolo Bonzini uint64_t value, unsigned size)
798aacf8895SPaolo Bonzini {
799aacf8895SPaolo Bonzini StrongARMPPCInfo *s = opaque;
800aacf8895SPaolo Bonzini
801aacf8895SPaolo Bonzini switch (offset) {
802aacf8895SPaolo Bonzini case PPDR: /* PPC Pin Direction registers */
803aacf8895SPaolo Bonzini s->dir = value & 0x3fffff;
804aacf8895SPaolo Bonzini strongarm_ppc_handler_update(s);
805aacf8895SPaolo Bonzini break;
806aacf8895SPaolo Bonzini
807aacf8895SPaolo Bonzini case PPSR: /* PPC Pin State registers */
808aacf8895SPaolo Bonzini s->olevel = value & s->dir & 0x3fffff;
809aacf8895SPaolo Bonzini strongarm_ppc_handler_update(s);
810aacf8895SPaolo Bonzini break;
811aacf8895SPaolo Bonzini
812aacf8895SPaolo Bonzini case PPAR:
813aacf8895SPaolo Bonzini s->ppar = value & 0x41000;
814aacf8895SPaolo Bonzini break;
815aacf8895SPaolo Bonzini
816aacf8895SPaolo Bonzini case PSDR:
817aacf8895SPaolo Bonzini s->psdr = value & 0x3fffff;
818aacf8895SPaolo Bonzini break;
819aacf8895SPaolo Bonzini
820aacf8895SPaolo Bonzini case PPFR:
821aacf8895SPaolo Bonzini s->ppfr = value & 0x7f001;
822aacf8895SPaolo Bonzini break;
823aacf8895SPaolo Bonzini
824aacf8895SPaolo Bonzini default:
8255e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
8265e5deca1SManos Pitsidianakis "%s: Bad ppc write offset 0x"HWADDR_FMT_plx"\n",
8275e5deca1SManos Pitsidianakis __func__, offset);
828aacf8895SPaolo Bonzini }
829aacf8895SPaolo Bonzini }
830aacf8895SPaolo Bonzini
831aacf8895SPaolo Bonzini static const MemoryRegionOps strongarm_ppc_ops = {
832aacf8895SPaolo Bonzini .read = strongarm_ppc_read,
833aacf8895SPaolo Bonzini .write = strongarm_ppc_write,
834aacf8895SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
835aacf8895SPaolo Bonzini };
836aacf8895SPaolo Bonzini
strongarm_ppc_init(Object * obj)8375a67508cSxiaoqiang.zhao static void strongarm_ppc_init(Object *obj)
838aacf8895SPaolo Bonzini {
8395a67508cSxiaoqiang.zhao DeviceState *dev = DEVICE(obj);
8405a67508cSxiaoqiang.zhao StrongARMPPCInfo *s = STRONGARM_PPC(obj);
8415a67508cSxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
842aacf8895SPaolo Bonzini
843c71e6732SAndreas Färber qdev_init_gpio_in(dev, strongarm_ppc_set, 22);
844c71e6732SAndreas Färber qdev_init_gpio_out(dev, s->handler, 22);
845aacf8895SPaolo Bonzini
8465a67508cSxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &strongarm_ppc_ops, s,
84764bde0f3SPaolo Bonzini "ppc", 0x1000);
848aacf8895SPaolo Bonzini
849c71e6732SAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
850aacf8895SPaolo Bonzini }
851aacf8895SPaolo Bonzini
852aacf8895SPaolo Bonzini static const VMStateDescription vmstate_strongarm_ppc_regs = {
853aacf8895SPaolo Bonzini .name = "strongarm-ppc",
854aacf8895SPaolo Bonzini .version_id = 0,
855aacf8895SPaolo Bonzini .minimum_version_id = 0,
856607ef570SRichard Henderson .fields = (const VMStateField[]) {
857aacf8895SPaolo Bonzini VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
858aacf8895SPaolo Bonzini VMSTATE_UINT32(olevel, StrongARMPPCInfo),
859aacf8895SPaolo Bonzini VMSTATE_UINT32(dir, StrongARMPPCInfo),
860aacf8895SPaolo Bonzini VMSTATE_UINT32(ppar, StrongARMPPCInfo),
861aacf8895SPaolo Bonzini VMSTATE_UINT32(psdr, StrongARMPPCInfo),
862aacf8895SPaolo Bonzini VMSTATE_UINT32(ppfr, StrongARMPPCInfo),
863ed657d71SPeter Maydell VMSTATE_UINT32(prev_level, StrongARMPPCInfo),
864aacf8895SPaolo Bonzini VMSTATE_END_OF_LIST(),
865aacf8895SPaolo Bonzini },
866aacf8895SPaolo Bonzini };
867aacf8895SPaolo Bonzini
strongarm_ppc_class_init(ObjectClass * klass,void * data)868aacf8895SPaolo Bonzini static void strongarm_ppc_class_init(ObjectClass *klass, void *data)
869aacf8895SPaolo Bonzini {
870aacf8895SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
871aacf8895SPaolo Bonzini
872aacf8895SPaolo Bonzini dc->desc = "StrongARM PPC controller";
873ed657d71SPeter Maydell dc->vmsd = &vmstate_strongarm_ppc_regs;
874aacf8895SPaolo Bonzini }
875aacf8895SPaolo Bonzini
876aacf8895SPaolo Bonzini static const TypeInfo strongarm_ppc_info = {
877c71e6732SAndreas Färber .name = TYPE_STRONGARM_PPC,
878aacf8895SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
879aacf8895SPaolo Bonzini .instance_size = sizeof(StrongARMPPCInfo),
8805a67508cSxiaoqiang.zhao .instance_init = strongarm_ppc_init,
881aacf8895SPaolo Bonzini .class_init = strongarm_ppc_class_init,
882aacf8895SPaolo Bonzini };
883aacf8895SPaolo Bonzini
884aacf8895SPaolo Bonzini /* UART Ports */
885aacf8895SPaolo Bonzini #define UTCR0 0x00
886aacf8895SPaolo Bonzini #define UTCR1 0x04
887aacf8895SPaolo Bonzini #define UTCR2 0x08
888aacf8895SPaolo Bonzini #define UTCR3 0x0c
889aacf8895SPaolo Bonzini #define UTDR 0x14
890aacf8895SPaolo Bonzini #define UTSR0 0x1c
891aacf8895SPaolo Bonzini #define UTSR1 0x20
892aacf8895SPaolo Bonzini
893aacf8895SPaolo Bonzini #define UTCR0_PE (1 << 0) /* Parity enable */
894aacf8895SPaolo Bonzini #define UTCR0_OES (1 << 1) /* Even parity */
895aacf8895SPaolo Bonzini #define UTCR0_SBS (1 << 2) /* 2 stop bits */
896aacf8895SPaolo Bonzini #define UTCR0_DSS (1 << 3) /* 8-bit data */
897aacf8895SPaolo Bonzini
898aacf8895SPaolo Bonzini #define UTCR3_RXE (1 << 0) /* Rx enable */
899aacf8895SPaolo Bonzini #define UTCR3_TXE (1 << 1) /* Tx enable */
900aacf8895SPaolo Bonzini #define UTCR3_BRK (1 << 2) /* Force Break */
901aacf8895SPaolo Bonzini #define UTCR3_RIE (1 << 3) /* Rx int enable */
902aacf8895SPaolo Bonzini #define UTCR3_TIE (1 << 4) /* Tx int enable */
903aacf8895SPaolo Bonzini #define UTCR3_LBM (1 << 5) /* Loopback */
904aacf8895SPaolo Bonzini
905aacf8895SPaolo Bonzini #define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */
906aacf8895SPaolo Bonzini #define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */
907aacf8895SPaolo Bonzini #define UTSR0_RID (1 << 2) /* Receiver Idle */
908aacf8895SPaolo Bonzini #define UTSR0_RBB (1 << 3) /* Receiver begin break */
909aacf8895SPaolo Bonzini #define UTSR0_REB (1 << 4) /* Receiver end break */
910aacf8895SPaolo Bonzini #define UTSR0_EIF (1 << 5) /* Error in FIFO */
911aacf8895SPaolo Bonzini
912aacf8895SPaolo Bonzini #define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */
913aacf8895SPaolo Bonzini #define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */
914aacf8895SPaolo Bonzini #define UTSR1_PRE (1 << 3) /* Parity error */
915aacf8895SPaolo Bonzini #define UTSR1_FRE (1 << 4) /* Frame error */
916aacf8895SPaolo Bonzini #define UTSR1_ROR (1 << 5) /* Receive Over Run */
917aacf8895SPaolo Bonzini
918aacf8895SPaolo Bonzini #define RX_FIFO_PRE (1 << 8)
919aacf8895SPaolo Bonzini #define RX_FIFO_FRE (1 << 9)
920aacf8895SPaolo Bonzini #define RX_FIFO_ROR (1 << 10)
921aacf8895SPaolo Bonzini
922fff3af97SAndreas Färber #define TYPE_STRONGARM_UART "strongarm-uart"
9238063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(StrongARMUARTState, STRONGARM_UART)
924fff3af97SAndreas Färber
925db1015e9SEduardo Habkost struct StrongARMUARTState {
926fff3af97SAndreas Färber SysBusDevice parent_obj;
927fff3af97SAndreas Färber
928aacf8895SPaolo Bonzini MemoryRegion iomem;
929becdfa00SMarc-André Lureau CharBackend chr;
930aacf8895SPaolo Bonzini qemu_irq irq;
931aacf8895SPaolo Bonzini
932aacf8895SPaolo Bonzini uint8_t utcr0;
933aacf8895SPaolo Bonzini uint16_t brd;
934aacf8895SPaolo Bonzini uint8_t utcr3;
935aacf8895SPaolo Bonzini uint8_t utsr0;
936aacf8895SPaolo Bonzini uint8_t utsr1;
937aacf8895SPaolo Bonzini
938aacf8895SPaolo Bonzini uint8_t tx_fifo[8];
939aacf8895SPaolo Bonzini uint8_t tx_start;
940aacf8895SPaolo Bonzini uint8_t tx_len;
941aacf8895SPaolo Bonzini uint16_t rx_fifo[12]; /* value + error flags in high bits */
942aacf8895SPaolo Bonzini uint8_t rx_start;
943aacf8895SPaolo Bonzini uint8_t rx_len;
944aacf8895SPaolo Bonzini
9458ddd611aSPhilippe Mathieu-Daudé uint64_t char_transmit_time; /* time to transmit a char in nanoseconds */
946aacf8895SPaolo Bonzini bool wait_break_end;
947aacf8895SPaolo Bonzini QEMUTimer *rx_timeout_timer;
948aacf8895SPaolo Bonzini QEMUTimer *tx_timer;
949db1015e9SEduardo Habkost };
950aacf8895SPaolo Bonzini
strongarm_uart_update_status(StrongARMUARTState * s)951aacf8895SPaolo Bonzini static void strongarm_uart_update_status(StrongARMUARTState *s)
952aacf8895SPaolo Bonzini {
953aacf8895SPaolo Bonzini uint16_t utsr1 = 0;
954aacf8895SPaolo Bonzini
955aacf8895SPaolo Bonzini if (s->tx_len != 8) {
956aacf8895SPaolo Bonzini utsr1 |= UTSR1_TNF;
957aacf8895SPaolo Bonzini }
958aacf8895SPaolo Bonzini
959aacf8895SPaolo Bonzini if (s->rx_len != 0) {
960aacf8895SPaolo Bonzini uint16_t ent = s->rx_fifo[s->rx_start];
961aacf8895SPaolo Bonzini
962aacf8895SPaolo Bonzini utsr1 |= UTSR1_RNE;
963aacf8895SPaolo Bonzini if (ent & RX_FIFO_PRE) {
964aacf8895SPaolo Bonzini s->utsr1 |= UTSR1_PRE;
965aacf8895SPaolo Bonzini }
966aacf8895SPaolo Bonzini if (ent & RX_FIFO_FRE) {
967aacf8895SPaolo Bonzini s->utsr1 |= UTSR1_FRE;
968aacf8895SPaolo Bonzini }
969aacf8895SPaolo Bonzini if (ent & RX_FIFO_ROR) {
970aacf8895SPaolo Bonzini s->utsr1 |= UTSR1_ROR;
971aacf8895SPaolo Bonzini }
972aacf8895SPaolo Bonzini }
973aacf8895SPaolo Bonzini
974aacf8895SPaolo Bonzini s->utsr1 = utsr1;
975aacf8895SPaolo Bonzini }
976aacf8895SPaolo Bonzini
strongarm_uart_update_int_status(StrongARMUARTState * s)977aacf8895SPaolo Bonzini static void strongarm_uart_update_int_status(StrongARMUARTState *s)
978aacf8895SPaolo Bonzini {
979aacf8895SPaolo Bonzini uint16_t utsr0 = s->utsr0 &
980aacf8895SPaolo Bonzini (UTSR0_REB | UTSR0_RBB | UTSR0_RID);
981aacf8895SPaolo Bonzini int i;
982aacf8895SPaolo Bonzini
983aacf8895SPaolo Bonzini if ((s->utcr3 & UTCR3_TXE) &&
984aacf8895SPaolo Bonzini (s->utcr3 & UTCR3_TIE) &&
985aacf8895SPaolo Bonzini s->tx_len <= 4) {
986aacf8895SPaolo Bonzini utsr0 |= UTSR0_TFS;
987aacf8895SPaolo Bonzini }
988aacf8895SPaolo Bonzini
989aacf8895SPaolo Bonzini if ((s->utcr3 & UTCR3_RXE) &&
990aacf8895SPaolo Bonzini (s->utcr3 & UTCR3_RIE) &&
991aacf8895SPaolo Bonzini s->rx_len > 4) {
992aacf8895SPaolo Bonzini utsr0 |= UTSR0_RFS;
993aacf8895SPaolo Bonzini }
994aacf8895SPaolo Bonzini
995aacf8895SPaolo Bonzini for (i = 0; i < s->rx_len && i < 4; i++)
996aacf8895SPaolo Bonzini if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) {
997aacf8895SPaolo Bonzini utsr0 |= UTSR0_EIF;
998aacf8895SPaolo Bonzini break;
999aacf8895SPaolo Bonzini }
1000aacf8895SPaolo Bonzini
1001aacf8895SPaolo Bonzini s->utsr0 = utsr0;
1002aacf8895SPaolo Bonzini qemu_set_irq(s->irq, utsr0);
1003aacf8895SPaolo Bonzini }
1004aacf8895SPaolo Bonzini
strongarm_uart_update_parameters(StrongARMUARTState * s)1005aacf8895SPaolo Bonzini static void strongarm_uart_update_parameters(StrongARMUARTState *s)
1006aacf8895SPaolo Bonzini {
1007aacf8895SPaolo Bonzini int speed, parity, data_bits, stop_bits, frame_size;
1008aacf8895SPaolo Bonzini QEMUSerialSetParams ssp;
1009aacf8895SPaolo Bonzini
1010aacf8895SPaolo Bonzini /* Start bit. */
1011aacf8895SPaolo Bonzini frame_size = 1;
1012aacf8895SPaolo Bonzini if (s->utcr0 & UTCR0_PE) {
1013aacf8895SPaolo Bonzini /* Parity bit. */
1014aacf8895SPaolo Bonzini frame_size++;
1015aacf8895SPaolo Bonzini if (s->utcr0 & UTCR0_OES) {
1016aacf8895SPaolo Bonzini parity = 'E';
1017aacf8895SPaolo Bonzini } else {
1018aacf8895SPaolo Bonzini parity = 'O';
1019aacf8895SPaolo Bonzini }
1020aacf8895SPaolo Bonzini } else {
1021aacf8895SPaolo Bonzini parity = 'N';
1022aacf8895SPaolo Bonzini }
1023aacf8895SPaolo Bonzini if (s->utcr0 & UTCR0_SBS) {
1024aacf8895SPaolo Bonzini stop_bits = 2;
1025aacf8895SPaolo Bonzini } else {
1026aacf8895SPaolo Bonzini stop_bits = 1;
1027aacf8895SPaolo Bonzini }
1028aacf8895SPaolo Bonzini
1029aacf8895SPaolo Bonzini data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7;
1030aacf8895SPaolo Bonzini frame_size += data_bits + stop_bits;
1031aacf8895SPaolo Bonzini speed = 3686400 / 16 / (s->brd + 1);
1032aacf8895SPaolo Bonzini ssp.speed = speed;
1033aacf8895SPaolo Bonzini ssp.parity = parity;
1034aacf8895SPaolo Bonzini ssp.data_bits = data_bits;
1035aacf8895SPaolo Bonzini ssp.stop_bits = stop_bits;
103673bcb24dSRutuja Shah s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
10375345fdb4SMarc-André Lureau qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
1038aacf8895SPaolo Bonzini
10395e5deca1SManos Pitsidianakis trace_strongarm_uart_update_parameters((s->chr.chr ?
10405e5deca1SManos Pitsidianakis s->chr.chr->label : "NULL") ?:
10415e5deca1SManos Pitsidianakis "NULL",
10425e5deca1SManos Pitsidianakis speed,
10435e5deca1SManos Pitsidianakis parity,
10445e5deca1SManos Pitsidianakis data_bits,
10455e5deca1SManos Pitsidianakis stop_bits);
1046aacf8895SPaolo Bonzini }
1047aacf8895SPaolo Bonzini
strongarm_uart_rx_to(void * opaque)1048aacf8895SPaolo Bonzini static void strongarm_uart_rx_to(void *opaque)
1049aacf8895SPaolo Bonzini {
1050aacf8895SPaolo Bonzini StrongARMUARTState *s = opaque;
1051aacf8895SPaolo Bonzini
1052aacf8895SPaolo Bonzini if (s->rx_len) {
1053aacf8895SPaolo Bonzini s->utsr0 |= UTSR0_RID;
1054aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1055aacf8895SPaolo Bonzini }
1056aacf8895SPaolo Bonzini }
1057aacf8895SPaolo Bonzini
strongarm_uart_rx_push(StrongARMUARTState * s,uint16_t c)1058aacf8895SPaolo Bonzini static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c)
1059aacf8895SPaolo Bonzini {
1060aacf8895SPaolo Bonzini if ((s->utcr3 & UTCR3_RXE) == 0) {
1061aacf8895SPaolo Bonzini /* rx disabled */
1062aacf8895SPaolo Bonzini return;
1063aacf8895SPaolo Bonzini }
1064aacf8895SPaolo Bonzini
1065aacf8895SPaolo Bonzini if (s->wait_break_end) {
1066aacf8895SPaolo Bonzini s->utsr0 |= UTSR0_REB;
1067aacf8895SPaolo Bonzini s->wait_break_end = false;
1068aacf8895SPaolo Bonzini }
1069aacf8895SPaolo Bonzini
1070aacf8895SPaolo Bonzini if (s->rx_len < 12) {
1071aacf8895SPaolo Bonzini s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c;
1072aacf8895SPaolo Bonzini s->rx_len++;
1073aacf8895SPaolo Bonzini } else
1074aacf8895SPaolo Bonzini s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR;
1075aacf8895SPaolo Bonzini }
1076aacf8895SPaolo Bonzini
strongarm_uart_can_receive(void * opaque)1077aacf8895SPaolo Bonzini static int strongarm_uart_can_receive(void *opaque)
1078aacf8895SPaolo Bonzini {
1079aacf8895SPaolo Bonzini StrongARMUARTState *s = opaque;
1080aacf8895SPaolo Bonzini
1081aacf8895SPaolo Bonzini if (s->rx_len == 12) {
1082aacf8895SPaolo Bonzini return 0;
1083aacf8895SPaolo Bonzini }
1084aacf8895SPaolo Bonzini /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */
1085aacf8895SPaolo Bonzini if (s->rx_len < 8) {
1086aacf8895SPaolo Bonzini return 8 - s->rx_len;
1087aacf8895SPaolo Bonzini }
1088aacf8895SPaolo Bonzini return 1;
1089aacf8895SPaolo Bonzini }
1090aacf8895SPaolo Bonzini
strongarm_uart_receive(void * opaque,const uint8_t * buf,int size)1091aacf8895SPaolo Bonzini static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size)
1092aacf8895SPaolo Bonzini {
1093aacf8895SPaolo Bonzini StrongARMUARTState *s = opaque;
1094aacf8895SPaolo Bonzini int i;
1095aacf8895SPaolo Bonzini
1096aacf8895SPaolo Bonzini for (i = 0; i < size; i++) {
1097aacf8895SPaolo Bonzini strongarm_uart_rx_push(s, buf[i]);
1098aacf8895SPaolo Bonzini }
1099aacf8895SPaolo Bonzini
1100aacf8895SPaolo Bonzini /* call the timeout receive callback in 3 char transmit time */
1101bc72ad67SAlex Bligh timer_mod(s->rx_timeout_timer,
1102bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 3);
1103aacf8895SPaolo Bonzini
1104aacf8895SPaolo Bonzini strongarm_uart_update_status(s);
1105aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1106aacf8895SPaolo Bonzini }
1107aacf8895SPaolo Bonzini
strongarm_uart_event(void * opaque,QEMUChrEvent event)1108083b266fSPhilippe Mathieu-Daudé static void strongarm_uart_event(void *opaque, QEMUChrEvent event)
1109aacf8895SPaolo Bonzini {
1110aacf8895SPaolo Bonzini StrongARMUARTState *s = opaque;
1111aacf8895SPaolo Bonzini if (event == CHR_EVENT_BREAK) {
1112aacf8895SPaolo Bonzini s->utsr0 |= UTSR0_RBB;
1113aacf8895SPaolo Bonzini strongarm_uart_rx_push(s, RX_FIFO_FRE);
1114aacf8895SPaolo Bonzini s->wait_break_end = true;
1115aacf8895SPaolo Bonzini strongarm_uart_update_status(s);
1116aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1117aacf8895SPaolo Bonzini }
1118aacf8895SPaolo Bonzini }
1119aacf8895SPaolo Bonzini
strongarm_uart_tx(void * opaque)1120aacf8895SPaolo Bonzini static void strongarm_uart_tx(void *opaque)
1121aacf8895SPaolo Bonzini {
1122aacf8895SPaolo Bonzini StrongARMUARTState *s = opaque;
1123bc72ad67SAlex Bligh uint64_t new_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1124aacf8895SPaolo Bonzini
1125aacf8895SPaolo Bonzini if (s->utcr3 & UTCR3_LBM) /* loopback */ {
1126aacf8895SPaolo Bonzini strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
112730650701SAnton Nefedov } else if (qemu_chr_fe_backend_connected(&s->chr)) {
11286ab3fc32SDaniel P. Berrange /* XXX this blocks entire thread. Rewrite to use
11296ab3fc32SDaniel P. Berrange * qemu_chr_fe_write and background I/O callbacks */
11305345fdb4SMarc-André Lureau qemu_chr_fe_write_all(&s->chr, &s->tx_fifo[s->tx_start], 1);
1131aacf8895SPaolo Bonzini }
1132aacf8895SPaolo Bonzini
1133aacf8895SPaolo Bonzini s->tx_start = (s->tx_start + 1) % 8;
1134aacf8895SPaolo Bonzini s->tx_len--;
1135aacf8895SPaolo Bonzini if (s->tx_len) {
1136bc72ad67SAlex Bligh timer_mod(s->tx_timer, new_xmit_ts + s->char_transmit_time);
1137aacf8895SPaolo Bonzini }
1138aacf8895SPaolo Bonzini strongarm_uart_update_status(s);
1139aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1140aacf8895SPaolo Bonzini }
1141aacf8895SPaolo Bonzini
strongarm_uart_read(void * opaque,hwaddr addr,unsigned size)1142aacf8895SPaolo Bonzini static uint64_t strongarm_uart_read(void *opaque, hwaddr addr,
1143aacf8895SPaolo Bonzini unsigned size)
1144aacf8895SPaolo Bonzini {
1145aacf8895SPaolo Bonzini StrongARMUARTState *s = opaque;
1146aacf8895SPaolo Bonzini uint16_t ret;
1147aacf8895SPaolo Bonzini
1148aacf8895SPaolo Bonzini switch (addr) {
1149aacf8895SPaolo Bonzini case UTCR0:
1150aacf8895SPaolo Bonzini return s->utcr0;
1151aacf8895SPaolo Bonzini
1152aacf8895SPaolo Bonzini case UTCR1:
1153aacf8895SPaolo Bonzini return s->brd >> 8;
1154aacf8895SPaolo Bonzini
1155aacf8895SPaolo Bonzini case UTCR2:
1156aacf8895SPaolo Bonzini return s->brd & 0xff;
1157aacf8895SPaolo Bonzini
1158aacf8895SPaolo Bonzini case UTCR3:
1159aacf8895SPaolo Bonzini return s->utcr3;
1160aacf8895SPaolo Bonzini
1161aacf8895SPaolo Bonzini case UTDR:
1162aacf8895SPaolo Bonzini if (s->rx_len != 0) {
1163aacf8895SPaolo Bonzini ret = s->rx_fifo[s->rx_start];
1164aacf8895SPaolo Bonzini s->rx_start = (s->rx_start + 1) % 12;
1165aacf8895SPaolo Bonzini s->rx_len--;
1166aacf8895SPaolo Bonzini strongarm_uart_update_status(s);
1167aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1168aacf8895SPaolo Bonzini return ret;
1169aacf8895SPaolo Bonzini }
1170aacf8895SPaolo Bonzini return 0;
1171aacf8895SPaolo Bonzini
1172aacf8895SPaolo Bonzini case UTSR0:
1173aacf8895SPaolo Bonzini return s->utsr0;
1174aacf8895SPaolo Bonzini
1175aacf8895SPaolo Bonzini case UTSR1:
1176aacf8895SPaolo Bonzini return s->utsr1;
1177aacf8895SPaolo Bonzini
1178aacf8895SPaolo Bonzini default:
11795e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
11805e5deca1SManos Pitsidianakis "%s: Bad uart register read 0x"HWADDR_FMT_plx"\n",
11815e5deca1SManos Pitsidianakis __func__, addr);
1182aacf8895SPaolo Bonzini return 0;
1183aacf8895SPaolo Bonzini }
1184aacf8895SPaolo Bonzini }
1185aacf8895SPaolo Bonzini
strongarm_uart_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)1186aacf8895SPaolo Bonzini static void strongarm_uart_write(void *opaque, hwaddr addr,
1187aacf8895SPaolo Bonzini uint64_t value, unsigned size)
1188aacf8895SPaolo Bonzini {
1189aacf8895SPaolo Bonzini StrongARMUARTState *s = opaque;
1190aacf8895SPaolo Bonzini
1191aacf8895SPaolo Bonzini switch (addr) {
1192aacf8895SPaolo Bonzini case UTCR0:
1193aacf8895SPaolo Bonzini s->utcr0 = value & 0x7f;
1194aacf8895SPaolo Bonzini strongarm_uart_update_parameters(s);
1195aacf8895SPaolo Bonzini break;
1196aacf8895SPaolo Bonzini
1197aacf8895SPaolo Bonzini case UTCR1:
1198aacf8895SPaolo Bonzini s->brd = (s->brd & 0xff) | ((value & 0xf) << 8);
1199aacf8895SPaolo Bonzini strongarm_uart_update_parameters(s);
1200aacf8895SPaolo Bonzini break;
1201aacf8895SPaolo Bonzini
1202aacf8895SPaolo Bonzini case UTCR2:
1203aacf8895SPaolo Bonzini s->brd = (s->brd & 0xf00) | (value & 0xff);
1204aacf8895SPaolo Bonzini strongarm_uart_update_parameters(s);
1205aacf8895SPaolo Bonzini break;
1206aacf8895SPaolo Bonzini
1207aacf8895SPaolo Bonzini case UTCR3:
1208aacf8895SPaolo Bonzini s->utcr3 = value & 0x3f;
1209aacf8895SPaolo Bonzini if ((s->utcr3 & UTCR3_RXE) == 0) {
1210aacf8895SPaolo Bonzini s->rx_len = 0;
1211aacf8895SPaolo Bonzini }
1212aacf8895SPaolo Bonzini if ((s->utcr3 & UTCR3_TXE) == 0) {
1213aacf8895SPaolo Bonzini s->tx_len = 0;
1214aacf8895SPaolo Bonzini }
1215aacf8895SPaolo Bonzini strongarm_uart_update_status(s);
1216aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1217aacf8895SPaolo Bonzini break;
1218aacf8895SPaolo Bonzini
1219aacf8895SPaolo Bonzini case UTDR:
1220aacf8895SPaolo Bonzini if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) {
1221aacf8895SPaolo Bonzini s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value;
1222aacf8895SPaolo Bonzini s->tx_len++;
1223aacf8895SPaolo Bonzini strongarm_uart_update_status(s);
1224aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1225aacf8895SPaolo Bonzini if (s->tx_len == 1) {
1226aacf8895SPaolo Bonzini strongarm_uart_tx(s);
1227aacf8895SPaolo Bonzini }
1228aacf8895SPaolo Bonzini }
1229aacf8895SPaolo Bonzini break;
1230aacf8895SPaolo Bonzini
1231aacf8895SPaolo Bonzini case UTSR0:
1232aacf8895SPaolo Bonzini s->utsr0 = s->utsr0 & ~(value &
1233aacf8895SPaolo Bonzini (UTSR0_REB | UTSR0_RBB | UTSR0_RID));
1234aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1235aacf8895SPaolo Bonzini break;
1236aacf8895SPaolo Bonzini
1237aacf8895SPaolo Bonzini default:
12385e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
12395e5deca1SManos Pitsidianakis "%s: Bad uart register write 0x"HWADDR_FMT_plx"\n",
12405e5deca1SManos Pitsidianakis __func__, addr);
1241aacf8895SPaolo Bonzini }
1242aacf8895SPaolo Bonzini }
1243aacf8895SPaolo Bonzini
1244aacf8895SPaolo Bonzini static const MemoryRegionOps strongarm_uart_ops = {
1245aacf8895SPaolo Bonzini .read = strongarm_uart_read,
1246aacf8895SPaolo Bonzini .write = strongarm_uart_write,
1247aacf8895SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
1248aacf8895SPaolo Bonzini };
1249aacf8895SPaolo Bonzini
strongarm_uart_init(Object * obj)12505a67508cSxiaoqiang.zhao static void strongarm_uart_init(Object *obj)
1251aacf8895SPaolo Bonzini {
12525a67508cSxiaoqiang.zhao StrongARMUARTState *s = STRONGARM_UART(obj);
12535a67508cSxiaoqiang.zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj);
1254aacf8895SPaolo Bonzini
12555a67508cSxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &strongarm_uart_ops, s,
125664bde0f3SPaolo Bonzini "uart", 0x10000);
1257aacf8895SPaolo Bonzini sysbus_init_mmio(dev, &s->iomem);
1258aacf8895SPaolo Bonzini sysbus_init_irq(dev, &s->irq);
12598934515aSxiaoqiang zhao }
12608934515aSxiaoqiang zhao
strongarm_uart_realize(DeviceState * dev,Error ** errp)12618934515aSxiaoqiang zhao static void strongarm_uart_realize(DeviceState *dev, Error **errp)
12628934515aSxiaoqiang zhao {
12638934515aSxiaoqiang zhao StrongARMUARTState *s = STRONGARM_UART(dev);
1264aacf8895SPaolo Bonzini
1265efb27a49SPan Nengyuan s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1266efb27a49SPan Nengyuan strongarm_uart_rx_to,
1267efb27a49SPan Nengyuan s);
1268efb27a49SPan Nengyuan s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s);
12695345fdb4SMarc-André Lureau qemu_chr_fe_set_handlers(&s->chr,
1270aacf8895SPaolo Bonzini strongarm_uart_can_receive,
1271aacf8895SPaolo Bonzini strongarm_uart_receive,
1272aacf8895SPaolo Bonzini strongarm_uart_event,
127381517ba3SAnton Nefedov NULL, s, NULL, true);
1274aacf8895SPaolo Bonzini }
1275aacf8895SPaolo Bonzini
strongarm_uart_reset(DeviceState * dev)1276aacf8895SPaolo Bonzini static void strongarm_uart_reset(DeviceState *dev)
1277aacf8895SPaolo Bonzini {
1278fff3af97SAndreas Färber StrongARMUARTState *s = STRONGARM_UART(dev);
1279aacf8895SPaolo Bonzini
1280aacf8895SPaolo Bonzini s->utcr0 = UTCR0_DSS; /* 8 data, no parity */
1281aacf8895SPaolo Bonzini s->brd = 23; /* 9600 */
1282aacf8895SPaolo Bonzini /* enable send & recv - this actually violates spec */
1283aacf8895SPaolo Bonzini s->utcr3 = UTCR3_TXE | UTCR3_RXE;
1284aacf8895SPaolo Bonzini
1285aacf8895SPaolo Bonzini s->rx_len = s->tx_len = 0;
1286aacf8895SPaolo Bonzini
1287aacf8895SPaolo Bonzini strongarm_uart_update_parameters(s);
1288aacf8895SPaolo Bonzini strongarm_uart_update_status(s);
1289aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1290aacf8895SPaolo Bonzini }
1291aacf8895SPaolo Bonzini
strongarm_uart_post_load(void * opaque,int version_id)1292aacf8895SPaolo Bonzini static int strongarm_uart_post_load(void *opaque, int version_id)
1293aacf8895SPaolo Bonzini {
1294aacf8895SPaolo Bonzini StrongARMUARTState *s = opaque;
1295aacf8895SPaolo Bonzini
1296aacf8895SPaolo Bonzini strongarm_uart_update_parameters(s);
1297aacf8895SPaolo Bonzini strongarm_uart_update_status(s);
1298aacf8895SPaolo Bonzini strongarm_uart_update_int_status(s);
1299aacf8895SPaolo Bonzini
1300aacf8895SPaolo Bonzini /* tx and restart timer */
1301aacf8895SPaolo Bonzini if (s->tx_len) {
1302aacf8895SPaolo Bonzini strongarm_uart_tx(s);
1303aacf8895SPaolo Bonzini }
1304aacf8895SPaolo Bonzini
1305aacf8895SPaolo Bonzini /* restart rx timeout timer */
1306aacf8895SPaolo Bonzini if (s->rx_len) {
1307bc72ad67SAlex Bligh timer_mod(s->rx_timeout_timer,
1308bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 3);
1309aacf8895SPaolo Bonzini }
1310aacf8895SPaolo Bonzini
1311aacf8895SPaolo Bonzini return 0;
1312aacf8895SPaolo Bonzini }
1313aacf8895SPaolo Bonzini
1314aacf8895SPaolo Bonzini static const VMStateDescription vmstate_strongarm_uart_regs = {
1315aacf8895SPaolo Bonzini .name = "strongarm-uart",
1316aacf8895SPaolo Bonzini .version_id = 0,
1317aacf8895SPaolo Bonzini .minimum_version_id = 0,
1318aacf8895SPaolo Bonzini .post_load = strongarm_uart_post_load,
1319607ef570SRichard Henderson .fields = (const VMStateField[]) {
1320aacf8895SPaolo Bonzini VMSTATE_UINT8(utcr0, StrongARMUARTState),
1321aacf8895SPaolo Bonzini VMSTATE_UINT16(brd, StrongARMUARTState),
1322aacf8895SPaolo Bonzini VMSTATE_UINT8(utcr3, StrongARMUARTState),
1323aacf8895SPaolo Bonzini VMSTATE_UINT8(utsr0, StrongARMUARTState),
1324aacf8895SPaolo Bonzini VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8),
1325aacf8895SPaolo Bonzini VMSTATE_UINT8(tx_start, StrongARMUARTState),
1326aacf8895SPaolo Bonzini VMSTATE_UINT8(tx_len, StrongARMUARTState),
1327aacf8895SPaolo Bonzini VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12),
1328aacf8895SPaolo Bonzini VMSTATE_UINT8(rx_start, StrongARMUARTState),
1329aacf8895SPaolo Bonzini VMSTATE_UINT8(rx_len, StrongARMUARTState),
1330aacf8895SPaolo Bonzini VMSTATE_BOOL(wait_break_end, StrongARMUARTState),
1331aacf8895SPaolo Bonzini VMSTATE_END_OF_LIST(),
1332aacf8895SPaolo Bonzini },
1333aacf8895SPaolo Bonzini };
1334aacf8895SPaolo Bonzini
1335aacf8895SPaolo Bonzini static Property strongarm_uart_properties[] = {
1336aacf8895SPaolo Bonzini DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
1337aacf8895SPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
1338aacf8895SPaolo Bonzini };
1339aacf8895SPaolo Bonzini
strongarm_uart_class_init(ObjectClass * klass,void * data)1340aacf8895SPaolo Bonzini static void strongarm_uart_class_init(ObjectClass *klass, void *data)
1341aacf8895SPaolo Bonzini {
1342aacf8895SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
1343aacf8895SPaolo Bonzini
1344aacf8895SPaolo Bonzini dc->desc = "StrongARM UART controller";
1345*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, strongarm_uart_reset);
1346aacf8895SPaolo Bonzini dc->vmsd = &vmstate_strongarm_uart_regs;
13474f67d30bSMarc-André Lureau device_class_set_props(dc, strongarm_uart_properties);
13488934515aSxiaoqiang zhao dc->realize = strongarm_uart_realize;
1349aacf8895SPaolo Bonzini }
1350aacf8895SPaolo Bonzini
1351aacf8895SPaolo Bonzini static const TypeInfo strongarm_uart_info = {
1352fff3af97SAndreas Färber .name = TYPE_STRONGARM_UART,
1353aacf8895SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
1354aacf8895SPaolo Bonzini .instance_size = sizeof(StrongARMUARTState),
13555a67508cSxiaoqiang.zhao .instance_init = strongarm_uart_init,
1356aacf8895SPaolo Bonzini .class_init = strongarm_uart_class_init,
1357aacf8895SPaolo Bonzini };
1358aacf8895SPaolo Bonzini
1359aacf8895SPaolo Bonzini /* Synchronous Serial Ports */
13600ca81872SAndreas Färber
13610ca81872SAndreas Färber #define TYPE_STRONGARM_SSP "strongarm-ssp"
13628063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(StrongARMSSPState, STRONGARM_SSP)
13630ca81872SAndreas Färber
1364db1015e9SEduardo Habkost struct StrongARMSSPState {
13650ca81872SAndreas Färber SysBusDevice parent_obj;
13660ca81872SAndreas Färber
1367aacf8895SPaolo Bonzini MemoryRegion iomem;
1368aacf8895SPaolo Bonzini qemu_irq irq;
1369aacf8895SPaolo Bonzini SSIBus *bus;
1370aacf8895SPaolo Bonzini
1371aacf8895SPaolo Bonzini uint16_t sscr[2];
1372aacf8895SPaolo Bonzini uint16_t sssr;
1373aacf8895SPaolo Bonzini
1374aacf8895SPaolo Bonzini uint16_t rx_fifo[8];
1375aacf8895SPaolo Bonzini uint8_t rx_level;
1376aacf8895SPaolo Bonzini uint8_t rx_start;
1377db1015e9SEduardo Habkost };
1378aacf8895SPaolo Bonzini
1379aacf8895SPaolo Bonzini #define SSCR0 0x60 /* SSP Control register 0 */
1380aacf8895SPaolo Bonzini #define SSCR1 0x64 /* SSP Control register 1 */
1381aacf8895SPaolo Bonzini #define SSDR 0x6c /* SSP Data register */
1382aacf8895SPaolo Bonzini #define SSSR 0x74 /* SSP Status register */
1383aacf8895SPaolo Bonzini
1384aacf8895SPaolo Bonzini /* Bitfields for above registers */
1385aacf8895SPaolo Bonzini #define SSCR0_SPI(x) (((x) & 0x30) == 0x00)
1386aacf8895SPaolo Bonzini #define SSCR0_SSP(x) (((x) & 0x30) == 0x10)
1387aacf8895SPaolo Bonzini #define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
1388aacf8895SPaolo Bonzini #define SSCR0_PSP(x) (((x) & 0x30) == 0x30)
1389aacf8895SPaolo Bonzini #define SSCR0_SSE (1 << 7)
1390aacf8895SPaolo Bonzini #define SSCR0_DSS(x) (((x) & 0xf) + 1)
1391aacf8895SPaolo Bonzini #define SSCR1_RIE (1 << 0)
1392aacf8895SPaolo Bonzini #define SSCR1_TIE (1 << 1)
1393aacf8895SPaolo Bonzini #define SSCR1_LBM (1 << 2)
1394aacf8895SPaolo Bonzini #define SSSR_TNF (1 << 2)
1395aacf8895SPaolo Bonzini #define SSSR_RNE (1 << 3)
1396aacf8895SPaolo Bonzini #define SSSR_TFS (1 << 5)
1397aacf8895SPaolo Bonzini #define SSSR_RFS (1 << 6)
1398aacf8895SPaolo Bonzini #define SSSR_ROR (1 << 7)
1399aacf8895SPaolo Bonzini #define SSSR_RW 0x0080
1400aacf8895SPaolo Bonzini
strongarm_ssp_int_update(StrongARMSSPState * s)1401aacf8895SPaolo Bonzini static void strongarm_ssp_int_update(StrongARMSSPState *s)
1402aacf8895SPaolo Bonzini {
1403aacf8895SPaolo Bonzini int level = 0;
1404aacf8895SPaolo Bonzini
1405aacf8895SPaolo Bonzini level |= (s->sssr & SSSR_ROR);
1406aacf8895SPaolo Bonzini level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE);
1407aacf8895SPaolo Bonzini level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE);
1408aacf8895SPaolo Bonzini qemu_set_irq(s->irq, level);
1409aacf8895SPaolo Bonzini }
1410aacf8895SPaolo Bonzini
strongarm_ssp_fifo_update(StrongARMSSPState * s)1411aacf8895SPaolo Bonzini static void strongarm_ssp_fifo_update(StrongARMSSPState *s)
1412aacf8895SPaolo Bonzini {
1413aacf8895SPaolo Bonzini s->sssr &= ~SSSR_TFS;
1414aacf8895SPaolo Bonzini s->sssr &= ~SSSR_TNF;
1415aacf8895SPaolo Bonzini if (s->sscr[0] & SSCR0_SSE) {
1416aacf8895SPaolo Bonzini if (s->rx_level >= 4) {
1417aacf8895SPaolo Bonzini s->sssr |= SSSR_RFS;
1418aacf8895SPaolo Bonzini } else {
1419aacf8895SPaolo Bonzini s->sssr &= ~SSSR_RFS;
1420aacf8895SPaolo Bonzini }
1421aacf8895SPaolo Bonzini if (s->rx_level) {
1422aacf8895SPaolo Bonzini s->sssr |= SSSR_RNE;
1423aacf8895SPaolo Bonzini } else {
1424aacf8895SPaolo Bonzini s->sssr &= ~SSSR_RNE;
1425aacf8895SPaolo Bonzini }
1426aacf8895SPaolo Bonzini /* TX FIFO is never filled, so it is always in underrun
1427aacf8895SPaolo Bonzini condition if SSP is enabled */
1428aacf8895SPaolo Bonzini s->sssr |= SSSR_TFS;
1429aacf8895SPaolo Bonzini s->sssr |= SSSR_TNF;
1430aacf8895SPaolo Bonzini }
1431aacf8895SPaolo Bonzini
1432aacf8895SPaolo Bonzini strongarm_ssp_int_update(s);
1433aacf8895SPaolo Bonzini }
1434aacf8895SPaolo Bonzini
strongarm_ssp_read(void * opaque,hwaddr addr,unsigned size)1435aacf8895SPaolo Bonzini static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
1436aacf8895SPaolo Bonzini unsigned size)
1437aacf8895SPaolo Bonzini {
1438aacf8895SPaolo Bonzini StrongARMSSPState *s = opaque;
1439aacf8895SPaolo Bonzini uint32_t retval;
1440aacf8895SPaolo Bonzini
1441aacf8895SPaolo Bonzini switch (addr) {
1442aacf8895SPaolo Bonzini case SSCR0:
1443aacf8895SPaolo Bonzini return s->sscr[0];
1444aacf8895SPaolo Bonzini case SSCR1:
1445aacf8895SPaolo Bonzini return s->sscr[1];
1446aacf8895SPaolo Bonzini case SSSR:
1447aacf8895SPaolo Bonzini return s->sssr;
1448aacf8895SPaolo Bonzini case SSDR:
1449aacf8895SPaolo Bonzini if (~s->sscr[0] & SSCR0_SSE) {
1450aacf8895SPaolo Bonzini return 0xffffffff;
1451aacf8895SPaolo Bonzini }
1452aacf8895SPaolo Bonzini if (s->rx_level < 1) {
14535e5deca1SManos Pitsidianakis trace_strongarm_ssp_read_underrun();
1454aacf8895SPaolo Bonzini return 0xffffffff;
1455aacf8895SPaolo Bonzini }
1456aacf8895SPaolo Bonzini s->rx_level--;
1457aacf8895SPaolo Bonzini retval = s->rx_fifo[s->rx_start++];
1458aacf8895SPaolo Bonzini s->rx_start &= 0x7;
1459aacf8895SPaolo Bonzini strongarm_ssp_fifo_update(s);
1460aacf8895SPaolo Bonzini return retval;
1461aacf8895SPaolo Bonzini default:
14625e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
14635e5deca1SManos Pitsidianakis "%s: Bad ssp register read 0x"HWADDR_FMT_plx"\n",
14645e5deca1SManos Pitsidianakis __func__, addr);
1465aacf8895SPaolo Bonzini break;
1466aacf8895SPaolo Bonzini }
1467aacf8895SPaolo Bonzini return 0;
1468aacf8895SPaolo Bonzini }
1469aacf8895SPaolo Bonzini
strongarm_ssp_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)1470aacf8895SPaolo Bonzini static void strongarm_ssp_write(void *opaque, hwaddr addr,
1471aacf8895SPaolo Bonzini uint64_t value, unsigned size)
1472aacf8895SPaolo Bonzini {
1473aacf8895SPaolo Bonzini StrongARMSSPState *s = opaque;
1474aacf8895SPaolo Bonzini
1475aacf8895SPaolo Bonzini switch (addr) {
1476aacf8895SPaolo Bonzini case SSCR0:
1477aacf8895SPaolo Bonzini s->sscr[0] = value & 0xffbf;
1478aacf8895SPaolo Bonzini if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
14795e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR, "%s: Wrong data size: %i bits\n",
14805e5deca1SManos Pitsidianakis __func__, (int)SSCR0_DSS(value));
1481aacf8895SPaolo Bonzini }
1482aacf8895SPaolo Bonzini if (!(value & SSCR0_SSE)) {
1483aacf8895SPaolo Bonzini s->sssr = 0;
1484aacf8895SPaolo Bonzini s->rx_level = 0;
1485aacf8895SPaolo Bonzini }
1486aacf8895SPaolo Bonzini strongarm_ssp_fifo_update(s);
1487aacf8895SPaolo Bonzini break;
1488aacf8895SPaolo Bonzini
1489aacf8895SPaolo Bonzini case SSCR1:
1490aacf8895SPaolo Bonzini s->sscr[1] = value & 0x2f;
1491aacf8895SPaolo Bonzini if (value & SSCR1_LBM) {
14925e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
14935e5deca1SManos Pitsidianakis "%s: Attempt to use SSP LBM mode\n",
14945e5deca1SManos Pitsidianakis __func__);
1495aacf8895SPaolo Bonzini }
1496aacf8895SPaolo Bonzini strongarm_ssp_fifo_update(s);
1497aacf8895SPaolo Bonzini break;
1498aacf8895SPaolo Bonzini
1499aacf8895SPaolo Bonzini case SSSR:
1500aacf8895SPaolo Bonzini s->sssr &= ~(value & SSSR_RW);
1501aacf8895SPaolo Bonzini strongarm_ssp_int_update(s);
1502aacf8895SPaolo Bonzini break;
1503aacf8895SPaolo Bonzini
1504aacf8895SPaolo Bonzini case SSDR:
1505aacf8895SPaolo Bonzini if (SSCR0_UWIRE(s->sscr[0])) {
1506aacf8895SPaolo Bonzini value &= 0xff;
1507aacf8895SPaolo Bonzini } else
1508aacf8895SPaolo Bonzini /* Note how 32bits overflow does no harm here */
1509aacf8895SPaolo Bonzini value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
1510aacf8895SPaolo Bonzini
1511aacf8895SPaolo Bonzini /* Data goes from here to the Tx FIFO and is shifted out from
1512aacf8895SPaolo Bonzini * there directly to the slave, no need to buffer it.
1513aacf8895SPaolo Bonzini */
1514aacf8895SPaolo Bonzini if (s->sscr[0] & SSCR0_SSE) {
1515aacf8895SPaolo Bonzini uint32_t readval;
1516aacf8895SPaolo Bonzini if (s->sscr[1] & SSCR1_LBM) {
1517aacf8895SPaolo Bonzini readval = value;
1518aacf8895SPaolo Bonzini } else {
1519aacf8895SPaolo Bonzini readval = ssi_transfer(s->bus, value);
1520aacf8895SPaolo Bonzini }
1521aacf8895SPaolo Bonzini
1522aacf8895SPaolo Bonzini if (s->rx_level < 0x08) {
1523aacf8895SPaolo Bonzini s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval;
1524aacf8895SPaolo Bonzini } else {
1525aacf8895SPaolo Bonzini s->sssr |= SSSR_ROR;
1526aacf8895SPaolo Bonzini }
1527aacf8895SPaolo Bonzini }
1528aacf8895SPaolo Bonzini strongarm_ssp_fifo_update(s);
1529aacf8895SPaolo Bonzini break;
1530aacf8895SPaolo Bonzini
1531aacf8895SPaolo Bonzini default:
15325e5deca1SManos Pitsidianakis qemu_log_mask(LOG_GUEST_ERROR,
15335e5deca1SManos Pitsidianakis "%s: Bad ssp register write 0x"HWADDR_FMT_plx"\n",
15345e5deca1SManos Pitsidianakis __func__, addr);
1535aacf8895SPaolo Bonzini break;
1536aacf8895SPaolo Bonzini }
1537aacf8895SPaolo Bonzini }
1538aacf8895SPaolo Bonzini
1539aacf8895SPaolo Bonzini static const MemoryRegionOps strongarm_ssp_ops = {
1540aacf8895SPaolo Bonzini .read = strongarm_ssp_read,
1541aacf8895SPaolo Bonzini .write = strongarm_ssp_write,
1542aacf8895SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
1543aacf8895SPaolo Bonzini };
1544aacf8895SPaolo Bonzini
strongarm_ssp_post_load(void * opaque,int version_id)1545aacf8895SPaolo Bonzini static int strongarm_ssp_post_load(void *opaque, int version_id)
1546aacf8895SPaolo Bonzini {
1547aacf8895SPaolo Bonzini StrongARMSSPState *s = opaque;
1548aacf8895SPaolo Bonzini
1549aacf8895SPaolo Bonzini strongarm_ssp_fifo_update(s);
1550aacf8895SPaolo Bonzini
1551aacf8895SPaolo Bonzini return 0;
1552aacf8895SPaolo Bonzini }
1553aacf8895SPaolo Bonzini
strongarm_ssp_init(Object * obj)15548934515aSxiaoqiang zhao static void strongarm_ssp_init(Object *obj)
1555aacf8895SPaolo Bonzini {
15568934515aSxiaoqiang zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
15570ca81872SAndreas Färber DeviceState *dev = DEVICE(sbd);
15580ca81872SAndreas Färber StrongARMSSPState *s = STRONGARM_SSP(dev);
1559aacf8895SPaolo Bonzini
15600ca81872SAndreas Färber sysbus_init_irq(sbd, &s->irq);
1561aacf8895SPaolo Bonzini
15628934515aSxiaoqiang zhao memory_region_init_io(&s->iomem, obj, &strongarm_ssp_ops, s,
156364bde0f3SPaolo Bonzini "ssp", 0x1000);
15640ca81872SAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
1565aacf8895SPaolo Bonzini
15660ca81872SAndreas Färber s->bus = ssi_create_bus(dev, "ssi");
1567aacf8895SPaolo Bonzini }
1568aacf8895SPaolo Bonzini
strongarm_ssp_reset(DeviceState * dev)1569aacf8895SPaolo Bonzini static void strongarm_ssp_reset(DeviceState *dev)
1570aacf8895SPaolo Bonzini {
15710ca81872SAndreas Färber StrongARMSSPState *s = STRONGARM_SSP(dev);
15720ca81872SAndreas Färber
1573aacf8895SPaolo Bonzini s->sssr = 0x03; /* 3 bit data, SPI, disabled */
1574aacf8895SPaolo Bonzini s->rx_start = 0;
1575aacf8895SPaolo Bonzini s->rx_level = 0;
1576aacf8895SPaolo Bonzini }
1577aacf8895SPaolo Bonzini
1578aacf8895SPaolo Bonzini static const VMStateDescription vmstate_strongarm_ssp_regs = {
1579aacf8895SPaolo Bonzini .name = "strongarm-ssp",
1580aacf8895SPaolo Bonzini .version_id = 0,
1581aacf8895SPaolo Bonzini .minimum_version_id = 0,
1582aacf8895SPaolo Bonzini .post_load = strongarm_ssp_post_load,
1583607ef570SRichard Henderson .fields = (const VMStateField[]) {
1584aacf8895SPaolo Bonzini VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
1585aacf8895SPaolo Bonzini VMSTATE_UINT16(sssr, StrongARMSSPState),
1586aacf8895SPaolo Bonzini VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8),
1587aacf8895SPaolo Bonzini VMSTATE_UINT8(rx_start, StrongARMSSPState),
1588aacf8895SPaolo Bonzini VMSTATE_UINT8(rx_level, StrongARMSSPState),
1589aacf8895SPaolo Bonzini VMSTATE_END_OF_LIST(),
1590aacf8895SPaolo Bonzini },
1591aacf8895SPaolo Bonzini };
1592aacf8895SPaolo Bonzini
strongarm_ssp_class_init(ObjectClass * klass,void * data)1593aacf8895SPaolo Bonzini static void strongarm_ssp_class_init(ObjectClass *klass, void *data)
1594aacf8895SPaolo Bonzini {
1595aacf8895SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
1596aacf8895SPaolo Bonzini
1597aacf8895SPaolo Bonzini dc->desc = "StrongARM SSP controller";
1598*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, strongarm_ssp_reset);
1599aacf8895SPaolo Bonzini dc->vmsd = &vmstate_strongarm_ssp_regs;
1600aacf8895SPaolo Bonzini }
1601aacf8895SPaolo Bonzini
1602aacf8895SPaolo Bonzini static const TypeInfo strongarm_ssp_info = {
16030ca81872SAndreas Färber .name = TYPE_STRONGARM_SSP,
1604aacf8895SPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
1605aacf8895SPaolo Bonzini .instance_size = sizeof(StrongARMSSPState),
16068934515aSxiaoqiang zhao .instance_init = strongarm_ssp_init,
1607aacf8895SPaolo Bonzini .class_init = strongarm_ssp_class_init,
1608aacf8895SPaolo Bonzini };
1609aacf8895SPaolo Bonzini
1610aacf8895SPaolo Bonzini /* Main CPU functions */
sa1110_init(const char * cpu_type)16113cd892daSPhilippe Mathieu-Daudé StrongARMState *sa1110_init(const char *cpu_type)
1612aacf8895SPaolo Bonzini {
1613aacf8895SPaolo Bonzini StrongARMState *s;
1614aacf8895SPaolo Bonzini int i;
1615aacf8895SPaolo Bonzini
1616b45c03f5SMarkus Armbruster s = g_new0(StrongARMState, 1);
1617aacf8895SPaolo Bonzini
1618ba1ba5ccSIgor Mammedov if (strncmp(cpu_type, "sa1110", 6)) {
1619aacf8895SPaolo Bonzini error_report("Machine requires a SA1110 processor.");
1620aacf8895SPaolo Bonzini exit(1);
1621aacf8895SPaolo Bonzini }
1622aacf8895SPaolo Bonzini
1623ba1ba5ccSIgor Mammedov s->cpu = ARM_CPU(cpu_create(cpu_type));
1624aacf8895SPaolo Bonzini
1625aacf8895SPaolo Bonzini s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
16264f071cf9SPeter Maydell qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ),
16274f071cf9SPeter Maydell qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ),
16284f071cf9SPeter Maydell NULL);
1629aacf8895SPaolo Bonzini
1630aacf8895SPaolo Bonzini sysbus_create_varargs("pxa25x-timer", 0x90000000,
1631aacf8895SPaolo Bonzini qdev_get_gpio_in(s->pic, SA_PIC_OSTC0),
1632aacf8895SPaolo Bonzini qdev_get_gpio_in(s->pic, SA_PIC_OSTC1),
1633aacf8895SPaolo Bonzini qdev_get_gpio_in(s->pic, SA_PIC_OSTC2),
1634aacf8895SPaolo Bonzini qdev_get_gpio_in(s->pic, SA_PIC_OSTC3),
1635aacf8895SPaolo Bonzini NULL);
1636aacf8895SPaolo Bonzini
16374e002105SAndreas Färber sysbus_create_simple(TYPE_STRONGARM_RTC, 0x90010000,
1638aacf8895SPaolo Bonzini qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM));
1639aacf8895SPaolo Bonzini
1640aacf8895SPaolo Bonzini s->gpio = strongarm_gpio_init(0x90040000, s->pic);
1641aacf8895SPaolo Bonzini
1642c71e6732SAndreas Färber s->ppc = sysbus_create_varargs(TYPE_STRONGARM_PPC, 0x90060000, NULL);
1643aacf8895SPaolo Bonzini
1644aacf8895SPaolo Bonzini for (i = 0; sa_serial[i].io_base; i++) {
16453e80f690SMarkus Armbruster DeviceState *dev = qdev_new(TYPE_STRONGARM_UART);
16469bca0edbSPeter Maydell qdev_prop_set_chr(dev, "chardev", serial_hd(i));
16473c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1648aacf8895SPaolo Bonzini sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
1649aacf8895SPaolo Bonzini sa_serial[i].io_base);
1650aacf8895SPaolo Bonzini sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
1651aacf8895SPaolo Bonzini qdev_get_gpio_in(s->pic, sa_serial[i].irq));
1652aacf8895SPaolo Bonzini }
1653aacf8895SPaolo Bonzini
16540ca81872SAndreas Färber s->ssp = sysbus_create_varargs(TYPE_STRONGARM_SSP, 0x80070000,
1655aacf8895SPaolo Bonzini qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL);
1656aacf8895SPaolo Bonzini s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi");
1657aacf8895SPaolo Bonzini
1658aacf8895SPaolo Bonzini return s;
1659aacf8895SPaolo Bonzini }
1660aacf8895SPaolo Bonzini
strongarm_register_types(void)1661aacf8895SPaolo Bonzini static void strongarm_register_types(void)
1662aacf8895SPaolo Bonzini {
1663aacf8895SPaolo Bonzini type_register_static(&strongarm_pic_info);
1664aacf8895SPaolo Bonzini type_register_static(&strongarm_rtc_sysbus_info);
1665aacf8895SPaolo Bonzini type_register_static(&strongarm_gpio_info);
1666aacf8895SPaolo Bonzini type_register_static(&strongarm_ppc_info);
1667aacf8895SPaolo Bonzini type_register_static(&strongarm_uart_info);
1668aacf8895SPaolo Bonzini type_register_static(&strongarm_ssp_info);
1669aacf8895SPaolo Bonzini }
1670aacf8895SPaolo Bonzini
1671aacf8895SPaolo Bonzini type_init(strongarm_register_types)
1672