1 /* 2 * Copyright (C) STMicroelectronics SA 2014 3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Vincent Abriou <vincent.abriou@st.com> 5 * for STMicroelectronics. 6 * License terms: GNU General Public License (GPL), version 2 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/component.h> 11 #include <linux/module.h> 12 #include <linux/of_platform.h> 13 #include <linux/platform_device.h> 14 #include <linux/reset.h> 15 16 #include <drm/drmP.h> 17 #include <drm/drm_crtc_helper.h> 18 19 #include "sti_crtc.h" 20 21 /* glue registers */ 22 #define TVO_CSC_MAIN_M0 0x000 23 #define TVO_CSC_MAIN_M1 0x004 24 #define TVO_CSC_MAIN_M2 0x008 25 #define TVO_CSC_MAIN_M3 0x00c 26 #define TVO_CSC_MAIN_M4 0x010 27 #define TVO_CSC_MAIN_M5 0x014 28 #define TVO_CSC_MAIN_M6 0x018 29 #define TVO_CSC_MAIN_M7 0x01c 30 #define TVO_MAIN_IN_VID_FORMAT 0x030 31 #define TVO_CSC_AUX_M0 0x100 32 #define TVO_CSC_AUX_M1 0x104 33 #define TVO_CSC_AUX_M2 0x108 34 #define TVO_CSC_AUX_M3 0x10c 35 #define TVO_CSC_AUX_M4 0x110 36 #define TVO_CSC_AUX_M5 0x114 37 #define TVO_CSC_AUX_M6 0x118 38 #define TVO_CSC_AUX_M7 0x11c 39 #define TVO_AUX_IN_VID_FORMAT 0x130 40 #define TVO_VIP_HDF 0x400 41 #define TVO_HD_SYNC_SEL 0x418 42 #define TVO_HD_DAC_CFG_OFF 0x420 43 #define TVO_VIP_HDMI 0x500 44 #define TVO_HDMI_FORCE_COLOR_0 0x504 45 #define TVO_HDMI_FORCE_COLOR_1 0x508 46 #define TVO_HDMI_CLIP_VALUE_B_CB 0x50c 47 #define TVO_HDMI_CLIP_VALUE_Y_G 0x510 48 #define TVO_HDMI_CLIP_VALUE_R_CR 0x514 49 #define TVO_HDMI_SYNC_SEL 0x518 50 #define TVO_HDMI_DFV_OBS 0x540 51 #define TVO_VIP_DVO 0x600 52 #define TVO_DVO_SYNC_SEL 0x618 53 #define TVO_DVO_CONFIG 0x620 54 55 #define TVO_IN_FMT_SIGNED BIT(0) 56 #define TVO_SYNC_EXT BIT(4) 57 58 #define TVO_VIP_REORDER_R_SHIFT 24 59 #define TVO_VIP_REORDER_G_SHIFT 20 60 #define TVO_VIP_REORDER_B_SHIFT 16 61 #define TVO_VIP_REORDER_MASK 0x3 62 #define TVO_VIP_REORDER_Y_G_SEL 0 63 #define TVO_VIP_REORDER_CB_B_SEL 1 64 #define TVO_VIP_REORDER_CR_R_SEL 2 65 66 #define TVO_VIP_CLIP_SHIFT 8 67 #define TVO_VIP_CLIP_MASK 0x7 68 #define TVO_VIP_CLIP_DISABLED 0 69 #define TVO_VIP_CLIP_EAV_SAV 1 70 #define TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y 2 71 #define TVO_VIP_CLIP_LIMITED_RANGE_CB_CR 3 72 #define TVO_VIP_CLIP_PROG_RANGE 4 73 74 #define TVO_VIP_RND_SHIFT 4 75 #define TVO_VIP_RND_MASK 0x3 76 #define TVO_VIP_RND_8BIT_ROUNDED 0 77 #define TVO_VIP_RND_10BIT_ROUNDED 1 78 #define TVO_VIP_RND_12BIT_ROUNDED 2 79 80 #define TVO_VIP_SEL_INPUT_MASK 0xf 81 #define TVO_VIP_SEL_INPUT_MAIN 0x0 82 #define TVO_VIP_SEL_INPUT_AUX 0x8 83 #define TVO_VIP_SEL_INPUT_FORCE_COLOR 0xf 84 #define TVO_VIP_SEL_INPUT_BYPASS_MASK 0x1 85 #define TVO_VIP_SEL_INPUT_BYPASSED 1 86 87 #define TVO_SYNC_MAIN_VTG_SET_REF 0x00 88 #define TVO_SYNC_MAIN_VTG_SET_1 0x01 89 #define TVO_SYNC_MAIN_VTG_SET_2 0x02 90 #define TVO_SYNC_MAIN_VTG_SET_3 0x03 91 #define TVO_SYNC_MAIN_VTG_SET_4 0x04 92 #define TVO_SYNC_MAIN_VTG_SET_5 0x05 93 #define TVO_SYNC_MAIN_VTG_SET_6 0x06 94 #define TVO_SYNC_AUX_VTG_SET_REF 0x10 95 #define TVO_SYNC_AUX_VTG_SET_1 0x11 96 #define TVO_SYNC_AUX_VTG_SET_2 0x12 97 #define TVO_SYNC_AUX_VTG_SET_3 0x13 98 #define TVO_SYNC_AUX_VTG_SET_4 0x14 99 #define TVO_SYNC_AUX_VTG_SET_5 0x15 100 #define TVO_SYNC_AUX_VTG_SET_6 0x16 101 102 #define TVO_SYNC_HD_DCS_SHIFT 8 103 104 #define TVO_SYNC_DVO_PAD_HSYNC_SHIFT 8 105 #define TVO_SYNC_DVO_PAD_VSYNC_SHIFT 16 106 107 #define ENCODER_CRTC_MASK (BIT(0) | BIT(1)) 108 109 /* enum listing the supported output data format */ 110 enum sti_tvout_video_out_type { 111 STI_TVOUT_VIDEO_OUT_RGB, 112 STI_TVOUT_VIDEO_OUT_YUV, 113 }; 114 115 struct sti_tvout { 116 struct device *dev; 117 struct drm_device *drm_dev; 118 void __iomem *regs; 119 struct reset_control *reset; 120 struct drm_encoder *hdmi; 121 struct drm_encoder *hda; 122 struct drm_encoder *dvo; 123 }; 124 125 struct sti_tvout_encoder { 126 struct drm_encoder encoder; 127 struct sti_tvout *tvout; 128 }; 129 130 #define to_sti_tvout_encoder(x) \ 131 container_of(x, struct sti_tvout_encoder, encoder) 132 133 #define to_sti_tvout(x) to_sti_tvout_encoder(x)->tvout 134 135 /* preformatter conversion matrix */ 136 static const u32 rgb_to_ycbcr_601[8] = { 137 0xF927082E, 0x04C9FEAB, 0x01D30964, 0xFA95FD3D, 138 0x0000082E, 0x00002000, 0x00002000, 0x00000000 139 }; 140 141 /* 709 RGB to YCbCr */ 142 static const u32 rgb_to_ycbcr_709[8] = { 143 0xF891082F, 0x0367FF40, 0x01280B71, 0xF9B1FE20, 144 0x0000082F, 0x00002000, 0x00002000, 0x00000000 145 }; 146 147 static u32 tvout_read(struct sti_tvout *tvout, int offset) 148 { 149 return readl(tvout->regs + offset); 150 } 151 152 static void tvout_write(struct sti_tvout *tvout, u32 val, int offset) 153 { 154 writel(val, tvout->regs + offset); 155 } 156 157 /** 158 * Set the clipping mode of a VIP 159 * 160 * @tvout: tvout structure 161 * @reg: register to set 162 * @cr_r: 163 * @y_g: 164 * @cb_b: 165 */ 166 static void tvout_vip_set_color_order(struct sti_tvout *tvout, int reg, 167 u32 cr_r, u32 y_g, u32 cb_b) 168 { 169 u32 val = tvout_read(tvout, reg); 170 171 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT); 172 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT); 173 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT); 174 val |= cr_r << TVO_VIP_REORDER_R_SHIFT; 175 val |= y_g << TVO_VIP_REORDER_G_SHIFT; 176 val |= cb_b << TVO_VIP_REORDER_B_SHIFT; 177 178 tvout_write(tvout, val, reg); 179 } 180 181 /** 182 * Set the clipping mode of a VIP 183 * 184 * @tvout: tvout structure 185 * @reg: register to set 186 * @range: clipping range 187 */ 188 static void tvout_vip_set_clip_mode(struct sti_tvout *tvout, int reg, u32 range) 189 { 190 u32 val = tvout_read(tvout, reg); 191 192 val &= ~(TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT); 193 val |= range << TVO_VIP_CLIP_SHIFT; 194 tvout_write(tvout, val, reg); 195 } 196 197 /** 198 * Set the rounded value of a VIP 199 * 200 * @tvout: tvout structure 201 * @reg: register to set 202 * @rnd: rounded val per component 203 */ 204 static void tvout_vip_set_rnd(struct sti_tvout *tvout, int reg, u32 rnd) 205 { 206 u32 val = tvout_read(tvout, reg); 207 208 val &= ~(TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT); 209 val |= rnd << TVO_VIP_RND_SHIFT; 210 tvout_write(tvout, val, reg); 211 } 212 213 /** 214 * Select the VIP input 215 * 216 * @tvout: tvout structure 217 * @reg: register to set 218 * @main_path: main or auxiliary path 219 * @sel_input_logic_inverted: need to invert the logic 220 * @sel_input: selected_input (main/aux + conv) 221 */ 222 static void tvout_vip_set_sel_input(struct sti_tvout *tvout, 223 int reg, 224 bool main_path, 225 bool sel_input_logic_inverted, 226 enum sti_tvout_video_out_type video_out) 227 { 228 u32 sel_input; 229 u32 val = tvout_read(tvout, reg); 230 231 if (main_path) 232 sel_input = TVO_VIP_SEL_INPUT_MAIN; 233 else 234 sel_input = TVO_VIP_SEL_INPUT_AUX; 235 236 switch (video_out) { 237 case STI_TVOUT_VIDEO_OUT_RGB: 238 sel_input |= TVO_VIP_SEL_INPUT_BYPASSED; 239 break; 240 case STI_TVOUT_VIDEO_OUT_YUV: 241 sel_input &= ~TVO_VIP_SEL_INPUT_BYPASSED; 242 break; 243 } 244 245 /* on stih407 chip the sel_input bypass mode logic is inverted */ 246 if (sel_input_logic_inverted) 247 sel_input = sel_input ^ TVO_VIP_SEL_INPUT_BYPASS_MASK; 248 249 val &= ~TVO_VIP_SEL_INPUT_MASK; 250 val |= sel_input; 251 tvout_write(tvout, val, reg); 252 } 253 254 /** 255 * Select the input video signed or unsigned 256 * 257 * @tvout: tvout structure 258 * @reg: register to set 259 * @in_vid_signed: used video input format 260 */ 261 static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout, 262 int reg, u32 in_vid_fmt) 263 { 264 u32 val = tvout_read(tvout, reg); 265 266 val &= ~TVO_IN_FMT_SIGNED; 267 val |= in_vid_fmt; 268 tvout_write(tvout, val, reg); 269 } 270 271 /** 272 * Start VIP block for DVO output 273 * 274 * @tvout: pointer on tvout structure 275 * @main_path: true if main path has to be used in the vip configuration 276 * else aux path is used. 277 */ 278 static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path) 279 { 280 struct device_node *node = tvout->dev->of_node; 281 bool sel_input_logic_inverted = false; 282 u32 tvo_in_vid_format; 283 int val; 284 285 dev_dbg(tvout->dev, "%s\n", __func__); 286 287 if (main_path) { 288 DRM_DEBUG_DRIVER("main vip for DVO\n"); 289 /* Select the input sync for dvo = VTG set 4 */ 290 val = TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT; 291 val |= TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT; 292 val |= TVO_SYNC_MAIN_VTG_SET_4; 293 tvout_write(tvout, val, TVO_DVO_SYNC_SEL); 294 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 295 } else { 296 DRM_DEBUG_DRIVER("aux vip for DVO\n"); 297 /* Select the input sync for dvo = VTG set 4 */ 298 val = TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT; 299 val |= TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT; 300 val |= TVO_SYNC_AUX_VTG_SET_4; 301 tvout_write(tvout, val, TVO_DVO_SYNC_SEL); 302 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 303 } 304 305 /* Set color channel order */ 306 tvout_vip_set_color_order(tvout, TVO_VIP_DVO, 307 TVO_VIP_REORDER_CR_R_SEL, 308 TVO_VIP_REORDER_Y_G_SEL, 309 TVO_VIP_REORDER_CB_B_SEL); 310 311 /* Set clipping mode (Limited range RGB/Y) */ 312 tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, 313 TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y); 314 315 /* Set round mode (rounded to 8-bit per component) */ 316 tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED); 317 318 if (of_device_is_compatible(node, "st,stih407-tvout")) { 319 /* Set input video format */ 320 tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, 321 TVO_IN_FMT_SIGNED); 322 sel_input_logic_inverted = true; 323 } 324 325 /* Input selection */ 326 tvout_vip_set_sel_input(tvout, TVO_VIP_DVO, main_path, 327 sel_input_logic_inverted, 328 STI_TVOUT_VIDEO_OUT_RGB); 329 } 330 331 /** 332 * Start VIP block for HDMI output 333 * 334 * @tvout: pointer on tvout structure 335 * @main_path: true if main path has to be used in the vip configuration 336 * else aux path is used. 337 */ 338 static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path) 339 { 340 struct device_node *node = tvout->dev->of_node; 341 bool sel_input_logic_inverted = false; 342 u32 tvo_in_vid_format; 343 344 dev_dbg(tvout->dev, "%s\n", __func__); 345 346 if (main_path) { 347 DRM_DEBUG_DRIVER("main vip for hdmi\n"); 348 /* select the input sync for hdmi = VTG set 1 */ 349 tvout_write(tvout, TVO_SYNC_MAIN_VTG_SET_1, TVO_HDMI_SYNC_SEL); 350 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 351 } else { 352 DRM_DEBUG_DRIVER("aux vip for hdmi\n"); 353 /* select the input sync for hdmi = VTG set 1 */ 354 tvout_write(tvout, TVO_SYNC_AUX_VTG_SET_1, TVO_HDMI_SYNC_SEL); 355 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 356 } 357 358 /* set color channel order */ 359 tvout_vip_set_color_order(tvout, TVO_VIP_HDMI, 360 TVO_VIP_REORDER_CR_R_SEL, 361 TVO_VIP_REORDER_Y_G_SEL, 362 TVO_VIP_REORDER_CB_B_SEL); 363 364 /* set clipping mode (Limited range RGB/Y) */ 365 tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, 366 TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y); 367 368 /* set round mode (rounded to 8-bit per component) */ 369 tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED); 370 371 if (of_device_is_compatible(node, "st,stih407-tvout")) { 372 /* set input video format */ 373 tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, 374 TVO_IN_FMT_SIGNED); 375 sel_input_logic_inverted = true; 376 } 377 378 /* input selection */ 379 tvout_vip_set_sel_input(tvout, TVO_VIP_HDMI, main_path, 380 sel_input_logic_inverted, STI_TVOUT_VIDEO_OUT_RGB); 381 } 382 383 /** 384 * Start HDF VIP and HD DAC 385 * 386 * @tvout: pointer on tvout structure 387 * @main_path: true if main path has to be used in the vip configuration 388 * else aux path is used. 389 */ 390 static void tvout_hda_start(struct sti_tvout *tvout, bool main_path) 391 { 392 struct device_node *node = tvout->dev->of_node; 393 bool sel_input_logic_inverted = false; 394 u32 tvo_in_vid_format; 395 int val; 396 397 dev_dbg(tvout->dev, "%s\n", __func__); 398 399 if (main_path) { 400 val = TVO_SYNC_MAIN_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT; 401 val |= TVO_SYNC_MAIN_VTG_SET_3; 402 tvout_write(tvout, val, TVO_HD_SYNC_SEL); 403 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 404 } else { 405 val = TVO_SYNC_AUX_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT; 406 val |= TVO_SYNC_AUX_VTG_SET_3; 407 tvout_write(tvout, val, TVO_HD_SYNC_SEL); 408 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 409 } 410 411 /* set color channel order */ 412 tvout_vip_set_color_order(tvout, TVO_VIP_HDF, 413 TVO_VIP_REORDER_CR_R_SEL, 414 TVO_VIP_REORDER_Y_G_SEL, 415 TVO_VIP_REORDER_CB_B_SEL); 416 417 /* set clipping mode (EAV/SAV clipping) */ 418 tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_EAV_SAV); 419 420 /* set round mode (rounded to 10-bit per component) */ 421 tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED); 422 423 if (of_device_is_compatible(node, "st,stih407-tvout")) { 424 /* set input video format */ 425 tvout_vip_set_in_vid_fmt(tvout, 426 tvo_in_vid_format, TVO_IN_FMT_SIGNED); 427 sel_input_logic_inverted = true; 428 } 429 430 /* Input selection */ 431 tvout_vip_set_sel_input(tvout, TVO_VIP_HDF, main_path, 432 sel_input_logic_inverted, 433 STI_TVOUT_VIDEO_OUT_YUV); 434 435 /* power up HD DAC */ 436 tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF); 437 } 438 439 static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode) 440 { 441 } 442 443 static bool sti_tvout_encoder_mode_fixup(struct drm_encoder *encoder, 444 const struct drm_display_mode *mode, 445 struct drm_display_mode *adjusted_mode) 446 { 447 return true; 448 } 449 450 static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder, 451 struct drm_display_mode *mode, 452 struct drm_display_mode *adjusted_mode) 453 { 454 } 455 456 static void sti_tvout_encoder_prepare(struct drm_encoder *encoder) 457 { 458 } 459 460 static void sti_tvout_encoder_destroy(struct drm_encoder *encoder) 461 { 462 struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder); 463 464 drm_encoder_cleanup(encoder); 465 kfree(sti_encoder); 466 } 467 468 static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { 469 .destroy = sti_tvout_encoder_destroy, 470 }; 471 472 static void sti_dvo_encoder_commit(struct drm_encoder *encoder) 473 { 474 struct sti_tvout *tvout = to_sti_tvout(encoder); 475 476 tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc)); 477 } 478 479 static void sti_dvo_encoder_disable(struct drm_encoder *encoder) 480 { 481 struct sti_tvout *tvout = to_sti_tvout(encoder); 482 483 /* Reset VIP register */ 484 tvout_write(tvout, 0x0, TVO_VIP_DVO); 485 } 486 487 static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = { 488 .dpms = sti_tvout_encoder_dpms, 489 .mode_fixup = sti_tvout_encoder_mode_fixup, 490 .mode_set = sti_tvout_encoder_mode_set, 491 .prepare = sti_tvout_encoder_prepare, 492 .commit = sti_dvo_encoder_commit, 493 .disable = sti_dvo_encoder_disable, 494 }; 495 496 static struct drm_encoder * 497 sti_tvout_create_dvo_encoder(struct drm_device *dev, 498 struct sti_tvout *tvout) 499 { 500 struct sti_tvout_encoder *encoder; 501 struct drm_encoder *drm_encoder; 502 503 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 504 if (!encoder) 505 return NULL; 506 507 encoder->tvout = tvout; 508 509 drm_encoder = (struct drm_encoder *)encoder; 510 511 drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; 512 drm_encoder->possible_clones = 1 << 0; 513 514 drm_encoder_init(dev, drm_encoder, 515 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS); 516 517 drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs); 518 519 return drm_encoder; 520 } 521 522 static void sti_hda_encoder_commit(struct drm_encoder *encoder) 523 { 524 struct sti_tvout *tvout = to_sti_tvout(encoder); 525 526 tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc)); 527 } 528 529 static void sti_hda_encoder_disable(struct drm_encoder *encoder) 530 { 531 struct sti_tvout *tvout = to_sti_tvout(encoder); 532 533 /* reset VIP register */ 534 tvout_write(tvout, 0x0, TVO_VIP_HDF); 535 536 /* power down HD DAC */ 537 tvout_write(tvout, 1, TVO_HD_DAC_CFG_OFF); 538 } 539 540 static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = { 541 .dpms = sti_tvout_encoder_dpms, 542 .mode_fixup = sti_tvout_encoder_mode_fixup, 543 .mode_set = sti_tvout_encoder_mode_set, 544 .prepare = sti_tvout_encoder_prepare, 545 .commit = sti_hda_encoder_commit, 546 .disable = sti_hda_encoder_disable, 547 }; 548 549 static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev, 550 struct sti_tvout *tvout) 551 { 552 struct sti_tvout_encoder *encoder; 553 struct drm_encoder *drm_encoder; 554 555 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 556 if (!encoder) 557 return NULL; 558 559 encoder->tvout = tvout; 560 561 drm_encoder = (struct drm_encoder *) encoder; 562 563 drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; 564 drm_encoder->possible_clones = 1 << 0; 565 566 drm_encoder_init(dev, drm_encoder, 567 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC); 568 569 drm_encoder_helper_add(drm_encoder, &sti_hda_encoder_helper_funcs); 570 571 return drm_encoder; 572 } 573 574 static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) 575 { 576 struct sti_tvout *tvout = to_sti_tvout(encoder); 577 578 tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc)); 579 } 580 581 static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) 582 { 583 struct sti_tvout *tvout = to_sti_tvout(encoder); 584 585 /* reset VIP register */ 586 tvout_write(tvout, 0x0, TVO_VIP_HDMI); 587 } 588 589 static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = { 590 .dpms = sti_tvout_encoder_dpms, 591 .mode_fixup = sti_tvout_encoder_mode_fixup, 592 .mode_set = sti_tvout_encoder_mode_set, 593 .prepare = sti_tvout_encoder_prepare, 594 .commit = sti_hdmi_encoder_commit, 595 .disable = sti_hdmi_encoder_disable, 596 }; 597 598 static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev, 599 struct sti_tvout *tvout) 600 { 601 struct sti_tvout_encoder *encoder; 602 struct drm_encoder *drm_encoder; 603 604 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 605 if (!encoder) 606 return NULL; 607 608 encoder->tvout = tvout; 609 610 drm_encoder = (struct drm_encoder *) encoder; 611 612 drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; 613 drm_encoder->possible_clones = 1 << 1; 614 615 drm_encoder_init(dev, drm_encoder, 616 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS); 617 618 drm_encoder_helper_add(drm_encoder, &sti_hdmi_encoder_helper_funcs); 619 620 return drm_encoder; 621 } 622 623 static void sti_tvout_create_encoders(struct drm_device *dev, 624 struct sti_tvout *tvout) 625 { 626 tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout); 627 tvout->hda = sti_tvout_create_hda_encoder(dev, tvout); 628 tvout->dvo = sti_tvout_create_dvo_encoder(dev, tvout); 629 } 630 631 static void sti_tvout_destroy_encoders(struct sti_tvout *tvout) 632 { 633 if (tvout->hdmi) 634 drm_encoder_cleanup(tvout->hdmi); 635 tvout->hdmi = NULL; 636 637 if (tvout->hda) 638 drm_encoder_cleanup(tvout->hda); 639 tvout->hda = NULL; 640 } 641 642 static int sti_tvout_bind(struct device *dev, struct device *master, void *data) 643 { 644 struct sti_tvout *tvout = dev_get_drvdata(dev); 645 struct drm_device *drm_dev = data; 646 unsigned int i; 647 648 tvout->drm_dev = drm_dev; 649 650 /* set preformatter matrix */ 651 for (i = 0; i < 8; i++) { 652 tvout_write(tvout, rgb_to_ycbcr_601[i], 653 TVO_CSC_MAIN_M0 + (i * 4)); 654 tvout_write(tvout, rgb_to_ycbcr_601[i], 655 TVO_CSC_AUX_M0 + (i * 4)); 656 } 657 658 sti_tvout_create_encoders(drm_dev, tvout); 659 660 return 0; 661 } 662 663 static void sti_tvout_unbind(struct device *dev, struct device *master, 664 void *data) 665 { 666 struct sti_tvout *tvout = dev_get_drvdata(dev); 667 668 sti_tvout_destroy_encoders(tvout); 669 } 670 671 static const struct component_ops sti_tvout_ops = { 672 .bind = sti_tvout_bind, 673 .unbind = sti_tvout_unbind, 674 }; 675 676 static int sti_tvout_probe(struct platform_device *pdev) 677 { 678 struct device *dev = &pdev->dev; 679 struct device_node *node = dev->of_node; 680 struct sti_tvout *tvout; 681 struct resource *res; 682 683 DRM_INFO("%s\n", __func__); 684 685 if (!node) 686 return -ENODEV; 687 688 tvout = devm_kzalloc(dev, sizeof(*tvout), GFP_KERNEL); 689 if (!tvout) 690 return -ENOMEM; 691 692 tvout->dev = dev; 693 694 /* get Memory ressources */ 695 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg"); 696 if (!res) { 697 DRM_ERROR("Invalid glue resource\n"); 698 return -ENOMEM; 699 } 700 tvout->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); 701 if (!tvout->regs) 702 return -ENOMEM; 703 704 /* get reset resources */ 705 tvout->reset = devm_reset_control_get(dev, "tvout"); 706 /* take tvout out of reset */ 707 if (!IS_ERR(tvout->reset)) 708 reset_control_deassert(tvout->reset); 709 710 platform_set_drvdata(pdev, tvout); 711 712 return component_add(dev, &sti_tvout_ops); 713 } 714 715 static int sti_tvout_remove(struct platform_device *pdev) 716 { 717 component_del(&pdev->dev, &sti_tvout_ops); 718 return 0; 719 } 720 721 static const struct of_device_id tvout_of_match[] = { 722 { .compatible = "st,stih416-tvout", }, 723 { .compatible = "st,stih407-tvout", }, 724 { /* end node */ } 725 }; 726 MODULE_DEVICE_TABLE(of, tvout_of_match); 727 728 struct platform_driver sti_tvout_driver = { 729 .driver = { 730 .name = "sti-tvout", 731 .owner = THIS_MODULE, 732 .of_match_table = tvout_of_match, 733 }, 734 .probe = sti_tvout_probe, 735 .remove = sti_tvout_remove, 736 }; 737 738 module_platform_driver(sti_tvout_driver); 739 740 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 741 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 742 MODULE_LICENSE("GPL"); 743