aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/arm/Makefile.objs2
-rw-r--r--hw/dsi.c417
-rw-r--r--hw/dsi.h145
-rw-r--r--hw/omap.h17
-rw-r--r--hw/omap2.c22
-rw-r--r--hw/omap_dss.c2231
6 files changed, 2441 insertions, 393 deletions
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 01b6046ff0..612e533f8c 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -26,7 +26,7 @@ obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
omap_gpio.o omap_intc.o omap_uart.o
obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
-obj-y += omap_usb.o omap3_boot.o omap3_mmc.o
+obj-y += omap_usb.o omap3_boot.o omap3_mmc.o dsi.o
obj-y += omap_sx1.o palm.o tsc210x.o
obj-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o
obj-y += mst_fpga.o mainstone.o
diff --git a/hw/dsi.c b/hw/dsi.c
new file mode 100644
index 0000000000..fba94dbe9d
--- /dev/null
+++ b/hw/dsi.c
@@ -0,0 +1,417 @@
+/*
+ * MIPI DSI interface.
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dsi.h"
+
+#define DSI_ERROR_NODEVICE(channel) \
+ fprintf(stderr, "%s: no device attached on virtual channel %d\n", \
+ __FUNCTION__, channel)
+#define DSI_EXTRACTPARAM(var, data, nb) \
+ { \
+ int i; \
+ for (i = nb; i--; data >>= 8) \
+ var = (var << 8) | (data & 0xff); \
+ }
+
+struct DSIHost {
+ BusState qbus;
+ DSIDevice *device[4];
+ dsi_te_trigger_cb te_trigger;
+ dsi_get_drawfn_cb get_drawfn;
+};
+
+static Property dsi_props[] = {
+ DEFINE_PROP_UINT8("virtual_channel", DSIDevice, vchannel, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+#define TYPE_DSI_BUS "dsi-bus"
+#define DSI_BUS(obj) OBJECT_CHECK(DSIHost, (obj), TYPE_DSI_BUS)
+
+static const TypeInfo dsi_bus_info = {
+ .name = TYPE_DSI_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(DSIHost),
+};
+
+DSIHost *dsi_init_host(DeviceState *parent, const char *name,
+ dsi_te_trigger_cb te_trigger_cb,
+ dsi_get_drawfn_cb get_drawfn_cb)
+{
+ DSIHost *host = FROM_QBUS(DSIHost, qbus_create(TYPE_DSI_BUS, parent, name));
+ host->te_trigger = te_trigger_cb;
+ host->get_drawfn = get_drawfn_cb;
+ return host;
+}
+
+uint32_t dsi_short_write(DSIHost *host, uint32_t data)
+{
+ DSIDevice *dev = host->device[(data >> 6) & 3];
+ if (dev) {
+ DSIDeviceClass *dc = DSI_DEVICE_GET_CLASS(dev);
+ uint16_t payload = data >> 8;
+ switch (data & 0x3f) { /* id */
+ case 0x05: /* short_write_0 */
+ dc->write(dev, payload & 0xff, 1);
+ break;
+ case 0x06: /* read */
+ return dc->read(dev, payload & 0xff, 1);
+ case 0x15: /* short_write_1 */
+ dc->write(dev, payload, 2);
+ break;
+ case 0x37: /* set maximum return packet size */
+ dev->max_return_size = data;
+ break;
+ default:
+ hw_error("%s: unknown/unimplemented DSI id (0x%02x)",
+ __FUNCTION__, data & 0x3f);
+ break;
+ }
+ } else {
+ DSI_ERROR_NODEVICE((data >> 6) & 3);
+ }
+ return 0;
+}
+
+void dsi_long_write(DSIHost *host, uint32_t header, uint32_t payload,
+ uint32_t counter)
+{
+ DSIDevice *dev = host->device[(header >> 6) & 3];
+ if (dev) {
+ DSIDeviceClass *dc = DSI_DEVICE_GET_CLASS(dev);
+ switch (header & 0x3f) { /* id */
+ case 0x09: /* null packet */
+ /* ignore */
+ break;
+ case 0x39: /* long write */
+ dc->write(dev, payload, counter > 4 ? 4 : counter);
+ break;
+ default:
+ hw_error("%s: unknown/unimplemented DSI id (0x%02x)",
+ __FUNCTION__, header & 0x3f);
+ break;
+ }
+ } else {
+ DSI_ERROR_NODEVICE((header >> 6) & 3);
+ }
+}
+
+int dsi_blt(DSIHost *host, int vc, void *data, int width, int height,
+ int col_pitch, int row_pitch, int format)
+{
+ if (vc >= 0 && vc < 4) {
+ DSIDevice *dev = host->device[vc];
+ if (dev) {
+ DSIDeviceClass *dc = DSI_DEVICE_GET_CLASS(dev);
+ return dc->blt(dev, data, width, height,
+ col_pitch, row_pitch, format);
+ } else {
+ DSI_ERROR_NODEVICE(vc);
+ }
+ } else {
+ hw_error("%s: invalid virtual channel id (%d)\n", __FUNCTION__, vc);
+ }
+ return 0;
+}
+
+void dsi_te_trigger(const DSIDevice *dev)
+{
+ if (dev && dev->host && dev->host->te_trigger) {
+ dev->host->te_trigger(dev->host->qbus.parent, dev->vchannel);
+ }
+}
+
+drawfn dsi_get_drawfn(const DSIDevice *dev, int format, int bpp)
+{
+ if (dev && dev->host && dev->host->get_drawfn) {
+ return dev->host->get_drawfn(dev->host->qbus.parent, format, bpp);
+ }
+ return NULL;
+}
+
+static void dsi_common_reset(DeviceState *dev)
+{
+ DSICommonDevice *s = DSI_COMMON_DEVICE_FROM_QDEV(dev);
+ DSICommonDeviceClass *dcc = DSI_COMMON_DEVICE_GET_CLASS(dev);
+ s->bs = bs_cmd;
+ s->cmd = 0;
+ s->powermode = 0x08;
+ s->addrmode = 0;
+ s->bpp_dbi = 0;
+ s->bpp_dpi = 0;
+ s->dr = 0;
+ s->sc = 0;
+ s->ec = 0;
+ s->cc = 0;
+ s->sp = 0;
+ s->ep = 0;
+ s->cp = 0;
+ s->te_mode = te_off;
+ if (dcc->reset) {
+ dcc->reset(s);
+ }
+}
+
+static void dsi_common_write(DSIDevice *dev, uint32_t data, int len)
+{
+ uint8_t x;
+ DSICommonDevice *s = FROM_DSI_DEVICE(DSICommonDevice, dev);
+ DSICommonDeviceClass *dcc = DSI_COMMON_DEVICE_GET_CLASS(s);
+ if (s->bs == bs_cmd) {
+ s->cmd = data & 0xff;
+ data >>= 8;
+ len--;
+ }
+ switch (s->cmd) {
+ case 0x10: /* enter sleep */
+ x = s->powermode;
+ s->powermode &= ~0x10;
+ if ((x ^ s->powermode) && dcc->powermode_changed) {
+ dcc->powermode_changed(s);
+ }
+ break;
+ case 0x11: /* exit sleep */
+ x = s->powermode;
+ s->powermode |= 0x10;
+ s->dr ^= 0xe0;
+ if ((x ^ s->powermode) && dcc->powermode_changed) {
+ dcc->powermode_changed(s);
+ }
+ break;
+ case 0x28: /* display off */
+ x = s->powermode;
+ s->powermode &= ~0x04;
+ if ((x ^ s->powermode) && dcc->powermode_changed) {
+ dcc->powermode_changed(s);
+ }
+ break;
+ case 0x29: /* display on */
+ x = s->powermode;
+ s->powermode |= 0x04;
+ if ((x ^ s->powermode) && dcc->powermode_changed) {
+ dcc->powermode_changed(s);
+ }
+ break;
+ case 0x2a: /* set column address */
+ if (s->bs == bs_cmd) {
+ s->bs = bs_data;
+ s->sc = 0;
+ s->ec = 0;
+ DSI_EXTRACTPARAM(s->sc, data, 2);
+ DSI_EXTRACTPARAM(s->ec, data, 1);
+ s->cc = s->sc;
+ } else {
+ s->bs = bs_cmd;
+ DSI_EXTRACTPARAM(s->ec, data, 1);
+ s->cc = s->sc;
+ }
+ break;
+ case 0x2b: /* set page address */
+ if (s->bs == bs_cmd) {
+ s->bs = bs_data;
+ s->sp = 0;
+ s->ep = 0;
+ DSI_EXTRACTPARAM(s->sp, data, 2);
+ DSI_EXTRACTPARAM(s->ep, data, 1);
+ s->cp = s->sp;
+ } else {
+ s->bs = bs_cmd;
+ DSI_EXTRACTPARAM(s->ep, data, 1);
+ s->cp = s->sp;
+ }
+ break;
+ case 0x34: /* disable tear effect control */
+ x = s->te_mode;
+ s->te_mode = te_off;
+ if ((x ^ s->te_mode) && dcc->temode_changed) {
+ dcc->temode_changed(s);
+ }
+ break;
+ case 0x35: /* enable tear effect control */
+ x = s->te_mode;
+ s->te_mode = (data & 0x01) ? te_hvsync : te_vsync;
+ if ((x ^ s->te_mode) && dcc->temode_changed) {
+ dcc->temode_changed(s);
+ }
+ break;
+ case 0x36: /* set address mode */
+ s->addrmode = data & 0xff;
+ break;
+ case 0x3a: /* set pixel format */
+ switch ((data >> 4) & 7) {
+ case 0:
+ s->bpp_dpi = 0;
+ break;
+ case 2: /* 8bpp */
+ s->bpp_dpi = 1;
+ break;
+ case 5: /* 16bpp */
+ s->bpp_dpi = 2;
+ break;
+ case 7: /* 24bpp */
+ s->bpp_dpi = 4; /* faster to process than 3 */
+ break;
+ default:
+ hw_error("%s: unsupported dpi pixel format %d",
+ __FUNCTION__, (data >> 4) & 7);
+ break;
+ }
+ switch ((data & 7)) {
+ case 0:
+ s->bpp_dbi = 0;
+ break;
+ case 2: /* 8bpp */
+ s->bpp_dbi = 1;
+ break;
+ case 5: /* 16bpp */
+ s->bpp_dbi = 2;
+ break;
+ case 7: /* 24bpp */
+ s->bpp_dbi = 4; /* faster to process than 3 */
+ break;
+ default:
+ hw_error("%s: unsupported dbi pixel format %d",
+ __FUNCTION__, data & 7);
+ break;
+ }
+ break;
+ default:
+ if (dcc->write) {
+ if (s->bs == bs_cmd) {
+ data = (data << 8) | s->cmd;
+ len++;
+ }
+ dcc->write(s, data, len);
+ } else {
+ hw_error("%s: unknown command 0x%02x\n", __FUNCTION__, s->cmd);
+ }
+ break;
+ }
+}
+
+static uint32_t dsi_common_read(DSIDevice *dev, uint32_t data, int len)
+{
+ DSICommonDevice *s = FROM_DSI_DEVICE(DSICommonDevice, dev);
+ DSICommonDeviceClass *dcc = DSI_COMMON_DEVICE_GET_CLASS(s);
+ if (s->bs != bs_cmd) {
+ hw_error("%s: previous WRITE command not completed", __FUNCTION__);
+ }
+ s->cmd = data & 0xff;
+ switch (s->cmd) {
+ case 0x0a: /* get power mode */
+ return DSI_MAKERETURNBYTE(s->powermode);
+ case 0x0b: /* get address mode */
+ return DSI_MAKERETURNBYTE(s->addrmode);
+ case 0x0f: /* get diagnostic result */
+ return DSI_MAKERETURNBYTE(s->dr);
+ default:
+ if (dcc->read) {
+ return dcc->read(s, data, len);
+ } else {
+ hw_error("%s: unknown command 0x%02x\n", __FUNCTION__, s->cmd);
+ }
+ break;
+ }
+ return 0;
+}
+
+static int dsi_device_init(DeviceState *dev)
+{
+ DSIDevice *dsi_dev = DSI_DEVICE_FROM_QDEV(dev);
+ DSIDeviceClass *dc = DSI_DEVICE_GET_CLASS(dsi_dev);
+ return dc->init(dsi_dev);
+}
+
+DeviceState *dsi_create_device_noinit(DSIHost *host, const char *name, int vc)
+{
+ if (host->device[vc]) {
+ hw_error("%s: virtual channel %d already has a device attached\n",
+ __FUNCTION__, vc);
+ }
+ DeviceState *dev = qdev_create(&host->qbus, name);
+ qdev_prop_set_uint8(dev, "virtual_channel", vc);
+ DSIDevice *dsi_dev = DSI_DEVICE_FROM_QDEV(dev);
+ host->device[vc] = dsi_dev;
+ dsi_dev->host = host;
+ return dev;
+}
+
+DeviceState *dsi_create_device(DSIHost *host, const char *name, int vc)
+{
+ DeviceState *dev = dsi_create_device_noinit(host, name, vc);
+ qdev_init_nofail(dev);
+ return dev;
+}
+
+DeviceState *dsi_create_common_device_noinit(DSIHost *host, const char *name,
+ int vc)
+{
+ return dsi_create_device_noinit(host, name, vc);
+}
+
+DeviceState *dsi_create_common_device(DSIHost *host, const char *name, int vc)
+{
+ DeviceState *dev = dsi_create_common_device_noinit(host, name, vc);
+ qdev_init_nofail(dev);
+ return dev;
+}
+
+static void dsi_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = dsi_device_init;
+ k->bus_type = TYPE_DSI_BUS;
+ k->props = dsi_props;
+}
+
+static void dsi_common_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ DSIDeviceClass *dc = DSI_DEVICE_CLASS(klass);
+ dc->write = dsi_common_write;
+ dc->read = dsi_common_read;
+ k->reset = dsi_common_reset;
+}
+
+static TypeInfo dsi_device_type_info = {
+ .name = TYPE_DSI_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(DSIDevice),
+ .abstract = true,
+ .class_size = sizeof(DSIDeviceClass),
+ .class_init = dsi_device_class_init,
+};
+
+static TypeInfo dsi_common_device_type_info = {
+ .name = TYPE_DSI_COMMON_DEVICE,
+ .parent = TYPE_DSI_DEVICE,
+ .instance_size = sizeof(DSICommonDevice),
+ .abstract = true,
+ .class_size = sizeof(DSICommonDeviceClass),
+ .class_init = dsi_common_device_class_init,
+};
+
+static void dsi_register_types(void)
+{
+ type_register_static(&dsi_bus_info);
+ type_register_static(&dsi_device_type_info);
+ type_register_static(&dsi_common_device_type_info);
+}
+
+type_init(dsi_register_types)
diff --git a/hw/dsi.h b/hw/dsi.h
new file mode 100644
index 0000000000..21ee6cc300
--- /dev/null
+++ b/hw/dsi.h
@@ -0,0 +1,145 @@
+/*
+ * MIPI DSI interface.
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef HW_DSI_H__
+#define HW_DSI_H__
+#include "qdev.h"
+#include "framebuffer.h"
+
+#define DSI_MAKERETURNBYTE(b) ((((b) & 0xff) << 8) | 0x21)
+#define DSI_MAKERETURNWORD(w) ((((w) & 0xffff) << 8) | 0x22)
+#define DSI_MAKERETURNERROR(e) ((((e) & 0xffff) << 8) | 0x02)
+
+typedef struct DSIDevice DSIDevice;
+typedef struct DSICommonDevice DSICommonDevice;
+typedef struct DSIHost DSIHost;
+
+#define TYPE_DSI_DEVICE "dsi-device"
+#define DSI_DEVICE(obj) \
+ OBJECT_CHECK(DSIDevice, (obj), TYPE_DSI_DEVICE)
+#define DSI_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(DSIDeviceClass, (klass), TYPE_DSI_DEVICE)
+#define DSI_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(DSIDeviceClass, (obj), TYPE_DSI_DEVICE)
+
+#define TYPE_DSI_COMMON_DEVICE "dsi-common-device"
+#define DSI_COMMON_DEVICE(obj) \
+ OBJECT_CHECK(DSICommonDevice, (obj), TYPE_DSI_COMMON_DEVICE)
+#define DSI_COMMON_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(DSICommonDeviceClass, (klass), TYPE_DSI_COMMON_DEVICE)
+#define DSI_COMMON_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(DSICommonDeviceClass, (obj), TYPE_DSI_COMMON_DEVICE)
+
+
+
+/* device callbacks */
+typedef int (*dsi_device_initfn)(DSIDevice *dev);
+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);
+
+/* common device callbacks */
+typedef void (*dsi_common_write_cb)(DSICommonDevice *dev, uint32_t data,
+ int len);
+typedef uint32_t (*dsi_common_read_cb)(DSICommonDevice *dev, uint32_t data,
+ int len);
+typedef void (*dsi_common_device_resetfn)(DSICommonDevice *dev);
+typedef void (*dsi_powermode_changed_cb)(DSICommonDevice *dev);
+typedef void (*dsi_temode_changed_cb)(DSICommonDevice *dev);
+
+/* host callbacks */
+typedef void (*dsi_te_trigger_cb)(DeviceState *dev, int vc);
+typedef drawfn (*dsi_get_drawfn_cb)(const DeviceState *dev, int format,
+ int bpp);
+
+typedef struct {
+ DeviceClass parent_class;
+ dsi_device_initfn init;
+ dsi_write_cb write;
+ dsi_read_cb read;
+ dsi_blt_cb blt;
+} DSIDeviceClass;
+
+typedef struct {
+ DSIDeviceClass parent_class;
+ dsi_common_write_cb write;
+ dsi_common_read_cb read;
+ dsi_common_device_resetfn reset;
+ dsi_powermode_changed_cb powermode_changed;
+ dsi_temode_changed_cb temode_changed;
+} DSICommonDeviceClass;
+
+struct DSIDevice {
+ DeviceState qdev;
+
+ /* internal fields used by DSI code */
+ DSIHost *host;
+ uint8_t vchannel;
+ uint16_t max_return_size;
+};
+
+struct DSICommonDevice {
+ DSIDevice dsi;
+ enum { bs_cmd, bs_data } bs;
+ uint8_t cmd;
+ uint8_t powermode;
+ uint8_t addrmode;
+ uint8_t bpp_dpi;
+ uint8_t bpp_dbi;
+ uint8_t dr;
+ uint32_t sc;
+ uint32_t ec;
+ uint32_t cc;
+ uint32_t sp;
+ uint32_t ep;
+ uint32_t cp;
+ enum {
+ te_off = -1,
+ te_vsync = 0,
+ te_hvsync = 1
+ } te_mode;
+};
+
+/* host functions */
+DSIHost *dsi_init_host(DeviceState *parent, const char *name,
+ dsi_te_trigger_cb te_trigger_cb,
+ dsi_get_drawfn_cb get_drawfn_cb);
+uint32_t dsi_short_write(DSIHost *host, uint32_t data);
+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);
+
+/* device -> host functions */
+void dsi_te_trigger(const DSIDevice *dev);
+drawfn dsi_get_drawfn(const DSIDevice *dev, int format, int bpp);
+
+#define DSI_DEVICE_FROM_QDEV(dev) DO_UPCAST(DSIDevice, qdev, dev)
+#define DSI_COMMON_DEVICE_FROM_QDEV(dev) DO_UPCAST(DSICommonDevice, dsi, \
+ DSI_DEVICE_FROM_QDEV(dev))
+#define FROM_DSI_DEVICE(type, dev) DO_UPCAST(type, dsi, dev)
+
+DeviceState *dsi_create_device(DSIHost *host, const char *name, int vc);
+DeviceState *dsi_create_device_noinit(DSIHost *host, const char *name, int vc);
+DeviceState *dsi_create_common_device(DSIHost *host, const char *name, int vc);
+DeviceState *dsi_create_common_device_noinit(DSIHost *host, const char *name,
+ int vc);
+
+#endif
diff --git a/hw/omap.h b/hw/omap.h
index 9ed96258a0..48acdfac13 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -20,6 +20,8 @@
#include "memory.h"
# define hw_omap_h "omap.h"
+#include "sysemu.h"
+#include "dsi.h"
#include "spi.h"
# define OMAP_EMIFS_BASE 0x00000000
@@ -936,15 +938,10 @@ struct rfbi_chip_s {
void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch);
uint16_t (*read)(void *opaque, int dc);
};
-struct omap_dss_s;
-void omap_dss_reset(struct omap_dss_s *s);
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- target_phys_addr_t l3_base,
- qemu_irq irq, qemu_irq drq,
- omap_clk fck1, omap_clk fck2, omap_clk ck54m,
- omap_clk ick1, omap_clk ick2);
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip);
+DSIHost *omap_dsi_host(DeviceState *dev);
+void omap_rfbi_attach(DeviceState *dev, int cs, const struct rfbi_chip_s *chip);
+void omap_lcd_panel_attach(DeviceState *dev);
+void omap_digital_panel_attach(DeviceState *dev);
/* omap_mmc.c */
struct omap_mmc_s;
@@ -1127,7 +1124,7 @@ struct omap_mpu_state_s {
DeviceState *mcspi;
- struct omap_dss_s *dss;
+ DeviceState *dss;
struct omap_eac_s *eac;
MemoryRegion bootrom;
diff --git a/hw/omap2.c b/hw/omap2.c
index 7850f53a7e..f2df3d9fa7 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2215,7 +2215,6 @@ static void omap2_mpu_reset(void *opaque)
omap_synctimer_reset(mpu->synctimer);
omap_sdrc_reset(mpu->sdrc);
omap_gpmc_reset(mpu->gpmc);
- omap_dss_reset(mpu->dss);
omap_mmc_reset(mpu->mmc);
cpu_reset(CPU(mpu->cpu));
}
@@ -2498,14 +2497,19 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4ta(s->l4, 35), 0));
sysbus_mmio_map(busdev, 1, omap_l4_region_base(omap_l4ta(s->l4, 36), 0));
- s->dss = omap_dss_init(omap_l4ta(s->l4, 10), sysmem, 0x68000800,
- /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ),
- s->drq[OMAP24XX_DMA_DSS],
- omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
- omap_findclk(s, "dss_54m_clk"),
- omap_findclk(s, "dss_l3_iclk"),
- omap_findclk(s, "dss_l4_iclk"));
+ s->dss = qdev_create(NULL, "omap_dss");
+ qdev_prop_set_int32(s->dss, "mpu_model", s->mpu_model);
+ qdev_init_nofail(s->dss);
+ busdev = sysbus_from_qdev(s->dss);
+ sysbus_connect_irq(busdev, 0,
+ qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ));
+ sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_DSS]);
+ ta = omap_l4ta(s->l4, 10);
+ sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 0));
+ sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 1));
+ sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2));
+ sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 3));
+ sysbus_mmio_map(busdev, 4, 0x68000800);
omap_sti_init(omap_l4ta(s->l4, 18), sysmem, 0x54000000,
qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI),
diff --git a/hw/omap_dss.c b/hw/omap_dss.c
index 86ed6ea5d9..0128a98eb8 100644
--- a/hw/omap_dss.c
+++ b/hw/omap_dss.c
@@ -1,13 +1,14 @@
/*
- * OMAP2 Display Subsystem.
+ * OMAP2/3 Display Subsystem.
*
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ * Copyright (C) 2008,2009 Nokia Corporation
+ * Original OMAP2 support written by Andrzej Zaborowski <andrew@openedhand.com>
+ * Enhancements and OMAP3 support written by Juha Riihimäki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
+ * (at your option) any later version of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -17,30 +18,134 @@
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "hw.h"
#include "console.h"
#include "omap.h"
+#include "sysbus.h"
+#include "dsi.h"
+
+//#define OMAP_DSS_DEBUG
+#define OMAP_DSS_DEBUG_DISPC
+#define OMAP_DSS_DEBUG_DISS
+#define OMAP_DSS_DEBUG_DSI
+#define OMAP_DSS_DEBUG_RFBI
+//#define OMAP_DSS_DEBUG_VENC
+
+#ifdef OMAP_DSS_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \
+ __LINE__, ##__VA_ARGS__)
+#define LAYERNAME(n) ((!(n)) ? "GFX" : ((n)==1) ? "VID1" : "VID2")
+#ifdef OMAP_DSS_DEBUG_DISPC
+#define TRACEDISPC(fmt,...) TRACE(fmt, ##__VA_ARGS__)
+#else
+#define TRACEDISPC(...)
+#endif
+#ifdef OMAP_DSS_DEBUG_DISS
+#define TRACEDISS(fmt,...) TRACE(fmt, ##__VA_ARGS__)
+#else
+#define TRACEDISS(...)
+#endif
+#ifdef OMAP_DSS_DEBUG_DSI
+#define TRACEDSI(fmt,...) TRACE(fmt, ##__VA_ARGS__)
+#else
+#define TRACEDSI(...)
+#endif
+#ifdef OMAP_DSS_DEBUG_RFBI
+#define TRACERFBI(fmt,...) TRACE(fmt, ##__VA_ARGS__)
+#else
+#define TRACERFBI(...)
+#endif
+#ifdef OMAP_DSS_DEBUG_VENC
+#define TRACEVENC(fmt,...) TRACE(fmt, ##__VA_ARGS__)
+#else
+#define TRACEVENC(...)
+#endif
+#else
+#define TRACE(...)
+#define TRACEDISPC(...)
+#define TRACEDISS(...)
+#define TRACEDSI(...)
+#define TRACERFBI(...)
+#define TRACEVENC(...)
+#undef OMAP_RO_REG
+#undef OMAP_RO_REGV
+#undef OMAP_BAD_REG
+#undef OMAP_BAD_REGV
+#define OMAP_RO_REG(...)
+#define OMAP_RO_REGV(...)
+#define OMAP_BAD_REG(...)
+#define OMAP_BAD_REGV(...)
+#endif
-struct omap_dss_s {
- qemu_irq irq;
- qemu_irq drq;
- DisplayState *state;
- MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
+#define OMAP_DSI_RX_FIFO_SIZE 32
- int autoidle;
- int control;
+struct omap_dss_plane_s {
int enable;
+ int bpp;
+ int posx;
+ int posy;
+ int nx;
+ int ny;
+
+ int rotation_flag;
+ int gfx_format;
+ int gfx_channel;
+
+ target_phys_addr_t addr[3]; /* BA0, BA1, TABLE_BA */
+
+ uint32_t attr;
+ uint32_t tresh;
+ int rowinc;
+ int colinc;
+ int wininc;
+
+ uint32_t preload;
+
+ /* following used for planes 1 and 2 only (VID1 and VID2) */
+ uint32_t fir;
+ uint32_t fir_coef_h[8];
+ uint32_t fir_coef_hv[8];
+ uint32_t fir_coef_v[8];
+ uint32_t conv_coef[5];
+ uint32_t picture_size;
+ uint32_t accu[2];
+};
- struct omap_dss_panel_s {
- int enable;
- int nx;
- int ny;
+struct omap_dss_panel_s {
+ int attached;
+ int invalidate;
+ DisplayState *ds;
+ struct {
+ uint32_t control;
+ uint32_t width;
+ uint32_t height;
+ struct omap_dss_plane_s gfx;
+ struct omap_dss_plane_s vid1;
+ struct omap_dss_plane_s vid2;
+ uint32_t *gfx_palette;
+ uint32_t gfx_palette_size;
+ } shadow;
+};
- int x;
- int y;
- } dig, lcd;
+struct omap_dss_s {
+ SysBusDevice busdev;
+ MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
+ MemoryRegion iomem_dsi;
+ int32_t mpu_model;
+ qemu_irq irq;
+ qemu_irq drq;
+
+ uint32_t autoidle;
+ uint32_t control;
+ uint32_t sdi_control;
+ uint32_t pll_control;
+ uint32_t dss_status;
+
+ struct omap_dss_panel_s dig, lcd;
struct {
+ QEMUTimer *lcdframer;
+
+ uint8_t rev;
uint32_t idlemode;
uint32_t irqst;
uint32_t irqen;
@@ -48,31 +153,19 @@ struct omap_dss_s {
uint32_t config;
uint32_t capable;
uint32_t timing[4];
- int line;
+ uint32_t line;
uint32_t bg[2];
uint32_t trans[2];
-
- struct omap_dss_plane_s {
- int enable;
- int bpp;
- int posx;
- int posy;
- int nx;
- int ny;
-
- target_phys_addr_t addr[3];
-
- uint32_t attr;
- uint32_t tresh;
- int rowinc;
- int colinc;
- int wininc;
- } l[3];
-
- int invalidate;
- uint16_t palette[256];
+ uint32_t size_dig;
+ uint32_t size_lcd;
+ uint32_t global_alpha;
+ uint32_t cpr_coef_r;
+ uint32_t cpr_coef_g;
+ uint32_t cpr_coef_b;
+
+ struct omap_dss_plane_s plane[3]; /* GFX, VID1, VID2 */
} dispc;
-
+
struct {
int idlemode;
uint32_t control;
@@ -86,13 +179,486 @@ struct omap_dss_s {
uint32_t data[6];
uint16_t vsync;
uint16_t hsync;
- struct rfbi_chip_s *chip[2];
+ const struct rfbi_chip_s *chip[2];
} rfbi;
+
+ struct {
+ DSIHost *host;
+ qemu_irq drq[4];
+ /* protocol engine registers */
+ uint32_t sysconfig;
+ uint32_t irqst;
+ uint32_t irqen;
+ uint32_t ctrl;
+ uint32_t complexio_cfg1;
+ uint32_t complexio_cfg2;
+ uint32_t complexio_irqst;
+ uint32_t complexio_irqen;
+ uint32_t clk_ctrl;
+ uint32_t timing1;
+ uint32_t timing2;
+ uint32_t vm_timing1;
+ uint32_t vm_timing2;
+ uint32_t vm_timing3;
+ uint32_t vm_timing4;
+ uint32_t vm_timing5;
+ uint32_t vm_timing6;
+ uint32_t vm_timing7;
+ uint32_t clk_timing;
+ uint32_t stopclk_timing;
+ uint32_t tx_fifo_vc_size;
+ uint32_t rx_fifo_vc_size;
+ struct {
+ uint32_t ctrl;
+ uint32_t te;
+ uint32_t lp_header;
+ uint32_t lp_payload;
+ int lp_counter;
+ uint32_t sp_header;
+ uint32_t irqst;
+ uint32_t irqen;
+ uint32_t rx_fifo[OMAP_DSI_RX_FIFO_SIZE];
+ int rx_fifo_pos;
+ int rx_fifo_len;
+ } vc[4];
+ /* phy registers */
+ uint32_t phy_cfg0;
+ uint32_t phy_cfg1;
+ uint32_t phy_cfg2;
+ /* pll controller registers */
+ uint32_t pll_control;
+ uint32_t pll_go;
+ uint32_t pll_config1;
+ uint32_t pll_config2;
+ } dsi;
+};
+
+#include "pixel_ops.h"
+#include "framebuffer.h"
+#define DEPTH 8
+#include "omap_dss_drawfn.h"
+#define DEPTH 15
+#include "omap_dss_drawfn.h"
+#define DEPTH 16
+#include "omap_dss_drawfn.h"
+#define DEPTH 24
+#include "omap_dss_drawfn.h"
+#define DEPTH 32
+#include "omap_dss_drawfn.h"
+#undef DEPTH
+
+static drawfn omap_dss_linefn(const DeviceState *dev, int format, int bpp)
+{
+ switch (bpp) {
+ case 8: return omap_dss_drawfn_8[format];
+ case 15: return omap_dss_drawfn_15[format];
+ case 16: return omap_dss_drawfn_16[format];
+ case 24: return omap_dss_drawfn_24[format];
+ case 32: return omap_dss_drawfn_32[format];
+ default:
+ hw_error("%s: unsupported host display color depth: %d\n",
+ __FUNCTION__, bpp);
+ break;
+ }
+ return NULL;
+}
+
+/* Bytes(!) per pixel */
+static const int omap_lcd_Bpp[0x10] = {
+ 0, /* 0x0: BITMAP1 (CLUT) */
+ 0, /* 0x1: BITMAP2 (CLUT) */
+ 0, /* 0x2: BITMAP4 (CLUT) */
+ 1, /* 0x3: BITMAP8 (CLUT) */
+ 2, /* 0x4: RGB12 (unpacked 16-bit container)*/
+ 2, /* 0x5: ARGB16 */
+ 2, /* 0x6: RGB16 */
+ 0, /* 0x7: reserved */
+ 4, /* 0x8: RGB24 (unpacked in 32-bit container) */
+ 3, /* 0x9: RGB24 (packed in 24-bit container) */
+ 2, /* 0xa: YUV2 422 */
+ 2, /* 0xb: UYVY 422 */
+ 4, /* 0xc: ARGB32 */
+ 4, /* 0xd: RGBA32 */
+ 4, /* 0xe: RGBx32 (24-bit RGB aligned on MSB of the 32-bit container) */
+ 0, /* 0xf: reserved */
};
-static void omap_dispc_interrupt_update(struct omap_dss_s *s)
+static void omap_dss_interrupt_update(struct omap_dss_s *s)
{
- qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
+ qemu_set_irq(s->irq,
+ (s->dsi.irqst & s->dsi.irqen)
+ | (s->dsi.complexio_irqst & s->dsi.complexio_irqen)
+ | (s->dsi.vc[0].irqst & s->dsi.vc[0].irqen)
+ | (s->dsi.vc[1].irqst & s->dsi.vc[1].irqen)
+ | (s->dsi.vc[2].irqst & s->dsi.vc[2].irqen)
+ | (s->dsi.vc[3].irqst & s->dsi.vc[3].irqen)
+ | (s->dispc.irqst & s->dispc.irqen));
+}
+
+static void omap_dss_framedone(void *opaque)
+{
+ struct omap_dss_s *s = (struct omap_dss_s *)opaque;
+ if (s->dispc.control & 3) { /* DIGITALENABLE | LCDENABLE */
+ if ((s->dispc.control & (1 << 11))) { /* STALLMODE */
+ s->dispc.control &= ~1; /* LCDENABLE */
+ if ((s->rfbi.control & 1)) { /* ENABLE */
+ s->rfbi.pixels = 0;
+ s->rfbi.busy = 0;
+ }
+ if (s->dispc.lcdframer) {
+ qemu_del_timer(s->dispc.lcdframer);
+ }
+ } else {
+ if (s->dispc.lcdframer) {
+ qemu_mod_timer(s->dispc.lcdframer,
+ qemu_get_clock_ns(vm_clock)
+ + get_ticks_per_sec() / 10);
+ }
+ }
+ s->dispc.irqst |= 1 | 2; /* FRAMEDONE | VSYNC */
+ omap_dss_interrupt_update(s);
+ }
+}
+
+static void omap_dsi_te_trigger(DeviceState *dev, int vc)
+{
+ struct omap_dss_s *s = FROM_SYSBUS(struct omap_dss_s,
+ sysbus_from_qdev(dev));
+ if ((s->dsi.ctrl & 1) && /* IF_EN */
+ (s->dsi.vc[vc].ctrl & 1)) { /* VC_EN */
+ s->dsi.irqst |= 1 << 16; /* TE_TRIGGER_IRQ */
+ omap_dss_interrupt_update(s);
+ }
+}
+
+static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
+{
+ if (!s->rfbi.busy)
+ return;
+
+ /* TODO: in non-Bypass mode we probably need to just deassert the DRQ. */
+
+ s->rfbi.busy = 0;
+ s->rfbi.control &= ~0x10; /* ITE */
+}
+
+static void omap_rfbi_transfer_start(struct omap_dss_s *s)
+{
+ void *data;
+ target_phys_addr_t len;
+ target_phys_addr_t data_addr;
+ int pitch;
+ static void *bounce_buffer;
+ static target_phys_addr_t bounce_len;
+
+ if (!s->rfbi.enable || s->rfbi.busy)
+ return;
+
+ if (s->rfbi.control & (1 << 1)) { /* BYPASS */
+ /* TODO: in non-Bypass mode we probably need to just assert the
+ * DRQ and wait for DMA to write the pixels. */
+ hw_error("%s: Bypass mode unimplemented", __FUNCTION__);
+ }
+
+ if (!(s->dispc.control & (1 << 11))) /* STALLMODE */
+ return;
+
+ s->rfbi.busy = 1;
+
+ len = s->rfbi.pixels * 2;
+
+ data_addr = s->dispc.plane[0].addr[0];
+ data = cpu_physical_memory_map(data_addr, &len, 0);
+ if (data && len != s->rfbi.pixels * 2) {
+ cpu_physical_memory_unmap(data, len, 0, 0);
+ data = NULL;
+ len = s->rfbi.pixels * 2;
+ }
+ if (!data) {
+ if (len > bounce_len) {
+ bounce_buffer = g_realloc(bounce_buffer, len);
+ }
+ data = bounce_buffer;
+ cpu_physical_memory_read(data_addr, data, len);
+ }
+
+ /* TODO: negative values */
+ pitch = s->dispc.plane[0].nx + (s->dispc.plane[0].rowinc - 1) / 2;
+
+ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+ s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
+ if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+ s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
+
+ if (data != bounce_buffer) {
+ cpu_physical_memory_unmap(data, len, 0, len);
+ }
+
+ omap_rfbi_transfer_stop(s);
+
+ omap_dss_framedone(s);
+}
+
+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 */
+ 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);
+ TRACEDSI("dsi irqenable=0x%08x", s->dsi.irqen);
+ TRACEDSI("dispc irqenable=0x%08x", s->dispc.irqen);
+ int tx_dma = (s->dsi.vc[ch].ctrl >> 21) & 7; /* DMA_TX_REQ_NB */
+ if (tx_dma < 4) {
+ qemu_irq_raise(s->dsi.drq[tx_dma]);
+ } 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);
+ const int row_pitch = (s->dispc.plane[0].nx * col_pitch) +
+ (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);
+ if (!data || len != row_pitch * s->dispc.plane[0].ny) {
+ fprintf(stderr, "%s: unable to map contiguous frame buffer\n",
+ __FUNCTION__);
+ } else {
+ dsi_blt(s->dsi.host, ch, data, s->dispc.plane[0].nx,
+ s->dispc.plane[0].ny, col_pitch, row_pitch, format);
+ }
+ if (data) {
+ cpu_physical_memory_unmap(data, len, 0, 0);
+ }
+ s->dsi.vc[ch].te = 0; /* transfer complete */
+ omap_dss_framedone(s);
+ }
+ }
+}
+
+static void omap_dss_panel_layer_update(DisplayState *ds, MemoryRegion *mr,
+ uint32_t panel_width,
+ uint32_t panel_height,
+ uint32_t posx,
+ int *posy, int *endy,
+ uint32_t width, uint32_t height,
+ uint32_t attrib,
+ target_phys_addr_t addr,
+ uint32_t *palette,
+ int full_update)
+{
+ if (!(attrib & 1)) { /* layer disabled? */
+ return;
+ }
+ uint32_t format = (attrib >> 1) & 0xf;
+ if ((attrib & 0x600)) { /* GFXENDIANNESS | GFXNIBBLEMODE */
+ hw_error("%s: unsupported layer attributes (0x%08x)\n",
+ __FUNCTION__, attrib);
+ }
+ drawfn line_fn = omap_dss_linefn(NULL, format, ds_get_bits_per_pixel(ds));
+ if (!line_fn) {
+ hw_error("%s: unsupported omap dss color format: %d\n",
+ __FUNCTION__, format);
+ }
+ if (posx) {
+ fprintf(stderr, "%s@%d: non-zero layer x-coordinate (%d), "
+ "not currently supported -> using zero\n", __FUNCTION__,
+ __LINE__, posx);
+ posx = 0;
+ }
+
+ uint32_t copy_width = (posx + width) > panel_width
+ ? (panel_width - posx) : width;
+ uint32_t copy_height = ((*posy) + height) > panel_height
+ ? (panel_height - (*posy)) : height;
+ uint32_t linesize = ds_get_linesize(ds);
+ framebuffer_update_display(ds, mr, addr, copy_width, copy_height,
+ (format < 3)
+ ? (width >> (3 - format))
+ : (width * omap_lcd_Bpp[format]),
+ linesize, linesize / ds_get_width(ds),
+ full_update, line_fn, palette,
+ posy, endy);
+}
+
+static void omap_dss_panel_update_display(struct omap_dss_panel_s *s,
+ MemoryRegion *mr, int lcd)
+{
+ if (s->invalidate) {
+ if (s->shadow.width != ds_get_width(s->ds)
+ || s->shadow.height != ds_get_height(s->ds)) {
+ qemu_console_resize(s->ds, s->shadow.width, s->shadow.height);
+ }
+ if ((s->shadow.gfx.attr >> 12) & 0x3) { /* GFXROTATION */
+ hw_error("%s: GFX rotation is not supported", __FUNCTION__);
+ }
+ }
+
+ /* TODO: draw background color */
+ int first_row = -1;
+ int last_row = 0;
+ if ((lcd && !(s->shadow.gfx.attr & 0x100)) ||
+ (!lcd && (s->shadow.gfx.attr & 0x100))) {
+ if (s->shadow.gfx_palette && s->shadow.gfx_palette_size) {
+ cpu_physical_memory_read(s->shadow.gfx.addr[2],
+ (uint8_t *)s->shadow.gfx_palette,
+ s->shadow.gfx_palette_size
+ * sizeof(uint32_t));
+ }
+ first_row = s->shadow.gfx.posy;
+ omap_dss_panel_layer_update(s->ds, mr,
+ s->shadow.width, s->shadow.height,
+ s->shadow.gfx.posx, &first_row, &last_row,
+ s->shadow.gfx.nx, s->shadow.gfx.ny,
+ s->shadow.gfx.attr, s->shadow.gfx.addr[0],
+ s->shadow.gfx_palette, s->invalidate);
+ }
+ /* TODO: draw VID1 & VID2 layers */
+ s->invalidate = 0;
+
+ if (first_row >= 0) {
+ dpy_update(s->ds, 0, first_row, s->shadow.width,
+ last_row - first_row + 1);
+ }
+}
+
+static void omap_lcd_panel_update_display(void *opaque)
+{
+ struct omap_dss_s *s = opaque;
+ if (!s->lcd.ds
+ || !(s->lcd.shadow.control & 1) /* LCDENABLE */
+ || (s->lcd.shadow.control & (1 << 11))) { /* STALLMODE */
+ return;
+ }
+ omap_dss_panel_update_display(&s->lcd, sysbus_address_space(&s->busdev), 1);
+ omap_dss_framedone(s);
+}
+
+static void omap_lcd_panel_invalidate_display(void *opaque)
+{
+ struct omap_dss_s *s = opaque;
+ s->lcd.invalidate = 1;
+}
+
+static void omap_dig_panel_update_display(void *opaque)
+{
+ struct omap_dss_s *s = opaque;
+ if (!s->dig.ds || !(s->dig.shadow.control & 2)) { /* DIGITALENABLE */
+ return;
+ }
+ omap_dss_panel_update_display(&s->dig, sysbus_address_space(&s->busdev), 0);
+ omap_dss_framedone(s);
+}
+
+static void omap_dig_panel_invalidate_display(void *opaque)
+{
+ struct omap_dss_s *s = opaque;
+ s->dig.invalidate = 1;
+}
+
+static void omap_dss_panel_go(struct omap_dss_s *s,
+ struct omap_dss_panel_s *p,
+ uint32_t size)
+{
+ if (p->attached) {
+ p->invalidate = 1;
+ p->shadow.control = s->dispc.control;
+ p->shadow.width = (size & 0x7ff) + 1;
+ p->shadow.height = ((size >> 16) & 0x7ff) + 1;
+ p->shadow.gfx = s->dispc.plane[0];
+ p->shadow.vid1 = s->dispc.plane[1];
+ p->shadow.vid2 = s->dispc.plane[2];
+ int new_size = 0;
+ switch ((p->shadow.gfx.attr >> 1) & 0x0f) {
+ case 0: new_size = 2; break;
+ case 1: new_size = 4; break;
+ case 2: new_size = 16; break;
+ case 3: new_size = 256; break;
+ default: break;
+ }
+ if (new_size != p->shadow.gfx_palette_size) {
+ if (p->shadow.gfx_palette) {
+ g_free(p->shadow.gfx_palette);
+ p->shadow.gfx_palette = NULL;
+ }
+ if (new_size) {
+ p->shadow.gfx_palette = g_malloc(new_size * sizeof(uint32_t));
+ }
+ p->shadow.gfx_palette_size = new_size;
+ }
+ }
+}
+
+static void omap_dss_panel_reset(void *opaque)
+{
+ struct omap_dss_panel_s *s = opaque;
+ if (s->attached) {
+ s->shadow.control = 0;
+ memset(&s->shadow.gfx, 0, sizeof(s->shadow.gfx));
+ memset(&s->shadow.vid1, 0, sizeof(s->shadow.vid1));
+ memset(&s->shadow.vid2, 0, sizeof(s->shadow.vid2));
+ if (s->shadow.gfx_palette) {
+ g_free(s->shadow.gfx_palette);
+ s->shadow.gfx_palette = NULL;
+ s->shadow.gfx_palette_size = 0;
+ }
+ }
+}
+
+static void omap_dsi_reset(struct omap_dss_s *s)
+{
+ int i;
+
+ s->dsi.sysconfig = 0x11;
+ s->dsi.irqst = 0;
+ s->dsi.irqen = 0;
+ s->dsi.ctrl = 0x100;
+ s->dsi.complexio_cfg1 = 0x20000000;
+ s->dsi.complexio_cfg2 = 0;
+ s->dsi.complexio_irqst = 0;
+ s->dsi.complexio_irqen = 0;
+ s->dsi.clk_ctrl = 1;
+ s->dsi.timing1 = 0x7fff7fff;
+ s->dsi.timing2 = 0x7fff7fff;
+ s->dsi.vm_timing1 = 0;
+ s->dsi.vm_timing2 = 0;
+ s->dsi.vm_timing3 = 0;
+ s->dsi.vm_timing4 = 0;
+ s->dsi.vm_timing5 = 0;
+ s->dsi.vm_timing6 = 0;
+ s->dsi.vm_timing7 = 0;
+ s->dsi.clk_timing = 0x0101;
+ s->dsi.stopclk_timing = 0x80;
+ s->dsi.tx_fifo_vc_size = 0;
+ s->dsi.rx_fifo_vc_size = 0;
+ for (i = 0; i < 4; i++) {
+ s->dsi.vc[i].ctrl = 0;
+ s->dsi.vc[i].te = 0;
+ s->dsi.vc[i].lp_header = 0;
+ s->dsi.vc[i].lp_payload = 0;
+ s->dsi.vc[i].lp_counter = 0;
+ s->dsi.vc[i].sp_header = 0;
+ s->dsi.vc[i].irqst = 0;
+ s->dsi.vc[i].irqen = 0;
+ s->dsi.vc[i].rx_fifo_pos = 0;
+ s->dsi.vc[i].rx_fifo_len = 0;
+ }
+ if (s->mpu_model < omap3630) {
+ s->dsi.phy_cfg0 = 0x1a3c1a28;
+ s->dsi.phy_cfg1 = 0x420a1875;
+ s->dsi.phy_cfg2 = 0xb800001b;
+ } else {
+ s->dsi.phy_cfg0 = 0x1e481d3a;
+ s->dsi.phy_cfg1 = 0x420a1a6a;
+ s->dsi.phy_cfg2 = 0xb800001a;
+ }
+ s->dsi.pll_control = 0;
+ s->dsi.pll_go = 0;
+ s->dsi.pll_config1 = 0;
+ s->dsi.pll_config2 = 0;
+ omap_dss_interrupt_update(s);
}
static void omap_rfbi_reset(struct omap_dss_s *s)
@@ -119,19 +685,21 @@ static void omap_rfbi_reset(struct omap_dss_s *s)
s->rfbi.hsync = 0;
}
-void omap_dss_reset(struct omap_dss_s *s)
+static void omap_dss_reset(DeviceState *dev)
{
- s->autoidle = 0;
- s->control = 0;
- s->enable = 0;
-
- s->dig.enable = 0;
- s->dig.nx = 1;
- s->dig.ny = 1;
+ int i, j;
- s->lcd.enable = 0;
- s->lcd.nx = 1;
- s->lcd.ny = 1;
+ struct omap_dss_s *s = FROM_SYSBUS(struct omap_dss_s,
+ sysbus_from_qdev(dev));
+ s->autoidle = 0x10; /* was 0 for OMAP2 but bit4 must be set for OMAP3 */
+ s->control = 0;
+ if (s->mpu_model == omap3430) {
+ s->sdi_control = 0;
+ s->pll_control = 0;
+ s->dss_status = 0x81; /* bit 7 is not present prior to OMAP3 */
+ } else { /* omap2, omap3630 */
+ s->dss_status = 0x01;
+ }
s->dispc.idlemode = 0;
s->dispc.irqst = 0;
@@ -142,36 +710,60 @@ void omap_dss_reset(struct omap_dss_s *s)
s->dispc.timing[0] = 0;
s->dispc.timing[1] = 0;
s->dispc.timing[2] = 0;
- s->dispc.timing[3] = 0;
+ s->dispc.timing[3] = 0x00010002;
s->dispc.line = 0;
s->dispc.bg[0] = 0;
s->dispc.bg[1] = 0;
s->dispc.trans[0] = 0;
s->dispc.trans[1] = 0;
+ s->dispc.size_dig = 0;
+ s->dispc.size_lcd = 0;
+ s->dispc.global_alpha = 0;
+ s->dispc.cpr_coef_r = 0;
+ s->dispc.cpr_coef_g = 0;
+ s->dispc.cpr_coef_b = 0;
+
+ for (i = 0; i < 3; i++) {
+ s->dispc.plane[i].enable = 0;
+ s->dispc.plane[i].bpp = 0;
+ s->dispc.plane[i].addr[0] = 0;
+ s->dispc.plane[i].addr[1] = 0;
+ s->dispc.plane[i].addr[2] = 0;
+ s->dispc.plane[i].posx = 0;
+ s->dispc.plane[i].posy = 0;
+ s->dispc.plane[i].nx = 1;
+ s->dispc.plane[i].ny = 1;
+ s->dispc.plane[i].attr = 0;
+ s->dispc.plane[i].tresh = (s->dispc.rev < 0x30) ? 0 : 0x03ff03c0;
+ s->dispc.plane[i].rowinc = 1;
+ s->dispc.plane[i].colinc = 1;
+ s->dispc.plane[i].wininc = 0;
+ s->dispc.plane[i].preload = 0x100;
+ s->dispc.plane[i].fir = 0;
+ s->dispc.plane[i].picture_size = 0;
+ s->dispc.plane[i].accu[0] = 0;
+ s->dispc.plane[i].accu[1] = 0;
+ for (j = 0; j < 5; j++)
+ s->dispc.plane[i].conv_coef[j] = 0;
+ for (j = 0; j < 8; j++) {
+ s->dispc.plane[i].fir_coef_h[j] = 0;
+ s->dispc.plane[i].fir_coef_hv[j] = 0;
+ s->dispc.plane[i].fir_coef_v[j] = 0;
+ }
+ }
- s->dispc.l[0].enable = 0;
- s->dispc.l[0].bpp = 0;
- s->dispc.l[0].addr[0] = 0;
- s->dispc.l[0].addr[1] = 0;
- s->dispc.l[0].addr[2] = 0;
- s->dispc.l[0].posx = 0;
- s->dispc.l[0].posy = 0;
- s->dispc.l[0].nx = 1;
- s->dispc.l[0].ny = 1;
- s->dispc.l[0].attr = 0;
- s->dispc.l[0].tresh = 0;
- s->dispc.l[0].rowinc = 1;
- s->dispc.l[0].colinc = 1;
- s->dispc.l[0].wininc = 0;
-
+ omap_dsi_reset(s);
omap_rfbi_reset(s);
- omap_dispc_interrupt_update(s);
+ omap_dss_panel_reset(&s->lcd);
+ omap_dss_panel_reset(&s->dig);
+ omap_dss_interrupt_update(s);
}
static uint64_t omap_diss_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+ uint32_t x;
if (size != 4) {
return omap_badwidth_read32(opaque, addr);
@@ -179,26 +771,70 @@ static uint64_t omap_diss_read(void *opaque, target_phys_addr_t addr,
switch (addr) {
case 0x00: /* DSS_REVISIONNUMBER */
+ TRACEDISS("DSS_REVISIONNUMBER: 0x20");
return 0x20;
case 0x10: /* DSS_SYSCONFIG */
+ TRACEDISS("DSS_SYSCONFIG: 0x%08x", s->autoidle);
return s->autoidle;
case 0x14: /* DSS_SYSSTATUS */
- return 1; /* RESETDONE */
+ TRACEDISS("DSS_SYSSTATUS: 0x1");
+ return 1; /* RESETDONE */
+
+ case 0x18: /* DSS_IRQSTATUS */
+ x = (s->dispc.irqst & s->dispc.irqen) ? 1 : 0;
+ if ((s->dsi.irqst & s->dsi.irqen)
+ | (s->dsi.complexio_irqst & s->dsi.complexio_irqen)
+ | (s->dsi.vc[0].irqst & s->dsi.vc[0].irqen)
+ | (s->dsi.vc[1].irqst & s->dsi.vc[1].irqen)
+ | (s->dsi.vc[2].irqst & s->dsi.vc[2].irqen)
+ | (s->dsi.vc[3].irqst & s->dsi.vc[3].irqen))
+ x |= 2;
+ TRACEDISS("DSS_IRQSTATUS: 0x%08x", x);
+ return x;
case 0x40: /* DSS_CONTROL */
+ TRACEDISS("DSS_CONTROL: 0x%08x", s->control);
return s->control;
+ case 0x44: /* DSS_SDI_CONTROL */
+ if (s->mpu_model == omap3430) {
+ TRACEDISS("DSS_SDI_CONTROL: 0x%08x", s->sdi_control);
+ return s->sdi_control;
+ }
+ break;
+
+ case 0x48: /* DSS_PLL_CONTROL */
+ if (s->mpu_model == omap3430) {
+ TRACEDISS("DSS_PLL_CONTROL: 0x%08x", s->pll_control);
+ return s->pll_control;
+ }
+ break;
+
case 0x50: /* DSS_PSA_LCD_REG_1 */
case 0x54: /* DSS_PSA_LCD_REG_2 */
case 0x58: /* DSS_PSA_VIDEO_REG */
- /* TODO: fake some values when appropriate s->control bits are set */
- return 0;
-
- case 0x5c: /* DSS_STATUS */
- return 1 + (s->control & 1);
+ if (s->mpu_model < omap3430) {
+ TRACEDISS("DSS_PSA_xxx: 0");
+ /* TODO: fake some values according to s->control bits */
+ return 0;
+ }
+ break;
+ case 0x5c:
+ x = s->dss_status;
+ if (s->mpu_model < omap3430) {
+ TRACEDISS("DSS_STATUS: 0x%08x", x);
+ } else {
+ if (s->mpu_model == omap3430) {
+ s->dss_status &= ~(1 << 6); /* SDI_PLL_BUSYFLAG */
+ TRACEDISS("DSS_SDI_STATUS: 0x%08x", x);
+ } else { /* omap3630 */
+ TRACEDISS("DSS_CLK_STATUS: 0x%08x", x);
+ }
+ }
+ return x;
default:
break;
}
@@ -218,25 +854,75 @@ static void omap_diss_write(void *opaque, target_phys_addr_t addr,
switch (addr) {
case 0x00: /* DSS_REVISIONNUMBER */
case 0x14: /* DSS_SYSSTATUS */
+ case 0x18: /* DSS_IRQSTATUS */
case 0x50: /* DSS_PSA_LCD_REG_1 */
case 0x54: /* DSS_PSA_LCD_REG_2 */
case 0x58: /* DSS_PSA_VIDEO_REG */
case 0x5c: /* DSS_STATUS */
- OMAP_RO_REG(addr);
+ /* quietly ignore */
+ /*OMAP_RO_REGV(addr, value);*/
break;
case 0x10: /* DSS_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dss_reset(s);
- s->autoidle = value & 1;
+ TRACEDISS("DSS_SYSCONFIG = 0x%08x", value);
+ if (value & 2) { /* SOFTRESET */
+ omap_dss_reset(&s->busdev.qdev);
+ }
+ if (s->mpu_model < omap3430) {
+ value &= 0x01;
+ } else {
+ value &= 0x19;
+ }
+ s->autoidle = value;
break;
case 0x40: /* DSS_CONTROL */
- s->control = value & 0x3dd;
+ TRACEDISS("DSS_CONTROL = 0x%08x", value);
+ if (s->mpu_model < omap3430) {
+ value &= 0x3dd;
+ } else {
+ value &= 0x3ff;
+ }
+ s->control = value;
+ s->dss_status &= ~0x3;
+ s->dss_status |= 1 + (s->control & 1);
+ break;
+
+ case 0x44: /* DSS_SDI_CONTROL */
+ if (s->mpu_model == omap3430) {
+ TRACEDISS("DSS_SDI_CONTROL = 0x%08x", value);
+ s->sdi_control = value & 0x000ff80f;
+ } else {
+ OMAP_BAD_REGV(addr, value);
+ }
+ break;
+
+ case 0x48: /* DSS_PLL_CONTROL */
+ if (s->mpu_model == omap3430) {
+ TRACEDISS("DSS_PLL_CONTROL = 0x%08x", value);
+ if (value & (1 << 18)) { /* SDI_PLL_SYSRESET */
+ s->dss_status |= 1 << 2; /* SDI_PLL_RESETDONE */
+ } else {
+ s->dss_status &= ~(1 << 2); /* SDI_PLL_RESETDONE */
+ }
+ if (value & (1 << 28)) { /* SDI_PLL_GOBIT */
+ s->dss_status |= 1 << 6; /* SDI_PLL_BUSYFLAG */
+ s->dss_status &= ~(1 << 5); /* SDI_PLL_LOCK */
+ } else {
+ if (s->pll_control & (1 << 28)) { /* SDI_PLL_GOBIT */
+ s->dss_status &= ~(1 << 6); /* SDI_PLL_BUSYFLAG */
+ s->dss_status |= 1 << 5; /* SDI_PLL_LOCK */
+ }
+ }
+ s->pll_control = value;
+ } else {
+ OMAP_BAD_REGV(addr, value);
+ }
break;
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REGV(addr, value);
+ break;
}
}
@@ -250,6 +936,7 @@ static uint64_t omap_disc_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+ int n = 0;
if (size != 4) {
return omap_badwidth_read32(opaque, addr);
@@ -257,113 +944,230 @@ static uint64_t omap_disc_read(void *opaque, target_phys_addr_t addr,
switch (addr) {
case 0x000: /* DISPC_REVISION */
- return 0x20;
-
+ TRACEDISPC("DISPC_REVISION: 0x%08x", s->dispc.rev);
+ return s->dispc.rev;
case 0x010: /* DISPC_SYSCONFIG */
+ TRACEDISPC("DISPC_SYSCONFIG: 0x%08x", s->dispc.idlemode);
return s->dispc.idlemode;
-
case 0x014: /* DISPC_SYSSTATUS */
+ TRACEDISPC("DISPC_SYSSTATUS: 1");
return 1; /* RESETDONE */
-
case 0x018: /* DISPC_IRQSTATUS */
+ TRACEDISPC("DISPC_IRQSTATUS: 0x%08x", s->dispc.irqst);
return s->dispc.irqst;
-
case 0x01c: /* DISPC_IRQENABLE */
+ TRACEDISPC("DISPC_IRQENABLE: 0x%08x", s->dispc.irqen);
return s->dispc.irqen;
-
case 0x040: /* DISPC_CONTROL */
+ TRACEDISPC("DISPC_CONTROL: 0x%08x", s->dispc.control);
return s->dispc.control;
-
case 0x044: /* DISPC_CONFIG */
+ TRACEDISPC("DISPC_CONFIG: 0x%08x", s->dispc.config);
return s->dispc.config;
-
case 0x048: /* DISPC_CAPABLE */
+ TRACEDISPC("DISPC_CAPABLE: 0x%08x", s->dispc.capable);
return s->dispc.capable;
-
case 0x04c: /* DISPC_DEFAULT_COLOR0 */
+ TRACEDISPC("DISPC_DEFAULT_COLOR0: 0x%08x", s->dispc.bg[0]);
return s->dispc.bg[0];
case 0x050: /* DISPC_DEFAULT_COLOR1 */
+ TRACEDISPC("DISPC_DEFAULT_COLOR0: 0x%08x", s->dispc.bg[1]);
return s->dispc.bg[1];
case 0x054: /* DISPC_TRANS_COLOR0 */
+ TRACEDISPC("DISPC_TRANS_COLOR0: 0x%08x", s->dispc.trans[0]);
return s->dispc.trans[0];
case 0x058: /* DISPC_TRANS_COLOR1 */
+ TRACEDISPC("DISPC_TRANS_COLOR0: 0x%08x", s->dispc.trans[1]);
return s->dispc.trans[1];
-
case 0x05c: /* DISPC_LINE_STATUS */
+ TRACEDISPC("DISPC_LINE_STATUS: 0x7ff");
return 0x7ff;
case 0x060: /* DISPC_LINE_NUMBER */
+ TRACEDISPC("DISPC_LINE_NUMBER: 0x%08x", s->dispc.line);
return s->dispc.line;
-
case 0x064: /* DISPC_TIMING_H */
+ TRACEDISPC("DISPC_TIMING_H: 0x%08x", s->dispc.timing[0]);
return s->dispc.timing[0];
case 0x068: /* DISPC_TIMING_V */
+ TRACEDISPC("DISPC_TIMING_H: 0x%08x", s->dispc.timing[1]);
return s->dispc.timing[1];
case 0x06c: /* DISPC_POL_FREQ */
+ TRACEDISPC("DISPC_POL_FREQ: 0x%08x", s->dispc.timing[2]);
return s->dispc.timing[2];
case 0x070: /* DISPC_DIVISOR */
+ TRACEDISPC("DISPC_DIVISOR: 0x%08x", s->dispc.timing[3]);
return s->dispc.timing[3];
-
+ case 0x074: /* DISPC_GLOBAL_ALPHA */
+ TRACEDISPC("DISPC_GLOBAL_ALPHA: 0x%08x", s->dispc.global_alpha);
+ return s->dispc.global_alpha;
case 0x078: /* DISPC_SIZE_DIG */
- return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
+ TRACEDISPC("DISPC_SIZE_DIG: 0x%08x", s->dispc.size_dig);
+ return s->dispc.size_dig;
case 0x07c: /* DISPC_SIZE_LCD */
- return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
-
+ TRACEDISPC("DISPC_SIZE_LCD: 0x%08x", s->dispc.size_lcd);
+ return s->dispc.size_lcd;
+ case 0x14c: /* DISPC_VID2_BA0 */
+ n++;
+ case 0x0bc: /* DISPC_VID1_BA0 */
+ n++;
case 0x080: /* DISPC_GFX_BA0 */
- return s->dispc.l[0].addr[0];
+ TRACEDISPC("DISPC_%s_BA0: " OMAP_FMT_plx, LAYERNAME(n),
+ s->dispc.plane[n].addr[0]);
+ return s->dispc.plane[n].addr[0];
+ case 0x150: /* DISPC_VID2_BA1 */
+ n++;
+ case 0x0c0: /* DISPC_VID1_BA1 */
+ n++;
case 0x084: /* DISPC_GFX_BA1 */
- return s->dispc.l[0].addr[1];
+ TRACEDISPC("DISPC_%s_BA1: " OMAP_FMT_plx, LAYERNAME(n),
+ s->dispc.plane[n].addr[1]);
+ return s->dispc.plane[n].addr[1];
+ case 0x154: /* DISPC_VID2_POSITION */
+ n++;
+ case 0x0c4: /* DISPC_VID1_POSITION */
+ n++;
case 0x088: /* DISPC_GFX_POSITION */
- return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
+ TRACEDISPC("DISPC_%s_POSITION: 0x%08x", LAYERNAME(n),
+ (s->dispc.plane[n].posy << 16) | s->dispc.plane[n].posx);
+ return (s->dispc.plane[n].posy << 16) | s->dispc.plane[n].posx;
+ case 0x158: /* DISPC_VID2_SIZE */
+ n++;
+ case 0x0c8: /* DISPC_VID1_SIZE */
+ n++;
case 0x08c: /* DISPC_GFX_SIZE */
- return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
+ TRACEDISPC("DISPC_%s_SIZE: 0x%08x", LAYERNAME(n),
+ ((s->dispc.plane[n].ny - 1) << 16)
+ | (s->dispc.plane[n].nx - 1));
+ return ((s->dispc.plane[n].ny - 1) << 16) | (s->dispc.plane[n].nx - 1);
+ case 0x15c: /* DISPC_VID2_ATTRIBUTES */
+ n++;
+ case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
+ n++;
case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
- return s->dispc.l[0].attr;
+ TRACEDISPC("DISPC_%s_ATTRIBUTES: 0x%08x", LAYERNAME(n),
+ s->dispc.plane[n].attr);
+ return s->dispc.plane[n].attr;
+ case 0x160: /* DISPC_VID2_FIFO_THRESHOLD */
+ n++;
+ case 0x0d0: /* DISPC_VID1_FIFO_THRESHOLD */
+ n++;
case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
- return s->dispc.l[0].tresh;
+ TRACEDISPC("DISPC_%s_THRESHOLD: 0x%08x", LAYERNAME(n),
+ s->dispc.plane[n].tresh);
+ return s->dispc.plane[n].tresh;
+ case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */
+ n++;
+ case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */
+ n++;
case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
- return 256;
+ TRACEDISPC("DISPC_%s_FIFO_SIZE_STATUS: 0x%08x", LAYERNAME(n),
+ s->dispc.rev < 0x30 ? 256 : 1024);
+ return s->dispc.rev < 0x30 ? 256 : 1024;
+ case 0x168: /* DISPC_VID2_ROW_INC */
+ n++;
+ case 0x0d8: /* DISPC_VID1_ROW_INC */
+ n++;
case 0x0ac: /* DISPC_GFX_ROW_INC */
- return s->dispc.l[0].rowinc;
+ TRACEDISPC("DISPC_%s_ROW_INC: 0x%08x", LAYERNAME(n),
+ s->dispc.plane[n].rowinc);
+ return s->dispc.plane[n].rowinc;
+ case 0x16c: /* DISPC_VID2_PIXEL_INC */
+ n++;
+ case 0x0dc: /* DISPC_VID1_PIXEL_INC */
+ n++;
case 0x0b0: /* DISPC_GFX_PIXEL_INC */
- return s->dispc.l[0].colinc;
+ TRACEDISPC("DISPC_%s_PIXEL_INC: 0x%08x", LAYERNAME(n),
+ s->dispc.plane[n].colinc);
+ return s->dispc.plane[n].colinc;
case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
- return s->dispc.l[0].wininc;
+ TRACEDISPC("DISPC_GFX_WINDOW_SKIP: 0x%08x", s->dispc.plane[0].wininc);
+ return s->dispc.plane[0].wininc;
case 0x0b8: /* DISPC_GFX_TABLE_BA */
- return s->dispc.l[0].addr[2];
-
- case 0x0bc: /* DISPC_VID1_BA0 */
- case 0x0c0: /* DISPC_VID1_BA1 */
- case 0x0c4: /* DISPC_VID1_POSITION */
- case 0x0c8: /* DISPC_VID1_SIZE */
- case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
- case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
- case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */
- case 0x0d8: /* DISPC_VID1_ROW_INC */
- case 0x0dc: /* DISPC_VID1_PIXEL_INC */
- case 0x0e0: /* DISPC_VID1_FIR */
- case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
- case 0x0e8: /* DISPC_VID1_ACCU0 */
- case 0x0ec: /* DISPC_VID1_ACCU1 */
- case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
- case 0x14c: /* DISPC_VID2_BA0 */
- case 0x150: /* DISPC_VID2_BA1 */
- case 0x154: /* DISPC_VID2_POSITION */
- case 0x158: /* DISPC_VID2_SIZE */
- case 0x15c: /* DISPC_VID2_ATTRIBUTES */
- case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
- case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */
- case 0x168: /* DISPC_VID2_ROW_INC */
- case 0x16c: /* DISPC_VID2_PIXEL_INC */
+ TRACEDISPC("DISPC_GFX_TABLE_BA: " OMAP_FMT_plx,
+ s->dispc.plane[0].addr[2]);
+ return s->dispc.plane[0].addr[2];
case 0x170: /* DISPC_VID2_FIR */
+ n++;
+ case 0x0e0: /* DISPC_VID1_FIR */
+ n++;
+ TRACEDISPC("DISPC_%s_FIR: 0x%08x", LAYERNAME(n),
+ s->dispc.plane[n].fir);
+ return s->dispc.plane[n].fir;
case 0x174: /* DISPC_VID2_PICTURE_SIZE */
+ n++;
+ case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
+ n++;
+ TRACEDISPC("DISPC_%s_PICTURE_SIZE: 0x%08x", LAYERNAME(n),
+ s->dispc.plane[n].picture_size);
+ return s->dispc.plane[n].picture_size;
case 0x178: /* DISPC_VID2_ACCU0 */
case 0x17c: /* DISPC_VID2_ACCU1 */
- case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+ n++;
+ case 0x0e8: /* DISPC_VID1_ACCU0 */
+ case 0x0ec: /* DISPC_VID1_ACCU1 */
+ n++;
+ TRACEDISPC("DISPC_%s_ACCU%d: 0x%08x", LAYERNAME(n),
+ (int)((addr >> 1) & 1),
+ s->dispc.plane[n].accu[(addr >> 1 ) & 1]);
+ return s->dispc.plane[n].accu[(addr >> 1) & 1];
+ case 0x180 ... 0x1bc: /* DISPC_VID2_FIR_COEF */
+ n++;
+ case 0x0f0 ... 0x12c: /* DISPC_VID1_FIR_COEF */
+ n++;
+ if (addr & 4) {
+ TRACEDISPC("DISPC_%s_FIR_COEF_HV%d: 0x%08x", LAYERNAME(n),
+ (int)((addr - ((n > 1) ? 0x180 : 0xf0)) / 8),
+ s->dispc.plane[n].fir_coef_hv[
+ (addr - ((n > 1) ? 0x180 : 0xf0)) / 8]);
+ return s->dispc.plane[n].fir_coef_hv[
+ (addr - ((n > 1) ? 0x180 : 0xf0)) / 8];
+ }
+ TRACEDISPC("DISPC_%s_FIR_COEF_H%d: 0x%08x", LAYERNAME(n),
+ (int)((addr - ((n > 1) ? 0x180 : 0xf0)) / 8),
+ s->dispc.plane[n].fir_coef_h[
+ (addr - ((n > 1) ? 0x180 : 0xf0)) / 8]);
+ return s->dispc.plane[n].fir_coef_h[
+ (addr - ((n > 1) ? 0x180 : 0xf0)) / 8];
+ case 0x1c0 ... 0x1d0: /* DISPC_VID2_CONV_COEFi */
+ n++;
+ case 0x130 ... 0x140: /* DISPC_VID1_CONV_COEFi */
+ n++;
+ TRACEDISPC("DISPC_%s_CONV_COEF%d: 0x%08x", LAYERNAME(n),
+ (int)((addr - ((n > 1) ? 0x1c0 : 0x130)) / 4),
+ s->dispc.plane[n].conv_coef[
+ (addr - ((n > 1) ? 0x1c0 : 0x130)) / 4]);
+ return s->dispc.plane[n].conv_coef[
+ (addr - ((n > 1) ? 0x1c0 : 0x130)) / 4];
case 0x1d4: /* DISPC_DATA_CYCLE1 */
case 0x1d8: /* DISPC_DATA_CYCLE2 */
case 0x1dc: /* DISPC_DATA_CYCLE3 */
+ TRACEDISPC("DISPC_DATA_CYCLE%d: 0", (int)((addr - 0x1d4) / 4));
return 0;
-
+ case 0x200 ... 0x21c: /* DISPC_VID2_FIR_COEF_Vi */
+ n++;
+ case 0x1e0 ... 0x1fc: /* DISPC_VID1_FIR_COEF_Vi */
+ n++;
+ TRACEDISPC("DISPC_%s_FIR_COEF_V%d: 0x%08x", LAYERNAME(n),
+ (int)((addr & 0x01f) / 4),
+ s->dispc.plane[n].fir_coef_v[(addr & 0x01f) / 4]);
+ return s->dispc.plane[n].fir_coef_v[(addr & 0x01f) / 4];
+ case 0x220: /* DISPC_CPR_COEF_R */
+ TRACEDISPC("DISPC_CPR_COEF_R: 0x%08x", s->dispc.cpr_coef_r);
+ return s->dispc.cpr_coef_r;
+ case 0x224: /* DISPC_CPR_COEF_G */
+ TRACEDISPC("DISPC_CPR_COEF_G: 0x%08x", s->dispc.cpr_coef_g);
+ return s->dispc.cpr_coef_g;
+ case 0x228: /* DISPC_CPR_COEF_B */
+ TRACEDISPC("DISPC_CPR_COEF_B: 0x%08x", s->dispc.cpr_coef_b);
+ return s->dispc.cpr_coef_b;
+ case 0x234: /* DISPC_VID2_PRELOAD */
+ n++;
+ case 0x230: /* DISPC_VID1_PRELOAD */
+ n++;
+ case 0x22c: /* DISPC_GFX_PRELOAD */
+ TRACEDISPC("DISPC_%s_PRELOAD: 0x%08x", LAYERNAME(n),
+ s->dispc.plane[n].preload);
+ return s->dispc.plane[n].preload;
default:
break;
}
@@ -375,211 +1179,329 @@ static void omap_disc_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned size)
{
struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+ uint32_t n = 0;
if (size != 4) {
return omap_badwidth_write32(opaque, addr, value);
}
switch (addr) {
+ case 0x000: /* DISPC_REVISION */
+ case 0x014: /* DISPC_SYSSTATUS */
+ case 0x05c: /* DISPC_LINE_STATUS */
+ case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
+ /* quietly ignore */
+ /*OMAP_RO_REGV(addr, value);*/
+ break;
case 0x010: /* DISPC_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dss_reset(s);
- s->dispc.idlemode = value & 0x301b;
+ TRACEDISPC("DISPC_SYSCONFIG = 0x%08x", value);
+ if (value & 2) { /* SOFTRESET */
+ omap_dss_reset(&s->busdev.qdev);
+ }
+ s->dispc.idlemode = value & ((s->dispc.rev < 0x30) ? 0x301b : 0x331f);
break;
-
case 0x018: /* DISPC_IRQSTATUS */
+ TRACEDISPC("DISPC_IRQSTATUS = 0x%08x", value);
s->dispc.irqst &= ~value;
- omap_dispc_interrupt_update(s);
+ omap_dss_interrupt_update(s);
break;
-
case 0x01c: /* DISPC_IRQENABLE */
- s->dispc.irqen = value & 0xffff;
- omap_dispc_interrupt_update(s);
+ TRACEDISPC("DISPC_IRQENABLE = 0x%08x", value);
+ s->dispc.irqen = value & ((s->dispc.rev < 0x30) ? 0xffff : 0x1ffff);
+ omap_dss_interrupt_update(s);
break;
-
case 0x040: /* DISPC_CONTROL */
- s->dispc.control = value & 0x07ff9fff;
- s->dig.enable = (value >> 1) & 1;
- s->lcd.enable = (value >> 0) & 1;
+ TRACEDISPC("DISPC_CONTROL = 0x%08x", value);
+ n = s->dispc.control; /* cache old value */
+ /* always clear GODIGITAL and GOLCD to signal completed shadowing */
+ if (s->dispc.rev < 0x30) {
+ s->dispc.control = value & 0x07ff9f9f;
+ } else {
+ s->dispc.control = (value & 0xffff9b9f)
+ | (s->dispc.control & 0x6000);
+ }
if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */
- if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
- fprintf(stderr, "%s: Overlay Optimization when no overlay "
- "region effectively exists leads to "
- "unpredictable behaviour!\n", __func__);
+ if (!((s->dispc.plane[1].attr | s->dispc.plane[2].attr) & 1)) {
+ TRACEDISPC("Overlay Optimization when no overlay "
+ "region effectively exists leads to "
+ "unpredictable behaviour!");
}
- if (value & (1 << 6)) { /* GODIGITAL */
- /* XXX: Shadowed fields are:
- * s->dispc.config
- * s->dispc.capable
- * s->dispc.bg[0]
- * s->dispc.bg[1]
- * s->dispc.trans[0]
- * s->dispc.trans[1]
- * s->dispc.line
- * s->dispc.timing[0]
- * s->dispc.timing[1]
- * s->dispc.timing[2]
- * s->dispc.timing[3]
- * s->lcd.nx
- * s->lcd.ny
- * s->dig.nx
- * s->dig.ny
- * s->dispc.l[0].addr[0]
- * s->dispc.l[0].addr[1]
- * s->dispc.l[0].addr[2]
- * s->dispc.l[0].posx
- * s->dispc.l[0].posy
- * s->dispc.l[0].nx
- * s->dispc.l[0].ny
- * s->dispc.l[0].tresh
- * s->dispc.l[0].rowinc
- * s->dispc.l[0].colinc
- * s->dispc.l[0].wininc
- * All they need to be loaded here from their shadow registers.
- */
+ if ((value & 0x21)) { /* GOLCD | LCDENABLE */
+ omap_dss_panel_go(s, &s->lcd, s->dispc.size_lcd);
}
- if (value & (1 << 5)) { /* GOLCD */
- /* XXX: Likewise for LCD here. */
+ if ((value & 0x42)) { /* GODIGITAL | DIGITALENABLE */
+ omap_dss_panel_go(s, &s->dig, s->dispc.size_dig);
+ }
+ if (value & 1) { /* LCDENABLE */
+ if ((value & (1 << 11))) { /* STALLMODE */
+ if ((s->rfbi.control & 0x11) && /* ITE | ENABLE */
+ !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc)) { /* TRIGGERMODE */
+ omap_rfbi_transfer_start(s);
+ }
+ if (s->dsi.ctrl & 1) { /* IF_EN */
+ int ch;
+ for (ch = 0; ch < 4; ch++) {
+ if ((s->dsi.vc[ch].ctrl & 1) && /* VC_EN */
+ (s->dsi.vc[ch].te >> 30) & 3) { /* TE_START | TE_EN */
+ omap_dsi_transfer_start(s, ch);
+ }
+ }
+ }
+ } else if (s->dispc.lcdframer) {
+ qemu_mod_timer(s->dispc.lcdframer,
+ qemu_get_clock_ns(vm_clock)
+ + get_ticks_per_sec() / 10);
+ }
+ } else if (n & 1) { /* enable -> disable, signal wip frame done */
+ s->dispc.control |= 1;
+ omap_dss_framedone(s);
+ s->dispc.control &= ~1;
}
- s->dispc.invalidate = 1;
break;
-
case 0x044: /* DISPC_CONFIG */
+ TRACEDISPC("DISPC_CONFIG = 0x%08x", value);
s->dispc.config = value & 0x3fff;
/* XXX:
* bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
* bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
*/
- s->dispc.invalidate = 1;
break;
-
case 0x048: /* DISPC_CAPABLE */
+ TRACEDISPC("DISPC_CAPABLE = 0x%08x", value);
s->dispc.capable = value & 0x3ff;
break;
-
case 0x04c: /* DISPC_DEFAULT_COLOR0 */
+ TRACEDISPC("DISPC_DEFAULT_COLOR0 = 0x%08x", value);
s->dispc.bg[0] = value & 0xffffff;
- s->dispc.invalidate = 1;
break;
case 0x050: /* DISPC_DEFAULT_COLOR1 */
+ TRACEDISPC("DISPC_DEFAULT_COLOR1 = 0x%08x", value);
s->dispc.bg[1] = value & 0xffffff;
- s->dispc.invalidate = 1;
break;
case 0x054: /* DISPC_TRANS_COLOR0 */
+ TRACEDISPC("DISPC_TRANS_COLOR0 = 0x%08x", value);
s->dispc.trans[0] = value & 0xffffff;
- s->dispc.invalidate = 1;
break;
case 0x058: /* DISPC_TRANS_COLOR1 */
+ TRACEDISPC("DISPC_TRANS_COLOR1 = 0x%08x", value);
s->dispc.trans[1] = value & 0xffffff;
- s->dispc.invalidate = 1;
break;
-
case 0x060: /* DISPC_LINE_NUMBER */
+ TRACEDISPC("DISPC_LINE_NUMBER = 0x%08x", value);
s->dispc.line = value & 0x7ff;
break;
-
case 0x064: /* DISPC_TIMING_H */
+ TRACEDISPC("DISPC_TIMING_H = 0x%08x", value);
s->dispc.timing[0] = value & 0x0ff0ff3f;
break;
case 0x068: /* DISPC_TIMING_V */
+ TRACEDISPC("DISPC_TIMING_V = 0x%08x", value);
s->dispc.timing[1] = value & 0x0ff0ff3f;
break;
case 0x06c: /* DISPC_POL_FREQ */
+ TRACEDISPC("DISPC_POL_FREQ = 0x%08x", value);
s->dispc.timing[2] = value & 0x0003ffff;
break;
case 0x070: /* DISPC_DIVISOR */
+ TRACEDISPC("DISPC_DIVISOR = 0x%08x", value);
s->dispc.timing[3] = value & 0x00ff00ff;
break;
-
+ case 0x074: /* DISPC_GLOBAL_ALPHA */
+ TRACEDISPC("DISPC_GLOBAL_ALPHA = 0x%08x", value);
+ s->dispc.global_alpha = value & 0x00ff00ff;
+ break;
case 0x078: /* DISPC_SIZE_DIG */
- s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
- s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
- s->dispc.invalidate = 1;
+ TRACEDISPC("DISPC_SIZE_DIG = 0x%08x (%dx%d)",
+ value, (value & 0x7ff) + 1, ((value >> 16) & 0x7ff) + 1);
+ s->dispc.size_dig = value;
break;
case 0x07c: /* DISPC_SIZE_LCD */
- s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
- s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
- s->dispc.invalidate = 1;
+ TRACEDISPC("DISPC_SIZE_LCD = 0x%08x (%dx%d)",
+ value, (value & 0x7ff) + 1, ((value >> 16) & 0x7ff) + 1);
+ s->dispc.size_lcd = value;
break;
+ case 0x14c: /* DISPC_VID2_BA0 */
+ n++;
+ case 0x0bc: /* DISPC_VID1_BA0 */
+ n++;
case 0x080: /* DISPC_GFX_BA0 */
- s->dispc.l[0].addr[0] = (target_phys_addr_t) value;
- s->dispc.invalidate = 1;
+ TRACEDISPC("DISPC_%s_BA0 = 0x%08x", LAYERNAME(n), value);
+ s->dispc.plane[n].addr[0] = (target_phys_addr_t) value;
break;
+ case 0x150: /* DISPC_VID2_BA1 */
+ n++;
+ case 0x0c0: /* DISPC_VID1_BA1 */
+ n++;
case 0x084: /* DISPC_GFX_BA1 */
- s->dispc.l[0].addr[1] = (target_phys_addr_t) value;
- s->dispc.invalidate = 1;
+ TRACEDISPC("DISPC_%s_BA1 = 0x%08x", LAYERNAME(n), value);
+ s->dispc.plane[n].addr[1] = (target_phys_addr_t) value;
break;
+ case 0x154: /* DISPC_VID2_POSITION */
+ n++;
+ case 0x0c4: /* DISPC_VID1_POSITION */
+ n++;
case 0x088: /* DISPC_GFX_POSITION */
- s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */
- s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */
- s->dispc.invalidate = 1;
+ s->dispc.plane[n].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */
+ s->dispc.plane[n].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */
+ TRACEDISPC("DISPC_%s_POSITION = 0x%08x (%d,%d)", LAYERNAME(n),
+ value, s->dispc.plane[n].posx, s->dispc.plane[n].posy);
break;
+ case 0x158: /* DISPC_VID2_SIZE */
+ n++;
+ case 0x0c8: /* DISPC_VID1_SIZE */
+ n++;
case 0x08c: /* DISPC_GFX_SIZE */
- s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */
- s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */
- s->dispc.invalidate = 1;
+ s->dispc.plane[n].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */
+ s->dispc.plane[n].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */
+ TRACEDISPC("DISPC_%s_SIZE = 0x%08x (%dx%d)", LAYERNAME(n),
+ value, s->dispc.plane[n].nx, s->dispc.plane[n].ny);
break;
case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
- s->dispc.l[0].attr = value & 0x7ff;
- if (value & (3 << 9))
- fprintf(stderr, "%s: Big-endian pixel format not supported\n",
- __FUNCTION__);
- s->dispc.l[0].enable = value & 1;
- s->dispc.l[0].bpp = (value >> 1) & 0xf;
- s->dispc.invalidate = 1;
+ TRACEDISPC("DISPC_GFX_ATTRIBUTES = 0x%08x", value);
+ if (s->mpu_model < omap3630) {
+ value &= 0xffff;
+ } else {
+ value &= 0x1000ffff;
+ }
+ s->dispc.plane[0].attr = value;
+ if (value & (3 << 9)) {
+ hw_error("%s: Big-endian pixel format not supported",
+ __FUNCTION__);
+ }
+ s->dispc.plane[0].enable = value & 1;
+ s->dispc.plane[0].bpp = (value >> 1) & 0xf;
+ s->dispc.plane[0].rotation_flag = (value >> 12) & 0x3;
+ s->dispc.plane[0].gfx_format = (value >> 1) & 0xf;
+ s->dispc.plane[0].gfx_channel = (value >> 8) & 0x1;
break;
- case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
- s->dispc.l[0].tresh = value & 0x01ff01ff;
+ case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
+ n++;
+ case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
+ n++;
+ case 0x0a4: /* DISPC_GFX_FIFO_THRESHOLD */
+ TRACEDISPC("DISPC_%s_FIFO_THRESHOLD = 0x%08x", LAYERNAME(n), value);
+ s->dispc.plane[n].tresh = value & ((s->dispc.rev < 0x30)
+ ? 0x01ff01ff : 0x0fff0fff);
break;
+ case 0x168: /* DISPC_VID2_ROW_INC */
+ n++;
+ case 0x0d8: /* DISPC_VID1_ROW_INC */
+ n++;
case 0x0ac: /* DISPC_GFX_ROW_INC */
- s->dispc.l[0].rowinc = value;
- s->dispc.invalidate = 1;
+ TRACEDISPC("DISPC_%s_ROW_INC = 0x%08x", LAYERNAME(n), value);
+ s->dispc.plane[n].rowinc = value;
break;
+ case 0x16c: /* DISPC_VID2_PIXEL_INC */
+ n++;
+ case 0x0dc: /* DISPC_VID1_PIXEL_INC */
+ n++;
case 0x0b0: /* DISPC_GFX_PIXEL_INC */
- s->dispc.l[0].colinc = value;
- s->dispc.invalidate = 1;
+ TRACEDISPC("DISPC_%s_PIXEL_INC = 0x%08x", LAYERNAME(n), value);
+ s->dispc.plane[n].colinc = value;
break;
case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
- s->dispc.l[0].wininc = value;
+ TRACEDISPC("DISPC_GFX_WINDOW_SKIP = 0x%08x", value);
+ s->dispc.plane[0].wininc = value;
break;
case 0x0b8: /* DISPC_GFX_TABLE_BA */
- s->dispc.l[0].addr[2] = (target_phys_addr_t) value;
- s->dispc.invalidate = 1;
+ TRACEDISPC("DISPC_GFX_TABLE_BA = 0x%08x", value);
+ s->dispc.plane[0].addr[2] = (target_phys_addr_t) value;
break;
-
- case 0x0bc: /* DISPC_VID1_BA0 */
- case 0x0c0: /* DISPC_VID1_BA1 */
- case 0x0c4: /* DISPC_VID1_POSITION */
- case 0x0c8: /* DISPC_VID1_SIZE */
- case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
- case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
- case 0x0d8: /* DISPC_VID1_ROW_INC */
- case 0x0dc: /* DISPC_VID1_PIXEL_INC */
- case 0x0e0: /* DISPC_VID1_FIR */
- case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
- case 0x0e8: /* DISPC_VID1_ACCU0 */
- case 0x0ec: /* DISPC_VID1_ACCU1 */
- case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
- case 0x14c: /* DISPC_VID2_BA0 */
- case 0x150: /* DISPC_VID2_BA1 */
- case 0x154: /* DISPC_VID2_POSITION */
- case 0x158: /* DISPC_VID2_SIZE */
case 0x15c: /* DISPC_VID2_ATTRIBUTES */
- case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
- case 0x168: /* DISPC_VID2_ROW_INC */
- case 0x16c: /* DISPC_VID2_PIXEL_INC */
+ n++;
+ case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
+ n++;
+ TRACEDISPC("DISPC_%s_ATTRIBUTES = 0x%08x", LAYERNAME(n), value);
+ if (s->mpu_model < omap3630) {
+ value &= 0x01ffffff;
+ } else {
+ value &= 0x11ffffff;
+ }
+ s->dispc.plane[n].attr = value;
+ break;
case 0x170: /* DISPC_VID2_FIR */
+ n++;
+ case 0x0e0: /* DISPC_VID1_FIR */
+ n++;
+ TRACEDISPC("DISPC_%s_FIR = 0x%08x", LAYERNAME(n), value);
+ s->dispc.plane[n].fir = value & 0x1fff1fff;
+ break;
case 0x174: /* DISPC_VID2_PICTURE_SIZE */
+ n++;
+ case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
+ n++;
+ TRACEDISPC("DISPC_%s_PICTURE_SIZE = 0x%08x", LAYERNAME(n), value);
+ s->dispc.plane[n].picture_size = value & 0x07ff07ff;
+ break;
case 0x178: /* DISPC_VID2_ACCU0 */
case 0x17c: /* DISPC_VID2_ACCU1 */
- case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+ n++;
+ case 0x0e8: /* DISPC_VID1_ACCU0 */
+ case 0x0ec: /* DISPC_VID1_ACCU1 */
+ n++;
+ TRACEDISPC("DISPC_%s_ACCU%d = 0x%08x", LAYERNAME(n),
+ (int)((addr >> 1) & 1), value);
+ s->dispc.plane[n].accu[(addr >> 1) & 1] = value & 0x03ff03ff;
+ break;
+ case 0x180 ... 0x1bc: /* DISPC_VID2_FIR_COEF */
+ n++;
+ case 0x0f0 ... 0x12c: /* DISPC_VID1_FIR_COEF */
+ n++;
+ if (addr & 4) {
+ TRACEDISPC("DISPC_%s_FIR_COEF_HV%d = 0x%08x", LAYERNAME(n),
+ (int)((addr - ((n > 1) ? 0x180 : 0xf0)) / 8), value);
+ s->dispc.plane[n].fir_coef_hv[(addr - ((n > 1) ? 0x180 : 0xf0)) / 8] = value;
+ } else {
+ TRACEDISPC("DISPC_%s_FIR_COEF_H%d = 0x%08x", LAYERNAME(n),
+ (int)((addr - ((n > 1) ? 0x180 : 0xf0)) / 8), value);
+ s->dispc.plane[n].fir_coef_h[(addr - ((n > 1) ? 0x180 : 0xf0)) / 8] = value;
+ }
+ break;
+ case 0x1c0 ... 0x1d0: /* DISPC_VID2_CONV_COEFi */
+ n++;
+ case 0x130 ... 0x140: /* DISPC_VID1_CONV_COEFi */
+ n++;
+ TRACEDISPC("DISPC_%s_CONV_COEF%d = 0x%08x", LAYERNAME(n),
+ (int)((addr - ((n > 1) ? 0x1c0 : 0x130)) / 4), value);
+ s->dispc.plane[n].conv_coef[(addr - ((n > 1) ? 0x1c0 : 0x130)) / 4] = value;
+ break;
case 0x1d4: /* DISPC_DATA_CYCLE1 */
case 0x1d8: /* DISPC_DATA_CYCLE2 */
case 0x1dc: /* DISPC_DATA_CYCLE3 */
+ TRACEDISPC("DISPC_DATA_CYCLE%d = 0x%08x (ignored)",
+ (int)((addr - 0x1d4) / 4), value);
+ break;
+ case 0x200 ... 0x21c: /* DISPC_VID2_FIR_COEF_Vi */
+ n++;
+ case 0x1e0 ... 0x1fc: /* DISPC_VID1_FIR_COEF_Vi */
+ n++;
+ TRACEDISPC("DISPC_%s_FIR_COEF_V%d = 0x%08x", LAYERNAME(n),
+ (int)((addr & 0x01f) / 4), value);
+ s->dispc.plane[n].fir_coef_v[(addr & 0x01f) / 4] = value & 0x0000ffff;
+ break;
+ case 0x220: /* DISPC_CPR_COEF_R */
+ TRACEDISPC("DISPC_CPR_COEF_R = 0x%08x", value);
+ s->dispc.cpr_coef_r = value & 0xffbffbff;
+ break;
+ case 0x224: /* DISPC_CPR_COEF_G */
+ TRACEDISPC("DISPC_CPR_COEF_G = 0x%08x", value);
+ s->dispc.cpr_coef_g = value & 0xffbffbff;
+ break;
+ case 0x228: /* DISPC_CPR_COEF_B */
+ TRACEDISPC("DISPC_CPR_COEF_B = 0x%08x", value);
+ s->dispc.cpr_coef_b = value & 0xffbffbff;
+ break;
+ case 0x234: /* DISPC_VID2_PRELOAD */
+ n++;
+ case 0x230: /* DISPC_VID1_PRELOAD */
+ n++;
+ case 0x22c: /* DISPC_GFX_PRELOAD */
+ TRACEDISPC("DISPC_%s_PRELOAD = 0x%08x", LAYERNAME(n), value);
+ s->dispc.plane[n].preload = value & 0x0fff;
break;
-
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REGV(addr, value);
+ break;
}
}
@@ -589,80 +1511,6 @@ static const MemoryRegionOps omap_disc_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
-{
- if (!s->rfbi.busy)
- return;
-
- /* TODO: in non-Bypass mode we probably need to just deassert the DRQ. */
-
- s->rfbi.busy = 0;
-}
-
-static void omap_rfbi_transfer_start(struct omap_dss_s *s)
-{
- void *data;
- target_phys_addr_t len;
- target_phys_addr_t data_addr;
- int pitch;
- static void *bounce_buffer;
- static target_phys_addr_t bounce_len;
-
- if (!s->rfbi.enable || s->rfbi.busy)
- return;
-
- if (s->rfbi.control & (1 << 1)) { /* BYPASS */
- /* TODO: in non-Bypass mode we probably need to just assert the
- * DRQ and wait for DMA to write the pixels. */
- fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
- return;
- }
-
- if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */
- return;
- /* TODO: check that LCD output is enabled in DISPC. */
-
- s->rfbi.busy = 1;
-
- len = s->rfbi.pixels * 2;
-
- data_addr = s->dispc.l[0].addr[0];
- data = cpu_physical_memory_map(data_addr, &len, 0);
- if (data && len != s->rfbi.pixels * 2) {
- cpu_physical_memory_unmap(data, len, 0, 0);
- data = NULL;
- len = s->rfbi.pixels * 2;
- }
- if (!data) {
- if (len > bounce_len) {
- bounce_buffer = g_realloc(bounce_buffer, len);
- }
- data = bounce_buffer;
- cpu_physical_memory_read(data_addr, data, len);
- }
-
- /* TODO bpp */
- s->rfbi.pixels = 0;
-
- /* TODO: negative values */
- pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
-
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
-
- if (data != bounce_buffer) {
- cpu_physical_memory_unmap(data, len, 0, len);
- }
-
- omap_rfbi_transfer_stop(s);
-
- /* TODO */
- s->dispc.irqst |= 1; /* FRAMEDONE */
- omap_dispc_interrupt_update(s);
-}
-
static uint64_t omap_rfbi_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
@@ -674,56 +1522,77 @@ static uint64_t omap_rfbi_read(void *opaque, target_phys_addr_t addr,
switch (addr) {
case 0x00: /* RFBI_REVISION */
+ TRACERFBI("RFBI_REVISION: 0x10");
return 0x10;
case 0x10: /* RFBI_SYSCONFIG */
+ TRACERFBI("RFBI_SYSCONFIG: 0x%08x", s->rfbi.idlemode);
return s->rfbi.idlemode;
case 0x14: /* RFBI_SYSSTATUS */
- return 1 | (s->rfbi.busy << 8); /* RESETDONE */
+ TRACERFBI("RFBI_SYSSTATUS: 0x%08x", 1 | (s->rfbi.busy << 8));
+ return 1 | (s->rfbi.busy << 8); /* RESETDONE */
case 0x40: /* RFBI_CONTROL */
+ TRACERFBI("RFBI_CONTROL: 0x%08x", s->rfbi.control);
return s->rfbi.control;
case 0x44: /* RFBI_PIXELCNT */
+ TRACERFBI("RFBI_PIXELCNT: 0x%08x", s->rfbi.pixels);
return s->rfbi.pixels;
case 0x48: /* RFBI_LINE_NUMBER */
+ TRACERFBI("RFBI_LINE_NUMBER: 0x%08x", s->rfbi.skiplines);
return s->rfbi.skiplines;
case 0x58: /* RFBI_READ */
case 0x5c: /* RFBI_STATUS */
+ TRACERFBI("RFBI_READ/STATUS: 0x%08x", s->rfbi.rxbuf);
return s->rfbi.rxbuf;
case 0x60: /* RFBI_CONFIG0 */
+ TRACERFBI("RFBI_CONFIG0: 0x%08x", s->rfbi.config[0]);
return s->rfbi.config[0];
case 0x64: /* RFBI_ONOFF_TIME0 */
+ TRACERFBI("RFBI_ONOFF_TIME0: 0x%08x", s->rfbi.time[0]);
return s->rfbi.time[0];
case 0x68: /* RFBI_CYCLE_TIME0 */
+ TRACERFBI("RFBI_CYCLE_TIME0: 0x%08x", s->rfbi.time[1]);
return s->rfbi.time[1];
case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+ TRACERFBI("RFBI_DATA_CYCLE1_0: 0x%08x", s->rfbi.data[0]);
return s->rfbi.data[0];
case 0x70: /* RFBI_DATA_CYCLE2_0 */
+ TRACERFBI("RFBI_DATA_CYCLE2_0: 0x%08x", s->rfbi.data[1]);
return s->rfbi.data[1];
case 0x74: /* RFBI_DATA_CYCLE3_0 */
+ TRACERFBI("RFBI_DATA_CYCLE3_0: 0x%08x", s->rfbi.data[2]);
return s->rfbi.data[2];
case 0x78: /* RFBI_CONFIG1 */
+ TRACERFBI("RFBI_CONFIG1: 0x%08x", s->rfbi.config[1]);
return s->rfbi.config[1];
case 0x7c: /* RFBI_ONOFF_TIME1 */
+ TRACERFBI("RFBI_ONOFF_TIME1: 0x%08x", s->rfbi.time[2]);
return s->rfbi.time[2];
case 0x80: /* RFBI_CYCLE_TIME1 */
+ TRACERFBI("RFBI_CYCLE_TIME1: 0x%08x", s->rfbi.time[3]);
return s->rfbi.time[3];
case 0x84: /* RFBI_DATA_CYCLE1_1 */
+ TRACERFBI("RFBI_DATA_CYCLE1_1: 0x%08x", s->rfbi.data[3]);
return s->rfbi.data[3];
case 0x88: /* RFBI_DATA_CYCLE2_1 */
+ TRACERFBI("RFBI_DATA_CYCLE2_1: 0x%08x", s->rfbi.data[4]);
return s->rfbi.data[4];
case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+ TRACERFBI("RFBI_DATA_CYCLE3_1: 0x%08x", s->rfbi.data[5]);
return s->rfbi.data[5];
case 0x90: /* RFBI_VSYNC_WIDTH */
+ TRACERFBI("RFBI_VSYNC_WIDTH: 0x%08x", s->rfbi.vsync);
return s->rfbi.vsync;
case 0x94: /* RFBI_HSYNC_WIDTH */
+ TRACERFBI("RFBI_HSYNC_WIDTH: 0x%08x", s->rfbi.hsync);
return s->rfbi.hsync;
}
OMAP_BAD_REG(addr);
@@ -741,40 +1610,51 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
switch (addr) {
case 0x10: /* RFBI_SYSCONFIG */
+ TRACERFBI("RFBI_SYSCONFIG = 0x%08x", value);
if (value & 2) /* SOFTRESET */
omap_rfbi_reset(s);
s->rfbi.idlemode = value & 0x19;
break;
case 0x40: /* RFBI_CONTROL */
- s->rfbi.control = value & 0xf;
+ TRACERFBI("RFBI_CONTROL = 0x%08x", value);
+ if (s->dispc.rev < 0x30)
+ s->rfbi.control = value & 0x1f;
+ else
+ s->rfbi.control = value & 0x1ff;
s->rfbi.enable = value & 1;
- if (value & (1 << 4) && /* ITE */
- !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
+ if ((s->dispc.control & 1) && /* LCDENABLE */
+ (value & 0x10) && /* ITE */
+ !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc)) /* TRIGGERMODE */
omap_rfbi_transfer_start(s);
break;
case 0x44: /* RFBI_PIXELCNT */
+ TRACERFBI("RFBI_PIXELCNT = 0x%08x", value);
s->rfbi.pixels = value;
break;
case 0x48: /* RFBI_LINE_NUMBER */
+ TRACERFBI("RFBI_LINE_NUMBER = 0x%08x", value);
s->rfbi.skiplines = value & 0x7ff;
break;
case 0x4c: /* RFBI_CMD */
+ TRACERFBI("RFBI_CMD = 0x%08x", value);
if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
break;
case 0x50: /* RFBI_PARAM */
+ TRACERFBI("RFBI_PARAM = 0x%08x", value);
if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
break;
case 0x54: /* RFBI_DATA */
+ TRACERFBI("RFBI_DATA = 0x%08x", value);
/* TODO: take into account the format set up in s->rfbi.config[?] and
* s->rfbi.data[?], but special-case the most usual scenario so that
* speed doesn't suffer. */
@@ -790,6 +1670,7 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
omap_rfbi_transfer_stop(s);
break;
case 0x58: /* RFBI_READ */
+ TRACERFBI("RFBI_READ = 0x%08x", value);
if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
@@ -799,6 +1680,7 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
break;
case 0x5c: /* RFBI_STATUS */
+ TRACERFBI("RFBI_STATUS = 0x%08x", value);
if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
@@ -808,53 +1690,68 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
break;
case 0x60: /* RFBI_CONFIG0 */
+ TRACERFBI("RFBI_CONFIG0 = 0x%08x", value);
s->rfbi.config[0] = value & 0x003f1fff;
break;
case 0x64: /* RFBI_ONOFF_TIME0 */
+ TRACERFBI("RFBI_ONOFF_TIME0 = 0x%08x", value);
s->rfbi.time[0] = value & 0x3fffffff;
break;
case 0x68: /* RFBI_CYCLE_TIME0 */
+ TRACERFBI("RFBI_CYCLE_TIME0 = 0x%08x", value);
s->rfbi.time[1] = value & 0x0fffffff;
break;
case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+ TRACERFBI("RFBI_DATA_CYCLE1_0 = 0x%08x", value);
s->rfbi.data[0] = value & 0x0f1f0f1f;
break;
case 0x70: /* RFBI_DATA_CYCLE2_0 */
+ TRACERFBI("RFBI_DATA_CYCLE2_0 = 0x%08x", value);
s->rfbi.data[1] = value & 0x0f1f0f1f;
break;
case 0x74: /* RFBI_DATA_CYCLE3_0 */
+ TRACERFBI("RFBI_DATA_CYCLE3_0 = 0x%08x", value);
s->rfbi.data[2] = value & 0x0f1f0f1f;
break;
case 0x78: /* RFBI_CONFIG1 */
+ TRACERFBI("RFBI_CONFIG1 = 0x%08x", value);
s->rfbi.config[1] = value & 0x003f1fff;
break;
case 0x7c: /* RFBI_ONOFF_TIME1 */
+ TRACERFBI("RFBI_ONOFF_TIME1 = 0x%08x", value);
s->rfbi.time[2] = value & 0x3fffffff;
break;
case 0x80: /* RFBI_CYCLE_TIME1 */
+ TRACERFBI("RFBI_CYCLE_TIME1 = 0x%08x", value);
s->rfbi.time[3] = value & 0x0fffffff;
break;
case 0x84: /* RFBI_DATA_CYCLE1_1 */
+ TRACERFBI("RFBI_DATA_CYCLE1_1 = 0x%08x", value);
s->rfbi.data[3] = value & 0x0f1f0f1f;
break;
case 0x88: /* RFBI_DATA_CYCLE2_1 */
+ TRACERFBI("RFBI_DATA_CYCLE2_1 = 0x%08x", value);
s->rfbi.data[4] = value & 0x0f1f0f1f;
break;
case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+ TRACERFBI("RFBI_DATA_CYCLE3_1 = 0x%08x", value);
s->rfbi.data[5] = value & 0x0f1f0f1f;
break;
case 0x90: /* RFBI_VSYNC_WIDTH */
+ TRACERFBI("RFBI_VSYNC_WIDTH = 0x%08x", value);
s->rfbi.vsync = value & 0xffff;
break;
case 0x94: /* RFBI_HSYNC_WIDTH */
+ TRACERFBI("RFBI_HSYNC_WIDTH = 0x%08x", value);
s->rfbi.hsync = value & 0xffff;
break;
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REGV(addr, value);
+ break;
}
}
@@ -873,6 +1770,7 @@ static uint64_t omap_venc_read(void *opaque, target_phys_addr_t addr,
switch (addr) {
case 0x00: /* REV_ID */
+ return 0x2;
case 0x04: /* STATUS */
case 0x08: /* F_CONTROL */
case 0x10: /* VIDOUT_CTRL */
@@ -915,8 +1813,7 @@ static uint64_t omap_venc_read(void *opaque, target_phys_addr_t addr,
case 0xb8: /* GEN_CTRL */
case 0xc4: /* DAC_TST__DAC_A */
case 0xc8: /* DAC_B__DAC_C */
- return 0;
-
+ return 0;
default:
break;
}
@@ -932,6 +1829,10 @@ static void omap_venc_write(void *opaque, target_phys_addr_t addr,
}
switch (addr) {
+ case 0x00: /* REV_ID */
+ case 0x04: /* STATUS */
+ /* read-only, ignore */
+ break;
case 0x08: /* F_CONTROL */
case 0x10: /* VIDOUT_CTRL */
case 0x14: /* SYNC_CTRL */
@@ -974,9 +1875,9 @@ static void omap_venc_write(void *opaque, target_phys_addr_t addr,
case 0xc4: /* DAC_TST__DAC_A */
case 0xc8: /* DAC_B__DAC_C */
break;
-
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REGV(addr, value);
+ break;
}
}
@@ -1029,7 +1930,8 @@ static void omap_im3_write(void *opaque, target_phys_addr_t addr,
break;
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REGV(addr, value);
+ break;
}
}
@@ -1039,48 +1941,631 @@ static const MemoryRegionOps omap_im3_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- target_phys_addr_t l3_base,
- qemu_irq irq, qemu_irq drq,
- omap_clk fck1, omap_clk fck2, omap_clk ck54m,
- omap_clk ick1, omap_clk ick2)
+static void omap_dsi_push_rx_fifo(struct omap_dss_s *s, int ch, uint32_t value)
{
- struct omap_dss_s *s = (struct omap_dss_s *)
- g_malloc0(sizeof(struct omap_dss_s));
-
- s->irq = irq;
- s->drq = drq;
- omap_dss_reset(s);
-
- memory_region_init_io(&s->iomem_diss1, &omap_diss_ops, s, "omap.diss1",
- omap_l4_region_size(ta, 0));
- memory_region_init_io(&s->iomem_disc1, &omap_disc_ops, s, "omap.disc1",
- omap_l4_region_size(ta, 1));
- memory_region_init_io(&s->iomem_rfbi1, &omap_rfbi_ops, s, "omap.rfbi1",
- omap_l4_region_size(ta, 2));
- memory_region_init_io(&s->iomem_venc1, &omap_venc_ops, s, "omap.venc1",
- omap_l4_region_size(ta, 3));
- memory_region_init_io(&s->iomem_im3, &omap_im3_ops, s,
- "omap.im3", 0x1000);
-
- omap_l4_attach(ta, 0, &s->iomem_diss1);
- omap_l4_attach(ta, 1, &s->iomem_disc1);
- omap_l4_attach(ta, 2, &s->iomem_rfbi1);
- omap_l4_attach(ta, 3, &s->iomem_venc1);
- memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
-
-#if 0
- s->state = graphic_console_init(omap_update_display,
- omap_invalidate_display, omap_screen_dump, s);
-#endif
+ int p;
+
+ if (s->dsi.vc[ch].rx_fifo_len < OMAP_DSI_RX_FIFO_SIZE) {
+ p = s->dsi.vc[ch].rx_fifo_pos + s->dsi.vc[ch].rx_fifo_len;
+ if (p >= OMAP_DSI_RX_FIFO_SIZE)
+ p -= OMAP_DSI_RX_FIFO_SIZE;
+ s->dsi.vc[ch].rx_fifo[p] = value;
+ s->dsi.vc[ch].rx_fifo_len++;
+ } else {
+ TRACEDSI("vc%d rx fifo overflow!", ch);
+ }
+}
+
+static uint32_t omap_dsi_pull_rx_fifo(struct omap_dss_s *s, int ch)
+{
+ int v = 0;
+
+ if (!s->dsi.vc[ch].rx_fifo_len) {
+ TRACEDSI("vc%d rx fifo underflow!", ch);
+ } else {
+ v = s->dsi.vc[ch].rx_fifo[s->dsi.vc[ch].rx_fifo_pos++];
+ s->dsi.vc[ch].rx_fifo_len--;
+ if (s->dsi.vc[ch].rx_fifo_pos >= OMAP_DSI_RX_FIFO_SIZE)
+ s->dsi.vc[ch].rx_fifo_pos = 0;
+ }
+
+ return v;
+}
+
+static uint32_t omap_dsi_read(void *opaque, target_phys_addr_t addr)
+{
+ struct omap_dss_s *s = (struct omap_dss_s *)opaque;
+ uint32_t x, y;
+
+ switch (addr) {
+ case 0x000: /* DSI_REVISION */
+ TRACEDSI("DSI_REVISION = 0x10");
+ return 0x10;
+ case 0x010: /* DSI_SYSCONFIG */
+ TRACEDSI("DSI_SYSCONFIG = 0x%04x", s->dsi.sysconfig);
+ return s->dsi.sysconfig;
+ case 0x014: /* DSI_SYSSTATUS */
+ TRACEDSI("DSI_SYSSTATUS = 0x01");
+ return 1; /* RESET_DONE */
+ case 0x018: /* DSI_IRQSTATUS */
+ TRACEDSI("DSI_IRQSTATUS = 0x%08x", s->dsi.irqst);
+ return s->dsi.irqst;
+ case 0x01c: /* DSI_IRQENABLE */
+ TRACEDSI("DSI_IRQENABLE = 0x%08x", s->dsi.irqen);
+ return s->dsi.irqen;
+ case 0x040: /* DSI_CTRL */
+ TRACEDSI("DSI_CTRL = 0x%08x", s->dsi.ctrl);
+ return s->dsi.ctrl;
+ case 0x048: /* DSI_COMPLEXIO_CFG1 */
+ TRACEDSI("DSI_COMPLEXIO_CFG1 = 0x%08x", s->dsi.complexio_cfg1);
+ return s->dsi.complexio_cfg1;
+ case 0x04c: /* DSI_COMPLEXIO_IRQSTATUS */
+ TRACEDSI("DSI_COMPLEXIO_IRQSTATUS = 0x%08x", s->dsi.complexio_irqst);
+ return s->dsi.complexio_irqst;
+ case 0x050: /* DSI_COMPLEXIO_IRQENABLE */
+ TRACEDSI("DSI_COMPLEXIO_IRQENABLE = 0x%08x", s->dsi.complexio_irqen);
+ return s->dsi.complexio_irqen;
+ case 0x054: /* DSI_CLK_CTRL */
+ TRACEDSI("DSI_CLK_CTRL = 0x%08x", s->dsi.clk_ctrl);
+ return s->dsi.clk_ctrl;
+ case 0x058: /* DSI_TIMING1 */
+ TRACEDSI("DSI_TIMING1 = 0x%08x", s->dsi.timing1);
+ return s->dsi.timing1;
+ case 0x05c: /* DSI_TIMING2 */
+ TRACEDSI("DSI_TIMING2 = 0x%08x", s->dsi.timing2);
+ return s->dsi.timing2;
+ case 0x060: /* DSI_VM_TIMING1 */
+ TRACEDSI("DSI_VM_TIMING1 = 0x%08x", s->dsi.vm_timing1);
+ return s->dsi.vm_timing1;
+ case 0x064: /* DSI_VM_TIMING2 */
+ TRACEDSI("DSI_VM_TIMING2 = 0x%08x", s->dsi.vm_timing2);
+ return s->dsi.vm_timing2;
+ case 0x068: /* DSI_VM_TIMING3 */
+ TRACEDSI("DSI_VM_TIMING3 = 0x%08x", s->dsi.vm_timing3);
+ return s->dsi.vm_timing3;
+ case 0x06c: /* DSI_CLK_TIMING */
+ TRACEDSI("DSI_CLK_TIMING = 0x%08x", s->dsi.clk_timing);
+ return s->dsi.clk_timing;
+ case 0x070: /* DSI_TX_FIFO_VC_SIZE */
+ TRACEDSI("DSI_TX_FIFO_VC_SIZE = 0x%08x", s->dsi.tx_fifo_vc_size);
+ return s->dsi.tx_fifo_vc_size;
+ case 0x074: /* DSI_RX_FIFO_VC_SIZE */
+ TRACEDSI("DSI_RX_FIFO_VC_SIZE = 0x%08x", s->dsi.rx_fifo_vc_size);
+ return s->dsi.rx_fifo_vc_size;
+ case 0x078: /* DSI_COMPLEXIO_CFG_2 */
+ TRACEDSI("DSI_COMPLEXIO_CFG_2 = 0x%08x", s->dsi.complexio_cfg2);
+ return s->dsi.complexio_cfg2;
+ case 0x07c: /* DSI_RX_FIFO_VC_FULLNESS */
+ TRACEDSI("DSI_RX_FIFO_VC_FULLNESS = 0x00");
+ return 0;
+ case 0x080: /* DSI_VM_TIMING4 */
+ TRACEDSI("DSI_VM_TIMING4 = 0x%08x", s->dsi.vm_timing4);
+ return s->dsi.vm_timing4;
+ case 0x084: /* DSI_TX_FIFO_VC_EMPTINESS */
+ TRACEDSI("DSI_TX_FIFO_VC_EMPTINESS = 0x7f7f7f7f");
+ return 0x7f7f7f7f;
+ case 0x088: /* DSI_VM_TIMING5 */
+ TRACEDSI("DSI_VM_TIMING5 = 0x%08x", s->dsi.vm_timing5);
+ return s->dsi.vm_timing5;
+ case 0x08c: /* DSI_VM_TIMING6 */
+ TRACEDSI("DSI_VM_TIMING6 = 0x%08x", s->dsi.vm_timing6);
+ return s->dsi.vm_timing6;
+ case 0x090: /* DSI_VM_TIMING7 */
+ TRACEDSI("DSI_VM_TIMING7 = 0x%08x", s->dsi.vm_timing7);
+ return s->dsi.vm_timing7;
+ case 0x094: /* DSI_STOPCLK_TIMING */
+ TRACEDSI("DSI_STOPCLK_TIMING = 0x%08x", s->dsi.stopclk_timing);
+ return s->dsi.stopclk_timing;
+ case 0x100 ... 0x17c: /* DSI_VCx_xxx */
+ x = (addr >> 5) & 3;
+ switch (addr & 0x1f) {
+ case 0x00: /* DSI_VCx_CTRL */
+ TRACEDSI("DSI_VC%d_CTRL = 0x%08x", x, s->dsi.vc[x].ctrl);
+ return s->dsi.vc[x].ctrl;
+ case 0x04: /* DSI_VCx_TE */
+ TRACEDSI("DSI_VC%d_TE = 0x%08x", x, s->dsi.vc[x].te);
+ return s->dsi.vc[x].te;
+ case 0x08: /* DSI_VCx_LONG_PACKET_HEADER */
+ /* write-only */
+ TRACEDSI("DSI_VC%d_LONG_PACKET_HEADER = 0", x);
+ return 0;
+ case 0x0c: /* DSI_VCx_LONG_PACKET_PAYLOAD */
+ /* write-only */
+ TRACEDSI("DSI_VC%d_LONG_PACKET_PAYLOAD = 0", x);
+ return 0;
+ case 0x10: /* DSI_VCx_SHORT_PACKET_HEADER */
+ if (s->dsi.vc[x].ctrl & (1 << 20)) { /* RX_FIFO_NOT_EMPTY */
+ y = omap_dsi_pull_rx_fifo(s, x);
+ TRACEDSI("DSI_VC%d_SHORT_PACKET_HEADER = 0x%08x", x, y);
+ if (!s->dsi.vc[x].rx_fifo_len)
+ s->dsi.vc[x].ctrl &= ~(1 << 20); /* RX_FIFO_NOT_EMPTY */
+ return y;
+ }
+ TRACEDSI("vc%d rx fifo underflow!", x);
+ return 0;
+ case 0x18: /* DSI_VCx_IRQSTATUS */
+ TRACEDSI("DSI_VC%d_IRQSTATUS = 0x%08x", x, s->dsi.vc[x].irqst);
+ return s->dsi.vc[x].irqst;
+ case 0x1c: /* DSI_VCx_IRQENABLE */
+ TRACEDSI("DSI_VC%d_IRQENABLE = 0x%08x", x, s->dsi.vc[x].irqen);
+ return s->dsi.vc[x].irqen;
+ default:
+ OMAP_BAD_REG(addr);
+ }
+ break;
+ case 0x200: /* DSI_PHY_CFG0 */
+ TRACEDSI("DSI_PHY_CFG0 = 0x%08x", s->dsi.phy_cfg0);
+ return s->dsi.phy_cfg0;
+ case 0x204: /* DSI_PHY_CFG1 */
+ TRACEDSI("DSI_PHY_CFG1 = 0x%08x", s->dsi.phy_cfg1);
+ return s->dsi.phy_cfg1;
+ case 0x208: /* DSI_PHY_CFG2 */
+ TRACEDSI("DSI_PHY_CFG2 = 0x%08x", s->dsi.phy_cfg2);
+ return s->dsi.phy_cfg2;
+ case 0x214: /* DSI_PHY_CFG5 */
+ TRACEDSI("DSI_PHY_CFG5 = 0xfc000000");
+ return 0xfc000000; /* all resets done */
+ case 0x300: /* DSI_PLL_CONTROL */
+ TRACEDSI("DSI_PLL_CONTROL = 0x%08x", s->dsi.pll_control);
+ return s->dsi.pll_control;
+ case 0x304: /* DSI_PLL_STATUS */
+ x = 1; /* DSI_PLLCTRL_RESET_DONE */
+ if ((s->dsi.clk_ctrl >> 28) & 3) { /* DSI PLL control powered? */
+ if (((s->dsi.pll_config1 >> 1) & 0x7f) && /* DSI_PLL_REGN */
+ ((s->dsi.pll_config1 >> 8) & 0x7ff)) { /* DSI_PLL_REGM */
+ x |= 2; /* DSI_PLL_LOCK */
+ }
+ }
+ if ((s->dsi.pll_config2 >> 20) & 1) /* DSI_HSDIVBYPASS */
+ x |= (1 << 9); /* DSI_BYPASSACKZ */
+ if ((s->dsi.pll_config2 >> 18) & 1) /* DSI_PROTO_CLOCK_EN */
+ x |= (1 << 8); /* DSIPROTO_CLOCK_ACK */
+ if ((s->dsi.pll_config2 >> 16) & 1) /* DSS_CLOCK_EN */
+ x |= (1 << 7); /* DSS_CLOCK_ACK */
+ if (!((s->dsi.pll_config2 >> 13) & 1)) /* DSI_PLL_REFEN */
+ x |= (1 << 3); /* DSI_PLL_LOSSREF */
+ TRACEDSI("DSI_PLL_STATUS = 0x%08x", x);
+ return x;
+ case 0x308: /* DSI_PLL_GO */
+ TRACEDSI("DSI_PLL_GO = 0x%08x", s->dsi.pll_go);
+ return s->dsi.pll_go;
+ case 0x30c: /* DSI_PLL_CONFIGURATION1 */
+ TRACEDSI("DSI_PLL_CONFIGURATION1 = 0x%08x", s->dsi.pll_config1);
+ return s->dsi.pll_config1;
+ case 0x310: /* DSI_PLL_CONFIGURATION2 */
+ TRACEDSI("DSI_PLL_CONFIGURATION2 = 0x%08x", s->dsi.pll_config2);
+ return s->dsi.pll_config2;
+ default:
+ break;
+ }
+ OMAP_BAD_REG(addr);
+ return 0;
+}
+
+static void omap_dsi_txdone(struct omap_dss_s *s, int ch, int bta)
+{
+ if (bta) {
+ s->dsi.vc[ch].irqst |= 0x20; /* BTA_IRQ */
+ if (s->dsi.vc[ch].rx_fifo_len)
+ s->dsi.vc[ch].ctrl |= 1 << 20; /* RX_FIFO_NOT_EMPTY */
+ } else {
+ s->dsi.vc[ch].irqst |= 0x04; /* PACKET_SENT_IRQ */
+ }
+ s->dsi.irqst |= 1 << ch; /* VIRTUAL_CHANNELx_IRQ */
+ omap_dss_interrupt_update(s);
+}
+
+static void omap_dsi_short_write(struct omap_dss_s *s, int ch)
+{
+ uint32_t data = s->dsi.vc[ch].sp_header;
+
+ if (((data >> 6) & 0x03) != ch) {
+ TRACEDSI("error - vc%d != %d", ch, (data >> 6) & 0x03);
+ } else {
+ data = dsi_short_write(s->dsi.host, data);
+ /* responses cannot be all-zero so it is safe to use that
+ * as a no-reply value */
+ if (data) {
+ omap_dsi_push_rx_fifo(s, ch, data);
+ }
+ omap_dsi_txdone(s, ch, (s->dsi.vc[ch].ctrl & 0x04)); /* BTA_SHORT_EN */
+ }
+}
+
+static void omap_dsi_long_write(struct omap_dss_s *s, int ch)
+{
+ uint32_t hdr = s->dsi.vc[ch].lp_header;
+
+ /* TODO: implement packet footer sending (16bit checksum).
+ * Currently none is sent and receiver is supposed to not expect one */
+ if (((hdr >> 6) & 0x03) != ch) {
+ TRACEDSI("error - vc%d != %d", ch, (hdr >> 6) & 0x03);
+ } else {
+ dsi_long_write(s->dsi.host, hdr, s->dsi.vc[ch].lp_payload,
+ s->dsi.vc[ch].lp_counter);
+ if ((s->dsi.vc[ch].te >> 30) & 3) { /* TE_START | TE_EN */
+ /* TODO: do we really need to implement something for this?
+ * Should writes decrease the TE_SIZE counter, for example?
+ * For now, the TE transfers are completed immediately */
+ } else {
+ if (s->dsi.vc[ch].lp_counter > 0)
+ s->dsi.vc[ch].lp_counter -= 4;
+ if (s->dsi.vc[ch].lp_counter <= 0)
+ omap_dsi_txdone(s, ch, (s->dsi.vc[ch].ctrl & 0x08)); /* BTA_LONG_EN */
+ }
+ }
+}
+
+static void omap_dsi_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap_dss_s *s = (struct omap_dss_s *)opaque;
+ uint32_t x;
+
+ switch (addr) {
+ case 0x000: /* DSI_REVISION */
+ case 0x014: /* DSI_SYSSTATUS */
+ case 0x07c: /* DSI_RX_FIFO_VC_FULLNESS */
+ case 0x084: /* DSI_RX_FIFO_VC_EMPTINESS */
+ case 0x214: /* DSI_PHY_CFG5 */
+ case 0x304: /* DSI_PLL_STATUS */
+ /* read-only, ignore */
+ break;
+ case 0x010: /* DSI_SYSCONFIG */
+ TRACEDSI("DSI_SYSCONFIG = 0x%08x", value);
+ if (value & 2) /* SOFT_RESET */
+ omap_dsi_reset(s);
+ else
+ s->dsi.sysconfig = value;
+ break;
+ case 0x018: /* DSI_IRQSTATUS */
+ TRACEDSI("DSI_IRQSTATUS = 0x%08x", value);
+ s->dsi.irqst &= ~(value & 0x1fc3b0);
+ omap_dss_interrupt_update(s);
+ break;
+ case 0x01c: /* DSI_IRQENABLE */
+ TRACEDSI("DSI_IRQENABLE = 0x%08x", value);
+ s->dsi.irqen = value & 0x1fc3b0;
+ omap_dss_interrupt_update(s);
+ break;
+ case 0x040: /* DSI_CTRL */
+ TRACEDSI("DSI_CTRL = 0x%08x", value);
+ s->dsi.ctrl = value & 0x7ffffff;
+ break;
+ case 0x048: /* DSI_COMPLEXIO_CFG_1 */
+ TRACEDSI("DSI_COMPLEXIO_CFG1 = 0x%08x", value);
+ value |= 1 << 29; /* RESET_DONE */
+ value |= 1 << 21; /* LDO_POWER_GOOD_STATE */
+ value &= ~(1 << 30); /* GOBIT */
+ /* copy PWR_CMD directly to PWR_STATUS */
+ value &= ~(3 << 25);
+ value |= (value >> 2) & (3 << 25);
+ /* TODO: notify screen refresh control about PWR_STATUS */
+ s->dsi.complexio_cfg1 = value;
+ break;
+ case 0x04c: /* DSI_COMPLEXIO_IRQSTATUS */
+ TRACEDSI("DSI_COMPLEXIO_IRQSTATUS = 0x%08x", value);
+ s->dsi.complexio_irqst &= ~(value & 0xc3f39ce7);
+ if (s->dsi.complexio_irqst & s->dsi.complexio_irqen)
+ s->dsi.irqst |= (1 << 10); /* COMPLEXIO_ERR_IRQ */
+ else
+ s->dsi.irqst &= ~(1 << 10); /* COMPLEXIO_ERR_IRQ */
+ omap_dss_interrupt_update(s);
+ break;
+ case 0x050: /* DSI_COMPLEXIO_IRQENABLE */
+ TRACEDSI("DSI_COMPLEXIO_IRQENABLE = 0x%08x", value);
+ s->dsi.complexio_irqen = value & 0xc3f39ce7;
+ omap_dss_interrupt_update(s);
+ break;
+ case 0x054: /* DSI_CLK_CTRL */
+ TRACEDSI("DSI_CLK_CTRL = 0x%08x", value);
+ value &= 0xc03fffff;
+ /* copy PLL_PWR_CMD directly to PLL_PWR_STATUS */
+ value |= (value >> 2) & (3 << 28);
+ s->dsi.clk_ctrl = value;
+ break;
+ case 0x058: /* DSI_TIMING1 */
+ TRACEDSI("DSI_TIMING1 = 0x%08x", value);
+ value &= ~(1 << 15); /* deassert ForceTxStopMode signal */
+ s->dsi.timing1 = value;
+ break;
+ case 0x05c: /* DSI_TIMING2 */
+ TRACEDSI("DSI_TIMING2 = 0x%08x", value);
+ s->dsi.timing2 = value;
+ break;
+ case 0x060: /* DSI_VM_TIMING1 */
+ TRACEDSI("DSI_VM_TIMING1 = 0x%08x", value);
+ s->dsi.vm_timing1 = value;
+ break;
+ case 0x064: /* DSI_VM_TIMING2 */
+ TRACEDSI("DSI_VM_TIMING2 = 0x%08x", value);
+ s->dsi.vm_timing2 = value & 0x0fffffff;
+ break;
+ case 0x068: /* DSI_VM_TIMING3 */
+ TRACEDSI("DSI_VM_TIMING3 = 0x%08x", value);
+ s->dsi.vm_timing3 = value;
+ break;
+ case 0x06c: /* DSI_CLK_TIMING */
+ TRACEDSI("DSI_CLK_TIMING = 0x%08x", value);
+ s->dsi.clk_timing = value & 0xffff;
+ break;
+ case 0x070: /* DSI_TX_FIFO_VC_SIZE */
+ TRACEDSI("DSI_TX_FIFO_VC_SIZE = 0x%08x", value);
+ s->dsi.tx_fifo_vc_size = value & 0xf7f7f7f7;
+ break;
+ case 0x074: /* DSI_RX_FIFO_VC_SIZE */
+ TRACEDSI("DSI_RX_FIFO_VC_SIZE = 0x%08x", value);
+ s->dsi.rx_fifo_vc_size = value & 0xf7f7f7f7;
+ break;
+ case 0x078: /* DSI_COMPLEXIO_CFG_2 */
+ TRACEDSI("DSI_COMPLEXIO_CFG_2 = 0x%08x", value);
+ s->dsi.complexio_cfg2 = (value & 0xfffcffff)
+ | (s->dsi.complexio_cfg2 & (3 << 16));
+ break;
+ case 0x080: /* DSI_VM_TIMING4 */
+ TRACEDSI("DSI_VM_TIMING4 = 0x%08x", value);
+ s->dsi.vm_timing4 = value;
+ break;
+ case 0x088: /* DSI_VM_TIMING5 */
+ TRACEDSI("DSI_VM_TIMING5 = 0x%08x", value);
+ s->dsi.vm_timing5 = value;
+ break;
+ case 0x08c: /* DSI_VM_TIMING6 */
+ TRACEDSI("DSI_VM_TIMING6 = 0x%08x", value);
+ s->dsi.vm_timing6 = value;
+ break;
+ case 0x090: /* DSI_VM_TIMING7 */
+ TRACEDSI("DSI_VM_TIMING7 = 0x%08x", value);
+ s->dsi.vm_timing7 = value;
+ break;
+ case 0x094: /* DSI_STOPCLK_TIMING */
+ TRACEDSI("DSI_STOPCLK_TIMING = 0x%08x", value);
+ s->dsi.stopclk_timing = value & 0xff;
+ break;
+ case 0x100 ... 0x17c: /* DSI_VCx_xxx */
+ x = (addr >> 5) & 3;
+ switch (addr & 0x1f) {
+ case 0x00: /* DSI_VCx_CTRL */
+ TRACEDSI("DSI_VC%d_CTRL = 0x%08x", x, value);
+ if (((value >> 27) & 7) != 4) /* DMA_RX_REQ_NB */
+ hw_error("%s: RX DMA mode not implemented", __FUNCTION__);
+ if (((value >> 21) & 7) != 4) /* DMA_TX_REQ_NB */
+ hw_error("%s: TX DMA mode not implemented", __FUNCTION__);
+ if (value & 1) { /* VC_EN */
+ s->dsi.vc[x].ctrl &= ~0x40; /* BTA_EN */
+ s->dsi.vc[x].ctrl |= 0x8001; /* VC_BUSY | VC_EN */
+ } else {
+ /* clear VC_BUSY and VC_EN, assign writable bits */
+ s->dsi.vc[x].ctrl = (s->dsi.vc[x].ctrl & 0x114020) |
+ (value & 0x3fee039f);
+ }
+ if (value & 0x40) /* BTA_EN */
+ omap_dsi_txdone(s, x, 1);
+ break;
+ case 0x04: /* DSI_VCx_TE */
+ TRACEDSI("DSI_VC%d_TE = 0x%08x", x, value);
+ value &= 0xc0ffffff;
+ /* according to the OMAP3 TRM the TE_EN bit in this
+ * register is protected by VCx_CTRL VC_EN bit but
+ * let's forget that */
+ s->dsi.vc[x].te = value;
+ if (s->dispc.control & 1) /* LCDENABLE */
+ omap_dsi_transfer_start(s, x);
+ break;
+ case 0x08: /* DSI_VCx_LONG_PACKET_HEADER */
+ TRACEDSI("DSI_VC%d_LONG_PACKET_HEADER id=0x%02x, len=0x%04x, ecc=0x%02x",
+ x, value & 0xff, (value >> 8) & 0xffff, (value >> 24) & 0xff);
+ s->dsi.vc[x].lp_header = value;
+ s->dsi.vc[x].lp_counter = (value >> 8) & 0xffff;
+ break;
+ case 0x0c: /* DSI_VCx_LONG_PACKET_PAYLOAD */
+ TRACEDSI("DSI_VC%d_LONG_PACKET_PAYLOAD = 0x%08x", x, value);
+ s->dsi.vc[x].lp_payload = value;
+ if ((s->dsi.vc[x].te >> 30) & 3) { /* TE_START | TE_EN */
+ int tx_dma = (s->dsi.vc[x].ctrl >> 21) & 7; /* DMA_TX_REQ_NB */
+ if (tx_dma < 4)
+ qemu_irq_lower(s->dsi.drq[tx_dma]);
+ }
+ omap_dsi_long_write(s, x);
+ break;
+ case 0x10: /* DSI_VCx_SHORT_PACKET_HEADER */
+ TRACEDSI("DSI_VC%d_SHORT_PACKET_HEADER = 0x%08x", x, value);
+ s->dsi.vc[x].sp_header = value;
+ omap_dsi_short_write(s, x);
+ break;
+ case 0x18: /* DSI_VCx_IRQSTATUS */
+ TRACEDSI("DSI_VC%d_IRQSTATUS = 0x%08x", x, value);
+ s->dsi.vc[x].irqst &= ~(value & 0x1ff);
+ if (s->dsi.vc[x].irqst & s->dsi.vc[x].irqen)
+ s->dsi.irqst |= 1 << x; /* VIRTUAL_CHANNELx_IRQ */
+ else
+ s->dsi.irqst &= ~(1 << x); /* VIRTUAL_CHANNELx_IRQ */
+ omap_dss_interrupt_update(s);
+ break;
+ case 0x1c: /* DSI_VCx_IRQENABLE */
+ TRACEDSI("DSI_VC%d_IRQENABLE = 0x%08x", x, value);
+ s->dsi.vc[x].irqen = value & 0x1ff;
+ omap_dss_interrupt_update(s);
+ break;
+ default:
+ OMAP_BAD_REGV(addr, value);
+ break;
+ }
+ break;
+ case 0x200: /* DSI_PHY_CFG0 */
+ TRACEDSI("DSI_PHY_CFG0 = 0x%08x", value);
+ s->dsi.phy_cfg0 = value;
+ break;
+ case 0x204: /* DSI_PHY_CFG1 */
+ TRACEDSI("DSI_PHY_CFG1 = 0x%08x", value);
+ s->dsi.phy_cfg1 = value;
+ break;
+ case 0x208: /* DSI_PHY_CFG2 */
+ TRACEDSI("DSI_PHY_CFG2 = 0x%08x", value);
+ if (s->mpu_model >= omap3630) {
+ value &= 0xff0000ff;
+ }
+ s->dsi.phy_cfg2 = value;
+ break;
+ case 0x300: /* DSI_PLL_CONTROL */
+ TRACEDSI("DSI_PLL_CONTROL = 0x%08x", value);
+ s->dsi.pll_control = value & 0x1f;
+ break;
+ case 0x308: /* DSI_PLL_GO */
+ TRACEDSI("DSI_PLL_GO = 0x%08x", value);
+ /* TODO: check if we need to update something here */
+ value &= ~1; /* mark it done */
+ s->dsi.pll_go = value & 1;
+ break;
+ case 0x30c: /* DSI_PLL_CONFIGURATION1 */
+ TRACEDSI("DSI_PLL_CONFIGURATION1 = 0x%08x", value);
+ s->dsi.pll_config1 = value & 0x7ffffff;
+ break;
+ case 0x310: /* DSI_PLL_CONFIGURATION2 */
+ TRACEDSI("DSI_PLL_CONFIGURATION2 = 0x%08x", value);
+ if (s->mpu_model < omap3630) {
+ value &= 0x1fffff;
+ } else {
+ value &= 0x1fffe1;
+ }
+ s->dsi.pll_config2 = value;
+ break;
+ default:
+ OMAP_BAD_REGV(addr, value);
+ break;
+ }
+}
+
+static const MemoryRegionOps omap_dsi_ops = {
+ .old_mmio = {
+ .read = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap_dsi_read,
+ },
+ .write = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap_dsi_write,
+ },
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int omap_dss_init(SysBusDevice *dev)
+{
+ struct omap_dss_s *s = FROM_SYSBUS(struct omap_dss_s, dev);
+ sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(dev, &s->drq); /* linetrigger */
+
+ memory_region_init_io(&s->iomem_diss1, &omap_diss_ops, s,
+ "omap.diss1", 0x400);
+ memory_region_init_io(&s->iomem_disc1, &omap_disc_ops, s,
+ "omap.disc1", 0x400);
+ memory_region_init_io(&s->iomem_rfbi1, &omap_rfbi_ops, s,
+ "omap.rfbi1", 0x400);
+ memory_region_init_io(&s->iomem_venc1, &omap_venc_ops, s,
+ "omap.venc1", 0x400);
+ sysbus_init_mmio(dev, &s->iomem_diss1);
+ sysbus_init_mmio(dev, &s->iomem_disc1);
+ sysbus_init_mmio(dev, &s->iomem_rfbi1);
+ sysbus_init_mmio(dev, &s->iomem_venc1);
+
+ if (s->mpu_model < omap2410) {
+ hw_error("%s: unsupported cpu type\n", __FUNCTION__);
+ } else if (s->mpu_model < omap3430) {
+ s->dispc.rev = 0x20;
+ memory_region_init_io(&s->iomem_im3, &omap_im3_ops, s,
+ "omap.im3", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem_im3);
+ } else {
+ s->dispc.rev = 0x30;
+ s->dispc.lcdframer = qemu_new_timer_ns(vm_clock, omap_dss_framedone, s);
+ s->dsi.host = dsi_init_host(&dev->qdev, "omap3_dsi",
+ omap_dsi_te_trigger,
+ omap_dss_linefn);
+ memory_region_init_io(&s->iomem_dsi, &omap_dsi_ops, s,
+ "omap.dsi", 0x400);
+ sysbus_init_mmio(dev, &s->iomem_dsi);
+ sysbus_init_irq(dev, &s->dsi.drq[0]);
+ sysbus_init_irq(dev, &s->dsi.drq[1]);
+ sysbus_init_irq(dev, &s->dsi.drq[2]);
+ sysbus_init_irq(dev, &s->dsi.drq[3]);
+ }
+ return 0;
+}
+
+static Property omap_dss_properties[] = {
+ DEFINE_PROP_INT32("mpu_model", struct omap_dss_s, mpu_model, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void omap_dss_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ k->init = omap_dss_init;
+ dc->reset = omap_dss_reset;
+ dc->props = omap_dss_properties;
+}
+
+static TypeInfo omap_dss_info = {
+ .name = "omap_dss",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap_dss_s),
+ .class_init = omap_dss_class_init,
+};
- return s;
+static void omap_dss_register_types(void)
+{
+ type_register_static(&omap_dss_info);
}
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
+void omap_rfbi_attach(DeviceState *dev, int cs,
+ const struct rfbi_chip_s *chip)
{
- if (cs < 0 || cs > 1)
+ struct omap_dss_s *s = FROM_SYSBUS(struct omap_dss_s,
+ sysbus_from_qdev(dev));
+ if (cs < 0 || cs > 1) {
hw_error("%s: wrong CS %i\n", __FUNCTION__, cs);
+ }
+ if (s->rfbi.chip[cs]) {
+ TRACERFBI("warning - replacing previously attached "
+ "RFBI chip on CS%d", cs);
+ }
s->rfbi.chip[cs] = chip;
}
+
+DSIHost *omap_dsi_host(DeviceState *dev)
+{
+ return FROM_SYSBUS(struct omap_dss_s,
+ sysbus_from_qdev(dev))->dsi.host;
+}
+
+void omap_lcd_panel_attach(DeviceState *dev)
+{
+ struct omap_dss_s *s = FROM_SYSBUS(struct omap_dss_s,
+ sysbus_from_qdev(dev));
+ if (!s->lcd.attached) {
+ s->lcd.attached = 1;
+ s->lcd.invalidate = 1;
+ s->lcd.ds = graphic_console_init(omap_lcd_panel_update_display,
+ omap_lcd_panel_invalidate_display,
+ NULL, NULL, s);
+ }
+}
+
+void omap_digital_panel_attach(DeviceState *dev)
+{
+ struct omap_dss_s *s = FROM_SYSBUS(struct omap_dss_s,
+ sysbus_from_qdev(dev));
+ if (!s->dig.attached) {
+ s->dig.attached = 1;
+ s->dig.invalidate = 1;
+ s->dig.ds = graphic_console_init(omap_dig_panel_update_display,
+ omap_dig_panel_invalidate_display,
+ NULL, NULL, s);
+ }
+}
+
+type_init(omap_dss_register_types)