Revisión | f28e129682f5758f68a7b4ac2b76a51006a24895 (tree) |
---|---|
Tiempo | 2021-05-27 14:10:23 |
Autor | Yoshinori Sato <ysato@user...> |
Commiter | Yoshinori Sato |
hw/char: Renesas SCI module.
This module supported SCI / SCIa / SCIF.
Hardware manual.
SCI / SCIF
https://www.renesas.com/us/en/doc/products/mpumcu/001/r01uh0457ej0401_sh7751.pdf
SCIa
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
@@ -1,10 +1,12 @@ | ||
1 | 1 | /* |
2 | - * Renesas Serial Communication Interface | |
2 | + * Renesas Serial Communication Interface (SCI / SCIa / SCIF) | |
3 | 3 | * |
4 | 4 | * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware |
5 | 5 | * (Rev.1.40 R01UH0033EJ0140) |
6 | + * And SH7751 Group, SH7751R Group User's Manual: Hardware | |
7 | + * (Rev.4.01 R01UH0457EJ0401) | |
6 | 8 | * |
7 | - * Copyright (c) 2019 Yoshinori Sato | |
9 | + * Copyright (c) 2020 Yoshinori Sato | |
8 | 10 | * |
9 | 11 | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | 12 | * |
@@ -23,15 +25,25 @@ | ||
23 | 25 | |
24 | 26 | #include "qemu/osdep.h" |
25 | 27 | #include "qemu/log.h" |
28 | +#include "qapi/error.h" | |
29 | +#include "qemu-common.h" | |
30 | +#include "hw/hw.h" | |
26 | 31 | #include "hw/irq.h" |
32 | +#include "hw/sysbus.h" | |
27 | 33 | #include "hw/registerfields.h" |
28 | -#include "hw/qdev-properties.h" | |
29 | 34 | #include "hw/qdev-properties-system.h" |
35 | +#include "hw/qdev-clock.h" | |
30 | 36 | #include "hw/char/renesas_sci.h" |
31 | 37 | #include "migration/vmstate.h" |
38 | +#include "qemu/error-report.h" | |
32 | 39 | |
33 | -/* SCI register map */ | |
34 | -REG8(SMR, 0) | |
40 | +/* | |
41 | + * SCI register map | |
42 | + * SCI(a) register size all 8bit. | |
43 | + * SCIF regsister size 8bit and 16bit. | |
44 | + * Allocate 16bit to match the larger one. | |
45 | + */ | |
46 | +REG32(SMR, 0) /* 8bit */ | |
35 | 47 | FIELD(SMR, CKS, 0, 2) |
36 | 48 | FIELD(SMR, MP, 2, 1) |
37 | 49 | FIELD(SMR, STOP, 3, 1) |
@@ -39,263 +51,840 @@ REG8(SMR, 0) | ||
39 | 51 | FIELD(SMR, PE, 5, 1) |
40 | 52 | FIELD(SMR, CHR, 6, 1) |
41 | 53 | FIELD(SMR, CM, 7, 1) |
42 | -REG8(BRR, 1) | |
43 | -REG8(SCR, 2) | |
44 | - FIELD(SCR, CKE, 0, 2) | |
54 | +REG32(BRR, 4) /* 8bit */ | |
55 | +REG32(SCR, 8) | |
56 | + FIELD(SCR, CKE, 0, 2) | |
45 | 57 | FIELD(SCR, TEIE, 2, 1) |
46 | 58 | FIELD(SCR, MPIE, 3, 1) |
59 | + FIELD(SCR, REIE, 3, 1) | |
47 | 60 | FIELD(SCR, RE, 4, 1) |
48 | 61 | FIELD(SCR, TE, 5, 1) |
49 | 62 | FIELD(SCR, RIE, 6, 1) |
50 | 63 | FIELD(SCR, TIE, 7, 1) |
51 | -REG8(TDR, 3) | |
52 | -REG8(SSR, 4) | |
64 | +REG32(TDR, 12) /* 8bit */ | |
65 | +REG32(SSR, 16) /* 8bit */ | |
53 | 66 | FIELD(SSR, MPBT, 0, 1) |
54 | 67 | FIELD(SSR, MPB, 1, 1) |
55 | 68 | FIELD(SSR, TEND, 2, 1) |
56 | - FIELD(SSR, ERR, 3, 3) | |
69 | + FIELD(SSR, ERR, 3, 3) | |
57 | 70 | FIELD(SSR, PER, 3, 1) |
58 | 71 | FIELD(SSR, FER, 4, 1) |
59 | 72 | FIELD(SSR, ORER, 5, 1) |
60 | 73 | FIELD(SSR, RDRF, 6, 1) |
61 | 74 | FIELD(SSR, TDRE, 7, 1) |
62 | -REG8(RDR, 5) | |
63 | -REG8(SCMR, 6) | |
75 | +REG32(FSR, 16) | |
76 | + FIELD(FSR, DR, 0, 1) | |
77 | + FIELD(FSR, RDF, 1, 1) | |
78 | + FIELD(FSR, RDF_DR, 0, 2) | |
79 | + FIELD(FSR, PER, 2, 1) | |
80 | + FIELD(FSR, FER, 3, 1) | |
81 | + FIELD(FSR, BRK, 4, 1) | |
82 | + FIELD(FSR, TDFE, 5, 1) | |
83 | + FIELD(FSR, TEND, 6, 1) | |
84 | + FIELD(FSR, ER, 7, 1) | |
85 | + FIELD(FSR, FERn, 8, 4) | |
86 | + FIELD(FSR, PERn, 12, 4) | |
87 | +REG32(RDR, 20) /* 8bit */ | |
88 | +REG32(SCMR, 24) /* 8bit */ | |
64 | 89 | FIELD(SCMR, SMIF, 0, 1) |
65 | 90 | FIELD(SCMR, SINV, 2, 1) |
66 | 91 | FIELD(SCMR, SDIR, 3, 1) |
67 | 92 | FIELD(SCMR, BCP2, 7, 1) |
68 | -REG8(SEMR, 7) | |
93 | +REG32(FCR, 24) | |
94 | + FIELD(FCR, LOOP, 0, 1) | |
95 | + FIELD(FCR, RFRST, 1, 1) | |
96 | + FIELD(FCR, TFRST, 2, 1) | |
97 | + FIELD(FCR, MCE, 3, 1) | |
98 | + FIELD(FCR, TTRG, 4, 2) | |
99 | + FIELD(FCR, RTRG, 6, 2) | |
100 | + FIELD(FCR, RSTRG, 8, 3) | |
101 | +REG32(SEMR, 28) /* 8bit */ | |
69 | 102 | FIELD(SEMR, ACS0, 0, 1) |
70 | 103 | FIELD(SEMR, ABCS, 4, 1) |
104 | +REG32(FDR, 28) | |
105 | + FIELD(FDR, Rn, 0, 4) | |
106 | + FIELD(FDR, Tn, 8, 4) | |
107 | +REG32(SPTR, 32) | |
108 | + FIELD(SPTR, SPB2DT, 0, 1) | |
109 | + FIELD(SPTR, SPB2IO, 1, 1) | |
110 | + FIELD(SPTR, SCKDT, 2, 1) | |
111 | + FIELD(SPTR, SCKIO, 3, 1) | |
112 | + FIELD(SPTR, CTSDT, 4, 1) | |
113 | + FIELD(SPTR, CTSIO, 5, 1) | |
114 | + FIELD(SPTR, RTSDT, 6, 1) | |
115 | + FIELD(SPTR, RTSIO, 7, 1) | |
116 | + FIELD(SPTR, EIO, 7, 1) | |
117 | +REG32(LSR, 36) | |
118 | + FIELD(LSR, ORER, 0, 1) | |
119 | + | |
120 | +#define SCIF_FIFO_DEPTH 16 | |
71 | 121 | |
72 | -static int can_receive(void *opaque) | |
122 | +static const int sci_rtrg[] = {1, 4, 8, 14}; | |
123 | + | |
124 | +static void update_event_time(RenesasSCIBaseState *sci, int evt, int64_t t) | |
73 | 125 | { |
74 | - RSCIState *sci = RSCI(opaque); | |
75 | - if (sci->rx_next > qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { | |
76 | - return 0; | |
126 | + if (t > 0) { | |
127 | + t += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
128 | + sci->event[evt].time = t; | |
129 | + if (timer_expire_time_ns(sci->event_timer) > t) { | |
130 | + timer_mod(sci->event_timer, t); | |
131 | + } | |
77 | 132 | } else { |
78 | - return FIELD_EX8(sci->scr, SCR, RE); | |
133 | + sci->event[evt].time = 0; | |
134 | + } | |
135 | +} | |
136 | + | |
137 | +static void sci_irq(RenesasSCIBaseState *sci_common, int req) | |
138 | +{ | |
139 | + int irq = 0; | |
140 | + int rie; | |
141 | + int tie; | |
142 | + RenesasSCIState *sci = RENESAS_SCI(sci_common); | |
143 | + | |
144 | + rie = FIELD_EX16(sci_common->scr, SCR, RIE); | |
145 | + tie = FIELD_EX16(sci_common->scr, SCR, TIE); | |
146 | + switch (req) { | |
147 | + case ERI: | |
148 | + irq = rie && (FIELD_EX16(sci_common->Xsr, SSR, ERR) != 0); | |
149 | + break; | |
150 | + case RXI: | |
151 | + irq = FIELD_EX16(sci_common->Xsr, SSR, RDRF) && rie && | |
152 | + !FIELD_EX16(sci->sptr, SPTR, EIO); | |
153 | + break; | |
154 | + case TXI: | |
155 | + irq = FIELD_EX16(sci_common->Xsr, SSR, TDRE) && tie; | |
156 | + break; | |
157 | + case BRI_TEI: | |
158 | + irq = FIELD_EX16(sci_common->Xsr, SSR, TEND) && | |
159 | + FIELD_EX16(sci_common->scr, SCR, TEIE); | |
160 | + break; | |
79 | 161 | } |
162 | + qemu_set_irq(sci_common->irq[req], irq); | |
80 | 163 | } |
81 | 164 | |
82 | -static void receive(void *opaque, const uint8_t *buf, int size) | |
165 | +static void scia_irq(RenesasSCIBaseState *sci, int req) | |
83 | 166 | { |
84 | - RSCIState *sci = RSCI(opaque); | |
85 | - sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime; | |
86 | - if (FIELD_EX8(sci->ssr, SSR, RDRF) || size > 1) { | |
87 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, ORER, 1); | |
88 | - if (FIELD_EX8(sci->scr, SCR, RIE)) { | |
89 | - qemu_set_irq(sci->irq[ERI], 1); | |
167 | + int irq = 0; | |
168 | + int rie; | |
169 | + int tie; | |
170 | + | |
171 | + rie = FIELD_EX16(sci->scr, SCR, RIE); | |
172 | + tie = FIELD_EX16(sci->scr, SCR, TIE); | |
173 | + switch (req) { | |
174 | + case ERI: | |
175 | + irq = (FIELD_EX16(sci->Xsr, SSR, ERR) != 0) && rie; | |
176 | + qemu_set_irq(sci->irq[req], irq); | |
177 | + break; | |
178 | + case RXI: | |
179 | + if (FIELD_EX16(sci->Xsr, SSR, RDRF) && rie) { | |
180 | + qemu_irq_pulse(sci->irq[req]); | |
90 | 181 | } |
91 | - } else { | |
92 | - sci->rdr = buf[0]; | |
93 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, RDRF, 1); | |
94 | - if (FIELD_EX8(sci->scr, SCR, RIE)) { | |
95 | - qemu_irq_pulse(sci->irq[RXI]); | |
182 | + break; | |
183 | + case TXI: | |
184 | + if (FIELD_EX16(sci->Xsr, SSR, TDRE) && tie) { | |
185 | + qemu_irq_pulse(sci->irq[req]); | |
186 | + } | |
187 | + break; | |
188 | + case BRI_TEI: | |
189 | + irq = FIELD_EX16(sci->Xsr, SSR, TEND) && | |
190 | + FIELD_EX16(sci->scr, SCR, TEIE); | |
191 | + qemu_set_irq(sci->irq[req], irq); | |
192 | + break; | |
193 | + } | |
194 | +} | |
195 | + | |
196 | +static void scif_irq(RenesasSCIBaseState *sci, int req) | |
197 | +{ | |
198 | + int irq = 0; | |
199 | + int rie; | |
200 | + int reie; | |
201 | + int tie; | |
202 | + | |
203 | + rie = FIELD_EX16(sci->scr, SCR, RIE); | |
204 | + reie = FIELD_EX16(sci->scr, SCR, REIE); | |
205 | + tie = FIELD_EX16(sci->scr, SCR, TIE); | |
206 | + switch (req) { | |
207 | + case ERI: | |
208 | + irq = (rie || reie) && FIELD_EX16(sci->Xsr, FSR, ER); | |
209 | + break; | |
210 | + case RXI: | |
211 | + irq = (FIELD_EX16(sci->Xsr, FSR, RDF_DR) != 0) && rie; | |
212 | + break; | |
213 | + case TXI: | |
214 | + irq = FIELD_EX16(sci->Xsr, FSR, TDFE) & tie; | |
215 | + break; | |
216 | + case BRI_TEI: | |
217 | + irq = (rie || reie) && FIELD_EX16(sci->Xsr, FSR, BRK); | |
218 | + break; | |
219 | + } | |
220 | + qemu_set_irq(sci->irq[req], irq); | |
221 | +} | |
222 | + | |
223 | +static int sci_can_receive(void *opaque) | |
224 | +{ | |
225 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
226 | + int fifo_free = 0; | |
227 | + if (clock_is_enabled(sci->pck) && FIELD_EX16(sci->scr, SCR, RE)) { | |
228 | + /* Receiver enabled */ | |
229 | + fifo_free = fifo8_num_free(&sci->rxfifo); | |
230 | + } | |
231 | + return fifo_free; | |
232 | +} | |
233 | + | |
234 | +static void sci_receive(void *opaque, const uint8_t *buf, int size) | |
235 | +{ | |
236 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
237 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_GET_CLASS(sci); | |
238 | + fifo8_push_all(&sci->rxfifo, buf, size); | |
239 | + if (sci->event[RXNEXT].time == 0) { | |
240 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, RDRF, 1); | |
241 | + update_event_time(sci, RXNEXT, sci->trtime); | |
242 | + rc->irq_fn(sci, RXI); | |
243 | + } | |
244 | +} | |
245 | + | |
246 | +static int scif_can_receive(void *opaque) | |
247 | +{ | |
248 | + RenesasSCIFState *scif = RENESAS_SCIF(opaque); | |
249 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
250 | + int fifo_free = 0; | |
251 | + if (clock_is_enabled(sci->pck) && FIELD_EX16(sci->scr, SCR, RE)) { | |
252 | + /* Receiver enabled */ | |
253 | + fifo_free = fifo8_num_free(&sci->rxfifo); | |
254 | + if (fifo_free == 0) { | |
255 | + /* FIFO overrun */ | |
256 | + scif->lsr = FIELD_DP16(scif->lsr, LSR, ORER, 1); | |
257 | + scif_irq(sci, ERI); | |
258 | + } | |
259 | + } | |
260 | + return fifo_free; | |
261 | +} | |
262 | + | |
263 | +static void scif_receive(void *opaque, const uint8_t *buf, int size) | |
264 | +{ | |
265 | + RenesasSCIFState *scif = RENESAS_SCIF(opaque); | |
266 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
267 | + int rtrg; | |
268 | + | |
269 | + fifo8_push_all(&sci->rxfifo, buf, size); | |
270 | + if (sci->event[RXNEXT].time == 0) { | |
271 | + rtrg = sci_rtrg[FIELD_EX16(scif->fcr, FCR, RTRG)]; | |
272 | + if (fifo8_num_used(&sci->rxfifo) >= rtrg) { | |
273 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, RDF, 1); | |
274 | + } else { | |
275 | + update_event_time(sci, RXTOUT, 15 * sci->etu); | |
96 | 276 | } |
277 | + scif_irq(sci, RXI); | |
97 | 278 | } |
98 | 279 | } |
99 | 280 | |
100 | -static void send_byte(RSCIState *sci) | |
281 | +static void sci_send_byte(RenesasSCIBaseState *sci) | |
101 | 282 | { |
102 | 283 | if (qemu_chr_fe_backend_connected(&sci->chr)) { |
103 | 284 | qemu_chr_fe_write_all(&sci->chr, &sci->tdr, 1); |
104 | 285 | } |
105 | - timer_mod(&sci->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime); | |
106 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 0); | |
107 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1); | |
108 | - qemu_set_irq(sci->irq[TEI], 0); | |
109 | - if (FIELD_EX8(sci->scr, SCR, TIE)) { | |
110 | - qemu_irq_pulse(sci->irq[TXI]); | |
286 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, TEND, 0); | |
287 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, TDRE, 1); | |
288 | +} | |
289 | + | |
290 | +static int transmit_byte(RenesasSCIFState *scif) | |
291 | +{ | |
292 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(scif); | |
293 | + int64_t elapsed; | |
294 | + int byte = 0; | |
295 | + if (sci->tx_start_time > 0) { | |
296 | + elapsed = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sci->tx_start_time; | |
297 | + byte = elapsed / sci->trtime; | |
298 | + if (byte > scif->tdcnt) { | |
299 | + byte = scif->tdcnt; | |
300 | + } | |
111 | 301 | } |
302 | + return byte; | |
112 | 303 | } |
113 | 304 | |
114 | -static void txend(void *opaque) | |
305 | +static int64_t scif_rx_timeout(RenesasSCIBaseState *sci) | |
115 | 306 | { |
116 | - RSCIState *sci = RSCI(opaque); | |
117 | - if (!FIELD_EX8(sci->ssr, SSR, TDRE)) { | |
118 | - send_byte(sci); | |
307 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, DR, 1); | |
308 | + scif_irq(sci, RXI); | |
309 | + return 0; | |
310 | +} | |
311 | + | |
312 | +static int64_t sci_rx_next(RenesasSCIBaseState *sci) | |
313 | +{ | |
314 | + int64_t next_event = 0; | |
315 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_GET_CLASS(sci); | |
316 | + if (FIELD_EX16(sci->Xsr, SSR, RDRF)) { | |
317 | + /* Receiver overrun */ | |
318 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, ORER, 1); | |
319 | + rc->irq_fn(sci, ERI); | |
119 | 320 | } else { |
120 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1); | |
121 | - if (FIELD_EX8(sci->scr, SCR, TEIE)) { | |
122 | - qemu_set_irq(sci->irq[TEI], 1); | |
321 | + if (!fifo8_is_empty(&sci->rxfifo)) { | |
322 | + /* set next event */ | |
323 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, RDRF, 1); | |
324 | + rc->irq_fn(sci, RXI); | |
325 | + next_event = sci->trtime; | |
123 | 326 | } |
124 | 327 | } |
328 | + return next_event; | |
125 | 329 | } |
126 | 330 | |
127 | -static void update_trtime(RSCIState *sci) | |
331 | +static int64_t sci_tx_empty(RenesasSCIBaseState *sci) | |
128 | 332 | { |
129 | - /* char per bits */ | |
130 | - sci->trtime = 8 - FIELD_EX8(sci->smr, SMR, CHR); | |
131 | - sci->trtime += FIELD_EX8(sci->smr, SMR, PE); | |
132 | - sci->trtime += FIELD_EX8(sci->smr, SMR, STOP) + 1; | |
133 | - /* x bit transmit time (32 * divrate * brr) / base freq */ | |
134 | - sci->trtime *= 32 * sci->brr; | |
135 | - sci->trtime *= 1 << (2 * FIELD_EX8(sci->smr, SMR, CKS)); | |
136 | - sci->trtime *= NANOSECONDS_PER_SECOND; | |
137 | - sci->trtime /= sci->input_freq; | |
333 | + int64_t ret = 0; | |
334 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_GET_CLASS(sci); | |
335 | + if (!FIELD_EX16(sci->Xsr, SSR, TDRE)) { | |
336 | + sci_send_byte(sci); | |
337 | + ret = sci->trtime; | |
338 | + rc->irq_fn(sci, TXI); | |
339 | + } else { | |
340 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, TEND, 1); | |
341 | + rc->irq_fn(sci, BRI_TEI); | |
342 | + } | |
343 | + return ret; | |
138 | 344 | } |
139 | 345 | |
140 | -static bool sci_is_tr_enabled(RSCIState *sci) | |
346 | +static int64_t scif_tx_empty(RenesasSCIBaseState *sci) | |
141 | 347 | { |
142 | - return FIELD_EX8(sci->scr, SCR, TE) || FIELD_EX8(sci->scr, SCR, RE); | |
348 | + RenesasSCIFState *scif = RENESAS_SCIF(sci); | |
349 | + scif->tdcnt -= transmit_byte(scif); | |
350 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, TDFE, 1); | |
351 | + scif_irq(sci, TXI); | |
352 | + return 0; | |
143 | 353 | } |
144 | 354 | |
145 | -static void sci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) | |
355 | +static int64_t scif_tx_end(RenesasSCIBaseState *sci) | |
146 | 356 | { |
147 | - RSCIState *sci = RSCI(opaque); | |
357 | + RenesasSCIFState *scif = RENESAS_SCIF(sci); | |
358 | + scif->tdcnt = 0; | |
359 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, TEND, 1); | |
360 | + return 0; | |
361 | +} | |
148 | 362 | |
149 | - switch (offset) { | |
150 | - case A_SMR: | |
151 | - if (!sci_is_tr_enabled(sci)) { | |
152 | - sci->smr = val; | |
153 | - update_trtime(sci); | |
363 | +static void sci_timer_event(void *opaque) | |
364 | +{ | |
365 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
366 | + int64_t now, next, t; | |
367 | + int i; | |
368 | + | |
369 | + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
370 | + next = INT64_MAX; | |
371 | + for (i = 0; i < NR_SCI_EVENT; i++) { | |
372 | + if (sci->event[i].time > 0 && sci->event[i].time <= now) { | |
373 | + t = sci->event[i].handler(sci); | |
374 | + sci->event[i].time = (t > 0) ? now + t : 0; | |
154 | 375 | } |
155 | - break; | |
156 | - case A_BRR: | |
157 | - if (!sci_is_tr_enabled(sci)) { | |
158 | - sci->brr = val; | |
159 | - update_trtime(sci); | |
376 | + if (sci->event[i].time > 0) { | |
377 | + next = MIN(next, sci->event[i].time); | |
160 | 378 | } |
161 | - break; | |
379 | + } | |
380 | + if (next < INT64_MAX) { | |
381 | + timer_mod(sci->event_timer, next); | |
382 | + } else { | |
383 | + timer_del(sci->event_timer); | |
384 | + } | |
385 | +} | |
386 | + | |
387 | +static int static_divrate(RenesasSCIBaseState *sci) | |
388 | +{ | |
389 | + /* SCI / SCIF have static divide rate */ | |
390 | + return 32; | |
391 | +} | |
392 | + | |
393 | +static int scia_divrate(RenesasSCIBaseState *sci) | |
394 | +{ | |
395 | + /* | |
396 | + * SEMR.ABCS = 0 -> 32 | |
397 | + * SEMR.ABCS = 1 -> 16 | |
398 | + */ | |
399 | + RenesasSCIAState *scia = RENESAS_SCIA(sci); | |
400 | + return 16 * (2 - FIELD_EX8(scia->semr, SEMR, ABCS)); | |
401 | +} | |
402 | + | |
403 | +static void update_trtime(RenesasSCIBaseState *sci) | |
404 | +{ | |
405 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_GET_CLASS(sci); | |
406 | + int cks = 1 << (2 * FIELD_EX16(sci->smr, SMR, CKS)); | |
407 | + if (sci->input_freq > 0) { | |
408 | + /* x bit transmit time (divrate * brr) / base freq */ | |
409 | + sci->etu = rc->divrate(sci) * cks; | |
410 | + sci->etu *= sci->brr + 1; | |
411 | + sci->etu *= NANOSECONDS_PER_SECOND; | |
412 | + sci->etu /= sci->input_freq; | |
413 | + | |
414 | + /* char per bits */ | |
415 | + sci->trtime = 8 - FIELD_EX16(sci->smr, SMR, CHR); | |
416 | + sci->trtime += FIELD_EX16(sci->smr, SMR, PE); | |
417 | + sci->trtime += FIELD_EX16(sci->smr, SMR, STOP) + 1 + 1; | |
418 | + sci->trtime *= sci->etu; | |
419 | + } | |
420 | +} | |
421 | + | |
422 | +static void sci_pck_update(void *opaque, ClockEvent evt) | |
423 | +{ | |
424 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
425 | + | |
426 | + sci->input_freq = clock_get_hz(sci->pck); | |
427 | + update_trtime(sci); | |
428 | +} | |
429 | + | |
430 | +#define IS_TR_ENABLED(scr) \ | |
431 | + (FIELD_EX16(scr, SCR, TE) || FIELD_EX16(scr, SCR, RE)) | |
432 | + | |
433 | +static hwaddr map_address(RenesasSCIBaseState *sci, hwaddr addr) | |
434 | +{ | |
435 | + return addr << (2 - sci->regshift); | |
436 | +} | |
437 | + | |
438 | +static void sci_common_write(void *opaque, hwaddr addr, | |
439 | + uint64_t val, unsigned size) | |
440 | +{ | |
441 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
442 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_GET_CLASS(opaque); | |
443 | + switch (addr) { | |
162 | 444 | case A_SCR: |
163 | 445 | sci->scr = val; |
164 | - if (FIELD_EX8(sci->scr, SCR, TE)) { | |
165 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1); | |
166 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1); | |
167 | - if (FIELD_EX8(sci->scr, SCR, TIE)) { | |
168 | - qemu_irq_pulse(sci->irq[TXI]); | |
169 | - } | |
446 | + if (FIELD_EX16(sci->scr, SCR, TE)) { | |
447 | + /* Transmitter enable */ | |
448 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, TDRE, 1); | |
449 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, TEND, 1); | |
450 | + rc->irq_fn(sci, TXI); | |
451 | + rc->irq_fn(sci, BRI_TEI); | |
452 | + } else { | |
453 | + /* Transmitter disable */ | |
454 | + update_event_time(sci, TXEND, 0); | |
455 | + update_event_time(sci, TXEMPTY, 0); | |
456 | + } | |
457 | + break; | |
458 | + case A_SMR: | |
459 | + sci->smr = val; | |
460 | + update_trtime(sci); | |
461 | + break; | |
462 | + case A_BRR: | |
463 | + sci->brr = val; | |
464 | + update_trtime(sci); | |
465 | + break; | |
466 | + default: | |
467 | + qemu_log_mask(LOG_UNIMP, "renesas_sci: Register 0x%" HWADDR_PRIX | |
468 | + " not implemented\n", addr); | |
469 | + } | |
470 | +} | |
471 | + | |
472 | +static void sci_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
473 | +{ | |
474 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
475 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_GET_CLASS(sci); | |
476 | + bool tx_start; | |
477 | + | |
478 | + if (!clock_is_enabled(sci->pck)) { | |
479 | + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCI %d is stopped.\n", | |
480 | + sci->unit); | |
481 | + return ; | |
482 | + } | |
483 | + addr = map_address(sci, addr); | |
484 | + switch (addr) { | |
485 | + case A_TDR: | |
486 | + sci->tdr = val; | |
487 | + break; | |
488 | + case A_SSR: | |
489 | + /* Mask for read only bits */ | |
490 | + sci->Xsr = FIELD_DP16(RENESAS_SCI_BASE(sci)->Xsr, SSR, MPBT, | |
491 | + FIELD_EX16(val, SSR, MPBT)); | |
492 | + sci->Xsr &= (val | 0x07); | |
493 | + /* Clear ERI */ | |
494 | + rc->irq_fn(sci, ERI); | |
495 | + tx_start = FIELD_EX16(sci->read_Xsr, SSR, TDRE) && | |
496 | + !FIELD_EX16(sci->Xsr, SSR, TDRE) && | |
497 | + (FIELD_EX16(sci->Xsr, SSR, ERR) == 0); | |
498 | + if (tx_start) { | |
499 | + sci_send_byte(sci); | |
500 | + update_event_time(sci, TXEMPTY, sci->trtime); | |
501 | + rc->irq_fn(sci, TXI); | |
170 | 502 | } |
171 | - if (!FIELD_EX8(sci->scr, SCR, TEIE)) { | |
172 | - qemu_set_irq(sci->irq[TEI], 0); | |
503 | + break; | |
504 | + case A_SPTR: | |
505 | + RENESAS_SCI(sci)->sptr = val; | |
506 | + break; | |
507 | + default: | |
508 | + sci_common_write(sci, addr, val, size); | |
509 | + } | |
510 | +} | |
511 | + | |
512 | +static void scia_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
513 | +{ | |
514 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
515 | + RenesasSCIAState *scia = RENESAS_SCIA(opaque); | |
516 | + | |
517 | + if (!clock_is_enabled(sci->pck)) { | |
518 | + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCIa %d is stopped.\n", | |
519 | + sci->unit); | |
520 | + return ; | |
521 | + } | |
522 | + addr = map_address(sci, addr); | |
523 | + switch (addr) { | |
524 | + case A_SMR: | |
525 | + if (IS_TR_ENABLED(sci->scr)) { | |
526 | + qemu_log_mask(LOG_GUEST_ERROR, | |
527 | + "reneas_sci: SMR write protected.\n"); | |
528 | + } else { | |
529 | + sci_common_write(sci, addr, val, size); | |
173 | 530 | } |
174 | - if (!FIELD_EX8(sci->scr, SCR, RIE)) { | |
175 | - qemu_set_irq(sci->irq[ERI], 0); | |
531 | + break; | |
532 | + case A_BRR: | |
533 | + if (IS_TR_ENABLED(sci->scr)) { | |
534 | + qemu_log_mask(LOG_GUEST_ERROR, | |
535 | + "reneas_sci: BRR write protected.\n"); | |
536 | + break; | |
537 | + } else { | |
538 | + sci_common_write(sci, addr, val, size); | |
176 | 539 | } |
177 | 540 | break; |
178 | 541 | case A_TDR: |
179 | 542 | sci->tdr = val; |
180 | - if (FIELD_EX8(sci->ssr, SSR, TEND)) { | |
181 | - send_byte(sci); | |
543 | + if (FIELD_EX16(sci->Xsr, SSR, TEND)) { | |
544 | + update_event_time(sci, TXEMPTY, sci->trtime); | |
545 | + sci_send_byte(sci); | |
182 | 546 | } else { |
183 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 0); | |
547 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, TDRE, 0); | |
184 | 548 | } |
549 | + scia_irq(sci, TXI); | |
550 | + scia_irq(sci, BRI_TEI); | |
185 | 551 | break; |
186 | 552 | case A_SSR: |
187 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, MPBT, | |
188 | - FIELD_EX8(val, SSR, MPBT)); | |
189 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, ERR, | |
190 | - FIELD_EX8(val, SSR, ERR) & 0x07); | |
191 | - if (FIELD_EX8(sci->read_ssr, SSR, ERR) && | |
192 | - FIELD_EX8(sci->ssr, SSR, ERR) == 0) { | |
193 | - qemu_set_irq(sci->irq[ERI], 0); | |
194 | - } | |
195 | - break; | |
196 | - case A_RDR: | |
197 | - qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: RDR is read only.\n"); | |
553 | + /* Mask for read only bits */ | |
554 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, MPBT, | |
555 | + FIELD_EX16(val, SSR, MPBT)); | |
556 | + sci->Xsr &= (val | 0xc7); | |
557 | + /* Clear ERI */ | |
558 | + scia_irq(sci, ERI); | |
198 | 559 | break; |
199 | 560 | case A_SCMR: |
200 | - sci->scmr = val; break; | |
201 | - case A_SEMR: /* SEMR */ | |
202 | - sci->semr = val; break; | |
561 | + scia->scmr = val; | |
562 | + break; | |
563 | + case A_SEMR: | |
564 | + scia->semr = val; | |
565 | + break; | |
203 | 566 | default: |
204 | - qemu_log_mask(LOG_UNIMP, "renesas_sci: Register 0x%" HWADDR_PRIX " " | |
205 | - "not implemented\n", | |
206 | - offset); | |
567 | + sci_common_write(sci, addr, val, size); | |
568 | + break; | |
207 | 569 | } |
208 | 570 | } |
209 | 571 | |
210 | -static uint64_t sci_read(void *opaque, hwaddr offset, unsigned size) | |
572 | +static void scif_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
211 | 573 | { |
212 | - RSCIState *sci = RSCI(opaque); | |
574 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
575 | + RenesasSCIFState *scif = RENESAS_SCIF(opaque); | |
576 | + int txtrg; | |
577 | + int rxtrg; | |
578 | + uint16_t ssr_mask; | |
579 | + uint8_t txd; | |
580 | + | |
581 | + if (!clock_is_enabled(sci->pck)) { | |
582 | + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCIF %d is stopped.\n", | |
583 | + sci->unit); | |
584 | + return ; | |
585 | + } | |
586 | + txtrg = 1 << (3 - FIELD_EX16(scif->fcr, FCR, TTRG)); | |
587 | + addr = map_address(sci, addr); | |
588 | + switch (addr) { | |
589 | + case A_SCR: | |
590 | + sci->scr = val; | |
591 | + if (FIELD_EX16(sci->scr, SCR, TE)) { | |
592 | + /* Transmitter enable */ | |
593 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, TEND, 1); | |
594 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, TDFE, 1); | |
595 | + sci->tx_start_time = 0; | |
596 | + scif_irq(sci, TXI); | |
597 | + } else { | |
598 | + /* Transmitter disable */ | |
599 | + update_event_time(sci, TXEND, 0); | |
600 | + update_event_time(sci, TXEMPTY, 0); | |
601 | + } | |
602 | + break; | |
603 | + case A_TDR: | |
604 | + if (sci->tx_start_time > 0) { | |
605 | + scif->tdcnt -= transmit_byte(scif); | |
606 | + } else { | |
607 | + sci->tx_start_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
608 | + } | |
609 | + if (scif->tdcnt >= SCIF_FIFO_DEPTH) { | |
610 | + break; | |
611 | + } | |
612 | + txd = val; | |
613 | + if (qemu_chr_fe_backend_connected(&sci->chr)) { | |
614 | + qemu_chr_fe_write_all(&sci->chr, &txd, 1); | |
615 | + } | |
616 | + if (FIELD_EX16(scif->fcr, FCR, LOOP) && scif_can_receive(sci) > 0) { | |
617 | + /* Loopback mode */ | |
618 | + scif_receive(sci, &txd, 1); | |
619 | + } | |
620 | + scif->tdcnt++; | |
621 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, TEND, 0); | |
622 | + update_event_time(sci, TXEND, scif->tdcnt); | |
623 | + if (scif->tdcnt > txtrg) { | |
624 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, TDFE, 0); | |
625 | + update_event_time(sci, TXEMPTY, scif->tdcnt - txtrg + 1); | |
626 | + scif_irq(sci, TXI); | |
627 | + } | |
628 | + break; | |
629 | + case A_FSR: | |
630 | + rxtrg = sci_rtrg[FIELD_EX16(scif->fcr, FCR, RTRG)]; | |
631 | + ssr_mask = ~(sci->read_Xsr & 0xf3); | |
632 | + scif->tdcnt -= transmit_byte(scif); | |
633 | + if (scif->tdcnt < txtrg) { | |
634 | + ssr_mask = FIELD_DP16(ssr_mask, FSR, TDFE, 1); | |
635 | + } | |
636 | + if (fifo8_num_used(&sci->rxfifo) >= rxtrg) { | |
637 | + ssr_mask = FIELD_DP16(ssr_mask, FSR, RDF, 1); | |
638 | + } | |
639 | + sci->Xsr &= (val | ssr_mask); | |
640 | + scif_irq(sci, ERI); | |
641 | + scif_irq(sci, RXI); | |
642 | + scif_irq(sci, TXI); | |
643 | + break; | |
644 | + case A_FCR: | |
645 | + scif->fcr = val; | |
646 | + if (FIELD_EX16(scif->fcr, FCR, RFRST)) { | |
647 | + fifo8_reset(&sci->rxfifo); | |
648 | + update_event_time(sci, RXTOUT, 0); | |
649 | + update_event_time(sci, RXNEXT, 0); | |
650 | + } | |
651 | + if (FIELD_EX16(scif->fcr, FCR, TFRST)) { | |
652 | + scif->tdcnt = 0; | |
653 | + } | |
654 | + break; | |
655 | + case A_FDR: | |
656 | + qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: FDR is read only.\n"); | |
657 | + break; | |
658 | + case A_SPTR: | |
659 | + scif->sptr = val; | |
660 | + break; | |
661 | + case A_LSR: | |
662 | + if (FIELD_EX16(scif->read_lsr, LSR, ORER) != 1) { | |
663 | + val = FIELD_DP16(val, LSR, ORER, 1); | |
664 | + } | |
665 | + scif->lsr &= val; | |
666 | + scif_irq(sci, ERI); | |
667 | + break; | |
668 | + default: | |
669 | + sci_common_write(sci, addr, val, size); | |
670 | + break; | |
671 | + } | |
672 | +} | |
213 | 673 | |
214 | - switch (offset) { | |
674 | +static uint64_t sci_common_read(void *opaque, hwaddr addr, unsigned size) | |
675 | +{ | |
676 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
677 | + switch (addr) { | |
215 | 678 | case A_SMR: |
216 | 679 | return sci->smr; |
217 | 680 | case A_BRR: |
218 | 681 | return sci->brr; |
219 | 682 | case A_SCR: |
220 | 683 | return sci->scr; |
221 | - case A_TDR: | |
222 | - return sci->tdr; | |
223 | - case A_SSR: | |
224 | - sci->read_ssr = sci->ssr; | |
225 | - return sci->ssr; | |
684 | + case A_FSR: /* A_SSR */ | |
685 | + sci->read_Xsr = sci->Xsr; | |
686 | + return sci->Xsr; | |
226 | 687 | case A_RDR: |
227 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, RDRF, 0); | |
228 | - return sci->rdr; | |
229 | - case A_SCMR: | |
230 | - return sci->scmr; | |
231 | - case A_SEMR: | |
232 | - return sci->semr; | |
688 | + if (fifo8_num_used(&sci->rxfifo) > 0) { | |
689 | + return fifo8_pop(&sci->rxfifo); | |
690 | + } else { | |
691 | + return 0xff; | |
692 | + } | |
233 | 693 | default: |
234 | 694 | qemu_log_mask(LOG_UNIMP, "renesas_sci: Register 0x%" HWADDR_PRIX |
235 | - " not implemented.\n", offset); | |
695 | + " not implemented.\n", addr); | |
236 | 696 | } |
237 | 697 | return UINT64_MAX; |
238 | 698 | } |
239 | 699 | |
240 | -static const MemoryRegionOps sci_ops = { | |
241 | - .write = sci_write, | |
242 | - .read = sci_read, | |
243 | - .endianness = DEVICE_NATIVE_ENDIAN, | |
244 | - .impl.max_access_size = 1, | |
245 | - .valid.max_access_size = 1, | |
246 | -}; | |
700 | +static uint64_t sci_read(void *opaque, hwaddr addr, unsigned size) | |
701 | +{ | |
702 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
703 | + addr = map_address(sci, addr); | |
704 | + | |
705 | + if (clock_is_enabled(sci->pck)) { | |
706 | + switch (addr) { | |
707 | + case A_TDR: | |
708 | + return sci->tdr; | |
709 | + case A_SPTR: | |
710 | + return RENESAS_SCI(sci)->sptr; | |
711 | + default: | |
712 | + return sci_common_read(sci, addr, size); | |
713 | + } | |
714 | + } else { | |
715 | + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCI %d is stopped.\n", | |
716 | + sci->unit); | |
717 | + } | |
718 | + return UINT64_MAX; | |
719 | +} | |
247 | 720 | |
248 | -static void rsci_reset(DeviceState *dev) | |
721 | +static uint64_t scia_read(void *opaque, hwaddr addr, unsigned size) | |
249 | 722 | { |
250 | - RSCIState *sci = RSCI(dev); | |
251 | - sci->smr = sci->scr = 0x00; | |
252 | - sci->brr = 0xff; | |
253 | - sci->tdr = 0xff; | |
254 | - sci->rdr = 0x00; | |
255 | - sci->ssr = 0x84; | |
256 | - sci->scmr = 0x00; | |
257 | - sci->semr = 0x00; | |
258 | - sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
723 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
724 | + RenesasSCIAState *scia = RENESAS_SCIA(opaque); | |
725 | + | |
726 | + if (clock_is_enabled(sci->pck)) { | |
727 | + addr = map_address(sci, addr); | |
728 | + switch (addr) { | |
729 | + case A_TDR: | |
730 | + return sci->tdr; | |
731 | + case A_RDR: | |
732 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, RDRF, 0); | |
733 | + return fifo8_pop(&sci->rxfifo); | |
734 | + case A_SCMR: | |
735 | + return scia->scmr; | |
736 | + default: | |
737 | + return sci_common_read(sci, addr, size); | |
738 | + } | |
739 | + } else { | |
740 | + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCIa %d is stopped.\n", | |
741 | + sci->unit); | |
742 | + } | |
743 | + return UINT64_MAX; | |
744 | +} | |
745 | + | |
746 | +static uint64_t scif_read(void *opaque, hwaddr addr, unsigned size) | |
747 | +{ | |
748 | + RenesasSCIFState *scif = RENESAS_SCIF(opaque); | |
749 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
750 | + uint64_t ret; | |
751 | + | |
752 | + if (clock_is_enabled(sci->pck)) { | |
753 | + addr = map_address(sci, addr); | |
754 | + switch (addr) { | |
755 | + case A_FCR: | |
756 | + return scif->fcr & 0x7ff; | |
757 | + case A_FDR: | |
758 | + ret = 0; | |
759 | + ret = FIELD_DP16(ret, FDR, Rn, fifo8_num_used(&sci->rxfifo)); | |
760 | + ret = FIELD_DP16(ret, FDR, Tn, scif->tdcnt - transmit_byte(scif)); | |
761 | + return ret; | |
762 | + case A_SPTR: | |
763 | + return scif->sptr; | |
764 | + case A_LSR: | |
765 | + scif->read_lsr = scif->lsr; | |
766 | + return scif->lsr; | |
767 | + default: | |
768 | + return sci_common_read(sci, addr, size); | |
769 | + } | |
770 | + } else { | |
771 | + qemu_log_mask(LOG_GUEST_ERROR, "renesas_sci: SCIF %d is stopped.\n", | |
772 | + sci->unit); | |
773 | + } | |
774 | + return UINT64_MAX; | |
775 | +} | |
776 | + | |
777 | +static void rsci_common_init(Object *obj) | |
778 | +{ | |
779 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(obj); | |
780 | + SysBusDevice *d = SYS_BUS_DEVICE(obj); | |
781 | + int i; | |
782 | + | |
783 | + for (i = 0; i < SCI_NR_IRQ; i++) { | |
784 | + sysbus_init_irq(d, &sci->irq[i]); | |
785 | + } | |
786 | + fifo8_create(&sci->rxfifo, SCIF_FIFO_DEPTH); | |
787 | + sci->event_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sci_timer_event, sci); | |
788 | + sci->pck = qdev_init_clock_in(DEVICE(d), "pck", | |
789 | + sci_pck_update, sci, ClockUpdate); | |
259 | 790 | } |
260 | 791 | |
261 | 792 | static void sci_event(void *opaque, QEMUChrEvent event) |
262 | 793 | { |
263 | - RSCIState *sci = RSCI(opaque); | |
794 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
795 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_GET_CLASS(sci); | |
796 | + if (clock_is_enabled(sci->pck) && event == CHR_EVENT_BREAK) { | |
797 | + sci->Xsr = FIELD_DP16(sci->Xsr, SSR, FER, 1); | |
798 | + rc->irq_fn(sci, BRI_TEI); | |
799 | + } | |
800 | +} | |
801 | + | |
802 | +static void scif_event(void *opaque, QEMUChrEvent event) | |
803 | +{ | |
804 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(opaque); | |
264 | 805 | if (event == CHR_EVENT_BREAK) { |
265 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, FER, 1); | |
266 | - if (FIELD_EX8(sci->scr, SCR, RIE)) { | |
267 | - qemu_set_irq(sci->irq[ERI], 1); | |
268 | - } | |
806 | + sci->Xsr = FIELD_DP16(sci->Xsr, FSR, BRK, 1); | |
807 | + scif_irq(sci, BRI_TEI); | |
269 | 808 | } |
270 | 809 | } |
271 | 810 | |
272 | -static void rsci_realize(DeviceState *dev, Error **errp) | |
811 | +static void rsci_common_realize(DeviceState *dev, Error **errp) | |
273 | 812 | { |
274 | - RSCIState *sci = RSCI(dev); | |
813 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(dev); | |
275 | 814 | |
276 | - if (sci->input_freq == 0) { | |
815 | + if (sci->regshift != 8 && sci->regshift != 16 && sci->regshift != 32) { | |
277 | 816 | qemu_log_mask(LOG_GUEST_ERROR, |
278 | - "renesas_sci: input-freq property must be set."); | |
817 | + "renesas_sci: Invalid register size."); | |
279 | 818 | return; |
280 | 819 | } |
281 | - qemu_chr_fe_set_handlers(&sci->chr, can_receive, receive, | |
282 | - sci_event, NULL, sci, NULL, true); | |
820 | + | |
821 | + sci->smr = sci->scr = 0x00; | |
822 | + sci->brr = 0xff; | |
823 | + sci->tdr = 0xff; | |
824 | + sci->Xsr = 0x84; | |
825 | + update_trtime(sci); | |
826 | + | |
283 | 827 | } |
284 | 828 | |
285 | -static void rsci_init(Object *obj) | |
829 | +static void register_mmio(RenesasSCIBaseState *sci, int size) | |
286 | 830 | { |
287 | - SysBusDevice *d = SYS_BUS_DEVICE(obj); | |
288 | - RSCIState *sci = RSCI(obj); | |
289 | - int i; | |
831 | + SysBusDevice *d = SYS_BUS_DEVICE(sci); | |
832 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_GET_CLASS(sci); | |
290 | 833 | |
291 | - memory_region_init_io(&sci->memory, OBJECT(sci), &sci_ops, | |
292 | - sci, "renesas-sci", 0x8); | |
834 | + memory_region_init_io(&sci->memory, OBJECT(sci), rc->ops, | |
835 | + sci, "renesas-sci", size); | |
293 | 836 | sysbus_init_mmio(d, &sci->memory); |
837 | + memory_region_init_alias(&sci->memory_p4, NULL, "renesas-sci-p4", | |
838 | + &sci->memory, 0, size); | |
839 | + sysbus_init_mmio(d, &sci->memory_p4); | |
840 | + memory_region_init_alias(&sci->memory_a7, NULL, "renesas-sci-a7", | |
841 | + &sci->memory, 0, size); | |
842 | + sysbus_init_mmio(d, &sci->memory_a7); | |
843 | +} | |
294 | 844 | |
295 | - for (i = 0; i < SCI_NR_IRQ; i++) { | |
296 | - sysbus_init_irq(d, &sci->irq[i]); | |
297 | - } | |
298 | - timer_init_ns(&sci->timer, QEMU_CLOCK_VIRTUAL, txend, sci); | |
845 | +static void rsci_realize(DeviceState *dev, Error **errp) | |
846 | +{ | |
847 | + RenesasSCIState *sci = RENESAS_SCI(dev); | |
848 | + RenesasSCIBaseState *common = RENESAS_SCI_BASE(dev); | |
849 | + | |
850 | + rsci_common_realize(dev, errp); | |
851 | + | |
852 | + register_mmio(common, 8 * (1 << common->regshift)); | |
853 | + qemu_chr_fe_set_handlers(&common->chr, sci_can_receive, sci_receive, | |
854 | + sci_event, NULL, sci, NULL, true); | |
855 | + | |
856 | + sci->sptr = 0x00; | |
857 | +} | |
858 | + | |
859 | +static void rscia_realize(DeviceState *dev, Error **errp) | |
860 | +{ | |
861 | + RenesasSCIAState *sci = RENESAS_SCIA(dev); | |
862 | + RenesasSCIBaseState *common = RENESAS_SCI_BASE(dev); | |
863 | + | |
864 | + rsci_common_realize(dev, errp); | |
865 | + | |
866 | + register_mmio(common, 8 * (1 << common->regshift)); | |
867 | + qemu_chr_fe_set_handlers(&common->chr, sci_can_receive, sci_receive, | |
868 | + sci_event, NULL, sci, NULL, true); | |
869 | + | |
870 | + sci->scmr = 0x00; | |
871 | + sci->semr = 0x00; | |
872 | +} | |
873 | + | |
874 | +static void rscif_realize(DeviceState *dev, Error **errp) | |
875 | +{ | |
876 | + RenesasSCIFState *sci = RENESAS_SCIF(dev); | |
877 | + RenesasSCIBaseState *common = RENESAS_SCI_BASE(sci); | |
878 | + | |
879 | + rsci_common_realize(dev, errp); | |
880 | + | |
881 | + register_mmio(common, 10 * (1 << common->regshift)); | |
882 | + qemu_chr_fe_set_handlers(&common->chr, scif_can_receive, scif_receive, | |
883 | + scif_event, NULL, sci, NULL, true); | |
884 | + common->Xsr = 0x0060; | |
885 | + sci->fcr = 0x0000; | |
886 | + sci->sptr = 0x0000; | |
887 | + sci->lsr = 0x0000; | |
299 | 888 | } |
300 | 889 | |
301 | 890 | static const VMStateDescription vmstate_rsci = { |
@@ -303,49 +892,141 @@ static const VMStateDescription vmstate_rsci = { | ||
303 | 892 | .version_id = 1, |
304 | 893 | .minimum_version_id = 1, |
305 | 894 | .fields = (VMStateField[]) { |
306 | - VMSTATE_INT64(trtime, RSCIState), | |
307 | - VMSTATE_INT64(rx_next, RSCIState), | |
308 | - VMSTATE_UINT8(smr, RSCIState), | |
309 | - VMSTATE_UINT8(brr, RSCIState), | |
310 | - VMSTATE_UINT8(scr, RSCIState), | |
311 | - VMSTATE_UINT8(tdr, RSCIState), | |
312 | - VMSTATE_UINT8(ssr, RSCIState), | |
313 | - VMSTATE_UINT8(rdr, RSCIState), | |
314 | - VMSTATE_UINT8(scmr, RSCIState), | |
315 | - VMSTATE_UINT8(semr, RSCIState), | |
316 | - VMSTATE_UINT8(read_ssr, RSCIState), | |
317 | - VMSTATE_TIMER(timer, RSCIState), | |
318 | 895 | VMSTATE_END_OF_LIST() |
319 | 896 | } |
320 | 897 | }; |
321 | 898 | |
322 | 899 | static Property rsci_properties[] = { |
323 | - DEFINE_PROP_UINT64("input-freq", RSCIState, input_freq, 0), | |
324 | - DEFINE_PROP_CHR("chardev", RSCIState, chr), | |
900 | + DEFINE_PROP_INT32("register-size", RenesasSCIBaseState, | |
901 | + regshift, SCI_REGSIZE_32), | |
902 | + DEFINE_PROP_UINT32("unit", RenesasSCIBaseState, unit, 0), | |
903 | + DEFINE_PROP_CHR("chardev", RenesasSCIBaseState, chr), | |
325 | 904 | DEFINE_PROP_END_OF_LIST(), |
326 | 905 | }; |
327 | 906 | |
328 | -static void rsci_class_init(ObjectClass *klass, void *data) | |
907 | +static void rsci_init(Object *obj) | |
329 | 908 | { |
909 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(obj); | |
910 | + sci->event[RXNEXT].handler = sci_rx_next; | |
911 | + sci->event[TXEMPTY].handler = sci_tx_empty; | |
912 | +} | |
913 | + | |
914 | +static void rscif_init(Object *obj) | |
915 | +{ | |
916 | + RenesasSCIBaseState *sci = RENESAS_SCI_BASE(obj); | |
917 | + sci->event[RXTOUT].handler = scif_rx_timeout; | |
918 | + sci->event[TXEMPTY].handler = scif_tx_empty; | |
919 | + sci->event[TXEND].handler = scif_tx_end; | |
920 | +} | |
921 | + | |
922 | +static void rsci_common_class_init(ObjectClass *klass, void *data) | |
923 | +{ | |
924 | + RenesasSCIBaseClass *rc = RENESAS_SCI_BASE_CLASS(klass); | |
330 | 925 | DeviceClass *dc = DEVICE_CLASS(klass); |
331 | 926 | |
332 | - dc->realize = rsci_realize; | |
333 | 927 | dc->vmsd = &vmstate_rsci; |
334 | - dc->reset = rsci_reset; | |
335 | 928 | device_class_set_props(dc, rsci_properties); |
929 | + rc->divrate = static_divrate; | |
336 | 930 | } |
337 | 931 | |
338 | -static const TypeInfo rsci_info = { | |
339 | - .name = TYPE_RENESAS_SCI, | |
340 | - .parent = TYPE_SYS_BUS_DEVICE, | |
341 | - .instance_size = sizeof(RSCIState), | |
342 | - .instance_init = rsci_init, | |
343 | - .class_init = rsci_class_init, | |
932 | +static const MemoryRegionOps sci_ops = { | |
933 | + .read = sci_read, | |
934 | + .write = sci_write, | |
935 | + .endianness = DEVICE_NATIVE_ENDIAN, | |
936 | + .valid = { | |
937 | + .min_access_size = 1, | |
938 | + .max_access_size = 4, | |
939 | + }, | |
344 | 940 | }; |
345 | 941 | |
346 | -static void rsci_register_types(void) | |
942 | +static void rsci_class_init(ObjectClass *klass, void *data) | |
347 | 943 | { |
348 | - type_register_static(&rsci_info); | |
944 | + RenesasSCIBaseClass *comm_rc = RENESAS_SCI_BASE_CLASS(klass); | |
945 | + DeviceClass *dc = DEVICE_CLASS(klass); | |
946 | + | |
947 | + comm_rc->ops = &sci_ops; | |
948 | + comm_rc->irq_fn = sci_irq; | |
949 | + dc->realize = rsci_realize; | |
349 | 950 | } |
350 | 951 | |
351 | -type_init(rsci_register_types) | |
952 | +static const MemoryRegionOps scia_ops = { | |
953 | + .read = scia_read, | |
954 | + .write = scia_write, | |
955 | + .endianness = DEVICE_NATIVE_ENDIAN, | |
956 | + .valid = { | |
957 | + .min_access_size = 1, | |
958 | + .max_access_size = 4, | |
959 | + }, | |
960 | +}; | |
961 | + | |
962 | +static void rscia_class_init(ObjectClass *klass, void *data) | |
963 | +{ | |
964 | + RenesasSCIBaseClass *comm_rc = RENESAS_SCI_BASE_CLASS(klass); | |
965 | + DeviceClass *dc = DEVICE_CLASS(klass); | |
966 | + | |
967 | + comm_rc->ops = &scia_ops; | |
968 | + comm_rc->irq_fn = scia_irq; | |
969 | + comm_rc->divrate = scia_divrate; | |
970 | + | |
971 | + dc->realize = rscia_realize; | |
972 | +} | |
973 | + | |
974 | +static const MemoryRegionOps scif_ops = { | |
975 | + .read = scif_read, | |
976 | + .write = scif_write, | |
977 | + .endianness = DEVICE_NATIVE_ENDIAN, | |
978 | + .valid = { | |
979 | + .min_access_size = 1, | |
980 | + .max_access_size = 4, | |
981 | + }, | |
982 | +}; | |
983 | + | |
984 | +static void rscif_class_init(ObjectClass *klass, void *data) | |
985 | +{ | |
986 | + RenesasSCIBaseClass *comm_rc = RENESAS_SCI_BASE_CLASS(klass); | |
987 | + DeviceClass *dc = DEVICE_CLASS(klass); | |
988 | + | |
989 | + comm_rc->ops = &scif_ops; | |
990 | + comm_rc->irq_fn = scif_irq; | |
991 | + | |
992 | + dc->realize = rscif_realize; | |
993 | +} | |
994 | + | |
995 | +static const TypeInfo renesas_sci_info[] = { | |
996 | + { | |
997 | + .name = TYPE_RENESAS_SCI_BASE, | |
998 | + .parent = TYPE_SYS_BUS_DEVICE, | |
999 | + .instance_size = sizeof(RenesasSCIBaseState), | |
1000 | + .instance_init = rsci_common_init, | |
1001 | + .class_init = rsci_common_class_init, | |
1002 | + .class_size = sizeof(RenesasSCIBaseClass), | |
1003 | + .abstract = true, | |
1004 | + }, | |
1005 | + { | |
1006 | + .name = TYPE_RENESAS_SCI, | |
1007 | + .parent = TYPE_RENESAS_SCI_BASE, | |
1008 | + .instance_size = sizeof(RenesasSCIState), | |
1009 | + .instance_init = rsci_init, | |
1010 | + .class_init = rsci_class_init, | |
1011 | + .class_size = sizeof(RenesasSCIClass), | |
1012 | + }, | |
1013 | + { | |
1014 | + .name = TYPE_RENESAS_SCIA, | |
1015 | + .parent = TYPE_RENESAS_SCI_BASE, | |
1016 | + .instance_size = sizeof(RenesasSCIAState), | |
1017 | + /* Initializer same of SCI */ | |
1018 | + .instance_init = rsci_init, | |
1019 | + .class_init = rscia_class_init, | |
1020 | + .class_size = sizeof(RenesasSCIAClass), | |
1021 | + }, | |
1022 | + { | |
1023 | + .name = TYPE_RENESAS_SCIF, | |
1024 | + .parent = TYPE_RENESAS_SCI_BASE, | |
1025 | + .instance_size = sizeof(RenesasSCIFState), | |
1026 | + .instance_init = rscif_init, | |
1027 | + .class_init = rscif_class_init, | |
1028 | + .class_size = sizeof(RenesasSCIFClass), | |
1029 | + }, | |
1030 | +}; | |
1031 | + | |
1032 | +DEFINE_TYPES(renesas_sci_info) |
@@ -1,54 +1,137 @@ | ||
1 | 1 | /* |
2 | 2 | * Renesas Serial Communication Interface |
3 | 3 | * |
4 | - * Copyright (c) 2018 Yoshinori Sato | |
4 | + * Copyright (c) 2020 Yoshinori Sato | |
5 | + * | |
6 | + * This code is licensed under the GPL version 2 or later. | |
5 | 7 | * |
6 | - * SPDX-License-Identifier: GPL-2.0-or-later | |
7 | 8 | */ |
8 | 9 | |
9 | -#ifndef HW_CHAR_RENESAS_SCI_H | |
10 | -#define HW_CHAR_RENESAS_SCI_H | |
11 | - | |
12 | 10 | #include "chardev/char-fe.h" |
11 | +#include "qemu/timer.h" | |
12 | +#include "qemu/fifo8.h" | |
13 | 13 | #include "hw/sysbus.h" |
14 | 14 | #include "qom/object.h" |
15 | 15 | |
16 | +#define TYPE_RENESAS_SCI_BASE "renesas-sci-base" | |
17 | +OBJECT_DECLARE_TYPE(RenesasSCIBaseState, RenesasSCIBaseClass, | |
18 | + RENESAS_SCI_BASE) | |
16 | 19 | #define TYPE_RENESAS_SCI "renesas-sci" |
17 | -typedef struct RSCIState RSCIState; | |
18 | -DECLARE_INSTANCE_CHECKER(RSCIState, RSCI, | |
19 | - TYPE_RENESAS_SCI) | |
20 | +OBJECT_DECLARE_TYPE(RenesasSCIState, RenesasSCIClass, | |
21 | + RENESAS_SCI) | |
22 | +#define TYPE_RENESAS_SCIA "renesas-scia" | |
23 | +OBJECT_DECLARE_TYPE(RenesasSCIAState, RenesasSCIAClass, | |
24 | + RENESAS_SCIA) | |
25 | +#define TYPE_RENESAS_SCIF "renesas-scif" | |
26 | +OBJECT_DECLARE_TYPE(RenesasSCIFState, RenesasSCIFClass, | |
27 | + RENESAS_SCIF) | |
20 | 28 | |
21 | 29 | enum { |
22 | 30 | ERI = 0, |
23 | 31 | RXI = 1, |
24 | 32 | TXI = 2, |
25 | - TEI = 3, | |
26 | - SCI_NR_IRQ = 4 | |
33 | + BRI_TEI = 3, | |
34 | + SCI_NR_IRQ = 4, | |
35 | +}; | |
36 | + | |
37 | +enum { | |
38 | + RXTOUT, | |
39 | + RXNEXT, | |
40 | + TXEMPTY, | |
41 | + TXEND, | |
42 | + NR_SCI_EVENT, | |
27 | 43 | }; |
28 | 44 | |
29 | -struct RSCIState { | |
45 | +enum { | |
46 | + SCI_REGSIZE_8 = 0, | |
47 | + SCI_REGSIZE_16 = 1, | |
48 | + SCI_REGSIZE_32 = 2, | |
49 | +}; | |
50 | + | |
51 | +typedef struct RenesasSCIBaseState { | |
30 | 52 | /*< private >*/ |
31 | 53 | SysBusDevice parent_obj; |
32 | - /*< public >*/ | |
33 | - | |
34 | 54 | MemoryRegion memory; |
35 | - QEMUTimer timer; | |
36 | - CharBackend chr; | |
37 | - qemu_irq irq[SCI_NR_IRQ]; | |
55 | + MemoryRegion memory_p4; | |
56 | + MemoryRegion memory_a7; | |
38 | 57 | |
58 | + /* SCI register */ | |
39 | 59 | uint8_t smr; |
40 | 60 | uint8_t brr; |
41 | 61 | uint8_t scr; |
42 | 62 | uint8_t tdr; |
43 | - uint8_t ssr; | |
44 | - uint8_t rdr; | |
45 | - uint8_t scmr; | |
46 | - uint8_t semr; | |
63 | + uint16_t Xsr; | |
47 | 64 | |
48 | - uint8_t read_ssr; | |
65 | + /* internal use */ | |
66 | + uint16_t read_Xsr; | |
67 | + int64_t etu; | |
49 | 68 | int64_t trtime; |
50 | - int64_t rx_next; | |
69 | + int64_t tx_start_time; | |
70 | + struct { | |
71 | + int64_t time; | |
72 | + int64_t (*handler)(struct RenesasSCIBaseState *sci); | |
73 | + } event[NR_SCI_EVENT]; | |
74 | + QEMUTimer *event_timer; | |
75 | + CharBackend chr; | |
51 | 76 | uint64_t input_freq; |
77 | + qemu_irq irq[SCI_NR_IRQ]; | |
78 | + Fifo8 rxfifo; | |
79 | + int regshift; | |
80 | + uint32_t unit; | |
81 | + Clock *pck; | |
82 | +} RenesasSCIBaseState; | |
83 | + | |
84 | +struct RenesasSCIState { | |
85 | + RenesasSCIBaseState parent_obj; | |
86 | + | |
87 | + /* SCI specific register */ | |
88 | + uint8_t sptr; | |
52 | 89 | }; |
53 | 90 | |
54 | -#endif | |
91 | +struct RenesasSCIAState { | |
92 | + RenesasSCIBaseState parent_obj; | |
93 | + | |
94 | + /* SCIa specific register */ | |
95 | + uint8_t scmr; | |
96 | + uint8_t semr; | |
97 | +}; | |
98 | + | |
99 | +struct RenesasSCIFState { | |
100 | + RenesasSCIBaseState parent_obj; | |
101 | + | |
102 | + /* SCIF specific register */ | |
103 | + uint16_t fcr; | |
104 | + uint16_t sptr; | |
105 | + uint16_t lsr; | |
106 | + | |
107 | + /* private */ | |
108 | + uint16_t read_lsr; | |
109 | + int tdcnt; | |
110 | +}; | |
111 | + | |
112 | +typedef struct RenesasSCIBaseClass { | |
113 | + SysBusDeviceClass parent; | |
114 | + | |
115 | + const struct MemoryRegionOps *ops; | |
116 | + void (*irq_fn)(struct RenesasSCIBaseState *sci, int request); | |
117 | + int (*divrate)(struct RenesasSCIBaseState *sci); | |
118 | +} RenesasSCIBaseClass; | |
119 | + | |
120 | +typedef struct RenesasSCIClass { | |
121 | + RenesasSCIBaseClass parent; | |
122 | + | |
123 | + void (*p_irq_fn)(struct RenesasSCIBaseState *sci, int request); | |
124 | +} RenesasSCIClass; | |
125 | + | |
126 | +typedef struct RenesasSCIAClass { | |
127 | + RenesasSCIBaseClass parent; | |
128 | + | |
129 | + void (*p_irq_fn)(struct RenesasSCIBaseState *sci, int request); | |
130 | + int (*p_divrate)(struct RenesasSCIBaseState *sci); | |
131 | +} RenesasSCIAClass; | |
132 | + | |
133 | +typedef struct RenesasSCIFClass { | |
134 | + RenesasSCIBaseClass parent; | |
135 | + | |
136 | + void (*p_irq_fn)(struct RenesasSCIBaseState *sci, int request); | |
137 | +} RenesasSCIFClass; |