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 drm_vblank_put(drm_dev, crtc); 716 717 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 718 } 719 720 static irqreturn_t mixer_irq_handler(int irq, void *arg) 721 { 722 struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg; 723 struct mixer_context *ctx = 724 (struct mixer_context *)drm_hdmi_ctx->ctx; 725 struct mixer_resources *res = &ctx->mixer_res; 726 u32 val, val_base; 727 728 spin_lock(&res->reg_slock); 729 730 /* read interrupt status for handling and clearing flags for VSYNC */ 731 val = mixer_reg_read(res, MXR_INT_STATUS); 732 733 /* handling VSYNC */ 734 if (val & MXR_INT_STATUS_VSYNC) { 735 /* interlace scan need to check shadow register */ 736 if (ctx->interlace) { 737 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0)); 738 if (ctx->win_data[0].dma_addr != val_base) 739 goto out; 740 741 val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1)); 742 if (ctx->win_data[1].dma_addr != val_base) 743 goto out; 744 } 745 746 drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe); 747 mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe); 748 } 749 750 out: 751 /* clear interrupts */ 752 if (~val & MXR_INT_EN_VSYNC) { 753 /* vsync interrupt use different bit for read and clear */ 754 val &= ~MXR_INT_EN_VSYNC; 755 val |= MXR_INT_CLEAR_VSYNC; 756 } 757 mixer_reg_write(res, MXR_INT_STATUS, val); 758 759 spin_unlock(&res->reg_slock); 760 761 return IRQ_HANDLED; 762 } 763 764 static void mixer_win_reset(struct mixer_context *ctx) 765 { 766 struct mixer_resources *res = &ctx->mixer_res; 767 unsigned long flags; 768 u32 val; /* value stored to register */ 769 770 spin_lock_irqsave(&res->reg_slock, flags); 771 mixer_vsync_set_update(ctx, false); 772 773 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK); 774 775 /* set output in RGB888 mode */ 776 mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK); 777 778 /* 16 beat burst in DMA */ 779 mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST, 780 MXR_STATUS_BURST_MASK); 781 782 /* setting default layer priority: layer1 > layer0 > video 783 * because typical usage scenario would be 784 * layer1 - OSD 785 * layer0 - framebuffer 786 * video - video overlay 787 */ 788 val = MXR_LAYER_CFG_GRP1_VAL(3); 789 val |= MXR_LAYER_CFG_GRP0_VAL(2); 790 val |= MXR_LAYER_CFG_VP_VAL(1); 791 mixer_reg_write(res, MXR_LAYER_CFG, val); 792 793 /* setting background color */ 794 mixer_reg_write(res, MXR_BG_COLOR0, 0x008080); 795 mixer_reg_write(res, MXR_BG_COLOR1, 0x008080); 796 mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); 797 798 /* setting graphical layers */ 799 800 val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ 801 val |= MXR_GRP_CFG_WIN_BLEND_EN; 802 val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ 803 804 /* the same configuration for both layers */ 805 mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); 806 807 val |= MXR_GRP_CFG_BLEND_PRE_MUL; 808 val |= MXR_GRP_CFG_PIXEL_BLEND_EN; 809 mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); 810 811 /* configuration of Video Processor Registers */ 812 vp_win_reset(ctx); 813 vp_default_filter(res); 814 815 /* disable all layers */ 816 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE); 817 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE); 818 mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); 819 820 mixer_vsync_set_update(ctx, true); 821 spin_unlock_irqrestore(&res->reg_slock, flags); 822 } 823 824 static void mixer_resource_poweron(struct mixer_context *ctx) 825 { 826 struct mixer_resources *res = &ctx->mixer_res; 827 828 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 829 830 clk_enable(res->mixer); 831 clk_enable(res->vp); 832 clk_enable(res->sclk_mixer); 833 834 mixer_win_reset(ctx); 835 } 836 837 static void mixer_resource_poweroff(struct mixer_context *ctx) 838 { 839 struct mixer_resources *res = &ctx->mixer_res; 840 841 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 842 843 clk_disable(res->mixer); 844 clk_disable(res->vp); 845 clk_disable(res->sclk_mixer); 846 } 847 848 static int mixer_runtime_resume(struct device *dev) 849 { 850 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev); 851 852 DRM_DEBUG_KMS("resume - start\n"); 853 854 mixer_resource_poweron((struct mixer_context *)ctx->ctx); 855 856 return 0; 857 } 858 859 static int mixer_runtime_suspend(struct device *dev) 860 { 861 struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev); 862 863 DRM_DEBUG_KMS("suspend - start\n"); 864 865 mixer_resource_poweroff((struct mixer_context *)ctx->ctx); 866 867 return 0; 868 } 869 870 static const struct dev_pm_ops mixer_pm_ops = { 871 .runtime_suspend = mixer_runtime_suspend, 872 .runtime_resume = mixer_runtime_resume, 873 }; 874 875 static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, 876 struct platform_device *pdev) 877 { 878 struct mixer_context *mixer_ctx = 879 (struct mixer_context *)ctx->ctx; 880 struct device *dev = &pdev->dev; 881 struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; 882 struct resource *res; 883 int ret; 884 885 mixer_res->dev = dev; 886 spin_lock_init(&mixer_res->reg_slock); 887 888 mixer_res->mixer = clk_get(dev, "mixer"); 889 if (IS_ERR_OR_NULL(mixer_res->mixer)) { 890 dev_err(dev, "failed to get clock 'mixer'\n"); 891 ret = -ENODEV; 892 goto fail; 893 } 894 mixer_res->vp = clk_get(dev, "vp"); 895 if (IS_ERR_OR_NULL(mixer_res->vp)) { 896 dev_err(dev, "failed to get clock 'vp'\n"); 897 ret = -ENODEV; 898 goto fail; 899 } 900 mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer"); 901 if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { 902 dev_err(dev, "failed to get clock 'sclk_mixer'\n"); 903 ret = -ENODEV; 904 goto fail; 905 } 906 mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); 907 if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) { 908 dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); 909 ret = -ENODEV; 910 goto fail; 911 } 912 mixer_res->sclk_dac = clk_get(dev, "sclk_dac"); 913 if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { 914 dev_err(dev, "failed to get clock 'sclk_dac'\n"); 915 ret = -ENODEV; 916 goto fail; 917 } 918 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr"); 919 if (res == NULL) { 920 dev_err(dev, "get memory resource failed.\n"); 921 ret = -ENXIO; 922 goto fail; 923 } 924 925 clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); 926 927 mixer_res->mixer_regs = ioremap(res->start, resource_size(res)); 928 if (mixer_res->mixer_regs == NULL) { 929 dev_err(dev, "register mapping failed.\n"); 930 ret = -ENXIO; 931 goto fail; 932 } 933 934 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp"); 935 if (res == NULL) { 936 dev_err(dev, "get memory resource failed.\n"); 937 ret = -ENXIO; 938 goto fail_mixer_regs; 939 } 940 941 mixer_res->vp_regs = ioremap(res->start, resource_size(res)); 942 if (mixer_res->vp_regs == NULL) { 943 dev_err(dev, "register mapping failed.\n"); 944 ret = -ENXIO; 945 goto fail_mixer_regs; 946 } 947 948 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq"); 949 if (res == NULL) { 950 dev_err(dev, "get interrupt resource failed.\n"); 951 ret = -ENXIO; 952 goto fail_vp_regs; 953 } 954 955 ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx); 956 if (ret) { 957 dev_err(dev, "request interrupt failed.\n"); 958 goto fail_vp_regs; 959 } 960 mixer_res->irq = res->start; 961 962 return 0; 963 964 fail_vp_regs: 965 iounmap(mixer_res->vp_regs); 966 967 fail_mixer_regs: 968 iounmap(mixer_res->mixer_regs); 969 970 fail: 971 if (!IS_ERR_OR_NULL(mixer_res->sclk_dac)) 972 clk_put(mixer_res->sclk_dac); 973 if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) 974 clk_put(mixer_res->sclk_hdmi); 975 if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer)) 976 clk_put(mixer_res->sclk_mixer); 977 if (!IS_ERR_OR_NULL(mixer_res->vp)) 978 clk_put(mixer_res->vp); 979 if (!IS_ERR_OR_NULL(mixer_res->mixer)) 980 clk_put(mixer_res->mixer); 981 mixer_res->dev = NULL; 982 return ret; 983 } 984 985 static void mixer_resources_cleanup(struct mixer_context *ctx) 986 { 987 struct mixer_resources *res = &ctx->mixer_res; 988 989 disable_irq(res->irq); 990 free_irq(res->irq, ctx); 991 992 iounmap(res->vp_regs); 993 iounmap(res->mixer_regs); 994 } 995 996 static int __devinit mixer_probe(struct platform_device *pdev) 997 { 998 struct device *dev = &pdev->dev; 999 struct exynos_drm_hdmi_context *drm_hdmi_ctx; 1000 struct mixer_context *ctx; 1001 int ret; 1002 1003 dev_info(dev, "probe start\n"); 1004 1005 drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL); 1006 if (!drm_hdmi_ctx) { 1007 DRM_ERROR("failed to allocate common hdmi context.\n"); 1008 return -ENOMEM; 1009 } 1010 1011 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 1012 if (!ctx) { 1013 DRM_ERROR("failed to alloc mixer context.\n"); 1014 kfree(drm_hdmi_ctx); 1015 return -ENOMEM; 1016 } 1017 1018 drm_hdmi_ctx->ctx = (void *)ctx; 1019 1020 platform_set_drvdata(pdev, drm_hdmi_ctx); 1021 1022 /* acquire resources: regs, irqs, clocks */ 1023 ret = mixer_resources_init(drm_hdmi_ctx, pdev); 1024 if (ret) 1025 goto fail; 1026 1027 /* register specific callback point to common hdmi. */ 1028 exynos_drm_overlay_ops_register(&overlay_ops); 1029 1030 mixer_resource_poweron(ctx); 1031 1032 return 0; 1033 1034 1035 fail: 1036 dev_info(dev, "probe failed\n"); 1037 return ret; 1038 } 1039 1040 static int mixer_remove(struct platform_device *pdev) 1041 { 1042 struct device *dev = &pdev->dev; 1043 struct exynos_drm_hdmi_context *drm_hdmi_ctx = 1044 platform_get_drvdata(pdev); 1045 struct mixer_context *ctx = (struct mixer_context *)drm_hdmi_ctx->ctx; 1046 1047 dev_info(dev, "remove successful\n"); 1048 1049 mixer_resource_poweroff(ctx); 1050 mixer_resources_cleanup(ctx); 1051 1052 return 0; 1053 } 1054 1055 struct platform_driver mixer_driver = { 1056 .driver = { 1057 .name = "s5p-mixer", 1058 .owner = THIS_MODULE, 1059 .pm = &mixer_pm_ops, 1060 }, 1061 .probe = mixer_probe, 1062 .remove = __devexit_p(mixer_remove), 1063 }; 1064 EXPORT_SYMBOL(mixer_driver); 1065 1066 MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>"); 1067 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 1068 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 1069 MODULE_DESCRIPTION("Samsung DRM HDMI mixer Driver"); 1070 MODULE_LICENSE("GPL"); 1071