aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrik Jakobsson <patrik.r.jakobsson@gmail.com>2013-11-06 16:31:18 -0500
committerPatrik Jakobsson <patrik.r.jakobsson@gmail.com>2013-11-08 10:22:09 -0500
commitac6113ebb70d4bc7018db4e73f923653347da743 (patch)
tree36ac4bbf67f626206cb7650b271dd4bb43d6f8e8
parent86bd4103254adf7f3d32fa5c2578162c9e27b205 (diff)
drm/gma500/mrst: Add SDVO clock calculation
We start off by adding SDVO limits and converting all limits to the generic gma_limit_t stuct. Then we separate clock calculations for LVDS and SDVO. This will be cleaned up later but keep it simple for now. Signed-off-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_crtc.c175
1 files changed, 126 insertions, 49 deletions
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
index 54c98962b73e..bde3065f7422 100644
--- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -26,24 +26,10 @@
26#include "gma_display.h" 26#include "gma_display.h"
27#include "power.h" 27#include "power.h"
28 28
29struct psb_intel_range_t { 29#define MRST_LIMIT_LVDS_100L 0
30 int min, max; 30#define MRST_LIMIT_LVDS_83 1
31}; 31#define MRST_LIMIT_LVDS_100 2
32 32#define MRST_LIMIT_SDVO 3
33struct oaktrail_limit_t {
34 struct psb_intel_range_t dot, m, p1;
35};
36
37struct oaktrail_clock_t {
38 /* derived values */
39 int dot;
40 int m;
41 int p1;
42};
43
44#define MRST_LIMIT_LVDS_100L 0
45#define MRST_LIMIT_LVDS_83 1
46#define MRST_LIMIT_LVDS_100 2
47 33
48#define MRST_DOT_MIN 19750 34#define MRST_DOT_MIN 19750
49#define MRST_DOT_MAX 120000 35#define MRST_DOT_MAX 120000
@@ -57,21 +43,40 @@ struct oaktrail_clock_t {
57#define MRST_P1_MAX_0 7 43#define MRST_P1_MAX_0 7
58#define MRST_P1_MAX_1 8 44#define MRST_P1_MAX_1 8
59 45
60static const struct oaktrail_limit_t oaktrail_limits[] = { 46static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit,
47 struct drm_crtc *crtc, int target,
48 int refclk, struct gma_clock_t *best_clock);
49
50static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit,
51 struct drm_crtc *crtc, int target,
52 int refclk, struct gma_clock_t *best_clock);
53
54static const struct gma_limit_t mrst_limits[] = {
61 { /* MRST_LIMIT_LVDS_100L */ 55 { /* MRST_LIMIT_LVDS_100L */
62 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, 56 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX},
63 .m = {.min = MRST_M_MIN_100L, .max = MRST_M_MAX_100L}, 57 .m = {.min = MRST_M_MIN_100L, .max = MRST_M_MAX_100L},
64 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1}, 58 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1},
59 .find_pll = mrst_lvds_find_best_pll,
65 }, 60 },
66 { /* MRST_LIMIT_LVDS_83L */ 61 { /* MRST_LIMIT_LVDS_83L */
67 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, 62 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX},
68 .m = {.min = MRST_M_MIN_83, .max = MRST_M_MAX_83}, 63 .m = {.min = MRST_M_MIN_83, .max = MRST_M_MAX_83},
69 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_0}, 64 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_0},
65 .find_pll = mrst_lvds_find_best_pll,
70 }, 66 },
71 { /* MRST_LIMIT_LVDS_100 */ 67 { /* MRST_LIMIT_LVDS_100 */
72 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, 68 .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX},
73 .m = {.min = MRST_M_MIN_100, .max = MRST_M_MAX_100}, 69 .m = {.min = MRST_M_MIN_100, .max = MRST_M_MAX_100},
74 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1}, 70 .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1},
71 .find_pll = mrst_lvds_find_best_pll,
72 },
73 { /* MRST_LIMIT_SDVO */
74 .vco = {.min = 1400000, .max = 2800000},
75 .n = {.min = 3, .max = 7},
76 .m = {.min = 80, .max = 137},
77 .p1 = {.min = 1, .max = 2},
78 .p2 = {.dot_limit = 200000, .p2_slow = 10, .p2_fast = 10},
79 .find_pll = mrst_sdvo_find_best_pll,
75 }, 80 },
76}; 81};
77 82
@@ -82,9 +87,10 @@ static const u32 oaktrail_m_converts[] = {
82 0x12, 0x09, 0x24, 0x32, 0x39, 0x1c, 87 0x12, 0x09, 0x24, 0x32, 0x39, 0x1c,
83}; 88};
84 89
85static const struct oaktrail_limit_t *oaktrail_limit(struct drm_crtc *crtc) 90static const struct gma_limit_t *mrst_limit(struct drm_crtc *crtc,
91 int refclk)
86{ 92{
87 const struct oaktrail_limit_t *limit = NULL; 93 const struct gma_limit_t *limit = NULL;
88 struct drm_device *dev = crtc->dev; 94 struct drm_device *dev = crtc->dev;
89 struct drm_psb_private *dev_priv = dev->dev_private; 95 struct drm_psb_private *dev_priv = dev->dev_private;
90 96
@@ -92,45 +98,100 @@ static const struct oaktrail_limit_t *oaktrail_limit(struct drm_crtc *crtc)
92 || gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)) { 98 || gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)) {
93 switch (dev_priv->core_freq) { 99 switch (dev_priv->core_freq) {
94 case 100: 100 case 100:
95 limit = &oaktrail_limits[MRST_LIMIT_LVDS_100L]; 101 limit = &mrst_limits[MRST_LIMIT_LVDS_100L];
96 break; 102 break;
97 case 166: 103 case 166:
98 limit = &oaktrail_limits[MRST_LIMIT_LVDS_83]; 104 limit = &mrst_limits[MRST_LIMIT_LVDS_83];
99 break; 105 break;
100 case 200: 106 case 200:
101 limit = &oaktrail_limits[MRST_LIMIT_LVDS_100]; 107 limit = &mrst_limits[MRST_LIMIT_LVDS_100];
102 break; 108 break;
103 } 109 }
110 } else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
111 limit = &mrst_limits[MRST_LIMIT_SDVO];
104 } else { 112 } else {
105 limit = NULL; 113 limit = NULL;
106 dev_err(dev->dev, "oaktrail_limit Wrong display type.\n"); 114 dev_err(dev->dev, "mrst_limit Wrong display type.\n");
107 } 115 }
108 116
109 return limit; 117 return limit;
110} 118}
111 119
112/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ 120/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
113static void oaktrail_clock(int refclk, struct oaktrail_clock_t *clock) 121static void mrst_lvds_clock(int refclk, struct gma_clock_t *clock)
114{ 122{
115 clock->dot = (refclk * clock->m) / (14 * clock->p1); 123 clock->dot = (refclk * clock->m) / (14 * clock->p1);
116} 124}
117 125
118static void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock) 126static void mrst_print_pll(struct gma_clock_t *clock)
119{ 127{
120 pr_debug("%s: dotclock = %d, m = %d, p1 = %d.\n", 128 DRM_DEBUG_DRIVER("dotclock=%d, m=%d, m1=%d, m2=%d, n=%d, p1=%d, p2=%d\n",
121 prefix, clock->dot, clock->m, clock->p1); 129 clock->dot, clock->m, clock->m1, clock->m2, clock->n,
130 clock->p1, clock->p2);
131}
132
133static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit,
134 struct drm_crtc *crtc, int target,
135 int refclk, struct gma_clock_t *best_clock)
136{
137 struct gma_clock_t clock;
138 u32 target_vco, actual_freq;
139 s32 freq_error, min_error = 100000;
140
141 memset(best_clock, 0, sizeof(*best_clock));
142
143 for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
144 for (clock.n = limit->n.min; clock.n <= limit->n.max;
145 clock.n++) {
146 for (clock.p1 = limit->p1.min;
147 clock.p1 <= limit->p1.max; clock.p1++) {
148 /* p2 value always stored in p2_slow on SDVO */
149 clock.p = clock.p1 * limit->p2.p2_slow;
150 target_vco = target * clock.p;
151
152 /* VCO will increase at this point so break */
153 if (target_vco > limit->vco.max)
154 break;
155
156 if (target_vco < limit->vco.min)
157 continue;
158
159 actual_freq = (refclk * clock.m) /
160 (clock.n * clock.p);
161 freq_error = 10000 -
162 ((target * 10000) / actual_freq);
163
164 if (freq_error < -min_error) {
165 /* freq_error will start to decrease at
166 this point so break */
167 break;
168 }
169
170 if (freq_error < 0)
171 freq_error = -freq_error;
172
173 if (freq_error < min_error) {
174 min_error = freq_error;
175 *best_clock = clock;
176 }
177 }
178 }
179 if (min_error == 0)
180 break;
181 }
182
183 return min_error == 0;
122} 184}
123 185
124/** 186/**
125 * Returns a set of divisors for the desired target clock with the given refclk, 187 * Returns a set of divisors for the desired target clock with the given refclk,
126 * or FALSE. Divisor values are the actual divisors for 188 * or FALSE. Divisor values are the actual divisors for
127 */ 189 */
128static bool 190static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit,
129mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk, 191 struct drm_crtc *crtc, int target,
130 struct oaktrail_clock_t *best_clock) 192 int refclk, struct gma_clock_t *best_clock)
131{ 193{
132 struct oaktrail_clock_t clock; 194 struct gma_clock_t clock;
133 const struct oaktrail_limit_t *limit = oaktrail_limit(crtc);
134 int err = target; 195 int err = target;
135 196
136 memset(best_clock, 0, sizeof(*best_clock)); 197 memset(best_clock, 0, sizeof(*best_clock));
@@ -140,7 +201,7 @@ mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
140 clock.p1++) { 201 clock.p1++) {
141 int this_err; 202 int this_err;
142 203
143 oaktrail_clock(refclk, &clock); 204 mrst_lvds_clock(refclk, &clock);
144 205
145 this_err = abs(clock.dot - target); 206 this_err = abs(clock.dot - target);
146 if (this_err < err) { 207 if (this_err < err) {
@@ -149,7 +210,6 @@ mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
149 } 210 }
150 } 211 }
151 } 212 }
152 dev_dbg(crtc->dev->dev, "mrstFindBestPLL err = %d.\n", err);
153 return err != target; 213 return err != target;
154} 214}
155 215
@@ -297,7 +357,8 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
297 int pipe = gma_crtc->pipe; 357 int pipe = gma_crtc->pipe;
298 const struct psb_offset *map = &dev_priv->regmap[pipe]; 358 const struct psb_offset *map = &dev_priv->regmap[pipe];
299 int refclk = 0; 359 int refclk = 0;
300 struct oaktrail_clock_t clock; 360 struct gma_clock_t clock;
361 const struct gma_limit_t *limit;
301 u32 dpll = 0, fp = 0, dspcntr, pipeconf; 362 u32 dpll = 0, fp = 0, dspcntr, pipeconf;
302 bool ok, is_sdvo = false; 363 bool ok, is_sdvo = false;
303 bool is_lvds = false; 364 bool is_lvds = false;
@@ -418,21 +479,30 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
418 if (is_mipi) 479 if (is_mipi)
419 goto oaktrail_crtc_mode_set_exit; 480 goto oaktrail_crtc_mode_set_exit;
420 481
421 refclk = dev_priv->core_freq * 1000;
422 482
423 dpll = 0; /*BIT16 = 0 for 100MHz reference */ 483 dpll = 0; /*BIT16 = 0 for 100MHz reference */
424 484
425 ok = mrstFindBestPLL(crtc, adjusted_mode->clock, refclk, &clock); 485 refclk = is_sdvo ? 96000 : dev_priv->core_freq * 1000;
486 limit = mrst_limit(crtc, refclk);
487 ok = limit->find_pll(limit, crtc, adjusted_mode->clock,
488 refclk, &clock);
426 489
427 if (!ok) { 490 if (is_sdvo) {
428 dev_dbg(dev->dev, "mrstFindBestPLL fail in oaktrail_crtc_mode_set.\n"); 491 /* Convert calculated values to register values */
429 } else { 492 clock.p1 = (1L << (clock.p1 - 1));
430 dev_dbg(dev->dev, "oaktrail_crtc_mode_set pixel clock = %d," 493 clock.m -= 2;
431 "m = %x, p1 = %x.\n", clock.dot, clock.m, 494 clock.n = (1L << (clock.n - 1));
432 clock.p1);
433 } 495 }
434 496
435 fp = oaktrail_m_converts[(clock.m - MRST_M_MIN)] << 8; 497 if (!ok)
498 DRM_ERROR("Failed to find proper PLL settings");
499
500 mrst_print_pll(&clock);
501
502 if (is_sdvo)
503 fp = clock.n << 16 | clock.m;
504 else
505 fp = oaktrail_m_converts[(clock.m - MRST_M_MIN)] << 8;
436 506
437 dpll |= DPLL_VGA_MODE_DIS; 507 dpll |= DPLL_VGA_MODE_DIS;
438 508
@@ -456,12 +526,13 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
456 526
457 527
458 /* compute bitmask from p1 value */ 528 /* compute bitmask from p1 value */
459 dpll |= (1 << (clock.p1 - 2)) << 17; 529 if (is_sdvo)
530 dpll |= clock.p1 << 16; // dpll |= (1 << (clock.p1 - 1)) << 16;
531 else
532 dpll |= (1 << (clock.p1 - 2)) << 17;
460 533
461 dpll |= DPLL_VCO_ENABLE; 534 dpll |= DPLL_VCO_ENABLE;
462 535
463 mrstPrintPll("chosen", &clock);
464
465 if (dpll & DPLL_VCO_ENABLE) { 536 if (dpll & DPLL_VCO_ENABLE) {
466 REG_WRITE(map->fp0, fp); 537 REG_WRITE(map->fp0, fp);
467 REG_WRITE(map->dpll, dpll & ~DPLL_VCO_ENABLE); 538 REG_WRITE(map->dpll, dpll & ~DPLL_VCO_ENABLE);
@@ -565,3 +636,9 @@ const struct drm_crtc_helper_funcs oaktrail_helper_funcs = {
565 .commit = gma_crtc_commit, 636 .commit = gma_crtc_commit,
566}; 637};
567 638
639/* Not used yet */
640const struct gma_clock_funcs mrst_clock_funcs = {
641 .clock = mrst_lvds_clock,
642 .limit = mrst_limit,
643 .pll_is_valid = gma_pll_is_valid,
644};