xref: /openbmc/qemu/hw/display/dm163.c (revision c771f883)
1*c771f883SInès Varhol /*
2*c771f883SInès Varhol  * QEMU DM163 8x3-channel constant current led driver
3*c771f883SInès Varhol  * driving columns of associated 8x8 RGB matrix.
4*c771f883SInès Varhol  *
5*c771f883SInès Varhol  * Copyright (C) 2024 Samuel Tardieu <sam@rfc1149.net>
6*c771f883SInès Varhol  * Copyright (C) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
7*c771f883SInès Varhol  * Copyright (C) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
8*c771f883SInès Varhol  *
9*c771f883SInès Varhol  * SPDX-License-Identifier: GPL-2.0-or-later
10*c771f883SInès Varhol  */
11*c771f883SInès Varhol 
12*c771f883SInès Varhol /*
13*c771f883SInès Varhol  * The reference used for the DM163 is the following :
14*c771f883SInès Varhol  * http://www.siti.com.tw/product/spec/LED/DM163.pdf
15*c771f883SInès Varhol  */
16*c771f883SInès Varhol 
17*c771f883SInès Varhol #include "qemu/osdep.h"
18*c771f883SInès Varhol #include "qapi/error.h"
19*c771f883SInès Varhol #include "migration/vmstate.h"
20*c771f883SInès Varhol #include "hw/irq.h"
21*c771f883SInès Varhol #include "hw/qdev-properties.h"
22*c771f883SInès Varhol #include "hw/display/dm163.h"
23*c771f883SInès Varhol #include "ui/console.h"
24*c771f883SInès Varhol #include "trace.h"
25*c771f883SInès Varhol 
26*c771f883SInès Varhol #define LED_SQUARE_SIZE 100
27*c771f883SInès Varhol /* Number of frames a row stays visible after being turned off. */
28*c771f883SInès Varhol #define ROW_PERSISTENCE 3
29*c771f883SInès Varhol #define TURNED_OFF_ROW (COLOR_BUFFER_SIZE - 1)
30*c771f883SInès Varhol 
31*c771f883SInès Varhol static const VMStateDescription vmstate_dm163 = {
32*c771f883SInès Varhol     .name = TYPE_DM163,
33*c771f883SInès Varhol     .version_id = 1,
34*c771f883SInès Varhol     .minimum_version_id = 1,
35*c771f883SInès Varhol     .fields = (const VMStateField[]) {
36*c771f883SInès Varhol         VMSTATE_UINT64_ARRAY(bank0_shift_register, DM163State, 3),
37*c771f883SInès Varhol         VMSTATE_UINT64_ARRAY(bank1_shift_register, DM163State, 3),
38*c771f883SInès Varhol         VMSTATE_UINT16_ARRAY(latched_outputs, DM163State, DM163_NUM_LEDS),
39*c771f883SInès Varhol         VMSTATE_UINT16_ARRAY(outputs, DM163State, DM163_NUM_LEDS),
40*c771f883SInès Varhol         VMSTATE_UINT8(dck, DM163State),
41*c771f883SInès Varhol         VMSTATE_UINT8(en_b, DM163State),
42*c771f883SInès Varhol         VMSTATE_UINT8(lat_b, DM163State),
43*c771f883SInès Varhol         VMSTATE_UINT8(rst_b, DM163State),
44*c771f883SInès Varhol         VMSTATE_UINT8(selbk, DM163State),
45*c771f883SInès Varhol         VMSTATE_UINT8(sin, DM163State),
46*c771f883SInès Varhol         VMSTATE_UINT8(activated_rows, DM163State),
47*c771f883SInès Varhol         VMSTATE_UINT32_2DARRAY(buffer, DM163State, COLOR_BUFFER_SIZE,
48*c771f883SInès Varhol                                RGB_MATRIX_NUM_COLS),
49*c771f883SInès Varhol         VMSTATE_UINT8(last_buffer_idx, DM163State),
50*c771f883SInès Varhol         VMSTATE_UINT8_ARRAY(buffer_idx_of_row, DM163State, RGB_MATRIX_NUM_ROWS),
51*c771f883SInès Varhol         VMSTATE_UINT8_ARRAY(row_persistence_delay, DM163State,
52*c771f883SInès Varhol                             RGB_MATRIX_NUM_ROWS),
53*c771f883SInès Varhol         VMSTATE_END_OF_LIST()
54*c771f883SInès Varhol     }
55*c771f883SInès Varhol };
56*c771f883SInès Varhol 
dm163_reset_hold(Object * obj,ResetType type)57*c771f883SInès Varhol static void dm163_reset_hold(Object *obj, ResetType type)
58*c771f883SInès Varhol {
59*c771f883SInès Varhol     DM163State *s = DM163(obj);
60*c771f883SInès Varhol 
61*c771f883SInès Varhol     s->sin = 0;
62*c771f883SInès Varhol     s->dck = 0;
63*c771f883SInès Varhol     s->rst_b = 0;
64*c771f883SInès Varhol     /* Ensuring the first falling edge of lat_b isn't missed */
65*c771f883SInès Varhol     s->lat_b = 1;
66*c771f883SInès Varhol     s->selbk = 0;
67*c771f883SInès Varhol     s->en_b = 0;
68*c771f883SInès Varhol     /* Reset stops the PWM, not the shift and latched registers. */
69*c771f883SInès Varhol     memset(s->outputs, 0, sizeof(s->outputs));
70*c771f883SInès Varhol 
71*c771f883SInès Varhol     s->activated_rows = 0;
72*c771f883SInès Varhol     s->redraw = 0;
73*c771f883SInès Varhol     trace_dm163_redraw(s->redraw);
74*c771f883SInès Varhol     for (unsigned i = 0; i < COLOR_BUFFER_SIZE; i++) {
75*c771f883SInès Varhol         memset(s->buffer[i], 0, sizeof(s->buffer[0]));
76*c771f883SInès Varhol     }
77*c771f883SInès Varhol     s->last_buffer_idx = 0;
78*c771f883SInès Varhol     memset(s->buffer_idx_of_row, TURNED_OFF_ROW, sizeof(s->buffer_idx_of_row));
79*c771f883SInès Varhol     memset(s->row_persistence_delay, 0, sizeof(s->row_persistence_delay));
80*c771f883SInès Varhol }
81*c771f883SInès Varhol 
dm163_dck_gpio_handler(void * opaque,int line,int new_state)82*c771f883SInès Varhol static void dm163_dck_gpio_handler(void *opaque, int line, int new_state)
83*c771f883SInès Varhol {
84*c771f883SInès Varhol     DM163State *s = opaque;
85*c771f883SInès Varhol 
86*c771f883SInès Varhol     if (new_state && !s->dck) {
87*c771f883SInès Varhol         /*
88*c771f883SInès Varhol          * On raising dck, sample selbk to get the bank to use, and
89*c771f883SInès Varhol          * sample sin for the bit to enter into the bank shift buffer.
90*c771f883SInès Varhol          */
91*c771f883SInès Varhol         uint64_t *sb =
92*c771f883SInès Varhol             s->selbk ? s->bank1_shift_register : s->bank0_shift_register;
93*c771f883SInès Varhol         /* Output the outgoing bit on sout */
94*c771f883SInès Varhol         const bool sout = (s->selbk ? sb[2] & MAKE_64BIT_MASK(63, 1) :
95*c771f883SInès Varhol                            sb[2] & MAKE_64BIT_MASK(15, 1)) != 0;
96*c771f883SInès Varhol         qemu_set_irq(s->sout, sout);
97*c771f883SInès Varhol         /* Enter sin into the shift buffer */
98*c771f883SInès Varhol         sb[2] = (sb[2] << 1) | ((sb[1] >> 63) & 1);
99*c771f883SInès Varhol         sb[1] = (sb[1] << 1) | ((sb[0] >> 63) & 1);
100*c771f883SInès Varhol         sb[0] = (sb[0] << 1) | s->sin;
101*c771f883SInès Varhol     }
102*c771f883SInès Varhol 
103*c771f883SInès Varhol     s->dck = new_state;
104*c771f883SInès Varhol     trace_dm163_dck(new_state);
105*c771f883SInès Varhol }
106*c771f883SInès Varhol 
dm163_propagate_outputs(DM163State * s)107*c771f883SInès Varhol static void dm163_propagate_outputs(DM163State *s)
108*c771f883SInès Varhol {
109*c771f883SInès Varhol     s->last_buffer_idx = (s->last_buffer_idx + 1) % RGB_MATRIX_NUM_ROWS;
110*c771f883SInès Varhol     /* Values are output when reset is high and enable is low. */
111*c771f883SInès Varhol     if (s->rst_b && !s->en_b) {
112*c771f883SInès Varhol         memcpy(s->outputs, s->latched_outputs, sizeof(s->outputs));
113*c771f883SInès Varhol     } else {
114*c771f883SInès Varhol         memset(s->outputs, 0, sizeof(s->outputs));
115*c771f883SInès Varhol     }
116*c771f883SInès Varhol     for (unsigned x = 0; x < RGB_MATRIX_NUM_COLS; x++) {
117*c771f883SInès Varhol         /* Grouping the 3 RGB channels in a pixel value */
118*c771f883SInès Varhol         const uint16_t b = extract16(s->outputs[3 * x + 0], 6, 8);
119*c771f883SInès Varhol         const uint16_t g = extract16(s->outputs[3 * x + 1], 6, 8);
120*c771f883SInès Varhol         const uint16_t r = extract16(s->outputs[3 * x + 2], 6, 8);
121*c771f883SInès Varhol         uint32_t rgba = 0;
122*c771f883SInès Varhol 
123*c771f883SInès Varhol         trace_dm163_channels(3 * x + 2, r);
124*c771f883SInès Varhol         trace_dm163_channels(3 * x + 1, g);
125*c771f883SInès Varhol         trace_dm163_channels(3 * x + 0, b);
126*c771f883SInès Varhol 
127*c771f883SInès Varhol         rgba = deposit32(rgba,  0, 8, r);
128*c771f883SInès Varhol         rgba = deposit32(rgba,  8, 8, g);
129*c771f883SInès Varhol         rgba = deposit32(rgba, 16, 8, b);
130*c771f883SInès Varhol 
131*c771f883SInès Varhol         /* Led values are sent from the last one to the first one */
132*c771f883SInès Varhol         s->buffer[s->last_buffer_idx][RGB_MATRIX_NUM_COLS - x - 1] = rgba;
133*c771f883SInès Varhol     }
134*c771f883SInès Varhol     for (unsigned row = 0; row < RGB_MATRIX_NUM_ROWS; row++) {
135*c771f883SInès Varhol         if (s->activated_rows & (1 << row)) {
136*c771f883SInès Varhol             s->buffer_idx_of_row[row] = s->last_buffer_idx;
137*c771f883SInès Varhol             s->redraw |= (1 << row);
138*c771f883SInès Varhol             trace_dm163_redraw(s->redraw);
139*c771f883SInès Varhol         }
140*c771f883SInès Varhol     }
141*c771f883SInès Varhol }
142*c771f883SInès Varhol 
dm163_en_b_gpio_handler(void * opaque,int line,int new_state)143*c771f883SInès Varhol static void dm163_en_b_gpio_handler(void *opaque, int line, int new_state)
144*c771f883SInès Varhol {
145*c771f883SInès Varhol     DM163State *s = opaque;
146*c771f883SInès Varhol 
147*c771f883SInès Varhol     s->en_b = new_state;
148*c771f883SInès Varhol     dm163_propagate_outputs(s);
149*c771f883SInès Varhol     trace_dm163_en_b(new_state);
150*c771f883SInès Varhol }
151*c771f883SInès Varhol 
dm163_bank0(const DM163State * s,uint8_t led)152*c771f883SInès Varhol static uint8_t dm163_bank0(const DM163State *s, uint8_t led)
153*c771f883SInès Varhol {
154*c771f883SInès Varhol     /*
155*c771f883SInès Varhol      * Bank 0 uses 6 bits per led, so a value may be stored accross
156*c771f883SInès Varhol      * two uint64_t entries.
157*c771f883SInès Varhol      */
158*c771f883SInès Varhol     const uint8_t low_bit = 6 * led;
159*c771f883SInès Varhol     const uint8_t low_word = low_bit / 64;
160*c771f883SInès Varhol     const uint8_t high_word = (low_bit + 5) / 64;
161*c771f883SInès Varhol     const uint8_t low_shift = low_bit % 64;
162*c771f883SInès Varhol 
163*c771f883SInès Varhol     if (low_word == high_word) {
164*c771f883SInès Varhol         /* Simple case: the value belongs to one entry. */
165*c771f883SInès Varhol         return extract64(s->bank0_shift_register[low_word], low_shift, 6);
166*c771f883SInès Varhol     }
167*c771f883SInès Varhol 
168*c771f883SInès Varhol     const uint8_t nb_bits_in_low_word = 64 - low_shift;
169*c771f883SInès Varhol     const uint8_t nb_bits_in_high_word = 6 - nb_bits_in_low_word;
170*c771f883SInès Varhol 
171*c771f883SInès Varhol     const uint64_t bits_in_low_word = \
172*c771f883SInès Varhol         extract64(s->bank0_shift_register[low_word], low_shift,
173*c771f883SInès Varhol                   nb_bits_in_low_word);
174*c771f883SInès Varhol     const uint64_t bits_in_high_word = \
175*c771f883SInès Varhol         extract64(s->bank0_shift_register[high_word], 0,
176*c771f883SInès Varhol                   nb_bits_in_high_word);
177*c771f883SInès Varhol     uint8_t val = 0;
178*c771f883SInès Varhol 
179*c771f883SInès Varhol     val = deposit32(val, 0, nb_bits_in_low_word, bits_in_low_word);
180*c771f883SInès Varhol     val = deposit32(val, nb_bits_in_low_word, nb_bits_in_high_word,
181*c771f883SInès Varhol                     bits_in_high_word);
182*c771f883SInès Varhol 
183*c771f883SInès Varhol     return val;
184*c771f883SInès Varhol }
185*c771f883SInès Varhol 
dm163_bank1(const DM163State * s,uint8_t led)186*c771f883SInès Varhol static uint8_t dm163_bank1(const DM163State *s, uint8_t led)
187*c771f883SInès Varhol {
188*c771f883SInès Varhol     const uint64_t entry = s->bank1_shift_register[led / RGB_MATRIX_NUM_COLS];
189*c771f883SInès Varhol     return extract64(entry, 8 * (led % RGB_MATRIX_NUM_COLS), 8);
190*c771f883SInès Varhol }
191*c771f883SInès Varhol 
dm163_lat_b_gpio_handler(void * opaque,int line,int new_state)192*c771f883SInès Varhol static void dm163_lat_b_gpio_handler(void *opaque, int line, int new_state)
193*c771f883SInès Varhol {
194*c771f883SInès Varhol     DM163State *s = opaque;
195*c771f883SInès Varhol 
196*c771f883SInès Varhol     if (s->lat_b && !new_state) {
197*c771f883SInès Varhol         for (int led = 0; led < DM163_NUM_LEDS; led++) {
198*c771f883SInès Varhol             s->latched_outputs[led] = dm163_bank0(s, led) * dm163_bank1(s, led);
199*c771f883SInès Varhol         }
200*c771f883SInès Varhol         dm163_propagate_outputs(s);
201*c771f883SInès Varhol     }
202*c771f883SInès Varhol 
203*c771f883SInès Varhol     s->lat_b = new_state;
204*c771f883SInès Varhol     trace_dm163_lat_b(new_state);
205*c771f883SInès Varhol }
206*c771f883SInès Varhol 
dm163_rst_b_gpio_handler(void * opaque,int line,int new_state)207*c771f883SInès Varhol static void dm163_rst_b_gpio_handler(void *opaque, int line, int new_state)
208*c771f883SInès Varhol {
209*c771f883SInès Varhol     DM163State *s = opaque;
210*c771f883SInès Varhol 
211*c771f883SInès Varhol     s->rst_b = new_state;
212*c771f883SInès Varhol     dm163_propagate_outputs(s);
213*c771f883SInès Varhol     trace_dm163_rst_b(new_state);
214*c771f883SInès Varhol }
215*c771f883SInès Varhol 
dm163_selbk_gpio_handler(void * opaque,int line,int new_state)216*c771f883SInès Varhol static void dm163_selbk_gpio_handler(void *opaque, int line, int new_state)
217*c771f883SInès Varhol {
218*c771f883SInès Varhol     DM163State *s = opaque;
219*c771f883SInès Varhol 
220*c771f883SInès Varhol     s->selbk = new_state;
221*c771f883SInès Varhol     trace_dm163_selbk(new_state);
222*c771f883SInès Varhol }
223*c771f883SInès Varhol 
dm163_sin_gpio_handler(void * opaque,int line,int new_state)224*c771f883SInès Varhol static void dm163_sin_gpio_handler(void *opaque, int line, int new_state)
225*c771f883SInès Varhol {
226*c771f883SInès Varhol     DM163State *s = opaque;
227*c771f883SInès Varhol 
228*c771f883SInès Varhol     s->sin = new_state;
229*c771f883SInès Varhol     trace_dm163_sin(new_state);
230*c771f883SInès Varhol }
231*c771f883SInès Varhol 
dm163_rows_gpio_handler(void * opaque,int line,int new_state)232*c771f883SInès Varhol static void dm163_rows_gpio_handler(void *opaque, int line, int new_state)
233*c771f883SInès Varhol {
234*c771f883SInès Varhol     DM163State *s = opaque;
235*c771f883SInès Varhol 
236*c771f883SInès Varhol     if (new_state) {
237*c771f883SInès Varhol         s->activated_rows |= (1 << line);
238*c771f883SInès Varhol         s->buffer_idx_of_row[line] = s->last_buffer_idx;
239*c771f883SInès Varhol         s->redraw |= (1 << line);
240*c771f883SInès Varhol         trace_dm163_redraw(s->redraw);
241*c771f883SInès Varhol     } else {
242*c771f883SInès Varhol         s->activated_rows &= ~(1 << line);
243*c771f883SInès Varhol         s->row_persistence_delay[line] = ROW_PERSISTENCE;
244*c771f883SInès Varhol     }
245*c771f883SInès Varhol     trace_dm163_activated_rows(s->activated_rows);
246*c771f883SInès Varhol }
247*c771f883SInès Varhol 
dm163_invalidate_display(void * opaque)248*c771f883SInès Varhol static void dm163_invalidate_display(void *opaque)
249*c771f883SInès Varhol {
250*c771f883SInès Varhol     DM163State *s = (DM163State *)opaque;
251*c771f883SInès Varhol     s->redraw = 0xFF;
252*c771f883SInès Varhol     trace_dm163_redraw(s->redraw);
253*c771f883SInès Varhol }
254*c771f883SInès Varhol 
update_row_persistence_delay(DM163State * s,unsigned row)255*c771f883SInès Varhol static void update_row_persistence_delay(DM163State *s, unsigned row)
256*c771f883SInès Varhol {
257*c771f883SInès Varhol     if (s->row_persistence_delay[row]) {
258*c771f883SInès Varhol         s->row_persistence_delay[row]--;
259*c771f883SInès Varhol     } else {
260*c771f883SInès Varhol         /*
261*c771f883SInès Varhol          * If the ROW_PERSISTENCE delay is up,
262*c771f883SInès Varhol          * the row is turned off.
263*c771f883SInès Varhol          */
264*c771f883SInès Varhol         s->buffer_idx_of_row[row] = TURNED_OFF_ROW;
265*c771f883SInès Varhol         s->redraw |= (1 << row);
266*c771f883SInès Varhol         trace_dm163_redraw(s->redraw);
267*c771f883SInès Varhol     }
268*c771f883SInès Varhol }
269*c771f883SInès Varhol 
update_display_of_row(DM163State * s,uint32_t * dest,unsigned row)270*c771f883SInès Varhol static uint32_t *update_display_of_row(DM163State *s, uint32_t *dest,
271*c771f883SInès Varhol                                        unsigned row)
272*c771f883SInès Varhol {
273*c771f883SInès Varhol     for (unsigned _ = 0; _ < LED_SQUARE_SIZE; _++) {
274*c771f883SInès Varhol         for (int x = 0; x < RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE; x++) {
275*c771f883SInès Varhol             /* UI layer guarantees that there's 32 bits per pixel (Mar 2024) */
276*c771f883SInès Varhol             *dest++ = s->buffer[s->buffer_idx_of_row[row]][x / LED_SQUARE_SIZE];
277*c771f883SInès Varhol         }
278*c771f883SInès Varhol     }
279*c771f883SInès Varhol 
280*c771f883SInès Varhol     dpy_gfx_update(s->console, 0, LED_SQUARE_SIZE * row,
281*c771f883SInès Varhol                     RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE, LED_SQUARE_SIZE);
282*c771f883SInès Varhol     s->redraw &= ~(1 << row);
283*c771f883SInès Varhol     trace_dm163_redraw(s->redraw);
284*c771f883SInès Varhol 
285*c771f883SInès Varhol     return dest;
286*c771f883SInès Varhol }
287*c771f883SInès Varhol 
dm163_update_display(void * opaque)288*c771f883SInès Varhol static void dm163_update_display(void *opaque)
289*c771f883SInès Varhol {
290*c771f883SInès Varhol     DM163State *s = (DM163State *)opaque;
291*c771f883SInès Varhol     DisplaySurface *surface = qemu_console_surface(s->console);
292*c771f883SInès Varhol     uint32_t *dest;
293*c771f883SInès Varhol 
294*c771f883SInès Varhol     dest = surface_data(surface);
295*c771f883SInès Varhol     for (unsigned row = 0; row < RGB_MATRIX_NUM_ROWS; row++) {
296*c771f883SInès Varhol         update_row_persistence_delay(s, row);
297*c771f883SInès Varhol         if (!extract8(s->redraw, row, 1)) {
298*c771f883SInès Varhol             dest += LED_SQUARE_SIZE * LED_SQUARE_SIZE * RGB_MATRIX_NUM_COLS;
299*c771f883SInès Varhol             continue;
300*c771f883SInès Varhol         }
301*c771f883SInès Varhol         dest = update_display_of_row(s, dest, row);
302*c771f883SInès Varhol     }
303*c771f883SInès Varhol }
304*c771f883SInès Varhol 
305*c771f883SInès Varhol static const GraphicHwOps dm163_ops = {
306*c771f883SInès Varhol     .invalidate  = dm163_invalidate_display,
307*c771f883SInès Varhol     .gfx_update  = dm163_update_display,
308*c771f883SInès Varhol };
309*c771f883SInès Varhol 
dm163_realize(DeviceState * dev,Error ** errp)310*c771f883SInès Varhol static void dm163_realize(DeviceState *dev, Error **errp)
311*c771f883SInès Varhol {
312*c771f883SInès Varhol     DM163State *s = DM163(dev);
313*c771f883SInès Varhol 
314*c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_rows_gpio_handler, RGB_MATRIX_NUM_ROWS);
315*c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_sin_gpio_handler, 1);
316*c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_dck_gpio_handler, 1);
317*c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_rst_b_gpio_handler, 1);
318*c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_lat_b_gpio_handler, 1);
319*c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_selbk_gpio_handler, 1);
320*c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_en_b_gpio_handler, 1);
321*c771f883SInès Varhol     qdev_init_gpio_out_named(dev, &s->sout, "sout", 1);
322*c771f883SInès Varhol 
323*c771f883SInès Varhol     s->console = graphic_console_init(dev, 0, &dm163_ops, s);
324*c771f883SInès Varhol     qemu_console_resize(s->console, RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE,
325*c771f883SInès Varhol                         RGB_MATRIX_NUM_ROWS * LED_SQUARE_SIZE);
326*c771f883SInès Varhol }
327*c771f883SInès Varhol 
dm163_class_init(ObjectClass * klass,void * data)328*c771f883SInès Varhol static void dm163_class_init(ObjectClass *klass, void *data)
329*c771f883SInès Varhol {
330*c771f883SInès Varhol     DeviceClass *dc = DEVICE_CLASS(klass);
331*c771f883SInès Varhol     ResettableClass *rc = RESETTABLE_CLASS(klass);
332*c771f883SInès Varhol 
333*c771f883SInès Varhol     dc->desc = "DM163";
334*c771f883SInès Varhol     dc->vmsd = &vmstate_dm163;
335*c771f883SInès Varhol     dc->realize = dm163_realize;
336*c771f883SInès Varhol     rc->phases.hold = dm163_reset_hold;
337*c771f883SInès Varhol     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
338*c771f883SInès Varhol }
339*c771f883SInès Varhol 
340*c771f883SInès Varhol static const TypeInfo dm163_types[] = {
341*c771f883SInès Varhol     {
342*c771f883SInès Varhol         .name = TYPE_DM163,
343*c771f883SInès Varhol         .parent = TYPE_DEVICE,
344*c771f883SInès Varhol         .instance_size = sizeof(DM163State),
345*c771f883SInès Varhol         .class_init = dm163_class_init
346*c771f883SInès Varhol     }
347*c771f883SInès Varhol };
348*c771f883SInès Varhol 
349*c771f883SInès Varhol DEFINE_TYPES(dm163_types)
350