aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPatrik Jakobsson <patrik.r.jakobsson@gmail.com>2013-06-30 19:42:16 -0400
committerPatrik Jakobsson <patrik.r.jakobsson@gmail.com>2013-07-23 19:47:17 -0400
commit2adb29ff61c97982addf702d7da106569e217329 (patch)
tree820b0c2de0917da3b9bf8f278cbcbc94c5995e65 /drivers
parent5ea75e0f05d03007369f155c6c67541bc4ec309f (diff)
drm/gma500/cdv: Make use of the generic clock code
Add chip specific callbacks for the generic and non-generic clock calculation code. Also remove as much dupilicated code as possible. Signed-off-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.c1
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.h1
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_display.c197
3 files changed, 36 insertions, 163 deletions
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c
index 23e14e93991f..daa45b5b3a45 100644
--- a/drivers/gpu/drm/gma500/cdv_device.c
+++ b/drivers/gpu/drm/gma500/cdv_device.c
@@ -641,6 +641,7 @@ const struct psb_ops cdv_chip_ops = {
641 641
642 .crtc_helper = &cdv_intel_helper_funcs, 642 .crtc_helper = &cdv_intel_helper_funcs,
643 .crtc_funcs = &cdv_intel_crtc_funcs, 643 .crtc_funcs = &cdv_intel_crtc_funcs,
644 .clock_funcs = &cdv_clock_funcs,
644 645
645 .output_init = cdv_output_init, 646 .output_init = cdv_output_init,
646 .hotplug = cdv_hotplug_event, 647 .hotplug = cdv_hotplug_event,
diff --git a/drivers/gpu/drm/gma500/cdv_device.h b/drivers/gpu/drm/gma500/cdv_device.h
index 9561e17621b3..0fcb608bbdf9 100644
--- a/drivers/gpu/drm/gma500/cdv_device.h
+++ b/drivers/gpu/drm/gma500/cdv_device.h
@@ -17,6 +17,7 @@
17 17
18extern const struct drm_crtc_helper_funcs cdv_intel_helper_funcs; 18extern const struct drm_crtc_helper_funcs cdv_intel_helper_funcs;
19extern const struct drm_crtc_funcs cdv_intel_crtc_funcs; 19extern const struct drm_crtc_funcs cdv_intel_crtc_funcs;
20extern const struct gma_clock_funcs cdv_clock_funcs;
20extern void cdv_intel_crt_init(struct drm_device *dev, 21extern void cdv_intel_crt_init(struct drm_device *dev,
21 struct psb_intel_mode_device *mode_dev); 22 struct psb_intel_mode_device *mode_dev);
22extern void cdv_intel_lvds_init(struct drm_device *dev, 23extern void cdv_intel_lvds_init(struct drm_device *dev,
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 82430ad8ba62..82f1ae46e0ac 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -30,43 +30,10 @@
30#include "power.h" 30#include "power.h"
31#include "cdv_device.h" 31#include "cdv_device.h"
32 32
33static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit,
34 struct drm_crtc *crtc, int target,
35 int refclk, struct gma_clock_t *best_clock);
33 36
34struct cdv_intel_range_t {
35 int min, max;
36};
37
38struct cdv_intel_p2_t {
39 int dot_limit;
40 int p2_slow, p2_fast;
41};
42
43struct cdv_intel_clock_t {
44 /* given values */
45 int n;
46 int m1, m2;
47 int p1, p2;
48 /* derived values */
49 int dot;
50 int vco;
51 int m;
52 int p;
53};
54
55#define INTEL_P2_NUM 2
56
57struct cdv_intel_limit_t {
58 struct cdv_intel_range_t dot, vco, n, m, m1, m2, p, p1;
59 struct cdv_intel_p2_t p2;
60 bool (*find_pll)(const struct cdv_intel_limit_t *, struct drm_crtc *,
61 int, int, struct cdv_intel_clock_t *);
62};
63
64static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
65 struct drm_crtc *crtc, int target, int refclk,
66 struct cdv_intel_clock_t *best_clock);
67static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct drm_crtc *crtc, int target,
68 int refclk,
69 struct cdv_intel_clock_t *best_clock);
70 37
71#define CDV_LIMIT_SINGLE_LVDS_96 0 38#define CDV_LIMIT_SINGLE_LVDS_96 0
72#define CDV_LIMIT_SINGLE_LVDS_100 1 39#define CDV_LIMIT_SINGLE_LVDS_100 1
@@ -75,7 +42,7 @@ static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct
75#define CDV_LIMIT_DP_27 4 42#define CDV_LIMIT_DP_27 4
76#define CDV_LIMIT_DP_100 5 43#define CDV_LIMIT_DP_100 5
77 44
78static const struct cdv_intel_limit_t cdv_intel_limits[] = { 45static const struct gma_limit_t cdv_intel_limits[] = {
79 { /* CDV_SINGLE_LVDS_96MHz */ 46 { /* CDV_SINGLE_LVDS_96MHz */
80 .dot = {.min = 20000, .max = 115500}, 47 .dot = {.min = 20000, .max = 115500},
81 .vco = {.min = 1800000, .max = 3600000}, 48 .vco = {.min = 1800000, .max = 3600000},
@@ -85,9 +52,8 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
85 .m2 = {.min = 58, .max = 158}, 52 .m2 = {.min = 58, .max = 158},
86 .p = {.min = 28, .max = 140}, 53 .p = {.min = 28, .max = 140},
87 .p1 = {.min = 2, .max = 10}, 54 .p1 = {.min = 2, .max = 10},
88 .p2 = {.dot_limit = 200000, 55 .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14},
89 .p2_slow = 14, .p2_fast = 14}, 56 .find_pll = gma_find_best_pll,
90 .find_pll = cdv_intel_find_best_PLL,
91 }, 57 },
92 { /* CDV_SINGLE_LVDS_100MHz */ 58 { /* CDV_SINGLE_LVDS_100MHz */
93 .dot = {.min = 20000, .max = 115500}, 59 .dot = {.min = 20000, .max = 115500},
@@ -102,7 +68,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
102 * is 80-224Mhz. Prefer single channel as much as possible. 68 * is 80-224Mhz. Prefer single channel as much as possible.
103 */ 69 */
104 .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14}, 70 .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14},
105 .find_pll = cdv_intel_find_best_PLL, 71 .find_pll = gma_find_best_pll,
106 }, 72 },
107 { /* CDV_DAC_HDMI_27MHz */ 73 { /* CDV_DAC_HDMI_27MHz */
108 .dot = {.min = 20000, .max = 400000}, 74 .dot = {.min = 20000, .max = 400000},
@@ -114,7 +80,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
114 .p = {.min = 5, .max = 90}, 80 .p = {.min = 5, .max = 90},
115 .p1 = {.min = 1, .max = 9}, 81 .p1 = {.min = 1, .max = 9},
116 .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, 82 .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5},
117 .find_pll = cdv_intel_find_best_PLL, 83 .find_pll = gma_find_best_pll,
118 }, 84 },
119 { /* CDV_DAC_HDMI_96MHz */ 85 { /* CDV_DAC_HDMI_96MHz */
120 .dot = {.min = 20000, .max = 400000}, 86 .dot = {.min = 20000, .max = 400000},
@@ -126,7 +92,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = {
126 .p = {.min = 5, .max = 100}, 92 .p = {.min = 5, .max = 100},
127 .p1 = {.min = 1, .max = 10}, 93 .p1 = {.min = 1, .max = 10},
128 .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, 94 .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5},
129 .find_pll = cdv_intel_find_best_PLL, 95 .find_pll = gma_find_best_pll,
130 }, 96 },
131 { /* CDV_DP_27MHz */ 97 { /* CDV_DP_27MHz */
132 .dot = {.min = 160000, .max = 272000}, 98 .dot = {.min = 160000, .max = 272000},
@@ -255,7 +221,7 @@ void cdv_sb_reset(struct drm_device *dev)
255 */ 221 */
256static int 222static int
257cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, 223cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
258 struct cdv_intel_clock_t *clock, bool is_lvds, u32 ddi_select) 224 struct gma_clock_t *clock, bool is_lvds, u32 ddi_select)
259{ 225{
260 struct psb_intel_crtc *psb_crtc = to_psb_intel_crtc(crtc); 226 struct psb_intel_crtc *psb_crtc = to_psb_intel_crtc(crtc);
261 int pipe = psb_crtc->pipe; 227 int pipe = psb_crtc->pipe;
@@ -405,31 +371,11 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
405 return 0; 371 return 0;
406} 372}
407 373
408/* 374static const struct gma_limit_t *cdv_intel_limit(struct drm_crtc *crtc,
409 * Returns whether any encoder on the specified pipe is of the specified type 375 int refclk)
410 */
411static bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type)
412{ 376{
413 struct drm_device *dev = crtc->dev; 377 const struct gma_limit_t *limit;
414 struct drm_mode_config *mode_config = &dev->mode_config; 378 if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
415 struct drm_connector *l_entry;
416
417 list_for_each_entry(l_entry, &mode_config->connector_list, head) {
418 if (l_entry->encoder && l_entry->encoder->crtc == crtc) {
419 struct psb_intel_encoder *psb_intel_encoder =
420 psb_intel_attached_encoder(l_entry);
421 if (psb_intel_encoder->type == type)
422 return true;
423 }
424 }
425 return false;
426}
427
428static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc,
429 int refclk)
430{
431 const struct cdv_intel_limit_t *limit;
432 if (cdv_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
433 /* 379 /*
434 * Now only single-channel LVDS is supported on CDV. If it is 380 * Now only single-channel LVDS is supported on CDV. If it is
435 * incorrect, please add the dual-channel LVDS. 381 * incorrect, please add the dual-channel LVDS.
@@ -454,8 +400,7 @@ static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc,
454} 400}
455 401
456/* m1 is reserved as 0 in CDV, n is a ring counter */ 402/* m1 is reserved as 0 in CDV, n is a ring counter */
457static void cdv_intel_clock(struct drm_device *dev, 403static void cdv_intel_clock(int refclk, struct gma_clock_t *clock)
458 int refclk, struct cdv_intel_clock_t *clock)
459{ 404{
460 clock->m = clock->m2 + 2; 405 clock->m = clock->m2 + 2;
461 clock->p = clock->p1 * clock->p2; 406 clock->p = clock->p1 * clock->p2;
@@ -463,93 +408,12 @@ static void cdv_intel_clock(struct drm_device *dev,
463 clock->dot = clock->vco / clock->p; 408 clock->dot = clock->vco / clock->p;
464} 409}
465 410
466 411static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit,
467#define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } 412 struct drm_crtc *crtc, int target,
468static bool cdv_intel_PLL_is_valid(struct drm_crtc *crtc, 413 int refclk,
469 const struct cdv_intel_limit_t *limit, 414 struct gma_clock_t *best_clock)
470 struct cdv_intel_clock_t *clock)
471{ 415{
472 if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) 416 struct gma_clock_t clock;
473 INTELPllInvalid("p1 out of range\n");
474 if (clock->p < limit->p.min || limit->p.max < clock->p)
475 INTELPllInvalid("p out of range\n");
476 /* unnecessary to check the range of m(m1/M2)/n again */
477 if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
478 INTELPllInvalid("vco out of range\n");
479 /* XXX: We may need to be checking "Dot clock"
480 * depending on the multiplier, connector, etc.,
481 * rather than just a single range.
482 */
483 if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
484 INTELPllInvalid("dot out of range\n");
485
486 return true;
487}
488
489static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit,
490 struct drm_crtc *crtc, int target, int refclk,
491 struct cdv_intel_clock_t *best_clock)
492{
493 struct drm_device *dev = crtc->dev;
494 struct cdv_intel_clock_t clock;
495 int err = target;
496
497
498 if (cdv_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
499 (REG_READ(LVDS) & LVDS_PORT_EN) != 0) {
500 /*
501 * For LVDS, if the panel is on, just rely on its current
502 * settings for dual-channel. We haven't figured out how to
503 * reliably set up different single/dual channel state, if we
504 * even can.
505 */
506 if ((REG_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
507 LVDS_CLKB_POWER_UP)
508 clock.p2 = limit->p2.p2_fast;
509 else
510 clock.p2 = limit->p2.p2_slow;
511 } else {
512 if (target < limit->p2.dot_limit)
513 clock.p2 = limit->p2.p2_slow;
514 else
515 clock.p2 = limit->p2.p2_fast;
516 }
517
518 memset(best_clock, 0, sizeof(*best_clock));
519 clock.m1 = 0;
520 /* m1 is reserved as 0 in CDV, n is a ring counter.
521 So skip the m1 loop */
522 for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) {
523 for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max;
524 clock.m2++) {
525 for (clock.p1 = limit->p1.min;
526 clock.p1 <= limit->p1.max;
527 clock.p1++) {
528 int this_err;
529
530 cdv_intel_clock(dev, refclk, &clock);
531
532 if (!cdv_intel_PLL_is_valid(crtc,
533 limit, &clock))
534 continue;
535
536 this_err = abs(clock.dot - target);
537 if (this_err < err) {
538 *best_clock = clock;
539 err = this_err;
540 }
541 }
542 }
543 }
544
545 return err != target;
546}
547
548static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct drm_crtc *crtc, int target,
549 int refclk,
550 struct cdv_intel_clock_t *best_clock)
551{
552 struct cdv_intel_clock_t clock;
553 if (refclk == 27000) { 417 if (refclk == 27000) {
554 if (target < 200000) { 418 if (target < 200000) {
555 clock.p1 = 2; 419 clock.p1 = 2;
@@ -584,7 +448,7 @@ static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct
584 clock.p = clock.p1 * clock.p2; 448 clock.p = clock.p1 * clock.p2;
585 clock.vco = (refclk * clock.m) / clock.n; 449 clock.vco = (refclk * clock.m) / clock.n;
586 clock.dot = clock.vco / clock.p; 450 clock.dot = clock.vco / clock.p;
587 memcpy(best_clock, &clock, sizeof(struct cdv_intel_clock_t)); 451 memcpy(best_clock, &clock, sizeof(struct gma_clock_t));
588 return true; 452 return true;
589} 453}
590 454
@@ -1035,14 +899,14 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
1035 int pipe = psb_intel_crtc->pipe; 899 int pipe = psb_intel_crtc->pipe;
1036 const struct psb_offset *map = &dev_priv->regmap[pipe]; 900 const struct psb_offset *map = &dev_priv->regmap[pipe];
1037 int refclk; 901 int refclk;
1038 struct cdv_intel_clock_t clock; 902 struct gma_clock_t clock;
1039 u32 dpll = 0, dspcntr, pipeconf; 903 u32 dpll = 0, dspcntr, pipeconf;
1040 bool ok; 904 bool ok;
1041 bool is_crt = false, is_lvds = false, is_tv = false; 905 bool is_crt = false, is_lvds = false, is_tv = false;
1042 bool is_hdmi = false, is_dp = false; 906 bool is_hdmi = false, is_dp = false;
1043 struct drm_mode_config *mode_config = &dev->mode_config; 907 struct drm_mode_config *mode_config = &dev->mode_config;
1044 struct drm_connector *connector; 908 struct drm_connector *connector;
1045 const struct cdv_intel_limit_t *limit; 909 const struct gma_limit_t *limit;
1046 u32 ddi_select = 0; 910 u32 ddi_select = 0;
1047 bool is_edp = false; 911 bool is_edp = false;
1048 912
@@ -1108,12 +972,13 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
1108 972
1109 drm_mode_debug_printmodeline(adjusted_mode); 973 drm_mode_debug_printmodeline(adjusted_mode);
1110 974
1111 limit = cdv_intel_limit(crtc, refclk); 975 limit = psb_intel_crtc->clock_funcs->limit(crtc, refclk);
1112 976
1113 ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, 977 ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk,
1114 &clock); 978 &clock);
1115 if (!ok) { 979 if (!ok) {
1116 dev_err(dev->dev, "Couldn't find PLL settings for mode!\n"); 980 DRM_ERROR("Couldn't find PLL settings for mode! target: %d, actual: %d",
981 adjusted_mode->clock, clock.dot);
1117 return 0; 982 return 0;
1118 } 983 }
1119 984
@@ -1612,7 +1477,7 @@ static int cdv_crtc_set_config(struct drm_mode_set *set)
1612 1477
1613/* FIXME: why are we using this, should it be cdv_ in this tree ? */ 1478/* FIXME: why are we using this, should it be cdv_ in this tree ? */
1614 1479
1615static void i8xx_clock(int refclk, struct cdv_intel_clock_t *clock) 1480static void i8xx_clock(int refclk, struct gma_clock_t *clock)
1616{ 1481{
1617 clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); 1482 clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
1618 clock->p = clock->p1 * clock->p2; 1483 clock->p = clock->p1 * clock->p2;
@@ -1630,7 +1495,7 @@ static int cdv_intel_crtc_clock_get(struct drm_device *dev,
1630 const struct psb_offset *map = &dev_priv->regmap[pipe]; 1495 const struct psb_offset *map = &dev_priv->regmap[pipe];
1631 u32 dpll; 1496 u32 dpll;
1632 u32 fp; 1497 u32 fp;
1633 struct cdv_intel_clock_t clock; 1498 struct gma_clock_t clock;
1634 bool is_lvds; 1499 bool is_lvds;
1635 struct psb_pipe *p = &dev_priv->regs.pipe[pipe]; 1500 struct psb_pipe *p = &dev_priv->regs.pipe[pipe];
1636 1501
@@ -1788,3 +1653,9 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
1788 .set_config = cdv_crtc_set_config, 1653 .set_config = cdv_crtc_set_config,
1789 .destroy = cdv_intel_crtc_destroy, 1654 .destroy = cdv_intel_crtc_destroy,
1790}; 1655};
1656
1657const struct gma_clock_funcs cdv_clock_funcs = {
1658 .clock = cdv_intel_clock,
1659 .limit = cdv_intel_limit,
1660 .pll_is_valid = gma_pll_is_valid,
1661};