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 NULL); 517 518 drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs); 519 520 return drm_encoder; 521 } 522 523 static void sti_hda_encoder_commit(struct drm_encoder *encoder) 524 { 525 struct sti_tvout *tvout = to_sti_tvout(encoder); 526 527 tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc)); 528 } 529 530 static void sti_hda_encoder_disable(struct drm_encoder *encoder) 531 { 532 struct sti_tvout *tvout = to_sti_tvout(encoder); 533 534 /* reset VIP register */ 535 tvout_write(tvout, 0x0, TVO_VIP_HDF); 536 537 /* power down HD DAC */ 538 tvout_write(tvout, 1, TVO_HD_DAC_CFG_OFF); 539 } 540 541 static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = { 542 .dpms = sti_tvout_encoder_dpms, 543 .mode_fixup = sti_tvout_encoder_mode_fixup, 544 .mode_set = sti_tvout_encoder_mode_set, 545 .prepare = sti_tvout_encoder_prepare, 546 .commit = sti_hda_encoder_commit, 547 .disable = sti_hda_encoder_disable, 548 }; 549 550 static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev, 551 struct sti_tvout *tvout) 552 { 553 struct sti_tvout_encoder *encoder; 554 struct drm_encoder *drm_encoder; 555 556 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 557 if (!encoder) 558 return NULL; 559 560 encoder->tvout = tvout; 561 562 drm_encoder = (struct drm_encoder *) encoder; 563 564 drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; 565 drm_encoder->possible_clones = 1 << 0; 566 567 drm_encoder_init(dev, drm_encoder, 568 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL); 569 570 drm_encoder_helper_add(drm_encoder, &sti_hda_encoder_helper_funcs); 571 572 return drm_encoder; 573 } 574 575 static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) 576 { 577 struct sti_tvout *tvout = to_sti_tvout(encoder); 578 579 tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc)); 580 } 581 582 static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) 583 { 584 struct sti_tvout *tvout = to_sti_tvout(encoder); 585 586 /* reset VIP register */ 587 tvout_write(tvout, 0x0, TVO_VIP_HDMI); 588 } 589 590 static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = { 591 .dpms = sti_tvout_encoder_dpms, 592 .mode_fixup = sti_tvout_encoder_mode_fixup, 593 .mode_set = sti_tvout_encoder_mode_set, 594 .prepare = sti_tvout_encoder_prepare, 595 .commit = sti_hdmi_encoder_commit, 596 .disable = sti_hdmi_encoder_disable, 597 }; 598 599 static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev, 600 struct sti_tvout *tvout) 601 { 602 struct sti_tvout_encoder *encoder; 603 struct drm_encoder *drm_encoder; 604 605 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 606 if (!encoder) 607 return NULL; 608 609 encoder->tvout = tvout; 610 611 drm_encoder = (struct drm_encoder *) encoder; 612 613 drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; 614 drm_encoder->possible_clones = 1 << 1; 615 616 drm_encoder_init(dev, drm_encoder, 617 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); 618 619 drm_encoder_helper_add(drm_encoder, &sti_hdmi_encoder_helper_funcs); 620 621 return drm_encoder; 622 } 623 624 static void sti_tvout_create_encoders(struct drm_device *dev, 625 struct sti_tvout *tvout) 626 { 627 tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout); 628 tvout->hda = sti_tvout_create_hda_encoder(dev, tvout); 629 tvout->dvo = sti_tvout_create_dvo_encoder(dev, tvout); 630 } 631 632 static void sti_tvout_destroy_encoders(struct sti_tvout *tvout) 633 { 634 if (tvout->hdmi) 635 drm_encoder_cleanup(tvout->hdmi); 636 tvout->hdmi = NULL; 637 638 if (tvout->hda) 639 drm_encoder_cleanup(tvout->hda); 640 tvout->hda = NULL; 641 } 642 643 static int sti_tvout_bind(struct device *dev, struct device *master, void *data) 644 { 645 struct sti_tvout *tvout = dev_get_drvdata(dev); 646 struct drm_device *drm_dev = data; 647 unsigned int i; 648 649 tvout->drm_dev = drm_dev; 650 651 /* set preformatter matrix */ 652 for (i = 0; i < 8; i++) { 653 tvout_write(tvout, rgb_to_ycbcr_601[i], 654 TVO_CSC_MAIN_M0 + (i * 4)); 655 tvout_write(tvout, rgb_to_ycbcr_601[i], 656 TVO_CSC_AUX_M0 + (i * 4)); 657 } 658 659 sti_tvout_create_encoders(drm_dev, tvout); 660 661 return 0; 662 } 663 664 static void sti_tvout_unbind(struct device *dev, struct device *master, 665 void *data) 666 { 667 struct sti_tvout *tvout = dev_get_drvdata(dev); 668 669 sti_tvout_destroy_encoders(tvout); 670 } 671 672 static const struct component_ops sti_tvout_ops = { 673 .bind = sti_tvout_bind, 674 .unbind = sti_tvout_unbind, 675 }; 676 677 static int sti_tvout_probe(struct platform_device *pdev) 678 { 679 struct device *dev = &pdev->dev; 680 struct device_node *node = dev->of_node; 681 struct sti_tvout *tvout; 682 struct resource *res; 683 684 DRM_INFO("%s\n", __func__); 685 686 if (!node) 687 return -ENODEV; 688 689 tvout = devm_kzalloc(dev, sizeof(*tvout), GFP_KERNEL); 690 if (!tvout) 691 return -ENOMEM; 692 693 tvout->dev = dev; 694 695 /* get Memory ressources */ 696 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg"); 697 if (!res) { 698 DRM_ERROR("Invalid glue resource\n"); 699 return -ENOMEM; 700 } 701 tvout->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); 702 if (!tvout->regs) 703 return -ENOMEM; 704 705 /* get reset resources */ 706 tvout->reset = devm_reset_control_get(dev, "tvout"); 707 /* take tvout out of reset */ 708 if (!IS_ERR(tvout->reset)) 709 reset_control_deassert(tvout->reset); 710 711 platform_set_drvdata(pdev, tvout); 712 713 return component_add(dev, &sti_tvout_ops); 714 } 715 716 static int sti_tvout_remove(struct platform_device *pdev) 717 { 718 component_del(&pdev->dev, &sti_tvout_ops); 719 return 0; 720 } 721 722 static const struct of_device_id tvout_of_match[] = { 723 { .compatible = "st,stih416-tvout", }, 724 { .compatible = "st,stih407-tvout", }, 725 { /* end node */ } 726 }; 727 MODULE_DEVICE_TABLE(of, tvout_of_match); 728 729 struct platform_driver sti_tvout_driver = { 730 .driver = { 731 .name = "sti-tvout", 732 .owner = THIS_MODULE, 733 .of_match_table = tvout_of_match, 734 }, 735 .probe = sti_tvout_probe, 736 .remove = sti_tvout_remove, 737 }; 738 739 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 740 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 741 MODULE_LICENSE("GPL"); 742