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