rk27xx: clip LCD updates to the screen

lcd_update_rect() took the rect as given. One reaching past the screen
set a GRAM window off the panel, so the update showed nothing, and
built one DMA descriptor per line into scr_llp[LCD_HEIGHT] - past its
end for a rect taller than what is left of the screen. What follows
scr_llp in memory is the PCM driver's locks and then all_queues, the
kernel's queue list: a later broadcast posted to garbage.

invadrox asks for such a rect every frame. On a Samsung YP-CP3 nothing
of its playfield moved - aliens, bombs, the ship - and powering off
afterwards took a data abort in queue_post() from interrupt context.

Clip the rect to the screen, as other targets do, and do nothing if
nothing is left. Every rk27xx screen is a multiple of 4 pixels each
way, so aligning the clipped rect to 4 cannot take it past the edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I1f8bf865251859cd223e208a807c9a9da76a0ba0
This commit is contained in:
Marcin Bukat 2026-10-02 10:30:58 +02:00
parent 1488b30c62
commit 5c5dac2dbc

View file

@ -258,6 +258,27 @@ void lcd_update_rect(int x, int y, int width, int height)
{
int x_end, y_end, x_align, y_align;
/* Clip to the screen, as other targets do. A rect reaching past it
* set a GRAM window off the panel - nothing showed - and built more
* DMA descriptors than scr_llp[] holds, overwriting what follows it
* in memory: the kernel's queue list among it. */
if (x < 0)
{
width += x;
x = 0;
}
if (y < 0)
{
height += y;
y = 0;
}
if (width > LCD_WIDTH - x)
width = LCD_WIDTH - x;
if (height > LCD_HEIGHT - y)
height = LCD_HEIGHT - y;
if (width <= 0 || height <= 0)
return;
/* min alowed transfer seems to be 4x4 pixels */
x_align = x & 3;
y_align = y & 3;