From cafdedfa0501a30289fde5668501f8ccea600eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= Date: Wed, 4 Jul 2012 11:18:45 +0000 Subject: dsi: add transfer done callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juha Riihimäki --- hw/dsi.c | 15 +++++++++++++++ hw/dsi.h | 3 +++ hw/omap_dss.c | 35 ++++++++++++++++++++++++++++++----- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/hw/dsi.c b/hw/dsi.c index fba94dbe9d..6e631d9480 100644 --- a/hw/dsi.c +++ b/hw/dsi.c @@ -130,6 +130,21 @@ int dsi_blt(DSIHost *host, int vc, void *data, int width, int height, return 0; } +void dsi_bltdone(DSIHost *host, int vc) +{ + if (vc >=0 && vc < 4) { + DSIDevice *dev = host->device[vc]; + if (dev) { + DSIDeviceClass *dc = DSI_DEVICE_GET_CLASS(dev); + dc->bltdone(dev); + } else { + DSI_ERROR_NODEVICE(vc); + } + } else { + hw_error("%s: invalid virtual channel id (%d)\n", __FUNCTION__, vc); + } +} + void dsi_te_trigger(const DSIDevice *dev) { if (dev && dev->host && dev->host->te_trigger) { diff --git a/hw/dsi.h b/hw/dsi.h index 21ee6cc300..fa11976384 100644 --- a/hw/dsi.h +++ b/hw/dsi.h @@ -54,6 +54,7 @@ typedef void (*dsi_write_cb)(DSIDevice *dev, uint32_t data, int len); typedef uint32_t (*dsi_read_cb)(DSIDevice *dev, uint32_t data, int len); typedef int (*dsi_blt_cb)(DSIDevice *dev, void *data, int width, int height, int col_pitch, int row_pitch, int format); +typedef void (*dsi_bltdone_cb)(DSIDevice *dev); /* common device callbacks */ typedef void (*dsi_common_write_cb)(DSICommonDevice *dev, uint32_t data, @@ -75,6 +76,7 @@ typedef struct { dsi_write_cb write; dsi_read_cb read; dsi_blt_cb blt; + dsi_bltdone_cb bltdone; } DSIDeviceClass; typedef struct { @@ -126,6 +128,7 @@ void dsi_long_write(DSIHost *host, uint32_t header, uint32_t payload, uint32_t counter); int dsi_blt(DSIHost *host, int vc, void *data, int width, int height, int col_pitch, int row_pitch, int format); +void dsi_bltdone(DSIHost *host, int vc); /* device -> host functions */ void dsi_te_trigger(const DSIDevice *dev); diff --git a/hw/omap_dss.c b/hw/omap_dss.c index 0128a98eb8..4836621036 100644 --- a/hw/omap_dss.c +++ b/hw/omap_dss.c @@ -184,6 +184,7 @@ struct omap_dss_s { struct { DSIHost *host; + QEMUTimer *xfer_timer; qemu_irq drq[4]; /* protocol engine registers */ uint32_t sysconfig; @@ -399,12 +400,28 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s) omap_dss_framedone(s); } +static void omap_dsi_transfer_stop(void *opaque) +{ + struct omap_dss_s *s = opaque; + int i; + qemu_del_timer(s->dsi.xfer_timer); + for (i = 0; i < 4; i++) { + if ((s->dsi.vc[i].ctrl & 1) && /* VC_EN */ + ((s->dsi.vc[i].te >> 30) & 3)) { /* TE_START | TE_EN */ + TRACEDSI("TE data transfer ready, signaling framedone"); + s->dsi.vc[i].te = 0; /* transfer complete */ + omap_dss_framedone(s); + dsi_bltdone(s->dsi.host, i); + } + } +} + static void omap_dsi_transfer_start(struct omap_dss_s *s, int ch) { if (((s->dispc.control >> 11) & 1) && /* STALLMODE */ (s->dsi.ctrl & 1) && /* IF_EN */ (s->dsi.vc[ch].ctrl & 1) && /* VC_EN */ - (s->dsi.vc[ch].te >> 30) & 3) { /* TE_START | TE_EN */ + ((s->dsi.vc[ch].te >> 30) & 3)) { /* TE_START | TE_EN */ TRACEDSI("start TE data transfer on channel %d for %d bytes", ch, s->dsi.vc[ch].te & 0xffffff); TRACEDSI("vc%d irqenable=0x%08x", ch, s->dsi.vc[ch].irqen); @@ -416,9 +433,9 @@ static void omap_dsi_transfer_start(struct omap_dss_s *s, int ch) } else { const int format = (s->dispc.plane[0].attr >> 1) & 0xf; const int col_pitch = omap_lcd_Bpp[format] + - (s->dispc.plane[0].colinc - 1); + (s->dispc.plane[0].colinc - 1); const int row_pitch = (s->dispc.plane[0].nx * col_pitch) + - (s->dispc.plane[0].rowinc - 1); + (s->dispc.plane[0].rowinc - 1); target_phys_addr_t len = row_pitch * s->dispc.plane[0].ny; void *data = cpu_physical_memory_map(s->dispc.plane[0].addr[0], &len, 0); @@ -432,8 +449,14 @@ static void omap_dsi_transfer_start(struct omap_dss_s *s, int ch) if (data) { cpu_physical_memory_unmap(data, len, 0, 0); } - s->dsi.vc[ch].te = 0; /* transfer complete */ - omap_dss_framedone(s); + /* We cannot signal transfer complete immediately since some + * display drivers assume transfer takes some time. Instead, + * setup a small delay and report transfer complete a bit + * later. */ + s->dsi.vc[ch].ctrl &= ~(0x11 << 16); /* TX/RX fifo not full */ + qemu_mod_timer(s->dsi.xfer_timer, + qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec() / 1000); } } } @@ -2484,6 +2507,8 @@ static int omap_dss_init(SysBusDevice *dev) s->dsi.host = dsi_init_host(&dev->qdev, "omap3_dsi", omap_dsi_te_trigger, omap_dss_linefn); + s->dsi.xfer_timer = qemu_new_timer_ns(vm_clock, omap_dsi_transfer_stop, + s); memory_region_init_io(&s->iomem_dsi, &omap_dsi_ops, s, "omap.dsi", 0x400); sysbus_init_mmio(dev, &s->iomem_dsi); -- cgit v1.2.3