ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_glcdc_layer.c
Go to the documentation of this file.
1
23
24#include <stdint.h>
25
26#include "ra8_attributes.h"
27#include "ra8_check.h"
28#include "ra8_err.h"
29#include "ra8_glcdc.h"
30#include "ra8_glcdc_regs.h"
31#include "ra8_log.h"
32
33static const char* s_tag = "GLCDC";
34
35/* =============================================================================
36 * Local constants
37 *
38 * Private enum copies of the GLCDC field shifts / masks this translation
39 * unit needs. They mirror the matching definitions in ra8_glcdc.c verbatim
40 * (TU-local enum constants, not linkable symbols, so duplication is safe).
41 * =============================================================================
42 */
43
53
54typedef enum : uint16_t {
57
58typedef enum : uint32_t {
62
70
71/* AB7.ARCDEF[23:16] alpha constants. */
72typedef enum : uint32_t {
75
76/* OUT_SET.FORMAT[1:0] / FLM6.FORMAT codes for RGB565 framebuffers. */
77typedef enum : uint32_t {
80
81/* =============================================================================
82 * Layer 2 (background-image) configuration
83 *
84 * Mirrors FSP `r_glcdc_graphics_layer_set` register order:
85 * FLM6 (format) -> FLM2 (base) -> FLM3 (line stride) ->
86 * FLM5 (datanum/lnnum) -> AB3 (H size+pos) -> AB2 (V size+pos) ->
87 * AB5 / AB4 (alpha-area H/V) -> AB7 (default alpha) -> AB1 (DISPSEL).
88 * =============================================================================
89 */
90
92{
93 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
94
95 /* HUM Ch 63 "GR2_FLM6.FORMAT" p 3744 */
97
98 /* HUM Ch 63 "GR2_FLM2.BASE" p 3744 */
100
101 /* HUM Ch 63 "GR2_FLM3.LNOFF" p 3744 -- bytes between successive
102 * lines, sign-extended into bits [31:16]. */
104
105 /* HUM Ch 63 "GR2_FLM5.LNNUM/DATANUM" p 3744 */
107 ((uint32_t)cfg->height_px << k_ra8_glcdc_word_shift) | (uint32_t)cfg->width_px;
108
109 /* HUM Ch 63 "GR2_AB3.GRCHS/GRCHW" p 3744 */ /* horizontal pos + width. */
111 ((uint32_t)cfg->pos_x << k_ra8_glcdc_word_shift) | (uint32_t)cfg->width_px;
112
113 /* HUM Ch 63 "GR2_AB2.GRCVS/GRCVW" p 3744 */ /* vertical pos + height. */
115 ((uint32_t)cfg->pos_y << k_ra8_glcdc_word_shift) | (uint32_t)cfg->height_px;
116
117 /* HUM Ch 63 "GR2_AB5.ARCHS/ARCHW" p 3744 */ /* alpha-rect H. */
119 ((uint32_t)cfg->pos_x << k_ra8_glcdc_word_shift) | (uint32_t)cfg->width_px;
120
121 /* HUM Ch 63 "GR2_AB4.ARCVS/ARCVW" p 3744 */ /* alpha-rect V. */
123 ((uint32_t)cfg->pos_y << k_ra8_glcdc_word_shift) | (uint32_t)cfg->height_px;
124
125 /* HUM Ch 63 "GR2_AB7.ARCDEF" p 3744 */ /* constant alpha. */
127
128 /* HUM Ch 63 "GR2_AB1.DISPSEL" p 3744 */ /* default to "blend below". */
130
131 /* HUM Ch 63 "GR2_FLMRD.RENB" p 3744 */ /* enable framebuffer read. */
133
134 /* HUM Ch 63 "GR2.VEN" p 3744 */ /* request register update on VS. */
136
137 ra8_log_info_val(s_tag, "set_layer2 fb", cfg->framebuffer_addr);
138 return k_ra8_ok;
139}
140
141/* =============================================================================
142 * Layer 1 / Layer 2 blending
143 * =============================================================================
144 */
145
147{
148 uint32_t dispsel = 0U;
149 uint32_t arcon = 0U;
150
151 switch (mode) {
153 dispsel = (uint32_t)k_ra8_glcdc_dispsel_below;
154 arcon = 0U;
155 break;
156 }
157 case k_ra8_blend_normal: {
158 dispsel = (uint32_t)k_ra8_glcdc_dispsel_above;
159 arcon = 0U;
160 break;
161 }
162 case k_ra8_blend_alpha: {
163 dispsel = (uint32_t)k_ra8_glcdc_dispsel_above;
164 arcon = (uint32_t)k_ra8_glcdc_arcon_mask;
165 break;
166 }
167 default: {
169 }
170 }
171
172 /* HUM Ch 63 "GR1_AB1.DISPSEL/ARCON" p 3744 */ /* top-layer blend mode. */
173 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr1_ab1) = dispsel | arcon;
174
175 /* HUM Ch 63 "GR1_AB7.ARCDEF" p 3744 -- global alpha applied in
176 * k_ra8_blend_alpha mode. */
178 return k_ra8_ok;
179}
180
181/* =============================================================================
182 * Background colour
183 * =============================================================================
184 */
185
187{
188 /* BG_BGC is direct-write (not shadow-latched). Writing it mid-
189 * frame tears the panel horizontally. Sync to vblank by pulsing
190 * BG.EN.VEN and polling BG.EN.VEN to auto-clear (= VS just fired),
191 * then write BG_BGC during the vblank window so the next visible
192 * scan starts with the new colour. FSP polls BG.EN.VEN_b in
193 * exactly this way (see r_glcdc.c FSP_ERROR_RETURN checks). */
194 enum : uint32_t {
195 k_bg_en_ven = 1UL << 8,
196 k_ven_timeout = 0x40000UL,
197 };
198
199 uint32_t bg_en = *ra8_glcdc_reg32(k_ra8_glcdc_off_bg_en);
200 bg_en |= k_bg_en_ven;
202
203 for (uint32_t i = 0U; i < (uint32_t)k_ven_timeout; i++) {
204 if ((*ra8_glcdc_reg32(k_ra8_glcdc_off_bg_en) & k_bg_en_ven) == 0U) {
205 break;
206 }
207 }
208 /* Write BG_BGC during the vblank window we just polled into. */
209 /* HUM Ch 63 "BG_BGC" p 3763 */
211 return k_ra8_ok;
212}
213
235{
236 enum : uint32_t {
237 k_gr1_ven = 1UL << 0,
238 k_gr1_dispsel_lower = 3UL,
239 };
240 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr1_saddr) = (uint32_t)fb_addr;
243 /* Both GR layers use ON_LOWER (FSP's BLEND_ON_LOWER_LAYER) so they
244 * coexist in composition. With NON_TRANSPARENT (2) the chip
245 * empirically drops GR1 from the output once GR2 is also enabled. */
246 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr1_ab1) = k_gr1_dispsel_lower;
249 return k_ra8_ok;
250}
251
285{
286 enum : uint32_t {
287 k_gr2_ven = 1UL << 0,
288 /* Try several plausible CKON bit positions at once -- the HUM
289 * isn't in front of me and different RA parts have moved the
290 * bit around (0, 16, 24). Setting all three is safe: at most
291 * one is meaningful, the others land in reserved bits which
292 * the chip ignores. */
294 k_ab7_ckon = (1UL << 0) | (1UL << 16) | (1UL << 24),
296 k_ab1_arcon = 1UL << 12,
298 k_arcdef_op = ((uint32_t)k_glcdc_alpha_opaque << k_glcdc_shift_arcdef),
299 k_alpha_opaque_byte = 0xFFUL << 24,
300 k_rgb888_mask = 0x00FFFFFFUL,
301 k_ab9_transparent = 0x00000000UL,
302 };
303 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr2_ab8) = k_alpha_opaque_byte | (key_rgb888 & k_rgb888_mask);
304 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr2_ab9) = k_ab9_transparent;
305 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr2_ab7) = k_arcdef_op | k_ab7_ckon;
306 /* OR in ARCON without clobbering DISPSEL (already set by layer2_show). */
307 const uint32_t ab1 = *ra8_glcdc_reg32(k_ra8_glcdc_off_gr2_ab1);
308 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr2_ab1) = ab1 | k_ab1_arcon;
310 return k_ra8_ok;
311}
312
341 uint16_t panel_x,
342 uint16_t panel_y,
343 uint16_t fb_w,
344 uint16_t fb_h)
345{
346 enum : uint32_t {
347 k_gr2_ven = 1UL << 0,
348 k_gr2_dispsel_lower = 3UL,
349 };
350 /* HUM 63: GR2_FLM6.FORMAT[30:28] = 2 (RGB565). */
353 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr2_saddr) = (uint32_t)fb_addr;
354
355 const uint32_t line_bytes = (uint32_t)fb_w * (uint32_t)k_glcdc_bpp_rgb565;
357
358 const uint32_t datanum = (line_bytes / (uint32_t)k_glcdc_axi_burst_bytes) - 1U;
359 const uint32_t lnnum = (uint32_t)fb_h - 1U;
361
363 ((uint32_t)panel_x << k_glcdc_shift_high) | (uint32_t)fb_w;
365 ((uint32_t)panel_y << k_glcdc_shift_high) | (uint32_t)fb_h;
367 ((uint32_t)panel_y << k_glcdc_shift_high) | (uint32_t)fb_h;
369 ((uint32_t)panel_x << k_glcdc_shift_high) | (uint32_t)fb_w;
370
373 *ra8_glcdc_reg32(k_ra8_glcdc_off_gr2_ab1) = k_gr2_dispsel_lower;
376 return k_ra8_ok;
377}
378
379/* =============================================================================
380 * Double-buffered CLUT update
381 *
382 * GR[layer].CLUTINT.SEL selects the active plane (0 or 1). A new
383 * table is written into the *inactive* plane, then SEL is flipped
384 * so that hardware switches at the next vertical sync. Mirrors
385 * FSP `R_GLCDC_ClutEdit` / `R_GLCDC_ColorPaletteUpdate`.
386 * =============================================================================
387 */
388
390static volatile uint32_t* internal_clut_plane(uint8_t layer, uint8_t plane)
391{
392 uint16_t off;
393 if (layer == k_ra8_glcdc_layer1) {
394 off = (plane == 0U) ? (uint16_t)k_ra8_glcdc_off_gr1_clut0 : (uint16_t)k_ra8_glcdc_off_gr1_clut1;
395 } else {
396 off = (plane == 0U) ? (uint16_t)k_ra8_glcdc_off_gr2_clut0 : (uint16_t)k_ra8_glcdc_off_gr2_clut1;
397 }
398 return (volatile uint32_t*)(k_ra8_glcdc_base_addr + off);
399}
400
401/* internal_clutint_reg -- see header for full description. */
403static volatile uint32_t* internal_clutint_reg(uint8_t layer)
404{
405 if (layer == k_ra8_glcdc_layer1) {
407 }
409}
410
412 const uint32_t* clut,
413 uint32_t entries,
414 bool swap_now)
415{
416 RA8_CHECK_NULL_PTR(clut, s_tag, "clut must not be nullptr");
417 if (layer >= (uint8_t)k_ra8_glcdc_layer_count) {
419 }
420 if ((entries == 0U) || (entries > (uint32_t)k_ra8_glcdc_clut_entries)) {
422 }
423
424 /* HUM Ch 63 "GR[n]_CLUTINT.SEL" p 3744 -- pick the *inactive*
425 * plane (FSP shadow-buffer pattern). */
426 volatile uint32_t* clutint = internal_clutint_reg(layer);
427 const uint32_t active =
428 ((*clutint) & (uint32_t)k_ra8_glcdc_clutsel_mask) >> k_ra8_glcdc_clutsel_shift;
429 const uint8_t target_plane = (active != 0U) ? (uint8_t)0U : (uint8_t)1U;
430
431 /* HUM Ch 63 "GR[n]_CLUT[plane]" p 3744 */ /* write inactive plane. */
432 volatile uint32_t* dst = internal_clut_plane(layer, target_plane);
433 for (uint32_t i = 0U; i < entries; ++i) {
434 dst[i] = clut[i];
435 }
436
437 if (swap_now) {
438 /* HUM Ch 63 "GR[n]_CLUTINT.SEL" p 3744 */ /* flip on next VS. */
439 const uint32_t cleared = (*clutint) & ~(uint32_t)k_ra8_glcdc_clutsel_mask;
440 *clutint = cleared | ((uint32_t)target_plane << k_ra8_glcdc_clutsel_shift);
441 }
442 return k_ra8_ok;
443}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
ra8_glcdc_layout_priv_t
Definition ra8_glcdc.c:337
@ k_glcdc_shift_arcdef
GLCDC shift arcdef.
Definition ra8_glcdc.c:342
@ k_glcdc_shift_high
GLCDC shift high.
Definition ra8_glcdc.c:338
@ k_glcdc_axi_burst_bytes
GLCDC axi burst bytes.
Definition ra8_glcdc.c:343
@ k_glcdc_bpp_rgb565
GLCDC bpp rgb565.
Definition ra8_glcdc.c:344
@ k_glcdc_shift_flm6_fmt
GLCDC shift flm6 fmt.
Definition ra8_glcdc.c:339
ra8_glcdc_out_set_fmt_t
Definition ra8_glcdc.c:375
@ k_glcdc_out_set_rgb565
GLCDC out set rgb565.
Definition ra8_glcdc.c:378
ra8_glcdc_clut_const_t
Definition ra8_glcdc.c:79
@ k_ra8_glcdc_clut_entries
Entries per CLUT plane.
Definition ra8_glcdc.c:80
ra8_glcdc_priv_const_t
Definition ra8_glcdc.c:66
@ k_ra8_glcdc_word_shift
16-bit field shift.
Definition ra8_glcdc.c:74
@ k_ra8_glcdc_dispsel_above
AB1.DISPSEL = upper layer.
Definition ra8_glcdc.c:70
@ k_ra8_glcdc_clutsel_shift
CLUTINT.SEL bit position.
Definition ra8_glcdc.c:72
@ k_ra8_glcdc_layer_count
Number of graphics layers.
Definition ra8_glcdc.c:67
@ k_ra8_glcdc_arcdef_shift
AB7.ARCDEF bit shift.
Definition ra8_glcdc.c:71
@ k_ra8_glcdc_dispsel_below
AB1.DISPSEL = lower layer.
Definition ra8_glcdc.c:69
@ k_ra8_glcdc_layer1
Layer index for GR[0].
Definition ra8_glcdc.c:68
ra8_glcdc_alpha_priv_t
Definition ra8_glcdc.c:365
@ k_glcdc_alpha_opaque
Fully opaque (constant alpha).
Definition ra8_glcdc.c:366
ra8_glcdc_priv_mask_t
Definition ra8_glcdc.c:83
@ k_ra8_glcdc_clutsel_mask
CLUTINT.SEL bit mask.
Definition ra8_glcdc.c:84
@ k_ra8_glcdc_arcon_mask
AB1.ARCON bit mask.
Definition ra8_glcdc.c:85
Graphics LCD Controller driver (two-layer with alpha blending).
ra8_glcdc_blend_mode_t
Compositing mode between Graphics 1 and Graphics 2.
Definition ra8_glcdc.h:89
@ k_ra8_blend_alpha
Per-pixel + global alpha blend (DISPSEL=10+AR).
Definition ra8_glcdc.h:92
@ k_ra8_blend_overwrite
Layer 1 fully covers layer 2 (DISPSEL=01).
Definition ra8_glcdc.h:90
@ k_ra8_blend_normal
Layer 1 over layer 2, no alpha (DISPSEL=10).
Definition ra8_glcdc.h:91
ra8_err_t ra8_glcdc_layer2_chroma_key_enable(uint32_t key_rgb888)
Enable chroma-key transparency on GLCDC graphics layer 2.
ra8_err_t ra8_glcdc_set_layer2(const ra8_glcdc_layer2_cfg_t *cfg)
Configure the Graphics 2 (background-image) layer.
ra8_err_t ra8_glcdc_set_background_color(uint32_t argb)
Set the panel-wide background colour shown where neither layer covers a pixel.
ra8_err_t ra8_glcdc_layer1_show(uintptr_t fb_addr)
Implementation of ra8_glcdc_layer1_show.
ra8_err_t ra8_glcdc_set_clut_double_buffered(uint8_t layer, const uint32_t *clut, uint32_t entries, bool swap_now)
Update a CLUT plane double-buffered, optionally swapping on the next vsync.
static volatile uint32_t * internal_clut_plane(uint8_t layer, uint8_t plane)
ra8_err_t ra8_glcdc_set_blend(ra8_glcdc_blend_mode_t mode, uint8_t global_alpha)
Set the layer-1-over-layer-2 blend mode and global alpha.
static volatile uint32_t * internal_clutint_reg(uint8_t layer)
ra8_err_t ra8_glcdc_layer2_show(uintptr_t fb_addr, uint16_t panel_x, uint16_t panel_y, uint16_t fb_w, uint16_t fb_h)
Make graphics layer 2 visible at the given panel position.
Graphics LCD Controller (GLCDC) register layout for the RA8D2.
@ k_ra8_glcdc_off_gr2_ab5
GR[1].AB5: alpha rect H size+pos.
@ k_ra8_glcdc_off_gr2_ab2
GR[1].AB2: graphics V size + pos.
@ k_ra8_glcdc_off_gr2_ab9
GR[1].AB9: chroma-key replace col.
@ k_ra8_glcdc_off_gr2_saddr
GR[1].FLM2.BASE.
@ k_ra8_glcdc_off_gr1_ab1
GR[0].AB1: alpha blend ctrl 1.
@ k_ra8_glcdc_off_bg_en
BG.EN: module enable.
@ k_ra8_glcdc_off_gr2_ab1
GR[1].AB1.
@ k_ra8_glcdc_off_gr2_clut1
GR2_CLUT1[256] @ 0x0C00.
@ k_ra8_glcdc_off_gr2_ab8
GR[1].AB8: chroma-key key colour.
@ k_ra8_glcdc_off_gr1_saddr
GR[0].FLM2.BASE: framebuffer addr.
@ k_ra8_glcdc_off_gr1_ab7
GR[0].AB7: chroma-key on, def alf.
@ k_ra8_glcdc_off_gr2_clutint
GR[1].CLUTINT.
@ k_ra8_glcdc_off_gr1_en
GR[0].VEN: register update ctrl.
@ k_ra8_glcdc_off_gr2_ab4
GR[1].AB4: alpha rect V size+pos.
@ k_ra8_glcdc_off_gr2_clut0
GR2_CLUT0[256] @ 0x0800.
@ k_ra8_glcdc_off_gr2_flmrd
GR[1].FLMRD.
@ k_ra8_glcdc_off_gr2_line
GR[1].FLM5.
@ k_ra8_glcdc_off_gr2_en
GR[1].VEN.
@ k_ra8_glcdc_off_gr1_clutint
GR[0].CLUTINT: CLUT swap + line.
@ k_ra8_glcdc_off_gr1_clut1
GR1_CLUT1[256] @ 0x0400.
@ k_ra8_glcdc_off_gr2_fmt
GR[1].FLM6.FORMAT.
@ k_ra8_glcdc_off_gr2_size
GR[1].AB3: graphics H size + pos.
@ k_ra8_glcdc_off_gr1_clut0
GR1_CLUT0[256] @ 0x0000.
@ k_ra8_glcdc_off_gr1_flmrd
GR[0].FLMRD: frame buffer read en.
@ k_ra8_glcdc_off_bg_bgc
BG.BGC: background colour.
@ k_ra8_glcdc_off_gr2_ab7
GR[1].AB7: chroma-key on, def alf.
@ k_ra8_glcdc_off_gr2_flm3
GR[1].FLM3.
static volatile uint32_t * ra8_glcdc_reg32(ra8_glcdc_block_off_t offset)
Pointer to a 32-bit register inside the GLCDC block.
@ k_ra8_glcdc_base_addr
RA8 GLCDC base address.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
Configuration for the background-image (Graphics 2) layer.
Definition ra8_glcdc.h:74
uint32_t framebuffer_addr
Layer-2 framebuffer base address.
Definition ra8_glcdc.h:75
uint16_t height_px
Layer-2 image height (lines).
Definition ra8_glcdc.h:78
uint16_t pos_x
Top-left X within the panel viewport.
Definition ra8_glcdc.h:79
uint16_t width_px
Layer-2 image width (pixels).
Definition ra8_glcdc.h:77
uint16_t pos_y
Top-left Y within the panel viewport.
Definition ra8_glcdc.h:80
uint32_t line_stride_bytes
Bytes between successive scan lines.
Definition ra8_glcdc.h:76
ra8_glcdc_pixel_fmt_t format
Pixel format code (FLM6.FORMAT).
Definition ra8_glcdc.h:81
uint8_t alpha
Constant alpha 0..255 (AB7.ARCDEF).
Definition ra8_glcdc.h:82