aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/EDID/1600x1200.S44
-rw-r--r--Documentation/EDID/HOWTO.txt12
-rw-r--r--Documentation/devicetree/bindings/drm/exynos/g2d.txt22
-rw-r--r--arch/arm/mach-omap2/board-2430sdp.c2
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c2
-rw-r--r--arch/arm/mach-omap2/board-am3517evm.c3
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c3
-rw-r--r--arch/arm/mach-omap2/board-devkit8000.c3
-rw-r--r--arch/arm/mach-omap2/board-h4.c2
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c2
-rw-r--r--arch/arm/mach-omap2/board-ldp.c2
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c2
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c2
-rw-r--r--arch/arm/mach-omap2/board-omap3stalker.c3
-rw-r--r--arch/arm/mach-omap2/board-overo.c3
-rw-r--r--arch/arm/mach-omap2/dss-common.c4
-rw-r--r--drivers/gpu/Makefile1
-rw-r--r--drivers/gpu/drm/Kconfig4
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h2
-rw-r--r--drivers/gpu/drm/ast/ast_fb.c43
-rw-r--r--drivers/gpu/drm/ast/ast_ttm.c2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.h2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c38
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_ttm.c2
-rw-r--r--drivers/gpu/drm/drm_cache.c7
-rw-r--r--drivers/gpu/drm/drm_crtc.c411
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c3
-rw-r--r--drivers/gpu/drm/drm_drv.c9
-rw-r--r--drivers/gpu/drm/drm_edid.c279
-rw-r--r--drivers/gpu/drm/drm_edid_load.c21
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c23
-rw-r--r--drivers/gpu/drm/drm_gem.c4
-rw-r--r--drivers/gpu/drm/drm_modes.c22
-rw-r--r--drivers/gpu/drm/drm_pci.c10
-rw-r--r--drivers/gpu/drm/drm_prime.c99
-rw-r--r--drivers/gpu/drm/drm_vm.c1
-rw-r--r--drivers/gpu/drm/exynos/Kconfig6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_connector.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c9
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c273
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c39
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c54
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.h3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c27
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c712
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c22
-rw-r--r--drivers/gpu/drm/exynos/regs-fimc.h7
-rw-r--r--drivers/gpu/drm/gma500/Kconfig13
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_crt.c1
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_hdmi.c1
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c6
-rw-r--r--drivers/gpu/drm/gma500/gtt.c52
-rw-r--r--drivers/gpu/drm/gma500/gtt.h2
-rw-r--r--drivers/gpu/drm/gma500/intel_bios.c3
-rw-r--r--drivers/gpu/drm/gma500/intel_bios.h6
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_output.c7
-rw-r--r--drivers/gpu/drm/gma500/power.c17
-rw-r--r--drivers/gpu/drm/gma500/power.h3
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.c3
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h1
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.c154
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.h3
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_drv.h8
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_reg.h1
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_sdvo.c33
-rw-r--r--drivers/gpu/drm/gma500/psb_irq.c2
-rw-r--r--drivers/gpu/drm/gma500/psb_irq.h6
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c433
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c90
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c206
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h94
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c135
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c7
-rw-r--r--drivers/gpu/drm/i915/i915_gem_dmabuf.c18
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c36
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c262
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c65
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c33
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c659
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h293
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c15
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c27
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c9
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h4
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c22
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c70
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1535
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c526
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h155
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c13
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c8
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c166
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c4
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c49
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c49
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c245
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c131
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c243
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c16
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h8
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_fb.c55
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c31
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c7
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c4
-rw-r--r--drivers/gpu/drm/nouveau/Makefile26
-rw-r--r--drivers/gpu/drm/nouveau/core/core/client.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/core/engine.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/core/event.c12
-rw-r--r--drivers/gpu/drm/nouveau/core/core/object.c19
-rw-r--r--drivers/gpu/drm/nouveau/core/core/parent.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/base.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/base.c)186
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv04.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/nv04.c)2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv10.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/nv10.c)2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv20.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/nv20.c)2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv30.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/nv30.c)2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv40.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/nv40.c)2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv50.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/nv50.c)20
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nvc0.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c)30
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nve0.c (renamed from drivers/gpu/drm/nouveau/core/subdev/device/nve0.c)36
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dport.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c89
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/base.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c18
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c22
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c51
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c13
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc5
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv20.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv25.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv30.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv34.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv35.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv40.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv50.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c31
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nve0.c230
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nvc0.c29
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/class.h12
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/device.h6
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/parent.h4
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/device.h (renamed from drivers/gpu/drm/nouveau/core/include/subdev/device.h)1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/disp.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/fifo.h3
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/graph.h4
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mc.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/therm.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/os.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c22
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c14
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/init.c56
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c72
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/base.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c20
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c12
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c129
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/base.c60
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c175
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c221
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/priv.h3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/temp.c14
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c13
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c58
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/Makefile10
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/arb.c (renamed from drivers/gpu/drm/nouveau/nouveau_calc.c)2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c (renamed from drivers/gpu/drm/nouveau/nv04_crtc.c)5
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/cursor.c (renamed from drivers/gpu/drm/nouveau/nv04_cursor.c)3
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/dac.c (renamed from drivers/gpu/drm/nouveau/nv04_dac.c)2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/dfp.c (renamed from drivers/gpu/drm/nouveau/nv04_dfp.c)2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.c (renamed from drivers/gpu/drm/nouveau/nv04_display.c)2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.h (renamed from drivers/gpu/drm/nouveau/nv04_display.h)0
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/hw.c (renamed from drivers/gpu/drm/nouveau/nouveau_hw.c)2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/hw.h (renamed from drivers/gpu/drm/nouveau/nouveau_hw.h)3
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/nvreg.h (renamed from drivers/gpu/drm/nouveau/nvreg.h)0
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c (renamed from drivers/gpu/drm/nouveau/nv17_tv_modes.c)4
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv04.c (renamed from drivers/gpu/drm/nouveau/nv04_tv.c)2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv17.c (renamed from drivers/gpu/drm/nouveau/nv17_tv.c)4
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv17.h (renamed from drivers/gpu/drm/nouveau/nv17_tv.h)0
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_backlight.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c26
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h13
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c76
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.h11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c25
-rw-r--r--drivers/gpu/drm/nouveau/nv04_pm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv40_pm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.c27
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c21
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c165
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h38
-rw-r--r--drivers/gpu/drm/omapdrm/omap_encoder.c24
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c3
-rw-r--r--drivers/gpu/drm/omapdrm/omap_irq.c17
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c6
-rw-r--r--drivers/gpu/drm/qxl/Kconfig10
-rw-r--r--drivers/gpu/drm/qxl/Makefile9
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c685
-rw-r--r--drivers/gpu/drm/qxl/qxl_debugfs.c141
-rw-r--r--drivers/gpu/drm/qxl/qxl_dev.h879
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c982
-rw-r--r--drivers/gpu/drm/qxl/qxl_draw.c390
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c145
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h566
-rw-r--r--drivers/gpu/drm/qxl/qxl_dumb.c93
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c567
-rw-r--r--drivers/gpu/drm/qxl/qxl_fence.c97
-rw-r--r--drivers/gpu/drm/qxl/qxl_gem.c149
-rw-r--r--drivers/gpu/drm/qxl/qxl_image.c176
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c411
-rw-r--r--drivers/gpu/drm/qxl/qxl_irq.c97
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c302
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c365
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.h112
-rw-r--r--drivers/gpu/drm/qxl/qxl_release.c304
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c581
-rw-r--r--drivers/gpu/drm/radeon/Makefile2
-rw-r--r--drivers/gpu/drm/radeon/atom.c6
-rw-r--r--drivers/gpu/drm/radeon/atombios.h2
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c3
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c17
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c1187
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c169
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h2
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h48
-rw-r--r--drivers/gpu/drm/radeon/ni.c414
-rw-r--r--drivers/gpu/drm/radeon/nid.h21
-rw-r--r--drivers/gpu/drm/radeon/r100.c77
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h2
-rw-r--r--drivers/gpu/drm/radeon/r600.c404
-rw-r--r--drivers/gpu/drm/radeon/r600_audio.c64
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c150
-rw-r--r--drivers/gpu/drm/radeon/r600d.h72
-rw-r--r--drivers/gpu/drm/radeon/radeon.h94
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c100
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h28
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c132
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c83
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c56
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c20
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c50
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c187
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h23
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c27
-rw-r--r--drivers/gpu/drm/radeon/radeon_sa.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c72
-rw-r--r--drivers/gpu/drm/radeon/radeon_uvd.c831
-rw-r--r--drivers/gpu/drm/radeon/rs600.c52
-rw-r--r--drivers/gpu/drm/radeon/rs690.c23
-rw-r--r--drivers/gpu/drm/radeon/rs690d.h3
-rw-r--r--drivers/gpu/drm/radeon/rv515.c56
-rw-r--r--drivers/gpu/drm/radeon/rv770.c909
-rw-r--r--drivers/gpu/drm/radeon/rv770d.h43
-rw-r--r--drivers/gpu/drm/radeon/si.c979
-rw-r--r--drivers/gpu/drm/radeon/sid.h40
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/tegra/Makefile7
-rw-r--r--drivers/gpu/drm/tegra/drm.c217
-rw-r--r--drivers/gpu/drm/tegra/fb.c52
-rw-r--r--drivers/gpu/drm/tegra/host1x.c327
-rw-r--r--drivers/gpu/drm/tilcdc/Makefile5
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c9
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_panel.c3
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_slave.c1
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_tfp410.c1
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c13
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c4
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c2
-rw-r--r--drivers/gpu/drm/udl/udl_gem.c4
-rw-r--r--drivers/gpu/host1x/Kconfig24
-rw-r--r--drivers/gpu/host1x/Makefile20
-rw-r--r--drivers/gpu/host1x/cdma.c491
-rw-r--r--drivers/gpu/host1x/cdma.h100
-rw-r--r--drivers/gpu/host1x/channel.c126
-rw-r--r--drivers/gpu/host1x/channel.h52
-rw-r--r--drivers/gpu/host1x/debug.c210
-rw-r--r--drivers/gpu/host1x/debug.h51
-rw-r--r--drivers/gpu/host1x/dev.c246
-rw-r--r--drivers/gpu/host1x/dev.h308
-rw-r--r--drivers/gpu/host1x/drm/Kconfig (renamed from drivers/gpu/drm/tegra/Kconfig)20
-rw-r--r--drivers/gpu/host1x/drm/dc.c (renamed from drivers/gpu/drm/tegra/dc.c)31
-rw-r--r--drivers/gpu/host1x/drm/dc.h (renamed from drivers/gpu/drm/tegra/dc.h)0
-rw-r--r--drivers/gpu/host1x/drm/drm.c640
-rw-r--r--drivers/gpu/host1x/drm/drm.h (renamed from drivers/gpu/drm/tegra/drm.h)68
-rw-r--r--drivers/gpu/host1x/drm/fb.c374
-rw-r--r--drivers/gpu/host1x/drm/gem.c270
-rw-r--r--drivers/gpu/host1x/drm/gem.h59
-rw-r--r--drivers/gpu/host1x/drm/gr2d.c339
-rw-r--r--drivers/gpu/host1x/drm/hdmi.c (renamed from drivers/gpu/drm/tegra/hdmi.c)5
-rw-r--r--drivers/gpu/host1x/drm/hdmi.h (renamed from drivers/gpu/drm/tegra/hdmi.h)0
-rw-r--r--drivers/gpu/host1x/drm/output.c (renamed from drivers/gpu/drm/tegra/output.c)0
-rw-r--r--drivers/gpu/host1x/drm/rgb.c (renamed from drivers/gpu/drm/tegra/rgb.c)0
-rw-r--r--drivers/gpu/host1x/host1x.h30
-rw-r--r--drivers/gpu/host1x/host1x_bo.h87
-rw-r--r--drivers/gpu/host1x/host1x_client.h35
-rw-r--r--drivers/gpu/host1x/hw/Makefile6
-rw-r--r--drivers/gpu/host1x/hw/cdma_hw.c326
-rw-r--r--drivers/gpu/host1x/hw/channel_hw.c168
-rw-r--r--drivers/gpu/host1x/hw/debug_hw.c322
-rw-r--r--drivers/gpu/host1x/hw/host1x01.c42
-rw-r--r--drivers/gpu/host1x/hw/host1x01.h25
-rw-r--r--drivers/gpu/host1x/hw/host1x01_hardware.h143
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x01_channel.h120
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x01_sync.h243
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x01_uclass.h174
-rw-r--r--drivers/gpu/host1x/hw/intr_hw.c143
-rw-r--r--drivers/gpu/host1x/hw/syncpt_hw.c114
-rw-r--r--drivers/gpu/host1x/intr.c354
-rw-r--r--drivers/gpu/host1x/intr.h102
-rw-r--r--drivers/gpu/host1x/job.c603
-rw-r--r--drivers/gpu/host1x/job.h162
-rw-r--r--drivers/gpu/host1x/syncpt.c387
-rw-r--r--drivers/gpu/host1x/syncpt.h165
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/fbmem.c7
-rw-r--r--drivers/video/hdmi.c21
-rw-r--r--drivers/video/omap2/Makefile2
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c59
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c39
-rw-r--r--drivers/video/omap2/displays/panel-lgphilips-lb035q02.c58
-rw-r--r--drivers/video/omap2/displays/panel-n8x0.c95
-rw-r--r--drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c135
-rw-r--r--drivers/video/omap2/displays/panel-picodlp.c49
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c126
-rw-r--r--drivers/video/omap2/displays/panel-taal.c300
-rw-r--r--drivers/video/omap2/displays/panel-tfp410.c4
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c45
-rw-r--r--drivers/video/omap2/dss/apply.c15
-rw-r--r--drivers/video/omap2/dss/core.c5
-rw-r--r--drivers/video/omap2/dss/dispc.c176
-rw-r--r--drivers/video/omap2/dss/dispc.h1
-rw-r--r--drivers/video/omap2/dss/dpi.c351
-rw-r--r--drivers/video/omap2/dss/dsi.c1256
-rw-r--r--drivers/video/omap2/dss/dss.c181
-rw-r--r--drivers/video/omap2/dss/dss.h59
-rw-r--r--drivers/video/omap2/dss/dss_features.c8
-rw-r--r--drivers/video/omap2/dss/hdmi.c68
-rw-r--r--drivers/video/omap2/dss/output.c1
-rw-r--r--drivers/video/omap2/dss/rfbi.c34
-rw-r--r--drivers/video/omap2/dss/sdi.c103
-rw-r--r--drivers/video/omap2/dss/venc.c56
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c32
-rw-r--r--include/drm/drmP.h5
-rw-r--r--include/drm/drm_crtc.h23
-rw-r--r--include/drm/drm_edid.h9
-rw-r--r--include/drm/drm_fb_helper.h10
-rw-r--r--include/drm/drm_pciids.h5
-rw-r--r--include/drm/ttm/ttm_bo_driver.h4
-rw-r--r--include/linux/fb.h2
-rw-r--r--include/linux/pm.h13
-rw-r--r--include/linux/scatterlist.h28
-rw-r--r--include/trace/events/host1x.h253
-rw-r--r--include/uapi/drm/Kbuild2
-rw-r--r--include/uapi/drm/drm.h6
-rw-r--r--include/uapi/drm/drm_mode.h6
-rw-r--r--include/uapi/drm/qxl_drm.h152
-rw-r--r--include/uapi/drm/radeon_drm.h26
-rw-r--r--include/uapi/drm/tegra_drm.h136
-rw-r--r--include/video/omap-panel-data.h150
-rw-r--r--include/video/omap-panel-generic-dpi.h37
-rw-r--r--include/video/omap-panel-n8x0.h15
-rw-r--r--include/video/omap-panel-nokia-dsi.h32
-rw-r--r--include/video/omap-panel-picodlp.h23
-rw-r--r--include/video/omap-panel-tfp410.h35
-rw-r--r--include/video/omapdss.h86
-rw-r--r--kernel/power/console.c116
-rw-r--r--lib/scatterlist.c4
404 files changed, 29273 insertions, 7295 deletions
diff --git a/Documentation/EDID/1600x1200.S b/Documentation/EDID/1600x1200.S
new file mode 100644
index 00000000000..0ded64cfd1f
--- /dev/null
+++ b/Documentation/EDID/1600x1200.S
@@ -0,0 +1,44 @@
+/*
+ 1600x1200.S: EDID data set for standard 1600x1200 60 Hz monitor
+
+ Copyright (C) 2013 Carsten Emde <C.Emde@osadl.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 162000 /* kHz */
+#define XPIX 1600
+#define YPIX 1200
+#define XY_RATIO XY_RATIO_4_3
+#define XBLANK 560
+#define YBLANK 50
+#define XOFFSET 64
+#define XPULSE 192
+#define YOFFSET (63+1)
+#define YPULSE (63+3)
+#define DPI 72
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux UXGA"
+#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
+#define HSYNC_POL 1
+#define VSYNC_POL 1
+#define CRC 0x9d
+
+#include "edid.S"
diff --git a/Documentation/EDID/HOWTO.txt b/Documentation/EDID/HOWTO.txt
index 2d0a8f09475..7146db1d9e8 100644
--- a/Documentation/EDID/HOWTO.txt
+++ b/Documentation/EDID/HOWTO.txt
@@ -18,12 +18,12 @@ CONFIG_DRM_LOAD_EDID_FIRMWARE was introduced. It allows to provide an
individually prepared or corrected EDID data set in the /lib/firmware
directory from where it is loaded via the firmware interface. The code
(see drivers/gpu/drm/drm_edid_load.c) contains built-in data sets for
-commonly used screen resolutions (1024x768, 1280x1024, 1680x1050,
-1920x1080) as binary blobs, but the kernel source tree does not contain
-code to create these data. In order to elucidate the origin of the
-built-in binary EDID blobs and to facilitate the creation of individual
-data for a specific misbehaving monitor, commented sources and a
-Makefile environment are given here.
+commonly used screen resolutions (1024x768, 1280x1024, 1600x1200,
+1680x1050, 1920x1080) as binary blobs, but the kernel source tree does
+not contain code to create these data. In order to elucidate the origin
+of the built-in binary EDID blobs and to facilitate the creation of
+individual data for a specific misbehaving monitor, commented sources
+and a Makefile environment are given here.
To create binary EDID and C source code files from the existing data
material, simply type "make".
diff --git a/Documentation/devicetree/bindings/drm/exynos/g2d.txt b/Documentation/devicetree/bindings/drm/exynos/g2d.txt
deleted file mode 100644
index 1eb124d35a9..00000000000
--- a/Documentation/devicetree/bindings/drm/exynos/g2d.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-Samsung 2D Graphic Accelerator using DRM frame work
-
-Samsung FIMG2D is a graphics 2D accelerator which supports Bit Block Transfer.
-We set the drawing-context registers for configuring rendering parameters and
-then start rendering.
-This driver is for SOCs which contain G2D IPs with version 4.1.
-
-Required properties:
- -compatible:
- should be "samsung,exynos-g2d-41".
- -reg:
- physical base address of the controller and length
- of memory mapped region.
- -interrupts:
- interrupt combiner values.
-
-Example:
- g2d {
- compatible = "samsung,exynos-g2d-41";
- reg = <0x10850000 0x1000>;
- interrupts = <0 91 0>;
- };
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index cb0596b631c..5b86423c89f 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -38,7 +38,7 @@
#include "gpmc-smc91x.h"
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-data.h>
#include "mux.h"
#include "hsmmc.h"
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index ce812decfac..2612eeaa588 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -35,7 +35,7 @@
#include "common.h"
#include <linux/omap-dma.h>
#include <video/omapdss.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include "gpmc.h"
#include "gpmc-smc91x.h"
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index 9fb85908a61..1d6c2887250 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -35,8 +35,7 @@
#include "common.h"
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include "am35xx-emac.h"
#include "mux.h"
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index af2bb219e21..bccd3e51fec 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -41,8 +41,7 @@
#include <linux/platform_data/mtd-nand-omap2.h>
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include "common.h"
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 53056c3b083..12d2126a238 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -43,8 +43,7 @@
#include "gpmc.h"
#include <linux/platform_data/mtd-nand-omap2.h>
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/input/matrix_keypad.h>
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 5b4ec51c385..69c0acf5aa6 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -34,7 +34,7 @@
#include <asm/mach/map.h>
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-data.h>
#include "common.h"
#include "mux.h"
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index bf92678a01d..e979d48270c 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -31,7 +31,7 @@
#include <asm/mach/arch.h>
#include <video/omapdss.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
#include "common.h"
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index b12fe966a7b..8a8e505a0e9 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -41,7 +41,7 @@
#include "gpmc-smsc911x.h"
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-data.h>
#include "board-flash.h"
#include "mux.h"
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index c3558f93d42..0ce91af753f 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -43,7 +43,7 @@
#include <asm/mach/flash.h>
#include <video/omapdss.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include <linux/platform_data/mtd-nand-omap2.h>
#include "common.h"
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 48789e0bb91..233a0d528fc 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -51,7 +51,7 @@
#include "common.h"
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <video/omapdss.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include "soc.h"
#include "mux.h"
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index 95c10b3aa67..495b989f904 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -44,8 +44,7 @@
#include "gpmc.h"
#include <linux/platform_data/mtd-nand-omap2.h>
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 86bab51154e..630833235cb 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -47,8 +47,7 @@
#include <asm/mach/map.h>
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
#include "common.h"
#include "mux.h"
diff --git a/arch/arm/mach-omap2/dss-common.c b/arch/arm/mach-omap2/dss-common.c
index 4be5cfc81ab..9c49bbe825f 100644
--- a/arch/arm/mach-omap2/dss-common.c
+++ b/arch/arm/mach-omap2/dss-common.c
@@ -27,9 +27,7 @@
#include <linux/gpio.h>
#include <video/omapdss.h>
-#include <video/omap-panel-tfp410.h>
-#include <video/omap-panel-nokia-dsi.h>
-#include <video/omap-panel-picodlp.h>
+#include <video/omap-panel-data.h>
#include "soc.h"
#include "dss-common.h"
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
index 30879df3dae..d8a22c2a579 100644
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -1 +1,2 @@
obj-y += drm/ vga/
+obj-$(CONFIG_TEGRA_HOST1X) += host1x/
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 1e82882da9d..b16c50ee769 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -215,8 +215,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
source "drivers/gpu/drm/shmobile/Kconfig"
-source "drivers/gpu/drm/tegra/Kconfig"
-
source "drivers/gpu/drm/omapdrm/Kconfig"
source "drivers/gpu/drm/tilcdc/Kconfig"
+
+source "drivers/gpu/drm/qxl/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 0d59b24f8d2..1c9f2439600 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -49,7 +49,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
obj-$(CONFIG_DRM_UDL) += udl/
obj-$(CONFIG_DRM_AST) += ast/
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
-obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_DRM_TILCDC) += tilcdc/
+obj-$(CONFIG_DRM_QXL) += qxl/
obj-y += i2c/
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 528429252f0..02e52d543e4 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -241,6 +241,8 @@ struct ast_fbdev {
void *sysram;
int size;
struct ttm_bo_kmap_obj mapping;
+ int x1, y1, x2, y2; /* dirty rect */
+ spinlock_t dirty_lock;
};
#define to_ast_crtc(x) container_of(x, struct ast_crtc, base)
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index 34931fe7d2c..fbc0823cfa1 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -53,16 +53,52 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8;
int ret;
bool unmap = false;
+ bool store_for_later = false;
+ int x2, y2;
+ unsigned long flags;
obj = afbdev->afb.obj;
bo = gem_to_ast_bo(obj);
+ /*
+ * try and reserve the BO, if we fail with busy
+ * then the BO is being moved and we should
+ * store up the damage until later.
+ */
ret = ast_bo_reserve(bo, true);
if (ret) {
- DRM_ERROR("failed to reserve fb bo\n");
+ if (ret != -EBUSY)
+ return;
+
+ store_for_later = true;
+ }
+
+ x2 = x + width - 1;
+ y2 = y + height - 1;
+ spin_lock_irqsave(&afbdev->dirty_lock, flags);
+
+ if (afbdev->y1 < y)
+ y = afbdev->y1;
+ if (afbdev->y2 > y2)
+ y2 = afbdev->y2;
+ if (afbdev->x1 < x)
+ x = afbdev->x1;
+ if (afbdev->x2 > x2)
+ x2 = afbdev->x2;
+
+ if (store_for_later) {
+ afbdev->x1 = x;
+ afbdev->x2 = x2;
+ afbdev->y1 = y;
+ afbdev->y2 = y2;
+ spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
return;
}
+ afbdev->x1 = afbdev->y1 = INT_MAX;
+ afbdev->x2 = afbdev->y2 = 0;
+ spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
+
if (!bo->kmap.virtual) {
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
if (ret) {
@@ -72,10 +108,10 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
}
unmap = true;
}
- for (i = y; i < y + height; i++) {
+ for (i = y; i <= y2; i++) {
/* assume equal stride for now */
src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp);
- memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
+ memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, (x2 - x + 1) * bpp);
}
if (unmap)
@@ -292,6 +328,7 @@ int ast_fbdev_init(struct drm_device *dev)
ast->fbdev = afbdev;
afbdev->helper.funcs = &ast_fb_helper_funcs;
+ spin_lock_init(&afbdev->dirty_lock);
ret = drm_fb_helper_init(dev, &afbdev->helper,
1, 1);
if (ret) {
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c
index 3602731a611..09da3393c52 100644
--- a/drivers/gpu/drm/ast/ast_ttm.c
+++ b/drivers/gpu/drm/ast/ast_ttm.c
@@ -316,7 +316,7 @@ int ast_bo_reserve(struct ast_bo *bo, bool no_wait)
ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
if (ret) {
- if (ret != -ERESTARTSYS)
+ if (ret != -ERESTARTSYS && ret != -EBUSY)
DRM_ERROR("reserve failed %p\n", bo);
return ret;
}
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 6e0cc724e5a..7ca05959688 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -154,6 +154,8 @@ struct cirrus_fbdev {
struct list_head fbdev_list;
void *sysram;
int size;
+ int x1, y1, x2, y2; /* dirty rect */
+ spinlock_t dirty_lock;
};
struct cirrus_bo {
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index e25afccaf85..3541b567bbd 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -27,16 +27,51 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8;
int ret;
bool unmap = false;
+ bool store_for_later = false;
+ int x2, y2;
+ unsigned long flags;
obj = afbdev->gfb.obj;
bo = gem_to_cirrus_bo(obj);
+ /*
+ * try and reserve the BO, if we fail with busy
+ * then the BO is being moved and we should
+ * store up the damage until later.
+ */
ret = cirrus_bo_reserve(bo, true);
if (ret) {
- DRM_ERROR("failed to reserve fb bo\n");
+ if (ret != -EBUSY)
+ return;
+ store_for_later = true;
+ }
+
+ x2 = x + width - 1;
+ y2 = y + height - 1;
+ spin_lock_irqsave(&afbdev->dirty_lock, flags);
+
+ if (afbdev->y1 < y)
+ y = afbdev->y1;
+ if (afbdev->y2 > y2)
+ y2 = afbdev->y2;
+ if (afbdev->x1 < x)
+ x = afbdev->x1;
+ if (afbdev->x2 > x2)
+ x2 = afbdev->x2;
+
+ if (store_for_later) {
+ afbdev->x1 = x;
+ afbdev->x2 = x2;
+ afbdev->y1 = y;
+ afbdev->y2 = y2;
+ spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
return;
}
+ afbdev->x1 = afbdev->y1 = INT_MAX;
+ afbdev->x2 = afbdev->y2 = 0;
+ spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
+
if (!bo->kmap.virtual) {
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
if (ret) {
@@ -268,6 +303,7 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
cdev->mode_info.gfbdev = gfbdev;
gfbdev->helper.funcs = &cirrus_fb_helper_funcs;
+ spin_lock_init(&gfbdev->dirty_lock);
ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
cdev->num_crtc, CIRRUSFB_CONN_LIMIT);
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
index 1413a26e490..2ed8cfc740c 100644
--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -321,7 +321,7 @@ int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait)
ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
if (ret) {
- if (ret != -ERESTARTSYS)
+ if (ret != -ERESTARTSYS && ret != -EBUSY)
DRM_ERROR("reserve failed %p\n", bo);
return ret;
}
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index a575cb2e6bd..bb8f5801218 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -105,12 +105,11 @@ drm_clflush_sg(struct sg_table *st)
{
#if defined(CONFIG_X86)
if (cpu_has_clflush) {
- struct scatterlist *sg;
- int i;
+ struct sg_page_iter sg_iter;
mb();
- for_each_sg(st->sgl, sg, st->nents, i)
- drm_clflush_page(sg_page(sg));
+ for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
+ drm_clflush_page(sg_page_iter_page(&sg_iter));
mb();
return;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index dd64a06dc5b..3a8f7e6db29 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -178,9 +178,6 @@ static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
{ DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
};
-DRM_ENUM_NAME_FN(drm_get_dirty_info_name,
- drm_dirty_info_enum_list)
-
struct drm_conn_prop_enum_list {
int type;
char *name;
@@ -412,7 +409,7 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
mutex_lock(&dev->mode_config.fb_lock);
fb = __drm_framebuffer_lookup(dev, id);
if (fb)
- kref_get(&fb->refcount);
+ drm_framebuffer_reference(fb);
mutex_unlock(&dev->mode_config.fb_lock);
return fb;
@@ -706,7 +703,6 @@ int drm_connector_init(struct drm_device *dev,
connector->connector_type = connector_type;
connector->connector_type_id =
++drm_connector_enum_list[connector_type].count; /* TODO */
- INIT_LIST_HEAD(&connector->user_modes);
INIT_LIST_HEAD(&connector->probed_modes);
INIT_LIST_HEAD(&connector->modes);
connector->edid_blob_ptr = NULL;
@@ -747,9 +743,6 @@ void drm_connector_cleanup(struct drm_connector *connector)
list_for_each_entry_safe(mode, t, &connector->modes, head)
drm_mode_remove(connector, mode);
- list_for_each_entry_safe(mode, t, &connector->user_modes, head)
- drm_mode_remove(connector, mode);
-
drm_mode_object_put(dev, &connector->base);
list_del(&connector->head);
dev->mode_config.num_connector--;
@@ -1120,45 +1113,7 @@ int drm_mode_create_dirty_info_property(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
-/**
- * drm_mode_config_init - initialize DRM mode_configuration structure
- * @dev: DRM device
- *
- * Initialize @dev's mode_config structure, used for tracking the graphics
- * configuration of @dev.
- *
- * Since this initializes the modeset locks, no locking is possible. Which is no
- * problem, since this should happen single threaded at init time. It is the
- * driver's problem to ensure this guarantee.
- *
- */
-void drm_mode_config_init(struct drm_device *dev)
-{
- mutex_init(&dev->mode_config.mutex);
- mutex_init(&dev->mode_config.idr_mutex);
- mutex_init(&dev->mode_config.fb_lock);
- INIT_LIST_HEAD(&dev->mode_config.fb_list);
- INIT_LIST_HEAD(&dev->mode_config.crtc_list);
- INIT_LIST_HEAD(&dev->mode_config.connector_list);
- INIT_LIST_HEAD(&dev->mode_config.encoder_list);
- INIT_LIST_HEAD(&dev->mode_config.property_list);
- INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
- INIT_LIST_HEAD(&dev->mode_config.plane_list);
- idr_init(&dev->mode_config.crtc_idr);
-
- drm_modeset_lock_all(dev);
- drm_mode_create_standard_connector_properties(dev);
- drm_modeset_unlock_all(dev);
-
- /* Just to be sure */
- dev->mode_config.num_fb = 0;
- dev->mode_config.num_connector = 0;
- dev->mode_config.num_crtc = 0;
- dev->mode_config.num_encoder = 0;
-}
-EXPORT_SYMBOL(drm_mode_config_init);
-
-int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
+static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
{
uint32_t total_objects = 0;
@@ -1203,69 +1158,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
/**
- * drm_mode_config_cleanup - free up DRM mode_config info
- * @dev: DRM device
- *
- * Free up all the connectors and CRTCs associated with this DRM device, then
- * free up the framebuffers and associated buffer objects.
- *
- * Note that since this /should/ happen single-threaded at driver/device
- * teardown time, no locking is required. It's the driver's job to ensure that
- * this guarantee actually holds true.
- *
- * FIXME: cleanup any dangling user buffer objects too
- */
-void drm_mode_config_cleanup(struct drm_device *dev)
-{
- struct drm_connector *connector, *ot;
- struct drm_crtc *crtc, *ct;
- struct drm_encoder *encoder, *enct;
- struct drm_framebuffer *fb, *fbt;
- struct drm_property *property, *pt;
- struct drm_plane *plane, *plt;
-
- list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
- head) {
- encoder->funcs->destroy(encoder);
- }
-
- list_for_each_entry_safe(connector, ot,
- &dev->mode_config.connector_list, head) {
- connector->funcs->destroy(connector);
- }
-
- list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
- head) {
- drm_property_destroy(dev, property);
- }
-
- /*
- * Single-threaded teardown context, so it's not required to grab the
- * fb_lock to protect against concurrent fb_list access. Contrary, it
- * would actually deadlock with the drm_framebuffer_cleanup function.
- *
- * Also, if there are any framebuffers left, that's a driver leak now,
- * so politely WARN about this.
- */
- WARN_ON(!list_empty(&dev->mode_config.fb_list));
- list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
- drm_framebuffer_remove(fb);
- }
-
- list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
- head) {
- plane->funcs->destroy(plane);
- }
-
- list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
- crtc->funcs->destroy(crtc);
- }
-
- idr_destroy(&dev->mode_config.crtc_idr);
-}
-EXPORT_SYMBOL(drm_mode_config_cleanup);
-
-/**
* drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
* @out: drm_mode_modeinfo struct to return to the user
* @in: drm_display_mode to use
@@ -2717,192 +2609,6 @@ void drm_fb_release(struct drm_file *priv)
mutex_unlock(&priv->fbs_lock);
}
-/**
- * drm_mode_attachmode - add a mode to the user mode list
- * @dev: DRM device
- * @connector: connector to add the mode to
- * @mode: mode to add
- *
- * Add @mode to @connector's user mode list.
- */
-static void drm_mode_attachmode(struct drm_device *dev,
- struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- list_add_tail(&mode->head, &connector->user_modes);
-}
-
-int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
- const struct drm_display_mode *mode)
-{
- struct drm_connector *connector;
- int ret = 0;
- struct drm_display_mode *dup_mode, *next;
- LIST_HEAD(list);
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (!connector->encoder)
- continue;
- if (connector->encoder->crtc == crtc) {
- dup_mode = drm_mode_duplicate(dev, mode);
- if (!dup_mode) {
- ret = -ENOMEM;
- goto out;
- }
- list_add_tail(&dup_mode->head, &list);
- }
- }
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (!connector->encoder)
- continue;
- if (connector->encoder->crtc == crtc)
- list_move_tail(list.next, &connector->user_modes);
- }
-
- WARN_ON(!list_empty(&list));
-
- out:
- list_for_each_entry_safe(dup_mode, next, &list, head)
- drm_mode_destroy(dev, dup_mode);
-
- return ret;
-}
-EXPORT_SYMBOL(drm_mode_attachmode_crtc);
-
-static int drm_mode_detachmode(struct drm_device *dev,
- struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- int found = 0;
- int ret = 0;
- struct drm_display_mode *match_mode, *t;
-
- list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) {
- if (drm_mode_equal(match_mode, mode)) {
- list_del(&match_mode->head);
- drm_mode_destroy(dev, match_mode);
- found = 1;
- break;
- }
- }
-
- if (!found)
- ret = -EINVAL;
-
- return ret;
-}
-
-int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode)
-{
- struct drm_connector *connector;
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- drm_mode_detachmode(dev, connector, mode);
- }
- return 0;
-}
-EXPORT_SYMBOL(drm_mode_detachmode_crtc);
-
-/**
- * drm_fb_attachmode - Attach a user mode to an connector
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * This attaches a user specified mode to an connector.
- * Called by the user via ioctl.
- *
- * RETURNS:
- * Zero on success, errno on failure.
- */
-int drm_mode_attachmode_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
-{
- struct drm_mode_mode_cmd *mode_cmd = data;
- struct drm_connector *connector;
- struct drm_display_mode *mode;
- struct drm_mode_object *obj;
- struct drm_mode_modeinfo *umode = &mode_cmd->mode;
- int ret;
-
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
- drm_modeset_lock_all(dev);
-
- obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
- if (!obj) {
- ret = -EINVAL;
- goto out;
- }
- connector = obj_to_connector(obj);
-
- mode = drm_mode_create(dev);
- if (!mode) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = drm_crtc_convert_umode(mode, umode);
- if (ret) {
- DRM_DEBUG_KMS("Invalid mode\n");
- drm_mode_destroy(dev, mode);
- goto out;
- }
-
- drm_mode_attachmode(dev, connector, mode);
-out:
- drm_modeset_unlock_all(dev);
- return ret;
-}
-
-
-/**
- * drm_fb_detachmode - Detach a user specified mode from an connector
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
- *
- * Called by the user via ioctl.
- *
- * RETURNS:
- * Zero on success, errno on failure.
- */
-int drm_mode_detachmode_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
-{
- struct drm_mode_object *obj;
- struct drm_mode_mode_cmd *mode_cmd = data;
- struct drm_connector *connector;
- struct drm_display_mode mode;
- struct drm_mode_modeinfo *umode = &mode_cmd->mode;
- int ret;
-
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
- drm_modeset_lock_all(dev);
-
- obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
- if (!obj) {
- ret = -EINVAL;
- goto out;
- }
- connector = obj_to_connector(obj);
-
- ret = drm_crtc_convert_umode(&mode, umode);
- if (ret) {
- DRM_DEBUG_KMS("Invalid mode\n");
- goto out;
- }
-
- ret = drm_mode_detachmode(dev, connector, &mode);
-out:
- drm_modeset_unlock_all(dev);
- return ret;
-}
-
struct drm_property *drm_property_create(struct drm_device *dev, int flags,
const char *name, int num_values)
{
@@ -3739,6 +3445,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
goto out;
}
+ if (crtc->fb->pixel_format != fb->pixel_format) {
+ DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
ret = -ENOMEM;
spin_lock_irqsave(&dev->event_lock, flags);
@@ -4064,3 +3776,110 @@ int drm_format_vert_chroma_subsampling(uint32_t format)
}
}
EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
+
+/**
+ * drm_mode_config_init - initialize DRM mode_configuration structure
+ * @dev: DRM device
+ *
+ * Initialize @dev's mode_config structure, used for tracking the graphics
+ * configuration of @dev.
+ *
+ * Since this initializes the modeset locks, no locking is possible. Which is no
+ * problem, since this should happen single threaded at init time. It is the
+ * driver's problem to ensure this guarantee.
+ *
+ */
+void drm_mode_config_init(struct drm_device *dev)
+{
+ mutex_init(&dev->mode_config.mutex);
+ mutex_init(&dev->mode_config.idr_mutex);
+ mutex_init(&dev->mode_config.fb_lock);
+ INIT_LIST_HEAD(&dev->mode_config.fb_list);
+ INIT_LIST_HEAD(&dev->mode_config.crtc_list);
+ INIT_LIST_HEAD(&dev->mode_config.connector_list);
+ INIT_LIST_HEAD(&dev->mode_config.encoder_list);
+ INIT_LIST_HEAD(&dev->mode_config.property_list);
+ INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
+ INIT_LIST_HEAD(&dev->mode_config.plane_list);
+ idr_init(&dev->mode_config.crtc_idr);
+
+ drm_modeset_lock_all(dev);
+ drm_mode_create_standard_connector_properties(dev);
+ drm_modeset_unlock_all(dev);
+
+ /* Just to be sure */
+ dev->mode_config.num_fb = 0;
+ dev->mode_config.num_connector = 0;
+ dev->mode_config.num_crtc = 0;
+ dev->mode_config.num_encoder = 0;
+}
+EXPORT_SYMBOL(drm_mode_config_init);
+
+/**
+ * drm_mode_config_cleanup - free up DRM mode_config info
+ * @dev: DRM device
+ *
+ * Free up all the connectors and CRTCs associated with this DRM device, then
+ * free up the framebuffers and associated buffer objects.
+ *
+ * Note that since this /should/ happen single-threaded at driver/device
+ * teardown time, no locking is required. It's the driver's job to ensure that
+ * this guarantee actually holds true.
+ *
+ * FIXME: cleanup any dangling user buffer objects too
+ */
+void drm_mode_config_cleanup(struct drm_device *dev)
+{
+ struct drm_connector *connector, *ot;
+ struct drm_crtc *crtc, *ct;
+ struct drm_encoder *encoder, *enct;
+ struct drm_framebuffer *fb, *fbt;
+ struct drm_property *property, *pt;
+ struct drm_property_blob *blob, *bt;
+ struct drm_plane *plane, *plt;
+
+ list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
+ head) {
+ encoder->funcs->destroy(encoder);
+ }
+
+ list_for_each_entry_safe(connector, ot,
+ &dev->mode_config.connector_list, head) {
+ connector->funcs->destroy(connector);
+ }
+
+ list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
+ head) {
+ drm_property_destroy(dev, property);
+ }
+
+ list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
+ head) {
+ drm_property_destroy_blob(dev, blob);
+ }
+
+ /*
+ * Single-threaded teardown context, so it's not required to grab the
+ * fb_lock to protect against concurrent fb_list access. Contrary, it
+ * would actually deadlock with the drm_framebuffer_cleanup function.
+ *
+ * Also, if there are any framebuffers left, that's a driver leak now,
+ * so politely WARN about this.
+ */
+ WARN_ON(!list_empty(&dev->mode_config.fb_list));
+ list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
+ drm_framebuffer_remove(fb);
+ }
+
+ list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
+ head) {
+ plane->funcs->destroy(plane);
+ }
+
+ list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
+ crtc->funcs->destroy(crtc);
+ }
+
+ idr_destroy(&dev->mode_config.crtc_idr);
+}
+EXPORT_SYMBOL(drm_mode_config_cleanup);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 7b2d378b257..e974f9309b7 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -648,6 +648,9 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
} else if (set->fb->bits_per_pixel !=
set->crtc->fb->bits_per_pixel) {
mode_changed = true;
+ } else if (set->fb->pixel_format !=
+ set->crtc->fb->pixel_format) {
+ mode_changed = true;
} else
fb_changed = true;
}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 25f91cd23e6..8d4f29075af 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -60,7 +60,7 @@ static int drm_version(struct drm_device *dev, void *data,
[DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0}
/** Ioctl table */
-static struct drm_ioctl_desc drm_ioctls[] = {
+static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
@@ -150,8 +150,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
@@ -375,7 +375,7 @@ long drm_ioctl(struct file *filp,
{
struct drm_file *file_priv = filp->private_data;
struct drm_device *dev;
- struct drm_ioctl_desc *ioctl;
+ const struct drm_ioctl_desc *ioctl;
drm_ioctl_t *func;
unsigned int nr = DRM_IOCTL_NR(cmd);
int retcode = -EINVAL;
@@ -408,6 +408,7 @@ long drm_ioctl(struct file *filp,
usize = asize = _IOC_SIZE(cmd);
if (drv_size > asize)
asize = drv_size;
+ cmd = ioctl->cmd_drv;
}
else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
ioctl = &drm_ioctls[nr];
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index e2acfdbf7d3..9e62bbedb5a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -587,284 +587,348 @@ static const struct drm_display_mode edid_cea_modes[] = {
/* 1 - 640x480@60Hz */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
752, 800, 0, 480, 490, 492, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 2 - 720x480@60Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 3 - 720x480@60Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 4 - 1280x720@60Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
1430, 1650, 0, 720, 725, 730, 750, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, },
/* 5 - 1920x1080i@60Hz */
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 60, },
/* 6 - 1440x480i@60Hz */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 60, },
/* 7 - 1440x480i@60Hz */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 60, },
/* 8 - 1440x240@60Hz */
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 240, 244, 247, 262, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 60, },
/* 9 - 1440x240@60Hz */
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 240, 244, 247, 262, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 60, },
/* 10 - 2880x480i@60Hz */
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
3204, 3432, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 60, },
/* 11 - 2880x480i@60Hz */
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
3204, 3432, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 60, },
/* 12 - 2880x240@60Hz */
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
3204, 3432, 0, 240, 244, 247, 262, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 13 - 2880x240@60Hz */
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
3204, 3432, 0, 240, 244, 247, 262, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 14 - 1440x480@60Hz */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
1596, 1716, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 15 - 1440x480@60Hz */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
1596, 1716, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 16 - 1920x1080@60Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, },
/* 17 - 720x576@50Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 50, },
/* 18 - 720x576@50Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 50, },
/* 19 - 1280x720@50Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
1760, 1980, 0, 720, 725, 730, 750, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, },
/* 20 - 1920x1080i@50Hz */
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 50, },
/* 21 - 1440x576i@50Hz */
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 50, },
/* 22 - 1440x576i@50Hz */
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 50, },
/* 23 - 1440x288@50Hz */
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 288, 290, 293, 312, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 50, },
/* 24 - 1440x288@50Hz */
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 288, 290, 293, 312, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 50, },
/* 25 - 2880x576i@50Hz */
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
3180, 3456, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 50, },
/* 26 - 2880x576i@50Hz */
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
3180, 3456, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 50, },
/* 27 - 2880x288@50Hz */
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
3180, 3456, 0, 288, 290, 293, 312, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 50, },
/* 28 - 2880x288@50Hz */
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
3180, 3456, 0, 288, 290, 293, 312, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 50, },
/* 29 - 1440x576@50Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1592, 1728, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 50, },
/* 30 - 1440x576@50Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1592, 1728, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 50, },
/* 31 - 1920x1080@50Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, },
/* 32 - 1920x1080@24Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, },
/* 33 - 1920x1080@25Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, },
/* 34 - 1920x1080@30Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, },
/* 35 - 2880x480@60Hz */
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
3192, 3432, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 36 - 2880x480@60Hz */
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
3192, 3432, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, },
/* 37 - 2880x576@50Hz */
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
3184, 3456, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 50, },
/* 38 - 2880x576@50Hz */
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
3184, 3456, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 50, },
/* 39 - 1920x1080i@50Hz */
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 50, },
/* 40 - 1920x1080i@100Hz */
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 100, },
/* 41 - 1280x720@100Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
1760, 1980, 0, 720, 725, 730, 750, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, },
/* 42 - 720x576@100Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 100, },
/* 43 - 720x576@100Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 100, },
/* 44 - 1440x576i@100Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 100, },
/* 45 - 1440x576i@100Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 100, },
/* 46 - 1920x1080i@120Hz */
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
+ DRM_MODE_FLAG_INTERLACE),
+ .vrefresh = 120, },
/* 47 - 1280x720@120Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
1430, 1650, 0, 720, 725, 730, 750, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, },
/* 48 - 720x480@120Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 120, },
/* 49 - 720x480@120Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 120, },
/* 50 - 1440x480i@120Hz */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 120, },
/* 51 - 1440x480i@120Hz */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 120, },
/* 52 - 720x576@200Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 200, },
/* 53 - 720x576@200Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 200, },
/* 54 - 1440x576i@200Hz */
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 200, },
/* 55 - 1440x576i@200Hz */
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 200, },
/* 56 - 720x480@240Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 240, },
/* 57 - 720x480@240Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 240, },
/* 58 - 1440x480i@240 */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 240, },
/* 59 - 1440x480i@240 */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
+ .vrefresh = 240, },
/* 60 - 1280x720@24Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
3080, 3300, 0, 720, 725, 730, 750, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, },
/* 61 - 1280x720@25Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
3740, 3960, 0, 720, 725, 730, 750, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, },
/* 62 - 1280x720@30Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
3080, 3300, 0, 720, 725, 730, 750, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, },
/* 63 - 1920x1080@120Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, },
/* 64 - 1920x1080@100Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, },
};
/*** DDC fetch and block validation ***/
@@ -2266,13 +2330,34 @@ EXPORT_SYMBOL(drm_find_cea_extension);
*/
u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
{
- struct drm_display_mode *cea_mode;
u8 mode;
+ if (!to_match->clock)
+ return 0;
+
for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
- cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode];
+ const struct drm_display_mode *cea_mode = &edid_cea_modes[mode];
+ unsigned int clock1, clock2;
+
+ clock1 = clock2 = cea_mode->clock;
- if (drm_mode_equal(to_match, cea_mode))
+ /* Check both 60Hz and 59.94Hz */
+ if (cea_mode->vrefresh % 6 == 0) {
+ /*
+ * edid_cea_modes contains the 59.94Hz
+ * variant for 240 and 480 line modes,
+ * and the 60Hz variant otherwise.
+ */
+ if (cea_mode->vdisplay == 240 ||
+ cea_mode->vdisplay == 480)
+ clock1 = clock1 * 1001 / 1000;
+ else
+ clock2 = DIV_ROUND_UP(clock2 * 1000, 1001);
+ }
+
+ if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
+ KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
+ drm_mode_equal_no_clocks(to_match, cea_mode))
return mode + 1;
}
return 0;
@@ -2294,6 +2379,7 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
newmode = drm_mode_duplicate(dev,
&edid_cea_modes[cea_mode]);
if (newmode) {
+ newmode->vrefresh = 0;
drm_mode_probed_add(connector, newmode);
modes++;
}
@@ -2511,6 +2597,65 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
EXPORT_SYMBOL(drm_edid_to_eld);
/**
+ * drm_edid_to_sad - extracts SADs from EDID
+ * @edid: EDID to parse
+ * @sads: pointer that will be set to the extracted SADs
+ *
+ * Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it.
+ * Note: returned pointer needs to be kfreed
+ *
+ * Return number of found SADs or negative number on error.
+ */
+int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads)
+{
+ int count = 0;
+ int i, start, end, dbl;
+ u8 *cea;
+
+ cea = drm_find_cea_extension(edid);
+ if (!cea) {
+ DRM_DEBUG_KMS("SAD: no CEA Extension found\n");
+ return -ENOENT;
+ }
+
+ if (cea_revision(cea) < 3) {
+ DRM_DEBUG_KMS("SAD: wrong CEA revision\n");
+ return -ENOTSUPP;
+ }
+
+ if (cea_db_offsets(cea, &start, &end)) {
+ DRM_DEBUG_KMS("SAD: invalid data block offsets\n");
+ return -EPROTO;
+ }
+
+ for_each_cea_db(cea, i, start, end) {
+ u8 *db = &cea[i];
+
+ if (cea_db_tag(db) == AUDIO_BLOCK) {
+ int j;
+ dbl = cea_db_payload_len(db);
+
+ count = dbl / 3; /* SAD is 3B */
+ *sads = kcalloc(count, sizeof(**sads), GFP_KERNEL);
+ if (!*sads)
+ return -ENOMEM;
+ for (j = 0; j < count; j++) {
+ u8 *sad = &db[1 + j * 3];
+
+ (*sads)[j].format = (sad[0] & 0x78) >> 3;
+ (*sads)[j].channels = sad[0] & 0x7;
+ (*sads)[j].freq = sad[1] & 0x7F;
+ (*sads)[j].byte2 = sad[2];
+ }
+ break;
+ }
+ }
+
+ return count;
+}
+EXPORT_SYMBOL(drm_edid_to_sad);
+
+/**
* drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond
* @connector: connector associated with the HDMI/DP sink
* @mode: the display mode
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
index 38d3943f72d..fa445dd4dc0 100644
--- a/drivers/gpu/drm/drm_edid_load.c
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -31,10 +31,11 @@ module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
"from built-in data or /lib/firmware instead. ");
-#define GENERIC_EDIDS 4
+#define GENERIC_EDIDS 5
static char *generic_edid_name[GENERIC_EDIDS] = {
"edid/1024x768.bin",
"edid/1280x1024.bin",
+ "edid/1600x1200.bin",
"edid/1680x1050.bin",
"edid/1920x1080.bin",
};
@@ -79,6 +80,24 @@ static u8 generic_edid[GENERIC_EDIDS][128] = {
{
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
+ 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+ 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
+ 0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
+ 0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+ 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+ 0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+ 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
+ 0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
+ },
+ {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 892ff9f9597..b78cbe74dad 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1398,7 +1398,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
struct drm_mode_set *modeset;
bool *enabled;
int width, height;
- int i, ret;
+ int i;
DRM_DEBUG_KMS("\n");
@@ -1419,16 +1419,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
drm_enable_connectors(fb_helper, enabled);
- ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
- if (!ret) {
- ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
- if (!ret)
+ if (!(fb_helper->funcs->initial_config &&
+ fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
+ enabled, width, height))) {
+ memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
+ memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
+
+ if (!drm_target_cloned(fb_helper,
+ modes, enabled, width, height) &&
+ !drm_target_preferred(fb_helper,
+ modes, enabled, width, height))
DRM_ERROR("Unable to find initial modes\n");
- }
- DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
+ DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
+ width, height);
- drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
+ drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
+ }
/* need to set the modesets up here for use later */
/* fill out the connector<->crtc mappings into the modesets */
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index af779ae19eb..cf919e36e8a 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -205,11 +205,11 @@ static void
drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
{
if (obj->import_attach) {
- drm_prime_remove_imported_buf_handle(&filp->prime,
+ drm_prime_remove_buf_handle(&filp->prime,
obj->import_attach->dmabuf);
}
if (obj->export_dma_buf) {
- drm_prime_remove_imported_buf_handle(&filp->prime,
+ drm_prime_remove_buf_handle(&filp->prime,
obj->export_dma_buf);
}
}
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index f83f0719922..faa79df0264 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -848,6 +848,26 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ
} else if (mode1->clock != mode2->clock)
return false;
+ return drm_mode_equal_no_clocks(mode1, mode2);
+}
+EXPORT_SYMBOL(drm_mode_equal);
+
+/**
+ * drm_mode_equal_no_clocks - test modes for equality
+ * @mode1: first mode
+ * @mode2: second mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Check to see if @mode1 and @mode2 are equivalent, but
+ * don't check the pixel clocks.
+ *
+ * RETURNS:
+ * True if the modes are equal, false otherwise.
+ */
+bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
+{
if (mode1->hdisplay == mode2->hdisplay &&
mode1->hsync_start == mode2->hsync_start &&
mode1->hsync_end == mode2->hsync_end &&
@@ -863,7 +883,7 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ
return false;
}
-EXPORT_SYMBOL(drm_mode_equal);
+EXPORT_SYMBOL(drm_mode_equal_no_clocks);
/**
* drm_mode_validate_size - make sure modes adhere to size constraints
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index bd719e936e1..14194b6ef64 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -152,7 +152,7 @@ static const char *drm_pci_get_name(struct drm_device *dev)
return pdriver->name;
}
-int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
+static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
{
int len, ret;
struct pci_driver *pdriver = dev->driver->kdriver.pci;
@@ -194,9 +194,9 @@ err:
return ret;
}
-int drm_pci_set_unique(struct drm_device *dev,
- struct drm_master *master,
- struct drm_unique *u)
+static int drm_pci_set_unique(struct drm_device *dev,
+ struct drm_master *master,
+ struct drm_unique *u)
{
int domain, bus, slot, func, ret;
const char *bus_name;
@@ -266,7 +266,7 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
return 0;
}
-int drm_pci_agp_init(struct drm_device *dev)
+static int drm_pci_agp_init(struct drm_device *dev)
{
if (drm_core_has_AGP(dev)) {
if (drm_pci_device_is_agp(dev))
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 366910ddcfc..dcde35231e2 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -62,6 +62,7 @@ struct drm_prime_member {
struct dma_buf *dma_buf;
uint32_t handle;
};
+static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle);
static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
enum dma_data_direction dir)
@@ -200,7 +201,8 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
{
struct drm_gem_object *obj;
void *buf;
- int ret;
+ int ret = 0;
+ struct dma_buf *dmabuf;
obj = drm_gem_object_lookup(dev, file_priv, handle);
if (!obj)
@@ -209,43 +211,44 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
mutex_lock(&file_priv->prime.lock);
/* re-export the original imported object */
if (obj->import_attach) {
- get_dma_buf(obj->import_attach->dmabuf);
- *prime_fd = dma_buf_fd(obj->import_attach->dmabuf, flags);
- drm_gem_object_unreference_unlocked(obj);
- mutex_unlock(&file_priv->prime.lock);
- return 0;
+ dmabuf = obj->import_attach->dmabuf;
+ goto out_have_obj;
}
if (obj->export_dma_buf) {
- get_dma_buf(obj->export_dma_buf);
- *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
- drm_gem_object_unreference_unlocked(obj);
- } else {
- buf = dev->driver->gem_prime_export(dev, obj, flags);
- if (IS_ERR(buf)) {
- /* normally the created dma-buf takes ownership of the ref,
- * but if that fails then drop the ref
- */
- drm_gem_object_unreference_unlocked(obj);
- mutex_unlock(&file_priv->prime.lock);
- return PTR_ERR(buf);
- }
- obj->export_dma_buf = buf;
- *prime_fd = dma_buf_fd(buf, flags);
+ dmabuf = obj->export_dma_buf;
+ goto out_have_obj;
+ }
+
+ buf = dev->driver->gem_prime_export(dev, obj, flags);
+ if (IS_ERR(buf)) {
+ /* normally the created dma-buf takes ownership of the ref,
+ * but if that fails then drop the ref
+ */
+ ret = PTR_ERR(buf);
+ goto out;
}
+ obj->export_dma_buf = buf;
+
/* if we've exported this buffer the cheat and add it to the import list
* so we get the correct handle back
*/
- ret = drm_prime_add_imported_buf_handle(&file_priv->prime,
- obj->export_dma_buf, handle);
- if (ret) {
- drm_gem_object_unreference_unlocked(obj);
- mutex_unlock(&file_priv->prime.lock);
- return ret;
- }
+ ret = drm_prime_add_buf_handle(&file_priv->prime,
+ obj->export_dma_buf, handle);
+ if (ret)
+ goto out;
+ *prime_fd = dma_buf_fd(buf, flags);
mutex_unlock(&file_priv->prime.lock);
return 0;
+
+out_have_obj:
+ get_dma_buf(dmabuf);
+ *prime_fd = dma_buf_fd(dmabuf, flags);
+out:
+ drm_gem_object_unreference_unlocked(obj);
+ mutex_unlock(&file_priv->prime.lock);
+ return ret;
}
EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
@@ -268,7 +271,6 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
* refcount on gem itself instead of f_count of dmabuf.
*/
drm_gem_object_reference(obj);
- dma_buf_put(dma_buf);
return obj;
}
}
@@ -277,6 +279,8 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
if (IS_ERR(attach))
return ERR_PTR(PTR_ERR(attach));
+ get_dma_buf(dma_buf);
+
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
if (IS_ERR_OR_NULL(sgt)) {
ret = PTR_ERR(sgt);
@@ -297,6 +301,8 @@ fail_unmap:
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
fail_detach:
dma_buf_detach(dma_buf, attach);
+ dma_buf_put(dma_buf);
+
return ERR_PTR(ret);
}
EXPORT_SYMBOL(drm_gem_prime_import);
@@ -314,7 +320,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
mutex_lock(&file_priv->prime.lock);
- ret = drm_prime_lookup_imported_buf_handle(&file_priv->prime,
+ ret = drm_prime_lookup_buf_handle(&file_priv->prime,
dma_buf, handle);
if (!ret) {
ret = 0;
@@ -333,12 +339,15 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
if (ret)
goto out_put;
- ret = drm_prime_add_imported_buf_handle(&file_priv->prime,
+ ret = drm_prime_add_buf_handle(&file_priv->prime,
dma_buf, *handle);
if (ret)
goto fail;
mutex_unlock(&file_priv->prime.lock);
+
+ dma_buf_put(dma_buf);
+
return 0;
fail:
@@ -401,21 +410,17 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
{
struct sg_table *sg = NULL;
- struct scatterlist *iter;
- int i;
int ret;
sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!sg)
goto out;
- ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL);
+ ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
+ nr_pages << PAGE_SHIFT, GFP_KERNEL);
if (ret)
goto out;
- for_each_sg(sg->sgl, iter, nr_pages, i)
- sg_set_page(iter, pages[i], PAGE_SIZE, 0);
-
return sg;
out:
kfree(sg);
@@ -483,15 +488,12 @@ EXPORT_SYMBOL(drm_prime_init_file_private);
void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
{
- struct drm_prime_member *member, *safe;
- list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
- list_del(&member->entry);
- kfree(member);
- }
+ /* by now drm_gem_release should've made sure the list is empty */
+ WARN_ON(!list_empty(&prime_fpriv->head));
}
EXPORT_SYMBOL(drm_prime_destroy_file_private);
-int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
+static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
{
struct drm_prime_member *member;
@@ -499,14 +501,14 @@ int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv
if (!member)
return -ENOMEM;
+ get_dma_buf(dma_buf);
member->dma_buf = dma_buf;
member->handle = handle;
list_add(&member->entry, &prime_fpriv->head);
return 0;
}
-EXPORT_SYMBOL(drm_prime_add_imported_buf_handle);
-int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle)
+int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle)
{
struct drm_prime_member *member;
@@ -518,19 +520,20 @@ int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fp
}
return -ENOENT;
}
-EXPORT_SYMBOL(drm_prime_lookup_imported_buf_handle);
+EXPORT_SYMBOL(drm_prime_lookup_buf_handle);
-void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf)
+void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf)
{
struct drm_prime_member *member, *safe;
mutex_lock(&prime_fpriv->lock);
list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
if (member->dma_buf == dma_buf) {
+ dma_buf_put(dma_buf);
list_del(&member->entry);
kfree(member);
}
}
mutex_unlock(&prime_fpriv->lock);
}
-EXPORT_SYMBOL(drm_prime_remove_imported_buf_handle);
+EXPORT_SYMBOL(drm_prime_remove_buf_handle);
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index db7bd292410..1d4f7c9fe66 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -422,6 +422,7 @@ void drm_vm_open_locked(struct drm_device *dev,
list_add(&vma_entry->head, &dev->vmalist);
}
}
+EXPORT_SYMBOL_GPL(drm_vm_open_locked);
static void drm_vm_open(struct vm_area_struct *vma)
{
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 046bcda36ab..772c62a6e2a 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -24,7 +24,9 @@ config DRM_EXYNOS_DMABUF
config DRM_EXYNOS_FIMD
bool "Exynos DRM FIMD"
- depends on DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM
+ depends on OF && DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM
+ select FB_MODE_HELPERS
+ select VIDEOMODE_HELPERS
help
Choose this option if you want to use Exynos FIMD for DRM.
@@ -54,7 +56,7 @@ config DRM_EXYNOS_IPP
config DRM_EXYNOS_FIMC
bool "Exynos DRM FIMC"
- depends on DRM_EXYNOS_IPP
+ depends on DRM_EXYNOS_IPP && MFD_SYSCON && OF
help
Choose this option if you want to use Exynos FIMC for DRM.
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 4c5b6859c9e..8bcc13ac9f7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -124,7 +124,7 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
}
count = drm_add_edid_modes(connector, edid);
- if (count < 0) {
+ if (!count) {
DRM_ERROR("Add edid modes failed %d\n", count);
goto out;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index ba0a3aa7854..ff7f2a886a3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -235,7 +235,6 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
* refcount on gem itself instead of f_count of dmabuf.
*/
drm_gem_object_reference(obj);
- dma_buf_put(dma_buf);
return obj;
}
}
@@ -244,6 +243,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
if (IS_ERR(attach))
return ERR_PTR(-EINVAL);
+ get_dma_buf(dma_buf);
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
if (IS_ERR_OR_NULL(sgt)) {
@@ -298,6 +298,8 @@ err_unmap_attach:
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
err_buf_detach:
dma_buf_detach(dma_buf, attach);
+ dma_buf_put(dma_buf);
+
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 3da5c2d214d..ba6d995e437 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -380,6 +380,10 @@ static int __init exynos_drm_init(void)
ret = platform_driver_register(&ipp_driver);
if (ret < 0)
goto out_ipp;
+
+ ret = exynos_platform_device_ipp_register();
+ if (ret < 0)
+ goto out_ipp_dev;
#endif
ret = platform_driver_register(&exynos_drm_platform_driver);
@@ -388,7 +392,7 @@ static int __init exynos_drm_init(void)
exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
NULL, 0);
- if (IS_ERR_OR_NULL(exynos_drm_pdev)) {
+ if (IS_ERR(exynos_drm_pdev)) {
ret = PTR_ERR(exynos_drm_pdev);
goto out;
}
@@ -400,6 +404,8 @@ out:
out_drm:
#ifdef CONFIG_DRM_EXYNOS_IPP
+ exynos_platform_device_ipp_unregister();
+out_ipp_dev:
platform_driver_unregister(&ipp_driver);
out_ipp:
#endif
@@ -456,6 +462,7 @@ static void __exit exynos_drm_exit(void)
platform_driver_unregister(&exynos_drm_platform_driver);
#ifdef CONFIG_DRM_EXYNOS_IPP
+ exynos_platform_device_ipp_unregister();
platform_driver_unregister(&ipp_driver);
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 4606fac7241..680a7c1b9de 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -322,13 +322,23 @@ void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
* this function registers exynos drm hdmi platform device. It ensures only one
* instance of the device is created.
*/
-extern int exynos_platform_device_hdmi_register(void);
+int exynos_platform_device_hdmi_register(void);
/*
* this function unregisters exynos drm hdmi platform device if it exists.
*/
void exynos_platform_device_hdmi_unregister(void);
+/*
+ * this function registers exynos drm ipp platform device.
+ */
+int exynos_platform_device_ipp_register(void);
+
+/*
+ * this function unregisters exynos drm ipp platform device if it exists.
+ */
+void exynos_platform_device_ipp_unregister(void);
+
extern struct platform_driver fimd_driver;
extern struct platform_driver hdmi_driver;
extern struct platform_driver mixer_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 411f69b76e8..773f583fa96 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -12,11 +12,12 @@
*
*/
#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
-#include <plat/map-base.h>
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
@@ -76,6 +77,27 @@ enum fimc_wb {
FIMC_WB_B,
};
+enum {
+ FIMC_CLK_LCLK,
+ FIMC_CLK_GATE,
+ FIMC_CLK_WB_A,
+ FIMC_CLK_WB_B,
+ FIMC_CLK_MUX,
+ FIMC_CLK_PARENT,
+ FIMC_CLKS_MAX
+};
+
+static const char * const fimc_clock_names[] = {
+ [FIMC_CLK_LCLK] = "sclk_fimc",
+ [FIMC_CLK_GATE] = "fimc",
+ [FIMC_CLK_WB_A] = "pxl_async0",
+ [FIMC_CLK_WB_B] = "pxl_async1",
+ [FIMC_CLK_MUX] = "mux",
+ [FIMC_CLK_PARENT] = "parent",
+};
+
+#define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL
+
/*
* A structure of scaler.
*
@@ -119,28 +141,16 @@ struct fimc_capability {
};
/*
- * A structure of fimc driver data.
- *
- * @parent_clk: name of parent clock.
- */
-struct fimc_driverdata {
- char *parent_clk;
-};
-
-/*
* A structure of fimc context.
*
* @ippdrv: prepare initialization using ippdrv.
* @regs_res: register resources.
* @regs: memory mapped io registers.
* @lock: locking of operations.
- * @sclk_fimc_clk: fimc source clock.
- * @fimc_clk: fimc clock.
- * @wb_clk: writeback a clock.
- * @wb_b_clk: writeback b clock.
+ * @clocks: fimc clocks.
+ * @clk_frequency: LCLK clock frequency.
+ * @sysreg: handle to SYSREG block regmap.
* @sc: scaler infomations.
- * @odr: ordering of YUV.
- * @ver: fimc version.
* @pol: porarity of writeback.
* @id: fimc id.
* @irq: irq number.
@@ -151,12 +161,10 @@ struct fimc_context {
struct resource *regs_res;
void __iomem *regs;
struct mutex lock;
- struct clk *sclk_fimc_clk;
- struct clk *fimc_clk;
- struct clk *wb_clk;
- struct clk *wb_b_clk;
+ struct clk *clocks[FIMC_CLKS_MAX];
+ u32 clk_frequency;
+ struct regmap *sysreg;
struct fimc_scaler sc;
- struct fimc_driverdata *ddata;
struct exynos_drm_ipp_pol pol;
int id;
int irq;
@@ -200,17 +208,13 @@ static void fimc_sw_reset(struct fimc_context *ctx)
fimc_write(0x0, EXYNOS_CIFCNTSEQ);
}
-static void fimc_set_camblk_fimd0_wb(struct fimc_context *ctx)
+static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx)
{
- u32 camblk_cfg;
-
DRM_DEBUG_KMS("%s\n", __func__);
- camblk_cfg = readl(SYSREG_CAMERA_BLK);
- camblk_cfg &= ~(SYSREG_FIMD0WB_DEST_MASK);
- camblk_cfg |= ctx->id << (SYSREG_FIMD0WB_DEST_SHIFT);
-
- writel(camblk_cfg, SYSREG_CAMERA_BLK);
+ return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK,
+ SYSREG_FIMD0WB_DEST_MASK,
+ ctx->id << SYSREG_FIMD0WB_DEST_SHIFT);
}
static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb)
@@ -1301,14 +1305,12 @@ static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable)
DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
if (enable) {
- clk_enable(ctx->sclk_fimc_clk);
- clk_enable(ctx->fimc_clk);
- clk_enable(ctx->wb_clk);
+ clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
+ clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]);
ctx->suspended = false;
} else {
- clk_disable(ctx->sclk_fimc_clk);
- clk_disable(ctx->fimc_clk);
- clk_disable(ctx->wb_clk);
+ clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]);
+ clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]);
ctx->suspended = true;
}
@@ -1613,7 +1615,11 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
fimc_handle_lastend(ctx, true);
/* setup FIMD */
- fimc_set_camblk_fimd0_wb(ctx);
+ ret = fimc_set_camblk_fimd0_wb(ctx);
+ if (ret < 0) {
+ dev_err(dev, "camblk setup failed.\n");
+ return ret;
+ }
set_wb.enable = 1;
set_wb.refresh = property->refresh_rate;
@@ -1713,76 +1719,118 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
fimc_write(cfg, EXYNOS_CIGCTRL);
}
+static void fimc_put_clocks(struct fimc_context *ctx)
+{
+ int i;
+
+ for (i = 0; i < FIMC_CLKS_MAX; i++) {
+ if (IS_ERR(ctx->clocks[i]))
+ continue;
+ clk_put(ctx->clocks[i]);
+ ctx->clocks[i] = ERR_PTR(-EINVAL);
+ }
+}
+
+static int fimc_setup_clocks(struct fimc_context *ctx)
+{
+ struct device *fimc_dev = ctx->ippdrv.dev;
+ struct device *dev;
+ int ret, i;
+
+ for (i = 0; i < FIMC_CLKS_MAX; i++)
+ ctx->clocks[i] = ERR_PTR(-EINVAL);
+
+ for (i = 0; i < FIMC_CLKS_MAX; i++) {
+ if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B)
+ dev = fimc_dev->parent;
+ else
+ dev = fimc_dev;
+
+ ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]);
+ if (IS_ERR(ctx->clocks[i])) {
+ if (i >= FIMC_CLK_MUX)
+ break;
+ ret = PTR_ERR(ctx->clocks[i]);
+ dev_err(fimc_dev, "failed to get clock: %s\n",
+ fimc_clock_names[i]);
+ goto e_clk_free;
+ }
+ }
+
+ /* Optional FIMC LCLK parent clock setting */
+ if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) {
+ ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX],
+ ctx->clocks[FIMC_CLK_PARENT]);
+ if (ret < 0) {
+ dev_err(fimc_dev, "failed to set parent.\n");
+ goto e_clk_free;
+ }
+ }
+
+ ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency);
+ if (ret < 0)
+ goto e_clk_free;
+
+ ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]);
+ if (!ret)
+ return ret;
+e_clk_free:
+ fimc_put_clocks(ctx);
+ return ret;
+}
+
+static int fimc_parse_dt(struct fimc_context *ctx)
+{
+ struct device_node *node = ctx->ippdrv.dev->of_node;
+
+ /* Handle only devices that support the LCD Writeback data path */
+ if (!of_property_read_bool(node, "samsung,lcd-wb"))
+ return -ENODEV;
+
+ if (of_property_read_u32(node, "clock-frequency",
+ &ctx->clk_frequency))
+ ctx->clk_frequency = FIMC_DEFAULT_LCLK_FREQUENCY;
+
+ ctx->id = of_alias_get_id(node, "fimc");
+
+ if (ctx->id < 0) {
+ dev_err(ctx->ippdrv.dev, "failed to get node alias id.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int fimc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fimc_context *ctx;
- struct clk *parent_clk;
struct resource *res;
struct exynos_drm_ippdrv *ippdrv;
- struct exynos_drm_fimc_pdata *pdata;
- struct fimc_driverdata *ddata;
int ret;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(dev, "no platform data specified.\n");
- return -EINVAL;
+ if (!dev->of_node) {
+ dev_err(dev, "device tree node not found.\n");
+ return -ENODEV;
}
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
- ddata = (struct fimc_driverdata *)
- platform_get_device_id(pdev)->driver_data;
-
- /* clock control */
- ctx->sclk_fimc_clk = devm_clk_get(dev, "sclk_fimc");
- if (IS_ERR(ctx->sclk_fimc_clk)) {
- dev_err(dev, "failed to get src fimc clock.\n");
- return PTR_ERR(ctx->sclk_fimc_clk);
- }
- clk_enable(ctx->sclk_fimc_clk);
-
- ctx->fimc_clk = devm_clk_get(dev, "fimc");
- if (IS_ERR(ctx->fimc_clk)) {
- dev_err(dev, "failed to get fimc clock.\n");
- clk_disable(ctx->sclk_fimc_clk);
- return PTR_ERR(ctx->fimc_clk);
- }
-
- ctx->wb_clk = devm_clk_get(dev, "pxl_async0");
- if (IS_ERR(ctx->wb_clk)) {
- dev_err(dev, "failed to get writeback a clock.\n");
- clk_disable(ctx->sclk_fimc_clk);
- return PTR_ERR(ctx->wb_clk);
- }
-
- ctx->wb_b_clk = devm_clk_get(dev, "pxl_async1");
- if (IS_ERR(ctx->wb_b_clk)) {
- dev_err(dev, "failed to get writeback b clock.\n");
- clk_disable(ctx->sclk_fimc_clk);
- return PTR_ERR(ctx->wb_b_clk);
- }
+ ctx->ippdrv.dev = dev;
- parent_clk = devm_clk_get(dev, ddata->parent_clk);
-
- if (IS_ERR(parent_clk)) {
- dev_err(dev, "failed to get parent clock.\n");
- clk_disable(ctx->sclk_fimc_clk);
- return PTR_ERR(parent_clk);
- }
+ ret = fimc_parse_dt(ctx);
+ if (ret < 0)
+ return ret;
- if (clk_set_parent(ctx->sclk_fimc_clk, parent_clk)) {
- dev_err(dev, "failed to set parent.\n");
- clk_disable(ctx->sclk_fimc_clk);
- return -EINVAL;
+ ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,sysreg");
+ if (IS_ERR(ctx->sysreg)) {
+ dev_err(dev, "syscon regmap lookup failed.\n");
+ return PTR_ERR(ctx->sysreg);
}
- devm_clk_put(dev, parent_clk);
- clk_set_rate(ctx->sclk_fimc_clk, pdata->clk_rate);
-
/* resource memory */
ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ctx->regs = devm_ioremap_resource(dev, ctx->regs_res);
@@ -1804,13 +1852,11 @@ static int fimc_probe(struct platform_device *pdev)
return ret;
}
- /* context initailization */
- ctx->id = pdev->id;
- ctx->pol = pdata->pol;
- ctx->ddata = ddata;
+ ret = fimc_setup_clocks(ctx);
+ if (ret < 0)
+ goto err_free_irq;
ippdrv = &ctx->ippdrv;
- ippdrv->dev = dev;
ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops;
ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops;
ippdrv->check_property = fimc_ippdrv_check_property;
@@ -1820,7 +1866,7 @@ static int fimc_probe(struct platform_device *pdev)
ret = fimc_init_prop_list(ippdrv);
if (ret < 0) {
dev_err(dev, "failed to init property list.\n");
- goto err_get_irq;
+ goto err_put_clk;
}
DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
@@ -1835,17 +1881,18 @@ static int fimc_probe(struct platform_device *pdev)
ret = exynos_drm_ippdrv_register(ippdrv);
if (ret < 0) {
dev_err(dev, "failed to register drm fimc device.\n");
- goto err_ippdrv_register;
+ goto err_pm_dis;
}
dev_info(&pdev->dev, "drm fimc registered successfully.\n");
return 0;
-err_ippdrv_register:
- devm_kfree(dev, ippdrv->prop_list);
+err_pm_dis:
pm_runtime_disable(dev);
-err_get_irq:
+err_put_clk:
+ fimc_put_clocks(ctx);
+err_free_irq:
free_irq(ctx->irq, ctx);
return ret;
@@ -1857,10 +1904,10 @@ static int fimc_remove(struct platform_device *pdev)
struct fimc_context *ctx = get_fimc_context(dev);
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
- devm_kfree(dev, ippdrv->prop_list);
exynos_drm_ippdrv_unregister(ippdrv);
mutex_destroy(&ctx->lock);
+ fimc_put_clocks(ctx);
pm_runtime_set_suspended(dev);
pm_runtime_disable(dev);
@@ -1915,36 +1962,22 @@ static int fimc_runtime_resume(struct device *dev)
}
#endif
-static struct fimc_driverdata exynos4210_fimc_data = {
- .parent_clk = "mout_mpll",
-};
-
-static struct fimc_driverdata exynos4410_fimc_data = {
- .parent_clk = "mout_mpll_user",
-};
-
-static struct platform_device_id fimc_driver_ids[] = {
- {
- .name = "exynos4210-fimc",
- .driver_data = (unsigned long)&exynos4210_fimc_data,
- }, {
- .name = "exynos4412-fimc",
- .driver_data = (unsigned long)&exynos4410_fimc_data,
- },
- {},
-};
-MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
-
static const struct dev_pm_ops fimc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
};
+static const struct of_device_id fimc_of_match[] = {
+ { .compatible = "samsung,exynos4210-fimc" },
+ { .compatible = "samsung,exynos4212-fimc" },
+ { },
+};
+
struct platform_driver fimc_driver = {
.probe = fimc_probe,
.remove = fimc_remove,
- .id_table = fimc_driver_ids,
.driver = {
+ .of_match_table = fimc_of_match,
.name = "exynos-drm-fimc",
.owner = THIS_MODULE,
.pm = &fimc_pm_ops,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 98cc14725ba..746b282b343 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -20,6 +20,7 @@
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
+#include <video/of_display_timing.h>
#include <video/samsung_fimd.h>
#include <drm/exynos_drm.h>
@@ -800,18 +801,18 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
if (enable) {
int ret;
- ret = clk_enable(ctx->bus_clk);
+ ret = clk_prepare_enable(ctx->bus_clk);
if (ret < 0)
return ret;
- ret = clk_enable(ctx->lcd_clk);
+ ret = clk_prepare_enable(ctx->lcd_clk);
if (ret < 0) {
- clk_disable(ctx->bus_clk);
+ clk_disable_unprepare(ctx->bus_clk);
return ret;
}
} else {
- clk_disable(ctx->lcd_clk);
- clk_disable(ctx->bus_clk);
+ clk_disable_unprepare(ctx->lcd_clk);
+ clk_disable_unprepare(ctx->bus_clk);
}
return 0;
@@ -884,10 +885,25 @@ static int fimd_probe(struct platform_device *pdev)
DRM_DEBUG_KMS("%s\n", __FILE__);
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(dev, "no platform data specified\n");
- return -EINVAL;
+ if (pdev->dev.of_node) {
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ DRM_ERROR("memory allocation for pdata failed\n");
+ return -ENOMEM;
+ }
+
+ ret = of_get_fb_videomode(dev->of_node, &pdata->panel.timing,
+ OF_USE_NATIVE_MODE);
+ if (ret) {
+ DRM_ERROR("failed: of_get_fb_videomode() : %d\n", ret);
+ return ret;
+ }
+ } else {
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ DRM_ERROR("no platform data specified\n");
+ return -EINVAL;
+ }
}
panel = &pdata->panel;
@@ -918,7 +934,7 @@ static int fimd_probe(struct platform_device *pdev)
if (IS_ERR(ctx->regs))
return PTR_ERR(ctx->regs);
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync");
if (!res) {
dev_err(dev, "irq request failed.\n");
return -ENXIO;
@@ -980,9 +996,6 @@ static int fimd_remove(struct platform_device *pdev)
if (ctx->suspended)
goto out;
- clk_disable(ctx->lcd_clk);
- clk_disable(ctx->bus_clk);
-
pm_runtime_set_suspended(dev);
pm_runtime_put_sync(dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 0e6fe000578..cf4543ffa07 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -682,7 +682,8 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
args->pitch = args->width * ((args->bpp + 7) / 8);
args->size = args->pitch * args->height;
- exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
+ exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG |
+ EXYNOS_BO_WC, args->size);
if (IS_ERR(exynos_gem_obj))
return PTR_ERR(exynos_gem_obj);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 7c27df03c9f..ba2f0f1aa05 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -51,21 +51,27 @@ struct drm_hdmi_context {
int exynos_platform_device_hdmi_register(void)
{
+ struct platform_device *pdev;
+
if (exynos_drm_hdmi_pdev)
return -EEXIST;
- exynos_drm_hdmi_pdev = platform_device_register_simple(
+ pdev = platform_device_register_simple(
"exynos-drm-hdmi", -1, NULL, 0);
- if (IS_ERR_OR_NULL(exynos_drm_hdmi_pdev))
- return PTR_ERR(exynos_drm_hdmi_pdev);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ exynos_drm_hdmi_pdev = pdev;
return 0;
}
void exynos_platform_device_hdmi_unregister(void)
{
- if (exynos_drm_hdmi_pdev)
+ if (exynos_drm_hdmi_pdev) {
platform_device_unregister(exynos_drm_hdmi_pdev);
+ exynos_drm_hdmi_pdev = NULL;
+ }
}
void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
@@ -205,13 +211,45 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ struct drm_display_mode *m;
+ int mode_ok;
DRM_DEBUG_KMS("%s\n", __FILE__);
- if (hdmi_ops && hdmi_ops->mode_fixup)
- hdmi_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, mode,
- adjusted_mode);
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+ mode_ok = drm_hdmi_check_timing(subdrv_dev, adjusted_mode);
+
+ /* just return if user desired mode exists. */
+ if (mode_ok == 0)
+ return;
+
+ /*
+ * otherwise, find the most suitable mode among modes and change it
+ * to adjusted_mode.
+ */
+ list_for_each_entry(m, &connector->modes, head) {
+ mode_ok = drm_hdmi_check_timing(subdrv_dev, m);
+
+ if (mode_ok == 0) {
+ struct drm_mode_object base;
+ struct list_head head;
+
+ DRM_INFO("desired mode doesn't exist so\n");
+ DRM_INFO("use the most suitable mode among modes.\n");
+
+ DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
+ m->hdisplay, m->vdisplay, m->vrefresh);
+
+ /* preserve display mode header while copying. */
+ head = adjusted_mode->head;
+ base = adjusted_mode->base;
+ memcpy(adjusted_mode, m, sizeof(*m));
+ adjusted_mode->head = head;
+ adjusted_mode->base = base;
+ break;
+ }
+ }
}
static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index b7faa366230..6b709440df4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -36,9 +36,6 @@ struct exynos_hdmi_ops {
int (*power_on)(void *ctx, int mode);
/* manager */
- void (*mode_fixup)(void *ctx, struct drm_connector *connector,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
void (*mode_set)(void *ctx, void *mode);
void (*get_max_resol)(void *ctx, unsigned int *width,
unsigned int *height);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index 1adce07ecb5..29d2ad31449 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -47,6 +47,9 @@
#define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev))
#define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M)
+/* platform device pointer for ipp device. */
+static struct platform_device *exynos_drm_ipp_pdev;
+
/*
* A structure of event.
*
@@ -102,6 +105,30 @@ static LIST_HEAD(exynos_drm_ippdrv_list);
static DEFINE_MUTEX(exynos_drm_ippdrv_lock);
static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list);
+int exynos_platform_device_ipp_register(void)
+{
+ struct platform_device *pdev;
+
+ if (exynos_drm_ipp_pdev)
+ return -EEXIST;
+
+ pdev = platform_device_register_simple("exynos-drm-ipp", -1, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ exynos_drm_ipp_pdev = pdev;
+
+ return 0;
+}
+
+void exynos_platform_device_ipp_unregister(void)
+{
+ if (exynos_drm_ipp_pdev) {
+ platform_device_unregister(exynos_drm_ipp_pdev);
+ exynos_drm_ipp_pdev = NULL;
+ }
+}
+
int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
{
DRM_DEBUG_KMS("%s\n", __func__);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index a40b9fb6024..947f09f15ad 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -674,7 +674,7 @@ static int rotator_probe(struct platform_device *pdev)
}
rot->clock = devm_clk_get(dev, "rotator");
- if (IS_ERR_OR_NULL(rot->clock)) {
+ if (IS_ERR(rot->clock)) {
dev_err(dev, "failed to get clock\n");
ret = PTR_ERR(rot->clock);
goto err_clk_get;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 2c5f266154a..bbfc3840080 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -108,7 +108,20 @@ struct hdmi_tg_regs {
u8 tg_3d[1];
};
-struct hdmi_core_regs {
+struct hdmi_v13_core_regs {
+ u8 h_blank[2];
+ u8 v_blank[3];
+ u8 h_v_line[3];
+ u8 vsync_pol[1];
+ u8 int_pro_mode[1];
+ u8 v_blank_f[3];
+ u8 h_sync_gen[3];
+ u8 v_sync_gen1[3];
+ u8 v_sync_gen2[3];
+ u8 v_sync_gen3[3];
+};
+
+struct hdmi_v14_core_regs {
u8 h_blank[2];
u8 v2_blank[2];
u8 v1_blank[2];
@@ -147,11 +160,23 @@ struct hdmi_core_regs {
u8 vact_space_6[2];
};
+struct hdmi_v13_conf {
+ struct hdmi_v13_core_regs core;
+ struct hdmi_tg_regs tg;
+};
+
struct hdmi_v14_conf {
- int pixel_clock;
- struct hdmi_core_regs core;
+ struct hdmi_v14_core_regs core;
struct hdmi_tg_regs tg;
+};
+
+struct hdmi_conf_regs {
+ int pixel_clock;
int cea_video_id;
+ union {
+ struct hdmi_v13_conf v13_conf;
+ struct hdmi_v14_conf v14_conf;
+ } conf;
};
struct hdmi_context {
@@ -169,9 +194,8 @@ struct hdmi_context {
struct i2c_client *ddc_port;
struct i2c_client *hdmiphy_port;
- /* current hdmiphy conf index */
- int cur_conf;
- struct hdmi_v14_conf mode_conf;
+ /* current hdmiphy conf regs */
+ struct hdmi_conf_regs mode_conf;
struct hdmi_resources res;
@@ -180,292 +204,60 @@ struct hdmi_context {
enum hdmi_type type;
};
-/* HDMI Version 1.3 */
-static const u8 hdmiphy_v13_conf27[32] = {
- 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
- 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
- 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
-};
-
-static const u8 hdmiphy_v13_conf27_027[32] = {
- 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
- 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
- 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
-};
-
-static const u8 hdmiphy_v13_conf74_175[32] = {
- 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
- 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
- 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
-};
-
-static const u8 hdmiphy_v13_conf74_25[32] = {
- 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
- 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
- 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
- 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
-};
-
-static const u8 hdmiphy_v13_conf148_5[32] = {
- 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
- 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
- 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
-};
-
-struct hdmi_v13_tg_regs {
- u8 cmd;
- u8 h_fsz_l;
- u8 h_fsz_h;
- u8 hact_st_l;
- u8 hact_st_h;
- u8 hact_sz_l;
- u8 hact_sz_h;
- u8 v_fsz_l;
- u8 v_fsz_h;
- u8 vsync_l;
- u8 vsync_h;
- u8 vsync2_l;
- u8 vsync2_h;
- u8 vact_st_l;
- u8 vact_st_h;
- u8 vact_sz_l;
- u8 vact_sz_h;
- u8 field_chg_l;
- u8 field_chg_h;
- u8 vact_st2_l;
- u8 vact_st2_h;
- u8 vsync_top_hdmi_l;
- u8 vsync_top_hdmi_h;
- u8 vsync_bot_hdmi_l;
- u8 vsync_bot_hdmi_h;
- u8 field_top_hdmi_l;
- u8 field_top_hdmi_h;
- u8 field_bot_hdmi_l;
- u8 field_bot_hdmi_h;
-};
-
-struct hdmi_v13_core_regs {
- u8 h_blank[2];
- u8 v_blank[3];
- u8 h_v_line[3];
- u8 vsync_pol[1];
- u8 int_pro_mode[1];
- u8 v_blank_f[3];
- u8 h_sync_gen[3];
- u8 v_sync_gen1[3];
- u8 v_sync_gen2[3];
- u8 v_sync_gen3[3];
-};
-
-struct hdmi_v13_preset_conf {
- struct hdmi_v13_core_regs core;
- struct hdmi_v13_tg_regs tg;
-};
-
-struct hdmi_v13_conf {
- int width;
- int height;
- int vrefresh;
- bool interlace;
- int cea_video_id;
- const u8 *hdmiphy_data;
- const struct hdmi_v13_preset_conf *conf;
-};
-
-static const struct hdmi_v13_preset_conf hdmi_v13_conf_480p = {
- .core = {
- .h_blank = {0x8a, 0x00},
- .v_blank = {0x0d, 0x6a, 0x01},
- .h_v_line = {0x0d, 0xa2, 0x35},
- .vsync_pol = {0x01},
- .int_pro_mode = {0x00},
- .v_blank_f = {0x00, 0x00, 0x00},
- .h_sync_gen = {0x0e, 0x30, 0x11},
- .v_sync_gen1 = {0x0f, 0x90, 0x00},
- /* other don't care */
- },
- .tg = {
- 0x00, /* cmd */
- 0x5a, 0x03, /* h_fsz */
- 0x8a, 0x00, 0xd0, 0x02, /* hact */
- 0x0d, 0x02, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x2d, 0x00, 0xe0, 0x01, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x49, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
- },
-};
-
-static const struct hdmi_v13_preset_conf hdmi_v13_conf_720p60 = {
- .core = {
- .h_blank = {0x72, 0x01},
- .v_blank = {0xee, 0xf2, 0x00},
- .h_v_line = {0xee, 0x22, 0x67},
- .vsync_pol = {0x00},
- .int_pro_mode = {0x00},
- .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
- .h_sync_gen = {0x6c, 0x50, 0x02},
- .v_sync_gen1 = {0x0a, 0x50, 0x00},
- .v_sync_gen2 = {0x01, 0x10, 0x00},
- .v_sync_gen3 = {0x01, 0x10, 0x00},
- /* other don't care */
- },
- .tg = {
- 0x00, /* cmd */
- 0x72, 0x06, /* h_fsz */
- 0x71, 0x01, 0x01, 0x05, /* hact */
- 0xee, 0x02, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x1e, 0x00, 0xd0, 0x02, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x49, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
- },
-};
-
-static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i50 = {
- .core = {
- .h_blank = {0xd0, 0x02},
- .v_blank = {0x32, 0xB2, 0x00},
- .h_v_line = {0x65, 0x04, 0xa5},
- .vsync_pol = {0x00},
- .int_pro_mode = {0x01},
- .v_blank_f = {0x49, 0x2A, 0x23},
- .h_sync_gen = {0x0E, 0xEA, 0x08},
- .v_sync_gen1 = {0x07, 0x20, 0x00},
- .v_sync_gen2 = {0x39, 0x42, 0x23},
- .v_sync_gen3 = {0x38, 0x87, 0x73},
- /* other don't care */
- },
- .tg = {
- 0x00, /* cmd */
- 0x50, 0x0A, /* h_fsz */
- 0xCF, 0x02, 0x81, 0x07, /* hact */
- 0x65, 0x04, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x16, 0x00, 0x1c, 0x02, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x49, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
- },
+struct hdmiphy_config {
+ int pixel_clock;
+ u8 conf[32];
};
-static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p50 = {
- .core = {
- .h_blank = {0xd0, 0x02},
- .v_blank = {0x65, 0x6c, 0x01},
- .h_v_line = {0x65, 0x04, 0xa5},
- .vsync_pol = {0x00},
- .int_pro_mode = {0x00},
- .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
- .h_sync_gen = {0x0e, 0xea, 0x08},
- .v_sync_gen1 = {0x09, 0x40, 0x00},
- .v_sync_gen2 = {0x01, 0x10, 0x00},
- .v_sync_gen3 = {0x01, 0x10, 0x00},
- /* other don't care */
- },
- .tg = {
- 0x00, /* cmd */
- 0x50, 0x0A, /* h_fsz */
- 0xCF, 0x02, 0x81, 0x07, /* hact */
- 0x65, 0x04, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x2d, 0x00, 0x38, 0x04, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x48, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+/* list of phy config settings */
+static const struct hdmiphy_config hdmiphy_v13_configs[] = {
+ {
+ .pixel_clock = 27000000,
+ .conf = {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+ 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
+ },
},
-};
-
-static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i60 = {
- .core = {
- .h_blank = {0x18, 0x01},
- .v_blank = {0x32, 0xB2, 0x00},
- .h_v_line = {0x65, 0x84, 0x89},
- .vsync_pol = {0x00},
- .int_pro_mode = {0x01},
- .v_blank_f = {0x49, 0x2A, 0x23},
- .h_sync_gen = {0x56, 0x08, 0x02},
- .v_sync_gen1 = {0x07, 0x20, 0x00},
- .v_sync_gen2 = {0x39, 0x42, 0x23},
- .v_sync_gen3 = {0xa4, 0x44, 0x4a},
- /* other don't care */
+ {
+ .pixel_clock = 27027000,
+ .conf = {
+ 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
+ 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
+ },
},
- .tg = {
- 0x00, /* cmd */
- 0x98, 0x08, /* h_fsz */
- 0x17, 0x01, 0x81, 0x07, /* hact */
- 0x65, 0x04, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x16, 0x00, 0x1c, 0x02, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x49, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ {
+ .pixel_clock = 74176000,
+ .conf = {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
+ 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
+ },
},
-};
-
-static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p60 = {
- .core = {
- .h_blank = {0x18, 0x01},
- .v_blank = {0x65, 0x6c, 0x01},
- .h_v_line = {0x65, 0x84, 0x89},
- .vsync_pol = {0x00},
- .int_pro_mode = {0x00},
- .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
- .h_sync_gen = {0x56, 0x08, 0x02},
- .v_sync_gen1 = {0x09, 0x40, 0x00},
- .v_sync_gen2 = {0x01, 0x10, 0x00},
- .v_sync_gen3 = {0x01, 0x10, 0x00},
- /* other don't care */
+ {
+ .pixel_clock = 74250000,
+ .conf = {
+ 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
+ 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
+ 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
+ 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
+ },
},
- .tg = {
- 0x00, /* cmd */
- 0x98, 0x08, /* h_fsz */
- 0x17, 0x01, 0x81, 0x07, /* hact */
- 0x65, 0x04, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x2d, 0x00, 0x38, 0x04, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x48, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ {
+ .pixel_clock = 148500000,
+ .conf = {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
+ 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
+ 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
+ },
},
};
-static const struct hdmi_v13_conf hdmi_v13_confs[] = {
- { 1280, 720, 60, false, 4, hdmiphy_v13_conf74_25,
- &hdmi_v13_conf_720p60 },
- { 1280, 720, 50, false, 19, hdmiphy_v13_conf74_25,
- &hdmi_v13_conf_720p60 },
- { 720, 480, 60, false, 3, hdmiphy_v13_conf27_027,
- &hdmi_v13_conf_480p },
- { 1920, 1080, 50, true, 20, hdmiphy_v13_conf74_25,
- &hdmi_v13_conf_1080i50 },
- { 1920, 1080, 50, false, 31, hdmiphy_v13_conf148_5,
- &hdmi_v13_conf_1080p50 },
- { 1920, 1080, 60, true, 5, hdmiphy_v13_conf74_25,
- &hdmi_v13_conf_1080i60 },
- { 1920, 1080, 60, false, 16, hdmiphy_v13_conf148_5,
- &hdmi_v13_conf_1080p60 },
-};
-
-/* HDMI Version 1.4 */
-struct hdmiphy_config {
- int pixel_clock;
- u8 conf[32];
-};
-
-/* list of all required phy config settings */
static const struct hdmiphy_config hdmiphy_v14_configs[] = {
{
.pixel_clock = 25200000,
@@ -873,22 +665,6 @@ static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
hdmi_v14_regs_dump(hdata, prefix);
}
-static int hdmi_v13_conf_index(struct drm_display_mode *mode)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
- if (hdmi_v13_confs[i].width == mode->hdisplay &&
- hdmi_v13_confs[i].height == mode->vdisplay &&
- hdmi_v13_confs[i].vrefresh == mode->vrefresh &&
- hdmi_v13_confs[i].interlace ==
- ((mode->flags & DRM_MODE_FLAG_INTERLACE) ?
- true : false))
- return i;
-
- return -EINVAL;
-}
-
static u8 hdmi_chksum(struct hdmi_context *hdata,
u32 start, u8 len, u32 hdr_sum)
{
@@ -943,11 +719,7 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), aspect_ratio |
AVI_SAME_AS_PIC_ASPECT_RATIO);
- if (hdata->type == HDMI_TYPE13)
- vic = hdmi_v13_confs[hdata->cur_conf].cea_video_id;
- else
- vic = hdata->mode_conf.cea_video_id;
-
+ vic = hdata->mode_conf.cea_video_id;
hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
@@ -1000,63 +772,34 @@ static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
return raw_edid;
}
-static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
+static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
{
- int i;
+ const struct hdmiphy_config *confs;
+ int count, i;
- DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
- check_timing->xres, check_timing->yres,
- check_timing->refresh, (check_timing->vmode &
- FB_VMODE_INTERLACED) ? true : false);
-
- for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
- if (hdmi_v13_confs[i].width == check_timing->xres &&
- hdmi_v13_confs[i].height == check_timing->yres &&
- hdmi_v13_confs[i].vrefresh == check_timing->refresh &&
- hdmi_v13_confs[i].interlace ==
- ((check_timing->vmode & FB_VMODE_INTERLACED) ?
- true : false))
- return 0;
-
- /* TODO */
-
- return -EINVAL;
-}
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-static int hdmi_v14_find_phy_conf(int pixel_clock)
-{
- int i;
+ if (hdata->type == HDMI_TYPE13) {
+ confs = hdmiphy_v13_configs;
+ count = ARRAY_SIZE(hdmiphy_v13_configs);
+ } else if (hdata->type == HDMI_TYPE14) {
+ confs = hdmiphy_v14_configs;
+ count = ARRAY_SIZE(hdmiphy_v14_configs);
+ } else
+ return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(hdmiphy_v14_configs); i++) {
- if (hdmiphy_v14_configs[i].pixel_clock == pixel_clock)
+ for (i = 0; i < count; i++)
+ if (confs[i].pixel_clock == pixel_clock)
return i;
- }
DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
return -EINVAL;
}
-static int hdmi_v14_check_timing(struct fb_videomode *check_timing)
-{
- int i;
-
- DRM_DEBUG_KMS("mode: xres=%d, yres=%d, refresh=%d, clock=%d, intl=%d\n",
- check_timing->xres, check_timing->yres,
- check_timing->refresh, check_timing->pixclock,
- (check_timing->vmode & FB_VMODE_INTERLACED) ?
- true : false);
-
- for (i = 0; i < ARRAY_SIZE(hdmiphy_v14_configs); i++)
- if (hdmiphy_v14_configs[i].pixel_clock ==
- check_timing->pixclock)
- return 0;
-
- return -EINVAL;
-}
-
static int hdmi_check_timing(void *ctx, struct fb_videomode *timing)
{
struct hdmi_context *hdata = ctx;
+ int ret;
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
@@ -1064,10 +807,10 @@ static int hdmi_check_timing(void *ctx, struct fb_videomode *timing)
timing->yres, timing->refresh,
timing->vmode);
- if (hdata->type == HDMI_TYPE13)
- return hdmi_v13_check_timing(timing);
- else
- return hdmi_v14_check_timing(timing);
+ ret = hdmi_find_phy_conf(hdata, timing->pixclock);
+ if (ret < 0)
+ return ret;
+ return 0;
}
static void hdmi_set_acr(u32 freq, u8 *acr)
@@ -1301,10 +1044,9 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
{
- const struct hdmi_v13_preset_conf *conf =
- hdmi_v13_confs[hdata->cur_conf].conf;
- const struct hdmi_v13_core_regs *core = &conf->core;
- const struct hdmi_v13_tg_regs *tg = &conf->tg;
+ const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
+ const struct hdmi_v13_core_regs *core =
+ &hdata->mode_conf.conf.v13_conf.core;
int tries;
/* setting core registers */
@@ -1334,34 +1076,34 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
/* Timing generator registers */
- hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
- hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
- hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l);
- hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h);
- hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
- hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
- hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
- hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+ hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
+ hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
+ hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
/* waiting for HDMIPHY's PLL to get to steady state */
for (tries = 100; tries; --tries) {
@@ -1391,8 +1133,9 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
{
- struct hdmi_core_regs *core = &hdata->mode_conf.core;
- struct hdmi_tg_regs *tg = &hdata->mode_conf.tg;
+ const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
+ const struct hdmi_v14_core_regs *core =
+ &hdata->mode_conf.conf.v14_conf.core;
int tries;
/* setting core registers */
@@ -1624,17 +1367,16 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
}
/* pixel clock */
- if (hdata->type == HDMI_TYPE13) {
- hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data;
- } else {
- i = hdmi_v14_find_phy_conf(hdata->mode_conf.pixel_clock);
- if (i < 0) {
- DRM_ERROR("failed to find hdmiphy conf\n");
- return;
- }
+ i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
+ if (i < 0) {
+ DRM_ERROR("failed to find hdmiphy conf\n");
+ return;
+ }
+ if (hdata->type == HDMI_TYPE13)
+ hdmiphy_data = hdmiphy_v13_configs[i].conf;
+ else
hdmiphy_data = hdmiphy_v14_configs[i].conf;
- }
memcpy(buffer, hdmiphy_data, 32);
ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
@@ -1687,75 +1429,121 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
hdmi_regs_dump(hdata, "start");
}
-static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
{
- struct drm_display_mode *m;
- struct hdmi_context *hdata = ctx;
- int index;
+ int i;
+ BUG_ON(num_bytes > 4);
+ for (i = 0; i < num_bytes; i++)
+ reg_pair[i] = (value >> (8 * i)) & 0xff;
+}
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+static void hdmi_v13_mode_set(struct hdmi_context *hdata,
+ struct drm_display_mode *m)
+{
+ struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
+ struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
+ unsigned int val;
- drm_mode_set_crtcinfo(adjusted_mode, 0);
+ hdata->mode_conf.cea_video_id =
+ drm_match_cea_mode((struct drm_display_mode *)m);
+ hdata->mode_conf.pixel_clock = m->clock * 1000;
- if (hdata->type == HDMI_TYPE13)
- index = hdmi_v13_conf_index(adjusted_mode);
- else
- index = hdmi_v14_find_phy_conf(adjusted_mode->clock * 1000);
+ hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
+ hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
- /* just return if user desired mode exists. */
- if (index >= 0)
- return;
+ val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
+ hdmi_set_reg(core->vsync_pol, 1, val);
+
+ val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
+ hdmi_set_reg(core->int_pro_mode, 1, val);
+
+ val = (m->hsync_start - m->hdisplay - 2);
+ val |= ((m->hsync_end - m->hdisplay - 2) << 10);
+ val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
+ hdmi_set_reg(core->h_sync_gen, 3, val);
/*
- * otherwise, find the most suitable mode among modes and change it
- * to adjusted_mode.
+ * Quirk requirement for exynos HDMI IP design,
+ * 2 pixels less than the actual calculation for hsync_start
+ * and end.
*/
- list_for_each_entry(m, &connector->modes, head) {
- if (hdata->type == HDMI_TYPE13)
- index = hdmi_v13_conf_index(m);
- else
- index = hdmi_v14_find_phy_conf(m->clock * 1000);
-
- if (index >= 0) {
- struct drm_mode_object base;
- struct list_head head;
-
- DRM_INFO("desired mode doesn't exist so\n");
- DRM_INFO("use the most suitable mode among modes.\n");
-
- DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
- m->hdisplay, m->vdisplay, m->vrefresh);
-
- /* preserve display mode header while copying. */
- head = adjusted_mode->head;
- base = adjusted_mode->base;
- memcpy(adjusted_mode, m, sizeof(*m));
- adjusted_mode->head = head;
- adjusted_mode->base = base;
- break;
- }
+
+ /* Following values & calculations differ for different type of modes */
+ if (m->flags & DRM_MODE_FLAG_INTERLACE) {
+ /* Interlaced Mode */
+ val = ((m->vsync_end - m->vdisplay) / 2);
+ val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
+ hdmi_set_reg(core->v_sync_gen1, 3, val);
+
+ val = m->vtotal / 2;
+ val |= ((m->vtotal - m->vdisplay) / 2) << 11;
+ hdmi_set_reg(core->v_blank, 3, val);
+
+ val = (m->vtotal +
+ ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
+ val |= m->vtotal << 11;
+ hdmi_set_reg(core->v_blank_f, 3, val);
+
+ val = ((m->vtotal / 2) + 7);
+ val |= ((m->vtotal / 2) + 2) << 12;
+ hdmi_set_reg(core->v_sync_gen2, 3, val);
+
+ val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
+ val |= ((m->htotal / 2) +
+ (m->hsync_start - m->hdisplay)) << 12;
+ hdmi_set_reg(core->v_sync_gen3, 3, val);
+
+ hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
+ hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
+
+ hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
+ } else {
+ /* Progressive Mode */
+
+ val = m->vtotal;
+ val |= (m->vtotal - m->vdisplay) << 11;
+ hdmi_set_reg(core->v_blank, 3, val);
+
+ hdmi_set_reg(core->v_blank_f, 3, 0);
+
+ val = (m->vsync_end - m->vdisplay);
+ val |= ((m->vsync_start - m->vdisplay) << 12);
+ hdmi_set_reg(core->v_sync_gen1, 3, val);
+
+ hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
+ hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
+ hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
+ hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
+ hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
}
-}
-static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
-{
- int i;
- BUG_ON(num_bytes > 4);
- for (i = 0; i < num_bytes; i++)
- reg_pair[i] = (value >> (8 * i)) & 0xff;
+ /* Timing generator registers */
+ hdmi_set_reg(tg->cmd, 1, 0x0);
+ hdmi_set_reg(tg->h_fsz, 2, m->htotal);
+ hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
+ hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
+ hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
+ hdmi_set_reg(tg->vsync, 2, 0x1);
+ hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
+ hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
+ hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
+ hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
+ hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
+ hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
+ hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
}
static void hdmi_v14_mode_set(struct hdmi_context *hdata,
struct drm_display_mode *m)
{
- struct hdmi_core_regs *core = &hdata->mode_conf.core;
- struct hdmi_tg_regs *tg = &hdata->mode_conf.tg;
-
- hdata->mode_conf.cea_video_id = drm_match_cea_mode(m);
+ struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
+ struct hdmi_v14_core_regs *core =
+ &hdata->mode_conf.conf.v14_conf.core;
+ hdata->mode_conf.cea_video_id =
+ drm_match_cea_mode((struct drm_display_mode *)m);
hdata->mode_conf.pixel_clock = m->clock * 1000;
+
hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
hdmi_set_reg(core->v_line, 2, m->vtotal);
hdmi_set_reg(core->h_line, 2, m->htotal);
@@ -1852,25 +1640,22 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
hdmi_set_reg(tg->tg_3d, 1, 0x0);
-
}
static void hdmi_mode_set(void *ctx, void *mode)
{
struct hdmi_context *hdata = ctx;
- int conf_idx;
+ struct drm_display_mode *m = mode;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+ DRM_DEBUG_KMS("[%s]: xres=%d, yres=%d, refresh=%d, intl=%s\n",
+ __func__, m->hdisplay, m->vdisplay,
+ m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
+ "INTERLACED" : "PROGERESSIVE");
- if (hdata->type == HDMI_TYPE13) {
- conf_idx = hdmi_v13_conf_index(mode);
- if (conf_idx >= 0)
- hdata->cur_conf = conf_idx;
- else
- DRM_DEBUG_KMS("not supported mode\n");
- } else {
+ if (hdata->type == HDMI_TYPE13)
+ hdmi_v13_mode_set(hdata, mode);
+ else
hdmi_v14_mode_set(hdata, mode);
- }
}
static void hdmi_get_max_resol(void *ctx, unsigned int *width,
@@ -1983,7 +1768,6 @@ static struct exynos_hdmi_ops hdmi_ops = {
.check_timing = hdmi_check_timing,
/* manager */
- .mode_fixup = hdmi_mode_fixup,
.mode_set = hdmi_mode_set,
.get_max_resol = hdmi_get_max_resol,
.commit = hdmi_commit,
@@ -2023,27 +1807,27 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
/* get clocks, power */
res->hdmi = devm_clk_get(dev, "hdmi");
- if (IS_ERR_OR_NULL(res->hdmi)) {
+ if (IS_ERR(res->hdmi)) {
DRM_ERROR("failed to get clock 'hdmi'\n");
goto fail;
}
res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
- if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+ if (IS_ERR(res->sclk_hdmi)) {
DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
goto fail;
}
res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
- if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+ if (IS_ERR(res->sclk_pixel)) {
DRM_ERROR("failed to get clock 'sclk_pixel'\n");
goto fail;
}
res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
- if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+ if (IS_ERR(res->sclk_hdmiphy)) {
DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
goto fail;
}
res->hdmiphy = devm_clk_get(dev, "hdmiphy");
- if (IS_ERR_OR_NULL(res->hdmiphy)) {
+ if (IS_ERR(res->hdmiphy)) {
DRM_ERROR("failed to get clock 'hdmiphy'\n");
goto fail;
}
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 2f4f72f0704..ec3e376b7e0 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -643,12 +643,14 @@ static void mixer_win_reset(struct mixer_context *ctx)
/* setting graphical layers */
val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
val |= MXR_GRP_CFG_WIN_BLEND_EN;
- val |= MXR_GRP_CFG_BLEND_PRE_MUL;
- val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
- /* the same configuration for both layers */
+ /* Don't blend layer 0 onto the mixer background */
mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
+
+ /* Blend layer 1 into layer 0 */
+ val |= MXR_GRP_CFG_BLEND_PRE_MUL;
+ val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
/* setting video layers */
@@ -820,7 +822,6 @@ static void mixer_win_disable(void *ctx, int win)
static int mixer_check_timing(void *ctx, struct fb_videomode *timing)
{
- struct mixer_context *mixer_ctx = ctx;
u32 w, h;
w = timing->xres;
@@ -831,9 +832,6 @@ static int mixer_check_timing(void *ctx, struct fb_videomode *timing)
timing->refresh, (timing->vmode &
FB_VMODE_INTERLACED) ? true : false);
- if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16)
- return 0;
-
if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
(w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
@@ -1047,13 +1045,13 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
spin_lock_init(&mixer_res->reg_slock);
mixer_res->mixer = devm_clk_get(dev, "mixer");
- if (IS_ERR_OR_NULL(mixer_res->mixer)) {
+ if (IS_ERR(mixer_res->mixer)) {
dev_err(dev, "failed to get clock 'mixer'\n");
return -ENODEV;
}
mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
- if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
+ if (IS_ERR(mixer_res->sclk_hdmi)) {
dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
return -ENODEV;
}
@@ -1096,17 +1094,17 @@ static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
struct resource *res;
mixer_res->vp = devm_clk_get(dev, "vp");
- if (IS_ERR_OR_NULL(mixer_res->vp)) {
+ if (IS_ERR(mixer_res->vp)) {
dev_err(dev, "failed to get clock 'vp'\n");
return -ENODEV;
}
mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
- if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
+ if (IS_ERR(mixer_res->sclk_mixer)) {
dev_err(dev, "failed to get clock 'sclk_mixer'\n");
return -ENODEV;
}
mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
- if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
+ if (IS_ERR(mixer_res->sclk_dac)) {
dev_err(dev, "failed to get clock 'sclk_dac'\n");
return -ENODEV;
}
diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h
index b4f9ca1fd85..30496134a3d 100644
--- a/drivers/gpu/drm/exynos/regs-fimc.h
+++ b/drivers/gpu/drm/exynos/regs-fimc.h
@@ -661,9 +661,8 @@
#define EXYNOS_CLKSRC_SCLK (1 << 1)
/* SYSREG for FIMC writeback */
-#define SYSREG_CAMERA_BLK (S3C_VA_SYS + 0x0218)
-#define SYSREG_ISP_BLK (S3C_VA_SYS + 0x020c)
-#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23)
-#define SYSREG_FIMD0WB_DEST_SHIFT 23
+#define SYSREG_CAMERA_BLK (0x0218)
+#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23)
+#define SYSREG_FIMD0WB_DEST_SHIFT 23
#endif /* EXYNOS_REGS_FIMC_H */
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index 1188f0fe7e4..1f6e2dfaaea 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -2,10 +2,15 @@ config DRM_GMA500
tristate "Intel GMA5/600 KMS Framebuffer"
depends on DRM && PCI && X86
select FB_CFB_COPYAREA
- select FB_CFB_FILLRECT
- select FB_CFB_IMAGEBLIT
- select DRM_KMS_HELPER
- select DRM_TTM
+ select FB_CFB_FILLRECT
+ select FB_CFB_IMAGEBLIT
+ select DRM_KMS_HELPER
+ select DRM_TTM
+ # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
+ select ACPI_VIDEO if ACPI
+ select BACKLIGHT_CLASS_DEVICE if ACPI
+ select VIDEO_OUTPUT_CONTROL if ACPI
+ select INPUT if ACPI
help
Say yes for an experimental 2D KMS framebuffer driver for the
Intel GMA500 ('Poulsbo') and other Intel IMG based graphics
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index 8c175345d85..7b8386fc302 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -276,6 +276,7 @@ void cdv_intel_crt_init(struct drm_device *dev,
goto failed_connector;
connector = &psb_intel_connector->base;
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_init(dev, connector,
&cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index e223b500022..464153d9d2d 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -319,6 +319,7 @@ void cdv_hdmi_init(struct drm_device *dev,
goto err_priv;
connector = &psb_intel_connector->base;
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
encoder = &psb_intel_encoder->base;
drm_connector_init(dev, connector,
&cdv_hdmi_connector_funcs,
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 2590cac8425..1534e220097 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -431,7 +431,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
fbdev->psb_fb_helper.fbdev = info;
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
- strcpy(info->fix.id, "psbfb");
+ strcpy(info->fix.id, "psbdrmfb");
info->flags = FBINFO_DEFAULT;
if (dev_priv->ops->accel_2d && pitch_lines > 8) /* 2D engine */
@@ -772,8 +772,8 @@ void psb_modeset_init(struct drm_device *dev)
for (i = 0; i < dev_priv->num_pipe; i++)
psb_intel_crtc_init(dev, i, mode_dev);
- dev->mode_config.max_width = 2048;
- dev->mode_config.max_height = 2048;
+ dev->mode_config.max_width = 4096;
+ dev->mode_config.max_height = 4096;
psb_setup_outputs(dev);
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index 054e26e769e..1f82183536a 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -80,7 +80,8 @@ static u32 __iomem *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
* the GTT. This is protected via the gtt mutex which the caller
* must hold.
*/
-static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
+static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r,
+ int resume)
{
u32 __iomem *gtt_slot;
u32 pte;
@@ -97,8 +98,10 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
gtt_slot = psb_gtt_entry(dev, r);
pages = r->pages;
- /* Make sure changes are visible to the GPU */
- set_pages_array_wc(pages, r->npage);
+ if (!resume) {
+ /* Make sure changes are visible to the GPU */
+ set_pages_array_wc(pages, r->npage);
+ }
/* Write our page entries into the GTT itself */
for (i = r->roll; i < r->npage; i++) {
@@ -269,7 +272,7 @@ int psb_gtt_pin(struct gtt_range *gt)
ret = psb_gtt_attach_pages(gt);
if (ret < 0)
goto out;
- ret = psb_gtt_insert(dev, gt);
+ ret = psb_gtt_insert(dev, gt, 0);
if (ret < 0) {
psb_gtt_detach_pages(gt);
goto out;
@@ -421,9 +424,11 @@ int psb_gtt_init(struct drm_device *dev, int resume)
int ret = 0;
uint32_t pte;
- mutex_init(&dev_priv->gtt_mutex);
+ if (!resume) {
+ mutex_init(&dev_priv->gtt_mutex);
+ psb_gtt_alloc(dev);
+ }
- psb_gtt_alloc(dev);
pg = &dev_priv->gtt;
/* Enable the GTT */
@@ -505,7 +510,8 @@ int psb_gtt_init(struct drm_device *dev, int resume)
/*
* Map the GTT and the stolen memory area
*/
- dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start,
+ if (!resume)
+ dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start,
gtt_pages << PAGE_SHIFT);
if (!dev_priv->gtt_map) {
dev_err(dev->dev, "Failure to map gtt.\n");
@@ -513,7 +519,9 @@ int psb_gtt_init(struct drm_device *dev, int resume)
goto out_err;
}
- dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size);
+ if (!resume)
+ dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base,
+ stolen_size);
if (!dev_priv->vram_addr) {
dev_err(dev->dev, "Failure to map stolen base.\n");
ret = -ENOMEM;
@@ -549,3 +557,31 @@ out_err:
psb_gtt_takedown(dev);
return ret;
}
+
+int psb_gtt_restore(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct resource *r = dev_priv->gtt_mem->child;
+ struct gtt_range *range;
+ unsigned int restored = 0, total = 0, size = 0;
+
+ /* On resume, the gtt_mutex is already initialized */
+ mutex_lock(&dev_priv->gtt_mutex);
+ psb_gtt_init(dev, 1);
+
+ while (r != NULL) {
+ range = container_of(r, struct gtt_range, resource);
+ if (range->pages) {
+ psb_gtt_insert(dev, range, 1);
+ size += range->resource.end - range->resource.start;
+ restored++;
+ }
+ r = r->sibling;
+ total++;
+ }
+ mutex_unlock(&dev_priv->gtt_mutex);
+ DRM_DEBUG_DRIVER("Restored %u of %u gtt ranges (%u KB)", restored,
+ total, (size / 1024));
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h
index aa1742387f5..6191d10acf3 100644
--- a/drivers/gpu/drm/gma500/gtt.h
+++ b/drivers/gpu/drm/gma500/gtt.h
@@ -60,5 +60,5 @@ extern int psb_gtt_pin(struct gtt_range *gt);
extern void psb_gtt_unpin(struct gtt_range *gt);
extern void psb_gtt_roll(struct drm_device *dev,
struct gtt_range *gt, int roll);
-
+extern int psb_gtt_restore(struct drm_device *dev);
#endif
diff --git a/drivers/gpu/drm/gma500/intel_bios.c b/drivers/gpu/drm/gma500/intel_bios.c
index 403fffb03ab..d3497348c4d 100644
--- a/drivers/gpu/drm/gma500/intel_bios.c
+++ b/drivers/gpu/drm/gma500/intel_bios.c
@@ -218,12 +218,11 @@ static void parse_backlight_data(struct drm_psb_private *dev_priv,
bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT);
vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start + 1) + p_type;
- lvds_bl = kzalloc(sizeof(*vbt_lvds_bl), GFP_KERNEL);
+ lvds_bl = kmemdup(vbt_lvds_bl, sizeof(*vbt_lvds_bl), GFP_KERNEL);
if (!lvds_bl) {
dev_err(dev_priv->dev->dev, "out of memory for backlight data\n");
return;
}
- memcpy(lvds_bl, vbt_lvds_bl, sizeof(*vbt_lvds_bl));
dev_priv->lvds_bl = lvds_bl;
}
diff --git a/drivers/gpu/drm/gma500/intel_bios.h b/drivers/gpu/drm/gma500/intel_bios.h
index c6267c98c9e..978ae4b25e8 100644
--- a/drivers/gpu/drm/gma500/intel_bios.h
+++ b/drivers/gpu/drm/gma500/intel_bios.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef _I830_BIOS_H_
-#define _I830_BIOS_H_
+#ifndef _INTEL_BIOS_H_
+#define _INTEL_BIOS_H_
#include <drm/drmP.h>
#include <drm/drm_dp_helper.h>
@@ -618,4 +618,4 @@ extern void psb_intel_destroy_bios(struct drm_device *dev);
#define PORT_IDPC 8
#define PORT_IDPD 9
-#endif /* _I830_BIOS_H_ */
+#endif /* _INTEL_BIOS_H_ */
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index 2d4ab48f07a..3abf8315f57 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -92,8 +92,8 @@ void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe)
{
struct mdfld_dsi_pkg_sender *sender =
mdfld_dsi_get_pkg_sender(dsi_config);
- struct drm_device *dev = sender->dev;
- struct drm_psb_private *dev_priv = dev->dev_private;
+ struct drm_device *dev;
+ struct drm_psb_private *dev_priv;
u32 gen_ctrl_val;
if (!sender) {
@@ -101,6 +101,9 @@ void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe)
return;
}
+ dev = sender->dev;
+ dev_priv = dev->dev_private;
+
/* Set default display backlight value to 85% (0xd8)*/
mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1,
true);
diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c
index 889b854751d..b6b135fcd59 100644
--- a/drivers/gpu/drm/gma500/power.c
+++ b/drivers/gpu/drm/gma500/power.c
@@ -110,6 +110,8 @@ static void gma_resume_display(struct pci_dev *pdev)
PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
pci_write_config_word(pdev, PSB_GMCH_CTRL,
dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED);
+
+ psb_gtt_restore(dev); /* Rebuild our GTT mappings */
dev_priv->ops->restore_regs(dev);
}
@@ -313,3 +315,18 @@ int psb_runtime_idle(struct device *dev)
else
return 1;
}
+
+int gma_power_thaw(struct device *_dev)
+{
+ return gma_power_resume(_dev);
+}
+
+int gma_power_freeze(struct device *_dev)
+{
+ return gma_power_suspend(_dev);
+}
+
+int gma_power_restore(struct device *_dev)
+{
+ return gma_power_resume(_dev);
+}
diff --git a/drivers/gpu/drm/gma500/power.h b/drivers/gpu/drm/gma500/power.h
index 1969d2ecb32..56d8708bd41 100644
--- a/drivers/gpu/drm/gma500/power.h
+++ b/drivers/gpu/drm/gma500/power.h
@@ -41,6 +41,9 @@ void gma_power_uninit(struct drm_device *dev);
*/
int gma_power_suspend(struct device *dev);
int gma_power_resume(struct device *dev);
+int gma_power_thaw(struct device *dev);
+int gma_power_freeze(struct device *dev);
+int gma_power_restore(struct device *_dev);
/*
* These are the functions the driver should use to wrap all hw access
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 111e3df9c5d..bddea580744 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -601,6 +601,9 @@ static void psb_remove(struct pci_dev *pdev)
static const struct dev_pm_ops psb_pm_ops = {
.resume = gma_power_resume,
.suspend = gma_power_suspend,
+ .thaw = gma_power_thaw,
+ .freeze = gma_power_freeze,
+ .restore = gma_power_restore,
.runtime_suspend = psb_runtime_suspend,
.runtime_resume = psb_runtime_resume,
.runtime_idle = psb_runtime_idle,
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index a7fd6c48b79..6053b8abcd1 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -876,7 +876,6 @@ extern const struct psb_ops cdv_chip_ops;
#define PSB_D_MSVDX (1 << 9)
#define PSB_D_TOPAZ (1 << 10)
-extern int drm_psb_no_fb;
extern int drm_idle_check_interval;
/*
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 9edb1902a09..6e8f42b61ff 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -50,119 +50,41 @@ struct psb_intel_p2_t {
int p2_slow, p2_fast;
};
-#define INTEL_P2_NUM 2
-
struct psb_intel_limit_t {
struct psb_intel_range_t dot, vco, n, m, m1, m2, p, p1;
struct psb_intel_p2_t p2;
};
-#define I8XX_DOT_MIN 25000
-#define I8XX_DOT_MAX 350000
-#define I8XX_VCO_MIN 930000
-#define I8XX_VCO_MAX 1400000
-#define I8XX_N_MIN 3
-#define I8XX_N_MAX 16
-#define I8XX_M_MIN 96
-#define I8XX_M_MAX 140
-#define I8XX_M1_MIN 18
-#define I8XX_M1_MAX 26
-#define I8XX_M2_MIN 6
-#define I8XX_M2_MAX 16
-#define I8XX_P_MIN 4
-#define I8XX_P_MAX 128
-#define I8XX_P1_MIN 2
-#define I8XX_P1_MAX 33
-#define I8XX_P1_LVDS_MIN 1
-#define I8XX_P1_LVDS_MAX 6
-#define I8XX_P2_SLOW 4
-#define I8XX_P2_FAST 2
-#define I8XX_P2_LVDS_SLOW 14
-#define I8XX_P2_LVDS_FAST 14 /* No fast option */
-#define I8XX_P2_SLOW_LIMIT 165000
-
-#define I9XX_DOT_MIN 20000
-#define I9XX_DOT_MAX 400000
-#define I9XX_VCO_MIN 1400000
-#define I9XX_VCO_MAX 2800000
-#define I9XX_N_MIN 1
-#define I9XX_N_MAX 6
-#define I9XX_M_MIN 70
-#define I9XX_M_MAX 120
-#define I9XX_M1_MIN 8
-#define I9XX_M1_MAX 18
-#define I9XX_M2_MIN 3
-#define I9XX_M2_MAX 7
-#define I9XX_P_SDVO_DAC_MIN 5
-#define I9XX_P_SDVO_DAC_MAX 80
-#define I9XX_P_LVDS_MIN 7
-#define I9XX_P_LVDS_MAX 98
-#define I9XX_P1_MIN 1
-#define I9XX_P1_MAX 8
-#define I9XX_P2_SDVO_DAC_SLOW 10
-#define I9XX_P2_SDVO_DAC_FAST 5
-#define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000
-#define I9XX_P2_LVDS_SLOW 14
-#define I9XX_P2_LVDS_FAST 7
-#define I9XX_P2_LVDS_SLOW_LIMIT 112000
-
-#define INTEL_LIMIT_I8XX_DVO_DAC 0
-#define INTEL_LIMIT_I8XX_LVDS 1
-#define INTEL_LIMIT_I9XX_SDVO_DAC 2
-#define INTEL_LIMIT_I9XX_LVDS 3
+#define INTEL_LIMIT_I9XX_SDVO_DAC 0
+#define INTEL_LIMIT_I9XX_LVDS 1
static const struct psb_intel_limit_t psb_intel_limits[] = {
- { /* INTEL_LIMIT_I8XX_DVO_DAC */
- .dot = {.min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX},
- .vco = {.min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX},
- .n = {.min = I8XX_N_MIN, .max = I8XX_N_MAX},
- .m = {.min = I8XX_M_MIN, .max = I8XX_M_MAX},
- .m1 = {.min = I8XX_M1_MIN, .max = I8XX_M1_MAX},
- .m2 = {.min = I8XX_M2_MIN, .max = I8XX_M2_MAX},
- .p = {.min = I8XX_P_MIN, .max = I8XX_P_MAX},
- .p1 = {.min = I8XX_P1_MIN, .max = I8XX_P1_MAX},
- .p2 = {.dot_limit = I8XX_P2_SLOW_LIMIT,
- .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST},
- },
- { /* INTEL_LIMIT_I8XX_LVDS */
- .dot = {.min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX},
- .vco = {.min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX},
- .n = {.min = I8XX_N_MIN, .max = I8XX_N_MAX},
- .m = {.min = I8XX_M_MIN, .max = I8XX_M_MAX},
- .m1 = {.min = I8XX_M1_MIN, .max = I8XX_M1_MAX},
- .m2 = {.min = I8XX_M2_MIN, .max = I8XX_M2_MAX},
- .p = {.min = I8XX_P_MIN, .max = I8XX_P_MAX},
- .p1 = {.min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX},
- .p2 = {.dot_limit = I8XX_P2_SLOW_LIMIT,
- .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST},
- },
{ /* INTEL_LIMIT_I9XX_SDVO_DAC */
- .dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
- .vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX},
- .n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX},
- .m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX},
- .m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX},
- .m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX},
- .p = {.min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX},
- .p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX},
- .p2 = {.dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
- .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast =
- I9XX_P2_SDVO_DAC_FAST},
+ .dot = {.min = 20000, .max = 400000},
+ .vco = {.min = 1400000, .max = 2800000},
+ .n = {.min = 1, .max = 6},
+ .m = {.min = 70, .max = 120},
+ .m1 = {.min = 8, .max = 18},
+ .m2 = {.min = 3, .max = 7},
+ .p = {.min = 5, .max = 80},
+ .p1 = {.min = 1, .max = 8},
+ .p2 = {.dot_limit = 200000,
+ .p2_slow = 10, .p2_fast = 5},
},
{ /* INTEL_LIMIT_I9XX_LVDS */
- .dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
- .vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX},
- .n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX},
- .m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX},
- .m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX},
- .m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX},
- .p = {.min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX},
- .p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX},
+ .dot = {.min = 20000, .max = 400000},
+ .vco = {.min = 1400000, .max = 2800000},
+ .n = {.min = 1, .max = 6},
+ .m = {.min = 70, .max = 120},
+ .m1 = {.min = 8, .max = 18},
+ .m2 = {.min = 3, .max = 7},
+ .p = {.min = 7, .max = 98},
+ .p1 = {.min = 1, .max = 8},
/* The single-channel range is 25-112Mhz, and dual-channel
* is 80-224Mhz. Prefer single channel as much as possible.
*/
- .p2 = {.dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
- .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST},
+ .p2 = {.dot_limit = 112000,
+ .p2_slow = 14, .p2_fast = 7},
},
};
@@ -177,9 +99,7 @@ static const struct psb_intel_limit_t *psb_intel_limit(struct drm_crtc *crtc)
return limit;
}
-/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
-
-static void i8xx_clock(int refclk, struct psb_intel_clock_t *clock)
+static void psb_intel_clock(int refclk, struct psb_intel_clock_t *clock)
{
clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
clock->p = clock->p1 * clock->p2;
@@ -187,22 +107,6 @@ static void i8xx_clock(int refclk, struct psb_intel_clock_t *clock)
clock->dot = clock->vco / clock->p;
}
-/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */
-
-static void i9xx_clock(int refclk, struct psb_intel_clock_t *clock)
-{
- clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
- clock->p = clock->p1 * clock->p2;
- clock->vco = refclk * clock->m / (clock->n + 2);
- clock->dot = clock->vco / clock->p;
-}
-
-static void psb_intel_clock(struct drm_device *dev, int refclk,
- struct psb_intel_clock_t *clock)
-{
- return i9xx_clock(refclk, clock);
-}
-
/**
* Returns whether any output on the specified pipe is of the specified type
*/
@@ -308,7 +212,7 @@ static bool psb_intel_find_best_PLL(struct drm_crtc *crtc, int target,
clock.p1++) {
int this_err;
- psb_intel_clock(dev, refclk, &clock);
+ psb_intel_clock(refclk, &clock);
if (!psb_intel_PLL_is_valid
(crtc, &clock))
@@ -1068,7 +972,7 @@ static int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
return 0;
}
-void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
+static void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
u16 *green, u16 *blue, uint32_t type, uint32_t size)
{
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
@@ -1149,9 +1053,9 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev,
if ((dpll & PLL_REF_INPUT_MASK) ==
PLLB_REF_INPUT_SPREADSPECTRUMIN) {
/* XXX: might not be 66MHz */
- i8xx_clock(66000, &clock);
+ psb_intel_clock(66000, &clock);
} else
- i8xx_clock(48000, &clock);
+ psb_intel_clock(48000, &clock);
} else {
if (dpll & PLL_P1_DIVIDE_BY_TWO)
clock.p1 = 2;
@@ -1166,7 +1070,7 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev,
else
clock.p2 = 2;
- i8xx_clock(48000, &clock);
+ psb_intel_clock(48000, &clock);
}
/* XXX: It would be nice to validate the clocks, but we can't reuse
@@ -1225,7 +1129,7 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
return mode;
}
-void psb_intel_crtc_destroy(struct drm_crtc *crtc)
+static void psb_intel_crtc_destroy(struct drm_crtc *crtc)
{
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct gtt_range *gt;
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.h b/drivers/gpu/drm/gma500/psb_intel_display.h
index 535b49a5e40..3724b971e91 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.h
+++ b/drivers/gpu/drm/gma500/psb_intel_display.h
@@ -21,8 +21,5 @@
#define _INTEL_DISPLAY_H_
bool psb_intel_pipe_has_type(struct drm_crtc *crtc, int type);
-void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
- u16 *green, u16 *blue, uint32_t type, uint32_t size);
-void psb_intel_crtc_destroy(struct drm_crtc *crtc);
#endif
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index 90f2d11e686..4dcae421a58 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -32,9 +32,6 @@
/* maximum connectors per crtcs in the mode set */
#define INTELFB_CONN_LIMIT 4
-#define INTEL_I2C_BUS_DVO 1
-#define INTEL_I2C_BUS_SDVO 2
-
/* Intel Pipe Clone Bit */
#define INTEL_HDMIB_CLONE_BIT 1
#define INTEL_HDMIC_CLONE_BIT 2
@@ -68,11 +65,6 @@
#define INTEL_OUTPUT_DISPLAYPORT 9
#define INTEL_OUTPUT_EDP 10
-#define INTEL_DVO_CHIP_NONE 0
-#define INTEL_DVO_CHIP_LVDS 1
-#define INTEL_DVO_CHIP_TMDS 2
-#define INTEL_DVO_CHIP_TVOUT 4
-
#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
diff --git a/drivers/gpu/drm/gma500/psb_intel_reg.h b/drivers/gpu/drm/gma500/psb_intel_reg.h
index d914719c4b6..0be30e4d146 100644
--- a/drivers/gpu/drm/gma500/psb_intel_reg.h
+++ b/drivers/gpu/drm/gma500/psb_intel_reg.h
@@ -493,7 +493,6 @@
#define PIPEACONF_DISABLE 0
#define PIPEACONF_DOUBLE_WIDE (1 << 30)
#define PIPECONF_ACTIVE (1 << 30)
-#define I965_PIPECONF_ACTIVE (1 << 30)
#define PIPECONF_DSIPLL_LOCK (1 << 29)
#define PIPEACONF_SINGLE_WIDE 0
#define PIPEACONF_PIPE_UNLOCKED 0
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index a4cc777ab7a..19e36603b23 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -134,6 +134,9 @@ struct psb_intel_sdvo {
/* Input timings for adjusted_mode */
struct psb_intel_sdvo_dtd input_dtd;
+
+ /* Saved SDVO output states */
+ uint32_t saveSDVO; /* Can be SDVOB or SDVOC depending on sdvo_reg */
};
struct psb_intel_sdvo_connector {
@@ -1830,6 +1833,34 @@ done:
#undef CHECK_PROPERTY
}
+static void psb_intel_sdvo_save(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct psb_intel_encoder *psb_intel_encoder =
+ psb_intel_attached_encoder(connector);
+ struct psb_intel_sdvo *sdvo =
+ to_psb_intel_sdvo(&psb_intel_encoder->base);
+
+ sdvo->saveSDVO = REG_READ(sdvo->sdvo_reg);
+}
+
+static void psb_intel_sdvo_restore(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_encoder *encoder =
+ &psb_intel_attached_encoder(connector)->base;
+ struct psb_intel_sdvo *sdvo = to_psb_intel_sdvo(encoder);
+ struct drm_crtc *crtc = encoder->crtc;
+
+ REG_WRITE(sdvo->sdvo_reg, sdvo->saveSDVO);
+
+ /* Force a full mode set on the crtc. We're supposed to have the
+ mode_config lock already. */
+ if (connector->status == connector_status_connected)
+ drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
+ NULL);
+}
+
static const struct drm_encoder_helper_funcs psb_intel_sdvo_helper_funcs = {
.dpms = psb_intel_sdvo_dpms,
.mode_fixup = psb_intel_sdvo_mode_fixup,
@@ -1840,6 +1871,8 @@ static const struct drm_encoder_helper_funcs psb_intel_sdvo_helper_funcs = {
static const struct drm_connector_funcs psb_intel_sdvo_connector_funcs = {
.dpms = drm_helper_connector_dpms,
+ .save = psb_intel_sdvo_save,
+ .restore = psb_intel_sdvo_restore,
.detect = psb_intel_sdvo_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = psb_intel_sdvo_set_property,
diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c
index 8652cdf3f03..029eccf3013 100644
--- a/drivers/gpu/drm/gma500/psb_irq.c
+++ b/drivers/gpu/drm/gma500/psb_irq.c
@@ -211,7 +211,7 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
vdc_stat = PSB_RVDC32(PSB_INT_IDENTITY_R);
- if (vdc_stat & _PSB_PIPE_EVENT_FLAG)
+ if (vdc_stat & (_PSB_PIPE_EVENT_FLAG|_PSB_IRQ_ASLE))
dsp_int = 1;
/* FIXME: Handle Medfield
diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h
index 603045bee58..debb7f190c0 100644
--- a/drivers/gpu/drm/gma500/psb_irq.h
+++ b/drivers/gpu/drm/gma500/psb_irq.h
@@ -21,8 +21,8 @@
*
**************************************************************************/
-#ifndef _SYSIRQ_H_
-#define _SYSIRQ_H_
+#ifndef _PSB_IRQ_H_
+#define _PSB_IRQ_H_
#include <drm/drmP.h>
@@ -44,4 +44,4 @@ u32 psb_get_vblank_counter(struct drm_device *dev, int pipe);
int mdfld_enable_te(struct drm_device *dev, int pipe);
void mdfld_disable_te(struct drm_device *dev, int pipe);
-#endif /* _SYSIRQ_H_ */
+#endif /* _PSB_IRQ_H_ */
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 7299ea45dd0..e913d325d5b 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -772,6 +772,23 @@ static int i915_error_state(struct seq_file *m, void *unused)
}
}
}
+
+ obj = error->ring[i].ctx;
+ if (obj) {
+ seq_printf(m, "%s --- HW Context = 0x%08x\n",
+ dev_priv->ring[i].name,
+ obj->gtt_offset);
+ offset = 0;
+ for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
+ seq_printf(m, "[%04x] %08x %08x %08x %08x\n",
+ offset,
+ obj->pages[0][elt],
+ obj->pages[0][elt+1],
+ obj->pages[0][elt+2],
+ obj->pages[0][elt+3]);
+ offset += 16;
+ }
+ }
}
if (error->overlay)
@@ -849,76 +866,42 @@ static const struct file_operations i915_error_state_fops = {
.release = i915_error_state_release,
};
-static ssize_t
-i915_next_seqno_read(struct file *filp,
- char __user *ubuf,
- size_t max,
- loff_t *ppos)
+static int
+i915_next_seqno_get(void *data, u64 *val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
drm_i915_private_t *dev_priv = dev->dev_private;
- char buf[80];
- int len;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
- len = snprintf(buf, sizeof(buf),
- "next_seqno : 0x%x\n",
- dev_priv->next_seqno);
-
+ *val = dev_priv->next_seqno;
mutex_unlock(&dev->struct_mutex);
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+ return 0;
}
-static ssize_t
-i915_next_seqno_write(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
-{
- struct drm_device *dev = filp->private_data;
- char buf[20];
- u32 val = 1;
+static int
+i915_next_seqno_set(void *data, u64 val)
+{
+ struct drm_device *dev = data;
int ret;
- if (cnt > 0) {
- if (cnt > sizeof(buf) - 1)
- return -EINVAL;
-
- if (copy_from_user(buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = 0;
-
- ret = kstrtouint(buf, 0, &val);
- if (ret < 0)
- return ret;
- }
-
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
ret = i915_gem_set_seqno(dev, val);
-
mutex_unlock(&dev->struct_mutex);
- return ret ?: cnt;
+ return ret;
}
-static const struct file_operations i915_next_seqno_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = i915_next_seqno_read,
- .write = i915_next_seqno_write,
- .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops,
+ i915_next_seqno_get, i915_next_seqno_set,
+ "0x%llx\n");
static int i915_rstdby_delays(struct seq_file *m, void *unused)
{
@@ -1023,6 +1006,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
max_freq = rp_state_cap & 0xff;
seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
max_freq * GT_FREQUENCY_MULTIPLIER);
+
+ seq_printf(m, "Max overclocked frequency: %dMHz\n",
+ dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
} else {
seq_printf(m, "no P-state info available\n");
}
@@ -1371,7 +1357,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
if (ret)
return ret;
- seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n");
+ seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n");
for (gpu_freq = dev_priv->rps.min_delay;
gpu_freq <= dev_priv->rps.max_delay;
@@ -1380,7 +1366,10 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
sandybridge_pcode_read(dev_priv,
GEN6_PCODE_READ_MIN_FREQ_TABLE,
&ia_freq);
- seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100);
+ seq_printf(m, "%d\t\t%d\t\t\t\t%d\n",
+ gpu_freq * GT_FREQUENCY_MULTIPLIER,
+ ((ia_freq >> 0) & 0xff) * 100,
+ ((ia_freq >> 8) & 0xff) * 100);
}
mutex_unlock(&dev_priv->rps.hw_lock);
@@ -1680,105 +1669,51 @@ static int i915_dpio_info(struct seq_file *m, void *data)
return 0;
}
-static ssize_t
-i915_wedged_read(struct file *filp,
- char __user *ubuf,
- size_t max,
- loff_t *ppos)
+static int
+i915_wedged_get(void *data, u64 *val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
drm_i915_private_t *dev_priv = dev->dev_private;
- char buf[80];
- int len;
- len = snprintf(buf, sizeof(buf),
- "wedged : %d\n",
- atomic_read(&dev_priv->gpu_error.reset_counter));
+ *val = atomic_read(&dev_priv->gpu_error.reset_counter);
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+ return 0;
}
-static ssize_t
-i915_wedged_write(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
+static int
+i915_wedged_set(void *data, u64 val)
{
- struct drm_device *dev = filp->private_data;
- char buf[20];
- int val = 1;
-
- if (cnt > 0) {
- if (cnt > sizeof(buf) - 1)
- return -EINVAL;
+ struct drm_device *dev = data;
- if (copy_from_user(buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = 0;
-
- val = simple_strtoul(buf, NULL, 0);
- }
-
- DRM_INFO("Manually setting wedged to %d\n", val);
+ DRM_INFO("Manually setting wedged to %llu\n", val);
i915_handle_error(dev, val);
- return cnt;
+ return 0;
}
-static const struct file_operations i915_wedged_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = i915_wedged_read,
- .write = i915_wedged_write,
- .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops,
+ i915_wedged_get, i915_wedged_set,
+ "%llu\n");
-static ssize_t
-i915_ring_stop_read(struct file *filp,
- char __user *ubuf,
- size_t max,
- loff_t *ppos)
+static int
+i915_ring_stop_get(void *data, u64 *val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
drm_i915_private_t *dev_priv = dev->dev_private;
- char buf[20];
- int len;
- len = snprintf(buf, sizeof(buf),
- "0x%08x\n", dev_priv->gpu_error.stop_rings);
+ *val = dev_priv->gpu_error.stop_rings;
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+ return 0;
}
-static ssize_t
-i915_ring_stop_write(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
+static int
+i915_ring_stop_set(void *data, u64 val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
- char buf[20];
- int val = 0, ret;
-
- if (cnt > 0) {
- if (cnt > sizeof(buf) - 1)
- return -EINVAL;
-
- if (copy_from_user(buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = 0;
-
- val = simple_strtoul(buf, NULL, 0);
- }
+ int ret;
- DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val);
+ DRM_DEBUG_DRIVER("Stopping rings 0x%08llx\n", val);
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
@@ -1787,16 +1722,12 @@ i915_ring_stop_write(struct file *filp,
dev_priv->gpu_error.stop_rings = val;
mutex_unlock(&dev->struct_mutex);
- return cnt;
+ return 0;
}
-static const struct file_operations i915_ring_stop_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = i915_ring_stop_read,
- .write = i915_ring_stop_write,
- .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_ring_stop_fops,
+ i915_ring_stop_get, i915_ring_stop_set,
+ "0x%08llx\n");
#define DROP_UNBOUND 0x1
#define DROP_BOUND 0x2
@@ -1806,46 +1737,23 @@ static const struct file_operations i915_ring_stop_fops = {
DROP_BOUND | \
DROP_RETIRE | \
DROP_ACTIVE)
-static ssize_t
-i915_drop_caches_read(struct file *filp,
- char __user *ubuf,
- size_t max,
- loff_t *ppos)
+static int
+i915_drop_caches_get(void *data, u64 *val)
{
- char buf[20];
- int len;
+ *val = DROP_ALL;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", DROP_ALL);
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+ return 0;
}
-static ssize_t
-i915_drop_caches_write(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
+static int
+i915_drop_caches_set(void *data, u64 val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj, *next;
- char buf[20];
- int val = 0, ret;
-
- if (cnt > 0) {
- if (cnt > sizeof(buf) - 1)
- return -EINVAL;
-
- if (copy_from_user(buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = 0;
-
- val = simple_strtoul(buf, NULL, 0);
- }
+ int ret;
- DRM_DEBUG_DRIVER("Dropping caches: 0x%08x\n", val);
+ DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val);
/* No need to check and wait for gpu resets, only libdrm auto-restarts
* on ioctls on -EAGAIN. */
@@ -1883,27 +1791,19 @@ i915_drop_caches_write(struct file *filp,
unlock:
mutex_unlock(&dev->struct_mutex);
- return ret ?: cnt;
+ return ret;
}
-static const struct file_operations i915_drop_caches_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = i915_drop_caches_read,
- .write = i915_drop_caches_write,
- .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_drop_caches_fops,
+ i915_drop_caches_get, i915_drop_caches_set,
+ "0x%08llx\n");
-static ssize_t
-i915_max_freq_read(struct file *filp,
- char __user *ubuf,
- size_t max,
- loff_t *ppos)
+static int
+i915_max_freq_get(void *data, u64 *val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
drm_i915_private_t *dev_priv = dev->dev_private;
- char buf[80];
- int len, ret;
+ int ret;
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
return -ENODEV;
@@ -1912,42 +1812,23 @@ i915_max_freq_read(struct file *filp,
if (ret)
return ret;
- len = snprintf(buf, sizeof(buf),
- "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER);
+ *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+ return 0;
}
-static ssize_t
-i915_max_freq_write(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
+static int
+i915_max_freq_set(void *data, u64 val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
- char buf[20];
- int val = 1, ret;
+ int ret;
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
return -ENODEV;
- if (cnt > 0) {
- if (cnt > sizeof(buf) - 1)
- return -EINVAL;
-
- if (copy_from_user(buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = 0;
-
- val = simple_strtoul(buf, NULL, 0);
- }
-
- DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val);
+ DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val);
ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
if (ret)
@@ -1956,30 +1837,24 @@ i915_max_freq_write(struct file *filp,
/*
* Turbo will still be enabled, but won't go above the set value.
*/
- dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER;
-
- gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
+ do_div(val, GT_FREQUENCY_MULTIPLIER);
+ dev_priv->rps.max_delay = val;
+ gen6_set_rps(dev, val);
mutex_unlock(&dev_priv->rps.hw_lock);
- return cnt;
+ return 0;
}
-static const struct file_operations i915_max_freq_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = i915_max_freq_read,
- .write = i915_max_freq_write,
- .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_max_freq_fops,
+ i915_max_freq_get, i915_max_freq_set,
+ "%llu\n");
-static ssize_t
-i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
- loff_t *ppos)
+static int
+i915_min_freq_get(void *data, u64 *val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
drm_i915_private_t *dev_priv = dev->dev_private;
- char buf[80];
- int len, ret;
+ int ret;
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
return -ENODEV;
@@ -1988,40 +1863,23 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
if (ret)
return ret;
- len = snprintf(buf, sizeof(buf),
- "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER);
+ *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+ return 0;
}
-static ssize_t
-i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
- loff_t *ppos)
+static int
+i915_min_freq_set(void *data, u64 val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
- char buf[20];
- int val = 1, ret;
+ int ret;
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
return -ENODEV;
- if (cnt > 0) {
- if (cnt > sizeof(buf) - 1)
- return -EINVAL;
-
- if (copy_from_user(buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = 0;
-
- val = simple_strtoul(buf, NULL, 0);
- }
-
- DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val);
+ DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val);
ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
if (ret)
@@ -2030,33 +1888,25 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
/*
* Turbo will still be enabled, but won't go below the set value.
*/
- dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER;
-
- gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
+ do_div(val, GT_FREQUENCY_MULTIPLIER);
+ dev_priv->rps.min_delay = val;
+ gen6_set_rps(dev, val);
mutex_unlock(&dev_priv->rps.hw_lock);
- return cnt;
+ return 0;
}
-static const struct file_operations i915_min_freq_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = i915_min_freq_read,
- .write = i915_min_freq_write,
- .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops,
+ i915_min_freq_get, i915_min_freq_set,
+ "%llu\n");
-static ssize_t
-i915_cache_sharing_read(struct file *filp,
- char __user *ubuf,
- size_t max,
- loff_t *ppos)
+static int
+i915_cache_sharing_get(void *data, u64 *val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
drm_i915_private_t *dev_priv = dev->dev_private;
- char buf[80];
u32 snpcr;
- int len, ret;
+ int ret;
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
return -ENODEV;
@@ -2068,46 +1918,25 @@ i915_cache_sharing_read(struct file *filp,
snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
mutex_unlock(&dev_priv->dev->struct_mutex);
- len = snprintf(buf, sizeof(buf),
- "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >>
- GEN6_MBC_SNPCR_SHIFT);
+ *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT;
- if (len > sizeof(buf))
- len = sizeof(buf);
-
- return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+ return 0;
}
-static ssize_t
-i915_cache_sharing_write(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
+static int
+i915_cache_sharing_set(void *data, u64 val)
{
- struct drm_device *dev = filp->private_data;
+ struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
- char buf[20];
u32 snpcr;
- int val = 1;
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
return -ENODEV;
- if (cnt > 0) {
- if (cnt > sizeof(buf) - 1)
- return -EINVAL;
-
- if (copy_from_user(buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = 0;
-
- val = simple_strtoul(buf, NULL, 0);
- }
-
- if (val < 0 || val > 3)
+ if (val > 3)
return -EINVAL;
- DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val);
+ DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val);
/* Update the cache sharing policy here as well */
snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
@@ -2115,16 +1944,12 @@ i915_cache_sharing_write(struct file *filp,
snpcr |= (val << GEN6_MBC_SNPCR_SHIFT);
I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
- return cnt;
+ return 0;
}
-static const struct file_operations i915_cache_sharing_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = i915_cache_sharing_read,
- .write = i915_cache_sharing_write,
- .llseek = default_llseek,
-};
+DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops,
+ i915_cache_sharing_get, i915_cache_sharing_set,
+ "%llu\n");
/* As the drm_debugfs_init() routines are called before dev->dev_private is
* allocated we need to hook into the minor for release. */
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 4fa6beb14c7..3b315ba85a3 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1322,6 +1322,10 @@ static int i915_load_modeset_init(struct drm_device *dev)
/* Always safe in the mode setting case. */
/* FIXME: do pre/post-mode set stuff in core KMS code */
dev->vblank_disable_allowed = 1;
+ if (INTEL_INFO(dev)->num_pipes == 0) {
+ dev_priv->mm.suspended = 0;
+ return 0;
+ }
ret = intel_fbdev_init(dev);
if (ret)
@@ -1453,6 +1457,22 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv)
}
/**
+ * intel_early_sanitize_regs - clean up BIOS state
+ * @dev: DRM device
+ *
+ * This function must be called before we do any I915_READ or I915_WRITE. Its
+ * purpose is to clean up any state left by the BIOS that may affect us when
+ * reading and/or writing registers.
+ */
+static void intel_early_sanitize_regs(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (IS_HASWELL(dev))
+ I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+}
+
+/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
* @flags: startup flags
@@ -1498,6 +1518,28 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto free_priv;
}
+ mmio_bar = IS_GEN2(dev) ? 1 : 0;
+ /* Before gen4, the registers and the GTT are behind different BARs.
+ * However, from gen4 onwards, the registers and the GTT are shared
+ * in the same BAR, so we want to restrict this ioremap from
+ * clobbering the GTT which we want ioremap_wc instead. Fortunately,
+ * the register BAR remains the same size for all the earlier
+ * generations up to Ironlake.
+ */
+ if (info->gen < 5)
+ mmio_size = 512*1024;
+ else
+ mmio_size = 2*1024*1024;
+
+ dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
+ if (!dev_priv->regs) {
+ DRM_ERROR("failed to map registers\n");
+ ret = -EIO;
+ goto put_bridge;
+ }
+
+ intel_early_sanitize_regs(dev);
+
ret = i915_gem_gtt_init(dev);
if (ret)
goto put_bridge;
@@ -1522,26 +1564,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
- mmio_bar = IS_GEN2(dev) ? 1 : 0;
- /* Before gen4, the registers and the GTT are behind different BARs.
- * However, from gen4 onwards, the registers and the GTT are shared
- * in the same BAR, so we want to restrict this ioremap from
- * clobbering the GTT which we want ioremap_wc instead. Fortunately,
- * the register BAR remains the same size for all the earlier
- * generations up to Ironlake.
- */
- if (info->gen < 5)
- mmio_size = 512*1024;
- else
- mmio_size = 2*1024*1024;
-
- dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
- if (!dev_priv->regs) {
- DRM_ERROR("failed to map registers\n");
- ret = -EIO;
- goto put_gmch;
- }
-
aperture_size = dev_priv->gtt.mappable_end;
dev_priv->gtt.mappable =
@@ -1612,16 +1634,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
mutex_init(&dev_priv->rps.hw_lock);
mutex_init(&dev_priv->modeset_restore_lock);
- if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
- dev_priv->num_pipe = 3;
- else if (IS_MOBILE(dev) || !IS_GEN2(dev))
- dev_priv->num_pipe = 2;
- else
- dev_priv->num_pipe = 1;
+ dev_priv->num_plane = 1;
+ if (IS_VALLEYVIEW(dev))
+ dev_priv->num_plane = 2;
- ret = drm_vblank_init(dev, dev_priv->num_pipe);
- if (ret)
- goto out_gem_unload;
+ if (INTEL_INFO(dev)->num_pipes) {
+ ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes);
+ if (ret)
+ goto out_gem_unload;
+ }
/* Start out suspended */
dev_priv->mm.suspended = 1;
@@ -1636,9 +1657,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
i915_setup_sysfs(dev);
- /* Must be done after probing outputs */
- intel_opregion_init(dev);
- acpi_video_register();
+ if (INTEL_INFO(dev)->num_pipes) {
+ /* Must be done after probing outputs */
+ intel_opregion_init(dev);
+ acpi_video_register();
+ }
if (IS_GEN5(dev))
intel_gpu_ips_init(dev_priv);
@@ -1663,10 +1686,9 @@ out_mtrrfree:
dev_priv->mm.gtt_mtrr = -1;
}
io_mapping_free(dev_priv->gtt.mappable);
+ dev_priv->gtt.gtt_remove(dev);
out_rmmap:
pci_iounmap(dev->pdev, dev_priv->regs);
-put_gmch:
- dev_priv->gtt.gtt_remove(dev);
put_bridge:
pci_dev_put(dev_priv->bridge_dev);
free_priv:
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index e9b57893db2..9ebe895c17d 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -121,9 +121,7 @@ MODULE_PARM_DESC(i915_enable_ppgtt,
unsigned int i915_preliminary_hw_support __read_mostly = 0;
module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600);
MODULE_PARM_DESC(preliminary_hw_support,
- "Enable preliminary hardware support. "
- "Enable Haswell and ValleyView Support. "
- "(default: false)");
+ "Enable preliminary hardware support. (default: false)");
int i915_disable_power_well __read_mostly = 0;
module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
@@ -142,75 +140,85 @@ extern int intel_agp_enabled;
.subdevice = PCI_ANY_ID, \
.driver_data = (unsigned long) info }
+#define INTEL_QUANTA_VGA_DEVICE(info) { \
+ .class = PCI_BASE_CLASS_DISPLAY << 16, \
+ .class_mask = 0xff0000, \
+ .vendor = 0x8086, \
+ .device = 0x16a, \
+ .subvendor = 0x152d, \
+ .subdevice = 0x8990, \
+ .driver_data = (unsigned long) info }
+
+
static const struct intel_device_info intel_i830_info = {
- .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1,
+ .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
.has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_845g_info = {
- .gen = 2,
+ .gen = 2, .num_pipes = 1,
.has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i85x_info = {
- .gen = 2, .is_i85x = 1, .is_mobile = 1,
+ .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2,
.cursor_needs_physical = 1,
.has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i865g_info = {
- .gen = 2,
+ .gen = 2, .num_pipes = 1,
.has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i915g_info = {
- .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1,
+ .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2,
.has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i915gm_info = {
- .gen = 3, .is_mobile = 1,
+ .gen = 3, .is_mobile = 1, .num_pipes = 2,
.cursor_needs_physical = 1,
.has_overlay = 1, .overlay_needs_physical = 1,
.supports_tv = 1,
};
static const struct intel_device_info intel_i945g_info = {
- .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1,
+ .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2,
.has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i945gm_info = {
- .gen = 3, .is_i945gm = 1, .is_mobile = 1,
+ .gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2,
.has_hotplug = 1, .cursor_needs_physical = 1,
.has_overlay = 1, .overlay_needs_physical = 1,
.supports_tv = 1,
};
static const struct intel_device_info intel_i965g_info = {
- .gen = 4, .is_broadwater = 1,
+ .gen = 4, .is_broadwater = 1, .num_pipes = 2,
.has_hotplug = 1,
.has_overlay = 1,
};
static const struct intel_device_info intel_i965gm_info = {
- .gen = 4, .is_crestline = 1,
+ .gen = 4, .is_crestline = 1, .num_pipes = 2,
.is_mobile = 1, .has_fbc = 1, .has_hotplug = 1,
.has_overlay = 1,
.supports_tv = 1,
};
static const struct intel_device_info intel_g33_info = {
- .gen = 3, .is_g33 = 1,
+ .gen = 3, .is_g33 = 1, .num_pipes = 2,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_overlay = 1,
};
static const struct intel_device_info intel_g45_info = {
- .gen = 4, .is_g4x = 1, .need_gfx_hws = 1,
+ .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2,
.has_pipe_cxsr = 1, .has_hotplug = 1,
.has_bsd_ring = 1,
};
static const struct intel_device_info intel_gm45_info = {
- .gen = 4, .is_g4x = 1,
+ .gen = 4, .is_g4x = 1, .num_pipes = 2,
.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1,
.has_pipe_cxsr = 1, .has_hotplug = 1,
.supports_tv = 1,
@@ -218,26 +226,26 @@ static const struct intel_device_info intel_gm45_info = {
};
static const struct intel_device_info intel_pineview_info = {
- .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
+ .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_overlay = 1,
};
static const struct intel_device_info intel_ironlake_d_info = {
- .gen = 5,
+ .gen = 5, .num_pipes = 2,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_bsd_ring = 1,
};
static const struct intel_device_info intel_ironlake_m_info = {
- .gen = 5, .is_mobile = 1,
+ .gen = 5, .is_mobile = 1, .num_pipes = 2,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_fbc = 1,
.has_bsd_ring = 1,
};
static const struct intel_device_info intel_sandybridge_d_info = {
- .gen = 6,
+ .gen = 6, .num_pipes = 2,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_bsd_ring = 1,
.has_blt_ring = 1,
@@ -246,7 +254,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
};
static const struct intel_device_info intel_sandybridge_m_info = {
- .gen = 6, .is_mobile = 1,
+ .gen = 6, .is_mobile = 1, .num_pipes = 2,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_fbc = 1,
.has_bsd_ring = 1,
@@ -255,61 +263,57 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.has_force_wake = 1,
};
+#define GEN7_FEATURES \
+ .gen = 7, .num_pipes = 3, \
+ .need_gfx_hws = 1, .has_hotplug = 1, \
+ .has_bsd_ring = 1, \
+ .has_blt_ring = 1, \
+ .has_llc = 1, \
+ .has_force_wake = 1
+
static const struct intel_device_info intel_ivybridge_d_info = {
- .is_ivybridge = 1, .gen = 7,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .has_bsd_ring = 1,
- .has_blt_ring = 1,
- .has_llc = 1,
- .has_force_wake = 1,
+ GEN7_FEATURES,
+ .is_ivybridge = 1,
};
static const struct intel_device_info intel_ivybridge_m_info = {
- .is_ivybridge = 1, .gen = 7, .is_mobile = 1,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */
- .has_bsd_ring = 1,
- .has_blt_ring = 1,
- .has_llc = 1,
- .has_force_wake = 1,
+ GEN7_FEATURES,
+ .is_ivybridge = 1,
+ .is_mobile = 1,
+};
+
+static const struct intel_device_info intel_ivybridge_q_info = {
+ GEN7_FEATURES,
+ .is_ivybridge = 1,
+ .num_pipes = 0, /* legal, last one wins */
};
static const struct intel_device_info intel_valleyview_m_info = {
- .gen = 7, .is_mobile = 1,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .has_fbc = 0,
- .has_bsd_ring = 1,
- .has_blt_ring = 1,
+ GEN7_FEATURES,
+ .is_mobile = 1,
+ .num_pipes = 2,
.is_valleyview = 1,
.display_mmio_offset = VLV_DISPLAY_BASE,
+ .has_llc = 0, /* legal, last one wins */
};
static const struct intel_device_info intel_valleyview_d_info = {
- .gen = 7,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .has_fbc = 0,
- .has_bsd_ring = 1,
- .has_blt_ring = 1,
+ GEN7_FEATURES,
+ .num_pipes = 2,
.is_valleyview = 1,
.display_mmio_offset = VLV_DISPLAY_BASE,
+ .has_llc = 0, /* legal, last one wins */
};
static const struct intel_device_info intel_haswell_d_info = {
- .is_haswell = 1, .gen = 7,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .has_bsd_ring = 1,
- .has_blt_ring = 1,
- .has_llc = 1,
- .has_force_wake = 1,
+ GEN7_FEATURES,
+ .is_haswell = 1,
};
static const struct intel_device_info intel_haswell_m_info = {
- .is_haswell = 1, .gen = 7, .is_mobile = 1,
- .need_gfx_hws = 1, .has_hotplug = 1,
- .has_bsd_ring = 1,
- .has_blt_ring = 1,
- .has_llc = 1,
- .has_force_wake = 1,
+ GEN7_FEATURES,
+ .is_haswell = 1,
+ .is_mobile = 1,
};
static const struct pci_device_id pciidlist[] = { /* aka */
@@ -356,6 +360,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */
INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
+ INTEL_QUANTA_VGA_DEVICE(&intel_ivybridge_q_info), /* Quanta transcode */
INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */
INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */
@@ -394,6 +399,9 @@ static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */
INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */
INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info),
+ INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info),
+ INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info),
+ INTEL_VGA_DEVICE(0x0f33, &intel_valleyview_m_info),
INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info),
INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info),
{0, 0, 0}
@@ -408,6 +416,15 @@ void intel_detect_pch(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
struct pci_dev *pch;
+ /* In all current cases, num_pipes is equivalent to the PCH_NOP setting
+ * (which really amounts to a PCH but no South Display).
+ */
+ if (INTEL_INFO(dev)->num_pipes == 0) {
+ dev_priv->pch_type = PCH_NOP;
+ dev_priv->num_pch_pll = 0;
+ return;
+ }
+
/*
* The reason to probe ISA bridge instead of Dev31:Fun0 is to
* make graphics device passthrough work easy for VMM, that only
@@ -442,11 +459,13 @@ void intel_detect_pch(struct drm_device *dev)
dev_priv->num_pch_pll = 0;
DRM_DEBUG_KMS("Found LynxPoint PCH\n");
WARN_ON(!IS_HASWELL(dev));
+ WARN_ON(IS_ULT(dev));
} else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_LPT;
dev_priv->num_pch_pll = 0;
DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
WARN_ON(!IS_HASWELL(dev));
+ WARN_ON(!IS_ULT(dev));
}
BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS);
}
@@ -474,6 +493,7 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
static int i915_drm_freeze(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
/* ignore lid events during suspend */
mutex_lock(&dev_priv->modeset_restore_lock);
@@ -497,10 +517,14 @@ static int i915_drm_freeze(struct drm_device *dev)
cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
- intel_modeset_disable(dev);
-
drm_irq_uninstall(dev);
dev_priv->enable_hotplug_processing = false;
+ /*
+ * Disable CRTCs directly since we want to preserve sw state
+ * for _thaw.
+ */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+ dev_priv->display.crtc_disable(crtc);
}
i915_save_state(dev);
@@ -556,6 +580,24 @@ void intel_console_resume(struct work_struct *work)
console_unlock();
}
+static void intel_resume_hotplug(struct drm_device *dev)
+{
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct intel_encoder *encoder;
+
+ mutex_lock(&mode_config->mutex);
+ DRM_DEBUG_KMS("running encoder hotplug functions\n");
+
+ list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+ if (encoder->hot_plug)
+ encoder->hot_plug(encoder);
+
+ mutex_unlock(&mode_config->mutex);
+
+ /* Just fire off a uevent and let userspace tell us what to do */
+ drm_helper_hpd_irq_event(dev);
+}
+
static int __i915_drm_thaw(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -578,7 +620,10 @@ static int __i915_drm_thaw(struct drm_device *dev)
drm_irq_install(dev);
intel_modeset_init_hw(dev);
- intel_modeset_setup_hw_state(dev, false);
+
+ drm_modeset_lock_all(dev);
+ intel_modeset_setup_hw_state(dev, true);
+ drm_modeset_unlock_all(dev);
/*
* ... but also need to make sure that hotplug processing
@@ -588,6 +633,8 @@ static int __i915_drm_thaw(struct drm_device *dev)
* */
intel_hpd_init(dev);
dev_priv->enable_hotplug_processing = true;
+ /* Config may have changed between suspend and resume */
+ intel_resume_hotplug(dev);
}
intel_opregion_init(dev);
@@ -732,6 +779,7 @@ static int ironlake_do_reset(struct drm_device *dev)
int ret;
gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+ gdrst &= ~GRDOM_MASK;
I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE);
ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
@@ -740,6 +788,7 @@ static int ironlake_do_reset(struct drm_device *dev)
/* We can't reset render&media without also resetting display ... */
gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+ gdrst &= ~GRDOM_MASK;
I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE);
return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
@@ -803,7 +852,7 @@ int intel_gpu_reset(struct drm_device *dev)
/* Also reset the gpu hangman. */
if (dev_priv->gpu_error.stop_rings) {
- DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n");
+ DRM_INFO("Simulated gpu hang, resetting stop_rings\n");
dev_priv->gpu_error.stop_rings = 0;
if (ret == -ENODEV) {
DRM_ERROR("Reset not implemented, but ignoring "
@@ -882,7 +931,11 @@ int i915_reset(struct drm_device *dev)
ring->init(ring);
i915_gem_context_init(dev);
- i915_gem_init_ppgtt(dev);
+ if (dev_priv->mm.aliasing_ppgtt) {
+ ret = dev_priv->mm.aliasing_ppgtt->enable(dev);
+ if (ret)
+ i915_gem_cleanup_aliasing_ppgtt(dev);
+ }
/*
* It would make sense to re-init all the other hw state, at
@@ -1147,6 +1200,27 @@ ilk_dummy_write(struct drm_i915_private *dev_priv)
I915_WRITE_NOTRACE(MI_MODE, 0);
}
+static void
+hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg)
+{
+ if (IS_HASWELL(dev_priv->dev) &&
+ (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+ DRM_ERROR("Unknown unclaimed register before writing to %x\n",
+ reg);
+ I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+ }
+}
+
+static void
+hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
+{
+ if (IS_HASWELL(dev_priv->dev) &&
+ (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+ DRM_ERROR("Unclaimed write to %x\n", reg);
+ I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+ }
+}
+
#define __i915_read(x, y) \
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
u##x val = 0; \
@@ -1183,18 +1257,12 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
} \
if (IS_GEN5(dev_priv->dev)) \
ilk_dummy_write(dev_priv); \
- if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \
- DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \
- I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \
- } \
+ hsw_unclaimed_reg_clear(dev_priv, reg); \
write##y(val, dev_priv->regs + reg); \
if (unlikely(__fifo_ret)) { \
gen6_gt_check_fifodbg(dev_priv); \
} \
- if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \
- DRM_ERROR("Unclaimed write to %x\n", reg); \
- writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT); \
- } \
+ hsw_unclaimed_reg_check(dev_priv, reg); \
}
__i915_write(8, b)
__i915_write(16, w)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 01769e2a995..d5dcf7fe1ee 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -86,6 +86,19 @@ enum port {
};
#define port_name(p) ((p) + 'A')
+enum hpd_pin {
+ HPD_NONE = 0,
+ HPD_PORT_A = HPD_NONE, /* PORT_A is internal */
+ HPD_TV = HPD_NONE, /* TV is known to be unreliable */
+ HPD_CRT,
+ HPD_SDVO_B,
+ HPD_SDVO_C,
+ HPD_PORT_B,
+ HPD_PORT_C,
+ HPD_PORT_D,
+ HPD_NUM_PINS
+};
+
#define I915_GEM_GPU_DOMAINS \
(I915_GEM_DOMAIN_RENDER | \
I915_GEM_DOMAIN_SAMPLER | \
@@ -93,7 +106,7 @@ enum port {
I915_GEM_DOMAIN_INSTRUCTION | \
I915_GEM_DOMAIN_VERTEX)
-#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++)
+#define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++)
#define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
@@ -182,9 +195,9 @@ struct drm_i915_master_private {
struct _drm_i915_sarea *sarea_priv;
};
#define I915_FENCE_REG_NONE -1
-#define I915_MAX_NUM_FENCES 16
-/* 16 fences + sign bit for FENCE_REG_NONE */
-#define I915_MAX_NUM_FENCE_BITS 5
+#define I915_MAX_NUM_FENCES 32
+/* 32 fences + sign bit for FENCE_REG_NONE */
+#define I915_MAX_NUM_FENCE_BITS 6
struct drm_i915_fence_reg {
struct list_head lru_list;
@@ -243,7 +256,7 @@ struct drm_i915_error_state {
int page_count;
u32 gtt_offset;
u32 *pages[0];
- } *ringbuffer, *batchbuffer;
+ } *ringbuffer, *batchbuffer, *ctx;
struct drm_i915_error_request {
long jiffies;
u32 seqno;
@@ -271,6 +284,9 @@ struct drm_i915_error_state {
struct intel_display_error_state *display;
};
+struct intel_crtc_config;
+struct intel_crtc;
+
struct drm_i915_display_funcs {
bool (*fbc_enabled)(struct drm_device *dev);
void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval);
@@ -283,9 +299,11 @@ struct drm_i915_display_funcs {
void (*update_linetime_wm)(struct drm_device *dev, int pipe,
struct drm_display_mode *mode);
void (*modeset_global_resources)(struct drm_device *dev);
+ /* Returns the active state of the crtc, and if the crtc is active,
+ * fills out the pipe-config with the hw state. */
+ bool (*get_pipe_config)(struct intel_crtc *,
+ struct intel_crtc_config *);
int (*crtc_mode_set)(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *old_fb);
void (*crtc_enable)(struct drm_crtc *crtc);
@@ -341,6 +359,7 @@ struct drm_i915_gt_funcs {
struct intel_device_info {
u32 display_mmio_offset;
+ u8 num_pipes:3;
u8 gen;
u8 is_mobile:1;
u8 is_i85x:1;
@@ -430,6 +449,7 @@ struct i915_hw_ppgtt {
struct sg_table *st,
unsigned int pg_start,
enum i915_cache_level cache_level);
+ int (*enable)(struct drm_device *dev);
void (*cleanup)(struct i915_hw_ppgtt *ppgtt);
};
@@ -460,6 +480,7 @@ enum intel_pch {
PCH_IBX, /* Ibexpeak PCH */
PCH_CPT, /* Cougarpoint PCH */
PCH_LPT, /* Lynxpoint PCH */
+ PCH_NOP,
};
enum intel_sbi_destination {
@@ -647,6 +668,7 @@ struct intel_gen6_power_mgmt {
u8 cur_delay;
u8 min_delay;
u8 max_delay;
+ u8 hw_max;
struct delayed_work delayed_resume_work;
@@ -905,16 +927,24 @@ typedef struct drm_i915_private {
struct mutex dpio_lock;
/** Cached value of IMR to avoid reads in updating the bitfield */
- u32 pipestat[2];
u32 irq_mask;
u32 gt_irq_mask;
- u32 hotplug_supported_mask;
struct work_struct hotplug_work;
bool enable_hotplug_processing;
+ struct {
+ unsigned long hpd_last_jiffies;
+ int hpd_cnt;
+ enum {
+ HPD_ENABLED = 0,
+ HPD_DISABLED = 1,
+ HPD_MARK_DISABLED = 2
+ } hpd_mark;
+ } hpd_stats[HPD_NUM_PINS];
+ struct timer_list hotplug_reenable_timer;
- int num_pipe;
int num_pch_pll;
+ int num_plane;
unsigned long cfb_size;
unsigned int cfb_fb;
@@ -928,9 +958,14 @@ typedef struct drm_i915_private {
struct intel_overlay *overlay;
unsigned int sprite_scaling_enabled;
+ /* backlight */
+ struct {
+ int level;
+ bool enabled;
+ struct backlight_device *device;
+ } backlight;
+
/* LVDS info */
- int backlight_level; /* restore backlight to this value */
- bool backlight_enabled;
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -941,6 +976,7 @@ typedef struct drm_i915_private {
unsigned int int_crt_support:1;
unsigned int lvds_use_ssc:1;
unsigned int display_clock_mode:1;
+ unsigned int fdi_rx_polarity_inverted:1;
int lvds_ssc_freq;
unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
struct {
@@ -1032,8 +1068,6 @@ typedef struct drm_i915_private {
*/
struct work_struct console_resume_work;
- struct backlight_device *backlight;
-
struct drm_property *broadcast_rgb_property;
struct drm_property *force_audio_property;
@@ -1340,6 +1374,7 @@ struct drm_i915_file_private {
#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
#define HAS_DDI(dev) (IS_HASWELL(dev))
+#define HAS_POWER_WELL(dev) (IS_HASWELL(dev))
#define INTEL_PCH_DEVICE_ID_MASK 0xff00
#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00
@@ -1352,6 +1387,7 @@ struct drm_i915_file_private {
#define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT)
#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
+#define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP)
#define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE)
#define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake)
@@ -1529,17 +1565,12 @@ void i915_gem_lastclose(struct drm_device *dev);
int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
{
- struct scatterlist *sg = obj->pages->sgl;
- int nents = obj->pages->nents;
- while (nents > SG_MAX_SINGLE_ALLOC) {
- if (n < SG_MAX_SINGLE_ALLOC - 1)
- break;
-
- sg = sg_chain_ptr(sg + SG_MAX_SINGLE_ALLOC - 1);
- n -= SG_MAX_SINGLE_ALLOC - 1;
- nents -= SG_MAX_SINGLE_ALLOC - 1;
- }
- return sg_page(sg+n);
+ struct sg_page_iter sg_iter;
+
+ for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n)
+ return sg_page_iter_page(&sg_iter);
+
+ return NULL;
}
static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj)
{
@@ -1624,7 +1655,6 @@ int __must_check i915_gem_init(struct drm_device *dev);
int __must_check i915_gem_init_hw(struct drm_device *dev);
void i915_gem_l3_remap(struct drm_device *dev);
void i915_gem_init_swizzling(struct drm_device *dev);
-void i915_gem_init_ppgtt(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
int __must_check i915_gpu_idle(struct drm_device *dev);
int __must_check i915_gem_idle(struct drm_device *dev);
@@ -1718,6 +1748,11 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev);
void i915_gem_cleanup_stolen(struct drm_device *dev);
struct drm_i915_gem_object *
i915_gem_object_create_stolen(struct drm_device *dev, u32 size);
+struct drm_i915_gem_object *
+i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
+ u32 stolen_offset,
+ u32 gtt_offset,
+ u32 size);
void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj);
/* i915_gem_tiling.c */
@@ -1848,6 +1883,8 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val);
int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
+int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val);
+int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
#define __i915_read(x, y) \
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
@@ -1901,4 +1938,9 @@ static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev)
return VGACNTRL;
}
+static inline void __user *to_user_ptr(u64 address)
+{
+ return (void __user *)(uintptr_t)address;
+}
+
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 0e207e6e0df..6be940effef 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -411,10 +411,9 @@ i915_gem_shmem_pread(struct drm_device *dev,
int obj_do_bit17_swizzling, page_do_bit17_swizzling;
int prefaulted = 0;
int needs_clflush = 0;
- struct scatterlist *sg;
- int i;
+ struct sg_page_iter sg_iter;
- user_data = (char __user *) (uintptr_t) args->data_ptr;
+ user_data = to_user_ptr(args->data_ptr);
remain = args->size;
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
@@ -441,11 +440,9 @@ i915_gem_shmem_pread(struct drm_device *dev,
offset = args->offset;
- for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
- struct page *page;
-
- if (i < offset >> PAGE_SHIFT)
- continue;
+ for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
+ offset >> PAGE_SHIFT) {
+ struct page *page = sg_page_iter_page(&sg_iter);
if (remain <= 0)
break;
@@ -460,7 +457,6 @@ i915_gem_shmem_pread(struct drm_device *dev,
if ((shmem_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - shmem_page_offset;
- page = sg_page(sg);
page_do_bit17_swizzling = obj_do_bit17_swizzling &&
(page_to_phys(page) & (1 << 17)) != 0;
@@ -522,7 +518,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
return 0;
if (!access_ok(VERIFY_WRITE,
- (char __user *)(uintptr_t)args->data_ptr,
+ to_user_ptr(args->data_ptr),
args->size))
return -EFAULT;
@@ -613,7 +609,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
if (ret)
goto out_unpin;
- user_data = (char __user *) (uintptr_t) args->data_ptr;
+ user_data = to_user_ptr(args->data_ptr);
remain = args->size;
offset = obj->gtt_offset + args->offset;
@@ -732,10 +728,9 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
int hit_slowpath = 0;
int needs_clflush_after = 0;
int needs_clflush_before = 0;
- int i;
- struct scatterlist *sg;
+ struct sg_page_iter sg_iter;
- user_data = (char __user *) (uintptr_t) args->data_ptr;
+ user_data = to_user_ptr(args->data_ptr);
remain = args->size;
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
@@ -768,13 +763,11 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
offset = args->offset;
obj->dirty = 1;
- for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
- struct page *page;
+ for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
+ offset >> PAGE_SHIFT) {
+ struct page *page = sg_page_iter_page(&sg_iter);
int partial_cacheline_write;
- if (i < offset >> PAGE_SHIFT)
- continue;
-
if (remain <= 0)
break;
@@ -796,7 +789,6 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
((shmem_page_offset | page_length)
& (boot_cpu_data.x86_clflush_size - 1));
- page = sg_page(sg);
page_do_bit17_swizzling = obj_do_bit17_swizzling &&
(page_to_phys(page) & (1 << 17)) != 0;
@@ -867,11 +859,11 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
return 0;
if (!access_ok(VERIFY_READ,
- (char __user *)(uintptr_t)args->data_ptr,
+ to_user_ptr(args->data_ptr),
args->size))
return -EFAULT;
- ret = fault_in_multipages_readable((char __user *)(uintptr_t)args->data_ptr,
+ ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr),
args->size);
if (ret)
return -EFAULT;
@@ -1633,9 +1625,8 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
static void
i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
{
- int page_count = obj->base.size / PAGE_SIZE;
- struct scatterlist *sg;
- int ret, i;
+ struct sg_page_iter sg_iter;
+ int ret;
BUG_ON(obj->madv == __I915_MADV_PURGED);
@@ -1655,8 +1646,8 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
if (obj->madv == I915_MADV_DONTNEED)
obj->dirty = 0;
- for_each_sg(obj->pages->sgl, sg, page_count, i) {
- struct page *page = sg_page(sg);
+ for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+ struct page *page = sg_page_iter_page(&sg_iter);
if (obj->dirty)
set_page_dirty(page);
@@ -1757,7 +1748,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
struct address_space *mapping;
struct sg_table *st;
struct scatterlist *sg;
+ struct sg_page_iter sg_iter;
struct page *page;
+ unsigned long last_pfn = 0; /* suppress gcc warning */
gfp_t gfp;
/* Assert that the object is not currently in any GPU domain. As it
@@ -1787,7 +1780,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
gfp = mapping_gfp_mask(mapping);
gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
gfp &= ~(__GFP_IO | __GFP_WAIT);
- for_each_sg(st->sgl, sg, page_count, i) {
+ sg = st->sgl;
+ st->nents = 0;
+ for (i = 0; i < page_count; i++) {
page = shmem_read_mapping_page_gfp(mapping, i, gfp);
if (IS_ERR(page)) {
i915_gem_purge(dev_priv, page_count);
@@ -1810,9 +1805,18 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
gfp &= ~(__GFP_IO | __GFP_WAIT);
}
- sg_set_page(sg, page, PAGE_SIZE, 0);
+ if (!i || page_to_pfn(page) != last_pfn + 1) {
+ if (i)
+ sg = sg_next(sg);
+ st->nents++;
+ sg_set_page(sg, page, PAGE_SIZE, 0);
+ } else {
+ sg->length += PAGE_SIZE;
+ }
+ last_pfn = page_to_pfn(page);
}
+ sg_mark_end(sg);
obj->pages = st;
if (i915_gem_object_needs_bit17_swizzle(obj))
@@ -1821,8 +1825,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
return 0;
err_pages:
- for_each_sg(st->sgl, sg, i, page_count)
- page_cache_release(sg_page(sg));
+ sg_mark_end(sg);
+ for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
+ page_cache_release(sg_page_iter_page(&sg_iter));
sg_free_table(st);
kfree(st);
return PTR_ERR(page);
@@ -2123,11 +2128,11 @@ static void i915_gem_reset_fences(struct drm_device *dev)
for (i = 0; i < dev_priv->num_fence_regs; i++) {
struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
- i915_gem_write_fence(dev, i, NULL);
-
if (reg->obj)
i915_gem_object_fence_lost(reg->obj);
+ i915_gem_write_fence(dev, i, NULL);
+
reg->pin_count = 0;
reg->obj = NULL;
INIT_LIST_HEAD(&reg->lru_list);
@@ -2678,17 +2683,35 @@ static inline int fence_number(struct drm_i915_private *dev_priv,
return fence - dev_priv->fence_regs;
}
+static void i915_gem_write_fence__ipi(void *data)
+{
+ wbinvd();
+}
+
static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
struct drm_i915_fence_reg *fence,
bool enable)
{
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
- int reg = fence_number(dev_priv, fence);
-
- i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int fence_reg = fence_number(dev_priv, fence);
+
+ /* In order to fully serialize access to the fenced region and
+ * the update to the fence register we need to take extreme
+ * measures on SNB+. In theory, the write to the fence register
+ * flushes all memory transactions before, and coupled with the
+ * mb() placed around the register write we serialise all memory
+ * operations with respect to the changes in the tiler. Yet, on
+ * SNB+ we need to take a step further and emit an explicit wbinvd()
+ * on each processor in order to manually flush all memory
+ * transactions before updating the fence register.
+ */
+ if (HAS_LLC(obj->base.dev))
+ on_each_cpu(i915_gem_write_fence__ipi, NULL, 1);
+ i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL);
if (enable) {
- obj->fence_reg = reg;
+ obj->fence_reg = fence_reg;
fence->obj = obj;
list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
} else {
@@ -2717,6 +2740,7 @@ int
i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+ struct drm_i915_fence_reg *fence;
int ret;
ret = i915_gem_object_wait_fence(obj);
@@ -2726,10 +2750,10 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
if (obj->fence_reg == I915_FENCE_REG_NONE)
return 0;
- i915_gem_object_update_fence(obj,
- &dev_priv->fence_regs[obj->fence_reg],
- false);
+ fence = &dev_priv->fence_regs[obj->fence_reg];
+
i915_gem_object_fence_lost(obj);
+ i915_gem_object_update_fence(obj, fence, false);
return 0;
}
@@ -3986,6 +4010,12 @@ i915_gem_init_hw(struct drm_device *dev)
if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1))
I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000);
+ if (HAS_PCH_NOP(dev)) {
+ u32 temp = I915_READ(GEN7_MSG_CTL);
+ temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK);
+ I915_WRITE(GEN7_MSG_CTL, temp);
+ }
+
i915_gem_l3_remap(dev);
i915_gem_init_swizzling(dev);
@@ -3999,7 +4029,13 @@ i915_gem_init_hw(struct drm_device *dev)
* contexts before PPGTT.
*/
i915_gem_context_init(dev);
- i915_gem_init_ppgtt(dev);
+ if (dev_priv->mm.aliasing_ppgtt) {
+ ret = dev_priv->mm.aliasing_ppgtt->enable(dev);
+ if (ret) {
+ i915_gem_cleanup_aliasing_ppgtt(dev);
+ DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n");
+ }
+ }
return 0;
}
@@ -4010,7 +4046,16 @@ int i915_gem_init(struct drm_device *dev)
int ret;
mutex_lock(&dev->struct_mutex);
+
+ if (IS_VALLEYVIEW(dev)) {
+ /* VLVA0 (potential hack), BIOS isn't actually waking us */
+ I915_WRITE(VLV_GTLC_WAKE_CTRL, 1);
+ if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10))
+ DRM_DEBUG_DRIVER("allow wake ack timed out\n");
+ }
+
i915_gem_init_global_gtt(dev);
+
ret = i915_gem_init_hw(dev);
mutex_unlock(&dev->struct_mutex);
if (ret) {
@@ -4145,7 +4190,9 @@ i915_gem_load(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_MODESET))
dev_priv->fence_reg_start = 3;
- if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev))
+ dev_priv->num_fence_regs = 32;
+ else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
dev_priv->num_fence_regs = 16;
else
dev_priv->num_fence_regs = 8;
@@ -4327,7 +4374,7 @@ i915_gem_phys_pwrite(struct drm_device *dev,
struct drm_file *file_priv)
{
void *vaddr = obj->phys_obj->handle->vaddr + args->offset;
- char __user *user_data = (char __user *) (uintptr_t) args->data_ptr;
+ char __user *user_data = to_user_ptr(args->data_ptr);
if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
unsigned long unwritten;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 94d873a6cff..a1e8ecb6adf 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -152,6 +152,13 @@ create_hw_context(struct drm_device *dev,
return ERR_PTR(-ENOMEM);
}
+ if (INTEL_INFO(dev)->gen >= 7) {
+ ret = i915_gem_object_set_cache_level(ctx->obj,
+ I915_CACHE_LLC_MLC);
+ if (ret)
+ goto err_out;
+ }
+
/* The ring associated with the context object is handled by the normal
* object tracking code. We give an initial ring value simple to pass an
* assertion in the context switch code.
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
index 6a5af682862..dc53a527126 100644
--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -62,7 +62,7 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme
src = obj->pages->sgl;
dst = st->sgl;
for (i = 0; i < obj->pages->nents; i++) {
- sg_set_page(dst, sg_page(src), PAGE_SIZE, 0);
+ sg_set_page(dst, sg_page(src), src->length, 0);
dst = sg_next(dst);
src = sg_next(src);
}
@@ -105,7 +105,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
{
struct drm_i915_gem_object *obj = dma_buf->priv;
struct drm_device *dev = obj->base.dev;
- struct scatterlist *sg;
+ struct sg_page_iter sg_iter;
struct page **pages;
int ret, i;
@@ -124,14 +124,15 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
ret = -ENOMEM;
- pages = drm_malloc_ab(obj->pages->nents, sizeof(struct page *));
+ pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
if (pages == NULL)
goto error;
- for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i)
- pages[i] = sg_page(sg);
+ i = 0;
+ for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0)
+ pages[i++] = sg_page_iter_page(&sg_iter);
- obj->dma_buf_vmapping = vmap(pages, obj->pages->nents, 0, PAGE_KERNEL);
+ obj->dma_buf_vmapping = vmap(pages, i, 0, PAGE_KERNEL);
drm_free_large(pages);
if (!obj->dma_buf_vmapping)
@@ -271,7 +272,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
* refcount on gem itself instead of f_count of dmabuf.
*/
drm_gem_object_reference(&obj->base);
- dma_buf_put(dma_buf);
return &obj->base;
}
}
@@ -281,6 +281,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
if (IS_ERR(attach))
return ERR_CAST(attach);
+ get_dma_buf(dma_buf);
+
obj = i915_gem_object_alloc(dev);
if (obj == NULL) {
ret = -ENOMEM;
@@ -300,5 +302,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
fail_detach:
dma_buf_detach(dma_buf, attach);
+ dma_buf_put(dma_buf);
+
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 9a48e1a2d41..117ce381368 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -305,7 +305,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
int remain, ret;
- user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
+ user_relocs = to_user_ptr(entry->relocs_ptr);
remain = entry->relocation_count;
while (remain) {
@@ -359,8 +359,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
}
static int
-i915_gem_execbuffer_relocate(struct drm_device *dev,
- struct eb_objects *eb)
+i915_gem_execbuffer_relocate(struct eb_objects *eb)
{
struct drm_i915_gem_object *obj;
int ret = 0;
@@ -475,7 +474,6 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
static int
i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
- struct drm_file *file,
struct list_head *objects,
bool *need_relocs)
{
@@ -618,7 +616,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
u64 invalid_offset = (u64)-1;
int j;
- user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr;
+ user_relocs = to_user_ptr(exec[i].relocs_ptr);
if (copy_from_user(reloc+total, user_relocs,
exec[i].relocation_count * sizeof(*reloc))) {
@@ -663,7 +661,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
goto err;
need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
- ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs);
+ ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs);
if (ret)
goto err;
@@ -736,7 +734,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry);
for (i = 0; i < count; i++) {
- char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
+ char __user *ptr = to_user_ptr(exec[i].relocs_ptr);
int length; /* limited by fault_in_pages_readable() */
if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS)
@@ -752,7 +750,11 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
length = exec[i].relocation_count *
sizeof(struct drm_i915_gem_relocation_entry);
- /* we may also need to update the presumed offsets */
+ /*
+ * We must check that the entire relocation array is safe
+ * to read, but since we may need to update the presumed
+ * offsets during execution, check for full write access.
+ */
if (!access_ok(VERIFY_WRITE, ptr, length))
return -EFAULT;
@@ -949,9 +951,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
}
if (copy_from_user(cliprects,
- (struct drm_clip_rect __user *)(uintptr_t)
- args->cliprects_ptr,
- sizeof(*cliprects)*args->num_cliprects)) {
+ to_user_ptr(args->cliprects_ptr),
+ sizeof(*cliprects)*args->num_cliprects)) {
ret = -EFAULT;
goto pre_mutex_err;
}
@@ -986,13 +987,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
/* Move the objects en-masse into the GTT, evicting if necessary. */
need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0;
- ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs);
+ ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs);
if (ret)
goto err;
/* The objects are in their final locations, apply the relocations. */
if (need_relocs)
- ret = i915_gem_execbuffer_relocate(dev, eb);
+ ret = i915_gem_execbuffer_relocate(eb);
if (ret) {
if (ret == -EFAULT) {
ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring,
@@ -1115,7 +1116,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
return -ENOMEM;
}
ret = copy_from_user(exec_list,
- (void __user *)(uintptr_t)args->buffers_ptr,
+ to_user_ptr(args->buffers_ptr),
sizeof(*exec_list) * args->buffer_count);
if (ret != 0) {
DRM_DEBUG("copy %d exec entries failed %d\n",
@@ -1154,7 +1155,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
for (i = 0; i < args->buffer_count; i++)
exec_list[i].offset = exec2_list[i].offset;
/* ... and back out to userspace */
- ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr,
+ ret = copy_to_user(to_user_ptr(args->buffers_ptr),
exec_list,
sizeof(*exec_list) * args->buffer_count);
if (ret) {
@@ -1195,8 +1196,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
return -ENOMEM;
}
ret = copy_from_user(exec2_list,
- (struct drm_i915_relocation_entry __user *)
- (uintptr_t) args->buffers_ptr,
+ to_user_ptr(args->buffers_ptr),
sizeof(*exec2_list) * args->buffer_count);
if (ret != 0) {
DRM_DEBUG("copy %d exec entries failed %d\n",
@@ -1208,7 +1208,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
if (!ret) {
/* Copy the new buffer offsets back to the user's exec list. */
- ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr,
+ ret = copy_to_user(to_user_ptr(args->buffers_ptr),
exec2_list,
sizeof(*exec2_list) * args->buffer_count);
if (ret) {
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 926a1e2dd23..dca614de71b 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -28,7 +28,7 @@
#include "i915_trace.h"
#include "intel_drv.h"
-typedef uint32_t gtt_pte_t;
+typedef uint32_t gen6_gtt_pte_t;
/* PPGTT stuff */
#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0))
@@ -44,11 +44,11 @@ typedef uint32_t gtt_pte_t;
#define GEN6_PTE_CACHE_LLC_MLC (3 << 1)
#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
-static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev,
- dma_addr_t addr,
- enum i915_cache_level level)
+static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
+ dma_addr_t addr,
+ enum i915_cache_level level)
{
- gtt_pte_t pte = GEN6_PTE_VALID;
+ gen6_gtt_pte_t pte = GEN6_PTE_VALID;
pte |= GEN6_PTE_ADDR_ENCODE(addr);
switch (level) {
@@ -72,18 +72,85 @@ static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev,
BUG();
}
-
return pte;
}
+static int gen6_ppgtt_enable(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t pd_offset;
+ struct intel_ring_buffer *ring;
+ struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+ gen6_gtt_pte_t __iomem *pd_addr;
+ uint32_t pd_entry;
+ int i;
+
+ pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm +
+ ppgtt->pd_offset / sizeof(gen6_gtt_pte_t);
+ for (i = 0; i < ppgtt->num_pd_entries; i++) {
+ dma_addr_t pt_addr;
+
+ pt_addr = ppgtt->pt_dma_addr[i];
+ pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
+ pd_entry |= GEN6_PDE_VALID;
+
+ writel(pd_entry, pd_addr + i);
+ }
+ readl(pd_addr);
+
+ pd_offset = ppgtt->pd_offset;
+ pd_offset /= 64; /* in cachelines, */
+ pd_offset <<= 16;
+
+ if (INTEL_INFO(dev)->gen == 6) {
+ uint32_t ecochk, gab_ctl, ecobits;
+
+ ecobits = I915_READ(GAC_ECO_BITS);
+ I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
+ ECOBITS_PPGTT_CACHE64B);
+
+ gab_ctl = I915_READ(GAB_CTL);
+ I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
+
+ ecochk = I915_READ(GAM_ECOCHK);
+ I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
+ ECOCHK_PPGTT_CACHE64B);
+ I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+ } else if (INTEL_INFO(dev)->gen >= 7) {
+ uint32_t ecochk, ecobits;
+
+ ecobits = I915_READ(GAC_ECO_BITS);
+ I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
+
+ ecochk = I915_READ(GAM_ECOCHK);
+ if (IS_HASWELL(dev)) {
+ ecochk |= ECOCHK_PPGTT_WB_HSW;
+ } else {
+ ecochk |= ECOCHK_PPGTT_LLC_IVB;
+ ecochk &= ~ECOCHK_PPGTT_GFDT_IVB;
+ }
+ I915_WRITE(GAM_ECOCHK, ecochk);
+ /* GFX_MODE is per-ring on gen7+ */
+ }
+
+ for_each_ring(ring, dev_priv, i) {
+ if (INTEL_INFO(dev)->gen >= 7)
+ I915_WRITE(RING_MODE_GEN7(ring),
+ _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+
+ I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+ I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
+ }
+ return 0;
+}
+
/* PPGTT support for Sandybdrige/Gen6 and later */
static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
unsigned first_entry,
unsigned num_entries)
{
- gtt_pte_t *pt_vaddr;
- gtt_pte_t scratch_pte;
- unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+ gen6_gtt_pte_t *pt_vaddr, scratch_pte;
+ unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
unsigned last_pte, i;
@@ -96,7 +163,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
if (last_pte > I915_PPGTT_PT_ENTRIES)
last_pte = I915_PPGTT_PT_ENTRIES;
- pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+ pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
for (i = first_pte; i < last_pte; i++)
pt_vaddr[i] = scratch_pte;
@@ -105,7 +172,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
num_entries -= last_pte - first_pte;
first_pte = 0;
- act_pd++;
+ act_pt++;
}
}
@@ -114,43 +181,27 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
unsigned first_entry,
enum i915_cache_level cache_level)
{
- gtt_pte_t *pt_vaddr;
- unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
- unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
- unsigned i, j, m, segment_len;
- dma_addr_t page_addr;
- struct scatterlist *sg;
-
- /* init sg walking */
- sg = pages->sgl;
- i = 0;
- segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
- m = 0;
-
- while (i < pages->nents) {
- pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
-
- for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) {
- page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
- pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr,
- cache_level);
-
- /* grab the next page */
- if (++m == segment_len) {
- if (++i == pages->nents)
- break;
-
- sg = sg_next(sg);
- segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
- m = 0;
- }
- }
+ gen6_gtt_pte_t *pt_vaddr;
+ unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
+ unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+ struct sg_page_iter sg_iter;
- kunmap_atomic(pt_vaddr);
+ pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
+ for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
+ dma_addr_t page_addr;
- first_pte = 0;
- act_pd++;
+ page_addr = sg_page_iter_dma_address(&sg_iter);
+ pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr,
+ cache_level);
+ if (++act_pte == I915_PPGTT_PT_ENTRIES) {
+ kunmap_atomic(pt_vaddr);
+ act_pt++;
+ pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
+ act_pte = 0;
+
+ }
}
+ kunmap_atomic(pt_vaddr);
}
static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
@@ -182,10 +233,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
* entries. For aliasing ppgtt support we just steal them at the end for
* now. */
- first_pd_entry_in_global_pt =
- gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES;
+ first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
+ ppgtt->enable = gen6_ppgtt_enable;
ppgtt->clear_range = gen6_ppgtt_clear_range;
ppgtt->insert_entries = gen6_ppgtt_insert_entries;
ppgtt->cleanup = gen6_ppgtt_cleanup;
@@ -219,12 +270,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
ppgtt->pt_dma_addr[i] = pt_addr;
}
- ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma;
-
ppgtt->clear_range(ppgtt, 0,
ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
- ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t);
+ ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
return 0;
@@ -256,8 +305,13 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
return -ENOMEM;
ppgtt->dev = dev;
+ ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma;
+
+ if (INTEL_INFO(dev)->gen < 8)
+ ret = gen6_ppgtt_init(ppgtt);
+ else
+ BUG();
- ret = gen6_ppgtt_init(ppgtt);
if (ret)
kfree(ppgtt);
else
@@ -275,6 +329,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
return;
ppgtt->cleanup(ppgtt);
+ dev_priv->mm.aliasing_ppgtt = NULL;
}
void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
@@ -294,64 +349,6 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
obj->base.size >> PAGE_SHIFT);
}
-void i915_gem_init_ppgtt(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t pd_offset;
- struct intel_ring_buffer *ring;
- struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
- gtt_pte_t __iomem *pd_addr;
- uint32_t pd_entry;
- int i;
-
- if (!dev_priv->mm.aliasing_ppgtt)
- return;
-
-
- pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t);
- for (i = 0; i < ppgtt->num_pd_entries; i++) {
- dma_addr_t pt_addr;
-
- pt_addr = ppgtt->pt_dma_addr[i];
- pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
- pd_entry |= GEN6_PDE_VALID;
-
- writel(pd_entry, pd_addr + i);
- }
- readl(pd_addr);
-
- pd_offset = ppgtt->pd_offset;
- pd_offset /= 64; /* in cachelines, */
- pd_offset <<= 16;
-
- if (INTEL_INFO(dev)->gen == 6) {
- uint32_t ecochk, gab_ctl, ecobits;
-
- ecobits = I915_READ(GAC_ECO_BITS);
- I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
-
- gab_ctl = I915_READ(GAB_CTL);
- I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
-
- ecochk = I915_READ(GAM_ECOCHK);
- I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
- ECOCHK_PPGTT_CACHE64B);
- I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
- } else if (INTEL_INFO(dev)->gen >= 7) {
- I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B);
- /* GFX_MODE is per-ring on gen7+ */
- }
-
- for_each_ring(ring, dev_priv, i) {
- if (INTEL_INFO(dev)->gen >= 7)
- I915_WRITE(RING_MODE_GEN7(ring),
- _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
- I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
- I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
- }
-}
-
extern int intel_iommu_gfx_mapped;
/* Certain Gen5 chipsets require require idling the GPU before
* unmapping anything from the GTT when VT-d is enabled.
@@ -432,21 +429,16 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
enum i915_cache_level level)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct scatterlist *sg = st->sgl;
- gtt_pte_t __iomem *gtt_entries =
- (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
- int unused, i = 0;
- unsigned int len, m = 0;
+ gen6_gtt_pte_t __iomem *gtt_entries =
+ (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
+ int i = 0;
+ struct sg_page_iter sg_iter;
dma_addr_t addr;
- for_each_sg(st->sgl, sg, st->nents, unused) {
- len = sg_dma_len(sg) >> PAGE_SHIFT;
- for (m = 0; m < len; m++) {
- addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
- iowrite32(gen6_pte_encode(dev, addr, level),
- &gtt_entries[i]);
- i++;
- }
+ for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
+ addr = sg_page_iter_dma_address(&sg_iter);
+ iowrite32(gen6_pte_encode(dev, addr, level), &gtt_entries[i]);
+ i++;
}
/* XXX: This serves as a posting read to make sure that the PTE has
@@ -472,8 +464,8 @@ static void gen6_ggtt_clear_range(struct drm_device *dev,
unsigned int num_entries)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- gtt_pte_t scratch_pte;
- gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
+ gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
+ (gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
int i;
@@ -647,9 +639,12 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
int ret;
- /* PPGTT pdes are stolen from global gtt ptes, so shrink the
- * aperture accordingly when using aliasing ppgtt. */
- gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+
+ if (INTEL_INFO(dev)->gen <= 7) {
+ /* PPGTT pdes are stolen from global gtt ptes, so shrink the
+ * aperture accordingly when using aliasing ppgtt. */
+ gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+ }
i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
@@ -752,15 +747,17 @@ static int gen6_gmch_probe(struct drm_device *dev,
pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl);
- if (IS_GEN7(dev))
+ if (IS_GEN7(dev) && !IS_VALLEYVIEW(dev))
*stolen = gen7_get_stolen_size(snb_gmch_ctl);
else
*stolen = gen6_get_stolen_size(snb_gmch_ctl);
- *gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT;
+ *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT;
+
+ /* For Modern GENs the PTEs and register space are split in the BAR */
+ gtt_bus_addr = pci_resource_start(dev->pdev, 0) +
+ (pci_resource_len(dev->pdev, 0) / 2);
- /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */
- gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20);
dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size);
if (!dev_priv->gtt.gsm) {
DRM_ERROR("Failed to map the gtt page table\n");
@@ -817,7 +814,6 @@ int i915_gem_gtt_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_gtt *gtt = &dev_priv->gtt;
- unsigned long gtt_size;
int ret;
if (INTEL_INFO(dev)->gen <= 5) {
@@ -835,8 +831,6 @@ int i915_gem_gtt_init(struct drm_device *dev)
if (ret)
return ret;
- gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t);
-
/* GMADR is the PCI mmio aperture into the global GTT. */
DRM_INFO("Memory usable by graphics device = %zdM\n",
dev_priv->gtt.total >> 20);
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 69d97cbac13..130d1db27e2 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -312,6 +312,71 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
return NULL;
}
+struct drm_i915_gem_object *
+i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
+ u32 stolen_offset,
+ u32 gtt_offset,
+ u32 size)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj;
+ struct drm_mm_node *stolen;
+
+ if (dev_priv->mm.stolen_base == 0)
+ return NULL;
+
+ DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n",
+ stolen_offset, gtt_offset, size);
+
+ /* KISS and expect everything to be page-aligned */
+ BUG_ON(stolen_offset & 4095);
+ BUG_ON(gtt_offset & 4095);
+ BUG_ON(size & 4095);
+
+ if (WARN_ON(size == 0))
+ return NULL;
+
+ stolen = drm_mm_create_block(&dev_priv->mm.stolen,
+ stolen_offset, size,
+ false);
+ if (stolen == NULL) {
+ DRM_DEBUG_KMS("failed to allocate stolen space\n");
+ return NULL;
+ }
+
+ obj = _i915_gem_object_create_stolen(dev, stolen);
+ if (obj == NULL) {
+ DRM_DEBUG_KMS("failed to allocate stolen object\n");
+ drm_mm_put_block(stolen);
+ return NULL;
+ }
+
+ /* To simplify the initialisation sequence between KMS and GTT,
+ * we allow construction of the stolen object prior to
+ * setting up the GTT space. The actual reservation will occur
+ * later.
+ */
+ if (drm_mm_initialized(&dev_priv->mm.gtt_space)) {
+ obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space,
+ gtt_offset, size,
+ false);
+ if (obj->gtt_space == NULL) {
+ DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
+ drm_gem_object_unreference(&obj->base);
+ return NULL;
+ }
+ } else
+ obj->gtt_space = I915_GTT_RESERVED;
+
+ obj->gtt_offset = gtt_offset;
+ obj->has_global_gtt_mapping = 1;
+
+ list_add_tail(&obj->gtt_list, &dev_priv->mm.bound_list);
+ list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+
+ return obj;
+}
+
void
i915_gem_object_release_stolen(struct drm_i915_gem_object *obj)
{
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index abcba2f5a78..537545be69d 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -217,9 +217,12 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
tile_width = 512;
/* check maximum stride & object size */
- if (INTEL_INFO(dev)->gen >= 4) {
- /* i965 stores the end address of the gtt mapping in the fence
- * reg, so dont bother to check the size */
+ /* i965+ stores the end address of the gtt mapping in the fence
+ * reg, so dont bother to check the size */
+ if (INTEL_INFO(dev)->gen >= 7) {
+ if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL)
+ return false;
+ } else if (INTEL_INFO(dev)->gen >= 4) {
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
return false;
} else {
@@ -235,6 +238,9 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
}
}
+ if (stride < tile_width)
+ return false;
+
/* 965+ just needs multiples of tile width */
if (INTEL_INFO(dev)->gen >= 4) {
if (stride & (tile_width - 1))
@@ -243,9 +249,6 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
}
/* Pre-965 needs power of two tile widths */
- if (stride < tile_width)
- return false;
-
if (stride & (stride - 1))
return false;
@@ -473,28 +476,29 @@ i915_gem_swizzle_page(struct page *page)
void
i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
{
- struct scatterlist *sg;
- int page_count = obj->base.size >> PAGE_SHIFT;
+ struct sg_page_iter sg_iter;
int i;
if (obj->bit_17 == NULL)
return;
- for_each_sg(obj->pages->sgl, sg, page_count, i) {
- struct page *page = sg_page(sg);
+ i = 0;
+ for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+ struct page *page = sg_page_iter_page(&sg_iter);
char new_bit_17 = page_to_phys(page) >> 17;
if ((new_bit_17 & 0x1) !=
(test_bit(i, obj->bit_17) != 0)) {
i915_gem_swizzle_page(page);
set_page_dirty(page);
}
+ i++;
}
}
void
i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
{
- struct scatterlist *sg;
+ struct sg_page_iter sg_iter;
int page_count = obj->base.size >> PAGE_SHIFT;
int i;
@@ -508,11 +512,12 @@ i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
}
}
- for_each_sg(obj->pages->sgl, sg, page_count, i) {
- struct page *page = sg_page(sg);
- if (page_to_phys(page) & (1 << 17))
+ i = 0;
+ for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+ if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17))
__set_bit(i, obj->bit_17);
else
__clear_bit(i, obj->bit_17);
+ i++;
}
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 3c7bb0410b5..0aa2ef0d2ae 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -36,6 +36,61 @@
#include "i915_trace.h"
#include "intel_drv.h"
+static const u32 hpd_ibx[] = {
+ [HPD_CRT] = SDE_CRT_HOTPLUG,
+ [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
+ [HPD_PORT_B] = SDE_PORTB_HOTPLUG,
+ [HPD_PORT_C] = SDE_PORTC_HOTPLUG,
+ [HPD_PORT_D] = SDE_PORTD_HOTPLUG
+};
+
+static const u32 hpd_cpt[] = {
+ [HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
+ [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
+ [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
+ [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
+ [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
+};
+
+static const u32 hpd_mask_i915[] = {
+ [HPD_CRT] = CRT_HOTPLUG_INT_EN,
+ [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
+ [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
+ [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN,
+ [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN,
+ [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
+};
+
+static const u32 hpd_status_gen4[] = {
+ [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+ [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
+ [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
+ [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+ [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+ [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+static const u32 hpd_status_i965[] = {
+ [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+ [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965,
+ [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965,
+ [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+ [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+ [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
+ [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+ [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
+ [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
+ [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+ [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+ [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+static void ibx_hpd_irq_setup(struct drm_device *dev);
+static void i915_hpd_irq_setup(struct drm_device *dev);
+
/* For display hotplug interrupt */
static void
ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -47,7 +102,7 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
}
}
-static inline void
+static void
ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{
if ((dev_priv->irq_mask & mask) != mask) {
@@ -60,26 +115,30 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
void
i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
{
- if ((dev_priv->pipestat[pipe] & mask) != mask) {
- u32 reg = PIPESTAT(pipe);
+ u32 reg = PIPESTAT(pipe);
+ u32 pipestat = I915_READ(reg) & 0x7fff0000;
- dev_priv->pipestat[pipe] |= mask;
- /* Enable the interrupt, clear any pending status */
- I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16));
- POSTING_READ(reg);
- }
+ if ((pipestat & mask) == mask)
+ return;
+
+ /* Enable the interrupt, clear any pending status */
+ pipestat |= mask | (mask >> 16);
+ I915_WRITE(reg, pipestat);
+ POSTING_READ(reg);
}
void
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
{
- if ((dev_priv->pipestat[pipe] & mask) != 0) {
- u32 reg = PIPESTAT(pipe);
+ u32 reg = PIPESTAT(pipe);
+ u32 pipestat = I915_READ(reg) & 0x7fff0000;
- dev_priv->pipestat[pipe] &= ~mask;
- I915_WRITE(reg, dev_priv->pipestat[pipe]);
- POSTING_READ(reg);
- }
+ if ((pipestat & mask) == 0)
+ return;
+
+ pipestat &= ~mask;
+ I915_WRITE(reg, pipestat);
+ POSTING_READ(reg);
}
/**
@@ -250,10 +309,9 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
struct timeval *vblank_time,
unsigned flags)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
- if (pipe < 0 || pipe >= dev_priv->num_pipe) {
+ if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) {
DRM_ERROR("Invalid crtc %d\n", pipe);
return -EINVAL;
}
@@ -279,13 +337,19 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
/*
* Handle hotplug events outside the interrupt handler proper.
*/
+#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000)
+
static void i915_hotplug_work_func(struct work_struct *work)
{
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
hotplug_work);
struct drm_device *dev = dev_priv->dev;
struct drm_mode_config *mode_config = &dev->mode_config;
- struct intel_encoder *encoder;
+ struct intel_connector *intel_connector;
+ struct intel_encoder *intel_encoder;
+ struct drm_connector *connector;
+ unsigned long irqflags;
+ bool hpd_disabled = false;
/* HPD irq before everything is fully set up. */
if (!dev_priv->enable_hotplug_processing)
@@ -294,9 +358,36 @@ static void i915_hotplug_work_func(struct work_struct *work)
mutex_lock(&mode_config->mutex);
DRM_DEBUG_KMS("running encoder hotplug functions\n");
- list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
- if (encoder->hot_plug)
- encoder->hot_plug(encoder);
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ list_for_each_entry(connector, &mode_config->connector_list, head) {
+ intel_connector = to_intel_connector(connector);
+ intel_encoder = intel_connector->encoder;
+ if (intel_encoder->hpd_pin > HPD_NONE &&
+ dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED &&
+ connector->polled == DRM_CONNECTOR_POLL_HPD) {
+ DRM_INFO("HPD interrupt storm detected on connector %s: "
+ "switching from hotplug detection to polling\n",
+ drm_get_connector_name(connector));
+ dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED;
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT
+ | DRM_CONNECTOR_POLL_DISCONNECT;
+ hpd_disabled = true;
+ }
+ }
+ /* if there were no outputs to poll, poll was disabled,
+ * therefore make sure it's enabled when disabling HPD on
+ * some connectors */
+ if (hpd_disabled) {
+ drm_kms_helper_poll_enable(dev);
+ mod_timer(&dev_priv->hotplug_reenable_timer,
+ jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY));
+ }
+
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+ if (intel_encoder->hot_plug)
+ intel_encoder->hot_plug(intel_encoder);
mutex_unlock(&mode_config->mutex);
@@ -525,6 +616,45 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
queue_work(dev_priv->wq, &dev_priv->rps.work);
}
+#define HPD_STORM_DETECT_PERIOD 1000
+#define HPD_STORM_THRESHOLD 5
+
+static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
+ u32 hotplug_trigger,
+ const u32 *hpd)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long irqflags;
+ int i;
+ bool ret = false;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+ for (i = 1; i < HPD_NUM_PINS; i++) {
+
+ if (!(hpd[i] & hotplug_trigger) ||
+ dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
+ continue;
+
+ if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies,
+ dev_priv->hpd_stats[i].hpd_last_jiffies
+ + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) {
+ dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies;
+ dev_priv->hpd_stats[i].hpd_cnt = 0;
+ } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) {
+ dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
+ DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
+ ret = true;
+ } else {
+ dev_priv->hpd_stats[i].hpd_cnt++;
+ }
+ }
+
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ return ret;
+}
+
static void gmbus_irq_handler(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -593,13 +723,16 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
/* Consume port. Then clear IIR or we'll miss events */
if (iir & I915_DISPLAY_PORT_INTERRUPT) {
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+ u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status);
- if (hotplug_status & dev_priv->hotplug_supported_mask)
+ if (hotplug_trigger) {
+ if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+ i915_hpd_irq_setup(dev);
queue_work(dev_priv->wq,
&dev_priv->hotplug_work);
-
+ }
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
I915_READ(PORT_HOTPLUG_STAT);
}
@@ -623,10 +756,13 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int pipe;
+ u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
- if (pch_iir & SDE_HOTPLUG_MASK)
+ if (hotplug_trigger) {
+ if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx))
+ ibx_hpd_irq_setup(dev);
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
-
+ }
if (pch_iir & SDE_AUDIO_POWER_MASK)
DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
(pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -669,10 +805,13 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int pipe;
+ u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
- if (pch_iir & SDE_HOTPLUG_MASK_CPT)
+ if (hotplug_trigger) {
+ if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt))
+ ibx_hpd_irq_setup(dev);
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
-
+ }
if (pch_iir & SDE_AUDIO_POWER_MASK_CPT)
DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
(pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -701,7 +840,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier;
+ u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier = 0;
irqreturn_t ret = IRQ_NONE;
int i;
@@ -716,9 +855,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
* able to process them after we restore SDEIER (as soon as we restore
* it, we'll get an interrupt if SDEIIR still has something to process
* due to its back queue). */
- sde_ier = I915_READ(SDEIER);
- I915_WRITE(SDEIER, 0);
- POSTING_READ(SDEIER);
+ if (!HAS_PCH_NOP(dev)) {
+ sde_ier = I915_READ(SDEIER);
+ I915_WRITE(SDEIER, 0);
+ POSTING_READ(SDEIER);
+ }
gt_iir = I915_READ(GTIIR);
if (gt_iir) {
@@ -745,7 +886,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
}
/* check event from PCH */
- if (de_iir & DE_PCH_EVENT_IVB) {
+ if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) {
u32 pch_iir = I915_READ(SDEIIR);
cpt_irq_handler(dev, pch_iir);
@@ -768,8 +909,10 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
I915_WRITE(DEIER, de_ier);
POSTING_READ(DEIER);
- I915_WRITE(SDEIER, sde_ier);
- POSTING_READ(SDEIER);
+ if (!HAS_PCH_NOP(dev)) {
+ I915_WRITE(SDEIER, sde_ier);
+ POSTING_READ(SDEIER);
+ }
return ret;
}
@@ -937,6 +1080,8 @@ static void i915_error_work_func(struct work_struct *work)
for_each_ring(ring, dev_priv, i)
wake_up_all(&ring->irq_queue);
+ intel_display_handle_reset(dev);
+
wake_up_all(&dev_priv->gpu_error.reset_queue);
}
}
@@ -972,24 +1117,23 @@ static void i915_get_extra_instdone(struct drm_device *dev,
#ifdef CONFIG_DEBUG_FS
static struct drm_i915_error_object *
-i915_error_object_create(struct drm_i915_private *dev_priv,
- struct drm_i915_gem_object *src)
+i915_error_object_create_sized(struct drm_i915_private *dev_priv,
+ struct drm_i915_gem_object *src,
+ const int num_pages)
{
struct drm_i915_error_object *dst;
- int i, count;
+ int i;
u32 reloc_offset;
if (src == NULL || src->pages == NULL)
return NULL;
- count = src->base.size / PAGE_SIZE;
-
- dst = kmalloc(sizeof(*dst) + count * sizeof(u32 *), GFP_ATOMIC);
+ dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
if (dst == NULL)
return NULL;
reloc_offset = src->gtt_offset;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < num_pages; i++) {
unsigned long flags;
void *d;
@@ -1039,7 +1183,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
reloc_offset += PAGE_SIZE;
}
- dst->page_count = count;
+ dst->page_count = num_pages;
dst->gtt_offset = src->gtt_offset;
return dst;
@@ -1050,6 +1194,9 @@ unwind:
kfree(dst);
return NULL;
}
+#define i915_error_object_create(dev_priv, src) \
+ i915_error_object_create_sized((dev_priv), (src), \
+ (src)->base.size>>PAGE_SHIFT)
static void
i915_error_object_free(struct drm_i915_error_object *obj)
@@ -1148,7 +1295,7 @@ static void i915_gem_record_fences(struct drm_device *dev,
switch (INTEL_INFO(dev)->gen) {
case 7:
case 6:
- for (i = 0; i < 16; i++)
+ for (i = 0; i < dev_priv->num_fence_regs; i++)
error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
break;
case 5:
@@ -1256,6 +1403,26 @@ static void i915_record_ring_state(struct drm_device *dev,
error->cpu_ring_tail[ring->id] = ring->tail;
}
+
+static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
+ struct drm_i915_error_state *error,
+ struct drm_i915_error_ring *ering)
+{
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ struct drm_i915_gem_object *obj;
+
+ /* Currently render ring is the only HW context user */
+ if (ring->id != RCS || !error->ccid)
+ return;
+
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ if ((error->ccid & PAGE_MASK) == obj->gtt_offset) {
+ ering->ctx = i915_error_object_create_sized(dev_priv,
+ obj, 1);
+ }
+ }
+}
+
static void i915_gem_record_rings(struct drm_device *dev,
struct drm_i915_error_state *error)
{
@@ -1273,6 +1440,9 @@ static void i915_gem_record_rings(struct drm_device *dev,
error->ring[i].ringbuffer =
i915_error_object_create(dev_priv, ring->obj);
+
+ i915_gem_record_active_context(ring, error, &error->ring[i]);
+
count = 0;
list_for_each_entry(request, &ring->request_list, list)
count++;
@@ -1328,14 +1498,15 @@ static void i915_capture_error_state(struct drm_device *dev)
return;
}
- DRM_INFO("capturing error event; look for more information in"
+ DRM_INFO("capturing error event; look for more information in "
"/sys/kernel/debug/dri/%d/i915_error_state\n",
dev->primary->index);
kref_init(&error->ref);
error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER);
- error->ccid = I915_READ(CCID);
+ if (HAS_HW_CONTEXTS(dev))
+ error->ccid = I915_READ(CCID);
if (HAS_PCH_SPLIT(dev))
error->ier = I915_READ(DEIER) | I915_READ(GTIER);
@@ -1356,8 +1527,9 @@ static void i915_capture_error_state(struct drm_device *dev)
else if (INTEL_INFO(dev)->gen == 6)
error->forcewake = I915_READ(FORCEWAKE);
- for_each_pipe(pipe)
- error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
+ if (!HAS_PCH_SPLIT(dev))
+ for_each_pipe(pipe)
+ error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
if (INTEL_INFO(dev)->gen >= 6) {
error->error = I915_READ(ERROR_GEN6);
@@ -1567,7 +1739,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
queue_work(dev_priv->wq, &dev_priv->gpu_error.work);
}
-static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
+static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
@@ -1777,6 +1949,37 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
return false;
}
+static bool semaphore_passed(struct intel_ring_buffer *ring)
+{
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR;
+ struct intel_ring_buffer *signaller;
+ u32 cmd, ipehr, acthd_min;
+
+ ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
+ if ((ipehr & ~(0x3 << 16)) !=
+ (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER))
+ return false;
+
+ /* ACTHD is likely pointing to the dword after the actual command,
+ * so scan backwards until we find the MBOX.
+ */
+ acthd_min = max((int)acthd - 3 * 4, 0);
+ do {
+ cmd = ioread32(ring->virtual_start + acthd);
+ if (cmd == ipehr)
+ break;
+
+ acthd -= 4;
+ if (acthd < acthd_min)
+ return false;
+ } while (1);
+
+ signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
+ return i915_seqno_passed(signaller->get_seqno(signaller, false),
+ ioread32(ring->virtual_start+acthd+4)+1);
+}
+
static bool kick_ring(struct intel_ring_buffer *ring)
{
struct drm_device *dev = ring->dev;
@@ -1788,6 +1991,15 @@ static bool kick_ring(struct intel_ring_buffer *ring)
I915_WRITE_CTL(ring, tmp);
return true;
}
+
+ if (INTEL_INFO(dev)->gen >= 6 &&
+ tmp & RING_WAIT_SEMAPHORE &&
+ semaphore_passed(ring)) {
+ DRM_ERROR("Kicking stuck semaphore on %s\n",
+ ring->name);
+ I915_WRITE_CTL(ring, tmp);
+ return true;
+ }
return false;
}
@@ -1901,9 +2113,18 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
I915_WRITE(GTIER, 0x0);
POSTING_READ(GTIER);
+ if (HAS_PCH_NOP(dev))
+ return;
+
/* south display irq */
I915_WRITE(SDEIMR, 0xffffffff);
- I915_WRITE(SDEIER, 0x0);
+ /*
+ * SDEIER is also touched by the interrupt handler to work around missed
+ * PCH interrupts. Hence we can't update it after the interrupt handler
+ * is enabled - instead we unconditionally enable all PCH interrupt
+ * sources here, but then only unmask them as needed with SDEIMR.
+ */
+ I915_WRITE(SDEIER, 0xffffffff);
POSTING_READ(SDEIER);
}
@@ -1939,18 +2160,34 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
POSTING_READ(VLV_IER);
}
-/*
- * Enable digital hotplug on the PCH, and configure the DP short pulse
- * duration to 2ms (which is the minimum in the Display Port spec)
- *
- * This register is the same on all known PCH chips.
- */
-
-static void ibx_enable_hotplug(struct drm_device *dev)
+static void ibx_hpd_irq_setup(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 hotplug;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct intel_encoder *intel_encoder;
+ u32 mask = ~I915_READ(SDEIMR);
+ u32 hotplug;
+
+ if (HAS_PCH_IBX(dev)) {
+ mask &= ~SDE_HOTPLUG_MASK;
+ list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+ if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+ mask |= hpd_ibx[intel_encoder->hpd_pin];
+ } else {
+ mask &= ~SDE_HOTPLUG_MASK_CPT;
+ list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+ if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+ mask |= hpd_cpt[intel_encoder->hpd_pin];
+ }
+ I915_WRITE(SDEIMR, ~mask);
+
+ /*
+ * Enable digital hotplug on the PCH, and configure the DP short pulse
+ * duration to 2ms (which is the minimum in the Display Port spec)
+ *
+ * This register is the same on all known PCH chips.
+ */
hotplug = I915_READ(PCH_PORT_HOTPLUG);
hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK);
hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
@@ -1965,20 +2202,15 @@ static void ibx_irq_postinstall(struct drm_device *dev)
u32 mask;
if (HAS_PCH_IBX(dev))
- mask = SDE_HOTPLUG_MASK |
- SDE_GMBUS |
- SDE_AUX_MASK;
+ mask = SDE_GMBUS | SDE_AUX_MASK;
else
- mask = SDE_HOTPLUG_MASK_CPT |
- SDE_GMBUS_CPT |
- SDE_AUX_MASK_CPT;
+ mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
+
+ if (HAS_PCH_NOP(dev))
+ return;
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
I915_WRITE(SDEIMR, ~mask);
- I915_WRITE(SDEIER, mask);
- POSTING_READ(SDEIER);
-
- ibx_enable_hotplug(dev);
}
static int ironlake_irq_postinstall(struct drm_device *dev)
@@ -2089,9 +2321,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
- dev_priv->pipestat[0] = 0;
- dev_priv->pipestat[1] = 0;
-
/* Hack for broken MSIs on VLV */
pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000);
pci_read_config_word(dev->pdev, 0x98, &msid);
@@ -2135,30 +2364,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
return 0;
}
-static void valleyview_hpd_irq_setup(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-
- /* Note HDMI and DP share bits */
- if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTB_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTC_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTD_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
- hotplug_en |= SDVOC_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
- hotplug_en |= SDVOB_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
- hotplug_en |= CRT_HOTPLUG_INT_EN;
- hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
- }
-
- I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-}
-
static void valleyview_irq_uninstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -2167,6 +2372,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
if (!dev_priv)
return;
+ del_timer_sync(&dev_priv->hotplug_reenable_timer);
+
for_each_pipe(pipe)
I915_WRITE(PIPESTAT(pipe), 0xffff);
@@ -2188,6 +2395,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
if (!dev_priv)
return;
+ del_timer_sync(&dev_priv->hotplug_reenable_timer);
+
I915_WRITE(HWSTAM, 0xffffffff);
I915_WRITE(DEIMR, 0xffffffff);
@@ -2198,6 +2407,9 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
I915_WRITE(GTIER, 0x0);
I915_WRITE(GTIIR, I915_READ(GTIIR));
+ if (HAS_PCH_NOP(dev))
+ return;
+
I915_WRITE(SDEIMR, 0xffffffff);
I915_WRITE(SDEIER, 0x0);
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
@@ -2221,9 +2433,6 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- dev_priv->pipestat[0] = 0;
- dev_priv->pipestat[1] = 0;
-
I915_WRITE16(EMR,
~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
@@ -2246,6 +2455,37 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
return 0;
}
+/*
+ * Returns true when a page flip has completed.
+ */
+static bool i8xx_handle_vblank(struct drm_device *dev,
+ int pipe, u16 iir)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe);
+
+ if (!drm_handle_vblank(dev, pipe))
+ return false;
+
+ if ((iir & flip_pending) == 0)
+ return false;
+
+ intel_prepare_page_flip(dev, pipe);
+
+ /* We detect FlipDone by looking for the change in PendingFlip from '1'
+ * to '0' on the following vblank, i.e. IIR has the Pendingflip
+ * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
+ * the flip is completed (no longer pending). Since this doesn't raise
+ * an interrupt per se, we watch for the change at vblank.
+ */
+ if (I915_READ16(ISR) & flip_pending)
+ return false;
+
+ intel_finish_page_flip(dev, pipe);
+
+ return true;
+}
+
static irqreturn_t i8xx_irq_handler(int irq, void *arg)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -2301,22 +2541,12 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
notify_ring(dev, &dev_priv->ring[RCS]);
if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
- drm_handle_vblank(dev, 0)) {
- if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
- intel_prepare_page_flip(dev, 0);
- intel_finish_page_flip(dev, 0);
- flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
- }
- }
+ i8xx_handle_vblank(dev, 0, iir))
+ flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0);
if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
- drm_handle_vblank(dev, 1)) {
- if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
- intel_prepare_page_flip(dev, 1);
- intel_finish_page_flip(dev, 1);
- flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
- }
- }
+ i8xx_handle_vblank(dev, 1, iir))
+ flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1);
iir = new_iir;
}
@@ -2364,9 +2594,6 @@ static int i915_irq_postinstall(struct drm_device *dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 enable_mask;
- dev_priv->pipestat[0] = 0;
- dev_priv->pipestat[1] = 0;
-
I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
/* Unmask the interrupts that we always want on. */
@@ -2404,33 +2631,35 @@ static int i915_irq_postinstall(struct drm_device *dev)
return 0;
}
-static void i915_hpd_irq_setup(struct drm_device *dev)
+/*
+ * Returns true when a page flip has completed.
+ */
+static bool i915_handle_vblank(struct drm_device *dev,
+ int plane, int pipe, u32 iir)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 hotplug_en;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
- if (I915_HAS_HOTPLUG(dev)) {
- hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+ if (!drm_handle_vblank(dev, pipe))
+ return false;
- if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTB_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTC_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTD_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
- hotplug_en |= SDVOC_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
- hotplug_en |= SDVOB_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
- hotplug_en |= CRT_HOTPLUG_INT_EN;
- hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
- }
+ if ((iir & flip_pending) == 0)
+ return false;
- /* Ignore TV since it's buggy */
+ intel_prepare_page_flip(dev, plane);
- I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
- }
+ /* We detect FlipDone by looking for the change in PendingFlip from '1'
+ * to '0' on the following vblank, i.e. IIR has the Pendingflip
+ * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
+ * the flip is completed (no longer pending). Since this doesn't raise
+ * an interrupt per se, we watch for the change at vblank.
+ */
+ if (I915_READ(ISR) & flip_pending)
+ return false;
+
+ intel_finish_page_flip(dev, pipe);
+
+ return true;
}
static irqreturn_t i915_irq_handler(int irq, void *arg)
@@ -2442,10 +2671,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
u32 flip_mask =
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
- u32 flip[2] = {
- I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT,
- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT
- };
int pipe, ret = IRQ_NONE;
atomic_inc(&dev_priv->irq_received);
@@ -2486,13 +2711,16 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
if ((I915_HAS_HOTPLUG(dev)) &&
(iir & I915_DISPLAY_PORT_INTERRUPT)) {
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+ u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status);
- if (hotplug_status & dev_priv->hotplug_supported_mask)
+ if (hotplug_trigger) {
+ if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+ i915_hpd_irq_setup(dev);
queue_work(dev_priv->wq,
&dev_priv->hotplug_work);
-
+ }
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
POSTING_READ(PORT_HOTPLUG_STAT);
}
@@ -2507,14 +2735,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
int plane = pipe;
if (IS_MOBILE(dev))
plane = !plane;
+
if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
- drm_handle_vblank(dev, pipe)) {
- if (iir & flip[plane]) {
- intel_prepare_page_flip(dev, plane);
- intel_finish_page_flip(dev, pipe);
- flip_mask &= ~flip[plane];
- }
- }
+ i915_handle_vblank(dev, plane, pipe, iir))
+ flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
blc_event = true;
@@ -2552,6 +2776,8 @@ static void i915_irq_uninstall(struct drm_device * dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int pipe;
+ del_timer_sync(&dev_priv->hotplug_reenable_timer);
+
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -2603,13 +2829,13 @@ static int i965_irq_postinstall(struct drm_device *dev)
I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
enable_mask = ~dev_priv->irq_mask;
+ enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT);
enable_mask |= I915_USER_INTERRUPT;
if (IS_G4X(dev))
enable_mask |= I915_BSD_USER_INTERRUPT;
- dev_priv->pipestat[0] = 0;
- dev_priv->pipestat[1] = 0;
i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
/*
@@ -2639,45 +2865,33 @@ static int i965_irq_postinstall(struct drm_device *dev)
return 0;
}
-static void i965_hpd_irq_setup(struct drm_device *dev)
+static void i915_hpd_irq_setup(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct intel_encoder *intel_encoder;
u32 hotplug_en;
- /* Note HDMI and DP share hotplug bits */
- hotplug_en = 0;
- if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTB_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTC_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
- hotplug_en |= PORTD_HOTPLUG_INT_EN;
- if (IS_G4X(dev)) {
- if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)
- hotplug_en |= SDVOC_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X)
- hotplug_en |= SDVOB_HOTPLUG_INT_EN;
- } else {
- if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965)
- hotplug_en |= SDVOC_HOTPLUG_INT_EN;
- if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965)
- hotplug_en |= SDVOB_HOTPLUG_INT_EN;
- }
- if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
- hotplug_en |= CRT_HOTPLUG_INT_EN;
-
+ if (I915_HAS_HOTPLUG(dev)) {
+ hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+ hotplug_en &= ~HOTPLUG_INT_EN_MASK;
+ /* Note HDMI and DP share hotplug bits */
+ /* enable bits are the same for all generations */
+ list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+ if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+ hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
/* Programming the CRT detection parameters tends
to generate a spurious hotplug event about three
seconds later. So just do it once.
- */
+ */
if (IS_G4X(dev))
hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
+ hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
- }
-
- /* Ignore TV since it's buggy */
- I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+ /* Ignore TV since it's buggy */
+ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+ }
}
static irqreturn_t i965_irq_handler(int irq, void *arg)
@@ -2689,6 +2903,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
unsigned long irqflags;
int irq_received;
int ret = IRQ_NONE, pipe;
+ u32 flip_mask =
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
atomic_inc(&dev_priv->irq_received);
@@ -2697,7 +2914,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
for (;;) {
bool blc_event = false;
- irq_received = iir != 0;
+ irq_received = (iir & ~flip_mask) != 0;
/* Can't rely on pipestat interrupt bit in iir as it might
* have been cleared after the pipestat interrupt was received.
@@ -2733,18 +2950,24 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
/* Consume port. Then clear IIR or we'll miss events */
if (iir & I915_DISPLAY_PORT_INTERRUPT) {
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+ u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ?
+ HOTPLUG_INT_STATUS_G4X :
+ HOTPLUG_INT_STATUS_I965);
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status);
- if (hotplug_status & dev_priv->hotplug_supported_mask)
+ if (hotplug_trigger) {
+ if (hotplug_irq_storm_detect(dev, hotplug_trigger,
+ IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965))
+ i915_hpd_irq_setup(dev);
queue_work(dev_priv->wq,
&dev_priv->hotplug_work);
-
+ }
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
I915_READ(PORT_HOTPLUG_STAT);
}
- I915_WRITE(IIR, iir);
+ I915_WRITE(IIR, iir & ~flip_mask);
new_iir = I915_READ(IIR); /* Flush posted writes */
if (iir & I915_USER_INTERRUPT)
@@ -2752,18 +2975,10 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
if (iir & I915_BSD_USER_INTERRUPT)
notify_ring(dev, &dev_priv->ring[VCS]);
- if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT)
- intel_prepare_page_flip(dev, 0);
-
- if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT)
- intel_prepare_page_flip(dev, 1);
-
for_each_pipe(pipe) {
if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
- drm_handle_vblank(dev, pipe)) {
- i915_pageflip_stall_check(dev, pipe);
- intel_finish_page_flip(dev, pipe);
- }
+ i915_handle_vblank(dev, pipe, pipe, iir))
+ flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
blc_event = true;
@@ -2807,6 +3022,8 @@ static void i965_irq_uninstall(struct drm_device * dev)
if (!dev_priv)
return;
+ del_timer_sync(&dev_priv->hotplug_reenable_timer);
+
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -2822,6 +3039,41 @@ static void i965_irq_uninstall(struct drm_device * dev)
I915_WRITE(IIR, I915_READ(IIR));
}
+static void i915_reenable_hotplug_timer_func(unsigned long data)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *)data;
+ struct drm_device *dev = dev_priv->dev;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ unsigned long irqflags;
+ int i;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) {
+ struct drm_connector *connector;
+
+ if (dev_priv->hpd_stats[i].hpd_mark != HPD_DISABLED)
+ continue;
+
+ dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED;
+
+ list_for_each_entry(connector, &mode_config->connector_list, head) {
+ struct intel_connector *intel_connector = to_intel_connector(connector);
+
+ if (intel_connector->encoder->hpd_pin == i) {
+ if (connector->polled != intel_connector->polled)
+ DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n",
+ drm_get_connector_name(connector));
+ connector->polled = intel_connector->polled;
+ if (!connector->polled)
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ }
+ }
+ }
+ if (dev_priv->display.hpd_irq_setup)
+ dev_priv->display.hpd_irq_setup(dev);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
void intel_irq_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2834,6 +3086,8 @@ void intel_irq_init(struct drm_device *dev)
setup_timer(&dev_priv->gpu_error.hangcheck_timer,
i915_hangcheck_elapsed,
(unsigned long) dev);
+ setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func,
+ (unsigned long) dev_priv);
pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
@@ -2857,7 +3111,7 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->irq_uninstall = valleyview_irq_uninstall;
dev->driver->enable_vblank = valleyview_enable_vblank;
dev->driver->disable_vblank = valleyview_disable_vblank;
- dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup;
+ dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
/* Share pre & uninstall handlers with ILK/SNB */
dev->driver->irq_handler = ivybridge_irq_handler;
@@ -2866,6 +3120,7 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->irq_uninstall = ironlake_irq_uninstall;
dev->driver->enable_vblank = ivybridge_enable_vblank;
dev->driver->disable_vblank = ivybridge_disable_vblank;
+ dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
} else if (HAS_PCH_SPLIT(dev)) {
dev->driver->irq_handler = ironlake_irq_handler;
dev->driver->irq_preinstall = ironlake_irq_preinstall;
@@ -2873,6 +3128,7 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->irq_uninstall = ironlake_irq_uninstall;
dev->driver->enable_vblank = ironlake_enable_vblank;
dev->driver->disable_vblank = ironlake_disable_vblank;
+ dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
} else {
if (INTEL_INFO(dev)->gen == 2) {
dev->driver->irq_preinstall = i8xx_irq_preinstall;
@@ -2890,7 +3146,7 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->irq_postinstall = i965_irq_postinstall;
dev->driver->irq_uninstall = i965_irq_uninstall;
dev->driver->irq_handler = i965_irq_handler;
- dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup;
+ dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
}
dev->driver->enable_vblank = i915_enable_vblank;
dev->driver->disable_vblank = i915_disable_vblank;
@@ -2900,7 +3156,20 @@ void intel_irq_init(struct drm_device *dev)
void intel_hpd_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector *connector;
+ int i;
+ for (i = 1; i < HPD_NUM_PINS; i++) {
+ dev_priv->hpd_stats[i].hpd_cnt = 0;
+ dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED;
+ }
+ list_for_each_entry(connector, &mode_config->connector_list, head) {
+ struct intel_connector *intel_connector = to_intel_connector(connector);
+ connector->polled = intel_connector->polled;
+ if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ }
if (dev_priv->display.hpd_irq_setup)
dev_priv->display.hpd_irq_setup(dev);
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 848992f67d5..83f9c26e1ad 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -91,6 +91,7 @@
#define GRDOM_FULL (0<<2)
#define GRDOM_RENDER (1<<2)
#define GRDOM_MEDIA (3<<2)
+#define GRDOM_MASK (3<<2)
#define GRDOM_RESET_ENABLE (1<<0)
#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */
@@ -121,10 +122,17 @@
#define GAM_ECOCHK 0x4090
#define ECOCHK_SNB_BIT (1<<10)
+#define HSW_ECOCHK_ARB_PRIO_SOL (1<<6)
#define ECOCHK_PPGTT_CACHE64B (0x3<<3)
#define ECOCHK_PPGTT_CACHE4B (0x0<<3)
+#define ECOCHK_PPGTT_GFDT_IVB (0x1<<4)
+#define ECOCHK_PPGTT_LLC_IVB (0x1<<3)
+#define ECOCHK_PPGTT_UC_HSW (0x1<<3)
+#define ECOCHK_PPGTT_WT_HSW (0x2<<3)
+#define ECOCHK_PPGTT_WB_HSW (0x3<<3)
#define GAC_ECO_BITS 0x14090
+#define ECOBITS_SNB_BIT (1<<13)
#define ECOBITS_PPGTT_CACHE64B (3<<8)
#define ECOBITS_PPGTT_CACHE4B (0<<8)
@@ -422,6 +430,7 @@
#define FENCE_REG_SANDYBRIDGE_0 0x100000
#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32
+#define GEN7_FENCE_MAX_PITCH_VAL 0x0800
/* control register for cpu gtt access */
#define TILECTL 0x101000
@@ -522,6 +531,9 @@
#define GEN7_ERR_INT 0x44040
#define ERR_INT_MMIO_UNCLAIMED (1<<13)
+#define FPGA_DBG 0x42300
+#define FPGA_DBG_RM_NOCLAIM (1<<31)
+
#define DERRMR 0x44050
/* GM45+ chicken bits -- debug workaround bits that may be required
@@ -591,6 +603,7 @@
#define I915_USER_INTERRUPT (1<<1)
#define I915_ASLE_INTERRUPT (1<<0)
#define I915_BSD_USER_INTERRUPT (1<<25)
+#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */
#define EIR 0x020b0
#define EMR 0x020b4
#define ESR 0x020b8
@@ -1197,6 +1210,9 @@
#define MCHBAR_MIRROR_BASE_SNB 0x140000
+/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */
+#define DCLK 0x5e04
+
/** 915-945 and GM965 MCH register controlling DRAM channel access */
#define DCC 0x10200
#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0)
@@ -1637,6 +1653,12 @@
#define SDVOC_HOTPLUG_INT_EN (1 << 25)
#define TV_HOTPLUG_INT_EN (1 << 18)
#define CRT_HOTPLUG_INT_EN (1 << 9)
+#define HOTPLUG_INT_EN_MASK (PORTB_HOTPLUG_INT_EN | \
+ PORTC_HOTPLUG_INT_EN | \
+ PORTD_HOTPLUG_INT_EN | \
+ SDVOC_HOTPLUG_INT_EN | \
+ SDVOB_HOTPLUG_INT_EN | \
+ CRT_HOTPLUG_INT_EN)
#define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
#define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8)
/* must use period 64 on GM45 according to docs */
@@ -1675,43 +1697,84 @@
#define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2)
#define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7)
#define SDVOB_HOTPLUG_INT_STATUS_I915 (1 << 6)
-
-/* SDVO port control */
-#define SDVOB 0x61140
-#define SDVOC 0x61160
-#define SDVO_ENABLE (1 << 31)
-#define SDVO_PIPE_B_SELECT (1 << 30)
-#define SDVO_STALL_SELECT (1 << 29)
-#define SDVO_INTERRUPT_ENABLE (1 << 26)
+#define HOTPLUG_INT_STATUS_G4X (CRT_HOTPLUG_INT_STATUS | \
+ SDVOB_HOTPLUG_INT_STATUS_G4X | \
+ SDVOC_HOTPLUG_INT_STATUS_G4X | \
+ PORTB_HOTPLUG_INT_STATUS | \
+ PORTC_HOTPLUG_INT_STATUS | \
+ PORTD_HOTPLUG_INT_STATUS)
+
+#define HOTPLUG_INT_STATUS_I965 (CRT_HOTPLUG_INT_STATUS | \
+ SDVOB_HOTPLUG_INT_STATUS_I965 | \
+ SDVOC_HOTPLUG_INT_STATUS_I965 | \
+ PORTB_HOTPLUG_INT_STATUS | \
+ PORTC_HOTPLUG_INT_STATUS | \
+ PORTD_HOTPLUG_INT_STATUS)
+
+#define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \
+ SDVOB_HOTPLUG_INT_STATUS_I915 | \
+ SDVOC_HOTPLUG_INT_STATUS_I915 | \
+ PORTB_HOTPLUG_INT_STATUS | \
+ PORTC_HOTPLUG_INT_STATUS | \
+ PORTD_HOTPLUG_INT_STATUS)
+
+/* SDVO and HDMI port control.
+ * The same register may be used for SDVO or HDMI */
+#define GEN3_SDVOB 0x61140
+#define GEN3_SDVOC 0x61160
+#define GEN4_HDMIB GEN3_SDVOB
+#define GEN4_HDMIC GEN3_SDVOC
+#define PCH_SDVOB 0xe1140
+#define PCH_HDMIB PCH_SDVOB
+#define PCH_HDMIC 0xe1150
+#define PCH_HDMID 0xe1160
+
+/* Gen 3 SDVO bits: */
+#define SDVO_ENABLE (1 << 31)
+#define SDVO_PIPE_SEL(pipe) ((pipe) << 30)
+#define SDVO_PIPE_SEL_MASK (1 << 30)
+#define SDVO_PIPE_B_SELECT (1 << 30)
+#define SDVO_STALL_SELECT (1 << 29)
+#define SDVO_INTERRUPT_ENABLE (1 << 26)
/**
* 915G/GM SDVO pixel multiplier.
- *
* Programmed value is multiplier - 1, up to 5x.
- *
* \sa DPLL_MD_UDI_MULTIPLIER_MASK
*/
-#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
+#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
#define SDVO_PORT_MULTIPLY_SHIFT 23
-#define SDVO_PHASE_SELECT_MASK (15 << 19)
-#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
-#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
-#define SDVOC_GANG_MODE (1 << 16)
-#define SDVO_ENCODING_SDVO (0x0 << 10)
-#define SDVO_ENCODING_HDMI (0x2 << 10)
-/** Requird for HDMI operation */
-#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9)
-#define SDVO_COLOR_RANGE_16_235 (1 << 8)
-#define SDVO_BORDER_ENABLE (1 << 7)
-#define SDVO_AUDIO_ENABLE (1 << 6)
-/** New with 965, default is to be set */
-#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4)
-/** New with 965, default is to be set */
-#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3)
-#define SDVOB_PCIE_CONCURRENCY (1 << 3)
-#define SDVO_DETECTED (1 << 2)
+#define SDVO_PHASE_SELECT_MASK (15 << 19)
+#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
+#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
+#define SDVOC_GANG_MODE (1 << 16) /* Port C only */
+#define SDVO_BORDER_ENABLE (1 << 7) /* SDVO only */
+#define SDVOB_PCIE_CONCURRENCY (1 << 3) /* Port B only */
+#define SDVO_DETECTED (1 << 2)
/* Bits to be preserved when writing */
-#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26))
-#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26))
+#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | \
+ SDVO_INTERRUPT_ENABLE)
+#define SDVOC_PRESERVE_MASK ((1 << 17) | SDVO_INTERRUPT_ENABLE)
+
+/* Gen 4 SDVO/HDMI bits: */
+#define SDVO_COLOR_FORMAT_8bpc (0 << 26)
+#define SDVO_ENCODING_SDVO (0 << 10)
+#define SDVO_ENCODING_HDMI (2 << 10)
+#define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */
+#define HDMI_MODE_SELECT_DVI (0 << 9) /* HDMI only */
+#define HDMI_COLOR_RANGE_16_235 (1 << 8) /* HDMI only */
+#define SDVO_AUDIO_ENABLE (1 << 6)
+/* VSYNC/HSYNC bits new with 965, default is to be set */
+#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4)
+#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3)
+
+/* Gen 5 (IBX) SDVO/HDMI bits: */
+#define HDMI_COLOR_FORMAT_12bpc (3 << 26) /* HDMI only */
+#define SDVOB_HOTPLUG_ENABLE (1 << 23) /* SDVO only */
+
+/* Gen 6 (CPT) SDVO/HDMI bits: */
+#define SDVO_PIPE_SEL_CPT(pipe) ((pipe) << 29)
+#define SDVO_PIPE_SEL_MASK_CPT (3 << 29)
+
/* DVO port control */
#define DVOA 0x61120
@@ -1898,7 +1961,7 @@
#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238)
/* Backlight control */
-#define BLC_PWM_CTL2 0x61250 /* 965+ only */
+#define BLC_PWM_CTL2 (dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */
#define BLM_PWM_ENABLE (1 << 31)
#define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */
#define BLM_PIPE_SELECT (1 << 29)
@@ -1917,7 +1980,7 @@
#define BLM_PHASE_IN_COUNT_MASK (0xff << 8)
#define BLM_PHASE_IN_INCR_SHIFT (0)
#define BLM_PHASE_IN_INCR_MASK (0xff << 0)
-#define BLC_PWM_CTL 0x61254
+#define BLC_PWM_CTL (dev_priv->info->display_mmio_offset + 0x61254)
/*
* This is the most significant 15 bits of the number of backlight cycles in a
* complete cycle of the modulated backlight control.
@@ -1939,7 +2002,7 @@
#define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe)
#define BLM_POLARITY_PNV (1 << 0) /* pnv only */
-#define BLC_HIST_CTL 0x61260
+#define BLC_HIST_CTL (dev_priv->info->display_mmio_offset + 0x61260)
/* New registers for PCH-split platforms. Safe where new bits show up, the
* register layout machtes with gen4 BLC_PWM_CTL[12]. */
@@ -2589,14 +2652,14 @@
#define _PIPEB_GMCH_DATA_M 0x71050
/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
-#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25)
-#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25
+#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
+#define TU_SIZE_MASK (0x3f << 25)
-#define PIPE_GMCH_DATA_M_MASK (0xffffff)
+#define DATA_LINK_M_N_MASK (0xffffff)
+#define DATA_LINK_N_MAX (0x800000)
#define _PIPEA_GMCH_DATA_N 0x70054
#define _PIPEB_GMCH_DATA_N 0x71054
-#define PIPE_GMCH_DATA_N_MASK (0xffffff)
/*
* Computing Link M and N values for the Display Port link
@@ -2611,11 +2674,9 @@
#define _PIPEA_DP_LINK_M 0x70060
#define _PIPEB_DP_LINK_M 0x71060
-#define PIPEA_DP_LINK_M_MASK (0xffffff)
#define _PIPEA_DP_LINK_N 0x70064
#define _PIPEB_DP_LINK_N 0x71064
-#define PIPEA_DP_LINK_N_MASK (0xffffff)
#define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M)
#define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N)
@@ -2776,6 +2837,8 @@
#define DSPFW_HPLL_CURSOR_SHIFT 16
#define DSPFW_HPLL_CURSOR_MASK (0x3f<<16)
#define DSPFW_HPLL_SR_MASK (0x1ff)
+#define DSPFW4 (dev_priv->info->display_mmio_offset + 0x70070)
+#define DSPFW7 (dev_priv->info->display_mmio_offset + 0x7007c)
/* drain latency register values*/
#define DRAIN_LATENCY_PRECISION_32 32
@@ -3233,6 +3296,63 @@
#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
+#define _SPACNTR 0x72180
+#define SP_ENABLE (1<<31)
+#define SP_GEAMMA_ENABLE (1<<30)
+#define SP_PIXFORMAT_MASK (0xf<<26)
+#define SP_FORMAT_YUV422 (0<<26)
+#define SP_FORMAT_BGR565 (5<<26)
+#define SP_FORMAT_BGRX8888 (6<<26)
+#define SP_FORMAT_BGRA8888 (7<<26)
+#define SP_FORMAT_RGBX1010102 (8<<26)
+#define SP_FORMAT_RGBA1010102 (9<<26)
+#define SP_FORMAT_RGBX8888 (0xe<<26)
+#define SP_FORMAT_RGBA8888 (0xf<<26)
+#define SP_SOURCE_KEY (1<<22)
+#define SP_YUV_BYTE_ORDER_MASK (3<<16)
+#define SP_YUV_ORDER_YUYV (0<<16)
+#define SP_YUV_ORDER_UYVY (1<<16)
+#define SP_YUV_ORDER_YVYU (2<<16)
+#define SP_YUV_ORDER_VYUY (3<<16)
+#define SP_TILED (1<<10)
+#define _SPALINOFF 0x72184
+#define _SPASTRIDE 0x72188
+#define _SPAPOS 0x7218c
+#define _SPASIZE 0x72190
+#define _SPAKEYMINVAL 0x72194
+#define _SPAKEYMSK 0x72198
+#define _SPASURF 0x7219c
+#define _SPAKEYMAXVAL 0x721a0
+#define _SPATILEOFF 0x721a4
+#define _SPACONSTALPHA 0x721a8
+#define _SPAGAMC 0x721f4
+
+#define _SPBCNTR 0x72280
+#define _SPBLINOFF 0x72284
+#define _SPBSTRIDE 0x72288
+#define _SPBPOS 0x7228c
+#define _SPBSIZE 0x72290
+#define _SPBKEYMINVAL 0x72294
+#define _SPBKEYMSK 0x72298
+#define _SPBSURF 0x7229c
+#define _SPBKEYMAXVAL 0x722a0
+#define _SPBTILEOFF 0x722a4
+#define _SPBCONSTALPHA 0x722a8
+#define _SPBGAMC 0x722f4
+
+#define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR)
+#define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF)
+#define SPSTRIDE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASTRIDE, _SPBSTRIDE)
+#define SPPOS(pipe, plane) _PIPE(pipe * 2 + plane, _SPAPOS, _SPBPOS)
+#define SPSIZE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASIZE, _SPBSIZE)
+#define SPKEYMINVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMINVAL, _SPBKEYMINVAL)
+#define SPKEYMSK(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMSK, _SPBKEYMSK)
+#define SPSURF(pipe, plane) _PIPE(pipe * 2 + plane, _SPASURF, _SPBSURF)
+#define SPKEYMAXVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMAXVAL, _SPBKEYMAXVAL)
+#define SPTILEOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPATILEOFF, _SPBTILEOFF)
+#define SPCONSTALPHA(pipe, plane) _PIPE(pipe * 2 + plane, _SPACONSTALPHA, _SPBCONSTALPHA)
+#define SPGAMC(pipe, plane) _PIPE(pipe * 2 + plane, _SPAGAMC, _SPBGAMC)
+
/* VBIOS regs */
#define VGACNTRL 0x71400
# define VGA_DISP_DISABLE (1 << 31)
@@ -3282,8 +3402,6 @@
#define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030)
-#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
-#define TU_SIZE_MASK 0x7e000000
#define PIPE_DATA_M1_OFFSET 0
#define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034)
#define PIPE_DATA_N1_OFFSET 0
@@ -3456,6 +3574,9 @@
#define DISP_ARB_CTL 0x45000
#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
#define DISP_FBC_WM_DIS (1<<15)
+#define GEN7_MSG_CTL 0x45010
+#define WAIT_FOR_PCH_RESET_ACK (1<<1)
+#define WAIT_FOR_PCH_FLR_ACK (1<<0)
/* GEN7 chicken */
#define GEN7_COMMON_SLICE_CHICKEN1 0x7010
@@ -3508,7 +3629,11 @@
#define SDE_PORTC_HOTPLUG (1 << 9)
#define SDE_PORTB_HOTPLUG (1 << 8)
#define SDE_SDVOB_HOTPLUG (1 << 6)
-#define SDE_HOTPLUG_MASK (0xf << 8)
+#define SDE_HOTPLUG_MASK (SDE_CRT_HOTPLUG | \
+ SDE_SDVOB_HOTPLUG | \
+ SDE_PORTB_HOTPLUG | \
+ SDE_PORTC_HOTPLUG | \
+ SDE_PORTD_HOTPLUG)
#define SDE_TRANSB_CRC_DONE (1 << 5)
#define SDE_TRANSB_CRC_ERR (1 << 4)
#define SDE_TRANSB_FIFO_UNDER (1 << 3)
@@ -3531,7 +3656,9 @@
#define SDE_PORTC_HOTPLUG_CPT (1 << 22)
#define SDE_PORTB_HOTPLUG_CPT (1 << 21)
#define SDE_CRT_HOTPLUG_CPT (1 << 19)
+#define SDE_SDVOB_HOTPLUG_CPT (1 << 18)
#define SDE_HOTPLUG_MASK_CPT (SDE_CRT_HOTPLUG_CPT | \
+ SDE_SDVOB_HOTPLUG_CPT | \
SDE_PORTD_HOTPLUG_CPT | \
SDE_PORTC_HOTPLUG_CPT | \
SDE_PORTB_HOTPLUG_CPT)
@@ -3754,14 +3881,16 @@
#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344
#define HSW_VIDEO_DIP_GCP_B 0x61210
-#define HSW_TVIDEO_DIP_CTL(pipe) \
- _PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
-#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \
- _PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
-#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \
- _PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
-#define HSW_TVIDEO_DIP_GCP(pipe) \
- _PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
+#define HSW_TVIDEO_DIP_CTL(trans) \
+ _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
+#define HSW_TVIDEO_DIP_AVI_DATA(trans) \
+ _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
+#define HSW_TVIDEO_DIP_SPD_DATA(trans) \
+ _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
+#define HSW_TVIDEO_DIP_GCP(trans) \
+ _TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
+#define HSW_TVIDEO_DIP_VSC_DATA(trans) \
+ _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B)
#define _TRANS_HTOTAL_B 0xe1000
#define _TRANS_HBLANK_B 0xe1004
@@ -3826,8 +3955,11 @@
#define _TRANSA_CHICKEN2 0xf0064
#define _TRANSB_CHICKEN2 0xf1064
#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
-#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31)
-
+#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31)
+#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29)
+#define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3<<27)
+#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1<<26)
+#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1<<25)
#define SOUTH_CHICKEN1 0xc2000
#define FDIA_PHASE_SYNC_SHIFT_OVR 19
@@ -3976,34 +4108,6 @@
#define FDI_PLL_CTL_1 0xfe000
#define FDI_PLL_CTL_2 0xfe004
-/* or SDVOB */
-#define HDMIB 0xe1140
-#define PORT_ENABLE (1 << 31)
-#define TRANSCODER(pipe) ((pipe) << 30)
-#define TRANSCODER_CPT(pipe) ((pipe) << 29)
-#define TRANSCODER_MASK (1 << 30)
-#define TRANSCODER_MASK_CPT (3 << 29)
-#define COLOR_FORMAT_8bpc (0)
-#define COLOR_FORMAT_12bpc (3 << 26)
-#define SDVOB_HOTPLUG_ENABLE (1 << 23)
-#define SDVO_ENCODING (0)
-#define TMDS_ENCODING (2 << 10)
-#define NULL_PACKET_VSYNC_ENABLE (1 << 9)
-/* CPT */
-#define HDMI_MODE_SELECT (1 << 9)
-#define DVI_MODE_SELECT (0)
-#define SDVOB_BORDER_ENABLE (1 << 7)
-#define AUDIO_ENABLE (1 << 6)
-#define VSYNC_ACTIVE_HIGH (1 << 4)
-#define HSYNC_ACTIVE_HIGH (1 << 3)
-#define PORT_DETECTED (1 << 2)
-
-/* PCH SDVOB multiplex with HDMIB */
-#define PCH_SDVOB HDMIB
-
-#define HDMIC 0xe1150
-#define HDMID 0xe1160
-
#define PCH_LVDS 0xe1180
#define LVDS_DETECTED (1 << 1)
@@ -4020,6 +4124,15 @@
#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c)
#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310)
+#define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS)
+#define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL)
+#define VLV_PIPE_PP_ON_DELAYS(pipe) \
+ _PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS)
+#define VLV_PIPE_PP_OFF_DELAYS(pipe) \
+ _PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS)
+#define VLV_PIPE_PP_DIVISOR(pipe) \
+ _PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR)
+
#define PCH_PP_STATUS 0xc7200
#define PCH_PP_CONTROL 0xc7204
#define PANEL_UNLOCK_REGS (0xabcd << 16)
@@ -4149,8 +4262,12 @@
#define FORCEWAKE 0xA18C
#define FORCEWAKE_VLV 0x1300b0
#define FORCEWAKE_ACK_VLV 0x1300b4
+#define FORCEWAKE_MEDIA_VLV 0x1300b8
+#define FORCEWAKE_ACK_MEDIA_VLV 0x1300bc
#define FORCEWAKE_ACK_HSW 0x130044
#define FORCEWAKE_ACK 0x130090
+#define VLV_GTLC_WAKE_CTRL 0x130090
+#define VLV_GTLC_PW_STATUS 0x130094
#define FORCEWAKE_MT 0xa188 /* multi-threaded */
#define FORCEWAKE_KERNEL 0x1
#define FORCEWAKE_USER 0x2
@@ -4184,6 +4301,7 @@
#define GEN6_RPNSWREQ 0xA008
#define GEN6_TURBO_DISABLE (1<<31)
#define GEN6_FREQUENCY(x) ((x)<<25)
+#define HSW_FREQUENCY(x) ((x)<<24)
#define GEN6_OFFSET(x) ((x)<<19)
#define GEN6_AGGRESSIVE_TURBO (0<<15)
#define GEN6_RC_VIDEO_FREQ 0xA00C
@@ -4274,6 +4392,21 @@
#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245)
#define GEN6_PCODE_DATA 0x138128
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
+#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16
+
+#define VLV_IOSF_DOORBELL_REQ 0x182100
+#define IOSF_DEVFN_SHIFT 24
+#define IOSF_OPCODE_SHIFT 16
+#define IOSF_PORT_SHIFT 8
+#define IOSF_BYTE_ENABLES_SHIFT 4
+#define IOSF_BAR_SHIFT 1
+#define IOSF_SB_BUSY (1<<0)
+#define IOSF_PORT_PUNIT 0x4
+#define VLV_IOSF_DATA 0x182104
+#define VLV_IOSF_ADDR 0x182108
+
+#define PUNIT_OPCODE_REG_READ 6
+#define PUNIT_OPCODE_REG_WRITE 7
#define GEN6_GT_CORE_STATUS 0x138060
#define GEN6_CORE_CPD_STATE_MASK (7<<4)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 2135f21ea45..41f0fdecfbd 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -209,7 +209,8 @@ static void i915_save_display(struct drm_device *dev)
dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL);
dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2);
- dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
+ if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+ dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
} else {
dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
@@ -255,6 +256,7 @@ static void i915_save_display(struct drm_device *dev)
static void i915_restore_display(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 mask = 0xffffffff;
/* Display arbitration */
if (INTEL_INFO(dev)->gen <= 4)
@@ -267,10 +269,13 @@ static void i915_restore_display(struct drm_device *dev)
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
- if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS);
- } else if (IS_MOBILE(dev) && !IS_I830(dev))
- I915_WRITE(LVDS, dev_priv->regfile.saveLVDS);
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ mask = ~LVDS_PORT_EN;
+
+ if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+ I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS & mask);
+ else if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev))
+ I915_WRITE(LVDS, dev_priv->regfile.saveLVDS & mask);
if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL);
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 9462081b1e6..d5e1890678f 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -49,7 +49,7 @@ static ssize_t
show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf)
{
struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
- return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev));
+ return snprintf(buf, PAGE_SIZE, "%x\n", intel_enable_rc6(dminor->dev));
}
static ssize_t
@@ -57,7 +57,7 @@ show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf)
{
struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6);
- return snprintf(buf, PAGE_SIZE, "%u", rc6_residency);
+ return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency);
}
static ssize_t
@@ -65,7 +65,7 @@ show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf)
{
struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
- return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency);
+ return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency);
}
static ssize_t
@@ -73,7 +73,7 @@ show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf)
{
struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev);
u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
- return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency);
+ return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency);
}
static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL);
@@ -215,7 +215,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
- return snprintf(buf, PAGE_SIZE, "%d", ret);
+ return snprintf(buf, PAGE_SIZE, "%d\n", ret);
}
static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
@@ -229,7 +229,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
- return snprintf(buf, PAGE_SIZE, "%d", ret);
+ return snprintf(buf, PAGE_SIZE, "%d\n", ret);
}
static ssize_t gt_max_freq_mhz_store(struct device *kdev,
@@ -239,7 +239,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
struct drm_device *dev = minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 val, rp_state_cap, hw_max, hw_min;
+ u32 val, rp_state_cap, hw_max, hw_min, non_oc_max;
ssize_t ret;
ret = kstrtou32(buf, 0, &val);
@@ -251,7 +251,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
mutex_lock(&dev_priv->rps.hw_lock);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- hw_max = (rp_state_cap & 0xff);
+ hw_max = dev_priv->rps.hw_max;
+ non_oc_max = (rp_state_cap & 0xff);
hw_min = ((rp_state_cap & 0xff0000) >> 16);
if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) {
@@ -259,6 +260,10 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
return -EINVAL;
}
+ if (val > non_oc_max)
+ DRM_DEBUG("User requested overclocking to %d\n",
+ val * GT_FREQUENCY_MULTIPLIER);
+
if (dev_priv->rps.cur_delay > val)
gen6_set_rps(dev_priv->dev, val);
@@ -280,7 +285,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute
ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
- return snprintf(buf, PAGE_SIZE, "%d", ret);
+ return snprintf(buf, PAGE_SIZE, "%d\n", ret);
}
static ssize_t gt_min_freq_mhz_store(struct device *kdev,
@@ -302,7 +307,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
mutex_lock(&dev_priv->rps.hw_lock);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- hw_max = (rp_state_cap & 0xff);
+ hw_max = dev_priv->rps.hw_max;
hw_min = ((rp_state_cap & 0xff0000) >> 16);
if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
@@ -355,7 +360,7 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr
} else {
BUG();
}
- return snprintf(buf, PAGE_SIZE, "%d", val);
+ return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static const struct attribute *gen6_attrs[] = {
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 55ffba1f581..95070b2124c 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -351,12 +351,14 @@ parse_general_features(struct drm_i915_private *dev_priv,
dev_priv->lvds_ssc_freq =
intel_bios_ssc_frequency(dev, general->ssc_freq);
dev_priv->display_clock_mode = general->display_clock_mode;
- DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n",
+ dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
+ DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n",
dev_priv->int_tv_support,
dev_priv->int_crt_support,
dev_priv->lvds_use_ssc,
dev_priv->lvds_ssc_freq,
- dev_priv->display_clock_mode);
+ dev_priv->display_clock_mode,
+ dev_priv->fdi_rx_polarity_inverted);
}
}
@@ -692,6 +694,9 @@ intel_parse_bios(struct drm_device *dev)
struct bdb_header *bdb = NULL;
u8 __iomem *bios = NULL;
+ if (HAS_PCH_NOP(dev))
+ return -ENODEV;
+
init_vbt_defaults(dev_priv);
/* XXX Should this validation be moved to intel_opregion.c? */
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 36e57f93437..e088d6f0956 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -127,7 +127,9 @@ struct bdb_general_features {
/* bits 3 */
u8 disable_smooth_vision:1;
u8 single_dvi:1;
- u8 rsvd9:6; /* finish byte */
+ u8 rsvd9:1;
+ u8 fdi_rx_polarity_inverted:1;
+ u8 rsvd10:4; /* finish byte */
/* bits 4 */
u8 legacy_monitor_detect;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 1ce45a0a2d3..58b4a53715c 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -199,10 +199,14 @@ static int intel_crt_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
-static bool intel_crt_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static bool intel_crt_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
{
+ struct drm_device *dev = encoder->base.dev;
+
+ if (HAS_PCH_SPLIT(dev))
+ pipe_config->has_pch_encoder = true;
+
return true;
}
@@ -676,7 +680,6 @@ static void intel_crt_reset(struct drm_connector *connector)
*/
static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
- .mode_fixup = intel_crt_mode_fixup,
.mode_set = intel_crt_mode_set,
};
@@ -768,8 +771,11 @@ void intel_crt_init(struct drm_device *dev)
else
crt->adpa_reg = ADPA;
+ crt->base.compute_config = intel_crt_compute_config;
crt->base.disable = intel_disable_crt;
crt->base.enable = intel_enable_crt;
+ if (I915_HAS_HOTPLUG(dev))
+ crt->base.hpd_pin = HPD_CRT;
if (HAS_DDI(dev))
crt->base.get_hw_state = intel_ddi_get_hw_state;
else
@@ -781,18 +787,14 @@ void intel_crt_init(struct drm_device *dev)
drm_sysfs_connector_add(connector);
- if (I915_HAS_HOTPLUG(dev))
- connector->polled = DRM_CONNECTOR_POLL_HPD;
- else
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ if (!I915_HAS_HOTPLUG(dev))
+ intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
/*
* Configure the automatic hotplug detection stuff
*/
crt->force_hotplug_required = 0;
- dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
-
/*
* TODO: find a proper way to discover whether we need to set the the
* polarity and link reversal bits or not, instead of relying on the
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 8d0bac3c35d..26a0a570f92 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -898,6 +898,9 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock)
plls->spll_refcount++;
reg = SPLL_CTL;
intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL;
+ } else {
+ DRM_ERROR("SPLL already in use\n");
+ return false;
}
WARN(I915_READ(reg) & SPLL_PLL_ENABLE,
@@ -921,14 +924,14 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
int type = intel_encoder->type;
uint32_t temp;
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
temp = TRANS_MSA_SYNC_CLK;
- switch (intel_crtc->bpp) {
+ switch (intel_crtc->config.pipe_bpp) {
case 18:
temp |= TRANS_MSA_6_BPC;
break;
@@ -942,22 +945,20 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
temp |= TRANS_MSA_12_BPC;
break;
default:
- temp |= TRANS_MSA_8_BPC;
- WARN(1, "%d bpp unsupported by DDI function\n",
- intel_crtc->bpp);
+ BUG();
}
I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp);
}
}
-void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
+void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
struct drm_encoder *encoder = &intel_encoder->base;
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
enum pipe pipe = intel_crtc->pipe;
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
enum port port = intel_ddi_get_encoder_port(intel_encoder);
int type = intel_encoder->type;
uint32_t temp;
@@ -966,7 +967,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
temp = TRANS_DDI_FUNC_ENABLE;
temp |= TRANS_DDI_SELECT_PORT(port);
- switch (intel_crtc->bpp) {
+ switch (intel_crtc->config.pipe_bpp) {
case 18:
temp |= TRANS_DDI_BPC_6;
break;
@@ -980,8 +981,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
temp |= TRANS_DDI_BPC_12;
break;
default:
- WARN(1, "%d bpp unsupported by transcoder DDI function\n",
- intel_crtc->bpp);
+ BUG();
}
if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
@@ -1150,14 +1150,14 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port);
- return true;
+ return false;
}
static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
uint32_t temp, ret;
- enum port port;
+ enum port port = I915_MAX_PORTS;
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
pipe);
int i;
@@ -1173,10 +1173,16 @@ static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv,
port = i;
}
- ret = I915_READ(PORT_CLK_SEL(port));
-
- DRM_DEBUG_KMS("Pipe %c connected to port %c using clock 0x%08x\n",
- pipe_name(pipe), port_name(port), ret);
+ if (port == I915_MAX_PORTS) {
+ WARN(1, "Pipe %c enabled on an unknown port\n",
+ pipe_name(pipe));
+ ret = PORT_CLK_SEL_NONE;
+ } else {
+ ret = I915_READ(PORT_CLK_SEL(port));
+ DRM_DEBUG_KMS("Pipe %c connected to port %c using clock "
+ "0x%08x\n", pipe_name(pipe), port_name(port),
+ ret);
+ }
return ret;
}
@@ -1217,7 +1223,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
enum port port = intel_ddi_get_encoder_port(intel_encoder);
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
if (cpu_transcoder != TRANSCODER_EDP)
I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
@@ -1227,7 +1233,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
{
struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
if (cpu_transcoder != TRANSCODER_EDP)
I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
@@ -1341,15 +1347,15 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp;
+ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
+ tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4));
+ I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
+
if (type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
ironlake_edp_backlight_off(intel_dp);
}
-
- tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
- tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4));
- I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
}
int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
@@ -1467,19 +1473,17 @@ static void intel_ddi_destroy(struct drm_encoder *encoder)
intel_dp_encoder_destroy(encoder);
}
-static bool intel_ddi_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static bool intel_ddi_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
{
- struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
- int type = intel_encoder->type;
+ int type = encoder->type;
- WARN(type == INTEL_OUTPUT_UNKNOWN, "mode_fixup() on unknown output!\n");
+ WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n");
if (type == INTEL_OUTPUT_HDMI)
- return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode);
+ return intel_hdmi_compute_config(encoder, pipe_config);
else
- return intel_dp_mode_fixup(encoder, mode, adjusted_mode);
+ return intel_dp_compute_config(encoder, pipe_config);
}
static const struct drm_encoder_funcs intel_ddi_funcs = {
@@ -1487,7 +1491,6 @@ static const struct drm_encoder_funcs intel_ddi_funcs = {
};
static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = {
- .mode_fixup = intel_ddi_mode_fixup,
.mode_set = intel_ddi_mode_set,
};
@@ -1527,6 +1530,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs);
+ intel_encoder->compute_config = intel_ddi_compute_config;
intel_encoder->enable = intel_enable_ddi;
intel_encoder->pre_enable = intel_ddi_pre_enable;
intel_encoder->disable = intel_disable_ddi;
@@ -1537,9 +1541,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
DDI_BUF_PORT_REVERSAL;
if (hdmi_connector)
- intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port);
- else
- intel_dig_port->hdmi.sdvox_reg = 0;
+ intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b20d50192fc..efe82991975 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -71,8 +71,24 @@ typedef struct intel_limit intel_limit_t;
struct intel_limit {
intel_range_t dot, vco, n, m, m1, m2, p, p1;
intel_p2_t p2;
- bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
- int, int, intel_clock_t *, intel_clock_t *);
+ /**
+ * find_pll() - Find the best values for the PLL
+ * @limit: limits for the PLL
+ * @crtc: current CRTC
+ * @target: target frequency in kHz
+ * @refclk: reference clock frequency in kHz
+ * @match_clock: if provided, @best_clock P divider must
+ * match the P divider from @match_clock
+ * used for LVDS downclocking
+ * @best_clock: best PLL values found
+ *
+ * Returns true on success, false on failure.
+ */
+ bool (*find_pll)(const intel_limit_t *limit,
+ struct drm_crtc *crtc,
+ int target, int refclk,
+ intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
};
/* FDI */
@@ -471,7 +487,6 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
if (intel_is_dual_link_lvds(dev)) {
- /* LVDS dual channel */
if (refclk == 100000)
limit = &intel_limits_ironlake_dual_lvds_100m;
else
@@ -498,10 +513,8 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
if (intel_is_dual_link_lvds(dev))
- /* LVDS with dual channel */
limit = &intel_limits_g4x_dual_channel_lvds;
else
- /* LVDS with dual channel */
limit = &intel_limits_g4x_single_channel_lvds;
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
@@ -879,7 +892,7 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- return intel_crtc->cpu_transcoder;
+ return intel_crtc->config.cpu_transcoder;
}
static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe)
@@ -1214,8 +1227,8 @@ void assert_pipe(struct drm_i915_private *dev_priv,
if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
state = true;
- if (IS_HASWELL(dev_priv->dev) && cpu_transcoder != TRANSCODER_EDP &&
- !(I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE)) {
+ if (!intel_using_power_well(dev_priv->dev) &&
+ cpu_transcoder != TRANSCODER_EDP) {
cur_state = false;
} else {
reg = PIPECONF(cpu_transcoder);
@@ -1254,7 +1267,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
int cur_pipe;
/* Planes are fixed to pipes on ILK+ */
- if (HAS_PCH_SPLIT(dev_priv->dev)) {
+ if (HAS_PCH_SPLIT(dev_priv->dev) || IS_VALLEYVIEW(dev_priv->dev)) {
reg = DSPCNTR(pipe);
val = I915_READ(reg);
WARN((val & DISPLAY_PLANE_ENABLE),
@@ -1275,6 +1288,25 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
}
}
+static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
+ enum pipe pipe)
+{
+ int reg, i;
+ u32 val;
+
+ if (!IS_VALLEYVIEW(dev_priv->dev))
+ return;
+
+ /* Need to check both planes against the pipe */
+ for (i = 0; i < dev_priv->num_plane; i++) {
+ reg = SPCNTR(pipe, i);
+ val = I915_READ(reg);
+ WARN((val & SP_ENABLE),
+ "sprite %d assertion failure, should be off on pipe %c but is still active\n",
+ pipe * 2 + i, pipe_name(pipe));
+ }
+}
+
static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
{
u32 val;
@@ -1327,14 +1359,14 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv,
enum pipe pipe, u32 val)
{
- if ((val & PORT_ENABLE) == 0)
+ if ((val & SDVO_ENABLE) == 0)
return false;
if (HAS_PCH_CPT(dev_priv->dev)) {
- if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+ if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe))
return false;
} else {
- if ((val & TRANSCODER_MASK) != TRANSCODER(pipe))
+ if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe))
return false;
}
return true;
@@ -1392,7 +1424,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
"PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
reg, pipe_name(pipe));
- WARN(HAS_PCH_IBX(dev_priv->dev) && (val & PORT_ENABLE) == 0
+ WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
&& (val & SDVO_PIPE_B_SELECT),
"IBX PCH hdmi port still using transcoder B\n");
}
@@ -1419,9 +1451,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
"PCH LVDS enabled on transcoder %c, should be disabled\n",
pipe_name(pipe));
- assert_pch_hdmi_disabled(dev_priv, pipe, HDMIB);
- assert_pch_hdmi_disabled(dev_priv, pipe, HDMIC);
- assert_pch_hdmi_disabled(dev_priv, pipe, HDMID);
+ assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB);
+ assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC);
+ assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID);
}
/**
@@ -1859,6 +1891,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
* or we might hang the display.
*/
assert_planes_disabled(dev_priv, pipe);
+ assert_sprites_disabled(dev_priv, pipe);
/* Don't disable pipe A or pipe A PLLs if needed */
if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
@@ -1937,6 +1970,15 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv,
intel_wait_for_vblank(dev_priv->dev, pipe);
}
+static bool need_vtd_wa(struct drm_device *dev)
+{
+#ifdef CONFIG_INTEL_IOMMU
+ if (INTEL_INFO(dev)->gen >= 6 && intel_iommu_gfx_mapped)
+ return true;
+#endif
+ return false;
+}
+
int
intel_pin_and_fence_fb_obj(struct drm_device *dev,
struct drm_i915_gem_object *obj,
@@ -1960,13 +2002,23 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
alignment = 0;
break;
case I915_TILING_Y:
- /* FIXME: Is this true? */
- DRM_ERROR("Y tiled not allowed for scan out buffers\n");
+ /* Despite that we check this in framebuffer_init userspace can
+ * screw us over and change the tiling after the fact. Only
+ * pinned buffers can't change their tiling. */
+ DRM_DEBUG_DRIVER("Y tiled not allowed for scan out buffers\n");
return -EINVAL;
default:
BUG();
}
+ /* Note that the w/a also requires 64 PTE of padding following the
+ * bo. We currently fill all unused PTE with the shadow page and so
+ * we should always have valid PTE following the scanout preventing
+ * the VT-d warning.
+ */
+ if (need_vtd_wa(dev) && alignment < 256 * 1024)
+ alignment = 256 * 1024;
+
dev_priv->mm.interruptible = false;
ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined);
if (ret)
@@ -2083,8 +2135,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
dspcntr |= DISPPLANE_RGBX101010;
break;
default:
- DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
- return -EINVAL;
+ BUG();
}
if (INTEL_INFO(dev)->gen >= 4) {
@@ -2177,8 +2228,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
dspcntr |= DISPPLANE_RGBX101010;
break;
default:
- DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
- return -EINVAL;
+ BUG();
}
if (obj->tiling_mode != I915_TILING_NONE)
@@ -2229,6 +2279,44 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
return dev_priv->display.update_plane(crtc, fb, x, y);
}
+void intel_display_handle_reset(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+
+ /*
+ * Flips in the rings have been nuked by the reset,
+ * so complete all pending flips so that user space
+ * will get its events and not get stuck.
+ *
+ * Also update the base address of all primary
+ * planes to the the last fb to make sure we're
+ * showing the correct fb after a reset.
+ *
+ * Need to make two loops over the crtcs so that we
+ * don't try to grab a crtc mutex before the
+ * pending_flip_queue really got woken up.
+ */
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ enum plane plane = intel_crtc->plane;
+
+ intel_prepare_page_flip(dev, plane);
+ intel_finish_page_flip_plane(dev, plane);
+ }
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ mutex_lock(&crtc->mutex);
+ if (intel_crtc->active)
+ dev_priv->display.update_plane(crtc, crtc->fb,
+ crtc->x, crtc->y);
+ mutex_unlock(&crtc->mutex);
+ }
+}
+
static int
intel_finish_fb(struct drm_framebuffer *old_fb)
{
@@ -2295,10 +2383,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
- if(intel_crtc->plane > dev_priv->num_pipe) {
+ if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) {
DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n",
intel_crtc->plane,
- dev_priv->num_pipe);
+ INTEL_INFO(dev)->num_pipes);
return -EINVAL;
}
@@ -2312,9 +2400,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return ret;
}
- if (crtc->fb)
- intel_finish_fb(crtc->fb);
-
ret = dev_priv->display.update_plane(crtc, fb, x, y);
if (ret) {
intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
@@ -2912,32 +2997,6 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
mutex_unlock(&dev->struct_mutex);
}
-static bool ironlake_crtc_driving_pch(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct intel_encoder *intel_encoder;
-
- /*
- * If there's a non-PCH eDP on this crtc, it must be DP_A, and that
- * must be driven by its own crtc; no sharing is possible.
- */
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
- switch (intel_encoder->type) {
- case INTEL_OUTPUT_EDP:
- if (!intel_encoder_is_pch_edp(&intel_encoder->base))
- return false;
- continue;
- }
- }
-
- return true;
-}
-
-static bool haswell_crtc_driving_pch(struct drm_crtc *crtc)
-{
- return intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG);
-}
-
/* Program iCLKIP clock to the desired frequency */
static void lpt_program_iclkip(struct drm_crtc *crtc)
{
@@ -3144,7 +3203,7 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
assert_transcoder_disabled(dev_priv, TRANSCODER_A);
@@ -3273,7 +3332,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
u32 temp;
- bool is_pch_port;
WARN_ON(!crtc->enabled);
@@ -3289,9 +3347,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
}
- is_pch_port = ironlake_crtc_driving_pch(crtc);
- if (is_pch_port) {
+ if (intel_crtc->config.has_pch_encoder) {
/* Note: FDI PLL enabling _must_ be done before we enable the
* cpu pipes, hence this is separate from all the other fdi/pch
* enabling. */
@@ -3328,10 +3385,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
*/
intel_crtc_load_lut(crtc);
- intel_enable_pipe(dev_priv, pipe, is_pch_port);
+ intel_enable_pipe(dev_priv, pipe,
+ intel_crtc->config.has_pch_encoder);
intel_enable_plane(dev_priv, plane, pipe);
- if (is_pch_port)
+ if (intel_crtc->config.has_pch_encoder)
ironlake_pch_enable(crtc);
mutex_lock(&dev->struct_mutex);
@@ -3365,7 +3423,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
struct intel_encoder *encoder;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
- bool is_pch_port;
WARN_ON(!crtc->enabled);
@@ -3375,9 +3432,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_crtc->active = true;
intel_update_watermarks(dev);
- is_pch_port = haswell_crtc_driving_pch(crtc);
-
- if (is_pch_port)
+ if (intel_crtc->config.has_pch_encoder)
dev_priv->display.fdi_link_train(crtc);
for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -3406,12 +3461,13 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_crtc_load_lut(crtc);
intel_ddi_set_pipe_settings(crtc);
- intel_ddi_enable_pipe_func(crtc);
+ intel_ddi_enable_transcoder_func(crtc);
- intel_enable_pipe(dev_priv, pipe, is_pch_port);
+ intel_enable_pipe(dev_priv, pipe,
+ intel_crtc->config.has_pch_encoder);
intel_enable_plane(dev_priv, plane, pipe);
- if (is_pch_port)
+ if (intel_crtc->config.has_pch_encoder)
lpt_pch_enable(crtc);
mutex_lock(&dev->struct_mutex);
@@ -3522,14 +3578,11 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
struct intel_encoder *encoder;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
- bool is_pch_port;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
if (!intel_crtc->active)
return;
- is_pch_port = haswell_crtc_driving_pch(crtc);
-
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->disable(encoder);
@@ -3546,9 +3599,13 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
- /* Disable PF */
- I915_WRITE(PF_CTL(pipe), 0);
- I915_WRITE(PF_WIN_SZ(pipe), 0);
+ /* XXX: Once we have proper panel fitter state tracking implemented with
+ * hardware state read/check support we should switch to only disable
+ * the panel fitter when we know it's used. */
+ if (intel_using_power_well(dev)) {
+ I915_WRITE(PF_CTL(pipe), 0);
+ I915_WRITE(PF_WIN_SZ(pipe), 0);
+ }
intel_ddi_disable_pipe_clock(intel_crtc);
@@ -3556,7 +3613,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
if (encoder->post_disable)
encoder->post_disable(encoder);
- if (is_pch_port) {
+ if (intel_crtc->config.has_pch_encoder) {
lpt_disable_pch_transcoder(dev_priv);
intel_ddi_fdi_disable(crtc);
}
@@ -3581,7 +3638,7 @@ static void haswell_crtc_off(struct drm_crtc *crtc)
/* Stop saying we're using TRANSCODER_EDP because some other CRTC might
* start using it. */
- intel_crtc->cpu_transcoder = (enum transcoder) intel_crtc->pipe;
+ intel_crtc->config.cpu_transcoder = (enum transcoder) intel_crtc->pipe;
intel_ddi_put_crtc_pll(crtc);
}
@@ -3667,6 +3724,26 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
encoder->enable(encoder);
}
+static void i9xx_pfit_disable(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum pipe pipe;
+ uint32_t pctl = I915_READ(PFIT_CONTROL);
+
+ assert_pipe_disabled(dev_priv, crtc->pipe);
+
+ if (INTEL_INFO(dev)->gen >= 4)
+ pipe = (pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT;
+ else
+ pipe = PIPE_B;
+
+ if (pipe == crtc->pipe) {
+ DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", pctl);
+ I915_WRITE(PFIT_CONTROL, 0);
+ }
+}
+
static void i9xx_crtc_disable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -3675,8 +3752,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
struct intel_encoder *encoder;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
- u32 pctl;
-
if (!intel_crtc->active)
return;
@@ -3696,11 +3771,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
intel_disable_plane(dev_priv, plane, pipe);
intel_disable_pipe(dev_priv, pipe);
- /* Disable pannel fitter if it is on this pipe. */
- pctl = I915_READ(PFIT_CONTROL);
- if ((pctl & PFIT_ENABLE) &&
- ((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe)
- I915_WRITE(PFIT_CONTROL, 0);
+ i9xx_pfit_disable(intel_crtc);
intel_disable_pll(dev_priv, pipe);
@@ -3906,22 +3977,23 @@ bool intel_connector_get_hw_state(struct intel_connector *connector)
return encoder->get_hw_state(encoder, &pipe);
}
-static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static bool intel_crtc_compute_config(struct drm_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
{
struct drm_device *dev = crtc->dev;
+ struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
if (HAS_PCH_SPLIT(dev)) {
/* FDI link clock is fixed at 2.7G */
- if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4)
+ if (pipe_config->requested_mode.clock * 3
+ > IRONLAKE_FDI_FREQ * 4)
return false;
}
/* All interlaced capable intel hw wants timings in frames. Note though
* that intel_lvds_mode_fixup does some funny tricks with the crtc
* timings, so we need to be careful not to clobber these.*/
- if (!(adjusted_mode->private_flags & INTEL_MODE_CRTC_TIMINGS_SET))
+ if (!pipe_config->timings_set)
drm_mode_set_crtcinfo(adjusted_mode, 0);
/* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes
@@ -3931,6 +4003,14 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
adjusted_mode->hsync_start == adjusted_mode->hdisplay)
return false;
+ if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) {
+ pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */
+ } else if (INTEL_INFO(dev)->gen <= 4 && pipe_config->pipe_bpp > 8*3) {
+ /* only a 8bpc pipe, with 6bpc dither through the panel fitter
+ * for lvds. */
+ pipe_config->pipe_bpp = 8*3;
+ }
+
return true;
}
@@ -4004,26 +4084,36 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
}
static void
-intel_reduce_ratio(uint32_t *num, uint32_t *den)
+intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den)
{
- while (*num > 0xffffff || *den > 0xffffff) {
+ while (*num > DATA_LINK_M_N_MASK ||
+ *den > DATA_LINK_M_N_MASK) {
*num >>= 1;
*den >>= 1;
}
}
+static void compute_m_n(unsigned int m, unsigned int n,
+ uint32_t *ret_m, uint32_t *ret_n)
+{
+ *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
+ *ret_m = div_u64((uint64_t) m * *ret_n, n);
+ intel_reduce_m_n_ratio(ret_m, ret_n);
+}
+
void
intel_link_compute_m_n(int bits_per_pixel, int nlanes,
int pixel_clock, int link_clock,
struct intel_link_m_n *m_n)
{
m_n->tu = 64;
- m_n->gmch_m = bits_per_pixel * pixel_clock;
- m_n->gmch_n = link_clock * nlanes * 8;
- intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
- m_n->link_m = pixel_clock;
- m_n->link_n = link_clock;
- intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
+
+ compute_m_n(bits_per_pixel * pixel_clock,
+ link_clock * nlanes * 8,
+ &m_n->gmch_m, &m_n->gmch_n);
+
+ compute_m_n(pixel_clock, link_clock,
+ &m_n->link_m, &m_n->link_n);
}
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
@@ -4034,142 +4124,6 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
}
-/**
- * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
- * @crtc: CRTC structure
- * @mode: requested mode
- *
- * A pipe may be connected to one or more outputs. Based on the depth of the
- * attached framebuffer, choose a good color depth to use on the pipe.
- *
- * If possible, match the pipe depth to the fb depth. In some cases, this
- * isn't ideal, because the connected output supports a lesser or restricted
- * set of depths. Resolve that here:
- * LVDS typically supports only 6bpc, so clamp down in that case
- * HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc
- * Displays may support a restricted set as well, check EDID and clamp as
- * appropriate.
- * DP may want to dither down to 6bpc to fit larger modes
- *
- * RETURNS:
- * Dithering requirement (i.e. false if display bpc and pipe bpc match,
- * true if they don't match).
- */
-static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- unsigned int *pipe_bpp,
- struct drm_display_mode *mode)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_connector *connector;
- struct intel_encoder *intel_encoder;
- unsigned int display_bpc = UINT_MAX, bpc;
-
- /* Walk the encoders & connectors on this crtc, get min bpc */
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
-
- if (intel_encoder->type == INTEL_OUTPUT_LVDS) {
- unsigned int lvds_bpc;
-
- if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) ==
- LVDS_A3_POWER_UP)
- lvds_bpc = 8;
- else
- lvds_bpc = 6;
-
- if (lvds_bpc < display_bpc) {
- DRM_DEBUG_KMS("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc);
- display_bpc = lvds_bpc;
- }
- continue;
- }
-
- /* Not one of the known troublemakers, check the EDID */
- list_for_each_entry(connector, &dev->mode_config.connector_list,
- head) {
- if (connector->encoder != &intel_encoder->base)
- continue;
-
- /* Don't use an invalid EDID bpc value */
- if (connector->display_info.bpc &&
- connector->display_info.bpc < display_bpc) {
- DRM_DEBUG_KMS("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc);
- display_bpc = connector->display_info.bpc;
- }
- }
-
- if (intel_encoder->type == INTEL_OUTPUT_EDP) {
- /* Use VBT settings if we have an eDP panel */
- unsigned int edp_bpc = dev_priv->edp.bpp / 3;
-
- if (edp_bpc && edp_bpc < display_bpc) {
- DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
- display_bpc = edp_bpc;
- }
- continue;
- }
-
- /*
- * HDMI is either 12 or 8, so if the display lets 10bpc sneak
- * through, clamp it down. (Note: >12bpc will be caught below.)
- */
- if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
- if (display_bpc > 8 && display_bpc < 12) {
- DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n");
- display_bpc = 12;
- } else {
- DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n");
- display_bpc = 8;
- }
- }
- }
-
- if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
- DRM_DEBUG_KMS("Dithering DP to 6bpc\n");
- display_bpc = 6;
- }
-
- /*
- * We could just drive the pipe at the highest bpc all the time and
- * enable dithering as needed, but that costs bandwidth. So choose
- * the minimum value that expresses the full color range of the fb but
- * also stays within the max display bpc discovered above.
- */
-
- switch (fb->depth) {
- case 8:
- bpc = 8; /* since we go through a colormap */
- break;
- case 15:
- case 16:
- bpc = 6; /* min is 18bpp */
- break;
- case 24:
- bpc = 8;
- break;
- case 30:
- bpc = 10;
- break;
- case 48:
- bpc = 12;
- break;
- default:
- DRM_DEBUG("unsupported depth, assuming 24 bits\n");
- bpc = min((unsigned int)8, display_bpc);
- break;
- }
-
- display_bpc = min(display_bpc, bpc);
-
- DRM_DEBUG_KMS("setting pipe bpc to %d (max display bpc %d)\n",
- bpc, display_bpc);
-
- *pipe_bpp = display_bpc * 3;
-
- return display_bpc != bpc;
-}
-
static int vlv_get_refclk(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -4214,37 +4168,38 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
return refclk;
}
-static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
- intel_clock_t *clock)
+static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc *crtc)
{
+ unsigned dotclock = crtc->config.adjusted_mode.clock;
+ struct dpll *clock = &crtc->config.dpll;
+
/* SDVO TV has fixed PLL values depend on its clock range,
this mirrors vbios setting. */
- if (adjusted_mode->clock >= 100000
- && adjusted_mode->clock < 140500) {
+ if (dotclock >= 100000 && dotclock < 140500) {
clock->p1 = 2;
clock->p2 = 10;
clock->n = 3;
clock->m1 = 16;
clock->m2 = 8;
- } else if (adjusted_mode->clock >= 140500
- && adjusted_mode->clock <= 200000) {
+ } else if (dotclock >= 140500 && dotclock <= 200000) {
clock->p1 = 1;
clock->p2 = 10;
clock->n = 6;
clock->m1 = 12;
clock->m2 = 8;
}
+
+ crtc->config.clock_set = true;
}
-static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
- intel_clock_t *clock,
+static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
intel_clock_t *reduced_clock)
{
- struct drm_device *dev = crtc->dev;
+ struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int pipe = intel_crtc->pipe;
+ int pipe = crtc->pipe;
u32 fp, fp2 = 0;
+ struct dpll *clock = &crtc->config.dpll;
if (IS_PINEVIEW(dev)) {
fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
@@ -4260,26 +4215,29 @@ static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
I915_WRITE(FP0(pipe), fp);
- intel_crtc->lowfreq_avail = false;
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ crtc->lowfreq_avail = false;
+ if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
reduced_clock && i915_powersave) {
I915_WRITE(FP1(pipe), fp2);
- intel_crtc->lowfreq_avail = true;
+ crtc->lowfreq_avail = true;
} else {
I915_WRITE(FP1(pipe), fp);
}
}
-static void vlv_update_pll(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- intel_clock_t *clock, intel_clock_t *reduced_clock,
- int num_connectors)
+static void intel_dp_set_m_n(struct intel_crtc *crtc)
{
- struct drm_device *dev = crtc->dev;
+ if (crtc->config.has_pch_encoder)
+ intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n);
+ else
+ intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n);
+}
+
+static void vlv_update_pll(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int pipe = intel_crtc->pipe;
+ int pipe = crtc->pipe;
u32 dpll, mdiv, pdiv;
u32 bestn, bestm1, bestm2, bestp1, bestp2;
bool is_sdvo;
@@ -4287,8 +4245,8 @@ static void vlv_update_pll(struct drm_crtc *crtc,
mutex_lock(&dev_priv->dpio_lock);
- is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ||
- intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI);
+ is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) ||
+ intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI);
dpll = DPLL_VGA_MODE_DIS;
dpll |= DPLL_EXT_BUFFER_ENABLE_VLV;
@@ -4298,11 +4256,11 @@ static void vlv_update_pll(struct drm_crtc *crtc,
I915_WRITE(DPLL(pipe), dpll);
POSTING_READ(DPLL(pipe));
- bestn = clock->n;
- bestm1 = clock->m1;
- bestm2 = clock->m2;
- bestp1 = clock->p1;
- bestp2 = clock->p2;
+ bestn = crtc->config.dpll.n;
+ bestm1 = crtc->config.dpll.m1;
+ bestm2 = crtc->config.dpll.m2;
+ bestp1 = crtc->config.dpll.p1;
+ bestp2 = crtc->config.dpll.p2;
/*
* In Valleyview PLL and program lane counter registers are exposed
@@ -4334,8 +4292,8 @@ static void vlv_update_pll(struct drm_crtc *crtc,
intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x620);
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
- intel_dp_set_m_n(crtc, mode, adjusted_mode);
+ if (crtc->config.has_dp_encoder)
+ intel_dp_set_m_n(crtc);
I915_WRITE(DPLL(pipe), dpll);
@@ -4345,26 +4303,25 @@ static void vlv_update_pll(struct drm_crtc *crtc,
temp = 0;
if (is_sdvo) {
- temp = intel_mode_get_pixel_multiplier(adjusted_mode);
- if (temp > 1)
- temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
- else
- temp = 0;
+ temp = 0;
+ if (crtc->config.pixel_multiplier > 1) {
+ temp = (crtc->config.pixel_multiplier - 1)
+ << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+ }
}
I915_WRITE(DPLL_MD(pipe), temp);
POSTING_READ(DPLL_MD(pipe));
/* Now program lane control registers */
- if(intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)
- || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI))
- {
+ if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)
+ || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) {
temp = 0x1000C4;
if(pipe == 1)
temp |= (1 << 21);
intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL1, temp);
}
- if(intel_pipe_has_type(crtc,INTEL_OUTPUT_EDP))
- {
+
+ if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) {
temp = 0x1000C4;
if(pipe == 1)
temp |= (1 << 21);
@@ -4374,40 +4331,39 @@ static void vlv_update_pll(struct drm_crtc *crtc,
mutex_unlock(&dev_priv->dpio_lock);
}
-static void i9xx_update_pll(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- intel_clock_t *clock, intel_clock_t *reduced_clock,
+static void i9xx_update_pll(struct intel_crtc *crtc,
+ intel_clock_t *reduced_clock,
int num_connectors)
{
- struct drm_device *dev = crtc->dev;
+ struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
- int pipe = intel_crtc->pipe;
+ int pipe = crtc->pipe;
u32 dpll;
bool is_sdvo;
+ struct dpll *clock = &crtc->config.dpll;
- i9xx_update_pll_dividers(crtc, clock, reduced_clock);
+ i9xx_update_pll_dividers(crtc, reduced_clock);
- is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ||
- intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI);
+ is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) ||
+ intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI);
dpll = DPLL_VGA_MODE_DIS;
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+ if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS))
dpll |= DPLLB_MODE_LVDS;
else
dpll |= DPLLB_MODE_DAC_SERIAL;
+
if (is_sdvo) {
- int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
- if (pixel_multiplier > 1) {
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
- dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+ if ((crtc->config.pixel_multiplier > 1) &&
+ (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))) {
+ dpll |= (crtc->config.pixel_multiplier - 1)
+ << SDVO_MULTIPLIER_SHIFT_HIRES;
}
dpll |= DPLL_DVO_HIGH_SPEED;
}
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
+ if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT))
dpll |= DPLL_DVO_HIGH_SPEED;
/* compute bitmask from p1 value */
@@ -4435,13 +4391,13 @@ static void i9xx_update_pll(struct drm_crtc *crtc,
if (INTEL_INFO(dev)->gen >= 4)
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
- if (is_sdvo && intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+ if (is_sdvo && intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT))
dpll |= PLL_REF_INPUT_TVCLKINBC;
- else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+ else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT))
/* XXX: just matching BIOS for now */
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
- else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
intel_panel_use_ssc(dev_priv) && num_connectors < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
else
@@ -4452,12 +4408,12 @@ static void i9xx_update_pll(struct drm_crtc *crtc,
POSTING_READ(DPLL(pipe));
udelay(150);
- for_each_encoder_on_crtc(dev, crtc, encoder)
+ for_each_encoder_on_crtc(dev, &crtc->base, encoder)
if (encoder->pre_pll_enable)
encoder->pre_pll_enable(encoder);
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
- intel_dp_set_m_n(crtc, mode, adjusted_mode);
+ if (crtc->config.has_dp_encoder)
+ intel_dp_set_m_n(crtc);
I915_WRITE(DPLL(pipe), dpll);
@@ -4468,11 +4424,11 @@ static void i9xx_update_pll(struct drm_crtc *crtc,
if (INTEL_INFO(dev)->gen >= 4) {
u32 temp = 0;
if (is_sdvo) {
- temp = intel_mode_get_pixel_multiplier(adjusted_mode);
- if (temp > 1)
- temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
- else
- temp = 0;
+ temp = 0;
+ if (crtc->config.pixel_multiplier > 1) {
+ temp = (crtc->config.pixel_multiplier - 1)
+ << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+ }
}
I915_WRITE(DPLL_MD(pipe), temp);
} else {
@@ -4485,23 +4441,23 @@ static void i9xx_update_pll(struct drm_crtc *crtc,
}
}
-static void i8xx_update_pll(struct drm_crtc *crtc,
+static void i8xx_update_pll(struct intel_crtc *crtc,
struct drm_display_mode *adjusted_mode,
- intel_clock_t *clock, intel_clock_t *reduced_clock,
+ intel_clock_t *reduced_clock,
int num_connectors)
{
- struct drm_device *dev = crtc->dev;
+ struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
- int pipe = intel_crtc->pipe;
+ int pipe = crtc->pipe;
u32 dpll;
+ struct dpll *clock = &crtc->config.dpll;
- i9xx_update_pll_dividers(crtc, clock, reduced_clock);
+ i9xx_update_pll_dividers(crtc, reduced_clock);
dpll = DPLL_VGA_MODE_DIS;
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)) {
dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
} else {
if (clock->p1 == 2)
@@ -4512,11 +4468,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc,
dpll |= PLL_P2_DIVIDE_BY_4;
}
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
- /* XXX: just matching BIOS for now */
- /* dpll |= PLL_REF_INPUT_TVCLKINBC; */
- dpll |= 3;
- else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
intel_panel_use_ssc(dev_priv) && num_connectors < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
else
@@ -4527,7 +4479,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc,
POSTING_READ(DPLL(pipe));
udelay(150);
- for_each_encoder_on_crtc(dev, crtc, encoder)
+ for_each_encoder_on_crtc(dev, &crtc->base, encoder)
if (encoder->pre_pll_enable)
encoder->pre_pll_enable(encoder);
@@ -4552,7 +4504,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe = intel_crtc->pipe;
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
uint32_t vsyncshift;
if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
@@ -4603,22 +4555,92 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
}
+static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
+{
+ struct drm_device *dev = intel_crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t pipeconf;
+
+ pipeconf = I915_READ(PIPECONF(intel_crtc->pipe));
+
+ if (intel_crtc->pipe == 0 && INTEL_INFO(dev)->gen < 4) {
+ /* Enable pixel doubling when the dot clock is > 90% of the (display)
+ * core speed.
+ *
+ * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
+ * pipe == 0 check?
+ */
+ if (intel_crtc->config.requested_mode.clock >
+ dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
+ pipeconf |= PIPECONF_DOUBLE_WIDE;
+ else
+ pipeconf &= ~PIPECONF_DOUBLE_WIDE;
+ }
+
+ /* default to 8bpc */
+ pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN);
+ if (intel_crtc->config.has_dp_encoder) {
+ if (intel_crtc->config.dither) {
+ pipeconf |= PIPECONF_6BPC |
+ PIPECONF_DITHER_EN |
+ PIPECONF_DITHER_TYPE_SP;
+ }
+ }
+
+ if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(&intel_crtc->base,
+ INTEL_OUTPUT_EDP)) {
+ if (intel_crtc->config.dither) {
+ pipeconf |= PIPECONF_6BPC |
+ PIPECONF_ENABLE |
+ I965_PIPECONF_ACTIVE;
+ }
+ }
+
+ if (HAS_PIPE_CXSR(dev)) {
+ if (intel_crtc->lowfreq_avail) {
+ DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+ pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+ } else {
+ DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+ pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+ }
+ }
+
+ pipeconf &= ~PIPECONF_INTERLACE_MASK;
+ if (!IS_GEN2(dev) &&
+ intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+ pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+ else
+ pipeconf |= PIPECONF_PROGRESSIVE;
+
+ if (IS_VALLEYVIEW(dev)) {
+ if (intel_crtc->config.limited_color_range)
+ pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
+ else
+ pipeconf &= ~PIPECONF_COLOR_RANGE_SELECT;
+ }
+
+ I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
+ POSTING_READ(PIPECONF(intel_crtc->pipe));
+}
+
static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *fb)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_display_mode *adjusted_mode =
+ &intel_crtc->config.adjusted_mode;
+ struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
int refclk, num_connectors = 0;
intel_clock_t clock, reduced_clock;
- u32 dspcntr, pipeconf;
+ u32 dspcntr;
bool ok, has_reduced_clock = false, is_sdvo = false;
- bool is_lvds = false, is_tv = false, is_dp = false;
+ bool is_lvds = false, is_tv = false;
struct intel_encoder *encoder;
const intel_limit_t *limit;
int ret;
@@ -4637,9 +4659,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_TVOUT:
is_tv = true;
break;
- case INTEL_OUTPUT_DISPLAYPORT:
- is_dp = true;
- break;
}
num_connectors++;
@@ -4676,86 +4695,42 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
&clock,
&reduced_clock);
}
+ /* Compat-code for transition, will disappear. */
+ if (!intel_crtc->config.clock_set) {
+ intel_crtc->config.dpll.n = clock.n;
+ intel_crtc->config.dpll.m1 = clock.m1;
+ intel_crtc->config.dpll.m2 = clock.m2;
+ intel_crtc->config.dpll.p1 = clock.p1;
+ intel_crtc->config.dpll.p2 = clock.p2;
+ }
if (is_sdvo && is_tv)
- i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+ i9xx_adjust_sdvo_tv_clock(intel_crtc);
if (IS_GEN2(dev))
- i8xx_update_pll(crtc, adjusted_mode, &clock,
+ i8xx_update_pll(intel_crtc, adjusted_mode,
has_reduced_clock ? &reduced_clock : NULL,
num_connectors);
else if (IS_VALLEYVIEW(dev))
- vlv_update_pll(crtc, mode, adjusted_mode, &clock,
- has_reduced_clock ? &reduced_clock : NULL,
- num_connectors);
+ vlv_update_pll(intel_crtc);
else
- i9xx_update_pll(crtc, mode, adjusted_mode, &clock,
+ i9xx_update_pll(intel_crtc,
has_reduced_clock ? &reduced_clock : NULL,
num_connectors);
- /* setup pipeconf */
- pipeconf = I915_READ(PIPECONF(pipe));
-
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
- if (pipe == 0)
- dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
- else
- dspcntr |= DISPPLANE_SEL_PIPE_B;
-
- if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
- /* Enable pixel doubling when the dot clock is > 90% of the (display)
- * core speed.
- *
- * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
- * pipe == 0 check?
- */
- if (mode->clock >
- dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
- pipeconf |= PIPECONF_DOUBLE_WIDE;
+ if (!IS_VALLEYVIEW(dev)) {
+ if (pipe == 0)
+ dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
else
- pipeconf &= ~PIPECONF_DOUBLE_WIDE;
- }
-
- /* default to 8bpc */
- pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN);
- if (is_dp) {
- if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
- pipeconf |= PIPECONF_6BPC |
- PIPECONF_DITHER_EN |
- PIPECONF_DITHER_TYPE_SP;
- }
- }
-
- if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) {
- if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) {
- pipeconf |= PIPECONF_6BPC |
- PIPECONF_ENABLE |
- I965_PIPECONF_ACTIVE;
- }
+ dspcntr |= DISPPLANE_SEL_PIPE_B;
}
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
- if (HAS_PIPE_CXSR(dev)) {
- if (intel_crtc->lowfreq_avail) {
- DRM_DEBUG_KMS("enabling CxSR downclocking\n");
- pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
- } else {
- DRM_DEBUG_KMS("disabling CxSR downclocking\n");
- pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
- }
- }
-
- pipeconf &= ~PIPECONF_INTERLACE_MASK;
- if (!IS_GEN2(dev) &&
- adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
- pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
- else
- pipeconf |= PIPECONF_PROGRESSIVE;
-
intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
/* pipesrc and dspsize control the size that is scaled from,
@@ -4766,8 +4741,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
(mode->hdisplay - 1));
I915_WRITE(DSPPOS(plane), 0);
- I915_WRITE(PIPECONF(pipe), pipeconf);
- POSTING_READ(PIPECONF(pipe));
+ i9xx_set_pipeconf(intel_crtc);
+
intel_enable_pipe(dev_priv, pipe, false);
intel_wait_for_vblank(dev, pipe);
@@ -4782,12 +4757,26 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
return ret;
}
+static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
+ tmp = I915_READ(PIPECONF(crtc->pipe));
+ if (!(tmp & PIPECONF_ENABLE))
+ return false;
+
+ return true;
+}
+
static void ironlake_init_pch_refclk(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_mode_config *mode_config = &dev->mode_config;
struct intel_encoder *encoder;
- u32 temp;
+ u32 val, final;
bool has_lvds = false;
bool has_cpu_edp = false;
bool has_pch_edp = false;
@@ -4830,70 +4819,109 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
* PCH B stepping, previous chipset stepping should be
* ignoring this setting.
*/
- temp = I915_READ(PCH_DREF_CONTROL);
+ val = I915_READ(PCH_DREF_CONTROL);
+
+ /* As we must carefully and slowly disable/enable each source in turn,
+ * compute the final state we want first and check if we need to
+ * make any changes at all.
+ */
+ final = val;
+ final &= ~DREF_NONSPREAD_SOURCE_MASK;
+ if (has_ck505)
+ final |= DREF_NONSPREAD_CK505_ENABLE;
+ else
+ final |= DREF_NONSPREAD_SOURCE_ENABLE;
+
+ final &= ~DREF_SSC_SOURCE_MASK;
+ final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+ final &= ~DREF_SSC1_ENABLE;
+
+ if (has_panel) {
+ final |= DREF_SSC_SOURCE_ENABLE;
+
+ if (intel_panel_use_ssc(dev_priv) && can_ssc)
+ final |= DREF_SSC1_ENABLE;
+
+ if (has_cpu_edp) {
+ if (intel_panel_use_ssc(dev_priv) && can_ssc)
+ final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+ else
+ final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+ } else
+ final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+ } else {
+ final |= DREF_SSC_SOURCE_DISABLE;
+ final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+ }
+
+ if (final == val)
+ return;
+
/* Always enable nonspread source */
- temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+ val &= ~DREF_NONSPREAD_SOURCE_MASK;
if (has_ck505)
- temp |= DREF_NONSPREAD_CK505_ENABLE;
+ val |= DREF_NONSPREAD_CK505_ENABLE;
else
- temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+ val |= DREF_NONSPREAD_SOURCE_ENABLE;
if (has_panel) {
- temp &= ~DREF_SSC_SOURCE_MASK;
- temp |= DREF_SSC_SOURCE_ENABLE;
+ val &= ~DREF_SSC_SOURCE_MASK;
+ val |= DREF_SSC_SOURCE_ENABLE;
/* SSC must be turned on before enabling the CPU output */
if (intel_panel_use_ssc(dev_priv) && can_ssc) {
DRM_DEBUG_KMS("Using SSC on panel\n");
- temp |= DREF_SSC1_ENABLE;
+ val |= DREF_SSC1_ENABLE;
} else
- temp &= ~DREF_SSC1_ENABLE;
+ val &= ~DREF_SSC1_ENABLE;
/* Get SSC going before enabling the outputs */
- I915_WRITE(PCH_DREF_CONTROL, temp);
+ I915_WRITE(PCH_DREF_CONTROL, val);
POSTING_READ(PCH_DREF_CONTROL);
udelay(200);
- temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+ val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
/* Enable CPU source on CPU attached eDP */
if (has_cpu_edp) {
if (intel_panel_use_ssc(dev_priv) && can_ssc) {
DRM_DEBUG_KMS("Using SSC on eDP\n");
- temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+ val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
}
else
- temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+ val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
} else
- temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+ val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
+ I915_WRITE(PCH_DREF_CONTROL, val);
POSTING_READ(PCH_DREF_CONTROL);
udelay(200);
} else {
DRM_DEBUG_KMS("Disabling SSC entirely\n");
- temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+ val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
/* Turn off CPU output */
- temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+ val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
+ I915_WRITE(PCH_DREF_CONTROL, val);
POSTING_READ(PCH_DREF_CONTROL);
udelay(200);
/* Turn off the SSC source */
- temp &= ~DREF_SSC_SOURCE_MASK;
- temp |= DREF_SSC_SOURCE_DISABLE;
+ val &= ~DREF_SSC_SOURCE_MASK;
+ val |= DREF_SSC_SOURCE_DISABLE;
/* Turn off SSC1 */
- temp &= ~ DREF_SSC1_ENABLE;
+ val &= ~DREF_SSC1_ENABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
+ I915_WRITE(PCH_DREF_CONTROL, val);
POSTING_READ(PCH_DREF_CONTROL);
udelay(200);
}
+
+ BUG_ON(val != final);
}
/* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */
@@ -4958,13 +4986,6 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
tmp |= (0x12 << 24);
intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
- if (!is_sdv) {
- tmp = intel_sbi_read(dev_priv, 0x808C, SBI_MPHY);
- tmp &= ~(0x3 << 6);
- tmp |= (1 << 6) | (1 << 0);
- intel_sbi_write(dev_priv, 0x808C, tmp, SBI_MPHY);
- }
-
if (is_sdv) {
tmp = intel_sbi_read(dev_priv, 0x800C, SBI_MPHY);
tmp |= 0x7FFF;
@@ -5118,7 +5139,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
val = I915_READ(PIPECONF(pipe));
val &= ~PIPECONF_BPC_MASK;
- switch (intel_crtc->bpp) {
+ switch (intel_crtc->config.pipe_bpp) {
case 18:
val |= PIPECONF_6BPC;
break;
@@ -5146,7 +5167,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
else
val |= PIPECONF_PROGRESSIVE;
- if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+ if (intel_crtc->config.limited_color_range)
val |= PIPECONF_COLOR_RANGE_SELECT;
else
val &= ~PIPECONF_COLOR_RANGE_SELECT;
@@ -5162,8 +5183,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
* is supported, but eventually this should handle various
* RGB<->YCbCr scenarios as well.
*/
-static void intel_set_pipe_csc(struct drm_crtc *crtc,
- const struct drm_display_mode *adjusted_mode)
+static void intel_set_pipe_csc(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5178,7 +5198,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc,
* consideration.
*/
- if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+ if (intel_crtc->config.limited_color_range)
coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
/*
@@ -5202,7 +5222,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc,
if (INTEL_INFO(dev)->gen > 6) {
uint16_t postoff = 0;
- if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+ if (intel_crtc->config.limited_color_range)
postoff = (16 * (1 << 13) / 255) & 0x1fff;
I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
@@ -5213,7 +5233,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc,
} else {
uint32_t mode = CSC_MODE_YUV_TO_RGB;
- if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+ if (intel_crtc->config.limited_color_range)
mode |= CSC_BLACK_SCREEN_OFFSET;
I915_WRITE(PIPE_CSC_MODE(pipe), mode);
@@ -5226,7 +5246,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc,
{
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
uint32_t val;
val = I915_READ(PIPECONF(cpu_transcoder));
@@ -5303,7 +5323,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
}
if (is_sdvo && is_tv)
- i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock);
+ i9xx_adjust_sdvo_tv_clock(to_intel_crtc(crtc));
return true;
}
@@ -5344,7 +5364,7 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc)
return false;
}
- if (dev_priv->num_pipe == 2)
+ if (INTEL_INFO(dev)->num_pipes == 2)
return true;
switch (intel_crtc->pipe) {
@@ -5401,87 +5421,87 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
return bps / (link_bw * 8) + 1;
}
-static void ironlake_set_m_n(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
+ struct intel_link_m_n *m_n)
{
- struct drm_device *dev = crtc->dev;
+ struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
- struct intel_encoder *intel_encoder, *edp_encoder = NULL;
- struct intel_link_m_n m_n = {0};
- int target_clock, pixel_multiplier, lane, link_bw;
- bool is_dp = false, is_cpu_edp = false;
+ int pipe = crtc->pipe;
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
- switch (intel_encoder->type) {
- case INTEL_OUTPUT_DISPLAYPORT:
- is_dp = true;
- break;
- case INTEL_OUTPUT_EDP:
- is_dp = true;
- if (!intel_encoder_is_pch_edp(&intel_encoder->base))
- is_cpu_edp = true;
- edp_encoder = intel_encoder;
- break;
- }
- }
+ I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
+ I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n);
+ I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m);
+ I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n);
+}
+
+void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
+ struct intel_link_m_n *m_n)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe = crtc->pipe;
+ enum transcoder transcoder = crtc->config.cpu_transcoder;
- /* FDI link */
- pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
- lane = 0;
- /* CPU eDP doesn't require FDI link, so just set DP M/N
- according to current link config */
- if (is_cpu_edp) {
- intel_edp_link_config(edp_encoder, &lane, &link_bw);
+ if (INTEL_INFO(dev)->gen >= 5) {
+ I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
+ I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
+ I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
+ I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
} else {
- /* FDI is a binary signal running at ~2.7GHz, encoding
- * each output octet as 10 bits. The actual frequency
- * is stored as a divider into a 100MHz clock, and the
- * mode pixel clock is stored in units of 1KHz.
- * Hence the bw of each lane in terms of the mode signal
- * is:
- */
- link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
+ I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
+ I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n);
+ I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m);
+ I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n);
}
+}
+
+static void ironlake_fdi_set_m_n(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_display_mode *adjusted_mode =
+ &intel_crtc->config.adjusted_mode;
+ struct intel_link_m_n m_n = {0};
+ int target_clock, lane, link_bw;
+
+ /* FDI is a binary signal running at ~2.7GHz, encoding
+ * each output octet as 10 bits. The actual frequency
+ * is stored as a divider into a 100MHz clock, and the
+ * mode pixel clock is stored in units of 1KHz.
+ * Hence the bw of each lane in terms of the mode signal
+ * is:
+ */
+ link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
- /* [e]DP over FDI requires target mode clock instead of link clock. */
- if (edp_encoder)
- target_clock = intel_edp_target_clock(edp_encoder, mode);
- else if (is_dp)
- target_clock = mode->clock;
+ if (intel_crtc->config.pixel_target_clock)
+ target_clock = intel_crtc->config.pixel_target_clock;
else
target_clock = adjusted_mode->clock;
- if (!lane)
- lane = ironlake_get_lanes_required(target_clock, link_bw,
- intel_crtc->bpp);
+ lane = ironlake_get_lanes_required(target_clock, link_bw,
+ intel_crtc->config.pipe_bpp);
intel_crtc->fdi_lanes = lane;
- if (pixel_multiplier > 1)
- link_bw *= pixel_multiplier;
- intel_link_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, &m_n);
+ if (intel_crtc->config.pixel_multiplier > 1)
+ link_bw *= intel_crtc->config.pixel_multiplier;
+ intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane, target_clock,
+ link_bw, &m_n);
- I915_WRITE(PIPE_DATA_M1(cpu_transcoder), TU_SIZE(m_n.tu) | m_n.gmch_m);
- I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n);
- I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m);
- I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n);
+ intel_cpu_transcoder_set_m_n(intel_crtc, &m_n);
}
static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
- struct drm_display_mode *adjusted_mode,
- intel_clock_t *clock, u32 fp)
+ intel_clock_t *clock, u32 *fp,
+ intel_clock_t *reduced_clock, u32 *fp2)
{
struct drm_crtc *crtc = &intel_crtc->base;
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
uint32_t dpll;
- int factor, pixel_multiplier, num_connectors = 0;
+ int factor, num_connectors = 0;
bool is_lvds = false, is_sdvo = false, is_tv = false;
- bool is_dp = false, is_cpu_edp = false;
for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
switch (intel_encoder->type) {
@@ -5497,14 +5517,6 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
case INTEL_OUTPUT_TVOUT:
is_tv = true;
break;
- case INTEL_OUTPUT_DISPLAYPORT:
- is_dp = true;
- break;
- case INTEL_OUTPUT_EDP:
- is_dp = true;
- if (!intel_encoder_is_pch_edp(&intel_encoder->base))
- is_cpu_edp = true;
- break;
}
num_connectors++;
@@ -5515,13 +5527,16 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
if (is_lvds) {
if ((intel_panel_use_ssc(dev_priv) &&
dev_priv->lvds_ssc_freq == 100) ||
- intel_is_dual_link_lvds(dev))
+ (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev)))
factor = 25;
} else if (is_sdvo && is_tv)
factor = 20;
if (clock->m < factor * clock->n)
- fp |= FP_CB_TUNE;
+ *fp |= FP_CB_TUNE;
+
+ if (fp2 && (reduced_clock->m < factor * reduced_clock->n))
+ *fp2 |= FP_CB_TUNE;
dpll = 0;
@@ -5530,13 +5545,14 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
else
dpll |= DPLLB_MODE_DAC_SERIAL;
if (is_sdvo) {
- pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
- if (pixel_multiplier > 1) {
- dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+ if (intel_crtc->config.pixel_multiplier > 1) {
+ dpll |= (intel_crtc->config.pixel_multiplier - 1)
+ << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
}
dpll |= DPLL_DVO_HIGH_SPEED;
}
- if (is_dp && !is_cpu_edp)
+ if (intel_crtc->config.has_dp_encoder &&
+ intel_crtc->config.has_pch_encoder)
dpll |= DPLL_DVO_HIGH_SPEED;
/* compute bitmask from p1 value */
@@ -5574,21 +5590,22 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
}
static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *fb)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_display_mode *adjusted_mode =
+ &intel_crtc->config.adjusted_mode;
+ struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
int num_connectors = 0;
intel_clock_t clock, reduced_clock;
u32 dpll, fp = 0, fp2 = 0;
bool ok, has_reduced_clock = false;
- bool is_lvds = false, is_dp = false, is_cpu_edp = false;
+ bool is_lvds = false;
struct intel_encoder *encoder;
int ret;
bool dither, fdi_config_ok;
@@ -5598,14 +5615,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_LVDS:
is_lvds = true;
break;
- case INTEL_OUTPUT_DISPLAYPORT:
- is_dp = true;
- break;
- case INTEL_OUTPUT_EDP:
- is_dp = true;
- if (!intel_encoder_is_pch_edp(&encoder->base))
- is_cpu_edp = true;
- break;
}
num_connectors++;
@@ -5614,19 +5623,28 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
"Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev));
+ intel_crtc->config.cpu_transcoder = pipe;
+
ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock,
&has_reduced_clock, &reduced_clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
}
+ /* Compat-code for transition, will disappear. */
+ if (!intel_crtc->config.clock_set) {
+ intel_crtc->config.dpll.n = clock.n;
+ intel_crtc->config.dpll.m1 = clock.m1;
+ intel_crtc->config.dpll.m2 = clock.m2;
+ intel_crtc->config.dpll.p1 = clock.p1;
+ intel_crtc->config.dpll.p2 = clock.p2;
+ }
/* Ensure that the cursor is valid for the new mode before changing... */
intel_crtc_update_cursor(crtc, true);
/* determine panel color depth */
- dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp,
- adjusted_mode);
+ dither = intel_crtc->config.dither;
if (is_lvds && dev_priv->lvds_dither)
dither = true;
@@ -5635,13 +5653,14 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
reduced_clock.m2;
- dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp);
+ dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp, &reduced_clock,
+ has_reduced_clock ? &fp2 : NULL);
DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
drm_mode_debug_printmodeline(mode);
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
- if (!is_cpu_edp) {
+ if (intel_crtc->config.has_pch_encoder) {
struct intel_pch_pll *pll;
pll = intel_get_pch_pll(intel_crtc, dpll, fp);
@@ -5653,8 +5672,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
} else
intel_put_pch_pll(intel_crtc);
- if (is_dp && !is_cpu_edp)
- intel_dp_set_m_n(crtc, mode, adjusted_mode);
+ if (intel_crtc->config.has_dp_encoder)
+ intel_dp_set_m_n(intel_crtc);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_pll_enable)
@@ -5689,7 +5708,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
/* Note, this also computes intel_crtc->fdi_lanes which is used below in
* ironlake_check_fdi_lanes. */
- ironlake_set_m_n(crtc, mode, adjusted_mode);
+ intel_crtc->fdi_lanes = 0;
+ if (intel_crtc->config.has_pch_encoder)
+ ironlake_fdi_set_m_n(crtc);
fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc);
@@ -5710,6 +5731,23 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
return fdi_config_ok ? ret : -EINVAL;
}
+static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
+ tmp = I915_READ(PIPECONF(crtc->pipe));
+ if (!(tmp & PIPECONF_ENABLE))
+ return false;
+
+ if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE)
+ pipe_config->has_pch_encoder = true;
+
+ return true;
+}
+
static void haswell_modeset_global_resources(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5740,29 +5778,26 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
}
static int haswell_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *fb)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_display_mode *adjusted_mode =
+ &intel_crtc->config.adjusted_mode;
+ struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
int num_connectors = 0;
- bool is_dp = false, is_cpu_edp = false;
+ bool is_cpu_edp = false;
struct intel_encoder *encoder;
int ret;
bool dither;
for_each_encoder_on_crtc(dev, crtc, encoder) {
switch (encoder->type) {
- case INTEL_OUTPUT_DISPLAYPORT:
- is_dp = true;
- break;
case INTEL_OUTPUT_EDP:
- is_dp = true;
if (!intel_encoder_is_pch_edp(&encoder->base))
is_cpu_edp = true;
break;
@@ -5772,9 +5807,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
}
if (is_cpu_edp)
- intel_crtc->cpu_transcoder = TRANSCODER_EDP;
+ intel_crtc->config.cpu_transcoder = TRANSCODER_EDP;
else
- intel_crtc->cpu_transcoder = pipe;
+ intel_crtc->config.cpu_transcoder = pipe;
/* We are not sure yet this won't happen. */
WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n",
@@ -5783,7 +5818,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
WARN(num_connectors != 1, "%d connectors attached to pipe %c\n",
num_connectors, pipe_name(pipe));
- WARN_ON(I915_READ(PIPECONF(intel_crtc->cpu_transcoder)) &
+ WARN_ON(I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) &
(PIPECONF_ENABLE | I965_PIPECONF_ACTIVE));
WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE);
@@ -5795,25 +5830,24 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc_update_cursor(crtc, true);
/* determine panel color depth */
- dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp,
- adjusted_mode);
+ dither = intel_crtc->config.dither;
DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
drm_mode_debug_printmodeline(mode);
- if (is_dp && !is_cpu_edp)
- intel_dp_set_m_n(crtc, mode, adjusted_mode);
+ if (intel_crtc->config.has_dp_encoder)
+ intel_dp_set_m_n(intel_crtc);
intel_crtc->lowfreq_avail = false;
intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
- if (!is_dp || is_cpu_edp)
- ironlake_set_m_n(crtc, mode, adjusted_mode);
+ if (intel_crtc->config.has_pch_encoder)
+ ironlake_fdi_set_m_n(crtc);
haswell_set_pipeconf(crtc, adjusted_mode, dither);
- intel_set_pipe_csc(crtc, adjusted_mode);
+ intel_set_pipe_csc(crtc);
/* Set up the display plane register */
I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE);
@@ -5828,9 +5862,32 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
return ret;
}
+static bool haswell_get_pipe_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
+ tmp = I915_READ(PIPECONF(crtc->config.cpu_transcoder));
+ if (!(tmp & PIPECONF_ENABLE))
+ return false;
+
+ /*
+ * aswell has only FDI/PCH transcoder A. It is which is connected to
+ * DDI E. So just check whether this pipe is wired to DDI E and whether
+ * the PCH transcoder is on.
+ */
+ tmp = I915_READ(TRANS_DDI_FUNC_CTL(crtc->pipe));
+ if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) &&
+ I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE)
+ pipe_config->has_pch_encoder = true;
+
+
+ return true;
+}
+
static int intel_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *fb)
{
@@ -5839,13 +5896,16 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_encoder_helper_funcs *encoder_funcs;
struct intel_encoder *encoder;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_display_mode *adjusted_mode =
+ &intel_crtc->config.adjusted_mode;
+ struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
int pipe = intel_crtc->pipe;
int ret;
drm_vblank_pre_modeset(dev, pipe);
- ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
- x, y, fb);
+ ret = dev_priv->display.crtc_mode_set(crtc, x, y, fb);
+
drm_vblank_post_modeset(dev, pipe);
if (ret != 0)
@@ -5856,8 +5916,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
encoder->base.base.id,
drm_get_encoder_name(&encoder->base),
mode->base.id, mode->name);
- encoder_funcs = encoder->base.helper_private;
- encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode);
+ if (encoder->mode_set) {
+ encoder->mode_set(encoder);
+ } else {
+ encoder_funcs = encoder->base.helper_private;
+ encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode);
+ }
}
return 0;
@@ -6325,13 +6389,24 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
/* we only need to pin inside GTT if cursor is non-phy */
mutex_lock(&dev->struct_mutex);
if (!dev_priv->info->cursor_needs_physical) {
+ unsigned alignment;
+
if (obj->tiling_mode) {
DRM_ERROR("cursor cannot be tiled\n");
ret = -EINVAL;
goto fail_locked;
}
- ret = i915_gem_object_pin_to_display_plane(obj, 0, NULL);
+ /* Note that the w/a also requires 2 PTE of padding following
+ * the bo. We currently fill all unused PTE with the shadow
+ * page and so we should always have valid PTE following the
+ * cursor preventing the VT-d warning.
+ */
+ alignment = 0;
+ if (need_vtd_wa(dev))
+ alignment = 64*1024;
+
+ ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL);
if (ret) {
DRM_ERROR("failed to move cursor bo into the GTT\n");
goto fail_locked;
@@ -6436,20 +6511,6 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
intel_crtc_load_lut(crtc);
}
-/**
- * Get a pipe with a simple mode set on it for doing load-based monitor
- * detection.
- *
- * It will be up to the load-detect code to adjust the pipe as appropriate for
- * its requirements. The pipe will be connected to no other encoders.
- *
- * Currently this code will only succeed if there is a pipe with no encoders
- * configured for it. In the future, it could choose to temporarily disable
- * some outputs to free up a pipe for its use.
- *
- * \return crtc, or NULL if no pipes are available.
- */
-
/* VESA 640x480x72Hz mode to set on the pipe */
static struct drm_display_mode load_detect_mode = {
DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
@@ -6776,7 +6837,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
struct drm_display_mode *mode;
int htot = I915_READ(HTOTAL(cpu_transcoder));
int hsync = I915_READ(HSYNC(cpu_transcoder));
@@ -6954,7 +7015,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_unpin_work *work;
- struct drm_i915_gem_object *obj;
unsigned long flags;
/* Ignore early vblank irqs */
@@ -6984,8 +7044,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
spin_unlock_irqrestore(&dev->event_lock, flags);
- obj = work->old_fb_obj;
-
wake_up_all(&dev_priv->pending_flip_queue);
queue_work(dev_priv->wq, &work->work);
@@ -7473,19 +7531,93 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
}
}
-static struct drm_display_mode *
-intel_modeset_adjusted_mode(struct drm_crtc *crtc,
- struct drm_display_mode *mode)
+static int
+pipe_config_set_bpp(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_connector *connector;
+ int bpp;
+
+ switch (fb->pixel_format) {
+ case DRM_FORMAT_C8:
+ bpp = 8*3; /* since we go through a colormap */
+ break;
+ case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_ARGB1555:
+ /* checked in intel_framebuffer_init already */
+ if (WARN_ON(INTEL_INFO(dev)->gen > 3))
+ return -EINVAL;
+ case DRM_FORMAT_RGB565:
+ bpp = 6*3; /* min is 18bpp */
+ break;
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ABGR8888:
+ /* checked in intel_framebuffer_init already */
+ if (WARN_ON(INTEL_INFO(dev)->gen < 4))
+ return -EINVAL;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
+ bpp = 8*3;
+ break;
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ABGR2101010:
+ /* checked in intel_framebuffer_init already */
+ if (WARN_ON(INTEL_INFO(dev)->gen < 4))
+ return -EINVAL;
+ bpp = 10*3;
+ break;
+ /* TODO: gen4+ supports 16 bpc floating point, too. */
+ default:
+ DRM_DEBUG_KMS("unsupported depth\n");
+ return -EINVAL;
+ }
+
+ pipe_config->pipe_bpp = bpp;
+
+ /* Clamp display bpp to EDID value */
+ list_for_each_entry(connector, &dev->mode_config.connector_list,
+ head) {
+ if (connector->encoder && connector->encoder->crtc != crtc)
+ continue;
+
+ /* Don't use an invalid EDID bpc value */
+ if (connector->display_info.bpc &&
+ connector->display_info.bpc * 3 < bpp) {
+ DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
+ bpp, connector->display_info.bpc*3);
+ pipe_config->pipe_bpp = connector->display_info.bpc*3;
+ }
+ }
+
+ return bpp;
+}
+
+static struct intel_crtc_config *
+intel_modeset_pipe_config(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_display_mode *mode)
{
struct drm_device *dev = crtc->dev;
- struct drm_display_mode *adjusted_mode;
struct drm_encoder_helper_funcs *encoder_funcs;
struct intel_encoder *encoder;
+ struct intel_crtc_config *pipe_config;
+ int plane_bpp;
- adjusted_mode = drm_mode_duplicate(dev, mode);
- if (!adjusted_mode)
+ pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
+ if (!pipe_config)
return ERR_PTR(-ENOMEM);
+ drm_mode_copy(&pipe_config->adjusted_mode, mode);
+ drm_mode_copy(&pipe_config->requested_mode, mode);
+
+ plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config);
+ if (plane_bpp < 0)
+ goto fail;
+
/* Pass our mode to the connectors and the CRTC to give them a chance to
* adjust it according to limitations or connector properties, and also
* a chance to reject the mode entirely.
@@ -7495,23 +7627,38 @@ intel_modeset_adjusted_mode(struct drm_crtc *crtc,
if (&encoder->new_crtc->base != crtc)
continue;
+
+ if (encoder->compute_config) {
+ if (!(encoder->compute_config(encoder, pipe_config))) {
+ DRM_DEBUG_KMS("Encoder config failure\n");
+ goto fail;
+ }
+
+ continue;
+ }
+
encoder_funcs = encoder->base.helper_private;
- if (!(encoder_funcs->mode_fixup(&encoder->base, mode,
- adjusted_mode))) {
+ if (!(encoder_funcs->mode_fixup(&encoder->base,
+ &pipe_config->requested_mode,
+ &pipe_config->adjusted_mode))) {
DRM_DEBUG_KMS("Encoder fixup failed\n");
goto fail;
}
}
- if (!(intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) {
+ if (!(intel_crtc_compute_config(crtc, pipe_config))) {
DRM_DEBUG_KMS("CRTC fixup failed\n");
goto fail;
}
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
- return adjusted_mode;
+ pipe_config->dither = pipe_config->pipe_bpp != plane_bpp;
+ DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
+ plane_bpp, pipe_config->pipe_bpp, pipe_config->dither);
+
+ return pipe_config;
fail:
- drm_mode_destroy(dev, adjusted_mode);
+ kfree(pipe_config);
return ERR_PTR(-EINVAL);
}
@@ -7589,22 +7736,25 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
if (crtc->enabled)
*prepare_pipes |= 1 << intel_crtc->pipe;
- /* We only support modeset on one single crtc, hence we need to do that
- * only for the passed in crtc iff we change anything else than just
- * disable crtcs.
- *
- * This is actually not true, to be fully compatible with the old crtc
- * helper we automatically disable _any_ output (i.e. doesn't need to be
- * connected to the crtc we're modesetting on) if it's disconnected.
- * Which is a rather nutty api (since changed the output configuration
- * without userspace's explicit request can lead to confusion), but
- * alas. Hence we currently need to modeset on all pipes we prepare. */
+ /*
+ * For simplicity do a full modeset on any pipe where the output routing
+ * changed. We could be more clever, but that would require us to be
+ * more careful with calling the relevant encoder->mode_set functions.
+ */
if (*prepare_pipes)
*modeset_pipes = *prepare_pipes;
/* ... and mask these out. */
*modeset_pipes &= ~(*disable_pipes);
*prepare_pipes &= ~(*disable_pipes);
+
+ /*
+ * HACK: We don't (yet) fully support global modesets. intel_set_config
+ * obies this rule, but the modeset restore mode of
+ * intel_modeset_setup_hw_state does not.
+ */
+ *modeset_pipes &= 1 << intel_crtc->pipe;
+ *prepare_pipes &= 1 << intel_crtc->pipe;
}
static bool intel_crtc_in_use(struct drm_crtc *crtc)
@@ -7673,12 +7823,29 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
base.head) \
if (mask & (1 <<(intel_crtc)->pipe)) \
+static bool
+intel_pipe_config_compare(struct intel_crtc_config *current_config,
+ struct intel_crtc_config *pipe_config)
+{
+ if (current_config->has_pch_encoder != pipe_config->has_pch_encoder) {
+ DRM_ERROR("mismatch in has_pch_encoder "
+ "(expected %i, found %i)\n",
+ current_config->has_pch_encoder,
+ pipe_config->has_pch_encoder);
+ return false;
+ }
+
+ return true;
+}
+
void
intel_modeset_check_state(struct drm_device *dev)
{
+ drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_crtc *crtc;
struct intel_encoder *encoder;
struct intel_connector *connector;
+ struct intel_crtc_config pipe_config;
list_for_each_entry(connector, &dev->mode_config.connector_list,
base.head) {
@@ -7767,17 +7934,27 @@ intel_modeset_check_state(struct drm_device *dev)
"crtc's computed enabled state doesn't match tracked enabled state "
"(expected %i, found %i)\n", enabled, crtc->base.enabled);
- assert_pipe(dev->dev_private, crtc->pipe, crtc->active);
+ memset(&pipe_config, 0, sizeof(pipe_config));
+ active = dev_priv->display.get_pipe_config(crtc,
+ &pipe_config);
+ WARN(crtc->active != active,
+ "crtc active state doesn't match with hw state "
+ "(expected %i, found %i)\n", crtc->active, active);
+
+ WARN(active &&
+ !intel_pipe_config_compare(&crtc->config, &pipe_config),
+ "pipe state doesn't match!\n");
}
}
-int intel_set_mode(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- int x, int y, struct drm_framebuffer *fb)
+static int __intel_set_mode(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ int x, int y, struct drm_framebuffer *fb)
{
struct drm_device *dev = crtc->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_display_mode *adjusted_mode, *saved_mode, *saved_hwmode;
+ struct drm_display_mode *saved_mode, *saved_hwmode;
+ struct intel_crtc_config *pipe_config = NULL;
struct intel_crtc *intel_crtc;
unsigned disable_pipes, prepare_pipes, modeset_pipes;
int ret = 0;
@@ -7790,12 +7967,6 @@ int intel_set_mode(struct drm_crtc *crtc,
intel_modeset_affected_pipes(crtc, &modeset_pipes,
&prepare_pipes, &disable_pipes);
- DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
- modeset_pipes, prepare_pipes, disable_pipes);
-
- for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
- intel_crtc_disable(&intel_crtc->base);
-
*saved_hwmode = crtc->hwmode;
*saved_mode = crtc->mode;
@@ -7804,15 +7975,22 @@ int intel_set_mode(struct drm_crtc *crtc,
* Hence simply check whether any bit is set in modeset_pipes in all the
* pieces of code that are not yet converted to deal with mutliple crtcs
* changing their mode at the same time. */
- adjusted_mode = NULL;
if (modeset_pipes) {
- adjusted_mode = intel_modeset_adjusted_mode(crtc, mode);
- if (IS_ERR(adjusted_mode)) {
- ret = PTR_ERR(adjusted_mode);
+ pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
+ if (IS_ERR(pipe_config)) {
+ ret = PTR_ERR(pipe_config);
+ pipe_config = NULL;
+
goto out;
}
}
+ DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
+ modeset_pipes, prepare_pipes, disable_pipes);
+
+ for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
+ intel_crtc_disable(&intel_crtc->base);
+
for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
if (intel_crtc->base.enabled)
dev_priv->display.crtc_disable(&intel_crtc->base);
@@ -7821,8 +7999,14 @@ int intel_set_mode(struct drm_crtc *crtc,
/* crtc->mode is already used by the ->mode_set callbacks, hence we need
* to set it here already despite that we pass it down the callchain.
*/
- if (modeset_pipes)
+ if (modeset_pipes) {
+ enum transcoder tmp = to_intel_crtc(crtc)->config.cpu_transcoder;
crtc->mode = *mode;
+ /* mode_set/enable/disable functions rely on a correct pipe
+ * config. */
+ to_intel_crtc(crtc)->config = *pipe_config;
+ to_intel_crtc(crtc)->config.cpu_transcoder = tmp;
+ }
/* Only after disabling all output pipelines that will be changed can we
* update the the output configuration. */
@@ -7836,7 +8020,6 @@ int intel_set_mode(struct drm_crtc *crtc,
*/
for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
ret = intel_crtc_mode_set(&intel_crtc->base,
- mode, adjusted_mode,
x, y, fb);
if (ret)
goto done;
@@ -7848,7 +8031,7 @@ int intel_set_mode(struct drm_crtc *crtc,
if (modeset_pipes) {
/* Store real post-adjustment hardware mode. */
- crtc->hwmode = *adjusted_mode;
+ crtc->hwmode = pipe_config->adjusted_mode;
/* Calculate and store various constants which
* are later needed by vblank and swap-completion
@@ -7859,19 +8042,31 @@ int intel_set_mode(struct drm_crtc *crtc,
/* FIXME: add subpixel order */
done:
- drm_mode_destroy(dev, adjusted_mode);
if (ret && crtc->enabled) {
crtc->hwmode = *saved_hwmode;
crtc->mode = *saved_mode;
- } else {
- intel_modeset_check_state(dev);
}
out:
+ kfree(pipe_config);
kfree(saved_mode);
return ret;
}
+int intel_set_mode(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ int x, int y, struct drm_framebuffer *fb)
+{
+ int ret;
+
+ ret = __intel_set_mode(crtc, mode, x, y, fb);
+
+ if (ret == 0)
+ intel_modeset_check_state(crtc->dev);
+
+ return ret;
+}
+
void intel_crtc_restore_mode(struct drm_crtc *crtc)
{
intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb);
@@ -7959,10 +8154,8 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
config->mode_changed = true;
} else if (set->fb == NULL) {
config->mode_changed = true;
- } else if (set->fb->depth != set->crtc->fb->depth) {
- config->mode_changed = true;
- } else if (set->fb->bits_per_pixel !=
- set->crtc->fb->bits_per_pixel) {
+ } else if (set->fb->pixel_format !=
+ set->crtc->fb->pixel_format) {
config->mode_changed = true;
} else
config->fb_changed = true;
@@ -8145,6 +8338,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
goto fail;
}
} else if (config->fb_changed) {
+ intel_crtc_wait_for_pending_flips(set->crtc);
+
ret = intel_pipe_set_base(set->crtc,
set->x, set->y, set->fb);
}
@@ -8221,7 +8416,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
/* Swap pipes & planes for FBC on pre-965 */
intel_crtc->pipe = pipe;
intel_crtc->plane = pipe;
- intel_crtc->cpu_transcoder = pipe;
+ intel_crtc->config.cpu_transcoder = pipe;
if (IS_MOBILE(dev) && IS_GEN3(dev)) {
DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
intel_crtc->plane = !pipe;
@@ -8232,8 +8427,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
- intel_crtc->bpp = 24; /* default for pre-Ironlake */
-
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
}
@@ -8314,7 +8507,7 @@ static void intel_setup_outputs(struct drm_device *dev)
I915_WRITE(PFIT_CONTROL, 0);
}
- if (!(HAS_DDI(dev) && (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES)))
+ if (!IS_ULT(dev))
intel_crt_init(dev);
if (HAS_DDI(dev)) {
@@ -8343,20 +8536,20 @@ static void intel_setup_outputs(struct drm_device *dev)
if (has_edp_a(dev))
intel_dp_init(dev, DP_A, PORT_A);
- if (I915_READ(HDMIB) & PORT_DETECTED) {
+ if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) {
/* PCH SDVOB multiplex with HDMIB */
found = intel_sdvo_init(dev, PCH_SDVOB, true);
if (!found)
- intel_hdmi_init(dev, HDMIB, PORT_B);
+ intel_hdmi_init(dev, PCH_HDMIB, PORT_B);
if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
intel_dp_init(dev, PCH_DP_B, PORT_B);
}
- if (I915_READ(HDMIC) & PORT_DETECTED)
- intel_hdmi_init(dev, HDMIC, PORT_C);
+ if (I915_READ(PCH_HDMIC) & SDVO_DETECTED)
+ intel_hdmi_init(dev, PCH_HDMIC, PORT_C);
- if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED)
- intel_hdmi_init(dev, HDMID, PORT_D);
+ if (!dpd_is_edp && I915_READ(PCH_HDMID) & SDVO_DETECTED)
+ intel_hdmi_init(dev, PCH_HDMID, PORT_D);
if (I915_READ(PCH_DP_C) & DP_DETECTED)
intel_dp_init(dev, PCH_DP_C, PORT_C);
@@ -8368,24 +8561,21 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED)
intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C);
- if (I915_READ(VLV_DISPLAY_BASE + SDVOB) & PORT_DETECTED) {
- intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOB, PORT_B);
+ if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) {
+ intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB,
+ PORT_B);
if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED)
intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B);
}
-
- if (I915_READ(VLV_DISPLAY_BASE + SDVOC) & PORT_DETECTED)
- intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOC, PORT_C);
-
} else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
bool found = false;
- if (I915_READ(SDVOB) & SDVO_DETECTED) {
+ if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOB\n");
- found = intel_sdvo_init(dev, SDVOB, true);
+ found = intel_sdvo_init(dev, GEN3_SDVOB, true);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
- intel_hdmi_init(dev, SDVOB, PORT_B);
+ intel_hdmi_init(dev, GEN4_HDMIB, PORT_B);
}
if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
@@ -8396,16 +8586,16 @@ static void intel_setup_outputs(struct drm_device *dev)
/* Before G4X SDVOC doesn't have its own detect register */
- if (I915_READ(SDVOB) & SDVO_DETECTED) {
+ if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOC\n");
- found = intel_sdvo_init(dev, SDVOC, false);
+ found = intel_sdvo_init(dev, GEN3_SDVOC, false);
}
- if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
+ if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) {
if (SUPPORTS_INTEGRATED_HDMI(dev)) {
DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
- intel_hdmi_init(dev, SDVOC, PORT_C);
+ intel_hdmi_init(dev, GEN4_HDMIC, PORT_C);
}
if (SUPPORTS_INTEGRATED_DP(dev)) {
DRM_DEBUG_KMS("probing DP_C\n");
@@ -8572,20 +8762,22 @@ static void intel_init_display(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- /* We always want a DPMS function */
if (HAS_DDI(dev)) {
+ dev_priv->display.get_pipe_config = haswell_get_pipe_config;
dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
dev_priv->display.crtc_enable = haswell_crtc_enable;
dev_priv->display.crtc_disable = haswell_crtc_disable;
dev_priv->display.off = haswell_crtc_off;
dev_priv->display.update_plane = ironlake_update_plane;
} else if (HAS_PCH_SPLIT(dev)) {
+ dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
dev_priv->display.crtc_enable = ironlake_crtc_enable;
dev_priv->display.crtc_disable = ironlake_crtc_disable;
dev_priv->display.off = ironlake_crtc_off;
dev_priv->display.update_plane = ironlake_update_plane;
} else {
+ dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
dev_priv->display.crtc_enable = i9xx_crtc_enable;
dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -8828,7 +9020,7 @@ void intel_modeset_init_hw(struct drm_device *dev)
void intel_modeset_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int i, ret;
+ int i, j, ret;
drm_mode_config_init(dev);
@@ -8844,6 +9036,9 @@ void intel_modeset_init(struct drm_device *dev)
intel_init_pm(dev);
+ if (INTEL_INFO(dev)->num_pipes == 0)
+ return;
+
intel_init_display(dev);
if (IS_GEN2(dev)) {
@@ -8859,13 +9054,17 @@ void intel_modeset_init(struct drm_device *dev)
dev->mode_config.fb_base = dev_priv->gtt.mappable_base;
DRM_DEBUG_KMS("%d display pipe%s available.\n",
- dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : "");
+ INTEL_INFO(dev)->num_pipes,
+ INTEL_INFO(dev)->num_pipes > 1 ? "s" : "");
- for (i = 0; i < dev_priv->num_pipe; i++) {
+ for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
intel_crtc_init(dev, i);
- ret = intel_plane_init(dev, i);
- if (ret)
- DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret);
+ for (j = 0; j < dev_priv->num_plane; j++) {
+ ret = intel_plane_init(dev, i, j);
+ if (ret)
+ DRM_DEBUG_KMS("pipe %d plane %d init failed: %d\n",
+ i, j, ret);
+ }
}
intel_cpu_pll_init(dev);
@@ -8918,10 +9117,11 @@ static void intel_enable_pipe_a(struct drm_device *dev)
static bool
intel_check_plane_mapping(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg, val;
- if (dev_priv->num_pipe == 1)
+ if (INTEL_INFO(dev)->num_pipes == 1)
return true;
reg = DSPCNTR(!crtc->plane);
@@ -8941,7 +9141,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
u32 reg;
/* Clear any frame start delays used for debugging left by the BIOS */
- reg = PIPECONF(crtc->cpu_transcoder);
+ reg = PIPECONF(crtc->config.cpu_transcoder);
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
/* We need to sanitize the plane -> pipe mapping first because this will
@@ -9077,6 +9277,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe;
u32 tmp;
+ struct drm_plane *plane;
struct intel_crtc *crtc;
struct intel_encoder *encoder;
struct intel_connector *connector;
@@ -9096,24 +9297,32 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
case TRANS_DDI_EDP_INPUT_C_ONOFF:
pipe = PIPE_C;
break;
+ default:
+ /* A bogus value has been programmed, disable
+ * the transcoder */
+ WARN(1, "Bogus eDP source %08x\n", tmp);
+ intel_ddi_disable_transcoder_func(dev_priv,
+ TRANSCODER_EDP);
+ goto setup_pipes;
}
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
- crtc->cpu_transcoder = TRANSCODER_EDP;
+ crtc->config.cpu_transcoder = TRANSCODER_EDP;
DRM_DEBUG_KMS("Pipe %c using transcoder EDP\n",
pipe_name(pipe));
}
}
- for_each_pipe(pipe) {
- crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+setup_pipes:
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+ base.head) {
+ enum transcoder tmp = crtc->config.cpu_transcoder;
+ memset(&crtc->config, 0, sizeof(crtc->config));
+ crtc->config.cpu_transcoder = tmp;
- tmp = I915_READ(PIPECONF(crtc->cpu_transcoder));
- if (tmp & PIPECONF_ENABLE)
- crtc->active = true;
- else
- crtc->active = false;
+ crtc->active = dev_priv->display.get_pipe_config(crtc,
+ &crtc->config);
crtc->base.enabled = crtc->active;
@@ -9172,9 +9381,19 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
}
if (force_restore) {
+ /*
+ * We need to use raw interfaces for restoring state to avoid
+ * checking (bogus) intermediate states.
+ */
for_each_pipe(pipe) {
- intel_crtc_restore_mode(dev_priv->pipe_to_crtc_mapping[pipe]);
+ struct drm_crtc *crtc =
+ dev_priv->pipe_to_crtc_mapping[pipe];
+
+ __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
+ crtc->fb);
}
+ list_for_each_entry(plane, &dev->mode_config.plane_list, head)
+ intel_plane_restore(plane);
i915_redisable_vga(dev);
} else {
@@ -9236,6 +9455,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
/* flush any delayed tasks or pending work */
flush_scheduled_work();
+ /* destroy backlight, if any, before the connectors */
+ intel_panel_destroy_backlight(dev);
+
drm_mode_config_cleanup(dev);
intel_cleanup_overlay(dev);
@@ -9323,15 +9545,24 @@ intel_display_capture_error_state(struct drm_device *dev)
for_each_pipe(i) {
cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i);
- error->cursor[i].control = I915_READ(CURCNTR(i));
- error->cursor[i].position = I915_READ(CURPOS(i));
- error->cursor[i].base = I915_READ(CURBASE(i));
+ if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) {
+ error->cursor[i].control = I915_READ(CURCNTR(i));
+ error->cursor[i].position = I915_READ(CURPOS(i));
+ error->cursor[i].base = I915_READ(CURBASE(i));
+ } else {
+ error->cursor[i].control = I915_READ(CURCNTR_IVB(i));
+ error->cursor[i].position = I915_READ(CURPOS_IVB(i));
+ error->cursor[i].base = I915_READ(CURBASE_IVB(i));
+ }
error->plane[i].control = I915_READ(DSPCNTR(i));
error->plane[i].stride = I915_READ(DSPSTRIDE(i));
- error->plane[i].size = I915_READ(DSPSIZE(i));
- error->plane[i].pos = I915_READ(DSPPOS(i));
- error->plane[i].addr = I915_READ(DSPADDR(i));
+ if (INTEL_INFO(dev)->gen <= 3) {
+ error->plane[i].size = I915_READ(DSPSIZE(i));
+ error->plane[i].pos = I915_READ(DSPPOS(i));
+ }
+ if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
+ error->plane[i].addr = I915_READ(DSPADDR(i));
if (INTEL_INFO(dev)->gen >= 4) {
error->plane[i].surface = I915_READ(DSPSURF(i));
error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i));
@@ -9355,10 +9586,9 @@ intel_display_print_error_state(struct seq_file *m,
struct drm_device *dev,
struct intel_display_error_state *error)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
int i;
- seq_printf(m, "Num Pipes: %d\n", dev_priv->num_pipe);
+ seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
for_each_pipe(i) {
seq_printf(m, "Pipe [%d]:\n", i);
seq_printf(m, " CONF: %08x\n", error->pipe[i].conf);
@@ -9373,9 +9603,12 @@ intel_display_print_error_state(struct seq_file *m,
seq_printf(m, "Plane [%d]:\n", i);
seq_printf(m, " CNTR: %08x\n", error->plane[i].control);
seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride);
- seq_printf(m, " SIZE: %08x\n", error->plane[i].size);
- seq_printf(m, " POS: %08x\n", error->plane[i].pos);
- seq_printf(m, " ADDR: %08x\n", error->plane[i].addr);
+ if (INTEL_INFO(dev)->gen <= 3) {
+ seq_printf(m, " SIZE: %08x\n", error->plane[i].size);
+ seq_printf(m, " POS: %08x\n", error->plane[i].pos);
+ }
+ if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
+ seq_printf(m, " ADDR: %08x\n", error->plane[i].addr);
if (INTEL_INFO(dev)->gen >= 4) {
seq_printf(m, " SURF: %08x\n", error->plane[i].surface);
seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c3f5bd8a507..fb2fbc1e08b 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -109,29 +109,6 @@ bool intel_encoder_is_pch_edp(struct drm_encoder *encoder)
static void intel_dp_link_down(struct intel_dp *intel_dp);
-void
-intel_edp_link_config(struct intel_encoder *intel_encoder,
- int *lane_num, int *link_bw)
-{
- struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
-
- *lane_num = intel_dp->lane_count;
- *link_bw = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
-}
-
-int
-intel_edp_target_clock(struct intel_encoder *intel_encoder,
- struct drm_display_mode *mode)
-{
- struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
- struct intel_connector *intel_connector = intel_dp->attached_connector;
-
- if (intel_connector->panel.fixed_mode)
- return intel_connector->panel.fixed_mode->clock;
- else
- return mode->clock;
-}
-
static int
intel_dp_max_link_bw(struct intel_dp *intel_dp)
{
@@ -177,34 +154,6 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
return (max_link_clock * max_lanes * 8) / 10;
}
-static bool
-intel_dp_adjust_dithering(struct intel_dp *intel_dp,
- struct drm_display_mode *mode,
- bool adjust_mode)
-{
- int max_link_clock =
- drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp));
- int max_lanes = drm_dp_max_lane_count(intel_dp->dpcd);
- int max_rate, mode_rate;
-
- mode_rate = intel_dp_link_required(mode->clock, 24);
- max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
-
- if (mode_rate > max_rate) {
- mode_rate = intel_dp_link_required(mode->clock, 18);
- if (mode_rate > max_rate)
- return false;
-
- if (adjust_mode)
- mode->private_flags
- |= INTEL_MODE_DP_FORCE_6BPC;
-
- return true;
- }
-
- return true;
-}
-
static int
intel_dp_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
@@ -212,6 +161,8 @@ intel_dp_mode_valid(struct drm_connector *connector,
struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+ int target_clock = mode->clock;
+ int max_rate, mode_rate, max_lanes, max_link_clock;
if (is_edp(intel_dp) && fixed_mode) {
if (mode->hdisplay > fixed_mode->hdisplay)
@@ -219,9 +170,17 @@ intel_dp_mode_valid(struct drm_connector *connector,
if (mode->vdisplay > fixed_mode->vdisplay)
return MODE_PANEL;
+
+ target_clock = fixed_mode->clock;
}
- if (!intel_dp_adjust_dithering(intel_dp, mode, false))
+ max_link_clock = drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp));
+ max_lanes = drm_dp_max_lane_count(intel_dp->dpcd);
+
+ max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
+ mode_rate = intel_dp_link_required(target_clock, 18);
+
+ if (mode_rate > max_rate)
return MODE_CLOCK_HIGH;
if (mode->clock < 10000)
@@ -294,16 +253,20 @@ static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 pp_stat_reg;
- return (I915_READ(PCH_PP_STATUS) & PP_ON) != 0;
+ pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS;
+ return (I915_READ(pp_stat_reg) & PP_ON) != 0;
}
static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 pp_ctrl_reg;
- return (I915_READ(PCH_PP_CONTROL) & EDP_FORCE_VDD) != 0;
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+ return (I915_READ(pp_ctrl_reg) & EDP_FORCE_VDD) != 0;
}
static void
@@ -311,14 +274,19 @@ intel_dp_check_edp(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 pp_stat_reg, pp_ctrl_reg;
if (!is_edp(intel_dp))
return;
+
+ pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS;
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+
if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) {
WARN(1, "eDP powered off while attempting aux channel communication.\n");
DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n",
- I915_READ(PCH_PP_STATUS),
- I915_READ(PCH_PP_CONTROL));
+ I915_READ(pp_stat_reg),
+ I915_READ(pp_ctrl_reg));
}
}
@@ -328,29 +296,10 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t ch_ctl = intel_dp->output_reg + 0x10;
+ uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
uint32_t status;
bool done;
- if (IS_HASWELL(dev)) {
- switch (intel_dig_port->port) {
- case PORT_A:
- ch_ctl = DPA_AUX_CH_CTL;
- break;
- case PORT_B:
- ch_ctl = PCH_DPB_AUX_CH_CTL;
- break;
- case PORT_C:
- ch_ctl = PCH_DPC_AUX_CH_CTL;
- break;
- case PORT_D:
- ch_ctl = PCH_DPD_AUX_CH_CTL;
- break;
- default:
- BUG();
- }
- }
-
#define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
if (has_aux_irq)
done = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
@@ -370,11 +319,10 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
uint8_t *send, int send_bytes,
uint8_t *recv, int recv_size)
{
- uint32_t output_reg = intel_dp->output_reg;
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t ch_ctl = output_reg + 0x10;
+ uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
uint32_t ch_data = ch_ctl + 4;
int i, ret, recv_bytes;
uint32_t status;
@@ -388,29 +336,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
*/
pm_qos_update_request(&dev_priv->pm_qos, 0);
- if (IS_HASWELL(dev)) {
- switch (intel_dig_port->port) {
- case PORT_A:
- ch_ctl = DPA_AUX_CH_CTL;
- ch_data = DPA_AUX_CH_DATA1;
- break;
- case PORT_B:
- ch_ctl = PCH_DPB_AUX_CH_CTL;
- ch_data = PCH_DPB_AUX_CH_DATA1;
- break;
- case PORT_C:
- ch_ctl = PCH_DPC_AUX_CH_CTL;
- ch_data = PCH_DPC_AUX_CH_DATA1;
- break;
- case PORT_D:
- ch_ctl = PCH_DPD_AUX_CH_CTL;
- ch_data = PCH_DPD_AUX_CH_DATA1;
- break;
- default:
- BUG();
- }
- }
-
intel_dp_check_edp(intel_dp);
/* The clock divider is based off the hrawclk,
* and would like to run at 2MHz. So, take the
@@ -428,10 +353,14 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
else
aux_clock_divider = 225; /* eDP input clock at 450Mhz */
- } else if (HAS_PCH_SPLIT(dev))
+ } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
+ /* Workaround for non-ULT HSW */
+ aux_clock_divider = 74;
+ } else if (HAS_PCH_SPLIT(dev)) {
aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
- else
+ } else {
aux_clock_divider = intel_hrawclk(dev) / 2;
+ }
if (IS_GEN6(dev))
precharge = 3;
@@ -732,18 +661,26 @@ intel_dp_i2c_init(struct intel_dp *intel_dp,
}
bool
-intel_dp_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+intel_dp_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
{
- struct drm_device *dev = encoder->dev;
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *mode = &pipe_config->requested_mode;
+ struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
struct intel_connector *intel_connector = intel_dp->attached_connector;
int lane_count, clock;
int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
int bpp, mode_rate;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
+ int target_clock, link_avail, link_clock;
+
+ if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && !is_cpu_edp(intel_dp))
+ pipe_config->has_pch_encoder = true;
+
+ pipe_config->has_dp_encoder = true;
if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
@@ -752,6 +689,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder,
intel_connector->panel.fitting_mode,
mode, adjusted_mode);
}
+ /* We need to take the panel's fixed mode into account. */
+ target_clock = adjusted_mode->clock;
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
return false;
@@ -760,11 +699,28 @@ intel_dp_mode_fixup(struct drm_encoder *encoder,
"max bw %02x pixel clock %iKHz\n",
max_lane_count, bws[max_clock], adjusted_mode->clock);
- if (!intel_dp_adjust_dithering(intel_dp, adjusted_mode, true))
- return false;
+ /* Walk through all bpp values. Luckily they're all nicely spaced with 2
+ * bpc in between. */
+ bpp = min_t(int, 8*3, pipe_config->pipe_bpp);
+ for (; bpp >= 6*3; bpp -= 2*3) {
+ mode_rate = intel_dp_link_required(target_clock, bpp);
+
+ for (clock = 0; clock <= max_clock; clock++) {
+ for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+ link_clock = drm_dp_bw_code_to_link_rate(bws[clock]);
+ link_avail = intel_dp_max_data_rate(link_clock,
+ lane_count);
+
+ if (mode_rate <= link_avail) {
+ goto found;
+ }
+ }
+ }
+ }
- bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24;
+ return false;
+found:
if (intel_dp->color_range_auto) {
/*
* See:
@@ -778,104 +734,38 @@ intel_dp_mode_fixup(struct drm_encoder *encoder,
}
if (intel_dp->color_range)
- adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE;
-
- mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp);
-
- for (clock = 0; clock <= max_clock; clock++) {
- for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
- int link_bw_clock =
- drm_dp_bw_code_to_link_rate(bws[clock]);
- int link_avail = intel_dp_max_data_rate(link_bw_clock,
- lane_count);
-
- if (mode_rate <= link_avail) {
- intel_dp->link_bw = bws[clock];
- intel_dp->lane_count = lane_count;
- adjusted_mode->clock = link_bw_clock;
- DRM_DEBUG_KMS("DP link bw %02x lane "
- "count %d clock %d bpp %d\n",
- intel_dp->link_bw, intel_dp->lane_count,
- adjusted_mode->clock, bpp);
- DRM_DEBUG_KMS("DP link bw required %i available %i\n",
- mode_rate, link_avail);
- return true;
- }
- }
- }
-
- return false;
-}
+ pipe_config->limited_color_range = true;
-void
-intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct drm_device *dev = crtc->dev;
- struct intel_encoder *intel_encoder;
- struct intel_dp *intel_dp;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int lane_count = 4;
- struct intel_link_m_n m_n;
- int pipe = intel_crtc->pipe;
- enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
- int target_clock;
+ intel_dp->link_bw = bws[clock];
+ intel_dp->lane_count = lane_count;
+ adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
+ pipe_config->pixel_target_clock = target_clock;
- /*
- * Find the lane count in the intel_encoder private
- */
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
- intel_dp = enc_to_intel_dp(&intel_encoder->base);
+ DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
+ intel_dp->link_bw, intel_dp->lane_count,
+ adjusted_mode->clock, bpp);
+ DRM_DEBUG_KMS("DP link bw required %i available %i\n",
+ mode_rate, link_avail);
- if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
- intel_encoder->type == INTEL_OUTPUT_EDP)
- {
- lane_count = intel_dp->lane_count;
- break;
- }
- }
-
- target_clock = mode->clock;
- for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
- if (intel_encoder->type == INTEL_OUTPUT_EDP) {
- target_clock = intel_edp_target_clock(intel_encoder,
- mode);
- break;
- }
- }
+ intel_link_compute_m_n(bpp, lane_count,
+ target_clock, adjusted_mode->clock,
+ &pipe_config->dp_m_n);
/*
- * Compute the GMCH and Link ratios. The '3' here is
- * the number of bytes_per_pixel post-LUT, which we always
- * set up for 8-bits of R/G/B, or 3 bytes total.
+ * XXX: We have a strange regression where using the vbt edp bpp value
+ * for the link bw computation results in black screens, the panel only
+ * works when we do the computation at the usual 24bpp (but still
+ * requires us to use 18bpp). Until that's fully debugged, stay
+ * bug-for-bug compatible with the old code.
*/
- intel_link_compute_m_n(intel_crtc->bpp, lane_count,
- target_clock, adjusted_mode->clock, &m_n);
-
- if (IS_HASWELL(dev)) {
- I915_WRITE(PIPE_DATA_M1(cpu_transcoder),
- TU_SIZE(m_n.tu) | m_n.gmch_m);
- I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n);
- I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m);
- I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n);
- } else if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
- I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n);
- I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m);
- I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n);
- } else if (IS_VALLEYVIEW(dev)) {
- I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
- I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
- I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
- I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
- } else {
- I915_WRITE(PIPE_GMCH_DATA_M(pipe),
- TU_SIZE(m_n.tu) | m_n.gmch_m);
- I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n);
- I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m);
- I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n);
+ if (is_edp(intel_dp) && dev_priv->edp.bpp) {
+ DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n",
+ bpp, dev_priv->edp.bpp);
+ bpp = min_t(int, bpp, dev_priv->edp.bpp);
}
+ pipe_config->pipe_bpp = bpp;
+
+ return true;
}
void intel_dp_init_link_config(struct intel_dp *intel_dp)
@@ -994,7 +884,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
else
intel_dp->DP |= DP_PLL_FREQ_270MHZ;
} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
- if (!HAS_PCH_SPLIT(dev))
+ if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev))
intel_dp->DP |= intel_dp->color_range;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
@@ -1009,7 +899,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (intel_crtc->pipe == 1)
intel_dp->DP |= DP_PIPEB_SELECT;
- if (is_cpu_edp(intel_dp)) {
+ if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
/* don't miss out required setting for eDP */
if (adjusted_mode->clock < 200000)
intel_dp->DP |= DP_PLL_FREQ_160MHZ;
@@ -1020,7 +910,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
}
- if (is_cpu_edp(intel_dp))
+ if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev))
ironlake_set_pll_edp(crtc, adjusted_mode->clock);
}
@@ -1039,16 +929,20 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp,
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 pp_stat_reg, pp_ctrl_reg;
+
+ pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS;
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n",
- mask, value,
- I915_READ(PCH_PP_STATUS),
- I915_READ(PCH_PP_CONTROL));
+ mask, value,
+ I915_READ(pp_stat_reg),
+ I915_READ(pp_ctrl_reg));
- if (_wait_for((I915_READ(PCH_PP_STATUS) & mask) == value, 5000, 10)) {
+ if (_wait_for((I915_READ(pp_stat_reg) & mask) == value, 5000, 10)) {
DRM_ERROR("Panel status timeout: status %08x control %08x\n",
- I915_READ(PCH_PP_STATUS),
- I915_READ(PCH_PP_CONTROL));
+ I915_READ(pp_stat_reg),
+ I915_READ(pp_ctrl_reg));
}
}
@@ -1075,9 +969,15 @@ static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp)
* is locked
*/
-static u32 ironlake_get_pp_control(struct drm_i915_private *dev_priv)
+static u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
{
- u32 control = I915_READ(PCH_PP_CONTROL);
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 control;
+ u32 pp_ctrl_reg;
+
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+ control = I915_READ(pp_ctrl_reg);
control &= ~PANEL_UNLOCK_MASK;
control |= PANEL_UNLOCK_REGS;
@@ -1089,6 +989,7 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp;
+ u32 pp_stat_reg, pp_ctrl_reg;
if (!is_edp(intel_dp))
return;
@@ -1107,13 +1008,16 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
if (!ironlake_edp_have_panel_power(intel_dp))
ironlake_wait_panel_power_cycle(intel_dp);
- pp = ironlake_get_pp_control(dev_priv);
+ pp = ironlake_get_pp_control(intel_dp);
pp |= EDP_FORCE_VDD;
- I915_WRITE(PCH_PP_CONTROL, pp);
- POSTING_READ(PCH_PP_CONTROL);
- DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n",
- I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL));
+ pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS;
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+
+ I915_WRITE(pp_ctrl_reg, pp);
+ POSTING_READ(pp_ctrl_reg);
+ DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
/*
* If the panel wasn't on, delay before accessing aux channel
*/
@@ -1128,19 +1032,23 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp;
+ u32 pp_stat_reg, pp_ctrl_reg;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
- pp = ironlake_get_pp_control(dev_priv);
+ pp = ironlake_get_pp_control(intel_dp);
pp &= ~EDP_FORCE_VDD;
- I915_WRITE(PCH_PP_CONTROL, pp);
- POSTING_READ(PCH_PP_CONTROL);
- /* Make sure sequencer is idle before allowing subsequent activity */
- DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n",
- I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL));
+ pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS;
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+
+ I915_WRITE(pp_ctrl_reg, pp);
+ POSTING_READ(pp_ctrl_reg);
+ /* Make sure sequencer is idle before allowing subsequent activity */
+ DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
msleep(intel_dp->panel_power_down_delay);
}
}
@@ -1184,6 +1092,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp;
+ u32 pp_ctrl_reg;
if (!is_edp(intel_dp))
return;
@@ -1197,7 +1106,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
ironlake_wait_panel_power_cycle(intel_dp);
- pp = ironlake_get_pp_control(dev_priv);
+ pp = ironlake_get_pp_control(intel_dp);
if (IS_GEN5(dev)) {
/* ILK workaround: disable reset around power sequence */
pp &= ~PANEL_POWER_RESET;
@@ -1209,8 +1118,10 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
if (!IS_GEN5(dev))
pp |= PANEL_POWER_RESET;
- I915_WRITE(PCH_PP_CONTROL, pp);
- POSTING_READ(PCH_PP_CONTROL);
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+
+ I915_WRITE(pp_ctrl_reg, pp);
+ POSTING_READ(pp_ctrl_reg);
ironlake_wait_panel_on(intel_dp);
@@ -1226,6 +1137,7 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp;
+ u32 pp_ctrl_reg;
if (!is_edp(intel_dp))
return;
@@ -1234,12 +1146,15 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
- pp = ironlake_get_pp_control(dev_priv);
+ pp = ironlake_get_pp_control(intel_dp);
/* We need to switch off panel power _and_ force vdd, for otherwise some
* panels get very unhappy and cease to work. */
pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
- I915_WRITE(PCH_PP_CONTROL, pp);
- POSTING_READ(PCH_PP_CONTROL);
+
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+
+ I915_WRITE(pp_ctrl_reg, pp);
+ POSTING_READ(pp_ctrl_reg);
intel_dp->want_panel_vdd = false;
@@ -1253,6 +1168,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = to_intel_crtc(intel_dig_port->base.base.crtc)->pipe;
u32 pp;
+ u32 pp_ctrl_reg;
if (!is_edp(intel_dp))
return;
@@ -1265,10 +1181,13 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
* allowing it to appear.
*/
msleep(intel_dp->backlight_on_delay);
- pp = ironlake_get_pp_control(dev_priv);
+ pp = ironlake_get_pp_control(intel_dp);
pp |= EDP_BLC_ENABLE;
- I915_WRITE(PCH_PP_CONTROL, pp);
- POSTING_READ(PCH_PP_CONTROL);
+
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+
+ I915_WRITE(pp_ctrl_reg, pp);
+ POSTING_READ(pp_ctrl_reg);
intel_panel_enable_backlight(dev, pipe);
}
@@ -1278,6 +1197,7 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp;
+ u32 pp_ctrl_reg;
if (!is_edp(intel_dp))
return;
@@ -1285,10 +1205,13 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
intel_panel_disable_backlight(dev);
DRM_DEBUG_KMS("\n");
- pp = ironlake_get_pp_control(dev_priv);
+ pp = ironlake_get_pp_control(intel_dp);
pp &= ~EDP_BLC_ENABLE;
- I915_WRITE(PCH_PP_CONTROL, pp);
- POSTING_READ(PCH_PP_CONTROL);
+
+ pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL;
+
+ I915_WRITE(pp_ctrl_reg, pp);
+ POSTING_READ(pp_ctrl_reg);
msleep(intel_dp->backlight_off_delay);
}
@@ -1384,7 +1307,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
if (!(tmp & DP_PORT_EN))
return false;
- if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) {
+ if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
*pipe = PORT_TO_PIPE_CPT(tmp);
} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
*pipe = PORT_TO_PIPE(tmp);
@@ -1441,10 +1364,12 @@ static void intel_disable_dp(struct intel_encoder *encoder)
static void intel_post_disable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ struct drm_device *dev = encoder->base.dev;
if (is_cpu_edp(intel_dp)) {
intel_dp_link_down(intel_dp);
- ironlake_edp_pll_off(intel_dp);
+ if (!IS_VALLEYVIEW(dev))
+ ironlake_edp_pll_off(intel_dp);
}
}
@@ -1470,8 +1395,9 @@ static void intel_enable_dp(struct intel_encoder *encoder)
static void intel_pre_enable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ struct drm_device *dev = encoder->base.dev;
- if (is_cpu_edp(intel_dp))
+ if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev))
ironlake_edp_pll_on(intel_dp);
}
@@ -1548,7 +1474,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
- if (IS_HASWELL(dev)) {
+ if (HAS_DDI(dev)) {
switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
case DP_TRAIN_VOLTAGE_SWING_400:
return DP_TRAIN_PRE_EMPHASIS_9_5;
@@ -1756,7 +1682,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
uint32_t signal_levels, mask;
uint8_t train_set = intel_dp->train_set[0];
- if (IS_HASWELL(dev)) {
+ if (HAS_DDI(dev)) {
signal_levels = intel_hsw_signal_levels(train_set);
mask = DDI_BUF_EMP_MASK;
} else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
@@ -1787,7 +1713,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
int ret;
uint32_t temp;
- if (IS_HASWELL(dev)) {
+ if (HAS_DDI(dev)) {
temp = I915_READ(DP_TP_CTL(port));
if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
@@ -2311,6 +2237,16 @@ g4x_dp_detect(struct intel_dp *intel_dp)
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
uint32_t bit;
+ /* Can't disconnect eDP, but you can close the lid... */
+ if (is_edp(intel_dp)) {
+ enum drm_connector_status status;
+
+ status = intel_panel_detect(dev);
+ if (status == connector_status_unknown)
+ status = connector_status_connected;
+ return status;
+ }
+
switch (intel_dig_port->port) {
case PORT_B:
bit = PORTB_HOTPLUG_LIVE_STATUS;
@@ -2492,6 +2428,9 @@ intel_dp_set_property(struct drm_connector *connector,
}
if (property == dev_priv->broadcast_rgb_property) {
+ bool old_auto = intel_dp->color_range_auto;
+ uint32_t old_range = intel_dp->color_range;
+
switch (val) {
case INTEL_BROADCAST_RGB_AUTO:
intel_dp->color_range_auto = true;
@@ -2507,6 +2446,11 @@ intel_dp_set_property(struct drm_connector *connector,
default:
return -EINVAL;
}
+
+ if (old_auto == intel_dp->color_range_auto &&
+ old_range == intel_dp->color_range)
+ return 0;
+
goto done;
}
@@ -2538,17 +2482,14 @@ done:
static void
intel_dp_destroy(struct drm_connector *connector)
{
- struct drm_device *dev = connector->dev;
struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_connector *intel_connector = to_intel_connector(connector);
if (!IS_ERR_OR_NULL(intel_connector->edid))
kfree(intel_connector->edid);
- if (is_edp(intel_dp)) {
- intel_panel_destroy_backlight(dev);
+ if (is_edp(intel_dp))
intel_panel_fini(&intel_connector->panel);
- }
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
@@ -2573,7 +2514,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
}
static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
- .mode_fixup = intel_dp_mode_fixup,
.mode_set = intel_dp_mode_set,
};
@@ -2669,15 +2609,28 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
struct edp_power_seq cur, vbt, spec, final;
u32 pp_on, pp_off, pp_div, pp;
+ int pp_control_reg, pp_on_reg, pp_off_reg, pp_div_reg;
+
+ if (HAS_PCH_SPLIT(dev)) {
+ pp_control_reg = PCH_PP_CONTROL;
+ pp_on_reg = PCH_PP_ON_DELAYS;
+ pp_off_reg = PCH_PP_OFF_DELAYS;
+ pp_div_reg = PCH_PP_DIVISOR;
+ } else {
+ pp_control_reg = PIPEA_PP_CONTROL;
+ pp_on_reg = PIPEA_PP_ON_DELAYS;
+ pp_off_reg = PIPEA_PP_OFF_DELAYS;
+ pp_div_reg = PIPEA_PP_DIVISOR;
+ }
/* Workaround: Need to write PP_CONTROL with the unlock key as
* the very first thing. */
- pp = ironlake_get_pp_control(dev_priv);
- I915_WRITE(PCH_PP_CONTROL, pp);
+ pp = ironlake_get_pp_control(intel_dp);
+ I915_WRITE(pp_control_reg, pp);
- pp_on = I915_READ(PCH_PP_ON_DELAYS);
- pp_off = I915_READ(PCH_PP_OFF_DELAYS);
- pp_div = I915_READ(PCH_PP_DIVISOR);
+ pp_on = I915_READ(pp_on_reg);
+ pp_off = I915_READ(pp_off_reg);
+ pp_div = I915_READ(pp_div_reg);
/* Pull timing values out of registers */
cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >>
@@ -2752,7 +2705,22 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
struct edp_power_seq *seq)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 pp_on, pp_off, pp_div;
+ u32 pp_on, pp_off, pp_div, port_sel = 0;
+ int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev);
+ int pp_on_reg, pp_off_reg, pp_div_reg;
+
+ if (HAS_PCH_SPLIT(dev)) {
+ pp_on_reg = PCH_PP_ON_DELAYS;
+ pp_off_reg = PCH_PP_OFF_DELAYS;
+ pp_div_reg = PCH_PP_DIVISOR;
+ } else {
+ pp_on_reg = PIPEA_PP_ON_DELAYS;
+ pp_off_reg = PIPEA_PP_OFF_DELAYS;
+ pp_div_reg = PIPEA_PP_DIVISOR;
+ }
+
+ if (IS_VALLEYVIEW(dev))
+ port_sel = I915_READ(pp_on_reg) & 0xc0000000;
/* And finally store the new values in the power sequencer. */
pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
@@ -2761,8 +2729,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
(seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT);
/* Compute the divisor for the pp clock, simply match the Bspec
* formula. */
- pp_div = ((100 * intel_pch_rawclk(dev))/2 - 1)
- << PP_REFERENCE_DIVIDER_SHIFT;
+ pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT;
pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000)
<< PANEL_POWER_CYCLE_DELAY_SHIFT);
@@ -2770,19 +2737,21 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
* power sequencer any more. */
if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
if (is_cpu_edp(intel_dp))
- pp_on |= PANEL_POWER_PORT_DP_A;
+ port_sel = PANEL_POWER_PORT_DP_A;
else
- pp_on |= PANEL_POWER_PORT_DP_D;
+ port_sel = PANEL_POWER_PORT_DP_D;
}
- I915_WRITE(PCH_PP_ON_DELAYS, pp_on);
- I915_WRITE(PCH_PP_OFF_DELAYS, pp_off);
- I915_WRITE(PCH_PP_DIVISOR, pp_div);
+ pp_on |= port_sel;
+
+ I915_WRITE(pp_on_reg, pp_on);
+ I915_WRITE(pp_off_reg, pp_off);
+ I915_WRITE(pp_div_reg, pp_div);
DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n",
- I915_READ(PCH_PP_ON_DELAYS),
- I915_READ(PCH_PP_OFF_DELAYS),
- I915_READ(PCH_PP_DIVISOR));
+ I915_READ(pp_on_reg),
+ I915_READ(pp_off_reg),
+ I915_READ(pp_div_reg));
}
void
@@ -2829,7 +2798,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
- connector->polled = DRM_CONNECTOR_POLL_HPD;
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
@@ -2844,27 +2812,46 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
else
intel_connector->get_hw_state = intel_connector_get_hw_state;
+ intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
+ if (HAS_DDI(dev)) {
+ switch (intel_dig_port->port) {
+ case PORT_A:
+ intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
+ break;
+ case PORT_B:
+ intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL;
+ break;
+ case PORT_C:
+ intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL;
+ break;
+ case PORT_D:
+ intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
+ break;
+ default:
+ BUG();
+ }
+ }
/* Set up the DDC bus. */
switch (port) {
case PORT_A:
+ intel_encoder->hpd_pin = HPD_PORT_A;
name = "DPDDC-A";
break;
case PORT_B:
- dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS;
+ intel_encoder->hpd_pin = HPD_PORT_B;
name = "DPDDC-B";
break;
case PORT_C:
- dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS;
+ intel_encoder->hpd_pin = HPD_PORT_C;
name = "DPDDC-C";
break;
case PORT_D:
- dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS;
+ intel_encoder->hpd_pin = HPD_PORT_D;
name = "DPDDC-D";
break;
default:
- WARN(1, "Invalid port %c\n", port_name(port));
- break;
+ BUG();
}
if (is_edp(intel_dp))
@@ -2974,6 +2961,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs);
+ intel_encoder->compute_config = intel_dp_compute_config;
intel_encoder->enable = intel_enable_dp;
intel_encoder->pre_enable = intel_pre_enable_dp;
intel_encoder->disable = intel_disable_dp;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 07ebac6fe8c..b5b6d19e6dd 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -33,12 +33,21 @@
#include <drm/drm_fb_helper.h>
#include <drm/drm_dp_helper.h>
+/**
+ * _wait_for - magic (register) wait macro
+ *
+ * Does the right thing for modeset paths when run under kdgb or similar atomic
+ * contexts. Note that it's important that we check the condition again after
+ * having timed out, since the timeout could be due to preemption or similar and
+ * we've never had a chance to check the condition before the timeout.
+ */
#define _wait_for(COND, MS, W) ({ \
- unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
+ unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \
int ret__ = 0; \
while (!(COND)) { \
if (time_after(jiffies, timeout__)) { \
- ret__ = -ETIMEDOUT; \
+ if (!(COND)) \
+ ret__ = -ETIMEDOUT; \
break; \
} \
if (W && drm_can_sleep()) { \
@@ -50,21 +59,10 @@
ret__; \
})
-#define wait_for_atomic_us(COND, US) ({ \
- unsigned long timeout__ = jiffies + usecs_to_jiffies(US); \
- int ret__ = 0; \
- while (!(COND)) { \
- if (time_after(jiffies, timeout__)) { \
- ret__ = -ETIMEDOUT; \
- break; \
- } \
- cpu_relax(); \
- } \
- ret__; \
-})
-
#define wait_for(COND, MS) _wait_for(COND, MS, 1)
#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
+#define wait_for_atomic_us(COND, US) _wait_for((COND), \
+ DIV_ROUND_UP((US), 1000), 0)
#define KHz(x) (1000*x)
#define MHz(x) KHz(1000*x)
@@ -101,34 +99,6 @@
#define INTEL_DVO_CHIP_TMDS 2
#define INTEL_DVO_CHIP_TVOUT 4
-/* drm_display_mode->private_flags */
-#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
-#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
-#define INTEL_MODE_DP_FORCE_6BPC (0x10)
-/* This flag must be set by the encoder's mode_fixup if it changes the crtc
- * timings in the mode to prevent the crtc fixup from overwriting them.
- * Currently only lvds needs that. */
-#define INTEL_MODE_CRTC_TIMINGS_SET (0x20)
-/*
- * Set when limited 16-235 (as opposed to full 0-255) RGB color range is
- * to be used.
- */
-#define INTEL_MODE_LIMITED_COLOR_RANGE (0x40)
-
-static inline void
-intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
- int multiplier)
-{
- mode->clock *= multiplier;
- mode->private_flags |= multiplier;
-}
-
-static inline int
-intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
-{
- return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
-}
-
struct intel_framebuffer {
struct drm_framebuffer base;
struct drm_i915_gem_object *obj;
@@ -158,9 +128,12 @@ struct intel_encoder {
bool cloneable;
bool connectors_active;
void (*hot_plug)(struct intel_encoder *);
+ bool (*compute_config)(struct intel_encoder *,
+ struct intel_crtc_config *);
void (*pre_pll_enable)(struct intel_encoder *);
void (*pre_enable)(struct intel_encoder *);
void (*enable)(struct intel_encoder *);
+ void (*mode_set)(struct intel_encoder *intel_encoder);
void (*disable)(struct intel_encoder *);
void (*post_disable)(struct intel_encoder *);
/* Read out the current hw state of this connector, returning true if
@@ -168,6 +141,7 @@ struct intel_encoder {
* it is connected to in the pipe parameter. */
bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
int crtc_mask;
+ enum hpd_pin hpd_pin;
};
struct intel_panel {
@@ -197,13 +171,65 @@ struct intel_connector {
/* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
struct edid *edid;
+
+ /* since POLL and HPD connectors may use the same HPD line keep the native
+ state of connector->polled in case hotplug storm detection changes it */
+ u8 polled;
+};
+
+struct intel_crtc_config {
+ struct drm_display_mode requested_mode;
+ struct drm_display_mode adjusted_mode;
+ /* This flag must be set by the encoder's compute_config callback if it
+ * changes the crtc timings in the mode to prevent the crtc fixup from
+ * overwriting them. Currently only lvds needs that. */
+ bool timings_set;
+ /* Whether to set up the PCH/FDI. Note that we never allow sharing
+ * between pch encoders and cpu encoders. */
+ bool has_pch_encoder;
+
+ /* CPU Transcoder for the pipe. Currently this can only differ from the
+ * pipe on Haswell (where we have a special eDP transcoder). */
+ enum transcoder cpu_transcoder;
+
+ /*
+ * Use reduced/limited/broadcast rbg range, compressing from the full
+ * range fed into the crtcs.
+ */
+ bool limited_color_range;
+
+ /* DP has a bunch of special case unfortunately, so mark the pipe
+ * accordingly. */
+ bool has_dp_encoder;
+ bool dither;
+
+ /* Controls for the clock computation, to override various stages. */
+ bool clock_set;
+
+ /* Settings for the intel dpll used on pretty much everything but
+ * haswell. */
+ struct dpll {
+ unsigned n;
+ unsigned m1, m2;
+ unsigned p1, p2;
+ } dpll;
+
+ int pipe_bpp;
+ struct intel_link_m_n dp_m_n;
+ /**
+ * This is currently used by DP and HDMI encoders since those can have a
+ * target pixel clock != the port link clock (which is currently stored
+ * in adjusted_mode->clock).
+ */
+ int pixel_target_clock;
+ /* Used by SDVO (and if we ever fix it, HDMI). */
+ unsigned pixel_multiplier;
};
struct intel_crtc {
struct drm_crtc base;
enum pipe pipe;
enum plane plane;
- enum transcoder cpu_transcoder;
u8 lut_r[256], lut_g[256], lut_b[256];
/*
* Whether the crtc and the connected output pipeline is active. Implies
@@ -230,7 +256,8 @@ struct intel_crtc {
int16_t cursor_x, cursor_y;
int16_t cursor_width, cursor_height;
bool cursor_visible;
- unsigned int bpp;
+
+ struct intel_crtc_config config;
/* We can share PLLs across outputs if the timings match */
struct intel_pch_pll *pch_pll;
@@ -242,11 +269,16 @@ struct intel_crtc {
struct intel_plane {
struct drm_plane base;
+ int plane;
enum pipe pipe;
struct drm_i915_gem_object *obj;
bool can_scale;
int max_downscale;
u32 lut_r[1024], lut_g[1024], lut_b[1024];
+ int crtc_x, crtc_y;
+ unsigned int crtc_w, crtc_h;
+ uint32_t src_x, src_y;
+ uint32_t src_w, src_h;
void (*update_plane)(struct drm_plane *plane,
struct drm_framebuffer *fb,
struct drm_i915_gem_object *obj,
@@ -347,7 +379,7 @@ struct dip_infoframe {
} __attribute__((packed));
struct intel_hdmi {
- u32 sdvox_reg;
+ u32 hdmi_reg;
int ddc_bus;
uint32_t color_range;
bool color_range_auto;
@@ -366,6 +398,7 @@ struct intel_hdmi {
struct intel_dp {
uint32_t output_reg;
+ uint32_t aux_ch_ctl_reg;
uint32_t DP;
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
bool has_audio;
@@ -443,13 +476,12 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector)
extern void intel_crt_init(struct drm_device *dev);
extern void intel_hdmi_init(struct drm_device *dev,
- int sdvox_reg, enum port port);
+ int hdmi_reg, enum port port);
extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector);
extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
-extern bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
+extern bool intel_hdmi_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config);
extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
bool is_sdvob);
@@ -464,18 +496,14 @@ extern void intel_dp_init(struct drm_device *dev, int output_reg,
enum port port);
extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector);
-void
-intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
extern void intel_dp_init_link_config(struct intel_dp *intel_dp);
extern void intel_dp_start_link_train(struct intel_dp *intel_dp);
extern void intel_dp_complete_link_train(struct intel_dp *intel_dp);
extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
extern void intel_dp_encoder_destroy(struct drm_encoder *encoder);
extern void intel_dp_check_link_status(struct intel_dp *intel_dp);
-extern bool intel_dp_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
+extern bool intel_dp_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config);
extern bool intel_dpd_is_edp(struct drm_device *dev);
extern void ironlake_edp_backlight_on(struct intel_dp *intel_dp);
extern void ironlake_edp_backlight_off(struct intel_dp *intel_dp);
@@ -483,11 +511,8 @@ extern void ironlake_edp_panel_on(struct intel_dp *intel_dp);
extern void ironlake_edp_panel_off(struct intel_dp *intel_dp);
extern void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp);
extern void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
-extern void intel_edp_link_config(struct intel_encoder *, int *, int *);
-extern int intel_edp_target_clock(struct intel_encoder *,
- struct drm_display_mode *mode);
extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
-extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
+extern int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
enum plane plane);
@@ -531,6 +556,7 @@ extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder);
extern void intel_connector_dpms(struct drm_connector *, int mode);
extern bool intel_connector_get_hw_state(struct intel_connector *connector);
extern void intel_modeset_check_state(struct drm_device *dev);
+extern void intel_plane_restore(struct drm_plane *plane);
static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
@@ -636,6 +662,10 @@ extern void intel_init_clock_gating(struct drm_device *dev);
extern void intel_write_eld(struct drm_encoder *encoder,
struct drm_display_mode *mode);
extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
+extern void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
+ struct intel_link_m_n *m_n);
+extern void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
+ struct intel_link_m_n *m_n);
extern void intel_prepare_ddi(struct drm_device *dev);
extern void hsw_fdi_link_train(struct drm_crtc *crtc);
extern void intel_ddi_init(struct drm_device *dev, enum port port);
@@ -670,6 +700,7 @@ extern void intel_update_fbc(struct drm_device *dev);
extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
extern void intel_gpu_ips_teardown(void);
+extern bool intel_using_power_well(struct drm_device *dev);
extern void intel_init_power_well(struct drm_device *dev);
extern void intel_set_power_well(struct drm_device *dev, bool enable);
extern void intel_enable_gt_powersave(struct drm_device *dev);
@@ -681,7 +712,7 @@ extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe);
extern int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv);
extern void intel_ddi_pll_init(struct drm_device *dev);
-extern void intel_ddi_enable_pipe_func(struct drm_crtc *crtc);
+extern void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc);
extern void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
enum transcoder cpu_transcoder);
extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc);
@@ -695,4 +726,6 @@ extern bool
intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
extern void intel_ddi_fdi_disable(struct drm_crtc *crtc);
+extern void intel_display_handle_reset(struct drm_device *dev);
+
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 00e70dbe82d..cc70b16d5d4 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -448,6 +448,7 @@ void intel_dvo_init(struct drm_device *dev)
const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
struct i2c_adapter *i2c;
int gpio;
+ bool dvoinit;
/* Allow the I2C driver info to specify the GPIO to be used in
* special cases, but otherwise default to what's defined
@@ -467,7 +468,17 @@ void intel_dvo_init(struct drm_device *dev)
i2c = intel_gmbus_get_adapter(dev_priv, gpio);
intel_dvo->dev = *dvo;
- if (!dvo->dev_ops->init(&intel_dvo->dev, i2c))
+
+ /* GMBUS NAK handling seems to be unstable, hence let the
+ * transmitter detection run in bit banging mode for now.
+ */
+ intel_gmbus_force_bit(i2c, true);
+
+ dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c);
+
+ intel_gmbus_force_bit(i2c, false);
+
+ if (!dvoinit)
continue;
intel_encoder->type = INTEL_OUTPUT_DVO;
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 981bdce3634..0e19e575a1b 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -150,7 +150,8 @@ static int intelfb_create(struct drm_fb_helper *helper,
}
info->screen_size = size;
-// memset(info->screen_base, 0, size);
+ /* This driver doesn't need a VT switch to restore the mode on resume */
+ info->skip_vt_switch = true;
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
@@ -227,7 +228,7 @@ int intel_fbdev_init(struct drm_device *dev)
ifbdev->helper.funcs = &intel_fb_helper_funcs;
ret = drm_fb_helper_init(dev, &ifbdev->helper,
- dev_priv->num_pipe,
+ INTEL_INFO(dev)->num_pipes,
INTELFB_CONN_LIMIT);
if (ret) {
kfree(ifbdev);
@@ -282,6 +283,9 @@ void intel_fb_restore_mode(struct drm_device *dev)
struct drm_mode_config *config = &dev->mode_config;
struct drm_plane *plane;
+ if (INTEL_INFO(dev)->num_pipes == 0)
+ return;
+
drm_modeset_lock_all(dev);
ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index fa8ec4a2604..a9057930f2b 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -50,7 +50,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
- WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits,
+ WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits,
"HDMI port enabled, expecting disabled\n");
}
@@ -120,13 +120,14 @@ static u32 hsw_infoframe_enable(struct dip_infoframe *frame)
}
}
-static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe)
+static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame,
+ enum transcoder cpu_transcoder)
{
switch (frame->type) {
case DIP_TYPE_AVI:
- return HSW_TVIDEO_DIP_AVI_DATA(pipe);
+ return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder);
case DIP_TYPE_SPD:
- return HSW_TVIDEO_DIP_SPD_DATA(pipe);
+ return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder);
default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
return 0;
@@ -293,8 +294,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
- u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe);
+ u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
+ u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->config.cpu_transcoder);
unsigned int i, len = DIP_HEADER_SIZE + frame->len;
u32 val = I915_READ(ctl_reg);
@@ -332,6 +333,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct dip_infoframe avi_if = {
.type = DIP_TYPE_AVI,
.ver = DIP_VERSION_AVI,
@@ -342,7 +344,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
if (intel_hdmi->rgb_quant_range_selectable) {
- if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
+ if (intel_crtc->config.limited_color_range)
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED;
else
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL;
@@ -568,7 +570,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
+ u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
u32 val = I915_READ(reg);
assert_hdmi_port_disabled(intel_hdmi);
@@ -597,40 +599,40 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- u32 sdvox;
+ u32 hdmi_val;
- sdvox = SDVO_ENCODING_HDMI;
- if (!HAS_PCH_SPLIT(dev))
- sdvox |= intel_hdmi->color_range;
+ hdmi_val = SDVO_ENCODING_HDMI;
+ if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev))
+ hdmi_val |= intel_hdmi->color_range;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
- sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
+ hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
- sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
+ hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
- if (intel_crtc->bpp > 24)
- sdvox |= COLOR_FORMAT_12bpc;
+ if (intel_crtc->config.pipe_bpp > 24)
+ hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
else
- sdvox |= COLOR_FORMAT_8bpc;
+ hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
/* Required on CPT */
if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
- sdvox |= HDMI_MODE_SELECT;
+ hdmi_val |= HDMI_MODE_SELECT_HDMI;
if (intel_hdmi->has_audio) {
DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
pipe_name(intel_crtc->pipe));
- sdvox |= SDVO_AUDIO_ENABLE;
- sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
+ hdmi_val |= SDVO_AUDIO_ENABLE;
+ hdmi_val |= HDMI_MODE_SELECT_HDMI;
intel_write_eld(encoder, adjusted_mode);
}
if (HAS_PCH_CPT(dev))
- sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
- else if (intel_crtc->pipe == PIPE_B)
- sdvox |= SDVO_PIPE_B_SELECT;
+ hdmi_val |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe);
+ else
+ hdmi_val |= SDVO_PIPE_SEL(intel_crtc->pipe);
- I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
+ POSTING_READ(intel_hdmi->hdmi_reg);
intel_hdmi->set_infoframes(encoder, adjusted_mode);
}
@@ -643,7 +645,7 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
u32 tmp;
- tmp = I915_READ(intel_hdmi->sdvox_reg);
+ tmp = I915_READ(intel_hdmi->hdmi_reg);
if (!(tmp & SDVO_ENABLE))
return false;
@@ -660,6 +662,7 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
u32 temp;
u32 enable_bits = SDVO_ENABLE;
@@ -667,38 +670,32 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
if (intel_hdmi->has_audio)
enable_bits |= SDVO_AUDIO_ENABLE;
- temp = I915_READ(intel_hdmi->sdvox_reg);
+ temp = I915_READ(intel_hdmi->hdmi_reg);
/* HW workaround for IBX, we need to move the port to transcoder A
- * before disabling it. */
- if (HAS_PCH_IBX(dev)) {
- struct drm_crtc *crtc = encoder->base.crtc;
- int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
-
- /* Restore the transcoder select bit. */
- if (pipe == PIPE_B)
- enable_bits |= SDVO_PIPE_B_SELECT;
- }
+ * before disabling it, so restore the transcoder select bit here. */
+ if (HAS_PCH_IBX(dev))
+ enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe);
/* HW workaround, need to toggle enable bit off and on for 12bpc, but
* we do this anyway which shows more stable in testing.
*/
if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
+ POSTING_READ(intel_hdmi->hdmi_reg);
}
temp |= enable_bits;
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, temp);
+ POSTING_READ(intel_hdmi->hdmi_reg);
/* HW workaround, need to write this twice for issue that may result
* in first write getting masked.
*/
if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, temp);
+ POSTING_READ(intel_hdmi->hdmi_reg);
}
}
@@ -710,7 +707,7 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
u32 temp;
u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
- temp = I915_READ(intel_hdmi->sdvox_reg);
+ temp = I915_READ(intel_hdmi->hdmi_reg);
/* HW workaround for IBX, we need to move the port to transcoder A
* before disabling it. */
@@ -720,12 +717,12 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
if (temp & SDVO_PIPE_B_SELECT) {
temp &= ~SDVO_PIPE_B_SELECT;
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, temp);
+ POSTING_READ(intel_hdmi->hdmi_reg);
/* Again we need to write this twice. */
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, temp);
+ POSTING_READ(intel_hdmi->hdmi_reg);
/* Transcoder selection bits only update
* effectively on vblank. */
@@ -740,21 +737,21 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
* we do this anyway which shows more stable in testing.
*/
if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
+ POSTING_READ(intel_hdmi->hdmi_reg);
}
temp &= ~enable_bits;
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, temp);
+ POSTING_READ(intel_hdmi->hdmi_reg);
/* HW workaround, need to write this twice for issue that may result
* in first write getting masked.
*/
if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(intel_hdmi->sdvox_reg, temp);
- POSTING_READ(intel_hdmi->sdvox_reg);
+ I915_WRITE(intel_hdmi->hdmi_reg, temp);
+ POSTING_READ(intel_hdmi->hdmi_reg);
}
}
@@ -772,23 +769,40 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
-bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+bool intel_hdmi_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
{
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
if (intel_hdmi->color_range_auto) {
/* See CEA-861-E - 5.1 Default Encoding Parameters */
if (intel_hdmi->has_hdmi_sink &&
drm_match_cea_mode(adjusted_mode) > 1)
- intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235;
+ intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235;
else
intel_hdmi->color_range = 0;
}
if (intel_hdmi->color_range)
- adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE;
+ pipe_config->limited_color_range = true;
+
+ if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev))
+ pipe_config->has_pch_encoder = true;
+
+ /*
+ * HDMI is either 12 or 8, so if the display lets 10bpc sneak
+ * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi
+ * outputs.
+ */
+ if (pipe_config->pipe_bpp > 8*3 && HAS_PCH_SPLIT(dev)) {
+ DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n");
+ pipe_config->pipe_bpp = 12*3;
+ } else {
+ DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n");
+ pipe_config->pipe_bpp = 8*3;
+ }
return true;
}
@@ -906,6 +920,9 @@ intel_hdmi_set_property(struct drm_connector *connector,
}
if (property == dev_priv->broadcast_rgb_property) {
+ bool old_auto = intel_hdmi->color_range_auto;
+ uint32_t old_range = intel_hdmi->color_range;
+
switch (val) {
case INTEL_BROADCAST_RGB_AUTO:
intel_hdmi->color_range_auto = true;
@@ -916,11 +933,16 @@ intel_hdmi_set_property(struct drm_connector *connector,
break;
case INTEL_BROADCAST_RGB_LIMITED:
intel_hdmi->color_range_auto = false;
- intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235;
+ intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235;
break;
default:
return -EINVAL;
}
+
+ if (old_auto == intel_hdmi->color_range_auto &&
+ old_range == intel_hdmi->color_range)
+ return 0;
+
goto done;
}
@@ -941,7 +963,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
}
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
- .mode_fixup = intel_hdmi_mode_fixup,
.mode_set = intel_hdmi_mode_set,
};
@@ -985,36 +1006,36 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
DRM_MODE_CONNECTOR_HDMIA);
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
- connector->polled = DRM_CONNECTOR_POLL_HPD;
connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
switch (port) {
case PORT_B:
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
- dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS;
+ intel_encoder->hpd_pin = HPD_PORT_B;
break;
case PORT_C:
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
- dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS;
+ intel_encoder->hpd_pin = HPD_PORT_C;
break;
case PORT_D:
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
- dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS;
+ intel_encoder->hpd_pin = HPD_PORT_D;
break;
case PORT_A:
+ intel_encoder->hpd_pin = HPD_PORT_A;
/* Internal port only for eDP. */
default:
BUG();
}
- if (!HAS_PCH_SPLIT(dev)) {
- intel_hdmi->write_infoframe = g4x_write_infoframe;
- intel_hdmi->set_infoframes = g4x_set_infoframes;
- } else if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev)) {
intel_hdmi->write_infoframe = vlv_write_infoframe;
intel_hdmi->set_infoframes = vlv_set_infoframes;
- } else if (IS_HASWELL(dev)) {
+ } else if (!HAS_PCH_SPLIT(dev)) {
+ intel_hdmi->write_infoframe = g4x_write_infoframe;
+ intel_hdmi->set_infoframes = g4x_set_infoframes;
+ } else if (HAS_DDI(dev)) {
intel_hdmi->write_infoframe = hsw_write_infoframe;
intel_hdmi->set_infoframes = hsw_set_infoframes;
} else if (HAS_PCH_IBX(dev)) {
@@ -1045,7 +1066,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
}
}
-void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
+void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
{
struct intel_digital_port *intel_dig_port;
struct intel_encoder *intel_encoder;
@@ -1069,6 +1090,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
+ intel_encoder->compute_config = intel_hdmi_compute_config;
intel_encoder->enable = intel_enable_hdmi;
intel_encoder->disable = intel_disable_hdmi;
intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
@@ -1078,7 +1100,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
intel_encoder->cloneable = false;
intel_dig_port->port = port;
- intel_dig_port->hdmi.sdvox_reg = sdvox_reg;
+ intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
intel_dig_port->dp.output_reg = 0;
intel_hdmi_init_connector(intel_dig_port, intel_connector);
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index ef4744e1bf0..5d245031e39 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -522,7 +522,9 @@ int intel_setup_gmbus(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret, i;
- if (HAS_PCH_SPLIT(dev))
+ if (HAS_PCH_NOP(dev))
+ return 0;
+ else if (HAS_PCH_SPLIT(dev))
dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA;
else if (IS_VALLEYVIEW(dev))
dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 3d1d97488cc..f36f1baabd5 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -261,8 +261,6 @@ centre_horizontally(struct drm_display_mode *mode,
mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
-
- mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET;
}
static void
@@ -284,8 +282,6 @@ centre_vertically(struct drm_display_mode *mode,
mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
-
- mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET;
}
static inline u32 panel_fitter_scaling(u32 source, u32 target)
@@ -301,17 +297,20 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target)
return (FACTOR * ratio + FACTOR/2) / FACTOR;
}
-static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
+ struct intel_crtc_config *pipe_config)
{
- struct drm_device *dev = encoder->dev;
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
+ struct intel_lvds_encoder *lvds_encoder =
+ to_lvds_encoder(&intel_encoder->base);
struct intel_connector *intel_connector =
&lvds_encoder->attached_connector->base;
+ struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *mode = &pipe_config->requested_mode;
struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
+ unsigned int lvds_bpp;
int pipe;
/* Should never happen!! */
@@ -323,6 +322,17 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
if (intel_encoder_check_is_cloned(&lvds_encoder->base))
return false;
+ if ((I915_READ(lvds_encoder->reg) & LVDS_A3_POWER_MASK) ==
+ LVDS_A3_POWER_UP)
+ lvds_bpp = 8*3;
+ else
+ lvds_bpp = 6*3;
+
+ if (lvds_bpp != pipe_config->pipe_bpp) {
+ DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n",
+ pipe_config->pipe_bpp, lvds_bpp);
+ pipe_config->pipe_bpp = lvds_bpp;
+ }
/*
* We have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode,
@@ -333,6 +343,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
adjusted_mode);
if (HAS_PCH_SPLIT(dev)) {
+ pipe_config->has_pch_encoder = true;
+
intel_pch_panel_fitting(dev,
intel_connector->panel.fitting_mode,
mode, adjusted_mode);
@@ -359,6 +371,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
I915_WRITE(BCLRPAT(pipe), 0);
drm_mode_set_crtcinfo(adjusted_mode, 0);
+ pipe_config->timings_set = true;
switch (intel_connector->panel.fitting_mode) {
case DRM_MODE_SCALE_CENTER:
@@ -618,7 +631,6 @@ static void intel_lvds_destroy(struct drm_connector *connector)
if (!IS_ERR_OR_NULL(lvds_connector->base.edid))
kfree(lvds_connector->base.edid);
- intel_panel_destroy_backlight(connector->dev);
intel_panel_fini(&lvds_connector->base.panel);
drm_sysfs_connector_remove(connector);
@@ -661,7 +673,6 @@ static int intel_lvds_set_property(struct drm_connector *connector,
}
static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
- .mode_fixup = intel_lvds_mode_fixup,
.mode_set = intel_lvds_mode_set,
};
@@ -850,6 +861,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"),
},
},
+ {
+ .callback = intel_no_lvds_dmi_callback,
+ .ident = "Fujitsu Esprimo Q900",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"),
+ },
+ },
{ } /* terminating entry */
};
@@ -1019,12 +1038,15 @@ static bool intel_lvds_supported(struct drm_device *dev)
{
/* With the introduction of the PCH we gained a dedicated
* LVDS presence pin, use it. */
- if (HAS_PCH_SPLIT(dev))
+ if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
return true;
/* Otherwise LVDS was only attached to mobile products,
* except for the inglorious 830gm */
- return IS_MOBILE(dev) && !IS_I830(dev);
+ if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev))
+ return true;
+
+ return false;
}
/**
@@ -1102,6 +1124,7 @@ bool intel_lvds_init(struct drm_device *dev)
intel_encoder->enable = intel_enable_lvds;
intel_encoder->pre_enable = intel_pre_enable_lvds;
intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds;
+ intel_encoder->compute_config = intel_lvds_compute_config;
intel_encoder->disable = intel_disable_lvds;
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
intel_connector->get_hw_state = intel_connector_get_hw_state;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index bee8cb6108a..eb5e6e95f3c 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -286,8 +286,11 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- dev_priv->backlight_level = level;
- if (dev_priv->backlight_enabled)
+ dev_priv->backlight.level = level;
+ if (dev_priv->backlight.device)
+ dev_priv->backlight.device->props.brightness = level;
+
+ if (dev_priv->backlight.enabled)
intel_panel_actually_set_backlight(dev, level);
}
@@ -295,7 +298,7 @@ void intel_panel_disable_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- dev_priv->backlight_enabled = false;
+ dev_priv->backlight.enabled = false;
intel_panel_actually_set_backlight(dev, 0);
if (INTEL_INFO(dev)->gen >= 4) {
@@ -318,8 +321,12 @@ void intel_panel_enable_backlight(struct drm_device *dev,
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (dev_priv->backlight_level == 0)
- dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
+ if (dev_priv->backlight.level == 0) {
+ dev_priv->backlight.level = intel_panel_get_max_backlight(dev);
+ if (dev_priv->backlight.device)
+ dev_priv->backlight.device->props.brightness =
+ dev_priv->backlight.level;
+ }
if (INTEL_INFO(dev)->gen >= 4) {
uint32_t reg, tmp;
@@ -335,7 +342,7 @@ void intel_panel_enable_backlight(struct drm_device *dev,
if (tmp & BLM_PWM_ENABLE)
goto set_level;
- if (dev_priv->num_pipe == 3)
+ if (INTEL_INFO(dev)->num_pipes == 3)
tmp &= ~BLM_PIPE_SELECT_IVB;
else
tmp &= ~BLM_PIPE_SELECT;
@@ -360,16 +367,16 @@ set_level:
* BLC_PWM_CPU_CTL may be cleared to zero automatically when these
* registers are set.
*/
- dev_priv->backlight_enabled = true;
- intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
+ dev_priv->backlight.enabled = true;
+ intel_panel_actually_set_backlight(dev, dev_priv->backlight.level);
}
static void intel_panel_init_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- dev_priv->backlight_level = intel_panel_get_backlight(dev);
- dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
+ dev_priv->backlight.level = intel_panel_get_backlight(dev);
+ dev_priv->backlight.enabled = dev_priv->backlight.level != 0;
}
enum drm_connector_status
@@ -405,8 +412,7 @@ static int intel_panel_update_status(struct backlight_device *bd)
static int intel_panel_get_brightness(struct backlight_device *bd)
{
struct drm_device *dev = bl_get_data(bd);
- struct drm_i915_private *dev_priv = dev->dev_private;
- return dev_priv->backlight_level;
+ return intel_panel_get_backlight(dev);
}
static const struct backlight_ops intel_panel_bl_ops = {
@@ -422,33 +428,38 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
intel_panel_init_backlight(dev);
+ if (WARN_ON(dev_priv->backlight.device))
+ return -ENODEV;
+
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW;
+ props.brightness = dev_priv->backlight.level;
props.max_brightness = _intel_panel_get_max_backlight(dev);
if (props.max_brightness == 0) {
DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
return -ENODEV;
}
- dev_priv->backlight =
+ dev_priv->backlight.device =
backlight_device_register("intel_backlight",
&connector->kdev, dev,
&intel_panel_bl_ops, &props);
- if (IS_ERR(dev_priv->backlight)) {
+ if (IS_ERR(dev_priv->backlight.device)) {
DRM_ERROR("Failed to register backlight: %ld\n",
- PTR_ERR(dev_priv->backlight));
- dev_priv->backlight = NULL;
+ PTR_ERR(dev_priv->backlight.device));
+ dev_priv->backlight.device = NULL;
return -ENODEV;
}
- dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
return 0;
}
void intel_panel_destroy_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (dev_priv->backlight)
- backlight_device_unregister(dev_priv->backlight);
+ if (dev_priv->backlight.device) {
+ backlight_device_unregister(dev_priv->backlight.device);
+ dev_priv->backlight.device = NULL;
+ }
}
#else
int intel_panel_setup_backlight(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index adca00783e6..de3b0dc5658 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2460,10 +2460,14 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
if (val == dev_priv->rps.cur_delay)
return;
- I915_WRITE(GEN6_RPNSWREQ,
- GEN6_FREQUENCY(val) |
- GEN6_OFFSET(0) |
- GEN6_AGGRESSIVE_TURBO);
+ if (IS_HASWELL(dev))
+ I915_WRITE(GEN6_RPNSWREQ,
+ HSW_FREQUENCY(val));
+ else
+ I915_WRITE(GEN6_RPNSWREQ,
+ GEN6_FREQUENCY(val) |
+ GEN6_OFFSET(0) |
+ GEN6_AGGRESSIVE_TURBO);
/* Make sure we continue to get interrupts
* until we hit the minimum or maximum frequencies.
@@ -2554,8 +2558,8 @@ static void gen6_enable_rps(struct drm_device *dev)
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
- /* In units of 100MHz */
- dev_priv->rps.max_delay = rp_state_cap & 0xff;
+ /* In units of 50MHz */
+ dev_priv->rps.hw_max = dev_priv->rps.max_delay = rp_state_cap & 0xff;
dev_priv->rps.min_delay = (rp_state_cap & 0xff0000) >> 16;
dev_priv->rps.cur_delay = 0;
@@ -2601,12 +2605,19 @@ static void gen6_enable_rps(struct drm_device *dev)
GEN6_RC_CTL_EI_MODE(1) |
GEN6_RC_CTL_HW_ENABLE);
- I915_WRITE(GEN6_RPNSWREQ,
- GEN6_FREQUENCY(10) |
- GEN6_OFFSET(0) |
- GEN6_AGGRESSIVE_TURBO);
- I915_WRITE(GEN6_RC_VIDEO_FREQ,
- GEN6_FREQUENCY(12));
+ if (IS_HASWELL(dev)) {
+ I915_WRITE(GEN6_RPNSWREQ,
+ HSW_FREQUENCY(10));
+ I915_WRITE(GEN6_RC_VIDEO_FREQ,
+ HSW_FREQUENCY(12));
+ } else {
+ I915_WRITE(GEN6_RPNSWREQ,
+ GEN6_FREQUENCY(10) |
+ GEN6_OFFSET(0) |
+ GEN6_AGGRESSIVE_TURBO);
+ I915_WRITE(GEN6_RC_VIDEO_FREQ,
+ GEN6_FREQUENCY(12));
+ }
I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
@@ -2631,9 +2642,11 @@ static void gen6_enable_rps(struct drm_device *dev)
if (!ret) {
pcu_mbox = 0;
ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
- if (ret && pcu_mbox & (1<<31)) { /* OC supported */
- dev_priv->rps.max_delay = pcu_mbox & 0xff;
- DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
+ if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */
+ DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n",
+ (dev_priv->rps.max_delay & 0xff) * 50,
+ (pcu_mbox & 0xff) * 50);
+ dev_priv->rps.hw_max = pcu_mbox & 0xff;
}
} else {
DRM_DEBUG_DRIVER("Failed to set the min frequency\n");
@@ -2671,8 +2684,8 @@ static void gen6_update_ring_freq(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int min_freq = 15;
- int gpu_freq;
- unsigned int ia_freq, max_ia_freq;
+ unsigned int gpu_freq;
+ unsigned int max_ia_freq, min_ring_freq;
int scaling_factor = 180;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
@@ -2688,6 +2701,10 @@ static void gen6_update_ring_freq(struct drm_device *dev)
/* Convert from kHz to MHz */
max_ia_freq /= 1000;
+ min_ring_freq = I915_READ(MCHBAR_MIRROR_BASE_SNB + DCLK);
+ /* convert DDR frequency from units of 133.3MHz to bandwidth */
+ min_ring_freq = (2 * 4 * min_ring_freq + 2) / 3;
+
/*
* For each potential GPU frequency, load a ring frequency we'd like
* to use for memory access. We do this by specifying the IA frequency
@@ -2696,21 +2713,32 @@ static void gen6_update_ring_freq(struct drm_device *dev)
for (gpu_freq = dev_priv->rps.max_delay; gpu_freq >= dev_priv->rps.min_delay;
gpu_freq--) {
int diff = dev_priv->rps.max_delay - gpu_freq;
-
- /*
- * For GPU frequencies less than 750MHz, just use the lowest
- * ring freq.
- */
- if (gpu_freq < min_freq)
- ia_freq = 800;
- else
- ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
- ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
- ia_freq <<= GEN6_PCODE_FREQ_IA_RATIO_SHIFT;
+ unsigned int ia_freq = 0, ring_freq = 0;
+
+ if (IS_HASWELL(dev)) {
+ ring_freq = (gpu_freq * 5 + 3) / 4;
+ ring_freq = max(min_ring_freq, ring_freq);
+ /* leave ia_freq as the default, chosen by cpufreq */
+ } else {
+ /* On older processors, there is no separate ring
+ * clock domain, so in order to boost the bandwidth
+ * of the ring, we need to upclock the CPU (ia_freq).
+ *
+ * For GPU frequencies less than 750MHz,
+ * just use the lowest ring freq.
+ */
+ if (gpu_freq < min_freq)
+ ia_freq = 800;
+ else
+ ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
+ ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
+ }
sandybridge_pcode_write(dev_priv,
GEN6_PCODE_WRITE_MIN_FREQ_TABLE,
- ia_freq | gpu_freq);
+ ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT |
+ ring_freq << GEN6_PCODE_FREQ_RING_RATIO_SHIFT |
+ gpu_freq);
}
}
@@ -2821,7 +2849,7 @@ static void ironlake_enable_rc6(struct drm_device *dev)
ret = intel_ring_idle(ring);
dev_priv->mm.interruptible = was_interruptible;
if (ret) {
- DRM_ERROR("failed to enable ironlake power power savings\n");
+ DRM_ERROR("failed to enable ironlake power savings\n");
ironlake_teardown_rc6(dev);
return;
}
@@ -3562,6 +3590,7 @@ static void cpt_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe;
+ uint32_t val;
/*
* On Ibex Peak and Cougar Point, we need to disable clock
@@ -3574,8 +3603,17 @@ static void cpt_init_clock_gating(struct drm_device *dev)
/* The below fixes the weird display corruption, a few pixels shifted
* downward, on (only) LVDS of some HP laptops with IVY.
*/
- for_each_pipe(pipe)
- I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_CHICKEN2_TIMING_OVERRIDE);
+ for_each_pipe(pipe) {
+ val = I915_READ(TRANS_CHICKEN2(pipe));
+ val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
+ val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
+ if (dev_priv->fdi_rx_polarity_inverted)
+ val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
+ val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK;
+ val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER;
+ val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH;
+ I915_WRITE(TRANS_CHICKEN2(pipe), val);
+ }
/* WADP0ClockGatingDisable */
for_each_pipe(pipe) {
I915_WRITE(TRANS_CHICKEN1(pipe),
@@ -3768,6 +3806,9 @@ static void haswell_init_clock_gating(struct drm_device *dev)
I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) |
GEN6_MBCTL_ENABLE_BOOT_FETCH);
+ /* WaSwitchSolVfFArbitrationPriority */
+ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
+
/* XXX: This is a workaround for early silicon revisions and should be
* removed later.
*/
@@ -3874,7 +3915,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
snpcr |= GEN6_MBC_SNPCR_MED;
I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
- cpt_init_clock_gating(dev);
+ if (!HAS_PCH_NOP(dev))
+ cpt_init_clock_gating(dev);
gen6_check_mch_setup(dev);
}
@@ -3899,8 +3941,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
CHICKEN3_DGMG_DONE_FIX_DISABLE);
+ /* WaDisablePSDDualDispatchEnable */
I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
- _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
+ _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP |
+ GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
/* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
@@ -3968,24 +4012,20 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
_MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
/*
- * On ValleyView, the GUnit needs to signal the GT
- * when flip and other events complete. So enable
- * all the GUnit->GT interrupts here
- */
- I915_WRITE(VLV_DPFLIPSTAT, PIPEB_LINE_COMPARE_INT_EN |
- PIPEB_HLINE_INT_EN | PIPEB_VBLANK_INT_EN |
- SPRITED_FLIPDONE_INT_EN | SPRITEC_FLIPDONE_INT_EN |
- PLANEB_FLIPDONE_INT_EN | PIPEA_LINE_COMPARE_INT_EN |
- PIPEA_HLINE_INT_EN | PIPEA_VBLANK_INT_EN |
- SPRITEB_FLIPDONE_INT_EN | SPRITEA_FLIPDONE_INT_EN |
- PLANEA_FLIPDONE_INT_EN);
-
- /*
* WaDisableVLVClockGating_VBIIssue
* Disable clock gating on th GCFG unit to prevent a delay
* in the reporting of vblank events.
*/
- I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS);
+ I915_WRITE(VLV_GUNIT_CLOCK_GATE, 0xffffffff);
+
+ /* Conservative clock gating settings for now */
+ I915_WRITE(0x9400, 0xffffffff);
+ I915_WRITE(0x9404, 0xffffffff);
+ I915_WRITE(0x9408, 0xffffffff);
+ I915_WRITE(0x940c, 0xffffffff);
+ I915_WRITE(0x9410, 0xffffffff);
+ I915_WRITE(0x9414, 0xffffffff);
+ I915_WRITE(0x9418, 0xffffffff);
}
static void g4x_init_clock_gating(struct drm_device *dev)
@@ -4070,13 +4110,29 @@ void intel_init_clock_gating(struct drm_device *dev)
dev_priv->display.init_clock_gating(dev);
}
+/**
+ * We should only use the power well if we explicitly asked the hardware to
+ * enable it, so check if it's enabled and also check if we've requested it to
+ * be enabled.
+ */
+bool intel_using_power_well(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (IS_HASWELL(dev))
+ return I915_READ(HSW_PWR_WELL_DRIVER) ==
+ (HSW_PWR_WELL_ENABLE | HSW_PWR_WELL_STATE);
+ else
+ return true;
+}
+
void intel_set_power_well(struct drm_device *dev, bool enable)
{
struct drm_i915_private *dev_priv