diff --git a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml index 47950fced28d..dafc0980c4fa 100644 --- a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml +++ b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml @@ -36,6 +36,9 @@ properties: resets: maxItems: 1 + vcc-dsi-supply: + description: VCC-DSI power supply of the DSI encoder + phys: maxItems: 1 @@ -64,6 +67,7 @@ required: - phys - phy-names - resets + - vcc-dsi-supply - port additionalProperties: false @@ -79,6 +83,7 @@ examples: resets = <&ccu 4>; phys = <&dphy0>; phy-names = "dphy"; + vcc-dsi-supply = <®_dcdc1>; #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/display/bridge/anx7814.txt b/Documentation/devicetree/bindings/display/bridge/anx7814.txt index dbd7c84ee584..17258747fff6 100644 --- a/Documentation/devicetree/bindings/display/bridge/anx7814.txt +++ b/Documentation/devicetree/bindings/display/bridge/anx7814.txt @@ -6,7 +6,11 @@ designed for portable devices. Required properties: - - compatible : "analogix,anx7814" + - compatible : Must be one of: + "analogix,anx7808" + "analogix,anx7812" + "analogix,anx7814" + "analogix,anx7818" - reg : I2C address of the device - interrupts : Should contain the INTP interrupt - hpd-gpios : Which GPIO to use for hpd diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index b664f054c259..59619296c84b 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -400,16 +400,13 @@ GEM VRAM Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_gem_vram_helper.c :export: -VRAM MM Helper Functions Reference ----------------------------------- +GEM TTM Helper Functions Reference +----------------------------------- -.. kernel-doc:: drivers/gpu/drm/drm_vram_mm_helper.c +.. kernel-doc:: drivers/gpu/drm/drm_gem_ttm_helper.c :doc: overview -.. kernel-doc:: include/drm/drm_vram_mm_helper.h - :internal: - -.. kernel-doc:: drivers/gpu/drm/drm_vram_mm_helper.c +.. kernel-doc:: drivers/gpu/drm/drm_gem_ttm_helper.c :export: VMA Offset Manager diff --git a/Documentation/gpu/mcde.rst b/Documentation/gpu/mcde.rst index c69e977defda..dd43dde379e0 100644 --- a/Documentation/gpu/mcde.rst +++ b/Documentation/gpu/mcde.rst @@ -5,4 +5,4 @@ ======================================================= .. kernel-doc:: drivers/gpu/drm/mcde/mcde_drv.c - :doc: ST-Ericsson MCDE DRM Driver + :doc: ST-Ericsson MCDE Driver diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 32787acff0a8..8dc147c93c9c 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -284,6 +284,18 @@ drm_fb_helper tasks removed: drm_fb_helper_single_add_all_connectors(), drm_fb_helper_add_one_connector() and drm_fb_helper_remove_one_connector(). +connector register/unregister fixes +----------------------------------- + +- For most connectors it's a no-op to call drm_connector_register/unregister + directly from driver code, drm_dev_register/unregister take care of this + already. We can remove all of them. + +- For dp drivers it's a bit more a mess, since we need the connector to be + registered when calling drm_dp_aux_register. Fix this by instead calling + drm_dp_aux_init, and moving the actual registering into a late_register + callback as recommended in the kerneldoc. + Core refactorings ================= diff --git a/MAINTAINERS b/MAINTAINERS index 55199ef7fa74..07ad2f9d2d20 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1272,6 +1272,8 @@ F: Documentation/gpu/afbc.rst ARM MALI PANFROST DRM DRIVER M: Rob Herring M: Tomeu Vizoso +R: Steven Price +R: Alyssa Rosenzweig L: dri-devel@lists.freedesktop.org S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc @@ -5376,12 +5378,22 @@ F: include/linux/vga* DRM DRIVERS FOR ALLWINNER A10 M: Maxime Ripard +M: Chen-Yu Tsai L: dri-devel@lists.freedesktop.org S: Supported F: drivers/gpu/drm/sun4i/ F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt T: git git://anongit.freedesktop.org/drm/drm-misc +DRM DRIVER FOR ALLWINNER DE2 AND DE3 ENGINE +M: Maxime Ripard +M: Chen-Yu Tsai +R: Jernej Skrabec +L: dri-devel@lists.freedesktop.org +S: Supported +F: drivers/gpu/drm/sun4i/sun8i* +T: git git://anongit.freedesktop.org/drm/drm-misc + DRM DRIVERS FOR AMLOGIC SOCS M: Neil Armstrong L: dri-devel@lists.freedesktop.org diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 2c136aee3e79..052a41e2451c 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -273,6 +273,30 @@ void dma_fence_free(struct dma_fence *fence) } EXPORT_SYMBOL(dma_fence_free); +static bool __dma_fence_enable_signaling(struct dma_fence *fence) +{ + bool was_set; + + lockdep_assert_held(fence->lock); + + was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, + &fence->flags); + + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) + return false; + + if (!was_set && fence->ops->enable_signaling) { + trace_dma_fence_enable_signal(fence); + + if (!fence->ops->enable_signaling(fence)) { + dma_fence_signal_locked(fence); + return false; + } + } + + return true; +} + /** * dma_fence_enable_sw_signaling - enable signaling on fence * @fence: the fence to enable @@ -285,19 +309,12 @@ void dma_fence_enable_sw_signaling(struct dma_fence *fence) { unsigned long flags; - if (!test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, - &fence->flags) && - !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) && - fence->ops->enable_signaling) { - trace_dma_fence_enable_signal(fence); + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) + return; - spin_lock_irqsave(fence->lock, flags); - - if (!fence->ops->enable_signaling(fence)) - dma_fence_signal_locked(fence); - - spin_unlock_irqrestore(fence->lock, flags); - } + spin_lock_irqsave(fence->lock, flags); + __dma_fence_enable_signaling(fence); + spin_unlock_irqrestore(fence->lock, flags); } EXPORT_SYMBOL(dma_fence_enable_sw_signaling); @@ -331,7 +348,6 @@ int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb, { unsigned long flags; int ret = 0; - bool was_set; if (WARN_ON(!fence || !func)) return -EINVAL; @@ -343,25 +359,14 @@ int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb, spin_lock_irqsave(fence->lock, flags); - was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, - &fence->flags); - - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) - ret = -ENOENT; - else if (!was_set && fence->ops->enable_signaling) { - trace_dma_fence_enable_signal(fence); - - if (!fence->ops->enable_signaling(fence)) { - dma_fence_signal_locked(fence); - ret = -ENOENT; - } - } - - if (!ret) { + if (__dma_fence_enable_signaling(fence)) { cb->func = func; list_add_tail(&cb->node, &fence->cb_list); - } else + } else { INIT_LIST_HEAD(&cb->node); + ret = -ENOENT; + } + spin_unlock_irqrestore(fence->lock, flags); return ret; @@ -461,7 +466,6 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) struct default_wait_cb cb; unsigned long flags; signed long ret = timeout ? timeout : 1; - bool was_set; if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) return ret; @@ -473,21 +477,9 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) goto out; } - was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, - &fence->flags); - - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) + if (!__dma_fence_enable_signaling(fence)) goto out; - if (!was_set && fence->ops->enable_signaling) { - trace_dma_fence_enable_signal(fence); - - if (!fence->ops->enable_signaling(fence)) { - dma_fence_signal_locked(fence); - goto out; - } - } - if (!timeout) { ret = 0; goto out; diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index 42a8f3f11681..709002515550 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -471,7 +471,7 @@ unlock: if (pfence_excl) *pfence_excl = fence_excl; else if (fence_excl) - shared[++shared_count] = fence_excl; + shared[shared_count++] = fence_excl; if (!shared_count) { kfree(shared); diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index e67c194c2aca..caeef11976e8 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -168,10 +168,16 @@ config DRM_TTM config DRM_VRAM_HELPER tristate depends on DRM - select DRM_TTM help Helpers for VRAM memory management +config DRM_TTM_HELPER + tristate + depends on DRM + select DRM_TTM + help + Helpers for ttm-based gem objects + config DRM_GEM_CMA_HELPER bool depends on DRM diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 82ff826b33cc..9f1c7c486f88 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -33,10 +33,12 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_vram_helper-y := drm_gem_vram_helper.o \ - drm_vram_helper_common.o \ - drm_vram_mm_helper.o + drm_vram_helper_common.o obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o +drm_ttm_helper-y := drm_gem_ttm_helper.o +obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o + drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index ece55c8fa673..d8729285f731 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -217,11 +217,10 @@ amdgpu_connector_update_scratch_regs(struct drm_connector *connector, struct drm_encoder *encoder; const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; bool connected; - int i; best_encoder = connector_funcs->best_encoder(connector); - drm_connector_for_each_possible_encoder(connector, encoder, i) { + drm_connector_for_each_possible_encoder(connector, encoder) { if ((encoder == best_encoder) && (status == connector_status_connected)) connected = true; else @@ -236,9 +235,8 @@ amdgpu_connector_find_encoder(struct drm_connector *connector, int encoder_type) { struct drm_encoder *encoder; - int i; - drm_connector_for_each_possible_encoder(connector, encoder, i) { + drm_connector_for_each_possible_encoder(connector, encoder) { if (encoder->encoder_type == encoder_type) return encoder; } @@ -347,10 +345,9 @@ static struct drm_encoder * amdgpu_connector_best_single_encoder(struct drm_connector *connector) { struct drm_encoder *encoder; - int i; /* pick the first one */ - drm_connector_for_each_possible_encoder(connector, encoder, i) + drm_connector_for_each_possible_encoder(connector, encoder) return encoder; return NULL; @@ -1065,9 +1062,8 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) /* find analog encoder */ if (amdgpu_connector->dac_load_detect) { struct drm_encoder *encoder; - int i; - drm_connector_for_each_possible_encoder(connector, encoder, i) { + drm_connector_for_each_possible_encoder(connector, encoder) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) continue; @@ -1117,9 +1113,8 @@ amdgpu_connector_dvi_encoder(struct drm_connector *connector) { struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct drm_encoder *encoder; - int i; - drm_connector_for_each_possible_encoder(connector, encoder, i) { + drm_connector_for_each_possible_encoder(connector, encoder) { if (amdgpu_connector->use_digital == true) { if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) return encoder; @@ -1134,7 +1129,7 @@ amdgpu_connector_dvi_encoder(struct drm_connector *connector) /* then check use digitial */ /* pick the first one */ - drm_connector_for_each_possible_encoder(connector, encoder, i) + drm_connector_for_each_possible_encoder(connector, encoder) return encoder; return NULL; @@ -1271,9 +1266,8 @@ u16 amdgpu_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *conn { struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; - int i; - drm_connector_for_each_possible_encoder(connector, encoder, i) { + drm_connector_for_each_possible_encoder(connector, encoder) { amdgpu_encoder = to_amdgpu_encoder(encoder); switch (amdgpu_encoder->encoder_id) { @@ -1292,10 +1286,9 @@ static bool amdgpu_connector_encoder_is_hbr2(struct drm_connector *connector) { struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; - int i; bool found = false; - drm_connector_for_each_possible_encoder(connector, encoder, i) { + drm_connector_for_each_possible_encoder(connector, encoder) { amdgpu_encoder = to_amdgpu_encoder(encoder); if (amdgpu_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) found = true; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 6f8aaf655a9f..baf32484b820 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1049,7 +1049,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, } /* Get rid of things like offb */ - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "amdgpudrmfb"); + ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "amdgpudrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index dff41d0a85fe..8e867b8b432f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1731,6 +1731,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) r = ttm_bo_device_init(&adev->mman.bdev, &amdgpu_bo_driver, adev->ddev->anon_inode->i_mapping, + adev->ddev->vma_offset_manager, dma_addressing_limited(adev->dev)); if (r) { DRM_ERROR("failed initializing buffer object driver(%d).\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index c9608ae8643b..e4f94863332c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -260,15 +260,14 @@ static struct drm_encoder * dce_virtual_encoder(struct drm_connector *connector) { struct drm_encoder *encoder; - int i; - drm_connector_for_each_possible_encoder(connector, encoder, i) { + drm_connector_for_each_possible_encoder(connector, encoder) { if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) return encoder; } /* pick the first one */ - drm_connector_for_each_possible_encoder(connector, encoder, i) + drm_connector_for_each_possible_encoder(connector, encoder) return encoder; return NULL; 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 a52f0b13a2c8..c67d3c41db19 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4837,7 +4837,13 @@ static int to_drm_connector_type(enum signal_type st) static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector) { - return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]); + struct drm_encoder *encoder; + + /* There is only one encoder per connector */ + drm_connector_for_each_possible_encoder(connector, encoder) + return encoder; + + return NULL; } static void amdgpu_dm_get_native_mode(struct drm_connector *connector) 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 16218a202b59..5ec14efd4d8c 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 @@ -416,7 +416,7 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, drm_dp_aux_register(&aconnector->dm_dp_aux.aux); drm_dp_cec_register_connector(&aconnector->dm_dp_aux.aux, - aconnector->base.name, dm->adev->dev); + &aconnector->base); aconnector->mst_mgr.cbs = &dm_mst_cbs; drm_dp_mst_topology_mgr_init( &aconnector->mst_mgr, diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c index 98aac743cc26..8fd7094beece 100644 --- a/drivers/gpu/drm/arc/arcpgu_hdmi.c +++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c @@ -5,6 +5,7 @@ * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) */ +#include #include #include #include diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig index cec0639e3aa1..e87ff8623076 100644 --- a/drivers/gpu/drm/arm/display/Kconfig +++ b/drivers/gpu/drm/arm/display/Kconfig @@ -12,3 +12,9 @@ config DRM_KOMEDA Processor driver. It supports the D71 variants of the hardware. If compiled as a module it will be called komeda. + +config DRM_KOMEDA_ERROR_PRINT + bool "Enable komeda error print" + depends on DRM_KOMEDA + help + Choose this option to enable error printing. diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile index 5c3900c2e764..f095a1c68ac7 100644 --- a/drivers/gpu/drm/arm/display/komeda/Makefile +++ b/drivers/gpu/drm/arm/display/komeda/Makefile @@ -22,4 +22,6 @@ komeda-y += \ d71/d71_dev.o \ d71/d71_component.o +komeda-$(CONFIG_DRM_KOMEDA_ERROR_PRINT) += komeda_event.o + obj-$(CONFIG_DRM_KOMEDA) += komeda.o diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c index 55a8cc94808a..c3d29c0b051b 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c @@ -1218,6 +1218,90 @@ int d71_probe_block(struct d71_dev *d71, return err; } +static void d71_gcu_dump(struct d71_dev *d71, struct seq_file *sf) +{ + u32 v[5]; + + seq_puts(sf, "\n------ GCU ------\n"); + + get_values_from_reg(d71->gcu_addr, 0, 3, v); + seq_printf(sf, "GLB_ARCH_ID:\t\t0x%X\n", v[0]); + seq_printf(sf, "GLB_CORE_ID:\t\t0x%X\n", v[1]); + seq_printf(sf, "GLB_CORE_INFO:\t\t0x%X\n", v[2]); + + get_values_from_reg(d71->gcu_addr, 0x10, 1, v); + seq_printf(sf, "GLB_IRQ_STATUS:\t\t0x%X\n", v[0]); + + get_values_from_reg(d71->gcu_addr, 0xA0, 5, v); + seq_printf(sf, "GCU_IRQ_RAW_STATUS:\t0x%X\n", v[0]); + seq_printf(sf, "GCU_IRQ_CLEAR:\t\t0x%X\n", v[1]); + seq_printf(sf, "GCU_IRQ_MASK:\t\t0x%X\n", v[2]); + seq_printf(sf, "GCU_IRQ_STATUS:\t\t0x%X\n", v[3]); + seq_printf(sf, "GCU_STATUS:\t\t0x%X\n", v[4]); + + get_values_from_reg(d71->gcu_addr, 0xD0, 3, v); + seq_printf(sf, "GCU_CONTROL:\t\t0x%X\n", v[0]); + seq_printf(sf, "GCU_CONFIG_VALID0:\t0x%X\n", v[1]); + seq_printf(sf, "GCU_CONFIG_VALID1:\t0x%X\n", v[2]); +} + +static void d71_lpu_dump(struct d71_pipeline *pipe, struct seq_file *sf) +{ + u32 v[6]; + + seq_printf(sf, "\n------ LPU%d ------\n", pipe->base.id); + + dump_block_header(sf, pipe->lpu_addr); + + get_values_from_reg(pipe->lpu_addr, 0xA0, 6, v); + seq_printf(sf, "LPU_IRQ_RAW_STATUS:\t0x%X\n", v[0]); + seq_printf(sf, "LPU_IRQ_CLEAR:\t\t0x%X\n", v[1]); + seq_printf(sf, "LPU_IRQ_MASK:\t\t0x%X\n", v[2]); + seq_printf(sf, "LPU_IRQ_STATUS:\t\t0x%X\n", v[3]); + seq_printf(sf, "LPU_STATUS:\t\t0x%X\n", v[4]); + seq_printf(sf, "LPU_TBU_STATUS:\t\t0x%X\n", v[5]); + + get_values_from_reg(pipe->lpu_addr, 0xC0, 1, v); + seq_printf(sf, "LPU_INFO:\t\t0x%X\n", v[0]); + + get_values_from_reg(pipe->lpu_addr, 0xD0, 3, v); + seq_printf(sf, "LPU_RAXI_CONTROL:\t0x%X\n", v[0]); + seq_printf(sf, "LPU_WAXI_CONTROL:\t0x%X\n", v[1]); + seq_printf(sf, "LPU_TBU_CONTROL:\t0x%X\n", v[2]); +} + +static void d71_dou_dump(struct d71_pipeline *pipe, struct seq_file *sf) +{ + u32 v[5]; + + seq_printf(sf, "\n------ DOU%d ------\n", pipe->base.id); + + dump_block_header(sf, pipe->dou_addr); + + get_values_from_reg(pipe->dou_addr, 0xA0, 5, v); + seq_printf(sf, "DOU_IRQ_RAW_STATUS:\t0x%X\n", v[0]); + seq_printf(sf, "DOU_IRQ_CLEAR:\t\t0x%X\n", v[1]); + seq_printf(sf, "DOU_IRQ_MASK:\t\t0x%X\n", v[2]); + seq_printf(sf, "DOU_IRQ_STATUS:\t\t0x%X\n", v[3]); + seq_printf(sf, "DOU_STATUS:\t\t0x%X\n", v[4]); +} + +static void d71_pipeline_dump(struct komeda_pipeline *pipe, struct seq_file *sf) +{ + struct d71_pipeline *d71_pipe = to_d71_pipeline(pipe); + + d71_lpu_dump(d71_pipe, sf); + d71_dou_dump(d71_pipe, sf); +} + const struct komeda_pipeline_funcs d71_pipeline_funcs = { - .downscaling_clk_check = d71_downscaling_clk_check, + .downscaling_clk_check = d71_downscaling_clk_check, + .dump_register = d71_pipeline_dump, }; + +void d71_dump(struct komeda_dev *mdev, struct seq_file *sf) +{ + struct d71_dev *d71 = mdev->chip_data; + + d71_gcu_dump(d71, sf); +} diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c index d567ab7ed314..822b23a1ce75 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c @@ -195,7 +195,7 @@ d71_irq_handler(struct komeda_dev *mdev, struct komeda_events *evts) if (gcu_status & GLB_IRQ_STATUS_PIPE1) evts->pipes[1] |= get_pipeline_event(d71->pipes[1], gcu_status); - return gcu_status ? IRQ_HANDLED : IRQ_NONE; + return IRQ_RETVAL(gcu_status); } #define ENABLED_GCU_IRQS (GCU_IRQ_CVAL0 | GCU_IRQ_CVAL1 | \ @@ -395,6 +395,22 @@ static int d71_enum_resources(struct komeda_dev *mdev) err = PTR_ERR(pipe); goto err_cleanup; } + + /* D71 HW doesn't update shadow registers when display output + * is turning off, so when we disable all pipeline components + * together with display output disable by one flush or one + * operation, the disable operation updated registers will not + * be flush to or valid in HW, which may leads problem. + * To workaround this problem, introduce a two phase disable. + * Phase1: Disabling components with display is on to make sure + * the disable can be flushed to HW. + * Phase2: Only turn-off display output. + */ + value = KOMEDA_PIPELINE_IMPROCS | + BIT(KOMEDA_COMPONENT_TIMING_CTRLR); + + pipe->standalone_disabled_comps = value; + d71->pipes[i] = to_d71_pipeline(pipe); } @@ -561,17 +577,18 @@ static int d71_disconnect_iommu(struct komeda_dev *mdev) } static const struct komeda_dev_funcs d71_chip_funcs = { - .init_format_table = d71_init_fmt_tbl, - .enum_resources = d71_enum_resources, - .cleanup = d71_cleanup, - .irq_handler = d71_irq_handler, - .enable_irq = d71_enable_irq, - .disable_irq = d71_disable_irq, - .on_off_vblank = d71_on_off_vblank, - .change_opmode = d71_change_opmode, - .flush = d71_flush, - .connect_iommu = d71_connect_iommu, - .disconnect_iommu = d71_disconnect_iommu, + .init_format_table = d71_init_fmt_tbl, + .enum_resources = d71_enum_resources, + .cleanup = d71_cleanup, + .irq_handler = d71_irq_handler, + .enable_irq = d71_enable_irq, + .disable_irq = d71_disable_irq, + .on_off_vblank = d71_on_off_vblank, + .change_opmode = d71_change_opmode, + .flush = d71_flush, + .connect_iommu = d71_connect_iommu, + .disconnect_iommu = d71_disconnect_iommu, + .dump_register = d71_dump, }; const struct komeda_dev_funcs * diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.h b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.h index 84f1878b647d..c7357c2b9e62 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.h +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.h @@ -49,4 +49,6 @@ int d71_probe_block(struct d71_dev *d71, struct block_header *blk, u32 __iomem *reg); void d71_read_block_header(u32 __iomem *reg, struct block_header *blk); +void d71_dump(struct komeda_dev *mdev, struct seq_file *sf); + #endif /* !_D71_DEV_H_ */ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 624d257da20f..75263d8cd0bd 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -5,7 +5,6 @@ * */ #include -#include #include #include @@ -250,23 +249,57 @@ komeda_crtc_atomic_enable(struct drm_crtc *crtc, { komeda_crtc_prepare(to_kcrtc(crtc)); drm_crtc_vblank_on(crtc); + WARN_ON(drm_crtc_vblank_get(crtc)); komeda_crtc_do_flush(crtc, old); } +static void +komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc, + struct completion *input_flip_done) +{ + struct drm_device *drm = kcrtc->base.dev; + struct komeda_dev *mdev = kcrtc->master->mdev; + struct completion *flip_done; + struct completion temp; + int timeout; + + /* if caller doesn't send a flip_done, use a private flip_done */ + if (input_flip_done) { + flip_done = input_flip_done; + } else { + init_completion(&temp); + kcrtc->disable_done = &temp; + flip_done = &temp; + } + + mdev->funcs->flush(mdev, kcrtc->master->id, 0); + + /* wait the flip take affect.*/ + timeout = wait_for_completion_timeout(flip_done, HZ); + if (timeout == 0) { + DRM_ERROR("wait pipe%d flip done timeout\n", kcrtc->master->id); + if (!input_flip_done) { + unsigned long flags; + + spin_lock_irqsave(&drm->event_lock, flags); + kcrtc->disable_done = NULL; + spin_unlock_irqrestore(&drm->event_lock, flags); + } + } +} + static void komeda_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old) { struct komeda_crtc *kcrtc = to_kcrtc(crtc); struct komeda_crtc_state *old_st = to_kcrtc_st(old); - struct komeda_dev *mdev = crtc->dev->dev_private; struct komeda_pipeline *master = kcrtc->master; struct komeda_pipeline *slave = kcrtc->slave; struct completion *disable_done = &crtc->state->commit->flip_done; - struct completion temp; - int timeout; + bool needs_phase2 = false; - DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x.\n", + DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x\n", drm_crtc_index(crtc), old_st->active_pipes, old_st->affected_pipes); @@ -274,7 +307,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc, komeda_pipeline_disable(slave, old->state); if (has_bit(master->id, old_st->active_pipes)) - komeda_pipeline_disable(master, old->state); + needs_phase2 = komeda_pipeline_disable(master, old->state); /* crtc_disable has two scenarios according to the state->active switch. * 1. active -> inactive @@ -293,32 +326,23 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc, * That's also the reason why skip modeset commit in * komeda_crtc_atomic_flush() */ - if (crtc->state->active) { - struct komeda_pipeline_state *pipe_st; - /* clear the old active_comps to zero */ - pipe_st = komeda_pipeline_get_old_state(master, old->state); - pipe_st->active_comps = 0; + disable_done = (needs_phase2 || crtc->state->active) ? + NULL : &crtc->state->commit->flip_done; - init_completion(&temp); - kcrtc->disable_done = &temp; - disable_done = &temp; - } - - mdev->funcs->flush(mdev, master->id, 0); - - /* wait the disable take affect.*/ - timeout = wait_for_completion_timeout(disable_done, HZ); - if (timeout == 0) { - DRM_ERROR("disable pipeline%d timeout.\n", kcrtc->master->id); - if (crtc->state->active) { - unsigned long flags; - - spin_lock_irqsave(&crtc->dev->event_lock, flags); - kcrtc->disable_done = NULL; - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); - } + /* wait phase 1 disable done */ + komeda_crtc_flush_and_wait_for_flip_done(kcrtc, disable_done); + + /* phase 2 */ + if (needs_phase2) { + komeda_pipeline_disable(kcrtc->master, old->state); + + disable_done = crtc->state->active ? + NULL : &crtc->state->commit->flip_done; + + komeda_crtc_flush_and_wait_for_flip_done(kcrtc, disable_done); } + drm_crtc_vblank_put(crtc); drm_crtc_vblank_off(crtc); komeda_crtc_unprepare(kcrtc); } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c index ca64a129c594..937a6d4c4865 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c @@ -25,6 +25,8 @@ static int komeda_register_show(struct seq_file *sf, void *x) struct komeda_dev *mdev = sf->private; int i; + seq_puts(sf, "\n====== Komeda register dump =========\n"); + if (mdev->funcs->dump_register) mdev->funcs->dump_register(mdev, sf); @@ -91,9 +93,19 @@ config_id_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(config_id); +static ssize_t +aclk_hz_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct komeda_dev *mdev = dev_to_mdev(dev); + + return snprintf(buf, PAGE_SIZE, "%lu\n", clk_get_rate(mdev->aclk)); +} +static DEVICE_ATTR_RO(aclk_hz); + static struct attribute *komeda_sysfs_entries[] = { &dev_attr_core_id.attr, &dev_attr_config_id.attr, + &dev_attr_aclk_hz.attr, NULL, }; @@ -216,7 +228,7 @@ struct komeda_dev *komeda_dev_create(struct device *dev) product->product_id, MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id)); err = -ENODEV; - goto err_cleanup; + goto disable_clk; } DRM_INFO("Found ARM Mali-D%x version r%dp%d\n", @@ -229,19 +241,19 @@ struct komeda_dev *komeda_dev_create(struct device *dev) err = mdev->funcs->enum_resources(mdev); if (err) { DRM_ERROR("enumerate display resource failed.\n"); - goto err_cleanup; + goto disable_clk; } err = komeda_parse_dt(dev, mdev); if (err) { DRM_ERROR("parse device tree failed.\n"); - goto err_cleanup; + goto disable_clk; } err = komeda_assemble_pipelines(mdev); if (err) { DRM_ERROR("assemble display pipelines failed.\n"); - goto err_cleanup; + goto disable_clk; } dev->dma_parms = &mdev->dma_parms; @@ -254,11 +266,14 @@ struct komeda_dev *komeda_dev_create(struct device *dev) if (mdev->iommu && mdev->funcs->connect_iommu) { err = mdev->funcs->connect_iommu(mdev); if (err) { + DRM_ERROR("connect iommu failed.\n"); mdev->iommu = NULL; - goto err_cleanup; + goto disable_clk; } } + clk_disable_unprepare(mdev->aclk); + err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group); if (err) { DRM_ERROR("create sysfs group failed.\n"); @@ -271,6 +286,8 @@ struct komeda_dev *komeda_dev_create(struct device *dev) return mdev; +disable_clk: + clk_disable_unprepare(mdev->aclk); err_cleanup: komeda_dev_destroy(mdev); return ERR_PTR(err); @@ -288,8 +305,12 @@ void komeda_dev_destroy(struct komeda_dev *mdev) debugfs_remove_recursive(mdev->debugfs_root); #endif + if (mdev->aclk) + clk_prepare_enable(mdev->aclk); + if (mdev->iommu && mdev->funcs->disconnect_iommu) - mdev->funcs->disconnect_iommu(mdev); + if (mdev->funcs->disconnect_iommu(mdev)) + DRM_ERROR("disconnect iommu failed.\n"); mdev->iommu = NULL; for (i = 0; i < mdev->n_pipelines; i++) { @@ -317,3 +338,47 @@ void komeda_dev_destroy(struct komeda_dev *mdev) devm_kfree(dev, mdev); } + +int komeda_dev_resume(struct komeda_dev *mdev) +{ + int ret = 0; + + clk_prepare_enable(mdev->aclk); + + if (mdev->iommu && mdev->funcs->connect_iommu) { + ret = mdev->funcs->connect_iommu(mdev); + if (ret < 0) { + DRM_ERROR("connect iommu failed.\n"); + goto disable_clk; + } + } + + ret = mdev->funcs->enable_irq(mdev); + +disable_clk: + clk_disable_unprepare(mdev->aclk); + + return ret; +} + +int komeda_dev_suspend(struct komeda_dev *mdev) +{ + int ret = 0; + + clk_prepare_enable(mdev->aclk); + + if (mdev->iommu && mdev->funcs->disconnect_iommu) { + ret = mdev->funcs->disconnect_iommu(mdev); + if (ret < 0) { + DRM_ERROR("disconnect iommu failed.\n"); + goto disable_clk; + } + } + + ret = mdev->funcs->disable_irq(mdev); + +disable_clk: + clk_disable_unprepare(mdev->aclk); + + return ret; +} diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h index d1c86b6174c8..414200233b64 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h @@ -40,6 +40,17 @@ #define KOMEDA_ERR_TTNG BIT_ULL(30) #define KOMEDA_ERR_TTF BIT_ULL(31) +#define KOMEDA_ERR_EVENTS \ + (KOMEDA_EVENT_URUN | KOMEDA_EVENT_IBSY | KOMEDA_EVENT_OVR |\ + KOMEDA_ERR_TETO | KOMEDA_ERR_TEMR | KOMEDA_ERR_TITR |\ + KOMEDA_ERR_CPE | KOMEDA_ERR_CFGE | KOMEDA_ERR_AXIE |\ + KOMEDA_ERR_ACE0 | KOMEDA_ERR_ACE1 | KOMEDA_ERR_ACE2 |\ + KOMEDA_ERR_ACE3 | KOMEDA_ERR_DRIFTTO | KOMEDA_ERR_FRAMETO |\ + KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\ + KOMEDA_ERR_TTNG | KOMEDA_ERR_TTF) + +#define KOMEDA_WARN_EVENTS KOMEDA_ERR_CSCE + /* malidp device id */ enum { MALI_D71 = 0, @@ -207,4 +218,13 @@ void komeda_dev_destroy(struct komeda_dev *mdev); struct komeda_dev *dev_to_mdev(struct device *dev); +#ifdef CONFIG_DRM_KOMEDA_ERROR_PRINT +void komeda_print_events(struct komeda_events *evts); +#else +static inline void komeda_print_events(struct komeda_events *evts) {} +#endif + +int komeda_dev_resume(struct komeda_dev *mdev); +int komeda_dev_suspend(struct komeda_dev *mdev); + #endif /*_KOMEDA_DEV_H_*/ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index 69ace6f9055d..d6c2222c5d33 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "komeda_dev.h" #include "komeda_kms.h" @@ -136,13 +137,40 @@ static const struct of_device_id komeda_of_match[] = { MODULE_DEVICE_TABLE(of, komeda_of_match); +static int __maybe_unused komeda_pm_suspend(struct device *dev) +{ + struct komeda_drv *mdrv = dev_get_drvdata(dev); + struct drm_device *drm = &mdrv->kms->base; + int res; + + res = drm_mode_config_helper_suspend(drm); + + komeda_dev_suspend(mdrv->mdev); + + return res; +} + +static int __maybe_unused komeda_pm_resume(struct device *dev) +{ + struct komeda_drv *mdrv = dev_get_drvdata(dev); + struct drm_device *drm = &mdrv->kms->base; + + komeda_dev_resume(mdrv->mdev); + + return drm_mode_config_helper_resume(drm); +} + +static const struct dev_pm_ops komeda_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) +}; + static struct platform_driver komeda_platform_driver = { .probe = komeda_platform_probe, .remove = komeda_platform_remove, .driver = { .name = "komeda", .of_match_table = komeda_of_match, - .pm = NULL, + .pm = &komeda_pm_ops, }, }; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_event.c b/drivers/gpu/drm/arm/display/komeda/komeda_event.c new file mode 100644 index 000000000000..a36fb86cc054 --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/komeda_event.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) COPYRIGHT 2019 ARM Limited. All rights reserved. + * Author: James.Qian.Wang + * + */ +#include + +#include "komeda_dev.h" + +struct komeda_str { + char *str; + u32 sz; + u32 len; +}; + +/* return 0 on success, < 0 on no space. + */ +static int komeda_sprintf(struct komeda_str *str, const char *fmt, ...) +{ + va_list args; + int num, free_sz; + int err; + + free_sz = str->sz - str->len - 1; + if (free_sz <= 0) + return -ENOSPC; + + va_start(args, fmt); + + num = vsnprintf(str->str + str->len, free_sz, fmt, args); + + va_end(args); + + if (num < free_sz) { + str->len += num; + err = 0; + } else { + str->len = str->sz - 1; + err = -ENOSPC; + } + + return err; +} + +static void evt_sprintf(struct komeda_str *str, u64 evt, const char *msg) +{ + if (evt) + komeda_sprintf(str, msg); +} + +static void evt_str(struct komeda_str *str, u64 events) +{ + if (events == 0ULL) { + komeda_sprintf(str, "None"); + return; + } + + evt_sprintf(str, events & KOMEDA_EVENT_VSYNC, "VSYNC|"); + evt_sprintf(str, events & KOMEDA_EVENT_FLIP, "FLIP|"); + evt_sprintf(str, events & KOMEDA_EVENT_EOW, "EOW|"); + evt_sprintf(str, events & KOMEDA_EVENT_MODE, "OP-MODE|"); + + evt_sprintf(str, events & KOMEDA_EVENT_URUN, "UNDERRUN|"); + evt_sprintf(str, events & KOMEDA_EVENT_OVR, "OVERRUN|"); + + /* GLB error */ + evt_sprintf(str, events & KOMEDA_ERR_MERR, "MERR|"); + evt_sprintf(str, events & KOMEDA_ERR_FRAMETO, "FRAMETO|"); + + /* DOU error */ + evt_sprintf(str, events & KOMEDA_ERR_DRIFTTO, "DRIFTTO|"); + evt_sprintf(str, events & KOMEDA_ERR_FRAMETO, "FRAMETO|"); + evt_sprintf(str, events & KOMEDA_ERR_TETO, "TETO|"); + evt_sprintf(str, events & KOMEDA_ERR_CSCE, "CSCE|"); + + /* LPU errors or events */ + evt_sprintf(str, events & KOMEDA_EVENT_IBSY, "IBSY|"); + evt_sprintf(str, events & KOMEDA_ERR_AXIE, "AXIE|"); + evt_sprintf(str, events & KOMEDA_ERR_ACE0, "ACE0|"); + evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|"); + evt_sprintf(str, events & KOMEDA_ERR_ACE2, "ACE2|"); + evt_sprintf(str, events & KOMEDA_ERR_ACE3, "ACE3|"); + + /* LPU TBU errors*/ + evt_sprintf(str, events & KOMEDA_ERR_TCF, "TCF|"); + evt_sprintf(str, events & KOMEDA_ERR_TTNG, "TTNG|"); + evt_sprintf(str, events & KOMEDA_ERR_TITR, "TITR|"); + evt_sprintf(str, events & KOMEDA_ERR_TEMR, "TEMR|"); + evt_sprintf(str, events & KOMEDA_ERR_TTF, "TTF|"); + + /* CU errors*/ + evt_sprintf(str, events & KOMEDA_ERR_CPE, "COPROC|"); + evt_sprintf(str, events & KOMEDA_ERR_ZME, "ZME|"); + evt_sprintf(str, events & KOMEDA_ERR_CFGE, "CFGE|"); + evt_sprintf(str, events & KOMEDA_ERR_TEMR, "TEMR|"); + + if (str->len > 0 && (str->str[str->len - 1] == '|')) { + str->str[str->len - 1] = 0; + str->len--; + } +} + +static bool is_new_frame(struct komeda_events *a) +{ + return (a->pipes[0] | a->pipes[1]) & + (KOMEDA_EVENT_FLIP | KOMEDA_EVENT_EOW); +} + +void komeda_print_events(struct komeda_events *evts) +{ + u64 print_evts = KOMEDA_ERR_EVENTS; + static bool en_print = true; + + /* reduce the same msg print, only print the first evt for one frame */ + if (evts->global || is_new_frame(evts)) + en_print = true; + if (!en_print) + return; + + if ((evts->global | evts->pipes[0] | evts->pipes[1]) & print_evts) { + char msg[256]; + struct komeda_str str; + + str.str = msg; + str.sz = sizeof(msg); + str.len = 0; + + komeda_sprintf(&str, "gcu: "); + evt_str(&str, evts->global); + komeda_sprintf(&str, ", pipes[0]: "); + evt_str(&str, evts->pipes[0]); + komeda_sprintf(&str, ", pipes[1]: "); + evt_str(&str, evts->pipes[1]); + + DRM_ERROR("err detect: %s\n", msg); + + en_print = false; + } +} diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 8820ce15ce37..d49772de93e0 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -48,6 +48,8 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data) memset(&evts, 0, sizeof(evts)); status = mdev->funcs->irq_handler(mdev, &evts); + komeda_print_events(&evts); + /* Notify the crtc to handle the events */ for (i = 0; i < kms->n_crtcs; i++) komeda_crtc_handle_event(&kms->crtcs[i], &evts); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h index cf5bea578ad9..b322f52ba8f2 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h @@ -389,6 +389,18 @@ struct komeda_pipeline { int id; /** @avail_comps: available components mask of pipeline */ u32 avail_comps; + /** + * @standalone_disabled_comps: + * + * When disable the pipeline, some components can not be disabled + * together with others, but need a sparated and standalone disable. + * The standalone_disabled_comps are the components which need to be + * disabled standalone, and this concept also introduce concept of + * two phase. + * phase 1: for disabling the common components. + * phase 2: for disabling the standalong_disabled_comps. + */ + u32 standalone_disabled_comps; /** @n_layers: the number of layer on @layers */ int n_layers; /** @layers: the pipeline layers */ @@ -535,7 +547,7 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe, struct komeda_pipeline_state * komeda_pipeline_get_old_state(struct komeda_pipeline *pipe, struct drm_atomic_state *state); -void komeda_pipeline_disable(struct komeda_pipeline *pipe, +bool komeda_pipeline_disable(struct komeda_pipeline *pipe, struct drm_atomic_state *old_state); void komeda_pipeline_update(struct komeda_pipeline *pipe, struct drm_atomic_state *old_state); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c index ea26bc9c2d00..0ba9c6aa3708 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -1218,7 +1218,17 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe, return 0; } -void komeda_pipeline_disable(struct komeda_pipeline *pipe, +/* Since standalong disabled components must be disabled separately and in the + * last, So a complete disable operation may needs to call pipeline_disable + * twice (two phase disabling). + * Phase 1: disable the common components, flush it. + * Phase 2: disable the standalone disabled components, flush it. + * + * RETURNS: + * true: disable is not complete, needs a phase 2 disable. + * false: disable is complete. + */ +bool komeda_pipeline_disable(struct komeda_pipeline *pipe, struct drm_atomic_state *old_state) { struct komeda_pipeline_state *old; @@ -1228,9 +1238,14 @@ void komeda_pipeline_disable(struct komeda_pipeline *pipe, old = komeda_pipeline_get_old_state(pipe, old_state); - disabling_comps = old->active_comps; - DRM_DEBUG_ATOMIC("PIPE%d: disabling_comps: 0x%x.\n", - pipe->id, disabling_comps); + disabling_comps = old->active_comps & + (~pipe->standalone_disabled_comps); + if (!disabling_comps) + disabling_comps = old->active_comps & + pipe->standalone_disabled_comps; + + DRM_DEBUG_ATOMIC("PIPE%d: active_comps: 0x%x, disabling_comps: 0x%x.\n", + pipe->id, old->active_comps, disabling_comps); dp_for_each_set_bit(id, disabling_comps) { c = komeda_pipeline_get_component(pipe, id); @@ -1248,6 +1263,13 @@ void komeda_pipeline_disable(struct komeda_pipeline *pipe, c->funcs->disable(c); } + + /* Update the pipeline state, if there are components that are still + * active, return true for calling the phase 2 disable. + */ + old->active_comps &= ~disabling_comps; + + return old->active_comps ? true : false; } void komeda_pipeline_update(struct komeda_pipeline *pipe, diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig index 829620d5326c..fbcf2f45cef5 100644 --- a/drivers/gpu/drm/ast/Kconfig +++ b/drivers/gpu/drm/ast/Kconfig @@ -4,6 +4,8 @@ config DRM_AST depends on DRM && PCI && MMU select DRM_KMS_HELPER select DRM_VRAM_HELPER + select DRM_TTM + select DRM_TTM_HELPER help Say yes for experimental AST GPU driver. Do not enable this driver without having a working -modesetting, diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 6ed6ff49efc0..e0e8770462bc 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -35,7 +35,6 @@ #include #include #include -#include #include "ast_drv.h" diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 244cc7c382af..ff161bd622f3 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -82,6 +82,25 @@ enum ast_tx_chip { #define AST_DRAM_4Gx16 7 #define AST_DRAM_8Gx16 8 + +#define AST_MAX_HWC_WIDTH 64 +#define AST_MAX_HWC_HEIGHT 64 + +#define AST_HWC_SIZE (AST_MAX_HWC_WIDTH * AST_MAX_HWC_HEIGHT * 2) +#define AST_HWC_SIGNATURE_SIZE 32 + +#define AST_DEFAULT_HWC_NUM 2 + +/* define for signature structure */ +#define AST_HWC_SIGNATURE_CHECKSUM 0x00 +#define AST_HWC_SIGNATURE_SizeX 0x04 +#define AST_HWC_SIGNATURE_SizeY 0x08 +#define AST_HWC_SIGNATURE_X 0x0C +#define AST_HWC_SIGNATURE_Y 0x10 +#define AST_HWC_SIGNATURE_HOTSPOTX 0x14 +#define AST_HWC_SIGNATURE_HOTSPOTY 0x18 + + struct ast_private { struct drm_device *dev; @@ -97,8 +116,11 @@ struct ast_private { int fb_mtrr; - struct drm_gem_object *cursor_cache; - int next_cursor; + struct { + struct drm_gem_vram_object *gbo[AST_DEFAULT_HWC_NUM]; + unsigned int next_index; + } cursor; + bool support_wide_screen; enum { ast_use_p2a, @@ -199,23 +221,6 @@ static inline void ast_open_key(struct ast_private *ast) #define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M -#define AST_MAX_HWC_WIDTH 64 -#define AST_MAX_HWC_HEIGHT 64 - -#define AST_HWC_SIZE (AST_MAX_HWC_WIDTH*AST_MAX_HWC_HEIGHT*2) -#define AST_HWC_SIGNATURE_SIZE 32 - -#define AST_DEFAULT_HWC_NUM 2 -/* define for signature structure */ -#define AST_HWC_SIGNATURE_CHECKSUM 0x00 -#define AST_HWC_SIGNATURE_SizeX 0x04 -#define AST_HWC_SIGNATURE_SizeY 0x08 -#define AST_HWC_SIGNATURE_X 0x0C -#define AST_HWC_SIGNATURE_Y 0x10 -#define AST_HWC_SIGNATURE_HOTSPOTX 0x14 -#define AST_HWC_SIGNATURE_HOTSPOTY 0x18 - - struct ast_i2c_chan { struct i2c_adapter adapter; struct drm_device *dev; diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 50de8e47659c..21715d6a9b56 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "ast_drv.h" diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index d349c721501c..b13eaa2619ab 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -687,17 +687,6 @@ static void ast_encoder_destroy(struct drm_encoder *encoder) kfree(encoder); } - -static struct drm_encoder *ast_best_single_encoder(struct drm_connector *connector) -{ - int enc_id = connector->encoder_ids[0]; - /* pick the encoder ids */ - if (enc_id) - return drm_encoder_find(connector->dev, NULL, enc_id); - return NULL; -} - - static const struct drm_encoder_funcs ast_enc_funcs = { .destroy = ast_encoder_destroy, }; @@ -847,7 +836,6 @@ static void ast_connector_destroy(struct drm_connector *connector) static const struct drm_connector_helper_funcs ast_connector_helper_funcs = { .mode_valid = ast_mode_valid, .get_modes = ast_get_modes, - .best_encoder = ast_best_single_encoder, }; static const struct drm_connector_funcs ast_connector_funcs = { @@ -895,50 +883,53 @@ static int ast_connector_init(struct drm_device *dev) static int ast_cursor_init(struct drm_device *dev) { struct ast_private *ast = dev->dev_private; - int size; - int ret; - struct drm_gem_object *obj; + size_t size, i; struct drm_gem_vram_object *gbo; - s64 gpu_addr; - void *base; + int ret; - size = (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE) * AST_DEFAULT_HWC_NUM; + size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); - ret = ast_gem_create(dev, size, true, &obj); - if (ret) - return ret; - gbo = drm_gem_vram_of_gem(obj); - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); - if (ret) - goto fail; - gpu_addr = drm_gem_vram_offset(gbo); - if (gpu_addr < 0) { - drm_gem_vram_unpin(gbo); - ret = (int)gpu_addr; - goto fail; + for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) { + gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, + size, 0, false); + if (IS_ERR(gbo)) { + ret = PTR_ERR(gbo); + goto err_drm_gem_vram_put; + } + ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM | + DRM_GEM_VRAM_PL_FLAG_TOPDOWN); + if (ret) { + drm_gem_vram_put(gbo); + goto err_drm_gem_vram_put; + } + + ast->cursor.gbo[i] = gbo; } - /* kmap the object */ - base = drm_gem_vram_kmap(gbo, true, NULL); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto fail; - } - - ast->cursor_cache = obj; return 0; -fail: + +err_drm_gem_vram_put: + while (i) { + --i; + gbo = ast->cursor.gbo[i]; + drm_gem_vram_unpin(gbo); + drm_gem_vram_put(gbo); + ast->cursor.gbo[i] = NULL; + } return ret; } static void ast_cursor_fini(struct drm_device *dev) { struct ast_private *ast = dev->dev_private; - struct drm_gem_vram_object *gbo = - drm_gem_vram_of_gem(ast->cursor_cache); - drm_gem_vram_kunmap(gbo); - drm_gem_vram_unpin(gbo); - drm_gem_object_put_unlocked(ast->cursor_cache); + size_t i; + struct drm_gem_vram_object *gbo; + + for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) { + gbo = ast->cursor.gbo[i]; + drm_gem_vram_unpin(gbo); + drm_gem_vram_put(gbo); + } } int ast_mode_init(struct drm_device *dev) @@ -1076,23 +1067,6 @@ static void ast_i2c_destroy(struct ast_i2c_chan *i2c) kfree(i2c); } -static void ast_show_cursor(struct drm_crtc *crtc) -{ - struct ast_private *ast = crtc->dev->dev_private; - u8 jreg; - - jreg = 0x2; - /* enable ARGB cursor */ - jreg |= 1; - ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg); -} - -static void ast_hide_cursor(struct drm_crtc *crtc) -{ - struct ast_private *ast = crtc->dev->dev_private; - ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00); -} - static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height) { union { @@ -1149,21 +1123,99 @@ static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height) return csum; } +static int ast_cursor_update(void *dst, void *src, unsigned int width, + unsigned int height) +{ + u32 csum; + + /* do data transfer to cursor cache */ + csum = copy_cursor_image(src, dst, width, height); + + /* write checksum + signature */ + dst += AST_HWC_SIZE; + writel(csum, dst); + writel(width, dst + AST_HWC_SIGNATURE_SizeX); + writel(height, dst + AST_HWC_SIGNATURE_SizeY); + writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX); + writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY); + + return 0; +} + +static void ast_cursor_set_base(struct ast_private *ast, u64 address) +{ + u8 addr0 = (address >> 3) & 0xff; + u8 addr1 = (address >> 11) & 0xff; + u8 addr2 = (address >> 19) & 0xff; + + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, addr0); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, addr1); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, addr2); +} + +static int ast_show_cursor(struct drm_crtc *crtc, void *src, + unsigned int width, unsigned int height) +{ + struct ast_private *ast = crtc->dev->dev_private; + struct ast_crtc *ast_crtc = to_ast_crtc(crtc); + struct drm_gem_vram_object *gbo; + void *dst; + s64 off; + int ret; + u8 jreg; + + gbo = ast->cursor.gbo[ast->cursor.next_index]; + dst = drm_gem_vram_vmap(gbo); + if (IS_ERR(dst)) + return PTR_ERR(dst); + off = drm_gem_vram_offset(gbo); + if (off < 0) { + ret = (int)off; + goto err_drm_gem_vram_vunmap; + } + + ret = ast_cursor_update(dst, src, width, height); + if (ret) + goto err_drm_gem_vram_vunmap; + ast_cursor_set_base(ast, off); + + ast_crtc->offset_x = AST_MAX_HWC_WIDTH - width; + ast_crtc->offset_y = AST_MAX_HWC_WIDTH - height; + + jreg = 0x2; + /* enable ARGB cursor */ + jreg |= 1; + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg); + + ++ast->cursor.next_index; + ast->cursor.next_index %= ARRAY_SIZE(ast->cursor.gbo); + + drm_gem_vram_vunmap(gbo, dst); + + return 0; + +err_drm_gem_vram_vunmap: + drm_gem_vram_vunmap(gbo, dst); + return ret; +} + +static void ast_hide_cursor(struct drm_crtc *crtc) +{ + struct ast_private *ast = crtc->dev->dev_private; + + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00); +} + static int ast_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height) { - struct ast_private *ast = crtc->dev->dev_private; - struct ast_crtc *ast_crtc = to_ast_crtc(crtc); struct drm_gem_object *obj; struct drm_gem_vram_object *gbo; - s64 dst_gpu; - u64 gpu_addr; - u32 csum; + u8 *src; int ret; - u8 *src, *dst; if (!handle) { ast_hide_cursor(crtc); @@ -1179,70 +1231,23 @@ static int ast_cursor_set(struct drm_crtc *crtc, return -ENOENT; } gbo = drm_gem_vram_of_gem(obj); - - ret = drm_gem_vram_pin(gbo, 0); - if (ret) - goto err_drm_gem_object_put_unlocked; - src = drm_gem_vram_kmap(gbo, true, NULL); + src = drm_gem_vram_vmap(gbo); if (IS_ERR(src)) { ret = PTR_ERR(src); - goto err_drm_gem_vram_unpin; + goto err_drm_gem_object_put_unlocked; } - dst = drm_gem_vram_kmap(drm_gem_vram_of_gem(ast->cursor_cache), - false, NULL); - if (IS_ERR(dst)) { - ret = PTR_ERR(dst); - goto err_drm_gem_vram_kunmap; - } - dst_gpu = drm_gem_vram_offset(drm_gem_vram_of_gem(ast->cursor_cache)); - if (dst_gpu < 0) { - ret = (int)dst_gpu; - goto err_drm_gem_vram_kunmap; - } + ret = ast_show_cursor(crtc, src, width, height); + if (ret) + goto err_drm_gem_vram_vunmap; - dst += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor; - - /* do data transfer to cursor cache */ - csum = copy_cursor_image(src, dst, width, height); - - /* write checksum + signature */ - { - struct drm_gem_vram_object *dst_gbo = - drm_gem_vram_of_gem(ast->cursor_cache); - u8 *dst = drm_gem_vram_kmap(dst_gbo, false, NULL); - dst += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE; - writel(csum, dst); - writel(width, dst + AST_HWC_SIGNATURE_SizeX); - writel(height, dst + AST_HWC_SIGNATURE_SizeY); - writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX); - writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY); - - /* set pattern offset */ - gpu_addr = (u64)dst_gpu; - gpu_addr += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor; - gpu_addr >>= 3; - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, gpu_addr & 0xff); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, (gpu_addr >> 8) & 0xff); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, (gpu_addr >> 16) & 0xff); - } - ast_crtc->offset_x = AST_MAX_HWC_WIDTH - width; - ast_crtc->offset_y = AST_MAX_HWC_WIDTH - height; - - ast->next_cursor = (ast->next_cursor + 1) % AST_DEFAULT_HWC_NUM; - - ast_show_cursor(crtc); - - drm_gem_vram_kunmap(gbo); - drm_gem_vram_unpin(gbo); + drm_gem_vram_vunmap(gbo, src); drm_gem_object_put_unlocked(obj); return 0; -err_drm_gem_vram_kunmap: - drm_gem_vram_kunmap(gbo); -err_drm_gem_vram_unpin: - drm_gem_vram_unpin(gbo); +err_drm_gem_vram_vunmap: + drm_gem_vram_vunmap(gbo, src); err_drm_gem_object_put_unlocked: drm_gem_object_put_unlocked(obj); return ret; @@ -1253,12 +1258,17 @@ static int ast_cursor_move(struct drm_crtc *crtc, { struct ast_crtc *ast_crtc = to_ast_crtc(crtc); struct ast_private *ast = crtc->dev->dev_private; + struct drm_gem_vram_object *gbo; int x_offset, y_offset; - u8 *sig; + u8 *dst, *sig; + u8 jreg; - sig = drm_gem_vram_kmap(drm_gem_vram_of_gem(ast->cursor_cache), - false, NULL); - sig += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE; + gbo = ast->cursor.gbo[ast->cursor.next_index]; + dst = drm_gem_vram_vmap(gbo); + if (IS_ERR(dst)) + return PTR_ERR(dst); + + sig = dst + AST_HWC_SIZE; writel(x, sig + AST_HWC_SIGNATURE_X); writel(y, sig + AST_HWC_SIGNATURE_Y); @@ -1281,7 +1291,11 @@ static int ast_cursor_move(struct drm_crtc *crtc, ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07)); /* dummy write to fire HWC */ - ast_show_cursor(crtc); + jreg = 0x02 | + 0x01; /* enable ARGB4444 cursor */ + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg); + + drm_gem_vram_vunmap(gbo, dst); return 0; } diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index c52d92294171..fad34106083a 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -30,7 +30,6 @@ #include #include -#include #include "ast_drv.h" @@ -42,7 +41,7 @@ int ast_mm_init(struct ast_private *ast) vmm = drm_vram_helper_alloc_mm( dev, pci_resource_start(dev->pdev, 0), - ast->vram_size, &drm_gem_vram_mm_funcs); + ast->vram_size); if (IS_ERR(vmm)) { ret = PTR_ERR(vmm); DRM_ERROR("Error initializing VRAM MM; %d\n", ret); diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c index 375fa84c548b..121b62682d80 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c @@ -107,7 +107,8 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) output->encoder.possible_crtcs = 0x1; if (panel) { - bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_Unknown); + bridge = drm_panel_bridge_add_typed(panel, + DRM_MODE_CONNECTOR_Unknown); if (IS_ERR(bridge)) return PTR_ERR(bridge); } diff --git a/drivers/gpu/drm/bochs/Kconfig b/drivers/gpu/drm/bochs/Kconfig index 32b043abb668..7bcdf294fed8 100644 --- a/drivers/gpu/drm/bochs/Kconfig +++ b/drivers/gpu/drm/bochs/Kconfig @@ -4,6 +4,8 @@ config DRM_BOCHS depends on DRM && PCI && MMU select DRM_KMS_HELPER select DRM_VRAM_HELPER + select DRM_TTM + select DRM_TTM_HELPER help Choose this option for qemu. If M is selected the module will be called bochs-drm. diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h index 68483a2fc12c..917767173ee6 100644 --- a/drivers/gpu/drm/bochs/bochs.h +++ b/drivers/gpu/drm/bochs/bochs.h @@ -10,7 +10,6 @@ #include #include #include -#include /* ---------------------------------------------------------------------- */ diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index 770e1625d05e..3b9b0d9bbc14 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -114,7 +114,7 @@ static int bochs_pci_probe(struct pci_dev *pdev, return -ENOMEM; } - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "bochsdrmfb"); + ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "bochsdrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 8f9bb886f7ad..1b74f530b07c 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -11,8 +11,7 @@ int bochs_mm_init(struct bochs_device *bochs) struct drm_vram_mm *vmm; vmm = drm_vram_helper_alloc_mm(bochs->dev, bochs->fb_base, - bochs->fb_size, - &drm_gem_vram_mm_funcs); + bochs->fb_size); return PTR_ERR_OR_ZERO(vmm); } diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index 3c7cc5af735c..31118d385580 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -715,7 +716,9 @@ static int anx78xx_init_pdata(struct anx78xx *anx78xx) /* 1.0V digital core power regulator */ pdata->dvdd10 = devm_regulator_get(dev, "dvdd10"); if (IS_ERR(pdata->dvdd10)) { - DRM_ERROR("DVDD10 regulator not found\n"); + if (PTR_ERR(pdata->dvdd10) != -EPROBE_DEFER) + DRM_ERROR("DVDD10 regulator not found\n"); + return PTR_ERR(pdata->dvdd10); } @@ -1301,6 +1304,7 @@ static const struct regmap_config anx78xx_regmap_config = { }; static const u16 anx78xx_chipid_list[] = { + 0x7808, 0x7812, 0x7814, 0x7818, @@ -1332,7 +1336,9 @@ static int anx78xx_i2c_probe(struct i2c_client *client, err = anx78xx_init_pdata(anx78xx); if (err) { - DRM_ERROR("Failed to initialize pdata: %d\n", err); + if (err != -EPROBE_DEFER) + DRM_ERROR("Failed to initialize pdata: %d\n", err); + return err; } @@ -1350,15 +1356,18 @@ static int anx78xx_i2c_probe(struct i2c_client *client, /* Map slave addresses of ANX7814 */ for (i = 0; i < I2C_NUM_ADDRESSES; i++) { - anx78xx->i2c_dummy[i] = i2c_new_dummy(client->adapter, - anx78xx_i2c_addresses[i] >> 1); - if (!anx78xx->i2c_dummy[i]) { - err = -ENOMEM; - DRM_ERROR("Failed to reserve I2C bus %02x\n", - anx78xx_i2c_addresses[i]); + struct i2c_client *i2c_dummy; + + i2c_dummy = i2c_new_dummy_device(client->adapter, + anx78xx_i2c_addresses[i] >> 1); + if (IS_ERR(i2c_dummy)) { + err = PTR_ERR(i2c_dummy); + DRM_ERROR("Failed to reserve I2C bus %02x: %d\n", + anx78xx_i2c_addresses[i], err); goto err_unregister_i2c; } + anx78xx->i2c_dummy[i] = i2c_dummy; anx78xx->map[i] = devm_regmap_init_i2c(anx78xx->i2c_dummy[i], &anx78xx_regmap_config); if (IS_ERR(anx78xx->map[i])) { @@ -1463,7 +1472,10 @@ MODULE_DEVICE_TABLE(i2c, anx78xx_id); #if IS_ENABLED(CONFIG_OF) static const struct of_device_id anx78xx_match_table[] = { + { .compatible = "analogix,anx7808", }, + { .compatible = "analogix,anx7812", }, { .compatible = "analogix,anx7814", }, + { .compatible = "analogix,anx7818", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, anx78xx_match_table); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 22885dceaa17..bb411fe52ae8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 6166dca6be81..3a5bd4e7fd1e 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -956,7 +956,8 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host, panel = of_drm_find_panel(np); if (!IS_ERR(panel)) { - bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI); + bridge = drm_panel_bridge_add_typed(panel, + DRM_MODE_CONNECTOR_DSI); } else { bridge = of_drm_find_bridge(dev->dev.of_node); if (!bridge) diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index 7aa789c35882..cc33dc411b9e 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c index 2ab2c234f26c..e2132a8d5106 100644 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ b/drivers/gpu/drm/bridge/lvds-encoder.c @@ -106,7 +106,8 @@ static int lvds_encoder_probe(struct platform_device *pdev) } lvds_encoder->panel_bridge = - devm_drm_panel_bridge_add(dev, panel, DRM_MODE_CONNECTOR_LVDS); + devm_drm_panel_bridge_add_typed(dev, panel, + DRM_MODE_CONNECTOR_LVDS); if (IS_ERR(lvds_encoder->panel_bridge)) return PTR_ERR(lvds_encoder->panel_bridge); 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 6e81e5db57f2..e8a49f6146c6 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index d4a1cc5052c3..57ff01339559 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index b12ae3a4c5f1..f4e293e7cf64 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -133,8 +134,6 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { * just calls the appropriate functions from &drm_panel. * * @panel: The drm_panel being wrapped. Must be non-NULL. - * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be - * created. * * For drivers converting from directly using drm_panel: The expected * usage pattern is that during either encoder module probe or DSI @@ -148,11 +147,37 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { * drm_mode_config_cleanup() if the bridge has already been attached), then * drm_panel_bridge_remove() to free it. * + * The connector type is set to @panel->connector_type, which must be set to a + * known type. Calling this function with a panel whose connector type is + * DRM_MODE_CONNECTOR_Unknown will return NULL. + * * See devm_drm_panel_bridge_add() for an automatically manged version of this * function. */ -struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel, - u32 connector_type) +struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel) +{ + if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown)) + return NULL; + + return drm_panel_bridge_add_typed(panel, panel->connector_type); +} +EXPORT_SYMBOL(drm_panel_bridge_add); + +/** + * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with + * an explicit connector type. + * @panel: The drm_panel being wrapped. Must be non-NULL. + * @connector_type: The connector type (DRM_MODE_CONNECTOR_*) + * + * This is just like drm_panel_bridge_add(), but forces the connector type to + * @connector_type instead of infering it from the panel. + * + * This function is deprecated and should not be used in new drivers. Use + * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they + * don't report a connector type. + */ +struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, + u32 connector_type) { struct panel_bridge *panel_bridge; @@ -176,7 +201,7 @@ struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel, return &panel_bridge->bridge; } -EXPORT_SYMBOL(drm_panel_bridge_add); +EXPORT_SYMBOL(drm_panel_bridge_add_typed); /** * drm_panel_bridge_remove - Unregisters and frees a drm_bridge @@ -213,15 +238,38 @@ static void devm_drm_panel_bridge_release(struct device *dev, void *res) * that just calls the appropriate functions from &drm_panel. * @dev: device to tie the bridge lifetime to * @panel: The drm_panel being wrapped. Must be non-NULL. - * @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be - * created. * * This is the managed version of drm_panel_bridge_add() which automatically * calls drm_panel_bridge_remove() when @dev is unbound. */ struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, - struct drm_panel *panel, - u32 connector_type) + struct drm_panel *panel) +{ + if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown)) + return NULL; + + return devm_drm_panel_bridge_add_typed(dev, panel, + panel->connector_type); +} +EXPORT_SYMBOL(devm_drm_panel_bridge_add); + +/** + * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and + * &drm_connector with an explicit connector type. + * @dev: device to tie the bridge lifetime to + * @panel: The drm_panel being wrapped. Must be non-NULL. + * @connector_type: The connector type (DRM_MODE_CONNECTOR_*) + * + * This is just like devm_drm_panel_bridge_add(), but forces the connector type + * to @connector_type instead of infering it from the panel. + * + * This function is deprecated and should not be used in new drivers. Use + * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if + * they don't report a connector type. + */ +struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, + struct drm_panel *panel, + u32 connector_type) { struct drm_bridge **ptr, *bridge; @@ -230,7 +278,7 @@ struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, if (!ptr) return ERR_PTR(-ENOMEM); - bridge = drm_panel_bridge_add(panel, connector_type); + bridge = drm_panel_bridge_add_typed(panel, connector_type); if (!IS_ERR(bridge)) { *ptr = bridge; devres_add(dev, ptr); @@ -240,4 +288,4 @@ struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, return bridge; } -EXPORT_SYMBOL(devm_drm_panel_bridge_add); +EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed); diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index 93c68e2e9484..b7a72dfdcac3 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 38f75ac580df..b70e8c5cf2e1 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index 25d4ad8c7ad6..ad00d841ed9e 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -13,6 +13,7 @@ * Dharam Kumar */ #include +#include #include #include diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index bd3165ee5354..14643923a721 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c index ac1e001d0882..70ab4fbdc23e 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c @@ -285,7 +285,7 @@ static int dw_hdmi_cec_probe(struct platform_device *pdev) ret = cec_register_adapter(cec->adap, pdev->dev.parent); if (ret < 0) { - cec_notifier_cec_adap_unregister(cec->notify); + cec_notifier_cec_adap_unregister(cec->notify, cec->adap); return ret; } @@ -302,7 +302,7 @@ static int dw_hdmi_cec_remove(struct platform_device *pdev) { struct dw_hdmi_cec *cec = platform_get_drvdata(pdev); - cec_notifier_cec_adap_unregister(cec->notify); + cec_notifier_cec_adap_unregister(cec->notify, cec->adap); cec_unregister_adapter(cec->adap); return 0; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index 1d15cf9b6821..20f4f92dd866 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -102,6 +102,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, } dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); + dw_hdmi_set_channel_status(hdmi, hparms->iec.status); dw_hdmi_set_channel_count(hdmi, hparms->channels); dw_hdmi_set_channel_allocation(hdmi, hparms->cea.channel_allocation); @@ -109,6 +110,14 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, hdmi_write(audio, conf0, HDMI_AUD_CONF0); hdmi_write(audio, conf1, HDMI_AUD_CONF1); + return 0; +} + +static int dw_hdmi_i2s_audio_startup(struct device *dev, void *data) +{ + struct dw_hdmi_i2s_audio_data *audio = data; + struct dw_hdmi *hdmi = audio->hdmi; + dw_hdmi_audio_enable(hdmi); return 0; @@ -153,6 +162,7 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, static struct hdmi_codec_ops dw_hdmi_i2s_ops = { .hw_params = dw_hdmi_i2s_hw_params, + .audio_startup = dw_hdmi_i2s_audio_startup, .audio_shutdown = dw_hdmi_i2s_audio_shutdown, .get_eld = dw_hdmi_i2s_get_eld, .get_dai_id = dw_hdmi_i2s_get_dai_id, diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 521d689413c8..a15fbf71b9d7 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include "dw-hdmi-cec.h" #include "dw-hdmi.h" +#define DDC_CI_ADDR 0x37 #define DDC_SEGMENT_ADDR 0x30 #define HDMI_EDID_LEN 512 @@ -398,6 +400,15 @@ static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap, u8 addr = msgs[0].addr; int i, ret = 0; + if (addr == DDC_CI_ADDR) + /* + * The internal I2C controller does not support the multi-byte + * read and write operations needed for DDC/CI. + * TOFIX: Blacklist the DDC/CI address until we filter out + * unsupported I2C operations. + */ + return -EOPNOTSUPP; + dev_dbg(hdmi->dev, "xfer: num: %d, addr: %#x\n", num, addr); for (i = 0; i < num; i++) { @@ -580,6 +591,26 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk) return n; } +/* + * When transmitting IEC60958 linear PCM audio, these registers allow to + * configure the channel status information of all the channel status + * bits in the IEC60958 frame. For the moment this configuration is only + * used when the I2S audio interface, General Purpose Audio (GPA), + * or AHB audio DMA (AHBAUDDMA) interface is active + * (for S/PDIF interface this information comes from the stream). + */ +void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, + u8 *channel_status) +{ + /* + * Set channel status register for frequency and word length. + * Use default values for other registers. + */ + hdmi_writeb(hdmi, channel_status[3], HDMI_FC_AUDSCHNLS7); + hdmi_writeb(hdmi, channel_status[4], HDMI_FC_AUDSCHNLS8); +} +EXPORT_SYMBOL_GPL(dw_hdmi_set_channel_status); + static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, unsigned long pixel_clk, unsigned int sample_rate) { diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h index 6988f12d89d9..fcff5059db24 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h @@ -158,6 +158,8 @@ #define HDMI_FC_SPDDEVICEINF 0x1062 #define HDMI_FC_AUDSCONF 0x1063 #define HDMI_FC_AUDSSTAT 0x1064 +#define HDMI_FC_AUDSCHNLS7 0x106e +#define HDMI_FC_AUDSCHNLS8 0x106f #define HDMI_FC_DATACH0FILL 0x1070 #define HDMI_FC_DATACH1FILL 0x1071 #define HDMI_FC_DATACH2FILL 0x1072 diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 675442bfc1bd..b6e793bb653c 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -316,7 +316,8 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, return ret; if (panel) { - bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI); + bridge = drm_panel_bridge_add_typed(panel, + DRM_MODE_CONNECTOR_DSI); if (IS_ERR(bridge)) return PTR_ERR(bridge); } @@ -981,7 +982,6 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, struct device *dev = &pdev->dev; struct reset_control *apb_rst; struct dw_mipi_dsi *dsi; - struct resource *res; int ret; dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); @@ -997,11 +997,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, } if (!plat_data->base) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return ERR_PTR(-ENODEV); - - dsi->base = devm_ioremap_resource(dev, res); + dsi->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dsi->base)) return ERR_PTR(-ENODEV); diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index 170f162ffa55..db298f550a5a 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -16,6 +16,7 @@ #include