diff --git a/core/embed/io/display/fb_queue/fb_queue.c b/core/embed/io/display/fb_queue/fb_queue.c index a65e67e459..c4c7d32756 100644 --- a/core/embed/io/display/fb_queue/fb_queue.c +++ b/core/embed/io/display/fb_queue/fb_queue.c @@ -1,33 +1,48 @@ #ifdef KERNEL_MODE + +#include + #include "fb_queue.h" -int16_t fb_queue_get_for_copy(volatile frame_buffer_queue_t *queue) { - if (queue->entry[queue->wix] != FB_STATE_PREPARING) { +int16_t fb_queue_get_for_copy(frame_buffer_queue_t *queue) { + irq_key_t key = irq_lock(); + int16_t wix = queue->wix; + if (queue->entry[wix] != FB_STATE_PREPARING) { // No refresh needed as the frame buffer is not in // the state to be copied to the display + irq_unlock(key); return -1; } - return queue->wix; + irq_unlock(key); + return wix; } -int16_t fb_queue_get_for_write(volatile frame_buffer_queue_t *queue) { +int16_t fb_queue_get_for_write(frame_buffer_queue_t *queue) { frame_buffer_state_t state; // We have to wait if the buffer was passed for copying // to the interrupt handler do { + irq_key_t key = irq_lock(); state = queue->entry[queue->wix]; + irq_unlock(key); + } while (state == FB_STATE_READY || state == FB_STATE_COPYING); + irq_key_t key = irq_lock(); queue->entry[queue->wix] = FB_STATE_PREPARING; + irq_unlock(key); return queue->wix; } -int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue) { +int16_t fb_queue_get_for_transfer(frame_buffer_queue_t *queue) { + irq_key_t key = irq_lock(); + if (queue->rix >= FRAME_BUFFER_COUNT) { // This is an invalid state, and we should never get here + irq_unlock(key); return -1; } @@ -38,12 +53,15 @@ int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue) { case FB_STATE_COPYING: // Currently we are copying a data to the display. + + irq_unlock(key); return -1; break; case FB_STATE_READY: // Now it's proper time to copy the data to the display queue->entry[queue->rix] = FB_STATE_COPYING; + irq_unlock(key); return queue->rix; // NOTE: when copying is done, this queue slot is marked empty @@ -51,29 +69,36 @@ int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue) { default: // This is an invalid state, and we should never get here + irq_unlock(key); return -1; break; } } -bool fb_queue_set_done(volatile frame_buffer_queue_t *queue) { +bool fb_queue_set_done(frame_buffer_queue_t *queue) { + irq_key_t key = irq_lock(); if (queue->rix >= FRAME_BUFFER_COUNT) { // This is an invalid state, and we should never get here + irq_unlock(key); return false; } if (queue->entry[queue->rix] == FB_STATE_COPYING) { queue->entry[queue->rix] = FB_STATE_EMPTY; queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT; + irq_unlock(key); return true; } + irq_unlock(key); return false; } -bool fb_queue_set_switched(volatile frame_buffer_queue_t *queue) { +bool fb_queue_set_switched(frame_buffer_queue_t *queue) { + irq_key_t key = irq_lock(); if (queue->rix >= FRAME_BUFFER_COUNT) { // This is an invalid state, and we should never get here + irq_unlock(key); return false; } @@ -83,28 +108,35 @@ bool fb_queue_set_switched(volatile frame_buffer_queue_t *queue) { } queue->aix = queue->rix; queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT; + irq_unlock(key); return true; } + irq_unlock(key); return false; } -bool fb_queue_set_ready_for_transfer(volatile frame_buffer_queue_t *queue) { +bool fb_queue_set_ready_for_transfer(frame_buffer_queue_t *queue) { + irq_key_t key = irq_lock(); if (queue->wix >= FRAME_BUFFER_COUNT) { // This is an invalid state, and we should never get here + irq_unlock(key); return false; } if (queue->entry[queue->rix] == FB_STATE_PREPARING) { queue->entry[queue->rix] = FB_STATE_READY; queue->wix = (queue->wix + 1) % FRAME_BUFFER_COUNT; + irq_unlock(key); return true; } + irq_unlock(key); return false; } -void fb_queue_reset(volatile frame_buffer_queue_t *queue) { +void fb_queue_reset(frame_buffer_queue_t *queue) { + irq_key_t key = irq_lock(); // Reset the buffer queue so we can eventually continue // safely in thread mode queue->wix = 0; @@ -112,17 +144,21 @@ void fb_queue_reset(volatile frame_buffer_queue_t *queue) { for (int i = 0; i < FRAME_BUFFER_COUNT; i++) { queue->entry[i] = FB_STATE_EMPTY; } + irq_unlock(key); } -bool fb_queue_is_processed(volatile frame_buffer_queue_t *queue) { +bool fb_queue_is_processed(frame_buffer_queue_t *queue) { + irq_key_t key = irq_lock(); for (int i = 0; i < FRAME_BUFFER_COUNT; i++) { frame_buffer_state_t state = queue->entry[i]; if (state == FB_STATE_READY || (state == FB_STATE_COPYING && i != queue->aix)) { + irq_unlock(key); return false; } } + irq_unlock(key); return true; } diff --git a/core/embed/io/display/fb_queue/fb_queue.h b/core/embed/io/display/fb_queue/fb_queue.h index 53240f50ee..f189d940c8 100644 --- a/core/embed/io/display/fb_queue/fb_queue.h +++ b/core/embed/io/display/fb_queue/fb_queue.h @@ -43,7 +43,7 @@ typedef enum { typedef struct { // Queue entries - volatile frame_buffer_state_t entry[FRAME_BUFFER_COUNT]; + frame_buffer_state_t entry[FRAME_BUFFER_COUNT]; // Active index // (accessed & updated in the context of the interrupt handlers int16_t aix; @@ -56,18 +56,29 @@ typedef struct { } frame_buffer_queue_t; -int16_t fb_queue_get_for_copy(volatile frame_buffer_queue_t *queue); +// Get the frame buffer index for copying to display +// Call from main thread only +int16_t fb_queue_get_for_copy(frame_buffer_queue_t *queue); -int16_t fb_queue_get_for_write(volatile frame_buffer_queue_t *queue); +// Get the frame buffer index for writing +// Call from main thread only +int16_t fb_queue_get_for_write(frame_buffer_queue_t *queue); -int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue); +// Get the frame buffer index for transfer +int16_t fb_queue_get_for_transfer(frame_buffer_queue_t *queue); -bool fb_queue_set_done(volatile frame_buffer_queue_t *queue); +// Mark the frame buffer as done, thus no longer used +bool fb_queue_set_done(frame_buffer_queue_t *queue); -bool fb_queue_set_switched(volatile frame_buffer_queue_t *queue); +// Mark the frame buffer as switched, thus actively used by display +bool fb_queue_set_switched(frame_buffer_queue_t *queue); -bool fb_queue_set_ready_for_transfer(volatile frame_buffer_queue_t *queue); +// Mark the frame buffer as ready to be copied to the display +// Call from main thread only +bool fb_queue_set_ready_for_transfer(frame_buffer_queue_t *queue); -void fb_queue_reset(volatile frame_buffer_queue_t *queue); +// Reset the queue state +void fb_queue_reset(frame_buffer_queue_t *queue); -bool fb_queue_is_processed(volatile frame_buffer_queue_t *queue); +// Check if all frame buffers are processed +bool fb_queue_is_processed(frame_buffer_queue_t *queue); diff --git a/core/embed/io/display/st-7789/display_fb.c b/core/embed/io/display/st-7789/display_fb.c index 3532785301..d67c3d6f03 100644 --- a/core/embed/io/display/st-7789/display_fb.c +++ b/core/embed/io/display/st-7789/display_fb.c @@ -210,26 +210,8 @@ void display_refresh(void) { mpu_set_active_fb(NULL, 0); #ifndef BOARDLOADER - if (is_mode_exception()) { - // Disable scheduling of any new background copying - NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); - // Wait for next TE signal. During this time the - // display might be updated in the background - wait_for_te_signal(); - // Stop any background copying even if it is not finished yet - bg_copy_abort(); - // Copy the frame buffer to the display manually - copy_fb_to_display(fb_idx); - // Reset the buffer queue so we can eventually continue - // safely in thread mode - fb_queue_reset(&drv->queue); - - // Enable normal processing again - NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM); - } else { - // Mark the buffer ready to switch to - fb_queue_set_ready_for_transfer(&drv->queue); - } + // Mark the buffer ready to switch to + fb_queue_set_ready_for_transfer(&drv->queue); #else // BOARDLOADER wait_for_te_signal(); diff --git a/core/embed/io/display/st-7789/display_internal.h b/core/embed/io/display/st-7789/display_internal.h index 7af7934ba1..0aaac241f5 100644 --- a/core/embed/io/display/st-7789/display_internal.h +++ b/core/embed/io/display/st-7789/display_internal.h @@ -19,7 +19,7 @@ typedef struct { // Framebuffer queue // (accessed & updated in the context of the main thread // and the interrupt context) - volatile frame_buffer_queue_t queue; + frame_buffer_queue_t queue; #endif // Current display orientation (0, 90, 180, 270)