Compare commits
7 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e300fea6e5 | ||
|
|
c9698ac501 | ||
|
|
b5fbbfbda4 | ||
|
|
90bb55cbee | ||
|
|
b2c2c81a31 | ||
|
|
5629ede70e | ||
|
|
e31af84028 |
6 changed files with 244 additions and 14 deletions
|
|
@ -23,6 +23,7 @@ static void dvi_dma0_irq();
|
|||
static void dvi_dma1_irq();
|
||||
|
||||
void dvi_init(struct dvi_inst *inst, uint spinlock_tmds_queue, uint spinlock_colour_queue) {
|
||||
inst->started = inst->suspendflag = false;
|
||||
dvi_timing_state_init(&inst->timing_state);
|
||||
dvi_serialiser_init(&inst->ser_cfg);
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
||||
|
|
@ -82,6 +83,25 @@ void dvi_register_irqs_this_core(struct dvi_inst *inst, uint irq_num) {
|
|||
irq_set_enabled(irq_num, true);
|
||||
}
|
||||
|
||||
// Start/stop code from mlorenzatiglb on github:
|
||||
// https://github.com/mlorenzati/PicoDVI
|
||||
void dvi_unregister_irqs_this_core(struct dvi_inst *inst, uint irq_num) {
|
||||
irq_set_enabled(irq_num, false);
|
||||
if (irq_num == DMA_IRQ_0) {
|
||||
irq_remove_handler(DMA_IRQ_0, dvi_dma0_irq);
|
||||
} else {
|
||||
irq_remove_handler(DMA_IRQ_1, dvi_dma1_irq);
|
||||
}
|
||||
if (inst->tmds_buf_release) {
|
||||
queue_try_add_u32(&inst->q_tmds_free, &inst->tmds_buf_release);
|
||||
}
|
||||
if (inst->tmds_buf_release_next) {
|
||||
queue_try_add_u32(&inst->q_tmds_free, &inst->tmds_buf_release_next);
|
||||
}
|
||||
inst->tmds_buf_release = NULL;
|
||||
inst->tmds_buf_release_next = NULL;
|
||||
}
|
||||
|
||||
// Set up control channels to make transfers to data channels' control
|
||||
// registers (but don't trigger the control channels -- this is done either by
|
||||
// data channel CHAIN_TO or an initial write to MULTI_CHAN_TRIGGER)
|
||||
|
|
@ -107,6 +127,11 @@ static inline void __attribute__((always_inline)) _dvi_load_dma_op(const struct
|
|||
// CHAIN_TO on data channel completion. IRQ handler *must* be prepared before
|
||||
// calling this. (Hooked to DMA IRQ0)
|
||||
void dvi_start(struct dvi_inst *inst) {
|
||||
if (inst->started) return;
|
||||
// Purge any FIFO cruft that dvi_stop() may have left
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
||||
pio_sm_clear_fifos(inst->ser_cfg.pio, inst->ser_cfg.sm_tmds[i]);
|
||||
}
|
||||
_dvi_load_dma_op(inst->dma_cfg, &inst->dma_list_vblank_nosync);
|
||||
dma_start_channel_mask(
|
||||
(1u << inst->dma_cfg[0].chan_ctrl) |
|
||||
|
|
@ -115,14 +140,38 @@ void dvi_start(struct dvi_inst *inst) {
|
|||
|
||||
// We really don't want the FIFOs to bottom out, so wait for full before
|
||||
// starting the shift-out.
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i)
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
||||
while (!pio_sm_is_tx_fifo_full(inst->ser_cfg.pio, inst->ser_cfg.sm_tmds[i]))
|
||||
tight_loop_contents();
|
||||
}
|
||||
dvi_serialiser_enable(&inst->ser_cfg, true);
|
||||
inst->started = true;
|
||||
}
|
||||
|
||||
// Start/stop code from mlorenzatiglb on github:
|
||||
// https://github.com/mlorenzati/PicoDVI
|
||||
void dvi_stop(struct dvi_inst *inst) {
|
||||
if (!inst->started) return;
|
||||
uint mask = 0;
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
||||
dma_channel_config cfg = dma_channel_get_default_config(inst->dma_cfg[i].chan_ctrl);
|
||||
dma_channel_set_config(inst->dma_cfg[i].chan_ctrl, &cfg, false);
|
||||
cfg = dma_channel_get_default_config(inst->dma_cfg[i].chan_data);
|
||||
dma_channel_set_config(inst->dma_cfg[i].chan_data, &cfg, false);
|
||||
mask |= 1 << inst->dma_cfg[i].chan_data;
|
||||
mask |= 1 << inst->dma_cfg[i].chan_ctrl;
|
||||
}
|
||||
|
||||
dma_channel_abort(mask);
|
||||
dma_irqn_acknowledge_channel(0, inst->dma_cfg[TMDS_SYNC_LANE].chan_data);
|
||||
dma_hw->ints0 = 1u << inst->dma_cfg[TMDS_SYNC_LANE].chan_data;
|
||||
|
||||
dvi_serialiser_enable(&inst->ser_cfg, false);
|
||||
inst->started = false;
|
||||
}
|
||||
|
||||
static inline void __dvi_func_x(_dvi_prepare_scanline_8bpp)(struct dvi_inst *inst, uint32_t *scanbuf) {
|
||||
uint32_t *tmdsbuf;
|
||||
uint32_t *tmdsbuf = NULL;
|
||||
queue_remove_blocking_u32(&inst->q_tmds_free, &tmdsbuf);
|
||||
uint pixwidth = inst->timing->h_active_pixels;
|
||||
uint words_per_channel = pixwidth / DVI_SYMBOLS_PER_WORD;
|
||||
|
|
@ -134,7 +183,7 @@ static inline void __dvi_func_x(_dvi_prepare_scanline_8bpp)(struct dvi_inst *ins
|
|||
}
|
||||
|
||||
static inline void __dvi_func_x(_dvi_prepare_scanline_16bpp)(struct dvi_inst *inst, uint32_t *scanbuf) {
|
||||
uint32_t *tmdsbuf;
|
||||
uint32_t *tmdsbuf = NULL;
|
||||
queue_remove_blocking_u32(&inst->q_tmds_free, &tmdsbuf);
|
||||
uint pixwidth = inst->timing->h_active_pixels;
|
||||
uint words_per_channel = pixwidth / DVI_SYMBOLS_PER_WORD;
|
||||
|
|
@ -150,7 +199,17 @@ static inline void __dvi_func_x(_dvi_prepare_scanline_16bpp)(struct dvi_inst *in
|
|||
void __dvi_func(dvi_scanbuf_main_8bpp)(struct dvi_inst *inst) {
|
||||
uint y = 0;
|
||||
while (1) {
|
||||
uint32_t *scanbuf;
|
||||
if (inst->suspendflag) {
|
||||
dvi_unregister_irqs_this_core(inst, DMA_IRQ_0);
|
||||
dvi_stop(inst);
|
||||
inst->suspendflag = false; // Ack core 0
|
||||
while (!inst->suspendflag); // Wait for restart
|
||||
//y = 0;
|
||||
dvi_register_irqs_this_core(inst, DMA_IRQ_0);
|
||||
dvi_start(inst);
|
||||
inst->suspendflag = false; // Ack core 0
|
||||
}
|
||||
uint32_t *scanbuf = NULL;
|
||||
queue_remove_blocking_u32(&inst->q_colour_valid, &scanbuf);
|
||||
_dvi_prepare_scanline_8bpp(inst, scanbuf);
|
||||
queue_add_blocking_u32(&inst->q_colour_free, &scanbuf);
|
||||
|
|
@ -166,7 +225,17 @@ void __dvi_func(dvi_scanbuf_main_8bpp)(struct dvi_inst *inst) {
|
|||
void __dvi_func(dvi_scanbuf_main_16bpp)(struct dvi_inst *inst) {
|
||||
uint y = 0;
|
||||
while (1) {
|
||||
uint32_t *scanbuf;
|
||||
if (inst->suspendflag) {
|
||||
dvi_unregister_irqs_this_core(inst, DMA_IRQ_0);
|
||||
dvi_stop(inst);
|
||||
inst->suspendflag = false; // Ack core 0
|
||||
while (!inst->suspendflag); // Wait for restart
|
||||
//y = 0;
|
||||
dvi_register_irqs_this_core(inst, DMA_IRQ_0);
|
||||
dvi_start(inst);
|
||||
inst->suspendflag = false; // Ack core 0
|
||||
}
|
||||
uint32_t *scanbuf = NULL;
|
||||
queue_remove_blocking_u32(&inst->q_colour_valid, &scanbuf);
|
||||
_dvi_prepare_scanline_16bpp(inst, scanbuf);
|
||||
queue_add_blocking_u32(&inst->q_colour_free, &scanbuf);
|
||||
|
|
@ -195,7 +264,7 @@ static void __dvi_func(dvi_dma_irq_handler)(struct dvi_inst *inst) {
|
|||
tight_loop_contents();
|
||||
}
|
||||
|
||||
uint32_t *tmdsbuf;
|
||||
uint32_t *tmdsbuf = NULL;
|
||||
while (inst->late_scanline_ctr > 0 && queue_try_remove_u32(&inst->q_tmds_valid, &tmdsbuf)) {
|
||||
// If we displayed this buffer then it would be in the wrong vertical
|
||||
// position on-screen. Just pass it back.
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ struct dvi_inst {
|
|||
queue_t q_colour_valid;
|
||||
queue_t q_colour_free;
|
||||
|
||||
bool started;
|
||||
volatile bool suspendflag;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
|
@ -60,10 +62,16 @@ void dvi_init(struct dvi_inst *inst, uint spinlock_tmds_queue, uint spinlock_col
|
|||
// whichever core called this function. Registers an exclusive IRQ handler.
|
||||
void dvi_register_irqs_this_core(struct dvi_inst *inst, uint irq_num);
|
||||
|
||||
// Unregisters DVI irq callbacks for this core
|
||||
void dvi_unregister_irqs_this_core(struct dvi_inst *inst, uint irq_num);
|
||||
|
||||
// Start actually wiggling TMDS pairs. Call this once you have initialised the
|
||||
// DVI, have registered the IRQs, and are producing rendered scanlines.
|
||||
void dvi_start(struct dvi_inst *inst);
|
||||
|
||||
// Stops DVI pairs generations
|
||||
void dvi_stop(struct dvi_inst *inst);
|
||||
|
||||
// TMDS encode worker function: core enters and doesn't leave, but still
|
||||
// responds to IRQs. Repeatedly pop a scanline buffer from q_colour_valid,
|
||||
// TMDS encode it, and pass it to the tmds valid queue.
|
||||
|
|
|
|||
|
|
@ -39,18 +39,36 @@ static PicoDVI *dviptr = NULL; // For C access to active C++ object
|
|||
@brief Runs on core 1 on startup; this is how Philhower RP2040 handles
|
||||
multiprocessing.
|
||||
*/
|
||||
void setup1(void) {
|
||||
void __not_in_flash_func(setup1)(void) {
|
||||
while (dviptr == NULL) // Wait for PicoDVI::begin() to start on core 0
|
||||
yield();
|
||||
dviptr->_setup();
|
||||
}
|
||||
|
||||
// Runs on core 1 after dviptr set
|
||||
void PicoDVI::_setup(void) {
|
||||
void __not_in_flash_func(PicoDVI::_setup)(void) {
|
||||
while (wait_begin)
|
||||
; // Wait for DVIGFX*::begin() to set this
|
||||
|
||||
dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
|
||||
dvi_start(&dvi0);
|
||||
|
||||
#if 0
|
||||
// From CircuitPython source. Turns off flash access for core 1; any
|
||||
// access will hard fault from here forward, but is better than messing
|
||||
// up the CIRCUITPY filesystem.
|
||||
MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
|
||||
MPU->RNR = 6; // 7 is used by pico-sdk stack protection.
|
||||
MPU->RBAR = XIP_MAIN_BASE | MPU_RBAR_VALID_Msk;
|
||||
MPU->RASR = MPU_RASR_XN_Msk | // Execute never + restrict all else
|
||||
MPU_RASR_ENABLE_Msk |
|
||||
(0x1b << MPU_RASR_SIZE_Pos); // Mask up to SRAM region.
|
||||
MPU->RNR = 7;
|
||||
// Doesn't actually work yet though. Keeping this chunk of code around for
|
||||
// notes, as getting all the vital functions in RAM may provide a simpler
|
||||
// solution than the suspend/resume code as currently written.
|
||||
#endif
|
||||
|
||||
(*mainloop)(&dvi0);
|
||||
}
|
||||
|
||||
|
|
@ -251,6 +269,15 @@ static void mainloop1(struct dvi_inst *inst) {
|
|||
|
||||
void __not_in_flash_func(DVIGFX1::_mainloop)(void) {
|
||||
for (;;) {
|
||||
if (dvi0.suspendflag) {
|
||||
dvi_unregister_irqs_this_core(&dvi0, DMA_IRQ_0);
|
||||
dvi_stop(&dvi0);
|
||||
dvi0.suspendflag = false; // Ack core 0
|
||||
while (!dvi0.suspendflag); // Wait for restart
|
||||
dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
|
||||
dvi_start(&dvi0);
|
||||
dvi0.suspendflag = false; // Ack core 0
|
||||
}
|
||||
uint8_t *b8 = buffer_save;
|
||||
if (dbuf)
|
||||
b8 += ((WIDTH + 7) / 8) * HEIGHT * (1 - back_index);
|
||||
|
|
@ -387,6 +414,15 @@ static void mainlooptext1(struct dvi_inst *inst) {
|
|||
|
||||
void __not_in_flash_func(DVItext1::_mainloop)(void) {
|
||||
for (;;) {
|
||||
if (dvi0.suspendflag) {
|
||||
dvi_unregister_irqs_this_core(&dvi0, DMA_IRQ_0);
|
||||
dvi_stop(&dvi0);
|
||||
dvi0.suspendflag = false; // Ack core 0
|
||||
while (!dvi0.suspendflag); // Wait for restart
|
||||
dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
|
||||
dvi_start(&dvi0);
|
||||
dvi0.suspendflag = false; // Ack core 0
|
||||
}
|
||||
for (uint16_t y = 0; y < HEIGHT; y++) {
|
||||
uint16_t *row = getBuffer() + y * WIDTH;
|
||||
for (uint8_t y1 = 0; y1 < 8; y1++) {
|
||||
|
|
@ -429,3 +465,34 @@ bool DVItext1::begin(void) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start/stop code from mlorenzatiglb on github:
|
||||
// https://github.com/mlorenzati/PicoDVI
|
||||
// This part just sets flags to communicate between cores;
|
||||
// the actual suspend/resume takes place over in libdvi.
|
||||
|
||||
void PicoDVI::_toggle(void) {
|
||||
// DVI start/stop must occur on core 1. Signal DVI main loop to toggle
|
||||
// its state (suspend or resume), block until acknowledged.
|
||||
for (dviptr->dvi0.suspendflag = true; dviptr->dvi0.suspendflag; );
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Pause DVI output. This ability is required for code that writes
|
||||
to flash memory (such as Adafruit_CPFS). It's declared outside
|
||||
the PicoDVI class so that other code can declare a 'weak' version
|
||||
that's referenced if not linking with the PicoDVI library; the
|
||||
libraries need not be interdependent, but can still work together.
|
||||
*/
|
||||
void PicoDVI_suspend(void) {
|
||||
if (dviptr) dviptr->_toggle();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Resume previously-paused DVI output. Declared outside the PicoDVI
|
||||
class so that other code can declare a 'weak' version if not
|
||||
linking with the PicoDVI library.
|
||||
*/
|
||||
void PicoDVI_resume(void) {
|
||||
if (dviptr) dviptr->_toggle();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,12 @@ public:
|
|||
C init code to access protected elements.
|
||||
*/
|
||||
void _setup(void);
|
||||
/*!
|
||||
@brief Internal function for DVI suspend/resume. User code should not
|
||||
touch this, but needed for C PicoDVI_suspend() & PicoDVI_resume()
|
||||
functions.
|
||||
*/
|
||||
void _toggle(void);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
|
|
@ -341,3 +347,6 @@ public:
|
|||
|
||||
protected:
|
||||
};
|
||||
|
||||
void PicoDVI_suspend(void);
|
||||
void PicoDVI_resume(void);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ static void dvi_dma0_irq();
|
|||
static void dvi_dma1_irq();
|
||||
|
||||
void dvi_init(struct dvi_inst *inst, uint spinlock_tmds_queue, uint spinlock_colour_queue) {
|
||||
inst->started = inst->suspendflag = false;
|
||||
dvi_timing_state_init(&inst->timing_state);
|
||||
dvi_serialiser_init(&inst->ser_cfg);
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
||||
|
|
@ -82,6 +83,25 @@ void dvi_register_irqs_this_core(struct dvi_inst *inst, uint irq_num) {
|
|||
irq_set_enabled(irq_num, true);
|
||||
}
|
||||
|
||||
// Start/stop code from mlorenzatiglb on github:
|
||||
// https://github.com/mlorenzati/PicoDVI
|
||||
void dvi_unregister_irqs_this_core(struct dvi_inst *inst, uint irq_num) {
|
||||
irq_set_enabled(irq_num, false);
|
||||
if (irq_num == DMA_IRQ_0) {
|
||||
irq_remove_handler(DMA_IRQ_0, dvi_dma0_irq);
|
||||
} else {
|
||||
irq_remove_handler(DMA_IRQ_1, dvi_dma1_irq);
|
||||
}
|
||||
if (inst->tmds_buf_release) {
|
||||
queue_try_add_u32(&inst->q_tmds_free, &inst->tmds_buf_release);
|
||||
}
|
||||
if (inst->tmds_buf_release_next) {
|
||||
queue_try_add_u32(&inst->q_tmds_free, &inst->tmds_buf_release_next);
|
||||
}
|
||||
inst->tmds_buf_release = NULL;
|
||||
inst->tmds_buf_release_next = NULL;
|
||||
}
|
||||
|
||||
// Set up control channels to make transfers to data channels' control
|
||||
// registers (but don't trigger the control channels -- this is done either by
|
||||
// data channel CHAIN_TO or an initial write to MULTI_CHAN_TRIGGER)
|
||||
|
|
@ -107,6 +127,11 @@ static inline void __attribute__((always_inline)) _dvi_load_dma_op(const struct
|
|||
// CHAIN_TO on data channel completion. IRQ handler *must* be prepared before
|
||||
// calling this. (Hooked to DMA IRQ0)
|
||||
void dvi_start(struct dvi_inst *inst) {
|
||||
if (inst->started) return;
|
||||
// Purge any FIFO cruft that dvi_stop() may have left
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
||||
pio_sm_clear_fifos(inst->ser_cfg.pio, inst->ser_cfg.sm_tmds[i]);
|
||||
}
|
||||
_dvi_load_dma_op(inst->dma_cfg, &inst->dma_list_vblank_nosync);
|
||||
dma_start_channel_mask(
|
||||
(1u << inst->dma_cfg[0].chan_ctrl) |
|
||||
|
|
@ -115,14 +140,38 @@ void dvi_start(struct dvi_inst *inst) {
|
|||
|
||||
// We really don't want the FIFOs to bottom out, so wait for full before
|
||||
// starting the shift-out.
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i)
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
||||
while (!pio_sm_is_tx_fifo_full(inst->ser_cfg.pio, inst->ser_cfg.sm_tmds[i]))
|
||||
tight_loop_contents();
|
||||
}
|
||||
dvi_serialiser_enable(&inst->ser_cfg, true);
|
||||
inst->started = true;
|
||||
}
|
||||
|
||||
// Start/stop code from mlorenzatiglb on github:
|
||||
// https://github.com/mlorenzati/PicoDVI
|
||||
void dvi_stop(struct dvi_inst *inst) {
|
||||
if (!inst->started) return;
|
||||
uint mask = 0;
|
||||
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
||||
dma_channel_config cfg = dma_channel_get_default_config(inst->dma_cfg[i].chan_ctrl);
|
||||
dma_channel_set_config(inst->dma_cfg[i].chan_ctrl, &cfg, false);
|
||||
cfg = dma_channel_get_default_config(inst->dma_cfg[i].chan_data);
|
||||
dma_channel_set_config(inst->dma_cfg[i].chan_data, &cfg, false);
|
||||
mask |= 1 << inst->dma_cfg[i].chan_data;
|
||||
mask |= 1 << inst->dma_cfg[i].chan_ctrl;
|
||||
}
|
||||
|
||||
dma_channel_abort(mask);
|
||||
dma_irqn_acknowledge_channel(0, inst->dma_cfg[TMDS_SYNC_LANE].chan_data);
|
||||
dma_hw->ints0 = 1u << inst->dma_cfg[TMDS_SYNC_LANE].chan_data;
|
||||
|
||||
dvi_serialiser_enable(&inst->ser_cfg, false);
|
||||
inst->started = false;
|
||||
}
|
||||
|
||||
static inline void __dvi_func_x(_dvi_prepare_scanline_8bpp)(struct dvi_inst *inst, uint32_t *scanbuf) {
|
||||
uint32_t *tmdsbuf;
|
||||
uint32_t *tmdsbuf = NULL;
|
||||
queue_remove_blocking_u32(&inst->q_tmds_free, &tmdsbuf);
|
||||
uint pixwidth = inst->timing->h_active_pixels;
|
||||
uint words_per_channel = pixwidth / DVI_SYMBOLS_PER_WORD;
|
||||
|
|
@ -134,7 +183,7 @@ static inline void __dvi_func_x(_dvi_prepare_scanline_8bpp)(struct dvi_inst *ins
|
|||
}
|
||||
|
||||
static inline void __dvi_func_x(_dvi_prepare_scanline_16bpp)(struct dvi_inst *inst, uint32_t *scanbuf) {
|
||||
uint32_t *tmdsbuf;
|
||||
uint32_t *tmdsbuf = NULL;
|
||||
queue_remove_blocking_u32(&inst->q_tmds_free, &tmdsbuf);
|
||||
uint pixwidth = inst->timing->h_active_pixels;
|
||||
uint words_per_channel = pixwidth / DVI_SYMBOLS_PER_WORD;
|
||||
|
|
@ -150,7 +199,17 @@ static inline void __dvi_func_x(_dvi_prepare_scanline_16bpp)(struct dvi_inst *in
|
|||
void __dvi_func(dvi_scanbuf_main_8bpp)(struct dvi_inst *inst) {
|
||||
uint y = 0;
|
||||
while (1) {
|
||||
uint32_t *scanbuf;
|
||||
if (inst->suspendflag) {
|
||||
dvi_unregister_irqs_this_core(inst, DMA_IRQ_0);
|
||||
dvi_stop(inst);
|
||||
inst->suspendflag = false; // Ack core 0
|
||||
while (!inst->suspendflag); // Wait for restart
|
||||
//y = 0;
|
||||
dvi_register_irqs_this_core(inst, DMA_IRQ_0);
|
||||
dvi_start(inst);
|
||||
inst->suspendflag = false; // Ack core 0
|
||||
}
|
||||
uint32_t *scanbuf = NULL;
|
||||
queue_remove_blocking_u32(&inst->q_colour_valid, &scanbuf);
|
||||
_dvi_prepare_scanline_8bpp(inst, scanbuf);
|
||||
queue_add_blocking_u32(&inst->q_colour_free, &scanbuf);
|
||||
|
|
@ -166,7 +225,17 @@ void __dvi_func(dvi_scanbuf_main_8bpp)(struct dvi_inst *inst) {
|
|||
void __dvi_func(dvi_scanbuf_main_16bpp)(struct dvi_inst *inst) {
|
||||
uint y = 0;
|
||||
while (1) {
|
||||
uint32_t *scanbuf;
|
||||
if (inst->suspendflag) {
|
||||
dvi_unregister_irqs_this_core(inst, DMA_IRQ_0);
|
||||
dvi_stop(inst);
|
||||
inst->suspendflag = false; // Ack core 0
|
||||
while (!inst->suspendflag); // Wait for restart
|
||||
//y = 0;
|
||||
dvi_register_irqs_this_core(inst, DMA_IRQ_0);
|
||||
dvi_start(inst);
|
||||
inst->suspendflag = false; // Ack core 0
|
||||
}
|
||||
uint32_t *scanbuf = NULL;
|
||||
queue_remove_blocking_u32(&inst->q_colour_valid, &scanbuf);
|
||||
_dvi_prepare_scanline_16bpp(inst, scanbuf);
|
||||
queue_add_blocking_u32(&inst->q_colour_free, &scanbuf);
|
||||
|
|
@ -195,7 +264,7 @@ static void __dvi_func(dvi_dma_irq_handler)(struct dvi_inst *inst) {
|
|||
tight_loop_contents();
|
||||
}
|
||||
|
||||
uint32_t *tmdsbuf;
|
||||
uint32_t *tmdsbuf = NULL;
|
||||
while (inst->late_scanline_ctr > 0 && queue_try_remove_u32(&inst->q_tmds_valid, &tmdsbuf)) {
|
||||
// If we displayed this buffer then it would be in the wrong vertical
|
||||
// position on-screen. Just pass it back.
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ struct dvi_inst {
|
|||
queue_t q_colour_valid;
|
||||
queue_t q_colour_free;
|
||||
|
||||
bool started;
|
||||
volatile bool suspendflag;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
|
@ -60,10 +62,16 @@ void dvi_init(struct dvi_inst *inst, uint spinlock_tmds_queue, uint spinlock_col
|
|||
// whichever core called this function. Registers an exclusive IRQ handler.
|
||||
void dvi_register_irqs_this_core(struct dvi_inst *inst, uint irq_num);
|
||||
|
||||
// Unregisters DVI irq callbacks for this core
|
||||
void dvi_unregister_irqs_this_core(struct dvi_inst *inst, uint irq_num);
|
||||
|
||||
// Start actually wiggling TMDS pairs. Call this once you have initialised the
|
||||
// DVI, have registered the IRQs, and are producing rendered scanlines.
|
||||
void dvi_start(struct dvi_inst *inst);
|
||||
|
||||
// Stops DVI pairs generations
|
||||
void dvi_stop(struct dvi_inst *inst);
|
||||
|
||||
// TMDS encode worker function: core enters and doesn't leave, but still
|
||||
// responds to IRQs. Repeatedly pop a scanline buffer from q_colour_valid,
|
||||
// TMDS encode it, and pass it to the tmds valid queue.
|
||||
|
|
|
|||
Loading…
Reference in a new issue