1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd. 4 * http://www.samsung.com 5 * 6 * Samsung EXYNOS5 SoC series G-Scaler driver 7 */ 8 9 #include <linux/io.h> 10 #include <linux/delay.h> 11 12 #include "gsc-core.h" 13 14 void gsc_hw_set_sw_reset(struct gsc_dev *dev) 15 { 16 writel(GSC_SW_RESET_SRESET, dev->regs + GSC_SW_RESET); 17 } 18 19 int 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 34 void 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 else 42 cfg &= ~GSC_IRQ_FRMDONE_MASK; 43 writel(cfg, dev->regs + GSC_IRQ); 44 } 45 46 void 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 else 54 cfg &= ~GSC_IRQ_ENABLE; 55 writel(cfg, dev->regs + GSC_IRQ); 56 } 57 58 void 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 72 void 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 86 void 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 97 void 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 107 void 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 120 void 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 142 void 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 else 152 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 162 void 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 else 188 cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C; 189 if (frame->fmt->corder == GSC_CBCR) 190 cfg |= GSC_IN_CHROMA_ORDER_CBCR; 191 else 192 cfg |= GSC_IN_CHROMA_ORDER_CRCB; 193 break; 194 case 2: 195 if (depth == 12) 196 cfg |= GSC_IN_YUV420_2P; 197 else 198 cfg |= GSC_IN_YUV422_2P; 199 if (frame->fmt->corder == GSC_CBCR) 200 cfg |= GSC_IN_CHROMA_ORDER_CBCR; 201 else 202 cfg |= GSC_IN_CHROMA_ORDER_CRCB; 203 break; 204 case 3: 205 if (depth == 12) 206 cfg |= GSC_IN_YUV420_3P; 207 else 208 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 218 void 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 else 228 cfg |= GSC_OUT_PATH_LOCAL; 229 230 writel(cfg, dev->regs + GSC_OUT_CON); 231 } 232 233 void 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 262 void 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 else 272 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 282 void 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 else 314 cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C; 315 if (frame->fmt->corder == GSC_CBCR) 316 cfg |= GSC_OUT_CHROMA_ORDER_CBCR; 317 else 318 cfg |= GSC_OUT_CHROMA_ORDER_CRCB; 319 break; 320 case 2: 321 if (depth == 12) 322 cfg |= GSC_OUT_YUV420_2P; 323 else 324 cfg |= GSC_OUT_YUV422_2P; 325 if (frame->fmt->corder == GSC_CBCR) 326 cfg |= GSC_OUT_CHROMA_ORDER_CBCR; 327 else 328 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 338 end_set: 339 writel(cfg, dev->regs + GSC_OUT_CON); 340 } 341 342 void 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 354 void 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 367 void 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 else 388 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 400 void 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 418 void 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