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