mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 15:40:03 +02:00
drm next/fixes for 7.3-rc1
core: - use drm_warn instead of warn msm: - Bindings: - Added Shikra support - Document a840, a704, a722 - Core: - Use drm_client buffers for fbdev emulation - teardown fixes - ARM32 DMA fixup - Remove objects from evict list when re-validated - Bunch of corner case and error path fixes - DPU: - Dropped dev_pm_opp_set_rate(0) preventing burnout - Fixed SSPP offsets of Kaanapali - DP: - Dropped dev_pm_opp_set_rate(0) preventing burnout - Cleaned up core code in preparation for MST support - Fixed prepare() to let Pipewire continue in case of the unplugged cable - GPU: - Add support for a704 - Add support for a722 - HDMI: - Simplifed register access amdgpu: - eGPU fixes - Runtime PM fix - UserQ fixes - Backlight fix - Discovery sysfs fix - Reset handling fixes - Buffer func handling fix for xgmi - VCN boundary check fix - DC lut handling fixes - MES fixes - UVD fix - VCE 3 fix - Enforce isolation fix - HPD fix for VGA/LVDS - DML fix - DCN 6 fixes - DC gpu reset fix amdkfd: - Fix return value - CU occupancy for GFX 11 - CU occupancy for GFX 12/12.1 - Queue bounds checking fix - SVM fixes - CRIU bounds checking fix radeon: - iMac display fix xe: - error message cleanups - i2c global register definitions as dependency for xe/i2c fixes - Media workardound - Add CCS to gt_idle debugfs print - Page fault related fix - i2c related fixes - System Controller mailbox bit fix -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmqR+2wACgkQDHTzWXnE hr5VPRAAhJpCnUEOUnhiBRfQB3lqHuKV4N9XQGVoaAZHYLxNkZD6I99ScpIznEr9 sHG0ViBqz2PHyM2XoJzPZDzm8Us0moVUMMdV56IH7h11l8E7Az2Sd/Ji+AQvZEBT /qh9Py0/fjibfDm0ueMROFRhuD8RA2sJqzkGMZUBvErh+zmEQvkIDkIT6A5RpHD8 B3XEGN+UCxPBzCnKNixyNDgY2i4ipFAe0MDj9+Mh0b9BM9BoV8+Eb7sjkBz+ROMH tl57Mjjd37FaYM9MgtEt9m7eOBf266V9Xb9tbIfqShwO1aZa0Vfzuih/3Ck53Nwc VkwepP7NHZZKFHIxFgcRCVjzyA3HpZJmLot8YYOyZDJOG6KKp2X0ZUFBog5Uiv8o 7exd95FLUtIsnUtmLxlermOYJwrokgcVoigcalhLCB2+KZ5/BznutzcCSvrd8vI2 LzEGnLMgzuEKeOmiWZjagID51TYwHfPogULUlwWT4XB62dKih7/uselCObj4m/Lc kRSbiXWz1pxisfiFRsK2GECwsbEb/8qOYgSOQBgppuPbSWpX+2P4IApomRBesQ8E Db+i6hptauOwT0/1ZBo8gkOfb0XIWsjg9iV6pVuUIS80hOlr7Zj1MR7mMrWgL0nM Chs4/Nq8jWU1ESbmKPBINIXCGOGuev4lJO/pBjfySLpTUhWOQcw= =wbEZ -----END PGP SIGNATURE----- Merge tag 'drm-next-2026-08-29' of https://gitlab.freedesktop.org/drm/kernel Pull more drm updates from Dave Airlie: "As mentioned last week, an msm pull request fell down the side of the couch or whatever the email equivalent of that is. This has the msm next stuff + the usual fixes for amd/intel. core: - use drm_warn instead of warn msm: - Bindings: - Added Shikra support - Document a840, a704, a722 - Core: - Use drm_client buffers for fbdev emulation - teardown fixes - ARM32 DMA fixup - Remove objects from evict list when re-validated - Bunch of corner case and error path fixes - DPU: - Dropped dev_pm_opp_set_rate(0) preventing burnout - Fixed SSPP offsets of Kaanapali - DP: - Dropped dev_pm_opp_set_rate(0) preventing burnout - Cleaned up core code in preparation for MST support - Fixed prepare() to let Pipewire continue in case of the unplugged cable - GPU: - Add support for a704 - Add support for a722 - HDMI: - Simplifed register access amdgpu: - eGPU fixes - Runtime PM fix - UserQ fixes - Backlight fix - Discovery sysfs fix - Reset handling fixes - Buffer func handling fix for xgmi - VCN boundary check fix - DC lut handling fixes - MES fixes - UVD fix - VCE 3 fix - Enforce isolation fix - HPD fix for VGA/LVDS - DML fix - DCN 6 fixes - DC gpu reset fix amdkfd: - Fix return value - CU occupancy for GFX 11 - CU occupancy for GFX 12/12.1 - Queue bounds checking fix - SVM fixes - CRIU bounds checking fix radeon: - iMac display fix xe: - error message cleanups - i2c global register definitions as dependency for xe/i2c fixes - Media workardound - Add CCS to gt_idle debugfs print - Page fault related fix - i2c related fixes - System Controller mailbox bit fix" * tag 'drm-next-2026-08-29' of https://gitlab.freedesktop.org/drm/kernel: (121 commits) drm/xe/sysctrl: Read mailbox phase bit from hardware drm/xe/i2c: Keep the i2c controller always enabled drm/xe/i2c: Fix the interrupt handling i2c: designware: Global register definitions drm/xe: Reject page faults from non-fault-mode scratch VMs drm/xe/xe_gt_idle: Add CCS to the powergating info print drm/xe: Do not apply WA 14025883347 to media 3503 drm/amd/display: fix dc_lock leak on GPU reset error paths drm/amd/display: Fix redundant GPUVMEnable checks in dcn6 flip schedule drm/amd/display: Fix wrong bytes-per-pixel value for dml2_422_packed_10 drm/amdkfd: guard against NULL restore_mqd in CRIU queue restore drm/amdgpu/userq: fix lock missing for userq fence error set drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram drm/amdkfd: Fix error path at svm_migrate_copy_to_ram drm/amd/display: Log details when failing to register HPD IRQ drm/amd/display: Fix HPD consideration for VGA/LVDS connectors on DCE drm/amdgpu: clamp the isolation index for rings outside a partition drm/amdkfd: Reject zero-sized AQL queue allocations after size halving drm/amdgpu: Fix VCE 3 ring align_mask drm/kfd: Add CU occupancy support to GFX12.1 ...
This commit is contained in:
commit
a99d741df7
|
|
@ -47,6 +47,10 @@ properties:
|
|||
- qcom,sm8650-dsi-ctrl
|
||||
- qcom,sm8750-dsi-ctrl
|
||||
- const: qcom,mdss-dsi-ctrl
|
||||
- items:
|
||||
- const: qcom,shikra-dsi-ctrl
|
||||
- const: qcom,qcm2290-dsi-ctrl
|
||||
- const: qcom,mdss-dsi-ctrl
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,qcs8300-dsi-ctrl
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,adreno-gmu-722.0
|
||||
- qcom,adreno-gmu-730.1
|
||||
- qcom,adreno-gmu-740.1
|
||||
- qcom,adreno-gmu-750.1
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ allOf:
|
|||
- qcom,adreno-610.0
|
||||
- qcom,adreno-619.1
|
||||
- qcom,adreno-07000200
|
||||
- qcom,adreno-07000400
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
|
|
@ -413,6 +414,7 @@ allOf:
|
|||
contains:
|
||||
enum:
|
||||
- qcom,adreno-44010000
|
||||
- qcom,adreno-44050a01
|
||||
- qcom,adreno-44070001
|
||||
then:
|
||||
properties:
|
||||
|
|
@ -443,11 +445,13 @@ allOf:
|
|||
- qcom,adreno-680.1
|
||||
- qcom,adreno-690.0
|
||||
- qcom,adreno-730.1
|
||||
- qcom,adreno-43020100
|
||||
- qcom,adreno-43030c00
|
||||
- qcom,adreno-43050a01
|
||||
- qcom,adreno-43050c01
|
||||
- qcom,adreno-43051401
|
||||
- qcom,adreno-44010000
|
||||
- qcom,adreno-44050a01
|
||||
- qcom,adreno-44070001
|
||||
|
||||
then: # Starting with A6xx, the clocks are usually defined in the GMU node
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@ $ref: /schemas/display/msm/dpu-common.yaml#
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,qcm2290-dpu
|
||||
oneOf:
|
||||
- const: qcom,qcm2290-dpu
|
||||
- items:
|
||||
- const: qcom,shikra-dpu
|
||||
- const: qcom,qcm2290-dpu
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
$id: http://devicetree.org/schemas/display/msm/qcom,qcm2290-mdss.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm QCM220 Display MDSS
|
||||
title: Qualcomm QCM2290 and Shikra Display MDSS
|
||||
|
||||
maintainers:
|
||||
- Loic Poulain <loic.poulain@linaro.org>
|
||||
|
|
@ -12,13 +12,18 @@ maintainers:
|
|||
description:
|
||||
Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
|
||||
sub-blocks like DPU display controller and DSI. Device tree bindings of MDSS
|
||||
are mentioned for QCM2290 target.
|
||||
are mentioned for QCM2290 and Shikra targets. Shikra uses the same MDSS/DPU/DSI
|
||||
hardware as QCM2290 (DPU 6.5) and shares the same register layout.
|
||||
|
||||
$ref: /schemas/display/msm/mdss-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,qcm2290-mdss
|
||||
oneOf:
|
||||
- const: qcom,qcm2290-mdss
|
||||
- items:
|
||||
- const: qcom,shikra-mdss
|
||||
- const: qcom,qcm2290-mdss
|
||||
|
||||
clocks:
|
||||
items:
|
||||
|
|
@ -52,7 +57,8 @@ patternProperties:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,qcm2290-dpu
|
||||
contains:
|
||||
const: qcom,qcm2290-dpu
|
||||
|
||||
"^dsi@[0-9a-f]+$":
|
||||
type: object
|
||||
|
|
@ -60,9 +66,8 @@ patternProperties:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: qcom,qcm2290-dsi-ctrl
|
||||
- const: qcom,mdss-dsi-ctrl
|
||||
contains:
|
||||
const: qcom,qcm2290-dsi-ctrl
|
||||
|
||||
"^phy@[0-9a-f]+$":
|
||||
type: object
|
||||
|
|
|
|||
|
|
@ -26543,6 +26543,7 @@ R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
|||
L: linux-i2c@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/i2c/busses/i2c-designware-*
|
||||
F: include/linux/designware_i2c.h
|
||||
|
||||
SYNOPSYS DESIGNWARE I2C DRIVER - AMDISP
|
||||
M: Nirujogi Pratap <pratap.nirujogi@amd.com>
|
||||
|
|
|
|||
|
|
@ -807,6 +807,153 @@ static uint32_t kgd_gfx_v11_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void lock_spi_csq_mutexes(struct amdgpu_device *adev)
|
||||
{
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
|
||||
}
|
||||
|
||||
static void unlock_spi_csq_mutexes(struct amdgpu_device *adev)
|
||||
{
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
mutex_unlock(&adev->srbm_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_wave_count: Read device registers to get number of waves in flight for
|
||||
* a particular queue. The method also returns the doorbell offset associated
|
||||
* with the queue.
|
||||
*
|
||||
* @adev: Handle of device whose registers are to be read
|
||||
* @queue_idx: Index of queue in the queue-map bit-field
|
||||
* @queue_cnt: Stores the wave count and doorbell offset for an active queue
|
||||
* @inst: xcc's instance number on a multi-XCC setup
|
||||
*/
|
||||
static void get_wave_count(struct amdgpu_device *adev, int queue_idx,
|
||||
struct kfd_cu_occupancy *queue_cnt, uint32_t inst)
|
||||
{
|
||||
int pipe_idx;
|
||||
int queue_slot;
|
||||
unsigned int reg_val;
|
||||
unsigned int wave_cnt;
|
||||
/*
|
||||
* Program GRBM with appropriate MEID, PIPEID, QUEUEID and VMID
|
||||
* parameters to read out waves in flight. Get doorbell offset if there are
|
||||
* non-zero waves in flight.
|
||||
*/
|
||||
pipe_idx = queue_idx / adev->gfx.mec.num_queue_per_pipe;
|
||||
queue_slot = queue_idx % adev->gfx.mec.num_queue_per_pipe;
|
||||
soc21_grbm_select(adev, 1, pipe_idx, queue_slot, 0);
|
||||
reg_val = RREG32_SOC15_IP(GC, SOC15_REG_OFFSET(GC, 0,
|
||||
regSPI_CSQ_WF_ACTIVE_COUNT_0) + queue_slot);
|
||||
wave_cnt = reg_val & SPI_CSQ_WF_ACTIVE_COUNT_0__COUNT_MASK;
|
||||
if (wave_cnt != 0) {
|
||||
queue_cnt->wave_cnt += wave_cnt;
|
||||
queue_cnt->doorbell_off =
|
||||
(RREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL) &
|
||||
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK) >>
|
||||
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kgd_gfx_v11_get_cu_occupancy: Reads relevant registers associated with each
|
||||
* shader engine and aggregates the number of waves that are in flight for the
|
||||
* process whose pasid is provided as a parameter. The process could have ZERO
|
||||
* or more queues running and submitting waves to compute units.
|
||||
*
|
||||
* @adev: Handle of device from which to get number of waves in flight
|
||||
* @cu_occupancy: Array that gets filled with wave_cnt and doorbell offset
|
||||
* for comparison later.
|
||||
* @max_waves_per_cu: Output parameter updated with maximum number of waves
|
||||
* possible per Compute Unit
|
||||
* @inst: xcc's instance number on a multi-XCC setup
|
||||
*
|
||||
* Note: It's possible that the device has too many queues (oversubscription)
|
||||
* in which case a VMID could be remapped to a different PASID. This could lead
|
||||
* to an inaccurate wave count. Following is a high-level sequence:
|
||||
* Time T1: vmid = getVmid(); vmid is associated with Pasid P1
|
||||
* Time T2: passId = getPasId(vmid); vmid is associated with Pasid P2
|
||||
* In the sequence above wave count obtained from time T1 will be incorrectly
|
||||
* lost or added to total wave count.
|
||||
*
|
||||
* The registers that provide the waves in flight are:
|
||||
*
|
||||
* SPI_CSQ_WF_ACTIVE_STATUS - bit-map of queues per pipe. The bit is ON if a
|
||||
* queue is slotted, OFF if there is no queue. A process could have ZERO or
|
||||
* more queues slotted and submitting waves to be run on compute units. Even
|
||||
* when there is a queue it is possible there could be zero wave fronts, this
|
||||
* can happen when queue is waiting on top-of-pipe events - e.g. waitRegMem
|
||||
* command
|
||||
*
|
||||
* For each bit that is ON from above:
|
||||
*
|
||||
* Read (SPI_CSQ_WF_ACTIVE_COUNT_0 + queue_idx) register. It provides the
|
||||
* number of waves that are in flight for the queue at specified index. The
|
||||
* index ranges from 0 to 7.
|
||||
*
|
||||
* If non-zero waves are in flight, store the corresponding doorbell offset
|
||||
* of the queue, along with the wave count.
|
||||
*
|
||||
* Determine if the queue belongs to the process by comparing the doorbell
|
||||
* offset against the process's queues. If it matches, aggregate the wave
|
||||
* count for the process.
|
||||
*
|
||||
* Reading registers referenced above involves programming GRBM appropriately
|
||||
*/
|
||||
static void kgd_gfx_v11_get_cu_occupancy(struct amdgpu_device *adev,
|
||||
struct kfd_cu_occupancy *cu_occupancy,
|
||||
int *max_waves_per_cu, uint32_t inst)
|
||||
{
|
||||
int qidx;
|
||||
int se_idx;
|
||||
int se_cnt;
|
||||
int queue_map;
|
||||
int max_queue_cnt;
|
||||
DECLARE_BITMAP(cp_queue_bitmap, AMDGPU_MAX_QUEUES);
|
||||
|
||||
lock_spi_csq_mutexes(adev);
|
||||
soc21_grbm_select(adev, 1, 0, 0, 0);
|
||||
|
||||
/*
|
||||
* Iterate through the shader engines and arrays of the device
|
||||
* to get number of waves in flight
|
||||
*/
|
||||
bitmap_complement(cp_queue_bitmap, adev->gfx.mec_bitmap[0].queue_bitmap,
|
||||
AMDGPU_MAX_QUEUES);
|
||||
max_queue_cnt = adev->gfx.mec.num_pipe_per_mec *
|
||||
adev->gfx.mec.num_queue_per_pipe;
|
||||
se_cnt = adev->gfx.config.max_shader_engines;
|
||||
for (se_idx = 0; se_idx < se_cnt; se_idx++) {
|
||||
amdgpu_gfx_select_se_sh(adev, se_idx, 0, 0xffffffff, inst);
|
||||
queue_map = RREG32_SOC15(GC, 0,
|
||||
regSPI_CSQ_WF_ACTIVE_STATUS);
|
||||
|
||||
for (qidx = 0; qidx < max_queue_cnt; qidx++) {
|
||||
/* Skip queues that are not associated with
|
||||
* compute functions
|
||||
*/
|
||||
if (!test_bit(qidx, cp_queue_bitmap))
|
||||
continue;
|
||||
|
||||
if (!(queue_map & (1 << qidx)))
|
||||
continue;
|
||||
|
||||
/* Get number of waves in flight and aggregate them */
|
||||
get_wave_count(adev, qidx, &cu_occupancy[qidx], inst);
|
||||
}
|
||||
}
|
||||
|
||||
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, inst);
|
||||
soc21_grbm_select(adev, 0, 0, 0, 0);
|
||||
unlock_spi_csq_mutexes(adev);
|
||||
|
||||
/* Update the output parameters and return */
|
||||
*max_waves_per_cu = adev->gfx.cu_info.simd_per_cu *
|
||||
adev->gfx.cu_info.max_waves_per_simd;
|
||||
}
|
||||
|
||||
const struct kfd2kgd_calls gfx_v11_kfd2kgd = {
|
||||
.program_sh_mem_settings = program_sh_mem_settings_v11,
|
||||
.set_pasid_vmid_mapping = set_pasid_vmid_mapping_v11,
|
||||
|
|
@ -832,5 +979,6 @@ const struct kfd2kgd_calls gfx_v11_kfd2kgd = {
|
|||
.clear_address_watch = kgd_gfx_v11_clear_address_watch,
|
||||
.hqd_get_pq_addr = kgd_gfx_v11_hqd_get_pq_addr,
|
||||
.hqd_reset = kgd_gfx_v11_hqd_reset,
|
||||
.get_cu_occupancy = kgd_gfx_v11_get_cu_occupancy,
|
||||
.hqd_sdma_get_doorbell = kgd_gfx_v11_hqd_sdma_get_doorbell
|
||||
};
|
||||
|
|
|
|||
|
|
@ -368,6 +368,153 @@ static uint32_t kgd_gfx_v12_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void lock_spi_csq_mutexes(struct amdgpu_device *adev)
|
||||
{
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
|
||||
}
|
||||
|
||||
static void unlock_spi_csq_mutexes(struct amdgpu_device *adev)
|
||||
{
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
mutex_unlock(&adev->srbm_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_wave_count: Read device registers to get number of waves in flight for
|
||||
* a particular queue. The method also returns the doorbell offset associated
|
||||
* with the queue.
|
||||
*
|
||||
* @adev: Handle of device whose registers are to be read
|
||||
* @queue_idx: Index of queue in the queue-map bit-field
|
||||
* @queue_cnt: Stores the wave count and doorbell offset for an active queue
|
||||
* @inst: xcc's instance number on a multi-XCC setup
|
||||
*/
|
||||
static void get_wave_count(struct amdgpu_device *adev, int queue_idx,
|
||||
struct kfd_cu_occupancy *queue_cnt, uint32_t inst)
|
||||
{
|
||||
int pipe_idx;
|
||||
int queue_slot;
|
||||
unsigned int reg_val;
|
||||
unsigned int wave_cnt;
|
||||
/*
|
||||
* Program GRBM with appropriate MEID, PIPEID, QUEUEID and VMID
|
||||
* parameters to read out waves in flight. Get doorbell offset if there are
|
||||
* non-zero waves in flight.
|
||||
*/
|
||||
pipe_idx = queue_idx / adev->gfx.mec.num_queue_per_pipe;
|
||||
queue_slot = queue_idx % adev->gfx.mec.num_queue_per_pipe;
|
||||
soc24_grbm_select(adev, 1, pipe_idx, queue_slot, 0);
|
||||
reg_val = RREG32_SOC15_IP(GC, SOC15_REG_OFFSET(GC, 0,
|
||||
regSPI_CSQ_WF_ACTIVE_COUNT_0) + queue_slot);
|
||||
wave_cnt = reg_val & SPI_CSQ_WF_ACTIVE_COUNT_0__COUNT_MASK;
|
||||
if (wave_cnt != 0) {
|
||||
queue_cnt->wave_cnt += wave_cnt;
|
||||
queue_cnt->doorbell_off =
|
||||
(RREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL) &
|
||||
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK) >>
|
||||
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kgd_gfx_v12_get_cu_occupancy: Reads relevant registers associated with each
|
||||
* shader engine and aggregates the number of waves that are in flight for the
|
||||
* process whose pasid is provided as a parameter. The process could have ZERO
|
||||
* or more queues running and submitting waves to compute units.
|
||||
*
|
||||
* @adev: Handle of device from which to get number of waves in flight
|
||||
* @cu_occupancy: Array that gets filled with wave_cnt and doorbell offset
|
||||
* for comparison later.
|
||||
* @max_waves_per_cu: Output parameter updated with maximum number of waves
|
||||
* possible per Compute Unit
|
||||
* @inst: xcc's instance number on a multi-XCC setup
|
||||
*
|
||||
* Note: It's possible that the device has too many queues (oversubscription)
|
||||
* in which case a VMID could be remapped to a different PASID. This could lead
|
||||
* to an inaccurate wave count. Following is a high-level sequence:
|
||||
* Time T1: vmid = getVmid(); vmid is associated with Pasid P1
|
||||
* Time T2: passId = getPasId(vmid); vmid is associated with Pasid P2
|
||||
* In the sequence above wave count obtained from time T1 will be incorrectly
|
||||
* lost or added to total wave count.
|
||||
*
|
||||
* The registers that provide the waves in flight are:
|
||||
*
|
||||
* SPI_CSQ_WF_ACTIVE_STATUS - bit-map of queues per pipe. The bit is ON if a
|
||||
* queue is slotted, OFF if there is no queue. A process could have ZERO or
|
||||
* more queues slotted and submitting waves to be run on compute units. Even
|
||||
* when there is a queue it is possible there could be zero wave fronts, this
|
||||
* can happen when queue is waiting on top-of-pipe events - e.g. waitRegMem
|
||||
* command
|
||||
*
|
||||
* For each bit that is ON from above:
|
||||
*
|
||||
* Read (SPI_CSQ_WF_ACTIVE_COUNT_0 + queue_idx) register. It provides the
|
||||
* number of waves that are in flight for the queue at specified index. The
|
||||
* index ranges from 0 to 7.
|
||||
*
|
||||
* If non-zero waves are in flight, store the corresponding doorbell offset
|
||||
* of the queue, along with the wave count.
|
||||
*
|
||||
* Determine if the queue belongs to the process by comparing the doorbell
|
||||
* offset against the process's queues. If it matches, aggregate the wave
|
||||
* count for the process.
|
||||
*
|
||||
* Reading registers referenced above involves programming GRBM appropriately
|
||||
*/
|
||||
static void kgd_gfx_v12_get_cu_occupancy(struct amdgpu_device *adev,
|
||||
struct kfd_cu_occupancy *cu_occupancy,
|
||||
int *max_waves_per_cu, uint32_t inst)
|
||||
{
|
||||
int qidx;
|
||||
int se_idx;
|
||||
int se_cnt;
|
||||
int queue_map;
|
||||
int max_queue_cnt;
|
||||
DECLARE_BITMAP(cp_queue_bitmap, AMDGPU_MAX_QUEUES);
|
||||
|
||||
lock_spi_csq_mutexes(adev);
|
||||
soc24_grbm_select(adev, 1, 0, 0, 0);
|
||||
|
||||
/*
|
||||
* Iterate through the shader engines and arrays of the device
|
||||
* to get number of waves in flight
|
||||
*/
|
||||
bitmap_complement(cp_queue_bitmap, adev->gfx.mec_bitmap[0].queue_bitmap,
|
||||
AMDGPU_MAX_QUEUES);
|
||||
max_queue_cnt = adev->gfx.mec.num_pipe_per_mec *
|
||||
adev->gfx.mec.num_queue_per_pipe;
|
||||
se_cnt = adev->gfx.config.max_shader_engines;
|
||||
for (se_idx = 0; se_idx < se_cnt; se_idx++) {
|
||||
amdgpu_gfx_select_se_sh(adev, se_idx, 0, 0xffffffff, inst);
|
||||
queue_map = RREG32_SOC15(GC, 0,
|
||||
regSPI_CSQ_WF_ACTIVE_STATUS);
|
||||
|
||||
for (qidx = 0; qidx < max_queue_cnt; qidx++) {
|
||||
/* Skip queues that are not associated with
|
||||
* compute functions
|
||||
*/
|
||||
if (!test_bit(qidx, cp_queue_bitmap))
|
||||
continue;
|
||||
|
||||
if (!(queue_map & (1 << qidx)))
|
||||
continue;
|
||||
|
||||
/* Get number of waves in flight and aggregate them */
|
||||
get_wave_count(adev, qidx, &cu_occupancy[qidx], inst);
|
||||
}
|
||||
}
|
||||
|
||||
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, inst);
|
||||
soc24_grbm_select(adev, 0, 0, 0, 0);
|
||||
unlock_spi_csq_mutexes(adev);
|
||||
|
||||
/* Update the output parameters and return */
|
||||
*max_waves_per_cu = adev->gfx.cu_info.simd_per_cu *
|
||||
adev->gfx.cu_info.max_waves_per_simd;
|
||||
}
|
||||
|
||||
const struct kfd2kgd_calls gfx_v12_kfd2kgd = {
|
||||
.init_interrupts = init_interrupts_v12,
|
||||
.hqd_dump = hqd_dump_v12,
|
||||
|
|
@ -381,5 +528,6 @@ const struct kfd2kgd_calls gfx_v12_kfd2kgd = {
|
|||
.set_wave_launch_mode = kgd_gfx_v12_set_wave_launch_mode,
|
||||
.set_address_watch = kgd_gfx_v12_set_address_watch,
|
||||
.clear_address_watch = kgd_gfx_v12_clear_address_watch,
|
||||
.hqd_sdma_get_doorbell = kgd_gfx_v12_hqd_sdma_get_doorbell
|
||||
.hqd_sdma_get_doorbell = kgd_gfx_v12_hqd_sdma_get_doorbell,
|
||||
.get_cu_occupancy = kgd_gfx_v12_get_cu_occupancy,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -371,6 +371,153 @@ static uint32_t kgd_gfx_v12_1_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void lock_spi_csq_mutexes(struct amdgpu_device *adev)
|
||||
{
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
|
||||
}
|
||||
|
||||
static void unlock_spi_csq_mutexes(struct amdgpu_device *adev)
|
||||
{
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
mutex_unlock(&adev->srbm_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_wave_count: Read device registers to get number of waves in flight for
|
||||
* a particular queue. The method also returns the doorbell offset associated
|
||||
* with the queue.
|
||||
*
|
||||
* @adev: Handle of device whose registers are to be read
|
||||
* @queue_idx: Index of queue in the queue-map bit-field
|
||||
* @queue_cnt: Stores the wave count and doorbell offset for an active queue
|
||||
* @inst: xcc's instance number on a multi-XCC setup
|
||||
*/
|
||||
static void get_wave_count(struct amdgpu_device *adev, int queue_idx,
|
||||
struct kfd_cu_occupancy *queue_cnt, uint32_t inst)
|
||||
{
|
||||
int pipe_idx;
|
||||
int queue_slot;
|
||||
unsigned int reg_val;
|
||||
unsigned int wave_cnt;
|
||||
/*
|
||||
* Program GRBM with appropriate MEID, PIPEID, QUEUEID and VMID
|
||||
* parameters to read out waves in flight. Get doorbell offset if there are
|
||||
* non-zero waves in flight.
|
||||
*/
|
||||
pipe_idx = queue_idx / adev->gfx.mec.num_queue_per_pipe;
|
||||
queue_slot = queue_idx % adev->gfx.mec.num_queue_per_pipe;
|
||||
amdgpu_gfx_select_me_pipe_q(adev, 1, pipe_idx, queue_slot, 0, inst);
|
||||
reg_val = RREG32_SOC15_IP(GC, SOC15_REG_OFFSET(GC, GET_INST(GC, inst),
|
||||
regSPI_CSQ_WF_ACTIVE_COUNT_0) + queue_slot);
|
||||
wave_cnt = reg_val & SPI_CSQ_WF_ACTIVE_COUNT_0__COUNT_MASK;
|
||||
if (wave_cnt != 0) {
|
||||
queue_cnt->wave_cnt += wave_cnt;
|
||||
queue_cnt->doorbell_off =
|
||||
(RREG32_SOC15(GC, GET_INST(GC, inst), regCP_HQD_PQ_DOORBELL_CONTROL) &
|
||||
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK) >>
|
||||
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kgd_gfx_v12_1_get_cu_occupancy: Reads relevant registers associated with
|
||||
* each shader engine and aggregates the number of waves that are in flight
|
||||
* for the process whose pasid is provided as a parameter. The process could
|
||||
* have ZERO or more queues running and submitting waves to compute units.
|
||||
*
|
||||
* @adev: Handle of device from which to get number of waves in flight
|
||||
* @cu_occupancy: Array that gets filled with wave_cnt and doorbell offset
|
||||
* for comparison later.
|
||||
* @max_waves_per_cu: Output parameter updated with maximum number of waves
|
||||
* possible per Compute Unit
|
||||
* @inst: xcc's instance number on a multi-XCC setup
|
||||
*
|
||||
* Note: It's possible that the device has too many queues (oversubscription)
|
||||
* in which case a VMID could be remapped to a different PASID. This could lead
|
||||
* to an inaccurate wave count. Following is a high-level sequence:
|
||||
* Time T1: vmid = getVmid(); vmid is associated with Pasid P1
|
||||
* Time T2: passId = getPasId(vmid); vmid is associated with Pasid P2
|
||||
* In the sequence above wave count obtained from time T1 will be incorrectly
|
||||
* lost or added to total wave count.
|
||||
*
|
||||
* The registers that provide the waves in flight are:
|
||||
*
|
||||
* SPI_CSQ_WF_ACTIVE_STATUS - bit-map of queues per pipe. The bit is ON if a
|
||||
* queue is slotted, OFF if there is no queue. A process could have ZERO or
|
||||
* more queues slotted and submitting waves to be run on compute units. Even
|
||||
* when there is a queue it is possible there could be zero wave fronts, this
|
||||
* can happen when queue is waiting on top-of-pipe events - e.g. waitRegMem
|
||||
* command
|
||||
*
|
||||
* For each bit that is ON from above:
|
||||
*
|
||||
* Read (SPI_CSQ_WF_ACTIVE_COUNT_0 + queue_idx) register. It provides the
|
||||
* number of waves that are in flight for the queue at specified index. The
|
||||
* index ranges from 0 to 7.
|
||||
*
|
||||
* If non-zero waves are in flight, store the corresponding doorbell offset
|
||||
* of the queue, along with the wave count.
|
||||
*
|
||||
* Determine if the queue belongs to the process by comparing the doorbell
|
||||
* offset against the process's queues. If it matches, aggregate the wave
|
||||
* count for the process.
|
||||
*
|
||||
* Reading registers referenced above involves programming GRBM appropriately
|
||||
*/
|
||||
static void kgd_gfx_v12_1_get_cu_occupancy(struct amdgpu_device *adev,
|
||||
struct kfd_cu_occupancy *cu_occupancy,
|
||||
int *max_waves_per_cu, uint32_t inst)
|
||||
{
|
||||
int qidx;
|
||||
int se_idx;
|
||||
int se_cnt;
|
||||
int queue_map;
|
||||
int max_queue_cnt;
|
||||
DECLARE_BITMAP(cp_queue_bitmap, AMDGPU_MAX_QUEUES);
|
||||
|
||||
lock_spi_csq_mutexes(adev);
|
||||
amdgpu_gfx_select_me_pipe_q(adev, 1, 0, 0, 0, inst);
|
||||
|
||||
/*
|
||||
* Iterate through the shader engines and arrays of the device
|
||||
* to get number of waves in flight
|
||||
*/
|
||||
bitmap_complement(cp_queue_bitmap, adev->gfx.mec_bitmap[0].queue_bitmap,
|
||||
AMDGPU_MAX_QUEUES);
|
||||
max_queue_cnt = adev->gfx.mec.num_pipe_per_mec *
|
||||
adev->gfx.mec.num_queue_per_pipe;
|
||||
se_cnt = adev->gfx.config.max_shader_engines;
|
||||
for (se_idx = 0; se_idx < se_cnt; se_idx++) {
|
||||
amdgpu_gfx_select_se_sh(adev, se_idx, 0, 0xffffffff, inst);
|
||||
queue_map = RREG32_SOC15(GC, GET_INST(GC, inst),
|
||||
regSPI_CSQ_WF_ACTIVE_STATUS);
|
||||
|
||||
for (qidx = 0; qidx < max_queue_cnt; qidx++) {
|
||||
/* Skip queues that are not associated with
|
||||
* compute functions
|
||||
*/
|
||||
if (!test_bit(qidx, cp_queue_bitmap))
|
||||
continue;
|
||||
|
||||
if (!(queue_map & (1 << qidx)))
|
||||
continue;
|
||||
|
||||
/* Get number of waves in flight and aggregate them */
|
||||
get_wave_count(adev, qidx, &cu_occupancy[qidx], inst);
|
||||
}
|
||||
}
|
||||
|
||||
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, inst);
|
||||
amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0, inst);
|
||||
unlock_spi_csq_mutexes(adev);
|
||||
|
||||
/* Update the output parameters and return */
|
||||
*max_waves_per_cu = adev->gfx.cu_info.simd_per_cu *
|
||||
adev->gfx.cu_info.max_waves_per_simd;
|
||||
}
|
||||
|
||||
const struct kfd2kgd_calls gfx_v12_1_kfd2kgd = {
|
||||
.init_interrupts = init_interrupts_v12_1,
|
||||
.hqd_dump = hqd_dump_v12_1,
|
||||
|
|
@ -384,5 +531,6 @@ const struct kfd2kgd_calls gfx_v12_1_kfd2kgd = {
|
|||
.set_wave_launch_mode = kgd_gfx_v12_1_set_wave_launch_mode,
|
||||
.set_address_watch = kgd_gfx_v12_1_set_address_watch,
|
||||
.clear_address_watch = kgd_gfx_v12_1_clear_address_watch,
|
||||
.hqd_sdma_get_doorbell = kgd_gfx_v12_1_hqd_sdma_get_doorbell
|
||||
.hqd_sdma_get_doorbell = kgd_gfx_v12_1_hqd_sdma_get_doorbell,
|
||||
.get_cu_occupancy = kgd_gfx_v12_1_get_cu_occupancy
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1795,6 +1795,12 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
|
|||
size >>= 1;
|
||||
aligned_size = PAGE_ALIGN(size);
|
||||
|
||||
/* reject AQL queue with size < 2 */
|
||||
if (!aligned_size) {
|
||||
ret = -EINVAL;
|
||||
goto err_alignment_size;
|
||||
}
|
||||
|
||||
(*mem)->alloc_flags = flags;
|
||||
|
||||
amdgpu_sync_create(&(*mem)->sync);
|
||||
|
|
@ -1886,6 +1892,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
|
|||
amdgpu_amdkfd_unreserve_mem_limit(adev, aligned_size, flags, xcp_id);
|
||||
err_reserve_limit:
|
||||
amdgpu_sync_free(&(*mem)->sync);
|
||||
err_alignment_size:
|
||||
mutex_destroy(&(*mem)->lock);
|
||||
if (gobj)
|
||||
drm_gem_object_put(gobj);
|
||||
|
|
|
|||
|
|
@ -609,6 +609,13 @@ void amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device *adev)
|
|||
int bamaco_support;
|
||||
|
||||
adev->pm.rpm_mode = AMDGPU_RUNPM_NONE;
|
||||
if (pci_is_thunderbolt_attached(adev->pdev) ||
|
||||
dev_is_removable(&adev->pdev->dev)) {
|
||||
dev_info(adev->dev,
|
||||
"Runtime PM disabled for externally attached device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bamaco_support = amdgpu_device_supports_baco(adev);
|
||||
|
||||
switch (amdgpu_runtime_pm) {
|
||||
|
|
@ -2523,7 +2530,11 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
|
|||
if (r)
|
||||
goto init_failed;
|
||||
|
||||
amdgpu_ttm_enable_buffer_funcs(adev);
|
||||
/* If SDMA is not brought up during hwini, the ttm buffer funcs enablement
|
||||
* is delayed after reset-on-init completes.
|
||||
*/
|
||||
if (amdgpu_ip_member_of_hwini(adev, AMD_IP_BLOCK_TYPE_SDMA))
|
||||
amdgpu_ttm_enable_buffer_funcs(adev);
|
||||
|
||||
/* Don't init kfd if whole hive need to be reset during init */
|
||||
if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) {
|
||||
|
|
@ -3733,6 +3744,14 @@ static void amdgpu_device_sys_interface_fini(struct amdgpu_device *adev)
|
|||
amdgpu_ptl_sysfs_fini(adev);
|
||||
}
|
||||
|
||||
static bool
|
||||
amdgpu_device_should_register_switcheroo(struct amdgpu_device *adev, bool px)
|
||||
{
|
||||
return !pci_is_thunderbolt_attached(adev->pdev) &&
|
||||
(px || (!dev_is_removable(&adev->pdev->dev) &&
|
||||
apple_gmux_detect(NULL, NULL)));
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_device_init - initialize the driver
|
||||
*
|
||||
|
|
@ -4183,8 +4202,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
|
||||
px = amdgpu_device_supports_px(adev);
|
||||
|
||||
if (px || (!dev_is_removable(&adev->pdev->dev) &&
|
||||
apple_gmux_detect(NULL, NULL)))
|
||||
if (amdgpu_device_should_register_switcheroo(adev, px))
|
||||
vga_switcheroo_register_client(adev->pdev,
|
||||
&amdgpu_switcheroo_ops, px);
|
||||
|
||||
|
|
@ -4349,8 +4367,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
|
|||
|
||||
px = amdgpu_device_supports_px(adev);
|
||||
|
||||
if (px || (!dev_is_removable(&adev->pdev->dev) &&
|
||||
apple_gmux_detect(NULL, NULL)))
|
||||
if (amdgpu_device_should_register_switcheroo(adev, px))
|
||||
vga_switcheroo_unregister_client(adev->pdev);
|
||||
|
||||
if (px)
|
||||
|
|
@ -5037,6 +5054,31 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
|
|||
amdgpu_fence_driver_force_completion(ring, fence);
|
||||
}
|
||||
|
||||
/*
|
||||
* MES scheduler rings have no drm scheduler, so they are missed by the
|
||||
* loop above. Realign their polling fence too (one per XCC), otherwise the
|
||||
* first post-reset submission polls forever on a stale seq. sched.ready is
|
||||
* only set while the driver owns the ring.
|
||||
*/
|
||||
for (i = 0; i < AMDGPU_MAX_MES_INST_PIPES; i++) {
|
||||
struct amdgpu_ring *mes_ring = &adev->mes.ring[i];
|
||||
|
||||
if (mes_ring->fence_drv.initialized && mes_ring->sched.ready)
|
||||
amdgpu_fence_driver_force_completion(mes_ring, fence);
|
||||
}
|
||||
|
||||
/*
|
||||
* KIQ rings are polling-fence/no_scheduler like MES, so realign their
|
||||
* fence too (one ring per XCC), otherwise the first post-reset KIQ
|
||||
* submission polls forever on a stale seq.
|
||||
*/
|
||||
for (i = 0; i < AMDGPU_MAX_GC_INSTANCES; i++) {
|
||||
struct amdgpu_ring *kiq_ring = &adev->gfx.kiq[i].ring;
|
||||
|
||||
if (kiq_ring->fence_drv.initialized && kiq_ring->sched.ready)
|
||||
amdgpu_fence_driver_force_completion(kiq_ring, fence);
|
||||
}
|
||||
|
||||
amdgpu_fence_driver_isr_toggle(adev, false);
|
||||
|
||||
r = amdgpu_reset_prepare_hwcontext(adev, reset_context);
|
||||
|
|
@ -5137,8 +5179,6 @@ int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context)
|
|||
if (r)
|
||||
goto out;
|
||||
|
||||
amdgpu_ttm_enable_buffer_funcs(tmp_adev);
|
||||
|
||||
r = amdgpu_device_ip_resume_phase3(tmp_adev);
|
||||
if (r)
|
||||
goto out;
|
||||
|
|
@ -6647,8 +6687,8 @@ struct dma_fence *amdgpu_device_enforce_isolation(struct amdgpu_device *adev,
|
|||
struct amdgpu_ring *ring,
|
||||
struct amdgpu_job *job)
|
||||
{
|
||||
struct amdgpu_isolation *isolation = &adev->isolation[ring->xcp_id];
|
||||
struct drm_sched_fence *f = job->base.s_fence;
|
||||
struct amdgpu_isolation *isolation;
|
||||
struct dma_fence *dep;
|
||||
void *owner;
|
||||
int r;
|
||||
|
|
@ -6661,6 +6701,9 @@ struct dma_fence *amdgpu_device_enforce_isolation(struct amdgpu_device *adev,
|
|||
ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE)
|
||||
return NULL;
|
||||
|
||||
isolation = &adev->isolation[ring->xcp_id == AMDGPU_XCP_NO_PARTITION ?
|
||||
0 : ring->xcp_id];
|
||||
|
||||
/*
|
||||
* All submissions where enforce isolation is false are handled as if
|
||||
* they come from a single client. Use ~0l as the owner to distinct it
|
||||
|
|
|
|||
|
|
@ -1307,8 +1307,19 @@ static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev,
|
|||
ip_hw_instance->num_instance);
|
||||
ip_hw_instance->num_base_addresses = ip->num_base_address;
|
||||
|
||||
for (kk = 0; kk < ip_hw_instance->num_base_addresses; kk++)
|
||||
ip_hw_instance->base_addr[kk] = ip->base_address[kk];
|
||||
for (kk = 0; kk < ip_hw_instance->num_base_addresses; kk++) {
|
||||
/*
|
||||
* Standalone mode uses a raw copy of the discovery
|
||||
* binary; decode 64-bit addresses here. The shared
|
||||
* bin is already collapsed to 32-bit in place.
|
||||
*/
|
||||
if (reg_base_64 && ip_top->standalone_mode)
|
||||
ip_hw_instance->base_addr[kk] =
|
||||
lower_32_bits(le64_to_cpu(ip->base_address_64[kk])) & 0x3FFFFFFF;
|
||||
else
|
||||
ip_hw_instance->base_addr[kk] =
|
||||
le32_to_cpu(ip->base_address[kk]);
|
||||
}
|
||||
|
||||
kobject_init(&ip_hw_instance->kobj, &ip_hw_instance_ktype);
|
||||
ip_hw_instance->kobj.kset = &ip_hw_id->hw_id_kset;
|
||||
|
|
|
|||
|
|
@ -2557,6 +2557,7 @@ amdgpu_pci_remove(struct pci_dev *pdev)
|
|||
if (adev->pm.rpm_mode != AMDGPU_RUNPM_NONE) {
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
pm_runtime_forbid(dev->dev);
|
||||
pm_runtime_dont_use_autosuspend(dev->dev);
|
||||
}
|
||||
|
||||
amdgpu_driver_unload_kms(dev);
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
|
|||
vm_af = job->hw_vm_fence;
|
||||
/* VM sequence */
|
||||
vm_af->ib_wptr = ring->wptr;
|
||||
amdgpu_vm_flush(ring, job, need_pipe_sync, &emit_spm_needed,
|
||||
amdgpu_vm_flush(ring, job, &need_pipe_sync, &emit_spm_needed,
|
||||
&emit_gds_needed);
|
||||
vm_af->ib_dw_size =
|
||||
amdgpu_ring_get_dw_distance(ring, vm_af->ib_wptr, ring->wptr);
|
||||
|
|
@ -235,6 +235,10 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
|
|||
if (ring->funcs->insert_start)
|
||||
ring->funcs->insert_start(ring);
|
||||
|
||||
/* this may have been handled by amdgpu_vm_flush */
|
||||
if (need_pipe_sync)
|
||||
amdgpu_ring_emit_pipeline_sync(ring);
|
||||
|
||||
if (emit_spm_needed)
|
||||
adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid);
|
||||
|
||||
|
|
|
|||
|
|
@ -287,22 +287,24 @@ static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
|
|||
|
||||
static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
int i, r = 0;
|
||||
int i;
|
||||
bool mapped;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(queue->userq_vas.va_array); i++) {
|
||||
if (!queue->userq_vas.va_array[i])
|
||||
continue;
|
||||
r += amdgpu_userq_buffer_va_mapped(queue->vm,
|
||||
|
||||
mapped = amdgpu_userq_buffer_va_mapped(queue->vm,
|
||||
queue->userq_vas.va_array[i]);
|
||||
dev_dbg(queue->userq_mgr->adev->dev,
|
||||
"validate the userq mapping:%p va:%llx r:%d\n",
|
||||
queue, queue->userq_vas.va_array[i], r);
|
||||
queue, queue->userq_vas.va_array[i], mapped);
|
||||
|
||||
if (!mapped)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (r != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -416,19 +418,12 @@ static void amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue
|
|||
dma_fence_wait(f, false);
|
||||
}
|
||||
|
||||
static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
|
||||
static void amdgpu_userq_detach_doorbell(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
struct amdgpu_device *adev = queue->userq_mgr->adev;
|
||||
|
||||
/* Wait for mode-1 reset to complete */
|
||||
down_read(&adev->reset_domain->sem);
|
||||
|
||||
/* Use interrupt-safe locking since IRQ handlers may access these XArrays */
|
||||
xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
queue->fence_drv = NULL;
|
||||
|
||||
up_read(&adev->reset_domain->sem);
|
||||
}
|
||||
|
||||
|
|
@ -549,18 +544,19 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
|
|||
|
||||
cancel_delayed_work_sync(&uq_mgr->resume_work);
|
||||
|
||||
/* Cancel any pending hang detection work and cleanup */
|
||||
cancel_delayed_work_sync(&queue->hang_detect_work);
|
||||
|
||||
mutex_lock(&uq_mgr->userq_mutex);
|
||||
amdgpu_userq_wait_for_last_fence(queue);
|
||||
|
||||
amdgpu_userq_detach_doorbell(queue);
|
||||
cancel_delayed_work_sync(&queue->hang_detect_work);
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
debugfs_remove_recursive(queue->debugfs_queue);
|
||||
#endif
|
||||
r = amdgpu_userq_unmap_helper(queue);
|
||||
atomic_dec(&uq_mgr->userq_count[queue->queue_type]);
|
||||
amdgpu_userq_cleanup(queue);
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
queue->fence_drv = NULL;
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
||||
/*
|
||||
|
|
@ -572,7 +568,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
|
|||
if (r)
|
||||
queue_work(adev->reset_domain->wq, &uq_mgr->reset_work);
|
||||
|
||||
cancel_delayed_work_sync(&queue->hang_detect_work);
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
queue->userq_mgr = NULL;
|
||||
|
||||
|
|
@ -700,10 +695,10 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
args->in.queue_size,
|
||||
&queue->userq_vas.va.queue_rb) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va,
|
||||
AMDGPU_GPU_PAGE_SIZE,
|
||||
sizeof(u64),
|
||||
&queue->userq_vas.va.rptr) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va,
|
||||
AMDGPU_GPU_PAGE_SIZE,
|
||||
sizeof(u64),
|
||||
&queue->userq_vas.va.wptr)) {
|
||||
r = -EINVAL;
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
|
|
@ -746,7 +741,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
((queue->queue_type != AMDGPU_HW_IP_GFX) &&
|
||||
(queue->queue_type != AMDGPU_HW_IP_COMPUTE))) {
|
||||
/* Serialize the map against an in-progress GPU reset (MES is
|
||||
* unresponsive during recovery), matching amdgpu_userq_cleanup().
|
||||
* unresponsive during recovery), matching amdgpu_userq_detach_doorbell().
|
||||
*/
|
||||
down_read(&adev->reset_domain->sem);
|
||||
r = amdgpu_userq_map_helper(queue);
|
||||
|
|
@ -848,6 +843,12 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev,
|
|||
drm_file_err(filp, "invalidate userq queue rptr or wptr\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!IS_ALIGNED(args->in.wptr_va, sizeof(u64)) ||
|
||||
!IS_ALIGNED(args->in.rptr_va, sizeof(u64))) {
|
||||
drm_file_err(filp, "user queue rptr or wptr is not 8-byte aligned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AMDGPU_USERQ_OP_FREE:
|
||||
if (args->in.ip_type ||
|
||||
|
|
@ -1046,6 +1047,30 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr)
|
|||
drm_exec_retry_on_contention(&exec);
|
||||
if (unlikely(ret))
|
||||
goto unlock_all;
|
||||
|
||||
/*
|
||||
* WPTR BOs are VM-mapped, but each BO has its own reservation
|
||||
* object. Lock them into this drm_exec ww context so the later
|
||||
* amdgpu_bo_gpu_offset() reads are done with the BO resv locked.
|
||||
*/
|
||||
xa_for_each(&uq_mgr->userq_xa, tmp_key, queue) {
|
||||
struct ttm_operation_ctx wptr_ctx = { false, false };
|
||||
|
||||
bo = queue->wptr_obj.obj;
|
||||
if (!bo)
|
||||
continue;
|
||||
|
||||
ret = drm_exec_prepare_obj(&exec, &bo->tbo.base,
|
||||
TTM_NUM_MOVE_FENCES + 1);
|
||||
drm_exec_retry_on_contention(&exec);
|
||||
if (unlikely(ret))
|
||||
goto unlock_all;
|
||||
|
||||
amdgpu_bo_placement_from_domain(bo, bo->allowed_domains);
|
||||
ret = ttm_bo_validate(&bo->tbo, &bo->placement, &wptr_ctx);
|
||||
if (unlikely(ret))
|
||||
goto unlock_all;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidated) {
|
||||
|
|
|
|||
|
|
@ -191,14 +191,15 @@ void amdgpu_userq_fence_driver_destroy(struct kref *ref)
|
|||
struct dma_fence *f;
|
||||
|
||||
spin_lock_irqsave(&fence_drv->fence_list_lock, flags);
|
||||
lockdep_assert_held(&fence_drv->fence_list_lock);
|
||||
list_for_each_entry_safe(fence, tmp, &fence_drv->fences, link) {
|
||||
f = &fence->base;
|
||||
|
||||
if (!dma_fence_is_signaled(f)) {
|
||||
spin_lock(dma_fence_spinlock(f));
|
||||
if (!dma_fence_is_signaled_locked(f)) {
|
||||
dma_fence_set_error(f, -ECANCELED);
|
||||
dma_fence_signal(f);
|
||||
dma_fence_signal_locked(f);
|
||||
}
|
||||
|
||||
spin_unlock(dma_fence_spinlock(f));
|
||||
list_del(&fence->link);
|
||||
dma_fence_put(f);
|
||||
}
|
||||
|
|
@ -423,11 +424,16 @@ amdgpu_userq_fence_driver_set_error(struct amdgpu_userq_fence *fence,
|
|||
struct dma_fence *f;
|
||||
|
||||
spin_lock_irqsave(&fence_drv->fence_list_lock, flags);
|
||||
|
||||
lockdep_assert_held(&fence_drv->fence_list_lock);
|
||||
f = rcu_dereference_protected(&fence->base,
|
||||
lockdep_is_held(&fence_drv->fence_list_lock));
|
||||
if (f && !dma_fence_is_signaled_locked(f))
|
||||
dma_fence_set_error(f, error);
|
||||
if (f) {
|
||||
/* nest f->lock inside fence_list_lock */
|
||||
spin_lock(dma_fence_spinlock(f));
|
||||
if (!dma_fence_is_signaled_locked(f))
|
||||
dma_fence_set_error(f, error);
|
||||
spin_unlock(dma_fence_spinlock(f));
|
||||
}
|
||||
spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -537,7 +543,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
|
|||
* amdgpu_userq_ensure_ev_fence() can't be called while holding the resv
|
||||
* locks.
|
||||
*/
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES,
|
||||
(num_read_bo_handles + num_write_bo_handles));
|
||||
|
||||
drm_exec_until_all_locked(&exec) {
|
||||
|
|
@ -643,7 +649,7 @@ amdgpu_userq_wait_count_fences(struct drm_file *filp,
|
|||
/* TODO: It is actually not necessary to lock them */
|
||||
num_read_bo_handles = wait_info->num_bo_read_handles;
|
||||
num_write_bo_handles = wait_info->num_bo_write_handles;
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES,
|
||||
num_read_bo_handles + num_write_bo_handles);
|
||||
|
||||
drm_exec_until_all_locked(&exec) {
|
||||
|
|
@ -778,7 +784,7 @@ amdgpu_userq_wait_return_fence_info(struct drm_device *dev, struct drm_file *fil
|
|||
/* Lock all the GEM objects */
|
||||
num_read_bo_handles = wait_info->num_bo_read_handles;
|
||||
num_write_bo_handles = wait_info->num_bo_write_handles;
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
|
||||
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES,
|
||||
num_read_bo_handles + num_write_bo_handles);
|
||||
|
||||
drm_exec_until_all_locked(&exec) {
|
||||
|
|
|
|||
|
|
@ -517,7 +517,8 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev)
|
|||
}
|
||||
memset_io(ptr, 0, size);
|
||||
/* to restore uvd fence seq */
|
||||
amdgpu_fence_driver_force_completion(&adev->uvd.inst[i].ring, NULL);
|
||||
if (adev->uvd.inst[i].ring.fence_drv.initialized)
|
||||
amdgpu_fence_driver_force_completion(&adev->uvd.inst[i].ring, NULL);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -772,11 +772,13 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring,
|
|||
* Emit a VM flush when it is necessary.
|
||||
*/
|
||||
void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
|
||||
bool need_pipe_sync, bool *emit_spm_needed,
|
||||
bool *need_pipe_sync, bool *emit_spm_needed,
|
||||
bool *emit_gds_needed)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_isolation *isolation = &adev->isolation[ring->xcp_id];
|
||||
struct amdgpu_isolation *isolation =
|
||||
&adev->isolation[ring->xcp_id == AMDGPU_XCP_NO_PARTITION ?
|
||||
0 : ring->xcp_id];
|
||||
unsigned vmhub = ring->vm_hub;
|
||||
struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
||||
struct amdgpu_vmid *id = &id_mgr->ids[job->vmid];
|
||||
|
|
@ -827,8 +829,7 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
|
|||
if (gds_switch_needed && emit_fence)
|
||||
*emit_gds_needed = false;
|
||||
|
||||
if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync &&
|
||||
!cleaner_shader_needed && !spm_update_needed)
|
||||
if (!emit_fence)
|
||||
return;
|
||||
|
||||
amdgpu_ring_ib_begin(ring);
|
||||
|
|
@ -847,8 +848,10 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
|
|||
patch = amdgpu_ring_init_cond_exec(ring,
|
||||
ring->cond_exe_gpu_addr);
|
||||
|
||||
if (need_pipe_sync)
|
||||
if (*need_pipe_sync) {
|
||||
amdgpu_ring_emit_pipeline_sync(ring);
|
||||
*need_pipe_sync = false;
|
||||
}
|
||||
|
||||
if (cleaner_shader_needed)
|
||||
ring->funcs->emit_cleaner_shader(ring);
|
||||
|
|
@ -861,21 +864,19 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
|
|||
if (pasid_mapping_needed)
|
||||
amdgpu_gmc_emit_pasid_mapping(ring, job->vmid, job->pasid);
|
||||
|
||||
if (emit_fence) {
|
||||
if (spm_update_needed)
|
||||
adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid);
|
||||
if (spm_update_needed)
|
||||
adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid);
|
||||
|
||||
if (gds_switch_needed)
|
||||
amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base,
|
||||
if (gds_switch_needed)
|
||||
amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base,
|
||||
job->gds_size, job->gws_base,
|
||||
job->gws_size, job->oa_base,
|
||||
job->oa_size);
|
||||
|
||||
amdgpu_fence_emit(ring, job->hw_vm_fence, 0);
|
||||
fence = &job->hw_vm_fence->base;
|
||||
/* get a ref for the job */
|
||||
dma_fence_get(fence);
|
||||
}
|
||||
amdgpu_fence_emit(ring, job->hw_vm_fence, 0);
|
||||
fence = &job->hw_vm_fence->base;
|
||||
/* get a ref for the job */
|
||||
dma_fence_get(fence);
|
||||
|
||||
if (vm_flush_needed) {
|
||||
mutex_lock(&id_mgr->lock);
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
|||
int (*callback)(void *p, struct amdgpu_bo *bo),
|
||||
void *param);
|
||||
void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
|
||||
bool need_pipe_sync, bool *emit_spm_needed,
|
||||
bool *need_pipe_sync, bool *emit_spm_needed,
|
||||
bool *emit_gds_needed);
|
||||
int amdgpu_vm_update_pdes(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm, bool immediate);
|
||||
|
|
|
|||
|
|
@ -1380,6 +1380,9 @@ static void amdgpu_xgmi_reset_on_init_work(struct work_struct *work)
|
|||
amdgpu_device_unlock_reset_domain(tmp_adev->reset_domain);
|
||||
|
||||
list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
|
||||
/* Enable ttm buffers funcs after the reset lock has been dropped. */
|
||||
amdgpu_ttm_enable_buffer_funcs(tmp_adev);
|
||||
|
||||
r = amdgpu_ras_init_badpage_info(tmp_adev);
|
||||
if (r && r != -EHWPOISON)
|
||||
dev_err(tmp_adev->dev,
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ static int mes_userq_map(struct amdgpu_usermode_queue *queue)
|
|||
queue_input.wptr_mc_addr = queue->wptr_obj.gpu_addr;
|
||||
|
||||
if (mes->use_rs64mem) {
|
||||
if (!uq_mgr->proc_ctx_allocated) {
|
||||
if (!uq_mgr->proc_ctx_allocated) {
|
||||
r = amdgpu_mes_alloc_proc_ctx_index(mes, &uq_mgr->proc_ctx_array_index);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to allocate userq process index err:%d\n", r);
|
||||
|
|
|
|||
|
|
@ -891,7 +891,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = {
|
|||
|
||||
static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = {
|
||||
.type = AMDGPU_RING_TYPE_VCE,
|
||||
.align_mask = 0xf,
|
||||
.align_mask = 0x1f,
|
||||
.nop = VCE_CMD_NO_OP,
|
||||
.support_64bit_ptrs = false,
|
||||
.no_user_fence = true,
|
||||
|
|
|
|||
|
|
@ -1964,9 +1964,13 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
|||
len_dw = msg[1] / 4;
|
||||
num_buffers = msg[2];
|
||||
|
||||
/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
|
||||
if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
|
||||
DRM_ERROR("VCN message has too many buffers!\n");
|
||||
/* Verify that all indices fit within the claimed length.
|
||||
* There are 6 dwords in the header before the first buffer.
|
||||
* Each buffer has 4 dwords. Any trailing dwords after the
|
||||
* last buffer are ignored.
|
||||
*/
|
||||
if (len_dw < 6 || num_buffers > (len_dw - 6) / 4) {
|
||||
DRM_ERROR("Invalid VCN message!\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1880,9 +1880,13 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
|||
len_dw = msg[1] / 4;
|
||||
num_buffers = msg[2];
|
||||
|
||||
/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
|
||||
if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
|
||||
DRM_ERROR("VCN message has too many buffers!\n");
|
||||
/* Verify that all indices fit within the claimed length.
|
||||
* There are 6 dwords in the header before the first buffer.
|
||||
* Each buffer has 4 dwords. Any trailing dwords after the
|
||||
* last buffer are ignored.
|
||||
*/
|
||||
if (len_dw < 6 || num_buffers > (len_dw - 6) / 4) {
|
||||
DRM_ERROR("Invalid VCN message!\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1200,7 +1200,8 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
|
|||
|
||||
if (flags & KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM)
|
||||
size >>= 1;
|
||||
atomic64_add(PAGE_ALIGN(size), &pdd->vram_usage);
|
||||
size = PAGE_ALIGN(size);
|
||||
atomic64_add(size, &pdd->vram_usage);
|
||||
}
|
||||
|
||||
mutex_unlock(&p->mutex);
|
||||
|
|
@ -3329,7 +3330,7 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t profile_lock_device(struct kfd_process *p,
|
||||
static inline int profile_lock_device(struct kfd_process *p,
|
||||
uint32_t gpu_id, uint32_t op)
|
||||
{
|
||||
struct kfd_process_device *pdd;
|
||||
|
|
|
|||
|
|
@ -769,6 +769,11 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
|
|||
|
||||
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
|
||||
q->properties.type)];
|
||||
if (qd && !mqd_mgr->restore_mqd) {
|
||||
pr_debug("restore_mqd not implemented for this GPU\n");
|
||||
retval = -EOPNOTSUPP;
|
||||
goto deallocate_vmid;
|
||||
}
|
||||
if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
|
||||
retval = allocate_hqd(dqm, q);
|
||||
if (retval)
|
||||
|
|
@ -2236,6 +2241,11 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
|
|||
|
||||
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
|
||||
q->properties.type)];
|
||||
if (qd && !mqd_mgr->restore_mqd) {
|
||||
pr_debug("restore_mqd not implemented for this GPU\n");
|
||||
retval = -EOPNOTSUPP;
|
||||
goto out_deallocate_doorbell;
|
||||
}
|
||||
|
||||
if (q->properties.type == KFD_QUEUE_TYPE_SDMA ||
|
||||
q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys,
|
|||
u64 gart_s, gart_d;
|
||||
struct dma_fence *next;
|
||||
u64 size;
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
ring = to_amdgpu_ring(adev->mman.buffer_funcs_scheds[0]);
|
||||
entity = &adev->mman.move_entities[0];
|
||||
|
|
@ -258,15 +258,6 @@ svm_migrate_get_sys_page(struct vm_area_struct *vma, unsigned long addr)
|
|||
return page;
|
||||
}
|
||||
|
||||
static void svm_migrate_put_sys_page(unsigned long addr)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
page = pfn_to_page(addr >> PAGE_SHIFT);
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
static unsigned long svm_migrate_successful_pages(struct migrate_vma *migrate)
|
||||
{
|
||||
unsigned long mpages = 0;
|
||||
|
|
@ -293,7 +284,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
|
|||
dma_addr_t *src;
|
||||
u64 *dst;
|
||||
u64 i, j;
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
pr_debug("svms 0x%p [0x%lx 0x%lx 0x%llx]\n", prange->svms, prange->start,
|
||||
prange->last, ttm_res_offset);
|
||||
|
|
@ -319,6 +310,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
|
|||
DMA_BIDIRECTIONAL);
|
||||
r = dma_mapping_error(dev, src[i]);
|
||||
if (r) {
|
||||
src[i] = 0;
|
||||
dev_err(dev, "%s: fail %d dma_map_page\n",
|
||||
__func__, r);
|
||||
goto out_free_vram_pages;
|
||||
|
|
@ -343,7 +335,8 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
|
|||
pr_debug_ratelimited("dma mapping src to 0x%llx, pfn 0x%lx\n",
|
||||
src[i] >> PAGE_SHIFT, page_to_pfn(spage));
|
||||
|
||||
if (j >= (cursor.size >> PAGE_SHIFT) - 1 && i < npages - 1) {
|
||||
/* accumulated j + 1 pages reach end of current drm_buddy_block */
|
||||
if (j + 1 >= (cursor.size >> PAGE_SHIFT)) {
|
||||
r = svm_migrate_copy_memory_gart(adev, src + i - j,
|
||||
dst + i - j, j + 1,
|
||||
FROM_RAM_TO_VRAM,
|
||||
|
|
@ -357,7 +350,8 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
|
|||
}
|
||||
}
|
||||
|
||||
r = svm_migrate_copy_memory_gart(adev, src + i - j, dst + i - j, j,
|
||||
if (j > 0)
|
||||
r = svm_migrate_copy_memory_gart(adev, src + i - j, dst + i - j, j,
|
||||
FROM_RAM_TO_VRAM, mfence);
|
||||
|
||||
out_free_vram_pages:
|
||||
|
|
@ -591,9 +585,10 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
|
|||
dma_addr_t *scratch, u64 npages)
|
||||
{
|
||||
struct device *dev = adev->dev;
|
||||
u64 *src;
|
||||
struct page *dpage = NULL;
|
||||
dma_addr_t *dst;
|
||||
struct page *dpage;
|
||||
u64 *src;
|
||||
|
||||
u64 i = 0, j;
|
||||
u64 addr;
|
||||
int r = 0;
|
||||
|
|
@ -647,6 +642,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
|
|||
r = dma_mapping_error(dev, dst[i]);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "%s: fail %d dma_map_page\n", __func__, r);
|
||||
dst[i] = 0;
|
||||
goto out_oom;
|
||||
}
|
||||
|
||||
|
|
@ -654,17 +650,39 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
|
|||
dst[i] >> PAGE_SHIFT, page_to_pfn(dpage));
|
||||
|
||||
migrate->dst[i] = migrate_pfn(page_to_pfn(dpage));
|
||||
|
||||
dpage = NULL;
|
||||
j++;
|
||||
}
|
||||
|
||||
r = svm_migrate_copy_memory_gart(adev, dst + i - j, src + i - j, j,
|
||||
FROM_VRAM_TO_RAM, mfence);
|
||||
|
||||
if (j > 0)
|
||||
r = svm_migrate_copy_memory_gart(adev, dst + i - j, src + i - j, j,
|
||||
FROM_VRAM_TO_RAM, mfence);
|
||||
out_oom:
|
||||
if (r) {
|
||||
pr_debug("failed %d copy to ram\n", r);
|
||||
|
||||
/* first release current dpage when dma_map_page fail */
|
||||
if (dpage) {
|
||||
unlock_page(dpage);
|
||||
put_page(dpage);
|
||||
}
|
||||
|
||||
/* release previous allocated sys pages and unmap dma address */
|
||||
while (i--) {
|
||||
svm_migrate_put_sys_page(dst[i]);
|
||||
|
||||
if (dst[i]) {
|
||||
dma_unmap_page(dev, dst[i], PAGE_SIZE,
|
||||
DMA_BIDIRECTIONAL);
|
||||
dst[i] = 0;
|
||||
}
|
||||
|
||||
dpage = migrate_pfn_to_page(migrate->dst[i]);
|
||||
if (!dpage)
|
||||
continue;
|
||||
|
||||
unlock_page(dpage);
|
||||
put_page(dpage);
|
||||
migrate->dst[i] = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1589,6 +1589,9 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
|
|||
res = amdgpu_dm_commit_zero_streams(dm->dc);
|
||||
if (res != DC_OK) {
|
||||
drm_err(adev_to_drm(adev), "Failed to commit zero streams: %d\n", res);
|
||||
dc_state_release(dm->cached_dc_state);
|
||||
dm->cached_dc_state = NULL;
|
||||
mutex_unlock(&dm->dc_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1884,6 +1887,9 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
|
|||
r = dm_dmub_hw_init(adev);
|
||||
if (r) {
|
||||
drm_err(adev_to_drm(adev), "DMUB interface failed to initialize: status=%d\n", r);
|
||||
dc_state_release(dm->cached_dc_state);
|
||||
dm->cached_dc_state = NULL;
|
||||
mutex_unlock(&dm->dc_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,10 +106,10 @@ int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps,
|
|||
}
|
||||
EXPORT_IF_KUNIT(get_brightness_range);
|
||||
|
||||
/* Rescale from [min..max] to [0..AMDGPU_MAX_BL_LEVEL] */
|
||||
static inline u32 scale_input_to_fw(int min, int max, u64 input)
|
||||
/* Rescale userspace [0..max] to the firmware curve's [0..255]. */
|
||||
static inline u32 scale_input_to_fw(int max, u64 input)
|
||||
{
|
||||
return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max - min);
|
||||
return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max);
|
||||
}
|
||||
|
||||
/* Rescale from [0..AMDGPU_MAX_BL_LEVEL] to [min..max] */
|
||||
|
|
@ -123,7 +123,7 @@ void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps,
|
|||
unsigned int min, unsigned int max,
|
||||
uint32_t *user_brightness)
|
||||
{
|
||||
u32 brightness = scale_input_to_fw(min, max, *user_brightness);
|
||||
u32 brightness = scale_input_to_fw(max, *user_brightness);
|
||||
u8 lower_signal, upper_signal, upper_lum, lower_lum, lum;
|
||||
int left, right;
|
||||
|
||||
|
|
|
|||
|
|
@ -471,6 +471,12 @@ bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
|
|||
uint32_t expected;
|
||||
int delta;
|
||||
|
||||
/* A LUT with fewer than two entries can't be interpolated and would
|
||||
* divide by zero below (size - 1); it can't be treated as linear.
|
||||
*/
|
||||
if (size < 2)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
/* All color values should equal */
|
||||
if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue))
|
||||
|
|
@ -1489,6 +1495,13 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state,
|
|||
degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut,
|
||||
°amma_size);
|
||||
|
||||
if (degamma_lut && degamma_size != MAX_COLOR_LUT_ENTRIES) {
|
||||
drm_dbg(plane_state->state->dev,
|
||||
"Invalid Plane Degamma LUT size. Should be %u but got %u.\n",
|
||||
MAX_COLOR_LUT_ENTRIES, degamma_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
has_degamma_lut = degamma_lut &&
|
||||
!__is_lut_linear(degamma_lut, degamma_size);
|
||||
|
||||
|
|
|
|||
|
|
@ -1735,7 +1735,9 @@ int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev)
|
|||
if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
|
||||
int_params.irq_source < DC_IRQ_SOURCE_HPD1 ||
|
||||
int_params.irq_source > DC_IRQ_SOURCE_HPD6) {
|
||||
drm_err(adev_to_drm(adev), "Failed to register hpd irq!\n");
|
||||
drm_err(adev_to_drm(adev),
|
||||
"Failed to register hpd irq %u for %s!\n",
|
||||
int_params.irq_source, connector->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1753,7 +1755,9 @@ int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev)
|
|||
if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
|
||||
int_params.irq_source < DC_IRQ_SOURCE_HPD1RX ||
|
||||
int_params.irq_source > DC_IRQ_SOURCE_HPD6RX) {
|
||||
drm_err(adev_to_drm(adev), "Failed to register hpd rx irq!\n");
|
||||
drm_err(adev_to_drm(adev),
|
||||
"Failed to register hpd rx irq %u for %s!\n",
|
||||
int_params.irq_source, connector->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,9 @@ void dcn5_calculate_byte_per_pixel_and_block_sizes(
|
|||
*BytePerPixelDETC = 0;
|
||||
*BytePerPixelY = 8;
|
||||
*BytePerPixelC = 0;
|
||||
} else if (SourcePixelFormat == dml2_444_32 || SourcePixelFormat == dml2_rgbe || SourcePixelFormat == dml2_422_packed_10 || SourcePixelFormat == dml2_422_packed_12) {
|
||||
} else if (SourcePixelFormat == dml2_444_32 ||
|
||||
SourcePixelFormat == dml2_rgbe ||
|
||||
SourcePixelFormat == dml2_422_packed_12) {
|
||||
*BytePerPixelDETY = 4;
|
||||
*BytePerPixelDETC = 0;
|
||||
*BytePerPixelY = 4;
|
||||
|
|
|
|||
|
|
@ -569,20 +569,11 @@ void dcn6_calculate_flip_schedule(
|
|||
|
||||
if (GPUVMEnable) {
|
||||
if (l->dual_plane) {
|
||||
if (GPUVMEnable) {
|
||||
l->min_row_height = dpte_row_height;
|
||||
l->min_row_height_chroma = dpte_row_height_chroma;
|
||||
} else {
|
||||
l->min_row_height = meta_row_height;
|
||||
l->min_row_height_chroma = meta_row_height_chroma;
|
||||
}
|
||||
l->min_row_height = dpte_row_height;
|
||||
l->min_row_height_chroma = dpte_row_height_chroma;
|
||||
l->min_row_time = math_min2(l->min_row_height * LineTime / VRatio, l->min_row_height_chroma * LineTime / VRatioChroma);
|
||||
} else {
|
||||
if (GPUVMEnable)
|
||||
l->min_row_height = dpte_row_height;
|
||||
else
|
||||
l->min_row_height = meta_row_height;
|
||||
|
||||
l->min_row_height = dpte_row_height;
|
||||
l->min_row_time = l->min_row_height * LineTime / VRatio;
|
||||
}
|
||||
DML_LOG_VERBOSE("DML::%s: min_row_time = %f\n", __func__, l->min_row_time);
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ static bool construct_phy(struct dc_link *link,
|
|||
|
||||
DC_LOG_DC("BIOS object table - hpd_gpio id: %d", enc_init_data.hpd_gpio->id);
|
||||
DC_LOG_DC("BIOS object table - hpd_gpio en: %d", enc_init_data.hpd_gpio->en);
|
||||
} else {
|
||||
} else if (link->ctx->dce_version > DCN_VERSION_4_01) {
|
||||
struct graphics_object_hpd_info hpd_info;
|
||||
|
||||
if (link->ctx->dc_bios->funcs->get_hpd_info(link->ctx->dc_bios, link->link_id, &hpd_info) == BP_RESULT_OK) {
|
||||
|
|
|
|||
|
|
@ -869,8 +869,9 @@ static void validate_blend_mode_for_alpha_formats(struct drm_plane *plane)
|
|||
for (i = 0; i < plane->format_count; i++) {
|
||||
fmt = drm_format_info(plane->format_types[i]);
|
||||
if (fmt->has_alpha) {
|
||||
WARN(1, "[PLANE:%d:%s] pixel format with alpha exposed but blend mode not setup",
|
||||
plane->base.id, plane->name);
|
||||
drm_warn(plane->dev,
|
||||
"[PLANE:%d:%s] pixel format with alpha exposed but blend mode not setup. Please fix.\n",
|
||||
plane->base.id, plane->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
extern bool hang_debug;
|
||||
|
||||
#define A3XX_VBIF_XIN_HALT_CTRL0_MASK GENMASK(5, 0)
|
||||
|
||||
static void a3xx_dump(struct msm_gpu *gpu);
|
||||
static bool a3xx_idle(struct msm_gpu *gpu);
|
||||
|
||||
|
|
@ -496,6 +498,38 @@ static u64 a3xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
|
|||
return busy_cycles;
|
||||
}
|
||||
|
||||
static int a3xx_vbif_halt(struct msm_gpu *gpu)
|
||||
{
|
||||
u32 ack;
|
||||
int ret;
|
||||
|
||||
gpu_write(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL0,
|
||||
A3XX_VBIF_XIN_HALT_CTRL0_MASK);
|
||||
ret = spin_until(((ack = gpu_read(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL1)) &
|
||||
A3XX_VBIF_XIN_HALT_CTRL0_MASK) ==
|
||||
A3XX_VBIF_XIN_HALT_CTRL0_MASK);
|
||||
gpu_write(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL0, 0);
|
||||
|
||||
if (ret)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a3xx_pm_suspend(struct msm_gpu *gpu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!a3xx_idle(gpu))
|
||||
return -EBUSY;
|
||||
|
||||
ret = a3xx_vbif_halt(gpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return msm_gpu_pm_suspend(gpu);
|
||||
}
|
||||
|
||||
static u32 a3xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
|
||||
{
|
||||
ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR);
|
||||
|
|
@ -581,7 +615,7 @@ const struct adreno_gpu_funcs a3xx_gpu_funcs = {
|
|||
.get_param = adreno_get_param,
|
||||
.set_param = adreno_set_param,
|
||||
.hw_init = a3xx_hw_init,
|
||||
.pm_suspend = msm_gpu_pm_suspend,
|
||||
.pm_suspend = a3xx_pm_suspend,
|
||||
.pm_resume = msm_gpu_pm_resume,
|
||||
.recover = a3xx_recover,
|
||||
.submit = a3xx_submit,
|
||||
|
|
|
|||
|
|
@ -1275,6 +1275,11 @@ static irqreturn_t a5xx_irq(struct msm_gpu *gpu)
|
|||
status & ~A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR);
|
||||
|
||||
if (priv->disable_err_irq) {
|
||||
/* Turn off interrupts to avoid interrupt storm */
|
||||
gpu_write(gpu, REG_A5XX_RBBM_INT_0_MASK,
|
||||
A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS |
|
||||
A5XX_RBBM_INT_0_MASK_CP_SW);
|
||||
|
||||
status &= A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS |
|
||||
A5XX_RBBM_INT_0_MASK_CP_SW;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1199,7 +1199,7 @@ static const struct adreno_reglist a730_hwcg[] = {
|
|||
{ REG_A6XX_RBBM_CLOCK_DELAY_SP0, 0x00000080 },
|
||||
{ REG_A6XX_RBBM_CLOCK_CNTL_TP0, 0x22222220 },
|
||||
{ REG_A6XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222 },
|
||||
{ REG_A6XX_RBBM_CLOCK_CNTL3_TP0, 0x22222222 },
|
||||
{ REG_A6XX_RBBM_CLOCK_CNTL3_TP0, 0x22220222 },
|
||||
{ REG_A6XX_RBBM_CLOCK_CNTL4_TP0, 0x00222222 },
|
||||
{ REG_A6XX_RBBM_CLOCK_HYST_TP0, 0x77777777 },
|
||||
{ REG_A6XX_RBBM_CLOCK_HYST2_TP0, 0x77777777 },
|
||||
|
|
@ -1454,7 +1454,7 @@ DECLARE_ADRENO_REGLIST_PIPE_LIST(a7xx_dyn_pwrup_reglist);
|
|||
|
||||
static const struct adreno_info a7xx_gpus[] = {
|
||||
{
|
||||
.chip_ids = ADRENO_CHIP_IDS(0x07000200),
|
||||
.chip_ids = ADRENO_CHIP_IDS(0x07000200, 0x07000400),
|
||||
.family = ADRENO_6XX_GEN1, /* NOT a mistake! */
|
||||
.fw = {
|
||||
[ADRENO_FW_SQE] = "a702_sqe.fw",
|
||||
|
|
@ -1500,6 +1500,40 @@ static const struct adreno_info a7xx_gpus[] = {
|
|||
.gmu_cgc_mode = 0x00020000,
|
||||
},
|
||||
.preempt_record_size = 2860 * SZ_1K,
|
||||
}, {
|
||||
.chip_ids = ADRENO_CHIP_IDS(0x43020100),
|
||||
.family = ADRENO_7XX_GEN1,
|
||||
.fw = {
|
||||
[ADRENO_FW_SQE] = "qcom/gen71700_sqe.fw",
|
||||
[ADRENO_FW_GMU] = "qcom/gen71700_gmu.bin",
|
||||
},
|
||||
.gmem = SZ_1M,
|
||||
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
|
||||
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
|
||||
ADRENO_QUIRK_HAS_HW_APRIV |
|
||||
ADRENO_QUIRK_PREEMPTION,
|
||||
.funcs = &a7xx_gpu_funcs,
|
||||
.a6xx = &(const struct a6xx_info) {
|
||||
.hwcg = a730_hwcg,
|
||||
.protect = &a730_protect,
|
||||
.pwrup_reglist = &a7xx_pwrup_reglist,
|
||||
.dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist,
|
||||
.gbif_cx = a640_gbif,
|
||||
.gmu_chipid = 0x07110000,
|
||||
.gmu_cgc_mode = 0x00020000,
|
||||
.bcms = (const struct a6xx_bcm[]) {
|
||||
{ .name = "SH0", .buswidth = 16 },
|
||||
{ .name = "MC0", .buswidth = 4 },
|
||||
{
|
||||
.name = "ACV",
|
||||
.fixed = true,
|
||||
.perfmode = BIT(3),
|
||||
.perfmode_bw = 16500000,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
},
|
||||
},
|
||||
.preempt_record_size = 1536 * SZ_1K,
|
||||
}, {
|
||||
.chip_ids = ADRENO_CHIP_IDS(0x43050a01), /* "C510v2" */
|
||||
.family = ADRENO_7XX_GEN2,
|
||||
|
|
@ -2180,7 +2214,7 @@ static const struct adreno_reglist a840_gbif[] = {
|
|||
{ REG_A6XX_GBIF_QSB_SIDE1, 0x00071e20 },
|
||||
{ REG_A6XX_GBIF_QSB_SIDE2, 0x00071e20 },
|
||||
{ REG_A6XX_GBIF_QSB_SIDE3, 0x00071e20 },
|
||||
{ REG_A8XX_GBIF_CX_CONFIG, 0x20023000 },
|
||||
{ REG_A6XX_GBIF_CX_CONFIG, 0x20023000 },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu)
|
|||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (test_and_clear_bit(GMU_STATUS_FW_START, &gmu->status))
|
||||
if (!test_and_clear_bit(GMU_STATUS_FW_START, &gmu->status))
|
||||
return;
|
||||
|
||||
if (adreno_is_a840(adreno_gpu))
|
||||
|
|
@ -710,7 +710,8 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
|
|||
gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 2, 0);
|
||||
gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 2, 0);
|
||||
gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 4,
|
||||
adreno_is_a740_family(adreno_gpu) ? 0x80000021 : 0x80000000);
|
||||
(adreno_is_a740_family(adreno_gpu) ||
|
||||
adreno_is_a722(adreno_gpu)) ? 0x80000021 : 0x80000000);
|
||||
gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 4, 0);
|
||||
gmu_write_rscc(gmu, REG_A6XX_RSCC_OVERRIDE_START_ADDR, 0);
|
||||
gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520);
|
||||
|
|
@ -718,7 +719,7 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
|
|||
gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514);
|
||||
|
||||
/* The second spin of A7xx GPUs messed with some register offsets.. */
|
||||
if (adreno_is_a740_family(adreno_gpu))
|
||||
if (adreno_is_a740_family(adreno_gpu) || adreno_is_a722(adreno_gpu))
|
||||
seqmem0_drv0_reg = REG_A7XX_RSCC_SEQ_MEM_0_DRV0_A740;
|
||||
|
||||
/* Load RSC sequencer uCode for sleep and wakeup */
|
||||
|
|
@ -1032,9 +1033,11 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
|
|||
gpu_write(gpu, gbif_cx[i].offset, gbif_cx[i].value);
|
||||
|
||||
if (adreno_is_a8xx(adreno_gpu)) {
|
||||
gpu_write(gpu, REG_A8XX_GBIF_CX_CONFIG, 0x20023000);
|
||||
gpu_write(gpu, REG_A6XX_GBIF_CX_CONFIG, 0x20023000);
|
||||
gmu_write(gmu, REG_A6XX_GMU_MRC_GBIF_QOS_CTRL, 0x33);
|
||||
}
|
||||
} else if (adreno_is_a722(adreno_gpu))
|
||||
gpu_rmw(gpu, REG_A6XX_GBIF_CX_CONFIG, GENMASK(31, 29),
|
||||
FIELD_PREP(GENMASK(31, 29), 2));
|
||||
|
||||
/* Set up the lowest idle level on the GMU */
|
||||
a6xx_gmu_power_config(gmu);
|
||||
|
|
@ -1087,7 +1090,8 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
|
|||
u32 val, seqmem_off = 0;
|
||||
|
||||
/* The second spin of A7xx GPUs messed with some register offsets.. */
|
||||
if (adreno_is_a740_family(adreno_gpu) || adreno_is_a8xx(adreno_gpu))
|
||||
if (adreno_is_a740_family(adreno_gpu) || adreno_is_a722(adreno_gpu) ||
|
||||
adreno_is_a8xx(adreno_gpu))
|
||||
seqmem_off = 4;
|
||||
|
||||
/* Make sure there are no outstanding RPMh votes */
|
||||
|
|
@ -1100,7 +1104,8 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
|
|||
gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS + seqmem_off,
|
||||
val, (val & 1), 100, 1000);
|
||||
|
||||
if (!adreno_is_a740_family(adreno_gpu) && !adreno_is_a8xx(adreno_gpu))
|
||||
if (!adreno_is_a740_family(adreno_gpu) && !adreno_is_a722(adreno_gpu) &&
|
||||
!adreno_is_a8xx(adreno_gpu))
|
||||
return;
|
||||
|
||||
gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS4_DRV0_STATUS + seqmem_off,
|
||||
|
|
@ -1465,6 +1470,9 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu)
|
|||
/* Stop the interrupts and mask the hardware */
|
||||
a6xx_gmu_irq_disable(gmu);
|
||||
|
||||
/* Halt the gmu cm3 core */
|
||||
gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1);
|
||||
|
||||
/* Tell RPMh to power off the GPU */
|
||||
a6xx_rpmh_stop(gmu);
|
||||
|
||||
|
|
@ -1546,7 +1554,7 @@ static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo,
|
|||
flags |= MSM_BO_MAP_PRIV;
|
||||
}
|
||||
|
||||
bo->obj = msm_gem_new(dev, size, flags);
|
||||
bo->obj = msm_gem_new(dev, size, flags, NULL);
|
||||
if (IS_ERR(bo->obj))
|
||||
return PTR_ERR(bo->obj);
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,
|
|||
{
|
||||
bool sysprof = msm_gpu_sysprof_no_perfcntr_zap(&a6xx_gpu->base.base);
|
||||
struct msm_context *ctx = submit->queue->ctx;
|
||||
struct drm_gpuvm *vm = msm_context_vm(submit->dev, ctx);
|
||||
struct drm_gpuvm *vm = ctx->vm;
|
||||
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
|
||||
phys_addr_t ttbr;
|
||||
u32 asid;
|
||||
|
|
@ -1273,7 +1273,8 @@ static int hw_init(struct msm_gpu *gpu)
|
|||
if (!(adreno_is_a650_family(adreno_gpu) ||
|
||||
adreno_is_a702(adreno_gpu) ||
|
||||
adreno_is_a730(adreno_gpu))) {
|
||||
gmem_range_min = adreno_is_a740_family(adreno_gpu) ? SZ_16M : SZ_1M;
|
||||
gmem_range_min = (adreno_is_a740_family(adreno_gpu) ||
|
||||
adreno_is_a722(adreno_gpu)) ? SZ_16M : SZ_1M;
|
||||
|
||||
/* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */
|
||||
gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN, gmem_range_min);
|
||||
|
|
@ -1338,6 +1339,7 @@ static int hw_init(struct msm_gpu *gpu)
|
|||
|
||||
/* Enable fault detection */
|
||||
if (adreno_is_a612(adreno_gpu) ||
|
||||
adreno_is_a722(adreno_gpu) ||
|
||||
adreno_is_a730(adreno_gpu) ||
|
||||
adreno_is_a740_family(adreno_gpu))
|
||||
gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0xcfffff);
|
||||
|
|
@ -1911,8 +1913,11 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
|
|||
|
||||
gpu_write(gpu, REG_A6XX_RBBM_INT_CLEAR_CMD, status);
|
||||
|
||||
if (priv->disable_err_irq)
|
||||
if (priv->disable_err_irq) {
|
||||
/* Turn off interrupts to avoid interrupt storm */
|
||||
gpu_write(gpu, REG_A6XX_RBBM_INT_0_MASK, A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS);
|
||||
status &= A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS;
|
||||
}
|
||||
|
||||
if (status & A6XX_RBBM_INT_0_MASK_RBBM_HANG_DETECT)
|
||||
a6xx_fault_detect_irq(gpu);
|
||||
|
|
@ -2770,8 +2775,9 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
|
|||
|
||||
adreno_gpu->ubwc_config = qcom_ubwc_config_get_data();
|
||||
if (IS_ERR(adreno_gpu->ubwc_config)) {
|
||||
ret = PTR_ERR(adreno_gpu->ubwc_config);
|
||||
a6xx_destroy(&(a6xx_gpu->base.base));
|
||||
return ERR_CAST(adreno_gpu->ubwc_config);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* Set up the preemption specific bits and pieces for each ringbuffer */
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@
|
|||
static const unsigned int *gen7_0_0_external_core_regs[] __always_unused;
|
||||
static const unsigned int *gen7_2_0_external_core_regs[] __always_unused;
|
||||
static const unsigned int *gen7_9_0_external_core_regs[] __always_unused;
|
||||
static const unsigned int *gen7_17_0_external_core_regs[] __always_unused;
|
||||
static const struct gen7_sptp_cluster_registers gen7_9_0_sptp_clusters[] __always_unused;
|
||||
static const u32 gen7_9_0_cx_debugbus_blocks[] __always_unused;
|
||||
|
||||
#include "adreno_gen7_0_0_snapshot.h"
|
||||
#include "adreno_gen7_2_0_snapshot.h"
|
||||
#include "adreno_gen7_9_0_snapshot.h"
|
||||
#include "adreno_gen7_17_0_snapshot.h"
|
||||
|
||||
struct a6xx_gpu_state_obj {
|
||||
const void *handle;
|
||||
|
|
@ -404,8 +406,13 @@ static void a7xx_get_debugbus_blocks(struct msm_gpu *gpu,
|
|||
int i;
|
||||
|
||||
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
|
||||
debugbus_blocks = gen7_0_0_debugbus_blocks;
|
||||
debugbus_blocks_count = ARRAY_SIZE(gen7_0_0_debugbus_blocks);
|
||||
if (adreno_is_a722(adreno_gpu)) {
|
||||
debugbus_blocks = gen7_17_0_debugbus_blocks;
|
||||
debugbus_blocks_count = ARRAY_SIZE(gen7_17_0_debugbus_blocks);
|
||||
} else {
|
||||
debugbus_blocks = gen7_0_0_debugbus_blocks;
|
||||
debugbus_blocks_count = ARRAY_SIZE(gen7_0_0_debugbus_blocks);
|
||||
}
|
||||
gbif_debugbus_blocks = a7xx_gbif_debugbus_blocks;
|
||||
gbif_debugbus_blocks_count = ARRAY_SIZE(a7xx_gbif_debugbus_blocks);
|
||||
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
|
||||
|
|
@ -678,8 +685,13 @@ static void a7xx_get_dbgahb_clusters(struct msm_gpu *gpu,
|
|||
unsigned dbgahb_clusters_size;
|
||||
|
||||
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
|
||||
dbgahb_clusters = gen7_0_0_sptp_clusters;
|
||||
dbgahb_clusters_size = ARRAY_SIZE(gen7_0_0_sptp_clusters);
|
||||
if (adreno_is_a722(adreno_gpu)) {
|
||||
dbgahb_clusters = gen7_17_0_sptp_clusters;
|
||||
dbgahb_clusters_size = ARRAY_SIZE(gen7_17_0_sptp_clusters);
|
||||
} else {
|
||||
dbgahb_clusters = gen7_0_0_sptp_clusters;
|
||||
dbgahb_clusters_size = ARRAY_SIZE(gen7_0_0_sptp_clusters);
|
||||
}
|
||||
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
|
||||
dbgahb_clusters = gen7_2_0_sptp_clusters;
|
||||
dbgahb_clusters_size = ARRAY_SIZE(gen7_2_0_sptp_clusters);
|
||||
|
|
@ -839,8 +851,13 @@ static void a7xx_get_clusters(struct msm_gpu *gpu,
|
|||
unsigned clusters_size;
|
||||
|
||||
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
|
||||
clusters = gen7_0_0_clusters;
|
||||
clusters_size = ARRAY_SIZE(gen7_0_0_clusters);
|
||||
if (adreno_is_a722(adreno_gpu)) {
|
||||
clusters = gen7_17_0_clusters;
|
||||
clusters_size = ARRAY_SIZE(gen7_17_0_clusters);
|
||||
} else {
|
||||
clusters = gen7_0_0_clusters;
|
||||
clusters_size = ARRAY_SIZE(gen7_0_0_clusters);
|
||||
}
|
||||
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
|
||||
clusters = gen7_2_0_clusters;
|
||||
clusters_size = ARRAY_SIZE(gen7_2_0_clusters);
|
||||
|
|
@ -977,8 +994,13 @@ static void a7xx_get_shaders(struct msm_gpu *gpu,
|
|||
int i;
|
||||
|
||||
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
|
||||
shader_blocks = gen7_0_0_shader_blocks;
|
||||
num_shader_blocks = ARRAY_SIZE(gen7_0_0_shader_blocks);
|
||||
if (adreno_is_a722(adreno_gpu)) {
|
||||
shader_blocks = gen7_17_0_shader_blocks;
|
||||
num_shader_blocks = ARRAY_SIZE(gen7_17_0_shader_blocks);
|
||||
} else {
|
||||
shader_blocks = gen7_0_0_shader_blocks;
|
||||
num_shader_blocks = ARRAY_SIZE(gen7_0_0_shader_blocks);
|
||||
}
|
||||
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
|
||||
shader_blocks = gen7_2_0_shader_blocks;
|
||||
num_shader_blocks = ARRAY_SIZE(gen7_2_0_shader_blocks);
|
||||
|
|
@ -1244,9 +1266,12 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu,
|
|||
_a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gmu_reglist[1],
|
||||
&a6xx_state->gmu_registers[1], true);
|
||||
|
||||
if (adreno_is_a621(adreno_gpu) || adreno_is_a623(adreno_gpu))
|
||||
if (adreno_is_a621(adreno_gpu))
|
||||
_a6xx_get_gmu_registers(gpu, a6xx_state, &a621_gpucc_reg,
|
||||
&a6xx_state->gmu_registers[2], false);
|
||||
else if (adreno_is_a623(adreno_gpu) || adreno_is_a663(adreno_gpu))
|
||||
_a6xx_get_gmu_registers(gpu, a6xx_state, &a623_gpucc_reg,
|
||||
&a6xx_state->gmu_registers[2], false);
|
||||
else
|
||||
_a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gpucc_reg,
|
||||
&a6xx_state->gmu_registers[2], false);
|
||||
|
|
@ -1376,8 +1401,13 @@ static void a7xx_get_registers(struct msm_gpu *gpu,
|
|||
const struct gen7_reg_list *reglist;
|
||||
|
||||
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
|
||||
reglist = gen7_0_0_reg_list;
|
||||
pre_crashdumper_regs = gen7_0_0_pre_crashdumper_gpu_registers;
|
||||
if (adreno_is_a722(adreno_gpu)) {
|
||||
reglist = gen7_17_0_reg_list;
|
||||
pre_crashdumper_regs = gen7_9_0_pre_crashdumper_gpu_registers;
|
||||
} else {
|
||||
reglist = gen7_0_0_reg_list;
|
||||
pre_crashdumper_regs = gen7_0_0_pre_crashdumper_gpu_registers;
|
||||
}
|
||||
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
|
||||
reglist = gen7_2_0_reg_list;
|
||||
pre_crashdumper_regs = gen7_0_0_pre_crashdumper_gpu_registers;
|
||||
|
|
@ -1433,7 +1463,9 @@ static void a7xx_get_post_crashdumper_registers(struct msm_gpu *gpu,
|
|||
const u32 *regs;
|
||||
|
||||
BUG_ON(adreno_gpu->info->family > ADRENO_7XX_GEN3);
|
||||
regs = gen7_0_0_post_crashdumper_registers;
|
||||
regs = adreno_is_a722(adreno_gpu) ?
|
||||
gen7_17_0_post_crashdumper_registers :
|
||||
gen7_0_0_post_crashdumper_registers;
|
||||
|
||||
a7xx_get_ahb_gpu_registers(gpu,
|
||||
a6xx_state, regs,
|
||||
|
|
@ -1540,19 +1572,35 @@ static void a7xx_get_indexed_registers(struct msm_gpu *gpu,
|
|||
{
|
||||
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
|
||||
const struct a6xx_indexed_registers *indexed_regs;
|
||||
const struct a6xx_indexed_registers *mempool_regs;
|
||||
int i, indexed_count, mempool_count;
|
||||
bool concurrent_binning;
|
||||
|
||||
if (adreno_gpu->info->family <= ADRENO_7XX_GEN2) {
|
||||
if (adreno_is_a722(adreno_gpu)) {
|
||||
/*
|
||||
* Eliza has no BV or LPAC SQE — skip the BV/LPAC indexed
|
||||
* registers and the BV mempool
|
||||
*/
|
||||
indexed_regs = gen7_17_0_cp_indexed_reglist;
|
||||
indexed_count = ARRAY_SIZE(gen7_17_0_cp_indexed_reglist);
|
||||
mempool_regs = a7xx_cp_mempool_indexed;
|
||||
mempool_count = ARRAY_SIZE(a7xx_cp_mempool_indexed);
|
||||
concurrent_binning = false;
|
||||
} else if (adreno_gpu->info->family <= ADRENO_7XX_GEN2) {
|
||||
indexed_regs = a7xx_indexed_reglist;
|
||||
indexed_count = ARRAY_SIZE(a7xx_indexed_reglist);
|
||||
mempool_regs = a7xx_cp_bv_mempool_indexed;
|
||||
mempool_count = ARRAY_SIZE(a7xx_cp_bv_mempool_indexed);
|
||||
concurrent_binning = true;
|
||||
} else {
|
||||
BUG_ON(adreno_gpu->info->family != ADRENO_7XX_GEN3);
|
||||
indexed_regs = gen7_9_0_cp_indexed_reg_list;
|
||||
indexed_count = ARRAY_SIZE(gen7_9_0_cp_indexed_reg_list);
|
||||
mempool_regs = a7xx_cp_bv_mempool_indexed;
|
||||
mempool_count = ARRAY_SIZE(a7xx_cp_bv_mempool_indexed);
|
||||
concurrent_binning = true;
|
||||
}
|
||||
|
||||
mempool_count = ARRAY_SIZE(a7xx_cp_bv_mempool_indexed);
|
||||
|
||||
a6xx_state->indexed_regs = state_kcalloc(a6xx_state,
|
||||
indexed_count + mempool_count,
|
||||
sizeof(*a6xx_state->indexed_regs));
|
||||
|
|
@ -1567,15 +1615,17 @@ static void a7xx_get_indexed_registers(struct msm_gpu *gpu,
|
|||
&a6xx_state->indexed_regs[i]);
|
||||
|
||||
gpu_rmw(gpu, REG_A6XX_CP_CHICKEN_DBG, 0, BIT(2));
|
||||
gpu_rmw(gpu, REG_A7XX_CP_BV_CHICKEN_DBG, 0, BIT(2));
|
||||
if (concurrent_binning)
|
||||
gpu_rmw(gpu, REG_A7XX_CP_BV_CHICKEN_DBG, 0, BIT(2));
|
||||
|
||||
/* Get the contents of the CP_BV mempool */
|
||||
for (i = 0; i < mempool_count; i++)
|
||||
a6xx_get_indexed_regs(gpu, a6xx_state, &a7xx_cp_bv_mempool_indexed[i],
|
||||
a6xx_get_indexed_regs(gpu, a6xx_state, &mempool_regs[i],
|
||||
&a6xx_state->indexed_regs[indexed_count + i]);
|
||||
|
||||
gpu_rmw(gpu, REG_A6XX_CP_CHICKEN_DBG, BIT(2), 0);
|
||||
gpu_rmw(gpu, REG_A7XX_CP_BV_CHICKEN_DBG, BIT(2), 0);
|
||||
if (concurrent_binning)
|
||||
gpu_rmw(gpu, REG_A7XX_CP_BV_CHICKEN_DBG, BIT(2), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -377,6 +377,17 @@ static const u32 a6xx_gmu_gpucc_registers[] = {
|
|||
};
|
||||
|
||||
static const u32 a621_gmu_gpucc_registers[] = {
|
||||
/* GPU CC */
|
||||
0x24000, 0x2400e, 0x24400, 0x2440e, 0x24800, 0x24805, 0x24c00, 0x24cff,
|
||||
0x25800, 0x25804, 0x25c00, 0x25c04, 0x26000, 0x26004, 0x26400, 0x26405,
|
||||
0x26414, 0x2641d, 0x2642a, 0x26430, 0x26432, 0x26432, 0x26441, 0x26455,
|
||||
0x26466, 0x26468, 0x26478, 0x2647a, 0x26489, 0x2648a, 0x2649c, 0x2649e,
|
||||
0x264a0, 0x264a3, 0x264b3, 0x264b5, 0x264c5, 0x264c7, 0x264d6, 0x264d8,
|
||||
0x264e8, 0x264e9, 0x264f9, 0x264fc, 0x2650b, 0x2650c, 0x2651c, 0x2651e,
|
||||
0x26540, 0x26570, 0x26600, 0x26616, 0x26620, 0x2662d,
|
||||
};
|
||||
|
||||
static const u32 a623_gmu_gpucc_registers[] = {
|
||||
/* GPU CC */
|
||||
0x24000, 0x2400e, 0x24400, 0x2440e, 0x25800, 0x25804, 0x25c00, 0x25c04,
|
||||
0x26000, 0x26004, 0x26400, 0x26405, 0x26414, 0x2641d, 0x2642a, 0x26430,
|
||||
|
|
@ -402,6 +413,7 @@ static const struct a6xx_registers a6xx_gmu_reglist[] = {
|
|||
|
||||
static const struct a6xx_registers a6xx_gpucc_reg = REGS(a6xx_gmu_gpucc_registers, 0, 0);
|
||||
static const struct a6xx_registers a621_gpucc_reg = REGS(a621_gmu_gpucc_registers, 0, 0);
|
||||
static const struct a6xx_registers a623_gpucc_reg = REGS(a623_gmu_gpucc_registers, 0, 0);
|
||||
|
||||
static u32 a6xx_get_cp_roq_size(struct msm_gpu *gpu);
|
||||
static u32 a7xx_get_cp_roq_size(struct msm_gpu *gpu);
|
||||
|
|
@ -462,6 +474,11 @@ static const struct a6xx_indexed_registers a7xx_cp_bv_mempool_indexed[] = {
|
|||
REG_A7XX_CP_BV_MEM_POOL_DBG_DATA, 0x2200, NULL },
|
||||
};
|
||||
|
||||
static const struct a6xx_indexed_registers a7xx_cp_mempool_indexed[] = {
|
||||
{ "CP_MEM_POOL_DBG", REG_A6XX_CP_MEM_POOL_DBG_ADDR,
|
||||
REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2200, NULL },
|
||||
};
|
||||
|
||||
#define DEBUGBUS(_id, _count) { .id = _id, .name = #_id, .count = _count }
|
||||
|
||||
static const struct a6xx_debugbus_block {
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ static void a8xx_set_hwcg(struct msm_gpu *gpu, bool state)
|
|||
* GMU enables clk gating in GBIF during boot up. So,
|
||||
* override that here when hwcg feature is disabled
|
||||
*/
|
||||
gpu_rmw(gpu, REG_A8XX_GBIF_CX_CONFIG, BIT(0), 0);
|
||||
gpu_rmw(gpu, REG_A6XX_GBIF_CX_CONFIG, BIT(0), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1211,8 +1211,11 @@ irqreturn_t a8xx_irq(struct msm_gpu *gpu)
|
|||
|
||||
gpu_write(gpu, REG_A8XX_RBBM_INT_CLEAR_CMD, status);
|
||||
|
||||
if (priv->disable_err_irq)
|
||||
if (priv->disable_err_irq) {
|
||||
/* Turn off interrupts to avoid interrupt storm */
|
||||
gpu_write(gpu, REG_A8XX_RBBM_INT_0_MASK, A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS);
|
||||
status &= A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS;
|
||||
}
|
||||
|
||||
if (status & A6XX_RBBM_INT_0_MASK_RBBM_HANG_DETECT)
|
||||
a8xx_fault_detect_irq(gpu);
|
||||
|
|
|
|||
428
drivers/gpu/drm/msm/adreno/adreno_gen7_17_0_snapshot.h
Normal file
428
drivers/gpu/drm/msm/adreno/adreno_gen7_17_0_snapshot.h
Normal file
|
|
@ -0,0 +1,428 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#ifndef __ADRENO_GEN7_17_0_SNAPSHOT_H
|
||||
#define __ADRENO_GEN7_17_0_SNAPSHOT_H
|
||||
|
||||
#include "a6xx_gpu_state.h"
|
||||
|
||||
/*
|
||||
* Snapshot tables for Adreno A722 (Eliza).
|
||||
* Cluster sub-arrays that are identical to A730 reference gen7_0_0_*
|
||||
* symbols; adreno_gen7_0_0_snapshot.h is included first in the TU.
|
||||
*/
|
||||
|
||||
static const u32 gen7_17_0_rscc_registers[] = {
|
||||
0x14000, 0x14034, 0x14036, 0x14036, 0x14040, 0x14042, 0x14044, 0x14045,
|
||||
0x14047, 0x14047, 0x14080, 0x14084, 0x14089, 0x1408c, 0x14091, 0x14094,
|
||||
0x14099, 0x1409c, 0x140a1, 0x140a4, 0x140a9, 0x140ac, 0x140b1, 0x140b4,
|
||||
0x140b9, 0x140bc, 0x14100, 0x14104, 0x14114, 0x14119, 0x14124, 0x14132,
|
||||
0x14154, 0x1416b, 0x14340, 0x14341, 0x14344, 0x14344, 0x14346, 0x1437c,
|
||||
0x143f0, 0x143f8, 0x143fa, 0x143fe, 0x14400, 0x14404, 0x14406, 0x1440a,
|
||||
0x1440c, 0x14410, 0x14412, 0x14416, 0x14418, 0x1441c, 0x1441e, 0x14422,
|
||||
0x14424, 0x14424, 0x14498, 0x144a0, 0x144a2, 0x144a6, 0x144a8, 0x144ac,
|
||||
0x144ae, 0x144b2, 0x144b4, 0x144b8, 0x144ba, 0x144be, 0x144c0, 0x144c4,
|
||||
0x144c6, 0x144ca, 0x144cc, 0x144cc, 0x14540, 0x14548, 0x1454a, 0x1454e,
|
||||
0x14550, 0x14554, 0x14556, 0x1455a, 0x1455c, 0x14560, 0x14562, 0x14566,
|
||||
0x14568, 0x1456c, 0x1456e, 0x14572, 0x14574, 0x14574, 0x145e8, 0x145f0,
|
||||
0x145f2, 0x145f6, 0x145f8, 0x145fc, 0x145fe, 0x14602, 0x14604, 0x14608,
|
||||
0x1460a, 0x1460e, 0x14610, 0x14614, 0x14616, 0x1461a, 0x1461c, 0x1461c,
|
||||
0x14690, 0x14698, 0x1469a, 0x1469e, 0x146a0, 0x146a4, 0x146a6, 0x146aa,
|
||||
0x146ac, 0x146b0, 0x146b2, 0x146b6, 0x146b8, 0x146bc, 0x146be, 0x146c2,
|
||||
0x146c4, 0x146c4, 0x14738, 0x14740, 0x14742, 0x14746, 0x14748, 0x1474c,
|
||||
0x1474e, 0x14752, 0x14754, 0x14758, 0x1475a, 0x1475e, 0x14760, 0x14764,
|
||||
0x14766, 0x1476a, 0x1476c, 0x1476c, 0x147e0, 0x147e8, 0x147ea, 0x147ee,
|
||||
0x147f0, 0x147f4, 0x147f6, 0x147fa, 0x147fc, 0x14800, 0x14802, 0x14806,
|
||||
0x14808, 0x1480c, 0x1480e, 0x14812, 0x14814, 0x14814, 0x14888, 0x14890,
|
||||
0x14892, 0x14896, 0x14898, 0x1489c, 0x1489e, 0x148a2, 0x148a4, 0x148a8,
|
||||
0x148aa, 0x148ae, 0x148b0, 0x148b4, 0x148b6, 0x148ba, 0x148bc, 0x148bc,
|
||||
0x14930, 0x14938, 0x1493a, 0x1493e, 0x14940, 0x14944, 0x14946, 0x1494a,
|
||||
0x1494c, 0x14950, 0x14952, 0x14956, 0x14958, 0x1495c, 0x1495e, 0x14962,
|
||||
0x14964, 0x14964,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_rscc_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_cpr_registers[] = {
|
||||
0x26800, 0x26805, 0x26808, 0x2680c, 0x26814, 0x26814, 0x2681c, 0x2681c,
|
||||
0x26820, 0x26838, 0x26840, 0x26840, 0x26848, 0x26848, 0x26850, 0x26850,
|
||||
0x26880, 0x2688e, 0x26980, 0x269b0, 0x269c0, 0x269c2, 0x269c6, 0x269c8,
|
||||
0x269e0, 0x269ee, 0x269fb, 0x269ff, 0x26a02, 0x26a07, 0x26a09, 0x26a0b,
|
||||
0x26a10, 0x26b0f, 0x27440, 0x27441, 0x27444, 0x27444, 0x27480, 0x274a2,
|
||||
0x274ac, 0x274c4, 0x274c8, 0x274da,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_cpr_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_gpucc_registers[] = {
|
||||
0x24000, 0x2400f, 0x24400, 0x2440f, 0x24800, 0x24805, 0x24c00, 0x24cff,
|
||||
0x25400, 0x25404, 0x25800, 0x25804, 0x25c00, 0x25c04, 0x26000, 0x26004,
|
||||
0x26400, 0x26405, 0x26414, 0x2641d, 0x2642a, 0x2642c, 0x2642e, 0x26432,
|
||||
0x26434, 0x26434, 0x26443, 0x26457, 0x26459, 0x2645d, 0x2645f, 0x26464,
|
||||
0x26477, 0x26479, 0x26489, 0x2648b, 0x2649a, 0x2649b, 0x264ad, 0x264af,
|
||||
0x264b1, 0x264b5, 0x264d6, 0x264d8, 0x264e7, 0x264e9, 0x264f9, 0x264fa,
|
||||
0x2650a, 0x2650d, 0x2651f, 0x26520, 0x2652d, 0x2652f, 0x2653e, 0x2653e,
|
||||
0x26540, 0x2654e, 0x26554, 0x26573, 0x26576, 0x26576, 0x26593, 0x26593,
|
||||
0x26600, 0x26616, 0x26620, 0x2662d, 0x26630, 0x26631, 0x26635, 0x26635,
|
||||
0x26637, 0x26637, 0x2663a, 0x2663a, 0x26642, 0x26642, 0x26656, 0x26658,
|
||||
0x2665b, 0x2665d, 0x2665f, 0x26662,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_gpucc_registers), 8));
|
||||
|
||||
static const u32 *gen7_17_0_external_core_regs[] = {
|
||||
gen7_17_0_gpucc_registers,
|
||||
gen7_17_0_cpr_registers,
|
||||
};
|
||||
|
||||
static const u32 gen7_17_0_debugbus_blocks[] = {
|
||||
A7XX_DBGBUS_CP_0_0,
|
||||
A7XX_DBGBUS_CP_0_1,
|
||||
A7XX_DBGBUS_RBBM,
|
||||
A7XX_DBGBUS_HLSQ,
|
||||
A7XX_DBGBUS_UCHE_0,
|
||||
A7XX_DBGBUS_TESS_BR,
|
||||
A7XX_DBGBUS_PC_BR,
|
||||
A7XX_DBGBUS_VFDP_BR,
|
||||
A7XX_DBGBUS_VPC_BR,
|
||||
A7XX_DBGBUS_TSE_BR,
|
||||
A7XX_DBGBUS_RAS_BR,
|
||||
A7XX_DBGBUS_VSC,
|
||||
A7XX_DBGBUS_COM_0,
|
||||
A7XX_DBGBUS_LRZ_BR,
|
||||
A7XX_DBGBUS_UFC_0,
|
||||
A7XX_DBGBUS_UFC_1,
|
||||
A7XX_DBGBUS_GMU_GX,
|
||||
A7XX_DBGBUS_DBGC,
|
||||
A7XX_DBGBUS_GPC_BR,
|
||||
A7XX_DBGBUS_LARC,
|
||||
A7XX_DBGBUS_HLSQ_SPTP,
|
||||
A7XX_DBGBUS_RB_0,
|
||||
A7XX_DBGBUS_RB_1,
|
||||
A7XX_DBGBUS_UCHE_WRAPPER,
|
||||
A7XX_DBGBUS_CCU_0,
|
||||
A7XX_DBGBUS_CCU_1,
|
||||
A7XX_DBGBUS_VFD_BR_0,
|
||||
A7XX_DBGBUS_VFD_BR_1,
|
||||
A7XX_DBGBUS_VFD_BR_2,
|
||||
A7XX_DBGBUS_VFD_BR_3,
|
||||
A7XX_DBGBUS_USP_0,
|
||||
A7XX_DBGBUS_USP_1,
|
||||
A7XX_DBGBUS_TP_0,
|
||||
A7XX_DBGBUS_TP_1,
|
||||
A7XX_DBGBUS_TP_2,
|
||||
A7XX_DBGBUS_TP_3,
|
||||
A7XX_DBGBUS_USPTP_0,
|
||||
A7XX_DBGBUS_USPTP_1,
|
||||
A7XX_DBGBUS_USPTP_2,
|
||||
A7XX_DBGBUS_USPTP_3,
|
||||
};
|
||||
|
||||
static const struct gen7_sel_reg gen7_17_0_rb_rac_sel = {
|
||||
.host_reg = REG_A6XX_RB_SUB_BLOCK_SEL_CNTL_HOST,
|
||||
.cd_reg = REG_A6XX_RB_SUB_BLOCK_SEL_CNTL_CD,
|
||||
.val = 0x0,
|
||||
};
|
||||
|
||||
static const struct gen7_sel_reg gen7_17_0_rb_rbp_sel = {
|
||||
.host_reg = REG_A6XX_RB_SUB_BLOCK_SEL_CNTL_HOST,
|
||||
.cd_reg = REG_A6XX_RB_SUB_BLOCK_SEL_CNTL_CD,
|
||||
.val = 0x9,
|
||||
};
|
||||
|
||||
static const u32 gen7_17_0_post_crashdumper_registers[] = {
|
||||
0x00535, 0x00535,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_post_crashdumper_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_gpu_registers[] = {
|
||||
0x00000, 0x00000, 0x00002, 0x00002, 0x00011, 0x00012, 0x00016, 0x0001b,
|
||||
0x0001f, 0x00032, 0x00038, 0x0003c, 0x00042, 0x00042, 0x00044, 0x00044,
|
||||
0x00047, 0x00047, 0x00049, 0x0004a, 0x0004c, 0x0004c, 0x00050, 0x00050,
|
||||
0x00056, 0x00056, 0x00073, 0x00075, 0x000ad, 0x000ae, 0x000b0, 0x000b0,
|
||||
0x000b4, 0x000b4, 0x000b8, 0x000b8, 0x000bc, 0x000bc, 0x000c0, 0x000c0,
|
||||
0x000c4, 0x000c4, 0x000c8, 0x000c8, 0x000cc, 0x000cc, 0x000d0, 0x000d0,
|
||||
0x000d4, 0x000d4, 0x000d8, 0x000d8, 0x000dc, 0x000dc, 0x000e0, 0x000e0,
|
||||
0x000e4, 0x000e4, 0x000e8, 0x000e8, 0x000ec, 0x000ec, 0x000f0, 0x000f0,
|
||||
0x000f4, 0x000f4, 0x000f8, 0x000f8, 0x00100, 0x00100, 0x00104, 0x0010b,
|
||||
0x0010f, 0x0011d, 0x0012f, 0x0012f, 0x00200, 0x0020d, 0x00215, 0x00243,
|
||||
0x00260, 0x00268, 0x00272, 0x00274, 0x00286, 0x00286, 0x0028a, 0x0028a,
|
||||
0x0028c, 0x0028c, 0x00300, 0x00401, 0x00500, 0x00500, 0x00507, 0x0050b,
|
||||
0x0050f, 0x0050f, 0x00511, 0x00511, 0x00533, 0x00534, 0x00540, 0x00555,
|
||||
0x00564, 0x00567, 0x00800, 0x00808, 0x00810, 0x00813, 0x00820, 0x00821,
|
||||
0x00823, 0x00827, 0x00830, 0x00834, 0x00840, 0x00841, 0x00843, 0x00847,
|
||||
0x0084f, 0x00886, 0x008a0, 0x008ab, 0x008c0, 0x008c0, 0x008c4, 0x008c5,
|
||||
0x008d0, 0x008dd, 0x008f0, 0x008f3, 0x00900, 0x00903, 0x00908, 0x00911,
|
||||
0x00928, 0x0093e, 0x00942, 0x0094d, 0x00980, 0x00984, 0x0098d, 0x0098f,
|
||||
0x009b0, 0x009b4, 0x009c2, 0x009c9, 0x009ce, 0x009d7, 0x00a00, 0x00a00,
|
||||
0x00a02, 0x00a03, 0x00a10, 0x00a4f, 0x00a67, 0x00a6c, 0x00a9c, 0x00a9f,
|
||||
0x00c00, 0x00c00, 0x00c02, 0x00c04, 0x00c06, 0x00c06, 0x00c10, 0x00cd9,
|
||||
0x00ce0, 0x00d0c, 0x00df0, 0x00df4, 0x00e01, 0x00e02, 0x00e07, 0x00e0e,
|
||||
0x00e10, 0x00e12, 0x00e17, 0x00e17, 0x00e19, 0x00e19, 0x00e1b, 0x00e2b,
|
||||
0x00e30, 0x00e32, 0x00e38, 0x00e3c,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_gpu_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_dbgc_registers[] = {
|
||||
0x00600, 0x0061c, 0x0061e, 0x00634, 0x00640, 0x0065a, 0x00679, 0x0067a,
|
||||
0x00699, 0x00699, 0x0069b, 0x0069e, 0x18400, 0x1841c, 0x1841e, 0x18434,
|
||||
0x18440, 0x1845c, 0x18479, 0x1847c, 0x18580, 0x18581,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_dbgc_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_noncontext_pipe_br_registers[] = {
|
||||
0x00887, 0x0088c, 0x08600, 0x08600, 0x08602, 0x08602, 0x08610, 0x0861b,
|
||||
0x08620, 0x08620, 0x08630, 0x08630, 0x08637, 0x08639, 0x08640, 0x08640,
|
||||
0x09600, 0x09600, 0x09602, 0x09603, 0x0960a, 0x09616, 0x09624, 0x0963a,
|
||||
0x09640, 0x09640, 0x09e00, 0x09e00, 0x09e02, 0x09e07, 0x09e0a, 0x09e16,
|
||||
0x09e19, 0x09e19, 0x09e1c, 0x09e1c, 0x09e20, 0x09e25, 0x09e30, 0x09e31,
|
||||
0x09e40, 0x09e51, 0x09e64, 0x09e64, 0x09e70, 0x09e72, 0x09e78, 0x09e79,
|
||||
0x09e80, 0x09fff, 0x0a600, 0x0a600, 0x0a603, 0x0a603, 0x0a610, 0x0a61f,
|
||||
0x0a630, 0x0a631, 0x0a638, 0x0a638,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_noncontext_pipe_br_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_noncontext_rb_rac_pipe_br_registers[] = {
|
||||
0x08e10, 0x08e1c, 0x08e20, 0x08e25, 0x08e51, 0x08e54,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_noncontext_rb_rac_pipe_br_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_noncontext_rb_rbp_pipe_br_registers[] = {
|
||||
0x08e01, 0x08e01, 0x08e04, 0x08e04, 0x08e06, 0x08e09, 0x08e0c, 0x08e0c,
|
||||
0x08e28, 0x08e28, 0x08e2c, 0x08e35, 0x08e3b, 0x08e3f, 0x08e50, 0x08e50,
|
||||
0x08e5b, 0x08e5d, 0x08e5f, 0x08e5f, 0x08e61, 0x08e61, 0x08e63, 0x08e65,
|
||||
0x08e68, 0x08e68, 0x08e70, 0x08e79, 0x08e80, 0x08e8f,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_noncontext_rb_rbp_pipe_br_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_pc_cluster_fe_pipe_br_registers[] = {
|
||||
0x09800, 0x09804, 0x09806, 0x0980a, 0x09810, 0x09811, 0x09884, 0x09886,
|
||||
0x09970, 0x09972, 0x09b00, 0x09b08,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_pc_cluster_fe_pipe_br_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_sp_cluster_sp_ps_pipe_lpac_hlsq_state_registers[] = {
|
||||
0x0aa40, 0x0aabf,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_sp_cluster_sp_ps_pipe_lpac_hlsq_state_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_sp_cluster_sp_ps_pipe_lpac_usptp_registers[] = {
|
||||
0x0aa40, 0x0aabf,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_sp_cluster_sp_ps_pipe_lpac_usptp_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_non_context_tpl1_pipe_none_usptp_registers[] = {
|
||||
0x0b602, 0x0b602, 0x0b604, 0x0b604, 0x0b608, 0x0b60c, 0x0b60f, 0x0b621,
|
||||
0x0b630, 0x0b633,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_non_context_tpl1_pipe_none_usptp_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_non_context_tpl1_pipe_br_usptp_registers[] = {
|
||||
0x0b600, 0x0b600,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_non_context_tpl1_pipe_br_usptp_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_tpl1_cluster_sp_vs_pipe_br_usptp_registers[] = {
|
||||
0x0b300, 0x0b307, 0x0b309, 0x0b309, 0x0b310, 0x0b310,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_tpl1_cluster_sp_vs_pipe_br_usptp_registers), 8));
|
||||
|
||||
static const u32 gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers[] = {
|
||||
0x0b180, 0x0b183, 0x0b190, 0x0b195, 0x0b2c0, 0x0b2d5, 0x0b300, 0x0b307,
|
||||
0x0b309, 0x0b309, 0x0b310, 0x0b310,
|
||||
UINT_MAX, UINT_MAX,
|
||||
};
|
||||
static_assert(IS_ALIGNED(sizeof(gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers), 8));
|
||||
|
||||
/* No BV pipe — gen7_0_0_* sub-arrays are shared from adreno_gen7_0_0_snapshot.h */
|
||||
static struct gen7_cluster_registers gen7_17_0_clusters[] = {
|
||||
{ A7XX_CLUSTER_NONE, PIPE_BR, STATE_NON_CONTEXT,
|
||||
gen7_17_0_noncontext_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_NONE, PIPE_BR, STATE_NON_CONTEXT,
|
||||
gen7_17_0_noncontext_rb_rac_pipe_br_registers, &gen7_17_0_rb_rac_sel, },
|
||||
{ A7XX_CLUSTER_NONE, PIPE_BR, STATE_NON_CONTEXT,
|
||||
gen7_17_0_noncontext_rb_rbp_pipe_br_registers, &gen7_17_0_rb_rbp_sel, },
|
||||
{ A7XX_CLUSTER_PS, PIPE_BR, STATE_FORCE_CTXT_0,
|
||||
gen7_0_0_rb_rac_cluster_ps_pipe_br_registers, &gen7_17_0_rb_rac_sel, },
|
||||
{ A7XX_CLUSTER_PS, PIPE_BR, STATE_FORCE_CTXT_1,
|
||||
gen7_0_0_rb_rac_cluster_ps_pipe_br_registers, &gen7_17_0_rb_rac_sel, },
|
||||
{ A7XX_CLUSTER_PS, PIPE_BR, STATE_FORCE_CTXT_0,
|
||||
gen7_0_0_rb_rbp_cluster_ps_pipe_br_registers, &gen7_17_0_rb_rbp_sel, },
|
||||
{ A7XX_CLUSTER_PS, PIPE_BR, STATE_FORCE_CTXT_1,
|
||||
gen7_0_0_rb_rbp_cluster_ps_pipe_br_registers, &gen7_17_0_rb_rbp_sel, },
|
||||
{ A7XX_CLUSTER_GRAS, PIPE_BR, STATE_FORCE_CTXT_0,
|
||||
gen7_0_0_gras_cluster_gras_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_GRAS, PIPE_BR, STATE_FORCE_CTXT_1,
|
||||
gen7_0_0_gras_cluster_gras_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_0,
|
||||
gen7_17_0_pc_cluster_fe_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_1,
|
||||
gen7_17_0_pc_cluster_fe_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_0,
|
||||
gen7_0_0_vfd_cluster_fe_pipe_bv_registers, },
|
||||
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_1,
|
||||
gen7_0_0_vfd_cluster_fe_pipe_bv_registers, },
|
||||
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_0,
|
||||
gen7_0_0_vpc_cluster_fe_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_1,
|
||||
gen7_0_0_vpc_cluster_fe_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_PC_VS, PIPE_BR, STATE_FORCE_CTXT_0,
|
||||
gen7_0_0_vpc_cluster_pc_vs_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_PC_VS, PIPE_BR, STATE_FORCE_CTXT_1,
|
||||
gen7_0_0_vpc_cluster_pc_vs_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_VPC_PS, PIPE_BR, STATE_FORCE_CTXT_0,
|
||||
gen7_0_0_vpc_cluster_vpc_ps_pipe_br_registers, },
|
||||
{ A7XX_CLUSTER_VPC_PS, PIPE_BR, STATE_FORCE_CTXT_1,
|
||||
gen7_0_0_vpc_cluster_vpc_ps_pipe_br_registers, },
|
||||
};
|
||||
|
||||
/* No BV pipe; 2 SPs, 2 USPTPs */
|
||||
static struct gen7_sptp_cluster_registers gen7_17_0_sptp_clusters[] = {
|
||||
{ A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, PIPE_BR, 0, A7XX_HLSQ_STATE,
|
||||
gen7_0_0_sp_noncontext_pipe_br_hlsq_state_registers, 0xae00 },
|
||||
{ A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, PIPE_BR, 0, A7XX_SP_TOP,
|
||||
gen7_0_0_sp_noncontext_pipe_br_sp_top_registers, 0xae00 },
|
||||
{ A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, PIPE_BR, 0, A7XX_USPTP,
|
||||
gen7_0_0_sp_noncontext_pipe_br_usptp_registers, 0xae00 },
|
||||
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX0_3D_CVS_REG, PIPE_BR, 0, A7XX_HLSQ_STATE,
|
||||
gen7_0_0_sp_cluster_sp_vs_pipe_br_hlsq_state_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX0_3D_CVS_REG, PIPE_BR, 0, A7XX_SP_TOP,
|
||||
gen7_0_0_sp_cluster_sp_vs_pipe_br_sp_top_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX0_3D_CVS_REG, PIPE_BR, 0, A7XX_USPTP,
|
||||
gen7_0_0_sp_cluster_sp_vs_pipe_br_usptp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX1_3D_CVS_REG, PIPE_BR, 1, A7XX_HLSQ_STATE,
|
||||
gen7_0_0_sp_cluster_sp_vs_pipe_br_hlsq_state_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX1_3D_CVS_REG, PIPE_BR, 1, A7XX_SP_TOP,
|
||||
gen7_0_0_sp_cluster_sp_vs_pipe_br_sp_top_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX1_3D_CVS_REG, PIPE_BR, 1, A7XX_USPTP,
|
||||
gen7_0_0_sp_cluster_sp_vs_pipe_br_usptp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_HLSQ_STATE,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_state_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_HLSQ_DP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_dp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_SP_TOP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_sp_top_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_USPTP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_usptp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_LPAC, 0, A7XX_HLSQ_STATE,
|
||||
gen7_17_0_sp_cluster_sp_ps_pipe_lpac_hlsq_state_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_LPAC, 0, A7XX_USPTP,
|
||||
gen7_17_0_sp_cluster_sp_ps_pipe_lpac_usptp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_HLSQ_STATE,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_state_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_HLSQ_DP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_dp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_SP_TOP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_sp_top_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_USPTP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_usptp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX2_3D_CPS_REG, PIPE_BR, 2, A7XX_HLSQ_DP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_dp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX2_3D_CPS_REG, PIPE_BR, 2, A7XX_SP_TOP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_sp_top_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX2_3D_CPS_REG, PIPE_BR, 2, A7XX_USPTP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_usptp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX3_3D_CPS_REG, PIPE_BR, 3, A7XX_HLSQ_DP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_dp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX3_3D_CPS_REG, PIPE_BR, 3, A7XX_SP_TOP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_sp_top_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX3_3D_CPS_REG, PIPE_BR, 3, A7XX_USPTP,
|
||||
gen7_0_0_sp_cluster_sp_ps_pipe_br_usptp_registers, 0xa800 },
|
||||
{ A7XX_CLUSTER_NONE, A7XX_TP0_NCTX_REG, PIPE_NONE, 0, A7XX_USPTP,
|
||||
gen7_17_0_non_context_tpl1_pipe_none_usptp_registers, 0xb600 },
|
||||
{ A7XX_CLUSTER_NONE, A7XX_TP0_NCTX_REG, PIPE_BR, 0, A7XX_USPTP,
|
||||
gen7_17_0_non_context_tpl1_pipe_br_usptp_registers, 0xb600 },
|
||||
{ A7XX_CLUSTER_SP_VS, A7XX_TP0_CTX0_3D_CVS_REG, PIPE_BR, 0, A7XX_USPTP,
|
||||
gen7_17_0_tpl1_cluster_sp_vs_pipe_br_usptp_registers, 0xb000 },
|
||||
{ A7XX_CLUSTER_SP_VS, A7XX_TP0_CTX1_3D_CVS_REG, PIPE_BR, 1, A7XX_USPTP,
|
||||
gen7_17_0_tpl1_cluster_sp_vs_pipe_br_usptp_registers, 0xb000 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_TP0_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_USPTP,
|
||||
gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers, 0xb000 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_TP0_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_USPTP,
|
||||
gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers, 0xb000 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_TP0_CTX2_3D_CPS_REG, PIPE_BR, 2, A7XX_USPTP,
|
||||
gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers, 0xb000 },
|
||||
{ A7XX_CLUSTER_SP_PS, A7XX_TP0_CTX3_3D_CPS_REG, PIPE_BR, 3, A7XX_USPTP,
|
||||
gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers, 0xb000 },
|
||||
};
|
||||
|
||||
static struct gen7_shader_block gen7_17_0_shader_blocks[] = {
|
||||
{ A7XX_TP0_TMO_DATA, 0x0200, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_TP0_SMO_DATA, 0x0080, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_TP0_MIPMAP_BASE_DATA, 0x03c0, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_INST_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_INST_DATA_1, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_LB_0_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_LB_1_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_LB_2_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_LB_3_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_LB_4_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_LB_5_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_CB_RAM, 0x0390, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_INST_TAG, 0x0090, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_TMO_TAG, 0x0080, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_SMO_TAG, 0x0080, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_STATE_DATA, 0x0040, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_HWAVE_RAM, 0x0100, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_SP_L0_INST_BUF, 0x0050, 2, 2, PIPE_BR, A7XX_USPTP },
|
||||
{ A7XX_HLSQ_CVS_BE_CTXT_BUF_RAM_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CPS_BE_CTXT_BUF_RAM_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_GFX_CVS_BE_CTXT_BUF_RAM, 0x0300, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_GFX_CPS_BE_CTXT_BUF_RAM, 0x0300, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CHUNK_CVS_RAM, 0x01c0, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CHUNK_CPS_RAM, 0x0300, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CHUNK_CVS_RAM_TAG, 0x0040, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CHUNK_CPS_RAM_TAG, 0x0040, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_ICB_CVS_CB_BASE_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_ICB_CPS_CB_BASE_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CVS_MISC_RAM, 0x0280, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CPS_MISC_RAM, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CPS_MISC_RAM_1, 0x0200, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_INST_RAM, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_GFX_CVS_CONST_RAM, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_GFX_CPS_CONST_RAM, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CVS_MISC_RAM_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_CPS_MISC_RAM_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_INST_RAM_TAG, 0x0080, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_GFX_CVS_CONST_RAM_TAG, 0x0064, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_GFX_CPS_CONST_RAM_TAG, 0x0064, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_INST_RAM_1, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_STPROC_META, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_BV_BE_META, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_DATAPATH_META, 0x0020, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_FRONTEND_META, 0x0040, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_INDIRECT_META, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
{ A7XX_HLSQ_BACKEND_META, 0x0040, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
|
||||
};
|
||||
|
||||
static struct gen7_reg_list gen7_17_0_reg_list[] = {
|
||||
{ gen7_17_0_gpu_registers, NULL },
|
||||
{ gen7_17_0_dbgc_registers, NULL },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
static const struct a6xx_indexed_registers gen7_17_0_cp_indexed_reglist[] = {
|
||||
{ "CP_SQE_STAT", REG_A6XX_CP_SQE_STAT_ADDR,
|
||||
REG_A6XX_CP_SQE_STAT_DATA, 0x40, NULL },
|
||||
{ "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR,
|
||||
REG_A6XX_CP_DRAW_STATE_DATA, 0x100, NULL },
|
||||
{ "CP_SQE_UCODE_DBG", REG_A6XX_CP_SQE_UCODE_DBG_ADDR,
|
||||
REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x8000, NULL },
|
||||
{ "CP_ROQ_DBG", REG_A6XX_CP_ROQ_DBG_ADDR,
|
||||
REG_A6XX_CP_ROQ_DBG_DATA, 0, a7xx_get_cp_roq_size },
|
||||
};
|
||||
|
||||
#endif /* __ADRENO_GEN7_17_0_SNAPSHOT_H */
|
||||
|
|
@ -357,6 +357,12 @@ int adreno_fault_handler(struct msm_gpu *gpu, unsigned long iova, int flags,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
valid_per_process_vm(struct msm_gpu *gpu, struct drm_gpuvm *vm)
|
||||
{
|
||||
return vm && (vm != gpu->vm);
|
||||
}
|
||||
|
||||
int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
|
||||
uint32_t param, uint64_t *value, uint32_t *len)
|
||||
{
|
||||
|
|
@ -415,12 +421,12 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
|
|||
*value = gpu->suspend_count;
|
||||
return 0;
|
||||
case MSM_PARAM_VA_START:
|
||||
if (vm == gpu->vm)
|
||||
if (!valid_per_process_vm(gpu, vm))
|
||||
return UERR(EINVAL, drm, "requires per-process pgtables");
|
||||
*value = vm->mm_start;
|
||||
return 0;
|
||||
case MSM_PARAM_VA_SIZE:
|
||||
if (vm == gpu->vm)
|
||||
if (!valid_per_process_vm(gpu, vm))
|
||||
return UERR(EINVAL, drm, "requires per-process pgtables");
|
||||
*value = vm->mm_range;
|
||||
return 0;
|
||||
|
|
@ -504,9 +510,11 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_context *ctx,
|
|||
if (!perfmon_capable())
|
||||
return UERR(EPERM, drm, "invalid permissions");
|
||||
return msm_context_set_sysprof(ctx, gpu, value);
|
||||
case MSM_PARAM_EN_VM_BIND:
|
||||
case MSM_PARAM_EN_VM_BIND: {
|
||||
guard(rwsem_read)(&ctx->ctxlock);
|
||||
|
||||
/* We can only support VM_BIND with per-process pgtables: */
|
||||
if (ctx->vm == gpu->vm)
|
||||
if (!gpu->funcs->create_private_vm)
|
||||
return UERR(EINVAL, drm, "requires per-process pgtables");
|
||||
|
||||
/*
|
||||
|
|
@ -519,6 +527,7 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_context *ctx,
|
|||
ctx->userspace_managed_vm = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return UERR(EINVAL, drm, "%s: invalid param: %u", gpu->name, param);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -562,6 +562,11 @@ static inline int adreno_is_x185(struct adreno_gpu *gpu)
|
|||
return gpu->info->chip_ids[0] == 0x43050c01;
|
||||
}
|
||||
|
||||
static inline int adreno_is_a722(struct adreno_gpu *gpu)
|
||||
{
|
||||
return gpu->info->chip_ids[0] == 0x43020100;
|
||||
}
|
||||
|
||||
static inline int adreno_is_a740_family(struct adreno_gpu *gpu)
|
||||
{
|
||||
if (WARN_ON_ONCE(!gpu->info))
|
||||
|
|
|
|||
|
|
@ -86,42 +86,42 @@ static const struct dpu_sspp_cfg kaanapali_sspp[] = {
|
|||
.name = "sspp_8", .id = SSPP_DMA0,
|
||||
.base = 0x97000, .len = 0x84,
|
||||
.features = DMA_SDM845_MASK_SDMA,
|
||||
.sblk = &dpu_dma_sblk,
|
||||
.sblk = &dpu_dma_sblk_v13,
|
||||
.xin_id = 1,
|
||||
.type = SSPP_TYPE_DMA,
|
||||
}, {
|
||||
.name = "sspp_9", .id = SSPP_DMA1,
|
||||
.base = 0xa0000, .len = 0x84,
|
||||
.features = DMA_SDM845_MASK_SDMA,
|
||||
.sblk = &dpu_dma_sblk,
|
||||
.sblk = &dpu_dma_sblk_v13,
|
||||
.xin_id = 5,
|
||||
.type = SSPP_TYPE_DMA,
|
||||
}, {
|
||||
.name = "sspp_10", .id = SSPP_DMA2,
|
||||
.base = 0xa9000, .len = 0x84,
|
||||
.features = DMA_SDM845_MASK_SDMA,
|
||||
.sblk = &dpu_dma_sblk,
|
||||
.sblk = &dpu_dma_sblk_v13,
|
||||
.xin_id = 9,
|
||||
.type = SSPP_TYPE_DMA,
|
||||
}, {
|
||||
.name = "sspp_11", .id = SSPP_DMA3,
|
||||
.base = 0xb2000, .len = 0x84,
|
||||
.features = DMA_SDM845_MASK_SDMA,
|
||||
.sblk = &dpu_dma_sblk,
|
||||
.sblk = &dpu_dma_sblk_v13,
|
||||
.xin_id = 13,
|
||||
.type = SSPP_TYPE_DMA,
|
||||
}, {
|
||||
.name = "sspp_12", .id = SSPP_DMA4,
|
||||
.base = 0xbb000, .len = 0x84,
|
||||
.features = DMA_CURSOR_SDM845_MASK_SDMA,
|
||||
.sblk = &dpu_dma_sblk,
|
||||
.sblk = &dpu_dma_sblk_v13,
|
||||
.xin_id = 14,
|
||||
.type = SSPP_TYPE_DMA,
|
||||
}, {
|
||||
.name = "sspp_13", .id = SSPP_DMA5,
|
||||
.base = 0xc4000, .len = 0x84,
|
||||
.features = DMA_CURSOR_SDM845_MASK_SDMA,
|
||||
.sblk = &dpu_dma_sblk,
|
||||
.sblk = &dpu_dma_sblk_v13,
|
||||
.xin_id = 15,
|
||||
.type = SSPP_TYPE_DMA,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ enum dpu_perf_mode {
|
|||
/**
|
||||
* dpu_core_perf_adjusted_mode_clk - Adjust given mode clock rate according to
|
||||
* the perf clock factor.
|
||||
* @crtc_clk_rate - Unadjusted mode clock rate
|
||||
* @mode_clk_rate: unadjusted mode clock rate
|
||||
* @perf_cfg: performance configuration
|
||||
*/
|
||||
u64 dpu_core_perf_adjusted_mode_clk(u64 mode_clk_rate,
|
||||
|
|
@ -394,6 +394,10 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
|
|||
|
||||
trace_dpu_core_perf_update_clk(kms->dev, !crtc->enabled, clk_rate);
|
||||
|
||||
/* If we're going offline, PM callbacks will disable the clocks instead */
|
||||
if (!clk_rate)
|
||||
return 0;
|
||||
|
||||
clk_rate = min(clk_rate, kms->perf.max_core_clk_rate);
|
||||
ret = dev_pm_opp_set_rate(&kms->pdev->dev, clk_rate);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -710,8 +710,7 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc,
|
|||
if (fb && MSM_FORMAT_IS_YUV(msm_framebuffer_format(fb)))
|
||||
topology->num_cdm++;
|
||||
} else if (disp_info->intf_type == INTF_DP) {
|
||||
if (msm_dp_is_yuv_420_enabled(priv->kms->dp[disp_info->h_tile_instance[0]],
|
||||
adj_mode))
|
||||
if (drm_mode_is_420_only(&connector->display_info, adj_mode))
|
||||
topology->num_cdm++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,6 +303,16 @@ static const u32 wb2_formats_rgb_yuv[] = {
|
|||
.num_formats = ARRAY_SIZE(plane_formats), \
|
||||
}
|
||||
|
||||
#define _DMA_SBLK_V13() \
|
||||
{ \
|
||||
.sspp_rec0_blk = {.name = "sspp_rec0", \
|
||||
.base = 0x1000, .len = 0x180,}, \
|
||||
.sspp_rec1_blk = {.name = "sspp_rec1", \
|
||||
.base = 0x3000, .len = 0x180,}, \
|
||||
.format_list = plane_formats, \
|
||||
.num_formats = ARRAY_SIZE(plane_formats), \
|
||||
}
|
||||
|
||||
static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = {
|
||||
.rot_maxheight = 1088,
|
||||
.rot_num_formats = ARRAY_SIZE(rotation_v2_formats),
|
||||
|
|
@ -353,6 +363,8 @@ static const struct dpu_sspp_sub_blks dpu_rgb_sblk = _RGB_SBLK();
|
|||
|
||||
static const struct dpu_sspp_sub_blks dpu_dma_sblk = _DMA_SBLK();
|
||||
|
||||
static const struct dpu_sspp_sub_blks dpu_dma_sblk_v13 = _DMA_SBLK_V13();
|
||||
|
||||
/*************************************************************
|
||||
* MIXER sub blocks config
|
||||
*************************************************************/
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ static int mdp4_kms_init(struct drm_device *dev)
|
|||
ret = mdp_kms_init(&mdp4_kms->base, &kms_funcs);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev->dev, "failed to init kms\n");
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
kms = priv->kms;
|
||||
|
|
@ -409,7 +409,7 @@ static int mdp4_kms_init(struct drm_device *dev)
|
|||
ret = regulator_enable(mdp4_kms->vdd);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev->dev, "failed to enable regulator vdd: %d\n", ret);
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +421,7 @@ static int mdp4_kms_init(struct drm_device *dev)
|
|||
DRM_DEV_ERROR(dev->dev, "unexpected MDP version: v%d.%d\n",
|
||||
major, minor);
|
||||
ret = -ENXIO;
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdp4_kms->rev = minor;
|
||||
|
|
@ -430,7 +430,7 @@ static int mdp4_kms_init(struct drm_device *dev)
|
|||
if (!mdp4_kms->lut_clk) {
|
||||
DRM_DEV_ERROR(dev->dev, "failed to get lut_clk\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
clk_set_rate(mdp4_kms->lut_clk, max_clk);
|
||||
}
|
||||
|
|
@ -452,7 +452,7 @@ static int mdp4_kms_init(struct drm_device *dev)
|
|||
vm = msm_kms_init_vm(mdp4_kms->dev, NULL);
|
||||
if (IS_ERR(vm)) {
|
||||
ret = PTR_ERR(vm);
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
kms->vm = vm;
|
||||
|
|
@ -460,22 +460,22 @@ static int mdp4_kms_init(struct drm_device *dev)
|
|||
ret = modeset_init(mdp4_kms);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev->dev, "modeset_init failed: %d\n", ret);
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC | MSM_BO_SCANOUT);
|
||||
mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC | MSM_BO_SCANOUT, NULL);
|
||||
if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
|
||||
ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
|
||||
DRM_DEV_ERROR(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
|
||||
mdp4_kms->blank_cursor_bo = NULL;
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = msm_gem_get_and_pin_iova(mdp4_kms->blank_cursor_bo, kms->vm,
|
||||
&mdp4_kms->blank_cursor_iova);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev->dev, "could not pin blank-cursor bo: %d\n", ret);
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev->mode_config.min_width = 0;
|
||||
|
|
@ -484,12 +484,6 @@ static int mdp4_kms_init(struct drm_device *dev)
|
|||
dev->mode_config.max_height = 2048;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (kms)
|
||||
mdp4_destroy(kms);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops mdp4_pm_ops = {
|
||||
|
|
|
|||
|
|
@ -517,7 +517,7 @@ static int mdp5_kms_init(struct drm_device *dev)
|
|||
ret = mdp_kms_init(&mdp5_kms->base, &kms_funcs);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(&pdev->dev, "failed to init kms\n");
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
config = mdp5_cfg_get_config(mdp5_kms->cfg);
|
||||
|
|
@ -540,7 +540,7 @@ static int mdp5_kms_init(struct drm_device *dev)
|
|||
vm = msm_kms_init_vm(mdp5_kms->dev, pdev->dev.parent);
|
||||
if (IS_ERR(vm)) {
|
||||
ret = PTR_ERR(vm);
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
kms->vm = vm;
|
||||
|
|
@ -550,7 +550,7 @@ static int mdp5_kms_init(struct drm_device *dev)
|
|||
ret = modeset_init(mdp5_kms);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(&pdev->dev, "modeset_init failed: %d\n", ret);
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev->mode_config.min_width = 0;
|
||||
|
|
@ -562,11 +562,6 @@ static int mdp5_kms_init(struct drm_device *dev)
|
|||
dev->vblank_disable_immediate = true;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
if (kms)
|
||||
mdp5_kms_destroy(kms);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mdp5_destroy(struct mdp5_kms *mdp5_kms)
|
||||
|
|
|
|||
|
|
@ -284,10 +284,8 @@ int msm_dp_audio_prepare(struct drm_bridge *bridge,
|
|||
* such cases check for connection status and bail out if not
|
||||
* connected.
|
||||
*/
|
||||
if (!msm_dp_display->power_on) {
|
||||
rc = -EINVAL;
|
||||
if (!msm_dp_display->power_on)
|
||||
goto end;
|
||||
}
|
||||
|
||||
audio = msm_dp_audio_get_data(msm_dp_display);
|
||||
if (IS_ERR(audio)) {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ struct msm_dp_ctrl_private {
|
|||
struct drm_device *drm_dev;
|
||||
struct device *dev;
|
||||
struct drm_dp_aux *aux;
|
||||
struct msm_dp_panel *panel;
|
||||
struct msm_dp_link *link;
|
||||
void __iomem *ahb_base;
|
||||
void __iomem *link_base;
|
||||
|
|
@ -202,7 +201,8 @@ static int msm_dp_aux_link_configure(struct drm_dp_aux *aux,
|
|||
/*
|
||||
* NOTE: resetting DP controller will also clear any pending HPD related interrupts
|
||||
*/
|
||||
void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl =
|
||||
container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
|
@ -217,10 +217,9 @@ void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
sw_reset &= ~DP_SW_RESET;
|
||||
msm_dp_write_ahb(ctrl, REG_DP_SW_RESET, sw_reset);
|
||||
|
||||
if (!ctrl->hw_revision) {
|
||||
if (!ctrl->hw_revision)
|
||||
ctrl->hw_revision = msm_dp_read_ahb(ctrl, REG_DP_HW_VERSION);
|
||||
ctrl->panel->hw_revision = ctrl->hw_revision;
|
||||
}
|
||||
panel->hw_revision = ctrl->hw_revision;
|
||||
}
|
||||
|
||||
static u32 msm_dp_ctrl_get_aux_interrupt(struct msm_dp_ctrl_private *ctrl)
|
||||
|
|
@ -388,26 +387,49 @@ void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
drm_dbg_dp(ctrl->drm_dev, "mainlink off\n");
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl)
|
||||
static void msm_dp_ctrl_config_ctrl_streams(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *msm_dp_panel)
|
||||
{
|
||||
u32 config = 0, tbd;
|
||||
const u8 *dpcd = ctrl->panel->dpcd;
|
||||
|
||||
/*
|
||||
* RMW: called from atomic_enable(), serialized by the DRM atomic framework.
|
||||
* Clear stream-specific fields before OR-ing to avoid bit accumulation.
|
||||
*/
|
||||
config = msm_dp_read_link(ctrl, REG_DP_CONFIGURATION_CTRL);
|
||||
config &= ~(DP_CONFIGURATION_CTRL_RGB_YUV_MASK |
|
||||
DP_CONFIGURATION_CTRL_BPC_MASK |
|
||||
DP_CONFIGURATION_CTRL_SEND_VSC);
|
||||
|
||||
if (msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420)
|
||||
config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
|
||||
|
||||
tbd = msm_dp_link_get_test_bits_depth(ctrl->link,
|
||||
msm_dp_panel->msm_dp_mode.bpp);
|
||||
|
||||
config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
|
||||
|
||||
if (msm_dp_panel->psr_cap.version)
|
||||
config |= DP_CONFIGURATION_CTRL_SEND_VSC;
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "stream DP_CONFIGURATION_CTRL=0x%x\n", config);
|
||||
|
||||
msm_dp_write_link(ctrl, REG_DP_CONFIGURATION_CTRL, config);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_config_ctrl_link(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
u32 config = 0;
|
||||
const u8 *dpcd = panel->dpcd;
|
||||
|
||||
/* Default-> LSCLK DIV: 1/4 LCLK */
|
||||
config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
|
||||
|
||||
if (ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420)
|
||||
config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
|
||||
|
||||
/* Scrambler reset enable */
|
||||
if (drm_dp_alternate_scrambler_reset_cap(dpcd))
|
||||
config |= DP_CONFIGURATION_CTRL_ASSR;
|
||||
|
||||
tbd = msm_dp_link_get_test_bits_depth(ctrl->link,
|
||||
ctrl->panel->msm_dp_mode.bpp);
|
||||
|
||||
config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
|
||||
|
||||
/* Num of Lanes */
|
||||
config |= ((ctrl->link->link_params.num_lanes - 1)
|
||||
<< DP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT);
|
||||
|
|
@ -421,10 +443,7 @@ static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl)
|
|||
config |= DP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN;
|
||||
config |= DP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK;
|
||||
|
||||
if (ctrl->panel->psr_cap.version)
|
||||
config |= DP_CONFIGURATION_CTRL_SEND_VSC;
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "DP_CONFIGURATION_CTRL=0x%x\n", config);
|
||||
drm_dbg_dp(ctrl->drm_dev, "link DP_CONFIGURATION_CTRL=0x%x\n", config);
|
||||
|
||||
msm_dp_write_link(ctrl, REG_DP_CONFIGURATION_CTRL, config);
|
||||
}
|
||||
|
|
@ -443,16 +462,13 @@ static void msm_dp_ctrl_lane_mapping(struct msm_dp_ctrl_private *ctrl)
|
|||
ln_mapping);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl)
|
||||
static void msm_dp_ctrl_config_misc1_misc0(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *msm_dp_panel)
|
||||
{
|
||||
u32 colorimetry_cfg, test_bits_depth, misc_val;
|
||||
|
||||
msm_dp_ctrl_lane_mapping(ctrl);
|
||||
msm_dp_setup_peripheral_flush(ctrl);
|
||||
|
||||
msm_dp_ctrl_config_ctrl(ctrl);
|
||||
|
||||
test_bits_depth = msm_dp_link_get_test_bits_depth(ctrl->link, ctrl->panel->msm_dp_mode.bpp);
|
||||
test_bits_depth = msm_dp_link_get_test_bits_depth(ctrl->link,
|
||||
msm_dp_panel->msm_dp_mode.bpp);
|
||||
colorimetry_cfg = msm_dp_link_get_colorimetry_config(ctrl->link);
|
||||
|
||||
misc_val = msm_dp_read_link(ctrl, REG_DP_MISC1_MISC0);
|
||||
|
|
@ -466,8 +482,16 @@ static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl
|
|||
|
||||
drm_dbg_dp(ctrl->drm_dev, "misc settings = 0x%x\n", misc_val);
|
||||
msm_dp_write_link(ctrl, REG_DP_MISC1_MISC0, misc_val);
|
||||
}
|
||||
|
||||
msm_dp_panel_timing_cfg(ctrl->panel, ctrl->msm_dp_ctrl.wide_bus_en);
|
||||
static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
msm_dp_ctrl_config_ctrl_streams(ctrl, panel);
|
||||
|
||||
msm_dp_ctrl_config_misc1_misc0(ctrl, panel);
|
||||
|
||||
msm_dp_panel_timing_cfg(panel, ctrl->msm_dp_ctrl.wide_bus_en);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1237,20 +1261,21 @@ static void _dp_ctrl_calc_tu(struct msm_dp_ctrl_private *ctrl,
|
|||
}
|
||||
|
||||
static void msm_dp_ctrl_calc_tu_parameters(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
struct msm_dp_vc_tu_mapping_table *tu_table)
|
||||
{
|
||||
struct msm_dp_tu_calc_input in;
|
||||
struct drm_display_mode *drm_mode;
|
||||
const struct drm_display_mode *drm_mode;
|
||||
|
||||
drm_mode = &ctrl->panel->msm_dp_mode.drm_mode;
|
||||
drm_mode = &panel->msm_dp_mode.drm_mode;
|
||||
|
||||
in.lclk = ctrl->link->link_params.rate / 1000;
|
||||
in.pclk_khz = drm_mode->clock;
|
||||
in.hactive = drm_mode->hdisplay;
|
||||
in.hporch = drm_mode->htotal - drm_mode->hdisplay;
|
||||
in.nlanes = ctrl->link->link_params.num_lanes;
|
||||
in.bpp = ctrl->panel->msm_dp_mode.bpp;
|
||||
in.pixel_enc = ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
|
||||
in.bpp = panel->msm_dp_mode.bpp;
|
||||
in.pixel_enc = panel->msm_dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
|
||||
in.dsc_en = 0;
|
||||
in.async_en = 0;
|
||||
in.fec_en = 0;
|
||||
|
|
@ -1260,14 +1285,15 @@ static void msm_dp_ctrl_calc_tu_parameters(struct msm_dp_ctrl_private *ctrl,
|
|||
_dp_ctrl_calc_tu(ctrl, &in, tu_table);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_setup_tr_unit(struct msm_dp_ctrl_private *ctrl)
|
||||
static void msm_dp_ctrl_setup_tr_unit(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
u32 msm_dp_tu = 0x0;
|
||||
u32 valid_boundary = 0x0;
|
||||
u32 valid_boundary2 = 0x0;
|
||||
struct msm_dp_vc_tu_mapping_table tu_calc_table;
|
||||
|
||||
msm_dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table);
|
||||
msm_dp_ctrl_calc_tu_parameters(ctrl, panel, &tu_calc_table);
|
||||
|
||||
msm_dp_tu |= tu_calc_table.tu_size_minus1;
|
||||
valid_boundary |= tu_calc_table.valid_boundary_link;
|
||||
|
|
@ -1419,6 +1445,7 @@ static int msm_dp_ctrl_set_pattern_state_bit(struct msm_dp_ctrl_private *ctrl,
|
|||
}
|
||||
|
||||
static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
int *training_step, enum drm_dp_phy dp_phy)
|
||||
{
|
||||
int delay_us;
|
||||
|
|
@ -1427,7 +1454,7 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
|
|||
int const maximum_retries = 4;
|
||||
|
||||
delay_us = drm_dp_read_clock_recovery_delay(ctrl->aux,
|
||||
ctrl->panel->dpcd, dp_phy, false);
|
||||
panel->dpcd, dp_phy, false);
|
||||
|
||||
msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0);
|
||||
|
||||
|
|
@ -1513,14 +1540,15 @@ static int msm_dp_ctrl_link_rate_down_shift(struct msm_dp_ctrl_private *ctrl)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl)
|
||||
static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
|
||||
if (ctrl->link->link_params.num_lanes == 1)
|
||||
return -1;
|
||||
|
||||
ctrl->link->link_params.num_lanes /= 2;
|
||||
ctrl->link->link_params.rate = ctrl->panel->link_info.rate;
|
||||
ctrl->link->link_params.rate = panel->link_info.rate;
|
||||
|
||||
ctrl->link->phy_params.p_level = 0;
|
||||
ctrl->link->phy_params.v_level = 0;
|
||||
|
|
@ -1529,6 +1557,7 @@ static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl)
|
|||
}
|
||||
|
||||
static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
enum drm_dp_phy dp_phy)
|
||||
{
|
||||
int delay_us;
|
||||
|
|
@ -1536,11 +1565,12 @@ static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl,
|
|||
msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE, dp_phy);
|
||||
|
||||
delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
|
||||
ctrl->panel->dpcd, dp_phy, false);
|
||||
panel->dpcd, dp_phy, false);
|
||||
fsleep(delay_us);
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
int *training_step, enum drm_dp_phy dp_phy)
|
||||
{
|
||||
int delay_us;
|
||||
|
|
@ -1551,16 +1581,16 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
|
|||
u8 link_status[DP_LINK_STATUS_SIZE];
|
||||
|
||||
delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
|
||||
ctrl->panel->dpcd, dp_phy, false);
|
||||
panel->dpcd, dp_phy, false);
|
||||
|
||||
msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0);
|
||||
|
||||
*training_step = DP_TRAINING_2;
|
||||
|
||||
if (drm_dp_tps4_supported(ctrl->panel->dpcd)) {
|
||||
if (drm_dp_tps4_supported(panel->dpcd)) {
|
||||
pattern = DP_TRAINING_PATTERN_4;
|
||||
state_ctrl_bit = 4;
|
||||
} else if (drm_dp_tps3_supported(ctrl->panel->dpcd)) {
|
||||
} else if (drm_dp_tps3_supported(panel->dpcd)) {
|
||||
pattern = DP_TRAINING_PATTERN_3;
|
||||
state_ctrl_bit = 3;
|
||||
} else {
|
||||
|
|
@ -1597,18 +1627,19 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
|
|||
}
|
||||
|
||||
static int msm_dp_ctrl_link_train_1_2(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
int *training_step, enum drm_dp_phy dp_phy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = msm_dp_ctrl_link_train_1(ctrl, training_step, dp_phy);
|
||||
ret = msm_dp_ctrl_link_train_1(ctrl, panel, training_step, dp_phy);
|
||||
if (ret) {
|
||||
DRM_ERROR("link training #1 on phy %d failed. ret=%d\n", dp_phy, ret);
|
||||
return ret;
|
||||
}
|
||||
drm_dbg_dp(ctrl->drm_dev, "link training #1 on phy %d successful\n", dp_phy);
|
||||
|
||||
ret = msm_dp_ctrl_link_train_2(ctrl, training_step, dp_phy);
|
||||
ret = msm_dp_ctrl_link_train_2(ctrl, panel, training_step, dp_phy);
|
||||
if (ret) {
|
||||
DRM_ERROR("link training #2 on phy %d failed. ret=%d\n", dp_phy, ret);
|
||||
return ret;
|
||||
|
|
@ -1619,16 +1650,18 @@ static int msm_dp_ctrl_link_train_1_2(struct msm_dp_ctrl_private *ctrl,
|
|||
}
|
||||
|
||||
static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
int *training_step)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
const u8 *dpcd = ctrl->panel->dpcd;
|
||||
const u8 *dpcd = panel->dpcd;
|
||||
u8 encoding[] = { 0, DP_SET_ANSI_8B10B };
|
||||
u8 assr;
|
||||
struct msm_dp_link_info link_info = {0};
|
||||
|
||||
msm_dp_ctrl_config_ctrl(ctrl);
|
||||
msm_dp_ctrl_config_ctrl_link(ctrl, panel);
|
||||
msm_dp_ctrl_config_ctrl_streams(ctrl, panel);
|
||||
|
||||
link_info.num_lanes = ctrl->link->link_params.num_lanes;
|
||||
link_info.rate = ctrl->link->link_params.rate;
|
||||
|
|
@ -1651,8 +1684,8 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
|
|||
for (i = ctrl->link->lttpr_count - 1; i >= 0; i--) {
|
||||
enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
|
||||
|
||||
ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, dp_phy);
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, dp_phy);
|
||||
ret = msm_dp_ctrl_link_train_1_2(ctrl, panel, training_step, dp_phy);
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, panel, dp_phy);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
|
@ -1663,7 +1696,7 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
|
|||
goto end;
|
||||
}
|
||||
|
||||
ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, DP_PHY_DPRX);
|
||||
ret = msm_dp_ctrl_link_train_1_2(ctrl, panel, training_step, DP_PHY_DPRX);
|
||||
if (ret) {
|
||||
DRM_ERROR("link training on sink failed. ret=%d\n", ret);
|
||||
goto end;
|
||||
|
|
@ -1676,6 +1709,7 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
|
|||
}
|
||||
|
||||
static int msm_dp_ctrl_setup_main_link(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
int *training_step)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
@ -1691,7 +1725,7 @@ static int msm_dp_ctrl_setup_main_link(struct msm_dp_ctrl_private *ctrl,
|
|||
* a link training pattern, we have to first do soft reset.
|
||||
*/
|
||||
|
||||
ret = msm_dp_ctrl_link_train(ctrl, training_step);
|
||||
ret = msm_dp_ctrl_link_train(ctrl, panel, training_step);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1790,11 +1824,12 @@ static void msm_dp_ctrl_link_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
str_on_off(ctrl->core_clks_on));
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_enable_mainlink_clocks(struct msm_dp_ctrl_private *ctrl)
|
||||
static int msm_dp_ctrl_enable_mainlink_clocks(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
int ret = 0;
|
||||
struct phy *phy = ctrl->phy;
|
||||
const u8 *dpcd = ctrl->panel->dpcd;
|
||||
const u8 *dpcd = panel->dpcd;
|
||||
|
||||
ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;
|
||||
ctrl->phy_opts.dp.link_rate = ctrl->link->link_params.rate / 100;
|
||||
|
|
@ -1846,13 +1881,14 @@ static void msm_dp_ctrl_psr_exit(struct msm_dp_ctrl_private *ctrl)
|
|||
msm_dp_write_link(ctrl, REG_PSR_CMD, cmd);
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl = container_of(msm_dp_ctrl,
|
||||
struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
u32 cfg;
|
||||
|
||||
if (!ctrl->panel->psr_cap.version)
|
||||
if (!panel->psr_cap.version)
|
||||
return;
|
||||
|
||||
/* enable PSR1 function */
|
||||
|
|
@ -1867,12 +1903,13 @@ void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
drm_dp_dpcd_write(ctrl->aux, DP_PSR_EN_CFG, &cfg, 1);
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl, bool enter)
|
||||
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel, bool enter)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl = container_of(msm_dp_ctrl,
|
||||
struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
||||
if (!ctrl->panel->psr_cap.version)
|
||||
if (!panel->psr_cap.version)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
|
@ -1942,7 +1979,8 @@ void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
phy_exit(phy);
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
|
||||
static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
struct phy *phy = ctrl->phy;
|
||||
int ret = 0;
|
||||
|
|
@ -1950,20 +1988,19 @@ static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
|
|||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;
|
||||
phy_configure(phy, &ctrl->phy_opts);
|
||||
|
||||
/*
|
||||
* Disable and re-enable the mainlink clock since the
|
||||
* link clock might have been adjusted as part of the
|
||||
* link maintenance.
|
||||
*/
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
|
||||
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
|
||||
|
||||
phy_power_off(phy);
|
||||
/* hw recommended delay before re-enabling clocks */
|
||||
msleep(20);
|
||||
|
||||
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl);
|
||||
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl, panel);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to enable mainlink clks. ret=%d\n", ret);
|
||||
return ret;
|
||||
|
|
@ -1972,7 +2009,8 @@ static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
|
||||
static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
struct phy *phy;
|
||||
|
||||
|
|
@ -1980,9 +2018,8 @@ static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
|
|||
|
||||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
|
||||
msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl);
|
||||
msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl, panel);
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
|
||||
|
||||
phy_power_off(phy);
|
||||
|
|
@ -1994,7 +2031,8 @@ static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
|
||||
static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
int ret = 0;
|
||||
int training_step = DP_TRAINING_NONE;
|
||||
|
|
@ -2004,11 +2042,11 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
|
|||
ctrl->link->phy_params.p_level = 0;
|
||||
ctrl->link->phy_params.v_level = 0;
|
||||
|
||||
ret = msm_dp_ctrl_setup_main_link(ctrl, &training_step);
|
||||
ret = msm_dp_ctrl_setup_main_link(ctrl, panel, &training_step);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, panel, DP_PHY_DPRX);
|
||||
|
||||
msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO);
|
||||
|
||||
|
|
@ -2152,7 +2190,43 @@ static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl)
|
|||
return success;
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl)
|
||||
static int msm_dp_ctrl_on_pixel_clk(struct msm_dp_ctrl_private *ctrl, unsigned long pixel_rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(ctrl->stream_clks_on))
|
||||
return 0;
|
||||
|
||||
ret = clk_prepare_enable(ctrl->pixel_clk);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ctrl->stream_clks_on = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
||||
if (ctrl->stream_clks_on) {
|
||||
clk_disable_unprepare(ctrl->pixel_clk);
|
||||
ctrl->stream_clks_on = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
int ret;
|
||||
unsigned long pixel_rate;
|
||||
|
|
@ -2168,38 +2242,27 @@ static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl
|
|||
* running. Add the global reset just before disabling the
|
||||
* link clocks and core clocks.
|
||||
*/
|
||||
msm_dp_ctrl_off(&ctrl->msm_dp_ctrl);
|
||||
msm_dp_ctrl_off_pixel_clk(&ctrl->msm_dp_ctrl);
|
||||
msm_dp_ctrl_off_link(&ctrl->msm_dp_ctrl, panel);
|
||||
|
||||
ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl);
|
||||
ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl, panel);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to enable DP link controller\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock;
|
||||
ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
|
||||
pixel_rate = panel->msm_dp_mode.drm_mode.clock;
|
||||
ret = msm_dp_ctrl_on_pixel_clk(ctrl, pixel_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ctrl->stream_clks_on) {
|
||||
drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n");
|
||||
} else {
|
||||
ret = clk_prepare_enable(ctrl->pixel_clk);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ctrl->stream_clks_on = true;
|
||||
}
|
||||
|
||||
msm_dp_ctrl_send_phy_test_pattern(ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
u32 sink_request = 0x0;
|
||||
|
|
@ -2214,14 +2277,14 @@ void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
|
||||
if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
|
||||
drm_dbg_dp(ctrl->drm_dev, "PHY_TEST_PATTERN request\n");
|
||||
if (msm_dp_ctrl_process_phy_test_request(ctrl)) {
|
||||
if (msm_dp_ctrl_process_phy_test_request(ctrl, panel)) {
|
||||
DRM_ERROR("process phy_test_req failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (sink_request & DP_LINK_STATUS_UPDATED) {
|
||||
if (msm_dp_ctrl_link_maintenance(ctrl)) {
|
||||
if (msm_dp_ctrl_link_maintenance(ctrl, panel)) {
|
||||
DRM_ERROR("LM failed: TEST_LINK_TRAINING\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -2229,7 +2292,7 @@ void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
|
||||
if (sink_request & DP_TEST_LINK_TRAINING) {
|
||||
msm_dp_link_send_test_response(ctrl->link);
|
||||
if (msm_dp_ctrl_link_maintenance(ctrl)) {
|
||||
if (msm_dp_ctrl_link_maintenance(ctrl, panel)) {
|
||||
DRM_ERROR("LM failed: TEST_LINK_TRAINING\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -2265,7 +2328,8 @@ static bool msm_dp_ctrl_channel_eq_ok(struct msm_dp_ctrl_private *ctrl)
|
|||
return drm_dp_channel_eq_ok(link_status, num_lanes);
|
||||
}
|
||||
|
||||
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
|
|
@ -2281,8 +2345,8 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
||||
rate = ctrl->panel->link_info.rate;
|
||||
pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock;
|
||||
rate = panel->link_info.rate;
|
||||
pixel_rate = panel->msm_dp_mode.drm_mode.clock;
|
||||
|
||||
msm_dp_ctrl_core_clk_enable(&ctrl->msm_dp_ctrl);
|
||||
|
||||
|
|
@ -2294,8 +2358,8 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
} else {
|
||||
ctrl->link->link_params.rate = rate;
|
||||
ctrl->link->link_params.num_lanes =
|
||||
ctrl->panel->link_info.num_lanes;
|
||||
if (ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420)
|
||||
panel->link_info.num_lanes;
|
||||
if (panel->msm_dp_mode.out_fmt_is_yuv_420)
|
||||
pixel_rate >>= 1;
|
||||
}
|
||||
|
||||
|
|
@ -2303,13 +2367,13 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
ctrl->link->link_params.rate, ctrl->link->link_params.num_lanes,
|
||||
pixel_rate);
|
||||
|
||||
rc = msm_dp_ctrl_enable_mainlink_clocks(ctrl);
|
||||
rc = msm_dp_ctrl_enable_mainlink_clocks(ctrl, panel);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
while (--link_train_max_retries) {
|
||||
training_step = DP_TRAINING_NONE;
|
||||
rc = msm_dp_ctrl_setup_main_link(ctrl, &training_step);
|
||||
rc = msm_dp_ctrl_setup_main_link(ctrl, panel, &training_step);
|
||||
if (rc == 0) {
|
||||
/* training completed successfully */
|
||||
break;
|
||||
|
|
@ -2328,7 +2392,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
* some lanes are ready,
|
||||
* reduce lane number
|
||||
*/
|
||||
rc = msm_dp_ctrl_link_lane_down_shift(ctrl);
|
||||
rc = msm_dp_ctrl_link_lane_down_shift(ctrl, panel);
|
||||
if (rc < 0) { /* lane == 1 already */
|
||||
/* end with failure */
|
||||
break;
|
||||
|
|
@ -2349,7 +2413,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
ctrl->link->link_params.num_lanes))
|
||||
rc = msm_dp_ctrl_link_rate_down_shift(ctrl);
|
||||
else
|
||||
rc = msm_dp_ctrl_link_lane_down_shift(ctrl);
|
||||
rc = msm_dp_ctrl_link_lane_down_shift(ctrl, panel);
|
||||
|
||||
if (rc < 0) {
|
||||
/* end with failure */
|
||||
|
|
@ -2357,10 +2421,10 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
}
|
||||
|
||||
/* stop link training before start re training */
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, panel, DP_PHY_DPRX);
|
||||
}
|
||||
|
||||
rc = msm_dp_ctrl_reinitialize_mainlink(ctrl);
|
||||
rc = msm_dp_ctrl_reinitialize_mainlink(ctrl, panel);
|
||||
if (rc) {
|
||||
DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n", rc);
|
||||
break;
|
||||
|
|
@ -2381,20 +2445,21 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
* link training failed
|
||||
* end txing train pattern here
|
||||
*/
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, panel, DP_PHY_DPRX);
|
||||
|
||||
msm_dp_ctrl_deinitialize_mainlink(ctrl);
|
||||
msm_dp_ctrl_deinitialize_mainlink(ctrl, panel);
|
||||
rc = -ECONNRESET;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_link_retrain(struct msm_dp_ctrl_private *ctrl)
|
||||
static int msm_dp_ctrl_link_retrain(struct msm_dp_ctrl_private *ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
int training_step = DP_TRAINING_NONE;
|
||||
|
||||
return msm_dp_ctrl_setup_main_link(ctrl, &training_step);
|
||||
return msm_dp_ctrl_setup_main_link(ctrl, panel, &training_step);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl,
|
||||
|
|
@ -2465,7 +2530,44 @@ static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl,
|
|||
msm_dp_write_link(ctrl, REG_DP_SOFTWARE_NVID, nvid);
|
||||
}
|
||||
|
||||
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train)
|
||||
int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
bool force_link_train)
|
||||
{
|
||||
int ret = 0;
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
|
||||
if (!msm_dp_ctrl)
|
||||
return -EINVAL;
|
||||
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d\n",
|
||||
ctrl->link->link_params.rate,
|
||||
ctrl->link->link_params.num_lanes);
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev,
|
||||
"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
|
||||
ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on);
|
||||
|
||||
if (!ctrl->link_clks_on) { /* link clk is off */
|
||||
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl, panel);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to start link clocks. ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl))
|
||||
msm_dp_ctrl_link_retrain(ctrl, panel);
|
||||
|
||||
/* stop txing train pattern to end link training */
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, panel, DP_PHY_DPRX);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel)
|
||||
{
|
||||
int ret = 0;
|
||||
bool mainlink_ready = false;
|
||||
|
|
@ -2478,49 +2580,17 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
|
|||
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
||||
pixel_rate = pixel_rate_orig = ctrl->panel->msm_dp_mode.drm_mode.clock;
|
||||
pixel_rate_orig = panel->msm_dp_mode.drm_mode.clock;
|
||||
pixel_rate = pixel_rate_orig;
|
||||
|
||||
if (msm_dp_ctrl->wide_bus_en || ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420)
|
||||
if (msm_dp_ctrl->wide_bus_en || panel->msm_dp_mode.out_fmt_is_yuv_420)
|
||||
pixel_rate >>= 1;
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
|
||||
ctrl->link->link_params.rate,
|
||||
ctrl->link->link_params.num_lanes, pixel_rate);
|
||||
drm_dbg_dp(ctrl->drm_dev, "pixel_rate=%lu\n", pixel_rate);
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev,
|
||||
"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
|
||||
ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on);
|
||||
|
||||
if (!ctrl->link_clks_on) { /* link clk is off */
|
||||
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to start link clocks. ret=%d\n", ret);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ctrl->stream_clks_on) {
|
||||
drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n");
|
||||
} else {
|
||||
ret = clk_prepare_enable(ctrl->pixel_clk);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
|
||||
goto end;
|
||||
}
|
||||
ctrl->stream_clks_on = true;
|
||||
}
|
||||
|
||||
if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl))
|
||||
msm_dp_ctrl_link_retrain(ctrl);
|
||||
|
||||
/* stop txing train pattern to end link training */
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
|
||||
ret = msm_dp_ctrl_on_pixel_clk(ctrl, pixel_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set up transfer unit values and set controller state to send
|
||||
|
|
@ -2528,16 +2598,20 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
|
|||
*/
|
||||
reinit_completion(&ctrl->video_comp);
|
||||
|
||||
msm_dp_ctrl_configure_source_params(ctrl);
|
||||
msm_dp_ctrl_lane_mapping(ctrl);
|
||||
msm_dp_setup_peripheral_flush(ctrl);
|
||||
msm_dp_ctrl_config_ctrl_link(ctrl, panel);
|
||||
|
||||
msm_dp_ctrl_configure_source_params(ctrl, panel);
|
||||
|
||||
msm_dp_ctrl_config_msa(ctrl,
|
||||
ctrl->link->link_params.rate,
|
||||
pixel_rate_orig,
|
||||
ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420);
|
||||
panel->msm_dp_mode.out_fmt_is_yuv_420);
|
||||
|
||||
msm_dp_panel_clear_dsc_dto(ctrl->panel);
|
||||
msm_dp_panel_clear_dsc_dto(panel);
|
||||
|
||||
msm_dp_ctrl_setup_tr_unit(ctrl);
|
||||
msm_dp_ctrl_setup_tr_unit(ctrl, panel);
|
||||
|
||||
msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO);
|
||||
|
||||
|
|
@ -2549,11 +2623,10 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
|
|||
drm_dbg_dp(ctrl->drm_dev,
|
||||
"mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
void msm_dp_ctrl_reinit_phy(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
struct phy *phy;
|
||||
|
|
@ -2561,29 +2634,13 @@ void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
phy = ctrl->phy;
|
||||
|
||||
msm_dp_panel_disable_vsc_sdp(ctrl->panel);
|
||||
|
||||
/* set dongle to D3 (power off) mode */
|
||||
msm_dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true);
|
||||
|
||||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
|
||||
if (ctrl->stream_clks_on) {
|
||||
clk_disable_unprepare(ctrl->pixel_clk);
|
||||
ctrl->stream_clks_on = false;
|
||||
}
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
|
||||
|
||||
phy_power_off(phy);
|
||||
|
||||
/* aux channel down, reinit phy */
|
||||
phy_exit(phy);
|
||||
phy_init(phy);
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
struct phy *phy;
|
||||
|
|
@ -2591,24 +2648,19 @@ void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
phy = ctrl->phy;
|
||||
|
||||
msm_dp_panel_disable_vsc_sdp(ctrl->panel);
|
||||
msm_dp_panel_disable_vsc_sdp(panel);
|
||||
|
||||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
|
||||
msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl);
|
||||
msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl, panel);
|
||||
|
||||
if (ctrl->stream_clks_on) {
|
||||
clk_disable_unprepare(ctrl->pixel_clk);
|
||||
ctrl->stream_clks_on = false;
|
||||
}
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
|
||||
|
||||
phy_power_off(phy);
|
||||
}
|
||||
|
||||
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
u32 isr;
|
||||
|
|
@ -2619,7 +2671,7 @@ irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
||||
if (ctrl->panel->psr_cap.version) {
|
||||
if (panel->psr_cap.version) {
|
||||
isr = msm_dp_ctrl_get_psr_interrupt(ctrl);
|
||||
|
||||
if (isr)
|
||||
|
|
@ -2708,7 +2760,7 @@ static int msm_dp_ctrl_clk_init(struct msm_dp_ctrl *msm_dp_ctrl)
|
|||
}
|
||||
|
||||
struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link,
|
||||
struct msm_dp_panel *panel, struct drm_dp_aux *aux,
|
||||
struct drm_dp_aux *aux,
|
||||
struct phy *phy,
|
||||
void __iomem *ahb_base,
|
||||
void __iomem *link_base)
|
||||
|
|
@ -2716,7 +2768,7 @@ struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link
|
|||
struct msm_dp_ctrl_private *ctrl;
|
||||
int ret;
|
||||
|
||||
if (!dev || !panel || !aux || !link) {
|
||||
if (!dev || !aux || !link) {
|
||||
DRM_ERROR("invalid input\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
|
@ -2744,7 +2796,6 @@ struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link
|
|||
init_completion(&ctrl->video_comp);
|
||||
|
||||
/* in parameters */
|
||||
ctrl->panel = panel;
|
||||
ctrl->aux = aux;
|
||||
ctrl->link = link;
|
||||
ctrl->dev = dev;
|
||||
|
|
|
|||
|
|
@ -16,28 +16,37 @@ struct msm_dp_ctrl {
|
|||
|
||||
struct phy;
|
||||
|
||||
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train);
|
||||
void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel);
|
||||
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel);
|
||||
int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel,
|
||||
bool force_link_train);
|
||||
void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel);
|
||||
void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel);
|
||||
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel);
|
||||
struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev,
|
||||
struct msm_dp_link *link,
|
||||
struct msm_dp_panel *panel,
|
||||
struct drm_dp_aux *aux,
|
||||
struct phy *phy,
|
||||
void __iomem *ahb_base,
|
||||
void __iomem *link_base);
|
||||
|
||||
void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel);
|
||||
void msm_dp_ctrl_phy_init(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_irq_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
|
||||
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl, bool enable);
|
||||
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel, bool enable);
|
||||
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl,
|
||||
struct msm_dp_panel *panel);
|
||||
|
||||
int msm_dp_ctrl_core_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
|
|
@ -45,4 +54,5 @@ void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl);
|
|||
void msm_dp_ctrl_enable_irq(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
void msm_dp_ctrl_disable_irq(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
|
||||
void msm_dp_ctrl_reinit_phy(struct msm_dp_ctrl *msm_dp_ctrl);
|
||||
#endif /* _DP_CTRL_H_ */
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ struct msm_dp_display_private {
|
|||
struct msm_dp_panel *panel;
|
||||
struct msm_dp_ctrl *ctrl;
|
||||
|
||||
struct msm_dp_display_mode msm_dp_mode;
|
||||
struct msm_dp msm_dp_display;
|
||||
|
||||
/* wait for audio signaling */
|
||||
|
|
@ -269,6 +268,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
|
|||
const struct drm_display_info *info = &connector->display_info;
|
||||
int rc = 0;
|
||||
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
const struct drm_edid *drm_edid = NULL;
|
||||
|
||||
rc = drm_dp_read_dpcd_caps(dp->aux, dpcd);
|
||||
if (rc)
|
||||
|
|
@ -276,10 +276,20 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
|
|||
|
||||
dp->link->lttpr_count = msm_dp_display_lttpr_init(dp, dpcd);
|
||||
|
||||
rc = msm_dp_panel_read_sink_caps(dp->panel, connector);
|
||||
rc = msm_dp_panel_read_link_caps(dp->panel, connector);
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
drm_edid = drm_edid_read_ddc(connector, &dp->aux->ddc);
|
||||
drm_edid_connector_update(connector, drm_edid);
|
||||
|
||||
if (!drm_edid) {
|
||||
DRM_ERROR("panel edid read failed\n");
|
||||
/* check edid read fail is due to unplug */
|
||||
if (!msm_dp_aux_is_link_connected(dp->aux))
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
msm_dp_link_process_request(dp->link);
|
||||
|
||||
if (!dp->msm_dp_display.is_edp)
|
||||
|
|
@ -291,7 +301,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
|
|||
dp->msm_dp_display.psr_supported = dp->panel->psr_cap.version && psr_enabled;
|
||||
|
||||
dp->audio_supported = info->has_audio;
|
||||
msm_dp_panel_handle_sink_request(dp->panel);
|
||||
msm_dp_panel_handle_sink_request(dp->panel, drm_edid);
|
||||
|
||||
/*
|
||||
* set sink to normal operation mode -- D0
|
||||
|
|
@ -302,6 +312,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
|
|||
msm_dp_link_reset_phy_params_vx_px(dp->link);
|
||||
|
||||
end:
|
||||
drm_edid_free(drm_edid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -348,7 +359,7 @@ static void msm_dp_display_host_init(struct msm_dp_display_private *dp)
|
|||
dp->phy_initialized);
|
||||
|
||||
msm_dp_ctrl_core_clk_enable(dp->ctrl);
|
||||
msm_dp_ctrl_reset(dp->ctrl);
|
||||
msm_dp_ctrl_reset(dp->ctrl, dp->panel);
|
||||
msm_dp_ctrl_enable_irq(dp->ctrl);
|
||||
msm_dp_aux_init(dp->aux);
|
||||
dp->core_initialized = true;
|
||||
|
|
@ -360,7 +371,7 @@ static void msm_dp_display_host_deinit(struct msm_dp_display_private *dp)
|
|||
dp->msm_dp_display.connector_type, dp->core_initialized,
|
||||
dp->phy_initialized);
|
||||
|
||||
msm_dp_ctrl_reset(dp->ctrl);
|
||||
msm_dp_ctrl_reset(dp->ctrl, dp->panel);
|
||||
msm_dp_ctrl_disable_irq(dp->ctrl);
|
||||
msm_dp_aux_deinit(dp->aux);
|
||||
msm_dp_ctrl_core_clk_disable(dp->ctrl);
|
||||
|
|
@ -381,7 +392,7 @@ static int msm_dp_display_handle_irq_hpd(struct msm_dp_display_private *dp)
|
|||
|
||||
drm_dbg_dp(dp->drm_dev, "%d\n", sink_request);
|
||||
|
||||
msm_dp_ctrl_handle_sink_request(dp->ctrl);
|
||||
msm_dp_ctrl_handle_sink_request(dp->ctrl, dp->panel);
|
||||
|
||||
if (sink_request & DP_TEST_LINK_VIDEO_PATTERN)
|
||||
msm_dp_display_handle_video_request(dp);
|
||||
|
|
@ -453,7 +464,7 @@ static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp)
|
|||
|
||||
/* Don't forget modes for eDP */
|
||||
if (!dp->msm_dp_display.is_edp)
|
||||
msm_dp_panel_unplugged(dp->panel, dp->msm_dp_display.connector);
|
||||
drm_edid_connector_update(dp->msm_dp_display.connector, NULL);
|
||||
|
||||
/* triggered by irq_hdp with sink_count = 0 */
|
||||
if (dp->link->sink_count == 0)
|
||||
|
|
@ -515,7 +526,6 @@ static int msm_dp_irq_hpd_handle(struct msm_dp_display_private *dp)
|
|||
static void msm_dp_display_deinit_sub_modules(struct msm_dp_display_private *dp)
|
||||
{
|
||||
msm_dp_audio_put(dp->audio);
|
||||
msm_dp_panel_put(dp->panel);
|
||||
msm_dp_aux_put(dp->aux);
|
||||
}
|
||||
|
||||
|
|
@ -560,13 +570,13 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp)
|
|||
goto error_link;
|
||||
}
|
||||
|
||||
dp->ctrl = msm_dp_ctrl_get(dev, dp->link, dp->panel, dp->aux,
|
||||
phy, dp->ahb_base, dp->link_base);
|
||||
dp->ctrl = msm_dp_ctrl_get(dev, dp->link, dp->aux,
|
||||
phy, dp->ahb_base, dp->link_base);
|
||||
if (IS_ERR(dp->ctrl)) {
|
||||
rc = PTR_ERR(dp->ctrl);
|
||||
DRM_ERROR("failed to initialize ctrl, rc = %d\n", rc);
|
||||
dp->ctrl = NULL;
|
||||
goto error_ctrl;
|
||||
goto error_link;
|
||||
}
|
||||
|
||||
dp->audio = msm_dp_audio_get(dp->msm_dp_display.pdev, dp->link_base);
|
||||
|
|
@ -574,13 +584,11 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp)
|
|||
rc = PTR_ERR(dp->audio);
|
||||
pr_err("failed to initialize audio, rc = %d\n", rc);
|
||||
dp->audio = NULL;
|
||||
goto error_ctrl;
|
||||
goto error_link;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
error_ctrl:
|
||||
msm_dp_panel_put(dp->panel);
|
||||
error_link:
|
||||
msm_dp_aux_put(dp->aux);
|
||||
error:
|
||||
|
|
@ -588,20 +596,64 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp)
|
|||
}
|
||||
|
||||
static int msm_dp_display_set_mode(struct msm_dp *msm_dp_display,
|
||||
struct msm_dp_display_mode *mode)
|
||||
const struct drm_display_mode *adjusted_mode,
|
||||
struct msm_dp_panel *msm_dp_panel)
|
||||
{
|
||||
struct msm_dp_display_private *dp;
|
||||
u32 bpp;
|
||||
|
||||
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
|
||||
|
||||
drm_mode_copy(&dp->panel->msm_dp_mode.drm_mode, &mode->drm_mode);
|
||||
dp->panel->msm_dp_mode.bpp = mode->bpp;
|
||||
dp->panel->msm_dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420;
|
||||
msm_dp_panel_init_panel_info(dp->panel);
|
||||
if (msm_dp_display_check_video_test(msm_dp_display))
|
||||
bpp = msm_dp_display_get_test_bpp(msm_dp_display);
|
||||
else
|
||||
bpp = msm_dp_panel->connector->display_info.bpc * 3;
|
||||
|
||||
msm_dp_panel_init_panel_info(msm_dp_panel, adjusted_mode, bpp ? bpp : 24);
|
||||
|
||||
/* populate wide_bus_support to different layers */
|
||||
dp->ctrl->wide_bus_en =
|
||||
msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420 ? false : dp->wide_bus_supported;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_dp_display_enable(struct msm_dp_display_private *dp, bool force_link_train)
|
||||
static int msm_dp_display_prepare_link(struct msm_dp_display_private *dp)
|
||||
{
|
||||
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
|
||||
int rc = 0;
|
||||
bool force_link_train = false;
|
||||
|
||||
drm_dbg_dp(dp->drm_dev, "sink_count=%d\n", dp->link->sink_count);
|
||||
|
||||
if (msm_dp_display->is_edp)
|
||||
msm_dp_hpd_plug_handle(dp);
|
||||
|
||||
rc = pm_runtime_resume_and_get(&msm_dp_display->pdev->dev);
|
||||
if (rc) {
|
||||
DRM_ERROR("failed to pm_runtime_resume\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (dp->link->sink_count == 0)
|
||||
return -ENOTCONN;
|
||||
|
||||
if (!msm_dp_display->power_on) {
|
||||
msm_dp_display_host_phy_init(dp);
|
||||
force_link_train = true;
|
||||
}
|
||||
|
||||
rc = msm_dp_ctrl_on_link(dp->ctrl, dp->panel);
|
||||
if (rc) {
|
||||
DRM_ERROR("Failed link training (rc=%d)\n", rc);
|
||||
// TODO: schedule drm_connector_set_link_status_property()
|
||||
return rc;
|
||||
}
|
||||
|
||||
return msm_dp_ctrl_prepare_stream_on(dp->ctrl, dp->panel, force_link_train);
|
||||
}
|
||||
|
||||
static int msm_dp_display_enable(struct msm_dp_display_private *dp,
|
||||
struct msm_dp_panel *msm_dp_panel)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
|
||||
|
|
@ -612,7 +664,7 @@ static int msm_dp_display_enable(struct msm_dp_display_private *dp, bool force_l
|
|||
return 0;
|
||||
}
|
||||
|
||||
rc = msm_dp_ctrl_on_stream(dp->ctrl, force_link_train);
|
||||
rc = msm_dp_ctrl_on_stream(dp->ctrl, msm_dp_panel);
|
||||
if (!rc)
|
||||
msm_dp_display->power_on = true;
|
||||
|
||||
|
|
@ -637,18 +689,15 @@ static int msm_dp_display_post_enable(struct msm_dp *msm_dp_display)
|
|||
msm_dp_display_handle_plugged_change(msm_dp_display, true);
|
||||
|
||||
if (msm_dp_display->psr_supported)
|
||||
msm_dp_ctrl_config_psr(dp->ctrl);
|
||||
msm_dp_ctrl_config_psr(dp->ctrl, dp->panel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_dp_display_disable(struct msm_dp_display_private *dp)
|
||||
static void msm_dp_display_audio_notify_disable(struct msm_dp_display_private *dp)
|
||||
{
|
||||
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
|
||||
|
||||
if (!msm_dp_display->power_on)
|
||||
return 0;
|
||||
|
||||
/* wait only if audio was enabled */
|
||||
if (msm_dp_display->audio_enabled) {
|
||||
/* signal the disconnect event */
|
||||
|
|
@ -659,21 +708,31 @@ static int msm_dp_display_disable(struct msm_dp_display_private *dp)
|
|||
}
|
||||
|
||||
msm_dp_display->audio_enabled = false;
|
||||
}
|
||||
|
||||
if (dp->link->sink_count == 0) {
|
||||
/*
|
||||
* irq_hpd with sink_count = 0
|
||||
* hdmi unplugged out of dongle
|
||||
*/
|
||||
msm_dp_ctrl_off_link_stream(dp->ctrl);
|
||||
} else {
|
||||
/*
|
||||
* unplugged interrupt
|
||||
* dongle unplugged out of DUT
|
||||
*/
|
||||
msm_dp_ctrl_off(dp->ctrl);
|
||||
static int msm_dp_display_disable(struct msm_dp_display_private *dp,
|
||||
struct msm_dp_panel *msm_dp_panel)
|
||||
{
|
||||
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
|
||||
|
||||
if (!msm_dp_display->power_on)
|
||||
return 0;
|
||||
|
||||
msm_dp_panel_disable_vsc_sdp(msm_dp_panel);
|
||||
|
||||
msm_dp_ctrl_off_pixel_clk(dp->ctrl);
|
||||
|
||||
/* dongle is still connected but sinks are disconnected */
|
||||
if (dp->link->sink_count == 0)
|
||||
msm_dp_link_psm_config(dp->link, &msm_dp_panel->link_info, true);
|
||||
|
||||
msm_dp_ctrl_off_link(dp->ctrl, msm_dp_panel);
|
||||
|
||||
if (dp->link->sink_count == 0)
|
||||
/* re-init the PHY so that we can listen to Dongle disconnect */
|
||||
msm_dp_ctrl_reinit_phy(dp->ctrl);
|
||||
else
|
||||
msm_dp_display_host_phy_exit(dp);
|
||||
}
|
||||
|
||||
msm_dp_display->power_on = false;
|
||||
|
||||
|
|
@ -682,24 +741,22 @@ static int msm_dp_display_disable(struct msm_dp_display_private *dp)
|
|||
}
|
||||
|
||||
/**
|
||||
* msm_dp_bridge_mode_valid - callback to determine if specified mode is valid
|
||||
* @bridge: Pointer to drm bridge structure
|
||||
* msm_dp_display_mode_valid - callback to determine if specified mode is valid
|
||||
* @dp: Pointer to dp display structure
|
||||
* @info: display info
|
||||
* @mode: Pointer to drm mode structure
|
||||
* Returns: Validity status for specified mode
|
||||
*/
|
||||
enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_info *info,
|
||||
const struct drm_display_mode *mode)
|
||||
enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp,
|
||||
const struct drm_display_info *info,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
const u32 num_components = 3, default_bpp = 24;
|
||||
struct msm_dp_display_private *msm_dp_display;
|
||||
struct msm_dp_link_info *link_info;
|
||||
u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;
|
||||
struct msm_dp *dp;
|
||||
int mode_pclk_khz = mode->clock;
|
||||
|
||||
dp = to_dp_bridge(bridge)->msm_dp_display;
|
||||
bool is_yuv_420;
|
||||
|
||||
if (!dp || !mode_pclk_khz || !dp->connector) {
|
||||
DRM_ERROR("invalid params\n");
|
||||
|
|
@ -709,9 +766,16 @@ enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
|
|||
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
|
||||
link_info = &msm_dp_display->panel->link_info;
|
||||
|
||||
if ((drm_mode_is_420_only(&dp->connector->display_info, mode) &&
|
||||
msm_dp_display->panel->vsc_sdp_supported) ||
|
||||
msm_dp_wide_bus_available(dp))
|
||||
is_yuv_420 = drm_mode_is_420_only(&dp->connector->display_info, mode);
|
||||
|
||||
/*
|
||||
* YUV 420 is carried over DP by signalling the colorimetry through a
|
||||
* VSC SDP, so a 420-only mode cannot be driven without VSC SDP support.
|
||||
*/
|
||||
if (is_yuv_420 && !msm_dp_display->panel->vsc_sdp_supported)
|
||||
return MODE_NO_420;
|
||||
|
||||
if (is_yuv_420 || msm_dp_display->wide_bus_supported)
|
||||
mode_pclk_khz /= 2;
|
||||
|
||||
if (mode_pclk_khz > DP_MAX_PIXEL_CLK_KHZ)
|
||||
|
|
@ -744,8 +808,7 @@ int msm_dp_display_get_modes(struct msm_dp *dp)
|
|||
|
||||
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
|
||||
|
||||
return msm_dp_panel_get_modes(msm_dp_display->panel,
|
||||
dp->connector);
|
||||
return drm_edid_connector_add_modes(msm_dp_display->panel->connector);
|
||||
}
|
||||
|
||||
bool msm_dp_display_check_video_test(struct msm_dp *dp)
|
||||
|
|
@ -808,7 +871,7 @@ void msm_dp_display_set_psr(struct msm_dp *msm_dp_display, bool enter)
|
|||
}
|
||||
|
||||
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
|
||||
msm_dp_ctrl_set_psr(dp->ctrl, enter);
|
||||
msm_dp_ctrl_set_psr(dp->ctrl, dp->panel, enter);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -918,7 +981,7 @@ static irqreturn_t msm_dp_display_irq_handler(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/* DP controller isr */
|
||||
ret |= msm_dp_ctrl_isr(dp->ctrl);
|
||||
ret |= msm_dp_ctrl_isr(dp->ctrl, dp->panel);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1277,22 +1340,10 @@ void __exit msm_dp_unregister(void)
|
|||
platform_driver_unregister(&msm_dp_display_driver);
|
||||
}
|
||||
|
||||
bool msm_dp_is_yuv_420_enabled(const struct msm_dp *msm_dp_display,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct msm_dp_display_private *dp;
|
||||
const struct drm_display_info *info;
|
||||
|
||||
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
|
||||
info = &msm_dp_display->connector->display_info;
|
||||
|
||||
return dp->panel->vsc_sdp_supported && drm_mode_is_420_only(info, mode);
|
||||
}
|
||||
|
||||
bool msm_dp_needs_periph_flush(const struct msm_dp *msm_dp_display,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
return msm_dp_is_yuv_420_enabled(msm_dp_display, mode);
|
||||
return drm_mode_is_420_only(&msm_dp_display->connector->display_info, mode);
|
||||
}
|
||||
|
||||
bool msm_dp_wide_bus_available(const struct msm_dp *msm_dp_display)
|
||||
|
|
@ -1301,7 +1352,7 @@ bool msm_dp_wide_bus_available(const struct msm_dp *msm_dp_display)
|
|||
|
||||
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
|
||||
|
||||
if (dp->msm_dp_mode.out_fmt_is_yuv_420)
|
||||
if (dp->panel->msm_dp_mode.out_fmt_is_yuv_420)
|
||||
return false;
|
||||
|
||||
return dp->wide_bus_supported;
|
||||
|
|
@ -1352,66 +1403,57 @@ int msm_dp_modeset_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state)
|
||||
void msm_dp_display_atomic_pre_enable(struct msm_dp *msm_dp_display,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
|
||||
int rc = 0;
|
||||
struct msm_dp_display_private *msm_dp_display;
|
||||
bool force_link_train = false;
|
||||
struct msm_dp_display_private *dp;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
|
||||
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
|
||||
if (!msm_dp_display->msm_dp_mode.drm_mode.clock) {
|
||||
DRM_ERROR("invalid params\n");
|
||||
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
|
||||
|
||||
crtc = drm_atomic_get_new_crtc_for_encoder(state, msm_dp_display->bridge->encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
}
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
|
||||
if (dp->is_edp)
|
||||
msm_dp_hpd_plug_handle(msm_dp_display);
|
||||
|
||||
if (pm_runtime_resume_and_get(&dp->pdev->dev)) {
|
||||
DRM_ERROR("failed to pm_runtime_resume\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (msm_dp_display->link->sink_count == 0)
|
||||
return;
|
||||
|
||||
rc = msm_dp_display_set_mode(dp, &msm_dp_display->msm_dp_mode);
|
||||
if (rc) {
|
||||
DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dp->power_on) {
|
||||
msm_dp_display_host_phy_init(msm_dp_display);
|
||||
force_link_train = true;
|
||||
}
|
||||
|
||||
rc = msm_dp_ctrl_on_link(msm_dp_display->ctrl);
|
||||
if (rc) {
|
||||
DRM_ERROR("Failed link training (rc=%d)\n", rc);
|
||||
// TODO: schedule drm_connector_set_link_status_property()
|
||||
return;
|
||||
}
|
||||
|
||||
msm_dp_display_enable(msm_dp_display, force_link_train);
|
||||
|
||||
rc = msm_dp_display_post_enable(dp);
|
||||
if (rc) {
|
||||
DRM_ERROR("DP display post enable failed, rc=%d\n", rc);
|
||||
msm_dp_display_disable(msm_dp_display);
|
||||
}
|
||||
|
||||
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
|
||||
/*
|
||||
* The DPU encoder's .atomic_enable() reads the mode's YUV420 / wide bus
|
||||
* state and runs before the bridge's .atomic_enable(), so the mode must
|
||||
* be programmed here, in .atomic_pre_enable().
|
||||
*/
|
||||
msm_dp_display_set_mode(msm_dp_display, &crtc_state->adjusted_mode, dp->panel);
|
||||
}
|
||||
|
||||
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
|
||||
void msm_dp_display_atomic_enable(struct msm_dp *msm_dp_display,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
|
||||
int rc = 0;
|
||||
struct msm_dp_display_private *dp;
|
||||
|
||||
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
|
||||
|
||||
rc = msm_dp_display_prepare_link(dp);
|
||||
if (rc) {
|
||||
DRM_ERROR("DP display prepare failed, rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = msm_dp_display_enable(dp, dp->panel);
|
||||
if (rc)
|
||||
DRM_ERROR("DP display enable failed, rc=%d\n", rc);
|
||||
|
||||
rc = msm_dp_display_post_enable(msm_dp_display);
|
||||
if (rc) {
|
||||
DRM_ERROR("DP display post enable failed, rc=%d\n", rc);
|
||||
msm_dp_display_disable(dp, dp->panel);
|
||||
}
|
||||
|
||||
drm_dbg_dp(msm_dp_display->drm_dev, "type=%d Done\n", msm_dp_display->connector_type);
|
||||
}
|
||||
|
||||
void msm_dp_display_atomic_disable(struct msm_dp *dp)
|
||||
{
|
||||
struct msm_dp_display_private *msm_dp_display;
|
||||
|
||||
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
|
||||
|
|
@ -1419,11 +1461,17 @@ void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
|
|||
msm_dp_ctrl_push_idle(msm_dp_display->ctrl);
|
||||
}
|
||||
|
||||
void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state)
|
||||
static void msm_dp_display_unprepare(struct msm_dp_display_private *dp)
|
||||
{
|
||||
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
|
||||
|
||||
pm_runtime_put_sync(&msm_dp_display->pdev->dev);
|
||||
|
||||
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", msm_dp_display->connector_type);
|
||||
}
|
||||
|
||||
void msm_dp_display_atomic_post_disable(struct msm_dp *dp)
|
||||
{
|
||||
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
|
||||
struct msm_dp_display_private *msm_dp_display;
|
||||
|
||||
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
|
||||
|
|
@ -1431,50 +1479,11 @@ void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
|
|||
if (dp->is_edp)
|
||||
msm_dp_hpd_unplug_handle(msm_dp_display);
|
||||
|
||||
msm_dp_display_disable(msm_dp_display);
|
||||
msm_dp_display_audio_notify_disable(msm_dp_display);
|
||||
|
||||
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
|
||||
msm_dp_display_disable(msm_dp_display, msm_dp_display->panel);
|
||||
|
||||
pm_runtime_put_sync(&dp->pdev->dev);
|
||||
}
|
||||
|
||||
void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
|
||||
struct msm_dp_display_private *msm_dp_display;
|
||||
struct msm_dp_panel *msm_dp_panel;
|
||||
|
||||
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
|
||||
msm_dp_panel = msm_dp_display->panel;
|
||||
|
||||
memset(&msm_dp_display->msm_dp_mode, 0x0, sizeof(struct msm_dp_display_mode));
|
||||
|
||||
if (msm_dp_display_check_video_test(dp))
|
||||
msm_dp_display->msm_dp_mode.bpp = msm_dp_display_get_test_bpp(dp);
|
||||
else /* Default num_components per pixel = 3 */
|
||||
msm_dp_display->msm_dp_mode.bpp = dp->connector->display_info.bpc * 3;
|
||||
|
||||
if (!msm_dp_display->msm_dp_mode.bpp)
|
||||
msm_dp_display->msm_dp_mode.bpp = 24; /* Default bpp */
|
||||
|
||||
drm_mode_copy(&msm_dp_display->msm_dp_mode.drm_mode, adjusted_mode);
|
||||
|
||||
msm_dp_display->msm_dp_mode.v_active_low =
|
||||
!!(msm_dp_display->msm_dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC);
|
||||
|
||||
msm_dp_display->msm_dp_mode.h_active_low =
|
||||
!!(msm_dp_display->msm_dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
|
||||
|
||||
msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 =
|
||||
drm_mode_is_420_only(&dp->connector->display_info, adjusted_mode) &&
|
||||
msm_dp_panel->vsc_sdp_supported;
|
||||
|
||||
/* populate wide_bus_support to different layers */
|
||||
msm_dp_display->ctrl->wide_bus_en =
|
||||
msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 ? false : msm_dp_display->wide_bus_supported;
|
||||
msm_dp_display_unprepare(msm_dp_display);
|
||||
}
|
||||
|
||||
void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge)
|
||||
|
|
|
|||
|
|
@ -33,5 +33,14 @@ void msm_dp_display_signal_audio_start(struct msm_dp *msm_dp_display);
|
|||
void msm_dp_display_signal_audio_complete(struct msm_dp *msm_dp_display);
|
||||
void msm_dp_display_set_psr(struct msm_dp *dp, bool enter);
|
||||
void msm_dp_display_debugfs_init(struct msm_dp *msm_dp_display, struct dentry *dentry, bool is_edp);
|
||||
void msm_dp_display_atomic_post_disable(struct msm_dp *dp_display);
|
||||
void msm_dp_display_atomic_disable(struct msm_dp *dp_display);
|
||||
void msm_dp_display_atomic_pre_enable(struct msm_dp *dp_display,
|
||||
struct drm_atomic_commit *state);
|
||||
void msm_dp_display_atomic_enable(struct msm_dp *dp_display,
|
||||
struct drm_atomic_commit *state);
|
||||
enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp,
|
||||
const struct drm_display_info *info,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
#endif /* _DP_DISPLAY_H_ */
|
||||
|
|
|
|||
|
|
@ -49,14 +49,60 @@ static void msm_dp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry
|
|||
msm_dp_display_debugfs_init(dp, root, false);
|
||||
}
|
||||
|
||||
static void msm_dp_bridge_atomic_pre_enable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = dp_bridge->msm_dp_display;
|
||||
|
||||
msm_dp_display_atomic_pre_enable(dp, state);
|
||||
}
|
||||
|
||||
static void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = dp_bridge->msm_dp_display;
|
||||
|
||||
msm_dp_display_atomic_enable(dp, state);
|
||||
}
|
||||
|
||||
static void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = dp_bridge->msm_dp_display;
|
||||
|
||||
msm_dp_display_atomic_disable(dp);
|
||||
}
|
||||
|
||||
static void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = dp_bridge->msm_dp_display;
|
||||
|
||||
msm_dp_display_atomic_post_disable(dp);
|
||||
}
|
||||
|
||||
static enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *drm_bridge,
|
||||
const struct drm_display_info *info,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = dp_bridge->msm_dp_display;
|
||||
|
||||
return msm_dp_display_mode_valid(dp, info, mode);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs msm_dp_bridge_ops = {
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_pre_enable = msm_dp_bridge_atomic_pre_enable,
|
||||
.atomic_enable = msm_dp_bridge_atomic_enable,
|
||||
.atomic_disable = msm_dp_bridge_atomic_disable,
|
||||
.atomic_post_disable = msm_dp_bridge_atomic_post_disable,
|
||||
.mode_set = msm_dp_bridge_mode_set,
|
||||
.mode_valid = msm_dp_bridge_mode_valid,
|
||||
.get_modes = msm_dp_bridge_get_modes,
|
||||
.detect = msm_dp_bridge_detect,
|
||||
|
|
@ -116,7 +162,7 @@ static void msm_edp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
|
|||
return;
|
||||
}
|
||||
|
||||
msm_dp_bridge_atomic_enable(drm_bridge, state);
|
||||
msm_dp_display_atomic_enable(dp, state);
|
||||
}
|
||||
|
||||
static void msm_edp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
|
||||
|
|
@ -230,10 +276,10 @@ static void msm_edp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs msm_edp_bridge_ops = {
|
||||
.atomic_pre_enable = msm_dp_bridge_atomic_pre_enable,
|
||||
.atomic_enable = msm_edp_bridge_atomic_enable,
|
||||
.atomic_disable = msm_edp_bridge_atomic_disable,
|
||||
.atomic_post_disable = msm_edp_bridge_atomic_post_disable,
|
||||
.mode_set = msm_dp_bridge_mode_set,
|
||||
.mode_valid = msm_edp_bridge_mode_valid,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
|
|
|
|||
|
|
@ -27,18 +27,6 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
|
|||
|
||||
enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
|
||||
struct drm_connector *connector);
|
||||
void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state);
|
||||
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state);
|
||||
void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
|
||||
struct drm_atomic_commit *state);
|
||||
enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_info *info,
|
||||
const struct drm_display_mode *mode);
|
||||
void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adjusted_mode);
|
||||
void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge);
|
||||
void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge);
|
||||
void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge,
|
||||
|
|
|
|||
|
|
@ -232,8 +232,8 @@ static u32 msm_dp_panel_get_supported_bpp(struct msm_dp_panel *msm_dp_panel,
|
|||
return min_supported_bpp;
|
||||
}
|
||||
|
||||
int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel,
|
||||
struct drm_connector *connector)
|
||||
int msm_dp_panel_read_link_caps(struct msm_dp_panel *msm_dp_panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
int rc, bw_code;
|
||||
int count;
|
||||
|
|
@ -271,36 +271,9 @@ int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel,
|
|||
|
||||
rc = drm_dp_read_downstream_info(panel->aux, msm_dp_panel->dpcd,
|
||||
msm_dp_panel->downstream_ports);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
drm_edid_free(msm_dp_panel->drm_edid);
|
||||
|
||||
msm_dp_panel->drm_edid = drm_edid_read_ddc(connector, &panel->aux->ddc);
|
||||
|
||||
drm_edid_connector_update(connector, msm_dp_panel->drm_edid);
|
||||
|
||||
if (!msm_dp_panel->drm_edid) {
|
||||
DRM_ERROR("panel edid read failed\n");
|
||||
/* check edid read fail is due to unplug */
|
||||
if (!msm_dp_aux_is_link_connected(panel->aux)) {
|
||||
rc = -ETIMEDOUT;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void msm_dp_panel_unplugged(struct msm_dp_panel *msm_dp_panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
drm_edid_connector_update(connector, NULL);
|
||||
drm_edid_free(msm_dp_panel->drm_edid);
|
||||
msm_dp_panel->drm_edid = NULL;
|
||||
}
|
||||
|
||||
u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel,
|
||||
u32 mode_edid_bpp, u32 mode_pclk_khz)
|
||||
{
|
||||
|
|
@ -324,20 +297,6 @@ u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel,
|
|||
return bpp;
|
||||
}
|
||||
|
||||
int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
if (!msm_dp_panel) {
|
||||
DRM_ERROR("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (msm_dp_panel->drm_edid)
|
||||
return drm_edid_connector_add_modes(connector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 msm_dp_panel_get_edid_checksum(const struct edid *edid)
|
||||
{
|
||||
edid += edid->extensions;
|
||||
|
|
@ -345,7 +304,8 @@ static u8 msm_dp_panel_get_edid_checksum(const struct edid *edid)
|
|||
return edid->checksum;
|
||||
}
|
||||
|
||||
void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel)
|
||||
void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel,
|
||||
const struct drm_edid *drm_edid)
|
||||
{
|
||||
struct msm_dp_panel_private *panel;
|
||||
|
||||
|
|
@ -358,7 +318,7 @@ void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel)
|
|||
|
||||
if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) {
|
||||
/* FIXME: get rid of drm_edid_raw() */
|
||||
const struct edid *edid = drm_edid_raw(msm_dp_panel->drm_edid);
|
||||
const struct edid *edid = drm_edid_raw(drm_edid);
|
||||
u8 checksum;
|
||||
|
||||
if (edid)
|
||||
|
|
@ -687,15 +647,27 @@ int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel)
|
||||
int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel,
|
||||
const struct drm_display_mode *adjusted_mode,
|
||||
u32 bpp)
|
||||
{
|
||||
struct drm_display_mode *drm_mode;
|
||||
struct msm_dp_panel_private *panel;
|
||||
|
||||
drm_mode = &msm_dp_panel->msm_dp_mode.drm_mode;
|
||||
|
||||
panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
|
||||
|
||||
drm_mode_copy(&msm_dp_panel->msm_dp_mode.drm_mode, adjusted_mode);
|
||||
msm_dp_panel->msm_dp_mode.bpp = bpp;
|
||||
msm_dp_panel->msm_dp_mode.v_active_low =
|
||||
!!(adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC);
|
||||
msm_dp_panel->msm_dp_mode.h_active_low =
|
||||
!!(adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC);
|
||||
msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420 =
|
||||
drm_mode_is_420_only(&msm_dp_panel->connector->display_info, adjusted_mode) &&
|
||||
msm_dp_panel->vsc_sdp_supported;
|
||||
|
||||
drm_mode = &msm_dp_panel->msm_dp_mode.drm_mode;
|
||||
|
||||
/*
|
||||
* print resolution info as this is a result
|
||||
* of user initiated action of cable connection
|
||||
|
|
@ -755,10 +727,3 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux
|
|||
return msm_dp_panel;
|
||||
}
|
||||
|
||||
void msm_dp_panel_put(struct msm_dp_panel *msm_dp_panel)
|
||||
{
|
||||
if (!msm_dp_panel)
|
||||
return;
|
||||
|
||||
drm_edid_free(msm_dp_panel->drm_edid);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ struct msm_dp_panel {
|
|||
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
|
||||
|
||||
struct msm_dp_link_info link_info;
|
||||
const struct drm_edid *drm_edid;
|
||||
struct drm_connector *connector;
|
||||
struct msm_dp_display_mode msm_dp_mode;
|
||||
struct msm_dp_panel_psr psr_cap;
|
||||
|
|
@ -44,18 +43,17 @@ struct msm_dp_panel {
|
|||
u32 max_bw_code;
|
||||
};
|
||||
|
||||
int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel);
|
||||
int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel,
|
||||
const struct drm_display_mode *adjusted_mode,
|
||||
u32 bpp);
|
||||
int msm_dp_panel_deinit(struct msm_dp_panel *msm_dp_panel);
|
||||
int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en);
|
||||
int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel,
|
||||
struct drm_connector *connector);
|
||||
void msm_dp_panel_unplugged(struct msm_dp_panel *msm_dp_panel,
|
||||
struct drm_connector *connector);
|
||||
int msm_dp_panel_read_link_caps(struct msm_dp_panel *msm_dp_panel,
|
||||
struct drm_connector *connector);
|
||||
u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel, u32 mode_max_bpp,
|
||||
u32 mode_pclk_khz);
|
||||
int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel,
|
||||
struct drm_connector *connector);
|
||||
void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel);
|
||||
void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel,
|
||||
const struct drm_edid *drm_edid);
|
||||
void msm_dp_panel_tpg_config(struct msm_dp_panel *msm_dp_panel, bool enable);
|
||||
|
||||
void msm_dp_panel_clear_dsc_dto(struct msm_dp_panel *msm_dp_panel);
|
||||
|
|
@ -94,5 +92,4 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux
|
|||
struct msm_dp_link *link,
|
||||
void __iomem *link_base,
|
||||
void __iomem *p0_base);
|
||||
void msm_dp_panel_put(struct msm_dp_panel *msm_dp_panel);
|
||||
#endif /* _DP_PANEL_H_ */
|
||||
|
|
|
|||
|
|
@ -149,8 +149,10 @@
|
|||
#define DP_CONFIGURATION_CTRL_ENHANCED_FRAMING (0x00000040)
|
||||
#define DP_CONFIGURATION_CTRL_SEND_VSC (0x00000080)
|
||||
#define DP_CONFIGURATION_CTRL_BPC (0x00000100)
|
||||
#define DP_CONFIGURATION_CTRL_BPC_MASK GENMASK(9, 8)
|
||||
#define DP_CONFIGURATION_CTRL_ASSR (0x00000400)
|
||||
#define DP_CONFIGURATION_CTRL_RGB_YUV (0x00000800)
|
||||
#define DP_CONFIGURATION_CTRL_RGB_YUV_MASK GENMASK(12, 11)
|
||||
#define DP_CONFIGURATION_CTRL_LSCLK_DIV (0x00002000)
|
||||
#define DP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT (0x04)
|
||||
#define DP_CONFIGURATION_CTRL_BPC_SHIFT (0x08)
|
||||
|
|
|
|||
|
|
@ -550,8 +550,6 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)
|
|||
|
||||
void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host)
|
||||
{
|
||||
/* Drop the performance state vote */
|
||||
dev_pm_opp_set_rate(&msm_host->pdev->dev, 0);
|
||||
clk_disable_unprepare(msm_host->esc_clk);
|
||||
clk_disable_unprepare(msm_host->pixel_clk);
|
||||
clk_disable_unprepare(msm_host->byte_intf_clk);
|
||||
|
|
@ -671,12 +669,24 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
|
|||
|
||||
int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
|
||||
{
|
||||
long rounded_byte_clk_rate;
|
||||
|
||||
if (!msm_host->mode) {
|
||||
pr_err("%s: mode not set\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dsi_calc_pclk(msm_host, is_bonded_dsi);
|
||||
|
||||
rounded_byte_clk_rate = clk_round_rate(msm_host->byte_clk,
|
||||
msm_host->byte_clk_rate);
|
||||
if (rounded_byte_clk_rate < 0) {
|
||||
pr_err("%s: failed to round byte clock rate, %ld\n",
|
||||
__func__, rounded_byte_clk_rate);
|
||||
return rounded_byte_clk_rate;
|
||||
}
|
||||
|
||||
msm_host->byte_clk_rate = rounded_byte_clk_rate;
|
||||
msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ struct msm_dsi_phy {
|
|||
struct msm_dsi_dphy_timing timing;
|
||||
const struct msm_dsi_phy_cfg *cfg;
|
||||
void *tuning_cfg;
|
||||
void *pll_data;
|
||||
|
||||
enum msm_dsi_phy_usecase usecase;
|
||||
bool regulator_ldo_mode;
|
||||
|
|
|
|||
|
|
@ -426,8 +426,11 @@ static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll)
|
|||
u32 data;
|
||||
|
||||
spin_lock_irqsave(&pll->pll_enable_lock, flags);
|
||||
pll->pll_enable_cnt++;
|
||||
WARN_ON(pll->pll_enable_cnt == INT_MAX);
|
||||
if (pll->pll_enable_cnt++) {
|
||||
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
|
||||
WARN_ON(pll->pll_enable_cnt == INT_MAX);
|
||||
return;
|
||||
}
|
||||
|
||||
data = readl(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
|
||||
data |= DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
|
||||
|
|
@ -873,6 +876,7 @@ static int dsi_pll_7nm_init(struct msm_dsi_phy *phy)
|
|||
spin_lock_init(&pll_7nm->pll_enable_lock);
|
||||
|
||||
pll_7nm->phy = phy;
|
||||
phy->pll_data = pll_7nm;
|
||||
|
||||
ret = pll_7nm_register(pll_7nm, phy->provided_clocks->hws);
|
||||
if (ret) {
|
||||
|
|
@ -961,8 +965,10 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
|
|||
u32 const delay_us = 5;
|
||||
u32 const timeout_us = 1000;
|
||||
struct msm_dsi_dphy_timing *timing = &phy->timing;
|
||||
struct dsi_pll_7nm *pll = phy->pll_data;
|
||||
void __iomem *base = phy->base;
|
||||
bool less_than_1500_mhz;
|
||||
unsigned long flags;
|
||||
u32 vreg_ctrl_0, vreg_ctrl_1, lane_ctrl0;
|
||||
u32 glbl_pemph_ctrl_0;
|
||||
u32 glbl_str_swi_cal_sel_ctrl, glbl_hstx_str_ctrl_0;
|
||||
|
|
@ -1084,10 +1090,13 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
|
|||
glbl_rescode_bot_ctrl = 0x3c;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pll->pll_enable_lock, flags);
|
||||
pll->pll_enable_cnt = 1;
|
||||
/* de-assert digital and pll power down */
|
||||
data = DSI_7nm_PHY_CMN_CTRL_0_DIGTOP_PWRDN_B |
|
||||
DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
|
||||
writel(data, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
|
||||
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
|
||||
|
||||
/* Assert PLL core reset */
|
||||
writel(0x00, base + REG_DSI_7nm_PHY_CMN_PLL_CNTRL);
|
||||
|
|
@ -1200,7 +1209,9 @@ static bool dsi_7nm_set_continuous_clock(struct msm_dsi_phy *phy, bool enable)
|
|||
|
||||
static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
|
||||
{
|
||||
struct dsi_pll_7nm *pll = phy->pll_data;
|
||||
void __iomem *base = phy->base;
|
||||
unsigned long flags;
|
||||
u32 data;
|
||||
|
||||
DBG("");
|
||||
|
|
@ -1227,8 +1238,11 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
|
|||
writel(data, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
|
||||
writel(0, base + REG_DSI_7nm_PHY_CMN_LANE_CTRL0);
|
||||
|
||||
spin_lock_irqsave(&pll->pll_enable_lock, flags);
|
||||
pll->pll_enable_cnt = 0;
|
||||
/* Turn off all PHY blocks */
|
||||
writel(0x00, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
|
||||
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
|
||||
|
||||
/* make sure phy is turned off */
|
||||
wmb();
|
||||
|
|
|
|||
|
|
@ -112,6 +112,25 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
|
|||
return readl(hdmi->mmio + reg);
|
||||
}
|
||||
|
||||
static inline void hdmi_clear_bits(struct hdmi *hdmi, u32 reg, u32 mask)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = hdmi_read(hdmi, reg);
|
||||
val &= ~mask;
|
||||
hdmi_write(hdmi, reg, val);
|
||||
}
|
||||
|
||||
static inline void hdmi_update_bits(struct hdmi *hdmi, u32 reg, u32 mask, u32 data)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = hdmi_read(hdmi, reg);
|
||||
val &= ~mask;
|
||||
val |= data & mask;
|
||||
hdmi_write(hdmi, reg, val);
|
||||
}
|
||||
|
||||
static inline u32 hdmi_qfprom_read(struct hdmi *hdmi, u32 reg)
|
||||
{
|
||||
return readl(hdmi->qfprom_mmio + reg);
|
||||
|
|
|
|||
|
|
@ -58,16 +58,13 @@ static int msm_hdmi_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
|
|||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
u32 val;
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
|
||||
val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
|
||||
HDMI_INFOFRAME_CTRL0_AVI_CONT);
|
||||
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_INFOFRAME_CTRL0,
|
||||
HDMI_INFOFRAME_CTRL0_AVI_SEND |
|
||||
HDMI_INFOFRAME_CTRL0_AVI_CONT);
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
|
||||
val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
|
||||
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_INFOFRAME_CTRL1,
|
||||
HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -76,18 +73,15 @@ static int msm_hdmi_bridge_clear_audio_infoframe(struct drm_bridge *bridge)
|
|||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
u32 val;
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
|
||||
val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
|
||||
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_INFOFRAME_CTRL0,
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
|
||||
val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
|
||||
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_INFOFRAME_CTRL1,
|
||||
HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -96,13 +90,11 @@ static int msm_hdmi_bridge_clear_spd_infoframe(struct drm_bridge *bridge)
|
|||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
u32 val;
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
|
||||
val &= ~(HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK);
|
||||
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_GEN_PKT_CTRL,
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -111,14 +103,12 @@ static int msm_hdmi_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge)
|
|||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
u32 val;
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
|
||||
val &= ~(HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK);
|
||||
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_GEN_PKT_CTRL,
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -129,7 +119,6 @@ static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge,
|
|||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = hdmi_bridge->hdmi;
|
||||
u32 buf[4] = {};
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
|
||||
|
|
@ -153,15 +142,13 @@ static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge,
|
|||
for (i = 0; i < ARRAY_SIZE(buf); i++)
|
||||
hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
|
||||
val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
|
||||
HDMI_INFOFRAME_CTRL0_AVI_CONT;
|
||||
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_INFOFRAME_CTRL0,
|
||||
HDMI_INFOFRAME_CTRL0_AVI_SEND | HDMI_INFOFRAME_CTRL0_AVI_CONT,
|
||||
HDMI_INFOFRAME_CTRL0_AVI_SEND | HDMI_INFOFRAME_CTRL0_AVI_CONT);
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
|
||||
val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
|
||||
val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
|
||||
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_INFOFRAME_CTRL1,
|
||||
HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK,
|
||||
HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -193,12 +180,11 @@ static int msm_hdmi_bridge_write_audio_infoframe(struct drm_bridge *bridge,
|
|||
buffer[9] << 16 |
|
||||
buffer[10] << 24);
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
|
||||
val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
|
||||
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
|
||||
val = HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
|
||||
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
|
||||
hdmi_update_bits(hdmi, REG_HDMI_INFOFRAME_CTRL0, val, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -231,11 +217,10 @@ static int msm_hdmi_bridge_write_spd_infoframe(struct drm_bridge *bridge,
|
|||
for (i = 0; i < ARRAY_SIZE(buf); i++)
|
||||
hdmi_write(hdmi, REG_HDMI_GENERIC1(i), buf[i]);
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
|
||||
val |= HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_LINE(SPD_IFRAME_LINE_NUMBER);
|
||||
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
|
||||
val = HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC1_LINE(SPD_IFRAME_LINE_NUMBER);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_GEN_PKT_CTRL, val, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -269,12 +254,11 @@ static int msm_hdmi_bridge_write_hdmi_infoframe(struct drm_bridge *bridge,
|
|||
for (i = 0; i < ARRAY_SIZE(buf); i++)
|
||||
hdmi_write(hdmi, REG_HDMI_GENERIC0(i), buf[i]);
|
||||
|
||||
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
|
||||
val |= HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_LINE(VENSPEC_IFRAME_LINE_NUMBER);
|
||||
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
|
||||
val = HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
|
||||
HDMI_GEN_PKT_CTRL_GENERIC0_LINE(VENSPEC_IFRAME_LINE_NUMBER);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_GEN_PKT_CTRL, val, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,9 +306,9 @@ static int msm_reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
HDMI_HDCP_DDC_CTRL_0_DISABLE);
|
||||
|
||||
/* ACK the Failure to Clear it */
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_CTRL_1);
|
||||
reg_val |= HDMI_HDCP_DDC_CTRL_1_FAILED_ACK;
|
||||
hdmi_write(hdmi, REG_HDMI_HDCP_DDC_CTRL_1, reg_val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_HDCP_DDC_CTRL_1,
|
||||
HDMI_HDCP_DDC_CTRL_1_FAILED_ACK,
|
||||
HDMI_HDCP_DDC_CTRL_1_FAILED_ACK);
|
||||
|
||||
/* Check if the FAILURE got Cleared */
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_STATUS);
|
||||
|
|
@ -324,28 +324,22 @@ static int msm_reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
DBG("Before: HDMI_DDC_SW_STATUS=0x%08x",
|
||||
hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS));
|
||||
/* Reset HDMI DDC software status */
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
|
||||
reg_val |= HDMI_DDC_CTRL_SW_STATUS_RESET;
|
||||
hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SW_STATUS_RESET,
|
||||
HDMI_DDC_CTRL_SW_STATUS_RESET);
|
||||
|
||||
rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
|
||||
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
|
||||
reg_val &= ~HDMI_DDC_CTRL_SW_STATUS_RESET;
|
||||
hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SW_STATUS_RESET);
|
||||
|
||||
/* Reset HDMI DDC Controller */
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
|
||||
reg_val |= HDMI_DDC_CTRL_SOFT_RESET;
|
||||
hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SOFT_RESET,
|
||||
HDMI_DDC_CTRL_SOFT_RESET);
|
||||
|
||||
/* If previous msleep is aborted, skip this msleep */
|
||||
if (!rc)
|
||||
rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
|
||||
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
|
||||
reg_val &= ~HDMI_DDC_CTRL_SOFT_RESET;
|
||||
hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SOFT_RESET);
|
||||
DBG("After: HDMI_DDC_SW_STATUS=0x%08x",
|
||||
hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS));
|
||||
}
|
||||
|
|
@ -399,7 +393,6 @@ static void msm_hdmi_hdcp_reauth_work(struct work_struct *work)
|
|||
struct hdmi_hdcp_ctrl, hdcp_reauth_work);
|
||||
struct hdmi *hdmi = hdcp_ctrl->hdmi;
|
||||
unsigned long flags;
|
||||
u32 reg_val;
|
||||
|
||||
DBG("HDCP REAUTH WORK");
|
||||
/*
|
||||
|
|
@ -409,9 +402,7 @@ static void msm_hdmi_hdcp_reauth_work(struct work_struct *work)
|
|||
* AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
|
||||
*/
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
|
||||
reg_val &= ~HDMI_HPD_CTRL_ENABLE;
|
||||
hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_HPD_CTRL, HDMI_HPD_CTRL_ENABLE);
|
||||
|
||||
/* Disable HDCP interrupts */
|
||||
hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL, 0);
|
||||
|
|
@ -431,9 +422,8 @@ static void msm_hdmi_hdcp_reauth_work(struct work_struct *work)
|
|||
|
||||
/* Enable HPD circuitry */
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
|
||||
reg_val |= HDMI_HPD_CTRL_ENABLE;
|
||||
hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_HPD_CTRL, HDMI_HPD_CTRL_ENABLE,
|
||||
HDMI_HPD_CTRL_ENABLE);
|
||||
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||
|
||||
/*
|
||||
|
|
@ -456,7 +446,6 @@ static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
{
|
||||
struct hdmi *hdmi = hdcp_ctrl->hdmi;
|
||||
u32 link0_status;
|
||||
u32 reg_val;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
|
|
@ -472,14 +461,11 @@ static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
/* disable HDMI Encrypt */
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
|
||||
reg_val &= ~HDMI_CTRL_ENCRYPTED;
|
||||
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED);
|
||||
|
||||
/* Enabling Software DDC */
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_ARBITRATION);
|
||||
reg_val &= ~HDMI_DDC_ARBITRATION_HW_ARBITRATION;
|
||||
hdmi_write(hdmi, REG_HDMI_DDC_ARBITRATION, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_DDC_ARBITRATION,
|
||||
HDMI_DDC_ARBITRATION_HW_ARBITRATION);
|
||||
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||
|
||||
/*
|
||||
|
|
@ -498,9 +484,8 @@ static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
hdmi_write(hdmi, REG_HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE);
|
||||
|
||||
/* Disable the RngCipher state */
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DEBUG_CTRL);
|
||||
reg_val &= ~HDMI_HDCP_DEBUG_CTRL_RNG_CIPHER;
|
||||
hdmi_write(hdmi, REG_HDMI_HDCP_DEBUG_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_HDCP_DEBUG_CTRL,
|
||||
HDMI_HDCP_DEBUG_CTRL_RNG_CIPHER);
|
||||
DBG("HDCP_DEBUG_CTRL=0x%08x",
|
||||
hdmi_read(hdmi, REG_HDMI_HDCP_DEBUG_CTRL));
|
||||
|
||||
|
|
@ -537,15 +522,12 @@ static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
static void msm_hdmi_hdcp_auth_fail(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
||||
{
|
||||
struct hdmi *hdmi = hdcp_ctrl->hdmi;
|
||||
u32 reg_val;
|
||||
unsigned long flags;
|
||||
|
||||
DBG("hdcp auth failed, queue reauth work");
|
||||
/* clear HDMI Encrypt */
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
|
||||
reg_val &= ~HDMI_CTRL_ENCRYPTED;
|
||||
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED);
|
||||
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||
|
||||
hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAILED;
|
||||
|
|
@ -555,7 +537,6 @@ static void msm_hdmi_hdcp_auth_fail(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
static void msm_hdmi_hdcp_auth_done(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
||||
{
|
||||
struct hdmi *hdmi = hdcp_ctrl->hdmi;
|
||||
u32 reg_val;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
|
|
@ -563,16 +544,15 @@ static void msm_hdmi_hdcp_auth_done(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
* there is no Arbitration between software and hardware for DDC
|
||||
*/
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_ARBITRATION);
|
||||
reg_val |= HDMI_DDC_ARBITRATION_HW_ARBITRATION;
|
||||
hdmi_write(hdmi, REG_HDMI_DDC_ARBITRATION, reg_val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_DDC_ARBITRATION,
|
||||
HDMI_DDC_ARBITRATION_HW_ARBITRATION,
|
||||
HDMI_DDC_ARBITRATION_HW_ARBITRATION);
|
||||
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||
|
||||
/* enable HDMI Encrypt */
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
|
||||
reg_val |= HDMI_CTRL_ENCRYPTED;
|
||||
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED,
|
||||
HDMI_CTRL_ENCRYPTED);
|
||||
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||
|
||||
hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATED;
|
||||
|
|
@ -1304,7 +1284,6 @@ static void msm_hdmi_hdcp_auth_work(struct work_struct *work)
|
|||
void msm_hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
||||
{
|
||||
struct hdmi *hdmi = hdcp_ctrl->hdmi;
|
||||
u32 reg_val;
|
||||
unsigned long flags;
|
||||
|
||||
if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) ||
|
||||
|
|
@ -1315,9 +1294,7 @@ void msm_hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
|
||||
/* clear HDMI Encrypt */
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
|
||||
reg_val &= ~HDMI_CTRL_ENCRYPTED;
|
||||
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED);
|
||||
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||
|
||||
hdcp_ctrl->auth_event = 0;
|
||||
|
|
@ -1330,7 +1307,6 @@ void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
{
|
||||
struct hdmi *hdmi = hdcp_ctrl->hdmi;
|
||||
unsigned long flags;
|
||||
u32 reg_val;
|
||||
|
||||
if ((HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) ||
|
||||
(HDCP_STATE_NO_AKSV == hdcp_ctrl->hdcp_state)) {
|
||||
|
|
@ -1345,9 +1321,7 @@ void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
* AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
|
||||
*/
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
|
||||
reg_val &= ~HDMI_HPD_CTRL_ENABLE;
|
||||
hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_HPD_CTRL, HDMI_HPD_CTRL_ENABLE);
|
||||
|
||||
/*
|
||||
* Disable HDCP interrupts.
|
||||
|
|
@ -1375,14 +1349,11 @@ void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
hdmi_write(hdmi, REG_HDMI_HDCP_CTRL, 0);
|
||||
|
||||
spin_lock_irqsave(&hdmi->reg_lock, flags);
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
|
||||
reg_val &= ~HDMI_CTRL_ENCRYPTED;
|
||||
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
|
||||
hdmi_clear_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED);
|
||||
|
||||
/* Enable HPD circuitry */
|
||||
reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
|
||||
reg_val |= HDMI_HPD_CTRL_ENABLE;
|
||||
hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
|
||||
hdmi_update_bits(hdmi, REG_HDMI_HPD_CTRL, HDMI_HPD_CTRL_ENABLE,
|
||||
HDMI_HPD_CTRL_ENABLE);
|
||||
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
|
||||
|
||||
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
|
||||
|
|
|
|||
|
|
@ -222,20 +222,21 @@ static void load_gpu(struct drm_device *dev)
|
|||
*/
|
||||
struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx)
|
||||
{
|
||||
static DEFINE_MUTEX(init_lock);
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct drm_gpuvm *vm = smp_load_acquire(&ctx->vm);
|
||||
|
||||
/* Once ctx->vm is created it is valid for the lifetime of the context: */
|
||||
if (ctx->vm)
|
||||
return ctx->vm;
|
||||
if (vm)
|
||||
return vm;
|
||||
|
||||
guard(rwsem_write)(&ctx->ctxlock);
|
||||
|
||||
mutex_lock(&init_lock);
|
||||
if (!ctx->vm) {
|
||||
ctx->vm = msm_gpu_create_private_vm(
|
||||
vm = msm_gpu_create_private_vm(
|
||||
priv->gpu, current, !ctx->userspace_managed_vm);
|
||||
|
||||
if (!IS_ERR_OR_NULL(vm))
|
||||
smp_store_release(&ctx->vm, vm);
|
||||
}
|
||||
mutex_unlock(&init_lock);
|
||||
|
||||
return ctx->vm;
|
||||
}
|
||||
|
|
@ -250,7 +251,7 @@ static int context_init(struct drm_device *dev, struct drm_file *file)
|
|||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&ctx->submitqueues);
|
||||
rwlock_init(&ctx->queuelock);
|
||||
init_rwsem(&ctx->ctxlock);
|
||||
|
||||
kref_init(&ctx->ref);
|
||||
msm_submitqueue_init(dev, ctx);
|
||||
|
|
@ -422,10 +423,14 @@ static int msm_ioctl_gem_info_iova(struct drm_device *dev,
|
|||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_context *ctx = file->driver_priv;
|
||||
struct drm_gpuvm *vm = msm_context_vm(dev, ctx);
|
||||
|
||||
if (!priv->gpu)
|
||||
return -EINVAL;
|
||||
|
||||
if (!vm)
|
||||
return UERR(ENOMEM, dev, "no VM");
|
||||
|
||||
if (msm_context_is_vmbind(ctx))
|
||||
return UERR(EINVAL, dev, "VM_BIND is enabled");
|
||||
|
||||
|
|
@ -436,7 +441,7 @@ static int msm_ioctl_gem_info_iova(struct drm_device *dev,
|
|||
* Don't pin the memory here - just get an address so that userspace can
|
||||
* be productive
|
||||
*/
|
||||
return msm_gem_get_iova(obj, msm_context_vm(dev, ctx), iova);
|
||||
return msm_gem_get_iova(obj, vm, iova);
|
||||
}
|
||||
|
||||
static int msm_ioctl_gem_info_set_iova(struct drm_device *dev,
|
||||
|
|
@ -450,6 +455,9 @@ static int msm_ioctl_gem_info_set_iova(struct drm_device *dev,
|
|||
if (!priv->gpu)
|
||||
return -EINVAL;
|
||||
|
||||
if (!vm)
|
||||
return UERR(ENOMEM, dev, "no VM");
|
||||
|
||||
if (msm_context_is_vmbind(ctx))
|
||||
return UERR(EINVAL, dev, "VM_BIND is enabled");
|
||||
|
||||
|
|
|
|||
|
|
@ -261,8 +261,6 @@ const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
|
|||
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_file *file, const struct drm_format_info *info,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd);
|
||||
struct drm_framebuffer * msm_alloc_stolen_fb(struct drm_device *dev,
|
||||
int w, int h, int p, uint32_t format);
|
||||
|
||||
#ifdef CONFIG_DRM_MSM_KMS_FBDEV
|
||||
int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
|
||||
|
|
@ -356,8 +354,6 @@ void __exit msm_dp_unregister(void);
|
|||
int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
struct drm_encoder *encoder, bool yuv_supported);
|
||||
void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display);
|
||||
bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode);
|
||||
bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode);
|
||||
bool msm_dp_wide_bus_available(const struct msm_dp *dp_display);
|
||||
|
|
@ -382,12 +378,6 @@ static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm
|
|||
{
|
||||
}
|
||||
|
||||
static inline bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
|
|
@ -503,13 +493,6 @@ void msm_hrtimer_work_init(struct msm_hrtimer_work *work,
|
|||
#define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)
|
||||
#define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)
|
||||
|
||||
static inline int align_pitch(int width, int bpp)
|
||||
{
|
||||
int bytespp = (bpp + 7) / 8;
|
||||
/* adreno needs pitch aligned to 32 pixels: */
|
||||
return bytespp * ALIGN(width, 32);
|
||||
}
|
||||
|
||||
/* for the generated headers: */
|
||||
#define INVALID_IDX(idx) ({BUG(); 0;})
|
||||
#define fui(x) ({BUG(); 0;})
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
|
|
@ -29,10 +28,6 @@ struct msm_framebuffer {
|
|||
};
|
||||
#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
|
||||
|
||||
static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
|
||||
const struct drm_format_info *info,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
|
||||
|
||||
static int msm_framebuffer_dirtyfb(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv, unsigned int flags,
|
||||
unsigned int color, struct drm_clip_rect *clips,
|
||||
|
|
@ -139,39 +134,10 @@ const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb)
|
|||
return msm_fb->format;
|
||||
}
|
||||
|
||||
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_file *file, const struct drm_format_info *info,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
struct drm_gem_object *bos[4] = {0};
|
||||
struct drm_framebuffer *fb;
|
||||
int ret, i, n = info->num_planes;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
|
||||
if (!bos[i]) {
|
||||
ret = -ENXIO;
|
||||
goto out_unref;
|
||||
}
|
||||
}
|
||||
|
||||
fb = msm_framebuffer_init(dev, info, mode_cmd, bos);
|
||||
if (IS_ERR(fb)) {
|
||||
ret = PTR_ERR(fb);
|
||||
goto out_unref;
|
||||
}
|
||||
|
||||
return fb;
|
||||
|
||||
out_unref:
|
||||
for (i = 0; i < n; i++)
|
||||
drm_gem_object_put(bos[i]);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
|
||||
const struct drm_format_info *info,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
|
||||
static struct drm_framebuffer *
|
||||
msm_framebuffer_init(struct drm_device *dev, const struct drm_format_info *info,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object **bos)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
|
|
@ -251,47 +217,33 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct drm_framebuffer *
|
||||
msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format)
|
||||
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_file *file,
|
||||
const struct drm_format_info *info,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
struct drm_mode_fb_cmd2 mode_cmd = {
|
||||
.pixel_format = format,
|
||||
.width = w,
|
||||
.height = h,
|
||||
.pitches = { p },
|
||||
};
|
||||
struct drm_gem_object *bo;
|
||||
struct drm_gem_object *bos[4] = {0};
|
||||
struct drm_framebuffer *fb;
|
||||
int size;
|
||||
int ret, i, n = info->num_planes;
|
||||
|
||||
/* allocate backing bo */
|
||||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
|
||||
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC | MSM_BO_STOLEN);
|
||||
if (IS_ERR(bo)) {
|
||||
dev_warn(dev->dev, "could not allocate stolen bo\n");
|
||||
/* try regular bo: */
|
||||
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
|
||||
}
|
||||
if (IS_ERR(bo)) {
|
||||
DRM_DEV_ERROR(dev->dev, "failed to allocate buffer object\n");
|
||||
return ERR_CAST(bo);
|
||||
for (i = 0; i < n; i++) {
|
||||
bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
|
||||
if (!bos[i]) {
|
||||
ret = -ENXIO;
|
||||
goto out_unref;
|
||||
}
|
||||
}
|
||||
|
||||
msm_gem_object_set_name(bo, "stolenfb");
|
||||
|
||||
fb = msm_framebuffer_init(dev,
|
||||
drm_get_format_info(dev, mode_cmd.pixel_format,
|
||||
mode_cmd.modifier[0]),
|
||||
&mode_cmd, &bo);
|
||||
fb = msm_framebuffer_init(dev, info, mode_cmd, bos);
|
||||
if (IS_ERR(fb)) {
|
||||
DRM_DEV_ERROR(dev->dev, "failed to allocate fb\n");
|
||||
/* note: if fb creation failed, we can't rely on fb destroy
|
||||
* to unref the bo:
|
||||
*/
|
||||
drm_gem_object_put(bo);
|
||||
return ERR_CAST(fb);
|
||||
ret = PTR_ERR(fb);
|
||||
goto out_unref;
|
||||
}
|
||||
|
||||
return fb;
|
||||
|
||||
out_unref:
|
||||
for (i = 0; i < n; i++)
|
||||
drm_gem_object_put(bos[i]);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_prime.h>
|
||||
|
|
@ -40,17 +41,15 @@ static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
|
|||
static void msm_fbdev_fb_destroy(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par;
|
||||
struct drm_framebuffer *fb = helper->fb;
|
||||
struct drm_gem_object *bo = msm_framebuffer_bo(fb, 0);
|
||||
struct drm_gem_object *bo = msm_framebuffer_bo(helper->fb, 0);
|
||||
|
||||
DBG();
|
||||
|
||||
drm_fb_helper_fini(helper);
|
||||
|
||||
/* this will free the backing object */
|
||||
msm_gem_put_vaddr(bo);
|
||||
drm_framebuffer_remove(fb);
|
||||
|
||||
drm_client_buffer_delete(helper->buffer);
|
||||
drm_client_release(&helper->client);
|
||||
}
|
||||
|
||||
|
|
@ -89,31 +88,54 @@ static const struct drm_fb_helper_funcs msm_fbdev_helper_funcs = {
|
|||
int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct drm_device *dev = helper->dev;
|
||||
struct drm_client_dev *client = &helper->client;
|
||||
struct drm_device *dev = client->dev;
|
||||
struct drm_file *file = client->file;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct fb_info *fbi = helper->info;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
const struct drm_format_info *format;
|
||||
u32 fourcc, pitch, handle;
|
||||
u64 size;
|
||||
struct drm_gem_object *bo;
|
||||
struct drm_client_buffer *buffer;
|
||||
uint64_t paddr;
|
||||
uint32_t format;
|
||||
int ret, pitch;
|
||||
|
||||
format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
|
||||
int ret;
|
||||
|
||||
DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
|
||||
sizes->surface_height, sizes->surface_bpp,
|
||||
sizes->fb_width, sizes->fb_height);
|
||||
|
||||
pitch = align_pitch(sizes->surface_width, sizes->surface_bpp);
|
||||
fb = msm_alloc_stolen_fb(dev, sizes->surface_width,
|
||||
sizes->surface_height, pitch, format);
|
||||
fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
|
||||
format = drm_get_format_info(dev, fourcc, DRM_FORMAT_MOD_LINEAR);
|
||||
/* adreno needs pitch aligned to 32 pixels: */
|
||||
pitch = drm_format_info_min_pitch(format, 0, ALIGN(sizes->surface_width, 32));
|
||||
size = ALIGN(pitch * sizes->surface_height, PAGE_SIZE);
|
||||
|
||||
if (IS_ERR(fb)) {
|
||||
DRM_DEV_ERROR(dev->dev, "failed to allocate fb\n");
|
||||
return PTR_ERR(fb);
|
||||
/* allocate backing bo */
|
||||
DBG("allocating %llu bytes for fb %d", size, dev->primary->index);
|
||||
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC | MSM_BO_STOLEN, NULL);
|
||||
if (IS_ERR(bo)) {
|
||||
drm_warn(dev, "could not allocate stolen bo\n");
|
||||
/* try regular bo: */
|
||||
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC, NULL);
|
||||
if (IS_ERR(bo)) {
|
||||
drm_err(dev, "failed to allocate buffer object\n");
|
||||
return PTR_ERR(bo);
|
||||
}
|
||||
}
|
||||
|
||||
bo = msm_framebuffer_bo(fb, 0);
|
||||
msm_gem_object_set_name(bo, "stolenfb");
|
||||
|
||||
ret = drm_gem_handle_create(file, bo, &handle);
|
||||
if (ret)
|
||||
goto err_drm_gem_object_put;
|
||||
|
||||
buffer = drm_client_buffer_create(client, sizes->surface_width, sizes->surface_height,
|
||||
fourcc, handle, pitch);
|
||||
if (IS_ERR(buffer)) {
|
||||
ret = PTR_ERR(buffer);
|
||||
goto err_drm_gem_handle_delete;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: if we can be guaranteed to be able to map buffer
|
||||
|
|
@ -122,14 +144,15 @@ int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
|
|||
*/
|
||||
ret = msm_gem_get_and_pin_iova(bo, priv->kms->vm, &paddr);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev->dev, "failed to get buffer obj iova: %d\n", ret);
|
||||
goto fail;
|
||||
drm_err(dev, "failed to get buffer obj iova: %d\n", ret);
|
||||
goto err_drm_client_buffer_delete;
|
||||
}
|
||||
|
||||
DBG("fbi=%p, dev=%p", fbi, dev);
|
||||
|
||||
helper->funcs = &msm_fbdev_helper_funcs;
|
||||
helper->fb = fb;
|
||||
helper->buffer = buffer;
|
||||
helper->fb = buffer->fb;
|
||||
|
||||
fbi->fbops = &msm_fb_ops;
|
||||
|
||||
|
|
@ -138,18 +161,31 @@ int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
|
|||
fbi->screen_buffer = msm_gem_get_vaddr(bo);
|
||||
if (IS_ERR(fbi->screen_buffer)) {
|
||||
ret = PTR_ERR(fbi->screen_buffer);
|
||||
goto fail;
|
||||
goto err_msm_gem_unpin;
|
||||
}
|
||||
fbi->screen_size = bo->size;
|
||||
fbi->fix.smem_start = paddr;
|
||||
fbi->fix.smem_len = bo->size;
|
||||
|
||||
DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
|
||||
DBG("allocated %dx%d fb", fb->width, fb->height);
|
||||
DBG("allocated %dx%d fb", buffer->fb->width, buffer->fb->height);
|
||||
|
||||
/* The handle is only needed for creating the framebuffer. */
|
||||
drm_gem_handle_delete(file, handle);
|
||||
|
||||
/* The framebuffer still holds a reference on the GEM object. */
|
||||
drm_gem_object_put(bo);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
drm_framebuffer_remove(fb);
|
||||
err_msm_gem_unpin:
|
||||
msm_gem_unpin_iova(bo, priv->kms->vm);
|
||||
msm_gem_vma_put(bo);
|
||||
err_drm_client_buffer_delete:
|
||||
drm_client_buffer_delete(buffer);
|
||||
err_drm_gem_handle_delete:
|
||||
drm_gem_handle_delete(file, handle);
|
||||
err_drm_gem_object_put:
|
||||
drm_gem_object_put(bo);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1094,7 +1094,9 @@ static void msm_gem_free_object(struct drm_gem_object *obj)
|
|||
*/
|
||||
kvfree(msm_obj->pages);
|
||||
|
||||
drm_prime_gem_destroy(obj, msm_obj->sgt);
|
||||
/* In msm_gem_import() error path, sgt won't be set yet: */
|
||||
if (msm_obj->sgt)
|
||||
drm_prime_gem_destroy(obj, msm_obj->sgt);
|
||||
} else {
|
||||
msm_gem_vunmap(obj);
|
||||
put_pages(obj);
|
||||
|
|
@ -1135,10 +1137,21 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
|
|||
size_t size, uint32_t flags, uint32_t *handle,
|
||||
char *name)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_gem_object *obj, *r_obj = NULL;
|
||||
int ret;
|
||||
|
||||
obj = msm_gem_new(dev, size, flags);
|
||||
if (flags & MSM_BO_NO_SHARE) {
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_context *ctx = file->driver_priv;
|
||||
struct drm_gpuvm *vm = msm_context_vm(dev, ctx);
|
||||
|
||||
if (!priv->gpu || !vm)
|
||||
return UERR(EINVAL, dev, "not supported with shared VM");
|
||||
|
||||
r_obj = drm_gpuvm_resv_obj(vm);
|
||||
}
|
||||
|
||||
obj = msm_gem_new(dev, size, flags, r_obj);
|
||||
|
||||
if (IS_ERR(obj))
|
||||
return PTR_ERR(obj);
|
||||
|
|
@ -1146,15 +1159,6 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
|
|||
if (name)
|
||||
msm_gem_object_set_name(obj, "%s", name);
|
||||
|
||||
if (flags & MSM_BO_NO_SHARE) {
|
||||
struct msm_context *ctx = file->driver_priv;
|
||||
struct drm_gem_object *r_obj = drm_gpuvm_resv_obj(ctx->vm);
|
||||
|
||||
drm_gem_object_get(r_obj);
|
||||
|
||||
obj->resv = r_obj->resv;
|
||||
}
|
||||
|
||||
ret = drm_gem_handle_create(file, obj, handle);
|
||||
|
||||
/* drop reference from allocate - handle holds it now */
|
||||
|
|
@ -1233,10 +1237,27 @@ static int msm_gem_new_impl(struct drm_device *dev, uint32_t flags,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t flags)
|
||||
static int msm_gem_init_bookkeeping(struct drm_gem_object *obj)
|
||||
{
|
||||
struct msm_drm_private *priv = obj->dev->dev_private;
|
||||
|
||||
if (drm_gem_is_imported(obj)) {
|
||||
drm_gem_lru_move_tail(&priv->lru.pinned, obj);
|
||||
} else {
|
||||
drm_gem_lru_move_tail(&priv->lru.unbacked, obj);
|
||||
}
|
||||
|
||||
mutex_lock(&priv->obj_lock);
|
||||
list_add_tail(&to_msm_bo(obj)->node, &priv->objects);
|
||||
mutex_unlock(&priv->obj_lock);
|
||||
|
||||
return drm_gem_create_mmap_offset(obj);
|
||||
}
|
||||
|
||||
struct drm_gem_object *
|
||||
msm_gem_new(struct drm_device *dev, size_t size, uint32_t flags,
|
||||
struct drm_gem_object *r_obj)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_gem_object *msm_obj;
|
||||
struct drm_gem_object *obj = NULL;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1252,7 +1273,10 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t
|
|||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
msm_obj = to_msm_bo(obj);
|
||||
if (flags & MSM_BO_NO_SHARE) {
|
||||
drm_gem_object_get(r_obj);
|
||||
obj->resv = r_obj->resv;
|
||||
}
|
||||
|
||||
ret = drm_gem_object_init(dev, obj, size);
|
||||
if (ret)
|
||||
|
|
@ -1265,13 +1289,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t
|
|||
*/
|
||||
mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER);
|
||||
|
||||
drm_gem_lru_move_tail(&priv->lru.unbacked, obj);
|
||||
|
||||
mutex_lock(&priv->obj_lock);
|
||||
list_add_tail(&msm_obj->node, &priv->objects);
|
||||
mutex_unlock(&priv->obj_lock);
|
||||
|
||||
ret = drm_gem_create_mmap_offset(obj);
|
||||
ret = msm_gem_init_bookkeeping(obj);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -1283,11 +1301,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t
|
|||
}
|
||||
|
||||
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
|
||||
struct dma_buf *dmabuf, struct sg_table *sgt)
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sgt)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_gem_object *msm_obj;
|
||||
struct drm_gem_object *obj;
|
||||
struct dma_buf *dmabuf = attach->dmabuf;
|
||||
size_t size, npages;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1297,38 +1316,35 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
|
|||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/*
|
||||
* Set import_attach here in case we hit an error path that ends
|
||||
* up in drm_gem_object_put() -> msm_gem_free_object()
|
||||
*/
|
||||
obj->import_attach = attach;
|
||||
obj->resv = dmabuf->resv;
|
||||
drm_gem_private_object_init(dev, obj, size);
|
||||
|
||||
npages = size / PAGE_SIZE;
|
||||
|
||||
msm_obj = to_msm_bo(obj);
|
||||
msm_gem_lock(obj);
|
||||
msm_obj->sgt = sgt;
|
||||
msm_obj->pages = kvmalloc_objs(struct page *, npages);
|
||||
if (!msm_obj->pages) {
|
||||
msm_gem_unlock(obj);
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = drm_prime_sg_to_page_array(sgt, msm_obj->pages, npages);
|
||||
if (ret) {
|
||||
msm_gem_unlock(obj);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
msm_gem_unlock(obj);
|
||||
|
||||
drm_gem_lru_move_tail(&priv->lru.pinned, obj);
|
||||
|
||||
mutex_lock(&priv->obj_lock);
|
||||
list_add_tail(&msm_obj->node, &priv->objects);
|
||||
mutex_unlock(&priv->obj_lock);
|
||||
|
||||
ret = drm_gem_create_mmap_offset(obj);
|
||||
ret = msm_gem_init_bookkeeping(obj);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/* Now that we are past potential failure points, set sgt: */
|
||||
msm_obj->sgt = sgt;
|
||||
|
||||
return obj;
|
||||
|
||||
fail:
|
||||
|
|
@ -1341,7 +1357,7 @@ void *msm_gem_kernel_new(struct drm_device *dev, size_t size, uint32_t flags,
|
|||
uint64_t *iova)
|
||||
{
|
||||
void *vaddr;
|
||||
struct drm_gem_object *obj = msm_gem_new(dev, size, flags);
|
||||
struct drm_gem_object *obj = msm_gem_new(dev, size, flags, NULL);
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(obj))
|
||||
|
|
|
|||
|
|
@ -296,13 +296,14 @@ int msm_gem_cpu_fini(struct drm_gem_object *obj);
|
|||
int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
|
||||
size_t size, uint32_t flags, uint32_t *handle, char *name);
|
||||
struct drm_gem_object *msm_gem_new(struct drm_device *dev,
|
||||
size_t size, uint32_t flags);
|
||||
size_t size, uint32_t flags, struct drm_gem_object *r_obj);
|
||||
void *msm_gem_kernel_new(struct drm_device *dev, size_t size, uint32_t flags,
|
||||
struct drm_gpuvm *vm, struct drm_gem_object **bo,
|
||||
uint64_t *iova);
|
||||
void msm_gem_kernel_put(struct drm_gem_object *bo, struct drm_gpuvm *vm);
|
||||
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
|
||||
struct dma_buf *dmabuf, struct sg_table *sgt);
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sgt);
|
||||
__printf(2, 3)
|
||||
void msm_gem_object_set_name(struct drm_gem_object *bo, const char *fmt, ...);
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ struct drm_gem_object *msm_gem_prime_import(struct drm_device *dev,
|
|||
struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach, struct sg_table *sg)
|
||||
{
|
||||
return msm_gem_import(dev, attach->dmabuf, sg);
|
||||
return msm_gem_import(dev, attach, sg);
|
||||
}
|
||||
|
||||
struct dma_buf *msm_gem_prime_export(struct drm_gem_object *obj, int flags)
|
||||
|
|
|
|||
|
|
@ -30,20 +30,17 @@
|
|||
*/
|
||||
|
||||
static struct msm_gem_submit *submit_create(struct drm_device *dev,
|
||||
struct msm_gpu *gpu,
|
||||
struct msm_gpu *gpu, struct drm_gpuvm *vm,
|
||||
struct msm_gpu_submitqueue *queue, uint32_t nr_bos,
|
||||
uint32_t nr_cmds, u64 drm_client_id)
|
||||
{
|
||||
static atomic_t ident = ATOMIC_INIT(0);
|
||||
struct msm_gem_submit *submit;
|
||||
uint64_t sz;
|
||||
size_t sz;
|
||||
int ret;
|
||||
|
||||
sz = struct_size(submit, bos, nr_bos) +
|
||||
((u64)nr_cmds * sizeof(submit->cmd[0]));
|
||||
|
||||
if (sz > SIZE_MAX)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
sz = size_add(struct_size(submit, bos, nr_bos),
|
||||
array_size(sizeof(submit->cmd[0]), nr_cmds));
|
||||
|
||||
submit = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN);
|
||||
if (!submit)
|
||||
|
|
@ -66,7 +63,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
|
|||
|
||||
kref_init(&submit->ref);
|
||||
submit->dev = dev;
|
||||
submit->vm = msm_context_vm(dev, queue->ctx);
|
||||
submit->vm = vm;
|
||||
submit->gpu = gpu;
|
||||
submit->cmd = (void *)&submit->bos[nr_bos];
|
||||
submit->queue = queue;
|
||||
|
|
@ -250,16 +247,14 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit,
|
|||
|
||||
sz = array_size(submit_cmd.nr_relocs,
|
||||
sizeof(struct drm_msm_gem_submit_reloc));
|
||||
/* check for overflow: */
|
||||
if (sz == SIZE_MAX) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL | __GFP_NOWARN);
|
||||
if (!submit->cmd[i].relocs) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
submit->nr_cmds = i + 1;
|
||||
|
||||
ret = copy_from_user(submit->cmd[i].relocs, userptr, sz);
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
|
|
@ -554,6 +549,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
|||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct drm_msm_gem_submit *args = data;
|
||||
struct msm_context *ctx = file->driver_priv;
|
||||
struct drm_gpuvm *vm = msm_context_vm(dev, ctx);
|
||||
struct msm_gem_submit *submit = NULL;
|
||||
struct msm_gpu *gpu = priv->gpu;
|
||||
struct msm_gpu_submitqueue *queue;
|
||||
|
|
@ -569,10 +565,13 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
|||
if (!gpu)
|
||||
return -ENXIO;
|
||||
|
||||
if (!vm)
|
||||
return UERR(ENOMEM, dev, "no VM");
|
||||
|
||||
if (args->pad)
|
||||
return -EINVAL;
|
||||
|
||||
if (to_msm_vm(ctx->vm)->unusable)
|
||||
if (to_msm_vm(vm)->unusable)
|
||||
return UERR(EPIPE, dev, "context is unusable");
|
||||
|
||||
/* for now, we just have 3d pipe.. eventually this would need to
|
||||
|
|
@ -609,7 +608,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
|||
}
|
||||
}
|
||||
|
||||
submit = submit_create(dev, gpu, queue, args->nr_bos, args->nr_cmds,
|
||||
submit = submit_create(dev, gpu, vm, queue, args->nr_bos, args->nr_cmds,
|
||||
file->client_id);
|
||||
if (IS_ERR(submit)) {
|
||||
ret = PTR_ERR(submit);
|
||||
|
|
@ -719,8 +718,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
|||
goto out;
|
||||
}
|
||||
|
||||
submit->nr_cmds = args->nr_cmds;
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
|
||||
spin_lock(&queue->idr_lock);
|
||||
|
|
|
|||
|
|
@ -458,6 +458,8 @@ msm_gem_vm_bo_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
drm_gpuvm_bo_evict(vm_bo, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -955,7 +957,7 @@ msm_gem_vm_close(struct drm_gpuvm *gpuvm)
|
|||
|
||||
|
||||
static struct msm_vm_bind_job *
|
||||
vm_bind_job_create(struct drm_device *dev, struct drm_file *file,
|
||||
vm_bind_job_create(struct drm_device *dev, struct drm_file *file, struct drm_gpuvm *vm,
|
||||
struct msm_gpu_submitqueue *queue, uint32_t nr_ops)
|
||||
{
|
||||
struct msm_vm_bind_job *job;
|
||||
|
|
@ -972,7 +974,7 @@ vm_bind_job_create(struct drm_device *dev, struct drm_file *file,
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
job->vm = msm_context_vm(dev, queue->ctx);
|
||||
job->vm = vm;
|
||||
job->queue = queue;
|
||||
INIT_LIST_HEAD(&job->vm_ops);
|
||||
|
||||
|
|
@ -1431,6 +1433,7 @@ msm_ioctl_vm_bind(struct drm_device *dev, void *data, struct drm_file *file)
|
|||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct drm_msm_vm_bind *args = data;
|
||||
struct msm_context *ctx = file->driver_priv;
|
||||
struct drm_gpuvm *vm = msm_context_vm(dev, ctx);
|
||||
struct msm_vm_bind_job *job = NULL;
|
||||
struct msm_gpu *gpu = priv->gpu;
|
||||
struct msm_gpu_submitqueue *queue;
|
||||
|
|
@ -1445,11 +1448,14 @@ msm_ioctl_vm_bind(struct drm_device *dev, void *data, struct drm_file *file)
|
|||
if (!gpu)
|
||||
return -ENXIO;
|
||||
|
||||
if (!vm)
|
||||
return UERR(ENOMEM, dev, "no VM");
|
||||
|
||||
/*
|
||||
* Maybe we could allow just UNMAP ops? OTOH userspace should just
|
||||
* immediately close the device file and all will be torn down.
|
||||
*/
|
||||
if (to_msm_vm(msm_context_vm(dev, ctx))->unusable)
|
||||
if (to_msm_vm(vm)->unusable)
|
||||
return UERR(EPIPE, dev, "context is unusable");
|
||||
|
||||
/*
|
||||
|
|
@ -1480,7 +1486,7 @@ msm_ioctl_vm_bind(struct drm_device *dev, void *data, struct drm_file *file)
|
|||
}
|
||||
}
|
||||
|
||||
job = vm_bind_job_create(dev, file, queue, args->nr_ops);
|
||||
job = vm_bind_job_create(dev, file, vm, queue, args->nr_ops);
|
||||
if (IS_ERR(job)) {
|
||||
ret = PTR_ERR(job);
|
||||
goto out_post_unlock;
|
||||
|
|
|
|||
|
|
@ -505,6 +505,8 @@ static void recover_worker(struct kthread_work *work)
|
|||
*/
|
||||
if (!vm->managed)
|
||||
msm_gem_vm_unusable(submit->vm);
|
||||
|
||||
put_task_struct(task);
|
||||
}
|
||||
|
||||
noreclaim_flag = memalloc_noreclaim_save();
|
||||
|
|
@ -552,11 +554,13 @@ static void recover_worker(struct kthread_work *work)
|
|||
msm_update_fence(ring->fctx, fence);
|
||||
}
|
||||
|
||||
/* retire completed submits, plus the one that hung: */
|
||||
retire_submits(gpu);
|
||||
priv->disable_err_irq = false;
|
||||
|
||||
gpu->funcs->recover(gpu);
|
||||
|
||||
/* retire completed submits, plus the one that hung: */
|
||||
retire_submits(gpu);
|
||||
|
||||
/*
|
||||
* Replay all remaining submits starting with highest priority
|
||||
* ring
|
||||
|
|
@ -875,7 +879,7 @@ msm_gpu_create_private_vm(struct msm_gpu *gpu, struct task_struct *task,
|
|||
to_msm_vm(vm)->pid = get_pid(task_pid(task));
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(vm))
|
||||
if (IS_ERR_OR_NULL(vm) && kernel_managed)
|
||||
vm = drm_gpuvm_get(gpu->vm);
|
||||
|
||||
return vm;
|
||||
|
|
|
|||
|
|
@ -392,8 +392,8 @@ msm_gpu_sysprof_no_ifpc(struct msm_gpu *gpu)
|
|||
* struct msm_context - per-drm_file context
|
||||
*/
|
||||
struct msm_context {
|
||||
/** @queuelock: synchronizes access to submitqueues list */
|
||||
rwlock_t queuelock;
|
||||
/** @ctxlock: synchronizes access to submitqueues list, etc */
|
||||
struct rw_semaphore ctxlock;
|
||||
/** @submitqueues: list of &msm_gpu_submitqueue created by userspace */
|
||||
struct list_head submitqueues;
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,6 +7,15 @@
|
|||
#include <linux/adreno-smmu-priv.h>
|
||||
#include <linux/io-pgtable.h>
|
||||
#include <linux/kmemleak.h>
|
||||
|
||||
#if defined(CONFIG_ARM_DMA_USE_IOMMU)
|
||||
#include <asm/dma-iommu.h>
|
||||
#else
|
||||
#define arm_iommu_detach_device(...) ({ })
|
||||
#define arm_iommu_release_mapping(...) ({ })
|
||||
#define to_dma_iommu_mapping(dev) NULL
|
||||
#endif
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "msm_gpu_trace.h"
|
||||
#include "msm_mmu.h"
|
||||
|
|
@ -749,6 +758,19 @@ struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks)
|
|||
|
||||
mutex_init(&iommu->init_lock);
|
||||
|
||||
/*
|
||||
* ARM32 attaches a DMA mapping domain to every IOMMU-backed device,
|
||||
* which would make attaching our own domain fail with -EBUSY.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
|
||||
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
|
||||
|
||||
if (mapping) {
|
||||
arm_iommu_detach_device(dev);
|
||||
arm_iommu_release_mapping(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
ret = iommu_attach_device(iommu->domain, dev);
|
||||
if (ret) {
|
||||
iommu_domain_free(domain);
|
||||
|
|
|
|||
|
|
@ -109,9 +109,9 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
|
|||
ring->memptrs_iova = memptrs_iova;
|
||||
|
||||
ret = drm_sched_init(&ring->sched, &args);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
ring->sched_initialized = true;
|
||||
|
||||
INIT_LIST_HEAD(&ring->submits);
|
||||
spin_lock_init(&ring->submit_lock);
|
||||
|
|
@ -133,7 +133,8 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring)
|
|||
if (IS_ERR_OR_NULL(ring))
|
||||
return;
|
||||
|
||||
drm_sched_fini(&ring->sched);
|
||||
if (ring->sched_initialized)
|
||||
drm_sched_fini(&ring->sched);
|
||||
|
||||
msm_fence_context_free(ring->fctx);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ struct msm_ringbuffer {
|
|||
* The job scheduler for this ring.
|
||||
*/
|
||||
struct drm_gpu_scheduler sched;
|
||||
bool sched_initialized;
|
||||
|
||||
/*
|
||||
* List of in-flight submits on this ring. Protected by submit_lock.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
int msm_context_set_sysprof(struct msm_context *ctx, struct msm_gpu *gpu, int sysprof)
|
||||
{
|
||||
guard(rwsem_write)(&ctx->ctxlock);
|
||||
|
||||
/*
|
||||
* Since pm_runtime and sysprof_active are both refcounts, we
|
||||
* call apply the new value first, and then unwind the previous
|
||||
|
|
@ -93,18 +95,15 @@ struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_context *ctx,
|
|||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
read_lock(&ctx->queuelock);
|
||||
guard(rwsem_read)(&ctx->ctxlock);
|
||||
|
||||
list_for_each_entry(entry, &ctx->submitqueues, node) {
|
||||
if (entry->id == id) {
|
||||
kref_get(&entry->ref);
|
||||
read_unlock(&ctx->queuelock);
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
read_unlock(&ctx->queuelock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -175,6 +174,7 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
|
|||
struct msm_drm_private *priv = drm->dev_private;
|
||||
struct msm_gpu_submitqueue *queue;
|
||||
enum drm_sched_priority sched_prio;
|
||||
struct drm_gpuvm *vm = NULL;
|
||||
unsigned ring_nr;
|
||||
int ret;
|
||||
|
||||
|
|
@ -187,6 +187,11 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
|
|||
if (flags & MSM_SUBMITQUEUE_VM_BIND) {
|
||||
unsigned sz;
|
||||
|
||||
vm = msm_context_vm(drm, ctx);
|
||||
|
||||
if (!vm)
|
||||
return UERR(ENOMEM, drm, "no VM");
|
||||
|
||||
/* Not allowed for kernel managed VMs (ie. kernel allocs VA) */
|
||||
if (!msm_context_is_vmbind(ctx))
|
||||
return -EINVAL;
|
||||
|
|
@ -218,7 +223,7 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
|
|||
queue->flags = flags;
|
||||
|
||||
if (flags & MSM_SUBMITQUEUE_VM_BIND) {
|
||||
struct drm_gpu_scheduler *sched = &to_msm_vm(msm_context_vm(drm, ctx))->sched;
|
||||
struct drm_gpu_scheduler *sched = &to_msm_vm(vm)->sched;
|
||||
|
||||
queue->entity = &queue->_vm_bind_entity[0];
|
||||
|
||||
|
|
@ -237,7 +242,7 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
|
|||
return ret;
|
||||
}
|
||||
|
||||
write_lock(&ctx->queuelock);
|
||||
guard(rwsem_write)(&ctx->ctxlock);
|
||||
|
||||
queue->ctx = msm_context_get(ctx);
|
||||
queue->id = ctx->queueid++;
|
||||
|
|
@ -251,8 +256,6 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
|
|||
|
||||
list_add_tail(&queue->node, &ctx->submitqueues);
|
||||
|
||||
write_unlock(&ctx->queuelock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -335,19 +338,16 @@ int msm_submitqueue_remove(struct msm_context *ctx, u32 id)
|
|||
if (!id)
|
||||
return -ENOENT;
|
||||
|
||||
write_lock(&ctx->queuelock);
|
||||
guard(rwsem_write)(&ctx->ctxlock);
|
||||
|
||||
list_for_each_entry(entry, &ctx->submitqueues, node) {
|
||||
if (entry->id == id) {
|
||||
list_del(&entry->node);
|
||||
write_unlock(&ctx->queuelock);
|
||||
|
||||
msm_submitqueue_put(entry);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
write_unlock(&ctx->queuelock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1495,6 +1495,8 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
|
|||
<reg32 offset="0x3058" name="VBIF_OUT_AXI_AMEMTYPE_CONF0"/>
|
||||
<reg32 offset="0x305e" name="VBIF_OUT_AXI_AOOO_EN"/>
|
||||
<reg32 offset="0x305f" name="VBIF_OUT_AXI_AOOO"/>
|
||||
<reg32 offset="0x3080" name="VBIF_XIN_HALT_CTRL0"/>
|
||||
<reg32 offset="0x3081" name="VBIF_XIN_HALT_CTRL1"/>
|
||||
|
||||
<bitset name="a3xx_vbif_perf_cnt" inline="yes">
|
||||
<bitfield name="CNT0" pos="0" type="boolean"/>
|
||||
|
|
|
|||
|
|
@ -1268,7 +1268,7 @@ by a particular renderpass/blit.
|
|||
<reg32 offset="0x3119" name="VBIF_PERF_PWR_CNT_HIGH1" variants="A6XX"/>
|
||||
<reg32 offset="0x311a" name="VBIF_PERF_PWR_CNT_HIGH2" variants="A6XX"/>
|
||||
|
||||
<reg32 offset="0x3c00" name="GBIF_CX_CONFIG" variants="A8XX-"/>
|
||||
<reg32 offset="0x3c00" name="GBIF_CX_CONFIG" variants="A6XX-"/>
|
||||
<reg32 offset="0x3c01" name="GBIF_SCACHE_CNTL0"/>
|
||||
<reg32 offset="0x3c02" name="GBIF_SCACHE_CNTL1"/>
|
||||
<reg32 offset="0x3c03" name="GBIF_QSB_SIDE0"/>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
* Alex Deucher
|
||||
*/
|
||||
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#include <drm/drm_fixed.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
|
|
@ -594,7 +596,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
|||
if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
|
||||
&& !radeon_crtc->ss_enabled)
|
||||
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
|
||||
if (ASIC_IS_DCE32(rdev) && mode->clock > 165000)
|
||||
if ((ASIC_IS_DCE32(rdev) || dmi_match(DMI_PRODUCT_NAME, "iMac11,1"))
|
||||
&& mode->clock > 165000)
|
||||
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
|
||||
} else {
|
||||
radeon_crtc->pll_flags |= RADEON_PLL_LEGACY;
|
||||
|
|
|
|||
|
|
@ -1707,7 +1707,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
|
|||
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
|
||||
/* DP_SET_POWER_D0 is set in radeon_dp_link_train */
|
||||
radeon_dp_link_train(encoder, connector);
|
||||
if (ASIC_IS_DCE4(rdev))
|
||||
if (ASIC_IS_DCE4(rdev) || dmi_match(DMI_PRODUCT_NAME, "iMac11,1"))
|
||||
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
|
||||
}
|
||||
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
|
||||
|
|
@ -2123,17 +2123,20 @@ int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
|
|||
}
|
||||
|
||||
/*
|
||||
* On DCE32 any encoder can drive any block so usually just use crtc id,
|
||||
* but Apple thinks different at least on iMac10,1 and iMac11,2, so there use linkb,
|
||||
* otherwise the internal eDP panel will stay dark.
|
||||
* Apple routes the internal eDP panel through Link B of the DIG encoder
|
||||
* instead of Link A on the iMac10,1, iMac11,1 and iMac11,2.
|
||||
* Use linkb to avoid a dark display.
|
||||
*/
|
||||
if (ASIC_IS_DCE32(rdev)) {
|
||||
if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "iMac11,2"))
|
||||
enc_idx = (dig->linkb) ? 1 : 0;
|
||||
else
|
||||
enc_idx = radeon_crtc->crtc_id;
|
||||
if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "iMac11,1") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "iMac11,2")) {
|
||||
enc_idx = (dig->linkb) ? 1 : 0;
|
||||
goto assigned;
|
||||
}
|
||||
|
||||
/* on DCE32 and encoder can driver any block so just crtc id */
|
||||
if (ASIC_IS_DCE32(rdev)) {
|
||||
enc_idx = radeon_crtc->crtc_id;
|
||||
goto assigned;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,9 @@ xe-y += xe_bb.o \
|
|||
xe_wait_user_fence.o \
|
||||
xe_wopcm.o
|
||||
|
||||
xe-$(CONFIG_I2C) += xe_i2c.o
|
||||
xe-$(CONFIG_I2C) += xe_i2c.o \
|
||||
xe_amc.o
|
||||
|
||||
xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
|
||||
xe-$(CONFIG_DRM_GPUSVM) += xe_userptr.o
|
||||
|
||||
|
|
|
|||
|
|
@ -20,4 +20,6 @@
|
|||
#define I2C_CONFIG_CMD XE_REG(I2C_CONFIG_SPACE_OFFSET + PCI_COMMAND)
|
||||
#define I2C_CONFIG_PMCSR XE_REG(I2C_CONFIG_SPACE_OFFSET + 0x84)
|
||||
|
||||
#define I2C_REG(reg) XE_REG((reg) + I2C_MEM_SPACE_OFFSET)
|
||||
|
||||
#endif /* _XE_I2C_REGS_H_ */
|
||||
|
|
|
|||
|
|
@ -198,8 +198,7 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test,
|
|||
|
||||
err = xe_bo_vmap(bo);
|
||||
if (err) {
|
||||
KUNIT_FAIL(test, "Failed to vmap our pagetables: %li\n",
|
||||
PTR_ERR(bo));
|
||||
KUNIT_FAIL(test, "Failed to vmap our pagetables: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
197
drivers/gpu/drm/xe/xe_amc.c
Normal file
197
drivers/gpu/drm/xe/xe_amc.c
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "regs/xe_i2c_regs.h"
|
||||
|
||||
#include "xe_amc.h"
|
||||
#include "xe_device.h"
|
||||
#include "xe_i2c.h"
|
||||
#include "xe_mmio.h"
|
||||
|
||||
/**
|
||||
* DOC: Add-In Management Controller (AMC)
|
||||
*
|
||||
* Handler for the SMBus Alerts from the AMC. All the alerts from AMC will cause
|
||||
* the device to be declared wedged.
|
||||
*/
|
||||
|
||||
#define AMC_COMMAND 0x0f
|
||||
#define AMC_GPU_I2C_ADDR 0x8f
|
||||
#define AMC_VERSION_V1 0x01
|
||||
#define AMC_DESTINATION_ID 12
|
||||
#define AMC_SOURCE_ID 8
|
||||
#define AMC_FLAGS 0xc8
|
||||
|
||||
#define AMC_MSG_TYPE 0x7e
|
||||
#define AMC_GET_ALERT_REASON 0x01
|
||||
|
||||
enum xe_amc_alert {
|
||||
AMC_ALERT_UNKNOWN,
|
||||
AMC_ALERT_FW_DOWNLOAD,
|
||||
AMC_ALERT_THERMAL_TRIP,
|
||||
AMC_ALERT_OOB_REQUEST,
|
||||
AMC_ALERT_OOB_RESET,
|
||||
AMC_ALERT_CATERR,
|
||||
};
|
||||
|
||||
static const char * const amc_alert[] = {
|
||||
[AMC_ALERT_FW_DOWNLOAD] = "Firmware Download",
|
||||
[AMC_ALERT_THERMAL_TRIP] = "Thermal Trip",
|
||||
[AMC_ALERT_OOB_REQUEST] = "OOB Request",
|
||||
[AMC_ALERT_OOB_RESET] = "OOB Reset",
|
||||
[AMC_ALERT_CATERR] = "Catastrophic",
|
||||
};
|
||||
|
||||
struct xe_amc {
|
||||
struct xe_i2c *i2c;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
struct amc_header {
|
||||
u8 command;
|
||||
u8 len;
|
||||
u8 address;
|
||||
u8 version;
|
||||
u8 destination;
|
||||
u8 source;
|
||||
u8 flags;
|
||||
} __packed;
|
||||
|
||||
struct amc_message {
|
||||
u8 type;
|
||||
u16 vendor;
|
||||
u8 command;
|
||||
} __packed;
|
||||
|
||||
struct amc_request {
|
||||
struct amc_header header;
|
||||
struct amc_message message;
|
||||
u32 reserved;
|
||||
} __packed;
|
||||
|
||||
struct amc_response {
|
||||
struct amc_header header;
|
||||
struct amc_message message;
|
||||
u8 error;
|
||||
u8 value;
|
||||
} __packed;
|
||||
|
||||
static const struct amc_request amc_get_alert_reason = {
|
||||
.header = {
|
||||
.command = AMC_COMMAND,
|
||||
.len = sizeof(struct amc_request) - 2,
|
||||
.address = AMC_GPU_I2C_ADDR,
|
||||
.version = AMC_VERSION_V1,
|
||||
.destination = AMC_DESTINATION_ID,
|
||||
.source = AMC_SOURCE_ID,
|
||||
.flags = AMC_FLAGS,
|
||||
},
|
||||
.message = {
|
||||
.type = AMC_MSG_TYPE,
|
||||
.vendor = htons(PCI_VENDOR_ID_INTEL),
|
||||
.command = AMC_GET_ALERT_REASON,
|
||||
},
|
||||
};
|
||||
|
||||
static void xe_amc_work(struct work_struct *work)
|
||||
{
|
||||
const struct amc_request *request = &amc_get_alert_reason;
|
||||
struct xe_amc *amc = from_work(amc, work, work);
|
||||
u8 alert_reason = AMC_ALERT_UNKNOWN;
|
||||
struct amc_response response;
|
||||
struct i2c_client *client;
|
||||
int ret;
|
||||
|
||||
client = amc->i2c->client[XE_I2C_CLIENT_AMC];
|
||||
if (IS_ERR_OR_NULL(client))
|
||||
goto out_reassert_interrupt;
|
||||
|
||||
ret = i2c_master_send(client, (u8 *)request, sizeof(*request));
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to send request (%d)\n", ret);
|
||||
goto out_reassert_interrupt;
|
||||
}
|
||||
|
||||
/* AMC needs 20ms to generate the response. */
|
||||
fsleep(20 * USEC_PER_MSEC);
|
||||
|
||||
ret = i2c_master_recv(client, (u8 *)&response, sizeof(response));
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to read response (%d)\n", ret);
|
||||
goto out_reassert_interrupt;
|
||||
}
|
||||
|
||||
if (!response.header.len) {
|
||||
dev_err(&client->dev, "empty response from AMC\n");
|
||||
goto out_reassert_interrupt;
|
||||
}
|
||||
|
||||
if (memcmp(&response.message, &request->message, sizeof(struct amc_message))) {
|
||||
dev_err(&client->dev, "response does not match the request\n");
|
||||
goto out_reassert_interrupt;
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
dev_err(&client->dev, "AMC error 0x%02x\n", response.error);
|
||||
goto out_reassert_interrupt;
|
||||
}
|
||||
|
||||
alert_reason = response.value;
|
||||
dev_dbg(&client->dev, "Alert reason: %d\n", alert_reason);
|
||||
|
||||
out_reassert_interrupt:
|
||||
xe_mmio_rmw32(amc->i2c->mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0);
|
||||
|
||||
switch (alert_reason) {
|
||||
case AMC_ALERT_FW_DOWNLOAD:
|
||||
case AMC_ALERT_THERMAL_TRIP:
|
||||
case AMC_ALERT_OOB_REQUEST:
|
||||
case AMC_ALERT_OOB_RESET:
|
||||
case AMC_ALERT_CATERR:
|
||||
dev_warn(amc->i2c->drm_dev, "AMC Alert: %s\n", amc_alert[alert_reason]);
|
||||
xe_device_declare_wedged(i2c_client_to_xe_device(client));
|
||||
break;
|
||||
default:
|
||||
dev_warn(amc->i2c->drm_dev, "unknown AMC alert: %d\n", alert_reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void xe_amc_handle_alert(struct xe_i2c *i2c)
|
||||
{
|
||||
queue_work(system_long_wq, &i2c->amc->work);
|
||||
}
|
||||
|
||||
int xe_amc_init(struct xe_i2c *i2c)
|
||||
{
|
||||
struct xe_amc *amc;
|
||||
|
||||
amc = kzalloc(sizeof(*amc), GFP_KERNEL);
|
||||
if (!amc)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&amc->work, xe_amc_work);
|
||||
i2c->amc = amc;
|
||||
amc->i2c = i2c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xe_amc_exit(struct xe_i2c *i2c)
|
||||
{
|
||||
if (i2c->amc) {
|
||||
cancel_work_sync(&i2c->amc->work);
|
||||
kfree(i2c->amc);
|
||||
}
|
||||
}
|
||||
25
drivers/gpu/drm/xe/xe_amc.h
Normal file
25
drivers/gpu/drm/xe/xe_amc.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _XE_AMC_H_
|
||||
#define _XE_AMC_H_
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include "xe_device.h"
|
||||
|
||||
struct xe_i2c;
|
||||
|
||||
static inline struct xe_device *i2c_adapter_to_xe_device(struct i2c_adapter *adapter)
|
||||
{
|
||||
return kdev_to_xe_device(adapter->dev.parent->parent);
|
||||
}
|
||||
|
||||
static inline struct xe_device *i2c_client_to_xe_device(struct i2c_client *client)
|
||||
{
|
||||
return i2c_adapter_to_xe_device(client->adapter);
|
||||
}
|
||||
|
||||
int xe_amc_init(struct xe_i2c *i2c);
|
||||
void xe_amc_exit(struct xe_i2c *i2c);
|
||||
void xe_amc_handle_alert(struct xe_i2c *i2c);
|
||||
|
||||
#endif /* _XE_AMC_H_ */
|
||||
|
|
@ -248,7 +248,8 @@ int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p)
|
|||
pg_status = xe_mmio_read32(>->mmio, POWERGATE_DOMAIN_STATUS);
|
||||
}
|
||||
|
||||
if (gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK) {
|
||||
if (gt->info.engine_mask &
|
||||
(XE_HW_ENGINE_RCS_MASK | XE_HW_ENGINE_CCS_MASK)) {
|
||||
drm_printf(p, "Render Power Gating Enabled: %s\n",
|
||||
str_yes_no(pg_enabled & RENDER_POWERGATE_ENABLE));
|
||||
|
||||
|
|
|
|||
|
|
@ -1559,8 +1559,14 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
|
|||
if (!skip_timeout_check && !check_timeout(q, job))
|
||||
goto rearm;
|
||||
|
||||
/*
|
||||
* Killed queues must not newly wedge the device, but preserve an
|
||||
* already-wedged state to avoid warning on teardown timeouts.
|
||||
*/
|
||||
if (!exec_queue_killed(q))
|
||||
wedged = guc_submit_hint_wedged(exec_queue_to_guc(q));
|
||||
else
|
||||
wedged = xe_device_wedged(xe);
|
||||
|
||||
set_exec_queue_banned(q);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@
|
|||
#include <drm/drm_print.h>
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -24,9 +23,12 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/designware_i2c.h>
|
||||
|
||||
#include "regs/xe_i2c_regs.h"
|
||||
#include "regs/xe_irq_regs.h"
|
||||
|
||||
#include "xe_amc.h"
|
||||
#include "xe_device.h"
|
||||
#include "xe_i2c.h"
|
||||
#include "xe_mmio.h"
|
||||
|
|
@ -61,16 +63,32 @@ static inline void xe_i2c_read_endpoint(struct xe_mmio *mmio, void *ep)
|
|||
val[1] = xe_mmio_read32(mmio, REG_SG_REMAP_ADDR_POSTFIX);
|
||||
}
|
||||
|
||||
static void xe_i2c_handle_smbus_alert(struct xe_i2c *i2c)
|
||||
{
|
||||
u32 stat;
|
||||
|
||||
stat = xe_mmio_read32(i2c->mmio, I2C_REG(DW_IC_SMBUS_INTR_STAT));
|
||||
if (!stat)
|
||||
return;
|
||||
|
||||
xe_mmio_write32(i2c->mmio, I2C_REG(DW_IC_CLR_SMBUS_INTR), stat);
|
||||
|
||||
if (stat & DW_IC_SMBUS_INTR_ALERT && i2c->amc)
|
||||
xe_amc_handle_alert(i2c);
|
||||
else
|
||||
xe_mmio_rmw32(i2c->mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0);
|
||||
}
|
||||
|
||||
static void xe_i2c_client_work(struct work_struct *work)
|
||||
{
|
||||
struct xe_i2c *i2c = container_of(work, struct xe_i2c, work);
|
||||
struct i2c_board_info info = {
|
||||
.type = "amc",
|
||||
.flags = I2C_CLIENT_HOST_NOTIFY,
|
||||
.addr = i2c->ep.addr[1],
|
||||
.addr = i2c->ep.addr[XE_I2C_CLIENT_AMC],
|
||||
};
|
||||
|
||||
i2c->client[0] = i2c_new_client_device(i2c->adapter, &info);
|
||||
i2c->client[XE_I2C_CLIENT_AMC] = i2c_new_client_device(i2c->adapter, &info);
|
||||
}
|
||||
|
||||
static int xe_i2c_notifier(struct notifier_block *nb, unsigned long action, void *data)
|
||||
|
|
@ -114,16 +132,6 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c)
|
|||
if (ret)
|
||||
goto err_pdev_put;
|
||||
|
||||
if (i2c->adapter_irq) {
|
||||
struct resource res;
|
||||
|
||||
res = DEFINE_RES_IRQ_NAMED(i2c->adapter_irq, "xe_i2c");
|
||||
|
||||
ret = platform_device_add_resources(pdev, &res, 1);
|
||||
if (ret)
|
||||
goto err_pdev_put;
|
||||
}
|
||||
|
||||
pdev->dev.parent = i2c->drm_dev;
|
||||
i2c->pdev = pdev;
|
||||
|
||||
|
|
@ -160,7 +168,8 @@ bool xe_i2c_present(struct xe_device *xe)
|
|||
|
||||
static bool xe_i2c_irq_present(struct xe_device *xe)
|
||||
{
|
||||
return xe->i2c && xe->i2c->adapter_irq;
|
||||
return xe->i2c && xe->i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ &&
|
||||
!xe_survivability_mode_is_boot_enabled(xe);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -173,18 +182,10 @@ static bool xe_i2c_irq_present(struct xe_device *xe)
|
|||
*/
|
||||
void xe_i2c_irq_handler(struct xe_device *xe, u32 master_ctl)
|
||||
{
|
||||
struct xe_mmio *mmio = xe_root_tile_mmio(xe);
|
||||
|
||||
if (!(master_ctl & I2C_IRQ) || !xe_i2c_irq_present(xe))
|
||||
return;
|
||||
|
||||
/* Forward interrupt to I2C adapter */
|
||||
generic_handle_irq_safe(xe->i2c->adapter_irq);
|
||||
|
||||
/* Deassert after I2C adapter clears the interrupt */
|
||||
xe_mmio_rmw32(mmio, I2C_CONFIG_CMD, 0, PCI_COMMAND_INTX_DISABLE);
|
||||
/* Reassert to allow subsequent interrupt generation */
|
||||
xe_mmio_rmw32(mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0);
|
||||
xe_i2c_handle_smbus_alert(xe->i2c);
|
||||
}
|
||||
|
||||
void xe_i2c_irq_reset(struct xe_device *xe)
|
||||
|
|
@ -209,50 +210,40 @@ void xe_i2c_irq_postinstall(struct xe_device *xe)
|
|||
xe_mmio_rmw32(mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0);
|
||||
}
|
||||
|
||||
static int xe_i2c_irq_map(struct irq_domain *h, unsigned int virq,
|
||||
irq_hw_number_t hw_irq_num)
|
||||
/* See "Disabling DW_apb_i2c" in the DesignWare DW_abp_i2c databook. */
|
||||
static void xe_i2c_disable(struct xe_i2c *i2c)
|
||||
{
|
||||
irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq);
|
||||
return 0;
|
||||
}
|
||||
int timeout = 100;
|
||||
u32 status;
|
||||
|
||||
static const struct irq_domain_ops xe_i2c_irq_ops = {
|
||||
.map = xe_i2c_irq_map,
|
||||
};
|
||||
xe_mmio_rmw32(i2c->mmio, I2C_REG(DW_IC_ENABLE), DW_IC_ENABLE_ENABLE, 0);
|
||||
|
||||
static int xe_i2c_create_irq(struct xe_device *xe)
|
||||
{
|
||||
struct xe_i2c *i2c = xe->i2c;
|
||||
struct irq_domain *domain;
|
||||
do {
|
||||
status = xe_mmio_read32(i2c->mmio, I2C_REG(DW_IC_ENABLE_STATUS));
|
||||
if (!(status & DW_IC_ENABLE_ENABLE))
|
||||
return;
|
||||
/* Can't sleep here. */
|
||||
udelay(25);
|
||||
} while (timeout--);
|
||||
|
||||
if (!(i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ) ||
|
||||
xe_survivability_mode_is_boot_enabled(xe))
|
||||
return 0;
|
||||
|
||||
domain = irq_domain_create_linear(dev_fwnode(i2c->drm_dev), 1, &xe_i2c_irq_ops, NULL);
|
||||
if (!domain)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c->adapter_irq = irq_create_mapping(domain, 0);
|
||||
i2c->irqdomain = domain;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xe_i2c_remove_irq(struct xe_i2c *i2c)
|
||||
{
|
||||
if (!i2c->irqdomain)
|
||||
return;
|
||||
|
||||
irq_dispose_mapping(i2c->adapter_irq);
|
||||
irq_domain_remove(i2c->irqdomain);
|
||||
dev_warn(i2c->drm_dev, "timeout in disabling i2c adapter\n");
|
||||
}
|
||||
|
||||
static int xe_i2c_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct xe_i2c *i2c = context;
|
||||
|
||||
*val = xe_mmio_read32(i2c->mmio, XE_REG(reg + I2C_MEM_SPACE_OFFSET));
|
||||
*val = xe_mmio_read32(i2c->mmio, I2C_REG(reg));
|
||||
|
||||
switch (reg) {
|
||||
case DW_IC_ENABLE:
|
||||
case DW_IC_ENABLE_STATUS:
|
||||
FIELD_MODIFY(DW_IC_ENABLE_ENABLE, val,
|
||||
i2c->ic_enable & DW_IC_ENABLE_ENABLE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -261,8 +252,33 @@ static int xe_i2c_write(void *context, unsigned int reg, unsigned int val)
|
|||
{
|
||||
struct xe_i2c *i2c = context;
|
||||
|
||||
xe_mmio_write32(i2c->mmio, XE_REG(reg + I2C_MEM_SPACE_OFFSET), val);
|
||||
switch (reg) {
|
||||
case DW_IC_CON:
|
||||
case DW_IC_TAR:
|
||||
case DW_IC_SAR:
|
||||
/* Disable the controller. */
|
||||
xe_i2c_disable(i2c);
|
||||
|
||||
/* Write the register. */
|
||||
xe_mmio_write32(i2c->mmio, I2C_REG(reg), val);
|
||||
|
||||
/* Enable the controller. */
|
||||
xe_mmio_rmw32(i2c->mmio, I2C_REG(DW_IC_ENABLE), 0, DW_IC_ENABLE_ENABLE);
|
||||
return 0;
|
||||
case DW_IC_ENABLE:
|
||||
i2c->ic_enable = val;
|
||||
/* Other fields can be updated except the enable bit. */
|
||||
val |= DW_IC_ENABLE_ENABLE;
|
||||
break;
|
||||
case DW_IC_SMBUS_INTR_MASK:
|
||||
/* Make sure the Alert is never masked. */
|
||||
val |= DW_IC_SMBUS_INTR_ALERT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
xe_mmio_write32(i2c->mmio, I2C_REG(reg), val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -304,12 +320,15 @@ static void xe_i2c_remove(void *data)
|
|||
struct xe_i2c *i2c = data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < XE_I2C_MAX_CLIENTS; i++)
|
||||
xe_amc_exit(i2c);
|
||||
|
||||
for (i = 0; i < XE_I2C_MAX_CLIENTS; i++) {
|
||||
i2c_unregister_device(i2c->client[i]);
|
||||
i2c->client[i] = NULL;
|
||||
}
|
||||
|
||||
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
|
||||
xe_i2c_unregister_adapter(i2c);
|
||||
xe_i2c_remove_irq(i2c);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -357,22 +376,18 @@ int xe_i2c_probe(struct xe_device *xe)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xe_i2c_create_irq(xe);
|
||||
if (ret)
|
||||
goto err_unregister_notifier;
|
||||
|
||||
ret = xe_i2c_register_adapter(i2c);
|
||||
if (ret)
|
||||
goto err_remove_irq;
|
||||
if (ret) {
|
||||
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = xe_amc_init(i2c);
|
||||
if (ret) {
|
||||
xe_i2c_remove(i2c);
|
||||
return ret;
|
||||
}
|
||||
|
||||
xe_i2c_irq_postinstall(xe);
|
||||
return devm_add_action_or_reset(drm_dev, xe_i2c_remove, i2c);
|
||||
|
||||
err_remove_irq:
|
||||
xe_i2c_remove_irq(i2c);
|
||||
|
||||
err_unregister_notifier:
|
||||
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,18 +11,21 @@ struct device;
|
|||
struct fwnode_handle;
|
||||
struct i2c_adapter;
|
||||
struct i2c_client;
|
||||
struct irq_domain;
|
||||
struct platform_device;
|
||||
struct xe_amc;
|
||||
struct xe_device;
|
||||
struct xe_mmio;
|
||||
|
||||
#define XE_I2C_MAX_CLIENTS 3
|
||||
|
||||
#define XE_I2C_EP_COOKIE_DEVICE 0xde
|
||||
|
||||
/* Endpoint Capabilities */
|
||||
#define XE_I2C_EP_CAP_IRQ BIT(0)
|
||||
|
||||
enum XE_I2C_CLIENT {
|
||||
XE_I2C_CLIENT_AMC = 1,
|
||||
XE_I2C_MAX_CLIENTS = 3,
|
||||
};
|
||||
|
||||
struct xe_i2c_endpoint {
|
||||
u8 cookie;
|
||||
u8 capabilities;
|
||||
|
|
@ -33,17 +36,16 @@ struct xe_i2c {
|
|||
struct platform_device *pdev;
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client[XE_I2C_MAX_CLIENTS];
|
||||
unsigned int ic_enable;
|
||||
|
||||
struct notifier_block bus_notifier;
|
||||
struct work_struct work;
|
||||
|
||||
struct irq_domain *irqdomain;
|
||||
int adapter_irq;
|
||||
|
||||
struct xe_i2c_endpoint ep;
|
||||
struct device *drm_dev;
|
||||
|
||||
struct xe_mmio *mmio;
|
||||
struct xe_amc *amc;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ static struct xe_vm *xe_pagefault_asid_to_vm(struct xe_device *xe, u32 asid)
|
|||
|
||||
down_read(&xe->usm.lock);
|
||||
vm = xa_load(&xe->usm.asid_to_vm, asid);
|
||||
if (vm && (xe_vm_in_fault_mode(vm) || xe_vm_has_scratch(vm)))
|
||||
if (vm && xe_vm_in_fault_mode(vm))
|
||||
xe_vm_get(vm);
|
||||
else
|
||||
vm = ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ int xe_sysctrl_init(struct xe_device *xe)
|
|||
return ret;
|
||||
|
||||
xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
|
||||
xe_sysctrl_mailbox_init(sc);
|
||||
INIT_WORK(&sc->work, xe_sysctrl_work);
|
||||
|
||||
return devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe);
|
||||
|
|
@ -114,12 +113,10 @@ void xe_sysctrl_irq_handler(struct xe_device *xe, u32 master_ctl)
|
|||
* @xe: xe device instance
|
||||
*
|
||||
* Invoked during system resume (S3/S4 to S0) and runtime resume from D3cold.
|
||||
* Restores SoC remapper configuration and reinitializes mailbox interface.
|
||||
* Restores SoC remapper configuration.
|
||||
*/
|
||||
void xe_sysctrl_pm_resume(struct xe_device *xe)
|
||||
{
|
||||
struct xe_sysctrl *sc = &xe->sc;
|
||||
|
||||
if (!xe->info.has_soc_remapper_sysctrl)
|
||||
return;
|
||||
|
||||
|
|
@ -127,6 +124,4 @@ void xe_sysctrl_pm_resume(struct xe_device *xe)
|
|||
return;
|
||||
|
||||
xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX);
|
||||
|
||||
xe_sysctrl_mailbox_init(sc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ static int sysctrl_send_frames(struct xe_sysctrl *sc,
|
|||
struct xe_device *xe = sc_to_xe(sc);
|
||||
u32 ctrl_reg, total_frames, frame;
|
||||
size_t bytes_sent, frame_size;
|
||||
bool phase;
|
||||
|
||||
total_frames = DIV_ROUND_UP(cmd_size, XE_SYSCTRL_MB_FRAME_SIZE);
|
||||
|
||||
|
|
@ -153,7 +154,8 @@ static int sysctrl_send_frames(struct xe_sysctrl *sc,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
sc->phase_bit ^= 1;
|
||||
ctrl_reg = xe_mmio_read32(sc->mmio, SYSCTRL_MB_CTRL);
|
||||
phase = !(ctrl_reg & SYSCTRL_FRAME_PHASE);
|
||||
bytes_sent = 0;
|
||||
|
||||
for (frame = 0; frame < total_frames; frame++) {
|
||||
|
|
@ -161,7 +163,6 @@ static int sysctrl_send_frames(struct xe_sysctrl *sc,
|
|||
|
||||
if (sysctrl_write_frame(sc, mbox_cmd + bytes_sent, frame_size)) {
|
||||
xe_err(xe, "sysctrl: Failed to write frame %u\n", frame);
|
||||
sc->phase_bit = 0;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -169,13 +170,12 @@ static int sysctrl_send_frames(struct xe_sysctrl *sc,
|
|||
REG_FIELD_PREP(SYSCTRL_FRAME_CURRENT_MASK, frame) |
|
||||
REG_FIELD_PREP(SYSCTRL_FRAME_TOTAL_MASK, total_frames - 1) |
|
||||
SYSCTRL_MB_CTRL_CMD |
|
||||
(sc->phase_bit ? SYSCTRL_FRAME_PHASE : 0);
|
||||
(phase ? SYSCTRL_FRAME_PHASE : 0);
|
||||
|
||||
xe_mmio_write32(sc->mmio, SYSCTRL_MB_CTRL, ctrl_reg);
|
||||
|
||||
if (!sysctrl_wait_bit_clear(sc, SYSCTRL_MB_CTRL_RUN_BUSY, timeout_ms)) {
|
||||
xe_err(xe, "sysctrl: Frame %u acknowledgment timeout\n", frame);
|
||||
sc->phase_bit = 0;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
|
@ -321,20 +321,6 @@ void xe_sysctrl_create_command(struct xe_sysctrl_mailbox_command *command, u8 gr
|
|||
command->data_out_len = response_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_sysctrl_mailbox_init - Initialize System Controller mailbox interface
|
||||
* @sc: System controller structure
|
||||
*
|
||||
* Initialize system controller mailbox interface for communication.
|
||||
*/
|
||||
void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc)
|
||||
{
|
||||
u32 ctrl_reg;
|
||||
|
||||
ctrl_reg = xe_mmio_read32(sc->mmio, SYSCTRL_MB_CTRL);
|
||||
sc->phase_bit = (ctrl_reg & SYSCTRL_FRAME_PHASE) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_sysctrl_send_command() - Send mailbox command to System Controller
|
||||
* @sc: System Controller instance
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ struct xe_sysctrl_mailbox_command;
|
|||
void xe_sysctrl_create_command(struct xe_sysctrl_mailbox_command *command, u8 group_id, u8 cmd_id,
|
||||
void *request, size_t request_len, void *response,
|
||||
size_t response_len);
|
||||
void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc);
|
||||
int xe_sysctrl_send_command(struct xe_sysctrl *sc,
|
||||
struct xe_sysctrl_mailbox_command *cmd,
|
||||
size_t *rdata_len);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user