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