2323#include "sysemu/runstate.h"
2424#include "qemu/timer.h"
2525#include "hw/qdev-properties.h"
26+ #include <pixman.h>
2627
2728#define PANEL_WIDTH 240
2829#define PANEL_HEIGHT 135
@@ -46,11 +47,12 @@ typedef struct ConsoleState {
4647 int cmd_mode ;
4748 int64_t lasttime ;
4849 int lastlevel ;
49- //int64_t offtime ;
50- uint32_t * data ; // surface data
50+ uint16_t * fb_data ;
51+ uint16_t * data ; // surface data
5152 int64_t time_off ;
5253 int64_t time_on ;
5354 QEMUTimer backlight_timer ;
55+
5456} ConsoleState ;
5557
5658// only one console
@@ -68,20 +70,27 @@ struct St7789vState {
6870#define TYPE_ST7789V "st7789v"
6971OBJECT_DECLARE_SIMPLE_TYPE (St7789vState , ST7789V )
7072
71- #define PORTRAIT_X_OFFSET 52
72- #define PORTRAIT_Y_OFFSET 40
73- #define LANDSCAPE_X_OFFSET 40
74- #define LANDSCAPE_Y_OFFSET 53
73+ #define PORTRAIT_X_OFFSET (52)
74+ #define PORTRAIT_Y_OFFSET (40)
75+ #define LANDSCAPE_X_OFFSET (40)
76+ #define LANDSCAPE_Y_OFFSET (53)
77+
78+ #define PORTRAIT_X_OFFSET_S3 (35)
79+ #define PORTRAIT_Y_OFFSET_S3 (0)
80+ #define LANDSCAPE_X_OFFSET_S3 (0)
81+ #define LANDSCAPE_Y_OFFSET_S3 (35)
7582
7683#define SKIN_PORTRAIT_X_OFFSET (62/2)
7784#define SKIN_PORTRAIT_Y_OFFSET (126/2)
7885#define SKIN_LANDSCAPE_X_OFFSET (126/2)
7986#define SKIN_LANDSCAPE_Y_OFFSET (82/2)
8087
81- #define SKIN_PORTRAIT_X_OFFSET_S3 (82/2)
82- #define SKIN_PORTRAIT_Y_OFFSET_S3 (126/2+48)
83- #define SKIN_LANDSCAPE_X_OFFSET_S3 (126/2+48)
84- #define SKIN_LANDSCAPE_Y_OFFSET_S3 (82/2-8)
88+ #define SKIN_PORTRAIT_X_OFFSET_S3 (38/2)
89+ #define SKIN_PORTRAIT_Y_OFFSET_S3 (126/2)
90+ #define SKIN_LANDSCAPE_X_OFFSET_S3 (126/2)
91+ #define SKIN_LANDSCAPE_Y_OFFSET_S3 (35/2)
92+
93+ #define DEBUG 0
8594
8695typedef struct { uint8_t r ; uint8_t g ; uint8_t b ; uint8_t a ;} pixel ;
8796
@@ -99,19 +108,34 @@ extern image_header ttgos3_board_skin;
99108image_header * board_skin = & ttgos3_board_skin ;
100109
101110
111+ static uint16_t argbto565 (uint32_t argb )
112+ {
113+ uint8_t r = (argb >> 16 ) & 0xFF ;
114+ uint8_t g = (argb >> 8 ) & 0xFF ;
115+ uint8_t b = (argb ) & 0xFF ;
116+
117+ return (uint16_t )(
118+ ((r >> 3 ) << 11 ) | // 5 bits red
119+ ((g >> 2 ) << 5 ) | // 6 bits green
120+ ( b >> 3 ) // 5 bits blue
121+ );
122+ }
123+
102124static void draw_skin (ConsoleState * c ) {
103- volatile uint32_t * dest = c -> data ;
125+ volatile uint16_t * dest = c -> data ;
104126 for (int i = 0 ; i < board_skin -> height ; i ++ )
105127 for (int j = 0 ; j < board_skin -> width ; j ++ ) {
106128 pixel p = board_skin -> pixel_data [i * board_skin -> width + j ];
107129 uint32_t rgba = (p .a <<24 ) | (p .r <<16 ) | (p .g <<8 ) | p .b ;
108130 if (p .a < 200 )
109131 rgba = 0xff000000 ;
132+ uint16_t rgb565 = argbto565 (rgba );
110133 if (c -> width < c -> height ) // portrait
111- dest [i * board_skin -> width + j ] = rgba ;
134+ dest [i * board_skin -> width + j ] = rgb565 ;
112135 else
113- dest [(board_skin -> width - j - 1 ) * board_skin -> height + i ] = rgba ;
136+ dest [(board_skin -> width - j - 1 ) * board_skin -> height + i ] = rgb565 ;
114137 }
138+ dpy_gfx_update_full (c -> con );
115139}
116140static void bl_timer_cb (void * v ) {
117141 uint64_t now = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
@@ -121,7 +145,9 @@ static void bl_timer_cb(void *v) {
121145 } else {
122146 c -> backlight = (c -> time_on * 256 )/(c -> time_on + c -> time_off );
123147 }
124- // printf("bl:%ld %ld %d\n",c->time_on,c->time_off, c->backlight);
148+ c -> redraw = 1 ;
149+ if (DEBUG )
150+ printf ("bl:%d %d %d\n" ,(int )c -> time_on ,(int )c -> time_off , c -> backlight );
125151 c -> time_on = 0 ;
126152 c -> time_off = 0 ;
127153 timer_mod_ns (& console_state .backlight_timer , now + 100000000 );
@@ -134,6 +160,11 @@ static void set_portrait(St7789vState *s) {
134160 board_skin = & ttgo_board_skin ;
135161 qemu_console_resize (c -> con , board_skin -> width ,
136162 board_skin -> height );
163+ DisplaySurface * surface = qemu_create_displaysurface_from (board_skin -> width , board_skin -> height ,
164+ PIXMAN_r5g6b5 ,
165+ board_skin -> width * 2 , NULL );
166+ dpy_gfx_replace_surface (c -> con ,surface );
167+
137168 c -> data = surface_data (qemu_console_surface (c -> con ));
138169 c -> width = PANEL_HEIGHT ;
139170 c -> height = PANEL_WIDTH ;
@@ -142,6 +173,10 @@ static void set_portrait(St7789vState *s) {
142173 c -> skin_x_offset = SKIN_PORTRAIT_X_OFFSET ;
143174 c -> skin_y_offset = SKIN_PORTRAIT_Y_OFFSET ;
144175 if (s -> iss3 ) {
176+ c -> width = 170 ;
177+ c -> height = 320 ;
178+ c -> x_offset = PORTRAIT_X_OFFSET_S3 ;
179+ c -> y_offset = PORTRAIT_Y_OFFSET_S3 ;
145180 c -> skin_x_offset = SKIN_PORTRAIT_X_OFFSET_S3 ;
146181 c -> skin_y_offset = SKIN_PORTRAIT_Y_OFFSET_S3 ;
147182 }
@@ -157,6 +192,10 @@ static void set_landscape(St7789vState *s) {
157192 board_skin = & ttgo_board_skin ;
158193 qemu_console_resize (c -> con , board_skin -> height ,
159194 board_skin -> width );
195+ DisplaySurface * surface = qemu_create_displaysurface_from (board_skin -> height , board_skin -> width ,
196+ PIXMAN_r5g6b5 ,
197+ board_skin -> height * 2 , NULL );
198+ dpy_gfx_replace_surface (c -> con ,surface );
160199 c -> data = surface_data (qemu_console_surface (c -> con ));
161200 c -> width = PANEL_WIDTH ;
162201 c -> height = PANEL_HEIGHT ;
@@ -165,6 +204,10 @@ static void set_landscape(St7789vState *s) {
165204 c -> skin_x_offset = SKIN_LANDSCAPE_X_OFFSET ;
166205 c -> skin_y_offset = SKIN_LANDSCAPE_Y_OFFSET ;
167206 if (s -> iss3 ) {
207+ c -> width = 320 ;
208+ c -> height = 170 ;
209+ c -> x_offset = LANDSCAPE_X_OFFSET_S3 ;
210+ c -> y_offset = LANDSCAPE_Y_OFFSET_S3 ;
168211 c -> skin_x_offset = SKIN_LANDSCAPE_X_OFFSET_S3 ;
169212 c -> skin_y_offset = SKIN_LANDSCAPE_Y_OFFSET_S3 ;
170213 }
@@ -178,11 +221,13 @@ static uint32_t st7789v_transfer(SSIPeripheral *dev, uint32_t data)
178221{
179222 ConsoleState * c = & console_state ;
180223 St7789vState * s = ST7789V (dev );
181- // printf(" st7789 %x %x\n", c->current_command, data);
224+
182225 uint8_t * bytes ;
183226 if (c -> cmd_mode ) {
184227 c -> current_command = data ;
185228 } else {
229+ if (DEBUG && c -> current_command != 0x2c )
230+ printf (" st7789 %x %x\n" , c -> current_command , data );
186231 switch (c -> current_command ) {
187232 case ST7789_MADCTL :
188233 if (data == 0 || data == 8 ) { // portrait
@@ -221,30 +266,9 @@ static uint32_t st7789v_transfer(SSIPeripheral *dev, uint32_t data)
221266 if (!c -> little_endian ) {
222267 d16 = (d16 >>8 ) | (d16 <<8 );
223268 }
224- int brightness = c -> backlight ;
225- int d32 ;
226- if (brightness == 256 ) {
227- d32 = ((d16 & 0xf800 ) << 8 ) |
228- ((d16 & 0x7e0 ) << 5 ) |
229- ((d16 & 0x1f ) << 3 ) | (0x80 <<24 );
230- } else {
231- if (brightness == 0 ) d32 = 0 ;
232- else {
233- int r = (d16 & 0xf800 )>>8 ;
234- int g = (d16 & 0x7e0 )>>3 ;
235- int b = (d16 & 0x1f )<<3 ;
236- r = (r * brightness )>>8 ;
237- g = (g * brightness )>>8 ;
238- b = (b * brightness )>>8 ;
239- d32 = r <<16 | g <<8 | b ;
240- }
241- }
242- // if(!c->backlight)
243- // d32=(d32>>2)&0x3f3f3f;
244- uint32_t offset = (c -> y - c -> y_offset + c -> skin_y_offset ) *
245- c -> skin_width + c -> x - c -> x_offset + c -> skin_x_offset ;
246- if (offset < board_skin -> height * board_skin -> width )
247- c -> data [offset ] = d32 ;
269+ uint32_t offset = c -> y * 320 + c -> x ;
270+ if (offset < 320 * 320 )
271+ c -> fb_data [offset ] = d16 ;
248272 c -> x ++ ;
249273 if (c -> x > c -> x_end ) {
250274 c -> x = c -> x_start ;
@@ -267,22 +291,24 @@ static uint32_t st7789v_transfer(SSIPeripheral *dev, uint32_t data)
267291/* Command/data input. */
268292static void st7789v_cd (void * opaque , int n , int level )
269293{
294+ if (DEBUG )
295+ printf ("st7789v_cd %d\n" ,level );
270296 ConsoleState * c = & console_state ;
271297 c -> cmd_mode = !level ;
272298}
273299
274300static void st7789v_backlight (void * opaque , int n , int level )
275301{
276302 int64_t now = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
303+ if (DEBUG )
304+ printf ("st7789v_backlight %d\n" ,level );
277305 ConsoleState * c = & console_state ;
278- // if(level==c->lastlevel) return;
279306 int v = level & 1 ;
280307 int t = c -> lastlevel >>1 ;
281308 c -> lastlevel = level ;
282309 if (t != 0 ) {
283310 now = c -> lasttime + t ;
284311 }
285- // printf("bl=%ld %d\n",now, level);
286312 if (now - c -> lasttime < 100000000 ) {
287313 if (v == 0 ) {
288314 c -> time_on += now - c -> lasttime ;
@@ -291,12 +317,7 @@ static void st7789v_backlight(void *opaque, int n, int level)
291317 }
292318 } else {
293319 c -> backlight = 256 * v ;
294- volatile unsigned * dest = c -> data ;
295- uint32_t px = v ?(64 <<16 )|(64 <<8 )|(64 ):0 ;
296- for (int y = 0 ;y < c -> height ;y ++ )
297- for (int x = 0 ;x < c -> width ;x ++ )
298- dest [(y + c -> skin_y_offset )* c -> skin_width + x + c -> skin_x_offset ]= px ^(rand ()& 0x0f0f0f );
299- dpy_gfx_update (c -> con , c -> skin_x_offset , c -> skin_y_offset , c -> width , c -> height );
320+ c -> redraw = 1 ;
300321 }
301322 c -> lasttime = now ;
302323}
@@ -305,8 +326,25 @@ static void st7789_update_display(void *opaque) {
305326 ConsoleState * c = & console_state ;
306327 if (!c -> redraw ) return ;
307328 c -> redraw = 0 ;
308- dpy_gfx_update_full (c -> con );
309- // dpy_gfx_update(c->con, c->skin_x_offset, c->skin_y_offset, c->width, c->height);
329+
330+ for (int y = 0 ;y < c -> height ;y ++ ) {
331+ for (int x = 0 ;x < c -> width ;x ++ ) {
332+ uint16_t rgb565 = c -> fb_data [(y + c -> y_offset )* 320 + x + c -> x_offset ];
333+ if (c -> backlight < 255 ) {
334+ uint32_t r = (rgb565 >>8 ) & 0xf8 ;
335+ uint32_t g = (rgb565 >>3 ) & 0xfc ;
336+ uint32_t b = (rgb565 <<2 ) & 0xf8 ;
337+ r = (r * c -> backlight )/256 ;
338+ g = (g * c -> backlight )/256 ;
339+ b = (b * c -> backlight )/256 ;
340+ rgb565 = (uint16_t )(((r >> 3 ) << 11 ) | ((g >> 2 ) << 5 ) | ( b >> 3 ));
341+ }
342+ uint32_t index = (y + c -> skin_y_offset )* c -> skin_width + x + c -> skin_x_offset ;
343+ if (index < 320 * 320 )
344+ c -> data [index ]= rgb565 ;
345+ }
346+ }
347+ dpy_gfx_update (c -> con , c -> skin_x_offset , c -> skin_y_offset , c -> width , c -> height );
310348}
311349
312350static void st7789_invalidate_display (void * opaque ) {
@@ -319,7 +357,6 @@ static const GraphicHwOps st7789_ops = {
319357 .gfx_update = st7789_update_display ,
320358};
321359
322- //extern int touch_sensor[14];
323360#define PW 1200
324361static void keyboard_event (DeviceState * dev , QemuConsole * src ,
325362 InputEvent * evt ) {
@@ -373,7 +410,6 @@ static void keyboard_event(DeviceState *dev, QemuConsole *src,
373410 qemu_set_irq (s -> touch_sensor [i ],0 );
374411 break ;
375412 }
376- // printf("xpos=%d ypos=%d\n",xpos,ypos);
377413 if (portrait ) {
378414 if (s -> iss3 ) {
379415 if (xpos > 24575 && xpos < 30561 && ypos > 30063 &&
@@ -435,7 +471,6 @@ static void keyboard_event(DeviceState *dev, QemuConsole *src,
435471 ypos < 29931 ) {
436472 qemu_set_irq (s -> button [0 ], up );
437473 }
438-
439474 if (xpos > 25382 && xpos < 30561 && ypos > 30063 &&
440475 ypos < 31382 && up == 0 )
441476 qemu_set_irq (s -> reset , 1 );
@@ -452,20 +487,15 @@ static void keyboard_event(DeviceState *dev, QemuConsole *src,
452487 up == 0 )
453488 qemu_set_irq (s -> reset , 1 );
454489 }
455- /*
456- int xs[] = {0, 0, 12166, 13618, 15277,
457- 16798, 0, 18388, 12166, 13791};
458- int ys[] = {0, 0, 31743, 31743, 31743,
459- 31743, 0, 2993, 2993, 2993};
460- for (int i = 2; i < 10; i++) {
461- if (i != 6) {
462- if (xpos > (xs[i] - PW) && xpos < (xs[i] + PW) &&
463- ypos > (ys[i] - PW) && ypos < (ys[i] + PW))
464- // touch_sensor[i] = 1000;
465-
466- }
490+
491+ int xs [] = {12166 , 13618 , 12166 , 13791 };
492+ int ys [] = {31743 , 31743 , 2993 , 2993 };
493+ for (int i = 0 ; i < 4 ; i ++ ) {
494+ if (xpos > (xs [i ] - PW ) && xpos < (xs [i ] + PW ) &&
495+ ypos > (ys [i ] - PW ) && ypos < (ys [i ] + PW ))
496+ qemu_set_irq (s -> touch_sensor [i ], 1000 );
467497 }
468- */
498+
469499 }
470500 break ;
471501 default :
@@ -500,10 +530,13 @@ static void st7789v_realize(SSIPeripheral *d, Error **errp) {
500530 if (console_state .con == 0 ) {
501531 ConsoleState * c = & console_state ;
502532 s -> con = c ;
503- console_state .con = graphic_console_init (dev , 0 , & st7789_ops , s );
533+ c -> con = graphic_console_init (dev , 0 , & st7789_ops , s );
534+
504535 int64_t now = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
505536 c -> lastlevel = 0 ;
506537 c -> lasttime = now ;
538+ c -> cmd_mode = 1 ;
539+ c -> fb_data = malloc (320 * 320 * 2 );
507540 timer_init_ns (& c -> backlight_timer ,QEMU_CLOCK_VIRTUAL , bl_timer_cb ,0 );
508541 timer_mod_ns (& c -> backlight_timer , now + 100000000 );
509542 set_landscape (s );
@@ -522,7 +555,7 @@ static void st7789v_reset(DeviceState *dev) {
522555static void st7789v_class_init (ObjectClass * klass , void * data ) {
523556 DeviceClass * dc = DEVICE_CLASS (klass );
524557 SSIPeripheralClass * k = SSI_PERIPHERAL_CLASS (klass );
525- dc -> legacy_reset = st7789v_reset ;
558+ device_class_set_legacy_reset ( dc , st7789v_reset ) ;
526559 k -> realize = st7789v_realize ;
527560 k -> transfer = st7789v_transfer ;
528561 k -> cs_polarity = SSI_CS_NONE ;
0 commit comments