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 #include "sti_vtg.h" 21 22 /* glue registers */ 23 #define TVO_CSC_MAIN_M0 0x000 24 #define TVO_CSC_MAIN_M1 0x004 25 #define TVO_CSC_MAIN_M2 0x008 26 #define TVO_CSC_MAIN_M3 0x00c 27 #define TVO_CSC_MAIN_M4 0x010 28 #define TVO_CSC_MAIN_M5 0x014 29 #define TVO_CSC_MAIN_M6 0x018 30 #define TVO_CSC_MAIN_M7 0x01c 31 #define TVO_MAIN_IN_VID_FORMAT 0x030 32 #define TVO_CSC_AUX_M0 0x100 33 #define TVO_CSC_AUX_M1 0x104 34 #define TVO_CSC_AUX_M2 0x108 35 #define TVO_CSC_AUX_M3 0x10c 36 #define TVO_CSC_AUX_M4 0x110 37 #define TVO_CSC_AUX_M5 0x114 38 #define TVO_CSC_AUX_M6 0x118 39 #define TVO_CSC_AUX_M7 0x11c 40 #define TVO_AUX_IN_VID_FORMAT 0x130 41 #define TVO_VIP_HDF 0x400 42 #define TVO_HD_SYNC_SEL 0x418 43 #define TVO_HD_DAC_CFG_OFF 0x420 44 #define TVO_VIP_HDMI 0x500 45 #define TVO_HDMI_FORCE_COLOR_0 0x504 46 #define TVO_HDMI_FORCE_COLOR_1 0x508 47 #define TVO_HDMI_CLIP_VALUE_B_CB 0x50c 48 #define TVO_HDMI_CLIP_VALUE_Y_G 0x510 49 #define TVO_HDMI_CLIP_VALUE_R_CR 0x514 50 #define TVO_HDMI_SYNC_SEL 0x518 51 #define TVO_HDMI_DFV_OBS 0x540 52 #define TVO_VIP_DVO 0x600 53 #define TVO_DVO_SYNC_SEL 0x618 54 #define TVO_DVO_CONFIG 0x620 55 56 #define TVO_IN_FMT_SIGNED BIT(0) 57 #define TVO_SYNC_EXT BIT(4) 58 59 #define TVO_VIP_REORDER_R_SHIFT 24 60 #define TVO_VIP_REORDER_G_SHIFT 20 61 #define TVO_VIP_REORDER_B_SHIFT 16 62 #define TVO_VIP_REORDER_MASK 0x3 63 #define TVO_VIP_REORDER_Y_G_SEL 0 64 #define TVO_VIP_REORDER_CB_B_SEL 1 65 #define TVO_VIP_REORDER_CR_R_SEL 2 66 67 #define TVO_VIP_CLIP_SHIFT 8 68 #define TVO_VIP_CLIP_MASK 0x7 69 #define TVO_VIP_CLIP_DISABLED 0 70 #define TVO_VIP_CLIP_EAV_SAV 1 71 #define TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y 2 72 #define TVO_VIP_CLIP_LIMITED_RANGE_CB_CR 3 73 #define TVO_VIP_CLIP_PROG_RANGE 4 74 75 #define TVO_VIP_RND_SHIFT 4 76 #define TVO_VIP_RND_MASK 0x3 77 #define TVO_VIP_RND_8BIT_ROUNDED 0 78 #define TVO_VIP_RND_10BIT_ROUNDED 1 79 #define TVO_VIP_RND_12BIT_ROUNDED 2 80 81 #define TVO_VIP_SEL_INPUT_MASK 0xf 82 #define TVO_VIP_SEL_INPUT_MAIN 0x0 83 #define TVO_VIP_SEL_INPUT_AUX 0x8 84 #define TVO_VIP_SEL_INPUT_FORCE_COLOR 0xf 85 #define TVO_VIP_SEL_INPUT_BYPASS_MASK 0x1 86 #define TVO_VIP_SEL_INPUT_BYPASSED 1 87 88 #define TVO_SYNC_MAIN_VTG_SET_REF 0x00 89 #define TVO_SYNC_AUX_VTG_SET_REF 0x10 90 91 #define TVO_SYNC_HD_DCS_SHIFT 8 92 93 #define TVO_SYNC_DVO_PAD_HSYNC_SHIFT 8 94 #define TVO_SYNC_DVO_PAD_VSYNC_SHIFT 16 95 96 #define ENCODER_CRTC_MASK (BIT(0) | BIT(1)) 97 98 #define TVO_MIN_HD_HEIGHT 720 99 100 /* enum listing the supported output data format */ 101 enum sti_tvout_video_out_type { 102 STI_TVOUT_VIDEO_OUT_RGB, 103 STI_TVOUT_VIDEO_OUT_YUV, 104 }; 105 106 struct sti_tvout { 107 struct device *dev; 108 struct drm_device *drm_dev; 109 void __iomem *regs; 110 struct reset_control *reset; 111 struct drm_encoder *hdmi; 112 struct drm_encoder *hda; 113 struct drm_encoder *dvo; 114 }; 115 116 struct sti_tvout_encoder { 117 struct drm_encoder encoder; 118 struct sti_tvout *tvout; 119 }; 120 121 #define to_sti_tvout_encoder(x) \ 122 container_of(x, struct sti_tvout_encoder, encoder) 123 124 #define to_sti_tvout(x) to_sti_tvout_encoder(x)->tvout 125 126 /* preformatter conversion matrix */ 127 static const u32 rgb_to_ycbcr_601[8] = { 128 0xF927082E, 0x04C9FEAB, 0x01D30964, 0xFA95FD3D, 129 0x0000082E, 0x00002000, 0x00002000, 0x00000000 130 }; 131 132 /* 709 RGB to YCbCr */ 133 static const u32 rgb_to_ycbcr_709[8] = { 134 0xF891082F, 0x0367FF40, 0x01280B71, 0xF9B1FE20, 135 0x0000082F, 0x00002000, 0x00002000, 0x00000000 136 }; 137 138 static u32 tvout_read(struct sti_tvout *tvout, int offset) 139 { 140 return readl(tvout->regs + offset); 141 } 142 143 static void tvout_write(struct sti_tvout *tvout, u32 val, int offset) 144 { 145 writel(val, tvout->regs + offset); 146 } 147 148 /** 149 * Set the clipping mode of a VIP 150 * 151 * @tvout: tvout structure 152 * @reg: register to set 153 * @cr_r: 154 * @y_g: 155 * @cb_b: 156 */ 157 static void tvout_vip_set_color_order(struct sti_tvout *tvout, int reg, 158 u32 cr_r, u32 y_g, u32 cb_b) 159 { 160 u32 val = tvout_read(tvout, reg); 161 162 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT); 163 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT); 164 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT); 165 val |= cr_r << TVO_VIP_REORDER_R_SHIFT; 166 val |= y_g << TVO_VIP_REORDER_G_SHIFT; 167 val |= cb_b << TVO_VIP_REORDER_B_SHIFT; 168 169 tvout_write(tvout, val, reg); 170 } 171 172 /** 173 * Set the clipping mode of a VIP 174 * 175 * @tvout: tvout structure 176 * @reg: register to set 177 * @range: clipping range 178 */ 179 static void tvout_vip_set_clip_mode(struct sti_tvout *tvout, int reg, u32 range) 180 { 181 u32 val = tvout_read(tvout, reg); 182 183 val &= ~(TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT); 184 val |= range << TVO_VIP_CLIP_SHIFT; 185 tvout_write(tvout, val, reg); 186 } 187 188 /** 189 * Set the rounded value of a VIP 190 * 191 * @tvout: tvout structure 192 * @reg: register to set 193 * @rnd: rounded val per component 194 */ 195 static void tvout_vip_set_rnd(struct sti_tvout *tvout, int reg, u32 rnd) 196 { 197 u32 val = tvout_read(tvout, reg); 198 199 val &= ~(TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT); 200 val |= rnd << TVO_VIP_RND_SHIFT; 201 tvout_write(tvout, val, reg); 202 } 203 204 /** 205 * Select the VIP input 206 * 207 * @tvout: tvout structure 208 * @reg: register to set 209 * @main_path: main or auxiliary path 210 * @sel_input_logic_inverted: need to invert the logic 211 * @sel_input: selected_input (main/aux + conv) 212 */ 213 static void tvout_vip_set_sel_input(struct sti_tvout *tvout, 214 int reg, 215 bool main_path, 216 bool sel_input_logic_inverted, 217 enum sti_tvout_video_out_type video_out) 218 { 219 u32 sel_input; 220 u32 val = tvout_read(tvout, reg); 221 222 if (main_path) 223 sel_input = TVO_VIP_SEL_INPUT_MAIN; 224 else 225 sel_input = TVO_VIP_SEL_INPUT_AUX; 226 227 switch (video_out) { 228 case STI_TVOUT_VIDEO_OUT_RGB: 229 sel_input |= TVO_VIP_SEL_INPUT_BYPASSED; 230 break; 231 case STI_TVOUT_VIDEO_OUT_YUV: 232 sel_input &= ~TVO_VIP_SEL_INPUT_BYPASSED; 233 break; 234 } 235 236 /* on stih407 chip the sel_input bypass mode logic is inverted */ 237 if (sel_input_logic_inverted) 238 sel_input = sel_input ^ TVO_VIP_SEL_INPUT_BYPASS_MASK; 239 240 val &= ~TVO_VIP_SEL_INPUT_MASK; 241 val |= sel_input; 242 tvout_write(tvout, val, reg); 243 } 244 245 /** 246 * Select the input video signed or unsigned 247 * 248 * @tvout: tvout structure 249 * @reg: register to set 250 * @in_vid_signed: used video input format 251 */ 252 static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout, 253 int reg, u32 in_vid_fmt) 254 { 255 u32 val = tvout_read(tvout, reg); 256 257 val &= ~TVO_IN_FMT_SIGNED; 258 val |= in_vid_fmt; 259 tvout_write(tvout, val, reg); 260 } 261 262 /** 263 * Set preformatter matrix 264 * 265 * @tvout: tvout structure 266 * @mode: display mode structure 267 */ 268 static void tvout_preformatter_set_matrix(struct sti_tvout *tvout, 269 struct drm_display_mode *mode) 270 { 271 unsigned int i; 272 const u32 *pf_matrix; 273 274 if (mode->vdisplay >= TVO_MIN_HD_HEIGHT) 275 pf_matrix = rgb_to_ycbcr_709; 276 else 277 pf_matrix = rgb_to_ycbcr_601; 278 279 for (i = 0; i < 8; i++) { 280 tvout_write(tvout, *(pf_matrix + i), 281 TVO_CSC_MAIN_M0 + (i * 4)); 282 tvout_write(tvout, *(pf_matrix + i), 283 TVO_CSC_AUX_M0 + (i * 4)); 284 } 285 } 286 287 /** 288 * Start VIP block for DVO output 289 * 290 * @tvout: pointer on tvout structure 291 * @main_path: true if main path has to be used in the vip configuration 292 * else aux path is used. 293 */ 294 static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path) 295 { 296 struct device_node *node = tvout->dev->of_node; 297 bool sel_input_logic_inverted = false; 298 u32 tvo_in_vid_format; 299 int val, tmp; 300 301 dev_dbg(tvout->dev, "%s\n", __func__); 302 303 if (main_path) { 304 DRM_DEBUG_DRIVER("main vip for DVO\n"); 305 /* Select the input sync for dvo */ 306 tmp = TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_DVO; 307 val = tmp << TVO_SYNC_DVO_PAD_VSYNC_SHIFT; 308 val |= tmp << TVO_SYNC_DVO_PAD_HSYNC_SHIFT; 309 val |= tmp; 310 tvout_write(tvout, val, TVO_DVO_SYNC_SEL); 311 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 312 } else { 313 DRM_DEBUG_DRIVER("aux vip for DVO\n"); 314 /* Select the input sync for dvo */ 315 tmp = TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_DVO; 316 val = tmp << TVO_SYNC_DVO_PAD_VSYNC_SHIFT; 317 val |= tmp << TVO_SYNC_DVO_PAD_HSYNC_SHIFT; 318 val |= tmp; 319 tvout_write(tvout, val, TVO_DVO_SYNC_SEL); 320 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 321 } 322 323 /* Set color channel order */ 324 tvout_vip_set_color_order(tvout, TVO_VIP_DVO, 325 TVO_VIP_REORDER_CR_R_SEL, 326 TVO_VIP_REORDER_Y_G_SEL, 327 TVO_VIP_REORDER_CB_B_SEL); 328 329 /* Set clipping mode */ 330 tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, TVO_VIP_CLIP_DISABLED); 331 332 /* Set round mode (rounded to 8-bit per component) */ 333 tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED); 334 335 if (of_device_is_compatible(node, "st,stih407-tvout")) { 336 /* Set input video format */ 337 tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, 338 TVO_IN_FMT_SIGNED); 339 sel_input_logic_inverted = true; 340 } 341 342 /* Input selection */ 343 tvout_vip_set_sel_input(tvout, TVO_VIP_DVO, main_path, 344 sel_input_logic_inverted, 345 STI_TVOUT_VIDEO_OUT_RGB); 346 } 347 348 /** 349 * Start VIP block for HDMI output 350 * 351 * @tvout: pointer on tvout structure 352 * @main_path: true if main path has to be used in the vip configuration 353 * else aux path is used. 354 */ 355 static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path) 356 { 357 struct device_node *node = tvout->dev->of_node; 358 bool sel_input_logic_inverted = false; 359 u32 tvo_in_vid_format; 360 361 dev_dbg(tvout->dev, "%s\n", __func__); 362 363 if (main_path) { 364 DRM_DEBUG_DRIVER("main vip for hdmi\n"); 365 /* select the input sync for hdmi */ 366 tvout_write(tvout, 367 TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDMI, 368 TVO_HDMI_SYNC_SEL); 369 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 370 } else { 371 DRM_DEBUG_DRIVER("aux vip for hdmi\n"); 372 /* select the input sync for hdmi */ 373 tvout_write(tvout, 374 TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDMI, 375 TVO_HDMI_SYNC_SEL); 376 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 377 } 378 379 /* set color channel order */ 380 tvout_vip_set_color_order(tvout, TVO_VIP_HDMI, 381 TVO_VIP_REORDER_CR_R_SEL, 382 TVO_VIP_REORDER_Y_G_SEL, 383 TVO_VIP_REORDER_CB_B_SEL); 384 385 /* set clipping mode */ 386 tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, TVO_VIP_CLIP_DISABLED); 387 388 /* set round mode (rounded to 8-bit per component) */ 389 tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED); 390 391 if (of_device_is_compatible(node, "st,stih407-tvout")) { 392 /* set input video format */ 393 tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, 394 TVO_IN_FMT_SIGNED); 395 sel_input_logic_inverted = true; 396 } 397 398 /* input selection */ 399 tvout_vip_set_sel_input(tvout, TVO_VIP_HDMI, main_path, 400 sel_input_logic_inverted, STI_TVOUT_VIDEO_OUT_RGB); 401 } 402 403 /** 404 * Start HDF VIP and HD DAC 405 * 406 * @tvout: pointer on tvout structure 407 * @main_path: true if main path has to be used in the vip configuration 408 * else aux path is used. 409 */ 410 static void tvout_hda_start(struct sti_tvout *tvout, bool main_path) 411 { 412 struct device_node *node = tvout->dev->of_node; 413 bool sel_input_logic_inverted = false; 414 u32 tvo_in_vid_format; 415 int val; 416 417 dev_dbg(tvout->dev, "%s\n", __func__); 418 419 if (main_path) { 420 DRM_DEBUG_DRIVER("main vip for HDF\n"); 421 /* Select the input sync for HD analog and HD DCS */ 422 val = TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDDCS; 423 val = val << TVO_SYNC_HD_DCS_SHIFT; 424 val |= TVO_SYNC_MAIN_VTG_SET_REF | VTG_SYNC_ID_HDF; 425 tvout_write(tvout, val, TVO_HD_SYNC_SEL); 426 tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; 427 } else { 428 DRM_DEBUG_DRIVER("aux vip for HDF\n"); 429 /* Select the input sync for HD analog and HD DCS */ 430 val = TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDDCS; 431 val = val << TVO_SYNC_HD_DCS_SHIFT; 432 val |= TVO_SYNC_AUX_VTG_SET_REF | VTG_SYNC_ID_HDF; 433 tvout_write(tvout, val, TVO_HD_SYNC_SEL); 434 tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; 435 } 436 437 /* set color channel order */ 438 tvout_vip_set_color_order(tvout, TVO_VIP_HDF, 439 TVO_VIP_REORDER_CR_R_SEL, 440 TVO_VIP_REORDER_Y_G_SEL, 441 TVO_VIP_REORDER_CB_B_SEL); 442 443 /* set clipping mode */ 444 tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_DISABLED); 445 446 /* set round mode (rounded to 10-bit per component) */ 447 tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED); 448 449 if (of_device_is_compatible(node, "st,stih407-tvout")) { 450 /* set input video format */ 451 tvout_vip_set_in_vid_fmt(tvout, 452 tvo_in_vid_format, TVO_IN_FMT_SIGNED); 453 sel_input_logic_inverted = true; 454 } 455 456 /* Input selection */ 457 tvout_vip_set_sel_input(tvout, TVO_VIP_HDF, main_path, 458 sel_input_logic_inverted, 459 STI_TVOUT_VIDEO_OUT_YUV); 460 461 /* power up HD DAC */ 462 tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF); 463 } 464 465 #define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ 466 readl(tvout->regs + reg)) 467 468 static void tvout_dbg_vip(struct seq_file *s, int val) 469 { 470 int r, g, b, tmp, mask; 471 char *const reorder[] = {"Y_G", "Cb_B", "Cr_R"}; 472 char *const clipping[] = {"No", "EAV/SAV", "Limited range RGB/Y", 473 "Limited range Cb/Cr", "decided by register"}; 474 char *const round[] = {"8-bit", "10-bit", "12-bit"}; 475 char *const input_sel[] = {"Main (color matrix enabled)", 476 "Main (color matrix by-passed)", 477 "", "", "", "", "", "", 478 "Aux (color matrix enabled)", 479 "Aux (color matrix by-passed)", 480 "", "", "", "", "", "Force value"}; 481 482 seq_puts(s, "\t"); 483 mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT; 484 r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT; 485 mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT; 486 g = (val & mask) >> TVO_VIP_REORDER_G_SHIFT; 487 mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT; 488 b = (val & mask) >> TVO_VIP_REORDER_B_SHIFT; 489 seq_printf(s, "%-24s %s->%s %s->%s %s->%s\n", "Reorder:", 490 reorder[r], reorder[TVO_VIP_REORDER_CR_R_SEL], 491 reorder[g], reorder[TVO_VIP_REORDER_Y_G_SEL], 492 reorder[b], reorder[TVO_VIP_REORDER_CB_B_SEL]); 493 seq_puts(s, "\t\t\t\t\t"); 494 mask = TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT; 495 tmp = (val & mask) >> TVO_VIP_CLIP_SHIFT; 496 seq_printf(s, "%-24s %s\n", "Clipping:", clipping[tmp]); 497 seq_puts(s, "\t\t\t\t\t"); 498 mask = TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT; 499 tmp = (val & mask) >> TVO_VIP_RND_SHIFT; 500 seq_printf(s, "%-24s input data rounded to %s per component\n", 501 "Round:", round[tmp]); 502 seq_puts(s, "\t\t\t\t\t"); 503 tmp = (val & TVO_VIP_SEL_INPUT_MASK); 504 seq_printf(s, "%-24s %s", "Input selection:", input_sel[tmp]); 505 } 506 507 static void tvout_dbg_hd_dac_cfg(struct seq_file *s, int val) 508 { 509 seq_printf(s, "\t%-24s %s", "HD DAC:", 510 val & 1 ? "disabled" : "enabled"); 511 } 512 513 static int tvout_dbg_show(struct seq_file *s, void *data) 514 { 515 struct drm_info_node *node = s->private; 516 struct sti_tvout *tvout = (struct sti_tvout *)node->info_ent->data; 517 struct drm_device *dev = node->minor->dev; 518 struct drm_crtc *crtc; 519 int ret; 520 521 ret = mutex_lock_interruptible(&dev->struct_mutex); 522 if (ret) 523 return ret; 524 525 seq_printf(s, "TVOUT: (vaddr = 0x%p)", tvout->regs); 526 527 seq_puts(s, "\n\n HDMI encoder: "); 528 crtc = tvout->hdmi->crtc; 529 if (crtc) { 530 seq_printf(s, "connected to %s path", 531 sti_crtc_is_main(crtc) ? "main" : "aux"); 532 DBGFS_DUMP(TVO_HDMI_SYNC_SEL); 533 DBGFS_DUMP(TVO_VIP_HDMI); 534 tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDMI)); 535 } else { 536 seq_puts(s, "disabled"); 537 } 538 539 seq_puts(s, "\n\n DVO encoder: "); 540 crtc = tvout->dvo->crtc; 541 if (crtc) { 542 seq_printf(s, "connected to %s path", 543 sti_crtc_is_main(crtc) ? "main" : "aux"); 544 DBGFS_DUMP(TVO_DVO_SYNC_SEL); 545 DBGFS_DUMP(TVO_DVO_CONFIG); 546 DBGFS_DUMP(TVO_VIP_DVO); 547 tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_DVO)); 548 } else { 549 seq_puts(s, "disabled"); 550 } 551 552 seq_puts(s, "\n\n HDA encoder: "); 553 crtc = tvout->hda->crtc; 554 if (crtc) { 555 seq_printf(s, "connected to %s path", 556 sti_crtc_is_main(crtc) ? "main" : "aux"); 557 DBGFS_DUMP(TVO_HD_SYNC_SEL); 558 DBGFS_DUMP(TVO_HD_DAC_CFG_OFF); 559 tvout_dbg_hd_dac_cfg(s, 560 readl(tvout->regs + TVO_HD_DAC_CFG_OFF)); 561 DBGFS_DUMP(TVO_VIP_HDF); 562 tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDF)); 563 } else { 564 seq_puts(s, "disabled"); 565 } 566 567 seq_puts(s, "\n\n main path configuration"); 568 DBGFS_DUMP(TVO_CSC_MAIN_M0); 569 DBGFS_DUMP(TVO_CSC_MAIN_M1); 570 DBGFS_DUMP(TVO_CSC_MAIN_M2); 571 DBGFS_DUMP(TVO_CSC_MAIN_M3); 572 DBGFS_DUMP(TVO_CSC_MAIN_M4); 573 DBGFS_DUMP(TVO_CSC_MAIN_M5); 574 DBGFS_DUMP(TVO_CSC_MAIN_M6); 575 DBGFS_DUMP(TVO_CSC_MAIN_M7); 576 DBGFS_DUMP(TVO_MAIN_IN_VID_FORMAT); 577 578 seq_puts(s, "\n\n auxiliary path configuration"); 579 DBGFS_DUMP(TVO_CSC_AUX_M0); 580 DBGFS_DUMP(TVO_CSC_AUX_M2); 581 DBGFS_DUMP(TVO_CSC_AUX_M3); 582 DBGFS_DUMP(TVO_CSC_AUX_M4); 583 DBGFS_DUMP(TVO_CSC_AUX_M5); 584 DBGFS_DUMP(TVO_CSC_AUX_M6); 585 DBGFS_DUMP(TVO_CSC_AUX_M7); 586 DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT); 587 seq_puts(s, "\n"); 588 589 mutex_unlock(&dev->struct_mutex); 590 return 0; 591 } 592 593 static struct drm_info_list tvout_debugfs_files[] = { 594 { "tvout", tvout_dbg_show, 0, NULL }, 595 }; 596 597 static void tvout_debugfs_exit(struct sti_tvout *tvout, struct drm_minor *minor) 598 { 599 drm_debugfs_remove_files(tvout_debugfs_files, 600 ARRAY_SIZE(tvout_debugfs_files), 601 minor); 602 } 603 604 static int tvout_debugfs_init(struct sti_tvout *tvout, struct drm_minor *minor) 605 { 606 unsigned int i; 607 608 for (i = 0; i < ARRAY_SIZE(tvout_debugfs_files); i++) 609 tvout_debugfs_files[i].data = tvout; 610 611 return drm_debugfs_create_files(tvout_debugfs_files, 612 ARRAY_SIZE(tvout_debugfs_files), 613 minor->debugfs_root, minor); 614 } 615 616 static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode) 617 { 618 } 619 620 static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder, 621 struct drm_display_mode *mode, 622 struct drm_display_mode *adjusted_mode) 623 { 624 } 625 626 static void sti_tvout_encoder_destroy(struct drm_encoder *encoder) 627 { 628 struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder); 629 630 drm_encoder_cleanup(encoder); 631 kfree(sti_encoder); 632 } 633 634 static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { 635 .destroy = sti_tvout_encoder_destroy, 636 }; 637 638 static void sti_dvo_encoder_enable(struct drm_encoder *encoder) 639 { 640 struct sti_tvout *tvout = to_sti_tvout(encoder); 641 642 tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode); 643 644 tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc)); 645 } 646 647 static void sti_dvo_encoder_disable(struct drm_encoder *encoder) 648 { 649 struct sti_tvout *tvout = to_sti_tvout(encoder); 650 651 /* Reset VIP register */ 652 tvout_write(tvout, 0x0, TVO_VIP_DVO); 653 } 654 655 static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = { 656 .dpms = sti_tvout_encoder_dpms, 657 .mode_set = sti_tvout_encoder_mode_set, 658 .enable = sti_dvo_encoder_enable, 659 .disable = sti_dvo_encoder_disable, 660 }; 661 662 static struct drm_encoder * 663 sti_tvout_create_dvo_encoder(struct drm_device *dev, 664 struct sti_tvout *tvout) 665 { 666 struct sti_tvout_encoder *encoder; 667 struct drm_encoder *drm_encoder; 668 669 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 670 if (!encoder) 671 return NULL; 672 673 encoder->tvout = tvout; 674 675 drm_encoder = (struct drm_encoder *)encoder; 676 677 drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; 678 drm_encoder->possible_clones = 1 << 0; 679 680 drm_encoder_init(dev, drm_encoder, 681 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS, 682 NULL); 683 684 drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs); 685 686 return drm_encoder; 687 } 688 689 static void sti_hda_encoder_enable(struct drm_encoder *encoder) 690 { 691 struct sti_tvout *tvout = to_sti_tvout(encoder); 692 693 tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode); 694 695 tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc)); 696 } 697 698 static void sti_hda_encoder_disable(struct drm_encoder *encoder) 699 { 700 struct sti_tvout *tvout = to_sti_tvout(encoder); 701 702 /* reset VIP register */ 703 tvout_write(tvout, 0x0, TVO_VIP_HDF); 704 705 /* power down HD DAC */ 706 tvout_write(tvout, 1, TVO_HD_DAC_CFG_OFF); 707 } 708 709 static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = { 710 .dpms = sti_tvout_encoder_dpms, 711 .mode_set = sti_tvout_encoder_mode_set, 712 .commit = sti_hda_encoder_enable, 713 .disable = sti_hda_encoder_disable, 714 }; 715 716 static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev, 717 struct sti_tvout *tvout) 718 { 719 struct sti_tvout_encoder *encoder; 720 struct drm_encoder *drm_encoder; 721 722 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 723 if (!encoder) 724 return NULL; 725 726 encoder->tvout = tvout; 727 728 drm_encoder = (struct drm_encoder *) encoder; 729 730 drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; 731 drm_encoder->possible_clones = 1 << 0; 732 733 drm_encoder_init(dev, drm_encoder, 734 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL); 735 736 drm_encoder_helper_add(drm_encoder, &sti_hda_encoder_helper_funcs); 737 738 return drm_encoder; 739 } 740 741 static void sti_hdmi_encoder_enable(struct drm_encoder *encoder) 742 { 743 struct sti_tvout *tvout = to_sti_tvout(encoder); 744 745 tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode); 746 747 tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc)); 748 } 749 750 static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) 751 { 752 struct sti_tvout *tvout = to_sti_tvout(encoder); 753 754 /* reset VIP register */ 755 tvout_write(tvout, 0x0, TVO_VIP_HDMI); 756 } 757 758 static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = { 759 .dpms = sti_tvout_encoder_dpms, 760 .mode_set = sti_tvout_encoder_mode_set, 761 .commit = sti_hdmi_encoder_enable, 762 .disable = sti_hdmi_encoder_disable, 763 }; 764 765 static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev, 766 struct sti_tvout *tvout) 767 { 768 struct sti_tvout_encoder *encoder; 769 struct drm_encoder *drm_encoder; 770 771 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 772 if (!encoder) 773 return NULL; 774 775 encoder->tvout = tvout; 776 777 drm_encoder = (struct drm_encoder *) encoder; 778 779 drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; 780 drm_encoder->possible_clones = 1 << 1; 781 782 drm_encoder_init(dev, drm_encoder, 783 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); 784 785 drm_encoder_helper_add(drm_encoder, &sti_hdmi_encoder_helper_funcs); 786 787 return drm_encoder; 788 } 789 790 static void sti_tvout_create_encoders(struct drm_device *dev, 791 struct sti_tvout *tvout) 792 { 793 tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout); 794 tvout->hda = sti_tvout_create_hda_encoder(dev, tvout); 795 tvout->dvo = sti_tvout_create_dvo_encoder(dev, tvout); 796 } 797 798 static void sti_tvout_destroy_encoders(struct sti_tvout *tvout) 799 { 800 if (tvout->hdmi) 801 drm_encoder_cleanup(tvout->hdmi); 802 tvout->hdmi = NULL; 803 804 if (tvout->hda) 805 drm_encoder_cleanup(tvout->hda); 806 tvout->hda = NULL; 807 808 if (tvout->dvo) 809 drm_encoder_cleanup(tvout->dvo); 810 tvout->dvo = NULL; 811 } 812 813 static int sti_tvout_bind(struct device *dev, struct device *master, void *data) 814 { 815 struct sti_tvout *tvout = dev_get_drvdata(dev); 816 struct drm_device *drm_dev = data; 817 818 tvout->drm_dev = drm_dev; 819 820 sti_tvout_create_encoders(drm_dev, tvout); 821 822 if (tvout_debugfs_init(tvout, drm_dev->primary)) 823 DRM_ERROR("TVOUT debugfs setup failed\n"); 824 825 return 0; 826 } 827 828 static void sti_tvout_unbind(struct device *dev, struct device *master, 829 void *data) 830 { 831 struct sti_tvout *tvout = dev_get_drvdata(dev); 832 struct drm_device *drm_dev = data; 833 834 sti_tvout_destroy_encoders(tvout); 835 836 tvout_debugfs_exit(tvout, drm_dev->primary); 837 } 838 839 static const struct component_ops sti_tvout_ops = { 840 .bind = sti_tvout_bind, 841 .unbind = sti_tvout_unbind, 842 }; 843 844 static int sti_tvout_probe(struct platform_device *pdev) 845 { 846 struct device *dev = &pdev->dev; 847 struct device_node *node = dev->of_node; 848 struct sti_tvout *tvout; 849 struct resource *res; 850 851 DRM_INFO("%s\n", __func__); 852 853 if (!node) 854 return -ENODEV; 855 856 tvout = devm_kzalloc(dev, sizeof(*tvout), GFP_KERNEL); 857 if (!tvout) 858 return -ENOMEM; 859 860 tvout->dev = dev; 861 862 /* get Memory ressources */ 863 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg"); 864 if (!res) { 865 DRM_ERROR("Invalid glue resource\n"); 866 return -ENOMEM; 867 } 868 tvout->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); 869 if (!tvout->regs) 870 return -ENOMEM; 871 872 /* get reset resources */ 873 tvout->reset = devm_reset_control_get(dev, "tvout"); 874 /* take tvout out of reset */ 875 if (!IS_ERR(tvout->reset)) 876 reset_control_deassert(tvout->reset); 877 878 platform_set_drvdata(pdev, tvout); 879 880 return component_add(dev, &sti_tvout_ops); 881 } 882 883 static int sti_tvout_remove(struct platform_device *pdev) 884 { 885 component_del(&pdev->dev, &sti_tvout_ops); 886 return 0; 887 } 888 889 static const struct of_device_id tvout_of_match[] = { 890 { .compatible = "st,stih416-tvout", }, 891 { .compatible = "st,stih407-tvout", }, 892 { /* end node */ } 893 }; 894 MODULE_DEVICE_TABLE(of, tvout_of_match); 895 896 struct platform_driver sti_tvout_driver = { 897 .driver = { 898 .name = "sti-tvout", 899 .owner = THIS_MODULE, 900 .of_match_table = tvout_of_match, 901 }, 902 .probe = sti_tvout_probe, 903 .remove = sti_tvout_remove, 904 }; 905 906 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 907 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 908 MODULE_LICENSE("GPL"); 909