427 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.4 * http://www.samsung.com5 *6 * Samsung EXYNOS5 SoC series G-Scaler driver7 */8 9#include <linux/io.h>10#include <linux/delay.h>11 12#include "gsc-core.h"13 14void gsc_hw_set_sw_reset(struct gsc_dev *dev)15{16 writel(GSC_SW_RESET_SRESET, dev->regs + GSC_SW_RESET);17}18 19int gsc_wait_reset(struct gsc_dev *dev)20{21 unsigned long end = jiffies + msecs_to_jiffies(50);22 u32 cfg;23 24 while (time_before(jiffies, end)) {25 cfg = readl(dev->regs + GSC_SW_RESET);26 if (!cfg)27 return 0;28 usleep_range(10, 20);29 }30 31 return -EBUSY;32}33 34void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask)35{36 u32 cfg;37 38 cfg = readl(dev->regs + GSC_IRQ);39 if (mask)40 cfg |= GSC_IRQ_FRMDONE_MASK;41 else42 cfg &= ~GSC_IRQ_FRMDONE_MASK;43 writel(cfg, dev->regs + GSC_IRQ);44}45 46void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask)47{48 u32 cfg;49 50 cfg = readl(dev->regs + GSC_IRQ);51 if (mask)52 cfg |= GSC_IRQ_ENABLE;53 else54 cfg &= ~GSC_IRQ_ENABLE;55 writel(cfg, dev->regs + GSC_IRQ);56}57 58void gsc_hw_set_input_buf_masking(struct gsc_dev *dev, u32 shift,59 bool enable)60{61 u32 cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);62 u32 mask = 1 << shift;63 64 cfg &= ~mask;65 cfg |= enable << shift;66 67 writel(cfg, dev->regs + GSC_IN_BASE_ADDR_Y_MASK);68 writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CB_MASK);69 writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CR_MASK);70}71 72void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift,73 bool enable)74{75 u32 cfg = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);76 u32 mask = 1 << shift;77 78 cfg &= ~mask;79 cfg |= enable << shift;80 81 writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);82 writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CB_MASK);83 writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CR_MASK);84}85 86void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,87 int index)88{89 pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", index,90 &addr->y, &addr->cb, &addr->cr);91 writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index));92 writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index));93 writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index));94 95}96 97void gsc_hw_set_output_addr(struct gsc_dev *dev,98 struct gsc_addr *addr, int index)99{100 pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad",101 index, &addr->y, &addr->cb, &addr->cr);102 writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index));103 writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index));104 writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index));105}106 107void gsc_hw_set_input_path(struct gsc_ctx *ctx)108{109 struct gsc_dev *dev = ctx->gsc_dev;110 111 u32 cfg = readl(dev->regs + GSC_IN_CON);112 cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);113 114 if (ctx->in_path == GSC_DMA)115 cfg |= GSC_IN_PATH_MEMORY;116 117 writel(cfg, dev->regs + GSC_IN_CON);118}119 120void gsc_hw_set_in_size(struct gsc_ctx *ctx)121{122 struct gsc_dev *dev = ctx->gsc_dev;123 struct gsc_frame *frame = &ctx->s_frame;124 u32 cfg;125 126 /* Set input pixel offset */127 cfg = GSC_SRCIMG_OFFSET_X(frame->crop.left);128 cfg |= GSC_SRCIMG_OFFSET_Y(frame->crop.top);129 writel(cfg, dev->regs + GSC_SRCIMG_OFFSET);130 131 /* Set input original size */132 cfg = GSC_SRCIMG_WIDTH(frame->f_width);133 cfg |= GSC_SRCIMG_HEIGHT(frame->f_height);134 writel(cfg, dev->regs + GSC_SRCIMG_SIZE);135 136 /* Set input cropped size */137 cfg = GSC_CROPPED_WIDTH(frame->crop.width);138 cfg |= GSC_CROPPED_HEIGHT(frame->crop.height);139 writel(cfg, dev->regs + GSC_CROPPED_SIZE);140}141 142void gsc_hw_set_in_image_rgb(struct gsc_ctx *ctx)143{144 struct gsc_dev *dev = ctx->gsc_dev;145 struct gsc_frame *frame = &ctx->s_frame;146 u32 cfg;147 148 cfg = readl(dev->regs + GSC_IN_CON);149 if (frame->colorspace == V4L2_COLORSPACE_REC709)150 cfg |= GSC_IN_RGB_HD_WIDE;151 else152 cfg |= GSC_IN_RGB_SD_WIDE;153 154 if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB565X)155 cfg |= GSC_IN_RGB565;156 else if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB32)157 cfg |= GSC_IN_XRGB8888;158 159 writel(cfg, dev->regs + GSC_IN_CON);160}161 162void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)163{164 struct gsc_dev *dev = ctx->gsc_dev;165 struct gsc_frame *frame = &ctx->s_frame;166 u32 i, depth = 0;167 u32 cfg;168 169 cfg = readl(dev->regs + GSC_IN_CON);170 cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK |171 GSC_IN_CHROMA_ORDER_MASK | GSC_IN_FORMAT_MASK |172 GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE);173 writel(cfg, dev->regs + GSC_IN_CON);174 175 if (is_rgb(frame->fmt->color)) {176 gsc_hw_set_in_image_rgb(ctx);177 return;178 }179 for (i = 0; i < frame->fmt->num_planes; i++)180 depth += frame->fmt->depth[i];181 182 switch (frame->fmt->num_comp) {183 case 1:184 cfg |= GSC_IN_YUV422_1P;185 if (frame->fmt->yorder == GSC_LSB_Y)186 cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;187 else188 cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;189 if (frame->fmt->corder == GSC_CBCR)190 cfg |= GSC_IN_CHROMA_ORDER_CBCR;191 else192 cfg |= GSC_IN_CHROMA_ORDER_CRCB;193 break;194 case 2:195 if (depth == 12)196 cfg |= GSC_IN_YUV420_2P;197 else198 cfg |= GSC_IN_YUV422_2P;199 if (frame->fmt->corder == GSC_CBCR)200 cfg |= GSC_IN_CHROMA_ORDER_CBCR;201 else202 cfg |= GSC_IN_CHROMA_ORDER_CRCB;203 break;204 case 3:205 if (depth == 12)206 cfg |= GSC_IN_YUV420_3P;207 else208 cfg |= GSC_IN_YUV422_3P;209 break;210 }211 212 if (is_tiled(frame->fmt))213 cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;214 215 writel(cfg, dev->regs + GSC_IN_CON);216}217 218void gsc_hw_set_output_path(struct gsc_ctx *ctx)219{220 struct gsc_dev *dev = ctx->gsc_dev;221 222 u32 cfg = readl(dev->regs + GSC_OUT_CON);223 cfg &= ~GSC_OUT_PATH_MASK;224 225 if (ctx->out_path == GSC_DMA)226 cfg |= GSC_OUT_PATH_MEMORY;227 else228 cfg |= GSC_OUT_PATH_LOCAL;229 230 writel(cfg, dev->regs + GSC_OUT_CON);231}232 233void gsc_hw_set_out_size(struct gsc_ctx *ctx)234{235 struct gsc_dev *dev = ctx->gsc_dev;236 struct gsc_frame *frame = &ctx->d_frame;237 u32 cfg;238 239 /* Set output original size */240 if (ctx->out_path == GSC_DMA) {241 cfg = GSC_DSTIMG_OFFSET_X(frame->crop.left);242 cfg |= GSC_DSTIMG_OFFSET_Y(frame->crop.top);243 writel(cfg, dev->regs + GSC_DSTIMG_OFFSET);244 245 cfg = GSC_DSTIMG_WIDTH(frame->f_width);246 cfg |= GSC_DSTIMG_HEIGHT(frame->f_height);247 writel(cfg, dev->regs + GSC_DSTIMG_SIZE);248 }249 250 /* Set output scaled size */251 if (ctx->gsc_ctrls.rotate->val == 90 ||252 ctx->gsc_ctrls.rotate->val == 270) {253 cfg = GSC_SCALED_WIDTH(frame->crop.height);254 cfg |= GSC_SCALED_HEIGHT(frame->crop.width);255 } else {256 cfg = GSC_SCALED_WIDTH(frame->crop.width);257 cfg |= GSC_SCALED_HEIGHT(frame->crop.height);258 }259 writel(cfg, dev->regs + GSC_SCALED_SIZE);260}261 262void gsc_hw_set_out_image_rgb(struct gsc_ctx *ctx)263{264 struct gsc_dev *dev = ctx->gsc_dev;265 struct gsc_frame *frame = &ctx->d_frame;266 u32 cfg;267 268 cfg = readl(dev->regs + GSC_OUT_CON);269 if (frame->colorspace == V4L2_COLORSPACE_REC709)270 cfg |= GSC_OUT_RGB_HD_WIDE;271 else272 cfg |= GSC_OUT_RGB_SD_WIDE;273 274 if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB565X)275 cfg |= GSC_OUT_RGB565;276 else if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB32)277 cfg |= GSC_OUT_XRGB8888;278 279 writel(cfg, dev->regs + GSC_OUT_CON);280}281 282void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)283{284 struct gsc_dev *dev = ctx->gsc_dev;285 struct gsc_frame *frame = &ctx->d_frame;286 u32 i, depth = 0;287 u32 cfg;288 289 cfg = readl(dev->regs + GSC_OUT_CON);290 cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK |291 GSC_OUT_CHROMA_ORDER_MASK | GSC_OUT_FORMAT_MASK |292 GSC_OUT_TILE_TYPE_MASK | GSC_OUT_TILE_MODE);293 writel(cfg, dev->regs + GSC_OUT_CON);294 295 if (is_rgb(frame->fmt->color)) {296 gsc_hw_set_out_image_rgb(ctx);297 return;298 }299 300 if (ctx->out_path != GSC_DMA) {301 cfg |= GSC_OUT_YUV444;302 goto end_set;303 }304 305 for (i = 0; i < frame->fmt->num_planes; i++)306 depth += frame->fmt->depth[i];307 308 switch (frame->fmt->num_comp) {309 case 1:310 cfg |= GSC_OUT_YUV422_1P;311 if (frame->fmt->yorder == GSC_LSB_Y)312 cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;313 else314 cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;315 if (frame->fmt->corder == GSC_CBCR)316 cfg |= GSC_OUT_CHROMA_ORDER_CBCR;317 else318 cfg |= GSC_OUT_CHROMA_ORDER_CRCB;319 break;320 case 2:321 if (depth == 12)322 cfg |= GSC_OUT_YUV420_2P;323 else324 cfg |= GSC_OUT_YUV422_2P;325 if (frame->fmt->corder == GSC_CBCR)326 cfg |= GSC_OUT_CHROMA_ORDER_CBCR;327 else328 cfg |= GSC_OUT_CHROMA_ORDER_CRCB;329 break;330 case 3:331 cfg |= GSC_OUT_YUV420_3P;332 break;333 }334 335 if (is_tiled(frame->fmt))336 cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;337 338end_set:339 writel(cfg, dev->regs + GSC_OUT_CON);340}341 342void gsc_hw_set_prescaler(struct gsc_ctx *ctx)343{344 struct gsc_dev *dev = ctx->gsc_dev;345 struct gsc_scaler *sc = &ctx->scaler;346 u32 cfg;347 348 cfg = GSC_PRESC_SHFACTOR(sc->pre_shfactor);349 cfg |= GSC_PRESC_H_RATIO(sc->pre_hratio);350 cfg |= GSC_PRESC_V_RATIO(sc->pre_vratio);351 writel(cfg, dev->regs + GSC_PRE_SCALE_RATIO);352}353 354void gsc_hw_set_mainscaler(struct gsc_ctx *ctx)355{356 struct gsc_dev *dev = ctx->gsc_dev;357 struct gsc_scaler *sc = &ctx->scaler;358 u32 cfg;359 360 cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio);361 writel(cfg, dev->regs + GSC_MAIN_H_RATIO);362 363 cfg = GSC_MAIN_V_RATIO_VALUE(sc->main_vratio);364 writel(cfg, dev->regs + GSC_MAIN_V_RATIO);365}366 367void gsc_hw_set_rotation(struct gsc_ctx *ctx)368{369 struct gsc_dev *dev = ctx->gsc_dev;370 u32 cfg;371 372 cfg = readl(dev->regs + GSC_IN_CON);373 cfg &= ~GSC_IN_ROT_MASK;374 375 switch (ctx->gsc_ctrls.rotate->val) {376 case 270:377 cfg |= GSC_IN_ROT_270;378 break;379 case 180:380 cfg |= GSC_IN_ROT_180;381 break;382 case 90:383 if (ctx->gsc_ctrls.hflip->val)384 cfg |= GSC_IN_ROT_90_XFLIP;385 else if (ctx->gsc_ctrls.vflip->val)386 cfg |= GSC_IN_ROT_90_YFLIP;387 else388 cfg |= GSC_IN_ROT_90;389 break;390 case 0:391 if (ctx->gsc_ctrls.hflip->val)392 cfg |= GSC_IN_ROT_XFLIP;393 else if (ctx->gsc_ctrls.vflip->val)394 cfg |= GSC_IN_ROT_YFLIP;395 }396 397 writel(cfg, dev->regs + GSC_IN_CON);398}399 400void gsc_hw_set_global_alpha(struct gsc_ctx *ctx)401{402 struct gsc_dev *dev = ctx->gsc_dev;403 struct gsc_frame *frame = &ctx->d_frame;404 u32 cfg;405 406 if (!is_rgb(frame->fmt->color)) {407 pr_debug("Not a RGB format");408 return;409 }410 411 cfg = readl(dev->regs + GSC_OUT_CON);412 cfg &= ~GSC_OUT_GLOBAL_ALPHA_MASK;413 414 cfg |= GSC_OUT_GLOBAL_ALPHA(ctx->gsc_ctrls.global_alpha->val);415 writel(cfg, dev->regs + GSC_OUT_CON);416}417 418void gsc_hw_set_sfr_update(struct gsc_ctx *ctx)419{420 struct gsc_dev *dev = ctx->gsc_dev;421 u32 cfg;422 423 cfg = readl(dev->regs + GSC_ENABLE);424 cfg |= GSC_ENABLE_SFR_UPDATE;425 writel(cfg, dev->regs + GSC_ENABLE);426}427