aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrik Jakobsson <patrik.r.jakobsson@gmail.com>2013-06-30 15:39:00 -0400
committerPatrik Jakobsson <patrik.r.jakobsson@gmail.com>2013-07-23 19:47:16 -0400
commit5ea75e0f05d03007369f155c6c67541bc4ec309f (patch)
treeb8c624fce04934ae94559283ce04f99a10a625f4
parent85d9cb41db3bf0f36c999c2e547b37cb9f32367b (diff)
drm/gma500: Add generic code for clock calculation
This patch aims to unify the bits and pieces that are common (or similar enough) for pll clock calculations. Nothing makes use of this code yet That will come in later patches. Signed-off-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
-rw-r--r--drivers/gpu/drm/gma500/Makefile1
-rw-r--r--drivers/gpu/drm/gma500/gma_display.c143
-rw-r--r--drivers/gpu/drm/gma500/gma_display.h74
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h2
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.c3
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_drv.h3
6 files changed, 226 insertions, 0 deletions
diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile
index 7a2d40a5c1e1..e9064dd9045d 100644
--- a/drivers/gpu/drm/gma500/Makefile
+++ b/drivers/gpu/drm/gma500/Makefile
@@ -15,6 +15,7 @@ gma500_gfx-y += \
15 mmu.o \ 15 mmu.o \
16 power.o \ 16 power.o \
17 psb_drv.o \ 17 psb_drv.o \
18 gma_display.o \
18 psb_intel_display.o \ 19 psb_intel_display.o \
19 psb_intel_lvds.o \ 20 psb_intel_lvds.o \
20 psb_intel_modes.o \ 21 psb_intel_modes.o \
diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
new file mode 100644
index 000000000000..8f66d5c6505b
--- /dev/null
+++ b/drivers/gpu/drm/gma500/gma_display.c
@@ -0,0 +1,143 @@
1/*
2 * Copyright © 2006-2011 Intel Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * Authors:
18 * Eric Anholt <eric@anholt.net>
19 * Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
20 */
21
22#include <drm/drmP.h>
23#include "gma_display.h"
24#include "psb_intel_drv.h"
25#include "psb_intel_reg.h"
26#include "psb_drv.h"
27
28/**
29 * Returns whether any output on the specified pipe is of the specified type
30 */
31bool gma_pipe_has_type(struct drm_crtc *crtc, int type)
32{
33 struct drm_device *dev = crtc->dev;
34 struct drm_mode_config *mode_config = &dev->mode_config;
35 struct drm_connector *l_entry;
36
37 list_for_each_entry(l_entry, &mode_config->connector_list, head) {
38 if (l_entry->encoder && l_entry->encoder->crtc == crtc) {
39 struct psb_intel_encoder *psb_intel_encoder =
40 psb_intel_attached_encoder(l_entry);
41 if (psb_intel_encoder->type == type)
42 return true;
43 }
44 }
45
46 return false;
47}
48
49#define GMA_PLL_INVALID(s) { /* DRM_ERROR(s); */ return false; }
50
51bool gma_pll_is_valid(struct drm_crtc *crtc,
52 const struct gma_limit_t *limit,
53 struct gma_clock_t *clock)
54{
55 if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
56 GMA_PLL_INVALID("p1 out of range");
57 if (clock->p < limit->p.min || limit->p.max < clock->p)
58 GMA_PLL_INVALID("p out of range");
59 if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2)
60 GMA_PLL_INVALID("m2 out of range");
61 if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
62 GMA_PLL_INVALID("m1 out of range");
63 /* On CDV m1 is always 0 */
64 if (clock->m1 <= clock->m2 && clock->m1 != 0)
65 GMA_PLL_INVALID("m1 <= m2 && m1 != 0");
66 if (clock->m < limit->m.min || limit->m.max < clock->m)
67 GMA_PLL_INVALID("m out of range");
68 if (clock->n < limit->n.min || limit->n.max < clock->n)
69 GMA_PLL_INVALID("n out of range");
70 if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
71 GMA_PLL_INVALID("vco out of range");
72 /* XXX: We may need to be checking "Dot clock"
73 * depending on the multiplier, connector, etc.,
74 * rather than just a single range.
75 */
76 if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
77 GMA_PLL_INVALID("dot out of range");
78
79 return true;
80}
81
82bool gma_find_best_pll(const struct gma_limit_t *limit,
83 struct drm_crtc *crtc, int target, int refclk,
84 struct gma_clock_t *best_clock)
85{
86 struct drm_device *dev = crtc->dev;
87 const struct gma_clock_funcs *clock_funcs =
88 to_psb_intel_crtc(crtc)->clock_funcs;
89 struct gma_clock_t clock;
90 int err = target;
91
92 if (gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
93 (REG_READ(LVDS) & LVDS_PORT_EN) != 0) {
94 /*
95 * For LVDS, if the panel is on, just rely on its current
96 * settings for dual-channel. We haven't figured out how to
97 * reliably set up different single/dual channel state, if we
98 * even can.
99 */
100 if ((REG_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
101 LVDS_CLKB_POWER_UP)
102 clock.p2 = limit->p2.p2_fast;
103 else
104 clock.p2 = limit->p2.p2_slow;
105 } else {
106 if (target < limit->p2.dot_limit)
107 clock.p2 = limit->p2.p2_slow;
108 else
109 clock.p2 = limit->p2.p2_fast;
110 }
111
112 memset(best_clock, 0, sizeof(*best_clock));
113
114 /* m1 is always 0 on CDV so the outmost loop will run just once */
115 for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
116 for (clock.m2 = limit->m2.min;
117 (clock.m2 < clock.m1 || clock.m1 == 0) &&
118 clock.m2 <= limit->m2.max; clock.m2++) {
119 for (clock.n = limit->n.min;
120 clock.n <= limit->n.max; clock.n++) {
121 for (clock.p1 = limit->p1.min;
122 clock.p1 <= limit->p1.max;
123 clock.p1++) {
124 int this_err;
125
126 clock_funcs->clock(refclk, &clock);
127
128 if (!clock_funcs->pll_is_valid(crtc,
129 limit, &clock))
130 continue;
131
132 this_err = abs(clock.dot - target);
133 if (this_err < err) {
134 *best_clock = clock;
135 err = this_err;
136 }
137 }
138 }
139 }
140 }
141
142 return err != target;
143}
diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h
new file mode 100644
index 000000000000..a5d8aa31b5b7
--- /dev/null
+++ b/drivers/gpu/drm/gma500/gma_display.h
@@ -0,0 +1,74 @@
1/*
2 * Copyright © 2006-2011 Intel Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * Authors:
18 * Eric Anholt <eric@anholt.net>
19 * Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
20 */
21
22#ifndef _GMA_DISPLAY_H_
23#define _GMA_DISPLAY_H_
24
25struct gma_clock_t {
26 /* given values */
27 int n;
28 int m1, m2;
29 int p1, p2;
30 /* derived values */
31 int dot;
32 int vco;
33 int m;
34 int p;
35};
36
37struct gma_range_t {
38 int min, max;
39};
40
41struct gma_p2_t {
42 int dot_limit;
43 int p2_slow, p2_fast;
44};
45
46struct gma_limit_t {
47 struct gma_range_t dot, vco, n, m, m1, m2, p, p1;
48 struct gma_p2_t p2;
49 bool (*find_pll)(const struct gma_limit_t *, struct drm_crtc *,
50 int target, int refclk,
51 struct gma_clock_t *best_clock);
52};
53
54struct gma_clock_funcs {
55 void (*clock)(int refclk, struct gma_clock_t *clock);
56 const struct gma_limit_t *(*limit)(struct drm_crtc *crtc, int refclk);
57 bool (*pll_is_valid)(struct drm_crtc *crtc,
58 const struct gma_limit_t *limit,
59 struct gma_clock_t *clock);
60};
61
62/* Common pipe related functions */
63extern bool gma_pipe_has_type(struct drm_crtc *crtc, int type);
64
65/* Common clock related functions */
66extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk);
67extern void gma_clock(int refclk, struct gma_clock_t *clock);
68extern bool gma_pll_is_valid(struct drm_crtc *crtc,
69 const struct gma_limit_t *limit,
70 struct gma_clock_t *clock);
71extern bool gma_find_best_pll(const struct gma_limit_t *limit,
72 struct drm_crtc *crtc, int target, int refclk,
73 struct gma_clock_t *best_clock);
74#endif
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index 6053b8abcd12..eeed88c3c37e 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -27,6 +27,7 @@
27#include <drm/gma_drm.h> 27#include <drm/gma_drm.h>
28#include "psb_reg.h" 28#include "psb_reg.h"
29#include "psb_intel_drv.h" 29#include "psb_intel_drv.h"
30#include "gma_display.h"
30#include "intel_bios.h" 31#include "intel_bios.h"
31#include "gtt.h" 32#include "gtt.h"
32#include "power.h" 33#include "power.h"
@@ -675,6 +676,7 @@ struct psb_ops {
675 /* Sub functions */ 676 /* Sub functions */
676 struct drm_crtc_helper_funcs const *crtc_helper; 677 struct drm_crtc_helper_funcs const *crtc_helper;
677 struct drm_crtc_funcs const *crtc_funcs; 678 struct drm_crtc_funcs const *crtc_funcs;
679 const struct gma_clock_funcs *clock_funcs;
678 680
679 /* Setup hooks */ 681 /* Setup hooks */
680 int (*chip_setup)(struct drm_device *dev); 682 int (*chip_setup)(struct drm_device *dev);
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 6666493789d1..0f1d069afa11 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -1251,6 +1251,9 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
1251 /* Set the CRTC operations from the chip specific data */ 1251 /* Set the CRTC operations from the chip specific data */
1252 drm_crtc_init(dev, &psb_intel_crtc->base, dev_priv->ops->crtc_funcs); 1252 drm_crtc_init(dev, &psb_intel_crtc->base, dev_priv->ops->crtc_funcs);
1253 1253
1254 /* Set the CRTC clock functions from chip specific data */
1255 psb_intel_crtc->clock_funcs = dev_priv->ops->clock_funcs;
1256
1254 drm_mode_crtc_set_gamma_size(&psb_intel_crtc->base, 256); 1257 drm_mode_crtc_set_gamma_size(&psb_intel_crtc->base, 256);
1255 psb_intel_crtc->pipe = pipe; 1258 psb_intel_crtc->pipe = pipe;
1256 psb_intel_crtc->plane = pipe; 1259 psb_intel_crtc->plane = pipe;
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index 4dcae421a58d..bfe0408c1291 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -24,6 +24,7 @@
24#include <drm/drm_crtc.h> 24#include <drm/drm_crtc.h>
25#include <drm/drm_crtc_helper.h> 25#include <drm/drm_crtc_helper.h>
26#include <linux/gpio.h> 26#include <linux/gpio.h>
27#include "gma_display.h"
27 28
28/* 29/*
29 * Display related stuff 30 * Display related stuff
@@ -188,6 +189,8 @@ struct psb_intel_crtc {
188 189
189 /* Saved Crtc HW states */ 190 /* Saved Crtc HW states */
190 struct psb_intel_crtc_state *crtc_state; 191 struct psb_intel_crtc_state *crtc_state;
192
193 const struct gma_clock_funcs *clock_funcs;
191}; 194};
192 195
193#define to_psb_intel_crtc(x) \ 196#define to_psb_intel_crtc(x) \