diff --git a/drivers/gpu/drm/phytium/phytium_crtc.c b/drivers/gpu/drm/phytium/phytium_crtc.c index e1464b437e6d3..964c448cdb76a 100644 --- a/drivers/gpu/drm/phytium/phytium_crtc.c +++ b/drivers/gpu/drm/phytium/phytium_crtc.c @@ -348,11 +348,16 @@ static void phytium_crtc_gamma_set(struct drm_crtc *crtc) uint32_t active_line = 0, timeout = 500; int i; + if (!state) + return; + if (state->gamma_lut) { if (WARN((state->gamma_lut->length/sizeof(struct drm_color_lut) != GAMMA_INDEX_MAX), "gamma size is not match\n")) return; lut = (struct drm_color_lut *)state->gamma_lut->data; + if (!lut) + return; config = phytium_readl_reg(priv, group_offset, PHYTIUM_DC_FRAMEBUFFER_CONFIG); if (config & FRAMEBUFFER_OUTPUT) { @@ -360,6 +365,8 @@ static void phytium_crtc_gamma_set(struct drm_crtc *crtc) uint32_t frame_time; uint32_t value_a, value_b; + if (!mode) + return; frame_time = mode->crtc_vtotal * mode->crtc_htotal / mode->crtc_clock; value_b = (frame_time - 2) * mode->crtc_vtotal; local_irq_save(flags); diff --git a/drivers/gpu/drm/phytium/phytium_dp.c b/drivers/gpu/drm/phytium/phytium_dp.c index 1bbd391887f89..c800a7ac83442 100644 --- a/drivers/gpu/drm/phytium/phytium_dp.c +++ b/drivers/gpu/drm/phytium/phytium_dp.c @@ -20,6 +20,7 @@ #include "pe220x_dp.h" #include "phytium_panel.h" #include "phytium_reg.h" +#include "phytium_crtc.h" static void phytium_dp_aux_init(struct phytium_dp_device *phytium_dp); static void handle_plugged_change(struct phytium_dp_device *phytium_dp, bool plugged); @@ -310,19 +311,25 @@ static int phytium_connector_add_common_modes(struct phytium_dp_device *phytium_ static int phytium_connector_get_modes(struct drm_connector *connector) { + struct drm_device *dev = connector->dev; + struct phytium_display_private *priv = dev->dev_private; struct phytium_dp_device *phytium_dp = connector_to_dp_device(connector); struct edid *edid; int ret = 0; - if (phytium_dp->is_edp) + if (phytium_dp->is_edp) { edid = phytium_dp->edp_edid; - else + } else if (priv->info.bmc_mode) { edid = drm_get_edid(connector, &phytium_dp->aux.ddc); + } else { + edid = phytium_dp->detect_edid; + } if (edid && drm_edid_is_valid(edid)) { drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); - phytium_dp->has_audio = drm_detect_monitor_audio(edid); + if (priv->info.bmc_mode) + phytium_dp->has_audio = drm_detect_monitor_audio(edid); phytium_get_native_mode(phytium_dp); if (dc_fake_mode_enable) ret += phytium_connector_add_common_modes(phytium_dp); @@ -331,7 +338,7 @@ static int phytium_connector_get_modes(struct drm_connector *connector) phytium_dp->has_audio = false; } - if (!phytium_dp->is_edp) + if (priv->info.bmc_mode) kfree(edid); return ret; @@ -1723,8 +1730,33 @@ static void phytium_dp_handle_test_request(struct phytium_dp_device *phytium_dp) } +static void phytium_dp_unset_edid(struct drm_connector *connector) +{ + struct phytium_dp_device *phytium_dp = connector_to_dp_device(connector); + + kfree(phytium_dp->detect_edid); + phytium_dp->detect_edid = NULL; + phytium_dp->has_audio = false; +} + +static enum drm_connector_status phytium_dp_set_edid(struct drm_connector *connector) +{ + struct phytium_dp_device *phytium_dp = connector_to_dp_device(connector); + + phytium_dp_unset_edid(connector); + phytium_dp->detect_edid = drm_get_edid(connector, &phytium_dp->aux.ddc); + if (!phytium_dp->detect_edid) + return connector_status_disconnected; + + phytium_dp->has_audio = drm_detect_monitor_audio(phytium_dp->detect_edid); + + return connector_status_connected; +} + static int phytium_dp_long_pulse(struct drm_connector *connector, bool hpd_raw_state) { + struct drm_device *dev = connector->dev; + struct phytium_display_private *priv = dev->dev_private; struct phytium_dp_device *phytium_dp = connector_to_dp_device(connector); enum drm_connector_status status = connector->status; bool video_enable = false; @@ -1759,6 +1791,12 @@ static int phytium_dp_long_pulse(struct drm_connector *connector, bool hpd_raw_s video_enable = phytium_dp_hw_video_is_enable(phytium_dp); phytium_dp_start_link_train(phytium_dp); + if (!priv->info.bmc_mode) { + status = phytium_dp_set_edid(connector); + if (status == connector_status_disconnected) + goto out; + } + if (video_enable) { mdelay(2); phytium_dp_hw_enable_video(phytium_dp); @@ -2177,6 +2215,99 @@ void phytium_dp_adjust_link_train_parameter(struct phytium_dp_device *phytium_dp phytium_dp->link_rate, phytium_dp->link_lane_count); } +static void +phytium_dp_modify_dc_hsync_time(struct phytium_dp_device *phytium_dp) +{ + struct drm_device *dev = NULL; + struct phytium_display_private *priv = NULL; + struct drm_connector *connector = NULL; + struct drm_crtc *crtc = NULL; + struct phytium_crtc *phytium_crtc = NULL; + struct drm_display_mode temp_mode = phytium_dp->mode; + int phys_pipe = 0, back_porch = 0, lines_add = 0; + int config = 0, fifo_value = 0; + uint32_t group_offset; + + dev = phytium_dp->dev; + if (!dev) { + DRM_INFO("%s: dev is null\n", __func__); + return; + } + + priv = dev->dev_private; + if (!priv) { + DRM_INFO("%s: priv is null\n", __func__); + return; + } + + connector = &phytium_dp->connector; + if (!connector) { + DRM_INFO("%s: connector is null\n", __func__); + return; + } + + crtc = connector->state->crtc; + if (!crtc) + return; + + group_offset = priv->dp_reg_base[phytium_dp->port]; + fifo_value = phytium_readl_reg(priv, group_offset, PHYTIUM_DP_DATA_CONTROL); + if (fifo_value != PHYTIUM_DP_DEFAULT_FIFO_VALUE) { + pr_info("fifo value changed,no hsync change\n"); + return; + } + + + DRM_DEBUG_KMS("before modify hdisplay:%d,h_start:%d,h_end:%d,h_total:%d\n", + temp_mode.crtc_hdisplay, temp_mode.crtc_hsync_start, + temp_mode.crtc_hsync_end, temp_mode.crtc_htotal); + + + phytium_crtc = to_phytium_crtc(crtc); + phys_pipe = phytium_crtc->phys_pipe; + group_offset = priv->dc_reg_base[phys_pipe]; + back_porch = temp_mode.crtc_htotal - temp_mode.crtc_hsync_end; + lines_add = phytium_dp->link_lane_count * HSYNC_LANE_COUNT_MULTI - + (temp_mode.crtc_hsync_end - temp_mode.crtc_hsync_start); + + if (lines_add > 0) { + if (lines_add < back_porch) { + temp_mode.crtc_hsync_end += lines_add; + } else { + temp_mode.crtc_hsync_end += (back_porch - HSYNC_MIN_ADJ_OFFSET); + temp_mode.crtc_hsync_start -= + (lines_add - back_porch + HSYNC_MIN_ADJ_OFFSET); + + if (temp_mode.crtc_hsync_start < temp_mode.crtc_hdisplay) + temp_mode.crtc_hsync_start = + temp_mode.crtc_hdisplay + HSYNC_MIN_ADJ_OFFSET; + } + } else { + if ((temp_mode.crtc_hsync_end + lines_add) > temp_mode.crtc_hsync_start) { + temp_mode.crtc_hsync_end += lines_add; + } else { + if ((temp_mode.crtc_hsync_end + lines_add) > temp_mode.crtc_hdisplay) + temp_mode.crtc_hsync_start = temp_mode.crtc_hsync_end + lines_add; + else + temp_mode.crtc_hsync_start = + temp_mode.crtc_hdisplay + HSYNC_MIN_ADJ_OFFSET; + temp_mode.crtc_hsync_end = + temp_mode.crtc_hsync_start + HSYNC_MIN_ADJ_OFFSET; + } + } + + config = ((temp_mode.crtc_hsync_start & HSYNC_START_MASK) << HSYNC_START_SHIFT) + | ((temp_mode.crtc_hsync_end & HSYNC_END_MASK) << HSYNC_END_SHIFT) + | HSYNC_PULSE_ENABLED; + config |= (temp_mode.flags & DRM_MODE_FLAG_PHSYNC) ? 0 : HSYNC_NEGATIVE; + phytium_writel_reg(priv, config, group_offset, PHYTIUM_DC_HSYNC); + + DRM_DEBUG_KMS("after modify hdisplay:%d,h_start:%d,h_end:%d,h_total:%d\n", + temp_mode.crtc_hdisplay, temp_mode.crtc_hsync_start, + temp_mode.crtc_hsync_end, temp_mode.crtc_htotal); + +} + static void phytium_encoder_enable(struct drm_encoder *encoder) { struct phytium_dp_device *phytium_dp = encoder_to_dp_device(encoder); @@ -2198,6 +2329,9 @@ static void phytium_encoder_enable(struct drm_encoder *encoder) mdelay(2); } + if (!phytium_dp->is_edp) + phytium_dp_modify_dc_hsync_time(phytium_dp); + phytium_dp_hw_config_video(phytium_dp); if (ret == 0) { phytium_dp_hw_enable_video(phytium_dp); @@ -2247,12 +2381,6 @@ phytium_encoder_mode_valid(struct drm_encoder *encoder, const struct drm_display (phytium_dp->native_mode.vtotal == mode->vtotal)) return MODE_OK; - if ((mode->hdisplay == 1600) && (mode->vdisplay == 900)) - return MODE_BAD_HVALUE; - - if ((mode->hdisplay == 1024) && (mode->clock > 78000)) - return MODE_BAD_HVALUE; - if ((mode->hdisplay < 640) || (mode->vdisplay < 480)) return MODE_BAD_HVALUE; diff --git a/drivers/gpu/drm/phytium/phytium_dp.h b/drivers/gpu/drm/phytium/phytium_dp.h index b8cc42e010958..00a3dcb6a7375 100644 --- a/drivers/gpu/drm/phytium/phytium_dp.h +++ b/drivers/gpu/drm/phytium/phytium_dp.h @@ -98,6 +98,7 @@ struct phytium_dp_device { uint32_t trigger_train_fail; unsigned char train_set[4]; + struct edid *detect_edid; struct edid *edp_edid; bool has_audio; bool fast_train_support; @@ -145,6 +146,9 @@ enum phytium_dpcd_phy_tp { #define connector_to_dp_device(x) container_of(x, struct phytium_dp_device, connector) #define panel_to_dp_device(x) container_of(x, struct phytium_dp_device, panel) #define train_retry_to_dp_device(x) container_of(x, struct phytium_dp_device, train_retry_work) +#define HSYNC_LANE_COUNT_MULTI 30 +#define HSYNC_MIN_ADJ_OFFSET 1 + void phytium_phy_writel(struct phytium_dp_device *phytium_dp, uint32_t address, uint32_t data); uint32_t phytium_phy_readl(struct phytium_dp_device *phytium_dp, uint32_t address); diff --git a/drivers/gpu/drm/phytium/phytium_gem.c b/drivers/gpu/drm/phytium/phytium_gem.c index 95b6b0360c065..5ced76ce94d55 100644 --- a/drivers/gpu/drm/phytium/phytium_gem.c +++ b/drivers/gpu/drm/phytium/phytium_gem.c @@ -36,7 +36,8 @@ int phytium_memory_pool_alloc(struct phytium_display_private *priv, void **pvadd void phytium_memory_pool_free(struct phytium_display_private *priv, void *vaddr, uint64_t size) { - gen_pool_free(priv->memory_pool, (unsigned long)vaddr, size); + if (priv->memory_pool) + gen_pool_free(priv->memory_pool, (unsigned long)vaddr, size); } int phytium_memory_pool_init(struct device *dev, struct phytium_display_private *priv) @@ -69,7 +70,8 @@ int phytium_memory_pool_init(struct device *dev, struct phytium_display_private void phytium_memory_pool_fini(struct device *dev, struct phytium_display_private *priv) { - gen_pool_destroy(priv->memory_pool); + if (priv->memory_pool) + gen_pool_destroy(priv->memory_pool); } struct sg_table * diff --git a/drivers/gpu/drm/phytium/phytium_pci.c b/drivers/gpu/drm/phytium/phytium_pci.c index d87e216b14091..b899d25fd0bcf 100644 --- a/drivers/gpu/drm/phytium/phytium_pci.c +++ b/drivers/gpu/drm/phytium/phytium_pci.c @@ -327,6 +327,14 @@ static int phytium_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return -1; } +static void phytium_pci_shutdown(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + struct phytium_display_private *priv = dev->dev_private; + + priv->display_shutdown(dev); +} + static void phytium_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); @@ -334,6 +342,7 @@ static void phytium_pci_remove(struct pci_dev *pdev) phytium_dp_hpd_irq_setup(dev, false); cancel_work_sync(&priv->hotplug_work); + phytium_pci_shutdown(pdev); drm_dev_unregister(dev); phytium_pci_vram_fini(pdev, priv); phytium_pci_private_fini(pdev, priv); @@ -344,14 +353,6 @@ static void phytium_pci_remove(struct pci_dev *pdev) drm_dev_put(dev); } -static void phytium_pci_shutdown(struct pci_dev *pdev) -{ - struct drm_device *dev = pci_get_drvdata(pdev); - struct phytium_display_private *priv = dev->dev_private; - - priv->display_shutdown(dev); -} - static int phytium_pci_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); diff --git a/drivers/gpu/drm/phytium/phytium_platform.c b/drivers/gpu/drm/phytium/phytium_platform.c index 059a8555d7dff..f94047a2e5daf 100644 --- a/drivers/gpu/drm/phytium/phytium_platform.c +++ b/drivers/gpu/drm/phytium/phytium_platform.c @@ -290,6 +290,14 @@ static int phytium_platform_probe(struct platform_device *pdev) return -1; } +static void phytium_platform_shutdown(struct platform_device *pdev) +{ + struct drm_device *dev = dev_get_drvdata(&pdev->dev); + struct phytium_display_private *priv = dev->dev_private; + + priv->display_shutdown(dev); +} + static int phytium_platform_remove(struct platform_device *pdev) { struct drm_device *dev = dev_get_drvdata(&pdev->dev); @@ -297,6 +305,7 @@ static int phytium_platform_remove(struct platform_device *pdev) phytium_dp_hpd_irq_setup(dev, false); cancel_work_sync(&priv->hotplug_work); + phytium_platform_shutdown(pdev); drm_dev_unregister(dev); phytium_platform_private_fini(pdev); dev_set_drvdata(&pdev->dev, NULL); @@ -305,14 +314,6 @@ static int phytium_platform_remove(struct platform_device *pdev) return 0; } -static void phytium_platform_shutdown(struct platform_device *pdev) -{ - struct drm_device *dev = dev_get_drvdata(&pdev->dev); - struct phytium_display_private *priv = dev->dev_private; - - priv->display_shutdown(dev); -} - static int phytium_platform_pm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); diff --git a/drivers/gpu/drm/phytium/phytium_reg.h b/drivers/gpu/drm/phytium/phytium_reg.h index e23ac74d4c78c..9aaa3f6a36318 100644 --- a/drivers/gpu/drm/phytium/phytium_reg.h +++ b/drivers/gpu/drm/phytium/phytium_reg.h @@ -239,6 +239,7 @@ #define SCRAMBLER_RESET BIT(0) #define PHYTIUM_DP_SOURCE_CONTROL_STATUS 0x00C4 #define PHYTIUM_DP_DATA_CONTROL 0x00C8 + #define PHYTIUM_DP_DEFAULT_FIFO_VALUE 0x20042004 #define PHYTIUM_DP_CORE_CAPABILITY 0x00F8 #define PHYTIUM_DP_CORE_ID 0x00FC #define PHYTIUM_DP_AUX_COMMAND 0x0100 diff --git a/drivers/gpu/drm/phytium/px210_dp.c b/drivers/gpu/drm/phytium/px210_dp.c index be3c520a3c09d..c9516de1c1135 100644 --- a/drivers/gpu/drm/phytium/px210_dp.c +++ b/drivers/gpu/drm/phytium/px210_dp.c @@ -896,6 +896,9 @@ int px210_dp_hw_reset(struct phytium_dp_device *phytium_dp) uint8_t px210_dp_hw_get_source_lane_count(struct phytium_dp_device *phytium_dp) { + if (source_max_lane_count != 4) + return source_max_lane_count; + return px210_dp_source_lane_count[phytium_dp->port]; }