cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

cbus.c (15156B)


      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
     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/* Retu/Vilma */
    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	/* (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 */
    211enum {
    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 */
    224enum {
    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
    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:	/* 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
    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        /* 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
    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) {	/* 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
    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        /* 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 */
    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	/* (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
    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);	/* 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
    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}