ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_mipi_csi_irq.c
Go to the documentation of this file.
1
29
30#include <stdint.h>
31
32#include "ra8_attributes.h"
33#include "ra8_check.h"
34#include "ra8_err.h"
35#include "ra8_hal_internal.h"
36#include "ra8_log.h"
37#include "ra8_mipi_csi.h"
38#include "ra8_mipi_csi_regs.h"
39#include "ra8_mstp.h"
40
47static const char* s_tag = "MIPI_CSI";
48
58typedef enum : uint16_t {
61
68
74static void* s_mipi_csi_ctx;
75
82
88static void* s_mipi_csi_dl_ctx;
89
96
102static void* s_mipi_csi_vc_ctx;
103
110
116static void* s_mipi_csi_pm_ctx;
117
125
133
142
150
158
166
167/* =============================================================================
168 * Interrupt path (handlers + dispatchers)
169 * =============================================================================
170 */
171
198
205
212
219
226
229{
230 /* HUM Ch 66.3.12 "RXST : Receive Status Register" p 3944 */
231 const uint32_t rxst = *ra8_mipi_csi_reg32(k_ra8_mipi_csi_off_rxst);
232 /* HUM Ch 66.3.13 "RXSC : Receive Status Clear Register" p 3945
233 * Clear sticky RACTDET so the next edge can be observed. */
235
237 void* const ctx = s_mipi_csi_ctx;
238 if (fn != nullptr) {
239 fn(ctx, rxst);
240 }
241}
242
245{
246 /* HUM Ch 66.3.9 "MIST : Module Interrupt Status" p 3941 */
247 const uint32_t mist = *ra8_mipi_csi_reg32(k_ra8_mipi_csi_off_mist);
248
249 /* HUM Ch 66.3.15 "DLST(N) : Data Lane N Status" p 3946 */
250 const uint32_t dlst0 = *ra8_mipi_csi_reg32(k_ra8_mipi_csi_off_dlst0);
251 const uint32_t dlst1 = *ra8_mipi_csi_reg32(k_ra8_mipi_csi_off_dlst1);
252
253 /* HUM Ch 66.3.16 "DLSC(N) : Data Lane N Status Clear" p 3947
254 * ULP bit (24) is RO; mask it out before W1C. */
257
259 void* const ctx = s_mipi_csi_dl_ctx;
260 if (fn == nullptr) {
261 return;
262 }
263
264 if ((mist & k_ra8_mipi_csi_mist_dl0s_mask) != 0UL) {
265 fn(ctx, 0U, dlst0);
266 }
267 if ((mist & k_ra8_mipi_csi_mist_dl1s_mask) != 0UL) {
268 fn(ctx, 1U, dlst1);
269 }
270}
271
274{
275 /* HUM Ch 66.3.9 "MIST : Module Interrupt Status" p 3941 */
276 const uint32_t mist = *ra8_mipi_csi_reg32(k_ra8_mipi_csi_off_mist);
277 const uint32_t vc_flags = (mist & k_ra8_mipi_csi_mist_vc_mask) >> k_ra8_mipi_csi_mist_vc_shift;
278
280 void* const ctx = s_mipi_csi_vc_ctx;
281
282 uint32_t generic_errors = 0UL;
283 for (uint8_t vc = 0U; vc < (uint8_t)k_ra8_mipi_csi_vc_count; ++vc) {
284 if ((vc_flags & ((uint32_t)1U << vc)) == 0UL) {
285 continue;
286 }
287 /* HUM Ch 66.3.18 "VCST(M) : Virtual Channel M Status" p 3949 */
290 const uint32_t vcst = *ra8_mipi_csi_reg32(st_off);
291
292 /* HUM Ch 66.3.19 "VCSC(M) : Virtual Channel M Status Clear" p 3951 */
294
295 /* MLF + ECD apply to every VC because the offending packet's VC
296 * cannot be determined. Surface them once at the end. */
297 generic_errors |= vcst & k_ra8_mipi_csi_vcst_generic_err_mask;
298 const uint32_t vc_specific = vcst & ~k_ra8_mipi_csi_vcst_generic_err_mask;
299
300 if (fn != nullptr) {
301 fn(ctx, vc, vc_specific);
302 }
303
304 /* Surface ECC + CRC errors to the dedicated error handler if any
305 * are set in this VC's snapshot. HUM Ch 66.3.18 p 3949. */
307 if (err_fn != nullptr) {
308 const uint32_t err_bits =
311 if (err_bits != 0UL) {
312 const ra8_mipi_csi_error_report_t report = {
313 .vc = vc,
314 .ecc_corrected = ((vcst & k_ra8_mipi_csi_vcst_ecc_mask) != 0UL),
315 .ecc_two_bit_error = ((vcst & k_ra8_mipi_csi_vcst_ecd_mask) != 0UL),
316 .crc_error = ((vcst & k_ra8_mipi_csi_vcst_crc_mask) != 0UL),
317 .raw_vcst = vcst,
318 };
319 err_fn(s_mipi_csi_err_ctx, &report);
320 }
321 }
322 }
323
324 if (fn != nullptr) {
325 fn(ctx, (uint8_t)k_ra8_mipi_csi_vc_invalid_idx, generic_errors);
326 }
327}
328
331{
332 /* HUM Ch 66.3.21 "PMST : Power Management Status" p 3954 */
333 const uint32_t pmst = *ra8_mipi_csi_reg32(k_ra8_mipi_csi_off_pmst);
334 /* HUM Ch 66.3.22 "PMSC : Power Management Status Clear" p 3955
335 * Only [7:0] are W1C; the upper state bits are RO. */
337
339 void* const ctx = s_mipi_csi_pm_ctx;
340 if (fn != nullptr) {
341 fn(ctx, pmst);
342 }
343}
344
347{
348 /* HUM Ch 66.3.25 "GSST : Generic Short Packet Status" p 3957 */
349 const uint32_t gsst = *ra8_mipi_csi_reg32(k_ra8_mipi_csi_off_gsst);
350 /* HUM Ch 66.3.26 "GSSC : Generic Short Packet Status Clear" p 3958
351 * Clear GOV so the next overflow can be observed. */
353
355 void* const ctx = s_mipi_csi_gst_ctx;
356 if (fn != nullptr) {
357 fn(ctx, gsst);
358 }
359}
360
362{
363 s_mipi_csi_fn = nullptr;
364 s_mipi_csi_ctx = nullptr;
365 s_mipi_csi_dl_fn = nullptr;
366 s_mipi_csi_dl_ctx = nullptr;
367 s_mipi_csi_vc_fn = nullptr;
368 s_mipi_csi_vc_ctx = nullptr;
369 s_mipi_csi_pm_fn = nullptr;
370 s_mipi_csi_pm_ctx = nullptr;
371 s_mipi_csi_gst_fn = nullptr;
372 s_mipi_csi_gst_ctx = nullptr;
373}
374
375/* =============================================================================
376 * Sweep 6: per-VC framing helpers + error reporting
377 * =============================================================================
378 */
379
380/* Translate a public ::ra8_mipi_csi_data_format_t to its DT bit -- see surrounding code and HUM citations. */
382static ra8_err_t
383internal_format_to_bit(ra8_mipi_csi_data_format_t format, bool* is_high, uint32_t* bit)
384{
385 switch (format) {
387 *is_high = false;
388 *bit = 0UL;
389 return k_ra8_ok;
390 }
392 *is_high = false;
394 return k_ra8_ok;
395 }
397 *is_high = false;
399 return k_ra8_ok;
400 }
402 *is_high = true;
404 return k_ra8_ok;
405 }
407 *is_high = true;
409 return k_ra8_ok;
410 }
413 default: {
414 /* RAW10 / YUV420 are not exposed by RA8D2 DTEL/DTEH. */
416 }
417 }
418}
419
420/* Recompute DTEL/DTEH from the per-VC format shadow -- see surrounding code and HUM citations. */
423{
424 uint32_t low = 0UL;
425 uint32_t high = 0UL;
426 for (uint8_t vc = 0U; vc < (uint8_t)k_ra8_mipi_csi_vc_count; ++vc) {
427 bool is_high = false;
428 uint32_t bit = 0UL;
430 /* Unknown shadow values would have been rejected by setter -- safe. */
431 (void)internal_format_to_bit(fmt, &is_high, &bit);
432 if (is_high) {
433 high |= bit;
434 } else {
435 low |= bit;
436 }
437 }
438 /* HUM Ch 66.3.10 "DTEL : Receive Data Type Enable Low" p 3943 */
440 /* HUM Ch 66.3.11 "DTEH : Receive Data Type Enable High" p 3944 */
442}
443
445{
446 if (vc_mask == 0U) {
447 ra8_log_error(s_tag, "set_virtual_channels: empty mask rejected");
449 }
450 for (uint8_t vc = 0U; vc < (uint8_t)k_ra8_mipi_csi_vc_count; ++vc) {
451 /* HUM Ch 66.3.20 "VCIE(M) : Virtual Channel M Interrupt Enable" p 3952 */
453 const bool keep = ((vc_mask & ((uint16_t)1U << vc)) != 0U);
454 if (keep) {
455 /* If we previously masked this VC off, restore the saved enable.
456 * Otherwise leave whatever the caller has currently programmed. */
457 const uint32_t saved = s_mipi_csi_vcie_saved[vc];
458 if (saved != 0UL) {
459 *ra8_mipi_csi_reg32(off) = saved;
460 s_mipi_csi_vcie_saved[vc] = 0UL;
461 }
462 } else {
463 const uint32_t cur = *ra8_mipi_csi_reg32(off);
464 if (cur != 0UL) {
465 s_mipi_csi_vcie_saved[vc] = cur;
466 }
467 *ra8_mipi_csi_reg32(off) = 0UL;
468 }
469 }
470 return k_ra8_ok;
471}
472
474{
475 if (vc >= (uint8_t)k_ra8_mipi_csi_vc_count) {
477 }
478 bool is_high = false;
479 uint32_t bit = 0UL;
480 const ra8_err_t lookup = internal_format_to_bit(format, &is_high, &bit);
481 if (lookup != k_ra8_ok) {
482 return lookup;
483 }
484 s_mipi_csi_vc_format[vc] = (uint8_t)format;
486 return k_ra8_ok;
487}
488
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_ISR_SAFE
The function is callable from interrupt context.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
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
Cross-translation-unit private helpers shared inside ra8_hal.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
MIPI CSI-2 receiver HAL driver – public API.
static void * s_mipi_csi_pm_ctx
Caller context forwarded to the PM callback.
static ra8_mipi_csi_error_fn_t s_mipi_csi_err_fn
Callback invoked from dispatch_vc when an ECC/CRC error is decoded out of a VCST snapshot.
static ra8_mipi_csi_event_fn_t s_mipi_csi_fn
Currently-attached receive event callback.
static void * s_mipi_csi_dl_ctx
Caller context forwarded to the data-lane callback.
ra8_err_t ra8_mipi_csi_set_data_format(uint8_t vc, ra8_mipi_csi_data_format_t format)
Select the CSI-2 payload format the receiver should accept on a specific virtual channel.
static void * s_mipi_csi_ctx
Caller context forwarded to the receive event callback.
static ra8_mipi_csi_pm_event_fn_t s_mipi_csi_pm_fn
Currently-attached power-management callback.
ra8_err_t ra8_mipi_csi_attach_short_packet_handler(ra8_mipi_csi_short_event_fn_t fn, void *ctx)
Attach the short-packet FIFO callback (MIPI CSI GST vector).
ra8_err_t ra8_mipi_csi_attach_error_handler(ra8_mipi_csi_error_fn_t fn, void *ctx)
Register a callback invoked on ECC / CRC error reports.
static ra8_mipi_csi_dl_event_fn_t s_mipi_csi_dl_fn
Currently-attached data-lane callback.
static ra8_err_t internal_format_to_bit(ra8_mipi_csi_data_format_t format, bool *is_high, uint32_t *bit)
void ra8_mipi_csi_dispatch(void)
ISR-side dispatcher for the receive vector.
static void * s_mipi_csi_gst_ctx
Caller context forwarded to the short-packet callback.
ra8_err_t ra8_mipi_csi_attach_pm_handler(ra8_mipi_csi_pm_event_fn_t fn, void *ctx)
Attach the power-management callback (MIPI CSI PM vector).
ra8_err_t ra8_mipi_csi_set_virtual_channels(uint16_t vc_mask)
Filter which CSI-2 virtual channels the receiver will surface.
static void * s_mipi_csi_vc_ctx
Caller context forwarded to the per-VC callback.
static uint8_t s_mipi_csi_vc_format[k_ra8_mipi_csi_vc_count]
Software shadow of the per-VC payload format selection published by ra8_mipi_csi_set_data_format.
ra8_mipi_csi_irq_intern_t
Internal limits used by this translation unit only.
@ k_ra8_mipi_csi_vc_invalid_idx
Sentinel for "generic" event.
static void internal_recompute_dt_filter(void)
void ra8_mipi_csi_dispatch_pm(void)
ISR-side dispatcher for the power-management vector.
static void * s_mipi_csi_err_ctx
Caller context forwarded to the error callback.
ra8_err_t ra8_mipi_csi_attach_handler(ra8_mipi_csi_event_fn_t fn, void *ctx)
Attach the module-level CSI event callback.
ra8_err_t ra8_mipi_csi_attach_vc_handler(ra8_mipi_csi_vc_event_fn_t fn, void *ctx)
Attach the per-VC callback (MIPI CSI VC vector).
void ra8_mipi_csi_dispatch_short_packet(void)
ISR-side dispatcher for the generic-short-packet vector.
void priv_ra8_mipi_csi_detach_all_handlers(void)
Detach every MIPI CSI-2 receiver callback (module / data-lane / virtual-channel / power-management / ...
void ra8_mipi_csi_dispatch_vc(void)
ISR-side dispatcher for the per-VC vector.
static uint32_t s_mipi_csi_vcie_saved[k_ra8_mipi_csi_vc_count]
Snapshot of VCIE(M) at the time the last ra8_mipi_csi_set_virtual_channels call masked it off.
void ra8_mipi_csi_dispatch_dl(void)
ISR-side dispatcher for the data-lane vector.
ra8_err_t ra8_mipi_csi_attach_dl_handler(ra8_mipi_csi_dl_event_fn_t fn, void *ctx)
Attach the per-data-lane callback (MIPI CSI DL vector).
static ra8_mipi_csi_short_event_fn_t s_mipi_csi_gst_fn
Currently-attached short-packet FIFO callback.
static ra8_mipi_csi_vc_event_fn_t s_mipi_csi_vc_fn
Currently-attached per-VC callback.
MIPI CSI-2 Receiver register layout for the RA8D2 (HUM Ch 66).
@ k_ra8_mipi_csi_vc_count
Number of virtual channels.
@ k_ra8_mipi_csi_dteh_rgb888_mask
[4] RGB888.
@ k_ra8_mipi_csi_dteh_raw8_mask
[10] RAW8.
@ k_ra8_mipi_csi_mist_vc_mask
[31:16] per-VC src.
@ k_ra8_mipi_csi_mist_dl0s_mask
[0] DL0 has IRQ src.
@ k_ra8_mipi_csi_mist_dl1s_mask
[1] DL1 has IRQ src.
@ k_ra8_mipi_csi_mist_vc_shift
VC mask shift.
ra8_mipi_csi_off_t
Absolute byte offsets into the MIPI CSI register window.
@ k_ra8_mipi_csi_off_vcst0
Virtual Channel 0 Status.
@ k_ra8_mipi_csi_off_dtel
Receive Data-Type Enable Low.
@ k_ra8_mipi_csi_off_dlsc1
Data Lane 1 Status Clear.
@ k_ra8_mipi_csi_off_vcie0
Virtual Channel 0 IRQ Enable.
@ k_ra8_mipi_csi_off_gsst
Generic Short Packet Status.
@ k_ra8_mipi_csi_off_vcsc0
Virtual Channel 0 Status Clear.
@ k_ra8_mipi_csi_off_dlst0
Data Lane 0 Status.
@ k_ra8_mipi_csi_off_rxst
Receive Status.
@ k_ra8_mipi_csi_off_gssc
Generic Short Packet Stat Clear.
@ k_ra8_mipi_csi_off_mist
Module Interrupt Status.
@ k_ra8_mipi_csi_off_dlsc0
Data Lane 0 Status Clear.
@ k_ra8_mipi_csi_off_dteh
Receive Data-Type Enable High.
@ k_ra8_mipi_csi_off_pmst
Power-Management Status.
@ k_ra8_mipi_csi_off_dlst1
Data Lane 1 Status.
@ k_ra8_mipi_csi_off_pmsc
Power-Management Status Clear.
@ k_ra8_mipi_csi_off_rxsc
Receive Status Clear.
@ k_ra8_mipi_csi_pmst_w1c_mask
Lower 8 bits W1C-clr.
@ k_ra8_mipi_csi_rxsc_ractdetc_mask
[17] clear RXDET.
@ k_ra8_mipi_csi_gssc_govc_mask
[4] clear GOV.
@ k_ra8_mipi_csi_dlsc_all_mask
All clearable.
@ k_ra8_mipi_csi_vcst_generic_err_mask
Errors that affect every VC because the VC of the offending packet cannot be determined (MLF + ECD).
@ k_ra8_mipi_csi_vcst_ecd_mask
[1] ECC 2-bit error.
@ k_ra8_mipi_csi_vcst_ecc_mask
[5] ECC 1-bit corr.
@ k_ra8_mipi_csi_vcst_crc_mask
[2] CRC error.
@ k_ra8_mipi_csi_vcsc_per_vc_mask
All per-VC W1C bits.
@ k_ra8_mipi_csi_dtel_yuv422_8_mask
[30] YUV 8b.
@ k_ra8_mipi_csi_dtel_yuv422_10_mask
[31] YUV 10b.
static ra8_mipi_csi_off_t ra8_mipi_csi_vc_off(ra8_mipi_csi_off_t base, uint8_t vc)
Compute the byte offset of a per-virtual-channel register.
static volatile uint32_t * ra8_mipi_csi_reg32(ra8_mipi_csi_off_t off)
Get a 32-bit volatile pointer to a register inside the MIPI CSI window.
void(* ra8_mipi_csi_dl_event_fn_t)(void *ctx, uint8_t lane, uint32_t dlst)
Data-lane IRQ callback.
void(* ra8_mipi_csi_event_fn_t)(void *ctx, uint32_t rxst_mask)
MIPI CSI receive-status event callback.
void(* ra8_mipi_csi_pm_event_fn_t)(void *ctx, uint32_t pmst)
Power-management IRQ callback.
void(* ra8_mipi_csi_short_event_fn_t)(void *ctx, uint32_t gsst)
Generic-short-packet FIFO IRQ callback.
ra8_mipi_csi_data_format_t
Per-virtual-channel payload format used by ra8_mipi_csi_set_data_format.
@ k_ra8_mipi_csi_format_off
Disable – accept nothing for VC.
@ k_ra8_mipi_csi_format_yuv422_10
CSI-2 DT 0x1F – YUV 4:2:2 10-bit.
@ k_ra8_mipi_csi_format_rgb888
CSI-2 DT 0x24 – RGB888.
@ k_ra8_mipi_csi_format_yuv420
CSI-2 DT 0x18 – YUV 4:2:0 8-bit.
@ k_ra8_mipi_csi_format_raw8
CSI-2 DT 0x2A – RAW8.
@ k_ra8_mipi_csi_format_yuv422_8
CSI-2 DT 0x1E – YUV 4:2:2 8-bit.
@ k_ra8_mipi_csi_format_raw10
CSI-2 DT 0x2B – RAW10 (FSP-only).
void(* ra8_mipi_csi_error_fn_t)(void *ctx, const ra8_mipi_csi_error_report_t *report)
Callback invoked when the receiver reports an ECC or CRC error.
void(* ra8_mipi_csi_vc_event_fn_t)(void *ctx, uint8_t vc, uint32_t vcst)
Per-virtual-channel IRQ callback.
Ref-counted Module Stop Control wrapper for the RA8D2.
One ECC / CRC error notification from the receiver.