diff options
author | Patrik Jakobsson <patrik.r.jakobsson@gmail.com> | 2013-11-06 16:31:18 -0500 |
---|---|---|
committer | Patrik Jakobsson <patrik.r.jakobsson@gmail.com> | 2013-11-08 10:22:09 -0500 |
commit | ac6113ebb70d4bc7018db4e73f923653347da743 (patch) | |
tree | 36ac4bbf67f626206cb7650b271dd4bb43d6f8e8 | |
parent | 86bd4103254adf7f3d32fa5c2578162c9e27b205 (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.c | 175 |
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 | ||
29 | struct 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 | |
33 | struct oaktrail_limit_t { | ||
34 | struct psb_intel_range_t dot, m, p1; | ||
35 | }; | ||
36 | |||
37 | struct 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 | ||
60 | static const struct oaktrail_limit_t oaktrail_limits[] = { | 46 | static 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 | |||
50 | static 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 | |||
54 | static 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 | ||
85 | static const struct oaktrail_limit_t *oaktrail_limit(struct drm_crtc *crtc) | 90 | static 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. */ |
113 | static void oaktrail_clock(int refclk, struct oaktrail_clock_t *clock) | 121 | static 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 | ||
118 | static void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock) | 126 | static 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 | |||
133 | static 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 | */ |
128 | static bool | 190 | static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit, |
129 | mrstFindBestPLL(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 */ | ||
640 | const 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 | }; | ||