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