1 /* 2 * Copyright (C) 2011 Samsung Electronics Co.Ltd 3 * Authors: 4 * Seung-Woo Kim <sw0312.kim@samsung.com> 5 * Inki Dae <inki.dae@samsung.com> 6 * Joonyoung Shim <jy0922.shim@samsung.com> 7 * 8 * Based on drivers/media/video/s5p-tv/mixer_reg.c 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 */ 16 17 #include "drmP.h" 18 19 #include "regs-mixer.h" 20 #include "regs-vp.h" 21 22 #include <linux/kernel.h> 23 #include <linux/spinlock.h> 24 #include <linux/wait.h> 25 #include <linux/i2c.h> 26 #include <linux/module.h> 27 #include <linux/platform_device.h> 28 #include <linux/interrupt.h> 29 #include <linux/irq.h> 30 #include <linux/delay.h> 31 #include <linux/pm_runtime.h> 32 #include <linux/clk.h> 33 #include <linux/regulator/consumer.h> 34 35 #include <drm/exynos_drm.h> 36 37 #include "exynos_drm_drv.h" 38 #include "exynos_drm_hdmi.h" 39 #include "exynos_hdmi.h" 40 #include "exynos_mixer.h" 41 42 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) 43 44 static const u8 filter_y_horiz_tap8[] = { 45 0, -1, -1, -1, -1, -1, -1, -1, 46 -1, -1, -1, -1, -1, 0, 0, 0, 47 0, 2, 4, 5, 6, 6, 6, 6, 48 6, 5, 5, 4, 3, 2, 1, 1, 49 0, -6, -12, -16, -18, -20, -21, -20, 50 -20, -18, -16, -13, -10, -8, -5, -2, 51 127, 126, 125, 121, 114, 107, 99, 89, 52 79, 68, 57, 46, 35, 25, 16, 8, 53 }; 54 55 static const u8 filter_y_vert_tap4[] = { 56 0, -3, -6, -8, -8, -8, -8, -7, 57 -6, -5, -4, -3, -2, -1, -1, 0, 58 127, 126, 124, 118, 111, 102, 92, 81, 59 70, 59, 48, 37, 27, 19, 11, 5, 60 0, 5, 11, 19, 27, 37, 48, 59, 61 70, 81, 92, 102, 111, 118, 124, 126, 62 0, 0, -1, -1, -2, -3, -4, -5, 63 -6, -7, -8, -8, -8, -8, -6, -3, 64 }; 65 66 static const u8 filter_cr_horiz_tap4[] = { 67 0, -3, -6, -8, -8, -8, -8, -7, 68 -6, -5, -4, -3, -2, -1, -1, 0, 69 127, 126, 124, 118, 111, 102, 92, 81, 70 70, 59, 48, 37, 27, 19, 11, 5, 71 }; 72 73 static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id) 74 { 75 return readl(res->vp_regs + reg_id); 76 } 77 78 static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id, 79 u32 val) 80 { 81 writel(val, res->vp_regs + reg_id); 82 } 83 84 static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id, 85 u32 val, u32 mask) 86 { 87 u32 old = vp_reg_read(res, reg_id); 88 89 val = (val & mask) | (old & ~mask); 90 writel(val, res->vp_regs + reg_id); 91 } 92 93 static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id) 94 { 95 return readl(res->mixer_regs + reg_id); 96 } 97 98 static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id, 99 u32 val) 100 { 101 writel(val, res->mixer_regs + reg_id); 102 } 103 104 static inline void mixer_reg_writemask(struct mixer_resources *res, 105 u32 reg_id, u32 val, u32 mask) 106 { 107 u32 old = mixer_reg_read(res, reg_id); 108 109 val = (val & mask) | (old & ~mask); 110 writel(val, res->mixer_regs + reg_id); 111 } 112 113 static void mixer_regs_dump(struct mixer_context *ctx) 114 { 115 #define DUMPREG(reg_id) \ 116 do { \ 117 DRM_DEBUG_KMS(#reg_id " = %08x\n", \ 118 (u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \ 119 } while (0) 120 121 DUMPREG(MXR_STATUS); 122 DUMPREG(MXR_CFG); 123 DUMPREG(MXR_INT_EN); 124 DUMPREG(MXR_INT_STATUS); 125 126 DUMPREG(MXR_LAYER_CFG); 127 DUMPREG(MXR_VIDEO_CFG); 128 129 DUMPREG(MXR_GRAPHIC0_CFG); 130 DUMPREG(MXR_GRAPHIC0_BASE); 131 DUMPREG(MXR_GRAPHIC0_SPAN); 132 DUMPREG(MXR_GRAPHIC0_WH); 133 DUMPREG(MXR_GRAPHIC0_SXY); 134 DUMPREG(MXR_GRAPHIC0_DXY); 135 136 DUMPREG(MXR_GRAPHIC1_CFG); 137 DUMPREG(MXR_GRAPHIC1_BASE); 138 DUMPREG(MXR_GRAPHIC1_SPAN); 139 DUMPREG(MXR_GRAPHIC1_WH); 140 DUMPREG(MXR_GRAPHIC1_SXY); 141 DUMPREG(MXR_GRAPHIC1_DXY); 142 #undef DUMPREG 143 } 144 145 static void vp_regs_dump(struct mixer_context *ctx) 146 { 147 #define DUMPREG(reg_id) \ 148 do { \ 149 DRM_DEBUG_KMS(#reg_id " = %08x\n", \ 150 (u32) readl(ctx->mixer_res.vp_regs + reg_id)); \ 151 } while (0) 152 153 DUMPREG(VP_ENABLE); 154 DUMPREG(VP_SRESET); 155 DUMPREG(VP_SHADOW_UPDATE); 156 DUMPREG(VP_FIELD_ID); 157 DUMPREG(VP_MODE); 158 DUMPREG(VP_IMG_SIZE_Y); 159 DUMPREG(VP_IMG_SIZE_C); 160 DUMPREG(VP_PER_RATE_CTRL); 161 DUMPREG(VP_TOP_Y_PTR); 162 DUMPREG(VP_BOT_Y_PTR); 163 DUMPREG(VP_TOP_C_PTR); 164 DUMPREG(VP_BOT_C_PTR); 165 DUMPREG(VP_ENDIAN_MODE); 166 DUMPREG(VP_SRC_H_POSITION); 167 DUMPREG(VP_SRC_V_POSITION); 168 DUMPREG(VP_SRC_WIDTH); 169 DUMPREG(VP_SRC_HEIGHT); 170 DUMPREG(VP_DST_H_POSITION); 171 DUMPREG(VP_DST_V_POSITION); 172 DUMPREG(VP_DST_WIDTH); 173 DUMPREG(VP_DST_HEIGHT); 174 DUMPREG(VP_H_RATIO); 175 DUMPREG(VP_V_RATIO); 176 177 #undef DUMPREG 178 } 179 180 static inline void vp_filter_set(struct mixer_resources *res, 181 int reg_id, const u8 *data, unsigned int size) 182 { 183 /* assure 4-byte align */ 184 BUG_ON(size & 3); 185 for (; size; size -= 4, reg_id += 4, data += 4) { 186 u32 val = (data[0] << 24) | (data[1] << 16) | 187 (data[2] << 8) | data[3]; 188 vp_reg_write(res, reg_id, val); 189 } 190 } 191 192 static void vp_default_filter(struct mixer_resources *res) 193 { 194 vp_filter_set(res, VP_POLY8_Y0_LL, 195 filter_y_horiz_tap8, sizeof filter_y_horiz_tap8); 196 vp_filter_set(res, VP_POLY4_Y0_LL, 197 filter_y_vert_tap4, sizeof filter_y_vert_tap4); 198 vp_filter_set(res, VP_POLY4_C0_LL, 199 filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4); 200 } 201 202 static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable) 203 { 204 struct mixer_resources *res = &ctx->mixer_res; 205 206 /* block update on vsync */ 207 mixer_reg_writemask(res, MXR_STATUS, enable ? 208 MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE); 209 210 vp_reg_write(res, VP_SHADOW_UPDATE, enable ? 211 VP_SHADOW_UPDATE_ENABLE : 0); 212 } 213 214 static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height) 215 { 216 struct mixer_resources *res = &ctx->mixer_res; 217 u32 val; 218 219 /* choosing between interlace and progressive mode */ 220 val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE : 221 MXR_CFG_SCAN_PROGRASSIVE); 222 223 /* choosing between porper HD and SD mode */ 224 if (height == 480) 225 val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD; 226 else if (height == 576) 227 val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD; 228 else if (height == 720) 229 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD; 230 else if (height == 1080) 231 val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD; 232 else 233 val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD; 234 235 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK); 236 } 237 238 static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height) 239 { 240 struct mixer_resources *res = &ctx->mixer_res; 241 u32 val; 242 243 if (height == 480) { 244 val = MXR_CFG_RGB601_0_255; 245 } else if (height == 576) { 246 val = MXR_CFG_RGB601_0_255; 247 } else if (height == 720) { 248 val = MXR_CFG_RGB709_16_235; 249 mixer_reg_write(res, MXR_CM_COEFF_Y, 250 (1 << 30) | (94 << 20) | (314 << 10) | 251 (32 << 0)); 252 mixer_reg_write(res, MXR_CM_COEFF_CB, 253 (972 << 20) | (851 << 10) | (225 << 0)); 254 mixer_reg_write(res, MXR_CM_COEFF_CR, 255 (225 << 20) | (820 << 10) | (1004 << 0)); 256 } else if (height == 1080) { 257 val = MXR_CFG_RGB709_16_235; 258 mixer_reg_write(res, MXR_CM_COEFF_Y, 259 (1 << 30) | (94 << 20) | (314 << 10) | 260 (32 << 0)); 261 mixer_reg_write(res, MXR_CM_COEFF_CB, 262 (972 << 20) | (851 << 10) | (225 << 0)); 263 mixer_reg_write(res, MXR_CM_COEFF_CR, 264 (225 << 20) | (820 << 10) | (1004 << 0)); 265 } else { 266 val = MXR_CFG_RGB709_16_235; 267 mixer_reg_write(res, MXR_CM_COEFF_Y, 268 (1 << 30) | (94 << 20) | (314 << 10) | 269 (32 << 0)); 270 mixer_reg_write(res, MXR_CM_COEFF_CB, 271 (972 << 20) | (851 << 10) | (225 << 0)); 272 mixer_reg_write(res, MXR_CM_COEFF_CR, 273 (225 << 20) | (820 << 10) | (1004 << 0)); 274 } 275 276 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK); 277 } 278 279 static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable) 280 { 281 struct mixer_resources *res = &ctx->mixer_res; 282 u32 val = enable ? ~0 : 0; 283 284 switch (win) { 285 case 0: 286 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE); 287 break; 288 case 1: 289 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE); 290 break; 291 case 2: 292 vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON); 293 mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE); 294 break; 295 } 296 } 297 298 static void mixer_run(struct mixer_context *ctx) 299 { 300 struct mixer_resources *res = &ctx->mixer_res; 301 302 mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN); 303 304 mixer_regs_dump(ctx); 305 } 306 307 static void vp_video_buffer(struct mixer_context *ctx, int win) 308 { 309 struct mixer_resources *res = &ctx->mixer_res; 310 unsigned long flags; 311 struct hdmi_win_data *win_data; 312 unsigned int full_width, full_height, width, height; 313 unsigned int x_ratio, y_ratio; 314 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; 315 unsigned int mode_width, mode_height; 316 unsigned int buf_num; 317 dma_addr_t luma_addr[2], chroma_addr[2]; 318 bool tiled_mode = false; 319 bool crcb_mode = false; 320 u32 val; 321 322 win_data = &ctx->win_data[win]; 323 324 switch (win_data->pixel_format) { 325 case DRM_FORMAT_NV12MT: 326 tiled_mode = true; 327 case DRM_FORMAT_NV12M: 328 crcb_mode = false; 329 buf_num = 2; 330 break; 331 /* TODO: single buffer format NV12, NV21 */ 332 default: 333 /* ignore pixel format at disable time */ 334 if (!win_data->dma_addr) 335 break; 336 337 DRM_ERROR("pixel format for vp is wrong [%d].\n", 338 win_data->pixel_format); 339 return; 340 } 341 342 full_width = win_data->fb_width; 343 full_height = win_data->fb_height; 344 width = win_data->crtc_width; 345 height = win_data->crtc_height; 346 mode_width = win_data->mode_width; 347 mode_height = win_data->mode_height; 348 349 /* scaling feature: (src << 16) / dst */ 350 x_ratio = (width << 16) / width; 351 y_ratio = (height << 16) / height; 352 353 src_x_offset = win_data->fb_x; 354 src_y_offset = win_data->fb_y; 355 dst_x_offset = win_data->crtc_x; 356 dst_y_offset = win_data->crtc_y; 357 358 if (buf_num == 2) { 359 luma_addr[0] = win_data->dma_addr; 360 chroma_addr[0] = win_data->chroma_dma_addr; 361 } else { 362 luma_addr[0] = win_data->dma_addr; 363 chroma_addr[0] = win_data->dma_addr 364 + (full_width * full_height); 365 } 366 367 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) { 368 ctx->interlace = true; 369 if (tiled_mode) { 370 luma_addr[1] = luma_addr[0] + 0x40; 371 chroma_addr[1] = chroma_addr[0] + 0x40; 372 } else { 373 luma_addr[1] = luma_addr[0] + full_width; 374 chroma_addr[1] = chroma_addr[0] + full_width; 375 } 376 } else { 377 ctx->interlace = false; 378 luma_addr[1] = 0; 379 chroma_addr[1] = 0; 380 } 381 382 spin_lock_irqsave(&res->reg_slock, flags); 383 mixer_vsync_set_update(ctx, false); 384 385 /* interlace or progressive scan mode */ 386 val = (ctx->interlace ? ~0 : 0); 387 vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP); 388 389 /* setup format */ 390 val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12); 391 val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR); 392 vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); 393 394 /* setting size of input image */ 395 vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(full_width) | 396 VP_IMG_VSIZE(full_height)); 397 /* chroma height has to reduced by 2 to avoid chroma distorions */ 398 vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(full_width) | 399 VP_IMG_VSIZE(full_height / 2)); 400 401 vp_reg_write(res, VP_SRC_WIDTH, width); 402 vp_reg_write(res, VP_SRC_HEIGHT, height); 403 vp_reg_write(res, VP_SRC_H_POSITION, 404 VP_SRC_H_POSITION_VAL(src_x_offset)); 405 vp_reg_write(res, VP_SRC_V_POSITION, src_y_offset); 406 407 vp_reg_write(res, VP_DST_WIDTH, width); 408 vp_reg_write(res, VP_DST_H_POSITION, dst_x_offset); 409 if (ctx->interlace) { 410 vp_reg_write(res, VP_DST_HEIGHT, height / 2); 411 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset / 2); 412 } else { 413 vp_reg_write(res, VP_DST_HEIGHT, height); 414 vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset); 415 } 416 417 vp_reg_write(res, VP_H_RATIO, x_ratio); 418 vp_reg_write(res, VP_V_RATIO, y_ratio); 419 420 vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE); 421 422 /* set buffer address to vp */ 423 vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]); 424 vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]); 425 vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]); 426 vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]); 427 428 mixer_cfg_scan(ctx, mode_height); 429 mixer_cfg_rgb_fmt(ctx, mode_height); 430 mixer_cfg_layer(ctx, win, true); 431 mixer_run(ctx); 432 433 mixer_vsync_set_update(ctx, true); 434 spin_unlock_irqrestore(&res->reg_slock, flags); 435 436 vp_regs_dump(ctx); 437 } 438 439 static void mixer_graph_buffer(struct mixer_context *ctx, int win) 440 { 441 struct mixer_resources *res = &ctx->mixer_res; 442 unsigned long flags; 443 struct hdmi_win_data *win_data; 444 unsigned int full_width, width, height; 445 unsigned int x_ratio, y_ratio; 446 unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; 447 unsigned int mode_width, mode_height; 448 dma_addr_t dma_addr; 449 unsigned int fmt; 450 u32 val; 451 452 win_data = &ctx->win_data[win]; 453 454 #define RGB565 4 455 #define ARGB1555 5 456 #define ARGB4444 6 457 #define ARGB8888 7 458 459 switch (win_data->bpp) { 460 case 16: 461 fmt = ARGB4444; 462 break; 463 case 32: 464 fmt = ARGB8888; 465 break; 466 default: 467 fmt = ARGB8888; 468 } 469 470 dma_addr = win_data->dma_addr; 471 full_width = win_data->fb_width; 472 width = win_data->crtc_width; 473 height = win_data->crtc_height; 474 mode_width = win_data->mode_width; 475 mode_height = win_data->mode_height; 476 477 /* 2x scaling feature */ 478 x_ratio = 0; 479 y_ratio = 0; 480 481 src_x_offset = win_data->fb_x; 482 src_y_offset = win_data->fb_y; 483 dst_x_offset = win_data->crtc_x; 484 dst_y_offset = win_data->crtc_y; 485 486 /* converting dma address base and source offset */ 487 dma_addr = dma_addr 488 + (src_x_offset * win_data->bpp >> 3) 489 + (src_y_offset * full_width * win_data->bpp >> 3); 490 src_x_offset = 0; 491 src_y_offset = 0; 492 493 if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) 494 ctx->interlace = true; 495 else 496 ctx->interlace = false; 497 498 spin_lock_irqsave(&res->reg_slock, flags); 499 mixer_vsync_set_update(ctx, false); 500 501 /* setup format */ 502 mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win), 503 MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK); 504 505 /* setup geometry */ 506 mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), full_width); 507 508 val = MXR_GRP_WH_WIDTH(width); 509 val |= MXR_GRP_WH_HEIGHT(height); 510 val |= MXR_GRP_WH_H_SCALE(x_ratio); 511 val |= MXR_GRP_WH_V_SCALE(y_ratio); 512 mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); 513 514 /* setup offsets in source image */ 515 val = MXR_GRP_SXY_SX(src_x_offset); 516 val |= MXR_GRP_SXY_SY(src_y_offset); 517 mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val); 518 519 /* setup offsets in display image */ 520 val = MXR_GRP_DXY_DX(dst_x_offset); 521 val |= MXR_GRP_DXY_DY(dst_y_offset); 522 mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val); 523 524 /* set buffer address to mixer */ 525 mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr); 526 527 mixer_cfg_scan(ctx, mode_height); 528 mixer_cfg_rgb_fmt(ctx, mode_height); 529 mixer_cfg_layer(ctx, win, true); 530 mixer_run(ctx); 531 532 mixer_vsync_set_update(ctx, true); 533 spin_unlock_irqrestore(&res->reg_slock, flags); 534 } 535 536 static void vp_win_reset(struct mixer_context *ctx) 537 { 538 struct mixer_resources *res = &ctx->mixer_res; 539 int tries = 100; 540 541 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING); 542 for (tries = 100; tries; --tries) { 543 /* waiting until VP_SRESET_PROCESSING is 0 */ 544 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING) 545 break; 546 mdelay(10); 547 } 548 WARN(tries == 0, "failed to reset Video Processor\n"); 549 } 550 551 static int mixer_enable_vblank(void *ctx, int pipe) 552 { 553 struct mixer_context *mixer_ctx = ctx; 554 struct mixer_resources *res = &mixer_ctx->mixer_res; 555 556 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 557 558 mixer_ctx->pipe = pipe; 559 560 /* enable vsync interrupt */ 561 mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC, 562 MXR_INT_EN_VSYNC); 563 564 return 0; 565 } 566 567 static void mixer_disable_vblank(void *ctx) 568 { 569 struct mixer_context *mixer_ctx = ctx; 570 struct mixer_resources *res = &mixer_ctx->mixer_res; 571 572 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 573 574 /* disable vsync interrupt */ 575 mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); 576 } 577 578 static void mixer_win_mode_set(void *ctx, 579 struct exynos_drm_overlay *overlay) 580 { 581 struct mixer_context *mixer_ctx = ctx; 582 struct hdmi_win_data *win_data; 583 int win; 584 585 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 586 587 if (!overlay) { 588 DRM_ERROR("overlay is NULL\n"); 589 return; 590 } 591 592 DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n", 593 overlay->fb_width, overlay->fb_height, 594 overlay->fb_x, overlay->fb_y, 595 overlay->crtc_width, overlay->crtc_height, 596 overlay->crtc_x, overlay->crtc_y); 597 598 win = overlay->zpos; 599 if (win == DEFAULT_ZPOS) 600 win = mixer_ctx->default_win; 601 602 if (win < 0 || win > HDMI_OVERLAY_NUMBER) { 603 DRM_ERROR("overlay plane[%d] is wrong\n", win); 604 return; 605 } 606 607 win_data = &mixer_ctx->win_data[win]; 608 609 win_data->dma_addr = overlay->dma_addr[0]; 610 win_data->vaddr = overlay->vaddr[0]; 611 win_data->chroma_dma_addr = overlay->dma_addr[1]; 612 win_data->chroma_vaddr = overlay->vaddr[1]; 613 win_data->pixel_format = overlay->pixel_format; 614 win_data->bpp = overlay->bpp; 615 616 win_data->crtc_x = overlay->crtc_x; 617 win_data->crtc_y = overlay->crtc_y; 618 win_data->crtc_width = overlay->crtc_width; 619 win_data->crtc_height = overlay->crtc_height; 620 621 win_data->fb_x = overlay->fb_x; 622 win_data->fb_y = overlay->fb_y; 623 win_data->fb_width = overlay->fb_width; 624 win_data->fb_height = overlay->fb_height; 625 626 win_data->mode_width = overlay->mode_width; 627 win_data->mode_height = overlay->mode_height; 628 629 win_data->scan_flags = overlay->scan_flag; 630 } 631 632 static void mixer_win_commit(void *ctx, int zpos) 633 { 634 struct mixer_context *mixer_ctx = ctx; 635 int win = zpos; 636 637 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); 638 639 if (win == DEFAULT_ZPOS) 640 win = mixer_ctx->default_win; 641 642 if (win < 0 || win > HDMI_OVERLAY_NUMBER) { 643 DRM_ERROR("overlay plane[%d] is wrong\n", win); 644 return; 645 } 646 647 if (win > 1) 648 vp_video_buffer(mixer_ctx, win); 649 else 650 mixer_graph_buffer(mixer_ctx, win); 651 } 652 653 static void mixer_win_disable(void *ctx, int zpos) 654 { 655 struct mixer_context *mixer_ctx = ctx; 656 struct mixer_resources *res = &mixer_ctx->mixer_res; 657 unsigned long flags; 658 int win = zpos; 659 660 DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); 661 662 if (win == DEFAULT_ZPOS) 663 win = mixer_ctx->default_win; 664 665 if (win < 0 || win > HDMI_OVERLAY_NUMBER) { 666 DRM_ERROR("overlay plane[%d] is wrong\n", win); 667 return; 668 } 669 670 spin_lock_irqsave(&res->reg_slock, flags); 671 mixer_vsync_set_update(mixer_ctx, false); 672 673 mixer_cfg_layer(mixer_ctx, win, false); 674 675 mixer_vsync_set_update(mixer_ctx, true); 676 spin_unlock_irqrestore(&res->reg_slock, flags); 677 } 678 679 static struct exynos_hdmi_overlay_ops overlay_ops = { 680 .enable_vblank = mixer_enable_vblank, 681 .disable_vblank = mixer_disable_vblank, 682 .win_mode_set = mixer_win_mode_set, 683 .win_commit = mixer_win_commit, 684 .win_disable = mixer_win_disable, 685 }; 686 687 /* for pageflip event */ 688 static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc) 689 { 690 struct exynos_drm_private *dev_priv = drm_dev->dev_private; 691 struct drm_pending_vblank_event *e, *t; 692 struct timeval now; 693 unsigned long flags; 694 bool is_checked = false; 695 696 spin_lock_irqsave(&drm_dev->event_lock, flags); 697 698 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, 699 base.link) { 700 /* if event's pipe isn't same as crtc then ignore it. */ 701 if (crtc != e->pipe) 702 continue; 703 704 is_checked = true; 705 do_gettimeofday(&now); 706 e->event.sequence = 0; 707 e->event.tv_sec = now.tv_sec; 708 e->event.tv_usec = now.tv_usec; 709 710 list_move_tail(&e->base.link, &e->base.file_priv->event_list); 711 wake_up_interruptible(&e->base.file_priv->event_wait); 712 } 713 714 if (is_checked) 715 /* 716 * call drm_vblank_put only in case that drm_vblank_get was 717 * called. 718 */ 719 if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0) 720 drm_vblank_put(drm_dev, crtc); 721 722 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 723 } 724 725 static irqreturn_t mixer_irq_handler(int irq, void *arg) 726 { 727 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg; 728 struct mixer_context *ctx = 729 (struct mixer_context *)drm_hdmi_ctx->ctx; 730 struct mixer_resources *res = &ctx->mixer_res; 731 u32 val, val_base; 732 733 spin_lock(&res->reg_slock); 734 735 /* read interrupt status for handling and clearing flags for VSYNC */ 736 val = mixer_reg_read(res, MXR_INT_STATUS); 737 738 /* handling VSYNC */ 739 if (val & MXR_INT_STATUS_VSYNC) { 740 /* interlace scan need to check shadow register */ 741 if (ctx->interlace) { 742 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0)); 743 if (ctx->win_data[0].dma_addr != val_base) 744 goto out; 745 746 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1)); 747 if (ctx->win_data[1].dma_addr != val_base) 748 goto out; 749 } 750 751 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe); 752 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe); 753 } 754 755 out: 756 /* clear interrupts */ 757 if (~val & MXR_INT_EN_VSYNC) { 758 /* vsync interrupt use different bit for read and clear */ 759 val &= ~MXR_INT_EN_VSYNC; 760 val |= MXR_INT_CLEAR_VSYNC; 761 } 762 mixer_reg_write(res, MXR_INT_STATUS, val); 763 764 spin_unlock(&res->reg_slock); 765 766 return IRQ_HANDLED; 767 } 768 769 static void mixer_win_reset(struct mixer_context *ctx) 770 { 771 struct mixer_resources *res = &ctx->mixer_res; 772 unsigned long flags; 773 u32 val; /* value stored to register */ 774 775 spin_lock_irqsave(&res->reg_slock, flags); 776 mixer_vsync_set_update(ctx, false); 777 778 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK); 779 780 /* set output in RGB888 mode */ 781 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK); 782 783 /* 16 beat burst in DMA */ 784 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST, 785 MXR_STATUS_BURST_MASK); 786 787 /* setting default layer priority: layer1 > layer0 > video 788 * because typical usage scenario would be 789 * layer1 - OSD 790 * layer0 - framebuffer 791 * video - video overlay 792 */ 793 val = MXR_LAYER_CFG_GRP1_VAL(3); 794 val |= MXR_LAYER_CFG_GRP0_VAL(2); 795 val |= MXR_LAYER_CFG_VP_VAL(1); 796 mixer_reg_write(res, MXR_LAYER_CFG, val); 797 798 /* setting background color */ 799 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080); 800 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080); 801 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); 802 803 /* setting graphical layers */ 804 805 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ 806 val |= MXR_GRP_CFG_WIN_BLEND_EN; 807 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ 808 809 /* the same configuration for both layers */ 810 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); 811 812 val |= MXR_GRP_CFG_BLEND_PRE_MUL; 813 val |= MXR_GRP_CFG_PIXEL_BLEND_EN; 814 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); 815 816 /* configuration of Video Processor Registers */ 817 vp_win_reset(ctx); 818 vp_default_filter(res); 819 820 /* disable all layers */ 821 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE); 822 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE); 823 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); 824 825 mixer_vsync_set_update(ctx, true); 826 spin_unlock_irqrestore(&res->reg_slock, flags); 827 } 828 829 static void mixer_resource_poweron(struct mixer_context *ctx) 830 { 831 struct mixer_resources *res = &ctx->mixer_res; 832 833 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 834 835 clk_enable(res->mixer); 836 clk_enable(res->vp); 837 clk_enable(res->sclk_mixer); 838 839 mixer_win_reset(ctx); 840 } 841 842 static void mixer_resource_poweroff(struct mixer_context *ctx) 843 { 844 struct mixer_resources *res = &ctx->mixer_res; 845 846 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 847 848 clk_disable(res->mixer); 849 clk_disable(res->vp); 850 clk_disable(res->sclk_mixer); 851 } 852 853 static int mixer_runtime_resume(struct device *dev) 854 { 855 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev); 856 857 DRM_DEBUG_KMS("resume - start\n"); 858 859 mixer_resource_poweron((struct mixer_context *)ctx->ctx); 860 861 return 0; 862 } 863 864 static int mixer_runtime_suspend(struct device *dev) 865 { 866 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev); 867 868 DRM_DEBUG_KMS("suspend - start\n"); 869 870 mixer_resource_poweroff((struct mixer_context *)ctx->ctx); 871 872 return 0; 873 } 874 875 static const struct dev_pm_ops mixer_pm_ops = { 876 .runtime_suspend = mixer_runtime_suspend, 877 .runtime_resume = mixer_runtime_resume, 878 }; 879 880 static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, 881 struct platform_device *pdev) 882 { 883 struct mixer_context *mixer_ctx = 884 (struct mixer_context *)ctx->ctx; 885 struct device *dev = &pdev->dev; 886 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; 887 struct resource *res; 888 int ret; 889 890 mixer_res->dev = dev; 891 spin_lock_init(&mixer_res->reg_slock); 892 893 mixer_res->mixer = clk_get(dev, "mixer"); 894 if (IS_ERR_OR_NULL(mixer_res->mixer)) { 895 dev_err(dev, "failed to get clock 'mixer'\n"); 896 ret = -ENODEV; 897 goto fail; 898 } 899 mixer_res->vp = clk_get(dev, "vp"); 900 if (IS_ERR_OR_NULL(mixer_res->vp)) { 901 dev_err(dev, "failed to get clock 'vp'\n"); 902 ret = -ENODEV; 903 goto fail; 904 } 905 mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer"); 906 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { 907 dev_err(dev, "failed to get clock 'sclk_mixer'\n"); 908 ret = -ENODEV; 909 goto fail; 910 } 911 mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); 912 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) { 913 dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); 914 ret = -ENODEV; 915 goto fail; 916 } 917 mixer_res->sclk_dac = clk_get(dev, "sclk_dac"); 918 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { 919 dev_err(dev, "failed to get clock 'sclk_dac'\n"); 920 ret = -ENODEV; 921 goto fail; 922 } 923 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr"); 924 if (res == NULL) { 925 dev_err(dev, "get memory resource failed.\n"); 926 ret = -ENXIO; 927 goto fail; 928 } 929 930 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); 931 932 mixer_res->mixer_regs = ioremap(res->start, resource_size(res)); 933 if (mixer_res->mixer_regs == NULL) { 934 dev_err(dev, "register mapping failed.\n"); 935 ret = -ENXIO; 936 goto fail; 937 } 938 939 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp"); 940 if (res == NULL) { 941 dev_err(dev, "get memory resource failed.\n"); 942 ret = -ENXIO; 943 goto fail_mixer_regs; 944 } 945 946 mixer_res->vp_regs = ioremap(res->start, resource_size(res)); 947 if (mixer_res->vp_regs == NULL) { 948 dev_err(dev, "register mapping failed.\n"); 949 ret = -ENXIO; 950 goto fail_mixer_regs; 951 } 952 953 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq"); 954 if (res == NULL) { 955 dev_err(dev, "get interrupt resource failed.\n"); 956 ret = -ENXIO; 957 goto fail_vp_regs; 958 } 959 960 ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx); 961 if (ret) { 962 dev_err(dev, "request interrupt failed.\n"); 963 goto fail_vp_regs; 964 } 965 mixer_res->irq = res->start; 966 967 return 0; 968 969 fail_vp_regs: 970 iounmap(mixer_res->vp_regs); 971 972 fail_mixer_regs: 973 iounmap(mixer_res->mixer_regs); 974 975 fail: 976 if (!IS_ERR_OR_NULL(mixer_res->sclk_dac)) 977 clk_put(mixer_res->sclk_dac); 978 if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) 979 clk_put(mixer_res->sclk_hdmi); 980 if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer)) 981 clk_put(mixer_res->sclk_mixer); 982 if (!IS_ERR_OR_NULL(mixer_res->vp)) 983 clk_put(mixer_res->vp); 984 if (!IS_ERR_OR_NULL(mixer_res->mixer)) 985 clk_put(mixer_res->mixer); 986 mixer_res->dev = NULL; 987 return ret; 988 } 989 990 static void mixer_resources_cleanup(struct mixer_context *ctx) 991 { 992 struct mixer_resources *res = &ctx->mixer_res; 993 994 disable_irq(res->irq); 995 free_irq(res->irq, ctx); 996 997 iounmap(res->vp_regs); 998 iounmap(res->mixer_regs); 999 } 1000 1001 static int __devinit mixer_probe(struct platform_device *pdev) 1002 { 1003 struct device *dev = &pdev->dev; 1004 struct exynos_drm_hdmi_context *drm_hdmi_ctx; 1005 struct mixer_context *ctx; 1006 int ret; 1007 1008 dev_info(dev, "probe start\n"); 1009 1010 drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL); 1011 if (!drm_hdmi_ctx) { 1012 DRM_ERROR("failed to allocate common hdmi context.\n"); 1013 return -ENOMEM; 1014 } 1015 1016 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 1017 if (!ctx) { 1018 DRM_ERROR("failed to alloc mixer context.\n"); 1019 kfree(drm_hdmi_ctx); 1020 return -ENOMEM; 1021 } 1022 1023 drm_hdmi_ctx->ctx = (void *)ctx; 1024 1025 platform_set_drvdata(pdev, drm_hdmi_ctx); 1026 1027 /* acquire resources: regs, irqs, clocks */ 1028 ret = mixer_resources_init(drm_hdmi_ctx, pdev); 1029 if (ret) 1030 goto fail; 1031 1032 /* register specific callback point to common hdmi. */ 1033 exynos_drm_overlay_ops_register(&overlay_ops); 1034 1035 mixer_resource_poweron(ctx); 1036 1037 return 0; 1038 1039 1040 fail: 1041 dev_info(dev, "probe failed\n"); 1042 return ret; 1043 } 1044 1045 static int mixer_remove(struct platform_device *pdev) 1046 { 1047 struct device *dev = &pdev->dev; 1048 struct exynos_drm_hdmi_context *drm_hdmi_ctx = 1049 platform_get_drvdata(pdev); 1050 struct mixer_context *ctx = (struct mixer_context *)drm_hdmi_ctx->ctx; 1051 1052 dev_info(dev, "remove successful\n"); 1053 1054 mixer_resource_poweroff(ctx); 1055 mixer_resources_cleanup(ctx); 1056 1057 return 0; 1058 } 1059 1060 struct platform_driver mixer_driver = { 1061 .driver = { 1062 .name = "s5p-mixer", 1063 .owner = THIS_MODULE, 1064 .pm = &mixer_pm_ops, 1065 }, 1066 .probe = mixer_probe, 1067 .remove = __devexit_p(mixer_remove), 1068 }; 1069 EXPORT_SYMBOL(mixer_driver); 1070 1071 MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>"); 1072 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 1073 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 1074 MODULE_DESCRIPTION("Samsung DRM HDMI mixer Driver"); 1075 MODULE_LICENSE("GPL"); 1076