1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Register interface file for Samsung Camera Interface (FIMC) driver 4 * 5 * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd. 6 * Sylwester Nawrocki <s.nawrocki@samsung.com> 7 */ 8 9 #include <linux/delay.h> 10 #include <linux/io.h> 11 #include <linux/regmap.h> 12 13 #include <media/drv-intf/exynos-fimc.h> 14 #include "media-dev.h" 15 16 #include "fimc-reg.h" 17 #include "fimc-core.h" 18 19 void fimc_hw_reset(struct fimc_dev *dev) 20 { 21 u32 cfg; 22 23 cfg = readl(dev->regs + FIMC_REG_CISRCFMT); 24 cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; 25 writel(cfg, dev->regs + FIMC_REG_CISRCFMT); 26 27 /* Software reset. */ 28 cfg = readl(dev->regs + FIMC_REG_CIGCTRL); 29 cfg |= (FIMC_REG_CIGCTRL_SWRST | FIMC_REG_CIGCTRL_IRQ_LEVEL); 30 writel(cfg, dev->regs + FIMC_REG_CIGCTRL); 31 udelay(10); 32 33 cfg = readl(dev->regs + FIMC_REG_CIGCTRL); 34 cfg &= ~FIMC_REG_CIGCTRL_SWRST; 35 writel(cfg, dev->regs + FIMC_REG_CIGCTRL); 36 37 if (dev->drv_data->out_buf_count > 4) 38 fimc_hw_set_dma_seq(dev, 0xF); 39 } 40 41 static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) 42 { 43 u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL; 44 45 if (ctx->hflip) 46 flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR; 47 if (ctx->vflip) 48 flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR; 49 50 if (ctx->rotation <= 90) 51 return flip; 52 53 return (flip ^ FIMC_REG_MSCTRL_FLIP_180) & FIMC_REG_MSCTRL_FLIP_180; 54 } 55 56 static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx) 57 { 58 u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL; 59 60 if (ctx->hflip) 61 flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR; 62 if (ctx->vflip) 63 flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR; 64 65 if (ctx->rotation <= 90) 66 return flip; 67 68 return (flip ^ FIMC_REG_CITRGFMT_FLIP_180) & FIMC_REG_CITRGFMT_FLIP_180; 69 } 70 71 void fimc_hw_set_rotation(struct fimc_ctx *ctx) 72 { 73 u32 cfg, flip; 74 struct fimc_dev *dev = ctx->fimc_dev; 75 76 cfg = readl(dev->regs + FIMC_REG_CITRGFMT); 77 cfg &= ~(FIMC_REG_CITRGFMT_INROT90 | FIMC_REG_CITRGFMT_OUTROT90 | 78 FIMC_REG_CITRGFMT_FLIP_180); 79 80 /* 81 * The input and output rotator cannot work simultaneously. 82 * Use the output rotator in output DMA mode or the input rotator 83 * in direct fifo output mode. 84 */ 85 if (ctx->rotation == 90 || ctx->rotation == 270) { 86 if (ctx->out_path == FIMC_IO_LCDFIFO) 87 cfg |= FIMC_REG_CITRGFMT_INROT90; 88 else 89 cfg |= FIMC_REG_CITRGFMT_OUTROT90; 90 } 91 92 if (ctx->out_path == FIMC_IO_DMA) { 93 cfg |= fimc_hw_get_target_flip(ctx); 94 writel(cfg, dev->regs + FIMC_REG_CITRGFMT); 95 } else { 96 /* LCD FIFO path */ 97 flip = readl(dev->regs + FIMC_REG_MSCTRL); 98 flip &= ~FIMC_REG_MSCTRL_FLIP_MASK; 99 flip |= fimc_hw_get_in_flip(ctx); 100 writel(flip, dev->regs + FIMC_REG_MSCTRL); 101 } 102 } 103 104 void fimc_hw_set_target_format(struct fimc_ctx *ctx) 105 { 106 u32 cfg; 107 struct fimc_dev *dev = ctx->fimc_dev; 108 const struct fimc_frame *frame = &ctx->d_frame; 109 110 dbg("w= %d, h= %d color: %d", frame->width, 111 frame->height, frame->fmt->color); 112 113 cfg = readl(dev->regs + FIMC_REG_CITRGFMT); 114 cfg &= ~(FIMC_REG_CITRGFMT_FMT_MASK | FIMC_REG_CITRGFMT_HSIZE_MASK | 115 FIMC_REG_CITRGFMT_VSIZE_MASK); 116 117 switch (frame->fmt->color) { 118 case FIMC_FMT_RGB444...FIMC_FMT_RGB888: 119 cfg |= FIMC_REG_CITRGFMT_RGB; 120 break; 121 case FIMC_FMT_YCBCR420: 122 cfg |= FIMC_REG_CITRGFMT_YCBCR420; 123 break; 124 case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: 125 if (frame->fmt->colplanes == 1) 126 cfg |= FIMC_REG_CITRGFMT_YCBCR422_1P; 127 else 128 cfg |= FIMC_REG_CITRGFMT_YCBCR422; 129 break; 130 default: 131 break; 132 } 133 134 if (ctx->rotation == 90 || ctx->rotation == 270) 135 cfg |= (frame->height << 16) | frame->width; 136 else 137 cfg |= (frame->width << 16) | frame->height; 138 139 writel(cfg, dev->regs + FIMC_REG_CITRGFMT); 140 141 cfg = readl(dev->regs + FIMC_REG_CITAREA); 142 cfg &= ~FIMC_REG_CITAREA_MASK; 143 cfg |= (frame->width * frame->height); 144 writel(cfg, dev->regs + FIMC_REG_CITAREA); 145 } 146 147 static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) 148 { 149 struct fimc_dev *dev = ctx->fimc_dev; 150 const struct fimc_frame *frame = &ctx->d_frame; 151 u32 cfg; 152 153 cfg = (frame->f_height << 16) | frame->f_width; 154 writel(cfg, dev->regs + FIMC_REG_ORGOSIZE); 155 156 /* Select color space conversion equation (HD/SD size).*/ 157 cfg = readl(dev->regs + FIMC_REG_CIGCTRL); 158 if (frame->f_width >= 1280) /* HD */ 159 cfg |= FIMC_REG_CIGCTRL_CSC_ITU601_709; 160 else /* SD */ 161 cfg &= ~FIMC_REG_CIGCTRL_CSC_ITU601_709; 162 writel(cfg, dev->regs + FIMC_REG_CIGCTRL); 163 164 } 165 166 void fimc_hw_set_out_dma(struct fimc_ctx *ctx) 167 { 168 struct fimc_dev *dev = ctx->fimc_dev; 169 const struct fimc_frame *frame = &ctx->d_frame; 170 const struct fimc_dma_offset *offset = &frame->dma_offset; 171 const struct fimc_fmt *fmt = frame->fmt; 172 u32 cfg; 173 174 /* Set the input dma offsets. */ 175 cfg = (offset->y_v << 16) | offset->y_h; 176 writel(cfg, dev->regs + FIMC_REG_CIOYOFF); 177 178 cfg = (offset->cb_v << 16) | offset->cb_h; 179 writel(cfg, dev->regs + FIMC_REG_CIOCBOFF); 180 181 cfg = (offset->cr_v << 16) | offset->cr_h; 182 writel(cfg, dev->regs + FIMC_REG_CIOCROFF); 183 184 fimc_hw_set_out_dma_size(ctx); 185 186 /* Configure chroma components order. */ 187 cfg = readl(dev->regs + FIMC_REG_CIOCTRL); 188 189 cfg &= ~(FIMC_REG_CIOCTRL_ORDER2P_MASK | 190 FIMC_REG_CIOCTRL_ORDER422_MASK | 191 FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK | 192 FIMC_REG_CIOCTRL_RGB16FMT_MASK); 193 194 if (fmt->colplanes == 1) 195 cfg |= ctx->out_order_1p; 196 else if (fmt->colplanes == 2) 197 cfg |= ctx->out_order_2p | FIMC_REG_CIOCTRL_YCBCR_2PLANE; 198 else if (fmt->colplanes == 3) 199 cfg |= FIMC_REG_CIOCTRL_YCBCR_3PLANE; 200 201 if (fmt->color == FIMC_FMT_RGB565) 202 cfg |= FIMC_REG_CIOCTRL_RGB565; 203 else if (fmt->color == FIMC_FMT_RGB555) 204 cfg |= FIMC_REG_CIOCTRL_ARGB1555; 205 else if (fmt->color == FIMC_FMT_RGB444) 206 cfg |= FIMC_REG_CIOCTRL_ARGB4444; 207 208 writel(cfg, dev->regs + FIMC_REG_CIOCTRL); 209 } 210 211 static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable) 212 { 213 u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE); 214 if (enable) 215 cfg |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; 216 else 217 cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; 218 writel(cfg, dev->regs + FIMC_REG_ORGISIZE); 219 } 220 221 void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) 222 { 223 u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL); 224 if (enable) 225 cfg |= FIMC_REG_CIOCTRL_LASTIRQ_ENABLE; 226 else 227 cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE; 228 writel(cfg, dev->regs + FIMC_REG_CIOCTRL); 229 } 230 231 void fimc_hw_set_prescaler(struct fimc_ctx *ctx) 232 { 233 struct fimc_dev *dev = ctx->fimc_dev; 234 struct fimc_scaler *sc = &ctx->scaler; 235 u32 cfg, shfactor; 236 237 shfactor = 10 - (sc->hfactor + sc->vfactor); 238 cfg = shfactor << 28; 239 240 cfg |= (sc->pre_hratio << 16) | sc->pre_vratio; 241 writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO); 242 243 cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height; 244 writel(cfg, dev->regs + FIMC_REG_CISCPREDST); 245 } 246 247 static void fimc_hw_set_scaler(struct fimc_ctx *ctx) 248 { 249 struct fimc_dev *dev = ctx->fimc_dev; 250 struct fimc_scaler *sc = &ctx->scaler; 251 const struct fimc_frame *src_frame = &ctx->s_frame; 252 const struct fimc_frame *dst_frame = &ctx->d_frame; 253 254 u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); 255 256 cfg &= ~(FIMC_REG_CISCCTRL_CSCR2Y_WIDE | FIMC_REG_CISCCTRL_CSCY2R_WIDE | 257 FIMC_REG_CISCCTRL_SCALEUP_H | FIMC_REG_CISCCTRL_SCALEUP_V | 258 FIMC_REG_CISCCTRL_SCALERBYPASS | FIMC_REG_CISCCTRL_ONE2ONE | 259 FIMC_REG_CISCCTRL_INRGB_FMT_MASK | FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK | 260 FIMC_REG_CISCCTRL_INTERLACE | FIMC_REG_CISCCTRL_RGB_EXT); 261 262 if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) 263 cfg |= (FIMC_REG_CISCCTRL_CSCR2Y_WIDE | 264 FIMC_REG_CISCCTRL_CSCY2R_WIDE); 265 266 if (!sc->enabled) 267 cfg |= FIMC_REG_CISCCTRL_SCALERBYPASS; 268 269 if (sc->scaleup_h) 270 cfg |= FIMC_REG_CISCCTRL_SCALEUP_H; 271 272 if (sc->scaleup_v) 273 cfg |= FIMC_REG_CISCCTRL_SCALEUP_V; 274 275 if (sc->copy_mode) 276 cfg |= FIMC_REG_CISCCTRL_ONE2ONE; 277 278 if (ctx->in_path == FIMC_IO_DMA) { 279 switch (src_frame->fmt->color) { 280 case FIMC_FMT_RGB565: 281 cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB565; 282 break; 283 case FIMC_FMT_RGB666: 284 cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB666; 285 break; 286 case FIMC_FMT_RGB888: 287 cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB888; 288 break; 289 } 290 } 291 292 if (ctx->out_path == FIMC_IO_DMA) { 293 u32 color = dst_frame->fmt->color; 294 295 if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565) 296 cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565; 297 else if (color == FIMC_FMT_RGB666) 298 cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666; 299 else if (color == FIMC_FMT_RGB888) 300 cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888; 301 } else { 302 cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888; 303 304 if (ctx->flags & FIMC_SCAN_MODE_INTERLACED) 305 cfg |= FIMC_REG_CISCCTRL_INTERLACE; 306 } 307 308 writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 309 } 310 311 void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) 312 { 313 struct fimc_dev *dev = ctx->fimc_dev; 314 const struct fimc_variant *variant = dev->variant; 315 struct fimc_scaler *sc = &ctx->scaler; 316 u32 cfg; 317 318 dbg("main_hratio= 0x%X main_vratio= 0x%X", 319 sc->main_hratio, sc->main_vratio); 320 321 fimc_hw_set_scaler(ctx); 322 323 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); 324 cfg &= ~(FIMC_REG_CISCCTRL_MHRATIO_MASK | 325 FIMC_REG_CISCCTRL_MVRATIO_MASK); 326 327 if (variant->has_mainscaler_ext) { 328 cfg |= FIMC_REG_CISCCTRL_MHRATIO_EXT(sc->main_hratio); 329 cfg |= FIMC_REG_CISCCTRL_MVRATIO_EXT(sc->main_vratio); 330 writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 331 332 cfg = readl(dev->regs + FIMC_REG_CIEXTEN); 333 334 cfg &= ~(FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK | 335 FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK); 336 cfg |= FIMC_REG_CIEXTEN_MHRATIO_EXT(sc->main_hratio); 337 cfg |= FIMC_REG_CIEXTEN_MVRATIO_EXT(sc->main_vratio); 338 writel(cfg, dev->regs + FIMC_REG_CIEXTEN); 339 } else { 340 cfg |= FIMC_REG_CISCCTRL_MHRATIO(sc->main_hratio); 341 cfg |= FIMC_REG_CISCCTRL_MVRATIO(sc->main_vratio); 342 writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 343 } 344 } 345 346 void fimc_hw_enable_capture(struct fimc_ctx *ctx) 347 { 348 struct fimc_dev *dev = ctx->fimc_dev; 349 u32 cfg; 350 351 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT); 352 cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE; 353 354 if (ctx->scaler.enabled) 355 cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC; 356 else 357 cfg &= FIMC_REG_CIIMGCPT_IMGCPTEN_SC; 358 359 cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN; 360 writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); 361 } 362 363 void fimc_hw_disable_capture(struct fimc_dev *dev) 364 { 365 u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT); 366 cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN | 367 FIMC_REG_CIIMGCPT_IMGCPTEN_SC); 368 writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); 369 } 370 371 void fimc_hw_set_effect(struct fimc_ctx *ctx) 372 { 373 struct fimc_dev *dev = ctx->fimc_dev; 374 struct fimc_effect *effect = &ctx->effect; 375 u32 cfg = 0; 376 377 if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) { 378 cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER | 379 FIMC_REG_CIIMGEFF_IE_ENABLE; 380 cfg |= effect->type; 381 if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY) 382 cfg |= (effect->pat_cb << 13) | effect->pat_cr; 383 } 384 385 writel(cfg, dev->regs + FIMC_REG_CIIMGEFF); 386 } 387 388 void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) 389 { 390 struct fimc_dev *dev = ctx->fimc_dev; 391 const struct fimc_frame *frame = &ctx->d_frame; 392 u32 cfg; 393 394 if (!(frame->fmt->flags & FMT_HAS_ALPHA)) 395 return; 396 397 cfg = readl(dev->regs + FIMC_REG_CIOCTRL); 398 cfg &= ~FIMC_REG_CIOCTRL_ALPHA_OUT_MASK; 399 cfg |= (frame->alpha << 4); 400 writel(cfg, dev->regs + FIMC_REG_CIOCTRL); 401 } 402 403 static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) 404 { 405 struct fimc_dev *dev = ctx->fimc_dev; 406 const struct fimc_frame *frame = &ctx->s_frame; 407 u32 cfg_o = 0; 408 u32 cfg_r = 0; 409 410 if (FIMC_IO_LCDFIFO == ctx->out_path) 411 cfg_r |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; 412 413 cfg_o |= (frame->f_height << 16) | frame->f_width; 414 cfg_r |= (frame->height << 16) | frame->width; 415 416 writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE); 417 writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE); 418 } 419 420 void fimc_hw_set_in_dma(struct fimc_ctx *ctx) 421 { 422 struct fimc_dev *dev = ctx->fimc_dev; 423 const struct fimc_frame *frame = &ctx->s_frame; 424 const struct fimc_dma_offset *offset = &frame->dma_offset; 425 u32 cfg; 426 427 /* Set the pixel offsets. */ 428 cfg = (offset->y_v << 16) | offset->y_h; 429 writel(cfg, dev->regs + FIMC_REG_CIIYOFF); 430 431 cfg = (offset->cb_v << 16) | offset->cb_h; 432 writel(cfg, dev->regs + FIMC_REG_CIICBOFF); 433 434 cfg = (offset->cr_v << 16) | offset->cr_h; 435 writel(cfg, dev->regs + FIMC_REG_CIICROFF); 436 437 /* Input original and real size. */ 438 fimc_hw_set_in_dma_size(ctx); 439 440 /* Use DMA autoload only in FIFO mode. */ 441 fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO); 442 443 /* Set the input DMA to process single frame only. */ 444 cfg = readl(dev->regs + FIMC_REG_MSCTRL); 445 cfg &= ~(FIMC_REG_MSCTRL_INFORMAT_MASK 446 | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK 447 | FIMC_REG_MSCTRL_INPUT_MASK 448 | FIMC_REG_MSCTRL_C_INT_IN_MASK 449 | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK 450 | FIMC_REG_MSCTRL_ORDER422_MASK); 451 452 cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4) 453 | FIMC_REG_MSCTRL_INPUT_MEMORY 454 | FIMC_REG_MSCTRL_FIFO_CTRL_FULL); 455 456 switch (frame->fmt->color) { 457 case FIMC_FMT_RGB565...FIMC_FMT_RGB888: 458 cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB; 459 break; 460 case FIMC_FMT_YCBCR420: 461 cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420; 462 463 if (frame->fmt->colplanes == 2) 464 cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; 465 else 466 cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; 467 468 break; 469 case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: 470 if (frame->fmt->colplanes == 1) { 471 cfg |= ctx->in_order_1p 472 | FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P; 473 } else { 474 cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422; 475 476 if (frame->fmt->colplanes == 2) 477 cfg |= ctx->in_order_2p 478 | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; 479 else 480 cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; 481 } 482 break; 483 default: 484 break; 485 } 486 487 writel(cfg, dev->regs + FIMC_REG_MSCTRL); 488 489 /* Input/output DMA linear/tiled mode. */ 490 cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM); 491 cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK; 492 493 if (tiled_fmt(ctx->s_frame.fmt)) 494 cfg |= FIMC_REG_CIDMAPARAM_R_64X32; 495 496 if (tiled_fmt(ctx->d_frame.fmt)) 497 cfg |= FIMC_REG_CIDMAPARAM_W_64X32; 498 499 writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM); 500 } 501 502 503 void fimc_hw_set_input_path(struct fimc_ctx *ctx) 504 { 505 struct fimc_dev *dev = ctx->fimc_dev; 506 507 u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); 508 cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK; 509 510 if (ctx->in_path == FIMC_IO_DMA) 511 cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY; 512 else 513 cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM; 514 515 writel(cfg, dev->regs + FIMC_REG_MSCTRL); 516 } 517 518 void fimc_hw_set_output_path(struct fimc_ctx *ctx) 519 { 520 struct fimc_dev *dev = ctx->fimc_dev; 521 522 u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); 523 cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; 524 if (ctx->out_path == FIMC_IO_LCDFIFO) 525 cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; 526 writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 527 } 528 529 void fimc_hw_set_input_addr(struct fimc_dev *dev, const struct fimc_addr *addr) 530 { 531 u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE); 532 cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; 533 writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); 534 535 writel(addr->y, dev->regs + FIMC_REG_CIIYSA(0)); 536 writel(addr->cb, dev->regs + FIMC_REG_CIICBSA(0)); 537 writel(addr->cr, dev->regs + FIMC_REG_CIICRSA(0)); 538 539 cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; 540 writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); 541 } 542 543 void fimc_hw_set_output_addr(struct fimc_dev *dev, 544 const struct fimc_addr *addr, int index) 545 { 546 int i = (index == -1) ? 0 : index; 547 do { 548 writel(addr->y, dev->regs + FIMC_REG_CIOYSA(i)); 549 writel(addr->cb, dev->regs + FIMC_REG_CIOCBSA(i)); 550 writel(addr->cr, dev->regs + FIMC_REG_CIOCRSA(i)); 551 dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", 552 i, addr->y, addr->cb, addr->cr); 553 } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); 554 } 555 556 int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, 557 const struct fimc_source_info *cam) 558 { 559 u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); 560 561 cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC | 562 FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC | 563 FIMC_REG_CIGCTRL_INVPOLFIELD); 564 565 if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) 566 cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK; 567 568 if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 569 cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC; 570 571 if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 572 cfg |= FIMC_REG_CIGCTRL_INVPOLHREF; 573 574 if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 575 cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC; 576 577 if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW) 578 cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD; 579 580 writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); 581 582 return 0; 583 } 584 585 struct mbus_pixfmt_desc { 586 u32 pixelcode; 587 u32 cisrcfmt; 588 u16 bus_width; 589 }; 590 591 static const struct mbus_pixfmt_desc pix_desc[] = { 592 { MEDIA_BUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 }, 593 { MEDIA_BUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 }, 594 { MEDIA_BUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 }, 595 { MEDIA_BUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 }, 596 }; 597 598 int fimc_hw_set_camera_source(struct fimc_dev *fimc, 599 struct fimc_source_info *source) 600 { 601 const struct fimc_vid_cap *vc = &fimc->vid_cap; 602 const struct fimc_frame *f = &vc->ctx->s_frame; 603 u32 bus_width, cfg = 0; 604 int i; 605 606 switch (source->fimc_bus_type) { 607 case FIMC_BUS_TYPE_ITU_601: 608 case FIMC_BUS_TYPE_ITU_656: 609 if (fimc_fmt_is_user_defined(f->fmt->color)) { 610 cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; 611 break; 612 } 613 614 for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { 615 if (vc->ci_fmt.code == pix_desc[i].pixelcode) { 616 cfg = pix_desc[i].cisrcfmt; 617 bus_width = pix_desc[i].bus_width; 618 break; 619 } 620 } 621 622 if (i == ARRAY_SIZE(pix_desc)) { 623 v4l2_err(&vc->ve.vdev, 624 "Camera color format not supported: %d\n", 625 vc->ci_fmt.code); 626 return -EINVAL; 627 } 628 629 if (source->fimc_bus_type == FIMC_BUS_TYPE_ITU_601) { 630 if (bus_width == 8) 631 cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; 632 else if (bus_width == 16) 633 cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT; 634 } /* else defaults to ITU-R BT.656 8-bit */ 635 break; 636 case FIMC_BUS_TYPE_MIPI_CSI2: 637 if (fimc_fmt_is_user_defined(f->fmt->color)) 638 cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; 639 break; 640 default: 641 case FIMC_BUS_TYPE_ISP_WRITEBACK: 642 /* Anything to do here ? */ 643 break; 644 } 645 646 cfg |= (f->o_width << 16) | f->o_height; 647 writel(cfg, fimc->regs + FIMC_REG_CISRCFMT); 648 return 0; 649 } 650 651 void fimc_hw_set_camera_offset(struct fimc_dev *fimc, const struct fimc_frame *f) 652 { 653 u32 hoff2, voff2; 654 655 u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST); 656 657 cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK); 658 cfg |= FIMC_REG_CIWDOFST_OFF_EN | 659 (f->offs_h << 16) | f->offs_v; 660 661 writel(cfg, fimc->regs + FIMC_REG_CIWDOFST); 662 663 /* See CIWDOFSTn register description in the datasheet for details. */ 664 hoff2 = f->o_width - f->width - f->offs_h; 665 voff2 = f->o_height - f->height - f->offs_v; 666 cfg = (hoff2 << 16) | voff2; 667 writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2); 668 } 669 670 int fimc_hw_set_camera_type(struct fimc_dev *fimc, 671 const struct fimc_source_info *source) 672 { 673 const struct fimc_vid_cap *vid_cap = &fimc->vid_cap; 674 u32 csis_data_alignment = 32; 675 u32 cfg, tmp; 676 677 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); 678 679 /* Select ITU B interface, disable Writeback path and test pattern. */ 680 cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A | 681 FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB | 682 FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG | 683 FIMC_REG_CIGCTRL_SELWB_A); 684 685 switch (source->fimc_bus_type) { 686 case FIMC_BUS_TYPE_MIPI_CSI2: 687 cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI; 688 689 if (source->mux_id == 0) 690 cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A; 691 692 /* TODO: add remaining supported formats. */ 693 switch (vid_cap->ci_fmt.code) { 694 case MEDIA_BUS_FMT_VYUY8_2X8: 695 tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; 696 break; 697 case MEDIA_BUS_FMT_JPEG_1X8: 698 case MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8: 699 tmp = FIMC_REG_CSIIMGFMT_USER(1); 700 cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; 701 break; 702 default: 703 v4l2_err(&vid_cap->ve.vdev, 704 "Not supported camera pixel format: %#x\n", 705 vid_cap->ci_fmt.code); 706 return -EINVAL; 707 } 708 tmp |= (csis_data_alignment == 32) << 8; 709 710 writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT); 711 break; 712 case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656: 713 if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ 714 cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A; 715 if (vid_cap->ci_fmt.code == MEDIA_BUS_FMT_JPEG_1X8) 716 cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; 717 break; 718 case FIMC_BUS_TYPE_LCD_WRITEBACK_A: 719 cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; 720 fallthrough; 721 case FIMC_BUS_TYPE_ISP_WRITEBACK: 722 if (fimc->variant->has_isp_wb) 723 cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; 724 else 725 WARN_ONCE(1, "ISP Writeback input is not supported\n"); 726 break; 727 default: 728 v4l2_err(&vid_cap->ve.vdev, 729 "Invalid FIMC bus type selected: %d\n", 730 source->fimc_bus_type); 731 return -EINVAL; 732 } 733 writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); 734 735 return 0; 736 } 737 738 void fimc_hw_clear_irq(struct fimc_dev *dev) 739 { 740 u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL); 741 cfg |= FIMC_REG_CIGCTRL_IRQ_CLR; 742 writel(cfg, dev->regs + FIMC_REG_CIGCTRL); 743 } 744 745 void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on) 746 { 747 u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); 748 if (on) 749 cfg |= FIMC_REG_CISCCTRL_SCALERSTART; 750 else 751 cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART; 752 writel(cfg, dev->regs + FIMC_REG_CISCCTRL); 753 } 754 755 void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on) 756 { 757 u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); 758 if (on) 759 cfg |= FIMC_REG_MSCTRL_ENVID; 760 else 761 cfg &= ~FIMC_REG_MSCTRL_ENVID; 762 writel(cfg, dev->regs + FIMC_REG_MSCTRL); 763 } 764 765 /* Return an index to the buffer actually being written. */ 766 s32 fimc_hw_get_frame_index(struct fimc_dev *dev) 767 { 768 s32 reg; 769 770 if (dev->drv_data->cistatus2) { 771 reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; 772 return reg - 1; 773 } 774 775 reg = readl(dev->regs + FIMC_REG_CISTATUS); 776 777 return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >> 778 FIMC_REG_CISTATUS_FRAMECNT_SHIFT; 779 } 780 781 /* Return an index to the buffer being written previously. */ 782 s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) 783 { 784 s32 reg; 785 786 if (!dev->drv_data->cistatus2) 787 return -1; 788 789 reg = readl(dev->regs + FIMC_REG_CISTATUS2); 790 return ((reg >> 7) & 0x3f) - 1; 791 } 792 793 /* Locking: the caller holds fimc->slock */ 794 void fimc_activate_capture(struct fimc_ctx *ctx) 795 { 796 fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled); 797 fimc_hw_enable_capture(ctx); 798 } 799 800 void fimc_deactivate_capture(struct fimc_dev *fimc) 801 { 802 fimc_hw_en_lastirq(fimc, true); 803 fimc_hw_disable_capture(fimc); 804 fimc_hw_enable_scaler(fimc, false); 805 fimc_hw_en_lastirq(fimc, false); 806 } 807 808 int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc) 809 { 810 struct regmap *map = fimc->sysreg; 811 unsigned int mask, val, camblk_cfg; 812 int ret; 813 814 if (map == NULL) 815 return 0; 816 817 ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg); 818 if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3)) 819 return ret; 820 821 if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id)) 822 val = 0x1 << (fimc->id + 20); 823 else 824 val = 0; 825 826 mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN; 827 ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); 828 if (ret < 0) 829 return ret; 830 831 usleep_range(1000, 2000); 832 833 val |= SYSREG_CAMBLK_FIFORST_ISP; 834 ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); 835 if (ret < 0) 836 return ret; 837 838 mask = SYSREG_ISPBLK_FIFORST_CAM_BLK; 839 ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask); 840 if (ret < 0) 841 return ret; 842 843 usleep_range(1000, 2000); 844 845 return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask); 846 } 847