Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.7-rc7 909 lines 25 kB view raw
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 */ 102enum sti_tvout_video_out_type { 103 STI_TVOUT_VIDEO_OUT_RGB, 104 STI_TVOUT_VIDEO_OUT_YUV, 105}; 106 107struct 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 117struct 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 */ 128static const u32 rgb_to_ycbcr_601[8] = { 129 0xF927082E, 0x04C9FEAB, 0x01D30964, 0xFA95FD3D, 130 0x0000082E, 0x00002000, 0x00002000, 0x00000000 131}; 132 133/* 709 RGB to YCbCr */ 134static const u32 rgb_to_ycbcr_709[8] = { 135 0xF891082F, 0x0367FF40, 0x01280B71, 0xF9B1FE20, 136 0x0000082F, 0x00002000, 0x00002000, 0x00000000 137}; 138 139static u32 tvout_read(struct sti_tvout *tvout, int offset) 140{ 141 return readl(tvout->regs + offset); 142} 143 144static 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 */ 158static 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 */ 180static 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 */ 196static 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 */ 214static 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 */ 253static 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 */ 269static 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 */ 295static 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 */ 356static 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 */ 411static 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 469static 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 508static 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 514static 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 594static struct drm_info_list tvout_debugfs_files[] = { 595 { "tvout", tvout_dbg_show, 0, NULL }, 596}; 597 598static 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 605static 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 617static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode) 618{ 619} 620 621static 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 627static 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 635static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { 636 .destroy = sti_tvout_encoder_destroy, 637}; 638 639static 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 648static 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 656static 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 663static struct drm_encoder * 664sti_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 690static 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 699static 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 710static 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 717static 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 742static 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 751static 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 759static 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 766static 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 791static 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 799static 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 814static 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 829static 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 840static const struct component_ops sti_tvout_ops = { 841 .bind = sti_tvout_bind, 842 .unbind = sti_tvout_unbind, 843}; 844 845static 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 884static int sti_tvout_remove(struct platform_device *pdev) 885{ 886 component_del(&pdev->dev, &sti_tvout_ops); 887 return 0; 888} 889 890static const struct of_device_id tvout_of_match[] = { 891 { .compatible = "st,stih416-tvout", }, 892 { .compatible = "st,stih407-tvout", }, 893 { /* end node */ } 894}; 895MODULE_DEVICE_TABLE(of, tvout_of_match); 896 897struct 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 907MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 908MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 909MODULE_LICENSE("GPL");