aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuha Riihimäki <juha.riihimaki@nokia.com>2012-07-04 11:18:45 +0000
committerPeter Maydell <peter.maydell@linaro.org>2012-07-25 13:33:43 +0100
commitcafdedfa0501a30289fde5668501f8ccea600eb7 (patch)
treeaaa25bf00ebb62cbaf7c20abaf447f79ff4c2ecb
parent72c12884bc8d65468ad59d1371ac63782a299746 (diff)
downloadqemu-arm-cafdedfa0501a30289fde5668501f8ccea600eb7.tar.gz
dsi: add transfer done callback
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
-rw-r--r--hw/dsi.c15
-rw-r--r--hw/dsi.h3
-rw-r--r--hw/omap_dss.c35
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);