Commit 34f64942d902de45b380afb99de5faf704121029

Authored by Evgeniy Dushistov
1 parent 5eb9fc83

initial at91 lcdc implementation

Makefile.target
... ... @@ -411,7 +411,7 @@ obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
411 411 endif
412 412  
413 413 obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o
414   -obj-arm-y += pflash_atmel.o at91sam9.o spi_flash.o
  414 +obj-arm-y += pflash_atmel.o at91sam9.o spi_flash.o at91_lcdc.o
415 415 obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
416 416 obj-arm-y += versatile_pci.o
417 417 obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o
... ...
hw/at91_lcdc.c 0 → 100644
  1 +/*
  2 + * AT91 SAM9 LCD Controller (LCDC)
  3 + * Written by Evgeniy Dushistov
  4 + * This code is licenced under the GPL.
  5 + */
  6 +#include "sysbus.h"
  7 +#include "console.h"
  8 +#include "pixel_ops.h"
  9 +
  10 +#define LCDC_SIZE 0x100000
  11 +
  12 +#define LCDC_DMABADDR1 0x0
  13 +#define LCDC_DMAFRMCFG 0x18
  14 +#define LCDC_DMACON 0x1C
  15 +#define LCDC_LCDCON1 0x800
  16 +#define LCDC_LCDCON2 0x804
  17 +#define LCDC_LCDFRMCFG 0x810
  18 +#define LCDC_PWRCON 0x83C
  19 +
  20 +#define DMACON_DMAEN 1
  21 +
  22 +typedef struct LCDCState {
  23 + SysBusDevice busdev;
  24 + qemu_irq irq;
  25 + DisplayState *ds;
  26 + uint32_t dmacon;
  27 + uint32_t pwrcon;
  28 + uint32_t dmafrmcfg;
  29 + uint32_t lcdcon1;
  30 + uint32_t lcdcon2;
  31 + uint32_t lcdfrmcfg;
  32 + uint32_t dmabaddr1;
  33 +} LCDCState;
  34 +
  35 +#define AT91_LCDC_DEBUG
  36 +#ifdef AT91_LCDC_DEBUG
  37 +#define DPRINTF(fmt, ...) \
  38 + do { \
  39 + printf("AT91LCD: " fmt , ## __VA_ARGS__); \
  40 + } while (0)
  41 +#else
  42 +#define DPRINTF(fmt, ...) do { } while (0)
  43 +#endif
  44 +
  45 +
  46 +static uint32_t at91_lcdc_mem_read(void *opaque, target_phys_addr_t offset)
  47 +{
  48 + LCDCState *s = opaque;
  49 +
  50 + offset &= LCDC_SIZE - 1;
  51 + DPRINTF("read from %X\n", offset);
  52 + switch (offset) {
  53 + case LCDC_PWRCON:
  54 + return s->pwrcon;
  55 + case LCDC_DMACON:
  56 + return s->dmacon;
  57 + case LCDC_DMAFRMCFG:
  58 + return s->dmafrmcfg;
  59 + case LCDC_LCDCON1:
  60 + return s->lcdcon1;
  61 + case LCDC_LCDCON2:
  62 + return s->lcdcon2;
  63 + case LCDC_LCDFRMCFG:
  64 + return s->lcdfrmcfg;
  65 + default:
  66 + DPRINTF("unsup. read\n");
  67 + return 0;
  68 + }
  69 +}
  70 +
  71 +static void at91_lcdc_mem_write(void *opaque, target_phys_addr_t offset,
  72 + uint32_t value)
  73 +{
  74 + LCDCState *s = opaque;
  75 + offset &= LCDC_SIZE - 1;
  76 + DPRINTF("write to %X: %X\n", offset, value);
  77 +
  78 + switch (offset) {
  79 + case LCDC_DMABADDR1:
  80 + s->dmabaddr1 = value;
  81 + break;
  82 + case LCDC_PWRCON:
  83 + s->pwrcon = value;
  84 + break;
  85 + case LCDC_DMACON:
  86 + s->dmacon = value;
  87 + break;
  88 + case LCDC_DMAFRMCFG:
  89 + s->dmafrmcfg = value;
  90 + break;
  91 + case LCDC_LCDCON1:
  92 + s->lcdcon1 = value;
  93 + break;
  94 + case LCDC_LCDCON2:
  95 + DPRINTF("pixel size %u\n", (value >> 5) & 7);
  96 + s->lcdcon2 = value;
  97 + break;
  98 + case LCDC_LCDFRMCFG:
  99 + DPRINTF("lineval %u, linsize %u\n", value & 0x7FF, (value >> 21) & 0x7FF);
  100 + qemu_console_resize(s->ds, ((value >> 21) & 0x7FF) + 1, (value & 0x7FF) + 1);
  101 + s->lcdfrmcfg = value;
  102 + break;
  103 + default:
  104 + DPRINTF("unsup. write\n");
  105 + }
  106 +}
  107 +
  108 +static CPUReadMemoryFunc *at91_lcdc_readfn[] = {
  109 + at91_lcdc_mem_read,
  110 + at91_lcdc_mem_read,
  111 + at91_lcdc_mem_read,
  112 +};
  113 +
  114 +static CPUWriteMemoryFunc *at91_lcdc_writefn[] = {
  115 + at91_lcdc_mem_write,
  116 + at91_lcdc_mem_write,
  117 + at91_lcdc_mem_write,
  118 +};
  119 +
  120 +static void at91_lcdc_reset(void *opaque)
  121 +{
  122 + LCDCState *s = opaque;
  123 + s->pwrcon = 0x0000000e;
  124 + s->dmacon = 0;
  125 + s->dmafrmcfg = 0;
  126 + s->lcdcon1 = 0x00002000;
  127 + s->lcdfrmcfg = 0;
  128 +}
  129 +
  130 +struct pixel8 {
  131 + unsigned b : 2;
  132 + unsigned g : 3;
  133 + unsigned r : 3;
  134 +};
  135 +
  136 +union pixel8u {
  137 + struct pixel8 p;
  138 + uint8_t val;
  139 +};
  140 +
  141 +static void at91_lcdc_update_display(void *opaque)
  142 +{
  143 + LCDCState *s = opaque;
  144 + uint32_t color;
  145 + int x, y;
  146 + uint8_t *d;
  147 + int width = ((s->lcdfrmcfg >> 21) & 0x7FF) + 1;
  148 + int height = (s->lcdfrmcfg & 0x7FF) + 1;
  149 + int q_bpp = (ds_get_bits_per_pixel(s->ds) + 7) >> 3;
  150 + int bpp;
  151 + int bpp_idx = (s->lcdcon2 >> 5) & 7;
  152 + union pixel8u tmp;
  153 +
  154 + DPRINTF("update begin\n");
  155 + if (!(s->dmacon & DMACON_DMAEN))
  156 + return;
  157 + DPRINTF("update continue\n");
  158 + switch (bpp_idx) {
  159 + case 0 ... 4:
  160 + bpp = 1 << bpp_idx;
  161 + break;
  162 + case 5 ... 6:
  163 + bpp = 24;
  164 + break;
  165 + default:
  166 + fprintf(stderr, "Unknown pixel size\n");
  167 + return;//reserved value, unknown pixel size
  168 + }
  169 + /*TODO: fix this restriction*/
  170 + if (bpp != 8) {
  171 + fprintf(stderr, "Unsupported pixel size\n");
  172 + return;
  173 + }
  174 + int once = 0;
  175 + for (y = 0; y < height; ++y) {
  176 + for (x = 0; x < width; ++x) {
  177 + cpu_physical_memory_read(s->dmabaddr1 + width * y + x, &tmp.val, 1);
  178 + if (tmp.val != 0 && once == 0) {
  179 + once = 1;
  180 + DPRINTF("not null %X, %X, %X, bpp %d\n", (unsigned)tmp.p.r << 5, (unsigned)tmp.p.g << 5, (unsigned)tmp.p.b << 6, ds_get_bits_per_pixel(s->ds));
  181 + }
  182 + switch (ds_get_bits_per_pixel(s->ds)) {
  183 + case 8:
  184 + color = rgb_to_pixel8(tmp.p.r, tmp.p.g, tmp.p.b);
  185 + break;
  186 + case 15:
  187 + color = rgb_to_pixel15(tmp.p.r, tmp.p.g, tmp.p.b);
  188 + break;
  189 + case 16:
  190 + color = rgb_to_pixel16(tmp.p.r, tmp.p.g, tmp.p.b);
  191 + break;
  192 + case 24:
  193 + color = rgb_to_pixel24(tmp.p.r, tmp.p.g, tmp.p.b);
  194 + break;
  195 + case 32:
  196 + color = rgb_to_pixel32((unsigned)tmp.p.r << 5, (unsigned)tmp.p.g << 5, (unsigned)tmp.p.b << 6);
  197 + break;
  198 + default:
  199 + return;
  200 + }
  201 +
  202 + d = ds_get_data(s->ds) + ds_get_linesize(s->ds) * y + q_bpp * x;
  203 + *d = color;
  204 + }
  205 + }
  206 +
  207 + dpy_update(s->ds, 0, 0, width, height);
  208 +}
  209 +
  210 +static void at91_lcdc_init(SysBusDevice *dev)
  211 +{
  212 + LCDCState *s = FROM_SYSBUS(typeof(*s), dev);
  213 + int lcdc_regs;
  214 +
  215 + sysbus_init_irq(dev, &s->irq);
  216 + lcdc_regs = cpu_register_io_memory(at91_lcdc_readfn,
  217 + at91_lcdc_writefn, s);
  218 + sysbus_init_mmio(dev, LCDC_SIZE, lcdc_regs);
  219 + qemu_register_reset(at91_lcdc_reset, s);
  220 + s->ds = graphic_console_init(at91_lcdc_update_display, NULL, NULL, NULL, s);
  221 +}
  222 +
  223 +static void at91_lcdc_register(void)
  224 +{
  225 + sysbus_register_dev("at91,lcdc", sizeof(LCDCState), at91_lcdc_init);
  226 +}
  227 +
  228 +device_init(at91_lcdc_register)
... ...
hw/at91sam9.c
... ... @@ -336,7 +336,7 @@ static void at91sam9_init(ram_addr_t ram_size,
336 336 sysbus_mmio_map(sysbus_from_qdev(dev), 0, AT91_EMAC_BASE);
337 337 sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[21]);
338 338  
339   -
  339 + sysbus_create_simple("at91,lcdc", AT91_LCDC_BASE, pic[26]);
340 340 /*
341 341 we use variant of booting from external memory (NOR FLASH),
342 342 it mapped to 0x0 at start, and also it is accessable from 0x10000000 address
... ...
hw/at91sam9263_defs.h
... ... @@ -2,6 +2,7 @@
2 2 #define _HW_AT91SAM9263_DEFS_H_
3 3  
4 4 /* base periph addresses */
  5 +#define AT91_LCDC_BASE 0x00700000
5 6 #define AT91_PERIPH_BASE 0xF0000000
6 7 #define AT91_TC012_BASE 0xFFF7C000
7 8 #define AT91_USART0_BASE 0xFFF8C000
... ...