qemu

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

sii9022.c (4831B)


      1 /*
      2  * Silicon Image SiI9022
      3  *
      4  * This is a pretty hollow emulation: all we do is acknowledge that we
      5  * exist (chip ID) and confirm that we get switched over into DDC mode
      6  * so the emulated host can proceed to read out EDID data. All subsequent
      7  * set-up of connectors etc will be acknowledged and ignored.
      8  *
      9  * Copyright (C) 2018 Linus Walleij
     10  *
     11  * This work is licensed under the terms of the GNU GPL, version 2 or later.
     12  * See the COPYING file in the top-level directory.
     13  * SPDX-License-Identifier: GPL-2.0-or-later
     14  */
     15 
     16 #include "qemu/osdep.h"
     17 #include "qemu/module.h"
     18 #include "hw/i2c/i2c.h"
     19 #include "migration/vmstate.h"
     20 #include "hw/display/i2c-ddc.h"
     21 #include "trace.h"
     22 #include "qom/object.h"
     23 
     24 #define SII9022_SYS_CTRL_DATA 0x1a
     25 #define SII9022_SYS_CTRL_PWR_DWN 0x10
     26 #define SII9022_SYS_CTRL_AV_MUTE 0x08
     27 #define SII9022_SYS_CTRL_DDC_BUS_REQ 0x04
     28 #define SII9022_SYS_CTRL_DDC_BUS_GRTD 0x02
     29 #define SII9022_SYS_CTRL_OUTPUT_MODE 0x01
     30 #define SII9022_SYS_CTRL_OUTPUT_HDMI 1
     31 #define SII9022_SYS_CTRL_OUTPUT_DVI 0
     32 #define SII9022_REG_CHIPID 0x1b
     33 #define SII9022_INT_ENABLE 0x3c
     34 #define SII9022_INT_STATUS 0x3d
     35 #define SII9022_INT_STATUS_HOTPLUG 0x01;
     36 #define SII9022_INT_STATUS_PLUGGED 0x04;
     37 
     38 #define TYPE_SII9022 "sii9022"
     39 OBJECT_DECLARE_SIMPLE_TYPE(sii9022_state, SII9022)
     40 
     41 struct sii9022_state {
     42     I2CSlave parent_obj;
     43     uint8_t ptr;
     44     bool addr_byte;
     45     bool ddc_req;
     46     bool ddc_skip_finish;
     47     bool ddc;
     48 };
     49 
     50 static const VMStateDescription vmstate_sii9022 = {
     51     .name = "sii9022",
     52     .version_id = 1,
     53     .minimum_version_id = 1,
     54     .fields = (VMStateField[]) {
     55         VMSTATE_I2C_SLAVE(parent_obj, sii9022_state),
     56         VMSTATE_UINT8(ptr, sii9022_state),
     57         VMSTATE_BOOL(addr_byte, sii9022_state),
     58         VMSTATE_BOOL(ddc_req, sii9022_state),
     59         VMSTATE_BOOL(ddc_skip_finish, sii9022_state),
     60         VMSTATE_BOOL(ddc, sii9022_state),
     61         VMSTATE_END_OF_LIST()
     62     }
     63 };
     64 
     65 static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
     66 {
     67     sii9022_state *s = SII9022(i2c);
     68 
     69     switch (event) {
     70     case I2C_START_SEND:
     71         s->addr_byte = true;
     72         break;
     73     case I2C_START_RECV:
     74         break;
     75     case I2C_FINISH:
     76         break;
     77     case I2C_NACK:
     78         break;
     79     default:
     80         return -1;
     81     }
     82 
     83     return 0;
     84 }
     85 
     86 static uint8_t sii9022_rx(I2CSlave *i2c)
     87 {
     88     sii9022_state *s = SII9022(i2c);
     89     uint8_t res = 0x00;
     90 
     91     switch (s->ptr) {
     92     case SII9022_SYS_CTRL_DATA:
     93         if (s->ddc_req) {
     94             /* Acknowledge DDC bus request */
     95             res = SII9022_SYS_CTRL_DDC_BUS_GRTD | SII9022_SYS_CTRL_DDC_BUS_REQ;
     96         }
     97         break;
     98     case SII9022_REG_CHIPID:
     99         res = 0xb0;
    100         break;
    101     case SII9022_INT_STATUS:
    102         /* Something is cold-plugged in, no interrupts */
    103         res = SII9022_INT_STATUS_PLUGGED;
    104         break;
    105     default:
    106         break;
    107     }
    108 
    109     trace_sii9022_read_reg(s->ptr, res);
    110     s->ptr++;
    111 
    112     return res;
    113 }
    114 
    115 static int sii9022_tx(I2CSlave *i2c, uint8_t data)
    116 {
    117     sii9022_state *s = SII9022(i2c);
    118 
    119     if (s->addr_byte) {
    120         s->ptr = data;
    121         s->addr_byte = false;
    122         return 0;
    123     }
    124 
    125     switch (s->ptr) {
    126     case SII9022_SYS_CTRL_DATA:
    127         if (data & SII9022_SYS_CTRL_DDC_BUS_REQ) {
    128             s->ddc_req = true;
    129             if (data & SII9022_SYS_CTRL_DDC_BUS_GRTD) {
    130                 s->ddc = true;
    131                 /* Skip this finish since we just switched to DDC */
    132                 s->ddc_skip_finish = true;
    133                 trace_sii9022_switch_mode("DDC");
    134             }
    135         } else {
    136             s->ddc_req = false;
    137             s->ddc = false;
    138             trace_sii9022_switch_mode("normal");
    139         }
    140         break;
    141     default:
    142         break;
    143     }
    144 
    145     trace_sii9022_write_reg(s->ptr, data);
    146     s->ptr++;
    147 
    148     return 0;
    149 }
    150 
    151 static void sii9022_reset(DeviceState *dev)
    152 {
    153     sii9022_state *s = SII9022(dev);
    154 
    155     s->ptr = 0;
    156     s->addr_byte = false;
    157     s->ddc_req = false;
    158     s->ddc_skip_finish = false;
    159     s->ddc = false;
    160 }
    161 
    162 static void sii9022_realize(DeviceState *dev, Error **errp)
    163 {
    164     I2CBus *bus;
    165 
    166     bus = I2C_BUS(qdev_get_parent_bus(dev));
    167     i2c_slave_create_simple(bus, TYPE_I2CDDC, 0x50);
    168 }
    169 
    170 static void sii9022_class_init(ObjectClass *klass, void *data)
    171 {
    172     DeviceClass *dc = DEVICE_CLASS(klass);
    173     I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
    174 
    175     k->event = sii9022_event;
    176     k->recv = sii9022_rx;
    177     k->send = sii9022_tx;
    178     dc->reset = sii9022_reset;
    179     dc->realize = sii9022_realize;
    180     dc->vmsd = &vmstate_sii9022;
    181 }
    182 
    183 static const TypeInfo sii9022_info = {
    184     .name          = TYPE_SII9022,
    185     .parent        = TYPE_I2C_SLAVE,
    186     .instance_size = sizeof(sii9022_state),
    187     .class_init    = sii9022_class_init,
    188 };
    189 
    190 static void sii9022_register_types(void)
    191 {
    192     type_register_static(&sii9022_info);
    193 }
    194 
    195 type_init(sii9022_register_types)