aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tegra/sor.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-06-05 10:31:10 -0400
committerThierry Reding <treding@nvidia.com>2014-06-09 06:02:47 -0400
commit34fa183bacf9b5ecfda864857e8a797065b6b7e8 (patch)
treeb191566cc27d6a8c64468c5b67de37b0b1f28a46 /drivers/gpu/drm/tegra/sor.c
parentca185c68ed626bf91e22e41e2358d39e8508453c (diff)
drm/tegra: sor - Don't hardcode link parameters
The currently hardcoded link parameters don't work on all eDP panels, so compute the parameters at runtime depending on the mode and panel type to allow the driver to cope with a wider variety of panels. Note that the number of bits per pixel of the panel is still hardcoded, but this can be addressed in a separate patch. This is largely based on a patch by Stéphane Marchesin but the algorithm was largely rewritten to be more readable and concise. Signed-off-by: Stéphane Marchesin <marcheu@chromium.org> Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/sor.c')
-rw-r--r--drivers/gpu/drm/tegra/sor.c223
1 files changed, 213 insertions, 10 deletions
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index f082ea22f32e..4b554908be5e 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -40,6 +40,16 @@ struct tegra_sor {
40 struct dentry *debugfs; 40 struct dentry *debugfs;
41}; 41};
42 42
43struct tegra_sor_config {
44 u32 bits_per_pixel;
45
46 u32 active_polarity;
47 u32 active_count;
48 u32 tu_size;
49 u32 active_frac;
50 u32 watermark;
51};
52
43static inline struct tegra_sor * 53static inline struct tegra_sor *
44host1x_client_to_sor(struct host1x_client *client) 54host1x_client_to_sor(struct host1x_client *client)
45{ 55{
@@ -293,12 +303,173 @@ static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout)
293 return -ETIMEDOUT; 303 return -ETIMEDOUT;
294} 304}
295 305
306struct tegra_sor_params {
307 /* number of link clocks per line */
308 unsigned int num_clocks;
309 /* ratio between input and output */
310 u64 ratio;
311 /* precision factor */
312 u64 precision;
313
314 unsigned int active_polarity;
315 unsigned int active_count;
316 unsigned int active_frac;
317 unsigned int tu_size;
318 unsigned int error;
319};
320
321static int tegra_sor_compute_params(struct tegra_sor *sor,
322 struct tegra_sor_params *params,
323 unsigned int tu_size)
324{
325 u64 active_sym, active_count, frac, approx;
326 u32 active_polarity, active_frac = 0;
327 const u64 f = params->precision;
328 s64 error;
329
330 active_sym = params->ratio * tu_size;
331 active_count = div_u64(active_sym, f) * f;
332 frac = active_sym - active_count;
333
334 /* fraction < 0.5 */
335 if (frac >= (f / 2)) {
336 active_polarity = 1;
337 frac = f - frac;
338 } else {
339 active_polarity = 0;
340 }
341
342 if (frac != 0) {
343 frac = div_u64(f * f, frac); /* 1/fraction */
344 if (frac <= (15 * f)) {
345 active_frac = div_u64(frac, f);
346
347 /* round up */
348 if (active_polarity)
349 active_frac++;
350 } else {
351 active_frac = active_polarity ? 1 : 15;
352 }
353 }
354
355 if (active_frac == 1)
356 active_polarity = 0;
357
358 if (active_polarity == 1) {
359 if (active_frac) {
360 approx = active_count + (active_frac * (f - 1)) * f;
361 approx = div_u64(approx, active_frac * f);
362 } else {
363 approx = active_count + f;
364 }
365 } else {
366 if (active_frac)
367 approx = active_count + div_u64(f, active_frac);
368 else
369 approx = active_count;
370 }
371
372 error = div_s64(active_sym - approx, tu_size);
373 error *= params->num_clocks;
374
375 if (error <= 0 && abs64(error) < params->error) {
376 params->active_count = div_u64(active_count, f);
377 params->active_polarity = active_polarity;
378 params->active_frac = active_frac;
379 params->error = abs64(error);
380 params->tu_size = tu_size;
381
382 if (error == 0)
383 return true;
384 }
385
386 return false;
387}
388
389static int tegra_sor_calc_config(struct tegra_sor *sor,
390 struct drm_display_mode *mode,
391 struct tegra_sor_config *config,
392 struct drm_dp_link *link)
393{
394 const u64 f = 100000, link_rate = link->rate * 1000;
395 const u64 pclk = mode->clock * 1000;
396 struct tegra_sor_params params;
397 u64 input, output, watermark;
398 u32 num_syms_per_line;
399 unsigned int i;
400
401 if (!link_rate || !link->num_lanes || !pclk || !config->bits_per_pixel)
402 return -EINVAL;
403
404 output = link_rate * 8 * link->num_lanes;
405 input = pclk * config->bits_per_pixel;
406
407 if (input >= output)
408 return -ERANGE;
409
410 memset(&params, 0, sizeof(params));
411 params.ratio = div64_u64(input * f, output);
412 params.num_clocks = div_u64(link_rate * mode->hdisplay, pclk);
413 params.precision = f;
414 params.error = 64 * f;
415 params.tu_size = 64;
416
417 for (i = params.tu_size; i >= 32; i--)
418 if (tegra_sor_compute_params(sor, &params, i))
419 break;
420
421 if (params.active_frac == 0) {
422 config->active_polarity = 0;
423 config->active_count = params.active_count;
424
425 if (!params.active_polarity)
426 config->active_count--;
427
428 config->tu_size = params.tu_size;
429 config->active_frac = 1;
430 } else {
431 config->active_polarity = params.active_polarity;
432 config->active_count = params.active_count;
433 config->active_frac = params.active_frac;
434 config->tu_size = params.tu_size;
435 }
436
437 dev_dbg(sor->dev,
438 "polarity: %d active count: %d tu size: %d active frac: %d\n",
439 config->active_polarity, config->active_count,
440 config->tu_size, config->active_frac);
441
442 watermark = params.ratio * config->tu_size * (f - params.ratio);
443 watermark = div_u64(watermark, f);
444
445 watermark = div_u64(watermark + params.error, f);
446 config->watermark = watermark + (config->bits_per_pixel / 8) + 2;
447 num_syms_per_line = (mode->hdisplay * config->bits_per_pixel) *
448 (link->num_lanes * 8);
449
450 if (config->watermark > 30) {
451 config->watermark = 30;
452 dev_err(sor->dev,
453 "unable to compute TU size, forcing watermark to %u\n",
454 config->watermark);
455 } else if (config->watermark > num_syms_per_line) {
456 config->watermark = num_syms_per_line;
457 dev_err(sor->dev, "watermark too high, forcing to %u\n",
458 config->watermark);
459 }
460
461 return 0;
462}
463
296static int tegra_output_sor_enable(struct tegra_output *output) 464static int tegra_output_sor_enable(struct tegra_output *output)
297{ 465{
298 struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); 466 struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
299 struct drm_display_mode *mode = &dc->base.mode; 467 struct drm_display_mode *mode = &dc->base.mode;
300 unsigned int vbe, vse, hbe, hse, vbs, hbs, i; 468 unsigned int vbe, vse, hbe, hse, vbs, hbs, i;
301 struct tegra_sor *sor = to_sor(output); 469 struct tegra_sor *sor = to_sor(output);
470 struct tegra_sor_config config;
471 struct drm_dp_link link;
472 struct drm_dp_aux *aux;
302 unsigned long value; 473 unsigned long value;
303 int err = 0; 474 int err = 0;
304 475
@@ -313,16 +484,34 @@ static int tegra_output_sor_enable(struct tegra_output *output)
313 484
314 reset_control_deassert(sor->rst); 485 reset_control_deassert(sor->rst);
315 486
487 /* FIXME: properly convert to struct drm_dp_aux */
488 aux = (struct drm_dp_aux *)sor->dpaux;
489
316 if (sor->dpaux) { 490 if (sor->dpaux) {
317 err = tegra_dpaux_enable(sor->dpaux); 491 err = tegra_dpaux_enable(sor->dpaux);
318 if (err < 0) 492 if (err < 0)
319 dev_err(sor->dev, "failed to enable DP: %d\n", err); 493 dev_err(sor->dev, "failed to enable DP: %d\n", err);
494
495 err = drm_dp_link_probe(aux, &link);
496 if (err < 0) {
497 dev_err(sor->dev, "failed to probe eDP link: %d\n",
498 err);
499 return err;
500 }
320 } 501 }
321 502
322 err = clk_set_parent(sor->clk, sor->clk_safe); 503 err = clk_set_parent(sor->clk, sor->clk_safe);
323 if (err < 0) 504 if (err < 0)
324 dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 505 dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
325 506
507 memset(&config, 0, sizeof(config));
508 config.bits_per_pixel = 24; /* XXX: don't hardcode? */
509
510 err = tegra_sor_calc_config(sor, mode, &config, &link);
511 if (err < 0)
512 dev_err(sor->dev, "failed to compute link configuration: %d\n",
513 err);
514
326 value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 515 value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
327 value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 516 value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
328 value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; 517 value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK;
@@ -460,7 +649,7 @@ static int tegra_output_sor_enable(struct tegra_output *output)
460 value |= SOR_DP_LINKCTL_ENABLE; 649 value |= SOR_DP_LINKCTL_ENABLE;
461 650
462 value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; 651 value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK;
463 value |= SOR_DP_LINKCTL_TU_SIZE(59); /* XXX: don't hardcode? */ 652 value |= SOR_DP_LINKCTL_TU_SIZE(config.tu_size);
464 653
465 value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 654 value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
466 tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); 655 tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
@@ -476,15 +665,18 @@ static int tegra_output_sor_enable(struct tegra_output *output)
476 665
477 value = tegra_sor_readl(sor, SOR_DP_CONFIG_0); 666 value = tegra_sor_readl(sor, SOR_DP_CONFIG_0);
478 value &= ~SOR_DP_CONFIG_WATERMARK_MASK; 667 value &= ~SOR_DP_CONFIG_WATERMARK_MASK;
479 value |= SOR_DP_CONFIG_WATERMARK(14); /* XXX: don't hardcode? */ 668 value |= SOR_DP_CONFIG_WATERMARK(config.watermark);
480 669
481 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; 670 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK;
482 value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(47); /* XXX: don't hardcode? */ 671 value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config.active_count);
483 672
484 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; 673 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK;
485 value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(9); /* XXX: don't hardcode? */ 674 value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config.active_frac);
486 675
487 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; /* XXX: don't hardcode? */ 676 if (config.active_polarity)
677 value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY;
678 else
679 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY;
488 680
489 value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; 681 value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE;
490 value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; /* XXX: don't hardcode? */ 682 value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; /* XXX: don't hardcode? */
@@ -506,9 +698,6 @@ static int tegra_output_sor_enable(struct tegra_output *output)
506 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 698 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
507 699
508 if (sor->dpaux) { 700 if (sor->dpaux) {
509 /* FIXME: properly convert to struct drm_dp_aux */
510 struct drm_dp_aux *aux = (struct drm_dp_aux *)sor->dpaux;
511 struct drm_dp_link link;
512 u8 rate, lanes; 701 u8 rate, lanes;
513 702
514 err = drm_dp_link_probe(aux, &link); 703 err = drm_dp_link_probe(aux, &link);
@@ -592,12 +781,26 @@ static int tegra_output_sor_enable(struct tegra_output *output)
592 * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete 781 * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete
593 * raster, associate with display controller) 782 * raster, associate with display controller)
594 */ 783 */
595 value = SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 | 784 value = SOR_STATE_ASY_VSYNCPOL |
596 SOR_STATE_ASY_VSYNCPOL |
597 SOR_STATE_ASY_HSYNCPOL | 785 SOR_STATE_ASY_HSYNCPOL |
598 SOR_STATE_ASY_PROTOCOL_DP_A | 786 SOR_STATE_ASY_PROTOCOL_DP_A |
599 SOR_STATE_ASY_CRC_MODE_COMPLETE | 787 SOR_STATE_ASY_CRC_MODE_COMPLETE |
600 SOR_STATE_ASY_OWNER(dc->pipe + 1); 788 SOR_STATE_ASY_OWNER(dc->pipe + 1);
789
790 switch (config.bits_per_pixel) {
791 case 24:
792 value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444;
793 break;
794
795 case 18:
796 value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444;
797 break;
798
799 default:
800 BUG();
801 break;
802 }
803
601 tegra_sor_writel(sor, value, SOR_STATE_1); 804 tegra_sor_writel(sor, value, SOR_STATE_1);
602 805
603 /* 806 /*