1 /******************************************************************************
2 *
3 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4 * Analog Devices, Inc.),
5 * Copyright (C) 2023-2024 Analog Devices, Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ******************************************************************************/
20
21 #ifdef __riscv
22 #warning "CSI2 drivers not supported on RISC-V"
23 #else
24
25 /* **** Includes **** */
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include "mxc_device.h"
30 #include "mxc_assert.h"
31 #include "mxc_pins.h"
32 #include "mxc_sys.h"
33 #include "mxc_delay.h"
34 #include "csi2.h"
35 #include "csi2_reva.h"
36 #include "nvic_table.h"
37 #include "dma.h"
38 #include "dma_reva.h"
39 #include "mcr_regs.h"
40
41 /* **** Definitions **** */
42
43 #define MXC_CSI2_REVA_CTRL_ERRINT_FL \
44 (MXC_F_CSI2_REVA_RX_EINT_CTRL_IE_EECC2 | MXC_F_CSI2_REVA_RX_EINT_CTRL_IE_EECC1 | \
45 MXC_F_CSI2_REVA_RX_EINT_CTRL_IE_ECRC | MXC_F_CSI2_REVA_RX_EINT_CTRL_IE_EID)
46
47 #define MXC_CSI2_REVA_VFIFO_ERRINT_FL \
48 (MXC_F_CSI2_REVA_RX_EINT_VFF_IF_OUTSYNC | MXC_F_CSI2_REVA_RX_EINT_VFF_IF_FMTERR | \
49 MXC_F_CSI2_REVA_RX_EINT_VFF_IF_RAW_AHBERR)
50
51 #define MXC_CSI2_REVA_VFIFO_FIFOINT_FL \
52 (MXC_F_CSI2_REVA_RX_EINT_VFF_IF_FNEMPTY | MXC_F_CSI2_REVA_RX_EINT_VFF_IF_FTHD | \
53 MXC_F_CSI2_REVA_RX_EINT_VFF_IF_FFULL)
54
55 #define MXC_CSI2_REVA_VFIFO_FIFOINT_EN \
56 (MXC_F_CSI2_REVA_RX_EINT_VFF_IE_FNEMPTY | MXC_F_CSI2_REVA_RX_EINT_VFF_IE_FTHD | \
57 MXC_F_CSI2_REVA_RX_EINT_VFF_IE_FFULL)
58
59 #define MXC_CSI2_REVA_VFIFO_DETECT_MD \
60 (MXC_F_CSI2_REVA_RX_EINT_VFF_IE_FNEMP_MD | MXC_F_CSI2_REVA_RX_EINT_VFF_IE_FTHD_MD | \
61 MXC_F_CSI2_REVA_RX_EINT_VFF_IE_FFUL_MD)
62
63 // A macro to convert a DMA channel number to an IRQn number
64 #define GetIRQnForDMAChannel(x) \
65 ((IRQn_Type)(((x) == 0) ? DMA0_IRQn : \
66 ((x) == 1) ? DMA1_IRQn : \
67 ((x) == 2) ? DMA2_IRQn : \
68 DMA3_IRQn))
69
70 /* **** Globals **** */
71
72 static volatile uint32_t dphy_rdy;
73 static volatile uint32_t frame_end_cnt;
74 static volatile uint32_t line_cnt;
75 static volatile uint32_t odd_line_byte_num;
76 static volatile uint32_t even_line_byte_num;
77 static volatile uint32_t line_byte_num;
78 static volatile uint32_t frame_byte_num;
79 static volatile bool g_frame_complete = false;
80
81 // Used for Non-DMA CSI2 Cases
82 static volatile uint32_t bits_per_pixel;
83 static volatile uint32_t fifo_burst_size;
84 static volatile mxc_csi2_reva_fifo_trig_t fifo_int_trig;
85 static volatile mxc_csi2_ahbwait_t ahbwait_en;
86
87 struct line_buffer {
88 uint8_t *a; // Line buffer A
89 uint8_t *b; // Line buffer B
90 uint8_t *active; // Pointer to the active line buffer (volatile!)
91 uint8_t *inactive; // Pointer to the inactive line buffer (safe to read)
92 } lb;
93
_free_line_buffer(void)94 void _free_line_buffer(void)
95 {
96 if (lb.a != NULL) {
97 free((uint8_t *)lb.a);
98 lb.a = NULL;
99 }
100 if (lb.b != NULL) {
101 free((uint8_t *)lb.b);
102 lb.b = NULL;
103 }
104 }
105
_init_line_buffer()106 int _init_line_buffer()
107 {
108 _free_line_buffer();
109
110 lb.a = (uint8_t *)malloc(line_byte_num);
111 lb.b = (uint8_t *)malloc(line_byte_num);
112 if (lb.a == NULL || lb.b == NULL)
113 return E_NULL_PTR;
114
115 lb.active = lb.a;
116 lb.inactive = lb.b;
117 return E_NO_ERROR;
118 }
119
_swap_line_buffer()120 void _swap_line_buffer()
121 {
122 uint8_t *temp = lb.active;
123 lb.active = lb.inactive;
124 lb.inactive = temp;
125 }
126
127 typedef struct {
128 mxc_csi2_req_t *req;
129 mxc_csi2_ctrl_cfg_t *ctrl_cfg;
130 mxc_csi2_vfifo_cfg_t *vfifo_cfg;
131 int dma_channel;
132 bool synced;
133 mxc_csi2_reva_capture_stats_t capture_stats;
134 } csi2_reva_req_state_t;
135
136 volatile csi2_reva_req_state_t csi2_state;
137
138 /* **** Functions **** */
139
140 /******************************************/
141 /* Global Control/Configuration Functions */
142 /******************************************/
143
MXC_CSI2_RevA_Init(mxc_csi2_reva_regs_t * csi2,mxc_csi2_req_t * req,mxc_csi2_ctrl_cfg_t * ctrl_cfg,mxc_csi2_vfifo_cfg_t * vfifo_cfg)144 int MXC_CSI2_RevA_Init(mxc_csi2_reva_regs_t *csi2, mxc_csi2_req_t *req,
145 mxc_csi2_ctrl_cfg_t *ctrl_cfg, mxc_csi2_vfifo_cfg_t *vfifo_cfg)
146 {
147 int error;
148
149 dphy_rdy = 0;
150 line_cnt = 0;
151 frame_end_cnt = 0;
152
153 csi2_state.req = req;
154 csi2_state.ctrl_cfg = ctrl_cfg;
155 csi2_state.vfifo_cfg = vfifo_cfg;
156 csi2_state.synced = false;
157
158 // Convert respective pixel bit number to bytes
159 frame_byte_num = ((req->bits_per_pixel_odd + req->bits_per_pixel_even) * req->pixels_per_line *
160 req->lines_per_frame) >>
161 4;
162 odd_line_byte_num = (req->bits_per_pixel_odd * req->pixels_per_line) >> 3;
163 even_line_byte_num = (req->bits_per_pixel_even * req->pixels_per_line) >> 3;
164
165 // Presetting with even line byte number as default
166 line_byte_num = even_line_byte_num;
167
168 // D-PHY reset
169 csi2->dphy_rst_n = 0x00;
170
171 error = MXC_CSI2_CTRL_Config(ctrl_cfg);
172 if (error != E_NO_ERROR) {
173 return error;
174 }
175
176 error = MXC_DMA_Init();
177 if (error != E_NO_ERROR) {
178 return error;
179 }
180
181 int channel = MXC_DMA_AcquireChannel();
182 csi2_state.dma_channel = channel;
183
184 // Configure VFIFO
185 csi2->vfifo_pixel_num = req->pixels_per_line;
186 csi2->vfifo_line_num = req->lines_per_frame;
187
188 error = MXC_CSI2_VFIFO_Config(vfifo_cfg);
189 if (error != E_NO_ERROR) {
190 return error;
191 }
192
193 error = MXC_CSI2_VFIFO_ProcessRAWtoRGB(req);
194 if (error != E_NO_ERROR) {
195 return error;
196 }
197
198 return E_NO_ERROR;
199 }
200
MXC_CSI2_RevA_Shutdown(mxc_csi2_reva_regs_t * csi2)201 int MXC_CSI2_RevA_Shutdown(mxc_csi2_reva_regs_t *csi2)
202 {
203 int error;
204
205 error = MXC_CSI2_Stop();
206 if (error != E_NO_ERROR) {
207 return error;
208 }
209
210 MXC_CSI2_CTRL_DisableInt(0xFFFFFFFF);
211 MXC_CSI2_VFIFO_DisableInt(0xFFFFFFFF);
212 MXC_CSI2_PPI_DisableInt(0xFFFFFFFF);
213
214 error = MXC_DMA_ReleaseChannel(csi2_state.dma_channel);
215 if (error != E_NO_ERROR) {
216 return error;
217 }
218
219 return E_NO_ERROR;
220 }
221
MXC_CSI2_RevA_Start(mxc_csi2_reva_regs_t * csi2,int num_data_lanes)222 int MXC_CSI2_RevA_Start(mxc_csi2_reva_regs_t *csi2, int num_data_lanes)
223 {
224 int i;
225 int enable_dlanes;
226
227 dphy_rdy = 0;
228 line_cnt = 0;
229 frame_end_cnt = 0;
230 csi2_state.synced = false;
231
232 MXC_CSI2_CTRL_ClearFlags(0xFFFFFFFF);
233 MXC_CSI2_VFIFO_ClearFlags(0xFFFFFFFF);
234 MXC_CSI2_PPI_ClearFlags(0xFFFFFFFF);
235
236 // Enable VFIFO
237 csi2->vfifo_ctrl |= MXC_F_CSI2_REVA_VFIFO_CTRL_FIFOEN;
238
239 // Release DPHY reset
240 csi2->dphy_rst_n |= 0x01;
241
242 // Enable CSI2 lanes
243 csi2->cfg_clk_lane_en = 0x01;
244
245 // This function assumes configured data lanes are used sequentially (e.g. x2 data lanes = data lane0 and lane1).
246 enable_dlanes = 0;
247 for (i = 0; i < num_data_lanes; i++) {
248 enable_dlanes |= (1 << i);
249 }
250
251 csi2->cfg_data_lane_en = enable_dlanes;
252
253 // Must include setting this bit.
254 csi2->xcfgi_dw0b = 0x10000000;
255
256 return E_NO_ERROR;
257 }
258
MXC_CSI2_RevA_Stop(mxc_csi2_reva_regs_t * csi2)259 int MXC_CSI2_RevA_Stop(mxc_csi2_reva_regs_t *csi2)
260 {
261 g_frame_complete = true;
262
263 MXC_CSI2_VFIFO_Disable();
264
265 // Reset DPHY
266 csi2->dphy_rst_n = 0x00;
267
268 // Enable CSI2 lanes
269 csi2->cfg_clk_lane_en = 0;
270 csi2->cfg_data_lane_en = 0;
271
272 _free_line_buffer();
273
274 return E_NO_ERROR;
275 }
276
MXC_CSI2_RevA_CaptureFrameDMA()277 int MXC_CSI2_RevA_CaptureFrameDMA()
278 {
279 int i;
280 int error;
281 int dma_byte_cnt;
282 int dlane_stop_inten;
283
284 csi2_state.capture_stats.success = false;
285 csi2_state.capture_stats.ctrl_err = 0;
286 csi2_state.capture_stats.ppi_err = 0;
287 csi2_state.capture_stats.vfifo_err = 0;
288 csi2_state.capture_stats.bytes_captured = 0;
289 g_frame_complete = false;
290
291 mxc_csi2_req_t *req = csi2_state.req;
292 mxc_csi2_vfifo_cfg_t *vfifo = csi2_state.vfifo_cfg;
293
294 // Convert respective pixel bit number to bytes
295 frame_byte_num = ((req->bits_per_pixel_odd + req->bits_per_pixel_even) * req->pixels_per_line *
296 req->lines_per_frame) >>
297 4;
298 csi2_state.capture_stats.frame_size = frame_byte_num;
299 odd_line_byte_num = (req->bits_per_pixel_odd * req->pixels_per_line) >> 3;
300 even_line_byte_num = (req->bits_per_pixel_even * req->pixels_per_line) >> 3;
301
302 // Select lower line byte number (Odd line)
303 line_byte_num = odd_line_byte_num;
304
305 if (vfifo->dma_whole_frame == MXC_CSI2_DMA_WHOLE_FRAME) {
306 // Whole frame
307 // dma_byte_cnt = frame_byte_num;
308 // error = MXC_CSI2_DMA_Config(req->img_addr, dma_byte_cnt, vfifo->rx_thd);
309 // if (error != E_NO_ERROR) {
310 // return error;
311 // }
312
313 /*
314 Whole frame captures have been defeatured in favor of application-defined line handlers.
315 We won't entirely burn this bridge now, so we'll leave the framework intact and return not supported.
316 */
317 return E_NOT_SUPPORTED;
318 } else {
319 // Line by line
320 dma_byte_cnt = line_byte_num;
321
322 error = _init_line_buffer();
323 if (error)
324 return error;
325
326 error = MXC_CSI2_DMA_Config(lb.a, dma_byte_cnt, vfifo->rx_thd);
327 if (error != E_NO_ERROR) {
328 return error;
329 }
330 }
331
332 // Enable Stop State interrupts for all used data lanes
333 dlane_stop_inten = 0;
334 for (i = 0; i < csi2_state.ctrl_cfg->num_lanes; i++) {
335 dlane_stop_inten |= (1 << i);
336 }
337
338 dlane_stop_inten <<= MXC_F_CSI2_RX_EINT_PPI_IE_DL0STOP_POS;
339 MXC_CSI2_PPI_EnableInt(dlane_stop_inten);
340
341 // Clear all flags, enable all interrupts.
342 MXC_CSI2->rx_eint_ctrl_if = 0xFFFFFFFF;
343 MXC_CSI2->rx_eint_ppi_if = 0xFFFFFFFF;
344 MXC_CSI2->rx_eint_vff_if = 0xFFFFFFFF;
345 MXC_CSI2->rx_eint_ctrl_ie = 0xFFFFFFFF;
346 MXC_CSI2->rx_eint_ppi_ie = 0xFFFFFFFF;
347 MXC_CSI2->rx_eint_vff_ie = 0xFFFFFFFF;
348
349 error = MXC_CSI2_Start(csi2_state.ctrl_cfg->num_lanes);
350 if (error != E_NO_ERROR) {
351 return error;
352 }
353
354 /*
355 After starting, the drivers should wait for the PPI interrupt flags
356 to indicate the CSI2 is synced up with the sensor. Then, they should
357 wait for the Frame Start VFIFO interrupt flag before enabling the DMA
358 pipeline.
359
360 Register polling is too slow to do that here, so it's implemented in the
361 interrupt handler. (MXC_CSI2_RevA_Handler)
362 */
363
364 while (!g_frame_complete) {}
365
366 if (!csi2_state.capture_stats.success)
367 return E_FAIL;
368 else
369 return E_NO_ERROR;
370 }
371
MXC_CSI2_RevA_SetLaneCtrlSource(mxc_csi2_reva_regs_t * csi2,mxc_csi2_lane_src_t * src)372 int MXC_CSI2_RevA_SetLaneCtrlSource(mxc_csi2_reva_regs_t *csi2, mxc_csi2_lane_src_t *src)
373 {
374 if (src == NULL) {
375 return E_BAD_PARAM;
376 }
377
378 csi2->cfg_d0_swap_sel = src->d0_swap_sel;
379 csi2->cfg_d1_swap_sel = src->d1_swap_sel;
380 csi2->cfg_d2_swap_sel = src->d2_swap_sel;
381 csi2->cfg_d3_swap_sel = src->d3_swap_sel;
382 csi2->cfg_c0_swap_sel = src->c0_swap_sel;
383
384 return E_NO_ERROR;
385 }
386
MXC_CSI2_RevA_GetLaneCtrlSource(mxc_csi2_reva_regs_t * csi2,mxc_csi2_lane_src_t * src)387 int MXC_CSI2_RevA_GetLaneCtrlSource(mxc_csi2_reva_regs_t *csi2, mxc_csi2_lane_src_t *src)
388 {
389 if (src == NULL) {
390 return E_BAD_PARAM;
391 }
392
393 src->d0_swap_sel = csi2->cfg_d0_swap_sel;
394 src->d1_swap_sel = csi2->cfg_d1_swap_sel;
395 src->d2_swap_sel = csi2->cfg_d2_swap_sel;
396 src->d3_swap_sel = csi2->cfg_d3_swap_sel;
397 src->c0_swap_sel = csi2->cfg_c0_swap_sel;
398
399 return E_NO_ERROR;
400 }
401
MXC_CSI2_RevA_GetImageDetails(uint32_t * imgLen,uint32_t * w,uint32_t * h)402 void MXC_CSI2_RevA_GetImageDetails(uint32_t *imgLen, uint32_t *w, uint32_t *h)
403 {
404 *imgLen = frame_byte_num;
405 *w = csi2_state.req->pixels_per_line;
406 *h = csi2_state.req->lines_per_frame;
407 }
408
MXC_CSI2_RevA_Handler()409 void MXC_CSI2_RevA_Handler()
410 {
411 uint32_t ctrl_flags, vfifo_flags, ppi_flags;
412
413 ctrl_flags = MXC_CSI2_CTRL_GetFlags();
414 ppi_flags = MXC_CSI2_PPI_GetFlags();
415 vfifo_flags = MXC_CSI2_VFIFO_GetFlags();
416
417 // Clear Flags.
418 MXC_CSI2_CTRL_ClearFlags(ctrl_flags);
419 MXC_CSI2_PPI_ClearFlags(ppi_flags);
420 MXC_CSI2_VFIFO_ClearFlags(vfifo_flags);
421
422 // Mask out non-critical CTRL status flags
423 ctrl_flags &= (0b11111);
424 if (ctrl_flags) {
425 csi2_state.capture_stats.ctrl_err |= ctrl_flags;
426 }
427
428 if (!csi2_state.synced && ppi_flags != 0) {
429 /*
430 When the PPI flags below have been signaled, the CSI2 interface
431 has synced up with the sensor. It's now safe to monitor the VFIFO.
432 */
433 csi2_state.synced = (bool)(ppi_flags & (MXC_F_CSI2_REVA_RX_EINT_PPI_IF_DL0STOP |
434 MXC_F_CSI2_REVA_RX_EINT_PPI_IF_DL1STOP |
435 MXC_F_CSI2_REVA_RX_EINT_PPI_IF_CL0STOP));
436 }
437
438 // Mask out non-critical PPI status flags
439 ppi_flags &= ~(MXC_F_CSI2_REVA_RX_EINT_PPI_IF_DL0STOP | MXC_F_CSI2_REVA_RX_EINT_PPI_IF_DL1STOP |
440 MXC_F_CSI2_REVA_RX_EINT_PPI_IF_CL0STOP);
441
442 if (ppi_flags) {
443 csi2_state.capture_stats.ppi_err |= ppi_flags;
444 }
445
446 if (vfifo_flags != 0) {
447 if (vfifo_flags & MXC_F_CSI2_RX_EINT_VFF_IF_FS && csi2_state.synced) {
448 /*
449 "Frame Start" has been received. Enable the DMA channel.
450 MXC_CSI2_RevA_DMA_Handler does the heavy lifting from here.
451 */
452 MXC_DMA_Start(csi2_state.dma_channel);
453 }
454
455 // Mask out non-critical VFIFO status flags
456 vfifo_flags &= (MXC_F_CSI2_RX_EINT_VFF_IF_UNDERRUN | MXC_F_CSI2_RX_EINT_VFF_IF_OVERRUN |
457 MXC_F_CSI2_RX_EINT_VFF_IF_OUTSYNC | MXC_F_CSI2_RX_EINT_VFF_IF_FMTERR |
458 MXC_F_CSI2_RX_EINT_VFF_IF_AHBWTO | MXC_F_CSI2_RX_EINT_VFF_IF_RAW_OVR |
459 MXC_F_CSI2_RX_EINT_VFF_IF_RAW_AHBERR);
460
461 if (vfifo_flags) {
462 csi2_state.capture_stats.vfifo_err |= vfifo_flags;
463 }
464 }
465
466 if (csi2_state.capture_stats.ctrl_err | csi2_state.capture_stats.ppi_err |
467 csi2_state.capture_stats.vfifo_err) {
468 csi2_state.capture_stats.success = false;
469 MXC_CSI2_RevA_Stop((mxc_csi2_reva_regs_t *)MXC_CSI2);
470 }
471 }
472
473 /********************************/
474 /* CSI2 RX Controller Functions */
475 /********************************/
476
MXC_CSI2_RevA_CTRL_Config(mxc_csi2_reva_regs_t * csi2,mxc_csi2_ctrl_cfg_t * cfg)477 int MXC_CSI2_RevA_CTRL_Config(mxc_csi2_reva_regs_t *csi2, mxc_csi2_ctrl_cfg_t *cfg)
478 {
479 // Set Power Ready
480 csi2->aon_power_ready_n &= ~0x01;
481
482 // Invert RX Clock
483 if (cfg->invert_ppi_clk) {
484 csi2->rxbyteclkhs_inv = 0x01;
485 } else {
486 csi2->rxbyteclkhs_inv = 0x00;
487 }
488
489 // Setting number of lanes used
490 csi2->cfg_num_lanes = cfg->num_lanes;
491
492 // Must select payload data type
493 if ((cfg->payload0 == MXC_CSI2_PL0_DISABLE_ALL) &&
494 (cfg->payload1 == MXC_CSI2_PL1_DISABLE_ALL)) {
495 return E_NOT_SUPPORTED;
496 }
497
498 csi2->cfg_disable_payload_0 = cfg->payload0;
499 csi2->cfg_disable_payload_1 = cfg->payload1;
500
501 // Set flush count
502 if (cfg->flush_cnt < 0 || cfg->flush_cnt > 15) {
503 return E_BAD_PARAM;
504 }
505
506 csi2->cfg_flush_count = cfg->flush_cnt;
507
508 // Configure Data and Clock Lane Control Source
509 MXC_CSI2_SetLaneCtrlSource(&(cfg->lane_src));
510
511 return E_NO_ERROR;
512 }
513
MXC_CSI2_RevA_CTRL_EnableInt(mxc_csi2_reva_regs_t * csi2,uint32_t mask)514 void MXC_CSI2_RevA_CTRL_EnableInt(mxc_csi2_reva_regs_t *csi2, uint32_t mask)
515 {
516 // Clear flags before enabling
517 csi2->rx_eint_ctrl_if |= mask;
518
519 csi2->rx_eint_ctrl_ie |= mask;
520 }
521
MXC_CSI2_RevA_CTRL_DisableInt(mxc_csi2_reva_regs_t * csi2,uint32_t mask)522 void MXC_CSI2_RevA_CTRL_DisableInt(mxc_csi2_reva_regs_t *csi2, uint32_t mask)
523 {
524 csi2->rx_eint_ctrl_ie &= ~mask;
525 }
526
MXC_CSI2_RevA_CTRL_GetFlags(mxc_csi2_reva_regs_t * csi2)527 int MXC_CSI2_RevA_CTRL_GetFlags(mxc_csi2_reva_regs_t *csi2)
528 {
529 return (csi2->rx_eint_ctrl_if);
530 }
531
MXC_CSI2_RevA_CTRL_ClearFlags(mxc_csi2_reva_regs_t * csi2,uint32_t flags)532 void MXC_CSI2_RevA_CTRL_ClearFlags(mxc_csi2_reva_regs_t *csi2, uint32_t flags)
533 {
534 csi2->rx_eint_ctrl_if |= flags;
535 }
536
537 /************************/
538 /* CSI2 VFIFO Functions */
539 /************************/
540
MXC_CSI2_RevA_VFIFO_Config(mxc_csi2_reva_regs_t * csi2,mxc_csi2_vfifo_cfg_t * cfg)541 int MXC_CSI2_RevA_VFIFO_Config(mxc_csi2_reva_regs_t *csi2, mxc_csi2_vfifo_cfg_t *cfg)
542 {
543 int error;
544
545 csi2->vfifo_cfg1 = (cfg->flow_ctrl) | ((cfg->wait_cyc << MXC_F_CSI2_VFIFO_CFG1_AHBWCYC_POS) &
546 MXC_F_CSI2_VFIFO_CFG1_AHBWCYC);
547
548 // Set virtual channel
549 if (cfg->virtual_channel > 3 || cfg->virtual_channel < 0) {
550 return E_BAD_PARAM;
551 }
552
553 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_VC,
554 cfg->virtual_channel << MXC_F_CSI2_REVA_VFIFO_CFG0_VC_POS);
555
556 error = MXC_CSI2_VFIFO_SetDMAMode(cfg->dma_mode);
557 if (error != E_NO_ERROR) {
558 return error;
559 }
560
561 // Enable AHB WAIT
562 if (cfg->wait_en) {
563 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT,
564 0x1 << MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT_POS);
565 } else {
566 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT,
567 0x0 << MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT_POS);
568 }
569
570 // Select FIFO Read Mode (One-by-One vs Direct Addressing for each entity)
571 if (cfg->fifo_rd_mode) {
572 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_FIFORM,
573 0x1 << MXC_F_CSI2_REVA_VFIFO_CFG0_FIFORM_POS);
574 } else {
575 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_FIFORM,
576 0x0 << MXC_F_CSI2_REVA_VFIFO_CFG0_FIFORM_POS);
577 }
578
579 // Enable Error Detection
580 if (cfg->err_det_en == MXC_CSI2_ERR_DETECT_ENABLE) {
581 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_ERRDE,
582 0x1 << MXC_F_CSI2_REVA_VFIFO_CFG0_ERRDE_POS);
583 } else {
584 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_ERRDE,
585 0x0 << MXC_F_CSI2_REVA_VFIFO_CFG0_ERRDE_POS);
586 }
587
588 // Select Normal mode or Full Bandwidth mode
589 if (cfg->bandwidth_mode) {
590 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_FBWM,
591 0x1 << MXC_F_CSI2_VFIFO_CFG0_FBWM_POS);
592 } else {
593 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_FBWM,
594 0x0 << MXC_F_CSI2_VFIFO_CFG0_FBWM_POS);
595 }
596
597 // Set RX Threshold
598 if (cfg->rx_thd >= MXC_CSI2_FIFO_DEPTH) {
599 return E_BAD_PARAM;
600 }
601
602 MXC_SETFIELD(csi2->vfifo_ctrl, MXC_F_CSI2_REVA_VFIFO_CTRL_THD,
603 cfg->rx_thd << MXC_F_CSI2_REVA_VFIFO_CTRL_THD_POS);
604
605 return E_NO_ERROR;
606 }
607
608 /* Note for maintainers: The CSI2 RevA hardware has significant issues with its RAW->RGB
609 debayering engine. It is strongly recommended to avoid using this until the
610 issues have been resolved. See the AI87 Design Jira for more details.
611 */
MXC_CSI2_RevA_VFIFO_ProcessRAWtoRGB(mxc_csi2_reva_regs_t * csi2,mxc_csi2_req_t * req)612 int MXC_CSI2_RevA_VFIFO_ProcessRAWtoRGB(mxc_csi2_reva_regs_t *csi2, mxc_csi2_req_t *req)
613 {
614 int error;
615
616 csi2->vfifo_raw_buf0_addr = req->raw_buf0_addr;
617 csi2->vfifo_raw_buf1_addr = req->raw_buf1_addr;
618
619 // Process RAW to Selected RGB Type if applicable
620 if (req->process_raw_to_rgb) {
621 error = MXC_CSI2_VFIFO_SetRGBType(req->rgb_type);
622 if (error != E_NO_ERROR) {
623 return error;
624 }
625
626 error = MXC_CSI2_VFIFO_SetRAWFormat(req->raw_format);
627 if (error != E_NO_ERROR) {
628 return error;
629 }
630
631 if (req->autoflush) {
632 MXC_SETFIELD(csi2->vfifo_raw_ctrl, MXC_F_CSI2_VFIFO_RAW_CTRL_RAW_FF_AFO,
633 0x1 << MXC_F_CSI2_VFIFO_RAW_CTRL_RAW_FF_AFO_POS);
634 } else {
635 MXC_SETFIELD(csi2->vfifo_raw_ctrl, MXC_F_CSI2_VFIFO_RAW_CTRL_RAW_FF_AFO,
636 0x0 << MXC_F_CSI2_VFIFO_RAW_CTRL_RAW_FF_AFO_POS);
637 }
638
639 csi2->vfifo_raw_ctrl |= MXC_F_CSI2_REVA_VFIFO_RAW_CTRL_RAW_CEN;
640 }
641
642 return E_NO_ERROR;
643 }
644
MXC_CSI2_RevA_VFIFO_NextFIFOTrigMode(mxc_csi2_reva_regs_t * csi2,uint8_t ff_not_empty,uint8_t ff_abv_thd,uint8_t ff_full)645 int MXC_CSI2_RevA_VFIFO_NextFIFOTrigMode(mxc_csi2_reva_regs_t *csi2, uint8_t ff_not_empty,
646 uint8_t ff_abv_thd, uint8_t ff_full)
647 {
648 // Disable FIFO-related interrupts and clear FIFO trigger detection mode before switching
649 MXC_CSI2_VFIFO_DisableInt(MXC_CSI2_REVA_VFIFO_FIFOINT_EN);
650 MXC_CSI2_VFIFO_ChangeIntMode(MXC_CSI2_REVA_VFIFO_FIFOINT_EN, 0);
651
652 // Set to next FIFO trigger if applicable
653 switch (fifo_int_trig) {
654 case MXC_CSI2_REVA_FF_TRIG_NOT_EMPTY:
655 if (ff_abv_thd) {
656 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_ABV_THD;
657 } else if (ff_full) {
658 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_FULL;
659 } else {
660 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_NOT_EMPTY;
661 }
662 break;
663
664 case MXC_CSI2_REVA_FF_TRIG_ABV_THD:
665 if (ff_full) {
666 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_FULL;
667 } else if (ff_not_empty) {
668 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_NOT_EMPTY;
669 } else {
670 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_ABV_THD;
671 }
672 break;
673
674 case MXC_CSI2_REVA_FF_TRIG_FULL:
675 if (ff_not_empty) {
676 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_NOT_EMPTY;
677 } else if (ff_abv_thd) {
678 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_ABV_THD;
679 } else {
680 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_FULL;
681 }
682 break;
683
684 default:
685 fifo_int_trig = MXC_CSI2_REVA_FF_TRIG_NO_TRIGGER;
686 break;
687 }
688
689 // Set new burst length and ahbwait parameters if applicable
690 switch (fifo_int_trig) {
691 case MXC_CSI2_REVA_FF_TRIG_NOT_EMPTY:
692 fifo_burst_size = bits_per_pixel >> 1;
693 ahbwait_en = MXC_CSI2_AHBWAIT_ENABLE;
694 break;
695
696 case MXC_CSI2_REVA_FF_TRIG_ABV_THD:
697 fifo_burst_size = csi2_state.vfifo_cfg->rx_thd;
698 ahbwait_en = MXC_CSI2_AHBWAIT_DISABLE;
699 break;
700
701 case MXC_CSI2_REVA_FF_TRIG_FULL:
702 fifo_burst_size = 64; // Max burst size
703 ahbwait_en = MXC_CSI2_AHBWAIT_DISABLE;
704 break;
705
706 default:
707 return E_BAD_PARAM;
708 }
709
710 // Update new configurations for next FIFO read
711 MXC_CSI2_VFIFO_SetAHBWait(ahbwait_en);
712 MXC_CSI2_VFIFO_EnableInt(fifo_int_trig, 1);
713
714 return E_NO_ERROR;
715 }
716
MXC_CSI2_RevA_VFIFO_EnableInt(mxc_csi2_reva_regs_t * csi2,uint32_t mask,uint32_t edge)717 void MXC_CSI2_RevA_VFIFO_EnableInt(mxc_csi2_reva_regs_t *csi2, uint32_t mask, uint32_t edge)
718 {
719 // Clear flags before enabling
720 csi2->rx_eint_vff_if |= mask;
721
722 csi2->rx_eint_vff_ie |= mask;
723
724 // Set edge triggered or level triggered FIFO modes if applicable
725 MXC_CSI2_VFIFO_ChangeIntMode(mask, edge);
726 }
727
MXC_CSI2_RevA_VFIFO_ChangeIntMode(mxc_csi2_reva_regs_t * csi2,uint32_t mask,uint32_t edge)728 void MXC_CSI2_RevA_VFIFO_ChangeIntMode(mxc_csi2_reva_regs_t *csi2, uint32_t mask, uint32_t edge)
729 {
730 // Edge Triggered Mode
731 if (edge && (mask & MXC_CSI2_REVA_VFIFO_FIFOINT_EN)) {
732 // Set corresponding detection mode for FIFO not empty, above thd, and full interrupts
733 csi2->rx_eint_vff_ie |=
734 ((mask & MXC_CSI2_REVA_VFIFO_FIFOINT_EN) << MXC_F_CSI2_RX_EINT_VFF_IE_FNEMP_MD_POS);
735
736 // Level Triggered Mode
737 } else if (!edge && (mask & MXC_CSI2_REVA_VFIFO_FIFOINT_EN)) {
738 // Clear corresponding detection mode for FIFO not empty, above thd, and full interrupts
739 csi2->rx_eint_vff_ie &=
740 ~((mask & MXC_CSI2_REVA_VFIFO_FIFOINT_EN) << MXC_F_CSI2_RX_EINT_VFF_IE_FNEMP_MD_POS);
741 }
742 }
743
MXC_CSI2_RevA_VFIFO_DisableInt(mxc_csi2_reva_regs_t * csi2,uint32_t mask)744 void MXC_CSI2_RevA_VFIFO_DisableInt(mxc_csi2_reva_regs_t *csi2, uint32_t mask)
745 {
746 csi2->rx_eint_vff_ie &= ~mask;
747 }
748
MXC_CSI2_RevA_VFIFO_GetFlags(mxc_csi2_reva_regs_t * csi2)749 int MXC_CSI2_RevA_VFIFO_GetFlags(mxc_csi2_reva_regs_t *csi2)
750 {
751 return (csi2->rx_eint_vff_if);
752 }
753
MXC_CSI2_RevA_VFIFO_ClearFlags(mxc_csi2_reva_regs_t * csi2,uint32_t flags)754 void MXC_CSI2_RevA_VFIFO_ClearFlags(mxc_csi2_reva_regs_t *csi2, uint32_t flags)
755 {
756 csi2->rx_eint_vff_if |= flags;
757 }
758
MXC_CSI2_RevA_VFIFO_Enable(mxc_csi2_reva_regs_t * csi2)759 int MXC_CSI2_RevA_VFIFO_Enable(mxc_csi2_reva_regs_t *csi2)
760 {
761 csi2->vfifo_ctrl |= MXC_F_CSI2_REVA_VFIFO_CTRL_FIFOEN;
762
763 return E_NO_ERROR;
764 }
765
MXC_CSI2_RevA_VFIFO_Disable(mxc_csi2_reva_regs_t * csi2)766 int MXC_CSI2_RevA_VFIFO_Disable(mxc_csi2_reva_regs_t *csi2)
767 {
768 csi2->vfifo_ctrl &= ~MXC_F_CSI2_REVA_VFIFO_CTRL_FIFOEN;
769
770 return E_NO_ERROR;
771 }
772
MXC_CSI2_RevA_VFIFO_SetPayloadType(mxc_csi2_reva_regs_t * csi2,mxc_csi2_payload0_t payload0,mxc_csi2_payload1_t payload1)773 int MXC_CSI2_RevA_VFIFO_SetPayloadType(mxc_csi2_reva_regs_t *csi2, mxc_csi2_payload0_t payload0,
774 mxc_csi2_payload1_t payload1)
775 {
776 // Need to set one Payload data type
777 if ((payload0 == MXC_CSI2_PL0_DISABLE_ALL) && (payload1 == MXC_CSI2_PL1_DISABLE_ALL)) {
778 return E_BAD_PARAM;
779 }
780
781 csi2->cfg_disable_payload_0 = payload0;
782 csi2->cfg_disable_payload_1 = payload1;
783
784 return E_NO_ERROR;
785 }
786
MXC_CSI2_RevA_VFIFO_GetPayloadType(mxc_csi2_reva_regs_t * csi2,uint32_t * payload0,uint32_t * payload1)787 int MXC_CSI2_RevA_VFIFO_GetPayloadType(mxc_csi2_reva_regs_t *csi2, uint32_t *payload0,
788 uint32_t *payload1)
789 {
790 if (payload0 == NULL || payload1 == NULL) {
791 return E_NULL_PTR;
792 }
793
794 *payload0 = csi2->cfg_disable_payload_0;
795 *payload1 = csi2->cfg_disable_payload_1;
796
797 return E_NO_ERROR;
798 }
799
MXC_CSI2_RevA_VFIFO_SetDMAMode(mxc_csi2_reva_regs_t * csi2,mxc_csi2_dma_mode_t dma_mode)800 int MXC_CSI2_RevA_VFIFO_SetDMAMode(mxc_csi2_reva_regs_t *csi2, mxc_csi2_dma_mode_t dma_mode)
801 {
802 // Check for valid DMA Mode
803 if (dma_mode < MXC_CSI2_DMA_NO_DMA || dma_mode > MXC_CSI2_DMA_FIFO_FULL) {
804 return E_BAD_PARAM;
805 }
806
807 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_DMAMODE, dma_mode);
808
809 return E_NO_ERROR;
810 }
811
MXC_CSI2_RevA_VFIFO_GetDMAMode(mxc_csi2_reva_regs_t * csi2)812 mxc_csi2_dma_mode_t MXC_CSI2_RevA_VFIFO_GetDMAMode(mxc_csi2_reva_regs_t *csi2)
813 {
814 int dma_mode;
815 mxc_csi2_dma_mode_t result;
816
817 dma_mode = csi2->vfifo_cfg0 & MXC_F_CSI2_REVA_VFIFO_CFG0_DMAMODE;
818 switch (dma_mode) {
819 // No DMA
820 case MXC_S_CSI2_REVA_VFIFO_CFG0_DMAMODE_NO_DMA:
821 result = MXC_CSI2_DMA_NO_DMA;
822 break;
823
824 // DMA Request
825 case MXC_S_CSI2_REVA_VFIFO_CFG0_DMAMODE_DMA_REQ:
826 result = MXC_CSI2_DMA_SEND_REQUEST;
827 break;
828
829 // FIFO Above Threshold
830 case MXC_S_CSI2_REVA_VFIFO_CFG0_DMAMODE_FIFO_THD:
831 result = MXC_CSI2_DMA_FIFO_ABV_THD;
832 break;
833
834 // FIFO Full
835 case MXC_S_CSI2_REVA_VFIFO_CFG0_DMAMODE_FIFO_FULL:
836 result = MXC_CSI2_DMA_FIFO_FULL;
837 break;
838
839 default:
840 return E_BAD_PARAM;
841 }
842
843 return result;
844 }
845
MXC_CSI2_RevA_VFIFO_SetRGBType(mxc_csi2_reva_regs_t * csi2,mxc_csi2_rgb_type_t rgb_type)846 int MXC_CSI2_RevA_VFIFO_SetRGBType(mxc_csi2_reva_regs_t *csi2, mxc_csi2_rgb_type_t rgb_type)
847 {
848 // Check for valid RGB Type
849 if (rgb_type < MXC_CSI2_TYPE_RGB444 || rgb_type > MXC_CSI2_TYPE_RGB888) {
850 return E_BAD_PARAM;
851 }
852
853 MXC_SETFIELD(csi2->vfifo_raw_ctrl, MXC_F_CSI2_REVA_VFIFO_RAW_CTRL_RGB_TYP, rgb_type);
854
855 return E_NO_ERROR;
856 }
857
MXC_CSI2_RevA_VFIFO_GetRGBType(mxc_csi2_reva_regs_t * csi2)858 mxc_csi2_rgb_type_t MXC_CSI2_RevA_VFIFO_GetRGBType(mxc_csi2_reva_regs_t *csi2)
859 {
860 int rgb_type;
861 mxc_csi2_rgb_type_t result;
862
863 rgb_type = csi2->vfifo_raw_ctrl & MXC_F_CSI2_REVA_VFIFO_RAW_CTRL_RGB_TYP;
864
865 switch (rgb_type) {
866 // RGB444
867 case MXC_S_CSI2_REVA_VFIFO_RAW_CTRL_RGB_TYP_RGB444:
868 result = MXC_CSI2_TYPE_RGB444;
869 break;
870
871 // RGB555
872 case MXC_S_CSI2_REVA_VFIFO_RAW_CTRL_RGB_TYP_RGB555:
873 result = MXC_CSI2_TYPE_RGB555;
874 break;
875
876 // RGB565
877 case MXC_S_CSI2_REVA_VFIFO_RAW_CTRL_RGB_TYP_RGB565:
878 result = MXC_CSI2_TYPE_RGB565;
879 break;
880
881 // RGB666
882 case MXC_S_CSI2_REVA_VFIFO_RAW_CTRL_RGB_TYP_RGB666:
883 result = MXC_CSI2_TYPE_RGB666;
884 break;
885
886 // RGB888
887 case MXC_S_CSI2_REVA_VFIFO_RAW_CTRL_RGB_TYP_RGG888:
888 result = MXC_CSI2_TYPE_RGB888;
889 break;
890
891 default:
892 return E_BAD_PARAM;
893 }
894
895 return result;
896 }
897
MXC_CSI2_RevA_VFIFO_SetRAWFormat(mxc_csi2_reva_regs_t * csi2,mxc_csi2_raw_format_t raw_format)898 int MXC_CSI2_RevA_VFIFO_SetRAWFormat(mxc_csi2_reva_regs_t *csi2, mxc_csi2_raw_format_t raw_format)
899 {
900 // Check for valid format
901 if (raw_format < MXC_CSI2_FORMAT_RGRG_GBGB || raw_format > MXC_CSI2_FORMAT_BGBG_GRGR) {
902 return E_BAD_PARAM;
903 }
904
905 MXC_SETFIELD(csi2->vfifo_raw_ctrl, MXC_F_CSI2_REVA_VFIFO_RAW_CTRL_RAW_FMT, raw_format);
906
907 return E_NO_ERROR;
908 }
909
MXC_CSI2_RevA_VFIFO_GetRAWFormat(mxc_csi2_reva_regs_t * csi2)910 mxc_csi2_raw_format_t MXC_CSI2_RevA_VFIFO_GetRAWFormat(mxc_csi2_reva_regs_t *csi2)
911 {
912 int raw_format;
913 mxc_csi2_raw_format_t result;
914
915 raw_format = (csi2->vfifo_raw_ctrl & MXC_F_CSI2_REVA_VFIFO_RAW_CTRL_RAW_FMT) >>
916 MXC_F_CSI2_REVA_VFIFO_RAW_CTRL_RAW_FMT_POS;
917
918 switch (raw_format) {
919 // RGRG_GBGB
920 case MXC_V_CSI2_REVA_VFIFO_RAW_CTRL_RAW_FMT_RGRG_GBGB:
921 result = MXC_CSI2_FORMAT_RGRG_GBGB;
922 break;
923
924 // GRGR_BGBG
925 case MXC_V_CSI2_REVA_VFIFO_RAW_CTRL_RAW_FMT_GRGR_BGBG:
926 result = MXC_CSI2_FORMAT_GRGR_BGBG;
927 break;
928
929 // GBGB_RGRG
930 case MXC_V_CSI2_REVA_VFIFO_RAW_CTRL_RAW_FMT_GBGB_RGRG:
931 result = MXC_CSI2_FORMAT_GBGB_RGRG;
932 break;
933
934 // BGBG_GRGR
935 case MXC_V_CSI2_REVA_VFIFO_RAW_CTRL_RAW_FMT_BGBG_GRGR:
936 result = MXC_CSI2_FORMAT_BGBG_GRGR;
937 break;
938
939 default:
940 return E_BAD_STATE;
941 }
942
943 return result;
944 }
945
MXC_CSI2_RevA_VFIFO_GetFIFOEntityCount(mxc_csi2_reva_regs_t * csi2)946 int MXC_CSI2_RevA_VFIFO_GetFIFOEntityCount(mxc_csi2_reva_regs_t *csi2)
947 {
948 return ((csi2->vfifo_sts & MXC_F_CSI2_VFIFO_STS_FELT) >> MXC_F_CSI2_VFIFO_STS_FELT_POS);
949 }
950
MXC_CSI2_RevA_VFIFO_SetAHBWait(mxc_csi2_reva_regs_t * csi2,mxc_csi2_ahbwait_t wait_en)951 void MXC_CSI2_RevA_VFIFO_SetAHBWait(mxc_csi2_reva_regs_t *csi2, mxc_csi2_ahbwait_t wait_en)
952 {
953 // Enable AHB Wait
954 if (wait_en) {
955 if (csi2_state.vfifo_cfg->wait_en == MXC_CSI2_AHBWAIT_DISABLE) {
956 csi2_state.vfifo_cfg->wait_en = MXC_CSI2_AHBWAIT_ENABLE;
957 }
958
959 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT,
960 (1 << MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT_POS));
961
962 // Disable AHB Wait
963 } else {
964 if (csi2_state.vfifo_cfg->wait_en == MXC_CSI2_AHBWAIT_ENABLE) {
965 csi2_state.vfifo_cfg->wait_en = MXC_CSI2_AHBWAIT_DISABLE;
966 }
967
968 MXC_SETFIELD(csi2->vfifo_cfg0, MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT,
969 (0 << MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT_POS));
970 }
971 }
972
MXC_CSI2_RevA_VFIFO_GetAHBWait(mxc_csi2_reva_regs_t * csi2)973 mxc_csi2_ahbwait_t MXC_CSI2_RevA_VFIFO_GetAHBWait(mxc_csi2_reva_regs_t *csi2)
974 {
975 int ahbwait;
976
977 ahbwait = (csi2->vfifo_cfg0 & MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT) >>
978 MXC_F_CSI2_REVA_VFIFO_CFG0_AHBWAIT_POS;
979
980 if (ahbwait) {
981 return MXC_CSI2_AHBWAIT_ENABLE;
982 } else {
983 return MXC_CSI2_AHBWAIT_DISABLE;
984 }
985 }
986
987 /***********************************************/
988 /* CSI2 PHY Protocol Interface (PPI) Functions */
989 /***********************************************/
990
MXC_CSI2_RevA_PPI_EnableInt(mxc_csi2_reva_regs_t * csi2,uint32_t mask)991 void MXC_CSI2_RevA_PPI_EnableInt(mxc_csi2_reva_regs_t *csi2, uint32_t mask)
992 {
993 // Clear flags before enabling
994 csi2->rx_eint_ppi_if |= mask;
995
996 csi2->rx_eint_ppi_ie |= mask;
997 }
998
MXC_CSI2_RevA_PPI_DisableInt(mxc_csi2_reva_regs_t * csi2,uint32_t mask)999 void MXC_CSI2_RevA_PPI_DisableInt(mxc_csi2_reva_regs_t *csi2, uint32_t mask)
1000 {
1001 csi2->rx_eint_ppi_ie &= ~mask;
1002 }
1003
MXC_CSI2_RevA_PPI_GetFlags(mxc_csi2_reva_regs_t * csi2)1004 int MXC_CSI2_RevA_PPI_GetFlags(mxc_csi2_reva_regs_t *csi2)
1005 {
1006 return (csi2->rx_eint_ppi_if);
1007 }
1008
MXC_CSI2_RevA_PPI_ClearFlags(mxc_csi2_reva_regs_t * csi2,uint32_t flags)1009 void MXC_CSI2_RevA_PPI_ClearFlags(mxc_csi2_reva_regs_t *csi2, uint32_t flags)
1010 {
1011 csi2->rx_eint_ppi_if |= flags;
1012 }
1013
MXC_CSI2_RevA_PPI_Stop(void)1014 int MXC_CSI2_RevA_PPI_Stop(void)
1015 {
1016 MXC_CSI2_PPI_DisableInt(0xFFFFFFFF);
1017
1018 return E_NO_ERROR;
1019 }
1020
1021 /************************************/
1022 /* CSI2 DMA - Used for all features */
1023 /************************************/
1024
1025 // #define GPIO_INDICATOR
1026 /* ^ This can be uncommented to enable a GPIO toggle as each row is received
1027 from the camera. Each edge corresponds to a received row. Useful for
1028 debugging timing issues.
1029 */
1030 #ifdef GPIO_INDICATOR
1031 #define GPIO_INDICATOR_PORT MXC_GPIO1
1032 #define GPIO_INDICATOR_PIN MXC_GPIO_PIN_11
1033 mxc_gpio_cfg_t indicator = { .func = MXC_GPIO_FUNC_OUT,
1034 .port = GPIO_INDICATOR_PORT,
1035 .mask = GPIO_INDICATOR_PIN,
1036 .vssel = MXC_GPIO_VSSEL_VDDIOH,
1037 .drvstr = MXC_GPIO_DRVSTR_0,
1038 .pad = MXC_GPIO_PAD_NONE };
1039 #endif
1040
MXC_CSI2_RevA_DMA_Frame_Complete(void)1041 bool MXC_CSI2_RevA_DMA_Frame_Complete(void)
1042 {
1043 return g_frame_complete;
1044 }
1045
MXC_CSI2_RevA_DMA_GetCaptureStats()1046 mxc_csi2_reva_capture_stats_t MXC_CSI2_RevA_DMA_GetCaptureStats()
1047 {
1048 return csi2_state.capture_stats;
1049 }
1050
MXC_CSI2_RevA_DMA_Handler()1051 void MXC_CSI2_RevA_DMA_Handler()
1052 {
1053 // Clear CTZ Status Flag
1054 if (MXC_DMA->ch[csi2_state.dma_channel].status & MXC_F_DMA_STATUS_CTZ_IF) {
1055 MXC_DMA->ch[csi2_state.dma_channel].status |= MXC_F_DMA_STATUS_CTZ_IF;
1056
1057 if (csi2_state.vfifo_cfg->dma_whole_frame != MXC_CSI2_DMA_WHOLE_FRAME) {
1058 // line by line
1059 line_cnt++;
1060 #ifdef GPIO_INDICATOR
1061 MXC_GPIO_OutToggle(indicator.port, indicator.mask);
1062 #endif
1063 if (line_cnt > csi2_state.req->lines_per_frame) {
1064 // Frame complete
1065 line_cnt = 0;
1066 MXC_CSI2_RevA_Stop((mxc_csi2_reva_regs_t *)MXC_CSI2);
1067 csi2_state.capture_stats.success = true;
1068 // TODO(Jake): Call frame complete handler here when multi-frame exposures are implemented.
1069 } else {
1070 // There is a line to process
1071 // Swap line buffers and reload DMA
1072 csi2_state.capture_stats.bytes_captured += line_byte_num;
1073 _swap_line_buffer();
1074 MXC_DMA->ch[csi2_state.dma_channel].cnt = line_byte_num;
1075 MXC_DMA->ch[csi2_state.dma_channel].dst = (uint32_t)lb.active;
1076 MXC_DMA->ch[csi2_state.dma_channel].ctrl |= MXC_F_DMA_REVA_CTRL_EN;
1077
1078 if (csi2_state.req->line_handler != NULL) {
1079 // Call line handler with a pointer to the inactive line buffer
1080 int error = csi2_state.req->line_handler(lb.inactive, line_byte_num);
1081 if (error)
1082 MXC_CSI2_RevA_Stop((mxc_csi2_reva_regs_t *)MXC_CSI2);
1083 }
1084 }
1085 } else {
1086 // whole frame
1087 MXC_CSI2_RevA_Stop((mxc_csi2_reva_regs_t *)MXC_CSI2);
1088 }
1089 }
1090 }
1091
MXC_CSI2_RevA_DMA_Config(uint8_t * dst_addr,uint32_t byte_cnt,uint32_t burst_size)1092 int MXC_CSI2_RevA_DMA_Config(uint8_t *dst_addr, uint32_t byte_cnt, uint32_t burst_size)
1093 {
1094 int error;
1095 mxc_dma_config_t config;
1096 mxc_dma_srcdst_t srcdst;
1097 mxc_dma_adv_config_t advConfig = { csi2_state.dma_channel, 0, 0, 0, 0, 0 };
1098
1099 #ifdef GPIO_INDICATOR
1100 MXC_GPIO_Config(&indicator);
1101 MXC_GPIO_OutSet(indicator.port, indicator.mask);
1102 #endif
1103
1104 config.reqsel = MXC_DMA_REQUEST_CSI2RX;
1105 config.ch = csi2_state.dma_channel;
1106 config.srcwd = MXC_DMA_WIDTH_WORD;
1107 config.dstwd = MXC_DMA_WIDTH_WORD;
1108 config.srcinc_en = 0;
1109 config.dstinc_en = 1;
1110
1111 advConfig.ch = csi2_state.dma_channel;
1112 advConfig.burst_size = burst_size;
1113
1114 srcdst.ch = csi2_state.dma_channel;
1115 srcdst.source = MXC_CSI2_FIFO;
1116 srcdst.dest = dst_addr;
1117 srcdst.len = byte_cnt;
1118
1119 error = MXC_DMA_ConfigChannel(config, srcdst);
1120 if (error != E_NO_ERROR) {
1121 return error;
1122 }
1123
1124 error = MXC_DMA_SetChannelInterruptEn(csi2_state.dma_channel, false, true);
1125 if (error != E_NO_ERROR) {
1126 return error;
1127 }
1128
1129 error = MXC_DMA_AdvConfigChannel(advConfig);
1130 if (error != E_NO_ERROR) {
1131 return error;
1132 }
1133
1134 error = MXC_DMA_EnableInt(csi2_state.dma_channel);
1135 if (error != E_NO_ERROR) {
1136 return error;
1137 }
1138
1139 MXC_NVIC_SetVector(GetIRQnForDMAChannel(csi2_state.dma_channel), MXC_CSI2_RevA_DMA_Handler);
1140 NVIC_EnableIRQ(GetIRQnForDMAChannel(csi2_state.dma_channel));
1141
1142 return E_NO_ERROR;
1143 }
1144
MXC_CSI2_RevA_DMA_GetChannel(void)1145 int MXC_CSI2_RevA_DMA_GetChannel(void)
1146 {
1147 return csi2_state.dma_channel;
1148 }
1149
MXC_CSI2_RevA_DMA_GetCurrentLineCnt(void)1150 int MXC_CSI2_RevA_DMA_GetCurrentLineCnt(void)
1151 {
1152 return line_cnt;
1153 }
1154
MXC_CSI2_RevA_DMA_GetCurrentFrameEndCnt(void)1155 int MXC_CSI2_RevA_DMA_GetCurrentFrameEndCnt(void)
1156 {
1157 return frame_end_cnt;
1158 }
1159
1160 #endif
1161
1162 /**@} end of group csi2 */
1163