aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/display/xlnx_dp.c30
-rw-r--r--include/hw/display/xlnx_dp.h3
2 files changed, 29 insertions, 4 deletions
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index 0378570..ed856b5 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -114,6 +114,7 @@
#define DP_TX_N_AUD (0x032C >> 2)
#define DP_TX_AUDIO_EXT_DATA(n) ((0x0330 + 4 * n) >> 2)
#define DP_INT_STATUS (0x03A0 >> 2)
+#define DP_INT_VBLNK_START (1 << 13)
#define DP_INT_MASK (0x03A4 >> 2)
#define DP_INT_EN (0x03A8 >> 2)
#define DP_INT_DS (0x03AC >> 2)
@@ -260,7 +261,7 @@ typedef enum DPVideoFmt DPVideoFmt;
static const VMStateDescription vmstate_dp = {
.name = TYPE_XLNX_DP,
- .version_id = 1,
+ .version_id = 2,
.fields = (VMStateField[]){
VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState,
DP_CORE_REG_ARRAY_SIZE),
@@ -270,10 +271,15 @@ static const VMStateDescription vmstate_dp = {
DP_VBLEND_REG_ARRAY_SIZE),
VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState,
DP_AUDIO_REG_ARRAY_SIZE),
+ VMSTATE_PTIMER(vblank, XlnxDPState),
VMSTATE_END_OF_LIST()
}
};
+#define DP_VBLANK_PTIMER_POLICY (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | \
+ PTIMER_POLICY_CONTINUOUS_TRIGGER | \
+ PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)
+
static void xlnx_dp_update_irq(XlnxDPState *s);
static uint64_t xlnx_dp_audio_read(void *opaque, hwaddr offset, unsigned size)
@@ -773,6 +779,13 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value,
break;
case DP_TRANSMITTER_ENABLE:
s->core_registers[offset] = value & 0x01;
+ ptimer_transaction_begin(s->vblank);
+ if (value & 0x1) {
+ ptimer_run(s->vblank, 0);
+ } else {
+ ptimer_stop(s->vblank);
+ }
+ ptimer_transaction_commit(s->vblank);
break;
case DP_FORCE_SCRAMBLER_RESET:
/*
@@ -1177,9 +1190,6 @@ static void xlnx_dp_update_display(void *opaque)
return;
}
- s->core_registers[DP_INT_STATUS] |= (1 << 13);
- xlnx_dp_update_irq(s);
-
xlnx_dpdma_trigger_vsync_irq(s->dpdma);
/*
@@ -1275,6 +1285,14 @@ static void xlnx_dp_finalize(Object *obj)
fifo8_destroy(&s->rx_fifo);
}
+static void vblank_hit(void *opaque)
+{
+ XlnxDPState *s = XLNX_DP(opaque);
+
+ s->core_registers[DP_INT_STATUS] |= DP_INT_VBLNK_START;
+ xlnx_dp_update_irq(s);
+}
+
static void xlnx_dp_realize(DeviceState *dev, Error **errp)
{
XlnxDPState *s = XLNX_DP(dev);
@@ -1309,6 +1327,10 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp)
&as);
AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255);
xlnx_dp_audio_activate(s);
+ s->vblank = ptimer_init(vblank_hit, s, DP_VBLANK_PTIMER_POLICY);
+ ptimer_transaction_begin(s->vblank);
+ ptimer_set_freq(s->vblank, 30);
+ ptimer_transaction_commit(s->vblank);
}
static void xlnx_dp_reset(DeviceState *dev)
diff --git a/include/hw/display/xlnx_dp.h b/include/hw/display/xlnx_dp.h
index 1ef5a89..e86a87f 100644
--- a/include/hw/display/xlnx_dp.h
+++ b/include/hw/display/xlnx_dp.h
@@ -35,6 +35,7 @@
#include "hw/dma/xlnx_dpdma.h"
#include "audio/audio.h"
#include "qom/object.h"
+#include "hw/ptimer.h"
#define AUD_CHBUF_MAX_DEPTH (32 * KiB)
#define MAX_QEMU_BUFFER_SIZE (4 * KiB)
@@ -107,6 +108,8 @@ struct XlnxDPState {
*/
DPCDState *dpcd;
I2CDDCState *edid;
+
+ ptimer_state *vblank;
};
#define TYPE_XLNX_DP "xlnx.v-dp"