1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for STM32 Digital Camera Memory Interface Pixel Processor 4 * 5 * Copyright (C) STMicroelectronics SA 2023 6 * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com> 7 * Alain Volmat <alain.volmat@foss.st.com> 8 * for STMicroelectronics. 9 */ 10 11 #include <linux/v4l2-mediabus.h> 12 #include <media/v4l2-event.h> 13 #include <media/v4l2-subdev.h> 14 15 #include "dcmipp-common.h" 16 17 #define DCMIPP_PRCR 0x104 18 #define DCMIPP_PRCR_FORMAT_SHIFT 16 19 #define DCMIPP_PRCR_FORMAT_YUV422 0x1e 20 #define DCMIPP_PRCR_FORMAT_RGB565 0x22 21 #define DCMIPP_PRCR_FORMAT_RAW8 0x2a 22 #define DCMIPP_PRCR_FORMAT_G8 0x4a 23 #define DCMIPP_PRCR_FORMAT_BYTE_STREAM 0x5a 24 #define DCMIPP_PRCR_ESS BIT(4) 25 #define DCMIPP_PRCR_PCKPOL BIT(5) 26 #define DCMIPP_PRCR_HSPOL BIT(6) 27 #define DCMIPP_PRCR_VSPOL BIT(7) 28 #define DCMIPP_PRCR_ENABLE BIT(14) 29 #define DCMIPP_PRCR_SWAPCYCLES BIT(25) 30 31 #define DCMIPP_PRESCR 0x108 32 #define DCMIPP_PRESUR 0x10c 33 34 #define IS_SINK(pad) (!(pad)) 35 #define IS_SRC(pad) ((pad)) 36 37 struct dcmipp_par_pix_map { 38 unsigned int code_sink; 39 unsigned int code_src; 40 u8 prcr_format; 41 u8 prcr_swapcycles; 42 }; 43 44 #define PIXMAP_SINK_SRC_PRCR_SWAP(sink, src, prcr, swap) \ 45 { \ 46 .code_sink = MEDIA_BUS_FMT_##sink, \ 47 .code_src = MEDIA_BUS_FMT_##src, \ 48 .prcr_format = DCMIPP_PRCR_FORMAT_##prcr, \ 49 .prcr_swapcycles = swap, \ 50 } 51 static const struct dcmipp_par_pix_map dcmipp_par_pix_map_list[] = { 52 /* RGB565 */ 53 PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_LE, RGB565_2X8_LE, RGB565, 1), 54 PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_BE, RGB565_2X8_LE, RGB565, 0), 55 /* YUV422 */ 56 PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, YUYV8_2X8, YUV422, 1), 57 PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, UYVY8_2X8, YUV422, 0), 58 PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, UYVY8_2X8, YUV422, 1), 59 PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, YUYV8_2X8, YUV422, 0), 60 PIXMAP_SINK_SRC_PRCR_SWAP(YVYU8_2X8, YVYU8_2X8, YUV422, 1), 61 PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_2X8, VYUY8_2X8, YUV422, 1), 62 /* GREY */ 63 PIXMAP_SINK_SRC_PRCR_SWAP(Y8_1X8, Y8_1X8, G8, 0), 64 /* Raw Bayer */ 65 PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR8_1X8, SBGGR8_1X8, RAW8, 0), 66 PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG8_1X8, SGBRG8_1X8, RAW8, 0), 67 PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG8_1X8, SGRBG8_1X8, RAW8, 0), 68 PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB8_1X8, SRGGB8_1X8, RAW8, 0), 69 /* JPEG */ 70 PIXMAP_SINK_SRC_PRCR_SWAP(JPEG_1X8, JPEG_1X8, BYTE_STREAM, 0), 71 }; 72 73 /* 74 * Search through the pix_map table, skipping two consecutive entry with the 75 * same code 76 */ 77 static inline const struct dcmipp_par_pix_map *dcmipp_par_pix_map_by_index 78 (unsigned int index, 79 unsigned int pad) 80 { 81 unsigned int i = 0; 82 u32 prev_code = 0, cur_code; 83 84 while (i < ARRAY_SIZE(dcmipp_par_pix_map_list)) { 85 if (IS_SRC(pad)) 86 cur_code = dcmipp_par_pix_map_list[i].code_src; 87 else 88 cur_code = dcmipp_par_pix_map_list[i].code_sink; 89 90 if (cur_code == prev_code) { 91 i++; 92 continue; 93 } 94 prev_code = cur_code; 95 96 if (index == 0) 97 break; 98 i++; 99 index--; 100 } 101 102 if (i >= ARRAY_SIZE(dcmipp_par_pix_map_list)) 103 return NULL; 104 105 return &dcmipp_par_pix_map_list[i]; 106 } 107 108 static inline const struct dcmipp_par_pix_map *dcmipp_par_pix_map_by_code 109 (u32 code_sink, u32 code_src) 110 { 111 unsigned int i; 112 113 for (i = 0; i < ARRAY_SIZE(dcmipp_par_pix_map_list); i++) { 114 if ((dcmipp_par_pix_map_list[i].code_sink == code_sink && 115 dcmipp_par_pix_map_list[i].code_src == code_src) || 116 (dcmipp_par_pix_map_list[i].code_sink == code_src && 117 dcmipp_par_pix_map_list[i].code_src == code_sink) || 118 (dcmipp_par_pix_map_list[i].code_sink == code_sink && 119 code_src == 0) || 120 (code_sink == 0 && 121 dcmipp_par_pix_map_list[i].code_src == code_src)) 122 return &dcmipp_par_pix_map_list[i]; 123 } 124 return NULL; 125 } 126 127 struct dcmipp_par_device { 128 struct dcmipp_ent_device ved; 129 struct v4l2_subdev sd; 130 struct device *dev; 131 void __iomem *regs; 132 bool streaming; 133 }; 134 135 static const struct v4l2_mbus_framefmt fmt_default = { 136 .width = DCMIPP_FMT_WIDTH_DEFAULT, 137 .height = DCMIPP_FMT_HEIGHT_DEFAULT, 138 .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 139 .field = V4L2_FIELD_NONE, 140 .colorspace = DCMIPP_COLORSPACE_DEFAULT, 141 .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT, 142 .quantization = DCMIPP_QUANTIZATION_DEFAULT, 143 .xfer_func = DCMIPP_XFER_FUNC_DEFAULT, 144 }; 145 146 static int dcmipp_par_init_state(struct v4l2_subdev *sd, 147 struct v4l2_subdev_state *sd_state) 148 { 149 unsigned int i; 150 151 for (i = 0; i < sd->entity.num_pads; i++) { 152 struct v4l2_mbus_framefmt *mf; 153 154 mf = v4l2_subdev_state_get_format(sd_state, i); 155 *mf = fmt_default; 156 } 157 158 return 0; 159 } 160 161 static int dcmipp_par_enum_mbus_code(struct v4l2_subdev *sd, 162 struct v4l2_subdev_state *sd_state, 163 struct v4l2_subdev_mbus_code_enum *code) 164 { 165 const struct dcmipp_par_pix_map *vpix = 166 dcmipp_par_pix_map_by_index(code->index, code->pad); 167 168 if (!vpix) 169 return -EINVAL; 170 171 code->code = IS_SRC(code->pad) ? vpix->code_src : vpix->code_sink; 172 173 return 0; 174 } 175 176 static int dcmipp_par_enum_frame_size(struct v4l2_subdev *sd, 177 struct v4l2_subdev_state *sd_state, 178 struct v4l2_subdev_frame_size_enum *fse) 179 { 180 const struct dcmipp_par_pix_map *vpix; 181 182 if (fse->index) 183 return -EINVAL; 184 185 /* Only accept code in the pix map table */ 186 vpix = dcmipp_par_pix_map_by_code(IS_SINK(fse->pad) ? fse->code : 0, 187 IS_SRC(fse->pad) ? fse->code : 0); 188 if (!vpix) 189 return -EINVAL; 190 191 fse->min_width = DCMIPP_FRAME_MIN_WIDTH; 192 fse->max_width = DCMIPP_FRAME_MAX_WIDTH; 193 fse->min_height = DCMIPP_FRAME_MIN_HEIGHT; 194 fse->max_height = DCMIPP_FRAME_MAX_HEIGHT; 195 196 return 0; 197 } 198 199 static void dcmipp_par_adjust_fmt(struct dcmipp_par_device *par, 200 struct v4l2_mbus_framefmt *fmt, __u32 pad) 201 { 202 const struct dcmipp_par_pix_map *vpix; 203 204 /* Only accept code in the pix map table */ 205 vpix = dcmipp_par_pix_map_by_code(IS_SINK(pad) ? fmt->code : 0, 206 IS_SRC(pad) ? fmt->code : 0); 207 if (!vpix) 208 fmt->code = fmt_default.code; 209 210 /* Exclude JPEG if BT656 bus is selected */ 211 if (vpix && vpix->code_sink == MEDIA_BUS_FMT_JPEG_1X8 && 212 par->ved.bus_type == V4L2_MBUS_BT656) 213 fmt->code = fmt_default.code; 214 215 fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH, 216 DCMIPP_FRAME_MAX_WIDTH) & ~1; 217 fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT, 218 DCMIPP_FRAME_MAX_HEIGHT) & ~1; 219 220 if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE) 221 fmt->field = fmt_default.field; 222 223 dcmipp_colorimetry_clamp(fmt); 224 } 225 226 static int dcmipp_par_set_fmt(struct v4l2_subdev *sd, 227 struct v4l2_subdev_state *sd_state, 228 struct v4l2_subdev_format *fmt) 229 { 230 struct dcmipp_par_device *par = v4l2_get_subdevdata(sd); 231 struct v4l2_mbus_framefmt *mf; 232 233 if (par->streaming) 234 return -EBUSY; 235 236 mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); 237 238 /* Set the new format */ 239 dcmipp_par_adjust_fmt(par, &fmt->format, fmt->pad); 240 241 dev_dbg(par->dev, "%s: format update: old:%dx%d (0x%x, %d, %d, %d, %d) new:%dx%d (0x%x, %d, %d, %d, %d)\n", 242 par->sd.name, 243 /* old */ 244 mf->width, mf->height, mf->code, 245 mf->colorspace, mf->quantization, 246 mf->xfer_func, mf->ycbcr_enc, 247 /* new */ 248 fmt->format.width, fmt->format.height, fmt->format.code, 249 fmt->format.colorspace, fmt->format.quantization, 250 fmt->format.xfer_func, fmt->format.ycbcr_enc); 251 252 *mf = fmt->format; 253 254 /* When setting the sink format, report that format on the src pad */ 255 if (IS_SINK(fmt->pad)) { 256 mf = v4l2_subdev_state_get_format(sd_state, 1); 257 *mf = fmt->format; 258 dcmipp_par_adjust_fmt(par, mf, 1); 259 } 260 261 return 0; 262 } 263 264 static const struct v4l2_subdev_pad_ops dcmipp_par_pad_ops = { 265 .enum_mbus_code = dcmipp_par_enum_mbus_code, 266 .enum_frame_size = dcmipp_par_enum_frame_size, 267 .get_fmt = v4l2_subdev_get_fmt, 268 .set_fmt = dcmipp_par_set_fmt, 269 }; 270 271 static int dcmipp_par_configure(struct dcmipp_par_device *par) 272 { 273 u32 val = 0; 274 const struct dcmipp_par_pix_map *vpix; 275 struct v4l2_subdev_state *state; 276 struct v4l2_mbus_framefmt *sink_fmt; 277 struct v4l2_mbus_framefmt *src_fmt; 278 279 /* Set vertical synchronization polarity */ 280 if (par->ved.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) 281 val |= DCMIPP_PRCR_VSPOL; 282 283 /* Set horizontal synchronization polarity */ 284 if (par->ved.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 285 val |= DCMIPP_PRCR_HSPOL; 286 287 /* Set pixel clock polarity */ 288 if (par->ved.bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 289 val |= DCMIPP_PRCR_PCKPOL; 290 291 /* 292 * BT656 embedded synchronisation bus mode. 293 * 294 * Default SAV/EAV mode is supported here with default codes 295 * SAV=0xff000080 & EAV=0xff00009d. 296 * With DCMIPP this means LSC=SAV=0x80 & LEC=EAV=0x9d. 297 */ 298 if (par->ved.bus_type == V4L2_MBUS_BT656) { 299 val |= DCMIPP_PRCR_ESS; 300 301 /* Unmask all codes */ 302 reg_write(par, DCMIPP_PRESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */ 303 304 /* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */ 305 reg_write(par, DCMIPP_PRESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */ 306 } 307 308 /* Set format */ 309 state = v4l2_subdev_lock_and_get_active_state(&par->sd); 310 sink_fmt = v4l2_subdev_state_get_format(state, 0); 311 src_fmt = v4l2_subdev_state_get_format(state, 1); 312 v4l2_subdev_unlock_state(state); 313 314 vpix = dcmipp_par_pix_map_by_code(sink_fmt->code, src_fmt->code); 315 if (!vpix) { 316 dev_err(par->dev, "Invalid sink/src format configuration\n"); 317 return -EINVAL; 318 } 319 320 val |= vpix->prcr_format << DCMIPP_PRCR_FORMAT_SHIFT; 321 322 /* swap cycles */ 323 if (vpix->prcr_swapcycles) 324 val |= DCMIPP_PRCR_SWAPCYCLES; 325 326 reg_write(par, DCMIPP_PRCR, val); 327 328 return 0; 329 } 330 331 static int dcmipp_par_s_stream(struct v4l2_subdev *sd, int enable) 332 { 333 struct dcmipp_par_device *par = 334 container_of(sd, struct dcmipp_par_device, sd); 335 struct v4l2_subdev *s_subdev; 336 struct media_pad *pad; 337 int ret = 0; 338 339 /* Get source subdev */ 340 pad = media_pad_remote_pad_first(&sd->entity.pads[0]); 341 if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 342 return -EINVAL; 343 s_subdev = media_entity_to_v4l2_subdev(pad->entity); 344 345 if (enable) { 346 ret = dcmipp_par_configure(par); 347 if (ret) 348 return ret; 349 350 /* Enable parallel interface */ 351 reg_set(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE); 352 353 ret = v4l2_subdev_call(s_subdev, video, s_stream, enable); 354 if (ret < 0) { 355 dev_err(par->dev, 356 "failed to start source subdev streaming (%d)\n", 357 ret); 358 return ret; 359 } 360 } else { 361 ret = v4l2_subdev_call(s_subdev, video, s_stream, enable); 362 if (ret < 0) { 363 dev_err(par->dev, 364 "failed to stop source subdev streaming (%d)\n", 365 ret); 366 return ret; 367 } 368 369 /* Disable parallel interface */ 370 reg_clear(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE); 371 } 372 373 par->streaming = enable; 374 375 return ret; 376 } 377 378 static const struct v4l2_subdev_video_ops dcmipp_par_video_ops = { 379 .s_stream = dcmipp_par_s_stream, 380 }; 381 382 static const struct v4l2_subdev_ops dcmipp_par_ops = { 383 .pad = &dcmipp_par_pad_ops, 384 .video = &dcmipp_par_video_ops, 385 }; 386 387 static void dcmipp_par_release(struct v4l2_subdev *sd) 388 { 389 struct dcmipp_par_device *par = 390 container_of(sd, struct dcmipp_par_device, sd); 391 392 kfree(par); 393 } 394 395 static const struct v4l2_subdev_internal_ops dcmipp_par_int_ops = { 396 .init_state = dcmipp_par_init_state, 397 .release = dcmipp_par_release, 398 }; 399 400 void dcmipp_par_ent_release(struct dcmipp_ent_device *ved) 401 { 402 struct dcmipp_par_device *par = 403 container_of(ved, struct dcmipp_par_device, ved); 404 405 dcmipp_ent_sd_unregister(ved, &par->sd); 406 } 407 408 struct dcmipp_ent_device *dcmipp_par_ent_init(struct device *dev, 409 const char *entity_name, 410 struct v4l2_device *v4l2_dev, 411 void __iomem *regs) 412 { 413 struct dcmipp_par_device *par; 414 const unsigned long pads_flag[] = { 415 MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE, 416 }; 417 int ret; 418 419 /* Allocate the par struct */ 420 par = kzalloc(sizeof(*par), GFP_KERNEL); 421 if (!par) 422 return ERR_PTR(-ENOMEM); 423 424 par->regs = regs; 425 426 /* Initialize ved and sd */ 427 ret = dcmipp_ent_sd_register(&par->ved, &par->sd, v4l2_dev, 428 entity_name, MEDIA_ENT_F_VID_IF_BRIDGE, 429 ARRAY_SIZE(pads_flag), pads_flag, 430 &dcmipp_par_int_ops, &dcmipp_par_ops, 431 NULL, NULL); 432 if (ret) { 433 kfree(par); 434 return ERR_PTR(ret); 435 } 436 437 par->dev = dev; 438 439 return &par->ved; 440 } 441