/* Le masque LCD et l'acquittement doivent survivre à plusieurs resprings. */ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "sysemu/cpus.h" #include "hw/arm/ipod_touch_lcd.c" #define ipod_touch_machine_types test_mipi_register_types #include "hw/arm/ipod_touch_mipi_dsi.c" #undef ipod_touch_machine_types #include "hw/arm/ipod_touch_tvout.c" static void irq_changed(void *opaque, int n, int level) { *(int *)opaque = level; } static void test_interrupt_reenable(void) { IPodTouchLCDState *s = IPOD_TOUCH_LCD(object_new(TYPE_IPOD_TOUCH_LCD)); int level = 0; qemu_irq irq = qemu_allocate_irq(irq_changed, &level, 0); sysbus_connect_irq(SYS_BUS_DEVICE(s), 0, irq); s->refresh_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, refresh_timer_tick, s); for (int cycle = 0; cycle < 3; cycle++) { /* Vblank masqué : état en attente, aucune interruption CPU. */ ipod_touch_lcd_write(s, 0x8, 0, 4); refresh_timer_tick(s); g_assert_cmpint(level, ==, 0); g_assert_cmpuint(ipod_touch_lcd_read(s, 0xc, 4), ==, 1); ipod_touch_lcd_write(s, 0xc, 0xff, 4); g_assert_cmpuint(ipod_touch_lcd_read(s, 0xc, 4), ==, 0); /* Nouveau client : le masque réactive les vblanks après cet ACK. */ ipod_touch_lcd_write(s, 0x8, 1, 4); g_assert_cmpint(level, ==, 0); refresh_timer_tick(s); g_assert_cmpint(level, ==, 1); ipod_touch_lcd_write(s, 0xc, 2, 4); g_assert_cmpint(level, ==, 1); ipod_touch_lcd_write(s, 0xc, 1, 4); g_assert_cmpint(level, ==, 0); g_assert_cmpuint(ipod_touch_lcd_read(s, 0x8, 4), ==, 1); refresh_timer_tick(s); g_assert_cmpint(level, ==, 1); ipod_touch_lcd_write(s, 0x8, 0, 4); g_assert_cmpint(level, ==, 0); ipod_touch_lcd_write(s, 0x8, 1, 4); g_assert_cmpint(level, ==, 1); } ipod_touch_lcd_write(s, 0x24, 0x12340000, 4); device_cold_reset(DEVICE(s)); g_assert_cmpint(level, ==, 0); g_assert_cmpuint(ipod_touch_lcd_read(s, 0x8, 4), ==, 0); g_assert_cmpuint(ipod_touch_lcd_read(s, 0xc, 4), ==, 0); g_assert_cmpuint(ipod_touch_lcd_read(s, 0x24, 4), ==, 0); timer_del(s->refresh_timer); timer_free(s->refresh_timer); object_unref(OBJECT(s)); qemu_free_irq(irq); } static void test_tvout_submissions(void) { IPodTouchTVOutState *s = IPOD_TOUCH_TVOUT(object_new(TYPE_IPOD_TOUCH_TVOUT)); int level = 0; qemu_irq irq = qemu_allocate_irq(irq_changed, &level, 0); sysbus_connect_irq(SYS_BUS_DEVICE(s), 0, irq); /* L'ancien quota global cessait de répondre dès la troisième soumission. */ for (int cycle = 0; cycle < 20; cycle++) { ipod_touch_tvout_mixer1_write(s, MXR_STATUS, 0x85, 4); g_assert_cmpint(level, ==, 1); ipod_touch_tvout_sdo_write(s, SDO_IRQ, 2, 4); g_assert_cmpint(level, ==, 1); ipod_touch_tvout_sdo_write(s, SDO_IRQ, 1, 4); g_assert_cmpint(level, ==, 0); } ipod_touch_tvout_sdo_write(s, SDO_IRQMASK, 1, 4); ipod_touch_tvout_mixer1_write(s, MXR_STATUS, 0x85, 4); g_assert_cmpint(level, ==, 0); g_assert_cmpuint(ipod_touch_tvout_sdo_read(s, SDO_IRQ, 4), ==, 1); ipod_touch_tvout_sdo_write(s, SDO_IRQMASK, 0, 4); g_assert_cmpint(level, ==, 1); device_cold_reset(DEVICE(s)); g_assert_cmpint(level, ==, 0); g_assert_cmpuint(ipod_touch_tvout_sdo_read(s, SDO_IRQ, 4), ==, 0); ipod_touch_tvout_mixer1_write(s, MXR_STATUS, 0x85, 4); g_assert_cmpint(level, ==, 1); object_unref(OBJECT(s)); qemu_free_irq(irq); } static void test_panel_reset(void) { IPodTouchMIPIDSIState *s = IPOD_TOUCH_MIPI_DSI(object_new(TYPE_IPOD_TOUCH_MIPI_DSI)); for (int cycle = 0; cycle < 3; cycle++) { ipod_touch_mipi_dsi_write(s, REG_CLKCTRL, DSIM_CLKCTRL_TX_REQUEST_HSCLK, 4); g_assert_cmpuint(ipod_touch_mipi_dsi_read(s, 0, 4) & rDSIM_STATUS_TxReadyHsClk, !=, 0); g_assert_cmpuint(ipod_touch_mipi_dsi_read(s, REG_RXFIFO, 4), ==, 0x31a); /* Un reset pendant une réponse doit recommencer par son en-tête. */ device_cold_reset(DEVICE(s)); g_assert_cmpuint(ipod_touch_mipi_dsi_read(s, 0, 4) & rDSIM_STATUS_TxReadyHsClk, ==, 0); g_assert_cmpuint(ipod_touch_mipi_dsi_read(s, REG_RXFIFO, 4), ==, 0x31a); g_assert_cmpuint(ipod_touch_mipi_dsi_read(s, REG_RXFIFO, 4), ==, 0x00a1d13c); } object_unref(OBJECT(s)); } int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); module_call_init(MODULE_INIT_QOM); qemu_init_main_loop(&error_abort); qemu_init_cpu_loop(); qemu_mutex_lock_iothread(); g_test_add_func("/ipod-lcd/interrupt-reenable", test_interrupt_reenable); g_test_add_func("/ipod-tvout/repeated-submissions", test_tvout_submissions); g_test_add_func("/ipod-mipi/panel-reset", test_panel_reset); return g_test_run(); }