1 /*
2  * Copyright (c) 2015-2017, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <stdint.h>
34 
35 /*
36  * By default disable both asserts and log for this module.
37  * This must be done before DebugP.h is included.
38  */
39 #ifndef DebugP_ASSERT_ENABLED
40 #define DebugP_ASSERT_ENABLED 0
41 #endif
42 #ifndef DebugP_LOG_ENABLED
43 #define DebugP_LOG_ENABLED 0
44 #endif
45 #include <ti/drivers/dpl/DebugP.h>
46 #include <ti/drivers/dpl/HwiP.h>
47 #include <ti/drivers/dpl/SemaphoreP.h>
48 
49 #include <ti/drivers/Power.h>
50 #include <ti/drivers/power/PowerCC32XX.h>
51 
52 #include <ti/drivers/camera/CameraCC32XXDMA.h>
53 
54 /* driverlib header files */
55 #include <ti/devices/cc32xx/inc/hw_memmap.h>
56 #include <ti/devices/cc32xx/inc/hw_ints.h>
57 #include <ti/devices/cc32xx/inc/hw_types.h>
58 #include <ti/devices/cc32xx/driverlib/rom.h>
59 #include <ti/devices/cc32xx/driverlib/rom_map.h>
60 #include <ti/devices/cc32xx/driverlib/camera.h>
61 #include <ti/devices/cc32xx/driverlib/interrupt.h>
62 #include <ti/devices/cc32xx/driverlib/prcm.h>
63 #include <ti/devices/cc32xx/driverlib/udma.h>
64 #include <ti/devices/cc32xx/driverlib/utils.h>
65 
66 #define CAM_BT_CORRECT_EN   0x00001000
67 
68 /* CameraCC32XXDMA functions */
69 void           CameraCC32XXDMA_close(Camera_Handle handle);
70 int_fast16_t   CameraCC32XXDMA_control(Camera_Handle handle,
71                                        uint_fast16_t cmd, void *arg);
72 void           CameraCC32XXDMA_init(Camera_Handle handle);
73 Camera_Handle  CameraCC32XXDMA_open(Camera_Handle handle,
74                                     Camera_Params *params);
75 int_fast16_t   CameraCC32XXDMA_capture(Camera_Handle handle, void *buffer,
76                                        size_t bufferlen, size_t *frameLen);
77 
78 /* Camera function table for CameraCC32XXDMA implementation */
79 const Camera_FxnTable CameraCC32XXDMA_fxnTable = {
80     CameraCC32XXDMA_close,
81     CameraCC32XXDMA_control,
82     CameraCC32XXDMA_init,
83     CameraCC32XXDMA_open,
84     CameraCC32XXDMA_capture
85 };
86 
87 /*
88  *  ======== CameraCC32XXDMA_configDMA ========
89  */
CameraCC32XXDMA_configDMA(Camera_Handle handle)90 static void CameraCC32XXDMA_configDMA(Camera_Handle handle)
91 {
92     CameraCC32XXDMA_Object           *object = handle->object;
93     CameraCC32XXDMA_HWAttrs const    *hwAttrs = handle->hwAttrs;
94     unsigned long **bufferPtr = (unsigned long**)&object->captureBuf;
95 
96 
97     /* Clear ALT SELECT Attribute */
98     MAP_uDMAChannelAttributeDisable(hwAttrs->channelIndex,UDMA_ATTR_ALTSELECT);
99 
100     /* Setup ping-pong transfer */
101     MAP_uDMAChannelControlSet(hwAttrs->channelIndex,
102               UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 | UDMA_ARB_8);
103     MAP_uDMAChannelAttributeEnable(hwAttrs->channelIndex,UDMA_ATTR_USEBURST);
104     MAP_uDMAChannelTransferSet(hwAttrs->channelIndex, UDMA_MODE_PINGPONG,
105                                (void *)CAM_BUFFER_ADDR, (void *)*bufferPtr,
106                                CameraCC32XXDMA_DMA_TRANSFER_SIZE);
107 
108     /* Pong Buffer */
109     *bufferPtr += CameraCC32XXDMA_DMA_TRANSFER_SIZE;
110     MAP_uDMAChannelControlSet(hwAttrs->channelIndex | UDMA_ALT_SELECT,
111               UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 | UDMA_ARB_8);
112     MAP_uDMAChannelAttributeEnable(hwAttrs->channelIndex | UDMA_ALT_SELECT,
113                                                        UDMA_ATTR_USEBURST);
114     MAP_uDMAChannelTransferSet(hwAttrs->channelIndex | UDMA_ALT_SELECT,
115                                 UDMA_MODE_PINGPONG,
116                                (void *)CAM_BUFFER_ADDR,
117                                (void *)*bufferPtr,
118                                CameraCC32XXDMA_DMA_TRANSFER_SIZE);
119     MAP_uDMAChannelEnable(hwAttrs->channelIndex | UDMA_ALT_SELECT);
120 
121     /*  Ping Buffer */
122     *bufferPtr += CameraCC32XXDMA_DMA_TRANSFER_SIZE;
123 
124     DebugP_log1("Camera:(%p) DMA transfer enabled", hwAttrs->baseAddr);
125 
126     /* Set mode to Ping buffer initially */
127     object->cameraDMA_PingPongMode = 0;
128 
129     /* Clear any pending interrupt */
130     MAP_CameraIntClear(hwAttrs->baseAddr, CAM_INT_DMA);
131 
132     /* DMA Interrupt unmask from apps config */
133     MAP_CameraIntEnable(hwAttrs->baseAddr, CAM_INT_DMA);
134 
135     DebugP_log3("Camera:(%p) DMA receive, "
136                    "CaptureBuf: %p; Count: %d",
137                     hwAttrs->baseAddr,
138                     (uintptr_t)*bufferPtr,
139                     (uintptr_t)object->bufferlength);
140 }
141 
142 /*
143  *  ======== captureSemCallback ========
144  *  Simple callback to post a semaphore for the blocking mode.
145  */
captureSemCallback(Camera_Handle handle,void * buffer,size_t count)146 static void captureSemCallback(Camera_Handle handle, void *buffer, size_t count)
147 {
148     CameraCC32XXDMA_Object *object = handle->object;
149 
150     SemaphoreP_post(object->captureSem);
151 }
152 
153 /*
154  *  ======== CameraCC32XXDMA_hwiIntFxn ========
155  *  Hwi function that processes Camera interrupts.
156  *
157  *  The Frame end,DMA interrupts is enabled for the camera.
158  *  The DMA interrupt is triggered for every 64 elements.
159  *  The ISR will check for Frame end interrupt to trigger the callback
160  *  in the non-blocking mode/post a semaphore in the blocking mode to
161  *  indicate capture complete.
162  *
163  *  @param(arg)         The Camera_Handle for this Hwi.
164  */
CameraCC32XXDMA_hwiIntFxn(uintptr_t arg)165 static void CameraCC32XXDMA_hwiIntFxn(uintptr_t arg)
166 {
167     uint32_t                     status;
168     CameraCC32XXDMA_Object        *object = ((Camera_Handle)arg)->object;
169     CameraCC32XXDMA_HWAttrs const *hwAttrs = ((Camera_Handle)arg)->hwAttrs;
170     unsigned long **bufferPtr = (unsigned long**)&object->captureBuf;
171 
172     status = MAP_CameraIntStatus(hwAttrs->baseAddr);
173     if ((object->cameraDMAxIntrRcvd > 1) && (status & (CAM_INT_FE))) {
174         DebugP_log2("Camera:(%p) Interrupt with mask 0x%x",
175                hwAttrs->baseAddr,status);
176 
177         MAP_CameraIntClear(hwAttrs->baseAddr, CAM_INT_FE);
178         object->captureCallback((Camera_Handle)arg, *bufferPtr,
179                                  object->frameLength);
180         DebugP_log2("Camera:(%p) capture finished, %d bytes written",
181                 hwAttrs->baseAddr, object->frameLength);
182         object->inUse = 0;
183 
184         MAP_CameraCaptureStop(hwAttrs->baseAddr, true);
185 
186         Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
187     }
188 
189     if (status & CAM_INT_DMA) {
190         // Camera DMA Done clear
191         MAP_CameraIntClear(hwAttrs->baseAddr, CAM_INT_DMA);
192 
193         object->cameraDMAxIntrRcvd++;
194 
195         object->frameLength +=
196          (CameraCC32XXDMA_DMA_TRANSFER_SIZE*sizeof(unsigned long));
197         if (object->frameLength < object->bufferlength) {
198              if (object->cameraDMA_PingPongMode == 0) {
199                 MAP_uDMAChannelControlSet(hwAttrs->channelIndex,
200                 UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 | UDMA_ARB_8);
201 
202                 MAP_uDMAChannelAttributeEnable(hwAttrs->channelIndex,
203                                                  UDMA_ATTR_USEBURST);
204                 MAP_uDMAChannelTransferSet(hwAttrs->channelIndex,
205                                            UDMA_MODE_PINGPONG,
206                                            (void *)CAM_BUFFER_ADDR,
207                                            (void *)*bufferPtr,
208                                            CameraCC32XXDMA_DMA_TRANSFER_SIZE);
209                 MAP_uDMAChannelEnable(hwAttrs->channelIndex);
210                 *bufferPtr += CameraCC32XXDMA_DMA_TRANSFER_SIZE;
211                 object->cameraDMA_PingPongMode = 1;
212             }
213             else {
214                 MAP_uDMAChannelControlSet(hwAttrs->channelIndex | UDMA_ALT_SELECT,
215                   UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 | UDMA_ARB_8);
216 
217                 MAP_uDMAChannelAttributeEnable(
218                     hwAttrs->channelIndex | UDMA_ALT_SELECT,
219                     UDMA_ATTR_USEBURST);
220                 MAP_uDMAChannelTransferSet(
221                     hwAttrs->channelIndex | UDMA_ALT_SELECT,
222                     UDMA_MODE_PINGPONG,
223                     (void *)CAM_BUFFER_ADDR, (void *)*bufferPtr,
224                     CameraCC32XXDMA_DMA_TRANSFER_SIZE);
225                 MAP_uDMAChannelEnable(hwAttrs->channelIndex | UDMA_ALT_SELECT);
226                 *bufferPtr += CameraCC32XXDMA_DMA_TRANSFER_SIZE;
227                 object->cameraDMA_PingPongMode = 0;
228             }
229         }
230         else {
231             // Disable DMA
232             ROM_UtilsDelayDirect(40000);
233             MAP_uDMAChannelDisable(hwAttrs->channelIndex);
234             MAP_CameraIntDisable(hwAttrs->baseAddr, CAM_INT_DMA);
235             object->cameraDMA_PingPongMode = 0;
236             object->captureCallback((Camera_Handle)arg, *bufferPtr,
237                                      object->frameLength);
238             DebugP_log2("Camera:(%p) capture finished, %d bytes written",
239                     hwAttrs->baseAddr, object->frameLength);
240 
241             MAP_CameraCaptureStop(hwAttrs->baseAddr, true);
242 
243             Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
244         }
245     }
246 }
247 
248 /*
249  *  ======== CameraCC32XXDMA_init ========
250  */
CameraCC32XXDMA_init(Camera_Handle handle)251 void CameraCC32XXDMA_init(Camera_Handle handle)
252 {
253     CameraCC32XXDMA_Object *object = handle->object;
254 
255     object->opened = false;
256 }
257 
258 /*
259  *  ======== CameraCC32XXDMA_open ========
260  */
CameraCC32XXDMA_open(Camera_Handle handle,Camera_Params * params)261 Camera_Handle CameraCC32XXDMA_open(Camera_Handle handle, Camera_Params *params)
262 {
263     uintptr_t                      key;
264     CameraCC32XXDMA_Object        *object = handle->object;
265     CameraCC32XXDMA_HWAttrs const *hwAttrs = handle->hwAttrs;
266     unsigned long                  hSyncPolarityConfig;
267     unsigned long                  vSyncPolarityConfig;
268     unsigned long                  byteOrderConfig;
269     unsigned long                  interfaceSync;
270     unsigned long                  pixelClkConfig;
271     HwiP_Params                    hwiParams;
272     SemaphoreP_Params              semParams;
273 
274     /* Timeouts cannot be 0 */
275     DebugP_assert((params->captureTimeout != 0));
276 
277     /* Check that a callback is set */
278     DebugP_assert((params->captureMode != Camera_MODE_CALLBACK) ||
279                   (params->captureCallback != NULL));
280 
281     /* Disable preemption while checking if the Camera is open. */
282     key = HwiP_disable();
283 
284     /* Check if the Camera is open already with the base addr. */
285     if (object->opened == true) {
286         HwiP_restore(key);
287 
288         DebugP_log1("Camera:(%p) already in use.", hwAttrs->baseAddr);
289         return (NULL);
290     }
291 
292     object->opened = true;
293     HwiP_restore(key);
294 
295     object->operationMode    = params->captureMode;
296     object->captureCallback  = params->captureCallback;
297     object->captureTimeout   = params->captureTimeout;
298 
299     /* Set Camera variables to defaults. */
300     object->captureBuf = NULL;
301     object->bufferlength = 0;
302     object->frameLength  = 0;
303     object->inUse        = 0;
304 
305     /*
306      *  Register power dependency. Keeps the clock running in SLP
307      *  and DSLP modes.
308      */
309     Power_setDependency(PowerCC32XX_PERIPH_CAMERA);
310     Power_setDependency(PowerCC32XX_PERIPH_UDMA);
311 
312     /* Disable the Camera interrupt. */
313     MAP_CameraIntDisable(hwAttrs->baseAddr, (CAM_INT_FE | CAM_INT_DMA));
314 
315     HwiP_clearInterrupt(hwAttrs->intNum);
316 
317     /* Create Hwi object for the Camera peripheral. */
318     /* Register the interrupt for this Camera peripheral. */
319     HwiP_Params_init(&hwiParams);
320     hwiParams.arg = (uintptr_t)handle;
321     hwiParams.priority = hwAttrs->intPriority;
322     object->hwiHandle = HwiP_create(hwAttrs->intNum, CameraCC32XXDMA_hwiIntFxn,
323                                     &hwiParams);
324     if (object->hwiHandle == NULL) {
325         CameraCC32XXDMA_close(handle);
326         return (NULL);
327     }
328 
329     MAP_IntEnable(INT_CAMERA);
330 
331     SemaphoreP_Params_init(&semParams);
332     semParams.mode = SemaphoreP_Mode_BINARY;
333 
334     /* If capture is blocking create a semaphore and set callback. */
335     if (object->operationMode == Camera_MODE_BLOCKING) {
336         object->captureSem = SemaphoreP_create(0, &semParams);
337         if (object->captureSem == NULL) {
338             CameraCC32XXDMA_close(handle);
339             return (NULL);
340         }
341         object->captureCallback = &captureSemCallback;
342     }
343 
344     MAP_CameraReset(hwAttrs->baseAddr);
345 
346     if (params->hsyncPolarity == Camera_HSYNC_POLARITY_HIGH) {
347         hSyncPolarityConfig = CAM_HS_POL_HI;
348     }
349     else {
350         hSyncPolarityConfig = CAM_HS_POL_LO;
351     }
352 
353     if (params->vsyncPolarity == Camera_VSYNC_POLARITY_HIGH) {
354         vSyncPolarityConfig = CAM_VS_POL_HI;
355     }
356     else {
357         vSyncPolarityConfig = CAM_VS_POL_LO;
358     }
359 
360     if (params->byteOrder == Camera_BYTE_ORDER_SWAP) {
361         byteOrderConfig = CAM_ORDERCAM_SWAP;
362     }
363     else {
364         byteOrderConfig = 0;
365     }
366 
367     if (params->interfaceSync == Camera_INTERFACE_SYNC_OFF) {
368         interfaceSync = CAM_NOBT_SYNCHRO;
369     }
370     else {
371         interfaceSync = CAM_NOBT_SYNCHRO | CAM_IF_SYNCHRO | CAM_BT_CORRECT_EN;
372     }
373 
374     if (params->pixelClkConfig == Camera_PCLK_CONFIG_RISING_EDGE) {
375         pixelClkConfig = CAM_PCLK_RISE_EDGE;
376     }
377     else {
378         pixelClkConfig = CAM_PCLK_FALL_EDGE;
379     }
380 
381     MAP_CameraParamsConfig(hwAttrs->baseAddr, hSyncPolarityConfig,
382                            vSyncPolarityConfig,
383                            byteOrderConfig | interfaceSync | pixelClkConfig);
384 
385     /*Set the clock divider based on the output clock */
386     MAP_CameraXClkConfig(hwAttrs->baseAddr,
387                          MAP_PRCMPeripheralClockGet(PRCM_CAMERA),
388                          params->outputClock);
389 
390     /*Setting the FIFO threshold for a DMA request */
391     MAP_CameraThresholdSet(hwAttrs->baseAddr, 8);
392 
393     MAP_CameraIntEnable(hwAttrs->baseAddr, (CAM_INT_FE | CAM_INT_DMA));
394     MAP_CameraDMAEnable(hwAttrs->baseAddr);
395 
396     DebugP_log1("Camera:(%p) opened", hwAttrs->baseAddr);
397 
398     /* Return the handle */
399     return (handle);
400 }
401 
402 /*
403  *  ======== CameraCC32XXDMA_close ========
404  */
CameraCC32XXDMA_close(Camera_Handle handle)405 void CameraCC32XXDMA_close(Camera_Handle handle)
406 {
407     CameraCC32XXDMA_Object           *object = handle->object;
408     CameraCC32XXDMA_HWAttrs const    *hwAttrs = handle->hwAttrs;
409 
410     /* Disable Camera and interrupts. */
411     MAP_CameraIntDisable(hwAttrs->baseAddr,CAM_INT_FE);
412     MAP_CameraDMADisable(hwAttrs->baseAddr);
413 
414     if (object->hwiHandle) {
415         HwiP_delete(object->hwiHandle);
416     }
417     if (object->captureSem) {
418         SemaphoreP_delete(object->captureSem);
419     }
420 
421     Power_releaseDependency(PowerCC32XX_PERIPH_CAMERA);
422     Power_releaseDependency(PowerCC32XX_PERIPH_UDMA);
423 
424     object->opened = false;
425 
426     DebugP_log1("Camera:(%p) closed", hwAttrs->baseAddr);
427 }
428 
429 /*
430  *  ======== CameraCC32XXDMA_control ========
431  *  @pre    Function assumes that the handle is not NULL
432  */
CameraCC32XXDMA_control(Camera_Handle handle,uint_fast16_t cmd,void * arg)433 int_fast16_t CameraCC32XXDMA_control(Camera_Handle handle, uint_fast16_t cmd,
434                                      void *arg)
435 {
436     /* No implementation yet */
437     return (CAMERA_STATUS_UNDEFINEDCMD);
438 }
439 
440 /*
441  *  ======== CameraCC32XXDMA_capture ========
442  */
443 
CameraCC32XXDMA_capture(Camera_Handle handle,void * buffer,size_t bufferlen,size_t * frameLen)444 int_fast16_t CameraCC32XXDMA_capture(Camera_Handle handle, void *buffer,
445     size_t bufferlen, size_t *frameLen)
446 {
447    CameraCC32XXDMA_Object        *object = handle->object;
448    CameraCC32XXDMA_HWAttrs const *hwAttrs = handle->hwAttrs;
449    uintptr_t                      key;
450 
451    key = HwiP_disable();
452    if (object->inUse) {
453        HwiP_restore(key);
454        DebugP_log1("Camera:(%p) Could not capture data, camera in use.",
455                       ((CameraCC32XXDMA_HWAttrs const *)
456                           (handle->hwAttrs))->baseAddr);
457 
458        return (CAMERA_STATUS_ERROR);
459    }
460 
461    object->captureBuf             = buffer;
462    object->bufferlength           = bufferlen;
463    object->frameLength            = 0;
464    object->cameraDMAxIntrRcvd     = 0;
465    object->inUse                  = 1;
466    object->cameraDMA_PingPongMode = 0;
467 
468    HwiP_restore(key);
469 
470    /* Set constraints to guarantee transaction */
471    Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
472 
473    /* Start the DMA transfer */
474    CameraCC32XXDMA_configDMA(handle);
475    MAP_CameraCaptureStart(hwAttrs->baseAddr);
476 
477    /* If operationMode is blocking, block and get the status. */
478    if (object->operationMode == Camera_MODE_BLOCKING) {
479        /* Pend on semaphore and wait for Hwi to finish. */
480        if (SemaphoreP_OK == SemaphoreP_pend(object->captureSem,
481                    object->captureTimeout)) {
482 
483            DebugP_log2("Camera:(%p) Capture timed out, %d bytes captured",
484                           ((CameraCC32XXDMA_HWAttrs const *)
485                           (handle->hwAttrs))->baseAddr,
486                           object->frameLength);
487        }
488        else {
489            MAP_CameraCaptureStop(hwAttrs->baseAddr, true);
490            *frameLen = object->frameLength;
491            return (CAMERA_STATUS_SUCCESS);
492        }
493    }
494 
495    *frameLen = 0;
496    return (CAMERA_STATUS_SUCCESS);
497 }
498