178c71af8SPeter Maydell /* A simple I2C slave for returning monitor EDID data via DDC. 278c71af8SPeter Maydell * 378c71af8SPeter Maydell * Copyright (c) 2011 Linaro Limited 478c71af8SPeter Maydell * Written by Peter Maydell 578c71af8SPeter Maydell * 678c71af8SPeter Maydell * This program is free software; you can redistribute it and/or modify 778c71af8SPeter Maydell * it under the terms of the GNU General Public License version 2 as 878c71af8SPeter Maydell * published by the Free Software Foundation. 978c71af8SPeter Maydell * 1078c71af8SPeter Maydell * This program is distributed in the hope that it will be useful, 1178c71af8SPeter Maydell * but WITHOUT ANY WARRANTY; without even the implied warranty of 1278c71af8SPeter Maydell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1378c71af8SPeter Maydell * GNU General Public License for more details. 1478c71af8SPeter Maydell * 1578c71af8SPeter Maydell * You should have received a copy of the GNU General Public License along 1678c71af8SPeter Maydell * with this program; if not, see <http://www.gnu.org/licenses/>. 1778c71af8SPeter Maydell */ 1878c71af8SPeter Maydell 1978c71af8SPeter Maydell #include "qemu/osdep.h" 2008a0aee1SJuan Quintela #include "qemu-common.h" 2178c71af8SPeter Maydell #include "qemu/log.h" 2278c71af8SPeter Maydell #include "hw/i2c/i2c.h" 23*6306cae2SPaolo Bonzini #include "hw/display/i2c-ddc.h" 2478c71af8SPeter Maydell 2578c71af8SPeter Maydell #ifndef DEBUG_I2CDDC 2678c71af8SPeter Maydell #define DEBUG_I2CDDC 0 2778c71af8SPeter Maydell #endif 2878c71af8SPeter Maydell 2978c71af8SPeter Maydell #define DPRINTF(fmt, ...) do { \ 3078c71af8SPeter Maydell if (DEBUG_I2CDDC) { \ 3178c71af8SPeter Maydell qemu_log("i2c-ddc: " fmt , ## __VA_ARGS__); \ 3278c71af8SPeter Maydell } \ 332562755eSEric Blake } while (0) 3478c71af8SPeter Maydell 3578c71af8SPeter Maydell static void i2c_ddc_reset(DeviceState *ds) 3678c71af8SPeter Maydell { 3778c71af8SPeter Maydell I2CDDCState *s = I2CDDC(ds); 3878c71af8SPeter Maydell 3978c71af8SPeter Maydell s->firstbyte = false; 4078c71af8SPeter Maydell s->reg = 0; 4178c71af8SPeter Maydell } 4278c71af8SPeter Maydell 43d307c28cSCorey Minyard static int i2c_ddc_event(I2CSlave *i2c, enum i2c_event event) 4478c71af8SPeter Maydell { 4578c71af8SPeter Maydell I2CDDCState *s = I2CDDC(i2c); 4678c71af8SPeter Maydell 4778c71af8SPeter Maydell if (event == I2C_START_SEND) { 4878c71af8SPeter Maydell s->firstbyte = true; 4978c71af8SPeter Maydell } 50d307c28cSCorey Minyard 51d307c28cSCorey Minyard return 0; 5278c71af8SPeter Maydell } 5378c71af8SPeter Maydell 542ac4c5f4SCorey Minyard static uint8_t i2c_ddc_rx(I2CSlave *i2c) 5578c71af8SPeter Maydell { 5678c71af8SPeter Maydell I2CDDCState *s = I2CDDC(i2c); 5778c71af8SPeter Maydell 5878c71af8SPeter Maydell int value; 59b05b2678SGerd Hoffmann value = s->edid_blob[s->reg % sizeof(s->edid_blob)]; 6078c71af8SPeter Maydell s->reg++; 6178c71af8SPeter Maydell return value; 6278c71af8SPeter Maydell } 6378c71af8SPeter Maydell 6478c71af8SPeter Maydell static int i2c_ddc_tx(I2CSlave *i2c, uint8_t data) 6578c71af8SPeter Maydell { 6678c71af8SPeter Maydell I2CDDCState *s = I2CDDC(i2c); 6778c71af8SPeter Maydell if (s->firstbyte) { 6878c71af8SPeter Maydell s->reg = data; 6978c71af8SPeter Maydell s->firstbyte = false; 7078c71af8SPeter Maydell DPRINTF("[EDID] Written new pointer: %u\n", data); 71839a2b28SLinus Walleij return 0; 7278c71af8SPeter Maydell } 7378c71af8SPeter Maydell 7478c71af8SPeter Maydell /* Ignore all writes */ 7578c71af8SPeter Maydell s->reg++; 76839a2b28SLinus Walleij return 0; 7778c71af8SPeter Maydell } 7878c71af8SPeter Maydell 7978c71af8SPeter Maydell static void i2c_ddc_init(Object *obj) 8078c71af8SPeter Maydell { 8178c71af8SPeter Maydell I2CDDCState *s = I2CDDC(obj); 82715eb05bSGerd Hoffmann 83715eb05bSGerd Hoffmann qemu_edid_generate(s->edid_blob, sizeof(s->edid_blob), &s->edid_info); 8478c71af8SPeter Maydell } 8578c71af8SPeter Maydell 8678c71af8SPeter Maydell static const VMStateDescription vmstate_i2c_ddc = { 8778c71af8SPeter Maydell .name = TYPE_I2CDDC, 8878c71af8SPeter Maydell .version_id = 1, 8978c71af8SPeter Maydell .fields = (VMStateField[]) { 9078c71af8SPeter Maydell VMSTATE_BOOL(firstbyte, I2CDDCState), 9178c71af8SPeter Maydell VMSTATE_UINT8(reg, I2CDDCState), 9278c71af8SPeter Maydell VMSTATE_END_OF_LIST() 9378c71af8SPeter Maydell } 9478c71af8SPeter Maydell }; 9578c71af8SPeter Maydell 96715eb05bSGerd Hoffmann static Property i2c_ddc_properties[] = { 97715eb05bSGerd Hoffmann DEFINE_EDID_PROPERTIES(I2CDDCState, edid_info), 98715eb05bSGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 99715eb05bSGerd Hoffmann }; 100715eb05bSGerd Hoffmann 10178c71af8SPeter Maydell static void i2c_ddc_class_init(ObjectClass *oc, void *data) 10278c71af8SPeter Maydell { 10378c71af8SPeter Maydell DeviceClass *dc = DEVICE_CLASS(oc); 10478c71af8SPeter Maydell I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); 10578c71af8SPeter Maydell 10678c71af8SPeter Maydell dc->reset = i2c_ddc_reset; 10778c71af8SPeter Maydell dc->vmsd = &vmstate_i2c_ddc; 108715eb05bSGerd Hoffmann dc->props = i2c_ddc_properties; 10978c71af8SPeter Maydell isc->event = i2c_ddc_event; 11078c71af8SPeter Maydell isc->recv = i2c_ddc_rx; 11178c71af8SPeter Maydell isc->send = i2c_ddc_tx; 11278c71af8SPeter Maydell } 11378c71af8SPeter Maydell 11478c71af8SPeter Maydell static TypeInfo i2c_ddc_info = { 11578c71af8SPeter Maydell .name = TYPE_I2CDDC, 11678c71af8SPeter Maydell .parent = TYPE_I2C_SLAVE, 11778c71af8SPeter Maydell .instance_size = sizeof(I2CDDCState), 11878c71af8SPeter Maydell .instance_init = i2c_ddc_init, 11978c71af8SPeter Maydell .class_init = i2c_ddc_class_init 12078c71af8SPeter Maydell }; 12178c71af8SPeter Maydell 12278c71af8SPeter Maydell static void ddc_register_devices(void) 12378c71af8SPeter Maydell { 12478c71af8SPeter Maydell type_register_static(&i2c_ddc_info); 12578c71af8SPeter Maydell } 12678c71af8SPeter Maydell 12778c71af8SPeter Maydell type_init(ddc_register_devices); 128