diff options
-rw-r--r-- | drivers/gpu/drm/gma500/oaktrail.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/oaktrail_crtc.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/oaktrail_device.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/oaktrail_hdmi.c | 365 |
4 files changed, 365 insertions, 16 deletions
diff --git a/drivers/gpu/drm/gma500/oaktrail.h b/drivers/gpu/drm/gma500/oaktrail.h index f2f9f38a5362..30adbbe23024 100644 --- a/drivers/gpu/drm/gma500/oaktrail.h +++ b/drivers/gpu/drm/gma500/oaktrail.h | |||
@@ -249,3 +249,9 @@ extern void oaktrail_hdmi_i2c_exit(struct pci_dev *dev); | |||
249 | extern void oaktrail_hdmi_save(struct drm_device *dev); | 249 | extern void oaktrail_hdmi_save(struct drm_device *dev); |
250 | extern void oaktrail_hdmi_restore(struct drm_device *dev); | 250 | extern void oaktrail_hdmi_restore(struct drm_device *dev); |
251 | extern void oaktrail_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); | 251 | extern void oaktrail_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); |
252 | extern int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, | ||
253 | struct drm_display_mode *adjusted_mode, int x, int y, | ||
254 | struct drm_framebuffer *old_fb); | ||
255 | extern void oaktrail_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode); | ||
256 | |||
257 | |||
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c index cdafd2acc72f..4ec2962f7635 100644 --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c | |||
@@ -168,6 +168,11 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
168 | const struct psb_offset *map = &dev_priv->regmap[pipe]; | 168 | const struct psb_offset *map = &dev_priv->regmap[pipe]; |
169 | u32 temp; | 169 | u32 temp; |
170 | 170 | ||
171 | if (pipe == 1) { | ||
172 | oaktrail_crtc_hdmi_dpms(crtc, mode); | ||
173 | return; | ||
174 | } | ||
175 | |||
171 | if (!gma_power_begin(dev, true)) | 176 | if (!gma_power_begin(dev, true)) |
172 | return; | 177 | return; |
173 | 178 | ||
@@ -302,6 +307,9 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc, | |||
302 | uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; | 307 | uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; |
303 | struct drm_connector *connector; | 308 | struct drm_connector *connector; |
304 | 309 | ||
310 | if (pipe == 1) | ||
311 | return oaktrail_crtc_hdmi_mode_set(crtc, mode, adjusted_mode, x, y, old_fb); | ||
312 | |||
305 | if (!gma_power_begin(dev, true)) | 313 | if (!gma_power_begin(dev, true)) |
306 | return 0; | 314 | return 0; |
307 | 315 | ||
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c index 010b820744a5..08747fd7105c 100644 --- a/drivers/gpu/drm/gma500/oaktrail_device.c +++ b/drivers/gpu/drm/gma500/oaktrail_device.c | |||
@@ -544,7 +544,7 @@ const struct psb_ops oaktrail_chip_ops = { | |||
544 | .accel_2d = 1, | 544 | .accel_2d = 1, |
545 | .pipes = 2, | 545 | .pipes = 2, |
546 | .crtcs = 2, | 546 | .crtcs = 2, |
547 | .hdmi_mask = (1 << 0), | 547 | .hdmi_mask = (1 << 1), |
548 | .lvds_mask = (1 << 0), | 548 | .lvds_mask = (1 << 0), |
549 | .cursor_needs_phys = 0, | 549 | .cursor_needs_phys = 0, |
550 | .sgx_offset = MRST_SGX_OFFSET, | 550 | .sgx_offset = MRST_SGX_OFFSET, |
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index 69e51e903f35..f036f1fc161e 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c | |||
@@ -155,6 +155,345 @@ static void oaktrail_hdmi_audio_disable(struct drm_device *dev) | |||
155 | HDMI_READ(HDMI_HCR); | 155 | HDMI_READ(HDMI_HCR); |
156 | } | 156 | } |
157 | 157 | ||
158 | static void wait_for_vblank(struct drm_device *dev) | ||
159 | { | ||
160 | /* Wait for 20ms, i.e. one cycle at 50hz. */ | ||
161 | mdelay(20); | ||
162 | } | ||
163 | |||
164 | static unsigned int htotal_calculate(struct drm_display_mode *mode) | ||
165 | { | ||
166 | u32 htotal, new_crtc_htotal; | ||
167 | |||
168 | htotal = (mode->crtc_hdisplay - 1) | ((mode->crtc_htotal - 1) << 16); | ||
169 | |||
170 | /* | ||
171 | * 1024 x 768 new_crtc_htotal = 0x1024; | ||
172 | * 1280 x 1024 new_crtc_htotal = 0x0c34; | ||
173 | */ | ||
174 | new_crtc_htotal = (mode->crtc_htotal - 1) * 200 * 1000 / mode->clock; | ||
175 | |||
176 | DRM_DEBUG_KMS("new crtc htotal 0x%4x\n", new_crtc_htotal); | ||
177 | return (mode->crtc_hdisplay - 1) | (new_crtc_htotal << 16); | ||
178 | } | ||
179 | |||
180 | static void oaktrail_hdmi_find_dpll(struct drm_crtc *crtc, int target, | ||
181 | int refclk, struct oaktrail_hdmi_clock *best_clock) | ||
182 | { | ||
183 | int np_min, np_max, nr_min, nr_max; | ||
184 | int np, nr, nf; | ||
185 | |||
186 | np_min = DIV_ROUND_UP(oaktrail_hdmi_limit.vco.min, target * 10); | ||
187 | np_max = oaktrail_hdmi_limit.vco.max / (target * 10); | ||
188 | if (np_min < oaktrail_hdmi_limit.np.min) | ||
189 | np_min = oaktrail_hdmi_limit.np.min; | ||
190 | if (np_max > oaktrail_hdmi_limit.np.max) | ||
191 | np_max = oaktrail_hdmi_limit.np.max; | ||
192 | |||
193 | nr_min = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_max)); | ||
194 | nr_max = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_min)); | ||
195 | if (nr_min < oaktrail_hdmi_limit.nr.min) | ||
196 | nr_min = oaktrail_hdmi_limit.nr.min; | ||
197 | if (nr_max > oaktrail_hdmi_limit.nr.max) | ||
198 | nr_max = oaktrail_hdmi_limit.nr.max; | ||
199 | |||
200 | np = DIV_ROUND_UP((refclk * 1000), (target * 10 * nr_max)); | ||
201 | nr = DIV_ROUND_UP((refclk * 1000), (target * 10 * np)); | ||
202 | nf = DIV_ROUND_CLOSEST((target * 10 * np * nr), refclk); | ||
203 | DRM_DEBUG_KMS("np, nr, nf %d %d %d\n", np, nr, nf); | ||
204 | |||
205 | /* | ||
206 | * 1024 x 768 np = 1; nr = 0x26; nf = 0x0fd8000; | ||
207 | * 1280 x 1024 np = 1; nr = 0x17; nf = 0x1034000; | ||
208 | */ | ||
209 | best_clock->np = np; | ||
210 | best_clock->nr = nr - 1; | ||
211 | best_clock->nf = (nf << 14); | ||
212 | } | ||
213 | |||
214 | static void scu_busy_loop(void __iomem *scu_base) | ||
215 | { | ||
216 | u32 status = 0; | ||
217 | u32 loop_count = 0; | ||
218 | |||
219 | status = readl(scu_base + 0x04); | ||
220 | while (status & 1) { | ||
221 | udelay(1); /* scu processing time is in few u secods */ | ||
222 | status = readl(scu_base + 0x04); | ||
223 | loop_count++; | ||
224 | /* break if scu doesn't reset busy bit after huge retry */ | ||
225 | if (loop_count > 1000) { | ||
226 | DRM_DEBUG_KMS("SCU IPC timed out"); | ||
227 | return; | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * You don't want to know, you really really don't want to know.... | ||
234 | * | ||
235 | * This is magic. However it's safe magic because of the way the platform | ||
236 | * works and it is necessary magic. | ||
237 | */ | ||
238 | static void oaktrail_hdmi_reset(struct drm_device *dev) | ||
239 | { | ||
240 | void __iomem *base; | ||
241 | unsigned long scu_ipc_mmio = 0xff11c000UL; | ||
242 | int scu_len = 1024; | ||
243 | |||
244 | base = ioremap((resource_size_t)scu_ipc_mmio, scu_len); | ||
245 | if (base == NULL) { | ||
246 | DRM_ERROR("failed to map scu mmio\n"); | ||
247 | return; | ||
248 | } | ||
249 | |||
250 | /* scu ipc: assert hdmi controller reset */ | ||
251 | writel(0xff11d118, base + 0x0c); | ||
252 | writel(0x7fffffdf, base + 0x80); | ||
253 | writel(0x42005, base + 0x0); | ||
254 | scu_busy_loop(base); | ||
255 | |||
256 | /* scu ipc: de-assert hdmi controller reset */ | ||
257 | writel(0xff11d118, base + 0x0c); | ||
258 | writel(0x7fffffff, base + 0x80); | ||
259 | writel(0x42005, base + 0x0); | ||
260 | scu_busy_loop(base); | ||
261 | |||
262 | iounmap(base); | ||
263 | } | ||
264 | |||
265 | int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, | ||
266 | struct drm_display_mode *mode, | ||
267 | struct drm_display_mode *adjusted_mode, | ||
268 | int x, int y, | ||
269 | struct drm_framebuffer *old_fb) | ||
270 | { | ||
271 | struct drm_device *dev = crtc->dev; | ||
272 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
273 | struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; | ||
274 | int pipe = 1; | ||
275 | int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; | ||
276 | int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; | ||
277 | int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; | ||
278 | int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; | ||
279 | int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; | ||
280 | int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; | ||
281 | int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; | ||
282 | int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; | ||
283 | int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; | ||
284 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
285 | int refclk; | ||
286 | struct oaktrail_hdmi_clock clock; | ||
287 | u32 dspcntr, pipeconf, dpll, temp; | ||
288 | int dspcntr_reg = DSPBCNTR; | ||
289 | |||
290 | if (!gma_power_begin(dev, true)) | ||
291 | return 0; | ||
292 | |||
293 | /* Disable the VGA plane that we never use */ | ||
294 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
295 | |||
296 | /* Disable dpll if necessary */ | ||
297 | dpll = REG_READ(DPLL_CTRL); | ||
298 | if ((dpll & DPLL_PWRDN) == 0) { | ||
299 | REG_WRITE(DPLL_CTRL, dpll | (DPLL_PWRDN | DPLL_RESET)); | ||
300 | REG_WRITE(DPLL_DIV_CTRL, 0x00000000); | ||
301 | REG_WRITE(DPLL_STATUS, 0x1); | ||
302 | } | ||
303 | udelay(150); | ||
304 | |||
305 | /* Reset controller */ | ||
306 | oaktrail_hdmi_reset(dev); | ||
307 | |||
308 | /* program and enable dpll */ | ||
309 | refclk = 25000; | ||
310 | oaktrail_hdmi_find_dpll(crtc, adjusted_mode->clock, refclk, &clock); | ||
311 | |||
312 | /* Set the DPLL */ | ||
313 | dpll = REG_READ(DPLL_CTRL); | ||
314 | dpll &= ~DPLL_PDIV_MASK; | ||
315 | dpll &= ~(DPLL_PWRDN | DPLL_RESET); | ||
316 | REG_WRITE(DPLL_CTRL, 0x00000008); | ||
317 | REG_WRITE(DPLL_DIV_CTRL, ((clock.nf << 6) | clock.nr)); | ||
318 | REG_WRITE(DPLL_ADJUST, ((clock.nf >> 14) - 1)); | ||
319 | REG_WRITE(DPLL_CTRL, (dpll | (clock.np << DPLL_PDIV_SHIFT) | DPLL_ENSTAT | DPLL_DITHEN)); | ||
320 | REG_WRITE(DPLL_UPDATE, 0x80000000); | ||
321 | REG_WRITE(DPLL_CLK_ENABLE, 0x80050102); | ||
322 | udelay(150); | ||
323 | |||
324 | /* configure HDMI */ | ||
325 | HDMI_WRITE(0x1004, 0x1fd); | ||
326 | HDMI_WRITE(0x2000, 0x1); | ||
327 | HDMI_WRITE(0x2008, 0x0); | ||
328 | HDMI_WRITE(0x3130, 0x8); | ||
329 | HDMI_WRITE(0x101c, 0x1800810); | ||
330 | |||
331 | temp = htotal_calculate(adjusted_mode); | ||
332 | REG_WRITE(htot_reg, temp); | ||
333 | REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
334 | REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
335 | REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
336 | REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
337 | REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
338 | REG_WRITE(pipesrc_reg, ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1)); | ||
339 | |||
340 | REG_WRITE(PCH_HTOTAL_B, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
341 | REG_WRITE(PCH_HBLANK_B, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
342 | REG_WRITE(PCH_HSYNC_B, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
343 | REG_WRITE(PCH_VTOTAL_B, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
344 | REG_WRITE(PCH_VBLANK_B, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
345 | REG_WRITE(PCH_VSYNC_B, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
346 | REG_WRITE(PCH_PIPEBSRC, ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1)); | ||
347 | |||
348 | temp = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start; | ||
349 | HDMI_WRITE(HDMI_HBLANK_A, ((adjusted_mode->crtc_hdisplay - 1) << 16) | temp); | ||
350 | |||
351 | REG_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); | ||
352 | REG_WRITE(dsppos_reg, 0); | ||
353 | |||
354 | /* Flush the plane changes */ | ||
355 | { | ||
356 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
357 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); | ||
358 | } | ||
359 | |||
360 | /* Set up the display plane register */ | ||
361 | dspcntr = REG_READ(dspcntr_reg); | ||
362 | dspcntr |= DISPPLANE_GAMMA_ENABLE; | ||
363 | dspcntr |= DISPPLANE_SEL_PIPE_B; | ||
364 | dspcntr |= DISPLAY_PLANE_ENABLE; | ||
365 | |||
366 | /* setup pipeconf */ | ||
367 | pipeconf = REG_READ(pipeconf_reg); | ||
368 | pipeconf |= PIPEACONF_ENABLE; | ||
369 | |||
370 | REG_WRITE(pipeconf_reg, pipeconf); | ||
371 | REG_READ(pipeconf_reg); | ||
372 | |||
373 | REG_WRITE(PCH_PIPEBCONF, pipeconf); | ||
374 | REG_READ(PCH_PIPEBCONF); | ||
375 | wait_for_vblank(dev); | ||
376 | |||
377 | REG_WRITE(dspcntr_reg, dspcntr); | ||
378 | wait_for_vblank(dev); | ||
379 | |||
380 | gma_power_end(dev); | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | void oaktrail_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode) | ||
386 | { | ||
387 | struct drm_device *dev = crtc->dev; | ||
388 | u32 temp; | ||
389 | |||
390 | DRM_DEBUG_KMS("%s %d\n", __func__, mode); | ||
391 | |||
392 | switch (mode) { | ||
393 | case DRM_MODE_DPMS_OFF: | ||
394 | REG_WRITE(VGACNTRL, 0x80000000); | ||
395 | |||
396 | /* Disable plane */ | ||
397 | temp = REG_READ(DSPBCNTR); | ||
398 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
399 | REG_WRITE(DSPBCNTR, temp & ~DISPLAY_PLANE_ENABLE); | ||
400 | REG_READ(DSPBCNTR); | ||
401 | /* Flush the plane changes */ | ||
402 | REG_WRITE(DSPBSURF, REG_READ(DSPBSURF)); | ||
403 | REG_READ(DSPBSURF); | ||
404 | } | ||
405 | |||
406 | /* Disable pipe B */ | ||
407 | temp = REG_READ(PIPEBCONF); | ||
408 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
409 | REG_WRITE(PIPEBCONF, temp & ~PIPEACONF_ENABLE); | ||
410 | REG_READ(PIPEBCONF); | ||
411 | } | ||
412 | |||
413 | /* Disable LNW Pipes, etc */ | ||
414 | temp = REG_READ(PCH_PIPEBCONF); | ||
415 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
416 | REG_WRITE(PCH_PIPEBCONF, temp & ~PIPEACONF_ENABLE); | ||
417 | REG_READ(PCH_PIPEBCONF); | ||
418 | } | ||
419 | |||
420 | /* wait for pipe off */ | ||
421 | udelay(150); | ||
422 | |||
423 | /* Disable dpll */ | ||
424 | temp = REG_READ(DPLL_CTRL); | ||
425 | if ((temp & DPLL_PWRDN) == 0) { | ||
426 | REG_WRITE(DPLL_CTRL, temp | (DPLL_PWRDN | DPLL_RESET)); | ||
427 | REG_WRITE(DPLL_STATUS, 0x1); | ||
428 | } | ||
429 | |||
430 | /* wait for dpll off */ | ||
431 | udelay(150); | ||
432 | |||
433 | break; | ||
434 | case DRM_MODE_DPMS_ON: | ||
435 | case DRM_MODE_DPMS_STANDBY: | ||
436 | case DRM_MODE_DPMS_SUSPEND: | ||
437 | /* Enable dpll */ | ||
438 | temp = REG_READ(DPLL_CTRL); | ||
439 | if ((temp & DPLL_PWRDN) != 0) { | ||
440 | REG_WRITE(DPLL_CTRL, temp & ~(DPLL_PWRDN | DPLL_RESET)); | ||
441 | temp = REG_READ(DPLL_CLK_ENABLE); | ||
442 | REG_WRITE(DPLL_CLK_ENABLE, temp | DPLL_EN_DISP | DPLL_SEL_HDMI | DPLL_EN_HDMI); | ||
443 | REG_READ(DPLL_CLK_ENABLE); | ||
444 | } | ||
445 | /* wait for dpll warm up */ | ||
446 | udelay(150); | ||
447 | |||
448 | /* Enable pipe B */ | ||
449 | temp = REG_READ(PIPEBCONF); | ||
450 | if ((temp & PIPEACONF_ENABLE) == 0) { | ||
451 | REG_WRITE(PIPEBCONF, temp | PIPEACONF_ENABLE); | ||
452 | REG_READ(PIPEBCONF); | ||
453 | } | ||
454 | |||
455 | /* Enable LNW Pipe B */ | ||
456 | temp = REG_READ(PCH_PIPEBCONF); | ||
457 | if ((temp & PIPEACONF_ENABLE) == 0) { | ||
458 | REG_WRITE(PCH_PIPEBCONF, temp | PIPEACONF_ENABLE); | ||
459 | REG_READ(PCH_PIPEBCONF); | ||
460 | } | ||
461 | |||
462 | wait_for_vblank(dev); | ||
463 | |||
464 | /* Enable plane */ | ||
465 | temp = REG_READ(DSPBCNTR); | ||
466 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
467 | REG_WRITE(DSPBCNTR, temp | DISPLAY_PLANE_ENABLE); | ||
468 | /* Flush the plane changes */ | ||
469 | REG_WRITE(DSPBSURF, REG_READ(DSPBSURF)); | ||
470 | REG_READ(DSPBSURF); | ||
471 | } | ||
472 | |||
473 | psb_intel_crtc_load_lut(crtc); | ||
474 | } | ||
475 | |||
476 | /* DSPARB */ | ||
477 | REG_WRITE(DSPARB, 0x00003fbf); | ||
478 | |||
479 | /* FW1 */ | ||
480 | REG_WRITE(0x70034, 0x3f880a0a); | ||
481 | |||
482 | /* FW2 */ | ||
483 | REG_WRITE(0x70038, 0x0b060808); | ||
484 | |||
485 | /* FW4 */ | ||
486 | REG_WRITE(0x70050, 0x08030404); | ||
487 | |||
488 | /* FW5 */ | ||
489 | REG_WRITE(0x70054, 0x04040404); | ||
490 | |||
491 | /* LNC Chicken Bits - Squawk! */ | ||
492 | REG_WRITE(0x70400, 0x4000); | ||
493 | |||
494 | return; | ||
495 | } | ||
496 | |||
158 | static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode) | 497 | static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode) |
159 | { | 498 | { |
160 | static int dpms_mode = -1; | 499 | static int dpms_mode = -1; |
@@ -233,13 +572,15 @@ static const unsigned char raw_edid[] = { | |||
233 | 572 | ||
234 | static int oaktrail_hdmi_get_modes(struct drm_connector *connector) | 573 | static int oaktrail_hdmi_get_modes(struct drm_connector *connector) |
235 | { | 574 | { |
236 | struct drm_device *dev = connector->dev; | ||
237 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
238 | struct i2c_adapter *i2c_adap; | 575 | struct i2c_adapter *i2c_adap; |
239 | struct edid *edid; | 576 | struct edid *edid; |
240 | struct drm_display_mode *mode, *t; | 577 | int ret = 0; |
241 | int i = 0, ret = 0; | ||
242 | 578 | ||
579 | /* | ||
580 | * FIXME: We need to figure this lot out. In theory we can | ||
581 | * read the EDID somehow but I've yet to find working reference | ||
582 | * code. | ||
583 | */ | ||
243 | i2c_adap = i2c_get_adapter(3); | 584 | i2c_adap = i2c_get_adapter(3); |
244 | if (i2c_adap == NULL) { | 585 | if (i2c_adap == NULL) { |
245 | DRM_ERROR("No ddc adapter available!\n"); | 586 | DRM_ERROR("No ddc adapter available!\n"); |
@@ -253,17 +594,7 @@ static int oaktrail_hdmi_get_modes(struct drm_connector *connector) | |||
253 | drm_mode_connector_update_edid_property(connector, edid); | 594 | drm_mode_connector_update_edid_property(connector, edid); |
254 | ret = drm_add_edid_modes(connector, edid); | 595 | ret = drm_add_edid_modes(connector, edid); |
255 | } | 596 | } |
256 | 597 | return ret; | |
257 | /* | ||
258 | * prune modes that require frame buffer bigger than stolen mem | ||
259 | */ | ||
260 | list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { | ||
261 | if ((mode->hdisplay * mode->vdisplay * 4) >= dev_priv->vram_stolen_size) { | ||
262 | i++; | ||
263 | drm_mode_remove(connector, mode); | ||
264 | } | ||
265 | } | ||
266 | return ret - i; | ||
267 | } | 598 | } |
268 | 599 | ||
269 | static void oaktrail_hdmi_mode_set(struct drm_encoder *encoder, | 600 | static void oaktrail_hdmi_mode_set(struct drm_encoder *encoder, |
@@ -349,6 +680,7 @@ void oaktrail_hdmi_init(struct drm_device *dev, | |||
349 | connector->interlace_allowed = false; | 680 | connector->interlace_allowed = false; |
350 | connector->doublescan_allowed = false; | 681 | connector->doublescan_allowed = false; |
351 | drm_sysfs_connector_add(connector); | 682 | drm_sysfs_connector_add(connector); |
683 | dev_info(dev->dev, "HDMI initialised.\n"); | ||
352 | 684 | ||
353 | return; | 685 | return; |
354 | 686 | ||
@@ -403,6 +735,9 @@ void oaktrail_hdmi_setup(struct drm_device *dev) | |||
403 | 735 | ||
404 | dev_priv->hdmi_priv = hdmi_dev; | 736 | dev_priv->hdmi_priv = hdmi_dev; |
405 | oaktrail_hdmi_audio_disable(dev); | 737 | oaktrail_hdmi_audio_disable(dev); |
738 | |||
739 | dev_info(dev->dev, "HDMI hardware present.\n"); | ||
740 | |||
406 | return; | 741 | return; |
407 | 742 | ||
408 | free: | 743 | free: |