diff options
Diffstat (limited to 'drivers/gpu/drm/msm')
115 files changed, 2576 insertions, 1285 deletions
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 9c37e4de5896..6deaa7d01654 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -7,6 +7,7 @@ config DRM_MSM depends on OF && COMMON_CLK depends on MMU depends on INTERCONNECT || !INTERCONNECT + depends on QCOM_OCMEM || QCOM_OCMEM=n select QCOM_MDT_LOADER if ARCH_QCOM select REGULATOR select DRM_KMS_HELPER @@ -14,11 +15,11 @@ config DRM_MSM select SHMEM select TMPFS select QCOM_SCM if ARCH_QCOM + select QCOM_COMMAND_DB if ARCH_QCOM select WANT_DEV_COREDUMP select SND_SOC_HDMI_CODEC if SND_SOC select SYNC_FILE select PM_OPP - default y help DRM/KMS driver for MSM/snapdragon. diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 7a05cbf2f820..1579cf0d828f 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -75,6 +75,7 @@ msm-y := \ disp/dpu1/dpu_rm.o \ disp/dpu1/dpu_vbif.o \ msm_atomic.o \ + msm_atomic_tracepoints.o \ msm_debugfs.o \ msm_drv.o \ msm_fb.o \ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 5f7e98028eaf..b67f88872726 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -6,10 +6,6 @@ * Copyright (c) 2014 The Linux Foundation. All rights reserved. */ -#ifdef CONFIG_MSM_OCMEM -# include <mach/ocmem.h> -#endif - #include "a3xx_gpu.h" #define A3XX_INT0_MASK \ @@ -195,9 +191,9 @@ static int a3xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000); /* Set the OCMEM base address for A330, etc */ - if (a3xx_gpu->ocmem_hdl) { + if (a3xx_gpu->ocmem.hdl) { gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR, - (unsigned int)(a3xx_gpu->ocmem_base >> 14)); + (unsigned int)(a3xx_gpu->ocmem.base >> 14)); } /* Turn on performance counters: */ @@ -318,10 +314,7 @@ static void a3xx_destroy(struct msm_gpu *gpu) adreno_gpu_cleanup(adreno_gpu); -#ifdef CONFIG_MSM_OCMEM - if (a3xx_gpu->ocmem_base) - ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); -#endif + adreno_gpu_ocmem_cleanup(&a3xx_gpu->ocmem); kfree(a3xx_gpu); } @@ -494,17 +487,10 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) /* if needed, allocate gmem: */ if (adreno_is_a330(adreno_gpu)) { -#ifdef CONFIG_MSM_OCMEM - /* TODO this is different/missing upstream: */ - struct ocmem_buf *ocmem_hdl = - ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem); - - a3xx_gpu->ocmem_hdl = ocmem_hdl; - a3xx_gpu->ocmem_base = ocmem_hdl->addr; - adreno_gpu->gmem = ocmem_hdl->len; - DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024, - a3xx_gpu->ocmem_base); -#endif + ret = adreno_gpu_ocmem_init(&adreno_gpu->base.pdev->dev, + adreno_gpu, &a3xx_gpu->ocmem); + if (ret) + goto fail; } if (!gpu->aspace) { @@ -520,6 +506,14 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) goto fail; } + /* + * Set the ICC path to maximum speed for now by multiplying the fastest + * frequency by the bus width (8). We'll want to scale this later on to + * improve battery life. + */ + icc_set_bw(gpu->icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8); + icc_set_bw(gpu->ocmem_icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8); + return gpu; fail: diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h index 5dc33e5ea53b..c555fb13e0d7 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h @@ -19,8 +19,7 @@ struct a3xx_gpu { struct adreno_gpu base; /* if OCMEM is used for GMEM: */ - uint32_t ocmem_base; - void *ocmem_hdl; + struct adreno_ocmem ocmem; }; #define to_a3xx_gpu(x) container_of(x, struct a3xx_gpu, base) diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index ab2b752566d8..253d8d85daad 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -2,9 +2,6 @@ /* Copyright (c) 2014 The Linux Foundation. All rights reserved. */ #include "a4xx_gpu.h" -#ifdef CONFIG_MSM_OCMEM -# include <soc/qcom/ocmem.h> -#endif #define A4XX_INT0_MASK \ (A4XX_INT0_RBBM_AHB_ERROR | \ @@ -188,7 +185,7 @@ static int a4xx_hw_init(struct msm_gpu *gpu) (1 << 30) | 0xFFFF); gpu_write(gpu, REG_A4XX_RB_GMEM_BASE_ADDR, - (unsigned int)(a4xx_gpu->ocmem_base >> 14)); + (unsigned int)(a4xx_gpu->ocmem.base >> 14)); /* Turn on performance counters: */ gpu_write(gpu, REG_A4XX_RBBM_PERFCTR_CTL, 0x01); @@ -318,10 +315,7 @@ static void a4xx_destroy(struct msm_gpu *gpu) adreno_gpu_cleanup(adreno_gpu); -#ifdef CONFIG_MSM_OCMEM - if (a4xx_gpu->ocmem_base) - ocmem_free(OCMEM_GRAPHICS, a4xx_gpu->ocmem_hdl); -#endif + adreno_gpu_ocmem_cleanup(&a4xx_gpu->ocmem); kfree(a4xx_gpu); } @@ -578,17 +572,10 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev) /* if needed, allocate gmem: */ if (adreno_is_a4xx(adreno_gpu)) { -#ifdef CONFIG_MSM_OCMEM - /* TODO this is different/missing upstream: */ - struct ocmem_buf *ocmem_hdl = - ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem); - - a4xx_gpu->ocmem_hdl = ocmem_hdl; - a4xx_gpu->ocmem_base = ocmem_hdl->addr; - adreno_gpu->gmem = ocmem_hdl->len; - DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024, - a4xx_gpu->ocmem_base); -#endif + ret = adreno_gpu_ocmem_init(dev->dev, adreno_gpu, + &a4xx_gpu->ocmem); + if (ret) + goto fail; } if (!gpu->aspace) { @@ -604,6 +591,14 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev) goto fail; } + /* + * Set the ICC path to maximum speed for now by multiplying the fastest + * frequency by the bus width (8). We'll want to scale this later on to + * improve battery life. + */ + icc_set_bw(gpu->icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8); + icc_set_bw(gpu->ocmem_icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8); + return gpu; fail: diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.h b/drivers/gpu/drm/msm/adreno/a4xx_gpu.h index d506311ee240..a01448cba2ea 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.h @@ -16,8 +16,7 @@ struct a4xx_gpu { struct adreno_gpu base; /* if OCMEM is used for GMEM: */ - uint32_t ocmem_base; - void *ocmem_hdl; + struct adreno_ocmem ocmem; }; #define to_a4xx_gpu(x) container_of(x, struct a4xx_gpu, base) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c index 9f2dd76bd67a..075ecce4b5e0 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c @@ -2,9 +2,11 @@ /* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. */ - #include <linux/types.h> #include <linux/debugfs.h> + +#include <drm/drm_debugfs.h> +#include <drm/drm_file.h> #include <drm/drm_print.h> #include "a5xx_gpu.h" diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index e9c55d1d6c04..7d9e63e20ded 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -353,6 +353,9 @@ static int a5xx_me_init(struct msm_gpu *gpu) * 2D mode 3 draw */ OUT_RING(ring, 0x0000000B); + } else if (adreno_is_a510(adreno_gpu)) { + /* Workaround for token and syncs */ + OUT_RING(ring, 0x00000001); } else { /* No workarounds enabled */ OUT_RING(ring, 0x00000000); @@ -568,15 +571,24 @@ static int a5xx_hw_init(struct msm_gpu *gpu) 0x00100000 + adreno_gpu->gmem - 1); gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_HI, 0x00000000); - gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x40); - if (adreno_is_a530(adreno_gpu)) - gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x40); - if (adreno_is_a540(adreno_gpu)) - gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x400); - gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x80000060); - gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x40201B16); - - gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, (0x400 << 11 | 0x300 << 22)); + if (adreno_is_a510(adreno_gpu)) { + gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x20); + gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x20); + gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x40000030); + gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x20100D0A); + gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, + (0x200 << 11 | 0x200 << 22)); + } else { + gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x40); + if (adreno_is_a530(adreno_gpu)) + gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x40); + if (adreno_is_a540(adreno_gpu)) + gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x400); + gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x80000060); + gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x40201B16); + gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, + (0x400 << 11 | 0x300 << 22)); + } if (adreno_gpu->info->quirks & ADRENO_QUIRK_TWO_PASS_USE_WFI) gpu_rmw(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0, (1 << 8)); @@ -589,6 +601,19 @@ static int a5xx_hw_init(struct msm_gpu *gpu) /* Enable ME/PFP split notification */ gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL1, 0xA6FFFFFF); + /* + * In A5x, CCU can send context_done event of a particular context to + * UCHE which ultimately reaches CP even when there is valid + * transaction of that context inside CCU. This can let CP to program + * config registers, which will make the "valid transaction" inside + * CCU to be interpreted differently. This can cause gpu fault. This + * bug is fixed in latest A510 revision. To enable this bug fix - + * bit[11] of RB_DBG_ECO_CNTL need to be set to 0, default is 1 + * (disable). For older A510 version this bit is unused. + */ + if (adreno_is_a510(adreno_gpu)) + gpu_rmw(gpu, REG_A5XX_RB_DBG_ECO_CNTL, (1 << 11), 0); + /* Enable HWCG */ a5xx_set_hwcg(gpu, true); @@ -635,7 +660,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) /* UCHE */ gpu_write(gpu, REG_A5XX_CP_PROTECT(16), ADRENO_PROTECT_RW(0xE80, 16)); - if (adreno_is_a530(adreno_gpu)) + if (adreno_is_a530(adreno_gpu) || adreno_is_a510(adreno_gpu)) gpu_write(gpu, REG_A5XX_CP_PROTECT(17), ADRENO_PROTECT_RW(0x10000, 0x8000)); @@ -679,7 +704,8 @@ static int a5xx_hw_init(struct msm_gpu *gpu) a5xx_preempt_hw_init(gpu); - a5xx_gpmu_ucode_init(gpu); + if (!adreno_is_a510(adreno_gpu)) + a5xx_gpmu_ucode_init(gpu); ret = a5xx_ucode_init(gpu); if (ret) @@ -712,7 +738,8 @@ static int a5xx_hw_init(struct msm_gpu *gpu) } /* - * Try to load a zap shader into the secure world. If successful + * If the chip that we are using does support loading one, then + * try to load a zap shader into the secure world. If successful * we can use the CP to switch out of secure mode. If not then we * have no resource but to try to switch ourselves out manually. If we * guessed wrong then access to the RBBM_SECVID_TRUST_CNTL register will @@ -726,11 +753,18 @@ static int a5xx_hw_init(struct msm_gpu *gpu) gpu->funcs->flush(gpu, gpu->rb[0]); if (!a5xx_idle(gpu, gpu->rb[0])) return -EINVAL; - } else { - /* Print a warning so if we die, we know why */ + } else if (ret == -ENODEV) { + /* + * This device does not use zap shader (but print a warning + * just in case someone got their dt wrong.. hopefully they + * have a debug UART to realize the error of their ways... + * if you mess this up you are about to crash horribly) + */ dev_warn_once(gpu->dev->dev, "Zap shader not enabled - using SECVID_TRUST_CNTL instead\n"); gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0); + } else { + return ret; } /* Last step - yield the ringbuffer */ @@ -1066,6 +1100,7 @@ static void a5xx_dump(struct msm_gpu *gpu) static int a5xx_pm_resume(struct msm_gpu *gpu) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int ret; /* Turn on the core power */ @@ -1073,6 +1108,15 @@ static int a5xx_pm_resume(struct msm_gpu *gpu) if (ret) return ret; + if (adreno_is_a510(adreno_gpu)) { + /* Halt the sp_input_clk at HM level */ + gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, 0x00000055); + a5xx_set_hwcg(gpu, true); + /* Turn on sp_input_clk at HM level */ + gpu_rmw(gpu, REG_A5XX_RBBM_CLOCK_CNTL, 0xff, 0); + return 0; + } + /* Turn the RBCCU domain first to limit the chances of voltage droop */ gpu_write(gpu, REG_A5XX_GPMU_RBCCU_POWER_CNTL, 0x778000); @@ -1101,9 +1145,17 @@ static int a5xx_pm_resume(struct msm_gpu *gpu) static int a5xx_pm_suspend(struct msm_gpu *gpu) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + u32 mask = 0xf; + + /* A510 has 3 XIN ports in VBIF */ + if (adreno_is_a510(adreno_gpu)) + mask = 0x7; + /* Clear the VBIF pipe before shutting down */ - gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF); - spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) == 0xF); + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, mask); + spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & + mask) == mask); gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); @@ -1289,7 +1341,7 @@ static void a5xx_gpu_state_destroy(struct kref *kref) kfree(a5xx_state); } -int a5xx_gpu_state_put(struct msm_gpu_state *state) +static int a5xx_gpu_state_put(struct msm_gpu_state *state) { if (IS_ERR_OR_NULL(state)) return 1; @@ -1299,8 +1351,8 @@ int a5xx_gpu_state_put(struct msm_gpu_state *state) #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) -void a5xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state, - struct drm_printer *p) +static void a5xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state, + struct drm_printer *p) { int i, j; u32 pos = 0; diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c index a3a06db675ba..321a8061fd32 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_power.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c @@ -297,6 +297,10 @@ int a5xx_power_init(struct msm_gpu *gpu) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int ret; + /* Not all A5xx chips have a GPMU */ + if (adreno_is_a510(adreno_gpu)) + return 0; + /* Set up the limits management */ if (adreno_is_a530(adreno_gpu)) a530_lm_setup(gpu); @@ -326,6 +330,9 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) unsigned int *data, *ptr, *cmds; unsigned int cmds_size; + if (adreno_is_a510(adreno_gpu)) + return; + if (a5xx_gpu->gpmu_bo) return; diff --git a/drivers/gpu/drm/msm/adreno/a6xx.xml.h b/drivers/gpu/drm/msm/adreno/a6xx.xml.h index f44553ec3193..ed78fee2a262 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a6xx.xml.h @@ -16,11 +16,11 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/envytools/rnndb/adreno/a3xx.xml ( 83840 bytes, from 2018-07-03 19:37:13) - /home/robclark/src/envytools/rnndb/adreno/a4xx.xml ( 112086 bytes, from 2018-07-03 19:37:13) - /home/robclark/src/envytools/rnndb/adreno/a5xx.xml ( 147240 bytes, from 2018-12-02 17:29:54) -- /home/robclark/src/envytools/rnndb/adreno/a6xx.xml ( 140790 bytes, from 2018-12-02 17:29:54) +- /home/smasetty/playarea/envytools/rnndb/adreno/a6xx.xml ( 161969 bytes, from 2019-11-29 07:18:16) - /home/robclark/src/envytools/rnndb/adreno/a6xx_gmu.xml ( 10431 bytes, from 2018-09-14 13:03:07) - /home/robclark/src/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2018-07-03 19:37:13) -Copyright (C) 2013-2018 by the following authors: +Copyright (C) 2013-2019 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) - Ilia Mirkin <imirkin@alum.mit.edu> (imirkin) @@ -2519,6 +2519,54 @@ static inline uint32_t A6XX_VBIF_TEST_BUS2_CTRL1_DATA_SEL(uint32_t val) #define REG_A6XX_VBIF_PERF_PWR_CNT_HIGH2 0x0000311a +#define REG_A6XX_GBIF_SCACHE_CNTL1 0x00003c02 + +#define REG_A6XX_GBIF_QSB_SIDE0 0x00003c03 + +#define REG_A6XX_GBIF_QSB_SIDE1 0x00003c04 + +#define REG_A6XX_GBIF_QSB_SIDE2 0x00003c05 + +#define REG_A6XX_GBIF_QSB_SIDE3 0x00003c06 + +#define REG_A6XX_GBIF_HALT 0x00003c45 + +#define REG_A6XX_GBIF_HALT_ACK 0x00003c46 + +#define REG_A6XX_GBIF_PERF_PWR_CNT_EN 0x00003cc0 + +#define REG_A6XX_GBIF_PERF_CNT_SEL 0x00003cc2 + +#define REG_A6XX_GBIF_PERF_PWR_CNT_SEL 0x00003cc3 + +#define REG_A6XX_GBIF_PERF_CNT_LOW0 0x00003cc4 + +#define REG_A6XX_GBIF_PERF_CNT_LOW1 0x00003cc5 + +#define REG_A6XX_GBIF_PERF_CNT_LOW2 0x00003cc6 + +#define REG_A6XX_GBIF_PERF_CNT_LOW3 0x00003cc7 + +#define REG_A6XX_GBIF_PERF_CNT_HIGH0 0x00003cc8 + +#define REG_A6XX_GBIF_PERF_CNT_HIGH1 0x00003cc9 + +#define REG_A6XX_GBIF_PERF_CNT_HIGH2 0x00003cca + +#define REG_A6XX_GBIF_PERF_CNT_HIGH3 0x00003ccb + +#define REG_A6XX_GBIF_PWR_CNT_LOW0 0x00003ccc + +#define REG_A6XX_GBIF_PWR_CNT_LOW1 0x00003ccd + +#define REG_A6XX_GBIF_PWR_CNT_LOW2 0x00003cce + +#define REG_A6XX_GBIF_PWR_CNT_HIGH0 0x00003ccf + +#define REG_A6XX_GBIF_PWR_CNT_HIGH1 0x00003cd0 + +#define REG_A6XX_GBIF_PWR_CNT_HIGH2 0x00003cd1 + #define REG_A6XX_RB_WINDOW_OFFSET2 0x000088d4 #define A6XX_RB_WINDOW_OFFSET2_WINDOW_OFFSET_DISABLE 0x80000000 #define A6XX_RB_WINDOW_OFFSET2_X__MASK 0x00007fff diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 2ca470eb5cb8..983afeaee737 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. */ #include <linux/clk.h> #include <linux/interconnect.h> @@ -149,6 +149,8 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq) if (freq == gmu->gpu_freqs[perf_index]) break; + gmu->current_perf_index = perf_index; + __a6xx_gmu_set_freq(gmu, perf_index); } @@ -433,6 +435,8 @@ static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev, static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) { + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct platform_device *pdev = to_platform_device(gmu->dev); void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc"); void __iomem *seqptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc_seq"); @@ -480,20 +484,34 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_MSGID + 4, 0x10108); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_ADDR + 4, 0x30000); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_DATA + 4, 0x0); + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_MSGID + 8, 0x10108); - pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_ADDR + 8, 0x30080); + if (adreno_is_a618(adreno_gpu)) + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_ADDR + 8, 0x30090); + else + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_ADDR + 8, 0x30080); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_DATA + 8, 0x0); + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD_ENABLE_BANK, 7); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD_WAIT_FOR_CMPL_BANK, 0); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CONTROL, 0); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID, 0x10108); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR, 0x30010); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA, 2); + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 4, 0x10108); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 4, 0x30000); - pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x3); + if (adreno_is_a618(adreno_gpu)) + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x2); + else + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x3); + + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 8, 0x10108); - pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 8, 0x30080); + if (adreno_is_a618(adreno_gpu)) + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 8, 0x30090); + else + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 8, 0x30080); pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 8, 0x3); /* Setup GPU PDC */ @@ -741,8 +759,8 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) gmu_write(gmu, REG_A6XX_GMU_GMU2HOST_INTR_MASK, ~A6XX_HFI_IRQ_MASK); enable_irq(gmu->hfi_irq); - /* Set the GPU to the highest power frequency */ - __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); + /* Set the GPU to the current freq */ + __a6xx_gmu_set_freq(gmu, gmu->current_perf_index); /* * "enable" the GX power domain which won't actually do anything but it @@ -1166,13 +1184,15 @@ static int a6xx_gmu_pwrlevels_probe(struct a6xx_gmu *gmu) gmu->nr_gpu_freqs = a6xx_gmu_build_freq_table(&gpu->pdev->dev, gmu->gpu_freqs, ARRAY_SIZE(gmu->gpu_freqs)); + gmu->current_perf_index = gmu->nr_gpu_freqs - 1; + /* Build the list of RPMh votes that we'll send to the GMU */ return a6xx_gmu_rpmh_votes_init(gmu); } static int a6xx_gmu_clocks_probe(struct a6xx_gmu *gmu) { - int ret = msm_clk_bulk_get(gmu->dev, &gmu->clocks); + int ret = devm_clk_bulk_get_all(gmu->dev, &gmu->clocks); if (ret < 1) return ret; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h index 39a26dd63674..2af91ed7ed0c 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h @@ -63,6 +63,9 @@ struct a6xx_gmu { struct clk_bulk_data *clocks; struct clk *core_clk; + /* current performance index set externally */ + int current_perf_index; + int nr_gpu_freqs; unsigned long gpu_freqs[16]; u32 gx_arc_votes[16]; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index dc8ec2c94301..daf07800cde0 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. */ #include "msm_gem.h" @@ -378,6 +378,18 @@ static int a6xx_hw_init(struct msm_gpu *gpu) struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); int ret; + /* + * During a previous slumber, GBIF halt is asserted to ensure + * no further transaction can go through GPU before GPU + * headswitch is turned off. + * + * This halt is deasserted once headswitch goes off but + * incase headswitch doesn't goes off clear GBIF halt + * here to ensure GPU wake-up doesn't fail because of + * halted GPU transactions. + */ + gpu_write(gpu, REG_A6XX_GBIF_HALT, 0x0); + /* Make sure the GMU keeps the GPU on while we set it up */ a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); @@ -406,12 +418,17 @@ static int a6xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A6XX_TPL1_ADDR_MODE_CNTL, 0x1); gpu_write(gpu, REG_A6XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL, 0x1); - /* enable hardware clockgating */ - a6xx_set_hwcg(gpu, true); + /* + * enable hardware clockgating + * For now enable clock gating only for a630 + */ + if (adreno_is_a630(adreno_gpu)) + a6xx_set_hwcg(gpu, true); - /* VBIF start */ - gpu_write(gpu, REG_A6XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009); + /* VBIF/GBIF start*/ gpu_write(gpu, REG_A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x3); + if (adreno_is_a630(adreno_gpu)) + gpu_write(gpu, REG_A6XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009); /* Make all blocks contribute to the GPU BUSY perf counter */ gpu_write(gpu, REG_A6XX_RBBM_PERFCTR_GPU_BUSY_MASKED, 0xffffffff); @@ -537,12 +554,19 @@ static int a6xx_hw_init(struct msm_gpu *gpu) a6xx_flush(gpu, gpu->rb[0]); if (!a6xx_idle(gpu, gpu->rb[0])) return -EINVAL; - } else { - /* Print a warning so if we die, we know why */ + } else if (ret == -ENODEV) { + /* + * This device does not use zap shader (but print a warning + * just in case someone got their dt wrong.. hopefully they + * have a debug UART to realize the error of their ways... + * if you mess this up you are about to crash horribly) + */ dev_warn_once(gpu->dev->dev, "Zap shader not enabled - using SECVID_TRUST_CNTL instead\n"); gpu_write(gpu, REG_A6XX_RBBM_SECVID_TRUST_CNTL, 0x0); ret = 0; + } else { + return ret; } out: @@ -724,6 +748,39 @@ static const u32 a6xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_A6XX_CP_RB_CNTL), }; +#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) +{ + struct msm_gpu *gpu = &adreno_gpu->base; + + if(!a6xx_has_gbif(adreno_gpu)){ + gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0xf); + spin_until((gpu_read(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL1) & + 0xf) == 0xf); + gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0); + + return; + } + + /* Halt new client requests on GBIF */ + gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_CLIENT_HALT_MASK); + spin_until((gpu_read(gpu, REG_A6XX_GBIF_HALT_ACK) & + (GBIF_CLIENT_HALT_MASK)) == GBIF_CLIENT_HALT_MASK); + + /* Halt all AXI requests on GBIF */ + gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_ARB_HALT_MASK); + spin_until((gpu_read(gpu, REG_A6XX_GBIF_HALT_ACK) & + (GBIF_ARB_HALT_MASK)) == GBIF_ARB_HALT_MASK); + + /* + * GMU needs DDR access in slumber path. Deassert GBIF halt now + * to allow for GMU to access system memory. + */ + gpu_write(gpu, REG_A6XX_GBIF_HALT, 0x0); +} + static int a6xx_pm_resume(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -748,6 +805,16 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu) devfreq_suspend_device(gpu->devfreq.devfreq); + /* + * Make sure the GMU is idle before continuing (because some transitions + * may use VBIF + */ + a6xx_gmu_wait_for_idle(&a6xx_gpu->gmu); + + /* Clear the VBIF pipe before shutting down */ + /* FIXME: This accesses the GPU - do we need to make sure it is on? */ + a6xx_bus_clear_pending_transactions(adreno_gpu); + return a6xx_gmu_stop(a6xx_gpu); } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index 64399554f2dd..7239b8b60939 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2017 The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2017, 2019 The Linux Foundation. All rights reserved. */ #ifndef __A6XX_GPU_H__ #define __A6XX_GPU_H__ @@ -42,6 +42,13 @@ struct a6xx_gpu { #define A6XX_PROTECT_RDONLY(_reg, _len) \ ((((_len) & 0x3FFF) << 18) | ((_reg) & 0x3FFFF)) +static inline bool a6xx_has_gbif(struct adreno_gpu *gpu) +{ + if(adreno_is_a630(gpu)) + return false; + + return true; +} int a6xx_gmu_resume(struct a6xx_gpu *gpu); int a6xx_gmu_stop(struct a6xx_gpu *gpu); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index e686331fa089..d6023ba8033c 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. */ #include <linux/ascii85.h> #include "msm_gem.h" @@ -320,6 +320,7 @@ static void a6xx_get_debugbus(struct msm_gpu *gpu, { struct resource *res; void __iomem *cxdbg = NULL; + int nr_debugbus_blocks; /* Set up the GX debug bus */ @@ -352,31 +353,33 @@ static void a6xx_get_debugbus(struct msm_gpu *gpu, cxdbg = ioremap(res->start, resource_size(res)); if (cxdbg) { - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_CNTLT, + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_CNTLT, A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT(0xf)); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_CNTLM, + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_CNTLM, A6XX_DBGC_CFG_DBGBUS_CNTLM_ENABLE(0xf)); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_0, 0); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_1, 0); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_2, 0); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_IVTL_3, 0); + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_IVTL_0, 0); + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_IVTL_1, 0); + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_IVTL_2, 0); + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_IVTL_3, 0); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_0, + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_0, 0x76543210); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_BYTEL_1, + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_1, 0xFEDCBA98); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_0, 0); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_1, 0); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_2, 0); - cxdbg_write(cxdbg, REG_A6XX_DBGC_CFG_DBGBUS_MASKL_3, 0); + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_MASKL_0, 0); + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_MASKL_1, 0); + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_MASKL_2, 0); + cxdbg_write(cxdbg, REG_A6XX_CX_DBGC_CFG_DBGBUS_MASKL_3, 0); } - a6xx_state->debugbus = state_kcalloc(a6xx_state, - ARRAY_SIZE(a6xx_debugbus_blocks), - sizeof(*a6xx_state->debugbus)); + nr_debugbus_blocks = ARRAY_SIZE(a6xx_debugbus_blocks) + + (a6xx_has_gbif(to_adreno_gpu(gpu)) ? 1 : 0); + + a6xx_state->debugbus = state_kcalloc(a6xx_state, nr_debugbus_blocks, + sizeof(*a6xx_state->debugbus)); if (a6xx_state->debugbus) { int i; @@ -388,15 +391,31 @@ static void a6xx_get_debugbus(struct msm_gpu *gpu, &a6xx_state->debugbus[i]); a6xx_state->nr_debugbus = ARRAY_SIZE(a6xx_debugbus_blocks); + + /* + * GBIF has same debugbus as of other GPU blocks, fall back to + * default path if GPU uses GBIF, also GBIF uses exactly same + * ID as of VBIF. + */ + if (a6xx_has_gbif(to_adreno_gpu(gpu))) { + a6xx_get_debugbus_block(gpu, a6xx_state, + &a6xx_gbif_debugbus_block, + &a6xx_state->debugbus[i]); + + a6xx_state->nr_debugbus += 1; + } } - a6xx_state->vbif_debugbus = - state_kcalloc(a6xx_state, 1, - sizeof(*a6xx_state->vbif_debugbus)); + /* Dump the VBIF debugbus on applicable targets */ + if (!a6xx_has_gbif(to_adreno_gpu(gpu))) { + a6xx_state->vbif_debugbus = + state_kcalloc(a6xx_state, 1, + sizeof(*a6xx_state->vbif_debugbus)); - if (a6xx_state->vbif_debugbus) - a6xx_get_vbif_debugbus_block(gpu, a6xx_state, - a6xx_state->vbif_debugbus); + if (a6xx_state->vbif_debugbus) + a6xx_get_vbif_debugbus_block(gpu, a6xx_state, + a6xx_state->vbif_debugbus); + } if (cxdbg) { a6xx_state->cx_debugbus = @@ -770,14 +789,16 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu, &a6xx_state->gmu_registers[1]); } +#define A6XX_GBIF_REGLIST_SIZE 1 static void a6xx_get_registers(struct msm_gpu *gpu, struct a6xx_gpu_state *a6xx_state, struct a6xx_crashdumper *dumper) { int i, count = ARRAY_SIZE(a6xx_ahb_reglist) + ARRAY_SIZE(a6xx_reglist) + - ARRAY_SIZE(a6xx_hlsq_reglist); + ARRAY_SIZE(a6xx_hlsq_reglist) + A6XX_GBIF_REGLIST_SIZE; int index = 0; + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); a6xx_state->registers = state_kcalloc(a6xx_state, count, sizeof(*a6xx_state->registers)); @@ -792,6 +813,15 @@ static void a6xx_get_registers(struct msm_gpu *gpu, a6xx_state, &a6xx_ahb_reglist[i], &a6xx_state->registers[index++]); + if (a6xx_has_gbif(adreno_gpu)) + a6xx_get_ahb_gpu_registers(gpu, + a6xx_state, &a6xx_gbif_reglist, + &a6xx_state->registers[index++]); + else + a6xx_get_ahb_gpu_registers(gpu, + a6xx_state, &a6xx_vbif_reglist, + &a6xx_state->registers[index++]); + for (i = 0; i < ARRAY_SIZE(a6xx_reglist); i++) a6xx_get_crashdumper_registers(gpu, a6xx_state, &a6xx_reglist[i], diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h index 68cccfa2870a..e67c20c415af 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. */ #ifndef _A6XX_CRASH_DUMP_H_ #define _A6XX_CRASH_DUMP_H_ @@ -307,11 +307,20 @@ static const u32 a6xx_vbif_registers[] = { 0x3410, 0x3410, 0x3800, 0x3801, }; +static const u32 a6xx_gbif_registers[] = { + 0x3C00, 0X3C0B, 0X3C40, 0X3C47, 0X3CC0, 0X3CD1, 0xE3A, 0xE3A, +}; + static const struct a6xx_registers a6xx_ahb_reglist[] = { REGS(a6xx_ahb_registers, 0, 0), - REGS(a6xx_vbif_registers, 0, 0), }; +static const struct a6xx_registers a6xx_vbif_reglist = + REGS(a6xx_vbif_registers, 0, 0); + +static const struct a6xx_registers a6xx_gbif_reglist = + REGS(a6xx_gbif_registers, 0, 0); + static const u32 a6xx_gmu_gx_registers[] = { /* GMU GX */ 0x0000, 0x0000, 0x0010, 0x0013, 0x0016, 0x0016, 0x0018, 0x001b, @@ -422,6 +431,9 @@ static const struct a6xx_debugbus_block { DEBUGBUS(A6XX_DBGBUS_TPL1_3, 0x100), }; +static const struct a6xx_debugbus_block a6xx_gbif_debugbus_block = + DEBUGBUS(A6XX_DBGBUS_VBIF, 0x100); + static const struct a6xx_debugbus_block a6xx_cx_debugbus_blocks[] = { DEBUGBUS(A6XX_DBGBUS_GMU_CX, 0x100), DEBUGBUS(A6XX_DBGBUS_CX, 0x100), diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 40133a43960c..cb3a6e597d76 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -115,6 +115,21 @@ static const struct adreno_info gpulist[] = { .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a4xx_gpu_init, }, { + .rev = ADRENO_REV(5, 1, 0, ANY_ID), + .revn = 510, + .name = "A510", + .fw = { + [ADRENO_FW_PM4] = "a530_pm4.fw", + [ADRENO_FW_PFP] = "a530_pfp.fw", + }, + .gmem = SZ_256K, + /* + * Increase inactive period to 250 to avoid bouncing + * the GDSC which appears to make it grumpy + */ + .inactive_period = 250, + .init = a5xx_gpu_init, + }, { .rev = ADRENO_REV(5, 3, 0, 2), .revn = 530, .name = "A530", @@ -152,6 +167,17 @@ static const struct adreno_info gpulist[] = { .init = a5xx_gpu_init, .zapfw = "a540_zap.mdt", }, { + .rev = ADRENO_REV(6, 1, 8, ANY_ID), + .revn = 618, + .name = "A618", + .fw = { + [ADRENO_FW_SQE] = "a630_sqe.fw", + [ADRENO_FW_GMU] = "a630_gmu.bin", + }, + .gmem = SZ_512K, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, + .init = a6xx_gpu_init, + }, { .rev = ADRENO_REV(6, 3, 0, ANY_ID), .revn = 630, .name = "A630", @@ -181,6 +207,7 @@ MODULE_FIRMWARE("qcom/a530_zap.b01"); MODULE_FIRMWARE("qcom/a530_zap.b02"); MODULE_FIRMWARE("qcom/a630_sqe.fw"); MODULE_FIRMWARE("qcom/a630_gmu.bin"); +MODULE_FIRMWARE("qcom/a630_zap.mbn"); static inline bool _rev_match(uint8_t entry, uint8_t id) { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 048c8be426f3..7fd29829b2fa 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -14,6 +14,7 @@ #include <linux/pm_opp.h> #include <linux/slab.h> #include <linux/soc/qcom/mdt_loader.h> +#include <soc/qcom/ocmem.h> #include "adreno_gpu.h" #include "msm_gem.h" #include "msm_mmu.h" @@ -25,6 +26,7 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, { struct device *dev = &gpu->pdev->dev; const struct firmware *fw; + const char *signed_fwname = NULL; struct device_node *np, *mem_np; struct resource r; phys_addr_t mem_phys; @@ -57,8 +59,43 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, mem_phys = r.start; - /* Request the MDT file for the firmware */ - fw = adreno_request_fw(to_adreno_gpu(gpu), fwname); + /* + * Check for a firmware-name property. This is the new scheme + * to handle firmware that may be signed with device specific + * keys, allowing us to have a different zap fw path for different + * devices. + * + * If the firmware-name property is found, we bypass the + * adreno_request_fw() mechanism, because we don't need to handle + * the /lib/firmware/qcom/... vs /lib/firmware/... case. + * + * If the firmware-name property is not found, for backwards + * compatibility we fall back to the fwname from the gpulist + * table. + */ + of_property_read_string_index(np, "firmware-name", 0, &signed_fwname); + if (signed_fwname) { + fwname = signed_fwname; + ret = request_firmware_direct(&fw, fwname, gpu->dev->dev); + if (ret) + fw = ERR_PTR(ret); + } else if (fwname) { + /* Request the MDT file from the default location: */ + fw = adreno_request_fw(to_adreno_gpu(gpu), fwname); + } else { + /* + * For new targets, we require the firmware-name property, + * if a zap-shader is required, rather than falling back + * to a firmware name specified in gpulist. + * + * Because the firmware is signed with a (potentially) + * device specific key, having the name come from gpulist + * was a bad idea, and is only provided for backwards + * compatibility for older targets. + */ + return -ENODEV; + } + if (IS_ERR(fw)) { DRM_DEV_ERROR(dev, "Unable to load %s\n", fwname); return PTR_ERR(fw); @@ -94,7 +131,7 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, * not. But since we've already gotten through adreno_request_fw() * we know which of the two cases it is: */ - if (to_adreno_gpu(gpu)->fwloc == FW_LOCATION_LEGACY) { + if (signed_fwname || (to_adreno_gpu(gpu)->fwloc == FW_LOCATION_LEGACY)) { ret = qcom_mdt_load(dev, fw, fwname, pasid, mem_region, mem_phys, mem_size, NULL); } else { @@ -145,14 +182,6 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) return -EPROBE_DEFER; } - /* Each GPU has a target specific zap shader firmware name to use */ - if (!adreno_gpu->info->zapfw) { - zap_available = false; - DRM_DEV_ERROR(&pdev->dev, - "Zap shader firmware file not specified for this target\n"); - return -ENODEV; - } - return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid); } @@ -825,7 +854,7 @@ static int adreno_get_legacy_pwrlevels(struct device *dev) node = of_get_compatible_child(dev->of_node, "qcom,gpu-pwrlevels"); if (!node) { - DRM_DEV_ERROR(dev, "Could not find the GPU powerlevels\n"); + DRM_DEV_DEBUG(dev, "Could not find the GPU powerlevels\n"); return -ENXIO; } @@ -886,13 +915,63 @@ static int adreno_get_pwrlevels(struct device *dev, DBG("fast_rate=%u, slow_rate=27000000", gpu->fast_rate); /* Check for an interconnect path for the bus */ - gpu->icc_path = of_icc_get(dev, NULL); + gpu->icc_path = of_icc_get(dev, "gfx-mem"); + if (!gpu->icc_path) { + /* + * Keep compatbility with device trees that don't have an + * interconnect-names property. + */ + gpu->icc_path = of_icc_get(dev, NULL); + } if (IS_ERR(gpu->icc_path)) gpu->icc_path = NULL; + gpu->ocmem_icc_path = of_icc_get(dev, "ocmem"); + if (IS_ERR(gpu->ocmem_icc_path)) + gpu->ocmem_icc_path = NULL; + + return 0; +} + +int adreno_gpu_ocmem_init(struct device *dev, struct adreno_gpu *adreno_gpu, + struct adreno_ocmem *adreno_ocmem) +{ + struct ocmem_buf *ocmem_hdl; + struct ocmem *ocmem; + + ocmem = of_get_ocmem(dev); + if (IS_ERR(ocmem)) { + if (PTR_ERR(ocmem) == -ENODEV) { + /* + * Return success since either the ocmem property was + * not specified in device tree, or ocmem support is + * not compiled into the kernel. + */ + return 0; + } + + return PTR_ERR(ocmem); + } + + ocmem_hdl = ocmem_allocate(ocmem, OCMEM_GRAPHICS, adreno_gpu->gmem); + if (IS_ERR(ocmem_hdl)) + return PTR_ERR(ocmem_hdl); + + adreno_ocmem->ocmem = ocmem; + adreno_ocmem->base = ocmem_hdl->addr; + adreno_ocmem->hdl = ocmem_hdl; + adreno_gpu->gmem = ocmem_hdl->len; + return 0; } +void adreno_gpu_ocmem_cleanup(struct adreno_ocmem *adreno_ocmem) +{ + if (adreno_ocmem && adreno_ocmem->base) + ocmem_free(adreno_ocmem->ocmem, OCMEM_GRAPHICS, + adreno_ocmem->hdl); +} + int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct adreno_gpu *adreno_gpu, const struct adreno_gpu_funcs *funcs, int nr_rings) @@ -937,6 +1016,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) release_firmware(adreno_gpu->fw[i]); icc_put(gpu->icc_path); + icc_put(gpu->ocmem_icc_path); 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 c7441fb8313e..9ff4e550e7bd 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -3,7 +3,7 @@ * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * - * Copyright (c) 2014,2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2017, 2019 The Linux Foundation. All rights reserved. */ #ifndef __ADRENO_GPU_H__ @@ -126,6 +126,12 @@ struct adreno_gpu { }; #define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base) +struct adreno_ocmem { + struct ocmem *ocmem; + unsigned long base; + void *hdl; +}; + /* platform config data (ie. from DT, or pdata) */ struct adreno_platform_config { struct adreno_rev rev; @@ -206,6 +212,11 @@ static inline int adreno_is_a430(struct adreno_gpu *gpu) return gpu->revn == 430; } +static inline int adreno_is_a510(struct adreno_gpu *gpu) +{ + return gpu->revn == 510; +} + static inline int adreno_is_a530(struct adreno_gpu *gpu) { return gpu->revn == 530; @@ -216,6 +227,16 @@ static inline int adreno_is_a540(struct adreno_gpu *gpu) return gpu->revn == 540; } +static inline int adreno_is_a618(struct adreno_gpu *gpu) +{ + return gpu->revn == 618; +} + +static inline int adreno_is_a630(struct adreno_gpu *gpu) +{ + return gpu->revn == 630; +} + int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname); @@ -236,6 +257,10 @@ void adreno_dump(struct msm_gpu *gpu); void adreno_wait_ring(struct msm_ringbuffer *ring, uint32_t ndwords); struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu); +int adreno_gpu_ocmem_init(struct device *dev, struct adreno_gpu *adreno_gpu, + struct adreno_ocmem *ocmem); +void adreno_gpu_ocmem_cleanup(struct adreno_ocmem *ocmem); + int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs, int nr_rings); @@ -315,10 +340,7 @@ OUT_PKT7(struct msm_ringbuffer *ring, uint8_t opcode, uint16_t cnt) static inline bool adreno_reg_check(struct adreno_gpu *gpu, enum adreno_regs offset_name) { - if (offset_name >= REG_ADRENO_REGISTER_MAX || - !gpu->reg_offsets[offset_name]) { - BUG(); - } + BUG_ON(offset_name >= REG_ADRENO_REGISTER_MAX || !gpu->reg_offsets[offset_name]); /* * REG_SKIP is a special value that tell us that the register in diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c index cdbea38b8697..f1bc6a1af7a7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c @@ -55,8 +55,7 @@ static void dpu_core_irq_callback_handler(void *arg, int irq_idx) int dpu_core_irq_idx_lookup(struct dpu_kms *dpu_kms, enum dpu_intr_type intr_type, u32 instance_idx) { - if (!dpu_kms || !dpu_kms->hw_intr || - !dpu_kms->hw_intr->ops.irq_idx_lookup) + if (!dpu_kms->hw_intr || !dpu_kms->hw_intr->ops.irq_idx_lookup) return -EINVAL; return dpu_kms->hw_intr->ops.irq_idx_lookup(intr_type, @@ -73,7 +72,7 @@ static int _dpu_core_irq_enable(struct dpu_kms *dpu_kms, int irq_idx) unsigned long irq_flags; int ret = 0, enable_count; - if (!dpu_kms || !dpu_kms->hw_intr || + if (!dpu_kms->hw_intr || !dpu_kms->irq_obj.enable_counts || !dpu_kms->irq_obj.irq_counts) { DPU_ERROR("invalid params\n"); @@ -114,7 +113,7 @@ int dpu_core_irq_enable(struct dpu_kms *dpu_kms, int *irq_idxs, u32 irq_count) { int i, ret = 0, counts; - if (!dpu_kms || !irq_idxs || !irq_count) { + if (!irq_idxs || !irq_count) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -138,7 +137,7 @@ static int _dpu_core_irq_disable(struct dpu_kms *dpu_kms, int irq_idx) { int ret = 0, enable_count; - if (!dpu_kms || !dpu_kms->hw_intr || !dpu_kms->irq_obj.enable_counts) { + if (!dpu_kms->hw_intr || !dpu_kms->irq_obj.enable_counts) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -169,7 +168,7 @@ int dpu_core_irq_disable(struct dpu_kms *dpu_kms, int *irq_idxs, u32 irq_count) { int i, ret = 0, counts; - if (!dpu_kms || !irq_idxs || !irq_count) { + if (!irq_idxs || !irq_count) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -186,7 +185,7 @@ int dpu_core_irq_disable(struct dpu_kms *dpu_kms, int *irq_idxs, u32 irq_count) u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx, bool clear) { - if (!dpu_kms || !dpu_kms->hw_intr || + if (!dpu_kms->hw_intr || !dpu_kms->hw_intr->ops.get_interrupt_status) return 0; @@ -205,7 +204,7 @@ int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, { unsigned long irq_flags; - if (!dpu_kms || !dpu_kms->irq_obj.irq_cb_tbl) { + if (!dpu_kms->irq_obj.irq_cb_tbl) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -240,7 +239,7 @@ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx, { unsigned long irq_flags; - if (!dpu_kms || !dpu_kms->irq_obj.irq_cb_tbl) { + if (!dpu_kms->irq_obj.irq_cb_tbl) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -274,8 +273,7 @@ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx, static void dpu_clear_all_irqs(struct dpu_kms *dpu_kms) { - if (!dpu_kms || !dpu_kms->hw_intr || - !dpu_kms->hw_intr->ops.clear_all_irqs) + if (!dpu_kms->hw_intr || !dpu_kms->hw_intr->ops.clear_all_irqs) return; dpu_kms->hw_intr->ops.clear_all_irqs(dpu_kms->hw_intr); @@ -283,8 +281,7 @@ static void dpu_clear_all_irqs(struct dpu_kms *dpu_kms) static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms) { - if (!dpu_kms || !dpu_kms->hw_intr || - !dpu_kms->hw_intr->ops.disable_all_irqs) + if (!dpu_kms->hw_intr || !dpu_kms->hw_intr->ops.disable_all_irqs) return; dpu_kms->hw_intr->ops.disable_all_irqs(dpu_kms->hw_intr); @@ -343,18 +340,8 @@ void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms) { - struct msm_drm_private *priv; int i; - if (!dpu_kms->dev) { - DPU_ERROR("invalid drm device\n"); - return; - } else if (!dpu_kms->dev->dev_private) { - DPU_ERROR("invalid device private\n"); - return; - } - priv = dpu_kms->dev->dev_private; - pm_runtime_get_sync(&dpu_kms->pdev->dev); dpu_clear_all_irqs(dpu_kms); dpu_disable_all_irqs(dpu_kms); @@ -379,18 +366,8 @@ void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms) void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms) { - struct msm_drm_private *priv; int i; - if (!dpu_kms->dev) { - DPU_ERROR("invalid drm device\n"); - return; - } else if (!dpu_kms->dev->dev_private) { - DPU_ERROR("invalid device private\n"); - return; - } - priv = dpu_kms->dev->dev_private; - pm_runtime_get_sync(&dpu_kms->pdev->dev); for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) if (atomic_read(&dpu_kms->irq_obj.enable_counts[i]) || diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c index 5cda96875e03..11f2bebe3869 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -32,18 +32,7 @@ enum dpu_perf_mode { static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) { struct msm_drm_private *priv; - - if (!crtc->dev || !crtc->dev->dev_private) { - DPU_ERROR("invalid device\n"); - return NULL; - } - priv = crtc->dev->dev_private; - if (!priv || !priv->kms) { - DPU_ERROR("invalid kms\n"); - return NULL; - } - return to_dpu_kms(priv->kms); } @@ -116,7 +105,7 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc, } kms = _dpu_crtc_get_kms(crtc); - if (!kms || !kms->catalog) { + if (!kms->catalog) { DPU_ERROR("invalid parameters\n"); return 0; } @@ -214,9 +203,7 @@ static int _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, */ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc) { - struct drm_crtc *tmp_crtc; struct dpu_crtc *dpu_crtc; - struct dpu_crtc_state *dpu_cstate; struct dpu_kms *kms; if (!crtc) { @@ -225,30 +212,16 @@ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc) } kms = _dpu_crtc_get_kms(crtc); - if (!kms || !kms->catalog) { + if (!kms->catalog) { DPU_ERROR("invalid kms\n"); return; } dpu_crtc = to_dpu_crtc(crtc); - dpu_cstate = to_dpu_crtc_state(crtc->state); - /* only do this for command mode rt client */ - if (dpu_crtc_get_intf_mode(crtc) != INTF_MODE_CMD) + if (atomic_dec_return(&kms->bandwidth_ref) > 0) return; - /* - * If video interface present, cmd panel bandwidth cannot be - * released. - */ - if (dpu_crtc_get_intf_mode(crtc) == INTF_MODE_CMD) - drm_for_each_crtc(tmp_crtc, crtc->dev) { - if (tmp_crtc->enabled && - dpu_crtc_get_intf_mode(tmp_crtc) == - INTF_MODE_VIDEO) - return; - } - /* Release the bandwidth */ if (kms->perf.enable_bw_release) { trace_dpu_cmd_release_bw(crtc->base.id); @@ -301,7 +274,6 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc, u64 clk_rate = 0; struct dpu_crtc *dpu_crtc; struct dpu_crtc_state *dpu_cstate; - struct msm_drm_private *priv; struct dpu_kms *kms; int ret; @@ -311,11 +283,10 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc, } kms = _dpu_crtc_get_kms(crtc); - if (!kms || !kms->catalog) { + if (!kms->catalog) { DPU_ERROR("invalid kms\n"); return -EINVAL; } - priv = kms->dev->dev_private; dpu_crtc = to_dpu_crtc(crtc); dpu_cstate = to_dpu_crtc_state(crtc->state); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index b3417d56032d..bf513411b243 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -9,11 +9,13 @@ #include <linux/sort.h> #include <linux/debugfs.h> #include <linux/ktime.h> + #include <drm/drm_crtc.h> #include <drm/drm_flip_work.h> #include <drm/drm_mode.h> #include <drm/drm_probe_helper.h> #include <drm/drm_rect.h> +#include <drm/drm_vblank.h> #include "dpu_kms.h" #include "dpu_hw_lm.h" @@ -195,10 +197,6 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) DPU_DEBUG("%s\n", dpu_crtc->name); for (i = 0; i < cstate->num_mixers; i++) { - if (!mixer[i].hw_lm || !mixer[i].lm_ctl) { - DPU_ERROR("invalid lm or ctl assigned to mixer\n"); - return; - } mixer[i].mixer_op_mode = 0; mixer[i].flush_mask = 0; if (mixer[i].lm_ctl->ops.clear_all_blendstages) @@ -264,11 +262,20 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) { struct drm_encoder *encoder; - if (!crtc || !crtc->dev) { + if (!crtc) { DPU_ERROR("invalid crtc\n"); return INTF_MODE_NONE; } + /* + * TODO: This function is called from dpu debugfs and as part of atomic + * check. When called from debugfs, the crtc->mutex must be held to + * read crtc->state. However reading crtc->state from atomic check isn't + * allowed (unless you have a good reason, a big comment, and a deep + * understanding of how the atomic/modeset locks work (<- and this is + * probably not possible)). So we'll keep the WARN_ON here for now, but + * really we need to figure out a better way to track our operating mode + */ WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); /* TODO: Returns the first INTF_MODE, could there be multiple values? */ @@ -292,19 +299,6 @@ void dpu_crtc_vblank_callback(struct drm_crtc *crtc) trace_dpu_crtc_vblank_cb(DRMID(crtc)); } -static void dpu_crtc_release_bw_unlocked(struct drm_crtc *crtc) -{ - int ret = 0; - struct drm_modeset_acquire_ctx ctx; - - DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, ret); - dpu_core_perf_crtc_release_bw(crtc); - DRM_MODESET_LOCK_ALL_END(ctx, ret); - if (ret) - DRM_ERROR("Failed to acquire modeset locks to release bw, %d\n", - ret); -} - static void dpu_crtc_frame_event_work(struct kthread_work *work) { struct dpu_crtc_frame_event *fevent = container_of(work, @@ -324,17 +318,12 @@ static void dpu_crtc_frame_event_work(struct kthread_work *work) | DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) { if (atomic_read(&dpu_crtc->frame_pending) < 1) { - /* this should not happen */ - DRM_ERROR("crtc%d ev:%u ts:%lld frame_pending:%d\n", - crtc->base.id, - fevent->event, - ktime_to_ns(fevent->ts), - atomic_read(&dpu_crtc->frame_pending)); + /* ignore vblank when not pending */ } else if (atomic_dec_return(&dpu_crtc->frame_pending) == 0) { /* release bandwidth and other resources */ trace_dpu_crtc_frame_event_done(DRMID(crtc), fevent->event); - dpu_crtc_release_bw_unlocked(crtc); + dpu_core_perf_crtc_release_bw(crtc); } else { trace_dpu_crtc_frame_event_more_pending(DRMID(crtc), fevent->event); @@ -407,13 +396,8 @@ static void dpu_crtc_frame_event_cb(void *data, u32 event) kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); } -void dpu_crtc_complete_commit(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) +void dpu_crtc_complete_commit(struct drm_crtc *crtc) { - if (!crtc || !crtc->state) { - DPU_ERROR("invalid crtc\n"); - return; - } trace_dpu_crtc_complete_commit(DRMID(crtc)); } @@ -623,13 +607,12 @@ static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) return rc; } -void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async) +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) { struct drm_encoder *encoder; struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); - int ret; /* * If no mixers has been allocated in dpu_crtc_atomic_check(), @@ -647,37 +630,22 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async) */ drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) - dpu_encoder_prepare_for_kickoff(encoder, async); - - if (!async) { - /* wait for frame_event_done completion */ - DPU_ATRACE_BEGIN("wait_for_frame_done_event"); - ret = _dpu_crtc_wait_for_frame_done(crtc); - DPU_ATRACE_END("wait_for_frame_done_event"); - if (ret) { - DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", - crtc->base.id, - atomic_read(&dpu_crtc->frame_pending)); - goto end; - } + dpu_encoder_prepare_for_kickoff(encoder); - if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { - /* acquire bandwidth and other resources */ - DPU_DEBUG("crtc%d first commit\n", crtc->base.id); - } else - DPU_DEBUG("crtc%d commit\n", crtc->base.id); + if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { + /* acquire bandwidth and other resources */ + DPU_DEBUG("crtc%d first commit\n", crtc->base.id); + } else + DPU_DEBUG("crtc%d commit\n", crtc->base.id); - dpu_crtc->play_count++; - } + dpu_crtc->play_count++; dpu_vbif_clear_errors(dpu_kms); drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) - dpu_encoder_kickoff(encoder, async); + dpu_encoder_kickoff(encoder); -end: - if (!async) - reinit_completion(&dpu_crtc->frame_done_comp); + reinit_completion(&dpu_crtc->frame_done_comp); DPU_ATRACE_END("crtc_commit"); } @@ -729,8 +697,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, struct drm_encoder *encoder; struct msm_drm_private *priv; unsigned long flags; + bool release_bandwidth = false; - if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { + if (!crtc || !crtc->state) { DPU_ERROR("invalid crtc\n"); return; } @@ -745,8 +714,15 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, drm_crtc_vblank_off(crtc); drm_for_each_encoder_mask(encoder, crtc->dev, - old_crtc_state->encoder_mask) + old_crtc_state->encoder_mask) { + /* in video mode, we hold an extra bandwidth reference + * as we cannot drop bandwidth at frame-done if any + * crtc is being used in video mode. + */ + if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) + release_bandwidth = true; dpu_encoder_assign_crtc(encoder, NULL); + } /* wait for frame_event_done completion */ if (_dpu_crtc_wait_for_frame_done(crtc)) @@ -760,7 +736,8 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, if (atomic_read(&dpu_crtc->frame_pending)) { trace_dpu_crtc_disable_frame_pending(DRMID(crtc), atomic_read(&dpu_crtc->frame_pending)); - dpu_core_perf_crtc_release_bw(crtc); + if (release_bandwidth) + dpu_core_perf_crtc_release_bw(crtc); atomic_set(&dpu_crtc->frame_pending, 0); } @@ -792,8 +769,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, struct dpu_crtc *dpu_crtc; struct drm_encoder *encoder; struct msm_drm_private *priv; + bool request_bandwidth; - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + if (!crtc) { DPU_ERROR("invalid crtc\n"); return; } @@ -804,9 +782,19 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); dpu_crtc = to_dpu_crtc(crtc); - drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { + /* in video mode, we hold an extra bandwidth reference + * as we cannot drop bandwidth at frame-done if any + * crtc is being used in video mode. + */ + if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) + request_bandwidth = true; dpu_encoder_register_frame_event_callback(encoder, dpu_crtc_frame_event_cb, (void *)crtc); + } + + if (request_bandwidth) + atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); dpu_crtc->enabled = true; @@ -981,6 +969,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, } } + atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); + rc = dpu_core_perf_crtc_check(crtc, state); if (rc) { DPU_ERROR("crtc%d failed performance check %d\n", @@ -1119,14 +1109,9 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data) for (i = 0; i < cstate->num_mixers; ++i) { m = &cstate->mixers[i]; - if (!m->hw_lm) - seq_printf(s, "\tmixer[%d] has no lm\n", i); - else if (!m->lm_ctl) - seq_printf(s, "\tmixer[%d] has no ctl\n", i); - else - seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", - m->hw_lm->idx - LM_0, m->lm_ctl->idx - CTL_0, - out_width, mode->vdisplay); + seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", + m->hw_lm->idx - LM_0, m->lm_ctl->idx - CTL_0, + out_width, mode->vdisplay); } seq_puts(s, "\n"); @@ -1303,13 +1288,8 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, { struct drm_crtc *crtc = NULL; struct dpu_crtc *dpu_crtc = NULL; - struct msm_drm_private *priv = NULL; - struct dpu_kms *kms = NULL; int i; - priv = dev->dev_private; - kms = to_dpu_kms(priv->kms); - dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL); if (!dpu_crtc) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 5181f079a6a1..5174e86124cc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -238,17 +238,14 @@ void dpu_crtc_vblank_callback(struct drm_crtc *crtc); /** * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc * @crtc: Pointer to drm crtc object - * @async: true if the commit is asynchronous, false otherwise */ -void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async); +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc); /** * dpu_crtc_complete_commit - callback signalling completion of current commit * @crtc: Pointer to drm crtc object - * @old_state: Pointer to drm crtc old state object */ -void dpu_crtc_complete_commit(struct drm_crtc *crtc, - struct drm_crtc_state *old_state); +void dpu_crtc_complete_commit(struct drm_crtc *crtc); /** * dpu_crtc_init - create a new crtc object diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 0aa8a12c9952..f8ac3bf60fd6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -6,14 +6,16 @@ */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ -#include <linux/kthread.h> #include <linux/debugfs.h> +#include <linux/kthread.h> #include <linux/seq_file.h> -#include "msm_drv.h" -#include "dpu_kms.h" #include <drm/drm_crtc.h> +#include <drm/drm_file.h> #include <drm/drm_probe_helper.h> + +#include "msm_drv.h" +#include "dpu_kms.h" #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_intf.h" @@ -56,7 +58,7 @@ #define IDLE_SHORT_TIMEOUT 1 -#define MAX_VDISPLAY_SPLIT 1080 +#define MAX_HDISPLAY_SPLIT 1080 /* timeout in frames waiting for frame done */ #define DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES 5 @@ -231,7 +233,7 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, u32 irq_status; int ret; - if (!phys_enc || !wait_info || intr_idx >= INTR_IDX_MAX) { + if (!wait_info || intr_idx >= INTR_IDX_MAX) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -306,7 +308,7 @@ int dpu_encoder_helper_register_irq(struct dpu_encoder_phys *phys_enc, struct dpu_encoder_irq *irq; int ret = 0; - if (!phys_enc || intr_idx >= INTR_IDX_MAX) { + if (intr_idx >= INTR_IDX_MAX) { DPU_ERROR("invalid params\n"); return -EINVAL; } @@ -361,10 +363,6 @@ int dpu_encoder_helper_unregister_irq(struct dpu_encoder_phys *phys_enc, struct dpu_encoder_irq *irq; int ret; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return -EINVAL; - } irq = &phys_enc->irq[intr_idx]; /* silently skip irqs that weren't registered */ @@ -413,7 +411,7 @@ void dpu_encoder_get_hw_resources(struct drm_encoder *drm_enc, for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.get_hw_resources) + if (phys->ops.get_hw_resources) phys->ops.get_hw_resources(phys, hw_res); } } @@ -436,7 +434,7 @@ static void dpu_encoder_destroy(struct drm_encoder *drm_enc) for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.destroy) { + if (phys->ops.destroy) { phys->ops.destroy(phys); --dpu_enc->num_phys_encs; dpu_enc->phys_encs[i] = NULL; @@ -462,7 +460,7 @@ void dpu_encoder_helper_split_config( struct dpu_hw_mdp *hw_mdptop; struct msm_display_info *disp_info; - if (!phys_enc || !phys_enc->hw_mdptop || !phys_enc->parent) { + if (!phys_enc->hw_mdptop || !phys_enc->parent) { DPU_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0); return; } @@ -532,8 +530,23 @@ static struct msm_display_topology dpu_encoder_get_topology( if (dpu_enc->phys_encs[i]) intf_count++; - /* User split topology for width > 1080 */ - topology.num_lm = (mode->vdisplay > MAX_VDISPLAY_SPLIT) ? 2 : 1; + /* Datapath topology selection + * + * Dual display + * 2 LM, 2 INTF ( Split display using 2 interfaces) + * + * Single display + * 1 LM, 1 INTF + * 2 LM, 1 INTF (stream merge to support high resolution interfaces) + * + */ + if (intf_count == 2) + topology.num_lm = 2; + else if (!dpu_kms->catalog->caps->has_3d_merge) + topology.num_lm = 1; + else + topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; + topology.num_enc = 0; topology.num_intf = intf_count; @@ -581,10 +594,10 @@ static int dpu_encoder_virt_atomic_check( for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.atomic_check) + if (phys->ops.atomic_check) ret = phys->ops.atomic_check(phys, crtc_state, conn_state); - else if (phys && phys->ops.mode_fixup) + else if (phys->ops.mode_fixup) if (!phys->ops.mode_fixup(phys, mode, adj_mode)) ret = -EINVAL; @@ -643,11 +656,6 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, priv = drm_enc->dev->dev_private; dpu_kms = to_dpu_kms(priv->kms); - if (!dpu_kms) { - DPU_ERROR("invalid dpu_kms\n"); - return; - } - hw_mdptop = dpu_kms->hw_mdp; if (!hw_mdptop) { DPU_ERROR("invalid mdptop\n"); @@ -685,7 +693,7 @@ static void _dpu_encoder_irq_control(struct drm_encoder *drm_enc, bool enable) for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.irq_control) + if (phys->ops.irq_control) phys->ops.irq_control(phys, enable); } @@ -733,8 +741,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, struct msm_drm_private *priv; bool is_vid_mode = false; - if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || - !drm_enc->crtc) { + if (!drm_enc || !drm_enc->dev || !drm_enc->crtc) { DPU_ERROR("invalid parameters\n"); return -EINVAL; } @@ -1036,46 +1043,43 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys) { - if (!dpu_enc->hw_pp[i]) { - DPU_ERROR_ENC(dpu_enc, "no pp block assigned" - "at idx: %d\n", i); - goto error; - } + if (!dpu_enc->hw_pp[i]) { + DPU_ERROR_ENC(dpu_enc, + "no pp block assigned at idx: %d\n", i); + goto error; + } - if (!hw_ctl[i]) { - DPU_ERROR_ENC(dpu_enc, "no ctl block assigned" - "at idx: %d\n", i); - goto error; - } + if (!hw_ctl[i]) { + DPU_ERROR_ENC(dpu_enc, + "no ctl block assigned at idx: %d\n", i); + goto error; + } - phys->hw_pp = dpu_enc->hw_pp[i]; - phys->hw_ctl = hw_ctl[i]; + phys->hw_pp = dpu_enc->hw_pp[i]; + phys->hw_ctl = hw_ctl[i]; - dpu_rm_init_hw_iter(&hw_iter, drm_enc->base.id, - DPU_HW_BLK_INTF); - for (j = 0; j < MAX_CHANNELS_PER_ENC; j++) { - struct dpu_hw_intf *hw_intf; + dpu_rm_init_hw_iter(&hw_iter, drm_enc->base.id, + DPU_HW_BLK_INTF); + for (j = 0; j < MAX_CHANNELS_PER_ENC; j++) { + struct dpu_hw_intf *hw_intf; - if (!dpu_rm_get_hw(&dpu_kms->rm, &hw_iter)) - break; + if (!dpu_rm_get_hw(&dpu_kms->rm, &hw_iter)) + break; - hw_intf = (struct dpu_hw_intf *)hw_iter.hw; - if (hw_intf->idx == phys->intf_idx) - phys->hw_intf = hw_intf; - } + hw_intf = (struct dpu_hw_intf *)hw_iter.hw; + if (hw_intf->idx == phys->intf_idx) + phys->hw_intf = hw_intf; + } - if (!phys->hw_intf) { - DPU_ERROR_ENC(dpu_enc, - "no intf block assigned at idx: %d\n", - i); + if (!phys->hw_intf) { + DPU_ERROR_ENC(dpu_enc, + "no intf block assigned at idx: %d\n", i); goto error; - } - - phys->connector = conn->state->connector; - if (phys->ops.mode_set) - phys->ops.mode_set(phys, mode, adj_mode); } + + phys->connector = conn->state->connector; + if (phys->ops.mode_set) + phys->ops.mode_set(phys, mode, adj_mode); } dpu_enc->mode_set_complete = true; @@ -1090,17 +1094,13 @@ static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) struct msm_drm_private *priv; struct dpu_kms *dpu_kms; - if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + if (!drm_enc || !drm_enc->dev) { DPU_ERROR("invalid parameters\n"); return; } priv = drm_enc->dev->dev_private; dpu_kms = to_dpu_kms(priv->kms); - if (!dpu_kms) { - DPU_ERROR("invalid dpu_kms\n"); - return; - } dpu_enc = to_dpu_encoder_virt(drm_enc); if (!dpu_enc || !dpu_enc->cur_master) { @@ -1182,7 +1182,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) struct dpu_encoder_virt *dpu_enc = NULL; struct msm_drm_private *priv; struct dpu_kms *dpu_kms; - struct drm_display_mode *mode; int i = 0; if (!drm_enc) { @@ -1191,9 +1190,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) } else if (!drm_enc->dev) { DPU_ERROR("invalid dev\n"); return; - } else if (!drm_enc->dev->dev_private) { - DPU_ERROR("invalid dev_private\n"); - return; } dpu_enc = to_dpu_encoder_virt(drm_enc); @@ -1202,8 +1198,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) mutex_lock(&dpu_enc->enc_lock); dpu_enc->enabled = false; - mode = &drm_enc->crtc->state->adjusted_mode; - priv = drm_enc->dev->dev_private; dpu_kms = to_dpu_kms(priv->kms); @@ -1217,7 +1211,7 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.disable) + if (phys->ops.disable) phys->ops.disable(phys); } @@ -1230,8 +1224,7 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_STOP); for (i = 0; i < dpu_enc->num_phys_encs; i++) { - if (dpu_enc->phys_encs[i]) - dpu_enc->phys_encs[i]->connector = NULL; + dpu_enc->phys_encs[i]->connector = NULL; } DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); @@ -1321,7 +1314,7 @@ void dpu_encoder_toggle_vblank_for_crtc(struct drm_encoder *drm_enc, for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.control_vblank_irq) + if (phys->ops.control_vblank_irq) phys->ops.control_vblank_irq(phys, enable); } } @@ -1421,34 +1414,24 @@ static void dpu_encoder_off_work(struct work_struct *work) * extra_flush_bits: Additional bit mask to include in flush trigger */ static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc, - struct dpu_encoder_phys *phys, uint32_t extra_flush_bits, - bool async) + struct dpu_encoder_phys *phys, uint32_t extra_flush_bits) { struct dpu_hw_ctl *ctl; int pending_kickoff_cnt; u32 ret = UINT_MAX; - if (!drm_enc || !phys) { - DPU_ERROR("invalid argument(s), drm_enc %d, phys_enc %d\n", - drm_enc != 0, phys != 0); - return; - } - if (!phys->hw_pp) { DPU_ERROR("invalid pingpong hw\n"); return; } ctl = phys->hw_ctl; - if (!ctl || !ctl->ops.trigger_flush) { + if (!ctl->ops.trigger_flush) { DPU_ERROR("missing trigger cb\n"); return; } - if (!async) - pending_kickoff_cnt = dpu_encoder_phys_inc_pending(phys); - else - pending_kickoff_cnt = atomic_read(&phys->pending_kickoff_cnt); + pending_kickoff_cnt = dpu_encoder_phys_inc_pending(phys); if (extra_flush_bits && ctl->ops.update_pending_flush) ctl->ops.update_pending_flush(ctl, extra_flush_bits); @@ -1487,13 +1470,8 @@ void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc) { struct dpu_hw_ctl *ctl; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - ctl = phys_enc->hw_ctl; - if (ctl && ctl->ops.trigger_start) { + if (ctl->ops.trigger_start) { ctl->ops.trigger_start(ctl); trace_dpu_enc_trigger_start(DRMID(phys_enc->parent), ctl->idx); } @@ -1530,14 +1508,10 @@ static void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc) struct dpu_hw_ctl *ctl; int rc; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } dpu_enc = to_dpu_encoder_virt(phys_enc->parent); ctl = phys_enc->hw_ctl; - if (!ctl || !ctl->ops.reset) + if (!ctl->ops.reset) return; DRM_DEBUG_KMS("id:%u ctl %d reset\n", DRMID(phys_enc->parent), @@ -1559,18 +1533,12 @@ static void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc) * a time. * dpu_enc: Pointer to virtual encoder structure */ -static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc, - bool async) +static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc) { struct dpu_hw_ctl *ctl; uint32_t i, pending_flush; unsigned long lock_flags; - if (!dpu_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - pending_flush = 0x0; /* update pending counts and trigger kickoff ctl flush atomically */ @@ -1580,25 +1548,22 @@ static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc, for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (!phys || phys->enable_state == DPU_ENC_DISABLED) + if (phys->enable_state == DPU_ENC_DISABLED) continue; ctl = phys->hw_ctl; - if (!ctl) - continue; /* * This is cleared in frame_done worker, which isn't invoked * for async commits. So don't set this for async, since it'll * roll over to the next commit. */ - if (!async && phys->split_role != ENC_ROLE_SLAVE) + if (phys->split_role != ENC_ROLE_SLAVE) set_bit(i, dpu_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || !phys->ops.needs_single_flush(phys)) - _dpu_encoder_trigger_flush(&dpu_enc->base, phys, 0x0, - async); + _dpu_encoder_trigger_flush(&dpu_enc->base, phys, 0x0); else if (ctl->ops.get_pending_flush) pending_flush |= ctl->ops.get_pending_flush(ctl); } @@ -1608,7 +1573,7 @@ static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc, _dpu_encoder_trigger_flush( &dpu_enc->base, dpu_enc->cur_master, - pending_flush, async); + pending_flush); } _dpu_encoder_trigger_start(dpu_enc->cur_master); @@ -1634,17 +1599,15 @@ void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) for (i = 0; i < dpu_enc->num_phys_encs; i++) { phys = dpu_enc->phys_encs[i]; - if (phys && phys->hw_ctl) { - ctl = phys->hw_ctl; - if (ctl->ops.clear_pending_flush) - ctl->ops.clear_pending_flush(ctl); + ctl = phys->hw_ctl; + if (ctl->ops.clear_pending_flush) + ctl->ops.clear_pending_flush(ctl); - /* update only for command mode primary ctl */ - if ((phys == dpu_enc->cur_master) && - (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) - && ctl->ops.trigger_pending) - ctl->ops.trigger_pending(ctl); - } + /* update only for command mode primary ctl */ + if ((phys == dpu_enc->cur_master) && + (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) + && ctl->ops.trigger_pending) + ctl->ops.trigger_pending(ctl); } } @@ -1695,8 +1658,7 @@ static u32 _dpu_encoder_calculate_linetime(struct dpu_encoder_virt *dpu_enc, return line_time; } -static int _dpu_encoder_wakeup_time(struct drm_encoder *drm_enc, - ktime_t *wakeup_time) +int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time) { struct drm_display_mode *mode; struct dpu_encoder_virt *dpu_enc; @@ -1750,8 +1712,7 @@ static void dpu_encoder_vsync_event_handler(struct timer_list *t) struct msm_drm_private *priv; struct msm_drm_thread *event_thread; - if (!drm_enc->dev || !drm_enc->dev->dev_private || - !drm_enc->crtc) { + if (!drm_enc->dev || !drm_enc->crtc) { DPU_ERROR("invalid parameters\n"); return; } @@ -1783,7 +1744,7 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) return; } - if (_dpu_encoder_wakeup_time(&dpu_enc->base, &wakeup_time)) + if (dpu_encoder_vsync_time(&dpu_enc->base, &wakeup_time)) return; trace_dpu_enc_vsync_event_work(DRMID(&dpu_enc->base), wakeup_time); @@ -1791,17 +1752,13 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) nsecs_to_jiffies(ktime_to_ns(wakeup_time))); } -void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, bool async) +void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; struct dpu_encoder_phys *phys; bool needs_hw_reset = false; unsigned int i; - if (!drm_enc) { - DPU_ERROR("invalid args\n"); - return; - } dpu_enc = to_dpu_encoder_virt(drm_enc); trace_dpu_enc_prepare_kickoff(DRMID(drm_enc)); @@ -1810,12 +1767,10 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, bool async) DPU_ATRACE_BEGIN("enc_prepare_for_kickoff"); for (i = 0; i < dpu_enc->num_phys_encs; i++) { phys = dpu_enc->phys_encs[i]; - if (phys) { - if (phys->ops.prepare_for_kickoff) - phys->ops.prepare_for_kickoff(phys); - if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET) - needs_hw_reset = true; - } + if (phys->ops.prepare_for_kickoff) + phys->ops.prepare_for_kickoff(phys); + if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET) + needs_hw_reset = true; } DPU_ATRACE_END("enc_prepare_for_kickoff"); @@ -1830,49 +1785,38 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, bool async) } } -void dpu_encoder_kickoff(struct drm_encoder *drm_enc, bool async) +void dpu_encoder_kickoff(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; struct dpu_encoder_phys *phys; ktime_t wakeup_time; + unsigned long timeout_ms; unsigned int i; - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } DPU_ATRACE_BEGIN("encoder_kickoff"); dpu_enc = to_dpu_encoder_virt(drm_enc); trace_dpu_enc_kickoff(DRMID(drm_enc)); - /* - * Asynchronous frames don't handle FRAME_DONE events. As such, they - * shouldn't enable the frame_done watchdog since it will always time - * out. - */ - if (!async) { - unsigned long timeout_ms; - timeout_ms = DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES * 1000 / + timeout_ms = DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES * 1000 / drm_mode_vrefresh(&drm_enc->crtc->state->adjusted_mode); - atomic_set(&dpu_enc->frame_done_timeout_ms, timeout_ms); - mod_timer(&dpu_enc->frame_done_timer, - jiffies + msecs_to_jiffies(timeout_ms)); - } + atomic_set(&dpu_enc->frame_done_timeout_ms, timeout_ms); + mod_timer(&dpu_enc->frame_done_timer, + jiffies + msecs_to_jiffies(timeout_ms)); /* All phys encs are ready to go, trigger the kickoff */ - _dpu_encoder_kickoff_phys(dpu_enc, async); + _dpu_encoder_kickoff_phys(dpu_enc); /* allow phys encs to handle any post-kickoff business */ for (i = 0; i < dpu_enc->num_phys_encs; i++) { phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.handle_post_kickoff) + if (phys->ops.handle_post_kickoff) phys->ops.handle_post_kickoff(phys); } if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI && - !_dpu_encoder_wakeup_time(drm_enc, &wakeup_time)) { + !dpu_encoder_vsync_time(drm_enc, &wakeup_time)) { trace_dpu_enc_early_kickoff(DRMID(drm_enc), ktime_to_ms(wakeup_time)); mod_timer(&dpu_enc->vsync_event_timer, @@ -1896,7 +1840,7 @@ void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc) for (i = 0; i < dpu_enc->num_phys_encs; i++) { phys = dpu_enc->phys_encs[i]; - if (phys && phys->ops.prepare_commit) + if (phys->ops.prepare_commit) phys->ops.prepare_commit(phys); } } @@ -1911,9 +1855,6 @@ static int _dpu_encoder_status_show(struct seq_file *s, void *data) for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (!phys) - continue; - seq_printf(s, "intf:%d vsync:%8d underrun:%8d ", phys->intf_idx - INTF_0, atomic_read(&phys->vsync_cnt), @@ -1945,8 +1886,6 @@ static int _dpu_encoder_debugfs_status_open(struct inode *inode, static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); - struct msm_drm_private *priv; - struct dpu_kms *dpu_kms; int i; static const struct file_operations debugfs_status_fops = { @@ -1958,14 +1897,11 @@ static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) char name[DPU_NAME_SIZE]; - if (!drm_enc->dev || !drm_enc->dev->dev_private) { + if (!drm_enc->dev) { DPU_ERROR("invalid encoder or kms\n"); return -EINVAL; } - priv = drm_enc->dev->dev_private; - dpu_kms = to_dpu_kms(priv->kms); - snprintf(name, DPU_NAME_SIZE, "encoder%u", drm_enc->base.id); /* create overall sub-directory for the encoder */ @@ -1977,8 +1913,7 @@ static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) dpu_enc->debugfs_root, dpu_enc, &debugfs_status_fops); for (i = 0; i < dpu_enc->num_phys_encs; i++) - if (dpu_enc->phys_encs[i] && - dpu_enc->phys_encs[i]->ops.late_register) + if (dpu_enc->phys_encs[i]->ops.late_register) dpu_enc->phys_encs[i]->ops.late_register( dpu_enc->phys_encs[i], dpu_enc->debugfs_root); @@ -2073,9 +2008,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, enum dpu_intf_type intf_type; struct dpu_enc_phys_init_params phys_params; - if (!dpu_enc || !dpu_kms) { - DPU_ERROR("invalid arg(s), enc %d kms %d\n", - dpu_enc != 0, dpu_kms != 0); + if (!dpu_enc) { + DPU_ERROR("invalid arg(s), enc %d\n", dpu_enc != 0); return -EINVAL; } @@ -2148,11 +2082,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (phys) { - atomic_set(&phys->vsync_cnt, 0); - atomic_set(&phys->underrun_cnt, 0); - } + atomic_set(&phys->vsync_cnt, 0); + atomic_set(&phys->underrun_cnt, 0); } mutex_unlock(&dpu_enc->enc_lock); @@ -2164,14 +2095,12 @@ static void dpu_encoder_frame_done_timeout(struct timer_list *t) struct dpu_encoder_virt *dpu_enc = from_timer(dpu_enc, t, frame_done_timer); struct drm_encoder *drm_enc = &dpu_enc->base; - struct msm_drm_private *priv; u32 event; - if (!drm_enc->dev || !drm_enc->dev->dev_private) { + if (!drm_enc->dev) { DPU_ERROR("invalid parameters\n"); return; } - priv = drm_enc->dev->dev_private; if (!dpu_enc->frame_busy_mask[0] || !dpu_enc->crtc_frame_event_cb) { DRM_DEBUG_KMS("id:%u invalid timeout frame_busy_mask=%lu\n", @@ -2296,8 +2225,6 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - if (!phys) - continue; switch (event) { case MSM_ENC_COMMIT_DONE: @@ -2313,7 +2240,7 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n", event); return -EINVAL; - }; + } if (fn_wait) { DPU_ATRACE_BEGIN("wait_for_completion_event"); @@ -2330,7 +2257,6 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder) { struct dpu_encoder_virt *dpu_enc = NULL; - int i; if (!encoder) { DPU_ERROR("invalid encoder\n"); @@ -2341,12 +2267,8 @@ enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder) if (dpu_enc->cur_master) return dpu_enc->cur_master->intf_mode; - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (phys) - return phys->intf_mode; - } + if (dpu_enc->num_phys_encs) + return dpu_enc->phys_encs[0]->intf_mode; return INTF_MODE_NONE; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index a8bf1147fc56..b4913465e602 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -68,9 +68,8 @@ void dpu_encoder_register_frame_event_callback(struct drm_encoder *encoder, * Immediately: if no previous commit is outstanding. * Delayed: Block until next trigger can be issued. * @encoder: encoder pointer - * @async: true if this is an asynchronous commit */ -void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder, bool async); +void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder); /** * dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous @@ -83,9 +82,13 @@ void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *encoder); * dpu_encoder_kickoff - trigger a double buffer flip of the ctl path * (i.e. ctl flush and start) immediately. * @encoder: encoder pointer - * @async: true if this is an asynchronous commit */ -void dpu_encoder_kickoff(struct drm_encoder *encoder, bool async); +void dpu_encoder_kickoff(struct drm_encoder *encoder); + +/** + * dpu_encoder_wakeup_time - get the time of the next vsync + */ +int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time); /** * dpu_encoder_wait_for_event - Waits for encoder events 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 1b3ab909f367..39e1e280ba44 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 @@ -45,8 +45,7 @@ static bool dpu_encoder_phys_cmd_mode_fixup( const struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { - if (phys_enc) - DPU_DEBUG_CMDENC(to_dpu_encoder_phys_cmd(phys_enc), "\n"); + DPU_DEBUG_CMDENC(to_dpu_encoder_phys_cmd(phys_enc), "\n"); return true; } @@ -58,11 +57,8 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg( struct dpu_hw_ctl *ctl; struct dpu_hw_intf_cfg intf_cfg = { 0 }; - if (!phys_enc) - return; - ctl = phys_enc->hw_ctl; - if (!ctl || !ctl->ops.setup_intf_cfg) + if (!ctl->ops.setup_intf_cfg) return; intf_cfg.intf = phys_enc->intf_idx; @@ -79,7 +75,7 @@ static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) int new_cnt; u32 event = DPU_ENCODER_FRAME_EVENT_DONE; - if (!phys_enc || !phys_enc->hw_pp) + if (!phys_enc->hw_pp) return; DPU_ATRACE_BEGIN("pp_done_irq"); @@ -106,7 +102,7 @@ static void dpu_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx) struct dpu_encoder_phys *phys_enc = arg; struct dpu_encoder_phys_cmd *cmd_enc; - if (!phys_enc || !phys_enc->hw_pp) + if (!phys_enc->hw_pp) return; DPU_ATRACE_BEGIN("rd_ptr_irq"); @@ -124,13 +120,8 @@ static void dpu_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx) static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx) { struct dpu_encoder_phys *phys_enc = arg; - struct dpu_encoder_phys_cmd *cmd_enc; - - if (!phys_enc || !phys_enc->hw_ctl) - return; DPU_ATRACE_BEGIN("ctl_start_irq"); - cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0); @@ -143,9 +134,6 @@ static void dpu_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx) { struct dpu_encoder_phys *phys_enc = arg; - if (!phys_enc) - return; - if (phys_enc->parent_ops->handle_underrun_virt) phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent, phys_enc); @@ -181,7 +169,7 @@ static void dpu_encoder_phys_cmd_mode_set( struct dpu_encoder_phys_cmd *cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - if (!phys_enc || !mode || !adj_mode) { + if (!mode || !adj_mode) { DPU_ERROR("invalid args\n"); return; } @@ -200,7 +188,7 @@ static int _dpu_encoder_phys_cmd_handle_ppdone_timeout( u32 frame_event = DPU_ENCODER_FRAME_EVENT_ERROR; bool do_log = false; - if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl) + if (!phys_enc->hw_pp) return -EINVAL; cmd_enc->pp_timeout_report_cnt++; @@ -249,11 +237,6 @@ static int _dpu_encoder_phys_cmd_wait_for_idle( struct dpu_encoder_wait_info wait_info; int ret; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return -EINVAL; - } - wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; @@ -275,7 +258,7 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( int ret = 0; int refcount; - if (!phys_enc || !phys_enc->hw_pp) { + if (!phys_enc->hw_pp) { DPU_ERROR("invalid encoder\n"); return -EINVAL; } @@ -316,13 +299,6 @@ end: static void dpu_encoder_phys_cmd_irq_control(struct dpu_encoder_phys *phys_enc, bool enable) { - struct dpu_encoder_phys_cmd *cmd_enc; - - if (!phys_enc) - return; - - cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - trace_dpu_enc_phys_cmd_irq_ctrl(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, enable, atomic_read(&phys_enc->vblank_refcount)); @@ -355,10 +331,9 @@ static void dpu_encoder_phys_cmd_tearcheck_config( struct drm_display_mode *mode; bool tc_enable = true; u32 vsync_hz; - struct msm_drm_private *priv; struct dpu_kms *dpu_kms; - if (!phys_enc || !phys_enc->hw_pp) { + if (!phys_enc->hw_pp) { DPU_ERROR("invalid encoder\n"); return; } @@ -373,11 +348,6 @@ static void dpu_encoder_phys_cmd_tearcheck_config( } dpu_kms = phys_enc->dpu_kms; - if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev_private) { - DPU_ERROR("invalid device\n"); - return; - } - priv = dpu_kms->dev->dev_private; /* * TE default: dsi byte clock calculated base on 70 fps; @@ -440,8 +410,7 @@ static void _dpu_encoder_phys_cmd_pingpong_config( struct dpu_encoder_phys_cmd *cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp - || !phys_enc->hw_ctl->ops.setup_intf_cfg) { + if (!phys_enc->hw_pp || !phys_enc->hw_ctl->ops.setup_intf_cfg) { DPU_ERROR("invalid arg(s), enc %d\n", phys_enc != 0); return; } @@ -470,7 +439,7 @@ static void dpu_encoder_phys_cmd_enable_helper( struct dpu_hw_ctl *ctl; u32 flush_mask = 0; - if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp) { + if (!phys_enc->hw_pp) { DPU_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0); return; } @@ -492,7 +461,7 @@ static void dpu_encoder_phys_cmd_enable(struct dpu_encoder_phys *phys_enc) struct dpu_encoder_phys_cmd *cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - if (!phys_enc || !phys_enc->hw_pp) { + if (!phys_enc->hw_pp) { DPU_ERROR("invalid phys encoder\n"); return; } @@ -511,8 +480,7 @@ static void dpu_encoder_phys_cmd_enable(struct dpu_encoder_phys *phys_enc) static void _dpu_encoder_phys_cmd_connect_te( struct dpu_encoder_phys *phys_enc, bool enable) { - if (!phys_enc || !phys_enc->hw_pp || - !phys_enc->hw_pp->ops.connect_external_te) + if (!phys_enc->hw_pp || !phys_enc->hw_pp->ops.connect_external_te) return; trace_dpu_enc_phys_cmd_connect_te(DRMID(phys_enc->parent), enable); @@ -530,7 +498,7 @@ static int dpu_encoder_phys_cmd_get_line_count( { struct dpu_hw_pingpong *hw_pp; - if (!phys_enc || !phys_enc->hw_pp) + if (!phys_enc->hw_pp) return -EINVAL; if (!dpu_encoder_phys_cmd_is_master(phys_enc)) @@ -548,7 +516,7 @@ static void dpu_encoder_phys_cmd_disable(struct dpu_encoder_phys *phys_enc) struct dpu_encoder_phys_cmd *cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - if (!phys_enc || !phys_enc->hw_pp) { + if (!phys_enc->hw_pp) { DPU_ERROR("invalid encoder\n"); return; } @@ -571,10 +539,6 @@ static void dpu_encoder_phys_cmd_destroy(struct dpu_encoder_phys *phys_enc) struct dpu_encoder_phys_cmd *cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } kfree(cmd_enc); } @@ -592,7 +556,7 @@ static void dpu_encoder_phys_cmd_prepare_for_kickoff( to_dpu_encoder_phys_cmd(phys_enc); int ret; - if (!phys_enc || !phys_enc->hw_pp) { + if (!phys_enc->hw_pp) { DPU_ERROR("invalid encoder\n"); return; } @@ -626,11 +590,6 @@ static int _dpu_encoder_phys_cmd_wait_for_ctl_start( struct dpu_encoder_wait_info wait_info; int ret; - if (!phys_enc || !phys_enc->hw_ctl) { - DPU_ERROR("invalid argument(s)\n"); - return -EINVAL; - } - wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_ctlstart_cnt; wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; @@ -650,12 +609,6 @@ static int dpu_encoder_phys_cmd_wait_for_tx_complete( struct dpu_encoder_phys *phys_enc) { int rc; - struct dpu_encoder_phys_cmd *cmd_enc; - - if (!phys_enc) - return -EINVAL; - - cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); rc = _dpu_encoder_phys_cmd_wait_for_idle(phys_enc); if (rc) { @@ -673,9 +626,6 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( int rc = 0; struct dpu_encoder_phys_cmd *cmd_enc; - if (!phys_enc) - return -EINVAL; - cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); /* only required for master controller */ @@ -696,9 +646,6 @@ static int dpu_encoder_phys_cmd_wait_for_vblank( struct dpu_encoder_phys_cmd *cmd_enc; struct dpu_encoder_wait_info wait_info; - if (!phys_enc) - return -EINVAL; - cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); /* only required for master controller */ @@ -720,9 +667,6 @@ static int dpu_encoder_phys_cmd_wait_for_vblank( static void dpu_encoder_phys_cmd_handle_post_kickoff( struct dpu_encoder_phys *phys_enc) { - if (!phys_enc) - return; - /** * re-enable external TE, either for the first time after enabling * or if disabled for Autorefresh @@ -733,9 +677,6 @@ static void dpu_encoder_phys_cmd_handle_post_kickoff( static void dpu_encoder_phys_cmd_trigger_start( struct dpu_encoder_phys *phys_enc) { - if (!phys_enc) - return; - dpu_encoder_helper_trigger_start(phys_enc); } @@ -834,6 +775,4 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( DPU_DEBUG_CMDENC(cmd_enc, "created\n"); return phys_enc; - - return ERR_PTR(ret); } 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 5055a5eec869..c71c18de5966 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 @@ -220,8 +220,7 @@ static bool dpu_encoder_phys_vid_mode_fixup( const struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { - if (phys_enc) - DPU_DEBUG_VIDENC(phys_enc, "\n"); + DPU_DEBUG_VIDENC(phys_enc, "\n"); /* * Modifying mode has consequences when the mode comes back to us @@ -239,7 +238,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine( unsigned long lock_flags; struct dpu_hw_intf_cfg intf_cfg = { 0 }; - if (!phys_enc || !phys_enc->hw_ctl->ops.setup_intf_cfg) { + if (!phys_enc->hw_ctl->ops.setup_intf_cfg) { DPU_ERROR("invalid encoder %d\n", phys_enc != 0); return; } @@ -280,6 +279,14 @@ static void dpu_encoder_phys_vid_setup_timing_engine( phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, &timing_params, fmt); phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg); + + /* setup which pp blk will connect to this intf */ + if (phys_enc->hw_intf->ops.bind_pingpong_blk) + phys_enc->hw_intf->ops.bind_pingpong_blk( + phys_enc->hw_intf, + true, + phys_enc->hw_pp->idx); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); programmable_fetch_config(phys_enc, &timing_params); @@ -293,12 +300,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) u32 flush_register = 0; int new_cnt = -1, old_cnt = -1; - if (!phys_enc) - return; - hw_ctl = phys_enc->hw_ctl; - if (!hw_ctl) - return; DPU_ATRACE_BEGIN("vblank_irq"); @@ -314,7 +316,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) * so we need to double-check with hw that it accepted the flush bits */ spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); - if (hw_ctl && hw_ctl->ops.get_flush_register) + if (hw_ctl->ops.get_flush_register) flush_register = hw_ctl->ops.get_flush_register(hw_ctl); if (!(flush_register & hw_ctl->ops.get_pending_flush(hw_ctl))) @@ -324,6 +326,10 @@ 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_EVENT_DONE); + DPU_ATRACE_END("vblank_irq"); } @@ -331,9 +337,6 @@ static void dpu_encoder_phys_vid_underrun_irq(void *arg, int irq_idx) { struct dpu_encoder_phys *phys_enc = arg; - if (!phys_enc) - return; - if (phys_enc->parent_ops->handle_underrun_virt) phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent, phys_enc); @@ -370,11 +373,6 @@ static void dpu_encoder_phys_vid_mode_set( struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { - if (!phys_enc || !phys_enc->dpu_kms) { - DPU_ERROR("invalid encoder/kms\n"); - return; - } - if (adj_mode) { phys_enc->cached_mode = *adj_mode; drm_mode_debug_printmodeline(adj_mode); @@ -391,11 +389,6 @@ static int dpu_encoder_phys_vid_control_vblank_irq( int ret = 0; int refcount; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return -EINVAL; - } - refcount = atomic_read(&phys_enc->vblank_refcount); /* Slave encoders don't report vblank */ @@ -431,6 +424,7 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc) { struct dpu_hw_ctl *ctl; u32 flush_mask = 0; + u32 intf_flush_mask = 0; ctl = phys_enc->hw_ctl; @@ -455,10 +449,18 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc) ctl->ops.get_bitmask_intf(ctl, &flush_mask, phys_enc->hw_intf->idx); ctl->ops.update_pending_flush(ctl, flush_mask); + if (ctl->ops.get_bitmask_active_intf) + ctl->ops.get_bitmask_active_intf(ctl, &intf_flush_mask, + phys_enc->hw_intf->idx); + + if (ctl->ops.update_pending_intf_flush) + ctl->ops.update_pending_intf_flush(ctl, intf_flush_mask); + skip_flush: DPU_DEBUG_VIDENC(phys_enc, - "update pending flush ctl %d flush_mask %x\n", - ctl->idx - CTL_0, flush_mask); + "update pending flush ctl %d flush_mask 0%x intf_mask 0x%x\n", + ctl->idx - CTL_0, flush_mask, intf_flush_mask); + /* ctl_flush & timing engine enable will be triggered by framework */ if (phys_enc->enable_state == DPU_ENC_DISABLED) @@ -467,11 +469,6 @@ skip_flush: static void dpu_encoder_phys_vid_destroy(struct dpu_encoder_phys *phys_enc) { - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - DPU_DEBUG_VIDENC(phys_enc, "\n"); kfree(phys_enc); } @@ -483,26 +480,17 @@ static void dpu_encoder_phys_vid_get_hw_resources( hw_res->intfs[phys_enc->intf_idx - INTF_0] = INTF_MODE_VIDEO; } -static int _dpu_encoder_phys_vid_wait_for_vblank( - struct dpu_encoder_phys *phys_enc, bool notify) +static int dpu_encoder_phys_vid_wait_for_vblank( + struct dpu_encoder_phys *phys_enc) { struct dpu_encoder_wait_info wait_info; int ret; - if (!phys_enc) { - pr_err("invalid encoder\n"); - return -EINVAL; - } - wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; if (!dpu_encoder_phys_vid_is_master(phys_enc)) { - if (notify && phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done( - phys_enc->parent, phys_enc, - DPU_ENCODER_FRAME_EVENT_DONE); return 0; } @@ -512,18 +500,29 @@ static int _dpu_encoder_phys_vid_wait_for_vblank( if (ret == -ETIMEDOUT) { dpu_encoder_helper_report_irq_timeout(phys_enc, INTR_IDX_VSYNC); - } else if (!ret && notify && phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done( - phys_enc->parent, phys_enc, - DPU_ENCODER_FRAME_EVENT_DONE); + } return ret; } -static int dpu_encoder_phys_vid_wait_for_vblank( +static int dpu_encoder_phys_vid_wait_for_commit_done( struct dpu_encoder_phys *phys_enc) { - return _dpu_encoder_phys_vid_wait_for_vblank(phys_enc, true); + struct dpu_hw_ctl *hw_ctl = phys_enc->hw_ctl; + int ret; + + if (!hw_ctl) + return 0; + + ret = wait_event_timeout(phys_enc->pending_kickoff_wq, + (hw_ctl->ops.get_flush_register(hw_ctl) == 0), + msecs_to_jiffies(50)); + if (ret <= 0) { + DPU_ERROR("vblank timeout\n"); + return -ETIMEDOUT; + } + + return 0; } static void dpu_encoder_phys_vid_prepare_for_kickoff( @@ -532,13 +531,8 @@ static void dpu_encoder_phys_vid_prepare_for_kickoff( struct dpu_hw_ctl *ctl; int rc; - if (!phys_enc) { - DPU_ERROR("invalid encoder/parameters\n"); - return; - } - ctl = phys_enc->hw_ctl; - if (!ctl || !ctl->ops.wait_reset_status) + if (!ctl->ops.wait_reset_status) return; /* @@ -555,18 +549,15 @@ static void dpu_encoder_phys_vid_prepare_for_kickoff( static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) { - struct msm_drm_private *priv; unsigned long lock_flags; int ret; - if (!phys_enc || !phys_enc->parent || !phys_enc->parent->dev || - !phys_enc->parent->dev->dev_private) { + if (!phys_enc->parent || !phys_enc->parent->dev) { DPU_ERROR("invalid encoder/device\n"); return; } - priv = phys_enc->parent->dev->dev_private; - if (!phys_enc->hw_intf || !phys_enc->hw_ctl) { + if (!phys_enc->hw_intf) { DPU_ERROR("invalid hw_intf %d hw_ctl %d\n", phys_enc->hw_intf != 0, phys_enc->hw_ctl != 0); return; @@ -595,7 +586,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) * scanout buffer) don't latch properly.. */ if (dpu_encoder_phys_vid_is_master(phys_enc)) { - ret = _dpu_encoder_phys_vid_wait_for_vblank(phys_enc, false); + ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc); if (ret) { atomic_set(&phys_enc->pending_kickoff_cnt, 0); DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", @@ -612,11 +603,6 @@ static void dpu_encoder_phys_vid_handle_post_kickoff( { unsigned long lock_flags; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - /* * Video mode must flush CTL before enabling timing engine * Video encoders need to turn on their interfaces now @@ -636,9 +622,6 @@ static void dpu_encoder_phys_vid_irq_control(struct dpu_encoder_phys *phys_enc, { int ret; - if (!phys_enc) - return; - trace_dpu_enc_phys_vid_irq_ctrl(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, enable, @@ -659,9 +642,6 @@ static void dpu_encoder_phys_vid_irq_control(struct dpu_encoder_phys *phys_enc, static int dpu_encoder_phys_vid_get_line_count( struct dpu_encoder_phys *phys_enc) { - if (!phys_enc) - return -EINVAL; - if (!dpu_encoder_phys_vid_is_master(phys_enc)) return -EINVAL; @@ -681,7 +661,7 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->destroy = dpu_encoder_phys_vid_destroy; ops->get_hw_resources = dpu_encoder_phys_vid_get_hw_resources; ops->control_vblank_irq = dpu_encoder_phys_vid_control_vblank_irq; - ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_vblank; + ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_commit_done; ops->wait_for_vblank = dpu_encoder_phys_vid_wait_for_vblank; ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_vblank; ops->irq_control = dpu_encoder_phys_vid_irq_control; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c index 24ab6249083a..528632690f1e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -489,12 +489,28 @@ static const struct dpu_format dpu_format_map_ubwc[] = { true, 4, DPU_FORMAT_FLAG_COMPRESSED, DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + /* ARGB8888 and ABGR8888 purposely have the same color + * ordering. The hardware only supports ABGR8888 UBWC + * natively. + */ + INTERLEAVED_RGB_FMT_TILED(ARGB8888, + 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_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + INTERLEAVED_RGB_FMT_TILED(XBGR8888, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, false, 4, DPU_FORMAT_FLAG_COMPRESSED, DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + INTERLEAVED_RGB_FMT_TILED(XRGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + INTERLEAVED_RGB_FMT_TILED(ABGR2101010, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, @@ -550,7 +566,9 @@ static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt) { static const struct dpu_media_color_map dpu_media_ubwc_map[] = { {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC}, + {DRM_FORMAT_ARGB8888, COLOR_FMT_RGBA8888_UBWC}, {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, + {DRM_FORMAT_XRGB8888, COLOR_FMT_RGBA8888_UBWC}, {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_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 04c8c44f5b9c..c567917541e8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -11,11 +11,17 @@ #include "dpu_hw_catalog_format.h" #include "dpu_kms.h" -#define VIG_SDM845_MASK \ - (BIT(DPU_SSPP_SRC) | BIT(DPU_SSPP_SCALER_QSEED3) | BIT(DPU_SSPP_QOS) |\ +#define VIG_MASK \ + (BIT(DPU_SSPP_SRC) | BIT(DPU_SSPP_QOS) |\ BIT(DPU_SSPP_CSC_10BIT) | BIT(DPU_SSPP_CDP) | BIT(DPU_SSPP_QOS_8LVL) |\ BIT(DPU_SSPP_TS_PREFILL) | BIT(DPU_SSPP_EXCL_RECT)) +#define VIG_SDM845_MASK \ + (VIG_MASK | BIT(DPU_SSPP_SCALER_QSEED3)) + +#define VIG_SC7180_MASK \ + (VIG_MASK | BIT(DPU_SSPP_SCALER_QSEED4)) + #define DMA_SDM845_MASK \ (BIT(DPU_SSPP_SRC) | BIT(DPU_SSPP_QOS) | BIT(DPU_SSPP_QOS_8LVL) |\ BIT(DPU_SSPP_TS_PREFILL) | BIT(DPU_SSPP_TS_PREFILL_REC1) |\ @@ -27,6 +33,9 @@ #define MIXER_SDM845_MASK \ (BIT(DPU_MIXER_SOURCESPLIT) | BIT(DPU_DIM_LAYER)) +#define MIXER_SC7180_MASK \ + (BIT(DPU_DIM_LAYER)) + #define PINGPONG_SDM845_MASK BIT(DPU_PINGPONG_DITHER) #define PINGPONG_SDM845_SPLIT_MASK \ @@ -58,9 +67,20 @@ static const struct dpu_caps sdm845_dpu_caps = { .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, + .has_3d_merge = true, +}; + +static const struct dpu_caps sc7180_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0x9, + .qseed_type = DPU_SSPP_SCALER_QSEED4, + .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, + .ubwc_version = DPU_HW_UBWC_VER_20, + .has_dim_layer = true, + .has_idle_pc = true, }; -static struct dpu_mdp_cfg sdm845_mdp[] = { +static const struct dpu_mdp_cfg sdm845_mdp[] = { { .name = "top_0", .id = MDP_TOP, .base = 0x0, .len = 0x45C, @@ -85,10 +105,27 @@ static struct dpu_mdp_cfg sdm845_mdp[] = { }, }; +static const struct dpu_mdp_cfg sc7180_mdp[] = { + { + .name = "top_0", .id = MDP_TOP, + .base = 0x0, .len = 0x494, + .features = 0, + .highest_bank_bit = 0x3, + .clk_ctrls[DPU_CLK_CTRL_VIG0] = { + .reg_off = 0x2AC, .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}, + }, +}; + /************************************************************* * CTL sub blocks config *************************************************************/ -static struct dpu_ctl_cfg sdm845_ctl[] = { +static const struct dpu_ctl_cfg sdm845_ctl[] = { { .name = "ctl_0", .id = CTL_0, .base = 0x1000, .len = 0xE4, @@ -116,6 +153,24 @@ static struct dpu_ctl_cfg sdm845_ctl[] = { }, }; +static const struct dpu_ctl_cfg sc7180_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0xE4, + .features = BIT(DPU_CTL_ACTIVE_CFG) + }, + { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0xE4, + .features = BIT(DPU_CTL_ACTIVE_CFG) + }, + { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0xE4, + .features = BIT(DPU_CTL_ACTIVE_CFG) + }, +}; + /************************************************************* * SSPP sub blocks config *************************************************************/ @@ -128,7 +183,7 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = { .maxvdeciexp = MAX_VERT_DECIMATION, }; -#define _VIG_SBLK(num, sdma_pri) \ +#define _VIG_SBLK(num, sdma_pri, qseed_ver) \ { \ .common = &sdm845_sspp_common, \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ @@ -137,7 +192,7 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = { .src_blk = {.name = STRCAT("sspp_src_", num), \ .id = DPU_SSPP_SRC, .base = 0x00, .len = 0x150,}, \ .scaler_blk = {.name = STRCAT("sspp_scaler", num), \ - .id = DPU_SSPP_SCALER_QSEED3, \ + .id = qseed_ver, \ .base = 0xa00, .len = 0xa0,}, \ .csc_blk = {.name = STRCAT("sspp_csc", num), \ .id = DPU_SSPP_CSC_10BIT, \ @@ -162,10 +217,14 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = { .virt_num_formats = ARRAY_SIZE(plane_formats), \ } -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = _VIG_SBLK("0", 5); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = _VIG_SBLK("1", 6); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = _VIG_SBLK("2", 7); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = _VIG_SBLK("3", 8); +static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = + _VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED3); +static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = + _VIG_SBLK("1", 6, DPU_SSPP_SCALER_QSEED3); +static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = + _VIG_SBLK("2", 7, DPU_SSPP_SCALER_QSEED3); +static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = + _VIG_SBLK("3", 8, DPU_SSPP_SCALER_QSEED3); static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK("8", 1); static const struct dpu_sspp_sub_blks sdm845_dma_sblk_1 = _DMA_SBLK("9", 2); @@ -184,7 +243,7 @@ static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK("11", 4); .clk_ctrl = _clkctrl \ } -static struct dpu_sspp_cfg sdm845_sspp[] = { +static const struct dpu_sspp_cfg sdm845_sspp[] = { SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SDM845_MASK, sdm845_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0), SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SDM845_MASK, @@ -203,9 +262,26 @@ static struct dpu_sspp_cfg sdm845_sspp[] = { sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1), }; +static const struct dpu_sspp_sub_blks sc7180_vig_sblk_0 = + _VIG_SBLK("0", 4, DPU_SSPP_SCALER_QSEED4); + +static const struct dpu_sspp_cfg sc7180_sspp[] = { + SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SC7180_MASK, + sc7180_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), + 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), +}; + /************************************************************* * MIXER sub blocks config *************************************************************/ + +/* SDM845 */ + static const struct dpu_lm_sub_blks sdm845_lm_sblk = { .maxwidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .maxblendstages = 11, /* excluding base layer */ @@ -215,23 +291,46 @@ static const struct dpu_lm_sub_blks sdm845_lm_sblk = { }, }; -#define LM_BLK(_name, _id, _base, _pp, _lmpair) \ +#define LM_BLK(_name, _id, _base, _fmask, _sblk, _pp, _lmpair) \ { \ .name = _name, .id = _id, \ .base = _base, .len = 0x320, \ - .features = MIXER_SDM845_MASK, \ - .sblk = &sdm845_lm_sblk, \ + .features = _fmask, \ + .sblk = _sblk, \ .pingpong = _pp, \ .lm_pair_mask = (1 << _lmpair) \ } -static struct dpu_lm_cfg sdm845_lm[] = { - LM_BLK("lm_0", LM_0, 0x44000, PINGPONG_0, LM_1), - LM_BLK("lm_1", LM_1, 0x45000, PINGPONG_1, LM_0), - LM_BLK("lm_2", LM_2, 0x46000, PINGPONG_2, LM_5), - LM_BLK("lm_3", LM_3, 0x0, PINGPONG_MAX, 0), - LM_BLK("lm_4", LM_4, 0x0, PINGPONG_MAX, 0), - LM_BLK("lm_5", LM_5, 0x49000, PINGPONG_3, LM_2), +static const struct dpu_lm_cfg sdm845_lm[] = { + LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK, + &sdm845_lm_sblk, PINGPONG_0, LM_1), + LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK, + &sdm845_lm_sblk, PINGPONG_1, LM_0), + LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK, + &sdm845_lm_sblk, PINGPONG_2, LM_5), + LM_BLK("lm_3", LM_3, 0x0, MIXER_SDM845_MASK, + &sdm845_lm_sblk, PINGPONG_MAX, 0), + LM_BLK("lm_4", LM_4, 0x0, MIXER_SDM845_MASK, + &sdm845_lm_sblk, PINGPONG_MAX, 0), + LM_BLK("lm_5", LM_5, 0x49000, MIXER_SDM845_MASK, + &sdm845_lm_sblk, PINGPONG_3, LM_2), +}; + +/* SC7180 */ + +static const struct dpu_lm_sub_blks sc7180_lm_sblk = { + .maxwidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .maxblendstages = 7, /* excluding base layer */ + .blendstage_base = { /* offsets relative to mixer base */ + 0x20, 0x38, 0x50, 0x68, 0x80, 0x98, 0xb0 + }, +}; + +static const struct dpu_lm_cfg sc7180_lm[] = { + LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK, + &sc7180_lm_sblk, PINGPONG_0, LM_1), + LM_BLK("lm_1", LM_1, 0x45000, MIXER_SC7180_MASK, + &sc7180_lm_sblk, PINGPONG_1, LM_0), }; /************************************************************* @@ -264,13 +363,18 @@ static const struct dpu_pingpong_sub_blks sdm845_pp_sblk = { .sblk = &sdm845_pp_sblk \ } -static struct dpu_pingpong_cfg sdm845_pp[] = { +static const struct dpu_pingpong_cfg sdm845_pp[] = { PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000), PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800), PP_BLK("pingpong_2", PINGPONG_2, 0x71000), PP_BLK("pingpong_3", PINGPONG_3, 0x71800), }; +static struct dpu_pingpong_cfg sc7180_pp[] = { + PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000), + PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800), +}; + /************************************************************* * INTF sub blocks config *************************************************************/ @@ -278,26 +382,32 @@ static struct dpu_pingpong_cfg sdm845_pp[] = { {\ .name = _name, .id = _id, \ .base = _base, .len = 0x280, \ + .features = BIT(DPU_CTL_ACTIVE_CFG), \ .type = _type, \ .controller_id = _ctrl_id, \ .prog_fetch_lines_worst_case = 24 \ } -static struct dpu_intf_cfg sdm845_intf[] = { +static const struct dpu_intf_cfg sdm845_intf[] = { INTF_BLK("intf_0", INTF_0, 0x6A000, INTF_DP, 0), INTF_BLK("intf_1", INTF_1, 0x6A800, INTF_DSI, 0), INTF_BLK("intf_2", INTF_2, 0x6B000, INTF_DSI, 1), INTF_BLK("intf_3", INTF_3, 0x6B800, INTF_DP, 1), }; +static const struct dpu_intf_cfg sc7180_intf[] = { + INTF_BLK("intf_0", INTF_0, 0x6A000, INTF_DP, 0), + INTF_BLK("intf_1", INTF_1, 0x6A800, INTF_DSI, 0), +}; + /************************************************************* * VBIF sub blocks config *************************************************************/ /* VBIF QOS remap */ -static u32 sdm845_rt_pri_lvl[] = {3, 3, 4, 4, 5, 5, 6, 6}; -static u32 sdm845_nrt_pri_lvl[] = {3, 3, 3, 3, 3, 3, 3, 3}; +static const u32 sdm845_rt_pri_lvl[] = {3, 3, 4, 4, 5, 5, 6, 6}; +static const u32 sdm845_nrt_pri_lvl[] = {3, 3, 3, 3, 3, 3, 3, 3}; -static struct dpu_vbif_cfg sdm845_vbif[] = { +static const struct dpu_vbif_cfg sdm845_vbif[] = { { .name = "vbif_0", .id = VBIF_0, .base = 0, .len = 0x1040, @@ -316,7 +426,7 @@ static struct dpu_vbif_cfg sdm845_vbif[] = { }, }; -static struct dpu_reg_dma_cfg sdm845_regdma = { +static const struct dpu_reg_dma_cfg sdm845_regdma = { .base = 0x0, .version = 0x1, .trigger_sel_off = 0x119c }; @@ -325,7 +435,7 @@ static struct dpu_reg_dma_cfg sdm845_regdma = { *************************************************************/ /* SSPP QOS LUTs */ -static struct dpu_qos_lut_entry sdm845_qos_linear[] = { +static const struct dpu_qos_lut_entry sdm845_qos_linear[] = { {.fl = 4, .lut = 0x357}, {.fl = 5, .lut = 0x3357}, {.fl = 6, .lut = 0x23357}, @@ -340,7 +450,11 @@ static struct dpu_qos_lut_entry sdm845_qos_linear[] = { {.fl = 0, .lut = 0x11222222223357} }; -static struct dpu_qos_lut_entry sdm845_qos_macrotile[] = { +static const struct dpu_qos_lut_entry sc7180_qos_linear[] = { + {.fl = 0, .lut = 0x0011222222335777}, +}; + +static const struct dpu_qos_lut_entry sdm845_qos_macrotile[] = { {.fl = 10, .lut = 0x344556677}, {.fl = 11, .lut = 0x3344556677}, {.fl = 12, .lut = 0x23344556677}, @@ -349,11 +463,19 @@ static struct dpu_qos_lut_entry sdm845_qos_macrotile[] = { {.fl = 0, .lut = 0x112233344556677}, }; -static struct dpu_qos_lut_entry sdm845_qos_nrt[] = { +static const struct dpu_qos_lut_entry sc7180_qos_macrotile[] = { + {.fl = 0, .lut = 0x0011223344556677}, +}; + +static const struct dpu_qos_lut_entry sdm845_qos_nrt[] = { + {.fl = 0, .lut = 0x0}, +}; + +static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { {.fl = 0, .lut = 0x0}, }; -static struct dpu_perf_cfg sdm845_perf_data = { +static const struct dpu_perf_cfg sdm845_perf_data = { .max_bw_low = 6800000, .max_bw_high = 6800000, .min_core_ib = 2400000, @@ -392,6 +514,30 @@ static struct dpu_perf_cfg sdm845_perf_data = { }, }; +static const struct dpu_perf_cfg sc7180_perf_data = { + .max_bw_low = 3900000, + .max_bw_high = 5500000, + .min_core_ib = 2400000, + .min_llcc_ib = 800000, + .min_dram_ib = 800000, + .danger_lut_tbl = {0xff, 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 + }, + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, +}; + /************************************************************* * Hardware catalog init *************************************************************/ @@ -421,12 +567,43 @@ static void sdm845_cfg_init(struct dpu_mdss_cfg *dpu_cfg) .reg_dma_count = 1, .dma_cfg = sdm845_regdma, .perf = sdm845_perf_data, + .mdss_irqs = 0x3ff, + }; +} + +/* + * sc7180_cfg_init(): populate sc7180 dpu sub-blocks reg offsets + * and instance counts. + */ +static void sc7180_cfg_init(struct dpu_mdss_cfg *dpu_cfg) +{ + *dpu_cfg = (struct dpu_mdss_cfg){ + .caps = &sc7180_dpu_caps, + .mdp_count = ARRAY_SIZE(sc7180_mdp), + .mdp = sc7180_mdp, + .ctl_count = ARRAY_SIZE(sc7180_ctl), + .ctl = sc7180_ctl, + .sspp_count = ARRAY_SIZE(sc7180_sspp), + .sspp = sc7180_sspp, + .mixer_count = ARRAY_SIZE(sc7180_lm), + .mixer = sc7180_lm, + .pingpong_count = ARRAY_SIZE(sc7180_pp), + .pingpong = sc7180_pp, + .intf_count = ARRAY_SIZE(sc7180_intf), + .intf = sc7180_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .reg_dma_count = 1, + .dma_cfg = sdm845_regdma, + .perf = sc7180_perf_data, + .mdss_irqs = 0x3f, }; } -static struct dpu_mdss_hw_cfg_handler cfg_handler[] = { +static const struct dpu_mdss_hw_cfg_handler cfg_handler[] = { { .hw_rev = DPU_HW_VER_400, .cfg_init = sdm845_cfg_init}, { .hw_rev = DPU_HW_VER_401, .cfg_init = sdm845_cfg_init}, + { .hw_rev = DPU_HW_VER_620, .cfg_init = sc7180_cfg_init}, }; void dpu_hw_catalog_deinit(struct dpu_mdss_cfg *dpu_cfg) 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 90f439812088..09df7d87dd43 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -9,7 +9,6 @@ #include <linux/bug.h> #include <linux/bitmap.h> #include <linux/err.h> -#include <drm/drmP.h> /** * Max hardware block count: For ex: max 12 SSPP pipes or @@ -39,6 +38,7 @@ #define DPU_HW_VER_401 DPU_HW_VER(4, 0, 1) /* sdm845 v2.0 */ #define DPU_HW_VER_410 DPU_HW_VER(4, 1, 0) /* sdm670 v1.0 */ #define DPU_HW_VER_500 DPU_HW_VER(5, 0, 0) /* sdm855 v1.0 */ +#define DPU_HW_VER_620 DPU_HW_VER(6, 2, 0) /* sc7180 v1.0 */ #define IS_MSM8996_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_170) @@ -46,6 +46,7 @@ #define IS_SDM845_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_400) #define IS_SDM670_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_410) #define IS_SDM855_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_500) +#define IS_SC7180_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_620) #define DPU_HW_BLK_NAME_LEN 16 @@ -93,6 +94,7 @@ enum { * @DPU_SSPP_SRC Src and fetch part of the pipes, * @DPU_SSPP_SCALER_QSEED2, QSEED2 algorithm support * @DPU_SSPP_SCALER_QSEED3, QSEED3 alogorithm support + * @DPU_SSPP_SCALER_QSEED4, QSEED4 algorithm support * @DPU_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes * @DPU_SSPP_CSC, Support of Color space converion * @DPU_SSPP_CSC_10BIT, Support of 10-bit Color space conversion @@ -111,6 +113,7 @@ enum { DPU_SSPP_SRC = 0x1, DPU_SSPP_SCALER_QSEED2, DPU_SSPP_SCALER_QSEED3, + DPU_SSPP_SCALER_QSEED4, DPU_SSPP_SCALER_RGB, DPU_SSPP_CSC, DPU_SSPP_CSC_10BIT, @@ -167,6 +170,7 @@ enum { */ enum { DPU_CTL_SPLIT_DISPLAY = 0x1, + DPU_CTL_ACTIVE_CFG, DPU_CTL_MAX }; @@ -270,7 +274,7 @@ struct dpu_qos_lut_entry { */ struct dpu_qos_lut_tbl { u32 nentry; - struct dpu_qos_lut_entry *entries; + const struct dpu_qos_lut_entry *entries; }; /** @@ -284,6 +288,7 @@ struct dpu_qos_lut_tbl { * @has_src_split source split feature status * @has_dim_layer dim layer feature status * @has_idle_pc indicate if idle power collapse feature is supported + * @has_3d_merge indicate if 3D merge is supported */ struct dpu_caps { u32 max_mixer_width; @@ -294,6 +299,7 @@ struct dpu_caps { bool has_src_split; bool has_dim_layer; bool has_idle_pc; + bool has_3d_merge; }; /** @@ -321,6 +327,7 @@ struct dpu_sspp_blks_common { * @maxupscale: maxupscale ratio supported * @smart_dma_priority: hw priority of rect1 of multirect pipe * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps + * @qseed_ver: qseed version * @src_blk: * @scaler_blk: * @csc_blk: @@ -341,6 +348,7 @@ struct dpu_sspp_sub_blks { u32 maxupscale; u32 smart_dma_priority; u32 max_per_pipe_bw; + u32 qseed_ver; struct dpu_src_blk src_blk; struct dpu_scaler_blk scaler_blk; struct dpu_pp_blk csc_blk; @@ -512,7 +520,7 @@ struct dpu_vbif_dynamic_ot_cfg { */ struct dpu_vbif_dynamic_ot_tbl { u32 count; - struct dpu_vbif_dynamic_ot_cfg *cfg; + const struct dpu_vbif_dynamic_ot_cfg *cfg; }; /** @@ -522,7 +530,7 @@ struct dpu_vbif_dynamic_ot_tbl { */ struct dpu_vbif_qos_tbl { u32 npriority_lvl; - u32 *priority_lvl; + const u32 *priority_lvl; }; /** @@ -647,6 +655,7 @@ struct dpu_perf_cfg { * @dma_formats Supported formats for dma pipe * @cursor_formats Supported formats for cursor pipe * @vig_formats Supported formats for vig pipe + * @mdss_irqs: Bitmap with the irqs supported by the target */ struct dpu_mdss_cfg { u32 hwversion; @@ -654,25 +663,25 @@ struct dpu_mdss_cfg { const struct dpu_caps *caps; u32 mdp_count; - struct dpu_mdp_cfg *mdp; + const struct dpu_mdp_cfg *mdp; u32 ctl_count; - struct dpu_ctl_cfg *ctl; + const struct dpu_ctl_cfg *ctl; u32 sspp_count; - struct dpu_sspp_cfg *sspp; + const struct dpu_sspp_cfg *sspp; u32 mixer_count; - struct dpu_lm_cfg *mixer; + const struct dpu_lm_cfg *mixer; u32 pingpong_count; - struct dpu_pingpong_cfg *pingpong; + const struct dpu_pingpong_cfg *pingpong; u32 intf_count; - struct dpu_intf_cfg *intf; + const struct dpu_intf_cfg *intf; u32 vbif_count; - struct dpu_vbif_cfg *vbif; + const struct dpu_vbif_cfg *vbif; u32 reg_dma_count; struct dpu_reg_dma_cfg dma_cfg; @@ -682,9 +691,11 @@ struct dpu_mdss_cfg { /* Add additional block data structures here */ struct dpu_perf_cfg perf; - struct dpu_format_extended *dma_formats; - struct dpu_format_extended *cursor_formats; - struct dpu_format_extended *vig_formats; + const struct dpu_format_extended *dma_formats; + const struct dpu_format_extended *cursor_formats; + const struct dpu_format_extended *vig_formats; + + unsigned long mdss_irqs; }; struct dpu_mdss_hw_cfg_handler { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h index bb6112c949ae..3766f0fd0bf0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h @@ -6,8 +6,12 @@ static const uint32_t qcom_compressed_supported_formats[] = { DRM_FORMAT_ABGR8888, + DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, + DRM_FORMAT_XRGB8888, DRM_FORMAT_BGR565, + + DRM_FORMAT_NV12, }; static const uint32_t plane_formats[] = { 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 b2f7b0e886b5..831e5f7a9b7f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -22,14 +22,18 @@ #define CTL_PREPARE 0x0d0 #define CTL_SW_RESET 0x030 #define CTL_LAYER_EXTN_OFFSET 0x40 +#define CTL_INTF_ACTIVE 0x0F4 +#define CTL_INTF_FLUSH 0x110 +#define CTL_INTF_MASTER 0x134 #define CTL_MIXER_BORDER_OUT BIT(24) #define CTL_FLUSH_MASK_CTL BIT(17) #define DPU_REG_RESET_TIMEOUT_US 2000 +#define INTF_IDX 31 -static struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl, - struct dpu_mdss_cfg *m, +static const struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl, + const struct dpu_mdss_cfg *m, void __iomem *addr, struct dpu_hw_blk_reg_map *b) { @@ -100,14 +104,27 @@ static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx, ctx->pending_flush_mask |= flushbits; } -static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) +static inline void dpu_hw_ctl_update_pending_intf_flush(struct dpu_hw_ctl *ctx, + u32 flushbits) { - if (!ctx) - return 0x0; + ctx->pending_intf_flush_mask |= flushbits; +} +static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) +{ return ctx->pending_flush_mask; } +static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx) +{ + + if (ctx->pending_flush_mask & BIT(INTF_IDX)) + DPU_REG_WRITE(&ctx->hw, CTL_INTF_FLUSH, + ctx->pending_intf_flush_mask); + + DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); +} + static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx) { trace_dpu_hw_ctl_trigger_pending_flush(ctx->pending_flush_mask, @@ -225,6 +242,36 @@ static int dpu_hw_ctl_get_bitmask_intf(struct dpu_hw_ctl *ctx, return 0; } +static int dpu_hw_ctl_get_bitmask_intf_v1(struct dpu_hw_ctl *ctx, + u32 *flushbits, enum dpu_intf intf) +{ + switch (intf) { + case INTF_0: + case INTF_1: + *flushbits |= BIT(31); + break; + default: + return 0; + } + return 0; +} + +static int dpu_hw_ctl_active_get_bitmask_intf(struct dpu_hw_ctl *ctx, + u32 *flushbits, enum dpu_intf intf) +{ + switch (intf) { + case INTF_0: + *flushbits |= BIT(0); + break; + case INTF_1: + *flushbits |= BIT(1); + break; + default: + return 0; + } + return 0; +} + static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us) { struct dpu_hw_blk_reg_map *c = &ctx->hw; @@ -425,6 +472,24 @@ exit: DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3); } + +static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, + struct dpu_hw_intf_cfg *cfg) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 intf_active = 0; + u32 mode_sel = 0; + + if (cfg->intf_mode_sel == DPU_CTL_MODE_SEL_CMD) + mode_sel |= BIT(17); + + intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE); + intf_active |= BIT(cfg->intf - INTF_0); + + DPU_REG_WRITE(c, CTL_TOP, mode_sel); + DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active); +} + static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, struct dpu_hw_intf_cfg *cfg) { @@ -458,31 +523,41 @@ static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, unsigned long cap) { + if (cap & BIT(DPU_CTL_ACTIVE_CFG)) { + ops->trigger_flush = dpu_hw_ctl_trigger_flush_v1; + ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg_v1; + ops->get_bitmask_intf = dpu_hw_ctl_get_bitmask_intf_v1; + ops->get_bitmask_active_intf = + dpu_hw_ctl_active_get_bitmask_intf; + ops->update_pending_intf_flush = + dpu_hw_ctl_update_pending_intf_flush; + } else { + ops->trigger_flush = dpu_hw_ctl_trigger_flush; + ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg; + ops->get_bitmask_intf = dpu_hw_ctl_get_bitmask_intf; + } ops->clear_pending_flush = dpu_hw_ctl_clear_pending_flush; ops->update_pending_flush = dpu_hw_ctl_update_pending_flush; ops->get_pending_flush = dpu_hw_ctl_get_pending_flush; - ops->trigger_flush = dpu_hw_ctl_trigger_flush; ops->get_flush_register = dpu_hw_ctl_get_flush_register; ops->trigger_start = dpu_hw_ctl_trigger_start; ops->trigger_pending = dpu_hw_ctl_trigger_pending; - ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg; ops->reset = dpu_hw_ctl_reset_control; ops->wait_reset_status = dpu_hw_ctl_wait_reset_status; ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages; ops->setup_blendstage = dpu_hw_ctl_setup_blendstage; ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp; ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer; - ops->get_bitmask_intf = dpu_hw_ctl_get_bitmask_intf; }; static struct dpu_hw_blk_ops dpu_hw_ops; struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx, void __iomem *addr, - struct dpu_mdss_cfg *m) + const struct dpu_mdss_cfg *m) { struct dpu_hw_ctl *c; - struct dpu_ctl_cfg *cfg; + const struct dpu_ctl_cfg *cfg; c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index d3ae939ef9f8..09e1263c72e2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -91,6 +91,15 @@ struct dpu_hw_ctl_ops { u32 flushbits); /** + * OR in the given flushbits to the cached pending_intf_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @flushbits : module flushmask + */ + void (*update_pending_intf_flush)(struct dpu_hw_ctl *ctx, + u32 flushbits); + + /** * Write the value of the pending_flush_mask to hardware * @ctx : ctl path ctx pointer */ @@ -130,11 +139,24 @@ struct dpu_hw_ctl_ops { uint32_t (*get_bitmask_mixer)(struct dpu_hw_ctl *ctx, enum dpu_lm blk); + /** + * Query the value of the intf flush mask + * No effect on hardware + * @ctx : ctl path ctx pointer + */ int (*get_bitmask_intf)(struct dpu_hw_ctl *ctx, u32 *flushbits, enum dpu_intf blk); /** + * Query the value of the intf active flush mask + * No effect on hardware + * @ctx : ctl path ctx pointer + */ + int (*get_bitmask_active_intf)(struct dpu_hw_ctl *ctx, + u32 *flushbits, enum dpu_intf blk); + + /** * Set all blend stages to disabled * @ctx : ctl path ctx pointer */ @@ -159,6 +181,7 @@ struct dpu_hw_ctl_ops { * @mixer_count: number of mixers * @mixer_hw_caps: mixer hardware capabilities * @pending_flush_mask: storage for pending ctl_flush managed via ops + * @pending_intf_flush_mask: pending INTF flush * @ops: operation list */ struct dpu_hw_ctl { @@ -171,6 +194,7 @@ struct dpu_hw_ctl { int mixer_count; const struct dpu_lm_cfg *mixer_hw_caps; u32 pending_flush_mask; + u32 pending_intf_flush_mask; /* ops */ struct dpu_hw_ctl_ops ops; @@ -195,7 +219,7 @@ static inline struct dpu_hw_ctl *to_dpu_hw_ctl(struct dpu_hw_blk *hw) */ struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx, void __iomem *addr, - struct dpu_mdss_cfg *m); + const struct dpu_mdss_cfg *m); /** * dpu_hw_ctl_destroy(): Destroys ctl driver context 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 8bfa7d0eede6..d84a84f7fe1a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -800,8 +800,8 @@ static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, start_idx = reg_idx * 32; end_idx = start_idx + 32; - if (start_idx >= ARRAY_SIZE(dpu_irq_map) || - end_idx > ARRAY_SIZE(dpu_irq_map)) + if (!test_bit(reg_idx, &intr->irq_mask) || + start_idx >= ARRAY_SIZE(dpu_irq_map)) continue; /* @@ -955,8 +955,11 @@ static int dpu_hw_intr_clear_irqs(struct dpu_hw_intr *intr) if (!intr) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) - DPU_REG_WRITE(&intr->hw, dpu_intr_set[i].clr_off, 0xffffffff); + for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { + if (test_bit(i, &intr->irq_mask)) + DPU_REG_WRITE(&intr->hw, + dpu_intr_set[i].clr_off, 0xffffffff); + } /* ensure register writes go through */ wmb(); @@ -971,8 +974,11 @@ static int dpu_hw_intr_disable_irqs(struct dpu_hw_intr *intr) if (!intr) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) - DPU_REG_WRITE(&intr->hw, dpu_intr_set[i].en_off, 0x00000000); + for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { + if (test_bit(i, &intr->irq_mask)) + DPU_REG_WRITE(&intr->hw, + dpu_intr_set[i].en_off, 0x00000000); + } /* ensure register writes go through */ wmb(); @@ -991,6 +997,9 @@ static void dpu_hw_intr_get_interrupt_statuses(struct dpu_hw_intr *intr) spin_lock_irqsave(&intr->irq_lock, irq_flags); for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { + if (!test_bit(i, &intr->irq_mask)) + continue; + /* Read interrupt status */ intr->save_irq_status[i] = DPU_REG_READ(&intr->hw, dpu_intr_set[i].status_off); @@ -1115,6 +1124,7 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, return ERR_PTR(-ENOMEM); } + intr->irq_mask = m->mdss_irqs; spin_lock_init(&intr->irq_lock); return intr; 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 4edcf402dc46..fc9c98617281 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -187,6 +187,7 @@ struct dpu_hw_intr { u32 *save_irq_status; u32 irq_idx_tbl_size; spinlock_t irq_lock; + unsigned long irq_mask; }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c index dcd87cda13fe..efe9a5719c6b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -56,8 +56,10 @@ #define INTF_FRAME_COUNT 0x0AC #define INTF_LINE_COUNT 0x0B0 -static struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf, - struct dpu_mdss_cfg *m, +#define INTF_MUX 0x25C + +static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf, + const struct dpu_mdss_cfg *m, void __iomem *addr, struct dpu_hw_blk_reg_map *b) { @@ -218,6 +220,30 @@ static void dpu_hw_intf_setup_prg_fetch( DPU_REG_WRITE(c, INTF_CONFIG, fetch_enable); } +static void dpu_hw_intf_bind_pingpong_blk( + struct dpu_hw_intf *intf, + bool enable, + const enum dpu_pingpong pp) +{ + struct dpu_hw_blk_reg_map *c; + u32 mux_cfg; + + if (!intf) + return; + + c = &intf->hw; + + mux_cfg = DPU_REG_READ(c, INTF_MUX); + mux_cfg &= ~0xf; + + if (enable) + mux_cfg |= (pp - PINGPONG_0) & 0x7; + else + mux_cfg |= 0xf; + + DPU_REG_WRITE(c, INTF_MUX, mux_cfg); +} + static void dpu_hw_intf_get_status( struct dpu_hw_intf *intf, struct intf_status *s) @@ -254,16 +280,18 @@ static void _setup_intf_ops(struct dpu_hw_intf_ops *ops, ops->get_status = dpu_hw_intf_get_status; ops->enable_timing = dpu_hw_intf_enable_timing_engine; ops->get_line_count = dpu_hw_intf_get_line_count; + if (cap & BIT(DPU_CTL_ACTIVE_CFG)) + ops->bind_pingpong_blk = dpu_hw_intf_bind_pingpong_blk; } static struct dpu_hw_blk_ops dpu_hw_ops; struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx, void __iomem *addr, - struct dpu_mdss_cfg *m) + const struct dpu_mdss_cfg *m) { struct dpu_hw_intf *c; - struct dpu_intf_cfg *cfg; + const struct dpu_intf_cfg *cfg; c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index b03acc225c9b..85468981632d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -52,6 +52,8 @@ struct intf_status { * @ enable_timing: enable/disable timing engine * @ get_status: returns if timing engine is enabled or not * @ get_line_count: reads current vertical line counter + * @bind_pingpong_blk: enable/disable the connection with pingpong which will + * feed pixels to this interface */ struct dpu_hw_intf_ops { void (*setup_timing_gen)(struct dpu_hw_intf *intf, @@ -68,6 +70,10 @@ struct dpu_hw_intf_ops { struct intf_status *status); u32 (*get_line_count)(struct dpu_hw_intf *intf); + + void (*bind_pingpong_blk)(struct dpu_hw_intf *intf, + bool enable, + const enum dpu_pingpong pp); }; struct dpu_hw_intf { @@ -92,7 +98,7 @@ struct dpu_hw_intf { */ struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx, void __iomem *addr, - struct dpu_mdss_cfg *m); + const struct dpu_mdss_cfg *m); /** * dpu_hw_intf_destroy(): Destroys INTF driver context diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c index 5bc39baa746a..37becd43bd54 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -24,8 +24,8 @@ #define LM_BLEND0_FG_ALPHA 0x04 #define LM_BLEND0_BG_ALPHA 0x08 -static struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer, - struct dpu_mdss_cfg *m, +static const struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer, + const struct dpu_mdss_cfg *m, void __iomem *addr, struct dpu_hw_blk_reg_map *b) { @@ -147,12 +147,13 @@ static void dpu_hw_lm_setup_color3(struct dpu_hw_mixer *ctx, DPU_REG_WRITE(c, LM_OP_MODE, op_mode); } -static void _setup_mixer_ops(struct dpu_mdss_cfg *m, +static void _setup_mixer_ops(const struct dpu_mdss_cfg *m, struct dpu_hw_lm_ops *ops, unsigned long features) { ops->setup_mixer_out = dpu_hw_lm_setup_out; - if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion)) + if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion) + || IS_SC7180_TARGET(m->hwversion)) ops->setup_blend_config = dpu_hw_lm_setup_blend_config_sdm845; else ops->setup_blend_config = dpu_hw_lm_setup_blend_config; @@ -164,10 +165,10 @@ static struct dpu_hw_blk_ops dpu_hw_ops; struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx, void __iomem *addr, - struct dpu_mdss_cfg *m) + const struct dpu_mdss_cfg *m) { struct dpu_hw_mixer *c; - struct dpu_lm_cfg *cfg; + const struct dpu_lm_cfg *cfg; c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index 147ace31cfc2..4a6b2de19ef6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -91,7 +91,7 @@ static inline struct dpu_hw_mixer *to_dpu_hw_mixer(struct dpu_hw_blk *hw) */ struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx, void __iomem *addr, - struct dpu_mdss_cfg *m); + const struct dpu_mdss_cfg *m); /** * dpu_hw_lm_destroy(): Destroys layer mixer driver context diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c index 5dbaba9fd180..d110a40f0e73 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c @@ -28,8 +28,8 @@ #define PP_FBC_BUDGET_CTL 0x038 #define PP_FBC_LOSSY_MODE 0x03C -static struct dpu_pingpong_cfg *_pingpong_offset(enum dpu_pingpong pp, - struct dpu_mdss_cfg *m, +static const struct dpu_pingpong_cfg *_pingpong_offset(enum dpu_pingpong pp, + const struct dpu_mdss_cfg *m, void __iomem *addr, struct dpu_hw_blk_reg_map *b) { @@ -195,10 +195,10 @@ static struct dpu_hw_blk_ops dpu_hw_ops; struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx, void __iomem *addr, - struct dpu_mdss_cfg *m) + const struct dpu_mdss_cfg *m) { struct dpu_hw_pingpong *c; - struct dpu_pingpong_cfg *cfg; + const struct dpu_pingpong_cfg *cfg; c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index 58bdb9279aa8..3d6f46b1db30 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -106,7 +106,7 @@ struct dpu_hw_pingpong { */ struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx, void __iomem *addr, - struct dpu_mdss_cfg *m); + const struct dpu_mdss_cfg *m); /** * dpu_hw_pingpong_destroy - destroys pingpong driver context 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 4f8b813aab81..82c5dbfdabc7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -132,6 +132,7 @@ /* traffic shaper clock in Hz */ #define TS_CLK 19200000 + static int _sspp_subblk_offset(struct dpu_hw_pipe *ctx, int s_id, u32 *idx) @@ -657,7 +658,8 @@ static void _setup_layer_ops(struct dpu_hw_pipe *c, test_bit(DPU_SSPP_SMART_DMA_V2, &c->cap->features)) c->ops.setup_multirect = dpu_hw_sspp_setup_multirect; - if (test_bit(DPU_SSPP_SCALER_QSEED3, &features)) { + if (test_bit(DPU_SSPP_SCALER_QSEED3, &features) || + test_bit(DPU_SSPP_SCALER_QSEED4, &features)) { c->ops.setup_scaler = _dpu_hw_sspp_setup_scaler3; c->ops.get_scaler_ver = _dpu_hw_sspp_get_scaler3_ver; } @@ -666,7 +668,7 @@ static void _setup_layer_ops(struct dpu_hw_pipe *c, c->ops.setup_cdp = dpu_hw_sspp_setup_cdp; } -static struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp, +static const struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp, void __iomem *addr, struct dpu_mdss_cfg *catalog, struct dpu_hw_blk_reg_map *b) @@ -696,7 +698,7 @@ struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx, bool is_virtual_pipe) { struct dpu_hw_pipe *hw_pipe; - struct dpu_sspp_cfg *cfg; + const struct dpu_sspp_cfg *cfg; if (!addr || !catalog) return ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index a3680b482b41..85b018a9b03c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -27,7 +27,8 @@ struct dpu_hw_pipe; */ #define DPU_SSPP_SCALER ((1UL << DPU_SSPP_SCALER_RGB) | \ (1UL << DPU_SSPP_SCALER_QSEED2) | \ - (1UL << DPU_SSPP_SCALER_QSEED3)) + (1UL << DPU_SSPP_SCALER_QSEED3) | \ + (1UL << DPU_SSPP_SCALER_QSEED4)) /** * Component indices @@ -373,7 +374,7 @@ struct dpu_hw_pipe { struct dpu_hw_blk base; struct dpu_hw_blk_reg_map hw; struct dpu_mdss_cfg *catalog; - struct dpu_mdp_cfg *mdp; + const struct dpu_mdp_cfg *mdp; /* Pipe */ enum dpu_sspp idx; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c index 71b6987bff1e..078afc5f5882 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c @@ -7,6 +7,7 @@ #include <linux/clk/clk-conf.h> #include <linux/err.h> #include <linux/delay.h> +#include <linux/of.h> #include <drm/drm_print.h> @@ -92,19 +93,12 @@ int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable) DEV_DBG("%pS->%s: enable '%s'\n", __builtin_return_address(0), __func__, clk_arry[i].clk_name); - if (clk_arry[i].clk) { - rc = clk_prepare_enable(clk_arry[i].clk); - if (rc) - DEV_ERR("%pS->%s: %s en fail. rc=%d\n", - __builtin_return_address(0), - __func__, - clk_arry[i].clk_name, rc); - } else { - DEV_ERR("%pS->%s: '%s' is not available\n", - __builtin_return_address(0), __func__, - clk_arry[i].clk_name); - rc = -EPERM; - } + rc = clk_prepare_enable(clk_arry[i].clk); + if (rc) + DEV_ERR("%pS->%s: %s en fail. rc=%d\n", + __builtin_return_address(0), + __func__, + clk_arry[i].clk_name, rc); if (rc && i) { msm_dss_enable_clk(&clk_arry[i - 1], @@ -118,12 +112,7 @@ int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable) __builtin_return_address(0), __func__, clk_arry[i].clk_name); - if (clk_arry[i].clk) - clk_disable_unprepare(clk_arry[i].clk); - else - DEV_ERR("%pS->%s: '%s' is not available\n", - __builtin_return_address(0), __func__, - clk_arry[i].clk_name); + clk_disable_unprepare(clk_arry[i].clk); } } @@ -186,6 +175,7 @@ int msm_dss_parse_clock(struct platform_device *pdev, continue; mp->clk_config[i].rate = rate; mp->clk_config[i].type = DSS_CLK_PCLK; + mp->clk_config[i].max_rate = rate; } mp->num_clk = num_clk; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h index 09083e9f06bb..e6b5c772fa3b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h @@ -5,7 +5,6 @@ #ifndef __DPU_IO_UTIL_H__ #define __DPU_IO_UTIL_H__ -#include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/types.h> @@ -14,12 +13,6 @@ #define DEV_WARN(fmt, args...) pr_warn(fmt, ##args) #define DEV_ERR(fmt, args...) pr_err(fmt, ##args) -struct dss_gpio { - unsigned int gpio; - unsigned int value; - char gpio_name[32]; -}; - enum dss_clk_type { DSS_CLK_AHB, /* no set rate. rate controlled through rpm */ DSS_CLK_PCLK, @@ -34,8 +27,6 @@ struct dss_clk { }; struct dss_module_power { - unsigned int num_gpio; - struct dss_gpio *gpio_config; unsigned int num_clk; struct dss_clk *clk_config; }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index bb9d44e7bd26..cb08fafb1dc1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -7,10 +7,12 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ -#include <drm/drm_crtc.h> #include <linux/debugfs.h> -#include <linux/of_irq.h> #include <linux/dma-buf.h> +#include <linux/of_irq.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_file.h> #include "msm_drv.h" #include "msm_mmu.h" @@ -28,10 +30,6 @@ #define CREATE_TRACE_POINTS #include "dpu_trace.h" -static const char * const iommu_ports[] = { - "mdp_0", -}; - /* * To enable overall DRM driver logging * # echo 0x2 > /sys/module/drm/parameters/debug @@ -66,16 +64,14 @@ static int _dpu_danger_signal_status(struct seq_file *s, bool danger_status) { struct dpu_kms *kms = (struct dpu_kms *)s->private; - struct msm_drm_private *priv; struct dpu_danger_safe_status status; int i; - if (!kms->dev || !kms->dev->dev_private || !kms->hw_mdp) { + if (!kms->hw_mdp) { DPU_ERROR("invalid arg(s)\n"); return 0; } - priv = kms->dev->dev_private; memset(&status, 0, sizeof(struct dpu_danger_safe_status)); pm_runtime_get_sync(&kms->pdev->dev); @@ -151,13 +147,7 @@ static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data) return 0; dev = dpu_kms->dev; - if (!dev) - return 0; - priv = dev->dev_private; - if (!priv) - return 0; - base = dpu_kms->mmio + regset->offset; /* insert padding spaces, if needed */ @@ -248,11 +238,36 @@ static void dpu_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) dpu_crtc_vblank(crtc, false); } +static void dpu_kms_enable_commit(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + pm_runtime_get_sync(&dpu_kms->pdev->dev); +} + +static void dpu_kms_disable_commit(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + pm_runtime_put_sync(&dpu_kms->pdev->dev); +} + +static ktime_t dpu_kms_vsync_time(struct msm_kms *kms, struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { + ktime_t vsync_time; + + if (dpu_encoder_vsync_time(encoder, &vsync_time) == 0) + return vsync_time; + } + + return ktime_get(); +} + static void dpu_kms_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) { struct dpu_kms *dpu_kms; - struct msm_drm_private *priv; struct drm_device *dev; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; @@ -264,11 +279,6 @@ static void dpu_kms_prepare_commit(struct msm_kms *kms, dpu_kms = to_dpu_kms(kms); dev = dpu_kms->dev; - if (!dev || !dev->dev_private) - return; - priv = dev->dev_private; - pm_runtime_get_sync(&dpu_kms->pdev->dev); - /* Call prepare_commit for all affected encoders */ for_each_new_crtc_in_state(state, crtc, crtc_state, i) { drm_for_each_encoder_mask(encoder, crtc->dev, @@ -278,6 +288,20 @@ static void dpu_kms_prepare_commit(struct msm_kms *kms, } } +static void dpu_kms_flush_commit(struct msm_kms *kms, unsigned crtc_mask) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + struct drm_crtc *crtc; + + for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask) { + if (!crtc->state->active) + continue; + + trace_dpu_kms_commit(DRMID(crtc)); + dpu_crtc_commit_kickoff(crtc); + } +} + /* * Override the encoder enable since we need to setup the inline rotator and do * some crtc magic before enabling any bridge that might be present. @@ -292,58 +316,23 @@ void dpu_kms_encoder_enable(struct drm_encoder *encoder) if (funcs && funcs->commit) funcs->commit(encoder); - WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); drm_for_each_crtc(crtc, dev) { if (!(crtc->state->encoder_mask & drm_encoder_mask(encoder))) continue; trace_dpu_kms_enc_enable(DRMID(crtc)); - dpu_crtc_commit_kickoff(crtc, false); } } -static void dpu_kms_commit(struct msm_kms *kms, struct drm_atomic_state *state) +static void dpu_kms_complete_commit(struct msm_kms *kms, unsigned crtc_mask) { + struct dpu_kms *dpu_kms = to_dpu_kms(kms); struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int i; - - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { - /* If modeset is required, kickoff is run in encoder_enable */ - if (drm_atomic_crtc_needs_modeset(crtc_state)) - continue; - - if (crtc->state->active) { - trace_dpu_kms_commit(DRMID(crtc)); - dpu_crtc_commit_kickoff(crtc, - state->legacy_cursor_update); - } - } -} - -static void dpu_kms_complete_commit(struct msm_kms *kms, - struct drm_atomic_state *old_state) -{ - struct dpu_kms *dpu_kms; - struct msm_drm_private *priv; - struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state; - int i; - - if (!kms || !old_state) - return; - dpu_kms = to_dpu_kms(kms); - - if (!dpu_kms->dev || !dpu_kms->dev->dev_private) - return; - priv = dpu_kms->dev->dev_private; DPU_ATRACE_BEGIN("kms_complete_commit"); - for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) - dpu_crtc_complete_commit(crtc, old_crtc_state); - - pm_runtime_put_sync(&dpu_kms->pdev->dev); + for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask) + dpu_crtc_complete_commit(crtc); DPU_ATRACE_END("kms_complete_commit"); } @@ -389,6 +378,15 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms *kms, } } +static void dpu_kms_wait_flush(struct msm_kms *kms, unsigned crtc_mask) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + struct drm_crtc *crtc; + + for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask) + dpu_kms_wait_for_commit_done(kms, crtc); +} + static int _dpu_kms_initialize_dsi(struct drm_device *dev, struct msm_drm_private *priv, struct dpu_kms *dpu_kms) @@ -448,16 +446,6 @@ static void _dpu_kms_drm_obj_destroy(struct dpu_kms *dpu_kms) struct msm_drm_private *priv; int i; - if (!dpu_kms) { - DPU_ERROR("invalid dpu_kms\n"); - return; - } else if (!dpu_kms->dev) { - DPU_ERROR("invalid dev\n"); - return; - } else if (!dpu_kms->dev->dev_private) { - DPU_ERROR("invalid dev_private\n"); - return; - } priv = dpu_kms->dev->dev_private; for (i = 0; i < priv->num_crtcs; i++) @@ -489,12 +477,6 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) int primary_planes_idx = 0, cursor_planes_idx = 0, i, ret; int max_crtc_count; - - if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev) { - DPU_ERROR("invalid dpu_kms\n"); - return -EINVAL; - } - dev = dpu_kms->dev; priv = dev->dev_private; catalog = dpu_kms->catalog; @@ -574,8 +556,6 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) int i; dev = dpu_kms->dev; - if (!dev) - return; if (dpu_kms->hw_intr) dpu_hw_intr_destroy(dpu_kms->hw_intr); @@ -686,10 +666,13 @@ static const struct msm_kms_funcs kms_funcs = { .irq_preinstall = dpu_irq_preinstall, .irq_uninstall = dpu_irq_uninstall, .irq = dpu_irq, + .enable_commit = dpu_kms_enable_commit, + .disable_commit = dpu_kms_disable_commit, + .vsync_time = dpu_kms_vsync_time, .prepare_commit = dpu_kms_prepare_commit, - .commit = dpu_kms_commit, + .flush_commit = dpu_kms_flush_commit, + .wait_flush = dpu_kms_wait_flush, .complete_commit = dpu_kms_complete_commit, - .wait_for_crtc_commit_done = dpu_kms_wait_for_commit_done, .enable_vblank = dpu_kms_enable_vblank, .disable_vblank = dpu_kms_disable_vblank, .check_modified_format = dpu_format_check_modified_format, @@ -711,8 +694,7 @@ static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms) mmu = dpu_kms->base.aspace->mmu; - mmu->funcs->detach(mmu, (const char **)iommu_ports, - ARRAY_SIZE(iommu_ports)); + mmu->funcs->detach(mmu); msm_gem_address_space_put(dpu_kms->base.aspace); dpu_kms->base.aspace = NULL; @@ -738,8 +720,7 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms) return PTR_ERR(aspace); } - ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports, - ARRAY_SIZE(iommu_ports)); + ret = aspace->mmu->funcs->attach(aspace->mmu); if (ret) { DPU_ERROR("failed to attach iommu %d\n", ret); msm_gem_address_space_put(aspace); @@ -789,16 +770,9 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dpu_kms = to_dpu_kms(kms); dev = dpu_kms->dev; - if (!dev) { - DPU_ERROR("invalid device\n"); - return rc; - } - priv = dev->dev_private; - if (!priv) { - DPU_ERROR("invalid private data\n"); - return rc; - } + + atomic_set(&dpu_kms->bandwidth_ref, 0); dpu_kms->mmio = msm_ioremap(dpu_kms->pdev, "mdp", "mdp"); if (IS_ERR(dpu_kms->mmio)) { @@ -958,7 +932,7 @@ struct msm_kms *dpu_kms_init(struct drm_device *dev) struct dpu_kms *dpu_kms; int irq; - if (!dev || !dev->dev_private) { + if (!dev) { DPU_ERROR("drm device node invalid\n"); return ERR_PTR(-EINVAL); } @@ -1048,11 +1022,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) struct dss_module_power *mp = &dpu_kms->mp; ddev = dpu_kms->dev; - if (!ddev) { - DPU_ERROR("invalid drm_device\n"); - return rc; - } - rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, false); if (rc) DPU_ERROR("clock disable failed rc:%d\n", rc); @@ -1070,11 +1039,6 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) struct dss_module_power *mp = &dpu_kms->mp; ddev = dpu_kms->dev; - if (!ddev) { - DPU_ERROR("invalid drm_device\n"); - return rc; - } - rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); if (rc) { DPU_ERROR("clock enable failed rc:%d\n", rc); @@ -1095,6 +1059,7 @@ static const struct dev_pm_ops dpu_pm_ops = { static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,sdm845-dpu", }, + { .compatible = "qcom,sc7180-dpu", }, {} }; MODULE_DEVICE_TABLE(of, dpu_dt_match); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 9e40f559c51f..c6169e7df19d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -8,6 +8,8 @@ #ifndef __DPU_KMS_H__ #define __DPU_KMS_H__ +#include <drm/drm_drv.h> + #include "msm_drv.h" #include "msm_kms.h" #include "msm_mmu.h" @@ -29,7 +31,7 @@ */ #define DPU_DEBUG(fmt, ...) \ do { \ - if (unlikely(drm_debug & DRM_UT_KMS)) \ + if (drm_debug_enabled(DRM_UT_KMS)) \ DRM_DEBUG(fmt, ##__VA_ARGS__); \ else \ pr_debug(fmt, ##__VA_ARGS__); \ @@ -41,7 +43,7 @@ */ #define DPU_DEBUG_DRIVER(fmt, ...) \ do { \ - if (unlikely(drm_debug & DRM_UT_DRIVER)) \ + if (drm_debug_enabled(DRM_UT_DRIVER)) \ DRM_ERROR(fmt, ##__VA_ARGS__); \ else \ pr_debug(fmt, ##__VA_ARGS__); \ @@ -120,6 +122,14 @@ struct dpu_kms { struct platform_device *pdev; bool rpm_enabled; struct dss_module_power mp; + + /* reference count bandwidth requests, so we know when we can + * release bandwidth. Each atomic update increments, and frame- + * done event decrements. Additionally, for video mode, the + * reference is incremented when crtc is enabled, and decremented + * when disabled. + */ + atomic_t bandwidth_ref; }; struct vsync_info { @@ -129,10 +139,6 @@ struct vsync_info { #define to_dpu_kms(x) container_of(x, struct dpu_kms, base) -/* get struct msm_kms * from drm_device * */ -#define ddev_to_msm_kms(D) ((D) && (D)->dev_private ? \ - ((struct msm_drm_private *)((D)->dev_private))->kms : NULL) - /** * Debugfs functions - extra helper functions for debugfs support * diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c index 986915bbbc02..29705e773a4b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c @@ -3,6 +3,10 @@ * Copyright (c) 2018, The Linux Foundation */ +#include <linux/irq.h> +#include <linux/irqchip.h> +#include <linux/irqdesc.h> +#include <linux/irqchip/chained_irq.h> #include "dpu_kms.h" #include <linux/interconnect.h> @@ -22,7 +26,6 @@ struct dpu_mdss { struct msm_mdss base; void __iomem *mmio; unsigned long mmio_len; - u32 hwversion; struct dss_module_power mp; struct dpu_irq_controller irq_controller; struct icc_path *path[2]; @@ -287,10 +290,6 @@ int dpu_mdss_init(struct drm_device *dev) dpu_mdss_icc_request_bw(priv->mdss); - pm_runtime_get_sync(dev->dev); - dpu_mdss->hwversion = readl_relaxed(dpu_mdss->mmio); - pm_runtime_put_sync(dev->dev); - return ret; irq_error: diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 45bfac9e3af7..3b9c33e694bf 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -10,8 +10,10 @@ #include <linux/debugfs.h> #include <linux/dma-buf.h> -#include <drm/drm_damage_helper.h> #include <drm/drm_atomic_uapi.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_file.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "msm_drv.h" #include "dpu_kms.h" @@ -51,8 +53,13 @@ enum { R_MAX }; +/* + * Default Preload Values + */ #define DPU_QSEED3_DEFAULT_PRELOAD_H 0x4 #define DPU_QSEED3_DEFAULT_PRELOAD_V 0x3 +#define DPU_QSEED4_DEFAULT_PRELOAD_V 0x2 +#define DPU_QSEED4_DEFAULT_PRELOAD_H 0x4 #define DEFAULT_REFRESH_RATE 60 @@ -475,8 +482,16 @@ static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu, scale_cfg->src_width[i] /= chroma_subsmpl_h; scale_cfg->src_height[i] /= chroma_subsmpl_v; } - scale_cfg->preload_x[i] = DPU_QSEED3_DEFAULT_PRELOAD_H; - scale_cfg->preload_y[i] = DPU_QSEED3_DEFAULT_PRELOAD_V; + + if (pdpu->pipe_hw->cap->features & + BIT(DPU_SSPP_SCALER_QSEED4)) { + scale_cfg->preload_x[i] = DPU_QSEED4_DEFAULT_PRELOAD_H; + scale_cfg->preload_y[i] = DPU_QSEED4_DEFAULT_PRELOAD_V; + } else { + scale_cfg->preload_x[i] = DPU_QSEED3_DEFAULT_PRELOAD_H; + scale_cfg->preload_y[i] = DPU_QSEED3_DEFAULT_PRELOAD_V; + } + pstate->pixel_ext.num_ext_pxls_top[i] = scale_cfg->src_height[i]; pstate->pixel_ext.num_ext_pxls_left[i] = @@ -736,7 +751,7 @@ done: } else { pstate[R0]->multirect_index = DPU_SSPP_RECT_0; pstate[R1]->multirect_index = DPU_SSPP_RECT_1; - }; + } DPU_DEBUG_PLANE(dpu_plane[R0], "R0: %d - %d\n", pstate[R0]->multirect_mode, pstate[R0]->multirect_index); @@ -764,8 +779,6 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane, struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_state); struct dpu_hw_fmt_layout layout; - struct drm_gem_object *obj; - struct dma_fence *fence; struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); int ret; @@ -782,10 +795,7 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane, * we can use msm_atomic_prepare_fb() instead of doing the * implicit fence and fb prepare by hand here. */ - obj = msm_framebuffer_bo(new_state->fb, 0); - fence = reservation_object_get_excl_rcu(obj->resv); - if (fence) - drm_atomic_set_fence_for_plane(new_state, fence); + drm_gem_fb_prepare_fb(plane, new_state); if (pstate->aspace) { ret = msm_framebuffer_prepare(new_state->fb, @@ -861,7 +871,7 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, pdpu->pipe_sblk->maxupscale << 16, true, true); if (ret) { - DPU_ERROR_PLANE(pdpu, "Check plane state failed (%d)\n", ret); + DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret); return ret; } if (!state->visible) @@ -887,13 +897,13 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, (!(pdpu->features & DPU_SSPP_SCALER) || !(pdpu->features & (BIT(DPU_SSPP_CSC) | BIT(DPU_SSPP_CSC_10BIT))))) { - DPU_ERROR_PLANE(pdpu, + DPU_DEBUG_PLANE(pdpu, "plane doesn't have scaler/csc for yuv\n"); return -EINVAL; /* check src bounds */ } else if (!dpu_plane_validate_src(&src, &fb_rect, min_src_size)) { - DPU_ERROR_PLANE(pdpu, "invalid source " DRM_RECT_FMT "\n", + DPU_DEBUG_PLANE(pdpu, "invalid source " DRM_RECT_FMT "\n", DRM_RECT_ARG(&src)); return -E2BIG; @@ -902,19 +912,19 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, (src.x1 & 0x1 || src.y1 & 0x1 || drm_rect_width(&src) & 0x1 || drm_rect_height(&src) & 0x1)) { - DPU_ERROR_PLANE(pdpu, "invalid yuv source " DRM_RECT_FMT "\n", + DPU_DEBUG_PLANE(pdpu, "invalid yuv source " DRM_RECT_FMT "\n", DRM_RECT_ARG(&src)); return -EINVAL; /* min dst support */ } else if (drm_rect_width(&dst) < 0x1 || drm_rect_height(&dst) < 0x1) { - DPU_ERROR_PLANE(pdpu, "invalid dest rect " DRM_RECT_FMT "\n", + DPU_DEBUG_PLANE(pdpu, "invalid dest rect " DRM_RECT_FMT "\n", DRM_RECT_ARG(&dst)); return -EINVAL; /* check decimated source width */ } else if (drm_rect_width(&src) > max_linewidth) { - DPU_ERROR_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", DRM_RECT_ARG(&src), max_linewidth); return -E2BIG; } @@ -1040,8 +1050,21 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) pstate->multirect_mode); if (pdpu->pipe_hw->ops.setup_format) { + unsigned int rotation; + src_flags = 0x0; + rotation = drm_rotation_simplify(state->rotation, + DRM_MODE_ROTATE_0 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y); + + if (rotation & DRM_MODE_REFLECT_X) + src_flags |= DPU_SSPP_FLIP_LR; + + if (rotation & DRM_MODE_REFLECT_Y) + src_flags |= DPU_SSPP_FLIP_UD; + /* update format */ pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, fmt, src_flags, pstate->multirect_index); @@ -1327,7 +1350,8 @@ static int _dpu_plane_init_debugfs(struct drm_plane *plane) pdpu->debugfs_root, &pdpu->debugfs_src); if (cfg->features & BIT(DPU_SSPP_SCALER_QSEED3) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED2)) { + cfg->features & BIT(DPU_SSPP_SCALER_QSEED2) || + cfg->features & BIT(DPU_SSPP_SCALER_QSEED4)) { dpu_debugfs_setup_regset32(&pdpu->debugfs_scaler, sblk->scaler_blk.base + cfg->base, sblk->scaler_blk.len, @@ -1522,6 +1546,13 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, if (ret) DPU_ERROR("failed to install zpos property, rc = %d\n", ret); + drm_plane_create_rotation_property(plane, + DRM_MODE_ROTATE_0, + DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_180 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y); + drm_plane_enable_fb_damage_clips(plane); /* success! finalize initialization */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index ddc8412731af..23f5b1433b35 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -141,11 +141,11 @@ int dpu_rm_destroy(struct dpu_rm *rm) static int _dpu_rm_hw_blk_create( struct dpu_rm *rm, - struct dpu_mdss_cfg *cat, + const struct dpu_mdss_cfg *cat, void __iomem *mmio, enum dpu_hw_blk_type type, uint32_t id, - void *hw_catalog_info) + const void *hw_catalog_info) { struct dpu_rm_hw_blk *blk; void *hw; @@ -215,7 +215,7 @@ int dpu_rm_init(struct dpu_rm *rm, /* Interrogate HW catalog and create tracking items for hw blocks */ for (i = 0; i < cat->mixer_count; i++) { - struct dpu_lm_cfg *lm = &cat->mixer[i]; + const struct dpu_lm_cfg *lm = &cat->mixer[i]; if (lm->pingpong == PINGPONG_MAX) { DPU_DEBUG("skip mixer %d without pingpong\n", lm->id); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h index 765484437d11..eecfe9b3199e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h @@ -392,7 +392,7 @@ TRACE_EVENT(dpu_enc_rc, __entry->rc_state = rc_state; __assign_str(stage_str, stage); ), - TP_printk("%s: id:%u, sw_event:%d, idle_pc_supported:%s, rc_state:%d\n", + TP_printk("%s: id:%u, sw_event:%d, idle_pc_supported:%s, rc_state:%d", __get_str(stage_str), __entry->drm_id, __entry->sw_event, __entry->idle_pc_supported ? "true" : "false", __entry->rc_state) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c index 8bc3aea7cd86..93ab36bd8df3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c @@ -5,6 +5,7 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ #include <linux/debugfs.h> +#include <linux/delay.h> #include "dpu_vbif.h" #include "dpu_hw_vbif.h" @@ -153,10 +154,6 @@ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, u32 ot_lim; int ret, i; - if (!dpu_kms) { - DPU_ERROR("invalid arguments\n"); - return; - } mdp = dpu_kms->hw_mdp; for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { @@ -213,7 +210,7 @@ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, const struct dpu_vbif_qos_tbl *qos_tbl; int i; - if (!dpu_kms || !params || !dpu_kms->hw_mdp) { + if (!params || !dpu_kms->hw_mdp) { DPU_ERROR("invalid arguments\n"); return; } @@ -264,11 +261,6 @@ void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms) struct dpu_hw_vbif *vbif; u32 i, pnd, src; - if (!dpu_kms) { - DPU_ERROR("invalid argument\n"); - return; - } - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { vbif = dpu_kms->hw_vbif[i]; if (vbif && vbif->ops.clear_errors) { @@ -286,11 +278,6 @@ void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms) struct dpu_hw_vbif *vbif; int i, j; - if (!dpu_kms) { - DPU_ERROR("invalid argument\n"); - return; - } - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { vbif = dpu_kms->hw_vbif[i]; if (vbif && vbif->cap && vbif->ops.set_mem_type) { @@ -312,7 +299,7 @@ void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root) entry = debugfs_create_dir("vbif", debugfs_root); for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { - struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; + const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; snprintf(vbif_name, sizeof(vbif_name), "%d", vbif->id); @@ -331,7 +318,7 @@ void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root) (u32 *)&vbif->default_ot_wr_limit); for (j = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) { - struct dpu_vbif_dynamic_ot_cfg *cfg = + const struct dpu_vbif_dynamic_ot_cfg *cfg = &vbif->dynamic_ot_rd_tbl.cfg[j]; snprintf(vbif_name, sizeof(vbif_name), @@ -345,7 +332,7 @@ void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root) } for (j = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) { - struct dpu_vbif_dynamic_ot_cfg *cfg = + const struct dpu_vbif_dynamic_ot_cfg *cfg = &vbif->dynamic_ot_wr_tbl.cfg[j]; snprintf(vbif_name, sizeof(vbif_name), diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 668c41975d74..f34dca5d4532 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -8,6 +8,7 @@ #include <drm/drm_flip_work.h> #include <drm/drm_mode.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "mdp4_kms.h" diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c index 772f0753ed38..aaf2f26f8505 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c @@ -121,7 +121,7 @@ static void mdp4_dsi_encoder_enable(struct drm_encoder *encoder) if (mdp4_dsi_encoder->enabled) return; - mdp4_crtc_set_config(encoder->crtc, + mdp4_crtc_set_config(encoder->crtc, MDP4_DMA_CONFIG_PACK_ALIGN_MSB | MDP4_DMA_CONFIG_DEFLKR_EN | MDP4_DMA_CONFIG_DITHER_EN | diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c index 62fbca302ac2..4d49f3ba6a96 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c @@ -5,6 +5,7 @@ */ #include <drm/drm_print.h> +#include <drm/drm_vblank.h> #include "msm_drv.h" #include "mdp4_kms.h" diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 7a9ab55b4608..dda05436f716 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -4,6 +4,9 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/delay.h> + +#include <drm/drm_vblank.h> #include "msm_drv.h" #include "msm_gem.h" @@ -93,40 +96,51 @@ out: return ret; } -static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) +static void mdp4_enable_commit(struct msm_kms *kms) +{ + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + mdp4_enable(mdp4_kms); +} + +static void mdp4_disable_commit(struct msm_kms *kms) { struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + mdp4_disable(mdp4_kms); +} + +static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) +{ int i; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; - mdp4_enable(mdp4_kms); - /* see 119ecb7fd */ for_each_new_crtc_in_state(state, crtc, crtc_state, i) drm_crtc_vblank_get(crtc); } -static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) +static void mdp4_flush_commit(struct msm_kms *kms, unsigned crtc_mask) +{ + /* TODO */ +} + +static void mdp4_wait_flush(struct msm_kms *kms, unsigned crtc_mask) { struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); - int i; struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - - drm_atomic_helper_wait_for_vblanks(mdp4_kms->dev, state); - - /* see 119ecb7fd */ - for_each_new_crtc_in_state(state, crtc, crtc_state, i) - drm_crtc_vblank_put(crtc); - mdp4_disable(mdp4_kms); + for_each_crtc_mask(mdp4_kms->dev, crtc, crtc_mask) + mdp4_crtc_wait_for_commit_done(crtc); } -static void mdp4_wait_for_crtc_commit_done(struct msm_kms *kms, - struct drm_crtc *crtc) +static void mdp4_complete_commit(struct msm_kms *kms, unsigned crtc_mask) { - mdp4_crtc_wait_for_commit_done(crtc); + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + struct drm_crtc *crtc; + + /* see 119ecb7fd */ + for_each_crtc_mask(mdp4_kms->dev, crtc, crtc_mask) + drm_crtc_vblank_put(crtc); } static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate, @@ -143,10 +157,6 @@ static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate, } } -static const char * const iommu_ports[] = { - "mdp_port0_cb0", "mdp_port1_cb0", -}; - static void mdp4_destroy(struct msm_kms *kms) { struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); @@ -158,8 +168,7 @@ static void mdp4_destroy(struct msm_kms *kms) drm_gem_object_put_unlocked(mdp4_kms->blank_cursor_bo); if (aspace) { - aspace->mmu->funcs->detach(aspace->mmu, - iommu_ports, ARRAY_SIZE(iommu_ports)); + aspace->mmu->funcs->detach(aspace->mmu); msm_gem_address_space_put(aspace); } @@ -178,9 +187,12 @@ static const struct mdp_kms_funcs kms_funcs = { .irq = mdp4_irq, .enable_vblank = mdp4_enable_vblank, .disable_vblank = mdp4_disable_vblank, + .enable_commit = mdp4_enable_commit, + .disable_commit = mdp4_disable_commit, .prepare_commit = mdp4_prepare_commit, + .flush_commit = mdp4_flush_commit, + .wait_flush = mdp4_wait_flush, .complete_commit = mdp4_complete_commit, - .wait_for_crtc_commit_done = mdp4_wait_for_crtc_commit_done, .get_format = mdp_get_format, .round_pixclk = mdp4_round_pixclk, .destroy = mdp4_destroy, @@ -507,8 +519,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) kms->aspace = aspace; - ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports, - ARRAY_SIZE(iommu_ports)); + ret = aspace->mmu->funcs->attach(aspace->mmu); if (ret) goto fail; } else { diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index 62e2ebe455ea..871f3514ef69 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c @@ -5,6 +5,8 @@ * Author: Vinay Simha <vinaysimha@inforcecomputing.com> */ +#include <linux/delay.h> + #include <drm/drm_crtc.h> #include <drm/drm_probe_helper.h> diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c index ecef4f5b9f26..c7df71e2fafc 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c @@ -5,8 +5,6 @@ * Author: Vinay Simha <vinaysimha@inforcecomputing.com> */ -#include <linux/gpio.h> - #include "mdp4_kms.h" struct mdp4_lvds_connector { @@ -55,7 +53,7 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector) if (panel) { drm_panel_attach(panel, connector); - ret = panel->funcs->get_modes(panel); + ret = drm_panel_get_modes(panel, connector); drm_panel_detach(panel); } diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c index e3010f023371..da3cc1d8c331 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c @@ -5,6 +5,8 @@ */ #include <drm/drm_damage_helper.h> +#include <drm/drm_fourcc.h> + #include "mdp4_kms.h" #define DOWN_SCALE_MAX 8 diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c index dd1daf0e305a..e3c4c250238b 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c @@ -14,7 +14,7 @@ struct mdp5_cfg_handler { /* mdp5_cfg must be exposed (used in mdp5.xml.h) */ const struct mdp5_cfg_hw *mdp5_cfg = NULL; -const struct mdp5_cfg_hw msm8x74v1_config = { +static const struct mdp5_cfg_hw msm8x74v1_config = { .name = "msm8x74v1", .mdp = { .count = 1, @@ -98,7 +98,7 @@ const struct mdp5_cfg_hw msm8x74v1_config = { .max_clk = 200000000, }; -const struct mdp5_cfg_hw msm8x74v2_config = { +static const struct mdp5_cfg_hw msm8x74v2_config = { .name = "msm8x74", .mdp = { .count = 1, @@ -180,7 +180,7 @@ const struct mdp5_cfg_hw msm8x74v2_config = { .max_clk = 200000000, }; -const struct mdp5_cfg_hw apq8084_config = { +static const struct mdp5_cfg_hw apq8084_config = { .name = "apq8084", .mdp = { .count = 1, @@ -275,7 +275,7 @@ const struct mdp5_cfg_hw apq8084_config = { .max_clk = 320000000, }; -const struct mdp5_cfg_hw msm8x16_config = { +static const struct mdp5_cfg_hw msm8x16_config = { .name = "msm8x16", .mdp = { .count = 1, @@ -342,7 +342,7 @@ const struct mdp5_cfg_hw msm8x16_config = { .max_clk = 320000000, }; -const struct mdp5_cfg_hw msm8x94_config = { +static const struct mdp5_cfg_hw msm8x94_config = { .name = "msm8x94", .mdp = { .count = 1, @@ -437,7 +437,7 @@ const struct mdp5_cfg_hw msm8x94_config = { .max_clk = 400000000, }; -const struct mdp5_cfg_hw msm8x96_config = { +static const struct mdp5_cfg_hw msm8x96_config = { .name = "msm8x96", .mdp = { .count = 1, @@ -545,7 +545,104 @@ const struct mdp5_cfg_hw msm8x96_config = { .max_clk = 412500000, }; -const struct mdp5_cfg_hw msm8917_config = { +const struct mdp5_cfg_hw msm8x76_config = { + .name = "msm8x76", + .mdp = { + .count = 1, + .caps = MDP_CAP_SMP | + MDP_CAP_DSC | + MDP_CAP_SRC_SPLIT | + 0, + }, + .ctl = { + .count = 3, + .base = { 0x01000, 0x01200, 0x01400 }, + .flush_hw_mask = 0xffffffff, + }, + .smp = { + .mmb_count = 10, + .mmb_size = 10240, + .clients = { + [SSPP_VIG0] = 1, [SSPP_VIG1] = 9, + [SSPP_DMA0] = 4, + [SSPP_RGB0] = 7, [SSPP_RGB1] = 8, + }, + }, + .pipe_vig = { + .count = 2, + .base = { 0x04000, 0x06000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SCALE | + MDP_PIPE_CAP_CSC | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_rgb = { + .count = 2, + .base = { 0x14000, 0x16000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_dma = { + .count = 1, + .base = { 0x24000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_cursor = { + .count = 1, + .base = { 0x440DC }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SW_PIX_EXT | + MDP_PIPE_CAP_CURSOR | + 0, + }, + .lm = { + .count = 2, + .base = { 0x44000, 0x45000 }, + .instances = { + { .id = 0, .pp = 0, .dspp = 0, + .caps = MDP_LM_CAP_DISPLAY, }, + { .id = 1, .pp = -1, .dspp = -1, + .caps = MDP_LM_CAP_WB }, + }, + .nb_stages = 8, + .max_width = 2560, + .max_height = 0xFFFF, + }, + .dspp = { + .count = 1, + .base = { 0x54000 }, + + }, + .pp = { + .count = 3, + .base = { 0x70000, 0x70800, 0x72000 }, + }, + .dsc = { + .count = 2, + .base = { 0x80000, 0x80400 }, + }, + .intf = { + .base = { 0x6a000, 0x6a800, 0x6b000 }, + .connect = { + [0] = INTF_DISABLED, + [1] = INTF_DSI, + [2] = INTF_DSI, + }, + }, + .max_clk = 360000000, +}; + +static const struct mdp5_cfg_hw msm8917_config = { .name = "msm8917", .mdp = { .count = 1, @@ -630,16 +727,129 @@ const struct mdp5_cfg_hw msm8917_config = { .max_clk = 320000000, }; -static const struct mdp5_cfg_handler cfg_handlers[] = { +static const struct mdp5_cfg_hw msm8998_config = { + .name = "msm8998", + .mdp = { + .count = 1, + .caps = MDP_CAP_DSC | + MDP_CAP_CDM | + MDP_CAP_SRC_SPLIT | + 0, + }, + .ctl = { + .count = 5, + .base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 }, + .flush_hw_mask = 0xf7ffffff, + }, + .pipe_vig = { + .count = 4, + .base = { 0x04000, 0x06000, 0x08000, 0x0a000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SCALE | + MDP_PIPE_CAP_CSC | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_rgb = { + .count = 4, + .base = { 0x14000, 0x16000, 0x18000, 0x1a000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SCALE | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_dma = { + .count = 2, /* driver supports max of 2 currently */ + .base = { 0x24000, 0x26000, 0x28000, 0x2a000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_cursor = { + .count = 2, + .base = { 0x34000, 0x36000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SW_PIX_EXT | + MDP_PIPE_CAP_CURSOR | + 0, + }, + + .lm = { + .count = 6, + .base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 }, + .instances = { + { .id = 0, .pp = 0, .dspp = 0, + .caps = MDP_LM_CAP_DISPLAY | + MDP_LM_CAP_PAIR, }, + { .id = 1, .pp = 1, .dspp = 1, + .caps = MDP_LM_CAP_DISPLAY, }, + { .id = 2, .pp = 2, .dspp = -1, + .caps = MDP_LM_CAP_DISPLAY | + MDP_LM_CAP_PAIR, }, + { .id = 3, .pp = -1, .dspp = -1, + .caps = MDP_LM_CAP_WB, }, + { .id = 4, .pp = -1, .dspp = -1, + .caps = MDP_LM_CAP_WB, }, + { .id = 5, .pp = 3, .dspp = -1, + .caps = MDP_LM_CAP_DISPLAY, }, + }, + .nb_stages = 8, + .max_width = 2560, + .max_height = 0xFFFF, + }, + .dspp = { + .count = 2, + .base = { 0x54000, 0x56000 }, + }, + .ad = { + .count = 3, + .base = { 0x78000, 0x78800, 0x79000 }, + }, + .pp = { + .count = 4, + .base = { 0x70000, 0x70800, 0x71000, 0x71800 }, + }, + .cdm = { + .count = 1, + .base = { 0x79200 }, + }, + .dsc = { + .count = 2, + .base = { 0x80000, 0x80400 }, + }, + .intf = { + .base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 }, + .connect = { + [0] = INTF_eDP, + [1] = INTF_DSI, + [2] = INTF_DSI, + [3] = INTF_HDMI, + }, + }, + .max_clk = 412500000, +}; + +static const struct mdp5_cfg_handler cfg_handlers_v1[] = { { .revision = 0, .config = { .hw = &msm8x74v1_config } }, { .revision = 2, .config = { .hw = &msm8x74v2_config } }, { .revision = 3, .config = { .hw = &apq8084_config } }, { .revision = 6, .config = { .hw = &msm8x16_config } }, { .revision = 9, .config = { .hw = &msm8x94_config } }, { .revision = 7, .config = { .hw = &msm8x96_config } }, + { .revision = 11, .config = { .hw = &msm8x76_config } }, { .revision = 15, .config = { .hw = &msm8917_config } }, }; +static const struct mdp5_cfg_handler cfg_handlers_v3[] = { + { .revision = 0, .config = { .hw = &msm8998_config } }, +}; + static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev); const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler) @@ -668,8 +878,9 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, struct drm_device *dev = mdp5_kms->dev; struct platform_device *pdev = to_platform_device(dev->dev); struct mdp5_cfg_handler *cfg_handler; + const struct mdp5_cfg_handler *cfg_handlers; struct mdp5_cfg_platform *pconfig; - int i, ret = 0; + int i, ret = 0, num_handlers; cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL); if (unlikely(!cfg_handler)) { @@ -677,7 +888,16 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, goto fail; } - if (major != 1) { + switch (major) { + case 1: + cfg_handlers = cfg_handlers_v1; + num_handlers = ARRAY_SIZE(cfg_handlers_v1); + break; + case 3: + cfg_handlers = cfg_handlers_v3; + num_handlers = ARRAY_SIZE(cfg_handlers_v3); + break; + default: DRM_DEV_ERROR(dev->dev, "unexpected MDP major version: v%d.%d\n", major, minor); ret = -ENXIO; @@ -685,7 +905,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, } /* only after mdp5_cfg global pointer's init can we access the hw */ - for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) { + for (i = 0; i < num_handlers; i++) { if (cfg_handlers[i].revision != minor) continue; mdp5_cfg = cfg_handlers[i].config.hw; diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index 78d5fa230c16..05cc04f729d6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -6,10 +6,13 @@ */ #include <linux/sort.h> + #include <drm/drm_mode.h> #include <drm/drm_crtc.h> #include <drm/drm_flip_work.h> +#include <drm/drm_fourcc.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "mdp5_kms.h" @@ -211,7 +214,6 @@ static void blend_setup(struct drm_crtc *crtc) struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline; struct mdp5_kms *mdp5_kms = get_kms(crtc); struct drm_plane *plane; - const struct mdp5_cfg_hw *hw_cfg; struct mdp5_plane_state *pstate, *pstates[STAGE_MAX + 1] = {NULL}; const struct mdp_format *format; struct mdp5_hw_mixer *mixer = pipeline->mixer; @@ -229,8 +231,6 @@ static void blend_setup(struct drm_crtc *crtc) u32 val; #define blender(stage) ((stage) - STAGE0) - hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); - spin_lock_irqsave(&mdp5_crtc->lm_lock, flags); /* ctl could be released already when we are shutting down: */ diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c index 4804cf40de14..030279d7b64b 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c @@ -253,7 +253,7 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, u32 blend_cfg; struct mdp5_hw_mixer *mixer = pipeline->mixer; - if (unlikely(WARN_ON(!mixer))) { + if (WARN_ON(!mixer)) { DRM_DEV_ERROR(ctl_mgr->dev->dev, "CTL %d cannot find LM", ctl->id); return -EINVAL; @@ -695,7 +695,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, goto fail; } - if (unlikely(WARN_ON(ctl_cfg->count > MAX_CTL))) { + if (WARN_ON(ctl_cfg->count > MAX_CTL)) { DRM_DEV_ERROR(dev->dev, "Increase static pool size to at least %d\n", ctl_cfg->count); ret = -ENOSPC; diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c index 58db08a2abfa..9b4c8d92ff32 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c @@ -7,6 +7,7 @@ #include <linux/irq.h> #include <drm/drm_print.h> +#include <drm/drm_vblank.h> #include "msm_drv.h" #include "mdp5_kms.h" diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index fec6ef1ae3b9..e43ecd4be10a 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -5,18 +5,20 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/delay.h> #include <linux/interconnect.h> #include <linux/of_irq.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_drv.h> +#include <drm/drm_file.h> +#include <drm/drm_vblank.h> + #include "msm_drv.h" #include "msm_gem.h" #include "msm_mmu.h" #include "mdp5_kms.h" -static const char *iommu_ports[] = { - "mdp_0", -}; - static int mdp5_hw_init(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); @@ -140,40 +142,52 @@ static int mdp5_global_obj_init(struct mdp5_kms *mdp5_kms) return 0; } +static void mdp5_enable_commit(struct msm_kms *kms) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + pm_runtime_get_sync(&mdp5_kms->pdev->dev); +} + +static void mdp5_disable_commit(struct msm_kms *kms) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + pm_runtime_put_sync(&mdp5_kms->pdev->dev); +} + static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); - struct device *dev = &mdp5_kms->pdev->dev; struct mdp5_global_state *global_state; global_state = mdp5_get_existing_global_state(mdp5_kms); - pm_runtime_get_sync(dev); - if (mdp5_kms->smp) mdp5_smp_prepare_commit(mdp5_kms->smp, &global_state->smp); } -static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) +static void mdp5_flush_commit(struct msm_kms *kms, unsigned crtc_mask) +{ + /* TODO */ +} + +static void mdp5_wait_flush(struct msm_kms *kms, unsigned crtc_mask) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); - struct device *dev = &mdp5_kms->pdev->dev; - struct mdp5_global_state *global_state; + struct drm_crtc *crtc; - drm_atomic_helper_wait_for_vblanks(mdp5_kms->dev, state); + for_each_crtc_mask(mdp5_kms->dev, crtc, crtc_mask) + mdp5_crtc_wait_for_commit_done(crtc); +} + +static void mdp5_complete_commit(struct msm_kms *kms, unsigned crtc_mask) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + struct mdp5_global_state *global_state; global_state = mdp5_get_existing_global_state(mdp5_kms); if (mdp5_kms->smp) mdp5_smp_complete_commit(mdp5_kms->smp, &global_state->smp); - - pm_runtime_put_sync(dev); -} - -static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms, - struct drm_crtc *crtc) -{ - mdp5_crtc_wait_for_commit_done(crtc); } static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate, @@ -215,8 +229,7 @@ static void mdp5_kms_destroy(struct msm_kms *kms) mdp5_pipe_destroy(mdp5_kms->hwpipes[i]); if (aspace) { - aspace->mmu->funcs->detach(aspace->mmu, - iommu_ports, ARRAY_SIZE(iommu_ports)); + aspace->mmu->funcs->detach(aspace->mmu); msm_gem_address_space_put(aspace); } } @@ -271,9 +284,12 @@ static const struct mdp_kms_funcs kms_funcs = { .irq = mdp5_irq, .enable_vblank = mdp5_enable_vblank, .disable_vblank = mdp5_disable_vblank, + .flush_commit = mdp5_flush_commit, + .enable_commit = mdp5_enable_commit, + .disable_commit = mdp5_disable_commit, .prepare_commit = mdp5_prepare_commit, + .wait_flush = mdp5_wait_flush, .complete_commit = mdp5_complete_commit, - .wait_for_crtc_commit_done = mdp5_wait_for_crtc_commit_done, .get_format = mdp_get_format, .round_pixclk = mdp5_round_pixclk, .set_split_display = mdp5_set_split_display, @@ -293,6 +309,10 @@ int mdp5_disable(struct mdp5_kms *mdp5_kms) mdp5_kms->enable_count--; WARN_ON(mdp5_kms->enable_count < 0); + if (mdp5_kms->tbu_rt_clk) + clk_disable_unprepare(mdp5_kms->tbu_rt_clk); + if (mdp5_kms->tbu_clk) + clk_disable_unprepare(mdp5_kms->tbu_clk); clk_disable_unprepare(mdp5_kms->ahb_clk); clk_disable_unprepare(mdp5_kms->axi_clk); clk_disable_unprepare(mdp5_kms->core_clk); @@ -313,6 +333,10 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms) clk_prepare_enable(mdp5_kms->core_clk); if (mdp5_kms->lut_clk) clk_prepare_enable(mdp5_kms->lut_clk); + if (mdp5_kms->tbu_clk) + clk_prepare_enable(mdp5_kms->tbu_clk); + if (mdp5_kms->tbu_rt_clk) + clk_prepare_enable(mdp5_kms->tbu_rt_clk); return 0; } @@ -445,14 +469,11 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) { struct drm_device *dev = mdp5_kms->dev; struct msm_drm_private *priv = dev->dev_private; - const struct mdp5_cfg_hw *hw_cfg; unsigned int num_crtcs; int i, ret, pi = 0, ci = 0; struct drm_plane *primary[MAX_BASES] = { NULL }; struct drm_plane *cursor[MAX_BASES] = { NULL }; - hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); - /* * Construct encoders and modeset initialize connector devices * for each external display interface. @@ -663,6 +684,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) struct msm_kms *kms; struct msm_gem_address_space *aspace; int irq, i, ret; + struct device *iommu_dev; /* priv->kms would have been populated by the MDP5 driver */ kms = priv->kms; @@ -702,7 +724,11 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) mdelay(16); if (config->platform.iommu) { - aspace = msm_gem_address_space_create(&pdev->dev, + iommu_dev = &pdev->dev; + if (!iommu_dev->iommu_fwspec) + iommu_dev = iommu_dev->parent; + + aspace = msm_gem_address_space_create(iommu_dev, config->platform.iommu, "mdp5"); if (IS_ERR(aspace)) { ret = PTR_ERR(aspace); @@ -711,8 +737,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) kms->aspace = aspace; - ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports, - ARRAY_SIZE(iommu_ports)); + ret = aspace->mmu->funcs->attach(aspace->mmu); if (ret) { DRM_DEV_ERROR(&pdev->dev, "failed to attach iommu: %d\n", ret); @@ -948,6 +973,8 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) /* optional clocks: */ get_clk(pdev, &mdp5_kms->lut_clk, "lut", false); + get_clk(pdev, &mdp5_kms->tbu_clk, "tbu", false); + get_clk(pdev, &mdp5_kms->tbu_rt_clk, "tbu_rt", false); /* we need to set a default rate before enabling. Set a safe * rate first, then figure out hw revision, and then set a diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h index d1bf4fdfc815..128866742593 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h @@ -53,6 +53,8 @@ struct mdp5_kms { struct clk *ahb_clk; struct clk *core_clk; struct clk *lut_clk; + struct clk *tbu_clk; + struct clk *tbu_rt_clk; struct clk *vsync_clk; /* diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c index c7e6725693ea..83423092de2f 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c @@ -6,7 +6,9 @@ */ #include <drm/drm_damage_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_print.h> + #include "mdp5_kms.h" struct mdp5_plane { diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index 776337f85a68..d7fa2c49e741 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c @@ -5,6 +5,7 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <drm/drm_fourcc.h> #include <drm/drm_util.h> #include "mdp5_kms.h" @@ -120,7 +121,6 @@ uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, struct mdp5_kms *mdp5_kms = get_kms(smp); int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg); int i, hsub, nplanes, nlines; - u32 fmt = format->base.pixel_format; uint32_t blkcfg = 0; nplanes = info->num_planes; @@ -134,7 +134,6 @@ uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, * them together, writes to SMP using a single client. */ if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) { - fmt = DRM_FORMAT_NV24; nplanes = 2; /* if decimation is enabled, HW decimates less on the diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c index 8afb0f9c04bb..5495d8b3f5b9 100644 --- a/drivers/gpu/drm/msm/disp/mdp_format.c +++ b/drivers/gpu/drm/msm/disp/mdp_format.c @@ -174,7 +174,7 @@ const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format, struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type type) { - if (unlikely(WARN_ON(type >= CSC_MAX))) + if (WARN_ON(type >= CSC_MAX)) return NULL; return &csc_convert[type]; diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 0da8a4e428ad..4de771d6f0be 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -9,6 +9,7 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> @@ -177,6 +178,8 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, int msm_dsi_host_init(struct msm_dsi *msm_dsi); int msm_dsi_runtime_suspend(struct device *dev); int msm_dsi_runtime_resume(struct device *dev); +int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host); +int dsi_link_clk_set_rate_v2(struct msm_dsi_host *msm_host); 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); diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index b7b7c1a9164a..813d69deb5e8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -66,6 +66,26 @@ static const struct msm_dsi_config msm8916_dsi_cfg = { .num_dsi = 1, }; +static const char * const dsi_8976_bus_clk_names[] = { + "mdp_core", "iface", "bus", +}; + +static const struct msm_dsi_config msm8976_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .reg_cfg = { + .num = 3, + .regs = { + {"gdsc", -1, -1}, + {"vdda", 100000, 100}, /* 1.2 V */ + {"vddio", 100000, 100}, /* 1.8 V */ + }, + }, + .bus_clk_names = dsi_8976_bus_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_8976_bus_clk_names), + .io_start = { 0x1a94000, 0x1a96000 }, + .num_dsi = 2, +}; + static const struct msm_dsi_config msm8994_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, .reg_cfg = { @@ -133,6 +153,10 @@ static const char * const dsi_sdm845_bus_clk_names[] = { "iface", "bus", }; +static const char * const dsi_sc7180_bus_clk_names[] = { + "iface", "bus", +}; + static const struct msm_dsi_config sdm845_dsi_cfg = { .io_offset = DSI_6G_REG_SHIFT, .reg_cfg = { @@ -147,7 +171,22 @@ static const struct msm_dsi_config sdm845_dsi_cfg = { .num_dsi = 2, }; -const static struct msm_dsi_host_cfg_ops msm_dsi_v2_host_ops = { +static const struct msm_dsi_config sc7180_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .reg_cfg = { + .num = 1, + .regs = { + {"vdda", 21800, 4 }, /* 1.2 V */ + }, + }, + .bus_clk_names = dsi_sc7180_bus_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_sc7180_bus_clk_names), + .io_start = { 0xae94000 }, + .num_dsi = 1, +}; + +static const struct msm_dsi_host_cfg_ops msm_dsi_v2_host_ops = { + .link_clk_set_rate = dsi_link_clk_set_rate_v2, .link_clk_enable = dsi_link_clk_enable_v2, .link_clk_disable = dsi_link_clk_disable_v2, .clk_init_ver = dsi_clk_init_v2, @@ -158,7 +197,8 @@ const static struct msm_dsi_host_cfg_ops msm_dsi_v2_host_ops = { .calc_clk_rate = dsi_calc_clk_rate_v2, }; -const static struct msm_dsi_host_cfg_ops msm_dsi_6g_host_ops = { +static const struct msm_dsi_host_cfg_ops msm_dsi_6g_host_ops = { + .link_clk_set_rate = dsi_link_clk_set_rate_6g, .link_clk_enable = dsi_link_clk_enable_6g, .link_clk_disable = dsi_link_clk_disable_6g, .clk_init_ver = NULL, @@ -169,7 +209,8 @@ const static struct msm_dsi_host_cfg_ops msm_dsi_6g_host_ops = { .calc_clk_rate = dsi_calc_clk_rate_6g, }; -const static struct msm_dsi_host_cfg_ops msm_dsi_6g_v2_host_ops = { +static const struct msm_dsi_host_cfg_ops msm_dsi_6g_v2_host_ops = { + .link_clk_set_rate = dsi_link_clk_set_rate_6g, .link_clk_enable = dsi_link_clk_enable_6g, .link_clk_disable = dsi_link_clk_disable_6g, .clk_init_ver = dsi_clk_init_6g_v2, @@ -197,10 +238,15 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { &msm8916_dsi_cfg, &msm_dsi_6g_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1, &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, + &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_4_1, + &sc7180_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 e2b7a7dfbe49..217e24a65178 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -17,8 +17,10 @@ #define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000 #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 +#define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 #define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 +#define MSM_DSI_6G_VER_MINOR_V2_4_1 0x20040001 #define MSM_DSI_V2_VER_MINOR_8064 0x0 @@ -34,6 +36,7 @@ struct msm_dsi_config { }; struct msm_dsi_host_cfg_ops { + int (*link_clk_set_rate)(struct msm_dsi_host *msm_host); int (*link_clk_enable)(struct msm_dsi_host *msm_host); void (*link_clk_disable)(struct msm_dsi_host *msm_host); int (*clk_init_ver)(struct msm_dsi_host *msm_host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index aa35d18ab43c..11ae5b8444c3 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -5,19 +5,19 @@ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> +#include <linux/mfd/syscon.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> +#include <linux/of_graph.h> #include <linux/of_irq.h> #include <linux/pinctrl/consumer.h> -#include <linux/of_graph.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spinlock.h> -#include <linux/mfd/syscon.h> -#include <linux/regmap.h> + #include <video/mipi_display.h> #include "dsi.h" @@ -26,6 +26,8 @@ #include "dsi_cfg.h" #include "msm_kms.h" +#define DSI_RESET_TOGGLE_DELAY_MS 20 + static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) { u32 ver; @@ -421,15 +423,15 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) } msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk); - if (!msm_host->byte_clk_src) { - ret = -ENODEV; + if (IS_ERR(msm_host->byte_clk_src)) { + ret = PTR_ERR(msm_host->byte_clk_src); pr_err("%s: can't find byte_clk clock. ret=%d\n", __func__, ret); goto exit; } msm_host->pixel_clk_src = clk_get_parent(msm_host->pixel_clk); - if (!msm_host->pixel_clk_src) { - ret = -ENODEV; + if (IS_ERR(msm_host->pixel_clk_src)) { + ret = PTR_ERR(msm_host->pixel_clk_src); pr_err("%s: can't find pixel_clk clock. ret=%d\n", __func__, ret); goto exit; } @@ -503,7 +505,7 @@ int msm_dsi_runtime_resume(struct device *dev) return dsi_bus_clk_enable(msm_host); } -int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) +int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) { int ret; @@ -513,13 +515,13 @@ int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); if (ret) { pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret); - goto error; + return ret; } ret = clk_set_rate(msm_host->pixel_clk, msm_host->pixel_clk_rate); if (ret) { pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret); - goto error; + return ret; } if (msm_host->byte_intf_clk) { @@ -528,10 +530,18 @@ int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) if (ret) { pr_err("%s: Failed to set rate byte intf clk, %d\n", __func__, ret); - goto error; + return ret; } } + return 0; +} + + +int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) +{ + int ret; + ret = clk_prepare_enable(msm_host->esc_clk); if (ret) { pr_err("%s: Failed to enable dsi esc clk\n", __func__); @@ -571,7 +581,7 @@ error: return ret; } -int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) +int dsi_link_clk_set_rate_v2(struct msm_dsi_host *msm_host) { int ret; @@ -582,27 +592,34 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); if (ret) { pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret); - goto error; + return ret; } ret = clk_set_rate(msm_host->esc_clk, msm_host->esc_clk_rate); if (ret) { pr_err("%s: Failed to set rate esc clk, %d\n", __func__, ret); - goto error; + return ret; } ret = clk_set_rate(msm_host->src_clk, msm_host->src_clk_rate); if (ret) { pr_err("%s: Failed to set rate src clk, %d\n", __func__, ret); - goto error; + return ret; } ret = clk_set_rate(msm_host->pixel_clk, msm_host->pixel_clk_rate); if (ret) { pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret); - goto error; + return ret; } + return 0; +} + +int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) +{ + int ret; + ret = clk_prepare_enable(msm_host->byte_clk); if (ret) { pr_err("%s: Failed to enable dsi byte clk\n", __func__); @@ -816,7 +833,7 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, u32 flags = msm_host->mode_flags; enum mipi_dsi_pixel_format mipi_fmt = msm_host->format; const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; - u32 data = 0; + u32 data = 0, lane_ctrl = 0; if (!enable) { dsi_write(msm_host, REG_DSI_CTRL, 0); @@ -904,9 +921,11 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL, DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(msm_host->dlane_swap)); - if (!(flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) + if (!(flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) { + lane_ctrl = dsi_read(msm_host, REG_DSI_LANE_CTRL); dsi_write(msm_host, REG_DSI_LANE_CTRL, - DSI_LANE_CTRL_CLKLN_HS_FORCE_REQUEST); + lane_ctrl | DSI_LANE_CTRL_CLKLN_HS_FORCE_REQUEST); + } data |= DSI_CTRL_ENABLE; @@ -986,7 +1005,7 @@ static void dsi_sw_reset(struct msm_dsi_host *msm_host) wmb(); /* clocks need to be enabled before reset */ dsi_write(msm_host, REG_DSI_RESET, 1); - wmb(); /* make sure reset happen */ + msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */ dsi_write(msm_host, REG_DSI_RESET, 0); } @@ -1291,14 +1310,13 @@ static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len) static int dsi_cmd_dma_rx(struct msm_dsi_host *msm_host, u8 *buf, int rx_byte, int pkt_size) { - u32 *lp, *temp, data; + u32 *temp, data; int i, j = 0, cnt; u32 read_cnt; u8 reg[16]; int repeated_bytes = 0; int buf_offset = buf - msm_host->rx_buf; - lp = (u32 *)buf; temp = (u32 *)reg; cnt = (rx_byte + 3) >> 2; if (cnt > 4) @@ -1396,7 +1414,7 @@ static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host) /* dsi controller can only be reset while clocks are running */ dsi_write(msm_host, REG_DSI_RESET, 1); - wmb(); /* make sure reset happen */ + msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */ dsi_write(msm_host, REG_DSI_RESET, 0); wmb(); /* controller out of reset */ dsi_write(msm_host, REG_DSI_CTRL, data0); @@ -1995,6 +2013,7 @@ int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, * mdp clock need to be enabled to receive dsi interrupt */ pm_runtime_get_sync(&msm_host->pdev->dev); + cfg_hnd->ops->link_clk_set_rate(msm_host); cfg_hnd->ops->link_clk_enable(msm_host); /* TODO: vote for bus bandwidth */ @@ -2343,7 +2362,9 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, } pm_runtime_get_sync(&msm_host->pdev->dev); - ret = cfg_hnd->ops->link_clk_enable(msm_host); + ret = cfg_hnd->ops->link_clk_set_rate(msm_host); + if (!ret) + ret = cfg_hnd->ops->link_clk_enable(msm_host); if (ret) { pr_err("%s: failed to enable link clocks. ret=%d\n", __func__, ret); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 271aa7bbca92..104115d112eb 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -329,7 +329,7 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector) * attached to the drm_panel. */ drm_panel_attach(panel, connector); - num = drm_panel_get_modes(panel); + num = drm_panel_get_modes(panel, connector); if (!num) return 0; @@ -432,20 +432,8 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) } } - if (panel) { - ret = drm_panel_enable(panel); - if (ret) { - pr_err("%s: enable panel %d failed, %d\n", __func__, id, - ret); - goto panel_en_fail; - } - } - return; -panel_en_fail: - if (is_dual_dsi && msm_dsi1) - msm_dsi_host_disable(msm_dsi1->host); host1_en_fail: msm_dsi_host_disable(host); host_en_fail: @@ -464,12 +452,51 @@ phy_en_fail: static void dsi_mgr_bridge_enable(struct drm_bridge *bridge) { - DBG(""); + int id = dsi_mgr_bridge_get_id(bridge); + struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); + struct drm_panel *panel = msm_dsi->panel; + bool is_dual_dsi = IS_DUAL_DSI(); + int ret; + + DBG("id=%d", id); + if (!msm_dsi_device_connected(msm_dsi)) + return; + + /* Do nothing with the host if it is slave-DSI in case of dual DSI */ + if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) + return; + + if (panel) { + ret = drm_panel_enable(panel); + if (ret) { + pr_err("%s: enable panel %d failed, %d\n", __func__, id, + ret); + } + } } static void dsi_mgr_bridge_disable(struct drm_bridge *bridge) { - DBG(""); + int id = dsi_mgr_bridge_get_id(bridge); + struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); + struct drm_panel *panel = msm_dsi->panel; + bool is_dual_dsi = IS_DUAL_DSI(); + int ret; + + DBG("id=%d", id); + if (!msm_dsi_device_connected(msm_dsi)) + return; + + /* Do nothing with the host if it is slave-DSI in case of dual DSI */ + if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) + return; + + if (panel) { + ret = drm_panel_disable(panel); + if (ret) + pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, + ret); + } } static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) @@ -495,13 +522,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) goto disable_phy; - if (panel) { - ret = drm_panel_disable(panel); - if (ret) - pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, - ret); - } - ret = msm_dsi_host_disable(host); if (ret) pr_err("%s: host %d disable failed, %d\n", __func__, id, ret); diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 4097eca1b3ef..b0cfa67d2a57 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -145,7 +145,7 @@ int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing, { const unsigned long bit_rate = clk_req->bitclk_rate; const unsigned long esc_rate = clk_req->escclk_rate; - s32 ui, ui_x8, lpx; + s32 ui, ui_x8; s32 tmax, tmin; s32 pcnt0 = 50; s32 pcnt1 = 50; @@ -175,7 +175,6 @@ int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing, ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000); ui_x8 = ui << 3; - lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000); temp = S_DIV_ROUND_UP(38 * coeff - val_ckln * ui, ui_x8); tmin = max_t(s32, temp, 0); @@ -262,7 +261,7 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, { const unsigned long bit_rate = clk_req->bitclk_rate; const unsigned long esc_rate = clk_req->escclk_rate; - s32 ui, ui_x8, lpx; + s32 ui, ui_x8; s32 tmax, tmin; s32 pcnt0 = 50; s32 pcnt1 = 50; @@ -284,7 +283,6 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000); ui_x8 = ui << 3; - lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000); temp = S_DIV_ROUND_UP(38 * coeff, ui_x8); tmin = max_t(s32, temp, 0); @@ -396,8 +394,12 @@ static int dsi_phy_regulator_init(struct msm_dsi_phy *phy) ret = devm_regulator_bulk_get(dev, num, s); if (ret < 0) { - DRM_DEV_ERROR(dev, "%s: failed to init regulator, ret=%d\n", - __func__, ret); + if (ret != -EPROBE_DEFER) { + DRM_DEV_ERROR(dev, + "%s: failed to init regulator, ret=%d\n", + __func__, ret); + } + return ret; } @@ -481,6 +483,8 @@ static const struct of_device_id dsi_phy_dt_match[] = { #ifdef CONFIG_DRM_MSM_DSI_28NM_PHY { .compatible = "qcom,dsi-phy-28nm-hpm", .data = &dsi_phy_28nm_hpm_cfgs }, + { .compatible = "qcom,dsi-phy-28nm-hpm-fam-b", + .data = &dsi_phy_28nm_hpm_famb_cfgs }, { .compatible = "qcom,dsi-phy-28nm-lp", .data = &dsi_phy_28nm_lp_cfgs }, #endif @@ -584,10 +588,8 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) } ret = dsi_phy_regulator_init(phy); - if (ret) { - DRM_DEV_ERROR(dev, "%s: failed to init regulator\n", __func__); + if (ret) goto fail; - } phy->ahb_clk = msm_clk_get(pdev, "iface"); if (IS_ERR(phy->ahb_clk)) { diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index c4069ce6afe6..24b294ed3059 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -40,6 +40,7 @@ struct msm_dsi_phy_cfg { }; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; 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 c3a61876470f..1594f1422372 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -3,6 +3,8 @@ * Copyright (c) 2016, The Linux Foundation. All rights reserved. */ +#include <linux/delay.h> + #include "dsi_phy.h" #include "dsi.xml.h" diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c index b3f678f6c2aa..c3c580cfd8b1 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c @@ -39,15 +39,10 @@ static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy, DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); } -static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable) +static void dsi_28nm_phy_regulator_enable_dcdc(struct msm_dsi_phy *phy) { void __iomem *base = phy->reg_base; - if (!enable) { - dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0); - return; - } - dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0); dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1); dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0); @@ -56,6 +51,39 @@ static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable) dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9); dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7); dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20); + dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00); +} + +static void dsi_28nm_phy_regulator_enable_ldo(struct msm_dsi_phy *phy) +{ + void __iomem *base = phy->reg_base; + + dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0); + dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0); + dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0x7); + dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0); + dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x1); + dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x1); + dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20); + + if (phy->cfg->type == MSM_DSI_PHY_28NM_LP) + dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x05); + else + dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x0d); +} + +static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable) +{ + if (!enable) { + dsi_phy_write(phy->reg_base + + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0); + return; + } + + if (phy->regulator_ldo_mode) + dsi_28nm_phy_regulator_enable_ldo(phy); + else + dsi_28nm_phy_regulator_enable_dcdc(phy); } static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, @@ -77,8 +105,6 @@ static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, dsi_28nm_phy_regulator_ctrl(phy, true); - dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00); - dsi_28nm_dphy_set_timing(phy, timing); dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00); @@ -142,6 +168,24 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = { .num_dsi_phy = 2, }; +const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs = { + .type = MSM_DSI_PHY_28NM_HPM, + .src_pll_truthtable = { {true, true}, {false, true} }, + .reg_cfg = { + .num = 1, + .regs = { + {"vddio", 100000, 100}, + }, + }, + .ops = { + .enable = dsi_28nm_phy_enable, + .disable = dsi_28nm_phy_disable, + .init = msm_dsi_phy_init_common, + }, + .io_start = { 0x1a94400, 0x1a96400 }, + .num_dsi_phy = 2, +}; + const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = { .type = MSM_DSI_PHY_28NM_LP, .src_pll_truthtable = { {true, true}, {true, true} }, diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c index a198f51d47b4..f22583353957 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -3,6 +3,8 @@ * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. */ +#include <linux/delay.h> + #include "dsi_phy.h" #include "dsi.xml.h" diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h index 118bebe53de3..c6a3623f905d 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h @@ -6,8 +6,8 @@ #ifndef __DSI_PLL_H__ #define __DSI_PLL_H__ -#include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/delay.h> #include "dsi.h" diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c index 8f6100db90ed..1c894548dd72 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c @@ -751,9 +751,9 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); hw = clk_hw_register_mux(dev, clk_name, - (const char *[]){ + ((const char *[]){ parent, parent2, parent3, parent4 - }, 4, 0, pll_10nm->phy_cmn_mmio + + }), 4, 0, pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, 0, 2, 0, NULL); if (IS_ERR(hw)) { diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c index 8c99e01ae332..6dffd7f4a99b 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c @@ -554,9 +554,9 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); clks[num++] = clk_register_mux(dev, clk_name, - (const char *[]){ + ((const char *[]){ parent1, parent2 - }, 2, CLK_SET_RATE_PARENT, pll_28nm->mmio + + }), 2, CLK_SET_RATE_PARENT, pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL); snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id); diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c index 0f312ac5b624..ad4e963ccd9b 100644 --- a/drivers/gpu/drm/msm/edp/edp.c +++ b/drivers/gpu/drm/msm/edp/edp.c @@ -178,7 +178,9 @@ int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev, goto fail; } - encoder->bridge = edp->bridge; + ret = drm_bridge_attach(encoder, edp->bridge, NULL); + if (ret) + goto fail; priv->bridges[priv->num_bridges++] = edp->bridge; priv->connectors[priv->num_connectors++] = edp->connector; diff --git a/drivers/gpu/drm/msm/edp/edp.h b/drivers/gpu/drm/msm/edp/edp.h index f2c17858a703..eb34243dad53 100644 --- a/drivers/gpu/drm/msm/edp/edp.h +++ b/drivers/gpu/drm/msm/edp/edp.h @@ -10,6 +10,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/platform_device.h> +#include <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_dp_helper.h> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c index 2950bba4aca9..b65b5cc2dba2 100644 --- a/drivers/gpu/drm/msm/edp/edp_bridge.c +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c @@ -55,8 +55,14 @@ static void edp_bridge_mode_set(struct drm_bridge *bridge, DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if ((connector->encoder != NULL) && - (connector->encoder->bridge == bridge)) { + struct drm_encoder *encoder = connector->encoder; + struct drm_bridge *first_bridge; + + if (!connector->encoder) + continue; + + first_bridge = drm_bridge_chain_get_first_bridge(encoder); + if (bridge == first_bridge) { msm_edp_ctrl_timing_cfg(edp->ctrl, adjusted_mode, &connector->display_info); break; diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 7f3dd3ffe2c9..0d9657cc70db 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -89,7 +89,6 @@ struct edp_ctrl { /* edid raw data */ struct edid *edid; - struct drm_dp_link dp_link; struct drm_dp_aux *drm_aux; /* dpcd raw data */ @@ -403,7 +402,7 @@ static void edp_fill_link_cfg(struct edp_ctrl *ctrl) u32 prate; u32 lrate; u32 bpp; - u8 max_lane = ctrl->dp_link.num_lanes; + u8 max_lane = drm_dp_max_lane_count(ctrl->dpcd); u8 lane; prate = ctrl->pixel_rate; @@ -413,7 +412,7 @@ static void edp_fill_link_cfg(struct edp_ctrl *ctrl) * By default, use the maximum link rate and minimum lane count, * so that we can do rate down shift during link training. */ - ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate); + ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; prate *= bpp; prate /= 8; /* in kByte */ @@ -439,7 +438,7 @@ static void edp_config_ctrl(struct edp_ctrl *ctrl) data = EDP_CONFIGURATION_CTRL_LANES(ctrl->lane_cnt - 1); - if (ctrl->dp_link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) + if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) data |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING; depth = EDP_6BIT; @@ -701,7 +700,7 @@ static int edp_link_rate_down_shift(struct edp_ctrl *ctrl) rate = ctrl->link_rate; lane = ctrl->lane_cnt; - max_lane = ctrl->dp_link.num_lanes; + max_lane = drm_dp_max_lane_count(ctrl->dpcd); bpp = ctrl->color_depth * 3; prate = ctrl->pixel_rate; @@ -751,18 +750,22 @@ static int edp_clear_training_pattern(struct edp_ctrl *ctrl) static int edp_do_link_train(struct edp_ctrl *ctrl) { + u8 values[2]; int ret; - struct drm_dp_link dp_link; DBG(""); /* * Set the current link rate and lane cnt to panel. They may have been * adjusted and the values are different from them in DPCD CAP */ - dp_link.num_lanes = ctrl->lane_cnt; - dp_link.rate = drm_dp_bw_code_to_link_rate(ctrl->link_rate); - dp_link.capabilities = ctrl->dp_link.capabilities; - if (drm_dp_link_configure(ctrl->drm_aux, &dp_link) < 0) + values[0] = ctrl->lane_cnt; + values[1] = ctrl->link_rate; + + if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) + values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + if (drm_dp_dpcd_write(ctrl->drm_aux, DP_LINK_BW_SET, values, + sizeof(values)) < 0) return EDP_TRAIN_FAIL; ctrl->v_level = 0; /* start from default level */ @@ -952,6 +955,7 @@ static void edp_ctrl_on_worker(struct work_struct *work) { struct edp_ctrl *ctrl = container_of( work, struct edp_ctrl, on_work); + u8 value; int ret; mutex_lock(&ctrl->dev_mutex); @@ -965,9 +969,27 @@ static void edp_ctrl_on_worker(struct work_struct *work) edp_ctrl_link_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); - ret = drm_dp_link_power_up(ctrl->drm_aux, &ctrl->dp_link); - if (ret) - goto fail; + + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { + ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); + if (ret < 0) + goto fail; + + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D0; + + ret = drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); + if (ret < 0) + goto fail; + + /* + * According to the DP 1.1 specification, a "Sink Device must + * exit the power saving state within 1 ms" (Section 2.5.3.1, + * Table 5-52, "Sink Control Field" (register 0x600). + */ + usleep_range(1000, 2000); + } ctrl->power_on = true; @@ -1011,7 +1033,19 @@ static void edp_ctrl_off_worker(struct work_struct *work) edp_state_ctrl(ctrl, 0); - drm_dp_link_power_down(ctrl->drm_aux, &ctrl->dp_link); + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { + u8 value; + int ret; + + ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); + if (ret > 0) { + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D3; + + drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); + } + } edp_ctrl_irq_enable(ctrl, 0); @@ -1225,14 +1259,8 @@ int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, edp_ctrl_irq_enable(ctrl, 1); } - ret = drm_dp_link_probe(ctrl->drm_aux, &ctrl->dp_link); - if (ret) { - pr_err("%s: read dpcd cap failed, %d\n", __func__, ret); - goto disable_ret; - } - /* Initialize link rate as panel max link rate */ - ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate); + ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc); if (!ctrl->edid) { diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 0e4217be3f00..1a9b6289637d 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -327,7 +327,9 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, goto fail; } - encoder->bridge = hdmi->bridge; + ret = drm_bridge_attach(encoder, hdmi->bridge, NULL); + if (ret) + goto fail; priv->bridges[priv->num_bridges++] = hdmi->bridge; priv->connectors[priv->num_connectors++] = hdmi->connector; @@ -425,38 +427,6 @@ static const struct { { "qcom,hdmi-tx-mux-lpm", true, 1, "HDMI_MUX_LPM" }, }; -static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name) -{ - int gpio; - - /* try with the gpio names as in the table (downstream bindings) */ - gpio = of_get_named_gpio(of_node, name, 0); - if (gpio < 0) { - char name2[32]; - - /* try with the gpio names as in the upstream bindings */ - snprintf(name2, sizeof(name2), "%s-gpios", name); - gpio = of_get_named_gpio(of_node, name2, 0); - if (gpio < 0) { - char name3[32]; - - /* - * try again after stripping out the "qcom,hdmi-tx" - * prefix. This is mainly to match "hpd-gpios" used - * in the upstream bindings - */ - if (sscanf(name2, "qcom,hdmi-tx-%s", name3)) - gpio = of_get_named_gpio(of_node, name3, 0); - } - - if (gpio < 0) { - DBG("failed to get gpio: %s (%d)", name, gpio); - gpio = -1; - } - } - return gpio; -} - /* * HDMI audio codec callbacks */ @@ -582,11 +552,39 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) hdmi_cfg->qfprom_mmio_name = "qfprom_physical"; for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) { - hdmi_cfg->gpios[i].num = msm_hdmi_get_gpio(of_node, - msm_hdmi_gpio_pdata[i].name); + const char *name = msm_hdmi_gpio_pdata[i].name; + struct gpio_desc *gpiod; + + /* + * We are fetching the GPIO lines "as is" since the connector + * code is enabling and disabling the lines. Until that point + * the power-on default value will be kept. + */ + gpiod = devm_gpiod_get_optional(dev, name, GPIOD_ASIS); + /* This will catch e.g. -PROBE_DEFER */ + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + if (!gpiod) { + /* Try a second time, stripping down the name */ + char name3[32]; + + /* + * Try again after stripping out the "qcom,hdmi-tx" + * prefix. This is mainly to match "hpd-gpios" used + * in the upstream bindings. + */ + if (sscanf(name, "qcom,hdmi-tx-%s", name3)) + gpiod = devm_gpiod_get_optional(dev, name3, GPIOD_ASIS); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + if (!gpiod) + DBG("failed to get gpio: %s", name); + } + hdmi_cfg->gpios[i].gpiod = gpiod; + if (gpiod) + gpiod_set_consumer_name(gpiod, msm_hdmi_gpio_pdata[i].label); hdmi_cfg->gpios[i].output = msm_hdmi_gpio_pdata[i].output; hdmi_cfg->gpios[i].value = msm_hdmi_gpio_pdata[i].value; - hdmi_cfg->gpios[i].label = msm_hdmi_gpio_pdata[i].label; } dev->platform_data = hdmi_cfg; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 982865866a29..d0b84f0abee1 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -11,8 +11,11 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> #include <linux/hdmi.h> +#include <drm/drm_bridge.h> + #include "msm_drv.h" #include "hdmi.xml.h" @@ -22,10 +25,9 @@ struct hdmi_phy; struct hdmi_platform_config; struct hdmi_gpio_data { - int num; + struct gpio_desc *gpiod; bool output; int value; - const char *label; }; struct hdmi_audio { diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index c8dbd82854c2..ba81338a9bf8 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -4,6 +4,8 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/delay.h> + #include "hdmi.h" struct hdmi_bridge { diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index 07b4cb877d82..58707a1f3878 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -4,7 +4,8 @@ * Author: Rob Clark <robdclark@gmail.com> */ -#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/pinctrl/consumer.h> #include "msm_kms.h" @@ -68,30 +69,21 @@ static void msm_hdmi_phy_reset(struct hdmi *hdmi) static int gpio_config(struct hdmi *hdmi, bool on) { - struct device *dev = &hdmi->pdev->dev; const struct hdmi_platform_config *config = hdmi->config; - int ret, i; + int i; if (on) { for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) { struct hdmi_gpio_data gpio = config->gpios[i]; - if (gpio.num != -1) { - ret = gpio_request(gpio.num, gpio.label); - if (ret) { - DRM_DEV_ERROR(dev, - "'%s'(%d) gpio_request failed: %d\n", - gpio.label, gpio.num, ret); - goto err; - } - + if (gpio.gpiod) { if (gpio.output) { - gpio_direction_output(gpio.num, - gpio.value); + gpiod_direction_output(gpio.gpiod, + gpio.value); } else { - gpio_direction_input(gpio.num); - gpio_set_value_cansleep(gpio.num, - gpio.value); + gpiod_direction_input(gpio.gpiod); + gpiod_set_value_cansleep(gpio.gpiod, + gpio.value); } } } @@ -101,29 +93,20 @@ static int gpio_config(struct hdmi *hdmi, bool on) for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) { struct hdmi_gpio_data gpio = config->gpios[i]; - if (gpio.num == -1) + if (!gpio.gpiod) continue; if (gpio.output) { int value = gpio.value ? 0 : 1; - gpio_set_value_cansleep(gpio.num, value); + gpiod_set_value_cansleep(gpio.gpiod, value); } - - gpio_free(gpio.num); - }; + } DBG("gpio off"); } return 0; -err: - while (i--) { - if (config->gpios[i].num != -1) - gpio_free(config->gpios[i].num); - } - - return ret; } static void enable_hpd_clocks(struct hdmi *hdmi, bool enable) @@ -311,7 +294,7 @@ static enum drm_connector_status detect_gpio(struct hdmi *hdmi) const struct hdmi_platform_config *config = hdmi->config; struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX]; - return gpio_get_value(hpd_gpio.num) ? + return gpiod_get_value(hpd_gpio.gpiod) ? connector_status_connected : connector_status_disconnected; } @@ -330,7 +313,7 @@ static enum drm_connector_status hdmi_connector_detect( * some platforms may not have hpd gpio. Rely only on the status * provided by REG_HDMI_HPD_INT_STATUS in this case. */ - if (hpd_gpio.num == -1) + if (!hpd_gpio.gpiod) return detect_reg(hdmi); do { @@ -450,8 +433,10 @@ struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi) connector = &hdmi_connector->base; - drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); + drm_connector_init_with_ddc(hdmi->dev, connector, + &hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + hdmi->i2c); drm_connector_helper_add(connector, &msm_hdmi_connector_helper_funcs); connector->polled = DRM_CONNECTOR_POLL_CONNECT | diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 1697e61f9c2f..8a38d4b95102 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -29,8 +29,12 @@ static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy) reg = devm_regulator_get(dev, cfg->reg_names[i]); if (IS_ERR(reg)) { ret = PTR_ERR(reg); - DRM_DEV_ERROR(dev, "failed to get phy regulator: %s (%d)\n", - cfg->reg_names[i], ret); + if (ret != -EPROBE_DEFER) { + DRM_DEV_ERROR(dev, + "failed to get phy regulator: %s (%d)\n", + cfg->reg_names[i], ret); + } + return ret; } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c index fe82ad38aa7a..a8f3b2cbfdc5 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c @@ -4,6 +4,7 @@ */ #include <linux/clk-provider.h> +#include <linux/delay.h> #include "hdmi.h" diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c index 1acc33ce9d52..95f2928cb2cb 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c @@ -4,6 +4,8 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/delay.h> + #include "hdmi.h" static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c index e24a11d91945..562dfac67792 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c @@ -6,6 +6,8 @@ */ #include <linux/clk-provider.h> +#include <linux/delay.h> + #include "hdmi.h" struct hdmi_pll_8960 { diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index dd16babdd8c0..5ccfad794c6a 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -5,50 +5,138 @@ */ #include <drm/drm_atomic_uapi.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_vblank.h> +#include "msm_atomic_trace.h" #include "msm_drv.h" #include "msm_gem.h" #include "msm_kms.h" -static void msm_atomic_wait_for_commit_done(struct drm_device *dev, - struct drm_atomic_state *old_state) +int msm_atomic_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) { - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state; - struct msm_drm_private *priv = old_state->dev->dev_private; + struct msm_drm_private *priv = plane->dev->dev_private; struct msm_kms *kms = priv->kms; - int i; - for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { - if (!new_crtc_state->active) - continue; + if (!new_state->fb) + return 0; + + drm_gem_fb_prepare_fb(plane, new_state); + + return msm_framebuffer_prepare(new_state->fb, kms->aspace); +} + +static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx) +{ + unsigned crtc_mask = BIT(crtc_idx); - if (drm_crtc_vblank_get(crtc)) - continue; + trace_msm_atomic_async_commit_start(crtc_mask); - kms->funcs->wait_for_crtc_commit_done(kms, crtc); + mutex_lock(&kms->commit_lock); - drm_crtc_vblank_put(crtc); + if (!(kms->pending_crtc_mask & crtc_mask)) { + mutex_unlock(&kms->commit_lock); + goto out; } + + kms->pending_crtc_mask &= ~crtc_mask; + + kms->funcs->enable_commit(kms); + + /* + * Flush hardware updates: + */ + trace_msm_atomic_flush_commit(crtc_mask); + kms->funcs->flush_commit(kms, crtc_mask); + mutex_unlock(&kms->commit_lock); + + /* + * Wait for flush to complete: + */ + trace_msm_atomic_wait_flush_start(crtc_mask); + kms->funcs->wait_flush(kms, crtc_mask); + trace_msm_atomic_wait_flush_finish(crtc_mask); + + mutex_lock(&kms->commit_lock); + kms->funcs->complete_commit(kms, crtc_mask); + mutex_unlock(&kms->commit_lock); + kms->funcs->disable_commit(kms); + +out: + trace_msm_atomic_async_commit_finish(crtc_mask); } -int msm_atomic_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *new_state) +static enum hrtimer_restart msm_atomic_pending_timer(struct hrtimer *t) { - struct msm_drm_private *priv = plane->dev->dev_private; - struct msm_kms *kms = priv->kms; - struct drm_gem_object *obj; - struct dma_fence *fence; + struct msm_pending_timer *timer = container_of(t, + struct msm_pending_timer, timer); + struct msm_drm_private *priv = timer->kms->dev->dev_private; - if (!new_state->fb) - return 0; + queue_work(priv->wq, &timer->work); - obj = msm_framebuffer_bo(new_state->fb, 0); - fence = reservation_object_get_excl_rcu(obj->resv); + return HRTIMER_NORESTART; +} - drm_atomic_set_fence_for_plane(new_state, fence); +static void msm_atomic_pending_work(struct work_struct *work) +{ + struct msm_pending_timer *timer = container_of(work, + struct msm_pending_timer, work); - return msm_framebuffer_prepare(new_state->fb, kms->aspace); + msm_atomic_async_commit(timer->kms, timer->crtc_idx); +} + +void msm_atomic_init_pending_timer(struct msm_pending_timer *timer, + struct msm_kms *kms, int crtc_idx) +{ + timer->kms = kms; + timer->crtc_idx = crtc_idx; + hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + timer->timer.function = msm_atomic_pending_timer; + INIT_WORK(&timer->work, msm_atomic_pending_work); +} + +static bool can_do_async(struct drm_atomic_state *state, + struct drm_crtc **async_crtc) +{ + struct drm_connector_state *connector_state; + struct drm_connector *connector; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int i, num_crtcs = 0; + + if (!(state->legacy_cursor_update || state->async_update)) + return false; + + /* any connector change, means slow path: */ + for_each_new_connector_in_state(state, connector, connector_state, i) + return false; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + if (drm_atomic_crtc_needs_modeset(crtc_state)) + return false; + if (++num_crtcs > 1) + return false; + *async_crtc = crtc; + } + + return true; +} + +/* Get bitmask of crtcs that will need to be flushed. The bitmask + * can be used with for_each_crtc_mask() iterator, to iterate + * effected crtcs without needing to preserve the atomic state. + */ +static unsigned get_crtc_mask(struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + unsigned i, mask = 0; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) + mask |= drm_crtc_mask(crtc); + + return mask; } void msm_atomic_commit_tail(struct drm_atomic_state *state) @@ -56,26 +144,104 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) struct drm_device *dev = state->dev; struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; + struct drm_crtc *async_crtc = NULL; + unsigned crtc_mask = get_crtc_mask(state); + bool async = kms->funcs->vsync_time && + can_do_async(state, &async_crtc); + + trace_msm_atomic_commit_tail_start(async, crtc_mask); + + kms->funcs->enable_commit(kms); + /* + * Ensure any previous (potentially async) commit has + * completed: + */ + trace_msm_atomic_wait_flush_start(crtc_mask); + kms->funcs->wait_flush(kms, crtc_mask); + trace_msm_atomic_wait_flush_finish(crtc_mask); + + mutex_lock(&kms->commit_lock); + + /* + * Now that there is no in-progress flush, prepare the + * current update: + */ kms->funcs->prepare_commit(kms, state); + /* + * Push atomic updates down to hardware: + */ drm_atomic_helper_commit_modeset_disables(dev, state); - drm_atomic_helper_commit_planes(dev, state, 0); - drm_atomic_helper_commit_modeset_enables(dev, state); - if (kms->funcs->commit) { - DRM_DEBUG_ATOMIC("triggering commit\n"); - kms->funcs->commit(kms, state); - } + if (async) { + struct msm_pending_timer *timer = + &kms->pending_timers[drm_crtc_index(async_crtc)]; - if (!state->legacy_cursor_update) - msm_atomic_wait_for_commit_done(dev, state); + /* async updates are limited to single-crtc updates: */ + WARN_ON(crtc_mask != drm_crtc_mask(async_crtc)); - kms->funcs->complete_commit(kms, state); + /* + * Start timer if we don't already have an update pending + * on this crtc: + */ + if (!(kms->pending_crtc_mask & crtc_mask)) { + ktime_t vsync_time, wakeup_time; - drm_atomic_helper_commit_hw_done(state); + kms->pending_crtc_mask |= crtc_mask; + + vsync_time = kms->funcs->vsync_time(kms, async_crtc); + wakeup_time = ktime_sub(vsync_time, ms_to_ktime(1)); + + hrtimer_start(&timer->timer, wakeup_time, + HRTIMER_MODE_ABS); + } + kms->funcs->disable_commit(kms); + mutex_unlock(&kms->commit_lock); + + /* + * At this point, from drm core's perspective, we + * are done with the atomic update, so we can just + * go ahead and signal that it is done: + */ + drm_atomic_helper_commit_hw_done(state); + drm_atomic_helper_cleanup_planes(dev, state); + + trace_msm_atomic_commit_tail_finish(async, crtc_mask); + + return; + } + + /* + * If there is any async flush pending on updated crtcs, fold + * them into the current flush. + */ + kms->pending_crtc_mask &= ~crtc_mask; + + /* + * Flush hardware updates: + */ + trace_msm_atomic_flush_commit(crtc_mask); + kms->funcs->flush_commit(kms, crtc_mask); + mutex_unlock(&kms->commit_lock); + + /* + * Wait for flush to complete: + */ + trace_msm_atomic_wait_flush_start(crtc_mask); + kms->funcs->wait_flush(kms, crtc_mask); + trace_msm_atomic_wait_flush_finish(crtc_mask); + + mutex_lock(&kms->commit_lock); + kms->funcs->complete_commit(kms, crtc_mask); + mutex_unlock(&kms->commit_lock); + kms->funcs->disable_commit(kms); + + drm_atomic_helper_commit_hw_done(state); drm_atomic_helper_cleanup_planes(dev, state); + + trace_msm_atomic_commit_tail_finish(async, crtc_mask); } diff --git a/drivers/gpu/drm/msm/msm_atomic_trace.h b/drivers/gpu/drm/msm/msm_atomic_trace.h new file mode 100644 index 000000000000..b4ca0ed3b4a3 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_atomic_trace.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#if !defined(_MSM_GPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _MSM_GPU_TRACE_H_ + +#include <linux/tracepoint.h> + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM drm_msm_atomic +#define TRACE_INCLUDE_FILE msm_atomic_trace + +TRACE_EVENT(msm_atomic_commit_tail_start, + TP_PROTO(bool async, unsigned crtc_mask), + TP_ARGS(async, crtc_mask), + TP_STRUCT__entry( + __field(bool, async) + __field(u32, crtc_mask) + ), + TP_fast_assign( + __entry->async = async; + __entry->crtc_mask = crtc_mask; + ), + TP_printk("async=%d crtc_mask=%x", + __entry->async, __entry->crtc_mask) +); + +TRACE_EVENT(msm_atomic_commit_tail_finish, + TP_PROTO(bool async, unsigned crtc_mask), + TP_ARGS(async, crtc_mask), + TP_STRUCT__entry( + __field(bool, async) + __field(u32, crtc_mask) + ), + TP_fast_assign( + __entry->async = async; + __entry->crtc_mask = crtc_mask; + ), + TP_printk("async=%d crtc_mask=%x", + __entry->async, __entry->crtc_mask) +); + +TRACE_EVENT(msm_atomic_async_commit_start, + TP_PROTO(unsigned crtc_mask), + TP_ARGS(crtc_mask), + TP_STRUCT__entry( + __field(u32, crtc_mask) + ), + TP_fast_assign( + __entry->crtc_mask = crtc_mask; + ), + TP_printk("crtc_mask=%x", + __entry->crtc_mask) +); + +TRACE_EVENT(msm_atomic_async_commit_finish, + TP_PROTO(unsigned crtc_mask), + TP_ARGS(crtc_mask), + TP_STRUCT__entry( + __field(u32, crtc_mask) + ), + TP_fast_assign( + __entry->crtc_mask = crtc_mask; + ), + TP_printk("crtc_mask=%x", + __entry->crtc_mask) +); + +TRACE_EVENT(msm_atomic_wait_flush_start, + TP_PROTO(unsigned crtc_mask), + TP_ARGS(crtc_mask), + TP_STRUCT__entry( + __field(u32, crtc_mask) + ), + TP_fast_assign( + __entry->crtc_mask = crtc_mask; + ), + TP_printk("crtc_mask=%x", + __entry->crtc_mask) +); + +TRACE_EVENT(msm_atomic_wait_flush_finish, + TP_PROTO(unsigned crtc_mask), + TP_ARGS(crtc_mask), + TP_STRUCT__entry( + __field(u32, crtc_mask) + ), + TP_fast_assign( + __entry->crtc_mask = crtc_mask; + ), + TP_printk("crtc_mask=%x", + __entry->crtc_mask) +); + +TRACE_EVENT(msm_atomic_flush_commit, + TP_PROTO(unsigned crtc_mask), + TP_ARGS(crtc_mask), + TP_STRUCT__entry( + __field(u32, crtc_mask) + ), + TP_fast_assign( + __entry->crtc_mask = crtc_mask; + ), + TP_printk("crtc_mask=%x", + __entry->crtc_mask) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/msm +#include <trace/define_trace.h> diff --git a/drivers/gpu/drm/msm/msm_atomic_tracepoints.c b/drivers/gpu/drm/msm/msm_atomic_tracepoints.c new file mode 100644 index 000000000000..011dc881f391 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_atomic_tracepoints.c @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-2.0 +#define CREATE_TRACE_POINTS +#include "msm_atomic_trace.h" diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index a0a8df591e93..1c74381a4fc9 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -5,7 +5,12 @@ */ #ifdef CONFIG_DEBUG_FS + #include <linux/debugfs.h> + +#include <drm/drm_debugfs.h> +#include <drm/drm_file.h> + #include "msm_drv.h" #include "msm_gpu.h" #include "msm_kms.h" @@ -42,12 +47,8 @@ static int msm_gpu_release(struct inode *inode, struct file *file) struct msm_gpu_show_priv *show_priv = m->private; struct msm_drm_private *priv = show_priv->dev->dev_private; struct msm_gpu *gpu = priv->gpu; - int ret; - - ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex); - if (ret) - return ret; + mutex_lock(&show_priv->dev->struct_mutex); gpu->funcs->gpu_state_put(show_priv->state); mutex_unlock(&show_priv->dev->struct_mutex); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c356f5ccf253..e4b750b0c2d3 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -5,9 +5,18 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/dma-mapping.h> #include <linux/kthread.h> +#include <linux/uaccess.h> #include <uapi/linux/sched/types.h> + +#include <drm/drm_drv.h> +#include <drm/drm_file.h> +#include <drm/drm_ioctl.h> +#include <drm/drm_irq.h> +#include <drm/drm_prime.h> #include <drm/drm_of.h> +#include <drm/drm_vblank.h> #include "msm_drv.h" #include "msm_debugfs.h" @@ -17,7 +26,6 @@ #include "msm_kms.h" #include "adreno/adreno_gpu.h" - /* * MSM driver version: * - 1.0.0 - initial interface @@ -75,46 +83,6 @@ module_param(modeset, bool, 0600); * Util/helpers: */ -int msm_clk_bulk_get(struct device *dev, struct clk_bulk_data **bulk) -{ - struct property *prop; - const char *name; - struct clk_bulk_data *local; - int i = 0, ret, count; - - count = of_property_count_strings(dev->of_node, "clock-names"); - if (count < 1) - return 0; - - local = devm_kcalloc(dev, sizeof(struct clk_bulk_data *), - count, GFP_KERNEL); - if (!local) - return -ENOMEM; - - of_property_for_each_string(dev->of_node, "clock-names", prop, name) { - local[i].id = devm_kstrdup(dev, name, GFP_KERNEL); - if (!local[i].id) { - devm_kfree(dev, local); - return -ENOMEM; - } - - i++; - } - - ret = devm_clk_bulk_get(dev, count, local); - - if (ret) { - for (i = 0; i < count; i++) - devm_kfree(dev, (void *) local[i].id); - devm_kfree(dev, local); - - return ret; - } - - *bulk = local; - return count; -} - struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count, const char *name) { @@ -170,7 +138,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, size = resource_size(res); - ptr = devm_ioremap_nocache(&pdev->dev, res->start, size); + ptr = devm_ioremap(&pdev->dev, res->start, size); if (!ptr) { DRM_DEV_ERROR(&pdev->dev, "failed to ioremap: %s\n", name); return ERR_PTR(-ENOMEM); @@ -473,6 +441,14 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) if (ret) goto err_msm_uninit; + if (!dev->dma_parms) { + dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), + GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + msm_gem_shrinker_init(ddev); switch (get_mdp_ver(pdev)) { @@ -505,6 +481,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->mode_config.normalize_zpos = true; if (kms) { + kms->dev = ddev; ret = kms->funcs->hw_init(kms); if (ret) { DRM_DEV_ERROR(dev, "kms hw init failed: %d\n", ret); @@ -984,17 +961,17 @@ static int msm_ioctl_submitqueue_close(struct drm_device *dev, void *data, } static const struct drm_ioctl_desc msm_ioctls[] = { - DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_INFO, msm_ioctl_gem_info, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT, msm_ioctl_gem_submit, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_GEM_MADVISE, msm_ioctl_gem_madvise, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_NEW, msm_ioctl_submitqueue_new, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_CLOSE, msm_ioctl_submitqueue_close, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_INFO, msm_ioctl_gem_info, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT, msm_ioctl_gem_submit, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_MADVISE, msm_ioctl_gem_madvise, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_NEW, msm_ioctl_submitqueue_new, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_CLOSE, msm_ioctl_submitqueue_close, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_RENDER_ALLOW), }; static const struct vm_operations_struct vm_ops = { @@ -1017,7 +994,6 @@ static const struct file_operations fops = { static struct drm_driver msm_driver = { .driver_features = DRIVER_GEM | - DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC | DRIVER_MODESET, @@ -1036,8 +1012,6 @@ static struct drm_driver msm_driver = { .dumb_map_offset = msm_gem_dumb_map_offset, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_export = drm_gem_prime_export, - .gem_prime_import = drm_gem_prime_import, .gem_prime_pin = msm_gem_prime_pin, .gem_prime_unpin = msm_gem_prime_unpin, .gem_prime_get_sg_table = msm_gem_prime_get_sg_table, @@ -1226,7 +1200,8 @@ static int add_display_components(struct device *dev, * the interfaces to our components list. */ if (of_device_is_compatible(dev->of_node, "qcom,mdss") || - of_device_is_compatible(dev->of_node, "qcom,sdm845-mdss")) { + of_device_is_compatible(dev->of_node, "qcom,sdm845-mdss") || + of_device_is_compatible(dev->of_node, "qcom,sc7180-mdss")) { ret = of_platform_populate(dev->of_node, NULL, NULL, dev); if (ret) { DRM_DEV_ERROR(dev, "failed to populate children devices\n"); @@ -1351,6 +1326,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 }, { .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 }, { .compatible = "qcom,sdm845-mdss", .data = (void *)KMS_DPU }, + { .compatible = "qcom,sc7180-mdss", .data = (void *)KMS_DPU }, {} }; MODULE_DEVICE_TABLE(of, dt_match); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index ee7b512dc158..740bf7c70d8f 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -25,7 +25,6 @@ #include <linux/sizes.h> #include <linux/kthread.h> -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_plane_helper.h> @@ -222,8 +221,12 @@ struct msm_format { uint32_t pixel_format; }; +struct msm_pending_timer; + int msm_atomic_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state); +void msm_atomic_init_pending_timer(struct msm_pending_timer *timer, + struct msm_kms *kms, int crtc_idx); void msm_atomic_commit_tail(struct drm_atomic_state *state); struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev); void msm_atomic_state_clear(struct drm_atomic_state *state); @@ -399,7 +402,6 @@ static inline void msm_perf_debugfs_cleanup(struct msm_drm_private *priv) {} #endif struct clk *msm_clk_get(struct platform_device *pdev, const char *name); -int msm_clk_bulk_get(struct device *dev, struct clk_bulk_data **bulk); struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count, const char *name); @@ -452,8 +454,7 @@ static inline unsigned long timeout_to_jiffies(const ktime_t *timeout) remaining_jiffies = 0; } else { ktime_t rem = ktime_sub(*timeout, now); - struct timespec ts = ktime_to_timespec(rem); - remaining_jiffies = timespec_to_jiffies(&ts); + remaining_jiffies = ktime_divns(rem, NSEC_PER_SEC / HZ); } return remaining_jiffies; diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index 5bcd5e502a6b..37674e886e99 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -6,6 +6,8 @@ #include <drm/drm_crtc.h> #include <drm/drm_damage_helper.h> +#include <drm/drm_file.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_probe_helper.h> diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 2429d5e6ce9f..db48867df47d 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -6,6 +6,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_fourcc.h> #include "msm_drv.h" #include "msm_kms.h" @@ -25,7 +26,7 @@ struct msm_fbdev { struct drm_framebuffer *fb; }; -static struct fb_ops msm_fb_ops = { +static const struct fb_ops msm_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, @@ -169,6 +170,9 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) if (ret) goto fini; + /* the fw fb could be anywhere in memory */ + drm_fb_helper_remove_conflicting_framebuffers(NULL, "msm", false); + ret = drm_fb_helper_initial_config(helper, 32); if (ret) goto fini; diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 8cf6362e64bf..5a6a79fbc9d6 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -9,6 +9,8 @@ #include <linux/dma-buf.h> #include <linux/pfn_t.h> +#include <drm/drm_prime.h> + #include "msm_drv.h" #include "msm_fence.h" #include "msm_gem.h" @@ -50,7 +52,7 @@ static void sync_for_device(struct msm_gem_object *msm_obj) { struct device *dev = msm_obj->base.dev->dev; - if (get_dma_ops(dev)) { + if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) { dma_sync_sg_for_device(dev, msm_obj->sgt->sgl, msm_obj->sgt->nents, DMA_BIDIRECTIONAL); } else { @@ -63,7 +65,7 @@ static void sync_for_cpu(struct msm_gem_object *msm_obj) { struct device *dev = msm_obj->base.dev->dev; - if (get_dma_ops(dev)) { + if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) { dma_sync_sg_for_cpu(dev, msm_obj->sgt->sgl, msm_obj->sgt->nents, DMA_BIDIRECTIONAL); } else { @@ -700,13 +702,13 @@ void msm_gem_vunmap(struct drm_gem_object *obj, enum msm_gem_lock subclass) int msm_gem_sync_object(struct drm_gem_object *obj, struct msm_fence_context *fctx, bool exclusive) { - struct reservation_object_list *fobj; + struct dma_resv_list *fobj; struct dma_fence *fence; int i, ret; - fobj = reservation_object_get_list(obj->resv); + fobj = dma_resv_get_list(obj->resv); if (!fobj || (fobj->shared_count == 0)) { - fence = reservation_object_get_excl(obj->resv); + fence = dma_resv_get_excl(obj->resv); /* don't need to wait on our own fences, since ring is fifo */ if (fence && (fence->context != fctx->context)) { ret = dma_fence_wait(fence, true); @@ -720,7 +722,7 @@ int msm_gem_sync_object(struct drm_gem_object *obj, for (i = 0; i < fobj->shared_count; i++) { fence = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(obj->resv)); + dma_resv_held(obj->resv)); if (fence->context != fctx->context) { ret = dma_fence_wait(fence, true); if (ret) @@ -738,9 +740,9 @@ void msm_gem_move_to_active(struct drm_gem_object *obj, WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED); msm_obj->gpu = gpu; if (exclusive) - reservation_object_add_excl_fence(obj->resv, fence); + dma_resv_add_excl_fence(obj->resv, fence); else - reservation_object_add_shared_fence(obj->resv, fence); + dma_resv_add_shared_fence(obj->resv, fence); list_del_init(&msm_obj->mm_list); list_add_tail(&msm_obj->mm_list, &gpu->active_list); } @@ -765,7 +767,7 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) op & MSM_PREP_NOSYNC ? 0 : timeout_to_jiffies(timeout); long ret; - ret = reservation_object_wait_timeout_rcu(obj->resv, write, + ret = dma_resv_wait_timeout_rcu(obj->resv, write, true, remain); if (ret == 0) return remain == 0 ? -EBUSY : -ETIMEDOUT; @@ -797,8 +799,8 @@ static void describe_fence(struct dma_fence *fence, const char *type, void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { struct msm_gem_object *msm_obj = to_msm_bo(obj); - struct reservation_object *robj = obj->resv; - struct reservation_object_list *fobj; + struct dma_resv *robj = obj->resv; + struct dma_resv_list *fobj; struct dma_fence *fence; struct msm_gem_vma *vma; uint64_t off = drm_vma_node_start(&obj->vma_node); @@ -975,7 +977,6 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, static int msm_gem_new_impl(struct drm_device *dev, uint32_t size, uint32_t flags, - struct reservation_object *resv, struct drm_gem_object **obj, bool struct_mutex_locked) { @@ -1002,9 +1003,6 @@ static int msm_gem_new_impl(struct drm_device *dev, msm_obj->flags = flags; msm_obj->madv = MSM_MADV_WILLNEED; - if (resv) - msm_obj->base.resv = resv; - INIT_LIST_HEAD(&msm_obj->submit_entry); INIT_LIST_HEAD(&msm_obj->vmas); @@ -1046,7 +1044,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev, if (size == 0) return ERR_PTR(-EINVAL); - ret = msm_gem_new_impl(dev, size, flags, NULL, &obj, struct_mutex_locked); + ret = msm_gem_new_impl(dev, size, flags, &obj, struct_mutex_locked); if (ret) goto fail; @@ -1123,7 +1121,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, size = PAGE_ALIGN(dmabuf->size); - ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj, false); + ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj, false); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 8cfcf8f09e3e..9e0953c2b7ce 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -8,7 +8,7 @@ #define __MSM_GEM_H__ #include <linux/kref.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include "msm_drv.h" /* Additional internal-use only BO flags: */ diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index 5d64e0671f7a..d7c8948427fe 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -4,11 +4,13 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/dma-buf.h> + +#include <drm/drm_prime.h> + #include "msm_drv.h" #include "msm_gem.h" -#include <linux/dma-buf.h> - struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 348f8c2be806..385d4965a8d0 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -4,7 +4,11 @@ * Author: Rob Clark <robdclark@gmail.com> */ +#include <linux/file.h> #include <linux/sync_file.h> +#include <linux/uaccess.h> + +#include <drm/drm_file.h> #include "msm_drv.h" #include "msm_gpu.h" @@ -26,8 +30,8 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, uint32_t nr_cmds) { struct msm_gem_submit *submit; - uint64_t sz = sizeof(*submit) + ((u64)nr_bos * sizeof(submit->bos[0])) + - ((u64)nr_cmds * sizeof(submit->cmd[0])); + uint64_t sz = struct_size(submit, bos, nr_bos) + + ((u64)nr_cmds * sizeof(submit->cmd[0])); if (sz > SIZE_MAX) return NULL; @@ -50,7 +54,6 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, INIT_LIST_HEAD(&submit->node); INIT_LIST_HEAD(&submit->bo_list); - ww_acquire_init(&submit->ticket, &reservation_ww_class); return submit; } @@ -154,7 +157,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, msm_gem_unpin_iova(&msm_obj->base, submit->aspace); if (submit->bos[i].flags & BO_LOCKED) - ww_mutex_unlock(&msm_obj->base.resv->lock); + dma_resv_unlock(msm_obj->base.resv); if (backoff && !(submit->bos[i].flags & BO_VALID)) submit->bos[i].iova = 0; @@ -177,8 +180,8 @@ retry: contended = i; if (!(submit->bos[i].flags & BO_LOCKED)) { - ret = ww_mutex_lock_interruptible(&msm_obj->base.resv->lock, - &submit->ticket); + ret = dma_resv_lock_interruptible(msm_obj->base.resv, + &submit->ticket); if (ret) goto fail; submit->bos[i].flags |= BO_LOCKED; @@ -199,8 +202,8 @@ fail: if (ret == -EDEADLK) { struct msm_gem_object *msm_obj = submit->bos[contended].obj; /* we lost out in a seqno race, lock and retry.. */ - ret = ww_mutex_lock_slow_interruptible(&msm_obj->base.resv->lock, - &submit->ticket); + ret = dma_resv_lock_slow_interruptible(msm_obj->base.resv, + &submit->ticket); if (!ret) { submit->bos[contended].flags |= BO_LOCKED; slow_locked = contended; @@ -225,7 +228,7 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit) * strange place to call it. OTOH this is a * convenient can-fail point to hook it in. */ - ret = reservation_object_reserve_shared(msm_obj->base.resv, + ret = dma_resv_reserve_shared(msm_obj->base.resv, 1); if (ret) return ret; @@ -386,8 +389,6 @@ static void submit_cleanup(struct msm_gem_submit *submit) list_del_init(&msm_obj->submit_entry); drm_gem_object_put(&msm_obj->base); } - - ww_acquire_fini(&submit->ticket); } int msm_ioctl_gem_submit(struct drm_device *dev, void *data, @@ -404,6 +405,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct msm_ringbuffer *ring; int out_fence_fd = -1; struct pid *pid = get_pid(task_pid(current)); + bool has_ww_ticket = false; unsigned i; int ret, submitid; if (!gpu) @@ -485,6 +487,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto out; + /* copy_*_user while holding a ww ticket upsets lockdep */ + ww_acquire_init(&submit->ticket, &reservation_ww_class); + has_ww_ticket = true; ret = submit_lock_objects(submit); if (ret) goto out; @@ -584,6 +589,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out: submit_cleanup(submit); + if (has_ww_ticket) + ww_acquire_fini(&submit->ticket); if (ret) msm_gem_submit_free(submit); out_unlock: diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 4edb874548b3..18f3a5c53ffb 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -16,6 +16,7 @@ #include <linux/pm_opp.h> #include <linux/devfreq.h> #include <linux/devcoredump.h> +#include <linux/sched/task.h> /* * Power Management: @@ -95,7 +96,8 @@ static void msm_devfreq_init(struct msm_gpu *gpu) */ gpu->devfreq.devfreq = devm_devfreq_add_device(&gpu->pdev->dev, - &msm_devfreq_profile, "simple_ondemand", NULL); + &msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND, + NULL); if (IS_ERR(gpu->devfreq.devfreq)) { DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n"); @@ -783,7 +785,7 @@ static irqreturn_t irq_handler(int irq, void *data) static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu) { - int ret = msm_clk_bulk_get(&pdev->dev, &gpu->grp_clks); + int ret = devm_clk_bulk_get_all(&pdev->dev, &gpu->grp_clks); if (ret < 1) { gpu->nr_clocks = 0; @@ -837,7 +839,7 @@ msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev, return ERR_CAST(aspace); } - ret = aspace->mmu->funcs->attach(aspace->mmu, NULL, 0); + ret = aspace->mmu->funcs->attach(aspace->mmu); if (ret) { msm_gem_address_space_put(aspace); return ERR_PTR(ret); @@ -994,8 +996,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) msm_gem_kernel_put(gpu->memptrs_bo, gpu->aspace, false); if (!IS_ERR_OR_NULL(gpu->aspace)) { - gpu->aspace->mmu->funcs->detach(gpu->aspace->mmu, - NULL, 0); + gpu->aspace->mmu->funcs->detach(gpu->aspace->mmu); msm_gem_address_space_put(gpu->aspace); } } diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index ab8f0f9c9dc8..be5bc2e8425c 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -111,8 +111,15 @@ struct msm_gpu { struct clk *ebi1_clk, *core_clk, *rbbmtimer_clk; uint32_t fast_rate; + /* The gfx-mem interconnect path that's used by all GPU types. */ struct icc_path *icc_path; + /* + * Second interconnect path for some A3xx and all A4xx GPUs to the + * On Chip MEMory (OCMEM). + */ + struct icc_path *ocmem_icc_path; + /* Hang and Inactivity Detection: */ #define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */ diff --git a/drivers/gpu/drm/msm/msm_gpu_trace.h b/drivers/gpu/drm/msm/msm_gpu_trace.h index 1155118a27a1..122b84789238 100644 --- a/drivers/gpu/drm/msm/msm_gpu_trace.h +++ b/drivers/gpu/drm/msm/msm_gpu_trace.h @@ -5,7 +5,7 @@ #include <linux/tracepoint.h> #undef TRACE_SYSTEM -#define TRACE_SYSTEM drm_msm +#define TRACE_SYSTEM drm_msm_gpu #define TRACE_INCLUDE_FILE msm_gpu_trace TRACE_EVENT(msm_gpu_submit, diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c index 27312b553dd8..34980d8eb7ad 100644 --- a/drivers/gpu/drm/msm/msm_gpummu.c +++ b/drivers/gpu/drm/msm/msm_gpummu.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */ +#include <linux/dma-mapping.h> + #include "msm_drv.h" #include "msm_mmu.h" #include "adreno/adreno_gpu.h" @@ -19,14 +21,12 @@ struct msm_gpummu { #define GPUMMU_PAGE_SIZE SZ_4K #define TABLE_SIZE (sizeof(uint32_t) * GPUMMU_VA_RANGE / GPUMMU_PAGE_SIZE) -static int msm_gpummu_attach(struct msm_mmu *mmu, const char * const *names, - int cnt) +static int msm_gpummu_attach(struct msm_mmu *mmu) { return 0; } -static void msm_gpummu_detach(struct msm_mmu *mmu, const char * const *names, - int cnt) +static void msm_gpummu_detach(struct msm_mmu *mmu) { } diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 8c95c31e2b12..ad58cfe5998e 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -23,16 +23,14 @@ static int msm_fault_handler(struct iommu_domain *domain, struct device *dev, return 0; } -static int msm_iommu_attach(struct msm_mmu *mmu, const char * const *names, - int cnt) +static int msm_iommu_attach(struct msm_mmu *mmu) { struct msm_iommu *iommu = to_msm_iommu(mmu); return iommu_attach_device(iommu->domain, mmu->dev); } -static void msm_iommu_detach(struct msm_mmu *mmu, const char * const *names, - int cnt) +static void msm_iommu_detach(struct msm_mmu *mmu) { struct msm_iommu *iommu = to_msm_iommu(mmu); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index c7588a42635e..1cbef6b200b7 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -30,13 +30,76 @@ struct msm_kms_funcs { irqreturn_t (*irq)(struct msm_kms *kms); int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); - /* modeset, bracketing atomic_commit(): */ + + /* + * Atomic commit handling: + * + * Note that in the case of async commits, the funcs which take + * a crtc_mask (ie. ->flush_commit(), and ->complete_commit()) + * might not be evenly balanced with ->prepare_commit(), however + * each crtc that effected by a ->prepare_commit() (potentially + * multiple times) will eventually (at end of vsync period) be + * flushed and completed. + * + * This has some implications about tracking of cleanup state, + * for example SMP blocks to release after commit completes. Ie. + * cleanup state should be also duplicated in the various + * duplicate_state() methods, as the current cleanup state at + * ->complete_commit() time may have accumulated cleanup work + * from multiple commits. + */ + + /** + * Enable/disable power/clks needed for hw access done in other + * commit related methods. + * + * If mdp4 is migrated to runpm, we could probably drop these + * and use runpm directly. + */ + void (*enable_commit)(struct msm_kms *kms); + void (*disable_commit)(struct msm_kms *kms); + + /** + * If the kms backend supports async commit, it should implement + * this method to return the time of the next vsync. This is + * used to determine a time slightly before vsync, for the async + * commit timer to run and complete an async commit. + */ + ktime_t (*vsync_time)(struct msm_kms *kms, struct drm_crtc *crtc); + + /** + * Prepare for atomic commit. This is called after any previous + * (async or otherwise) commit has completed. + */ void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state); - void (*commit)(struct msm_kms *kms, struct drm_atomic_state *state); - void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state); - /* functions to wait for atomic commit completed on each CRTC */ - void (*wait_for_crtc_commit_done)(struct msm_kms *kms, - struct drm_crtc *crtc); + + /** + * Flush an atomic commit. This is called after the hardware + * updates have already been pushed down to effected planes/ + * crtcs/encoders/connectors. + */ + void (*flush_commit)(struct msm_kms *kms, unsigned crtc_mask); + + /** + * Wait for any in-progress flush to complete on the specified + * crtcs. This should not block if there is no in-progress + * commit (ie. don't just wait for a vblank), as it will also + * be called before ->prepare_commit() to ensure any potential + * "async" commit has completed. + */ + void (*wait_flush)(struct msm_kms *kms, unsigned crtc_mask); + + /** + * Clean up after commit is completed. This is called after + * ->wait_flush(), to give the backend a chance to do any + * post-commit cleanup. + */ + void (*complete_commit)(struct msm_kms *kms, unsigned crtc_mask); + + /* + * Format handling: + */ + /* get msm_format w/ optional format modifiers from drm_mode_fb_cmd2 */ const struct msm_format *(*get_format)(struct msm_kms *kms, const uint32_t format, @@ -46,6 +109,7 @@ struct msm_kms_funcs { const struct msm_format *msm_fmt, const struct drm_mode_fb_cmd2 *cmd, struct drm_gem_object **bos); + /* misc: */ long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder); @@ -64,20 +128,48 @@ struct msm_kms_funcs { #endif }; +struct msm_kms; + +/* + * A per-crtc timer for pending async atomic flushes. Scheduled to expire + * shortly before vblank to flush pending async updates. + */ +struct msm_pending_timer { + struct hrtimer timer; + struct work_struct work; + struct msm_kms *kms; + unsigned crtc_idx; +}; + struct msm_kms { const struct msm_kms_funcs *funcs; + struct drm_device *dev; /* irq number to be passed on to drm_irq_install */ int irq; /* mapper-id used to request GEM buffer mapped for scanout: */ struct msm_gem_address_space *aspace; + + /* + * For async commit, where ->flush_commit() and later happens + * from the crtc's pending_timer close to end of the frame: + */ + struct mutex commit_lock; + unsigned pending_crtc_mask; + struct msm_pending_timer pending_timers[MAX_CRTCS]; }; static inline void msm_kms_init(struct msm_kms *kms, const struct msm_kms_funcs *funcs) { + unsigned i; + + mutex_init(&kms->commit_lock); kms->funcs = funcs; + + for (i = 0; i < ARRAY_SIZE(kms->pending_timers); i++) + msm_atomic_init_pending_timer(&kms->pending_timers[i], kms, i); } struct msm_kms *mdp4_kms_init(struct drm_device *dev); @@ -98,4 +190,8 @@ struct msm_mdss { int mdp5_mdss_init(struct drm_device *dev); int dpu_mdss_init(struct drm_device *dev); +#define for_each_crtc_mask(dev, crtc, crtc_mask) \ + drm_for_each_crtc(crtc, dev) \ + for_each_if (drm_crtc_mask(crtc) & (crtc_mask)) + #endif /* __MSM_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 871d56303697..67a623f14319 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -10,8 +10,8 @@ #include <linux/iommu.h> struct msm_mmu_funcs { - int (*attach)(struct msm_mmu *mmu, const char * const *names, int cnt); - void (*detach)(struct msm_mmu *mmu, const char * const *names, int cnt); + int (*attach)(struct msm_mmu *mmu); + void (*detach)(struct msm_mmu *mmu); int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, unsigned len, int prot); int (*unmap)(struct msm_mmu *mmu, uint64_t iova, unsigned len); diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c index 490cadda2796..3a27153eef08 100644 --- a/drivers/gpu/drm/msm/msm_perf.c +++ b/drivers/gpu/drm/msm/msm_perf.c @@ -15,6 +15,9 @@ #ifdef CONFIG_DEBUG_FS #include <linux/debugfs.h> +#include <linux/uaccess.h> + +#include <drm/drm_file.h> #include "msm_drv.h" #include "msm_gpu.h" diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 76d3fdd17bf8..af7ceb246c7c 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -31,11 +31,14 @@ #ifdef CONFIG_DEBUG_FS -#include <linux/kfifo.h> -#include <linux/debugfs.h> #include <linux/circ_buf.h> +#include <linux/debugfs.h> +#include <linux/kfifo.h> +#include <linux/uaccess.h> #include <linux/wait.h> +#include <drm/drm_file.h> + #include "msm_drv.h" #include "msm_gpu.h" #include "msm_gem.h" @@ -295,7 +298,7 @@ void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) static void snapshot_buf(struct msm_rd_state *rd, struct msm_gem_submit *submit, int idx, - uint64_t iova, uint32_t size) + uint64_t iova, uint32_t size, bool full) { struct msm_gem_object *obj = submit->bos[idx].obj; unsigned offset = 0; @@ -315,6 +318,9 @@ static void snapshot_buf(struct msm_rd_state *rd, rd_write_section(rd, RD_GPUADDR, (uint32_t[3]){ iova, size, iova >> 32 }, 12); + if (!full) + return; + /* But only dump the contents of buffers marked READ */ if (!(submit->bos[idx].flags & MSM_SUBMIT_BO_READ)) return; @@ -378,18 +384,21 @@ void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit, rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); for (i = 0; i < submit->nr_bos; i++) - if (should_dump(submit, i)) - snapshot_buf(rd, submit, i, 0, 0); + snapshot_buf(rd, submit, i, 0, 0, should_dump(submit, i)); for (i = 0; i < submit->nr_cmds; i++) { - uint64_t iova = submit->cmd[i].iova; uint32_t szd = submit->cmd[i].size; /* in dwords */ /* snapshot cmdstream bo's (if we haven't already): */ if (!should_dump(submit, i)) { snapshot_buf(rd, submit, submit->cmd[i].idx, - submit->cmd[i].iova, szd * 4); + submit->cmd[i].iova, szd * 4, true); } + } + + for (i = 0; i < submit->nr_cmds; i++) { + uint64_t iova = submit->cmd[i].iova; + uint32_t szd = submit->cmd[i].size; /* in dwords */ switch (submit->cmd[i].type) { case MSM_SUBMIT_CMD_IB_TARGET_BUF: diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c b/drivers/gpu/drm/msm/msm_submitqueue.c index c70e00e22c4c..001fbf537440 100644 --- a/drivers/gpu/drm/msm/msm_submitqueue.c +++ b/drivers/gpu/drm/msm/msm_submitqueue.c @@ -3,6 +3,8 @@ */ #include <linux/kref.h> +#include <linux/uaccess.h> + #include "msm_gpu.h" void msm_submitqueue_destroy(struct kref *kref) |