diff options
Diffstat (limited to 'drivers/gpu/drm')
167 files changed, 2418 insertions, 871 deletions
| diff --git a/drivers/gpu/drm/amd/acp/Makefile b/drivers/gpu/drm/amd/acp/Makefile index 8a08e81ee90d..d4176a3fb706 100644 --- a/drivers/gpu/drm/amd/acp/Makefile +++ b/drivers/gpu/drm/amd/acp/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the ACP, which is a sub-component  # of AMDSOC/AMDGPU drm driver.  # It provides the HW control for ACP related functionalities. diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 78d609123420..90202cf4cd1e 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -1,4 +1,24 @@ -# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +#  #  # Makefile for the drm device driver.  This driver provides support for the  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 5afaf6016b4a..0b14b5373783 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -717,7 +717,7 @@ int amdgpu_queue_mgr_fini(struct amdgpu_device *adev,  			  struct amdgpu_queue_mgr *mgr);  int amdgpu_queue_mgr_map(struct amdgpu_device *adev,  			 struct amdgpu_queue_mgr *mgr, -			 int hw_ip, int instance, int ring, +			 u32 hw_ip, u32 instance, u32 ring,  			 struct amdgpu_ring **out_ring);  /* @@ -1572,18 +1572,14 @@ struct amdgpu_device {  	/* sdma */  	struct amdgpu_sdma		sdma; -	union { -		struct { -			/* uvd */ -			struct amdgpu_uvd		uvd; +	/* uvd */ +	struct amdgpu_uvd		uvd; -			/* vce */ -			struct amdgpu_vce		vce; -		}; +	/* vce */ +	struct amdgpu_vce		vce; -		/* vcn */ -		struct amdgpu_vcn		vcn; -	}; +	/* vcn */ +	struct amdgpu_vcn		vcn;  	/* firmwares */  	struct amdgpu_firmware		firmware; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 47d1c132ac40..1e3e9be7d77e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -379,29 +379,50 @@ static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd)  {  	struct amdgpu_device *adev = get_amdgpu_device(kgd);  	struct cik_sdma_rlc_registers *m; +	unsigned long end_jiffies;  	uint32_t sdma_base_addr; +	uint32_t data;  	m = get_sdma_mqd(mqd);  	sdma_base_addr = get_sdma_base_addr(m); -	WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR, -			m->sdma_rlc_virtual_addr); +	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, +		m->sdma_rlc_rb_cntl & (~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK)); -	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, -			m->sdma_rlc_rb_base); +	end_jiffies = msecs_to_jiffies(2000) + jiffies; +	while (true) { +		data = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS); +		if (data & SDMA0_RLC0_CONTEXT_STATUS__IDLE_MASK) +			break; +		if (time_after(jiffies, end_jiffies)) +			return -ETIME; +		usleep_range(500, 1000); +	} +	if (m->sdma_engine_id) { +		data = RREG32(mmSDMA1_GFX_CONTEXT_CNTL); +		data = REG_SET_FIELD(data, SDMA1_GFX_CONTEXT_CNTL, +				RESUME_CTX, 0); +		WREG32(mmSDMA1_GFX_CONTEXT_CNTL, data); +	} else { +		data = RREG32(mmSDMA0_GFX_CONTEXT_CNTL); +		data = REG_SET_FIELD(data, SDMA0_GFX_CONTEXT_CNTL, +				RESUME_CTX, 0); +		WREG32(mmSDMA0_GFX_CONTEXT_CNTL, data); +	} +	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, +				m->sdma_rlc_doorbell); +	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0); +	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0); +	WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR, +				m->sdma_rlc_virtual_addr); +	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, m->sdma_rlc_rb_base);  	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI,  			m->sdma_rlc_rb_base_hi); -  	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO,  			m->sdma_rlc_rb_rptr_addr_lo); -  	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI,  			m->sdma_rlc_rb_rptr_addr_hi); - -	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, -			m->sdma_rlc_doorbell); -  	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,  			m->sdma_rlc_rb_cntl); @@ -574,9 +595,9 @@ static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,  	}  	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0); -	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0); -	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0); -	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, 0); +	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, +		RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL) | +		SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK);  	return 0;  } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index a57cec737c18..57abf7abd7a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -409,6 +409,10 @@ static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p,  		if (candidate->robj == validated)  			break; +		/* We can't move pinned BOs here */ +		if (bo->pin_count) +			continue; +  		other = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);  		/* Check if this BO is in one of the domains we need space for */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 2c574374d9b6..3573ecdb06ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1837,9 +1837,6 @@ static int amdgpu_fini(struct amdgpu_device *adev)  		adev->ip_blocks[i].status.hw = false;  	} -	if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU) -		amdgpu_ucode_fini_bo(adev); -  	for (i = adev->num_ip_blocks - 1; i >= 0; i--) {  		if (!adev->ip_blocks[i].status.sw)  			continue; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index ec96bb1f9eaf..c2f414ffb2cc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -536,7 +536,7 @@ static const struct pci_device_id pciidlist[] = {  	{0x1002, 0x686c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},  	{0x1002, 0x687f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},  	/* Raven */ -	{0x1002, 0x15dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RAVEN|AMD_IS_APU|AMD_EXP_HW_SUPPORT}, +	{0x1002, 0x15dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RAVEN|AMD_IS_APU},  	{0, 0, 0}  }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 6c570d4e4516..f8edf5483f11 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -1,4 +1,6 @@  /* + * Copyright 2017 Advanced Micro Devices, Inc. + *   * Permission is hereby granted, free of charge, to any person obtaining a   * copy of this software and associated documentation files (the "Software"),   * to deal in the Software without restriction, including without limitation diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c index 033fba2def6f..5f5aa5fddc16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c @@ -164,6 +164,9 @@ static int amdgpu_pp_hw_fini(void *handle)  		ret = adev->powerplay.ip_funcs->hw_fini(  					adev->powerplay.pp_handle); +	if (adev->firmware.load_type == AMDGPU_FW_LOAD_SMU) +		amdgpu_ucode_fini_bo(adev); +  	return ret;  } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 7714f4a6c8b0..447d446b5015 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -442,6 +442,8 @@ static int psp_hw_fini(void *handle)  	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)  		return 0; +	amdgpu_ucode_fini_bo(adev); +  	psp_ring_destroy(psp, PSP_RING_TYPE__KM);  	amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c index 190e28cb827e..93d86619e802 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c @@ -63,7 +63,7 @@ static int amdgpu_update_cached_map(struct amdgpu_queue_mapper *mapper,  static int amdgpu_identity_map(struct amdgpu_device *adev,  			       struct amdgpu_queue_mapper *mapper, -			       int ring, +			       u32 ring,  			       struct amdgpu_ring **out_ring)  {  	switch (mapper->hw_ip) { @@ -121,7 +121,7 @@ static enum amdgpu_ring_type amdgpu_hw_ip_to_ring_type(int hw_ip)  static int amdgpu_lru_map(struct amdgpu_device *adev,  			  struct amdgpu_queue_mapper *mapper, -			  int user_ring, bool lru_pipe_order, +			  u32 user_ring, bool lru_pipe_order,  			  struct amdgpu_ring **out_ring)  {  	int r, i, j; @@ -208,7 +208,7 @@ int amdgpu_queue_mgr_fini(struct amdgpu_device *adev,   */  int amdgpu_queue_mgr_map(struct amdgpu_device *adev,  			 struct amdgpu_queue_mgr *mgr, -			 int hw_ip, int instance, int ring, +			 u32 hw_ip, u32 instance, u32 ring,  			 struct amdgpu_ring **out_ring)  {  	int r, ip_num_rings; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index f337c316ec2c..06525f2c36c3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -1,4 +1,26 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +  #if !defined(_AMDGPU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)  #define _AMDGPU_TRACE_H_ diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 793b1470284d..a296f7bbe57c 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1023,22 +1023,101 @@ static const struct amdgpu_allowed_register_entry cik_allowed_read_registers[] =  	{mmPA_SC_RASTER_CONFIG_1, true},  }; -static uint32_t cik_read_indexed_register(struct amdgpu_device *adev, -					  u32 se_num, u32 sh_num, -					  u32 reg_offset) + +static uint32_t cik_get_register_value(struct amdgpu_device *adev, +				       bool indexed, u32 se_num, +				       u32 sh_num, u32 reg_offset)  { -	uint32_t val; +	if (indexed) { +		uint32_t val; +		unsigned se_idx = (se_num == 0xffffffff) ? 0 : se_num; +		unsigned sh_idx = (sh_num == 0xffffffff) ? 0 : sh_num; + +		switch (reg_offset) { +		case mmCC_RB_BACKEND_DISABLE: +			return adev->gfx.config.rb_config[se_idx][sh_idx].rb_backend_disable; +		case mmGC_USER_RB_BACKEND_DISABLE: +			return adev->gfx.config.rb_config[se_idx][sh_idx].user_rb_backend_disable; +		case mmPA_SC_RASTER_CONFIG: +			return adev->gfx.config.rb_config[se_idx][sh_idx].raster_config; +		case mmPA_SC_RASTER_CONFIG_1: +			return adev->gfx.config.rb_config[se_idx][sh_idx].raster_config_1; +		} -	mutex_lock(&adev->grbm_idx_mutex); -	if (se_num != 0xffffffff || sh_num != 0xffffffff) -		amdgpu_gfx_select_se_sh(adev, se_num, sh_num, 0xffffffff); +		mutex_lock(&adev->grbm_idx_mutex); +		if (se_num != 0xffffffff || sh_num != 0xffffffff) +			amdgpu_gfx_select_se_sh(adev, se_num, sh_num, 0xffffffff); -	val = RREG32(reg_offset); +		val = RREG32(reg_offset); -	if (se_num != 0xffffffff || sh_num != 0xffffffff) -		amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); -	mutex_unlock(&adev->grbm_idx_mutex); -	return val; +		if (se_num != 0xffffffff || sh_num != 0xffffffff) +			amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); +		mutex_unlock(&adev->grbm_idx_mutex); +		return val; +	} else { +		unsigned idx; + +		switch (reg_offset) { +		case mmGB_ADDR_CONFIG: +			return adev->gfx.config.gb_addr_config; +		case mmMC_ARB_RAMCFG: +			return adev->gfx.config.mc_arb_ramcfg; +		case mmGB_TILE_MODE0: +		case mmGB_TILE_MODE1: +		case mmGB_TILE_MODE2: +		case mmGB_TILE_MODE3: +		case mmGB_TILE_MODE4: +		case mmGB_TILE_MODE5: +		case mmGB_TILE_MODE6: +		case mmGB_TILE_MODE7: +		case mmGB_TILE_MODE8: +		case mmGB_TILE_MODE9: +		case mmGB_TILE_MODE10: +		case mmGB_TILE_MODE11: +		case mmGB_TILE_MODE12: +		case mmGB_TILE_MODE13: +		case mmGB_TILE_MODE14: +		case mmGB_TILE_MODE15: +		case mmGB_TILE_MODE16: +		case mmGB_TILE_MODE17: +		case mmGB_TILE_MODE18: +		case mmGB_TILE_MODE19: +		case mmGB_TILE_MODE20: +		case mmGB_TILE_MODE21: +		case mmGB_TILE_MODE22: +		case mmGB_TILE_MODE23: +		case mmGB_TILE_MODE24: +		case mmGB_TILE_MODE25: +		case mmGB_TILE_MODE26: +		case mmGB_TILE_MODE27: +		case mmGB_TILE_MODE28: +		case mmGB_TILE_MODE29: +		case mmGB_TILE_MODE30: +		case mmGB_TILE_MODE31: +			idx = (reg_offset - mmGB_TILE_MODE0); +			return adev->gfx.config.tile_mode_array[idx]; +		case mmGB_MACROTILE_MODE0: +		case mmGB_MACROTILE_MODE1: +		case mmGB_MACROTILE_MODE2: +		case mmGB_MACROTILE_MODE3: +		case mmGB_MACROTILE_MODE4: +		case mmGB_MACROTILE_MODE5: +		case mmGB_MACROTILE_MODE6: +		case mmGB_MACROTILE_MODE7: +		case mmGB_MACROTILE_MODE8: +		case mmGB_MACROTILE_MODE9: +		case mmGB_MACROTILE_MODE10: +		case mmGB_MACROTILE_MODE11: +		case mmGB_MACROTILE_MODE12: +		case mmGB_MACROTILE_MODE13: +		case mmGB_MACROTILE_MODE14: +		case mmGB_MACROTILE_MODE15: +			idx = (reg_offset - mmGB_MACROTILE_MODE0); +			return adev->gfx.config.macrotile_mode_array[idx]; +		default: +			return RREG32(reg_offset); +		} +	}  }  static int cik_read_register(struct amdgpu_device *adev, u32 se_num, @@ -1048,13 +1127,13 @@ static int cik_read_register(struct amdgpu_device *adev, u32 se_num,  	*value = 0;  	for (i = 0; i < ARRAY_SIZE(cik_allowed_read_registers); i++) { +		bool indexed = cik_allowed_read_registers[i].grbm_indexed; +  		if (reg_offset != cik_allowed_read_registers[i].reg_offset)  			continue; -		*value = cik_allowed_read_registers[i].grbm_indexed ? -			 cik_read_indexed_register(adev, se_num, -						   sh_num, reg_offset) : -			 RREG32(reg_offset); +		*value = cik_get_register_value(adev, indexed, se_num, sh_num, +						reg_offset);  		return 0;  	}  	return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 5c8a7a48a4ad..419ba0ce7ee5 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -1819,6 +1819,22 @@ static void gfx_v7_0_setup_rb(struct amdgpu_device *adev)  							adev->gfx.config.backend_enable_mask,  							num_rb_pipes);  	} + +	/* cache the values for userspace */ +	for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { +		for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { +			gfx_v7_0_select_se_sh(adev, i, j, 0xffffffff); +			adev->gfx.config.rb_config[i][j].rb_backend_disable = +				RREG32(mmCC_RB_BACKEND_DISABLE); +			adev->gfx.config.rb_config[i][j].user_rb_backend_disable = +				RREG32(mmGC_USER_RB_BACKEND_DISABLE); +			adev->gfx.config.rb_config[i][j].raster_config = +				RREG32(mmPA_SC_RASTER_CONFIG); +			adev->gfx.config.rb_config[i][j].raster_config_1 = +				RREG32(mmPA_SC_RASTER_CONFIG_1); +		} +	} +	gfx_v7_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);  	mutex_unlock(&adev->grbm_idx_mutex);  } diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index da43813d67a4..5aeb5f8816f3 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -2467,7 +2467,7 @@ static int gfx_v9_0_kiq_kcq_enable(struct amdgpu_device *adev)  				  PACKET3_MAP_QUEUES_PIPE(ring->pipe) |  				  PACKET3_MAP_QUEUES_ME((ring->me == 1 ? 0 : 1)) |  				  PACKET3_MAP_QUEUES_QUEUE_TYPE(0) | /*queue_type: normal compute queue */ -				  PACKET3_MAP_QUEUES_ALLOC_FORMAT(1) | /* alloc format: all_on_one_pipe */ +				  PACKET3_MAP_QUEUES_ALLOC_FORMAT(0) | /* alloc format: all_on_one_pipe */  				  PACKET3_MAP_QUEUES_ENGINE_SEL(0) | /* engine_sel: compute */  				  PACKET3_MAP_QUEUES_NUM_QUEUES(1)); /* num_queues: must be 1 */  		amdgpu_ring_write(kiq_ring, PACKET3_MAP_QUEUES_DOORBELL_OFFSET(ring->doorbell_index)); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 1eb4d79d6e30..0450ac5ba6b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -1175,7 +1175,7 @@ static const struct amdgpu_irq_src_funcs vcn_v1_0_irq_funcs = {  static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev)  { -	adev->uvd.irq.num_types = adev->vcn.num_enc_rings + 1; +	adev->vcn.irq.num_types = adev->vcn.num_enc_rings + 1;  	adev->vcn.irq.funcs = &vcn_v1_0_irq_funcs;  } diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index 7bb0bc0ca3d6..342c2d937b17 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -1,4 +1,24 @@ -# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +#  #  # Makefile for Heterogenous System Architecture support for AMD GPU devices  # diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c index 6c5a9cab55de..f744caeaee04 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c @@ -24,6 +24,7 @@  #include <linux/sched.h>  #include <linux/moduleparam.h>  #include <linux/device.h> +#include <linux/printk.h>  #include "kfd_priv.h"  #define KFD_DRIVER_AUTHOR	"AMD Inc. and others" @@ -132,7 +133,7 @@ static void __exit kfd_module_exit(void)  	kfd_process_destroy_wq();  	kfd_topology_shutdown();  	kfd_chardev_exit(); -	dev_info(kfd_device, "Removed module\n"); +	pr_info("amdkfd: Removed module\n");  }  module_init(kfd_module_init); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 4859d263fa2a..4728fad3fd74 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -202,8 +202,8 @@ static int update_mqd_sdma(struct mqd_manager *mm, void *mqd,  	struct cik_sdma_rlc_registers *m;  	m = get_sdma_mqd(mqd); -	m->sdma_rlc_rb_cntl = ffs(q->queue_size / sizeof(unsigned int)) << -			SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT | +	m->sdma_rlc_rb_cntl = (ffs(q->queue_size / sizeof(unsigned int)) - 1) +			<< SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT |  			q->vmid << SDMA0_RLC0_RB_CNTL__RB_VMID__SHIFT |  			1 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_ENABLE__SHIFT |  			6 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 2bec902fc939..a3f1e62c60ba 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -191,6 +191,24 @@ int pqm_create_queue(struct process_queue_manager *pqm,  	switch (type) {  	case KFD_QUEUE_TYPE_SDMA: +		if (dev->dqm->queue_count >= +			CIK_SDMA_QUEUES_PER_ENGINE * CIK_SDMA_ENGINE_NUM) { +			pr_err("Over-subscription is not allowed for SDMA.\n"); +			retval = -EPERM; +			goto err_create_queue; +		} + +		retval = create_cp_queue(pqm, dev, &q, properties, f, *qid); +		if (retval != 0) +			goto err_create_queue; +		pqn->q = q; +		pqn->kq = NULL; +		retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd, +						&q->properties.vmid); +		pr_debug("DQM returned %d for create_queue\n", retval); +		print_queue(q); +		break; +  	case KFD_QUEUE_TYPE_COMPUTE:  		/* check if there is over subscription */  		if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) && diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index 8ba37dd9cf7f..c27c81cdeed3 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the DAL (Display Abstract Layer), which is a  sub-component  # of the AMDGPU drm driver.  # It provides the HW control for display related functionalities. diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 4699e47aa76b..2b72009844f8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'dm' sub-component of DAL.  # It provides the control and status of dm blocks. 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 889ed24084e8..bb5fa895fb64 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -520,7 +520,8 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev)  	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {  		aconnector = to_amdgpu_dm_connector(connector); -		if (aconnector->dc_link->type == dc_connection_mst_branch) { +		if (aconnector->dc_link->type == dc_connection_mst_branch && +		    aconnector->mst_mgr.aux) {  			DRM_DEBUG_DRIVER("DM_MST: starting TM on aconnector: %p [id: %d]\n",  					aconnector, aconnector->base.base.id); @@ -677,6 +678,10 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)  		mutex_lock(&aconnector->hpd_lock);  		dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD); + +		if (aconnector->fake_enable && aconnector->dc_link->local_sink) +			aconnector->fake_enable = false; +  		aconnector->dc_sink = NULL;  		amdgpu_dm_update_connector_after_detect(aconnector);  		mutex_unlock(&aconnector->hpd_lock); @@ -711,7 +716,6 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)  	ret = drm_atomic_helper_resume(ddev, adev->dm.cached_state); -	drm_atomic_state_put(adev->dm.cached_state);  	adev->dm.cached_state = NULL;  	amdgpu_dm_irq_resume_late(adev); @@ -2332,7 +2336,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  		       const struct dm_connector_state *dm_state)  {  	struct drm_display_mode *preferred_mode = NULL; -	const struct drm_connector *drm_connector; +	struct drm_connector *drm_connector;  	struct dc_stream_state *stream = NULL;  	struct drm_display_mode mode = *drm_mode;  	bool native_mode_found = false; @@ -2351,11 +2355,13 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  	if (!aconnector->dc_sink) {  		/* -		 * Exclude MST from creating fake_sink -		 * TODO: need to enable MST into fake_sink feature +		 * Create dc_sink when necessary to MST +		 * Don't apply fake_sink to MST  		 */ -		if (aconnector->mst_port) -			goto stream_create_fail; +		if (aconnector->mst_port) { +			dm_dp_mst_dc_sink_create(drm_connector); +			goto mst_dc_sink_create_done; +		}  		if (create_fake_sink(aconnector))  			goto stream_create_fail; @@ -2406,6 +2412,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  stream_create_fail:  dm_state_null:  drm_connector_null: +mst_dc_sink_create_done:  	return stream;  } @@ -2704,7 +2711,7 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)  			.link = aconnector->dc_link,  			.sink_signal = SIGNAL_TYPE_VIRTUAL  	}; -	struct edid *edid = (struct edid *) aconnector->base.edid_blob_ptr->data; +	struct edid *edid;  	if (!aconnector->base.edid_blob_ptr ||  		!aconnector->base.edid_blob_ptr->data) { @@ -2716,6 +2723,8 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)  		return;  	} +	edid = (struct edid *) aconnector->base.edid_blob_ptr->data; +  	aconnector->edid = edid;  	aconnector->dc_em_sink = dc_link_add_remote_sink( @@ -4193,13 +4202,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)  		update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,  				dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream); +		if (!dm_new_crtc_state->stream) +			continue; +  		status = dc_stream_get_status(dm_new_crtc_state->stream);  		WARN_ON(!status);  		WARN_ON(!status->plane_count); -		if (!dm_new_crtc_state->stream) -			continue; -  		/*TODO How it works with MPO ?*/  		if (!dc_commit_planes_to_stream(  				dm->dc, @@ -4253,7 +4262,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)  	drm_atomic_helper_commit_hw_done(state);  	if (wait_for_vblank) -		drm_atomic_helper_wait_for_vblanks(dev, state); +		drm_atomic_helper_wait_for_flip_done(dev, state);  	drm_atomic_helper_cleanup_planes(dev, state);  } @@ -4332,9 +4341,11 @@ void dm_restore_drm_connector_state(struct drm_device *dev,  		return;  	disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc); -	acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state); +	if (!disconnected_acrtc) +		return; -	if (!disconnected_acrtc || !acrtc_state->stream) +	acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state); +	if (!acrtc_state->stream)  		return;  	/* @@ -4455,7 +4466,7 @@ static int dm_update_crtcs_state(struct dc *dc,  			}  		} -		if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) && +		if (enable && dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&  				dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {  			new_crtc_state->mode_changed = false; @@ -4709,7 +4720,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,  		}  	} else {  		for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { -			if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) +			if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && +					!new_crtc_state->color_mgmt_changed)  				continue;  			if (!new_crtc_state->enable) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 117521c6a6ed..0230250a1164 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -189,6 +189,8 @@ struct amdgpu_dm_connector {  	struct mutex hpd_lock;  	bool fake_enable; + +	bool mst_connected;  };  #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base) 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 f8efb98b1fa7..638c2c2b5cd7 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 @@ -185,6 +185,42 @@ static int dm_connector_update_modes(struct drm_connector *connector,  	return ret;  } +void dm_dp_mst_dc_sink_create(struct drm_connector *connector) +{ +	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); +	struct edid *edid; +	struct dc_sink *dc_sink; +	struct dc_sink_init_data init_params = { +			.link = aconnector->dc_link, +			.sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST }; + +	edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port); + +	if (!edid) { +		drm_mode_connector_update_edid_property( +			&aconnector->base, +			NULL); +		return; +	} + +	aconnector->edid = edid; + +	dc_sink = dc_link_add_remote_sink( +		aconnector->dc_link, +		(uint8_t *)aconnector->edid, +		(aconnector->edid->extensions + 1) * EDID_LENGTH, +		&init_params); + +	dc_sink->priv = aconnector; +	aconnector->dc_sink = dc_sink; + +	amdgpu_dm_add_sink_to_freesync_module( +			connector, aconnector->edid); + +	drm_mode_connector_update_edid_property( +					&aconnector->base, aconnector->edid); +} +  static int dm_dp_mst_get_modes(struct drm_connector *connector)  {  	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); @@ -311,6 +347,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,  			drm_mode_connector_set_path_property(connector, pathprop);  			drm_connector_list_iter_end(&conn_iter); +			aconnector->mst_connected = true;  			return &aconnector->base;  		}  	} @@ -363,6 +400,8 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,  	 */  	amdgpu_dm_connector_funcs_reset(connector); +	aconnector->mst_connected = true; +  	DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",  			aconnector, connector->base.id, aconnector->mst_port); @@ -394,6 +433,8 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,  	drm_mode_connector_update_edid_property(  			&aconnector->base,  			NULL); + +	aconnector->mst_connected = false;  }  static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) @@ -404,10 +445,18 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)  	drm_kms_helper_hotplug_event(dev);  } +static void dm_dp_mst_link_status_reset(struct drm_connector *connector) +{ +	mutex_lock(&connector->dev->mode_config.mutex); +	drm_mode_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD); +	mutex_unlock(&connector->dev->mode_config.mutex); +} +  static void dm_dp_mst_register_connector(struct drm_connector *connector)  {  	struct drm_device *dev = connector->dev;  	struct amdgpu_device *adev = dev->dev_private; +	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);  	if (adev->mode_info.rfbdev)  		drm_fb_helper_add_one_connector(&adev->mode_info.rfbdev->helper, connector); @@ -416,6 +465,8 @@ static void dm_dp_mst_register_connector(struct drm_connector *connector)  	drm_connector_register(connector); +	if (aconnector->mst_connected) +		dm_dp_mst_link_status_reset(connector);  }  static const struct drm_dp_mst_topology_cbs dm_mst_cbs = { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h index 2da851b40042..8cf51da26657 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h @@ -31,5 +31,6 @@ struct amdgpu_dm_connector;  void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,  				       struct amdgpu_dm_connector *aconnector); +void dm_dp_mst_dc_sink_create(struct drm_connector *connector);  #endif diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 4f83e3011743..aed538a4d1ba 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for Display Core (dc) component.  # diff --git a/drivers/gpu/drm/amd/display/dc/basics/Makefile b/drivers/gpu/drm/amd/display/dc/basics/Makefile index 43c5ccdeeb72..6af8c8a9ad80 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/Makefile +++ b/drivers/gpu/drm/amd/display/dc/basics/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'utils' sub-component of DAL.  # It provides the general basic services required by other DAL  # subcomponents. diff --git a/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c b/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c index 785b943b60ed..6e43168fbdd6 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c @@ -75,6 +75,9 @@ void dc_conn_log(struct dc_context *ctx,  		if (signal == signal_type_info_tbl[i].type)  			break; +	if (i == NUM_ELEMENTS(signal_type_info_tbl)) +		goto fail; +  	dm_logger_append(&entry, "[%s][ConnIdx:%d] ",  			signal_type_info_tbl[i].name,  			link->link_index); @@ -96,6 +99,8 @@ void dc_conn_log(struct dc_context *ctx,  	dm_logger_append(&entry, "^\n");  	dm_helpers_dc_conn_log(ctx, &entry, event); + +fail:  	dm_logger_close(&entry);  	va_end(args); diff --git a/drivers/gpu/drm/amd/display/dc/bios/Makefile b/drivers/gpu/drm/amd/display/dc/bios/Makefile index 6ec815dce9cc..239e86bbec5a 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/Makefile +++ b/drivers/gpu/drm/amd/display/dc/bios/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'bios' sub-component of DAL.  # It provides the parsing and executing controls for atom bios image. diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index aaaebd06d7ee..86e6438c5cf3 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -249,7 +249,7 @@ static enum bp_result bios_parser_get_dst_obj(struct dc_bios *dcb,  	struct graphics_object_id *dest_object_id)  {  	uint32_t number; -	uint16_t *id; +	uint16_t *id = NULL;  	ATOM_OBJECT *object;  	struct bios_parser *bp = BP_FROM_DCB(dcb); @@ -260,7 +260,7 @@ static enum bp_result bios_parser_get_dst_obj(struct dc_bios *dcb,  	number = get_dest_obj_list(bp, object, &id); -	if (number <= index) +	if (number <= index || !id)  		return BP_RESULT_BADINPUT;  	*dest_object_id = object_id_from_bios_object_id(id[index]); diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 41ef35995b02..7959e382ed28 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'calcs' sub-component of DAL.  # It calculates Bandwidth and Watermarks values for HW programming  # diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 3dce35e66b09..b142629a1058 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -900,6 +900,15 @@ bool dcn_validate_bandwidth(  			v->override_vta_ps[input_idx] = pipe->plane_res.scl_data.taps.v_taps;  			v->override_hta_pschroma[input_idx] = pipe->plane_res.scl_data.taps.h_taps_c;  			v->override_vta_pschroma[input_idx] = pipe->plane_res.scl_data.taps.v_taps_c; +			/* +			 * Spreadsheet doesn't handle taps_c is one properly, +			 * need to force Chroma to always be scaled to pass +			 * bandwidth validation. +			 */ +			if (v->override_hta_pschroma[input_idx] == 1) +				v->override_hta_pschroma[input_idx] = 2; +			if (v->override_vta_pschroma[input_idx] == 1) +				v->override_vta_pschroma[input_idx] = 2;  			v->source_scan[input_idx] = (pipe->plane_state->rotation % 2) ? dcn_bw_vert : dcn_bw_hor;  		}  		if (v->is_line_buffer_bpp_fixed == dcn_bw_yes) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index fe63f5894d43..7240db2e6f09 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -121,6 +121,10 @@ static bool create_links(  			goto failed_alloc;  		} +		link->link_index = dc->link_count; +		dc->links[dc->link_count] = link; +		dc->link_count++; +  		link->ctx = dc->ctx;  		link->dc = dc;  		link->connector_signal = SIGNAL_TYPE_VIRTUAL; @@ -129,6 +133,13 @@ static bool create_links(  		link->link_id.enum_id = ENUM_ID_1;  		link->link_enc = kzalloc(sizeof(*link->link_enc), GFP_KERNEL); +		if (!link->link_enc) { +			BREAK_TO_DEBUGGER(); +			goto failed_alloc; +		} + +		link->link_status.dpcd_caps = &link->dpcd_caps; +  		enc_init.ctx = dc->ctx;  		enc_init.channel = CHANNEL_ID_UNKNOWN;  		enc_init.hpd_source = HPD_SOURCEID_UNKNOWN; @@ -138,10 +149,6 @@ static bool create_links(  		enc_init.encoder.id = ENCODER_ID_INTERNAL_VIRTUAL;  		enc_init.encoder.enum_id = ENUM_ID_1;  		virtual_link_encoder_construct(link->link_enc, &enc_init); - -		link->link_index = dc->link_count; -		dc->links[dc->link_count] = link; -		dc->link_count++;  	}  	return true; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 6acee5426e4b..43c7a7fddb83 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -1,4 +1,26 @@  /* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +/*   * dc_debug.c   *   *  Created on: Nov 3, 2016 diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 0602610489d7..42a111b9505d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -480,22 +480,6 @@ static void detect_dp(  		sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT;  		detect_dp_sink_caps(link); -		/* DP active dongles */ -		if (is_dp_active_dongle(link)) { -			link->type = dc_connection_active_dongle; -			if (!link->dpcd_caps.sink_count.bits.SINK_COUNT) { -				/* -				 * active dongle unplug processing for short irq -				 */ -				link_disconnect_sink(link); -				return; -			} - -			if (link->dpcd_caps.dongle_type != -			DISPLAY_DONGLE_DP_HDMI_CONVERTER) { -				*converter_disable_audio = true; -			} -		}  		if (is_mst_supported(link)) {  			sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;  			link->type = dc_connection_mst_branch; @@ -535,6 +519,22 @@ static void detect_dp(  				sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT;  			}  		} + +		if (link->type != dc_connection_mst_branch && +			is_dp_active_dongle(link)) { +			/* DP active dongles */ +			link->type = dc_connection_active_dongle; +			if (!link->dpcd_caps.sink_count.bits.SINK_COUNT) { +				/* +				 * active dongle unplug processing for short irq +				 */ +				link_disconnect_sink(link); +				return; +			} + +			if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER) +				*converter_disable_audio = true; +		}  	} else {  		/* DP passive dongles */  		sink_caps->signal = dp_passive_dongle_detection(link->ddc, @@ -1801,12 +1801,77 @@ static void disable_link(struct dc_link *link, enum signal_type signal)  		link->link_enc->funcs->disable_output(link->link_enc, signal, link);  } +static bool dp_active_dongle_validate_timing( +		const struct dc_crtc_timing *timing, +		const struct dc_dongle_caps *dongle_caps) +{ +	unsigned int required_pix_clk = timing->pix_clk_khz; + +	if (dongle_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER || +		dongle_caps->extendedCapValid == false) +		return true; + +	/* Check Pixel Encoding */ +	switch (timing->pixel_encoding) { +	case PIXEL_ENCODING_RGB: +	case PIXEL_ENCODING_YCBCR444: +		break; +	case PIXEL_ENCODING_YCBCR422: +		if (!dongle_caps->is_dp_hdmi_ycbcr422_pass_through) +			return false; +		break; +	case PIXEL_ENCODING_YCBCR420: +		if (!dongle_caps->is_dp_hdmi_ycbcr420_pass_through) +			return false; +		break; +	default: +		/* Invalid Pixel Encoding*/ +		return false; +	} + + +	/* Check Color Depth and Pixel Clock */ +	if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) +		required_pix_clk /= 2; +	else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) +		required_pix_clk = required_pix_clk * 2 / 3; + +	switch (timing->display_color_depth) { +	case COLOR_DEPTH_666: +	case COLOR_DEPTH_888: +		/*888 and 666 should always be supported*/ +		break; +	case COLOR_DEPTH_101010: +		if (dongle_caps->dp_hdmi_max_bpc < 10) +			return false; +		required_pix_clk = required_pix_clk * 10 / 8; +		break; +	case COLOR_DEPTH_121212: +		if (dongle_caps->dp_hdmi_max_bpc < 12) +			return false; +		required_pix_clk = required_pix_clk * 12 / 8; +		break; + +	case COLOR_DEPTH_141414: +	case COLOR_DEPTH_161616: +	default: +		/* These color depths are currently not supported */ +		return false; +	} + +	if (required_pix_clk > dongle_caps->dp_hdmi_max_pixel_clk) +		return false; + +	return true; +} +  enum dc_status dc_link_validate_mode_timing(  		const struct dc_stream_state *stream,  		struct dc_link *link,  		const struct dc_crtc_timing *timing)  {  	uint32_t max_pix_clk = stream->sink->dongle_max_pix_clk; +	struct dc_dongle_caps *dongle_caps = &link->link_status.dpcd_caps->dongle_caps;  	/* A hack to avoid failing any modes for EDID override feature on  	 * topology change such as lower quality cable for DP or different dongle @@ -1814,8 +1879,13 @@ enum dc_status dc_link_validate_mode_timing(  	if (link->remote_sinks[0])  		return DC_OK; +	/* Passive Dongle */  	if (0 != max_pix_clk && timing->pix_clk_khz > max_pix_clk) -		return DC_EXCEED_DONGLE_MAX_CLK; +		return DC_EXCEED_DONGLE_CAP; + +	/* Active Dongle*/ +	if (!dp_active_dongle_validate_timing(timing, dongle_caps)) +		return DC_EXCEED_DONGLE_CAP;  	switch (stream->signal) {  	case SIGNAL_TYPE_EDP: diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index ced42484dcfc..e6bf05d76a94 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -1512,7 +1512,7 @@ static bool hpd_rx_irq_check_link_loss_status(  	struct dc_link *link,  	union hpd_irq_data *hpd_irq_dpcd_data)  { -	uint8_t irq_reg_rx_power_state; +	uint8_t irq_reg_rx_power_state = 0;  	enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;  	union lane_status lane_status;  	uint32_t lane; @@ -1524,60 +1524,55 @@ static bool hpd_rx_irq_check_link_loss_status(  	if (link->cur_link_settings.lane_count == 0)  		return return_code; -	/*1. Check that we can handle interrupt: Not in FS DOS, -	 *  Not in "Display Timeout" state, Link is trained. -	 */ -	dpcd_result = core_link_read_dpcd(link, -		DP_SET_POWER, -		&irq_reg_rx_power_state, -		sizeof(irq_reg_rx_power_state)); +	/*1. Check that Link Status changed, before re-training.*/ -	if (dpcd_result != DC_OK) { -		irq_reg_rx_power_state = DP_SET_POWER_D0; -		dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, -			"%s: DPCD read failed to obtain power state.\n", -			__func__); +	/*parse lane status*/ +	for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { +		/* check status of lanes 0,1 +		 * changed DpcdAddress_Lane01Status (0x202) +		 */ +		lane_status.raw = get_nibble_at_index( +			&hpd_irq_dpcd_data->bytes.lane01_status.raw, +			lane); + +		if (!lane_status.bits.CHANNEL_EQ_DONE_0 || +			!lane_status.bits.CR_DONE_0 || +			!lane_status.bits.SYMBOL_LOCKED_0) { +			/* if one of the channel equalization, clock +			 * recovery or symbol lock is dropped +			 * consider it as (link has been +			 * dropped) dp sink status has changed +			 */ +			sink_status_changed = true; +			break; +		}  	} -	if (irq_reg_rx_power_state == DP_SET_POWER_D0) { - -		/*2. Check that Link Status changed, before re-training.*/ - -		/*parse lane status*/ -		for (lane = 0; -			lane < link->cur_link_settings.lane_count; -			lane++) { +	/* Check interlane align.*/ +	if (sink_status_changed || +		!hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { -			/* check status of lanes 0,1 -			 * changed DpcdAddress_Lane01Status (0x202)*/ -			lane_status.raw = get_nibble_at_index( -				&hpd_irq_dpcd_data->bytes.lane01_status.raw, -				lane); - -			if (!lane_status.bits.CHANNEL_EQ_DONE_0 || -				!lane_status.bits.CR_DONE_0 || -				!lane_status.bits.SYMBOL_LOCKED_0) { -				/* if one of the channel equalization, clock -				 * recovery or symbol lock is dropped -				 * consider it as (link has been -				 * dropped) dp sink status has changed*/ -				sink_status_changed = true; -				break; -			} +		dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, +			"%s: Link Status changed.\n", __func__); -		} +		return_code = true; -		/* Check interlane align.*/ -		if (sink_status_changed || -			!hpd_irq_dpcd_data->bytes.lane_status_updated.bits. -			INTERLANE_ALIGN_DONE) { +		/*2. Check that we can handle interrupt: Not in FS DOS, +		 *  Not in "Display Timeout" state, Link is trained. +		 */ +		dpcd_result = core_link_read_dpcd(link, +			DP_SET_POWER, +			&irq_reg_rx_power_state, +			sizeof(irq_reg_rx_power_state)); +		if (dpcd_result != DC_OK) {  			dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, -				"%s: Link Status changed.\n", +				"%s: DPCD read failed to obtain power state.\n",  				__func__); - -			return_code = true; +		} else { +			if (irq_reg_rx_power_state != DP_SET_POWER_D0) +				return_code = false;  		}  	} @@ -2062,6 +2057,24 @@ bool is_dp_active_dongle(const struct dc_link *link)  			(dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER);  } +static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc) +{ +	switch (bpc) { +	case DOWN_STREAM_MAX_8BPC: +		return 8; +	case DOWN_STREAM_MAX_10BPC: +		return 10; +	case DOWN_STREAM_MAX_12BPC: +		return 12; +	case DOWN_STREAM_MAX_16BPC: +		return 16; +	default: +		break; +	} + +	return -1; +} +  static void get_active_converter_info(  	uint8_t data, struct dc_link *link)  { @@ -2131,7 +2144,8 @@ static void get_active_converter_info(  					hdmi_caps.bits.YCrCr420_CONVERSION;  				link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc = -					hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT; +					translate_dpcd_max_bpc( +						hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT);  				link->dpcd_caps.dongle_caps.extendedCapValid = true;  			} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index d1cdf9f8853d..928895809867 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1,5 +1,5 @@  /* -* Copyright 2012-15 Advanced Micro Devices, Inc. + * Copyright 2012-15 Advanced Micro Devices, Inc.   *   * Permission is hereby granted, free of charge, to any person obtaining a   * copy of this software and associated documentation files (the "Software"), @@ -516,13 +516,11 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)  			right_view = (plane_state->rotation == ROTATION_ANGLE_270) != sec_split;  		if (right_view) { -			data->viewport.width /= 2; -			data->viewport_c.width /= 2; -			data->viewport.x +=  data->viewport.width; -			data->viewport_c.x +=  data->viewport_c.width; +			data->viewport.x +=  data->viewport.width / 2; +			data->viewport_c.x +=  data->viewport_c.width / 2;  			/* Ceil offset pipe */ -			data->viewport.width += data->viewport.width % 2; -			data->viewport_c.width += data->viewport_c.width % 2; +			data->viewport.width = (data->viewport.width + 1) / 2; +			data->viewport_c.width = (data->viewport_c.width + 1) / 2;  		} else {  			data->viewport.width /= 2;  			data->viewport_c.width /= 2; @@ -580,14 +578,12 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip  	if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state ==  		pipe_ctx->plane_state) {  		if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) { -			pipe_ctx->plane_res.scl_data.recout.height /= 2; -			pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height; +			pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height / 2;  			/* Floor primary pipe, ceil 2ndary pipe */ -			pipe_ctx->plane_res.scl_data.recout.height += pipe_ctx->plane_res.scl_data.recout.height % 2; +			pipe_ctx->plane_res.scl_data.recout.height = (pipe_ctx->plane_res.scl_data.recout.height + 1) / 2;  		} else { -			pipe_ctx->plane_res.scl_data.recout.width /= 2; -			pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width; -			pipe_ctx->plane_res.scl_data.recout.width += pipe_ctx->plane_res.scl_data.recout.width % 2; +			pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width / 2; +			pipe_ctx->plane_res.scl_data.recout.width = (pipe_ctx->plane_res.scl_data.recout.width + 1) / 2;  		}  	} else if (pipe_ctx->bottom_pipe &&  			pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state) { @@ -856,6 +852,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)  	pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;  	pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + timing->v_border_top + timing->v_border_bottom; +  	/* Taps calculations */  	if (pipe_ctx->plane_res.xfm != NULL)  		res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( @@ -864,16 +861,21 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)  	if (pipe_ctx->plane_res.dpp != NULL)  		res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(  				pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); -  	if (!res) {  		/* Try 24 bpp linebuffer */  		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP; -		res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( -			pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); +		if (pipe_ctx->plane_res.xfm != NULL) +			res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( +					pipe_ctx->plane_res.xfm, +					&pipe_ctx->plane_res.scl_data, +					&plane_state->scaling_quality); -		res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( -			pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); +		if (pipe_ctx->plane_res.dpp != NULL) +			res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( +					pipe_ctx->plane_res.dpp, +					&pipe_ctx->plane_res.scl_data, +					&plane_state->scaling_quality);  	}  	if (res) @@ -991,8 +993,10 @@ static struct pipe_ctx *acquire_free_pipe_for_stream(  	head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream); -	if (!head_pipe) +	if (!head_pipe) {  		ASSERT(0); +		return NULL; +	}  	if (!head_pipe->plane_state)  		return head_pipe; @@ -1447,11 +1451,16 @@ static struct stream_encoder *find_first_free_match_stream_enc_for_link(  static struct audio *find_first_free_audio(  		struct resource_context *res_ctx, -		const struct resource_pool *pool) +		const struct resource_pool *pool, +		enum engine_id id)  {  	int i;  	for (i = 0; i < pool->audio_count; i++) {  		if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) { +			/*we have enough audio endpoint, find the matching inst*/ +			if (id != i) +				continue; +  			return pool->audios[i];  		}  	} @@ -1700,7 +1709,7 @@ enum dc_status resource_map_pool_resources(  	    dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&  	    stream->audio_info.mode_count) {  		pipe_ctx->stream_res.audio = find_first_free_audio( -		&context->res_ctx, pool); +		&context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id);  		/*  		 * Audio assigned in order first come first get. @@ -1765,13 +1774,16 @@ enum dc_status dc_validate_global_state(  	enum dc_status result = DC_ERROR_UNEXPECTED;  	int i, j; +	if (!new_ctx) +		return DC_ERROR_UNEXPECTED; +  	if (dc->res_pool->funcs->validate_global) {  			result = dc->res_pool->funcs->validate_global(dc, new_ctx);  			if (result != DC_OK)  				return result;  	} -	for (i = 0; new_ctx && i < new_ctx->stream_count; i++) { +	for (i = 0; i < new_ctx->stream_count; i++) {  		struct dc_stream_state *stream = new_ctx->streams[i];  		for (j = 0; j < dc->res_pool->pipe_count; j++) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index b00a6040a697..e230cc44a0a7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -263,7 +263,6 @@ bool dc_stream_set_cursor_position(  		struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp;  		struct mem_input *mi = pipe_ctx->plane_res.mi;  		struct hubp *hubp = pipe_ctx->plane_res.hubp; -		struct transform *xfm = pipe_ctx->plane_res.xfm;  		struct dpp *dpp = pipe_ctx->plane_res.dpp;  		struct dc_cursor_position pos_cpy = *position;  		struct dc_cursor_mi_param param = { @@ -294,11 +293,11 @@ bool dc_stream_set_cursor_position(  		if (mi != NULL && mi->funcs->set_cursor_position != NULL)  			mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); -		if (hubp != NULL && hubp->funcs->set_cursor_position != NULL) -			hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); +		if (!hubp) +			continue; -		if (xfm != NULL && xfm->funcs->set_cursor_position != NULL) -			xfm->funcs->set_cursor_position(xfm, &pos_cpy, ¶m, hubp->curs_attr.width); +		if (hubp->funcs->set_cursor_position != NULL) +			hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m);  		if (dpp != NULL && dpp->funcs->set_cursor_position != NULL)  			dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index 0d84b2a1ccfd..90e81f7ba919 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -1,4 +1,26 @@  /* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +/*   * dc_helper.c   *   *  Created on: Aug 30, 2016 diff --git a/drivers/gpu/drm/amd/display/dc/dce/Makefile b/drivers/gpu/drm/amd/display/dc/dce/Makefile index 8abec0bed379..11401fd8e535 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for common 'dce' logic  # HW object file under this folder follow similar pattern for HW programming  #   - register offset and/or shift + mask stored in the dec_hw struct diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index 81c40f8864db..0df9ecb2710c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -352,11 +352,11 @@ void dce_aud_az_enable(struct audio *audio)  	uint32_t value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);  	set_reg_field_value(value, 1, -			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, -			CLOCK_GATING_DISABLE); -		set_reg_field_value(value, 1, -			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, -			AUDIO_ENABLED); +			    AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, +			    CLOCK_GATING_DISABLE); +	set_reg_field_value(value, 1, +			    AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, +			    AUDIO_ENABLED);  	AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);  	value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index 4fd49a16c3b6..e42b6eb1c1f0 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -87,6 +87,9 @@ static void dce110_update_generic_info_packet(  	 */  	uint32_t max_retries = 50; +	/*we need turn on clock before programming AFMT block*/ +	REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1); +  	if (REG(AFMT_VBI_PACKET_CONTROL1)) {  		if (packet_index >= 8)  			ASSERT(0); diff --git a/drivers/gpu/drm/amd/display/dc/dce100/Makefile b/drivers/gpu/drm/amd/display/dc/dce100/Makefile index ea40870624b3..a822d4e2a169 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce100/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'controller' sub-component of DAL.  # It provides the control and status of HW CRTC block. diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 90911258bdb3..3ea43e2a9450 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -1,5 +1,5 @@  /* -* Copyright 2012-15 Advanced Micro Devices, Inc. + * Copyright 2012-15 Advanced Micro Devices, Inc.   *   * Permission is hereby granted, free of charge, to any person obtaining a   * copy of this software and associated documentation files (the "Software"), diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h index de8fdf438f9b..2f366d66635d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h @@ -1,4 +1,27 @@  /* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + */ +/*   * dce100_resource.h   *   *  Created on: 2016-01-20 diff --git a/drivers/gpu/drm/amd/display/dc/dce110/Makefile b/drivers/gpu/drm/amd/display/dc/dce110/Makefile index 98d956e2f218..d564c0eb8b04 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce110/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'controller' sub-component of DAL.  # It provides the control and status of HW CRTC block. diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 1229a3315018..d844fadcd56f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -991,6 +991,16 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option)  	struct dc_link *link = stream->sink->link;  	struct dc *dc = pipe_ctx->stream->ctx->dc; +	if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) +		pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets( +			pipe_ctx->stream_res.stream_enc); + +	if (dc_is_dp_signal(pipe_ctx->stream->signal)) +		pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets( +			pipe_ctx->stream_res.stream_enc); + +	pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( +			pipe_ctx->stream_res.stream_enc, true);  	if (pipe_ctx->stream_res.audio) {  		pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); @@ -1015,18 +1025,6 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option)  		 */  	} -	if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) -		pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets( -			pipe_ctx->stream_res.stream_enc); - -	if (dc_is_dp_signal(pipe_ctx->stream->signal)) -		pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets( -			pipe_ctx->stream_res.stream_enc); - -	pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( -			pipe_ctx->stream_res.stream_enc, true); - -  	/* blank at encoder level */  	if (dc_is_dp_signal(pipe_ctx->stream->signal)) {  		if (pipe_ctx->stream->sink->link->connector_signal == SIGNAL_TYPE_EDP) @@ -1774,6 +1772,10 @@ static enum dc_status validate_fbc(struct dc *dc,  	if (pipe_ctx->stream->sink->link->psr_enabled)  		return DC_ERROR_UNEXPECTED; +	/* Nothing to compress */ +	if (!pipe_ctx->plane_state) +		return DC_ERROR_UNEXPECTED; +  	/* Only for non-linear tiling */  	if (pipe_ctx->plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL)  		return DC_ERROR_UNEXPECTED; @@ -1868,8 +1870,10 @@ static void dce110_reset_hw_ctx_wrap(  				pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {  			struct clock_source *old_clk = pipe_ctx_old->clock_source; -			/* disable already, no need to disable again */ -			if (pipe_ctx->stream && !pipe_ctx->stream->dpms_off) +			/* Disable if new stream is null. O/w, if stream is +			 * disabled already, no need to disable again. +			 */ +			if (!pipe_ctx->stream || !pipe_ctx->stream->dpms_off)  				core_link_disable_stream(pipe_ctx_old, FREE_ACQUIRED_RESOURCE);  			pipe_ctx_old->stream_res.tg->funcs->set_blank(pipe_ctx_old->stream_res.tg, true); @@ -2862,16 +2866,19 @@ static void dce110_apply_ctx_for_surface(  		int num_planes,  		struct dc_state *context)  { -	int i, be_idx; +	int i;  	if (num_planes == 0)  		return; -	be_idx = -1;  	for (i = 0; i < dc->res_pool->pipe_count; i++) { -		if (stream == context->res_ctx.pipe_ctx[i].stream) { -			be_idx = context->res_ctx.pipe_ctx[i].stream_res.tg->inst; -			break; +		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; +		struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + +		if (stream == pipe_ctx->stream) { +			if (!pipe_ctx->top_pipe && +				(pipe_ctx->plane_state || old_pipe_ctx->plane_state)) +				dc->hwss.pipe_control_lock(dc, pipe_ctx, true);  		}  	} @@ -2891,9 +2898,22 @@ static void dce110_apply_ctx_for_surface(  					context->stream_count);  		dce110_program_front_end_for_pipe(dc, pipe_ctx); + +		dc->hwss.update_plane_addr(dc, pipe_ctx); +  		program_surface_visibility(dc, pipe_ctx);  	} + +	for (i = 0; i < dc->res_pool->pipe_count; i++) { +		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; +		struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + +		if ((stream == pipe_ctx->stream) && +			(!pipe_ctx->top_pipe) && +			(pipe_ctx->plane_state || old_pipe_ctx->plane_state)) +			dc->hwss.pipe_control_lock(dc, pipe_ctx, false); +	}  }  static void dce110_power_down_fe(struct dc *dc, int fe_idx) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index db96d2b47ff1..42df17f9aa8d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -1,5 +1,5 @@  /* -* Copyright 2012-15 Advanced Micro Devices, Inc. + * Copyright 2012-15 Advanced Micro Devices, Inc.   *   * Permission is hereby granted, free of charge, to any person obtaining a   * copy of this software and associated documentation files (the "Software"), @@ -1037,11 +1037,13 @@ static bool underlay_create(struct dc_context *ctx, struct resource_pool *pool)  	struct dce110_opp *dce110_oppv = kzalloc(sizeof(*dce110_oppv),  						 GFP_KERNEL); -	if ((dce110_tgv == NULL) || -		(dce110_xfmv == NULL) || -		(dce110_miv == NULL) || -		(dce110_oppv == NULL)) -			return false; +	if (!dce110_tgv || !dce110_xfmv || !dce110_miv || !dce110_oppv) { +		kfree(dce110_tgv); +		kfree(dce110_xfmv); +		kfree(dce110_miv); +		kfree(dce110_oppv); +		return false; +	}  	dce110_opp_v_construct(dce110_oppv, ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c index 67ac737eaa7e..4befce6cd87a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c @@ -1112,10 +1112,7 @@ bool dce110_timing_generator_validate_timing(  	enum signal_type signal)  {  	uint32_t h_blank; -	uint32_t h_back_porch; -	uint32_t hsync_offset = timing->h_border_right + -			timing->h_front_porch; -	uint32_t h_sync_start = timing->h_addressable + hsync_offset; +	uint32_t h_back_porch, hsync_offset, h_sync_start;  	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); @@ -1124,6 +1121,9 @@ bool dce110_timing_generator_validate_timing(  	if (!timing)  		return false; +	hsync_offset = timing->h_border_right + timing->h_front_porch; +	h_sync_start = timing->h_addressable + hsync_offset; +  	/* Currently we don't support 3D, so block all 3D timings */  	if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE)  		return false; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c index 07d9303d5477..59b4cd329715 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c @@ -1,3 +1,26 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +  #include "dm_services.h"  /* include DCE11 register header files */ diff --git a/drivers/gpu/drm/amd/display/dc/dce112/Makefile b/drivers/gpu/drm/amd/display/dc/dce112/Makefile index 265ac4310d85..8e090446d511 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce112/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'controller' sub-component of DAL.  # It provides the control and status of HW CRTC block. diff --git a/drivers/gpu/drm/amd/display/dc/dce120/Makefile b/drivers/gpu/drm/amd/display/dc/dce120/Makefile index 1779b963525c..37db1f8d45ea 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce120/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'controller' sub-component of DAL.  # It provides the control and status of HW CRTC block. @@ -8,4 +29,4 @@ dce120_hw_sequencer.o  AMD_DAL_DCE120 = $(addprefix $(AMDDALPATH)/dc/dce120/,$(DCE120)) -AMD_DISPLAY_FILES += $(AMD_DAL_DCE120)
\ No newline at end of file +AMD_DISPLAY_FILES += $(AMD_DAL_DCE120) diff --git a/drivers/gpu/drm/amd/display/dc/dce80/Makefile b/drivers/gpu/drm/amd/display/dc/dce80/Makefile index c1105895e5fa..bc388aa4b2f5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce80/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'controller' sub-component of DAL.  # It provides the control and status of HW CRTC block. diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index ebeb88283a14..f565a6042970 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for DCN.  DCN10 = dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index 74e7c82bdc76..a9d55d0dd69e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -159,11 +159,10 @@ bool dpp_get_optimal_number_of_taps(  			scl_data->taps.h_taps = 1;  		if (IDENTITY_RATIO(scl_data->ratios.vert))  			scl_data->taps.v_taps = 1; -		/* -		 * Spreadsheet doesn't handle taps_c is one properly, -		 * need to force Chroma to always be scaled to pass -		 * bandwidth validation. -		 */ +		if (IDENTITY_RATIO(scl_data->ratios.horz_c)) +			scl_data->taps.h_taps_c = 1; +		if (IDENTITY_RATIO(scl_data->ratios.vert_c)) +			scl_data->taps.v_taps_c = 1;  	}  	return true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index a9782b1aba47..34daf895f848 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -1360,7 +1360,7 @@ void dpp1_cm_set_output_csc_adjustment(  void dpp1_cm_set_output_csc_default(  		struct dpp *dpp_base, -		const struct default_adjustment *default_adjust); +		enum dc_color_space colorspace);  void dpp1_cm_set_gamut_remap(  	struct dpp *dpp, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index 40627c244bf5..ed1216b53465 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -225,14 +225,13 @@ void dpp1_cm_set_gamut_remap(  void dpp1_cm_set_output_csc_default(  		struct dpp *dpp_base, -		const struct default_adjustment *default_adjust) +		enum dc_color_space colorspace)  {  	struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);  	uint32_t ocsc_mode = 0; -	if (default_adjust != NULL) { -		switch (default_adjust->out_color_space) { +	switch (colorspace) {  		case COLOR_SPACE_SRGB:  		case COLOR_SPACE_2020_RGB_FULLRANGE:  			ocsc_mode = 0; @@ -253,7 +252,6 @@ void dpp1_cm_set_output_csc_default(  		case COLOR_SPACE_UNKNOWN:  		default:  			break; -		}  	}  	REG_SET(CM_OCSC_CONTROL, 0, CM_OCSC_MODE, ocsc_mode); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 961ad5c3b454..05dc01e54531 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2097,6 +2097,8 @@ static void program_csc_matrix(struct pipe_ctx *pipe_ctx,  			tbl_entry.color_space = color_space;  			//tbl_entry.regval = matrix;  			pipe_ctx->plane_res.dpp->funcs->opp_set_csc_adjustment(pipe_ctx->plane_res.dpp, &tbl_entry); +	} else { +		pipe_ctx->plane_res.dpp->funcs->opp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace);  	}  }  static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 4c4bd72d4e40..9fc8f827f2a1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -912,11 +912,13 @@ static struct pipe_ctx *dcn10_acquire_idle_pipe_for_layer(  	struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);  	struct pipe_ctx *idle_pipe = find_idle_secondary_pipe(res_ctx, pool); -	if (!head_pipe) +	if (!head_pipe) {  		ASSERT(0); +		return NULL; +	}  	if (!idle_pipe) -		return false; +		return NULL;  	idle_pipe->stream = head_pipe->stream;  	idle_pipe->stream_res.tg = head_pipe->stream_res.tg; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c index c7333cdf1802..fced178c8c79 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c @@ -496,9 +496,6 @@ static bool tgn10_validate_timing(  		timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA)  		return false; -	if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE && -		tg->ctx->dc->debug.disable_stereo_support) -		return false;  	/* Temporarily blocking interlacing mode until it's supported */  	if (timing->flags.INTERLACE == 1)  		return false; diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 87bab8e8139f..3488af2b5786 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'utils' sub-component of DAL.  # It provides the general basic services required by other DAL  # subcomponents. diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile index 70d01a9e9676..562ee189d780 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'gpio' sub-component of DAL.  # It provides the control and status of HW GPIO pins. diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile index 55603400acd9..352885cb4d07 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile +++ b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'i2c' sub-component of DAL.  # It provides the control and status of HW i2c engine of the adapter. diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h index 01df85641684..94fc31080fda 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h @@ -38,7 +38,7 @@ enum dc_status {  	DC_FAIL_DETACH_SURFACES = 8,  	DC_FAIL_SURFACE_VALIDATE = 9,  	DC_NO_DP_LINK_BANDWIDTH = 10, -	DC_EXCEED_DONGLE_MAX_CLK = 11, +	DC_EXCEED_DONGLE_CAP = 11,  	DC_SURFACE_PIXEL_FORMAT_UNSUPPORTED = 12,  	DC_FAIL_BANDWIDTH_VALIDATE = 13, /* BW and Watermark validation */  	DC_FAIL_SCALING = 14, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 83a68460edcd..9420dfb94d39 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -64,7 +64,7 @@ struct dpp_funcs {  	void (*opp_set_csc_default)(  		struct dpp *dpp, -		const struct default_adjustment *default_adjust); +		enum dc_color_space colorspace);  	void (*opp_set_csc_adjustment)(  		struct dpp *dpp, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index 3d33bcda7059..498b7f05c5ca 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -1,4 +1,26 @@  /* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +/*   * link_encoder.h   *   *  Created on: Oct 6, 2015 diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h index 3050afe8e8a9..b5db1692393c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h @@ -1,4 +1,26 @@  /* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +/*   * stream_encoder.h   *   */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h index 7c08bc62c1f5..ea88997e1bbd 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h @@ -259,13 +259,6 @@ struct transform_funcs {  			struct transform *xfm_base,  			const struct dc_cursor_attributes *attr); -	void (*set_cursor_position)( -			struct transform *xfm_base, -			const struct dc_cursor_position *pos, -			const struct dc_cursor_mi_param *param, -			uint32_t width -			); -  };  const uint16_t *get_filter_2tap_16p(void); diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index c7e93f7223bd..498515aad4a5 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'audio' sub-component of DAL.  # It provides the control and status of HW adapter resources,  # that are global for the ASIC and sharable between pipes. diff --git a/drivers/gpu/drm/amd/display/dc/virtual/Makefile b/drivers/gpu/drm/amd/display/dc/virtual/Makefile index fc0b7318d9cc..07326d244d50 100644 --- a/drivers/gpu/drm/amd/display/dc/virtual/Makefile +++ b/drivers/gpu/drm/amd/display/dc/virtual/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the virtual sub-component of DAL.  # It provides the control and status of HW CRTC block. diff --git a/drivers/gpu/drm/amd/display/modules/freesync/Makefile b/drivers/gpu/drm/amd/display/modules/freesync/Makefile index db8e0ff6d7a9..fb9a499780e8 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/Makefile +++ b/drivers/gpu/drm/amd/display/modules/freesync/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'freesync' sub-module of DAL.  # diff --git a/drivers/gpu/drm/amd/lib/Makefile b/drivers/gpu/drm/amd/lib/Makefile index 87cd7009e80f..690243001e1a 100644 --- a/drivers/gpu/drm/amd/lib/Makefile +++ b/drivers/gpu/drm/amd/lib/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for AMD library routines, which are used by AMD driver  # components.  # diff --git a/drivers/gpu/drm/amd/powerplay/Makefile b/drivers/gpu/drm/amd/powerplay/Makefile index 8c55c6e254d9..231785a9e24c 100644 --- a/drivers/gpu/drm/amd/powerplay/Makefile +++ b/drivers/gpu/drm/amd/powerplay/Makefile @@ -1,4 +1,24 @@ -# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +#  subdir-ccflags-y += \  		-I$(FULL_AMD_PATH)/powerplay/inc/  \ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile index 824fb6fe54ae..a212c27f2e17 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile @@ -1,4 +1,24 @@ -# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +#  #  # Makefile for the 'hw manager' sub-component of powerplay.  # It provides the hardware management services for the driver. diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_overdriver.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_overdriver.c index 67fae834bc67..8de384bf9a8f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_overdriver.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_overdriver.c @@ -1,4 +1,26 @@ -// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +  #include "pp_overdriver.h"  #include <linux/errno.h> diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu72.h b/drivers/gpu/drm/amd/powerplay/inc/smu72.h index 08cd70c75d8b..9ad1cefff79f 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu72.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu72.h @@ -1,4 +1,26 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +  #ifndef SMU72_H  #define SMU72_H diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h b/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h index b2edbc0c3c4d..2aefbb85f620 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu72_discrete.h @@ -1,4 +1,26 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +  #ifndef SMU72_DISCRETE_H  #define SMU72_DISCRETE_H diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile index 30d3089d7dba..98e701e4f553 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile @@ -1,4 +1,24 @@ -# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +#  #  # Makefile for the 'smu manager' sub-component of powerplay.  # It provides the smu management services for the driver. diff --git a/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h b/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h index 283a0dc25e84..07129e6c31a9 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h @@ -1,4 +1,26 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +  #if !defined(_GPU_SCHED_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)  #define _GPU_SCHED_TRACE_H_ diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index 72b22b805412..5a5427bbd70e 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -317,9 +317,8 @@ static struct drm_plane *hdlcd_plane_init(struct drm_device *drm)  				       formats, ARRAY_SIZE(formats),  				       NULL,  				       DRM_PLANE_TYPE_PRIMARY, NULL); -	if (ret) { +	if (ret)  		return ERR_PTR(ret); -	}  	drm_plane_helper_add(plane, &hdlcd_plane_helper_funcs);  	hdlcd->plane = plane; diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 764d0c83710c..0afb53b1f4e9 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -13,6 +13,7 @@  #include <linux/spinlock.h>  #include <linux/clk.h>  #include <linux/component.h> +#include <linux/console.h>  #include <linux/list.h>  #include <linux/of_graph.h>  #include <linux/of_reserved_mem.h> @@ -354,7 +355,7 @@ err_unload:  err_free:  	drm_mode_config_cleanup(drm);  	dev_set_drvdata(dev, NULL); -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return ret;  } @@ -379,7 +380,7 @@ static void hdlcd_drm_unbind(struct device *dev)  	pm_runtime_disable(drm->dev);  	of_reserved_mem_device_release(drm->dev);  	drm_mode_config_cleanup(drm); -	drm_dev_unref(drm); +	drm_dev_put(drm);  	drm->dev_private = NULL;  	dev_set_drvdata(dev, NULL);  } @@ -432,9 +433,11 @@ static int __maybe_unused hdlcd_pm_suspend(struct device *dev)  		return 0;  	drm_kms_helper_poll_disable(drm); +	drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 1);  	hdlcd->state = drm_atomic_helper_suspend(drm);  	if (IS_ERR(hdlcd->state)) { +		drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 0);  		drm_kms_helper_poll_enable(drm);  		return PTR_ERR(hdlcd->state);  	} @@ -451,8 +454,8 @@ static int __maybe_unused hdlcd_pm_resume(struct device *dev)  		return 0;  	drm_atomic_helper_resume(drm, hdlcd->state); +	drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 0);  	drm_kms_helper_poll_enable(drm); -	pm_runtime_set_active(dev);  	return 0;  } diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 3615d18a7ddf..904fff80917b 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -65,8 +65,8 @@ static void malidp_crtc_atomic_enable(struct drm_crtc *crtc,  	/* We rely on firmware to set mclk to a sensible level. */  	clk_set_rate(hwdev->pxlclk, crtc->state->adjusted_mode.crtc_clock * 1000); -	hwdev->modeset(hwdev, &vm); -	hwdev->leave_config_mode(hwdev); +	hwdev->hw->modeset(hwdev, &vm); +	hwdev->hw->leave_config_mode(hwdev);  	drm_crtc_vblank_on(crtc);  } @@ -77,8 +77,12 @@ static void malidp_crtc_atomic_disable(struct drm_crtc *crtc,  	struct malidp_hw_device *hwdev = malidp->dev;  	int err; +	/* always disable planes on the CRTC that is being turned off */ +	drm_atomic_helper_disable_planes_on_crtc(old_state, false); +  	drm_crtc_vblank_off(crtc); -	hwdev->enter_config_mode(hwdev); +	hwdev->hw->enter_config_mode(hwdev); +  	clk_disable_unprepare(hwdev->pxlclk);  	err = pm_runtime_put(crtc->dev->dev); @@ -319,7 +323,7 @@ static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc,  mclk_calc:  	drm_display_mode_to_videomode(&state->adjusted_mode, &vm); -	ret = hwdev->se_calc_mclk(hwdev, s, &vm); +	ret = hwdev->hw->se_calc_mclk(hwdev, s, &vm);  	if (ret < 0)  		return -EINVAL;  	return 0; @@ -475,7 +479,7 @@ static int malidp_crtc_enable_vblank(struct drm_crtc *crtc)  	struct malidp_hw_device *hwdev = malidp->dev;  	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, -			     hwdev->map.de_irq_map.vsync_irq); +			     hwdev->hw->map.de_irq_map.vsync_irq);  	return 0;  } @@ -485,7 +489,7 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc)  	struct malidp_hw_device *hwdev = malidp->dev;  	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, -			      hwdev->map.de_irq_map.vsync_irq); +			      hwdev->hw->map.de_irq_map.vsync_irq);  }  static const struct drm_crtc_funcs malidp_crtc_funcs = { diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index b8944666a18f..91f2b0191368 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -47,10 +47,10 @@ static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,  	 * directly.  	 */  	malidp_hw_write(hwdev, gamma_write_mask, -			hwdev->map.coeffs_base + MALIDP_COEF_TABLE_ADDR); +			hwdev->hw->map.coeffs_base + MALIDP_COEF_TABLE_ADDR);  	for (i = 0; i < MALIDP_COEFFTAB_NUM_COEFFS; ++i)  		malidp_hw_write(hwdev, data[i], -				hwdev->map.coeffs_base + +				hwdev->hw->map.coeffs_base +  				MALIDP_COEF_TABLE_DATA);  } @@ -103,7 +103,7 @@ void malidp_atomic_commit_update_coloradj(struct drm_crtc *crtc,  			for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; ++i)  				malidp_hw_write(hwdev,  						mc->coloradj_coeffs[i], -						hwdev->map.coeffs_base + +						hwdev->hw->map.coeffs_base +  						MALIDP_COLOR_ADJ_COEF + 4 * i);  		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_CADJ, @@ -120,8 +120,8 @@ static void malidp_atomic_commit_se_config(struct drm_crtc *crtc,  	struct malidp_hw_device *hwdev = malidp->dev;  	struct malidp_se_config *s = &cs->scaler_config;  	struct malidp_se_config *old_s = &old_cs->scaler_config; -	u32 se_control = hwdev->map.se_base + -			 ((hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ? +	u32 se_control = hwdev->hw->map.se_base + +			 ((hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ?  			 0x10 : 0xC);  	u32 layer_control = se_control + MALIDP_SE_LAYER_CONTROL;  	u32 scr = se_control + MALIDP_SE_SCALING_CONTROL; @@ -135,7 +135,7 @@ static void malidp_atomic_commit_se_config(struct drm_crtc *crtc,  		return;  	} -	hwdev->se_set_scaling_coeffs(hwdev, s, old_s); +	hwdev->hw->se_set_scaling_coeffs(hwdev, s, old_s);  	val = malidp_hw_read(hwdev, se_control);  	val |= MALIDP_SE_SCALING_EN | MALIDP_SE_ALPHA_EN; @@ -170,9 +170,9 @@ static int malidp_set_and_wait_config_valid(struct drm_device *drm)  	int ret;  	atomic_set(&malidp->config_valid, 0); -	hwdev->set_config_valid(hwdev); +	hwdev->hw->set_config_valid(hwdev);  	/* don't wait for config_valid flag if we are in config mode */ -	if (hwdev->in_config_mode(hwdev)) +	if (hwdev->hw->in_config_mode(hwdev))  		return 0;  	ret = wait_event_interruptible_timeout(malidp->wq, @@ -455,7 +455,7 @@ static int malidp_runtime_pm_suspend(struct device *dev)  	struct malidp_hw_device *hwdev = malidp->dev;  	/* we can only suspend if the hardware is in config mode */ -	WARN_ON(!hwdev->in_config_mode(hwdev)); +	WARN_ON(!hwdev->hw->in_config_mode(hwdev));  	hwdev->pm_suspended = true;  	clk_disable_unprepare(hwdev->mclk); @@ -500,11 +500,7 @@ static int malidp_bind(struct device *dev)  	if (!hwdev)  		return -ENOMEM; -	/* -	 * copy the associated data from malidp_drm_of_match to avoid -	 * having to keep a reference to the OF node after binding -	 */ -	memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev)); +	hwdev->hw = (struct malidp_hw *)of_device_get_match_data(dev);  	malidp->dev = hwdev;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -568,13 +564,13 @@ static int malidp_bind(struct device *dev)  		goto query_hw_fail;  	} -	ret = hwdev->query_hw(hwdev); +	ret = hwdev->hw->query_hw(hwdev);  	if (ret) {  		DRM_ERROR("Invalid HW configuration\n");  		goto query_hw_fail;  	} -	version = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_DE_CORE_ID); +	version = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_DE_CORE_ID);  	DRM_INFO("found ARM Mali-DP%3x version r%dp%d\n", version >> 16,  		 (version >> 12) & 0xf, (version >> 8) & 0xf); @@ -589,7 +585,7 @@ static int malidp_bind(struct device *dev)  	for (i = 0; i < MAX_OUTPUT_CHANNELS; i++)  		out_depth = (out_depth << 8) | (output_width[i] & 0xf); -	malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base); +	malidp_hw_write(hwdev, out_depth, hwdev->hw->map.out_depth_base);  	atomic_set(&malidp->config_valid, 0);  	init_waitqueue_head(&malidp->wq); @@ -671,7 +667,7 @@ query_hw_fail:  		malidp_runtime_pm_suspend(dev);  	drm->dev_private = NULL;  	dev_set_drvdata(dev, NULL); -	drm_dev_unref(drm); +	drm_dev_put(drm);  alloc_fail:  	of_reserved_mem_device_release(dev); @@ -704,7 +700,7 @@ static void malidp_unbind(struct device *dev)  		malidp_runtime_pm_suspend(dev);  	drm->dev_private = NULL;  	dev_set_drvdata(dev, NULL); -	drm_dev_unref(drm); +	drm_dev_put(drm);  	of_reserved_mem_device_release(dev);  } diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 17bca99e8ac8..2bfb542135ac 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -183,7 +183,7 @@ static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)  	malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);  	while (count) { -		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); +		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);  		if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)  			break;  		/* @@ -203,7 +203,7 @@ static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)  	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);  	malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);  	while (count) { -		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); +		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);  		if ((status & MALIDP500_DC_CONFIG_REQ) == 0)  			break;  		usleep_range(100, 1000); @@ -216,7 +216,7 @@ static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)  {  	u32 status; -	status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); +	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);  	if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)  		return true; @@ -407,7 +407,7 @@ static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)  	malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);  	while (count) { -		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); +		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);  		if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)  			break;  		/* @@ -427,7 +427,7 @@ static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)  	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);  	malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);  	while (count) { -		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); +		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);  		if ((status & MALIDP550_DC_CONFIG_REQ) == 0)  			break;  		usleep_range(100, 1000); @@ -440,7 +440,7 @@ static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)  {  	u32 status; -	status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); +	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);  	if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)  		return true; @@ -616,7 +616,7 @@ static int malidp650_query_hw(struct malidp_hw_device *hwdev)  	return 0;  } -const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { +const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {  	[MALIDP_500] = {  		.map = {  			.coeffs_base = MALIDP500_COEFFS_BASE, @@ -751,7 +751,7 @@ static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 ir  {  	u32 base = malidp_get_block_base(hwdev, block); -	if (hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) +	if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)  		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);  	else  		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS); @@ -762,12 +762,14 @@ static irqreturn_t malidp_de_irq(int irq, void *arg)  	struct drm_device *drm = arg;  	struct malidp_drm *malidp = drm->dev_private;  	struct malidp_hw_device *hwdev; +	struct malidp_hw *hw;  	const struct malidp_irq_map *de;  	u32 status, mask, dc_status;  	irqreturn_t ret = IRQ_NONE;  	hwdev = malidp->dev; -	de = &hwdev->map.de_irq_map; +	hw = hwdev->hw; +	de = &hw->map.de_irq_map;  	/*  	 * if we are suspended it is likely that we were invoked because @@ -778,8 +780,8 @@ static irqreturn_t malidp_de_irq(int irq, void *arg)  		return IRQ_NONE;  	/* first handle the config valid IRQ */ -	dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS); -	if (dc_status & hwdev->map.dc_irq_map.vsync_irq) { +	dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); +	if (dc_status & hw->map.dc_irq_map.vsync_irq) {  		/* we have a page flip event */  		atomic_set(&malidp->config_valid, 1);  		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status); @@ -832,11 +834,11 @@ int malidp_de_irq_init(struct drm_device *drm, int irq)  	/* first enable the DC block IRQs */  	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK, -			     hwdev->map.dc_irq_map.irq_mask); +			     hwdev->hw->map.dc_irq_map.irq_mask);  	/* now enable the DE block IRQs */  	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, -			     hwdev->map.de_irq_map.irq_mask); +			     hwdev->hw->map.de_irq_map.irq_mask);  	return 0;  } @@ -847,9 +849,9 @@ void malidp_de_irq_fini(struct drm_device *drm)  	struct malidp_hw_device *hwdev = malidp->dev;  	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, -			      hwdev->map.de_irq_map.irq_mask); +			      hwdev->hw->map.de_irq_map.irq_mask);  	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, -			      hwdev->map.dc_irq_map.irq_mask); +			      hwdev->hw->map.dc_irq_map.irq_mask);  }  static irqreturn_t malidp_se_irq(int irq, void *arg) @@ -857,6 +859,8 @@ static irqreturn_t malidp_se_irq(int irq, void *arg)  	struct drm_device *drm = arg;  	struct malidp_drm *malidp = drm->dev_private;  	struct malidp_hw_device *hwdev = malidp->dev; +	struct malidp_hw *hw = hwdev->hw; +	const struct malidp_irq_map *se = &hw->map.se_irq_map;  	u32 status, mask;  	/* @@ -867,12 +871,12 @@ static irqreturn_t malidp_se_irq(int irq, void *arg)  	if (hwdev->pm_suspended)  		return IRQ_NONE; -	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS); -	if (!(status & hwdev->map.se_irq_map.irq_mask)) +	status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); +	if (!(status & se->irq_mask))  		return IRQ_NONE; -	mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ); -	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS); +	mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ); +	status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);  	status &= mask;  	/* ToDo: status decoding and firing up of VSYNC and page flip events */ @@ -905,7 +909,7 @@ int malidp_se_irq_init(struct drm_device *drm, int irq)  	}  	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, -			     hwdev->map.se_irq_map.irq_mask); +			     hwdev->hw->map.se_irq_map.irq_mask);  	return 0;  } @@ -916,5 +920,5 @@ void malidp_se_irq_fini(struct drm_device *drm)  	struct malidp_hw_device *hwdev = malidp->dev;  	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, -			      hwdev->map.se_irq_map.irq_mask); +			      hwdev->hw->map.se_irq_map.irq_mask);  } diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index 849ad9a30c3a..b0690ebb3565 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -120,18 +120,14 @@ struct malidp_hw_regmap {  /* Unlike DP550/650, DP500 has 3 stride registers in its video layer. */  #define MALIDP_DEVICE_LV_HAS_3_STRIDES	BIT(0) -struct malidp_hw_device { -	const struct malidp_hw_regmap map; -	void __iomem *regs; +struct malidp_hw_device; -	/* APB clock */ -	struct clk *pclk; -	/* AXI clock */ -	struct clk *aclk; -	/* main clock for display core */ -	struct clk *mclk; -	/* pixel clock for display core */ -	struct clk *pxlclk; +/* + * Static structure containing hardware specific data and pointers to + * functions that behave differently between various versions of the IP. + */ +struct malidp_hw { +	const struct malidp_hw_regmap map;  	/*  	 * Validate the driver instance against the hardware bits @@ -182,15 +178,6 @@ struct malidp_hw_device {  			     struct videomode *vm);  	u8 features; - -	u8 min_line_size; -	u16 max_line_size; - -	/* track the device PM state */ -	bool pm_suspended; - -	/* size of memory used for rotating layers, up to two banks available */ -	u32 rotation_memory[2];  };  /* Supported variants of the hardware */ @@ -202,7 +189,33 @@ enum {  	MALIDP_MAX_DEVICES  }; -extern const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES]; +extern const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES]; + +/* + * Structure used by the driver during runtime operation. + */ +struct malidp_hw_device { +	struct malidp_hw *hw; +	void __iomem *regs; + +	/* APB clock */ +	struct clk *pclk; +	/* AXI clock */ +	struct clk *aclk; +	/* main clock for display core */ +	struct clk *mclk; +	/* pixel clock for display core */ +	struct clk *pxlclk; + +	u8 min_line_size; +	u16 max_line_size; + +	/* track the device PM state */ +	bool pm_suspended; + +	/* size of memory used for rotating layers, up to two banks available */ +	u32 rotation_memory[2]; +};  static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg)  { @@ -240,9 +253,9 @@ static inline u32 malidp_get_block_base(struct malidp_hw_device *hwdev,  {  	switch (block) {  	case MALIDP_SE_BLOCK: -		return hwdev->map.se_base; +		return hwdev->hw->map.se_base;  	case MALIDP_DC_BLOCK: -		return hwdev->map.dc_base; +		return hwdev->hw->map.dc_base;  	}  	return 0; @@ -275,7 +288,7 @@ u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,  static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev,  					 unsigned int pitch)  { -	return !(pitch & (hwdev->map.bus_align_bytes - 1)); +	return !(pitch & (hwdev->hw->map.bus_align_bytes - 1));  }  /* U16.16 */ @@ -308,8 +321,8 @@ static inline void malidp_se_set_enh_coeffs(struct malidp_hw_device *hwdev)  	};  	u32 val = MALIDP_SE_SET_ENH_LIMIT_LOW(MALIDP_SE_ENH_LOW_LEVEL) |  		  MALIDP_SE_SET_ENH_LIMIT_HIGH(MALIDP_SE_ENH_HIGH_LEVEL); -	u32 image_enh = hwdev->map.se_base + -			((hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ? +	u32 image_enh = hwdev->hw->map.se_base + +			((hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ?  			 0x10 : 0xC) + MALIDP_SE_IMAGE_ENH;  	u32 enh_coeffs = image_enh + MALIDP_SE_ENH_COEFF0;  	int i; diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 94e7e3fa3408..e7419797bbd1 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -57,7 +57,7 @@ static void malidp_de_plane_destroy(struct drm_plane *plane)  	struct malidp_plane *mp = to_malidp_plane(plane);  	if (mp->base.fb) -		drm_framebuffer_unreference(mp->base.fb); +		drm_framebuffer_put(mp->base.fb);  	drm_plane_helper_disable(plane);  	drm_plane_cleanup(plane); @@ -185,8 +185,9 @@ static int malidp_de_plane_check(struct drm_plane *plane,  	fb = state->fb; -	ms->format = malidp_hw_get_format_id(&mp->hwdev->map, mp->layer->id, -					    fb->format->format); +	ms->format = malidp_hw_get_format_id(&mp->hwdev->hw->map, +					     mp->layer->id, +					     fb->format->format);  	if (ms->format == MALIDP_INVALID_FORMAT_ID)  		return -EINVAL; @@ -211,7 +212,7 @@ static int malidp_de_plane_check(struct drm_plane *plane,  	 * third plane stride register.  	 */  	if (ms->n_planes == 3 && -	    !(mp->hwdev->features & MALIDP_DEVICE_LV_HAS_3_STRIDES) && +	    !(mp->hwdev->hw->features & MALIDP_DEVICE_LV_HAS_3_STRIDES) &&  	    (state->fb->pitches[1] != state->fb->pitches[2]))  		return -EINVAL; @@ -229,9 +230,9 @@ static int malidp_de_plane_check(struct drm_plane *plane,  	if (state->rotation & MALIDP_ROTATED_MASK) {  		int val; -		val = mp->hwdev->rotmem_required(mp->hwdev, state->crtc_h, -						 state->crtc_w, -						 fb->format->format); +		val = mp->hwdev->hw->rotmem_required(mp->hwdev, state->crtc_h, +						     state->crtc_w, +						     fb->format->format);  		if (val < 0)  			return val; @@ -251,7 +252,7 @@ static void malidp_de_set_plane_pitches(struct malidp_plane *mp,  		return;  	if (num_planes == 3) -		num_strides = (mp->hwdev->features & +		num_strides = (mp->hwdev->hw->features &  			       MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2;  	for (i = 0; i < num_strides; ++i) @@ -264,13 +265,11 @@ static void malidp_de_plane_update(struct drm_plane *plane,  				   struct drm_plane_state *old_state)  {  	struct malidp_plane *mp; -	const struct malidp_hw_regmap *map;  	struct malidp_plane_state *ms = to_malidp_plane_state(plane->state);  	u32 src_w, src_h, dest_w, dest_h, val;  	int i;  	mp = to_malidp_plane(plane); -	map = &mp->hwdev->map;  	/* convert src values from Q16 fixed point to integer */  	src_w = plane->state->src_w >> 16; @@ -363,7 +362,7 @@ static const struct drm_plane_helper_funcs malidp_de_plane_helper_funcs = {  int malidp_de_planes_init(struct drm_device *drm)  {  	struct malidp_drm *malidp = drm->dev_private; -	const struct malidp_hw_regmap *map = &malidp->dev->map; +	const struct malidp_hw_regmap *map = &malidp->dev->hw->map;  	struct malidp_plane *plane = NULL;  	enum drm_plane_type plane_type;  	unsigned long crtcs = 1 << drm->mode_config.num_crtc; diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 2e065facdce7..a0f4d2a2a481 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -168,16 +168,23 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc)  void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb,  	int x, int y)  { +	const struct drm_format_info *format = fb->format; +	unsigned int num_planes = format->num_planes;  	u32 addr = drm_fb_obj(fb)->dev_addr; -	int num_planes = fb->format->num_planes;  	int i;  	if (num_planes > 3)  		num_planes = 3; -	for (i = 0; i < num_planes; i++) +	addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + +		   x * format->cpp[0]; + +	y /= format->vsub; +	x /= format->hsub; + +	for (i = 1; i < num_planes; i++)  		addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + -			     x * fb->format->cpp[i]; +			     x * format->cpp[i];  	for (; i < 3; i++)  		addrs[i] = 0;  } @@ -744,15 +751,14 @@ void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,  	if (plane->fb)  		drm_framebuffer_put(plane->fb); -	/* Power down the Y/U/V FIFOs */ -	sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66; -  	/* Power down most RAMs and FIFOs if this is the primary plane */  	if (plane->type == DRM_PLANE_TYPE_PRIMARY) { -		sram_para1 |= CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | -			      CFG_PDWN32x32 | CFG_PDWN64x66; +		sram_para1 = CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | +			     CFG_PDWN32x32 | CFG_PDWN64x66;  		dma_ctrl0_mask = CFG_GRA_ENA;  	} else { +		/* Power down the Y/U/V FIFOs */ +		sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;  		dma_ctrl0_mask = CFG_DMA_ENA;  	} @@ -1225,17 +1231,13 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  	ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc",  			       dcrtc); -	if (ret < 0) { -		kfree(dcrtc); -		return ret; -	} +	if (ret < 0) +		goto err_crtc;  	if (dcrtc->variant->init) {  		ret = dcrtc->variant->init(dcrtc, dev); -		if (ret) { -			kfree(dcrtc); -			return ret; -		} +		if (ret) +			goto err_crtc;  	}  	/* Ensure AXI pipeline is enabled */ @@ -1246,13 +1248,15 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  	dcrtc->crtc.port = port;  	primary = kzalloc(sizeof(*primary), GFP_KERNEL); -	if (!primary) -		return -ENOMEM; +	if (!primary) { +		ret = -ENOMEM; +		goto err_crtc; +	}  	ret = armada_drm_plane_init(primary);  	if (ret) {  		kfree(primary); -		return ret; +		goto err_crtc;  	}  	ret = drm_universal_plane_init(drm, &primary->base, 0, @@ -1263,7 +1267,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  				       DRM_PLANE_TYPE_PRIMARY, NULL);  	if (ret) {  		kfree(primary); -		return ret; +		goto err_crtc;  	}  	ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL, @@ -1282,6 +1286,9 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  err_crtc_init:  	primary->base.funcs->destroy(&primary->base); +err_crtc: +	kfree(dcrtc); +  	return ret;  } diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index bab11f483575..bfd3514fbe9b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -42,6 +42,8 @@ struct armada_plane_work {  };  struct armada_plane_state { +	u16 src_x; +	u16 src_y;  	u32 src_hw;  	u32 dst_hw;  	u32 dst_yx; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index b411b608821a..aba947696178 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -99,6 +99,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  {  	struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);  	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); +	const struct drm_format_info *format;  	struct drm_rect src = {  		.x1 = src_x,  		.y1 = src_y, @@ -117,7 +118,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  	};  	uint32_t val, ctrl0;  	unsigned idx = 0; -	bool visible; +	bool visible, fb_changed;  	int ret;  	trace_armada_ovl_plane_update(plane, crtc, fb, @@ -138,6 +139,18 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  	if (!visible)  		ctrl0 &= ~CFG_DMA_ENA; +	/* +	 * Shifting a YUV packed format image by one pixel causes the U/V +	 * planes to swap.  Compensate for it by also toggling the UV swap. +	 */ +	format = fb->format; +	if (format->num_planes == 1 && src.x1 >> 16 & (format->hsub - 1)) +		ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV); + +	fb_changed = plane->fb != fb || +		     dplane->base.state.src_x != src.x1 >> 16 || +	             dplane->base.state.src_y != src.y1 >> 16; +  	if (!dcrtc->plane) {  		dcrtc->plane = plane;  		armada_ovl_update_attr(&dplane->prop, dcrtc); @@ -145,7 +158,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  	/* FIXME: overlay on an interlaced display */  	/* Just updating the position/size? */ -	if (plane->fb == fb && dplane->base.state.ctrl0 == ctrl0) { +	if (!fb_changed && dplane->base.state.ctrl0 == ctrl0) {  		val = (drm_rect_height(&src) & 0xffff0000) |  		      drm_rect_width(&src) >> 16;  		dplane->base.state.src_hw = val; @@ -169,9 +182,8 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  	if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0)  		armada_drm_plane_work_cancel(dcrtc, &dplane->base); -	if (plane->fb != fb) { -		u32 addrs[3], pixel_format; -		int num_planes, hsub; +	if (fb_changed) { +		u32 addrs[3];  		/*  		 * Take a reference on the new framebuffer - we want to @@ -182,23 +194,11 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,  		if (plane->fb)  			armada_ovl_retire_fb(dplane, plane->fb); -		src_y = src.y1 >> 16; -		src_x = src.x1 >> 16; +		dplane->base.state.src_y = src_y = src.y1 >> 16; +		dplane->base.state.src_x = src_x = src.x1 >> 16;  		armada_drm_plane_calc_addrs(addrs, fb, src_x, src_y); -		pixel_format = fb->format->format; -		hsub = drm_format_horz_chroma_subsampling(pixel_format); -		num_planes = fb->format->num_planes; - -		/* -		 * Annoyingly, shifting a YUYV-format image by one pixel -		 * causes the U/V planes to toggle.  Toggle the UV swap. -		 * (Unfortunately, this causes momentary colour flickering.) -		 */ -		if (src_x & (hsub - 1) && num_planes == 1) -			ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV); -  		armada_reg_queue_set(dplane->vbl.regs, idx, addrs[0],  				     LCD_SPU_DMA_START_ADDR_Y0);  		armada_reg_queue_set(dplane->vbl.regs, idx, addrs[1], diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index b4efcbabf7f7..d034b2cb5eee 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -372,9 +372,18 @@ struct adv7511 {  };  #ifdef CONFIG_DRM_I2C_ADV7511_CEC -int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511, -		     unsigned int offset); +int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511);  void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1); +#else +static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511) +{ +	unsigned int offset = adv7511->type == ADV7533 ? +						ADV7533_REG_CEC_OFFSET : 0; + +	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, +		     ADV7511_CEC_CTRL_POWER_DOWN); +	return 0; +}  #endif  #ifdef CONFIG_DRM_I2C_ADV7533 diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c index b33d730e4d73..a20a45c0b353 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c @@ -300,18 +300,21 @@ static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)  	return 0;  } -int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511, -		     unsigned int offset) +int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)  { +	unsigned int offset = adv7511->type == ADV7533 ? +						ADV7533_REG_CEC_OFFSET : 0;  	int ret = adv7511_cec_parse_dt(dev, adv7511);  	if (ret) -		return ret; +		goto err_cec_parse_dt;  	adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,  		adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS); -	if (IS_ERR(adv7511->cec_adap)) -		return PTR_ERR(adv7511->cec_adap); +	if (IS_ERR(adv7511->cec_adap)) { +		ret = PTR_ERR(adv7511->cec_adap); +		goto err_cec_alloc; +	}  	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0);  	/* cec soft reset */ @@ -329,9 +332,18 @@ int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511,  		     ((adv7511->cec_clk_freq / 750000) - 1) << 2);  	ret = cec_register_adapter(adv7511->cec_adap, dev); -	if (ret) { -		cec_delete_adapter(adv7511->cec_adap); -		adv7511->cec_adap = NULL; -	} -	return ret; +	if (ret) +		goto err_cec_register; +	return 0; + +err_cec_register: +	cec_delete_adapter(adv7511->cec_adap); +	adv7511->cec_adap = NULL; +err_cec_alloc: +	dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n", +		 ret); +err_cec_parse_dt: +	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, +		     ADV7511_CEC_CTRL_POWER_DOWN); +	return ret == -EPROBE_DEFER ? ret : 0;  } diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 0e14f1572d05..efa29db5fc2b 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -1084,7 +1084,6 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)  	struct device *dev = &i2c->dev;  	unsigned int main_i2c_addr = i2c->addr << 1;  	unsigned int edid_i2c_addr = main_i2c_addr + 4; -	unsigned int offset;  	unsigned int val;  	int ret; @@ -1192,24 +1191,16 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)  	if (adv7511->type == ADV7511)  		adv7511_set_link_config(adv7511, &link_config); +	ret = adv7511_cec_init(dev, adv7511); +	if (ret) +		goto err_unregister_cec; +  	adv7511->bridge.funcs = &adv7511_bridge_funcs;  	adv7511->bridge.of_node = dev->of_node;  	drm_bridge_add(&adv7511->bridge);  	adv7511_audio_init(dev, adv7511); - -	offset = adv7511->type == ADV7533 ? ADV7533_REG_CEC_OFFSET : 0; - -#ifdef CONFIG_DRM_I2C_ADV7511_CEC -	ret = adv7511_cec_init(dev, adv7511, offset); -	if (ret) -		goto err_unregister_cec; -#else -	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, -		     ADV7511_CEC_CTRL_POWER_DOWN); -#endif -  	return 0;  err_unregister_cec: diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5dd3f1cd074a..a8905049b9da 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -946,7 +946,9 @@ static int analogix_dp_get_modes(struct drm_connector *connector)  			return 0;  		} +		pm_runtime_get_sync(dp->dev);  		edid = drm_get_edid(connector, &dp->aux.ddc); +		pm_runtime_put(dp->dev);  		if (edid) {  			drm_mode_connector_update_edid_property(&dp->connector,  								edid); diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c index 0903ba574f61..75b0d3f6e4de 100644 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ b/drivers/gpu/drm/bridge/lvds-encoder.c @@ -13,13 +13,37 @@  #include <linux/of_graph.h> +struct lvds_encoder { +	struct drm_bridge bridge; +	struct drm_bridge *panel_bridge; +}; + +static int lvds_encoder_attach(struct drm_bridge *bridge) +{ +	struct lvds_encoder *lvds_encoder = container_of(bridge, +							 struct lvds_encoder, +							 bridge); + +	return drm_bridge_attach(bridge->encoder, lvds_encoder->panel_bridge, +				 bridge); +} + +static struct drm_bridge_funcs funcs = { +	.attach = lvds_encoder_attach, +}; +  static int lvds_encoder_probe(struct platform_device *pdev)  {  	struct device_node *port;  	struct device_node *endpoint;  	struct device_node *panel_node;  	struct drm_panel *panel; -	struct drm_bridge *bridge; +	struct lvds_encoder *lvds_encoder; + +	lvds_encoder = devm_kzalloc(&pdev->dev, sizeof(*lvds_encoder), +				    GFP_KERNEL); +	if (!lvds_encoder) +		return -ENOMEM;  	/* Locate the panel DT node. */  	port = of_graph_get_port_by_id(pdev->dev.of_node, 1); @@ -49,20 +73,30 @@ static int lvds_encoder_probe(struct platform_device *pdev)  		return -EPROBE_DEFER;  	} -	bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_LVDS); -	if (IS_ERR(bridge)) -		return PTR_ERR(bridge); +	lvds_encoder->panel_bridge = +		devm_drm_panel_bridge_add(&pdev->dev, +					  panel, DRM_MODE_CONNECTOR_LVDS); +	if (IS_ERR(lvds_encoder->panel_bridge)) +		return PTR_ERR(lvds_encoder->panel_bridge); + +	/* The panel_bridge bridge is attached to the panel's of_node, +	 * but we need a bridge attached to our of_node for our user +	 * to look up. +	 */ +	lvds_encoder->bridge.of_node = pdev->dev.of_node; +	lvds_encoder->bridge.funcs = &funcs; +	drm_bridge_add(&lvds_encoder->bridge); -	platform_set_drvdata(pdev, bridge); +	platform_set_drvdata(pdev, lvds_encoder);  	return 0;  }  static int lvds_encoder_remove(struct platform_device *pdev)  { -	struct drm_bridge *bridge = platform_get_drvdata(pdev); +	struct lvds_encoder *lvds_encoder = platform_get_drvdata(pdev); -	drm_bridge_remove(bridge); +	drm_bridge_remove(&lvds_encoder->bridge);  	return 0;  } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index bf14214fa464..b72259bf6e2f 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -138,6 +138,7 @@ struct dw_hdmi {  	struct device *dev;  	struct clk *isfr_clk;  	struct clk *iahb_clk; +	struct clk *cec_clk;  	struct dw_hdmi_i2c *i2c;  	struct hdmi_data_info hdmi_data; @@ -2382,6 +2383,26 @@ __dw_hdmi_probe(struct platform_device *pdev,  		goto err_isfr;  	} +	hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec"); +	if (PTR_ERR(hdmi->cec_clk) == -ENOENT) { +		hdmi->cec_clk = NULL; +	} else if (IS_ERR(hdmi->cec_clk)) { +		ret = PTR_ERR(hdmi->cec_clk); +		if (ret != -EPROBE_DEFER) +			dev_err(hdmi->dev, "Cannot get HDMI cec clock: %d\n", +				ret); + +		hdmi->cec_clk = NULL; +		goto err_iahb; +	} else { +		ret = clk_prepare_enable(hdmi->cec_clk); +		if (ret) { +			dev_err(hdmi->dev, "Cannot enable HDMI cec clock: %d\n", +				ret); +			goto err_iahb; +		} +	} +  	/* Product and revision IDs */  	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)  		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0); @@ -2518,6 +2539,8 @@ err_iahb:  		cec_notifier_put(hdmi->cec_notifier);  	clk_disable_unprepare(hdmi->iahb_clk); +	if (hdmi->cec_clk) +		clk_disable_unprepare(hdmi->cec_clk);  err_isfr:  	clk_disable_unprepare(hdmi->isfr_clk);  err_res: @@ -2541,6 +2564,8 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)  	clk_disable_unprepare(hdmi->iahb_clk);  	clk_disable_unprepare(hdmi->isfr_clk); +	if (hdmi->cec_clk) +		clk_disable_unprepare(hdmi->cec_clk);  	if (hdmi->i2c)  		i2c_del_adapter(&hdmi->i2c->adap); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 8571cfd877c5..8636e7eeb731 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -97,7 +97,7 @@  #define DP0_ACTIVEVAL		0x0650  #define DP0_SYNCVAL		0x0654  #define DP0_MISC		0x0658 -#define TU_SIZE_RECOMMENDED		(0x3f << 16) /* LSCLK cycles per TU */ +#define TU_SIZE_RECOMMENDED		(63) /* LSCLK cycles per TU */  #define BPC_6				(0 << 5)  #define BPC_8				(1 << 5) @@ -318,7 +318,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,  				tmp = (tmp << 8) | buf[i];  			i++;  			if (((i % 4) == 0) || (i == size)) { -				tc_write(DP0_AUXWDATA(i >> 2), tmp); +				tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);  				tmp = 0;  			}  		} @@ -603,8 +603,15 @@ static int tc_get_display_props(struct tc_data *tc)  	ret = drm_dp_link_probe(&tc->aux, &tc->link.base);  	if (ret < 0)  		goto err_dpcd_read; -	if ((tc->link.base.rate != 162000) && (tc->link.base.rate != 270000)) -		goto err_dpcd_inval; +	if (tc->link.base.rate != 162000 && tc->link.base.rate != 270000) { +		dev_dbg(tc->dev, "Falling to 2.7 Gbps rate\n"); +		tc->link.base.rate = 270000; +	} + +	if (tc->link.base.num_lanes > 2) { +		dev_dbg(tc->dev, "Falling to 2 lanes\n"); +		tc->link.base.num_lanes = 2; +	}  	ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, tmp);  	if (ret < 0) @@ -637,9 +644,6 @@ static int tc_get_display_props(struct tc_data *tc)  err_dpcd_read:  	dev_err(tc->dev, "failed to read DPCD: %d\n", ret);  	return ret; -err_dpcd_inval: -	dev_err(tc->dev, "invalid DPCD\n"); -	return -EINVAL;  }  static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) @@ -655,6 +659,14 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode)  	int lower_margin = mode->vsync_start - mode->vdisplay;  	int vsync_len = mode->vsync_end - mode->vsync_start; +	/* +	 * Recommended maximum number of symbols transferred in a transfer unit: +	 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size, +	 *              (output active video bandwidth in bytes)) +	 * Must be less than tu_size. +	 */ +	max_tu_symbol = TU_SIZE_RECOMMENDED - 1; +  	dev_dbg(tc->dev, "set mode %dx%d\n",  		mode->hdisplay, mode->vdisplay);  	dev_dbg(tc->dev, "H margin %d,%d sync %d\n", @@ -664,13 +676,18 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode)  	dev_dbg(tc->dev, "total: %dx%d\n", mode->htotal, mode->vtotal); -	/* LCD Ctl Frame Size */ -	tc_write(VPCTRL0, (0x40 << 20) /* VSDELAY */ | +	/* +	 * LCD Ctl Frame Size +	 * datasheet is not clear of vsdelay in case of DPI +	 * assume we do not need any delay when DPI is a source of +	 * sync signals +	 */ +	tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |  		 OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED); -	tc_write(HTIM01, (left_margin << 16) |		/* H back porch */ -			 (hsync_len << 0));		/* Hsync */ -	tc_write(HTIM02, (right_margin << 16) |		/* H front porch */ -			 (mode->hdisplay << 0));	/* width */ +	tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */ +			 (ALIGN(hsync_len, 2) << 0));	 /* Hsync */ +	tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) |  /* H front porch */ +			 (ALIGN(mode->hdisplay, 2) << 0)); /* width */  	tc_write(VTIM01, (upper_margin << 16) |		/* V back porch */  			 (vsync_len << 0));		/* Vsync */  	tc_write(VTIM02, (lower_margin << 16) |		/* V front porch */ @@ -689,7 +706,7 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode)  	/* DP Main Stream Attributes */  	vid_sync_dly = hsync_len + left_margin + mode->hdisplay;  	tc_write(DP0_VIDSYNCDELAY, -		 (0x003e << 16) |	/* thresh_dly */ +		 (max_tu_symbol << 16) |	/* thresh_dly */  		 (vid_sync_dly << 0));  	tc_write(DP0_TOTALVAL, (mode->vtotal << 16) | (mode->htotal)); @@ -705,14 +722,8 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode)  	tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |  		 DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888); -	/* -	 * Recommended maximum number of symbols transferred in a transfer unit: -	 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size, -	 *              (output active video bandwidth in bytes)) -	 * Must be less than tu_size. -	 */ -	max_tu_symbol = TU_SIZE_RECOMMENDED - 1; -	tc_write(DP0_MISC, (max_tu_symbol << 23) | TU_SIZE_RECOMMENDED | BPC_8); +	tc_write(DP0_MISC, (max_tu_symbol << 23) | (TU_SIZE_RECOMMENDED << 16) | +			   BPC_8);  	return 0;  err: @@ -808,8 +819,6 @@ static int tc_main_link_setup(struct tc_data *tc)  	unsigned int rate;  	u32 dp_phy_ctrl;  	int timeout; -	bool aligned; -	bool ready;  	u32 value;  	int ret;  	u8 tmp[8]; @@ -954,16 +963,15 @@ static int tc_main_link_setup(struct tc_data *tc)  		ret = drm_dp_dpcd_read_link_status(aux, tmp + 2);  		if (ret < 0)  			goto err_dpcd_read; -		ready = (tmp[2] == ((DP_CHANNEL_EQ_BITS << 4) | /* Lane1 */ -				     DP_CHANNEL_EQ_BITS));      /* Lane0 */ -		aligned = tmp[4] & DP_INTERLANE_ALIGN_DONE; -	} while ((--timeout) && !(ready && aligned)); +	} while ((--timeout) && +		 !(drm_dp_channel_eq_ok(tmp + 2,  tc->link.base.num_lanes)));  	if (timeout == 0) {  		/* Read DPCD 0x200-0x201 */  		ret = drm_dp_dpcd_read(aux, DP_SINK_COUNT, tmp, 2);  		if (ret < 0)  			goto err_dpcd_read; +		dev_err(dev, "channel(s) EQ not ok\n");  		dev_info(dev, "0x0200 SINK_COUNT: 0x%02x\n", tmp[0]);  		dev_info(dev, "0x0201 DEVICE_SERVICE_IRQ_VECTOR: 0x%02x\n",  			 tmp[1]); @@ -974,10 +982,6 @@ static int tc_main_link_setup(struct tc_data *tc)  		dev_info(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n",  			 tmp[6]); -		if (!ready) -			dev_err(dev, "Lane0/1 not ready\n"); -		if (!aligned) -			dev_err(dev, "Lane0/1 not aligned\n");  		return -EAGAIN;  	} @@ -1099,7 +1103,10 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,  static int tc_connector_mode_valid(struct drm_connector *connector,  				   struct drm_display_mode *mode)  { -	/* Accept any mode */ +	/* DPI interface clock limitation: upto 154 MHz */ +	if (mode->clock > 154000) +		return MODE_CLOCK_HIGH; +  	return MODE_OK;  } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 71d712f1b56a..b16f1d69a0bb 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1225,7 +1225,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,  		return;  	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) { -		if (!new_crtc_state->active || !new_crtc_state->planes_changed) +		if (!new_crtc_state->active)  			continue;  		ret = drm_crtc_vblank_get(crtc); diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 25f4b2e9a44f..9ae236036e32 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -152,6 +152,25 @@ static void drm_connector_free(struct kref *kref)  	connector->funcs->destroy(connector);  } +void drm_connector_free_work_fn(struct work_struct *work) +{ +	struct drm_connector *connector, *n; +	struct drm_device *dev = +		container_of(work, struct drm_device, mode_config.connector_free_work); +	struct drm_mode_config *config = &dev->mode_config; +	unsigned long flags; +	struct llist_node *freed; + +	spin_lock_irqsave(&config->connector_list_lock, flags); +	freed = llist_del_all(&config->connector_free_list); +	spin_unlock_irqrestore(&config->connector_list_lock, flags); + +	llist_for_each_entry_safe(connector, n, freed, free_node) { +		drm_mode_object_unregister(dev, &connector->base); +		connector->funcs->destroy(connector); +	} +} +  /**   * drm_connector_init - Init a preallocated connector   * @dev: DRM device @@ -529,6 +548,25 @@ void drm_connector_list_iter_begin(struct drm_device *dev,  }  EXPORT_SYMBOL(drm_connector_list_iter_begin); +/* + * Extra-safe connector put function that works in any context. Should only be + * used from the connector_iter functions, where we never really expect to + * actually release the connector when dropping our final reference. + */ +static void +__drm_connector_put_safe(struct drm_connector *conn) +{ +	struct drm_mode_config *config = &conn->dev->mode_config; + +	lockdep_assert_held(&config->connector_list_lock); + +	if (!refcount_dec_and_test(&conn->base.refcount.refcount)) +		return; + +	llist_add(&conn->free_node, &config->connector_free_list); +	schedule_work(&config->connector_free_work); +} +  /**   * drm_connector_list_iter_next - return next connector   * @iter: connectr_list iterator @@ -558,10 +596,10 @@ drm_connector_list_iter_next(struct drm_connector_list_iter *iter)  		/* loop until it's not a zombie connector */  	} while (!kref_get_unless_zero(&iter->conn->base.refcount)); -	spin_unlock_irqrestore(&config->connector_list_lock, flags);  	if (old_conn) -		drm_connector_put(old_conn); +		__drm_connector_put_safe(old_conn); +	spin_unlock_irqrestore(&config->connector_list_lock, flags);  	return iter->conn;  } @@ -578,9 +616,15 @@ EXPORT_SYMBOL(drm_connector_list_iter_next);   */  void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)  { +	struct drm_mode_config *config = &iter->dev->mode_config; +	unsigned long flags; +  	iter->dev = NULL; -	if (iter->conn) -		drm_connector_put(iter->conn); +	if (iter->conn) { +		spin_lock_irqsave(&config->connector_list_lock, flags); +		__drm_connector_put_safe(iter->conn); +		spin_unlock_irqrestore(&config->connector_list_lock, flags); +	}  	lock_release(&connector_list_iter_dep_map, 0, _RET_IP_);  }  EXPORT_SYMBOL(drm_connector_list_iter_end); @@ -1207,6 +1251,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,  	if (edid)  		size = EDID_LENGTH * (1 + edid->extensions); +	/* Set the display info, using edid if available, otherwise +	 * reseting the values to defaults. This duplicates the work +	 * done in drm_add_edid_modes, but that function is not +	 * consistently called before this one in all drivers and the +	 * computation is cheap enough that it seems better to +	 * duplicate it rather than attempt to ensure some arbitrary +	 * ordering of calls. +	 */ +	if (edid) +		drm_add_display_info(connector, edid); +	else +		drm_reset_display_info(connector); +  	drm_object_property_set_value(&connector->base,  				      dev->mode_config.non_desktop_property,  				      connector->display_info.non_desktop); diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 9ebb8841778c..af00f42ba269 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -142,6 +142,7 @@ int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,  				    uint64_t value);  int drm_connector_create_standard_properties(struct drm_device *dev);  const char *drm_get_connector_force_name(enum drm_connector_force force); +void drm_connector_free_work_fn(struct work_struct *work);  /* IOCTL */  int drm_mode_connector_property_set_ioctl(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 2e8fb51282ef..cb487148359a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);   *   * Returns true if @vendor is in @edid, false otherwise   */ -static bool edid_vendor(struct edid *edid, const char *vendor) +static bool edid_vendor(const struct edid *edid, const char *vendor)  {  	char edid_vendor[3]; @@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)   *   * This tells subsequent routines what fixes they need to apply.   */ -static u32 edid_get_quirks(struct edid *edid) +static u32 edid_get_quirks(const struct edid *edid)  {  	const struct edid_quirk *quirk;  	int i; @@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,  /*   * Search EDID for CEA extension block.   */ -static u8 *drm_find_edid_extension(struct edid *edid, int ext_id) +static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)  {  	u8 *edid_ext = NULL;  	int i; @@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)  	return edid_ext;  } -static u8 *drm_find_cea_extension(struct edid *edid) +static u8 *drm_find_cea_extension(const struct edid *edid)  {  	return drm_find_edid_extension(edid, CEA_EXT);  } -static u8 *drm_find_displayid_extension(struct edid *edid) +static u8 *drm_find_displayid_extension(const struct edid *edid)  {  	return drm_find_edid_extension(edid, DISPLAYID_EXT);  } @@ -4363,7 +4363,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)  }  static void drm_parse_cea_ext(struct drm_connector *connector, -			      struct edid *edid) +			      const struct edid *edid)  {  	struct drm_display_info *info = &connector->display_info;  	const u8 *edid_ext; @@ -4397,11 +4397,33 @@ static void drm_parse_cea_ext(struct drm_connector *connector,  	}  } -static void drm_add_display_info(struct drm_connector *connector, -				 struct edid *edid, u32 quirks) +/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset + * all of the values which would have been set from EDID + */ +void +drm_reset_display_info(struct drm_connector *connector) +{ +	struct drm_display_info *info = &connector->display_info; + +	info->width_mm = 0; +	info->height_mm = 0; + +	info->bpc = 0; +	info->color_formats = 0; +	info->cea_rev = 0; +	info->max_tmds_clock = 0; +	info->dvi_dual = false; + +	info->non_desktop = 0; +} +EXPORT_SYMBOL_GPL(drm_reset_display_info); + +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)  {  	struct drm_display_info *info = &connector->display_info; +	u32 quirks = edid_get_quirks(edid); +  	info->width_mm = edid->width_cm * 10;  	info->height_mm = edid->height_cm * 10; @@ -4414,11 +4436,13 @@ static void drm_add_display_info(struct drm_connector *connector,  	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); +	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop); +  	if (edid->revision < 3) -		return; +		return quirks;  	if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) -		return; +		return quirks;  	drm_parse_cea_ext(connector, edid); @@ -4438,7 +4462,7 @@ static void drm_add_display_info(struct drm_connector *connector,  	/* Only defined for 1.4 with digital displays */  	if (edid->revision < 4) -		return; +		return quirks;  	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {  	case DRM_EDID_DIGITAL_DEPTH_6: @@ -4473,7 +4497,9 @@ static void drm_add_display_info(struct drm_connector *connector,  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;  	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; +	return quirks;  } +EXPORT_SYMBOL_GPL(drm_add_display_info);  static int validate_displayid(u8 *displayid, int length, int idx)  { @@ -4627,14 +4653,12 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)  		return 0;  	} -	quirks = edid_get_quirks(edid); -  	/*  	 * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks.  	 * To avoid multiple parsing of same block, lets parse that map  	 * from sink info, before parsing CEA modes.  	 */ -	drm_add_display_info(connector, edid, quirks); +	quirks = drm_add_display_info(connector, edid);  	/*  	 * EDID spec says modes should be preferred in this order: @@ -4831,7 +4855,8 @@ void  drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,  				   const struct drm_display_mode *mode,  				   enum hdmi_quantization_range rgb_quant_range, -				   bool rgb_quant_range_selectable) +				   bool rgb_quant_range_selectable, +				   bool is_hdmi2_sink)  {  	/*  	 * CEA-861: @@ -4855,8 +4880,15 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,  	 *  YQ-field to match the RGB Quantization Range being transmitted  	 *  (e.g., when Limited Range RGB, set YQ=0 or when Full Range RGB,  	 *  set YQ=1) and the Sink shall ignore the YQ-field." +	 * +	 * Unfortunate certain sinks (eg. VIZ Model 67/E261VA) get confused +	 * by non-zero YQ when receiving RGB. There doesn't seem to be any +	 * good way to tell which version of CEA-861 the sink supports, so +	 * we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based +	 * on on CEA-861-F.  	 */ -	if (rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) +	if (!is_hdmi2_sink || +	    rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED)  		frame->ycc_quantization_range =  			HDMI_YCC_QUANTIZATION_RANGE_LIMITED;  	else diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 07374008f146..e56166334455 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1809,6 +1809,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,  	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {  		DRM_INFO("Cannot find any crtc or sizes\n"); + +		/* First time: disable all crtc's.. */ +		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master)) +			restore_fbdev_mode(fb_helper);  		return -EAGAIN;  	} diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index d1eb56a1eff4..1402c0e71b03 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -220,17 +220,6 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr  	mutex_lock(&dev->mode_config.idr_mutex); -	/* Insert the new lessee into the tree */ -	id = idr_alloc(&(drm_lease_owner(lessor)->lessee_idr), lessee, 1, 0, GFP_KERNEL); -	if (id < 0) { -		error = id; -		goto out_lessee; -	} - -	lessee->lessee_id = id; -	lessee->lessor = drm_master_get(lessor); -	list_add_tail(&lessee->lessee_list, &lessor->lessees); -  	idr_for_each_entry(leases, entry, object) {  		error = 0;  		if (!idr_find(&dev->mode_config.crtc_idr, object)) @@ -246,6 +235,17 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr  		}  	} +	/* Insert the new lessee into the tree */ +	id = idr_alloc(&(drm_lease_owner(lessor)->lessee_idr), lessee, 1, 0, GFP_KERNEL); +	if (id < 0) { +		error = id; +		goto out_lessee; +	} + +	lessee->lessee_id = id; +	lessee->lessor = drm_master_get(lessor); +	list_add_tail(&lessee->lessee_list, &lessor->lessees); +  	/* Move the leases over */  	lessee->leases = *leases;  	DRM_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee->lessee_id, lessee, lessor->lessee_id, lessor); @@ -254,10 +254,10 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr  	return lessee;  out_lessee: -	drm_master_put(&lessee); -  	mutex_unlock(&dev->mode_config.idr_mutex); +	drm_master_put(&lessee); +  	return ERR_PTR(error);  } diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 61a1c8ea74bc..c3c79ee6119e 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -575,21 +575,23 @@ EXPORT_SYMBOL(drm_mm_remove_node);   */  void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)  { +	struct drm_mm *mm = old->mm; +  	DRM_MM_BUG_ON(!old->allocated);  	*new = *old;  	list_replace(&old->node_list, &new->node_list); -	rb_replace_node(&old->rb, &new->rb, &old->mm->interval_tree.rb_root); +	rb_replace_node_cached(&old->rb, &new->rb, &mm->interval_tree);  	if (drm_mm_hole_follows(old)) {  		list_replace(&old->hole_stack, &new->hole_stack);  		rb_replace_node(&old->rb_hole_size,  				&new->rb_hole_size, -				&old->mm->holes_size); +				&mm->holes_size);  		rb_replace_node(&old->rb_hole_addr,  				&new->rb_hole_addr, -				&old->mm->holes_addr); +				&mm->holes_addr);  	}  	old->allocated = false; diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index cda8bfab6d3b..256de7313612 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -382,6 +382,9 @@ void drm_mode_config_init(struct drm_device *dev)  	ida_init(&dev->mode_config.connector_ida);  	spin_lock_init(&dev->mode_config.connector_list_lock); +	init_llist_head(&dev->mode_config.connector_free_list); +	INIT_WORK(&dev->mode_config.connector_free_work, drm_connector_free_work_fn); +  	drm_mode_create_standard_properties(dev);  	/* Just to be sure */ @@ -431,6 +434,8 @@ void drm_mode_config_cleanup(struct drm_device *dev)  		drm_connector_put(connector);  	}  	drm_connector_list_iter_end(&conn_iter); +	/* connector_iter drops references in a work item. */ +	flush_work(&dev->mode_config.connector_free_work);  	if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) {  		drm_connector_list_iter_begin(dev, &conn_iter);  		drm_for_each_connector_iter(connector, &conn_iter) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 19404e34cd59..2c90519576a3 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -558,11 +558,10 @@ int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)  }  /* - * setplane_internal - setplane handler for internal callers + * __setplane_internal - setplane handler for internal callers   * - * Note that we assume an extra reference has already been taken on fb.  If the - * update fails, this reference will be dropped before return; if it succeeds, - * the previous framebuffer (if any) will be unreferenced instead. + * This function will take a reference on the new fb for the plane + * on success.   *   * src_{x,y,w,h} are provided in 16.16 fixed point format   */ @@ -630,14 +629,12 @@ static int __setplane_internal(struct drm_plane *plane,  	if (!ret) {  		plane->crtc = crtc;  		plane->fb = fb; -		fb = NULL; +		drm_framebuffer_get(plane->fb);  	} else {  		plane->old_fb = NULL;  	}  out: -	if (fb) -		drm_framebuffer_put(fb);  	if (plane->old_fb)  		drm_framebuffer_put(plane->old_fb);  	plane->old_fb = NULL; @@ -685,6 +682,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,  	struct drm_plane *plane;  	struct drm_crtc *crtc = NULL;  	struct drm_framebuffer *fb = NULL; +	int ret;  	if (!drm_core_check_feature(dev, DRIVER_MODESET))  		return -EINVAL; @@ -717,15 +715,16 @@ int drm_mode_setplane(struct drm_device *dev, void *data,  		}  	} -	/* -	 * setplane_internal will take care of deref'ing either the old or new -	 * framebuffer depending on success. -	 */ -	return setplane_internal(plane, crtc, fb, -				 plane_req->crtc_x, plane_req->crtc_y, -				 plane_req->crtc_w, plane_req->crtc_h, -				 plane_req->src_x, plane_req->src_y, -				 plane_req->src_w, plane_req->src_h); +	ret = setplane_internal(plane, crtc, fb, +				plane_req->crtc_x, plane_req->crtc_y, +				plane_req->crtc_w, plane_req->crtc_h, +				plane_req->src_x, plane_req->src_y, +				plane_req->src_w, plane_req->src_h); + +	if (fb) +		drm_framebuffer_put(fb); + +	return ret;  }  static int drm_mode_cursor_universal(struct drm_crtc *crtc, @@ -788,13 +787,12 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,  		src_h = fb->height << 16;  	} -	/* -	 * setplane_internal will take care of deref'ing either the old or new -	 * framebuffer depending on success. -	 */  	ret = __setplane_internal(crtc->cursor, crtc, fb, -				crtc_x, crtc_y, crtc_w, crtc_h, -				0, 0, src_w, src_h, ctx); +				  crtc_x, crtc_y, crtc_w, crtc_h, +				  0, 0, src_w, src_h, ctx); + +	if (fb) +		drm_framebuffer_put(fb);  	/* Update successful; save new cursor position, if necessary */  	if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { @@ -1030,6 +1028,7 @@ retry:  		e->event.base.type = DRM_EVENT_FLIP_COMPLETE;  		e->event.base.length = sizeof(e->event);  		e->event.vbl.user_data = page_flip->user_data; +		e->event.vbl.crtc_id = crtc->base.id;  		ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);  		if (ret) {  			kfree(e); diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index f776fc1cc543..cb4d09c70fd4 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -369,40 +369,26 @@ static const struct file_operations drm_syncobj_file_fops = {  	.release = drm_syncobj_file_release,  }; -static int drm_syncobj_alloc_file(struct drm_syncobj *syncobj) -{ -	struct file *file = anon_inode_getfile("syncobj_file", -					       &drm_syncobj_file_fops, -					       syncobj, 0); -	if (IS_ERR(file)) -		return PTR_ERR(file); - -	drm_syncobj_get(syncobj); -	if (cmpxchg(&syncobj->file, NULL, file)) { -		/* lost the race */ -		fput(file); -	} - -	return 0; -} -  int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)  { -	int ret; +	struct file *file;  	int fd;  	fd = get_unused_fd_flags(O_CLOEXEC);  	if (fd < 0)  		return fd; -	if (!syncobj->file) { -		ret = drm_syncobj_alloc_file(syncobj); -		if (ret) { -			put_unused_fd(fd); -			return ret; -		} +	file = anon_inode_getfile("syncobj_file", +				  &drm_syncobj_file_fops, +				  syncobj, 0); +	if (IS_ERR(file)) { +		put_unused_fd(fd); +		return PTR_ERR(file);  	} -	fd_install(fd, syncobj->file); + +	drm_syncobj_get(syncobj); +	fd_install(fd, file); +  	*p_fd = fd;  	return 0;  } @@ -422,31 +408,24 @@ static int drm_syncobj_handle_to_fd(struct drm_file *file_private,  	return ret;  } -static struct drm_syncobj *drm_syncobj_fdget(int fd) -{ -	struct file *file = fget(fd); - -	if (!file) -		return NULL; -	if (file->f_op != &drm_syncobj_file_fops) -		goto err; - -	return file->private_data; -err: -	fput(file); -	return NULL; -}; -  static int drm_syncobj_fd_to_handle(struct drm_file *file_private,  				    int fd, u32 *handle)  { -	struct drm_syncobj *syncobj = drm_syncobj_fdget(fd); +	struct drm_syncobj *syncobj; +	struct file *file;  	int ret; -	if (!syncobj) +	file = fget(fd); +	if (!file)  		return -EINVAL; +	if (file->f_op != &drm_syncobj_file_fops) { +		fput(file); +		return -EINVAL; +	} +  	/* take a reference to put in the idr */ +	syncobj = file->private_data;  	drm_syncobj_get(syncobj);  	idr_preload(GFP_KERNEL); @@ -455,12 +434,14 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,  	spin_unlock(&file_private->syncobj_table_lock);  	idr_preload_end(); -	if (ret < 0) { -		fput(syncobj->file); -		return ret; -	} -	*handle = ret; -	return 0; +	if (ret > 0) { +		*handle = ret; +		ret = 0; +	} else +		drm_syncobj_put(syncobj); + +	fput(file); +	return ret;  }  static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 82b72425a42f..27e423b87266 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -37,8 +37,6 @@  #define DRIVER_MAJOR	1  #define DRIVER_MINOR	0 -static struct device *exynos_drm_get_dma_device(void); -  int exynos_atomic_check(struct drm_device *dev,  			struct drm_atomic_state *state)  { @@ -148,7 +146,7 @@ static struct drm_driver exynos_drm_driver = {  	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,  	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,  	.gem_prime_export	= drm_gem_prime_export, -	.gem_prime_import	= drm_gem_prime_import, +	.gem_prime_import	= exynos_drm_gem_prime_import,  	.gem_prime_get_sg_table	= exynos_drm_gem_prime_get_sg_table,  	.gem_prime_import_sg_table	= exynos_drm_gem_prime_import_sg_table,  	.gem_prime_vmap		= exynos_drm_gem_prime_vmap, @@ -301,6 +299,27 @@ static struct component_match *exynos_drm_match_add(struct device *dev)  	return match ?: ERR_PTR(-ENODEV);  } +static struct device *exynos_drm_get_dma_device(void) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) { +		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i]; +		struct device *dev; + +		if (!info->driver || !(info->flags & DRM_DMA_DEVICE)) +			continue; + +		while ((dev = bus_find_device(&platform_bus_type, NULL, +					    &info->driver->driver, +					    (void *)platform_bus_type.match))) { +			put_device(dev); +			return dev; +		} +	} +	return NULL; +} +  static int exynos_drm_bind(struct device *dev)  {  	struct exynos_drm_private *private; @@ -469,27 +488,6 @@ static struct platform_driver exynos_drm_platform_driver = {  	},  }; -static struct device *exynos_drm_get_dma_device(void) -{ -	int i; - -	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) { -		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i]; -		struct device *dev; - -		if (!info->driver || !(info->flags & DRM_DMA_DEVICE)) -			continue; - -		while ((dev = bus_find_device(&platform_bus_type, NULL, -					    &info->driver->driver, -					    (void *)platform_bus_type.match))) { -			put_device(dev); -			return dev; -		} -	} -	return NULL; -} -  static void exynos_drm_unregister_devices(void)  {  	int i; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index c6847fa708fa..589d465a7f88 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -194,11 +194,6 @@ struct drm_exynos_file_private {  /*   * Exynos drm private structure.   * - * @da_start: start address to device address space. - *	with iommu, device address space starts from this address - *	otherwise default one. - * @da_space_size: size of device address space. - *	if 0 then default value is used for it.   * @pending: the crtcs that have pending updates to finish   * @lock: protect access to @pending   * @wait: wait an atomic commit to finish diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 077de014d610..11cc01b47bc0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -247,6 +247,15 @@ struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev,  	if (IS_ERR(exynos_gem))  		return exynos_gem; +	if (!is_drm_iommu_supported(dev) && (flags & EXYNOS_BO_NONCONTIG)) { +		/* +		 * when no IOMMU is available, all allocated buffers are +		 * contiguous anyway, so drop EXYNOS_BO_NONCONTIG flag +		 */ +		flags &= ~EXYNOS_BO_NONCONTIG; +		DRM_WARN("Non-contiguous allocation is not supported without IOMMU, falling back to contiguous buffer\n"); +	} +  	/* set memory type and cache attribute from user side. */  	exynos_gem->flags = flags; @@ -506,6 +515,12 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)  }  /* low-level interface prime helpers */ +struct drm_gem_object *exynos_drm_gem_prime_import(struct drm_device *dev, +					    struct dma_buf *dma_buf) +{ +	return drm_gem_prime_import_dev(dev, dma_buf, to_dma_dev(dev)); +} +  struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj)  {  	struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index e86d1a9518c3..5a4c7de80f65 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -117,6 +117,8 @@ int exynos_drm_gem_fault(struct vm_fault *vmf);  int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);  /* low-level interface prime helpers */ +struct drm_gem_object *exynos_drm_gem_prime_import(struct drm_device *dev, +					    struct dma_buf *dma_buf);  struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj);  struct drm_gem_object *  exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c index ab19545d59a1..4ce2e6bd0680 100644 --- a/drivers/gpu/drm/i915/gvt/cfg_space.c +++ b/drivers/gpu/drm/i915/gvt/cfg_space.c @@ -208,6 +208,20 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu,  	return 0;  } +static int emulate_pci_rom_bar_write(struct intel_vgpu *vgpu, +	unsigned int offset, void *p_data, unsigned int bytes) +{ +	u32 *pval = (u32 *)(vgpu_cfg_space(vgpu) + offset); +	u32 new = *(u32 *)(p_data); + +	if ((new & PCI_ROM_ADDRESS_MASK) == PCI_ROM_ADDRESS_MASK) +		/* We don't have rom, return size of 0. */ +		*pval = 0; +	else +		vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes); +	return 0; +} +  static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,  	void *p_data, unsigned int bytes)  { @@ -300,6 +314,11 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,  	}  	switch (rounddown(offset, 4)) { +	case PCI_ROM_ADDRESS: +		if (WARN_ON(!IS_ALIGNED(offset, 4))) +			return -EINVAL; +		return emulate_pci_rom_bar_write(vgpu, offset, p_data, bytes); +  	case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5:  		if (WARN_ON(!IS_ALIGNED(offset, 4)))  			return -EINVAL; @@ -375,6 +394,8 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,  				pci_resource_len(gvt->dev_priv->drm.pdev, 0);  	vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size =  				pci_resource_len(gvt->dev_priv->drm.pdev, 2); + +	memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4);  }  /** diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index 701a3c6f1669..85d4c57870fb 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -1628,7 +1628,7 @@ static int perform_bb_shadow(struct parser_exec_state *s)  	struct intel_shadow_bb_entry *entry_obj;  	struct intel_vgpu *vgpu = s->vgpu;  	unsigned long gma = 0; -	uint32_t bb_size; +	int bb_size;  	void *dst = NULL;  	int ret = 0; diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 3c318439a659..309f3fa6794a 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -266,6 +266,8 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)  	/* Clear host CRT status, so guest couldn't detect this host CRT. */  	if (IS_BROADWELL(dev_priv))  		vgpu_vreg(vgpu, PCH_ADPA) &= ~ADPA_CRT_HOTPLUG_MONITOR_MASK; + +	vgpu_vreg(vgpu, PIPECONF(PIPE_A)) |= PIPECONF_ENABLE;  }  static void clean_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num) @@ -307,6 +309,7 @@ static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,  	port->type = type;  	emulate_monitor_status_change(vgpu); +  	return 0;  } diff --git a/drivers/gpu/drm/i915/gvt/execlist.c b/drivers/gpu/drm/i915/gvt/execlist.c index 4427be18e4a9..940cdaaa3f24 100644 --- a/drivers/gpu/drm/i915/gvt/execlist.c +++ b/drivers/gpu/drm/i915/gvt/execlist.c @@ -496,6 +496,12 @@ static int prepare_execlist_workload(struct intel_vgpu_workload *workload)  		goto err_unpin_mm;  	} +	ret = intel_gvt_generate_request(workload); +	if (ret) { +		gvt_vgpu_err("fail to generate request\n"); +		goto err_unpin_mm; +	} +  	ret = prepare_shadow_batch_buffer(workload);  	if (ret) {  		gvt_vgpu_err("fail to prepare_shadow_batch_buffer\n"); diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 2801d70579d8..8e331142badb 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -311,9 +311,9 @@ static inline int gtt_set_entry64(void *pt,  #define GTT_HAW 46 -#define ADDR_1G_MASK (((1UL << (GTT_HAW - 30 + 1)) - 1) << 30) -#define ADDR_2M_MASK (((1UL << (GTT_HAW - 21 + 1)) - 1) << 21) -#define ADDR_4K_MASK (((1UL << (GTT_HAW - 12 + 1)) - 1) << 12) +#define ADDR_1G_MASK (((1UL << (GTT_HAW - 30)) - 1) << 30) +#define ADDR_2M_MASK (((1UL << (GTT_HAW - 21)) - 1) << 21) +#define ADDR_4K_MASK (((1UL << (GTT_HAW - 12)) - 1) << 12)  static unsigned long gen8_gtt_get_pfn(struct intel_gvt_gtt_entry *e)  { diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index a5bed2e71b92..1f840f6b81bb 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -137,17 +137,26 @@ static int new_mmio_info(struct intel_gvt *gvt,  	return 0;  } -static int render_mmio_to_ring_id(struct intel_gvt *gvt, unsigned int reg) +/** + * intel_gvt_render_mmio_to_ring_id - convert a mmio offset into ring id + * @gvt: a GVT device + * @offset: register offset + * + * Returns: + * Ring ID on success, negative error code if failed. + */ +int intel_gvt_render_mmio_to_ring_id(struct intel_gvt *gvt, +		unsigned int offset)  {  	enum intel_engine_id id;  	struct intel_engine_cs *engine; -	reg &= ~GENMASK(11, 0); +	offset &= ~GENMASK(11, 0);  	for_each_engine(engine, gvt->dev_priv, id) { -		if (engine->mmio_base == reg) +		if (engine->mmio_base == offset)  			return id;  	} -	return -1; +	return -ENODEV;  }  #define offset_to_fence_num(offset) \ @@ -1381,40 +1390,6 @@ static int skl_power_well_ctl_write(struct intel_vgpu *vgpu,  	return intel_vgpu_default_mmio_write(vgpu, offset, &v, bytes);  } -static int skl_misc_ctl_write(struct intel_vgpu *vgpu, unsigned int offset, -		void *p_data, unsigned int bytes) -{ -	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; -	u32 v = *(u32 *)p_data; - -	if (!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv)) -		return intel_vgpu_default_mmio_write(vgpu, -				offset, p_data, bytes); - -	switch (offset) { -	case 0x4ddc: -		/* bypass WaCompressedResourceSamplerPbeMediaNewHashMode */ -		vgpu_vreg(vgpu, offset) = v & ~(1 << 31); -		break; -	case 0x42080: -		/* bypass WaCompressedResourceDisplayNewHashMode */ -		vgpu_vreg(vgpu, offset) = v & ~(1 << 15); -		break; -	case 0xe194: -		/* bypass WaCompressedResourceSamplerPbeMediaNewHashMode */ -		vgpu_vreg(vgpu, offset) = v & ~(1 << 8); -		break; -	case 0x7014: -		/* bypass WaCompressedResourceSamplerPbeMediaNewHashMode */ -		vgpu_vreg(vgpu, offset) = v & ~(1 << 13); -		break; -	default: -		return -EINVAL; -	} - -	return 0; -} -  static int skl_lcpll_write(struct intel_vgpu *vgpu, unsigned int offset,  		void *p_data, unsigned int bytes)  { @@ -1432,18 +1407,36 @@ static int skl_lcpll_write(struct intel_vgpu *vgpu, unsigned int offset,  static int mmio_read_from_hw(struct intel_vgpu *vgpu,  		unsigned int offset, void *p_data, unsigned int bytes)  { -	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; +	struct intel_gvt *gvt = vgpu->gvt; +	struct drm_i915_private *dev_priv = gvt->dev_priv; +	int ring_id; +	u32 ring_base; + +	ring_id = intel_gvt_render_mmio_to_ring_id(gvt, offset); +	/** +	 * Read HW reg in following case +	 * a. the offset isn't a ring mmio +	 * b. the offset's ring is running on hw. +	 * c. the offset is ring time stamp mmio +	 */ +	if (ring_id >= 0) +		ring_base = dev_priv->engine[ring_id]->mmio_base; + +	if (ring_id < 0 || vgpu  == gvt->scheduler.engine_owner[ring_id] || +	    offset == i915_mmio_reg_offset(RING_TIMESTAMP(ring_base)) || +	    offset == i915_mmio_reg_offset(RING_TIMESTAMP_UDW(ring_base))) { +		mmio_hw_access_pre(dev_priv); +		vgpu_vreg(vgpu, offset) = I915_READ(_MMIO(offset)); +		mmio_hw_access_post(dev_priv); +	} -	mmio_hw_access_pre(dev_priv); -	vgpu_vreg(vgpu, offset) = I915_READ(_MMIO(offset)); -	mmio_hw_access_post(dev_priv);  	return intel_vgpu_default_mmio_read(vgpu, offset, p_data, bytes);  }  static int elsp_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,  		void *p_data, unsigned int bytes)  { -	int ring_id = render_mmio_to_ring_id(vgpu->gvt, offset); +	int ring_id = intel_gvt_render_mmio_to_ring_id(vgpu->gvt, offset);  	struct intel_vgpu_execlist *execlist;  	u32 data = *(u32 *)p_data;  	int ret = 0; @@ -1470,7 +1463,7 @@ static int ring_mode_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,  		void *p_data, unsigned int bytes)  {  	u32 data = *(u32 *)p_data; -	int ring_id = render_mmio_to_ring_id(vgpu->gvt, offset); +	int ring_id = intel_gvt_render_mmio_to_ring_id(vgpu->gvt, offset);  	bool enable_execlist;  	write_vreg(vgpu, offset, p_data, bytes); @@ -1671,8 +1664,8 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)  	MMIO_DFH(GAM_ECOCHK, D_ALL, F_CMD_ACCESS, NULL, NULL);  	MMIO_DFH(GEN7_COMMON_SLICE_CHICKEN1, D_ALL, F_MODE_MASK | F_CMD_ACCESS,  		NULL, NULL); -	MMIO_DFH(COMMON_SLICE_CHICKEN2, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, -		 skl_misc_ctl_write); +	MMIO_DFH(COMMON_SLICE_CHICKEN2, D_ALL, F_MODE_MASK | F_CMD_ACCESS, +		 NULL, NULL);  	MMIO_DFH(0x9030, D_ALL, F_CMD_ACCESS, NULL, NULL);  	MMIO_DFH(0x20a0, D_ALL, F_CMD_ACCESS, NULL, NULL);  	MMIO_DFH(0x2420, D_ALL, F_CMD_ACCESS, NULL, NULL); @@ -2564,8 +2557,7 @@ static int init_broadwell_mmio_info(struct intel_gvt *gvt)  	MMIO_D(0x6e570, D_BDW_PLUS);  	MMIO_D(0x65f10, D_BDW_PLUS); -	MMIO_DFH(0xe194, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, -		 skl_misc_ctl_write); +	MMIO_DFH(0xe194, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);  	MMIO_DFH(0xe188, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);  	MMIO_DFH(HALF_SLICE_CHICKEN2, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);  	MMIO_DFH(0x2580, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL); @@ -2615,8 +2607,8 @@ static int init_skl_mmio_info(struct intel_gvt *gvt)  	MMIO_D(GEN9_MEDIA_PG_IDLE_HYSTERESIS, D_SKL_PLUS);  	MMIO_D(GEN9_RENDER_PG_IDLE_HYSTERESIS, D_SKL_PLUS);  	MMIO_DFH(GEN9_GAMT_ECO_REG_RW_IA, D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); -	MMIO_DH(0x4ddc, D_SKL_PLUS, NULL, skl_misc_ctl_write); -	MMIO_DH(0x42080, D_SKL_PLUS, NULL, skl_misc_ctl_write); +	MMIO_DH(0x4ddc, D_SKL_PLUS, NULL, NULL); +	MMIO_DH(0x42080, D_SKL_PLUS, NULL, NULL);  	MMIO_D(0x45504, D_SKL_PLUS);  	MMIO_D(0x45520, D_SKL_PLUS);  	MMIO_D(0x46000, D_SKL_PLUS); diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h index 32cd64ddad26..dbc04ad2c7a1 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.h +++ b/drivers/gpu/drm/i915/gvt/mmio.h @@ -65,6 +65,8 @@ struct intel_gvt_mmio_info {  	struct hlist_node node;  }; +int intel_gvt_render_mmio_to_ring_id(struct intel_gvt *gvt, +		unsigned int reg);  unsigned long intel_gvt_get_device_type(struct intel_gvt *gvt);  bool intel_gvt_match_device(struct intel_gvt *gvt, unsigned long device); diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index f6ded475bb2c..69f8f0d155b9 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -131,6 +131,20 @@ static inline bool is_gvt_request(struct drm_i915_gem_request *req)  	return i915_gem_context_force_single_submission(req->ctx);  } +static void save_ring_hw_state(struct intel_vgpu *vgpu, int ring_id) +{ +	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; +	u32 ring_base = dev_priv->engine[ring_id]->mmio_base; +	i915_reg_t reg; + +	reg = RING_INSTDONE(ring_base); +	vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg); +	reg = RING_ACTHD(ring_base); +	vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg); +	reg = RING_ACTHD_UDW(ring_base); +	vgpu_vreg(vgpu, i915_mmio_reg_offset(reg)) = I915_READ_FW(reg); +} +  static int shadow_context_status_change(struct notifier_block *nb,  		unsigned long action, void *data)  { @@ -140,9 +154,10 @@ static int shadow_context_status_change(struct notifier_block *nb,  	struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;  	enum intel_engine_id ring_id = req->engine->id;  	struct intel_vgpu_workload *workload; +	unsigned long flags;  	if (!is_gvt_request(req)) { -		spin_lock_bh(&scheduler->mmio_context_lock); +		spin_lock_irqsave(&scheduler->mmio_context_lock, flags);  		if (action == INTEL_CONTEXT_SCHEDULE_IN &&  		    scheduler->engine_owner[ring_id]) {  			/* Switch ring from vGPU to host. */ @@ -150,7 +165,7 @@ static int shadow_context_status_change(struct notifier_block *nb,  					      NULL, ring_id);  			scheduler->engine_owner[ring_id] = NULL;  		} -		spin_unlock_bh(&scheduler->mmio_context_lock); +		spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);  		return NOTIFY_OK;  	} @@ -161,7 +176,7 @@ static int shadow_context_status_change(struct notifier_block *nb,  	switch (action) {  	case INTEL_CONTEXT_SCHEDULE_IN: -		spin_lock_bh(&scheduler->mmio_context_lock); +		spin_lock_irqsave(&scheduler->mmio_context_lock, flags);  		if (workload->vgpu != scheduler->engine_owner[ring_id]) {  			/* Switch ring from host to vGPU or vGPU to vGPU. */  			intel_gvt_switch_mmio(scheduler->engine_owner[ring_id], @@ -170,13 +185,16 @@ static int shadow_context_status_change(struct notifier_block *nb,  		} else  			gvt_dbg_sched("skip ring %d mmio switch for vgpu%d\n",  				      ring_id, workload->vgpu->id); -		spin_unlock_bh(&scheduler->mmio_context_lock); +		spin_unlock_irqrestore(&scheduler->mmio_context_lock, flags);  		atomic_set(&workload->shadow_ctx_active, 1);  		break;  	case INTEL_CONTEXT_SCHEDULE_OUT: -	case INTEL_CONTEXT_SCHEDULE_PREEMPTED: +		save_ring_hw_state(workload->vgpu, ring_id);  		atomic_set(&workload->shadow_ctx_active, 0);  		break; +	case INTEL_CONTEXT_SCHEDULE_PREEMPTED: +		save_ring_hw_state(workload->vgpu, ring_id); +		break;  	default:  		WARN_ON(1);  		return NOTIFY_OK; @@ -253,7 +271,6 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)  	struct i915_gem_context *shadow_ctx = workload->vgpu->shadow_ctx;  	struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv;  	struct intel_engine_cs *engine = dev_priv->engine[ring_id]; -	struct drm_i915_gem_request *rq;  	struct intel_vgpu *vgpu = workload->vgpu;  	struct intel_ring *ring;  	int ret; @@ -299,6 +316,26 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)  	ret = populate_shadow_context(workload);  	if (ret)  		goto err_unpin; +	workload->shadowed = true; +	return 0; + +err_unpin: +	engine->context_unpin(engine, shadow_ctx); +err_shadow: +	release_shadow_wa_ctx(&workload->wa_ctx); +err_scan: +	return ret; +} + +int intel_gvt_generate_request(struct intel_vgpu_workload *workload) +{ +	int ring_id = workload->ring_id; +	struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv; +	struct intel_engine_cs *engine = dev_priv->engine[ring_id]; +	struct drm_i915_gem_request *rq; +	struct intel_vgpu *vgpu = workload->vgpu; +	struct i915_gem_context *shadow_ctx = vgpu->shadow_ctx; +	int ret;  	rq = i915_gem_request_alloc(dev_priv->engine[ring_id], shadow_ctx);  	if (IS_ERR(rq)) { @@ -313,14 +350,11 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)  	ret = copy_workload_to_ring_buffer(workload);  	if (ret)  		goto err_unpin; -	workload->shadowed = true;  	return 0;  err_unpin:  	engine->context_unpin(engine, shadow_ctx); -err_shadow:  	release_shadow_wa_ctx(&workload->wa_ctx); -err_scan:  	return ret;  } @@ -723,6 +757,9 @@ int intel_vgpu_init_gvt_context(struct intel_vgpu *vgpu)  	if (IS_ERR(vgpu->shadow_ctx))  		return PTR_ERR(vgpu->shadow_ctx); +	if (INTEL_INFO(vgpu->gvt->dev_priv)->has_logical_ring_preemption) +		vgpu->shadow_ctx->priority = INT_MAX; +  	vgpu->shadow_ctx->engine[RCS].initialised = true;  	bitmap_zero(vgpu->shadow_ctx_desc_updated, I915_NUM_ENGINES); diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h index 2d694f6c0907..b9f872204d7e 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.h +++ b/drivers/gpu/drm/i915/gvt/scheduler.h @@ -142,4 +142,7 @@ int intel_vgpu_init_gvt_context(struct intel_vgpu *vgpu);  void intel_vgpu_clean_gvt_context(struct intel_vgpu *vgpu);  void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx); + +int intel_gvt_generate_request(struct intel_vgpu_workload *workload); +  #endif diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 960d3d8b95b8..2cf10d17acfb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1714,6 +1714,7 @@ static int i915_drm_resume(struct drm_device *dev)  	intel_guc_resume(dev_priv);  	intel_modeset_init_hw(dev); +	intel_init_clock_gating(dev_priv);  	spin_lock_irq(&dev_priv->irq_lock);  	if (dev_priv->display.hpd_irq_setup) @@ -2618,6 +2619,8 @@ static int intel_runtime_resume(struct device *kdev)  		ret = vlv_resume_prepare(dev_priv, true);  	} +	intel_uncore_runtime_resume(dev_priv); +  	/*  	 * No point of rolling back things in case of an error, as the best  	 * we can do is to hope that things will still work (and disable RPM). diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 54b5d4c582b6..e143004e66d5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2368,6 +2368,9 @@ struct drm_i915_private {  	 */  	struct workqueue_struct *wq; +	/* ordered wq for modesets */ +	struct workqueue_struct *modeset_wq; +  	/* Display functions */  	struct drm_i915_display_funcs display; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3a140eedfc83..18de6569d04a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -330,17 +330,10 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj)  	 * must wait for all rendering to complete to the object (as unbinding  	 * must anyway), and retire the requests.  	 */ -	ret = i915_gem_object_wait(obj, -				   I915_WAIT_INTERRUPTIBLE | -				   I915_WAIT_LOCKED | -				   I915_WAIT_ALL, -				   MAX_SCHEDULE_TIMEOUT, -				   NULL); +	ret = i915_gem_object_set_to_cpu_domain(obj, false);  	if (ret)  		return ret; -	i915_gem_retire_requests(to_i915(obj->base.dev)); -  	while ((vma = list_first_entry_or_null(&obj->vma_list,  					       struct i915_vma,  					       obj_link))) { @@ -4712,17 +4705,19 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv)  	 * state. Fortunately, the kernel_context is disposable and we do  	 * not rely on its state.  	 */ -	ret = i915_gem_switch_to_kernel_context(dev_priv); -	if (ret) -		goto err_unlock; +	if (!i915_terminally_wedged(&dev_priv->gpu_error)) { +		ret = i915_gem_switch_to_kernel_context(dev_priv); +		if (ret) +			goto err_unlock; -	ret = i915_gem_wait_for_idle(dev_priv, -				     I915_WAIT_INTERRUPTIBLE | -				     I915_WAIT_LOCKED); -	if (ret && ret != -EIO) -		goto err_unlock; +		ret = i915_gem_wait_for_idle(dev_priv, +					     I915_WAIT_INTERRUPTIBLE | +					     I915_WAIT_LOCKED); +		if (ret && ret != -EIO) +			goto err_unlock; -	assert_kernel_context_is_current(dev_priv); +		assert_kernel_context_is_current(dev_priv); +	}  	i915_gem_contexts_lost(dev_priv);  	mutex_unlock(&dev->struct_mutex); @@ -4946,8 +4941,6 @@ int i915_gem_init(struct drm_i915_private *dev_priv)  {  	int ret; -	mutex_lock(&dev_priv->drm.struct_mutex); -  	/*  	 * We need to fallback to 4K pages since gvt gtt handling doesn't  	 * support huge page entries - we will need to check either hypervisor @@ -4967,18 +4960,19 @@ int i915_gem_init(struct drm_i915_private *dev_priv)  		dev_priv->gt.cleanup_engine = intel_logical_ring_cleanup;  	} +	ret = i915_gem_init_userptr(dev_priv); +	if (ret) +		return ret; +  	/* This is just a security blanket to placate dragons.  	 * On some systems, we very sporadically observe that the first TLBs  	 * used by the CS may be stale, despite us poking the TLB reset. If  	 * we hold the forcewake during initialisation these problems  	 * just magically go away.  	 */ +	mutex_lock(&dev_priv->drm.struct_mutex);  	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); -	ret = i915_gem_init_userptr(dev_priv); -	if (ret) -		goto out_unlock; -  	ret = i915_gem_init_ggtt(dev_priv);  	if (ret)  		goto out_unlock; diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 135fc750a837..382a77a1097e 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -172,7 +172,9 @@ i915_mmu_notifier_create(struct mm_struct *mm)  	spin_lock_init(&mn->lock);  	mn->mn.ops = &i915_gem_userptr_notifier;  	mn->objects = RB_ROOT_CACHED; -	mn->wq = alloc_workqueue("i915-userptr-release", WQ_UNBOUND, 0); +	mn->wq = alloc_workqueue("i915-userptr-release", +				 WQ_UNBOUND | WQ_MEM_RECLAIM, +				 0);  	if (mn->wq == NULL) {  		kfree(mn);  		return ERR_PTR(-ENOMEM); @@ -827,7 +829,7 @@ int i915_gem_init_userptr(struct drm_i915_private *dev_priv)  	dev_priv->mm.userptr_wq =  		alloc_workqueue("i915-userptr-acquire", -				WQ_HIGHPRI | WQ_MEM_RECLAIM, +				WQ_HIGHPRI | WQ_UNBOUND,  				0);  	if (!dev_priv->mm.userptr_wq)  		return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_gemfs.c b/drivers/gpu/drm/i915/i915_gemfs.c index e2993857df37..888b7d3f04c3 100644 --- a/drivers/gpu/drm/i915/i915_gemfs.c +++ b/drivers/gpu/drm/i915/i915_gemfs.c @@ -52,7 +52,8 @@ int i915_gemfs_init(struct drm_i915_private *i915)  	if (has_transparent_hugepage()) {  		struct super_block *sb = gemfs->mnt_sb; -		char options[] = "huge=within_size"; +		/* FIXME: Disabled until we get W/A for read BW issue. */ +		char options[] = "huge=never";  		int flags = 0;  		int err; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 68a58cce6ab1..333f40bc03bb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2951,9 +2951,6 @@ enum i915_power_well_id {  #define ILK_DPFC_CHICKEN	_MMIO(0x43224)  #define   ILK_DPFC_DISABLE_DUMMY0 (1<<8)  #define   ILK_DPFC_NUKE_ON_ANY_MODIFICATION	(1<<23) -#define   GLK_SKIP_SEG_EN		(1<<12) -#define   GLK_SKIP_SEG_COUNT_MASK	(3<<10) -#define   GLK_SKIP_SEG_COUNT(x)		((x)<<10)  #define ILK_FBC_RT_BASE		_MMIO(0x2128)  #define   ILK_FBC_RT_VALID	(1<<0)  #define   SNB_FBC_FRONT_BUFFER	(1<<1) @@ -6980,6 +6977,7 @@ enum {  #define  RESET_PCH_HANDSHAKE_ENABLE	(1<<4)  #define GEN8_CHICKEN_DCPR_1		_MMIO(0x46430) +#define   SKL_SELECT_ALTERNATE_DC_EXIT	(1<<30)  #define   MASK_WAKEMEM			(1<<13)  #define SKL_DFSM			_MMIO(0x51000) @@ -8525,6 +8523,7 @@ enum skl_power_gate {  #define  BXT_CDCLK_CD2X_DIV_SEL_2	(2<<22)  #define  BXT_CDCLK_CD2X_DIV_SEL_4	(3<<22)  #define  BXT_CDCLK_CD2X_PIPE(pipe)	((pipe)<<20) +#define  CDCLK_DIVMUX_CD_OVERRIDE	(1<<19)  #define  BXT_CDCLK_CD2X_PIPE_NONE	BXT_CDCLK_CD2X_PIPE(3)  #define  BXT_CDCLK_SSA_PRECHARGE_ENABLE	(1<<16)  #define  CDCLK_FREQ_DECIMAL_MASK	(0x7ff) diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c index e8ca67a129d2..ac236b88c99c 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/i915_sw_fence.c @@ -367,6 +367,7 @@ struct i915_sw_dma_fence_cb {  	struct dma_fence *dma;  	struct timer_list timer;  	struct irq_work work; +	struct rcu_head rcu;  };  static void timer_i915_sw_fence_wake(struct timer_list *t) @@ -406,7 +407,7 @@ static void irq_i915_sw_fence_work(struct irq_work *wrk)  	del_timer_sync(&cb->timer);  	dma_fence_put(cb->dma); -	kfree(cb); +	kfree_rcu(cb, rcu);  }  int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 48e1ba01ccf8..bcbc7abe6693 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -186,7 +186,7 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)  	struct intel_wait *wait, *n, *first;  	if (!b->irq_armed) -		return; +		goto wakeup_signaler;  	/* We only disarm the irq when we are idle (all requests completed),  	 * so if the bottom-half remains asleep, it missed the request @@ -208,6 +208,14 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)  	b->waiters = RB_ROOT;  	spin_unlock_irq(&b->rb_lock); + +	/* +	 * The signaling thread may be asleep holding a reference to a request, +	 * that had its signaling cancelled prior to being preempted. We need +	 * to kick the signaler, just in case, to release any such reference. +	 */ +wakeup_signaler: +	wake_up_process(b->signaler);  }  static bool use_fake_irq(const struct intel_breadcrumbs *b) @@ -517,6 +525,7 @@ static void __intel_engine_remove_wait(struct intel_engine_cs *engine,  	GEM_BUG_ON(RB_EMPTY_NODE(&wait->node));  	rb_erase(&wait->node, &b->waiters); +	RB_CLEAR_NODE(&wait->node);  out:  	GEM_BUG_ON(b->irq_wait == wait); @@ -650,23 +659,15 @@ static int intel_breadcrumbs_signaler(void *arg)  		}  		if (unlikely(do_schedule)) { -			DEFINE_WAIT(exec); -  			if (kthread_should_park())  				kthread_parkme(); -			if (kthread_should_stop()) { -				GEM_BUG_ON(request); +			if (unlikely(kthread_should_stop())) { +				i915_gem_request_put(request);  				break;  			} -			if (request) -				add_wait_queue(&request->execute, &exec); -  			schedule(); - -			if (request) -				remove_wait_queue(&request->execute, &exec);  		}  		i915_gem_request_put(request);  	} while (1); diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index b2a6d62b71c0..60cf4e58389a 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -860,16 +860,10 @@ static void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv,  static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco)  { -	int min_cdclk = skl_calc_cdclk(0, vco);  	u32 val;  	WARN_ON(vco != 8100000 && vco != 8640000); -	/* select the minimum CDCLK before enabling DPLL 0 */ -	val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_cdclk); -	I915_WRITE(CDCLK_CTL, val); -	POSTING_READ(CDCLK_CTL); -  	/*  	 * We always enable DPLL0 with the lowest link rate possible, but still  	 * taking into account the VCO required to operate the eDP panel at the @@ -923,7 +917,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv,  {  	int cdclk = cdclk_state->cdclk;  	int vco = cdclk_state->vco; -	u32 freq_select, pcu_ack; +	u32 freq_select, pcu_ack, cdclk_ctl;  	int ret;  	WARN_ON((cdclk == 24000) != (vco == 0)); @@ -940,7 +934,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv,  		return;  	} -	/* set CDCLK_CTL */ +	/* Choose frequency for this cdclk */  	switch (cdclk) {  	case 450000:  	case 432000: @@ -968,10 +962,33 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv,  	    dev_priv->cdclk.hw.vco != vco)  		skl_dpll0_disable(dev_priv); +	cdclk_ctl = I915_READ(CDCLK_CTL); + +	if (dev_priv->cdclk.hw.vco != vco) { +		/* Wa Display #1183: skl,kbl,cfl */ +		cdclk_ctl &= ~(CDCLK_FREQ_SEL_MASK | CDCLK_FREQ_DECIMAL_MASK); +		cdclk_ctl |= freq_select | skl_cdclk_decimal(cdclk); +		I915_WRITE(CDCLK_CTL, cdclk_ctl); +	} + +	/* Wa Display #1183: skl,kbl,cfl */ +	cdclk_ctl |= CDCLK_DIVMUX_CD_OVERRIDE; +	I915_WRITE(CDCLK_CTL, cdclk_ctl); +	POSTING_READ(CDCLK_CTL); +  	if (dev_priv->cdclk.hw.vco != vco)  		skl_dpll0_enable(dev_priv, vco); -	I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(cdclk)); +	/* Wa Display #1183: skl,kbl,cfl */ +	cdclk_ctl &= ~(CDCLK_FREQ_SEL_MASK | CDCLK_FREQ_DECIMAL_MASK); +	I915_WRITE(CDCLK_CTL, cdclk_ctl); + +	cdclk_ctl |= freq_select | skl_cdclk_decimal(cdclk); +	I915_WRITE(CDCLK_CTL, cdclk_ctl); + +	/* Wa Display #1183: skl,kbl,cfl */ +	cdclk_ctl &= ~CDCLK_DIVMUX_CD_OVERRIDE; +	I915_WRITE(CDCLK_CTL, cdclk_ctl);  	POSTING_READ(CDCLK_CTL);  	/* inform PCU of the change */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 933c18fd4258..58a3755544b2 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2128,9 +2128,12 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder,  	if (WARN_ON(!pll))  		return; +	 mutex_lock(&dev_priv->dpll_lock); +  	if (IS_CANNONLAKE(dev_priv)) {  		/* Configure DPCLKA_CFGCR0 to map the DPLL to the DDI. */  		val = I915_READ(DPCLKA_CFGCR0); +		val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);  		val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->id, port);  		I915_WRITE(DPCLKA_CFGCR0, val); @@ -2156,6 +2159,8 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder,  	} else if (INTEL_INFO(dev_priv)->gen < 9) {  		I915_WRITE(PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll));  	} + +	mutex_unlock(&dev_priv->dpll_lock);  }  static void intel_ddi_clk_disable(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 878acc432a4b..123585eeb87d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1000,7 +1000,8 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,  	return crtc->config->cpu_transcoder;  } -static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv, enum pipe pipe) +static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv, +				    enum pipe pipe)  {  	i915_reg_t reg = PIPEDSL(pipe);  	u32 line1, line2; @@ -1015,7 +1016,28 @@ static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv, enum pipe pipe)  	msleep(5);  	line2 = I915_READ(reg) & line_mask; -	return line1 == line2; +	return line1 != line2; +} + +static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state) +{ +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); +	enum pipe pipe = crtc->pipe; + +	/* Wait for the display line to settle/start moving */ +	if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100)) +		DRM_ERROR("pipe %c scanline %s wait timed out\n", +			  pipe_name(pipe), onoff(state)); +} + +static void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc) +{ +	wait_for_pipe_scanline_moving(crtc, false); +} + +static void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc) +{ +	wait_for_pipe_scanline_moving(crtc, true);  }  /* @@ -1038,7 +1060,6 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)  {  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);  	enum transcoder cpu_transcoder = crtc->config->cpu_transcoder; -	enum pipe pipe = crtc->pipe;  	if (INTEL_GEN(dev_priv) >= 4) {  		i915_reg_t reg = PIPECONF(cpu_transcoder); @@ -1049,9 +1070,7 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)  					    100))  			WARN(1, "pipe_off wait timed out\n");  	} else { -		/* Wait for the display line to settle */ -		if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100)) -			WARN(1, "pipe_off wait timed out\n"); +		intel_wait_for_pipe_scanline_stopped(crtc);  	}  } @@ -1936,15 +1955,14 @@ static void intel_enable_pipe(struct intel_crtc *crtc)  	POSTING_READ(reg);  	/* -	 * Until the pipe starts DSL will read as 0, which would cause -	 * an apparent vblank timestamp jump, which messes up also the -	 * frame count when it's derived from the timestamps. So let's -	 * wait for the pipe to start properly before we call -	 * drm_crtc_vblank_on() +	 * Until the pipe starts PIPEDSL reads will return a stale value, +	 * which causes an apparent vblank timestamp jump when PIPEDSL +	 * resets to its proper value. That also messes up the frame count +	 * when it's derived from the timestamps. So let's wait for the +	 * pipe to start properly before we call drm_crtc_vblank_on()  	 */ -	if (dev->max_vblank_count == 0 && -	    wait_for(intel_get_crtc_scanline(crtc) != crtc->scanline_offset, 50)) -		DRM_ERROR("pipe %c didn't start\n", pipe_name(pipe)); +	if (dev->max_vblank_count == 0) +		intel_wait_for_pipe_scanline_moving(crtc);  }  /** @@ -9926,11 +9944,10 @@ found:  	}  	ret = intel_modeset_setup_plane_state(state, crtc, mode, fb, 0, 0); +	drm_framebuffer_put(fb);  	if (ret)  		goto fail; -	drm_framebuffer_put(fb); -  	ret = drm_atomic_set_mode_for_crtc(&crtc_state->base, mode);  	if (ret)  		goto fail; @@ -12527,11 +12544,15 @@ static int intel_atomic_commit(struct drm_device *dev,  	INIT_WORK(&state->commit_work, intel_atomic_commit_work);  	i915_sw_fence_commit(&intel_state->commit_ready); -	if (nonblock) +	if (nonblock && intel_state->modeset) { +		queue_work(dev_priv->modeset_wq, &state->commit_work); +	} else if (nonblock) {  		queue_work(system_unbound_wq, &state->commit_work); -	else +	} else { +		if (intel_state->modeset) +			flush_workqueue(dev_priv->modeset_wq);  		intel_atomic_commit_tail(state); - +	}  	return 0;  } @@ -13177,7 +13198,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)  	primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe);  	primary->check_plane = intel_check_primary_plane; -	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { +	if (INTEL_GEN(dev_priv) >= 10) {  		intel_primary_formats = skl_primary_formats;  		num_formats = ARRAY_SIZE(skl_primary_formats);  		modifiers = skl_format_modifiers_ccs; @@ -14445,6 +14466,8 @@ int intel_modeset_init(struct drm_device *dev)  	enum pipe pipe;  	struct intel_crtc *crtc; +	dev_priv->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0); +  	drm_mode_config_init(dev);  	dev->mode_config.min_width = 0; @@ -14643,6 +14666,8 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)  void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)  { +	struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); +  	DRM_DEBUG_KMS("disabling pipe %c due to force quirk\n",  		      pipe_name(pipe)); @@ -14652,8 +14677,7 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)  	I915_WRITE(PIPECONF(pipe), 0);  	POSTING_READ(PIPECONF(pipe)); -	if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100)) -		DRM_ERROR("pipe %c off wait timed out\n", pipe_name(pipe)); +	intel_wait_for_pipe_scanline_stopped(crtc);  	I915_WRITE(DPLL(pipe), DPLL_VGA_MODE_DIS);  	POSTING_READ(DPLL(pipe)); @@ -15252,6 +15276,8 @@ void intel_modeset_cleanup(struct drm_device *dev)  	intel_cleanup_gt_powersave(dev_priv);  	intel_teardown_gmbus(dev_priv); + +	destroy_workqueue(dev_priv->modeset_wq);  }  void intel_connector_attach_encoder(struct intel_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7bc60c848940..6c7f8bca574e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1736,7 +1736,7 @@ extern struct drm_display_mode *intel_find_panel_downclock(  int intel_backlight_device_register(struct intel_connector *connector);  void intel_backlight_device_unregister(struct intel_connector *connector);  #else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ -static int intel_backlight_device_register(struct intel_connector *connector) +static inline int intel_backlight_device_register(struct intel_connector *connector)  {  	return 0;  } diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index b8af35187d22..ea96682568e8 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -697,10 +697,8 @@ static void intel_fbdev_initial_config(void *data, async_cookie_t cookie)  	/* Due to peculiar init order wrt to hpd handling this is separate. */  	if (drm_fb_helper_initial_config(&ifbdev->helper, -					 ifbdev->preferred_bpp)) { +					 ifbdev->preferred_bpp))  		intel_fbdev_unregister(to_i915(ifbdev->helper.dev)); -		intel_fbdev_fini(to_i915(ifbdev->helper.dev)); -	}  }  void intel_fbdev_initial_config_async(struct drm_device *dev) @@ -800,7 +798,11 @@ void intel_fbdev_output_poll_changed(struct drm_device *dev)  {  	struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; -	if (ifbdev) +	if (!ifbdev) +		return; + +	intel_fbdev_sync(ifbdev); +	if (ifbdev->vma)  		drm_fb_helper_hotplug_event(&ifbdev->helper);  } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 5132dc814788..4dea833f9d1b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -487,7 +487,8 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,  					   crtc_state->limited_color_range ?  					   HDMI_QUANTIZATION_RANGE_LIMITED :  					   HDMI_QUANTIZATION_RANGE_FULL, -					   intel_hdmi->rgb_quant_range_selectable); +					   intel_hdmi->rgb_quant_range_selectable, +					   is_hdmi2_sink);  	/* TODO: handle pixel repetition for YCBCR420 outputs */  	intel_write_infoframe(encoder, crtc_state, &frame); diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index eb5827110d8f..49fdf09f9919 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -438,7 +438,9 @@ static bool  gmbus_is_index_read(struct i2c_msg *msgs, int i, int num)  {  	return (i + 1 < num && -		!(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 && +		msgs[i].addr == msgs[i + 1].addr && +		!(msgs[i].flags & I2C_M_RD) && +		(msgs[i].len == 1 || msgs[i].len == 2) &&  		(msgs[i + 1].flags & I2C_M_RD));  } diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index 3bf65288ffff..5809b29044fc 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -193,7 +193,7 @@ static bool lpe_audio_detect(struct drm_i915_private *dev_priv)  		};  		if (!pci_dev_present(atom_hdaudio_ids)) { -			DRM_INFO("%s\n", "HDaudio controller not detected, using LPE audio instead\n"); +			DRM_INFO("HDaudio controller not detected, using LPE audio instead\n");  			lpe_present = true;  		}  	} diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f4a4e9496893..f0d0dbab4150 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -124,7 +124,6 @@ static void bxt_init_clock_gating(struct drm_i915_private *dev_priv)  static void glk_init_clock_gating(struct drm_i915_private *dev_priv)  { -	u32 val;  	gen9_init_clock_gating(dev_priv);  	/* @@ -144,11 +143,6 @@ static void glk_init_clock_gating(struct drm_i915_private *dev_priv)  		I915_WRITE(CHICKEN_MISC_2, val);  	} -	/* Display WA #1133: WaFbcSkipSegments:glk */ -	val = I915_READ(ILK_DPFC_CHICKEN); -	val &= ~GLK_SKIP_SEG_COUNT_MASK; -	val |= GLK_SKIP_SEG_EN | GLK_SKIP_SEG_COUNT(1); -	I915_WRITE(ILK_DPFC_CHICKEN, val);  }  static void i915_pineview_get_mem_freq(struct drm_i915_private *dev_priv) @@ -8517,7 +8511,6 @@ static void cnp_init_clock_gating(struct drm_i915_private *dev_priv)  static void cnl_init_clock_gating(struct drm_i915_private *dev_priv)  { -	u32 val;  	cnp_init_clock_gating(dev_priv);  	/* This is not an Wa. Enable for better image quality */ @@ -8537,12 +8530,6 @@ static void cnl_init_clock_gating(struct drm_i915_private *dev_priv)  		I915_WRITE(SLICE_UNIT_LEVEL_CLKGATE,  			   I915_READ(SLICE_UNIT_LEVEL_CLKGATE) |  			   SARBUNIT_CLKGATE_DIS); - -	/* Display WA #1133: WaFbcSkipSegments:cnl */ -	val = I915_READ(ILK_DPFC_CHICKEN); -	val &= ~GLK_SKIP_SEG_COUNT_MASK; -	val |= GLK_SKIP_SEG_EN | GLK_SKIP_SEG_COUNT(1); -	I915_WRITE(ILK_DPFC_CHICKEN, val);  }  static void cfl_init_clock_gating(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 6e3b430fccdc..55ea5eb3b7df 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -590,7 +590,7 @@ static void hsw_psr_disable(struct intel_dp *intel_dp,  	struct drm_i915_private *dev_priv = to_i915(dev);  	if (dev_priv->psr.active) { -		i915_reg_t psr_ctl; +		i915_reg_t psr_status;  		u32 psr_status_mask;  		if (dev_priv->psr.aux_frame_sync) @@ -599,24 +599,24 @@ static void hsw_psr_disable(struct intel_dp *intel_dp,  					0);  		if (dev_priv->psr.psr2_support) { -			psr_ctl = EDP_PSR2_CTL; +			psr_status = EDP_PSR2_STATUS_CTL;  			psr_status_mask = EDP_PSR2_STATUS_STATE_MASK; -			I915_WRITE(psr_ctl, -				   I915_READ(psr_ctl) & +			I915_WRITE(EDP_PSR2_CTL, +				   I915_READ(EDP_PSR2_CTL) &  				   ~(EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE));  		} else { -			psr_ctl = EDP_PSR_STATUS_CTL; +			psr_status = EDP_PSR_STATUS_CTL;  			psr_status_mask = EDP_PSR_STATUS_STATE_MASK; -			I915_WRITE(psr_ctl, -				   I915_READ(psr_ctl) & ~EDP_PSR_ENABLE); +			I915_WRITE(EDP_PSR_CTL, +				   I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);  		}  		/* Wait till PSR is idle */  		if (intel_wait_for_register(dev_priv, -					    psr_ctl, psr_status_mask, 0, +					    psr_status, psr_status_mask, 0,  					    2000))  			DRM_ERROR("Timed out waiting for PSR Idle State\n"); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 8af286c63d3b..7e115f3927f6 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -598,6 +598,11 @@ void gen9_enable_dc5(struct drm_i915_private *dev_priv)  	DRM_DEBUG_KMS("Enabling DC5\n"); +	/* Wa Display #1183: skl,kbl,cfl */ +	if (IS_GEN9_BC(dev_priv)) +		I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | +			   SKL_SELECT_ALTERNATE_DC_EXIT); +  	gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);  } @@ -625,6 +630,11 @@ void skl_disable_dc6(struct drm_i915_private *dev_priv)  {  	DRM_DEBUG_KMS("Disabling DC6\n"); +	/* Wa Display #1183: skl,kbl,cfl */ +	if (IS_GEN9_BC(dev_priv)) +		I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | +			   SKL_SELECT_ALTERNATE_DC_EXIT); +  	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);  } @@ -1786,6 +1796,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,  	GLK_DISPLAY_POWERWELL_2_POWER_DOMAINS |		\  	BIT_ULL(POWER_DOMAIN_MODESET) |			\  	BIT_ULL(POWER_DOMAIN_AUX_A) |			\ +	BIT_ULL(POWER_DOMAIN_GMBUS) |			\  	BIT_ULL(POWER_DOMAIN_INIT))  #define CNL_DISPLAY_POWERWELL_2_POWER_DOMAINS (		\ diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 20e3c65c0999..8c2ce81f01c2 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -434,6 +434,12 @@ void intel_uncore_resume_early(struct drm_i915_private *dev_priv)  	i915_check_and_clear_faults(dev_priv);  } +void intel_uncore_runtime_resume(struct drm_i915_private *dev_priv) +{ +	iosf_mbi_register_pmic_bus_access_notifier( +		&dev_priv->uncore.pmic_bus_access_nb); +} +  void intel_uncore_sanitize(struct drm_i915_private *dev_priv)  {  	i915_modparams.enable_rc6 = @@ -1240,8 +1246,15 @@ static int i915_pmic_bus_access_notifier(struct notifier_block *nb,  		 * bus, which will be busy after this notification, leading to:  		 * "render: timed out waiting for forcewake ack request."  		 * errors. +		 * +		 * The notifier is unregistered during intel_runtime_suspend(), +		 * so it's ok to access the HW here without holding a RPM +		 * wake reference -> disable wakeref asserts for the time of +		 * the access.  		 */ +		disable_rpm_wakeref_asserts(dev_priv);  		intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); +		enable_rpm_wakeref_asserts(dev_priv);  		break;  	case MBI_PMIC_BUS_ACCESS_END:  		intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index 582771251b57..9ce079b5dd0d 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -134,6 +134,7 @@ bool intel_uncore_arm_unclaimed_mmio_detection(struct drm_i915_private *dev_priv  void intel_uncore_fini(struct drm_i915_private *dev_priv);  void intel_uncore_suspend(struct drm_i915_private *dev_priv);  void intel_uncore_resume_early(struct drm_i915_private *dev_priv); +void intel_uncore_runtime_resume(struct drm_i915_private *dev_priv);  u64 intel_uncore_edram_size(struct drm_i915_private *dev_priv);  void assert_forcewakes_inactive(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 93c7e3f9b4a8..17d2f3a1c562 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -133,9 +133,16 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)  			plane_disabling = true;  	} -	if (plane_disabling) { -		drm_atomic_helper_wait_for_vblanks(dev, state); +	/* +	 * The flip done wait is only strictly required by imx-drm if a deferred +	 * plane disable is in-flight. As the core requires blocking commits +	 * to wait for the flip it is done here unconditionally. This keeps the +	 * workitem around a bit longer than required for the majority of +	 * non-blocking commits, but we accept that for the sake of simplicity. +	 */ +	drm_atomic_helper_wait_for_flip_done(dev, state); +	if (plane_disabling) {  		for_each_old_plane_in_state(state, plane, old_plane_state, i)  			ipu_plane_disable_deferred(plane); diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 2615912430cc..435ff8662cfa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -224,7 +224,7 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,  		/* Determine if we can get a cache-coherent map, forcing  		 * uncached mapping if we can't.  		 */ -		if (mmu->type[drm->ttm.type_host].type & NVIF_MEM_UNCACHED) +		if (!nouveau_drm_use_coherent_gpu_mapping(drm))  			nvbo->force_coherent = true;  	} @@ -262,7 +262,8 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,  		if (cli->device.info.family > NV_DEVICE_INFO_V0_CURIE &&  		    (flags & TTM_PL_FLAG_VRAM) && !vmm->page[i].vram)  			continue; -		if ((flags & TTM_PL_FLAG_TT  ) && !vmm->page[i].host) +		if ((flags & TTM_PL_FLAG_TT) && +		    (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT))  			continue;  		/* Select this page size if it's the first that supports diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 8d4a5be3b913..56fe261b6268 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -152,9 +152,9 @@ nouveau_cli_work_queue(struct nouveau_cli *cli, struct dma_fence *fence,  	work->cli = cli;  	mutex_lock(&cli->lock);  	list_add_tail(&work->head, &cli->worker); -	mutex_unlock(&cli->lock);  	if (dma_fence_add_callback(fence, &work->cb, nouveau_cli_work_fence))  		nouveau_cli_work_fence(fence, &work->cb); +	mutex_unlock(&cli->lock);  }  static void diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 3331e82ae9e7..96f6bd8aee5d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -157,8 +157,8 @@ struct nouveau_drm {  		struct nvif_object copy;  		int mtrr;  		int type_vram; -		int type_host; -		int type_ncoh; +		int type_host[2]; +		int type_ncoh[2];  	} ttm;  	/* GEM interface support */ @@ -217,6 +217,13 @@ nouveau_drm(struct drm_device *dev)  	return dev->dev_private;  } +static inline bool +nouveau_drm_use_coherent_gpu_mapping(struct nouveau_drm *drm) +{ +	struct nvif_mmu *mmu = &drm->client.mmu; +	return !(mmu->type[drm->ttm.type_host[0]].type & NVIF_MEM_UNCACHED); +} +  int nouveau_pmops_suspend(struct device *);  int nouveau_pmops_resume(struct device *);  bool nouveau_pmops_runtime(void); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index c533d8e04afc..be7357bf2246 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -429,7 +429,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)  	drm_fb_helper_unregister_fbi(&fbcon->helper);  	drm_fb_helper_fini(&fbcon->helper); -	if (nouveau_fb->nvbo) { +	if (nouveau_fb && nouveau_fb->nvbo) {  		nouveau_vma_del(&nouveau_fb->vma);  		nouveau_bo_unmap(nouveau_fb->nvbo);  		nouveau_bo_unpin(nouveau_fb->nvbo); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 589a9621db76..c002f8968507 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -103,10 +103,10 @@ nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt)  	u8 type;  	int ret; -	if (mmu->type[drm->ttm.type_host].type & NVIF_MEM_UNCACHED) -		type = drm->ttm.type_ncoh; +	if (!nouveau_drm_use_coherent_gpu_mapping(drm)) +		type = drm->ttm.type_ncoh[!!mem->kind];  	else -		type = drm->ttm.type_host; +		type = drm->ttm.type_host[0];  	if (mem->kind && !(mmu->type[type].type & NVIF_MEM_KIND))  		mem->comp = mem->kind = 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 08b974b30482..dff51a0ee028 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -235,27 +235,46 @@ nouveau_ttm_global_release(struct nouveau_drm *drm)  	drm->ttm.mem_global_ref.release = NULL;  } -int -nouveau_ttm_init(struct nouveau_drm *drm) +static int +nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind)  { -	struct nvkm_device *device = nvxx_device(&drm->client.device); -	struct nvkm_pci *pci = device->pci;  	struct nvif_mmu *mmu = &drm->client.mmu; -	struct drm_device *dev = drm->dev; -	int typei, ret; +	int typei;  	typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE | -						   NVIF_MEM_COHERENT); +					    kind | NVIF_MEM_COHERENT);  	if (typei < 0)  		return -ENOSYS; -	drm->ttm.type_host = typei; +	drm->ttm.type_host[!!kind] = typei; -	typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE); +	typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE | kind);  	if (typei < 0)  		return -ENOSYS; -	drm->ttm.type_ncoh = typei; +	drm->ttm.type_ncoh[!!kind] = typei; +	return 0; +} + +int +nouveau_ttm_init(struct nouveau_drm *drm) +{ +	struct nvkm_device *device = nvxx_device(&drm->client.device); +	struct nvkm_pci *pci = device->pci; +	struct nvif_mmu *mmu = &drm->client.mmu; +	struct drm_device *dev = drm->dev; +	int typei, ret; + +	ret = nouveau_ttm_init_host(drm, 0); +	if (ret) +		return ret; + +	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA && +	    drm->client.device.info.chipset != 0x50) { +		ret = nouveau_ttm_init_host(drm, NVIF_MEM_KIND); +		if (ret) +			return ret; +	}  	if (drm->client.device.info.platform != NV_DEVICE_INFO_V0_SOC &&  	    drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { diff --git a/drivers/gpu/drm/nouveau/nouveau_vmm.c b/drivers/gpu/drm/nouveau/nouveau_vmm.c index 9e2628dd8e4d..f5371d96b003 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_vmm.c @@ -67,8 +67,8 @@ nouveau_vma_del(struct nouveau_vma **pvma)  			nvif_vmm_put(&vma->vmm->vmm, &tmp);  		}  		list_del(&vma->head); -		*pvma = NULL;  		kfree(*pvma); +		*pvma = NULL;  	}  } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index e14643615698..00eeaaffeae5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2369,7 +2369,7 @@ nv13b_chipset = {  	.imem = gk20a_instmem_new,  	.ltc = gp100_ltc_new,  	.mc = gp10b_mc_new, -	.mmu = gf100_mmu_new, +	.mmu = gp10b_mmu_new,  	.secboot = gp10b_secboot_new,  	.pmu = gm20b_pmu_new,  	.timer = gk20a_timer_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c index 972370ed36f0..7c7efa4ea0d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c @@ -36,6 +36,7 @@ nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)  			if (data) {  				*ver = nvbios_rd08(bios, data + 0x00);  				switch (*ver) { +				case 0x20:  				case 0x21:  				case 0x30:  				case 0x40: @@ -63,6 +64,7 @@ nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx,  	if (data && idx < *cnt) {  		u16 outp = nvbios_rd16(bios, data + *hdr + idx * *len);  		switch (*ver * !!outp) { +		case 0x20:  		case 0x21:  		case 0x30:  			*hdr = nvbios_rd08(bios, data + 0x04); @@ -96,12 +98,16 @@ nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx,  		info->type = nvbios_rd16(bios, data + 0x00);  		info->mask = nvbios_rd16(bios, data + 0x02);  		switch (*ver) { +		case 0x20: +			info->mask |= 0x00c0; /* match any link */ +			/* fall-through */  		case 0x21:  		case 0x30:  			info->flags     = nvbios_rd08(bios, data + 0x05);  			info->script[0] = nvbios_rd16(bios, data + 0x06);  			info->script[1] = nvbios_rd16(bios, data + 0x08); -			info->lnkcmp    = nvbios_rd16(bios, data + 0x0a); +			if (*len >= 0x0c) +				info->lnkcmp    = nvbios_rd16(bios, data + 0x0a);  			if (*len >= 0x0f) {  				info->script[2] = nvbios_rd16(bios, data + 0x0c);  				info->script[3] = nvbios_rd16(bios, data + 0x0e); @@ -170,6 +176,7 @@ nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,  	memset(info, 0x00, sizeof(*info));  	if (data) {  		switch (*ver) { +		case 0x20:  		case 0x21:  			info->dc    = nvbios_rd08(bios, data + 0x02);  			info->pe    = nvbios_rd08(bios, data + 0x03); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 1ba7289684aa..db48a1daca0c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -249,7 +249,7 @@ nv50_instobj_acquire(struct nvkm_memory *memory)  			iobj->base.memory.ptrs = &nv50_instobj_fast;  		else  			iobj->base.memory.ptrs = &nv50_instobj_slow; -		refcount_inc(&iobj->maps); +		refcount_set(&iobj->maps, 1);  	}  	mutex_unlock(&imem->subdev.mutex); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c index b1b1f3626b96..deb96de54b00 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -136,6 +136,13 @@ nvkm_pci_init(struct nvkm_subdev *subdev)  		return ret;  	pci->irq = pdev->irq; + +	/* Ensure MSI interrupts are armed, for the case where there are +	 * already interrupts pending (for whatever reason) at load time. +	 */ +	if (pci->msi) +		pci->func->msi_rearm(pci); +  	return ret;  } diff --git a/drivers/gpu/drm/omapdrm/displays/Kconfig b/drivers/gpu/drm/omapdrm/displays/Kconfig index c226da145fb3..a349cb61961e 100644 --- a/drivers/gpu/drm/omapdrm/displays/Kconfig +++ b/drivers/gpu/drm/omapdrm/displays/Kconfig @@ -35,6 +35,7 @@ config DRM_OMAP_CONNECTOR_ANALOG_TV  config DRM_OMAP_PANEL_DPI  	tristate "Generic DPI panel" +	depends on BACKLIGHT_CLASS_DEVICE  	help  	  Driver for generic DPI panels. diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index daf286fc8a40..ca1e3b489540 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -566,8 +566,8 @@ static int dpi_verify_pll(struct dss_pll *pll)  }  static const struct soc_device_attribute dpi_soc_devices[] = { -	{ .family = "OMAP3[456]*" }, -	{ .family = "[AD]M37*" }, +	{ .machine = "OMAP3[456]*" }, +	{ .machine = "[AD]M37*" },  	{ /* sentinel */ }  }; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c index d86873f2abe6..23db74ae1826 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c @@ -78,6 +78,8 @@ static void hdmi_cec_received_msg(struct hdmi_core_data *core)  			/* then read the message */  			msg.len = cnt & 0xf; +			if (msg.len > CEC_MAX_MSG_SIZE - 2) +				msg.len = CEC_MAX_MSG_SIZE - 2;  			msg.msg[0] = hdmi_read_reg(core->base,  						   HDMI_CEC_RX_CMD_HEADER);  			msg.msg[1] = hdmi_read_reg(core->base, @@ -104,26 +106,6 @@ static void hdmi_cec_received_msg(struct hdmi_core_data *core)  	}  } -static void hdmi_cec_transmit_fifo_empty(struct hdmi_core_data *core, u32 stat1) -{ -	if (stat1 & 2) { -		u32 dbg3 = hdmi_read_reg(core->base, HDMI_CEC_DBG_3); - -		cec_transmit_done(core->adap, -				  CEC_TX_STATUS_NACK | -				  CEC_TX_STATUS_MAX_RETRIES, -				  0, (dbg3 >> 4) & 7, 0, 0); -	} else if (stat1 & 1) { -		cec_transmit_done(core->adap, -				  CEC_TX_STATUS_ARB_LOST | -				  CEC_TX_STATUS_MAX_RETRIES, -				  0, 0, 0, 0); -	} else if (stat1 == 0) { -		cec_transmit_done(core->adap, CEC_TX_STATUS_OK, -				  0, 0, 0, 0); -	} -} -  void hdmi4_cec_irq(struct hdmi_core_data *core)  {  	u32 stat0 = hdmi_read_reg(core->base, HDMI_CEC_INT_STATUS_0); @@ -132,27 +114,21 @@ void hdmi4_cec_irq(struct hdmi_core_data *core)  	hdmi_write_reg(core->base, HDMI_CEC_INT_STATUS_0, stat0);  	hdmi_write_reg(core->base, HDMI_CEC_INT_STATUS_1, stat1); -	if (stat0 & 0x40) +	if (stat0 & 0x20) { +		cec_transmit_done(core->adap, CEC_TX_STATUS_OK, +				  0, 0, 0, 0);  		REG_FLD_MOD(core->base, HDMI_CEC_DBG_3, 0x1, 7, 7); -	else if (stat0 & 0x24) -		hdmi_cec_transmit_fifo_empty(core, stat1); -	if (stat1 & 2) { +	} else if (stat1 & 0x02) {  		u32 dbg3 = hdmi_read_reg(core->base, HDMI_CEC_DBG_3);  		cec_transmit_done(core->adap,  				  CEC_TX_STATUS_NACK |  				  CEC_TX_STATUS_MAX_RETRIES,  				  0, (dbg3 >> 4) & 7, 0, 0); -	} else if (stat1 & 1) { -		cec_transmit_done(core->adap, -				  CEC_TX_STATUS_ARB_LOST | -				  CEC_TX_STATUS_MAX_RETRIES, -				  0, 0, 0, 0); +		REG_FLD_MOD(core->base, HDMI_CEC_DBG_3, 0x1, 7, 7);  	}  	if (stat0 & 0x02)  		hdmi_cec_received_msg(core); -	if (stat1 & 0x3) -		REG_FLD_MOD(core->base, HDMI_CEC_DBG_3, 0x1, 7, 7);  }  static bool hdmi_cec_clear_tx_fifo(struct cec_adapter *adap) @@ -231,18 +207,14 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)  	/*  	 * Enable CEC interrupts:  	 * Transmit Buffer Full/Empty Change event -	 * Transmitter FIFO Empty event  	 * Receiver FIFO Not Empty event  	 */ -	hdmi_write_reg(core->base, HDMI_CEC_INT_ENABLE_0, 0x26); +	hdmi_write_reg(core->base, HDMI_CEC_INT_ENABLE_0, 0x22);  	/*  	 * Enable CEC interrupts: -	 * RX FIFO Overrun Error event -	 * Short Pulse Detected event  	 * Frame Retransmit Count Exceeded event -	 * Start Bit Irregularity event  	 */ -	hdmi_write_reg(core->base, HDMI_CEC_INT_ENABLE_1, 0x0f); +	hdmi_write_reg(core->base, HDMI_CEC_INT_ENABLE_1, 0x02);  	/* cec calibration enable (self clearing) */  	hdmi_write_reg(core->base, HDMI_CEC_SETUP, 0x03); @@ -352,7 +324,7 @@ int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,  {  	const u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS |  			 CEC_CAP_PASSTHROUGH | CEC_CAP_RC; -	unsigned int ret; +	int ret;  	core->adap = cec_allocate_adapter(&hdmi_cec_adap_ops, core,  		"omap4", caps, CEC_MAX_LOG_ADDRS); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index 62e451162d96..b06f9956e733 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -886,25 +886,36 @@ struct hdmi4_features {  	bool audio_use_mclk;  }; -static const struct hdmi4_features hdmi4_es1_features = { +static const struct hdmi4_features hdmi4430_es1_features = {  	.cts_swmode = false,  	.audio_use_mclk = false,  }; -static const struct hdmi4_features hdmi4_es2_features = { +static const struct hdmi4_features hdmi4430_es2_features = {  	.cts_swmode = true,  	.audio_use_mclk = false,  }; -static const struct hdmi4_features hdmi4_es3_features = { +static const struct hdmi4_features hdmi4_features = {  	.cts_swmode = true,  	.audio_use_mclk = true,  };  static const struct soc_device_attribute hdmi4_soc_devices[] = { -	{ .family = "OMAP4", .revision = "ES1.?", .data = &hdmi4_es1_features }, -	{ .family = "OMAP4", .revision = "ES2.?", .data = &hdmi4_es2_features }, -	{ .family = "OMAP4",			  .data = &hdmi4_es3_features }, +	{ +		.machine = "OMAP4430", +		.revision = "ES1.?", +		.data = &hdmi4430_es1_features, +	}, +	{ +		.machine = "OMAP4430", +		.revision = "ES2.?", +		.data = &hdmi4430_es2_features, +	}, +	{ +		.family = "OMAP4", +		.data = &hdmi4_features, +	},  	{ /* sentinel */ }  }; diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 1dd3dafc59af..c60a85e82c6d 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -638,7 +638,8 @@ static int omap_dmm_probe(struct platform_device *dev)  		match = of_match_node(dmm_of_match, dev->dev.of_node);  		if (!match) {  			dev_err(&dev->dev, "failed to find matching device node\n"); -			return -ENODEV; +			ret = -ENODEV; +			goto fail;  		}  		omap_dmm->plat_data = match->data; diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 898f9a078830..a6511918f632 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -5451,28 +5451,6 @@ void cik_pcie_gart_tlb_flush(struct radeon_device *rdev)  	WREG32(VM_INVALIDATE_REQUEST, 0x1);  } -static void cik_pcie_init_compute_vmid(struct radeon_device *rdev) -{ -	int i; -	uint32_t sh_mem_bases, sh_mem_config; - -	sh_mem_bases = 0x6000 | 0x6000 << 16; -	sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED); -	sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED); - -	mutex_lock(&rdev->srbm_mutex); -	for (i = 8; i < 16; i++) { -		cik_srbm_select(rdev, 0, 0, 0, i); -		/* CP and shaders */ -		WREG32(SH_MEM_CONFIG, sh_mem_config); -		WREG32(SH_MEM_APE1_BASE, 1); -		WREG32(SH_MEM_APE1_LIMIT, 0); -		WREG32(SH_MEM_BASES, sh_mem_bases); -	} -	cik_srbm_select(rdev, 0, 0, 0, 0); -	mutex_unlock(&rdev->srbm_mutex); -} -  /**   * cik_pcie_gart_enable - gart enable   * @@ -5586,8 +5564,6 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)  	cik_srbm_select(rdev, 0, 0, 0, 0);  	mutex_unlock(&rdev->srbm_mutex); -	cik_pcie_init_compute_vmid(rdev); -  	cik_pcie_gart_tlb_flush(rdev);  	DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",  		 (unsigned)(rdev->mc.gtt_size >> 20), diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index b15755b6129c..b1fe0639227e 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -1285,8 +1285,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,  		goto err_pllref;  	} -	pm_runtime_enable(dev); -  	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;  	dsi->dsi_host.dev = dev;  	ret = mipi_dsi_host_register(&dsi->dsi_host); @@ -1301,6 +1299,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,  	}  	dev_set_drvdata(dev, dsi); +	pm_runtime_enable(dev);  	return 0;  err_mipi_dsi_host: diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index dda904ec0534..500b6fb3e028 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -175,11 +175,31 @@ static void sun4i_hdmi_mode_set(struct drm_encoder *encoder,  	writel(val, hdmi->base + SUN4I_HDMI_VID_TIMING_POL_REG);  } +static enum drm_mode_status sun4i_hdmi_mode_valid(struct drm_encoder *encoder, +					const struct drm_display_mode *mode) +{ +	struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder); +	unsigned long rate = mode->clock * 1000; +	unsigned long diff = rate / 200; /* +-0.5% allowed by HDMI spec */ +	long rounded_rate; + +	/* 165 MHz is the typical max pixelclock frequency for HDMI <= 1.2 */ +	if (rate > 165000000) +		return MODE_CLOCK_HIGH; +	rounded_rate = clk_round_rate(hdmi->tmds_clk, rate); +	if (rounded_rate > 0 && +	    max_t(unsigned long, rounded_rate, rate) - +	    min_t(unsigned long, rounded_rate, rate) < diff) +		return MODE_OK; +	return MODE_NOCLOCK; +} +  static const struct drm_encoder_helper_funcs sun4i_hdmi_helper_funcs = {  	.atomic_check	= sun4i_hdmi_atomic_check,  	.disable	= sun4i_hdmi_disable,  	.enable		= sun4i_hdmi_enable,  	.mode_set	= sun4i_hdmi_mode_set, +	.mode_valid	= sun4i_hdmi_mode_valid,  };  static const struct drm_encoder_funcs sun4i_hdmi_funcs = { diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index e122f5b2a395..f4284b51bdca 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -724,12 +724,12 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,  	if (IS_ERR(tcon->crtc)) {  		dev_err(dev, "Couldn't create our CRTC\n");  		ret = PTR_ERR(tcon->crtc); -		goto err_free_clocks; +		goto err_free_dotclock;  	}  	ret = sun4i_rgb_init(drm, tcon);  	if (ret < 0) -		goto err_free_clocks; +		goto err_free_dotclock;  	if (tcon->quirks->needs_de_be_mux) {  		/* diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 316f831ad5f0..5d252fb27a82 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -81,6 +81,7 @@ struct ttm_page_pool {  	char			*name;  	unsigned long		nfrees;  	unsigned long		nrefills; +	unsigned int		order;  };  /** @@ -222,6 +223,17 @@ static struct kobj_type ttm_pool_kobj_type = {  static struct ttm_pool_manager *_manager;  #ifndef CONFIG_X86 +static int set_pages_wb(struct page *page, int numpages) +{ +#if IS_ENABLED(CONFIG_AGP) +	int i; + +	for (i = 0; i < numpages; i++) +		unmap_page_from_agp(page++); +#endif +	return 0; +} +  static int set_pages_array_wb(struct page **pages, int addrinarray)  {  #if IS_ENABLED(CONFIG_AGP) @@ -284,13 +296,23 @@ static struct ttm_page_pool *ttm_get_pool(int flags, bool huge,  }  /* set memory back to wb and free the pages. */ -static void ttm_pages_put(struct page *pages[], unsigned npages) +static void ttm_pages_put(struct page *pages[], unsigned npages, +		unsigned int order)  { -	unsigned i; -	if (set_pages_array_wb(pages, npages)) -		pr_err("Failed to set %d pages to wb!\n", npages); -	for (i = 0; i < npages; ++i) -		__free_page(pages[i]); +	unsigned int i, pages_nr = (1 << order); + +	if (order == 0) { +		if (set_pages_array_wb(pages, npages)) +			pr_err("Failed to set %d pages to wb!\n", npages); +	} + +	for (i = 0; i < npages; ++i) { +		if (order > 0) { +			if (set_pages_wb(pages[i], pages_nr)) +				pr_err("Failed to set %d pages to wb!\n", pages_nr); +		} +		__free_pages(pages[i], order); +	}  }  static void ttm_pool_update_free_locked(struct ttm_page_pool *pool, @@ -353,7 +375,7 @@ restart:  			 */  			spin_unlock_irqrestore(&pool->lock, irq_flags); -			ttm_pages_put(pages_to_free, freed_pages); +			ttm_pages_put(pages_to_free, freed_pages, pool->order);  			if (likely(nr_free != FREE_ALL_PAGES))  				nr_free -= freed_pages; @@ -388,7 +410,7 @@ restart:  	spin_unlock_irqrestore(&pool->lock, irq_flags);  	if (freed_pages) -		ttm_pages_put(pages_to_free, freed_pages); +		ttm_pages_put(pages_to_free, freed_pages, pool->order);  out:  	if (pages_to_free != static_buf)  		kfree(pages_to_free); @@ -412,6 +434,7 @@ ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)  	struct ttm_page_pool *pool;  	int shrink_pages = sc->nr_to_scan;  	unsigned long freed = 0; +	unsigned int nr_free_pool;  	if (!mutex_trylock(&lock))  		return SHRINK_STOP; @@ -419,12 +442,20 @@ ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)  	/* select start pool in round robin fashion */  	for (i = 0; i < NUM_POOLS; ++i) {  		unsigned nr_free = shrink_pages; +		unsigned page_nr; +  		if (shrink_pages == 0)  			break; +  		pool = &_manager->pools[(i + pool_offset)%NUM_POOLS]; +		page_nr = (1 << pool->order);  		/* OK to use static buffer since global mutex is held. */ -		shrink_pages = ttm_page_pool_free(pool, nr_free, true); -		freed += nr_free - shrink_pages; +		nr_free_pool = roundup(nr_free, page_nr) >> pool->order; +		shrink_pages = ttm_page_pool_free(pool, nr_free_pool, true); +		freed += (nr_free_pool - shrink_pages) << pool->order; +		if (freed >= sc->nr_to_scan) +			break; +		shrink_pages <<= pool->order;  	}  	mutex_unlock(&lock);  	return freed; @@ -436,9 +467,12 @@ ttm_pool_shrink_count(struct shrinker *shrink, struct shrink_control *sc)  {  	unsigned i;  	unsigned long count = 0; +	struct ttm_page_pool *pool; -	for (i = 0; i < NUM_POOLS; ++i) -		count += _manager->pools[i].npages; +	for (i = 0; i < NUM_POOLS; ++i) { +		pool = &_manager->pools[i]; +		count += (pool->npages << pool->order); +	}  	return count;  } @@ -510,8 +544,7 @@ static int ttm_alloc_new_pages(struct list_head *pages, gfp_t gfp_flags,  	int r = 0;  	unsigned i, j, cpages;  	unsigned npages = 1 << order; -	unsigned max_cpages = min(count, -			(unsigned)(PAGE_SIZE/sizeof(struct page *))); +	unsigned max_cpages = min(count << order, (unsigned)NUM_PAGES_TO_ALLOC);  	/* allocate array for page caching change */  	caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL); @@ -744,12 +777,14 @@ static void ttm_put_pages(struct page **pages, unsigned npages, int flags,  			}  #ifdef CONFIG_TRANSPARENT_HUGEPAGE -			for (j = 0; j < HPAGE_PMD_NR; ++j) -				if (p++ != pages[i + j]) -				    break; +			if (!(flags & TTM_PAGE_FLAG_DMA32)) { +				for (j = 0; j < HPAGE_PMD_NR; ++j) +					if (p++ != pages[i + j]) +					    break; -			if (j == HPAGE_PMD_NR) -				order = HPAGE_PMD_ORDER; +				if (j == HPAGE_PMD_NR) +					order = HPAGE_PMD_ORDER; +			}  #endif  			if (page_count(pages[i]) != 1) @@ -843,7 +878,7 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags,  #endif  	struct list_head plist;  	struct page *p = NULL; -	unsigned count; +	unsigned count, first;  	int r;  	/* No pool for cached pages */ @@ -865,23 +900,26 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags,  		i = 0;  #ifdef CONFIG_TRANSPARENT_HUGEPAGE -		while (npages >= HPAGE_PMD_NR) { -			gfp_t huge_flags = gfp_flags; +		if (!(gfp_flags & GFP_DMA32)) { +			while (npages >= HPAGE_PMD_NR) { +				gfp_t huge_flags = gfp_flags; -			huge_flags |= GFP_TRANSHUGE; -			huge_flags &= ~__GFP_MOVABLE; -			huge_flags &= ~__GFP_COMP; -			p = alloc_pages(huge_flags, HPAGE_PMD_ORDER); -			if (!p) -				break; +				huge_flags |= GFP_TRANSHUGE; +				huge_flags &= ~__GFP_MOVABLE; +				huge_flags &= ~__GFP_COMP; +				p = alloc_pages(huge_flags, HPAGE_PMD_ORDER); +				if (!p) +					break; -			for (j = 0; j < HPAGE_PMD_NR; ++j) -				pages[i++] = p++; +				for (j = 0; j < HPAGE_PMD_NR; ++j) +					pages[i++] = p++; -			npages -= HPAGE_PMD_NR; +				npages -= HPAGE_PMD_NR; +			}  		}  #endif +		first = i;  		while (npages) {  			p = alloc_page(gfp_flags);  			if (!p) { @@ -889,6 +927,10 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags,  				return -ENOMEM;  			} +			/* Swap the pages if we detect consecutive order */ +			if (i > first && pages[i - 1] == p - 1) +				swap(p, pages[i - 1]); +  			pages[i++] = p;  			--npages;  		} @@ -917,8 +959,15 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags,  	r = ttm_page_pool_get_pages(pool, &plist, flags, cstate,  				    npages - count, 0); -	list_for_each_entry(p, &plist, lru) -		pages[count++] = p; +	first = count; +	list_for_each_entry(p, &plist, lru) { +		struct page *tmp = p; + +		/* Swap the pages if we detect consecutive order */ +		if (count > first && pages[count - 1] == tmp - 1) +			swap(tmp, pages[count - 1]); +		pages[count++] = tmp; +	}  	if (r) {  		/* If there is any pages in the list put them back to @@ -933,7 +982,7 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags,  }  static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, gfp_t flags, -		char *name) +		char *name, unsigned int order)  {  	spin_lock_init(&pool->lock);  	pool->fill_lock = false; @@ -941,35 +990,43 @@ static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, gfp_t flags,  	pool->npages = pool->nfrees = 0;  	pool->gfp_flags = flags;  	pool->name = name; +	pool->order = order;  }  int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages)  {  	int ret; +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +	unsigned order = HPAGE_PMD_ORDER; +#else +	unsigned order = 0; +#endif  	WARN_ON(_manager);  	pr_info("Initializing pool allocator\n");  	_manager = kzalloc(sizeof(*_manager), GFP_KERNEL); +	if (!_manager) +		return -ENOMEM; -	ttm_page_pool_init_locked(&_manager->wc_pool, GFP_HIGHUSER, "wc"); +	ttm_page_pool_init_locked(&_manager->wc_pool, GFP_HIGHUSER, "wc", 0); -	ttm_page_pool_init_locked(&_manager->uc_pool, GFP_HIGHUSER, "uc"); +	ttm_page_pool_init_locked(&_manager->uc_pool, GFP_HIGHUSER, "uc", 0);  	ttm_page_pool_init_locked(&_manager->wc_pool_dma32, -				  GFP_USER | GFP_DMA32, "wc dma"); +				  GFP_USER | GFP_DMA32, "wc dma", 0);  	ttm_page_pool_init_locked(&_manager->uc_pool_dma32, -				  GFP_USER | GFP_DMA32, "uc dma"); +				  GFP_USER | GFP_DMA32, "uc dma", 0);  	ttm_page_pool_init_locked(&_manager->wc_pool_huge,  				  GFP_TRANSHUGE	& ~(__GFP_MOVABLE | __GFP_COMP), -				  "wc huge"); +				  "wc huge", order);  	ttm_page_pool_init_locked(&_manager->uc_pool_huge,  				  GFP_TRANSHUGE	& ~(__GFP_MOVABLE | __GFP_COMP) -				  , "uc huge"); +				  , "uc huge", order);  	_manager->options.max_size = max_pages;  	_manager->options.small = SMALL_ALLOCATION; @@ -1058,7 +1115,6 @@ void ttm_pool_unpopulate(struct ttm_tt *ttm)  }  EXPORT_SYMBOL(ttm_pool_unpopulate); -#if defined(CONFIG_SWIOTLB) || defined(CONFIG_INTEL_IOMMU)  int ttm_populate_and_map_pages(struct device *dev, struct ttm_dma_tt *tt)  {  	unsigned i, j; @@ -1129,7 +1185,6 @@ void ttm_unmap_and_unpopulate_pages(struct device *dev, struct ttm_dma_tt *tt)  	ttm_pool_unpopulate(&tt->ttm);  }  EXPORT_SYMBOL(ttm_unmap_and_unpopulate_pages); -#endif  int ttm_page_alloc_debugfs(struct seq_file *m, void *data)  { diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 4ae45d7dac42..2decc8e2c79f 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -637,7 +637,8 @@ int vc4_bo_inc_usecnt(struct vc4_bo *bo)  	mutex_lock(&bo->madv_lock);  	switch (bo->madv) {  	case VC4_MADV_WILLNEED: -		refcount_inc(&bo->usecnt); +		if (!refcount_inc_not_zero(&bo->usecnt)) +			refcount_set(&bo->usecnt, 1);  		ret = 0;  		break;  	case VC4_MADV_DONTNEED: diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 6c32c89a83a9..638540943c61 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -888,8 +888,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)  	/* If we got force-completed because of GPU reset rather than  	 * through our IRQ handler, signal the fence now.  	 */ -	if (exec->fence) +	if (exec->fence) {  		dma_fence_signal(exec->fence); +		dma_fence_put(exec->fence); +	}  	if (exec->bo) {  		for (i = 0; i < exec->bo_count; i++) { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index fa37a1c07cf6..0b2088264039 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -424,7 +424,8 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)  					   vc4_encoder->limited_rgb_range ?  					   HDMI_QUANTIZATION_RANGE_LIMITED :  					   HDMI_QUANTIZATION_RANGE_FULL, -					   vc4_encoder->rgb_range_selectable); +					   vc4_encoder->rgb_range_selectable, +					   false);  	vc4_hdmi_write_infoframe(encoder, &frame);  } diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index 7d7af3a93d94..26eddbb62893 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -139,6 +139,7 @@ vc4_irq_finish_render_job(struct drm_device *dev)  	list_move_tail(&exec->head, &vc4->job_done_list);  	if (exec->fence) {  		dma_fence_signal_locked(exec->fence); +		dma_fence_put(exec->fence);  		exec->fence = NULL;  	}  	vc4_submit_next_render_job(dev); @@ -208,6 +209,9 @@ vc4_irq_postinstall(struct drm_device *dev)  {  	struct vc4_dev *vc4 = to_vc4_dev(dev); +	/* Undo the effects of a previous vc4_irq_uninstall. */ +	enable_irq(dev->irq); +  	/* Enable both the render done and out of memory interrupts. */  	V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); @@ -225,6 +229,9 @@ vc4_irq_uninstall(struct drm_device *dev)  	/* Clear any pending interrupts we might have left. */  	V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); +	/* Finish any interrupt handler still in flight. */ +	disable_irq(dev->irq); +  	cancel_work_sync(&vc4->overflow_mem_work);  } |