]> git.proxmox.com Git - mirror_qemu.git/blame - hw/display/sii9022.c
Move QOM typedefs and add missing includes
[mirror_qemu.git] / hw / display / sii9022.c
CommitLineData
a643bd77
LW
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"
0b8fa32f 17#include "qemu/module.h"
a643bd77 18#include "hw/i2c/i2c.h"
d6454270 19#include "migration/vmstate.h"
6306cae2 20#include "hw/display/i2c-ddc.h"
a643bd77 21#include "trace.h"
db1015e9 22#include "qom/object.h"
a643bd77
LW
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"
db1015e9 39typedef struct sii9022_state sii9022_state;
a643bd77
LW
40#define SII9022(obj) OBJECT_CHECK(sii9022_state, (obj), TYPE_SII9022)
41
db1015e9 42struct sii9022_state {
a643bd77
LW
43 I2CSlave parent_obj;
44 uint8_t ptr;
45 bool addr_byte;
46 bool ddc_req;
47 bool ddc_skip_finish;
48 bool ddc;
db1015e9 49};
a643bd77
LW
50
51static const VMStateDescription vmstate_sii9022 = {
52 .name = "sii9022",
53 .version_id = 1,
54 .minimum_version_id = 1,
55 .fields = (VMStateField[]) {
56 VMSTATE_I2C_SLAVE(parent_obj, sii9022_state),
57 VMSTATE_UINT8(ptr, sii9022_state),
58 VMSTATE_BOOL(addr_byte, sii9022_state),
59 VMSTATE_BOOL(ddc_req, sii9022_state),
60 VMSTATE_BOOL(ddc_skip_finish, sii9022_state),
61 VMSTATE_BOOL(ddc, sii9022_state),
62 VMSTATE_END_OF_LIST()
63 }
64};
65
66static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
67{
68 sii9022_state *s = SII9022(i2c);
69
70 switch (event) {
71 case I2C_START_SEND:
72 s->addr_byte = true;
73 break;
74 case I2C_START_RECV:
75 break;
76 case I2C_FINISH:
77 break;
78 case I2C_NACK:
79 break;
80 }
81
82 return 0;
83}
84
2ac4c5f4 85static uint8_t sii9022_rx(I2CSlave *i2c)
a643bd77
LW
86{
87 sii9022_state *s = SII9022(i2c);
88 uint8_t res = 0x00;
89
90 switch (s->ptr) {
91 case SII9022_SYS_CTRL_DATA:
92 if (s->ddc_req) {
93 /* Acknowledge DDC bus request */
94 res = SII9022_SYS_CTRL_DDC_BUS_GRTD | SII9022_SYS_CTRL_DDC_BUS_REQ;
95 }
96 break;
97 case SII9022_REG_CHIPID:
98 res = 0xb0;
99 break;
100 case SII9022_INT_STATUS:
101 /* Something is cold-plugged in, no interrupts */
102 res = SII9022_INT_STATUS_PLUGGED;
103 break;
104 default:
105 break;
106 }
107
108 trace_sii9022_read_reg(s->ptr, res);
109 s->ptr++;
110
111 return res;
112}
113
114static int sii9022_tx(I2CSlave *i2c, uint8_t data)
115{
116 sii9022_state *s = SII9022(i2c);
117
118 if (s->addr_byte) {
119 s->ptr = data;
120 s->addr_byte = false;
121 return 0;
122 }
123
124 switch (s->ptr) {
125 case SII9022_SYS_CTRL_DATA:
126 if (data & SII9022_SYS_CTRL_DDC_BUS_REQ) {
127 s->ddc_req = true;
128 if (data & SII9022_SYS_CTRL_DDC_BUS_GRTD) {
129 s->ddc = true;
130 /* Skip this finish since we just switched to DDC */
131 s->ddc_skip_finish = true;
132 trace_sii9022_switch_mode("DDC");
133 }
134 } else {
135 s->ddc_req = false;
136 s->ddc = false;
137 trace_sii9022_switch_mode("normal");
138 }
139 break;
140 default:
141 break;
142 }
143
144 trace_sii9022_write_reg(s->ptr, data);
145 s->ptr++;
146
147 return 0;
148}
149
150static void sii9022_reset(DeviceState *dev)
151{
152 sii9022_state *s = SII9022(dev);
153
154 s->ptr = 0;
155 s->addr_byte = false;
156 s->ddc_req = false;
157 s->ddc_skip_finish = false;
158 s->ddc = false;
159}
160
161static void sii9022_realize(DeviceState *dev, Error **errp)
162{
163 I2CBus *bus;
164
165 bus = I2C_BUS(qdev_get_parent_bus(dev));
1373b15b 166 i2c_slave_create_simple(bus, TYPE_I2CDDC, 0x50);
a643bd77
LW
167}
168
169static void sii9022_class_init(ObjectClass *klass, void *data)
170{
171 DeviceClass *dc = DEVICE_CLASS(klass);
172 I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
173
174 k->event = sii9022_event;
175 k->recv = sii9022_rx;
176 k->send = sii9022_tx;
177 dc->reset = sii9022_reset;
178 dc->realize = sii9022_realize;
179 dc->vmsd = &vmstate_sii9022;
180}
181
182static const TypeInfo sii9022_info = {
183 .name = TYPE_SII9022,
184 .parent = TYPE_I2C_SLAVE,
185 .instance_size = sizeof(sii9022_state),
186 .class_init = sii9022_class_init,
187};
188
189static void sii9022_register_types(void)
190{
191 type_register_static(&sii9022_info);
192}
193
194type_init(sii9022_register_types)