Skip to content

Commit 85c17b2

Browse files
author
Alain Volmat
committed
video: stm32: dcmipp: add (semi)planar support
Add support for NV12/NV21, NV16/NV61 and YUV420/YVU420 (semi)planar formats which can be output by the main #1 pipe. Signed-off-by: Alain Volmat <[email protected]>
1 parent f20bf99 commit 85c17b2

File tree

1 file changed

+160
-40
lines changed

1 file changed

+160
-40
lines changed

drivers/video/video_stm32_dcmipp.c

Lines changed: 160 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,49 @@ struct stm32_dcmipp_config {
134134
#define STM32_DCMIPP_WIDTH_MAX 4094
135135
#define STM32_DCMIPP_HEIGHT_MAX 4094
136136

137+
static void stm32_dcmipp_set_next_buffer_addr(struct stm32_dcmipp_pipe_data *pipe)
138+
{
139+
struct stm32_dcmipp_data *dcmipp = pipe->dcmipp;
140+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
141+
struct video_format *fmt = &pipe->fmt;
142+
#endif
143+
uint8_t *plane = pipe->next->buffer;
144+
145+
/* TODO - the HAL is missing a SetMemoryAddress for auxiliary addresses */
146+
/* Update main buffer address */
147+
if (pipe->id == DCMIPP_PIPE0) {
148+
WRITE_REG(dcmipp->hdcmipp.Instance->P0PPM0AR1, (uint32_t)plane);
149+
}
150+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
151+
else if (pipe->id == DCMIPP_PIPE1) {
152+
WRITE_REG(dcmipp->hdcmipp.Instance->P1PPM0AR1, (uint32_t)plane);
153+
} else {
154+
WRITE_REG(dcmipp->hdcmipp.Instance->P2PPM0AR1, (uint32_t)plane);
155+
}
156+
157+
if (pipe->id != DCMIPP_PIPE1) {
158+
return;
159+
}
160+
161+
if (fmt->pixelformat == VIDEO_PIX_FMT_NV12 || fmt->pixelformat == VIDEO_PIX_FMT_NV21 ||
162+
fmt->pixelformat == VIDEO_PIX_FMT_NV16 || fmt->pixelformat == VIDEO_PIX_FMT_NV61 ||
163+
fmt->pixelformat == VIDEO_PIX_FMT_YUV420 || fmt->pixelformat == VIDEO_PIX_FMT_YVU420) {
164+
/* Y plane has 8 bit per pixel, next plane is located at off + width * height */
165+
plane += (fmt->width * fmt->height);
166+
167+
WRITE_REG(dcmipp->hdcmipp.Instance->P1PPM1AR1, (uint32_t)plane);
168+
169+
if (fmt->pixelformat == VIDEO_PIX_FMT_YUV420 ||
170+
fmt->pixelformat == VIDEO_PIX_FMT_YVU420) {
171+
/* In case of YUV420 / YVU420, U plane has half width / half height */
172+
plane += (fmt->width * fmt->height) / 4;
173+
174+
WRITE_REG(dcmipp->hdcmipp.Instance->P1PPM2AR1, (uint32_t)plane);
175+
}
176+
}
177+
#endif
178+
}
179+
137180
/* Callback getting called for each frame written into memory */
138181
void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *hdcmipp, uint32_t Pipe)
139182
{
@@ -171,7 +214,6 @@ void HAL_DCMIPP_PIPE_VsyncEventCallback(DCMIPP_HandleTypeDef *hdcmipp, uint32_t
171214
struct stm32_dcmipp_data *dcmipp =
172215
CONTAINER_OF(hdcmipp, struct stm32_dcmipp_data, hdcmipp);
173216
struct stm32_dcmipp_pipe_data *pipe = dcmipp->pipe[Pipe];
174-
int ret;
175217

176218
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
177219
/*
@@ -209,17 +251,8 @@ void HAL_DCMIPP_PIPE_VsyncEventCallback(DCMIPP_HandleTypeDef *hdcmipp, uint32_t
209251
return;
210252
}
211253

212-
/*
213-
* TODO - we only support 1 buffer formats for the time being, setting of
214-
* MEMORY_ADDRESS_1 and MEMORY_ADDRESS_2 required depending on the pixelformat
215-
* for Pipe1
216-
*/
217-
ret = HAL_DCMIPP_PIPE_SetMemoryAddress(&dcmipp->hdcmipp, Pipe, DCMIPP_MEMORY_ADDRESS_0,
218-
(uint32_t)pipe->next->buffer);
219-
if (ret != HAL_OK) {
220-
LOG_ERR("Failed to update memory address");
221-
return;
222-
}
254+
/* Update buffer address */
255+
stm32_dcmipp_set_next_buffer_addr(pipe);
223256
}
224257

225258
#if defined(STM32_DCMIPP_HAS_CSI)
@@ -443,7 +476,13 @@ static const struct stm32_dcmipp_mapping {
443476
PIXEL_PIPE_FMT(ABGR32, ARGB8888, 0, (BIT(1) | BIT(2))),
444477
PIXEL_PIPE_FMT(RGBA32, ARGB8888, 1, (BIT(1) | BIT(2))),
445478
PIXEL_PIPE_FMT(BGRA32, RGBA888, 0, (BIT(1) | BIT(2))),
446-
/* TODO - need to add the semiplanar & planar formats */
479+
/* Multi-planes are only available on Pipe main (1) */
480+
PIXEL_PIPE_FMT(NV12, YUV420_2, 0, BIT(1)),
481+
PIXEL_PIPE_FMT(NV21, YUV420_2, 1, BIT(1)),
482+
PIXEL_PIPE_FMT(NV16, YUV422_2, 0, BIT(1)),
483+
PIXEL_PIPE_FMT(NV61, YUV422_2, 1, BIT(1)),
484+
PIXEL_PIPE_FMT(YUV420, YUV420_3, 0, BIT(1)),
485+
PIXEL_PIPE_FMT(YVU420, YUV420_3, 1, BIT(1)),
447486
#endif
448487
};
449488

@@ -464,6 +503,9 @@ static const struct stm32_dcmipp_mapping {
464503
((fmt) == VIDEO_PIX_FMT_GREY || \
465504
(fmt) == VIDEO_PIX_FMT_YUYV || (fmt) == VIDEO_PIX_FMT_YVYU || \
466505
(fmt) == VIDEO_PIX_FMT_VYUY || (fmt) == VIDEO_PIX_FMT_UYVY || \
506+
(fmt) == VIDEO_PIX_FMT_NV12 || (fmt) == VIDEO_PIX_FMT_NV21 || \
507+
(fmt) == VIDEO_PIX_FMT_NV16 || (fmt) == VIDEO_PIX_FMT_NV61 || \
508+
(fmt) == VIDEO_PIX_FMT_YUV420 || (fmt) == VIDEO_PIX_FMT_YVU420 || \
467509
(fmt) == VIDEO_PIX_FMT_XYUV32) ? VIDEO_COLORSPACE_YUV : \
468510
\
469511
VIDEO_COLORSPACE_RAW)
@@ -859,6 +901,98 @@ static int stm32_dcmipp_set_yuv_conversion(struct stm32_dcmipp_pipe_data *pipe,
859901
}
860902
#endif
861903

904+
static int stm32_dcmipp_start_pipeline(const struct device *dev,
905+
struct stm32_dcmipp_pipe_data *pipe)
906+
{
907+
const struct stm32_dcmipp_config *config = dev->config;
908+
struct stm32_dcmipp_data *dcmipp = pipe->dcmipp;
909+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
910+
struct video_format *fmt = &pipe->fmt;
911+
#endif
912+
int ret;
913+
914+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
915+
if (fmt->pixelformat == VIDEO_PIX_FMT_YUV420 || fmt->pixelformat == VIDEO_PIX_FMT_YVU420) {
916+
uint8_t *u_addr = pipe->next->buffer + fmt->width * fmt->height;
917+
uint8_t *v_addr = u_addr + (fmt->width * fmt->height / 4);
918+
DCMIPP_FullPlanarDstAddressTypeDef planar_addr = {
919+
.YAddress = (uint32_t)pipe->next->buffer,
920+
.UAddress = (uint32_t)u_addr,
921+
.VAddress = (uint32_t)v_addr,
922+
};
923+
924+
if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) {
925+
ret = HAL_DCMIPP_PIPE_FullPlanarStart(&dcmipp->hdcmipp, pipe->id,
926+
&planar_addr, DCMIPP_MODE_CONTINUOUS);
927+
}
928+
#if defined(STM32_DCMIPP_HAS_CSI)
929+
else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
930+
ret = HAL_DCMIPP_CSI_PIPE_FullPlanarStart(&dcmipp->hdcmipp, pipe->id,
931+
DCMIPP_VIRTUAL_CHANNEL0,
932+
&planar_addr,
933+
DCMIPP_MODE_CONTINUOUS);
934+
}
935+
#endif
936+
else {
937+
LOG_ERR("Invalid bus_type");
938+
ret = -EINVAL;
939+
}
940+
} else if (fmt->pixelformat == VIDEO_PIX_FMT_NV12 ||
941+
fmt->pixelformat == VIDEO_PIX_FMT_NV21 ||
942+
fmt->pixelformat == VIDEO_PIX_FMT_NV16 ||
943+
fmt->pixelformat == VIDEO_PIX_FMT_NV61) {
944+
uint8_t *uv_addr = pipe->next->buffer + fmt->width * fmt->height;
945+
DCMIPP_SemiPlanarDstAddressTypeDef semiplanar_addr = {
946+
.YAddress = (uint32_t)pipe->next->buffer,
947+
.UVAddress = (uint32_t)uv_addr,
948+
};
949+
950+
if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) {
951+
ret = HAL_DCMIPP_PIPE_SemiPlanarStart(&dcmipp->hdcmipp, pipe->id,
952+
&semiplanar_addr,
953+
DCMIPP_MODE_CONTINUOUS);
954+
}
955+
#if defined(STM32_DCMIPP_HAS_CSI)
956+
else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
957+
ret = HAL_DCMIPP_CSI_PIPE_SemiPlanarStart(&dcmipp->hdcmipp, pipe->id,
958+
DCMIPP_VIRTUAL_CHANNEL0,
959+
&semiplanar_addr,
960+
DCMIPP_MODE_CONTINUOUS);
961+
}
962+
#endif
963+
else {
964+
LOG_ERR("Invalid bus_type");
965+
ret = -EINVAL;
966+
}
967+
} else {
968+
#endif
969+
if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) {
970+
ret = HAL_DCMIPP_PIPE_Start(&dcmipp->hdcmipp, pipe->id,
971+
(uint32_t)pipe->next->buffer,
972+
DCMIPP_MODE_CONTINUOUS);
973+
}
974+
#if defined(STM32_DCMIPP_HAS_CSI)
975+
else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
976+
ret = HAL_DCMIPP_CSI_PIPE_Start(&dcmipp->hdcmipp, pipe->id,
977+
DCMIPP_VIRTUAL_CHANNEL0,
978+
(uint32_t)pipe->next->buffer,
979+
DCMIPP_MODE_CONTINUOUS);
980+
}
981+
#endif
982+
else {
983+
LOG_ERR("Invalid bus_type");
984+
ret = -EINVAL;
985+
}
986+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
987+
}
988+
#endif
989+
if (ret != HAL_OK) {
990+
return -EIO;
991+
}
992+
993+
return 0;
994+
}
995+
862996
static int stm32_dcmipp_stream_enable(const struct device *dev)
863997
{
864998
struct stm32_dcmipp_pipe_data *pipe = dev->data;
@@ -946,7 +1080,16 @@ static int stm32_dcmipp_stream_enable(const struct device *dev)
9461080
pipe_cfg.FrameRate = DCMIPP_FRAME_RATE_ALL;
9471081
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
9481082
if (pipe->id == DCMIPP_PIPE1 || pipe->id == DCMIPP_PIPE2) {
949-
pipe_cfg.PixelPipePitch = fmt->pitch;
1083+
if (fmt->pixelformat == VIDEO_PIX_FMT_NV12 ||
1084+
fmt->pixelformat == VIDEO_PIX_FMT_NV21 ||
1085+
fmt->pixelformat == VIDEO_PIX_FMT_NV16 ||
1086+
fmt->pixelformat == VIDEO_PIX_FMT_NV61 ||
1087+
fmt->pixelformat == VIDEO_PIX_FMT_YUV420 ||
1088+
fmt->pixelformat == VIDEO_PIX_FMT_YVU420) {
1089+
pipe_cfg.PixelPipePitch = fmt->width;
1090+
} else {
1091+
pipe_cfg.PixelPipePitch = fmt->pitch;
1092+
}
9501093
pipe_cfg.PixelPackerFormat = mapping->pixels.dcmipp_format;
9511094
}
9521095
#endif
@@ -1042,25 +1185,9 @@ static int stm32_dcmipp_stream_enable(const struct device *dev)
10421185
#endif
10431186

10441187
/* Enable the DCMIPP Pipeline */
1045-
if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) {
1046-
ret = HAL_DCMIPP_PIPE_Start(&dcmipp->hdcmipp, pipe->id,
1047-
(uint32_t)pipe->next->buffer, DCMIPP_MODE_CONTINUOUS);
1048-
}
1049-
#if defined(STM32_DCMIPP_HAS_CSI)
1050-
else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
1051-
ret = HAL_DCMIPP_CSI_PIPE_Start(&dcmipp->hdcmipp, pipe->id, DCMIPP_VIRTUAL_CHANNEL0,
1052-
(uint32_t)pipe->next->buffer,
1053-
DCMIPP_MODE_CONTINUOUS);
1054-
}
1055-
#endif
1056-
else {
1057-
LOG_ERR("Invalid bus_type");
1058-
ret = -EINVAL;
1059-
goto out;
1060-
}
1061-
if (ret != HAL_OK) {
1188+
ret = stm32_dcmipp_start_pipeline(dev, pipe);
1189+
if (ret < 0) {
10621190
LOG_ERR("Failed to start the pipeline");
1063-
ret = -EIO;
10641191
goto out;
10651192
}
10661193

@@ -1183,7 +1310,6 @@ static int stm32_dcmipp_enqueue(const struct device *dev, struct video_buffer *v
11831310
{
11841311
struct stm32_dcmipp_pipe_data *pipe = dev->data;
11851312
struct stm32_dcmipp_data *dcmipp = pipe->dcmipp;
1186-
int ret;
11871313

11881314
k_mutex_lock(&pipe->lock, K_FOREVER);
11891315

@@ -1194,13 +1320,7 @@ static int stm32_dcmipp_enqueue(const struct device *dev, struct video_buffer *v
11941320
if (pipe->state == STM32_DCMIPP_WAIT_FOR_BUFFER) {
11951321
LOG_DBG("Restart CPTREQ after wait for buffer");
11961322
pipe->next = vbuf;
1197-
ret = HAL_DCMIPP_PIPE_SetMemoryAddress(&dcmipp->hdcmipp, pipe->id,
1198-
DCMIPP_MEMORY_ADDRESS_0,
1199-
(uint32_t)pipe->next->buffer);
1200-
if (ret != HAL_OK) {
1201-
LOG_ERR("Failed to update memory address");
1202-
return -EIO;
1203-
}
1323+
stm32_dcmipp_set_next_buffer_addr(pipe);
12041324
if (pipe->id == DCMIPP_PIPE0) {
12051325
SET_BIT(dcmipp->hdcmipp.Instance->P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
12061326
}

0 commit comments

Comments
 (0)