1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright © 2006-2011 Intel Corporation
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Authors:
6*4882a593Smuzhiyun * Eric Anholt <eric@anholt.net>
7*4882a593Smuzhiyun * Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun #include <linux/highmem.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <drm/drm_crtc.h>
14*4882a593Smuzhiyun #include <drm/drm_fourcc.h>
15*4882a593Smuzhiyun #include <drm/drm_vblank.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "framebuffer.h"
18*4882a593Smuzhiyun #include "gma_display.h"
19*4882a593Smuzhiyun #include "psb_drv.h"
20*4882a593Smuzhiyun #include "psb_intel_drv.h"
21*4882a593Smuzhiyun #include "psb_intel_reg.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /**
24*4882a593Smuzhiyun * Returns whether any output on the specified pipe is of the specified type
25*4882a593Smuzhiyun */
gma_pipe_has_type(struct drm_crtc * crtc,int type)26*4882a593Smuzhiyun bool gma_pipe_has_type(struct drm_crtc *crtc, int type)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
29*4882a593Smuzhiyun struct drm_mode_config *mode_config = &dev->mode_config;
30*4882a593Smuzhiyun struct drm_connector *l_entry;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun list_for_each_entry(l_entry, &mode_config->connector_list, head) {
33*4882a593Smuzhiyun if (l_entry->encoder && l_entry->encoder->crtc == crtc) {
34*4882a593Smuzhiyun struct gma_encoder *gma_encoder =
35*4882a593Smuzhiyun gma_attached_encoder(l_entry);
36*4882a593Smuzhiyun if (gma_encoder->type == type)
37*4882a593Smuzhiyun return true;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun return false;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
gma_wait_for_vblank(struct drm_device * dev)44*4882a593Smuzhiyun void gma_wait_for_vblank(struct drm_device *dev)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun /* Wait for 20ms, i.e. one cycle at 50hz. */
47*4882a593Smuzhiyun mdelay(20);
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
gma_pipe_set_base(struct drm_crtc * crtc,int x,int y,struct drm_framebuffer * old_fb)50*4882a593Smuzhiyun int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
51*4882a593Smuzhiyun struct drm_framebuffer *old_fb)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
54*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
55*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
56*4882a593Smuzhiyun struct drm_framebuffer *fb = crtc->primary->fb;
57*4882a593Smuzhiyun struct gtt_range *gtt;
58*4882a593Smuzhiyun int pipe = gma_crtc->pipe;
59*4882a593Smuzhiyun const struct psb_offset *map = &dev_priv->regmap[pipe];
60*4882a593Smuzhiyun unsigned long start, offset;
61*4882a593Smuzhiyun u32 dspcntr;
62*4882a593Smuzhiyun int ret = 0;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun if (!gma_power_begin(dev, true))
65*4882a593Smuzhiyun return 0;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* no fb bound */
68*4882a593Smuzhiyun if (!fb) {
69*4882a593Smuzhiyun dev_err(dev->dev, "No FB bound\n");
70*4882a593Smuzhiyun goto gma_pipe_cleaner;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun gtt = to_gtt_range(fb->obj[0]);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* We are displaying this buffer, make sure it is actually loaded
76*4882a593Smuzhiyun into the GTT */
77*4882a593Smuzhiyun ret = psb_gtt_pin(gtt);
78*4882a593Smuzhiyun if (ret < 0)
79*4882a593Smuzhiyun goto gma_pipe_set_base_exit;
80*4882a593Smuzhiyun start = gtt->offset;
81*4882a593Smuzhiyun offset = y * fb->pitches[0] + x * fb->format->cpp[0];
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun REG_WRITE(map->stride, fb->pitches[0]);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun dspcntr = REG_READ(map->cntr);
86*4882a593Smuzhiyun dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun switch (fb->format->cpp[0] * 8) {
89*4882a593Smuzhiyun case 8:
90*4882a593Smuzhiyun dspcntr |= DISPPLANE_8BPP;
91*4882a593Smuzhiyun break;
92*4882a593Smuzhiyun case 16:
93*4882a593Smuzhiyun if (fb->format->depth == 15)
94*4882a593Smuzhiyun dspcntr |= DISPPLANE_15_16BPP;
95*4882a593Smuzhiyun else
96*4882a593Smuzhiyun dspcntr |= DISPPLANE_16BPP;
97*4882a593Smuzhiyun break;
98*4882a593Smuzhiyun case 24:
99*4882a593Smuzhiyun case 32:
100*4882a593Smuzhiyun dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
101*4882a593Smuzhiyun break;
102*4882a593Smuzhiyun default:
103*4882a593Smuzhiyun dev_err(dev->dev, "Unknown color depth\n");
104*4882a593Smuzhiyun ret = -EINVAL;
105*4882a593Smuzhiyun goto gma_pipe_set_base_exit;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun REG_WRITE(map->cntr, dspcntr);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun dev_dbg(dev->dev,
110*4882a593Smuzhiyun "Writing base %08lX %08lX %d %d\n", start, offset, x, y);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* FIXME: Investigate whether this really is the base for psb and why
113*4882a593Smuzhiyun the linear offset is named base for the other chips. map->surf
114*4882a593Smuzhiyun should be the base and map->linoff the offset for all chips */
115*4882a593Smuzhiyun if (IS_PSB(dev)) {
116*4882a593Smuzhiyun REG_WRITE(map->base, offset + start);
117*4882a593Smuzhiyun REG_READ(map->base);
118*4882a593Smuzhiyun } else {
119*4882a593Smuzhiyun REG_WRITE(map->base, offset);
120*4882a593Smuzhiyun REG_READ(map->base);
121*4882a593Smuzhiyun REG_WRITE(map->surf, start);
122*4882a593Smuzhiyun REG_READ(map->surf);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun gma_pipe_cleaner:
126*4882a593Smuzhiyun /* If there was a previous display we can now unpin it */
127*4882a593Smuzhiyun if (old_fb)
128*4882a593Smuzhiyun psb_gtt_unpin(to_gtt_range(old_fb->obj[0]));
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun gma_pipe_set_base_exit:
131*4882a593Smuzhiyun gma_power_end(dev);
132*4882a593Smuzhiyun return ret;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /* Loads the palette/gamma unit for the CRTC with the prepared values */
gma_crtc_load_lut(struct drm_crtc * crtc)136*4882a593Smuzhiyun void gma_crtc_load_lut(struct drm_crtc *crtc)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
139*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
140*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
141*4882a593Smuzhiyun const struct psb_offset *map = &dev_priv->regmap[gma_crtc->pipe];
142*4882a593Smuzhiyun int palreg = map->palette;
143*4882a593Smuzhiyun u16 *r, *g, *b;
144*4882a593Smuzhiyun int i;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* The clocks have to be on to load the palette. */
147*4882a593Smuzhiyun if (!crtc->enabled)
148*4882a593Smuzhiyun return;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun r = crtc->gamma_store;
151*4882a593Smuzhiyun g = r + crtc->gamma_size;
152*4882a593Smuzhiyun b = g + crtc->gamma_size;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (gma_power_begin(dev, false)) {
155*4882a593Smuzhiyun for (i = 0; i < 256; i++) {
156*4882a593Smuzhiyun REG_WRITE(palreg + 4 * i,
157*4882a593Smuzhiyun (((*r++ >> 8) + gma_crtc->lut_adj[i]) << 16) |
158*4882a593Smuzhiyun (((*g++ >> 8) + gma_crtc->lut_adj[i]) << 8) |
159*4882a593Smuzhiyun ((*b++ >> 8) + gma_crtc->lut_adj[i]));
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun gma_power_end(dev);
162*4882a593Smuzhiyun } else {
163*4882a593Smuzhiyun for (i = 0; i < 256; i++) {
164*4882a593Smuzhiyun /* FIXME: Why pipe[0] and not pipe[..._crtc->pipe]? */
165*4882a593Smuzhiyun dev_priv->regs.pipe[0].palette[i] =
166*4882a593Smuzhiyun (((*r++ >> 8) + gma_crtc->lut_adj[i]) << 16) |
167*4882a593Smuzhiyun (((*g++ >> 8) + gma_crtc->lut_adj[i]) << 8) |
168*4882a593Smuzhiyun ((*b++ >> 8) + gma_crtc->lut_adj[i]);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
gma_crtc_gamma_set(struct drm_crtc * crtc,u16 * red,u16 * green,u16 * blue,u32 size,struct drm_modeset_acquire_ctx * ctx)174*4882a593Smuzhiyun int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue,
175*4882a593Smuzhiyun u32 size,
176*4882a593Smuzhiyun struct drm_modeset_acquire_ctx *ctx)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun gma_crtc_load_lut(crtc);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun return 0;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /**
184*4882a593Smuzhiyun * Sets the power management mode of the pipe and plane.
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun * This code should probably grow support for turning the cursor off and back
187*4882a593Smuzhiyun * on appropriately at the same time as we're turning the pipe off/on.
188*4882a593Smuzhiyun */
gma_crtc_dpms(struct drm_crtc * crtc,int mode)189*4882a593Smuzhiyun void gma_crtc_dpms(struct drm_crtc *crtc, int mode)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
192*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
193*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
194*4882a593Smuzhiyun int pipe = gma_crtc->pipe;
195*4882a593Smuzhiyun const struct psb_offset *map = &dev_priv->regmap[pipe];
196*4882a593Smuzhiyun u32 temp;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /* XXX: When our outputs are all unaware of DPMS modes other than off
199*4882a593Smuzhiyun * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
200*4882a593Smuzhiyun */
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (IS_CDV(dev))
203*4882a593Smuzhiyun dev_priv->ops->disable_sr(dev);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun switch (mode) {
206*4882a593Smuzhiyun case DRM_MODE_DPMS_ON:
207*4882a593Smuzhiyun case DRM_MODE_DPMS_STANDBY:
208*4882a593Smuzhiyun case DRM_MODE_DPMS_SUSPEND:
209*4882a593Smuzhiyun if (gma_crtc->active)
210*4882a593Smuzhiyun break;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun gma_crtc->active = true;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /* Enable the DPLL */
215*4882a593Smuzhiyun temp = REG_READ(map->dpll);
216*4882a593Smuzhiyun if ((temp & DPLL_VCO_ENABLE) == 0) {
217*4882a593Smuzhiyun REG_WRITE(map->dpll, temp);
218*4882a593Smuzhiyun REG_READ(map->dpll);
219*4882a593Smuzhiyun /* Wait for the clocks to stabilize. */
220*4882a593Smuzhiyun udelay(150);
221*4882a593Smuzhiyun REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
222*4882a593Smuzhiyun REG_READ(map->dpll);
223*4882a593Smuzhiyun /* Wait for the clocks to stabilize. */
224*4882a593Smuzhiyun udelay(150);
225*4882a593Smuzhiyun REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
226*4882a593Smuzhiyun REG_READ(map->dpll);
227*4882a593Smuzhiyun /* Wait for the clocks to stabilize. */
228*4882a593Smuzhiyun udelay(150);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /* Enable the plane */
232*4882a593Smuzhiyun temp = REG_READ(map->cntr);
233*4882a593Smuzhiyun if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
234*4882a593Smuzhiyun REG_WRITE(map->cntr,
235*4882a593Smuzhiyun temp | DISPLAY_PLANE_ENABLE);
236*4882a593Smuzhiyun /* Flush the plane changes */
237*4882a593Smuzhiyun REG_WRITE(map->base, REG_READ(map->base));
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun udelay(150);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* Enable the pipe */
243*4882a593Smuzhiyun temp = REG_READ(map->conf);
244*4882a593Smuzhiyun if ((temp & PIPEACONF_ENABLE) == 0)
245*4882a593Smuzhiyun REG_WRITE(map->conf, temp | PIPEACONF_ENABLE);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun temp = REG_READ(map->status);
248*4882a593Smuzhiyun temp &= ~(0xFFFF);
249*4882a593Smuzhiyun temp |= PIPE_FIFO_UNDERRUN;
250*4882a593Smuzhiyun REG_WRITE(map->status, temp);
251*4882a593Smuzhiyun REG_READ(map->status);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun gma_crtc_load_lut(crtc);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /* Give the overlay scaler a chance to enable
256*4882a593Smuzhiyun * if it's on this pipe */
257*4882a593Smuzhiyun /* psb_intel_crtc_dpms_video(crtc, true); TODO */
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun drm_crtc_vblank_on(crtc);
260*4882a593Smuzhiyun break;
261*4882a593Smuzhiyun case DRM_MODE_DPMS_OFF:
262*4882a593Smuzhiyun if (!gma_crtc->active)
263*4882a593Smuzhiyun break;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun gma_crtc->active = false;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /* Give the overlay scaler a chance to disable
268*4882a593Smuzhiyun * if it's on this pipe */
269*4882a593Smuzhiyun /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* Disable the VGA plane that we never use */
272*4882a593Smuzhiyun REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /* Turn off vblank interrupts */
275*4882a593Smuzhiyun drm_crtc_vblank_off(crtc);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* Wait for vblank for the disable to take effect */
278*4882a593Smuzhiyun gma_wait_for_vblank(dev);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /* Disable plane */
281*4882a593Smuzhiyun temp = REG_READ(map->cntr);
282*4882a593Smuzhiyun if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
283*4882a593Smuzhiyun REG_WRITE(map->cntr,
284*4882a593Smuzhiyun temp & ~DISPLAY_PLANE_ENABLE);
285*4882a593Smuzhiyun /* Flush the plane changes */
286*4882a593Smuzhiyun REG_WRITE(map->base, REG_READ(map->base));
287*4882a593Smuzhiyun REG_READ(map->base);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun /* Disable pipe */
291*4882a593Smuzhiyun temp = REG_READ(map->conf);
292*4882a593Smuzhiyun if ((temp & PIPEACONF_ENABLE) != 0) {
293*4882a593Smuzhiyun REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE);
294*4882a593Smuzhiyun REG_READ(map->conf);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun /* Wait for vblank for the disable to take effect. */
298*4882a593Smuzhiyun gma_wait_for_vblank(dev);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun udelay(150);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* Disable DPLL */
303*4882a593Smuzhiyun temp = REG_READ(map->dpll);
304*4882a593Smuzhiyun if ((temp & DPLL_VCO_ENABLE) != 0) {
305*4882a593Smuzhiyun REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE);
306*4882a593Smuzhiyun REG_READ(map->dpll);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /* Wait for the clocks to turn off. */
310*4882a593Smuzhiyun udelay(150);
311*4882a593Smuzhiyun break;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (IS_CDV(dev))
315*4882a593Smuzhiyun dev_priv->ops->update_wm(dev, crtc);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* Set FIFO watermarks */
318*4882a593Smuzhiyun REG_WRITE(DSPARB, 0x3F3E);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
gma_crtc_cursor_set(struct drm_crtc * crtc,struct drm_file * file_priv,uint32_t handle,uint32_t width,uint32_t height)321*4882a593Smuzhiyun int gma_crtc_cursor_set(struct drm_crtc *crtc,
322*4882a593Smuzhiyun struct drm_file *file_priv,
323*4882a593Smuzhiyun uint32_t handle,
324*4882a593Smuzhiyun uint32_t width, uint32_t height)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
327*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
328*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
329*4882a593Smuzhiyun int pipe = gma_crtc->pipe;
330*4882a593Smuzhiyun uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
331*4882a593Smuzhiyun uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
332*4882a593Smuzhiyun uint32_t temp;
333*4882a593Smuzhiyun size_t addr = 0;
334*4882a593Smuzhiyun struct gtt_range *gt;
335*4882a593Smuzhiyun struct gtt_range *cursor_gt = gma_crtc->cursor_gt;
336*4882a593Smuzhiyun struct drm_gem_object *obj;
337*4882a593Smuzhiyun void *tmp_dst, *tmp_src;
338*4882a593Smuzhiyun int ret = 0, i, cursor_pages;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /* If we didn't get a handle then turn the cursor off */
341*4882a593Smuzhiyun if (!handle) {
342*4882a593Smuzhiyun temp = CURSOR_MODE_DISABLE;
343*4882a593Smuzhiyun if (gma_power_begin(dev, false)) {
344*4882a593Smuzhiyun REG_WRITE(control, temp);
345*4882a593Smuzhiyun REG_WRITE(base, 0);
346*4882a593Smuzhiyun gma_power_end(dev);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* Unpin the old GEM object */
350*4882a593Smuzhiyun if (gma_crtc->cursor_obj) {
351*4882a593Smuzhiyun gt = container_of(gma_crtc->cursor_obj,
352*4882a593Smuzhiyun struct gtt_range, gem);
353*4882a593Smuzhiyun psb_gtt_unpin(gt);
354*4882a593Smuzhiyun drm_gem_object_put(gma_crtc->cursor_obj);
355*4882a593Smuzhiyun gma_crtc->cursor_obj = NULL;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun return 0;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* Currently we only support 64x64 cursors */
361*4882a593Smuzhiyun if (width != 64 || height != 64) {
362*4882a593Smuzhiyun dev_dbg(dev->dev, "We currently only support 64x64 cursors\n");
363*4882a593Smuzhiyun return -EINVAL;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun obj = drm_gem_object_lookup(file_priv, handle);
367*4882a593Smuzhiyun if (!obj) {
368*4882a593Smuzhiyun ret = -ENOENT;
369*4882a593Smuzhiyun goto unlock;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (obj->size < width * height * 4) {
373*4882a593Smuzhiyun dev_dbg(dev->dev, "Buffer is too small\n");
374*4882a593Smuzhiyun ret = -ENOMEM;
375*4882a593Smuzhiyun goto unref_cursor;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun gt = container_of(obj, struct gtt_range, gem);
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* Pin the memory into the GTT */
381*4882a593Smuzhiyun ret = psb_gtt_pin(gt);
382*4882a593Smuzhiyun if (ret) {
383*4882a593Smuzhiyun dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle);
384*4882a593Smuzhiyun goto unref_cursor;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun if (dev_priv->ops->cursor_needs_phys) {
388*4882a593Smuzhiyun if (cursor_gt == NULL) {
389*4882a593Smuzhiyun dev_err(dev->dev, "No hardware cursor mem available");
390*4882a593Smuzhiyun ret = -ENOMEM;
391*4882a593Smuzhiyun goto unref_cursor;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun /* Prevent overflow */
395*4882a593Smuzhiyun if (gt->npage > 4)
396*4882a593Smuzhiyun cursor_pages = 4;
397*4882a593Smuzhiyun else
398*4882a593Smuzhiyun cursor_pages = gt->npage;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* Copy the cursor to cursor mem */
401*4882a593Smuzhiyun tmp_dst = dev_priv->vram_addr + cursor_gt->offset;
402*4882a593Smuzhiyun for (i = 0; i < cursor_pages; i++) {
403*4882a593Smuzhiyun tmp_src = kmap(gt->pages[i]);
404*4882a593Smuzhiyun memcpy(tmp_dst, tmp_src, PAGE_SIZE);
405*4882a593Smuzhiyun kunmap(gt->pages[i]);
406*4882a593Smuzhiyun tmp_dst += PAGE_SIZE;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun addr = gma_crtc->cursor_addr;
410*4882a593Smuzhiyun } else {
411*4882a593Smuzhiyun addr = gt->offset;
412*4882a593Smuzhiyun gma_crtc->cursor_addr = addr;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun temp = 0;
416*4882a593Smuzhiyun /* set the pipe for the cursor */
417*4882a593Smuzhiyun temp |= (pipe << 28);
418*4882a593Smuzhiyun temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun if (gma_power_begin(dev, false)) {
421*4882a593Smuzhiyun REG_WRITE(control, temp);
422*4882a593Smuzhiyun REG_WRITE(base, addr);
423*4882a593Smuzhiyun gma_power_end(dev);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* unpin the old bo */
427*4882a593Smuzhiyun if (gma_crtc->cursor_obj) {
428*4882a593Smuzhiyun gt = container_of(gma_crtc->cursor_obj, struct gtt_range, gem);
429*4882a593Smuzhiyun psb_gtt_unpin(gt);
430*4882a593Smuzhiyun drm_gem_object_put(gma_crtc->cursor_obj);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun gma_crtc->cursor_obj = obj;
434*4882a593Smuzhiyun unlock:
435*4882a593Smuzhiyun return ret;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun unref_cursor:
438*4882a593Smuzhiyun drm_gem_object_put(obj);
439*4882a593Smuzhiyun return ret;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
gma_crtc_cursor_move(struct drm_crtc * crtc,int x,int y)442*4882a593Smuzhiyun int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
445*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
446*4882a593Smuzhiyun int pipe = gma_crtc->pipe;
447*4882a593Smuzhiyun uint32_t temp = 0;
448*4882a593Smuzhiyun uint32_t addr;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (x < 0) {
451*4882a593Smuzhiyun temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
452*4882a593Smuzhiyun x = -x;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun if (y < 0) {
455*4882a593Smuzhiyun temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
456*4882a593Smuzhiyun y = -y;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
460*4882a593Smuzhiyun temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun addr = gma_crtc->cursor_addr;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (gma_power_begin(dev, false)) {
465*4882a593Smuzhiyun REG_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
466*4882a593Smuzhiyun REG_WRITE((pipe == 0) ? CURABASE : CURBBASE, addr);
467*4882a593Smuzhiyun gma_power_end(dev);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun return 0;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
gma_crtc_prepare(struct drm_crtc * crtc)472*4882a593Smuzhiyun void gma_crtc_prepare(struct drm_crtc *crtc)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
475*4882a593Smuzhiyun crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
gma_crtc_commit(struct drm_crtc * crtc)478*4882a593Smuzhiyun void gma_crtc_commit(struct drm_crtc *crtc)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
481*4882a593Smuzhiyun crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
gma_crtc_disable(struct drm_crtc * crtc)484*4882a593Smuzhiyun void gma_crtc_disable(struct drm_crtc *crtc)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun struct gtt_range *gt;
487*4882a593Smuzhiyun const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun if (crtc->primary->fb) {
492*4882a593Smuzhiyun gt = to_gtt_range(crtc->primary->fb->obj[0]);
493*4882a593Smuzhiyun psb_gtt_unpin(gt);
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
gma_crtc_destroy(struct drm_crtc * crtc)497*4882a593Smuzhiyun void gma_crtc_destroy(struct drm_crtc *crtc)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun kfree(gma_crtc->crtc_state);
502*4882a593Smuzhiyun drm_crtc_cleanup(crtc);
503*4882a593Smuzhiyun kfree(gma_crtc);
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun
gma_crtc_page_flip(struct drm_crtc * crtc,struct drm_framebuffer * fb,struct drm_pending_vblank_event * event,uint32_t page_flip_flags,struct drm_modeset_acquire_ctx * ctx)506*4882a593Smuzhiyun int gma_crtc_page_flip(struct drm_crtc *crtc,
507*4882a593Smuzhiyun struct drm_framebuffer *fb,
508*4882a593Smuzhiyun struct drm_pending_vblank_event *event,
509*4882a593Smuzhiyun uint32_t page_flip_flags,
510*4882a593Smuzhiyun struct drm_modeset_acquire_ctx *ctx)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
513*4882a593Smuzhiyun struct drm_framebuffer *current_fb = crtc->primary->fb;
514*4882a593Smuzhiyun struct drm_framebuffer *old_fb = crtc->primary->old_fb;
515*4882a593Smuzhiyun const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
516*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
517*4882a593Smuzhiyun unsigned long flags;
518*4882a593Smuzhiyun int ret;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun if (!crtc_funcs->mode_set_base)
521*4882a593Smuzhiyun return -EINVAL;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun /* Using mode_set_base requires the new fb to be set already. */
524*4882a593Smuzhiyun crtc->primary->fb = fb;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun if (event) {
527*4882a593Smuzhiyun spin_lock_irqsave(&dev->event_lock, flags);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun WARN_ON(drm_crtc_vblank_get(crtc) != 0);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun gma_crtc->page_flip_event = event;
532*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->event_lock, flags);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun /* Call this locked if we want an event at vblank interrupt. */
535*4882a593Smuzhiyun ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb);
536*4882a593Smuzhiyun if (ret) {
537*4882a593Smuzhiyun spin_lock_irqsave(&dev->event_lock, flags);
538*4882a593Smuzhiyun if (gma_crtc->page_flip_event) {
539*4882a593Smuzhiyun gma_crtc->page_flip_event = NULL;
540*4882a593Smuzhiyun drm_crtc_vblank_put(crtc);
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->event_lock, flags);
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun } else {
545*4882a593Smuzhiyun ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb);
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /* Restore previous fb in case of failure. */
549*4882a593Smuzhiyun if (ret)
550*4882a593Smuzhiyun crtc->primary->fb = current_fb;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun return ret;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
gma_crtc_set_config(struct drm_mode_set * set,struct drm_modeset_acquire_ctx * ctx)555*4882a593Smuzhiyun int gma_crtc_set_config(struct drm_mode_set *set,
556*4882a593Smuzhiyun struct drm_modeset_acquire_ctx *ctx)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun struct drm_device *dev = set->crtc->dev;
559*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
560*4882a593Smuzhiyun int ret;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun if (!dev_priv->rpm_enabled)
563*4882a593Smuzhiyun return drm_crtc_helper_set_config(set, ctx);
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun pm_runtime_forbid(&dev->pdev->dev);
566*4882a593Smuzhiyun ret = drm_crtc_helper_set_config(set, ctx);
567*4882a593Smuzhiyun pm_runtime_allow(&dev->pdev->dev);
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun return ret;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun /**
573*4882a593Smuzhiyun * Save HW states of given crtc
574*4882a593Smuzhiyun */
gma_crtc_save(struct drm_crtc * crtc)575*4882a593Smuzhiyun void gma_crtc_save(struct drm_crtc *crtc)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
578*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
579*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
580*4882a593Smuzhiyun struct psb_intel_crtc_state *crtc_state = gma_crtc->crtc_state;
581*4882a593Smuzhiyun const struct psb_offset *map = &dev_priv->regmap[gma_crtc->pipe];
582*4882a593Smuzhiyun uint32_t palette_reg;
583*4882a593Smuzhiyun int i;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if (!crtc_state) {
586*4882a593Smuzhiyun dev_err(dev->dev, "No CRTC state found\n");
587*4882a593Smuzhiyun return;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun crtc_state->saveDSPCNTR = REG_READ(map->cntr);
591*4882a593Smuzhiyun crtc_state->savePIPECONF = REG_READ(map->conf);
592*4882a593Smuzhiyun crtc_state->savePIPESRC = REG_READ(map->src);
593*4882a593Smuzhiyun crtc_state->saveFP0 = REG_READ(map->fp0);
594*4882a593Smuzhiyun crtc_state->saveFP1 = REG_READ(map->fp1);
595*4882a593Smuzhiyun crtc_state->saveDPLL = REG_READ(map->dpll);
596*4882a593Smuzhiyun crtc_state->saveHTOTAL = REG_READ(map->htotal);
597*4882a593Smuzhiyun crtc_state->saveHBLANK = REG_READ(map->hblank);
598*4882a593Smuzhiyun crtc_state->saveHSYNC = REG_READ(map->hsync);
599*4882a593Smuzhiyun crtc_state->saveVTOTAL = REG_READ(map->vtotal);
600*4882a593Smuzhiyun crtc_state->saveVBLANK = REG_READ(map->vblank);
601*4882a593Smuzhiyun crtc_state->saveVSYNC = REG_READ(map->vsync);
602*4882a593Smuzhiyun crtc_state->saveDSPSTRIDE = REG_READ(map->stride);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun /* NOTE: DSPSIZE DSPPOS only for psb */
605*4882a593Smuzhiyun crtc_state->saveDSPSIZE = REG_READ(map->size);
606*4882a593Smuzhiyun crtc_state->saveDSPPOS = REG_READ(map->pos);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun crtc_state->saveDSPBASE = REG_READ(map->base);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun palette_reg = map->palette;
611*4882a593Smuzhiyun for (i = 0; i < 256; ++i)
612*4882a593Smuzhiyun crtc_state->savePalette[i] = REG_READ(palette_reg + (i << 2));
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun /**
616*4882a593Smuzhiyun * Restore HW states of given crtc
617*4882a593Smuzhiyun */
gma_crtc_restore(struct drm_crtc * crtc)618*4882a593Smuzhiyun void gma_crtc_restore(struct drm_crtc *crtc)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
621*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
622*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
623*4882a593Smuzhiyun struct psb_intel_crtc_state *crtc_state = gma_crtc->crtc_state;
624*4882a593Smuzhiyun const struct psb_offset *map = &dev_priv->regmap[gma_crtc->pipe];
625*4882a593Smuzhiyun uint32_t palette_reg;
626*4882a593Smuzhiyun int i;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun if (!crtc_state) {
629*4882a593Smuzhiyun dev_err(dev->dev, "No crtc state\n");
630*4882a593Smuzhiyun return;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) {
634*4882a593Smuzhiyun REG_WRITE(map->dpll,
635*4882a593Smuzhiyun crtc_state->saveDPLL & ~DPLL_VCO_ENABLE);
636*4882a593Smuzhiyun REG_READ(map->dpll);
637*4882a593Smuzhiyun udelay(150);
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun REG_WRITE(map->fp0, crtc_state->saveFP0);
641*4882a593Smuzhiyun REG_READ(map->fp0);
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun REG_WRITE(map->fp1, crtc_state->saveFP1);
644*4882a593Smuzhiyun REG_READ(map->fp1);
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun REG_WRITE(map->dpll, crtc_state->saveDPLL);
647*4882a593Smuzhiyun REG_READ(map->dpll);
648*4882a593Smuzhiyun udelay(150);
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun REG_WRITE(map->htotal, crtc_state->saveHTOTAL);
651*4882a593Smuzhiyun REG_WRITE(map->hblank, crtc_state->saveHBLANK);
652*4882a593Smuzhiyun REG_WRITE(map->hsync, crtc_state->saveHSYNC);
653*4882a593Smuzhiyun REG_WRITE(map->vtotal, crtc_state->saveVTOTAL);
654*4882a593Smuzhiyun REG_WRITE(map->vblank, crtc_state->saveVBLANK);
655*4882a593Smuzhiyun REG_WRITE(map->vsync, crtc_state->saveVSYNC);
656*4882a593Smuzhiyun REG_WRITE(map->stride, crtc_state->saveDSPSTRIDE);
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun REG_WRITE(map->size, crtc_state->saveDSPSIZE);
659*4882a593Smuzhiyun REG_WRITE(map->pos, crtc_state->saveDSPPOS);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun REG_WRITE(map->src, crtc_state->savePIPESRC);
662*4882a593Smuzhiyun REG_WRITE(map->base, crtc_state->saveDSPBASE);
663*4882a593Smuzhiyun REG_WRITE(map->conf, crtc_state->savePIPECONF);
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun gma_wait_for_vblank(dev);
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun REG_WRITE(map->cntr, crtc_state->saveDSPCNTR);
668*4882a593Smuzhiyun REG_WRITE(map->base, crtc_state->saveDSPBASE);
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun gma_wait_for_vblank(dev);
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun palette_reg = map->palette;
673*4882a593Smuzhiyun for (i = 0; i < 256; ++i)
674*4882a593Smuzhiyun REG_WRITE(palette_reg + (i << 2), crtc_state->savePalette[i]);
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun
gma_encoder_prepare(struct drm_encoder * encoder)677*4882a593Smuzhiyun void gma_encoder_prepare(struct drm_encoder *encoder)
678*4882a593Smuzhiyun {
679*4882a593Smuzhiyun const struct drm_encoder_helper_funcs *encoder_funcs =
680*4882a593Smuzhiyun encoder->helper_private;
681*4882a593Smuzhiyun /* lvds has its own version of prepare see psb_intel_lvds_prepare */
682*4882a593Smuzhiyun encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun
gma_encoder_commit(struct drm_encoder * encoder)685*4882a593Smuzhiyun void gma_encoder_commit(struct drm_encoder *encoder)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun const struct drm_encoder_helper_funcs *encoder_funcs =
688*4882a593Smuzhiyun encoder->helper_private;
689*4882a593Smuzhiyun /* lvds has its own version of commit see psb_intel_lvds_commit */
690*4882a593Smuzhiyun encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
gma_encoder_destroy(struct drm_encoder * encoder)693*4882a593Smuzhiyun void gma_encoder_destroy(struct drm_encoder *encoder)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun struct gma_encoder *intel_encoder = to_gma_encoder(encoder);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun drm_encoder_cleanup(encoder);
698*4882a593Smuzhiyun kfree(intel_encoder);
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun /* Currently there is only a 1:1 mapping of encoders and connectors */
gma_best_encoder(struct drm_connector * connector)702*4882a593Smuzhiyun struct drm_encoder *gma_best_encoder(struct drm_connector *connector)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun return &gma_encoder->base;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
gma_connector_attach_encoder(struct gma_connector * connector,struct gma_encoder * encoder)709*4882a593Smuzhiyun void gma_connector_attach_encoder(struct gma_connector *connector,
710*4882a593Smuzhiyun struct gma_encoder *encoder)
711*4882a593Smuzhiyun {
712*4882a593Smuzhiyun connector->encoder = encoder;
713*4882a593Smuzhiyun drm_connector_attach_encoder(&connector->base,
714*4882a593Smuzhiyun &encoder->base);
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun #define GMA_PLL_INVALID(s) { /* DRM_ERROR(s); */ return false; }
718*4882a593Smuzhiyun
gma_pll_is_valid(struct drm_crtc * crtc,const struct gma_limit_t * limit,struct gma_clock_t * clock)719*4882a593Smuzhiyun bool gma_pll_is_valid(struct drm_crtc *crtc,
720*4882a593Smuzhiyun const struct gma_limit_t *limit,
721*4882a593Smuzhiyun struct gma_clock_t *clock)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
724*4882a593Smuzhiyun GMA_PLL_INVALID("p1 out of range");
725*4882a593Smuzhiyun if (clock->p < limit->p.min || limit->p.max < clock->p)
726*4882a593Smuzhiyun GMA_PLL_INVALID("p out of range");
727*4882a593Smuzhiyun if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2)
728*4882a593Smuzhiyun GMA_PLL_INVALID("m2 out of range");
729*4882a593Smuzhiyun if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
730*4882a593Smuzhiyun GMA_PLL_INVALID("m1 out of range");
731*4882a593Smuzhiyun /* On CDV m1 is always 0 */
732*4882a593Smuzhiyun if (clock->m1 <= clock->m2 && clock->m1 != 0)
733*4882a593Smuzhiyun GMA_PLL_INVALID("m1 <= m2 && m1 != 0");
734*4882a593Smuzhiyun if (clock->m < limit->m.min || limit->m.max < clock->m)
735*4882a593Smuzhiyun GMA_PLL_INVALID("m out of range");
736*4882a593Smuzhiyun if (clock->n < limit->n.min || limit->n.max < clock->n)
737*4882a593Smuzhiyun GMA_PLL_INVALID("n out of range");
738*4882a593Smuzhiyun if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
739*4882a593Smuzhiyun GMA_PLL_INVALID("vco out of range");
740*4882a593Smuzhiyun /* XXX: We may need to be checking "Dot clock"
741*4882a593Smuzhiyun * depending on the multiplier, connector, etc.,
742*4882a593Smuzhiyun * rather than just a single range.
743*4882a593Smuzhiyun */
744*4882a593Smuzhiyun if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
745*4882a593Smuzhiyun GMA_PLL_INVALID("dot out of range");
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun return true;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun
gma_find_best_pll(const struct gma_limit_t * limit,struct drm_crtc * crtc,int target,int refclk,struct gma_clock_t * best_clock)750*4882a593Smuzhiyun bool gma_find_best_pll(const struct gma_limit_t *limit,
751*4882a593Smuzhiyun struct drm_crtc *crtc, int target, int refclk,
752*4882a593Smuzhiyun struct gma_clock_t *best_clock)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun struct drm_device *dev = crtc->dev;
755*4882a593Smuzhiyun const struct gma_clock_funcs *clock_funcs =
756*4882a593Smuzhiyun to_gma_crtc(crtc)->clock_funcs;
757*4882a593Smuzhiyun struct gma_clock_t clock;
758*4882a593Smuzhiyun int err = target;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun if (gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
761*4882a593Smuzhiyun (REG_READ(LVDS) & LVDS_PORT_EN) != 0) {
762*4882a593Smuzhiyun /*
763*4882a593Smuzhiyun * For LVDS, if the panel is on, just rely on its current
764*4882a593Smuzhiyun * settings for dual-channel. We haven't figured out how to
765*4882a593Smuzhiyun * reliably set up different single/dual channel state, if we
766*4882a593Smuzhiyun * even can.
767*4882a593Smuzhiyun */
768*4882a593Smuzhiyun if ((REG_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
769*4882a593Smuzhiyun LVDS_CLKB_POWER_UP)
770*4882a593Smuzhiyun clock.p2 = limit->p2.p2_fast;
771*4882a593Smuzhiyun else
772*4882a593Smuzhiyun clock.p2 = limit->p2.p2_slow;
773*4882a593Smuzhiyun } else {
774*4882a593Smuzhiyun if (target < limit->p2.dot_limit)
775*4882a593Smuzhiyun clock.p2 = limit->p2.p2_slow;
776*4882a593Smuzhiyun else
777*4882a593Smuzhiyun clock.p2 = limit->p2.p2_fast;
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun memset(best_clock, 0, sizeof(*best_clock));
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun /* m1 is always 0 on CDV so the outmost loop will run just once */
783*4882a593Smuzhiyun for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
784*4882a593Smuzhiyun for (clock.m2 = limit->m2.min;
785*4882a593Smuzhiyun (clock.m2 < clock.m1 || clock.m1 == 0) &&
786*4882a593Smuzhiyun clock.m2 <= limit->m2.max; clock.m2++) {
787*4882a593Smuzhiyun for (clock.n = limit->n.min;
788*4882a593Smuzhiyun clock.n <= limit->n.max; clock.n++) {
789*4882a593Smuzhiyun for (clock.p1 = limit->p1.min;
790*4882a593Smuzhiyun clock.p1 <= limit->p1.max;
791*4882a593Smuzhiyun clock.p1++) {
792*4882a593Smuzhiyun int this_err;
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun clock_funcs->clock(refclk, &clock);
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun if (!clock_funcs->pll_is_valid(crtc,
797*4882a593Smuzhiyun limit, &clock))
798*4882a593Smuzhiyun continue;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun this_err = abs(clock.dot - target);
801*4882a593Smuzhiyun if (this_err < err) {
802*4882a593Smuzhiyun *best_clock = clock;
803*4882a593Smuzhiyun err = this_err;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun return err != target;
811*4882a593Smuzhiyun }
812