1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include "qemu/osdep.h"
24#include "hw/hw.h"
25#include "hw/irq.h"
26#include "hw/devices.h"
27#include "sysemu/sysemu.h"
28
29
30
31typedef struct {
32 void *opaque;
33 void (*io)(void *opaque, int rw, int reg, uint16_t *val);
34 int addr;
35} CBusSlave;
36
37typedef struct {
38 CBus cbus;
39
40 int sel;
41 int dat;
42 int clk;
43 int bit;
44 int dir;
45 uint16_t val;
46 qemu_irq dat_out;
47
48 int addr;
49 int reg;
50 int rw;
51 enum {
52 cbus_address,
53 cbus_value,
54 } cycle;
55
56 CBusSlave *slave[8];
57} CBusPriv;
58
59static void cbus_io(CBusPriv *s)
60{
61 if (s->slave[s->addr])
62 s->slave[s->addr]->io(s->slave[s->addr]->opaque,
63 s->rw, s->reg, &s->val);
64 else
65 hw_error("%s: bad slave address %i\n", __func__, s->addr);
66}
67
68static void cbus_cycle(CBusPriv *s)
69{
70 switch (s->cycle) {
71 case cbus_address:
72 s->addr = (s->val >> 6) & 7;
73 s->rw = (s->val >> 5) & 1;
74 s->reg = (s->val >> 0) & 0x1f;
75
76 s->cycle = cbus_value;
77 s->bit = 15;
78 s->dir = !s->rw;
79 s->val = 0;
80
81 if (s->rw)
82 cbus_io(s);
83 break;
84
85 case cbus_value:
86 if (!s->rw)
87 cbus_io(s);
88
89 s->cycle = cbus_address;
90 s->bit = 8;
91 s->dir = 1;
92 s->val = 0;
93 break;
94 }
95}
96
97static void cbus_clk(void *opaque, int line, int level)
98{
99 CBusPriv *s = (CBusPriv *) opaque;
100
101 if (!s->sel && level && !s->clk) {
102 if (s->dir)
103 s->val |= s->dat << (s->bit --);
104 else
105 qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
106
107 if (s->bit < 0)
108 cbus_cycle(s);
109 }
110
111 s->clk = level;
112}
113
114static void cbus_dat(void *opaque, int line, int level)
115{
116 CBusPriv *s = (CBusPriv *) opaque;
117
118 s->dat = level;
119}
120
121static void cbus_sel(void *opaque, int line, int level)
122{
123 CBusPriv *s = (CBusPriv *) opaque;
124
125 if (!level) {
126 s->dir = 1;
127 s->bit = 8;
128 s->val = 0;
129 }
130
131 s->sel = level;
132}
133
134CBus *cbus_init(qemu_irq dat)
135{
136 CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s));
137
138 s->dat_out = dat;
139 s->cbus.clk = qemu_allocate_irq(cbus_clk, s, 0);
140 s->cbus.dat = qemu_allocate_irq(cbus_dat, s, 0);
141 s->cbus.sel = qemu_allocate_irq(cbus_sel, s, 0);
142
143 s->sel = 1;
144 s->clk = 0;
145 s->dat = 0;
146
147 return &s->cbus;
148}
149
150void cbus_attach(CBus *bus, void *slave_opaque)
151{
152 CBusSlave *slave = (CBusSlave *) slave_opaque;
153 CBusPriv *s = (CBusPriv *) bus;
154
155 s->slave[slave->addr] = slave;
156}
157
158
159typedef struct {
160 uint16_t irqst;
161 uint16_t irqen;
162 uint16_t cc[2];
163 int channel;
164 uint16_t result[16];
165 uint16_t sample;
166 uint16_t status;
167
168 struct {
169 uint16_t cal;
170 } rtc;
171
172 int is_vilma;
173 qemu_irq irq;
174 CBusSlave cbus;
175} CBusRetu;
176
177static void retu_interrupt_update(CBusRetu *s)
178{
179 qemu_set_irq(s->irq, s->irqst & ~s->irqen);
180}
181
182#define RETU_REG_ASICR 0x00
183#define RETU_REG_IDR 0x01
184#define RETU_REG_IMR 0x02
185#define RETU_REG_RTCDSR 0x03
186#define RETU_REG_RTCHMR 0x04
187#define RETU_REG_RTCHMAR 0x05
188#define RETU_REG_RTCCALR 0x06
189#define RETU_REG_ADCR 0x08
190#define RETU_REG_ADCSCR 0x09
191#define RETU_REG_AFCR 0x0a
192#define RETU_REG_ANTIFR 0x0b
193#define RETU_REG_CALIBR 0x0c
194#define RETU_REG_CCR1 0x0d
195#define RETU_REG_CCR2 0x0e
196#define RETU_REG_RCTRL_CLR 0x0f
197#define RETU_REG_RCTRL_SET 0x10
198#define RETU_REG_TXCR 0x11
199#define RETU_REG_STATUS 0x16
200#define RETU_REG_WATCHDOG 0x17
201#define RETU_REG_AUDTXR 0x18
202#define RETU_REG_AUDPAR 0x19
203#define RETU_REG_AUDRXR1 0x1a
204#define RETU_REG_AUDRXR2 0x1b
205#define RETU_REG_SGR1 0x1c
206#define RETU_REG_SCR1 0x1d
207#define RETU_REG_SGR2 0x1e
208#define RETU_REG_SCR2 0x1f
209
210
211enum {
212 retu_int_pwr = 0,
213 retu_int_char = 1,
214 retu_int_rtcs = 2,
215 retu_int_rtcm = 3,
216 retu_int_rtcd = 4,
217 retu_int_rtca = 5,
218 retu_int_hook = 6,
219 retu_int_head = 7,
220 retu_int_adcs = 8,
221};
222
223
224enum {
225 retu_adc_bsi = 1,
226 retu_adc_batt_temp = 2,
227 retu_adc_chg_volt = 3,
228 retu_adc_head_det = 4,
229 retu_adc_hook_det = 5,
230 retu_adc_rf_gp = 6,
231 retu_adc_tx_det = 7,
232 retu_adc_batt_volt = 8,
233 retu_adc_sens = 10,
234 retu_adc_sens_temp = 11,
235 retu_adc_bbatt_volt = 12,
236 retu_adc_self_temp = 13,
237};
238
239static inline uint16_t retu_read(CBusRetu *s, int reg)
240{
241#ifdef DEBUG
242 printf("RETU read at %02x\n", reg);
243#endif
244
245 switch (reg) {
246 case RETU_REG_ASICR:
247 return 0x0215 | (s->is_vilma << 7);
248
249 case RETU_REG_IDR:
250 return s->irqst;
251
252 case RETU_REG_IMR:
253 return s->irqen;
254
255 case RETU_REG_RTCDSR:
256 case RETU_REG_RTCHMR:
257 case RETU_REG_RTCHMAR:
258
259 return 0x0000;
260
261 case RETU_REG_RTCCALR:
262 return s->rtc.cal;
263
264 case RETU_REG_ADCR:
265 return (s->channel << 10) | s->result[s->channel];
266 case RETU_REG_ADCSCR:
267 return s->sample;
268
269 case RETU_REG_AFCR:
270 case RETU_REG_ANTIFR:
271 case RETU_REG_CALIBR:
272
273 return 0x0000;
274
275 case RETU_REG_CCR1:
276 return s->cc[0];
277 case RETU_REG_CCR2:
278 return s->cc[1];
279
280 case RETU_REG_RCTRL_CLR:
281 case RETU_REG_RCTRL_SET:
282 case RETU_REG_TXCR:
283
284 return 0x0000;
285
286 case RETU_REG_STATUS:
287 return s->status;
288
289 case RETU_REG_WATCHDOG:
290 case RETU_REG_AUDTXR:
291 case RETU_REG_AUDPAR:
292 case RETU_REG_AUDRXR1:
293 case RETU_REG_AUDRXR2:
294 case RETU_REG_SGR1:
295 case RETU_REG_SCR1:
296 case RETU_REG_SGR2:
297 case RETU_REG_SCR2:
298
299 return 0x0000;
300
301 default:
302 hw_error("%s: bad register %02x\n", __func__, reg);
303 }
304}
305
306static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
307{
308#ifdef DEBUG
309 printf("RETU write of %04x at %02x\n", val, reg);
310#endif
311
312 switch (reg) {
313 case RETU_REG_IDR:
314 s->irqst ^= val;
315 retu_interrupt_update(s);
316 break;
317
318 case RETU_REG_IMR:
319 s->irqen = val;
320 retu_interrupt_update(s);
321 break;
322
323 case RETU_REG_RTCDSR:
324 case RETU_REG_RTCHMAR:
325
326 break;
327
328 case RETU_REG_RTCCALR:
329 s->rtc.cal = val;
330 break;
331
332 case RETU_REG_ADCR:
333 s->channel = (val >> 10) & 0xf;
334 s->irqst |= 1 << retu_int_adcs;
335 retu_interrupt_update(s);
336 break;
337 case RETU_REG_ADCSCR:
338 s->sample &= ~val;
339 break;
340
341 case RETU_REG_AFCR:
342 case RETU_REG_ANTIFR:
343 case RETU_REG_CALIBR:
344
345 case RETU_REG_CCR1:
346 s->cc[0] = val;
347 break;
348 case RETU_REG_CCR2:
349 s->cc[1] = val;
350 break;
351
352 case RETU_REG_RCTRL_CLR:
353 case RETU_REG_RCTRL_SET:
354
355 break;
356
357 case RETU_REG_WATCHDOG:
358 if (val == 0 && (s->cc[0] & 2))
359 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
360 break;
361
362 case RETU_REG_TXCR:
363 case RETU_REG_AUDTXR:
364 case RETU_REG_AUDPAR:
365 case RETU_REG_AUDRXR1:
366 case RETU_REG_AUDRXR2:
367 case RETU_REG_SGR1:
368 case RETU_REG_SCR1:
369 case RETU_REG_SGR2:
370 case RETU_REG_SCR2:
371
372 break;
373
374 default:
375 hw_error("%s: bad register %02x\n", __func__, reg);
376 }
377}
378
379static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
380{
381 CBusRetu *s = (CBusRetu *) opaque;
382
383 if (rw)
384 *val = retu_read(s, reg);
385 else
386 retu_write(s, reg, *val);
387}
388
389void *retu_init(qemu_irq irq, int vilma)
390{
391 CBusRetu *s = (CBusRetu *) g_malloc0(sizeof(*s));
392
393 s->irq = irq;
394 s->irqen = 0xffff;
395 s->irqst = 0x0000;
396 s->status = 0x0020;
397 s->is_vilma = !!vilma;
398 s->rtc.cal = 0x01;
399 s->result[retu_adc_bsi] = 0x3c2;
400 s->result[retu_adc_batt_temp] = 0x0fc;
401 s->result[retu_adc_chg_volt] = 0x165;
402 s->result[retu_adc_head_det] = 123;
403 s->result[retu_adc_hook_det] = 1023;
404 s->result[retu_adc_rf_gp] = 0x11;
405 s->result[retu_adc_tx_det] = 0x11;
406 s->result[retu_adc_batt_volt] = 0x250;
407 s->result[retu_adc_sens] = 2;
408 s->result[retu_adc_sens_temp] = 0x11;
409 s->result[retu_adc_bbatt_volt] = 0x3d0;
410 s->result[retu_adc_self_temp] = 0x330;
411
412 s->cbus.opaque = s;
413 s->cbus.io = retu_io;
414 s->cbus.addr = 1;
415
416 return &s->cbus;
417}
418
419void retu_key_event(void *retu, int state)
420{
421 CBusSlave *slave = (CBusSlave *) retu;
422 CBusRetu *s = (CBusRetu *) slave->opaque;
423
424 s->irqst |= 1 << retu_int_pwr;
425 retu_interrupt_update(s);
426
427 if (state)
428 s->status &= ~(1 << 5);
429 else
430 s->status |= 1 << 5;
431}
432
433#if 0
434static void retu_head_event(void *retu, int state)
435{
436 CBusSlave *slave = (CBusSlave *) retu;
437 CBusRetu *s = (CBusRetu *) slave->opaque;
438
439 if ((s->cc[0] & 0x500) == 0x500) {
440
441 s->irqst |= 1 << retu_int_head;
442 retu_interrupt_update(s);
443 }
444
445 if (state)
446 s->result[retu_adc_head_det] = 50;
447 else
448 s->result[retu_adc_head_det] = 123;
449}
450
451static void retu_hook_event(void *retu, int state)
452{
453 CBusSlave *slave = (CBusSlave *) retu;
454 CBusRetu *s = (CBusRetu *) slave->opaque;
455
456 if ((s->cc[0] & 0x500) == 0x500) {
457
458 s->irqst |= 1 << retu_int_hook;
459 retu_interrupt_update(s);
460 }
461
462 if (state)
463 s->result[retu_adc_hook_det] = 50;
464 else
465 s->result[retu_adc_hook_det] = 123;
466}
467#endif
468
469
470typedef struct {
471 uint16_t irqst;
472 uint16_t irqen;
473 uint8_t charger;
474 uint8_t backlight;
475 uint16_t usbr;
476 uint16_t power;
477
478 int is_betty;
479 qemu_irq irq;
480 CBusSlave cbus;
481} CBusTahvo;
482
483static void tahvo_interrupt_update(CBusTahvo *s)
484{
485 qemu_set_irq(s->irq, s->irqst & ~s->irqen);
486}
487
488#define TAHVO_REG_ASICR 0x00
489#define TAHVO_REG_IDR 0x01
490#define TAHVO_REG_IDSR 0x02
491#define TAHVO_REG_IMR 0x03
492#define TAHVO_REG_CHAPWMR 0x04
493#define TAHVO_REG_LEDPWMR 0x05
494#define TAHVO_REG_USBR 0x06
495#define TAHVO_REG_RCR 0x07
496#define TAHVO_REG_CCR1 0x08
497#define TAHVO_REG_CCR2 0x09
498#define TAHVO_REG_TESTR1 0x0a
499#define TAHVO_REG_TESTR2 0x0b
500#define TAHVO_REG_NOPR 0x0c
501#define TAHVO_REG_FRR 0x0d
502
503static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
504{
505#ifdef DEBUG
506 printf("TAHVO read at %02x\n", reg);
507#endif
508
509 switch (reg) {
510 case TAHVO_REG_ASICR:
511 return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300);
512
513 case TAHVO_REG_IDR:
514 case TAHVO_REG_IDSR:
515 return s->irqst;
516
517 case TAHVO_REG_IMR:
518 return s->irqen;
519
520 case TAHVO_REG_CHAPWMR:
521 return s->charger;
522
523 case TAHVO_REG_LEDPWMR:
524 return s->backlight;
525
526 case TAHVO_REG_USBR:
527 return s->usbr;
528
529 case TAHVO_REG_RCR:
530 return s->power;
531
532 case TAHVO_REG_CCR1:
533 case TAHVO_REG_CCR2:
534 case TAHVO_REG_TESTR1:
535 case TAHVO_REG_TESTR2:
536 case TAHVO_REG_NOPR:
537 case TAHVO_REG_FRR:
538 return 0x0000;
539
540 default:
541 hw_error("%s: bad register %02x\n", __func__, reg);
542 }
543}
544
545static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
546{
547#ifdef DEBUG
548 printf("TAHVO write of %04x at %02x\n", val, reg);
549#endif
550
551 switch (reg) {
552 case TAHVO_REG_IDR:
553 s->irqst ^= val;
554 tahvo_interrupt_update(s);
555 break;
556
557 case TAHVO_REG_IMR:
558 s->irqen = val;
559 tahvo_interrupt_update(s);
560 break;
561
562 case TAHVO_REG_CHAPWMR:
563 s->charger = val;
564 break;
565
566 case TAHVO_REG_LEDPWMR:
567 if (s->backlight != (val & 0x7f)) {
568 s->backlight = val & 0x7f;
569 printf("%s: LCD backlight now at %i / 127\n",
570 __func__, s->backlight);
571 }
572 break;
573
574 case TAHVO_REG_USBR:
575 s->usbr = val;
576 break;
577
578 case TAHVO_REG_RCR:
579 s->power = val;
580 break;
581
582 case TAHVO_REG_CCR1:
583 case TAHVO_REG_CCR2:
584 case TAHVO_REG_TESTR1:
585 case TAHVO_REG_TESTR2:
586 case TAHVO_REG_NOPR:
587 case TAHVO_REG_FRR:
588 break;
589
590 default:
591 hw_error("%s: bad register %02x\n", __func__, reg);
592 }
593}
594
595static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
596{
597 CBusTahvo *s = (CBusTahvo *) opaque;
598
599 if (rw)
600 *val = tahvo_read(s, reg);
601 else
602 tahvo_write(s, reg, *val);
603}
604
605void *tahvo_init(qemu_irq irq, int betty)
606{
607 CBusTahvo *s = (CBusTahvo *) g_malloc0(sizeof(*s));
608
609 s->irq = irq;
610 s->irqen = 0xffff;
611 s->irqst = 0x0000;
612 s->is_betty = !!betty;
613
614 s->cbus.opaque = s;
615 s->cbus.io = tahvo_io;
616 s->cbus.addr = 2;
617
618 return &s->cbus;
619}
620