diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 456 |
1 files changed, 295 insertions, 161 deletions
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 1ce4c98385e3..ae512ecb65ee 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -61,7 +61,8 @@ #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #include "soc15_common.h" #endif @@ -319,6 +320,7 @@ static void dm_crtc_high_irq(void *interrupt_params) crtc_index = acrtc->crtc_id; drm_handle_vblank(adev->ddev, crtc_index); + amdgpu_dm_crtc_handle_crc_irq(&acrtc->base); } static int dm_set_clockgating_state(void *handle, @@ -345,23 +347,43 @@ static void hotplug_notify_work_func(struct work_struct *work) } #if defined(CONFIG_DRM_AMD_DC_FBC) -#include "dal_asic_id.h" /* Allocate memory for FBC compressed data */ -/* TODO: Dynamic allocation */ -#define AMDGPU_FBC_SIZE (3840 * 2160 * 4) - -static void amdgpu_dm_initialize_fbc(struct amdgpu_device *adev) +static void amdgpu_dm_fbc_init(struct drm_connector *connector) { - int r; + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = dev->dev_private; struct dm_comressor_info *compressor = &adev->dm.compressor; + struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector); + struct drm_display_mode *mode; + unsigned long max_size = 0; + + if (adev->dm.dc->fbc_compressor == NULL) + return; + + if (aconn->dc_link->connector_signal != SIGNAL_TYPE_EDP) + return; + + if (compressor->bo_ptr) + return; - if (!compressor->bo_ptr) { - r = amdgpu_bo_create_kernel(adev, AMDGPU_FBC_SIZE, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &compressor->bo_ptr, - &compressor->gpu_addr, &compressor->cpu_addr); + + list_for_each_entry(mode, &connector->modes, head) { + if (max_size < mode->htotal * mode->vtotal) + max_size = mode->htotal * mode->vtotal; + } + + if (max_size) { + int r = amdgpu_bo_create_kernel(adev, max_size * 4, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, &compressor->bo_ptr, + &compressor->gpu_addr, &compressor->cpu_addr); if (r) - DRM_ERROR("DM: Failed to initialize fbc\n"); + DRM_ERROR("DM: Failed to initialize FBC\n"); + else { + adev->dm.dc->ctx->fbc_gpu_addr = compressor->gpu_addr; + DRM_INFO("DM: FBC alloc %lu\n", max_size*4); + } + } } @@ -381,12 +403,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) /* Zero all the fields */ memset(&init_data, 0, sizeof(init_data)); - /* initialize DAL's lock (for SYNC context use) */ - spin_lock_init(&adev->dm.dal_lock); - - /* initialize DAL's mutex */ - mutex_init(&adev->dm.dal_mutex); - if(amdgpu_dm_irq_init(adev)) { DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n"); goto error; @@ -397,7 +413,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.asic_id.pci_revision_id = adev->rev_id; init_data.asic_id.hw_internal_rev = adev->external_rev_id; - init_data.asic_id.vram_width = adev->mc.vram_width; + init_data.asic_id.vram_width = adev->gmc.vram_width; /* TODO: initialize init_data.asic_id.vram_type here!!!! */ init_data.asic_id.atombios_base_address = adev->mode_info.atom_context->bios; @@ -422,11 +438,14 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) else init_data.log_mask = DC_MIN_LOG_MASK; -#if defined(CONFIG_DRM_AMD_DC_FBC) - if (adev->family == FAMILY_CZ) - amdgpu_dm_initialize_fbc(adev); - init_data.fbc_gpu_addr = adev->dm.compressor.gpu_addr; -#endif + /* + * TODO debug why this doesn't work on Raven + */ + if (adev->flags & AMD_IS_APU && + adev->asic_type >= CHIP_CARRIZO && + adev->asic_type < CHIP_RAVEN) + init_data.flags.gpu_vm_support = true; + /* Display Core create. */ adev->dm.dc = dc_create(&init_data); @@ -447,6 +466,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) DRM_DEBUG_DRIVER("amdgpu: freesync_module init done %p.\n", adev->dm.freesync_module); + amdgpu_dm_init_color_mod(); + if (amdgpu_dm_initialize_drm_device(adev)) { DRM_ERROR( "amdgpu: failed to initialize sw for display support.\n"); @@ -540,9 +561,9 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev) static int dm_late_init(void *handle) { - struct drm_device *dev = ((struct amdgpu_device *)handle)->ddev; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; - return detect_mst_link_for_all_connectors(dev); + return detect_mst_link_for_all_connectors(adev->ddev); } static void s3_handle_mst(struct drm_device *dev, bool suspend) @@ -629,11 +650,13 @@ static int dm_resume(void *handle) { struct amdgpu_device *adev = handle; struct amdgpu_display_manager *dm = &adev->dm; + int ret = 0; /* power on hardware */ dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0); - return 0; + ret = amdgpu_dm_display_resume(adev); + return ret; } int amdgpu_dm_display_resume(struct amdgpu_device *adev) @@ -791,7 +814,7 @@ dm_atomic_state_alloc_free(struct drm_atomic_state *state) } static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = { - .fb_create = amdgpu_user_framebuffer_create, + .fb_create = amdgpu_display_user_framebuffer_create, .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = amdgpu_dm_atomic_check, .atomic_commit = amdgpu_dm_atomic_commit, @@ -1035,6 +1058,10 @@ static void handle_hpd_rx_irq(void *param) !is_mst_root_connector) { /* Downstream Port status changed. */ if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { + + if (aconnector->fake_enable) + aconnector->fake_enable = false; + amdgpu_dm_update_connector_after_detect(aconnector); @@ -1104,7 +1131,7 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) if (adev->asic_type == CHIP_VEGA10 || adev->asic_type == CHIP_RAVEN) - client_id = AMDGPU_IH_CLIENTID_DCE; + client_id = SOC15_IH_CLIENTID_DCE; int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; @@ -1204,7 +1231,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP; i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1; i++) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, i, &adev->crtc_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq); if (r) { DRM_ERROR("Failed to add crtc irq id!\n"); @@ -1228,7 +1255,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT; i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + adev->mode_info.num_crtc - 1; i++) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, i, &adev->pageflip_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq); if (r) { DRM_ERROR("Failed to add page flip irq id!\n"); return r; @@ -1249,7 +1276,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) } /* HPD */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, &adev->hpd_irq); if (r) { DRM_ERROR("Failed to add hpd irq id!\n"); @@ -1279,9 +1306,9 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) /* indicate support of immediate flip */ adev->ddev->mode_config.async_page_flip = true; - adev->ddev->mode_config.fb_base = adev->mc.aper_base; + adev->ddev->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_modeset_create_props(adev); + r = amdgpu_display_modeset_create_props(adev); if (r) return r; @@ -1338,6 +1365,43 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) #endif +static int initialize_plane(struct amdgpu_display_manager *dm, + struct amdgpu_mode_info *mode_info, + int plane_id) +{ + struct amdgpu_plane *plane; + unsigned long possible_crtcs; + int ret = 0; + + plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL); + mode_info->planes[plane_id] = plane; + + if (!plane) { + DRM_ERROR("KMS: Failed to allocate plane\n"); + return -ENOMEM; + } + plane->base.type = mode_info->plane_type[plane_id]; + + /* + * HACK: IGT tests expect that each plane can only have one + * one possible CRTC. For now, set one CRTC for each + * plane that is not an underlay, but still allow multiple + * CRTCs for underlay planes. + */ + possible_crtcs = 1 << plane_id; + if (plane_id >= dm->dc->caps.max_streams) + possible_crtcs = 0xff; + + ret = amdgpu_dm_plane_init(dm, mode_info->planes[plane_id], possible_crtcs); + + if (ret) { + DRM_ERROR("KMS: Failed to initialize plane\n"); + return ret; + } + + return ret; +} + /* In this architecture, the association * connector -> encoder -> crtc * id not really requried. The crtc and connector will hold the @@ -1348,12 +1412,12 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) { struct amdgpu_display_manager *dm = &adev->dm; - uint32_t i; + int32_t i; struct amdgpu_dm_connector *aconnector = NULL; struct amdgpu_encoder *aencoder = NULL; struct amdgpu_mode_info *mode_info = &adev->mode_info; uint32_t link_cnt; - unsigned long possible_crtcs; + int32_t total_overlay_planes, total_primary_planes; link_cnt = dm->dc->caps.max_links; if (amdgpu_dm_mode_config_init(dm->adev)) { @@ -1361,30 +1425,22 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) return -1; } - for (i = 0; i < dm->dc->caps.max_planes; i++) { - struct amdgpu_plane *plane; + /* Identify the number of planes to be initialized */ + total_overlay_planes = dm->dc->caps.max_slave_planes; + total_primary_planes = dm->dc->caps.max_planes - dm->dc->caps.max_slave_planes; - plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL); - mode_info->planes[i] = plane; - - if (!plane) { - DRM_ERROR("KMS: Failed to allocate plane\n"); + /* First initialize overlay planes, index starting after primary planes */ + for (i = (total_overlay_planes - 1); i >= 0; i--) { + if (initialize_plane(dm, mode_info, (total_primary_planes + i))) { + DRM_ERROR("KMS: Failed to initialize overlay plane\n"); goto fail; } - plane->base.type = mode_info->plane_type[i]; - - /* - * HACK: IGT tests expect that each plane can only have one - * one possible CRTC. For now, set one CRTC for each - * plane that is not an underlay, but still allow multiple - * CRTCs for underlay planes. - */ - possible_crtcs = 1 << i; - if (i >= dm->dc->caps.max_streams) - possible_crtcs = 0xff; + } - if (amdgpu_dm_plane_init(dm, mode_info->planes[i], possible_crtcs)) { - DRM_ERROR("KMS: Failed to initialize plane\n"); + /* Initialize primary planes */ + for (i = (total_primary_planes - 1); i >= 0; i--) { + if (initialize_plane(dm, mode_info, i)) { + DRM_ERROR("KMS: Failed to initialize primary plane\n"); goto fail; } } @@ -1538,7 +1594,6 @@ static int amdgpu_notify_freesync(struct drm_device *dev, void *data, static const struct amdgpu_display_funcs dm_display_funcs = { .bandwidth_update = dm_bandwidth_update, /* called unconditionally */ .vblank_get_counter = dm_vblank_get_counter,/* called unconditionally */ - .vblank_wait = NULL, .backlight_set_level = dm_set_backlight_level,/* called unconditionally */ .backlight_get_level = @@ -1589,8 +1644,6 @@ static int dm_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - adev->ddev->driver->driver_features |= DRIVER_ATOMIC; - switch (adev->asic_type) { case CHIP_BONAIRE: case CHIP_HAWAII: @@ -1924,32 +1977,6 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, } -static void fill_gamma_from_crtc_state(const struct drm_crtc_state *crtc_state, - struct dc_plane_state *plane_state) -{ - int i; - struct dc_gamma *gamma; - struct drm_color_lut *lut = - (struct drm_color_lut *) crtc_state->gamma_lut->data; - - gamma = dc_create_gamma(); - - if (gamma == NULL) { - WARN_ON(1); - return; - } - - gamma->type = GAMMA_RGB_256; - gamma->num_entries = GAMMA_RGB_256_ENTRIES; - for (i = 0; i < GAMMA_RGB_256_ENTRIES; i++) { - gamma->entries.red[i] = dal_fixed31_32_from_int(lut[i].red); - gamma->entries.green[i] = dal_fixed31_32_from_int(lut[i].green); - gamma->entries.blue[i] = dal_fixed31_32_from_int(lut[i].blue); - } - - plane_state->gamma_correction = gamma; -} - static int fill_plane_attributes(struct amdgpu_device *adev, struct dc_plane_state *dc_plane_state, struct drm_plane_state *plane_state, @@ -1977,14 +2004,17 @@ static int fill_plane_attributes(struct amdgpu_device *adev, if (input_tf == NULL) return -ENOMEM; - input_tf->type = TF_TYPE_PREDEFINED; - input_tf->tf = TRANSFER_FUNCTION_SRGB; - dc_plane_state->in_transfer_func = input_tf; - /* In case of gamma set, update gamma value */ - if (crtc_state->gamma_lut) - fill_gamma_from_crtc_state(crtc_state, dc_plane_state); + /* + * Always set input transfer function, since plane state is refreshed + * every time. + */ + ret = amdgpu_dm_set_degamma_lut(crtc_state, dc_plane_state); + if (ret) { + dc_transfer_func_release(dc_plane_state->in_transfer_func); + dc_plane_state->in_transfer_func = NULL; + } return ret; } @@ -2010,30 +2040,32 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, dst.width = stream->timing.h_addressable; dst.height = stream->timing.v_addressable; - rmx_type = dm_state->scaling; - if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { - if (src.width * dst.height < - src.height * dst.width) { - /* height needs less upscaling/more downscaling */ - dst.width = src.width * - dst.height / src.height; - } else { - /* width needs less upscaling/more downscaling */ - dst.height = src.height * - dst.width / src.width; + if (dm_state) { + rmx_type = dm_state->scaling; + if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { + if (src.width * dst.height < + src.height * dst.width) { + /* height needs less upscaling/more downscaling */ + dst.width = src.width * + dst.height / src.height; + } else { + /* width needs less upscaling/more downscaling */ + dst.height = src.height * + dst.width / src.width; + } + } else if (rmx_type == RMX_CENTER) { + dst = src; } - } else if (rmx_type == RMX_CENTER) { - dst = src; - } - dst.x = (stream->timing.h_addressable - dst.width) / 2; - dst.y = (stream->timing.v_addressable - dst.height) / 2; + dst.x = (stream->timing.h_addressable - dst.width) / 2; + dst.y = (stream->timing.v_addressable - dst.height) / 2; - if (dm_state->underscan_enable) { - dst.x += dm_state->underscan_hborder / 2; - dst.y += dm_state->underscan_vborder / 2; - dst.width -= dm_state->underscan_hborder; - dst.height -= dm_state->underscan_vborder; + if (dm_state->underscan_enable) { + dst.x += dm_state->underscan_hborder / 2; + dst.y += dm_state->underscan_vborder / 2; + dst.width -= dm_state->underscan_hborder; + dst.height -= dm_state->underscan_vborder; + } } stream->src = src; @@ -2322,7 +2354,7 @@ static void set_master_stream(struct dc_stream_state *stream_set[], } } for (j = 0; j < stream_count; j++) { - if (stream_set[j] && j != master_stream) + if (stream_set[j]) stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream]; } } @@ -2358,12 +2390,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, if (aconnector == NULL) { DRM_ERROR("aconnector is NULL!\n"); - goto drm_connector_null; - } - - if (dm_state == NULL) { - DRM_ERROR("dm_state is NULL!\n"); - goto dm_state_null; + return stream; } drm_connector = &aconnector->base; @@ -2375,18 +2402,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ if (aconnector->mst_port) { dm_dp_mst_dc_sink_create(drm_connector); - goto mst_dc_sink_create_done; + return stream; } if (create_fake_sink(aconnector)) - goto stream_create_fail; + return stream; } stream = dc_create_stream_for_sink(aconnector->dc_sink); if (stream == NULL) { DRM_ERROR("Failed to create stream for sink!\n"); - goto stream_create_fail; + return stream; } list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { @@ -2412,9 +2439,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, } else { decide_crtc_timing_for_drm_display_mode( &mode, preferred_mode, - dm_state->scaling != RMX_OFF); + dm_state ? (dm_state->scaling != RMX_OFF) : false); } + if (!dm_state) + drm_mode_set_crtcinfo(&mode, 0); + fill_stream_properties_from_drm_display_mode(stream, &mode, &aconnector->base); update_stream_scaling_settings(&mode, dm_state, stream); @@ -2424,10 +2454,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, drm_connector, aconnector->dc_sink); -stream_create_fail: -dm_state_null: -drm_connector_null: -mst_dc_sink_create_done: + update_stream_signal(stream); + return stream; } @@ -2495,6 +2523,27 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) return &state->base; } + +static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) +{ + enum dc_irq_source irq_source; + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); + struct amdgpu_device *adev = crtc->dev->dev_private; + + irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; + return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; +} + +static int dm_enable_vblank(struct drm_crtc *crtc) +{ + return dm_set_vblank(crtc, true); +} + +static void dm_disable_vblank(struct drm_crtc *crtc) +{ + dm_set_vblank(crtc, false); +} + /* Implemented only the options currently availible for the driver */ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .reset = dm_crtc_reset_state, @@ -2504,6 +2553,9 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .page_flip = drm_atomic_helper_page_flip, .atomic_duplicate_state = dm_crtc_duplicate_state, .atomic_destroy_state = dm_crtc_destroy_state, + .set_crc_source = amdgpu_dm_crtc_set_crc_source, + .enable_vblank = dm_enable_vblank, + .disable_vblank = dm_disable_vblank, }; static enum drm_connector_status @@ -2779,6 +2831,7 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector, /* TODO: Unhardcode stream count */ struct dc_stream_state *stream; struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + enum dc_status dc_result = DC_OK; if ((mode->flags & DRM_MODE_FLAG_INTERLACE) || (mode->flags & DRM_MODE_FLAG_DBLSCAN)) @@ -2798,21 +2851,22 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector, goto fail; } - stream = dc_create_stream_for_sink(dc_sink); + stream = create_stream_for_sink(aconnector, mode, NULL); if (stream == NULL) { DRM_ERROR("Failed to create stream for sink!\n"); goto fail; } - drm_mode_set_crtcinfo(mode, 0); - fill_stream_properties_from_drm_display_mode(stream, mode, connector); - - stream->src.width = mode->hdisplay; - stream->src.height = mode->vdisplay; - stream->dst = stream->src; + dc_result = dc_validate_stream(adev->dm.dc, stream); - if (dc_validate_stream(adev->dm.dc, stream) == DC_OK) + if (dc_result == DC_OK) result = MODE_OK; + else + DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d\n", + mode->vdisplay, + mode->hdisplay, + mode->clock, + dc_result); dc_stream_release(stream); @@ -2954,11 +3008,13 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, { struct amdgpu_framebuffer *afb; struct drm_gem_object *obj; + struct amdgpu_device *adev; struct amdgpu_bo *rbo; uint64_t chroma_addr = 0; - int r; struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old; unsigned int awidth; + uint32_t domain; + int r; dm_plane_state_old = to_dm_plane_state(plane->state); dm_plane_state_new = to_dm_plane_state(new_state); @@ -2972,12 +3028,17 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, obj = afb->obj; rbo = gem_to_amdgpu_bo(obj); + adev = amdgpu_ttm_adev(rbo->tbo.bdev); r = amdgpu_bo_reserve(rbo, false); if (unlikely(r != 0)) return r; - r = amdgpu_bo_pin(rbo, AMDGPU_GEM_DOMAIN_VRAM, &afb->address); + if (plane->type != DRM_PLANE_TYPE_CURSOR) + domain = amdgpu_display_framebuffer_domains(adev); + else + domain = AMDGPU_GEM_DOMAIN_VRAM; + r = amdgpu_bo_pin(rbo, domain, &afb->address); amdgpu_bo_unreserve(rbo); @@ -3058,6 +3119,9 @@ static int dm_plane_atomic_check(struct drm_plane *plane, if (!dm_plane_state->dc_state) return 0; + if (!fill_rects_from_plane_state(state, dm_plane_state->dc_state)) + return -EINVAL; + if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK) return 0; @@ -3190,7 +3254,9 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, acrtc->base.enabled = false; dm->adev->mode_info.crtcs[crtc_index] = acrtc; - drm_mode_crtc_set_gamma_size(&acrtc->base, 256); + drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES, + true, MAX_COLOR_LUT_ENTRIES); + drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES); return 0; @@ -3366,9 +3432,12 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) struct edid *edid = amdgpu_dm_connector->edid; encoder = helper->best_encoder(connector); - amdgpu_dm_connector_ddc_get_modes(connector, edid); amdgpu_dm_connector_add_common_modes(encoder, connector); + +#if defined(CONFIG_DRM_AMD_DC_FBC) + amdgpu_dm_fbc_init(connector); +#endif return amdgpu_dm_connector->num_modes; } @@ -3641,7 +3710,7 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, * constant is the same as PFLIP */ int irq_type = - amdgpu_crtc_idx_to_irq_type( + amdgpu_display_crtc_idx_to_irq_type( adev, acrtc->crtc_id); @@ -3836,7 +3905,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, /* Prepare wait for target vblank early - before the fence-waits */ - target_vblank = target - drm_crtc_vblank_count(crtc) + + target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) + amdgpu_get_vblank_counter_kms(crtc->dev, acrtc->crtc_id); /* TODO This might fail and hence better not used, wait @@ -3860,9 +3929,9 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, * targeted by the flip */ while ((acrtc->enabled && - (amdgpu_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id, 0, - &vpos, &hpos, NULL, NULL, - &crtc->hwmode) + (amdgpu_display_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id, + 0, &vpos, &hpos, NULL, + NULL, &crtc->hwmode) & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && (int)(target_vblank - @@ -3982,7 +4051,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, amdgpu_dm_do_flip( crtc, fb, - drm_crtc_vblank_count(crtc) + *wait_for_vblank, + (uint32_t)drm_crtc_vblank_count(crtc) + *wait_for_vblank, dm_state->context); } @@ -4603,6 +4672,30 @@ next_crtc: /* Release extra reference */ if (new_stream) dc_stream_release(new_stream); + + /* + * We want to do dc stream updates that do not require a + * full modeset below. + */ + if (!enable || !aconnector || modereset_required(new_crtc_state)) + continue; + /* + * Given above conditions, the dc state cannot be NULL because: + * 1. We're attempting to enable a CRTC. Which has a... + * 2. Valid connector attached, and + * 3. User does not want to reset it (disable or mark inactive, + * which can happen on a CRTC that's already disabled). + * => It currently exists. + */ + BUG_ON(dm_new_crtc_state->stream == NULL); + + /* Color managment settings */ + if (dm_new_crtc_state->base.color_mgmt_changed) { + ret = amdgpu_dm_set_regamma_lut(dm_new_crtc_state); + if (ret) + goto fail; + amdgpu_dm_set_ctm(dm_new_crtc_state); + } } return ret; @@ -4630,11 +4723,9 @@ static int dm_update_planes_state(struct dc *dc, bool pflip_needed = !state->allow_modeset; int ret = 0; - if (pflip_needed) - return ret; - /* Add new planes */ - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { + /* Add new planes, in reverse order as DC expectation */ + for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { new_plane_crtc = new_plane_state->crtc; old_plane_crtc = old_plane_state->crtc; dm_new_plane_state = to_dm_plane_state(new_plane_state); @@ -4646,6 +4737,8 @@ static int dm_update_planes_state(struct dc *dc, /* Remove any changed/removed planes */ if (!enable) { + if (pflip_needed) + continue; if (!old_plane_crtc) continue; @@ -4677,6 +4770,7 @@ static int dm_update_planes_state(struct dc *dc, *lock_and_validation_needed = true; } else { /* Add new planes */ + struct dc_plane_state *dc_new_plane_state; if (drm_atomic_plane_disabling(plane->state, new_plane_state)) continue; @@ -4690,38 +4784,47 @@ static int dm_update_planes_state(struct dc *dc, if (!dm_new_crtc_state->stream) continue; + if (pflip_needed) + continue; WARN_ON(dm_new_plane_state->dc_state); - dm_new_plane_state->dc_state = dc_create_plane_state(dc); + dc_new_plane_state = dc_create_plane_state(dc); + if (!dc_new_plane_state) + return -ENOMEM; DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", plane->base.id, new_plane_crtc->base.id); - if (!dm_new_plane_state->dc_state) { - ret = -EINVAL; - return ret; - } - ret = fill_plane_attributes( new_plane_crtc->dev->dev_private, - dm_new_plane_state->dc_state, + dc_new_plane_state, new_plane_state, new_crtc_state); - if (ret) + if (ret) { + dc_plane_state_release(dc_new_plane_state); return ret; + } - + /* + * Any atomic check errors that occur after this will + * not need a release. The plane state will be attached + * to the stream, and therefore part of the atomic + * state. It'll be released when the atomic state is + * cleaned. + */ if (!dc_add_plane_to_context( dc, dm_new_crtc_state->stream, - dm_new_plane_state->dc_state, + dc_new_plane_state, dm_state->context)) { - ret = -EINVAL; - return ret; + dc_plane_state_release(dc_new_plane_state); + return -EINVAL; } + dm_new_plane_state->dc_state = dc_new_plane_state; + /* Tell DC to do a full surface update every time there * is a plane change. Inefficient, but works for now. */ @@ -4735,6 +4838,33 @@ static int dm_update_planes_state(struct dc *dc, return ret; } +static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state, + struct drm_crtc *crtc) +{ + struct drm_plane *plane; + struct drm_crtc_state *crtc_state; + + WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); + + drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); + + if (IS_ERR(plane_state)) + return -EDEADLK; + + crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (crtc->primary == plane && crtc_state->active) { + if (!plane_state->fb) + return -EINVAL; + } + } + return 0; +} + static int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -4758,6 +4888,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + ret = dm_atomic_check_plane_state_fb(state, crtc); + if (ret) + goto fail; + if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && !new_crtc_state->color_mgmt_changed) continue; |