pxa2xx_lcd.c (41128B)
1/* 2 * Intel XScale PXA255/270 LCDC emulation. 3 * 4 * Copyright (c) 2006 Openedhand Ltd. 5 * Written by Andrzej Zaborowski <balrog@zabor.org> 6 * 7 * This code is licensed under the GPLv2. 8 * 9 * Contributions after 2012-01-13 are licensed under the terms of the 10 * GNU GPL, version 2 or (at your option) any later version. 11 */ 12 13#include "qemu/osdep.h" 14#include "qemu/log.h" 15#include "hw/irq.h" 16#include "migration/vmstate.h" 17#include "ui/console.h" 18#include "hw/arm/pxa.h" 19#include "ui/pixel_ops.h" 20#include "hw/boards.h" 21/* FIXME: For graphic_rotate. Should probably be done in common code. */ 22#include "sysemu/sysemu.h" 23#include "framebuffer.h" 24 25struct DMAChannel { 26 uint32_t branch; 27 uint8_t up; 28 uint8_t palette[1024]; 29 uint8_t pbuffer[1024]; 30 void (*redraw)(PXA2xxLCDState *s, hwaddr addr, 31 int *miny, int *maxy); 32 33 uint32_t descriptor; 34 uint32_t source; 35 uint32_t id; 36 uint32_t command; 37}; 38 39struct PXA2xxLCDState { 40 MemoryRegion *sysmem; 41 MemoryRegion iomem; 42 MemoryRegionSection fbsection; 43 qemu_irq irq; 44 int irqlevel; 45 46 int invalidated; 47 QemuConsole *con; 48 int dest_width; 49 int xres, yres; 50 int pal_for; 51 int transp; 52 enum { 53 pxa_lcdc_2bpp = 1, 54 pxa_lcdc_4bpp = 2, 55 pxa_lcdc_8bpp = 3, 56 pxa_lcdc_16bpp = 4, 57 pxa_lcdc_18bpp = 5, 58 pxa_lcdc_18pbpp = 6, 59 pxa_lcdc_19bpp = 7, 60 pxa_lcdc_19pbpp = 8, 61 pxa_lcdc_24bpp = 9, 62 pxa_lcdc_25bpp = 10, 63 } bpp; 64 65 uint32_t control[6]; 66 uint32_t status[2]; 67 uint32_t ovl1c[2]; 68 uint32_t ovl2c[2]; 69 uint32_t ccr; 70 uint32_t cmdcr; 71 uint32_t trgbr; 72 uint32_t tcr; 73 uint32_t liidr; 74 uint8_t bscntr; 75 76 struct DMAChannel dma_ch[7]; 77 78 qemu_irq vsync_cb; 79 int orientation; 80}; 81 82typedef struct QEMU_PACKED { 83 uint32_t fdaddr; 84 uint32_t fsaddr; 85 uint32_t fidr; 86 uint32_t ldcmd; 87} PXAFrameDescriptor; 88 89#define LCCR0 0x000 /* LCD Controller Control register 0 */ 90#define LCCR1 0x004 /* LCD Controller Control register 1 */ 91#define LCCR2 0x008 /* LCD Controller Control register 2 */ 92#define LCCR3 0x00c /* LCD Controller Control register 3 */ 93#define LCCR4 0x010 /* LCD Controller Control register 4 */ 94#define LCCR5 0x014 /* LCD Controller Control register 5 */ 95 96#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */ 97#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */ 98#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */ 99#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */ 100#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */ 101#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */ 102#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */ 103 104#define LCSR1 0x034 /* LCD Controller Status register 1 */ 105#define LCSR0 0x038 /* LCD Controller Status register 0 */ 106#define LIIDR 0x03c /* LCD Controller Interrupt ID register */ 107 108#define TRGBR 0x040 /* TMED RGB Seed register */ 109#define TCR 0x044 /* TMED Control register */ 110 111#define OVL1C1 0x050 /* Overlay 1 Control register 1 */ 112#define OVL1C2 0x060 /* Overlay 1 Control register 2 */ 113#define OVL2C1 0x070 /* Overlay 2 Control register 1 */ 114#define OVL2C2 0x080 /* Overlay 2 Control register 2 */ 115#define CCR 0x090 /* Cursor Control register */ 116 117#define CMDCR 0x100 /* Command Control register */ 118#define PRSR 0x104 /* Panel Read Status register */ 119 120#define PXA_LCDDMA_CHANS 7 121#define DMA_FDADR 0x00 /* Frame Descriptor Address register */ 122#define DMA_FSADR 0x04 /* Frame Source Address register */ 123#define DMA_FIDR 0x08 /* Frame ID register */ 124#define DMA_LDCMD 0x0c /* Command register */ 125 126/* LCD Buffer Strength Control register */ 127#define BSCNTR 0x04000054 128 129/* Bitfield masks */ 130#define LCCR0_ENB (1 << 0) 131#define LCCR0_CMS (1 << 1) 132#define LCCR0_SDS (1 << 2) 133#define LCCR0_LDM (1 << 3) 134#define LCCR0_SOFM0 (1 << 4) 135#define LCCR0_IUM (1 << 5) 136#define LCCR0_EOFM0 (1 << 6) 137#define LCCR0_PAS (1 << 7) 138#define LCCR0_DPD (1 << 9) 139#define LCCR0_DIS (1 << 10) 140#define LCCR0_QDM (1 << 11) 141#define LCCR0_PDD (0xff << 12) 142#define LCCR0_BSM0 (1 << 20) 143#define LCCR0_OUM (1 << 21) 144#define LCCR0_LCDT (1 << 22) 145#define LCCR0_RDSTM (1 << 23) 146#define LCCR0_CMDIM (1 << 24) 147#define LCCR0_OUC (1 << 25) 148#define LCCR0_LDDALT (1 << 26) 149#define LCCR1_PPL(x) ((x) & 0x3ff) 150#define LCCR2_LPP(x) ((x) & 0x3ff) 151#define LCCR3_API (15 << 16) 152#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8)) 153#define LCCR3_PDFOR(x) (((x) >> 30) & 3) 154#define LCCR4_K1(x) (((x) >> 0) & 7) 155#define LCCR4_K2(x) (((x) >> 3) & 7) 156#define LCCR4_K3(x) (((x) >> 6) & 7) 157#define LCCR4_PALFOR(x) (((x) >> 15) & 3) 158#define LCCR5_SOFM(ch) (1 << (ch - 1)) 159#define LCCR5_EOFM(ch) (1 << (ch + 7)) 160#define LCCR5_BSM(ch) (1 << (ch + 15)) 161#define LCCR5_IUM(ch) (1 << (ch + 23)) 162#define OVLC1_EN (1 << 31) 163#define CCR_CEN (1 << 31) 164#define FBR_BRA (1 << 0) 165#define FBR_BINT (1 << 1) 166#define FBR_SRCADDR (0xfffffff << 4) 167#define LCSR0_LDD (1 << 0) 168#define LCSR0_SOF0 (1 << 1) 169#define LCSR0_BER (1 << 2) 170#define LCSR0_ABC (1 << 3) 171#define LCSR0_IU0 (1 << 4) 172#define LCSR0_IU1 (1 << 5) 173#define LCSR0_OU (1 << 6) 174#define LCSR0_QD (1 << 7) 175#define LCSR0_EOF0 (1 << 8) 176#define LCSR0_BS0 (1 << 9) 177#define LCSR0_SINT (1 << 10) 178#define LCSR0_RDST (1 << 11) 179#define LCSR0_CMDINT (1 << 12) 180#define LCSR0_BERCH(x) (((x) & 7) << 28) 181#define LCSR1_SOF(ch) (1 << (ch - 1)) 182#define LCSR1_EOF(ch) (1 << (ch + 7)) 183#define LCSR1_BS(ch) (1 << (ch + 15)) 184#define LCSR1_IU(ch) (1 << (ch + 23)) 185#define LDCMD_LENGTH(x) ((x) & 0x001ffffc) 186#define LDCMD_EOFINT (1 << 21) 187#define LDCMD_SOFINT (1 << 22) 188#define LDCMD_PAL (1 << 26) 189 190/* Size of a pixel in the QEMU UI output surface, in bytes */ 191#define DEST_PIXEL_WIDTH 4 192 193/* Line drawing code to handle the various possible guest pixel formats */ 194 195# define SKIP_PIXEL(to) do { to += deststep; } while (0) 196# define COPY_PIXEL(to, from) \ 197 do { \ 198 *(uint32_t *) to = from; \ 199 SKIP_PIXEL(to); \ 200 } while (0) 201 202#ifdef HOST_WORDS_BIGENDIAN 203# define SWAP_WORDS 1 204#endif 205 206#define FN_2(x) FN(x + 1) FN(x) 207#define FN_4(x) FN_2(x + 2) FN_2(x) 208 209static void pxa2xx_draw_line2(void *opaque, uint8_t *dest, const uint8_t *src, 210 int width, int deststep) 211{ 212 uint32_t *palette = opaque; 213 uint32_t data; 214 while (width > 0) { 215 data = *(uint32_t *) src; 216#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]); 217#ifdef SWAP_WORDS 218 FN_4(12) 219 FN_4(8) 220 FN_4(4) 221 FN_4(0) 222#else 223 FN_4(0) 224 FN_4(4) 225 FN_4(8) 226 FN_4(12) 227#endif 228#undef FN 229 width -= 16; 230 src += 4; 231 } 232} 233 234static void pxa2xx_draw_line4(void *opaque, uint8_t *dest, const uint8_t *src, 235 int width, int deststep) 236{ 237 uint32_t *palette = opaque; 238 uint32_t data; 239 while (width > 0) { 240 data = *(uint32_t *) src; 241#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]); 242#ifdef SWAP_WORDS 243 FN_2(6) 244 FN_2(4) 245 FN_2(2) 246 FN_2(0) 247#else 248 FN_2(0) 249 FN_2(2) 250 FN_2(4) 251 FN_2(6) 252#endif 253#undef FN 254 width -= 8; 255 src += 4; 256 } 257} 258 259static void pxa2xx_draw_line8(void *opaque, uint8_t *dest, const uint8_t *src, 260 int width, int deststep) 261{ 262 uint32_t *palette = opaque; 263 uint32_t data; 264 while (width > 0) { 265 data = *(uint32_t *) src; 266#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]); 267#ifdef SWAP_WORDS 268 FN(24) 269 FN(16) 270 FN(8) 271 FN(0) 272#else 273 FN(0) 274 FN(8) 275 FN(16) 276 FN(24) 277#endif 278#undef FN 279 width -= 4; 280 src += 4; 281 } 282} 283 284static void pxa2xx_draw_line16(void *opaque, uint8_t *dest, const uint8_t *src, 285 int width, int deststep) 286{ 287 uint32_t data; 288 unsigned int r, g, b; 289 while (width > 0) { 290 data = *(uint32_t *) src; 291#ifdef SWAP_WORDS 292 data = bswap32(data); 293#endif 294 b = (data & 0x1f) << 3; 295 data >>= 5; 296 g = (data & 0x3f) << 2; 297 data >>= 6; 298 r = (data & 0x1f) << 3; 299 data >>= 5; 300 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 301 b = (data & 0x1f) << 3; 302 data >>= 5; 303 g = (data & 0x3f) << 2; 304 data >>= 6; 305 r = (data & 0x1f) << 3; 306 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 307 width -= 2; 308 src += 4; 309 } 310} 311 312static void pxa2xx_draw_line16t(void *opaque, uint8_t *dest, const uint8_t *src, 313 int width, int deststep) 314{ 315 uint32_t data; 316 unsigned int r, g, b; 317 while (width > 0) { 318 data = *(uint32_t *) src; 319#ifdef SWAP_WORDS 320 data = bswap32(data); 321#endif 322 b = (data & 0x1f) << 3; 323 data >>= 5; 324 g = (data & 0x1f) << 3; 325 data >>= 5; 326 r = (data & 0x1f) << 3; 327 data >>= 5; 328 if (data & 1) { 329 SKIP_PIXEL(dest); 330 } else { 331 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 332 } 333 data >>= 1; 334 b = (data & 0x1f) << 3; 335 data >>= 5; 336 g = (data & 0x1f) << 3; 337 data >>= 5; 338 r = (data & 0x1f) << 3; 339 data >>= 5; 340 if (data & 1) { 341 SKIP_PIXEL(dest); 342 } else { 343 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 344 } 345 width -= 2; 346 src += 4; 347 } 348} 349 350static void pxa2xx_draw_line18(void *opaque, uint8_t *dest, const uint8_t *src, 351 int width, int deststep) 352{ 353 uint32_t data; 354 unsigned int r, g, b; 355 while (width > 0) { 356 data = *(uint32_t *) src; 357#ifdef SWAP_WORDS 358 data = bswap32(data); 359#endif 360 b = (data & 0x3f) << 2; 361 data >>= 6; 362 g = (data & 0x3f) << 2; 363 data >>= 6; 364 r = (data & 0x3f) << 2; 365 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 366 width -= 1; 367 src += 4; 368 } 369} 370 371/* The wicked packed format */ 372static void pxa2xx_draw_line18p(void *opaque, uint8_t *dest, const uint8_t *src, 373 int width, int deststep) 374{ 375 uint32_t data[3]; 376 unsigned int r, g, b; 377 while (width > 0) { 378 data[0] = *(uint32_t *) src; 379 src += 4; 380 data[1] = *(uint32_t *) src; 381 src += 4; 382 data[2] = *(uint32_t *) src; 383 src += 4; 384#ifdef SWAP_WORDS 385 data[0] = bswap32(data[0]); 386 data[1] = bswap32(data[1]); 387 data[2] = bswap32(data[2]); 388#endif 389 b = (data[0] & 0x3f) << 2; 390 data[0] >>= 6; 391 g = (data[0] & 0x3f) << 2; 392 data[0] >>= 6; 393 r = (data[0] & 0x3f) << 2; 394 data[0] >>= 12; 395 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 396 b = (data[0] & 0x3f) << 2; 397 data[0] >>= 6; 398 g = ((data[1] & 0xf) << 4) | (data[0] << 2); 399 data[1] >>= 4; 400 r = (data[1] & 0x3f) << 2; 401 data[1] >>= 12; 402 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 403 b = (data[1] & 0x3f) << 2; 404 data[1] >>= 6; 405 g = (data[1] & 0x3f) << 2; 406 data[1] >>= 6; 407 r = ((data[2] & 0x3) << 6) | (data[1] << 2); 408 data[2] >>= 8; 409 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 410 b = (data[2] & 0x3f) << 2; 411 data[2] >>= 6; 412 g = (data[2] & 0x3f) << 2; 413 data[2] >>= 6; 414 r = data[2] << 2; 415 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 416 width -= 4; 417 } 418} 419 420static void pxa2xx_draw_line19(void *opaque, uint8_t *dest, const uint8_t *src, 421 int width, int deststep) 422{ 423 uint32_t data; 424 unsigned int r, g, b; 425 while (width > 0) { 426 data = *(uint32_t *) src; 427#ifdef SWAP_WORDS 428 data = bswap32(data); 429#endif 430 b = (data & 0x3f) << 2; 431 data >>= 6; 432 g = (data & 0x3f) << 2; 433 data >>= 6; 434 r = (data & 0x3f) << 2; 435 data >>= 6; 436 if (data & 1) { 437 SKIP_PIXEL(dest); 438 } else { 439 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 440 } 441 width -= 1; 442 src += 4; 443 } 444} 445 446/* The wicked packed format */ 447static void pxa2xx_draw_line19p(void *opaque, uint8_t *dest, const uint8_t *src, 448 int width, int deststep) 449{ 450 uint32_t data[3]; 451 unsigned int r, g, b; 452 while (width > 0) { 453 data[0] = *(uint32_t *) src; 454 src += 4; 455 data[1] = *(uint32_t *) src; 456 src += 4; 457 data[2] = *(uint32_t *) src; 458 src += 4; 459# ifdef SWAP_WORDS 460 data[0] = bswap32(data[0]); 461 data[1] = bswap32(data[1]); 462 data[2] = bswap32(data[2]); 463# endif 464 b = (data[0] & 0x3f) << 2; 465 data[0] >>= 6; 466 g = (data[0] & 0x3f) << 2; 467 data[0] >>= 6; 468 r = (data[0] & 0x3f) << 2; 469 data[0] >>= 6; 470 if (data[0] & 1) { 471 SKIP_PIXEL(dest); 472 } else { 473 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 474 } 475 data[0] >>= 6; 476 b = (data[0] & 0x3f) << 2; 477 data[0] >>= 6; 478 g = ((data[1] & 0xf) << 4) | (data[0] << 2); 479 data[1] >>= 4; 480 r = (data[1] & 0x3f) << 2; 481 data[1] >>= 6; 482 if (data[1] & 1) { 483 SKIP_PIXEL(dest); 484 } else { 485 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 486 } 487 data[1] >>= 6; 488 b = (data[1] & 0x3f) << 2; 489 data[1] >>= 6; 490 g = (data[1] & 0x3f) << 2; 491 data[1] >>= 6; 492 r = ((data[2] & 0x3) << 6) | (data[1] << 2); 493 data[2] >>= 2; 494 if (data[2] & 1) { 495 SKIP_PIXEL(dest); 496 } else { 497 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 498 } 499 data[2] >>= 6; 500 b = (data[2] & 0x3f) << 2; 501 data[2] >>= 6; 502 g = (data[2] & 0x3f) << 2; 503 data[2] >>= 6; 504 r = data[2] << 2; 505 data[2] >>= 6; 506 if (data[2] & 1) { 507 SKIP_PIXEL(dest); 508 } else { 509 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 510 } 511 width -= 4; 512 } 513} 514 515static void pxa2xx_draw_line24(void *opaque, uint8_t *dest, const uint8_t *src, 516 int width, int deststep) 517{ 518 uint32_t data; 519 unsigned int r, g, b; 520 while (width > 0) { 521 data = *(uint32_t *) src; 522#ifdef SWAP_WORDS 523 data = bswap32(data); 524#endif 525 b = data & 0xff; 526 data >>= 8; 527 g = data & 0xff; 528 data >>= 8; 529 r = data & 0xff; 530 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 531 width -= 1; 532 src += 4; 533 } 534} 535 536static void pxa2xx_draw_line24t(void *opaque, uint8_t *dest, const uint8_t *src, 537 int width, int deststep) 538{ 539 uint32_t data; 540 unsigned int r, g, b; 541 while (width > 0) { 542 data = *(uint32_t *) src; 543#ifdef SWAP_WORDS 544 data = bswap32(data); 545#endif 546 b = (data & 0x7f) << 1; 547 data >>= 7; 548 g = data & 0xff; 549 data >>= 8; 550 r = data & 0xff; 551 data >>= 8; 552 if (data & 1) { 553 SKIP_PIXEL(dest); 554 } else { 555 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 556 } 557 width -= 1; 558 src += 4; 559 } 560} 561 562static void pxa2xx_draw_line25(void *opaque, uint8_t *dest, const uint8_t *src, 563 int width, int deststep) 564{ 565 uint32_t data; 566 unsigned int r, g, b; 567 while (width > 0) { 568 data = *(uint32_t *) src; 569#ifdef SWAP_WORDS 570 data = bswap32(data); 571#endif 572 b = data & 0xff; 573 data >>= 8; 574 g = data & 0xff; 575 data >>= 8; 576 r = data & 0xff; 577 data >>= 8; 578 if (data & 1) { 579 SKIP_PIXEL(dest); 580 } else { 581 COPY_PIXEL(dest, rgb_to_pixel32(r, g, b)); 582 } 583 width -= 1; 584 src += 4; 585 } 586} 587 588/* Overlay planes disabled, no transparency */ 589static drawfn pxa2xx_draw_fn_32[16] = { 590 [0 ... 0xf] = NULL, 591 [pxa_lcdc_2bpp] = pxa2xx_draw_line2, 592 [pxa_lcdc_4bpp] = pxa2xx_draw_line4, 593 [pxa_lcdc_8bpp] = pxa2xx_draw_line8, 594 [pxa_lcdc_16bpp] = pxa2xx_draw_line16, 595 [pxa_lcdc_18bpp] = pxa2xx_draw_line18, 596 [pxa_lcdc_18pbpp] = pxa2xx_draw_line18p, 597 [pxa_lcdc_24bpp] = pxa2xx_draw_line24, 598}; 599 600/* Overlay planes enabled, transparency used */ 601static drawfn pxa2xx_draw_fn_32t[16] = { 602 [0 ... 0xf] = NULL, 603 [pxa_lcdc_4bpp] = pxa2xx_draw_line4, 604 [pxa_lcdc_8bpp] = pxa2xx_draw_line8, 605 [pxa_lcdc_16bpp] = pxa2xx_draw_line16t, 606 [pxa_lcdc_19bpp] = pxa2xx_draw_line19, 607 [pxa_lcdc_19pbpp] = pxa2xx_draw_line19p, 608 [pxa_lcdc_24bpp] = pxa2xx_draw_line24t, 609 [pxa_lcdc_25bpp] = pxa2xx_draw_line25, 610}; 611 612#undef COPY_PIXEL 613#undef SKIP_PIXEL 614 615#ifdef SWAP_WORDS 616# undef SWAP_WORDS 617#endif 618 619/* Route internal interrupt lines to the global IC */ 620static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s) 621{ 622 int level = 0; 623 level |= (s->status[0] & LCSR0_LDD) && !(s->control[0] & LCCR0_LDM); 624 level |= (s->status[0] & LCSR0_SOF0) && !(s->control[0] & LCCR0_SOFM0); 625 level |= (s->status[0] & LCSR0_IU0) && !(s->control[0] & LCCR0_IUM); 626 level |= (s->status[0] & LCSR0_IU1) && !(s->control[5] & LCCR5_IUM(1)); 627 level |= (s->status[0] & LCSR0_OU) && !(s->control[0] & LCCR0_OUM); 628 level |= (s->status[0] & LCSR0_QD) && !(s->control[0] & LCCR0_QDM); 629 level |= (s->status[0] & LCSR0_EOF0) && !(s->control[0] & LCCR0_EOFM0); 630 level |= (s->status[0] & LCSR0_BS0) && !(s->control[0] & LCCR0_BSM0); 631 level |= (s->status[0] & LCSR0_RDST) && !(s->control[0] & LCCR0_RDSTM); 632 level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM); 633 level |= (s->status[1] & ~s->control[5]); 634 635 qemu_set_irq(s->irq, !!level); 636 s->irqlevel = level; 637} 638 639/* Set Branch Status interrupt high and poke associated registers */ 640static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch) 641{ 642 int unmasked; 643 if (ch == 0) { 644 s->status[0] |= LCSR0_BS0; 645 unmasked = !(s->control[0] & LCCR0_BSM0); 646 } else { 647 s->status[1] |= LCSR1_BS(ch); 648 unmasked = !(s->control[5] & LCCR5_BSM(ch)); 649 } 650 651 if (unmasked) { 652 if (s->irqlevel) 653 s->status[0] |= LCSR0_SINT; 654 else 655 s->liidr = s->dma_ch[ch].id; 656 } 657} 658 659/* Set Start Of Frame Status interrupt high and poke associated registers */ 660static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch) 661{ 662 int unmasked; 663 if (!(s->dma_ch[ch].command & LDCMD_SOFINT)) 664 return; 665 666 if (ch == 0) { 667 s->status[0] |= LCSR0_SOF0; 668 unmasked = !(s->control[0] & LCCR0_SOFM0); 669 } else { 670 s->status[1] |= LCSR1_SOF(ch); 671 unmasked = !(s->control[5] & LCCR5_SOFM(ch)); 672 } 673 674 if (unmasked) { 675 if (s->irqlevel) 676 s->status[0] |= LCSR0_SINT; 677 else 678 s->liidr = s->dma_ch[ch].id; 679 } 680} 681 682/* Set End Of Frame Status interrupt high and poke associated registers */ 683static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch) 684{ 685 int unmasked; 686 if (!(s->dma_ch[ch].command & LDCMD_EOFINT)) 687 return; 688 689 if (ch == 0) { 690 s->status[0] |= LCSR0_EOF0; 691 unmasked = !(s->control[0] & LCCR0_EOFM0); 692 } else { 693 s->status[1] |= LCSR1_EOF(ch); 694 unmasked = !(s->control[5] & LCCR5_EOFM(ch)); 695 } 696 697 if (unmasked) { 698 if (s->irqlevel) 699 s->status[0] |= LCSR0_SINT; 700 else 701 s->liidr = s->dma_ch[ch].id; 702 } 703} 704 705/* Set Bus Error Status interrupt high and poke associated registers */ 706static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch) 707{ 708 s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER; 709 if (s->irqlevel) 710 s->status[0] |= LCSR0_SINT; 711 else 712 s->liidr = s->dma_ch[ch].id; 713} 714 715/* Load new Frame Descriptors from DMA */ 716static void pxa2xx_descriptor_load(PXA2xxLCDState *s) 717{ 718 PXAFrameDescriptor desc; 719 hwaddr descptr; 720 int i; 721 722 for (i = 0; i < PXA_LCDDMA_CHANS; i ++) { 723 s->dma_ch[i].source = 0; 724 725 if (!s->dma_ch[i].up) 726 continue; 727 728 if (s->dma_ch[i].branch & FBR_BRA) { 729 descptr = s->dma_ch[i].branch & FBR_SRCADDR; 730 if (s->dma_ch[i].branch & FBR_BINT) 731 pxa2xx_dma_bs_set(s, i); 732 s->dma_ch[i].branch &= ~FBR_BRA; 733 } else 734 descptr = s->dma_ch[i].descriptor; 735 736 if (!((descptr >= PXA2XX_SDRAM_BASE && descptr + 737 sizeof(desc) <= PXA2XX_SDRAM_BASE + current_machine->ram_size) || 738 (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <= 739 PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) { 740 continue; 741 } 742 743 cpu_physical_memory_read(descptr, &desc, sizeof(desc)); 744 s->dma_ch[i].descriptor = le32_to_cpu(desc.fdaddr); 745 s->dma_ch[i].source = le32_to_cpu(desc.fsaddr); 746 s->dma_ch[i].id = le32_to_cpu(desc.fidr); 747 s->dma_ch[i].command = le32_to_cpu(desc.ldcmd); 748 } 749} 750 751static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset, 752 unsigned size) 753{ 754 PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; 755 int ch; 756 757 switch (offset) { 758 case LCCR0: 759 return s->control[0]; 760 case LCCR1: 761 return s->control[1]; 762 case LCCR2: 763 return s->control[2]; 764 case LCCR3: 765 return s->control[3]; 766 case LCCR4: 767 return s->control[4]; 768 case LCCR5: 769 return s->control[5]; 770 771 case OVL1C1: 772 return s->ovl1c[0]; 773 case OVL1C2: 774 return s->ovl1c[1]; 775 case OVL2C1: 776 return s->ovl2c[0]; 777 case OVL2C2: 778 return s->ovl2c[1]; 779 780 case CCR: 781 return s->ccr; 782 783 case CMDCR: 784 return s->cmdcr; 785 786 case TRGBR: 787 return s->trgbr; 788 case TCR: 789 return s->tcr; 790 791 case 0x200 ... 0x1000: /* DMA per-channel registers */ 792 ch = (offset - 0x200) >> 4; 793 if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) 794 goto fail; 795 796 switch (offset & 0xf) { 797 case DMA_FDADR: 798 return s->dma_ch[ch].descriptor; 799 case DMA_FSADR: 800 return s->dma_ch[ch].source; 801 case DMA_FIDR: 802 return s->dma_ch[ch].id; 803 case DMA_LDCMD: 804 return s->dma_ch[ch].command; 805 default: 806 goto fail; 807 } 808 809 case FBR0: 810 return s->dma_ch[0].branch; 811 case FBR1: 812 return s->dma_ch[1].branch; 813 case FBR2: 814 return s->dma_ch[2].branch; 815 case FBR3: 816 return s->dma_ch[3].branch; 817 case FBR4: 818 return s->dma_ch[4].branch; 819 case FBR5: 820 return s->dma_ch[5].branch; 821 case FBR6: 822 return s->dma_ch[6].branch; 823 824 case BSCNTR: 825 return s->bscntr; 826 827 case PRSR: 828 return 0; 829 830 case LCSR0: 831 return s->status[0]; 832 case LCSR1: 833 return s->status[1]; 834 case LIIDR: 835 return s->liidr; 836 837 default: 838 fail: 839 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", 840 __func__, offset); 841 } 842 843 return 0; 844} 845 846static void pxa2xx_lcdc_write(void *opaque, hwaddr offset, 847 uint64_t value, unsigned size) 848{ 849 PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; 850 int ch; 851 852 switch (offset) { 853 case LCCR0: 854 /* ACK Quick Disable done */ 855 if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB)) 856 s->status[0] |= LCSR0_QD; 857 858 if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) { 859 qemu_log_mask(LOG_UNIMP, 860 "%s: internal frame buffer unsupported\n", __func__); 861 } 862 if ((s->control[3] & LCCR3_API) && 863 (value & LCCR0_ENB) && !(value & LCCR0_LCDT)) 864 s->status[0] |= LCSR0_ABC; 865 866 s->control[0] = value & 0x07ffffff; 867 pxa2xx_lcdc_int_update(s); 868 869 s->dma_ch[0].up = !!(value & LCCR0_ENB); 870 s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS); 871 break; 872 873 case LCCR1: 874 s->control[1] = value; 875 break; 876 877 case LCCR2: 878 s->control[2] = value; 879 break; 880 881 case LCCR3: 882 s->control[3] = value & 0xefffffff; 883 s->bpp = LCCR3_BPP(value); 884 break; 885 886 case LCCR4: 887 s->control[4] = value & 0x83ff81ff; 888 break; 889 890 case LCCR5: 891 s->control[5] = value & 0x3f3f3f3f; 892 break; 893 894 case OVL1C1: 895 if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) { 896 qemu_log_mask(LOG_UNIMP, "%s: Overlay 1 not supported\n", __func__); 897 } 898 s->ovl1c[0] = value & 0x80ffffff; 899 s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS); 900 break; 901 902 case OVL1C2: 903 s->ovl1c[1] = value & 0x000fffff; 904 break; 905 906 case OVL2C1: 907 if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) { 908 qemu_log_mask(LOG_UNIMP, "%s: Overlay 2 not supported\n", __func__); 909 } 910 s->ovl2c[0] = value & 0x80ffffff; 911 s->dma_ch[2].up = !!(value & OVLC1_EN); 912 s->dma_ch[3].up = !!(value & OVLC1_EN); 913 s->dma_ch[4].up = !!(value & OVLC1_EN); 914 break; 915 916 case OVL2C2: 917 s->ovl2c[1] = value & 0x007fffff; 918 break; 919 920 case CCR: 921 if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) { 922 qemu_log_mask(LOG_UNIMP, 923 "%s: Hardware cursor unimplemented\n", __func__); 924 } 925 s->ccr = value & 0x81ffffe7; 926 s->dma_ch[5].up = !!(value & CCR_CEN); 927 break; 928 929 case CMDCR: 930 s->cmdcr = value & 0xff; 931 break; 932 933 case TRGBR: 934 s->trgbr = value & 0x00ffffff; 935 break; 936 937 case TCR: 938 s->tcr = value & 0x7fff; 939 break; 940 941 case 0x200 ... 0x1000: /* DMA per-channel registers */ 942 ch = (offset - 0x200) >> 4; 943 if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) 944 goto fail; 945 946 switch (offset & 0xf) { 947 case DMA_FDADR: 948 s->dma_ch[ch].descriptor = value & 0xfffffff0; 949 break; 950 951 default: 952 goto fail; 953 } 954 break; 955 956 case FBR0: 957 s->dma_ch[0].branch = value & 0xfffffff3; 958 break; 959 case FBR1: 960 s->dma_ch[1].branch = value & 0xfffffff3; 961 break; 962 case FBR2: 963 s->dma_ch[2].branch = value & 0xfffffff3; 964 break; 965 case FBR3: 966 s->dma_ch[3].branch = value & 0xfffffff3; 967 break; 968 case FBR4: 969 s->dma_ch[4].branch = value & 0xfffffff3; 970 break; 971 case FBR5: 972 s->dma_ch[5].branch = value & 0xfffffff3; 973 break; 974 case FBR6: 975 s->dma_ch[6].branch = value & 0xfffffff3; 976 break; 977 978 case BSCNTR: 979 s->bscntr = value & 0xf; 980 break; 981 982 case PRSR: 983 break; 984 985 case LCSR0: 986 s->status[0] &= ~(value & 0xfff); 987 if (value & LCSR0_BER) 988 s->status[0] &= ~LCSR0_BERCH(7); 989 break; 990 991 case LCSR1: 992 s->status[1] &= ~(value & 0x3e3f3f); 993 break; 994 995 default: 996 fail: 997 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n", 998 __func__, offset); 999 } 1000} 1001 1002static const MemoryRegionOps pxa2xx_lcdc_ops = { 1003 .read = pxa2xx_lcdc_read, 1004 .write = pxa2xx_lcdc_write, 1005 .endianness = DEVICE_NATIVE_ENDIAN, 1006}; 1007 1008/* Load new palette for a given DMA channel, convert to internal format */ 1009static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) 1010{ 1011 DisplaySurface *surface = qemu_console_surface(s->con); 1012 int i, n, format, r, g, b, alpha; 1013 uint32_t *dest; 1014 uint8_t *src; 1015 s->pal_for = LCCR4_PALFOR(s->control[4]); 1016 format = s->pal_for; 1017 1018 switch (bpp) { 1019 case pxa_lcdc_2bpp: 1020 n = 4; 1021 break; 1022 case pxa_lcdc_4bpp: 1023 n = 16; 1024 break; 1025 case pxa_lcdc_8bpp: 1026 n = 256; 1027 break; 1028 default: 1029 return; 1030 } 1031 1032 src = (uint8_t *) s->dma_ch[ch].pbuffer; 1033 dest = (uint32_t *) s->dma_ch[ch].palette; 1034 alpha = r = g = b = 0; 1035 1036 for (i = 0; i < n; i ++) { 1037 switch (format) { 1038 case 0: /* 16 bpp, no transparency */ 1039 alpha = 0; 1040 if (s->control[0] & LCCR0_CMS) { 1041 r = g = b = *(uint16_t *) src & 0xff; 1042 } 1043 else { 1044 r = (*(uint16_t *) src & 0xf800) >> 8; 1045 g = (*(uint16_t *) src & 0x07e0) >> 3; 1046 b = (*(uint16_t *) src & 0x001f) << 3; 1047 } 1048 src += 2; 1049 break; 1050 case 1: /* 16 bpp plus transparency */ 1051 alpha = *(uint32_t *) src & (1 << 24); 1052 if (s->control[0] & LCCR0_CMS) 1053 r = g = b = *(uint32_t *) src & 0xff; 1054 else { 1055 r = (*(uint32_t *) src & 0xf80000) >> 16; 1056 g = (*(uint32_t *) src & 0x00fc00) >> 8; 1057 b = (*(uint32_t *) src & 0x0000f8); 1058 } 1059 src += 4; 1060 break; 1061 case 2: /* 18 bpp plus transparency */ 1062 alpha = *(uint32_t *) src & (1 << 24); 1063 if (s->control[0] & LCCR0_CMS) 1064 r = g = b = *(uint32_t *) src & 0xff; 1065 else { 1066 r = (*(uint32_t *) src & 0xfc0000) >> 16; 1067 g = (*(uint32_t *) src & 0x00fc00) >> 8; 1068 b = (*(uint32_t *) src & 0x0000fc); 1069 } 1070 src += 4; 1071 break; 1072 case 3: /* 24 bpp plus transparency */ 1073 alpha = *(uint32_t *) src & (1 << 24); 1074 if (s->control[0] & LCCR0_CMS) 1075 r = g = b = *(uint32_t *) src & 0xff; 1076 else { 1077 r = (*(uint32_t *) src & 0xff0000) >> 16; 1078 g = (*(uint32_t *) src & 0x00ff00) >> 8; 1079 b = (*(uint32_t *) src & 0x0000ff); 1080 } 1081 src += 4; 1082 break; 1083 } 1084 switch (surface_bits_per_pixel(surface)) { 1085 case 8: 1086 *dest = rgb_to_pixel8(r, g, b) | alpha; 1087 break; 1088 case 15: 1089 *dest = rgb_to_pixel15(r, g, b) | alpha; 1090 break; 1091 case 16: 1092 *dest = rgb_to_pixel16(r, g, b) | alpha; 1093 break; 1094 case 24: 1095 *dest = rgb_to_pixel24(r, g, b) | alpha; 1096 break; 1097 case 32: 1098 *dest = rgb_to_pixel32(r, g, b) | alpha; 1099 break; 1100 } 1101 dest ++; 1102 } 1103} 1104 1105static inline drawfn pxa2xx_drawfn(PXA2xxLCDState *s) 1106{ 1107 if (s->transp) { 1108 return pxa2xx_draw_fn_32t[s->bpp]; 1109 } else { 1110 return pxa2xx_draw_fn_32[s->bpp]; 1111 } 1112} 1113 1114static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, 1115 hwaddr addr, int *miny, int *maxy) 1116{ 1117 DisplaySurface *surface = qemu_console_surface(s->con); 1118 int src_width, dest_width; 1119 drawfn fn = pxa2xx_drawfn(s); 1120 if (!fn) 1121 return; 1122 1123 src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ 1124 if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) 1125 src_width *= 3; 1126 else if (s->bpp > pxa_lcdc_16bpp) 1127 src_width *= 4; 1128 else if (s->bpp > pxa_lcdc_8bpp) 1129 src_width *= 2; 1130 1131 dest_width = s->xres * DEST_PIXEL_WIDTH; 1132 *miny = 0; 1133 if (s->invalidated) { 1134 framebuffer_update_memory_section(&s->fbsection, s->sysmem, 1135 addr, s->yres, src_width); 1136 } 1137 framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres, 1138 src_width, dest_width, DEST_PIXEL_WIDTH, 1139 s->invalidated, 1140 fn, s->dma_ch[0].palette, miny, maxy); 1141} 1142 1143static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, 1144 hwaddr addr, int *miny, int *maxy) 1145{ 1146 DisplaySurface *surface = qemu_console_surface(s->con); 1147 int src_width, dest_width; 1148 drawfn fn = pxa2xx_drawfn(s); 1149 if (!fn) 1150 return; 1151 1152 src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ 1153 if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) 1154 src_width *= 3; 1155 else if (s->bpp > pxa_lcdc_16bpp) 1156 src_width *= 4; 1157 else if (s->bpp > pxa_lcdc_8bpp) 1158 src_width *= 2; 1159 1160 dest_width = s->yres * DEST_PIXEL_WIDTH; 1161 *miny = 0; 1162 if (s->invalidated) { 1163 framebuffer_update_memory_section(&s->fbsection, s->sysmem, 1164 addr, s->yres, src_width); 1165 } 1166 framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres, 1167 src_width, DEST_PIXEL_WIDTH, -dest_width, 1168 s->invalidated, 1169 fn, s->dma_ch[0].palette, 1170 miny, maxy); 1171} 1172 1173static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, 1174 hwaddr addr, int *miny, int *maxy) 1175{ 1176 DisplaySurface *surface = qemu_console_surface(s->con); 1177 int src_width, dest_width; 1178 drawfn fn = pxa2xx_drawfn(s); 1179 if (!fn) { 1180 return; 1181 } 1182 1183 src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ 1184 if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) { 1185 src_width *= 3; 1186 } else if (s->bpp > pxa_lcdc_16bpp) { 1187 src_width *= 4; 1188 } else if (s->bpp > pxa_lcdc_8bpp) { 1189 src_width *= 2; 1190 } 1191 1192 dest_width = s->xres * DEST_PIXEL_WIDTH; 1193 *miny = 0; 1194 if (s->invalidated) { 1195 framebuffer_update_memory_section(&s->fbsection, s->sysmem, 1196 addr, s->yres, src_width); 1197 } 1198 framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres, 1199 src_width, -dest_width, -DEST_PIXEL_WIDTH, 1200 s->invalidated, 1201 fn, s->dma_ch[0].palette, miny, maxy); 1202} 1203 1204static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s, 1205 hwaddr addr, int *miny, int *maxy) 1206{ 1207 DisplaySurface *surface = qemu_console_surface(s->con); 1208 int src_width, dest_width; 1209 drawfn fn = pxa2xx_drawfn(s); 1210 if (!fn) { 1211 return; 1212 } 1213 1214 src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ 1215 if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) { 1216 src_width *= 3; 1217 } else if (s->bpp > pxa_lcdc_16bpp) { 1218 src_width *= 4; 1219 } else if (s->bpp > pxa_lcdc_8bpp) { 1220 src_width *= 2; 1221 } 1222 1223 dest_width = s->yres * DEST_PIXEL_WIDTH; 1224 *miny = 0; 1225 if (s->invalidated) { 1226 framebuffer_update_memory_section(&s->fbsection, s->sysmem, 1227 addr, s->yres, src_width); 1228 } 1229 framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres, 1230 src_width, -DEST_PIXEL_WIDTH, dest_width, 1231 s->invalidated, 1232 fn, s->dma_ch[0].palette, 1233 miny, maxy); 1234} 1235 1236static void pxa2xx_lcdc_resize(PXA2xxLCDState *s) 1237{ 1238 int width, height; 1239 if (!(s->control[0] & LCCR0_ENB)) 1240 return; 1241 1242 width = LCCR1_PPL(s->control[1]) + 1; 1243 height = LCCR2_LPP(s->control[2]) + 1; 1244 1245 if (width != s->xres || height != s->yres) { 1246 if (s->orientation == 90 || s->orientation == 270) { 1247 qemu_console_resize(s->con, height, width); 1248 } else { 1249 qemu_console_resize(s->con, width, height); 1250 } 1251 s->invalidated = 1; 1252 s->xres = width; 1253 s->yres = height; 1254 } 1255} 1256 1257static void pxa2xx_update_display(void *opaque) 1258{ 1259 PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; 1260 hwaddr fbptr; 1261 int miny, maxy; 1262 int ch; 1263 if (!(s->control[0] & LCCR0_ENB)) 1264 return; 1265 1266 pxa2xx_descriptor_load(s); 1267 1268 pxa2xx_lcdc_resize(s); 1269 miny = s->yres; 1270 maxy = 0; 1271 s->transp = s->dma_ch[2].up || s->dma_ch[3].up; 1272 /* Note: With overlay planes the order depends on LCCR0 bit 25. */ 1273 for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++) 1274 if (s->dma_ch[ch].up) { 1275 if (!s->dma_ch[ch].source) { 1276 pxa2xx_dma_ber_set(s, ch); 1277 continue; 1278 } 1279 fbptr = s->dma_ch[ch].source; 1280 if (!((fbptr >= PXA2XX_SDRAM_BASE && 1281 fbptr <= PXA2XX_SDRAM_BASE + current_machine->ram_size) || 1282 (fbptr >= PXA2XX_INTERNAL_BASE && 1283 fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) { 1284 pxa2xx_dma_ber_set(s, ch); 1285 continue; 1286 } 1287 1288 if (s->dma_ch[ch].command & LDCMD_PAL) { 1289 cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer, 1290 MAX(LDCMD_LENGTH(s->dma_ch[ch].command), 1291 sizeof(s->dma_ch[ch].pbuffer))); 1292 pxa2xx_palette_parse(s, ch, s->bpp); 1293 } else { 1294 /* Do we need to reparse palette */ 1295 if (LCCR4_PALFOR(s->control[4]) != s->pal_for) 1296 pxa2xx_palette_parse(s, ch, s->bpp); 1297 1298 /* ACK frame start */ 1299 pxa2xx_dma_sof_set(s, ch); 1300 1301 s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy); 1302 s->invalidated = 0; 1303 1304 /* ACK frame completed */ 1305 pxa2xx_dma_eof_set(s, ch); 1306 } 1307 } 1308 1309 if (s->control[0] & LCCR0_DIS) { 1310 /* ACK last frame completed */ 1311 s->control[0] &= ~LCCR0_ENB; 1312 s->status[0] |= LCSR0_LDD; 1313 } 1314 1315 if (miny >= 0) { 1316 switch (s->orientation) { 1317 case 0: 1318 dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1); 1319 break; 1320 case 90: 1321 dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres); 1322 break; 1323 case 180: 1324 maxy = s->yres - maxy - 1; 1325 miny = s->yres - miny - 1; 1326 dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1); 1327 break; 1328 case 270: 1329 maxy = s->yres - maxy - 1; 1330 miny = s->yres - miny - 1; 1331 dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres); 1332 break; 1333 } 1334 } 1335 pxa2xx_lcdc_int_update(s); 1336 1337 qemu_irq_raise(s->vsync_cb); 1338} 1339 1340static void pxa2xx_invalidate_display(void *opaque) 1341{ 1342 PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; 1343 s->invalidated = 1; 1344} 1345 1346static void pxa2xx_lcdc_orientation(void *opaque, int angle) 1347{ 1348 PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; 1349 1350 switch (angle) { 1351 case 0: 1352 s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0; 1353 break; 1354 case 90: 1355 s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90; 1356 break; 1357 case 180: 1358 s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180; 1359 break; 1360 case 270: 1361 s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270; 1362 break; 1363 } 1364 1365 s->orientation = angle; 1366 s->xres = s->yres = -1; 1367 pxa2xx_lcdc_resize(s); 1368} 1369 1370static const VMStateDescription vmstate_dma_channel = { 1371 .name = "dma_channel", 1372 .version_id = 0, 1373 .minimum_version_id = 0, 1374 .fields = (VMStateField[]) { 1375 VMSTATE_UINT32(branch, struct DMAChannel), 1376 VMSTATE_UINT8(up, struct DMAChannel), 1377 VMSTATE_BUFFER(pbuffer, struct DMAChannel), 1378 VMSTATE_UINT32(descriptor, struct DMAChannel), 1379 VMSTATE_UINT32(source, struct DMAChannel), 1380 VMSTATE_UINT32(id, struct DMAChannel), 1381 VMSTATE_UINT32(command, struct DMAChannel), 1382 VMSTATE_END_OF_LIST() 1383 } 1384}; 1385 1386static int pxa2xx_lcdc_post_load(void *opaque, int version_id) 1387{ 1388 PXA2xxLCDState *s = opaque; 1389 1390 s->bpp = LCCR3_BPP(s->control[3]); 1391 s->xres = s->yres = s->pal_for = -1; 1392 1393 return 0; 1394} 1395 1396static const VMStateDescription vmstate_pxa2xx_lcdc = { 1397 .name = "pxa2xx_lcdc", 1398 .version_id = 0, 1399 .minimum_version_id = 0, 1400 .post_load = pxa2xx_lcdc_post_load, 1401 .fields = (VMStateField[]) { 1402 VMSTATE_INT32(irqlevel, PXA2xxLCDState), 1403 VMSTATE_INT32(transp, PXA2xxLCDState), 1404 VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6), 1405 VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2), 1406 VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2), 1407 VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2), 1408 VMSTATE_UINT32(ccr, PXA2xxLCDState), 1409 VMSTATE_UINT32(cmdcr, PXA2xxLCDState), 1410 VMSTATE_UINT32(trgbr, PXA2xxLCDState), 1411 VMSTATE_UINT32(tcr, PXA2xxLCDState), 1412 VMSTATE_UINT32(liidr, PXA2xxLCDState), 1413 VMSTATE_UINT8(bscntr, PXA2xxLCDState), 1414 VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0, 1415 vmstate_dma_channel, struct DMAChannel), 1416 VMSTATE_END_OF_LIST() 1417 } 1418}; 1419 1420static const GraphicHwOps pxa2xx_ops = { 1421 .invalidate = pxa2xx_invalidate_display, 1422 .gfx_update = pxa2xx_update_display, 1423}; 1424 1425PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, 1426 hwaddr base, qemu_irq irq) 1427{ 1428 PXA2xxLCDState *s; 1429 1430 s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState)); 1431 s->invalidated = 1; 1432 s->irq = irq; 1433 s->sysmem = sysmem; 1434 1435 pxa2xx_lcdc_orientation(s, graphic_rotate); 1436 1437 memory_region_init_io(&s->iomem, NULL, &pxa2xx_lcdc_ops, s, 1438 "pxa2xx-lcd-controller", 0x00100000); 1439 memory_region_add_subregion(sysmem, base, &s->iomem); 1440 1441 s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s); 1442 1443 vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s); 1444 1445 return s; 1446} 1447 1448void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler) 1449{ 1450 s->vsync_cb = handler; 1451}