Skip to content

Commit d7d223e

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 <alain.volmat@foss.st.com>
1 parent f20bf99 commit d7d223e

File tree

1 file changed

+161
-40
lines changed

1 file changed

+161
-40
lines changed

drivers/video/video_stm32_dcmipp.c

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

137+
#define VIDEO_FMT_IS_SEMI_PLANAR(fmt) \
138+
(((fmt)->pixelformat == VIDEO_PIX_FMT_NV12 || \
139+
(fmt)->pixelformat == VIDEO_PIX_FMT_NV21 || \
140+
(fmt)->pixelformat == VIDEO_PIX_FMT_NV16 || \
141+
(fmt)->pixelformat == VIDEO_PIX_FMT_NV61) ? true : false)
142+
143+
#define VIDEO_FMT_IS_PLANAR(fmt) \
144+
(((fmt)->pixelformat == VIDEO_PIX_FMT_YUV420 || \
145+
(fmt)->pixelformat == VIDEO_PIX_FMT_YVU420) ? true : false)
146+
147+
#define VIDEO_Y_PLANE_PITCH(fmt) \
148+
((VIDEO_FMT_IS_PLANAR(fmt) || VIDEO_FMT_IS_SEMI_PLANAR(fmt)) ? \
149+
(fmt)->width : (fmt)->pitch)
150+
151+
#define VIDEO_FMT_PLANAR_Y_PLANE_SIZE(fmt) ((fmt)->width * (fmt)->height)
152+
153+
static void stm32_dcmipp_set_next_buffer_addr(struct stm32_dcmipp_pipe_data *pipe)
154+
{
155+
struct stm32_dcmipp_data *dcmipp = pipe->dcmipp;
156+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
157+
struct video_format *fmt = &pipe->fmt;
158+
#endif
159+
uint8_t *plane = pipe->next->buffer;
160+
161+
/* TODO - the HAL is missing a SetMemoryAddress for auxiliary addresses */
162+
/* Update main buffer address */
163+
if (pipe->id == DCMIPP_PIPE0) {
164+
WRITE_REG(dcmipp->hdcmipp.Instance->P0PPM0AR1, (uint32_t)plane);
165+
}
166+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
167+
else if (pipe->id == DCMIPP_PIPE1) {
168+
WRITE_REG(dcmipp->hdcmipp.Instance->P1PPM0AR1, (uint32_t)plane);
169+
} else {
170+
WRITE_REG(dcmipp->hdcmipp.Instance->P2PPM0AR1, (uint32_t)plane);
171+
}
172+
173+
if (pipe->id != DCMIPP_PIPE1) {
174+
return;
175+
}
176+
177+
if (VIDEO_FMT_IS_SEMI_PLANAR(fmt) || VIDEO_FMT_IS_PLANAR(fmt)) {
178+
/* Y plane has 8 bit per pixel, next plane is located at off + width * height */
179+
plane += VIDEO_FMT_PLANAR_Y_PLANE_SIZE(fmt);
180+
181+
WRITE_REG(dcmipp->hdcmipp.Instance->P1PPM1AR1, (uint32_t)plane);
182+
183+
if (VIDEO_FMT_IS_PLANAR(fmt)) {
184+
/* In case of YUV420 / YVU420, U plane has half width / half height */
185+
plane += VIDEO_FMT_PLANAR_Y_PLANE_SIZE(fmt) / 4;
186+
187+
WRITE_REG(dcmipp->hdcmipp.Instance->P1PPM2AR1, (uint32_t)plane);
188+
}
189+
}
190+
#endif
191+
}
192+
137193
/* Callback getting called for each frame written into memory */
138194
void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *hdcmipp, uint32_t Pipe)
139195
{
@@ -171,7 +227,6 @@ void HAL_DCMIPP_PIPE_VsyncEventCallback(DCMIPP_HandleTypeDef *hdcmipp, uint32_t
171227
struct stm32_dcmipp_data *dcmipp =
172228
CONTAINER_OF(hdcmipp, struct stm32_dcmipp_data, hdcmipp);
173229
struct stm32_dcmipp_pipe_data *pipe = dcmipp->pipe[Pipe];
174-
int ret;
175230

176231
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
177232
/*
@@ -209,17 +264,8 @@ void HAL_DCMIPP_PIPE_VsyncEventCallback(DCMIPP_HandleTypeDef *hdcmipp, uint32_t
209264
return;
210265
}
211266

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-
}
267+
/* Update buffer address */
268+
stm32_dcmipp_set_next_buffer_addr(pipe);
223269
}
224270

225271
#if defined(STM32_DCMIPP_HAS_CSI)
@@ -443,7 +489,13 @@ static const struct stm32_dcmipp_mapping {
443489
PIXEL_PIPE_FMT(ABGR32, ARGB8888, 0, (BIT(1) | BIT(2))),
444490
PIXEL_PIPE_FMT(RGBA32, ARGB8888, 1, (BIT(1) | BIT(2))),
445491
PIXEL_PIPE_FMT(BGRA32, RGBA888, 0, (BIT(1) | BIT(2))),
446-
/* TODO - need to add the semiplanar & planar formats */
492+
/* Multi-planes are only available on Pipe main (1) */
493+
PIXEL_PIPE_FMT(NV12, YUV420_2, 0, BIT(1)),
494+
PIXEL_PIPE_FMT(NV21, YUV420_2, 1, BIT(1)),
495+
PIXEL_PIPE_FMT(NV16, YUV422_2, 0, BIT(1)),
496+
PIXEL_PIPE_FMT(NV61, YUV422_2, 1, BIT(1)),
497+
PIXEL_PIPE_FMT(YUV420, YUV420_3, 0, BIT(1)),
498+
PIXEL_PIPE_FMT(YVU420, YUV420_3, 1, BIT(1)),
447499
#endif
448500
};
449501

@@ -464,6 +516,9 @@ static const struct stm32_dcmipp_mapping {
464516
((fmt) == VIDEO_PIX_FMT_GREY || \
465517
(fmt) == VIDEO_PIX_FMT_YUYV || (fmt) == VIDEO_PIX_FMT_YVYU || \
466518
(fmt) == VIDEO_PIX_FMT_VYUY || (fmt) == VIDEO_PIX_FMT_UYVY || \
519+
(fmt) == VIDEO_PIX_FMT_NV12 || (fmt) == VIDEO_PIX_FMT_NV21 || \
520+
(fmt) == VIDEO_PIX_FMT_NV16 || (fmt) == VIDEO_PIX_FMT_NV61 || \
521+
(fmt) == VIDEO_PIX_FMT_YUV420 || (fmt) == VIDEO_PIX_FMT_YVU420 || \
467522
(fmt) == VIDEO_PIX_FMT_XYUV32) ? VIDEO_COLORSPACE_YUV : \
468523
\
469524
VIDEO_COLORSPACE_RAW)
@@ -859,6 +914,95 @@ static int stm32_dcmipp_set_yuv_conversion(struct stm32_dcmipp_pipe_data *pipe,
859914
}
860915
#endif
861916

917+
static int stm32_dcmipp_start_pipeline(const struct device *dev,
918+
struct stm32_dcmipp_pipe_data *pipe)
919+
{
920+
const struct stm32_dcmipp_config *config = dev->config;
921+
struct stm32_dcmipp_data *dcmipp = pipe->dcmipp;
922+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
923+
struct video_format *fmt = &pipe->fmt;
924+
#endif
925+
int ret;
926+
927+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
928+
if (VIDEO_FMT_IS_PLANAR(fmt)) {
929+
uint8_t *u_addr = pipe->next->buffer + VIDEO_FMT_PLANAR_Y_PLANE_SIZE(fmt);
930+
uint8_t *v_addr = u_addr + (VIDEO_FMT_PLANAR_Y_PLANE_SIZE(fmt) / 4);
931+
DCMIPP_FullPlanarDstAddressTypeDef planar_addr = {
932+
.YAddress = (uint32_t)pipe->next->buffer,
933+
.UAddress = (uint32_t)u_addr,
934+
.VAddress = (uint32_t)v_addr,
935+
};
936+
937+
if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) {
938+
ret = HAL_DCMIPP_PIPE_FullPlanarStart(&dcmipp->hdcmipp, pipe->id,
939+
&planar_addr, DCMIPP_MODE_CONTINUOUS);
940+
}
941+
#if defined(STM32_DCMIPP_HAS_CSI)
942+
else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
943+
ret = HAL_DCMIPP_CSI_PIPE_FullPlanarStart(&dcmipp->hdcmipp, pipe->id,
944+
DCMIPP_VIRTUAL_CHANNEL0,
945+
&planar_addr,
946+
DCMIPP_MODE_CONTINUOUS);
947+
}
948+
#endif
949+
else {
950+
LOG_ERR("Invalid bus_type");
951+
ret = -EINVAL;
952+
}
953+
} else if (VIDEO_FMT_IS_SEMI_PLANAR(fmt)) {
954+
uint8_t *uv_addr = pipe->next->buffer + VIDEO_FMT_PLANAR_Y_PLANE_SIZE(fmt);
955+
DCMIPP_SemiPlanarDstAddressTypeDef semiplanar_addr = {
956+
.YAddress = (uint32_t)pipe->next->buffer,
957+
.UVAddress = (uint32_t)uv_addr,
958+
};
959+
960+
if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) {
961+
ret = HAL_DCMIPP_PIPE_SemiPlanarStart(&dcmipp->hdcmipp, pipe->id,
962+
&semiplanar_addr,
963+
DCMIPP_MODE_CONTINUOUS);
964+
}
965+
#if defined(STM32_DCMIPP_HAS_CSI)
966+
else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
967+
ret = HAL_DCMIPP_CSI_PIPE_SemiPlanarStart(&dcmipp->hdcmipp, pipe->id,
968+
DCMIPP_VIRTUAL_CHANNEL0,
969+
&semiplanar_addr,
970+
DCMIPP_MODE_CONTINUOUS);
971+
}
972+
#endif
973+
else {
974+
LOG_ERR("Invalid bus_type");
975+
ret = -EINVAL;
976+
}
977+
} else {
978+
#endif
979+
if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) {
980+
ret = HAL_DCMIPP_PIPE_Start(&dcmipp->hdcmipp, pipe->id,
981+
(uint32_t)pipe->next->buffer,
982+
DCMIPP_MODE_CONTINUOUS);
983+
}
984+
#if defined(STM32_DCMIPP_HAS_CSI)
985+
else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
986+
ret = HAL_DCMIPP_CSI_PIPE_Start(&dcmipp->hdcmipp, pipe->id,
987+
DCMIPP_VIRTUAL_CHANNEL0,
988+
(uint32_t)pipe->next->buffer,
989+
DCMIPP_MODE_CONTINUOUS);
990+
}
991+
#endif
992+
else {
993+
LOG_ERR("Invalid bus_type");
994+
ret = -EINVAL;
995+
}
996+
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
997+
}
998+
#endif
999+
if (ret != HAL_OK) {
1000+
return -EIO;
1001+
}
1002+
1003+
return 0;
1004+
}
1005+
8621006
static int stm32_dcmipp_stream_enable(const struct device *dev)
8631007
{
8641008
struct stm32_dcmipp_pipe_data *pipe = dev->data;
@@ -946,7 +1090,7 @@ static int stm32_dcmipp_stream_enable(const struct device *dev)
9461090
pipe_cfg.FrameRate = DCMIPP_FRAME_RATE_ALL;
9471091
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
9481092
if (pipe->id == DCMIPP_PIPE1 || pipe->id == DCMIPP_PIPE2) {
949-
pipe_cfg.PixelPipePitch = fmt->pitch;
1093+
pipe_cfg.PixelPipePitch = VIDEO_Y_PLANE_PITCH(fmt);
9501094
pipe_cfg.PixelPackerFormat = mapping->pixels.dcmipp_format;
9511095
}
9521096
#endif
@@ -1042,25 +1186,9 @@ static int stm32_dcmipp_stream_enable(const struct device *dev)
10421186
#endif
10431187

10441188
/* 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) {
1189+
ret = stm32_dcmipp_start_pipeline(dev, pipe);
1190+
if (ret < 0) {
10621191
LOG_ERR("Failed to start the pipeline");
1063-
ret = -EIO;
10641192
goto out;
10651193
}
10661194

@@ -1183,7 +1311,6 @@ static int stm32_dcmipp_enqueue(const struct device *dev, struct video_buffer *v
11831311
{
11841312
struct stm32_dcmipp_pipe_data *pipe = dev->data;
11851313
struct stm32_dcmipp_data *dcmipp = pipe->dcmipp;
1186-
int ret;
11871314

11881315
k_mutex_lock(&pipe->lock, K_FOREVER);
11891316

@@ -1194,13 +1321,7 @@ static int stm32_dcmipp_enqueue(const struct device *dev, struct video_buffer *v
11941321
if (pipe->state == STM32_DCMIPP_WAIT_FOR_BUFFER) {
11951322
LOG_DBG("Restart CPTREQ after wait for buffer");
11961323
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-
}
1324+
stm32_dcmipp_set_next_buffer_addr(pipe);
12041325
if (pipe->id == DCMIPP_PIPE0) {
12051326
SET_BIT(dcmipp->hdcmipp.Instance->P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
12061327
}

0 commit comments

Comments
 (0)