qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cbus.c (15116B)


      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 along
     20  * with this program; if not, see <http://www.gnu.org/licenses/>.
     21  */
     22 
     23 #include "qemu/osdep.h"
     24 #include "hw/hw.h"
     25 #include "hw/irq.h"
     26 #include "hw/misc/cbus.h"
     27 #include "sysemu/runstate.h"
     28 
     29 //#define DEBUG
     30 
     31 typedef struct {
     32     void *opaque;
     33     void (*io)(void *opaque, int rw, int reg, uint16_t *val);
     34     int addr;
     35 } CBusSlave;
     36 
     37 typedef 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 
     59 static 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 
     68 static 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 
     97 static 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 
    114 static void cbus_dat(void *opaque, int line, int level)
    115 {
    116     CBusPriv *s = (CBusPriv *) opaque;
    117 
    118     s->dat = level;
    119 }
    120 
    121 static 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 
    134 CBus *cbus_init(qemu_irq dat)
    135 {
    136     CBusPriv *s = 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 
    150 void 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 /* Retu/Vilma */
    159 typedef 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 
    177 static 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	/* (RO) ASIC ID & revision */
    183 #define RETU_REG_IDR		0x01	/* (T)  Interrupt ID */
    184 #define RETU_REG_IMR		0x02	/* (RW) Interrupt mask */
    185 #define RETU_REG_RTCDSR		0x03	/* (RW) RTC seconds register */
    186 #define RETU_REG_RTCHMR		0x04	/* (RO) RTC hours and minutes reg */
    187 #define RETU_REG_RTCHMAR	0x05	/* (RW) RTC hours and minutes set reg */
    188 #define RETU_REG_RTCCALR	0x06	/* (RW) RTC calibration register */
    189 #define RETU_REG_ADCR		0x08	/* (RW) ADC result register */
    190 #define RETU_REG_ADCSCR		0x09	/* (RW) ADC sample control register */
    191 #define RETU_REG_AFCR		0x0a	/* (RW) AFC register */
    192 #define RETU_REG_ANTIFR		0x0b	/* (RW) AntiF register */
    193 #define RETU_REG_CALIBR		0x0c	/* (RW) CalibR register*/
    194 #define RETU_REG_CCR1		0x0d	/* (RW) Common control register 1 */
    195 #define RETU_REG_CCR2		0x0e	/* (RW) Common control register 2 */
    196 #define RETU_REG_RCTRL_CLR	0x0f	/* (T)  Regulator clear register */
    197 #define RETU_REG_RCTRL_SET	0x10	/* (T)  Regulator set register */
    198 #define RETU_REG_TXCR		0x11	/* (RW) TxC register */
    199 #define RETU_REG_STATUS		0x16	/* (RO) Status register */
    200 #define RETU_REG_WATCHDOG	0x17	/* (RW) Watchdog register */
    201 #define RETU_REG_AUDTXR		0x18	/* (RW) Audio Codec Tx register */
    202 #define RETU_REG_AUDPAR		0x19	/* (RW) AudioPA register */
    203 #define RETU_REG_AUDRXR1	0x1a	/* (RW) Audio receive register 1 */
    204 #define RETU_REG_AUDRXR2	0x1b	/* (RW) Audio receive register 2 */
    205 #define RETU_REG_SGR1		0x1c	/* (RW) */
    206 #define RETU_REG_SCR1		0x1d	/* (RW) */
    207 #define RETU_REG_SGR2		0x1e	/* (RW) */
    208 #define RETU_REG_SCR2		0x1f	/* (RW) */
    209 
    210 /* Retu Interrupt sources */
    211 enum {
    212     retu_int_pwr	= 0,	/* Power button */
    213     retu_int_char	= 1,	/* Charger */
    214     retu_int_rtcs	= 2,	/* Seconds */
    215     retu_int_rtcm	= 3,	/* Minutes */
    216     retu_int_rtcd	= 4,	/* Days */
    217     retu_int_rtca	= 5,	/* Alarm */
    218     retu_int_hook	= 6,	/* Hook */
    219     retu_int_head	= 7,	/* Headset */
    220     retu_int_adcs	= 8,	/* ADC sample */
    221 };
    222 
    223 /* Retu ADC channel wiring */
    224 enum {
    225     retu_adc_bsi	= 1,	/* BSI */
    226     retu_adc_batt_temp	= 2,	/* Battery temperature */
    227     retu_adc_chg_volt	= 3,	/* Charger voltage */
    228     retu_adc_head_det	= 4,	/* Headset detection */
    229     retu_adc_hook_det	= 5,	/* Hook detection */
    230     retu_adc_rf_gp	= 6,	/* RF GP */
    231     retu_adc_tx_det	= 7,	/* Wideband Tx detection */
    232     retu_adc_batt_volt	= 8,	/* Battery voltage */
    233     retu_adc_sens	= 10,	/* Light sensor */
    234     retu_adc_sens_temp	= 11,	/* Light sensor temperature */
    235     retu_adc_bbatt_volt	= 12,	/* Backup battery voltage */
    236     retu_adc_self_temp	= 13,	/* RETU temperature */
    237 };
    238 
    239 static 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:	/* TODO: Or is this ffs(s->irqst)?  */
    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         /* TODO */
    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         /* TODO */
    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         /* TODO */
    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         /* TODO */
    299         return 0x0000;
    300 
    301     default:
    302         hw_error("%s: bad register %02x\n", __func__, reg);
    303     }
    304 }
    305 
    306 static 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         /* TODO */
    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         /* TODO */
    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         /* TODO */
    372         break;
    373 
    374     default:
    375         hw_error("%s: bad register %02x\n", __func__, reg);
    376     }
    377 }
    378 
    379 static 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 
    389 void *retu_init(qemu_irq irq, int vilma)
    390 {
    391     CBusRetu *s = 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 
    419 void 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
    434 static 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) {	/* TODO: Which bits? */
    440         /* TODO: reissue the interrupt every 100ms or so.  */
    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 
    451 static 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         /* TODO: reissue the interrupt every 100ms or so.  */
    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 /* Tahvo/Betty */
    470 typedef 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 
    483 static 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	/* (RO) ASIC ID & revision */
    489 #define TAHVO_REG_IDR		0x01	/* (T)  Interrupt ID */
    490 #define TAHVO_REG_IDSR		0x02	/* (RO) Interrupt status */
    491 #define TAHVO_REG_IMR		0x03	/* (RW) Interrupt mask */
    492 #define TAHVO_REG_CHAPWMR	0x04	/* (RW) Charger PWM */
    493 #define TAHVO_REG_LEDPWMR	0x05	/* (RW) LED PWM */
    494 #define TAHVO_REG_USBR		0x06	/* (RW) USB control */
    495 #define TAHVO_REG_RCR		0x07	/* (RW) Some kind of power management */
    496 #define TAHVO_REG_CCR1		0x08	/* (RW) Common control register 1 */
    497 #define TAHVO_REG_CCR2		0x09	/* (RW) Common control register 2 */
    498 #define TAHVO_REG_TESTR1	0x0a	/* (RW) Test register 1 */
    499 #define TAHVO_REG_TESTR2	0x0b	/* (RW) Test register 2 */
    500 #define TAHVO_REG_NOPR		0x0c	/* (RW) Number of periods */
    501 #define TAHVO_REG_FRR		0x0d	/* (RO) FR */
    502 
    503 static 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);	/* 22 in N810 */
    512 
    513     case TAHVO_REG_IDR:
    514     case TAHVO_REG_IDSR:	/* XXX: what does this do?  */
    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 
    545 static 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 
    595 static 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 
    605 void *tahvo_init(qemu_irq irq, int betty)
    606 {
    607     CBusTahvo *s = 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 }