Commit | Line | Data |
---|---|---|
026abc33 KS |
1 | /* |
2 | * Copyright © 2006-2007 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 | */ | |
20 | ||
21 | #include <linux/i2c.h> | |
22 | #include <linux/pm_runtime.h> | |
23 | ||
24 | #include <drm/drmP.h> | |
25 | #include "psb_intel_reg.h" | |
fe477cc1 | 26 | #include "gma_display.h" |
026abc33 KS |
27 | #include "framebuffer.h" |
28 | #include "mdfld_output.h" | |
29 | #include "mdfld_dsi_output.h" | |
30 | ||
31 | /* Hardcoded currently */ | |
32 | static int ksel = KSEL_CRYSTAL_19; | |
33 | ||
34 | struct psb_intel_range_t { | |
35 | int min, max; | |
36 | }; | |
37 | ||
38 | struct mrst_limit_t { | |
39 | struct psb_intel_range_t dot, m, p1; | |
40 | }; | |
41 | ||
42 | struct mrst_clock_t { | |
43 | /* derived values */ | |
44 | int dot; | |
45 | int m; | |
46 | int p1; | |
47 | }; | |
48 | ||
49 | #define COUNT_MAX 0x10000000 | |
50 | ||
51 | void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe) | |
52 | { | |
213a8434 AC |
53 | struct drm_psb_private *dev_priv = dev->dev_private; |
54 | const struct psb_offset *map = &dev_priv->regmap[pipe]; | |
026abc33 | 55 | int count, temp; |
026abc33 KS |
56 | |
57 | switch (pipe) { | |
58 | case 0: | |
026abc33 | 59 | case 1: |
026abc33 | 60 | case 2: |
026abc33 KS |
61 | break; |
62 | default: | |
63 | DRM_ERROR("Illegal Pipe Number.\n"); | |
64 | return; | |
65 | } | |
66 | ||
67 | /* FIXME JLIU7_PO */ | |
d1fa08f3 | 68 | gma_wait_for_vblank(dev); |
026abc33 KS |
69 | return; |
70 | ||
71 | /* Wait for for the pipe disable to take effect. */ | |
72 | for (count = 0; count < COUNT_MAX; count++) { | |
213a8434 | 73 | temp = REG_READ(map->conf); |
026abc33 KS |
74 | if ((temp & PIPEACONF_PIPE_STATE) == 0) |
75 | break; | |
76 | } | |
77 | } | |
78 | ||
79 | void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe) | |
80 | { | |
213a8434 AC |
81 | struct drm_psb_private *dev_priv = dev->dev_private; |
82 | const struct psb_offset *map = &dev_priv->regmap[pipe]; | |
026abc33 | 83 | int count, temp; |
026abc33 KS |
84 | |
85 | switch (pipe) { | |
86 | case 0: | |
026abc33 | 87 | case 1: |
026abc33 | 88 | case 2: |
026abc33 KS |
89 | break; |
90 | default: | |
91 | DRM_ERROR("Illegal Pipe Number.\n"); | |
92 | return; | |
93 | } | |
94 | ||
95 | /* FIXME JLIU7_PO */ | |
d1fa08f3 | 96 | gma_wait_for_vblank(dev); |
026abc33 KS |
97 | return; |
98 | ||
99 | /* Wait for for the pipe enable to take effect. */ | |
100 | for (count = 0; count < COUNT_MAX; count++) { | |
213a8434 | 101 | temp = REG_READ(map->conf); |
026abc33 KS |
102 | if ((temp & PIPEACONF_PIPE_STATE) == 1) |
103 | break; | |
104 | } | |
105 | } | |
106 | ||
026abc33 KS |
107 | /** |
108 | * Return the pipe currently connected to the panel fitter, | |
109 | * or -1 if the panel fitter is not present or not in use | |
110 | */ | |
111 | static int psb_intel_panel_fitter_pipe(struct drm_device *dev) | |
112 | { | |
113 | u32 pfit_control; | |
114 | ||
115 | pfit_control = REG_READ(PFIT_CONTROL); | |
116 | ||
117 | /* See if the panel fitter is in use */ | |
118 | if ((pfit_control & PFIT_ENABLE) == 0) | |
119 | return -1; | |
120 | ||
121 | /* 965 can place panel fitter on either pipe */ | |
122 | return (pfit_control >> 29) & 0x3; | |
123 | } | |
124 | ||
125 | static struct drm_device globle_dev; | |
126 | ||
127 | void mdfld__intel_plane_set_alpha(int enable) | |
128 | { | |
129 | struct drm_device *dev = &globle_dev; | |
130 | int dspcntr_reg = DSPACNTR; | |
131 | u32 dspcntr; | |
132 | ||
133 | dspcntr = REG_READ(dspcntr_reg); | |
134 | ||
135 | if (enable) { | |
136 | dspcntr &= ~DISPPLANE_32BPP_NO_ALPHA; | |
137 | dspcntr |= DISPPLANE_32BPP; | |
138 | } else { | |
139 | dspcntr &= ~DISPPLANE_32BPP; | |
140 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | |
141 | } | |
142 | ||
143 | REG_WRITE(dspcntr_reg, dspcntr); | |
144 | } | |
145 | ||
146 | static int check_fb(struct drm_framebuffer *fb) | |
147 | { | |
148 | if (!fb) | |
149 | return 0; | |
150 | ||
151 | switch (fb->bits_per_pixel) { | |
152 | case 8: | |
153 | case 16: | |
154 | case 24: | |
155 | case 32: | |
156 | return 0; | |
157 | default: | |
158 | DRM_ERROR("Unknown color depth\n"); | |
159 | return -EINVAL; | |
160 | } | |
161 | } | |
162 | ||
163 | static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | |
164 | struct drm_framebuffer *old_fb) | |
165 | { | |
166 | struct drm_device *dev = crtc->dev; | |
213a8434 | 167 | struct drm_psb_private *dev_priv = dev->dev_private; |
6306865d | 168 | struct gma_crtc *gma_crtc = to_gma_crtc(crtc); |
f4510a27 | 169 | struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb); |
6306865d | 170 | int pipe = gma_crtc->pipe; |
213a8434 | 171 | const struct psb_offset *map = &dev_priv->regmap[pipe]; |
026abc33 | 172 | unsigned long start, offset; |
026abc33 KS |
173 | u32 dspcntr; |
174 | int ret; | |
175 | ||
176 | memcpy(&globle_dev, dev, sizeof(struct drm_device)); | |
177 | ||
178 | dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe); | |
179 | ||
180 | /* no fb bound */ | |
f4510a27 | 181 | if (!crtc->primary->fb) { |
026abc33 KS |
182 | dev_dbg(dev->dev, "No FB bound\n"); |
183 | return 0; | |
184 | } | |
185 | ||
f4510a27 | 186 | ret = check_fb(crtc->primary->fb); |
026abc33 KS |
187 | if (ret) |
188 | return ret; | |
189 | ||
213a8434 | 190 | if (pipe > 2) { |
026abc33 KS |
191 | DRM_ERROR("Illegal Pipe Number.\n"); |
192 | return -EINVAL; | |
193 | } | |
194 | ||
195 | if (!gma_power_begin(dev, true)) | |
196 | return 0; | |
197 | ||
198 | start = psbfb->gtt->offset; | |
f4510a27 | 199 | offset = y * crtc->primary->fb->pitches[0] + x * (crtc->primary->fb->bits_per_pixel / 8); |
026abc33 | 200 | |
f4510a27 | 201 | REG_WRITE(map->stride, crtc->primary->fb->pitches[0]); |
213a8434 | 202 | dspcntr = REG_READ(map->cntr); |
026abc33 KS |
203 | dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; |
204 | ||
f4510a27 | 205 | switch (crtc->primary->fb->bits_per_pixel) { |
026abc33 KS |
206 | case 8: |
207 | dspcntr |= DISPPLANE_8BPP; | |
208 | break; | |
209 | case 16: | |
f4510a27 | 210 | if (crtc->primary->fb->depth == 15) |
026abc33 KS |
211 | dspcntr |= DISPPLANE_15_16BPP; |
212 | else | |
213 | dspcntr |= DISPPLANE_16BPP; | |
214 | break; | |
215 | case 24: | |
216 | case 32: | |
217 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | |
218 | break; | |
219 | } | |
213a8434 | 220 | REG_WRITE(map->cntr, dspcntr); |
026abc33 KS |
221 | |
222 | dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n", | |
223 | start, offset, x, y); | |
213a8434 AC |
224 | REG_WRITE(map->linoff, offset); |
225 | REG_READ(map->linoff); | |
226 | REG_WRITE(map->surf, start); | |
227 | REG_READ(map->surf); | |
026abc33 KS |
228 | |
229 | gma_power_end(dev); | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | /* | |
235 | * Disable the pipe, plane and pll. | |
236 | * | |
237 | */ | |
238 | void mdfld_disable_crtc(struct drm_device *dev, int pipe) | |
239 | { | |
213a8434 AC |
240 | struct drm_psb_private *dev_priv = dev->dev_private; |
241 | const struct psb_offset *map = &dev_priv->regmap[pipe]; | |
026abc33 KS |
242 | u32 temp; |
243 | ||
244 | dev_dbg(dev->dev, "pipe = %d\n", pipe); | |
245 | ||
246 | ||
026abc33 KS |
247 | if (pipe != 1) |
248 | mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe), | |
249 | HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); | |
250 | ||
251 | /* Disable display plane */ | |
213a8434 | 252 | temp = REG_READ(map->cntr); |
026abc33 | 253 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { |
213a8434 | 254 | REG_WRITE(map->cntr, |
026abc33 KS |
255 | temp & ~DISPLAY_PLANE_ENABLE); |
256 | /* Flush the plane changes */ | |
213a8434 AC |
257 | REG_WRITE(map->base, REG_READ(map->base)); |
258 | REG_READ(map->base); | |
026abc33 KS |
259 | } |
260 | ||
261 | /* FIXME_JLIU7 MDFLD_PO revisit */ | |
262 | ||
263 | /* Next, disable display pipes */ | |
213a8434 | 264 | temp = REG_READ(map->conf); |
026abc33 KS |
265 | if ((temp & PIPEACONF_ENABLE) != 0) { |
266 | temp &= ~PIPEACONF_ENABLE; | |
267 | temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; | |
213a8434 AC |
268 | REG_WRITE(map->conf, temp); |
269 | REG_READ(map->conf); | |
026abc33 KS |
270 | |
271 | /* Wait for for the pipe disable to take effect. */ | |
272 | mdfldWaitForPipeDisable(dev, pipe); | |
273 | } | |
274 | ||
213a8434 | 275 | temp = REG_READ(map->dpll); |
026abc33 KS |
276 | if (temp & DPLL_VCO_ENABLE) { |
277 | if ((pipe != 1 && | |
278 | !((REG_READ(PIPEACONF) | REG_READ(PIPECCONF)) | |
279 | & PIPEACONF_ENABLE)) || pipe == 1) { | |
280 | temp &= ~(DPLL_VCO_ENABLE); | |
213a8434 AC |
281 | REG_WRITE(map->dpll, temp); |
282 | REG_READ(map->dpll); | |
026abc33 KS |
283 | /* Wait for the clocks to turn off. */ |
284 | /* FIXME_MDFLD PO may need more delay */ | |
285 | udelay(500); | |
286 | ||
287 | if (!(temp & MDFLD_PWR_GATE_EN)) { | |
288 | /* gating power of DPLL */ | |
213a8434 | 289 | REG_WRITE(map->dpll, temp | MDFLD_PWR_GATE_EN); |
026abc33 KS |
290 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ |
291 | udelay(5000); | |
292 | } | |
293 | } | |
294 | } | |
295 | ||
296 | } | |
297 | ||
298 | /** | |
299 | * Sets the power management mode of the pipe and plane. | |
300 | * | |
301 | * This code should probably grow support for turning the cursor off and back | |
302 | * on appropriately at the same time as we're turning the pipe off/on. | |
303 | */ | |
304 | static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode) | |
305 | { | |
306 | struct drm_device *dev = crtc->dev; | |
307 | struct drm_psb_private *dev_priv = dev->dev_private; | |
6306865d PJ |
308 | struct gma_crtc *gma_crtc = to_gma_crtc(crtc); |
309 | int pipe = gma_crtc->pipe; | |
213a8434 | 310 | const struct psb_offset *map = &dev_priv->regmap[pipe]; |
026abc33 KS |
311 | u32 pipeconf = dev_priv->pipeconf[pipe]; |
312 | u32 temp; | |
026abc33 KS |
313 | int timeout = 0; |
314 | ||
315 | dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe); | |
316 | ||
213a8434 AC |
317 | /* Note: Old code uses pipe a stat for pipe b but that appears |
318 | to be a bug */ | |
026abc33 KS |
319 | |
320 | if (!gma_power_begin(dev, true)) | |
321 | return; | |
322 | ||
323 | /* XXX: When our outputs are all unaware of DPMS modes other than off | |
324 | * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. | |
325 | */ | |
326 | switch (mode) { | |
327 | case DRM_MODE_DPMS_ON: | |
328 | case DRM_MODE_DPMS_STANDBY: | |
329 | case DRM_MODE_DPMS_SUSPEND: | |
330 | /* Enable the DPLL */ | |
213a8434 | 331 | temp = REG_READ(map->dpll); |
026abc33 KS |
332 | |
333 | if ((temp & DPLL_VCO_ENABLE) == 0) { | |
334 | /* When ungating power of DPLL, needs to wait 0.5us | |
335 | before enable the VCO */ | |
336 | if (temp & MDFLD_PWR_GATE_EN) { | |
337 | temp &= ~MDFLD_PWR_GATE_EN; | |
213a8434 | 338 | REG_WRITE(map->dpll, temp); |
026abc33 KS |
339 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ |
340 | udelay(500); | |
341 | } | |
342 | ||
213a8434 AC |
343 | REG_WRITE(map->dpll, temp); |
344 | REG_READ(map->dpll); | |
026abc33 KS |
345 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ |
346 | udelay(500); | |
347 | ||
213a8434 AC |
348 | REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); |
349 | REG_READ(map->dpll); | |
026abc33 KS |
350 | |
351 | /** | |
352 | * wait for DSI PLL to lock | |
353 | * NOTE: only need to poll status of pipe 0 and pipe 1, | |
354 | * since both MIPI pipes share the same PLL. | |
355 | */ | |
356 | while ((pipe != 2) && (timeout < 20000) && | |
213a8434 | 357 | !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) { |
026abc33 KS |
358 | udelay(150); |
359 | timeout++; | |
360 | } | |
361 | } | |
362 | ||
363 | /* Enable the plane */ | |
213a8434 | 364 | temp = REG_READ(map->cntr); |
026abc33 | 365 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { |
213a8434 | 366 | REG_WRITE(map->cntr, |
026abc33 KS |
367 | temp | DISPLAY_PLANE_ENABLE); |
368 | /* Flush the plane changes */ | |
213a8434 | 369 | REG_WRITE(map->base, REG_READ(map->base)); |
026abc33 KS |
370 | } |
371 | ||
372 | /* Enable the pipe */ | |
213a8434 | 373 | temp = REG_READ(map->conf); |
026abc33 | 374 | if ((temp & PIPEACONF_ENABLE) == 0) { |
213a8434 | 375 | REG_WRITE(map->conf, pipeconf); |
026abc33 KS |
376 | |
377 | /* Wait for for the pipe enable to take effect. */ | |
378 | mdfldWaitForPipeEnable(dev, pipe); | |
379 | } | |
380 | ||
381 | /*workaround for sighting 3741701 Random X blank display*/ | |
382 | /*perform w/a in video mode only on pipe A or C*/ | |
383 | if (pipe == 0 || pipe == 2) { | |
213a8434 | 384 | REG_WRITE(map->status, REG_READ(map->status)); |
026abc33 | 385 | msleep(100); |
213a8434 | 386 | if (PIPE_VBLANK_STATUS & REG_READ(map->status)) |
026abc33 KS |
387 | dev_dbg(dev->dev, "OK"); |
388 | else { | |
389 | dev_dbg(dev->dev, "STUCK!!!!"); | |
390 | /*shutdown controller*/ | |
213a8434 AC |
391 | temp = REG_READ(map->cntr); |
392 | REG_WRITE(map->cntr, | |
026abc33 | 393 | temp & ~DISPLAY_PLANE_ENABLE); |
213a8434 | 394 | REG_WRITE(map->base, REG_READ(map->base)); |
026abc33 KS |
395 | /*mdfld_dsi_dpi_shut_down(dev, pipe);*/ |
396 | REG_WRITE(0xb048, 1); | |
397 | msleep(100); | |
213a8434 | 398 | temp = REG_READ(map->conf); |
026abc33 | 399 | temp &= ~PIPEACONF_ENABLE; |
213a8434 | 400 | REG_WRITE(map->conf, temp); |
026abc33 KS |
401 | msleep(100); /*wait for pipe disable*/ |
402 | REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0); | |
403 | msleep(100); | |
404 | REG_WRITE(0xb004, REG_READ(0xb004)); | |
405 | /* try to bring the controller back up again*/ | |
406 | REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1); | |
213a8434 AC |
407 | temp = REG_READ(map->cntr); |
408 | REG_WRITE(map->cntr, | |
026abc33 | 409 | temp | DISPLAY_PLANE_ENABLE); |
213a8434 | 410 | REG_WRITE(map->base, REG_READ(map->base)); |
026abc33 KS |
411 | /*mdfld_dsi_dpi_turn_on(dev, pipe);*/ |
412 | REG_WRITE(0xb048, 2); | |
413 | msleep(100); | |
213a8434 | 414 | temp = REG_READ(map->conf); |
026abc33 | 415 | temp |= PIPEACONF_ENABLE; |
213a8434 | 416 | REG_WRITE(map->conf, temp); |
026abc33 KS |
417 | } |
418 | } | |
419 | ||
6443ea1a | 420 | gma_crtc_load_lut(crtc); |
026abc33 KS |
421 | |
422 | /* Give the overlay scaler a chance to enable | |
423 | if it's on this pipe */ | |
424 | /* psb_intel_crtc_dpms_video(crtc, true); TODO */ | |
425 | ||
426 | break; | |
427 | case DRM_MODE_DPMS_OFF: | |
428 | /* Give the overlay scaler a chance to disable | |
429 | * if it's on this pipe */ | |
430 | /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */ | |
431 | if (pipe != 1) | |
432 | mdfld_dsi_gen_fifo_ready(dev, | |
433 | MIPI_GEN_FIFO_STAT_REG(pipe), | |
434 | HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); | |
435 | ||
436 | /* Disable the VGA plane that we never use */ | |
437 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | |
438 | ||
439 | /* Disable display plane */ | |
213a8434 | 440 | temp = REG_READ(map->cntr); |
026abc33 | 441 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { |
213a8434 | 442 | REG_WRITE(map->cntr, |
026abc33 KS |
443 | temp & ~DISPLAY_PLANE_ENABLE); |
444 | /* Flush the plane changes */ | |
213a8434 AC |
445 | REG_WRITE(map->base, REG_READ(map->base)); |
446 | REG_READ(map->base); | |
026abc33 KS |
447 | } |
448 | ||
449 | /* Next, disable display pipes */ | |
213a8434 | 450 | temp = REG_READ(map->conf); |
026abc33 KS |
451 | if ((temp & PIPEACONF_ENABLE) != 0) { |
452 | temp &= ~PIPEACONF_ENABLE; | |
453 | temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; | |
213a8434 AC |
454 | REG_WRITE(map->conf, temp); |
455 | REG_READ(map->conf); | |
026abc33 KS |
456 | |
457 | /* Wait for for the pipe disable to take effect. */ | |
458 | mdfldWaitForPipeDisable(dev, pipe); | |
459 | } | |
460 | ||
213a8434 | 461 | temp = REG_READ(map->dpll); |
026abc33 KS |
462 | if (temp & DPLL_VCO_ENABLE) { |
463 | if ((pipe != 1 && !((REG_READ(PIPEACONF) | |
464 | | REG_READ(PIPECCONF)) & PIPEACONF_ENABLE)) | |
465 | || pipe == 1) { | |
466 | temp &= ~(DPLL_VCO_ENABLE); | |
213a8434 AC |
467 | REG_WRITE(map->dpll, temp); |
468 | REG_READ(map->dpll); | |
026abc33 KS |
469 | /* Wait for the clocks to turn off. */ |
470 | /* FIXME_MDFLD PO may need more delay */ | |
471 | udelay(500); | |
472 | } | |
473 | } | |
474 | break; | |
475 | } | |
026abc33 KS |
476 | gma_power_end(dev); |
477 | } | |
478 | ||
479 | ||
480 | #define MDFLD_LIMT_DPLL_19 0 | |
481 | #define MDFLD_LIMT_DPLL_25 1 | |
482 | #define MDFLD_LIMT_DPLL_83 2 | |
483 | #define MDFLD_LIMT_DPLL_100 3 | |
484 | #define MDFLD_LIMT_DSIPLL_19 4 | |
485 | #define MDFLD_LIMT_DSIPLL_25 5 | |
486 | #define MDFLD_LIMT_DSIPLL_83 6 | |
487 | #define MDFLD_LIMT_DSIPLL_100 7 | |
488 | ||
489 | #define MDFLD_DOT_MIN 19750 | |
490 | #define MDFLD_DOT_MAX 120000 | |
491 | #define MDFLD_DPLL_M_MIN_19 113 | |
492 | #define MDFLD_DPLL_M_MAX_19 155 | |
493 | #define MDFLD_DPLL_P1_MIN_19 2 | |
494 | #define MDFLD_DPLL_P1_MAX_19 10 | |
495 | #define MDFLD_DPLL_M_MIN_25 101 | |
496 | #define MDFLD_DPLL_M_MAX_25 130 | |
497 | #define MDFLD_DPLL_P1_MIN_25 2 | |
498 | #define MDFLD_DPLL_P1_MAX_25 10 | |
499 | #define MDFLD_DPLL_M_MIN_83 64 | |
500 | #define MDFLD_DPLL_M_MAX_83 64 | |
501 | #define MDFLD_DPLL_P1_MIN_83 2 | |
502 | #define MDFLD_DPLL_P1_MAX_83 2 | |
503 | #define MDFLD_DPLL_M_MIN_100 64 | |
504 | #define MDFLD_DPLL_M_MAX_100 64 | |
505 | #define MDFLD_DPLL_P1_MIN_100 2 | |
506 | #define MDFLD_DPLL_P1_MAX_100 2 | |
507 | #define MDFLD_DSIPLL_M_MIN_19 131 | |
508 | #define MDFLD_DSIPLL_M_MAX_19 175 | |
509 | #define MDFLD_DSIPLL_P1_MIN_19 3 | |
510 | #define MDFLD_DSIPLL_P1_MAX_19 8 | |
511 | #define MDFLD_DSIPLL_M_MIN_25 97 | |
512 | #define MDFLD_DSIPLL_M_MAX_25 140 | |
513 | #define MDFLD_DSIPLL_P1_MIN_25 3 | |
514 | #define MDFLD_DSIPLL_P1_MAX_25 9 | |
515 | #define MDFLD_DSIPLL_M_MIN_83 33 | |
516 | #define MDFLD_DSIPLL_M_MAX_83 92 | |
517 | #define MDFLD_DSIPLL_P1_MIN_83 2 | |
518 | #define MDFLD_DSIPLL_P1_MAX_83 3 | |
519 | #define MDFLD_DSIPLL_M_MIN_100 97 | |
520 | #define MDFLD_DSIPLL_M_MAX_100 140 | |
521 | #define MDFLD_DSIPLL_P1_MIN_100 3 | |
522 | #define MDFLD_DSIPLL_P1_MAX_100 9 | |
523 | ||
524 | static const struct mrst_limit_t mdfld_limits[] = { | |
525 | { /* MDFLD_LIMT_DPLL_19 */ | |
526 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | |
527 | .m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19}, | |
528 | .p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19}, | |
529 | }, | |
530 | { /* MDFLD_LIMT_DPLL_25 */ | |
531 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | |
532 | .m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25}, | |
533 | .p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25}, | |
534 | }, | |
535 | { /* MDFLD_LIMT_DPLL_83 */ | |
536 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | |
537 | .m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83}, | |
538 | .p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83}, | |
539 | }, | |
540 | { /* MDFLD_LIMT_DPLL_100 */ | |
541 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | |
542 | .m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100}, | |
543 | .p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100}, | |
544 | }, | |
545 | { /* MDFLD_LIMT_DSIPLL_19 */ | |
546 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | |
547 | .m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19}, | |
548 | .p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19}, | |
549 | }, | |
550 | { /* MDFLD_LIMT_DSIPLL_25 */ | |
551 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | |
552 | .m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25}, | |
553 | .p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25}, | |
554 | }, | |
555 | { /* MDFLD_LIMT_DSIPLL_83 */ | |
556 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | |
557 | .m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83}, | |
558 | .p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83}, | |
559 | }, | |
560 | { /* MDFLD_LIMT_DSIPLL_100 */ | |
561 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | |
562 | .m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100}, | |
563 | .p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100}, | |
564 | }, | |
565 | }; | |
566 | ||
567 | #define MDFLD_M_MIN 21 | |
568 | #define MDFLD_M_MAX 180 | |
569 | static const u32 mdfld_m_converts[] = { | |
570 | /* M configuration table from 9-bit LFSR table */ | |
571 | 224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */ | |
572 | 173, 342, 171, 85, 298, 149, 74, 37, 18, 265, /* 31 - 40 */ | |
573 | 388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */ | |
574 | 83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */ | |
575 | 341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */ | |
576 | 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */ | |
577 | 106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */ | |
578 | 71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */ | |
579 | 253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */ | |
580 | 478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */ | |
581 | 477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */ | |
582 | 210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */ | |
583 | 145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */ | |
584 | 380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */ | |
585 | 103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */ | |
586 | 396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */ | |
587 | }; | |
588 | ||
589 | static const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc) | |
590 | { | |
591 | const struct mrst_limit_t *limit = NULL; | |
592 | struct drm_device *dev = crtc->dev; | |
593 | struct drm_psb_private *dev_priv = dev->dev_private; | |
594 | ||
fe477cc1 PJ |
595 | if (gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI) |
596 | || gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI2)) { | |
026abc33 KS |
597 | if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) |
598 | limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_19]; | |
599 | else if (ksel == KSEL_BYPASS_25) | |
600 | limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_25]; | |
601 | else if ((ksel == KSEL_BYPASS_83_100) && | |
602 | (dev_priv->core_freq == 166)) | |
603 | limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_83]; | |
604 | else if ((ksel == KSEL_BYPASS_83_100) && | |
605 | (dev_priv->core_freq == 100 || | |
606 | dev_priv->core_freq == 200)) | |
607 | limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_100]; | |
fe477cc1 | 608 | } else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) { |
026abc33 KS |
609 | if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) |
610 | limit = &mdfld_limits[MDFLD_LIMT_DPLL_19]; | |
611 | else if (ksel == KSEL_BYPASS_25) | |
612 | limit = &mdfld_limits[MDFLD_LIMT_DPLL_25]; | |
613 | else if ((ksel == KSEL_BYPASS_83_100) && | |
614 | (dev_priv->core_freq == 166)) | |
615 | limit = &mdfld_limits[MDFLD_LIMT_DPLL_83]; | |
616 | else if ((ksel == KSEL_BYPASS_83_100) && | |
617 | (dev_priv->core_freq == 100 || | |
618 | dev_priv->core_freq == 200)) | |
619 | limit = &mdfld_limits[MDFLD_LIMT_DPLL_100]; | |
620 | } else { | |
621 | limit = NULL; | |
622 | dev_dbg(dev->dev, "mdfld_limit Wrong display type.\n"); | |
623 | } | |
624 | ||
625 | return limit; | |
626 | } | |
627 | ||
628 | /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ | |
629 | static void mdfld_clock(int refclk, struct mrst_clock_t *clock) | |
630 | { | |
631 | clock->dot = (refclk * clock->m) / clock->p1; | |
632 | } | |
633 | ||
634 | /** | |
635 | * Returns a set of divisors for the desired target clock with the given refclk, | |
636 | * or FALSE. Divisor values are the actual divisors for | |
637 | */ | |
638 | static bool | |
639 | mdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk, | |
640 | struct mrst_clock_t *best_clock) | |
641 | { | |
642 | struct mrst_clock_t clock; | |
643 | const struct mrst_limit_t *limit = mdfld_limit(crtc); | |
644 | int err = target; | |
645 | ||
646 | memset(best_clock, 0, sizeof(*best_clock)); | |
647 | ||
648 | for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { | |
649 | for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; | |
650 | clock.p1++) { | |
651 | int this_err; | |
652 | ||
653 | mdfld_clock(refclk, &clock); | |
654 | ||
655 | this_err = abs(clock.dot - target); | |
656 | if (this_err < err) { | |
657 | *best_clock = clock; | |
658 | err = this_err; | |
659 | } | |
660 | } | |
661 | } | |
662 | return err != target; | |
663 | } | |
664 | ||
665 | static int mdfld_crtc_mode_set(struct drm_crtc *crtc, | |
666 | struct drm_display_mode *mode, | |
667 | struct drm_display_mode *adjusted_mode, | |
668 | int x, int y, | |
669 | struct drm_framebuffer *old_fb) | |
670 | { | |
671 | struct drm_device *dev = crtc->dev; | |
6306865d | 672 | struct gma_crtc *gma_crtc = to_gma_crtc(crtc); |
026abc33 | 673 | struct drm_psb_private *dev_priv = dev->dev_private; |
6306865d | 674 | int pipe = gma_crtc->pipe; |
213a8434 | 675 | const struct psb_offset *map = &dev_priv->regmap[pipe]; |
026abc33 KS |
676 | int refclk = 0; |
677 | int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0, | |
678 | clk_tmp = 0; | |
679 | struct mrst_clock_t clock; | |
680 | bool ok; | |
681 | u32 dpll = 0, fp = 0; | |
026abc33 KS |
682 | bool is_mipi = false, is_mipi2 = false, is_hdmi = false; |
683 | struct drm_mode_config *mode_config = &dev->mode_config; | |
367e4408 | 684 | struct gma_encoder *gma_encoder = NULL; |
026abc33 KS |
685 | uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; |
686 | struct drm_encoder *encoder; | |
687 | struct drm_connector *connector; | |
688 | int timeout = 0; | |
689 | int ret; | |
690 | ||
691 | dev_dbg(dev->dev, "pipe = 0x%x\n", pipe); | |
692 | ||
693 | #if 0 | |
694 | if (pipe == 1) { | |
695 | if (!gma_power_begin(dev, true)) | |
696 | return 0; | |
697 | android_hdmi_crtc_mode_set(crtc, mode, adjusted_mode, | |
698 | x, y, old_fb); | |
699 | goto mrst_crtc_mode_set_exit; | |
700 | } | |
701 | #endif | |
702 | ||
f4510a27 | 703 | ret = check_fb(crtc->primary->fb); |
026abc33 KS |
704 | if (ret) |
705 | return ret; | |
706 | ||
707 | dev_dbg(dev->dev, "adjusted_hdisplay = %d\n", | |
708 | adjusted_mode->hdisplay); | |
709 | dev_dbg(dev->dev, "adjusted_vdisplay = %d\n", | |
710 | adjusted_mode->vdisplay); | |
711 | dev_dbg(dev->dev, "adjusted_hsync_start = %d\n", | |
712 | adjusted_mode->hsync_start); | |
713 | dev_dbg(dev->dev, "adjusted_hsync_end = %d\n", | |
714 | adjusted_mode->hsync_end); | |
715 | dev_dbg(dev->dev, "adjusted_htotal = %d\n", | |
716 | adjusted_mode->htotal); | |
717 | dev_dbg(dev->dev, "adjusted_vsync_start = %d\n", | |
718 | adjusted_mode->vsync_start); | |
719 | dev_dbg(dev->dev, "adjusted_vsync_end = %d\n", | |
720 | adjusted_mode->vsync_end); | |
721 | dev_dbg(dev->dev, "adjusted_vtotal = %d\n", | |
722 | adjusted_mode->vtotal); | |
723 | dev_dbg(dev->dev, "adjusted_clock = %d\n", | |
724 | adjusted_mode->clock); | |
725 | dev_dbg(dev->dev, "hdisplay = %d\n", | |
726 | mode->hdisplay); | |
727 | dev_dbg(dev->dev, "vdisplay = %d\n", | |
728 | mode->vdisplay); | |
729 | ||
730 | if (!gma_power_begin(dev, true)) | |
731 | return 0; | |
732 | ||
6306865d | 733 | memcpy(&gma_crtc->saved_mode, mode, |
026abc33 | 734 | sizeof(struct drm_display_mode)); |
6306865d | 735 | memcpy(&gma_crtc->saved_adjusted_mode, adjusted_mode, |
026abc33 KS |
736 | sizeof(struct drm_display_mode)); |
737 | ||
738 | list_for_each_entry(connector, &mode_config->connector_list, head) { | |
739 | if (!connector) | |
740 | continue; | |
741 | ||
742 | encoder = connector->encoder; | |
743 | ||
744 | if (!encoder) | |
745 | continue; | |
746 | ||
747 | if (encoder->crtc != crtc) | |
748 | continue; | |
749 | ||
367e4408 | 750 | gma_encoder = gma_attached_encoder(connector); |
026abc33 | 751 | |
367e4408 | 752 | switch (gma_encoder->type) { |
026abc33 KS |
753 | case INTEL_OUTPUT_MIPI: |
754 | is_mipi = true; | |
755 | break; | |
756 | case INTEL_OUTPUT_MIPI2: | |
757 | is_mipi2 = true; | |
758 | break; | |
759 | case INTEL_OUTPUT_HDMI: | |
760 | is_hdmi = true; | |
761 | break; | |
762 | } | |
763 | } | |
764 | ||
765 | /* Disable the VGA plane that we never use */ | |
766 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | |
767 | ||
768 | /* Disable the panel fitter if it was on our pipe */ | |
769 | if (psb_intel_panel_fitter_pipe(dev) == pipe) | |
770 | REG_WRITE(PFIT_CONTROL, 0); | |
771 | ||
772 | /* pipesrc and dspsize control the size that is scaled from, | |
773 | * which should always be the user's requested size. | |
774 | */ | |
775 | if (pipe == 1) { | |
776 | /* FIXME: To make HDMI display with 864x480 (TPO), 480x864 | |
777 | * (PYR) or 480x854 (TMD), set the sprite width/height and | |
778 | * souce image size registers with the adjusted mode for | |
779 | * pipe B. | |
780 | */ | |
781 | ||
782 | /* | |
783 | * The defined sprite rectangle must always be completely | |
784 | * contained within the displayable area of the screen image | |
785 | * (frame buffer). | |
786 | */ | |
213a8434 | 787 | REG_WRITE(map->size, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16) |
026abc33 KS |
788 | | (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1)); |
789 | /* Set the CRTC with encoder mode. */ | |
213a8434 | 790 | REG_WRITE(map->src, ((mode->crtc_hdisplay - 1) << 16) |
026abc33 KS |
791 | | (mode->crtc_vdisplay - 1)); |
792 | } else { | |
213a8434 | 793 | REG_WRITE(map->size, |
026abc33 KS |
794 | ((mode->crtc_vdisplay - 1) << 16) | |
795 | (mode->crtc_hdisplay - 1)); | |
213a8434 | 796 | REG_WRITE(map->src, |
026abc33 KS |
797 | ((mode->crtc_hdisplay - 1) << 16) | |
798 | (mode->crtc_vdisplay - 1)); | |
799 | } | |
800 | ||
213a8434 | 801 | REG_WRITE(map->pos, 0); |
026abc33 | 802 | |
367e4408 | 803 | if (gma_encoder) |
a69ac9ea | 804 | drm_object_property_get_value(&connector->base, |
026abc33 KS |
805 | dev->mode_config.scaling_mode_property, &scalingType); |
806 | ||
807 | if (scalingType == DRM_MODE_SCALE_NO_SCALE) { | |
808 | /* Medfield doesn't have register support for centering so we | |
809 | * need to mess with the h/vblank and h/vsync start and ends | |
810 | * to get centering | |
811 | */ | |
812 | int offsetX = 0, offsetY = 0; | |
813 | ||
814 | offsetX = (adjusted_mode->crtc_hdisplay - | |
815 | mode->crtc_hdisplay) / 2; | |
816 | offsetY = (adjusted_mode->crtc_vdisplay - | |
817 | mode->crtc_vdisplay) / 2; | |
818 | ||
213a8434 | 819 | REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) | |
026abc33 | 820 | ((adjusted_mode->crtc_htotal - 1) << 16)); |
213a8434 | 821 | REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) | |
026abc33 | 822 | ((adjusted_mode->crtc_vtotal - 1) << 16)); |
213a8434 | 823 | REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - |
026abc33 KS |
824 | offsetX - 1) | |
825 | ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16)); | |
213a8434 | 826 | REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - |
026abc33 KS |
827 | offsetX - 1) | |
828 | ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16)); | |
213a8434 | 829 | REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - |
026abc33 KS |
830 | offsetY - 1) | |
831 | ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16)); | |
213a8434 | 832 | REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - |
026abc33 KS |
833 | offsetY - 1) | |
834 | ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16)); | |
835 | } else { | |
213a8434 | 836 | REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) | |
026abc33 | 837 | ((adjusted_mode->crtc_htotal - 1) << 16)); |
213a8434 | 838 | REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) | |
026abc33 | 839 | ((adjusted_mode->crtc_vtotal - 1) << 16)); |
213a8434 | 840 | REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) | |
026abc33 | 841 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); |
213a8434 | 842 | REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) | |
026abc33 | 843 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); |
213a8434 | 844 | REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) | |
026abc33 | 845 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); |
213a8434 | 846 | REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) | |
026abc33 KS |
847 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); |
848 | } | |
849 | ||
850 | /* Flush the plane changes */ | |
851 | { | |
45fe734c | 852 | const struct drm_crtc_helper_funcs *crtc_funcs = |
026abc33 KS |
853 | crtc->helper_private; |
854 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); | |
855 | } | |
856 | ||
857 | /* setup pipeconf */ | |
213a8434 | 858 | dev_priv->pipeconf[pipe] = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */ |
026abc33 KS |
859 | |
860 | /* Set up the display plane register */ | |
213a8434 AC |
861 | dev_priv->dspcntr[pipe] = REG_READ(map->cntr); |
862 | dev_priv->dspcntr[pipe] |= pipe << DISPPLANE_SEL_PIPE_POS; | |
863 | dev_priv->dspcntr[pipe] |= DISPLAY_PLANE_ENABLE; | |
026abc33 KS |
864 | |
865 | if (is_mipi2) | |
866 | goto mrst_crtc_mode_set_exit; | |
867 | clk = adjusted_mode->clock; | |
868 | ||
869 | if (is_hdmi) { | |
870 | if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) { | |
871 | refclk = 19200; | |
872 | ||
873 | if (is_mipi || is_mipi2) | |
874 | clk_n = 1, clk_p2 = 8; | |
875 | else if (is_hdmi) | |
876 | clk_n = 1, clk_p2 = 10; | |
877 | } else if (ksel == KSEL_BYPASS_25) { | |
878 | refclk = 25000; | |
879 | ||
880 | if (is_mipi || is_mipi2) | |
881 | clk_n = 1, clk_p2 = 8; | |
882 | else if (is_hdmi) | |
883 | clk_n = 1, clk_p2 = 10; | |
884 | } else if ((ksel == KSEL_BYPASS_83_100) && | |
885 | dev_priv->core_freq == 166) { | |
886 | refclk = 83000; | |
887 | ||
888 | if (is_mipi || is_mipi2) | |
889 | clk_n = 4, clk_p2 = 8; | |
890 | else if (is_hdmi) | |
891 | clk_n = 4, clk_p2 = 10; | |
892 | } else if ((ksel == KSEL_BYPASS_83_100) && | |
893 | (dev_priv->core_freq == 100 || | |
894 | dev_priv->core_freq == 200)) { | |
895 | refclk = 100000; | |
896 | if (is_mipi || is_mipi2) | |
897 | clk_n = 4, clk_p2 = 8; | |
898 | else if (is_hdmi) | |
899 | clk_n = 4, clk_p2 = 10; | |
900 | } | |
901 | ||
902 | if (is_mipi) | |
903 | clk_byte = dev_priv->bpp / 8; | |
904 | else if (is_mipi2) | |
905 | clk_byte = dev_priv->bpp2 / 8; | |
906 | ||
907 | clk_tmp = clk * clk_n * clk_p2 * clk_byte; | |
908 | ||
909 | dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n", | |
910 | clk, clk_n, clk_p2); | |
911 | dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n", | |
912 | adjusted_mode->clock, clk_tmp); | |
913 | ||
914 | ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock); | |
915 | ||
916 | if (!ok) { | |
917 | DRM_ERROR | |
918 | ("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n"); | |
919 | } else { | |
920 | m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)]; | |
921 | ||
922 | dev_dbg(dev->dev, "dot clock = %d," | |
923 | "m = %d, p1 = %d, m_conv = %d.\n", | |
924 | clock.dot, clock.m, | |
925 | clock.p1, m_conv); | |
926 | } | |
927 | ||
213a8434 | 928 | dpll = REG_READ(map->dpll); |
026abc33 KS |
929 | |
930 | if (dpll & DPLL_VCO_ENABLE) { | |
931 | dpll &= ~DPLL_VCO_ENABLE; | |
213a8434 AC |
932 | REG_WRITE(map->dpll, dpll); |
933 | REG_READ(map->dpll); | |
026abc33 KS |
934 | |
935 | /* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */ | |
936 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | |
937 | udelay(500); | |
938 | ||
939 | /* reset M1, N1 & P1 */ | |
213a8434 | 940 | REG_WRITE(map->fp0, 0); |
026abc33 | 941 | dpll &= ~MDFLD_P1_MASK; |
213a8434 | 942 | REG_WRITE(map->dpll, dpll); |
026abc33 KS |
943 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ |
944 | udelay(500); | |
945 | } | |
946 | ||
947 | /* When ungating power of DPLL, needs to wait 0.5us before | |
948 | * enable the VCO */ | |
949 | if (dpll & MDFLD_PWR_GATE_EN) { | |
950 | dpll &= ~MDFLD_PWR_GATE_EN; | |
213a8434 | 951 | REG_WRITE(map->dpll, dpll); |
026abc33 KS |
952 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ |
953 | udelay(500); | |
954 | } | |
955 | dpll = 0; | |
956 | ||
957 | #if 0 /* FIXME revisit later */ | |
958 | if (ksel == KSEL_CRYSTAL_19 || ksel == KSEL_BYPASS_19 || | |
959 | ksel == KSEL_BYPASS_25) | |
960 | dpll &= ~MDFLD_INPUT_REF_SEL; | |
961 | else if (ksel == KSEL_BYPASS_83_100) | |
962 | dpll |= MDFLD_INPUT_REF_SEL; | |
963 | #endif /* FIXME revisit later */ | |
964 | ||
965 | if (is_hdmi) | |
966 | dpll |= MDFLD_VCO_SEL; | |
967 | ||
968 | fp = (clk_n / 2) << 16; | |
969 | fp |= m_conv; | |
970 | ||
971 | /* compute bitmask from p1 value */ | |
972 | dpll |= (1 << (clock.p1 - 2)) << 17; | |
973 | ||
974 | #if 0 /* 1080p30 & 720p */ | |
975 | dpll = 0x00050000; | |
976 | fp = 0x000001be; | |
977 | #endif | |
978 | #if 0 /* 480p */ | |
979 | dpll = 0x02010000; | |
980 | fp = 0x000000d2; | |
981 | #endif | |
982 | } else { | |
983 | #if 0 /*DBI_TPO_480x864*/ | |
984 | dpll = 0x00020000; | |
985 | fp = 0x00000156; | |
986 | #endif /* DBI_TPO_480x864 */ /* get from spec. */ | |
987 | ||
988 | dpll = 0x00800000; | |
989 | fp = 0x000000c1; | |
990 | } | |
991 | ||
213a8434 AC |
992 | REG_WRITE(map->fp0, fp); |
993 | REG_WRITE(map->dpll, dpll); | |
026abc33 KS |
994 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ |
995 | udelay(500); | |
996 | ||
997 | dpll |= DPLL_VCO_ENABLE; | |
213a8434 AC |
998 | REG_WRITE(map->dpll, dpll); |
999 | REG_READ(map->dpll); | |
026abc33 KS |
1000 | |
1001 | /* wait for DSI PLL to lock */ | |
1002 | while (timeout < 20000 && | |
213a8434 | 1003 | !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) { |
026abc33 KS |
1004 | udelay(150); |
1005 | timeout++; | |
1006 | } | |
1007 | ||
1008 | if (is_mipi) | |
1009 | goto mrst_crtc_mode_set_exit; | |
1010 | ||
1011 | dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi); | |
1012 | ||
213a8434 AC |
1013 | REG_WRITE(map->conf, dev_priv->pipeconf[pipe]); |
1014 | REG_READ(map->conf); | |
026abc33 KS |
1015 | |
1016 | /* Wait for for the pipe enable to take effect. */ | |
213a8434 | 1017 | REG_WRITE(map->cntr, dev_priv->dspcntr[pipe]); |
d1fa08f3 | 1018 | gma_wait_for_vblank(dev); |
026abc33 KS |
1019 | |
1020 | mrst_crtc_mode_set_exit: | |
1021 | ||
1022 | gma_power_end(dev); | |
1023 | ||
1024 | return 0; | |
1025 | } | |
1026 | ||
1027 | const struct drm_crtc_helper_funcs mdfld_helper_funcs = { | |
1028 | .dpms = mdfld_crtc_dpms, | |
026abc33 KS |
1029 | .mode_set = mdfld_crtc_mode_set, |
1030 | .mode_set_base = mdfld__intel_pipe_set_base, | |
d903b610 PJ |
1031 | .prepare = gma_crtc_prepare, |
1032 | .commit = gma_crtc_commit, | |
026abc33 | 1033 | }; |