diff options
Diffstat (limited to 'drivers/gpu/drm/msm')
81 files changed, 2659 insertions, 1044 deletions
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 3c9dfdb0b328..871870ddf7ec 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -23,6 +23,7 @@ config DRM_MSM select SHMEM select TMPFS select QCOM_SCM + select DEVFREQ_GOV_SIMPLE_ONDEMAND select WANT_DEV_COREDUMP select SND_SOC_HDMI_CODEC if SND_SOC select SYNC_FILE @@ -140,12 +141,12 @@ config DRM_MSM_DSI_10NM_PHY Choose this option if DSI PHY on SDM845 is used on the platform. config DRM_MSM_DSI_7NM_PHY - bool "Enable DSI 7nm PHY driver in MSM DRM" + bool "Enable DSI 7nm/5nm/4nm PHY driver in MSM DRM" depends on DRM_MSM_DSI default y help - Choose this option if DSI PHY on SM8150/SM8250/SC7280 is used on - the platform. + Choose this option if DSI PHY on SM8150/SM8250/SM8350/SM8450/SM8550/SC7280 + is used on the platform. config DRM_MSM_HDMI bool "Enable HDMI support in MSM DRM driver" diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c index 6c9a747eb4ad..c67089a7ebc1 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c @@ -53,6 +53,8 @@ static void a2xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) static bool a2xx_me_init(struct msm_gpu *gpu) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu); struct msm_ringbuffer *ring = gpu->rb[0]; OUT_PKT3(ring, CP_ME_INIT, 18); @@ -84,15 +86,20 @@ static bool a2xx_me_init(struct msm_gpu *gpu) /* NQ and External Memory Swap */ OUT_RING(ring, 0x00000000); /* protected mode error checking (0x1f2 is REG_AXXX_CP_INT_CNTL) */ - OUT_RING(ring, 0x200001f2); + if (a2xx_gpu->protection_disabled) + OUT_RING(ring, 0x00000000); + else + OUT_RING(ring, 0x200001f2); /* Disable header dumping and Header dump address */ OUT_RING(ring, 0x00000000); /* Header dump size */ OUT_RING(ring, 0x00000000); - /* enable protected mode */ - OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1); - OUT_RING(ring, 1); + if (!a2xx_gpu->protection_disabled) { + /* enable protected mode */ + OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 1); + } adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR); return a2xx_idle(gpu); @@ -101,6 +108,7 @@ static bool a2xx_me_init(struct msm_gpu *gpu) static int a2xx_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu); dma_addr_t pt_base, tran_error; uint32_t *ptr, len; int i, ret; @@ -221,6 +229,17 @@ static int a2xx_hw_init(struct msm_gpu *gpu) len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4; DBG("loading PM4 ucode version: %x", ptr[1]); + /* + * New firmware files seem to have GPU and firmware version in this + * word (0x20xxxx for A200, 0x220xxx for A220, 0x225xxx for A225). + * Older firmware files, which lack protection support, have 0 instead. + */ + if (ptr[1] == 0) { + dev_warn(gpu->dev->dev, + "Legacy firmware detected, disabling protection support\n"); + a2xx_gpu->protection_disabled = true; + } + gpu_write(gpu, REG_AXXX_CP_DEBUG, AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE); gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0); diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.h b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h index 02fba2cb8932..161a075f94af 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h @@ -15,6 +15,7 @@ struct a2xx_gpu { struct adreno_gpu base; bool pm_enabled; + bool protection_disabled; }; #define to_a2xx_gpu(x) container_of(x, struct a2xx_gpu, base) diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 2c8b9899625b..948785ed07bb 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -500,7 +500,7 @@ static const struct adreno_gpu_funcs funcs = { #endif .gpu_state_get = a3xx_gpu_state_get, .gpu_state_put = adreno_gpu_state_put, - .create_address_space = adreno_iommu_create_address_space, + .create_address_space = adreno_create_address_space, .get_rptr = a3xx_get_rptr, }, }; diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 7cb8d9849c07..3e09d3a7a0ac 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -606,8 +606,7 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) { static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) { - *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO, - REG_A4XX_RBBM_PERFCTR_CP_0_HI); + *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO); return 0; } @@ -635,7 +634,7 @@ static const struct adreno_gpu_funcs funcs = { #endif .gpu_state_get = a4xx_gpu_state_get, .gpu_state_put = adreno_gpu_state_put, - .create_address_space = adreno_iommu_create_address_space, + .create_address_space = adreno_create_address_space, .get_rptr = a4xx_get_rptr, }, .get_timestamp = a4xx_get_timestamp, diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 3dcec7acb384..660ba0db8900 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -605,11 +605,9 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) a5xx_ucode_check_version(a5xx_gpu, a5xx_gpu->pfp_bo); } - gpu_write64(gpu, REG_A5XX_CP_ME_INSTR_BASE_LO, - REG_A5XX_CP_ME_INSTR_BASE_HI, a5xx_gpu->pm4_iova); + gpu_write64(gpu, REG_A5XX_CP_ME_INSTR_BASE_LO, a5xx_gpu->pm4_iova); - gpu_write64(gpu, REG_A5XX_CP_PFP_INSTR_BASE_LO, - REG_A5XX_CP_PFP_INSTR_BASE_HI, a5xx_gpu->pfp_iova); + gpu_write64(gpu, REG_A5XX_CP_PFP_INSTR_BASE_LO, a5xx_gpu->pfp_iova); return 0; } @@ -868,8 +866,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) * memory rendering at this point in time and we don't want to block off * part of the virtual memory space. */ - gpu_write64(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, - REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000); + gpu_write64(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, 0x00000000); gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000); /* Put the GPU into 64 bit by default */ @@ -908,8 +905,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) return ret; /* Set the ringbuffer address */ - gpu_write64(gpu, REG_A5XX_CP_RB_BASE, REG_A5XX_CP_RB_BASE_HI, - gpu->rb[0]->iova); + gpu_write64(gpu, REG_A5XX_CP_RB_BASE, gpu->rb[0]->iova); /* * If the microcode supports the WHERE_AM_I opcode then we can use that @@ -936,7 +932,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) } gpu_write64(gpu, REG_A5XX_CP_RB_RPTR_ADDR, - REG_A5XX_CP_RB_RPTR_ADDR_HI, shadowptr(a5xx_gpu, gpu->rb[0])); + shadowptr(a5xx_gpu, gpu->rb[0])); } else if (gpu->nr_rings > 1) { /* Disable preemption if WHERE_AM_I isn't available */ a5xx_preempt_fini(gpu); @@ -1239,9 +1235,9 @@ static void a5xx_fault_detect_irq(struct msm_gpu *gpu) gpu_read(gpu, REG_A5XX_RBBM_STATUS), gpu_read(gpu, REG_A5XX_CP_RB_RPTR), gpu_read(gpu, REG_A5XX_CP_RB_WPTR), - gpu_read64(gpu, REG_A5XX_CP_IB1_BASE, REG_A5XX_CP_IB1_BASE_HI), + gpu_read64(gpu, REG_A5XX_CP_IB1_BASE), gpu_read(gpu, REG_A5XX_CP_IB1_BUFSZ), - gpu_read64(gpu, REG_A5XX_CP_IB2_BASE, REG_A5XX_CP_IB2_BASE_HI), + gpu_read64(gpu, REG_A5XX_CP_IB2_BASE), gpu_read(gpu, REG_A5XX_CP_IB2_BUFSZ)); /* Turn off the hangcheck timer to keep it from bothering us */ @@ -1427,8 +1423,7 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu) static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) { - *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO, - REG_A5XX_RBBM_ALWAYSON_COUNTER_HI); + *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO); return 0; } @@ -1465,8 +1460,7 @@ static int a5xx_crashdumper_run(struct msm_gpu *gpu, if (IS_ERR_OR_NULL(dumper->ptr)) return -EINVAL; - gpu_write64(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO, - REG_A5XX_CP_CRASH_SCRIPT_BASE_HI, dumper->iova); + gpu_write64(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO, dumper->iova); gpu_write(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, 1); @@ -1666,8 +1660,7 @@ static u64 a5xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate) { u64 busy_cycles; - busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, - REG_A5XX_RBBM_PERFCTR_RBBM_0_HI); + busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO); *out_sample_rate = clk_get_rate(gpu->core_clk); return busy_cycles; @@ -1705,7 +1698,7 @@ static const struct adreno_gpu_funcs funcs = { .gpu_busy = a5xx_gpu_busy, .gpu_state_get = a5xx_gpu_state_get, .gpu_state_put = a5xx_gpu_state_put, - .create_address_space = adreno_iommu_create_address_space, + .create_address_space = adreno_create_address_space, .get_rptr = a5xx_get_rptr, }, .get_timestamp = a5xx_get_timestamp, diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c index 8abc9a2b114a..7658e89844b4 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c @@ -137,7 +137,6 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) /* Set the address of the incoming preemption record */ gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO, - REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI, a5xx_gpu->preempt_iova[ring->id]); a5xx_gpu->next_ring = ring; @@ -211,8 +210,7 @@ void a5xx_preempt_hw_init(struct msm_gpu *gpu) } /* Write a 0 to signal that we aren't switching pagetables */ - gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO, - REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI, 0); + gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO, 0); /* Reset the preemption state */ set_preempt_state(a5xx_gpu, PREEMPT_NONE); diff --git a/drivers/gpu/drm/msm/adreno/a6xx.xml.h b/drivers/gpu/drm/msm/adreno/a6xx.xml.h index beea4a7fc1df..a92788019376 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a6xx.xml.h @@ -241,6 +241,9 @@ enum a6xx_shader_id { A6XX_HLSQ_FRONTEND_META = 97, A6XX_HLSQ_INDIRECT_META = 98, A6XX_HLSQ_BACKEND_META = 99, + A6XX_SP_LB_6_DATA = 112, + A6XX_SP_LB_7_DATA = 113, + A6XX_HLSQ_INST_RAM_1 = 115, }; enum a6xx_debugbus_id { @@ -274,19 +277,32 @@ enum a6xx_debugbus_id { A6XX_DBGBUS_HLSQ_SPTP = 31, A6XX_DBGBUS_RB_0 = 32, A6XX_DBGBUS_RB_1 = 33, + A6XX_DBGBUS_RB_2 = 34, A6XX_DBGBUS_UCHE_WRAPPER = 36, A6XX_DBGBUS_CCU_0 = 40, A6XX_DBGBUS_CCU_1 = 41, + A6XX_DBGBUS_CCU_2 = 42, A6XX_DBGBUS_VFD_0 = 56, A6XX_DBGBUS_VFD_1 = 57, A6XX_DBGBUS_VFD_2 = 58, A6XX_DBGBUS_VFD_3 = 59, + A6XX_DBGBUS_VFD_4 = 60, + A6XX_DBGBUS_VFD_5 = 61, A6XX_DBGBUS_SP_0 = 64, A6XX_DBGBUS_SP_1 = 65, + A6XX_DBGBUS_SP_2 = 66, A6XX_DBGBUS_TPL1_0 = 72, A6XX_DBGBUS_TPL1_1 = 73, A6XX_DBGBUS_TPL1_2 = 74, A6XX_DBGBUS_TPL1_3 = 75, + A6XX_DBGBUS_TPL1_4 = 76, + A6XX_DBGBUS_TPL1_5 = 77, + A6XX_DBGBUS_SPTP_0 = 88, + A6XX_DBGBUS_SPTP_1 = 89, + A6XX_DBGBUS_SPTP_2 = 90, + A6XX_DBGBUS_SPTP_3 = 91, + A6XX_DBGBUS_SPTP_4 = 92, + A6XX_DBGBUS_SPTP_5 = 93, }; enum a6xx_cp_perfcounter_select { @@ -1071,6 +1087,8 @@ enum a6xx_tex_type { #define REG_A6XX_CP_MISC_CNTL 0x00000840 +#define REG_A6XX_CP_CHICKEN_DBG 0x00000841 + #define REG_A6XX_CP_APRIV_CNTL 0x00000844 #define REG_A6XX_CP_ROQ_THRESHOLDS_1 0x000008c1 diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index e033d6a67a20..f3c9600221d4 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -876,7 +876,8 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu) #define GBIF_CLIENT_HALT_MASK BIT(0) #define GBIF_ARB_HALT_MASK BIT(1) -static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu) +static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, + bool gx_off) { struct msm_gpu *gpu = &adreno_gpu->base; @@ -889,9 +890,11 @@ static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu) return; } - /* Halt the gx side of GBIF */ - gpu_write(gpu, REG_A6XX_RBBM_GBIF_HALT, 1); - spin_until(gpu_read(gpu, REG_A6XX_RBBM_GBIF_HALT_ACK) & 1); + if (gx_off) { + /* Halt the gx side of GBIF */ + gpu_write(gpu, REG_A6XX_RBBM_GBIF_HALT, 1); + spin_until(gpu_read(gpu, REG_A6XX_RBBM_GBIF_HALT_ACK) & 1); + } /* Halt new client requests on GBIF */ gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_CLIENT_HALT_MASK); @@ -929,7 +932,7 @@ static void a6xx_gmu_force_off(struct a6xx_gmu *gmu) /* Halt the gmu cm3 core */ gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1); - a6xx_bus_clear_pending_transactions(adreno_gpu); + a6xx_bus_clear_pending_transactions(adreno_gpu, true); /* Reset GPU core blocks */ gpu_write(gpu, REG_A6XX_RBBM_SW_RESET_CMD, 1); @@ -1083,7 +1086,7 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu) return; } - a6xx_bus_clear_pending_transactions(adreno_gpu); + a6xx_bus_clear_pending_transactions(adreno_gpu, a6xx_gpu->hung); /* tell the GMU we want to slumber */ ret = a6xx_gmu_notify_slumber(gmu); @@ -1213,19 +1216,17 @@ static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo, static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu) { - struct iommu_domain *domain; struct msm_mmu *mmu; - domain = iommu_domain_alloc(&platform_bus_type); - if (!domain) + mmu = msm_iommu_new(gmu->dev, 0); + if (!mmu) return -ENODEV; + if (IS_ERR(mmu)) + return PTR_ERR(mmu); - mmu = msm_iommu_new(gmu->dev, domain); gmu->aspace = msm_gem_address_space_create(mmu, "gmu", 0x0, 0x80000000); - if (IS_ERR(gmu->aspace)) { - iommu_domain_free(domain); + if (IS_ERR(gmu->aspace)) return PTR_ERR(gmu->aspace); - } return 0; } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index fdc578016e0b..aae60cbd9164 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -247,8 +247,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) OUT_RING(ring, submit->seqno); trace_msm_gpu_submit_flush(submit, - gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO, - REG_A6XX_CP_ALWAYS_ON_COUNTER_HI)); + gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO)); a6xx_flush(gpu, ring); } @@ -947,8 +946,7 @@ static int a6xx_ucode_init(struct msm_gpu *gpu) } } - gpu_write64(gpu, REG_A6XX_CP_SQE_INSTR_BASE, - REG_A6XX_CP_SQE_INSTR_BASE+1, a6xx_gpu->sqe_iova); + gpu_write64(gpu, REG_A6XX_CP_SQE_INSTR_BASE, a6xx_gpu->sqe_iova); return 0; } @@ -999,8 +997,7 @@ static int hw_init(struct msm_gpu *gpu) * memory rendering at this point in time and we don't want to block off * part of the virtual memory space. */ - gpu_write64(gpu, REG_A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, - REG_A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000); + gpu_write64(gpu, REG_A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, 0x00000000); gpu_write(gpu, REG_A6XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000); /* Turn on 64 bit addressing for all blocks */ @@ -1049,11 +1046,9 @@ static int hw_init(struct msm_gpu *gpu) if (!adreno_is_a650_family(adreno_gpu)) { /* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */ - gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN_LO, - REG_A6XX_UCHE_GMEM_RANGE_MIN_HI, 0x00100000); + gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN_LO, 0x00100000); gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MAX_LO, - REG_A6XX_UCHE_GMEM_RANGE_MAX_HI, 0x00100000 + adreno_gpu->gmem - 1); } @@ -1145,8 +1140,7 @@ static int hw_init(struct msm_gpu *gpu) goto out; /* Set the ringbuffer address */ - gpu_write64(gpu, REG_A6XX_CP_RB_BASE, REG_A6XX_CP_RB_BASE_HI, - gpu->rb[0]->iova); + gpu_write64(gpu, REG_A6XX_CP_RB_BASE, gpu->rb[0]->iova); /* Targets that support extended APRIV can use the RPTR shadow from * hardware but all the other ones need to disable the feature. Targets @@ -1178,7 +1172,6 @@ static int hw_init(struct msm_gpu *gpu) } gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR_LO, - REG_A6XX_CP_RB_RPTR_ADDR_HI, shadowptr(a6xx_gpu, gpu->rb[0])); } @@ -1277,6 +1270,12 @@ static void a6xx_recover(struct msm_gpu *gpu) if (hang_debug) a6xx_dump(gpu); + /* + * To handle recovery specific sequences during the rpm suspend we are + * about to trigger + */ + a6xx_gpu->hung = true; + /* Halt SQE first */ gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3); @@ -1319,6 +1318,7 @@ static void a6xx_recover(struct msm_gpu *gpu) mutex_unlock(&gpu->active_lock); msm_gpu_hw_init(gpu); + a6xx_gpu->hung = false; } static const char *a6xx_uche_fault_block(struct msm_gpu *gpu, u32 mid) @@ -1499,9 +1499,9 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu) gpu_read(gpu, REG_A6XX_RBBM_STATUS), gpu_read(gpu, REG_A6XX_CP_RB_RPTR), gpu_read(gpu, REG_A6XX_CP_RB_WPTR), - gpu_read64(gpu, REG_A6XX_CP_IB1_BASE, REG_A6XX_CP_IB1_BASE_HI), + gpu_read64(gpu, REG_A6XX_CP_IB1_BASE), gpu_read(gpu, REG_A6XX_CP_IB1_REM_SIZE), - gpu_read64(gpu, REG_A6XX_CP_IB2_BASE, REG_A6XX_CP_IB2_BASE_HI), + gpu_read64(gpu, REG_A6XX_CP_IB2_BASE), gpu_read(gpu, REG_A6XX_CP_IB2_REM_SIZE)); /* Turn off the hangcheck timer to keep it from bothering us */ @@ -1712,8 +1712,7 @@ static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) /* Force the GPU power on so we can read this register */ a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET); - *value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO, - REG_A6XX_CP_ALWAYS_ON_COUNTER_HI); + *value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER_LO); a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET); @@ -1786,43 +1785,16 @@ a6xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); - struct iommu_domain *iommu; - struct msm_mmu *mmu; - struct msm_gem_address_space *aspace; - u64 start, size; - - iommu = iommu_domain_alloc(&platform_bus_type); - if (!iommu) - return NULL; + unsigned long quirks = 0; /* * This allows GPU to set the bus attributes required to use system * cache on behalf of the iommu page table walker. */ if (!IS_ERR_OR_NULL(a6xx_gpu->htw_llc_slice)) - adreno_set_llc_attributes(iommu); + quirks |= IO_PGTABLE_QUIRK_ARM_OUTER_WBWA; - mmu = msm_iommu_new(&pdev->dev, iommu); - if (IS_ERR(mmu)) { - iommu_domain_free(iommu); - return ERR_CAST(mmu); - } - - /* - * Use the aperture start or SZ_16M, whichever is greater. This will - * ensure that we align with the allocated pagetable range while still - * allowing room in the lower 32 bits for GMEM and whatnot - */ - start = max_t(u64, SZ_16M, iommu->geometry.aperture_start); - size = iommu->geometry.aperture_end - start + 1; - - aspace = msm_gem_address_space_create(mmu, "gpu", - start & GENMASK_ULL(48, 0), size); - - if (IS_ERR(aspace) && !IS_ERR(mmu)) - mmu->funcs->destroy(mmu); - - return aspace; + return adreno_iommu_create_address_space(gpu, pdev, quirks); } static struct msm_gem_address_space * @@ -1851,6 +1823,39 @@ static uint32_t a6xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) return ring->memptrs->rptr = gpu_read(gpu, REG_A6XX_CP_RB_RPTR); } +static bool a6xx_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring) +{ + struct msm_cp_state cp_state = { + .ib1_base = gpu_read64(gpu, REG_A6XX_CP_IB1_BASE), + .ib2_base = gpu_read64(gpu, REG_A6XX_CP_IB2_BASE), + .ib1_rem = gpu_read(gpu, REG_A6XX_CP_IB1_REM_SIZE), + .ib2_rem = gpu_read(gpu, REG_A6XX_CP_IB2_REM_SIZE), + }; + bool progress; + + /* + * Adjust the remaining data to account for what has already been + * fetched from memory, but not yet consumed by the SQE. + * + * This is not *technically* correct, the amount buffered could + * exceed the IB size due to hw prefetching ahead, but: + * + * (1) We aren't trying to find the exact position, just whether + * progress has been made + * (2) The CP_REG_TO_MEM at the end of a submit should be enough + * to prevent prefetching into an unrelated submit. (And + * either way, at some point the ROQ will be full.) + */ + cp_state.ib1_rem += gpu_read(gpu, REG_A6XX_CP_CSQ_IB1_STAT) >> 16; + cp_state.ib2_rem += gpu_read(gpu, REG_A6XX_CP_CSQ_IB2_STAT) >> 16; + + progress = !!memcmp(&cp_state, &ring->last_cp_state, sizeof(cp_state)); + + ring->last_cp_state = cp_state; + + return progress; +} + static u32 a618_get_speed_bin(u32 fuse) { if (fuse == 0) @@ -1906,7 +1911,7 @@ static u32 fuse_to_supp_hw(struct device *dev, struct adreno_rev rev, u32 fuse) if (val == UINT_MAX) { DRM_DEV_ERROR(dev, - "missing support for speed-bin: %u. Some OPPs may not be supported by hardware", + "missing support for speed-bin: %u. Some OPPs may not be supported by hardware\n", fuse); return UINT_MAX; } @@ -1916,7 +1921,7 @@ static u32 fuse_to_supp_hw(struct device *dev, struct adreno_rev rev, u32 fuse) static int a6xx_set_supported_hw(struct device *dev, struct adreno_rev rev) { - u32 supp_hw = UINT_MAX; + u32 supp_hw; u32 speedbin; int ret; @@ -1928,15 +1933,13 @@ static int a6xx_set_supported_hw(struct device *dev, struct adreno_rev rev) if (ret == -ENOENT) { return 0; } else if (ret) { - DRM_DEV_ERROR(dev, - "failed to read speed-bin (%d). Some OPPs may not be supported by hardware", - ret); - goto done; + dev_err_probe(dev, ret, + "failed to read speed-bin. Some OPPs may not be supported by hardware\n"); + return ret; } supp_hw = fuse_to_supp_hw(dev, rev, speedbin); -done: ret = devm_pm_opp_set_supported_hw(dev, &supp_hw, 1); if (ret) return ret; @@ -1969,6 +1972,7 @@ static const struct adreno_gpu_funcs funcs = { .create_address_space = a6xx_create_address_space, .create_private_address_space = a6xx_create_private_address_space, .get_rptr = a6xx_get_rptr, + .progress = a6xx_progress, }, .get_timestamp = a6xx_get_timestamp, }; @@ -2005,13 +2009,6 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) adreno_cmp_rev(ADRENO_REV(6, 3, 5, ANY_ID), info->rev))) adreno_gpu->base.hw_apriv = true; - /* - * For now only clamp to idle freq for devices where this is known not - * to cause power supply issues: - */ - if (info && (info->revn == 618)) - gpu->clamp_to_idle = true; - a6xx_llc_slices_init(pdev, a6xx_gpu); ret = a6xx_set_supported_hw(&pdev->dev, config->rev); @@ -2026,6 +2023,13 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) return ERR_PTR(ret); } + /* + * For now only clamp to idle freq for devices where this is known not + * to cause power supply issues: + */ + if (adreno_is_a618(adreno_gpu) || adreno_is_7c3(adreno_gpu)) + priv->gpu_clamp_to_idle = true; + /* Check if there is a GMU phandle and set it up */ node = of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index ab853f61db63..eea2e60ce3b7 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -32,6 +32,7 @@ struct a6xx_gpu { void *llc_slice; void *htw_llc_slice; bool have_mmu500; + bool hung; }; #define to_a6xx_gpu(x) container_of(x, struct a6xx_gpu, base) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index a5c3d1ed255a..b7e217d00a22 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -147,8 +147,7 @@ static int a6xx_crashdumper_run(struct msm_gpu *gpu, /* Make sure all pending memory writes are posted */ wmb(); - gpu_write64(gpu, REG_A6XX_CP_CRASH_SCRIPT_BASE_LO, - REG_A6XX_CP_CRASH_SCRIPT_BASE_HI, dumper->iova); + gpu_write64(gpu, REG_A6XX_CP_CRASH_SCRIPT_BASE_LO, dumper->iova); gpu_write(gpu, REG_A6XX_CP_CRASH_DUMP_CNTL, 1); @@ -386,6 +385,9 @@ static void a6xx_get_debugbus(struct msm_gpu *gpu, nr_debugbus_blocks = ARRAY_SIZE(a6xx_debugbus_blocks) + (a6xx_has_gbif(to_adreno_gpu(gpu)) ? 1 : 0); + if (adreno_is_a650_family(to_adreno_gpu(gpu))) + nr_debugbus_blocks += ARRAY_SIZE(a650_debugbus_blocks); + a6xx_state->debugbus = state_kcalloc(a6xx_state, nr_debugbus_blocks, sizeof(*a6xx_state->debugbus)); @@ -412,6 +414,15 @@ static void a6xx_get_debugbus(struct msm_gpu *gpu, a6xx_state->nr_debugbus += 1; } + + + if (adreno_is_a650_family(to_adreno_gpu(gpu))) { + for (i = 0; i < ARRAY_SIZE(a650_debugbus_blocks); i++) + a6xx_get_debugbus_block(gpu, + a6xx_state, + &a650_debugbus_blocks[i], + &a6xx_state->debugbus[i]); + } } /* Dump the VBIF debugbus on applicable targets */ @@ -525,10 +536,21 @@ static void a6xx_get_cluster(struct msm_gpu *gpu, struct a6xx_gpu_state_obj *obj, struct a6xx_crashdumper *dumper) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); u64 *in = dumper->ptr; u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; size_t datasize; int i, regcount = 0; + u32 id = cluster->id; + + /* Skip registers that are not present on older generation */ + if (!adreno_is_a660_family(adreno_gpu) && + cluster->registers == a660_fe_cluster) + return; + + if (adreno_is_a650_family(adreno_gpu) && + cluster->registers == a6xx_ps_cluster) + id = CLUSTER_VPC_PS; /* Some clusters need a selector register to be programmed too */ if (cluster->sel_reg) @@ -538,7 +560,7 @@ static void a6xx_get_cluster(struct msm_gpu *gpu, int j; in += CRASHDUMP_WRITE(in, REG_A6XX_CP_APERTURE_CNTL_CD, - (cluster->id << 8) | (i << 4) | i); + (id << 8) | (i << 4) | i); for (j = 0; j < cluster->count; j += 2) { int count = RANGE(cluster->registers, j); @@ -688,6 +710,11 @@ static void a6xx_get_crashdumper_registers(struct msm_gpu *gpu, u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; int i, regcount = 0; + /* Skip unsupported registers on older generations */ + if (!adreno_is_a660_family(to_adreno_gpu(gpu)) && + (regs->registers == a660_registers)) + return; + /* Some blocks might need to program a selector register first */ if (regs->val0) in += CRASHDUMP_WRITE(in, regs->val0, regs->val1); @@ -722,6 +749,11 @@ static void a6xx_get_ahb_gpu_registers(struct msm_gpu *gpu, { int i, regcount = 0, index = 0; + /* Skip unsupported registers on older generations */ + if (!adreno_is_a660_family(to_adreno_gpu(gpu)) && + (regs->registers == a660_registers)) + return; + for (i = 0; i < regs->count; i += 2) regcount += RANGE(regs->registers, i); @@ -910,15 +942,24 @@ static void a6xx_get_registers(struct msm_gpu *gpu, dumper); } +static u32 a6xx_get_cp_roq_size(struct msm_gpu *gpu) +{ + /* The value at [16:31] is in 4dword units. Convert it to dwords */ + return gpu_read(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_2) >> 14; +} + /* Read a block of data from an indexed register pair */ static void a6xx_get_indexed_regs(struct msm_gpu *gpu, struct a6xx_gpu_state *a6xx_state, - const struct a6xx_indexed_registers *indexed, + struct a6xx_indexed_registers *indexed, struct a6xx_gpu_state_obj *obj) { int i; obj->handle = (const void *) indexed; + if (indexed->count_fn) + indexed->count = indexed->count_fn(gpu); + obj->data = state_kcalloc(a6xx_state, indexed->count, sizeof(u32)); if (!obj->data) return; @@ -947,6 +988,21 @@ static void a6xx_get_indexed_registers(struct msm_gpu *gpu, a6xx_get_indexed_regs(gpu, a6xx_state, &a6xx_indexed_reglist[i], &a6xx_state->indexed_regs[i]); + if (adreno_is_a650_family(to_adreno_gpu(gpu))) { + u32 val; + + val = gpu_read(gpu, REG_A6XX_CP_CHICKEN_DBG); + gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, val | 4); + + /* Get the contents of the CP mempool */ + a6xx_get_indexed_regs(gpu, a6xx_state, &a6xx_cp_mempool_indexed, + &a6xx_state->indexed_regs[i]); + + gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, val); + a6xx_state->nr_indexed_regs = count; + return; + } + /* Set the CP mempool size to 0 to stabilize it while dumping */ mempool_size = gpu_read(gpu, REG_A6XX_CP_MEM_POOL_SIZE); gpu_write(gpu, REG_A6XX_CP_MEM_POOL_SIZE, 0); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h index 2fb58b7098e4..790f55e24533 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h @@ -36,16 +36,21 @@ static const u32 a6xx_fe_cluster[] = { 0xa00e, 0xa0ef, 0xa0f8, 0xa0f8, }; +static const u32 a660_fe_cluster[] = { + 0x9807, 0x9807, +}; + static const u32 a6xx_pc_vs_cluster[] = { 0x9100, 0x9108, 0x9300, 0x9306, 0x9980, 0x9981, 0x9b00, 0x9b07, }; -#define CLUSTER_FE 0 -#define CLUSTER_SP_VS 1 -#define CLUSTER_PC_VS 2 -#define CLUSTER_GRAS 3 -#define CLUSTER_SP_PS 4 -#define CLUSTER_PS 5 +#define CLUSTER_FE 0 +#define CLUSTER_SP_VS 1 +#define CLUSTER_PC_VS 2 +#define CLUSTER_GRAS 3 +#define CLUSTER_SP_PS 4 +#define CLUSTER_PS 5 +#define CLUSTER_VPC_PS 6 #define CLUSTER(_id, _reg, _sel_reg, _sel_val) \ { .id = _id, .name = #_id,\ @@ -67,6 +72,7 @@ static const struct a6xx_cluster { CLUSTER(CLUSTER_PS, a6xx_ps_cluster, 0, 0), CLUSTER(CLUSTER_FE, a6xx_fe_cluster, 0, 0), CLUSTER(CLUSTER_PC_VS, a6xx_pc_vs_cluster, 0, 0), + CLUSTER(CLUSTER_FE, a660_fe_cluster, 0, 0), }; static const u32 a6xx_sp_vs_hlsq_cluster[] = { @@ -105,7 +111,7 @@ static const u32 a6xx_sp_ps_hlsq_2d_cluster[] = { static const u32 a6xx_sp_ps_sp_cluster[] = { 0xa980, 0xa9a8, 0xa9b0, 0xa9bc, 0xa9d0, 0xa9d3, 0xa9e0, 0xa9f3, - 0xaa00, 0xaa00, 0xaa30, 0xaa31, + 0xaa00, 0xaa00, 0xaa30, 0xaa31, 0xaaf2, 0xaaf2, }; static const u32 a6xx_sp_ps_sp_2d_cluster[] = { @@ -229,6 +235,9 @@ static const struct a6xx_shader_block { SHADER(A6XX_HLSQ_DATAPATH_META, 0x40), SHADER(A6XX_HLSQ_FRONTEND_META, 0x40), SHADER(A6XX_HLSQ_INDIRECT_META, 0x40), + SHADER(A6XX_SP_LB_6_DATA, 0x200), + SHADER(A6XX_SP_LB_7_DATA, 0x200), + SHADER(A6XX_HLSQ_INST_RAM_1, 0x200), }; static const u32 a6xx_rb_rac_registers[] = { @@ -251,7 +260,7 @@ static const u32 a6xx_registers[] = { 0x0540, 0x0555, /* CP */ 0x0800, 0x0808, 0x0810, 0x0813, 0x0820, 0x0821, 0x0823, 0x0824, - 0x0826, 0x0827, 0x0830, 0x0833, 0x0840, 0x0843, 0x084f, 0x086f, + 0x0826, 0x0827, 0x0830, 0x0833, 0x0840, 0x0845, 0x084f, 0x086f, 0x0880, 0x088a, 0x08a0, 0x08ab, 0x08c0, 0x08c4, 0x08d0, 0x08dd, 0x08f0, 0x08f3, 0x0900, 0x0903, 0x0908, 0x0911, 0x0928, 0x093e, 0x0942, 0x094d, 0x0980, 0x0984, 0x098d, 0x0996, 0x0998, 0x099e, @@ -274,6 +283,13 @@ static const u32 a6xx_registers[] = { /* VFD */ 0xa600, 0xa601, 0xa603, 0xa603, 0xa60a, 0xa60a, 0xa610, 0xa617, 0xa630, 0xa630, + /* HLSQ */ + 0xd002, 0xd003, +}; + +static const u32 a660_registers[] = { + /* UCHE */ + 0x0e3c, 0x0e3c, }; #define REGS(_array, _sel_reg, _sel_val) \ @@ -282,6 +298,7 @@ static const u32 a6xx_registers[] = { static const struct a6xx_registers a6xx_reglist[] = { REGS(a6xx_registers, 0, 0), + REGS(a660_registers, 0, 0), REGS(a6xx_rb_rac_registers, REG_A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD, 0), REGS(a6xx_rb_rbp_registers, REG_A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD, 9), }; @@ -366,25 +383,28 @@ static const struct a6xx_registers a6xx_gmu_reglist[] = { REGS(a6xx_gmu_gx_registers, 0, 0), }; -static const struct a6xx_indexed_registers { +static u32 a6xx_get_cp_roq_size(struct msm_gpu *gpu); + +static struct a6xx_indexed_registers { const char *name; u32 addr; u32 data; u32 count; + u32 (*count_fn)(struct msm_gpu *gpu); } a6xx_indexed_reglist[] = { { "CP_SQE_STAT", REG_A6XX_CP_SQE_STAT_ADDR, - REG_A6XX_CP_SQE_STAT_DATA, 0x33 }, + REG_A6XX_CP_SQE_STAT_DATA, 0x33, NULL }, { "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR, - REG_A6XX_CP_DRAW_STATE_DATA, 0x100 }, + REG_A6XX_CP_DRAW_STATE_DATA, 0x100, NULL }, { "CP_UCODE_DBG_DATA", REG_A6XX_CP_SQE_UCODE_DBG_ADDR, - REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x6000 }, + REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x8000, NULL }, { "CP_ROQ", REG_A6XX_CP_ROQ_DBG_ADDR, - REG_A6XX_CP_ROQ_DBG_DATA, 0x400 }, + REG_A6XX_CP_ROQ_DBG_DATA, 0, a6xx_get_cp_roq_size}, }; -static const struct a6xx_indexed_registers a6xx_cp_mempool_indexed = { +static struct a6xx_indexed_registers a6xx_cp_mempool_indexed = { "CP_MEMPOOL", REG_A6XX_CP_MEM_POOL_DBG_ADDR, - REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2060, + REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2060, NULL, }; #define DEBUGBUS(_id, _count) { .id = _id, .name = #_id, .count = _count } @@ -443,4 +463,20 @@ static const struct a6xx_debugbus_block a6xx_cx_debugbus_blocks[] = { DEBUGBUS(A6XX_DBGBUS_CX, 0x100), }; +static const struct a6xx_debugbus_block a650_debugbus_blocks[] = { + DEBUGBUS(A6XX_DBGBUS_RB_2, 0x100), + DEBUGBUS(A6XX_DBGBUS_CCU_2, 0x100), + DEBUGBUS(A6XX_DBGBUS_VFD_4, 0x100), + DEBUGBUS(A6XX_DBGBUS_VFD_5, 0x100), + DEBUGBUS(A6XX_DBGBUS_SP_2, 0x100), + DEBUGBUS(A6XX_DBGBUS_TPL1_4, 0x100), + DEBUGBUS(A6XX_DBGBUS_TPL1_5, 0x100), + DEBUGBUS(A6XX_DBGBUS_SPTP_0, 0x100), + DEBUGBUS(A6XX_DBGBUS_SPTP_1, 0x100), + DEBUGBUS(A6XX_DBGBUS_SPTP_2, 0x100), + DEBUGBUS(A6XX_DBGBUS_SPTP_3, 0x100), + DEBUGBUS(A6XX_DBGBUS_SPTP_4, 0x100), + DEBUGBUS(A6XX_DBGBUS_SPTP_5, 0x100), +}; + #endif diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 628806423f7d..36f062c7582f 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -551,13 +551,14 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) return 0; } +static int adreno_system_suspend(struct device *dev); static void adreno_unbind(struct device *dev, struct device *master, void *data) { struct msm_drm_private *priv = dev_get_drvdata(master); struct msm_gpu *gpu = dev_to_gpu(dev); - pm_runtime_force_suspend(dev); + WARN_ON_ONCE(adreno_system_suspend(dev)); gpu->funcs->destroy(gpu); priv->gpu_pdev = NULL; @@ -609,7 +610,7 @@ static int adreno_remove(struct platform_device *pdev) static void adreno_shutdown(struct platform_device *pdev) { - pm_runtime_force_suspend(&pdev->dev); + WARN_ON_ONCE(adreno_system_suspend(&pdev->dev)); } static const struct of_device_id dt_match[] = { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 5a0e8491cd3a..817599766329 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -191,37 +191,38 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid); } -void adreno_set_llc_attributes(struct iommu_domain *iommu) +struct msm_gem_address_space * +adreno_create_address_space(struct msm_gpu *gpu, + struct platform_device *pdev) { - iommu_set_pgtable_quirks(iommu, IO_PGTABLE_QUIRK_ARM_OUTER_WBWA); + return adreno_iommu_create_address_space(gpu, pdev, 0); } struct msm_gem_address_space * adreno_iommu_create_address_space(struct msm_gpu *gpu, - struct platform_device *pdev) + struct platform_device *pdev, + unsigned long quirks) { - struct iommu_domain *iommu; + struct iommu_domain_geometry *geometry; struct msm_mmu *mmu; struct msm_gem_address_space *aspace; u64 start, size; - iommu = iommu_domain_alloc(&platform_bus_type); - if (!iommu) - return NULL; - - mmu = msm_iommu_new(&pdev->dev, iommu); - if (IS_ERR(mmu)) { - iommu_domain_free(iommu); + mmu = msm_iommu_new(&pdev->dev, quirks); + if (IS_ERR_OR_NULL(mmu)) return ERR_CAST(mmu); - } + + geometry = msm_iommu_get_geometry(mmu); + if (IS_ERR(geometry)) + return ERR_CAST(geometry); /* * Use the aperture start or SZ_16M, whichever is greater. This will * ensure that we align with the allocated pagetable range while still * allowing room in the lower 32 bits for GMEM and whatnot */ - start = max_t(u64, SZ_16M, iommu->geometry.aperture_start); - size = iommu->geometry.aperture_end - start + 1; + start = max_t(u64, SZ_16M, geometry->aperture_start); + size = geometry->aperture_end - start + 1; aspace = msm_gem_address_space_create(mmu, "gpu", start & GENMASK_ULL(48, 0), size); @@ -351,6 +352,8 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_file_private *ctx, /* Ensure string is null terminated: */ str[len] = '\0'; + mutex_lock(&gpu->lock); + if (param == MSM_PARAM_COMM) { paramp = &ctx->comm; } else { @@ -360,6 +363,8 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_file_private *ctx, kfree(*paramp); *paramp = str; + mutex_unlock(&gpu->lock); + return 0; } case MSM_PARAM_SYSPROF: @@ -1078,13 +1083,13 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) { struct msm_gpu *gpu = &adreno_gpu->base; - struct msm_drm_private *priv = gpu->dev->dev_private; + struct msm_drm_private *priv = gpu->dev ? gpu->dev->dev_private : NULL; unsigned int i; for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) release_firmware(adreno_gpu->fw[i]); - if (pm_runtime_enabled(&priv->gpu_pdev->dev)) + if (priv && pm_runtime_enabled(&priv->gpu_pdev->dev)) pm_runtime_disable(&priv->gpu_pdev->dev); msm_gpu_cleanup(&adreno_gpu->base); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index e7adc5c632d0..b4f9b1343d63 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -29,11 +29,9 @@ enum { ADRENO_FW_MAX, }; -enum adreno_quirks { - ADRENO_QUIRK_TWO_PASS_USE_WFI = 1, - ADRENO_QUIRK_FAULT_DETECT_MASK = 2, - ADRENO_QUIRK_LMLOADKILL_DISABLE = 3, -}; +#define ADRENO_QUIRK_TWO_PASS_USE_WFI BIT(0) +#define ADRENO_QUIRK_FAULT_DETECT_MASK BIT(1) +#define ADRENO_QUIRK_LMLOADKILL_DISABLE BIT(2) struct adreno_rev { uint8_t core; @@ -65,7 +63,7 @@ struct adreno_info { const char *name; const char *fw[ADRENO_FW_MAX]; uint32_t gmem; - enum adreno_quirks quirks; + u64 quirks; struct msm_gpu *(*init)(struct drm_device *dev); const char *zapfw; u32 inactive_period; @@ -335,10 +333,13 @@ void adreno_show_object(struct drm_printer *p, void **ptr, int len, * attached targets */ struct msm_gem_address_space * -adreno_iommu_create_address_space(struct msm_gpu *gpu, - struct platform_device *pdev); +adreno_create_address_space(struct msm_gpu *gpu, + struct platform_device *pdev); -void adreno_set_llc_attributes(struct iommu_domain *iommu); +struct msm_gem_address_space * +adreno_iommu_create_address_space(struct msm_gpu *gpu, + struct platform_device *pdev, + unsigned long quirks); int adreno_read_speedbin(struct device *dev, u32 *speedbin); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 13ce321283ff..f29a339a3705 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -748,7 +748,7 @@ static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) int i; - if (!state->color_mgmt_changed) + if (!state->color_mgmt_changed && !drm_atomic_crtc_needs_modeset(state)) return; for (i = 0; i < cstate->num_mixers; i++) { @@ -968,7 +968,10 @@ static void dpu_crtc_reset(struct drm_crtc *crtc) if (crtc->state) dpu_crtc_destroy_state(crtc, crtc->state); - __drm_atomic_helper_crtc_reset(crtc, &cstate->base); + if (cstate) + __drm_atomic_helper_crtc_reset(crtc, &cstate->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); } /** @@ -1150,6 +1153,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state); pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL); + if (!pstates) + return -ENOMEM; if (!crtc_state->enable || !crtc_state->active) { DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n", @@ -1517,16 +1522,12 @@ DEFINE_SHOW_ATTRIBUTE(dpu_crtc_debugfs_state); static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) { struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); - struct dentry *debugfs_root; - - debugfs_root = debugfs_create_dir(dpu_crtc->name, - crtc->dev->primary->debugfs_root); debugfs_create_file("status", 0400, - debugfs_root, + crtc->debugfs_entry, dpu_crtc, &_dpu_debugfs_status_fops); debugfs_create_file("state", 0600, - debugfs_root, + crtc->debugfs_entry, &dpu_crtc->base, &dpu_crtc_debugfs_state_fops); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 9c6817b5a194..758261e8ac73 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -162,6 +162,7 @@ enum dpu_enc_rc_states { * @vsync_event_work: worker to handle vsync event for autorefresh * @topology: topology of the display * @idle_timeout: idle timeout duration in milliseconds + * @wide_bus_en: wide bus is enabled on this interface * @dsc: drm_dsc_config pointer, for DSC-enabled encoders */ struct dpu_encoder_virt { @@ -340,9 +341,7 @@ void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, phys_enc->intf_idx - INTF_0, phys_enc->wb_idx - WB_0, phys_enc->hw_pp->idx - PINGPONG_0, intr_idx); - if (phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done( - phys_enc->parent, phys_enc, + dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, DPU_ENCODER_FRAME_EVENT_ERROR); } @@ -579,19 +578,18 @@ static struct msm_display_topology dpu_encoder_get_topology( topology.num_dspp = topology.num_lm; } - topology.num_enc = 0; topology.num_intf = intf_count; if (dpu_enc->dsc) { - /* In case of Display Stream Compression (DSC), we would use - * 2 encoders, 2 layer mixers and 1 interface + /* + * In case of Display Stream Compression (DSC), we would use + * 2 DSC encoders, 2 layer mixers and 1 interface * this is power optimal and can drive up to (including) 4k * screens */ - topology.num_enc = 2; topology.num_dsc = 2; - topology.num_intf = 1; topology.num_lm = 2; + topology.num_intf = 1; } return topology; @@ -1284,7 +1282,7 @@ static enum dpu_wb dpu_encoder_get_wb(const struct dpu_mdss_cfg *catalog, return WB_MAX; } -static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, +void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, struct dpu_encoder_phys *phy_enc) { struct dpu_encoder_virt *dpu_enc = NULL; @@ -1306,7 +1304,7 @@ static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, DPU_ATRACE_END("encoder_vblank_callback"); } -static void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc, +void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc, struct dpu_encoder_phys *phy_enc) { if (!phy_enc) @@ -1382,7 +1380,7 @@ void dpu_encoder_register_frame_event_callback(struct drm_encoder *drm_enc, spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); } -static void dpu_encoder_frame_done_callback( +void dpu_encoder_frame_done_callback( struct drm_encoder *drm_enc, struct dpu_encoder_phys *ready_phys, u32 event) { @@ -1830,6 +1828,9 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc, if (hw_pp->ops.setup_dsc) hw_pp->ops.setup_dsc(hw_pp); + if (hw_dsc->ops.dsc_bind_pingpong_blk) + hw_dsc->ops.dsc_bind_pingpong_blk(hw_dsc, true, hw_pp->idx); + if (hw_pp->ops.enable_dsc) hw_pp->ops.enable_dsc(hw_pp); } @@ -2233,12 +2234,6 @@ static int dpu_encoder_virt_add_phys_encs( return 0; } -static const struct dpu_encoder_virt_ops dpu_encoder_parent_ops = { - .handle_vblank_virt = dpu_encoder_vblank_callback, - .handle_underrun_virt = dpu_encoder_underrun_callback, - .handle_frame_done = dpu_encoder_frame_done_callback, -}; - static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, struct dpu_kms *dpu_kms, struct msm_display_info *disp_info) @@ -2258,7 +2253,6 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, memset(&phys_params, 0, sizeof(phys_params)); phys_params.dpu_kms = dpu_kms; phys_params.parent = &dpu_enc->base; - phys_params.parent_ops = &dpu_encoder_parent_ops; phys_params.enc_spinlock = &dpu_enc->enc_spinlock; switch (disp_info->intf_type) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index f2af07d87f56..1d434b22180d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -61,25 +61,6 @@ enum dpu_enc_enable_state { struct dpu_encoder_phys; /** - * struct dpu_encoder_virt_ops - Interface the containing virtual encoder - * provides for the physical encoders to use to callback. - * @handle_vblank_virt: Notify virtual encoder of vblank IRQ reception - * Note: This is called from IRQ handler context. - * @handle_underrun_virt: Notify virtual encoder of underrun IRQ reception - * Note: This is called from IRQ handler context. - * @handle_frame_done: Notify virtual encoder that this phys encoder - * completes last request frame. - */ -struct dpu_encoder_virt_ops { - void (*handle_vblank_virt)(struct drm_encoder *, - struct dpu_encoder_phys *phys); - void (*handle_underrun_virt)(struct drm_encoder *, - struct dpu_encoder_phys *phys); - void (*handle_frame_done)(struct drm_encoder *, - struct dpu_encoder_phys *phys, u32 event); -}; - -/** * struct dpu_encoder_phys_ops - Interface the physical encoders provide to * the containing virtual encoder. * @late_register: DRM Call. Add Userspace interfaces, debugfs. @@ -199,7 +180,6 @@ enum dpu_intr_idx { struct dpu_encoder_phys { struct drm_encoder *parent; struct dpu_encoder_phys_ops ops; - const struct dpu_encoder_virt_ops *parent_ops; struct dpu_hw_mdp *hw_mdptop; struct dpu_hw_ctl *hw_ctl; struct dpu_hw_pingpong *hw_pp; @@ -283,7 +263,6 @@ struct dpu_encoder_phys_cmd { struct dpu_enc_phys_init_params { struct dpu_kms *dpu_kms; struct drm_encoder *parent; - const struct dpu_encoder_virt_ops *parent_ops; enum dpu_enc_split_role split_role; enum dpu_intf intf_idx; enum dpu_wb wb_idx; @@ -400,4 +379,30 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, */ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc); +/** + * dpu_encoder_vblank_callback - Notify virtual encoder of vblank IRQ reception + * @drm_enc: Pointer to drm encoder structure + * @phys_enc: Pointer to physical encoder + * Note: This is called from IRQ handler context. + */ +void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, + struct dpu_encoder_phys *phy_enc); + +/** dpu_encoder_underrun_callback - Notify virtual encoder of underrun IRQ reception + * @drm_enc: Pointer to drm encoder structure + * @phys_enc: Pointer to physical encoder + * Note: This is called from IRQ handler context. + */ +void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc, + struct dpu_encoder_phys *phy_enc); + +/** dpu_encoder_frame_done_callback -- Notify virtual encoder that this phys encoder completes last request frame + * @drm_enc: Pointer to drm encoder structure + * @phys_enc: Pointer to physical encoder + * @event: Event to process + */ +void dpu_encoder_frame_done_callback( + struct drm_encoder *drm_enc, + struct dpu_encoder_phys *ready_phys, u32 event); + #endif /* __dpu_encoder_phys_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index ae28b2b93e69..c8f4a62a9536 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -61,6 +61,7 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg( intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_CMD; intf_cfg.stream_sel = cmd_enc->stream_sel; intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc); + intf_cfg.dsc = dpu_encoder_helper_get_dsc(phys_enc); ctl->ops.setup_intf_cfg(ctl, &intf_cfg); /* setup which pp blk will connect to this intf */ @@ -83,9 +84,7 @@ static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) DPU_ATRACE_BEGIN("pp_done_irq"); /* notify all synchronous clients first, then asynchronous clients */ - if (phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done(phys_enc->parent, - phys_enc, event); + dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, event); spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); @@ -111,9 +110,7 @@ static void dpu_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx) DPU_ATRACE_BEGIN("rd_ptr_irq"); cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - if (phys_enc->parent_ops->handle_vblank_virt) - phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent, - phys_enc); + dpu_encoder_vblank_callback(phys_enc->parent, phys_enc); atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0); wake_up_all(&cmd_enc->pending_vblank_wq); @@ -137,9 +134,7 @@ static void dpu_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx) { struct dpu_encoder_phys *phys_enc = arg; - if (phys_enc->parent_ops->handle_underrun_virt) - phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent, - phys_enc); + dpu_encoder_underrun_callback(phys_enc->parent, phys_enc); } static void dpu_encoder_phys_cmd_atomic_mode_set( @@ -202,9 +197,7 @@ static int _dpu_encoder_phys_cmd_handle_ppdone_timeout( /* request a ctl reset before the next kickoff */ phys_enc->enable_state = DPU_ENC_ERR_NEEDS_HW_RESET; - if (phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done( - drm_enc, phys_enc, frame_event); + dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, frame_event); return -ETIMEDOUT; } @@ -780,7 +773,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( dpu_encoder_phys_cmd_init_ops(&phys_enc->ops); phys_enc->parent = p->parent; - phys_enc->parent_ops = p->parent_ops; phys_enc->dpu_kms = p->dpu_kms; phys_enc->split_role = p->split_role; phys_enc->intf_mode = INTF_MODE_CMD; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 2c14646661b7..48c48106b16a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -237,12 +237,13 @@ static void dpu_encoder_phys_vid_setup_timing_engine( unsigned long lock_flags; struct dpu_hw_intf_cfg intf_cfg = { 0 }; + drm_mode_init(&mode, &phys_enc->cached_mode); + if (!phys_enc->hw_ctl->ops.setup_intf_cfg) { DPU_ERROR("invalid encoder %d\n", phys_enc != NULL); return; } - mode = phys_enc->cached_mode; if (!phys_enc->hw_intf->ops.setup_timing_gen) { DPU_ERROR("timing engine setup is not supported\n"); return; @@ -273,6 +274,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine( intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID; intf_cfg.stream_sel = 0; /* Don't care value for video mode */ intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc); + intf_cfg.dsc = dpu_encoder_helper_get_dsc(phys_enc); if (phys_enc->hw_pp->merge_3d) intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx; @@ -307,9 +309,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) DPU_ATRACE_BEGIN("vblank_irq"); - if (phys_enc->parent_ops->handle_vblank_virt) - phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent, - phys_enc); + dpu_encoder_vblank_callback(phys_enc->parent, phys_enc); atomic_read(&phys_enc->pending_kickoff_cnt); @@ -329,7 +329,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); - phys_enc->parent_ops->handle_frame_done(phys_enc->parent, phys_enc, + dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, DPU_ENCODER_FRAME_EVENT_DONE); DPU_ATRACE_END("vblank_irq"); @@ -339,9 +339,7 @@ static void dpu_encoder_phys_vid_underrun_irq(void *arg, int irq_idx) { struct dpu_encoder_phys *phys_enc = arg; - if (phys_enc->parent_ops->handle_underrun_virt) - phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent, - phys_enc); + dpu_encoder_underrun_callback(phys_enc->parent, phys_enc); } static bool dpu_encoder_phys_vid_needs_single_flush( @@ -634,7 +632,9 @@ static int dpu_encoder_phys_vid_get_frame_count( { struct intf_status s = {0}; u32 fetch_start = 0; - struct drm_display_mode mode = phys_enc->cached_mode; + struct drm_display_mode mode; + + drm_mode_init(&mode, &phys_enc->cached_mode); if (!dpu_encoder_phys_vid_is_master(phys_enc)) return -EINVAL; @@ -697,7 +697,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init( dpu_encoder_phys_vid_init_ops(&phys_enc->ops); phys_enc->parent = p->parent; - phys_enc->parent_ops = p->parent_ops; phys_enc->dpu_kms = p->dpu_kms; phys_enc->split_role = p->split_role; phys_enc->intf_mode = INTF_MODE_VIDEO; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c index 7cbcef6efe17..bac4aa807b4b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c @@ -26,6 +26,7 @@ /** * dpu_encoder_phys_wb_is_master - report wb always as master encoder + * @phys_enc: Pointer to physical encoder */ static bool dpu_encoder_phys_wb_is_master(struct dpu_encoder_phys *phys_enc) { @@ -132,7 +133,6 @@ static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc) * dpu_encoder_phys_wb_setup_fb - setup output framebuffer * @phys_enc: Pointer to physical encoder * @fb: Pointer to output framebuffer - * @wb_roi: Pointer to output region of interest */ static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc, struct drm_framebuffer *fb) @@ -365,13 +365,9 @@ static void _dpu_encoder_phys_wb_frame_done_helper(void *arg) DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0); - if (phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done(phys_enc->parent, - phys_enc, event); + dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, event); - if (phys_enc->parent_ops->handle_vblank_virt) - phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent, - phys_enc); + dpu_encoder_vblank_callback(phys_enc->parent, phys_enc); spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); @@ -441,9 +437,7 @@ static void _dpu_encoder_phys_wb_handle_wbdone_timeout( if (wb_enc->wb_conn) drm_writeback_signal_completion(wb_enc->wb_conn, 0); - if (phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done( - phys_enc->parent, phys_enc, frame_event); + dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, frame_event); } /** @@ -692,7 +686,7 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops) /** * dpu_encoder_phys_wb_init - initialize writeback encoder - * @init: Pointer to init info structure with initialization params + * @p: Pointer to init info structure with initialization params */ struct dpu_encoder_phys *dpu_encoder_phys_wb_init( struct dpu_enc_phys_init_params *p) @@ -723,7 +717,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_wb_init( dpu_encoder_phys_wb_init_ops(&phys_enc->ops); phys_enc->parent = p->parent; - phys_enc->parent_ops = p->parent_ops; phys_enc->dpu_kms = p->dpu_kms; phys_enc->split_role = p->split_role; phys_enc->intf_mode = INTF_MODE_WB_LINE; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c index f436a1f3419d..d95540309d4d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -434,6 +434,12 @@ static const struct dpu_format dpu_format_map[] = { DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV, DPU_FETCH_LINEAR, 2), + PSEUDO_YUV_FMT_LOOSE(P010, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + INTERLEAVED_YUV_FMT(VYUY, 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, @@ -524,12 +530,26 @@ static const struct dpu_format dpu_format_map_ubwc[] = { true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + INTERLEAVED_RGB_FMT_TILED(XRGB2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + PSEUDO_YUV_FMT_TILED(NV12, 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C1_B_Cb, C2_R_Cr, DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV | DPU_FORMAT_FLAG_COMPRESSED, DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12), + + PSEUDO_YUV_FMT_TILED(P010, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, DPU_FORMAT_FLAG_DX | + DPU_FORMAT_FLAG_YUV | + DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_UBWC), }; /* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support @@ -571,13 +591,15 @@ static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt) {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, {DRM_FORMAT_XRGB8888, COLOR_FMT_RGBA8888_UBWC}, {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, + {DRM_FORMAT_XRGB2101010, COLOR_FMT_RGBA1010102_UBWC}, {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC}, }; int color_fmt = -1; int i; - if (fmt->base.pixel_format == DRM_FORMAT_NV12) { + if (fmt->base.pixel_format == DRM_FORMAT_NV12 || + fmt->base.pixel_format == DRM_FORMAT_P010) { if (DPU_FORMAT_IS_DX(fmt)) { if (fmt->unpack_tight) color_fmt = COLOR_FMT_NV12_BPP10_UBWC; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 27f029fdc682..cf053e8f081e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -56,7 +56,7 @@ #define MIXER_SDM845_MASK \ (BIT(DPU_MIXER_SOURCESPLIT) | BIT(DPU_DIM_LAYER) | BIT(DPU_MIXER_COMBINED_ALPHA)) -#define MIXER_SC7180_MASK \ +#define MIXER_QCM2290_MASK \ (BIT(DPU_DIM_LAYER) | BIT(DPU_MIXER_COMBINED_ALPHA)) #define PINGPONG_SDM845_MASK BIT(DPU_PINGPONG_DITHER) @@ -67,6 +67,9 @@ #define CTL_SC7280_MASK \ (BIT(DPU_CTL_ACTIVE_CFG) | BIT(DPU_CTL_FETCH_ACTIVE) | BIT(DPU_CTL_VM_CFG)) +#define CTL_SM8550_MASK \ + (CTL_SC7280_MASK | BIT(DPU_CTL_HAS_LAYER_EXT4)) + #define MERGE_3D_SM8150_MASK (0) #define DSPP_MSM8998_MASK BIT(DPU_DSPP_PCC) | BIT(DPU_DSPP_GC) @@ -86,7 +89,6 @@ BIT(MDP_INTF1_INTR) | \ BIT(MDP_INTF2_INTR) | \ BIT(MDP_INTF3_INTR) | \ - BIT(MDP_INTF4_INTR) | \ BIT(MDP_AD4_0_INTR) | \ BIT(MDP_AD4_1_INTR)) @@ -112,6 +114,14 @@ BIT(MDP_INTF3_INTR) | \ BIT(MDP_INTF4_INTR)) +#define IRQ_SM8350_MASK (BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ + BIT(MDP_SSPP_TOP0_HIST_INTR) | \ + BIT(MDP_INTF0_7xxx_INTR) | \ + BIT(MDP_INTF1_7xxx_INTR) | \ + BIT(MDP_INTF2_7xxx_INTR) | \ + BIT(MDP_INTF3_7xxx_INTR)) + #define IRQ_SC8180X_MASK (BIT(MDP_SSPP_TOP0_INTR) | \ BIT(MDP_SSPP_TOP0_INTR2) | \ BIT(MDP_SSPP_TOP0_HIST_INTR) | \ @@ -124,6 +134,27 @@ BIT(MDP_AD4_0_INTR) | \ BIT(MDP_AD4_1_INTR)) +#define IRQ_SC8280XP_MASK (BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ + BIT(MDP_SSPP_TOP0_HIST_INTR) | \ + BIT(MDP_INTF0_7xxx_INTR) | \ + BIT(MDP_INTF1_7xxx_INTR) | \ + BIT(MDP_INTF2_7xxx_INTR) | \ + BIT(MDP_INTF3_7xxx_INTR) | \ + BIT(MDP_INTF4_7xxx_INTR) | \ + BIT(MDP_INTF5_7xxx_INTR) | \ + BIT(MDP_INTF6_7xxx_INTR) | \ + BIT(MDP_INTF7_7xxx_INTR) | \ + BIT(MDP_INTF8_7xxx_INTR)) + +#define IRQ_SM8450_MASK (BIT(MDP_SSPP_TOP0_INTR) | \ + BIT(MDP_SSPP_TOP0_INTR2) | \ + BIT(MDP_SSPP_TOP0_HIST_INTR) | \ + BIT(MDP_INTF0_7xxx_INTR) | \ + BIT(MDP_INTF1_7xxx_INTR) | \ + BIT(MDP_INTF2_7xxx_INTR) | \ + BIT(MDP_INTF3_7xxx_INTR)) + #define WB_SM8250_MASK (BIT(DPU_WB_LINE_MODE) | \ BIT(DPU_WB_UBWC) | \ BIT(DPU_WB_YUV_CONFIG) | \ @@ -156,6 +187,7 @@ static const uint32_t plane_formats[] = { DRM_FORMAT_RGBX8888, DRM_FORMAT_BGRX8888, DRM_FORMAT_XBGR8888, + DRM_FORMAT_XRGB2101010, DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, DRM_FORMAT_RGB565, @@ -184,6 +216,7 @@ static const uint32_t plane_formats_yuv[] = { DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRX8888, DRM_FORMAT_BGRA8888, + DRM_FORMAT_XRGB2101010, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGBX8888, @@ -208,6 +241,7 @@ static const uint32_t plane_formats_yuv[] = { DRM_FORMAT_RGBX4444, DRM_FORMAT_BGRX4444, + DRM_FORMAT_P010, DRM_FORMAT_NV12, DRM_FORMAT_NV21, DRM_FORMAT_NV16, @@ -318,6 +352,18 @@ static const struct dpu_caps sc7180_dpu_caps = { .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, }; +static const struct dpu_caps sm6115_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0x4, + .qseed_type = DPU_SSPP_SCALER_QSEED3LITE, + .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */ + .ubwc_version = DPU_HW_UBWC_VER_10, + .has_dim_layer = true, + .has_idle_pc = true, + .max_linewidth = 2160, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + static const struct dpu_caps sm8150_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, @@ -350,6 +396,20 @@ static const struct dpu_caps sc8180x_dpu_caps = { .max_vdeci_exp = MAX_VERT_DECIMATION, }; +static const struct dpu_caps sc8280xp_dpu_caps = { + .max_mixer_width = 2560, + .max_mixer_blendstages = 11, + .qseed_type = DPU_SSPP_SCALER_QSEED3LITE, + .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */ + .ubwc_version = DPU_HW_UBWC_VER_40, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 5120, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + static const struct dpu_caps sm8250_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, @@ -364,6 +424,48 @@ static const struct dpu_caps sm8250_dpu_caps = { .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, }; +static const struct dpu_caps sm8350_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .qseed_type = DPU_SSPP_SCALER_QSEED3LITE, + .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */ + .ubwc_version = DPU_HW_UBWC_VER_40, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 4096, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + +static const struct dpu_caps sm8450_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .qseed_type = DPU_SSPP_SCALER_QSEED4, + .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */ + .ubwc_version = DPU_HW_UBWC_VER_40, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 5120, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + +static const struct dpu_caps sm8550_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .qseed_type = DPU_SSPP_SCALER_QSEED3LITE, + .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */ + .ubwc_version = DPU_HW_UBWC_VER_40, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 5120, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + static const struct dpu_caps sc7280_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x7, @@ -444,6 +546,8 @@ static const struct dpu_mdp_cfg sc7180_mdp[] = { .reg_off = 0x2B4, .bit_off = 8}, .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = { .reg_off = 0x2C4, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_WB2] = { + .reg_off = 0x3B8, .bit_off = 24}, }, }; @@ -451,7 +555,7 @@ static const struct dpu_mdp_cfg sc8180x_mdp[] = { { .name = "top_0", .id = MDP_TOP, .base = 0x0, .len = 0x45C, - .features = 0, + .features = BIT(DPU_MDP_AUDIO_SELECT), .highest_bank_bit = 0x3, .clk_ctrls[DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2AC, .bit_off = 0}, @@ -472,12 +576,27 @@ static const struct dpu_mdp_cfg sc8180x_mdp[] = { }, }; +static const struct dpu_mdp_cfg sm6115_mdp[] = { + { + .name = "top_0", .id = MDP_TOP, + .base = 0x0, .len = 0x494, + .features = 0, + .highest_bank_bit = 0x1, + .ubwc_swizzle = 0x7, + .clk_ctrls[DPU_CLK_CTRL_VIG0] = { + .reg_off = 0x2ac, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA0] = { + .reg_off = 0x2ac, .bit_off = 8}, + }, +}; + static const struct dpu_mdp_cfg sm8250_mdp[] = { { .name = "top_0", .id = MDP_TOP, .base = 0x0, .len = 0x494, .features = 0, .highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */ + .ubwc_swizzle = 0x6, .clk_ctrls[DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2AC, .bit_off = 0}, .clk_ctrls[DPU_CLK_CTRL_VIG1] = { @@ -501,11 +620,67 @@ static const struct dpu_mdp_cfg sm8250_mdp[] = { }, }; +static const struct dpu_mdp_cfg sm8350_mdp[] = { + { + .name = "top_0", .id = MDP_TOP, + .base = 0x0, .len = 0x494, + .features = 0, + .highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */ + .clk_ctrls[DPU_CLK_CTRL_VIG0] = { + .reg_off = 0x2ac, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG1] = { + .reg_off = 0x2b4, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG2] = { + .reg_off = 0x2bc, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG3] = { + .reg_off = 0x2c4, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA0] = { + .reg_off = 0x2ac, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_DMA1] = { + .reg_off = 0x2b4, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = { + .reg_off = 0x2bc, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = { + .reg_off = 0x2c4, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_REG_DMA] = { + .reg_off = 0x2bc, .bit_off = 20}, + }, +}; + +static const struct dpu_mdp_cfg sm8450_mdp[] = { + { + .name = "top_0", .id = MDP_TOP, + .base = 0x0, .len = 0x494, + .features = BIT(DPU_MDP_PERIPH_0_REMOVED), + .highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */ + .ubwc_swizzle = 0x6, + .clk_ctrls[DPU_CLK_CTRL_VIG0] = { + .reg_off = 0x2AC, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG1] = { + .reg_off = 0x2B4, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG2] = { + .reg_off = 0x2BC, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG3] = { + .reg_off = 0x2C4, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA0] = { + .reg_off = 0x2AC, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_DMA1] = { + .reg_off = 0x2B4, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = { + .reg_off = 0x2BC, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = { + .reg_off = 0x2C4, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_REG_DMA] = { + .reg_off = 0x2BC, .bit_off = 20}, + }, +}; + static const struct dpu_mdp_cfg sc7280_mdp[] = { { .name = "top_0", .id = MDP_TOP, .base = 0x0, .len = 0x2014, .highest_bank_bit = 0x1, + .ubwc_swizzle = 0x6, .clk_ctrls[DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2AC, .bit_off = 0}, .clk_ctrls[DPU_CLK_CTRL_DMA0] = { @@ -517,6 +692,57 @@ static const struct dpu_mdp_cfg sc7280_mdp[] = { }, }; +static const struct dpu_mdp_cfg sc8280xp_mdp[] = { + { + .name = "top_0", .id = MDP_TOP, + .base = 0x0, .len = 0x494, + .features = 0, + .highest_bank_bit = 2, + .ubwc_swizzle = 6, + .clk_ctrls[DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG1] = { .reg_off = 0x2b4, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG2] = { .reg_off = 0x2bc, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG3] = { .reg_off = 0x2c4, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = { .reg_off = 0x2bc, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = { .reg_off = 0x2c4, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20}, + }, +}; + +static const struct dpu_mdp_cfg sm8550_mdp[] = { + { + .name = "top_0", .id = MDP_TOP, + .base = 0, .len = 0x494, + .features = BIT(DPU_MDP_PERIPH_0_REMOVED), + .highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */ + .ubwc_swizzle = 0x6, + .clk_ctrls[DPU_CLK_CTRL_VIG0] = { + .reg_off = 0x4330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG1] = { + .reg_off = 0x6330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG2] = { + .reg_off = 0x8330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG3] = { + .reg_off = 0xa330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA0] = { + .reg_off = 0x24330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA1] = { + .reg_off = 0x26330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA2] = { + .reg_off = 0x28330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA3] = { + .reg_off = 0x2a330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = { + .reg_off = 0x2c330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = { + .reg_off = 0x2e330, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_REG_DMA] = { + .reg_off = 0x2bc, .bit_off = 20}, + }, +}; + static const struct dpu_mdp_cfg qcm2290_mdp[] = { { .name = "top_0", .id = MDP_TOP, @@ -620,6 +846,45 @@ static const struct dpu_ctl_cfg sc7180_ctl[] = { }, }; +static const struct dpu_ctl_cfg sc8280xp_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, + { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, + { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, + { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, + { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, + { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + static const struct dpu_ctl_cfg sm8150_ctl[] = { { .name = "ctl_0", .id = CTL_0, @@ -659,6 +924,123 @@ static const struct dpu_ctl_cfg sm8150_ctl[] = { }, }; +static const struct dpu_ctl_cfg sm8350_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x1e8, + .features = BIT(DPU_CTL_SPLIT_DISPLAY) | CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, + { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x1e8, + .features = BIT(DPU_CTL_SPLIT_DISPLAY) | CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, + { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x1e8, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, + { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x1e8, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, + { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x1e8, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, + { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x1e8, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + +static const struct dpu_ctl_cfg sm8450_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x204, + .features = BIT(DPU_CTL_ACTIVE_CFG) | BIT(DPU_CTL_SPLIT_DISPLAY) | BIT(DPU_CTL_FETCH_ACTIVE), + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, + { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x204, + .features = BIT(DPU_CTL_SPLIT_DISPLAY) | CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, + { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, + { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, + { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, + { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + +static const struct dpu_ctl_cfg sm8550_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x290, + .features = CTL_SM8550_MASK | BIT(DPU_CTL_SPLIT_DISPLAY), + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, + { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x290, + .features = CTL_SM8550_MASK | BIT(DPU_CTL_SPLIT_DISPLAY), + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, + { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x290, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, + { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x290, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, + { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x290, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, + { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x290, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + static const struct dpu_ctl_cfg sc7280_ctl[] = { { .name = "ctl_0", .id = CTL_0, @@ -849,6 +1231,16 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1), }; +static const struct dpu_sspp_sub_blks sm6115_vig_sblk_0 = + _VIG_SBLK("0", 2, DPU_SSPP_SCALER_QSEED3LITE); + +static const struct dpu_sspp_cfg sm6115_sspp[] = { + SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SM8250_MASK, + sm6115_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0), + SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK, + sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0), +}; + static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 = _VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED3LITE); static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 = @@ -877,6 +1269,68 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1), }; +static const struct dpu_sspp_sub_blks sm8450_vig_sblk_0 = + _VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sm8450_vig_sblk_1 = + _VIG_SBLK("1", 6, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sm8450_vig_sblk_2 = + _VIG_SBLK("2", 7, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sm8450_vig_sblk_3 = + _VIG_SBLK("3", 8, DPU_SSPP_SCALER_QSEED3LITE); + +static const struct dpu_sspp_cfg sm8450_sspp[] = { + SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SC7180_MASK, + sm8450_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0), + SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SC7180_MASK, + sm8450_vig_sblk_1, 4, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG1), + SSPP_BLK("sspp_2", SSPP_VIG2, 0x8000, VIG_SC7180_MASK, + sm8450_vig_sblk_2, 8, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG2), + SSPP_BLK("sspp_3", SSPP_VIG3, 0xa000, VIG_SC7180_MASK, + sm8450_vig_sblk_3, 12, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG3), + SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK, + sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0), + SSPP_BLK("sspp_9", SSPP_DMA1, 0x26000, DMA_SDM845_MASK, + sdm845_dma_sblk_1, 5, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA1), + SSPP_BLK("sspp_10", SSPP_DMA2, 0x28000, DMA_CURSOR_SDM845_MASK, + sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR0), + SSPP_BLK("sspp_11", SSPP_DMA3, 0x2a000, DMA_CURSOR_SDM845_MASK, + sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1), +}; + +static const struct dpu_sspp_sub_blks sm8550_vig_sblk_0 = + _VIG_SBLK("0", 7, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sm8550_vig_sblk_1 = + _VIG_SBLK("1", 8, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sm8550_vig_sblk_2 = + _VIG_SBLK("2", 9, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sm8550_vig_sblk_3 = + _VIG_SBLK("3", 10, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK("12", 5); +static const struct dpu_sspp_sub_blks sd8550_dma_sblk_5 = _DMA_SBLK("13", 6); + +static const struct dpu_sspp_cfg sm8550_sspp[] = { + SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SC7180_MASK, + sm8550_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0), + SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SC7180_MASK, + sm8550_vig_sblk_1, 4, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG1), + SSPP_BLK("sspp_2", SSPP_VIG2, 0x8000, VIG_SC7180_MASK, + sm8550_vig_sblk_2, 8, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG2), + SSPP_BLK("sspp_3", SSPP_VIG3, 0xa000, VIG_SC7180_MASK, + sm8550_vig_sblk_3, 12, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG3), + SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK, + sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0), + SSPP_BLK("sspp_9", SSPP_DMA1, 0x26000, DMA_SDM845_MASK, + sdm845_dma_sblk_1, 5, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA1), + SSPP_BLK("sspp_10", SSPP_DMA2, 0x28000, DMA_SDM845_MASK, + sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA2), + SSPP_BLK("sspp_11", SSPP_DMA3, 0x2a000, DMA_SDM845_MASK, + sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA3), + SSPP_BLK("sspp_12", SSPP_DMA4, 0x2c000, DMA_CURSOR_SDM845_MASK, + sm8550_dma_sblk_4, 14, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR0), + SSPP_BLK("sspp_13", SSPP_DMA5, 0x2e000, DMA_CURSOR_SDM845_MASK, + sd8550_dma_sblk_5, 15, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1), +}; + static const struct dpu_sspp_cfg sc7280_sspp[] = { SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SC7280_MASK, sc7280_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0), @@ -888,6 +1342,33 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1), }; +static const struct dpu_sspp_sub_blks sc8280xp_vig_sblk_0 = + _VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sc8280xp_vig_sblk_1 = + _VIG_SBLK("1", 6, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sc8280xp_vig_sblk_2 = + _VIG_SBLK("2", 7, DPU_SSPP_SCALER_QSEED3LITE); +static const struct dpu_sspp_sub_blks sc8280xp_vig_sblk_3 = + _VIG_SBLK("3", 8, DPU_SSPP_SCALER_QSEED3LITE); + +static const struct dpu_sspp_cfg sc8280xp_sspp[] = { + SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SM8250_MASK, + sc8280xp_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0), + SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SM8250_MASK, + sc8280xp_vig_sblk_1, 4, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG1), + SSPP_BLK("sspp_2", SSPP_VIG2, 0x8000, VIG_SM8250_MASK, + sc8280xp_vig_sblk_2, 8, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG2), + SSPP_BLK("sspp_3", SSPP_VIG3, 0xa000, VIG_SM8250_MASK, + sc8280xp_vig_sblk_3, 12, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG3), + SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK, + sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0), + SSPP_BLK("sspp_9", SSPP_DMA1, 0x26000, DMA_SDM845_MASK, + sdm845_dma_sblk_1, 5, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA1), + SSPP_BLK("sspp_10", SSPP_DMA2, 0x28000, DMA_CURSOR_SDM845_MASK, + sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR0), + SSPP_BLK("sspp_11", SSPP_DMA3, 0x2a000, DMA_CURSOR_SDM845_MASK, + sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1), +}; #define _VIG_SBLK_NOSCALE(num, sdma_pri) \ { \ @@ -990,12 +1471,23 @@ static const struct dpu_lm_sub_blks sc7180_lm_sblk = { }; static const struct dpu_lm_cfg sc7180_lm[] = { - LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK, + LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK, &sc7180_lm_sblk, PINGPONG_0, LM_1, DSPP_0), - LM_BLK("lm_1", LM_1, 0x45000, MIXER_SC7180_MASK, + LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK, &sc7180_lm_sblk, PINGPONG_1, LM_0, 0), }; +/* SC8280XP */ + +static const struct dpu_lm_cfg sc8280xp_lm[] = { + LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_0, LM_1, DSPP_0), + LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_1, LM_0, DSPP_1), + LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_2, LM_3, DSPP_2), + LM_BLK("lm_3", LM_3, 0x47000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_3, LM_2, DSPP_3), + LM_BLK("lm_4", LM_4, 0x48000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_4, LM_5, 0), + LM_BLK("lm_5", LM_5, 0x49000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_5, LM_4, 0), +}; + /* SM8150 */ static const struct dpu_lm_cfg sm8150_lm[] = { @@ -1014,11 +1506,11 @@ static const struct dpu_lm_cfg sm8150_lm[] = { }; static const struct dpu_lm_cfg sc7280_lm[] = { - LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK, + LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK, &sc7180_lm_sblk, PINGPONG_0, 0, DSPP_0), - LM_BLK("lm_2", LM_2, 0x46000, MIXER_SC7180_MASK, + LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK, &sc7180_lm_sblk, PINGPONG_2, LM_3, 0), - LM_BLK("lm_3", LM_3, 0x47000, MIXER_SC7180_MASK, + LM_BLK("lm_3", LM_3, 0x47000, MIXER_SDM845_MASK, &sc7180_lm_sblk, PINGPONG_3, LM_2, 0), }; @@ -1033,7 +1525,7 @@ static const struct dpu_lm_sub_blks qcm2290_lm_sblk = { }; static const struct dpu_lm_cfg qcm2290_lm[] = { - LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK, + LM_BLK("lm_0", LM_0, 0x44000, MIXER_QCM2290_MASK, &qcm2290_lm_sblk, PINGPONG_0, 0, DSPP_0), }; @@ -1113,6 +1605,16 @@ static const struct dpu_pingpong_sub_blks sc7280_pp_sblk = { .len = 0x20, .version = 0x20000}, }; +#define PP_BLK_DIPHER(_name, _id, _base, _merge_3d, _sblk, _done, _rdptr) \ + {\ + .name = _name, .id = _id, \ + .base = _base, .len = 0, \ + .features = BIT(DPU_PINGPONG_DITHER), \ + .merge_3d = _merge_3d, \ + .sblk = &_sblk, \ + .intr_done = _done, \ + .intr_rdptr = _rdptr, \ + } #define PP_BLK_TE(_name, _id, _base, _merge_3d, _sblk, _done, _rdptr) \ {\ .name = _name, .id = _id, \ @@ -1154,6 +1656,21 @@ static struct dpu_pingpong_cfg sc7180_pp[] = { PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800, 0, sdm845_pp_sblk_te, -1, -1), }; +static struct dpu_pingpong_cfg sc8280xp_pp[] = { + PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), -1), + PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), -1), + PP_BLK_TE("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), -1), + PP_BLK_TE("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), -1), + PP_BLK_TE("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), -1), + PP_BLK_TE("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), -1), +}; + static const struct dpu_pingpong_cfg sm8150_pp[] = { PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000, MERGE_3D_0, sdm845_pp_sblk_te, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), @@ -1175,12 +1692,95 @@ static const struct dpu_pingpong_cfg sm8150_pp[] = { -1), }; +static const struct dpu_pingpong_cfg sm8350_pp[] = { + PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)), + PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)), + PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14)), + PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15)), + PP_BLK("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + -1), + PP_BLK("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + -1), +}; + +static const struct dpu_pingpong_cfg sc7280_pp[] = { + PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1), +}; + static struct dpu_pingpong_cfg qcm2290_pp[] = { PP_BLK("pingpong_0", PINGPONG_0, 0x70000, 0, sdm845_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)), }; +/* FIXME: interrupts */ +static const struct dpu_pingpong_cfg sm8450_pp[] = { + PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)), + PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)), + PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14)), + PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15)), + PP_BLK("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + -1), + PP_BLK("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + -1), + PP_BLK("pingpong_6", PINGPONG_6, 0x65800, MERGE_3D_3, sdm845_pp_sblk, + -1, + -1), + PP_BLK("pingpong_7", PINGPONG_7, 0x65c00, MERGE_3D_3, sdm845_pp_sblk, + -1, + -1), +}; + +static const struct dpu_pingpong_cfg sm8550_pp[] = { + PP_BLK_DIPHER("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + -1), + PP_BLK_DIPHER("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + -1), + PP_BLK_DIPHER("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + -1), + PP_BLK_DIPHER("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + -1), + PP_BLK_DIPHER("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + -1), + PP_BLK_DIPHER("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + -1), + PP_BLK_DIPHER("pingpong_6", PINGPONG_6, 0x66000, MERGE_3D_3, sc7280_pp_sblk, + -1, + -1), + PP_BLK_DIPHER("pingpong_7", PINGPONG_7, 0x66400, MERGE_3D_3, sc7280_pp_sblk, + -1, + -1), +}; + /************************************************************* * MERGE_3D sub blocks config *************************************************************/ @@ -1198,28 +1798,48 @@ static const struct dpu_merge_3d_cfg sm8150_merge_3d[] = { MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x83200), }; -static const struct dpu_pingpong_cfg sc7280_pp[] = { - PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1), +static const struct dpu_merge_3d_cfg sm8350_merge_3d[] = { + MERGE_3D_BLK("merge_3d_0", MERGE_3D_0, 0x4e000), + MERGE_3D_BLK("merge_3d_1", MERGE_3D_1, 0x4f000), + MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x50000), +}; + +static const struct dpu_merge_3d_cfg sm8450_merge_3d[] = { + MERGE_3D_BLK("merge_3d_0", MERGE_3D_0, 0x4e000), + MERGE_3D_BLK("merge_3d_1", MERGE_3D_1, 0x4f000), + MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x50000), + MERGE_3D_BLK("merge_3d_3", MERGE_3D_3, 0x65f00), +}; + +static const struct dpu_merge_3d_cfg sm8550_merge_3d[] = { + MERGE_3D_BLK("merge_3d_0", MERGE_3D_0, 0x4e000), + MERGE_3D_BLK("merge_3d_1", MERGE_3D_1, 0x4f000), + MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x50000), + MERGE_3D_BLK("merge_3d_3", MERGE_3D_3, 0x66700), }; /************************************************************* * DSC sub blocks config *************************************************************/ -#define DSC_BLK(_name, _id, _base) \ +#define DSC_BLK(_name, _id, _base, _features) \ {\ .name = _name, .id = _id, \ .base = _base, .len = 0x140, \ - .features = 0, \ + .features = _features, \ } static struct dpu_dsc_cfg sdm845_dsc[] = { - DSC_BLK("dsc_0", DSC_0, 0x80000), - DSC_BLK("dsc_1", DSC_1, 0x80400), - DSC_BLK("dsc_2", DSC_2, 0x80800), - DSC_BLK("dsc_3", DSC_3, 0x80c00), + DSC_BLK("dsc_0", DSC_0, 0x80000, 0), + DSC_BLK("dsc_1", DSC_1, 0x80400, 0), + DSC_BLK("dsc_2", DSC_2, 0x80800, 0), + DSC_BLK("dsc_3", DSC_3, 0x80c00, 0), +}; + +static struct dpu_dsc_cfg sm8150_dsc[] = { + DSC_BLK("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_OUTPUT_CTRL)), + DSC_BLK("dsc_1", DSC_1, 0x80400, BIT(DPU_DSC_OUTPUT_CTRL)), + DSC_BLK("dsc_2", DSC_2, 0x80800, BIT(DPU_DSC_OUTPUT_CTRL)), + DSC_BLK("dsc_3", DSC_3, 0x80c00, BIT(DPU_DSC_OUTPUT_CTRL)), }; /************************************************************* @@ -1269,6 +1889,13 @@ static const struct dpu_intf_cfg sc7280_intf[] = { INTF_BLK("intf_5", INTF_5, 0x39000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 22, 23), }; +static const struct dpu_intf_cfg sm8350_intf[] = { + INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25), + INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27), + INTF_BLK("intf_2", INTF_2, 0x36000, INTF_DSI, 1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 28, 29), + INTF_BLK("intf_3", INTF_3, 0x37000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 30, 31), +}; + static const struct dpu_intf_cfg sc8180x_intf[] = { INTF_BLK("intf_0", INTF_0, 0x6A000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 24, 25), INTF_BLK("intf_1", INTF_1, 0x6A800, INTF_DSI, 0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 26, 27), @@ -1279,11 +1906,39 @@ static const struct dpu_intf_cfg sc8180x_intf[] = { INTF_BLK("intf_5", INTF_5, 0x6C800, INTF_DP, MSM_DP_CONTROLLER_2, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 22, 23), }; +/* TODO: INTF 3, 8 and 7 are used for MST, marked as INTF_NONE for now */ +static const struct dpu_intf_cfg sc8280xp_intf[] = { + INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25), + INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27), + INTF_BLK("intf_2", INTF_2, 0x36000, INTF_DSI, 1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 28, 29), + INTF_BLK("intf_3", INTF_3, 0x37000, INTF_NONE, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 30, 31), + INTF_BLK("intf_4", INTF_4, 0x38000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 20, 21), + INTF_BLK("intf_5", INTF_5, 0x39000, INTF_DP, MSM_DP_CONTROLLER_3, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 22, 23), + INTF_BLK("intf_6", INTF_6, 0x3a000, INTF_DP, MSM_DP_CONTROLLER_2, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 16, 17), + INTF_BLK("intf_7", INTF_7, 0x3b000, INTF_NONE, MSM_DP_CONTROLLER_2, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 18, 19), + INTF_BLK("intf_8", INTF_8, 0x3c000, INTF_NONE, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 12, 13), +}; + static const struct dpu_intf_cfg qcm2290_intf[] = { INTF_BLK("intf_0", INTF_0, 0x00000, INTF_NONE, 0, 0, 0, 0, 0, 0), INTF_BLK("intf_1", INTF_1, 0x6A800, INTF_DSI, 0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 26, 27), }; +static const struct dpu_intf_cfg sm8450_intf[] = { + INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25), + INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27), + INTF_BLK("intf_2", INTF_2, 0x36000, INTF_DSI, 1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 28, 29), + INTF_BLK("intf_3", INTF_3, 0x37000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 30, 31), +}; + +static const struct dpu_intf_cfg sm8550_intf[] = { + INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25), + /* TODO TE sub-blocks for intf1 & intf2 */ + INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27), + INTF_BLK("intf_2", INTF_2, 0x36000, INTF_DSI, 1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 28, 29), + INTF_BLK("intf_3", INTF_3, 0x37000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 30, 31), +}; + /************************************************************* * Writeback blocks config *************************************************************/ @@ -1381,6 +2036,14 @@ static const struct dpu_vbif_cfg sdm845_vbif[] = { }, }; +static const struct dpu_reg_dma_cfg sc8280xp_regdma = { + .base = 0x0, + .version = 0x00020000, + .trigger_sel_off = 0x119c, + .xin_id = 7, + .clk_ctrl = DPU_CLK_CTRL_REG_DMA, +}; + static const struct dpu_reg_dma_cfg sdm845_regdma = { .base = 0x0, .version = 0x1, .trigger_sel_off = 0x119c }; @@ -1397,6 +2060,22 @@ static const struct dpu_reg_dma_cfg sm8250_regdma = { .clk_ctrl = DPU_CLK_CTRL_REG_DMA, }; +static const struct dpu_reg_dma_cfg sm8350_regdma = { + .base = 0x400, + .version = 0x00020000, + .trigger_sel_off = 0x119c, + .xin_id = 7, + .clk_ctrl = DPU_CLK_CTRL_REG_DMA, +}; + +static const struct dpu_reg_dma_cfg sm8450_regdma = { + .base = 0x0, + .version = 0x00020000, + .trigger_sel_off = 0x119c, + .xin_id = 7, + .clk_ctrl = DPU_CLK_CTRL_REG_DMA, +}; + /************************************************************* * PERF data config *************************************************************/ @@ -1587,6 +2266,35 @@ static const struct dpu_perf_cfg sc7180_perf_data = { .bw_inefficiency_factor = 120, }; +static const struct dpu_perf_cfg sm6115_perf_data = { + .max_bw_low = 3100000, + .max_bw_high = 4000000, + .min_core_ib = 2400000, + .min_llcc_ib = 800000, + .min_dram_ib = 800000, + .min_prefill_lines = 24, + .danger_lut_tbl = {0xff, 0xffff, 0x0}, + .safe_lut_tbl = {0xfff0, 0xff00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear + }, + {.nentry = ARRAY_SIZE(sc7180_qos_macrotile), + .entries = sc7180_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + static const struct dpu_perf_cfg sm8150_perf_data = { .max_bw_low = 12800000, .max_bw_high = 12800000, @@ -1624,6 +2332,33 @@ static const struct dpu_perf_cfg sc8180x_perf_data = { .min_dram_ib = 800000, .danger_lut_tbl = {0xf, 0xffff, 0x0}, .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear + }, + {.nentry = ARRAY_SIZE(sc7180_qos_macrotile), + .entries = sc7180_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_perf_cfg sc8280xp_perf_data = { + .max_bw_low = 13600000, + .max_bw_high = 18200000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .danger_lut_tbl = {0xf, 0xffff, 0x0}, + .qos_lut_tbl = { {.nentry = ARRAY_SIZE(sc8180x_qos_linear), .entries = sc8180x_qos_linear }, @@ -1672,6 +2407,36 @@ static const struct dpu_perf_cfg sm8250_perf_data = { .bw_inefficiency_factor = 120, }; +static const struct dpu_perf_cfg sm8450_perf_data = { + .max_bw_low = 13600000, + .max_bw_high = 18200000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .min_prefill_lines = 35, + /* FIXME: lut tables */ + .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0}, + .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear + }, + {.nentry = ARRAY_SIZE(sc7180_qos_macrotile), + .entries = sc7180_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + static const struct dpu_perf_cfg sc7280_perf_data = { .max_bw_low = 4700000, .max_bw_high = 8800000, @@ -1700,6 +2465,36 @@ static const struct dpu_perf_cfg sc7280_perf_data = { .bw_inefficiency_factor = 120, }; +static const struct dpu_perf_cfg sm8350_perf_data = { + .max_bw_low = 11800000, + .max_bw_high = 15500000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .min_prefill_lines = 40, + /* FIXME: lut tables */ + .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0}, + .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear + }, + {.nentry = ARRAY_SIZE(sc7180_qos_macrotile), + .entries = sc7180_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + static const struct dpu_perf_cfg qcm2290_perf_data = { .max_bw_low = 2700000, .max_bw_high = 2700000, @@ -1798,6 +2593,28 @@ static const struct dpu_mdss_cfg sc7180_dpu_cfg = { .mdss_irqs = IRQ_SC7180_MASK, }; +static const struct dpu_mdss_cfg sm6115_dpu_cfg = { + .caps = &sm6115_dpu_caps, + .mdp_count = ARRAY_SIZE(sm6115_mdp), + .mdp = sm6115_mdp, + .ctl_count = ARRAY_SIZE(qcm2290_ctl), + .ctl = qcm2290_ctl, + .sspp_count = ARRAY_SIZE(sm6115_sspp), + .sspp = sm6115_sspp, + .mixer_count = ARRAY_SIZE(qcm2290_lm), + .mixer = qcm2290_lm, + .dspp_count = ARRAY_SIZE(qcm2290_dspp), + .dspp = qcm2290_dspp, + .pingpong_count = ARRAY_SIZE(qcm2290_pp), + .pingpong = qcm2290_pp, + .intf_count = ARRAY_SIZE(qcm2290_intf), + .intf = qcm2290_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .perf = &sm6115_perf_data, + .mdss_irqs = IRQ_SC7180_MASK, +}; + static const struct dpu_mdss_cfg sm8150_dpu_cfg = { .caps = &sm8150_dpu_caps, .mdp_count = ARRAY_SIZE(sdm845_mdp), @@ -1810,6 +2627,8 @@ static const struct dpu_mdss_cfg sm8150_dpu_cfg = { .mixer = sm8150_lm, .dspp_count = ARRAY_SIZE(sm8150_dspp), .dspp = sm8150_dspp, + .dsc_count = ARRAY_SIZE(sm8150_dsc), + .dsc = sm8150_dsc, .pingpong_count = ARRAY_SIZE(sm8150_pp), .pingpong = sm8150_pp, .merge_3d_count = ARRAY_SIZE(sm8150_merge_3d), @@ -1848,6 +2667,32 @@ static const struct dpu_mdss_cfg sc8180x_dpu_cfg = { .mdss_irqs = IRQ_SC8180X_MASK, }; +static const struct dpu_mdss_cfg sc8280xp_dpu_cfg = { + .caps = &sc8280xp_dpu_caps, + .mdp_count = ARRAY_SIZE(sc8280xp_mdp), + .mdp = sc8280xp_mdp, + .ctl_count = ARRAY_SIZE(sc8280xp_ctl), + .ctl = sc8280xp_ctl, + .sspp_count = ARRAY_SIZE(sc8280xp_sspp), + .sspp = sc8280xp_sspp, + .mixer_count = ARRAY_SIZE(sc8280xp_lm), + .mixer = sc8280xp_lm, + .dspp_count = ARRAY_SIZE(sm8150_dspp), + .dspp = sm8150_dspp, + .pingpong_count = ARRAY_SIZE(sc8280xp_pp), + .pingpong = sc8280xp_pp, + .merge_3d_count = ARRAY_SIZE(sm8350_merge_3d), + .merge_3d = sm8350_merge_3d, + .intf_count = ARRAY_SIZE(sc8280xp_intf), + .intf = sc8280xp_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .reg_dma_count = 1, + .dma_cfg = &sc8280xp_regdma, + .perf = &sc8280xp_perf_data, + .mdss_irqs = IRQ_SC8280XP_MASK, +}; + static const struct dpu_mdss_cfg sm8250_dpu_cfg = { .caps = &sm8250_dpu_caps, .mdp_count = ARRAY_SIZE(sm8250_mdp), @@ -1860,6 +2705,8 @@ static const struct dpu_mdss_cfg sm8250_dpu_cfg = { .mixer = sm8150_lm, .dspp_count = ARRAY_SIZE(sm8150_dspp), .dspp = sm8150_dspp, + .dsc_count = ARRAY_SIZE(sm8150_dsc), + .dsc = sm8150_dsc, .pingpong_count = ARRAY_SIZE(sm8150_pp), .pingpong = sm8150_pp, .merge_3d_count = ARRAY_SIZE(sm8150_merge_3d), @@ -1876,6 +2723,84 @@ static const struct dpu_mdss_cfg sm8250_dpu_cfg = { .mdss_irqs = IRQ_SM8250_MASK, }; +static const struct dpu_mdss_cfg sm8350_dpu_cfg = { + .caps = &sm8350_dpu_caps, + .mdp_count = ARRAY_SIZE(sm8350_mdp), + .mdp = sm8350_mdp, + .ctl_count = ARRAY_SIZE(sm8350_ctl), + .ctl = sm8350_ctl, + .sspp_count = ARRAY_SIZE(sm8250_sspp), + .sspp = sm8250_sspp, + .mixer_count = ARRAY_SIZE(sm8150_lm), + .mixer = sm8150_lm, + .dspp_count = ARRAY_SIZE(sm8150_dspp), + .dspp = sm8150_dspp, + .pingpong_count = ARRAY_SIZE(sm8350_pp), + .pingpong = sm8350_pp, + .merge_3d_count = ARRAY_SIZE(sm8350_merge_3d), + .merge_3d = sm8350_merge_3d, + .intf_count = ARRAY_SIZE(sm8350_intf), + .intf = sm8350_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .reg_dma_count = 1, + .dma_cfg = &sm8350_regdma, + .perf = &sm8350_perf_data, + .mdss_irqs = IRQ_SM8350_MASK, +}; + +static const struct dpu_mdss_cfg sm8450_dpu_cfg = { + .caps = &sm8450_dpu_caps, + .mdp_count = ARRAY_SIZE(sm8450_mdp), + .mdp = sm8450_mdp, + .ctl_count = ARRAY_SIZE(sm8450_ctl), + .ctl = sm8450_ctl, + .sspp_count = ARRAY_SIZE(sm8450_sspp), + .sspp = sm8450_sspp, + .mixer_count = ARRAY_SIZE(sm8150_lm), + .mixer = sm8150_lm, + .dspp_count = ARRAY_SIZE(sm8150_dspp), + .dspp = sm8150_dspp, + .pingpong_count = ARRAY_SIZE(sm8450_pp), + .pingpong = sm8450_pp, + .merge_3d_count = ARRAY_SIZE(sm8450_merge_3d), + .merge_3d = sm8450_merge_3d, + .intf_count = ARRAY_SIZE(sm8450_intf), + .intf = sm8450_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .reg_dma_count = 1, + .dma_cfg = &sm8450_regdma, + .perf = &sm8450_perf_data, + .mdss_irqs = IRQ_SM8450_MASK, +}; + +static const struct dpu_mdss_cfg sm8550_dpu_cfg = { + .caps = &sm8550_dpu_caps, + .mdp_count = ARRAY_SIZE(sm8550_mdp), + .mdp = sm8550_mdp, + .ctl_count = ARRAY_SIZE(sm8550_ctl), + .ctl = sm8550_ctl, + .sspp_count = ARRAY_SIZE(sm8550_sspp), + .sspp = sm8550_sspp, + .mixer_count = ARRAY_SIZE(sm8150_lm), + .mixer = sm8150_lm, + .dspp_count = ARRAY_SIZE(sm8150_dspp), + .dspp = sm8150_dspp, + .pingpong_count = ARRAY_SIZE(sm8550_pp), + .pingpong = sm8550_pp, + .merge_3d_count = ARRAY_SIZE(sm8550_merge_3d), + .merge_3d = sm8550_merge_3d, + .intf_count = ARRAY_SIZE(sm8550_intf), + .intf = sm8550_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .reg_dma_count = 1, + .dma_cfg = &sm8450_regdma, + .perf = &sm8450_perf_data, + .mdss_irqs = IRQ_SM8450_MASK, +}; + static const struct dpu_mdss_cfg sc7280_dpu_cfg = { .caps = &sc7280_dpu_caps, .mdp_count = ARRAY_SIZE(sc7280_mdp), @@ -1932,8 +2857,13 @@ static const struct dpu_mdss_hw_cfg_handler cfg_handler[] = { { .hw_rev = DPU_HW_VER_510, .dpu_cfg = &sc8180x_dpu_cfg}, { .hw_rev = DPU_HW_VER_600, .dpu_cfg = &sm8250_dpu_cfg}, { .hw_rev = DPU_HW_VER_620, .dpu_cfg = &sc7180_dpu_cfg}, + { .hw_rev = DPU_HW_VER_630, .dpu_cfg = &sm6115_dpu_cfg}, { .hw_rev = DPU_HW_VER_650, .dpu_cfg = &qcm2290_dpu_cfg}, + { .hw_rev = DPU_HW_VER_700, .dpu_cfg = &sm8350_dpu_cfg}, { .hw_rev = DPU_HW_VER_720, .dpu_cfg = &sc7280_dpu_cfg}, + { .hw_rev = DPU_HW_VER_800, .dpu_cfg = &sc8280xp_dpu_cfg}, + { .hw_rev = DPU_HW_VER_810, .dpu_cfg = &sm8450_dpu_cfg}, + { .hw_rev = DPU_HW_VER_900, .dpu_cfg = &sm8550_dpu_cfg}, }; const struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 38aa38ab1568..ddab9caebb18 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -44,8 +44,13 @@ #define DPU_HW_VER_510 DPU_HW_VER(5, 1, 1) /* sc8180 */ #define DPU_HW_VER_600 DPU_HW_VER(6, 0, 0) /* sm8250 */ #define DPU_HW_VER_620 DPU_HW_VER(6, 2, 0) /* sc7180 v1.0 */ +#define DPU_HW_VER_630 DPU_HW_VER(6, 3, 0) /* sm6115|sm4250 */ #define DPU_HW_VER_650 DPU_HW_VER(6, 5, 0) /* qcm2290|sm4125 */ +#define DPU_HW_VER_700 DPU_HW_VER(7, 0, 0) /* sm8350 */ #define DPU_HW_VER_720 DPU_HW_VER(7, 2, 0) /* sc7280 */ +#define DPU_HW_VER_800 DPU_HW_VER(8, 0, 0) /* sc8280xp */ +#define DPU_HW_VER_810 DPU_HW_VER(8, 1, 0) /* sm8450 */ +#define DPU_HW_VER_900 DPU_HW_VER(9, 0, 0) /* sm8550 */ #define IS_MSM8996_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_170) #define IS_MSM8998_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_300) @@ -82,6 +87,8 @@ enum { * @DPU_MDP_UBWC_1_0, This chipsets supports Universal Bandwidth * compression initial revision * @DPU_MDP_UBWC_1_5, Universal Bandwidth compression version 1.5 + * @DPU_MDP_PERIPH_0_REMOVED Indicates that access to periph top0 block results + * in a failure * @DPU_MDP_MAX Maximum value */ @@ -92,6 +99,7 @@ enum { DPU_MDP_UBWC_1_0, DPU_MDP_UBWC_1_5, DPU_MDP_AUDIO_SELECT, + DPU_MDP_PERIPH_0_REMOVED, DPU_MDP_MAX }; @@ -191,6 +199,7 @@ enum { * @DPU_CTL_SPLIT_DISPLAY: CTL supports video mode split display * @DPU_CTL_FETCH_ACTIVE: Active CTL for fetch HW (SSPPs) * @DPU_CTL_VM_CFG: CTL config to support multiple VMs + * @DPU_CTL_HAS_LAYER_EXT4: CTL has the CTL_LAYER_EXT4 register * @DPU_CTL_MAX */ enum { @@ -198,6 +207,7 @@ enum { DPU_CTL_ACTIVE_CFG, DPU_CTL_FETCH_ACTIVE, DPU_CTL_VM_CFG, + DPU_CTL_HAS_LAYER_EXT4, DPU_CTL_MAX }; @@ -266,6 +276,15 @@ enum { }; /** + * DSC features + * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets + * the pixel output from this DSC. + */ +enum { + DPU_DSC_OUTPUT_CTRL = 0x1, +}; + +/** * MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU * @name: string name for debug purposes * @id: enum identifying this block @@ -518,7 +537,6 @@ struct dpu_clk_ctrl_reg { * @base: register base offset to mdss * @features bit mask identifying sub-blocks/features * @highest_bank_bit: UBWC parameter - * @ubwc_static: ubwc static configuration * @ubwc_swizzle: ubwc default swizzle setting * @clk_ctrls clock control register definition */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index a35ecb6676c8..b88a2f3724e6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -17,6 +17,8 @@ (0x70 + (((lm) - LM_0) * 0x004)) #define CTL_LAYER_EXT3(lm) \ (0xA0 + (((lm) - LM_0) * 0x004)) +#define CTL_LAYER_EXT4(lm) \ + (0xB8 + (((lm) - LM_0) * 0x004)) #define CTL_TOP 0x014 #define CTL_FLUSH 0x018 #define CTL_START 0x01C @@ -377,12 +379,37 @@ static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx) DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0); } +struct ctl_blend_config { + int idx, shift, ext_shift; +}; + +static const struct ctl_blend_config ctl_blend_config[][2] = { + [SSPP_NONE] = { { -1 }, { -1 } }, + [SSPP_MAX] = { { -1 }, { -1 } }, + [SSPP_VIG0] = { { 0, 0, 0 }, { 3, 0 } }, + [SSPP_VIG1] = { { 0, 3, 2 }, { 3, 4 } }, + [SSPP_VIG2] = { { 0, 6, 4 }, { 3, 8 } }, + [SSPP_VIG3] = { { 0, 26, 6 }, { 3, 12 } }, + [SSPP_RGB0] = { { 0, 9, 8 }, { -1 } }, + [SSPP_RGB1] = { { 0, 12, 10 }, { -1 } }, + [SSPP_RGB2] = { { 0, 15, 12 }, { -1 } }, + [SSPP_RGB3] = { { 0, 29, 14 }, { -1 } }, + [SSPP_DMA0] = { { 0, 18, 16 }, { 2, 8 } }, + [SSPP_DMA1] = { { 0, 21, 18 }, { 2, 12 } }, + [SSPP_DMA2] = { { 2, 0 }, { 2, 16 } }, + [SSPP_DMA3] = { { 2, 4 }, { 2, 20 } }, + [SSPP_DMA4] = { { 4, 0 }, { 4, 8 } }, + [SSPP_DMA5] = { { 4, 4 }, { 4, 12 } }, + [SSPP_CURSOR0] = { { 1, 20 }, { -1 } }, + [SSPP_CURSOR1] = { { 1, 26 }, { -1 } }, +}; + static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx, enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg) { struct dpu_hw_blk_reg_map *c = &ctx->hw; - u32 mixercfg = 0, mixercfg_ext = 0, mix, ext; - u32 mixercfg_ext2 = 0, mixercfg_ext3 = 0; + u32 mix, ext, mix_ext; + u32 mixercfg[5] = { 0 }; int i, j; int stages; int pipes_per_stage; @@ -397,7 +424,7 @@ static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx, else pipes_per_stage = 1; - mixercfg = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */ + mixercfg[0] = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */ if (!stage_cfg) goto exit; @@ -406,109 +433,35 @@ static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx, /* overflow to ext register if 'i + 1 > 7' */ mix = (i + 1) & 0x7; ext = i >= 7; + mix_ext = (i + 1) & 0xf; for (j = 0 ; j < pipes_per_stage; j++) { enum dpu_sspp_multirect_index rect_index = stage_cfg->multirect_index[i][j]; - - switch (stage_cfg->stage[i][j]) { - case SSPP_VIG0: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext3 |= ((i + 1) & 0xF) << 0; - } else { - mixercfg |= mix << 0; - mixercfg_ext |= ext << 0; - } - break; - case SSPP_VIG1: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext3 |= ((i + 1) & 0xF) << 4; - } else { - mixercfg |= mix << 3; - mixercfg_ext |= ext << 2; - } - break; - case SSPP_VIG2: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext3 |= ((i + 1) & 0xF) << 8; - } else { - mixercfg |= mix << 6; - mixercfg_ext |= ext << 4; - } - break; - case SSPP_VIG3: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext3 |= ((i + 1) & 0xF) << 12; - } else { - mixercfg |= mix << 26; - mixercfg_ext |= ext << 6; - } - break; - case SSPP_RGB0: - mixercfg |= mix << 9; - mixercfg_ext |= ext << 8; - break; - case SSPP_RGB1: - mixercfg |= mix << 12; - mixercfg_ext |= ext << 10; - break; - case SSPP_RGB2: - mixercfg |= mix << 15; - mixercfg_ext |= ext << 12; - break; - case SSPP_RGB3: - mixercfg |= mix << 29; - mixercfg_ext |= ext << 14; - break; - case SSPP_DMA0: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext2 |= ((i + 1) & 0xF) << 8; - } else { - mixercfg |= mix << 18; - mixercfg_ext |= ext << 16; - } - break; - case SSPP_DMA1: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext2 |= ((i + 1) & 0xF) << 12; - } else { - mixercfg |= mix << 21; - mixercfg_ext |= ext << 18; - } - break; - case SSPP_DMA2: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext2 |= ((i + 1) & 0xF) << 16; - } else { - mix |= (i + 1) & 0xF; - mixercfg_ext2 |= mix << 0; - } - break; - case SSPP_DMA3: - if (rect_index == DPU_SSPP_RECT_1) { - mixercfg_ext2 |= ((i + 1) & 0xF) << 20; - } else { - mix |= (i + 1) & 0xF; - mixercfg_ext2 |= mix << 4; - } - break; - case SSPP_CURSOR0: - mixercfg_ext |= ((i + 1) & 0xF) << 20; - break; - case SSPP_CURSOR1: - mixercfg_ext |= ((i + 1) & 0xF) << 26; - break; - default: - break; + enum dpu_sspp pipe = stage_cfg->stage[i][j]; + const struct ctl_blend_config *cfg = + &ctl_blend_config[pipe][rect_index == DPU_SSPP_RECT_1]; + + /* + * CTL_LAYER has 3-bit field (and extra bits in EXT register), + * all EXT registers has 4-bit fields. + */ + if (cfg->idx == 0) { + mixercfg[0] |= mix << cfg->shift; + mixercfg[1] |= ext << cfg->ext_shift; + } else { + mixercfg[cfg->idx] |= mix_ext << cfg->shift; } } } exit: - DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg); - DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext); - DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg_ext2); - DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3); + DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg[0]); + DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg[1]); + DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg[2]); + DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg[3]); + if ((test_bit(DPU_CTL_HAS_LAYER_EXT4, &ctx->caps->features))) + DPU_REG_WRITE(c, CTL_LAYER_EXT4(lm), mixercfg[4]); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c index f2ddcfb6f7ee..619926da1441 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c @@ -29,6 +29,8 @@ #define DSC_RANGE_MAX_QP 0x0B0 #define DSC_RANGE_BPG_OFFSET 0x0EC +#define DSC_CTL(m) (0x1800 - 0x3FC * (m - DSC_0)) + static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc) { struct dpu_hw_blk_reg_map *c = &dsc->hw; @@ -42,7 +44,7 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, u32 initial_lines) { struct dpu_hw_blk_reg_map *c = &hw_dsc->hw; - u32 data, lsb, bpp; + u32 data; u32 slice_last_group_size; u32 det_thresh_flatness; bool is_cmd_mode = !(mode & DSC_MODE_VIDEO); @@ -56,14 +58,7 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, data = (initial_lines << 20); data |= ((slice_last_group_size - 1) << 18); /* bpp is 6.4 format, 4 LSBs bits are for fractional part */ - data |= dsc->bits_per_pixel << 12; - lsb = dsc->bits_per_pixel % 4; - bpp = dsc->bits_per_pixel / 4; - bpp *= 4; - bpp <<= 4; - bpp |= lsb; - - data |= bpp << 8; + data |= (dsc->bits_per_pixel << 8); data |= (dsc->block_pred_enable << 7); data |= (dsc->line_buf_depth << 3); data |= (dsc->simple_422 << 2); @@ -157,6 +152,29 @@ static void dpu_hw_dsc_config_thresh(struct dpu_hw_dsc *hw_dsc, } } +static void dpu_hw_dsc_bind_pingpong_blk( + struct dpu_hw_dsc *hw_dsc, + bool enable, + const enum dpu_pingpong pp) +{ + struct dpu_hw_blk_reg_map *c = &hw_dsc->hw; + int mux_cfg = 0xF; + u32 dsc_ctl_offset; + + dsc_ctl_offset = DSC_CTL(hw_dsc->idx); + + if (enable) + mux_cfg = (pp - PINGPONG_0) & 0x7; + + DRM_DEBUG_KMS("%s dsc:%d %s pp:%d\n", + enable ? "Binding" : "Unbinding", + hw_dsc->idx - DSC_0, + enable ? "to" : "from", + pp - PINGPONG_0); + + DPU_REG_WRITE(c, dsc_ctl_offset, mux_cfg); +} + static struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc, const struct dpu_mdss_cfg *m, void __iomem *addr, @@ -181,6 +199,8 @@ static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops, ops->dsc_disable = dpu_hw_dsc_disable; ops->dsc_config = dpu_hw_dsc_config; ops->dsc_config_thresh = dpu_hw_dsc_config_thresh; + if (cap & BIT(DPU_DSC_OUTPUT_CTRL)) + ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk; }; struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index c0b77fe1a696..ae9b5db53d7f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -42,6 +42,10 @@ struct dpu_hw_dsc_ops { */ void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc, struct drm_dsc_config *dsc); + + void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc, + bool enable, + enum dpu_pingpong pp); }; struct dpu_hw_dsc { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c index cf1b6d84c18a..53326f25e40e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -35,6 +35,9 @@ #define MDP_INTF_3_OFF_REV_7xxx 0x37000 #define MDP_INTF_4_OFF_REV_7xxx 0x38000 #define MDP_INTF_5_OFF_REV_7xxx 0x39000 +#define MDP_INTF_6_OFF_REV_7xxx 0x3a000 +#define MDP_INTF_7_OFF_REV_7xxx 0x3b000 +#define MDP_INTF_8_OFF_REV_7xxx 0x3c000 /** * struct dpu_intr_reg - array of DPU register sets @@ -139,6 +142,21 @@ static const struct dpu_intr_reg dpu_intr_set[] = { MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_EN, MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_STATUS }, + [MDP_INTF6_7xxx_INTR] = { + MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_CLEAR, + MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_EN, + MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_STATUS + }, + [MDP_INTF7_7xxx_INTR] = { + MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_CLEAR, + MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_EN, + MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_STATUS + }, + [MDP_INTF8_7xxx_INTR] = { + MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_CLEAR, + MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_EN, + MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_STATUS + }, }; #define DPU_IRQ_REG(irq_idx) (irq_idx / 32) @@ -252,9 +270,9 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) cache_irq_mask = intr->cache_irq_mask[reg_idx]; if (cache_irq_mask & DPU_IRQ_MASK(irq_idx)) { - dbgstr = "DPU IRQ already set:"; + dbgstr = "already "; } else { - dbgstr = "DPU IRQ enabled:"; + dbgstr = ""; cache_irq_mask |= DPU_IRQ_MASK(irq_idx); /* Cleaning any pending interrupt */ @@ -268,7 +286,7 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) intr->cache_irq_mask[reg_idx] = cache_irq_mask; } - pr_debug("%s MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", dbgstr, + pr_debug("DPU IRQ %d %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr, DPU_IRQ_MASK(irq_idx), cache_irq_mask); return 0; @@ -301,9 +319,9 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) cache_irq_mask = intr->cache_irq_mask[reg_idx]; if ((cache_irq_mask & DPU_IRQ_MASK(irq_idx)) == 0) { - dbgstr = "DPU IRQ is already cleared:"; + dbgstr = "already "; } else { - dbgstr = "DPU IRQ mask disable:"; + dbgstr = ""; cache_irq_mask &= ~DPU_IRQ_MASK(irq_idx); /* Disable interrupts based on the new mask */ @@ -317,7 +335,7 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) intr->cache_irq_mask[reg_idx] = cache_irq_mask; } - pr_debug("%s MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", dbgstr, + pr_debug("DPU IRQ %d %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr, DPU_IRQ_MASK(irq_idx), cache_irq_mask); return 0; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h index 46443955443c..425465011c80 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -31,6 +31,9 @@ enum dpu_hw_intr_reg { MDP_INTF3_7xxx_INTR, MDP_INTF4_7xxx_INTR, MDP_INTF5_7xxx_INTR, + MDP_INTF6_7xxx_INTR, + MDP_INTF7_7xxx_INTR, + MDP_INTF8_7xxx_INTR, MDP_INTR_MAX, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index d3b0ed0a9c6c..2d9192a6ce00 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -120,6 +120,8 @@ enum dpu_sspp { SSPP_DMA1, SSPP_DMA2, SSPP_DMA3, + SSPP_DMA4, + SSPP_DMA5, SSPP_CURSOR0, SSPP_CURSOR1, SSPP_MAX @@ -195,6 +197,8 @@ enum dpu_pingpong { PINGPONG_3, PINGPONG_4, PINGPONG_5, + PINGPONG_6, + PINGPONG_7, PINGPONG_S0, PINGPONG_MAX }; @@ -203,6 +207,7 @@ enum dpu_merge_3d { MERGE_3D_0 = 1, MERGE_3D_1, MERGE_3D_2, + MERGE_3D_3, MERGE_3D_MAX }; @@ -214,6 +219,8 @@ enum dpu_intf { INTF_4, INTF_5, INTF_6, + INTF_7, + INTF_8, INTF_MAX }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index 691c471b08c2..4246ab0b3bee 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -310,7 +310,11 @@ static void dpu_hw_sspp_setup_format(struct dpu_hw_pipe *ctx, ctx->mdp->highest_bank_bit << 18); switch (ctx->catalog->caps->ubwc_version) { case DPU_HW_UBWC_VER_10: - /* TODO: UBWC v1 case */ + fast_clear = fmt->alpha_enable ? BIT(31) : 0; + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + fast_clear | (ctx->mdp->ubwc_swizzle & 0x1) | + BIT(8) | + (ctx->mdp->highest_bank_bit << 4)); break; case DPU_HW_UBWC_VER_20: fast_clear = fmt->alpha_enable ? BIT(31) : 0; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c index c3110a25a30d..2bb02e17ee52 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c @@ -7,40 +7,17 @@ #include "dpu_hw_top.h" #include "dpu_kms.h" -#define SSPP_SPARE 0x28 - #define FLD_SPLIT_DISPLAY_CMD BIT(1) #define FLD_SMART_PANEL_FREE_RUN BIT(2) #define FLD_INTF_1_SW_TRG_MUX BIT(4) #define FLD_INTF_2_SW_TRG_MUX BIT(8) #define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF -#define DANGER_STATUS 0x360 -#define SAFE_STATUS 0x364 - -#define TE_LINE_INTERVAL 0x3F4 - #define TRAFFIC_SHAPER_EN BIT(31) #define TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4)) #define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4)) #define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4 -#define MDP_WD_TIMER_0_CTL 0x380 -#define MDP_WD_TIMER_0_CTL2 0x384 -#define MDP_WD_TIMER_0_LOAD_VALUE 0x388 -#define MDP_WD_TIMER_1_CTL 0x390 -#define MDP_WD_TIMER_1_CTL2 0x394 -#define MDP_WD_TIMER_1_LOAD_VALUE 0x398 -#define MDP_WD_TIMER_2_CTL 0x420 -#define MDP_WD_TIMER_2_CTL2 0x424 -#define MDP_WD_TIMER_2_LOAD_VALUE 0x428 -#define MDP_WD_TIMER_3_CTL 0x430 -#define MDP_WD_TIMER_3_CTL2 0x434 -#define MDP_WD_TIMER_3_LOAD_VALUE 0x438 -#define MDP_WD_TIMER_4_CTL 0x440 -#define MDP_WD_TIMER_4_CTL2 0x444 -#define MDP_WD_TIMER_4_LOAD_VALUE 0x448 - #define MDP_TICK_COUNT 16 #define XO_CLK_RATE 19200 #define MS_TICKS_IN_SEC 1000 @@ -48,8 +25,6 @@ #define CALCULATE_WD_LOAD_VALUE(fps) \ ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) -#define DCE_SEL 0x450 - static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp, struct split_pipe_cfg *cfg) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h index c8156ed4b7fb..feb9a729844a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h @@ -16,6 +16,7 @@ #define INTR_CLEAR 0x018 #define INTR2_EN 0x008 #define INTR2_STATUS 0x00c +#define SSPP_SPARE 0x028 #define INTR2_CLEAR 0x02c #define HIST_INTR_EN 0x01c #define HIST_INTR_STATUS 0x020 @@ -28,7 +29,15 @@ #define DSPP_IGC_COLOR0_RAM_LUTN 0x300 #define DSPP_IGC_COLOR1_RAM_LUTN 0x304 #define DSPP_IGC_COLOR2_RAM_LUTN 0x308 +#define DANGER_STATUS 0x360 +#define SAFE_STATUS 0x364 #define HW_EVENTS_CTL 0x37C +#define MDP_WD_TIMER_0_CTL 0x380 +#define MDP_WD_TIMER_0_CTL2 0x384 +#define MDP_WD_TIMER_0_LOAD_VALUE 0x388 +#define MDP_WD_TIMER_1_CTL 0x390 +#define MDP_WD_TIMER_1_CTL2 0x394 +#define MDP_WD_TIMER_1_LOAD_VALUE 0x398 #define CLK_CTRL3 0x3A8 #define CLK_STATUS3 0x3AC #define CLK_CTRL4 0x3B0 @@ -43,6 +52,18 @@ #define HDMI_DP_CORE_SELECT 0x408 #define MDP_OUT_CTL_0 0x410 #define MDP_VSYNC_SEL 0x414 +#define MDP_WD_TIMER_2_CTL 0x420 +#define MDP_WD_TIMER_2_CTL2 0x424 +#define MDP_WD_TIMER_2_LOAD_VALUE 0x428 +#define MDP_WD_TIMER_3_CTL 0x430 +#define MDP_WD_TIMER_3_CTL2 0x434 +#define MDP_WD_TIMER_3_LOAD_VALUE 0x438 +#define MDP_WD_TIMER_4_CTL 0x440 +#define MDP_WD_TIMER_4_CTL2 0x444 +#define MDP_WD_TIMER_4_LOAD_VALUE 0x448 #define DCE_SEL 0x450 +#define MDP_PERIPH_TOP0 MDP_WD_TIMER_0_CTL +#define MDP_PERIPH_TOP0_END CLK_CTRL3 + #endif /*_DPU_HWIO_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 5e6e2626151e..a683bd9b5a04 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -194,7 +194,7 @@ struct dpu_debugfs_regset32 { struct dpu_kms *dpu_kms; }; -static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data) +static int dpu_regset32_show(struct seq_file *s, void *data) { struct dpu_debugfs_regset32 *regset = s->private; struct dpu_kms *dpu_kms = regset->dpu_kms; @@ -227,19 +227,7 @@ static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data) return 0; } - -static int dpu_debugfs_open_regset32(struct inode *inode, - struct file *file) -{ - return single_open(file, _dpu_debugfs_show_regset32, inode->i_private); -} - -static const struct file_operations dpu_fops_regset32 = { - .open = dpu_debugfs_open_regset32, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(dpu_regset32); void dpu_debugfs_create_regset32(const char *name, umode_t mode, void *parent, @@ -259,7 +247,7 @@ void dpu_debugfs_create_regset32(const char *name, umode_t mode, regset->blk_len = length; regset->dpu_kms = dpu_kms; - debugfs_create_file(name, mode, parent, regset, &dpu_fops_regset32); + debugfs_create_file(name, mode, parent, regset, &dpu_regset32_fops); } static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) @@ -939,8 +927,20 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k msm_disp_snapshot_add_block(disp_state, cat->wb[i].len, dpu_kms->mmio + cat->wb[i].base, "wb_%d", i); - msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len, - dpu_kms->mmio + cat->mdp[0].base, "top"); + if (cat->mdp[0].features & BIT(DPU_MDP_PERIPH_0_REMOVED)) { + msm_disp_snapshot_add_block(disp_state, MDP_PERIPH_TOP0, + dpu_kms->mmio + cat->mdp[0].base, "top"); + msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len - MDP_PERIPH_TOP0_END, + dpu_kms->mmio + cat->mdp[0].base + MDP_PERIPH_TOP0_END, "top_2"); + } else { + msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len, + dpu_kms->mmio + cat->mdp[0].base, "top"); + } + + /* dump DSC sub-blocks HW regs info */ + for (i = 0; i < cat->dsc_count; i++) + msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len, + dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i); pm_runtime_put_sync(&dpu_kms->pdev->dev); } @@ -1304,8 +1304,13 @@ static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,sc7180-dpu", }, { .compatible = "qcom,sc7280-dpu", }, { .compatible = "qcom,sc8180x-dpu", }, + { .compatible = "qcom,sc8280xp-dpu", }, + { .compatible = "qcom,sm6115-dpu", }, { .compatible = "qcom,sm8150-dpu", }, { .compatible = "qcom,sm8250-dpu", }, + { .compatible = "qcom,sm8350-dpu", }, + { .compatible = "qcom,sm8450-dpu", }, + { .compatible = "qcom,sm8550-dpu", }, {} }; MODULE_DEVICE_TABLE(of, dpu_dt_match); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 658005f609f4..bfd5be89e8b8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -69,9 +69,11 @@ static const uint32_t qcom_compressed_supported_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, + DRM_FORMAT_XRGB2101010, DRM_FORMAT_BGR565, DRM_FORMAT_NV12, + DRM_FORMAT_P010, }; /** @@ -1124,7 +1126,7 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) struct dpu_plane_state *pstate = to_dpu_plane_state(state); struct drm_crtc *crtc = state->crtc; struct drm_framebuffer *fb = state->fb; - bool is_rt_pipe, update_qos_remap; + bool is_rt_pipe; const struct dpu_format *fmt = to_dpu_format(msm_framebuffer_format(fb)); struct dpu_hw_pipe_cfg pipe_cfg; @@ -1136,6 +1138,9 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) pstate->pending = true; is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT); + pstate->needs_qos_remap |= (is_rt_pipe != pdpu->is_rt_pipe); + pdpu->is_rt_pipe = is_rt_pipe; + _dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL); DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FP_FMT "->crtc%u " DRM_RECT_FMT @@ -1217,14 +1222,8 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) _dpu_plane_set_ot_limit(plane, crtc, &pipe_cfg); } - update_qos_remap = (is_rt_pipe != pdpu->is_rt_pipe) || - pstate->needs_qos_remap; - - if (update_qos_remap) { - if (is_rt_pipe != pdpu->is_rt_pipe) - pdpu->is_rt_pipe = is_rt_pipe; - else if (pstate->needs_qos_remap) - pstate->needs_qos_remap = false; + if (pstate->needs_qos_remap) { + pstate->needs_qos_remap = false; _dpu_plane_set_qos_remap(plane); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 73b3442e7467..396429e63756 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -496,6 +496,11 @@ static int _dpu_rm_reserve_dsc(struct dpu_rm *rm, /* check if DSC required are allocated or not */ for (i = 0; i < num_dsc; i++) { + if (!rm->dsc_blks[i]) { + DPU_ERROR("DSC %d does not exist\n", i); + return -EIO; + } + if (global_state->dsc_to_enc_id[i]) { DPU_ERROR("DSC %d is already allocated\n", i); return -EIO; @@ -543,8 +548,8 @@ static int _dpu_rm_populate_requirements( { reqs->topology = req_topology; - DRM_DEBUG_KMS("num_lm: %d num_enc: %d num_intf: %d\n", - reqs->topology.num_lm, reqs->topology.num_enc, + DRM_DEBUG_KMS("num_lm: %d num_dsc: %d num_intf: %d\n", + reqs->topology.num_lm, reqs->topology.num_dsc, reqs->topology.num_intf); return 0; @@ -660,6 +665,11 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm, blks_size, enc_id); break; } + if (!hw_blks[i]) { + DPU_ERROR("Allocated resource %d unavailable to assign to enc %d\n", + type, enc_id); + break; + } blks[num_blks++] = hw_blks[i]; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c index 088ec990a2f2..2a5a68366582 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c @@ -70,6 +70,8 @@ int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc, int rc = 0; dpu_wb_conn = devm_kzalloc(dev->dev, sizeof(*dpu_wb_conn), GFP_KERNEL); + if (!dpu_wb_conn) + return -ENOMEM; drm_connector_helper_add(&dpu_wb_conn->base.base, &dpu_wb_conn_helper_funcs); diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c index 4d49f3ba6a96..ddcdd5e87853 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c @@ -69,8 +69,7 @@ irqreturn_t mdp4_irq(struct msm_kms *kms) struct mdp_kms *mdp_kms = to_mdp_kms(kms); struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms); struct drm_device *dev = mdp4_kms->dev; - struct msm_drm_private *priv = dev->dev_private; - unsigned int id; + struct drm_crtc *crtc; uint32_t status, enable; enable = mdp4_read(mdp4_kms, REG_MDP4_INTR_ENABLE); @@ -81,9 +80,9 @@ irqreturn_t mdp4_irq(struct msm_kms *kms) mdp_dispatch_irqs(mdp_kms, status); - for (id = 0; id < priv->num_crtcs; id++) - if (status & mdp4_crtc_vblank(priv->crtcs[id])) - drm_handle_vblank(dev, id); + drm_for_each_crtc(crtc, dev) + if (status & mdp4_crtc_vblank(crtc)) + drm_crtc_handle_vblank(crtc); return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 964573d26d26..9a1a0769575d 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -387,7 +387,7 @@ static int mdp4_kms_init(struct drm_device *dev) struct msm_drm_private *priv = dev->dev_private; struct mdp4_kms *mdp4_kms; struct msm_kms *kms = NULL; - struct iommu_domain *iommu; + struct msm_mmu *mmu; struct msm_gem_address_space *aspace; int irq, ret; u32 major, minor; @@ -499,10 +499,15 @@ static int mdp4_kms_init(struct drm_device *dev) mdp4_disable(mdp4_kms); mdelay(16); - iommu = iommu_domain_alloc(pdev->dev.bus); - if (iommu) { - struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, iommu); - + mmu = msm_iommu_new(&pdev->dev, 0); + if (IS_ERR(mmu)) { + ret = PTR_ERR(mmu); + goto fail; + } else if (!mmu) { + DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys " + "contig buffers for scanout\n"); + aspace = NULL; + } else { aspace = msm_gem_address_space_create(mmu, "mdp4", 0x1000, 0x100000000 - 0x1000); @@ -514,10 +519,6 @@ static int mdp4_kms_init(struct drm_device *dev) } kms->aspace = aspace; - } else { - DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys " - "contig buffers for scanout\n"); - aspace = NULL; } ret = modeset_init(mdp4_kms); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index e86421c69bd1..86036dd4e1e8 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -1139,7 +1139,10 @@ static void mdp5_crtc_reset(struct drm_crtc *crtc) if (crtc->state) mdp5_crtc_destroy_state(crtc, crtc->state); - __drm_atomic_helper_crtc_reset(crtc, &mdp5_cstate->base); + if (mdp5_cstate) + __drm_atomic_helper_crtc_reset(crtc, &mdp5_cstate->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); } static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = { diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c index 9b4c8d92ff32..43443a435d59 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c @@ -82,8 +82,7 @@ irqreturn_t mdp5_irq(struct msm_kms *kms) struct mdp_kms *mdp_kms = to_mdp_kms(kms); struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); struct drm_device *dev = mdp5_kms->dev; - struct msm_drm_private *priv = dev->dev_private; - unsigned int id; + struct drm_crtc *crtc; uint32_t status, enable; enable = mdp5_read(mdp5_kms, REG_MDP5_INTR_EN); @@ -94,9 +93,9 @@ irqreturn_t mdp5_irq(struct msm_kms *kms) mdp_dispatch_irqs(mdp_kms, status); - for (id = 0; id < priv->num_crtcs; id++) - if (status & mdp5_crtc_vblank(priv->crtcs[id])) - drm_handle_vblank(dev, id); + drm_for_each_crtc(crtc, dev) + if (status & mdp5_crtc_vblank(crtc)) + drm_crtc_handle_vblank(crtc); return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index b0d21838a134..29ae5c9613f3 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -203,7 +203,7 @@ static int mdp5_set_split_display(struct msm_kms *kms, slave_encoder); } -static void mdp5_destroy(struct platform_device *pdev); +static void mdp5_destroy(struct mdp5_kms *mdp5_kms); static void mdp5_kms_destroy(struct msm_kms *kms) { @@ -223,7 +223,7 @@ static void mdp5_kms_destroy(struct msm_kms *kms) } mdp_kms_destroy(&mdp5_kms->base); - mdp5_destroy(mdp5_kms->pdev); + mdp5_destroy(mdp5_kms); } #ifdef CONFIG_DEBUG_FS @@ -559,6 +559,8 @@ static int mdp5_kms_init(struct drm_device *dev) int irq, i, ret; ret = mdp5_init(to_platform_device(dev->dev), dev); + if (ret) + return ret; /* priv->kms would have been populated by the MDP5 driver */ kms = priv->kms; @@ -632,9 +634,8 @@ fail: return ret; } -static void mdp5_destroy(struct platform_device *pdev) +static void mdp5_destroy(struct mdp5_kms *mdp5_kms) { - struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); int i; if (mdp5_kms->ctlm) @@ -648,7 +649,7 @@ static void mdp5_destroy(struct platform_device *pdev) kfree(mdp5_kms->intfs[i]); if (mdp5_kms->rpm_enabled) - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(&mdp5_kms->pdev->dev); drm_atomic_private_obj_fini(&mdp5_kms->glob_state); drm_modeset_lock_fini(&mdp5_kms->glob_state_lock); @@ -797,8 +798,6 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) goto fail; } - platform_set_drvdata(pdev, mdp5_kms); - spin_lock_init(&mdp5_kms->resource_lock); mdp5_kms->dev = dev; @@ -839,6 +838,9 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) */ clk_set_rate(mdp5_kms->core_clk, 200000000); + /* set uninit-ed kms */ + priv->kms = &mdp5_kms->base.base; + pm_runtime_enable(&pdev->dev); mdp5_kms->rpm_enabled = true; @@ -890,13 +892,10 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) if (ret) goto fail; - /* set uninit-ed kms */ - priv->kms = &mdp5_kms->base.base; - return 0; fail: if (mdp5_kms) - mdp5_destroy(pdev); + mdp5_destroy(mdp5_kms); return ret; } @@ -953,7 +952,8 @@ static int mdp5_dev_remove(struct platform_device *pdev) static __maybe_unused int mdp5_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); DBG(""); @@ -963,7 +963,8 @@ static __maybe_unused int mdp5_runtime_suspend(struct device *dev) static __maybe_unused int mdp5_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); DBG(""); diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c index e75b97127c0d..b73031cd48e4 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c @@ -129,6 +129,9 @@ void msm_disp_snapshot_destroy(struct drm_device *drm_dev) } priv = drm_dev->dev_private; + if (!priv->kms) + return; + kms = priv->kms; if (kms->dump_worker) diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index d030a93a08c3..cc3efed593aa 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -423,6 +423,10 @@ void dp_aux_isr(struct drm_dp_aux *dp_aux) isr = dp_catalog_aux_get_irq(aux->catalog); + /* no interrupts pending, return immediately */ + if (!isr) + return; + if (!aux->cmd_busy) return; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index a49f6dbbe888..bde1a7ce442f 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -122,61 +122,64 @@ struct dp_display_private { struct msm_dp_desc { phys_addr_t io_start; + unsigned int id; unsigned int connector_type; bool wide_bus_en; }; -struct msm_dp_config { - const struct msm_dp_desc *descs; - size_t num_descs; -}; - static const struct msm_dp_desc sc7180_dp_descs[] = { - [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, -}; - -static const struct msm_dp_config sc7180_dp_cfg = { - .descs = sc7180_dp_descs, - .num_descs = ARRAY_SIZE(sc7180_dp_descs), + { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + {} }; static const struct msm_dp_desc sc7280_dp_descs[] = { - [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, - [MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true }, -}; - -static const struct msm_dp_config sc7280_dp_cfg = { - .descs = sc7280_dp_descs, - .num_descs = ARRAY_SIZE(sc7280_dp_descs), + { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true }, + {} }; static const struct msm_dp_desc sc8180x_dp_descs[] = { - [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, - [MSM_DP_CONTROLLER_1] = { .io_start = 0x0ae98000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, - [MSM_DP_CONTROLLER_2] = { .io_start = 0x0ae9a000, .connector_type = DRM_MODE_CONNECTOR_eDP }, + { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP }, + {} }; -static const struct msm_dp_config sc8180x_dp_cfg = { - .descs = sc8180x_dp_descs, - .num_descs = ARRAY_SIZE(sc8180x_dp_descs), +static const struct msm_dp_desc sc8280xp_dp_descs[] = { + { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + { .io_start = 0x22090000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + { .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true }, + {} }; -static const struct msm_dp_desc sm8350_dp_descs[] = { - [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, +static const struct msm_dp_desc sc8280xp_edp_descs[] = { + { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true }, + { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true }, + { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true }, + { .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true }, + {} }; -static const struct msm_dp_config sm8350_dp_cfg = { - .descs = sm8350_dp_descs, - .num_descs = ARRAY_SIZE(sm8350_dp_descs), +static const struct msm_dp_desc sm8350_dp_descs[] = { + { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + {} }; static const struct of_device_id dp_dt_match[] = { - { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_cfg }, - { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_cfg }, - { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_cfg }, - { .compatible = "qcom,sc8180x-dp", .data = &sc8180x_dp_cfg }, - { .compatible = "qcom,sc8180x-edp", .data = &sc8180x_dp_cfg }, - { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_cfg }, + { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_descs }, + { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_descs }, + { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_descs }, + { .compatible = "qcom,sc8180x-dp", .data = &sc8180x_dp_descs }, + { .compatible = "qcom,sc8180x-edp", .data = &sc8180x_dp_descs }, + { .compatible = "qcom,sc8280xp-dp", .data = &sc8280xp_dp_descs }, + { .compatible = "qcom,sc8280xp-edp", .data = &sc8280xp_edp_descs }, + { .compatible = "qcom,sdm845-dp", .data = &sc7180_dp_descs }, + { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_descs }, {} }; @@ -390,6 +393,10 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) struct edid *edid; dp->panel->max_dp_lanes = dp->parser->max_dp_lanes; + dp->panel->max_dp_link_rate = dp->parser->max_dp_link_rate; + + drm_dbg_dp(dp->drm_dev, "max_lanes=%d max_link_rate=%d\n", + dp->panel->max_dp_lanes, dp->panel->max_dp_link_rate); rc = dp_panel_read_sink_caps(dp->panel, dp->dp_display.connector); if (rc) @@ -607,8 +614,10 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) } /* enable HDP irq_hpd/replug interrupt */ - dp_catalog_hpd_config_intr(dp->catalog, - DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true); + if (dp->dp_display.internal_hpd) + dp_catalog_hpd_config_intr(dp->catalog, + DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, + true); drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n", dp->dp_display.connector_type, state); @@ -648,8 +657,10 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) dp->dp_display.connector_type, state); /* disable irq_hpd/replug interrupts */ - dp_catalog_hpd_config_intr(dp->catalog, - DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, false); + if (dp->dp_display.internal_hpd) + dp_catalog_hpd_config_intr(dp->catalog, + DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, + false); /* unplugged, no more irq_hpd handle */ dp_del_event(dp, EV_IRQ_HPD_INT); @@ -675,7 +686,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) } /* disable HPD plug interrupts */ - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); + if (dp->dp_display.internal_hpd) + dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); /* * We don't need separate work for disconnect as @@ -693,7 +705,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) dp_display_handle_plugged_change(&dp->dp_display, false); /* enable HDP plug interrupt to prepare for next plugin */ - if (!dp->dp_display.is_edp) + if (dp->dp_display.internal_hpd) dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true); drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n", @@ -857,7 +869,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); - dp->panel->dp_mode.drm_mode = mode->drm_mode; + drm_mode_copy(&dp->panel->dp_mode.drm_mode, &mode->drm_mode); dp->panel->dp_mode.bpp = mode->bpp; dp->panel->dp_mode.capabilities = mode->capabilities; dp_panel_init_panel_info(dp->panel); @@ -1078,8 +1090,8 @@ static void dp_display_config_hpd(struct dp_display_private *dp) dp_display_host_init(dp); dp_catalog_ctrl_hpd_config(dp->catalog); - /* Enable plug and unplug interrupts only for external DisplayPort */ - if (!dp->dp_display.is_edp) + /* Enable plug and unplug interrupts only if requested */ + if (dp->dp_display.internal_hpd) dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | DP_DP_HPD_UNPLUG_INT_MASK, @@ -1262,10 +1274,9 @@ int dp_display_request_irq(struct msm_dp *dp_display) return 0; } -static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev, - unsigned int *id) +static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev) { - const struct msm_dp_config *cfg = of_device_get_match_data(&pdev->dev); + const struct msm_dp_desc *descs = of_device_get_match_data(&pdev->dev); struct resource *res; int i; @@ -1273,11 +1284,9 @@ static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pde if (!res) return NULL; - for (i = 0; i < cfg->num_descs; i++) { - if (cfg->descs[i].io_start == res->start) { - *id = i; - return &cfg->descs[i]; - } + for (i = 0; i < descs[i].io_start; i++) { + if (descs[i].io_start == res->start) + return &descs[i]; } dev_err(&pdev->dev, "unknown displayport instance\n"); @@ -1299,12 +1308,13 @@ static int dp_display_probe(struct platform_device *pdev) if (!dp) return -ENOMEM; - desc = dp_display_get_desc(pdev, &dp->id); + desc = dp_display_get_desc(pdev); if (!desc) return -EINVAL; dp->pdev = pdev; dp->name = "drm_dp"; + dp->id = desc->id; dp->dp_display.connector_type = desc->connector_type; dp->wide_bus_en = desc->wide_bus_en; dp->dp_display.is_edp = @@ -1373,8 +1383,7 @@ static int dp_pm_resume(struct device *dev) dp_catalog_ctrl_hpd_config(dp->catalog); - - if (!dp->dp_display.is_edp) + if (dp->dp_display.internal_hpd) dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | DP_DP_HPD_UNPLUG_INT_MASK, @@ -1497,7 +1506,7 @@ void msm_dp_irq_postinstall(struct msm_dp *dp_display) dp = container_of(dp_display, struct dp_display_private, dp_display); if (!dp_display->is_edp) - dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100); + dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0); } bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) @@ -1600,20 +1609,10 @@ error: int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, struct drm_encoder *encoder) { - struct msm_drm_private *priv; + struct msm_drm_private *priv = dev->dev_private; struct dp_display_private *dp_priv; int ret; - if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev)) - return -EINVAL; - - priv = dev->dev_private; - - if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) { - DRM_DEV_ERROR(dev->dev, "too many bridges\n"); - return -ENOSPC; - } - dp_display->drm_dev = dev; dp_priv = container_of(dp_display, struct dp_display_private, dp_display); @@ -1781,3 +1780,41 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge, dp_display->dp_mode.h_active_low = !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC); } + +void dp_bridge_hpd_enable(struct drm_bridge *bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + dp_display->internal_hpd = true; +} + +void dp_bridge_hpd_disable(struct drm_bridge *bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + dp_display->internal_hpd = false; +} + +void dp_bridge_hpd_notify(struct drm_bridge *bridge, + enum drm_connector_status status) +{ + struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display); + + /* Without next_bridge interrupts are handled by the DP core directly */ + if (dp_display->internal_hpd) + return; + + if (!dp->core_initialized) { + drm_dbg_dp(dp->drm_dev, "not initialized\n"); + return; + } + + if (!dp_display->is_connected && status == connector_status_connected) + dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); + else if (dp_display->is_connected && status == connector_status_disconnected) + dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); +} diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index dcedf021f7fe..371337d0fae2 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -21,6 +21,7 @@ struct msm_dp { bool power_on; unsigned int connector_type; bool is_edp; + bool internal_hpd; hdmi_codec_plugged_cb plugged_cb; diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 6db82f9b03af..275370f21115 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -102,6 +102,9 @@ static const struct drm_bridge_funcs dp_bridge_ops = { .get_modes = dp_bridge_get_modes, .detect = dp_bridge_detect, .atomic_check = dp_bridge_atomic_check, + .hpd_enable = dp_bridge_hpd_enable, + .hpd_disable = dp_bridge_hpd_disable, + .hpd_notify = dp_bridge_hpd_notify, }; struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h index 82035dbb0578..250f7c66201f 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.h +++ b/drivers/gpu/drm/msm/dp/dp_drm.h @@ -32,5 +32,9 @@ enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge, void dp_bridge_mode_set(struct drm_bridge *drm_bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode); +void dp_bridge_hpd_enable(struct drm_bridge *bridge); +void dp_bridge_hpd_disable(struct drm_bridge *bridge); +void dp_bridge_hpd_notify(struct drm_bridge *bridge, + enum drm_connector_status status); #endif /* _DP_DRM_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index 36bb6191d2f0..f1f1d646539d 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -49,23 +49,26 @@ static int dp_aux_link_power_up(struct drm_dp_aux *aux, struct dp_link_info *link) { u8 value; - int err; + ssize_t len; + int i; if (link->revision < 0x11) return 0; - err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); - if (err < 0) - return err; + len = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); + if (len < 0) + return len; value &= ~DP_SET_POWER_MASK; value |= DP_SET_POWER_D0; - err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); - if (err < 0) - return err; - - usleep_range(1000, 2000); + /* retry for 1ms to give the sink time to wake up */ + for (i = 0; i < 3; i++) { + len = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); + usleep_range(1000, 2000); + if (len == 1) + break; + } return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 5149cebc93f6..1800d8963f8a 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -75,12 +75,13 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) link_info->rate = drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]); link_info->num_lanes = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; + /* Limit data lanes from data-lanes of endpoint property of dtsi */ if (link_info->num_lanes > dp_panel->max_dp_lanes) link_info->num_lanes = dp_panel->max_dp_lanes; - /* Limit support upto HBR2 until HBR3 support is added */ - if (link_info->rate >= (drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4))) - link_info->rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4); + /* Limit link rate from link-frequencies of endpoint property of dtsi */ + if (link_info->rate > dp_panel->max_dp_link_rate) + link_info->rate = dp_panel->max_dp_link_rate; drm_dbg_dp(panel->drm_dev, "version: %d.%d\n", major, minor); drm_dbg_dp(panel->drm_dev, "link_rate=%d\n", link_info->rate); diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index d861197ac1c8..f04d0210b5cd 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -50,6 +50,7 @@ struct dp_panel { u32 vic; u32 max_dp_lanes; + u32 max_dp_link_rate; u32 max_bw_code; }; diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index dcbe893d66d7..7032dcc8842b 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -91,19 +91,53 @@ static int dp_parser_ctrl_res(struct dp_parser *parser) return 0; } +static u32 dp_parser_link_frequencies(struct device_node *of_node) +{ + struct device_node *endpoint; + u64 frequency = 0; + int cnt; + + endpoint = of_graph_get_endpoint_by_regs(of_node, 1, 0); /* port@1 */ + if (!endpoint) + return 0; + + cnt = of_property_count_u64_elems(endpoint, "link-frequencies"); + + if (cnt > 0) + of_property_read_u64_index(endpoint, "link-frequencies", + cnt - 1, &frequency); + of_node_put(endpoint); + + do_div(frequency, + 10 * /* from symbol rate to link rate */ + 1000); /* kbytes */ + + return frequency; +} + static int dp_parser_misc(struct dp_parser *parser) { struct device_node *of_node = parser->pdev->dev.of_node; - int len; - - len = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES); - if (len < 0) { - DRM_WARN("Invalid property \"data-lanes\", default max DP lanes = %d\n", - DP_MAX_NUM_DP_LANES); - len = DP_MAX_NUM_DP_LANES; + int cnt; + + /* + * data-lanes is the property of dp_out endpoint + */ + cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, DP_MAX_NUM_DP_LANES); + if (cnt < 0) { + /* legacy code, data-lanes is the property of mdss_dp node */ + cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES); } - parser->max_dp_lanes = len; + if (cnt > 0) + parser->max_dp_lanes = cnt; + else + parser->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ + + parser->max_dp_link_rate = dp_parser_link_frequencies(of_node); + if (!parser->max_dp_link_rate) + parser->max_dp_link_rate = DP_LINK_RATE_HBR2; + return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h index d30ab773db46..1f068626d445 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.h +++ b/drivers/gpu/drm/msm/dp/dp_parser.h @@ -15,6 +15,7 @@ #define DP_LABEL "MDSS DP DISPLAY" #define DP_MAX_PIXEL_CLK_KHZ 675000 #define DP_MAX_NUM_DP_LANES 4 +#define DP_LINK_RATE_HBR2 540000 /* kbytes */ enum dp_pm_type { DP_CORE_PM, @@ -119,6 +120,7 @@ struct dp_parser { struct dp_io io; struct dp_display_data disp_data; u32 max_dp_lanes; + u32 max_dp_link_rate; struct drm_bridge *next_bridge; int (*parse)(struct dp_parser *parser); diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 8a95c744972a..31fdee2052be 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -211,14 +211,9 @@ void __exit msm_dsi_unregister(void) int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, struct drm_encoder *encoder) { - struct msm_drm_private *priv; + struct msm_drm_private *priv = dev->dev_private; int ret; - if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev)) - return -EINVAL; - - priv = dev->dev_private; - if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) { DRM_DEV_ERROR(dev->dev, "too many bridges\n"); return -ENOSPC; diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 2a96b4fe7839..bd3763a5d723 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -118,6 +118,8 @@ int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host); int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host); void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host); void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host); +unsigned long dsi_byte_clk_get_rate(struct mipi_dsi_host *host, bool is_bonded_dsi, + const struct drm_display_mode *mode); int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size); int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size); void *dsi_tx_buf_get_6g(struct msm_dsi_host *msm_host); @@ -139,6 +141,7 @@ struct msm_dsi_phy_shared_timings { u32 clk_post; u32 clk_pre; bool clk_pre_inc_by_2; + bool byte_intf_clk_div_2; }; struct msm_dsi_phy_clk_request { diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 7e97c239ed48..6d21f0b33411 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -181,6 +181,20 @@ static const struct msm_dsi_config sdm845_dsi_cfg = { .num_dsi = 2, }; +static const struct regulator_bulk_data sm8550_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 16800 }, /* 1.2 V */ +}; + +static const struct msm_dsi_config sm8550_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .regulator_data = sm8550_dsi_regulators, + .num_regulators = ARRAY_SIZE(sm8550_dsi_regulators), + .bus_clk_names = dsi_sdm845_bus_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_sdm845_bus_clk_names), + .io_start = { 0xae94000, 0xae96000 }, + .num_dsi = 2, +}; + static const struct regulator_bulk_data sc7180_dsi_regulators[] = { { .supply = "vdda", .init_load_uA = 21800 }, /* 1.2 V */ }; @@ -209,8 +223,8 @@ static const struct msm_dsi_config sc7280_dsi_cfg = { .num_regulators = ARRAY_SIZE(sc7280_dsi_regulators), .bus_clk_names = dsi_sc7280_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_sc7280_bus_clk_names), - .io_start = { 0xae94000 }, - .num_dsi = 1, + .io_start = { 0xae94000, 0xae96000 }, + .num_dsi = 2, }; static const char * const dsi_qcm2290_bus_clk_names[] = { @@ -300,6 +314,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { &sc7180_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_5_0, &sc7280_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_6_0, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_7_0, + &sm8550_dsi_cfg, &msm_dsi_6g_v2_host_ops}, }; const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index 8f04e685a74e..44be4a88aa83 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -25,6 +25,8 @@ #define MSM_DSI_6G_VER_MINOR_V2_4_0 0x20040000 #define MSM_DSI_6G_VER_MINOR_V2_4_1 0x20040001 #define MSM_DSI_6G_VER_MINOR_V2_5_0 0x20050000 +#define MSM_DSI_6G_VER_MINOR_V2_6_0 0x20060000 +#define MSM_DSI_6G_VER_MINOR_V2_7_0 0x20070000 #define MSM_DSI_V2_VER_MINOR_8064 0x0 diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 7fbf391c024f..18fa30e1e858 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -21,6 +21,7 @@ #include <video/mipi_display.h> +#include <drm/display/drm_dsc_helper.h> #include <drm/drm_of.h> #include "dsi.h" @@ -33,7 +34,7 @@ #define DSI_RESET_TOGGLE_DELAY_MS 20 -static int dsi_populate_dsc_params(struct drm_dsc_config *dsc); +static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc_config *dsc); static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) { @@ -121,6 +122,7 @@ struct msm_dsi_host { struct clk *byte_intf_clk; unsigned long byte_clk_rate; + unsigned long byte_intf_clk_rate; unsigned long pixel_clk_rate; unsigned long esc_clk_rate; @@ -397,7 +399,6 @@ int msm_dsi_runtime_resume(struct device *dev) int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) { - unsigned long byte_intf_rate; int ret; DBG("Set clk rates: pclk=%d, byteclk=%lu", @@ -417,13 +418,7 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) } if (msm_host->byte_intf_clk) { - /* For CPHY, byte_intf_clk is same as byte_clk */ - if (msm_host->cphy_mode) - byte_intf_rate = msm_host->byte_clk_rate; - else - byte_intf_rate = msm_host->byte_clk_rate / 2; - - ret = clk_set_rate(msm_host->byte_intf_clk, byte_intf_rate); + ret = clk_set_rate(msm_host->byte_intf_clk, msm_host->byte_intf_clk_rate); if (ret) { pr_err("%s: Failed to set rate byte intf clk, %d\n", __func__, ret); @@ -569,9 +564,8 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) clk_disable_unprepare(msm_host->byte_clk); } -static unsigned long dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bonded_dsi) +static unsigned long dsi_get_pclk_rate(const struct drm_display_mode *mode, bool is_bonded_dsi) { - struct drm_display_mode *mode = msm_host->mode; unsigned long pclk_rate; pclk_rate = mode->clock * 1000; @@ -588,11 +582,13 @@ static unsigned long dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bo return pclk_rate; } -static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi) +unsigned long dsi_byte_clk_get_rate(struct mipi_dsi_host *host, bool is_bonded_dsi, + const struct drm_display_mode *mode) { + struct msm_dsi_host *msm_host = to_msm_dsi_host(host); u8 lanes = msm_host->lanes; u32 bpp = dsi_get_bpp(msm_host->format); - unsigned long pclk_rate = dsi_get_pclk_rate(msm_host, is_bonded_dsi); + unsigned long pclk_rate = dsi_get_pclk_rate(mode, is_bonded_dsi); u64 pclk_bpp = (u64)pclk_rate * bpp; if (lanes == 0) { @@ -606,8 +602,14 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi) else do_div(pclk_bpp, (8 * lanes)); - msm_host->pixel_clk_rate = pclk_rate; - msm_host->byte_clk_rate = pclk_bpp; + return pclk_bpp; +} + +static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi) +{ + msm_host->pixel_clk_rate = dsi_get_pclk_rate(msm_host->mode, is_bonded_dsi); + msm_host->byte_clk_rate = dsi_byte_clk_get_rate(&msm_host->base, is_bonded_dsi, + msm_host->mode); DBG("pclk=%lu, bclk=%lu", msm_host->pixel_clk_rate, msm_host->byte_clk_rate); @@ -635,7 +637,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi) dsi_calc_pclk(msm_host, is_bonded_dsi); - pclk_bpp = (u64)dsi_get_pclk_rate(msm_host, is_bonded_dsi) * bpp; + pclk_bpp = (u64)dsi_get_pclk_rate(msm_host->mode, is_bonded_dsi) * bpp; do_div(pclk_bpp, 8); msm_host->src_clk_rate = pclk_bpp; @@ -842,31 +844,25 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mode, u32 hdisplay) { struct drm_dsc_config *dsc = msm_host->dsc; - u32 reg, intf_width, reg_ctrl, reg_ctrl2; + u32 reg, reg_ctrl, reg_ctrl2; u32 slice_per_intf, total_bytes_per_intf; u32 pkt_per_line; - u32 bytes_in_slice; u32 eol_byte_num; /* first calculate dsc parameters and then program * compress mode registers */ - intf_width = hdisplay; - slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); + slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width); - /* If slice_per_pkt is greater than slice_per_intf + /* + * If slice_count is greater than slice_per_intf * then default to 1. This can happen during partial * update. */ - if (slice_per_intf > dsc->slice_count) + if (dsc->slice_count > slice_per_intf) dsc->slice_count = 1; - slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width); - bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bits_per_pixel, 8); - - dsc->slice_chunk_size = bytes_in_slice; - - total_bytes_per_intf = bytes_in_slice * slice_per_intf; + total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf; eol_byte_num = total_bytes_per_intf % 3; pkt_per_line = slice_per_intf / dsc->slice_count; @@ -892,7 +888,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod reg_ctrl |= reg; reg_ctrl2 &= ~DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH__MASK; - reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(bytes_in_slice); + reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(dsc->slice_chunk_size); dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl); dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2); @@ -915,6 +911,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) u32 va_end = va_start + mode->vdisplay; u32 hdisplay = mode->hdisplay; u32 wc; + int ret; DBG(""); @@ -950,7 +947,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) /* we do the calculations for dsc parameters here so that * panel can use these parameters */ - dsi_populate_dsc_params(dsc); + ret = dsi_populate_dsc_params(msm_host, dsc); + if (ret) + return; /* Divide the display by 3 but keep back/font porch and * pulse width same @@ -990,7 +989,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) if (!msm_host->dsc) wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1; else - wc = mode->hdisplay / 2 + 1; + wc = msm_host->dsc->slice_chunk_size * msm_host->dsc->slice_count + 1; dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL, DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) | @@ -1754,18 +1753,20 @@ static char bpg_offset[DSC_NUM_BUF_RANGES] = { 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 }; -static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) -{ - int mux_words_size; - int groups_per_line, groups_total; - int min_rate_buffer_size; - int hrd_delay; - int pre_num_extra_mux_bits, num_extra_mux_bits; - int slice_bits; - int target_bpp_x16; - int data; - int final_value, final_scale; +static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc_config *dsc) +{ int i; + u16 bpp = dsc->bits_per_pixel >> 4; + + if (dsc->bits_per_pixel & 0xf) { + DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support fractional bits_per_pixel\n"); + return -EINVAL; + } + + if (dsc->bits_per_component != 8) { + DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support bits_per_component != 8 yet\n"); + return -EOPNOTSUPP; + } dsc->rc_model_size = 8192; dsc->first_line_bpg_offset = 12; @@ -1783,16 +1784,21 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { dsc->rc_range_params[i].range_min_qp = min_qp[i]; dsc->rc_range_params[i].range_max_qp = max_qp[i]; - dsc->rc_range_params[i].range_bpg_offset = bpg_offset[i]; + /* + * Range BPG Offset contains two's-complement signed values that fill + * 8 bits, yet the registers and DCS PPS field are only 6 bits wide. + */ + dsc->rc_range_params[i].range_bpg_offset = bpg_offset[i] & DSC_RANGE_BPG_OFFSET_MASK; } - dsc->initial_offset = 6144; /* Not bpp 12 */ - if (dsc->bits_per_pixel != 8) + dsc->initial_offset = 6144; /* Not bpp 12 */ + if (bpp != 8) dsc->initial_offset = 2048; /* bpp = 12 */ - mux_words_size = 48; /* bpc == 8/10 */ - if (dsc->bits_per_component == 12) - mux_words_size = 64; + if (dsc->bits_per_component <= 10) + dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; + else + dsc->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC; dsc->initial_xmit_delay = 512; dsc->initial_scale_value = 32; @@ -1804,63 +1810,8 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) dsc->flatness_max_qp = 12; dsc->rc_quant_incr_limit0 = 11; dsc->rc_quant_incr_limit1 = 11; - dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; - - /* FIXME: need to call drm_dsc_compute_rc_parameters() so that rest of - * params are calculated - */ - groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); - dsc->slice_chunk_size = dsc->slice_width * dsc->bits_per_pixel / 8; - if ((dsc->slice_width * dsc->bits_per_pixel) % 8) - dsc->slice_chunk_size++; - - /* rbs-min */ - min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + - dsc->initial_xmit_delay * dsc->bits_per_pixel + - groups_per_line * dsc->first_line_bpg_offset; - hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, dsc->bits_per_pixel); - - dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; - - dsc->initial_scale_value = 8 * dsc->rc_model_size / - (dsc->rc_model_size - dsc->initial_offset); - - slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height; - - groups_total = groups_per_line * dsc->slice_height; - - data = dsc->first_line_bpg_offset * 2048; - - dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); - - pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * dsc->bits_per_component + 4) - 2); - - num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size - - ((slice_bits - pre_num_extra_mux_bits) % mux_words_size)); - - data = 2048 * (dsc->rc_model_size - dsc->initial_offset + num_extra_mux_bits); - dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); - - /* bpp * 16 + 0.5 */ - data = dsc->bits_per_pixel * 16; - data *= 2; - data++; - data /= 2; - target_bpp_x16 = data; - - data = (dsc->initial_xmit_delay * target_bpp_x16) / 16; - final_value = dsc->rc_model_size - data + num_extra_mux_bits; - dsc->final_offset = final_value; - - final_scale = 8 * dsc->rc_model_size / (dsc->rc_model_size - final_value); - - data = (final_scale - 9) * (dsc->nfl_bpg_offset + dsc->slice_bpg_offset); - dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; - - dsc->scale_decrement_interval = groups_per_line / (dsc->initial_scale_value - 8); - - return 0; + return drm_dsc_compute_rc_parameters(dsc); } static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) @@ -1934,8 +1885,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL); if (!msm_host) { - ret = -ENOMEM; - goto fail; + return -ENOMEM; } msm_host->pdev = pdev; @@ -1944,31 +1894,28 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) ret = dsi_host_parse_dt(msm_host); if (ret) { pr_err("%s: failed to parse dt\n", __func__); - goto fail; + return ret; } msm_host->ctrl_base = msm_ioremap_size(pdev, "dsi_ctrl", &msm_host->ctrl_size); if (IS_ERR(msm_host->ctrl_base)) { pr_err("%s: unable to map Dsi ctrl base\n", __func__); - ret = PTR_ERR(msm_host->ctrl_base); - goto fail; + return PTR_ERR(msm_host->ctrl_base); } pm_runtime_enable(&pdev->dev); msm_host->cfg_hnd = dsi_get_config(msm_host); if (!msm_host->cfg_hnd) { - ret = -EINVAL; pr_err("%s: get config failed\n", __func__); - goto fail; + return -EINVAL; } cfg = msm_host->cfg_hnd->cfg; msm_host->id = dsi_host_get_id(msm_host); if (msm_host->id < 0) { - ret = msm_host->id; pr_err("%s: unable to identify DSI host index\n", __func__); - goto fail; + return msm_host->id; } /* fixup base address by io offset */ @@ -1978,19 +1925,18 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) cfg->regulator_data, &msm_host->supplies); if (ret) - goto fail; + return ret; ret = dsi_clk_init(msm_host); if (ret) { pr_err("%s: unable to initialize dsi clks\n", __func__); - goto fail; + return ret; } msm_host->rx_buf = devm_kzalloc(&pdev->dev, SZ_4K, GFP_KERNEL); if (!msm_host->rx_buf) { - ret = -ENOMEM; pr_err("%s: alloc rx temp buf failed\n", __func__); - goto fail; + return -ENOMEM; } ret = devm_pm_opp_set_clkname(&pdev->dev, "byte"); @@ -2028,15 +1974,15 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) /* setup workqueue */ msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0); + if (!msm_host->workqueue) + return -ENOMEM; + INIT_WORK(&msm_host->err_work, dsi_err_worker); msm_dsi->id = msm_host->id; DBG("Dsi Host %d initialized", msm_host->id); return 0; - -fail: - return ret; } void msm_dsi_host_destroy(struct mipi_dsi_host *host) @@ -2442,6 +2388,10 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, goto unlock_ret; } + msm_host->byte_intf_clk_rate = msm_host->byte_clk_rate; + if (phy_shared_timings->byte_intf_clk_div_2) + msm_host->byte_intf_clk_rate /= 2; + msm_dsi_sfpb_config(msm_host, true); ret = regulator_bulk_enable(msm_host->cfg_hnd->cfg->num_regulators, diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 3a1417397283..1bbac72dad35 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -450,6 +450,26 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge, int id = dsi_mgr_bridge_get_id(bridge); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct mipi_dsi_host *host = msm_dsi->host; + struct platform_device *pdev = msm_dsi->pdev; + struct dev_pm_opp *opp; + unsigned long byte_clk_rate; + + byte_clk_rate = dsi_byte_clk_get_rate(host, IS_BONDED_DSI(), mode); + + opp = dev_pm_opp_find_freq_ceil(&pdev->dev, &byte_clk_rate); + if (!IS_ERR(opp)) { + dev_pm_opp_put(opp); + } else if (PTR_ERR(opp) == -ERANGE) { + /* + * An empty table is created by devm_pm_opp_set_clkname() even + * if there is none. Thus find_freq_ceil will still return + * -ERANGE in such case. + */ + if (dev_pm_opp_get_opp_count(&pdev->dev) != 0) + return MODE_CLOCK_RANGE; + } else { + return MODE_ERROR; + } return msm_dsi_host_check_dsc(host, mode); } diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 7fc0975cb869..bb09cbe8ff86 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -350,6 +350,8 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, timing->shared_timings.clk_pre_inc_by_2 = 0; } + timing->shared_timings.byte_intf_clk_div_2 = true; + timing->ta_go = 3; timing->ta_sure = 0; timing->ta_get = 4; @@ -454,6 +456,8 @@ int msm_dsi_dphy_timing_calc_v4(struct msm_dsi_dphy_timing *timing, tmax = 255; timing->shared_timings.clk_pre = DIV_ROUND_UP((tmax - tmin) * 125, 10000) + tmin; + timing->shared_timings.byte_intf_clk_div_2 = true; + DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d", timing->shared_timings.clk_pre, timing->shared_timings.clk_post, timing->clk_zero, timing->clk_trail, timing->clk_prepare, timing->hs_exit, @@ -549,6 +553,8 @@ static const struct of_device_id dsi_phy_dt_match[] = { #ifdef CONFIG_DRM_MSM_DSI_14NM_PHY { .compatible = "qcom,dsi-phy-14nm", .data = &dsi_phy_14nm_cfgs }, + { .compatible = "qcom,dsi-phy-14nm-2290", + .data = &dsi_phy_14nm_2290_cfgs }, { .compatible = "qcom,dsi-phy-14nm-660", .data = &dsi_phy_14nm_660_cfgs }, { .compatible = "qcom,dsi-phy-14nm-8953", @@ -567,6 +573,14 @@ static const struct of_device_id dsi_phy_dt_match[] = { .data = &dsi_phy_7nm_8150_cfgs }, { .compatible = "qcom,sc7280-dsi-phy-7nm", .data = &dsi_phy_7nm_7280_cfgs }, + { .compatible = "qcom,sm6375-dsi-phy-7nm", + .data = &dsi_phy_7nm_6375_cfgs }, + { .compatible = "qcom,sm8350-dsi-phy-5nm", + .data = &dsi_phy_5nm_8350_cfgs }, + { .compatible = "qcom,sm8450-dsi-phy-5nm", + .data = &dsi_phy_5nm_8450_cfgs }, + { .compatible = "qcom,sm8550-dsi-phy-4nm", + .data = &dsi_phy_4nm_8550_cfgs }, #endif {} }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 60a99c6525b2..7137a17ae523 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -50,12 +50,17 @@ extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_14nm_2290_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_7nm_6375_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8350_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8450_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs; struct msm_dsi_dphy_timing { u32 clk_zero; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c index 0f8f4ca46429..9f488adea7f5 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -1081,3 +1081,20 @@ const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs = { .io_start = { 0x1a94400, 0x1a96400 }, .num_dsi_phy = 2, }; + +const struct msm_dsi_phy_cfg dsi_phy_14nm_2290_cfgs = { + .has_phy_lane = true, + .regulator_data = dsi_phy_14nm_17mA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_14nm_17mA_regulators), + .ops = { + .enable = dsi_14nm_phy_enable, + .disable = dsi_14nm_phy_disable, + .pll_init = dsi_pll_14nm_init, + .save_pll_state = dsi_14nm_pll_save_state, + .restore_pll_state = dsi_14nm_pll_restore_state, + }, + .min_pll_rate = VCO_MIN_RATE, + .max_pll_rate = VCO_MAX_RATE, + .io_start = { 0x5e94400 }, + .num_dsi_phy = 1, +}; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c index 9e7fa7d88ead..3b1ed02f644d 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -39,8 +39,16 @@ #define VCO_REF_CLK_RATE 19200000 #define FRAC_BITS 18 +/* Hardware is pre V4.1 */ +#define DSI_PHY_7NM_QUIRK_PRE_V4_1 BIT(0) /* Hardware is V4.1 */ -#define DSI_PHY_7NM_QUIRK_V4_1 BIT(0) +#define DSI_PHY_7NM_QUIRK_V4_1 BIT(1) +/* Hardware is V4.2 */ +#define DSI_PHY_7NM_QUIRK_V4_2 BIT(2) +/* Hardware is V4.3 */ +#define DSI_PHY_7NM_QUIRK_V4_3 BIT(3) +/* Hardware is V5.2 */ +#define DSI_PHY_7NM_QUIRK_V5_2 BIT(4) struct dsi_pll_config { bool enable_ssc; @@ -116,16 +124,27 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config dec_multiple = div_u64(pll_freq * multiplier, divider); dec = div_u64_rem(dec_multiple, multiplier, &frac); - if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1)) + if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1) config->pll_clock_inverters = 0x28; - else if (pll_freq <= 1000000000ULL) - config->pll_clock_inverters = 0xa0; - else if (pll_freq <= 2500000000ULL) - config->pll_clock_inverters = 0x20; - else if (pll_freq <= 3020000000ULL) - config->pll_clock_inverters = 0x00; - else - config->pll_clock_inverters = 0x40; + else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) { + if (pll_freq <= 1300000000ULL) + config->pll_clock_inverters = 0xa0; + else if (pll_freq <= 2500000000ULL) + config->pll_clock_inverters = 0x20; + else if (pll_freq <= 4000000000ULL) + config->pll_clock_inverters = 0x00; + else + config->pll_clock_inverters = 0x40; + } else { + if (pll_freq <= 1000000000ULL) + config->pll_clock_inverters = 0xa0; + else if (pll_freq <= 2500000000ULL) + config->pll_clock_inverters = 0x20; + else if (pll_freq <= 3020000000ULL) + config->pll_clock_inverters = 0x00; + else + config->pll_clock_inverters = 0x40; + } config->decimal_div_start = dec; config->frac_div_start = frac; @@ -197,16 +216,32 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) void __iomem *base = pll->phy->pll_base; u8 analog_controls_five_1 = 0x01, vco_config_1 = 0x00; - if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) { + if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)) if (pll->vco_current_rate >= 3100000000ULL) analog_controls_five_1 = 0x03; + if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) { if (pll->vco_current_rate < 1520000000ULL) vco_config_1 = 0x08; else if (pll->vco_current_rate < 2990000000ULL) vco_config_1 = 0x01; } + if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_2) || + (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3)) { + if (pll->vco_current_rate < 1520000000ULL) + vco_config_1 = 0x08; + else if (pll->vco_current_rate >= 2990000000ULL) + vco_config_1 = 0x01; + } + + if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) { + if (pll->vco_current_rate < 1557000000ULL) + vco_config_1 = 0x08; + else + vco_config_1 = 0x01; + } + dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE_1, analog_controls_five_1); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_VCO_CONFIG_1, vco_config_1); @@ -231,9 +266,9 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x2f); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_IFILT, 0x2a); dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_IFILT, - pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1 ? 0x3f : 0x22); + !(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1) ? 0x3f : 0x22); - if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) { + if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)) { dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22); if (pll->slave) dsi_phy_write(pll->slave->phy->pll_base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22); @@ -788,7 +823,7 @@ static void dsi_phy_hw_v4_0_lane_settings(struct msm_dsi_phy *phy) const u8 *tx_dctrl = tx_dctrl_0; void __iomem *lane_base = phy->lane_base; - if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) + if (!(phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)) tx_dctrl = tx_dctrl_1; /* Strength ctrl settings */ @@ -844,6 +879,13 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, if (dsi_phy_hw_v4_0_is_pll_on(phy)) pr_warn("PLL turned on before configuring PHY\n"); + /* Request for REFGEN READY */ + if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) || + (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) { + dsi_phy_write(phy->base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10, 0x1); + udelay(500); + } + /* wait for REFGEN READY */ ret = readl_poll_timeout_atomic(base + REG_DSI_7nm_PHY_CMN_PHY_STATUS, status, (status & BIT(0)), @@ -858,23 +900,64 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, /* Alter PHY configurations if data rate less than 1.5GHZ*/ less_than_1500_mhz = (clk_req->bitclk_rate <= 1500000000); - if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) { + glbl_str_swi_cal_sel_ctrl = 0x00; + if (phy->cphy_mode) { + vreg_ctrl_0 = 0x51; + vreg_ctrl_1 = 0x55; + glbl_hstx_str_ctrl_0 = 0x00; + glbl_pemph_ctrl_0 = 0x11; + lane_ctrl0 = 0x17; + } else { vreg_ctrl_0 = less_than_1500_mhz ? 0x53 : 0x52; + vreg_ctrl_1 = 0x5c; + glbl_hstx_str_ctrl_0 = 0x88; + glbl_pemph_ctrl_0 = 0x00; + lane_ctrl0 = 0x1f; + } + + if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) { if (phy->cphy_mode) { + vreg_ctrl_0 = 0x45; + vreg_ctrl_1 = 0x45; + glbl_rescode_top_ctrl = 0x00; + glbl_rescode_bot_ctrl = 0x00; + } else { + vreg_ctrl_0 = 0x44; + vreg_ctrl_1 = 0x19; + glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3c : 0x03; + glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x3c; + } + } else if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3)) { + if (phy->cphy_mode) { + glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x01; + glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x3b; + } else { + glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x01; + glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x39; + } + } else if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_2) { + if (phy->cphy_mode) { + glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x01; + glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x3b; + } else { + glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3c : 0x00; + glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x39; + } + } else if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) { + if (phy->cphy_mode) { + glbl_hstx_str_ctrl_0 = 0x88; glbl_rescode_top_ctrl = 0x00; glbl_rescode_bot_ctrl = 0x3c; } else { glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x00; glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x39 : 0x3c; } - glbl_str_swi_cal_sel_ctrl = 0x00; - glbl_hstx_str_ctrl_0 = 0x88; } else { - vreg_ctrl_0 = less_than_1500_mhz ? 0x5B : 0x59; if (phy->cphy_mode) { glbl_str_swi_cal_sel_ctrl = 0x03; glbl_hstx_str_ctrl_0 = 0x66; } else { + vreg_ctrl_0 = less_than_1500_mhz ? 0x5B : 0x59; glbl_str_swi_cal_sel_ctrl = less_than_1500_mhz ? 0x03 : 0x00; glbl_hstx_str_ctrl_0 = less_than_1500_mhz ? 0x66 : 0x88; } @@ -882,17 +965,6 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, glbl_rescode_bot_ctrl = 0x3c; } - if (phy->cphy_mode) { - vreg_ctrl_0 = 0x51; - vreg_ctrl_1 = 0x55; - glbl_pemph_ctrl_0 = 0x11; - lane_ctrl0 = 0x17; - } else { - vreg_ctrl_1 = 0x5c; - glbl_pemph_ctrl_0 = 0x00; - lane_ctrl0 = 0x1f; - } - /* de-assert digital and pll power down */ data = BIT(6) | BIT(5); dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_CTRL_0, data); @@ -904,9 +976,8 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_RBUF_CTRL, 0x00); /* program CMN_CTRL_4 for minor_ver 2 chipsets*/ - data = dsi_phy_read(base + REG_DSI_7nm_PHY_CMN_REVISION_ID0); - data = data & (0xf0); - if (data == 0x20) + if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) || + (dsi_phy_read(base + REG_DSI_7nm_PHY_CMN_REVISION_ID0) & (0xf0)) == 0x20) dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_CTRL_4, 0x04); /* Configure PHY lane swap (TODO: we need to calculate this) */ @@ -1017,6 +1088,16 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy) pr_warn("Turning OFF PHY while PLL is on\n"); dsi_phy_hw_v4_0_config_lpcdrx(phy, false); + + /* Turn off REFGEN Vote */ + if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) || + (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) { + dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10, 0x0); + wmb(); + /* Delay to ensure HW removes vote before PHY shut down */ + udelay(2); + } + data = dsi_phy_read(base + REG_DSI_7nm_PHY_CMN_CTRL_0); /* disable all lanes */ @@ -1040,6 +1121,14 @@ static const struct regulator_bulk_data dsi_phy_7nm_37750uA_regulators[] = { { .supply = "vdds", .init_load_uA = 37550 }, }; +static const struct regulator_bulk_data dsi_phy_7nm_97800uA_regulators[] = { + { .supply = "vdds", .init_load_uA = 97800 }, +}; + +static const struct regulator_bulk_data dsi_phy_7nm_98400uA_regulators[] = { + { .supply = "vdds", .init_load_uA = 98400 }, +}; + const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs = { .has_phy_lane = true, .regulator_data = dsi_phy_7nm_36mA_regulators, @@ -1063,6 +1152,26 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs = { .quirks = DSI_PHY_7NM_QUIRK_V4_1, }; +const struct msm_dsi_phy_cfg dsi_phy_7nm_6375_cfgs = { + .has_phy_lane = true, + .ops = { + .enable = dsi_7nm_phy_enable, + .disable = dsi_7nm_phy_disable, + .pll_init = dsi_pll_7nm_init, + .save_pll_state = dsi_7nm_pll_save_state, + .restore_pll_state = dsi_7nm_pll_restore_state, + }, + .min_pll_rate = 600000000UL, +#ifdef CONFIG_64BIT + .max_pll_rate = 5000000000ULL, +#else + .max_pll_rate = ULONG_MAX, +#endif + .io_start = { 0x5e94400 }, + .num_dsi_phy = 1, + .quirks = DSI_PHY_7NM_QUIRK_V4_1, +}; + const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = { .has_phy_lane = true, .regulator_data = dsi_phy_7nm_36mA_regulators, @@ -1079,6 +1188,7 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = { .max_pll_rate = 3500000000UL, .io_start = { 0xae94400, 0xae96400 }, .num_dsi_phy = 2, + .quirks = DSI_PHY_7NM_QUIRK_PRE_V4_1, }; const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs = { @@ -1102,3 +1212,72 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs = { .num_dsi_phy = 1, .quirks = DSI_PHY_7NM_QUIRK_V4_1, }; + +const struct msm_dsi_phy_cfg dsi_phy_5nm_8350_cfgs = { + .has_phy_lane = true, + .regulator_data = dsi_phy_7nm_37750uA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_37750uA_regulators), + .ops = { + .enable = dsi_7nm_phy_enable, + .disable = dsi_7nm_phy_disable, + .pll_init = dsi_pll_7nm_init, + .save_pll_state = dsi_7nm_pll_save_state, + .restore_pll_state = dsi_7nm_pll_restore_state, + .set_continuous_clock = dsi_7nm_set_continuous_clock, + }, + .min_pll_rate = 600000000UL, +#ifdef CONFIG_64BIT + .max_pll_rate = 5000000000UL, +#else + .max_pll_rate = ULONG_MAX, +#endif + .io_start = { 0xae94400, 0xae96400 }, + .num_dsi_phy = 2, + .quirks = DSI_PHY_7NM_QUIRK_V4_2, +}; + +const struct msm_dsi_phy_cfg dsi_phy_5nm_8450_cfgs = { + .has_phy_lane = true, + .regulator_data = dsi_phy_7nm_97800uA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_97800uA_regulators), + .ops = { + .enable = dsi_7nm_phy_enable, + .disable = dsi_7nm_phy_disable, + .pll_init = dsi_pll_7nm_init, + .save_pll_state = dsi_7nm_pll_save_state, + .restore_pll_state = dsi_7nm_pll_restore_state, + .set_continuous_clock = dsi_7nm_set_continuous_clock, + }, + .min_pll_rate = 600000000UL, +#ifdef CONFIG_64BIT + .max_pll_rate = 5000000000UL, +#else + .max_pll_rate = ULONG_MAX, +#endif + .io_start = { 0xae94400, 0xae96400 }, + .num_dsi_phy = 2, + .quirks = DSI_PHY_7NM_QUIRK_V4_3, +}; + +const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs = { + .has_phy_lane = true, + .regulator_data = dsi_phy_7nm_98400uA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_98400uA_regulators), + .ops = { + .enable = dsi_7nm_phy_enable, + .disable = dsi_7nm_phy_disable, + .pll_init = dsi_pll_7nm_init, + .save_pll_state = dsi_7nm_pll_save_state, + .restore_pll_state = dsi_7nm_pll_restore_state, + .set_continuous_clock = dsi_7nm_set_continuous_clock, + }, + .min_pll_rate = 600000000UL, +#ifdef CONFIG_64BIT + .max_pll_rate = 5000000000UL, +#else + .max_pll_rate = ULONG_MAX, +#endif + .io_start = { 0xae95000, 0xae97000 }, + .num_dsi_phy = 2, + .quirks = DSI_PHY_7NM_QUIRK_V5_2, +}; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index f28fb21e3891..3132105a2a43 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -68,16 +68,17 @@ static void msm_hdmi_destroy(struct hdmi *hdmi) destroy_workqueue(hdmi->workq); msm_hdmi_hdcp_destroy(hdmi); + if (hdmi->i2c) + msm_hdmi_i2c_destroy(hdmi->i2c); +} + +static void msm_hdmi_put_phy(struct hdmi *hdmi) +{ if (hdmi->phy_dev) { put_device(hdmi->phy_dev); hdmi->phy = NULL; hdmi->phy_dev = NULL; } - - if (hdmi->i2c) - msm_hdmi_i2c_destroy(hdmi->i2c); - - platform_set_drvdata(hdmi->pdev, NULL); } static int msm_hdmi_get_phy(struct hdmi *hdmi) @@ -93,22 +94,18 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi) } phy_pdev = of_find_device_by_node(phy_node); - if (phy_pdev) - hdmi->phy = platform_get_drvdata(phy_pdev); - of_node_put(phy_node); - if (!phy_pdev) { - DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n"); - return -EPROBE_DEFER; - } + if (!phy_pdev) + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n"); + + hdmi->phy = platform_get_drvdata(phy_pdev); if (!hdmi->phy) { - DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n"); put_device(&phy_pdev->dev); - return -EPROBE_DEFER; + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n"); } - hdmi->phy_dev = get_device(&phy_pdev->dev); + hdmi->phy_dev = &phy_pdev->dev; return 0; } @@ -117,144 +114,16 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi) * we are to EPROBE_DEFER we want to do it here, rather than later * at modeset_init() time */ -static struct hdmi *msm_hdmi_init(struct platform_device *pdev) +static int msm_hdmi_init(struct hdmi *hdmi) { - struct hdmi_platform_config *config = pdev->dev.platform_data; - struct hdmi *hdmi = NULL; - struct resource *res; - int i, ret; - - hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) { - ret = -ENOMEM; - goto fail; - } - - hdmi->pdev = pdev; - hdmi->config = config; - spin_lock_init(&hdmi->reg_lock); - - ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge); - if (ret && ret != -ENODEV) - goto fail; - - hdmi->mmio = msm_ioremap(pdev, config->mmio_name); - if (IS_ERR(hdmi->mmio)) { - ret = PTR_ERR(hdmi->mmio); - goto fail; - } - - /* HDCP needs physical address of hdmi register */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - config->mmio_name); - if (!res) { - ret = -EINVAL; - goto fail; - } - hdmi->mmio_phy_addr = res->start; - - hdmi->qfprom_mmio = msm_ioremap(pdev, config->qfprom_mmio_name); - if (IS_ERR(hdmi->qfprom_mmio)) { - DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n"); - hdmi->qfprom_mmio = NULL; - } - - hdmi->hpd_regs = devm_kcalloc(&pdev->dev, - config->hpd_reg_cnt, - sizeof(hdmi->hpd_regs[0]), - GFP_KERNEL); - if (!hdmi->hpd_regs) { - ret = -ENOMEM; - goto fail; - } - for (i = 0; i < config->hpd_reg_cnt; i++) - hdmi->hpd_regs[i].supply = config->hpd_reg_names[i]; - - ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs); - if (ret) { - DRM_DEV_ERROR(&pdev->dev, "failed to get hpd regulator: %d\n", ret); - goto fail; - } - - hdmi->pwr_regs = devm_kcalloc(&pdev->dev, - config->pwr_reg_cnt, - sizeof(hdmi->pwr_regs[0]), - GFP_KERNEL); - if (!hdmi->pwr_regs) { - ret = -ENOMEM; - goto fail; - } - - for (i = 0; i < config->pwr_reg_cnt; i++) - hdmi->pwr_regs[i].supply = config->pwr_reg_names[i]; - - ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs); - if (ret) { - DRM_DEV_ERROR(&pdev->dev, "failed to get pwr regulator: %d\n", ret); - goto fail; - } - - hdmi->hpd_clks = devm_kcalloc(&pdev->dev, - config->hpd_clk_cnt, - sizeof(hdmi->hpd_clks[0]), - GFP_KERNEL); - if (!hdmi->hpd_clks) { - ret = -ENOMEM; - goto fail; - } - for (i = 0; i < config->hpd_clk_cnt; i++) { - struct clk *clk; - - clk = msm_clk_get(pdev, config->hpd_clk_names[i]); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - DRM_DEV_ERROR(&pdev->dev, "failed to get hpd clk: %s (%d)\n", - config->hpd_clk_names[i], ret); - goto fail; - } - - hdmi->hpd_clks[i] = clk; - } + struct platform_device *pdev = hdmi->pdev; + int ret; - hdmi->pwr_clks = devm_kcalloc(&pdev->dev, - config->pwr_clk_cnt, - sizeof(hdmi->pwr_clks[0]), - GFP_KERNEL); - if (!hdmi->pwr_clks) { + hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0); + if (!hdmi->workq) { ret = -ENOMEM; goto fail; } - for (i = 0; i < config->pwr_clk_cnt; i++) { - struct clk *clk; - - clk = msm_clk_get(pdev, config->pwr_clk_names[i]); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - DRM_DEV_ERROR(&pdev->dev, "failed to get pwr clk: %s (%d)\n", - config->pwr_clk_names[i], ret); - goto fail; - } - - hdmi->pwr_clks[i] = clk; - } - - hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); - /* This will catch e.g. -EPROBE_DEFER */ - if (IS_ERR(hdmi->hpd_gpiod)) { - ret = PTR_ERR(hdmi->hpd_gpiod); - DRM_DEV_ERROR(&pdev->dev, "failed to get hpd gpio: (%d)\n", ret); - goto fail; - } - - if (!hdmi->hpd_gpiod) - DBG("failed to get HPD gpio"); - - if (hdmi->hpd_gpiod) - gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD"); - - pm_runtime_enable(&pdev->dev); - - hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0); hdmi->i2c = msm_hdmi_i2c_init(hdmi); if (IS_ERR(hdmi->i2c)) { @@ -264,25 +133,18 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) goto fail; } - ret = msm_hdmi_get_phy(hdmi); - if (ret) { - DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n"); - goto fail; - } - hdmi->hdcp_ctrl = msm_hdmi_hdcp_init(hdmi); if (IS_ERR(hdmi->hdcp_ctrl)) { dev_warn(&pdev->dev, "failed to init hdcp: disabled\n"); hdmi->hdcp_ctrl = NULL; } - return hdmi; + return 0; fail: - if (hdmi) - msm_hdmi_destroy(hdmi); + msm_hdmi_destroy(hdmi); - return ERR_PTR(ret); + return ret; } /* Second part of initialization, the drm/kms level modeset_init, @@ -297,7 +159,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev, struct drm_encoder *encoder) { struct msm_drm_private *priv = dev->dev_private; - struct platform_device *pdev = hdmi->pdev; int ret; if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) { @@ -337,13 +198,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, drm_connector_attach_encoder(hdmi->connector, hdmi->encoder); - hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - if (!hdmi->irq) { - ret = -EINVAL; - DRM_DEV_ERROR(dev->dev, "failed to get irq\n"); - goto fail; - } - ret = devm_request_irq(dev->dev, hdmi->irq, msm_hdmi_irq, IRQF_TRIGGER_HIGH, "hdmi_isr", hdmi); @@ -353,8 +207,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, goto fail; } - drm_bridge_connector_enable_hpd(hdmi->connector); - ret = msm_hdmi_hpd_enable(hdmi->bridge); if (ret < 0) { DRM_DEV_ERROR(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret); @@ -363,8 +215,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, priv->bridges[priv->num_bridges++] = hdmi->bridge; - platform_set_drvdata(pdev, hdmi); - return 0; fail: @@ -392,7 +242,7 @@ fail: static const char *hpd_reg_names_8960[] = {"core-vdda"}; static const char *hpd_clk_names_8960[] = {"core", "master_iface", "slave_iface"}; -static struct hdmi_platform_config hdmi_tx_8960_config = { +static const struct hdmi_platform_config hdmi_tx_8960_config = { HDMI_CFG(hpd_reg, 8960), HDMI_CFG(hpd_clk, 8960), }; @@ -402,7 +252,7 @@ static const char *pwr_clk_names_8x74[] = {"extp", "alt_iface"}; static const char *hpd_clk_names_8x74[] = {"iface", "core", "mdp_core"}; static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0}; -static struct hdmi_platform_config hdmi_tx_8974_config = { +static const struct hdmi_platform_config hdmi_tx_8974_config = { HDMI_CFG(pwr_reg, 8x74), HDMI_CFG(pwr_clk, 8x74), HDMI_CFG(hpd_clk, 8x74), @@ -517,26 +367,12 @@ static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev) static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) { struct msm_drm_private *priv = dev_get_drvdata(master); - struct hdmi_platform_config *hdmi_cfg; - struct hdmi *hdmi; - struct device_node *of_node = dev->of_node; + struct hdmi *hdmi = dev_get_drvdata(dev); int err; - hdmi_cfg = (struct hdmi_platform_config *) - of_device_get_match_data(dev); - if (!hdmi_cfg) { - DRM_DEV_ERROR(dev, "unknown hdmi_cfg: %pOFn\n", of_node); - return -ENXIO; - } - - hdmi_cfg->mmio_name = "core_physical"; - hdmi_cfg->qfprom_mmio_name = "qfprom_physical"; - - dev->platform_data = hdmi_cfg; - - hdmi = msm_hdmi_init(to_platform_device(dev)); - if (IS_ERR(hdmi)) - return PTR_ERR(hdmi); + err = msm_hdmi_init(hdmi); + if (err) + return err; priv->hdmi = hdmi; err = msm_hdmi_register_audio_driver(hdmi, dev); @@ -569,12 +405,158 @@ static const struct component_ops msm_hdmi_ops = { static int msm_hdmi_dev_probe(struct platform_device *pdev) { - return component_add(&pdev->dev, &msm_hdmi_ops); + const struct hdmi_platform_config *config; + struct device *dev = &pdev->dev; + struct hdmi *hdmi; + struct resource *res; + int i, ret; + + config = of_device_get_match_data(dev); + if (!config) + return -EINVAL; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->pdev = pdev; + hdmi->config = config; + spin_lock_init(&hdmi->reg_lock); + + ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge); + if (ret && ret != -ENODEV) + return ret; + + hdmi->mmio = msm_ioremap(pdev, "core_physical"); + if (IS_ERR(hdmi->mmio)) + return PTR_ERR(hdmi->mmio); + + /* HDCP needs physical address of hdmi register */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "core_physical"); + if (!res) + return -EINVAL; + hdmi->mmio_phy_addr = res->start; + + hdmi->qfprom_mmio = msm_ioremap(pdev, "qfprom_physical"); + if (IS_ERR(hdmi->qfprom_mmio)) { + DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n"); + hdmi->qfprom_mmio = NULL; + } + + hdmi->irq = platform_get_irq(pdev, 0); + if (hdmi->irq < 0) + return hdmi->irq; + + hdmi->hpd_regs = devm_kcalloc(&pdev->dev, + config->hpd_reg_cnt, + sizeof(hdmi->hpd_regs[0]), + GFP_KERNEL); + if (!hdmi->hpd_regs) + return -ENOMEM; + + for (i = 0; i < config->hpd_reg_cnt; i++) + hdmi->hpd_regs[i].supply = config->hpd_reg_names[i]; + + ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs); + if (ret) + return dev_err_probe(dev, ret, "failed to get hpd regulators\n"); + + hdmi->pwr_regs = devm_kcalloc(&pdev->dev, + config->pwr_reg_cnt, + sizeof(hdmi->pwr_regs[0]), + GFP_KERNEL); + if (!hdmi->pwr_regs) + return -ENOMEM; + + for (i = 0; i < config->pwr_reg_cnt; i++) + hdmi->pwr_regs[i].supply = config->pwr_reg_names[i]; + + ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs); + if (ret) + return dev_err_probe(dev, ret, "failed to get pwr regulators\n"); + + hdmi->hpd_clks = devm_kcalloc(&pdev->dev, + config->hpd_clk_cnt, + sizeof(hdmi->hpd_clks[0]), + GFP_KERNEL); + if (!hdmi->hpd_clks) + return -ENOMEM; + + for (i = 0; i < config->hpd_clk_cnt; i++) { + struct clk *clk; + + clk = msm_clk_get(pdev, config->hpd_clk_names[i]); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get hpd clk: %s\n", + config->hpd_clk_names[i]); + + hdmi->hpd_clks[i] = clk; + } + + hdmi->pwr_clks = devm_kcalloc(&pdev->dev, + config->pwr_clk_cnt, + sizeof(hdmi->pwr_clks[0]), + GFP_KERNEL); + if (!hdmi->pwr_clks) + return -ENOMEM; + + for (i = 0; i < config->pwr_clk_cnt; i++) { + struct clk *clk; + + clk = msm_clk_get(pdev, config->pwr_clk_names[i]); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get pwr clk: %s\n", + config->pwr_clk_names[i]); + + hdmi->pwr_clks[i] = clk; + } + + hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); + /* This will catch e.g. -EPROBE_DEFER */ + if (IS_ERR(hdmi->hpd_gpiod)) + return dev_err_probe(dev, PTR_ERR(hdmi->hpd_gpiod), + "failed to get hpd gpio\n"); + + if (!hdmi->hpd_gpiod) + DBG("failed to get HPD gpio"); + + if (hdmi->hpd_gpiod) + gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD"); + + ret = msm_hdmi_get_phy(hdmi); + if (ret) { + DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n"); + return ret; + } + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + goto err_put_phy; + + platform_set_drvdata(pdev, hdmi); + + ret = component_add(&pdev->dev, &msm_hdmi_ops); + if (ret) + goto err_put_phy; + + return 0; + +err_put_phy: + msm_hdmi_put_phy(hdmi); + return ret; } static int msm_hdmi_dev_remove(struct platform_device *pdev) { + struct hdmi *hdmi = dev_get_drvdata(&pdev->dev); + component_del(&pdev->dev, &msm_hdmi_ops); + + msm_hdmi_put_phy(hdmi); + return 0; } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 04a74381aaf7..e8dbee50637f 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -86,9 +86,6 @@ struct hdmi { /* platform config data (ie. from DT, or pdata) */ struct hdmi_platform_config { - const char *mmio_name; - const char *qfprom_mmio_name; - /* regulators that need to be on for hpd: */ const char **hpd_reg_names; int hpd_reg_cnt; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c index be4b0b67e797..cb35a297afbd 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c @@ -406,14 +406,14 @@ static const struct clk_ops hdmi_pll_ops = { .set_rate = hdmi_pll_set_rate, }; -static const char * const hdmi_pll_parents[] = { - "pxo", +static const struct clk_parent_data hdmi_pll_parents[] = { + { .fw_name = "pxo", .name = "pxo_board" }, }; static struct clk_init_data pll_init = { .name = "hdmi_pll", .ops = &hdmi_pll_ops, - .parent_names = hdmi_pll_parents, + .parent_data = hdmi_pll_parents, .num_parents = ARRAY_SIZE(hdmi_pll_parents), .flags = CLK_IGNORE_UNUSED, }; @@ -422,8 +422,7 @@ int msm_hdmi_pll_8960_init(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct hdmi_pll_8960 *pll; - struct clk *clk; - int i; + int i, ret; /* sanity check: */ for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++) @@ -443,10 +442,16 @@ int msm_hdmi_pll_8960_init(struct platform_device *pdev) pll->pdev = pdev; pll->clk_hw.init = &pll_init; - clk = devm_clk_register(dev, &pll->clk_hw); - if (IS_ERR(clk)) { + ret = devm_clk_hw_register(dev, &pll->clk_hw); + if (ret < 0) { DRM_DEV_ERROR(dev, "failed to register pll clock\n"); - return -EINVAL; + return ret; + } + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw); + if (ret) { + DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret); + return ret; } return 0; diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 95f4374ae21c..d6ecff0ab618 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -305,6 +305,7 @@ void msm_debugfs_init(struct drm_minor *minor) { struct drm_device *dev = minor->dev; struct msm_drm_private *priv = dev->dev_private; + struct dentry *gpu_devfreq; drm_debugfs_create_files(msm_debugfs_list, ARRAY_SIZE(msm_debugfs_list), @@ -325,6 +326,17 @@ void msm_debugfs_init(struct drm_minor *minor) debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root, dev, &shrink_fops); + gpu_devfreq = debugfs_create_dir("devfreq", minor->debugfs_root); + + debugfs_create_bool("idle_clamp",0600, gpu_devfreq, + &priv->gpu_clamp_to_idle); + + debugfs_create_u32("upthreshold",0600, gpu_devfreq, + &priv->gpu_devfreq_config.upthreshold); + + debugfs_create_u32("downdifferential",0600, gpu_devfreq, + &priv->gpu_devfreq_config.downdifferential); + if (priv->kms && priv->kms->funcs->debugfs_init) priv->kms->funcs->debugfs_init(priv->kms, minor); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 105b5b48e828..aca48c868c14 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -45,9 +45,10 @@ * - 1.7.0 - Add MSM_PARAM_SUSPENDS to access suspend count * - 1.8.0 - Add MSM_BO_CACHED_COHERENT for supported GPUs (a6xx) * - 1.9.0 - Add MSM_SUBMIT_FENCE_SN_IN + * - 1.10.0 - Add MSM_SUBMIT_BO_NO_IMPLICIT */ #define MSM_VERSION_MAJOR 1 -#define MSM_VERSION_MINOR 9 +#define MSM_VERSION_MINOR 10 #define MSM_VERSION_PATCHLEVEL 0 static const struct drm_mode_config_funcs mode_config_funcs = { @@ -149,6 +150,9 @@ static void msm_irq_uninstall(struct drm_device *dev) struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; + if (!priv->kms) + return; + kms->funcs->irq_uninstall(kms); if (kms->irq_requested) free_irq(kms->irq, dev); @@ -266,8 +270,6 @@ static int msm_drm_uninit(struct device *dev) component_unbind_all(dev, ddev); ddev->dev_private = NULL; - drm_dev_put(ddev); - destroy_workqueue(priv->wq); return 0; @@ -277,7 +279,6 @@ static int msm_drm_uninit(struct device *dev) struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev) { - struct iommu_domain *domain; struct msm_gem_address_space *aspace; struct msm_mmu *mmu; struct device *mdp_dev = dev->dev; @@ -293,22 +294,21 @@ struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev) else iommu_dev = mdss_dev; - domain = iommu_domain_alloc(iommu_dev->bus); - if (!domain) { + mmu = msm_iommu_new(iommu_dev, 0); + if (IS_ERR(mmu)) + return ERR_CAST(mmu); + + if (!mmu) { drm_info(dev, "no IOMMU, fallback to phys contig buffers for scanout\n"); return NULL; } - mmu = msm_iommu_new(iommu_dev, domain); - if (IS_ERR(mmu)) { - iommu_domain_free(domain); - return ERR_CAST(mmu); - } - aspace = msm_gem_address_space_create(mmu, "mdp_kms", 0x1000, 0x100000000 - 0x1000); - if (IS_ERR(aspace)) + if (IS_ERR(aspace)) { + dev_err(mdp_dev, "aspace create, error %pe\n", aspace); mmu->funcs->destroy(mmu); + } return aspace; } @@ -420,7 +420,8 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) priv->dev = ddev; priv->wq = alloc_ordered_workqueue("msm", 0); - priv->hangcheck_period = DRM_MSM_HANGCHECK_DEFAULT_PERIOD; + if (!priv->wq) + return -ENOMEM; INIT_LIST_HEAD(&priv->objects); mutex_init(&priv->obj_lock); @@ -443,12 +444,12 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) ret = msm_init_vram(ddev); if (ret) - return ret; + goto err_drm_dev_put; /* Bind all our sub-components: */ ret = component_bind_all(dev, ddev); if (ret) - return ret; + goto err_drm_dev_put; dma_set_max_seg_size(dev, UINT_MAX); @@ -494,7 +495,7 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) if (IS_ERR(priv->event_thread[i].worker)) { ret = PTR_ERR(priv->event_thread[i].worker); DRM_DEV_ERROR(dev, "failed to create crtc_event kthread\n"); - ret = PTR_ERR(priv->event_thread[i].worker); + priv->event_thread[i].worker = NULL; goto err_msm_uninit; } @@ -543,6 +544,8 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) err_msm_uninit: msm_drm_uninit(dev); +err_drm_dev_put: + drm_dev_put(ddev); return ret; } @@ -819,6 +822,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, case MSM_INFO_GET_OFFSET: case MSM_INFO_GET_IOVA: case MSM_INFO_SET_IOVA: + case MSM_INFO_GET_FLAGS: /* value returned as immediate, not pointer, so len==0: */ if (args->len) return -EINVAL; @@ -846,6 +850,15 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, case MSM_INFO_SET_IOVA: ret = msm_ioctl_gem_info_set_iova(dev, file, obj, args->value); break; + case MSM_INFO_GET_FLAGS: + if (obj->import_attach) { + ret = -EINVAL; + break; + } + /* Hide internal kernel-only flags: */ + args->value = to_msm_bo(obj)->flags & MSM_BO_FLAGS; + ret = 0; + break; case MSM_INFO_SET_NAME: /* length check should leave room for terminating null: */ if (args->len >= sizeof(msm_obj->name)) { @@ -1271,7 +1284,7 @@ void msm_drv_shutdown(struct platform_device *pdev) * msm_drm_init, drm_dev->registered is used as an indicator that the * shutdown will be successful. */ - if (drm && drm->registered) + if (drm && drm->registered && priv->kms) drm_atomic_helper_shutdown(drm); } diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index b2ea262296a4..9f0c184b02a0 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/cpufreq.h> +#include <linux/devfreq.h> #include <linux/module.h> #include <linux/component.h> #include <linux/platform_device.h> @@ -61,6 +62,7 @@ enum msm_dp_controller { MSM_DP_CONTROLLER_0, MSM_DP_CONTROLLER_1, MSM_DP_CONTROLLER_2, + MSM_DP_CONTROLLER_3, MSM_DP_CONTROLLER_COUNT, }; @@ -82,14 +84,12 @@ enum msm_event_wait { /** * struct msm_display_topology - defines a display topology pipeline * @num_lm: number of layer mixers used - * @num_enc: number of compression encoder blocks used * @num_intf: number of interfaces the panel is mounted on * @num_dspp: number of dspp blocks used * @num_dsc: number of Display Stream Compression (DSC) blocks used */ struct msm_display_topology { u32 num_lm; - u32 num_enc; u32 num_intf; u32 num_dspp; u32 num_dsc; @@ -224,9 +224,23 @@ struct msm_drm_private { struct drm_atomic_state *pm_state; - /* For hang detection, in ms */ + /** + * hangcheck_period: For hang detection, in ms + * + * Note that in practice, a submit/job will get at least two hangcheck + * periods, due to checking for progress being implemented as simply + * "have the CP position registers changed since last time?" + */ unsigned int hangcheck_period; + /** gpu_devfreq_config: Devfreq tuning config for the GPU. */ + struct devfreq_simple_ondemand_data gpu_devfreq_config; + + /** + * gpu_clamp_to_idle: Enable clamping to idle freq when inactive + */ + bool gpu_clamp_to_idle; + /** * disable_err_irq: * diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 46168eccfac4..c1356aff87da 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -93,7 +93,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, goto fail; } - fbi = drm_fb_helper_alloc_fbi(helper); + fbi = drm_fb_helper_alloc_info(helper); if (IS_ERR(fbi)) { DRM_DEV_ERROR(dev->dev, "failed to allocate fb info\n"); ret = PTR_ERR(fbi); @@ -109,8 +109,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, drm_fb_helper_fill_info(fbi, helper, sizes); - dev->mode_config.fb_base = paddr; - fbi->screen_base = msm_gem_get_vaddr(bo); if (IS_ERR(fbi->screen_base)) { ret = PTR_ERR(fbi->screen_base); @@ -144,11 +142,11 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); if (!fbdev) - goto fail; + return NULL; helper = &fbdev->base; - drm_fb_helper_prepare(dev, helper, &msm_fb_helper_funcs); + drm_fb_helper_prepare(dev, helper, 32, &msm_fb_helper_funcs); ret = drm_fb_helper_init(dev, helper); if (ret) { @@ -161,7 +159,7 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) if (ret) goto fini; - ret = drm_fb_helper_initial_config(helper, 32); + ret = drm_fb_helper_initial_config(helper); if (ret) goto fini; @@ -172,6 +170,7 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) fini: drm_fb_helper_fini(helper); fail: + drm_fb_helper_unprepare(helper); kfree(fbdev); return NULL; } @@ -184,7 +183,7 @@ void msm_fbdev_free(struct drm_device *dev) DBG(); - drm_fb_helper_unregister_fbi(helper); + drm_fb_helper_unregister_info(helper); drm_fb_helper_fini(helper); @@ -198,6 +197,7 @@ void msm_fbdev_free(struct drm_device *dev) drm_framebuffer_remove(fbdev->fb); } + drm_fb_helper_unprepare(helper); kfree(fbdev); priv->fbdev = NULL; diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index a47e5837c528..56641408ea74 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -22,7 +22,7 @@ msm_fence_context_alloc(struct drm_device *dev, volatile uint32_t *fenceptr, return ERR_PTR(-ENOMEM); fctx->dev = dev; - strncpy(fctx->name, name, sizeof(fctx->name)); + strscpy(fctx->name, name, sizeof(fctx->name)); fctx->context = dma_fence_context_alloc(1); fctx->index = index++; fctx->fenceptr = fenceptr; diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 1de14e67f96b..051bdbc093cf 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -15,7 +15,7 @@ /* Default disabled for now until it has some more testing on the different * iommu combinations that can be paired with the driver: */ -static bool enable_eviction = false; +static bool enable_eviction = true; MODULE_PARM_DESC(enable_eviction, "Enable swappable GEM buffers"); module_param(enable_eviction, bool, 0600); diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 45a3e5cadc7d..be4bf77103cd 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -209,6 +209,10 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit, goto out; } submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL); + if (!submit->cmd[i].relocs) { + ret = -ENOMEM; + goto out; + } ret = copy_from_user(submit->cmd[i].relocs, userptr, sz); if (ret) { ret = -EFAULT; @@ -334,8 +338,18 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit) if (ret) return ret; - /* exclusive fences must be ordered */ - if (no_implicit && !write) + /* If userspace has determined that explicit fencing is + * used, it can disable implicit sync on the entire + * submit: + */ + if (no_implicit) + continue; + + /* Otherwise userspace can ask for implicit sync to be + * disabled on specific buffers. This is useful for internal + * usermode driver managed buffers, suballocation, etc. + */ + if (submit->bos[i].flags & MSM_SUBMIT_BO_NO_IMPLICIT) continue; ret = drm_sched_job_add_implicit_dependencies(&submit->base, diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 021f4e29b613..380249500325 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -335,6 +335,8 @@ static void get_comm_cmdline(struct msm_gem_submit *submit, char **comm, char ** struct msm_file_private *ctx = submit->queue->ctx; struct task_struct *task; + WARN_ON(!mutex_is_locked(&submit->gpu->lock)); + /* Note that kstrdup will return NULL if argument is NULL: */ *comm = kstrdup(ctx->comm, GFP_KERNEL); *cmd = kstrdup(ctx->cmdline, GFP_KERNEL); @@ -492,6 +494,21 @@ static void hangcheck_timer_reset(struct msm_gpu *gpu) round_jiffies_up(jiffies + msecs_to_jiffies(priv->hangcheck_period))); } +static bool made_progress(struct msm_gpu *gpu, struct msm_ringbuffer *ring) +{ + if (ring->hangcheck_progress_retries >= DRM_MSM_HANGCHECK_PROGRESS_RETRIES) + return false; + + if (!gpu->funcs->progress) + return false; + + if (!gpu->funcs->progress(gpu, ring)) + return false; + + ring->hangcheck_progress_retries++; + return true; +} + static void hangcheck_handler(struct timer_list *t) { struct msm_gpu *gpu = from_timer(gpu, t, hangcheck_timer); @@ -502,9 +519,12 @@ static void hangcheck_handler(struct timer_list *t) if (fence != ring->hangcheck_fence) { /* some progress has been made.. ya! */ ring->hangcheck_fence = fence; - } else if (fence_before(fence, ring->fctx->last_fence)) { + ring->hangcheck_progress_retries = 0; + } else if (fence_before(fence, ring->fctx->last_fence) && + !made_progress(gpu, ring)) { /* no progress and not done.. hung! */ ring->hangcheck_fence = fence; + ring->hangcheck_progress_retries = 0; DRM_DEV_ERROR(dev->dev, "%s: hangcheck detected gpu lockup rb %d!\n", gpu->name, ring->id); DRM_DEV_ERROR(dev->dev, "%s: completed fence: %u\n", @@ -830,6 +850,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, const char *name, struct msm_gpu_config *config) { + struct msm_drm_private *priv = drm->dev_private; int i, ret, nr_rings = config->nr_rings; void *memptrs; uint64_t memptrs_iova; @@ -857,6 +878,16 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, kthread_init_work(&gpu->recover_work, recover_worker); kthread_init_work(&gpu->fault_work, fault_worker); + priv->hangcheck_period = DRM_MSM_HANGCHECK_DEFAULT_PERIOD; + + /* + * If progress detection is supported, halve the hangcheck timer + * duration, as it takes two iterations of the hangcheck handler + * to detect a hang. + */ + if (funcs->progress) + priv->hangcheck_period /= 2; + timer_setup(&gpu->hangcheck_timer, hangcheck_handler, 0); spin_lock_init(&gpu->perf_lock); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 58a72e6b1400..fc1c0d8611a8 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -78,6 +78,15 @@ struct msm_gpu_funcs { struct msm_gem_address_space *(*create_private_address_space) (struct msm_gpu *gpu); uint32_t (*get_rptr)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); + + /** + * progress: Has the GPU made progress? + * + * Return true if GPU position in cmdstream has advanced (or changed) + * since the last call. To avoid false negatives, this should account + * for cmdstream that is buffered in this FIFO upstream of the CP fw. + */ + bool (*progress)(struct msm_gpu *gpu, struct msm_ringbuffer *ring); }; /* Additional state for iommu faults: */ @@ -100,11 +109,15 @@ struct msm_gpu_devfreq { struct mutex lock; /** - * idle_constraint: + * idle_freq: * - * A PM QoS constraint to limit max freq while the GPU is idle. + * Shadow frequency used while the GPU is idle. From the PoV of + * the devfreq governor, we are continuing to sample busyness and + * adjust frequency while the GPU is idle, but we use this shadow + * value as the GPU is actually clamped to minimum frequency while + * it is inactive. */ - struct dev_pm_qos_request idle_freq; + unsigned long idle_freq; /** * boost_constraint: @@ -126,8 +139,6 @@ struct msm_gpu_devfreq { /** idle_time: Time of last transition to idle: */ ktime_t idle_time; - struct devfreq_dev_status average_status; - /** * idle_work: * @@ -237,6 +248,7 @@ struct msm_gpu { #define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */ #define DRM_MSM_HANGCHECK_DEFAULT_PERIOD 500 /* in ms */ +#define DRM_MSM_HANGCHECK_PROGRESS_RETRIES 3 struct timer_list hangcheck_timer; /* Fault info for most recent iova fault: */ @@ -265,9 +277,6 @@ struct msm_gpu { struct msm_gpu_state *crashstate; - /* Enable clamping to idle freq when inactive: */ - bool clamp_to_idle; - /* True if the hardware supports expanded apriv (a650 and newer) */ bool hw_apriv; @@ -366,10 +375,18 @@ struct msm_file_private { */ int sysprof; - /** comm: Overridden task comm, see MSM_PARAM_COMM */ + /** + * comm: Overridden task comm, see MSM_PARAM_COMM + * + * Accessed under msm_gpu::lock + */ char *comm; - /** cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE */ + /** + * cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE + * + * Accessed under msm_gpu::lock + */ char *cmdline; /** @@ -540,7 +557,7 @@ static inline void gpu_rmw(struct msm_gpu *gpu, u32 reg, u32 mask, u32 or) msm_rmw(gpu->mmio + (reg << 2), mask, or); } -static inline u64 gpu_read64(struct msm_gpu *gpu, u32 lo, u32 hi) +static inline u64 gpu_read64(struct msm_gpu *gpu, u32 reg) { u64 val; @@ -558,17 +575,17 @@ static inline u64 gpu_read64(struct msm_gpu *gpu, u32 lo, u32 hi) * when the lo is read, so make sure to read the lo first to trigger * that */ - val = (u64) msm_readl(gpu->mmio + (lo << 2)); - val |= ((u64) msm_readl(gpu->mmio + (hi << 2)) << 32); + val = (u64) msm_readl(gpu->mmio + (reg << 2)); + val |= ((u64) msm_readl(gpu->mmio + ((reg + 1) << 2)) << 32); return val; } -static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val) +static inline void gpu_write64(struct msm_gpu *gpu, u32 reg, u64 val) { /* Why not a writeq here? Read the screed above */ - msm_writel(lower_32_bits(val), gpu->mmio + (lo << 2)); - msm_writel(upper_32_bits(val), gpu->mmio + (hi << 2)); + msm_writel(lower_32_bits(val), gpu->mmio + (reg << 2)); + msm_writel(upper_32_bits(val), gpu->mmio + ((reg + 1) << 2)); } int msm_gpu_pm_suspend(struct msm_gpu *gpu); diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index 85c443a37e4e..e27dbf12b5e8 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -33,6 +33,16 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq, trace_msm_gpu_freq_change(dev_pm_opp_get_freq(opp)); + /* + * If the GPU is idle, devfreq is not aware, so just stash + * the new target freq (to use when we return to active) + */ + if (df->idle_freq) { + df->idle_freq = *freq; + dev_pm_opp_put(opp); + return 0; + } + if (gpu->funcs->gpu_set_freq) { mutex_lock(&df->lock); gpu->funcs->gpu_set_freq(gpu, opp, df->suspended); @@ -48,15 +58,26 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq, static unsigned long get_freq(struct msm_gpu *gpu) { + struct msm_gpu_devfreq *df = &gpu->devfreq; + + /* + * If the GPU is idle, use the shadow/saved freq to avoid + * confusing devfreq (which is unaware that we are switching + * to lowest freq until the device is active again) + */ + if (df->idle_freq) + return df->idle_freq; + if (gpu->funcs->gpu_get_freq) return gpu->funcs->gpu_get_freq(gpu); return clk_get_rate(gpu->core_clk); } -static void get_raw_dev_status(struct msm_gpu *gpu, +static int msm_devfreq_get_dev_status(struct device *dev, struct devfreq_dev_status *status) { + struct msm_gpu *gpu = dev_to_gpu(dev); struct msm_gpu_devfreq *df = &gpu->devfreq; u64 busy_cycles, busy_time; unsigned long sample_rate; @@ -72,7 +93,7 @@ static void get_raw_dev_status(struct msm_gpu *gpu, if (df->suspended) { mutex_unlock(&df->lock); status->busy_time = 0; - return; + return 0; } busy_cycles = gpu->funcs->gpu_busy(gpu, &sample_rate); @@ -87,71 +108,6 @@ static void get_raw_dev_status(struct msm_gpu *gpu, busy_time = ~0LU; status->busy_time = busy_time; -} - -static void update_average_dev_status(struct msm_gpu *gpu, - const struct devfreq_dev_status *raw) -{ - struct msm_gpu_devfreq *df = &gpu->devfreq; - const u32 polling_ms = df->devfreq->profile->polling_ms; - const u32 max_history_ms = polling_ms * 11 / 10; - struct devfreq_dev_status *avg = &df->average_status; - u64 avg_freq; - - /* simple_ondemand governor interacts poorly with gpu->clamp_to_idle. - * When we enforce the constraint on idle, it calls get_dev_status - * which would normally reset the stats. When we remove the - * constraint on active, it calls get_dev_status again where busy_time - * would be 0. - * - * To remedy this, we always return the average load over the past - * polling_ms. - */ - - /* raw is longer than polling_ms or avg has no history */ - if (div_u64(raw->total_time, USEC_PER_MSEC) >= polling_ms || - !avg->total_time) { - *avg = *raw; - return; - } - - /* Truncate the oldest history first. - * - * Because we keep the history with a single devfreq_dev_status, - * rather than a list of devfreq_dev_status, we have to assume freq - * and load are the same over avg->total_time. We can scale down - * avg->busy_time and avg->total_time by the same factor to drop - * history. - */ - if (div_u64(avg->total_time + raw->total_time, USEC_PER_MSEC) >= - max_history_ms) { - const u32 new_total_time = polling_ms * USEC_PER_MSEC - - raw->total_time; - avg->busy_time = div_u64( - mul_u32_u32(avg->busy_time, new_total_time), - avg->total_time); - avg->total_time = new_total_time; - } - - /* compute the average freq over avg->total_time + raw->total_time */ - avg_freq = mul_u32_u32(avg->current_frequency, avg->total_time); - avg_freq += mul_u32_u32(raw->current_frequency, raw->total_time); - do_div(avg_freq, avg->total_time + raw->total_time); - - avg->current_frequency = avg_freq; - avg->busy_time += raw->busy_time; - avg->total_time += raw->total_time; -} - -static int msm_devfreq_get_dev_status(struct device *dev, - struct devfreq_dev_status *status) -{ - struct msm_gpu *gpu = dev_to_gpu(dev); - struct devfreq_dev_status raw; - - get_raw_dev_status(gpu, &raw); - update_average_dev_status(gpu, &raw); - *status = gpu->devfreq.average_status; return 0; } @@ -183,16 +139,23 @@ static bool has_devfreq(struct msm_gpu *gpu) void msm_devfreq_init(struct msm_gpu *gpu) { struct msm_gpu_devfreq *df = &gpu->devfreq; + struct msm_drm_private *priv = gpu->dev->dev_private; /* We need target support to do devfreq */ if (!gpu->funcs->gpu_busy) return; + /* + * Setup default values for simple_ondemand governor tuning. We + * want to throttle up at 50% load for the double-buffer case, + * where due to stalling waiting for vblank we could get stuck + * at (for ex) 30fps at 50% utilization. + */ + priv->gpu_devfreq_config.upthreshold = 50; + priv->gpu_devfreq_config.downdifferential = 10; + mutex_init(&df->lock); - dev_pm_qos_add_request(&gpu->pdev->dev, &df->idle_freq, - DEV_PM_QOS_MAX_FREQUENCY, - PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE); dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq, DEV_PM_QOS_MIN_FREQUENCY, 0); @@ -209,11 +172,10 @@ void msm_devfreq_init(struct msm_gpu *gpu) df->devfreq = devm_devfreq_add_device(&gpu->pdev->dev, &msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND, - NULL); + &priv->gpu_devfreq_config); if (IS_ERR(df->devfreq)) { DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n"); - dev_pm_qos_remove_request(&df->idle_freq); dev_pm_qos_remove_request(&df->boost_freq); df->devfreq = NULL; return; @@ -255,7 +217,6 @@ void msm_devfreq_cleanup(struct msm_gpu *gpu) devfreq_cooling_unregister(gpu->cooling); dev_pm_qos_remove_request(&df->boost_freq); - dev_pm_qos_remove_request(&df->idle_freq); } void msm_devfreq_resume(struct msm_gpu *gpu) @@ -328,6 +289,7 @@ void msm_devfreq_active(struct msm_gpu *gpu) { struct msm_gpu_devfreq *df = &gpu->devfreq; unsigned int idle_time; + unsigned long target_freq; if (!has_devfreq(gpu)) return; @@ -337,8 +299,28 @@ void msm_devfreq_active(struct msm_gpu *gpu) */ cancel_idle_work(df); + /* + * Hold devfreq lock to synchronize with get_dev_status()/ + * target() callbacks + */ + mutex_lock(&df->devfreq->lock); + + target_freq = df->idle_freq; + idle_time = ktime_to_ms(ktime_sub(ktime_get(), df->idle_time)); + df->idle_freq = 0; + + /* + * We could have become active again before the idle work had a + * chance to run, in which case the df->idle_freq would have + * still been zero. In this case, no need to change freq. + */ + if (target_freq) + msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0); + + mutex_unlock(&df->devfreq->lock); + /* * If we've been idle for a significant fraction of a polling * interval, then we won't meet the threshold of busyness for @@ -347,9 +329,6 @@ void msm_devfreq_active(struct msm_gpu *gpu) if (idle_time > msm_devfreq_profile.polling_ms) { msm_devfreq_boost(gpu, 2); } - - dev_pm_qos_update_request(&df->idle_freq, - PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE); } @@ -358,11 +337,24 @@ static void msm_devfreq_idle_work(struct kthread_work *work) struct msm_gpu_devfreq *df = container_of(work, struct msm_gpu_devfreq, idle_work.work); struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq); + struct msm_drm_private *priv = gpu->dev->dev_private; + unsigned long idle_freq, target_freq = 0; + + /* + * Hold devfreq lock to synchronize with get_dev_status()/ + * target() callbacks + */ + mutex_lock(&df->devfreq->lock); + + idle_freq = get_freq(gpu); + + if (priv->gpu_clamp_to_idle) + msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0); df->idle_time = ktime_get(); + df->idle_freq = idle_freq; - if (gpu->clamp_to_idle) - dev_pm_qos_update_request(&df->idle_freq, 0); + mutex_unlock(&df->devfreq->lock); } void msm_devfreq_idle(struct msm_gpu *gpu) diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 5577cea7c009..c2507582ecf3 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -186,6 +186,13 @@ int msm_iommu_pagetable_params(struct msm_mmu *mmu, return 0; } +struct iommu_domain_geometry *msm_iommu_get_geometry(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + + return &iommu->domain->geometry; +} + static const struct msm_mmu_funcs pagetable_funcs = { .map = msm_iommu_pagetable_map, .unmap = msm_iommu_pagetable_unmap, @@ -367,17 +374,23 @@ static const struct msm_mmu_funcs funcs = { .resume_translation = msm_iommu_resume_translation, }; -struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) +struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks) { + struct iommu_domain *domain; struct msm_iommu *iommu; int ret; + domain = iommu_domain_alloc(dev->bus); if (!domain) - return ERR_PTR(-ENODEV); + return NULL; + + iommu_set_pgtable_quirks(domain, quirks); iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); - if (!iommu) + if (!iommu) { + iommu_domain_free(domain); return ERR_PTR(-ENOMEM); + } iommu->domain = domain; msm_mmu_init(&iommu->base, dev, &funcs, MSM_MMU_IOMMU); @@ -386,6 +399,7 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) ret = iommu_attach_device(iommu->domain, dev); if (ret) { + iommu_domain_free(domain); kfree(iommu); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index e13c5c12b775..02646e4bb4cd 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -22,6 +22,7 @@ #define HW_REV 0x0 #define HW_INTR_STATUS 0x0010 +#define UBWC_DEC_HW_VERSION 0x58 #define UBWC_STATIC 0x144 #define UBWC_CTRL_2 0x150 #define UBWC_PREDICTION_MODE 0x154 @@ -46,15 +47,17 @@ struct msm_mdss { static int msm_mdss_parse_data_bus_icc_path(struct device *dev, struct msm_mdss *msm_mdss) { - struct icc_path *path0 = of_icc_get(dev, "mdp0-mem"); - struct icc_path *path1 = of_icc_get(dev, "mdp1-mem"); + struct icc_path *path0; + struct icc_path *path1; + path0 = of_icc_get(dev, "mdp0-mem"); if (IS_ERR_OR_NULL(path0)) return PTR_ERR_OR_ZERO(path0); msm_mdss->path[0] = path0; msm_mdss->num_paths = 1; + path1 = of_icc_get(dev, "mdp1-mem"); if (!IS_ERR_OR_NULL(path1)) { msm_mdss->path[1] = path1; msm_mdss->num_paths++; @@ -174,9 +177,63 @@ static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss) return 0; } +#define UBWC_1_0 0x10000000 +#define UBWC_2_0 0x20000000 +#define UBWC_3_0 0x30000000 +#define UBWC_4_0 0x40000000 + +static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss, + u32 ubwc_static) +{ + writel_relaxed(ubwc_static, msm_mdss->mmio + UBWC_STATIC); +} + +static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss, + unsigned int ubwc_version, + u32 ubwc_swizzle, + u32 highest_bank_bit, + u32 macrotile_mode) +{ + u32 value = (ubwc_swizzle & 0x1) | + (highest_bank_bit & 0x3) << 4 | + (macrotile_mode & 0x1) << 12; + + if (ubwc_version == UBWC_3_0) + value |= BIT(10); + + if (ubwc_version == UBWC_1_0) + value |= BIT(8); + + writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); +} + +static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss, + unsigned int ubwc_version, + u32 ubwc_swizzle, + u32 ubwc_static, + u32 highest_bank_bit, + u32 macrotile_mode) +{ + u32 value = (ubwc_swizzle & 0x7) | + (ubwc_static & 0x1) << 3 | + (highest_bank_bit & 0x7) << 4 | + (macrotile_mode & 0x1) << 12; + + writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); + + if (ubwc_version == UBWC_3_0) { + writel_relaxed(1, msm_mdss->mmio + UBWC_CTRL_2); + writel_relaxed(0, msm_mdss->mmio + UBWC_PREDICTION_MODE); + } else { + writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2); + writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE); + } +} + static int msm_mdss_enable(struct msm_mdss *msm_mdss) { int ret; + u32 hw_rev; /* * Several components have AXI clocks that can only be turned on if @@ -198,26 +255,51 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss) if (msm_mdss->is_mdp5) return 0; + hw_rev = readl_relaxed(msm_mdss->mmio + HW_REV); + dev_dbg(msm_mdss->dev, "HW_REV: 0x%x\n", hw_rev); + dev_dbg(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n", + readl_relaxed(msm_mdss->mmio + UBWC_DEC_HW_VERSION)); + /* * ubwc config is part of the "mdss" region which is not accessible * from the rest of the driver. hardcode known configurations here + * + * Decoder version can be read from the UBWC_DEC_HW_VERSION reg, + * UBWC_n and the rest of params comes from hw_catalog. + * Unforunately this driver can not access hw catalog, so we have to + * hardcode them here. */ - switch (readl_relaxed(msm_mdss->mmio + HW_REV)) { + switch (hw_rev) { case DPU_HW_VER_500: case DPU_HW_VER_501: - writel_relaxed(0x420, msm_mdss->mmio + UBWC_STATIC); + msm_mdss_setup_ubwc_dec_30(msm_mdss, UBWC_3_0, 0, 2, 0); break; case DPU_HW_VER_600: - /* TODO: 0x102e for LP_DDR4 */ - writel_relaxed(0x103e, msm_mdss->mmio + UBWC_STATIC); - writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2); - writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE); + /* TODO: highest_bank_bit = 2 for LP_DDR4 */ + msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 3, 1); break; case DPU_HW_VER_620: - writel_relaxed(0x1e, msm_mdss->mmio + UBWC_STATIC); + /* UBWC_2_0 */ + msm_mdss_setup_ubwc_dec_20(msm_mdss, 0x1e); + break; + case DPU_HW_VER_630: + /* UBWC_2_0 */ + msm_mdss_setup_ubwc_dec_20(msm_mdss, 0x11f); + break; + case DPU_HW_VER_700: + /* TODO: highest_bank_bit = 2 for LP_DDR4 */ + msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 3, 1); break; case DPU_HW_VER_720: - writel_relaxed(0x101e, msm_mdss->mmio + UBWC_STATIC); + msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_3_0, 6, 1, 1, 1); + break; + case DPU_HW_VER_800: + msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 2, 1); + break; + case DPU_HW_VER_810: + case DPU_HW_VER_900: + /* TODO: highest_bank_bit = 2 for LP_DDR4 */ + msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 3, 1); break; } @@ -445,8 +527,13 @@ static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,sc7180-mdss" }, { .compatible = "qcom,sc7280-mdss" }, { .compatible = "qcom,sc8180x-mdss" }, + { .compatible = "qcom,sc8280xp-mdss" }, + { .compatible = "qcom,sm6115-mdss" }, { .compatible = "qcom,sm8150-mdss" }, { .compatible = "qcom,sm8250-mdss" }, + { .compatible = "qcom,sm8350-mdss" }, + { .compatible = "qcom,sm8450-mdss" }, + { .compatible = "qcom,sm8550-mdss" }, {} }; MODULE_DEVICE_TABLE(of, mdss_dt_match); diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index de158e1bf765..74cd81e701ff 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -40,7 +40,7 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, mmu->type = type; } -struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain); +struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks); struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu); static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg, @@ -58,5 +58,6 @@ void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base, int msm_iommu_pagetable_params(struct msm_mmu *mmu, phys_addr_t *ttbr, int *asid); +struct iommu_domain_geometry *msm_iommu_get_geometry(struct msm_mmu *mmu); #endif /* __MSM_MMU_H__ */ diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h index 2a5045abe46e..698b333abccd 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.h +++ b/drivers/gpu/drm/msm/msm_ringbuffer.h @@ -35,6 +35,11 @@ struct msm_rbmemptrs { volatile u64 ttbr0; }; +struct msm_cp_state { + uint64_t ib1_base, ib2_base; + uint32_t ib1_rem, ib2_rem; +}; + struct msm_ringbuffer { struct msm_gpu *gpu; int id; @@ -64,6 +69,29 @@ struct msm_ringbuffer { uint64_t memptrs_iova; struct msm_fence_context *fctx; + /** + * hangcheck_progress_retries: + * + * The number of extra hangcheck duration cycles that we have given + * due to it appearing that the GPU is making forward progress. + * + * For GPU generations which support progress detection (see. + * msm_gpu_funcs::progress()), if the GPU appears to be making progress + * (ie. the CP has advanced in the command stream, we'll allow up to + * DRM_MSM_HANGCHECK_PROGRESS_RETRIES expirations of the hangcheck timer + * before killing the job. But to detect progress we need two sample + * points, so the duration of the hangcheck timer is halved. In other + * words we'll let the submit run for up to: + * + * (DRM_MSM_HANGCHECK_DEFAULT_PERIOD / 2) * (DRM_MSM_HANGCHECK_PROGRESS_RETRIES + 1) + */ + int hangcheck_progress_retries; + + /** + * last_cp_state: The state of the CP at the last call to gpu->progress() + */ + struct msm_cp_state last_cp_state; + /* * preempt_lock protects preemption and serializes wptr updates against * preemption. Can be aquired from irq context. |