summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml176
-rw-r--r--Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml127
-rw-r--r--Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml215
-rw-r--r--Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml4
-rw-r--r--Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml70
-rw-r--r--Documentation/devicetree/bindings/display/panel/panel-simple.yaml6
-rw-r--r--Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml40
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.yaml8
-rw-r--r--Documentation/gpu/drm-uapi.rst114
-rw-r--r--Documentation/gpu/pl111.rst8
-rw-r--r--Documentation/gpu/todo.rst46
-rw-r--r--MAINTAINERS11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c92
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c171
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h46
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c112
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_dp.c18
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c41
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c3
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c2
-rw-r--r--drivers/gpu/drm/ast/ast_cursor.c11
-rw-r--r--drivers/gpu/drm/ast/ast_dp501.c23
-rw-r--r--drivers/gpu/drm/ast/ast_drv.c82
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h43
-rw-r--r--drivers/gpu/drm/ast/ast_main.c74
-rw-r--r--drivers/gpu/drm/ast/ast_mm.c2
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c40
-rw-r--r--drivers/gpu/drm/ast/ast_post.c6
-rw-r--r--drivers/gpu/drm/bridge/Kconfig31
-rw-r--r--drivers/gpu/drm/bridge/Makefile3
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-anx6345.c12
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c9
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt9611.c1230
-rw-r--r--drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c109
-rw-r--r--drivers/gpu/drm/bridge/nxp-ptn3460.c101
-rw-r--r--drivers/gpu/drm/bridge/panel.c7
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8622.c100
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8640.c29
-rw-r--r--drivers/gpu/drm/bridge/tc358762.c280
-rw-r--r--drivers/gpu/drm/bridge/tc358764.c109
-rw-r--r--drivers/gpu/drm/bridge/tc358767.c123
-rw-r--r--drivers/gpu/drm/bridge/tc358775.c749
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c3
-rw-r--r--drivers/gpu/drm/drm_bridge_connector.c1
-rw-r--r--drivers/gpu/drm/drm_connector.c49
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c71
-rw-r--r--drivers/gpu/drm/drm_gem_vram_helper.c49
-rw-r--r--drivers/gpu/drm/drm_panel.c85
-rw-r--r--drivers/gpu/drm/drm_syncobj.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c7
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c9
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_dp.c2
-rw-r--r--drivers/gpu/drm/gma500/mdfld_device.c20
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_dpi.c2
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_output.c55
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_output.h2
-rw-r--r--drivers/gpu/drm/gma500/mdfld_output.h2
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_drv.h1
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_sdvo.c2
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c70
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c33
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h3
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c6
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_csr.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c111
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c88
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_debugfs.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.c16
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h6
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.c19
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c52
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c17
-rw-r--r--drivers/gpu/drm/i915/display/intel_frontbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c110
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.h5
-rw-r--r--drivers/gpu/drm/i915/display/intel_sprite.c5
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c367
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_workarounds.c113
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c5
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_rps.c4
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_timeline.c24
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c4
-rw-r--r--drivers/gpu/drm/i915/i915_active.c7
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c5
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h54
-rw-r--r--drivers/gpu/drm/i915/i915_getparam.c1
-rw-r--r--drivers/gpu/drm/i915/i915_params.c5
-rw-r--r--drivers/gpu/drm/i915/i915_params.h1
-rw-r--r--drivers/gpu/drm/i915/i915_pci.c1
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h32
-rw-r--r--drivers/gpu/drm/i915/i915_request.c7
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.c19
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.h1
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c14
-rw-r--r--drivers/gpu/drm/i915/selftests/i915_request.c2
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c10
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c6
-rw-r--r--drivers/gpu/drm/ingenic/ingenic-drm-drv.c41
-rw-r--r--drivers/gpu/drm/ingenic/ingenic-ipu.c38
-rw-r--r--drivers/gpu/drm/mcde/mcde_display.c218
-rw-r--r--drivers/gpu/drm/mcde/mcde_drm.h67
-rw-r--r--drivers/gpu/drm/mcde/mcde_drv.c81
-rw-r--r--drivers/gpu/drm/mcde/mcde_dsi.c276
-rw-r--r--drivers/gpu/drm/mgag200/Kconfig12
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c227
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h19
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mm.c8
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c153
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_reg.h4
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c7
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c1
-rw-r--r--drivers/gpu/drm/mxsfb/Kconfig8
-rw-r--r--drivers/gpu/drm/mxsfb/Makefile2
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_crtc.c343
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c252
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.h42
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_kms.c571
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_out.c99
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_regs.h107
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c137
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.h14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo0039.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo5039.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo74c1.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo85b5.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo9039.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo90b5.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_boa0b5.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.h10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c176
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.h6
-rw-r--r--drivers/gpu/drm/nouveau/nv17_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fence.c2
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4.c1
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5.c1
-rw-r--r--drivers/gpu/drm/omapdrm/dss/venc.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c17
-rw-r--r--drivers/gpu/drm/panel/Kconfig11
-rw-r--r--drivers/gpu/drm/panel/Makefile1
-rw-r--r--drivers/gpu/drm/panel/panel-arm-versatile.c4
-rw-r--r--drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c6
-rw-r--r--drivers/gpu/drm/panel/panel-boe-himax8279d.c48
-rw-r--r--drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c12
-rw-r--r--drivers/gpu/drm/panel/panel-elida-kd35t133.c51
-rw-r--r--drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c23
-rw-r--r--drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c25
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9322.c7
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9881c.c277
-rw-r--r--drivers/gpu/drm/panel/panel-innolux-p079zca.c35
-rw-r--r--drivers/gpu/drm/panel/panel-jdi-lt070me05000.c4
-rw-r--r--drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c37
-rw-r--r--drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c58
-rw-r--r--drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c49
-rw-r--r--drivers/gpu/drm/panel/panel-lg-lb035q02.c4
-rw-r--r--drivers/gpu/drm/panel/panel-lg-lg4573.c4
-rw-r--r--drivers/gpu/drm/panel/panel-lvds.c13
-rw-r--r--drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c328
-rw-r--r--drivers/gpu/drm/panel/panel-nec-nl8048hl11.c4
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt35510.c60
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt39016.c46
-rw-r--r--drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c4
-rw-r--r--drivers/gpu/drm/panel/panel-orisetech-otm8009a.c13
-rw-r--r--drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c4
-rw-r--r--drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c4
-rw-r--r--drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c6
-rw-r--r--drivers/gpu/drm/panel/panel-raydium-rm67191.c37
-rw-r--r--drivers/gpu/drm/panel/panel-raydium-rm68200.c18
-rw-r--r--drivers/gpu/drm/panel/panel-ronbo-rb070d30.c20
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-ld9040.c7
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6d16d0.c27
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c9
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c9
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e63m0.c26
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c6
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c7
-rw-r--r--drivers/gpu/drm/panel/panel-seiko-43wvf1g.c4
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c4
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c4
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c4
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c201
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7701.c14
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7703.c61
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7789v.c4
-rw-r--r--drivers/gpu/drm/panel/panel-sony-acx424akp.c85
-rw-r--r--drivers/gpu/drm/panel/panel-sony-acx565akm.c7
-rw-r--r--drivers/gpu/drm/panel/panel-tpo-td028ttec1.c4
-rw-r--r--drivers/gpu/drm/panel/panel-tpo-td043mtea1.c6
-rw-r--r--drivers/gpu/drm/panel/panel-tpo-tpg110.c42
-rw-r--r--drivers/gpu/drm/panel/panel-truly-nt35597.c63
-rw-r--r--drivers/gpu/drm/panel/panel-visionox-rm69299.c41
-rw-r--r--drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c51
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_devfreq.c175
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_devfreq.h30
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_device.c61
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_device.h14
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c16
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gpu.c14
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_job.c10
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_perfcnt.c10
-rw-r--r--drivers/gpu/drm/pl111/pl111_drv.c20
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c22
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c6
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h2
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c4
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.h4
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c75
-rw-r--r--drivers/gpu/drm/radeon/radeon.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c123
-rw-r--r--drivers/gpu/drm/radeon/radeon_vm.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds.c6
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_lvds.c9
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_framebuffer.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_frontend.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_lvds.c11
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_rgb.c13
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tv.c6
-rw-r--r--drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c5
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.c2
-rw-r--r--drivers/gpu/drm/tegra/dsi.c4
-rw-r--r--drivers/gpu/drm/tegra/output.c10
-rw-r--r--drivers/gpu/drm/tidss/tidss_dispc.c32
-rw-r--r--drivers/gpu/drm/tidss/tidss_dispc.h4
-rw-r--r--drivers/gpu/drm/ttm/Makefile3
-rw-r--r--drivers/gpu/drm/ttm/ttm_agp_backend.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c347
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c104
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c8
-rw-r--r--drivers/gpu/drm/ttm/ttm_execbuf_util.c12
-rw-r--r--drivers/gpu/drm/ttm/ttm_range_manager.c (renamed from drivers/gpu/drm/ttm/ttm_bo_manager.c)89
-rw-r--r--drivers/gpu/drm/ttm/ttm_resource.c151
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c6
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.c13
-rw-r--r--drivers/gpu/drm/vgem/vgem_drv.c2
-rw-r--r--drivers/gpu/drm/virtio/Kconfig1
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.c3
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h21
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_gem.c3
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_kms.c4
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_object.c8
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_prime.c96
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vq.c55
-rw-r--r--drivers/gpu/drm/vkms/vkms_composer.c22
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_bo.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c73
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h18
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c75
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_mob.c60
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_thp.c73
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c121
-rw-r--r--drivers/video/fbdev/arcfb.c2
-rw-r--r--drivers/video/fbdev/atmel_lcdfb.c2
-rw-r--r--drivers/video/fbdev/core/fbmem.c10
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c2
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c2
-rw-r--r--drivers/video/fbdev/pvr2fb.c2
-rw-r--r--drivers/video/fbdev/savage/savagefb_driver.c1
-rw-r--r--drivers/virtio/Kconfig7
-rw-r--r--drivers/virtio/Makefile1
-rw-r--r--drivers/virtio/virtio.c6
-rw-r--r--drivers/virtio/virtio_dma_buf.c88
-rw-r--r--include/drm/drm_connector.h3
-rw-r--r--include/drm/drm_dp_helper.h8
-rw-r--r--include/drm/drm_mode_config.h6
-rw-r--r--include/drm/drm_panel.h15
-rw-r--r--include/drm/i915_pciids.h4
-rw-r--r--include/drm/ttm/ttm_bo_api.h109
-rw-r--r--include/drm/ttm/ttm_bo_driver.h355
-rw-r--r--include/drm/ttm/ttm_resource.h261
-rw-r--r--include/drm/ttm/ttm_tt.h10
-rw-r--r--include/linux/fb.h18
-rw-r--r--include/linux/moduleparam.h7
-rw-r--r--include/linux/virtio.h1
-rw-r--r--include/linux/virtio_dma_buf.h37
-rw-r--r--include/uapi/drm/drm_mode.h21
-rw-r--r--include/uapi/drm/i915_drm.h59
-rw-r--r--include/uapi/linux/virtio_gpu.h19
-rw-r--r--kernel/params.c17
312 files changed, 9636 insertions, 4596 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
new file mode 100644
index 000000000000..d60208359234
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
@@ -0,0 +1,176 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/lontium,lt9611.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Lontium LT9611 2 Port MIPI to HDMI Bridge
+
+maintainers:
+ - Vinod Koul <vkoul@kernel.org>
+
+description: |
+ The LT9611 is a bridge device which converts DSI to HDMI
+
+properties:
+ compatible:
+ enum:
+ - lontium,lt9611
+
+ reg:
+ maxItems: 1
+
+ "#sound-dai-cells":
+ const: 1
+
+ interrupts:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+ description: GPIO connected to active high RESET pin.
+
+ vdd-supply:
+ description: Regulator for 1.8V MIPI phy power.
+
+ vcc-supply:
+ description: Regulator for 3.3V IO power.
+
+ ports:
+ type: object
+
+ properties:
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ port@0:
+ type: object
+ description: |
+ Primary MIPI port-1 for MIPI input
+
+ properties:
+ reg:
+ const: 0
+
+ patternProperties:
+ "^endpoint(@[0-9])$":
+ type: object
+ additionalProperties: false
+
+ properties:
+ remote-endpoint:
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ required:
+ - reg
+
+ port@1:
+ type: object
+ description: |
+ Additional MIPI port-2 for MIPI input, used in combination
+ with primary MIPI port-1 to drive higher resolution displays
+
+ properties:
+ reg:
+ const: 1
+
+ patternProperties:
+ "^endpoint(@[0-9])$":
+ type: object
+ additionalProperties: false
+
+ properties:
+ remote-endpoint:
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ required:
+ - reg
+
+ port@2:
+ type: object
+ description: |
+ HDMI port for HDMI output
+
+ properties:
+ reg:
+ const: 2
+
+ patternProperties:
+ "^endpoint(@[0-9])$":
+ type: object
+ additionalProperties: false
+
+ properties:
+ remote-endpoint:
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ required:
+ - reg
+
+ required:
+ - "#address-cells"
+ - "#size-cells"
+ - port@0
+ - port@2
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - vdd-supply
+ - vcc-supply
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c10 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdmi-bridge@3b {
+ compatible = "lontium,lt9611";
+ reg = <0x3b>;
+
+ reset-gpios = <&tlmm 128 GPIO_ACTIVE_HIGH>;
+ interrupts-extended = <&tlmm 84 IRQ_TYPE_EDGE_FALLING>;
+
+ vdd-supply = <&lt9611_1v8>;
+ vcc-supply = <&lt9611_3v3>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ lt9611_a: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ lt9611_b: endpoint {
+ remote-endpoint = <&dsi1_out>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ lt9611_out: endpoint {
+ remote-endpoint = <&hdmi_con>;
+ };
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml
new file mode 100644
index 000000000000..195025e6803c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358762.yaml
@@ -0,0 +1,127 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/toshiba,tc358762.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Toshiba TC358762 MIPI DSI to MIPI DPI bridge
+
+maintainers:
+ - Marek Vasut <marex@denx.de>
+
+description: |
+ The TC358762 is bridge device which converts MIPI DSI to MIPI DPI.
+
+properties:
+ compatible:
+ enum:
+ - toshiba,tc358762
+
+ reg:
+ maxItems: 1
+ description: virtual channel number of a DSI peripheral
+
+ vddc-supply:
+ description: Regulator for 1.2V internal core power.
+
+ ports:
+ type: object
+
+ properties:
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ port@0:
+ type: object
+ additionalProperties: false
+
+ description: |
+ Video port for MIPI DSI input
+
+ properties:
+ reg:
+ const: 0
+
+ patternProperties:
+ endpoint:
+ type: object
+ additionalProperties: false
+
+ properties:
+ remote-endpoint: true
+
+ required:
+ - reg
+
+ port@1:
+ type: object
+ additionalProperties: false
+
+ description: |
+ Video port for MIPI DPI output (panel or connector).
+
+ properties:
+ reg:
+ const: 1
+
+ patternProperties:
+ endpoint:
+ type: object
+ additionalProperties: false
+
+ properties:
+ remote-endpoint: true
+
+ required:
+ - reg
+
+ required:
+ - "#address-cells"
+ - "#size-cells"
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - vddc-supply
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ bridge@0 {
+ reg = <0>;
+ compatible = "toshiba,tc358762";
+ vddc-supply = <&vcc_1v2_reg>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ bridge_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ bridge_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml
new file mode 100644
index 000000000000..31f085d8ab13
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml
@@ -0,0 +1,215 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/toshiba,tc358775.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Toshiba TC358775 DSI to LVDS bridge bindings
+
+maintainers:
+ - Vinay Simha BN <simhavcs@gmail.com>
+
+description: |
+ This binding supports DSI to LVDS bridge TC358775
+
+ MIPI DSI-RX Data 4-lane, CLK 1-lane with data rates up to 800 Mbps/lane.
+ Video frame size:
+ Up to 1600x1200 24-bit/pixel resolution for single-link LVDS display panel
+ limited by 135 MHz LVDS speed
+ Up to WUXGA (1920x1200 24-bit pixels) resolution for dual-link LVDS display
+ panel, limited by 270 MHz LVDS speed.
+
+properties:
+ compatible:
+ const: toshiba,tc358775
+
+ reg:
+ maxItems: 1
+ description: i2c address of the bridge, 0x0f
+
+ vdd-supply:
+ maxItems: 1
+ description: 1.2V LVDS Power Supply
+
+ vddio-supply:
+ maxItems: 1
+ description: 1.8V IO Power Supply
+
+ stby-gpios:
+ maxItems: 1
+ description: Standby pin, Low active
+
+ reset-gpios:
+ maxItems: 1
+ description: Hardware reset, Low active
+
+ ports:
+ type: object
+ description:
+ A node containing input and output port nodes with endpoint definitions
+ as documented in
+ Documentation/devicetree/bindings/media/video-interfaces.txt
+ properties:
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ port@0:
+ type: object
+ description: |
+ DSI Input. The remote endpoint phandle should be a
+ reference to a valid mipi_dsi_host device node.
+
+ port@1:
+ type: object
+ description: |
+ Video port for LVDS output (panel or connector).
+
+ port@2:
+ type: object
+ description: |
+ Video port for Dual link LVDS output (panel or connector).
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - vddio-supply
+ - stby-gpios
+ - reset-gpios
+ - ports
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ /* For single-link LVDS display panel */
+
+ i2c@78b8000 {
+ /* On High speed expansion */
+ label = "HS-I2C2";
+ reg = <0x078b8000 0x500>;
+ clock-frequency = <400000>; /* fastmode operation */
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tc_bridge: bridge@f {
+ compatible = "toshiba,tc358775";
+ reg = <0x0f>;
+
+ vdd-supply = <&pm8916_l2>;
+ vddio-supply = <&pm8916_l6>;
+
+ stby-gpios = <&msmgpio 99 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&msmgpio 72 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ d2l_in_test: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ lvds_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+ };
+ };
+
+ dsi@1a98000 {
+ reg = <0x1a98000 0x25c>;
+ reg-names = "dsi_ctrl";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@1 {
+ reg = <1>;
+ dsi0_out: endpoint {
+ remote-endpoint = <&d2l_in_test>;
+ data-lanes = <0 1 2 3>;
+ };
+ };
+ };
+ };
+
+ - |
+ /* For dual-link LVDS display panel */
+
+ i2c@78b8000 {
+ /* On High speed expansion */
+ label = "HS-I2C2";
+ reg = <0x078b8000 0x500>;
+ clock-frequency = <400000>; /* fastmode operation */
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tc_bridge_dual: bridge@f {
+ compatible = "toshiba,tc358775";
+ reg = <0x0f>;
+
+ vdd-supply = <&pm8916_l2>;
+ vddio-supply = <&pm8916_l6>;
+
+ stby-gpios = <&msmgpio 99 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&msmgpio 72 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ d2l_in_dual: endpoint {
+ remote-endpoint = <&dsi0_out_dual>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in0>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ lvds1_out: endpoint {
+ remote-endpoint = <&panel_in1>;
+ };
+ };
+ };
+ };
+ };
+
+ dsi@1a98000 {
+ reg = <0x1a98000 0x25c>;
+ reg-names = "dsi_ctrl";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@1 {
+ reg = <1>;
+ dsi0_out_dual: endpoint {
+ remote-endpoint = <&d2l_in_dual>;
+ data-lanes = <0 1 2 3>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml
index 76a9068a85dd..c60b3bd74337 100644
--- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml
+++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml
@@ -13,7 +13,9 @@ properties:
compatible:
items:
- enum:
- - bananapi,lhr050h41
+ - bananapi,lhr050h41
+ - feixin,k101-im2byl02
+
- const: ilitek,ili9881c
backlight: true
diff --git a/Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml b/Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml
new file mode 100644
index 000000000000..937323cc9aaa
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/mantix,mlaf057we51-x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mantix MLAF057WE51-X 5.7" 720x1440 TFT LCD panel
+
+maintainers:
+ - Guido Günther <agx@sigxcpu.org>
+
+description:
+ Mantix MLAF057WE51 X is a 720x1440 TFT LCD panel connected using
+ a MIPI-DSI video interface.
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - mantix,mlaf057we51-x
+
+ port: true
+ reg:
+ maxItems: 1
+ description: DSI virtual channel
+
+ avdd-supply:
+ description: Positive analog power supply
+
+ avee-supply:
+ description: Negative analog power supply
+
+ vddi-supply:
+ description: 1.8V I/O voltage supply
+
+ reset-gpios: true
+
+ backlight: true
+
+required:
+ - compatible
+ - reg
+ - avdd-supply
+ - avee-supply
+ - vddi-supply
+ - reset-gpios
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ panel@0 {
+ compatible = "mantix,mlaf057we51-x";
+ reg = <0>;
+ avdd-supply = <&reg_avdd>;
+ avee-supply = <&reg_avee>;
+ vddi-supply = <&reg_1v8_p>;
+ reset-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>;
+ backlight = <&backlight>;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
index 6deeeed59e59..f2204f17a9dc 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
+++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
@@ -87,6 +87,8 @@ properties:
- cdtech,s070swv29hg-dc44
# CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel
- cdtech,s070wv95-ct16
+ # Chefree CH101OLHLWH-002 10.1" (1280x800) color TFT LCD panel
+ - chefree,ch101olhlwh-002
# Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel
- chunghwa,claa070wp03xg
# Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
@@ -159,6 +161,8 @@ properties:
- innolux,n156bge-l21
# Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel
- innolux,zj070na-01p
+ # King & Display KD116N21-30NV-A010 eDP TFT LCD panel
+ - kingdisplay,kd116n21-30nv-a010
# Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel
- koe,tx14d24vm1bpa
# Kaohsiung Opto-Electronics Inc. 10.1" WUXGA (1920 x 1200) LVDS TFT LCD panel
@@ -219,6 +223,8 @@ properties:
- osddisplays,osd070t1718-19ts
# One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel
- osddisplays,osd101t2045-53ts
+ # POWERTIP PH800480T013-IDF2 7.0" WVGA TFT LCD panel
+ - powertip,ph800480t013-idf02
# QiaoDian XianShi Corporation 4"3 TFT LCD panel
- qiaodian,qd43003c0-40
# Rocktech Displays Ltd. RK101II01D-CT 10.1" TFT 1280x800
diff --git a/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml b/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml
index d5733ef30954..09b5eb7542f8 100644
--- a/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml
+++ b/Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml
@@ -8,10 +8,11 @@ title: Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel
maintainers:
- Ondrej Jirman <megi@xff.cz>
+ - Guido Gŭnther <agx@sigxcpu.org>
-description: |
- Rocktech JH057N00900 is a 720x1440 TFT LCD panel
- connected using a MIPI-DSI video interface.
+description:
+ Rocktech JH057N00900 is a 720x1440 TFT LCD panel
+ connected using a MIPI-DSI video interface.
allOf:
- $ref: panel-common.yaml#
@@ -19,9 +20,9 @@ allOf:
properties:
compatible:
enum:
- # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel
+ # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel
- rocktech,jh057n00900
- # Xingbangda XBD599 5.99" 720x1440 TFT LCD panel
+ # Xingbangda XBD599 5.99" 720x1440 TFT LCD panel
- xingbangda,xbd599
port: true
@@ -35,13 +36,9 @@ properties:
iovcc-supply:
description: I/O voltage supply
- reset-gpios:
- description: GPIO used for the reset pin
- maxItems: 1
+ reset-gpios: true
- backlight:
- description: Backlight used by the panel
- $ref: "/schemas/types.yaml#/definitions/phandle"
+ backlight: true
required:
- compatible
@@ -57,15 +54,16 @@ examples:
#include <dt-bindings/gpio/gpio.h>
dsi {
- #address-cells = <1>;
- #size-cells = <0>;
- panel@0 {
- compatible = "rocktech,jh057n00900";
- reg = <0>;
- vcc-supply = <&reg_2v8_p>;
- iovcc-supply = <&reg_1v8_p>;
- reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>;
- backlight = <&backlight>;
- };
+ #address-cells = <1>;
+ #size-cells = <0>;
+ panel@0 {
+ compatible = "rocktech,jh057n00900";
+ reg = <0>;
+ vcc-supply = <&reg_2v8_p>;
+ iovcc-supply = <&reg_1v8_p>;
+ reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>;
+ backlight = <&backlight>;
+ };
};
+
...
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 63996ab03521..8f27994d4497 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -197,6 +197,8 @@ patternProperties:
description: Ceva, Inc.
"^checkpoint,.*":
description: Check Point Software Technologies Ltd.
+ "^chefree,.*":
+ description: Chefree Technology Corp.
"^chipidea,.*":
description: Chipidea, Inc
"^chipone,.*":
@@ -601,6 +603,8 @@ patternProperties:
description: Logic Technologies Limited
"^longcheer,.*":
description: Longcheer Technology (Shanghai) Co., Ltd.
+ "^lontium,.*":
+ description: Lontium Semiconductor Corporation
"^loongson,.*":
description: Loongson Technology Corporation Limited
"^lsi,.*":
@@ -611,6 +615,8 @@ patternProperties:
description: Linux Automation GmbH
"^macnica,.*":
description: Macnica Americas
+ "^mantix,.*":
+ description: Mantix Display Technology Co.,Ltd.
"^mapleboard,.*":
description: Mapleboard.org
"^marvell,.*":
@@ -830,6 +836,8 @@ patternProperties:
description: Poslab Technology Co., Ltd.
"^pov,.*":
description: Point of View International B.V.
+ "^powertip,.*":
+ description: Powertip Tech. Corp.
"^powervr,.*":
description: PowerVR (deprecated, use img)
"^primux,.*":
diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst
index 496d8fcd4da0..7dce175f6d75 100644
--- a/Documentation/gpu/drm-uapi.rst
+++ b/Documentation/gpu/drm-uapi.rst
@@ -1,3 +1,5 @@
+.. Copyright 2020 DisplayLink (UK) Ltd.
+
===================
Userland interfaces
===================
@@ -162,6 +164,116 @@ other hand, a driver requires shared state between clients which is
visible to user-space and accessible beyond open-file boundaries, they
cannot support render nodes.
+Device Hot-Unplug
+=================
+
+.. note::
+ The following is the plan. Implementation is not there yet
+ (2020 May).
+
+Graphics devices (display and/or render) may be connected via USB (e.g.
+display adapters or docking stations) or Thunderbolt (e.g. eGPU). An end
+user is able to hot-unplug this kind of devices while they are being
+used, and expects that the very least the machine does not crash. Any
+damage from hot-unplugging a DRM device needs to be limited as much as
+possible and userspace must be given the chance to handle it if it wants
+to. Ideally, unplugging a DRM device still lets a desktop continue to
+run, but that is going to need explicit support throughout the whole
+graphics stack: from kernel and userspace drivers, through display
+servers, via window system protocols, and in applications and libraries.
+
+Other scenarios that should lead to the same are: unrecoverable GPU
+crash, PCI device disappearing off the bus, or forced unbind of a driver
+from the physical device.
+
+In other words, from userspace perspective everything needs to keep on
+working more or less, until userspace stops using the disappeared DRM
+device and closes it completely. Userspace will learn of the device
+disappearance from the device removed uevent, ioctls returning ENODEV
+(or driver-specific ioctls returning driver-specific things), or open()
+returning ENXIO.
+
+Only after userspace has closed all relevant DRM device and dmabuf file
+descriptors and removed all mmaps, the DRM driver can tear down its
+instance for the device that no longer exists. If the same physical
+device somehow comes back in the mean time, it shall be a new DRM
+device.
+
+Similar to PIDs, chardev minor numbers are not recycled immediately. A
+new DRM device always picks the next free minor number compared to the
+previous one allocated, and wraps around when minor numbers are
+exhausted.
+
+The goal raises at least the following requirements for the kernel and
+drivers.
+
+Requirements for KMS UAPI
+-------------------------
+
+- KMS connectors must change their status to disconnected.
+
+- Legacy modesets and pageflips, and atomic commits, both real and
+ TEST_ONLY, and any other ioctls either fail with ENODEV or fake
+ success.
+
+- Pending non-blocking KMS operations deliver the DRM events userspace
+ is expecting. This applies also to ioctls that faked success.
+
+- open() on a device node whose underlying device has disappeared will
+ fail with ENXIO.
+
+- Attempting to create a DRM lease on a disappeared DRM device will
+ fail with ENODEV. Existing DRM leases remain and work as listed
+ above.
+
+Requirements for Render and Cross-Device UAPI
+---------------------------------------------
+
+- All GPU jobs that can no longer run must have their fences
+ force-signalled to avoid inflicting hangs on userspace.
+ The associated error code is ENODEV.
+
+- Some userspace APIs already define what should happen when the device
+ disappears (OpenGL, GL ES: `GL_KHR_robustness`_; `Vulkan`_:
+ VK_ERROR_DEVICE_LOST; etc.). DRM drivers are free to implement this
+ behaviour the way they see best, e.g. returning failures in
+ driver-specific ioctls and handling those in userspace drivers, or
+ rely on uevents, and so on.
+
+- dmabuf which point to memory that has disappeared will either fail to
+ import with ENODEV or continue to be successfully imported if it would
+ have succeeded before the disappearance. See also about memory maps
+ below for already imported dmabufs.
+
+- Attempting to import a dmabuf to a disappeared device will either fail
+ with ENODEV or succeed if it would have succeeded without the
+ disappearance.
+
+- open() on a device node whose underlying device has disappeared will
+ fail with ENXIO.
+
+.. _GL_KHR_robustness: https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_robustness.txt
+.. _Vulkan: https://www.khronos.org/vulkan/
+
+Requirements for Memory Maps
+----------------------------
+
+Memory maps have further requirements that apply to both existing maps
+and maps created after the device has disappeared. If the underlying
+memory disappears, the map is created or modified such that reads and
+writes will still complete successfully but the result is undefined.
+This applies to both userspace mmap()'d memory and memory pointed to by
+dmabuf which might be mapped to other devices (cross-device dmabuf
+imports).
+
+Raising SIGBUS is not an option, because userspace cannot realistically
+handle it. Signal handlers are global, which makes them extremely
+difficult to use correctly from libraries like those that Mesa produces.
+Signal handlers are not composable, you can't have different handlers
+for GPU1 and GPU2 from different vendors, and a third handler for
+mmapped regular files. Threads cause additional pain with signal
+handling as well.
+
.. _drm_driver_ioctl:
IOCTL Support on Device Nodes
@@ -199,7 +311,7 @@ EPERM/EACCES:
difference between EACCES and EPERM.
ENODEV:
- The device is not (yet) present or fully initialized.
+ The device is not present anymore or is not yet fully initialized.
EOPNOTSUPP:
Feature (like PRIME, modesetting, GEM) is not supported by the driver.
diff --git a/Documentation/gpu/pl111.rst b/Documentation/gpu/pl111.rst
index 9b03736d33dd..6d9a1b59a545 100644
--- a/Documentation/gpu/pl111.rst
+++ b/Documentation/gpu/pl111.rst
@@ -1,6 +1,6 @@
-==========================================
- drm/pl111 ARM PrimeCell PL111 CLCD Driver
-==========================================
+====================================================
+ drm/pl111 ARM PrimeCell PL110 and PL111 CLCD Driver
+====================================================
.. kernel-doc:: drivers/gpu/drm/pl111/pl111_drv.c
- :doc: ARM PrimeCell PL111 CLCD Driver
+ :doc: ARM PrimeCell PL110 and PL111 CLCD Driver
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 7969f106877d..b0ea17da8ff6 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -403,6 +403,52 @@ Contact: Emil Velikov, respective driver maintainers
Level: Intermediate
+Plumb drm_atomic_state all over
+-------------------------------
+
+Currently various atomic functions take just a single or a handful of
+object states (eg. plane state). While that single object state can
+suffice for some simple cases, we often have to dig out additional
+object states for dealing with various dependencies between the individual
+objects or the hardware they represent. The process of digging out the
+additional states is rather non-intuitive and error prone.
+
+To fix that most functions should rather take the overall
+drm_atomic_state as one of their parameters. The other parameters
+would generally be the object(s) we mainly want to interact with.
+
+For example, instead of
+
+.. code-block:: c
+
+ int (*atomic_check)(struct drm_plane *plane, struct drm_plane_state *state);
+
+we would have something like
+
+.. code-block:: c
+
+ int (*atomic_check)(struct drm_plane *plane, struct drm_atomic_state *state);
+
+The implementation can then trivially gain access to any required object
+state(s) via drm_atomic_get_plane_state(), drm_atomic_get_new_plane_state(),
+drm_atomic_get_old_plane_state(), and their equivalents for
+other object types.
+
+Additionally many drivers currently access the object->state pointer
+directly in their commit functions. That is not going to work if we
+eg. want to allow deeper commit pipelines as those pointers could
+then point to the states corresponding to a future commit instead of
+the current commit we're trying to process. Also non-blocking commits
+execute locklessly so there are serious concerns with dereferencing
+the object->state pointers without holding the locks that protect them.
+Use of drm_atomic_get_new_plane_state(), drm_atomic_get_old_plane_state(),
+etc. avoids these problems as well since they relate to a specific
+commit via the passed in drm_atomic_state.
+
+Contact: Ville Syrjälä, Daniel Vetter
+
+Level: Intermediate
+
Core refactorings
=================
diff --git a/MAINTAINERS b/MAINTAINERS
index b5cfab015bd6..a2fc087b7d37 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5493,12 +5493,19 @@ S: Maintained
F: drivers/gpu/drm/panel/panel-lvds.c
F: Documentation/devicetree/bindings/display/panel/lvds.yaml
+DRM DRIVER FOR MANTIX MLAF057WE51 PANELS
+M: Guido Günther <agx@sigxcpu.org>
+R: Purism Kernel Team <kernel@puri.sm>
+S: Maintained
+F: Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml
+F: drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c
+
DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS
S: Orphan / Obsolete
F: drivers/gpu/drm/mga/
F: include/uapi/drm/mga_drm.h
-DRM DRIVER FOR MGA G200 SERVER GRAPHICS CHIPS
+DRM DRIVER FOR MGA G200 GRAPHICS CHIPS
M: Dave Airlie <airlied@redhat.com>
S: Odd Fixes
F: drivers/gpu/drm/mgag200/
@@ -5786,7 +5793,7 @@ F: drivers/gpu/drm/gma500/
DRM DRIVERS FOR HISILICON
M: Xinliang Liu <xinliang.liu@linaro.org>
-M: Rongrong Zou <zourongrong@gmail.com>
+M: Tian Tao <tiantao6@hisilicon.com>
R: John Stultz <john.stultz@linaro.org>
R: Xinwei Kong <kong.kongxinwei@hisilicon.com>
R: Chen Feng <puck.chen@hisilicon.com>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 1b865fed74ca..478f67498a17 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -517,8 +517,9 @@ out_put:
uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd)
{
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
+ struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
- return amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+ return amdgpu_vram_mgr_usage(vram_man);
}
uint64_t amdgpu_amdkfd_get_hive_id(struct kgd_dev *kgd)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index a58af513c952..aa2b328c6202 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -562,7 +562,7 @@ static int init_user_pages(struct kgd_mem *mem, uint64_t user_addr)
mutex_lock(&process_info->lock);
- ret = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, user_addr, 0);
+ ret = amdgpu_ttm_tt_set_userptr(&bo->tbo, user_addr, 0);
if (ret) {
pr_err("%s: Failed to set userptr: %d\n", __func__, ret);
goto out;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index a1aec205435d..93160a849af4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -26,6 +26,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_dp_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include "amdgpu.h"
@@ -1413,6 +1414,10 @@ out:
pm_runtime_put_autosuspend(connector->dev->dev);
}
+ drm_dp_set_subconnector_property(&amdgpu_connector->base,
+ ret,
+ amdgpu_dig_connector->dpcd,
+ amdgpu_dig_connector->downstream_ports);
return ret;
}
@@ -1959,6 +1964,11 @@ amdgpu_connector_add(struct amdgpu_device *adev,
if (has_aux)
amdgpu_atombios_dp_aux_init(amdgpu_connector);
+ if (connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_type == DRM_MODE_CONNECTOR_eDP) {
+ drm_connector_attach_dp_subconnector_property(&amdgpu_connector->base);
+ }
+
return;
failed:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index a512ccbc4dea..ecd051976bce 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -299,7 +299,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
{
s64 time_us, increment_us;
u64 free_vram, total_vram, used_vram;
-
+ struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
/* Allow a maximum of 200 accumulated ms. This is basically per-IB
* throttling.
*
@@ -316,7 +316,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
}
total_vram = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size);
- used_vram = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+ used_vram = amdgpu_vram_mgr_usage(vram_man);
free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram;
spin_lock(&adev->mm_stats.lock);
@@ -363,7 +363,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) {
u64 total_vis_vram = adev->gmc.visible_vram_size;
u64 used_vis_vram =
- amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+ amdgpu_vram_mgr_vis_usage(vram_man);
if (used_vis_vram < total_vis_vram) {
u64 free_vis_vram = total_vis_vram - used_vis_vram;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index eb7cfe87042e..4204cda680f5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3882,7 +3882,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
amdgpu_virt_init_data_exchange(adev);
/* we need recover gart prior to run SMC/CP/SDMA resume */
- amdgpu_gtt_mgr_recover(&adev->mman.bdev.man[TTM_PL_TT]);
+ amdgpu_gtt_mgr_recover(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT));
r = amdgpu_device_fw_loading(adev);
if (r)
@@ -4081,8 +4081,7 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive,
amdgpu_inc_vram_lost(tmp_adev);
}
- r = amdgpu_gtt_mgr_recover(
- &tmp_adev->mman.bdev.man[TTM_PL_TT]);
+ r = amdgpu_gtt_mgr_recover(ttm_manager_type(&tmp_adev->mman.bdev, TTM_PL_TT));
if (r)
goto out;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 26127c7d2f32..81a79760ca61 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -393,12 +393,12 @@ MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default
module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444);
/**
- * DOC: ppfeaturemask (uint)
+ * DOC: ppfeaturemask (hexint)
* Override power features enabled. See enum PP_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h.
* The default is the current set of stable power features.
*/
MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))");
-module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, uint, 0444);
+module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, hexint, 0444);
/**
* DOC: forcelongtraining (uint)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 7f9e50247413..6b1eb9d045ae 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -332,7 +332,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
bo = gem_to_amdgpu_bo(gobj);
bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT;
bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT;
- r = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags);
+ r = amdgpu_ttm_tt_set_userptr(&bo->tbo, args->addr, args->flags);
if (r)
goto release_object;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
index 77fae40197ab..697bc2c6fdb2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
@@ -24,11 +24,10 @@
#include "amdgpu.h"
-struct amdgpu_gtt_mgr {
- struct drm_mm mm;
- spinlock_t lock;
- atomic64_t available;
-};
+static inline struct amdgpu_gtt_mgr *to_gtt_mgr(struct ttm_resource_manager *man)
+{
+ return container_of(man, struct amdgpu_gtt_mgr, manager);
+}
struct amdgpu_gtt_node {
struct drm_mm_node node;
@@ -48,9 +47,9 @@ static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
-
+ struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
return snprintf(buf, PAGE_SIZE, "%llu\n",
- (adev->mman.bdev.man[TTM_PL_TT].size) * PAGE_SIZE);
+ man->size * PAGE_SIZE);
}
/**
@@ -66,9 +65,9 @@ static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
-
+ struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
return snprintf(buf, PAGE_SIZE, "%llu\n",
- amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]));
+ amdgpu_gtt_mgr_usage(man));
}
static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
@@ -76,6 +75,7 @@ static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO,
amdgpu_mem_info_gtt_used_show, NULL);
+static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func;
/**
* amdgpu_gtt_mgr_init - init GTT manager and DRM MM
*
@@ -84,24 +84,25 @@ static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO,
*
* Allocate and initialize the GTT manager.
*/
-static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
- unsigned long p_size)
+int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size)
{
- struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
- struct amdgpu_gtt_mgr *mgr;
+ struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
+ struct ttm_resource_manager *man = &mgr->manager;
uint64_t start, size;
int ret;
- mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
- if (!mgr)
- return -ENOMEM;
+ man->use_tt = true;
+ man->func = &amdgpu_gtt_mgr_func;
+ man->available_caching = TTM_PL_MASK_CACHING;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+
+ ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT);
start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS;
size = (adev->gmc.gart_size >> PAGE_SHIFT) - start;
drm_mm_init(&mgr->mm, start, size);
spin_lock_init(&mgr->lock);
- atomic64_set(&mgr->available, p_size);
- man->priv = mgr;
+ atomic64_set(&mgr->available, gtt_size >> PAGE_SHIFT);
ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_total);
if (ret) {
@@ -114,6 +115,8 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
return ret;
}
+ ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager);
+ ttm_resource_manager_set_used(man, true);
return 0;
}
@@ -125,20 +128,27 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
* Destroy and free the GTT manager, returns -EBUSY if ranges are still
* allocated inside it.
*/
-static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
+void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev)
{
- struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
- struct amdgpu_gtt_mgr *mgr = man->priv;
+ struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
+ struct ttm_resource_manager *man = &mgr->manager;
+ int ret;
+
+ ttm_resource_manager_set_used(man, false);
+
+ ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man);
+ if (ret)
+ return;
+
spin_lock(&mgr->lock);
drm_mm_takedown(&mgr->mm);
spin_unlock(&mgr->lock);
- kfree(mgr);
- man->priv = NULL;
device_remove_file(adev->dev, &dev_attr_mem_info_gtt_total);
device_remove_file(adev->dev, &dev_attr_mem_info_gtt_used);
- return 0;
+ ttm_resource_manager_cleanup(man);
+ ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL);
}
/**
@@ -148,7 +158,7 @@ static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
*
* Check if a mem object has already address space allocated.
*/
-bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem)
+bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem)
{
return mem->mm_node != NULL;
}
@@ -163,12 +173,12 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem)
*
* Dummy, allocate the node but no space for it yet.
*/
-static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
+static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *tbo,
const struct ttm_place *place,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
- struct amdgpu_gtt_mgr *mgr = man->priv;
+ struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
struct amdgpu_gtt_node *node;
int r;
@@ -226,10 +236,10 @@ err_out:
*
* Free the allocated GTT again.
*/
-static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man,
- struct ttm_mem_reg *mem)
+static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
+ struct ttm_resource *mem)
{
- struct amdgpu_gtt_mgr *mgr = man->priv;
+ struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
struct amdgpu_gtt_node *node = mem->mm_node;
if (node) {
@@ -249,17 +259,17 @@ static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man,
*
* Return how many bytes are used in the GTT domain
*/
-uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man)
+uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man)
{
- struct amdgpu_gtt_mgr *mgr = man->priv;
+ struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
s64 result = man->size - atomic64_read(&mgr->available);
return (result > 0 ? result : 0) * PAGE_SIZE;
}
-int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man)
+int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man)
{
- struct amdgpu_gtt_mgr *mgr = man->priv;
+ struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
struct amdgpu_gtt_node *node;
struct drm_mm_node *mm_node;
int r = 0;
@@ -284,10 +294,10 @@ int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man)
*
* Dump the table content using printk.
*/
-static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man,
+static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man,
struct drm_printer *printer)
{
- struct amdgpu_gtt_mgr *mgr = man->priv;
+ struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
spin_lock(&mgr->lock);
drm_mm_print(&mgr->mm, printer);
@@ -298,10 +308,8 @@ static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man,
amdgpu_gtt_mgr_usage(man) >> 20);
}
-const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = {
- .init = amdgpu_gtt_mgr_init,
- .takedown = amdgpu_gtt_mgr_fini,
- .get_node = amdgpu_gtt_mgr_new,
- .put_node = amdgpu_gtt_mgr_del,
+static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = {
+ .alloc = amdgpu_gtt_mgr_new,
+ .free = amdgpu_gtt_mgr_del,
.debug = amdgpu_gtt_mgr_debug
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 414548064648..95f6ebc6ea12 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -595,13 +595,13 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
ui64 = atomic64_read(&adev->num_vram_cpu_page_faults);
return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
case AMDGPU_INFO_VRAM_USAGE:
- ui64 = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+ ui64 = amdgpu_vram_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM));
return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
case AMDGPU_INFO_VIS_VRAM_USAGE:
- ui64 = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+ ui64 = amdgpu_vram_mgr_vis_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM));
return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
case AMDGPU_INFO_GTT_USAGE:
- ui64 = amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]);
+ ui64 = amdgpu_gtt_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT));
return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
case AMDGPU_INFO_GDS_CONFIG: {
struct drm_amdgpu_info_gds gds_info;
@@ -624,7 +624,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
min(adev->gmc.visible_vram_size -
atomic64_read(&adev->visible_pin_size),
vram_gtt.vram_size);
- vram_gtt.gtt_size = adev->mman.bdev.man[TTM_PL_TT].size;
+ vram_gtt.gtt_size = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)->size;
vram_gtt.gtt_size *= PAGE_SIZE;
vram_gtt.gtt_size -= atomic64_read(&adev->gart_pin_size);
return copy_to_user(out, &vram_gtt,
@@ -632,14 +632,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
}
case AMDGPU_INFO_MEMORY: {
struct drm_amdgpu_memory_info mem;
-
+ struct ttm_resource_manager *vram_man =
+ ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
+ struct ttm_resource_manager *gtt_man =
+ ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
memset(&mem, 0, sizeof(mem));
mem.vram.total_heap_size = adev->gmc.real_vram_size;
mem.vram.usable_heap_size = adev->gmc.real_vram_size -
atomic64_read(&adev->vram_pin_size) -
AMDGPU_VM_RESERVED_VRAM;
mem.vram.heap_usage =
- amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+ amdgpu_vram_mgr_usage(vram_man);
mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4;
mem.cpu_accessible_vram.total_heap_size =
@@ -649,16 +652,16 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
atomic64_read(&adev->visible_pin_size),
mem.vram.usable_heap_size);
mem.cpu_accessible_vram.heap_usage =
- amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+ amdgpu_vram_mgr_vis_usage(vram_man);
mem.cpu_accessible_vram.max_allocation =
mem.cpu_accessible_vram.usable_heap_size * 3 / 4;
- mem.gtt.total_heap_size = adev->mman.bdev.man[TTM_PL_TT].size;
+ mem.gtt.total_heap_size = gtt_man->size;
mem.gtt.total_heap_size *= PAGE_SIZE;
mem.gtt.usable_heap_size = mem.gtt.total_heap_size -
atomic64_read(&adev->gart_pin_size);
mem.gtt.heap_usage =
- amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]);
+ amdgpu_gtt_mgr_usage(gtt_man);
mem.gtt.max_allocation = mem.gtt.usable_heap_size * 3 / 4;
return copy_to_user(out, &mem,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 37ba07e2feb5..04a430e0e2e1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -469,6 +469,7 @@ struct amdgpu_encoder {
struct amdgpu_connector_atom_dig {
/* displayport */
u8 dpcd[DP_RECEIVER_CAP_SIZE];
+ u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
u8 dp_sink_type;
int dp_clock;
int dp_lane_count;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 5ac7b5561475..b36d94f57d42 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -381,7 +381,7 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
if (cpu_addr)
amdgpu_bo_kunmap(*bo_ptr);
- ttm_bo_mem_put(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem);
+ ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem);
for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) {
(*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT;
@@ -442,14 +442,14 @@ void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr,
static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
unsigned long size, u32 domain)
{
- struct ttm_mem_type_manager *man = NULL;
+ struct ttm_resource_manager *man = NULL;
/*
* If GTT is part of requested domains the check must succeed to
* allow fall back to GTT
*/
if (domain & AMDGPU_GEM_DOMAIN_GTT) {
- man = &adev->mman.bdev.man[TTM_PL_TT];
+ man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
if (size < (man->size << PAGE_SHIFT))
return true;
@@ -458,7 +458,7 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
}
if (domain & AMDGPU_GEM_DOMAIN_VRAM) {
- man = &adev->mman.bdev.man[TTM_PL_VRAM];
+ man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
if (size < (man->size << PAGE_SHIFT))
return true;
@@ -1268,11 +1268,11 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
*/
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
bool evict,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
struct amdgpu_bo *abo;
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
if (!amdgpu_bo_is_amdgpu_bo(bo))
return;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
index afa5189dba7d..5ddb6cf96030 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -160,7 +160,7 @@ static inline int amdgpu_bo_reserve(struct amdgpu_bo *bo, bool no_intr)
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
int r;
- r = __ttm_bo_reserve(&bo->tbo, !no_intr, false, NULL);
+ r = ttm_bo_reserve(&bo->tbo, !no_intr, false, NULL);
if (unlikely(r != 0)) {
if (r != -ERESTARTSYS)
dev_err(adev->dev, "%p reserve failed\n", bo);
@@ -283,7 +283,7 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
uint64_t *flags);
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
bool evict,
- struct ttm_mem_reg *new_mem);
+ struct ttm_resource *new_mem);
void amdgpu_bo_release_notify(struct ttm_buffer_object *bo);
int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index e11c5d69843d..fc5f7ac53d0a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -63,61 +63,13 @@
#define AMDGPU_TTM_VRAM_MAX_DW_READ (size_t)128
-
-/**
- * amdgpu_init_mem_type - Initialize a memory manager for a specific type of
- * memory request.
- *
- * @bdev: The TTM BO device object (contains a reference to amdgpu_device)
- * @type: The type of memory requested
- * @man: The memory type manager for each domain
- *
- * This is called by ttm_bo_init_mm() when a buffer object is being
- * initialized.
- */
-static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
- struct ttm_mem_type_manager *man)
+static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev,
+ unsigned int type,
+ uint64_t size)
{
- struct amdgpu_device *adev;
-
- adev = amdgpu_ttm_adev(bdev);
-
- switch (type) {
- case TTM_PL_SYSTEM:
- /* System memory */
- man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- case TTM_PL_TT:
- /* GTT memory */
- man->func = &amdgpu_gtt_mgr_func;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
- break;
- case TTM_PL_VRAM:
- /* "On-card" video ram */
- man->func = &amdgpu_vram_mgr_func;
- man->flags = TTM_MEMTYPE_FLAG_FIXED |
- TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
- man->default_caching = TTM_PL_FLAG_WC;
- break;
- case AMDGPU_PL_GDS:
- case AMDGPU_PL_GWS:
- case AMDGPU_PL_OA:
- /* On-chip GDS memory*/
- man->func = &ttm_bo_manager_func;
- man->flags = TTM_MEMTYPE_FLAG_FIXED;
- man->available_caching = TTM_PL_FLAG_UNCACHED;
- man->default_caching = TTM_PL_FLAG_UNCACHED;
- break;
- default:
- DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
- return -EINVAL;
- }
- return 0;
+ return ttm_range_man_init(&adev->mman.bdev, type,
+ TTM_PL_FLAG_UNCACHED, TTM_PL_FLAG_UNCACHED,
+ false, size >> PAGE_SHIFT);
}
/**
@@ -231,9 +183,9 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp)
* Assign the memory from new_mem to the memory of the buffer object bo.
*/
static void amdgpu_move_null(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
BUG_ON(old_mem->mm_node != NULL);
*old_mem = *new_mem;
@@ -250,7 +202,7 @@ static void amdgpu_move_null(struct ttm_buffer_object *bo,
*/
static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo,
struct drm_mm_node *mm_node,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
uint64_t addr = 0;
@@ -270,7 +222,7 @@ static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo,
* @offset: The offset that drm_mm_node is used for finding.
*
*/
-static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem,
+static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_resource *mem,
uint64_t *offset)
{
struct drm_mm_node *mm_node = mem->mm_node;
@@ -298,7 +250,7 @@ static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem,
* the physical address for local memory.
*/
static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
struct drm_mm_node *mm_node,
unsigned num_pages, uint64_t offset,
unsigned window, struct amdgpu_ring *ring,
@@ -522,8 +474,8 @@ error:
*/
static int amdgpu_move_blit(struct ttm_buffer_object *bo,
bool evict, bool no_wait_gpu,
- struct ttm_mem_reg *new_mem,
- struct ttm_mem_reg *old_mem)
+ struct ttm_resource *new_mem,
+ struct ttm_resource *old_mem)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
@@ -582,10 +534,10 @@ error:
*/
static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
- struct ttm_mem_reg *old_mem = &bo->mem;
- struct ttm_mem_reg tmp_mem;
+ struct ttm_resource *old_mem = &bo->mem;
+ struct ttm_resource tmp_mem;
struct ttm_place placements;
struct ttm_placement placement;
int r;
@@ -627,7 +579,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict,
/* move BO (in tmp_mem) to new_mem */
r = ttm_bo_move_ttm(bo, ctx, new_mem);
out_cleanup:
- ttm_bo_mem_put(bo, &tmp_mem);
+ ttm_resource_free(bo, &tmp_mem);
return r;
}
@@ -638,10 +590,10 @@ out_cleanup:
*/
static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
- struct ttm_mem_reg *old_mem = &bo->mem;
- struct ttm_mem_reg tmp_mem;
+ struct ttm_resource *old_mem = &bo->mem;
+ struct ttm_resource tmp_mem;
struct ttm_placement placement;
struct ttm_place placements;
int r;
@@ -674,7 +626,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict,
goto out_cleanup;
}
out_cleanup:
- ttm_bo_mem_put(bo, &tmp_mem);
+ ttm_resource_free(bo, &tmp_mem);
return r;
}
@@ -684,7 +636,7 @@ out_cleanup:
* Called by amdgpu_bo_move()
*/
static bool amdgpu_mem_visible(struct amdgpu_device *adev,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
struct drm_mm_node *nodes = mem->mm_node;
@@ -694,7 +646,7 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev,
if (mem->mem_type != TTM_PL_VRAM)
return false;
- /* ttm_mem_reg_ioremap only supports contiguous memory */
+ /* ttm_resource_ioremap only supports contiguous memory */
if (nodes->size != mem->num_pages)
return false;
@@ -709,11 +661,11 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev,
*/
static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct amdgpu_device *adev;
struct amdgpu_bo *abo;
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
int r;
/* Can't move a pinned BO */
@@ -795,19 +747,12 @@ memcpy:
*
* Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault()
*/
-static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
{
- struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
struct drm_mm_node *mm_node = mem->mm_node;
+ size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
- mem->bus.addr = NULL;
- mem->bus.offset = 0;
- mem->bus.size = mem->num_pages << PAGE_SHIFT;
- mem->bus.base = 0;
- mem->bus.is_iomem = false;
- if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
- return -EINVAL;
switch (mem->mem_type) {
case TTM_PL_SYSTEM:
/* system memory */
@@ -817,11 +762,11 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
case TTM_PL_VRAM:
mem->bus.offset = mem->start << PAGE_SHIFT;
/* check if it's visible */
- if ((mem->bus.offset + mem->bus.size) > adev->gmc.visible_vram_size)
+ if ((mem->bus.offset + bus_size) > adev->gmc.visible_vram_size)
return -EINVAL;
/* Only physically contiguous buffers apply. In a contiguous
* buffer, size of the first mm_node would match the number of
- * pages in ttm_mem_reg.
+ * pages in ttm_resource.
*/
if (adev->mman.aper_base_kaddr &&
(mm_node->size == mem->num_pages))
@@ -1166,7 +1111,7 @@ gart_bind_fail:
* This handles binding GTT memory to the device address space.
*/
static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
- struct ttm_mem_reg *bo_mem)
+ struct ttm_resource *bo_mem)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev);
struct amdgpu_ttm_tt *gtt = (void*)ttm;
@@ -1217,7 +1162,7 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
struct ttm_operation_ctx ctx = { false, false };
struct amdgpu_ttm_tt *gtt = (void*)bo->ttm;
- struct ttm_mem_reg tmp;
+ struct ttm_resource tmp;
struct ttm_placement placement;
struct ttm_place placements;
uint64_t addr, flags;
@@ -1254,11 +1199,11 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
gtt->offset = (u64)tmp.start << PAGE_SHIFT;
r = amdgpu_ttm_gart_bind(adev, bo, flags);
if (unlikely(r)) {
- ttm_bo_mem_put(bo, &tmp);
+ ttm_resource_free(bo, &tmp);
return r;
}
- ttm_bo_mem_put(bo, &bo->mem);
+ ttm_resource_free(bo, &bo->mem);
bo->mem = tmp;
}
@@ -1457,21 +1402,26 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm)
* amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current
* task
*
- * @ttm: The ttm_tt object to bind this userptr object to
+ * @bo: The ttm_buffer_object to bind this userptr to
* @addr: The address in the current tasks VM space to use
* @flags: Requirements of userptr object.
*
* Called by amdgpu_gem_userptr_ioctl() to bind userptr pages
* to current task
*/
-int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
- uint32_t flags)
+int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
+ uint64_t addr, uint32_t flags)
{
- struct amdgpu_ttm_tt *gtt = (void *)ttm;
+ struct amdgpu_ttm_tt *gtt;
- if (gtt == NULL)
- return -EINVAL;
+ if (!bo->ttm) {
+ /* TODO: We want a separate TTM object type for userptrs */
+ bo->ttm = amdgpu_ttm_tt_create(bo, 0);
+ if (bo->ttm == NULL)
+ return -ENOMEM;
+ }
+ gtt = (void*)bo->ttm;
gtt->userptr = addr;
gtt->userflags = flags;
@@ -1557,7 +1507,7 @@ bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
*
* Figure out the flags to use for a VM PDE (Page Directory Entry).
*/
-uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
+uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem)
{
uint64_t flags = 0;
@@ -1583,7 +1533,7 @@ uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
* Figure out the flags to use for a VM PTE (Page Table Entry).
*/
uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
uint64_t flags = amdgpu_ttm_tt_pde_flags(ttm, mem);
@@ -1741,7 +1691,6 @@ static struct ttm_bo_driver amdgpu_bo_driver = {
.ttm_tt_create = &amdgpu_ttm_tt_create,
.ttm_tt_populate = &amdgpu_ttm_tt_populate,
.ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate,
- .init_mem_type = &amdgpu_init_mem_type,
.eviction_valuable = amdgpu_ttm_bo_eviction_valuable,
.evict_flags = &amdgpu_evict_flags,
.move = &amdgpu_bo_move,
@@ -1936,8 +1885,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
adev->mman.bdev.no_retry = true;
/* Initialize VRAM pool with all of VRAM divided into pages */
- r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM,
- adev->gmc.real_vram_size >> PAGE_SHIFT);
+ r = amdgpu_vram_mgr_init(adev);
if (r) {
DRM_ERROR("Failed initializing VRAM heap.\n");
return r;
@@ -2004,7 +1952,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
gtt_size = (uint64_t)amdgpu_gtt_size << 20;
/* Initialize GTT memory pool */
- r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_TT, gtt_size >> PAGE_SHIFT);
+ r = amdgpu_gtt_mgr_init(adev, gtt_size);
if (r) {
DRM_ERROR("Failed initializing GTT heap.\n");
return r;
@@ -2013,22 +1961,19 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
(unsigned)(gtt_size / (1024 * 1024)));
/* Initialize various on-chip memory pools */
- r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GDS,
- adev->gds.gds_size);
+ r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size);
if (r) {
DRM_ERROR("Failed initializing GDS heap.\n");
return r;
}
- r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GWS,
- adev->gds.gws_size);
+ r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size);
if (r) {
DRM_ERROR("Failed initializing gws heap.\n");
return r;
}
- r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_OA,
- adev->gds.oa_size);
+ r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size);
if (r) {
DRM_ERROR("Failed initializing oa heap.\n");
return r;
@@ -2064,11 +2009,11 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
iounmap(adev->mman.aper_base_kaddr);
adev->mman.aper_base_kaddr = NULL;
- ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_VRAM);
- ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_TT);
- ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GDS);
- ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS);
- ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA);
+ amdgpu_vram_mgr_fini(adev);
+ amdgpu_gtt_mgr_fini(adev);
+ ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS);
+ ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS);
+ ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA);
ttm_bo_device_release(&adev->mman.bdev);
adev->mman.initialized = false;
DRM_INFO("amdgpu: ttm finalized\n");
@@ -2085,7 +2030,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
*/
void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
{
- struct ttm_mem_type_manager *man = &adev->mman.bdev.man[TTM_PL_VRAM];
+ struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
uint64_t size;
int r;
@@ -2307,7 +2252,7 @@ static int amdgpu_mm_dump_table(struct seq_file *m, void *data)
unsigned ttm_pl = (uintptr_t)node->info_ent->data;
struct drm_device *dev = node->minor->dev;
struct amdgpu_device *adev = dev->dev_private;
- struct ttm_mem_type_manager *man = &adev->mman.bdev.man[ttm_pl];
+ struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, ttm_pl);
struct drm_printer p = drm_seq_file_printer(m);
man->func->debug(man, &p);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index 17c8d0d7bcc3..7ba2be37e6ba 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -41,6 +41,21 @@
#define AMDGPU_POISON 0xd0bed0be
+struct amdgpu_vram_mgr {
+ struct ttm_resource_manager manager;
+ struct drm_mm mm;
+ spinlock_t lock;
+ atomic64_t usage;
+ atomic64_t vis_usage;
+};
+
+struct amdgpu_gtt_mgr {
+ struct ttm_resource_manager manager;
+ struct drm_mm mm;
+ spinlock_t lock;
+ atomic64_t available;
+};
+
struct amdgpu_mman {
struct ttm_bo_device bdev;
bool mem_global_referenced;
@@ -59,24 +74,29 @@ struct amdgpu_mman {
struct mutex gtt_window_lock;
/* Scheduler entity for buffer moves */
struct drm_sched_entity entity;
+
+ struct amdgpu_vram_mgr vram_mgr;
+ struct amdgpu_gtt_mgr gtt_mgr;
};
struct amdgpu_copy_mem {
struct ttm_buffer_object *bo;
- struct ttm_mem_reg *mem;
+ struct ttm_resource *mem;
unsigned long offset;
};
-extern const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func;
-extern const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func;
+int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size);
+void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev);
+int amdgpu_vram_mgr_init(struct amdgpu_device *adev);
+void amdgpu_vram_mgr_fini(struct amdgpu_device *adev);
-bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem);
-uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man);
-int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man);
+bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem);
+uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man);
+int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man);
u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo);
int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
struct device *dev,
enum dma_data_direction dir,
struct sg_table **sgt);
@@ -84,8 +104,8 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
struct device *dev,
enum dma_data_direction dir,
struct sg_table *sgt);
-uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man);
-uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man);
+uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man);
+uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man);
int amdgpu_ttm_init(struct amdgpu_device *adev);
void amdgpu_ttm_late_init(struct amdgpu_device *adev);
@@ -130,8 +150,8 @@ static inline bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm)
#endif
void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages);
-int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
- uint32_t flags);
+int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
+ uint64_t addr, uint32_t flags);
bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm);
struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm);
bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
@@ -140,9 +160,9 @@ bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm,
int *last_invalidated);
bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm);
bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm);
-uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem);
+uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem);
uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 71e005cf2952..8bc2253939be 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1765,7 +1765,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
struct amdgpu_vm *vm = bo_va->base.vm;
struct amdgpu_bo_va_mapping *mapping;
dma_addr_t *pages_addr = NULL;
- struct ttm_mem_reg *mem;
+ struct ttm_resource *mem;
struct drm_mm_node *nodes;
struct dma_fence **last_update;
struct dma_resv *resv;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 0739e259bf91..a4154e203e78 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -28,12 +28,15 @@
#include "amdgpu_atomfirmware.h"
#include "atom.h"
-struct amdgpu_vram_mgr {
- struct drm_mm mm;
- spinlock_t lock;
- atomic64_t usage;
- atomic64_t vis_usage;
-};
+static inline struct amdgpu_vram_mgr *to_vram_mgr(struct ttm_resource_manager *man)
+{
+ return container_of(man, struct amdgpu_vram_mgr, manager);
+}
+
+static inline struct amdgpu_device *to_amdgpu_device(struct amdgpu_vram_mgr *mgr)
+{
+ return container_of(mgr, struct amdgpu_device, mman.vram_mgr);
+}
/**
* DOC: mem_info_vram_total
@@ -82,9 +85,9 @@ static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
-
+ struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
return snprintf(buf, PAGE_SIZE, "%llu\n",
- amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]));
+ amdgpu_vram_mgr_usage(man));
}
/**
@@ -100,9 +103,9 @@ static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = ddev->dev_private;
-
+ struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
return snprintf(buf, PAGE_SIZE, "%llu\n",
- amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]));
+ amdgpu_vram_mgr_vis_usage(man));
}
static ssize_t amdgpu_mem_info_vram_vendor(struct device *dev,
@@ -158,6 +161,8 @@ static const struct attribute *amdgpu_vram_mgr_attributes[] = {
NULL
};
+static const struct ttm_resource_manager_func amdgpu_vram_mgr_func;
+
/**
* amdgpu_vram_mgr_init - init VRAM manager and DRM MM
*
@@ -166,26 +171,29 @@ static const struct attribute *amdgpu_vram_mgr_attributes[] = {
*
* Allocate and initialize the VRAM manager.
*/
-static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
- unsigned long p_size)
+int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
{
- struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
- struct amdgpu_vram_mgr *mgr;
+ struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
+ struct ttm_resource_manager *man = &mgr->manager;
int ret;
- mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
- if (!mgr)
- return -ENOMEM;
+ man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+ man->default_caching = TTM_PL_FLAG_WC;
- drm_mm_init(&mgr->mm, 0, p_size);
+ ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT);
+
+ man->func = &amdgpu_vram_mgr_func;
+
+ drm_mm_init(&mgr->mm, 0, man->size);
spin_lock_init(&mgr->lock);
- man->priv = mgr;
/* Add the two VRAM-related sysfs files */
ret = sysfs_create_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes);
if (ret)
DRM_ERROR("Failed to register sysfs\n");
+ ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
+ ttm_resource_manager_set_used(man, true);
return 0;
}
@@ -197,18 +205,26 @@ static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
* Destroy and free the VRAM manager, returns -EBUSY if ranges are still
* allocated inside it.
*/
-static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man)
+void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
{
- struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
- struct amdgpu_vram_mgr *mgr = man->priv;
+ struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
+ struct ttm_resource_manager *man = &mgr->manager;
+ int ret;
+
+ ttm_resource_manager_set_used(man, false);
+
+ ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man);
+ if (ret)
+ return;
spin_lock(&mgr->lock);
drm_mm_takedown(&mgr->mm);
spin_unlock(&mgr->lock);
- kfree(mgr);
- man->priv = NULL;
+
sysfs_remove_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes);
- return 0;
+
+ ttm_resource_manager_cleanup(man);
+ ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL);
}
/**
@@ -243,7 +259,7 @@ static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
- struct ttm_mem_reg *mem = &bo->tbo.mem;
+ struct ttm_resource *mem = &bo->tbo.mem;
struct drm_mm_node *nodes = mem->mm_node;
unsigned pages = mem->num_pages;
u64 usage;
@@ -263,13 +279,13 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
/**
* amdgpu_vram_mgr_virt_start - update virtual start address
*
- * @mem: ttm_mem_reg to update
+ * @mem: ttm_resource to update
* @node: just allocated node
*
* Calculate a virtual BO start address to easily check if everything is CPU
* accessible.
*/
-static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem,
+static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem,
struct drm_mm_node *node)
{
unsigned long start;
@@ -292,13 +308,13 @@ static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem,
*
* Allocate VRAM for the given BO.
*/
-static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
+static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *tbo,
const struct ttm_place *place,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
- struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
- struct amdgpu_vram_mgr *mgr = man->priv;
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
+ struct amdgpu_device *adev = to_amdgpu_device(mgr);
struct drm_mm *mm = &mgr->mm;
struct drm_mm_node *nodes;
enum drm_mm_insert_mode mode;
@@ -410,11 +426,11 @@ error:
*
* Free the allocated VRAM again.
*/
-static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
- struct ttm_mem_reg *mem)
+static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
+ struct ttm_resource *mem)
{
- struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
- struct amdgpu_vram_mgr *mgr = man->priv;
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
+ struct amdgpu_device *adev = to_amdgpu_device(mgr);
struct drm_mm_node *nodes = mem->mm_node;
uint64_t usage = 0, vis_usage = 0;
unsigned pages = mem->num_pages;
@@ -451,7 +467,7 @@ static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
* Allocate and fill a sg table from a VRAM allocation.
*/
int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
struct device *dev,
enum dma_data_direction dir,
struct sg_table **sgt)
@@ -544,9 +560,9 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
*
* Returns how many bytes are used in this domain.
*/
-uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man)
+uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man)
{
- struct amdgpu_vram_mgr *mgr = man->priv;
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
return atomic64_read(&mgr->usage);
}
@@ -558,9 +574,9 @@ uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man)
*
* Returns how many bytes are used in the visible part of VRAM
*/
-uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man)
+uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man)
{
- struct amdgpu_vram_mgr *mgr = man->priv;
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
return atomic64_read(&mgr->vis_usage);
}
@@ -573,10 +589,10 @@ uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man)
*
* Dump the table content using printk.
*/
-static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man,
+static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
struct drm_printer *printer)
{
- struct amdgpu_vram_mgr *mgr = man->priv;
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
spin_lock(&mgr->lock);
drm_mm_print(&mgr->mm, printer);
@@ -587,10 +603,8 @@ static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man,
amdgpu_vram_mgr_vis_usage(man) >> 20);
}
-const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = {
- .init = amdgpu_vram_mgr_init,
- .takedown = amdgpu_vram_mgr_fini,
- .get_node = amdgpu_vram_mgr_new,
- .put_node = amdgpu_vram_mgr_del,
- .debug = amdgpu_vram_mgr_debug
+static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
+ .alloc = amdgpu_vram_mgr_new,
+ .free = amdgpu_vram_mgr_del,
+ .debug = amdgpu_vram_mgr_debug
};
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
index 9b74cfdba7b8..900b2727f432 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
@@ -328,6 +328,22 @@ static void amdgpu_atombios_dp_probe_oui(struct amdgpu_connector *amdgpu_connect
buf[0], buf[1], buf[2]);
}
+static void amdgpu_atombios_dp_ds_ports(struct amdgpu_connector *amdgpu_connector)
+{
+ struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
+ int ret;
+
+ if (dig_connector->dpcd[DP_DPCD_REV] > 0x10) {
+ ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux,
+ DP_DOWNSTREAM_PORT_0,
+ dig_connector->downstream_ports,
+ DP_MAX_DOWNSTREAM_PORTS);
+ if (ret)
+ memset(dig_connector->downstream_ports, 0,
+ DP_MAX_DOWNSTREAM_PORTS);
+ }
+}
+
int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector)
{
struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
@@ -343,7 +359,7 @@ int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector)
dig_connector->dpcd);
amdgpu_atombios_dp_probe_oui(amdgpu_connector);
-
+ amdgpu_atombios_dp_ds_ports(amdgpu_connector);
return 0;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b51c527a3f0d..490684787cff 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -127,6 +127,42 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU);
static int amdgpu_dm_init(struct amdgpu_device *adev);
static void amdgpu_dm_fini(struct amdgpu_device *adev);
+static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link)
+{
+ switch (link->dpcd_caps.dongle_type) {
+ case DISPLAY_DONGLE_NONE:
+ return DRM_MODE_SUBCONNECTOR_Native;
+ case DISPLAY_DONGLE_DP_VGA_CONVERTER:
+ return DRM_MODE_SUBCONNECTOR_VGA;
+ case DISPLAY_DONGLE_DP_DVI_CONVERTER:
+ case DISPLAY_DONGLE_DP_DVI_DONGLE:
+ return DRM_MODE_SUBCONNECTOR_DVID;
+ case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
+ case DISPLAY_DONGLE_DP_HDMI_DONGLE:
+ return DRM_MODE_SUBCONNECTOR_HDMIA;
+ case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE:
+ default:
+ return DRM_MODE_SUBCONNECTOR_Unknown;
+ }
+}
+
+static void update_subconnector_property(struct amdgpu_dm_connector *aconnector)
+{
+ struct dc_link *link = aconnector->dc_link;
+ struct drm_connector *connector = &aconnector->base;
+ enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
+
+ if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+ return;
+
+ if (aconnector->dc_sink)
+ subconnector = get_subconnector_type(link);
+
+ drm_object_property_set_value(&connector->base,
+ connector->dev->mode_config.dp_subconnector_property,
+ subconnector);
+}
+
/*
* initializes drm_device display related structures, based on the information
* provided by DAL. The drm strcutures are: drm_crtc, drm_connector,
@@ -2095,7 +2131,6 @@ void amdgpu_dm_update_connector_after_detect(
if (aconnector->mst_mgr.mst_state == true)
return;
-
sink = aconnector->dc_link->local_sink;
if (sink)
dc_sink_retain(sink);
@@ -2222,6 +2257,8 @@ void amdgpu_dm_update_connector_after_detect(
mutex_unlock(&dev->mode_config.mutex);
+ update_subconnector_property(aconnector);
+
if (sink)
dc_sink_release(sink);
}
@@ -4764,6 +4801,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
else
connected = (aconnector->base.force == DRM_FORCE_ON);
+ update_subconnector_property(aconnector);
+
return (connected ? connector_status_connected :
connector_status_disconnected);
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 336aaa09be46..461fa4da0a34 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -26,6 +26,7 @@
#include <linux/version.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_dp_helper.h>
#include "dm_services.h"
#include "amdgpu.h"
#include "amdgpu_dm.h"
@@ -431,6 +432,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
16,
4,
aconnector->connector_id);
+
+ drm_connector_attach_dp_subconnector_property(&aconnector->base);
}
int dm_mst_get_pbn_divider(struct dc_link *link)
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index ab45ac445045..351a85088d0e 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -346,7 +346,7 @@ static bool malidp_check_pages_threshold(struct malidp_plane_state *ms,
if (cma_obj->sgt)
sgt = cma_obj->sgt;
else
- sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
+ sgt = obj->funcs->get_sg_table(obj);
if (!sgt)
return false;
diff --git a/drivers/gpu/drm/ast/ast_cursor.c b/drivers/gpu/drm/ast/ast_cursor.c
index acf0d23514e8..e0f4613918ad 100644
--- a/drivers/gpu/drm/ast/ast_cursor.c
+++ b/drivers/gpu/drm/ast/ast_cursor.c
@@ -47,7 +47,7 @@ static void ast_cursor_fini(struct ast_private *ast)
static void ast_cursor_release(struct drm_device *dev, void *ptr)
{
- struct ast_private *ast = dev->dev_private;
+ struct ast_private *ast = to_ast_private(dev);
ast_cursor_fini(ast);
}
@@ -57,7 +57,7 @@ static void ast_cursor_release(struct drm_device *dev, void *ptr)
*/
int ast_cursor_init(struct ast_private *ast)
{
- struct drm_device *dev = ast->dev;
+ struct drm_device *dev = &ast->base;
size_t size, i;
struct drm_gem_vram_object *gbo;
void __iomem *vaddr;
@@ -168,7 +168,7 @@ static void update_cursor_image(u8 __iomem *dst, const u8 *src, int width, int h
int ast_cursor_blit(struct ast_private *ast, struct drm_framebuffer *fb)
{
- struct drm_device *dev = ast->dev;
+ struct drm_device *dev = &ast->base;
struct drm_gem_vram_object *gbo;
int ret;
void *src;
@@ -217,7 +217,7 @@ static void ast_cursor_set_base(struct ast_private *ast, u64 address)
void ast_cursor_page_flip(struct ast_private *ast)
{
- struct drm_device *dev = ast->dev;
+ struct drm_device *dev = &ast->base;
struct drm_gem_vram_object *gbo;
s64 off;
@@ -253,7 +253,8 @@ void ast_cursor_show(struct ast_private *ast, int x, int y,
unsigned int offset_x, unsigned int offset_y)
{
u8 x_offset, y_offset;
- u8 __iomem *dst, __iomem *sig;
+ u8 __iomem *dst;
+ u8 __iomem *sig;
u8 jreg;
dst = ast->cursor.vaddr[ast->cursor.next_index];
diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c
index 4b85a504825a..88121c0e0d05 100644
--- a/drivers/gpu/drm/ast/ast_dp501.c
+++ b/drivers/gpu/drm/ast/ast_dp501.c
@@ -8,11 +8,24 @@
MODULE_FIRMWARE("ast_dp501_fw.bin");
+static void ast_release_firmware(void *data)
+{
+ struct ast_private *ast = data;
+
+ release_firmware(ast->dp501_fw);
+ ast->dp501_fw = NULL;
+}
+
static int ast_load_dp501_microcode(struct drm_device *dev)
{
struct ast_private *ast = to_ast_private(dev);
+ int ret;
+
+ ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev);
+ if (ret)
+ return ret;
- return request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev);
+ return devm_add_action_or_reset(dev->dev, ast_release_firmware, ast);
}
static void send_ack(struct ast_private *ast)
@@ -435,11 +448,3 @@ void ast_init_3rdtx(struct drm_device *dev)
}
}
}
-
-void ast_release_firmware(struct drm_device *dev)
-{
- struct ast_private *ast = to_ast_private(dev);
-
- release_firmware(ast->dp501_fw);
- ast->dp501_fw = NULL;
-}
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index 0b58f7aee6b0..f0b4af1c390a 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -43,9 +43,33 @@ int ast_modeset = -1;
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, ast_modeset, int, 0400);
-#define PCI_VENDOR_ASPEED 0x1a03
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(ast_fops);
+
+static struct drm_driver ast_driver = {
+ .driver_features = DRIVER_ATOMIC |
+ DRIVER_GEM |
+ DRIVER_MODESET,
+
+ .fops = &ast_fops,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+
+ DRM_GEM_VRAM_DRIVER
+};
+
+/*
+ * PCI driver
+ */
-static struct drm_driver driver;
+#define PCI_VENDOR_ASPEED 0x1a03
#define AST_VGA_DEVICE(id, info) { \
.class = PCI_BASE_CLASS_DISPLAY << 16, \
@@ -56,13 +80,13 @@ static struct drm_driver driver;
.subdevice = PCI_ANY_ID, \
.driver_data = (unsigned long) info }
-static const struct pci_device_id pciidlist[] = {
+static const struct pci_device_id ast_pciidlist[] = {
AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL),
AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL),
{0, 0, 0},
};
-MODULE_DEVICE_TABLE(pci, pciidlist);
+MODULE_DEVICE_TABLE(pci, ast_pciidlist);
static void ast_kick_out_firmware_fb(struct pci_dev *pdev)
{
@@ -85,6 +109,7 @@ static void ast_kick_out_firmware_fb(struct pci_dev *pdev)
static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
+ struct ast_private *ast;
struct drm_device *dev;
int ret;
@@ -94,41 +119,25 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
return ret;
- dev = drm_dev_alloc(&driver, &pdev->dev);
- if (IS_ERR(dev))
- return PTR_ERR(dev);
-
- dev->pdev = pdev;
- pci_set_drvdata(pdev, dev);
-
- ret = ast_driver_load(dev, ent->driver_data);
- if (ret)
- goto err_drm_dev_put;
+ ast = ast_device_create(&ast_driver, pdev, ent->driver_data);
+ if (IS_ERR(ast))
+ return PTR_ERR(ast);
+ dev = &ast->base;
ret = drm_dev_register(dev, ent->driver_data);
if (ret)
- goto err_ast_driver_unload;
+ return ret;
drm_fbdev_generic_setup(dev, 32);
return 0;
-
-err_ast_driver_unload:
- ast_driver_unload(dev);
-err_drm_dev_put:
- drm_dev_put(dev);
- return ret;
-
}
-static void
-ast_pci_remove(struct pci_dev *pdev)
+static void ast_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
drm_dev_unregister(dev);
- ast_driver_unload(dev);
- drm_dev_put(dev);
}
static int ast_drm_freeze(struct drm_device *dev)
@@ -217,30 +226,12 @@ static const struct dev_pm_ops ast_pm_ops = {
static struct pci_driver ast_pci_driver = {
.name = DRIVER_NAME,
- .id_table = pciidlist,
+ .id_table = ast_pciidlist,
.probe = ast_pci_probe,
.remove = ast_pci_remove,
.driver.pm = &ast_pm_ops,
};
-DEFINE_DRM_GEM_FOPS(ast_fops);
-
-static struct drm_driver driver = {
- .driver_features = DRIVER_ATOMIC |
- DRIVER_GEM |
- DRIVER_MODESET,
-
- .fops = &ast_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-
- DRM_GEM_VRAM_DRIVER
-};
-
static int __init ast_init(void)
{
if (vgacon_text_force() && ast_modeset == -1)
@@ -261,4 +252,3 @@ module_exit(ast_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL and additional rights");
-
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index e3a264ac7ee2..c1af6b725933 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -98,9 +98,25 @@ enum ast_tx_chip {
#define AST_HWC_SIGNATURE_HOTSPOTX 0x14
#define AST_HWC_SIGNATURE_HOTSPOTY 0x18
+struct ast_i2c_chan {
+ struct i2c_adapter adapter;
+ struct drm_device *dev;
+ struct i2c_algo_bit_data bit;
+};
+
+struct ast_connector {
+ struct drm_connector base;
+ struct ast_i2c_chan *i2c;
+};
+
+static inline struct ast_connector *
+to_ast_connector(struct drm_connector *connector)
+{
+ return container_of(connector, struct ast_connector, base);
+}
struct ast_private {
- struct drm_device *dev;
+ struct drm_device base;
void __iomem *regs;
void __iomem *ioregs;
@@ -119,9 +135,11 @@ struct ast_private {
unsigned int next_index;
} cursor;
- struct drm_encoder encoder;
struct drm_plane primary_plane;
struct drm_plane cursor_plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
+ struct ast_connector connector;
bool support_wide_screen;
enum {
@@ -138,11 +156,12 @@ struct ast_private {
static inline struct ast_private *to_ast_private(struct drm_device *dev)
{
- return dev->dev_private;
+ return container_of(dev, struct ast_private, base);
}
-int ast_driver_load(struct drm_device *dev, unsigned long flags);
-void ast_driver_unload(struct drm_device *dev);
+struct ast_private *ast_device_create(struct drm_driver *drv,
+ struct pci_dev *pdev,
+ unsigned long flags);
#define AST_IO_AR_PORT_WRITE (0x40)
#define AST_IO_MISC_PORT_WRITE (0x42)
@@ -226,19 +245,6 @@ static inline void ast_open_key(struct ast_private *ast)
#define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M
-struct ast_i2c_chan {
- struct i2c_adapter adapter;
- struct drm_device *dev;
- struct i2c_algo_bit_data bit;
-};
-
-struct ast_connector {
- struct drm_connector base;
- struct ast_i2c_chan *i2c;
-};
-
-#define to_ast_connector(x) container_of(x, struct ast_connector, base)
-
struct ast_vbios_stdtable {
u8 misc;
u8 seq[4];
@@ -305,7 +311,6 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);
bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
u8 ast_get_dp501_max_clk(struct drm_device *dev);
void ast_init_3rdtx(struct drm_device *dev);
-void ast_release_firmware(struct drm_device *dev);
/* ast_cursor.c */
int ast_cursor_init(struct ast_private *ast);
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 6a9fba051d13..77066bca8793 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -30,8 +30,10 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_vram_helper.h>
+#include <drm/drm_managed.h>
#include "ast_drv.h"
@@ -230,11 +232,11 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
ast->tx_chip_type = AST_TX_SIL164;
break;
case 0x08:
- ast->dp501_fw_addr = kzalloc(32*1024, GFP_KERNEL);
+ ast->dp501_fw_addr = drmm_kzalloc(dev, 32*1024, GFP_KERNEL);
if (ast->dp501_fw_addr) {
/* backup firmware */
if (ast_backup_fw(dev, ast->dp501_fw_addr, 32*1024)) {
- kfree(ast->dp501_fw_addr);
+ drmm_kfree(dev, ast->dp501_fw_addr);
ast->dp501_fw_addr = NULL;
}
}
@@ -378,24 +380,38 @@ static int ast_get_dram_info(struct drm_device *dev)
return 0;
}
-int ast_driver_load(struct drm_device *dev, unsigned long flags)
+/*
+ * Run this function as part of the HW device cleanup; not
+ * when the DRM device gets released.
+ */
+static void ast_device_release(void *data)
{
+ struct ast_private *ast = data;
+
+ /* enable standard VGA decode */
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04);
+}
+
+struct ast_private *ast_device_create(struct drm_driver *drv,
+ struct pci_dev *pdev,
+ unsigned long flags)
+{
+ struct drm_device *dev;
struct ast_private *ast;
bool need_post;
int ret = 0;
- ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
- if (!ast)
- return -ENOMEM;
+ ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_private, base);
+ if (IS_ERR(ast))
+ return ast;
+ dev = &ast->base;
- dev->dev_private = ast;
- ast->dev = dev;
+ dev->pdev = pdev;
+ pci_set_drvdata(pdev, dev);
ast->regs = pci_iomap(dev->pdev, 1, 0);
- if (!ast->regs) {
- ret = -EIO;
- goto out_free;
- }
+ if (!ast->regs)
+ return ERR_PTR(-EIO);
/*
* If we don't have IO space at all, use MMIO now and
@@ -410,17 +426,16 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags)
/* "map" IO regs if the above hasn't done so already */
if (!ast->ioregs) {
ast->ioregs = pci_iomap(dev->pdev, 2, 0);
- if (!ast->ioregs) {
- ret = -EIO;
- goto out_free;
- }
+ if (!ast->ioregs)
+ return ERR_PTR(-EIO);
}
ast_detect_chip(dev, &need_post);
ret = ast_get_dram_info(dev);
if (ret)
- goto out_free;
+ return ERR_PTR(ret);
+
drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n",
ast->mclk, ast->dram_type, ast->dram_bus_width);
@@ -429,28 +444,15 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags)
ret = ast_mm_init(ast);
if (ret)
- goto out_free;
+ return ERR_PTR(ret);
ret = ast_mode_config_init(ast);
if (ret)
- goto out_free;
+ return ERR_PTR(ret);
- return 0;
-out_free:
- kfree(ast);
- dev->dev_private = NULL;
- return ret;
-}
-
-void ast_driver_unload(struct drm_device *dev)
-{
- struct ast_private *ast = to_ast_private(dev);
-
- /* enable standard VGA decode */
- ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04);
-
- ast_release_firmware(dev);
- kfree(ast->dp501_fw_addr);
+ ret = devm_add_action_or_reset(dev->dev, ast_device_release, ast);
+ if (ret)
+ return ERR_PTR(ret);
- kfree(ast);
+ return ast;
}
diff --git a/drivers/gpu/drm/ast/ast_mm.c b/drivers/gpu/drm/ast/ast_mm.c
index 9186ec3ebbe0..8392ebde504b 100644
--- a/drivers/gpu/drm/ast/ast_mm.c
+++ b/drivers/gpu/drm/ast/ast_mm.c
@@ -85,9 +85,9 @@ static void ast_mm_release(struct drm_device *dev, void *ptr)
int ast_mm_init(struct ast_private *ast)
{
+ struct drm_device *dev = &ast->base;
u32 vram_size;
int ret;
- struct drm_device *dev = ast->dev;
vram_size = ast_get_vram_size(ast);
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 154cd877d9d1..62fe682a7de6 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -663,7 +663,7 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
{
struct drm_plane_state *state = plane->state;
struct drm_framebuffer *fb = state->fb;
- struct ast_private *ast = plane->dev->dev_private;
+ struct ast_private *ast = to_ast_private(plane->dev);
unsigned int offset_x, offset_y;
offset_x = AST_MAX_HWC_WIDTH - fb->width;
@@ -831,12 +831,6 @@ static void ast_crtc_reset(struct drm_crtc *crtc)
__drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
}
-static void ast_crtc_destroy(struct drm_crtc *crtc)
-{
- drm_crtc_cleanup(crtc);
- kfree(crtc);
-}
-
static struct drm_crtc_state *
ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
{
@@ -872,7 +866,7 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
static const struct drm_crtc_funcs ast_crtc_funcs = {
.reset = ast_crtc_reset,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
- .destroy = ast_crtc_destroy,
+ .destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = ast_crtc_atomic_duplicate_state,
@@ -882,27 +876,19 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
static int ast_crtc_init(struct drm_device *dev)
{
struct ast_private *ast = to_ast_private(dev);
- struct drm_crtc *crtc;
+ struct drm_crtc *crtc = &ast->crtc;
int ret;
- crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
- if (!crtc)
- return -ENOMEM;
-
ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane,
&ast->cursor_plane, &ast_crtc_funcs,
NULL);
if (ret)
- goto err_kfree;
+ return ret;
drm_mode_crtc_set_gamma_size(crtc, 256);
drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs);
return 0;
-
-err_kfree:
- kfree(crtc);
- return ret;
}
/*
@@ -1021,7 +1007,6 @@ static void ast_connector_destroy(struct drm_connector *connector)
struct ast_connector *ast_connector = to_ast_connector(connector);
ast_i2c_destroy(ast_connector->i2c);
drm_connector_cleanup(connector);
- kfree(connector);
}
static const struct drm_connector_helper_funcs ast_connector_helper_funcs = {
@@ -1039,15 +1024,11 @@ static const struct drm_connector_funcs ast_connector_funcs = {
static int ast_connector_init(struct drm_device *dev)
{
- struct ast_connector *ast_connector;
- struct drm_connector *connector;
- struct drm_encoder *encoder;
-
- ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL);
- if (!ast_connector)
- return -ENOMEM;
+ struct ast_private *ast = to_ast_private(dev);
+ struct ast_connector *ast_connector = &ast->connector;
+ struct drm_connector *connector = &ast_connector->base;
+ struct drm_encoder *encoder = &ast->encoder;
- connector = &ast_connector->base;
ast_connector->i2c = ast_i2c_create(dev);
if (!ast_connector->i2c)
drm_err(dev, "failed to add ddc bus for connector\n");
@@ -1064,7 +1045,6 @@ static int ast_connector_init(struct drm_device *dev)
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head);
drm_connector_attach_encoder(connector, encoder);
return 0;
@@ -1083,7 +1063,7 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = {
int ast_mode_config_init(struct ast_private *ast)
{
- struct drm_device *dev = ast->dev;
+ struct drm_device *dev = &ast->base;
int ret;
ret = ast_cursor_init(ast);
@@ -1099,7 +1079,7 @@ int ast_mode_config_init(struct ast_private *ast)
dev->mode_config.min_height = 0;
dev->mode_config.preferred_depth = 24;
dev->mode_config.prefer_shadow = 1;
- dev->mode_config.fb_base = pci_resource_start(ast->dev->pdev, 0);
+ dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
if (ast->chip == AST2100 ||
ast->chip == AST2200 ||
diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c
index c043fe717553..8902c2f84bf9 100644
--- a/drivers/gpu/drm/ast/ast_post.c
+++ b/drivers/gpu/drm/ast/ast_post.c
@@ -365,12 +365,12 @@ static void ast_init_dram_reg(struct drm_device *dev)
void ast_post_gpu(struct drm_device *dev)
{
- u32 reg;
struct ast_private *ast = to_ast_private(dev);
+ u32 reg;
- pci_read_config_dword(ast->dev->pdev, 0x04, &reg);
+ pci_read_config_dword(dev->pdev, 0x04, &reg);
reg |= 0x3;
- pci_write_config_dword(ast->dev->pdev, 0x04, reg);
+ pci_write_config_dword(dev->pdev, 0x04, reg);
ast_enable_vga(dev);
ast_open_key(ast);
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 43271c21d3fc..3e11af4e9f63 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -48,6 +48,19 @@ config DRM_DISPLAY_CONNECTOR
on ARM-based platforms. Saying Y here when this driver is not needed
will not cause any issue.
+config DRM_LONTIUM_LT9611
+ tristate "Lontium LT9611 DSI/HDMI bridge"
+ select SND_SOC_HDMI_CODEC if SND_SOC
+ depends on OF
+ select DRM_PANEL_BRIDGE
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ help
+ Driver for Lontium LT9611 DSI to HDMI bridge
+ chip driver that converts dual DSI and I2S to
+ HDMI signals
+ Please say Y if you have such hardware.
+
config DRM_LVDS_CODEC
tristate "Transparent LVDS encoders and decoders support"
depends on OF
@@ -153,6 +166,14 @@ config DRM_THINE_THC63LVD1024
help
Thine THC63LVD1024 LVDS/parallel converter driver.
+config DRM_TOSHIBA_TC358762
+ tristate "TC358762 DSI/DPI bridge"
+ depends on OF
+ select DRM_MIPI_DSI
+ select DRM_PANEL_BRIDGE
+ help
+ Toshiba TC358762 DSI/DPI bridge driver.
+
config DRM_TOSHIBA_TC358764
tristate "TC358764 DSI/LVDS bridge"
depends on OF
@@ -181,6 +202,16 @@ config DRM_TOSHIBA_TC358768
help
Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver.
+config DRM_TOSHIBA_TC358775
+ tristate "Toshiba TC358775 DSI/LVDS bridge"
+ depends on OF
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ select DRM_PANEL
+ select DRM_MIPI_DSI
+ help
+ Toshiba TC358775 DSI/LVDS bridge chip driver.
+
config DRM_TI_TFP410
tristate "TI TFP410 DVI/HDMI bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index d63d4b7e4347..c589a6a7cbe1 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
+obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o
obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
@@ -12,9 +13,11 @@ obj-$(CONFIG_DRM_SII902X) += sii902x.o
obj-$(CONFIG_DRM_SII9234) += sii9234.o
obj-$(CONFIG_DRM_SIMPLE_BRIDGE) += simple-bridge.o
obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
+obj-$(CONFIG_DRM_TOSHIBA_TC358762) += tc358762.o
obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o
+obj-$(CONFIG_DRM_TOSHIBA_TC358775) += tc358775.o
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
index f082b4ed4878..d9164fab044d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
@@ -507,10 +507,6 @@ static const struct drm_connector_helper_funcs anx6345_connector_helper_funcs =
static void
anx6345_connector_destroy(struct drm_connector *connector)
{
- struct anx6345 *anx6345 = connector_to_anx6345(connector);
-
- if (anx6345->panel)
- drm_panel_detach(anx6345->panel);
drm_connector_cleanup(connector);
}
@@ -575,14 +571,6 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge,
return err;
}
- if (anx6345->panel) {
- err = drm_panel_attach(anx6345->panel, &anx6345->connector);
- if (err) {
- DRM_ERROR("Failed to attach panel: %d\n", err);
- return err;
- }
- }
-
return 0;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 76736fb8ed94..aa1bb86293fd 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1265,14 +1265,6 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
}
}
- if (dp->plat_data->panel) {
- ret = drm_panel_attach(dp->plat_data->panel, &dp->connector);
- if (ret) {
- DRM_ERROR("Failed to attach panel\n");
- return ret;
- }
- }
-
return 0;
}
@@ -1803,7 +1795,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
if (dp->plat_data->panel) {
if (drm_panel_unprepare(dp->plat_data->panel))
DRM_ERROR("failed to turnoff the panel\n");
- drm_panel_detach(dp->plat_data->panel);
}
drm_dp_aux_unregister(&dp->aux);
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
new file mode 100644
index 000000000000..1009fc4ed4ed
--- /dev/null
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -0,0 +1,1230 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020. Linaro Limited.
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/hdmi-codec.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+#define EDID_SEG_SIZE 256
+#define EDID_LEN 32
+#define EDID_LOOP 8
+#define KEY_DDC_ACCS_DONE 0x02
+#define DDC_NO_ACK 0x50
+
+#define LT9611_4LANES 0
+
+struct lt9611 {
+ struct device *dev;
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+
+ struct regmap *regmap;
+
+ struct device_node *dsi0_node;
+ struct device_node *dsi1_node;
+ struct mipi_dsi_device *dsi0;
+ struct mipi_dsi_device *dsi1;
+ struct platform_device *audio_pdev;
+
+ bool ac_mode;
+
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *enable_gpio;
+
+ bool power_on;
+ bool sleep;
+
+ struct regulator_bulk_data supplies[2];
+
+ struct i2c_client *client;
+
+ enum drm_connector_status status;
+
+ u8 edid_buf[EDID_SEG_SIZE];
+ u32 vic;
+};
+
+#define LT9611_PAGE_CONTROL 0xff
+
+static const struct regmap_range_cfg lt9611_ranges[] = {
+ {
+ .name = "register_range",
+ .range_min = 0,
+ .range_max = 0x85ff,
+ .selector_reg = LT9611_PAGE_CONTROL,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ },
+};
+
+static const struct regmap_config lt9611_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xffff,
+ .ranges = lt9611_ranges,
+ .num_ranges = ARRAY_SIZE(lt9611_ranges),
+};
+
+struct lt9611_mode {
+ u16 hdisplay;
+ u16 vdisplay;
+ u8 vrefresh;
+ u8 lanes;
+ u8 intfs;
+};
+
+static struct lt9611_mode lt9611_modes[] = {
+ { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */
+ { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */
+ { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */
+ { 1920, 1080, 24, 3, 1 },
+ { 720, 480, 60, 4, 1 },
+ { 720, 576, 50, 2, 1 },
+ { 640, 480, 60, 2, 1 },
+};
+
+static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct lt9611, bridge);
+}
+
+static struct lt9611 *connector_to_lt9611(struct drm_connector *connector)
+{
+ return container_of(connector, struct lt9611, connector);
+}
+
+static int lt9611_mipi_input_analog(struct lt9611 *lt9611)
+{
+ const struct reg_sequence reg_cfg[] = {
+ { 0x8106, 0x40 }, /* port A rx current */
+ { 0x810a, 0xfe }, /* port A ldo voltage set */
+ { 0x810b, 0xbf }, /* enable port A lprx */
+ { 0x8111, 0x40 }, /* port B rx current */
+ { 0x8115, 0xfe }, /* port B ldo voltage set */
+ { 0x8116, 0xbf }, /* enable port B lprx */
+
+ { 0x811c, 0x03 }, /* PortA clk lane no-LP mode */
+ { 0x8120, 0x03 }, /* PortB clk lane with-LP mode */
+ };
+
+ return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+}
+
+static int lt9611_mipi_input_digital(struct lt9611 *lt9611,
+ const struct drm_display_mode *mode)
+{
+ struct reg_sequence reg_cfg[] = {
+ { 0x8300, LT9611_4LANES },
+ { 0x830a, 0x00 },
+ { 0x824f, 0x80 },
+ { 0x8250, 0x10 },
+ { 0x8302, 0x0a },
+ { 0x8306, 0x0a },
+ };
+
+ if (mode->hdisplay == 3840)
+ reg_cfg[1].def = 0x03;
+
+ return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+}
+
+static void lt9611_mipi_video_setup(struct lt9611 *lt9611,
+ const struct drm_display_mode *mode)
+{
+ u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
+ u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
+
+ h_total = mode->htotal;
+ v_total = mode->vtotal;
+
+ hactive = mode->hdisplay;
+ hsync_len = mode->hsync_end - mode->hsync_start;
+ hfront_porch = mode->hsync_start - mode->hdisplay;
+ hsync_porch = hsync_len + mode->htotal - mode->hsync_end;
+
+ vactive = mode->vdisplay;
+ vsync_len = mode->vsync_end - mode->vsync_start;
+ vfront_porch = mode->vsync_start - mode->vdisplay;
+ vsync_porch = vsync_len + mode->vtotal - mode->vsync_end;
+
+ regmap_write(lt9611->regmap, 0x830d, (u8)(v_total / 256));
+ regmap_write(lt9611->regmap, 0x830e, (u8)(v_total % 256));
+
+ regmap_write(lt9611->regmap, 0x830f, (u8)(vactive / 256));
+ regmap_write(lt9611->regmap, 0x8310, (u8)(vactive % 256));
+
+ regmap_write(lt9611->regmap, 0x8311, (u8)(h_total / 256));
+ regmap_write(lt9611->regmap, 0x8312, (u8)(h_total % 256));
+
+ regmap_write(lt9611->regmap, 0x8313, (u8)(hactive / 256));
+ regmap_write(lt9611->regmap, 0x8314, (u8)(hactive % 256));
+
+ regmap_write(lt9611->regmap, 0x8315, (u8)(vsync_len % 256));
+ regmap_write(lt9611->regmap, 0x8316, (u8)(hsync_len % 256));
+
+ regmap_write(lt9611->regmap, 0x8317, (u8)(vfront_porch % 256));
+
+ regmap_write(lt9611->regmap, 0x8318, (u8)(vsync_porch % 256));
+
+ regmap_write(lt9611->regmap, 0x8319, (u8)(hfront_porch % 256));
+
+ regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256));
+ regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256));
+}
+
+static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode)
+{
+ const struct reg_sequence reg_cfg[] = {
+ { 0x830b, 0x01 },
+ { 0x830c, 0x10 },
+ { 0x8348, 0x00 },
+ { 0x8349, 0x81 },
+
+ /* stage 1 */
+ { 0x8321, 0x4a },
+ { 0x8324, 0x71 },
+ { 0x8325, 0x30 },
+ { 0x832a, 0x01 },
+
+ /* stage 2 */
+ { 0x834a, 0x40 },
+ { 0x831d, 0x10 },
+
+ /* MK limit */
+ { 0x832d, 0x38 },
+ { 0x8331, 0x08 },
+ };
+ const struct reg_sequence reg_cfg2[] = {
+ { 0x830b, 0x03 },
+ { 0x830c, 0xd0 },
+ { 0x8348, 0x03 },
+ { 0x8349, 0xe0 },
+ { 0x8324, 0x72 },
+ { 0x8325, 0x00 },
+ { 0x832a, 0x01 },
+ { 0x834a, 0x10 },
+ { 0x831d, 0x10 },
+ { 0x8326, 0x37 },
+ };
+
+ regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+
+ switch (mode->hdisplay) {
+ case 640:
+ regmap_write(lt9611->regmap, 0x8326, 0x14);
+ break;
+ case 1920:
+ regmap_write(lt9611->regmap, 0x8326, 0x37);
+ break;
+ case 3840:
+ regmap_multi_reg_write(lt9611->regmap, reg_cfg2, ARRAY_SIZE(reg_cfg2));
+ break;
+ }
+
+ /* pcr rst */
+ regmap_write(lt9611->regmap, 0x8011, 0x5a);
+ regmap_write(lt9611->regmap, 0x8011, 0xfa);
+}
+
+static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode)
+{
+ unsigned int pclk = mode->clock;
+ const struct reg_sequence reg_cfg[] = {
+ /* txpll init */
+ { 0x8123, 0x40 },
+ { 0x8124, 0x64 },
+ { 0x8125, 0x80 },
+ { 0x8126, 0x55 },
+ { 0x812c, 0x37 },
+ { 0x812f, 0x01 },
+ { 0x8126, 0x55 },
+ { 0x8127, 0x66 },
+ { 0x8128, 0x88 },
+ };
+
+ regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+
+ if (pclk > 150000)
+ regmap_write(lt9611->regmap, 0x812d, 0x88);
+ else if (pclk > 70000)
+ regmap_write(lt9611->regmap, 0x812d, 0x99);
+ else
+ regmap_write(lt9611->regmap, 0x812d, 0xaa);
+
+ /*
+ * first divide pclk by 2 first
+ * - write divide by 64k to 19:16 bits which means shift by 17
+ * - write divide by 256 to 15:8 bits which means shift by 9
+ * - write remainder to 7:0 bits, which means shift by 1
+ */
+ regmap_write(lt9611->regmap, 0x82e3, pclk >> 17); /* pclk[19:16] */
+ regmap_write(lt9611->regmap, 0x82e4, pclk >> 9); /* pclk[15:8] */
+ regmap_write(lt9611->regmap, 0x82e5, pclk >> 1); /* pclk[7:0] */
+
+ regmap_write(lt9611->regmap, 0x82de, 0x20);
+ regmap_write(lt9611->regmap, 0x82de, 0xe0);
+
+ regmap_write(lt9611->regmap, 0x8016, 0xf1);
+ regmap_write(lt9611->regmap, 0x8016, 0xf3);
+
+ return 0;
+}
+
+static int lt9611_read_video_check(struct lt9611 *lt9611, unsigned int reg)
+{
+ unsigned int temp, temp2;
+ int ret;
+
+ ret = regmap_read(lt9611->regmap, reg, &temp);
+ if (ret)
+ return ret;
+ temp <<= 8;
+ ret = regmap_read(lt9611->regmap, reg + 1, &temp2);
+ if (ret)
+ return ret;
+
+ return (temp + temp2);
+}
+
+static int lt9611_video_check(struct lt9611 *lt9611)
+{
+ u32 v_total, vactive, hactive_a, hactive_b, h_total_sysclk;
+ int temp;
+
+ /* top module video check */
+
+ /* vactive */
+ temp = lt9611_read_video_check(lt9611, 0x8282);
+ if (temp < 0)
+ goto end;
+ vactive = temp;
+
+ /* v_total */
+ temp = lt9611_read_video_check(lt9611, 0x826c);
+ if (temp < 0)
+ goto end;
+ v_total = temp;
+
+ /* h_total_sysclk */
+ temp = lt9611_read_video_check(lt9611, 0x8286);
+ if (temp < 0)
+ goto end;
+ h_total_sysclk = temp;
+
+ /* hactive_a */
+ temp = lt9611_read_video_check(lt9611, 0x8382);
+ if (temp < 0)
+ goto end;
+ hactive_a = temp / 3;
+
+ /* hactive_b */
+ temp = lt9611_read_video_check(lt9611, 0x8386);
+ if (temp < 0)
+ goto end;
+ hactive_b = temp / 3;
+
+ dev_info(lt9611->dev,
+ "video check: hactive_a=%d, hactive_b=%d, vactive=%d, v_total=%d, h_total_sysclk=%d\n",
+ hactive_a, hactive_b, vactive, v_total, h_total_sysclk);
+
+ return 0;
+
+end:
+ dev_err(lt9611->dev, "read video check error\n");
+ return temp;
+}
+
+static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611)
+{
+ regmap_write(lt9611->regmap, 0x8443, 0x46 - lt9611->vic);
+ regmap_write(lt9611->regmap, 0x8447, lt9611->vic);
+ regmap_write(lt9611->regmap, 0x843d, 0x0a); /* UD1 infoframe */
+
+ regmap_write(lt9611->regmap, 0x82d6, 0x8c);
+ regmap_write(lt9611->regmap, 0x82d7, 0x04);
+}
+
+static void lt9611_hdmi_tx_phy(struct lt9611 *lt9611)
+{
+ struct reg_sequence reg_cfg[] = {
+ { 0x8130, 0x6a },
+ { 0x8131, 0x44 }, /* HDMI DC mode */
+ { 0x8132, 0x4a },
+ { 0x8133, 0x0b },
+ { 0x8134, 0x00 },
+ { 0x8135, 0x00 },
+ { 0x8136, 0x00 },
+ { 0x8137, 0x44 },
+ { 0x813f, 0x0f },
+ { 0x8140, 0xa0 },
+ { 0x8141, 0xa0 },
+ { 0x8142, 0xa0 },
+ { 0x8143, 0xa0 },
+ { 0x8144, 0x0a },
+ };
+
+ /* HDMI AC mode */
+ if (lt9611->ac_mode)
+ reg_cfg[2].def = 0x73;
+
+ regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+}
+
+static irqreturn_t lt9611_irq_thread_handler(int irq, void *dev_id)
+{
+ struct lt9611 *lt9611 = dev_id;
+ unsigned int irq_flag0 = 0;
+ unsigned int irq_flag3 = 0;
+
+ regmap_read(lt9611->regmap, 0x820f, &irq_flag3);
+ regmap_read(lt9611->regmap, 0x820c, &irq_flag0);
+
+ /* hpd changed low */
+ if (irq_flag3 & 0x80) {
+ dev_info(lt9611->dev, "hdmi cable disconnected\n");
+
+ regmap_write(lt9611->regmap, 0x8207, 0xbf);
+ regmap_write(lt9611->regmap, 0x8207, 0x3f);
+ }
+
+ /* hpd changed high */
+ if (irq_flag3 & 0x40) {
+ dev_info(lt9611->dev, "hdmi cable connected\n");
+
+ regmap_write(lt9611->regmap, 0x8207, 0x7f);
+ regmap_write(lt9611->regmap, 0x8207, 0x3f);
+ }
+
+ if (irq_flag3 & 0xc0 && lt9611->bridge.dev)
+ drm_kms_helper_hotplug_event(lt9611->bridge.dev);
+
+ /* video input changed */
+ if (irq_flag0 & 0x01) {
+ dev_info(lt9611->dev, "video input changed\n");
+ regmap_write(lt9611->regmap, 0x829e, 0xff);
+ regmap_write(lt9611->regmap, 0x829e, 0xf7);
+ regmap_write(lt9611->regmap, 0x8204, 0xff);
+ regmap_write(lt9611->regmap, 0x8204, 0xfe);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void lt9611_enable_hpd_interrupts(struct lt9611 *lt9611)
+{
+ unsigned int val;
+
+ regmap_read(lt9611->regmap, 0x8203, &val);
+
+ val &= ~0xc0;
+ regmap_write(lt9611->regmap, 0x8203, val);
+ regmap_write(lt9611->regmap, 0x8207, 0xff); /* clear */
+ regmap_write(lt9611->regmap, 0x8207, 0x3f);
+}
+
+static void lt9611_sleep_setup(struct lt9611 *lt9611)
+{
+ const struct reg_sequence sleep_setup[] = {
+ { 0x8024, 0x76 },
+ { 0x8023, 0x01 },
+ { 0x8157, 0x03 }, /* set addr pin as output */
+ { 0x8149, 0x0b },
+ { 0x8151, 0x30 }, /* disable IRQ */
+ { 0x8102, 0x48 }, /* MIPI Rx power down */
+ { 0x8123, 0x80 },
+ { 0x8130, 0x00 },
+ { 0x8100, 0x01 }, /* bandgap power down */
+ { 0x8101, 0x00 }, /* system clk power down */
+ };
+
+ regmap_multi_reg_write(lt9611->regmap,
+ sleep_setup, ARRAY_SIZE(sleep_setup));
+ lt9611->sleep = true;
+}
+
+static int lt9611_power_on(struct lt9611 *lt9611)
+{
+ int ret;
+ const struct reg_sequence seq[] = {
+ /* LT9611_System_Init */
+ { 0x8101, 0x18 }, /* sel xtal clock */
+
+ /* timer for frequency meter */
+ { 0x821b, 0x69 }, /* timer 2 */
+ { 0x821c, 0x78 },
+ { 0x82cb, 0x69 }, /* timer 1 */
+ { 0x82cc, 0x78 },
+
+ /* irq init */
+ { 0x8251, 0x01 },
+ { 0x8258, 0x0a }, /* hpd irq */
+ { 0x8259, 0x80 }, /* hpd debounce width */
+ { 0x829e, 0xf7 }, /* video check irq */
+
+ /* power consumption for work */
+ { 0x8004, 0xf0 },
+ { 0x8006, 0xf0 },
+ { 0x800a, 0x80 },
+ { 0x800b, 0x40 },
+ { 0x800d, 0xef },
+ { 0x8011, 0xfa },
+ };
+
+ if (lt9611->power_on)
+ return 0;
+
+ ret = regmap_multi_reg_write(lt9611->regmap, seq, ARRAY_SIZE(seq));
+ if (!ret)
+ lt9611->power_on = true;
+
+ return ret;
+}
+
+static int lt9611_power_off(struct lt9611 *lt9611)
+{
+ int ret;
+
+ ret = regmap_write(lt9611->regmap, 0x8130, 0x6a);
+ if (!ret)
+ lt9611->power_on = false;
+
+ return ret;
+}
+
+static void lt9611_reset(struct lt9611 *lt9611)
+{
+ gpiod_set_value_cansleep(lt9611->reset_gpio, 1);
+ msleep(20);
+
+ gpiod_set_value_cansleep(lt9611->reset_gpio, 0);
+ msleep(20);
+
+ gpiod_set_value_cansleep(lt9611->reset_gpio, 1);
+ msleep(100);
+}
+
+static void lt9611_assert_5v(struct lt9611 *lt9611)
+{
+ if (!lt9611->enable_gpio)
+ return;
+
+ gpiod_set_value_cansleep(lt9611->enable_gpio, 1);
+ msleep(20);
+}
+
+static int lt9611_regulator_init(struct lt9611 *lt9611)
+{
+ int ret;
+
+ lt9611->supplies[0].supply = "vdd";
+ lt9611->supplies[1].supply = "vcc";
+
+ ret = devm_regulator_bulk_get(lt9611->dev, 2, lt9611->supplies);
+ if (ret < 0)
+ return ret;
+
+ return regulator_set_load(lt9611->supplies[0].consumer, 300000);
+}
+
+static int lt9611_regulator_enable(struct lt9611 *lt9611)
+{
+ int ret;
+
+ ret = regulator_enable(lt9611->supplies[0].consumer);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(1000, 10000);
+
+ ret = regulator_enable(lt9611->supplies[1].consumer);
+ if (ret < 0) {
+ regulator_disable(lt9611->supplies[0].consumer);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lt9611_modes); i++) {
+ if (lt9611_modes[i].hdisplay == mode->hdisplay &&
+ lt9611_modes[i].vdisplay == mode->vdisplay &&
+ lt9611_modes[i].vrefresh == drm_mode_vrefresh(mode)) {
+ return &lt9611_modes[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* connector funcs */
+static enum drm_connector_status
+lt9611_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct lt9611 *lt9611 = connector_to_lt9611(connector);
+ unsigned int reg_val = 0;
+ int connected = 0;
+
+ regmap_read(lt9611->regmap, 0x825e, &reg_val);
+ connected = (reg_val & BIT(2));
+
+ lt9611->status = connected ? connector_status_connected :
+ connector_status_disconnected;
+
+ return lt9611->status;
+}
+
+static int lt9611_read_edid(struct lt9611 *lt9611)
+{
+ unsigned int temp;
+ int ret = 0;
+ int i, j;
+
+ /* memset to clear old buffer, if any */
+ memset(lt9611->edid_buf, 0, sizeof(lt9611->edid_buf));
+
+ regmap_write(lt9611->regmap, 0x8503, 0xc9);
+
+ /* 0xA0 is EDID device address */
+ regmap_write(lt9611->regmap, 0x8504, 0xa0);
+ /* 0x00 is EDID offset address */
+ regmap_write(lt9611->regmap, 0x8505, 0x00);
+
+ /* length for read */
+ regmap_write(lt9611->regmap, 0x8506, EDID_LEN);
+ regmap_write(lt9611->regmap, 0x8514, 0x7f);
+
+ for (i = 0; i < EDID_LOOP; i++) {
+ /* offset address */
+ regmap_write(lt9611->regmap, 0x8505, i * EDID_LEN);
+ regmap_write(lt9611->regmap, 0x8507, 0x36);
+ regmap_write(lt9611->regmap, 0x8507, 0x31);
+ regmap_write(lt9611->regmap, 0x8507, 0x37);
+ usleep_range(5000, 10000);
+
+ regmap_read(lt9611->regmap, 0x8540, &temp);
+
+ if (temp & KEY_DDC_ACCS_DONE) {
+ for (j = 0; j < EDID_LEN; j++) {
+ regmap_read(lt9611->regmap, 0x8583, &temp);
+ lt9611->edid_buf[i * EDID_LEN + j] = temp;
+ }
+
+ } else if (temp & DDC_NO_ACK) { /* DDC No Ack or Abitration lost */
+ dev_err(lt9611->dev, "read edid failed: no ack\n");
+ ret = -EIO;
+ goto end;
+
+ } else {
+ dev_err(lt9611->dev, "read edid failed: access not done\n");
+ ret = -EIO;
+ goto end;
+ }
+ }
+
+end:
+ regmap_write(lt9611->regmap, 0x8507, 0x1f);
+ return ret;
+}
+
+static int
+lt9611_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+ struct lt9611 *lt9611 = data;
+ int ret;
+
+ if (len > 128)
+ return -EINVAL;
+
+ /* supports up to 1 extension block */
+ /* TODO: add support for more extension blocks */
+ if (block > 1)
+ return -EINVAL;
+
+ if (block == 0) {
+ ret = lt9611_read_edid(lt9611);
+ if (ret) {
+ dev_err(lt9611->dev, "edid read failed\n");
+ return ret;
+ }
+ }
+
+ block %= 2;
+ memcpy(buf, lt9611->edid_buf + (block * 128), len);
+
+ return 0;
+}
+
+static int lt9611_connector_get_modes(struct drm_connector *connector)
+{
+ struct lt9611 *lt9611 = connector_to_lt9611(connector);
+ unsigned int count;
+ struct edid *edid;
+
+ lt9611_power_on(lt9611);
+ edid = drm_do_get_edid(connector, lt9611_get_edid_block, lt9611);
+ drm_connector_update_edid_property(connector, edid);
+ count = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+
+ return count;
+}
+
+static enum drm_mode_status
+lt9611_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode);
+
+ return lt9611_mode ? MODE_OK : MODE_BAD;
+}
+
+/* bridge funcs */
+static void lt9611_bridge_enable(struct drm_bridge *bridge)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+ if (lt9611_power_on(lt9611)) {
+ dev_err(lt9611->dev, "power on failed\n");
+ return;
+ }
+
+ lt9611_mipi_input_analog(lt9611);
+ lt9611_hdmi_tx_digital(lt9611);
+ lt9611_hdmi_tx_phy(lt9611);
+
+ msleep(500);
+
+ lt9611_video_check(lt9611);
+
+ /* Enable HDMI output */
+ regmap_write(lt9611->regmap, 0x8130, 0xea);
+}
+
+static void lt9611_bridge_disable(struct drm_bridge *bridge)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+ int ret;
+
+ /* Disable HDMI output */
+ ret = regmap_write(lt9611->regmap, 0x8130, 0x6a);
+ if (ret) {
+ dev_err(lt9611->dev, "video on failed\n");
+ return;
+ }
+
+ if (lt9611_power_off(lt9611)) {
+ dev_err(lt9611->dev, "power on failed\n");
+ return;
+ }
+}
+
+static struct
+drm_connector_helper_funcs lt9611_bridge_connector_helper_funcs = {
+ .get_modes = lt9611_connector_get_modes,
+ .mode_valid = lt9611_connector_mode_valid,
+};
+
+static const struct drm_connector_funcs lt9611_bridge_connector_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = lt9611_connector_detect,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611,
+ struct device_node *dsi_node)
+{
+ const struct mipi_dsi_device_info info = { "lt9611", 0, NULL };
+ struct mipi_dsi_device *dsi;
+ struct mipi_dsi_host *host;
+ int ret;
+
+ host = of_find_mipi_dsi_host_by_node(dsi_node);
+ if (!host) {
+ dev_err(lt9611->dev, "failed to find dsi host\n");
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ dsi = mipi_dsi_device_register_full(host, &info);
+ if (IS_ERR(dsi)) {
+ dev_err(lt9611->dev, "failed to create dsi device\n");
+ return dsi;
+ }
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_MODE_VIDEO_HSE;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(lt9611->dev, "failed to attach dsi to host\n");
+ mipi_dsi_device_unregister(dsi);
+ return ERR_PTR(ret);
+ }
+
+ return dsi;
+}
+
+static void lt9611_bridge_detach(struct drm_bridge *bridge)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+ if (lt9611->dsi1) {
+ mipi_dsi_detach(lt9611->dsi1);
+ mipi_dsi_device_unregister(lt9611->dsi1);
+ }
+
+ mipi_dsi_detach(lt9611->dsi0);
+ mipi_dsi_device_unregister(lt9611->dsi0);
+}
+
+static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt9611)
+{
+ int ret;
+
+ ret = drm_connector_init(bridge->dev, &lt9611->connector,
+ &lt9611_bridge_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ if (ret) {
+ DRM_ERROR("Failed to initialize connector with drm\n");
+ return ret;
+ }
+
+ drm_connector_helper_add(&lt9611->connector,
+ &lt9611_bridge_connector_helper_funcs);
+ drm_connector_attach_encoder(&lt9611->connector, bridge->encoder);
+
+ if (!bridge->encoder) {
+ DRM_ERROR("Parent encoder object not found");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int lt9611_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+ int ret;
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
+ ret = lt9611_connector_init(bridge, lt9611);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Attach primary DSI */
+ lt9611->dsi0 = lt9611_attach_dsi(lt9611, lt9611->dsi0_node);
+ if (IS_ERR(lt9611->dsi0))
+ return PTR_ERR(lt9611->dsi0);
+
+ /* Attach secondary DSI, if specified */
+ if (lt9611->dsi1_node) {
+ lt9611->dsi1 = lt9611_attach_dsi(lt9611, lt9611->dsi1_node);
+ if (IS_ERR(lt9611->dsi1)) {
+ ret = PTR_ERR(lt9611->dsi1);
+ goto err_unregister_dsi0;
+ }
+ }
+
+ return 0;
+
+err_unregister_dsi0:
+ lt9611_bridge_detach(bridge);
+ drm_connector_cleanup(&lt9611->connector);
+ mipi_dsi_device_unregister(lt9611->dsi0);
+
+ return ret;
+}
+
+static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode);
+
+ return lt9611_mode ? MODE_OK : MODE_BAD;
+}
+
+static void lt9611_bridge_pre_enable(struct drm_bridge *bridge)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+ if (!lt9611->sleep)
+ return;
+
+ lt9611_reset(lt9611);
+ regmap_write(lt9611->regmap, 0x80ee, 0x01);
+
+ lt9611->sleep = false;
+}
+
+static void lt9611_bridge_post_disable(struct drm_bridge *bridge)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+ lt9611_sleep_setup(lt9611);
+}
+
+static void lt9611_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adj_mode)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+ struct hdmi_avi_infoframe avi_frame;
+ int ret;
+
+ lt9611_bridge_pre_enable(bridge);
+
+ lt9611_mipi_input_digital(lt9611, mode);
+ lt9611_pll_setup(lt9611, mode);
+ lt9611_mipi_video_setup(lt9611, mode);
+ lt9611_pcr_setup(lt9611, mode);
+
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame,
+ &lt9611->connector,
+ mode);
+ if (!ret)
+ lt9611->vic = avi_frame.video_code;
+}
+
+static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+ unsigned int reg_val = 0;
+ int connected;
+
+ regmap_read(lt9611->regmap, 0x825e, &reg_val);
+ connected = reg_val & BIT(2);
+
+ lt9611->status = connected ? connector_status_connected :
+ connector_status_disconnected;
+
+ return lt9611->status;
+}
+
+static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+ lt9611_power_on(lt9611);
+ return drm_do_get_edid(connector, lt9611_get_edid_block, lt9611);
+}
+
+static void lt9611_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+ lt9611_enable_hpd_interrupts(lt9611);
+}
+
+static const struct drm_bridge_funcs lt9611_bridge_funcs = {
+ .attach = lt9611_bridge_attach,
+ .detach = lt9611_bridge_detach,
+ .mode_valid = lt9611_bridge_mode_valid,
+ .enable = lt9611_bridge_enable,
+ .disable = lt9611_bridge_disable,
+ .post_disable = lt9611_bridge_post_disable,
+ .mode_set = lt9611_bridge_mode_set,
+ .detect = lt9611_bridge_detect,
+ .get_edid = lt9611_bridge_get_edid,
+ .hpd_enable = lt9611_bridge_hpd_enable,
+};
+
+static int lt9611_parse_dt(struct device *dev,
+ struct lt9611 *lt9611)
+{
+ lt9611->dsi0_node = of_graph_get_remote_node(dev->of_node, 1, -1);
+ if (!lt9611->dsi0_node) {
+ dev_err(lt9611->dev, "failed to get remote node for primary dsi\n");
+ return -ENODEV;
+ }
+
+ lt9611->dsi1_node = of_graph_get_remote_node(dev->of_node, 2, -1);
+
+ lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode");
+
+ return 0;
+}
+
+static int lt9611_gpio_init(struct lt9611 *lt9611)
+{
+ struct device *dev = lt9611->dev;
+
+ lt9611->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(lt9611->reset_gpio)) {
+ dev_err(dev, "failed to acquire reset gpio\n");
+ return PTR_ERR(lt9611->reset_gpio);
+ }
+
+ lt9611->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(lt9611->enable_gpio)) {
+ dev_err(dev, "failed to acquire enable gpio\n");
+ return PTR_ERR(lt9611->enable_gpio);
+ }
+
+ return 0;
+}
+
+static int lt9611_read_device_rev(struct lt9611 *lt9611)
+{
+ unsigned int rev;
+ int ret;
+
+ regmap_write(lt9611->regmap, 0x80ee, 0x01);
+ ret = regmap_read(lt9611->regmap, 0x8002, &rev);
+ if (ret)
+ dev_err(lt9611->dev, "failed to read revision: %d\n", ret);
+ else
+ dev_info(lt9611->dev, "LT9611 revision: 0x%x\n", rev);
+
+ return ret;
+}
+
+static int lt9611_hdmi_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *fmt,
+ struct hdmi_codec_params *hparms)
+{
+ struct lt9611 *lt9611 = data;
+
+ if (hparms->sample_rate == 48000)
+ regmap_write(lt9611->regmap, 0x840f, 0x2b);
+ else if (hparms->sample_rate == 96000)
+ regmap_write(lt9611->regmap, 0x840f, 0xab);
+ else
+ return -EINVAL;
+
+ regmap_write(lt9611->regmap, 0x8435, 0x00);
+ regmap_write(lt9611->regmap, 0x8436, 0x18);
+ regmap_write(lt9611->regmap, 0x8437, 0x00);
+
+ return 0;
+}
+
+static int lt9611_audio_startup(struct device *dev, void *data)
+{
+ struct lt9611 *lt9611 = data;
+
+ regmap_write(lt9611->regmap, 0x82d6, 0x8c);
+ regmap_write(lt9611->regmap, 0x82d7, 0x04);
+
+ regmap_write(lt9611->regmap, 0x8406, 0x08);
+ regmap_write(lt9611->regmap, 0x8407, 0x10);
+
+ regmap_write(lt9611->regmap, 0x8434, 0xd5);
+
+ return 0;
+}
+
+static void lt9611_audio_shutdown(struct device *dev, void *data)
+{
+ struct lt9611 *lt9611 = data;
+
+ regmap_write(lt9611->regmap, 0x8406, 0x00);
+ regmap_write(lt9611->regmap, 0x8407, 0x00);
+}
+
+static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
+ struct device_node *endpoint)
+{
+ struct of_endpoint of_ep;
+ int ret;
+
+ ret = of_graph_parse_endpoint(endpoint, &of_ep);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * HDMI sound should be located as reg = <2>
+ * Then, it is sound port 0
+ */
+ if (of_ep.port == 2)
+ return 0;
+
+ return -EINVAL;
+}
+
+static const struct hdmi_codec_ops lt9611_codec_ops = {
+ .hw_params = lt9611_hdmi_hw_params,
+ .audio_shutdown = lt9611_audio_shutdown,
+ .audio_startup = lt9611_audio_startup,
+ .get_dai_id = lt9611_hdmi_i2s_get_dai_id,
+};
+
+static struct hdmi_codec_pdata codec_data = {
+ .ops = &lt9611_codec_ops,
+ .max_i2s_channels = 8,
+ .i2s = 1,
+};
+
+static int lt9611_audio_init(struct device *dev, struct lt9611 *lt9611)
+{
+ codec_data.data = lt9611;
+ lt9611->audio_pdev =
+ platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO,
+ &codec_data, sizeof(codec_data));
+
+ return PTR_ERR_OR_ZERO(lt9611->audio_pdev);
+}
+
+static void lt9611_audio_exit(struct lt9611 *lt9611)
+{
+ if (lt9611->audio_pdev) {
+ platform_device_unregister(lt9611->audio_pdev);
+ lt9611->audio_pdev = NULL;
+ }
+}
+
+static int lt9611_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lt9611 *lt9611;
+ struct device *dev = &client->dev;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(dev, "device doesn't support I2C\n");
+ return -ENODEV;
+ }
+
+ lt9611 = devm_kzalloc(dev, sizeof(*lt9611), GFP_KERNEL);
+ if (!lt9611)
+ return -ENOMEM;
+
+ lt9611->dev = &client->dev;
+ lt9611->client = client;
+ lt9611->sleep = false;
+
+ lt9611->regmap = devm_regmap_init_i2c(client, &lt9611_regmap_config);
+ if (IS_ERR(lt9611->regmap)) {
+ dev_err(lt9611->dev, "regmap i2c init failed\n");
+ return PTR_ERR(lt9611->regmap);
+ }
+
+ ret = lt9611_parse_dt(&client->dev, lt9611);
+ if (ret) {
+ dev_err(dev, "failed to parse device tree\n");
+ return ret;
+ }
+
+ ret = lt9611_gpio_init(lt9611);
+ if (ret < 0)
+ goto err_of_put;
+
+ ret = lt9611_regulator_init(lt9611);
+ if (ret < 0)
+ goto err_of_put;
+
+ lt9611_assert_5v(lt9611);
+
+ ret = lt9611_regulator_enable(lt9611);
+ if (ret)
+ goto err_of_put;
+
+ lt9611_reset(lt9611);
+
+ ret = lt9611_read_device_rev(lt9611);
+ if (ret) {
+ dev_err(dev, "failed to read chip rev\n");
+ goto err_disable_regulators;
+ }
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ lt9611_irq_thread_handler,
+ IRQF_ONESHOT, "lt9611", lt9611);
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ goto err_disable_regulators;
+ }
+
+ i2c_set_clientdata(client, lt9611);
+
+ lt9611->bridge.funcs = &lt9611_bridge_funcs;
+ lt9611->bridge.of_node = client->dev.of_node;
+ lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
+ DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES;
+ lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
+
+ drm_bridge_add(&lt9611->bridge);
+
+ lt9611_enable_hpd_interrupts(lt9611);
+
+ return lt9611_audio_init(dev, lt9611);
+
+err_disable_regulators:
+ regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);
+
+err_of_put:
+ of_node_put(lt9611->dsi1_node);
+ of_node_put(lt9611->dsi0_node);
+
+ return ret;
+}
+
+static int lt9611_remove(struct i2c_client *client)
+{
+ struct lt9611 *lt9611 = i2c_get_clientdata(client);
+
+ disable_irq(client->irq);
+ lt9611_audio_exit(lt9611);
+ drm_bridge_remove(&lt9611->bridge);
+
+ regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);
+
+ of_node_put(lt9611->dsi1_node);
+ of_node_put(lt9611->dsi0_node);
+
+ return 0;
+}
+
+static struct i2c_device_id lt9611_id[] = {
+ { "lontium,lt9611", 0 },
+ {}
+};
+
+static const struct of_device_id lt9611_match_table[] = {
+ { .compatible = "lontium,lt9611" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lt9611_match_table);
+
+static struct i2c_driver lt9611_driver = {
+ .driver = {
+ .name = "lt9611",
+ .of_match_table = lt9611_match_table,
+ },
+ .probe = lt9611_probe,
+ .remove = lt9611_remove,
+ .id_table = lt9611_id,
+};
+module_i2c_driver(lt9611_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
index 6200f12a37e6..d2808c4a6fb1 100644
--- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
+++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
@@ -61,7 +61,6 @@ struct ge_b850v3_lvds {
struct drm_bridge bridge;
struct i2c_client *stdp4028_i2c;
struct i2c_client *stdp2690_i2c;
- struct edid *edid;
};
static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr;
@@ -131,22 +130,26 @@ err:
return NULL;
}
-static int ge_b850v3_lvds_get_modes(struct drm_connector *connector)
+static struct edid *ge_b850v3_lvds_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
{
struct i2c_client *client;
- int num_modes = 0;
client = ge_b850v3_lvds_ptr->stdp2690_i2c;
- kfree(ge_b850v3_lvds_ptr->edid);
- ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client);
+ return (struct edid *)stdp2690_get_edid(client);
+}
- if (ge_b850v3_lvds_ptr->edid) {
- drm_connector_update_edid_property(connector,
- ge_b850v3_lvds_ptr->edid);
- num_modes = drm_add_edid_modes(connector,
- ge_b850v3_lvds_ptr->edid);
- }
+static int ge_b850v3_lvds_get_modes(struct drm_connector *connector)
+{
+ struct edid *edid;
+ int num_modes;
+
+ edid = ge_b850v3_lvds_get_edid(&ge_b850v3_lvds_ptr->bridge, connector);
+
+ drm_connector_update_edid_property(connector, edid);
+ num_modes = drm_add_edid_modes(connector, edid);
+ kfree(edid);
return num_modes;
}
@@ -163,8 +166,7 @@ drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = {
.mode_valid = ge_b850v3_lvds_mode_valid,
};
-static enum drm_connector_status ge_b850v3_lvds_detect(
- struct drm_connector *connector, bool force)
+static enum drm_connector_status ge_b850v3_lvds_bridge_detect(struct drm_bridge *bridge)
{
struct i2c_client *stdp4028_i2c =
ge_b850v3_lvds_ptr->stdp4028_i2c;
@@ -182,6 +184,12 @@ static enum drm_connector_status ge_b850v3_lvds_detect(
return connector_status_unknown;
}
+static enum drm_connector_status ge_b850v3_lvds_detect(struct drm_connector *connector,
+ bool force)
+{
+ return ge_b850v3_lvds_bridge_detect(&ge_b850v3_lvds_ptr->bridge);
+}
+
static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = ge_b850v3_lvds_detect,
@@ -191,34 +199,11 @@ static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
-static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id)
-{
- struct i2c_client *stdp4028_i2c
- = ge_b850v3_lvds_ptr->stdp4028_i2c;
-
- i2c_smbus_write_word_data(stdp4028_i2c,
- STDP4028_DPTX_IRQ_STS_REG,
- STDP4028_DPTX_IRQ_CLEAR);
-
- if (ge_b850v3_lvds_ptr->connector.dev)
- drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->connector.dev);
-
- return IRQ_HANDLED;
-}
-
-static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
- enum drm_bridge_attach_flags flags)
+static int ge_b850v3_lvds_create_connector(struct drm_bridge *bridge)
{
struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector;
- struct i2c_client *stdp4028_i2c
- = ge_b850v3_lvds_ptr->stdp4028_i2c;
int ret;
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
- DRM_ERROR("Fix bridge driver to make connector optional!");
- return -EINVAL;
- }
-
if (!bridge->encoder) {
DRM_ERROR("Parent encoder object not found");
return -ENODEV;
@@ -237,9 +222,29 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
return ret;
}
- ret = drm_connector_attach_encoder(connector, bridge->encoder);
- if (ret)
- return ret;
+ return drm_connector_attach_encoder(connector, bridge->encoder);
+}
+
+static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id)
+{
+ struct i2c_client *stdp4028_i2c
+ = ge_b850v3_lvds_ptr->stdp4028_i2c;
+
+ i2c_smbus_write_word_data(stdp4028_i2c,
+ STDP4028_DPTX_IRQ_STS_REG,
+ STDP4028_DPTX_IRQ_CLEAR);
+
+ if (ge_b850v3_lvds_ptr->bridge.dev)
+ drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->bridge.dev);
+
+ return IRQ_HANDLED;
+}
+
+static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct i2c_client *stdp4028_i2c
+ = ge_b850v3_lvds_ptr->stdp4028_i2c;
/* Configures the bridge to re-enable interrupts after each ack. */
i2c_smbus_write_word_data(stdp4028_i2c,
@@ -251,11 +256,16 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
STDP4028_DPTX_IRQ_EN_REG,
STDP4028_DPTX_IRQ_CONFIG);
- return 0;
+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+ return 0;
+
+ return ge_b850v3_lvds_create_connector(bridge);
}
static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = {
.attach = ge_b850v3_lvds_attach,
+ .detect = ge_b850v3_lvds_bridge_detect,
+ .get_edid = ge_b850v3_lvds_get_edid,
};
static int ge_b850v3_lvds_init(struct device *dev)
@@ -291,8 +301,6 @@ static void ge_b850v3_lvds_remove(void)
drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge);
- kfree(ge_b850v3_lvds_ptr->edid);
-
ge_b850v3_lvds_ptr = NULL;
out:
mutex_unlock(&ge_b850v3_lvds_dev_mutex);
@@ -302,14 +310,21 @@ static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c,
const struct i2c_device_id *id)
{
struct device *dev = &stdp4028_i2c->dev;
+ int ret;
+
+ ret = ge_b850v3_lvds_init(dev);
- ge_b850v3_lvds_init(dev);
+ if (ret)
+ return ret;
ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c;
i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr);
/* drm bridge initialization */
ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs;
+ ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT |
+ DRM_BRIDGE_OP_EDID;
+ ge_b850v3_lvds_ptr->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node;
drm_bridge_add(&ge_b850v3_lvds_ptr->bridge);
@@ -361,8 +376,12 @@ static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c,
const struct i2c_device_id *id)
{
struct device *dev = &stdp2690_i2c->dev;
+ int ret;
+
+ ret = ge_b850v3_lvds_init(dev);
- ge_b850v3_lvds_init(dev);
+ if (ret)
+ return ret;
ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c;
i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr);
diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
index 438e566ce0a4..e941c1132598 100644
--- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
+++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
@@ -29,8 +29,7 @@ struct ptn3460_bridge {
struct drm_connector connector;
struct i2c_client *client;
struct drm_bridge bridge;
- struct edid *edid;
- struct drm_panel *panel;
+ struct drm_bridge *panel_bridge;
struct gpio_desc *gpio_pd_n;
struct gpio_desc *gpio_rst_n;
u32 edid_emulation;
@@ -127,11 +126,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
usleep_range(10, 20);
gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
- if (drm_panel_prepare(ptn_bridge->panel)) {
- DRM_ERROR("failed to prepare panel\n");
- return;
- }
-
/*
* There's a bug in the PTN chip where it falsely asserts hotplug before
* it is fully functional. We're forced to wait for the maximum start up
@@ -146,16 +140,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
ptn_bridge->enabled = true;
}
-static void ptn3460_enable(struct drm_bridge *bridge)
-{
- struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
-
- if (drm_panel_enable(ptn_bridge->panel)) {
- DRM_ERROR("failed to enable panel\n");
- return;
- }
-}
-
static void ptn3460_disable(struct drm_bridge *bridge)
{
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
@@ -165,36 +149,18 @@ static void ptn3460_disable(struct drm_bridge *bridge)
ptn_bridge->enabled = false;
- if (drm_panel_disable(ptn_bridge->panel)) {
- DRM_ERROR("failed to disable panel\n");
- return;
- }
-
gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
gpiod_set_value(ptn_bridge->gpio_pd_n, 0);
}
-static void ptn3460_post_disable(struct drm_bridge *bridge)
-{
- struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
- if (drm_panel_unprepare(ptn_bridge->panel)) {
- DRM_ERROR("failed to unprepare panel\n");
- return;
- }
-}
-
-static int ptn3460_get_modes(struct drm_connector *connector)
+static struct edid *ptn3460_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
{
- struct ptn3460_bridge *ptn_bridge;
- u8 *edid;
- int ret, num_modes = 0;
+ struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
bool power_off;
-
- ptn_bridge = connector_to_ptn3460(connector);
-
- if (ptn_bridge->edid)
- return drm_add_edid_modes(connector, ptn_bridge->edid);
+ u8 *edid;
+ int ret;
power_off = !ptn_bridge->enabled;
ptn3460_pre_enable(&ptn_bridge->bridge);
@@ -202,30 +168,40 @@ static int ptn3460_get_modes(struct drm_connector *connector)
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (!edid) {
DRM_ERROR("Failed to allocate EDID\n");
- return 0;
+ goto out;
}
ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid,
- EDID_LENGTH);
+ EDID_LENGTH);
if (ret) {
kfree(edid);
+ edid = NULL;
goto out;
}
- ptn_bridge->edid = (struct edid *)edid;
- drm_connector_update_edid_property(connector, ptn_bridge->edid);
-
- num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
-
out:
if (power_off)
ptn3460_disable(&ptn_bridge->bridge);
+ return (struct edid *)edid;
+}
+
+static int ptn3460_connector_get_modes(struct drm_connector *connector)
+{
+ struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
+ struct edid *edid;
+ int num_modes;
+
+ edid = ptn3460_get_edid(&ptn_bridge->bridge, connector);
+ drm_connector_update_edid_property(connector, edid);
+ num_modes = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+
return num_modes;
}
static const struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
- .get_modes = ptn3460_get_modes,
+ .get_modes = ptn3460_connector_get_modes,
};
static const struct drm_connector_funcs ptn3460_connector_funcs = {
@@ -242,10 +218,14 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge,
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
int ret;
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
- DRM_ERROR("Fix bridge driver to make connector optional!");
- return -EINVAL;
- }
+ /* Let this driver create connector if requested */
+ ret = drm_bridge_attach(bridge->encoder, ptn_bridge->panel_bridge,
+ bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+ if (ret < 0)
+ return ret;
+
+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+ return 0;
if (!bridge->encoder) {
DRM_ERROR("Parent encoder object not found");
@@ -265,9 +245,6 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge,
drm_connector_attach_encoder(&ptn_bridge->connector,
bridge->encoder);
- if (ptn_bridge->panel)
- drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
-
drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
return ret;
@@ -275,10 +252,9 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge,
static const struct drm_bridge_funcs ptn3460_bridge_funcs = {
.pre_enable = ptn3460_pre_enable,
- .enable = ptn3460_enable,
.disable = ptn3460_disable,
- .post_disable = ptn3460_post_disable,
.attach = ptn3460_bridge_attach,
+ .get_edid = ptn3460_get_edid,
};
static int ptn3460_probe(struct i2c_client *client,
@@ -286,6 +262,8 @@ static int ptn3460_probe(struct i2c_client *client,
{
struct device *dev = &client->dev;
struct ptn3460_bridge *ptn_bridge;
+ struct drm_bridge *panel_bridge;
+ struct drm_panel *panel;
int ret;
ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
@@ -293,10 +271,15 @@ static int ptn3460_probe(struct i2c_client *client,
return -ENOMEM;
}
- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ptn_bridge->panel, NULL);
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL);
if (ret)
return ret;
+ panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
+
+ ptn_bridge->panel_bridge = panel_bridge;
ptn_bridge->client = client;
ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown",
@@ -327,6 +310,8 @@ static int ptn3460_probe(struct i2c_client *client,
}
ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
+ ptn_bridge->bridge.ops = DRM_BRIDGE_OP_EDID;
+ ptn_bridge->bridge.type = DRM_MODE_CONNECTOR_LVDS;
ptn_bridge->bridge.of_node = dev->of_node;
drm_bridge_add(&ptn_bridge->bridge);
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 1e63ed6b18aa..0ddc37551194 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -82,18 +82,11 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
drm_connector_attach_encoder(&panel_bridge->connector,
bridge->encoder);
- ret = drm_panel_attach(panel_bridge->panel, &panel_bridge->connector);
- if (ret < 0)
- return ret;
-
return 0;
}
static void panel_bridge_detach(struct drm_bridge *bridge)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
- drm_panel_detach(panel_bridge->panel);
}
static void panel_bridge_pre_enable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
index d789ea2a7fb9..614b19f0f1b7 100644
--- a/drivers/gpu/drm/bridge/parade-ps8622.c
+++ b/drivers/gpu/drm/bridge/parade-ps8622.c
@@ -42,10 +42,9 @@
#endif
struct ps8622_bridge {
- struct drm_connector connector;
struct i2c_client *client;
struct drm_bridge bridge;
- struct drm_panel *panel;
+ struct drm_bridge *panel_bridge;
struct regulator *v12;
struct backlight_device *bl;
@@ -64,12 +63,6 @@ static inline struct ps8622_bridge *
return container_of(bridge, struct ps8622_bridge, bridge);
}
-static inline struct ps8622_bridge *
- connector_to_ps8622(struct drm_connector *connector)
-{
- return container_of(connector, struct ps8622_bridge, connector);
-}
-
static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
{
int ret;
@@ -365,11 +358,6 @@ static void ps8622_pre_enable(struct drm_bridge *bridge)
DRM_ERROR("fails to enable ps8622->v12");
}
- if (drm_panel_prepare(ps8622->panel)) {
- DRM_ERROR("failed to prepare panel\n");
- return;
- }
-
gpiod_set_value(ps8622->gpio_slp, 1);
/*
@@ -399,24 +387,9 @@ static void ps8622_pre_enable(struct drm_bridge *bridge)
ps8622->enabled = true;
}
-static void ps8622_enable(struct drm_bridge *bridge)
-{
- struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
-
- if (drm_panel_enable(ps8622->panel)) {
- DRM_ERROR("failed to enable panel\n");
- return;
- }
-}
-
static void ps8622_disable(struct drm_bridge *bridge)
{
- struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
-
- if (drm_panel_disable(ps8622->panel)) {
- DRM_ERROR("failed to disable panel\n");
- return;
- }
+ /* Delay after panel is disabled */
msleep(PS8622_PWMO_END_T12_MS);
}
@@ -436,11 +409,6 @@ static void ps8622_post_disable(struct drm_bridge *bridge)
*/
gpiod_set_value(ps8622->gpio_slp, 0);
- if (drm_panel_unprepare(ps8622->panel)) {
- DRM_ERROR("failed to unprepare panel\n");
- return;
- }
-
if (ps8622->v12)
regulator_disable(ps8622->v12);
@@ -455,67 +423,17 @@ static void ps8622_post_disable(struct drm_bridge *bridge)
msleep(PS8622_POWER_OFF_T17_MS);
}
-static int ps8622_get_modes(struct drm_connector *connector)
-{
- struct ps8622_bridge *ps8622;
-
- ps8622 = connector_to_ps8622(connector);
-
- return drm_panel_get_modes(ps8622->panel, connector);
-}
-
-static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
- .get_modes = ps8622_get_modes,
-};
-
-static const struct drm_connector_funcs ps8622_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
static int ps8622_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
- int ret;
-
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
- DRM_ERROR("Fix bridge driver to make connector optional!");
- return -EINVAL;
- }
- if (!bridge->encoder) {
- DRM_ERROR("Parent encoder object not found");
- return -ENODEV;
- }
-
- ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
- ret = drm_connector_init(bridge->dev, &ps8622->connector,
- &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
- if (ret) {
- DRM_ERROR("Failed to initialize connector with drm\n");
- return ret;
- }
- drm_connector_helper_add(&ps8622->connector,
- &ps8622_connector_helper_funcs);
- drm_connector_register(&ps8622->connector);
- drm_connector_attach_encoder(&ps8622->connector,
- bridge->encoder);
-
- if (ps8622->panel)
- drm_panel_attach(ps8622->panel, &ps8622->connector);
-
- drm_helper_hpd_irq_event(ps8622->connector.dev);
-
- return ret;
+ return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge,
+ &ps8622->bridge, flags);
}
static const struct drm_bridge_funcs ps8622_bridge_funcs = {
.pre_enable = ps8622_pre_enable,
- .enable = ps8622_enable,
.disable = ps8622_disable,
.post_disable = ps8622_post_disable,
.attach = ps8622_attach,
@@ -533,16 +451,23 @@ static int ps8622_probe(struct i2c_client *client,
{
struct device *dev = &client->dev;
struct ps8622_bridge *ps8622;
+ struct drm_bridge *panel_bridge;
+ struct drm_panel *panel;
int ret;
ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
if (!ps8622)
return -ENOMEM;
- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ps8622->panel, NULL);
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL);
if (ret)
return ret;
+ panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
+
+ ps8622->panel_bridge = panel_bridge;
ps8622->client = client;
ps8622->v12 = devm_regulator_get(dev, "vdd12");
@@ -595,6 +520,7 @@ static int ps8622_probe(struct i2c_client *client,
}
ps8622->bridge.funcs = &ps8622_bridge_funcs;
+ ps8622->bridge.type = DRM_MODE_CONNECTOR_LVDS;
ps8622->bridge.of_node = dev->of_node;
drm_bridge_add(&ps8622->bridge);
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
index 4b099196afeb..9f7b7a9c53c5 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -82,8 +82,11 @@ static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
sizeof(vdo_ctrl_buf),
vdo_ctrl_buf);
- if (ret < 0)
+ if (ret < 0) {
+ DRM_ERROR("failed to %sable VDO: %d\n",
+ ctrl == ENABLE ? "en" : "dis", ret);
return ret;
+ }
return 0;
}
@@ -150,10 +153,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge)
}
ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE);
- if (ret) {
- DRM_ERROR("failed to enable VDO: %d\n", ret);
+ if (ret)
goto err_regulators_disable;
- }
/* Switch access edp panel's edid through i2c */
ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
@@ -175,9 +176,7 @@ static void ps8640_post_disable(struct drm_bridge *bridge)
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
int ret;
- ret = ps8640_bridge_vdo_control(ps_bridge, DISABLE);
- if (ret < 0)
- DRM_ERROR("failed to disable VDO: %d\n", ret);
+ ps8640_bridge_vdo_control(ps_bridge, DISABLE);
gpiod_set_value(ps_bridge->gpio_reset, 1);
gpiod_set_value(ps_bridge->gpio_powerdown, 1);
@@ -200,6 +199,10 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge,
.channel = 0,
.node = NULL,
};
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+ return -EINVAL;
+
/* port@0 is ps8640 dsi input port */
in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
if (!in_ep)
@@ -242,8 +245,18 @@ err_dsi_attach:
return ret;
}
+static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+
+ return drm_get_edid(connector,
+ ps_bridge->page[PAGE0_DP_CNTL]->adapter);
+}
+
static const struct drm_bridge_funcs ps8640_bridge_funcs = {
.attach = ps8640_bridge_attach,
+ .get_edid = ps8640_bridge_get_edid,
.post_disable = ps8640_post_disable,
.pre_enable = ps8640_pre_enable,
};
@@ -294,6 +307,8 @@ static int ps8640_probe(struct i2c_client *client)
ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
ps_bridge->bridge.of_node = dev->of_node;
+ ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID;
+ ps_bridge->bridge.type = DRM_MODE_CONNECTOR_eDP;
ps_bridge->page[PAGE0_DP_CNTL] = client;
diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c
new file mode 100644
index 000000000000..1bfdfc6affaf
--- /dev/null
+++ b/drivers/gpu/drm/bridge/tc358762.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Marek Vasut <marex@denx.de>
+ *
+ * Based on tc358764.c by
+ * Andrzej Hajda <a.hajda@samsung.com>
+ * Maciej Purski <m.purski@samsung.com>
+ *
+ * Based on rpi_touchscreen.c by
+ * Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+/* PPI layer registers */
+#define PPI_STARTPPI 0x0104 /* START control bit */
+#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */
+#define PPI_D0S_ATMR 0x0144
+#define PPI_D1S_ATMR 0x0148
+#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* Assertion timer for Lane 0 */
+#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* Assertion timer for Lane 1 */
+#define PPI_START_FUNCTION 1
+
+/* DSI layer registers */
+#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */
+#define DSI_LANEENABLE 0x0210 /* Enables each lane */
+#define DSI_RX_START 1
+
+/* LCDC/DPI Host Registers */
+#define LCDCTRL 0x0420
+
+/* SPI Master Registers */
+#define SPICMR 0x0450
+#define SPITCR 0x0454
+
+/* System Controller Registers */
+#define SYSCTRL 0x0464
+
+/* System registers */
+#define LPX_PERIOD 3
+
+/* Lane enable PPI and DSI register bits */
+#define LANEENABLE_CLEN BIT(0)
+#define LANEENABLE_L0EN BIT(1)
+#define LANEENABLE_L1EN BIT(2)
+
+struct tc358762 {
+ struct device *dev;
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+ struct regulator *regulator;
+ struct drm_bridge *panel_bridge;
+ bool pre_enabled;
+ int error;
+};
+
+static int tc358762_clear_error(struct tc358762 *ctx)
+{
+ int ret = ctx->error;
+
+ ctx->error = 0;
+ return ret;
+}
+
+static void tc358762_write(struct tc358762 *ctx, u16 addr, u32 val)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ ssize_t ret;
+ u8 data[6];
+
+ if (ctx->error)
+ return;
+
+ data[0] = addr;
+ data[1] = addr >> 8;
+ data[2] = val;
+ data[3] = val >> 8;
+ data[4] = val >> 16;
+ data[5] = val >> 24;
+
+ ret = mipi_dsi_generic_write(dsi, data, sizeof(data));
+ if (ret < 0)
+ ctx->error = ret;
+}
+
+static inline struct tc358762 *bridge_to_tc358762(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct tc358762, bridge);
+}
+
+static int tc358762_init(struct tc358762 *ctx)
+{
+ tc358762_write(ctx, DSI_LANEENABLE,
+ LANEENABLE_L0EN | LANEENABLE_CLEN);
+ tc358762_write(ctx, PPI_D0S_CLRSIPOCOUNT, 5);
+ tc358762_write(ctx, PPI_D1S_CLRSIPOCOUNT, 5);
+ tc358762_write(ctx, PPI_D0S_ATMR, 0);
+ tc358762_write(ctx, PPI_D1S_ATMR, 0);
+ tc358762_write(ctx, PPI_LPTXTIMECNT, LPX_PERIOD);
+
+ tc358762_write(ctx, SPICMR, 0x00);
+ tc358762_write(ctx, LCDCTRL, 0x00100150);
+ tc358762_write(ctx, SYSCTRL, 0x040f);
+ msleep(100);
+
+ tc358762_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION);
+ tc358762_write(ctx, DSI_STARTDSI, DSI_RX_START);
+
+ msleep(100);
+
+ return tc358762_clear_error(ctx);
+}
+
+static void tc358762_post_disable(struct drm_bridge *bridge)
+{
+ struct tc358762 *ctx = bridge_to_tc358762(bridge);
+ int ret;
+
+ /*
+ * The post_disable hook might be called multiple times.
+ * We want to avoid regulator imbalance below.
+ */
+ if (!ctx->pre_enabled)
+ return;
+
+ ctx->pre_enabled = false;
+
+ ret = regulator_disable(ctx->regulator);
+ if (ret < 0)
+ dev_err(ctx->dev, "error disabling regulators (%d)\n", ret);
+}
+
+static void tc358762_pre_enable(struct drm_bridge *bridge)
+{
+ struct tc358762 *ctx = bridge_to_tc358762(bridge);
+ int ret;
+
+ ret = regulator_enable(ctx->regulator);
+ if (ret < 0)
+ dev_err(ctx->dev, "error enabling regulators (%d)\n", ret);
+
+ ret = tc358762_init(ctx);
+ if (ret < 0)
+ dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
+
+ ctx->pre_enabled = true;
+}
+
+static int tc358762_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct tc358762 *ctx = bridge_to_tc358762(bridge);
+
+ return drm_bridge_attach(bridge->encoder, ctx->panel_bridge,
+ bridge, flags);
+}
+
+static const struct drm_bridge_funcs tc358762_bridge_funcs = {
+ .post_disable = tc358762_post_disable,
+ .pre_enable = tc358762_pre_enable,
+ .attach = tc358762_attach,
+};
+
+static int tc358762_parse_dt(struct tc358762 *ctx)
+{
+ struct drm_bridge *panel_bridge;
+ struct device *dev = ctx->dev;
+ struct drm_panel *panel;
+ int ret;
+
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
+ if (ret)
+ return ret;
+
+ panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
+
+ ctx->panel_bridge = panel_bridge;
+
+ return 0;
+}
+
+static int tc358762_configure_regulators(struct tc358762 *ctx)
+{
+ ctx->regulator = devm_regulator_get(ctx->dev, "vddc");
+ if (IS_ERR(ctx->regulator))
+ return PTR_ERR(ctx->regulator);
+
+ return 0;
+}
+
+static int tc358762_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct tc358762 *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(struct tc358762), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ ctx->dev = dev;
+ ctx->pre_enabled = false;
+
+ /* TODO: Find out how to get dual-lane mode working */
+ dsi->lanes = 1;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_MODE_LPM;
+
+ ret = tc358762_parse_dt(ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = tc358762_configure_regulators(ctx);
+ if (ret < 0)
+ return ret;
+
+ ctx->bridge.funcs = &tc358762_bridge_funcs;
+ ctx->bridge.type = DRM_MODE_CONNECTOR_DPI;
+ ctx->bridge.of_node = dev->of_node;
+
+ drm_bridge_add(&ctx->bridge);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ drm_bridge_remove(&ctx->bridge);
+ dev_err(dev, "failed to attach dsi\n");
+ }
+
+ return ret;
+}
+
+static int tc358762_remove(struct mipi_dsi_device *dsi)
+{
+ struct tc358762 *ctx = mipi_dsi_get_drvdata(dsi);
+
+ mipi_dsi_detach(dsi);
+ drm_bridge_remove(&ctx->bridge);
+
+ return 0;
+}
+
+static const struct of_device_id tc358762_of_match[] = {
+ { .compatible = "toshiba,tc358762" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tc358762_of_match);
+
+static struct mipi_dsi_driver tc358762_driver = {
+ .probe = tc358762_probe,
+ .remove = tc358762_remove,
+ .driver = {
+ .name = "tc358762",
+ .of_match_table = tc358762_of_match,
+ },
+};
+module_mipi_dsi_driver(tc358762_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("MIPI-DSI based Driver for TC358762 DSI/DPI Bridge");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
index 5ac1430fab04..d89394bc5aa4 100644
--- a/drivers/gpu/drm/bridge/tc358764.c
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -153,10 +153,9 @@ static const char * const tc358764_supplies[] = {
struct tc358764 {
struct device *dev;
struct drm_bridge bridge;
- struct drm_connector connector;
struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)];
struct gpio_desc *gpio_reset;
- struct drm_panel *panel;
+ struct drm_bridge *panel_bridge;
int error;
};
@@ -210,12 +209,6 @@ static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge)
return container_of(bridge, struct tc358764, bridge);
}
-static inline
-struct tc358764 *connector_to_tc358764(struct drm_connector *connector)
-{
- return container_of(connector, struct tc358764, connector);
-}
-
static int tc358764_init(struct tc358764 *ctx)
{
u32 v = 0;
@@ -278,43 +271,11 @@ static void tc358764_reset(struct tc358764 *ctx)
usleep_range(1000, 2000);
}
-static int tc358764_get_modes(struct drm_connector *connector)
-{
- struct tc358764 *ctx = connector_to_tc358764(connector);
-
- return drm_panel_get_modes(ctx->panel, connector);
-}
-
-static const
-struct drm_connector_helper_funcs tc358764_connector_helper_funcs = {
- .get_modes = tc358764_get_modes,
-};
-
-static const struct drm_connector_funcs tc358764_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static void tc358764_disable(struct drm_bridge *bridge)
-{
- struct tc358764 *ctx = bridge_to_tc358764(bridge);
- int ret = drm_panel_disable(bridge_to_tc358764(bridge)->panel);
-
- if (ret < 0)
- dev_err(ctx->dev, "error disabling panel (%d)\n", ret);
-}
-
static void tc358764_post_disable(struct drm_bridge *bridge)
{
struct tc358764 *ctx = bridge_to_tc358764(bridge);
int ret;
- ret = drm_panel_unprepare(ctx->panel);
- if (ret < 0)
- dev_err(ctx->dev, "error unpreparing panel (%d)\n", ret);
tc358764_reset(ctx);
usleep_range(10000, 15000);
ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
@@ -335,73 +296,28 @@ static void tc358764_pre_enable(struct drm_bridge *bridge)
ret = tc358764_init(ctx);
if (ret < 0)
dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
- ret = drm_panel_prepare(ctx->panel);
- if (ret < 0)
- dev_err(ctx->dev, "error preparing panel (%d)\n", ret);
-}
-
-static void tc358764_enable(struct drm_bridge *bridge)
-{
- struct tc358764 *ctx = bridge_to_tc358764(bridge);
- int ret = drm_panel_enable(ctx->panel);
-
- if (ret < 0)
- dev_err(ctx->dev, "error enabling panel (%d)\n", ret);
}
static int tc358764_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct tc358764 *ctx = bridge_to_tc358764(bridge);
- struct drm_device *drm = bridge->dev;
- int ret;
-
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
- DRM_ERROR("Fix bridge driver to make connector optional!");
- return -EINVAL;
- }
-
- ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
- ret = drm_connector_init(drm, &ctx->connector,
- &tc358764_connector_funcs,
- DRM_MODE_CONNECTOR_LVDS);
- if (ret) {
- DRM_ERROR("Failed to initialize connector\n");
- return ret;
- }
-
- drm_connector_helper_add(&ctx->connector,
- &tc358764_connector_helper_funcs);
- drm_connector_attach_encoder(&ctx->connector, bridge->encoder);
- drm_panel_attach(ctx->panel, &ctx->connector);
- ctx->connector.funcs->reset(&ctx->connector);
- drm_connector_register(&ctx->connector);
-
- return 0;
-}
-
-static void tc358764_detach(struct drm_bridge *bridge)
-{
- struct tc358764 *ctx = bridge_to_tc358764(bridge);
- drm_connector_unregister(&ctx->connector);
- drm_panel_detach(ctx->panel);
- ctx->panel = NULL;
- drm_connector_put(&ctx->connector);
+ return drm_bridge_attach(bridge->encoder, ctx->panel_bridge,
+ bridge, flags);
}
static const struct drm_bridge_funcs tc358764_bridge_funcs = {
- .disable = tc358764_disable,
.post_disable = tc358764_post_disable,
- .enable = tc358764_enable,
.pre_enable = tc358764_pre_enable,
.attach = tc358764_attach,
- .detach = tc358764_detach,
};
static int tc358764_parse_dt(struct tc358764 *ctx)
{
+ struct drm_bridge *panel_bridge;
struct device *dev = ctx->dev;
+ struct drm_panel *panel;
int ret;
ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
@@ -410,12 +326,16 @@ static int tc358764_parse_dt(struct tc358764 *ctx)
return PTR_ERR(ctx->gpio_reset);
}
- ret = drm_of_find_panel_or_bridge(ctx->dev->of_node, 1, 0, &ctx->panel,
- NULL);
- if (ret && ret != -EPROBE_DEFER)
- dev_err(dev, "cannot find panel (%d)\n", ret);
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
+ if (ret)
+ return ret;
- return ret;
+ panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
+
+ ctx->panel_bridge = panel_bridge;
+ return 0;
}
static int tc358764_configure_regulators(struct tc358764 *ctx)
@@ -461,6 +381,7 @@ static int tc358764_probe(struct mipi_dsi_device *dsi)
return ret;
ctx->bridge.funcs = &tc358764_bridge_funcs;
+ ctx->bridge.type = DRM_MODE_CONNECTOR_LVDS;
ctx->bridge.of_node = dev->of_node;
drm_bridge_add(&ctx->bridge);
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index c2777b226c75..34a3e4e9f717 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -244,14 +244,12 @@ struct tc_data {
struct drm_dp_aux aux;
struct drm_bridge bridge;
+ struct drm_bridge *panel_bridge;
struct drm_connector connector;
- struct drm_panel *panel;
/* link settings */
struct tc_edp_link link;
- /* display edid */
- struct edid *edid;
/* current mode */
struct drm_display_mode mode;
@@ -1236,13 +1234,6 @@ static int tc_stream_disable(struct tc_data *tc)
return 0;
}
-static void tc_bridge_pre_enable(struct drm_bridge *bridge)
-{
- struct tc_data *tc = bridge_to_tc(bridge);
-
- drm_panel_prepare(tc->panel);
-}
-
static void tc_bridge_enable(struct drm_bridge *bridge)
{
struct tc_data *tc = bridge_to_tc(bridge);
@@ -1266,8 +1257,6 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
tc_main_link_disable(tc);
return;
}
-
- drm_panel_enable(tc->panel);
}
static void tc_bridge_disable(struct drm_bridge *bridge)
@@ -1275,8 +1264,6 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
struct tc_data *tc = bridge_to_tc(bridge);
int ret;
- drm_panel_disable(tc->panel);
-
ret = tc_stream_disable(tc);
if (ret < 0)
dev_err(tc->dev, "main link stream stop error: %d\n", ret);
@@ -1286,13 +1273,6 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
dev_err(tc->dev, "main link disable error: %d\n", ret);
}
-static void tc_bridge_post_disable(struct drm_bridge *bridge)
-{
- struct tc_data *tc = bridge_to_tc(bridge);
-
- drm_panel_unprepare(tc->panel);
-}
-
static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
struct drm_display_mode *adj)
@@ -1335,11 +1315,19 @@ static void tc_bridge_mode_set(struct drm_bridge *bridge,
tc->mode = *mode;
}
+static struct edid *tc_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+
+ return drm_get_edid(connector, &tc->aux.ddc);
+}
+
static int tc_connector_get_modes(struct drm_connector *connector)
{
struct tc_data *tc = connector_to_tc(connector);
+ int num_modes;
struct edid *edid;
- int count;
int ret;
ret = tc_get_display_props(tc);
@@ -1348,42 +1336,30 @@ static int tc_connector_get_modes(struct drm_connector *connector)
return 0;
}
- count = drm_panel_get_modes(tc->panel, connector);
- if (count > 0)
- return count;
-
- edid = drm_get_edid(connector, &tc->aux.ddc);
-
- kfree(tc->edid);
- tc->edid = edid;
- if (!edid)
- return 0;
+ if (tc->panel_bridge) {
+ num_modes = drm_bridge_get_modes(tc->panel_bridge, connector);
+ if (num_modes > 0)
+ return num_modes;
+ }
- drm_connector_update_edid_property(connector, edid);
- count = drm_add_edid_modes(connector, edid);
+ edid = tc_get_edid(&tc->bridge, connector);
+ num_modes = drm_add_edid_modes(connector, edid);
+ kfree(edid);
- return count;
+ return num_modes;
}
static const struct drm_connector_helper_funcs tc_connector_helper_funcs = {
.get_modes = tc_connector_get_modes,
};
-static enum drm_connector_status tc_connector_detect(struct drm_connector *connector,
- bool force)
+static enum drm_connector_status tc_bridge_detect(struct drm_bridge *bridge)
{
- struct tc_data *tc = connector_to_tc(connector);
+ struct tc_data *tc = bridge_to_tc(bridge);
bool conn;
u32 val;
int ret;
- if (tc->hpd_pin < 0) {
- if (tc->panel)
- return connector_status_connected;
- else
- return connector_status_unknown;
- }
-
ret = regmap_read(tc->regmap, GPIOI, &val);
if (ret)
return connector_status_unknown;
@@ -1396,6 +1372,20 @@ static enum drm_connector_status tc_connector_detect(struct drm_connector *conne
return connector_status_disconnected;
}
+static enum drm_connector_status
+tc_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct tc_data *tc = connector_to_tc(connector);
+
+ if (tc->hpd_pin >= 0)
+ return tc_bridge_detect(&tc->bridge);
+
+ if (tc->panel_bridge)
+ return connector_status_connected;
+ else
+ return connector_status_unknown;
+}
+
static const struct drm_connector_funcs tc_connector_funcs = {
.detect = tc_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -1413,16 +1403,20 @@ static int tc_bridge_attach(struct drm_bridge *bridge,
struct drm_device *drm = bridge->dev;
int ret;
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
- DRM_ERROR("Fix bridge driver to make connector optional!");
- return -EINVAL;
+ if (tc->panel_bridge) {
+ /* If a connector is required then this driver shall create it */
+ ret = drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
+ &tc->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+ if (ret)
+ return ret;
}
+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+ return 0;
+
/* Create DP/eDP connector */
drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs);
- ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs,
- tc->panel ? DRM_MODE_CONNECTOR_eDP :
- DRM_MODE_CONNECTOR_DisplayPort);
+ ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, tc->bridge.type);
if (ret)
return ret;
@@ -1435,9 +1429,6 @@ static int tc_bridge_attach(struct drm_bridge *bridge,
DRM_CONNECTOR_POLL_DISCONNECT;
}
- if (tc->panel)
- drm_panel_attach(tc->panel, &tc->connector);
-
drm_display_info_set_bus_formats(&tc->connector.display_info,
&bus_format, 1);
tc->connector.display_info.bus_flags =
@@ -1453,11 +1444,11 @@ static const struct drm_bridge_funcs tc_bridge_funcs = {
.attach = tc_bridge_attach,
.mode_valid = tc_mode_valid,
.mode_set = tc_bridge_mode_set,
- .pre_enable = tc_bridge_pre_enable,
.enable = tc_bridge_enable,
.disable = tc_bridge_disable,
- .post_disable = tc_bridge_post_disable,
.mode_fixup = tc_bridge_mode_fixup,
+ .detect = tc_bridge_detect,
+ .get_edid = tc_get_edid,
};
static bool tc_readable_reg(struct device *dev, unsigned int reg)
@@ -1547,6 +1538,7 @@ static irqreturn_t tc_irq_handler(int irq, void *arg)
static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
+ struct drm_panel *panel;
struct tc_data *tc;
int ret;
@@ -1557,10 +1549,23 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
tc->dev = dev;
/* port@2 is the output port */
- ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &tc->panel, NULL);
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL);
if (ret && ret != -ENODEV)
return ret;
+ if (panel) {
+ struct drm_bridge *panel_bridge;
+
+ panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
+
+ tc->panel_bridge = panel_bridge;
+ tc->bridge.type = DRM_MODE_CONNECTOR_eDP;
+ } else {
+ tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
+ }
+
/* Shut down GPIO is optional */
tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
if (IS_ERR(tc->sd_gpio))
@@ -1680,6 +1685,10 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
return ret;
tc->bridge.funcs = &tc_bridge_funcs;
+ if (tc->hpd_pin >= 0)
+ tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
+ tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
+
tc->bridge.of_node = dev->of_node;
drm_bridge_add(&tc->bridge);
diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c
new file mode 100644
index 000000000000..d951cdc58297
--- /dev/null
+++ b/drivers/gpu/drm/bridge/tc358775.c
@@ -0,0 +1,749 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TC358775 DSI to LVDS bridge driver
+ *
+ * Copyright (C) 2020 SMART Wireless Computing
+ * Author: Vinay Simha BN <simhavcs@gmail.com>
+ *
+ */
+/* #define DEBUG */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <asm/unaligned.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+#define FLD_VAL(val, start, end) FIELD_PREP(GENMASK(start, end), val)
+
+/* Registers */
+
+/* DSI D-PHY Layer Registers */
+#define D0W_DPHYCONTTX 0x0004 /* Data Lane 0 DPHY Tx Control */
+#define CLW_DPHYCONTRX 0x0020 /* Clock Lane DPHY Rx Control */
+#define D0W_DPHYCONTRX 0x0024 /* Data Lane 0 DPHY Rx Control */
+#define D1W_DPHYCONTRX 0x0028 /* Data Lane 1 DPHY Rx Control */
+#define D2W_DPHYCONTRX 0x002C /* Data Lane 2 DPHY Rx Control */
+#define D3W_DPHYCONTRX 0x0030 /* Data Lane 3 DPHY Rx Control */
+#define COM_DPHYCONTRX 0x0038 /* DPHY Rx Common Control */
+#define CLW_CNTRL 0x0040 /* Clock Lane Control */
+#define D0W_CNTRL 0x0044 /* Data Lane 0 Control */
+#define D1W_CNTRL 0x0048 /* Data Lane 1 Control */
+#define D2W_CNTRL 0x004C /* Data Lane 2 Control */
+#define D3W_CNTRL 0x0050 /* Data Lane 3 Control */
+#define DFTMODE_CNTRL 0x0054 /* DFT Mode Control */
+
+/* DSI PPI Layer Registers */
+#define PPI_STARTPPI 0x0104 /* START control bit of PPI-TX function. */
+#define PPI_START_FUNCTION 1
+
+#define PPI_BUSYPPI 0x0108
+#define PPI_LINEINITCNT 0x0110 /* Line Initialization Wait Counter */
+#define PPI_LPTXTIMECNT 0x0114
+#define PPI_LANEENABLE 0x0134 /* Enables each lane at the PPI layer. */
+#define PPI_TX_RX_TA 0x013C /* DSI Bus Turn Around timing parameters */
+
+/* Analog timer function enable */
+#define PPI_CLS_ATMR 0x0140 /* Delay for Clock Lane in LPRX */
+#define PPI_D0S_ATMR 0x0144 /* Delay for Data Lane 0 in LPRX */
+#define PPI_D1S_ATMR 0x0148 /* Delay for Data Lane 1 in LPRX */
+#define PPI_D2S_ATMR 0x014C /* Delay for Data Lane 2 in LPRX */
+#define PPI_D3S_ATMR 0x0150 /* Delay for Data Lane 3 in LPRX */
+
+#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* For lane 0 */
+#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* For lane 1 */
+#define PPI_D2S_CLRSIPOCOUNT 0x016C /* For lane 2 */
+#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* For lane 3 */
+
+#define CLS_PRE 0x0180 /* Digital Counter inside of PHY IO */
+#define D0S_PRE 0x0184 /* Digital Counter inside of PHY IO */
+#define D1S_PRE 0x0188 /* Digital Counter inside of PHY IO */
+#define D2S_PRE 0x018C /* Digital Counter inside of PHY IO */
+#define D3S_PRE 0x0190 /* Digital Counter inside of PHY IO */
+#define CLS_PREP 0x01A0 /* Digital Counter inside of PHY IO */
+#define D0S_PREP 0x01A4 /* Digital Counter inside of PHY IO */
+#define D1S_PREP 0x01A8 /* Digital Counter inside of PHY IO */
+#define D2S_PREP 0x01AC /* Digital Counter inside of PHY IO */
+#define D3S_PREP 0x01B0 /* Digital Counter inside of PHY IO */
+#define CLS_ZERO 0x01C0 /* Digital Counter inside of PHY IO */
+#define D0S_ZERO 0x01C4 /* Digital Counter inside of PHY IO */
+#define D1S_ZERO 0x01C8 /* Digital Counter inside of PHY IO */
+#define D2S_ZERO 0x01CC /* Digital Counter inside of PHY IO */
+#define D3S_ZERO 0x01D0 /* Digital Counter inside of PHY IO */
+
+#define PPI_CLRFLG 0x01E0 /* PRE Counters has reached set values */
+#define PPI_CLRSIPO 0x01E4 /* Clear SIPO values, Slave mode use only. */
+#define HSTIMEOUT 0x01F0 /* HS Rx Time Out Counter */
+#define HSTIMEOUTENABLE 0x01F4 /* Enable HS Rx Time Out Counter */
+#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX function */
+#define DSI_RX_START 1
+
+#define DSI_BUSYDSI 0x0208
+#define DSI_LANEENABLE 0x0210 /* Enables each lane at the Protocol layer. */
+#define DSI_LANESTATUS0 0x0214 /* Displays lane is in HS RX mode. */
+#define DSI_LANESTATUS1 0x0218 /* Displays lane is in ULPS or STOP state */
+
+#define DSI_INTSTATUS 0x0220 /* Interrupt Status */
+#define DSI_INTMASK 0x0224 /* Interrupt Mask */
+#define DSI_INTCLR 0x0228 /* Interrupt Clear */
+#define DSI_LPTXTO 0x0230 /* Low Power Tx Time Out Counter */
+
+#define DSIERRCNT 0x0300 /* DSI Error Count */
+#define APLCTRL 0x0400 /* Application Layer Control */
+#define RDPKTLN 0x0404 /* Command Read Packet Length */
+
+#define VPCTRL 0x0450 /* Video Path Control */
+#define HTIM1 0x0454 /* Horizontal Timing Control 1 */
+#define HTIM2 0x0458 /* Horizontal Timing Control 2 */
+#define VTIM1 0x045C /* Vertical Timing Control 1 */
+#define VTIM2 0x0460 /* Vertical Timing Control 2 */
+#define VFUEN 0x0464 /* Video Frame Timing Update Enable */
+#define VFUEN_EN BIT(0) /* Upload Enable */
+
+/* Mux Input Select for LVDS LINK Input */
+#define LV_MX0003 0x0480 /* Bit 0 to 3 */
+#define LV_MX0407 0x0484 /* Bit 4 to 7 */
+#define LV_MX0811 0x0488 /* Bit 8 to 11 */
+#define LV_MX1215 0x048C /* Bit 12 to 15 */
+#define LV_MX1619 0x0490 /* Bit 16 to 19 */
+#define LV_MX2023 0x0494 /* Bit 20 to 23 */
+#define LV_MX2427 0x0498 /* Bit 24 to 27 */
+#define LV_MX(b0, b1, b2, b3) (FLD_VAL(b0, 4, 0) | FLD_VAL(b1, 12, 8) | \
+ FLD_VAL(b2, 20, 16) | FLD_VAL(b3, 28, 24))
+
+/* Input bit numbers used in mux registers */
+enum {
+ LVI_R0,
+ LVI_R1,
+ LVI_R2,
+ LVI_R3,
+ LVI_R4,
+ LVI_R5,
+ LVI_R6,
+ LVI_R7,
+ LVI_G0,
+ LVI_G1,
+ LVI_G2,
+ LVI_G3,
+ LVI_G4,
+ LVI_G5,
+ LVI_G6,
+ LVI_G7,
+ LVI_B0,
+ LVI_B1,
+ LVI_B2,
+ LVI_B3,
+ LVI_B4,
+ LVI_B5,
+ LVI_B6,
+ LVI_B7,
+ LVI_HS,
+ LVI_VS,
+ LVI_DE,
+ LVI_L0
+};
+
+#define LVCFG 0x049C /* LVDS Configuration */
+#define LVPHY0 0x04A0 /* LVDS PHY 0 */
+#define LV_PHY0_RST(v) FLD_VAL(v, 22, 22) /* PHY reset */
+#define LV_PHY0_IS(v) FLD_VAL(v, 15, 14)
+#define LV_PHY0_ND(v) FLD_VAL(v, 4, 0) /* Frequency range select */
+#define LV_PHY0_PRBS_ON(v) FLD_VAL(v, 20, 16) /* Clock/Data Flag pins */
+
+#define LVPHY1 0x04A4 /* LVDS PHY 1 */
+#define SYSSTAT 0x0500 /* System Status */
+#define SYSRST 0x0504 /* System Reset */
+
+#define SYS_RST_I2CS BIT(0) /* Reset I2C-Slave controller */
+#define SYS_RST_I2CM BIT(1) /* Reset I2C-Master controller */
+#define SYS_RST_LCD BIT(2) /* Reset LCD controller */
+#define SYS_RST_BM BIT(3) /* Reset Bus Management controller */
+#define SYS_RST_DSIRX BIT(4) /* Reset DSI-RX and App controller */
+#define SYS_RST_REG BIT(5) /* Reset Register module */
+
+/* GPIO Registers */
+#define GPIOC 0x0520 /* GPIO Control */
+#define GPIOO 0x0524 /* GPIO Output */
+#define GPIOI 0x0528 /* GPIO Input */
+
+/* I2C Registers */
+#define I2CTIMCTRL 0x0540 /* I2C IF Timing and Enable Control */
+#define I2CMADDR 0x0544 /* I2C Master Addressing */
+#define WDATAQ 0x0548 /* Write Data Queue */
+#define RDATAQ 0x054C /* Read Data Queue */
+
+/* Chip ID and Revision ID Register */
+#define IDREG 0x0580
+
+#define LPX_PERIOD 4
+#define TTA_GET 0x40000
+#define TTA_SURE 6
+#define SINGLE_LINK 1
+#define DUAL_LINK 2
+
+#define TC358775XBG_ID 0x00007500
+
+/* Debug Registers */
+#define DEBUG00 0x05A0 /* Debug */
+#define DEBUG01 0x05A4 /* LVDS Data */
+
+#define DSI_CLEN_BIT BIT(0)
+#define DIVIDE_BY_3 3 /* PCLK=DCLK/3 */
+#define DIVIDE_BY_6 6 /* PCLK=DCLK/6 */
+#define LVCFG_LVEN_BIT BIT(0)
+
+#define L0EN BIT(1)
+
+#define TC358775_VPCTRL_VSDELAY__MASK 0x3FF00000
+#define TC358775_VPCTRL_VSDELAY__SHIFT 20
+static inline u32 TC358775_VPCTRL_VSDELAY(uint32_t val)
+{
+ return ((val) << TC358775_VPCTRL_VSDELAY__SHIFT) &
+ TC358775_VPCTRL_VSDELAY__MASK;
+}
+
+#define TC358775_VPCTRL_OPXLFMT__MASK 0x00000100
+#define TC358775_VPCTRL_OPXLFMT__SHIFT 8
+static inline u32 TC358775_VPCTRL_OPXLFMT(uint32_t val)
+{
+ return ((val) << TC358775_VPCTRL_OPXLFMT__SHIFT) &
+ TC358775_VPCTRL_OPXLFMT__MASK;
+}
+
+#define TC358775_VPCTRL_MSF__MASK 0x00000001
+#define TC358775_VPCTRL_MSF__SHIFT 0
+static inline u32 TC358775_VPCTRL_MSF(uint32_t val)
+{
+ return ((val) << TC358775_VPCTRL_MSF__SHIFT) &
+ TC358775_VPCTRL_MSF__MASK;
+}
+
+#define TC358775_LVCFG_PCLKDIV__MASK 0x000000f0
+#define TC358775_LVCFG_PCLKDIV__SHIFT 4
+static inline u32 TC358775_LVCFG_PCLKDIV(uint32_t val)
+{
+ return ((val) << TC358775_LVCFG_PCLKDIV__SHIFT) &
+ TC358775_LVCFG_PCLKDIV__MASK;
+}
+
+#define TC358775_LVCFG_LVDLINK__MASK 0x00000002
+#define TC358775_LVCFG_LVDLINK__SHIFT 0
+static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val)
+{
+ return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) &
+ TC358775_LVCFG_LVDLINK__MASK;
+}
+
+enum tc358775_ports {
+ TC358775_DSI_IN,
+ TC358775_LVDS_OUT0,
+ TC358775_LVDS_OUT1,
+};
+
+struct tc_data {
+ struct i2c_client *i2c;
+ struct device *dev;
+
+ struct drm_bridge bridge;
+ struct drm_bridge *panel_bridge;
+
+ struct device_node *host_node;
+ struct mipi_dsi_device *dsi;
+ u8 num_dsi_lanes;
+
+ struct regulator *vdd;
+ struct regulator *vddio;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *stby_gpio;
+ u8 lvds_link; /* single-link or dual-link */
+ u8 bpc;
+};
+
+static inline struct tc_data *bridge_to_tc(struct drm_bridge *b)
+{
+ return container_of(b, struct tc_data, bridge);
+}
+
+static void tc_bridge_pre_enable(struct drm_bridge *bridge)
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+ struct device *dev = &tc->dsi->dev;
+ int ret;
+
+ ret = regulator_enable(tc->vddio);
+ if (ret < 0)
+ dev_err(dev, "regulator vddio enable failed, %d\n", ret);
+ usleep_range(10000, 11000);
+
+ ret = regulator_enable(tc->vdd);
+ if (ret < 0)
+ dev_err(dev, "regulator vdd enable failed, %d\n", ret);
+ usleep_range(10000, 11000);
+
+ gpiod_set_value(tc->stby_gpio, 0);
+ usleep_range(10000, 11000);
+
+ gpiod_set_value(tc->reset_gpio, 0);
+ usleep_range(10, 20);
+}
+
+static void tc_bridge_post_disable(struct drm_bridge *bridge)
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+ struct device *dev = &tc->dsi->dev;
+ int ret;
+
+ gpiod_set_value(tc->reset_gpio, 1);
+ usleep_range(10, 20);
+
+ gpiod_set_value(tc->stby_gpio, 1);
+ usleep_range(10000, 11000);
+
+ ret = regulator_disable(tc->vdd);
+ if (ret < 0)
+ dev_err(dev, "regulator vdd disable failed, %d\n", ret);
+ usleep_range(10000, 11000);
+
+ ret = regulator_disable(tc->vddio);
+ if (ret < 0)
+ dev_err(dev, "regulator vddio disable failed, %d\n", ret);
+ usleep_range(10000, 11000);
+}
+
+static void d2l_read(struct i2c_client *i2c, u16 addr, u32 *val)
+{
+ int ret;
+ u8 buf_addr[2];
+
+ put_unaligned_be16(addr, buf_addr);
+ ret = i2c_master_send(i2c, buf_addr, sizeof(buf_addr));
+ if (ret < 0)
+ goto fail;
+
+ ret = i2c_master_recv(i2c, (u8 *)val, sizeof(*val));
+ if (ret < 0)
+ goto fail;
+
+ pr_debug("d2l: I2C : addr:%04x value:%08x\n", addr, *val);
+
+fail:
+ dev_err(&i2c->dev, "Error %d reading from subaddress 0x%x\n",
+ ret, addr);
+}
+
+static void d2l_write(struct i2c_client *i2c, u16 addr, u32 val)
+{
+ u8 data[6];
+ int ret;
+
+ put_unaligned_be16(addr, data);
+ put_unaligned_le32(val, data + 2);
+
+ ret = i2c_master_send(i2c, data, ARRAY_SIZE(data));
+ if (ret < 0)
+ dev_err(&i2c->dev, "Error %d writing to subaddress 0x%x\n",
+ ret, addr);
+}
+
+/* helper function to access bus_formats */
+static struct drm_connector *get_connector(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct drm_connector *connector;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ if (connector->encoder == encoder)
+ return connector;
+
+ return NULL;
+}
+
+static void tc_bridge_enable(struct drm_bridge *bridge)
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+ u32 hback_porch, hsync_len, hfront_porch, hactive, htime1, htime2;
+ u32 vback_porch, vsync_len, vfront_porch, vactive, vtime1, vtime2;
+ u32 val = 0;
+ u16 dsiclk, clkdiv, byteclk, t1, t2, t3, vsdelay;
+ struct drm_display_mode *mode;
+ struct drm_connector *connector = get_connector(bridge->encoder);
+
+ mode = &bridge->encoder->crtc->state->adjusted_mode;
+
+ hback_porch = mode->htotal - mode->hsync_end;
+ hsync_len = mode->hsync_end - mode->hsync_start;
+ vback_porch = mode->vtotal - mode->vsync_end;
+ vsync_len = mode->vsync_end - mode->vsync_start;
+
+ htime1 = (hback_porch << 16) + hsync_len;
+ vtime1 = (vback_porch << 16) + vsync_len;
+
+ hfront_porch = mode->hsync_start - mode->hdisplay;
+ hactive = mode->hdisplay;
+ vfront_porch = mode->vsync_start - mode->vdisplay;
+ vactive = mode->vdisplay;
+
+ htime2 = (hfront_porch << 16) + hactive;
+ vtime2 = (vfront_porch << 16) + vactive;
+
+ d2l_read(tc->i2c, IDREG, &val);
+
+ dev_info(tc->dev, "DSI2LVDS Chip ID.%02x Revision ID. %02x **\n",
+ (val >> 8) & 0xFF, val & 0xFF);
+
+ d2l_write(tc->i2c, SYSRST, SYS_RST_REG | SYS_RST_DSIRX | SYS_RST_BM |
+ SYS_RST_LCD | SYS_RST_I2CM | SYS_RST_I2CS);
+ usleep_range(30000, 40000);
+
+ d2l_write(tc->i2c, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
+ d2l_write(tc->i2c, PPI_LPTXTIMECNT, LPX_PERIOD);
+ d2l_write(tc->i2c, PPI_D0S_CLRSIPOCOUNT, 3);
+ d2l_write(tc->i2c, PPI_D1S_CLRSIPOCOUNT, 3);
+ d2l_write(tc->i2c, PPI_D2S_CLRSIPOCOUNT, 3);
+ d2l_write(tc->i2c, PPI_D3S_CLRSIPOCOUNT, 3);
+
+ val = ((L0EN << tc->num_dsi_lanes) - L0EN) | DSI_CLEN_BIT;
+ d2l_write(tc->i2c, PPI_LANEENABLE, val);
+ d2l_write(tc->i2c, DSI_LANEENABLE, val);
+
+ d2l_write(tc->i2c, PPI_STARTPPI, PPI_START_FUNCTION);
+ d2l_write(tc->i2c, DSI_STARTDSI, DSI_RX_START);
+
+ if (tc->bpc == 8)
+ val = TC358775_VPCTRL_OPXLFMT(1);
+ else /* bpc = 6; */
+ val = TC358775_VPCTRL_MSF(1);
+
+ dsiclk = mode->crtc_clock * 3 * tc->bpc / tc->num_dsi_lanes / 1000;
+ clkdiv = dsiclk / DIVIDE_BY_3 * tc->lvds_link;
+ byteclk = dsiclk / 4;
+ t1 = hactive * (tc->bpc * 3 / 8) / tc->num_dsi_lanes;
+ t2 = ((100000 / clkdiv)) * (hactive + hback_porch + hsync_len + hfront_porch) / 1000;
+ t3 = ((t2 * byteclk) / 100) - (hactive * (tc->bpc * 3 / 8) /
+ tc->num_dsi_lanes);
+
+ vsdelay = (clkdiv * (t1 + t3) / byteclk) - hback_porch - hsync_len - hactive;
+
+ val |= TC358775_VPCTRL_VSDELAY(vsdelay);
+ d2l_write(tc->i2c, VPCTRL, val);
+
+ d2l_write(tc->i2c, HTIM1, htime1);
+ d2l_write(tc->i2c, VTIM1, vtime1);
+ d2l_write(tc->i2c, HTIM2, htime2);
+ d2l_write(tc->i2c, VTIM2, vtime2);
+
+ d2l_write(tc->i2c, VFUEN, VFUEN_EN);
+ d2l_write(tc->i2c, SYSRST, SYS_RST_LCD);
+ d2l_write(tc->i2c, LVPHY0, LV_PHY0_PRBS_ON(4) | LV_PHY0_ND(6));
+
+ dev_dbg(tc->dev, "bus_formats %04x bpc %d\n",
+ connector->display_info.bus_formats[0],
+ tc->bpc);
+ /*
+ * Default hardware register settings of tc358775 configured
+ * with MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA jeida-24 format
+ */
+ if (connector->display_info.bus_formats[0] ==
+ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG) {
+ /* VESA-24 */
+ d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3));
+ d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_R7, LVI_R5, LVI_G0));
+ d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_G6, LVI_G7));
+ d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0));
+ d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2));
+ d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0));
+ d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6));
+ } else { /* MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - JEIDA-18 */
+ d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3));
+ d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_L0, LVI_R5, LVI_G0));
+ d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_L0, LVI_L0));
+ d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0));
+ d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_L0, LVI_L0, LVI_B1, LVI_B2));
+ d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0));
+ d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_L0));
+ }
+
+ d2l_write(tc->i2c, VFUEN, VFUEN_EN);
+
+ val = LVCFG_LVEN_BIT;
+ if (tc->lvds_link == DUAL_LINK) {
+ val |= TC358775_LVCFG_LVDLINK(1);
+ val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_6);
+ } else {
+ val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_3);
+ };
+ d2l_write(tc->i2c, LVCFG, val);
+}
+
+static enum drm_mode_status
+tc_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+
+ /*
+ * Maximum pixel clock speed 135MHz for single-link
+ * 270MHz for dual-link
+ */
+ if ((mode->clock > 135000 && tc->lvds_link == SINGLE_LINK) ||
+ (mode->clock > 270000 && tc->lvds_link == DUAL_LINK))
+ return MODE_CLOCK_HIGH;
+
+ switch (info->bus_formats[0]) {
+ case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+ case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+ /* RGB888 */
+ tc->bpc = 8;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+ /* RGB666 */
+ tc->bpc = 6;
+ break;
+ default:
+ dev_warn(tc->dev,
+ "unsupported LVDS bus format 0x%04x\n",
+ info->bus_formats[0]);
+ return MODE_NOMODE;
+ }
+
+ return MODE_OK;
+}
+
+static int tc358775_parse_dt(struct device_node *np, struct tc_data *tc)
+{
+ struct device_node *endpoint;
+ struct device_node *parent;
+ struct device_node *remote;
+ struct property *prop;
+ int len = 0;
+
+ /*
+ * To get the data-lanes of dsi, we need to access the dsi0_out of port1
+ * of dsi0 endpoint from bridge port0 of d2l_in
+ */
+ endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node,
+ TC358775_DSI_IN, -1);
+ if (endpoint) {
+ /* dsi0_out node */
+ parent = of_graph_get_remote_port_parent(endpoint);
+ of_node_put(endpoint);
+ if (parent) {
+ /* dsi0 port 1 */
+ endpoint = of_graph_get_endpoint_by_regs(parent, 1, -1);
+ of_node_put(parent);
+ if (endpoint) {
+ prop = of_find_property(endpoint, "data-lanes",
+ &len);
+ of_node_put(endpoint);
+ if (!prop) {
+ dev_err(tc->dev,
+ "failed to find data lane\n");
+ return -EPROBE_DEFER;
+ }
+ }
+ }
+ }
+
+ tc->num_dsi_lanes = len / sizeof(u32);
+
+ if (tc->num_dsi_lanes < 1 || tc->num_dsi_lanes > 4)
+ return -EINVAL;
+
+ tc->host_node = of_graph_get_remote_node(np, 0, 0);
+ if (!tc->host_node)
+ return -ENODEV;
+
+ of_node_put(tc->host_node);
+
+ tc->lvds_link = SINGLE_LINK;
+ endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node,
+ TC358775_LVDS_OUT1, -1);
+ if (endpoint) {
+ remote = of_graph_get_remote_port_parent(endpoint);
+ of_node_put(endpoint);
+
+ if (remote) {
+ if (of_device_is_available(remote))
+ tc->lvds_link = DUAL_LINK;
+ of_node_put(remote);
+ }
+ }
+
+ dev_dbg(tc->dev, "no.of dsi lanes: %d\n", tc->num_dsi_lanes);
+ dev_dbg(tc->dev, "operating in %d-link mode\n", tc->lvds_link);
+
+ return 0;
+}
+
+static int tc_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct tc_data *tc = bridge_to_tc(bridge);
+ struct device *dev = &tc->i2c->dev;
+ struct mipi_dsi_host *host;
+ struct mipi_dsi_device *dsi;
+ int ret;
+
+ const struct mipi_dsi_device_info info = { .type = "tc358775",
+ .channel = 0,
+ .node = NULL,
+ };
+
+ host = of_find_mipi_dsi_host_by_node(tc->host_node);
+ if (!host) {
+ dev_err(dev, "failed to find dsi host\n");
+ return -EPROBE_DEFER;
+ }
+
+ dsi = mipi_dsi_device_register_full(host, &info);
+ if (IS_ERR(dsi)) {
+ dev_err(dev, "failed to create dsi device\n");
+ ret = PTR_ERR(dsi);
+ goto err_dsi_device;
+ }
+
+ tc->dsi = dsi;
+
+ dsi->lanes = tc->num_dsi_lanes;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(dev, "failed to attach dsi to host\n");
+ goto err_dsi_attach;
+ }
+
+ /* Attach the panel-bridge to the dsi bridge */
+ return drm_bridge_attach(bridge->encoder, tc->panel_bridge,
+ &tc->bridge, flags);
+err_dsi_attach:
+ mipi_dsi_device_unregister(dsi);
+err_dsi_device:
+ return ret;
+}
+
+static const struct drm_bridge_funcs tc_bridge_funcs = {
+ .attach = tc_bridge_attach,
+ .pre_enable = tc_bridge_pre_enable,
+ .enable = tc_bridge_enable,
+ .mode_valid = tc_mode_valid,
+ .post_disable = tc_bridge_post_disable,
+};
+
+static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct drm_panel *panel;
+ struct tc_data *tc;
+ int ret;
+
+ tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL);
+ if (!tc)
+ return -ENOMEM;
+
+ tc->dev = dev;
+ tc->i2c = client;
+
+ ret = drm_of_find_panel_or_bridge(dev->of_node, TC358775_LVDS_OUT0,
+ 0, &panel, NULL);
+ if (ret < 0)
+ return ret;
+ if (!panel)
+ return -ENODEV;
+
+ tc->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ if (IS_ERR(tc->panel_bridge))
+ return PTR_ERR(tc->panel_bridge);
+
+ ret = tc358775_parse_dt(dev->of_node, tc);
+ if (ret)
+ return ret;
+
+ tc->vddio = devm_regulator_get(dev, "vddio-supply");
+ if (IS_ERR(tc->vddio)) {
+ ret = PTR_ERR(tc->vddio);
+ dev_err(dev, "vddio-supply not found\n");
+ return ret;
+ }
+
+ tc->vdd = devm_regulator_get(dev, "vdd-supply");
+ if (IS_ERR(tc->vdd)) {
+ ret = PTR_ERR(tc->vdd);
+ dev_err(dev, "vdd-supply not found\n");
+ return ret;
+ }
+
+ tc->stby_gpio = devm_gpiod_get(dev, "stby", GPIOD_OUT_HIGH);
+ if (IS_ERR(tc->stby_gpio)) {
+ ret = PTR_ERR(tc->stby_gpio);
+ dev_err(dev, "cannot get stby-gpio %d\n", ret);
+ return ret;
+ }
+
+ tc->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(tc->reset_gpio)) {
+ ret = PTR_ERR(tc->reset_gpio);
+ dev_err(dev, "cannot get reset-gpios %d\n", ret);
+ return ret;
+ }
+
+ tc->bridge.funcs = &tc_bridge_funcs;
+ tc->bridge.of_node = dev->of_node;
+ drm_bridge_add(&tc->bridge);
+
+ i2c_set_clientdata(client, tc);
+
+ return 0;
+}
+
+static int tc_remove(struct i2c_client *client)
+{
+ struct tc_data *tc = i2c_get_clientdata(client);
+
+ drm_bridge_remove(&tc->bridge);
+
+ return 0;
+}
+
+static const struct i2c_device_id tc358775_i2c_ids[] = {
+ { "tc358775", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tc358775_i2c_ids);
+
+static const struct of_device_id tc358775_of_ids[] = {
+ { .compatible = "toshiba,tc358775", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tc358775_of_ids);
+
+static struct i2c_driver tc358775_driver = {
+ .driver = {
+ .name = "tc358775",
+ .of_match_table = tc358775_of_ids,
+ },
+ .id_table = tc358775_i2c_ids,
+ .probe = tc_probe,
+ .remove = tc_remove,
+};
+module_i2c_driver(tc358775_driver);
+
+MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");
+MODULE_DESCRIPTION("TC358775 DSI/LVDS bridge driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 5b6e19ecbc84..ecdf9b01340f 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -394,9 +394,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge,
}
pdata->dsi = dsi;
- /* attach panel to bridge */
- drm_panel_attach(pdata->panel, &pdata->connector);
-
return 0;
err_dsi_attach:
diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
index c6994fe673f3..a58cbde59c34 100644
--- a/drivers/gpu/drm/drm_bridge_connector.c
+++ b/drivers/gpu/drm/drm_bridge_connector.c
@@ -187,6 +187,7 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force)
case DRM_MODE_CONNECTOR_DPI:
case DRM_MODE_CONNECTOR_LVDS:
case DRM_MODE_CONNECTOR_DSI:
+ case DRM_MODE_CONNECTOR_eDP:
status = connector_status_connected;
break;
default:
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 00e40a26a800..3d48ad1c3682 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -850,7 +850,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
- { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
+ { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */
{ DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
{ DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
};
@@ -867,7 +867,7 @@ static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
- { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
+ { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
{ DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
{ DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
@@ -876,6 +876,19 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
drm_tv_subconnector_enum_list)
+static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = {
+ { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */
+ { DRM_MODE_SUBCONNECTOR_VGA, "VGA" }, /* DP */
+ { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DP */
+ { DRM_MODE_SUBCONNECTOR_HDMIA, "HDMI" }, /* DP */
+ { DRM_MODE_SUBCONNECTOR_DisplayPort, "DP" }, /* DP */
+ { DRM_MODE_SUBCONNECTOR_Wireless, "Wireless" }, /* DP */
+ { DRM_MODE_SUBCONNECTOR_Native, "Native" }, /* DP */
+};
+
+DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name,
+ drm_dp_subconnector_enum_list)
+
static const struct drm_prop_enum_list hdmi_colorspaces[] = {
/* For Default case, driver will set the colorspace */
{ DRM_MODE_COLORIMETRY_DEFAULT, "Default" },
@@ -1217,6 +1230,14 @@ static const struct drm_prop_enum_list dp_colorspaces[] = {
* can also expose this property to external outputs, in which case they
* must support "None", which should be the default (since external screens
* have a built-in scaler).
+ *
+ * subconnector:
+ * This property is used by DVI-I, TVout and DisplayPort to indicate different
+ * connector subtypes. Enum values more or less match with those from main
+ * connector types.
+ * For DVI-I and TVout there is also a matching property "select subconnector"
+ * allowing to switch between signal types.
+ * DP subconnector corresponds to a downstream port.
*/
int drm_connector_create_standard_properties(struct drm_device *dev)
@@ -1306,6 +1327,30 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev)
EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
/**
+ * drm_connector_attach_dp_subconnector_property - create subconnector property for DP
+ * @connector: drm_connector to attach property
+ *
+ * Called by a driver when DP connector is created.
+ */
+void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector)
+{
+ struct drm_mode_config *mode_config = &connector->dev->mode_config;
+
+ if (!mode_config->dp_subconnector_property)
+ mode_config->dp_subconnector_property =
+ drm_property_create_enum(connector->dev,
+ DRM_MODE_PROP_IMMUTABLE,
+ "subconnector",
+ drm_dp_subconnector_enum_list,
+ ARRAY_SIZE(drm_dp_subconnector_enum_list));
+
+ drm_object_attach_property(&connector->base,
+ mode_config->dp_subconnector_property,
+ DRM_MODE_SUBCONNECTOR_Unknown);
+}
+EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
+
+/**
* DOC: HDMI connector properties
*
* content type (HDMI specific):
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 092c8c985911..ad7c03dac467 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -597,6 +597,77 @@ void drm_dp_downstream_debug(struct seq_file *m,
}
EXPORT_SYMBOL(drm_dp_downstream_debug);
+/**
+ * drm_dp_subconnector_type() - get DP branch device type
+ *
+ */
+enum drm_mode_subconnector
+drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+ const u8 port_cap[4])
+{
+ int type;
+ if (!drm_dp_is_branch(dpcd))
+ return DRM_MODE_SUBCONNECTOR_Native;
+ /* DP 1.0 approach */
+ if (dpcd[DP_DPCD_REV] == DP_DPCD_REV_10) {
+ type = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+ DP_DWN_STRM_PORT_TYPE_MASK;
+
+ switch (type) {
+ case DP_DWN_STRM_PORT_TYPE_TMDS:
+ /* Can be HDMI or DVI-D, DVI-D is a safer option */
+ return DRM_MODE_SUBCONNECTOR_DVID;
+ case DP_DWN_STRM_PORT_TYPE_ANALOG:
+ /* Can be VGA or DVI-A, VGA is more popular */
+ return DRM_MODE_SUBCONNECTOR_VGA;
+ case DP_DWN_STRM_PORT_TYPE_DP:
+ return DRM_MODE_SUBCONNECTOR_DisplayPort;
+ case DP_DWN_STRM_PORT_TYPE_OTHER:
+ default:
+ return DRM_MODE_SUBCONNECTOR_Unknown;
+ }
+ }
+ type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
+
+ switch (type) {
+ case DP_DS_PORT_TYPE_DP:
+ case DP_DS_PORT_TYPE_DP_DUALMODE:
+ return DRM_MODE_SUBCONNECTOR_DisplayPort;
+ case DP_DS_PORT_TYPE_VGA:
+ return DRM_MODE_SUBCONNECTOR_VGA;
+ case DP_DS_PORT_TYPE_DVI:
+ return DRM_MODE_SUBCONNECTOR_DVID;
+ case DP_DS_PORT_TYPE_HDMI:
+ return DRM_MODE_SUBCONNECTOR_HDMIA;
+ case DP_DS_PORT_TYPE_WIRELESS:
+ return DRM_MODE_SUBCONNECTOR_Wireless;
+ case DP_DS_PORT_TYPE_NON_EDID:
+ default:
+ return DRM_MODE_SUBCONNECTOR_Unknown;
+ }
+}
+EXPORT_SYMBOL(drm_dp_subconnector_type);
+
+/**
+ * drm_mode_set_dp_subconnector_property - set subconnector for DP connector
+ *
+ * Called by a driver on every detect event.
+ */
+void drm_dp_set_subconnector_property(struct drm_connector *connector,
+ enum drm_connector_status status,
+ const u8 *dpcd,
+ const u8 port_cap[4])
+{
+ enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
+
+ if (status == connector_status_connected)
+ subconnector = drm_dp_subconnector_type(dpcd, port_cap);
+ drm_object_property_set_value(&connector->base,
+ connector->dev->mode_config.dp_subconnector_property,
+ subconnector);
+}
+EXPORT_SYMBOL(drm_dp_set_subconnector_property);
+
/*
* I2C-over-AUX implementation
*/
diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c
index 3296ed3df358..545a877406f4 100644
--- a/drivers/gpu/drm/drm_gem_vram_helper.c
+++ b/drivers/gpu/drm/drm_gem_vram_helper.c
@@ -653,7 +653,7 @@ static void drm_gem_vram_bo_driver_evict_flags(struct drm_gem_vram_object *gbo,
static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo,
bool evict,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct ttm_bo_kmap_obj *kmap = &gbo->kmap;
@@ -1004,28 +1004,6 @@ err_ttm_tt_init:
return NULL;
}
-static int bo_driver_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
- struct ttm_mem_type_manager *man)
-{
- switch (type) {
- case TTM_PL_SYSTEM:
- man->flags = 0;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- case TTM_PL_VRAM:
- man->func = &ttm_bo_manager_func;
- man->flags = TTM_MEMTYPE_FLAG_FIXED;
- man->available_caching = TTM_PL_FLAG_UNCACHED |
- TTM_PL_FLAG_WC;
- man->default_caching = TTM_PL_FLAG_WC;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
static void bo_driver_evict_flags(struct ttm_buffer_object *bo,
struct ttm_placement *placement)
{
@@ -1042,7 +1020,7 @@ static void bo_driver_evict_flags(struct ttm_buffer_object *bo,
static void bo_driver_move_notify(struct ttm_buffer_object *bo,
bool evict,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct drm_gem_vram_object *gbo;
@@ -1056,18 +1034,12 @@ static void bo_driver_move_notify(struct ttm_buffer_object *bo,
}
static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bdev);
- mem->bus.addr = NULL;
- mem->bus.size = mem->num_pages << PAGE_SHIFT;
-
switch (mem->mem_type) {
case TTM_PL_SYSTEM: /* nothing to do */
- mem->bus.offset = 0;
- mem->bus.base = 0;
- mem->bus.is_iomem = false;
break;
case TTM_PL_VRAM:
mem->bus.offset = mem->start << PAGE_SHIFT;
@@ -1083,9 +1055,6 @@ static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev,
static struct ttm_bo_driver bo_driver = {
.ttm_tt_create = bo_driver_ttm_tt_create,
- .ttm_tt_populate = ttm_pool_populate,
- .ttm_tt_unpopulate = ttm_pool_unpopulate,
- .init_mem_type = bo_driver_init_mem_type,
.eviction_valuable = ttm_bo_eviction_valuable,
.evict_flags = bo_driver_evict_flags,
.move_notify = bo_driver_move_notify,
@@ -1100,12 +1069,10 @@ static int drm_vram_mm_debugfs(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_vram_mm *vmm = node->minor->dev->vram_mm;
- struct drm_mm *mm = vmm->bdev.man[TTM_PL_VRAM].priv;
+ struct ttm_resource_manager *man = ttm_manager_type(&vmm->bdev, TTM_PL_VRAM);
struct drm_printer p = drm_seq_file_printer(m);
- spin_lock(&ttm_bo_glob.lru_lock);
- drm_mm_print(mm, &p);
- spin_unlock(&ttm_bo_glob.lru_lock);
+ ttm_resource_manager_debug(man, &p);
return 0;
}
@@ -1142,7 +1109,10 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev,
if (ret)
return ret;
- ret = ttm_bo_init_mm(&vmm->bdev, TTM_PL_VRAM, vram_size >> PAGE_SHIFT);
+ ret = ttm_range_man_init(&vmm->bdev, TTM_PL_VRAM,
+ TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC,
+ TTM_PL_FLAG_WC, false,
+ vram_size >> PAGE_SHIFT);
if (ret)
return ret;
@@ -1151,6 +1121,7 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev,
static void drm_vram_mm_cleanup(struct drm_vram_mm *vmm)
{
+ ttm_range_man_fini(&vmm->bdev, TTM_PL_VRAM);
ttm_bo_device_release(&vmm->bdev);
}
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index 8c7bac85a793..f634371c717a 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -70,16 +70,12 @@ EXPORT_SYMBOL(drm_panel_init);
*
* Add a panel to the global registry so that it can be looked up by display
* drivers.
- *
- * Return: 0 on success or a negative error code on failure.
*/
-int drm_panel_add(struct drm_panel *panel)
+void drm_panel_add(struct drm_panel *panel)
{
mutex_lock(&panel_lock);
list_add_tail(&panel->list, &panel_list);
mutex_unlock(&panel_lock);
-
- return 0;
}
EXPORT_SYMBOL(drm_panel_add);
@@ -98,42 +94,6 @@ void drm_panel_remove(struct drm_panel *panel)
EXPORT_SYMBOL(drm_panel_remove);
/**
- * drm_panel_attach - attach a panel to a connector
- * @panel: DRM panel
- * @connector: DRM connector
- *
- * After obtaining a pointer to a DRM panel a display driver calls this
- * function to attach a panel to a connector.
- *
- * An error is returned if the panel is already attached to another connector.
- *
- * When unloading, the driver should detach from the panel by calling
- * drm_panel_detach().
- *
- * Return: 0 on success or a negative error code on failure.
- */
-int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector)
-{
- return 0;
-}
-EXPORT_SYMBOL(drm_panel_attach);
-
-/**
- * drm_panel_detach - detach a panel from a connector
- * @panel: DRM panel
- *
- * Detaches a panel from the connector it is attached to. If a panel is not
- * attached to any connector this is effectively a no-op.
- *
- * This function should not be called by the panel device itself. It
- * is only for the drm device that called drm_panel_attach().
- */
-void drm_panel_detach(struct drm_panel *panel)
-{
-}
-EXPORT_SYMBOL(drm_panel_detach);
-
-/**
* drm_panel_prepare - power on a panel
* @panel: DRM panel
*
@@ -300,6 +260,49 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(of_drm_find_panel);
+
+/**
+ * of_drm_get_panel_orientation - look up the orientation of the panel through
+ * the "rotation" binding from a device tree node
+ * @np: device tree node of the panel
+ * @orientation: orientation enum to be filled in
+ *
+ * Looks up the rotation of a panel in the device tree. The orientation of the
+ * panel is expressed as a property name "rotation" in the device tree. The
+ * rotation in the device tree is counter clockwise.
+ *
+ * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the
+ * rotation property doesn't exist. Return a negative error code on failure.
+ */
+int of_drm_get_panel_orientation(const struct device_node *np,
+ enum drm_panel_orientation *orientation)
+{
+ int rotation, ret;
+
+ ret = of_property_read_u32(np, "rotation", &rotation);
+ if (ret == -EINVAL) {
+ /* Don't return an error if there's no rotation property. */
+ *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+ return 0;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (rotation == 0)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
+ else if (rotation == 90)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
+ else if (rotation == 180)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
+ else if (rotation == 270)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL(of_drm_get_panel_orientation);
#endif
#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE)
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 3bf73971daf3..6e74e6745eca 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -297,7 +297,7 @@ void drm_syncobj_add_point(struct drm_syncobj *syncobj,
prev = drm_syncobj_fence_get(syncobj);
/* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */
if (prev && prev->seqno >= point)
- DRM_ERROR("You are adding an unorder point to timeline!\n");
+ DRM_DEBUG("You are adding an unorder point to timeline!\n");
dma_fence_chain_init(chain, prev, fence, point);
rcu_assign_pointer(syncobj->fence, &chain->base);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 7ba5354e7d94..741323a2e6c3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -42,11 +42,6 @@ static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e)
static enum drm_connector_status
exynos_dpi_detect(struct drm_connector *connector, bool force)
{
- struct exynos_dpi *ctx = connector_to_dpi(connector);
-
- if (ctx->panel)
- drm_panel_attach(ctx->panel, &ctx->connector);
-
return connector_status_connected;
}
@@ -249,8 +244,5 @@ int exynos_dpi_remove(struct drm_encoder *encoder)
exynos_dpi_disable(&ctx->encoder);
- if (ctx->panel)
- drm_panel_detach(ctx->panel);
-
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index b38e9b592b8a..1a1a2853a842 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1551,12 +1551,10 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
}
dsi->panel = of_drm_find_panel(device->dev.of_node);
- if (IS_ERR(dsi->panel)) {
+ if (IS_ERR(dsi->panel))
dsi->panel = NULL;
- } else {
- drm_panel_attach(dsi->panel, &dsi->connector);
+ else
dsi->connector.status = connector_status_connected;
- }
}
/*
@@ -1596,7 +1594,6 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
if (dsi->panel) {
mutex_lock(&drm->mode_config.mutex);
exynos_dsi_disable(&dsi->encoder);
- drm_panel_detach(dsi->panel);
dsi->panel = NULL;
dsi->connector.status = connector_status_disconnected;
mutex_unlock(&drm->mode_config.mutex);
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
index 9b0c4736c21a..4d4a715b429d 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
@@ -40,10 +40,7 @@ int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector)
{
- struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector);
-
drm_connector_unregister(connector);
- drm_panel_detach(fsl_con->panel);
drm_connector_cleanup(connector);
}
@@ -101,12 +98,6 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev,
if (ret < 0)
goto err_sysfs;
- ret = drm_panel_attach(panel, connector);
- if (ret) {
- dev_err(fsl_dev->dev, "failed to attach panel\n");
- goto err_sysfs;
- }
-
return 0;
err_sysfs:
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index f41cbb753bb4..720a767118c9 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -2078,7 +2078,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev
intel_dp->dpcd,
sizeof(intel_dp->dpcd));
cdv_intel_edp_panel_vdd_off(gma_encoder);
- if (ret == 0) {
+ if (ret <= 0) {
/* if this fails, presume the device is a ghost */
DRM_INFO("failed to retrieve link info, disabling eDP\n");
drm_encoder_cleanup(encoder);
diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c
index b718efccdcf2..be9cf6b1e3b3 100644
--- a/drivers/gpu/drm/gma500/mdfld_device.c
+++ b/drivers/gpu/drm/gma500/mdfld_device.c
@@ -6,6 +6,7 @@
**************************************************************************/
#include <linux/delay.h>
+#include <linux/gpio/machine.h>
#include <asm/intel_scu_ipc.h>
@@ -505,12 +506,31 @@ static const struct psb_offset mdfld_regmap[3] = {
},
};
+/*
+ * The GPIO lines for resetting DSI pipe 0 and 2 are available in the
+ * PCI device 0000:00:0c.0 on the Medfield.
+ */
+static struct gpiod_lookup_table mdfld_dsi_pipe_gpio_table = {
+ .table = {
+ GPIO_LOOKUP("0000:00:0c.0", 128, "dsi-pipe0-reset",
+ GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("0000:00:0c.0", 34, "dsi-pipe2-reset",
+ GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
static int mdfld_chip_setup(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
if (pci_enable_msi(dev->pdev))
dev_warn(dev->dev, "Enabling MSI failed!\n");
dev_priv->regmap = mdfld_regmap;
+
+ /* Associate the GPIO lines with the DRM device */
+ mdfld_dsi_pipe_gpio_table.dev_id = dev_name(dev->dev);
+ gpiod_add_lookup_table(&mdfld_dsi_pipe_gpio_table);
+
return mid_chip_setup(dev);
}
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
index c976a9dd9240..ae1223f631a7 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
@@ -955,7 +955,7 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
/* panel hard-reset */
if (p_funcs->reset) {
- ret = p_funcs->reset(pipe);
+ ret = p_funcs->reset(dev, pipe);
if (ret) {
DRM_ERROR("Panel %d hard-reset failed\n", pipe);
return NULL;
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index f350ac1ead18..4aab76613bd9 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/pm_runtime.h>
+#include <linux/gpio/consumer.h>
#include <asm/intel_scu_ipc.h>
@@ -366,7 +367,7 @@ static enum drm_mode_status mdfld_dsi_connector_mode_valid(struct drm_connector
/**
* FIXME: current DC has no fitting unit, reject any mode setting
* request
- * Will figure out a way to do up-scaling(pannel fitting) later.
+ * Will figure out a way to do up-scaling(panel fitting) later.
**/
if (fixed_mode) {
if (mode->hdisplay != fixed_mode->hdisplay)
@@ -432,42 +433,42 @@ static int mdfld_dsi_get_default_config(struct drm_device *dev,
return 0;
}
-int mdfld_dsi_panel_reset(int pipe)
+int mdfld_dsi_panel_reset(struct drm_device *ddev, int pipe)
{
- unsigned gpio;
- int ret = 0;
-
+ struct device *dev = ddev->dev;
+ struct gpio_desc *gpiod;
+
+ /*
+ * Raise the GPIO reset line for the corresponding pipe to HIGH,
+ * this is probably because it is active low so this takes the
+ * respective pipe out of reset. (We have no code to put it back
+ * into reset in this driver.)
+ */
switch (pipe) {
case 0:
- gpio = 128;
+ gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod))
+ return PTR_ERR(gpiod);
break;
case 2:
- gpio = 34;
+ gpiod = gpiod_get(dev, "dsi-pipe2-reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod))
+ return PTR_ERR(gpiod);
break;
default:
- DRM_ERROR("Invalid output\n");
+ DRM_DEV_ERROR(dev, "Invalid output pipe\n");
return -EINVAL;
}
+ gpiod_put(gpiod);
- ret = gpio_request(gpio, "gfx");
- if (ret) {
- DRM_ERROR("gpio_rqueset failed\n");
- return ret;
- }
-
- ret = gpio_direction_output(gpio, 1);
- if (ret) {
- DRM_ERROR("gpio_direction_output failed\n");
- goto gpio_error;
- }
+ /* Flush posted writes on the device */
+ gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_ASIS);
+ if (IS_ERR(gpiod))
+ return PTR_ERR(gpiod);
+ gpiod_get_value(gpiod);
+ gpiod_put(gpiod);
- gpio_get_value(128);
-
-gpio_error:
- if (gpio_is_valid(gpio))
- gpio_free(gpio);
-
- return ret;
+ return 0;
}
/*
@@ -531,7 +532,7 @@ void mdfld_dsi_output_init(struct drm_device *dev,
dsi_config->connector = dsi_connector;
if (!dsi_config->fixed_mode) {
- DRM_ERROR("No pannel fixed mode was found\n");
+ DRM_ERROR("No panel fixed mode was found\n");
goto dsi_init_err0;
}
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.h b/drivers/gpu/drm/gma500/mdfld_dsi_output.h
index 0cccfe400a98..5c0db3c2903f 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.h
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.h
@@ -372,6 +372,6 @@ extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config,
extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config,
u32 *mode, bool hs);
-extern int mdfld_dsi_panel_reset(int pipe);
+extern int mdfld_dsi_panel_reset(struct drm_device *dev, int pipe);
#endif /*__MDFLD_DSI_OUTPUT_H__*/
diff --git a/drivers/gpu/drm/gma500/mdfld_output.h b/drivers/gpu/drm/gma500/mdfld_output.h
index 17a944d70add..37a516cc56be 100644
--- a/drivers/gpu/drm/gma500/mdfld_output.h
+++ b/drivers/gpu/drm/gma500/mdfld_output.h
@@ -54,7 +54,7 @@ struct panel_funcs {
const struct drm_encoder_helper_funcs *encoder_helper_funcs;
struct drm_display_mode * (*get_config_mode)(struct drm_device *);
int (*get_panel_info)(struct drm_device *, int, struct panel_info *);
- int (*reset)(int pipe);
+ int (*reset)(struct drm_device *, int);
void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe);
};
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index 3dd5718c3e31..5340225d6997 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -13,7 +13,6 @@
#include <drm/drm_encoder.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
-#include <linux/gpio.h>
#include "gma_display.h"
/*
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 06e44f47e73e..907f966d6f22 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -125,7 +125,7 @@ struct psb_intel_sdvo {
bool is_lvds;
/**
- * This is sdvo fixed pannel mode pointer
+ * This is sdvo fixed panel mode pointer
*/
struct drm_display_mode *sdvo_lvds_fixed_mode;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
index cc70e836522f..4d57ec688f82 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -17,9 +17,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_vram_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_print.h>
-#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "hibmc_drm_drv.h"
@@ -74,12 +71,12 @@ static int hibmc_plane_atomic_check(struct drm_plane *plane,
return PTR_ERR(crtc_state);
if (src_w != state->crtc_w || src_h != state->crtc_h) {
- DRM_DEBUG_ATOMIC("scale not support\n");
+ drm_dbg_atomic(plane->dev, "scale not support\n");
return -EINVAL;
}
if (state->crtc_x < 0 || state->crtc_y < 0) {
- DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n");
+ drm_dbg_atomic(plane->dev, "crtc_x/y of drm_plane state is invalid\n");
return -EINVAL;
}
@@ -90,12 +87,12 @@ static int hibmc_plane_atomic_check(struct drm_plane *plane,
crtc_state->adjusted_mode.hdisplay ||
state->crtc_y + state->crtc_h >
crtc_state->adjusted_mode.vdisplay) {
- DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n");
+ drm_dbg_atomic(plane->dev, "visible portion of plane is invalid\n");
return -EINVAL;
}
if (state->fb->pitches[0] % 128 != 0) {
- DRM_DEBUG_ATOMIC("wrong stride with 128-byte aligned\n");
+ drm_dbg_atomic(plane->dev, "wrong stride with 128-byte aligned\n");
return -EINVAL;
}
return 0;
@@ -160,37 +157,6 @@ static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
.atomic_update = hibmc_plane_atomic_update,
};
-static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
-{
- struct drm_device *dev = priv->dev;
- struct drm_plane *plane;
- int ret = 0;
-
- plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
- if (!plane) {
- DRM_ERROR("failed to alloc memory when init plane\n");
- return ERR_PTR(-ENOMEM);
- }
- /*
- * plane init
- * TODO: Now only support primary plane, overlay planes
- * need to do.
- */
- ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
- channel_formats1,
- ARRAY_SIZE(channel_formats1),
- NULL,
- DRM_PLANE_TYPE_PRIMARY,
- NULL);
- if (ret) {
- DRM_ERROR("failed to init plane: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
- return plane;
-}
-
static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms)
{
struct hibmc_drm_private *priv = crtc->dev->dev_private;
@@ -537,32 +503,34 @@ static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
int hibmc_de_init(struct hibmc_drm_private *priv)
{
struct drm_device *dev = priv->dev;
- struct drm_crtc *crtc;
- struct drm_plane *plane;
+ struct drm_crtc *crtc = &priv->crtc;
+ struct drm_plane *plane = &priv->primary_plane;
int ret;
- plane = hibmc_plane_init(priv);
- if (IS_ERR(plane)) {
- DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane));
- return PTR_ERR(plane);
- }
+ ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
+ channel_formats1,
+ ARRAY_SIZE(channel_formats1),
+ NULL,
+ DRM_PLANE_TYPE_PRIMARY,
+ NULL);
- crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL);
- if (!crtc) {
- DRM_ERROR("failed to alloc memory when init crtc\n");
- return -ENOMEM;
+ if (ret) {
+ drm_err(dev, "failed to init plane: %d\n", ret);
+ return ret;
}
+ drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
+
ret = drm_crtc_init_with_planes(dev, crtc, plane,
NULL, &hibmc_crtc_funcs, NULL);
if (ret) {
- DRM_ERROR("failed to init crtc: %d\n", ret);
+ drm_err(dev, "failed to init crtc: %d\n", ret);
return ret;
}
ret = drm_mode_crtc_set_gamma_size(crtc, 256);
if (ret) {
- DRM_ERROR("failed to set gamma size: %d\n", ret);
+ drm_err(dev, "failed to set gamma size: %d\n", ret);
return ret;
}
drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index eea13e60187b..085d1b2fa8c0 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -11,18 +11,14 @@
* Jianhua Li <lijianhua@huawei.com>
*/
-#include <linux/console.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_irq.h>
#include <drm/drm_managed.h>
-#include <drm/drm_print.h>
-#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "hibmc_drm_drv.h"
@@ -102,13 +98,13 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
ret = hibmc_de_init(priv);
if (ret) {
- DRM_ERROR("failed to init de: %d\n", ret);
+ drm_err(priv->dev, "failed to init de: %d\n", ret);
return ret;
}
ret = hibmc_vdac_init(priv);
if (ret) {
- DRM_ERROR("failed to init vdac: %d\n", ret);
+ drm_err(priv->dev, "failed to init vdac: %d\n", ret);
return ret;
}
@@ -216,7 +212,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv)
iosize = pci_resource_len(pdev, 1);
priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize);
if (!priv->mmio) {
- DRM_ERROR("Cannot map mmio region\n");
+ drm_err(dev, "Cannot map mmio region\n");
return -ENOMEM;
}
@@ -224,7 +220,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv)
size = pci_resource_len(pdev, 0);
priv->fb_map = devm_ioremap(dev->dev, addr, size);
if (!priv->fb_map) {
- DRM_ERROR("Cannot map framebuffer\n");
+ drm_err(dev, "Cannot map framebuffer\n");
return -ENOMEM;
}
priv->fb_base = addr;
@@ -254,9 +250,8 @@ static int hibmc_unload(struct drm_device *dev)
if (dev->irq_enabled)
drm_irq_uninstall(dev);
- if (priv->msi_enabled)
- pci_disable_msi(dev->pdev);
+ pci_disable_msi(dev->pdev);
hibmc_kms_fini(priv);
hibmc_mm_fini(priv);
dev->dev_private = NULL;
@@ -270,7 +265,7 @@ static int hibmc_load(struct drm_device *dev)
priv = drmm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
- DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
+ drm_err(dev, "no memory to allocate for hibmc_drm_private\n");
return -ENOMEM;
}
dev->dev_private = priv;
@@ -290,19 +285,17 @@ static int hibmc_load(struct drm_device *dev)
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret) {
- DRM_ERROR("failed to initialize vblank: %d\n", ret);
+ drm_err(dev, "failed to initialize vblank: %d\n", ret);
goto err;
}
- priv->msi_enabled = 0;
ret = pci_enable_msi(dev->pdev);
if (ret) {
- DRM_WARN("enabling MSI failed: %d\n", ret);
+ drm_warn(dev, "enabling MSI failed: %d\n", ret);
} else {
- priv->msi_enabled = 1;
ret = drm_irq_install(dev, dev->pdev->irq);
if (ret)
- DRM_WARN("install irq failed: %d\n", ret);
+ drm_warn(dev, "install irq failed: %d\n", ret);
}
/* reset all the states of crtc/plane/encoder/connector */
@@ -312,7 +305,7 @@ static int hibmc_load(struct drm_device *dev)
err:
hibmc_unload(dev);
- DRM_ERROR("failed to initialize drm driver: %d\n", ret);
+ drm_err(dev, "failed to initialize drm driver: %d\n", ret);
return ret;
}
@@ -338,19 +331,19 @@ static int hibmc_pci_probe(struct pci_dev *pdev,
ret = pci_enable_device(pdev);
if (ret) {
- DRM_ERROR("failed to enable pci device: %d\n", ret);
+ drm_err(dev, "failed to enable pci device: %d\n", ret);
goto err_free;
}
ret = hibmc_load(dev);
if (ret) {
- DRM_ERROR("failed to load hibmc: %d\n", ret);
+ drm_err(dev, "failed to load hibmc: %d\n", ret);
goto err_disable;
}
ret = drm_dev_register(dev, 0);
if (ret) {
- DRM_ERROR("failed to register drv for userspace access: %d\n",
+ drm_err(dev, "failed to register drv for userspace access: %d\n",
ret);
goto err_unload;
}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 609768748de6..197485e2fe0b 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -25,10 +25,11 @@ struct hibmc_drm_private {
void __iomem *fb_map;
unsigned long fb_base;
unsigned long fb_size;
- bool msi_enabled;
/* drm */
struct drm_device *dev;
+ struct drm_plane primary_plane;
+ struct drm_crtc crtc;
struct drm_encoder encoder;
struct drm_connector connector;
bool mode_config_initialized;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
index 2ca69c38491a..376a05ddbc2f 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -11,10 +11,8 @@
* Jianhua Li <lijianhua@huawei.com>
*/
-#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_print.h>
#include "hibmc_drm_drv.h"
@@ -87,7 +85,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv)
ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs,
DRM_MODE_ENCODER_DAC, NULL);
if (ret) {
- DRM_ERROR("failed to init encoder: %d\n", ret);
+ drm_err(dev, "failed to init encoder: %d\n", ret);
return ret;
}
@@ -96,7 +94,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv)
ret = drm_connector_init(dev, connector, &hibmc_connector_funcs,
DRM_MODE_CONNECTOR_VGA);
if (ret) {
- DRM_ERROR("failed to init connector: %d\n", ret);
+ drm_err(dev, "failed to init connector: %d\n", ret);
return ret;
}
drm_connector_helper_add(connector, &hibmc_connector_helper_funcs);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 322bd542e89d..602ece11bb4a 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -32,7 +32,7 @@ int hibmc_mm_init(struct hibmc_drm_private *hibmc)
hibmc->fb_size);
if (IS_ERR(vmm)) {
ret = PTR_ERR(vmm);
- DRM_ERROR("Error initializing VRAM MM; %d\n", ret);
+ drm_err(dev, "Error initializing VRAM MM; %d\n", ret);
return ret;
}
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index 91a8161e7c05..577c4441f32d 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -2677,7 +2677,7 @@ void intel_update_cdclk(struct drm_i915_private *dev_priv)
*/
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
intel_de_write(dev_priv, GMBUSFREQ_VLV,
- DIV_ROUND_UP(dev_priv->cdclk.hw.cdclk, 1000));
+ DIV_ROUND_UP(dev_priv->cdclk.hw.cdclk, 1000));
}
static int cnp_rawclk(struct drm_i915_private *dev_priv)
@@ -2903,9 +2903,10 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
dev_priv->display.get_cdclk = i85x_get_cdclk;
else if (IS_I845G(dev_priv))
dev_priv->display.get_cdclk = fixed_200mhz_get_cdclk;
- else { /* 830 */
- drm_WARN(&dev_priv->drm, !IS_I830(dev_priv),
- "Unknown platform. Assuming 133 MHz CDCLK\n");
+ else if (IS_I830(dev_priv))
+ dev_priv->display.get_cdclk = fixed_133mhz_get_cdclk;
+
+ if (drm_WARN(&dev_priv->drm, !dev_priv->display.get_cdclk,
+ "Unknown platform. Assuming 133 MHz CDCLK\n"))
dev_priv->display.get_cdclk = fixed_133mhz_get_cdclk;
- }
}
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h
index 5731806e4cee..6b31fde4be16 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.h
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.h
@@ -17,8 +17,8 @@ struct intel_atomic_state;
struct intel_crtc_state;
struct intel_cdclk_vals {
- u16 refclk;
u32 cdclk;
+ u16 refclk;
u8 divider; /* CD2X divider * 2 */
u8 ratio;
};
diff --git a/drivers/gpu/drm/i915/display/intel_csr.c b/drivers/gpu/drm/i915/display/intel_csr.c
index f22a7645c249..d5db16764619 100644
--- a/drivers/gpu/drm/i915/display/intel_csr.c
+++ b/drivers/gpu/drm/i915/display/intel_csr.c
@@ -40,12 +40,12 @@
#define GEN12_CSR_MAX_FW_SIZE ICL_CSR_MAX_FW_SIZE
-#define RKL_CSR_PATH "i915/rkl_dmc_ver2_01.bin"
-#define RKL_CSR_VERSION_REQUIRED CSR_VERSION(2, 1)
+#define RKL_CSR_PATH "i915/rkl_dmc_ver2_02.bin"
+#define RKL_CSR_VERSION_REQUIRED CSR_VERSION(2, 2)
MODULE_FIRMWARE(RKL_CSR_PATH);
-#define TGL_CSR_PATH "i915/tgl_dmc_ver2_06.bin"
-#define TGL_CSR_VERSION_REQUIRED CSR_VERSION(2, 6)
+#define TGL_CSR_PATH "i915/tgl_dmc_ver2_08.bin"
+#define TGL_CSR_VERSION_REQUIRED CSR_VERSION(2, 8)
#define TGL_CSR_MAX_FW_SIZE 0x6000
MODULE_FIRMWARE(TGL_CSR_PATH);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index a49ff3a1a63c..19ac6b2a664c 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -706,6 +706,42 @@ static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr2[] =
{ 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */
};
+static const struct cnl_ddi_buf_trans tgl_uy_combo_phy_ddi_translations_dp_hbr2[] = {
+ /* NT mV Trans mV db */
+ { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */
+ { 0xA, 0x4F, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */
+ { 0xC, 0x60, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */
+ { 0xC, 0x7F, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */
+ { 0xC, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */
+ { 0xC, 0x6F, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */
+ { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */
+ { 0x6, 0x60, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */
+ { 0x6, 0x7F, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */
+};
+
+/*
+ * Cloned the HOBL entry to comply with the voltage and pre-emphasis entries
+ * that DisplayPort specification requires
+ */
+static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_edp_hbr2_hobl[] = {
+ /* VS pre-emp */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 0 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 1 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 2 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 3 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 0 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 1 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 2 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 0 */
+ { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 1 */
+};
+
+static bool is_hobl_buf_trans(const struct cnl_ddi_buf_trans *table)
+{
+ return table == tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
+}
+
static const struct ddi_buf_trans *
bdw_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries)
{
@@ -1050,9 +1086,26 @@ static const struct cnl_ddi_buf_trans *
tgl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
int *n_entries)
{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+ if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.hobl) {
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ if (!intel_dp->hobl_failed && rate <= 540000) {
+ /* Same table applies to TGL, RKL and DG1 */
+ *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl);
+ return tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
+ }
+ }
+
if (type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_EDP) {
return icl_get_combo_buf_trans(encoder, type, rate, n_entries);
} else if (rate > 270000) {
+ if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) {
+ *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2);
+ return tgl_uy_combo_phy_ddi_translations_dp_hbr2;
+ }
+
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2);
return tgl_combo_phy_ddi_translations_dp_hbr2;
}
@@ -2392,6 +2445,15 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder,
level = n_entries - 1;
}
+ if (type == INTEL_OUTPUT_EDP) {
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ val = EDP4K2K_MODE_OVRD_EN | EDP4K2K_MODE_OVRD_OPTIMIZED;
+ intel_dp->hobl_active = is_hobl_buf_trans(ddi_translations);
+ intel_de_rmw(dev_priv, ICL_PORT_CL_DW10(phy), val,
+ intel_dp->hobl_active ? val : 0);
+ }
+
/* Set PORT_TX_DW5 */
val = intel_de_read(dev_priv, ICL_PORT_TX_DW5_LN0(phy));
val &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK |
@@ -2802,7 +2864,9 @@ hsw_set_signal_levels(struct intel_dp *intel_dp)
static u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv,
enum phy phy)
{
- if (intel_phy_is_combo(dev_priv, phy)) {
+ if (IS_ROCKETLAKE(dev_priv)) {
+ return RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
+ } else if (intel_phy_is_combo(dev_priv, phy)) {
return ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy);
} else if (intel_phy_is_tc(dev_priv, phy)) {
enum tc_port tc_port = intel_port_to_tc(dev_priv,
@@ -2829,6 +2893,16 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder,
(val & icl_dpclka_cfgcr0_clk_off(dev_priv, phy)) == 0);
if (intel_phy_is_combo(dev_priv, phy)) {
+ u32 mask, sel;
+
+ if (IS_ROCKETLAKE(dev_priv)) {
+ mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
+ sel = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy);
+ } else {
+ mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
+ sel = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy);
+ }
+
/*
* Even though this register references DDIs, note that we
* want to pass the PHY rather than the port (DDI). For
@@ -2839,8 +2913,8 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder,
* Clock Select chooses the PLL for both DDIA and DDID and
* drives port A in all cases."
*/
- val &= ~ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
- val |= ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy);
+ val &= ~mask;
+ val |= sel;
intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val);
intel_de_posting_read(dev_priv, ICL_DPCLKA_CFGCR0);
}
@@ -4037,8 +4111,7 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
intel_wait_ddi_buf_idle(dev_priv, port);
}
- dp_tp_ctl = DP_TP_CTL_ENABLE |
- DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE;
+ dp_tp_ctl = DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_PAT1;
if (intel_dp->link_mst)
dp_tp_ctl |= DP_TP_CTL_MODE_MST;
else {
@@ -4061,16 +4134,10 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
- enum port port = dp_to_dig_port(intel_dp)->base.port;
u32 temp;
temp = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
- if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
- temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
- else
- temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE;
-
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
switch (dp_train_pat & train_pat_mask) {
case DP_TRAINING_PATTERN_DISABLE:
@@ -4091,9 +4158,6 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
}
intel_de_write(dev_priv, intel_dp->regs.dp_tp_ctl, temp);
-
- intel_de_write(dev_priv, DDI_BUF_CTL(port), intel_dp->DP);
- intel_de_posting_read(dev_priv, DDI_BUF_CTL(port));
}
static void intel_ddi_set_idle_link_train(struct intel_dp *intel_dp)
@@ -4878,6 +4942,13 @@ intel_ddi_max_lanes(struct intel_digital_port *dig_port)
return max_lanes;
}
+static bool hti_uses_phy(struct drm_i915_private *i915, enum phy phy)
+{
+ return i915->hti_state & HDPORT_ENABLED &&
+ (i915->hti_state & HDPORT_PHY_USED_DP(phy) ||
+ i915->hti_state & HDPORT_PHY_USED_HDMI(phy));
+}
+
void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
{
struct intel_digital_port *dig_port;
@@ -4885,6 +4956,18 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
bool init_hdmi, init_dp, init_lspcon = false;
enum phy phy = intel_port_to_phy(dev_priv, port);
+ /*
+ * On platforms with HTI (aka HDPORT), if it's enabled at boot it may
+ * have taken over some of the PHYs and made them unavailable to the
+ * driver. In that case we should skip initializing the corresponding
+ * outputs.
+ */
+ if (hti_uses_phy(dev_priv, phy)) {
+ drm_dbg_kms(&dev_priv->drm, "PORT %c / PHY %c reserved by HTI\n",
+ port_name(port), phy_name(phy));
+ return;
+ }
+
init_hdmi = intel_bios_port_supports_dvi(dev_priv, port) ||
intel_bios_port_supports_hdmi(dev_priv, port);
init_dp = intel_bios_port_supports_dp(dev_priv, port);
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 68325678f5ef..d60efb8f4ba3 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -47,6 +47,7 @@
#include "display/intel_ddi.h"
#include "display/intel_dp.h"
#include "display/intel_dp_mst.h"
+#include "display/intel_dpll_mgr.h"
#include "display/intel_dsi.h"
#include "display/intel_dvo.h"
#include "display/intel_gmbus.h"
@@ -3761,6 +3762,44 @@ static int glk_max_plane_width(const struct drm_framebuffer *fb,
}
}
+static int icl_min_plane_width(const struct drm_framebuffer *fb)
+{
+ /* Wa_14011264657, Wa_14011050563: gen11+ */
+ switch (fb->format->format) {
+ case DRM_FORMAT_C8:
+ return 18;
+ case DRM_FORMAT_RGB565:
+ return 10;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_XVYU2101010:
+ case DRM_FORMAT_Y212:
+ case DRM_FORMAT_Y216:
+ return 6;
+ case DRM_FORMAT_NV12:
+ return 20;
+ case DRM_FORMAT_P010:
+ case DRM_FORMAT_P012:
+ case DRM_FORMAT_P016:
+ return 12;
+ case DRM_FORMAT_XRGB16161616F:
+ case DRM_FORMAT_XBGR16161616F:
+ case DRM_FORMAT_ARGB16161616F:
+ case DRM_FORMAT_ABGR16161616F:
+ case DRM_FORMAT_XVYU12_16161616:
+ case DRM_FORMAT_XVYU16161616:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
static int icl_max_plane_width(const struct drm_framebuffer *fb,
int color_plane,
unsigned int rotation)
@@ -3843,29 +3882,31 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
int y = plane_state->uapi.src.y1 >> 16;
int w = drm_rect_width(&plane_state->uapi.src) >> 16;
int h = drm_rect_height(&plane_state->uapi.src) >> 16;
- int max_width;
- int max_height;
- u32 alignment;
- u32 offset;
+ int max_width, min_width, max_height;
+ u32 alignment, offset;
int aux_plane = intel_main_to_aux_plane(fb, 0);
u32 aux_offset = plane_state->color_plane[aux_plane].offset;
- if (INTEL_GEN(dev_priv) >= 11)
+ if (INTEL_GEN(dev_priv) >= 11) {
max_width = icl_max_plane_width(fb, 0, rotation);
- else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
+ min_width = icl_min_plane_width(fb);
+ } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
max_width = glk_max_plane_width(fb, 0, rotation);
- else
+ min_width = 1;
+ } else {
max_width = skl_max_plane_width(fb, 0, rotation);
+ min_width = 1;
+ }
if (INTEL_GEN(dev_priv) >= 11)
max_height = icl_max_plane_height();
else
max_height = skl_max_plane_height();
- if (w > max_width || h > max_height) {
+ if (w > max_width || w < min_width || h > max_height) {
drm_dbg_kms(&dev_priv->drm,
- "requested Y/RGB source size %dx%d too big (limit %dx%d)\n",
- w, h, max_width, max_height);
+ "requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n",
+ w, h, min_width, max_width, max_height);
return -EINVAL;
}
@@ -10802,9 +10843,18 @@ static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
u32 temp;
if (intel_phy_is_combo(dev_priv, phy)) {
- temp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0) &
- ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
- id = temp >> ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy);
+ u32 mask, shift;
+
+ if (IS_ROCKETLAKE(dev_priv)) {
+ mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
+ shift = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy);
+ } else {
+ mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy);
+ shift = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy);
+ }
+
+ temp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0) & mask;
+ id = temp >> shift;
port_dpll_id = ICL_PORT_DPLL_DEFAULT;
} else if (intel_phy_is_tc(dev_priv, phy)) {
u32 clk_sel = intel_de_read(dev_priv, DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK;
@@ -12760,6 +12810,9 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
}
+ if (!mode_changed)
+ intel_psr2_sel_fetch_update(state, crtc);
+
return 0;
}
@@ -15136,6 +15189,8 @@ static void commit_pipe_config(struct intel_atomic_state *state,
if (new_crtc_state->update_pipe)
intel_pipe_fastset(old_crtc_state, new_crtc_state);
+
+ intel_psr2_program_trans_man_trk_ctl(new_crtc_state);
}
if (dev_priv->display.atomic_update_watermarks)
@@ -17894,6 +17949,13 @@ int intel_modeset_init(struct drm_i915_private *i915)
if (i915->max_cdclk_freq == 0)
intel_update_max_cdclk(i915);
+ /*
+ * If the platform has HTI, we need to find out whether it has reserved
+ * any display resources before we create our display outputs.
+ */
+ if (INTEL_INFO(i915)->display.has_hti)
+ i915->hti_state = intel_de_read(i915, HDPORT_STATE);
+
/* Just disable it once at startup */
intel_vga_disable(i915);
intel_setup_outputs(i915);
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 5a5cfe25085b..f549381048b3 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -417,6 +417,9 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
su_blocks = su_blocks >> PSR2_SU_STATUS_SHIFT(frame);
seq_printf(m, "%d\t%d\n", frame, su_blocks);
}
+
+ seq_printf(m, "PSR2 selective fetch: %s\n",
+ enableddisabled(psr->psr2_sel_fetch_enabled));
}
unlock:
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index e0fcb89c736b..7946c6af4b1e 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -3927,12 +3927,13 @@ tgl_tc_cold_request(struct drm_i915_private *i915, bool block)
int ret;
while (1) {
- u32 low_val = 0, high_val;
+ u32 low_val;
+ u32 high_val = 0;
if (block)
- high_val = TGL_PCODE_EXIT_TCCOLD_DATA_H_BLOCK_REQ;
+ low_val = TGL_PCODE_EXIT_TCCOLD_DATA_L_BLOCK_REQ;
else
- high_val = TGL_PCODE_EXIT_TCCOLD_DATA_H_UNBLOCK_REQ;
+ low_val = TGL_PCODE_EXIT_TCCOLD_DATA_L_UNBLOCK_REQ;
/*
* Spec states that we should timeout the request after 200us
@@ -3951,8 +3952,7 @@ tgl_tc_cold_request(struct drm_i915_private *i915, bool block)
if (++tries == 3)
break;
- if (ret == -EAGAIN)
- msleep(1);
+ msleep(1);
}
if (ret)
@@ -5302,6 +5302,12 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+ /* Wa_14011294188:ehl,jsl,tgl,rkl */
+ if (INTEL_PCH_TYPE(dev_priv) >= PCH_JSP &&
+ INTEL_PCH_TYPE(dev_priv) < PCH_DG1)
+ intel_de_rmw(dev_priv, SOUTH_DSPCLK_GATE_D, 0,
+ PCH_DPMGUNIT_CLOCK_GATE_DISABLE);
+
/* 1. Enable PCH reset handshake. */
intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv));
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index e8f809161c75..9349b15afff6 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -931,6 +931,7 @@ struct intel_crtc_state {
bool has_psr;
bool has_psr2;
+ bool enable_psr2_sel_fetch;
u32 dc3co_exitline;
/*
@@ -1073,6 +1074,8 @@ struct intel_crtc_state {
/* For DSB related info */
struct intel_dsb *dsb;
+
+ u32 psr2_man_track_ctl;
};
enum intel_pipe_crc_source {
@@ -1375,6 +1378,9 @@ struct intel_dp {
/* Display stream compression testing */
bool force_dsc_en;
+
+ bool hobl_failed;
+ bool hobl_active;
};
enum lspcon_vendor {
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index d6295eb20b63..79c27f91f42c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -6243,6 +6243,11 @@ out:
*/
intel_display_power_flush_work(dev_priv);
+ if (!intel_dp_is_edp(intel_dp))
+ drm_dp_set_subconnector_property(connector,
+ status,
+ intel_dp->dpcd,
+ intel_dp->downstream_ports);
return status;
}
@@ -7312,6 +7317,9 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
struct drm_i915_private *dev_priv = to_i915(connector->dev);
enum port port = dp_to_dig_port(intel_dp)->base.port;
+ if (!intel_dp_is_edp(intel_dp))
+ drm_connector_attach_dp_subconnector_property(connector);
+
if (!IS_G4X(dev_priv) && port != PORT_A)
intel_attach_force_audio_property(connector);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index a23ed7290843..f2c8b56be9ea 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -410,10 +410,17 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
intel_connector->base.base.id,
intel_connector->base.name,
intel_dp->link_rate, intel_dp->lane_count);
- if (!intel_dp_get_link_train_fallback_values(intel_dp,
- intel_dp->link_rate,
- intel_dp->lane_count))
- /* Schedule a Hotplug Uevent to userspace to start modeset */
- schedule_work(&intel_connector->modeset_retry_work);
- return;
+
+ if (intel_dp->hobl_active) {
+ drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+ "Link Training failed with HOBL active, not enabling it from now on");
+ intel_dp->hobl_failed = true;
+ } else if (intel_dp_get_link_train_fallback_values(intel_dp,
+ intel_dp->link_rate,
+ intel_dp->lane_count)) {
+ return;
+ }
+
+ /* Schedule a Hotplug Uevent to userspace to start modeset */
+ schedule_work(&intel_connector->modeset_retry_work);
}
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index afa7a378b31d..c9013f8f766f 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -3475,6 +3475,14 @@ static void icl_update_active_dpll(struct intel_atomic_state *state,
icl_set_active_port_dpll(crtc_state, port_dpll_id);
}
+static u32 intel_get_hti_plls(struct drm_i915_private *i915)
+{
+ if (!(i915->hti_state & HDPORT_ENABLED))
+ return 0;
+
+ return REG_FIELD_GET(HDPORT_DPLL_USED_MASK, i915->hti_state);
+}
+
static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
struct intel_crtc *crtc,
struct intel_encoder *encoder)
@@ -3504,13 +3512,22 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state,
icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state);
- if (IS_ELKHARTLAKE(dev_priv) && port != PORT_A)
+ if (IS_ROCKETLAKE(dev_priv)) {
dpll_mask =
BIT(DPLL_ID_EHL_DPLL4) |
BIT(DPLL_ID_ICL_DPLL1) |
BIT(DPLL_ID_ICL_DPLL0);
- else
+ } else if (IS_ELKHARTLAKE(dev_priv) && port != PORT_A) {
+ dpll_mask =
+ BIT(DPLL_ID_EHL_DPLL4) |
+ BIT(DPLL_ID_ICL_DPLL1) |
+ BIT(DPLL_ID_ICL_DPLL0);
+ } else {
dpll_mask = BIT(DPLL_ID_ICL_DPLL1) | BIT(DPLL_ID_ICL_DPLL0);
+ }
+
+ /* Eliminate DPLLs from consideration if reserved by HTI */
+ dpll_mask &= ~intel_get_hti_plls(dev_priv);
port_dpll->pll = intel_find_shared_dpll(state, crtc,
&port_dpll->hw_state,
@@ -3791,7 +3808,12 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
if (!(val & PLL_ENABLE))
goto out;
- if (INTEL_GEN(dev_priv) >= 12) {
+ if (IS_ROCKETLAKE(dev_priv)) {
+ hw_state->cfgcr0 = intel_de_read(dev_priv,
+ RKL_DPLL_CFGCR0(id));
+ hw_state->cfgcr1 = intel_de_read(dev_priv,
+ RKL_DPLL_CFGCR1(id));
+ } else if (INTEL_GEN(dev_priv) >= 12) {
hw_state->cfgcr0 = intel_de_read(dev_priv,
TGL_DPLL_CFGCR0(id));
hw_state->cfgcr1 = intel_de_read(dev_priv,
@@ -3844,7 +3866,10 @@ static void icl_dpll_write(struct drm_i915_private *dev_priv,
const enum intel_dpll_id id = pll->info->id;
i915_reg_t cfgcr0_reg, cfgcr1_reg;
- if (INTEL_GEN(dev_priv) >= 12) {
+ if (IS_ROCKETLAKE(dev_priv)) {
+ cfgcr0_reg = RKL_DPLL_CFGCR0(id);
+ cfgcr1_reg = RKL_DPLL_CFGCR1(id);
+ } else if (INTEL_GEN(dev_priv) >= 12) {
cfgcr0_reg = TGL_DPLL_CFGCR0(id);
cfgcr1_reg = TGL_DPLL_CFGCR1(id);
} else {
@@ -4276,6 +4301,21 @@ static const struct intel_dpll_mgr tgl_pll_mgr = {
.dump_hw_state = icl_dump_hw_state,
};
+static const struct dpll_info rkl_plls[] = {
+ { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 },
+ { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 },
+ { "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 },
+ { },
+};
+
+static const struct intel_dpll_mgr rkl_pll_mgr = {
+ .dpll_info = rkl_plls,
+ .get_dplls = icl_get_dplls,
+ .put_dplls = icl_put_dplls,
+ .update_ref_clks = icl_update_dpll_ref_clks,
+ .dump_hw_state = icl_dump_hw_state,
+};
+
/**
* intel_shared_dpll_init - Initialize shared DPLLs
* @dev: drm device
@@ -4289,7 +4329,9 @@ void intel_shared_dpll_init(struct drm_device *dev)
const struct dpll_info *dpll_info;
int i;
- if (INTEL_GEN(dev_priv) >= 12)
+ if (IS_ROCKETLAKE(dev_priv))
+ dpll_mgr = &rkl_pll_mgr;
+ else if (INTEL_GEN(dev_priv) >= 12)
dpll_mgr = &tgl_pll_mgr;
else if (IS_ELKHARTLAKE(dev_priv))
dpll_mgr = &ehl_pll_mgr;
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index 24c3a0f212c6..135f5e8a4d70 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -424,6 +424,14 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv,
fbc->no_fbc_reason = reason;
}
+static u64 intel_fbc_cfb_base_max(struct drm_i915_private *i915)
+{
+ if (INTEL_GEN(i915) >= 5 || IS_G4X(i915))
+ return BIT_ULL(28);
+ else
+ return BIT_ULL(32);
+}
+
static int find_compression_threshold(struct drm_i915_private *dev_priv,
struct drm_mm_node *node,
unsigned int size,
@@ -442,6 +450,8 @@ static int find_compression_threshold(struct drm_i915_private *dev_priv,
else
end = U64_MAX;
+ end = min(end, intel_fbc_cfb_base_max(dev_priv));
+
/* HACK: This code depends on what we will do in *_enable_fbc. If that
* code changes, this code needs to change as well.
*
@@ -1416,6 +1426,13 @@ static int intel_sanitize_fbc_option(struct drm_i915_private *dev_priv)
if (!HAS_FBC(dev_priv))
return 0;
+ /*
+ * Fbc is causing random underruns in CI execution on TGL platforms.
+ * Disabling the same while the problem is being debugged and analyzed.
+ */
+ if (IS_TIGERLAKE(dev_priv))
+ return 0;
+
if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9)
return 1;
diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c
index 2979ed2588eb..d898b370d7a4 100644
--- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c
+++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c
@@ -232,6 +232,8 @@ static void frontbuffer_release(struct kref *ref)
RCU_INIT_POINTER(obj->frontbuffer, NULL);
spin_unlock(&to_i915(obj->base.dev)->fb_tracking.lock);
+ i915_active_fini(&front->write);
+
i915_gem_object_put(obj);
kfree_rcu(front, rcu);
}
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index bf9e320c547d..2b004ee9619c 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -553,6 +553,22 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
val |= EDP_PSR2_FAST_WAKE(7);
}
+ if (dev_priv->psr.psr2_sel_fetch_enabled) {
+ /* WA 1408330847 */
+ if (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) ||
+ IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0))
+ intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
+ DIS_RAM_BYPASS_PSR2_MAN_TRACK,
+ DIS_RAM_BYPASS_PSR2_MAN_TRACK);
+
+ intel_de_write(dev_priv,
+ PSR2_MAN_TRK_CTL(dev_priv->psr.transcoder),
+ PSR2_MAN_TRK_CTL_ENABLE);
+ } else if (HAS_PSR2_SEL_FETCH(dev_priv)) {
+ intel_de_write(dev_priv,
+ PSR2_MAN_TRK_CTL(dev_priv->psr.transcoder), 0);
+ }
+
/*
* PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is
* recommending keep this bit unset while PSR2 is enabled.
@@ -663,6 +679,38 @@ tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp,
crtc_state->dc3co_exitline = crtc_vdisplay - exit_scanlines;
}
+static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp,
+ struct intel_crtc_state *crtc_state)
+{
+ struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state);
+ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ struct intel_plane_state *plane_state;
+ struct intel_plane *plane;
+ int i;
+
+ if (!dev_priv->params.enable_psr2_sel_fetch) {
+ drm_dbg_kms(&dev_priv->drm,
+ "PSR2 sel fetch not enabled, disabled by parameter\n");
+ return false;
+ }
+
+ if (crtc_state->uapi.async_flip) {
+ drm_dbg_kms(&dev_priv->drm,
+ "PSR2 sel fetch not enabled, async flip enabled\n");
+ return false;
+ }
+
+ for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+ if (plane_state->uapi.rotation != DRM_MODE_ROTATE_0) {
+ drm_dbg_kms(&dev_priv->drm,
+ "PSR2 sel fetch not enabled, plane rotated\n");
+ return false;
+ }
+ }
+
+ return crtc_state->enable_psr2_sel_fetch = true;
+}
+
static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state)
{
@@ -732,22 +780,17 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
return false;
}
- /*
- * Some platforms lack PSR2 HW tracking and instead require manual
- * tracking by software. In this case, the driver is required to track
- * the areas that need updates and program hardware to send selective
- * updates.
- *
- * So until the software tracking is implemented, PSR2 needs to be
- * disabled for platforms without PSR2 HW tracking.
- */
- if (!HAS_PSR_HW_TRACKING(dev_priv)) {
- drm_dbg_kms(&dev_priv->drm,
- "No PSR2 HW tracking in the platform\n");
- return false;
+ if (HAS_PSR2_SEL_FETCH(dev_priv)) {
+ if (!intel_psr2_sel_fetch_config_valid(intel_dp, crtc_state) &&
+ !HAS_PSR_HW_TRACKING(dev_priv)) {
+ drm_dbg_kms(&dev_priv->drm,
+ "PSR2 not enabled, selective fetch not valid and no HW tracking available\n");
+ return false;
+ }
}
- if (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v) {
+ if (!crtc_state->enable_psr2_sel_fetch &&
+ (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v)) {
drm_dbg_kms(&dev_priv->drm,
"PSR2 not enabled, resolution %dx%d > max supported %dx%d\n",
crtc_hdisplay, crtc_vdisplay,
@@ -898,6 +941,11 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
val |= EXITLINE_ENABLE;
intel_de_write(dev_priv, EXITLINE(cpu_transcoder), val);
}
+
+ if (HAS_PSR_HW_TRACKING(dev_priv))
+ intel_de_rmw(dev_priv, CHICKEN_PAR1_1, IGNORE_PSR2_HW_TRACKING,
+ dev_priv->psr.psr2_sel_fetch_enabled ?
+ IGNORE_PSR2_HW_TRACKING : 0);
}
static void intel_psr_enable_locked(struct drm_i915_private *dev_priv,
@@ -919,6 +967,7 @@ static void intel_psr_enable_locked(struct drm_i915_private *dev_priv,
/* DC5/DC6 requires at least 6 idle frames */
val = usecs_to_jiffies(intel_get_frame_time_us(crtc_state) * 6);
dev_priv->psr.dc3co_exit_delay = val;
+ dev_priv->psr.psr2_sel_fetch_enabled = crtc_state->enable_psr2_sel_fetch;
/*
* If a PSR error happened and the driver is reloaded, the EDP_PSR_IIR
@@ -1058,6 +1107,13 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
psr_status_mask, 2000))
drm_err(&dev_priv->drm, "Timed out waiting PSR idle state\n");
+ /* WA 1408330847 */
+ if (dev_priv->psr.psr2_sel_fetch_enabled &&
+ (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) ||
+ IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0)))
+ intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
+ DIS_RAM_BYPASS_PSR2_MAN_TRACK, 0);
+
/* Disable PSR on Sink */
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0);
@@ -1115,6 +1171,32 @@ static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv)
intel_psr_exit(dev_priv);
}
+void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct i915_psr *psr = &dev_priv->psr;
+
+ if (!HAS_PSR2_SEL_FETCH(dev_priv) ||
+ !crtc_state->enable_psr2_sel_fetch)
+ return;
+
+ intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(psr->transcoder),
+ crtc_state->psr2_man_track_ctl);
+}
+
+void intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
+
+ if (!crtc_state->enable_psr2_sel_fetch)
+ return;
+
+ crtc_state->psr2_man_track_ctl = PSR2_MAN_TRK_CTL_ENABLE |
+ PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME;
+}
+
/**
* intel_psr_update - Update PSR state
* @intel_dp: Intel DP
diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
index b4515186d5f4..6a83c8e682e6 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.h
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
@@ -13,6 +13,8 @@ struct drm_connector_state;
struct drm_i915_private;
struct intel_crtc_state;
struct intel_dp;
+struct intel_crtc;
+struct intel_atomic_state;
#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
void intel_psr_init_dpcd(struct intel_dp *intel_dp);
@@ -43,5 +45,8 @@ void intel_psr_atomic_check(struct drm_connector *connector,
struct drm_connector_state *old_state,
struct drm_connector_state *new_state);
void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp);
+void intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
+ struct intel_crtc *crtc);
+void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_PSR_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index c89f5f7ccb06..6b72223981be 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -2843,8 +2843,9 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv,
enum plane_id plane_id)
{
- /* Wa_14010477008:tgl[a0..c0] */
- if (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0))
+ /* Wa_14010477008:tgl[a0..c0],rkl[all] */
+ if (IS_ROCKETLAKE(dev_priv) ||
+ IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0))
return false;
return plane_id < PLANE_SPRITE4;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 6b4ec66cb558..02b1630f513e 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -26,6 +26,7 @@
#include "i915_gem_ioctls.h"
#include "i915_sw_fence_work.h"
#include "i915_trace.h"
+#include "i915_user_extensions.h"
struct eb_vma {
struct i915_vma *vma;
@@ -222,6 +223,13 @@ struct eb_vma_array {
* the batchbuffer in trusted mode, otherwise the ioctl is rejected.
*/
+struct eb_fence {
+ struct drm_syncobj *syncobj; /* Use with ptr_mask_bits() */
+ struct dma_fence *dma_fence;
+ u64 value;
+ struct dma_fence_chain *chain_fence;
+};
+
struct i915_execbuffer {
struct drm_i915_private *i915; /** i915 backpointer */
struct drm_file *file; /** per-file lookup tables and limits */
@@ -281,6 +289,9 @@ struct i915_execbuffer {
int lut_size;
struct hlist_head *buckets; /** ht for relocation handles */
struct eb_vma_array *array;
+
+ struct eb_fence *fences;
+ unsigned long num_fences;
};
static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb)
@@ -1622,7 +1633,8 @@ static int i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
return -EINVAL;
/* Kernel clipping was a DRI1 misfeature */
- if (!(exec->flags & I915_EXEC_FENCE_ARRAY)) {
+ if (!(exec->flags & (I915_EXEC_FENCE_ARRAY |
+ I915_EXEC_USE_EXTENSIONS))) {
if (exec->num_cliprects || exec->cliprects_ptr)
return -EINVAL;
}
@@ -2201,107 +2213,241 @@ eb_pin_engine(struct i915_execbuffer *eb,
}
static void
-__free_fence_array(struct drm_syncobj **fences, unsigned int n)
+__free_fence_array(struct eb_fence *fences, unsigned int n)
{
- while (n--)
- drm_syncobj_put(ptr_mask_bits(fences[n], 2));
+ while (n--) {
+ drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2));
+ dma_fence_put(fences[n].dma_fence);
+ kfree(fences[n].chain_fence);
+ }
kvfree(fences);
}
-static struct drm_syncobj **
-get_fence_array(struct drm_i915_gem_execbuffer2 *args,
- struct drm_file *file)
+static int
+add_timeline_fence_array(struct i915_execbuffer *eb,
+ const struct drm_i915_gem_execbuffer_ext_timeline_fences *timeline_fences)
{
- const unsigned long nfences = args->num_cliprects;
- struct drm_i915_gem_exec_fence __user *user;
- struct drm_syncobj **fences;
- unsigned long n;
- int err;
+ struct drm_i915_gem_exec_fence __user *user_fences;
+ u64 __user *user_values;
+ struct eb_fence *f;
+ u64 nfences;
+ int err = 0;
- if (!(args->flags & I915_EXEC_FENCE_ARRAY))
- return NULL;
+ nfences = timeline_fences->fence_count;
+ if (!nfences)
+ return 0;
/* Check multiplication overflow for access_ok() and kvmalloc_array() */
BUILD_BUG_ON(sizeof(size_t) > sizeof(unsigned long));
if (nfences > min_t(unsigned long,
- ULONG_MAX / sizeof(*user),
- SIZE_MAX / sizeof(*fences)))
- return ERR_PTR(-EINVAL);
+ ULONG_MAX / sizeof(*user_fences),
+ SIZE_MAX / sizeof(*f)) - eb->num_fences)
+ return -EINVAL;
- user = u64_to_user_ptr(args->cliprects_ptr);
- if (!access_ok(user, nfences * sizeof(*user)))
- return ERR_PTR(-EFAULT);
+ user_fences = u64_to_user_ptr(timeline_fences->handles_ptr);
+ if (!access_ok(user_fences, nfences * sizeof(*user_fences)))
+ return -EFAULT;
+
+ user_values = u64_to_user_ptr(timeline_fences->values_ptr);
+ if (!access_ok(user_values, nfences * sizeof(*user_values)))
+ return -EFAULT;
- fences = kvmalloc_array(nfences, sizeof(*fences),
- __GFP_NOWARN | GFP_KERNEL);
- if (!fences)
- return ERR_PTR(-ENOMEM);
+ f = krealloc(eb->fences,
+ (eb->num_fences + nfences) * sizeof(*f),
+ __GFP_NOWARN | GFP_KERNEL);
+ if (!f)
+ return -ENOMEM;
+
+ eb->fences = f;
+ f += eb->num_fences;
- for (n = 0; n < nfences; n++) {
- struct drm_i915_gem_exec_fence fence;
+ BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) &
+ ~__I915_EXEC_FENCE_UNKNOWN_FLAGS);
+
+ while (nfences--) {
+ struct drm_i915_gem_exec_fence user_fence;
struct drm_syncobj *syncobj;
+ struct dma_fence *fence = NULL;
+ u64 point;
+
+ if (__copy_from_user(&user_fence,
+ user_fences++,
+ sizeof(user_fence)))
+ return -EFAULT;
+
+ if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS)
+ return -EINVAL;
+
+ if (__get_user(point, user_values++))
+ return -EFAULT;
- if (__copy_from_user(&fence, user++, sizeof(fence))) {
- err = -EFAULT;
- goto err;
+ syncobj = drm_syncobj_find(eb->file, user_fence.handle);
+ if (!syncobj) {
+ DRM_DEBUG("Invalid syncobj handle provided\n");
+ return -ENOENT;
}
- if (fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) {
- err = -EINVAL;
- goto err;
+ fence = drm_syncobj_fence_get(syncobj);
+
+ if (!fence && user_fence.flags &&
+ !(user_fence.flags & I915_EXEC_FENCE_SIGNAL)) {
+ DRM_DEBUG("Syncobj handle has no fence\n");
+ drm_syncobj_put(syncobj);
+ return -EINVAL;
}
- syncobj = drm_syncobj_find(file, fence.handle);
+ if (fence)
+ err = dma_fence_chain_find_seqno(&fence, point);
+
+ if (err && !(user_fence.flags & I915_EXEC_FENCE_SIGNAL)) {
+ DRM_DEBUG("Syncobj handle missing requested point %llu\n", point);
+ drm_syncobj_put(syncobj);
+ return err;
+ }
+
+ /*
+ * A point might have been signaled already and
+ * garbage collected from the timeline. In this case
+ * just ignore the point and carry on.
+ */
+ if (!fence && !(user_fence.flags & I915_EXEC_FENCE_SIGNAL)) {
+ drm_syncobj_put(syncobj);
+ continue;
+ }
+
+ /*
+ * For timeline syncobjs we need to preallocate chains for
+ * later signaling.
+ */
+ if (point != 0 && user_fence.flags & I915_EXEC_FENCE_SIGNAL) {
+ /*
+ * Waiting and signaling the same point (when point !=
+ * 0) would break the timeline.
+ */
+ if (user_fence.flags & I915_EXEC_FENCE_WAIT) {
+ DRM_DEBUG("Trying to wait & signal the same timeline point.\n");
+ dma_fence_put(fence);
+ drm_syncobj_put(syncobj);
+ return -EINVAL;
+ }
+
+ f->chain_fence =
+ kmalloc(sizeof(*f->chain_fence),
+ GFP_KERNEL);
+ if (!f->chain_fence) {
+ drm_syncobj_put(syncobj);
+ dma_fence_put(fence);
+ return -ENOMEM;
+ }
+ } else {
+ f->chain_fence = NULL;
+ }
+
+ f->syncobj = ptr_pack_bits(syncobj, user_fence.flags, 2);
+ f->dma_fence = fence;
+ f->value = point;
+ f++;
+ eb->num_fences++;
+ }
+
+ return 0;
+}
+
+static int add_fence_array(struct i915_execbuffer *eb)
+{
+ struct drm_i915_gem_execbuffer2 *args = eb->args;
+ struct drm_i915_gem_exec_fence __user *user;
+ unsigned long num_fences = args->num_cliprects;
+ struct eb_fence *f;
+
+ if (!(args->flags & I915_EXEC_FENCE_ARRAY))
+ return 0;
+
+ if (!num_fences)
+ return 0;
+
+ /* Check multiplication overflow for access_ok() and kvmalloc_array() */
+ BUILD_BUG_ON(sizeof(size_t) > sizeof(unsigned long));
+ if (num_fences > min_t(unsigned long,
+ ULONG_MAX / sizeof(*user),
+ SIZE_MAX / sizeof(*f) - eb->num_fences))
+ return -EINVAL;
+
+ user = u64_to_user_ptr(args->cliprects_ptr);
+ if (!access_ok(user, num_fences * sizeof(*user)))
+ return -EFAULT;
+
+ f = krealloc(eb->fences,
+ (eb->num_fences + num_fences) * sizeof(*f),
+ __GFP_NOWARN | GFP_KERNEL);
+ if (!f)
+ return -ENOMEM;
+
+ eb->fences = f;
+ f += eb->num_fences;
+ while (num_fences--) {
+ struct drm_i915_gem_exec_fence user_fence;
+ struct drm_syncobj *syncobj;
+ struct dma_fence *fence = NULL;
+
+ if (__copy_from_user(&user_fence, user++, sizeof(user_fence)))
+ return -EFAULT;
+
+ if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS)
+ return -EINVAL;
+
+ syncobj = drm_syncobj_find(eb->file, user_fence.handle);
if (!syncobj) {
DRM_DEBUG("Invalid syncobj handle provided\n");
- err = -ENOENT;
- goto err;
+ return -ENOENT;
+ }
+
+ if (user_fence.flags & I915_EXEC_FENCE_WAIT) {
+ fence = drm_syncobj_fence_get(syncobj);
+ if (!fence) {
+ DRM_DEBUG("Syncobj handle has no fence\n");
+ drm_syncobj_put(syncobj);
+ return -EINVAL;
+ }
}
BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) &
~__I915_EXEC_FENCE_UNKNOWN_FLAGS);
- fences[n] = ptr_pack_bits(syncobj, fence.flags, 2);
+ f->syncobj = ptr_pack_bits(syncobj, user_fence.flags, 2);
+ f->dma_fence = fence;
+ f->value = 0;
+ f->chain_fence = NULL;
+ f++;
+ eb->num_fences++;
}
- return fences;
-
-err:
- __free_fence_array(fences, n);
- return ERR_PTR(err);
+ return 0;
}
-static void
-put_fence_array(struct drm_i915_gem_execbuffer2 *args,
- struct drm_syncobj **fences)
+static void put_fence_array(struct eb_fence *fences, int num_fences)
{
if (fences)
- __free_fence_array(fences, args->num_cliprects);
+ __free_fence_array(fences, num_fences);
}
static int
-await_fence_array(struct i915_execbuffer *eb,
- struct drm_syncobj **fences)
+await_fence_array(struct i915_execbuffer *eb)
{
- const unsigned int nfences = eb->args->num_cliprects;
unsigned int n;
int err;
- for (n = 0; n < nfences; n++) {
+ for (n = 0; n < eb->num_fences; n++) {
struct drm_syncobj *syncobj;
- struct dma_fence *fence;
unsigned int flags;
- syncobj = ptr_unpack_bits(fences[n], &flags, 2);
- if (!(flags & I915_EXEC_FENCE_WAIT))
- continue;
+ syncobj = ptr_unpack_bits(eb->fences[n].syncobj, &flags, 2);
- fence = drm_syncobj_fence_get(syncobj);
- if (!fence)
- return -EINVAL;
+ if (!eb->fences[n].dma_fence)
+ continue;
- err = i915_request_await_dma_fence(eb->request, fence);
- dma_fence_put(fence);
+ err = i915_request_await_dma_fence(eb->request,
+ eb->fences[n].dma_fence);
if (err < 0)
return err;
}
@@ -2309,26 +2455,47 @@ await_fence_array(struct i915_execbuffer *eb,
return 0;
}
-static void
-signal_fence_array(struct i915_execbuffer *eb,
- struct drm_syncobj **fences)
+static void signal_fence_array(const struct i915_execbuffer *eb)
{
- const unsigned int nfences = eb->args->num_cliprects;
struct dma_fence * const fence = &eb->request->fence;
unsigned int n;
- for (n = 0; n < nfences; n++) {
+ for (n = 0; n < eb->num_fences; n++) {
struct drm_syncobj *syncobj;
unsigned int flags;
- syncobj = ptr_unpack_bits(fences[n], &flags, 2);
+ syncobj = ptr_unpack_bits(eb->fences[n].syncobj, &flags, 2);
if (!(flags & I915_EXEC_FENCE_SIGNAL))
continue;
- drm_syncobj_replace_fence(syncobj, fence);
+ if (eb->fences[n].chain_fence) {
+ drm_syncobj_add_point(syncobj,
+ eb->fences[n].chain_fence,
+ fence,
+ eb->fences[n].value);
+ /*
+ * The chain's ownership is transferred to the
+ * timeline.
+ */
+ eb->fences[n].chain_fence = NULL;
+ } else {
+ drm_syncobj_replace_fence(syncobj, fence);
+ }
}
}
+static int
+parse_timeline_fences(struct i915_user_extension __user *ext, void *data)
+{
+ struct i915_execbuffer *eb = data;
+ struct drm_i915_gem_execbuffer_ext_timeline_fences timeline_fences;
+
+ if (copy_from_user(&timeline_fences, ext, sizeof(timeline_fences)))
+ return -EFAULT;
+
+ return add_timeline_fence_array(eb, &timeline_fences);
+}
+
static void retire_requests(struct intel_timeline *tl, struct i915_request *end)
{
struct i915_request *rq, *rn;
@@ -2370,12 +2537,37 @@ static void eb_request_add(struct i915_execbuffer *eb)
mutex_unlock(&tl->mutex);
}
+static const i915_user_extension_fn execbuf_extensions[] = {
+ [DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES] = parse_timeline_fences,
+};
+
+static int
+parse_execbuf2_extensions(struct drm_i915_gem_execbuffer2 *args,
+ struct i915_execbuffer *eb)
+{
+ if (!(args->flags & I915_EXEC_USE_EXTENSIONS))
+ return 0;
+
+ /* The execbuf2 extension mechanism reuses cliprects_ptr. So we cannot
+ * have another flag also using it at the same time.
+ */
+ if (eb->args->flags & I915_EXEC_FENCE_ARRAY)
+ return -EINVAL;
+
+ if (args->num_cliprects != 0)
+ return -EINVAL;
+
+ return i915_user_extensions(u64_to_user_ptr(args->cliprects_ptr),
+ execbuf_extensions,
+ ARRAY_SIZE(execbuf_extensions),
+ eb);
+}
+
static int
i915_gem_do_execbuffer(struct drm_device *dev,
struct drm_file *file,
struct drm_i915_gem_execbuffer2 *args,
- struct drm_i915_gem_exec_object2 *exec,
- struct drm_syncobj **fences)
+ struct drm_i915_gem_exec_object2 *exec)
{
struct drm_i915_private *i915 = to_i915(dev);
struct i915_execbuffer eb;
@@ -2405,6 +2597,9 @@ i915_gem_do_execbuffer(struct drm_device *dev,
eb.batch_len = args->batch_len;
eb.trampoline = NULL;
+ eb.fences = NULL;
+ eb.num_fences = 0;
+
eb.batch_flags = 0;
if (args->flags & I915_EXEC_SECURE) {
if (INTEL_GEN(i915) >= 11)
@@ -2422,14 +2617,24 @@ i915_gem_do_execbuffer(struct drm_device *dev,
if (args->flags & I915_EXEC_IS_PINNED)
eb.batch_flags |= I915_DISPATCH_PINNED;
+ err = parse_execbuf2_extensions(args, &eb);
+ if (err)
+ goto err_ext;
+
+ err = add_fence_array(&eb);
+ if (err)
+ goto err_ext;
+
#define IN_FENCES (I915_EXEC_FENCE_IN | I915_EXEC_FENCE_SUBMIT)
if (args->flags & IN_FENCES) {
if ((args->flags & IN_FENCES) == IN_FENCES)
return -EINVAL;
in_fence = sync_file_get_fence(lower_32_bits(args->rsvd2));
- if (!in_fence)
- return -EINVAL;
+ if (!in_fence) {
+ err = -EINVAL;
+ goto err_ext;
+ }
}
#undef IN_FENCES
@@ -2539,8 +2744,8 @@ i915_gem_do_execbuffer(struct drm_device *dev,
goto err_request;
}
- if (fences) {
- err = await_fence_array(&eb, fences);
+ if (eb.fences) {
+ err = await_fence_array(&eb);
if (err)
goto err_request;
}
@@ -2571,8 +2776,8 @@ err_request:
i915_request_get(eb.request);
eb_request_add(&eb);
- if (fences)
- signal_fence_array(&eb, fences);
+ if (eb.fences)
+ signal_fence_array(&eb);
if (out_fence) {
if (err == 0) {
@@ -2605,6 +2810,8 @@ err_out_fence:
put_unused_fd(out_fence_fd);
err_in_fence:
dma_fence_put(in_fence);
+err_ext:
+ put_fence_array(eb.fences, eb.num_fences);
return err;
}
@@ -2699,7 +2906,7 @@ i915_gem_execbuffer_ioctl(struct drm_device *dev, void *data,
exec2_list[i].flags = 0;
}
- err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list, NULL);
+ err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list);
if (exec2.flags & __EXEC_HAS_RELOC) {
struct drm_i915_gem_exec_object __user *user_exec_list =
u64_to_user_ptr(args->buffers_ptr);
@@ -2731,7 +2938,6 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
struct drm_i915_private *i915 = to_i915(dev);
struct drm_i915_gem_execbuffer2 *args = data;
struct drm_i915_gem_exec_object2 *exec2_list;
- struct drm_syncobj **fences = NULL;
const size_t count = args->buffer_count;
int err;
@@ -2759,15 +2965,7 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
return -EFAULT;
}
- if (args->flags & I915_EXEC_FENCE_ARRAY) {
- fences = get_fence_array(args, file);
- if (IS_ERR(fences)) {
- kvfree(exec2_list);
- return PTR_ERR(fences);
- }
- }
-
- err = i915_gem_do_execbuffer(dev, file, args, exec2_list, fences);
+ err = i915_gem_do_execbuffer(dev, file, args, exec2_list);
/*
* Now that we have begun execution of the batchbuffer, we ignore
@@ -2808,7 +3006,6 @@ end:;
}
args->flags &= ~__I915_EXEC_UNKNOWN_FLAGS;
- put_fence_array(args, fences);
kvfree(exec2_list);
return err;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index 24322ef08aa4..d03da2f64a49 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -4555,7 +4555,7 @@ static int gen8_emit_flush_render(struct i915_request *request,
vf_flush_wa = true;
/* WaForGAMHang:kbl */
- if (IS_KBL_REVID(request->engine->i915, 0, KBL_REVID_B0))
+ if (IS_KBL_GT_REVID(request->engine->i915, 0, KBL_REVID_B0))
dc_flush_wa = true;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c
index 5726cd0a37e0..be5a4685c991 100644
--- a/drivers/gpu/drm/i915/gt/intel_workarounds.c
+++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c
@@ -52,6 +52,24 @@
* - Public functions to init or apply the given workaround type.
*/
+/*
+ * KBL revision ID ordering is bizarre; higher revision ID's map to lower
+ * steppings in some cases. So rather than test against the revision ID
+ * directly, let's map that into our own range of increasing ID's that we
+ * can test against in a regular manner.
+ */
+
+const struct i915_rev_steppings kbl_revids[] = {
+ [0] = { .gt_stepping = KBL_REVID_A0, .disp_stepping = KBL_REVID_A0 },
+ [1] = { .gt_stepping = KBL_REVID_B0, .disp_stepping = KBL_REVID_B0 },
+ [2] = { .gt_stepping = KBL_REVID_C0, .disp_stepping = KBL_REVID_B0 },
+ [3] = { .gt_stepping = KBL_REVID_D0, .disp_stepping = KBL_REVID_B0 },
+ [4] = { .gt_stepping = KBL_REVID_F0, .disp_stepping = KBL_REVID_C0 },
+ [5] = { .gt_stepping = KBL_REVID_C0, .disp_stepping = KBL_REVID_B1 },
+ [6] = { .gt_stepping = KBL_REVID_D1, .disp_stepping = KBL_REVID_B1 },
+ [7] = { .gt_stepping = KBL_REVID_G0, .disp_stepping = KBL_REVID_C0 },
+};
+
static void wa_init_start(struct i915_wa_list *wal, const char *name, const char *engine_name)
{
wal->name = name;
@@ -470,7 +488,7 @@ static void kbl_ctx_workarounds_init(struct intel_engine_cs *engine,
gen9_ctx_workarounds_init(engine, wal);
/* WaToEnableHwFixForPushConstHWBug:kbl */
- if (IS_KBL_REVID(i915, KBL_REVID_C0, REVID_FOREVER))
+ if (IS_KBL_GT_REVID(i915, KBL_REVID_C0, REVID_FOREVER))
WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
@@ -596,8 +614,8 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine,
wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN11_DIS_PICK_2ND_EU);
}
-static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine,
- struct i915_wa_list *wal)
+static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine,
+ struct i915_wa_list *wal)
{
/*
* Wa_1409142259:tgl
@@ -607,12 +625,28 @@ static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine,
* Wa_1409207793:tgl
* Wa_1409178076:tgl
* Wa_1408979724:tgl
+ * Wa_14010443199:rkl
+ * Wa_14010698770:rkl
*/
WA_SET_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3,
GEN12_DISABLE_CPS_AWARE_COLOR_PIPE);
+ /* WaDisableGPGPUMidThreadPreemption:gen12 */
+ WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1,
+ GEN9_PREEMPT_GPGPU_LEVEL_MASK,
+ GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL);
+}
+
+static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine,
+ struct i915_wa_list *wal)
+{
+ gen12_ctx_workarounds_init(engine, wal);
+
/*
- * Wa_1604555607:gen12 and Wa_1608008084:gen12
+ * Wa_1604555607:tgl,rkl
+ *
+ * Note that the implementation of this workaround is further modified
+ * according to the FF_MODE2 guidance given by Wa_1608008084:gen12.
* FF_MODE2 register will return the wrong value when read. The default
* value for this register is zero for all fields and there are no bit
* masks. So instead of doing a RMW we should just write the GS Timer
@@ -623,11 +657,6 @@ static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine,
FF_MODE2_GS_TIMER_MASK | FF_MODE2_TDS_TIMER_MASK,
FF_MODE2_GS_TIMER_224 | FF_MODE2_TDS_TIMER_128,
0);
-
- /* WaDisableGPGPUMidThreadPreemption:tgl */
- WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1,
- GEN9_PREEMPT_GPGPU_LEVEL_MASK,
- GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL);
}
static void
@@ -642,8 +671,10 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine,
wa_init_start(wal, name, engine->name);
- if (IS_GEN(i915, 12))
+ if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915))
tgl_ctx_workarounds_init(engine, wal);
+ else if (IS_GEN(i915, 12))
+ gen12_ctx_workarounds_init(engine, wal);
else if (IS_GEN(i915, 11))
icl_ctx_workarounds_init(engine, wal);
else if (IS_CANNONLAKE(i915))
@@ -995,7 +1026,7 @@ kbl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
gen9_gt_workarounds_init(i915, wal);
/* WaDisableDynamicCreditSharing:kbl */
- if (IS_KBL_REVID(i915, 0, KBL_REVID_B0))
+ if (IS_KBL_GT_REVID(i915, 0, KBL_REVID_B0))
wa_write_or(wal,
GAMT_CHKN_BIT_REG,
GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING);
@@ -1176,9 +1207,16 @@ icl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
}
static void
-tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
+gen12_gt_workarounds_init(struct drm_i915_private *i915,
+ struct i915_wa_list *wal)
{
wa_init_mcr(i915, wal);
+}
+
+static void
+tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
+{
+ gen12_gt_workarounds_init(i915, wal);
/* Wa_1409420604:tgl */
if (IS_TGL_REVID(i915, TGL_REVID_A0, TGL_REVID_A0))
@@ -1196,8 +1234,10 @@ tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
static void
gt_init_workarounds(struct drm_i915_private *i915, struct i915_wa_list *wal)
{
- if (IS_GEN(i915, 12))
+ if (IS_TIGERLAKE(i915))
tgl_gt_workarounds_init(i915, wal);
+ else if (IS_GEN(i915, 12))
+ gen12_gt_workarounds_init(i915, wal);
else if (IS_GEN(i915, 11))
icl_gt_workarounds_init(i915, wal);
else if (IS_CANNONLAKE(i915))
@@ -1630,18 +1670,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
GEN12_DISABLE_POSH_BUSY_FF_DOP_CG);
/*
- * Wa_1607030317:tgl
- * Wa_1607186500:tgl
- * Wa_1607297627:tgl there is 3 entries for this WA on BSpec, 2
- * of then says it is fixed on B0 the other one says it is
- * permanent
- */
- wa_masked_en(wal,
- GEN6_RC_SLEEP_PSMI_CONTROL,
- GEN12_WAIT_FOR_EVENT_POWER_DOWN_DISABLE |
- GEN8_RC_SEMA_IDLE_MSG_DISABLE);
-
- /*
* Wa_1606679103:tgl
* (see also Wa_1606682166:icl)
*/
@@ -1654,22 +1682,17 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
VSUNIT_CLKGATE_DIS_TGL);
}
- if (IS_TIGERLAKE(i915)) {
- /* Wa_1606931601:tgl */
+ if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) {
+ /* Wa_1606931601:tgl,rkl */
wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ);
- /* Wa_1409804808:tgl */
+ /* Wa_1409804808:tgl,rkl */
wa_masked_en(wal, GEN7_ROW_CHICKEN2,
GEN12_PUSH_CONST_DEREF_HOLD_DIS);
- /* Wa_1606700617:tgl */
- wa_masked_en(wal,
- GEN9_CS_DEBUG_MODE1,
- FF_DOP_CLOCK_GATE_DISABLE);
-
/*
* Wa_1409085225:tgl
- * Wa_14010229206:tgl
+ * Wa_14010229206:tgl,rkl
*/
wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH);
@@ -1677,9 +1700,29 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
* Wa_1407928979:tgl A*
* Wa_18011464164:tgl B0+
* Wa_22010931296:tgl B0+
+ * Wa_14010919138:rkl
*/
wa_write_or(wal, GEN7_FF_THREAD_MODE,
GEN12_FF_TESSELATION_DOP_GATE_DISABLE);
+
+ /*
+ * Wa_1607030317:tgl
+ * Wa_1607186500:tgl
+ * Wa_1607297627:tgl,rkl there are multiple entries for this
+ * WA in the BSpec; some indicate this is an A0-only WA,
+ * others indicate it applies to all steppings.
+ */
+ wa_masked_en(wal,
+ GEN6_RC_SLEEP_PSMI_CONTROL,
+ GEN12_WAIT_FOR_EVENT_POWER_DOWN_DISABLE |
+ GEN8_RC_SEMA_IDLE_MSG_DISABLE);
+ }
+
+ if (IS_TIGERLAKE(i915)) {
+ /* Wa_1606700617:tgl */
+ wa_masked_en(wal,
+ GEN9_CS_DEBUG_MODE1,
+ FF_DOP_CLOCK_GATE_DISABLE);
}
if (IS_GEN(i915, 11)) {
@@ -1898,7 +1941,7 @@ xcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
struct drm_i915_private *i915 = engine->i915;
/* WaKBLVECSSemaphoreWaitPoll:kbl */
- if (IS_KBL_REVID(i915, KBL_REVID_A0, KBL_REVID_E0)) {
+ if (IS_KBL_GT_REVID(i915, KBL_REVID_A0, KBL_REVID_E0)) {
wa_write(wal,
RING_SEMA_WAIT_POLL(engine->mmio_base),
1);
diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c
index 73243ba59c7d..e73854dd2fe0 100644
--- a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c
+++ b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c
@@ -47,7 +47,10 @@ static int pulse_active(struct i915_active *active)
static void pulse_free(struct kref *kref)
{
- kfree(container_of(kref, struct pulse, kref));
+ struct pulse *p = container_of(kref, typeof(*p), kref);
+
+ i915_active_fini(&p->active);
+ kfree(p);
}
static void pulse_put(struct pulse *p)
diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c
index 8624f5d2a1f3..34b403d47840 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rps.c
+++ b/drivers/gpu/drm/i915/gt/selftest_rps.c
@@ -700,7 +700,7 @@ int live_rps_frequency_cs(void *arg)
f = act; /* may skip ahead [pcu granularity] */
}
- err = -EINVAL;
+ err = -EINTR; /* ignore error, continue on with test */
}
err_vma:
@@ -841,7 +841,7 @@ int live_rps_frequency_srm(void *arg)
f = act; /* may skip ahead [pcu granularity] */
}
- err = -EINVAL;
+ err = -EINTR; /* ignore error, continue on with test */
}
err_vma:
diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c
index fb5b7d3498a6..6564c989dbee 100644
--- a/drivers/gpu/drm/i915/gt/selftest_timeline.c
+++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c
@@ -491,7 +491,7 @@ checked_intel_timeline_create(struct intel_gt *gt)
if (IS_ERR(tl))
return tl;
- if (*tl->hwsp_seqno != tl->seqno) {
+ if (READ_ONCE(*tl->hwsp_seqno) != tl->seqno) {
pr_err("Timeline created with incorrect breadcrumb, found %x, expected %x\n",
*tl->hwsp_seqno, tl->seqno);
intel_timeline_put(tl);
@@ -561,9 +561,9 @@ static int live_hwsp_engine(void *arg)
for (n = 0; n < count; n++) {
struct intel_timeline *tl = timelines[n];
- if (!err && *tl->hwsp_seqno != n) {
- pr_err("Invalid seqno stored in timeline %lu @ %x, found 0x%x\n",
- n, tl->hwsp_offset, *tl->hwsp_seqno);
+ if (!err && READ_ONCE(*tl->hwsp_seqno) != n) {
+ GEM_TRACE_ERR("Invalid seqno:%lu stored in timeline %llu @ %x, found 0x%x\n",
+ n, tl->fence_context, tl->hwsp_offset, *tl->hwsp_seqno);
GEM_TRACE_DUMP();
err = -EINVAL;
}
@@ -633,9 +633,9 @@ out:
for (n = 0; n < count; n++) {
struct intel_timeline *tl = timelines[n];
- if (!err && *tl->hwsp_seqno != n) {
- pr_err("Invalid seqno stored in timeline %lu @ %x, found 0x%x\n",
- n, tl->hwsp_offset, *tl->hwsp_seqno);
+ if (!err && READ_ONCE(*tl->hwsp_seqno) != n) {
+ GEM_TRACE_ERR("Invalid seqno:%lu stored in timeline %llu @ %x, found 0x%x\n",
+ n, tl->fence_context, tl->hwsp_offset, *tl->hwsp_seqno);
GEM_TRACE_DUMP();
err = -EINVAL;
}
@@ -733,7 +733,8 @@ static int live_hwsp_wrap(void *arg)
goto out;
}
- if (*hwsp_seqno[0] != seqno[0] || *hwsp_seqno[1] != seqno[1]) {
+ if (READ_ONCE(*hwsp_seqno[0]) != seqno[0] ||
+ READ_ONCE(*hwsp_seqno[1]) != seqno[1]) {
pr_err("Bad timeline values: found (%x, %x), expected (%x, %x)\n",
*hwsp_seqno[0], *hwsp_seqno[1],
seqno[0], seqno[1]);
@@ -966,9 +967,10 @@ static int live_hwsp_recycle(void *arg)
break;
}
- if (*tl->hwsp_seqno != count) {
- pr_err("Invalid seqno stored in timeline %lu @ tl->hwsp_offset, found 0x%x\n",
- count, *tl->hwsp_seqno);
+ if (READ_ONCE(*tl->hwsp_seqno) != count) {
+ GEM_TRACE_ERR("Invalid seqno:%lu stored in timeline %llu @ %x found 0x%x\n",
+ count, tl->fence_context,
+ tl->hwsp_offset, *tl->hwsp_seqno);
GEM_TRACE_DUMP();
err = -EINVAL;
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
index 59b27aba15c6..80e8b6c3bc8c 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
@@ -51,8 +51,8 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
* Note that RKL uses the same firmware as TGL.
*/
#define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \
- fw_def(ROCKETLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 0, 12)) \
- fw_def(TIGERLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 0, 12)) \
+ fw_def(ROCKETLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \
+ fw_def(TIGERLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \
fw_def(ELKHARTLAKE, 0, guc_def(ehl, 33, 0, 4), huc_def(ehl, 9, 0, 0)) \
fw_def(ICELAKE, 0, guc_def(icl, 33, 0, 0), huc_def(icl, 9, 0, 0)) \
fw_def(COMETLAKE, 5, guc_def(cml, 33, 0, 0), huc_def(cml, 4, 0, 0)) \
diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c
index d960d0be5bd2..1e1253207425 100644
--- a/drivers/gpu/drm/i915/i915_active.c
+++ b/drivers/gpu/drm/i915/i915_active.c
@@ -758,7 +758,6 @@ int i915_active_acquire_preallocate_barrier(struct i915_active *ref,
intel_engine_mask_t tmp, mask = engine->mask;
struct llist_node *first = NULL, *last = NULL;
struct intel_gt *gt = engine->gt;
- int err;
GEM_BUG_ON(i915_active_is_idle(ref));
@@ -781,10 +780,8 @@ int i915_active_acquire_preallocate_barrier(struct i915_active *ref,
node = reuse_idle_barrier(ref, idx);
if (!node) {
node = kmem_cache_alloc(global.slab_cache, GFP_KERNEL);
- if (!node) {
- err = ENOMEM;
+ if (!node)
goto unwind;
- }
RCU_INIT_POINTER(node->base.fence, NULL);
node->base.cb.func = node_retire;
@@ -832,7 +829,7 @@ unwind:
kmem_cache_free(global.slab_cache, node);
}
- return err;
+ return -ENOMEM;
}
void i915_active_acquire_barrier(struct i915_active *ref)
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 5fd5af4bc855..e6918c7c0709 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -392,7 +392,7 @@ static void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv)
pre |= IS_HSW_EARLY_SDV(dev_priv);
pre |= IS_SKL_REVID(dev_priv, 0, SKL_REVID_F0);
pre |= IS_BXT_REVID(dev_priv, 0, BXT_REVID_B_LAST);
- pre |= IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0);
+ pre |= IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_A0);
pre |= IS_GLK_REVID(dev_priv, 0, GLK_REVID_A2);
if (pre) {
@@ -1846,7 +1846,8 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_GEM |
- DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ,
+ DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ |
+ DRIVER_SYNCOBJ_TIMELINE,
.release = i915_driver_release,
.open = i915_driver_open,
.lastclose = i915_driver_lastclose,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e4f7f6518945..1314e0e92c41 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -108,8 +108,8 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20200715"
-#define DRIVER_TIMESTAMP 1594811881
+#define DRIVER_DATE "20200824"
+#define DRIVER_TIMESTAMP 1598293597
struct drm_i915_gem_object;
@@ -506,6 +506,7 @@ struct i915_psr {
bool link_standby;
bool colorimetry_support;
bool psr2_enabled;
+ bool psr2_sel_fetch_enabled;
u8 sink_sync_latency;
ktime_t last_entry_attempt;
ktime_t last_exit;
@@ -1045,6 +1046,14 @@ struct drm_i915_private {
struct intel_l3_parity l3_parity;
/*
+ * HTI (aka HDPORT) state read during initial hw readout. Most
+ * platforms don't have HTI, so this will just stay 0. Those that do
+ * will use this later to figure out which PLLs and PHYs are unavailable
+ * for driver usage.
+ */
+ u32 hti_state;
+
+ /*
* edram size in MB.
* Cannot be determined by PCIID. You must always read a register.
*/
@@ -1489,6 +1498,12 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define IS_ICL_WITH_PORT_F(dev_priv) \
IS_SUBPLATFORM(dev_priv, INTEL_ICELAKE, INTEL_SUBPLATFORM_PORTF)
+#define IS_TGL_U(dev_priv) \
+ IS_SUBPLATFORM(dev_priv, INTEL_TIGERLAKE, INTEL_SUBPLATFORM_ULT)
+
+#define IS_TGL_Y(dev_priv) \
+ IS_SUBPLATFORM(dev_priv, INTEL_TIGERLAKE, INTEL_SUBPLATFORM_ULX)
+
#define SKL_REVID_A0 0x0
#define SKL_REVID_B0 0x1
#define SKL_REVID_C0 0x2
@@ -1509,14 +1524,34 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define IS_BXT_REVID(dev_priv, since, until) \
(IS_BROXTON(dev_priv) && IS_REVID(dev_priv, since, until))
-#define KBL_REVID_A0 0x0
-#define KBL_REVID_B0 0x1
-#define KBL_REVID_C0 0x2
-#define KBL_REVID_D0 0x3
-#define KBL_REVID_E0 0x4
+enum {
+ KBL_REVID_A0,
+ KBL_REVID_B0,
+ KBL_REVID_B1,
+ KBL_REVID_C0,
+ KBL_REVID_D0,
+ KBL_REVID_D1,
+ KBL_REVID_E0,
+ KBL_REVID_F0,
+ KBL_REVID_G0,
+};
+
+struct i915_rev_steppings {
+ u8 gt_stepping;
+ u8 disp_stepping;
+};
+
+/* Defined in intel_workarounds.c */
+extern const struct i915_rev_steppings kbl_revids[];
-#define IS_KBL_REVID(dev_priv, since, until) \
- (IS_KABYLAKE(dev_priv) && IS_REVID(dev_priv, since, until))
+#define IS_KBL_GT_REVID(dev_priv, since, until) \
+ (IS_KABYLAKE(dev_priv) && \
+ kbl_revids[INTEL_REVID(dev_priv)].gt_stepping >= since && \
+ kbl_revids[INTEL_REVID(dev_priv)].gt_stepping <= until)
+#define IS_KBL_DISP_REVID(dev_priv, since, until) \
+ (IS_KABYLAKE(dev_priv) && \
+ kbl_revids[INTEL_REVID(dev_priv)].disp_stepping >= since && \
+ kbl_revids[INTEL_REVID(dev_priv)].disp_stepping <= until)
#define GLK_REVID_A0 0x0
#define GLK_REVID_A1 0x1
@@ -1665,6 +1700,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_PSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_psr)
#define HAS_PSR_HW_TRACKING(dev_priv) \
(INTEL_INFO(dev_priv)->display.has_psr_hw_tracking)
+#define HAS_PSR2_SEL_FETCH(dev_priv) (INTEL_GEN(dev_priv) >= 12)
#define HAS_TRANSCODER(dev_priv, trans) ((INTEL_INFO(dev_priv)->cpu_transcoder_mask & BIT(trans)) != 0)
#define HAS_RC6(dev_priv) (INTEL_INFO(dev_priv)->has_rc6)
diff --git a/drivers/gpu/drm/i915/i915_getparam.c b/drivers/gpu/drm/i915/i915_getparam.c
index 421613219ae9..f96032c60a12 100644
--- a/drivers/gpu/drm/i915/i915_getparam.c
+++ b/drivers/gpu/drm/i915/i915_getparam.c
@@ -132,6 +132,7 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data,
case I915_PARAM_HAS_EXEC_BATCH_FIRST:
case I915_PARAM_HAS_EXEC_FENCE_ARRAY:
case I915_PARAM_HAS_EXEC_SUBMIT_FENCE:
+ case I915_PARAM_HAS_EXEC_TIMELINE_FENCES:
/* For the time being all of these are always true;
* if some supported hardware does not have one of these
* features this value needs to be provided from
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 8d8db9ff0a48..7f139ea4a90b 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -102,6 +102,11 @@ i915_param_named(psr_safest_params, bool, 0400,
"is helpful to detect if PSR issues are related to bad values set in "
" VBT. (0=use VBT parameters, 1=use safest parameters)");
+i915_param_named_unsafe(enable_psr2_sel_fetch, bool, 0400,
+ "Enable PSR2 selective fetch "
+ "(0=disabled, 1=enabled) "
+ "Default: 0");
+
i915_param_named_unsafe(force_probe, charp, 0400,
"Force probe the driver for specified devices. "
"See CONFIG_DRM_I915_FORCE_PROBE for details.");
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index 53fb5ba8fbed..330c03e2b4f7 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -54,6 +54,7 @@ struct drm_printer;
param(int, enable_fbc, -1, 0600) \
param(int, enable_psr, -1, 0600) \
param(bool, psr_safest_params, false, 0600) \
+ param(bool, enable_psr2_sel_fetch, false, 0600) \
param(int, disable_power_well, -1, 0400) \
param(int, enable_ips, 1, 0600) \
param(int, invert_brightness, 0, 0600) \
diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
index 2338f92ce490..366ddfc8df6b 100644
--- a/drivers/gpu/drm/i915/i915_pci.c
+++ b/drivers/gpu/drm/i915/i915_pci.c
@@ -890,6 +890,7 @@ static const struct intel_device_info rkl_info = {
.cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) |
BIT(TRANSCODER_C),
.require_force_probe = 1,
+ .display.has_hti = 1,
.display.has_psr_hw_tracking = 0,
.platform_engine_mask =
BIT(RCS0) | BIT(BCS0) | BIT(VECS0) | BIT(VCS0),
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 4e796ff4d7d0..ac691927e29d 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1898,6 +1898,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define PWR_DOWN_LN_3_1_0 (0xb << 4)
#define PWR_DOWN_LN_MASK (0xf << 4)
#define PWR_DOWN_LN_SHIFT 4
+#define EDP4K2K_MODE_OVRD_EN (1 << 3)
+#define EDP4K2K_MODE_OVRD_OPTIMIZED (1 << 2)
#define ICL_PORT_CL_DW12(phy) _MMIO(_ICL_PORT_CL_DW(12, phy))
#define ICL_LANE_ENABLE_AUX (1 << 0)
@@ -2919,6 +2921,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define MBUS_BBOX_CTL_S1 _MMIO(0x45040)
#define MBUS_BBOX_CTL_S2 _MMIO(0x45044)
+#define HDPORT_STATE _MMIO(0x45050)
+#define HDPORT_DPLL_USED_MASK REG_GENMASK(14, 12)
+#define HDPORT_PHY_USED_DP(phy) REG_BIT(2 * (phy) + 2)
+#define HDPORT_PHY_USED_HDMI(phy) REG_BIT(2 * (phy) + 1)
+#define HDPORT_ENABLED REG_BIT(0)
+
/* Make render/texture TLB fetches lower priorty than associated data
* fetches. This is not turned on by default
*/
@@ -7870,6 +7878,7 @@ enum {
# define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2)
#define CHICKEN_PAR1_1 _MMIO(0x42080)
+#define DIS_RAM_BYPASS_PSR2_MAN_TRACK (1 << 16)
#define SKL_DE_COMPRESSED_HASH_MODE (1 << 15)
#define DPA_MASK_VBLANK_SRD (1 << 15)
#define FORCE_ARB_IDLE_PLANES (1 << 14)
@@ -8711,6 +8720,7 @@ enum {
#define PCH_GMBUSUNIT_CLOCK_GATE_DISABLE (1 << 31)
#define PCH_DPLUNIT_CLOCK_GATE_DISABLE (1 << 30)
#define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1 << 29)
+#define PCH_DPMGUNIT_CLOCK_GATE_DISABLE (1 << 15)
#define PCH_CPUNIT_CLOCK_GATE_DISABLE (1 << 14)
#define CNP_PWM_CGE_GATING_DISABLE (1 << 13)
#define PCH_LP_PARTITION_LEVEL_DISABLE (1 << 12)
@@ -9217,8 +9227,8 @@ enum {
#define DISPLAY_IPS_CONTROL 0x19
#define TGL_PCODE_TCCOLD 0x26
#define TGL_PCODE_EXIT_TCCOLD_DATA_L_EXIT_FAILED REG_BIT(0)
-#define TGL_PCODE_EXIT_TCCOLD_DATA_H_BLOCK_REQ 0
-#define TGL_PCODE_EXIT_TCCOLD_DATA_H_UNBLOCK_REQ REG_BIT(0)
+#define TGL_PCODE_EXIT_TCCOLD_DATA_L_BLOCK_REQ 0
+#define TGL_PCODE_EXIT_TCCOLD_DATA_L_UNBLOCK_REQ REG_BIT(0)
/* See also IPS_CTL */
#define IPS_PCODE_CONTROL (1 << 30)
#define HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL 0x1A
@@ -10277,12 +10287,18 @@ enum skl_power_gate {
#define ICL_DPCLKA_CFGCR0 _MMIO(0x164280)
#define ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) (1 << _PICK(phy, 10, 11, 24))
+#define RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) REG_BIT((phy) + 10)
#define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < PORT_TC4 ? \
(tc_port) + 12 : \
(tc_port) - PORT_TC4 + 21))
#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) ((phy) * 2)
#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (3 << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
#define ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) ((pll) << ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
+#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) _PICK(phy, 0, 2, 4, 27)
+#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) \
+ (3 << RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
+#define RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) \
+ ((pll) << RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy))
/* CNL PLL */
#define DPLL0_ENABLE 0x46010
@@ -10503,19 +10519,21 @@ enum skl_power_gate {
#define _TGL_DPLL0_CFGCR0 0x164284
#define _TGL_DPLL1_CFGCR0 0x16428C
-/* TODO: add DPLL4 */
#define _TGL_TBTPLL_CFGCR0 0x16429C
#define TGL_DPLL_CFGCR0(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR0, \
_TGL_DPLL1_CFGCR0, \
_TGL_TBTPLL_CFGCR0)
+#define RKL_DPLL_CFGCR0(pll) _MMIO_PLL(pll, _TGL_DPLL0_CFGCR0, \
+ _TGL_DPLL1_CFGCR0)
#define _TGL_DPLL0_CFGCR1 0x164288
#define _TGL_DPLL1_CFGCR1 0x164290
-/* TODO: add DPLL4 */
#define _TGL_TBTPLL_CFGCR1 0x1642A0
#define TGL_DPLL_CFGCR1(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR1, \
_TGL_DPLL1_CFGCR1, \
_TGL_TBTPLL_CFGCR1)
+#define RKL_DPLL_CFGCR1(pll) _MMIO_PLL(pll, _TGL_DPLL0_CFGCR1, \
+ _TGL_DPLL1_CFGCR1)
#define _DKL_PHY1_BASE 0x168000
#define _DKL_PHY2_BASE 0x169000
@@ -12336,4 +12354,10 @@ enum skl_power_gate {
#define DSB_ENABLE (1 << 31)
#define DSB_STATUS (1 << 0)
+#define TGL_ROOT_DEVICE_ID 0x9A00
+#define TGL_ROOT_DEVICE_MASK 0xFF00
+#define TGL_ROOT_DEVICE_SKU_MASK 0xF
+#define TGL_ROOT_DEVICE_SKU_ULX 0x2
+#define TGL_ROOT_DEVICE_SKU_ULT 0x4
+
#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index 0b2fe55e6194..7a05850ca931 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -1783,11 +1783,8 @@ long i915_request_wait(struct i915_request *rq,
* but at a cost of spending more power processing the workload
* (bad for battery).
*/
- if (flags & I915_WAIT_PRIORITY) {
- if (!i915_request_started(rq) &&
- INTEL_GEN(rq->engine->i915) >= 6)
- intel_rps_boost(rq);
- }
+ if (flags & I915_WAIT_PRIORITY && !i915_request_started(rq))
+ intel_rps_boost(rq);
wait.tsk = current;
if (dma_fence_add_callback(&rq->fence, &wait.cb, request_wait_wake))
diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c
index 40c590db3c76..e2aa5bc3a6e0 100644
--- a/drivers/gpu/drm/i915/intel_device_info.c
+++ b/drivers/gpu/drm/i915/intel_device_info.c
@@ -346,6 +346,25 @@ void intel_device_info_subplatform_init(struct drm_i915_private *i915)
mask = BIT(INTEL_SUBPLATFORM_PORTF);
}
+ if (IS_TIGERLAKE(i915)) {
+ struct pci_dev *root, *pdev = i915->drm.pdev;
+
+ root = list_first_entry(&pdev->bus->devices, typeof(*root), bus_list);
+
+ drm_WARN_ON(&i915->drm, mask);
+ drm_WARN_ON(&i915->drm, (root->device & TGL_ROOT_DEVICE_MASK) !=
+ TGL_ROOT_DEVICE_ID);
+
+ switch (root->device & TGL_ROOT_DEVICE_SKU_MASK) {
+ case TGL_ROOT_DEVICE_SKU_ULX:
+ mask = BIT(INTEL_SUBPLATFORM_ULX);
+ break;
+ case TGL_ROOT_DEVICE_SKU_ULT:
+ mask = BIT(INTEL_SUBPLATFORM_ULT);
+ break;
+ }
+ }
+
GEM_BUG_ON(mask & ~INTEL_SUBPLATFORM_BITS);
RUNTIME_INFO(i915)->platform_mask[pi] |= mask;
diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h
index fd2385457ab6..6a3d607218aa 100644
--- a/drivers/gpu/drm/i915/intel_device_info.h
+++ b/drivers/gpu/drm/i915/intel_device_info.h
@@ -146,6 +146,7 @@ enum intel_ppgtt_type {
func(has_gmch); \
func(has_hdcp); \
func(has_hotplug); \
+ func(has_hti); \
func(has_ipc); \
func(has_modular_fia); \
func(has_overlay); \
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index cfabbe0481ab..b4bd19266b8c 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -100,12 +100,6 @@ static void gen9_init_clock_gating(struct drm_i915_private *dev_priv)
*/
I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
DISP_FBC_MEMORY_WAKE);
-
- if (IS_SKYLAKE(dev_priv)) {
- /* WaDisableDopClockGating */
- I915_WRITE(GEN7_MISCCPCTL, I915_READ(GEN7_MISCCPCTL)
- & ~GEN7_DOP_CLOCK_GATE_ENABLE);
- }
}
static void bxt_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -7223,12 +7217,12 @@ static void kbl_init_clock_gating(struct drm_i915_private *dev_priv)
gen9_init_clock_gating(dev_priv);
/* WaDisableSDEUnitClockGating:kbl */
- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
+ if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0))
I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
/* WaDisableGamClockGating:kbl */
- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
+ if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0))
I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) |
GEN6_GAMUNIT_CLOCK_GATE_DISABLE);
@@ -7251,6 +7245,10 @@ static void skl_init_clock_gating(struct drm_i915_private *dev_priv)
{
gen9_init_clock_gating(dev_priv);
+ /* WaDisableDopClockGating:skl */
+ I915_WRITE(GEN7_MISCCPCTL, I915_READ(GEN7_MISCCPCTL) &
+ ~GEN7_DOP_CLOCK_GATE_ENABLE);
+
/* WAC6entrylatency:skl */
I915_WRITE(FBC_LLC_READ_CTRL, I915_READ(FBC_LLC_READ_CTRL) |
FBC_LLC_FULLY_OPEN);
diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c
index 57dd6f5122ee..c1dcd4b91bda 100644
--- a/drivers/gpu/drm/i915/selftests/i915_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_request.c
@@ -331,7 +331,7 @@ static int __igt_breadcrumbs_smoketest(void *arg)
if (!wait) {
i915_sw_fence_commit(submit);
heap_fence_put(submit);
- err = ENOMEM;
+ err = -ENOMEM;
break;
}
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index 8791d60be92e..af757d1e21fe 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -455,13 +455,6 @@ static int imx_ldb_register(struct drm_device *drm,
drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder);
}
- if (imx_ldb_ch->panel) {
- ret = drm_panel_attach(imx_ldb_ch->panel,
- &imx_ldb_ch->connector);
- if (ret)
- return ret;
- }
-
return 0;
}
@@ -702,9 +695,6 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
for (i = 0; i < 2; i++) {
struct imx_ldb_channel *channel = &imx_ldb->channel[i];
- if (channel->panel)
- drm_panel_detach(channel->panel);
-
kfree(channel->edid);
i2c_put_adapter(channel->ddc);
}
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index a831b5bd1613..8232f512b9ed 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -289,9 +289,6 @@ static int imx_pd_register(struct drm_device *drm,
DRM_MODE_CONNECTOR_DPI);
}
- if (imxpd->panel)
- drm_panel_attach(imxpd->panel, &imxpd->connector);
-
if (imxpd->next_bridge) {
ret = drm_bridge_attach(encoder, imxpd->next_bridge,
&imxpd->bridge, 0);
@@ -357,9 +354,6 @@ static void imx_pd_unbind(struct device *dev, struct device *master,
{
struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
- if (imxpd->panel)
- drm_panel_detach(imxpd->panel);
-
kfree(imxpd->edid);
}
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index ada990a7f911..5dab9c3d0a52 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -199,26 +199,20 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
{
struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL;
- long rate;
-
- if (!drm_atomic_crtc_needs_modeset(state))
- return 0;
-
- if (state->mode.hdisplay > priv->soc_info->max_width ||
- state->mode.vdisplay > priv->soc_info->max_height)
- return -EINVAL;
- rate = clk_round_rate(priv->pix_clk,
- state->adjusted_mode.clock * 1000);
- if (rate < 0)
- return rate;
-
- if (priv->soc_info->has_osd) {
+ if (drm_atomic_crtc_needs_modeset(state) && priv->soc_info->has_osd) {
f1_state = drm_atomic_get_plane_state(state->state, &priv->f1);
+ if (IS_ERR(f1_state))
+ return PTR_ERR(f1_state);
+
f0_state = drm_atomic_get_plane_state(state->state, &priv->f0);
+ if (IS_ERR(f0_state))
+ return PTR_ERR(f0_state);
if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) {
ipu_state = drm_atomic_get_plane_state(state->state, priv->ipu_plane);
+ if (IS_ERR(ipu_state))
+ return PTR_ERR(ipu_state);
/* IPU and F1 planes cannot be enabled at the same time. */
if (f1_state->fb && ipu_state->fb) {
@@ -235,6 +229,24 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
return 0;
}
+static enum drm_mode_status
+ingenic_drm_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
+{
+ struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
+ long rate;
+
+ if (mode->hdisplay > priv->soc_info->max_width)
+ return MODE_BAD_HVALUE;
+ if (mode->vdisplay > priv->soc_info->max_height)
+ return MODE_BAD_VVALUE;
+
+ rate = clk_round_rate(priv->pix_clk, mode->clock * 1000);
+ if (rate < 0)
+ return MODE_CLOCK_RANGE;
+
+ return MODE_OK;
+}
+
static void ingenic_drm_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *oldstate)
{
@@ -648,6 +660,7 @@ static const struct drm_crtc_helper_funcs ingenic_drm_crtc_helper_funcs = {
.atomic_begin = ingenic_drm_crtc_atomic_begin,
.atomic_flush = ingenic_drm_crtc_atomic_flush,
.atomic_check = ingenic_drm_crtc_atomic_check,
+ .mode_valid = ingenic_drm_crtc_mode_valid,
};
static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs = {
diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c
index 7a0a8bd865d3..fc8c6e970ee3 100644
--- a/drivers/gpu/drm/ingenic/ingenic-ipu.c
+++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c
@@ -35,6 +35,7 @@ struct soc_info {
const u32 *formats;
size_t num_formats;
bool has_bicubic;
+ bool manual_restart;
void (*set_coefs)(struct ingenic_ipu *ipu, unsigned int reg,
unsigned int sharpness, bool downscale,
@@ -48,6 +49,7 @@ struct ingenic_ipu {
struct regmap *map;
struct clk *clk;
const struct soc_info *soc_info;
+ bool clk_enabled;
unsigned int num_w, num_h, denom_w, denom_h;
@@ -287,12 +289,23 @@ static void ingenic_ipu_plane_atomic_update(struct drm_plane *plane,
const struct drm_format_info *finfo;
u32 ctrl, stride = 0, coef_index = 0, format = 0;
bool needs_modeset, upscaling_w, upscaling_h;
+ int err;
if (!state || !state->fb)
return;
finfo = drm_format_info(state->fb->format->format);
+ if (!ipu->clk_enabled) {
+ err = clk_enable(ipu->clk);
+ if (err) {
+ dev_err(ipu->dev, "Unable to enable clock: %d\n", err);
+ return;
+ }
+
+ ipu->clk_enabled = true;
+ }
+
/* Reset all the registers if needed */
needs_modeset = drm_atomic_crtc_needs_modeset(state->crtc->state);
if (needs_modeset) {
@@ -577,6 +590,11 @@ static void ingenic_ipu_plane_atomic_disable(struct drm_plane *plane,
regmap_clear_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_CHIP_EN);
ingenic_drm_plane_disable(ipu->master, plane);
+
+ if (ipu->clk_enabled) {
+ clk_disable(ipu->clk);
+ ipu->clk_enabled = false;
+ }
}
static const struct drm_plane_helper_funcs ingenic_ipu_plane_helper_funcs = {
@@ -645,7 +663,8 @@ static irqreturn_t ingenic_ipu_irq_handler(int irq, void *arg)
unsigned int dummy;
/* dummy read allows CPU to reconfigure IPU */
- regmap_read(ipu->map, JZ_REG_IPU_STATUS, &dummy);
+ if (ipu->soc_info->manual_restart)
+ regmap_read(ipu->map, JZ_REG_IPU_STATUS, &dummy);
/* ACK interrupt */
regmap_write(ipu->map, JZ_REG_IPU_STATUS, 0);
@@ -656,7 +675,8 @@ static irqreturn_t ingenic_ipu_irq_handler(int irq, void *arg)
regmap_write(ipu->map, JZ_REG_IPU_V_ADDR, ipu->addr_v);
/* Run IPU for the new frame */
- regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RUN);
+ if (ipu->soc_info->manual_restart)
+ regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RUN);
drm_crtc_handle_vblank(crtc);
@@ -758,9 +778,9 @@ static int ingenic_ipu_bind(struct device *dev, struct device *master, void *d)
drm_object_attach_property(&plane->base, ipu->sharpness_prop,
ipu->sharpness);
- err = clk_prepare_enable(ipu->clk);
+ err = clk_prepare(ipu->clk);
if (err) {
- dev_err(dev, "Unable to enable clock\n");
+ dev_err(dev, "Unable to prepare clock\n");
return err;
}
@@ -772,7 +792,7 @@ static void ingenic_ipu_unbind(struct device *dev,
{
struct ingenic_ipu *ipu = dev_get_drvdata(dev);
- clk_disable_unprepare(ipu->clk);
+ clk_unprepare(ipu->clk);
}
static const struct component_ops ingenic_ipu_ops = {
@@ -792,10 +812,16 @@ static int ingenic_ipu_remove(struct platform_device *pdev)
}
static const u32 jz4725b_ipu_formats[] = {
+ /*
+ * While officially supported, packed YUV 4:2:2 formats can cause
+ * random hardware crashes on JZ4725B under certain circumstances.
+ * It seems to happen with some specific resize ratios.
+ * Until a proper workaround or fix is found, disable these formats.
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
+ */
DRM_FORMAT_YUV411,
DRM_FORMAT_YUV420,
DRM_FORMAT_YUV422,
@@ -806,6 +832,7 @@ static const struct soc_info jz4725b_soc_info = {
.formats = jz4725b_ipu_formats,
.num_formats = ARRAY_SIZE(jz4725b_ipu_formats),
.has_bicubic = false,
+ .manual_restart = true,
.set_coefs = jz4725b_set_coefs,
};
@@ -831,6 +858,7 @@ static const struct soc_info jz4760_soc_info = {
.formats = jz4760_ipu_formats,
.num_formats = ARRAY_SIZE(jz4760_ipu_formats),
.has_bicubic = true,
+ .manual_restart = false,
.set_coefs = jz4760_set_coefs,
};
diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c
index 4d2290f88edb..c271e5bf042e 100644
--- a/drivers/gpu/drm/mcde/mcde_display.c
+++ b/drivers/gpu/drm/mcde/mcde_display.c
@@ -7,6 +7,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-buf.h>
+#include <linux/regulator/consumer.h>
#include <drm/drm_device.h>
#include <drm/drm_fb_cma_helper.h>
@@ -89,7 +90,7 @@ void mcde_display_irq(struct mcde *mcde)
* the update function is called, then we disable the
* flow on the channel once we get the TE IRQ.
*/
- if (mcde->oneshot_mode) {
+ if (mcde->flow_mode == MCDE_COMMAND_ONESHOT_FLOW) {
spin_lock(&mcde->flow_lock);
if (--mcde->flow_active == 0) {
dev_dbg(mcde->dev, "TE0 IRQ\n");
@@ -333,7 +334,7 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl,
enum mcde_extsrc src,
enum mcde_channel ch,
const struct drm_display_mode *mode,
- u32 format)
+ u32 format, int cpp)
{
u32 val;
u32 conf1;
@@ -342,6 +343,7 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl,
u32 ljinc;
u32 cr;
u32 comp;
+ u32 pixel_fetcher_watermark;
switch (ovl) {
case MCDE_OVERLAY_0:
@@ -426,8 +428,33 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl,
format);
break;
}
- /* The default watermark level for overlay 0 is 48 */
- val |= 48 << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT;
+
+ /*
+ * Pixel fetch watermark level is max 0x1FFF pixels.
+ * Two basic rules should be followed:
+ * 1. The value should be at least 256 bits.
+ * 2. The sum of all active overlays pixelfetch watermark level
+ * multiplied with bits per pixel, should be lower than the
+ * size of input_fifo_size in bits.
+ * 3. The value should be a multiple of a line (256 bits).
+ */
+ switch (cpp) {
+ case 2:
+ pixel_fetcher_watermark = 128;
+ break;
+ case 3:
+ pixel_fetcher_watermark = 96;
+ break;
+ case 4:
+ pixel_fetcher_watermark = 48;
+ break;
+ default:
+ pixel_fetcher_watermark = 48;
+ break;
+ }
+ dev_dbg(mcde->dev, "pixel fetcher watermark level %d pixels\n",
+ pixel_fetcher_watermark);
+ val |= pixel_fetcher_watermark << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT;
writel(val, mcde->regs + conf2);
/* Number of bytes to fetch per line */
@@ -498,19 +525,47 @@ static void mcde_configure_channel(struct mcde *mcde, enum mcde_channel ch,
}
/* Set up channel 0 sync (based on chnl_update_registers()) */
- if (mcde->video_mode || mcde->te_sync)
+ switch (mcde->flow_mode) {
+ case MCDE_COMMAND_ONESHOT_FLOW:
+ /* Oneshot is achieved with software sync */
+ val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE
+ << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT;
+ break;
+ case MCDE_COMMAND_TE_FLOW:
val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE
<< MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT;
- else
- val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE
+ val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0
+ << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT;
+ break;
+ case MCDE_COMMAND_BTA_TE_FLOW:
+ val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE
+ << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT;
+ /*
+ * TODO:
+ * The vendor driver uses the formatter as sync source
+ * for BTA TE mode. Test to use TE if you have a panel
+ * that uses this mode.
+ */
+ val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER
+ << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT;
+ break;
+ case MCDE_VIDEO_TE_FLOW:
+ val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE
<< MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT;
-
- if (mcde->te_sync)
val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0
<< MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT;
- else
+ break;
+ case MCDE_VIDEO_FORMATTER_FLOW:
+ val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE
+ << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT;
val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER
<< MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT;
+ break;
+ default:
+ dev_err(mcde->dev, "unknown flow mode %d\n",
+ mcde->flow_mode);
+ break;
+ }
writel(val, mcde->regs + sync);
@@ -825,6 +880,14 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
u32 formatter_frame;
u32 pkt_div;
u32 val;
+ int ret;
+
+ /* This powers up the entire MCDE block and the DSI hardware */
+ ret = regulator_enable(mcde->epod);
+ if (ret) {
+ dev_err(drm->dev, "can't re-enable EPOD regulator\n");
+ return;
+ }
dev_info(drm->dev, "enable MCDE, %d x %d format %s\n",
mode->hdisplay, mode->vdisplay,
@@ -835,6 +898,26 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
return;
}
+ /* Set up the main control, watermark level at 7 */
+ val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT;
+ /* 24 bits DPI: connect LSB Ch B to D[0:7] */
+ val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT;
+ /* TV out: connect LSB Ch B to D[8:15] */
+ val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT;
+ /* Don't care about this muxing */
+ val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT;
+ /* 24 bits DPI: connect MID Ch B to D[24:31] */
+ val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT;
+ /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */
+ val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT;
+ /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */
+ writel(val, mcde->regs + MCDE_CONF0);
+
+ /* Clear any pending interrupts */
+ mcde_display_disable_irqs(mcde);
+ writel(0, mcde->regs + MCDE_IMSCERR);
+ writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR);
+
dev_info(drm->dev, "output in %s mode, format %dbpp\n",
(mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ?
"VIDEO" : "CMD",
@@ -904,7 +987,7 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
* channel 0
*/
mcde_configure_overlay(mcde, MCDE_OVERLAY_0, MCDE_EXTSRC_0,
- MCDE_CHANNEL_0, mode, format);
+ MCDE_CHANNEL_0, mode, format, cpp);
/*
* Configure pixel-per-line and line-per-frame for channel 0 and then
@@ -916,11 +999,25 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0,
fifo_wtrmrk);
+ /*
+ * This brings up the DSI bridge which is tightly connected
+ * to the MCDE DSI formatter.
+ *
+ * FIXME: if we want to use another formatter, such as DPI,
+ * we need to be more elaborate here and select the appropriate
+ * bridge.
+ */
+ mcde_dsi_enable(mcde->bridge);
+
/* Configure the DSI formatter 0 for the DSI panel output */
mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0,
formatter_frame, pkt_size);
- if (mcde->te_sync) {
+ switch (mcde->flow_mode) {
+ case MCDE_COMMAND_TE_FLOW:
+ case MCDE_COMMAND_BTA_TE_FLOW:
+ case MCDE_VIDEO_TE_FLOW:
+ /* We are using TE in some comination */
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
val = MCDE_VSCRC_VSPOL;
else
@@ -930,16 +1027,31 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
val = readl(mcde->regs + MCDE_CRC);
val |= MCDE_CRC_SYCEN0;
writel(val, mcde->regs + MCDE_CRC);
+ break;
+ default:
+ /* No TE capture */
+ break;
}
drm_crtc_vblank_on(crtc);
- if (mcde->video_mode)
- /*
- * Keep FIFO permanently enabled in video mode,
- * otherwise MCDE will stop feeding data to the panel.
- */
+ /*
+ * If we're using oneshot mode we don't start the flow
+ * until each time the display is given an update, and
+ * then we disable it immediately after. For all other
+ * modes (command or video) we start the FIFO flow
+ * right here. This is necessary for the hardware to
+ * behave right.
+ */
+ if (mcde->flow_mode != MCDE_COMMAND_ONESHOT_FLOW) {
mcde_enable_fifo(mcde, MCDE_FIFO_A);
+ dev_dbg(mcde->dev, "started MCDE video FIFO flow\n");
+ }
+
+ /* Enable MCDE with automatic clock gating */
+ val = readl(mcde->regs + MCDE_CR);
+ val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN;
+ writel(val, mcde->regs + MCDE_CR);
dev_info(drm->dev, "MCDE display is enabled\n");
}
@@ -950,12 +1062,16 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe)
struct drm_device *drm = crtc->dev;
struct mcde *mcde = to_mcde(drm);
struct drm_pending_vblank_event *event;
+ int ret;
drm_crtc_vblank_off(crtc);
/* Disable FIFO A flow */
mcde_disable_fifo(mcde, MCDE_FIFO_A, true);
+ /* This disables the DSI bridge */
+ mcde_dsi_disable(mcde->bridge);
+
event = crtc->state->event;
if (event) {
crtc->state->event = NULL;
@@ -965,43 +1081,47 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe)
spin_unlock_irq(&crtc->dev->event_lock);
}
+ ret = regulator_disable(mcde->epod);
+ if (ret)
+ dev_err(drm->dev, "can't disable EPOD regulator\n");
+ /* Make sure we are powered down (before we may power up again) */
+ usleep_range(50000, 70000);
+
dev_info(drm->dev, "MCDE display is disabled\n");
}
-static void mcde_display_send_one_frame(struct mcde *mcde)
+static void mcde_start_flow(struct mcde *mcde)
{
- /* Request a TE ACK */
- if (mcde->te_sync)
+ /* Request a TE ACK only in TE+BTA mode */
+ if (mcde->flow_mode == MCDE_COMMAND_BTA_TE_FLOW)
mcde_dsi_te_request(mcde->mdsi);
/* Enable FIFO A flow */
mcde_enable_fifo(mcde, MCDE_FIFO_A);
- if (mcde->te_sync) {
+ /*
+ * If oneshot mode is enabled, the flow will be disabled
+ * when the TE0 IRQ arrives in the interrupt handler. Otherwise
+ * updates are continuously streamed to the display after this
+ * point.
+ */
+
+ if (mcde->flow_mode == MCDE_COMMAND_ONESHOT_FLOW) {
+ /* Trigger a software sync out on channel 0 */
+ writel(MCDE_CHNLXSYNCHSW_SW_TRIG,
+ mcde->regs + MCDE_CHNL0SYNCHSW);
+
/*
- * If oneshot mode is enabled, the flow will be disabled
- * when the TE0 IRQ arrives in the interrupt handler. Otherwise
- * updates are continuously streamed to the display after this
- * point.
+ * Disable FIFO A flow again: since we are using TE sync we
+ * need to wait for the FIFO to drain before we continue
+ * so repeated calls to this function will not cause a mess
+ * in the hardware by pushing updates will updates are going
+ * on already.
*/
- dev_dbg(mcde->dev, "sent TE0 framebuffer update\n");
- return;
+ mcde_disable_fifo(mcde, MCDE_FIFO_A, true);
}
- /* Trigger a software sync out on channel 0 */
- writel(MCDE_CHNLXSYNCHSW_SW_TRIG,
- mcde->regs + MCDE_CHNL0SYNCHSW);
-
- /*
- * Disable FIFO A flow again: since we are using TE sync we
- * need to wait for the FIFO to drain before we continue
- * so repeated calls to this function will not cause a mess
- * in the hardware by pushing updates will updates are going
- * on already.
- */
- mcde_disable_fifo(mcde, MCDE_FIFO_A, true);
-
- dev_dbg(mcde->dev, "sent SW framebuffer update\n");
+ dev_dbg(mcde->dev, "started MCDE FIFO flow\n");
}
static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address)
@@ -1060,15 +1180,13 @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe,
*/
if (fb) {
mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0));
- if (!mcde->video_mode) {
- /*
- * Send a single frame using software sync if the flow
- * is not active yet.
- */
- if (mcde->flow_active == 0)
- mcde_display_send_one_frame(mcde);
- }
- dev_info_once(mcde->dev, "sent first display update\n");
+ dev_info_once(mcde->dev, "first update of display contents\n");
+ /*
+ * Usually the flow is already active, unless we are in
+ * oneshot mode, then we need to kick the flow right here.
+ */
+ if (mcde->flow_active == 0)
+ mcde_start_flow(mcde);
} else {
/*
* If an update is receieved before the MCDE is enabled
diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h
index 679c2c4e6d9d..8253e2f9993e 100644
--- a/drivers/gpu/drm/mcde/mcde_drm.h
+++ b/drivers/gpu/drm/mcde/mcde_drm.h
@@ -9,6 +9,61 @@
#ifndef _MCDE_DRM_H_
#define _MCDE_DRM_H_
+/* Shared basic registers */
+#define MCDE_CR 0x00000000
+#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_SHIFT 0
+#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_MASK 0x0000003F
+#define MCDE_CR_IFIFOCTRLEN BIT(15)
+#define MCDE_CR_UFRECOVERY_MODE_V422 BIT(16)
+#define MCDE_CR_WRAP_MODE_V422_SHIFT BIT(17)
+#define MCDE_CR_AUTOCLKG_EN BIT(30)
+#define MCDE_CR_MCDEEN BIT(31)
+
+#define MCDE_CONF0 0x00000004
+#define MCDE_CONF0_SYNCMUX0 BIT(0)
+#define MCDE_CONF0_SYNCMUX1 BIT(1)
+#define MCDE_CONF0_SYNCMUX2 BIT(2)
+#define MCDE_CONF0_SYNCMUX3 BIT(3)
+#define MCDE_CONF0_SYNCMUX4 BIT(4)
+#define MCDE_CONF0_SYNCMUX5 BIT(5)
+#define MCDE_CONF0_SYNCMUX6 BIT(6)
+#define MCDE_CONF0_SYNCMUX7 BIT(7)
+#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12
+#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000
+#define MCDE_CONF0_OUTMUX0_SHIFT 16
+#define MCDE_CONF0_OUTMUX0_MASK 0x00070000
+#define MCDE_CONF0_OUTMUX1_SHIFT 19
+#define MCDE_CONF0_OUTMUX1_MASK 0x00380000
+#define MCDE_CONF0_OUTMUX2_SHIFT 22
+#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000
+#define MCDE_CONF0_OUTMUX3_SHIFT 25
+#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000
+#define MCDE_CONF0_OUTMUX4_SHIFT 28
+#define MCDE_CONF0_OUTMUX4_MASK 0x70000000
+
+#define MCDE_SSP 0x00000008
+#define MCDE_AIS 0x00000100
+#define MCDE_IMSCERR 0x00000110
+#define MCDE_RISERR 0x00000120
+#define MCDE_MISERR 0x00000130
+#define MCDE_SISERR 0x00000140
+
+enum mcde_flow_mode {
+ /* One-shot mode: flow stops after one frame */
+ MCDE_COMMAND_ONESHOT_FLOW,
+ /* Command mode with tearing effect (TE) IRQ sync */
+ MCDE_COMMAND_TE_FLOW,
+ /*
+ * Command mode with bus turn-around (BTA) and tearing effect
+ * (TE) IRQ sync.
+ */
+ MCDE_COMMAND_BTA_TE_FLOW,
+ /* Video mode with tearing effect (TE) sync IRQ */
+ MCDE_VIDEO_TE_FLOW,
+ /* Video mode with the formatter itself as sync source */
+ MCDE_VIDEO_FORMATTER_FLOW,
+};
+
struct mcde {
struct drm_device drm;
struct device *dev;
@@ -18,9 +73,7 @@ struct mcde {
struct drm_simple_display_pipe pipe;
struct mipi_dsi_device *mdsi;
s16 stride;
- bool te_sync;
- bool video_mode;
- bool oneshot_mode;
+ enum mcde_flow_mode flow_mode;
unsigned int flow_active;
spinlock_t flow_lock; /* Locks the channel flow control */
@@ -36,8 +89,16 @@ struct mcde {
#define to_mcde(dev) container_of(dev, struct mcde, drm)
+static inline bool mcde_flow_is_video(struct mcde *mcde)
+{
+ return (mcde->flow_mode == MCDE_VIDEO_TE_FLOW ||
+ mcde->flow_mode == MCDE_VIDEO_FORMATTER_FLOW);
+}
+
bool mcde_dsi_irq(struct mipi_dsi_device *mdsi);
void mcde_dsi_te_request(struct mipi_dsi_device *mdsi);
+void mcde_dsi_enable(struct drm_bridge *bridge);
+void mcde_dsi_disable(struct drm_bridge *bridge);
extern struct platform_driver mcde_dsi_driver;
void mcde_display_irq(struct mcde *mcde);
diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c
index 82137ab76cfc..c592957ed07f 100644
--- a/drivers/gpu/drm/mcde/mcde_drv.c
+++ b/drivers/gpu/drm/mcde/mcde_drv.c
@@ -63,6 +63,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
@@ -82,44 +83,6 @@
#define DRIVER_DESC "DRM module for MCDE"
-#define MCDE_CR 0x00000000
-#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_SHIFT 0
-#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_MASK 0x0000003F
-#define MCDE_CR_IFIFOCTRLEN BIT(15)
-#define MCDE_CR_UFRECOVERY_MODE_V422 BIT(16)
-#define MCDE_CR_WRAP_MODE_V422_SHIFT BIT(17)
-#define MCDE_CR_AUTOCLKG_EN BIT(30)
-#define MCDE_CR_MCDEEN BIT(31)
-
-#define MCDE_CONF0 0x00000004
-#define MCDE_CONF0_SYNCMUX0 BIT(0)
-#define MCDE_CONF0_SYNCMUX1 BIT(1)
-#define MCDE_CONF0_SYNCMUX2 BIT(2)
-#define MCDE_CONF0_SYNCMUX3 BIT(3)
-#define MCDE_CONF0_SYNCMUX4 BIT(4)
-#define MCDE_CONF0_SYNCMUX5 BIT(5)
-#define MCDE_CONF0_SYNCMUX6 BIT(6)
-#define MCDE_CONF0_SYNCMUX7 BIT(7)
-#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12
-#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000
-#define MCDE_CONF0_OUTMUX0_SHIFT 16
-#define MCDE_CONF0_OUTMUX0_MASK 0x00070000
-#define MCDE_CONF0_OUTMUX1_SHIFT 19
-#define MCDE_CONF0_OUTMUX1_MASK 0x00380000
-#define MCDE_CONF0_OUTMUX2_SHIFT 22
-#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000
-#define MCDE_CONF0_OUTMUX3_SHIFT 25
-#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000
-#define MCDE_CONF0_OUTMUX4_SHIFT 28
-#define MCDE_CONF0_OUTMUX4_MASK 0x70000000
-
-#define MCDE_SSP 0x00000008
-#define MCDE_AIS 0x00000100
-#define MCDE_IMSCERR 0x00000110
-#define MCDE_RISERR 0x00000120
-#define MCDE_MISERR 0x00000130
-#define MCDE_SISERR 0x00000140
-
#define MCDE_PID 0x000001FC
#define MCDE_PID_METALFIX_VERSION_SHIFT 0
#define MCDE_PID_METALFIX_VERSION_MASK 0x000000FF
@@ -293,7 +256,6 @@ static int mcde_probe(struct platform_device *pdev)
struct component_match *match = NULL;
struct resource *res;
u32 pid;
- u32 val;
int irq;
int ret;
int i;
@@ -305,9 +267,6 @@ static int mcde_probe(struct platform_device *pdev)
mcde->dev = dev;
platform_set_drvdata(pdev, drm);
- /* Enable continuous updates: this is what Linux' framebuffer expects */
- mcde->oneshot_mode = false;
-
/* First obtain and turn on the main power */
mcde->epod = devm_regulator_get(dev, "epod");
if (IS_ERR(mcde->epod)) {
@@ -405,27 +364,7 @@ static int mcde_probe(struct platform_device *pdev)
goto clk_disable;
}
- /* Set up the main control, watermark level at 7 */
- val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT;
- /* 24 bits DPI: connect LSB Ch B to D[0:7] */
- val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT;
- /* TV out: connect LSB Ch B to D[8:15] */
- val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT;
- /* Don't care about this muxing */
- val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT;
- /* 24 bits DPI: connect MID Ch B to D[24:31] */
- val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT;
- /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */
- val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT;
- /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */
- writel(val, mcde->regs + MCDE_CONF0);
-
- /* Enable automatic clock gating */
- val = readl(mcde->regs + MCDE_CR);
- val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN;
- writel(val, mcde->regs + MCDE_CR);
-
- /* Clear any pending interrupts */
+ /* Disable and clear any pending interrupts */
mcde_display_disable_irqs(mcde);
writel(0, mcde->regs + MCDE_IMSCERR);
writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR);
@@ -455,12 +394,28 @@ static int mcde_probe(struct platform_device *pdev)
ret = PTR_ERR(match);
goto clk_disable;
}
+
+ /*
+ * Perform an invasive reset of the MCDE and all blocks by
+ * cutting the power to the subsystem, then bring it back up
+ * later when we enable the display as a result of
+ * component_master_add_with_match().
+ */
+ ret = regulator_disable(mcde->epod);
+ if (ret) {
+ dev_err(dev, "can't disable EPOD regulator\n");
+ return ret;
+ }
+ /* Wait 50 ms so we are sure we cut the power */
+ usleep_range(50000, 70000);
+
ret = component_master_add_with_match(&pdev->dev, &mcde_drm_comp_ops,
match);
if (ret) {
dev_err(dev, "failed to add component master\n");
goto clk_disable;
}
+
return 0;
clk_disable:
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index 981923caa7e6..2314c8122992 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -43,6 +43,7 @@ struct mcde_dsi {
struct drm_bridge *bridge_out;
struct mipi_dsi_host dsi_host;
struct mipi_dsi_device *mdsi;
+ const struct drm_display_mode *mode;
struct clk *hs_clk;
struct clk *lp_clk;
unsigned long hs_freq;
@@ -148,9 +149,22 @@ static void mcde_dsi_attach_to_mcde(struct mcde_dsi *d)
{
d->mcde->mdsi = d->mdsi;
- d->mcde->video_mode = !!(d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO);
- /* Enable use of the TE signal for all command mode panels */
- d->mcde->te_sync = !d->mcde->video_mode;
+ /*
+ * Select the way the DSI data flow is pushing to the display:
+ * currently we just support video or command mode depending
+ * on the type of display. Video mode defaults to using the
+ * formatter itself for synchronization (stateless video panel).
+ *
+ * FIXME: add flags to struct mipi_dsi_device .flags to indicate
+ * displays that require BTA (bus turn around) so we can handle
+ * such displays as well. Figure out how to properly handle
+ * single frame on-demand updates with DRM for command mode
+ * displays (MCDE_COMMAND_ONESHOT_FLOW).
+ */
+ if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO)
+ d->mcde->flow_mode = MCDE_VIDEO_FORMATTER_FLOW;
+ else
+ d->mcde->flow_mode = MCDE_COMMAND_TE_FLOW;
}
static int mcde_dsi_host_attach(struct mipi_dsi_host *host,
@@ -194,79 +208,16 @@ static int mcde_dsi_host_detach(struct mipi_dsi_host *host,
(type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \
(type == MIPI_DSI_DCS_READ))
-static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host,
- const struct mipi_dsi_msg *msg)
+static int mcde_dsi_execute_transfer(struct mcde_dsi *d,
+ const struct mipi_dsi_msg *msg)
{
- struct mcde_dsi *d = host_to_mcde_dsi(host);
const u32 loop_delay_us = 10; /* us */
- const u8 *tx = msg->tx_buf;
u32 loop_counter;
size_t txlen = msg->tx_len;
size_t rxlen = msg->rx_len;
+ int i;
u32 val;
int ret;
- int i;
-
- if (txlen > 16) {
- dev_err(d->dev,
- "dunno how to write more than 16 bytes yet\n");
- return -EIO;
- }
- if (rxlen > 4) {
- dev_err(d->dev,
- "dunno how to read more than 4 bytes yet\n");
- return -EIO;
- }
-
- dev_dbg(d->dev,
- "message to channel %d, write %zd bytes read %zd bytes\n",
- msg->channel, txlen, rxlen);
-
- /* Command "nature" */
- if (MCDE_DSI_HOST_IS_READ(msg->type))
- /* MCTL_MAIN_DATA_CTL already set up */
- val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ;
- else
- val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE;
- /*
- * More than 2 bytes will not fit in a single packet, so it's
- * time to set the "long not short" bit. One byte is used by
- * the MIPI DCS command leaving just one byte for the payload
- * in a short package.
- */
- if (mipi_dsi_packet_format_is_long(msg->type))
- val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT;
- val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT;
- val |= txlen << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT;
- val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN;
- val |= msg->type << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT;
- writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS);
-
- /* MIPI DCS command is part of the data */
- if (txlen > 0) {
- val = 0;
- for (i = 0; i < 4 && i < txlen; i++)
- val |= tx[i] << (i * 8);
- }
- writel(val, d->regs + DSI_DIRECT_CMD_WRDAT0);
- if (txlen > 4) {
- val = 0;
- for (i = 0; i < 4 && (i + 4) < txlen; i++)
- val |= tx[i + 4] << (i * 8);
- writel(val, d->regs + DSI_DIRECT_CMD_WRDAT1);
- }
- if (txlen > 8) {
- val = 0;
- for (i = 0; i < 4 && (i + 8) < txlen; i++)
- val |= tx[i + 8] << (i * 8);
- writel(val, d->regs + DSI_DIRECT_CMD_WRDAT2);
- }
- if (txlen > 12) {
- val = 0;
- for (i = 0; i < 4 && (i + 12) < txlen; i++)
- val |= tx[i + 12] << (i * 8);
- writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3);
- }
writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR);
writel(~0, d->regs + DSI_CMD_MODE_STS_CLR);
@@ -283,6 +234,7 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host,
usleep_range(loop_delay_us, (loop_delay_us * 3) / 2);
if (!loop_counter) {
dev_err(d->dev, "DSI read timeout!\n");
+ /* Set exit code and retry */
return -ETIME;
}
} else {
@@ -293,6 +245,7 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host,
usleep_range(loop_delay_us, (loop_delay_us * 3) / 2);
if (!loop_counter) {
+ /* Set exit code and retry */
dev_err(d->dev, "DSI write timeout!\n");
return -ETIME;
}
@@ -334,6 +287,93 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host,
ret = rdsz;
}
+ /* Successful transmission */
+ return ret;
+}
+
+static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct mcde_dsi *d = host_to_mcde_dsi(host);
+ const u8 *tx = msg->tx_buf;
+ size_t txlen = msg->tx_len;
+ size_t rxlen = msg->rx_len;
+ unsigned int retries = 0;
+ u32 val;
+ int ret;
+ int i;
+
+ if (txlen > 16) {
+ dev_err(d->dev,
+ "dunno how to write more than 16 bytes yet\n");
+ return -EIO;
+ }
+ if (rxlen > 4) {
+ dev_err(d->dev,
+ "dunno how to read more than 4 bytes yet\n");
+ return -EIO;
+ }
+
+ dev_dbg(d->dev,
+ "message to channel %d, write %zd bytes read %zd bytes\n",
+ msg->channel, txlen, rxlen);
+
+ /* Command "nature" */
+ if (MCDE_DSI_HOST_IS_READ(msg->type))
+ /* MCTL_MAIN_DATA_CTL already set up */
+ val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ;
+ else
+ val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE;
+ /*
+ * More than 2 bytes will not fit in a single packet, so it's
+ * time to set the "long not short" bit. One byte is used by
+ * the MIPI DCS command leaving just one byte for the payload
+ * in a short package.
+ */
+ if (mipi_dsi_packet_format_is_long(msg->type))
+ val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT;
+ val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT;
+ val |= txlen << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT;
+ val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN;
+ val |= msg->type << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT;
+ writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS);
+
+ /* MIPI DCS command is part of the data */
+ if (txlen > 0) {
+ val = 0;
+ for (i = 0; i < 4 && i < txlen; i++)
+ val |= tx[i] << (i * 8);
+ }
+ writel(val, d->regs + DSI_DIRECT_CMD_WRDAT0);
+ if (txlen > 4) {
+ val = 0;
+ for (i = 0; i < 4 && (i + 4) < txlen; i++)
+ val |= tx[i + 4] << (i * 8);
+ writel(val, d->regs + DSI_DIRECT_CMD_WRDAT1);
+ }
+ if (txlen > 8) {
+ val = 0;
+ for (i = 0; i < 4 && (i + 8) < txlen; i++)
+ val |= tx[i + 8] << (i * 8);
+ writel(val, d->regs + DSI_DIRECT_CMD_WRDAT2);
+ }
+ if (txlen > 12) {
+ val = 0;
+ for (i = 0; i < 4 && (i + 12) < txlen; i++)
+ val |= tx[i + 12] << (i * 8);
+ writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3);
+ }
+
+ while (retries < 3) {
+ ret = mcde_dsi_execute_transfer(d, msg);
+ if (ret >= 0)
+ break;
+ retries++;
+ }
+ if (ret < 0 && retries)
+ dev_err(d->dev, "gave up after %d retries\n", retries);
+
+ /* Clear any errors */
writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR);
writel(~0, d->regs + DSI_CMD_MODE_STS_CLR);
@@ -799,10 +839,11 @@ static void mcde_dsi_start(struct mcde_dsi *d)
/* Command mode, clear IF1 ID */
val = readl(d->regs + DSI_CMD_MODE_CTL);
/*
- * If we enable low-power mode here, with
- * val |= DSI_CMD_MODE_CTL_IF1_LP_EN
+ * If we enable low-power mode here,
* then display updates become really slow.
*/
+ if (d->mdsi->mode_flags & MIPI_DSI_MODE_LPM)
+ val |= DSI_CMD_MODE_CTL_IF1_LP_EN;
val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK;
writel(val, d->regs + DSI_CMD_MODE_CTL);
@@ -811,23 +852,11 @@ static void mcde_dsi_start(struct mcde_dsi *d)
dev_info(d->dev, "DSI link enabled\n");
}
-
-static void mcde_dsi_bridge_enable(struct drm_bridge *bridge)
-{
- struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
- u32 val;
-
- if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
- /* Enable video mode */
- val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
- val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN;
- writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
- }
-
- dev_info(d->dev, "enable DSI master\n");
-};
-
-static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge)
+/*
+ * Notice that this is called from inside the display controller
+ * and not from the bridge callbacks.
+ */
+void mcde_dsi_enable(struct drm_bridge *bridge)
{
struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
unsigned long hs_freq, lp_freq;
@@ -871,7 +900,25 @@ static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge)
dev_info(d->dev, "DSI HS clock rate %lu Hz\n",
d->hs_freq);
+ /* Assert RESET through the PRCMU, active low */
+ /* FIXME: which DSI block? */
+ regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
+ PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
+
+ usleep_range(100, 200);
+
+ /* De-assert RESET again */
+ regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
+ PRCM_DSI_SW_RESET_DSI0_SW_RESETN,
+ PRCM_DSI_SW_RESET_DSI0_SW_RESETN);
+
+ /* Start up the hardware */
+ mcde_dsi_start(d);
+
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+ /* Set up the video mode from the DRM mode */
+ mcde_dsi_setup_video_mode(d, d->mode);
+
/* Put IF1 into video mode */
val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE;
@@ -887,17 +934,25 @@ static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge)
val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC;
val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA;
writel(val, d->regs + DSI_VID_MODE_STS_CTL);
+
+ /* Enable video mode */
+ val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
+ val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN;
+ writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
} else {
/* Command mode, clear IF1 ID */
val = readl(d->regs + DSI_CMD_MODE_CTL);
/*
- * If we enable low-power mode here with
- * val |= DSI_CMD_MODE_CTL_IF1_LP_EN
+ * If we enable low-power mode here
* the display updates become really slow.
*/
+ if (d->mdsi->mode_flags & MIPI_DSI_MODE_LPM)
+ val |= DSI_CMD_MODE_CTL_IF1_LP_EN;
val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK;
writel(val, d->regs + DSI_CMD_MODE_CTL);
}
+
+ dev_info(d->dev, "enabled MCDE DSI master\n");
}
static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
@@ -911,13 +966,12 @@ static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
return;
}
+ d->mode = mode;
+
dev_info(d->dev, "set DSI master to %dx%d %u Hz %s mode\n",
mode->hdisplay, mode->vdisplay, mode->clock * 1000,
(d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD"
);
-
- if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO)
- mcde_dsi_setup_video_mode(d, mode);
}
static void mcde_dsi_wait_for_command_mode_stop(struct mcde_dsi *d)
@@ -961,14 +1015,15 @@ static void mcde_dsi_wait_for_video_mode_stop(struct mcde_dsi *d)
}
}
-static void mcde_dsi_bridge_disable(struct drm_bridge *bridge)
+/*
+ * Notice that this is called from inside the display controller
+ * and not from the bridge callbacks.
+ */
+void mcde_dsi_disable(struct drm_bridge *bridge)
{
struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
u32 val;
- /* Disable all error interrupts */
- writel(0, d->regs + DSI_VID_MODE_STS_CTL);
-
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
/* Stop video mode */
val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
@@ -980,7 +1035,14 @@ static void mcde_dsi_bridge_disable(struct drm_bridge *bridge)
mcde_dsi_wait_for_command_mode_stop(d);
}
- /* Stop clocks */
+ /*
+ * Stop clocks and terminate any DSI traffic here so the panel can
+ * send commands to shut down the display using DSI direct write until
+ * this point.
+ */
+
+ /* Disable all error interrupts */
+ writel(0, d->regs + DSI_VID_MODE_STS_CTL);
clk_disable_unprepare(d->hs_clk);
clk_disable_unprepare(d->lp_clk);
}
@@ -1010,9 +1072,6 @@ static int mcde_dsi_bridge_attach(struct drm_bridge *bridge,
static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = {
.attach = mcde_dsi_bridge_attach,
.mode_set = mcde_dsi_bridge_mode_set,
- .disable = mcde_dsi_bridge_disable,
- .enable = mcde_dsi_bridge_enable,
- .pre_enable = mcde_dsi_bridge_pre_enable,
};
static int mcde_dsi_bind(struct device *dev, struct device *master,
@@ -1048,21 +1107,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
return PTR_ERR(d->lp_clk);
}
- /* Assert RESET through the PRCMU, active low */
- /* FIXME: which DSI block? */
- regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
- PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
-
- usleep_range(100, 200);
-
- /* De-assert RESET again */
- regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
- PRCM_DSI_SW_RESET_DSI0_SW_RESETN,
- PRCM_DSI_SW_RESET_DSI0_SW_RESETN);
-
- /* Start up the hardware */
- mcde_dsi_start(d);
-
/* Look for a panel as a child to this node */
for_each_available_child_of_node(dev->of_node, child) {
panel = of_drm_find_panel(child);
diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig
index 93be766715c9..eec59658a938 100644
--- a/drivers/gpu/drm/mgag200/Kconfig
+++ b/drivers/gpu/drm/mgag200/Kconfig
@@ -1,13 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_MGAG200
- tristate "Kernel modesetting driver for MGA G200 server engines"
+ tristate "Matrox G200"
depends on DRM && PCI && MMU
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
help
- This is a KMS driver for the MGA G200 server chips, it
- does not support the original MGA G200 or any of the desktop
- chips. It requires 0.3.0 of the modesetting userspace driver,
- and a version of mga driver that will fail on KMS enabled
- devices.
-
+ This is a KMS driver for Matrox G200 chips. It supports the original
+ MGA G200 desktop chips and the server variants. It requires 0.3.0
+ of the modesetting userspace driver, and a version of mga driver
+ that will fail on KMS enabled devices.
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index e19660f4a637..771b26aeee19 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -9,6 +9,7 @@
#include <linux/console.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/vmalloc.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
@@ -36,6 +37,7 @@ static struct drm_driver mgag200_driver = {
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
+ .gem_create_object = drm_gem_shmem_create_object_cached,
DRM_GEM_SHMEM_DRIVER_OPS,
};
@@ -43,18 +45,66 @@ static struct drm_driver mgag200_driver = {
* DRM device
*/
-static int mgag200_device_init(struct mga_device *mdev, unsigned long flags)
+static bool mgag200_has_sgram(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
- int ret, option;
+ u32 option;
+ int ret;
- mdev->flags = mgag200_flags_from_driver_data(flags);
- mdev->type = mgag200_type_from_driver_data(flags);
+ ret = pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option);
+ if (drm_WARN(dev, ret, "failed to read PCI config dword: %d\n", ret))
+ return false;
- pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option);
- mdev->has_sdram = !(option & (1 << 14));
+ return !!(option & PCI_MGA_OPTION_HARDPWMSK);
+}
- /* BAR 0 is the framebuffer, BAR 1 contains registers */
+static int mgag200_regs_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ u32 option, option2;
+ u8 crtcext3;
+
+ switch (mdev->type) {
+ case G200_PCI:
+ case G200_AGP:
+ if (mgag200_has_sgram(mdev))
+ option = 0x4049cd21;
+ else
+ option = 0x40499121;
+ option2 = 0x00008000;
+ break;
+ case G200_SE_A:
+ case G200_SE_B:
+ option = 0x40049120;
+ if (mgag200_has_sgram(mdev))
+ option |= PCI_MGA_OPTION_HARDPWMSK;
+ option2 = 0x00008000;
+ break;
+ case G200_WB:
+ case G200_EW3:
+ option = 0x41049120;
+ option2 = 0x0000b000;
+ break;
+ case G200_EV:
+ option = 0x00000120;
+ option2 = 0x0000b000;
+ break;
+ case G200_EH:
+ case G200_EH3:
+ option = 0x00000120;
+ option2 = 0x0000b000;
+ break;
+ default:
+ option = 0;
+ option2 = 0;
+ }
+
+ if (option)
+ pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
+ if (option2)
+ pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2);
+
+ /* BAR 1 contains registers */
mdev->rmmio_base = pci_resource_start(dev->pdev, 1);
mdev->rmmio_size = pci_resource_len(dev->pdev, 1);
@@ -68,12 +118,163 @@ static int mgag200_device_init(struct mga_device *mdev, unsigned long flags)
if (mdev->rmmio == NULL)
return -ENOMEM;
- /* stash G200 SE model number for later use */
- if (IS_G200_SE(mdev)) {
- mdev->unique_rev_id = RREG32(0x1e24);
- drm_dbg(dev, "G200 SE unique revision id is 0x%x\n",
- mdev->unique_rev_id);
+ RREG_ECRT(0x03, crtcext3);
+ crtcext3 |= MGAREG_CRTCEXT3_MGAMODE;
+ WREG_ECRT(0x03, crtcext3);
+
+ return 0;
+}
+
+static void mgag200_g200_interpret_bios(struct mga_device *mdev,
+ const unsigned char *bios,
+ size_t size)
+{
+ static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'};
+ static const unsigned int expected_length[6] = {
+ 0, 64, 64, 64, 128, 128
+ };
+ struct drm_device *dev = &mdev->base;
+ const unsigned char *pins;
+ unsigned int pins_len, version;
+ int offset;
+ int tmp;
+
+ /* Test for MATROX string. */
+ if (size < 45 + sizeof(matrox))
+ return;
+ if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0)
+ return;
+
+ /* Get the PInS offset. */
+ if (size < MGA_BIOS_OFFSET + 2)
+ return;
+ offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET];
+
+ /* Get PInS data structure. */
+
+ if (size < offset + 6)
+ return;
+ pins = bios + offset;
+ if (pins[0] == 0x2e && pins[1] == 0x41) {
+ version = pins[5];
+ pins_len = pins[2];
+ } else {
+ version = 1;
+ pins_len = pins[0] + (pins[1] << 8);
+ }
+
+ if (version < 1 || version > 5) {
+ drm_warn(dev, "Unknown BIOS PInS version: %d\n", version);
+ return;
+ }
+ if (pins_len != expected_length[version]) {
+ drm_warn(dev, "Unexpected BIOS PInS size: %d expected: %d\n",
+ pins_len, expected_length[version]);
+ return;
}
+ if (size < offset + pins_len)
+ return;
+
+ drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n",
+ version, pins_len);
+
+ /* Extract the clock values */
+
+ switch (version) {
+ case 1:
+ tmp = pins[24] + (pins[25] << 8);
+ if (tmp)
+ mdev->model.g200.pclk_max = tmp * 10;
+ break;
+ case 2:
+ if (pins[41] != 0xff)
+ mdev->model.g200.pclk_max = (pins[41] + 100) * 1000;
+ break;
+ case 3:
+ if (pins[36] != 0xff)
+ mdev->model.g200.pclk_max = (pins[36] + 100) * 1000;
+ if (pins[52] & 0x20)
+ mdev->model.g200.ref_clk = 14318;
+ break;
+ case 4:
+ if (pins[39] != 0xff)
+ mdev->model.g200.pclk_max = pins[39] * 4 * 1000;
+ if (pins[92] & 0x01)
+ mdev->model.g200.ref_clk = 14318;
+ break;
+ case 5:
+ tmp = pins[4] ? 8000 : 6000;
+ if (pins[123] != 0xff)
+ mdev->model.g200.pclk_min = pins[123] * tmp;
+ if (pins[38] != 0xff)
+ mdev->model.g200.pclk_max = pins[38] * tmp;
+ if (pins[110] & 0x01)
+ mdev->model.g200.ref_clk = 14318;
+ break;
+ default:
+ break;
+ }
+}
+
+static void mgag200_g200_init_refclk(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ unsigned char __iomem *rom;
+ unsigned char *bios;
+ size_t size;
+
+ mdev->model.g200.pclk_min = 50000;
+ mdev->model.g200.pclk_max = 230000;
+ mdev->model.g200.ref_clk = 27050;
+
+ rom = pci_map_rom(dev->pdev, &size);
+ if (!rom)
+ return;
+
+ bios = vmalloc(size);
+ if (!bios)
+ goto out;
+ memcpy_fromio(bios, rom, size);
+
+ if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa)
+ mgag200_g200_interpret_bios(mdev, bios, size);
+
+ drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n",
+ mdev->model.g200.pclk_min, mdev->model.g200.pclk_max,
+ mdev->model.g200.ref_clk);
+
+ vfree(bios);
+out:
+ pci_unmap_rom(dev->pdev, rom);
+}
+
+static void mgag200_g200se_init_unique_id(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+
+ /* stash G200 SE model number for later use */
+ mdev->model.g200se.unique_rev_id = RREG32(0x1e24);
+
+ drm_dbg(dev, "G200 SE unique revision id is 0x%x\n",
+ mdev->model.g200se.unique_rev_id);
+}
+
+static int mgag200_device_init(struct mga_device *mdev, unsigned long flags)
+{
+ struct drm_device *dev = &mdev->base;
+ int ret;
+
+ mdev->flags = mgag200_flags_from_driver_data(flags);
+ mdev->type = mgag200_type_from_driver_data(flags);
+
+ ret = mgag200_regs_init(mdev);
+ if (ret)
+ return ret;
+
+ if (mdev->type == G200_PCI || mdev->type == G200_AGP)
+ mgag200_g200_init_refclk(mdev);
+ else if (IS_G200_SE(mdev))
+ mgag200_g200se_init_unique_id(mdev);
ret = mgag200_mm_init(mdev);
if (ret)
@@ -116,6 +317,8 @@ mgag200_device_create(struct pci_dev *pdev, unsigned long flags)
*/
static const struct pci_device_id mgag200_pciidlist[] = {
+ { PCI_VENDOR_ID_MATROX, 0x520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_PCI },
+ { PCI_VENDOR_ID_MATROX, 0x521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_AGP },
{ PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD},
{ PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B },
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 3817520bfefc..749a075fe9e4 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -38,6 +38,8 @@
#define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg))
#define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg))
+#define MGA_BIOS_OFFSET 0x7ffc
+
#define ATTR_INDEX 0x1fc0
#define ATTR_DATA 0x1fc1
@@ -129,6 +131,8 @@ struct mga_mc {
};
enum mga_type {
+ G200_PCI,
+ G200_AGP,
G200_SE_A,
G200_SE_B,
G200_WB,
@@ -161,14 +165,23 @@ struct mga_device {
size_t vram_fb_available;
enum mga_type type;
- int has_sdram;
int bpp_shifts[4];
int fb_mtrr;
- /* SE model number stored in reg 0x1e24 */
- u32 unique_rev_id;
+ union {
+ struct {
+ long ref_clk;
+ long pclk_min;
+ long pclk_max;
+ } g200;
+ struct {
+ /* SE model number stored in reg 0x1e24 */
+ u32 unique_rev_id;
+ } g200se;
+ } model;
+
struct mga_connector connector;
struct drm_simple_display_pipe display_pipe;
diff --git a/drivers/gpu/drm/mgag200/mgag200_mm.c b/drivers/gpu/drm/mgag200/mgag200_mm.c
index 7b69392bcb89..641f1aa992be 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mm.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mm.c
@@ -90,9 +90,17 @@ static void mgag200_mm_release(struct drm_device *dev, void *ptr)
int mgag200_mm_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
+ u8 misc;
resource_size_t start, len;
int ret;
+ WREG_ECRT(0x04, 0x00);
+
+ misc = RREG8(MGA_MISC_IN);
+ misc |= MGAREG_MISC_RAMMAPEN |
+ MGAREG_MISC_HIGH_PG_SEL;
+ WREG8(MGA_MISC_OUT, misc);
+
/* BAR 0 is VRAM */
start = pci_resource_start(dev->pdev, 0);
len = pci_resource_len(dev->pdev, 0);
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index e0d037a7413c..38672f9e5c4f 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -9,7 +9,6 @@
*/
#include <linux/delay.h>
-#include <linux/pci.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_state_helper.h>
@@ -109,10 +108,82 @@ static inline void mga_wait_busy(struct mga_device *mdev)
} while ((status & 0x01) && time_before(jiffies, timeout));
}
+/*
+ * PLL setup
+ */
+
+static int mgag200_g200_set_plls(struct mga_device *mdev, long clock)
+{
+ struct drm_device *dev = &mdev->base;
+ const int post_div_max = 7;
+ const int in_div_min = 1;
+ const int in_div_max = 6;
+ const int feed_div_min = 7;
+ const int feed_div_max = 127;
+ u8 testm, testn;
+ u8 n = 0, m = 0, p, s;
+ long f_vco;
+ long computed;
+ long delta, tmp_delta;
+ long ref_clk = mdev->model.g200.ref_clk;
+ long p_clk_min = mdev->model.g200.pclk_min;
+ long p_clk_max = mdev->model.g200.pclk_max;
+
+ if (clock > p_clk_max) {
+ drm_err(dev, "Pixel Clock %ld too high\n", clock);
+ return 1;
+ }
+
+ if (clock < p_clk_min >> 3)
+ clock = p_clk_min >> 3;
+
+ f_vco = clock;
+ for (p = 0;
+ p <= post_div_max && f_vco < p_clk_min;
+ p = (p << 1) + 1, f_vco <<= 1)
+ ;
+
+ delta = clock;
+
+ for (testm = in_div_min; testm <= in_div_max; testm++) {
+ for (testn = feed_div_min; testn <= feed_div_max; testn++) {
+ computed = ref_clk * (testn + 1) / (testm + 1);
+ if (computed < f_vco)
+ tmp_delta = f_vco - computed;
+ else
+ tmp_delta = computed - f_vco;
+ if (tmp_delta < delta) {
+ delta = tmp_delta;
+ m = testm;
+ n = testn;
+ }
+ }
+ }
+ f_vco = ref_clk * (n + 1) / (m + 1);
+ if (f_vco < 100000)
+ s = 0;
+ else if (f_vco < 140000)
+ s = 1;
+ else if (f_vco < 180000)
+ s = 2;
+ else
+ s = 3;
+
+ drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
+ clock, f_vco, m, n, p, s);
+
+ WREG_DAC(MGA1064_PIX_PLLC_M, m);
+ WREG_DAC(MGA1064_PIX_PLLC_N, n);
+ WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3)));
+
+ return 0;
+}
+
#define P_ARRAY_SIZE 9
static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
{
+ u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
unsigned int vcomax, vcomin, pllreffreq;
unsigned int delta, tmpdelta, permitteddelta;
unsigned int testp, testm, testn;
@@ -122,7 +193,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
unsigned int fvv;
unsigned int i;
- if (mdev->unique_rev_id <= 0x03) {
+ if (unique_rev_id <= 0x03) {
m = n = p = 0;
vcomax = 320000;
@@ -220,7 +291,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
WREG_DAC(MGA1064_PIX_PLLC_N, n);
WREG_DAC(MGA1064_PIX_PLLC_P, p);
- if (mdev->unique_rev_id >= 0x04) {
+ if (unique_rev_id >= 0x04) {
WREG_DAC(0x1a, 0x09);
msleep(20);
WREG_DAC(0x1a, 0x01);
@@ -717,6 +788,9 @@ static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock)
u8 misc;
switch(mdev->type) {
+ case G200_PCI:
+ case G200_AGP:
+ return mgag200_g200_set_plls(mdev, clock);
case G200_SE_A:
case G200_SE_B:
return mga_g200se_set_plls(mdev, clock);
@@ -877,45 +951,6 @@ static void mgag200_set_startadd(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
}
-static void mgag200_set_pci_regs(struct mga_device *mdev)
-{
- uint32_t option = 0, option2 = 0;
- struct drm_device *dev = &mdev->base;
-
- switch (mdev->type) {
- case G200_SE_A:
- case G200_SE_B:
- if (mdev->has_sdram)
- option = 0x40049120;
- else
- option = 0x4004d120;
- option2 = 0x00008000;
- break;
- case G200_WB:
- case G200_EW3:
- option = 0x41049120;
- option2 = 0x0000b000;
- break;
- case G200_EV:
- option = 0x00000120;
- option2 = 0x0000b000;
- break;
- case G200_EH:
- case G200_EH3:
- option = 0x00000120;
- option2 = 0x0000b000;
- break;
- case G200_ER:
- break;
- }
-
- if (option)
- pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
-
- if (option2)
- pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2);
-}
-
static void mgag200_set_dac_regs(struct mga_device *mdev)
{
size_t i;
@@ -933,6 +968,12 @@ static void mgag200_set_dac_regs(struct mga_device *mdev)
};
switch (mdev->type) {
+ case G200_PCI:
+ case G200_AGP:
+ dacvalue[MGA1064_SYS_PLL_M] = 0x04;
+ dacvalue[MGA1064_SYS_PLL_N] = 0x2D;
+ dacvalue[MGA1064_SYS_PLL_P] = 0x19;
+ break;
case G200_SE_A:
case G200_SE_B:
dacvalue[MGA1064_VREF_CTL] = 0x03;
@@ -986,9 +1027,8 @@ static void mgag200_set_dac_regs(struct mga_device *mdev)
static void mgag200_init_regs(struct mga_device *mdev)
{
- u8 crtc11, crtcext3, crtcext4, misc;
+ u8 crtc11, misc;
- mgag200_set_pci_regs(mdev);
mgag200_set_dac_regs(mdev);
WREG_SEQ(2, 0x0f);
@@ -1002,14 +1042,6 @@ static void mgag200_init_regs(struct mga_device *mdev)
WREG_CRT(14, 0);
WREG_CRT(15, 0);
- RREG_ECRT(0x03, crtcext3);
-
- crtcext3 |= BIT(7); /* enable MGA mode */
- crtcext4 = 0x00;
-
- WREG_ECRT(0x03, crtcext3);
- WREG_ECRT(0x04, crtcext4);
-
RREG_CRT(0x11, crtc11);
crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT |
MGAREG_CRTC11_VINTEN |
@@ -1023,9 +1055,7 @@ static void mgag200_init_regs(struct mga_device *mdev)
WREG_ECRT(0x34, 0x5);
misc = RREG8(MGA_MISC_IN);
- misc |= MGAREG_MISC_IOADSEL |
- MGAREG_MISC_RAMMAPEN |
- MGAREG_MISC_HIGH_PG_SEL;
+ misc |= MGAREG_MISC_IOADSEL;
WREG8(MGA_MISC_OUT, misc);
}
@@ -1234,12 +1264,13 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
const struct drm_display_mode *mode,
const struct drm_framebuffer *fb)
{
+ u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
unsigned int hiprilvl;
u8 crtcext6;
- if (mdev->unique_rev_id >= 0x04) {
+ if (unique_rev_id >= 0x04) {
hiprilvl = 0;
- } else if (mdev->unique_rev_id >= 0x02) {
+ } else if (unique_rev_id >= 0x02) {
unsigned int bpp;
unsigned long mb;
@@ -1264,7 +1295,7 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
else
hiprilvl = 5;
- } else if (mdev->unique_rev_id >= 0x01) {
+ } else if (unique_rev_id >= 0x01) {
hiprilvl = 3;
} else {
hiprilvl = 4;
@@ -1388,7 +1419,9 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
int bpp = 32;
if (IS_G200_SE(mdev)) {
- if (mdev->unique_rev_id == 0x01) {
+ u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
+
+ if (unique_rev_id == 0x01) {
if (mode->hdisplay > 1600)
return MODE_VIRTUAL_X;
if (mode->vdisplay > 1200)
@@ -1396,7 +1429,7 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
if (mga_vga_calculate_mode_bandwidth(mode, bpp)
> (24400 * 1024))
return MODE_BANDWIDTH;
- } else if (mdev->unique_rev_id == 0x02) {
+ } else if (unique_rev_id == 0x02) {
if (mode->hdisplay > 1920)
return MODE_VIRTUAL_X;
if (mode->vdisplay > 1200)
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h
index c3b7bcad52ed..977be0565c06 100644
--- a/drivers/gpu/drm/mgag200/mgag200_reg.h
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -256,6 +256,8 @@
#define MGAREG_CRTCEXT1_VSYNCOFF BIT(5)
#define MGAREG_CRTCEXT1_HSYNCOFF BIT(4)
+#define MGAREG_CRTCEXT3_MGAMODE BIT(7)
+
/* Cursor X and Y position */
#define MGA_CURPOSXL 0x3c0c
#define MGA_CURPOSXH 0x3c0d
@@ -282,6 +284,8 @@
#define PCI_MGA_OPTION2 0x50
#define PCI_MGA_OPTION3 0x54
+#define PCI_MGA_OPTION_HARDPWMSK BIT(14)
+
#define RAMDAC_OFFSET 0x3c00
/* TVP3026 direct registers */
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
index c7df71e2fafc..7288041dd86a 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
@@ -50,14 +50,9 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
struct drm_panel *panel = mdp4_lvds_connector->panel;
int ret = 0;
- if (panel) {
- drm_panel_attach(panel, connector);
-
+ if (panel)
ret = drm_panel_get_modes(panel, connector);
- drm_panel_detach(panel);
- }
-
return ret;
}
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 4b363bd7ddff..1d28dfba2c9b 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -328,7 +328,6 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
* In dual DSI mode, we have one connector that can be
* attached to the drm_panel.
*/
- drm_panel_attach(panel, connector);
num = drm_panel_get_modes(panel, connector);
if (!num)
return 0;
diff --git a/drivers/gpu/drm/mxsfb/Kconfig b/drivers/gpu/drm/mxsfb/Kconfig
index 0dca8f27169e..0143d539f8f8 100644
--- a/drivers/gpu/drm/mxsfb/Kconfig
+++ b/drivers/gpu/drm/mxsfb/Kconfig
@@ -5,7 +5,7 @@ config DRM_MXS
Choose this option to select drivers for MXS FB devices
config DRM_MXSFB
- tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller"
+ tristate "i.MX (e)LCDIF LCD controller"
depends on DRM && OF
depends on COMMON_CLK
select DRM_MXS
@@ -13,8 +13,10 @@ config DRM_MXSFB
select DRM_KMS_FB_HELPER
select DRM_KMS_CMA_HELPER
select DRM_PANEL
+ select DRM_PANEL_BRIDGE
help
- Choose this option if you have an i.MX23/i.MX28/i.MX6SX MXSFB
- LCD controller.
+ Choose this option if you have an LCDIF or eLCDIF LCD controller.
+ Those devices are found in various i.MX SoC (including i.MX23,
+ i.MX28, i.MX6SX, i.MX7 and i.MX8M).
If M is selected the module will be called mxsfb.
diff --git a/drivers/gpu/drm/mxsfb/Makefile b/drivers/gpu/drm/mxsfb/Makefile
index ff6e358088fa..26d153896d72 100644
--- a/drivers/gpu/drm/mxsfb/Makefile
+++ b/drivers/gpu/drm/mxsfb/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-mxsfb-y := mxsfb_drv.o mxsfb_crtc.o mxsfb_out.o
+mxsfb-y := mxsfb_drv.o mxsfb_kms.o
obj-$(CONFIG_DRM_MXSFB) += mxsfb.o
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
deleted file mode 100644
index b69ace8bf526..000000000000
--- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
+++ /dev/null
@@ -1,343 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Marek Vasut <marex@denx.de>
- *
- * This code is based on drivers/video/fbdev/mxsfb.c :
- * Copyright (C) 2010 Juergen Beisert, Pengutronix
- * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-#include <linux/clk.h>
-#include <linux/iopoll.h>
-#include <linux/of_graph.h>
-#include <linux/platform_data/simplefb.h>
-
-#include <video/videomode.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_of.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
-#include <drm/drm_vblank.h>
-
-#include "mxsfb_drv.h"
-#include "mxsfb_regs.h"
-
-#define MXS_SET_ADDR 0x4
-#define MXS_CLR_ADDR 0x8
-#define MODULE_CLKGATE BIT(30)
-#define MODULE_SFTRST BIT(31)
-/* 1 second delay should be plenty of time for block reset */
-#define RESET_TIMEOUT 1000000
-
-static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
-{
- return (val & mxsfb->devdata->hs_wdth_mask) <<
- mxsfb->devdata->hs_wdth_shift;
-}
-
-/* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
-static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
-{
- struct drm_crtc *crtc = &mxsfb->pipe.crtc;
- struct drm_device *drm = crtc->dev;
- const u32 format = crtc->primary->state->fb->format->format;
- u32 ctrl, ctrl1;
-
- ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
-
- /*
- * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
- * match the selected mode here. This differs from the original
- * MXSFB driver, which had the option to configure the bus width
- * to arbitrary value. This limitation should not pose an issue.
- */
-
- /* CTRL1 contains IRQ config and status bits, preserve those. */
- ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
- ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
-
- switch (format) {
- case DRM_FORMAT_RGB565:
- dev_dbg(drm->dev, "Setting up RGB565 mode\n");
- ctrl |= CTRL_SET_WORD_LENGTH(0);
- ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
- break;
- case DRM_FORMAT_XRGB8888:
- dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
- ctrl |= CTRL_SET_WORD_LENGTH(3);
- /* Do not use packed pixels = one pixel per word instead. */
- ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
- break;
- default:
- dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
- return -EINVAL;
- }
-
- writel(ctrl1, mxsfb->base + LCDC_CTRL1);
- writel(ctrl, mxsfb->base + LCDC_CTRL);
-
- return 0;
-}
-
-static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
-{
- struct drm_crtc *crtc = &mxsfb->pipe.crtc;
- struct drm_device *drm = crtc->dev;
- u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
- u32 reg;
-
- reg = readl(mxsfb->base + LCDC_CTRL);
-
- if (mxsfb->connector->display_info.num_bus_formats)
- bus_format = mxsfb->connector->display_info.bus_formats[0];
-
- DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
- bus_format);
-
- reg &= ~CTRL_BUS_WIDTH_MASK;
- switch (bus_format) {
- case MEDIA_BUS_FMT_RGB565_1X16:
- reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
- break;
- case MEDIA_BUS_FMT_RGB666_1X18:
- reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
- break;
- case MEDIA_BUS_FMT_RGB888_1X24:
- reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
- break;
- default:
- dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
- break;
- }
- writel(reg, mxsfb->base + LCDC_CTRL);
-}
-
-static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
-{
- u32 reg;
-
- if (mxsfb->clk_disp_axi)
- clk_prepare_enable(mxsfb->clk_disp_axi);
- clk_prepare_enable(mxsfb->clk);
-
- /* If it was disabled, re-enable the mode again */
- writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
-
- /* Enable the SYNC signals first, then the DMA engine */
- reg = readl(mxsfb->base + LCDC_VDCTRL4);
- reg |= VDCTRL4_SYNC_SIGNALS_ON;
- writel(reg, mxsfb->base + LCDC_VDCTRL4);
-
- writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
-}
-
-static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
-{
- u32 reg;
-
- /*
- * Even if we disable the controller here, it will still continue
- * until its FIFOs are running out of data
- */
- writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
-
- readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
- 0, 1000);
-
- reg = readl(mxsfb->base + LCDC_VDCTRL4);
- reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
- writel(reg, mxsfb->base + LCDC_VDCTRL4);
-
- clk_disable_unprepare(mxsfb->clk);
- if (mxsfb->clk_disp_axi)
- clk_disable_unprepare(mxsfb->clk_disp_axi);
-}
-
-/*
- * Clear the bit and poll it cleared. This is usually called with
- * a reset address and mask being either SFTRST(bit 31) or CLKGATE
- * (bit 30).
- */
-static int clear_poll_bit(void __iomem *addr, u32 mask)
-{
- u32 reg;
-
- writel(mask, addr + MXS_CLR_ADDR);
- return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
-}
-
-static int mxsfb_reset_block(void __iomem *reset_addr)
-{
- int ret;
-
- ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
- if (ret)
- return ret;
-
- writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
-
- ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
- if (ret)
- return ret;
-
- return clear_poll_bit(reset_addr, MODULE_CLKGATE);
-}
-
-static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb)
-{
- struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb;
- struct drm_gem_cma_object *gem;
-
- if (!fb)
- return 0;
-
- gem = drm_fb_cma_get_gem_obj(fb, 0);
- if (!gem)
- return 0;
-
- return gem->paddr;
-}
-
-static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
-{
- struct drm_device *drm = mxsfb->pipe.crtc.dev;
- struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
- u32 bus_flags = mxsfb->connector->display_info.bus_flags;
- u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
- int err;
-
- /*
- * It seems, you can't re-program the controller if it is still
- * running. This may lead to shifted pictures (FIFO issue?), so
- * first stop the controller and drain its FIFOs.
- */
-
- /* Mandatory eLCDIF reset as per the Reference Manual */
- err = mxsfb_reset_block(mxsfb->base);
- if (err)
- return;
-
- /* Clear the FIFOs */
- writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
-
- err = mxsfb_set_pixel_fmt(mxsfb);
- if (err)
- return;
-
- clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
-
- if (mxsfb->bridge && mxsfb->bridge->timings)
- bus_flags = mxsfb->bridge->timings->input_bus_flags;
-
- DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
- m->crtc_clock,
- (int)(clk_get_rate(mxsfb->clk) / 1000));
- DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
- bus_flags);
- DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
-
- writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
- TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
- mxsfb->base + mxsfb->devdata->transfer_count);
-
- vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
-
- vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */
- VDCTRL0_VSYNC_PERIOD_UNIT |
- VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
- VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
- if (m->flags & DRM_MODE_FLAG_PHSYNC)
- vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
- if (m->flags & DRM_MODE_FLAG_PVSYNC)
- vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
- /* Make sure Data Enable is high active by default */
- if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
- vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
- /*
- * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
- * controllers VDCTRL0_DOTCLK is display centric.
- * Drive on positive edge -> display samples on falling edge
- * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
- */
- if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
- vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
-
- writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
-
- mxsfb_set_bus_fmt(mxsfb);
-
- /* Frame length in lines. */
- writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
-
- /* Line length in units of clocks or pixels. */
- hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
- writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
- VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
- mxsfb->base + LCDC_VDCTRL2);
-
- writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
- SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
- mxsfb->base + LCDC_VDCTRL3);
-
- writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
- mxsfb->base + LCDC_VDCTRL4);
-}
-
-void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
-{
- dma_addr_t paddr;
-
- mxsfb_enable_axi_clk(mxsfb);
- mxsfb_crtc_mode_set_nofb(mxsfb);
-
- /* Write cur_buf as well to avoid an initial corrupt frame */
- paddr = mxsfb_get_fb_paddr(mxsfb);
- if (paddr) {
- writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
- writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
- }
-
- mxsfb_enable_controller(mxsfb);
-}
-
-void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
-{
- mxsfb_disable_controller(mxsfb);
- mxsfb_disable_axi_clk(mxsfb);
-}
-
-void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
- struct drm_plane_state *state)
-{
- struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_pending_vblank_event *event;
- dma_addr_t paddr;
-
- spin_lock_irq(&crtc->dev->event_lock);
- event = crtc->state->event;
- if (event) {
- crtc->state->event = NULL;
-
- if (drm_crtc_vblank_get(crtc) == 0) {
- drm_crtc_arm_vblank_event(crtc, event);
- } else {
- drm_crtc_send_vblank_event(crtc, event);
- }
- }
- spin_unlock_irq(&crtc->dev->event_lock);
-
- paddr = mxsfb_get_fb_paddr(mxsfb);
- if (paddr) {
- mxsfb_enable_axi_clk(mxsfb);
- writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
- mxsfb_disable_axi_clk(mxsfb);
- }
-}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
index 508764fccd27..8c549c3931af 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -9,30 +9,24 @@
*/
#include <linux/clk.h>
-#include <linux/component.h>
#include <linux/dma-mapping.h>
-#include <linux/list.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
-#include <linux/of_graph.h>
-#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <linux/dma-resv.h>
-#include <linux/spinlock.h>
-#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_irq.h>
+#include <drm/drm_mode_config.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_vblank.h>
#include "mxsfb_drv.h"
@@ -41,6 +35,11 @@
enum mxsfb_devtype {
MXSFB_V3,
MXSFB_V4,
+ /*
+ * Starting at i.MX6 the hardware version register is gone, use the
+ * i.MX family number as the version.
+ */
+ MXSFB_V6,
};
static const struct mxsfb_devdata mxsfb_devdata[] = {
@@ -48,38 +47,28 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
.transfer_count = LCDC_V3_TRANSFER_COUNT,
.cur_buf = LCDC_V3_CUR_BUF,
.next_buf = LCDC_V3_NEXT_BUF,
- .debug0 = LCDC_V3_DEBUG0,
.hs_wdth_mask = 0xff,
.hs_wdth_shift = 24,
- .ipversion = 3,
+ .has_overlay = false,
},
[MXSFB_V4] = {
.transfer_count = LCDC_V4_TRANSFER_COUNT,
.cur_buf = LCDC_V4_CUR_BUF,
.next_buf = LCDC_V4_NEXT_BUF,
- .debug0 = LCDC_V4_DEBUG0,
.hs_wdth_mask = 0x3fff,
.hs_wdth_shift = 18,
- .ipversion = 4,
+ .has_overlay = false,
+ },
+ [MXSFB_V6] = {
+ .transfer_count = LCDC_V4_TRANSFER_COUNT,
+ .cur_buf = LCDC_V4_CUR_BUF,
+ .next_buf = LCDC_V4_NEXT_BUF,
+ .hs_wdth_mask = 0x3fff,
+ .hs_wdth_shift = 18,
+ .has_overlay = true,
},
};
-static const uint32_t mxsfb_formats[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_RGB565
-};
-
-static const uint64_t mxsfb_modifiers[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_INVALID
-};
-
-static struct mxsfb_drm_private *
-drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
-{
- return container_of(pipe, struct mxsfb_drm_private, pipe);
-}
-
void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb)
{
if (mxsfb->clk_axi)
@@ -102,101 +91,51 @@ static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = {
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
};
-static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *crtc_state,
- struct drm_plane_state *plane_state)
+static int mxsfb_attach_bridge(struct mxsfb_drm_private *mxsfb)
{
- struct drm_connector *connector;
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
- struct drm_device *drm = pipe->plane.dev;
-
- if (!mxsfb->connector) {
- list_for_each_entry(connector,
- &drm->mode_config.connector_list,
- head)
- if (connector->encoder == &mxsfb->pipe.encoder) {
- mxsfb->connector = connector;
- break;
- }
- }
-
- if (!mxsfb->connector) {
- dev_warn(drm->dev, "No connector attached, using default\n");
- mxsfb->connector = &mxsfb->panel_connector;
- }
-
- pm_runtime_get_sync(drm->dev);
- drm_panel_prepare(mxsfb->panel);
- mxsfb_crtc_enable(mxsfb);
- drm_panel_enable(mxsfb->panel);
-}
+ struct drm_device *drm = mxsfb->drm;
+ struct drm_connector_list_iter iter;
+ struct drm_panel *panel;
+ struct drm_bridge *bridge;
+ int ret;
-static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
-{
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
- struct drm_device *drm = pipe->plane.dev;
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_pending_vblank_event *event;
-
- drm_panel_disable(mxsfb->panel);
- mxsfb_crtc_disable(mxsfb);
- drm_panel_unprepare(mxsfb->panel);
- pm_runtime_put_sync(drm->dev);
+ ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel,
+ &bridge);
+ if (ret)
+ return ret;
- spin_lock_irq(&drm->event_lock);
- event = crtc->state->event;
- if (event) {
- crtc->state->event = NULL;
- drm_crtc_send_vblank_event(crtc, event);
+ if (panel) {
+ bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel,
+ DRM_MODE_CONNECTOR_DPI);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
}
- spin_unlock_irq(&drm->event_lock);
- if (mxsfb->connector != &mxsfb->panel_connector)
- mxsfb->connector = NULL;
-}
-
-static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state)
-{
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+ if (!bridge)
+ return -ENODEV;
- mxsfb_plane_atomic_update(mxsfb, plane_state);
-}
+ ret = drm_bridge_attach(&mxsfb->encoder, bridge, NULL, 0);
+ if (ret) {
+ DRM_DEV_ERROR(drm->dev,
+ "failed to attach bridge: %d\n", ret);
+ return ret;
+ }
-static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
-{
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+ mxsfb->bridge = bridge;
- /* Clear and enable VBLANK IRQ */
- mxsfb_enable_axi_clk(mxsfb);
- writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
- writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
- mxsfb_disable_axi_clk(mxsfb);
+ /*
+ * Get hold of the connector. This is a bit of a hack, until the bridge
+ * API gives us bus flags and formats.
+ */
+ drm_connector_list_iter_begin(drm, &iter);
+ mxsfb->connector = drm_connector_list_iter_next(&iter);
+ drm_connector_list_iter_end(&iter);
return 0;
}
-static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe)
-{
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
-
- /* Disable and clear VBLANK IRQ */
- mxsfb_enable_axi_clk(mxsfb);
- writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
- writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
- mxsfb_disable_axi_clk(mxsfb);
-}
-
-static struct drm_simple_display_pipe_funcs mxsfb_funcs = {
- .enable = mxsfb_pipe_enable,
- .disable = mxsfb_pipe_disable,
- .update = mxsfb_pipe_update,
- .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
- .enable_vblank = mxsfb_pipe_enable_vblank,
- .disable_vblank = mxsfb_pipe_disable_vblank,
-};
-
-static int mxsfb_load(struct drm_device *drm)
+static int mxsfb_load(struct drm_device *drm,
+ const struct mxsfb_devdata *devdata)
{
struct platform_device *pdev = to_platform_device(drm->dev);
struct mxsfb_drm_private *mxsfb;
@@ -207,8 +146,9 @@ static int mxsfb_load(struct drm_device *drm)
if (!mxsfb)
return -ENOMEM;
+ mxsfb->drm = drm;
drm->dev_private = mxsfb;
- mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+ mxsfb->devdata = devdata;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mxsfb->base = devm_ioremap_resource(drm->dev, res);
@@ -233,50 +173,28 @@ static int mxsfb_load(struct drm_device *drm)
pm_runtime_enable(drm->dev);
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
- if (ret < 0) {
- dev_err(drm->dev, "Failed to initialise vblank\n");
- goto err_vblank;
- }
-
/* Modeset init */
drm_mode_config_init(drm);
- ret = mxsfb_create_output(drm);
+ ret = mxsfb_kms_init(mxsfb);
if (ret < 0) {
- dev_err(drm->dev, "Failed to create outputs\n");
+ dev_err(drm->dev, "Failed to initialize KMS pipeline\n");
goto err_vblank;
}
- ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
- mxsfb_formats, ARRAY_SIZE(mxsfb_formats),
- mxsfb_modifiers, mxsfb->connector);
+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (ret < 0) {
- dev_err(drm->dev, "Cannot setup simple display pipe\n");
+ dev_err(drm->dev, "Failed to initialise vblank\n");
goto err_vblank;
}
- /*
- * Attach panel only if there is one.
- * If there is no panel attach, it must be a bridge. In this case, we
- * need a reference to its connector for a proper initialization.
- * We will do this check in pipe->enable(), since the connector won't
- * be attached to an encoder until then.
- */
+ /* Start with vertical blanking interrupt reporting disabled. */
+ drm_crtc_vblank_off(&mxsfb->crtc);
- if (mxsfb->panel) {
- ret = drm_panel_attach(mxsfb->panel, mxsfb->connector);
- if (ret) {
- dev_err(drm->dev, "Cannot connect panel: %d\n", ret);
- goto err_vblank;
- }
- } else if (mxsfb->bridge) {
- ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe,
- mxsfb->bridge);
- if (ret) {
- dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
- goto err_vblank;
- }
+ ret = mxsfb_attach_bridge(mxsfb);
+ if (ret) {
+ dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
+ goto err_vblank;
}
drm->mode_config.min_width = MXSFB_MIN_XRES;
@@ -294,7 +212,7 @@ static int mxsfb_load(struct drm_device *drm)
if (ret < 0) {
dev_err(drm->dev, "Failed to install IRQ handler\n");
- goto err_irq;
+ goto err_vblank;
}
drm_kms_helper_poll_init(drm);
@@ -305,8 +223,6 @@ static int mxsfb_load(struct drm_device *drm)
return 0;
-err_irq:
- drm_panel_detach(mxsfb->panel);
err_vblank:
pm_runtime_disable(drm->dev);
@@ -327,11 +243,13 @@ static void mxsfb_unload(struct drm_device *drm)
pm_runtime_disable(drm->dev);
}
-static void mxsfb_irq_preinstall(struct drm_device *drm)
+static void mxsfb_irq_disable(struct drm_device *drm)
{
struct mxsfb_drm_private *mxsfb = drm->dev_private;
- mxsfb_pipe_disable_vblank(&mxsfb->pipe);
+ mxsfb_enable_axi_clk(mxsfb);
+ mxsfb->crtc.funcs->disable_vblank(&mxsfb->crtc);
+ mxsfb_disable_axi_clk(mxsfb);
}
static irqreturn_t mxsfb_irq_handler(int irq, void *data)
@@ -340,17 +258,13 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data)
struct mxsfb_drm_private *mxsfb = drm->dev_private;
u32 reg;
- mxsfb_enable_axi_clk(mxsfb);
-
reg = readl(mxsfb->base + LCDC_CTRL1);
if (reg & CTRL1_CUR_FRAME_DONE_IRQ)
- drm_crtc_handle_vblank(&mxsfb->pipe.crtc);
+ drm_crtc_handle_vblank(&mxsfb->crtc);
writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
- mxsfb_disable_axi_clk(mxsfb);
-
return IRQ_HANDLED;
}
@@ -359,8 +273,8 @@ DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver mxsfb_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.irq_handler = mxsfb_irq_handler,
- .irq_preinstall = mxsfb_irq_preinstall,
- .irq_uninstall = mxsfb_irq_preinstall,
+ .irq_preinstall = mxsfb_irq_disable,
+ .irq_uninstall = mxsfb_irq_disable,
DRM_GEM_CMA_DRIVER_OPS,
.fops = &fops,
.name = "mxsfb-drm",
@@ -370,18 +284,10 @@ static struct drm_driver mxsfb_driver = {
.minor = 0,
};
-static const struct platform_device_id mxsfb_devtype[] = {
- { .name = "imx23-fb", .driver_data = MXSFB_V3, },
- { .name = "imx28-fb", .driver_data = MXSFB_V4, },
- { .name = "imx6sx-fb", .driver_data = MXSFB_V4, },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
-
static const struct of_device_id mxsfb_dt_ids[] = {
- { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
- { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
- { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], },
+ { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devdata[MXSFB_V3], },
+ { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devdata[MXSFB_V4], },
+ { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devdata[MXSFB_V6], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
@@ -396,14 +302,11 @@ static int mxsfb_probe(struct platform_device *pdev)
if (!pdev->dev.of_node)
return -ENODEV;
- if (of_id)
- pdev->id_entry = of_id->data;
-
drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
- ret = mxsfb_load(drm);
+ ret = mxsfb_load(drm, of_id->data);
if (ret)
goto err_free;
@@ -457,7 +360,6 @@ static const struct dev_pm_ops mxsfb_pm_ops = {
static struct platform_driver mxsfb_platform_driver = {
.probe = mxsfb_probe,
.remove = mxsfb_remove,
- .id_table = mxsfb_devtype,
.driver = {
.name = "mxsfb",
.of_match_table = mxsfb_dt_ids,
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
index 0b65b5194a9c..399d23e91ed1 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
@@ -8,14 +8,20 @@
#ifndef __MXSFB_DRV_H__
#define __MXSFB_DRV_H__
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_plane.h>
+
+struct clk;
+
struct mxsfb_devdata {
- unsigned int transfer_count;
- unsigned int cur_buf;
- unsigned int next_buf;
- unsigned int debug0;
- unsigned int hs_wdth_mask;
- unsigned int hs_wdth_shift;
- unsigned int ipversion;
+ unsigned int transfer_count;
+ unsigned int cur_buf;
+ unsigned int next_buf;
+ unsigned int hs_wdth_mask;
+ unsigned int hs_wdth_shift;
+ bool has_overlay;
};
struct mxsfb_drm_private {
@@ -26,22 +32,26 @@ struct mxsfb_drm_private {
struct clk *clk_axi;
struct clk *clk_disp_axi;
- struct drm_simple_display_pipe pipe;
- struct drm_connector panel_connector;
+ struct drm_device *drm;
+ struct {
+ struct drm_plane primary;
+ struct drm_plane overlay;
+ } planes;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
struct drm_connector *connector;
- struct drm_panel *panel;
struct drm_bridge *bridge;
};
-int mxsfb_setup_crtc(struct drm_device *dev);
-int mxsfb_create_output(struct drm_device *dev);
+static inline struct mxsfb_drm_private *
+to_mxsfb_drm_private(struct drm_device *drm)
+{
+ return drm->dev_private;
+}
void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb);
void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb);
-void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb);
-void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
-void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
- struct drm_plane_state *state);
+int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb);
#endif /* __MXSFB_DRV_H__ */
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c
new file mode 100644
index 000000000000..b721b8b262ce
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/mxsfb_kms.c
@@ -0,0 +1,571 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This code is based on drivers/video/fbdev/mxsfb.c :
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "mxsfb_drv.h"
+#include "mxsfb_regs.h"
+
+/* 1 second delay should be plenty of time for block reset */
+#define RESET_TIMEOUT 1000000
+
+/* -----------------------------------------------------------------------------
+ * CRTC
+ */
+
+static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
+{
+ return (val & mxsfb->devdata->hs_wdth_mask) <<
+ mxsfb->devdata->hs_wdth_shift;
+}
+
+/*
+ * Setup the MXSFB registers for decoding the pixels out of the framebuffer and
+ * outputting them on the bus.
+ */
+static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb)
+{
+ struct drm_device *drm = mxsfb->drm;
+ const u32 format = mxsfb->crtc.primary->state->fb->format->format;
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ u32 ctrl, ctrl1;
+
+ if (mxsfb->connector->display_info.num_bus_formats)
+ bus_format = mxsfb->connector->display_info.bus_formats[0];
+
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
+ bus_format);
+
+ ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
+
+ /* CTRL1 contains IRQ config and status bits, preserve those. */
+ ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
+ ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
+
+ switch (format) {
+ case DRM_FORMAT_RGB565:
+ dev_dbg(drm->dev, "Setting up RGB565 mode\n");
+ ctrl |= CTRL_WORD_LENGTH_16;
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+ break;
+ case DRM_FORMAT_XRGB8888:
+ dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
+ ctrl |= CTRL_WORD_LENGTH_24;
+ /* Do not use packed pixels = one pixel per word instead. */
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
+ break;
+ }
+
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ ctrl |= CTRL_BUS_WIDTH_16;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ ctrl |= CTRL_BUS_WIDTH_18;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ ctrl |= CTRL_BUS_WIDTH_24;
+ break;
+ default:
+ dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
+ break;
+ }
+
+ writel(ctrl1, mxsfb->base + LCDC_CTRL1);
+ writel(ctrl, mxsfb->base + LCDC_CTRL);
+}
+
+static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
+{
+ u32 reg;
+
+ if (mxsfb->clk_disp_axi)
+ clk_prepare_enable(mxsfb->clk_disp_axi);
+ clk_prepare_enable(mxsfb->clk);
+
+ /* If it was disabled, re-enable the mode again */
+ writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
+
+ /* Enable the SYNC signals first, then the DMA engine */
+ reg = readl(mxsfb->base + LCDC_VDCTRL4);
+ reg |= VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+ writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
+}
+
+static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
+{
+ u32 reg;
+
+ /*
+ * Even if we disable the controller here, it will still continue
+ * until its FIFOs are running out of data
+ */
+ writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+ readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
+ 0, 1000);
+
+ reg = readl(mxsfb->base + LCDC_VDCTRL4);
+ reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+ clk_disable_unprepare(mxsfb->clk);
+ if (mxsfb->clk_disp_axi)
+ clk_disable_unprepare(mxsfb->clk_disp_axi);
+}
+
+/*
+ * Clear the bit and poll it cleared. This is usually called with
+ * a reset address and mask being either SFTRST(bit 31) or CLKGATE
+ * (bit 30).
+ */
+static int clear_poll_bit(void __iomem *addr, u32 mask)
+{
+ u32 reg;
+
+ writel(mask, addr + REG_CLR);
+ return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
+}
+
+static int mxsfb_reset_block(struct mxsfb_drm_private *mxsfb)
+{
+ int ret;
+
+ ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
+ if (ret)
+ return ret;
+
+ writel(CTRL_CLKGATE, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+ ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
+ if (ret)
+ return ret;
+
+ return clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_CLKGATE);
+}
+
+static dma_addr_t mxsfb_get_fb_paddr(struct drm_plane *plane)
+{
+ struct drm_framebuffer *fb = plane->state->fb;
+ struct drm_gem_cma_object *gem;
+
+ if (!fb)
+ return 0;
+
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
+ if (!gem)
+ return 0;
+
+ return gem->paddr;
+}
+
+static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
+{
+ struct drm_device *drm = mxsfb->crtc.dev;
+ struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode;
+ u32 bus_flags = mxsfb->connector->display_info.bus_flags;
+ u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
+ int err;
+
+ /*
+ * It seems, you can't re-program the controller if it is still
+ * running. This may lead to shifted pictures (FIFO issue?), so
+ * first stop the controller and drain its FIFOs.
+ */
+
+ /* Mandatory eLCDIF reset as per the Reference Manual */
+ err = mxsfb_reset_block(mxsfb);
+ if (err)
+ return;
+
+ /* Clear the FIFOs */
+ writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
+
+ if (mxsfb->devdata->has_overlay)
+ writel(0, mxsfb->base + LCDC_AS_CTRL);
+
+ mxsfb_set_formats(mxsfb);
+
+ clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
+
+ if (mxsfb->bridge && mxsfb->bridge->timings)
+ bus_flags = mxsfb->bridge->timings->input_bus_flags;
+
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
+ m->crtc_clock,
+ (int)(clk_get_rate(mxsfb->clk) / 1000));
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
+ bus_flags);
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
+
+ writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
+ TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
+ mxsfb->base + mxsfb->devdata->transfer_count);
+
+ vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
+
+ vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */
+ VDCTRL0_VSYNC_PERIOD_UNIT |
+ VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+ VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
+ if (m->flags & DRM_MODE_FLAG_PHSYNC)
+ vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+ if (m->flags & DRM_MODE_FLAG_PVSYNC)
+ vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+ /* Make sure Data Enable is high active by default */
+ if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
+ vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+ /*
+ * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
+ * controllers VDCTRL0_DOTCLK is display centric.
+ * Drive on positive edge -> display samples on falling edge
+ * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
+ */
+ if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
+ vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
+
+ writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
+
+ /* Frame length in lines. */
+ writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
+
+ /* Line length in units of clocks or pixels. */
+ hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
+ writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
+ VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
+ mxsfb->base + LCDC_VDCTRL2);
+
+ writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
+ SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
+ mxsfb->base + LCDC_VDCTRL3);
+
+ writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
+ mxsfb->base + LCDC_VDCTRL4);
+}
+
+static int mxsfb_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ bool has_primary = state->plane_mask &
+ drm_plane_mask(crtc->primary);
+
+ /* The primary plane has to be enabled when the CRTC is active. */
+ if (state->active && !has_primary)
+ return -EINVAL;
+
+ /* TODO: Is this needed ? */
+ return drm_atomic_add_affected_planes(state->state, crtc);
+}
+
+static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct drm_pending_vblank_event *event;
+
+ event = crtc->state->event;
+ crtc->state->event = NULL;
+
+ if (!event)
+ return;
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (drm_crtc_vblank_get(crtc) == 0)
+ drm_crtc_arm_vblank_event(crtc, event);
+ else
+ drm_crtc_send_vblank_event(crtc, event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+ struct drm_device *drm = mxsfb->drm;
+ dma_addr_t paddr;
+
+ pm_runtime_get_sync(drm->dev);
+ mxsfb_enable_axi_clk(mxsfb);
+
+ drm_crtc_vblank_on(crtc);
+
+ mxsfb_crtc_mode_set_nofb(mxsfb);
+
+ /* Write cur_buf as well to avoid an initial corrupt frame */
+ paddr = mxsfb_get_fb_paddr(crtc->primary);
+ if (paddr) {
+ writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
+ writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
+ }
+
+ mxsfb_enable_controller(mxsfb);
+}
+
+static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+ struct drm_device *drm = mxsfb->drm;
+ struct drm_pending_vblank_event *event;
+
+ mxsfb_disable_controller(mxsfb);
+
+ spin_lock_irq(&drm->event_lock);
+ event = crtc->state->event;
+ if (event) {
+ crtc->state->event = NULL;
+ drm_crtc_send_vblank_event(crtc, event);
+ }
+ spin_unlock_irq(&drm->event_lock);
+
+ drm_crtc_vblank_off(crtc);
+
+ mxsfb_disable_axi_clk(mxsfb);
+ pm_runtime_put_sync(drm->dev);
+}
+
+static int mxsfb_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+
+ /* Clear and enable VBLANK IRQ */
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
+
+ return 0;
+}
+
+static void mxsfb_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+
+ /* Disable and clear VBLANK IRQ */
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+}
+
+static const struct drm_crtc_helper_funcs mxsfb_crtc_helper_funcs = {
+ .atomic_check = mxsfb_crtc_atomic_check,
+ .atomic_flush = mxsfb_crtc_atomic_flush,
+ .atomic_enable = mxsfb_crtc_atomic_enable,
+ .atomic_disable = mxsfb_crtc_atomic_disable,
+};
+
+static const struct drm_crtc_funcs mxsfb_crtc_funcs = {
+ .reset = drm_atomic_helper_crtc_reset,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = mxsfb_crtc_enable_vblank,
+ .disable_vblank = mxsfb_crtc_disable_vblank,
+};
+
+/* -----------------------------------------------------------------------------
+ * Encoder
+ */
+
+static const struct drm_encoder_funcs mxsfb_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+/* -----------------------------------------------------------------------------
+ * Planes
+ */
+
+static int mxsfb_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *plane_state)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+ struct drm_crtc_state *crtc_state;
+
+ crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
+ &mxsfb->crtc);
+
+ return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ false, true);
+}
+
+static void mxsfb_plane_primary_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_pstate)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+ dma_addr_t paddr;
+
+ paddr = mxsfb_get_fb_paddr(plane);
+ if (paddr)
+ writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
+}
+
+static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_pstate)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+ struct drm_plane_state *state = plane->state;
+ dma_addr_t paddr;
+ u32 ctrl;
+
+ paddr = mxsfb_get_fb_paddr(plane);
+ if (!paddr) {
+ writel(0, mxsfb->base + LCDC_AS_CTRL);
+ return;
+ }
+
+ /*
+ * HACK: The hardware seems to output 64 bytes of data of unknown
+ * origin, and then to proceed with the framebuffer. Until the reason
+ * is understood, live with the 16 initial invalid pixels on the first
+ * line and start 64 bytes within the framebuffer.
+ */
+ paddr += 64;
+
+ writel(paddr, mxsfb->base + LCDC_AS_NEXT_BUF);
+
+ /*
+ * If the plane was previously disabled, write LCDC_AS_BUF as well to
+ * provide the first buffer.
+ */
+ if (!old_pstate->fb)
+ writel(paddr, mxsfb->base + LCDC_AS_BUF);
+
+ ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255);
+
+ switch (state->fb->format->format) {
+ case DRM_FORMAT_XRGB4444:
+ ctrl |= AS_CTRL_FORMAT_RGB444 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+ break;
+ case DRM_FORMAT_ARGB4444:
+ ctrl |= AS_CTRL_FORMAT_ARGB4444 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+ break;
+ case DRM_FORMAT_XRGB1555:
+ ctrl |= AS_CTRL_FORMAT_RGB555 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+ break;
+ case DRM_FORMAT_ARGB1555:
+ ctrl |= AS_CTRL_FORMAT_ARGB1555 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+ break;
+ case DRM_FORMAT_RGB565:
+ ctrl |= AS_CTRL_FORMAT_RGB565 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+ break;
+ case DRM_FORMAT_XRGB8888:
+ ctrl |= AS_CTRL_FORMAT_RGB888 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+ break;
+ case DRM_FORMAT_ARGB8888:
+ ctrl |= AS_CTRL_FORMAT_ARGB8888 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+ break;
+ }
+
+ writel(ctrl, mxsfb->base + LCDC_AS_CTRL);
+}
+
+static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = {
+ .atomic_check = mxsfb_plane_atomic_check,
+ .atomic_update = mxsfb_plane_primary_atomic_update,
+};
+
+static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = {
+ .atomic_check = mxsfb_plane_atomic_check,
+ .atomic_update = mxsfb_plane_overlay_atomic_update,
+};
+
+static const struct drm_plane_funcs mxsfb_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static const uint32_t mxsfb_primary_plane_formats[] = {
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
+};
+
+static const uint32_t mxsfb_overlay_plane_formats[] = {
+ DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+};
+
+static const uint64_t mxsfb_modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb)
+{
+ struct drm_encoder *encoder = &mxsfb->encoder;
+ struct drm_crtc *crtc = &mxsfb->crtc;
+ int ret;
+
+ drm_plane_helper_add(&mxsfb->planes.primary,
+ &mxsfb_plane_primary_helper_funcs);
+ ret = drm_universal_plane_init(mxsfb->drm, &mxsfb->planes.primary, 1,
+ &mxsfb_plane_funcs,
+ mxsfb_primary_plane_formats,
+ ARRAY_SIZE(mxsfb_primary_plane_formats),
+ mxsfb_modifiers, DRM_PLANE_TYPE_PRIMARY,
+ NULL);
+ if (ret)
+ return ret;
+
+ if (mxsfb->devdata->has_overlay) {
+ drm_plane_helper_add(&mxsfb->planes.overlay,
+ &mxsfb_plane_overlay_helper_funcs);
+ ret = drm_universal_plane_init(mxsfb->drm,
+ &mxsfb->planes.overlay, 1,
+ &mxsfb_plane_funcs,
+ mxsfb_overlay_plane_formats,
+ ARRAY_SIZE(mxsfb_overlay_plane_formats),
+ mxsfb_modifiers, DRM_PLANE_TYPE_OVERLAY,
+ NULL);
+ if (ret)
+ return ret;
+ }
+
+ drm_crtc_helper_add(crtc, &mxsfb_crtc_helper_funcs);
+ ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
+ &mxsfb->planes.primary, NULL,
+ &mxsfb_crtc_funcs, NULL);
+ if (ret)
+ return ret;
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ return drm_encoder_init(mxsfb->drm, encoder, &mxsfb_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
+}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c
deleted file mode 100644
index 9eca1605d11d..000000000000
--- a/drivers/gpu/drm/mxsfb/mxsfb_out.c
+++ /dev/null
@@ -1,99 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Marek Vasut <marex@denx.de>
- */
-
-#include <linux/of_graph.h>
-
-#include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
-
-#include "mxsfb_drv.h"
-
-static struct mxsfb_drm_private *
-drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
-{
- return container_of(connector, struct mxsfb_drm_private,
- panel_connector);
-}
-
-static int mxsfb_panel_get_modes(struct drm_connector *connector)
-{
- struct mxsfb_drm_private *mxsfb =
- drm_connector_to_mxsfb_drm_private(connector);
-
- if (mxsfb->panel)
- return drm_panel_get_modes(mxsfb->panel, connector);
-
- return 0;
-}
-
-static const struct
-drm_connector_helper_funcs mxsfb_panel_connector_helper_funcs = {
- .get_modes = mxsfb_panel_get_modes,
-};
-
-static enum drm_connector_status
-mxsfb_panel_connector_detect(struct drm_connector *connector, bool force)
-{
- struct mxsfb_drm_private *mxsfb =
- drm_connector_to_mxsfb_drm_private(connector);
-
- if (mxsfb->panel)
- return connector_status_connected;
-
- return connector_status_disconnected;
-}
-
-static void mxsfb_panel_connector_destroy(struct drm_connector *connector)
-{
- struct mxsfb_drm_private *mxsfb =
- drm_connector_to_mxsfb_drm_private(connector);
-
- if (mxsfb->panel)
- drm_panel_detach(mxsfb->panel);
-
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_funcs mxsfb_panel_connector_funcs = {
- .detect = mxsfb_panel_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = mxsfb_panel_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-int mxsfb_create_output(struct drm_device *drm)
-{
- struct mxsfb_drm_private *mxsfb = drm->dev_private;
- int ret;
-
- ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0,
- &mxsfb->panel, &mxsfb->bridge);
- if (ret)
- return ret;
-
- if (mxsfb->panel) {
- mxsfb->connector = &mxsfb->panel_connector;
- mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
- mxsfb->connector->polled = 0;
- drm_connector_helper_add(mxsfb->connector,
- &mxsfb_panel_connector_helper_funcs);
- ret = drm_connector_init(drm, mxsfb->connector,
- &mxsfb_panel_connector_funcs,
- DRM_MODE_CONNECTOR_Unknown);
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_regs.h b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
index 932d7ea08fd5..55d28a27f912 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_regs.h
+++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
@@ -27,52 +27,61 @@
#define LCDC_VDCTRL4 0xb0
#define LCDC_V4_DEBUG0 0x1d0
#define LCDC_V3_DEBUG0 0x1f0
-
-#define CTRL_SFTRST (1 << 31)
-#define CTRL_CLKGATE (1 << 30)
-#define CTRL_BYPASS_COUNT (1 << 19)
-#define CTRL_VSYNC_MODE (1 << 18)
-#define CTRL_DOTCLK_MODE (1 << 17)
-#define CTRL_DATA_SELECT (1 << 16)
-#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10)
-#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3)
+#define LCDC_AS_CTRL 0x210
+#define LCDC_AS_BUF 0x220
+#define LCDC_AS_NEXT_BUF 0x230
+#define LCDC_AS_CLRKEYLOW 0x240
+#define LCDC_AS_CLRKEYHIGH 0x250
+
+#define CTRL_SFTRST BIT(31)
+#define CTRL_CLKGATE BIT(30)
+#define CTRL_BYPASS_COUNT BIT(19)
+#define CTRL_VSYNC_MODE BIT(18)
+#define CTRL_DOTCLK_MODE BIT(17)
+#define CTRL_DATA_SELECT BIT(16)
+#define CTRL_BUS_WIDTH_16 (0 << 10)
+#define CTRL_BUS_WIDTH_8 (1 << 10)
+#define CTRL_BUS_WIDTH_18 (2 << 10)
+#define CTRL_BUS_WIDTH_24 (3 << 10)
#define CTRL_BUS_WIDTH_MASK (0x3 << 10)
-#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8)
-#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3)
-#define CTRL_MASTER (1 << 5)
-#define CTRL_DF16 (1 << 3)
-#define CTRL_DF18 (1 << 2)
-#define CTRL_DF24 (1 << 1)
-#define CTRL_RUN (1 << 0)
-
-#define CTRL1_FIFO_CLEAR (1 << 21)
+#define CTRL_WORD_LENGTH_16 (0 << 8)
+#define CTRL_WORD_LENGTH_8 (1 << 8)
+#define CTRL_WORD_LENGTH_18 (2 << 8)
+#define CTRL_WORD_LENGTH_24 (3 << 8)
+#define CTRL_MASTER BIT(5)
+#define CTRL_DF16 BIT(3)
+#define CTRL_DF18 BIT(2)
+#define CTRL_DF24 BIT(1)
+#define CTRL_RUN BIT(0)
+
+#define CTRL1_FIFO_CLEAR BIT(21)
#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
-#define CTRL1_CUR_FRAME_DONE_IRQ_EN (1 << 13)
-#define CTRL1_CUR_FRAME_DONE_IRQ (1 << 9)
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13)
+#define CTRL1_CUR_FRAME_DONE_IRQ BIT(9)
#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff)
-#define VDCTRL0_ENABLE_PRESENT (1 << 28)
-#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27)
-#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26)
-#define VDCTRL0_DOTCLK_ACT_FALLING (1 << 25)
-#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24)
-#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21)
-#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20)
-#define VDCTRL0_HALF_LINE (1 << 19)
-#define VDCTRL0_HALF_LINE_MODE (1 << 18)
+#define VDCTRL0_ENABLE_PRESENT BIT(28)
+#define VDCTRL0_VSYNC_ACT_HIGH BIT(27)
+#define VDCTRL0_HSYNC_ACT_HIGH BIT(26)
+#define VDCTRL0_DOTCLK_ACT_FALLING BIT(25)
+#define VDCTRL0_ENABLE_ACT_HIGH BIT(24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT BIT(21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT BIT(20)
+#define VDCTRL0_HALF_LINE BIT(19)
+#define VDCTRL0_HALF_LINE_MODE BIT(18)
#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
-#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29)
-#define VDCTRL3_VSYNC_ONLY (1 << 28)
+#define VDCTRL3_MUX_SYNC_SIGNALS BIT(29)
+#define VDCTRL3_VSYNC_ONLY BIT(28)
#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16)
#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff)
#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff)
@@ -80,28 +89,32 @@
#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */
#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */
-#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18)
+#define VDCTRL4_SYNC_SIGNALS_ON BIT(18)
#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
-#define DEBUG0_HSYNC (1 < 26)
-#define DEBUG0_VSYNC (1 < 25)
+#define DEBUG0_HSYNC BIT(26)
+#define DEBUG0_VSYNC BIT(25)
+
+#define AS_CTRL_PS_DISABLE BIT(23)
+#define AS_CTRL_ALPHA_INVERT BIT(20)
+#define AS_CTRL_ALPHA(a) (((a) & 0xff) << 8)
+#define AS_CTRL_FORMAT_RGB565 (0xe << 4)
+#define AS_CTRL_FORMAT_RGB444 (0xd << 4)
+#define AS_CTRL_FORMAT_RGB555 (0xc << 4)
+#define AS_CTRL_FORMAT_ARGB4444 (0x9 << 4)
+#define AS_CTRL_FORMAT_ARGB1555 (0x8 << 4)
+#define AS_CTRL_FORMAT_RGB888 (0x4 << 4)
+#define AS_CTRL_FORMAT_ARGB8888 (0x0 << 4)
+#define AS_CTRL_ENABLE_COLORKEY BIT(3)
+#define AS_CTRL_ALPHA_CTRL_ROP (3 << 1)
+#define AS_CTRL_ALPHA_CTRL_MULTIPLY (2 << 1)
+#define AS_CTRL_ALPHA_CTRL_OVERRIDE (1 << 1)
+#define AS_CTRL_ALPHA_CTRL_EMBEDDED (0 << 1)
+#define AS_CTRL_AS_ENABLE BIT(0)
#define MXSFB_MIN_XRES 120
#define MXSFB_MIN_YRES 120
#define MXSFB_MAX_XRES 0xffff
#define MXSFB_MAX_YRES 0xffff
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define TRANSP 3
-
-#define STMLCDIF_8BIT 1 /* pixel data bus to the display is of 8 bit width */
-#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */
-#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
-#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
-
-#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6)
-#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negative edge sampling */
-
#endif /* __MXSFB_REGS_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 7806278dce57..9140387f30dc 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -646,66 +646,6 @@ nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags)
return nouveau_sgdma_create_ttm(bo, page_flags);
}
-static int
-nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
- struct ttm_mem_type_manager *man)
-{
- struct nouveau_drm *drm = nouveau_bdev(bdev);
- struct nvif_mmu *mmu = &drm->client.mmu;
-
- switch (type) {
- case TTM_PL_SYSTEM:
- man->flags = 0;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- case TTM_PL_VRAM:
- man->flags = TTM_MEMTYPE_FLAG_FIXED;
- man->available_caching = TTM_PL_FLAG_UNCACHED |
- TTM_PL_FLAG_WC;
- man->default_caching = TTM_PL_FLAG_WC;
-
- if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
- /* Some BARs do not support being ioremapped WC */
- const u8 type = mmu->type[drm->ttm.type_vram].type;
- if (type & NVIF_MEM_UNCACHED) {
- man->available_caching = TTM_PL_FLAG_UNCACHED;
- man->default_caching = TTM_PL_FLAG_UNCACHED;
- }
-
- man->func = &nouveau_vram_manager;
- man->use_io_reserve_lru = true;
- } else {
- man->func = &ttm_bo_manager_func;
- }
- break;
- case TTM_PL_TT:
- if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)
- man->func = &nouveau_gart_manager;
- else
- if (!drm->agp.bridge)
- man->func = &nv04_gart_manager;
- else
- man->func = &ttm_bo_manager_func;
-
- if (drm->agp.bridge) {
- man->flags = 0;
- man->available_caching = TTM_PL_FLAG_UNCACHED |
- TTM_PL_FLAG_WC;
- man->default_caching = TTM_PL_FLAG_WC;
- } else {
- man->flags = 0;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- }
-
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
static void
nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
{
@@ -726,7 +666,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
static int
nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
- struct ttm_mem_reg *reg)
+ struct ttm_resource *reg)
{
struct nouveau_mem *old_mem = nouveau_mem(&bo->mem);
struct nouveau_mem *new_mem = nouveau_mem(reg);
@@ -758,7 +698,7 @@ done:
static int
nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
- bool no_wait_gpu, struct ttm_mem_reg *new_reg)
+ bool no_wait_gpu, struct ttm_resource *new_reg)
{
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_channel *chan = drm->ttm.chan;
@@ -768,7 +708,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
/* create temporary vmas for the transfer and attach them to the
* old nvkm_mem node, these will get cleaned up after ttm has
- * destroyed the ttm_mem_reg
+ * destroyed the ttm_resource
*/
if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
ret = nouveau_bo_move_prep(drm, bo, new_reg);
@@ -804,7 +744,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
s32 oclass;
int (*exec)(struct nouveau_channel *,
struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
int (*init)(struct nouveau_channel *, u32 handle);
} _methods[] = {
{ "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init },
@@ -865,7 +805,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
static int
nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
- bool no_wait_gpu, struct ttm_mem_reg *new_reg)
+ bool no_wait_gpu, struct ttm_resource *new_reg)
{
struct ttm_operation_ctx ctx = { intr, no_wait_gpu };
struct ttm_place placement_memtype = {
@@ -874,7 +814,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
.flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
};
struct ttm_placement placement;
- struct ttm_mem_reg tmp_reg;
+ struct ttm_resource tmp_reg;
int ret;
placement.num_placement = placement.num_busy_placement = 1;
@@ -896,13 +836,13 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
ret = ttm_bo_move_ttm(bo, &ctx, new_reg);
out:
- ttm_bo_mem_put(bo, &tmp_reg);
+ ttm_resource_free(bo, &tmp_reg);
return ret;
}
static int
nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
- bool no_wait_gpu, struct ttm_mem_reg *new_reg)
+ bool no_wait_gpu, struct ttm_resource *new_reg)
{
struct ttm_operation_ctx ctx = { intr, no_wait_gpu };
struct ttm_place placement_memtype = {
@@ -911,7 +851,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
.flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
};
struct ttm_placement placement;
- struct ttm_mem_reg tmp_reg;
+ struct ttm_resource tmp_reg;
int ret;
placement.num_placement = placement.num_busy_placement = 1;
@@ -932,13 +872,13 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
goto out;
out:
- ttm_bo_mem_put(bo, &tmp_reg);
+ ttm_resource_free(bo, &tmp_reg);
return ret;
}
static void
nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
- struct ttm_mem_reg *new_reg)
+ struct ttm_resource *new_reg)
{
struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL;
struct nouveau_bo *nvbo = nouveau_bo(bo);
@@ -970,7 +910,7 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
}
static int
-nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_reg,
+nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_resource *new_reg,
struct nouveau_drm_tile **new_tile)
{
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -1006,11 +946,11 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
static int
nouveau_bo_move(struct ttm_buffer_object *bo, bool evict,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_reg)
+ struct ttm_resource *new_reg)
{
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_bo *nvbo = nouveau_bo(bo);
- struct ttm_mem_reg *old_reg = &bo->mem;
+ struct ttm_resource *old_reg = &bo->mem;
struct nouveau_drm_tile *new_tile = NULL;
int ret = 0;
@@ -1079,18 +1019,12 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
}
static int
-nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
+nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
{
struct nouveau_drm *drm = nouveau_bdev(bdev);
struct nvkm_device *device = nvxx_device(&drm->client.device);
struct nouveau_mem *mem = nouveau_mem(reg);
- reg->bus.addr = NULL;
- reg->bus.offset = 0;
- reg->bus.size = reg->num_pages << PAGE_SHIFT;
- reg->bus.base = 0;
- reg->bus.is_iomem = false;
-
switch (reg->mem_type) {
case TTM_PL_SYSTEM:
/* System memory */
@@ -1159,7 +1093,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
}
static void
-nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
+nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_resource *reg)
{
struct nouveau_drm *drm = nouveau_bdev(bdev);
struct nouveau_mem *mem = nouveau_mem(reg);
@@ -1231,8 +1165,6 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
struct ttm_dma_tt *ttm_dma = (void *)ttm;
struct nouveau_drm *drm;
struct device *dev;
- unsigned i;
- int r;
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
if (ttm->state != tt_unpopulated)
@@ -1260,31 +1192,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
return ttm_dma_populate((void *)ttm, dev, ctx);
}
#endif
-
- r = ttm_pool_populate(ttm, ctx);
- if (r) {
- return r;
- }
-
- for (i = 0; i < ttm->num_pages; i++) {
- dma_addr_t addr;
-
- addr = dma_map_page(dev, ttm->pages[i], 0, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
-
- if (dma_mapping_error(dev, addr)) {
- while (i--) {
- dma_unmap_page(dev, ttm_dma->dma_address[i],
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- ttm_dma->dma_address[i] = 0;
- }
- ttm_pool_unpopulate(ttm);
- return -EFAULT;
- }
-
- ttm_dma->dma_address[i] = addr;
- }
- return 0;
+ return ttm_populate_and_map_pages(dev, ttm_dma, ctx);
}
static void
@@ -1293,7 +1201,6 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
struct ttm_dma_tt *ttm_dma = (void *)ttm;
struct nouveau_drm *drm;
struct device *dev;
- unsigned i;
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
if (slave)
@@ -1316,14 +1223,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
}
#endif
- for (i = 0; i < ttm->num_pages; i++) {
- if (ttm_dma->dma_address[i]) {
- dma_unmap_page(dev, ttm_dma->dma_address[i], PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- }
- }
-
- ttm_pool_unpopulate(ttm);
+ ttm_unmap_and_unpopulate_pages(dev, ttm_dma);
}
void
@@ -1341,7 +1241,6 @@ struct ttm_bo_driver nouveau_bo_driver = {
.ttm_tt_create = &nouveau_ttm_tt_create,
.ttm_tt_populate = &nouveau_ttm_tt_populate,
.ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate,
- .init_mem_type = nouveau_bo_init_mem_type,
.eviction_valuable = ttm_bo_eviction_valuable,
.evict_flags = nouveau_bo_evict_flags,
.move_notify = nouveau_bo_move_ntfy,
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
index 52489ce7d029..aecb7481df0d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
@@ -139,28 +139,28 @@ nouveau_bo_new_pin_map(struct nouveau_cli *cli, u64 size, int align, u32 flags,
int nv04_bo_move_init(struct nouveau_channel *, u32);
int nv04_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
int nv50_bo_move_init(struct nouveau_channel *, u32);
int nv50_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
int nv84_bo_move_exec(struct nouveau_channel *, struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
int nva3_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
int nvc0_bo_move_init(struct nouveau_channel *, u32);
int nvc0_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
int nvc0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
int nve0_bo_move_init(struct nouveau_channel *, u32);
int nve0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
#define NVBO_WR32_(b,o,dr,f) nouveau_bo_wr32((b), (o)/4 + (dr), (f))
#define NVBO_RD32_(b,o,dr) nouveau_bo_rd32((b), (o)/4 + (dr))
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo0039.c b/drivers/gpu/drm/nouveau/nouveau_bo0039.c
index bf7ae2cecaf6..7390132129fe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo0039.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo0039.c
@@ -36,7 +36,7 @@
static inline uint32_t
nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
- struct nouveau_channel *chan, struct ttm_mem_reg *reg)
+ struct nouveau_channel *chan, struct ttm_resource *reg)
{
if (reg->mem_type == TTM_PL_TT)
return NvDmaTT;
@@ -45,7 +45,7 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
int
nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
- struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+ struct ttm_resource *old_reg, struct ttm_resource *new_reg)
{
struct nvif_push *push = chan->chan.push;
u32 src_ctxdma = nouveau_bo_mem_ctxdma(bo, chan, old_reg);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo5039.c b/drivers/gpu/drm/nouveau/nouveau_bo5039.c
index f9b9b85abe44..4c75c7b3804c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo5039.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo5039.c
@@ -37,7 +37,7 @@
int
nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
- struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+ struct ttm_resource *old_reg, struct ttm_resource *new_reg)
{
struct nouveau_mem *mem = nouveau_mem(old_reg);
struct nvif_push *push = chan->chan.push;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo74c1.c b/drivers/gpu/drm/nouveau/nouveau_bo74c1.c
index 1b5fd78ddcba..ed6c09d67840 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo74c1.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo74c1.c
@@ -34,7 +34,7 @@
int
nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
- struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+ struct ttm_resource *old_reg, struct ttm_resource *new_reg)
{
struct nouveau_mem *mem = nouveau_mem(old_reg);
struct nvif_push *push = chan->chan.push;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo85b5.c b/drivers/gpu/drm/nouveau/nouveau_bo85b5.c
index f0df172b029e..dec29b2d8bb2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo85b5.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo85b5.c
@@ -38,7 +38,7 @@
int
nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
- struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+ struct ttm_resource *old_reg, struct ttm_resource *new_reg)
{
struct nouveau_mem *mem = nouveau_mem(old_reg);
struct nvif_push *push = chan->chan.push;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo9039.c b/drivers/gpu/drm/nouveau/nouveau_bo9039.c
index 52fefb37064c..776b04976cdf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo9039.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo9039.c
@@ -36,7 +36,7 @@
int
nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
- struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+ struct ttm_resource *old_reg, struct ttm_resource *new_reg)
{
struct nvif_push *push = chan->chan.push;
struct nouveau_mem *mem = nouveau_mem(old_reg);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo90b5.c b/drivers/gpu/drm/nouveau/nouveau_bo90b5.c
index 34b79d561c7f..8499f58213e3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo90b5.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo90b5.c
@@ -31,7 +31,7 @@
int
nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
- struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+ struct ttm_resource *old_reg, struct ttm_resource *new_reg)
{
struct nouveau_mem *mem = nouveau_mem(old_reg);
struct nvif_push *push = chan->chan.push;
diff --git a/drivers/gpu/drm/nouveau/nouveau_boa0b5.c b/drivers/gpu/drm/nouveau/nouveau_boa0b5.c
index 394e29012e50..575212472e7a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_boa0b5.c
+++ b/drivers/gpu/drm/nouveau/nouveau_boa0b5.c
@@ -36,7 +36,7 @@
int
nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
- struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+ struct ttm_resource *old_reg, struct ttm_resource *new_reg)
{
struct nouveau_mem *mem = nouveau_mem(old_reg);
struct nvif_push *push = chan->chan.push;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index ae76a5865a5a..f63ac72aa556 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -157,7 +157,7 @@ struct nouveau_drm {
atomic_t validate_sequence;
int (*move)(struct nouveau_channel *,
struct ttm_buffer_object *,
- struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct ttm_resource *, struct ttm_resource *);
struct nouveau_channel *chan;
struct nvif_object copy;
int mtrr;
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index b1bb542d3115..269d8707acc3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -92,7 +92,7 @@ nouveau_mem_fini(struct nouveau_mem *mem)
}
int
-nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt)
+nouveau_mem_host(struct ttm_resource *reg, struct ttm_dma_tt *tt)
{
struct nouveau_mem *mem = nouveau_mem(reg);
struct nouveau_cli *cli = mem->cli;
@@ -130,7 +130,7 @@ nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt)
}
int
-nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page)
+nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page)
{
struct nouveau_mem *mem = nouveau_mem(reg);
struct nouveau_cli *cli = mem->cli;
@@ -173,7 +173,7 @@ nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page)
}
void
-nouveau_mem_del(struct ttm_mem_reg *reg)
+nouveau_mem_del(struct ttm_resource *reg)
{
struct nouveau_mem *mem = nouveau_mem(reg);
nouveau_mem_fini(mem);
@@ -183,7 +183,7 @@ nouveau_mem_del(struct ttm_mem_reg *reg)
int
nouveau_mem_new(struct nouveau_cli *cli, u8 kind, u8 comp,
- struct ttm_mem_reg *reg)
+ struct ttm_resource *reg)
{
struct nouveau_mem *mem;
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.h b/drivers/gpu/drm/nouveau/nouveau_mem.h
index f6d039e73812..3fe1cfed57a1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.h
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.h
@@ -7,7 +7,7 @@ struct ttm_dma_tt;
#include <nvif/vmm.h>
static inline struct nouveau_mem *
-nouveau_mem(struct ttm_mem_reg *reg)
+nouveau_mem(struct ttm_resource *reg)
{
return reg->mm_node;
}
@@ -21,10 +21,10 @@ struct nouveau_mem {
};
int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp,
- struct ttm_mem_reg *);
-void nouveau_mem_del(struct ttm_mem_reg *);
-int nouveau_mem_vram(struct ttm_mem_reg *, bool contig, u8 page);
-int nouveau_mem_host(struct ttm_mem_reg *, struct ttm_dma_tt *);
+ struct ttm_resource *);
+void nouveau_mem_del(struct ttm_resource *);
+int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page);
+int nouveau_mem_host(struct ttm_resource *, struct ttm_dma_tt *);
void nouveau_mem_fini(struct nouveau_mem *);
int nouveau_mem_map(struct nouveau_mem *, struct nvif_vmm *, struct nvif_vma *);
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index c3ccf661b7a6..eef75c53a197 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -26,7 +26,7 @@ nouveau_sgdma_destroy(struct ttm_tt *ttm)
}
static int
-nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg)
+nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
struct nouveau_mem *mem = nouveau_mem(reg);
@@ -60,7 +60,7 @@ static struct ttm_backend_func nv04_sgdma_backend = {
};
static int
-nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg)
+nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
struct nouveau_mem *mem = nouveau_mem(reg);
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index e89ea052cf71..53c6f8827322 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -31,35 +31,17 @@
#include <core/tegra.h>
-static int
-nouveau_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
-{
- return 0;
-}
-
-static int
-nouveau_manager_fini(struct ttm_mem_type_manager *man)
-{
- return 0;
-}
-
static void
-nouveau_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *reg)
+nouveau_manager_del(struct ttm_resource_manager *man, struct ttm_resource *reg)
{
nouveau_mem_del(reg);
}
-static void
-nouveau_manager_debug(struct ttm_mem_type_manager *man,
- struct drm_printer *printer)
-{
-}
-
static int
-nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
+nouveau_vram_manager_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
- struct ttm_mem_reg *reg)
+ struct ttm_resource *reg)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -81,19 +63,16 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
return 0;
}
-const struct ttm_mem_type_manager_func nouveau_vram_manager = {
- .init = nouveau_manager_init,
- .takedown = nouveau_manager_fini,
- .get_node = nouveau_vram_manager_new,
- .put_node = nouveau_manager_del,
- .debug = nouveau_manager_debug,
+const struct ttm_resource_manager_func nouveau_vram_manager = {
+ .alloc = nouveau_vram_manager_new,
+ .free = nouveau_manager_del,
};
static int
-nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
+nouveau_gart_manager_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
- struct ttm_mem_reg *reg)
+ struct ttm_resource *reg)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -107,19 +86,16 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
return 0;
}
-const struct ttm_mem_type_manager_func nouveau_gart_manager = {
- .init = nouveau_manager_init,
- .takedown = nouveau_manager_fini,
- .get_node = nouveau_gart_manager_new,
- .put_node = nouveau_manager_del,
- .debug = nouveau_manager_debug
+const struct ttm_resource_manager_func nouveau_gart_manager = {
+ .alloc = nouveau_gart_manager_new,
+ .free = nouveau_manager_del,
};
static int
-nv04_gart_manager_new(struct ttm_mem_type_manager *man,
+nv04_gart_manager_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
- struct ttm_mem_reg *reg)
+ struct ttm_resource *reg)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -142,12 +118,9 @@ nv04_gart_manager_new(struct ttm_mem_type_manager *man,
return 0;
}
-const struct ttm_mem_type_manager_func nv04_gart_manager = {
- .init = nouveau_manager_init,
- .takedown = nouveau_manager_fini,
- .get_node = nv04_gart_manager_new,
- .put_node = nouveau_manager_del,
- .debug = nouveau_manager_debug
+const struct ttm_resource_manager_func nv04_gart_manager = {
+ .alloc = nv04_gart_manager_new,
+ .free = nouveau_manager_del,
};
int
@@ -180,6 +153,113 @@ nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind)
return 0;
}
+static int
+nouveau_ttm_init_vram(struct nouveau_drm *drm)
+{
+ struct nvif_mmu *mmu = &drm->client.mmu;
+ if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
+ /* Some BARs do not support being ioremapped WC */
+ const u8 type = mmu->type[drm->ttm.type_vram].type;
+ struct ttm_resource_manager *man = kzalloc(sizeof(*man), GFP_KERNEL);
+ if (!man)
+ return -ENOMEM;
+
+ man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+ man->default_caching = TTM_PL_FLAG_WC;
+
+ if (type & NVIF_MEM_UNCACHED) {
+ man->available_caching = TTM_PL_FLAG_UNCACHED;
+ man->default_caching = TTM_PL_FLAG_UNCACHED;
+ }
+
+ man->func = &nouveau_vram_manager;
+ man->use_io_reserve_lru = true;
+
+ ttm_resource_manager_init(man,
+ drm->gem.vram_available >> PAGE_SHIFT);
+ ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man);
+ ttm_resource_manager_set_used(man, true);
+ return 0;
+ } else {
+ return ttm_range_man_init(&drm->ttm.bdev, TTM_PL_VRAM,
+ TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC,
+ TTM_PL_FLAG_WC, false,
+ drm->gem.vram_available >> PAGE_SHIFT);
+ }
+}
+
+static void
+nouveau_ttm_fini_vram(struct nouveau_drm *drm)
+{
+ struct ttm_resource_manager *man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM);
+
+ if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
+ ttm_resource_manager_set_used(man, false);
+ ttm_resource_manager_force_list_clean(&drm->ttm.bdev, man);
+ ttm_resource_manager_cleanup(man);
+ ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, NULL);
+ kfree(man);
+ } else
+ ttm_range_man_fini(&drm->ttm.bdev, TTM_PL_VRAM);
+}
+
+static int
+nouveau_ttm_init_gtt(struct nouveau_drm *drm)
+{
+ struct ttm_resource_manager *man;
+ unsigned long size_pages = drm->gem.gart_available >> PAGE_SHIFT;
+ unsigned available_caching, default_caching;
+ const struct ttm_resource_manager_func *func = NULL;
+ if (drm->agp.bridge) {
+ available_caching = TTM_PL_FLAG_UNCACHED |
+ TTM_PL_FLAG_WC;
+ default_caching = TTM_PL_FLAG_WC;
+ } else {
+ available_caching = TTM_PL_MASK_CACHING;
+ default_caching = TTM_PL_FLAG_CACHED;
+ }
+
+ if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)
+ func = &nouveau_gart_manager;
+ else if (!drm->agp.bridge)
+ func = &nv04_gart_manager;
+ else
+ return ttm_range_man_init(&drm->ttm.bdev, TTM_PL_TT,
+ available_caching, default_caching,
+ true,
+ size_pages);
+
+ man = kzalloc(sizeof(*man), GFP_KERNEL);
+ if (!man)
+ return -ENOMEM;
+
+ man->func = func;
+ man->available_caching = available_caching;
+ man->default_caching = default_caching;
+ man->use_tt = true;
+ ttm_resource_manager_init(man, size_pages);
+ ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, man);
+ ttm_resource_manager_set_used(man, true);
+ return 0;
+}
+
+static void
+nouveau_ttm_fini_gtt(struct nouveau_drm *drm)
+{
+ struct ttm_resource_manager *man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_TT);
+
+ if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA &&
+ drm->agp.bridge)
+ ttm_range_man_fini(&drm->ttm.bdev, TTM_PL_TT);
+ else {
+ ttm_resource_manager_set_used(man, false);
+ ttm_resource_manager_force_list_clean(&drm->ttm.bdev, man);
+ ttm_resource_manager_cleanup(man);
+ ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, NULL);
+ kfree(man);
+ }
+}
+
int
nouveau_ttm_init(struct nouveau_drm *drm)
{
@@ -237,8 +317,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1),
device->func->resource_size(device, 1));
- ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
- drm->gem.vram_available >> PAGE_SHIFT);
+ ret = nouveau_ttm_init_vram(drm);
if (ret) {
NV_ERROR(drm, "VRAM mm init failed, %d\n", ret);
return ret;
@@ -254,8 +333,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
drm->gem.gart_available = drm->agp.size;
}
- ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_TT,
- drm->gem.gart_available >> PAGE_SHIFT);
+ ret = nouveau_ttm_init_gtt(drm);
if (ret) {
NV_ERROR(drm, "GART mm init failed, %d\n", ret);
return ret;
@@ -271,8 +349,8 @@ nouveau_ttm_fini(struct nouveau_drm *drm)
{
struct nvkm_device *device = nvxx_device(&drm->client.device);
- ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM);
- ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT);
+ nouveau_ttm_fini_vram(drm);
+ nouveau_ttm_fini_gtt(drm);
ttm_bo_device_release(&drm->ttm.bdev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.h b/drivers/gpu/drm/nouveau/nouveau_ttm.h
index 085280754b3e..eaf25461cd91 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.h
@@ -8,9 +8,9 @@ nouveau_bdev(struct ttm_bo_device *bd)
return container_of(bd, struct nouveau_drm, ttm.bdev);
}
-extern const struct ttm_mem_type_manager_func nouveau_vram_manager;
-extern const struct ttm_mem_type_manager_func nouveau_gart_manager;
-extern const struct ttm_mem_type_manager_func nv04_gart_manager;
+extern const struct ttm_resource_manager_func nouveau_vram_manager;
+extern const struct ttm_resource_manager_func nouveau_gart_manager;
+extern const struct ttm_resource_manager_func nv04_gart_manager;
struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo,
u32 page_flags);
diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c
index cd1e87a528a4..6b697ee6bc0e 100644
--- a/drivers/gpu/drm/nouveau/nv17_fence.c
+++ b/drivers/gpu/drm/nouveau/nv17_fence.c
@@ -78,7 +78,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
{
struct nv10_fence_priv *priv = chan->drm->fence;
struct nv10_fence_chan *fctx;
- struct ttm_mem_reg *reg = &priv->bo->bo.mem;
+ struct ttm_resource *reg = &priv->bo->bo.mem;
u32 start = reg->start * PAGE_SIZE;
u32 limit = start + reg->size - 1;
int ret = 0;
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c
index ebb740686b44..49b46f51073c 100644
--- a/drivers/gpu/drm/nouveau/nv50_fence.c
+++ b/drivers/gpu/drm/nouveau/nv50_fence.c
@@ -37,7 +37,7 @@ nv50_fence_context_new(struct nouveau_channel *chan)
{
struct nv10_fence_priv *priv = chan->drm->fence;
struct nv10_fence_chan *fctx;
- struct ttm_mem_reg *reg = &priv->bo->bo.mem;
+ struct ttm_resource *reg = &priv->bo->bo.mem;
u32 start = reg->start * PAGE_SIZE;
u32 limit = start + reg->size - 1;
int ret;
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index 2578c95570f6..a14fbf06cb30 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/component.h>
#include <linux/of.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
index 4d4c1fabd0a1..b738d9750686 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
@@ -24,7 +24,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/component.h>
#include <linux/of.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
index bd12eae0cb31..5c027c81760f 100644
--- a/drivers/gpu/drm/omapdrm/dss/venc.c
+++ b/drivers/gpu/drm/omapdrm/dss/venc.c
@@ -781,7 +781,7 @@ static int venc_probe_of(struct venc_device *venc)
venc->type = OMAP_DSS_VENC_TYPE_SVIDEO;
break;
default:
- dev_err(&venc->pdev->dev, "bad channel propert '%d'\n",
+ dev_err(&venc->pdev->dev, "bad channel property '%d'\n",
channels);
r = -EINVAL;
goto err;
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 4526967978b7..53d5e184ee77 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -349,13 +349,6 @@ static int omap_modeset_init(struct drm_device *dev)
drm_connector_attach_encoder(pipe->connector, encoder);
- if (pipe->output->panel) {
- ret = drm_panel_attach(pipe->output->panel,
- pipe->connector);
- if (ret < 0)
- return ret;
- }
-
crtc = omap_crtc_init(dev, pipe, priv->planes[i]);
if (IS_ERR(crtc))
return PTR_ERR(crtc);
@@ -394,18 +387,8 @@ static int omap_modeset_init(struct drm_device *dev)
static void omap_modeset_fini(struct drm_device *ddev)
{
- struct omap_drm_private *priv = ddev->dev_private;
- unsigned int i;
-
omap_drm_irq_uninstall(ddev);
- for (i = 0; i < priv->num_pipes; i++) {
- struct omap_drm_pipeline *pipe = &priv->pipes[i];
-
- if (pipe->output->panel)
- drm_panel_detach(pipe->output->panel);
- }
-
drm_mode_config_cleanup(ddev);
}
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index de2f2a452be5..8d97d07c5871 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -217,6 +217,17 @@ config DRM_PANEL_NOVATEK_NT39016
Say Y here if you want to enable support for the panels built
around the Novatek NT39016 display controller.
+config DRM_PANEL_MANTIX_MLAF057WE51
+ tristate "Mantix MLAF057WE51-X MIPI-DSI LCD panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for the Mantix
+ MLAF057WE51-X MIPI DSI panel as e.g. used in the Librem 5. It
+ has a resolution of 720x1440 pixels, a built in backlight and touch
+ controller.
+
config DRM_PANEL_OLIMEX_LCD_OLINUXINO
tristate "Olimex LCD-OLinuXino panel"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index e45ceac6286f..15a4e7752951 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o
+obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o
obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) += panel-osd-osd101t2587-53ts.o
diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c
index 47b37fef7ee8..abb0788843c6 100644
--- a/drivers/gpu/drm/panel/panel-arm-versatile.c
+++ b/drivers/gpu/drm/panel/panel-arm-versatile.c
@@ -349,7 +349,9 @@ static int versatile_panel_probe(struct platform_device *pdev)
drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs,
DRM_MODE_CONNECTOR_DPI);
- return drm_panel_add(&vpanel->panel);
+ drm_panel_add(&vpanel->panel);
+
+ return 0;
}
static const struct of_device_id versatile_panel_match[] = {
diff --git a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c
index 9a5b7644d756..e95bc9f60b3f 100644
--- a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c
+++ b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c
@@ -315,11 +315,7 @@ static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi)
return ret;
}
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0) {
- dev_err(dev, "Failed to add panel: %d\n", ret);
- return ret;
- }
+ drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
index 7c27bd5e3486..42854bd37fd5 100644
--- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c
+++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
@@ -19,7 +19,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#include <video/mipi_display.h>
@@ -93,8 +92,7 @@ static int boe_panel_disable(struct drm_panel *panel)
err = mipi_dsi_dcs_set_display_off(pinfo->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
- err);
+ dev_err(panel->dev, "failed to set display off: %d\n", err);
return err;
}
@@ -113,13 +111,11 @@ static int boe_panel_unprepare(struct drm_panel *panel)
err = mipi_dsi_dcs_set_display_off(pinfo->link);
if (err < 0)
- DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
- err);
+ dev_err(panel->dev, "failed to set display off: %d\n", err);
err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link);
if (err < 0)
- DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
- err);
+ dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
/* sleep_mode_delay: 1ms - 2ms */
usleep_range(1000, 2000);
@@ -163,15 +159,13 @@ static int boe_panel_prepare(struct drm_panel *panel)
/* send init code */
err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to send DCS Init Code: %d\n",
- err);
+ dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);
goto poweroff;
}
err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
- err);
+ dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
goto poweroff;
}
@@ -180,8 +174,7 @@ static int boe_panel_prepare(struct drm_panel *panel)
err = mipi_dsi_dcs_set_display_on(pinfo->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
- err);
+ dev_err(panel->dev, "failed to set display on: %d\n", err);
goto poweroff;
}
@@ -209,8 +202,7 @@ static int boe_panel_enable(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_on(pinfo->link);
if (ret < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
- ret);
+ dev_err(panel->dev, "failed to set display on: %d\n", ret);
return ret;
}
@@ -228,8 +220,8 @@ static int boe_panel_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, m);
if (!mode) {
- DRM_DEV_ERROR(pinfo->base.dev, "failed to add mode %ux%u@%u\n",
- m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
+ dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n",
+ m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
return -ENOMEM;
}
@@ -865,8 +857,7 @@ static int panel_add(struct panel_info *pinfo)
if (IS_ERR(pinfo->pp18_gpio)) {
ret = PTR_ERR(pinfo->pp18_gpio);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev, "failed to get pp18 gpio: %d\n",
- ret);
+ dev_err(dev, "failed to get pp18 gpio: %d\n", ret);
return ret;
}
@@ -874,8 +865,7 @@ static int panel_add(struct panel_info *pinfo)
if (IS_ERR(pinfo->pp33_gpio)) {
ret = PTR_ERR(pinfo->pp33_gpio);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev, "failed to get pp33 gpio: %d\n",
- ret);
+ dev_err(dev, "failed to get pp33 gpio: %d\n", ret);
return ret;
}
@@ -883,8 +873,7 @@ static int panel_add(struct panel_info *pinfo)
if (IS_ERR(pinfo->enable_gpio)) {
ret = PTR_ERR(pinfo->enable_gpio);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev, "failed to get enable gpio: %d\n",
- ret);
+ dev_err(dev, "failed to get enable gpio: %d\n", ret);
return ret;
}
@@ -895,7 +884,9 @@ static int panel_add(struct panel_info *pinfo)
if (ret)
return ret;
- return drm_panel_add(&pinfo->base);
+ drm_panel_add(&pinfo->base);
+
+ return 0;
}
static int panel_probe(struct mipi_dsi_device *dsi)
@@ -935,18 +926,15 @@ static int panel_remove(struct mipi_dsi_device *dsi)
err = boe_panel_disable(&pinfo->base);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n",
- err);
+ dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
err = boe_panel_unprepare(&pinfo->base);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
- err);
+ dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
err = mipi_dsi_detach(dsi);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
- err);
+ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
drm_panel_remove(&pinfo->base);
diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
index e320aa30b9ae..db9d0b86d542 100644
--- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
+++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
@@ -11,6 +11,7 @@
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
+#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
@@ -43,6 +44,7 @@ struct boe_panel {
const struct panel_desc *desc;
+ enum drm_panel_orientation orientation;
struct regulator *pp1800;
struct regulator *avee;
struct regulator *avdd;
@@ -740,6 +742,7 @@ static int boe_panel_get_modes(struct drm_panel *panel,
connector->display_info.width_mm = boe->desc->size.width_mm;
connector->display_info.height_mm = boe->desc->size.height_mm;
connector->display_info.bpc = boe->desc->bpc;
+ drm_connector_set_panel_orientation(connector, boe->orientation);
return 1;
}
@@ -779,6 +782,11 @@ static int boe_panel_add(struct boe_panel *boe)
drm_panel_init(&boe->base, dev, &boe_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
+ err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation);
+ if (err < 0) {
+ dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
+ return err;
+ }
err = drm_panel_of_backlight(&boe->base);
if (err)
@@ -787,7 +795,9 @@ static int boe_panel_add(struct boe_panel *boe)
boe->base.funcs = &boe_panel_funcs;
boe->base.dev = &boe->dsi->dev;
- return drm_panel_add(&boe->base);
+ drm_panel_add(&boe->base);
+
+ return 0;
}
static int boe_panel_probe(struct mipi_dsi_device *dsi)
diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c
index e9675514d77b..bc36aa3c1123 100644
--- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c
+++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c
@@ -22,7 +22,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
/* Manufacturer specific Commands send via DSI */
#define KD35T133_CMD_INTERFACEMODECTRL 0xb0
@@ -89,7 +88,7 @@ static int kd35t133_init_sequence(struct kd35t133 *ctx)
0xa9, 0x51, 0x2c, 0x82);
mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0);
- DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n");
+ dev_dbg(dev, "Panel init sequence done\n");
return 0;
}
@@ -104,13 +103,11 @@ static int kd35t133_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0)
- DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n",
- ret);
+ dev_err(ctx->dev, "failed to set display off: %d\n", ret);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n",
- ret);
+ dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
return ret;
}
@@ -131,18 +128,16 @@ static int kd35t133_prepare(struct drm_panel *panel)
if (ctx->prepared)
return 0;
- DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
+ dev_dbg(ctx->dev, "Resetting the panel\n");
ret = regulator_enable(ctx->vdd);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable vdd supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable vdd supply: %d\n", ret);
return ret;
}
ret = regulator_enable(ctx->iovcc);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable iovcc supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
goto disable_vdd;
}
@@ -156,7 +151,7 @@ static int kd35t133_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
+ dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
goto disable_iovcc;
}
@@ -164,14 +159,13 @@ static int kd35t133_prepare(struct drm_panel *panel)
ret = kd35t133_init_sequence(ctx);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
- ret);
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
goto disable_iovcc;
}
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret);
+ dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
goto disable_iovcc;
}
@@ -210,9 +204,9 @@ static int kd35t133_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
- default_mode.hdisplay, default_mode.vdisplay,
- drm_mode_vrefresh(&default_mode));
+ dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
@@ -244,7 +238,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi)
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
+ dev_err(dev, "cannot get reset gpio\n");
return PTR_ERR(ctx->reset_gpio);
}
@@ -252,9 +246,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->vdd)) {
ret = PTR_ERR(ctx->vdd);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request vdd regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request vdd regulator: %d\n", ret);
return ret;
}
@@ -262,9 +254,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->iovcc)) {
ret = PTR_ERR(ctx->iovcc);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request iovcc regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
return ret;
}
@@ -288,7 +278,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi)
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret);
+ dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
@@ -303,13 +293,11 @@ static void kd35t133_shutdown(struct mipi_dsi_device *dsi)
ret = drm_panel_unprepare(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
ret = drm_panel_disable(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
}
static int kd35t133_remove(struct mipi_dsi_device *dsi)
@@ -321,8 +309,7 @@ static int kd35t133_remove(struct mipi_dsi_device *dsi)
ret = mipi_dsi_detach(dsi);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
diff --git a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
index 54610651ecdb..2a602aee61c3 100644
--- a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
+++ b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
@@ -13,7 +13,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define K101_IM2BA02_INIT_CMD_LEN 2
@@ -374,13 +373,11 @@ static int k101_im2ba02_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
if (ret < 0)
- DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
- ret);
+ dev_err(panel->dev, "failed to set display off: %d\n", ret);
ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
if (ret < 0)
- DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
- ret);
+ dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret);
msleep(200);
@@ -416,10 +413,10 @@ static int k101_im2ba02_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &k101_im2ba02_default_mode);
if (!mode) {
- DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
- k101_im2ba02_default_mode.hdisplay,
- k101_im2ba02_default_mode.vdisplay,
- drm_mode_vrefresh(&k101_im2ba02_default_mode));
+ dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n",
+ k101_im2ba02_default_mode.hdisplay,
+ k101_im2ba02_default_mode.vdisplay,
+ drm_mode_vrefresh(&k101_im2ba02_default_mode));
return -ENOMEM;
}
@@ -460,13 +457,13 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi)
ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies),
ctx->supplies);
if (ret < 0) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get regulators\n");
+ dev_err(&dsi->dev, "Couldn't get regulators\n");
return ret;
}
ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n");
+ dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
return PTR_ERR(ctx->reset);
}
@@ -477,9 +474,7 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi)
if (ret)
return ret;
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&ctx->panel);
dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
dsi->format = MIPI_DSI_FMT_RGB888;
diff --git a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
index 19a6274b10f5..581661b506f8 100644
--- a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
+++ b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
@@ -7,7 +7,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
@@ -118,13 +117,11 @@ static int feiyang_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
if (ret < 0)
- DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
- ret);
+ dev_err(panel->dev, "failed to set display off: %d\n", ret);
ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
if (ret < 0)
- DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
- ret);
+ dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret);
/* T13 (backlight fall + video & logic signal fall) T13 >= 200ms */
msleep(200);
@@ -165,10 +162,10 @@ static int feiyang_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &feiyang_default_mode);
if (!mode) {
- DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
- feiyang_default_mode.hdisplay,
- feiyang_default_mode.vdisplay,
- drm_mode_vrefresh(&feiyang_default_mode));
+ dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n",
+ feiyang_default_mode.hdisplay,
+ feiyang_default_mode.vdisplay,
+ drm_mode_vrefresh(&feiyang_default_mode));
return -ENOMEM;
}
@@ -204,19 +201,19 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi)
ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd");
if (IS_ERR(ctx->dvdd)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get dvdd regulator\n");
+ dev_err(&dsi->dev, "Couldn't get dvdd regulator\n");
return PTR_ERR(ctx->dvdd);
}
ctx->avdd = devm_regulator_get(&dsi->dev, "avdd");
if (IS_ERR(ctx->avdd)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get avdd regulator\n");
+ dev_err(&dsi->dev, "Couldn't get avdd regulator\n");
return PTR_ERR(ctx->avdd);
}
ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n");
+ dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
return PTR_ERR(ctx->reset);
}
@@ -224,9 +221,7 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi)
if (ret)
return ret;
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&ctx->panel);
dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST;
dsi->format = MIPI_DSI_FMT_RGB888;
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
index 67a64d1999f6..074e18559b9f 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
@@ -33,7 +33,6 @@
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define ILI9322_CHIP_ID 0x00
#define ILI9322_CHIP_ID_MAGIC 0x96
@@ -683,7 +682,7 @@ static int ili9322_get_modes(struct drm_panel *panel,
break;
}
if (!mode) {
- DRM_ERROR("bad mode or failed to add mode\n");
+ dev_err(panel->dev, "bad mode or failed to add mode\n");
return -EINVAL;
}
drm_mode_set_name(mode);
@@ -892,7 +891,9 @@ static int ili9322_probe(struct spi_device *spi)
drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs,
DRM_MODE_CONNECTOR_DPI);
- return drm_panel_add(&ili->panel);
+ drm_panel_add(&ili->panel);
+
+ return 0;
}
static int ili9322_remove(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
index 3ed8635a6fbd..0145129d7c66 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
@@ -10,6 +10,7 @@
#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
@@ -20,14 +21,6 @@
#include <video/mipi_display.h>
-struct ili9881c {
- struct drm_panel panel;
- struct mipi_dsi_device *dsi;
-
- struct regulator *power;
- struct gpio_desc *reset;
-};
-
enum ili9881c_op {
ILI9881C_SWITCH_PAGE,
ILI9881C_COMMAND,
@@ -45,6 +38,21 @@ struct ili9881c_instr {
} arg;
};
+struct ili9881c_desc {
+ const struct ili9881c_instr *init;
+ const size_t init_length;
+ const struct drm_display_mode *mode;
+};
+
+struct ili9881c {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ const struct ili9881c_desc *desc;
+
+ struct regulator *power;
+ struct gpio_desc *reset;
+};
+
#define ILI9881C_SWITCH_PAGE_INSTR(_page) \
{ \
.op = ILI9881C_SWITCH_PAGE, \
@@ -64,7 +72,7 @@ struct ili9881c_instr {
}, \
}
-static const struct ili9881c_instr ili9881c_init[] = {
+static const struct ili9881c_instr lhr050h41_init[] = {
ILI9881C_SWITCH_PAGE_INSTR(3),
ILI9881C_COMMAND_INSTR(0x01, 0x00),
ILI9881C_COMMAND_INSTR(0x02, 0x00),
@@ -252,6 +260,199 @@ static const struct ili9881c_instr ili9881c_init[] = {
ILI9881C_COMMAND_INSTR(0xD3, 0x3F),
};
+static const struct ili9881c_instr k101_im2byl02_init[] = {
+ ILI9881C_SWITCH_PAGE_INSTR(3),
+ ILI9881C_COMMAND_INSTR(0x01, 0x00),
+ ILI9881C_COMMAND_INSTR(0x02, 0x00),
+ ILI9881C_COMMAND_INSTR(0x03, 0x73),
+ ILI9881C_COMMAND_INSTR(0x04, 0x00),
+ ILI9881C_COMMAND_INSTR(0x05, 0x00),
+ ILI9881C_COMMAND_INSTR(0x06, 0x08),
+ ILI9881C_COMMAND_INSTR(0x07, 0x00),
+ ILI9881C_COMMAND_INSTR(0x08, 0x00),
+ ILI9881C_COMMAND_INSTR(0x09, 0x00),
+ ILI9881C_COMMAND_INSTR(0x0A, 0x01),
+ ILI9881C_COMMAND_INSTR(0x0B, 0x01),
+ ILI9881C_COMMAND_INSTR(0x0C, 0x00),
+ ILI9881C_COMMAND_INSTR(0x0D, 0x01),
+ ILI9881C_COMMAND_INSTR(0x0E, 0x01),
+ ILI9881C_COMMAND_INSTR(0x0F, 0x00),
+ ILI9881C_COMMAND_INSTR(0x10, 0x00),
+ ILI9881C_COMMAND_INSTR(0x11, 0x00),
+ ILI9881C_COMMAND_INSTR(0x12, 0x00),
+ ILI9881C_COMMAND_INSTR(0x13, 0x00),
+ ILI9881C_COMMAND_INSTR(0x14, 0x00),
+ ILI9881C_COMMAND_INSTR(0x15, 0x00),
+ ILI9881C_COMMAND_INSTR(0x16, 0x00),
+ ILI9881C_COMMAND_INSTR(0x17, 0x00),
+ ILI9881C_COMMAND_INSTR(0x18, 0x00),
+ ILI9881C_COMMAND_INSTR(0x19, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1A, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1B, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1C, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1D, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1E, 0x40),
+ ILI9881C_COMMAND_INSTR(0x1F, 0xC0),
+ ILI9881C_COMMAND_INSTR(0x20, 0x06),
+ ILI9881C_COMMAND_INSTR(0x21, 0x01),
+ ILI9881C_COMMAND_INSTR(0x22, 0x06),
+ ILI9881C_COMMAND_INSTR(0x23, 0x01),
+ ILI9881C_COMMAND_INSTR(0x24, 0x88),
+ ILI9881C_COMMAND_INSTR(0x25, 0x88),
+ ILI9881C_COMMAND_INSTR(0x26, 0x00),
+ ILI9881C_COMMAND_INSTR(0x27, 0x00),
+ ILI9881C_COMMAND_INSTR(0x28, 0x3B),
+ ILI9881C_COMMAND_INSTR(0x29, 0x03),
+ ILI9881C_COMMAND_INSTR(0x2A, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2B, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2C, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2D, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2E, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2F, 0x00),
+ ILI9881C_COMMAND_INSTR(0x30, 0x00),
+ ILI9881C_COMMAND_INSTR(0x31, 0x00),
+ ILI9881C_COMMAND_INSTR(0x32, 0x00),
+ ILI9881C_COMMAND_INSTR(0x33, 0x00),
+ ILI9881C_COMMAND_INSTR(0x34, 0x00), /* GPWR1/2 non overlap time 2.62us */
+ ILI9881C_COMMAND_INSTR(0x35, 0x00),
+ ILI9881C_COMMAND_INSTR(0x36, 0x00),
+ ILI9881C_COMMAND_INSTR(0x37, 0x00),
+ ILI9881C_COMMAND_INSTR(0x38, 0x00),
+ ILI9881C_COMMAND_INSTR(0x39, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3A, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3B, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3C, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3D, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3E, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3F, 0x00),
+ ILI9881C_COMMAND_INSTR(0x40, 0x00),
+ ILI9881C_COMMAND_INSTR(0x41, 0x00),
+ ILI9881C_COMMAND_INSTR(0x42, 0x00),
+ ILI9881C_COMMAND_INSTR(0x43, 0x00),
+ ILI9881C_COMMAND_INSTR(0x44, 0x00),
+ ILI9881C_COMMAND_INSTR(0x50, 0x01),
+ ILI9881C_COMMAND_INSTR(0x51, 0x23),
+ ILI9881C_COMMAND_INSTR(0x52, 0x45),
+ ILI9881C_COMMAND_INSTR(0x53, 0x67),
+ ILI9881C_COMMAND_INSTR(0x54, 0x89),
+ ILI9881C_COMMAND_INSTR(0x55, 0xAB),
+ ILI9881C_COMMAND_INSTR(0x56, 0x01),
+ ILI9881C_COMMAND_INSTR(0x57, 0x23),
+ ILI9881C_COMMAND_INSTR(0x58, 0x45),
+ ILI9881C_COMMAND_INSTR(0x59, 0x67),
+ ILI9881C_COMMAND_INSTR(0x5A, 0x89),
+ ILI9881C_COMMAND_INSTR(0x5B, 0xAB),
+ ILI9881C_COMMAND_INSTR(0x5C, 0xCD),
+ ILI9881C_COMMAND_INSTR(0x5D, 0xEF),
+ ILI9881C_COMMAND_INSTR(0x5E, 0x00),
+ ILI9881C_COMMAND_INSTR(0x5F, 0x01),
+ ILI9881C_COMMAND_INSTR(0x60, 0x01),
+ ILI9881C_COMMAND_INSTR(0x61, 0x06),
+ ILI9881C_COMMAND_INSTR(0x62, 0x06),
+ ILI9881C_COMMAND_INSTR(0x63, 0x07),
+ ILI9881C_COMMAND_INSTR(0x64, 0x07),
+ ILI9881C_COMMAND_INSTR(0x65, 0x00),
+ ILI9881C_COMMAND_INSTR(0x66, 0x00),
+ ILI9881C_COMMAND_INSTR(0x67, 0x02),
+ ILI9881C_COMMAND_INSTR(0x68, 0x02),
+ ILI9881C_COMMAND_INSTR(0x69, 0x05),
+ ILI9881C_COMMAND_INSTR(0x6A, 0x05),
+ ILI9881C_COMMAND_INSTR(0x6B, 0x02),
+ ILI9881C_COMMAND_INSTR(0x6C, 0x0D),
+ ILI9881C_COMMAND_INSTR(0x6D, 0x0D),
+ ILI9881C_COMMAND_INSTR(0x6E, 0x0C),
+ ILI9881C_COMMAND_INSTR(0x6F, 0x0C),
+ ILI9881C_COMMAND_INSTR(0x70, 0x0F),
+ ILI9881C_COMMAND_INSTR(0x71, 0x0F),
+ ILI9881C_COMMAND_INSTR(0x72, 0x0E),
+ ILI9881C_COMMAND_INSTR(0x73, 0x0E),
+ ILI9881C_COMMAND_INSTR(0x74, 0x02),
+ ILI9881C_COMMAND_INSTR(0x75, 0x01),
+ ILI9881C_COMMAND_INSTR(0x76, 0x01),
+ ILI9881C_COMMAND_INSTR(0x77, 0x06),
+ ILI9881C_COMMAND_INSTR(0x78, 0x06),
+ ILI9881C_COMMAND_INSTR(0x79, 0x07),
+ ILI9881C_COMMAND_INSTR(0x7A, 0x07),
+ ILI9881C_COMMAND_INSTR(0x7B, 0x00),
+ ILI9881C_COMMAND_INSTR(0x7C, 0x00),
+ ILI9881C_COMMAND_INSTR(0x7D, 0x02),
+ ILI9881C_COMMAND_INSTR(0x7E, 0x02),
+ ILI9881C_COMMAND_INSTR(0x7F, 0x05),
+ ILI9881C_COMMAND_INSTR(0x80, 0x05),
+ ILI9881C_COMMAND_INSTR(0x81, 0x02),
+ ILI9881C_COMMAND_INSTR(0x82, 0x0D),
+ ILI9881C_COMMAND_INSTR(0x83, 0x0D),
+ ILI9881C_COMMAND_INSTR(0x84, 0x0C),
+ ILI9881C_COMMAND_INSTR(0x85, 0x0C),
+ ILI9881C_COMMAND_INSTR(0x86, 0x0F),
+ ILI9881C_COMMAND_INSTR(0x87, 0x0F),
+ ILI9881C_COMMAND_INSTR(0x88, 0x0E),
+ ILI9881C_COMMAND_INSTR(0x89, 0x0E),
+ ILI9881C_COMMAND_INSTR(0x8A, 0x02),
+ ILI9881C_SWITCH_PAGE_INSTR(4),
+ ILI9881C_COMMAND_INSTR(0x3B, 0xC0), /* ILI4003D sel */
+ ILI9881C_COMMAND_INSTR(0x6C, 0x15), /* Set VCORE voltage = 1.5V */
+ ILI9881C_COMMAND_INSTR(0x6E, 0x2A), /* di_pwr_reg=0 for power mode 2A, VGH clamp 18V */
+ ILI9881C_COMMAND_INSTR(0x6F, 0x33), /* pumping ratio VGH=5x VGL=-3x */
+ ILI9881C_COMMAND_INSTR(0x8D, 0x1B), /* VGL clamp -10V */
+ ILI9881C_COMMAND_INSTR(0x87, 0xBA), /* ESD */
+ ILI9881C_COMMAND_INSTR(0x3A, 0x24), /* POWER SAVING */
+ ILI9881C_COMMAND_INSTR(0x26, 0x76),
+ ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
+ ILI9881C_SWITCH_PAGE_INSTR(1),
+ ILI9881C_COMMAND_INSTR(0x22, 0x0A), /* BGR, SS */
+ ILI9881C_COMMAND_INSTR(0x31, 0x00), /* Zigzag type3 inversion */
+ ILI9881C_COMMAND_INSTR(0x40, 0x53), /* ILI4003D sel */
+ ILI9881C_COMMAND_INSTR(0x43, 0x66),
+ ILI9881C_COMMAND_INSTR(0x53, 0x4C),
+ ILI9881C_COMMAND_INSTR(0x50, 0x87),
+ ILI9881C_COMMAND_INSTR(0x51, 0x82),
+ ILI9881C_COMMAND_INSTR(0x60, 0x15),
+ ILI9881C_COMMAND_INSTR(0x61, 0x01),
+ ILI9881C_COMMAND_INSTR(0x62, 0x0C),
+ ILI9881C_COMMAND_INSTR(0x63, 0x00),
+ ILI9881C_COMMAND_INSTR(0xA0, 0x00),
+ ILI9881C_COMMAND_INSTR(0xA1, 0x13), /* VP251 */
+ ILI9881C_COMMAND_INSTR(0xA2, 0x23), /* VP247 */
+ ILI9881C_COMMAND_INSTR(0xA3, 0x14), /* VP243 */
+ ILI9881C_COMMAND_INSTR(0xA4, 0x16), /* VP239 */
+ ILI9881C_COMMAND_INSTR(0xA5, 0x29), /* VP231 */
+ ILI9881C_COMMAND_INSTR(0xA6, 0x1E), /* VP219 */
+ ILI9881C_COMMAND_INSTR(0xA7, 0x1D), /* VP203 */
+ ILI9881C_COMMAND_INSTR(0xA8, 0x86), /* VP175 */
+ ILI9881C_COMMAND_INSTR(0xA9, 0x1E), /* VP144 */
+ ILI9881C_COMMAND_INSTR(0xAA, 0x29), /* VP111 */
+ ILI9881C_COMMAND_INSTR(0xAB, 0x74), /* VP80 */
+ ILI9881C_COMMAND_INSTR(0xAC, 0x19), /* VP52 */
+ ILI9881C_COMMAND_INSTR(0xAD, 0x17), /* VP36 */
+ ILI9881C_COMMAND_INSTR(0xAE, 0x4B), /* VP24 */
+ ILI9881C_COMMAND_INSTR(0xAF, 0x20), /* VP16 */
+ ILI9881C_COMMAND_INSTR(0xB0, 0x26), /* VP12 */
+ ILI9881C_COMMAND_INSTR(0xB1, 0x4C), /* VP8 */
+ ILI9881C_COMMAND_INSTR(0xB2, 0x5D), /* VP4 */
+ ILI9881C_COMMAND_INSTR(0xB3, 0x3F), /* VP0 */
+ ILI9881C_COMMAND_INSTR(0xC0, 0x00), /* VN255 GAMMA N */
+ ILI9881C_COMMAND_INSTR(0xC1, 0x13), /* VN251 */
+ ILI9881C_COMMAND_INSTR(0xC2, 0x23), /* VN247 */
+ ILI9881C_COMMAND_INSTR(0xC3, 0x14), /* VN243 */
+ ILI9881C_COMMAND_INSTR(0xC4, 0x16), /* VN239 */
+ ILI9881C_COMMAND_INSTR(0xC5, 0x29), /* VN231 */
+ ILI9881C_COMMAND_INSTR(0xC6, 0x1E), /* VN219 */
+ ILI9881C_COMMAND_INSTR(0xC7, 0x1D), /* VN203 */
+ ILI9881C_COMMAND_INSTR(0xC8, 0x86), /* VN175 */
+ ILI9881C_COMMAND_INSTR(0xC9, 0x1E), /* VN144 */
+ ILI9881C_COMMAND_INSTR(0xCA, 0x29), /* VN111 */
+ ILI9881C_COMMAND_INSTR(0xCB, 0x74), /* VN80 */
+ ILI9881C_COMMAND_INSTR(0xCC, 0x19), /* VN52 */
+ ILI9881C_COMMAND_INSTR(0xCD, 0x17), /* VN36 */
+ ILI9881C_COMMAND_INSTR(0xCE, 0x4B), /* VN24 */
+ ILI9881C_COMMAND_INSTR(0xCF, 0x20), /* VN16 */
+ ILI9881C_COMMAND_INSTR(0xD0, 0x26), /* VN12 */
+ ILI9881C_COMMAND_INSTR(0xD1, 0x4C), /* VN8 */
+ ILI9881C_COMMAND_INSTR(0xD2, 0x5D), /* VN4 */
+ ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */
+};
+
static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
{
return container_of(panel, struct ili9881c, panel);
@@ -311,8 +512,8 @@ static int ili9881c_prepare(struct drm_panel *panel)
gpiod_set_value(ctx->reset, 0);
msleep(20);
- for (i = 0; i < ARRAY_SIZE(ili9881c_init); i++) {
- const struct ili9881c_instr *instr = &ili9881c_init[i];
+ for (i = 0; i < ctx->desc->init_length; i++) {
+ const struct ili9881c_instr *instr = &ctx->desc->init[i];
if (instr->op == ILI9881C_SWITCH_PAGE)
ret = ili9881c_switch_page(ctx, instr->arg.page);
@@ -368,7 +569,7 @@ static int ili9881c_unprepare(struct drm_panel *panel)
return 0;
}
-static const struct drm_display_mode bananapi_default_mode = {
+static const struct drm_display_mode lhr050h41_default_mode = {
.clock = 62000,
.hdisplay = 720,
@@ -380,6 +581,26 @@ static const struct drm_display_mode bananapi_default_mode = {
.vsync_start = 1280 + 10,
.vsync_end = 1280 + 10 + 10,
.vtotal = 1280 + 10 + 10 + 20,
+
+ .width_mm = 62,
+ .height_mm = 110,
+};
+
+static const struct drm_display_mode k101_im2byl02_default_mode = {
+ .clock = 69700,
+
+ .hdisplay = 800,
+ .hsync_start = 800 + 6,
+ .hsync_end = 800 + 6 + 15,
+ .htotal = 800 + 6 + 15 + 16,
+
+ .vdisplay = 1280,
+ .vsync_start = 1280 + 8,
+ .vsync_end = 1280 + 8 + 48,
+ .vtotal = 1280 + 8 + 48 + 52,
+
+ .width_mm = 135,
+ .height_mm = 217,
};
static int ili9881c_get_modes(struct drm_panel *panel,
@@ -388,12 +609,12 @@ static int ili9881c_get_modes(struct drm_panel *panel,
struct ili9881c *ctx = panel_to_ili9881c(panel);
struct drm_display_mode *mode;
- mode = drm_mode_duplicate(connector->dev, &bananapi_default_mode);
+ mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
if (!mode) {
dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
- bananapi_default_mode.hdisplay,
- bananapi_default_mode.vdisplay,
- drm_mode_vrefresh(&bananapi_default_mode));
+ ctx->desc->mode->hdisplay,
+ ctx->desc->mode->vdisplay,
+ drm_mode_vrefresh(ctx->desc->mode));
return -ENOMEM;
}
@@ -402,8 +623,8 @@ static int ili9881c_get_modes(struct drm_panel *panel,
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
- connector->display_info.width_mm = 62;
- connector->display_info.height_mm = 110;
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
return 1;
}
@@ -426,6 +647,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
return -ENOMEM;
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dsi = dsi;
+ ctx->desc = of_device_get_match_data(&dsi->dev);
drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs,
DRM_MODE_CONNECTOR_DSI);
@@ -446,9 +668,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
if (ret)
return ret;
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&ctx->panel);
dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
dsi->format = MIPI_DSI_FMT_RGB888;
@@ -467,8 +687,21 @@ static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi)
return 0;
}
+static const struct ili9881c_desc lhr050h41_desc = {
+ .init = lhr050h41_init,
+ .init_length = ARRAY_SIZE(lhr050h41_init),
+ .mode = &lhr050h41_default_mode,
+};
+
+static const struct ili9881c_desc k101_im2byl02_desc = {
+ .init = k101_im2byl02_init,
+ .init_length = ARRAY_SIZE(k101_im2byl02_init),
+ .mode = &k101_im2byl02_default_mode,
+};
+
static const struct of_device_id ili9881c_of_match[] = {
- { .compatible = "bananapi,lhr050h41" },
+ { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc },
+ { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc },
{ }
};
MODULE_DEVICE_TABLE(of, ili9881c_of_match);
diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c
index fdf030f4cf92..aea316225391 100644
--- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c
+++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c
@@ -17,7 +17,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
struct panel_init_cmd {
size_t len;
@@ -85,13 +84,11 @@ static int innolux_panel_unprepare(struct drm_panel *panel)
err = mipi_dsi_dcs_set_display_off(innolux->link);
if (err < 0)
- DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
- err);
+ dev_err(panel->dev, "failed to set display off: %d\n", err);
err = mipi_dsi_dcs_enter_sleep_mode(innolux->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
- err);
+ dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
return err;
}
@@ -147,8 +144,7 @@ static int innolux_panel_prepare(struct drm_panel *panel)
err = mipi_dsi_generic_write(innolux->link, cmd->data,
cmd->len);
if (err < 0) {
- dev_err(panel->dev,
- "failed to write command %u\n", i);
+ dev_err(panel->dev, "failed to write command %u\n", i);
goto poweroff;
}
@@ -159,8 +155,7 @@ static int innolux_panel_prepare(struct drm_panel *panel)
*/
err = mipi_dsi_dcs_nop(innolux->link);
if (err < 0) {
- dev_err(panel->dev,
- "failed to send DCS nop: %d\n", err);
+ dev_err(panel->dev, "failed to send DCS nop: %d\n", err);
goto poweroff;
}
}
@@ -168,8 +163,7 @@ static int innolux_panel_prepare(struct drm_panel *panel)
err = mipi_dsi_dcs_exit_sleep_mode(innolux->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
- err);
+ dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
goto poweroff;
}
@@ -178,8 +172,7 @@ static int innolux_panel_prepare(struct drm_panel *panel)
err = mipi_dsi_dcs_set_display_on(innolux->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
- err);
+ dev_err(panel->dev, "failed to set display on: %d\n", err);
goto poweroff;
}
@@ -398,8 +391,8 @@ static int innolux_panel_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, m);
if (!mode) {
- DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n",
- m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
return -ENOMEM;
}
@@ -475,9 +468,7 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi,
if (err)
return err;
- err = drm_panel_add(&innolux->base);
- if (err < 0)
- return err;
+ drm_panel_add(&innolux->base);
mipi_dsi_set_drvdata(dsi, innolux);
innolux->link = dsi;
@@ -514,17 +505,15 @@ static int innolux_panel_remove(struct mipi_dsi_device *dsi)
err = drm_panel_unprepare(&innolux->base);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
- err);
+ dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
err = drm_panel_disable(&innolux->base);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err);
+ dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
err = mipi_dsi_detach(dsi);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
- err);
+ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
innolux_panel_del(innolux);
diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
index 1e3fd6633981..733010b5e4f5 100644
--- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
+++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
@@ -440,9 +440,9 @@ static int jdi_panel_add(struct jdi_panel *jdi)
drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
- ret = drm_panel_add(&jdi->base);
+ drm_panel_add(&jdi->base);
- return ret;
+ return 0;
}
static void jdi_panel_del(struct jdi_panel *jdi)
diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
index 0d397af23afe..86e4213e8bb1 100644
--- a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
+++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
@@ -16,7 +16,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
struct kingdisplay_panel {
struct drm_panel base;
@@ -191,8 +190,7 @@ static int kingdisplay_panel_disable(struct drm_panel *panel)
err = mipi_dsi_dcs_set_display_off(kingdisplay->link);
if (err < 0)
- DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
- err);
+ dev_err(panel->dev, "failed to set display off: %d\n", err);
kingdisplay->enabled = false;
@@ -209,8 +207,7 @@ static int kingdisplay_panel_unprepare(struct drm_panel *panel)
err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
- err);
+ dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
return err;
}
@@ -255,16 +252,14 @@ static int kingdisplay_panel_prepare(struct drm_panel *panel)
err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i],
sizeof(struct kingdisplay_panel_cmd));
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed write init cmds: %d\n",
- err);
+ dev_err(panel->dev, "failed write init cmds: %d\n", err);
goto poweroff;
}
}
err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
- err);
+ dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
goto poweroff;
}
@@ -273,8 +268,7 @@ static int kingdisplay_panel_prepare(struct drm_panel *panel)
err = mipi_dsi_dcs_set_display_on(kingdisplay->link);
if (err < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
- err);
+ dev_err(panel->dev, "failed to set display on: %d\n", err);
goto poweroff;
}
@@ -290,8 +284,7 @@ poweroff:
regulator_err = regulator_disable(kingdisplay->supply);
if (regulator_err)
- DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n",
- regulator_err);
+ dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err);
return err;
}
@@ -327,9 +320,9 @@ static int kingdisplay_panel_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n",
- default_mode.hdisplay, default_mode.vdisplay,
- drm_mode_vrefresh(&default_mode));
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
@@ -382,7 +375,9 @@ static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
if (err)
return err;
- return drm_panel_add(&kingdisplay->base);
+ drm_panel_add(&kingdisplay->base);
+
+ return 0;
}
static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
@@ -421,17 +416,15 @@ static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
err = drm_panel_unprepare(&kingdisplay->base);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
- err);
+ dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
err = drm_panel_disable(&kingdisplay->base);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err);
+ dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
err = mipi_dsi_detach(dsi);
if (err < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
- err);
+ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
kingdisplay_panel_del(kingdisplay);
diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
index eaa9da3ebbea..ed0d5f959037 100644
--- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
+++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
@@ -17,7 +17,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
struct ltk050h3146w_cmd {
char cmd;
@@ -314,8 +313,7 @@ static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
ret = mipi_dsi_dcs_set_tear_on(dsi, 1);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n",
- ret);
+ dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
return ret;
}
@@ -360,8 +358,7 @@ static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page,
ret = ltk050h3146w_a2_select_page(ctx, page);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "failed to select page %d: %d\n",
- page, ret);
+ dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret);
return ret;
}
@@ -369,9 +366,7 @@ static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page,
ret = mipi_dsi_generic_write(dsi, &cmds[i],
sizeof(struct ltk050h3146w_cmd));
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "failed to write page %d init cmds: %d\n",
- page, ret);
+ dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret);
return ret;
}
}
@@ -405,15 +400,14 @@ static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx)
ret = ltk050h3146w_a2_select_page(ctx, 0);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "failed to select page 0: %d\n", ret);
+ dev_err(ctx->dev, "failed to select page 0: %d\n", ret);
return ret;
}
/* vendor code called this without param, where there should be one */
ret = mipi_dsi_dcs_set_tear_on(dsi, 0);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n",
- ret);
+ dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
return ret;
}
@@ -452,15 +446,13 @@ static int ltk050h3146w_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n",
- ret);
+ dev_err(ctx->dev, "failed to set display off: %d\n", ret);
return ret;
}
mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n",
- ret);
+ dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
return ret;
}
@@ -481,17 +473,15 @@ static int ltk050h3146w_prepare(struct drm_panel *panel)
if (ctx->prepared)
return 0;
- DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
+ dev_dbg(ctx->dev, "Resetting the panel\n");
ret = regulator_enable(ctx->vci);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable vci supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
return ret;
}
ret = regulator_enable(ctx->iovcc);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable iovcc supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
goto disable_vci;
}
@@ -502,14 +492,13 @@ static int ltk050h3146w_prepare(struct drm_panel *panel)
ret = ctx->panel_desc->init(ctx);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
- ret);
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
goto disable_iovcc;
}
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
+ dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
goto disable_iovcc;
}
@@ -518,7 +507,7 @@ static int ltk050h3146w_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret);
+ dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
goto disable_iovcc;
}
@@ -577,7 +566,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
+ dev_err(dev, "cannot get reset gpio\n");
return PTR_ERR(ctx->reset_gpio);
}
@@ -585,9 +574,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->vci)) {
ret = PTR_ERR(ctx->vci);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request vci regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request vci regulator: %d\n", ret);
return ret;
}
@@ -595,9 +582,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->iovcc)) {
ret = PTR_ERR(ctx->iovcc);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request iovcc regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
return ret;
}
@@ -621,7 +606,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret);
+ dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
@@ -636,13 +621,11 @@ static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi)
ret = drm_panel_unprepare(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
ret = drm_panel_disable(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
}
static int ltk050h3146w_remove(struct mipi_dsi_device *dsi)
@@ -654,8 +637,7 @@ static int ltk050h3146w_remove(struct mipi_dsi_device *dsi)
ret = mipi_dsi_detach(dsi);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c
index 0f6a248c47a5..3c00e4f8f803 100644
--- a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c
+++ b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c
@@ -20,7 +20,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
struct ltk500hd1829 {
struct device *dev;
@@ -278,13 +277,11 @@ static int ltk500hd1829_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0)
- DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
- ret);
+ dev_err(panel->dev, "failed to set display off: %d\n", ret);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
- ret);
+ dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret);
}
/* 120ms to enter sleep mode */
@@ -310,14 +307,12 @@ static int ltk500hd1829_prepare(struct drm_panel *panel)
ret = regulator_enable(ctx->vcc);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable vci supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
return ret;
}
ret = regulator_enable(ctx->iovcc);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable iovcc supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
goto disable_vcc;
}
@@ -333,16 +328,14 @@ static int ltk500hd1829_prepare(struct drm_panel *panel)
ret = mipi_dsi_generic_write(dsi, &init_code[i],
sizeof(struct ltk500hd1829_cmd));
if (ret < 0) {
- DRM_DEV_ERROR(panel->dev,
- "failed to write init cmds: %d\n", ret);
+ dev_err(panel->dev, "failed to write init cmds: %d\n", ret);
goto disable_iovcc;
}
}
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
- ret);
+ dev_err(panel->dev, "failed to exit sleep mode: %d\n", ret);
goto disable_iovcc;
}
@@ -351,8 +344,7 @@ static int ltk500hd1829_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
- ret);
+ dev_err(panel->dev, "failed to set display on: %d\n", ret);
goto disable_iovcc;
}
@@ -389,9 +381,9 @@ static int ltk500hd1829_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_DEV_ERROR(ctx->dev, "failed to add mode %ux%ux@%u\n",
- default_mode.hdisplay, default_mode.vdisplay,
- drm_mode_vrefresh(&default_mode));
+ dev_err(ctx->dev, "failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
@@ -423,7 +415,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi)
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
+ dev_err(dev, "cannot get reset gpio\n");
return PTR_ERR(ctx->reset_gpio);
}
@@ -431,9 +423,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->vcc)) {
ret = PTR_ERR(ctx->vcc);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request vcc regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request vcc regulator: %d\n", ret);
return ret;
}
@@ -441,9 +431,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->iovcc)) {
ret = PTR_ERR(ctx->iovcc);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request iovcc regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
return ret;
}
@@ -467,7 +455,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi)
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret);
+ dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
@@ -482,13 +470,11 @@ static void ltk500hd1829_shutdown(struct mipi_dsi_device *dsi)
ret = drm_panel_unprepare(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
ret = drm_panel_disable(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
}
static int ltk500hd1829_remove(struct mipi_dsi_device *dsi)
@@ -500,8 +486,7 @@ static int ltk500hd1829_remove(struct mipi_dsi_device *dsi)
ret = mipi_dsi_detach(dsi);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
- ret);
+ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
diff --git a/drivers/gpu/drm/panel/panel-lg-lb035q02.c b/drivers/gpu/drm/panel/panel-lg-lb035q02.c
index 14456b9cd5c0..f3183b68704f 100644
--- a/drivers/gpu/drm/panel/panel-lg-lb035q02.c
+++ b/drivers/gpu/drm/panel/panel-lg-lb035q02.c
@@ -198,7 +198,9 @@ static int lb035q02_probe(struct spi_device *spi)
drm_panel_init(&lcd->panel, &lcd->spi->dev, &lb035q02_funcs,
DRM_MODE_CONNECTOR_DPI);
- return drm_panel_add(&lcd->panel);
+ drm_panel_add(&lcd->panel);
+
+ return 0;
}
static int lb035q02_remove(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c
index aedc485d0727..8e5160af1de5 100644
--- a/drivers/gpu/drm/panel/panel-lg-lg4573.c
+++ b/drivers/gpu/drm/panel/panel-lg-lg4573.c
@@ -261,7 +261,9 @@ static int lg4573_probe(struct spi_device *spi)
drm_panel_init(&ctx->panel, &spi->dev, &lg4573_drm_funcs,
DRM_MODE_CONNECTOR_DPI);
- return drm_panel_add(&ctx->panel);
+ drm_panel_add(&ctx->panel);
+
+ return 0;
}
static int lg4573_remove(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c
index 5ce3f4a2b7a1..66c7d765b8f7 100644
--- a/drivers/gpu/drm/panel/panel-lvds.c
+++ b/drivers/gpu/drm/panel/panel-lvds.c
@@ -37,6 +37,8 @@ struct panel_lvds {
struct gpio_desc *enable_gpio;
struct gpio_desc *reset_gpio;
+
+ enum drm_panel_orientation orientation;
};
static inline struct panel_lvds *to_panel_lvds(struct drm_panel *panel)
@@ -99,6 +101,7 @@ static int panel_lvds_get_modes(struct drm_panel *panel,
connector->display_info.bus_flags = lvds->data_mirror
? DRM_BUS_FLAG_DATA_LSB_TO_MSB
: DRM_BUS_FLAG_DATA_MSB_TO_LSB;
+ drm_connector_set_panel_orientation(connector, lvds->orientation);
return 1;
}
@@ -116,6 +119,12 @@ static int panel_lvds_parse_dt(struct panel_lvds *lvds)
const char *mapping;
int ret;
+ ret = of_drm_get_panel_orientation(np, &lvds->orientation);
+ if (ret < 0) {
+ dev_err(lvds->dev, "%pOF: failed to get orientation %d\n", np, ret);
+ return ret;
+ }
+
ret = of_get_display_timing(np, "panel-timing", &timing);
if (ret < 0) {
dev_err(lvds->dev, "%pOF: problems parsing panel-timing (%d)\n",
@@ -227,9 +236,7 @@ static int panel_lvds_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = drm_panel_add(&lvds->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&lvds->panel);
dev_set_drvdata(lvds->dev, lvds);
return 0;
diff --git a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c
new file mode 100644
index 000000000000..3482e28e30fc
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mantix MLAF057WE51 5.7" MIPI-DSI panel driver
+ *
+ * Copyright (C) Purism SPC 2020
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#define DRV_NAME "panel-mantix-mlaf057we51"
+
+/* Manufacturer specific Commands send via DSI */
+#define MANTIX_CMD_OTP_STOP_RELOAD_MIPI 0x41
+#define MANTIX_CMD_INT_CANCEL 0x4C
+
+struct mantix {
+ struct device *dev;
+ struct drm_panel panel;
+ struct gpio_desc *reset_gpio;
+
+ struct regulator *avdd;
+ struct regulator *avee;
+ struct regulator *vddi;
+};
+
+static inline struct mantix *panel_to_mantix(struct drm_panel *panel)
+{
+ return container_of(panel, struct mantix, panel);
+}
+
+#define dsi_generic_write_seq(dsi, seq...) do { \
+ static const u8 d[] = { seq }; \
+ int ret; \
+ ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
+ if (ret < 0) \
+ return ret; \
+ } while (0)
+
+static int mantix_init_sequence(struct mantix *ctx)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ struct device *dev = ctx->dev;
+
+ /*
+ * Init sequence was supplied by the panel vendor.
+ */
+ dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A);
+
+ dsi_generic_write_seq(dsi, MANTIX_CMD_INT_CANCEL, 0x03);
+ dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x03);
+ dsi_generic_write_seq(dsi, 0x80, 0xA9, 0x00);
+
+ dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x09);
+ dsi_generic_write_seq(dsi, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00);
+ msleep(20);
+
+ dev_dbg(dev, "Panel init sequence done\n");
+ return 0;
+}
+
+static int mantix_enable(struct drm_panel *panel)
+{
+ struct mantix *ctx = panel_to_mantix(panel);
+ struct device *dev = ctx->dev;
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+ int ret;
+
+ ret = mantix_init_sequence(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to exit sleep mode\n");
+ return ret;
+ }
+ msleep(20);
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret)
+ return ret;
+ usleep_range(10000, 12000);
+
+ ret = mipi_dsi_turn_on_peripheral(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to turn on peripheral\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mantix_disable(struct drm_panel *panel)
+{
+ struct mantix *ctx = panel_to_mantix(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret < 0)
+ dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret < 0)
+ dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
+
+
+ return 0;
+}
+
+static int mantix_unprepare(struct drm_panel *panel)
+{
+ struct mantix *ctx = panel_to_mantix(panel);
+
+ regulator_disable(ctx->avee);
+ regulator_disable(ctx->avdd);
+ /* T11 */
+ usleep_range(5000, 6000);
+ regulator_disable(ctx->vddi);
+ /* T14 */
+ msleep(50);
+
+ return 0;
+}
+
+static int mantix_prepare(struct drm_panel *panel)
+{
+ struct mantix *ctx = panel_to_mantix(panel);
+ int ret;
+
+ /* Focaltech FT8006P, section 7.3.1 and 7.3.4 */
+ dev_dbg(ctx->dev, "Resetting the panel\n");
+ ret = regulator_enable(ctx->vddi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to enable vddi supply: %d\n", ret);
+ return ret;
+ }
+
+ /* T1 + T2 */
+ usleep_range(8000, 10000);
+
+ ret = regulator_enable(ctx->avdd);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to enable avdd supply: %d\n", ret);
+ return ret;
+ }
+
+ /* T2d */
+ usleep_range(3500, 4000);
+ ret = regulator_enable(ctx->avee);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to enable avee supply: %d\n", ret);
+ return ret;
+ }
+
+ /* T3+T5 */
+ usleep_range(10000, 12000);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(5150, 7000);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+
+ /* T6 */
+ msleep(50);
+
+ return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+ .hdisplay = 720,
+ .hsync_start = 720 + 45,
+ .hsync_end = 720 + 45 + 14,
+ .htotal = 720 + 45 + 14 + 25,
+ .vdisplay = 1440,
+ .vsync_start = 1440 + 130,
+ .vsync_end = 1440 + 130 + 8,
+ .vtotal = 1440 + 130 + 8 + 106,
+ .clock = 85298,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ .width_mm = 65,
+ .height_mm = 130,
+};
+
+static int mantix_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct mantix *ctx = panel_to_mantix(panel);
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, &default_mode);
+ if (!mode) {
+ dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(mode));
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static const struct drm_panel_funcs mantix_drm_funcs = {
+ .disable = mantix_disable,
+ .unprepare = mantix_unprepare,
+ .prepare = mantix_prepare,
+ .enable = mantix_enable,
+ .get_modes = mantix_get_modes,
+};
+
+static int mantix_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct mantix *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio)) {
+ dev_err(dev, "cannot get reset gpio\n");
+ return PTR_ERR(ctx->reset_gpio);
+ }
+
+ mipi_dsi_set_drvdata(dsi, ctx);
+ ctx->dev = dev;
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+
+ ctx->avdd = devm_regulator_get(dev, "avdd");
+ if (IS_ERR(ctx->avdd))
+ return dev_err_probe(dev, PTR_ERR(ctx->avdd), "Failed to request avdd regulator\n");
+
+ ctx->avee = devm_regulator_get(dev, "avee");
+ if (IS_ERR(ctx->avee))
+ return dev_err_probe(dev, PTR_ERR(ctx->avee), "Failed to request avee regulator\n");
+
+ ctx->vddi = devm_regulator_get(dev, "vddi");
+ if (IS_ERR(ctx->vddi))
+ return dev_err_probe(dev, PTR_ERR(ctx->vddi), "Failed to request vddi regulator\n");
+
+ drm_panel_init(&ctx->panel, dev, &mantix_drm_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return ret;
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
+ drm_panel_remove(&ctx->panel);
+ return ret;
+ }
+
+ dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode),
+ mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
+
+ return 0;
+}
+
+static void mantix_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct mantix *ctx = mipi_dsi_get_drvdata(dsi);
+
+ drm_panel_unprepare(&ctx->panel);
+ drm_panel_disable(&ctx->panel);
+}
+
+static int mantix_remove(struct mipi_dsi_device *dsi)
+{
+ struct mantix *ctx = mipi_dsi_get_drvdata(dsi);
+
+ mantix_shutdown(dsi);
+
+ mipi_dsi_detach(dsi);
+ drm_panel_remove(&ctx->panel);
+
+ return 0;
+}
+
+static const struct of_device_id mantix_of_match[] = {
+ { .compatible = "mantix,mlaf057we51-x" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mantix_of_match);
+
+static struct mipi_dsi_driver mantix_driver = {
+ .probe = mantix_probe,
+ .remove = mantix_remove,
+ .shutdown = mantix_shutdown,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = mantix_of_match,
+ },
+};
+module_mipi_dsi_driver(mantix_driver);
+
+MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
+MODULE_DESCRIPTION("DRM driver for Mantix MLAF057WE51-X MIPI DSI panel");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c
index f894971c1c7c..6e5ab1debc8b 100644
--- a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c
+++ b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c
@@ -207,7 +207,9 @@ static int nl8048_probe(struct spi_device *spi)
drm_panel_init(&lcd->panel, &lcd->spi->dev, &nl8048_funcs,
DRM_MODE_CONNECTOR_DPI);
- return drm_panel_add(&lcd->panel);
+ drm_panel_add(&lcd->panel);
+
+ return 0;
}
static int nl8048_remove(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c
index e98d54df00e7..b9a0e56f33e2 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c
@@ -35,7 +35,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */
#define MCS_CMD_READ_ID1 0xDA
@@ -376,6 +375,10 @@ struct nt35510 {
};
/* Manufacturer command has strictly this byte sequence */
+static const u8 nt35510_mauc_mtp_read_param[] = { 0xAA, 0x55, 0x25, 0x01 };
+static const u8 nt35510_mauc_mtp_read_setting[] = { 0x01, 0x02, 0x00, 0x20,
+ 0x33, 0x13, 0x00, 0x40,
+ 0x00, 0x00, 0x23, 0x02 };
static const u8 nt35510_mauc_select_page_0[] = { 0x55, 0xAA, 0x52, 0x08, 0x00 };
static const u8 nt35510_mauc_select_page_1[] = { 0x55, 0xAA, 0x52, 0x08, 0x01 };
static const u8 nt35510_vgh_on[] = { 0x01 };
@@ -400,9 +403,7 @@ static int nt35510_send_long(struct nt35510 *nt, struct mipi_dsi_device *dsi,
chunk = 15;
ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk);
if (ret < 0) {
- DRM_DEV_ERROR(nt->dev,
- "error sending DCS command seq cmd %02x\n",
- cmd);
+ dev_err(nt->dev, "error sending DCS command seq cmd %02x\n", cmd);
return ret;
}
cmdwritten += chunk;
@@ -414,16 +415,13 @@ static int nt35510_send_long(struct nt35510 *nt, struct mipi_dsi_device *dsi,
chunk = 15;
ret = mipi_dsi_generic_write(dsi, seqp, chunk);
if (ret < 0) {
- DRM_DEV_ERROR(nt->dev,
- "error sending generic write seq %02x\n",
- cmd);
+ dev_err(nt->dev, "error sending generic write seq %02x\n", cmd);
return ret;
}
cmdwritten += chunk;
seqp += chunk;
}
- DRM_DEV_DEBUG(nt->dev, "sent command %02x %02x bytes\n",
- cmd, cmdlen);
+ dev_dbg(nt->dev, "sent command %02x %02x bytes\n", cmd, cmdlen);
return 0;
}
@@ -435,17 +433,17 @@ static int nt35510_read_id(struct nt35510 *nt)
ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID1, &id1, 1);
if (ret < 0) {
- DRM_DEV_ERROR(nt->dev, "could not read MTP ID1\n");
+ dev_err(nt->dev, "could not read MTP ID1\n");
return ret;
}
ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID2, &id2, 1);
if (ret < 0) {
- DRM_DEV_ERROR(nt->dev, "could not read MTP ID2\n");
+ dev_err(nt->dev, "could not read MTP ID2\n");
return ret;
}
ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID3, &id3, 1);
if (ret < 0) {
- DRM_DEV_ERROR(nt->dev, "could not read MTP ID3\n");
+ dev_err(nt->dev, "could not read MTP ID3\n");
return ret;
}
@@ -454,9 +452,7 @@ static int nt35510_read_id(struct nt35510 *nt)
* ID (e.g. Hydis 0x55), driver ID (e.g. NT35510 0xc0) and
* version.
*/
- DRM_DEV_INFO(nt->dev,
- "MTP ID manufacturer: %02x version: %02x driver: %02x\n",
- id1, id2, id3);
+ dev_info(nt->dev, "MTP ID manufacturer: %02x version: %02x driver: %02x\n", id1, id2, id3);
return 0;
}
@@ -657,7 +653,7 @@ static int nt35510_set_brightness(struct backlight_device *bl)
u8 brightness = bl->props.brightness;
int ret;
- DRM_DEV_DEBUG(nt->dev, "set brightness %d\n", brightness);
+ dev_dbg(nt->dev, "set brightness %d\n", brightness);
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
&brightness,
sizeof(brightness));
@@ -698,6 +694,18 @@ static int nt35510_power_on(struct nt35510 *nt)
usleep_range(120000, 140000);
}
+ ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_PARAM,
+ ARRAY_SIZE(nt35510_mauc_mtp_read_param),
+ nt35510_mauc_mtp_read_param);
+ if (ret)
+ return ret;
+
+ ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_SETTING,
+ ARRAY_SIZE(nt35510_mauc_mtp_read_setting),
+ nt35510_mauc_mtp_read_setting);
+ if (ret)
+ return ret;
+
ret = nt35510_read_id(nt);
if (ret)
return ret;
@@ -780,8 +788,7 @@ static int nt35510_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret) {
- DRM_DEV_ERROR(nt->dev, "failed to turn display off (%d)\n",
- ret);
+ dev_err(nt->dev, "failed to turn display off (%d)\n", ret);
return ret;
}
usleep_range(10000, 20000);
@@ -789,8 +796,7 @@ static int nt35510_unprepare(struct drm_panel *panel)
/* Enter sleep mode */
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret) {
- DRM_DEV_ERROR(nt->dev, "failed to enter sleep mode (%d)\n",
- ret);
+ dev_err(nt->dev, "failed to enter sleep mode (%d)\n", ret);
return ret;
}
@@ -817,8 +823,7 @@ static int nt35510_prepare(struct drm_panel *panel)
/* Exit sleep mode */
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret) {
- DRM_DEV_ERROR(nt->dev, "failed to exit sleep mode (%d)\n",
- ret);
+ dev_err(nt->dev, "failed to exit sleep mode (%d)\n", ret);
return ret;
}
/* Up to 120 ms */
@@ -826,8 +831,7 @@ static int nt35510_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret) {
- DRM_DEV_ERROR(nt->dev, "failed to turn display on (%d)\n",
- ret);
+ dev_err(nt->dev, "failed to turn display on (%d)\n", ret);
return ret;
}
/* Some 10 ms */
@@ -848,7 +852,7 @@ static int nt35510_get_modes(struct drm_panel *panel,
info->height_mm = nt->conf->height_mm;
mode = drm_mode_duplicate(connector->dev, &nt->conf->mode);
if (!mode) {
- DRM_ERROR("bad mode or failed to add mode\n");
+ dev_err(panel->dev, "bad mode or failed to add mode\n");
return -EINVAL;
}
drm_mode_set_name(mode);
@@ -947,7 +951,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi)
bl = devm_backlight_device_register(dev, "nt35510", dev, nt,
&nt35510_bl_ops, NULL);
if (IS_ERR(bl)) {
- DRM_DEV_ERROR(dev, "failed to register backlight device\n");
+ dev_err(dev, "failed to register backlight device\n");
return PTR_ERR(bl);
}
bl->props.max_brightness = 255;
@@ -956,9 +960,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi)
nt->panel.backlight = bl;
}
- ret = drm_panel_add(&nt->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&nt->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0)
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt39016.c b/drivers/gpu/drm/panel/panel-novatek-nt39016.c
index 91df050ba3f6..f8151fe3ac9a 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt39016.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt39016.c
@@ -6,7 +6,6 @@
* Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net>
*/
-#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
@@ -57,14 +56,11 @@ struct nt39016_panel_info {
struct nt39016 {
struct drm_panel drm_panel;
- struct device *dev;
struct regmap *map;
struct regulator *supply;
const struct nt39016_panel_info *panel_info;
struct gpio_desc *reset_gpio;
-
- struct backlight_device *backlight;
};
static inline struct nt39016 *to_nt39016(struct drm_panel *panel)
@@ -127,7 +123,7 @@ static int nt39016_prepare(struct drm_panel *drm_panel)
err = regulator_enable(panel->supply);
if (err) {
- dev_err(panel->dev, "Failed to enable power supply: %d", err);
+ dev_err(drm_panel->dev, "Failed to enable power supply: %d\n", err);
return err;
}
@@ -146,7 +142,7 @@ static int nt39016_prepare(struct drm_panel *drm_panel)
err = regmap_multi_reg_write(panel->map, nt39016_panel_regs,
ARRAY_SIZE(nt39016_panel_regs));
if (err) {
- dev_err(panel->dev, "Failed to init registers: %d", err);
+ dev_err(drm_panel->dev, "Failed to init registers: %d\n", err);
goto err_disable_regulator;
}
@@ -176,18 +172,16 @@ static int nt39016_enable(struct drm_panel *drm_panel)
ret = regmap_write(panel->map, NT39016_REG_SYSTEM,
NT39016_SYSTEM_RESET_N | NT39016_SYSTEM_STANDBY);
if (ret) {
- dev_err(panel->dev, "Unable to enable panel: %d", ret);
+ dev_err(drm_panel->dev, "Unable to enable panel: %d\n", ret);
return ret;
}
- if (panel->backlight) {
+ if (drm_panel->backlight) {
/* Wait for the picture to be ready before enabling backlight */
msleep(150);
-
- ret = backlight_enable(panel->backlight);
}
- return ret;
+ return 0;
}
static int nt39016_disable(struct drm_panel *drm_panel)
@@ -195,12 +189,10 @@ static int nt39016_disable(struct drm_panel *drm_panel)
struct nt39016 *panel = to_nt39016(drm_panel);
int err;
- backlight_disable(panel->backlight);
-
err = regmap_write(panel->map, NT39016_REG_SYSTEM,
NT39016_SYSTEM_RESET_N);
if (err) {
- dev_err(panel->dev, "Unable to disable panel: %d", err);
+ dev_err(drm_panel->dev, "Unable to disable panel: %d\n", err);
return err;
}
@@ -259,7 +251,6 @@ static int nt39016_probe(struct spi_device *spi)
if (!panel)
return -ENOMEM;
- panel->dev = dev;
spi_set_drvdata(spi, panel);
panel->panel_info = of_device_get_match_data(dev);
@@ -268,13 +259,13 @@ static int nt39016_probe(struct spi_device *spi)
panel->supply = devm_regulator_get(dev, "power");
if (IS_ERR(panel->supply)) {
- dev_err(dev, "Failed to get power supply");
+ dev_err(dev, "Failed to get power supply\n");
return PTR_ERR(panel->supply);
}
panel->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(panel->reset_gpio)) {
- dev_err(dev, "Failed to get reset GPIO");
+ dev_err(dev, "Failed to get reset GPIO\n");
return PTR_ERR(panel->reset_gpio);
}
@@ -282,33 +273,28 @@ static int nt39016_probe(struct spi_device *spi)
spi->mode = SPI_MODE_3 | SPI_3WIRE;
err = spi_setup(spi);
if (err) {
- dev_err(dev, "Failed to setup SPI");
+ dev_err(dev, "Failed to setup SPI\n");
return err;
}
panel->map = devm_regmap_init_spi(spi, &nt39016_regmap_config);
if (IS_ERR(panel->map)) {
- dev_err(dev, "Failed to init regmap");
+ dev_err(dev, "Failed to init regmap\n");
return PTR_ERR(panel->map);
}
- panel->backlight = devm_of_find_backlight(dev);
- if (IS_ERR(panel->backlight)) {
- err = PTR_ERR(panel->backlight);
- if (err != -EPROBE_DEFER)
- dev_err(dev, "Failed to get backlight handle");
- return err;
- }
-
drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs,
DRM_MODE_CONNECTOR_DPI);
- err = drm_panel_add(&panel->drm_panel);
- if (err < 0) {
- dev_err(dev, "Failed to register panel");
+ err = drm_panel_of_backlight(&panel->drm_panel);
+ if (err) {
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get backlight handle\n");
return err;
}
+ drm_panel_add(&panel->drm_panel);
+
return 0;
}
diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
index ecd76b5391d3..cb5cb27462df 100644
--- a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
+++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
@@ -283,7 +283,9 @@ static int lcd_olinuxino_probe(struct i2c_client *client,
if (ret)
return ret;
- return drm_panel_add(&lcd->panel);
+ drm_panel_add(&lcd->panel);
+
+ return 0;
}
static int lcd_olinuxino_remove(struct i2c_client *client)
diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
index d956522f32ee..b6e377aa1131 100644
--- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
@@ -17,7 +17,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define OTM8009A_BACKLIGHT_DEFAULT 240
#define OTM8009A_BACKLIGHT_MAX 255
@@ -97,7 +96,7 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data,
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
if (mipi_dsi_dcs_write_buffer(dsi, data, len) < 0)
- DRM_WARN("mipi dsi dcs write buffer failed\n");
+ dev_warn(ctx->dev, "mipi dsi dcs write buffer failed\n");
}
static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data,
@@ -313,7 +312,7 @@ static int otm8009a_prepare(struct drm_panel *panel)
ret = regulator_enable(ctx->supply);
if (ret < 0) {
- DRM_ERROR("failed to enable supply: %d\n", ret);
+ dev_err(panel->dev, "failed to enable supply: %d\n", ret);
return ret;
}
@@ -355,9 +354,9 @@ static int otm8009a_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_ERROR("failed to add mode %ux%ux@%u\n",
- default_mode.hdisplay, default_mode.vdisplay,
- drm_mode_vrefresh(&default_mode));
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
@@ -390,7 +389,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd)
u8 data[2];
if (!ctx->prepared) {
- DRM_DEBUG("lcd not ready yet for setting its backlight!\n");
+ dev_dbg(&bd->dev, "lcd not ready yet for setting its backlight!\n");
return -ENXIO;
}
diff --git a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c
index 83e5aa47f0d6..45b975dee587 100644
--- a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c
+++ b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c
@@ -164,7 +164,9 @@ static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587)
if (ret)
return ret;
- return drm_panel_add(&osd101t2587->base);
+ drm_panel_add(&osd101t2587->base);
+
+ return 0;
}
static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi)
diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
index 627dfcf8adb4..3c20beeb1781 100644
--- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
+++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
@@ -206,7 +206,9 @@ static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)
if (ret)
return ret;
- return drm_panel_add(&wuxga_nt->base);
+ drm_panel_add(&wuxga_nt->base);
+
+ return 0;
}
static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)
diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
index e50ee26474cf..5e9ccefb88f6 100644
--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
+++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
@@ -361,7 +361,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
struct rpi_touchscreen *ts;
struct device_node *endpoint, *dsi_host_node;
struct mipi_dsi_host *host;
- int ret, ver;
+ int ver;
struct mipi_dsi_device_info info = {
.type = RPI_DSI_DRIVER_NAME,
.channel = 0,
@@ -429,9 +429,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
/* This appears last, as it's what will unblock the DSI host
* driver's component bind function.
*/
- ret = drm_panel_add(&ts->base);
- if (ret)
- return ret;
+ drm_panel_add(&ts->base);
return 0;
diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67191.c b/drivers/gpu/drm/panel/panel-raydium-rm67191.c
index 57ff2b1f6361..23b62081e951 100644
--- a/drivers/gpu/drm/panel/panel-raydium-rm67191.c
+++ b/drivers/gpu/drm/panel/panel-raydium-rm67191.c
@@ -19,7 +19,6 @@
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
/* Panel specific color-format bits */
#define COL_FMT_16BPP 0x55
@@ -329,7 +328,7 @@ static int rad_panel_enable(struct drm_panel *panel)
ret = rad_panel_push_cmd_list(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to send MCS (%d)\n", ret);
+ dev_err(dev, "Failed to send MCS (%d)\n", ret);
goto fail;
}
@@ -341,7 +340,7 @@ static int rad_panel_enable(struct drm_panel *panel)
/* Software reset */
ret = mipi_dsi_dcs_soft_reset(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to do Software Reset (%d)\n", ret);
+ dev_err(dev, "Failed to do Software Reset (%d)\n", ret);
goto fail;
}
@@ -350,33 +349,32 @@ static int rad_panel_enable(struct drm_panel *panel)
/* Set DSI mode */
ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xC2, 0x0B }, 2);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to set DSI mode (%d)\n", ret);
+ dev_err(dev, "Failed to set DSI mode (%d)\n", ret);
goto fail;
}
/* Set tear ON */
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to set tear ON (%d)\n", ret);
+ dev_err(dev, "Failed to set tear ON (%d)\n", ret);
goto fail;
}
/* Set tear scanline */
ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0x380);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to set tear scanline (%d)\n", ret);
+ dev_err(dev, "Failed to set tear scanline (%d)\n", ret);
goto fail;
}
/* Set pixel format */
ret = mipi_dsi_dcs_set_pixel_format(dsi, color_format);
- DRM_DEV_DEBUG_DRIVER(dev, "Interface color format set to 0x%x\n",
- color_format);
+ dev_dbg(dev, "Interface color format set to 0x%x\n", color_format);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to set pixel format (%d)\n", ret);
+ dev_err(dev, "Failed to set pixel format (%d)\n", ret);
goto fail;
}
/* Exit sleep mode */
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to exit sleep mode (%d)\n", ret);
+ dev_err(dev, "Failed to exit sleep mode (%d)\n", ret);
goto fail;
}
@@ -384,7 +382,7 @@ static int rad_panel_enable(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to set display ON (%d)\n", ret);
+ dev_err(dev, "Failed to set display ON (%d)\n", ret);
goto fail;
}
@@ -418,7 +416,7 @@ static int rad_panel_disable(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to set display OFF (%d)\n", ret);
+ dev_err(dev, "Failed to set display OFF (%d)\n", ret);
return ret;
}
@@ -426,7 +424,7 @@ static int rad_panel_disable(struct drm_panel *panel)
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "Failed to enter sleep mode (%d)\n", ret);
+ dev_err(dev, "Failed to enter sleep mode (%d)\n", ret);
return ret;
}
@@ -442,9 +440,9 @@ static int rad_panel_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n",
- default_mode.hdisplay, default_mode.vdisplay,
- drm_mode_vrefresh(&default_mode));
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
@@ -609,9 +607,7 @@ static int rad_panel_probe(struct mipi_dsi_device *dsi)
DRM_MODE_CONNECTOR_DSI);
dev_set_drvdata(dev, panel);
- ret = drm_panel_add(&panel->panel);
- if (ret)
- return ret;
+ drm_panel_add(&panel->panel);
ret = mipi_dsi_attach(dsi);
if (ret)
@@ -628,8 +624,7 @@ static int rad_panel_remove(struct mipi_dsi_device *dsi)
ret = mipi_dsi_detach(dsi);
if (ret)
- DRM_DEV_ERROR(dev, "Failed to detach from host (%d)\n",
- ret);
+ dev_err(dev, "Failed to detach from host (%d)\n", ret);
drm_panel_remove(&rad->panel);
diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c
index 81ae8be62d15..f908eeafb1af 100644
--- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c
+++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c
@@ -17,7 +17,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
/*** Manufacturer Command Set ***/
#define MCS_CMD_MODE_SW 0xFE /* CMD Mode Switch */
@@ -110,8 +109,7 @@ static void rm68200_dcs_write_buf(struct rm68200 *ctx, const void *data,
err = mipi_dsi_dcs_write_buffer(dsi, data, len);
if (err < 0)
- DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n",
- err);
+ dev_err_ratelimited(ctx->dev, "MIPI DSI DCS write buffer failed: %d\n", err);
}
static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value)
@@ -121,7 +119,7 @@ static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value)
err = mipi_dsi_dcs_write(dsi, cmd, &value, 1);
if (err < 0)
- DRM_ERROR_RATELIMITED("MIPI DSI DCS write failed: %d\n", err);
+ dev_err_ratelimited(ctx->dev, "MIPI DSI DCS write failed: %d\n", err);
}
#define dcs_write_seq(ctx, seq...) \
@@ -256,11 +254,11 @@ static int rm68200_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret)
- DRM_WARN("failed to set display off: %d\n", ret);
+ dev_warn(panel->dev, "failed to set display off: %d\n", ret);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret)
- DRM_WARN("failed to enter sleep mode: %d\n", ret);
+ dev_warn(panel->dev, "failed to enter sleep mode: %d\n", ret);
msleep(120);
@@ -287,7 +285,7 @@ static int rm68200_prepare(struct drm_panel *panel)
ret = regulator_enable(ctx->supply);
if (ret < 0) {
- DRM_ERROR("failed to enable supply: %d\n", ret);
+ dev_err(ctx->dev, "failed to enable supply: %d\n", ret);
return ret;
}
@@ -336,9 +334,9 @@ static int rm68200_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_ERROR("failed to add mode %ux%ux@%u\n",
- default_mode.hdisplay, default_mode.vdisplay,
- drm_mode_vrefresh(&default_mode));
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
diff --git a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
index a7b0b3e39e1a..535c8d1cca21 100644
--- a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
+++ b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
@@ -23,7 +23,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
struct rb070d30_panel {
struct drm_panel panel;
@@ -50,7 +49,7 @@ static int rb070d30_panel_prepare(struct drm_panel *panel)
ret = regulator_enable(ctx->supply);
if (ret < 0) {
- DRM_DEV_ERROR(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret);
+ dev_err(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret);
return ret;
}
@@ -117,9 +116,8 @@ static int rb070d30_panel_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_DEV_ERROR(&ctx->dsi->dev,
- "Failed to add mode " DRM_MODE_FMT "\n",
- DRM_MODE_ARG(&default_mode));
+ dev_err(&ctx->dsi->dev, "Failed to add mode " DRM_MODE_FMT "\n",
+ DRM_MODE_ARG(&default_mode));
return -EINVAL;
}
@@ -166,13 +164,13 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)
ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->gpios.reset)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n");
+ dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
return PTR_ERR(ctx->gpios.reset);
}
ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(ctx->gpios.power)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get our power GPIO\n");
+ dev_err(&dsi->dev, "Couldn't get our power GPIO\n");
return PTR_ERR(ctx->gpios.power);
}
@@ -182,7 +180,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)
*/
ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW);
if (IS_ERR(ctx->gpios.updn)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get our updn GPIO\n");
+ dev_err(&dsi->dev, "Couldn't get our updn GPIO\n");
return PTR_ERR(ctx->gpios.updn);
}
@@ -192,7 +190,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)
*/
ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW);
if (IS_ERR(ctx->gpios.shlr)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get our shlr GPIO\n");
+ dev_err(&dsi->dev, "Couldn't get our shlr GPIO\n");
return PTR_ERR(ctx->gpios.shlr);
}
@@ -200,9 +198,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)
if (ret)
return ret;
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&ctx->panel);
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM;
dsi->format = MIPI_DSI_FMT_RGB888;
diff --git a/drivers/gpu/drm/panel/panel-samsung-ld9040.c b/drivers/gpu/drm/panel/panel-samsung-ld9040.c
index 9bb2e8c7934a..f484147fc3a6 100644
--- a/drivers/gpu/drm/panel/panel-samsung-ld9040.c
+++ b/drivers/gpu/drm/panel/panel-samsung-ld9040.c
@@ -21,7 +21,6 @@
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
/* Manufacturer Command Set */
#define MCS_MANPWR 0xb0
@@ -269,7 +268,7 @@ static int ld9040_get_modes(struct drm_panel *panel,
mode = drm_mode_create(connector->dev);
if (!mode) {
- DRM_ERROR("failed to create a new display mode\n");
+ dev_err(panel->dev, "failed to create a new display mode\n");
return 0;
}
@@ -354,7 +353,9 @@ static int ld9040_probe(struct spi_device *spi)
drm_panel_init(&ctx->panel, dev, &ld9040_drm_funcs,
DRM_MODE_CONNECTOR_DPI);
- return drm_panel_add(&ctx->panel);
+ drm_panel_add(&ctx->panel);
+
+ return 0;
}
static int ld9040_remove(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
index f02645d396ac..4aac0d1573dd 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
@@ -7,7 +7,6 @@
#include <drm/drm_modes.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
@@ -55,8 +54,7 @@ static int s6d16d0_unprepare(struct drm_panel *panel)
/* Enter sleep mode */
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret) {
- DRM_DEV_ERROR(s6->dev, "failed to enter sleep mode (%d)\n",
- ret);
+ dev_err(s6->dev, "failed to enter sleep mode (%d)\n", ret);
return ret;
}
@@ -75,7 +73,7 @@ static int s6d16d0_prepare(struct drm_panel *panel)
ret = regulator_enable(s6->supply);
if (ret) {
- DRM_DEV_ERROR(s6->dev, "failed to enable supply (%d)\n", ret);
+ dev_err(s6->dev, "failed to enable supply (%d)\n", ret);
return ret;
}
@@ -90,15 +88,13 @@ static int s6d16d0_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_tear_on(dsi,
MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret) {
- DRM_DEV_ERROR(s6->dev, "failed to enable vblank TE (%d)\n",
- ret);
+ dev_err(s6->dev, "failed to enable vblank TE (%d)\n", ret);
return ret;
}
/* Exit sleep mode and power on */
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret) {
- DRM_DEV_ERROR(s6->dev, "failed to exit sleep mode (%d)\n",
- ret);
+ dev_err(s6->dev, "failed to exit sleep mode (%d)\n", ret);
return ret;
}
@@ -113,8 +109,7 @@ static int s6d16d0_enable(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret) {
- DRM_DEV_ERROR(s6->dev, "failed to turn display on (%d)\n",
- ret);
+ dev_err(s6->dev, "failed to turn display on (%d)\n", ret);
return ret;
}
@@ -129,8 +124,7 @@ static int s6d16d0_disable(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret) {
- DRM_DEV_ERROR(s6->dev, "failed to turn display off (%d)\n",
- ret);
+ dev_err(s6->dev, "failed to turn display off (%d)\n", ret);
return ret;
}
@@ -144,7 +138,7 @@ static int s6d16d0_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &samsung_s6d16d0_mode);
if (!mode) {
- DRM_ERROR("bad mode or failed to add mode\n");
+ dev_err(panel->dev, "bad mode or failed to add mode\n");
return -EINVAL;
}
drm_mode_set_name(mode);
@@ -204,17 +198,14 @@ static int s6d16d0_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(s6->reset_gpio)) {
ret = PTR_ERR(s6->reset_gpio);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n",
- ret);
+ dev_err(dev, "failed to request GPIO (%d)\n", ret);
return ret;
}
drm_panel_init(&s6->panel, dev, &s6d16d0_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
- ret = drm_panel_add(&s6->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&s6->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0)
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
index 80ef122e7466..1d1c79a18613 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
@@ -18,7 +18,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define S6E3HA2_MIN_BRIGHTNESS 0
#define S6E3HA2_MAX_BRIGHTNESS 100
@@ -651,7 +650,7 @@ static int s6e3ha2_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
if (!mode) {
- DRM_ERROR("failed to add mode %ux%ux@%u\n",
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
drm_mode_vrefresh(ctx->desc->mode));
return -ENOMEM;
@@ -733,9 +732,7 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0)
- goto unregister_backlight;
+ drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0)
@@ -745,8 +742,6 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
remove_panel:
drm_panel_remove(&ctx->panel);
-
-unregister_backlight:
backlight_device_unregister(ctx->bl_dev);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
index 1247656d73bf..b962c817fb30 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
@@ -19,7 +19,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define MCS_LEVEL2_KEY 0xf0
#define MCS_MTP_KEY 0xf1
@@ -406,7 +405,7 @@ static int s6e63j0x03_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_ERROR("failed to add mode %ux%ux@%u\n",
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
default_mode.hdisplay, default_mode.vdisplay,
drm_mode_vrefresh(&default_mode));
return -ENOMEM;
@@ -479,9 +478,7 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi)
ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS;
ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0)
- goto unregister_backlight;
+ drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0)
@@ -491,8 +488,6 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi)
remove_panel:
drm_panel_remove(&ctx->panel);
-
-unregister_backlight:
backlight_device_unregister(ctx->bl_dev);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c
index 64421347bfd4..2cc772fdc456 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c
@@ -10,7 +10,6 @@
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#include <linux/backlight.h>
#include <linux/delay.h>
@@ -157,7 +156,7 @@ static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
if (ctx->error < 0 || len == 0)
return;
- DRM_DEV_DEBUG(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data);
+ dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data);
ret = s6e63m0_spi_write_word(ctx, *data);
while (!ret && --len) {
@@ -166,8 +165,7 @@ static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
}
if (ret) {
- DRM_DEV_ERROR(ctx->dev, "error %d writing dcs seq: %*ph\n", ret,
- (int)len, data);
+ dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, (int)len, data);
ctx->error = ret;
}
@@ -368,9 +366,9 @@ static int s6e63m0_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_ERROR("failed to add mode %ux%ux@%u\n",
- default_mode.hdisplay, default_mode.vdisplay,
- drm_mode_vrefresh(&default_mode));
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
@@ -425,8 +423,7 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx)
&props);
if (IS_ERR(ctx->bl_dev)) {
ret = PTR_ERR(ctx->bl_dev);
- DRM_DEV_ERROR(dev, "error registering backlight device (%d)\n",
- ret);
+ dev_err(dev, "error registering backlight device (%d)\n", ret);
}
return ret;
@@ -453,14 +450,13 @@ static int s6e63m0_probe(struct spi_device *spi)
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
ctx->supplies);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "failed to get regulators: %d\n", ret);
+ dev_err(dev, "failed to get regulators: %d\n", ret);
return ret;
}
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->reset_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get reset-gpios %ld\n",
- PTR_ERR(ctx->reset_gpio));
+ dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio));
return PTR_ERR(ctx->reset_gpio);
}
@@ -468,7 +464,7 @@ static int s6e63m0_probe(struct spi_device *spi)
spi->mode = SPI_MODE_3;
ret = spi_setup(spi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "spi setup failed.\n");
+ dev_err(dev, "spi setup failed.\n");
return ret;
}
@@ -479,7 +475,9 @@ static int s6e63m0_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- return drm_panel_add(&ctx->panel);
+ drm_panel_add(&ctx->panel);
+
+ return 0;
}
static int s6e63m0_remove(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c
index 485eabecfcc9..ea63799ff2a1 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c
@@ -242,11 +242,7 @@ static int s6e88a0_ams452ef01_probe(struct mipi_dsi_device *dsi)
drm_panel_init(&ctx->panel, dev, &s6e88a0_ams452ef01_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0) {
- dev_err(dev, "Failed to add panel: %d\n", ret);
- return ret;
- }
+ drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
index 8a028d2bd0d6..527371120266 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
@@ -25,7 +25,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define LDI_MTP_LENGTH 24
#define GAMMA_LEVEL_NUM 25
@@ -928,7 +927,7 @@ static int s6e8aa0_get_modes(struct drm_panel *panel,
mode = drm_mode_create(connector->dev);
if (!mode) {
- DRM_ERROR("failed to create a new display mode\n");
+ dev_err(panel->dev, "failed to create a new display mode\n");
return 0;
}
@@ -1020,9 +1019,7 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0)
diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
index e417dc4921c2..0ee508576231 100644
--- a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
+++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
@@ -258,9 +258,7 @@ static int seiko_panel_probe(struct device *dev,
if (err)
return err;
- err = drm_panel_add(&panel->base);
- if (err < 0)
- return err;
+ drm_panel_add(&panel->base);
dev_set_drvdata(dev, panel);
diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
index f07324b705b3..f8cd2a42ed13 100644
--- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
@@ -325,7 +325,9 @@ static int sharp_panel_add(struct sharp_panel *sharp)
if (ret)
return ret;
- return drm_panel_add(&sharp->base);
+ drm_panel_add(&sharp->base);
+
+ return 0;
}
static void sharp_panel_del(struct sharp_panel *sharp)
diff --git a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c
index d7bf13b9e1d6..94992f45113a 100644
--- a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c
@@ -187,7 +187,9 @@ static int ls037v7dw01_probe(struct platform_device *pdev)
drm_panel_init(&lcd->panel, &pdev->dev, &ls037v7dw01_funcs,
DRM_MODE_CONNECTOR_DPI);
- return drm_panel_add(&lcd->panel);
+ drm_panel_add(&lcd->panel);
+
+ return 0;
}
static int ls037v7dw01_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
index b2e58935529c..16dbf0f353ed 100644
--- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
@@ -261,7 +261,9 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
if (ret)
return ret;
- return drm_panel_add(&sharp_nt->base);
+ drm_panel_add(&sharp_nt->base);
+
+ return 0;
}
static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index cb6550d37e85..f499de71ab3d 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -112,6 +112,8 @@ struct panel_simple {
struct gpio_desc *hpd_gpio;
struct drm_display_mode override_mode;
+
+ enum drm_panel_orientation orientation;
};
static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
@@ -371,6 +373,9 @@ static int panel_simple_get_modes(struct drm_panel *panel,
/* add hard-coded panel modes */
num += panel_simple_get_non_edid_modes(p, connector);
+ /* set up connector's "panel orientation" property */
+ drm_connector_set_panel_orientation(connector, p->orientation);
+
return num;
}
@@ -500,6 +505,8 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
struct panel_simple *panel;
struct display_timing dt;
struct device_node *ddc;
+ int connector_type;
+ u32 bus_flags;
int err;
panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
@@ -530,6 +537,12 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
return err;
}
+ err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
+ if (err) {
+ dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
+ return err;
+ }
+
ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
if (ddc) {
panel->ddc = of_find_i2c_adapter_by_node(ddc);
@@ -549,8 +562,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
panel_simple_parse_panel_timing_node(dev, panel, &dt);
}
- if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) {
- /* Catch common mistakes for LVDS panels. */
+ connector_type = desc->connector_type;
+ /* Catch common mistakes for panels. */
+ switch (connector_type) {
+ case 0:
+ dev_warn(dev, "Specify missing connector_type\n");
+ connector_type = DRM_MODE_CONNECTOR_DPI;
+ break;
+ case DRM_MODE_CONNECTOR_LVDS:
WARN_ON(desc->bus_flags &
~(DRM_BUS_FLAG_DE_LOW |
DRM_BUS_FLAG_DE_HIGH |
@@ -564,18 +583,48 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG ||
desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) &&
desc->bpc != 8);
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ if (desc->bus_format == 0)
+ dev_warn(dev, "Specify missing bus_format\n");
+ if (desc->bpc != 6 && desc->bpc != 8)
+ dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
+ break;
+ case DRM_MODE_CONNECTOR_DSI:
+ if (desc->bpc != 6 && desc->bpc != 8)
+ dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
+ break;
+ case DRM_MODE_CONNECTOR_DPI:
+ bus_flags = DRM_BUS_FLAG_DE_LOW |
+ DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_DATA_MSB_TO_LSB |
+ DRM_BUS_FLAG_DATA_LSB_TO_MSB |
+ DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE;
+ if (desc->bus_flags & ~bus_flags)
+ dev_warn(dev, "Unexpected bus_flags(%d)\n", desc->bus_flags & ~bus_flags);
+ if (!(desc->bus_flags & bus_flags))
+ dev_warn(dev, "Specify missing bus_flags\n");
+ if (desc->bus_format == 0)
+ dev_warn(dev, "Specify missing bus_format\n");
+ if (desc->bpc != 6 && desc->bpc != 8)
+ dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
+ break;
+ default:
+ dev_warn(dev, "Specify a valid connector_type: %d\n", desc->connector_type);
+ connector_type = DRM_MODE_CONNECTOR_DPI;
+ break;
}
- drm_panel_init(&panel->base, dev, &panel_simple_funcs,
- desc->connector_type);
+ drm_panel_init(&panel->base, dev, &panel_simple_funcs, connector_type);
err = drm_panel_of_backlight(&panel->base);
if (err)
goto free_ddc;
- err = drm_panel_add(&panel->base);
- if (err < 0)
- goto free_ddc;
+ drm_panel_add(&panel->base);
dev_set_drvdata(dev, panel);
@@ -1191,10 +1240,14 @@ static const struct drm_display_mode boe_hv070wsa_mode = {
static const struct panel_desc boe_hv070wsa = {
.modes = &boe_hv070wsa_mode,
.num_modes = 1,
+ .bpc = 8,
.size = {
.width = 154,
.height = 90,
},
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+ .connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode boe_nv101wxmn51_modes[] = {
@@ -1414,6 +1467,36 @@ static const struct panel_desc cdtech_s070wv95_ct16 = {
},
};
+static const struct display_timing chefree_ch101olhlwh_002_timing = {
+ .pixelclock = { 68900000, 71100000, 73400000 },
+ .hactive = { 1280, 1280, 1280 },
+ .hfront_porch = { 65, 80, 95 },
+ .hback_porch = { 64, 79, 94 },
+ .hsync_len = { 1, 1, 1 },
+ .vactive = { 800, 800, 800 },
+ .vfront_porch = { 7, 11, 14 },
+ .vback_porch = { 7, 11, 14 },
+ .vsync_len = { 1, 1, 1 },
+ .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc chefree_ch101olhlwh_002 = {
+ .timings = &chefree_ch101olhlwh_002_timing,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 217,
+ .height = 135,
+ },
+ .delay = {
+ .enable = 200,
+ .disable = 200,
+ },
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+ .connector_type = DRM_MODE_CONNECTOR_LVDS,
+};
+
static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
.clock = 66770,
.hdisplay = 800,
@@ -2258,6 +2341,34 @@ static const struct panel_desc ivo_m133nwf4_r0 = {
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
+static const struct drm_display_mode kingdisplay_kd116n21_30nv_a010_mode = {
+ .clock = 81000,
+ .hdisplay = 1366,
+ .hsync_start = 1366 + 40,
+ .hsync_end = 1366 + 40 + 32,
+ .htotal = 1366 + 40 + 32 + 62,
+ .vdisplay = 768,
+ .vsync_start = 768 + 5,
+ .vsync_end = 768 + 5 + 5,
+ .vtotal = 768 + 5 + 5 + 122,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc kingdisplay_kd116n21_30nv_a010 = {
+ .modes = &kingdisplay_kd116n21_30nv_a010_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 256,
+ .height = 144,
+ },
+ .delay = {
+ .hpd_absent_delay = 200,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+ .connector_type = DRM_MODE_CONNECTOR_eDP,
+};
+
static const struct display_timing koe_tx14d24vm1bpa_timing = {
.pixelclock = { 5580000, 5850000, 6200000 },
.hactive = { 320, 320, 320 },
@@ -2946,7 +3057,7 @@ static const struct panel_desc ortustech_com43h4m85ulc = {
.width = 56,
.height = 93,
},
- .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
@@ -3000,6 +3111,31 @@ static const struct panel_desc pda_91_00156_a0 = {
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
};
+static const struct drm_display_mode powertip_ph800480t013_idf02_mode = {
+ .clock = 24750,
+ .hdisplay = 800,
+ .hsync_start = 800 + 54,
+ .hsync_end = 800 + 54 + 2,
+ .htotal = 800 + 54 + 2 + 44,
+ .vdisplay = 480,
+ .vsync_start = 480 + 49,
+ .vsync_end = 480 + 49 + 2,
+ .vtotal = 480 + 49 + 2 + 22,
+};
+
+static const struct panel_desc powertip_ph800480t013_idf02 = {
+ .modes = &powertip_ph800480t013_idf02_mode,
+ .num_modes = 1,
+ .size = {
+ .width = 152,
+ .height = 91,
+ },
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+ .connector_type = DRM_MODE_CONNECTOR_DPI,
+};
static const struct drm_display_mode qd43003c0_40_mode = {
.clock = 9000,
@@ -3301,22 +3437,36 @@ static const struct panel_desc sharp_lq123p1jx31 = {
},
};
-static const struct display_timing sharp_ls020b1dd01d_timing = {
- .pixelclock = { 2000000, 4200000, 5000000 },
- .hactive = { 240, 240, 240 },
- .hfront_porch = { 66, 66, 66 },
- .hback_porch = { 1, 1, 1 },
- .hsync_len = { 1, 1, 1 },
- .vactive = { 160, 160, 160 },
- .vfront_porch = { 52, 52, 52 },
- .vback_porch = { 6, 6, 6 },
- .vsync_len = { 10, 10, 10 },
- .flags = DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW,
+static const struct drm_display_mode sharp_ls020b1dd01d_modes[] = {
+ { /* 50 Hz */
+ .clock = 3000,
+ .hdisplay = 240,
+ .hsync_start = 240 + 58,
+ .hsync_end = 240 + 58 + 1,
+ .htotal = 240 + 58 + 1 + 1,
+ .vdisplay = 160,
+ .vsync_start = 160 + 24,
+ .vsync_end = 160 + 24 + 10,
+ .vtotal = 160 + 24 + 10 + 6,
+ .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+ { /* 60 Hz */
+ .clock = 3000,
+ .hdisplay = 240,
+ .hsync_start = 240 + 8,
+ .hsync_end = 240 + 8 + 1,
+ .htotal = 240 + 8 + 1 + 1,
+ .vdisplay = 160,
+ .vsync_start = 160 + 24,
+ .vsync_end = 160 + 24 + 10,
+ .vtotal = 160 + 24 + 10 + 6,
+ .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
};
static const struct panel_desc sharp_ls020b1dd01d = {
- .timings = &sharp_ls020b1dd01d_timing,
- .num_timings = 1,
+ .modes = sharp_ls020b1dd01d_modes,
+ .num_modes = ARRAY_SIZE(sharp_ls020b1dd01d_modes),
.bpc = 6,
.size = {
.width = 42,
@@ -3821,6 +3971,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "cdtech,s070wv95-ct16",
.data = &cdtech_s070wv95_ct16,
}, {
+ .compatible = "chefree,ch101olhlwh-002",
+ .data = &chefree_ch101olhlwh_002,
+ }, {
.compatible = "chunghwa,claa070wp03xg",
.data = &chunghwa_claa070wp03xg,
}, {
@@ -3923,6 +4076,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "ivo,m133nwf4-r0",
.data = &ivo_m133nwf4_r0,
}, {
+ .compatible = "kingdisplay,kd116n21-30nv-a010",
+ .data = &kingdisplay_kd116n21_30nv_a010,
+ }, {
.compatible = "koe,tx14d24vm1bpa",
.data = &koe_tx14d24vm1bpa,
}, {
@@ -4013,6 +4169,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "pda,91-00156-a0",
.data = &pda_91_00156_a0,
}, {
+ .compatible = "powertip,ph800480t013-idf02",
+ .data = &powertip_ph800480t013_idf02,
+ }, {
.compatible = "qiaodian,qd43003c0-40",
.data = &qd43003c0_40,
}, {
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
index 692041ae4eb6..4d2a149b202c 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
@@ -7,7 +7,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
@@ -269,10 +268,9 @@ static int st7701_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, desc_mode);
if (!mode) {
- DRM_DEV_ERROR(&st7701->dsi->dev,
- "failed to add mode %ux%ux@%u\n",
- desc_mode->hdisplay, desc_mode->vdisplay,
- drm_mode_vrefresh(desc_mode));
+ dev_err(&st7701->dsi->dev, "failed to add mode %ux%u@%u\n",
+ desc_mode->hdisplay, desc_mode->vdisplay,
+ drm_mode_vrefresh(desc_mode));
return -ENOMEM;
}
@@ -358,7 +356,7 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(st7701->reset)) {
- DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n");
+ dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
return PTR_ERR(st7701->reset);
}
@@ -380,9 +378,7 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
if (ret)
return ret;
- ret = drm_panel_add(&st7701->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&st7701->panel);
mipi_dsi_set_drvdata(dsi, st7701);
st7701->dsi = dsi;
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c
index 8996ced2b721..c22e7c49e077 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c
@@ -22,7 +22,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define DRV_NAME "panel-sitronix-st7703"
@@ -364,8 +363,7 @@ static int st7703_enable(struct drm_panel *panel)
ret = ctx->desc->init_sequence(ctx);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
- ret);
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
return ret;
}
@@ -373,7 +371,7 @@ static int st7703_enable(struct drm_panel *panel)
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
+ dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
@@ -384,7 +382,7 @@ static int st7703_enable(struct drm_panel *panel)
if (ret)
return ret;
- DRM_DEV_DEBUG_DRIVER(ctx->dev, "Panel init sequence done\n");
+ dev_dbg(ctx->dev, "Panel init sequence done\n");
return 0;
}
@@ -397,13 +395,11 @@ static int st7703_disable(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0)
- DRM_DEV_ERROR(ctx->dev,
- "Failed to turn off the display: %d\n", ret);
+ dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0)
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enter sleep mode: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
return 0;
}
@@ -431,17 +427,15 @@ static int st7703_prepare(struct drm_panel *panel)
if (ctx->prepared)
return 0;
- DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
+ dev_dbg(ctx->dev, "Resetting the panel\n");
ret = regulator_enable(ctx->vcc);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable vcc supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
return ret;
}
ret = regulator_enable(ctx->iovcc);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable iovcc supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
goto disable_vcc;
}
@@ -467,9 +461,9 @@ static int st7703_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
if (!mode) {
- DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
- ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
- drm_mode_vrefresh(ctx->desc->mode));
+ dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
+ ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+ drm_mode_vrefresh(ctx->desc->mode));
return -ENOMEM;
}
@@ -496,7 +490,7 @@ static int allpixelson_set(void *data, u64 val)
struct st7703 *ctx = data;
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
- DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n");
+ dev_dbg(ctx->dev, "Setting all pixels on\n");
dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
msleep(val * 1000);
/* Reset the panel to get video back */
@@ -537,7 +531,7 @@ static int st7703_probe(struct mipi_dsi_device *dsi)
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
+ dev_err(dev, "cannot get reset gpio\n");
return PTR_ERR(ctx->reset_gpio);
}
@@ -554,18 +548,14 @@ static int st7703_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->vcc)) {
ret = PTR_ERR(ctx->vcc);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request vcc regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request vcc regulator: %d\n", ret);
return ret;
}
ctx->iovcc = devm_regulator_get(dev, "iovcc");
if (IS_ERR(ctx->iovcc)) {
ret = PTR_ERR(ctx->iovcc);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request iovcc regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
return ret;
}
@@ -580,17 +570,15 @@ static int st7703_probe(struct mipi_dsi_device *dsi)
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev,
- "mipi_dsi_attach failed (%d). Is host ready?\n",
- ret);
+ dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
- DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
- ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
- drm_mode_vrefresh(ctx->desc->mode),
- mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
+ dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
+ ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+ drm_mode_vrefresh(ctx->desc->mode),
+ mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
st7703_debugfs_init(ctx);
return 0;
@@ -603,13 +591,11 @@ static void st7703_shutdown(struct mipi_dsi_device *dsi)
ret = drm_panel_unprepare(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
ret = drm_panel_disable(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
}
static int st7703_remove(struct mipi_dsi_device *dsi)
@@ -621,8 +607,7 @@ static int st7703_remove(struct mipi_dsi_device *dsi)
ret = mipi_dsi_detach(dsi);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index 3513ae40efa8..61e565524542 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -382,9 +382,7 @@ static int st7789v_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = drm_panel_add(&ctx->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&ctx->panel);
return 0;
}
diff --git a/drivers/gpu/drm/panel/panel-sony-acx424akp.c b/drivers/gpu/drm/panel/panel-sony-acx424akp.c
index 97a1b4790d3c..065efae213f5 100644
--- a/drivers/gpu/drm/panel/panel-sony-acx424akp.c
+++ b/drivers/gpu/drm/panel/panel-sony-acx424akp.c
@@ -20,7 +20,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#define ACX424_DCS_READ_ID1 0xDA
#define ACX424_DCS_READ_ID2 0xDB
@@ -110,13 +109,11 @@ static int acx424akp_set_brightness(struct backlight_device *bl)
SCALE_FACTOR_NS_DIV_MHZ);
/* Set up PWM dutycycle ONE byte (differs from the standard) */
- DRM_DEV_DEBUG(acx->dev, "calculated duty cycle %02x\n", pwm_ratio);
+ dev_dbg(acx->dev, "calculated duty cycle %02x\n", pwm_ratio);
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
&pwm_ratio, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev,
- "failed to set display PWM ratio (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to set display PWM ratio (%d)\n", ret);
return ret;
}
@@ -132,40 +129,30 @@ static int acx424akp_set_brightness(struct backlight_device *bl)
par = 0xaa;
ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev,
- "failed to unlock CMD 2 (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to unlock CMD 2 (%d)\n", ret);
return ret;
}
par = 0x01;
ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev,
- "failed to enter page 1 (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to enter page 1 (%d)\n", ret);
return ret;
}
par = 0x01;
ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev,
- "failed to disable MTP reload (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to disable MTP reload (%d)\n", ret);
return ret;
}
ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev,
- "failed to set PWM divisor (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to set PWM divisor (%d)\n", ret);
return ret;
}
par = 0xaa;
ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev,
- "failed to lock CMD 2 (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to lock CMD 2 (%d)\n", ret);
return ret;
}
@@ -174,9 +161,7 @@ static int acx424akp_set_brightness(struct backlight_device *bl)
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
&par, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev,
- "failed to enable display backlight (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to enable display backlight (%d)\n", ret);
return ret;
}
@@ -196,22 +181,22 @@ static int acx424akp_read_id(struct acx424akp *acx)
ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &vendor, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev, "could not vendor ID byte\n");
+ dev_err(acx->dev, "could not vendor ID byte\n");
return ret;
}
ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &version, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev, "could not read device version byte\n");
+ dev_err(acx->dev, "could not read device version byte\n");
return ret;
}
ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &panel, 1);
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev, "could not read panel ID byte\n");
+ dev_err(acx->dev, "could not read panel ID byte\n");
return ret;
}
if (vendor == 0x00) {
- DRM_DEV_ERROR(acx->dev, "device vendor ID is zero\n");
+ dev_err(acx->dev, "device vendor ID is zero\n");
return -ENODEV;
}
@@ -220,14 +205,12 @@ static int acx424akp_read_id(struct acx424akp *acx)
case DISPLAY_SONY_ACX424AKP_ID1:
case DISPLAY_SONY_ACX424AKP_ID2:
case DISPLAY_SONY_ACX424AKP_ID3:
- DRM_DEV_INFO(acx->dev,
- "MTP vendor: %02x, version: %02x, panel: %02x\n",
- vendor, version, panel);
+ dev_info(acx->dev, "MTP vendor: %02x, version: %02x, panel: %02x\n",
+ vendor, version, panel);
break;
default:
- DRM_DEV_INFO(acx->dev,
- "unknown vendor: %02x, version: %02x, panel: %02x\n",
- vendor, version, panel);
+ dev_info(acx->dev, "unknown vendor: %02x, version: %02x, panel: %02x\n",
+ vendor, version, panel);
break;
}
@@ -240,7 +223,7 @@ static int acx424akp_power_on(struct acx424akp *acx)
ret = regulator_enable(acx->supply);
if (ret) {
- DRM_DEV_ERROR(acx->dev, "failed to enable supply (%d)\n", ret);
+ dev_err(acx->dev, "failed to enable supply (%d)\n", ret);
return ret;
}
@@ -276,7 +259,7 @@ static int acx424akp_prepare(struct drm_panel *panel)
ret = acx424akp_read_id(acx);
if (ret) {
- DRM_DEV_ERROR(acx->dev, "failed to read panel ID (%d)\n", ret);
+ dev_err(acx->dev, "failed to read panel ID (%d)\n", ret);
goto err_power_off;
}
@@ -284,8 +267,7 @@ static int acx424akp_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_tear_on(dsi,
MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret) {
- DRM_DEV_ERROR(acx->dev, "failed to enable vblank TE (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to enable vblank TE (%d)\n", ret);
goto err_power_off;
}
@@ -302,23 +284,21 @@ static int acx424akp_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_write(dsi, ACX424_DCS_SET_MDDI,
&mddi, sizeof(mddi));
if (ret < 0) {
- DRM_DEV_ERROR(acx->dev, "failed to set MDDI (%d)\n", ret);
+ dev_err(acx->dev, "failed to set MDDI (%d)\n", ret);
goto err_power_off;
}
/* Exit sleep mode */
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret) {
- DRM_DEV_ERROR(acx->dev, "failed to exit sleep mode (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to exit sleep mode (%d)\n", ret);
goto err_power_off;
}
msleep(140);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret) {
- DRM_DEV_ERROR(acx->dev, "failed to turn display on (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to turn display on (%d)\n", ret);
goto err_power_off;
}
if (acx->video_mode) {
@@ -351,24 +331,20 @@ static int acx424akp_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
&par, 1);
if (ret) {
- DRM_DEV_ERROR(acx->dev,
- "failed to disable display backlight (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to disable display backlight (%d)\n", ret);
return ret;
}
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret) {
- DRM_DEV_ERROR(acx->dev, "failed to turn display off (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to turn display off (%d)\n", ret);
return ret;
}
/* Enter sleep mode */
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret) {
- DRM_DEV_ERROR(acx->dev, "failed to enter sleep mode (%d)\n",
- ret);
+ dev_err(acx->dev, "failed to enter sleep mode (%d)\n", ret);
return ret;
}
msleep(85);
@@ -418,7 +394,7 @@ static int acx424akp_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev,
&sony_acx424akp_cmd_mode);
if (!mode) {
- DRM_ERROR("bad mode or failed to add mode\n");
+ dev_err(panel->dev, "bad mode or failed to add mode\n");
return -EINVAL;
}
drm_mode_set_name(mode);
@@ -486,8 +462,7 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(acx->reset_gpio)) {
ret = PTR_ERR(acx->reset_gpio);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n",
- ret);
+ dev_err(dev, "failed to request GPIO (%d)\n", ret);
return ret;
}
@@ -497,16 +472,14 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi)
acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx,
&acx424akp_bl_ops, NULL);
if (IS_ERR(acx->bl)) {
- DRM_DEV_ERROR(dev, "failed to register backlight device\n");
+ dev_err(dev, "failed to register backlight device\n");
return PTR_ERR(acx->bl);
}
acx->bl->props.max_brightness = 1023;
acx->bl->props.brightness = 512;
acx->bl->props.power = FB_BLANK_POWERDOWN;
- ret = drm_panel_add(&acx->panel);
- if (ret < 0)
- return ret;
+ drm_panel_add(&acx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
diff --git a/drivers/gpu/drm/panel/panel-sony-acx565akm.c b/drivers/gpu/drm/panel/panel-sony-acx565akm.c
index fc6a7e451abe..e95fdfb16b6c 100644
--- a/drivers/gpu/drm/panel/panel-sony-acx565akm.c
+++ b/drivers/gpu/drm/panel/panel-sony-acx565akm.c
@@ -650,12 +650,7 @@ static int acx565akm_probe(struct spi_device *spi)
drm_panel_init(&lcd->panel, &lcd->spi->dev, &acx565akm_funcs,
DRM_MODE_CONNECTOR_DPI);
- ret = drm_panel_add(&lcd->panel);
- if (ret < 0) {
- if (lcd->has_bc)
- acx565akm_backlight_cleanup(lcd);
- return ret;
- }
+ drm_panel_add(&lcd->panel);
return 0;
}
diff --git a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
index 58d683cc5215..037c14fd6bac 100644
--- a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
+++ b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
@@ -350,7 +350,9 @@ static int td028ttec1_probe(struct spi_device *spi)
if (ret)
return ret;
- return drm_panel_add(&lcd->panel);
+ drm_panel_add(&lcd->panel);
+
+ return 0;
}
static int td028ttec1_remove(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c
index 9b2a356c4d9a..49e6c9386258 100644
--- a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c
+++ b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c
@@ -460,11 +460,7 @@ static int td043mtea1_probe(struct spi_device *spi)
drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs,
DRM_MODE_CONNECTOR_DPI);
- ret = drm_panel_add(&lcd->panel);
- if (ret < 0) {
- sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group);
- return ret;
- }
+ drm_panel_add(&lcd->panel);
return 0;
}
diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c
index c7a2f0ae5ba5..d57ed75a977c 100644
--- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c
+++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c
@@ -12,7 +12,6 @@
*/
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@@ -238,7 +237,7 @@ static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write,
spi_message_add_tail(&t[1], &m);
ret = spi_sync(tpg->spi, &m);
if (ret) {
- DRM_DEV_ERROR(tpg->dev, "SPI message error %d\n", ret);
+ dev_err(tpg->dev, "SPI message error %d\n", ret);
return ret;
}
if (write)
@@ -265,18 +264,18 @@ static int tpg110_startup(struct tpg110 *tpg)
/* De-assert the reset signal */
gpiod_set_value_cansleep(tpg->grestb, 0);
usleep_range(1000, 2000);
- DRM_DEV_DEBUG(tpg->dev, "de-asserted GRESTB\n");
+ dev_dbg(tpg->dev, "de-asserted GRESTB\n");
/* Test display communication */
tpg110_write_reg(tpg, TPG110_TEST, 0x55);
val = tpg110_read_reg(tpg, TPG110_TEST);
if (val != 0x55) {
- DRM_DEV_ERROR(tpg->dev, "failed communication test\n");
+ dev_err(tpg->dev, "failed communication test\n");
return -ENODEV;
}
val = tpg110_read_reg(tpg, TPG110_CHIPID);
- DRM_DEV_INFO(tpg->dev, "TPG110 chip ID: %d version: %d\n",
+ dev_info(tpg->dev, "TPG110 chip ID: %d version: %d\n",
val >> 4, val & 0x0f);
/* Show display resolution */
@@ -284,27 +283,25 @@ static int tpg110_startup(struct tpg110 *tpg)
val &= TPG110_RES_MASK;
switch (val) {
case TPG110_RES_400X240_D:
- DRM_DEV_INFO(tpg->dev,
- "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n");
+ dev_info(tpg->dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n");
break;
case TPG110_RES_480X272_D:
- DRM_DEV_INFO(tpg->dev,
- "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n");
+ dev_info(tpg->dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n");
break;
case TPG110_RES_480X640:
- DRM_DEV_INFO(tpg->dev, "480x640 RGB\n");
+ dev_info(tpg->dev, "480x640 RGB\n");
break;
case TPG110_RES_480X272:
- DRM_DEV_INFO(tpg->dev, "480x272 RGB\n");
+ dev_info(tpg->dev, "480x272 RGB\n");
break;
case TPG110_RES_640X480:
- DRM_DEV_INFO(tpg->dev, "640x480 RGB\n");
+ dev_info(tpg->dev, "640x480 RGB\n");
break;
case TPG110_RES_800X480:
- DRM_DEV_INFO(tpg->dev, "800x480 RGB\n");
+ dev_info(tpg->dev, "800x480 RGB\n");
break;
default:
- DRM_DEV_ERROR(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val);
+ dev_err(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val);
break;
}
@@ -322,13 +319,12 @@ static int tpg110_startup(struct tpg110 *tpg)
}
}
if (i == ARRAY_SIZE(tpg110_modes)) {
- DRM_DEV_ERROR(tpg->dev, "unsupported mode (%02x) detected\n",
- val);
+ dev_err(tpg->dev, "unsupported mode (%02x) detected\n", val);
return -ENODEV;
}
val = tpg110_read_reg(tpg, TPG110_CTRL2);
- DRM_DEV_INFO(tpg->dev, "resolution and standby is controlled by %s\n",
+ dev_info(tpg->dev, "resolution and standby is controlled by %s\n",
(val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware");
/* Take control over resolution and standby */
val |= TPG110_CTRL2_RES_PM_CTRL;
@@ -414,15 +410,15 @@ static int tpg110_probe(struct spi_device *spi)
/* We get the physical display dimensions from the DT */
ret = of_property_read_u32(np, "width-mm", &tpg->width);
if (ret)
- DRM_DEV_ERROR(dev, "no panel width specified\n");
+ dev_err(dev, "no panel width specified\n");
ret = of_property_read_u32(np, "height-mm", &tpg->height);
if (ret)
- DRM_DEV_ERROR(dev, "no panel height specified\n");
+ dev_err(dev, "no panel height specified\n");
/* This asserts the GRESTB signal, putting the display into reset */
tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH);
if (IS_ERR(tpg->grestb)) {
- DRM_DEV_ERROR(dev, "no GRESTB GPIO\n");
+ dev_err(dev, "no GRESTB GPIO\n");
return -ENODEV;
}
@@ -430,7 +426,7 @@ static int tpg110_probe(struct spi_device *spi)
spi->mode |= SPI_3WIRE_HIZ;
ret = spi_setup(spi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "spi setup failed.\n");
+ dev_err(dev, "spi setup failed.\n");
return ret;
}
tpg->spi = spi;
@@ -448,7 +444,9 @@ static int tpg110_probe(struct spi_device *spi)
spi_set_drvdata(spi, tpg);
- return drm_panel_add(&tpg->panel);
+ drm_panel_add(&tpg->panel);
+
+ return 0;
}
static int tpg110_remove(struct spi_device *spi)
diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c
index 9b9c167b8dc8..b24b92d93ea5 100644
--- a/drivers/gpu/drm/panel/panel-truly-nt35597.c
+++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c
@@ -17,7 +17,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
static const char * const regulator_names[] = {
"vdda",
@@ -231,9 +230,7 @@ static int truly_dcs_write(struct drm_panel *panel, u32 command)
for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
ret = mipi_dsi_dcs_write(ctx->dsi[i], command, NULL, 0);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "cmd 0x%x failed for dsi = %d\n",
- command, i);
+ dev_err(ctx->dev, "cmd 0x%x failed for dsi = %d\n", command, i);
}
}
@@ -250,8 +247,7 @@ static int truly_dcs_write_buf(struct drm_panel *panel,
for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
ret = mipi_dsi_dcs_write_buffer(ctx->dsi[i], buf, size);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "failed to tx cmd [%d], err: %d\n", i, ret);
+ dev_err(ctx->dev, "failed to tx cmd [%d], err: %d\n", i, ret);
return ret;
}
}
@@ -300,16 +296,14 @@ static int truly_nt35597_power_off(struct truly_nt35597 *ctx)
ret = regulator_set_load(ctx->supplies[i].consumer,
regulator_disable_loads[i]);
if (ret) {
- DRM_DEV_ERROR(ctx->dev,
- "regulator_set_load failed %d\n", ret);
+ dev_err(ctx->dev, "regulator_set_load failed %d\n", ret);
return ret;
}
}
ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret) {
- DRM_DEV_ERROR(ctx->dev,
- "regulator_bulk_disable failed %d\n", ret);
+ dev_err(ctx->dev, "regulator_bulk_disable failed %d\n", ret);
}
return ret;
}
@@ -325,8 +319,7 @@ static int truly_nt35597_disable(struct drm_panel *panel)
if (ctx->backlight) {
ret = backlight_disable(ctx->backlight);
if (ret < 0)
- DRM_DEV_ERROR(ctx->dev, "backlight disable failed %d\n",
- ret);
+ dev_err(ctx->dev, "backlight disable failed %d\n", ret);
}
ctx->enabled = false;
@@ -346,9 +339,7 @@ static int truly_nt35597_unprepare(struct drm_panel *panel)
ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_OFF);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "set_display_off cmd failed ret = %d\n",
- ret);
+ dev_err(ctx->dev, "set_display_off cmd failed ret = %d\n", ret);
}
/* 120ms delay required here as per DCS spec */
@@ -356,13 +347,12 @@ static int truly_nt35597_unprepare(struct drm_panel *panel)
ret = truly_dcs_write(panel, MIPI_DCS_ENTER_SLEEP_MODE);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "enter_sleep cmd failed ret = %d\n", ret);
+ dev_err(ctx->dev, "enter_sleep cmd failed ret = %d\n", ret);
}
ret = truly_nt35597_power_off(ctx);
if (ret < 0)
- DRM_DEV_ERROR(ctx->dev, "power_off failed ret = %d\n", ret);
+ dev_err(ctx->dev, "power_off failed ret = %d\n", ret);
ctx->prepared = false;
return ret;
@@ -396,18 +386,14 @@ static int truly_nt35597_prepare(struct drm_panel *panel)
panel_on_cmds[i].size,
panel_on_cmds[i].commands);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "cmd set tx failed i = %d ret = %d\n",
- i, ret);
+ dev_err(ctx->dev, "cmd set tx failed i = %d ret = %d\n", i, ret);
goto power_off;
}
}
ret = truly_dcs_write(panel, MIPI_DCS_EXIT_SLEEP_MODE);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "exit_sleep_mode cmd failed ret = %d\n",
- ret);
+ dev_err(ctx->dev, "exit_sleep_mode cmd failed ret = %d\n", ret);
goto power_off;
}
@@ -416,8 +402,7 @@ static int truly_nt35597_prepare(struct drm_panel *panel)
ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_ON);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "set_display_on cmd failed ret = %d\n", ret);
+ dev_err(ctx->dev, "set_display_on cmd failed ret = %d\n", ret);
goto power_off;
}
@@ -430,7 +415,7 @@ static int truly_nt35597_prepare(struct drm_panel *panel)
power_off:
if (truly_nt35597_power_off(ctx))
- DRM_DEV_ERROR(ctx->dev, "power_off failed\n");
+ dev_err(ctx->dev, "power_off failed\n");
return ret;
}
@@ -445,8 +430,7 @@ static int truly_nt35597_enable(struct drm_panel *panel)
if (ctx->backlight) {
ret = backlight_enable(ctx->backlight);
if (ret < 0)
- DRM_DEV_ERROR(ctx->dev, "backlight enable failed %d\n",
- ret);
+ dev_err(ctx->dev, "backlight enable failed %d\n", ret);
}
ctx->enabled = true;
@@ -464,8 +448,7 @@ static int truly_nt35597_get_modes(struct drm_panel *panel,
config = ctx->config;
mode = drm_mode_create(connector->dev);
if (!mode) {
- DRM_DEV_ERROR(ctx->dev,
- "failed to create a new display mode\n");
+ dev_err(ctx->dev, "failed to create a new display mode\n");
return 0;
}
@@ -501,15 +484,13 @@ static int truly_nt35597_panel_add(struct truly_nt35597 *ctx)
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n",
- PTR_ERR(ctx->reset_gpio));
+ dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio));
return PTR_ERR(ctx->reset_gpio);
}
ctx->mode_gpio = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW);
if (IS_ERR(ctx->mode_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get mode gpio %ld\n",
- PTR_ERR(ctx->mode_gpio));
+ dev_err(dev, "cannot get mode gpio %ld\n", PTR_ERR(ctx->mode_gpio));
return PTR_ERR(ctx->mode_gpio);
}
@@ -584,22 +565,21 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi)
dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
if (!dsi1) {
- DRM_DEV_ERROR(dev,
- "failed to get remote node for dsi1_device\n");
+ dev_err(dev, "failed to get remote node for dsi1_device\n");
return -ENODEV;
}
dsi1_host = of_find_mipi_dsi_host_by_node(dsi1);
of_node_put(dsi1);
if (!dsi1_host) {
- DRM_DEV_ERROR(dev, "failed to find dsi host\n");
+ dev_err(dev, "failed to find dsi host\n");
return -EPROBE_DEFER;
}
/* register the second DSI device */
dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info);
if (IS_ERR(dsi1_device)) {
- DRM_DEV_ERROR(dev, "failed to create dsi device\n");
+ dev_err(dev, "failed to create dsi device\n");
return PTR_ERR(dsi1_device);
}
@@ -611,7 +591,7 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi)
ret = truly_nt35597_panel_add(ctx);
if (ret) {
- DRM_DEV_ERROR(dev, "failed to add panel\n");
+ dev_err(dev, "failed to add panel\n");
goto err_panel_add;
}
@@ -623,8 +603,7 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi)
MIPI_DSI_CLOCK_NON_CONTINUOUS;
ret = mipi_dsi_attach(dsi_dev);
if (ret < 0) {
- DRM_DEV_ERROR(dev,
- "dsi attach failed i = %d\n", i);
+ dev_err(dev, "dsi attach failed i = %d\n", i);
goto err_dsi_attach;
}
}
diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c
index a12976b497ce..eb43503ec97b 100644
--- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c
+++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c
@@ -14,7 +14,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
struct visionox_rm69299 {
struct drm_panel panel;
@@ -69,16 +68,14 @@ static int visionox_rm69299_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);
if (ret < 0)
- DRM_DEV_ERROR(ctx->panel.dev,
- "set_display_off cmd failed ret = %d\n", ret);
+ dev_err(ctx->panel.dev, "set_display_off cmd failed ret = %d\n", ret);
/* 120ms delay required here as per DCS spec */
msleep(120);
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->panel.dev,
- "enter_sleep cmd failed ret = %d\n", ret);
+ dev_err(ctx->panel.dev, "enter_sleep cmd failed ret = %d\n", ret);
}
ret = visionox_rm69299_power_off(ctx);
@@ -103,36 +100,31 @@ static int visionox_rm69299_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->panel.dev,
- "cmd set tx 0 failed, ret = %d\n", ret);
+ dev_err(ctx->panel.dev, "cmd set tx 0 failed, ret = %d\n", ret);
goto power_off;
}
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->panel.dev,
- "cmd set tx 1 failed, ret = %d\n", ret);
+ dev_err(ctx->panel.dev, "cmd set tx 1 failed, ret = %d\n", ret);
goto power_off;
}
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->panel.dev,
- "cmd set tx 2 failed, ret = %d\n", ret);
+ dev_err(ctx->panel.dev, "cmd set tx 2 failed, ret = %d\n", ret);
goto power_off;
}
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->panel.dev,
- "cmd set tx 3 failed, ret = %d\n", ret);
+ dev_err(ctx->panel.dev, "cmd set tx 3 failed, ret = %d\n", ret);
goto power_off;
}
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->panel.dev,
- "exit_sleep_mode cmd failed ret = %d\n", ret);
+ dev_err(ctx->panel.dev, "exit_sleep_mode cmd failed ret = %d\n", ret);
goto power_off;
}
@@ -141,8 +133,7 @@ static int visionox_rm69299_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->panel.dev,
- "set_display_on cmd failed ret = %d\n", ret);
+ dev_err(ctx->panel.dev, "set_display_on cmd failed ret = %d\n", ret);
goto power_off;
}
@@ -179,8 +170,7 @@ static int visionox_rm69299_get_modes(struct drm_panel *panel,
mode = drm_mode_create(connector->dev);
if (!mode) {
- DRM_DEV_ERROR(ctx->panel.dev,
- "failed to create a new display mode\n");
+ dev_err(ctx->panel.dev, "failed to create a new display mode\n");
return 0;
}
@@ -225,8 +215,7 @@ static int visionox_rm69299_probe(struct mipi_dsi_device *dsi)
ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n",
- PTR_ERR(ctx->reset_gpio));
+ dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio));
return PTR_ERR(ctx->reset_gpio);
}
@@ -242,23 +231,19 @@ static int visionox_rm69299_probe(struct mipi_dsi_device *dsi)
MIPI_DSI_CLOCK_NON_CONTINUOUS;
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "dsi attach failed ret = %d\n", ret);
+ dev_err(dev, "dsi attach failed ret = %d\n", ret);
goto err_dsi_attach;
}
ret = regulator_set_load(ctx->supplies[0].consumer, 32000);
if (ret) {
- DRM_DEV_ERROR(dev,
- "regulator set load failed for vdda supply ret = %d\n",
- ret);
+ dev_err(dev, "regulator set load failed for vdda supply ret = %d\n", ret);
goto err_set_load;
}
ret = regulator_set_load(ctx->supplies[1].consumer, 13200);
if (ret) {
- DRM_DEV_ERROR(dev,
- "regulator set load failed for vdd3p3 supply ret = %d\n",
- ret);
+ dev_err(dev, "regulator set load failed for vdd3p3 supply ret = %d\n", ret);
goto err_set_load;
}
diff --git a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c
index 06341deb60ca..55172d63a922 100644
--- a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c
+++ b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c
@@ -12,7 +12,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
#include <video/display_timing.h>
#include <video/mipi_display.h>
@@ -135,7 +134,7 @@ static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
msleep(60);
- DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n");
+ dev_dbg(dev, "Panel init sequence done\n");
return 0;
}
@@ -150,13 +149,11 @@ static int xpp055c272_unprepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0)
- DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n",
- ret);
+ dev_err(ctx->dev, "failed to set display off: %d\n", ret);
mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n",
- ret);
+ dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
return ret;
}
@@ -177,17 +174,15 @@ static int xpp055c272_prepare(struct drm_panel *panel)
if (ctx->prepared)
return 0;
- DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
+ dev_dbg(ctx->dev, "Resetting the panel\n");
ret = regulator_enable(ctx->vci);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable vci supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
return ret;
}
ret = regulator_enable(ctx->iovcc);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev,
- "Failed to enable iovcc supply: %d\n", ret);
+ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
goto disable_vci;
}
@@ -201,14 +196,13 @@ static int xpp055c272_prepare(struct drm_panel *panel)
ret = xpp055c272_init_sequence(ctx);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
- ret);
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
goto disable_iovcc;
}
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
+ dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
goto disable_iovcc;
}
@@ -217,7 +211,7 @@ static int xpp055c272_prepare(struct drm_panel *panel)
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret);
+ dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
goto disable_iovcc;
}
@@ -256,9 +250,9 @@ static int xpp055c272_get_modes(struct drm_panel *panel,
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
- DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
- default_mode.hdisplay, default_mode.vdisplay,
- drm_mode_vrefresh(&default_mode));
+ dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
@@ -290,7 +284,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi)
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
- DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
+ dev_err(dev, "cannot get reset gpio\n");
return PTR_ERR(ctx->reset_gpio);
}
@@ -298,9 +292,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->vci)) {
ret = PTR_ERR(ctx->vci);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request vci regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request vci regulator: %d\n", ret);
return ret;
}
@@ -308,9 +300,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi)
if (IS_ERR(ctx->iovcc)) {
ret = PTR_ERR(ctx->iovcc);
if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dev,
- "Failed to request iovcc regulator: %d\n",
- ret);
+ dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
return ret;
}
@@ -334,7 +324,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi)
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
- DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret);
+ dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
@@ -349,13 +339,11 @@ static void xpp055c272_shutdown(struct mipi_dsi_device *dsi)
ret = drm_panel_unprepare(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
ret = drm_panel_disable(&ctx->panel);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
}
static int xpp055c272_remove(struct mipi_dsi_device *dsi)
@@ -367,8 +355,7 @@ static int xpp055c272_remove(struct mipi_dsi_device *dsi)
ret = mipi_dsi_detach(dsi);
if (ret < 0)
- DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
- ret);
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
index 413987038fbf..8ab025d0035f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
@@ -1,20 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2019 Collabora ltd. */
+
+#include <linux/clk.h>
#include <linux/devfreq.h>
#include <linux/devfreq_cooling.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
-#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
#include "panfrost_device.h"
#include "panfrost_devfreq.h"
-#include "panfrost_features.h"
-#include "panfrost_issues.h"
-#include "panfrost_gpu.h"
-#include "panfrost_regs.h"
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev);
+static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq)
+{
+ ktime_t now, last;
+
+ now = ktime_get();
+ last = pfdevfreq->time_last_update;
+
+ if (pfdevfreq->busy_count > 0)
+ pfdevfreq->busy_time += ktime_sub(now, last);
+ else
+ pfdevfreq->idle_time += ktime_sub(now, last);
+
+ pfdevfreq->time_last_update = now;
+}
static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
u32 flags)
@@ -34,30 +43,37 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
return 0;
}
-static void panfrost_devfreq_reset(struct panfrost_device *pfdev)
+static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq)
{
- pfdev->devfreq.busy_time = 0;
- pfdev->devfreq.idle_time = 0;
- pfdev->devfreq.time_last_update = ktime_get();
+ pfdevfreq->busy_time = 0;
+ pfdevfreq->idle_time = 0;
+ pfdevfreq->time_last_update = ktime_get();
}
static int panfrost_devfreq_get_dev_status(struct device *dev,
struct devfreq_dev_status *status)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
-
- panfrost_devfreq_update_utilization(pfdev);
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+ unsigned long irqflags;
status->current_frequency = clk_get_rate(pfdev->clock);
- status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time,
- pfdev->devfreq.idle_time));
- status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time);
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);
+
+ panfrost_devfreq_update_utilization(pfdevfreq);
+
+ status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time,
+ pfdevfreq->idle_time));
+
+ status->busy_time = ktime_to_ns(pfdevfreq->busy_time);
+
+ panfrost_devfreq_reset(pfdevfreq);
- panfrost_devfreq_reset(pfdev);
+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
- dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time,
- status->total_time,
+ dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
+ status->busy_time, status->total_time,
status->busy_time / (status->total_time / 100),
status->current_frequency / 1000 / 1000);
@@ -77,21 +93,43 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
unsigned long cur_freq;
struct device *dev = &pfdev->pdev->dev;
struct devfreq *devfreq;
+ struct opp_table *opp_table;
struct thermal_cooling_device *cooling;
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+
+ opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
+ pfdev->comp->num_supplies);
+ if (IS_ERR(opp_table)) {
+ ret = PTR_ERR(opp_table);
+ /* Continue if the optional regulator is missing */
+ if (ret != -ENODEV) {
+ DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");
+ goto err_fini;
+ }
+ } else {
+ pfdevfreq->regulators_opp_table = opp_table;
+ }
ret = dev_pm_opp_of_add_table(dev);
- if (ret == -ENODEV) /* Optional, continue without devfreq */
- return 0;
- else if (ret)
- return ret;
+ if (ret) {
+ /* Optional, continue without devfreq */
+ if (ret == -ENODEV)
+ ret = 0;
+ goto err_fini;
+ }
+ pfdevfreq->opp_of_table_added = true;
+
+ spin_lock_init(&pfdevfreq->lock);
- panfrost_devfreq_reset(pfdev);
+ panfrost_devfreq_reset(pfdevfreq);
cur_freq = clk_get_rate(pfdev->clock);
opp = devfreq_recommended_opp(dev, &cur_freq, 0);
- if (IS_ERR(opp))
- return PTR_ERR(opp);
+ if (IS_ERR(opp)) {
+ ret = PTR_ERR(opp);
+ goto err_fini;
+ }
panfrost_devfreq_profile.initial_freq = cur_freq;
dev_pm_opp_put(opp);
@@ -100,75 +138,94 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
if (IS_ERR(devfreq)) {
DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n");
- dev_pm_opp_of_remove_table(dev);
- return PTR_ERR(devfreq);
+ ret = PTR_ERR(devfreq);
+ goto err_fini;
}
- pfdev->devfreq.devfreq = devfreq;
+ pfdevfreq->devfreq = devfreq;
cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
if (IS_ERR(cooling))
DRM_DEV_INFO(dev, "Failed to register cooling device\n");
else
- pfdev->devfreq.cooling = cooling;
+ pfdevfreq->cooling = cooling;
return 0;
+
+err_fini:
+ panfrost_devfreq_fini(pfdev);
+ return ret;
}
void panfrost_devfreq_fini(struct panfrost_device *pfdev)
{
- if (pfdev->devfreq.cooling)
- devfreq_cooling_unregister(pfdev->devfreq.cooling);
- dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+
+ if (pfdevfreq->cooling) {
+ devfreq_cooling_unregister(pfdevfreq->cooling);
+ pfdevfreq->cooling = NULL;
+ }
+
+ if (pfdevfreq->opp_of_table_added) {
+ dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
+ pfdevfreq->opp_of_table_added = false;
+ }
+
+ if (pfdevfreq->regulators_opp_table) {
+ dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table);
+ pfdevfreq->regulators_opp_table = NULL;
+ }
}
void panfrost_devfreq_resume(struct panfrost_device *pfdev)
{
- if (!pfdev->devfreq.devfreq)
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+
+ if (!pfdevfreq->devfreq)
return;
- panfrost_devfreq_reset(pfdev);
+ panfrost_devfreq_reset(pfdevfreq);
- devfreq_resume_device(pfdev->devfreq.devfreq);
+ devfreq_resume_device(pfdevfreq->devfreq);
}
void panfrost_devfreq_suspend(struct panfrost_device *pfdev)
{
- if (!pfdev->devfreq.devfreq)
+ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+
+ if (!pfdevfreq->devfreq)
return;
- devfreq_suspend_device(pfdev->devfreq.devfreq);
+ devfreq_suspend_device(pfdevfreq->devfreq);
}
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev)
+void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq)
{
- ktime_t now;
- ktime_t last;
+ unsigned long irqflags;
- if (!pfdev->devfreq.devfreq)
+ if (!pfdevfreq->devfreq)
return;
- now = ktime_get();
- last = pfdev->devfreq.time_last_update;
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);
- if (atomic_read(&pfdev->devfreq.busy_count) > 0)
- pfdev->devfreq.busy_time += ktime_sub(now, last);
- else
- pfdev->devfreq.idle_time += ktime_sub(now, last);
+ panfrost_devfreq_update_utilization(pfdevfreq);
- pfdev->devfreq.time_last_update = now;
-}
+ pfdevfreq->busy_count++;
-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev)
-{
- panfrost_devfreq_update_utilization(pfdev);
- atomic_inc(&pfdev->devfreq.busy_count);
+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
}
-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev)
+void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq)
{
- int count;
+ unsigned long irqflags;
+
+ if (!pfdevfreq->devfreq)
+ return;
+
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);
+
+ panfrost_devfreq_update_utilization(pfdevfreq);
+
+ WARN_ON(--pfdevfreq->busy_count < 0);
- panfrost_devfreq_update_utilization(pfdev);
- count = atomic_dec_if_positive(&pfdev->devfreq.busy_count);
- WARN_ON(count < 0);
+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
index 0611beffc8d0..db6ea48e21f9 100644
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
@@ -4,13 +4,39 @@
#ifndef __PANFROST_DEVFREQ_H__
#define __PANFROST_DEVFREQ_H__
+#include <linux/spinlock.h>
+#include <linux/ktime.h>
+
+struct devfreq;
+struct opp_table;
+struct thermal_cooling_device;
+
+struct panfrost_device;
+
+struct panfrost_devfreq {
+ struct devfreq *devfreq;
+ struct opp_table *regulators_opp_table;
+ struct thermal_cooling_device *cooling;
+ bool opp_of_table_added;
+
+ ktime_t busy_time;
+ ktime_t idle_time;
+ ktime_t time_last_update;
+ int busy_count;
+ /*
+ * Protect busy_time, idle_time, time_last_update and busy_count
+ * because these can be updated concurrently between multiple jobs.
+ */
+ spinlock_t lock;
+};
+
int panfrost_devfreq_init(struct panfrost_device *pfdev);
void panfrost_devfreq_fini(struct panfrost_device *pfdev);
void panfrost_devfreq_resume(struct panfrost_device *pfdev);
void panfrost_devfreq_suspend(struct panfrost_device *pfdev);
-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev);
-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev);
+void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq);
+void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq);
#endif /* __PANFROST_DEVFREQ_H__ */
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index b172087eee6a..e6896733838a 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
{
int ret, i;
- if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators),
- "Too many supplies in compatible structure.\n"))
- return -EINVAL;
+ pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies,
+ sizeof(*pfdev->regulators),
+ GFP_KERNEL);
+ if (!pfdev->regulators)
+ return -ENOMEM;
for (i = 0; i < pfdev->comp->num_supplies; i++)
pfdev->regulators[i].supply = pfdev->comp->supply_names[i];
@@ -119,8 +121,10 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
static void panfrost_regulator_fini(struct panfrost_device *pfdev)
{
- regulator_bulk_disable(pfdev->comp->num_supplies,
- pfdev->regulators);
+ if (!pfdev->regulators)
+ return;
+
+ regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators);
}
static void panfrost_pm_domain_fini(struct panfrost_device *pfdev)
@@ -214,58 +218,70 @@ int panfrost_device_init(struct panfrost_device *pfdev)
return err;
}
- err = panfrost_regulator_init(pfdev);
- if (err)
- goto err_out0;
+ err = panfrost_devfreq_init(pfdev);
+ if (err) {
+ if (err != -EPROBE_DEFER)
+ dev_err(pfdev->dev, "devfreq init failed %d\n", err);
+ goto out_clk;
+ }
+
+ /* OPP will handle regulators */
+ if (!pfdev->pfdevfreq.opp_of_table_added) {
+ err = panfrost_regulator_init(pfdev);
+ if (err)
+ goto out_devfreq;
+ }
err = panfrost_reset_init(pfdev);
if (err) {
dev_err(pfdev->dev, "reset init failed %d\n", err);
- goto err_out1;
+ goto out_regulator;
}
err = panfrost_pm_domain_init(pfdev);
if (err)
- goto err_out2;
+ goto out_reset;
res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0);
pfdev->iomem = devm_ioremap_resource(pfdev->dev, res);
if (IS_ERR(pfdev->iomem)) {
dev_err(pfdev->dev, "failed to ioremap iomem\n");
err = PTR_ERR(pfdev->iomem);
- goto err_out3;
+ goto out_pm_domain;
}
err = panfrost_gpu_init(pfdev);
if (err)
- goto err_out3;
+ goto out_pm_domain;
err = panfrost_mmu_init(pfdev);
if (err)
- goto err_out4;
+ goto out_gpu;
err = panfrost_job_init(pfdev);
if (err)
- goto err_out5;
+ goto out_mmu;
err = panfrost_perfcnt_init(pfdev);
if (err)
- goto err_out6;
+ goto out_job;
return 0;
-err_out6:
+out_job:
panfrost_job_fini(pfdev);
-err_out5:
+out_mmu:
panfrost_mmu_fini(pfdev);
-err_out4:
+out_gpu:
panfrost_gpu_fini(pfdev);
-err_out3:
+out_pm_domain:
panfrost_pm_domain_fini(pfdev);
-err_out2:
+out_reset:
panfrost_reset_fini(pfdev);
-err_out1:
+out_regulator:
panfrost_regulator_fini(pfdev);
-err_out0:
+out_devfreq:
+ panfrost_devfreq_fini(pfdev);
+out_clk:
panfrost_clk_fini(pfdev);
return err;
}
@@ -278,6 +294,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev)
panfrost_gpu_fini(pfdev);
panfrost_pm_domain_fini(pfdev);
panfrost_reset_fini(pfdev);
+ panfrost_devfreq_fini(pfdev);
panfrost_regulator_fini(pfdev);
panfrost_clk_fini(pfdev);
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index c30c719a8059..953f7536a773 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -13,6 +13,8 @@
#include <drm/drm_mm.h>
#include <drm/gpu_scheduler.h>
+#include "panfrost_devfreq.h"
+
struct panfrost_device;
struct panfrost_mmu;
struct panfrost_job_slot;
@@ -20,7 +22,6 @@ struct panfrost_job;
struct panfrost_perfcnt;
#define NUM_JOB_SLOTS 3
-#define MAX_REGULATORS 2
#define MAX_PM_DOMAINS 3
struct panfrost_features {
@@ -79,7 +80,7 @@ struct panfrost_device {
void __iomem *iomem;
struct clk *clock;
struct clk *bus_clock;
- struct regulator_bulk_data regulators[MAX_REGULATORS];
+ struct regulator_bulk_data *regulators;
struct reset_control *rstc;
/* pm_domains for devices with more than one. */
struct device *pm_domain_devs[MAX_PM_DOMAINS];
@@ -107,14 +108,7 @@ struct panfrost_device {
struct list_head shrinker_list;
struct shrinker shrinker;
- struct {
- struct devfreq *devfreq;
- struct thermal_cooling_device *cooling;
- ktime_t busy_time;
- ktime_t idle_time;
- ktime_t time_last_update;
- atomic_t busy_count;
- } devfreq;
+ struct panfrost_devfreq pfdevfreq;
};
struct panfrost_mmu {
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index ada51df9a7a3..36463c89e966 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -14,7 +14,6 @@
#include <drm/drm_utils.h>
#include "panfrost_device.h"
-#include "panfrost_devfreq.h"
#include "panfrost_gem.h"
#include "panfrost_mmu.h"
#include "panfrost_job.h"
@@ -606,13 +605,6 @@ static int panfrost_probe(struct platform_device *pdev)
goto err_out0;
}
- err = panfrost_devfreq_init(pfdev);
- if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Fatal error during devfreq init\n");
- goto err_out1;
- }
-
pm_runtime_set_active(pfdev->dev);
pm_runtime_mark_last_busy(pfdev->dev);
pm_runtime_enable(pfdev->dev);
@@ -625,16 +617,14 @@ static int panfrost_probe(struct platform_device *pdev)
*/
err = drm_dev_register(ddev, 0);
if (err < 0)
- goto err_out2;
+ goto err_out1;
panfrost_gem_shrinker_init(ddev);
return 0;
-err_out2:
- pm_runtime_disable(pfdev->dev);
- panfrost_devfreq_fini(pfdev);
err_out1:
+ pm_runtime_disable(pfdev->dev);
panfrost_device_fini(pfdev);
err_out0:
drm_dev_put(ddev);
@@ -650,7 +640,6 @@ static int panfrost_remove(struct platform_device *pdev)
panfrost_gem_shrinker_cleanup(ddev);
pm_runtime_get_sync(pfdev->dev);
- panfrost_devfreq_fini(pfdev);
panfrost_device_fini(pfdev);
pm_runtime_put_sync_suspend(pfdev->dev);
pm_runtime_disable(pfdev->dev);
@@ -677,6 +666,7 @@ static const struct of_device_id dt_match[] = {
{ .compatible = "arm,mali-t830", .data = &default_data, },
{ .compatible = "arm,mali-t860", .data = &default_data, },
{ .compatible = "arm,mali-t880", .data = &default_data, },
+ { .compatible = "arm,mali-bifrost", .data = &default_data, },
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
index f2c1ddc41a9b..e0f190e43813 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
@@ -10,6 +10,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include "panfrost_device.h"
#include "panfrost_features.h"
@@ -368,7 +369,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev)
u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev)
{
- if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION))
- return gpu_read(pfdev, GPU_LATEST_FLUSH_ID);
+ u32 flush_id;
+
+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) {
+ /* Flush reduction only makes sense when the GPU is kept powered on between jobs */
+ if (pm_runtime_get_if_in_use(pfdev->dev)) {
+ flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID);
+ pm_runtime_put(pfdev->dev);
+ return flush_id;
+ }
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index 360146f6f3d9..30e7b7196dab 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -145,7 +145,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
u64 jc_head = job->jc;
int ret;
- panfrost_devfreq_record_busy(pfdev);
+ panfrost_devfreq_record_busy(&pfdev->pfdevfreq);
ret = pm_runtime_get_sync(pfdev->dev);
if (ret < 0)
@@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job)
for (i = 0; i < NUM_JOB_SLOTS; i++) {
if (pfdev->jobs[i]) {
pm_runtime_put_noidle(pfdev->dev);
- panfrost_devfreq_record_idle(pfdev);
+ panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
pfdev->jobs[i] = NULL;
}
}
@@ -478,7 +478,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
pfdev->jobs[j] = NULL;
panfrost_mmu_as_put(pfdev, &job->file_priv->mmu);
- panfrost_devfreq_record_idle(pfdev);
+ panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
dma_fence_signal_locked(job->done_fence);
pm_runtime_put_autosuspend(pfdev->dev);
@@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev)
struct panfrost_job_slot *js = pfdev->js;
int i;
- /* Check whether the hardware is idle */
- if (atomic_read(&pfdev->devfreq.busy_count))
- return false;
-
for (i = 0; i < NUM_JOB_SLOTS; i++) {
/* If there are any jobs in the HW queue, we're not idle */
if (atomic_read(&js->queue[i].sched.hw_rq_count))
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
index ec4695cf3caf..fdbc8d949135 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -83,11 +83,13 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
ret = pm_runtime_get_sync(pfdev->dev);
if (ret < 0)
- return ret;
+ goto err_put_pm;
bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize);
- if (IS_ERR(bo))
- return PTR_ERR(bo);
+ if (IS_ERR(bo)) {
+ ret = PTR_ERR(bo);
+ goto err_put_pm;
+ }
/* Map the perfcnt buf in the address space attached to file_priv. */
ret = panfrost_gem_open(&bo->base, file_priv);
@@ -168,6 +170,8 @@ err_close_bo:
panfrost_gem_close(&bo->base, file_priv);
err_put_bo:
drm_gem_object_put(&bo->base);
+err_put_pm:
+ pm_runtime_put(pfdev->dev);
return ret;
}
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c
index 96e58fda75d8..46b0d1c4a16c 100644
--- a/drivers/gpu/drm/pl111/pl111_drv.c
+++ b/drivers/gpu/drm/pl111/pl111_drv.c
@@ -10,18 +10,11 @@
*/
/**
- * DOC: ARM PrimeCell PL111 CLCD Driver
+ * DOC: ARM PrimeCell PL110 and PL111 CLCD Driver
*
- * The PL111 is a simple LCD controller that can support TFT and STN
- * displays. This driver exposes a standard KMS interface for them.
- *
- * This driver uses the same Device Tree binding as the fbdev CLCD
- * driver. While the fbdev driver supports panels that may be
- * connected to the CLCD internally to the CLCD driver, in DRM the
- * panels get split out to drivers/gpu/drm/panels/. This means that,
- * in converting from using fbdev to using DRM, you also need to write
- * a panel driver (which may be as simple as an entry in
- * panel-simple.c).
+ * The PL110/PL111 is a simple LCD controller that can support TFT
+ * and STN displays. This driver exposes a standard KMS interface
+ * for them.
*
* The driver currently doesn't expose the cursor. The DRM API for
* cursors requires support for 64x64 ARGB8888 cursor images, while
@@ -29,16 +22,13 @@
* cursors. While one could imagine trying to hack something together
* to look at the ARGB8888 and program reasonable in monochrome, we
* just don't expose the cursor at all instead, and leave cursor
- * support to the X11 software cursor layer.
+ * support to the application software cursor layer.
*
* TODO:
*
* - Fix race between setting plane base address and getting IRQ for
* vsync firing the pageflip completion.
*
- * - Use the "max-memory-bandwidth" DT property to filter the
- * supported formats.
- *
* - Read back hardware state at boot to skip reprogramming the
* hardware when doing a no-op modeset.
*
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 798f9dd7ad75..54e3c3a97440 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -588,7 +588,7 @@ static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stal
{
int ret;
- ret = qxl_bo_reserve(surf, false);
+ ret = qxl_bo_reserve(surf);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 099dca48b0ff..6063f3a15329 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -26,6 +26,7 @@
#include <linux/crc32.h>
#include <linux/delay.h>
+#include <drm/drm_drv.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
@@ -162,7 +163,8 @@ static void qxl_update_offset_props(struct qxl_device *qdev)
void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
{
struct drm_device *dev = &qdev->ddev;
- int status, retries;
+ struct drm_modeset_acquire_ctx ctx;
+ int status, retries, ret;
for (retries = 0; retries < 10; retries++) {
status = qxl_display_copy_rom_client_monitors_config(qdev);
@@ -183,9 +185,9 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
return;
}
- drm_modeset_lock_all(dev);
+ DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
qxl_update_offset_props(qdev);
- drm_modeset_unlock_all(dev);
+ DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
if (!drm_helper_hpd_irq_event(dev)) {
/* notify that the monitor configuration changed, to
adjust at the arbitrary resolution */
@@ -403,18 +405,17 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
struct qxl_device *qdev = to_qxl(fb->dev);
struct drm_clip_rect norect;
struct qxl_bo *qobj;
+ struct drm_modeset_acquire_ctx ctx;
bool is_primary;
- int inc = 1;
+ int inc = 1, ret;
- drm_modeset_lock_all(fb->dev);
+ DRM_MODESET_LOCK_ALL_BEGIN(fb->dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
qobj = gem_to_qxl_bo(fb->obj[0]);
/* if we aren't primary surface ignore this */
is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary;
- if (!is_primary) {
- drm_modeset_unlock_all(fb->dev);
- return 0;
- }
+ if (!is_primary)
+ goto out_lock_end;
if (!num_clips) {
num_clips = 1;
@@ -430,7 +431,8 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
qxl_draw_dirty_fb(qdev, fb, qobj, flags, color,
clips, num_clips, inc, 0);
- drm_modeset_unlock_all(fb->dev);
+out_lock_end:
+ DRM_MODESET_LOCK_ALL_END(fb->dev, ctx, ret);
return 0;
}
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 13872b882775..6e7f16f4cec7 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -96,7 +96,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto disable_pci;
- if (is_vga(pdev)) {
+ if (is_vga(pdev) && pdev->revision < 5) {
ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO);
if (ret) {
DRM_ERROR("can't get legacy vga ioports\n");
@@ -127,7 +127,7 @@ modeset_cleanup:
unload:
qxl_device_fini(qdev);
put_vga:
- if (is_vga(pdev))
+ if (is_vga(pdev) && pdev->revision < 5)
vga_put(pdev, VGA_RSRC_LEGACY_IO);
disable_pci:
pci_disable_device(pdev);
@@ -155,7 +155,7 @@ qxl_pci_remove(struct pci_dev *pdev)
drm_dev_unregister(dev);
drm_atomic_helper_shutdown(dev);
- if (is_vga(pdev))
+ if (is_vga(pdev) && pdev->revision < 5)
vga_put(pdev, VGA_RSRC_LEGACY_IO);
}
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 9691449aefdb..aae90a9ee1db 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -350,7 +350,7 @@ int qxl_mode_dumb_mmap(struct drm_file *filp,
int qxl_ttm_init(struct qxl_device *qdev);
void qxl_ttm_fini(struct qxl_device *qdev);
int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
/* qxl image */
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index 8f605d5cc149..5cea6eea72ab 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -322,7 +322,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
qobj = gem_to_qxl_bo(gobj);
- ret = qxl_bo_reserve(qobj, false);
+ ret = qxl_bo_reserve(qobj);
if (ret)
goto out;
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index 80e7a17aaddd..f838b6d689aa 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -284,7 +284,7 @@ int qxl_bo_pin(struct qxl_bo *bo)
{
int r;
- r = qxl_bo_reserve(bo, false);
+ r = qxl_bo_reserve(bo);
if (r)
return r;
@@ -302,7 +302,7 @@ int qxl_bo_unpin(struct qxl_bo *bo)
{
int r;
- r = qxl_bo_reserve(bo, false);
+ r = qxl_bo_reserve(bo);
if (r)
return r;
diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h
index 21fa81048f4f..6b434e5ef795 100644
--- a/drivers/gpu/drm/qxl/qxl_object.h
+++ b/drivers/gpu/drm/qxl/qxl_object.h
@@ -27,11 +27,11 @@
#include "qxl_drv.h"
-static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait)
+static inline int qxl_bo_reserve(struct qxl_bo *bo)
{
int r;
- r = ttm_bo_reserve(&bo->tbo, true, no_wait, NULL);
+ r = ttm_bo_reserve(&bo->tbo, true, false, NULL);
if (unlikely(r != 0)) {
if (r != -ERESTARTSYS) {
struct drm_device *ddev = bo->tbo.base.dev;
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index bf9dc451583a..7aae0a96f043 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -48,31 +48,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev)
return qdev;
}
-static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
- struct ttm_mem_type_manager *man)
-{
- switch (type) {
- case TTM_PL_SYSTEM:
- /* System memory */
- man->flags = 0;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- case TTM_PL_VRAM:
- case TTM_PL_PRIV:
- /* "On-card" video ram */
- man->func = &ttm_bo_manager_func;
- man->flags = TTM_MEMTYPE_FLAG_FIXED;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- default:
- DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type);
- return -EINVAL;
- }
- return 0;
-}
-
static void qxl_evict_flags(struct ttm_buffer_object *bo,
struct ttm_placement *placement)
{
@@ -96,16 +71,10 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo,
}
int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
struct qxl_device *qdev = qxl_get_qdev(bdev);
- mem->bus.addr = NULL;
- mem->bus.offset = 0;
- mem->bus.size = mem->num_pages << PAGE_SHIFT;
- mem->bus.base = 0;
- mem->bus.is_iomem = false;
-
switch (mem->mem_type) {
case TTM_PL_SYSTEM:
/* system memory */
@@ -136,7 +105,7 @@ struct qxl_ttm_tt {
};
static int qxl_ttm_backend_bind(struct ttm_tt *ttm,
- struct ttm_mem_reg *bo_mem)
+ struct ttm_resource *bo_mem)
{
struct qxl_ttm_tt *gtt = (void *)ttm;
@@ -188,9 +157,9 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo,
}
static void qxl_move_null(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
BUG_ON(old_mem->mm_node != NULL);
*old_mem = *new_mem;
@@ -199,9 +168,9 @@ static void qxl_move_null(struct ttm_buffer_object *bo,
static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
int ret;
ret = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu);
@@ -217,7 +186,7 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
bool evict,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct qxl_bo *qbo;
struct qxl_device *qdev;
@@ -233,7 +202,6 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
static struct ttm_bo_driver qxl_bo_driver = {
.ttm_tt_create = &qxl_ttm_tt_create,
- .init_mem_type = &qxl_init_mem_type,
.eviction_valuable = ttm_bo_eviction_valuable,
.evict_flags = &qxl_evict_flags,
.move = &qxl_bo_move,
@@ -241,6 +209,14 @@ static struct ttm_bo_driver qxl_bo_driver = {
.move_notify = &qxl_bo_move_notify,
};
+static int qxl_ttm_init_mem_type(struct qxl_device *qdev,
+ unsigned int type,
+ uint64_t size)
+{
+ return ttm_range_man_init(&qdev->mman.bdev, type, TTM_PL_MASK_CACHING,
+ TTM_PL_FLAG_CACHED, false, size);
+}
+
int qxl_ttm_init(struct qxl_device *qdev)
{
int r;
@@ -258,14 +234,13 @@ int qxl_ttm_init(struct qxl_device *qdev)
}
/* NOTE: this includes the framebuffer (aka surface 0) */
num_io_pages = qdev->rom->ram_header_offset / PAGE_SIZE;
- r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_VRAM,
- num_io_pages);
+ r = qxl_ttm_init_mem_type(qdev, TTM_PL_VRAM, num_io_pages);
if (r) {
DRM_ERROR("Failed initializing VRAM heap.\n");
return r;
}
- r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_PRIV,
- qdev->surfaceram_size / PAGE_SIZE);
+ r = qxl_ttm_init_mem_type(qdev, TTM_PL_PRIV,
+ qdev->surfaceram_size / PAGE_SIZE);
if (r) {
DRM_ERROR("Failed initializing Surfaces heap.\n");
return r;
@@ -281,8 +256,8 @@ int qxl_ttm_init(struct qxl_device *qdev)
void qxl_ttm_fini(struct qxl_device *qdev)
{
- ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM);
- ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV);
+ ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_VRAM);
+ ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_PRIV);
ttm_bo_device_release(&qdev->mman.bdev);
DRM_INFO("qxl: ttm finalized\n");
}
@@ -293,12 +268,10 @@ void qxl_ttm_fini(struct qxl_device *qdev)
static int qxl_mm_dump_table(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_mm *mm = (struct drm_mm *)node->info_ent->data;
+ struct ttm_resource_manager *man = (struct ttm_resource_manager *)node->info_ent->data;
struct drm_printer p = drm_seq_file_printer(m);
- spin_lock(&ttm_bo_glob.lru_lock);
- drm_mm_print(mm, &p);
- spin_unlock(&ttm_bo_glob.lru_lock);
+ ttm_resource_manager_debug(man, &p);
return 0;
}
#endif
@@ -319,9 +292,9 @@ void qxl_ttm_debugfs_init(struct qxl_device *qdev)
qxl_mem_types_list[i].show = &qxl_mm_dump_table;
qxl_mem_types_list[i].driver_features = 0;
if (i == 0)
- qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_VRAM].priv;
+ qxl_mem_types_list[i].data = ttm_manager_type(&qdev->mman.bdev, TTM_PL_VRAM);
else
- qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_PRIV].priv;
+ qxl_mem_types_list[i].data = ttm_manager_type(&qdev->mman.bdev, TTM_PL_PRIV);
}
qxl_debugfs_add_files(qdev, qxl_mem_types_list, i);
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index b7c3fb2bfb54..cc4f58d16589 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2857,7 +2857,7 @@ int radeon_vm_clear_invalids(struct radeon_device *rdev,
struct radeon_vm *vm);
int radeon_vm_bo_update(struct radeon_device *rdev,
struct radeon_bo_va *bo_va,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
void radeon_vm_bo_invalidate(struct radeon_device *rdev,
struct radeon_bo *bo);
struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm,
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index 44157ada9b0e..7f5dfe04789e 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -224,9 +224,9 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
{
struct radeon_device *rdev = dev->dev_private;
struct drm_radeon_gem_info *args = data;
- struct ttm_mem_type_manager *man;
+ struct ttm_resource_manager *man;
- man = &rdev->mman.bdev.man[TTM_PL_VRAM];
+ man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM);
args->vram_size = (u64)man->size << PAGE_SHIFT;
args->vram_visible = rdev->mc.visible_vram_size;
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index f3dee01250da..bb7582afd803 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -775,7 +775,7 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
void radeon_bo_move_notify(struct ttm_buffer_object *bo,
bool evict,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct radeon_bo *rbo;
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index 60275b822f79..44b47241ee42 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -165,7 +165,7 @@ extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
bool force_drop);
extern void radeon_bo_move_notify(struct ttm_buffer_object *bo,
bool evict,
- struct ttm_mem_reg *new_mem);
+ struct ttm_resource *new_mem);
extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
extern int radeon_bo_get_surface_reg(struct radeon_bo *bo);
extern void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 004344dce140..3a4372ea74b9 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -66,53 +66,20 @@ struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
return rdev;
}
-static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
- struct ttm_mem_type_manager *man)
+static int radeon_ttm_init_vram(struct radeon_device *rdev)
{
- struct radeon_device *rdev;
-
- rdev = radeon_get_rdev(bdev);
+ return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_VRAM,
+ TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC,
+ TTM_PL_FLAG_WC, false,
+ rdev->mc.real_vram_size >> PAGE_SHIFT);
+}
- switch (type) {
- case TTM_PL_SYSTEM:
- /* System memory */
- man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- case TTM_PL_TT:
- man->func = &ttm_bo_manager_func;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
-#if IS_ENABLED(CONFIG_AGP)
- if (rdev->flags & RADEON_IS_AGP) {
- if (!rdev->ddev->agp) {
- DRM_ERROR("AGP is not enabled for memory type %u\n",
- (unsigned)type);
- return -EINVAL;
- }
- if (!rdev->ddev->agp->cant_use_aperture)
- man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_FLAG_UNCACHED |
- TTM_PL_FLAG_WC;
- man->default_caching = TTM_PL_FLAG_WC;
- }
-#endif
- break;
- case TTM_PL_VRAM:
- /* "On-card" video ram */
- man->func = &ttm_bo_manager_func;
- man->flags = TTM_MEMTYPE_FLAG_FIXED |
- TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
- man->default_caching = TTM_PL_FLAG_WC;
- break;
- default:
- DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
- return -EINVAL;
- }
- return 0;
+static int radeon_ttm_init_gtt(struct radeon_device *rdev)
+{
+ return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_TT,
+ TTM_PL_MASK_CACHING,
+ TTM_PL_FLAG_CACHED, true,
+ rdev->mc.gtt_size >> PAGE_SHIFT);
}
static void radeon_evict_flags(struct ttm_buffer_object *bo,
@@ -182,9 +149,9 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp)
}
static void radeon_move_null(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
BUG_ON(old_mem->mm_node != NULL);
*old_mem = *new_mem;
@@ -193,8 +160,8 @@ static void radeon_move_null(struct ttm_buffer_object *bo,
static int radeon_move_blit(struct ttm_buffer_object *bo,
bool evict, bool no_wait_gpu,
- struct ttm_mem_reg *new_mem,
- struct ttm_mem_reg *old_mem)
+ struct ttm_resource *new_mem,
+ struct ttm_resource *old_mem)
{
struct radeon_device *rdev;
uint64_t old_start, new_start;
@@ -249,11 +216,11 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
bool evict, bool interruptible,
bool no_wait_gpu,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu };
- struct ttm_mem_reg *old_mem = &bo->mem;
- struct ttm_mem_reg tmp_mem;
+ struct ttm_resource *old_mem = &bo->mem;
+ struct ttm_resource tmp_mem;
struct ttm_place placements;
struct ttm_placement placement;
int r;
@@ -287,18 +254,18 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
}
r = ttm_bo_move_ttm(bo, &ctx, new_mem);
out_cleanup:
- ttm_bo_mem_put(bo, &tmp_mem);
+ ttm_resource_free(bo, &tmp_mem);
return r;
}
static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
bool evict, bool interruptible,
bool no_wait_gpu,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu };
- struct ttm_mem_reg *old_mem = &bo->mem;
- struct ttm_mem_reg tmp_mem;
+ struct ttm_resource *old_mem = &bo->mem;
+ struct ttm_resource tmp_mem;
struct ttm_placement placement;
struct ttm_place placements;
int r;
@@ -325,17 +292,17 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
goto out_cleanup;
}
out_cleanup:
- ttm_bo_mem_put(bo, &tmp_mem);
+ ttm_resource_free(bo, &tmp_mem);
return r;
}
static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct radeon_device *rdev;
struct radeon_bo *rbo;
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
int r;
r = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu);
@@ -392,18 +359,11 @@ memcpy:
return 0;
}
-static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
{
- struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
struct radeon_device *rdev = radeon_get_rdev(bdev);
+ size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
- mem->bus.addr = NULL;
- mem->bus.offset = 0;
- mem->bus.size = mem->num_pages << PAGE_SHIFT;
- mem->bus.base = 0;
- mem->bus.is_iomem = false;
- if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
- return -EINVAL;
switch (mem->mem_type) {
case TTM_PL_SYSTEM:
/* system memory */
@@ -421,7 +381,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
case TTM_PL_VRAM:
mem->bus.offset = mem->start << PAGE_SHIFT;
/* check if it's visible */
- if ((mem->bus.offset + mem->bus.size) > rdev->mc.visible_vram_size)
+ if ((mem->bus.offset + bus_size) > rdev->mc.visible_vram_size)
return -EINVAL;
mem->bus.base = rdev->mc.aper_base;
mem->bus.is_iomem = true;
@@ -433,11 +393,11 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
if (mem->placement & TTM_PL_FLAG_WC)
mem->bus.addr =
ioremap_wc(mem->bus.base + mem->bus.offset,
- mem->bus.size);
+ bus_size);
else
mem->bus.addr =
ioremap(mem->bus.base + mem->bus.offset,
- mem->bus.size);
+ bus_size);
if (!mem->bus.addr)
return -ENOMEM;
@@ -562,7 +522,7 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
}
static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
- struct ttm_mem_reg *bo_mem)
+ struct ttm_resource *bo_mem)
{
struct radeon_ttm_tt *gtt = (void*)ttm;
uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ |
@@ -760,7 +720,6 @@ static struct ttm_bo_driver radeon_bo_driver = {
.ttm_tt_create = &radeon_ttm_tt_create,
.ttm_tt_populate = &radeon_ttm_tt_populate,
.ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate,
- .init_mem_type = &radeon_init_mem_type,
.eviction_valuable = ttm_bo_eviction_valuable,
.evict_flags = &radeon_evict_flags,
.move = &radeon_bo_move,
@@ -785,8 +744,8 @@ int radeon_ttm_init(struct radeon_device *rdev)
return r;
}
rdev->mman.initialized = true;
- r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM,
- rdev->mc.real_vram_size >> PAGE_SHIFT);
+
+ r = radeon_ttm_init_vram(rdev);
if (r) {
DRM_ERROR("Failed initializing VRAM heap.\n");
return r;
@@ -811,8 +770,8 @@ int radeon_ttm_init(struct radeon_device *rdev)
}
DRM_INFO("radeon: %uM of VRAM memory ready\n",
(unsigned) (rdev->mc.real_vram_size / (1024 * 1024)));
- r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT,
- rdev->mc.gtt_size >> PAGE_SHIFT);
+
+ r = radeon_ttm_init_gtt(rdev);
if (r) {
DRM_ERROR("Failed initializing GTT heap.\n");
return r;
@@ -843,8 +802,8 @@ void radeon_ttm_fini(struct radeon_device *rdev)
}
radeon_bo_unref(&rdev->stolen_vga_memory);
}
- ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_VRAM);
- ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT);
+ ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_VRAM);
+ ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_TT);
ttm_bo_device_release(&rdev->mman.bdev);
radeon_gart_fini(rdev);
rdev->mman.initialized = false;
@@ -855,12 +814,12 @@ void radeon_ttm_fini(struct radeon_device *rdev)
* isn't running */
void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size)
{
- struct ttm_mem_type_manager *man;
+ struct ttm_resource_manager *man;
if (!rdev->mman.initialized)
return;
- man = &rdev->mman.bdev.man[TTM_PL_VRAM];
+ man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM);
/* this just adjusts TTM size idea, which sets lpfn to the correct value */
man->size = size >> PAGE_SHIFT;
}
@@ -914,7 +873,7 @@ static int radeon_mm_dump_table(struct seq_file *m, void *data)
unsigned ttm_pl = *(int*)node->info_ent->data;
struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private;
- struct ttm_mem_type_manager *man = &rdev->mman.bdev.man[ttm_pl];
+ struct ttm_resource_manager *man = ttm_manager_type(&rdev->mman.bdev, ttm_pl);
struct drm_printer p = drm_seq_file_printer(m);
man->func->debug(man, &p);
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
index f60fae0aed11..71e2c3785ab9 100644
--- a/drivers/gpu/drm/radeon/radeon_vm.c
+++ b/drivers/gpu/drm/radeon/radeon_vm.c
@@ -911,7 +911,7 @@ static void radeon_vm_fence_pts(struct radeon_vm *vm,
*/
int radeon_vm_bo_update(struct radeon_device *rdev,
struct radeon_bo_va *bo_va,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
struct radeon_vm *vm = bo_va->vm;
struct radeon_ib ib;
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
index ab0d49618cf9..bced729a96fe 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -677,15 +677,11 @@ static int rcar_lvds_attach(struct drm_bridge *bridge,
if (ret < 0)
return ret;
- return drm_panel_attach(lvds->panel, connector);
+ return 0;
}
static void rcar_lvds_detach(struct drm_bridge *bridge)
{
- struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
-
- if (lvds->panel)
- drm_panel_detach(lvds->panel);
}
static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 63f967902c2d..f292c6a6e20f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -634,13 +634,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
"failed to attach encoder: %d\n", ret);
goto err_free_connector;
}
-
- ret = drm_panel_attach(lvds->panel, connector);
- if (ret < 0) {
- DRM_DEV_ERROR(drm_dev->dev,
- "failed to attach panel: %d\n", ret);
- goto err_free_connector;
- }
} else {
ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0);
if (ret) {
@@ -676,8 +669,6 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master,
encoder_funcs = lvds->soc_data->helper_funcs;
encoder_funcs->disable(&lvds->encoder);
- if (lvds->panel)
- drm_panel_detach(lvds->panel);
pm_runtime_disable(dev);
drm_connector_cleanup(&lvds->connector);
drm_encoder_cleanup(&lvds->encoder);
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index de4af7735c46..ddb4184f0726 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -389,8 +389,6 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force)
dvo->panel = of_drm_find_panel(dvo->panel_node);
if (IS_ERR(dvo->panel))
dvo->panel = NULL;
- else
- drm_panel_attach(dvo->panel, connector);
}
if (dvo->panel)
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 072ea113e6be..f025534eb30c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -769,7 +769,7 @@ static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
.vblank_quirk = sun4i_backend_vblank_quirk,
};
-static struct regmap_config sun4i_backend_regmap_config = {
+static const struct regmap_config sun4i_backend_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 1568f68f9a9e..6825ef46f43f 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -35,7 +35,7 @@ static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
.fb_create = drm_gem_fb_create,
};
-static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
+static const struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
};
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
index ec2a032e07b9..b51cc685c13a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_frontend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -545,7 +545,7 @@ int sun4i_frontend_enable(struct sun4i_frontend *frontend)
}
EXPORT_SYMBOL(sun4i_frontend_enable);
-static struct regmap_config sun4i_frontend_regmap_config = {
+static const struct regmap_config sun4i_frontend_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c
index ffda3184aa12..ac570437172e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_lvds.c
+++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c
@@ -47,16 +47,13 @@ static int sun4i_lvds_get_modes(struct drm_connector *connector)
return drm_panel_get_modes(lvds->panel, connector);
}
-static struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = {
+static const struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = {
.get_modes = sun4i_lvds_get_modes,
};
static void
sun4i_lvds_connector_destroy(struct drm_connector *connector)
{
- struct sun4i_lvds *lvds = drm_connector_to_sun4i_lvds(connector);
-
- drm_panel_detach(lvds->panel);
drm_connector_cleanup(connector);
}
@@ -141,12 +138,6 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon)
drm_connector_attach_encoder(&lvds->connector,
&lvds->encoder);
-
- ret = drm_panel_attach(lvds->panel, &lvds->connector);
- if (ret) {
- dev_err(drm->dev, "Couldn't attach our panel\n");
- goto err_cleanup_connector;
- }
}
if (bridge) {
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index 5a7d43939ae6..e172426eb7e9 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -138,16 +138,13 @@ out:
return MODE_OK;
}
-static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
+static const struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
.get_modes = sun4i_rgb_get_modes,
};
static void
sun4i_rgb_connector_destroy(struct drm_connector *connector)
{
- struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
-
- drm_panel_detach(rgb->panel);
drm_connector_cleanup(connector);
}
@@ -183,7 +180,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
}
}
-static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
+static const struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
.disable = sun4i_rgb_encoder_disable,
.enable = sun4i_rgb_encoder_enable,
.mode_valid = sun4i_rgb_mode_valid,
@@ -233,12 +230,6 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon)
drm_connector_attach_encoder(&rgb->connector,
&rgb->encoder);
-
- ret = drm_panel_attach(rgb->panel, &rgb->connector);
- if (ret) {
- dev_err(drm->dev, "Couldn't attach our panel\n");
- goto err_cleanup_connector;
- }
}
if (rgb->bridge) {
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index ced9a8287dd8..d12446cbcae0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -825,7 +825,7 @@ static int sun4i_tcon_init_irq(struct device *dev,
return 0;
}
-static struct regmap_config sun4i_tcon_regmap_config = {
+static const struct regmap_config sun4i_tcon_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 63f4428ac3bf..cb91bc11a0c7 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -468,7 +468,7 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0);
}
-static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
+static const struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
.disable = sun4i_tv_disable,
.enable = sun4i_tv_enable,
.mode_set = sun4i_tv_mode_set,
@@ -504,7 +504,7 @@ static int sun4i_tv_comp_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
-static struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = {
.get_modes = sun4i_tv_comp_get_modes,
.mode_valid = sun4i_tv_comp_mode_valid,
};
@@ -523,7 +523,7 @@ static const struct drm_connector_funcs sun4i_tv_comp_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
-static struct regmap_config sun4i_tv_regmap_config = {
+static const struct regmap_config sun4i_tv_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 7f13f4d715bf..32af47197222 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -820,7 +820,7 @@ static int sun6i_dsi_get_modes(struct drm_connector *connector)
return drm_panel_get_modes(dsi->panel, connector);
}
-static struct drm_connector_helper_funcs sun6i_dsi_connector_helper_funcs = {
+static const struct drm_connector_helper_funcs sun6i_dsi_connector_helper_funcs = {
.get_modes = sun6i_dsi_get_modes,
};
@@ -973,7 +973,6 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
dsi->panel = panel;
dsi->device = device;
- drm_panel_attach(dsi->panel, &dsi->connector);
drm_kms_helper_hotplug_event(dsi->drm);
dev_info(host->dev, "Attached device %s\n", device->name);
@@ -985,12 +984,10 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
- struct drm_panel *panel = dsi->panel;
dsi->panel = NULL;
dsi->device = NULL;
- drm_panel_detach(panel);
drm_kms_helper_hotplug_event(dsi->drm);
return 0;
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 156d00e5165b..35c2133724e2 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -534,7 +534,7 @@ void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
}
}
-static struct regmap_config sun8i_hdmi_phy_regmap_config = {
+static const struct regmap_config sun8i_hdmi_phy_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index cc4fb916318f..4b59806b30df 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -303,7 +303,7 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
.layers_init = sun8i_layers_init,
};
-static struct regmap_config sun8i_mixer_regmap_config = {
+static const struct regmap_config sun8i_mixer_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 54f937a7d5e7..816ad4ce8996 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -298,7 +298,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
true, zpos, old_zpos);
}
-static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
+static const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
.prepare_fb = drm_gem_fb_prepare_fb,
.atomic_check = sun8i_ui_layer_atomic_check,
.atomic_disable = sun8i_ui_layer_atomic_disable,
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 22c8c5375d0d..a360697a4a4a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -401,7 +401,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
true, zpos, old_zpos);
}
-static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
+static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
.prepare_fb = drm_gem_fb_prepare_fb,
.atomic_check = sun8i_vi_layer_atomic_check,
.atomic_disable = sun8i_vi_layer_atomic_disable,
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 3820e8dff14b..3387de79718b 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -1498,10 +1498,8 @@ static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
if (IS_ERR(output->panel))
output->panel = NULL;
- if (output->panel && output->connector.dev) {
- drm_panel_attach(output->panel, &output->connector);
+ if (output->panel && output->connector.dev)
drm_helper_hpd_irq_event(output->connector.dev);
- }
}
return 0;
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index e36e5e7c2f69..a3adb9e4debf 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -179,13 +179,6 @@ void tegra_output_remove(struct tegra_output *output)
int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
{
int connector_type;
- int err;
-
- if (output->panel) {
- err = drm_panel_attach(output->panel, &output->connector);
- if (err < 0)
- return err;
- }
/*
* The connector is now registered and ready to receive hotplug events
@@ -220,9 +213,6 @@ void tegra_output_exit(struct tegra_output *output)
*/
if (output->hpd_gpio)
disable_irq(output->hpd_irq);
-
- if (output->panel)
- drm_panel_detach(output->panel);
}
void tegra_output_find_possible_crtcs(struct tegra_output *output,
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index c3ece2c9d1c8..b669168ae7cb 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/sys_soc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_fb_cma_helper.h>
@@ -302,6 +303,8 @@ struct dispc_device {
u32 num_fourccs;
u32 memory_bandwidth_limit;
+
+ struct dispc_errata errata;
};
static void dispc_write(struct dispc_device *dispc, u16 reg, u32 val)
@@ -2641,6 +2644,19 @@ static int dispc_init_am65x_oldi_io_ctrl(struct device *dev,
return 0;
}
+static void dispc_init_errata(struct dispc_device *dispc)
+{
+ static const struct soc_device_attribute am65x_sr10_soc_devices[] = {
+ { .family = "AM65X", .revision = "SR1.0" },
+ { /* sentinel */ }
+ };
+
+ if (soc_device_match(am65x_sr10_soc_devices)) {
+ dispc->errata.i2000 = true;
+ dev_info(dispc->dev, "WA for erratum i2000: YUV formats disabled\n");
+ }
+}
+
int dispc_init(struct tidss_device *tidss)
{
struct device *dev = tidss->dev;
@@ -2664,19 +2680,27 @@ int dispc_init(struct tidss_device *tidss)
if (!dispc)
return -ENOMEM;
+ dispc->tidss = tidss;
+ dispc->dev = dev;
+ dispc->feat = feat;
+
+ dispc_init_errata(dispc);
+
dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats),
sizeof(*dispc->fourccs), GFP_KERNEL);
if (!dispc->fourccs)
return -ENOMEM;
num_fourccs = 0;
- for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i)
+ for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) {
+ if (dispc->errata.i2000 &&
+ dispc_fourcc_is_yuv(dispc_color_formats[i].fourcc)) {
+ continue;
+ }
dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc;
+ }
dispc->num_fourccs = num_fourccs;
- dispc->tidss = tidss;
- dispc->dev = dev;
- dispc->feat = feat;
dispc_common_regmap = dispc->feat->common_regs;
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
index 5984e0de2cd9..e49432f0abf5 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc.h
@@ -46,6 +46,10 @@ struct dispc_features_scaling {
u32 xinc_max;
};
+struct dispc_errata {
+ bool i2000; /* DSS Does Not Support YUV Pixel Data Formats */
+};
+
enum dispc_vp_bus_type {
DISPC_VP_DPI, /* DPI output */
DISPC_VP_OLDI, /* OLDI (LVDS) output */
diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile
index caea2a099496..90c0da88cc98 100644
--- a/drivers/gpu/drm/ttm/Makefile
+++ b/drivers/gpu/drm/ttm/Makefile
@@ -4,7 +4,8 @@
ttm-y := ttm_memory.o ttm_tt.o ttm_bo.o \
ttm_bo_util.o ttm_bo_vm.o ttm_module.o \
- ttm_execbuf_util.o ttm_page_alloc.o ttm_bo_manager.o
+ ttm_execbuf_util.o ttm_page_alloc.o ttm_range_manager.o \
+ ttm_resource.o
ttm-$(CONFIG_AGP) += ttm_agp_backend.o
ttm-$(CONFIG_DRM_TTM_DMA_PAGE_POOL) += ttm_page_alloc_dma.o
diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c
index 38f1351140e2..09fe80e215c5 100644
--- a/drivers/gpu/drm/ttm/ttm_agp_backend.c
+++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c
@@ -48,7 +48,7 @@ struct ttm_agp_backend {
struct agp_bridge_data *bridge;
};
-static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
+static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem)
{
struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm);
struct page *dummy_read_page = ttm_bo_glob.dummy_read_page;
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index cc6a4e7551e3..e3931e515906 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -77,26 +77,12 @@ static inline int ttm_mem_type_from_place(const struct ttm_place *place,
return 0;
}
-static void ttm_mem_type_debug(struct ttm_bo_device *bdev, struct drm_printer *p,
- int mem_type)
-{
- struct ttm_mem_type_manager *man = &bdev->man[mem_type];
-
- drm_printf(p, " has_type: %d\n", man->has_type);
- drm_printf(p, " use_type: %d\n", man->use_type);
- drm_printf(p, " flags: 0x%08X\n", man->flags);
- drm_printf(p, " size: %llu\n", man->size);
- drm_printf(p, " available_caching: 0x%08X\n", man->available_caching);
- drm_printf(p, " default_caching: 0x%08X\n", man->default_caching);
- if (mem_type != TTM_PL_SYSTEM)
- (*man->func->debug)(man, p);
-}
-
static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
struct ttm_placement *placement)
{
struct drm_printer p = drm_debug_printer(TTM_PFX);
int i, ret, mem_type;
+ struct ttm_resource_manager *man;
drm_printf(&p, "No space for %p (%lu pages, %luK, %luM)\n",
bo, bo->mem.num_pages, bo->mem.size >> 10,
@@ -108,7 +94,8 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
return;
drm_printf(&p, " placement[%d]=0x%08X (%d)\n",
i, placement->placement[i].flags, mem_type);
- ttm_mem_type_debug(bo->bdev, &p, mem_type);
+ man = ttm_manager_type(bo->bdev, mem_type);
+ ttm_resource_manager_debug(man, &p);
}
}
@@ -145,10 +132,10 @@ static inline uint32_t ttm_bo_type_flags(unsigned type)
}
static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_type_manager *man;
+ struct ttm_resource_manager *man;
if (!list_empty(&bo->lru))
return;
@@ -156,10 +143,10 @@ static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo,
if (mem->placement & TTM_PL_FLAG_NO_EVICT)
return;
- man = &bdev->man[mem->mem_type];
+ man = ttm_manager_type(bdev, mem->mem_type);
list_add_tail(&bo->lru, &man->lru[bo->priority]);
- if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED) && bo->ttm &&
+ if (man->use_tt && bo->ttm &&
!(bo->ttm->page_flags & (TTM_PAGE_FLAG_SG |
TTM_PAGE_FLAG_SWAPPED))) {
list_add_tail(&bo->swap, &ttm_bo_glob.swap_lru[bo->priority]);
@@ -223,7 +210,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
struct ttm_lru_bulk_move_pos *pos = &bulk->tt[i];
- struct ttm_mem_type_manager *man;
+ struct ttm_resource_manager *man;
if (!pos->first)
continue;
@@ -231,14 +218,14 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
dma_resv_assert_held(pos->first->base.resv);
dma_resv_assert_held(pos->last->base.resv);
- man = &pos->first->bdev->man[TTM_PL_TT];
+ man = ttm_manager_type(pos->first->bdev, TTM_PL_TT);
list_bulk_move_tail(&man->lru[i], &pos->first->lru,
&pos->last->lru);
}
for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
struct ttm_lru_bulk_move_pos *pos = &bulk->vram[i];
- struct ttm_mem_type_manager *man;
+ struct ttm_resource_manager *man;
if (!pos->first)
continue;
@@ -246,7 +233,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
dma_resv_assert_held(pos->first->base.resv);
dma_resv_assert_held(pos->last->base.resv);
- man = &pos->first->bdev->man[TTM_PL_VRAM];
+ man = ttm_manager_type(pos->first->bdev, TTM_PL_VRAM);
list_bulk_move_tail(&man->lru[i], &pos->first->lru,
&pos->last->lru);
}
@@ -268,12 +255,12 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
EXPORT_SYMBOL(ttm_bo_bulk_move_lru_tail);
static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem, bool evict,
+ struct ttm_resource *mem, bool evict,
struct ttm_operation_ctx *ctx)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_type_manager *old_man = &bdev->man[bo->mem.mem_type];
- struct ttm_mem_type_manager *new_man = &bdev->man[mem->mem_type];
+ struct ttm_resource_manager *old_man = ttm_manager_type(bdev, bo->mem.mem_type);
+ struct ttm_resource_manager *new_man = ttm_manager_type(bdev, mem->mem_type);
int ret;
ret = ttm_mem_io_lock(old_man, true);
@@ -286,13 +273,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
* Create and bind a ttm if required.
*/
- if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
- if (bo->ttm == NULL) {
- bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED);
- ret = ttm_tt_create(bo, zero);
- if (ret)
- goto out_err;
- }
+ if (new_man->use_tt) {
+ /* Zero init the new TTM structure if the old location should
+ * have used one as well.
+ */
+ ret = ttm_tt_create(bo, old_man->use_tt);
+ if (ret)
+ goto out_err;
ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
if (ret)
@@ -315,8 +302,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
if (bdev->driver->move_notify)
bdev->driver->move_notify(bo, evict, mem);
- if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
- !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
+ if (old_man->use_tt && new_man->use_tt)
ret = ttm_bo_move_ttm(bo, ctx, mem);
else if (bdev->driver->move)
ret = bdev->driver->move(bo, evict, ctx, mem);
@@ -340,8 +326,8 @@ moved:
return 0;
out_err:
- new_man = &bdev->man[bo->mem.mem_type];
- if (new_man->flags & TTM_MEMTYPE_FLAG_FIXED) {
+ new_man = ttm_manager_type(bdev, bo->mem.mem_type);
+ if (!new_man->use_tt) {
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
}
@@ -364,7 +350,7 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
- ttm_bo_mem_put(bo, &bo->mem);
+ ttm_resource_free(bo, &bo->mem);
}
static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo)
@@ -552,7 +538,7 @@ static void ttm_bo_release(struct kref *kref)
struct ttm_buffer_object *bo =
container_of(kref, struct ttm_buffer_object, kref);
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type);
size_t acc_size = bo->acc_size;
int ret;
@@ -643,7 +629,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_reg evict_mem;
+ struct ttm_resource evict_mem;
struct ttm_placement placement;
int ret = 0;
@@ -654,10 +640,9 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
bdev->driver->evict_flags(bo, &placement);
if (!placement.num_placement && !placement.num_busy_placement) {
- ret = ttm_bo_pipeline_gutting(bo);
- if (ret)
- return ret;
+ ttm_bo_wait(bo, false, false);
+ ttm_bo_cleanup_memtype_use(bo);
return ttm_tt_create(bo, false);
}
@@ -680,7 +665,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
if (unlikely(ret)) {
if (ret != -ERESTARTSYS)
pr_err("Buffer eviction failed\n");
- ttm_bo_mem_put(bo, &evict_mem);
+ ttm_resource_free(bo, &evict_mem);
goto out;
}
bo->evicted = true;
@@ -769,14 +754,13 @@ static int ttm_mem_evict_wait_busy(struct ttm_buffer_object *busy_bo,
return r == -EDEADLK ? -EBUSY : r;
}
-static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
- uint32_t mem_type,
- const struct ttm_place *place,
- struct ttm_operation_ctx *ctx,
- struct ww_acquire_ctx *ticket)
+int ttm_mem_evict_first(struct ttm_bo_device *bdev,
+ struct ttm_resource_manager *man,
+ const struct ttm_place *place,
+ struct ttm_operation_ctx *ctx,
+ struct ww_acquire_ctx *ticket)
{
struct ttm_buffer_object *bo = NULL, *busy_bo = NULL;
- struct ttm_mem_type_manager *man = &bdev->man[mem_type];
bool locked = false;
unsigned i;
int ret;
@@ -842,38 +826,12 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
return ret;
}
-static int ttm_bo_mem_get(struct ttm_buffer_object *bo,
- const struct ttm_place *place,
- struct ttm_mem_reg *mem)
-{
- struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type];
-
- mem->mm_node = NULL;
- if (!man->func || !man->func->get_node)
- return 0;
-
- return man->func->get_node(man, bo, place, mem);
-}
-
-void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem)
-{
- struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type];
-
- if (!man->func || !man->func->put_node)
- return;
-
- man->func->put_node(man, mem);
- mem->mm_node = NULL;
- mem->mem_type = TTM_PL_SYSTEM;
-}
-EXPORT_SYMBOL(ttm_bo_mem_put);
-
/**
* Add the last move fence to the BO and reserve a new shared slot.
*/
static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
- struct ttm_mem_type_manager *man,
- struct ttm_mem_reg *mem,
+ struct ttm_resource_manager *man,
+ struct ttm_resource *mem,
bool no_wait_gpu)
{
struct dma_fence *fence;
@@ -910,22 +868,22 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
*/
static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
const struct ttm_place *place,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
struct ttm_operation_ctx *ctx)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type);
struct ww_acquire_ctx *ticket;
int ret;
ticket = dma_resv_locking_ctx(bo->base.resv);
do {
- ret = ttm_bo_mem_get(bo, place, mem);
+ ret = ttm_resource_alloc(bo, place, mem);
if (likely(!ret))
break;
if (unlikely(ret != -ENOSPC))
return ret;
- ret = ttm_mem_evict_first(bdev, mem->mem_type, place, ctx,
+ ret = ttm_mem_evict_first(bdev, man, place, ctx,
ticket);
if (unlikely(ret != 0))
return ret;
@@ -934,7 +892,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
return ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu);
}
-static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
+static uint32_t ttm_bo_select_caching(struct ttm_resource_manager *man,
uint32_t cur_placement,
uint32_t proposed_placement)
{
@@ -959,7 +917,7 @@ static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
return result;
}
-static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,
+static bool ttm_bo_mt_compatible(struct ttm_resource_manager *man,
uint32_t mem_type,
const struct ttm_place *place,
uint32_t *masked_placement)
@@ -991,12 +949,12 @@ static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,
*/
static int ttm_bo_mem_placement(struct ttm_buffer_object *bo,
const struct ttm_place *place,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
struct ttm_operation_ctx *ctx)
{
struct ttm_bo_device *bdev = bo->bdev;
uint32_t mem_type = TTM_PL_SYSTEM;
- struct ttm_mem_type_manager *man;
+ struct ttm_resource_manager *man;
uint32_t cur_flags = 0;
int ret;
@@ -1004,8 +962,8 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo,
if (ret)
return ret;
- man = &bdev->man[mem_type];
- if (!man->has_type || !man->use_type)
+ man = ttm_manager_type(bdev, mem_type);
+ if (!man || !ttm_resource_manager_used(man))
return -EBUSY;
if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags))
@@ -1039,7 +997,7 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo,
*/
int ttm_bo_mem_space(struct ttm_buffer_object *bo,
struct ttm_placement *placement,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
struct ttm_operation_ctx *ctx)
{
struct ttm_bo_device *bdev = bo->bdev;
@@ -1052,7 +1010,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
for (i = 0; i < placement->num_placement; ++i) {
const struct ttm_place *place = &placement->placement[i];
- struct ttm_mem_type_manager *man;
+ struct ttm_resource_manager *man;
ret = ttm_bo_mem_placement(bo, place, mem, ctx);
if (ret == -EBUSY)
@@ -1061,16 +1019,16 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
goto error;
type_found = true;
- ret = ttm_bo_mem_get(bo, place, mem);
+ ret = ttm_resource_alloc(bo, place, mem);
if (ret == -ENOSPC)
continue;
if (unlikely(ret))
goto error;
- man = &bdev->man[mem->mem_type];
+ man = ttm_manager_type(bdev, mem->mem_type);
ret = ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu);
if (unlikely(ret)) {
- ttm_bo_mem_put(bo, mem);
+ ttm_resource_free(bo, mem);
if (ret == -EBUSY)
continue;
@@ -1105,9 +1063,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
error:
if (bo->mem.mem_type == TTM_PL_SYSTEM && !list_empty(&bo->lru)) {
- spin_lock(&ttm_bo_glob.lru_lock);
- ttm_bo_move_to_lru_tail(bo, NULL);
- spin_unlock(&ttm_bo_glob.lru_lock);
+ ttm_bo_move_to_lru_tail_unlocked(bo);
}
return ret;
@@ -1119,7 +1075,7 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx)
{
int ret = 0;
- struct ttm_mem_reg mem;
+ struct ttm_resource mem;
dma_resv_assert_held(bo->base.resv);
@@ -1139,13 +1095,13 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
ret = ttm_bo_handle_move_mem(bo, &mem, false, ctx);
out_unlock:
if (ret)
- ttm_bo_mem_put(bo, &mem);
+ ttm_resource_free(bo, &mem);
return ret;
}
static bool ttm_bo_places_compat(const struct ttm_place *places,
unsigned num_placement,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
uint32_t *new_flags)
{
unsigned i;
@@ -1168,7 +1124,7 @@ static bool ttm_bo_places_compat(const struct ttm_place *places,
}
bool ttm_bo_mem_compat(struct ttm_placement *placement,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
uint32_t *new_flags)
{
if (ttm_bo_places_compat(placement->placement, placement->num_placement,
@@ -1224,7 +1180,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
/*
* We might need to add a TTM.
*/
- if (bo->mem.mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
+ if (bo->mem.mem_type == TTM_PL_SYSTEM) {
ret = ttm_tt_create(bo, true);
if (ret)
return ret;
@@ -1335,9 +1291,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev,
return ret;
}
- spin_lock(&ttm_bo_glob.lru_lock);
- ttm_bo_move_to_lru_tail(bo, NULL);
- spin_unlock(&ttm_bo_glob.lru_lock);
+ ttm_bo_move_to_lru_tail_unlocked(bo);
return ret;
}
@@ -1426,144 +1380,24 @@ int ttm_bo_create(struct ttm_bo_device *bdev,
}
EXPORT_SYMBOL(ttm_bo_create);
-static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
- unsigned mem_type)
-{
- struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false,
- .flags = TTM_OPT_FLAG_FORCE_ALLOC
- };
- struct ttm_mem_type_manager *man = &bdev->man[mem_type];
- struct ttm_bo_global *glob = &ttm_bo_glob;
- struct dma_fence *fence;
- int ret;
- unsigned i;
-
- /*
- * Can't use standard list traversal since we're unlocking.
- */
-
- spin_lock(&glob->lru_lock);
- for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
- while (!list_empty(&man->lru[i])) {
- spin_unlock(&glob->lru_lock);
- ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx,
- NULL);
- if (ret)
- return ret;
- spin_lock(&glob->lru_lock);
- }
- }
- spin_unlock(&glob->lru_lock);
-
- spin_lock(&man->move_lock);
- fence = dma_fence_get(man->move);
- spin_unlock(&man->move_lock);
-
- if (fence) {
- ret = dma_fence_wait(fence, false);
- dma_fence_put(fence);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
-{
- struct ttm_mem_type_manager *man;
- int ret = -EINVAL;
-
- if (mem_type >= TTM_NUM_MEM_TYPES) {
- pr_err("Illegal memory type %d\n", mem_type);
- return ret;
- }
- man = &bdev->man[mem_type];
-
- if (!man->has_type) {
- pr_err("Trying to take down uninitialized memory manager type %u\n",
- mem_type);
- return ret;
- }
-
- man->use_type = false;
- man->has_type = false;
-
- ret = 0;
- if (mem_type > 0) {
- ret = ttm_bo_force_list_clean(bdev, mem_type);
- if (ret) {
- pr_err("Cleanup eviction failed\n");
- return ret;
- }
-
- ret = (*man->func->takedown)(man);
- }
-
- dma_fence_put(man->move);
- man->move = NULL;
-
- return ret;
-}
-EXPORT_SYMBOL(ttm_bo_clean_mm);
-
int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type)
{
- struct ttm_mem_type_manager *man = &bdev->man[mem_type];
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, mem_type);
if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) {
pr_err("Illegal memory manager memory type %u\n", mem_type);
return -EINVAL;
}
- if (!man->has_type) {
+ if (!man) {
pr_err("Memory type %u has not been initialized\n", mem_type);
return 0;
}
- return ttm_bo_force_list_clean(bdev, mem_type);
+ return ttm_resource_manager_force_list_clean(bdev, man);
}
EXPORT_SYMBOL(ttm_bo_evict_mm);
-int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
- unsigned long p_size)
-{
- int ret;
- struct ttm_mem_type_manager *man;
- unsigned i;
-
- BUG_ON(type >= TTM_NUM_MEM_TYPES);
- man = &bdev->man[type];
- BUG_ON(man->has_type);
- man->use_io_reserve_lru = false;
- mutex_init(&man->io_reserve_mutex);
- spin_lock_init(&man->move_lock);
- INIT_LIST_HEAD(&man->io_reserve_lru);
-
- ret = bdev->driver->init_mem_type(bdev, type, man);
- if (ret)
- return ret;
- man->bdev = bdev;
-
- if (type != TTM_PL_SYSTEM) {
- ret = (*man->func->init)(man, p_size);
- if (ret)
- return ret;
- }
- man->has_type = true;
- man->use_type = true;
- man->size = p_size;
-
- for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
- INIT_LIST_HEAD(&man->lru[i]);
- man->move = NULL;
-
- return 0;
-}
-EXPORT_SYMBOL(ttm_bo_init_mm);
-
static void ttm_bo_global_kobj_release(struct kobject *kobj)
{
struct ttm_bo_global *glob =
@@ -1628,21 +1462,12 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
{
struct ttm_bo_global *glob = &ttm_bo_glob;
int ret = 0;
- unsigned i = TTM_NUM_MEM_TYPES;
- struct ttm_mem_type_manager *man;
-
- while (i--) {
- man = &bdev->man[i];
- if (man->has_type) {
- man->use_type = false;
- if ((i != TTM_PL_SYSTEM) && ttm_bo_clean_mm(bdev, i)) {
- ret = -EBUSY;
- pr_err("DRM memory manager type %d is not clean\n",
- i);
- }
- man->has_type = false;
- }
- }
+ unsigned i;
+ struct ttm_resource_manager *man;
+
+ man = ttm_manager_type(bdev, TTM_PL_SYSTEM);
+ ttm_resource_manager_set_used(man, false);
+ ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, NULL);
mutex_lock(&ttm_global_mutex);
list_del(&bdev->device_list);
@@ -1655,7 +1480,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
spin_lock(&glob->lru_lock);
for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
- if (list_empty(&bdev->man[0].lru[0]))
+ if (list_empty(&man->lru[0]))
pr_debug("Swap list %d was clean\n", i);
spin_unlock(&glob->lru_lock);
@@ -1666,6 +1491,23 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
}
EXPORT_SYMBOL(ttm_bo_device_release);
+static void ttm_bo_init_sysman(struct ttm_bo_device *bdev)
+{
+ struct ttm_resource_manager *man = &bdev->sysman;
+
+ /*
+ * Initialize the system memory buffer type.
+ * Other types need to be driver / IOCTL initialized.
+ */
+ man->use_tt = true;
+ man->available_caching = TTM_PL_MASK_CACHING;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+
+ ttm_resource_manager_init(man, 0);
+ ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man);
+ ttm_resource_manager_set_used(man, true);
+}
+
int ttm_bo_device_init(struct ttm_bo_device *bdev,
struct ttm_bo_driver *driver,
struct address_space *mapping,
@@ -1684,15 +1526,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
bdev->driver = driver;
- memset(bdev->man, 0, sizeof(bdev->man));
-
- /*
- * Initialize the system memory buffer type.
- * Other types need to be driver / IOCTL initialized.
- */
- ret = ttm_bo_init_mm(bdev, TTM_PL_SYSTEM, 0);
- if (unlikely(ret != 0))
- goto out_no_sys;
+ ttm_bo_init_sysman(bdev);
bdev->vma_manager = vma_manager;
INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue);
@@ -1704,9 +1538,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
mutex_unlock(&ttm_global_mutex);
return 0;
-out_no_sys:
- ttm_bo_global_release();
- return ret;
}
EXPORT_SYMBOL(ttm_bo_device_init);
@@ -1725,7 +1556,7 @@ void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo)
void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type);
ttm_mem_io_lock(man, false);
ttm_bo_unmap_virtual_locked(bo);
@@ -1812,7 +1643,7 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
if (bo->mem.mem_type != TTM_PL_SYSTEM ||
bo->ttm->caching_state != tt_cached) {
struct ttm_operation_ctx ctx = { false, false };
- struct ttm_mem_reg evict_mem;
+ struct ttm_resource evict_mem;
evict_mem = bo->mem;
evict_mem.mm_node = NULL;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index e6c8bd254055..ee04716b2603 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -47,15 +47,15 @@ struct ttm_transfer_obj {
void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
{
- ttm_bo_mem_put(bo, &bo->mem);
+ ttm_resource_free(bo, &bo->mem);
}
int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct ttm_tt *ttm = bo->ttm;
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
int ret;
if (old_mem->mem_type != TTM_PL_SYSTEM) {
@@ -91,7 +91,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
}
EXPORT_SYMBOL(ttm_bo_move_ttm);
-int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible)
+int ttm_mem_io_lock(struct ttm_resource_manager *man, bool interruptible)
{
if (likely(!man->use_io_reserve_lru))
return 0;
@@ -103,7 +103,7 @@ int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible)
return 0;
}
-void ttm_mem_io_unlock(struct ttm_mem_type_manager *man)
+void ttm_mem_io_unlock(struct ttm_resource_manager *man)
{
if (likely(!man->use_io_reserve_lru))
return;
@@ -111,7 +111,7 @@ void ttm_mem_io_unlock(struct ttm_mem_type_manager *man)
mutex_unlock(&man->io_reserve_mutex);
}
-static int ttm_mem_io_evict(struct ttm_mem_type_manager *man)
+static int ttm_mem_io_evict(struct ttm_resource_manager *man)
{
struct ttm_buffer_object *bo;
@@ -127,9 +127,9 @@ static int ttm_mem_io_evict(struct ttm_mem_type_manager *man)
}
int ttm_mem_io_reserve(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
- struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type);
int ret;
if (mem->bus.io_reserved_count++)
@@ -138,6 +138,10 @@ int ttm_mem_io_reserve(struct ttm_bo_device *bdev,
if (!bdev->driver->io_mem_reserve)
return 0;
+ mem->bus.addr = NULL;
+ mem->bus.offset = 0;
+ mem->bus.base = 0;
+ mem->bus.is_iomem = false;
retry:
ret = bdev->driver->io_mem_reserve(bdev, mem);
if (ret == -ENOSPC) {
@@ -149,7 +153,7 @@ retry:
}
void ttm_mem_io_free(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
if (--mem->bus.io_reserved_count)
return;
@@ -162,8 +166,8 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev,
int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo)
{
- struct ttm_mem_type_manager *man = &bo->bdev->man[bo->mem.mem_type];
- struct ttm_mem_reg *mem = &bo->mem;
+ struct ttm_resource_manager *man = ttm_manager_type(bo->bdev, bo->mem.mem_type);
+ struct ttm_resource *mem = &bo->mem;
int ret;
if (mem->bus.io_reserved_vm)
@@ -181,7 +185,7 @@ int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo)
void ttm_mem_io_free_vm(struct ttm_buffer_object *bo)
{
- struct ttm_mem_reg *mem = &bo->mem;
+ struct ttm_resource *mem = &bo->mem;
if (!mem->bus.io_reserved_vm)
return;
@@ -191,11 +195,11 @@ void ttm_mem_io_free_vm(struct ttm_buffer_object *bo)
ttm_mem_io_free(bo->bdev, mem);
}
-static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem,
+static int ttm_resource_ioremap(struct ttm_bo_device *bdev,
+ struct ttm_resource *mem,
void **virtual)
{
- struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type);
int ret;
void *addr;
@@ -209,12 +213,14 @@ static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev,
if (mem->bus.addr) {
addr = mem->bus.addr;
} else {
+ size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
+
if (mem->placement & TTM_PL_FLAG_WC)
addr = ioremap_wc(mem->bus.base + mem->bus.offset,
- mem->bus.size);
+ bus_size);
else
addr = ioremap(mem->bus.base + mem->bus.offset,
- mem->bus.size);
+ bus_size);
if (!addr) {
(void) ttm_mem_io_lock(man, false);
ttm_mem_io_free(bdev, mem);
@@ -226,13 +232,13 @@ static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev,
return 0;
}
-static void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem,
+static void ttm_resource_iounmap(struct ttm_bo_device *bdev,
+ struct ttm_resource *mem,
void *virtual)
{
- struct ttm_mem_type_manager *man;
+ struct ttm_resource_manager *man;
- man = &bdev->man[mem->mem_type];
+ man = ttm_manager_type(bdev, mem->mem_type);
if (virtual && mem->bus.addr == NULL)
iounmap(virtual);
@@ -300,13 +306,13 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
struct ttm_tt *ttm = bo->ttm;
- struct ttm_mem_reg *old_mem = &bo->mem;
- struct ttm_mem_reg old_copy = *old_mem;
+ struct ttm_resource *old_mem = &bo->mem;
+ struct ttm_resource old_copy = *old_mem;
void *old_iomap;
void *new_iomap;
int ret;
@@ -319,10 +325,10 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
if (ret)
return ret;
- ret = ttm_mem_reg_ioremap(bdev, old_mem, &old_iomap);
+ ret = ttm_resource_ioremap(bdev, old_mem, &old_iomap);
if (ret)
return ret;
- ret = ttm_mem_reg_ioremap(bdev, new_mem, &new_iomap);
+ ret = ttm_resource_ioremap(bdev, new_mem, &new_iomap);
if (ret)
goto out;
@@ -384,21 +390,21 @@ out2:
*old_mem = *new_mem;
new_mem->mm_node = NULL;
- if (man->flags & TTM_MEMTYPE_FLAG_FIXED) {
+ if (!man->use_tt) {
ttm_tt_destroy(ttm);
bo->ttm = NULL;
}
out1:
- ttm_mem_reg_iounmap(bdev, old_mem, new_iomap);
+ ttm_resource_iounmap(bdev, old_mem, new_iomap);
out:
- ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap);
+ ttm_resource_iounmap(bdev, &old_copy, old_iomap);
/*
* On error, keep the mm node!
*/
if (!ret)
- ttm_bo_mem_put(bo, &old_copy);
+ ttm_resource_free(bo, &old_copy);
return ret;
}
EXPORT_SYMBOL(ttm_bo_move_memcpy);
@@ -502,7 +508,7 @@ static int ttm_bo_ioremap(struct ttm_buffer_object *bo,
unsigned long size,
struct ttm_bo_kmap_obj *map)
{
- struct ttm_mem_reg *mem = &bo->mem;
+ struct ttm_resource *mem = &bo->mem;
if (bo->mem.bus.addr) {
map->bo_kmap_type = ttm_bo_map_premapped;
@@ -526,7 +532,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
unsigned long num_pages,
struct ttm_bo_kmap_obj *map)
{
- struct ttm_mem_reg *mem = &bo->mem;
+ struct ttm_resource *mem = &bo->mem;
struct ttm_operation_ctx ctx = {
.interruptible = false,
.no_wait_gpu = false
@@ -567,8 +573,8 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
unsigned long start_page, unsigned long num_pages,
struct ttm_bo_kmap_obj *map)
{
- struct ttm_mem_type_manager *man =
- &bo->bdev->man[bo->mem.mem_type];
+ struct ttm_resource_manager *man =
+ ttm_manager_type(bo->bdev, bo->mem.mem_type);
unsigned long offset, size;
int ret;
@@ -597,8 +603,8 @@ EXPORT_SYMBOL(ttm_bo_kmap);
void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
{
struct ttm_buffer_object *bo = map->bo;
- struct ttm_mem_type_manager *man =
- &bo->bdev->man[bo->mem.mem_type];
+ struct ttm_resource_manager *man =
+ ttm_manager_type(bo->bdev, bo->mem.mem_type);
if (!map->virtual)
return;
@@ -628,11 +634,11 @@ EXPORT_SYMBOL(ttm_bo_kunmap);
int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
struct dma_fence *fence,
bool evict,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
+ struct ttm_resource *old_mem = &bo->mem;
int ret;
struct ttm_buffer_object *ghost_obj;
@@ -642,7 +648,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
if (ret)
return ret;
- if (man->flags & TTM_MEMTYPE_FLAG_FIXED) {
+ if (!man->use_tt) {
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
}
@@ -671,7 +677,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
* bo to be unbound and destroyed.
*/
- if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED))
+ if (man->use_tt)
ghost_obj->ttm = NULL;
else
bo->ttm = NULL;
@@ -689,13 +695,13 @@ EXPORT_SYMBOL(ttm_bo_move_accel_cleanup);
int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
struct dma_fence *fence, bool evict,
- struct ttm_mem_reg *new_mem)
+ struct ttm_resource *new_mem)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_resource *old_mem = &bo->mem;
- struct ttm_mem_type_manager *from = &bdev->man[old_mem->mem_type];
- struct ttm_mem_type_manager *to = &bdev->man[new_mem->mem_type];
+ struct ttm_resource_manager *from = ttm_manager_type(bdev, old_mem->mem_type);
+ struct ttm_resource_manager *to = ttm_manager_type(bdev, new_mem->mem_type);
int ret;
@@ -727,7 +733,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
* bo to be unbound and destroyed.
*/
- if (!(to->flags & TTM_MEMTYPE_FLAG_FIXED))
+ if (to->use_tt)
ghost_obj->ttm = NULL;
else
bo->ttm = NULL;
@@ -735,7 +741,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
dma_resv_unlock(&ghost_obj->base._resv);
ttm_bo_put(ghost_obj);
- } else if (from->flags & TTM_MEMTYPE_FLAG_FIXED) {
+ } else if (!from->use_tt) {
/**
* BO doesn't have a TTM we need to bind/unbind. Just remember
@@ -765,7 +771,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
if (ret)
return ret;
- if (to->flags & TTM_MEMTYPE_FLAG_FIXED) {
+ if (!to->use_tt) {
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 4732dcc80e11..01693e8f24b7 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -281,8 +281,8 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
pgoff_t i;
vm_fault_t ret = VM_FAULT_NOPAGE;
unsigned long address = vmf->address;
- struct ttm_mem_type_manager *man =
- &bdev->man[bo->mem.mem_type];
+ struct ttm_resource_manager *man =
+ ttm_manager_type(bdev, bo->mem.mem_type);
/*
* Refuse to fault imported pages. This should be handled
@@ -308,9 +308,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
}
if (bo->moving != moving) {
- spin_lock(&ttm_bo_glob.lru_lock);
- ttm_bo_move_to_lru_tail(bo, NULL);
- spin_unlock(&ttm_bo_glob.lru_lock);
+ ttm_bo_move_to_lru_tail_unlocked(bo);
}
dma_fence_put(moving);
}
diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
index 1797f04c0534..8a8f1a6a83a6 100644
--- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c
+++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
@@ -93,7 +93,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
list_for_each_entry(entry, list, head) {
struct ttm_buffer_object *bo = entry->bo;
- ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), ticket);
+ ret = ttm_bo_reserve(bo, intr, (ticket == NULL), ticket);
if (ret == -EALREADY && dups) {
struct ttm_validate_buffer *safe = entry;
entry = list_prev_entry(entry, head);
@@ -119,13 +119,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
ttm_eu_backoff_reservation_reverse(list, entry);
if (ret == -EDEADLK) {
- if (intr) {
- ret = dma_resv_lock_slow_interruptible(bo->base.resv,
- ticket);
- } else {
- dma_resv_lock_slow(bo->base.resv, ticket);
- ret = 0;
- }
+ ret = ttm_bo_reserve_slowpath(bo, intr, ticket);
}
if (!ret && entry->num_shared)
@@ -133,8 +127,6 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
entry->num_shared);
if (unlikely(ret != 0)) {
- if (ret == -EINTR)
- ret = -ERESTARTSYS;
if (ticket) {
ww_acquire_done(ticket);
ww_acquire_fini(ticket);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c
index facd3049c3aa..770c8988c139 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_range_manager.c
@@ -44,16 +44,22 @@
*/
struct ttm_range_manager {
+ struct ttm_resource_manager manager;
struct drm_mm mm;
spinlock_t lock;
};
-static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
+static inline struct ttm_range_manager *to_range_manager(struct ttm_resource_manager *man)
+{
+ return container_of(man, struct ttm_range_manager, manager);
+}
+
+static int ttm_range_man_alloc(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
- struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+ struct ttm_range_manager *rman = to_range_manager(man);
struct drm_mm *mm = &rman->mm;
struct drm_mm_node *node;
enum drm_mm_insert_mode mode;
@@ -89,10 +95,10 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
return ret;
}
-static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
- struct ttm_mem_reg *mem)
+static void ttm_range_man_free(struct ttm_resource_manager *man,
+ struct ttm_resource *mem)
{
- struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+ struct ttm_range_manager *rman = to_range_manager(man);
if (mem->mm_node) {
spin_lock(&rman->lock);
@@ -104,53 +110,78 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
}
}
-static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
- unsigned long p_size)
+static const struct ttm_resource_manager_func ttm_range_manager_func;
+
+int ttm_range_man_init(struct ttm_bo_device *bdev,
+ unsigned type,
+ uint32_t available_caching,
+ uint32_t default_caching,
+ bool use_tt,
+ unsigned long p_size)
{
+ struct ttm_resource_manager *man;
struct ttm_range_manager *rman;
rman = kzalloc(sizeof(*rman), GFP_KERNEL);
if (!rman)
return -ENOMEM;
+ man = &rman->manager;
+ man->available_caching = available_caching;
+ man->default_caching = default_caching;
+ man->use_tt = use_tt;
+
+ man->func = &ttm_range_manager_func;
+
+ ttm_resource_manager_init(man, p_size);
+
drm_mm_init(&rman->mm, 0, p_size);
spin_lock_init(&rman->lock);
- man->priv = rman;
+
+ ttm_set_driver_manager(bdev, type, &rman->manager);
+ ttm_resource_manager_set_used(man, true);
return 0;
}
+EXPORT_SYMBOL(ttm_range_man_init);
-static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
+int ttm_range_man_fini(struct ttm_bo_device *bdev,
+ unsigned type)
{
- struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+ struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
+ struct ttm_range_manager *rman = to_range_manager(man);
struct drm_mm *mm = &rman->mm;
+ int ret;
+
+ ttm_resource_manager_set_used(man, false);
+
+ ret = ttm_resource_manager_force_list_clean(bdev, man);
+ if (ret)
+ return ret;
spin_lock(&rman->lock);
- if (drm_mm_clean(mm)) {
- drm_mm_takedown(mm);
- spin_unlock(&rman->lock);
- kfree(rman);
- man->priv = NULL;
- return 0;
- }
+ drm_mm_clean(mm);
+ drm_mm_takedown(mm);
spin_unlock(&rman->lock);
- return -EBUSY;
+
+ ttm_resource_manager_cleanup(man);
+ ttm_set_driver_manager(bdev, type, NULL);
+ kfree(rman);
+ return 0;
}
+EXPORT_SYMBOL(ttm_range_man_fini);
-static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
- struct drm_printer *printer)
+static void ttm_range_man_debug(struct ttm_resource_manager *man,
+ struct drm_printer *printer)
{
- struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+ struct ttm_range_manager *rman = to_range_manager(man);
spin_lock(&rman->lock);
drm_mm_print(&rman->mm, printer);
spin_unlock(&rman->lock);
}
-const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
- .init = ttm_bo_man_init,
- .takedown = ttm_bo_man_takedown,
- .get_node = ttm_bo_man_get_node,
- .put_node = ttm_bo_man_put_node,
- .debug = ttm_bo_man_debug
+static const struct ttm_resource_manager_func ttm_range_manager_func = {
+ .alloc = ttm_range_man_alloc,
+ .free = ttm_range_man_free,
+ .debug = ttm_range_man_debug
};
-EXPORT_SYMBOL(ttm_bo_manager_func);
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
new file mode 100644
index 000000000000..33b642532e5c
--- /dev/null
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Christian König
+ */
+
+#include <drm/ttm/ttm_resource.h>
+#include <drm/ttm/ttm_bo_driver.h>
+
+int ttm_resource_alloc(struct ttm_buffer_object *bo,
+ const struct ttm_place *place,
+ struct ttm_resource *res)
+{
+ struct ttm_resource_manager *man =
+ ttm_manager_type(bo->bdev, res->mem_type);
+
+ res->mm_node = NULL;
+ if (!man->func || !man->func->alloc)
+ return 0;
+
+ return man->func->alloc(man, bo, place, res);
+}
+
+void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource *res)
+{
+ struct ttm_resource_manager *man =
+ ttm_manager_type(bo->bdev, res->mem_type);
+
+ if (man->func && man->func->free)
+ man->func->free(man, res);
+
+ res->mm_node = NULL;
+ res->mem_type = TTM_PL_SYSTEM;
+}
+EXPORT_SYMBOL(ttm_resource_free);
+
+/**
+ * ttm_resource_manager_init
+ *
+ * @man: memory manager object to init
+ * @p_size: size managed area in pages.
+ *
+ * Initialise core parts of a manager object.
+ */
+void ttm_resource_manager_init(struct ttm_resource_manager *man,
+ unsigned long p_size)
+{
+ unsigned i;
+
+ man->use_io_reserve_lru = false;
+ mutex_init(&man->io_reserve_mutex);
+ spin_lock_init(&man->move_lock);
+ INIT_LIST_HEAD(&man->io_reserve_lru);
+ man->size = p_size;
+
+ for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
+ INIT_LIST_HEAD(&man->lru[i]);
+ man->move = NULL;
+}
+EXPORT_SYMBOL(ttm_resource_manager_init);
+
+/*
+ * ttm_resource_manager_force_list_clean
+ *
+ * @bdev - device to use
+ * @man - manager to use
+ *
+ * Force all the objects out of a memory manager until clean.
+ * Part of memory manager cleanup sequence.
+ */
+int ttm_resource_manager_force_list_clean(struct ttm_bo_device *bdev,
+ struct ttm_resource_manager *man)
+{
+ struct ttm_operation_ctx ctx = {
+ .interruptible = false,
+ .no_wait_gpu = false,
+ .flags = TTM_OPT_FLAG_FORCE_ALLOC
+ };
+ struct ttm_bo_global *glob = &ttm_bo_glob;
+ struct dma_fence *fence;
+ int ret;
+ unsigned i;
+
+ /*
+ * Can't use standard list traversal since we're unlocking.
+ */
+
+ spin_lock(&glob->lru_lock);
+ for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
+ while (!list_empty(&man->lru[i])) {
+ spin_unlock(&glob->lru_lock);
+ ret = ttm_mem_evict_first(bdev, man, NULL, &ctx,
+ NULL);
+ if (ret)
+ return ret;
+ spin_lock(&glob->lru_lock);
+ }
+ }
+ spin_unlock(&glob->lru_lock);
+
+ spin_lock(&man->move_lock);
+ fence = dma_fence_get(man->move);
+ spin_unlock(&man->move_lock);
+
+ if (fence) {
+ ret = dma_fence_wait(fence, false);
+ dma_fence_put(fence);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ttm_resource_manager_force_list_clean);
+
+/**
+ * ttm_resource_manager_debug
+ *
+ * @man: manager type to dump.
+ * @p: printer to use for debug.
+ */
+void ttm_resource_manager_debug(struct ttm_resource_manager *man,
+ struct drm_printer *p)
+{
+ drm_printf(p, " use_type: %d\n", man->use_type);
+ drm_printf(p, " use_tt: %d\n", man->use_tt);
+ drm_printf(p, " size: %llu\n", man->size);
+ drm_printf(p, " available_caching: 0x%08X\n", man->available_caching);
+ drm_printf(p, " default_caching: 0x%08X\n", man->default_caching);
+ if (man->func && man->func->debug)
+ (*man->func->debug)(man, p);
+}
+EXPORT_SYMBOL(ttm_resource_manager_debug);
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index 3437711ddb43..1ccf1ef050d6 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -50,6 +50,9 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc)
dma_resv_assert_held(bo->base.resv);
+ if (bo->ttm)
+ return 0;
+
if (bdev->need_dma32)
page_flags |= TTM_PAGE_FLAG_DMA32;
@@ -67,7 +70,6 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc)
page_flags |= TTM_PAGE_FLAG_SG;
break;
default:
- bo->ttm = NULL;
pr_err("Illegal buffer object type\n");
return -EINVAL;
}
@@ -314,7 +316,7 @@ void ttm_tt_unbind(struct ttm_tt *ttm)
}
}
-int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem,
+int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem,
struct ttm_operation_ctx *ctx)
{
int ret = 0;
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
index 82a7dfdd14c2..9f7c26193831 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -358,18 +358,7 @@ static struct platform_driver v3d_platform_driver = {
},
};
-static int __init v3d_drm_register(void)
-{
- return platform_driver_register(&v3d_platform_driver);
-}
-
-static void __exit v3d_drm_unregister(void)
-{
- platform_driver_unregister(&v3d_platform_driver);
-}
-
-module_init(v3d_drm_register);
-module_exit(v3d_drm_unregister);
+module_platform_driver(v3d_platform_driver);
MODULE_ALIAS("platform:v3d-drm");
MODULE_DESCRIPTION("Broadcom V3D DRM Driver");
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
index a775feda1cc7..313339bbff90 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.c
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
@@ -471,8 +471,8 @@ static int __init vgem_init(void)
out_put:
drm_dev_put(&vgem_device->drm);
+ platform_device_unregister(vgem_device->platform);
return ret;
-
out_unregister:
platform_device_unregister(vgem_device->platform);
out_free:
diff --git a/drivers/gpu/drm/virtio/Kconfig b/drivers/gpu/drm/virtio/Kconfig
index eff3047052d4..67624423013a 100644
--- a/drivers/gpu/drm/virtio/Kconfig
+++ b/drivers/gpu/drm/virtio/Kconfig
@@ -4,6 +4,7 @@ config DRM_VIRTIO_GPU
depends on DRM && VIRTIO && MMU
select DRM_KMS_HELPER
select DRM_GEM_SHMEM_HELPER
+ select VIRTIO_DMA_SHARED_BUFFER
help
This is the virtual GPU driver for virtio. It can be used with
QEMU based VMMs (like KVM or Xen).
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index af55b334be2f..2c2742b8d657 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -165,8 +165,6 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector)
count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
if (width == 0 || height == 0) {
- width = XRES_DEF;
- height = YRES_DEF;
drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
} else {
DRM_DEBUG("add mode: %dx%d\n", width, height);
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c
index ab4bed78e656..b039f493bda9 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
@@ -165,6 +165,7 @@ static unsigned int features[] = {
VIRTIO_GPU_F_VIRGL,
#endif
VIRTIO_GPU_F_EDID,
+ VIRTIO_GPU_F_RESOURCE_UUID,
};
static struct virtio_driver virtio_gpu_driver = {
.feature_table = features,
@@ -202,6 +203,8 @@ static struct drm_driver driver = {
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_mmap = drm_gem_prime_mmap,
+ .gem_prime_export = virtgpu_gem_prime_export,
+ .gem_prime_import = virtgpu_gem_prime_import,
.gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table,
.gem_create_object = virtio_gpu_create_object,
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 9ff9f4ac0522..9a8bfbf85412 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -49,6 +49,10 @@
#define DRIVER_MINOR 1
#define DRIVER_PATCHLEVEL 0
+#define UUID_INITIALIZING 0
+#define UUID_INITIALIZED 1
+#define UUID_INITIALIZATION_FAILED 2
+
struct virtio_gpu_object_params {
uint32_t format;
uint32_t width;
@@ -71,6 +75,9 @@ struct virtio_gpu_object {
uint32_t hw_res_handle;
bool dumb;
bool created;
+
+ int uuid_state;
+ uuid_t uuid;
};
#define gem_to_virtio_gpu_obj(gobj) \
container_of((gobj), struct virtio_gpu_object, base.base)
@@ -200,6 +207,7 @@ struct virtio_gpu_device {
bool has_virgl_3d;
bool has_edid;
bool has_indirect;
+ bool has_resource_assign_uuid;
struct work_struct config_changed_work;
@@ -210,6 +218,9 @@ struct virtio_gpu_device {
struct virtio_gpu_drv_capset *capsets;
uint32_t num_capsets;
struct list_head cap_cache;
+
+ /* protects resource state when exporting */
+ spinlock_t resource_export_lock;
};
struct virtio_gpu_fpriv {
@@ -336,6 +347,10 @@ void virtio_gpu_dequeue_fence_func(struct work_struct *work);
void virtio_gpu_notify(struct virtio_gpu_device *vgdev);
+int
+virtio_gpu_cmd_resource_assign_uuid(struct virtio_gpu_device *vgdev,
+ struct virtio_gpu_object_array *objs);
+
/* virtgpu_display.c */
void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev);
void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev);
@@ -367,6 +382,12 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo);
/* virtgpu_prime.c */
+struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj,
+ int flags);
+struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *buf);
+int virtgpu_gem_prime_get_uuid(struct drm_gem_object *obj,
+ uuid_t *uuid);
struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *sgt);
diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
index 24ffacac99e4..c30c75ee83fc 100644
--- a/drivers/gpu/drm/virtio/virtgpu_gem.c
+++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
@@ -154,9 +154,8 @@ void virtio_gpu_gem_object_close(struct drm_gem_object *obj,
struct virtio_gpu_object_array *virtio_gpu_array_alloc(u32 nents)
{
struct virtio_gpu_object_array *objs;
- size_t size = sizeof(*objs) + sizeof(objs->objs[0]) * nents;
- objs = kmalloc(size, GFP_KERNEL);
+ objs = kmalloc(struct_size(objs, objs, nents), GFP_KERNEL);
if (!objs)
return NULL;
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
index 4d944a0dff3e..75d0dc2f6d28 100644
--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -118,6 +118,7 @@ int virtio_gpu_init(struct drm_device *dev)
vgdev->dev = dev->dev;
spin_lock_init(&vgdev->display_info_lock);
+ spin_lock_init(&vgdev->resource_export_lock);
ida_init(&vgdev->ctx_id_ida);
ida_init(&vgdev->resource_ida);
init_waitqueue_head(&vgdev->resp_wq);
@@ -146,6 +147,9 @@ int virtio_gpu_init(struct drm_device *dev)
if (virtio_has_feature(vgdev->vdev, VIRTIO_RING_F_INDIRECT_DESC)) {
vgdev->has_indirect = true;
}
+ if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_UUID)) {
+ vgdev->has_resource_assign_uuid = true;
+ }
DRM_INFO("features: %cvirgl %cedid\n",
vgdev->has_virgl_3d ? '+' : '-',
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index e83651b7747d..842f8b61aa89 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -151,7 +151,13 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev,
if (ret < 0)
return -EINVAL;
- shmem->pages = drm_gem_shmem_get_pages_sgt(&bo->base.base);
+ /*
+ * virtio_gpu uses drm_gem_shmem_get_sg_table instead of
+ * drm_gem_shmem_get_pages_sgt because virtio has it's own set of
+ * dma-ops. This is discouraged for other drivers, but should be fine
+ * since virtio_gpu doesn't support dma-buf import from other devices.
+ */
+ shmem->pages = drm_gem_shmem_get_sg_table(&bo->base.base);
if (!shmem->pages) {
drm_gem_shmem_unpin(&bo->base.base);
return -EINVAL;
diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c
index 050d24c39a8f..acd14ef73d56 100644
--- a/drivers/gpu/drm/virtio/virtgpu_prime.c
+++ b/drivers/gpu/drm/virtio/virtgpu_prime.c
@@ -23,12 +23,102 @@
*/
#include <drm/drm_prime.h>
+#include <linux/virtio_dma_buf.h>
#include "virtgpu_drv.h"
-/* Empty Implementations as there should not be any other driver for a virtual
- * device that might share buffers with virtgpu
- */
+static int virtgpu_virtio_get_uuid(struct dma_buf *buf,
+ uuid_t *uuid)
+{
+ struct drm_gem_object *obj = buf->priv;
+ struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
+ struct virtio_gpu_device *vgdev = obj->dev->dev_private;
+
+ wait_event(vgdev->resp_wq, bo->uuid_state != UUID_INITIALIZING);
+ if (bo->uuid_state != UUID_INITIALIZED)
+ return -ENODEV;
+
+ uuid_copy(uuid, &bo->uuid);
+
+ return 0;
+}
+
+const struct virtio_dma_buf_ops virtgpu_dmabuf_ops = {
+ .ops = {
+ .cache_sgt_mapping = true,
+ .attach = virtio_dma_buf_attach,
+ .detach = drm_gem_map_detach,
+ .map_dma_buf = drm_gem_map_dma_buf,
+ .unmap_dma_buf = drm_gem_unmap_dma_buf,
+ .release = drm_gem_dmabuf_release,
+ .mmap = drm_gem_dmabuf_mmap,
+ .vmap = drm_gem_dmabuf_vmap,
+ .vunmap = drm_gem_dmabuf_vunmap,
+ },
+ .device_attach = drm_gem_map_attach,
+ .get_uuid = virtgpu_virtio_get_uuid,
+};
+
+struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj,
+ int flags)
+{
+ struct dma_buf *buf;
+ struct drm_device *dev = obj->dev;
+ struct virtio_gpu_device *vgdev = dev->dev_private;
+ struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
+ struct virtio_gpu_object_array *objs;
+ int ret = 0;
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+ if (vgdev->has_resource_assign_uuid) {
+ objs = virtio_gpu_array_alloc(1);
+ if (!objs)
+ return ERR_PTR(-ENOMEM);
+ virtio_gpu_array_add_obj(objs, &bo->base.base);
+
+ ret = virtio_gpu_cmd_resource_assign_uuid(vgdev, objs);
+ if (ret)
+ return ERR_PTR(ret);
+ virtio_gpu_notify(vgdev);
+ } else {
+ bo->uuid_state = UUID_INITIALIZATION_FAILED;
+ }
+
+ exp_info.ops = &virtgpu_dmabuf_ops.ops;
+ exp_info.size = obj->size;
+ exp_info.flags = flags;
+ exp_info.priv = obj;
+ exp_info.resv = obj->resv;
+
+ buf = virtio_dma_buf_export(&exp_info);
+ if (IS_ERR(buf))
+ return buf;
+
+ drm_dev_get(dev);
+ drm_gem_object_get(obj);
+
+ return buf;
+}
+
+struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *buf)
+{
+ struct drm_gem_object *obj;
+
+ if (buf->ops == &virtgpu_dmabuf_ops.ops) {
+ obj = buf->priv;
+ if (obj->dev == dev) {
+ /*
+ * Importing dmabuf exported from our own gem increases
+ * refcount on gem itself instead of f_count of dmabuf.
+ */
+ drm_gem_object_get(obj);
+ return obj;
+ }
+ }
+
+ return drm_gem_prime_import(dev, buf);
+}
struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 53af60d484a4..c93c2db35aaf 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -1107,3 +1107,58 @@ void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev,
memcpy(cur_p, &output->cursor, sizeof(output->cursor));
virtio_gpu_queue_cursor(vgdev, vbuf);
}
+
+static void virtio_gpu_cmd_resource_uuid_cb(struct virtio_gpu_device *vgdev,
+ struct virtio_gpu_vbuffer *vbuf)
+{
+ struct virtio_gpu_object *obj =
+ gem_to_virtio_gpu_obj(vbuf->objs->objs[0]);
+ struct virtio_gpu_resp_resource_uuid *resp =
+ (struct virtio_gpu_resp_resource_uuid *)vbuf->resp_buf;
+ uint32_t resp_type = le32_to_cpu(resp->hdr.type);
+
+ spin_lock(&vgdev->resource_export_lock);
+ WARN_ON(obj->uuid_state != UUID_INITIALIZING);
+
+ if (resp_type == VIRTIO_GPU_RESP_OK_RESOURCE_UUID &&
+ obj->uuid_state == UUID_INITIALIZING) {
+ memcpy(&obj->uuid.b, resp->uuid, sizeof(obj->uuid.b));
+ obj->uuid_state = UUID_INITIALIZED;
+ } else {
+ obj->uuid_state = UUID_INITIALIZATION_FAILED;
+ }
+ spin_unlock(&vgdev->resource_export_lock);
+
+ wake_up_all(&vgdev->resp_wq);
+}
+
+int
+virtio_gpu_cmd_resource_assign_uuid(struct virtio_gpu_device *vgdev,
+ struct virtio_gpu_object_array *objs)
+{
+ struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(objs->objs[0]);
+ struct virtio_gpu_resource_assign_uuid *cmd_p;
+ struct virtio_gpu_vbuffer *vbuf;
+ struct virtio_gpu_resp_resource_uuid *resp_buf;
+
+ resp_buf = kzalloc(sizeof(*resp_buf), GFP_KERNEL);
+ if (!resp_buf) {
+ spin_lock(&vgdev->resource_export_lock);
+ bo->uuid_state = UUID_INITIALIZATION_FAILED;
+ spin_unlock(&vgdev->resource_export_lock);
+ virtio_gpu_array_put_free(objs);
+ return -ENOMEM;
+ }
+
+ cmd_p = virtio_gpu_alloc_cmd_resp
+ (vgdev, virtio_gpu_cmd_resource_uuid_cb, &vbuf, sizeof(*cmd_p),
+ sizeof(struct virtio_gpu_resp_resource_uuid), resp_buf);
+ memset(cmd_p, 0, sizeof(*cmd_p));
+
+ cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID);
+ cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle);
+
+ vbuf->objs = objs;
+ virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
+ return 0;
+}
diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
index 4af2f19480f4..4f3b07a32b60 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -33,7 +33,7 @@ static uint32_t compute_crc(void *vaddr_out, struct vkms_composer *composer)
+ (i * composer->pitch)
+ (j * composer->cpp);
/* XRGB format ignores Alpha channel */
- memset(vaddr_out + src_offset + 24, 0, 8);
+ bitmap_clear(vaddr_out + src_offset, 24, 8);
crc = crc32_le(crc, vaddr_out + src_offset,
sizeof(u32));
}
@@ -233,6 +233,22 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
return 0;
}
+static void vkms_set_composer(struct vkms_output *out, bool enabled)
+{
+ bool old_enabled;
+
+ if (enabled)
+ drm_crtc_vblank_get(&out->crtc);
+
+ spin_lock_irq(&out->lock);
+ old_enabled = out->composer_enabled;
+ out->composer_enabled = enabled;
+ spin_unlock_irq(&out->lock);
+
+ if (old_enabled)
+ drm_crtc_vblank_put(&out->crtc);
+}
+
int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name)
{
struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
@@ -241,9 +257,7 @@ int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name)
ret = vkms_crc_parse_source(src_name, &enabled);
- spin_lock_irq(&out->lock);
- out->composer_enabled = enabled;
- spin_unlock_irq(&out->lock);
+ vkms_set_composer(out, enabled);
return ret;
}
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 57a8a397d5e8..83dd5567de8b 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -190,8 +190,8 @@ static int __init vkms_init(void)
out_put:
drm_dev_put(&vkms_device->drm);
+ platform_device_unregister(vkms_device->platform);
return ret;
-
out_unregister:
platform_device_unregister(vkms_device->platform);
out_free:
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index 1e59c019affa..3229451d0706 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -1135,14 +1135,14 @@ void vmw_bo_swap_notify(struct ttm_buffer_object *bo)
* vmw_bo_move_notify - TTM move_notify_callback
*
* @bo: The TTM buffer object about to move.
- * @mem: The struct ttm_mem_reg indicating to what memory
+ * @mem: The struct ttm_resource indicating to what memory
* region the move is taking place.
*
* Detaches cached maps and device bindings that require that the
* buffer doesn't move.
*/
void vmw_bo_move_notify(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
struct vmw_buffer_object *vbo;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index fb39826f72c1..e60012886065 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -620,6 +620,29 @@ static int vmw_dma_masks(struct vmw_private *dev_priv)
return ret;
}
+static int vmw_vram_manager_init(struct vmw_private *dev_priv)
+{
+ int ret;
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ ret = vmw_thp_init(dev_priv);
+#else
+ ret = ttm_range_man_init(&dev_priv->bdev, TTM_PL_VRAM,
+ TTM_PL_FLAG_CACHED, TTM_PL_FLAG_CACHED,
+ false, dev_priv->vram_size >> PAGE_SHIFT);
+#endif
+ ttm_resource_manager_set_used(ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM), false);
+ return ret;
+}
+
+static void vmw_vram_manager_fini(struct vmw_private *dev_priv)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ vmw_thp_fini(dev_priv);
+#else
+ ttm_range_man_fini(&dev_priv->bdev, TTM_PL_VRAM);
+#endif
+}
+
static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
{
struct vmw_private *dev_priv;
@@ -859,23 +882,30 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
DRM_ERROR("Failed initializing TTM buffer object driver.\n");
goto out_no_bdev;
}
+ ttm_manager_type(&dev_priv->bdev, TTM_PL_SYSTEM)->available_caching =
+ TTM_PL_FLAG_CACHED;
/*
* Enable VRAM, but initially don't use it until SVGA is enabled and
* unhidden.
*/
- ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM,
- (dev_priv->vram_size >> PAGE_SHIFT));
+
+ ret = vmw_vram_manager_init(dev_priv);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed initializing memory manager for VRAM.\n");
goto out_no_vram;
}
- dev_priv->bdev.man[TTM_PL_VRAM].use_type = false;
+ /*
+ * "Guest Memory Regions" is an aperture like feature with
+ * one slot per bo. There is an upper limit of the number of
+ * slots as well as the bo size.
+ */
dev_priv->has_gmr = true;
+ /* TODO: This is most likely not correct */
if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
- refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
- VMW_PL_GMR) != 0) {
+ refuse_dma ||
+ vmw_gmrid_man_init(dev_priv, VMW_PL_GMR) != 0) {
DRM_INFO("No GMR memory available. "
"Graphics memory resources are very limited.\n");
dev_priv->has_gmr = false;
@@ -883,8 +913,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS && !refuse_dma) {
dev_priv->has_mob = true;
- if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB,
- VMW_PL_MOB) != 0) {
+
+ if (vmw_gmrid_man_init(dev_priv, VMW_PL_MOB) != 0) {
DRM_INFO("No MOB memory available. "
"3D will be disabled.\n");
dev_priv->has_mob = false;
@@ -961,10 +991,10 @@ out_no_fifo:
vmw_kms_close(dev_priv);
out_no_kms:
if (dev_priv->has_mob)
- (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
+ vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB);
if (dev_priv->has_gmr)
- (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
- (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+ vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR);
+ vmw_vram_manager_fini(dev_priv);
out_no_vram:
(void)ttm_bo_device_release(&dev_priv->bdev);
out_no_bdev:
@@ -1012,12 +1042,12 @@ static void vmw_driver_unload(struct drm_device *dev)
vmw_overlay_close(dev_priv);
if (dev_priv->has_gmr)
- (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
- (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+ vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR);
vmw_release_device_early(dev_priv);
if (dev_priv->has_mob)
- (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
+ vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB);
+ vmw_vram_manager_fini(dev_priv);
(void) ttm_bo_device_release(&dev_priv->bdev);
drm_vma_offset_manager_destroy(&dev_priv->vma_manager);
vmw_release_device_late(dev_priv);
@@ -1159,10 +1189,12 @@ static void vmw_master_drop(struct drm_device *dev,
*/
static void __vmw_svga_enable(struct vmw_private *dev_priv)
{
+ struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM);
+
spin_lock(&dev_priv->svga_lock);
- if (!dev_priv->bdev.man[TTM_PL_VRAM].use_type) {
+ if (!ttm_resource_manager_used(man)) {
vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE);
- dev_priv->bdev.man[TTM_PL_VRAM].use_type = true;
+ ttm_resource_manager_set_used(man, true);
}
spin_unlock(&dev_priv->svga_lock);
}
@@ -1188,9 +1220,11 @@ void vmw_svga_enable(struct vmw_private *dev_priv)
*/
static void __vmw_svga_disable(struct vmw_private *dev_priv)
{
+ struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM);
+
spin_lock(&dev_priv->svga_lock);
- if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) {
- dev_priv->bdev.man[TTM_PL_VRAM].use_type = false;
+ if (ttm_resource_manager_used(man)) {
+ ttm_resource_manager_set_used(man, false);
vmw_write(dev_priv, SVGA_REG_ENABLE,
SVGA_REG_ENABLE_HIDE |
SVGA_REG_ENABLE_ENABLE);
@@ -1207,6 +1241,7 @@ static void __vmw_svga_disable(struct vmw_private *dev_priv)
*/
void vmw_svga_disable(struct vmw_private *dev_priv)
{
+ struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM);
/*
* Disabling SVGA will turn off device modesetting capabilities, so
* notify KMS about that so that it doesn't cache atomic state that
@@ -1222,8 +1257,8 @@ void vmw_svga_disable(struct vmw_private *dev_priv)
vmw_kms_lost_device(dev_priv->dev);
ttm_write_lock(&dev_priv->reservation_sem, false);
spin_lock(&dev_priv->svga_lock);
- if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) {
- dev_priv->bdev.man[TTM_PL_VRAM].use_type = false;
+ if (ttm_resource_manager_used(man)) {
+ ttm_resource_manager_set_used(man, false);
spin_unlock(&dev_priv->svga_lock);
if (ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM))
DRM_ERROR("Failed evicting VRAM buffers.\n");
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 3596f3923ea3..871ad738dadb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -793,7 +793,7 @@ extern void vmw_resource_unreserve(struct vmw_resource *res,
struct vmw_buffer_object *new_backup,
unsigned long new_backup_offset);
extern void vmw_query_move_notify(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob);
extern void vmw_resource_evict_all(struct vmw_private *dev_priv);
extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo);
@@ -878,7 +878,7 @@ extern void vmw_bo_fence_single(struct ttm_buffer_object *bo,
extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo);
extern void vmw_bo_unmap(struct vmw_buffer_object *vbo);
extern void vmw_bo_move_notify(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo);
extern struct vmw_buffer_object *
vmw_user_bo_noref_lookup(struct ttm_object_file *tfile, u32 handle);
@@ -1019,10 +1019,12 @@ extern struct ttm_placement vmw_mob_placement;
extern struct ttm_placement vmw_mob_ne_placement;
extern struct ttm_placement vmw_nonfixed_placement;
extern struct ttm_bo_driver vmw_bo_driver;
-extern int vmw_bo_map_dma(struct ttm_buffer_object *bo);
-extern void vmw_bo_unmap_dma(struct ttm_buffer_object *bo);
extern const struct vmw_sg_table *
vmw_bo_sg_table(struct ttm_buffer_object *bo);
+extern int vmw_bo_create_and_populate(struct vmw_private *dev_priv,
+ unsigned long bo_size,
+ struct ttm_buffer_object **bo_p);
+
extern void vmw_piter_start(struct vmw_piter *viter,
const struct vmw_sg_table *vsgt,
unsigned long p_offs);
@@ -1219,7 +1221,8 @@ int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
* GMR Id manager
*/
-extern const struct ttm_mem_type_manager_func vmw_gmrid_manager_func;
+int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type);
+void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type);
/**
* Prime - vmwgfx_prime.c
@@ -1518,9 +1521,8 @@ vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf,
/* Transparent hugepage support - vmwgfx_thp.c */
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-extern const struct ttm_mem_type_manager_func vmw_thp_func;
-#else
-#define vmw_thp_func ttm_bo_manager_func
+extern int vmw_thp_init(struct vmw_private *dev_priv);
+void vmw_thp_fini(struct vmw_private *dev_priv);
#endif
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
index 4a76fc7114ad..bb76acb5b0fc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
@@ -37,6 +37,7 @@
#include <linux/kernel.h>
struct vmwgfx_gmrid_man {
+ struct ttm_resource_manager manager;
spinlock_t lock;
struct ida gmr_ida;
uint32_t max_gmr_ids;
@@ -44,13 +45,17 @@ struct vmwgfx_gmrid_man {
uint32_t used_gmr_pages;
};
-static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
+static struct vmwgfx_gmrid_man *to_gmrid_manager(struct ttm_resource_manager *man)
+{
+ return container_of(man, struct vmwgfx_gmrid_man, manager);
+}
+
+static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
- struct vmwgfx_gmrid_man *gman =
- (struct vmwgfx_gmrid_man *)man->priv;
+ struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
int id;
id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL);
@@ -79,11 +84,10 @@ nospace:
return -ENOSPC;
}
-static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
- struct ttm_mem_reg *mem)
+static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man,
+ struct ttm_resource *mem)
{
- struct vmwgfx_gmrid_man *gman =
- (struct vmwgfx_gmrid_man *)man->priv;
+ struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
if (mem->mm_node) {
ida_free(&gman->gmr_ida, mem->start);
@@ -94,22 +98,30 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
}
}
-static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
- unsigned long p_size)
+static const struct ttm_resource_manager_func vmw_gmrid_manager_func;
+
+int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type)
{
- struct vmw_private *dev_priv =
- container_of(man->bdev, struct vmw_private, bdev);
+ struct ttm_resource_manager *man;
struct vmwgfx_gmrid_man *gman =
kzalloc(sizeof(*gman), GFP_KERNEL);
if (unlikely(!gman))
return -ENOMEM;
+ man = &gman->manager;
+
+ man->func = &vmw_gmrid_manager_func;
+ man->available_caching = TTM_PL_FLAG_CACHED;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+ /* TODO: This is most likely not correct */
+ man->use_tt = true;
+ ttm_resource_manager_init(man, 0);
spin_lock_init(&gman->lock);
gman->used_gmr_pages = 0;
ida_init(&gman->gmr_ida);
- switch (p_size) {
+ switch (type) {
case VMW_PL_GMR:
gman->max_gmr_ids = dev_priv->max_gmr_ids;
gman->max_gmr_pages = dev_priv->max_gmr_pages;
@@ -121,32 +133,29 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
default:
BUG();
}
- man->priv = (void *) gman;
+ ttm_set_driver_manager(&dev_priv->bdev, type, &gman->manager);
+ ttm_resource_manager_set_used(man, true);
return 0;
}
-static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man)
+void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type)
{
- struct vmwgfx_gmrid_man *gman =
- (struct vmwgfx_gmrid_man *)man->priv;
+ struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, type);
+ struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
- if (gman) {
- ida_destroy(&gman->gmr_ida);
- kfree(gman);
- }
- return 0;
-}
+ ttm_resource_manager_set_used(man, false);
+
+ ttm_resource_manager_force_list_clean(&dev_priv->bdev, man);
+
+ ttm_resource_manager_cleanup(man);
+
+ ttm_set_driver_manager(&dev_priv->bdev, type, NULL);
+ ida_destroy(&gman->gmr_ida);
+ kfree(gman);
-static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man,
- struct drm_printer *printer)
-{
- drm_printf(printer, "No debug info available for the GMR id manager\n");
}
-const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = {
- .init = vmw_gmrid_man_init,
- .takedown = vmw_gmrid_man_takedown,
- .get_node = vmw_gmrid_man_get_node,
- .put_node = vmw_gmrid_man_put_node,
- .debug = vmw_gmrid_man_debug
+static const struct ttm_resource_manager_func vmw_gmrid_manager_func = {
+ .alloc = vmw_gmrid_man_get_node,
+ .free = vmw_gmrid_man_put_node,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
index e8eb42933ca2..7f95ed6aa224 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
@@ -238,10 +238,6 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv,
unsigned long offset;
unsigned long bo_size;
struct vmw_otable *otables = batch->otables;
- struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false
- };
SVGAOTableType i;
int ret;
@@ -255,24 +251,9 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv,
bo_size += otables[i].size;
}
- ret = ttm_bo_create(&dev_priv->bdev, bo_size,
- ttm_bo_type_device,
- &vmw_sys_ne_placement,
- 0, false, &batch->otable_bo);
-
- if (unlikely(ret != 0))
- goto out_no_bo;
-
- ret = ttm_bo_reserve(batch->otable_bo, false, true, NULL);
- BUG_ON(ret != 0);
- ret = vmw_bo_driver.ttm_tt_populate(batch->otable_bo->ttm, &ctx);
- if (unlikely(ret != 0))
- goto out_unreserve;
- ret = vmw_bo_map_dma(batch->otable_bo);
+ ret = vmw_bo_create_and_populate(dev_priv, bo_size, &batch->otable_bo);
if (unlikely(ret != 0))
- goto out_unreserve;
-
- ttm_bo_unreserve(batch->otable_bo);
+ return ret;
offset = 0;
for (i = 0; i < batch->num_otables; ++i) {
@@ -289,8 +270,6 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv,
return 0;
-out_unreserve:
- ttm_bo_unreserve(batch->otable_bo);
out_no_setup:
for (i = 0; i < batch->num_otables; ++i) {
if (batch->otables[i].enabled)
@@ -300,7 +279,6 @@ out_no_setup:
ttm_bo_put(batch->otable_bo);
batch->otable_bo = NULL;
-out_no_bo:
return ret;
}
@@ -432,41 +410,9 @@ struct vmw_mob *vmw_mob_create(unsigned long data_pages)
static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
struct vmw_mob *mob)
{
- int ret;
- struct ttm_operation_ctx ctx = {
- .interruptible = false,
- .no_wait_gpu = false
- };
-
BUG_ON(mob->pt_bo != NULL);
- ret = ttm_bo_create(&dev_priv->bdev, mob->num_pages * PAGE_SIZE,
- ttm_bo_type_device,
- &vmw_sys_ne_placement,
- 0, false, &mob->pt_bo);
- if (unlikely(ret != 0))
- return ret;
-
- ret = ttm_bo_reserve(mob->pt_bo, false, true, NULL);
-
- BUG_ON(ret != 0);
- ret = vmw_bo_driver.ttm_tt_populate(mob->pt_bo->ttm, &ctx);
- if (unlikely(ret != 0))
- goto out_unreserve;
- ret = vmw_bo_map_dma(mob->pt_bo);
- if (unlikely(ret != 0))
- goto out_unreserve;
-
- ttm_bo_unreserve(mob->pt_bo);
-
- return 0;
-
-out_unreserve:
- ttm_bo_unreserve(mob->pt_bo);
- ttm_bo_put(mob->pt_bo);
- mob->pt_bo = NULL;
-
- return ret;
+ return vmw_bo_create_and_populate(dev_priv, mob->num_pages * PAGE_SIZE, &mob->pt_bo);
}
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index c8441030637a..c0f156078dda 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -855,7 +855,7 @@ int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob)
* states from the device.
*/
void vmw_query_move_notify(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
struct vmw_buffer_object *dx_query_mob;
struct ttm_bo_device *bdev = bo->bdev;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c
index b7c816ba7166..3c00a9e7cfcc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c
@@ -16,14 +16,20 @@
* @lock: Manager lock.
*/
struct vmw_thp_manager {
+ struct ttm_resource_manager manager;
struct drm_mm mm;
spinlock_t lock;
};
+static struct vmw_thp_manager *to_thp_manager(struct ttm_resource_manager *man)
+{
+ return container_of(man, struct vmw_thp_manager, manager);
+}
+
static int vmw_thp_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node,
unsigned long align_pages,
const struct ttm_place *place,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
unsigned long lpfn,
enum drm_mm_insert_mode mode)
{
@@ -38,12 +44,12 @@ static int vmw_thp_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node,
return -ENOSPC;
}
-static int vmw_thp_get_node(struct ttm_mem_type_manager *man,
+static int vmw_thp_get_node(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
- struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv;
+ struct vmw_thp_manager *rman = to_thp_manager(man);
struct drm_mm *mm = &rman->mm;
struct drm_mm_node *node;
unsigned long align_pages;
@@ -100,10 +106,10 @@ found_unlock:
-static void vmw_thp_put_node(struct ttm_mem_type_manager *man,
- struct ttm_mem_reg *mem)
+static void vmw_thp_put_node(struct ttm_resource_manager *man,
+ struct ttm_resource *mem)
{
- struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv;
+ struct vmw_thp_manager *rman = to_thp_manager(man);
if (mem->mm_node) {
spin_lock(&rman->lock);
@@ -115,52 +121,63 @@ static void vmw_thp_put_node(struct ttm_mem_type_manager *man,
}
}
-static int vmw_thp_init(struct ttm_mem_type_manager *man,
- unsigned long p_size)
+int vmw_thp_init(struct vmw_private *dev_priv)
{
+ struct ttm_resource_manager *man;
struct vmw_thp_manager *rman;
rman = kzalloc(sizeof(*rman), GFP_KERNEL);
if (!rman)
return -ENOMEM;
- drm_mm_init(&rman->mm, 0, p_size);
+ man = &rman->manager;
+ man->available_caching = TTM_PL_FLAG_CACHED;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+
+ ttm_resource_manager_init(man,
+ dev_priv->vram_size >> PAGE_SHIFT);
+
+ drm_mm_init(&rman->mm, 0, man->size);
spin_lock_init(&rman->lock);
- man->priv = rman;
+
+ ttm_set_driver_manager(&dev_priv->bdev, TTM_PL_VRAM, &rman->manager);
+ ttm_resource_manager_set_used(man, true);
return 0;
}
-static int vmw_thp_takedown(struct ttm_mem_type_manager *man)
+void vmw_thp_fini(struct vmw_private *dev_priv)
{
- struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv;
+ struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM);
+ struct vmw_thp_manager *rman = to_thp_manager(man);
struct drm_mm *mm = &rman->mm;
+ int ret;
+
+ ttm_resource_manager_set_used(man, false);
+ ret = ttm_resource_manager_force_list_clean(&dev_priv->bdev, man);
+ if (ret)
+ return;
spin_lock(&rman->lock);
- if (drm_mm_clean(mm)) {
- drm_mm_takedown(mm);
- spin_unlock(&rman->lock);
- kfree(rman);
- man->priv = NULL;
- return 0;
- }
+ drm_mm_clean(mm);
+ drm_mm_takedown(mm);
spin_unlock(&rman->lock);
- return -EBUSY;
+ ttm_resource_manager_cleanup(man);
+ ttm_set_driver_manager(&dev_priv->bdev, TTM_PL_VRAM, NULL);
+ kfree(rman);
}
-static void vmw_thp_debug(struct ttm_mem_type_manager *man,
+static void vmw_thp_debug(struct ttm_resource_manager *man,
struct drm_printer *printer)
{
- struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv;
+ struct vmw_thp_manager *rman = to_thp_manager(man);
spin_lock(&rman->lock);
drm_mm_print(&rman->mm, printer);
spin_unlock(&rman->lock);
}
-const struct ttm_mem_type_manager_func vmw_thp_func = {
- .init = vmw_thp_init,
- .takedown = vmw_thp_takedown,
- .get_node = vmw_thp_get_node,
- .put_node = vmw_thp_put_node,
+const struct ttm_resource_manager_func vmw_thp_func = {
+ .alloc = vmw_thp_get_node,
+ .free = vmw_thp_put_node,
.debug = vmw_thp_debug
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
index ab524ab3b0b4..c7f10b2c93d2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
@@ -519,43 +519,6 @@ static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt)
vmw_tt->mapped = false;
}
-
-/**
- * vmw_bo_map_dma - Make sure buffer object pages are visible to the device
- *
- * @bo: Pointer to a struct ttm_buffer_object
- *
- * Wrapper around vmw_ttm_map_dma, that takes a TTM buffer object pointer
- * instead of a pointer to a struct vmw_ttm_backend as argument.
- * Note that the buffer object must be either pinned or reserved before
- * calling this function.
- */
-int vmw_bo_map_dma(struct ttm_buffer_object *bo)
-{
- struct vmw_ttm_tt *vmw_tt =
- container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
-
- return vmw_ttm_map_dma(vmw_tt);
-}
-
-
-/**
- * vmw_bo_unmap_dma - Make sure buffer object pages are visible to the device
- *
- * @bo: Pointer to a struct ttm_buffer_object
- *
- * Wrapper around vmw_ttm_unmap_dma, that takes a TTM buffer object pointer
- * instead of a pointer to a struct vmw_ttm_backend as argument.
- */
-void vmw_bo_unmap_dma(struct ttm_buffer_object *bo)
-{
- struct vmw_ttm_tt *vmw_tt =
- container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
-
- vmw_ttm_unmap_dma(vmw_tt);
-}
-
-
/**
* vmw_bo_sg_table - Return a struct vmw_sg_table object for a
* TTM buffer object
@@ -576,7 +539,7 @@ const struct vmw_sg_table *vmw_bo_sg_table(struct ttm_buffer_object *bo)
}
-static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
+static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem)
{
struct vmw_ttm_tt *vmw_be =
container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
@@ -734,40 +697,6 @@ out_no_init:
return NULL;
}
-static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
- struct ttm_mem_type_manager *man)
-{
- switch (type) {
- case TTM_PL_SYSTEM:
- /* System memory */
- man->available_caching = TTM_PL_FLAG_CACHED;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- case TTM_PL_VRAM:
- /* "On-card" video ram */
- man->func = &vmw_thp_func;
- man->flags = TTM_MEMTYPE_FLAG_FIXED;
- man->available_caching = TTM_PL_FLAG_CACHED;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- case VMW_PL_GMR:
- case VMW_PL_MOB:
- /*
- * "Guest Memory Regions" is an aperture like feature with
- * one slot per bo. There is an upper limit of the number of
- * slots as well as the bo size.
- */
- man->func = &vmw_gmrid_manager_func;
- man->available_caching = TTM_PL_FLAG_CACHED;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- default:
- DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
- return -EINVAL;
- }
- return 0;
-}
-
static void vmw_evict_flags(struct ttm_buffer_object *bo,
struct ttm_placement *placement)
{
@@ -782,16 +711,10 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
return vmw_user_bo_verify_access(bo, tfile);
}
-static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
{
struct vmw_private *dev_priv = container_of(bdev, struct vmw_private, bdev);
- mem->bus.addr = NULL;
- mem->bus.is_iomem = false;
- mem->bus.offset = 0;
- mem->bus.size = mem->num_pages << PAGE_SHIFT;
- mem->bus.base = 0;
-
switch (mem->mem_type) {
case TTM_PL_SYSTEM:
case VMW_PL_GMR:
@@ -812,7 +735,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
* vmw_move_notify - TTM move_notify_callback
*
* @bo: The TTM buffer object about to move.
- * @mem: The struct ttm_mem_reg indicating to what memory
+ * @mem: The struct ttm_resource indicating to what memory
* region the move is taking place.
*
* Calls move_notify for all subsystems needing it.
@@ -820,7 +743,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
*/
static void vmw_move_notify(struct ttm_buffer_object *bo,
bool evict,
- struct ttm_mem_reg *mem)
+ struct ttm_resource *mem)
{
vmw_bo_move_notify(bo, mem);
vmw_query_move_notify(bo, mem);
@@ -843,7 +766,6 @@ struct ttm_bo_driver vmw_bo_driver = {
.ttm_tt_create = &vmw_ttm_tt_create,
.ttm_tt_populate = &vmw_ttm_populate,
.ttm_tt_unpopulate = &vmw_ttm_unpopulate,
- .init_mem_type = vmw_init_mem_type,
.eviction_valuable = ttm_bo_eviction_valuable,
.evict_flags = vmw_evict_flags,
.move = NULL,
@@ -852,3 +774,38 @@ struct ttm_bo_driver vmw_bo_driver = {
.swap_notify = vmw_swap_notify,
.io_mem_reserve = &vmw_ttm_io_mem_reserve,
};
+
+int vmw_bo_create_and_populate(struct vmw_private *dev_priv,
+ unsigned long bo_size,
+ struct ttm_buffer_object **bo_p)
+{
+ struct ttm_operation_ctx ctx = {
+ .interruptible = false,
+ .no_wait_gpu = false
+ };
+ struct ttm_buffer_object *bo;
+ int ret;
+
+ ret = ttm_bo_create(&dev_priv->bdev, bo_size,
+ ttm_bo_type_device,
+ &vmw_sys_ne_placement,
+ 0, false, &bo);
+
+ if (unlikely(ret != 0))
+ return ret;
+
+ ret = ttm_bo_reserve(bo, false, true, NULL);
+ BUG_ON(ret != 0);
+ ret = vmw_ttm_populate(bo->ttm, &ctx);
+ if (likely(ret == 0)) {
+ struct vmw_ttm_tt *vmw_tt =
+ container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
+ ret = vmw_ttm_map_dma(vmw_tt);
+ }
+
+ ttm_bo_unreserve(bo);
+
+ if (likely(ret == 0))
+ *bo_p = bo;
+ return ret;
+}
diff --git a/drivers/video/fbdev/arcfb.c b/drivers/video/fbdev/arcfb.c
index ae3d8e8b8d33..1447324ed0b6 100644
--- a/drivers/video/fbdev/arcfb.c
+++ b/drivers/video/fbdev/arcfb.c
@@ -419,7 +419,7 @@ static int arcfb_ioctl(struct fb_info *info,
schedule();
finish_wait(&arcfb_waitq, &wait);
}
- fallthrough;
+ fallthrough;
case FBIO_GETCONTROL2:
{
diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c
index bfd2f00b403b..8c1d47e52b1a 100644
--- a/drivers/video/fbdev/atmel_lcdfb.c
+++ b/drivers/video/fbdev/atmel_lcdfb.c
@@ -633,7 +633,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
- case 15:
+ case 15: fallthrough;
case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 6815bfb7f572..cc69649dce95 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -777,7 +777,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (info->fbops->fb_read)
return info->fbops->fb_read(info, buf, count, ppos);
-
+
total_size = info->screen_size;
if (total_size == 0)
@@ -842,7 +842,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (info->fbops->fb_write)
return info->fbops->fb_write(info, buf, count, ppos);
-
+
total_size = info->screen_size;
if (total_size == 0)
@@ -1057,7 +1057,7 @@ EXPORT_SYMBOL(fb_set_var);
int
fb_blank(struct fb_info *info, int blank)
-{
+{
struct fb_event event;
int ret = -EINVAL;
@@ -1433,7 +1433,7 @@ out:
return res;
}
-static int
+static int
fb_release(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
@@ -1623,7 +1623,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
fb_info->pixmap.access_align = 32;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
- }
+ }
fb_info->pixmap.offset = 0;
if (!fb_info->pixmap.blit_x)
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
index 22f1d37a968a..496b43bdad21 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/component.h>
#include <video/omapfb_dss.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
index a06b6f1355bd..e3d441ade241 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
@@ -24,7 +24,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/component.h>
#include <video/omapfb_dss.h>
diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c
index 2d9f69b93392..f4add36cb5f4 100644
--- a/drivers/video/fbdev/pvr2fb.c
+++ b/drivers/video/fbdev/pvr2fb.c
@@ -1028,6 +1028,8 @@ static int __init pvr2fb_setup(char *options)
if (!options || !*options)
return 0;
+ cable_arg[0] = output_arg[0] = 0;
+
while ((this_opt = strsep(&options, ","))) {
if (!*this_opt)
continue;
diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c
index a2442aae7e12..661398e40ff4 100644
--- a/drivers/video/fbdev/savage/savagefb_driver.c
+++ b/drivers/video/fbdev/savage/savagefb_driver.c
@@ -1859,7 +1859,6 @@ static int savage_init_hw(struct savagefb_par *par)
vga_out8(0x3d4, 0x68, par); /* memory control 1 */
if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6))
RamSavage4[1] = 8;
-
fallthrough;
case S3_SAVAGE2000:
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 5c92e4a50882..e76e9b9ba93c 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -126,4 +126,11 @@ config VIRTIO_MMIO_CMDLINE_DEVICES
If unsure, say 'N'.
+config VIRTIO_DMA_SHARED_BUFFER
+ tristate
+ depends on DMA_SHARED_BUFFER
+ help
+ This option adds a flavor of dma buffers that are backed by
+ virtio resources.
+
endif # VIRTIO_MENU
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 4d993791f2d7..591e6f72aa54 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
obj-$(CONFIG_VIRTIO_VDPA) += virtio_vdpa.o
obj-$(CONFIG_VIRTIO_MEM) += virtio_mem.o
+obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) += virtio_dma_buf.o
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index a977e32a88f2..5d46f0ded92d 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -357,6 +357,12 @@ out:
}
EXPORT_SYMBOL_GPL(register_virtio_device);
+bool is_virtio_device(struct device *dev)
+{
+ return dev->bus == &virtio_bus;
+}
+EXPORT_SYMBOL_GPL(is_virtio_device);
+
void unregister_virtio_device(struct virtio_device *dev)
{
int index = dev->index; /* save for after device release */
diff --git a/drivers/virtio/virtio_dma_buf.c b/drivers/virtio/virtio_dma_buf.c
new file mode 100644
index 000000000000..5127a2f0c986
--- /dev/null
+++ b/drivers/virtio/virtio_dma_buf.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * dma-bufs for virtio exported objects
+ *
+ * Copyright (C) 2020 Google, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/virtio_dma_buf.h>
+
+/**
+ * virtio_dma_buf_export - Creates a new dma-buf for a virtio exported object
+ * @exp_info: [in] see dma_buf_export(). ops MUST refer to a dma_buf_ops
+ * struct embedded in a virtio_dma_buf_ops.
+ *
+ * This wraps dma_buf_export() to allow virtio drivers to create a dma-buf
+ * for an virtio exported object that can be queried by other virtio drivers
+ * for the object's UUID.
+ */
+struct dma_buf *virtio_dma_buf_export
+ (const struct dma_buf_export_info *exp_info)
+{
+ const struct virtio_dma_buf_ops *virtio_ops =
+ container_of(exp_info->ops,
+ const struct virtio_dma_buf_ops, ops);
+
+ if (!exp_info->ops ||
+ exp_info->ops->attach != &virtio_dma_buf_attach ||
+ !virtio_ops->get_uuid) {
+ return ERR_PTR(-EINVAL);
+ }
+
+ return dma_buf_export(exp_info);
+}
+EXPORT_SYMBOL(virtio_dma_buf_export);
+
+/**
+ * virtio_dma_buf_attach - mandatory attach callback for virtio dma-bufs
+ */
+int virtio_dma_buf_attach(struct dma_buf *dma_buf,
+ struct dma_buf_attachment *attach)
+{
+ int ret;
+ const struct virtio_dma_buf_ops *ops =
+ container_of(dma_buf->ops,
+ const struct virtio_dma_buf_ops, ops);
+
+ if (ops->device_attach) {
+ ret = ops->device_attach(dma_buf, attach);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(virtio_dma_buf_attach);
+
+/**
+ * is_virtio_dma_buf - returns true if the given dma-buf is a virtio dma-buf
+ * @dma_buf: buffer to query
+ */
+bool is_virtio_dma_buf(struct dma_buf *dma_buf)
+{
+ return dma_buf->ops->attach == &virtio_dma_buf_attach;
+}
+EXPORT_SYMBOL(is_virtio_dma_buf);
+
+/**
+ * virtio_dma_buf_get_uuid - gets a virtio dma-buf's exported object's uuid
+ * @dma_buf: [in] buffer to query
+ * @uuid: [out] the uuid
+ *
+ * Returns: 0 on success, negative on failure.
+ */
+int virtio_dma_buf_get_uuid(struct dma_buf *dma_buf,
+ uuid_t *uuid)
+{
+ const struct virtio_dma_buf_ops *ops =
+ container_of(dma_buf->ops,
+ const struct virtio_dma_buf_ops, ops);
+
+ if (!is_virtio_dma_buf(dma_buf))
+ return -EINVAL;
+
+ return ops->get_uuid(dma_buf, uuid);
+}
+EXPORT_SYMBOL(virtio_dma_buf_get_uuid);
+
+MODULE_LICENSE("GPL");
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index af145608b5ed..928136556174 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1604,10 +1604,13 @@ const char *drm_get_dvi_i_subconnector_name(int val);
const char *drm_get_dvi_i_select_name(int val);
const char *drm_get_tv_subconnector_name(int val);
const char *drm_get_tv_select_name(int val);
+const char *drm_get_dp_subconnector_name(int val);
const char *drm_get_content_protection_name(int val);
const char *drm_get_hdcp_content_type_name(int val);
int drm_mode_create_dvi_i_properties(struct drm_device *dev);
+void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector);
+
int drm_mode_create_tv_margin_properties(struct drm_device *dev);
int drm_mode_create_tv_properties(struct drm_device *dev,
unsigned int num_modes,
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index e47dc22ebf50..5c2819924862 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/types.h>
+#include <drm/drm_connector.h>
/*
* Unless otherwise noted, all values are from the DP 1.1a spec. Note that
@@ -1619,6 +1620,13 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]);
void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
const u8 port_cap[4], struct drm_dp_aux *aux);
+enum drm_mode_subconnector
+drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+ const u8 port_cap[4]);
+void drm_dp_set_subconnector_property(struct drm_connector *connector,
+ enum drm_connector_status status,
+ const u8 *dpcd,
+ const u8 port_cap[4]);
void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
void drm_dp_aux_init(struct drm_dp_aux *aux);
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index c2d3d71d133c..a18f73eb3cf6 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -681,6 +681,12 @@ struct drm_mode_config {
struct drm_property *dvi_i_select_subconnector_property;
/**
+ * @dp_subconnector_property: Optional DP property to differentiate
+ * between different DP downstream port types.
+ */
+ struct drm_property *dp_subconnector_property;
+
+ /**
* @tv_subconnector_property: Optional TV property to differentiate
* between different TV connector types.
*/
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 6193cb555acc..33605c3f0eba 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -35,6 +35,8 @@ struct drm_device;
struct drm_panel;
struct display_timing;
+enum drm_panel_orientation;
+
/**
* struct drm_panel_funcs - perform operations on a given panel
*
@@ -175,12 +177,9 @@ void drm_panel_init(struct drm_panel *panel, struct device *dev,
const struct drm_panel_funcs *funcs,
int connector_type);
-int drm_panel_add(struct drm_panel *panel);
+void drm_panel_add(struct drm_panel *panel);
void drm_panel_remove(struct drm_panel *panel);
-int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector);
-void drm_panel_detach(struct drm_panel *panel);
-
int drm_panel_prepare(struct drm_panel *panel);
int drm_panel_unprepare(struct drm_panel *panel);
@@ -191,11 +190,19 @@ int drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector
#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL)
struct drm_panel *of_drm_find_panel(const struct device_node *np);
+int of_drm_get_panel_orientation(const struct device_node *np,
+ enum drm_panel_orientation *orientation);
#else
static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
{
return ERR_PTR(-ENODEV);
}
+
+static inline int of_drm_get_panel_orientation(const struct device_node *np,
+ enum drm_panel_orientation *orientation)
+{
+ return -ENODEV;
+}
#endif
#if IS_ENABLED(CONFIG_DRM_PANEL) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h
index 96e408b4bdc9..8e7ae30ebcbb 100644
--- a/include/drm/i915_pciids.h
+++ b/include/drm/i915_pciids.h
@@ -258,9 +258,7 @@
INTEL_VGA_DEVICE(0x0f30, info), \
INTEL_VGA_DEVICE(0x0f31, info), \
INTEL_VGA_DEVICE(0x0f32, info), \
- INTEL_VGA_DEVICE(0x0f33, info), \
- INTEL_VGA_DEVICE(0x0157, info), \
- INTEL_VGA_DEVICE(0x0155, info)
+ INTEL_VGA_DEVICE(0x0f33, info)
#define INTEL_BDW_ULT_GT1_IDS(info) \
INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
index a9e13b252820..6c580987ba16 100644
--- a/include/drm/ttm/ttm_bo_api.h
+++ b/include/drm/ttm/ttm_bo_api.h
@@ -42,6 +42,8 @@
#include <linux/bitmap.h>
#include <linux/dma-resv.h>
+#include "ttm_resource.h"
+
struct ttm_bo_global;
struct ttm_bo_device;
@@ -55,55 +57,6 @@ struct ttm_place;
struct ttm_lru_bulk_move;
/**
- * struct ttm_bus_placement
- *
- * @addr: mapped virtual address
- * @base: bus base address
- * @is_iomem: is this io memory ?
- * @size: size in byte
- * @offset: offset from the base address
- * @io_reserved_vm: The VM system has a refcount in @io_reserved_count
- * @io_reserved_count: Refcounting the numbers of callers to ttm_mem_io_reserve
- *
- * Structure indicating the bus placement of an object.
- */
-struct ttm_bus_placement {
- void *addr;
- phys_addr_t base;
- unsigned long size;
- unsigned long offset;
- bool is_iomem;
- bool io_reserved_vm;
- uint64_t io_reserved_count;
-};
-
-
-/**
- * struct ttm_mem_reg
- *
- * @mm_node: Memory manager node.
- * @size: Requested size of memory region.
- * @num_pages: Actual size of memory region in pages.
- * @page_alignment: Page alignment.
- * @placement: Placement flags.
- * @bus: Placement on io bus accessible to the CPU
- *
- * Structure indicating the placement and space resources used by a
- * buffer object.
- */
-
-struct ttm_mem_reg {
- void *mm_node;
- unsigned long start;
- unsigned long size;
- unsigned long num_pages;
- uint32_t page_alignment;
- uint32_t mem_type;
- uint32_t placement;
- struct ttm_bus_placement bus;
-};
-
-/**
* enum ttm_bo_type
*
* @ttm_bo_type_device: These are 'normal' buffers that can
@@ -185,7 +138,7 @@ struct ttm_buffer_object {
* Members protected by the bo::resv::reserved lock.
*/
- struct ttm_mem_reg mem;
+ struct ttm_resource mem;
struct file *persistent_swap_storage;
struct ttm_tt *ttm;
bool evicted;
@@ -314,12 +267,12 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, bool interruptible, bool no_wait);
* ttm_bo_mem_compat - Check if proposed placement is compatible with a bo
*
* @placement: Return immediately if buffer is busy.
- * @mem: The struct ttm_mem_reg indicating the region where the bo resides
+ * @mem: The struct ttm_resource indicating the region where the bo resides
* @new_flags: Describes compatible placement found
*
* Returns true if the placement is compatible
*/
-bool ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_mem_reg *mem,
+bool ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_resource *mem,
uint32_t *new_flags);
/**
@@ -532,52 +485,6 @@ int ttm_bo_create(struct ttm_bo_device *bdev, unsigned long size,
struct ttm_buffer_object **p_bo);
/**
- * ttm_bo_init_mm
- *
- * @bdev: Pointer to a ttm_bo_device struct.
- * @mem_type: The memory type.
- * @p_size: size managed area in pages.
- *
- * Initialize a manager for a given memory type.
- * Note: if part of driver firstopen, it must be protected from a
- * potentially racing lastclose.
- * Returns:
- * -EINVAL: invalid size or memory type.
- * -ENOMEM: Not enough memory.
- * May also return driver-specified errors.
- */
-int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
- unsigned long p_size);
-
-/**
- * ttm_bo_clean_mm
- *
- * @bdev: Pointer to a ttm_bo_device struct.
- * @mem_type: The memory type.
- *
- * Take down a manager for a given memory type after first walking
- * the LRU list to evict any buffers left alive.
- *
- * Normally, this function is part of lastclose() or unload(), and at that
- * point there shouldn't be any buffers left created by user-space, since
- * there should've been removed by the file descriptor release() method.
- * However, before this function is run, make sure to signal all sync objects,
- * and verify that the delayed delete queue is empty. The driver must also
- * make sure that there are no NO_EVICT buffers present in this memory type
- * when the call is made.
- *
- * If this function is part of a VT switch, the caller must make sure that
- * there are no appications currently validating buffers before this
- * function is called. The caller can do that by first taking the
- * struct ttm_bo_device::ttm_lock in write mode.
- *
- * Returns:
- * -EINVAL: invalid or uninitialized memory type.
- * -EBUSY: There are still buffers left in this memory type.
- */
-int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type);
-
-/**
* ttm_bo_evict_mm
*
* @bdev: Pointer to a ttm_bo_device struct.
@@ -713,6 +620,12 @@ static inline bool ttm_bo_uses_embedded_gem_object(struct ttm_buffer_object *bo)
return bo->base.dev != NULL;
}
+int ttm_mem_evict_first(struct ttm_bo_device *bdev,
+ struct ttm_resource_manager *man,
+ const struct ttm_place *place,
+ struct ttm_operation_ctx *ctx,
+ struct ww_acquire_ctx *ticket);
+
/* Default number of pre-faulted pages in the TTM fault handler */
#define TTM_BO_VM_NUM_PREFAULT 16
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index 5a37f1cc057e..bc8d0ebb7568 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -43,171 +43,10 @@
#include "ttm_placement.h"
#include "ttm_tt.h"
-#define TTM_MAX_BO_PRIORITY 4U
-
-#define TTM_MEMTYPE_FLAG_FIXED (1 << 0) /* Fixed (on-card) PCI memory */
-#define TTM_MEMTYPE_FLAG_MAPPABLE (1 << 1) /* Memory mappable */
-
-struct ttm_mem_type_manager;
-
-struct ttm_mem_type_manager_func {
- /**
- * struct ttm_mem_type_manager member init
- *
- * @man: Pointer to a memory type manager.
- * @p_size: Implementation dependent, but typically the size of the
- * range to be managed in pages.
- *
- * Called to initialize a private range manager. The function is
- * expected to initialize the man::priv member.
- * Returns 0 on success, negative error code on failure.
- */
- int (*init)(struct ttm_mem_type_manager *man, unsigned long p_size);
-
- /**
- * struct ttm_mem_type_manager member takedown
- *
- * @man: Pointer to a memory type manager.
- *
- * Called to undo the setup done in init. All allocated resources
- * should be freed.
- */
- int (*takedown)(struct ttm_mem_type_manager *man);
-
- /**
- * struct ttm_mem_type_manager member get_node
- *
- * @man: Pointer to a memory type manager.
- * @bo: Pointer to the buffer object we're allocating space for.
- * @placement: Placement details.
- * @flags: Additional placement flags.
- * @mem: Pointer to a struct ttm_mem_reg to be filled in.
- *
- * This function should allocate space in the memory type managed
- * by @man. Placement details if
- * applicable are given by @placement. If successful,
- * @mem::mm_node should be set to a non-null value, and
- * @mem::start should be set to a value identifying the beginning
- * of the range allocated, and the function should return zero.
- * If the memory region accommodate the buffer object, @mem::mm_node
- * should be set to NULL, and the function should return 0.
- * If a system error occurred, preventing the request to be fulfilled,
- * the function should return a negative error code.
- *
- * Note that @mem::mm_node will only be dereferenced by
- * struct ttm_mem_type_manager functions and optionally by the driver,
- * which has knowledge of the underlying type.
- *
- * This function may not be called from within atomic context, so
- * an implementation can and must use either a mutex or a spinlock to
- * protect any data structures managing the space.
- */
- int (*get_node)(struct ttm_mem_type_manager *man,
- struct ttm_buffer_object *bo,
- const struct ttm_place *place,
- struct ttm_mem_reg *mem);
-
- /**
- * struct ttm_mem_type_manager member put_node
- *
- * @man: Pointer to a memory type manager.
- * @mem: Pointer to a struct ttm_mem_reg to be filled in.
- *
- * This function frees memory type resources previously allocated
- * and that are identified by @mem::mm_node and @mem::start. May not
- * be called from within atomic context.
- */
- void (*put_node)(struct ttm_mem_type_manager *man,
- struct ttm_mem_reg *mem);
-
- /**
- * struct ttm_mem_type_manager member debug
- *
- * @man: Pointer to a memory type manager.
- * @printer: Prefix to be used in printout to identify the caller.
- *
- * This function is called to print out the state of the memory
- * type manager to aid debugging of out-of-memory conditions.
- * It may not be called from within atomic context.
- */
- void (*debug)(struct ttm_mem_type_manager *man,
- struct drm_printer *printer);
-};
-
-/**
- * struct ttm_mem_type_manager
- *
- * @has_type: The memory type has been initialized.
- * @use_type: The memory type is enabled.
- * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory
- * managed by this memory type.
- * @gpu_offset: If used, the GPU offset of the first managed page of
- * fixed memory or the first managed location in an aperture.
- * @size: Size of the managed region.
- * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX,
- * as defined in ttm_placement_common.h
- * @default_caching: The default caching policy used for a buffer object
- * placed in this memory type if the user doesn't provide one.
- * @func: structure pointer implementing the range manager. See above
- * @priv: Driver private closure for @func.
- * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures
- * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions
- * reserved by the TTM vm system.
- * @io_reserve_lru: Optional lru list for unreserving io mem regions.
- * @move_lock: lock for move fence
- * static information. bdev::driver::io_mem_free is never used.
- * @lru: The lru list for this memory type.
- * @move: The fence of the last pipelined move operation.
- *
- * This structure is used to identify and manage memory types for a device.
- * It's set up by the ttm_bo_driver::init_mem_type method.
- */
-
-
-
-struct ttm_mem_type_manager {
- struct ttm_bo_device *bdev;
-
- /*
- * No protection. Constant from start.
- */
-
- bool has_type;
- bool use_type;
- uint32_t flags;
- uint64_t size;
- uint32_t available_caching;
- uint32_t default_caching;
- const struct ttm_mem_type_manager_func *func;
- void *priv;
- struct mutex io_reserve_mutex;
- bool use_io_reserve_lru;
- spinlock_t move_lock;
-
- /*
- * Protected by @io_reserve_mutex:
- */
-
- struct list_head io_reserve_lru;
-
- /*
- * Protected by the global->lru_lock.
- */
-
- struct list_head lru[TTM_MAX_BO_PRIORITY];
-
- /*
- * Protected by @move_lock.
- */
- struct dma_fence *move;
-};
-
/**
* struct ttm_bo_driver
*
* @create_ttm_backend_entry: Callback to create a struct ttm_backend.
- * @init_mem_type: Callback to initialize a struct ttm_mem_type_manager
- * structure.
* @evict_flags: Callback to obtain placement flags when a buffer is evicted.
* @move: Callback for a driver to hook in accelerated functions to
* move a buffer.
@@ -250,9 +89,6 @@ struct ttm_bo_driver {
*/
void (*ttm_tt_unpopulate)(struct ttm_tt *ttm);
- int (*init_mem_type)(struct ttm_bo_device *bdev, uint32_t type,
- struct ttm_mem_type_manager *man);
-
/**
* struct ttm_bo_driver member eviction_valuable
*
@@ -290,7 +126,7 @@ struct ttm_bo_driver {
*/
int (*move)(struct ttm_buffer_object *bo, bool evict,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem);
+ struct ttm_resource *new_mem);
/**
* struct ttm_bo_driver_member verify_access
@@ -316,7 +152,7 @@ struct ttm_bo_driver {
*/
void (*move_notify)(struct ttm_buffer_object *bo,
bool evict,
- struct ttm_mem_reg *new_mem);
+ struct ttm_resource *new_mem);
/* notify the driver we are taking a fault on this BO
* and have reserved it */
int (*fault_reserve_notify)(struct ttm_buffer_object *bo);
@@ -333,9 +169,9 @@ struct ttm_bo_driver {
* are balanced.
*/
int (*io_mem_reserve)(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
void (*io_mem_free)(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
/**
* Return the pfn for a given page_offset inside the BO.
@@ -429,7 +265,7 @@ extern struct ttm_bo_global {
* struct ttm_bo_device - Buffer object driver device-specific data.
*
* @driver: Pointer to a struct ttm_bo_driver struct setup by the driver.
- * @man: An array of mem_type_managers.
+ * @man: An array of resource_managers.
* @vma_manager: Address space manager (pointer)
* lru_lock: Spinlock that protects the buffer+device lru lists and
* ddestroy lists.
@@ -447,8 +283,11 @@ struct ttm_bo_device {
*/
struct list_head device_list;
struct ttm_bo_driver *driver;
- struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES];
-
+ /*
+ * access via ttm_manager_type.
+ */
+ struct ttm_resource_manager sysman;
+ struct ttm_resource_manager *man_drv[TTM_NUM_MEM_TYPES];
/*
* Protected by internal locks.
*/
@@ -476,6 +315,19 @@ struct ttm_bo_device {
bool no_retry;
};
+static inline struct ttm_resource_manager *ttm_manager_type(struct ttm_bo_device *bdev,
+ int mem_type)
+{
+ return bdev->man_drv[mem_type];
+}
+
+static inline void ttm_set_driver_manager(struct ttm_bo_device *bdev,
+ int type,
+ struct ttm_resource_manager *manager)
+{
+ bdev->man_drv[type] = manager;
+}
+
/**
* struct ttm_lru_bulk_move_pos
*
@@ -531,7 +383,7 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask)
* @bo: Pointer to a struct ttm_buffer_object. the data of which
* we want to allocate space for.
* @proposed_placement: Proposed new placement for the buffer object.
- * @mem: A struct ttm_mem_reg.
+ * @mem: A struct ttm_resource.
* @interruptible: Sleep interruptible when sliping.
* @no_wait_gpu: Return immediately if the GPU is busy.
*
@@ -546,11 +398,9 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask)
*/
int ttm_bo_mem_space(struct ttm_buffer_object *bo,
struct ttm_placement *placement,
- struct ttm_mem_reg *mem,
+ struct ttm_resource *mem,
struct ttm_operation_ctx *ctx);
-void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem);
-
int ttm_bo_device_release(struct ttm_bo_device *bdev);
/**
@@ -593,33 +443,34 @@ void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo);
int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo);
void ttm_mem_io_free_vm(struct ttm_buffer_object *bo);
-int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible);
-void ttm_mem_io_unlock(struct ttm_mem_type_manager *man);
+int ttm_mem_io_lock(struct ttm_resource_manager *man, bool interruptible);
+void ttm_mem_io_unlock(struct ttm_resource_manager *man);
/**
- * __ttm_bo_reserve:
+ * ttm_bo_reserve:
*
* @bo: A pointer to a struct ttm_buffer_object.
* @interruptible: Sleep interruptible if waiting.
* @no_wait: Don't sleep while trying to reserve, rather return -EBUSY.
* @ticket: ticket used to acquire the ww_mutex.
*
- * Will not remove reserved buffers from the lru lists.
- * Otherwise identical to ttm_bo_reserve.
+ * Locks a buffer object for validation. (Or prevents other processes from
+ * locking it for validation), while taking a number of measures to prevent
+ * deadlocks.
*
* Returns:
* -EDEADLK: The reservation may cause a deadlock.
* Release all buffer reservations, wait for @bo to become unreserved and
- * try again. (only if use_sequence == 1).
+ * try again.
* -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by
* a signal. Release all buffer reservations and return to user-space.
* -EBUSY: The function needed to sleep, but @no_wait was true
* -EALREADY: Bo already reserved using @ticket. This error code will only
* be returned if @use_ticket is set to true.
*/
-static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo,
- bool interruptible, bool no_wait,
- struct ww_acquire_ctx *ticket)
+static inline int ttm_bo_reserve(struct ttm_buffer_object *bo,
+ bool interruptible, bool no_wait,
+ struct ww_acquire_ctx *ticket)
{
int ret = 0;
@@ -642,59 +493,6 @@ static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo,
}
/**
- * ttm_bo_reserve:
- *
- * @bo: A pointer to a struct ttm_buffer_object.
- * @interruptible: Sleep interruptible if waiting.
- * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY.
- * @ticket: ticket used to acquire the ww_mutex.
- *
- * Locks a buffer object for validation. (Or prevents other processes from
- * locking it for validation) and removes it from lru lists, while taking
- * a number of measures to prevent deadlocks.
- *
- * Deadlocks may occur when two processes try to reserve multiple buffers in
- * different order, either by will or as a result of a buffer being evicted
- * to make room for a buffer already reserved. (Buffers are reserved before
- * they are evicted). The following algorithm prevents such deadlocks from
- * occurring:
- * Processes attempting to reserve multiple buffers other than for eviction,
- * (typically execbuf), should first obtain a unique 32-bit
- * validation sequence number,
- * and call this function with @use_ticket == 1 and @ticket->stamp == the unique
- * sequence number. If upon call of this function, the buffer object is already
- * reserved, the validation sequence is checked against the validation
- * sequence of the process currently reserving the buffer,
- * and if the current validation sequence is greater than that of the process
- * holding the reservation, the function returns -EDEADLK. Otherwise it sleeps
- * waiting for the buffer to become unreserved, after which it retries
- * reserving.
- * The caller should, when receiving an -EDEADLK error
- * release all its buffer reservations, wait for @bo to become unreserved, and
- * then rerun the validation with the same validation sequence. This procedure
- * will always guarantee that the process with the lowest validation sequence
- * will eventually succeed, preventing both deadlocks and starvation.
- *
- * Returns:
- * -EDEADLK: The reservation may cause a deadlock.
- * Release all buffer reservations, wait for @bo to become unreserved and
- * try again. (only if use_sequence == 1).
- * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by
- * a signal. Release all buffer reservations and return to user-space.
- * -EBUSY: The function needed to sleep, but @no_wait was true
- * -EALREADY: Bo already reserved using @ticket. This error code will only
- * be returned if @use_ticket is set to true.
- */
-static inline int ttm_bo_reserve(struct ttm_buffer_object *bo,
- bool interruptible, bool no_wait,
- struct ww_acquire_ctx *ticket)
-{
- WARN_ON(!kref_read(&bo->kref));
-
- return __ttm_bo_reserve(bo, interruptible, no_wait, ticket);
-}
-
-/**
* ttm_bo_reserve_slowpath:
* @bo: A pointer to a struct ttm_buffer_object.
* @interruptible: Sleep interruptible if waiting.
@@ -708,20 +506,22 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo,
bool interruptible,
struct ww_acquire_ctx *ticket)
{
- int ret = 0;
-
- WARN_ON(!kref_read(&bo->kref));
-
- if (interruptible)
- ret = dma_resv_lock_slow_interruptible(bo->base.resv,
- ticket);
- else
- dma_resv_lock_slow(bo->base.resv, ticket);
-
- if (ret == -EINTR)
- ret = -ERESTARTSYS;
+ if (interruptible) {
+ int ret = dma_resv_lock_slow_interruptible(bo->base.resv,
+ ticket);
+ if (ret == -EINTR)
+ ret = -ERESTARTSYS;
+ return ret;
+ }
+ dma_resv_lock_slow(bo->base.resv, ticket);
+ return 0;
+}
- return ret;
+static inline void ttm_bo_move_to_lru_tail_unlocked(struct ttm_buffer_object *bo)
+{
+ spin_lock(&ttm_bo_glob.lru_lock);
+ ttm_bo_move_to_lru_tail(bo, NULL);
+ spin_unlock(&ttm_bo_glob.lru_lock);
}
/**
@@ -733,9 +533,7 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo,
*/
static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo)
{
- spin_lock(&ttm_bo_glob.lru_lock);
- ttm_bo_move_to_lru_tail(bo, NULL);
- spin_unlock(&ttm_bo_glob.lru_lock);
+ ttm_bo_move_to_lru_tail_unlocked(bo);
dma_resv_unlock(bo->base.resv);
}
@@ -744,16 +542,16 @@ static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo)
*/
int ttm_mem_io_reserve(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
void ttm_mem_io_free(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem);
+ struct ttm_resource *mem);
/**
* ttm_bo_move_ttm
*
* @bo: A pointer to a struct ttm_buffer_object.
* @interruptible: Sleep interruptible if waiting.
* @no_wait_gpu: Return immediately if the GPU is busy.
- * @new_mem: struct ttm_mem_reg indicating where to move.
+ * @new_mem: struct ttm_resource indicating where to move.
*
* Optimized move function for a buffer object with both old and
* new placement backed by a TTM. The function will, if successful,
@@ -767,7 +565,7 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev,
int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem);
+ struct ttm_resource *new_mem);
/**
* ttm_bo_move_memcpy
@@ -775,7 +573,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
* @bo: A pointer to a struct ttm_buffer_object.
* @interruptible: Sleep interruptible if waiting.
* @no_wait_gpu: Return immediately if the GPU is busy.
- * @new_mem: struct ttm_mem_reg indicating where to move.
+ * @new_mem: struct ttm_resource indicating where to move.
*
* Fallback move function for a mappable buffer object in mappable memory.
* The function will, if successful,
@@ -789,7 +587,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx,
- struct ttm_mem_reg *new_mem);
+ struct ttm_resource *new_mem);
/**
* ttm_bo_free_old_node
@@ -806,7 +604,7 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo);
* @bo: A pointer to a struct ttm_buffer_object.
* @fence: A fence object that signals when moving is complete.
* @evict: This is an evict move. Don't return until the buffer is idle.
- * @new_mem: struct ttm_mem_reg indicating where to move.
+ * @new_mem: struct ttm_resource indicating where to move.
*
* Accelerated move function to be called when an accelerated move
* has been scheduled. The function will create a new temporary buffer object
@@ -817,7 +615,7 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo);
*/
int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
struct dma_fence *fence, bool evict,
- struct ttm_mem_reg *new_mem);
+ struct ttm_resource *new_mem);
/**
* ttm_bo_pipeline_move.
@@ -825,14 +623,14 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
* @bo: A pointer to a struct ttm_buffer_object.
* @fence: A fence object that signals when moving is complete.
* @evict: This is an evict move. Don't return until the buffer is idle.
- * @new_mem: struct ttm_mem_reg indicating where to move.
+ * @new_mem: struct ttm_resource indicating where to move.
*
* Function for pipelining accelerated moves. Either free the memory
* immediately or hang it on a temporary buffer object.
*/
int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
struct dma_fence *fence, bool evict,
- struct ttm_mem_reg *new_mem);
+ struct ttm_resource *new_mem);
/**
* ttm_bo_pipeline_gutting.
@@ -854,6 +652,35 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo);
*/
pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp);
-extern const struct ttm_mem_type_manager_func ttm_bo_manager_func;
+/**
+ * ttm_range_man_init
+ *
+ * @bdev: ttm device
+ * @type: memory manager type
+ * @available_caching: TTM_PL_FLAG_* for allowed caching modes
+ * @default_caching: default caching mode
+ * @use_tt: if the memory manager uses tt
+ * @p_size: size of area to be managed in pages.
+ *
+ * Initialise a generic range manager for the selected memory type.
+ * The range manager is installed for this device in the type slot.
+ */
+int ttm_range_man_init(struct ttm_bo_device *bdev,
+ unsigned type,
+ uint32_t available_caching,
+ uint32_t default_caching,
+ bool use_tt,
+ unsigned long p_size);
+
+/**
+ * ttm_range_man_fini
+ *
+ * @bdev: ttm device
+ * @type: memory manager type
+ *
+ * Remove the generic range manager from a slot and tear it down.
+ */
+int ttm_range_man_fini(struct ttm_bo_device *bdev,
+ unsigned type);
#endif
diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h
new file mode 100644
index 000000000000..6d4226190480
--- /dev/null
+++ b/include/drm/ttm/ttm_resource.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Christian König
+ */
+
+#ifndef _TTM_RESOURCE_H_
+#define _TTM_RESOURCE_H_
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/dma-fence.h>
+#include <drm/drm_print.h>
+
+#define TTM_MAX_BO_PRIORITY 4U
+
+struct ttm_bo_device;
+struct ttm_resource_manager;
+struct ttm_resource;
+struct ttm_place;
+struct ttm_buffer_object;
+
+struct ttm_resource_manager_func {
+ /**
+ * struct ttm_resource_manager_func member alloc
+ *
+ * @man: Pointer to a memory type manager.
+ * @bo: Pointer to the buffer object we're allocating space for.
+ * @placement: Placement details.
+ * @flags: Additional placement flags.
+ * @mem: Pointer to a struct ttm_resource to be filled in.
+ *
+ * This function should allocate space in the memory type managed
+ * by @man. Placement details if
+ * applicable are given by @placement. If successful,
+ * @mem::mm_node should be set to a non-null value, and
+ * @mem::start should be set to a value identifying the beginning
+ * of the range allocated, and the function should return zero.
+ * If the memory region accommodate the buffer object, @mem::mm_node
+ * should be set to NULL, and the function should return 0.
+ * If a system error occurred, preventing the request to be fulfilled,
+ * the function should return a negative error code.
+ *
+ * Note that @mem::mm_node will only be dereferenced by
+ * struct ttm_resource_manager functions and optionally by the driver,
+ * which has knowledge of the underlying type.
+ *
+ * This function may not be called from within atomic context, so
+ * an implementation can and must use either a mutex or a spinlock to
+ * protect any data structures managing the space.
+ */
+ int (*alloc)(struct ttm_resource_manager *man,
+ struct ttm_buffer_object *bo,
+ const struct ttm_place *place,
+ struct ttm_resource *mem);
+
+ /**
+ * struct ttm_resource_manager_func member free
+ *
+ * @man: Pointer to a memory type manager.
+ * @mem: Pointer to a struct ttm_resource to be filled in.
+ *
+ * This function frees memory type resources previously allocated
+ * and that are identified by @mem::mm_node and @mem::start. May not
+ * be called from within atomic context.
+ */
+ void (*free)(struct ttm_resource_manager *man,
+ struct ttm_resource *mem);
+
+ /**
+ * struct ttm_resource_manager_func member debug
+ *
+ * @man: Pointer to a memory type manager.
+ * @printer: Prefix to be used in printout to identify the caller.
+ *
+ * This function is called to print out the state of the memory
+ * type manager to aid debugging of out-of-memory conditions.
+ * It may not be called from within atomic context.
+ */
+ void (*debug)(struct ttm_resource_manager *man,
+ struct drm_printer *printer);
+};
+
+/**
+ * struct ttm_resource_manager
+ *
+ * @use_type: The memory type is enabled.
+ * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory
+ * managed by this memory type.
+ * @gpu_offset: If used, the GPU offset of the first managed page of
+ * fixed memory or the first managed location in an aperture.
+ * @size: Size of the managed region.
+ * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX,
+ * as defined in ttm_placement_common.h
+ * @default_caching: The default caching policy used for a buffer object
+ * placed in this memory type if the user doesn't provide one.
+ * @func: structure pointer implementing the range manager. See above
+ * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures
+ * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions
+ * reserved by the TTM vm system.
+ * @io_reserve_lru: Optional lru list for unreserving io mem regions.
+ * @move_lock: lock for move fence
+ * static information. bdev::driver::io_mem_free is never used.
+ * @lru: The lru list for this memory type.
+ * @move: The fence of the last pipelined move operation.
+ *
+ * This structure is used to identify and manage memory types for a device.
+ */
+struct ttm_resource_manager {
+ /*
+ * No protection. Constant from start.
+ */
+ bool use_type;
+ bool use_tt;
+ uint64_t size;
+ uint32_t available_caching;
+ uint32_t default_caching;
+ const struct ttm_resource_manager_func *func;
+ struct mutex io_reserve_mutex;
+ bool use_io_reserve_lru;
+ spinlock_t move_lock;
+
+ /*
+ * Protected by @io_reserve_mutex:
+ */
+
+ struct list_head io_reserve_lru;
+
+ /*
+ * Protected by the global->lru_lock.
+ */
+
+ struct list_head lru[TTM_MAX_BO_PRIORITY];
+
+ /*
+ * Protected by @move_lock.
+ */
+ struct dma_fence *move;
+};
+
+/**
+ * struct ttm_bus_placement
+ *
+ * @addr: mapped virtual address
+ * @base: bus base address
+ * @is_iomem: is this io memory ?
+ * @offset: offset from the base address
+ * @io_reserved_vm: The VM system has a refcount in @io_reserved_count
+ * @io_reserved_count: Refcounting the numbers of callers to ttm_mem_io_reserve
+ *
+ * Structure indicating the bus placement of an object.
+ */
+struct ttm_bus_placement {
+ void *addr;
+ phys_addr_t base;
+ unsigned long offset;
+ bool is_iomem;
+ bool io_reserved_vm;
+ uint64_t io_reserved_count;
+};
+
+/**
+ * struct ttm_resource
+ *
+ * @mm_node: Memory manager node.
+ * @size: Requested size of memory region.
+ * @num_pages: Actual size of memory region in pages.
+ * @page_alignment: Page alignment.
+ * @placement: Placement flags.
+ * @bus: Placement on io bus accessible to the CPU
+ *
+ * Structure indicating the placement and space resources used by a
+ * buffer object.
+ */
+struct ttm_resource {
+ void *mm_node;
+ unsigned long start;
+ unsigned long size;
+ unsigned long num_pages;
+ uint32_t page_alignment;
+ uint32_t mem_type;
+ uint32_t placement;
+ struct ttm_bus_placement bus;
+};
+
+/**
+ * ttm_resource_manager_set_used
+ *
+ * @man: A memory manager object.
+ * @used: usage state to set.
+ *
+ * Set the manager in use flag. If disabled the manager is no longer
+ * used for object placement.
+ */
+static inline void
+ttm_resource_manager_set_used(struct ttm_resource_manager *man, bool used)
+{
+ man->use_type = used;
+}
+
+/**
+ * ttm_resource_manager_used
+ *
+ * @man: Manager to get used state for
+ *
+ * Get the in use flag for a manager.
+ * Returns:
+ * true is used, false if not.
+ */
+static inline bool ttm_resource_manager_used(struct ttm_resource_manager *man)
+{
+ return man->use_type;
+}
+
+/**
+ * ttm_resource_manager_cleanup
+ *
+ * @man: A memory manager object.
+ *
+ * Cleanup the move fences from the memory manager object.
+ */
+static inline void
+ttm_resource_manager_cleanup(struct ttm_resource_manager *man)
+{
+ dma_fence_put(man->move);
+ man->move = NULL;
+}
+
+int ttm_resource_alloc(struct ttm_buffer_object *bo,
+ const struct ttm_place *place,
+ struct ttm_resource *res);
+void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource *res);
+
+void ttm_resource_manager_init(struct ttm_resource_manager *man,
+ unsigned long p_size);
+
+int ttm_resource_manager_force_list_clean(struct ttm_bo_device *bdev,
+ struct ttm_resource_manager *man);
+
+void ttm_resource_manager_debug(struct ttm_resource_manager *man,
+ struct drm_printer *p);
+
+#endif
diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h
index 5e2393fe42c6..241cc40839ed 100644
--- a/include/drm/ttm/ttm_tt.h
+++ b/include/drm/ttm/ttm_tt.h
@@ -30,7 +30,7 @@
#include <linux/types.h>
struct ttm_tt;
-struct ttm_mem_reg;
+struct ttm_resource;
struct ttm_buffer_object;
struct ttm_operation_ctx;
@@ -53,14 +53,14 @@ struct ttm_backend_func {
* struct ttm_backend_func member bind
*
* @ttm: Pointer to a struct ttm_tt.
- * @bo_mem: Pointer to a struct ttm_mem_reg describing the
+ * @bo_mem: Pointer to a struct ttm_resource describing the
* memory type and location for binding.
*
* Bind the backend pages into the aperture in the location
* indicated by @bo_mem. This function should be able to handle
* differences between aperture and system page sizes.
*/
- int (*bind) (struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem);
+ int (*bind) (struct ttm_tt *ttm, struct ttm_resource *bo_mem);
/**
* struct ttm_backend_func member unbind
@@ -179,11 +179,11 @@ void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma);
* ttm_ttm_bind:
*
* @ttm: The struct ttm_tt containing backing pages.
- * @bo_mem: The struct ttm_mem_reg identifying the binding location.
+ * @bo_mem: The struct ttm_resource identifying the binding location.
*
* Bind the pages of @ttm to an aperture location identified by @bo_mem
*/
-int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem,
+int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem,
struct ttm_operation_ctx *ctx);
/**
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 850f79e9a7cb..ecfbcc0553a5 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -124,7 +124,7 @@ struct fb_cursor_user {
* Register/unregister for framebuffer events
*/
-/* The resolution of the passed in fb_info about to change */
+/* The resolution of the passed in fb_info about to change */
#define FB_EVENT_MODE_CHANGE 0x01
#ifdef CONFIG_GUMSTIX_AM200EPD
@@ -457,12 +457,12 @@ struct fb_info {
#if IS_ENABLED(CONFIG_FB_BACKLIGHT)
/* assigned backlight device */
- /* set before framebuffer registration,
+ /* set before framebuffer registration,
remove after unregister */
struct backlight_device *bl_dev;
/* Backlight level curve */
- struct mutex bl_curve_mutex;
+ struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
@@ -481,8 +481,8 @@ struct fb_info {
char __iomem *screen_base; /* Virtual address */
char *screen_buffer;
};
- unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
- void *pseudo_palette; /* Fake palette of 16 colors */
+ unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
+ void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* Hardware state i.e suspend */
@@ -585,11 +585,11 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
* `Generic' versions of the frame buffer device operations
*/
-extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var);
-extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var);
+extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var);
+extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var);
extern int fb_blank(struct fb_info *info, int blank);
-extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image);
/*
* Drawing operations where framebuffer is in system RAM
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 1ad5aa3b86d9..47879fc7f75e 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -118,7 +118,7 @@ struct kparam_array
* you can create your own by defining those variables.
*
* Standard types are:
- * byte, short, ushort, int, uint, long, ulong
+ * byte, hexint, short, ushort, int, uint, long, ulong
* charp: a character pointer
* bool: a bool, values 0/1, y/n, Y/N.
* invbool: the above, only sense-reversed (N = true).
@@ -448,6 +448,11 @@ extern int param_set_ullong(const char *val, const struct kernel_param *kp);
extern int param_get_ullong(char *buffer, const struct kernel_param *kp);
#define param_check_ullong(name, p) __param_check(name, p, unsigned long long)
+extern const struct kernel_param_ops param_ops_hexint;
+extern int param_set_hexint(const char *val, const struct kernel_param *kp);
+extern int param_get_hexint(char *buffer, const struct kernel_param *kp);
+#define param_check_hexint(name, p) param_check_uint(name, p)
+
extern const struct kernel_param_ops param_ops_charp;
extern int param_set_charp(const char *val, const struct kernel_param *kp);
extern int param_get_charp(char *buffer, const struct kernel_param *kp);
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index a493eac08393..55ea329fe72a 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -127,6 +127,7 @@ static inline struct virtio_device *dev_to_virtio(struct device *_dev)
void virtio_add_status(struct virtio_device *dev, unsigned int status);
int register_virtio_device(struct virtio_device *dev);
void unregister_virtio_device(struct virtio_device *dev);
+bool is_virtio_device(struct device *dev);
void virtio_break_device(struct virtio_device *dev);
diff --git a/include/linux/virtio_dma_buf.h b/include/linux/virtio_dma_buf.h
new file mode 100644
index 000000000000..a2fdf217ac62
--- /dev/null
+++ b/include/linux/virtio_dma_buf.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * dma-bufs for virtio exported objects
+ *
+ * Copyright (C) 2020 Google, Inc.
+ */
+
+#ifndef _LINUX_VIRTIO_DMA_BUF_H
+#define _LINUX_VIRTIO_DMA_BUF_H
+
+#include <linux/dma-buf.h>
+#include <linux/uuid.h>
+#include <linux/virtio.h>
+
+/**
+ * struct virtio_dma_buf_ops - operations possible on exported object dma-buf
+ * @ops: the base dma_buf_ops. ops.attach MUST be virtio_dma_buf_attach.
+ * @device_attach: [optional] callback invoked by virtio_dma_buf_attach during
+ * all attach operations.
+ * @get_uid: [required] callback to get the uuid of the exported object.
+ */
+struct virtio_dma_buf_ops {
+ struct dma_buf_ops ops;
+ int (*device_attach)(struct dma_buf *dma_buf,
+ struct dma_buf_attachment *attach);
+ int (*get_uuid)(struct dma_buf *dma_buf, uuid_t *uuid);
+};
+
+int virtio_dma_buf_attach(struct dma_buf *dma_buf,
+ struct dma_buf_attachment *attach);
+
+struct dma_buf *virtio_dma_buf_export
+ (const struct dma_buf_export_info *exp_info);
+bool is_virtio_dma_buf(struct dma_buf *dma_buf);
+int virtio_dma_buf_get_uuid(struct dma_buf *dma_buf, uuid_t *uuid);
+
+#endif /* _LINUX_VIRTIO_DMA_BUF_H */
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index deea447e5f22..863eda048265 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -332,14 +332,19 @@ struct drm_mode_get_encoder {
/* This is for connectors with multiple signal types. */
/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
enum drm_mode_subconnector {
- DRM_MODE_SUBCONNECTOR_Automatic = 0,
- DRM_MODE_SUBCONNECTOR_Unknown = 0,
- DRM_MODE_SUBCONNECTOR_DVID = 3,
- DRM_MODE_SUBCONNECTOR_DVIA = 4,
- DRM_MODE_SUBCONNECTOR_Composite = 5,
- DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
- DRM_MODE_SUBCONNECTOR_Component = 8,
- DRM_MODE_SUBCONNECTOR_SCART = 9,
+ DRM_MODE_SUBCONNECTOR_Automatic = 0, /* DVI-I, TV */
+ DRM_MODE_SUBCONNECTOR_Unknown = 0, /* DVI-I, TV, DP */
+ DRM_MODE_SUBCONNECTOR_VGA = 1, /* DP */
+ DRM_MODE_SUBCONNECTOR_DVID = 3, /* DVI-I DP */
+ DRM_MODE_SUBCONNECTOR_DVIA = 4, /* DVI-I */
+ DRM_MODE_SUBCONNECTOR_Composite = 5, /* TV */
+ DRM_MODE_SUBCONNECTOR_SVIDEO = 6, /* TV */
+ DRM_MODE_SUBCONNECTOR_Component = 8, /* TV */
+ DRM_MODE_SUBCONNECTOR_SCART = 9, /* TV */
+ DRM_MODE_SUBCONNECTOR_DisplayPort = 10, /* DP */
+ DRM_MODE_SUBCONNECTOR_HDMIA = 11, /* DP */
+ DRM_MODE_SUBCONNECTOR_Native = 15, /* DP */
+ DRM_MODE_SUBCONNECTOR_Wireless = 18, /* DP */
};
#define DRM_MODE_CONNECTOR_Unknown 0
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 00546062e023..fa1f3d62f9a6 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -619,6 +619,12 @@ typedef struct drm_i915_irq_wait {
*/
#define I915_PARAM_PERF_REVISION 54
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of
+ * timeline syncobj through drm_i915_gem_execbuffer_ext_timeline_fences. See
+ * I915_EXEC_USE_EXTENSIONS.
+ */
+#define I915_PARAM_HAS_EXEC_TIMELINE_FENCES 55
+
/* Must be kept compact -- no holes and well documented */
typedef struct drm_i915_getparam {
@@ -1046,6 +1052,38 @@ struct drm_i915_gem_exec_fence {
__u32 flags;
};
+/**
+ * See drm_i915_gem_execbuffer_ext_timeline_fences.
+ */
+#define DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES 0
+
+/**
+ * This structure describes an array of drm_syncobj and associated points for
+ * timeline variants of drm_syncobj. It is invalid to append this structure to
+ * the execbuf if I915_EXEC_FENCE_ARRAY is set.
+ */
+struct drm_i915_gem_execbuffer_ext_timeline_fences {
+ struct i915_user_extension base;
+
+ /**
+ * Number of element in the handles_ptr & value_ptr arrays.
+ */
+ __u64 fence_count;
+
+ /**
+ * Pointer to an array of struct drm_i915_gem_exec_fence of length
+ * fence_count.
+ */
+ __u64 handles_ptr;
+
+ /**
+ * Pointer to an array of u64 values of length fence_count. Values
+ * must be 0 for a binary drm_syncobj. A Value of 0 for a timeline
+ * drm_syncobj is invalid as it turns a drm_syncobj into a binary one.
+ */
+ __u64 values_ptr;
+};
+
struct drm_i915_gem_execbuffer2 {
/**
* List of gem_exec_object2 structs
@@ -1062,8 +1100,14 @@ struct drm_i915_gem_execbuffer2 {
__u32 num_cliprects;
/**
* This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY
- * is not set. If I915_EXEC_FENCE_ARRAY is set, then this is a
- * struct drm_i915_gem_exec_fence *fences.
+ * & I915_EXEC_USE_EXTENSIONS are not set.
+ *
+ * If I915_EXEC_FENCE_ARRAY is set, then this is a pointer to an array
+ * of struct drm_i915_gem_exec_fence and num_cliprects is the length
+ * of the array.
+ *
+ * If I915_EXEC_USE_EXTENSIONS is set, then this is a pointer to a
+ * single struct i915_user_extension and num_cliprects is 0.
*/
__u64 cliprects_ptr;
#define I915_EXEC_RING_MASK (0x3f)
@@ -1181,7 +1225,16 @@ struct drm_i915_gem_execbuffer2 {
*/
#define I915_EXEC_FENCE_SUBMIT (1 << 20)
-#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SUBMIT << 1))
+/*
+ * Setting I915_EXEC_USE_EXTENSIONS implies that
+ * drm_i915_gem_execbuffer2.cliprects_ptr is treated as a pointer to an linked
+ * list of i915_user_extension. Each i915_user_extension node is the base of a
+ * larger structure. The list of supported structures are listed in the
+ * drm_i915_gem_execbuffer_ext enum.
+ */
+#define I915_EXEC_USE_EXTENSIONS (1 << 21)
+
+#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_USE_EXTENSIONS << 1))
#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff)
#define i915_execbuffer2_set_context_id(eb2, context) \
diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h
index ccbd174ef321..747a5c5cc4e6 100644
--- a/include/uapi/linux/virtio_gpu.h
+++ b/include/uapi/linux/virtio_gpu.h
@@ -50,6 +50,10 @@
* VIRTIO_GPU_CMD_GET_EDID
*/
#define VIRTIO_GPU_F_EDID 1
+/*
+ * VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID
+ */
+#define VIRTIO_GPU_F_RESOURCE_UUID 2
enum virtio_gpu_ctrl_type {
VIRTIO_GPU_UNDEFINED = 0,
@@ -66,6 +70,7 @@ enum virtio_gpu_ctrl_type {
VIRTIO_GPU_CMD_GET_CAPSET_INFO,
VIRTIO_GPU_CMD_GET_CAPSET,
VIRTIO_GPU_CMD_GET_EDID,
+ VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID,
/* 3d commands */
VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
@@ -87,6 +92,7 @@ enum virtio_gpu_ctrl_type {
VIRTIO_GPU_RESP_OK_CAPSET_INFO,
VIRTIO_GPU_RESP_OK_CAPSET,
VIRTIO_GPU_RESP_OK_EDID,
+ VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
/* error responses */
VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
@@ -340,4 +346,17 @@ enum virtio_gpu_formats {
VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
};
+/* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */
+struct virtio_gpu_resource_assign_uuid {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_RESOURCE_UUID */
+struct virtio_gpu_resp_resource_uuid {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __u8 uuid[16];
+};
+
#endif
diff --git a/kernel/params.c b/kernel/params.c
index 8e56f8b12d8f..3835fb82c64b 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -233,14 +233,15 @@ char *parse_args(const char *doing,
EXPORT_SYMBOL(param_ops_##name)
-STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", kstrtou8);
-STANDARD_PARAM_DEF(short, short, "%hi", kstrtos16);
-STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", kstrtou16);
-STANDARD_PARAM_DEF(int, int, "%i", kstrtoint);
-STANDARD_PARAM_DEF(uint, unsigned int, "%u", kstrtouint);
-STANDARD_PARAM_DEF(long, long, "%li", kstrtol);
-STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", kstrtoul);
-STANDARD_PARAM_DEF(ullong, unsigned long long, "%llu", kstrtoull);
+STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", kstrtou8);
+STANDARD_PARAM_DEF(short, short, "%hi", kstrtos16);
+STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", kstrtou16);
+STANDARD_PARAM_DEF(int, int, "%i", kstrtoint);
+STANDARD_PARAM_DEF(uint, unsigned int, "%u", kstrtouint);
+STANDARD_PARAM_DEF(long, long, "%li", kstrtol);
+STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", kstrtoul);
+STANDARD_PARAM_DEF(ullong, unsigned long long, "%llu", kstrtoull);
+STANDARD_PARAM_DEF(hexint, unsigned int, "%#08x", kstrtouint);
int param_set_charp(const char *val, const struct kernel_param *kp)
{