]> git.proxmox.com Git - qemu.git/blame - hw/cbus.c
hw/pc: don't register the memory hole as unassigned twice
[qemu.git] / hw / cbus.c
CommitLineData
7e7c5e4c
AZ
1/*
2 * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
3 * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
4 * Based on reverse-engineering of a linux driver.
5 *
6 * Copyright (C) 2008 Nokia Corporation
7 * Written by Andrzej Zaborowski <andrew@openedhand.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 or
12 * (at your option) version 3 of the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 */
24
25#include "qemu-common.h"
26#include "irq.h"
27#include "devices.h"
28#include "sysemu.h"
29
30//#define DEBUG
31
32struct cbus_slave_s;
33struct cbus_priv_s {
34 struct cbus_s cbus;
35
36 int sel;
37 int dat;
38 int clk;
39 int bit;
40 int dir;
41 uint16_t val;
42 qemu_irq dat_out;
43
44 int addr;
45 int reg;
46 int rw;
47 enum {
48 cbus_address,
49 cbus_value,
50 } cycle;
51
52 struct cbus_slave_s *slave[8];
53};
54
55struct cbus_slave_s {
56 void *opaque;
57 void (*io)(void *opaque, int rw, int reg, uint16_t *val);
58 int addr;
59};
60
61static void cbus_io(struct cbus_priv_s *s)
62{
63 if (s->slave[s->addr])
64 s->slave[s->addr]->io(s->slave[s->addr]->opaque,
65 s->rw, s->reg, &s->val);
66 else
67 cpu_abort(cpu_single_env, "%s: bad slave address %i\n",
68 __FUNCTION__, s->addr);
69}
70
71static void cbus_cycle(struct cbus_priv_s *s)
72{
73 switch (s->cycle) {
74 case cbus_address:
75 s->addr = (s->val >> 6) & 7;
76 s->rw = (s->val >> 5) & 1;
77 s->reg = (s->val >> 0) & 0x1f;
78
79 s->cycle = cbus_value;
80 s->bit = 15;
81 s->dir = !s->rw;
82 s->val = 0;
83
84 if (s->rw)
85 cbus_io(s);
86 break;
87
88 case cbus_value:
89 if (!s->rw)
90 cbus_io(s);
91
92 s->cycle = cbus_address;
93 s->bit = 8;
94 s->dir = 1;
95 s->val = 0;
96 break;
97 }
98}
99
100static void cbus_clk(void *opaque, int line, int level)
101{
102 struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
103
104 if (!s->sel && level && !s->clk) {
105 if (s->dir)
106 s->val |= s->dat << (s->bit --);
107 else
108 qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
109
110 if (s->bit < 0)
111 cbus_cycle(s);
112 }
113
114 s->clk = level;
115}
116
117static void cbus_dat(void *opaque, int line, int level)
118{
119 struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
120
121 s->dat = level;
122}
123
124static void cbus_sel(void *opaque, int line, int level)
125{
126 struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
127
128 if (!level) {
129 s->dir = 1;
130 s->bit = 8;
131 s->val = 0;
132 }
133
134 s->sel = level;
135}
136
137struct cbus_s *cbus_init(qemu_irq dat)
138{
139 struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s));
140
141 s->dat_out = dat;
142 s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
143 s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
144 s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
145
146 s->sel = 1;
147 s->clk = 0;
148 s->dat = 0;
149
150 return &s->cbus;
151}
152
153void cbus_attach(struct cbus_s *bus, void *slave_opaque)
154{
155 struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque;
156 struct cbus_priv_s *s = (struct cbus_priv_s *) bus;
157
158 s->slave[slave->addr] = slave;
159}
160
161/* Retu/Vilma */
162struct cbus_retu_s {
163 uint16_t irqst;
164 uint16_t irqen;
165 uint16_t cc[2];
166 int channel;
167 uint16_t result[16];
168 uint16_t sample;
169 uint16_t status;
170
171 struct {
172 uint16_t cal;
173 } rtc;
174
175 int is_vilma;
176 qemu_irq irq;
177 struct cbus_slave_s cbus;
178};
179
180static void retu_interrupt_update(struct cbus_retu_s *s)
181{
182 qemu_set_irq(s->irq, s->irqst & ~s->irqen);
183}
184
185#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
186#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */
187#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */
188#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */
189#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */
190#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */
191#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */
192#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */
193#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */
194#define RETU_REG_AFCR 0x0a /* (RW) AFC register */
195#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */
196#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/
197#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */
198#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */
199#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */
200#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */
201#define RETU_REG_TXCR 0x11 /* (RW) TxC register */
202#define RETU_REG_STATUS 0x16 /* (RO) Status register */
203#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */
204#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */
205#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */
206#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */
207#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */
208#define RETU_REG_SGR1 0x1c /* (RW) */
209#define RETU_REG_SCR1 0x1d /* (RW) */
210#define RETU_REG_SGR2 0x1e /* (RW) */
211#define RETU_REG_SCR2 0x1f /* (RW) */
212
213/* Retu Interrupt sources */
214enum {
215 retu_int_pwr = 0, /* Power button */
216 retu_int_char = 1, /* Charger */
217 retu_int_rtcs = 2, /* Seconds */
218 retu_int_rtcm = 3, /* Minutes */
219 retu_int_rtcd = 4, /* Days */
220 retu_int_rtca = 5, /* Alarm */
221 retu_int_hook = 6, /* Hook */
222 retu_int_head = 7, /* Headset */
223 retu_int_adcs = 8, /* ADC sample */
224};
225
226/* Retu ADC channel wiring */
227enum {
228 retu_adc_bsi = 1, /* BSI */
229 retu_adc_batt_temp = 2, /* Battery temperature */
230 retu_adc_chg_volt = 3, /* Charger voltage */
231 retu_adc_head_det = 4, /* Headset detection */
232 retu_adc_hook_det = 5, /* Hook detection */
233 retu_adc_rf_gp = 6, /* RF GP */
234 retu_adc_tx_det = 7, /* Wideband Tx detection */
235 retu_adc_batt_volt = 8, /* Battery voltage */
236 retu_adc_sens = 10, /* Light sensor */
237 retu_adc_sens_temp = 11, /* Light sensor temperature */
238 retu_adc_bbatt_volt = 12, /* Backup battery voltage */
239 retu_adc_self_temp = 13, /* RETU temperature */
240};
241
242static inline uint16_t retu_read(struct cbus_retu_s *s, int reg)
243{
244#ifdef DEBUG
245 printf("RETU read at %02x\n", reg);
246#endif
247
248 switch (reg) {
249 case RETU_REG_ASICR:
250 return 0x0215 | (s->is_vilma << 7);
251
252 case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
253 return s->irqst;
254
255 case RETU_REG_IMR:
256 return s->irqen;
257
258 case RETU_REG_RTCDSR:
259 case RETU_REG_RTCHMR:
260 case RETU_REG_RTCHMAR:
261 /* TODO */
262 return 0x0000;
263
264 case RETU_REG_RTCCALR:
265 return s->rtc.cal;
266
267 case RETU_REG_ADCR:
268 return (s->channel << 10) | s->result[s->channel];
269 case RETU_REG_ADCSCR:
270 return s->sample;
271
272 case RETU_REG_AFCR:
273 case RETU_REG_ANTIFR:
274 case RETU_REG_CALIBR:
275 /* TODO */
276 return 0x0000;
277
278 case RETU_REG_CCR1:
279 return s->cc[0];
280 case RETU_REG_CCR2:
281 return s->cc[1];
282
283 case RETU_REG_RCTRL_CLR:
284 case RETU_REG_RCTRL_SET:
285 case RETU_REG_TXCR:
286 /* TODO */
287 return 0x0000;
288
289 case RETU_REG_STATUS:
290 return s->status;
291
292 case RETU_REG_WATCHDOG:
293 case RETU_REG_AUDTXR:
294 case RETU_REG_AUDPAR:
295 case RETU_REG_AUDRXR1:
296 case RETU_REG_AUDRXR2:
297 case RETU_REG_SGR1:
298 case RETU_REG_SCR1:
299 case RETU_REG_SGR2:
300 case RETU_REG_SCR2:
301 /* TODO */
302 return 0x0000;
303
304 default:
305 cpu_abort(cpu_single_env, "%s: bad register %02x\n",
306 __FUNCTION__, reg);
307 }
308}
309
310static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val)
311{
312#ifdef DEBUG
313 printf("RETU write of %04x at %02x\n", val, reg);
314#endif
315
316 switch (reg) {
317 case RETU_REG_IDR:
318 s->irqst ^= val;
319 retu_interrupt_update(s);
320 break;
321
322 case RETU_REG_IMR:
323 s->irqen = val;
324 retu_interrupt_update(s);
325 break;
326
327 case RETU_REG_RTCDSR:
328 case RETU_REG_RTCHMAR:
329 /* TODO */
330 break;
331
332 case RETU_REG_RTCCALR:
333 s->rtc.cal = val;
334 break;
335
336 case RETU_REG_ADCR:
337 s->channel = (val >> 10) & 0xf;
338 s->irqst |= 1 << retu_int_adcs;
339 retu_interrupt_update(s);
340 break;
341 case RETU_REG_ADCSCR:
342 s->sample &= ~val;
343 break;
344
345 case RETU_REG_AFCR:
346 case RETU_REG_ANTIFR:
347 case RETU_REG_CALIBR:
348
349 case RETU_REG_CCR1:
350 s->cc[0] = val;
351 break;
352 case RETU_REG_CCR2:
353 s->cc[1] = val;
354 break;
355
356 case RETU_REG_RCTRL_CLR:
357 case RETU_REG_RCTRL_SET:
358 /* TODO */
359 break;
360
361 case RETU_REG_WATCHDOG:
362 if (val == 0 && (s->cc[0] & 2))
363 qemu_system_shutdown_request();
364 break;
365
366 case RETU_REG_TXCR:
367 case RETU_REG_AUDTXR:
368 case RETU_REG_AUDPAR:
369 case RETU_REG_AUDRXR1:
370 case RETU_REG_AUDRXR2:
371 case RETU_REG_SGR1:
372 case RETU_REG_SCR1:
373 case RETU_REG_SGR2:
374 case RETU_REG_SCR2:
375 /* TODO */
376 break;
377
378 default:
379 cpu_abort(cpu_single_env, "%s: bad register %02x\n",
380 __FUNCTION__, reg);
381 }
382}
383
384static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
385{
386 struct cbus_retu_s *s = (struct cbus_retu_s *) opaque;
387
388 if (rw)
389 *val = retu_read(s, reg);
390 else
391 retu_write(s, reg, *val);
392}
393
394void *retu_init(qemu_irq irq, int vilma)
395{
396 struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s));
397
398 s->irq = irq;
399 s->irqen = 0xffff;
400 s->irqst = 0x0000;
401 s->status = 0x0020;
402 s->is_vilma = !!vilma;
403 s->rtc.cal = 0x01;
404 s->result[retu_adc_bsi] = 0x3c2;
405 s->result[retu_adc_batt_temp] = 0x0fc;
406 s->result[retu_adc_chg_volt] = 0x165;
407 s->result[retu_adc_head_det] = 123;
408 s->result[retu_adc_hook_det] = 1023;
409 s->result[retu_adc_rf_gp] = 0x11;
410 s->result[retu_adc_tx_det] = 0x11;
411 s->result[retu_adc_batt_volt] = 0x250;
412 s->result[retu_adc_sens] = 2;
413 s->result[retu_adc_sens_temp] = 0x11;
414 s->result[retu_adc_bbatt_volt] = 0x3d0;
415 s->result[retu_adc_self_temp] = 0x330;
416
417 s->cbus.opaque = s;
418 s->cbus.io = retu_io;
419 s->cbus.addr = 1;
420
421 return &s->cbus;
422}
423
424void retu_key_event(void *retu, int state)
425{
426 struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
427 struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
428
429 s->irqst |= 1 << retu_int_pwr;
430 retu_interrupt_update(s);
431
432 if (state)
433 s->status &= ~(1 << 5);
434 else
435 s->status |= 1 << 5;
436}
437
438void retu_head_event(void *retu, int state)
439{
440 struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
441 struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
442
443 if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
444 /* TODO: reissue the interrupt every 100ms or so. */
445 s->irqst |= 1 << retu_int_head;
446 retu_interrupt_update(s);
447 }
448
449 if (state)
450 s->result[retu_adc_head_det] = 50;
451 else
452 s->result[retu_adc_head_det] = 123;
453}
454
455void retu_hook_event(void *retu, int state)
456{
457 struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
458 struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
459
460 if ((s->cc[0] & 0x500) == 0x500) {
461 /* TODO: reissue the interrupt every 100ms or so. */
462 s->irqst |= 1 << retu_int_hook;
463 retu_interrupt_update(s);
464 }
465
466 if (state)
467 s->result[retu_adc_hook_det] = 50;
468 else
469 s->result[retu_adc_hook_det] = 123;
470}
471
472/* Tahvo/Betty */
473struct cbus_tahvo_s {
474 uint16_t irqst;
475 uint16_t irqen;
476 uint8_t charger;
477 uint8_t backlight;
478 uint16_t usbr;
479 uint16_t power;
480
481 int is_betty;
482 qemu_irq irq;
483 struct cbus_slave_s cbus;
484};
485
486static void tahvo_interrupt_update(struct cbus_tahvo_s *s)
487{
488 qemu_set_irq(s->irq, s->irqst & ~s->irqen);
489}
490
491#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
492#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
493#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
494#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
495#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
496#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
497#define TAHVO_REG_USBR 0x06 /* (RW) USB control */
498#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
499#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
500#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
501#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
502#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
503#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
504#define TAHVO_REG_FRR 0x0d /* (RO) FR */
505
506static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg)
507{
508#ifdef DEBUG
509 printf("TAHVO read at %02x\n", reg);
510#endif
511
512 switch (reg) {
513 case TAHVO_REG_ASICR:
514 return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
515
516 case TAHVO_REG_IDR:
517 case TAHVO_REG_IDSR: /* XXX: what does this do? */
518 return s->irqst;
519
520 case TAHVO_REG_IMR:
521 return s->irqen;
522
523 case TAHVO_REG_CHAPWMR:
524 return s->charger;
525
526 case TAHVO_REG_LEDPWMR:
527 return s->backlight;
528
529 case TAHVO_REG_USBR:
530 return s->usbr;
531
532 case TAHVO_REG_RCR:
533 return s->power;
534
535 case TAHVO_REG_CCR1:
536 case TAHVO_REG_CCR2:
537 case TAHVO_REG_TESTR1:
538 case TAHVO_REG_TESTR2:
539 case TAHVO_REG_NOPR:
540 case TAHVO_REG_FRR:
541 return 0x0000;
542
543 default:
544 cpu_abort(cpu_single_env, "%s: bad register %02x\n",
545 __FUNCTION__, reg);
546 }
547}
548
549static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val)
550{
551#ifdef DEBUG
552 printf("TAHVO write of %04x at %02x\n", val, reg);
553#endif
554
555 switch (reg) {
556 case TAHVO_REG_IDR:
557 s->irqst ^= val;
558 tahvo_interrupt_update(s);
559 break;
560
561 case TAHVO_REG_IMR:
562 s->irqen = val;
563 tahvo_interrupt_update(s);
564 break;
565
566 case TAHVO_REG_CHAPWMR:
567 s->charger = val;
568 break;
569
570 case TAHVO_REG_LEDPWMR:
571 if (s->backlight != (val & 0x7f)) {
572 s->backlight = val & 0x7f;
573 printf("%s: LCD backlight now at %i / 127\n",
574 __FUNCTION__, s->backlight);
575 }
576 break;
577
578 case TAHVO_REG_USBR:
579 s->usbr = val;
580 break;
581
582 case TAHVO_REG_RCR:
583 s->power = val;
584 break;
585
586 case TAHVO_REG_CCR1:
587 case TAHVO_REG_CCR2:
588 case TAHVO_REG_TESTR1:
589 case TAHVO_REG_TESTR2:
590 case TAHVO_REG_NOPR:
591 case TAHVO_REG_FRR:
592 break;
593
594 default:
595 cpu_abort(cpu_single_env, "%s: bad register %02x\n",
596 __FUNCTION__, reg);
597 }
598}
599
600static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
601{
602 struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque;
603
604 if (rw)
605 *val = tahvo_read(s, reg);
606 else
607 tahvo_write(s, reg, *val);
608}
609
610void *tahvo_init(qemu_irq irq, int betty)
611{
612 struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s));
613
614 s->irq = irq;
615 s->irqen = 0xffff;
616 s->irqst = 0x0000;
617 s->is_betty = !!betty;
618
619 s->cbus.opaque = s;
620 s->cbus.io = tahvo_io;
621 s->cbus.addr = 2;
622
623 return &s->cbus;
624}