1/* 2 * Register interface file for Samsung Camera Interface (FIMC) driver 3 * 4 * Copyright (c) 2010 Samsung Electronics 5 * 6 * Sylwester Nawrocki, s.nawrocki@samsung.com 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11*/ 12 13#include <linux/io.h> 14#include <linux/delay.h> 15#include <mach/map.h> 16#include <media/s5p_fimc.h> 17 18#include "fimc-core.h" 19 20 21void fimc_hw_reset(struct fimc_dev *dev) 22{ 23 u32 cfg; 24 25 cfg = readl(dev->regs + S5P_CISRCFMT); 26 cfg |= S5P_CISRCFMT_ITU601_8BIT; 27 writel(cfg, dev->regs + S5P_CISRCFMT); 28 29 /* Software reset. */ 30 cfg = readl(dev->regs + S5P_CIGCTRL); 31 cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL); 32 writel(cfg, dev->regs + S5P_CIGCTRL); 33 udelay(10); 34 35 cfg = readl(dev->regs + S5P_CIGCTRL); 36 cfg &= ~S5P_CIGCTRL_SWRST; 37 writel(cfg, dev->regs + S5P_CIGCTRL); 38 39 if (dev->variant->out_buf_count > 4) 40 fimc_hw_set_dma_seq(dev, 0xF); 41} 42 43static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) 44{ 45 u32 flip = S5P_MSCTRL_FLIP_NORMAL; 46 47 if (ctx->hflip) 48 flip = S5P_MSCTRL_FLIP_X_MIRROR; 49 if (ctx->vflip) 50 flip = S5P_MSCTRL_FLIP_Y_MIRROR; 51 52 if (ctx->rotation <= 90) 53 return flip; 54 55 return (flip ^ S5P_MSCTRL_FLIP_180) & S5P_MSCTRL_FLIP_180; 56} 57 58static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx) 59{ 60 u32 flip = S5P_CITRGFMT_FLIP_NORMAL; 61 62 if (ctx->hflip) 63 flip |= S5P_CITRGFMT_FLIP_X_MIRROR; 64 if (ctx->vflip) 65 flip |= S5P_CITRGFMT_FLIP_Y_MIRROR; 66 67 if (ctx->rotation <= 90) 68 return flip; 69 70 return (flip ^ S5P_CITRGFMT_FLIP_180) & S5P_CITRGFMT_FLIP_180; 71} 72 73void fimc_hw_set_rotation(struct fimc_ctx *ctx) 74{ 75 u32 cfg, flip; 76 struct fimc_dev *dev = ctx->fimc_dev; 77 78 cfg = readl(dev->regs + S5P_CITRGFMT); 79 cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 | 80 S5P_CITRGFMT_FLIP_180); 81 82 /* 83 * The input and output rotator cannot work simultaneously. 84 * Use the output rotator in output DMA mode or the input rotator 85 * in direct fifo output mode. 86 */ 87 if (ctx->rotation == 90 || ctx->rotation == 270) { 88 if (ctx->out_path == FIMC_LCDFIFO) 89 cfg |= S5P_CITRGFMT_INROT90; 90 else 91 cfg |= S5P_CITRGFMT_OUTROT90; 92 } 93 94 if (ctx->out_path == FIMC_DMA) { 95 cfg |= fimc_hw_get_target_flip(ctx); 96 writel(cfg, dev->regs + S5P_CITRGFMT); 97 } else { 98 /* LCD FIFO path */ 99 flip = readl(dev->regs + S5P_MSCTRL); 100 flip &= ~S5P_MSCTRL_FLIP_MASK; 101 flip |= fimc_hw_get_in_flip(ctx); 102 writel(flip, dev->regs + S5P_MSCTRL); 103 } 104} 105 106void fimc_hw_set_target_format(struct fimc_ctx *ctx) 107{ 108 u32 cfg; 109 struct fimc_dev *dev = ctx->fimc_dev; 110 struct fimc_frame *frame = &ctx->d_frame; 111 112 dbg("w= %d, h= %d color: %d", frame->width, 113 frame->height, frame->fmt->color); 114 115 cfg = readl(dev->regs + S5P_CITRGFMT); 116 cfg &= ~(S5P_CITRGFMT_FMT_MASK | S5P_CITRGFMT_HSIZE_MASK | 117 S5P_CITRGFMT_VSIZE_MASK); 118 119 switch (frame->fmt->color) { 120 case S5P_FIMC_RGB444...S5P_FIMC_RGB888: 121 cfg |= S5P_CITRGFMT_RGB; 122 break; 123 case S5P_FIMC_YCBCR420: 124 cfg |= S5P_CITRGFMT_YCBCR420; 125 break; 126 case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422: 127 if (frame->fmt->colplanes == 1) 128 cfg |= S5P_CITRGFMT_YCBCR422_1P; 129 else 130 cfg |= S5P_CITRGFMT_YCBCR422; 131 break; 132 default: 133 break; 134 } 135 136 if (ctx->rotation == 90 || ctx->rotation == 270) { 137 cfg |= S5P_CITRGFMT_HSIZE(frame->height); 138 cfg |= S5P_CITRGFMT_VSIZE(frame->width); 139 } else { 140 141 cfg |= S5P_CITRGFMT_HSIZE(frame->width); 142 cfg |= S5P_CITRGFMT_VSIZE(frame->height); 143 } 144 145 writel(cfg, dev->regs + S5P_CITRGFMT); 146 147 cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK; 148 cfg |= (frame->width * frame->height); 149 writel(cfg, dev->regs + S5P_CITAREA); 150} 151 152static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) 153{ 154 struct fimc_dev *dev = ctx->fimc_dev; 155 struct fimc_frame *frame = &ctx->d_frame; 156 u32 cfg; 157 158 cfg = S5P_ORIG_SIZE_HOR(frame->f_width); 159 cfg |= S5P_ORIG_SIZE_VER(frame->f_height); 160 writel(cfg, dev->regs + S5P_ORGOSIZE); 161 162 /* Select color space conversion equation (HD/SD size).*/ 163 cfg = readl(dev->regs + S5P_CIGCTRL); 164 if (frame->f_width >= 1280) /* HD */ 165 cfg |= S5P_CIGCTRL_CSC_ITU601_709; 166 else /* SD */ 167 cfg &= ~S5P_CIGCTRL_CSC_ITU601_709; 168 writel(cfg, dev->regs + S5P_CIGCTRL); 169 170} 171 172void fimc_hw_set_out_dma(struct fimc_ctx *ctx) 173{ 174 u32 cfg; 175 struct fimc_dev *dev = ctx->fimc_dev; 176 struct fimc_frame *frame = &ctx->d_frame; 177 struct fimc_dma_offset *offset = &frame->dma_offset; 178 struct fimc_fmt *fmt = frame->fmt; 179 180 /* Set the input dma offsets. */ 181 cfg = 0; 182 cfg |= S5P_CIO_OFFS_HOR(offset->y_h); 183 cfg |= S5P_CIO_OFFS_VER(offset->y_v); 184 writel(cfg, dev->regs + S5P_CIOYOFF); 185 186 cfg = 0; 187 cfg |= S5P_CIO_OFFS_HOR(offset->cb_h); 188 cfg |= S5P_CIO_OFFS_VER(offset->cb_v); 189 writel(cfg, dev->regs + S5P_CIOCBOFF); 190 191 cfg = 0; 192 cfg |= S5P_CIO_OFFS_HOR(offset->cr_h); 193 cfg |= S5P_CIO_OFFS_VER(offset->cr_v); 194 writel(cfg, dev->regs + S5P_CIOCROFF); 195 196 fimc_hw_set_out_dma_size(ctx); 197 198 /* Configure chroma components order. */ 199 cfg = readl(dev->regs + S5P_CIOCTRL); 200 201 cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK | 202 S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK); 203 204 if (fmt->colplanes == 1) 205 cfg |= ctx->out_order_1p; 206 else if (fmt->colplanes == 2) 207 cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE; 208 else if (fmt->colplanes == 3) 209 cfg |= S5P_CIOCTRL_YCBCR_3PLANE; 210 211 if (fmt->color == S5P_FIMC_RGB565) 212 cfg |= S5P_CIOCTRL_RGB565; 213 else if (fmt->color == S5P_FIMC_RGB555) 214 cfg |= S5P_CIOCTRL_ARGB1555; 215 else if (fmt->color == S5P_FIMC_RGB444) 216 cfg |= S5P_CIOCTRL_ARGB4444; 217 218 writel(cfg, dev->regs + S5P_CIOCTRL); 219} 220 221static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable) 222{ 223 u32 cfg = readl(dev->regs + S5P_ORGISIZE); 224 if (enable) 225 cfg |= S5P_CIREAL_ISIZE_AUTOLOAD_EN; 226 else 227 cfg &= ~S5P_CIREAL_ISIZE_AUTOLOAD_EN; 228 writel(cfg, dev->regs + S5P_ORGISIZE); 229} 230 231void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) 232{ 233 u32 cfg = readl(dev->regs + S5P_CIOCTRL); 234 if (enable) 235 cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE; 236 else 237 cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE; 238 writel(cfg, dev->regs + S5P_CIOCTRL); 239} 240 241void fimc_hw_set_prescaler(struct fimc_ctx *ctx) 242{ 243 struct fimc_dev *dev = ctx->fimc_dev; 244 struct fimc_scaler *sc = &ctx->scaler; 245 u32 cfg, shfactor; 246 247 shfactor = 10 - (sc->hfactor + sc->vfactor); 248 249 cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor); 250 cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio); 251 cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio); 252 writel(cfg, dev->regs + S5P_CISCPRERATIO); 253 254 cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width); 255 cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height); 256 writel(cfg, dev->regs + S5P_CISCPREDST); 257} 258 259static void fimc_hw_set_scaler(struct fimc_ctx *ctx) 260{ 261 struct fimc_dev *dev = ctx->fimc_dev; 262 struct fimc_scaler *sc = &ctx->scaler; 263 struct fimc_frame *src_frame = &ctx->s_frame; 264 struct fimc_frame *dst_frame = &ctx->d_frame; 265 266 u32 cfg = readl(dev->regs + S5P_CISCCTRL); 267 268 cfg &= ~(S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE | 269 S5P_CISCCTRL_SCALEUP_H | S5P_CISCCTRL_SCALEUP_V | 270 S5P_CISCCTRL_SCALERBYPASS | S5P_CISCCTRL_ONE2ONE | 271 S5P_CISCCTRL_INRGB_FMT_MASK | S5P_CISCCTRL_OUTRGB_FMT_MASK | 272 S5P_CISCCTRL_INTERLACE | S5P_CISCCTRL_RGB_EXT); 273 274 if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) 275 cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE); 276 277 if (!sc->enabled) 278 cfg |= S5P_CISCCTRL_SCALERBYPASS; 279 280 if (sc->scaleup_h) 281 cfg |= S5P_CISCCTRL_SCALEUP_H; 282 283 if (sc->scaleup_v) 284 cfg |= S5P_CISCCTRL_SCALEUP_V; 285 286 if (sc->copy_mode) 287 cfg |= S5P_CISCCTRL_ONE2ONE; 288 289 if (ctx->in_path == FIMC_DMA) { 290 switch (src_frame->fmt->color) { 291 case S5P_FIMC_RGB565: 292 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565; 293 break; 294 case S5P_FIMC_RGB666: 295 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666; 296 break; 297 case S5P_FIMC_RGB888: 298 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888; 299 break; 300 } 301 } 302 303 if (ctx->out_path == FIMC_DMA) { 304 u32 color = dst_frame->fmt->color; 305 306 if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565) 307 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565; 308 else if (color == S5P_FIMC_RGB666) 309 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666; 310 else if (color == S5P_FIMC_RGB888) 311 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; 312 } else { 313 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; 314 315 if (ctx->flags & FIMC_SCAN_MODE_INTERLACED) 316 cfg |= S5P_CISCCTRL_INTERLACE; 317 } 318 319 writel(cfg, dev->regs + S5P_CISCCTRL); 320} 321 322void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) 323{ 324 struct fimc_dev *dev = ctx->fimc_dev; 325 struct samsung_fimc_variant *variant = dev->variant; 326 struct fimc_scaler *sc = &ctx->scaler; 327 u32 cfg; 328 329 dbg("main_hratio= 0x%X main_vratio= 0x%X", 330 sc->main_hratio, sc->main_vratio); 331 332 fimc_hw_set_scaler(ctx); 333 334 cfg = readl(dev->regs + S5P_CISCCTRL); 335 cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); 336 337 if (variant->has_mainscaler_ext) { 338 cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio); 339 cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio); 340 writel(cfg, dev->regs + S5P_CISCCTRL); 341 342 cfg = readl(dev->regs + S5P_CIEXTEN); 343 344 cfg &= ~(S5P_CIEXTEN_MVRATIO_EXT_MASK | 345 S5P_CIEXTEN_MHRATIO_EXT_MASK); 346 cfg |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio); 347 cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio); 348 writel(cfg, dev->regs + S5P_CIEXTEN); 349 } else { 350 cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio); 351 cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio); 352 writel(cfg, dev->regs + S5P_CISCCTRL); 353 } 354} 355 356void fimc_hw_en_capture(struct fimc_ctx *ctx) 357{ 358 struct fimc_dev *dev = ctx->fimc_dev; 359 360 u32 cfg = readl(dev->regs + S5P_CIIMGCPT); 361 362 if (ctx->out_path == FIMC_DMA) { 363 /* one shot mode */ 364 cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN; 365 } else { 366 /* Continuous frame capture mode (freerun). */ 367 cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE | 368 S5P_CIIMGCPT_CPT_FRMOD_CNT); 369 cfg |= S5P_CIIMGCPT_IMGCPTEN; 370 } 371 372 if (ctx->scaler.enabled) 373 cfg |= S5P_CIIMGCPT_IMGCPTEN_SC; 374 375 writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT); 376} 377 378void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active) 379{ 380 struct fimc_dev *dev = ctx->fimc_dev; 381 struct fimc_effect *effect = &ctx->effect; 382 u32 cfg = 0; 383 384 if (active) { 385 cfg |= S5P_CIIMGEFF_IE_SC_AFTER | S5P_CIIMGEFF_IE_ENABLE; 386 cfg |= effect->type; 387 if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) { 388 cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb); 389 cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr); 390 } 391 } 392 393 writel(cfg, dev->regs + S5P_CIIMGEFF); 394} 395 396void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) 397{ 398 struct fimc_dev *dev = ctx->fimc_dev; 399 struct fimc_frame *frame = &ctx->d_frame; 400 u32 cfg; 401 402 if (!(frame->fmt->flags & FMT_HAS_ALPHA)) 403 return; 404 405 cfg = readl(dev->regs + S5P_CIOCTRL); 406 cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK; 407 cfg |= (frame->alpha << 4); 408 writel(cfg, dev->regs + S5P_CIOCTRL); 409} 410 411static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) 412{ 413 struct fimc_dev *dev = ctx->fimc_dev; 414 struct fimc_frame *frame = &ctx->s_frame; 415 u32 cfg_o = 0; 416 u32 cfg_r = 0; 417 418 if (FIMC_LCDFIFO == ctx->out_path) 419 cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN; 420 421 cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width); 422 cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height); 423 cfg_r |= S5P_CIREAL_ISIZE_WIDTH(frame->width); 424 cfg_r |= S5P_CIREAL_ISIZE_HEIGHT(frame->height); 425 426 writel(cfg_o, dev->regs + S5P_ORGISIZE); 427 writel(cfg_r, dev->regs + S5P_CIREAL_ISIZE); 428} 429 430void fimc_hw_set_in_dma(struct fimc_ctx *ctx) 431{ 432 struct fimc_dev *dev = ctx->fimc_dev; 433 struct fimc_frame *frame = &ctx->s_frame; 434 struct fimc_dma_offset *offset = &frame->dma_offset; 435 u32 cfg; 436 437 /* Set the pixel offsets. */ 438 cfg = S5P_CIO_OFFS_HOR(offset->y_h); 439 cfg |= S5P_CIO_OFFS_VER(offset->y_v); 440 writel(cfg, dev->regs + S5P_CIIYOFF); 441 442 cfg = S5P_CIO_OFFS_HOR(offset->cb_h); 443 cfg |= S5P_CIO_OFFS_VER(offset->cb_v); 444 writel(cfg, dev->regs + S5P_CIICBOFF); 445 446 cfg = S5P_CIO_OFFS_HOR(offset->cr_h); 447 cfg |= S5P_CIO_OFFS_VER(offset->cr_v); 448 writel(cfg, dev->regs + S5P_CIICROFF); 449 450 /* Input original and real size. */ 451 fimc_hw_set_in_dma_size(ctx); 452 453 /* Use DMA autoload only in FIFO mode. */ 454 fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO); 455 456 /* Set the input DMA to process single frame only. */ 457 cfg = readl(dev->regs + S5P_MSCTRL); 458 cfg &= ~(S5P_MSCTRL_INFORMAT_MASK 459 | S5P_MSCTRL_IN_BURST_COUNT_MASK 460 | S5P_MSCTRL_INPUT_MASK 461 | S5P_MSCTRL_C_INT_IN_MASK 462 | S5P_MSCTRL_2P_IN_ORDER_MASK); 463 464 cfg |= (S5P_MSCTRL_IN_BURST_COUNT(4) 465 | S5P_MSCTRL_INPUT_MEMORY 466 | S5P_MSCTRL_FIFO_CTRL_FULL); 467 468 switch (frame->fmt->color) { 469 case S5P_FIMC_RGB565...S5P_FIMC_RGB888: 470 cfg |= S5P_MSCTRL_INFORMAT_RGB; 471 break; 472 case S5P_FIMC_YCBCR420: 473 cfg |= S5P_MSCTRL_INFORMAT_YCBCR420; 474 475 if (frame->fmt->colplanes == 2) 476 cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE; 477 else 478 cfg |= S5P_MSCTRL_C_INT_IN_3PLANE; 479 480 break; 481 case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422: 482 if (frame->fmt->colplanes == 1) { 483 cfg |= ctx->in_order_1p 484 | S5P_MSCTRL_INFORMAT_YCBCR422_1P; 485 } else { 486 cfg |= S5P_MSCTRL_INFORMAT_YCBCR422; 487 488 if (frame->fmt->colplanes == 2) 489 cfg |= ctx->in_order_2p 490 | S5P_MSCTRL_C_INT_IN_2PLANE; 491 else 492 cfg |= S5P_MSCTRL_C_INT_IN_3PLANE; 493 } 494 break; 495 default: 496 break; 497 } 498 499 writel(cfg, dev->regs + S5P_MSCTRL); 500 501 /* Input/output DMA linear/tiled mode. */ 502 cfg = readl(dev->regs + S5P_CIDMAPARAM); 503 cfg &= ~S5P_CIDMAPARAM_TILE_MASK; 504 505 if (tiled_fmt(ctx->s_frame.fmt)) 506 cfg |= S5P_CIDMAPARAM_R_64X32; 507 508 if (tiled_fmt(ctx->d_frame.fmt)) 509 cfg |= S5P_CIDMAPARAM_W_64X32; 510 511 writel(cfg, dev->regs + S5P_CIDMAPARAM); 512} 513 514 515void fimc_hw_set_input_path(struct fimc_ctx *ctx) 516{ 517 struct fimc_dev *dev = ctx->fimc_dev; 518 519 u32 cfg = readl(dev->regs + S5P_MSCTRL); 520 cfg &= ~S5P_MSCTRL_INPUT_MASK; 521 522 if (ctx->in_path == FIMC_DMA) 523 cfg |= S5P_MSCTRL_INPUT_MEMORY; 524 else 525 cfg |= S5P_MSCTRL_INPUT_EXTCAM; 526 527 writel(cfg, dev->regs + S5P_MSCTRL); 528} 529 530void fimc_hw_set_output_path(struct fimc_ctx *ctx) 531{ 532 struct fimc_dev *dev = ctx->fimc_dev; 533 534 u32 cfg = readl(dev->regs + S5P_CISCCTRL); 535 cfg &= ~S5P_CISCCTRL_LCDPATHEN_FIFO; 536 if (ctx->out_path == FIMC_LCDFIFO) 537 cfg |= S5P_CISCCTRL_LCDPATHEN_FIFO; 538 writel(cfg, dev->regs + S5P_CISCCTRL); 539} 540 541void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr) 542{ 543 u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE); 544 cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS; 545 writel(cfg, dev->regs + S5P_CIREAL_ISIZE); 546 547 writel(paddr->y, dev->regs + S5P_CIIYSA(0)); 548 writel(paddr->cb, dev->regs + S5P_CIICBSA(0)); 549 writel(paddr->cr, dev->regs + S5P_CIICRSA(0)); 550 551 cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS; 552 writel(cfg, dev->regs + S5P_CIREAL_ISIZE); 553} 554 555void fimc_hw_set_output_addr(struct fimc_dev *dev, 556 struct fimc_addr *paddr, int index) 557{ 558 int i = (index == -1) ? 0 : index; 559 do { 560 writel(paddr->y, dev->regs + S5P_CIOYSA(i)); 561 writel(paddr->cb, dev->regs + S5P_CIOCBSA(i)); 562 writel(paddr->cr, dev->regs + S5P_CIOCRSA(i)); 563 dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", 564 i, paddr->y, paddr->cb, paddr->cr); 565 } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); 566} 567 568int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, 569 struct s5p_fimc_isp_info *cam) 570{ 571 u32 cfg = readl(fimc->regs + S5P_CIGCTRL); 572 573 cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC | 574 S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC | 575 S5P_CIGCTRL_INVPOLFIELD); 576 577 if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) 578 cfg |= S5P_CIGCTRL_INVPOLPCLK; 579 580 if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 581 cfg |= S5P_CIGCTRL_INVPOLVSYNC; 582 583 if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 584 cfg |= S5P_CIGCTRL_INVPOLHREF; 585 586 if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 587 cfg |= S5P_CIGCTRL_INVPOLHSYNC; 588 589 if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW) 590 cfg |= S5P_CIGCTRL_INVPOLFIELD; 591 592 writel(cfg, fimc->regs + S5P_CIGCTRL); 593 594 return 0; 595} 596 597int fimc_hw_set_camera_source(struct fimc_dev *fimc, 598 struct s5p_fimc_isp_info *cam) 599{ 600 struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; 601 u32 cfg = 0; 602 u32 bus_width; 603 int i; 604 605 static const struct { 606 u32 pixelcode; 607 u32 cisrcfmt; 608 u16 bus_width; 609 } pix_desc[] = { 610 { V4L2_MBUS_FMT_YUYV8_2X8, S5P_CISRCFMT_ORDER422_YCBYCR, 8 }, 611 { V4L2_MBUS_FMT_YVYU8_2X8, S5P_CISRCFMT_ORDER422_YCRYCB, 8 }, 612 { V4L2_MBUS_FMT_VYUY8_2X8, S5P_CISRCFMT_ORDER422_CRYCBY, 8 }, 613 { V4L2_MBUS_FMT_UYVY8_2X8, S5P_CISRCFMT_ORDER422_CBYCRY, 8 }, 614 /* TODO: Add pixel codes for 16-bit bus width */ 615 }; 616 617 if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) { 618 for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { 619 if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) { 620 cfg = pix_desc[i].cisrcfmt; 621 bus_width = pix_desc[i].bus_width; 622 break; 623 } 624 } 625 626 if (i == ARRAY_SIZE(pix_desc)) { 627 v4l2_err(fimc->vid_cap.vfd, 628 "Camera color format not supported: %d\n", 629 fimc->vid_cap.mf.code); 630 return -EINVAL; 631 } 632 633 if (cam->bus_type == FIMC_ITU_601) { 634 if (bus_width == 8) 635 cfg |= S5P_CISRCFMT_ITU601_8BIT; 636 else if (bus_width == 16) 637 cfg |= S5P_CISRCFMT_ITU601_16BIT; 638 } /* else defaults to ITU-R BT.656 8-bit */ 639 } else if (cam->bus_type == FIMC_MIPI_CSI2) { 640 if (fimc_fmt_is_jpeg(f->fmt->color)) 641 cfg |= S5P_CISRCFMT_ITU601_8BIT; 642 } 643 644 cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height); 645 writel(cfg, fimc->regs + S5P_CISRCFMT); 646 return 0; 647} 648 649 650int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) 651{ 652 u32 hoff2, voff2; 653 654 u32 cfg = readl(fimc->regs + S5P_CIWDOFST); 655 656 cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK); 657 cfg |= S5P_CIWDOFST_OFF_EN | 658 S5P_CIWDOFST_HOROFF(f->offs_h) | 659 S5P_CIWDOFST_VEROFF(f->offs_v); 660 661 writel(cfg, fimc->regs + S5P_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 = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2); 667 668 writel(cfg, fimc->regs + S5P_CIWDOFST2); 669 return 0; 670} 671 672int fimc_hw_set_camera_type(struct fimc_dev *fimc, 673 struct s5p_fimc_isp_info *cam) 674{ 675 u32 cfg, tmp; 676 struct fimc_vid_cap *vid_cap = &fimc->vid_cap; 677 678 cfg = readl(fimc->regs + S5P_CIGCTRL); 679 680 /* Select ITU B interface, disable Writeback path and test pattern. */ 681 cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A | 682 S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB | 683 S5P_CIGCTRL_SELCAM_MIPI_A | S5P_CIGCTRL_CAM_JPEG); 684 685 if (cam->bus_type == FIMC_MIPI_CSI2) { 686 cfg |= S5P_CIGCTRL_SELCAM_MIPI; 687 688 if (cam->mux_id == 0) 689 cfg |= S5P_CIGCTRL_SELCAM_MIPI_A; 690 691 /* TODO: add remaining supported formats. */ 692 switch (vid_cap->mf.code) { 693 case V4L2_MBUS_FMT_VYUY8_2X8: 694 tmp = S5P_CSIIMGFMT_YCBCR422_8BIT; 695 break; 696 case V4L2_MBUS_FMT_JPEG_1X8: 697 tmp = S5P_CSIIMGFMT_USER(1); 698 cfg |= S5P_CIGCTRL_CAM_JPEG; 699 break; 700 default: 701 v4l2_err(fimc->vid_cap.vfd, 702 "Not supported camera pixel format: %d", 703 vid_cap->mf.code); 704 return -EINVAL; 705 } 706 tmp |= (cam->csi_data_align == 32) << 8; 707 708 writel(tmp, fimc->regs + S5P_CSIIMGFMT); 709 710 } else if (cam->bus_type == FIMC_ITU_601 || 711 cam->bus_type == FIMC_ITU_656) { 712 if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ 713 cfg |= S5P_CIGCTRL_SELCAM_ITU_A; 714 } else if (cam->bus_type == FIMC_LCD_WB) { 715 cfg |= S5P_CIGCTRL_CAMIF_SELWB; 716 } else { 717 err("invalid camera bus type selected\n"); 718 return -EINVAL; 719 } 720 writel(cfg, fimc->regs + S5P_CIGCTRL); 721 722 return 0; 723} 724