847 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Register interface file for Samsung Camera Interface (FIMC) driver4 *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 19void 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 41static 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 56static 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 71void 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 rotator83 * 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 else89 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 104void 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 else128 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 else137 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 147static 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 166void 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 211static 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 else217 cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;218 writel(cfg, dev->regs + FIMC_REG_ORGISIZE);219}220 221void 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 else227 cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;228 writel(cfg, dev->regs + FIMC_REG_CIOCTRL);229}230 231void 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 247static 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 311void 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 346void 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 else357 cfg &= FIMC_REG_CIIMGCPT_IMGCPTEN_SC;358 359 cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;360 writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);361}362 363void 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 371void 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 388void 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 403static 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 420void 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_MASK446 | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK447 | FIMC_REG_MSCTRL_INPUT_MASK448 | FIMC_REG_MSCTRL_C_INT_IN_MASK449 | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK450 | FIMC_REG_MSCTRL_ORDER422_MASK);451 452 cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4)453 | FIMC_REG_MSCTRL_INPUT_MEMORY454 | 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 else466 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_1p472 | 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_2p478 | FIMC_REG_MSCTRL_C_INT_IN_2PLANE;479 else480 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 503void 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 else513 cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM;514 515 writel(cfg, dev->regs + FIMC_REG_MSCTRL);516}517 518void 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 529void 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 543void 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 556int 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 585struct mbus_pixfmt_desc {586 u32 pixelcode;587 u32 cisrcfmt;588 u16 bus_width;589};590 591static 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 598int 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 651void 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 670int 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 else725 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 738void 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 745void 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 else751 cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART;752 writel(cfg, dev->regs + FIMC_REG_CISCCTRL);753}754 755void 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 else761 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. */766s32 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. */782s32 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 */794void 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 800void 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 808int 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 else824 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