Merge tag 'drm-msm-next-2026-08-01' of https://gitlab.freedesktop.org/drm/msm into drm-next

Changes for v7.3

Bindings:
- Added Shikra support
- Document a840, a704, a722

Core:
- Use drm_client buffers for fbdev emulation
- teardown fixes
- ARM32 DMA fixup
- Remove objects from evict list when re-validated
- Bunch of corner case and error path fixes

DPU:
- Dropped dev_pm_opp_set_rate(0) preventing burnout
- Fixed SSPP offsets of Kaanapali

DP:
- Dropped dev_pm_opp_set_rate(0) preventing burnout
- Cleaned up core code in preparation for MST support
- Fixed prepare() to let Pipewire continue in case of the unplugged cable

GPU:
- Add support for a704
- Add support for a722

HDMI:
- Simplifed register access

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Rob Clark <rob.clark@oss.qualcomm.com>
Link: https://patch.msgid.link/CACSVV02Kp=J+w_RjEJbBbQnBYRb+SWdwMvVbCaAL70bq9EBagQ@mail.gmail.com
This commit is contained in:
Dave Airlie
2026-08-24 11:21:11 +10:00
57 changed files with 1573 additions and 845 deletions

View File

@@ -47,6 +47,10 @@ properties:
- qcom,sm8650-dsi-ctrl
- qcom,sm8750-dsi-ctrl
- const: qcom,mdss-dsi-ctrl
- items:
- const: qcom,shikra-dsi-ctrl
- const: qcom,qcm2290-dsi-ctrl
- const: qcom,mdss-dsi-ctrl
- items:
- enum:
- qcom,qcs8300-dsi-ctrl

View File

@@ -262,6 +262,7 @@ allOf:
compatible:
contains:
enum:
- qcom,adreno-gmu-722.0
- qcom,adreno-gmu-730.1
- qcom,adreno-gmu-740.1
- qcom,adreno-gmu-750.1

View File

@@ -353,6 +353,7 @@ allOf:
- qcom,adreno-610.0
- qcom,adreno-619.1
- qcom,adreno-07000200
- qcom,adreno-07000400
then:
properties:
clocks:
@@ -413,6 +414,7 @@ allOf:
contains:
enum:
- qcom,adreno-44010000
- qcom,adreno-44050a01
- qcom,adreno-44070001
then:
properties:
@@ -443,11 +445,13 @@ allOf:
- qcom,adreno-680.1
- qcom,adreno-690.0
- qcom,adreno-730.1
- qcom,adreno-43020100
- qcom,adreno-43030c00
- qcom,adreno-43050a01
- qcom,adreno-43050c01
- qcom,adreno-43051401
- qcom,adreno-44010000
- qcom,adreno-44050a01
- qcom,adreno-44070001
then: # Starting with A6xx, the clocks are usually defined in the GMU node

View File

@@ -13,7 +13,11 @@ $ref: /schemas/display/msm/dpu-common.yaml#
properties:
compatible:
const: qcom,qcm2290-dpu
oneOf:
- const: qcom,qcm2290-dpu
- items:
- const: qcom,shikra-dpu
- const: qcom,qcm2290-dpu
reg:
items:

View File

@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/display/msm/qcom,qcm2290-mdss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm QCM220 Display MDSS
title: Qualcomm QCM2290 and Shikra Display MDSS
maintainers:
- Loic Poulain <loic.poulain@linaro.org>
@@ -12,13 +12,18 @@ maintainers:
description:
Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates
sub-blocks like DPU display controller and DSI. Device tree bindings of MDSS
are mentioned for QCM2290 target.
are mentioned for QCM2290 and Shikra targets. Shikra uses the same MDSS/DPU/DSI
hardware as QCM2290 (DPU 6.5) and shares the same register layout.
$ref: /schemas/display/msm/mdss-common.yaml#
properties:
compatible:
const: qcom,qcm2290-mdss
oneOf:
- const: qcom,qcm2290-mdss
- items:
- const: qcom,shikra-mdss
- const: qcom,qcm2290-mdss
clocks:
items:
@@ -52,7 +57,8 @@ patternProperties:
properties:
compatible:
const: qcom,qcm2290-dpu
contains:
const: qcom,qcm2290-dpu
"^dsi@[0-9a-f]+$":
type: object
@@ -60,9 +66,8 @@ patternProperties:
properties:
compatible:
items:
- const: qcom,qcm2290-dsi-ctrl
- const: qcom,mdss-dsi-ctrl
contains:
const: qcom,qcm2290-dsi-ctrl
"^phy@[0-9a-f]+$":
type: object

View File

@@ -95,6 +95,7 @@ properties:
- description: Qcom Adreno GPUs implementing "qcom,smmu-500" and "arm,mmu-500"
items:
- enum:
- qcom,eliza-smmu-500
- qcom,glymur-smmu-500
- qcom,hawi-smmu-500
- qcom,kaanapali-smmu-500
@@ -108,6 +109,7 @@ properties:
- qcom,sc7280-smmu-500
- qcom,sc8180x-smmu-500
- qcom,sc8280xp-smmu-500
- qcom,shikra-smmu-500
- qcom,sm6115-smmu-500
- qcom,sm6125-smmu-500
- qcom,sm8150-smmu-500
@@ -543,6 +545,7 @@ allOf:
- enum:
- qcom,milos-smmu-500
- qcom,sar2130p-smmu-500
- qcom,shikra-smmu-500
- qcom,sm8550-smmu-500
- qcom,sm8650-smmu-500
- qcom,x1e80100-smmu-500
@@ -570,6 +573,7 @@ allOf:
compatible:
items:
- enum:
- qcom,eliza-smmu-500
- qcom,glymur-smmu-500
- qcom,hawi-smmu-500
- qcom,kaanapali-smmu-500

View File

@@ -25,6 +25,8 @@
extern bool hang_debug;
#define A3XX_VBIF_XIN_HALT_CTRL0_MASK GENMASK(5, 0)
static void a3xx_dump(struct msm_gpu *gpu);
static bool a3xx_idle(struct msm_gpu *gpu);
@@ -496,6 +498,38 @@ static u64 a3xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
return busy_cycles;
}
static int a3xx_vbif_halt(struct msm_gpu *gpu)
{
u32 ack;
int ret;
gpu_write(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL0,
A3XX_VBIF_XIN_HALT_CTRL0_MASK);
ret = spin_until(((ack = gpu_read(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL1)) &
A3XX_VBIF_XIN_HALT_CTRL0_MASK) ==
A3XX_VBIF_XIN_HALT_CTRL0_MASK);
gpu_write(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL0, 0);
if (ret)
return -EBUSY;
return 0;
}
static int a3xx_pm_suspend(struct msm_gpu *gpu)
{
int ret;
if (!a3xx_idle(gpu))
return -EBUSY;
ret = a3xx_vbif_halt(gpu);
if (ret)
return ret;
return msm_gpu_pm_suspend(gpu);
}
static u32 a3xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR);
@@ -581,7 +615,7 @@ const struct adreno_gpu_funcs a3xx_gpu_funcs = {
.get_param = adreno_get_param,
.set_param = adreno_set_param,
.hw_init = a3xx_hw_init,
.pm_suspend = msm_gpu_pm_suspend,
.pm_suspend = a3xx_pm_suspend,
.pm_resume = msm_gpu_pm_resume,
.recover = a3xx_recover,
.submit = a3xx_submit,

View File

@@ -1275,6 +1275,11 @@ static irqreturn_t a5xx_irq(struct msm_gpu *gpu)
status & ~A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR);
if (priv->disable_err_irq) {
/* Turn off interrupts to avoid interrupt storm */
gpu_write(gpu, REG_A5XX_RBBM_INT_0_MASK,
A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS |
A5XX_RBBM_INT_0_MASK_CP_SW);
status &= A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS |
A5XX_RBBM_INT_0_MASK_CP_SW;
}

View File

@@ -1199,7 +1199,7 @@ static const struct adreno_reglist a730_hwcg[] = {
{ REG_A6XX_RBBM_CLOCK_DELAY_SP0, 0x00000080 },
{ REG_A6XX_RBBM_CLOCK_CNTL_TP0, 0x22222220 },
{ REG_A6XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222 },
{ REG_A6XX_RBBM_CLOCK_CNTL3_TP0, 0x22222222 },
{ REG_A6XX_RBBM_CLOCK_CNTL3_TP0, 0x22220222 },
{ REG_A6XX_RBBM_CLOCK_CNTL4_TP0, 0x00222222 },
{ REG_A6XX_RBBM_CLOCK_HYST_TP0, 0x77777777 },
{ REG_A6XX_RBBM_CLOCK_HYST2_TP0, 0x77777777 },
@@ -1454,7 +1454,7 @@ DECLARE_ADRENO_REGLIST_PIPE_LIST(a7xx_dyn_pwrup_reglist);
static const struct adreno_info a7xx_gpus[] = {
{
.chip_ids = ADRENO_CHIP_IDS(0x07000200),
.chip_ids = ADRENO_CHIP_IDS(0x07000200, 0x07000400),
.family = ADRENO_6XX_GEN1, /* NOT a mistake! */
.fw = {
[ADRENO_FW_SQE] = "a702_sqe.fw",
@@ -1500,6 +1500,40 @@ static const struct adreno_info a7xx_gpus[] = {
.gmu_cgc_mode = 0x00020000,
},
.preempt_record_size = 2860 * SZ_1K,
}, {
.chip_ids = ADRENO_CHIP_IDS(0x43020100),
.family = ADRENO_7XX_GEN1,
.fw = {
[ADRENO_FW_SQE] = "qcom/gen71700_sqe.fw",
[ADRENO_FW_GMU] = "qcom/gen71700_gmu.bin",
},
.gmem = SZ_1M,
.inactive_period = DRM_MSM_INACTIVE_PERIOD,
.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
ADRENO_QUIRK_HAS_HW_APRIV |
ADRENO_QUIRK_PREEMPTION,
.funcs = &a7xx_gpu_funcs,
.a6xx = &(const struct a6xx_info) {
.hwcg = a730_hwcg,
.protect = &a730_protect,
.pwrup_reglist = &a7xx_pwrup_reglist,
.dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist,
.gbif_cx = a640_gbif,
.gmu_chipid = 0x07110000,
.gmu_cgc_mode = 0x00020000,
.bcms = (const struct a6xx_bcm[]) {
{ .name = "SH0", .buswidth = 16 },
{ .name = "MC0", .buswidth = 4 },
{
.name = "ACV",
.fixed = true,
.perfmode = BIT(3),
.perfmode_bw = 16500000,
},
{ /* sentinel */ },
},
},
.preempt_record_size = 1536 * SZ_1K,
}, {
.chip_ids = ADRENO_CHIP_IDS(0x43050a01), /* "C510v2" */
.family = ADRENO_7XX_GEN2,
@@ -2180,7 +2214,7 @@ static const struct adreno_reglist a840_gbif[] = {
{ REG_A6XX_GBIF_QSB_SIDE1, 0x00071e20 },
{ REG_A6XX_GBIF_QSB_SIDE2, 0x00071e20 },
{ REG_A6XX_GBIF_QSB_SIDE3, 0x00071e20 },
{ REG_A8XX_GBIF_CX_CONFIG, 0x20023000 },
{ REG_A6XX_GBIF_CX_CONFIG, 0x20023000 },
{ },
};

View File

@@ -642,7 +642,7 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu)
int ret;
u32 val;
if (test_and_clear_bit(GMU_STATUS_FW_START, &gmu->status))
if (!test_and_clear_bit(GMU_STATUS_FW_START, &gmu->status))
return;
if (adreno_is_a840(adreno_gpu))
@@ -710,7 +710,8 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 2, 0);
gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 2, 0);
gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 4,
adreno_is_a740_family(adreno_gpu) ? 0x80000021 : 0x80000000);
(adreno_is_a740_family(adreno_gpu) ||
adreno_is_a722(adreno_gpu)) ? 0x80000021 : 0x80000000);
gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 4, 0);
gmu_write_rscc(gmu, REG_A6XX_RSCC_OVERRIDE_START_ADDR, 0);
gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520);
@@ -718,7 +719,7 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514);
/* The second spin of A7xx GPUs messed with some register offsets.. */
if (adreno_is_a740_family(adreno_gpu))
if (adreno_is_a740_family(adreno_gpu) || adreno_is_a722(adreno_gpu))
seqmem0_drv0_reg = REG_A7XX_RSCC_SEQ_MEM_0_DRV0_A740;
/* Load RSC sequencer uCode for sleep and wakeup */
@@ -1032,9 +1033,11 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
gpu_write(gpu, gbif_cx[i].offset, gbif_cx[i].value);
if (adreno_is_a8xx(adreno_gpu)) {
gpu_write(gpu, REG_A8XX_GBIF_CX_CONFIG, 0x20023000);
gpu_write(gpu, REG_A6XX_GBIF_CX_CONFIG, 0x20023000);
gmu_write(gmu, REG_A6XX_GMU_MRC_GBIF_QOS_CTRL, 0x33);
}
} else if (adreno_is_a722(adreno_gpu))
gpu_rmw(gpu, REG_A6XX_GBIF_CX_CONFIG, GENMASK(31, 29),
FIELD_PREP(GENMASK(31, 29), 2));
/* Set up the lowest idle level on the GMU */
a6xx_gmu_power_config(gmu);
@@ -1087,7 +1090,8 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
u32 val, seqmem_off = 0;
/* The second spin of A7xx GPUs messed with some register offsets.. */
if (adreno_is_a740_family(adreno_gpu) || adreno_is_a8xx(adreno_gpu))
if (adreno_is_a740_family(adreno_gpu) || adreno_is_a722(adreno_gpu) ||
adreno_is_a8xx(adreno_gpu))
seqmem_off = 4;
/* Make sure there are no outstanding RPMh votes */
@@ -1100,7 +1104,8 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS + seqmem_off,
val, (val & 1), 100, 1000);
if (!adreno_is_a740_family(adreno_gpu) && !adreno_is_a8xx(adreno_gpu))
if (!adreno_is_a740_family(adreno_gpu) && !adreno_is_a722(adreno_gpu) &&
!adreno_is_a8xx(adreno_gpu))
return;
gmu_poll_timeout_rscc(gmu, REG_A7XX_RSCC_TCS4_DRV0_STATUS + seqmem_off,
@@ -1465,6 +1470,9 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu)
/* Stop the interrupts and mask the hardware */
a6xx_gmu_irq_disable(gmu);
/* Halt the gmu cm3 core */
gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1);
/* Tell RPMh to power off the GPU */
a6xx_rpmh_stop(gmu);
@@ -1546,7 +1554,7 @@ static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo,
flags |= MSM_BO_MAP_PRIV;
}
bo->obj = msm_gem_new(dev, size, flags);
bo->obj = msm_gem_new(dev, size, flags, NULL);
if (IS_ERR(bo->obj))
return PTR_ERR(bo->obj);

View File

@@ -229,7 +229,7 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,
{
bool sysprof = msm_gpu_sysprof_no_perfcntr_zap(&a6xx_gpu->base.base);
struct msm_context *ctx = submit->queue->ctx;
struct drm_gpuvm *vm = msm_context_vm(submit->dev, ctx);
struct drm_gpuvm *vm = ctx->vm;
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
phys_addr_t ttbr;
u32 asid;
@@ -1273,7 +1273,8 @@ static int hw_init(struct msm_gpu *gpu)
if (!(adreno_is_a650_family(adreno_gpu) ||
adreno_is_a702(adreno_gpu) ||
adreno_is_a730(adreno_gpu))) {
gmem_range_min = adreno_is_a740_family(adreno_gpu) ? SZ_16M : SZ_1M;
gmem_range_min = (adreno_is_a740_family(adreno_gpu) ||
adreno_is_a722(adreno_gpu)) ? SZ_16M : SZ_1M;
/* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */
gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN, gmem_range_min);
@@ -1338,6 +1339,7 @@ static int hw_init(struct msm_gpu *gpu)
/* Enable fault detection */
if (adreno_is_a612(adreno_gpu) ||
adreno_is_a722(adreno_gpu) ||
adreno_is_a730(adreno_gpu) ||
adreno_is_a740_family(adreno_gpu))
gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0xcfffff);
@@ -1911,8 +1913,11 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
gpu_write(gpu, REG_A6XX_RBBM_INT_CLEAR_CMD, status);
if (priv->disable_err_irq)
if (priv->disable_err_irq) {
/* Turn off interrupts to avoid interrupt storm */
gpu_write(gpu, REG_A6XX_RBBM_INT_0_MASK, A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS);
status &= A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS;
}
if (status & A6XX_RBBM_INT_0_MASK_RBBM_HANG_DETECT)
a6xx_fault_detect_irq(gpu);
@@ -2770,8 +2775,9 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
adreno_gpu->ubwc_config = qcom_ubwc_config_get_data();
if (IS_ERR(adreno_gpu->ubwc_config)) {
ret = PTR_ERR(adreno_gpu->ubwc_config);
a6xx_destroy(&(a6xx_gpu->base.base));
return ERR_CAST(adreno_gpu->ubwc_config);
return ERR_PTR(ret);
}
/* Set up the preemption specific bits and pieces for each ringbuffer */

View File

@@ -11,12 +11,14 @@
static const unsigned int *gen7_0_0_external_core_regs[] __always_unused;
static const unsigned int *gen7_2_0_external_core_regs[] __always_unused;
static const unsigned int *gen7_9_0_external_core_regs[] __always_unused;
static const unsigned int *gen7_17_0_external_core_regs[] __always_unused;
static const struct gen7_sptp_cluster_registers gen7_9_0_sptp_clusters[] __always_unused;
static const u32 gen7_9_0_cx_debugbus_blocks[] __always_unused;
#include "adreno_gen7_0_0_snapshot.h"
#include "adreno_gen7_2_0_snapshot.h"
#include "adreno_gen7_9_0_snapshot.h"
#include "adreno_gen7_17_0_snapshot.h"
struct a6xx_gpu_state_obj {
const void *handle;
@@ -404,8 +406,13 @@ static void a7xx_get_debugbus_blocks(struct msm_gpu *gpu,
int i;
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
debugbus_blocks = gen7_0_0_debugbus_blocks;
debugbus_blocks_count = ARRAY_SIZE(gen7_0_0_debugbus_blocks);
if (adreno_is_a722(adreno_gpu)) {
debugbus_blocks = gen7_17_0_debugbus_blocks;
debugbus_blocks_count = ARRAY_SIZE(gen7_17_0_debugbus_blocks);
} else {
debugbus_blocks = gen7_0_0_debugbus_blocks;
debugbus_blocks_count = ARRAY_SIZE(gen7_0_0_debugbus_blocks);
}
gbif_debugbus_blocks = a7xx_gbif_debugbus_blocks;
gbif_debugbus_blocks_count = ARRAY_SIZE(a7xx_gbif_debugbus_blocks);
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
@@ -678,8 +685,13 @@ static void a7xx_get_dbgahb_clusters(struct msm_gpu *gpu,
unsigned dbgahb_clusters_size;
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
dbgahb_clusters = gen7_0_0_sptp_clusters;
dbgahb_clusters_size = ARRAY_SIZE(gen7_0_0_sptp_clusters);
if (adreno_is_a722(adreno_gpu)) {
dbgahb_clusters = gen7_17_0_sptp_clusters;
dbgahb_clusters_size = ARRAY_SIZE(gen7_17_0_sptp_clusters);
} else {
dbgahb_clusters = gen7_0_0_sptp_clusters;
dbgahb_clusters_size = ARRAY_SIZE(gen7_0_0_sptp_clusters);
}
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
dbgahb_clusters = gen7_2_0_sptp_clusters;
dbgahb_clusters_size = ARRAY_SIZE(gen7_2_0_sptp_clusters);
@@ -839,8 +851,13 @@ static void a7xx_get_clusters(struct msm_gpu *gpu,
unsigned clusters_size;
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
clusters = gen7_0_0_clusters;
clusters_size = ARRAY_SIZE(gen7_0_0_clusters);
if (adreno_is_a722(adreno_gpu)) {
clusters = gen7_17_0_clusters;
clusters_size = ARRAY_SIZE(gen7_17_0_clusters);
} else {
clusters = gen7_0_0_clusters;
clusters_size = ARRAY_SIZE(gen7_0_0_clusters);
}
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
clusters = gen7_2_0_clusters;
clusters_size = ARRAY_SIZE(gen7_2_0_clusters);
@@ -977,8 +994,13 @@ static void a7xx_get_shaders(struct msm_gpu *gpu,
int i;
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
shader_blocks = gen7_0_0_shader_blocks;
num_shader_blocks = ARRAY_SIZE(gen7_0_0_shader_blocks);
if (adreno_is_a722(adreno_gpu)) {
shader_blocks = gen7_17_0_shader_blocks;
num_shader_blocks = ARRAY_SIZE(gen7_17_0_shader_blocks);
} else {
shader_blocks = gen7_0_0_shader_blocks;
num_shader_blocks = ARRAY_SIZE(gen7_0_0_shader_blocks);
}
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
shader_blocks = gen7_2_0_shader_blocks;
num_shader_blocks = ARRAY_SIZE(gen7_2_0_shader_blocks);
@@ -1244,9 +1266,12 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu,
_a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gmu_reglist[1],
&a6xx_state->gmu_registers[1], true);
if (adreno_is_a621(adreno_gpu) || adreno_is_a623(adreno_gpu))
if (adreno_is_a621(adreno_gpu))
_a6xx_get_gmu_registers(gpu, a6xx_state, &a621_gpucc_reg,
&a6xx_state->gmu_registers[2], false);
else if (adreno_is_a623(adreno_gpu) || adreno_is_a663(adreno_gpu))
_a6xx_get_gmu_registers(gpu, a6xx_state, &a623_gpucc_reg,
&a6xx_state->gmu_registers[2], false);
else
_a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gpucc_reg,
&a6xx_state->gmu_registers[2], false);
@@ -1376,8 +1401,13 @@ static void a7xx_get_registers(struct msm_gpu *gpu,
const struct gen7_reg_list *reglist;
if (adreno_gpu->info->family == ADRENO_7XX_GEN1) {
reglist = gen7_0_0_reg_list;
pre_crashdumper_regs = gen7_0_0_pre_crashdumper_gpu_registers;
if (adreno_is_a722(adreno_gpu)) {
reglist = gen7_17_0_reg_list;
pre_crashdumper_regs = gen7_9_0_pre_crashdumper_gpu_registers;
} else {
reglist = gen7_0_0_reg_list;
pre_crashdumper_regs = gen7_0_0_pre_crashdumper_gpu_registers;
}
} else if (adreno_gpu->info->family == ADRENO_7XX_GEN2) {
reglist = gen7_2_0_reg_list;
pre_crashdumper_regs = gen7_0_0_pre_crashdumper_gpu_registers;
@@ -1433,7 +1463,9 @@ static void a7xx_get_post_crashdumper_registers(struct msm_gpu *gpu,
const u32 *regs;
BUG_ON(adreno_gpu->info->family > ADRENO_7XX_GEN3);
regs = gen7_0_0_post_crashdumper_registers;
regs = adreno_is_a722(adreno_gpu) ?
gen7_17_0_post_crashdumper_registers :
gen7_0_0_post_crashdumper_registers;
a7xx_get_ahb_gpu_registers(gpu,
a6xx_state, regs,
@@ -1540,19 +1572,35 @@ static void a7xx_get_indexed_registers(struct msm_gpu *gpu,
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
const struct a6xx_indexed_registers *indexed_regs;
const struct a6xx_indexed_registers *mempool_regs;
int i, indexed_count, mempool_count;
bool concurrent_binning;
if (adreno_gpu->info->family <= ADRENO_7XX_GEN2) {
if (adreno_is_a722(adreno_gpu)) {
/*
* Eliza has no BV or LPAC SQE skip the BV/LPAC indexed
* registers and the BV mempool
*/
indexed_regs = gen7_17_0_cp_indexed_reglist;
indexed_count = ARRAY_SIZE(gen7_17_0_cp_indexed_reglist);
mempool_regs = a7xx_cp_mempool_indexed;
mempool_count = ARRAY_SIZE(a7xx_cp_mempool_indexed);
concurrent_binning = false;
} else if (adreno_gpu->info->family <= ADRENO_7XX_GEN2) {
indexed_regs = a7xx_indexed_reglist;
indexed_count = ARRAY_SIZE(a7xx_indexed_reglist);
mempool_regs = a7xx_cp_bv_mempool_indexed;
mempool_count = ARRAY_SIZE(a7xx_cp_bv_mempool_indexed);
concurrent_binning = true;
} else {
BUG_ON(adreno_gpu->info->family != ADRENO_7XX_GEN3);
indexed_regs = gen7_9_0_cp_indexed_reg_list;
indexed_count = ARRAY_SIZE(gen7_9_0_cp_indexed_reg_list);
mempool_regs = a7xx_cp_bv_mempool_indexed;
mempool_count = ARRAY_SIZE(a7xx_cp_bv_mempool_indexed);
concurrent_binning = true;
}
mempool_count = ARRAY_SIZE(a7xx_cp_bv_mempool_indexed);
a6xx_state->indexed_regs = state_kcalloc(a6xx_state,
indexed_count + mempool_count,
sizeof(*a6xx_state->indexed_regs));
@@ -1567,15 +1615,17 @@ static void a7xx_get_indexed_registers(struct msm_gpu *gpu,
&a6xx_state->indexed_regs[i]);
gpu_rmw(gpu, REG_A6XX_CP_CHICKEN_DBG, 0, BIT(2));
gpu_rmw(gpu, REG_A7XX_CP_BV_CHICKEN_DBG, 0, BIT(2));
if (concurrent_binning)
gpu_rmw(gpu, REG_A7XX_CP_BV_CHICKEN_DBG, 0, BIT(2));
/* Get the contents of the CP_BV mempool */
for (i = 0; i < mempool_count; i++)
a6xx_get_indexed_regs(gpu, a6xx_state, &a7xx_cp_bv_mempool_indexed[i],
a6xx_get_indexed_regs(gpu, a6xx_state, &mempool_regs[i],
&a6xx_state->indexed_regs[indexed_count + i]);
gpu_rmw(gpu, REG_A6XX_CP_CHICKEN_DBG, BIT(2), 0);
gpu_rmw(gpu, REG_A7XX_CP_BV_CHICKEN_DBG, BIT(2), 0);
if (concurrent_binning)
gpu_rmw(gpu, REG_A7XX_CP_BV_CHICKEN_DBG, BIT(2), 0);
return;
}

View File

@@ -377,6 +377,17 @@ static const u32 a6xx_gmu_gpucc_registers[] = {
};
static const u32 a621_gmu_gpucc_registers[] = {
/* GPU CC */
0x24000, 0x2400e, 0x24400, 0x2440e, 0x24800, 0x24805, 0x24c00, 0x24cff,
0x25800, 0x25804, 0x25c00, 0x25c04, 0x26000, 0x26004, 0x26400, 0x26405,
0x26414, 0x2641d, 0x2642a, 0x26430, 0x26432, 0x26432, 0x26441, 0x26455,
0x26466, 0x26468, 0x26478, 0x2647a, 0x26489, 0x2648a, 0x2649c, 0x2649e,
0x264a0, 0x264a3, 0x264b3, 0x264b5, 0x264c5, 0x264c7, 0x264d6, 0x264d8,
0x264e8, 0x264e9, 0x264f9, 0x264fc, 0x2650b, 0x2650c, 0x2651c, 0x2651e,
0x26540, 0x26570, 0x26600, 0x26616, 0x26620, 0x2662d,
};
static const u32 a623_gmu_gpucc_registers[] = {
/* GPU CC */
0x24000, 0x2400e, 0x24400, 0x2440e, 0x25800, 0x25804, 0x25c00, 0x25c04,
0x26000, 0x26004, 0x26400, 0x26405, 0x26414, 0x2641d, 0x2642a, 0x26430,
@@ -402,6 +413,7 @@ static const struct a6xx_registers a6xx_gmu_reglist[] = {
static const struct a6xx_registers a6xx_gpucc_reg = REGS(a6xx_gmu_gpucc_registers, 0, 0);
static const struct a6xx_registers a621_gpucc_reg = REGS(a621_gmu_gpucc_registers, 0, 0);
static const struct a6xx_registers a623_gpucc_reg = REGS(a623_gmu_gpucc_registers, 0, 0);
static u32 a6xx_get_cp_roq_size(struct msm_gpu *gpu);
static u32 a7xx_get_cp_roq_size(struct msm_gpu *gpu);
@@ -462,6 +474,11 @@ static const struct a6xx_indexed_registers a7xx_cp_bv_mempool_indexed[] = {
REG_A7XX_CP_BV_MEM_POOL_DBG_DATA, 0x2200, NULL },
};
static const struct a6xx_indexed_registers a7xx_cp_mempool_indexed[] = {
{ "CP_MEM_POOL_DBG", REG_A6XX_CP_MEM_POOL_DBG_ADDR,
REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2200, NULL },
};
#define DEBUGBUS(_id, _count) { .id = _id, .name = #_id, .count = _count }
static const struct a6xx_debugbus_block {

View File

@@ -228,7 +228,7 @@ static void a8xx_set_hwcg(struct msm_gpu *gpu, bool state)
* GMU enables clk gating in GBIF during boot up. So,
* override that here when hwcg feature is disabled
*/
gpu_rmw(gpu, REG_A8XX_GBIF_CX_CONFIG, BIT(0), 0);
gpu_rmw(gpu, REG_A6XX_GBIF_CX_CONFIG, BIT(0), 0);
}
}
@@ -1211,8 +1211,11 @@ irqreturn_t a8xx_irq(struct msm_gpu *gpu)
gpu_write(gpu, REG_A8XX_RBBM_INT_CLEAR_CMD, status);
if (priv->disable_err_irq)
if (priv->disable_err_irq) {
/* Turn off interrupts to avoid interrupt storm */
gpu_write(gpu, REG_A8XX_RBBM_INT_0_MASK, A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS);
status &= A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS;
}
if (status & A6XX_RBBM_INT_0_MASK_RBBM_HANG_DETECT)
a8xx_fault_detect_irq(gpu);

View File

@@ -0,0 +1,428 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __ADRENO_GEN7_17_0_SNAPSHOT_H
#define __ADRENO_GEN7_17_0_SNAPSHOT_H
#include "a6xx_gpu_state.h"
/*
* Snapshot tables for Adreno A722 (Eliza).
* Cluster sub-arrays that are identical to A730 reference gen7_0_0_*
* symbols; adreno_gen7_0_0_snapshot.h is included first in the TU.
*/
static const u32 gen7_17_0_rscc_registers[] = {
0x14000, 0x14034, 0x14036, 0x14036, 0x14040, 0x14042, 0x14044, 0x14045,
0x14047, 0x14047, 0x14080, 0x14084, 0x14089, 0x1408c, 0x14091, 0x14094,
0x14099, 0x1409c, 0x140a1, 0x140a4, 0x140a9, 0x140ac, 0x140b1, 0x140b4,
0x140b9, 0x140bc, 0x14100, 0x14104, 0x14114, 0x14119, 0x14124, 0x14132,
0x14154, 0x1416b, 0x14340, 0x14341, 0x14344, 0x14344, 0x14346, 0x1437c,
0x143f0, 0x143f8, 0x143fa, 0x143fe, 0x14400, 0x14404, 0x14406, 0x1440a,
0x1440c, 0x14410, 0x14412, 0x14416, 0x14418, 0x1441c, 0x1441e, 0x14422,
0x14424, 0x14424, 0x14498, 0x144a0, 0x144a2, 0x144a6, 0x144a8, 0x144ac,
0x144ae, 0x144b2, 0x144b4, 0x144b8, 0x144ba, 0x144be, 0x144c0, 0x144c4,
0x144c6, 0x144ca, 0x144cc, 0x144cc, 0x14540, 0x14548, 0x1454a, 0x1454e,
0x14550, 0x14554, 0x14556, 0x1455a, 0x1455c, 0x14560, 0x14562, 0x14566,
0x14568, 0x1456c, 0x1456e, 0x14572, 0x14574, 0x14574, 0x145e8, 0x145f0,
0x145f2, 0x145f6, 0x145f8, 0x145fc, 0x145fe, 0x14602, 0x14604, 0x14608,
0x1460a, 0x1460e, 0x14610, 0x14614, 0x14616, 0x1461a, 0x1461c, 0x1461c,
0x14690, 0x14698, 0x1469a, 0x1469e, 0x146a0, 0x146a4, 0x146a6, 0x146aa,
0x146ac, 0x146b0, 0x146b2, 0x146b6, 0x146b8, 0x146bc, 0x146be, 0x146c2,
0x146c4, 0x146c4, 0x14738, 0x14740, 0x14742, 0x14746, 0x14748, 0x1474c,
0x1474e, 0x14752, 0x14754, 0x14758, 0x1475a, 0x1475e, 0x14760, 0x14764,
0x14766, 0x1476a, 0x1476c, 0x1476c, 0x147e0, 0x147e8, 0x147ea, 0x147ee,
0x147f0, 0x147f4, 0x147f6, 0x147fa, 0x147fc, 0x14800, 0x14802, 0x14806,
0x14808, 0x1480c, 0x1480e, 0x14812, 0x14814, 0x14814, 0x14888, 0x14890,
0x14892, 0x14896, 0x14898, 0x1489c, 0x1489e, 0x148a2, 0x148a4, 0x148a8,
0x148aa, 0x148ae, 0x148b0, 0x148b4, 0x148b6, 0x148ba, 0x148bc, 0x148bc,
0x14930, 0x14938, 0x1493a, 0x1493e, 0x14940, 0x14944, 0x14946, 0x1494a,
0x1494c, 0x14950, 0x14952, 0x14956, 0x14958, 0x1495c, 0x1495e, 0x14962,
0x14964, 0x14964,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_rscc_registers), 8));
static const u32 gen7_17_0_cpr_registers[] = {
0x26800, 0x26805, 0x26808, 0x2680c, 0x26814, 0x26814, 0x2681c, 0x2681c,
0x26820, 0x26838, 0x26840, 0x26840, 0x26848, 0x26848, 0x26850, 0x26850,
0x26880, 0x2688e, 0x26980, 0x269b0, 0x269c0, 0x269c2, 0x269c6, 0x269c8,
0x269e0, 0x269ee, 0x269fb, 0x269ff, 0x26a02, 0x26a07, 0x26a09, 0x26a0b,
0x26a10, 0x26b0f, 0x27440, 0x27441, 0x27444, 0x27444, 0x27480, 0x274a2,
0x274ac, 0x274c4, 0x274c8, 0x274da,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_cpr_registers), 8));
static const u32 gen7_17_0_gpucc_registers[] = {
0x24000, 0x2400f, 0x24400, 0x2440f, 0x24800, 0x24805, 0x24c00, 0x24cff,
0x25400, 0x25404, 0x25800, 0x25804, 0x25c00, 0x25c04, 0x26000, 0x26004,
0x26400, 0x26405, 0x26414, 0x2641d, 0x2642a, 0x2642c, 0x2642e, 0x26432,
0x26434, 0x26434, 0x26443, 0x26457, 0x26459, 0x2645d, 0x2645f, 0x26464,
0x26477, 0x26479, 0x26489, 0x2648b, 0x2649a, 0x2649b, 0x264ad, 0x264af,
0x264b1, 0x264b5, 0x264d6, 0x264d8, 0x264e7, 0x264e9, 0x264f9, 0x264fa,
0x2650a, 0x2650d, 0x2651f, 0x26520, 0x2652d, 0x2652f, 0x2653e, 0x2653e,
0x26540, 0x2654e, 0x26554, 0x26573, 0x26576, 0x26576, 0x26593, 0x26593,
0x26600, 0x26616, 0x26620, 0x2662d, 0x26630, 0x26631, 0x26635, 0x26635,
0x26637, 0x26637, 0x2663a, 0x2663a, 0x26642, 0x26642, 0x26656, 0x26658,
0x2665b, 0x2665d, 0x2665f, 0x26662,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_gpucc_registers), 8));
static const u32 *gen7_17_0_external_core_regs[] = {
gen7_17_0_gpucc_registers,
gen7_17_0_cpr_registers,
};
static const u32 gen7_17_0_debugbus_blocks[] = {
A7XX_DBGBUS_CP_0_0,
A7XX_DBGBUS_CP_0_1,
A7XX_DBGBUS_RBBM,
A7XX_DBGBUS_HLSQ,
A7XX_DBGBUS_UCHE_0,
A7XX_DBGBUS_TESS_BR,
A7XX_DBGBUS_PC_BR,
A7XX_DBGBUS_VFDP_BR,
A7XX_DBGBUS_VPC_BR,
A7XX_DBGBUS_TSE_BR,
A7XX_DBGBUS_RAS_BR,
A7XX_DBGBUS_VSC,
A7XX_DBGBUS_COM_0,
A7XX_DBGBUS_LRZ_BR,
A7XX_DBGBUS_UFC_0,
A7XX_DBGBUS_UFC_1,
A7XX_DBGBUS_GMU_GX,
A7XX_DBGBUS_DBGC,
A7XX_DBGBUS_GPC_BR,
A7XX_DBGBUS_LARC,
A7XX_DBGBUS_HLSQ_SPTP,
A7XX_DBGBUS_RB_0,
A7XX_DBGBUS_RB_1,
A7XX_DBGBUS_UCHE_WRAPPER,
A7XX_DBGBUS_CCU_0,
A7XX_DBGBUS_CCU_1,
A7XX_DBGBUS_VFD_BR_0,
A7XX_DBGBUS_VFD_BR_1,
A7XX_DBGBUS_VFD_BR_2,
A7XX_DBGBUS_VFD_BR_3,
A7XX_DBGBUS_USP_0,
A7XX_DBGBUS_USP_1,
A7XX_DBGBUS_TP_0,
A7XX_DBGBUS_TP_1,
A7XX_DBGBUS_TP_2,
A7XX_DBGBUS_TP_3,
A7XX_DBGBUS_USPTP_0,
A7XX_DBGBUS_USPTP_1,
A7XX_DBGBUS_USPTP_2,
A7XX_DBGBUS_USPTP_3,
};
static const struct gen7_sel_reg gen7_17_0_rb_rac_sel = {
.host_reg = REG_A6XX_RB_SUB_BLOCK_SEL_CNTL_HOST,
.cd_reg = REG_A6XX_RB_SUB_BLOCK_SEL_CNTL_CD,
.val = 0x0,
};
static const struct gen7_sel_reg gen7_17_0_rb_rbp_sel = {
.host_reg = REG_A6XX_RB_SUB_BLOCK_SEL_CNTL_HOST,
.cd_reg = REG_A6XX_RB_SUB_BLOCK_SEL_CNTL_CD,
.val = 0x9,
};
static const u32 gen7_17_0_post_crashdumper_registers[] = {
0x00535, 0x00535,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_post_crashdumper_registers), 8));
static const u32 gen7_17_0_gpu_registers[] = {
0x00000, 0x00000, 0x00002, 0x00002, 0x00011, 0x00012, 0x00016, 0x0001b,
0x0001f, 0x00032, 0x00038, 0x0003c, 0x00042, 0x00042, 0x00044, 0x00044,
0x00047, 0x00047, 0x00049, 0x0004a, 0x0004c, 0x0004c, 0x00050, 0x00050,
0x00056, 0x00056, 0x00073, 0x00075, 0x000ad, 0x000ae, 0x000b0, 0x000b0,
0x000b4, 0x000b4, 0x000b8, 0x000b8, 0x000bc, 0x000bc, 0x000c0, 0x000c0,
0x000c4, 0x000c4, 0x000c8, 0x000c8, 0x000cc, 0x000cc, 0x000d0, 0x000d0,
0x000d4, 0x000d4, 0x000d8, 0x000d8, 0x000dc, 0x000dc, 0x000e0, 0x000e0,
0x000e4, 0x000e4, 0x000e8, 0x000e8, 0x000ec, 0x000ec, 0x000f0, 0x000f0,
0x000f4, 0x000f4, 0x000f8, 0x000f8, 0x00100, 0x00100, 0x00104, 0x0010b,
0x0010f, 0x0011d, 0x0012f, 0x0012f, 0x00200, 0x0020d, 0x00215, 0x00243,
0x00260, 0x00268, 0x00272, 0x00274, 0x00286, 0x00286, 0x0028a, 0x0028a,
0x0028c, 0x0028c, 0x00300, 0x00401, 0x00500, 0x00500, 0x00507, 0x0050b,
0x0050f, 0x0050f, 0x00511, 0x00511, 0x00533, 0x00534, 0x00540, 0x00555,
0x00564, 0x00567, 0x00800, 0x00808, 0x00810, 0x00813, 0x00820, 0x00821,
0x00823, 0x00827, 0x00830, 0x00834, 0x00840, 0x00841, 0x00843, 0x00847,
0x0084f, 0x00886, 0x008a0, 0x008ab, 0x008c0, 0x008c0, 0x008c4, 0x008c5,
0x008d0, 0x008dd, 0x008f0, 0x008f3, 0x00900, 0x00903, 0x00908, 0x00911,
0x00928, 0x0093e, 0x00942, 0x0094d, 0x00980, 0x00984, 0x0098d, 0x0098f,
0x009b0, 0x009b4, 0x009c2, 0x009c9, 0x009ce, 0x009d7, 0x00a00, 0x00a00,
0x00a02, 0x00a03, 0x00a10, 0x00a4f, 0x00a67, 0x00a6c, 0x00a9c, 0x00a9f,
0x00c00, 0x00c00, 0x00c02, 0x00c04, 0x00c06, 0x00c06, 0x00c10, 0x00cd9,
0x00ce0, 0x00d0c, 0x00df0, 0x00df4, 0x00e01, 0x00e02, 0x00e07, 0x00e0e,
0x00e10, 0x00e12, 0x00e17, 0x00e17, 0x00e19, 0x00e19, 0x00e1b, 0x00e2b,
0x00e30, 0x00e32, 0x00e38, 0x00e3c,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_gpu_registers), 8));
static const u32 gen7_17_0_dbgc_registers[] = {
0x00600, 0x0061c, 0x0061e, 0x00634, 0x00640, 0x0065a, 0x00679, 0x0067a,
0x00699, 0x00699, 0x0069b, 0x0069e, 0x18400, 0x1841c, 0x1841e, 0x18434,
0x18440, 0x1845c, 0x18479, 0x1847c, 0x18580, 0x18581,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_dbgc_registers), 8));
static const u32 gen7_17_0_noncontext_pipe_br_registers[] = {
0x00887, 0x0088c, 0x08600, 0x08600, 0x08602, 0x08602, 0x08610, 0x0861b,
0x08620, 0x08620, 0x08630, 0x08630, 0x08637, 0x08639, 0x08640, 0x08640,
0x09600, 0x09600, 0x09602, 0x09603, 0x0960a, 0x09616, 0x09624, 0x0963a,
0x09640, 0x09640, 0x09e00, 0x09e00, 0x09e02, 0x09e07, 0x09e0a, 0x09e16,
0x09e19, 0x09e19, 0x09e1c, 0x09e1c, 0x09e20, 0x09e25, 0x09e30, 0x09e31,
0x09e40, 0x09e51, 0x09e64, 0x09e64, 0x09e70, 0x09e72, 0x09e78, 0x09e79,
0x09e80, 0x09fff, 0x0a600, 0x0a600, 0x0a603, 0x0a603, 0x0a610, 0x0a61f,
0x0a630, 0x0a631, 0x0a638, 0x0a638,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_noncontext_pipe_br_registers), 8));
static const u32 gen7_17_0_noncontext_rb_rac_pipe_br_registers[] = {
0x08e10, 0x08e1c, 0x08e20, 0x08e25, 0x08e51, 0x08e54,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_noncontext_rb_rac_pipe_br_registers), 8));
static const u32 gen7_17_0_noncontext_rb_rbp_pipe_br_registers[] = {
0x08e01, 0x08e01, 0x08e04, 0x08e04, 0x08e06, 0x08e09, 0x08e0c, 0x08e0c,
0x08e28, 0x08e28, 0x08e2c, 0x08e35, 0x08e3b, 0x08e3f, 0x08e50, 0x08e50,
0x08e5b, 0x08e5d, 0x08e5f, 0x08e5f, 0x08e61, 0x08e61, 0x08e63, 0x08e65,
0x08e68, 0x08e68, 0x08e70, 0x08e79, 0x08e80, 0x08e8f,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_noncontext_rb_rbp_pipe_br_registers), 8));
static const u32 gen7_17_0_pc_cluster_fe_pipe_br_registers[] = {
0x09800, 0x09804, 0x09806, 0x0980a, 0x09810, 0x09811, 0x09884, 0x09886,
0x09970, 0x09972, 0x09b00, 0x09b08,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_pc_cluster_fe_pipe_br_registers), 8));
static const u32 gen7_17_0_sp_cluster_sp_ps_pipe_lpac_hlsq_state_registers[] = {
0x0aa40, 0x0aabf,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_sp_cluster_sp_ps_pipe_lpac_hlsq_state_registers), 8));
static const u32 gen7_17_0_sp_cluster_sp_ps_pipe_lpac_usptp_registers[] = {
0x0aa40, 0x0aabf,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_sp_cluster_sp_ps_pipe_lpac_usptp_registers), 8));
static const u32 gen7_17_0_non_context_tpl1_pipe_none_usptp_registers[] = {
0x0b602, 0x0b602, 0x0b604, 0x0b604, 0x0b608, 0x0b60c, 0x0b60f, 0x0b621,
0x0b630, 0x0b633,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_non_context_tpl1_pipe_none_usptp_registers), 8));
static const u32 gen7_17_0_non_context_tpl1_pipe_br_usptp_registers[] = {
0x0b600, 0x0b600,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_non_context_tpl1_pipe_br_usptp_registers), 8));
static const u32 gen7_17_0_tpl1_cluster_sp_vs_pipe_br_usptp_registers[] = {
0x0b300, 0x0b307, 0x0b309, 0x0b309, 0x0b310, 0x0b310,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_tpl1_cluster_sp_vs_pipe_br_usptp_registers), 8));
static const u32 gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers[] = {
0x0b180, 0x0b183, 0x0b190, 0x0b195, 0x0b2c0, 0x0b2d5, 0x0b300, 0x0b307,
0x0b309, 0x0b309, 0x0b310, 0x0b310,
UINT_MAX, UINT_MAX,
};
static_assert(IS_ALIGNED(sizeof(gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers), 8));
/* No BV pipe — gen7_0_0_* sub-arrays are shared from adreno_gen7_0_0_snapshot.h */
static struct gen7_cluster_registers gen7_17_0_clusters[] = {
{ A7XX_CLUSTER_NONE, PIPE_BR, STATE_NON_CONTEXT,
gen7_17_0_noncontext_pipe_br_registers, },
{ A7XX_CLUSTER_NONE, PIPE_BR, STATE_NON_CONTEXT,
gen7_17_0_noncontext_rb_rac_pipe_br_registers, &gen7_17_0_rb_rac_sel, },
{ A7XX_CLUSTER_NONE, PIPE_BR, STATE_NON_CONTEXT,
gen7_17_0_noncontext_rb_rbp_pipe_br_registers, &gen7_17_0_rb_rbp_sel, },
{ A7XX_CLUSTER_PS, PIPE_BR, STATE_FORCE_CTXT_0,
gen7_0_0_rb_rac_cluster_ps_pipe_br_registers, &gen7_17_0_rb_rac_sel, },
{ A7XX_CLUSTER_PS, PIPE_BR, STATE_FORCE_CTXT_1,
gen7_0_0_rb_rac_cluster_ps_pipe_br_registers, &gen7_17_0_rb_rac_sel, },
{ A7XX_CLUSTER_PS, PIPE_BR, STATE_FORCE_CTXT_0,
gen7_0_0_rb_rbp_cluster_ps_pipe_br_registers, &gen7_17_0_rb_rbp_sel, },
{ A7XX_CLUSTER_PS, PIPE_BR, STATE_FORCE_CTXT_1,
gen7_0_0_rb_rbp_cluster_ps_pipe_br_registers, &gen7_17_0_rb_rbp_sel, },
{ A7XX_CLUSTER_GRAS, PIPE_BR, STATE_FORCE_CTXT_0,
gen7_0_0_gras_cluster_gras_pipe_br_registers, },
{ A7XX_CLUSTER_GRAS, PIPE_BR, STATE_FORCE_CTXT_1,
gen7_0_0_gras_cluster_gras_pipe_br_registers, },
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_0,
gen7_17_0_pc_cluster_fe_pipe_br_registers, },
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_1,
gen7_17_0_pc_cluster_fe_pipe_br_registers, },
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_0,
gen7_0_0_vfd_cluster_fe_pipe_bv_registers, },
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_1,
gen7_0_0_vfd_cluster_fe_pipe_bv_registers, },
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_0,
gen7_0_0_vpc_cluster_fe_pipe_br_registers, },
{ A7XX_CLUSTER_FE, PIPE_BR, STATE_FORCE_CTXT_1,
gen7_0_0_vpc_cluster_fe_pipe_br_registers, },
{ A7XX_CLUSTER_PC_VS, PIPE_BR, STATE_FORCE_CTXT_0,
gen7_0_0_vpc_cluster_pc_vs_pipe_br_registers, },
{ A7XX_CLUSTER_PC_VS, PIPE_BR, STATE_FORCE_CTXT_1,
gen7_0_0_vpc_cluster_pc_vs_pipe_br_registers, },
{ A7XX_CLUSTER_VPC_PS, PIPE_BR, STATE_FORCE_CTXT_0,
gen7_0_0_vpc_cluster_vpc_ps_pipe_br_registers, },
{ A7XX_CLUSTER_VPC_PS, PIPE_BR, STATE_FORCE_CTXT_1,
gen7_0_0_vpc_cluster_vpc_ps_pipe_br_registers, },
};
/* No BV pipe; 2 SPs, 2 USPTPs */
static struct gen7_sptp_cluster_registers gen7_17_0_sptp_clusters[] = {
{ A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, PIPE_BR, 0, A7XX_HLSQ_STATE,
gen7_0_0_sp_noncontext_pipe_br_hlsq_state_registers, 0xae00 },
{ A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, PIPE_BR, 0, A7XX_SP_TOP,
gen7_0_0_sp_noncontext_pipe_br_sp_top_registers, 0xae00 },
{ A7XX_CLUSTER_NONE, A7XX_SP_NCTX_REG, PIPE_BR, 0, A7XX_USPTP,
gen7_0_0_sp_noncontext_pipe_br_usptp_registers, 0xae00 },
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX0_3D_CVS_REG, PIPE_BR, 0, A7XX_HLSQ_STATE,
gen7_0_0_sp_cluster_sp_vs_pipe_br_hlsq_state_registers, 0xa800 },
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX0_3D_CVS_REG, PIPE_BR, 0, A7XX_SP_TOP,
gen7_0_0_sp_cluster_sp_vs_pipe_br_sp_top_registers, 0xa800 },
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX0_3D_CVS_REG, PIPE_BR, 0, A7XX_USPTP,
gen7_0_0_sp_cluster_sp_vs_pipe_br_usptp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX1_3D_CVS_REG, PIPE_BR, 1, A7XX_HLSQ_STATE,
gen7_0_0_sp_cluster_sp_vs_pipe_br_hlsq_state_registers, 0xa800 },
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX1_3D_CVS_REG, PIPE_BR, 1, A7XX_SP_TOP,
gen7_0_0_sp_cluster_sp_vs_pipe_br_sp_top_registers, 0xa800 },
{ A7XX_CLUSTER_SP_VS, A7XX_SP_CTX1_3D_CVS_REG, PIPE_BR, 1, A7XX_USPTP,
gen7_0_0_sp_cluster_sp_vs_pipe_br_usptp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_HLSQ_STATE,
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_state_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_HLSQ_DP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_dp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_SP_TOP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_sp_top_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_USPTP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_usptp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_LPAC, 0, A7XX_HLSQ_STATE,
gen7_17_0_sp_cluster_sp_ps_pipe_lpac_hlsq_state_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX0_3D_CPS_REG, PIPE_LPAC, 0, A7XX_USPTP,
gen7_17_0_sp_cluster_sp_ps_pipe_lpac_usptp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_HLSQ_STATE,
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_state_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_HLSQ_DP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_dp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_SP_TOP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_sp_top_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_USPTP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_usptp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX2_3D_CPS_REG, PIPE_BR, 2, A7XX_HLSQ_DP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_dp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX2_3D_CPS_REG, PIPE_BR, 2, A7XX_SP_TOP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_sp_top_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX2_3D_CPS_REG, PIPE_BR, 2, A7XX_USPTP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_usptp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX3_3D_CPS_REG, PIPE_BR, 3, A7XX_HLSQ_DP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_hlsq_dp_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX3_3D_CPS_REG, PIPE_BR, 3, A7XX_SP_TOP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_sp_top_registers, 0xa800 },
{ A7XX_CLUSTER_SP_PS, A7XX_SP_CTX3_3D_CPS_REG, PIPE_BR, 3, A7XX_USPTP,
gen7_0_0_sp_cluster_sp_ps_pipe_br_usptp_registers, 0xa800 },
{ A7XX_CLUSTER_NONE, A7XX_TP0_NCTX_REG, PIPE_NONE, 0, A7XX_USPTP,
gen7_17_0_non_context_tpl1_pipe_none_usptp_registers, 0xb600 },
{ A7XX_CLUSTER_NONE, A7XX_TP0_NCTX_REG, PIPE_BR, 0, A7XX_USPTP,
gen7_17_0_non_context_tpl1_pipe_br_usptp_registers, 0xb600 },
{ A7XX_CLUSTER_SP_VS, A7XX_TP0_CTX0_3D_CVS_REG, PIPE_BR, 0, A7XX_USPTP,
gen7_17_0_tpl1_cluster_sp_vs_pipe_br_usptp_registers, 0xb000 },
{ A7XX_CLUSTER_SP_VS, A7XX_TP0_CTX1_3D_CVS_REG, PIPE_BR, 1, A7XX_USPTP,
gen7_17_0_tpl1_cluster_sp_vs_pipe_br_usptp_registers, 0xb000 },
{ A7XX_CLUSTER_SP_PS, A7XX_TP0_CTX0_3D_CPS_REG, PIPE_BR, 0, A7XX_USPTP,
gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers, 0xb000 },
{ A7XX_CLUSTER_SP_PS, A7XX_TP0_CTX1_3D_CPS_REG, PIPE_BR, 1, A7XX_USPTP,
gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers, 0xb000 },
{ A7XX_CLUSTER_SP_PS, A7XX_TP0_CTX2_3D_CPS_REG, PIPE_BR, 2, A7XX_USPTP,
gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers, 0xb000 },
{ A7XX_CLUSTER_SP_PS, A7XX_TP0_CTX3_3D_CPS_REG, PIPE_BR, 3, A7XX_USPTP,
gen7_17_0_tpl1_cluster_sp_ps_pipe_br_usptp_registers, 0xb000 },
};
static struct gen7_shader_block gen7_17_0_shader_blocks[] = {
{ A7XX_TP0_TMO_DATA, 0x0200, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_TP0_SMO_DATA, 0x0080, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_TP0_MIPMAP_BASE_DATA, 0x03c0, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_INST_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_INST_DATA_1, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_LB_0_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_LB_1_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_LB_2_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_LB_3_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_LB_4_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_LB_5_DATA, 0x0800, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_CB_RAM, 0x0390, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_INST_TAG, 0x0090, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_TMO_TAG, 0x0080, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_SMO_TAG, 0x0080, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_STATE_DATA, 0x0040, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_HWAVE_RAM, 0x0100, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_SP_L0_INST_BUF, 0x0050, 2, 2, PIPE_BR, A7XX_USPTP },
{ A7XX_HLSQ_CVS_BE_CTXT_BUF_RAM_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CPS_BE_CTXT_BUF_RAM_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_GFX_CVS_BE_CTXT_BUF_RAM, 0x0300, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_GFX_CPS_BE_CTXT_BUF_RAM, 0x0300, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CHUNK_CVS_RAM, 0x01c0, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CHUNK_CPS_RAM, 0x0300, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CHUNK_CVS_RAM_TAG, 0x0040, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CHUNK_CPS_RAM_TAG, 0x0040, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_ICB_CVS_CB_BASE_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_ICB_CPS_CB_BASE_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CVS_MISC_RAM, 0x0280, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CPS_MISC_RAM, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CPS_MISC_RAM_1, 0x0200, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_INST_RAM, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_GFX_CVS_CONST_RAM, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_GFX_CPS_CONST_RAM, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CVS_MISC_RAM_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_CPS_MISC_RAM_TAG, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_INST_RAM_TAG, 0x0080, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_GFX_CVS_CONST_RAM_TAG, 0x0064, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_GFX_CPS_CONST_RAM_TAG, 0x0064, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_INST_RAM_1, 0x0800, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_STPROC_META, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_BV_BE_META, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_DATAPATH_META, 0x0020, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_FRONTEND_META, 0x0040, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_INDIRECT_META, 0x0010, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
{ A7XX_HLSQ_BACKEND_META, 0x0040, 1, 1, PIPE_BR, A7XX_HLSQ_STATE },
};
static struct gen7_reg_list gen7_17_0_reg_list[] = {
{ gen7_17_0_gpu_registers, NULL },
{ gen7_17_0_dbgc_registers, NULL },
{ NULL, NULL },
};
static const struct a6xx_indexed_registers gen7_17_0_cp_indexed_reglist[] = {
{ "CP_SQE_STAT", REG_A6XX_CP_SQE_STAT_ADDR,
REG_A6XX_CP_SQE_STAT_DATA, 0x40, NULL },
{ "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR,
REG_A6XX_CP_DRAW_STATE_DATA, 0x100, NULL },
{ "CP_SQE_UCODE_DBG", REG_A6XX_CP_SQE_UCODE_DBG_ADDR,
REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x8000, NULL },
{ "CP_ROQ_DBG", REG_A6XX_CP_ROQ_DBG_ADDR,
REG_A6XX_CP_ROQ_DBG_DATA, 0, a7xx_get_cp_roq_size },
};
#endif /* __ADRENO_GEN7_17_0_SNAPSHOT_H */

View File

@@ -356,6 +356,12 @@ int adreno_fault_handler(struct msm_gpu *gpu, unsigned long iova, int flags,
return 0;
}
static bool
valid_per_process_vm(struct msm_gpu *gpu, struct drm_gpuvm *vm)
{
return vm && (vm != gpu->vm);
}
int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
uint32_t param, uint64_t *value, uint32_t *len)
{
@@ -414,12 +420,12 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
*value = gpu->suspend_count;
return 0;
case MSM_PARAM_VA_START:
if (vm == gpu->vm)
if (!valid_per_process_vm(gpu, vm))
return UERR(EINVAL, drm, "requires per-process pgtables");
*value = vm->mm_start;
return 0;
case MSM_PARAM_VA_SIZE:
if (vm == gpu->vm)
if (!valid_per_process_vm(gpu, vm))
return UERR(EINVAL, drm, "requires per-process pgtables");
*value = vm->mm_range;
return 0;
@@ -503,9 +509,11 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_context *ctx,
if (!perfmon_capable())
return UERR(EPERM, drm, "invalid permissions");
return msm_context_set_sysprof(ctx, gpu, value);
case MSM_PARAM_EN_VM_BIND:
case MSM_PARAM_EN_VM_BIND: {
guard(rwsem_read)(&ctx->ctxlock);
/* We can only support VM_BIND with per-process pgtables: */
if (ctx->vm == gpu->vm)
if (!gpu->funcs->create_private_vm)
return UERR(EINVAL, drm, "requires per-process pgtables");
/*
@@ -518,6 +526,7 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_context *ctx,
ctx->userspace_managed_vm = value;
return 0;
}
default:
return UERR(EINVAL, drm, "%s: invalid param: %u", gpu->name, param);
}

View File

@@ -562,6 +562,11 @@ static inline int adreno_is_x185(struct adreno_gpu *gpu)
return gpu->info->chip_ids[0] == 0x43050c01;
}
static inline int adreno_is_a722(struct adreno_gpu *gpu)
{
return gpu->info->chip_ids[0] == 0x43020100;
}
static inline int adreno_is_a740_family(struct adreno_gpu *gpu)
{
if (WARN_ON_ONCE(!gpu->info))

View File

@@ -86,42 +86,42 @@ static const struct dpu_sspp_cfg kaanapali_sspp[] = {
.name = "sspp_8", .id = SSPP_DMA0,
.base = 0x97000, .len = 0x84,
.features = DMA_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.sblk = &dpu_dma_sblk_v13,
.xin_id = 1,
.type = SSPP_TYPE_DMA,
}, {
.name = "sspp_9", .id = SSPP_DMA1,
.base = 0xa0000, .len = 0x84,
.features = DMA_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.sblk = &dpu_dma_sblk_v13,
.xin_id = 5,
.type = SSPP_TYPE_DMA,
}, {
.name = "sspp_10", .id = SSPP_DMA2,
.base = 0xa9000, .len = 0x84,
.features = DMA_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.sblk = &dpu_dma_sblk_v13,
.xin_id = 9,
.type = SSPP_TYPE_DMA,
}, {
.name = "sspp_11", .id = SSPP_DMA3,
.base = 0xb2000, .len = 0x84,
.features = DMA_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.sblk = &dpu_dma_sblk_v13,
.xin_id = 13,
.type = SSPP_TYPE_DMA,
}, {
.name = "sspp_12", .id = SSPP_DMA4,
.base = 0xbb000, .len = 0x84,
.features = DMA_CURSOR_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.sblk = &dpu_dma_sblk_v13,
.xin_id = 14,
.type = SSPP_TYPE_DMA,
}, {
.name = "sspp_13", .id = SSPP_DMA5,
.base = 0xc4000, .len = 0x84,
.features = DMA_CURSOR_SDM845_MASK_SDMA,
.sblk = &dpu_dma_sblk,
.sblk = &dpu_dma_sblk_v13,
.xin_id = 15,
.type = SSPP_TYPE_DMA,
},

View File

@@ -34,7 +34,7 @@ enum dpu_perf_mode {
/**
* dpu_core_perf_adjusted_mode_clk - Adjust given mode clock rate according to
* the perf clock factor.
* @crtc_clk_rate - Unadjusted mode clock rate
* @mode_clk_rate: unadjusted mode clock rate
* @perf_cfg: performance configuration
*/
u64 dpu_core_perf_adjusted_mode_clk(u64 mode_clk_rate,
@@ -394,6 +394,10 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
trace_dpu_core_perf_update_clk(kms->dev, !crtc->enabled, clk_rate);
/* If we're going offline, PM callbacks will disable the clocks instead */
if (!clk_rate)
return 0;
clk_rate = min(clk_rate, kms->perf.max_core_clk_rate);
ret = dev_pm_opp_set_rate(&kms->pdev->dev, clk_rate);
if (ret) {

View File

@@ -710,8 +710,7 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc,
if (fb && MSM_FORMAT_IS_YUV(msm_framebuffer_format(fb)))
topology->num_cdm++;
} else if (disp_info->intf_type == INTF_DP) {
if (msm_dp_is_yuv_420_enabled(priv->kms->dp[disp_info->h_tile_instance[0]],
adj_mode))
if (drm_mode_is_420_only(&connector->display_info, adj_mode))
topology->num_cdm++;
}
}

View File

@@ -303,6 +303,16 @@ static const u32 wb2_formats_rgb_yuv[] = {
.num_formats = ARRAY_SIZE(plane_formats), \
}
#define _DMA_SBLK_V13() \
{ \
.sspp_rec0_blk = {.name = "sspp_rec0", \
.base = 0x1000, .len = 0x180,}, \
.sspp_rec1_blk = {.name = "sspp_rec1", \
.base = 0x3000, .len = 0x180,}, \
.format_list = plane_formats, \
.num_formats = ARRAY_SIZE(plane_formats), \
}
static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = {
.rot_maxheight = 1088,
.rot_num_formats = ARRAY_SIZE(rotation_v2_formats),
@@ -353,6 +363,8 @@ static const struct dpu_sspp_sub_blks dpu_rgb_sblk = _RGB_SBLK();
static const struct dpu_sspp_sub_blks dpu_dma_sblk = _DMA_SBLK();
static const struct dpu_sspp_sub_blks dpu_dma_sblk_v13 = _DMA_SBLK_V13();
/*************************************************************
* MIXER sub blocks config
*************************************************************/

View File

@@ -398,7 +398,7 @@ static int mdp4_kms_init(struct drm_device *dev)
ret = mdp_kms_init(&mdp4_kms->base, &kms_funcs);
if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to init kms\n");
goto fail;
return ret;
}
kms = priv->kms;
@@ -409,7 +409,7 @@ static int mdp4_kms_init(struct drm_device *dev)
ret = regulator_enable(mdp4_kms->vdd);
if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to enable regulator vdd: %d\n", ret);
goto fail;
return ret;
}
}
@@ -421,7 +421,7 @@ static int mdp4_kms_init(struct drm_device *dev)
DRM_DEV_ERROR(dev->dev, "unexpected MDP version: v%d.%d\n",
major, minor);
ret = -ENXIO;
goto fail;
return ret;
}
mdp4_kms->rev = minor;
@@ -430,7 +430,7 @@ static int mdp4_kms_init(struct drm_device *dev)
if (!mdp4_kms->lut_clk) {
DRM_DEV_ERROR(dev->dev, "failed to get lut_clk\n");
ret = -ENODEV;
goto fail;
return ret;
}
clk_set_rate(mdp4_kms->lut_clk, max_clk);
}
@@ -452,7 +452,7 @@ static int mdp4_kms_init(struct drm_device *dev)
vm = msm_kms_init_vm(mdp4_kms->dev, NULL);
if (IS_ERR(vm)) {
ret = PTR_ERR(vm);
goto fail;
return ret;
}
kms->vm = vm;
@@ -460,22 +460,22 @@ static int mdp4_kms_init(struct drm_device *dev)
ret = modeset_init(mdp4_kms);
if (ret) {
DRM_DEV_ERROR(dev->dev, "modeset_init failed: %d\n", ret);
goto fail;
return ret;
}
mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC | MSM_BO_SCANOUT);
mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC | MSM_BO_SCANOUT, NULL);
if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
DRM_DEV_ERROR(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
mdp4_kms->blank_cursor_bo = NULL;
goto fail;
return ret;
}
ret = msm_gem_get_and_pin_iova(mdp4_kms->blank_cursor_bo, kms->vm,
&mdp4_kms->blank_cursor_iova);
if (ret) {
DRM_DEV_ERROR(dev->dev, "could not pin blank-cursor bo: %d\n", ret);
goto fail;
return ret;
}
dev->mode_config.min_width = 0;
@@ -484,12 +484,6 @@ static int mdp4_kms_init(struct drm_device *dev)
dev->mode_config.max_height = 2048;
return 0;
fail:
if (kms)
mdp4_destroy(kms);
return ret;
}
static const struct dev_pm_ops mdp4_pm_ops = {

View File

@@ -517,7 +517,7 @@ static int mdp5_kms_init(struct drm_device *dev)
ret = mdp_kms_init(&mdp5_kms->base, &kms_funcs);
if (ret) {
DRM_DEV_ERROR(&pdev->dev, "failed to init kms\n");
goto fail;
return ret;
}
config = mdp5_cfg_get_config(mdp5_kms->cfg);
@@ -540,7 +540,7 @@ static int mdp5_kms_init(struct drm_device *dev)
vm = msm_kms_init_vm(mdp5_kms->dev, pdev->dev.parent);
if (IS_ERR(vm)) {
ret = PTR_ERR(vm);
goto fail;
return ret;
}
kms->vm = vm;
@@ -550,7 +550,7 @@ static int mdp5_kms_init(struct drm_device *dev)
ret = modeset_init(mdp5_kms);
if (ret) {
DRM_DEV_ERROR(&pdev->dev, "modeset_init failed: %d\n", ret);
goto fail;
return ret;
}
dev->mode_config.min_width = 0;
@@ -562,11 +562,6 @@ static int mdp5_kms_init(struct drm_device *dev)
dev->vblank_disable_immediate = true;
return 0;
fail:
if (kms)
mdp5_kms_destroy(kms);
return ret;
}
static void mdp5_destroy(struct mdp5_kms *mdp5_kms)

View File

@@ -284,10 +284,8 @@ int msm_dp_audio_prepare(struct drm_bridge *bridge,
* such cases check for connection status and bail out if not
* connected.
*/
if (!msm_dp_display->power_on) {
rc = -EINVAL;
if (!msm_dp_display->power_on)
goto end;
}
audio = msm_dp_audio_get_data(msm_dp_display);
if (IS_ERR(audio)) {

View File

@@ -114,7 +114,6 @@ struct msm_dp_ctrl_private {
struct drm_device *drm_dev;
struct device *dev;
struct drm_dp_aux *aux;
struct msm_dp_panel *panel;
struct msm_dp_link *link;
void __iomem *ahb_base;
void __iomem *link_base;
@@ -202,7 +201,8 @@ static int msm_dp_aux_link_configure(struct drm_dp_aux *aux,
/*
* NOTE: resetting DP controller will also clear any pending HPD related interrupts
*/
void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl)
void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel)
{
struct msm_dp_ctrl_private *ctrl =
container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
@@ -217,10 +217,9 @@ void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl)
sw_reset &= ~DP_SW_RESET;
msm_dp_write_ahb(ctrl, REG_DP_SW_RESET, sw_reset);
if (!ctrl->hw_revision) {
if (!ctrl->hw_revision)
ctrl->hw_revision = msm_dp_read_ahb(ctrl, REG_DP_HW_VERSION);
ctrl->panel->hw_revision = ctrl->hw_revision;
}
panel->hw_revision = ctrl->hw_revision;
}
static u32 msm_dp_ctrl_get_aux_interrupt(struct msm_dp_ctrl_private *ctrl)
@@ -388,26 +387,49 @@ void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl)
drm_dbg_dp(ctrl->drm_dev, "mainlink off\n");
}
static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl)
static void msm_dp_ctrl_config_ctrl_streams(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *msm_dp_panel)
{
u32 config = 0, tbd;
const u8 *dpcd = ctrl->panel->dpcd;
/*
* RMW: called from atomic_enable(), serialized by the DRM atomic framework.
* Clear stream-specific fields before OR-ing to avoid bit accumulation.
*/
config = msm_dp_read_link(ctrl, REG_DP_CONFIGURATION_CTRL);
config &= ~(DP_CONFIGURATION_CTRL_RGB_YUV_MASK |
DP_CONFIGURATION_CTRL_BPC_MASK |
DP_CONFIGURATION_CTRL_SEND_VSC);
if (msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420)
config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
tbd = msm_dp_link_get_test_bits_depth(ctrl->link,
msm_dp_panel->msm_dp_mode.bpp);
config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
if (msm_dp_panel->psr_cap.version)
config |= DP_CONFIGURATION_CTRL_SEND_VSC;
drm_dbg_dp(ctrl->drm_dev, "stream DP_CONFIGURATION_CTRL=0x%x\n", config);
msm_dp_write_link(ctrl, REG_DP_CONFIGURATION_CTRL, config);
}
static void msm_dp_ctrl_config_ctrl_link(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
u32 config = 0;
const u8 *dpcd = panel->dpcd;
/* Default-> LSCLK DIV: 1/4 LCLK */
config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
if (ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420)
config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
/* Scrambler reset enable */
if (drm_dp_alternate_scrambler_reset_cap(dpcd))
config |= DP_CONFIGURATION_CTRL_ASSR;
tbd = msm_dp_link_get_test_bits_depth(ctrl->link,
ctrl->panel->msm_dp_mode.bpp);
config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
/* Num of Lanes */
config |= ((ctrl->link->link_params.num_lanes - 1)
<< DP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT);
@@ -421,10 +443,7 @@ static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl)
config |= DP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN;
config |= DP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK;
if (ctrl->panel->psr_cap.version)
config |= DP_CONFIGURATION_CTRL_SEND_VSC;
drm_dbg_dp(ctrl->drm_dev, "DP_CONFIGURATION_CTRL=0x%x\n", config);
drm_dbg_dp(ctrl->drm_dev, "link DP_CONFIGURATION_CTRL=0x%x\n", config);
msm_dp_write_link(ctrl, REG_DP_CONFIGURATION_CTRL, config);
}
@@ -443,16 +462,13 @@ static void msm_dp_ctrl_lane_mapping(struct msm_dp_ctrl_private *ctrl)
ln_mapping);
}
static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl)
static void msm_dp_ctrl_config_misc1_misc0(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *msm_dp_panel)
{
u32 colorimetry_cfg, test_bits_depth, misc_val;
msm_dp_ctrl_lane_mapping(ctrl);
msm_dp_setup_peripheral_flush(ctrl);
msm_dp_ctrl_config_ctrl(ctrl);
test_bits_depth = msm_dp_link_get_test_bits_depth(ctrl->link, ctrl->panel->msm_dp_mode.bpp);
test_bits_depth = msm_dp_link_get_test_bits_depth(ctrl->link,
msm_dp_panel->msm_dp_mode.bpp);
colorimetry_cfg = msm_dp_link_get_colorimetry_config(ctrl->link);
misc_val = msm_dp_read_link(ctrl, REG_DP_MISC1_MISC0);
@@ -466,8 +482,16 @@ static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl
drm_dbg_dp(ctrl->drm_dev, "misc settings = 0x%x\n", misc_val);
msm_dp_write_link(ctrl, REG_DP_MISC1_MISC0, misc_val);
}
msm_dp_panel_timing_cfg(ctrl->panel, ctrl->msm_dp_ctrl.wide_bus_en);
static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
msm_dp_ctrl_config_ctrl_streams(ctrl, panel);
msm_dp_ctrl_config_misc1_misc0(ctrl, panel);
msm_dp_panel_timing_cfg(panel, ctrl->msm_dp_ctrl.wide_bus_en);
}
/*
@@ -1237,20 +1261,21 @@ static void _dp_ctrl_calc_tu(struct msm_dp_ctrl_private *ctrl,
}
static void msm_dp_ctrl_calc_tu_parameters(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel,
struct msm_dp_vc_tu_mapping_table *tu_table)
{
struct msm_dp_tu_calc_input in;
struct drm_display_mode *drm_mode;
const struct drm_display_mode *drm_mode;
drm_mode = &ctrl->panel->msm_dp_mode.drm_mode;
drm_mode = &panel->msm_dp_mode.drm_mode;
in.lclk = ctrl->link->link_params.rate / 1000;
in.pclk_khz = drm_mode->clock;
in.hactive = drm_mode->hdisplay;
in.hporch = drm_mode->htotal - drm_mode->hdisplay;
in.nlanes = ctrl->link->link_params.num_lanes;
in.bpp = ctrl->panel->msm_dp_mode.bpp;
in.pixel_enc = ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
in.bpp = panel->msm_dp_mode.bpp;
in.pixel_enc = panel->msm_dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
in.dsc_en = 0;
in.async_en = 0;
in.fec_en = 0;
@@ -1260,14 +1285,15 @@ static void msm_dp_ctrl_calc_tu_parameters(struct msm_dp_ctrl_private *ctrl,
_dp_ctrl_calc_tu(ctrl, &in, tu_table);
}
static void msm_dp_ctrl_setup_tr_unit(struct msm_dp_ctrl_private *ctrl)
static void msm_dp_ctrl_setup_tr_unit(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
u32 msm_dp_tu = 0x0;
u32 valid_boundary = 0x0;
u32 valid_boundary2 = 0x0;
struct msm_dp_vc_tu_mapping_table tu_calc_table;
msm_dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table);
msm_dp_ctrl_calc_tu_parameters(ctrl, panel, &tu_calc_table);
msm_dp_tu |= tu_calc_table.tu_size_minus1;
valid_boundary |= tu_calc_table.valid_boundary_link;
@@ -1419,6 +1445,7 @@ static int msm_dp_ctrl_set_pattern_state_bit(struct msm_dp_ctrl_private *ctrl,
}
static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel,
int *training_step, enum drm_dp_phy dp_phy)
{
int delay_us;
@@ -1427,7 +1454,7 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
int const maximum_retries = 4;
delay_us = drm_dp_read_clock_recovery_delay(ctrl->aux,
ctrl->panel->dpcd, dp_phy, false);
panel->dpcd, dp_phy, false);
msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0);
@@ -1513,14 +1540,15 @@ static int msm_dp_ctrl_link_rate_down_shift(struct msm_dp_ctrl_private *ctrl)
return ret;
}
static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl)
static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
if (ctrl->link->link_params.num_lanes == 1)
return -1;
ctrl->link->link_params.num_lanes /= 2;
ctrl->link->link_params.rate = ctrl->panel->link_info.rate;
ctrl->link->link_params.rate = panel->link_info.rate;
ctrl->link->phy_params.p_level = 0;
ctrl->link->phy_params.v_level = 0;
@@ -1529,6 +1557,7 @@ static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl)
}
static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel,
enum drm_dp_phy dp_phy)
{
int delay_us;
@@ -1536,11 +1565,12 @@ static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl,
msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE, dp_phy);
delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
ctrl->panel->dpcd, dp_phy, false);
panel->dpcd, dp_phy, false);
fsleep(delay_us);
}
static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel,
int *training_step, enum drm_dp_phy dp_phy)
{
int delay_us;
@@ -1551,16 +1581,16 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
u8 link_status[DP_LINK_STATUS_SIZE];
delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
ctrl->panel->dpcd, dp_phy, false);
panel->dpcd, dp_phy, false);
msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0);
*training_step = DP_TRAINING_2;
if (drm_dp_tps4_supported(ctrl->panel->dpcd)) {
if (drm_dp_tps4_supported(panel->dpcd)) {
pattern = DP_TRAINING_PATTERN_4;
state_ctrl_bit = 4;
} else if (drm_dp_tps3_supported(ctrl->panel->dpcd)) {
} else if (drm_dp_tps3_supported(panel->dpcd)) {
pattern = DP_TRAINING_PATTERN_3;
state_ctrl_bit = 3;
} else {
@@ -1597,18 +1627,19 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
}
static int msm_dp_ctrl_link_train_1_2(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel,
int *training_step, enum drm_dp_phy dp_phy)
{
int ret;
ret = msm_dp_ctrl_link_train_1(ctrl, training_step, dp_phy);
ret = msm_dp_ctrl_link_train_1(ctrl, panel, training_step, dp_phy);
if (ret) {
DRM_ERROR("link training #1 on phy %d failed. ret=%d\n", dp_phy, ret);
return ret;
}
drm_dbg_dp(ctrl->drm_dev, "link training #1 on phy %d successful\n", dp_phy);
ret = msm_dp_ctrl_link_train_2(ctrl, training_step, dp_phy);
ret = msm_dp_ctrl_link_train_2(ctrl, panel, training_step, dp_phy);
if (ret) {
DRM_ERROR("link training #2 on phy %d failed. ret=%d\n", dp_phy, ret);
return ret;
@@ -1619,16 +1650,18 @@ static int msm_dp_ctrl_link_train_1_2(struct msm_dp_ctrl_private *ctrl,
}
static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel,
int *training_step)
{
int i;
int ret = 0;
const u8 *dpcd = ctrl->panel->dpcd;
const u8 *dpcd = panel->dpcd;
u8 encoding[] = { 0, DP_SET_ANSI_8B10B };
u8 assr;
struct msm_dp_link_info link_info = {0};
msm_dp_ctrl_config_ctrl(ctrl);
msm_dp_ctrl_config_ctrl_link(ctrl, panel);
msm_dp_ctrl_config_ctrl_streams(ctrl, panel);
link_info.num_lanes = ctrl->link->link_params.num_lanes;
link_info.rate = ctrl->link->link_params.rate;
@@ -1651,8 +1684,8 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
for (i = ctrl->link->lttpr_count - 1; i >= 0; i--) {
enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, dp_phy);
msm_dp_ctrl_clear_training_pattern(ctrl, dp_phy);
ret = msm_dp_ctrl_link_train_1_2(ctrl, panel, training_step, dp_phy);
msm_dp_ctrl_clear_training_pattern(ctrl, panel, dp_phy);
if (ret)
break;
@@ -1663,7 +1696,7 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
goto end;
}
ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, DP_PHY_DPRX);
ret = msm_dp_ctrl_link_train_1_2(ctrl, panel, training_step, DP_PHY_DPRX);
if (ret) {
DRM_ERROR("link training on sink failed. ret=%d\n", ret);
goto end;
@@ -1676,6 +1709,7 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
}
static int msm_dp_ctrl_setup_main_link(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel,
int *training_step)
{
int ret = 0;
@@ -1691,7 +1725,7 @@ static int msm_dp_ctrl_setup_main_link(struct msm_dp_ctrl_private *ctrl,
* a link training pattern, we have to first do soft reset.
*/
ret = msm_dp_ctrl_link_train(ctrl, training_step);
ret = msm_dp_ctrl_link_train(ctrl, panel, training_step);
return ret;
}
@@ -1790,11 +1824,12 @@ static void msm_dp_ctrl_link_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl)
str_on_off(ctrl->core_clks_on));
}
static int msm_dp_ctrl_enable_mainlink_clocks(struct msm_dp_ctrl_private *ctrl)
static int msm_dp_ctrl_enable_mainlink_clocks(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
int ret = 0;
struct phy *phy = ctrl->phy;
const u8 *dpcd = ctrl->panel->dpcd;
const u8 *dpcd = panel->dpcd;
ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;
ctrl->phy_opts.dp.link_rate = ctrl->link->link_params.rate / 100;
@@ -1846,13 +1881,14 @@ static void msm_dp_ctrl_psr_exit(struct msm_dp_ctrl_private *ctrl)
msm_dp_write_link(ctrl, REG_PSR_CMD, cmd);
}
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl)
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel)
{
struct msm_dp_ctrl_private *ctrl = container_of(msm_dp_ctrl,
struct msm_dp_ctrl_private, msm_dp_ctrl);
u32 cfg;
if (!ctrl->panel->psr_cap.version)
if (!panel->psr_cap.version)
return;
/* enable PSR1 function */
@@ -1867,12 +1903,13 @@ void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl)
drm_dp_dpcd_write(ctrl->aux, DP_PSR_EN_CFG, &cfg, 1);
}
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl, bool enter)
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel, bool enter)
{
struct msm_dp_ctrl_private *ctrl = container_of(msm_dp_ctrl,
struct msm_dp_ctrl_private, msm_dp_ctrl);
if (!ctrl->panel->psr_cap.version)
if (!panel->psr_cap.version)
return;
/*
@@ -1942,7 +1979,8 @@ void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl)
phy_exit(phy);
}
static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
struct phy *phy = ctrl->phy;
int ret = 0;
@@ -1950,20 +1988,19 @@ static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
msm_dp_ctrl_mainlink_disable(ctrl);
ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;
phy_configure(phy, &ctrl->phy_opts);
/*
* Disable and re-enable the mainlink clock since the
* link clock might have been adjusted as part of the
* link maintenance.
*/
dev_pm_opp_set_rate(ctrl->dev, 0);
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
phy_power_off(phy);
/* hw recommended delay before re-enabling clocks */
msleep(20);
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl);
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl, panel);
if (ret) {
DRM_ERROR("Failed to enable mainlink clks. ret=%d\n", ret);
return ret;
@@ -1972,7 +2009,8 @@ static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
return ret;
}
static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
struct phy *phy;
@@ -1980,9 +2018,8 @@ static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
msm_dp_ctrl_mainlink_disable(ctrl);
msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl);
msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl, panel);
dev_pm_opp_set_rate(ctrl->dev, 0);
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
phy_power_off(phy);
@@ -1994,7 +2031,8 @@ static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
return 0;
}
static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
int ret = 0;
int training_step = DP_TRAINING_NONE;
@@ -2004,11 +2042,11 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
ctrl->link->phy_params.p_level = 0;
ctrl->link->phy_params.v_level = 0;
ret = msm_dp_ctrl_setup_main_link(ctrl, &training_step);
ret = msm_dp_ctrl_setup_main_link(ctrl, panel, &training_step);
if (ret)
goto end;
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
msm_dp_ctrl_clear_training_pattern(ctrl, panel, DP_PHY_DPRX);
msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO);
@@ -2152,7 +2190,43 @@ static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl)
return success;
}
static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl)
static int msm_dp_ctrl_on_pixel_clk(struct msm_dp_ctrl_private *ctrl, unsigned long pixel_rate)
{
int ret;
ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
if (ret) {
DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
return ret;
}
if (WARN_ON_ONCE(ctrl->stream_clks_on))
return 0;
ret = clk_prepare_enable(ctrl->pixel_clk);
if (ret) {
DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
return ret;
}
ctrl->stream_clks_on = true;
return ret;
}
void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl)
{
struct msm_dp_ctrl_private *ctrl;
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
if (ctrl->stream_clks_on) {
clk_disable_unprepare(ctrl->pixel_clk);
ctrl->stream_clks_on = false;
}
}
static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
int ret;
unsigned long pixel_rate;
@@ -2168,38 +2242,27 @@ static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl
* running. Add the global reset just before disabling the
* link clocks and core clocks.
*/
msm_dp_ctrl_off(&ctrl->msm_dp_ctrl);
msm_dp_ctrl_off_pixel_clk(&ctrl->msm_dp_ctrl);
msm_dp_ctrl_off_link(&ctrl->msm_dp_ctrl, panel);
ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl);
ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl, panel);
if (ret) {
DRM_ERROR("failed to enable DP link controller\n");
return ret;
}
pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock;
ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
if (ret) {
DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
pixel_rate = panel->msm_dp_mode.drm_mode.clock;
ret = msm_dp_ctrl_on_pixel_clk(ctrl, pixel_rate);
if (ret)
return ret;
}
if (ctrl->stream_clks_on) {
drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n");
} else {
ret = clk_prepare_enable(ctrl->pixel_clk);
if (ret) {
DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
return ret;
}
ctrl->stream_clks_on = true;
}
msm_dp_ctrl_send_phy_test_pattern(ctrl);
return 0;
}
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl)
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel)
{
struct msm_dp_ctrl_private *ctrl;
u32 sink_request = 0x0;
@@ -2214,14 +2277,14 @@ void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl)
if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
drm_dbg_dp(ctrl->drm_dev, "PHY_TEST_PATTERN request\n");
if (msm_dp_ctrl_process_phy_test_request(ctrl)) {
if (msm_dp_ctrl_process_phy_test_request(ctrl, panel)) {
DRM_ERROR("process phy_test_req failed\n");
return;
}
}
if (sink_request & DP_LINK_STATUS_UPDATED) {
if (msm_dp_ctrl_link_maintenance(ctrl)) {
if (msm_dp_ctrl_link_maintenance(ctrl, panel)) {
DRM_ERROR("LM failed: TEST_LINK_TRAINING\n");
return;
}
@@ -2229,7 +2292,7 @@ void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl)
if (sink_request & DP_TEST_LINK_TRAINING) {
msm_dp_link_send_test_response(ctrl->link);
if (msm_dp_ctrl_link_maintenance(ctrl)) {
if (msm_dp_ctrl_link_maintenance(ctrl, panel)) {
DRM_ERROR("LM failed: TEST_LINK_TRAINING\n");
return;
}
@@ -2265,7 +2328,8 @@ static bool msm_dp_ctrl_channel_eq_ok(struct msm_dp_ctrl_private *ctrl)
return drm_dp_channel_eq_ok(link_status, num_lanes);
}
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel)
{
int rc = 0;
struct msm_dp_ctrl_private *ctrl;
@@ -2281,8 +2345,8 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
rate = ctrl->panel->link_info.rate;
pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock;
rate = panel->link_info.rate;
pixel_rate = panel->msm_dp_mode.drm_mode.clock;
msm_dp_ctrl_core_clk_enable(&ctrl->msm_dp_ctrl);
@@ -2294,8 +2358,8 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
} else {
ctrl->link->link_params.rate = rate;
ctrl->link->link_params.num_lanes =
ctrl->panel->link_info.num_lanes;
if (ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420)
panel->link_info.num_lanes;
if (panel->msm_dp_mode.out_fmt_is_yuv_420)
pixel_rate >>= 1;
}
@@ -2303,13 +2367,13 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
ctrl->link->link_params.rate, ctrl->link->link_params.num_lanes,
pixel_rate);
rc = msm_dp_ctrl_enable_mainlink_clocks(ctrl);
rc = msm_dp_ctrl_enable_mainlink_clocks(ctrl, panel);
if (rc)
return rc;
while (--link_train_max_retries) {
training_step = DP_TRAINING_NONE;
rc = msm_dp_ctrl_setup_main_link(ctrl, &training_step);
rc = msm_dp_ctrl_setup_main_link(ctrl, panel, &training_step);
if (rc == 0) {
/* training completed successfully */
break;
@@ -2328,7 +2392,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
* some lanes are ready,
* reduce lane number
*/
rc = msm_dp_ctrl_link_lane_down_shift(ctrl);
rc = msm_dp_ctrl_link_lane_down_shift(ctrl, panel);
if (rc < 0) { /* lane == 1 already */
/* end with failure */
break;
@@ -2349,7 +2413,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
ctrl->link->link_params.num_lanes))
rc = msm_dp_ctrl_link_rate_down_shift(ctrl);
else
rc = msm_dp_ctrl_link_lane_down_shift(ctrl);
rc = msm_dp_ctrl_link_lane_down_shift(ctrl, panel);
if (rc < 0) {
/* end with failure */
@@ -2357,10 +2421,10 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
}
/* stop link training before start re training */
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
msm_dp_ctrl_clear_training_pattern(ctrl, panel, DP_PHY_DPRX);
}
rc = msm_dp_ctrl_reinitialize_mainlink(ctrl);
rc = msm_dp_ctrl_reinitialize_mainlink(ctrl, panel);
if (rc) {
DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n", rc);
break;
@@ -2381,20 +2445,21 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
* link training failed
* end txing train pattern here
*/
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
msm_dp_ctrl_clear_training_pattern(ctrl, panel, DP_PHY_DPRX);
msm_dp_ctrl_deinitialize_mainlink(ctrl);
msm_dp_ctrl_deinitialize_mainlink(ctrl, panel);
rc = -ECONNRESET;
}
return rc;
}
static int msm_dp_ctrl_link_retrain(struct msm_dp_ctrl_private *ctrl)
static int msm_dp_ctrl_link_retrain(struct msm_dp_ctrl_private *ctrl,
struct msm_dp_panel *panel)
{
int training_step = DP_TRAINING_NONE;
return msm_dp_ctrl_setup_main_link(ctrl, &training_step);
return msm_dp_ctrl_setup_main_link(ctrl, panel, &training_step);
}
static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl,
@@ -2465,7 +2530,44 @@ static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl,
msm_dp_write_link(ctrl, REG_DP_SOFTWARE_NVID, nvid);
}
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train)
int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel,
bool force_link_train)
{
int ret = 0;
struct msm_dp_ctrl_private *ctrl;
if (!msm_dp_ctrl)
return -EINVAL;
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d\n",
ctrl->link->link_params.rate,
ctrl->link->link_params.num_lanes);
drm_dbg_dp(ctrl->drm_dev,
"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on);
if (!ctrl->link_clks_on) { /* link clk is off */
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl, panel);
if (ret) {
DRM_ERROR("Failed to start link clocks. ret=%d\n", ret);
return ret;
}
}
if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl))
msm_dp_ctrl_link_retrain(ctrl, panel);
/* stop txing train pattern to end link training */
msm_dp_ctrl_clear_training_pattern(ctrl, panel, DP_PHY_DPRX);
return ret;
}
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel)
{
int ret = 0;
bool mainlink_ready = false;
@@ -2478,49 +2580,17 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
pixel_rate = pixel_rate_orig = ctrl->panel->msm_dp_mode.drm_mode.clock;
pixel_rate_orig = panel->msm_dp_mode.drm_mode.clock;
pixel_rate = pixel_rate_orig;
if (msm_dp_ctrl->wide_bus_en || ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420)
if (msm_dp_ctrl->wide_bus_en || panel->msm_dp_mode.out_fmt_is_yuv_420)
pixel_rate >>= 1;
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
ctrl->link->link_params.rate,
ctrl->link->link_params.num_lanes, pixel_rate);
drm_dbg_dp(ctrl->drm_dev, "pixel_rate=%lu\n", pixel_rate);
drm_dbg_dp(ctrl->drm_dev,
"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on);
if (!ctrl->link_clks_on) { /* link clk is off */
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl);
if (ret) {
DRM_ERROR("Failed to start link clocks. ret=%d\n", ret);
goto end;
}
}
ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
if (ret) {
DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
goto end;
}
if (ctrl->stream_clks_on) {
drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n");
} else {
ret = clk_prepare_enable(ctrl->pixel_clk);
if (ret) {
DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
goto end;
}
ctrl->stream_clks_on = true;
}
if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl))
msm_dp_ctrl_link_retrain(ctrl);
/* stop txing train pattern to end link training */
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
ret = msm_dp_ctrl_on_pixel_clk(ctrl, pixel_rate);
if (ret)
return ret;
/*
* Set up transfer unit values and set controller state to send
@@ -2528,16 +2598,20 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
*/
reinit_completion(&ctrl->video_comp);
msm_dp_ctrl_configure_source_params(ctrl);
msm_dp_ctrl_lane_mapping(ctrl);
msm_dp_setup_peripheral_flush(ctrl);
msm_dp_ctrl_config_ctrl_link(ctrl, panel);
msm_dp_ctrl_configure_source_params(ctrl, panel);
msm_dp_ctrl_config_msa(ctrl,
ctrl->link->link_params.rate,
pixel_rate_orig,
ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420);
panel->msm_dp_mode.out_fmt_is_yuv_420);
msm_dp_panel_clear_dsc_dto(ctrl->panel);
msm_dp_panel_clear_dsc_dto(panel);
msm_dp_ctrl_setup_tr_unit(ctrl);
msm_dp_ctrl_setup_tr_unit(ctrl, panel);
msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO);
@@ -2549,11 +2623,10 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
drm_dbg_dp(ctrl->drm_dev,
"mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
end:
return ret;
}
void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl)
void msm_dp_ctrl_reinit_phy(struct msm_dp_ctrl *msm_dp_ctrl)
{
struct msm_dp_ctrl_private *ctrl;
struct phy *phy;
@@ -2561,29 +2634,13 @@ void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl)
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
phy = ctrl->phy;
msm_dp_panel_disable_vsc_sdp(ctrl->panel);
/* set dongle to D3 (power off) mode */
msm_dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true);
msm_dp_ctrl_mainlink_disable(ctrl);
if (ctrl->stream_clks_on) {
clk_disable_unprepare(ctrl->pixel_clk);
ctrl->stream_clks_on = false;
}
dev_pm_opp_set_rate(ctrl->dev, 0);
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
phy_power_off(phy);
/* aux channel down, reinit phy */
phy_exit(phy);
phy_init(phy);
}
void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl)
void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel)
{
struct msm_dp_ctrl_private *ctrl;
struct phy *phy;
@@ -2591,24 +2648,19 @@ void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl)
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
phy = ctrl->phy;
msm_dp_panel_disable_vsc_sdp(ctrl->panel);
msm_dp_panel_disable_vsc_sdp(panel);
msm_dp_ctrl_mainlink_disable(ctrl);
msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl);
msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl, panel);
if (ctrl->stream_clks_on) {
clk_disable_unprepare(ctrl->pixel_clk);
ctrl->stream_clks_on = false;
}
dev_pm_opp_set_rate(ctrl->dev, 0);
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
phy_power_off(phy);
}
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl)
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel)
{
struct msm_dp_ctrl_private *ctrl;
u32 isr;
@@ -2619,7 +2671,7 @@ irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl)
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
if (ctrl->panel->psr_cap.version) {
if (panel->psr_cap.version) {
isr = msm_dp_ctrl_get_psr_interrupt(ctrl);
if (isr)
@@ -2708,7 +2760,7 @@ static int msm_dp_ctrl_clk_init(struct msm_dp_ctrl *msm_dp_ctrl)
}
struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link,
struct msm_dp_panel *panel, struct drm_dp_aux *aux,
struct drm_dp_aux *aux,
struct phy *phy,
void __iomem *ahb_base,
void __iomem *link_base)
@@ -2716,7 +2768,7 @@ struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link
struct msm_dp_ctrl_private *ctrl;
int ret;
if (!dev || !panel || !aux || !link) {
if (!dev || !aux || !link) {
DRM_ERROR("invalid input\n");
return ERR_PTR(-EINVAL);
}
@@ -2744,7 +2796,6 @@ struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link
init_completion(&ctrl->video_comp);
/* in parameters */
ctrl->panel = panel;
ctrl->aux = aux;
ctrl->link = link;
ctrl->dev = dev;

View File

@@ -16,28 +16,37 @@ struct msm_dp_ctrl {
struct phy;
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl);
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train);
void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl);
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *panel);
int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel,
bool force_link_train);
void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl);
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl);
irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev,
struct msm_dp_link *link,
struct msm_dp_panel *panel,
struct drm_dp_aux *aux,
struct phy *phy,
void __iomem *ahb_base,
void __iomem *link_base);
void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
void msm_dp_ctrl_phy_init(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_irq_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl, bool enable);
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel, bool enable);
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *panel);
int msm_dp_ctrl_core_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl);
@@ -45,4 +54,5 @@ void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_enable_irq(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_disable_irq(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_reinit_phy(struct msm_dp_ctrl *msm_dp_ctrl);
#endif /* _DP_CTRL_H_ */

View File

@@ -63,7 +63,6 @@ struct msm_dp_display_private {
struct msm_dp_panel *panel;
struct msm_dp_ctrl *ctrl;
struct msm_dp_display_mode msm_dp_mode;
struct msm_dp msm_dp_display;
/* wait for audio signaling */
@@ -269,6 +268,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
const struct drm_display_info *info = &connector->display_info;
int rc = 0;
u8 dpcd[DP_RECEIVER_CAP_SIZE];
const struct drm_edid *drm_edid = NULL;
rc = drm_dp_read_dpcd_caps(dp->aux, dpcd);
if (rc)
@@ -276,10 +276,20 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
dp->link->lttpr_count = msm_dp_display_lttpr_init(dp, dpcd);
rc = msm_dp_panel_read_sink_caps(dp->panel, connector);
rc = msm_dp_panel_read_link_caps(dp->panel, connector);
if (rc)
goto end;
drm_edid = drm_edid_read_ddc(connector, &dp->aux->ddc);
drm_edid_connector_update(connector, drm_edid);
if (!drm_edid) {
DRM_ERROR("panel edid read failed\n");
/* check edid read fail is due to unplug */
if (!msm_dp_aux_is_link_connected(dp->aux))
return -ETIMEDOUT;
}
msm_dp_link_process_request(dp->link);
if (!dp->msm_dp_display.is_edp)
@@ -291,7 +301,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
dp->msm_dp_display.psr_supported = dp->panel->psr_cap.version && psr_enabled;
dp->audio_supported = info->has_audio;
msm_dp_panel_handle_sink_request(dp->panel);
msm_dp_panel_handle_sink_request(dp->panel, drm_edid);
/*
* set sink to normal operation mode -- D0
@@ -302,6 +312,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
msm_dp_link_reset_phy_params_vx_px(dp->link);
end:
drm_edid_free(drm_edid);
return rc;
}
@@ -348,7 +359,7 @@ static void msm_dp_display_host_init(struct msm_dp_display_private *dp)
dp->phy_initialized);
msm_dp_ctrl_core_clk_enable(dp->ctrl);
msm_dp_ctrl_reset(dp->ctrl);
msm_dp_ctrl_reset(dp->ctrl, dp->panel);
msm_dp_ctrl_enable_irq(dp->ctrl);
msm_dp_aux_init(dp->aux);
dp->core_initialized = true;
@@ -360,7 +371,7 @@ static void msm_dp_display_host_deinit(struct msm_dp_display_private *dp)
dp->msm_dp_display.connector_type, dp->core_initialized,
dp->phy_initialized);
msm_dp_ctrl_reset(dp->ctrl);
msm_dp_ctrl_reset(dp->ctrl, dp->panel);
msm_dp_ctrl_disable_irq(dp->ctrl);
msm_dp_aux_deinit(dp->aux);
msm_dp_ctrl_core_clk_disable(dp->ctrl);
@@ -381,7 +392,7 @@ static int msm_dp_display_handle_irq_hpd(struct msm_dp_display_private *dp)
drm_dbg_dp(dp->drm_dev, "%d\n", sink_request);
msm_dp_ctrl_handle_sink_request(dp->ctrl);
msm_dp_ctrl_handle_sink_request(dp->ctrl, dp->panel);
if (sink_request & DP_TEST_LINK_VIDEO_PATTERN)
msm_dp_display_handle_video_request(dp);
@@ -453,7 +464,7 @@ static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp)
/* Don't forget modes for eDP */
if (!dp->msm_dp_display.is_edp)
msm_dp_panel_unplugged(dp->panel, dp->msm_dp_display.connector);
drm_edid_connector_update(dp->msm_dp_display.connector, NULL);
/* triggered by irq_hdp with sink_count = 0 */
if (dp->link->sink_count == 0)
@@ -515,7 +526,6 @@ static int msm_dp_irq_hpd_handle(struct msm_dp_display_private *dp)
static void msm_dp_display_deinit_sub_modules(struct msm_dp_display_private *dp)
{
msm_dp_audio_put(dp->audio);
msm_dp_panel_put(dp->panel);
msm_dp_aux_put(dp->aux);
}
@@ -560,13 +570,13 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp)
goto error_link;
}
dp->ctrl = msm_dp_ctrl_get(dev, dp->link, dp->panel, dp->aux,
phy, dp->ahb_base, dp->link_base);
dp->ctrl = msm_dp_ctrl_get(dev, dp->link, dp->aux,
phy, dp->ahb_base, dp->link_base);
if (IS_ERR(dp->ctrl)) {
rc = PTR_ERR(dp->ctrl);
DRM_ERROR("failed to initialize ctrl, rc = %d\n", rc);
dp->ctrl = NULL;
goto error_ctrl;
goto error_link;
}
dp->audio = msm_dp_audio_get(dp->msm_dp_display.pdev, dp->link_base);
@@ -574,13 +584,11 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp)
rc = PTR_ERR(dp->audio);
pr_err("failed to initialize audio, rc = %d\n", rc);
dp->audio = NULL;
goto error_ctrl;
goto error_link;
}
return rc;
error_ctrl:
msm_dp_panel_put(dp->panel);
error_link:
msm_dp_aux_put(dp->aux);
error:
@@ -588,20 +596,64 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp)
}
static int msm_dp_display_set_mode(struct msm_dp *msm_dp_display,
struct msm_dp_display_mode *mode)
const struct drm_display_mode *adjusted_mode,
struct msm_dp_panel *msm_dp_panel)
{
struct msm_dp_display_private *dp;
u32 bpp;
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
drm_mode_copy(&dp->panel->msm_dp_mode.drm_mode, &mode->drm_mode);
dp->panel->msm_dp_mode.bpp = mode->bpp;
dp->panel->msm_dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420;
msm_dp_panel_init_panel_info(dp->panel);
if (msm_dp_display_check_video_test(msm_dp_display))
bpp = msm_dp_display_get_test_bpp(msm_dp_display);
else
bpp = msm_dp_panel->connector->display_info.bpc * 3;
msm_dp_panel_init_panel_info(msm_dp_panel, adjusted_mode, bpp ? bpp : 24);
/* populate wide_bus_support to different layers */
dp->ctrl->wide_bus_en =
msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420 ? false : dp->wide_bus_supported;
return 0;
}
static int msm_dp_display_enable(struct msm_dp_display_private *dp, bool force_link_train)
static int msm_dp_display_prepare_link(struct msm_dp_display_private *dp)
{
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
int rc = 0;
bool force_link_train = false;
drm_dbg_dp(dp->drm_dev, "sink_count=%d\n", dp->link->sink_count);
if (msm_dp_display->is_edp)
msm_dp_hpd_plug_handle(dp);
rc = pm_runtime_resume_and_get(&msm_dp_display->pdev->dev);
if (rc) {
DRM_ERROR("failed to pm_runtime_resume\n");
return rc;
}
if (dp->link->sink_count == 0)
return -ENOTCONN;
if (!msm_dp_display->power_on) {
msm_dp_display_host_phy_init(dp);
force_link_train = true;
}
rc = msm_dp_ctrl_on_link(dp->ctrl, dp->panel);
if (rc) {
DRM_ERROR("Failed link training (rc=%d)\n", rc);
// TODO: schedule drm_connector_set_link_status_property()
return rc;
}
return msm_dp_ctrl_prepare_stream_on(dp->ctrl, dp->panel, force_link_train);
}
static int msm_dp_display_enable(struct msm_dp_display_private *dp,
struct msm_dp_panel *msm_dp_panel)
{
int rc = 0;
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
@@ -612,7 +664,7 @@ static int msm_dp_display_enable(struct msm_dp_display_private *dp, bool force_l
return 0;
}
rc = msm_dp_ctrl_on_stream(dp->ctrl, force_link_train);
rc = msm_dp_ctrl_on_stream(dp->ctrl, msm_dp_panel);
if (!rc)
msm_dp_display->power_on = true;
@@ -637,18 +689,15 @@ static int msm_dp_display_post_enable(struct msm_dp *msm_dp_display)
msm_dp_display_handle_plugged_change(msm_dp_display, true);
if (msm_dp_display->psr_supported)
msm_dp_ctrl_config_psr(dp->ctrl);
msm_dp_ctrl_config_psr(dp->ctrl, dp->panel);
return 0;
}
static int msm_dp_display_disable(struct msm_dp_display_private *dp)
static void msm_dp_display_audio_notify_disable(struct msm_dp_display_private *dp)
{
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
if (!msm_dp_display->power_on)
return 0;
/* wait only if audio was enabled */
if (msm_dp_display->audio_enabled) {
/* signal the disconnect event */
@@ -659,21 +708,31 @@ static int msm_dp_display_disable(struct msm_dp_display_private *dp)
}
msm_dp_display->audio_enabled = false;
}
if (dp->link->sink_count == 0) {
/*
* irq_hpd with sink_count = 0
* hdmi unplugged out of dongle
*/
msm_dp_ctrl_off_link_stream(dp->ctrl);
} else {
/*
* unplugged interrupt
* dongle unplugged out of DUT
*/
msm_dp_ctrl_off(dp->ctrl);
static int msm_dp_display_disable(struct msm_dp_display_private *dp,
struct msm_dp_panel *msm_dp_panel)
{
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
if (!msm_dp_display->power_on)
return 0;
msm_dp_panel_disable_vsc_sdp(msm_dp_panel);
msm_dp_ctrl_off_pixel_clk(dp->ctrl);
/* dongle is still connected but sinks are disconnected */
if (dp->link->sink_count == 0)
msm_dp_link_psm_config(dp->link, &msm_dp_panel->link_info, true);
msm_dp_ctrl_off_link(dp->ctrl, msm_dp_panel);
if (dp->link->sink_count == 0)
/* re-init the PHY so that we can listen to Dongle disconnect */
msm_dp_ctrl_reinit_phy(dp->ctrl);
else
msm_dp_display_host_phy_exit(dp);
}
msm_dp_display->power_on = false;
@@ -682,24 +741,22 @@ static int msm_dp_display_disable(struct msm_dp_display_private *dp)
}
/**
* msm_dp_bridge_mode_valid - callback to determine if specified mode is valid
* @bridge: Pointer to drm bridge structure
* msm_dp_display_mode_valid - callback to determine if specified mode is valid
* @dp: Pointer to dp display structure
* @info: display info
* @mode: Pointer to drm mode structure
* Returns: Validity status for specified mode
*/
enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
const u32 num_components = 3, default_bpp = 24;
struct msm_dp_display_private *msm_dp_display;
struct msm_dp_link_info *link_info;
u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;
struct msm_dp *dp;
int mode_pclk_khz = mode->clock;
dp = to_dp_bridge(bridge)->msm_dp_display;
bool is_yuv_420;
if (!dp || !mode_pclk_khz || !dp->connector) {
DRM_ERROR("invalid params\n");
@@ -709,9 +766,16 @@ enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
link_info = &msm_dp_display->panel->link_info;
if ((drm_mode_is_420_only(&dp->connector->display_info, mode) &&
msm_dp_display->panel->vsc_sdp_supported) ||
msm_dp_wide_bus_available(dp))
is_yuv_420 = drm_mode_is_420_only(&dp->connector->display_info, mode);
/*
* YUV 420 is carried over DP by signalling the colorimetry through a
* VSC SDP, so a 420-only mode cannot be driven without VSC SDP support.
*/
if (is_yuv_420 && !msm_dp_display->panel->vsc_sdp_supported)
return MODE_NO_420;
if (is_yuv_420 || msm_dp_display->wide_bus_supported)
mode_pclk_khz /= 2;
if (mode_pclk_khz > DP_MAX_PIXEL_CLK_KHZ)
@@ -744,8 +808,7 @@ int msm_dp_display_get_modes(struct msm_dp *dp)
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
return msm_dp_panel_get_modes(msm_dp_display->panel,
dp->connector);
return drm_edid_connector_add_modes(msm_dp_display->panel->connector);
}
bool msm_dp_display_check_video_test(struct msm_dp *dp)
@@ -808,7 +871,7 @@ void msm_dp_display_set_psr(struct msm_dp *msm_dp_display, bool enter)
}
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
msm_dp_ctrl_set_psr(dp->ctrl, enter);
msm_dp_ctrl_set_psr(dp->ctrl, dp->panel, enter);
}
/**
@@ -918,7 +981,7 @@ static irqreturn_t msm_dp_display_irq_handler(int irq, void *dev_id)
}
/* DP controller isr */
ret |= msm_dp_ctrl_isr(dp->ctrl);
ret |= msm_dp_ctrl_isr(dp->ctrl, dp->panel);
return ret;
}
@@ -1277,22 +1340,10 @@ void __exit msm_dp_unregister(void)
platform_driver_unregister(&msm_dp_display_driver);
}
bool msm_dp_is_yuv_420_enabled(const struct msm_dp *msm_dp_display,
const struct drm_display_mode *mode)
{
struct msm_dp_display_private *dp;
const struct drm_display_info *info;
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
info = &msm_dp_display->connector->display_info;
return dp->panel->vsc_sdp_supported && drm_mode_is_420_only(info, mode);
}
bool msm_dp_needs_periph_flush(const struct msm_dp *msm_dp_display,
const struct drm_display_mode *mode)
{
return msm_dp_is_yuv_420_enabled(msm_dp_display, mode);
return drm_mode_is_420_only(&msm_dp_display->connector->display_info, mode);
}
bool msm_dp_wide_bus_available(const struct msm_dp *msm_dp_display)
@@ -1301,7 +1352,7 @@ bool msm_dp_wide_bus_available(const struct msm_dp *msm_dp_display)
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
if (dp->msm_dp_mode.out_fmt_is_yuv_420)
if (dp->panel->msm_dp_mode.out_fmt_is_yuv_420)
return false;
return dp->wide_bus_supported;
@@ -1352,66 +1403,57 @@ int msm_dp_modeset_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
return 0;
}
void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state)
void msm_dp_display_atomic_pre_enable(struct msm_dp *msm_dp_display,
struct drm_atomic_commit *state)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
int rc = 0;
struct msm_dp_display_private *msm_dp_display;
bool force_link_train = false;
struct msm_dp_display_private *dp;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
if (!msm_dp_display->msm_dp_mode.drm_mode.clock) {
DRM_ERROR("invalid params\n");
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
crtc = drm_atomic_get_new_crtc_for_encoder(state, msm_dp_display->bridge->encoder);
if (!crtc)
return;
}
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (dp->is_edp)
msm_dp_hpd_plug_handle(msm_dp_display);
if (pm_runtime_resume_and_get(&dp->pdev->dev)) {
DRM_ERROR("failed to pm_runtime_resume\n");
return;
}
if (msm_dp_display->link->sink_count == 0)
return;
rc = msm_dp_display_set_mode(dp, &msm_dp_display->msm_dp_mode);
if (rc) {
DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc);
return;
}
if (!dp->power_on) {
msm_dp_display_host_phy_init(msm_dp_display);
force_link_train = true;
}
rc = msm_dp_ctrl_on_link(msm_dp_display->ctrl);
if (rc) {
DRM_ERROR("Failed link training (rc=%d)\n", rc);
// TODO: schedule drm_connector_set_link_status_property()
return;
}
msm_dp_display_enable(msm_dp_display, force_link_train);
rc = msm_dp_display_post_enable(dp);
if (rc) {
DRM_ERROR("DP display post enable failed, rc=%d\n", rc);
msm_dp_display_disable(msm_dp_display);
}
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
/*
* The DPU encoder's .atomic_enable() reads the mode's YUV420 / wide bus
* state and runs before the bridge's .atomic_enable(), so the mode must
* be programmed here, in .atomic_pre_enable().
*/
msm_dp_display_set_mode(msm_dp_display, &crtc_state->adjusted_mode, dp->panel);
}
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
void msm_dp_display_atomic_enable(struct msm_dp *msm_dp_display,
struct drm_atomic_commit *state)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
int rc = 0;
struct msm_dp_display_private *dp;
dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
rc = msm_dp_display_prepare_link(dp);
if (rc) {
DRM_ERROR("DP display prepare failed, rc=%d\n", rc);
return;
}
rc = msm_dp_display_enable(dp, dp->panel);
if (rc)
DRM_ERROR("DP display enable failed, rc=%d\n", rc);
rc = msm_dp_display_post_enable(msm_dp_display);
if (rc) {
DRM_ERROR("DP display post enable failed, rc=%d\n", rc);
msm_dp_display_disable(dp, dp->panel);
}
drm_dbg_dp(msm_dp_display->drm_dev, "type=%d Done\n", msm_dp_display->connector_type);
}
void msm_dp_display_atomic_disable(struct msm_dp *dp)
{
struct msm_dp_display_private *msm_dp_display;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
@@ -1419,11 +1461,17 @@ void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
msm_dp_ctrl_push_idle(msm_dp_display->ctrl);
}
void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state)
static void msm_dp_display_unprepare(struct msm_dp_display_private *dp)
{
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
pm_runtime_put_sync(&msm_dp_display->pdev->dev);
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", msm_dp_display->connector_type);
}
void msm_dp_display_atomic_post_disable(struct msm_dp *dp)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
struct msm_dp_display_private *msm_dp_display;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
@@ -1431,50 +1479,11 @@ void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
if (dp->is_edp)
msm_dp_hpd_unplug_handle(msm_dp_display);
msm_dp_display_disable(msm_dp_display);
msm_dp_display_audio_notify_disable(msm_dp_display);
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
msm_dp_display_disable(msm_dp_display, msm_dp_display->panel);
pm_runtime_put_sync(&dp->pdev->dev);
}
void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
struct msm_dp_display_private *msm_dp_display;
struct msm_dp_panel *msm_dp_panel;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
msm_dp_panel = msm_dp_display->panel;
memset(&msm_dp_display->msm_dp_mode, 0x0, sizeof(struct msm_dp_display_mode));
if (msm_dp_display_check_video_test(dp))
msm_dp_display->msm_dp_mode.bpp = msm_dp_display_get_test_bpp(dp);
else /* Default num_components per pixel = 3 */
msm_dp_display->msm_dp_mode.bpp = dp->connector->display_info.bpc * 3;
if (!msm_dp_display->msm_dp_mode.bpp)
msm_dp_display->msm_dp_mode.bpp = 24; /* Default bpp */
drm_mode_copy(&msm_dp_display->msm_dp_mode.drm_mode, adjusted_mode);
msm_dp_display->msm_dp_mode.v_active_low =
!!(msm_dp_display->msm_dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC);
msm_dp_display->msm_dp_mode.h_active_low =
!!(msm_dp_display->msm_dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 =
drm_mode_is_420_only(&dp->connector->display_info, adjusted_mode) &&
msm_dp_panel->vsc_sdp_supported;
/* populate wide_bus_support to different layers */
msm_dp_display->ctrl->wide_bus_en =
msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 ? false : msm_dp_display->wide_bus_supported;
msm_dp_display_unprepare(msm_dp_display);
}
void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge)

View File

@@ -33,5 +33,14 @@ void msm_dp_display_signal_audio_start(struct msm_dp *msm_dp_display);
void msm_dp_display_signal_audio_complete(struct msm_dp *msm_dp_display);
void msm_dp_display_set_psr(struct msm_dp *dp, bool enter);
void msm_dp_display_debugfs_init(struct msm_dp *msm_dp_display, struct dentry *dentry, bool is_edp);
void msm_dp_display_atomic_post_disable(struct msm_dp *dp_display);
void msm_dp_display_atomic_disable(struct msm_dp *dp_display);
void msm_dp_display_atomic_pre_enable(struct msm_dp *dp_display,
struct drm_atomic_commit *state);
void msm_dp_display_atomic_enable(struct msm_dp *dp_display,
struct drm_atomic_commit *state);
enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp,
const struct drm_display_info *info,
const struct drm_display_mode *mode);
#endif /* _DP_DISPLAY_H_ */

View File

@@ -49,14 +49,60 @@ static void msm_dp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry
msm_dp_display_debugfs_init(dp, root, false);
}
static void msm_dp_bridge_atomic_pre_enable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state)
{
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->msm_dp_display;
msm_dp_display_atomic_pre_enable(dp, state);
}
static void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state)
{
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->msm_dp_display;
msm_dp_display_atomic_enable(dp, state);
}
static void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state)
{
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->msm_dp_display;
msm_dp_display_atomic_disable(dp);
}
static void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state)
{
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->msm_dp_display;
msm_dp_display_atomic_post_disable(dp);
}
static enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *drm_bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->msm_dp_display;
return msm_dp_display_mode_valid(dp, info, mode);
}
static const struct drm_bridge_funcs msm_dp_bridge_ops = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.atomic_pre_enable = msm_dp_bridge_atomic_pre_enable,
.atomic_enable = msm_dp_bridge_atomic_enable,
.atomic_disable = msm_dp_bridge_atomic_disable,
.atomic_post_disable = msm_dp_bridge_atomic_post_disable,
.mode_set = msm_dp_bridge_mode_set,
.mode_valid = msm_dp_bridge_mode_valid,
.get_modes = msm_dp_bridge_get_modes,
.detect = msm_dp_bridge_detect,
@@ -116,7 +162,7 @@ static void msm_edp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
return;
}
msm_dp_bridge_atomic_enable(drm_bridge, state);
msm_dp_display_atomic_enable(dp, state);
}
static void msm_edp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
@@ -230,10 +276,10 @@ static void msm_edp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry
}
static const struct drm_bridge_funcs msm_edp_bridge_ops = {
.atomic_pre_enable = msm_dp_bridge_atomic_pre_enable,
.atomic_enable = msm_edp_bridge_atomic_enable,
.atomic_disable = msm_edp_bridge_atomic_disable,
.atomic_post_disable = msm_edp_bridge_atomic_post_disable,
.mode_set = msm_dp_bridge_mode_set,
.mode_valid = msm_edp_bridge_mode_valid,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,

View File

@@ -27,18 +27,6 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
struct drm_connector *connector);
void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state);
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state);
void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
struct drm_atomic_commit *state);
enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode);
void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode);
void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge);
void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge);
void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge,

View File

@@ -232,8 +232,8 @@ static u32 msm_dp_panel_get_supported_bpp(struct msm_dp_panel *msm_dp_panel,
return min_supported_bpp;
}
int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector)
int msm_dp_panel_read_link_caps(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector)
{
int rc, bw_code;
int count;
@@ -271,36 +271,9 @@ int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel,
rc = drm_dp_read_downstream_info(panel->aux, msm_dp_panel->dpcd,
msm_dp_panel->downstream_ports);
if (rc)
return rc;
drm_edid_free(msm_dp_panel->drm_edid);
msm_dp_panel->drm_edid = drm_edid_read_ddc(connector, &panel->aux->ddc);
drm_edid_connector_update(connector, msm_dp_panel->drm_edid);
if (!msm_dp_panel->drm_edid) {
DRM_ERROR("panel edid read failed\n");
/* check edid read fail is due to unplug */
if (!msm_dp_aux_is_link_connected(panel->aux)) {
rc = -ETIMEDOUT;
goto end;
}
}
end:
return rc;
}
void msm_dp_panel_unplugged(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector)
{
drm_edid_connector_update(connector, NULL);
drm_edid_free(msm_dp_panel->drm_edid);
msm_dp_panel->drm_edid = NULL;
}
u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel,
u32 mode_edid_bpp, u32 mode_pclk_khz)
{
@@ -324,20 +297,6 @@ u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel,
return bpp;
}
int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector)
{
if (!msm_dp_panel) {
DRM_ERROR("invalid input\n");
return -EINVAL;
}
if (msm_dp_panel->drm_edid)
return drm_edid_connector_add_modes(connector);
return 0;
}
static u8 msm_dp_panel_get_edid_checksum(const struct edid *edid)
{
edid += edid->extensions;
@@ -345,7 +304,8 @@ static u8 msm_dp_panel_get_edid_checksum(const struct edid *edid)
return edid->checksum;
}
void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel)
void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel,
const struct drm_edid *drm_edid)
{
struct msm_dp_panel_private *panel;
@@ -358,7 +318,7 @@ void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel)
if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) {
/* FIXME: get rid of drm_edid_raw() */
const struct edid *edid = drm_edid_raw(msm_dp_panel->drm_edid);
const struct edid *edid = drm_edid_raw(drm_edid);
u8 checksum;
if (edid)
@@ -687,15 +647,27 @@ int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en)
return 0;
}
int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel)
int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel,
const struct drm_display_mode *adjusted_mode,
u32 bpp)
{
struct drm_display_mode *drm_mode;
struct msm_dp_panel_private *panel;
drm_mode = &msm_dp_panel->msm_dp_mode.drm_mode;
panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel);
drm_mode_copy(&msm_dp_panel->msm_dp_mode.drm_mode, adjusted_mode);
msm_dp_panel->msm_dp_mode.bpp = bpp;
msm_dp_panel->msm_dp_mode.v_active_low =
!!(adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC);
msm_dp_panel->msm_dp_mode.h_active_low =
!!(adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC);
msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420 =
drm_mode_is_420_only(&msm_dp_panel->connector->display_info, adjusted_mode) &&
msm_dp_panel->vsc_sdp_supported;
drm_mode = &msm_dp_panel->msm_dp_mode.drm_mode;
/*
* print resolution info as this is a result
* of user initiated action of cable connection
@@ -755,10 +727,3 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux
return msm_dp_panel;
}
void msm_dp_panel_put(struct msm_dp_panel *msm_dp_panel)
{
if (!msm_dp_panel)
return;
drm_edid_free(msm_dp_panel->drm_edid);
}

View File

@@ -33,7 +33,6 @@ struct msm_dp_panel {
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
struct msm_dp_link_info link_info;
const struct drm_edid *drm_edid;
struct drm_connector *connector;
struct msm_dp_display_mode msm_dp_mode;
struct msm_dp_panel_psr psr_cap;
@@ -44,18 +43,17 @@ struct msm_dp_panel {
u32 max_bw_code;
};
int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel);
int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel,
const struct drm_display_mode *adjusted_mode,
u32 bpp);
int msm_dp_panel_deinit(struct msm_dp_panel *msm_dp_panel);
int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en);
int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector);
void msm_dp_panel_unplugged(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector);
int msm_dp_panel_read_link_caps(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector);
u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel, u32 mode_max_bpp,
u32 mode_pclk_khz);
int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel,
struct drm_connector *connector);
void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel);
void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel,
const struct drm_edid *drm_edid);
void msm_dp_panel_tpg_config(struct msm_dp_panel *msm_dp_panel, bool enable);
void msm_dp_panel_clear_dsc_dto(struct msm_dp_panel *msm_dp_panel);
@@ -94,5 +92,4 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux
struct msm_dp_link *link,
void __iomem *link_base,
void __iomem *p0_base);
void msm_dp_panel_put(struct msm_dp_panel *msm_dp_panel);
#endif /* _DP_PANEL_H_ */

View File

@@ -149,8 +149,10 @@
#define DP_CONFIGURATION_CTRL_ENHANCED_FRAMING (0x00000040)
#define DP_CONFIGURATION_CTRL_SEND_VSC (0x00000080)
#define DP_CONFIGURATION_CTRL_BPC (0x00000100)
#define DP_CONFIGURATION_CTRL_BPC_MASK GENMASK(9, 8)
#define DP_CONFIGURATION_CTRL_ASSR (0x00000400)
#define DP_CONFIGURATION_CTRL_RGB_YUV (0x00000800)
#define DP_CONFIGURATION_CTRL_RGB_YUV_MASK GENMASK(12, 11)
#define DP_CONFIGURATION_CTRL_LSCLK_DIV (0x00002000)
#define DP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT (0x04)
#define DP_CONFIGURATION_CTRL_BPC_SHIFT (0x08)

View File

@@ -550,8 +550,6 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)
void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host)
{
/* Drop the performance state vote */
dev_pm_opp_set_rate(&msm_host->pdev->dev, 0);
clk_disable_unprepare(msm_host->esc_clk);
clk_disable_unprepare(msm_host->pixel_clk);
clk_disable_unprepare(msm_host->byte_intf_clk);
@@ -671,12 +669,24 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
{
long rounded_byte_clk_rate;
if (!msm_host->mode) {
pr_err("%s: mode not set\n", __func__);
return -EINVAL;
}
dsi_calc_pclk(msm_host, is_bonded_dsi);
rounded_byte_clk_rate = clk_round_rate(msm_host->byte_clk,
msm_host->byte_clk_rate);
if (rounded_byte_clk_rate < 0) {
pr_err("%s: failed to round byte clock rate, %ld\n",
__func__, rounded_byte_clk_rate);
return rounded_byte_clk_rate;
}
msm_host->byte_clk_rate = rounded_byte_clk_rate;
msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk);
return 0;
}

View File

@@ -111,6 +111,7 @@ struct msm_dsi_phy {
struct msm_dsi_dphy_timing timing;
const struct msm_dsi_phy_cfg *cfg;
void *tuning_cfg;
void *pll_data;
enum msm_dsi_phy_usecase usecase;
bool regulator_ldo_mode;

View File

@@ -426,8 +426,11 @@ static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll)
u32 data;
spin_lock_irqsave(&pll->pll_enable_lock, flags);
pll->pll_enable_cnt++;
WARN_ON(pll->pll_enable_cnt == INT_MAX);
if (pll->pll_enable_cnt++) {
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
WARN_ON(pll->pll_enable_cnt == INT_MAX);
return;
}
data = readl(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
data |= DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
@@ -873,6 +876,7 @@ static int dsi_pll_7nm_init(struct msm_dsi_phy *phy)
spin_lock_init(&pll_7nm->pll_enable_lock);
pll_7nm->phy = phy;
phy->pll_data = pll_7nm;
ret = pll_7nm_register(pll_7nm, phy->provided_clocks->hws);
if (ret) {
@@ -961,8 +965,10 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
u32 const delay_us = 5;
u32 const timeout_us = 1000;
struct msm_dsi_dphy_timing *timing = &phy->timing;
struct dsi_pll_7nm *pll = phy->pll_data;
void __iomem *base = phy->base;
bool less_than_1500_mhz;
unsigned long flags;
u32 vreg_ctrl_0, vreg_ctrl_1, lane_ctrl0;
u32 glbl_pemph_ctrl_0;
u32 glbl_str_swi_cal_sel_ctrl, glbl_hstx_str_ctrl_0;
@@ -1084,10 +1090,13 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
glbl_rescode_bot_ctrl = 0x3c;
}
spin_lock_irqsave(&pll->pll_enable_lock, flags);
pll->pll_enable_cnt = 1;
/* de-assert digital and pll power down */
data = DSI_7nm_PHY_CMN_CTRL_0_DIGTOP_PWRDN_B |
DSI_7nm_PHY_CMN_CTRL_0_PLL_SHUTDOWNB;
writel(data, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
/* Assert PLL core reset */
writel(0x00, base + REG_DSI_7nm_PHY_CMN_PLL_CNTRL);
@@ -1200,7 +1209,9 @@ static bool dsi_7nm_set_continuous_clock(struct msm_dsi_phy *phy, bool enable)
static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
{
struct dsi_pll_7nm *pll = phy->pll_data;
void __iomem *base = phy->base;
unsigned long flags;
u32 data;
DBG("");
@@ -1227,8 +1238,11 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
writel(data, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
writel(0, base + REG_DSI_7nm_PHY_CMN_LANE_CTRL0);
spin_lock_irqsave(&pll->pll_enable_lock, flags);
pll->pll_enable_cnt = 0;
/* Turn off all PHY blocks */
writel(0x00, base + REG_DSI_7nm_PHY_CMN_CTRL_0);
spin_unlock_irqrestore(&pll->pll_enable_lock, flags);
/* make sure phy is turned off */
wmb();

View File

@@ -112,6 +112,25 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
return readl(hdmi->mmio + reg);
}
static inline void hdmi_clear_bits(struct hdmi *hdmi, u32 reg, u32 mask)
{
u32 val;
val = hdmi_read(hdmi, reg);
val &= ~mask;
hdmi_write(hdmi, reg, val);
}
static inline void hdmi_update_bits(struct hdmi *hdmi, u32 reg, u32 mask, u32 data)
{
u32 val;
val = hdmi_read(hdmi, reg);
val &= ~mask;
val |= data & mask;
hdmi_write(hdmi, reg, val);
}
static inline u32 hdmi_qfprom_read(struct hdmi *hdmi, u32 reg)
{
return readl(hdmi->qfprom_mmio + reg);

View File

@@ -58,16 +58,13 @@ static int msm_hdmi_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
u32 val;
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
HDMI_INFOFRAME_CTRL0_AVI_CONT);
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
hdmi_clear_bits(hdmi, REG_HDMI_INFOFRAME_CTRL0,
HDMI_INFOFRAME_CTRL0_AVI_SEND |
HDMI_INFOFRAME_CTRL0_AVI_CONT);
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
hdmi_clear_bits(hdmi, REG_HDMI_INFOFRAME_CTRL1,
HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK);
return 0;
}
@@ -76,18 +73,15 @@ static int msm_hdmi_bridge_clear_audio_infoframe(struct drm_bridge *bridge)
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
u32 val;
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
hdmi_clear_bits(hdmi, REG_HDMI_INFOFRAME_CTRL0,
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
hdmi_clear_bits(hdmi, REG_HDMI_INFOFRAME_CTRL1,
HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK);
return 0;
}
@@ -96,13 +90,11 @@ static int msm_hdmi_bridge_clear_spd_infoframe(struct drm_bridge *bridge)
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
u32 val;
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
val &= ~(HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK);
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
hdmi_clear_bits(hdmi, REG_HDMI_GEN_PKT_CTRL,
HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK);
return 0;
}
@@ -111,14 +103,12 @@ static int msm_hdmi_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge)
{
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
u32 val;
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
val &= ~(HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK);
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
hdmi_clear_bits(hdmi, REG_HDMI_GEN_PKT_CTRL,
HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK);
return 0;
}
@@ -129,7 +119,6 @@ static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge,
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = hdmi_bridge->hdmi;
u32 buf[4] = {};
u32 val;
int i;
if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
@@ -153,15 +142,13 @@ static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge,
for (i = 0; i < ARRAY_SIZE(buf); i++)
hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
HDMI_INFOFRAME_CTRL0_AVI_CONT;
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
hdmi_update_bits(hdmi, REG_HDMI_INFOFRAME_CTRL0,
HDMI_INFOFRAME_CTRL0_AVI_SEND | HDMI_INFOFRAME_CTRL0_AVI_CONT,
HDMI_INFOFRAME_CTRL0_AVI_SEND | HDMI_INFOFRAME_CTRL0_AVI_CONT);
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
hdmi_update_bits(hdmi, REG_HDMI_INFOFRAME_CTRL1,
HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK,
HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER));
return 0;
}
@@ -193,12 +180,11 @@ static int msm_hdmi_bridge_write_audio_infoframe(struct drm_bridge *bridge,
buffer[9] << 16 |
buffer[10] << 24);
val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
val = HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
hdmi_update_bits(hdmi, REG_HDMI_INFOFRAME_CTRL0, val, val);
return 0;
}
@@ -231,11 +217,10 @@ static int msm_hdmi_bridge_write_spd_infoframe(struct drm_bridge *bridge,
for (i = 0; i < ARRAY_SIZE(buf); i++)
hdmi_write(hdmi, REG_HDMI_GENERIC1(i), buf[i]);
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
val |= HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
HDMI_GEN_PKT_CTRL_GENERIC1_LINE(SPD_IFRAME_LINE_NUMBER);
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
val = HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
HDMI_GEN_PKT_CTRL_GENERIC1_LINE(SPD_IFRAME_LINE_NUMBER);
hdmi_update_bits(hdmi, REG_HDMI_GEN_PKT_CTRL, val, val);
return 0;
}
@@ -269,12 +254,11 @@ static int msm_hdmi_bridge_write_hdmi_infoframe(struct drm_bridge *bridge,
for (i = 0; i < ARRAY_SIZE(buf); i++)
hdmi_write(hdmi, REG_HDMI_GENERIC0(i), buf[i]);
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
val |= HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
HDMI_GEN_PKT_CTRL_GENERIC0_LINE(VENSPEC_IFRAME_LINE_NUMBER);
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
val = HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
HDMI_GEN_PKT_CTRL_GENERIC0_LINE(VENSPEC_IFRAME_LINE_NUMBER);
hdmi_update_bits(hdmi, REG_HDMI_GEN_PKT_CTRL, val, val);
return 0;
}

View File

@@ -306,9 +306,9 @@ static int msm_reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl *hdcp_ctrl)
HDMI_HDCP_DDC_CTRL_0_DISABLE);
/* ACK the Failure to Clear it */
reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_CTRL_1);
reg_val |= HDMI_HDCP_DDC_CTRL_1_FAILED_ACK;
hdmi_write(hdmi, REG_HDMI_HDCP_DDC_CTRL_1, reg_val);
hdmi_update_bits(hdmi, REG_HDMI_HDCP_DDC_CTRL_1,
HDMI_HDCP_DDC_CTRL_1_FAILED_ACK,
HDMI_HDCP_DDC_CTRL_1_FAILED_ACK);
/* Check if the FAILURE got Cleared */
reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_STATUS);
@@ -324,28 +324,22 @@ static int msm_reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl *hdcp_ctrl)
DBG("Before: HDMI_DDC_SW_STATUS=0x%08x",
hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS));
/* Reset HDMI DDC software status */
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
reg_val |= HDMI_DDC_CTRL_SW_STATUS_RESET;
hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
hdmi_update_bits(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SW_STATUS_RESET,
HDMI_DDC_CTRL_SW_STATUS_RESET);
rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
reg_val &= ~HDMI_DDC_CTRL_SW_STATUS_RESET;
hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SW_STATUS_RESET);
/* Reset HDMI DDC Controller */
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
reg_val |= HDMI_DDC_CTRL_SOFT_RESET;
hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
hdmi_update_bits(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SOFT_RESET,
HDMI_DDC_CTRL_SOFT_RESET);
/* If previous msleep is aborted, skip this msleep */
if (!rc)
rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
reg_val &= ~HDMI_DDC_CTRL_SOFT_RESET;
hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SOFT_RESET);
DBG("After: HDMI_DDC_SW_STATUS=0x%08x",
hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS));
}
@@ -399,7 +393,6 @@ static void msm_hdmi_hdcp_reauth_work(struct work_struct *work)
struct hdmi_hdcp_ctrl, hdcp_reauth_work);
struct hdmi *hdmi = hdcp_ctrl->hdmi;
unsigned long flags;
u32 reg_val;
DBG("HDCP REAUTH WORK");
/*
@@ -409,9 +402,7 @@ static void msm_hdmi_hdcp_reauth_work(struct work_struct *work)
* AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
*/
spin_lock_irqsave(&hdmi->reg_lock, flags);
reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
reg_val &= ~HDMI_HPD_CTRL_ENABLE;
hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_HPD_CTRL, HDMI_HPD_CTRL_ENABLE);
/* Disable HDCP interrupts */
hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL, 0);
@@ -431,9 +422,8 @@ static void msm_hdmi_hdcp_reauth_work(struct work_struct *work)
/* Enable HPD circuitry */
spin_lock_irqsave(&hdmi->reg_lock, flags);
reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
reg_val |= HDMI_HPD_CTRL_ENABLE;
hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
hdmi_update_bits(hdmi, REG_HDMI_HPD_CTRL, HDMI_HPD_CTRL_ENABLE,
HDMI_HPD_CTRL_ENABLE);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
/*
@@ -456,7 +446,6 @@ static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
struct hdmi *hdmi = hdcp_ctrl->hdmi;
u32 link0_status;
u32 reg_val;
unsigned long flags;
int rc;
@@ -472,14 +461,11 @@ static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
spin_lock_irqsave(&hdmi->reg_lock, flags);
/* disable HDMI Encrypt */
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
reg_val &= ~HDMI_CTRL_ENCRYPTED;
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED);
/* Enabling Software DDC */
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_ARBITRATION);
reg_val &= ~HDMI_DDC_ARBITRATION_HW_ARBITRATION;
hdmi_write(hdmi, REG_HDMI_DDC_ARBITRATION, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_DDC_ARBITRATION,
HDMI_DDC_ARBITRATION_HW_ARBITRATION);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
/*
@@ -498,9 +484,8 @@ static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
hdmi_write(hdmi, REG_HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE);
/* Disable the RngCipher state */
reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DEBUG_CTRL);
reg_val &= ~HDMI_HDCP_DEBUG_CTRL_RNG_CIPHER;
hdmi_write(hdmi, REG_HDMI_HDCP_DEBUG_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_HDCP_DEBUG_CTRL,
HDMI_HDCP_DEBUG_CTRL_RNG_CIPHER);
DBG("HDCP_DEBUG_CTRL=0x%08x",
hdmi_read(hdmi, REG_HDMI_HDCP_DEBUG_CTRL));
@@ -537,15 +522,12 @@ static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
static void msm_hdmi_hdcp_auth_fail(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
struct hdmi *hdmi = hdcp_ctrl->hdmi;
u32 reg_val;
unsigned long flags;
DBG("hdcp auth failed, queue reauth work");
/* clear HDMI Encrypt */
spin_lock_irqsave(&hdmi->reg_lock, flags);
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
reg_val &= ~HDMI_CTRL_ENCRYPTED;
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAILED;
@@ -555,7 +537,6 @@ static void msm_hdmi_hdcp_auth_fail(struct hdmi_hdcp_ctrl *hdcp_ctrl)
static void msm_hdmi_hdcp_auth_done(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
struct hdmi *hdmi = hdcp_ctrl->hdmi;
u32 reg_val;
unsigned long flags;
/*
@@ -563,16 +544,15 @@ static void msm_hdmi_hdcp_auth_done(struct hdmi_hdcp_ctrl *hdcp_ctrl)
* there is no Arbitration between software and hardware for DDC
*/
spin_lock_irqsave(&hdmi->reg_lock, flags);
reg_val = hdmi_read(hdmi, REG_HDMI_DDC_ARBITRATION);
reg_val |= HDMI_DDC_ARBITRATION_HW_ARBITRATION;
hdmi_write(hdmi, REG_HDMI_DDC_ARBITRATION, reg_val);
hdmi_update_bits(hdmi, REG_HDMI_DDC_ARBITRATION,
HDMI_DDC_ARBITRATION_HW_ARBITRATION,
HDMI_DDC_ARBITRATION_HW_ARBITRATION);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
/* enable HDMI Encrypt */
spin_lock_irqsave(&hdmi->reg_lock, flags);
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
reg_val |= HDMI_CTRL_ENCRYPTED;
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
hdmi_update_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED,
HDMI_CTRL_ENCRYPTED);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATED;
@@ -1304,7 +1284,6 @@ static void msm_hdmi_hdcp_auth_work(struct work_struct *work)
void msm_hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
struct hdmi *hdmi = hdcp_ctrl->hdmi;
u32 reg_val;
unsigned long flags;
if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) ||
@@ -1315,9 +1294,7 @@ void msm_hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl)
/* clear HDMI Encrypt */
spin_lock_irqsave(&hdmi->reg_lock, flags);
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
reg_val &= ~HDMI_CTRL_ENCRYPTED;
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
hdcp_ctrl->auth_event = 0;
@@ -1330,7 +1307,6 @@ void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
struct hdmi *hdmi = hdcp_ctrl->hdmi;
unsigned long flags;
u32 reg_val;
if ((HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) ||
(HDCP_STATE_NO_AKSV == hdcp_ctrl->hdcp_state)) {
@@ -1345,9 +1321,7 @@ void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl)
* AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
*/
spin_lock_irqsave(&hdmi->reg_lock, flags);
reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
reg_val &= ~HDMI_HPD_CTRL_ENABLE;
hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_HPD_CTRL, HDMI_HPD_CTRL_ENABLE);
/*
* Disable HDCP interrupts.
@@ -1375,14 +1349,11 @@ void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl)
hdmi_write(hdmi, REG_HDMI_HDCP_CTRL, 0);
spin_lock_irqsave(&hdmi->reg_lock, flags);
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
reg_val &= ~HDMI_CTRL_ENCRYPTED;
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
hdmi_clear_bits(hdmi, REG_HDMI_CTRL, HDMI_CTRL_ENCRYPTED);
/* Enable HPD circuitry */
reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
reg_val |= HDMI_HPD_CTRL_ENABLE;
hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
hdmi_update_bits(hdmi, REG_HDMI_HPD_CTRL, HDMI_HPD_CTRL_ENABLE,
HDMI_HPD_CTRL_ENABLE);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;

View File

@@ -222,20 +222,21 @@ static void load_gpu(struct drm_device *dev)
*/
struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx)
{
static DEFINE_MUTEX(init_lock);
struct msm_drm_private *priv = dev->dev_private;
struct drm_gpuvm *vm = smp_load_acquire(&ctx->vm);
/* Once ctx->vm is created it is valid for the lifetime of the context: */
if (ctx->vm)
return ctx->vm;
if (vm)
return vm;
guard(rwsem_write)(&ctx->ctxlock);
mutex_lock(&init_lock);
if (!ctx->vm) {
ctx->vm = msm_gpu_create_private_vm(
vm = msm_gpu_create_private_vm(
priv->gpu, current, !ctx->userspace_managed_vm);
if (!IS_ERR_OR_NULL(vm))
smp_store_release(&ctx->vm, vm);
}
mutex_unlock(&init_lock);
return ctx->vm;
}
@@ -250,7 +251,7 @@ static int context_init(struct drm_device *dev, struct drm_file *file)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->submitqueues);
rwlock_init(&ctx->queuelock);
init_rwsem(&ctx->ctxlock);
kref_init(&ctx->ref);
msm_submitqueue_init(dev, ctx);
@@ -422,10 +423,14 @@ static int msm_ioctl_gem_info_iova(struct drm_device *dev,
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_context *ctx = file->driver_priv;
struct drm_gpuvm *vm = msm_context_vm(dev, ctx);
if (!priv->gpu)
return -EINVAL;
if (!vm)
return UERR(ENOMEM, dev, "no VM");
if (msm_context_is_vmbind(ctx))
return UERR(EINVAL, dev, "VM_BIND is enabled");
@@ -436,7 +441,7 @@ static int msm_ioctl_gem_info_iova(struct drm_device *dev,
* Don't pin the memory here - just get an address so that userspace can
* be productive
*/
return msm_gem_get_iova(obj, msm_context_vm(dev, ctx), iova);
return msm_gem_get_iova(obj, vm, iova);
}
static int msm_ioctl_gem_info_set_iova(struct drm_device *dev,
@@ -450,6 +455,9 @@ static int msm_ioctl_gem_info_set_iova(struct drm_device *dev,
if (!priv->gpu)
return -EINVAL;
if (!vm)
return UERR(ENOMEM, dev, "no VM");
if (msm_context_is_vmbind(ctx))
return UERR(EINVAL, dev, "VM_BIND is enabled");

View File

@@ -261,8 +261,6 @@ const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
struct drm_file *file, const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_framebuffer * msm_alloc_stolen_fb(struct drm_device *dev,
int w, int h, int p, uint32_t format);
#ifdef CONFIG_DRM_MSM_KMS_FBDEV
int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
@@ -356,8 +354,6 @@ void __exit msm_dp_unregister(void);
int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder, bool yuv_supported);
void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display);
bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,
const struct drm_display_mode *mode);
bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
const struct drm_display_mode *mode);
bool msm_dp_wide_bus_available(const struct msm_dp *dp_display);
@@ -382,12 +378,6 @@ static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm
{
}
static inline bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,
const struct drm_display_mode *mode)
{
return false;
}
static inline bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
const struct drm_display_mode *mode)
{
@@ -503,13 +493,6 @@ void msm_hrtimer_work_init(struct msm_hrtimer_work *work,
#define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)
#define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)
static inline int align_pitch(int width, int bpp)
{
int bytespp = (bpp + 7) / 8;
/* adreno needs pitch aligned to 32 pixels: */
return bytespp * ALIGN(width, 32);
}
/* for the generated headers: */
#define INVALID_IDX(idx) ({BUG(); 0;})
#define fui(x) ({BUG(); 0;})

View File

@@ -6,7 +6,6 @@
#include <drm/drm_crtc.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
@@ -29,10 +28,6 @@ struct msm_framebuffer {
};
#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
static int msm_framebuffer_dirtyfb(struct drm_framebuffer *fb,
struct drm_file *file_priv, unsigned int flags,
unsigned int color, struct drm_clip_rect *clips,
@@ -139,39 +134,10 @@ const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb)
return msm_fb->format;
}
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
struct drm_file *file, const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *bos[4] = {0};
struct drm_framebuffer *fb;
int ret, i, n = info->num_planes;
for (i = 0; i < n; i++) {
bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
if (!bos[i]) {
ret = -ENXIO;
goto out_unref;
}
}
fb = msm_framebuffer_init(dev, info, mode_cmd, bos);
if (IS_ERR(fb)) {
ret = PTR_ERR(fb);
goto out_unref;
}
return fb;
out_unref:
for (i = 0; i < n; i++)
drm_gem_object_put(bos[i]);
return ERR_PTR(ret);
}
static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
static struct drm_framebuffer *
msm_framebuffer_init(struct drm_device *dev, const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **bos)
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_kms *kms = priv->kms;
@@ -251,47 +217,33 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
return ERR_PTR(ret);
}
struct drm_framebuffer *
msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format)
struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
struct drm_file *file,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_mode_fb_cmd2 mode_cmd = {
.pixel_format = format,
.width = w,
.height = h,
.pitches = { p },
};
struct drm_gem_object *bo;
struct drm_gem_object *bos[4] = {0};
struct drm_framebuffer *fb;
int size;
int ret, i, n = info->num_planes;
/* allocate backing bo */
size = mode_cmd.pitches[0] * mode_cmd.height;
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC | MSM_BO_STOLEN);
if (IS_ERR(bo)) {
dev_warn(dev->dev, "could not allocate stolen bo\n");
/* try regular bo: */
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
}
if (IS_ERR(bo)) {
DRM_DEV_ERROR(dev->dev, "failed to allocate buffer object\n");
return ERR_CAST(bo);
for (i = 0; i < n; i++) {
bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
if (!bos[i]) {
ret = -ENXIO;
goto out_unref;
}
}
msm_gem_object_set_name(bo, "stolenfb");
fb = msm_framebuffer_init(dev,
drm_get_format_info(dev, mode_cmd.pixel_format,
mode_cmd.modifier[0]),
&mode_cmd, &bo);
fb = msm_framebuffer_init(dev, info, mode_cmd, bos);
if (IS_ERR(fb)) {
DRM_DEV_ERROR(dev->dev, "failed to allocate fb\n");
/* note: if fb creation failed, we can't rely on fb destroy
* to unref the bo:
*/
drm_gem_object_put(bo);
return ERR_CAST(fb);
ret = PTR_ERR(fb);
goto out_unref;
}
return fb;
out_unref:
for (i = 0; i < n; i++)
drm_gem_object_put(bos[i]);
return ERR_PTR(ret);
}

View File

@@ -9,6 +9,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_prime.h>
@@ -40,17 +41,15 @@ static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
static void msm_fbdev_fb_destroy(struct fb_info *info)
{
struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par;
struct drm_framebuffer *fb = helper->fb;
struct drm_gem_object *bo = msm_framebuffer_bo(fb, 0);
struct drm_gem_object *bo = msm_framebuffer_bo(helper->fb, 0);
DBG();
drm_fb_helper_fini(helper);
/* this will free the backing object */
msm_gem_put_vaddr(bo);
drm_framebuffer_remove(fb);
drm_client_buffer_delete(helper->buffer);
drm_client_release(&helper->client);
}
@@ -89,31 +88,54 @@ static const struct drm_fb_helper_funcs msm_fbdev_helper_funcs = {
int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct drm_device *dev = helper->dev;
struct drm_client_dev *client = &helper->client;
struct drm_device *dev = client->dev;
struct drm_file *file = client->file;
struct msm_drm_private *priv = dev->dev_private;
struct fb_info *fbi = helper->info;
struct drm_framebuffer *fb = NULL;
const struct drm_format_info *format;
u32 fourcc, pitch, handle;
u64 size;
struct drm_gem_object *bo;
struct drm_client_buffer *buffer;
uint64_t paddr;
uint32_t format;
int ret, pitch;
format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
int ret;
DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
sizes->surface_height, sizes->surface_bpp,
sizes->fb_width, sizes->fb_height);
pitch = align_pitch(sizes->surface_width, sizes->surface_bpp);
fb = msm_alloc_stolen_fb(dev, sizes->surface_width,
sizes->surface_height, pitch, format);
fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
format = drm_get_format_info(dev, fourcc, DRM_FORMAT_MOD_LINEAR);
/* adreno needs pitch aligned to 32 pixels: */
pitch = drm_format_info_min_pitch(format, 0, ALIGN(sizes->surface_width, 32));
size = ALIGN(pitch * sizes->surface_height, PAGE_SIZE);
if (IS_ERR(fb)) {
DRM_DEV_ERROR(dev->dev, "failed to allocate fb\n");
return PTR_ERR(fb);
/* allocate backing bo */
DBG("allocating %llu bytes for fb %d", size, dev->primary->index);
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC | MSM_BO_STOLEN, NULL);
if (IS_ERR(bo)) {
drm_warn(dev, "could not allocate stolen bo\n");
/* try regular bo: */
bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC, NULL);
if (IS_ERR(bo)) {
drm_err(dev, "failed to allocate buffer object\n");
return PTR_ERR(bo);
}
}
bo = msm_framebuffer_bo(fb, 0);
msm_gem_object_set_name(bo, "stolenfb");
ret = drm_gem_handle_create(file, bo, &handle);
if (ret)
goto err_drm_gem_object_put;
buffer = drm_client_buffer_create(client, sizes->surface_width, sizes->surface_height,
fourcc, handle, pitch);
if (IS_ERR(buffer)) {
ret = PTR_ERR(buffer);
goto err_drm_gem_handle_delete;
}
/*
* NOTE: if we can be guaranteed to be able to map buffer
@@ -122,14 +144,15 @@ int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
*/
ret = msm_gem_get_and_pin_iova(bo, priv->kms->vm, &paddr);
if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to get buffer obj iova: %d\n", ret);
goto fail;
drm_err(dev, "failed to get buffer obj iova: %d\n", ret);
goto err_drm_client_buffer_delete;
}
DBG("fbi=%p, dev=%p", fbi, dev);
helper->funcs = &msm_fbdev_helper_funcs;
helper->fb = fb;
helper->buffer = buffer;
helper->fb = buffer->fb;
fbi->fbops = &msm_fb_ops;
@@ -138,18 +161,31 @@ int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
fbi->screen_buffer = msm_gem_get_vaddr(bo);
if (IS_ERR(fbi->screen_buffer)) {
ret = PTR_ERR(fbi->screen_buffer);
goto fail;
goto err_msm_gem_unpin;
}
fbi->screen_size = bo->size;
fbi->fix.smem_start = paddr;
fbi->fix.smem_len = bo->size;
DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
DBG("allocated %dx%d fb", fb->width, fb->height);
DBG("allocated %dx%d fb", buffer->fb->width, buffer->fb->height);
/* The handle is only needed for creating the framebuffer. */
drm_gem_handle_delete(file, handle);
/* The framebuffer still holds a reference on the GEM object. */
drm_gem_object_put(bo);
return 0;
fail:
drm_framebuffer_remove(fb);
err_msm_gem_unpin:
msm_gem_unpin_iova(bo, priv->kms->vm);
msm_gem_vma_put(bo);
err_drm_client_buffer_delete:
drm_client_buffer_delete(buffer);
err_drm_gem_handle_delete:
drm_gem_handle_delete(file, handle);
err_drm_gem_object_put:
drm_gem_object_put(bo);
return ret;
}

View File

@@ -1093,7 +1093,9 @@ static void msm_gem_free_object(struct drm_gem_object *obj)
*/
kvfree(msm_obj->pages);
drm_prime_gem_destroy(obj, msm_obj->sgt);
/* In msm_gem_import() error path, sgt won't be set yet: */
if (msm_obj->sgt)
drm_prime_gem_destroy(obj, msm_obj->sgt);
} else {
msm_gem_vunmap(obj);
put_pages(obj);
@@ -1134,10 +1136,21 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
size_t size, uint32_t flags, uint32_t *handle,
char *name)
{
struct drm_gem_object *obj;
struct drm_gem_object *obj, *r_obj = NULL;
int ret;
obj = msm_gem_new(dev, size, flags);
if (flags & MSM_BO_NO_SHARE) {
struct msm_drm_private *priv = dev->dev_private;
struct msm_context *ctx = file->driver_priv;
struct drm_gpuvm *vm = msm_context_vm(dev, ctx);
if (!priv->gpu || !vm)
return UERR(EINVAL, dev, "not supported with shared VM");
r_obj = drm_gpuvm_resv_obj(vm);
}
obj = msm_gem_new(dev, size, flags, r_obj);
if (IS_ERR(obj))
return PTR_ERR(obj);
@@ -1145,15 +1158,6 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
if (name)
msm_gem_object_set_name(obj, "%s", name);
if (flags & MSM_BO_NO_SHARE) {
struct msm_context *ctx = file->driver_priv;
struct drm_gem_object *r_obj = drm_gpuvm_resv_obj(ctx->vm);
drm_gem_object_get(r_obj);
obj->resv = r_obj->resv;
}
ret = drm_gem_handle_create(file, obj, handle);
/* drop reference from allocate - handle holds it now */
@@ -1232,10 +1236,27 @@ static int msm_gem_new_impl(struct drm_device *dev, uint32_t flags,
return 0;
}
struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t flags)
static int msm_gem_init_bookkeeping(struct drm_gem_object *obj)
{
struct msm_drm_private *priv = obj->dev->dev_private;
if (drm_gem_is_imported(obj)) {
drm_gem_lru_move_tail(&priv->lru.pinned, obj);
} else {
drm_gem_lru_move_tail(&priv->lru.unbacked, obj);
}
mutex_lock(&priv->obj_lock);
list_add_tail(&to_msm_bo(obj)->node, &priv->objects);
mutex_unlock(&priv->obj_lock);
return drm_gem_create_mmap_offset(obj);
}
struct drm_gem_object *
msm_gem_new(struct drm_device *dev, size_t size, uint32_t flags,
struct drm_gem_object *r_obj)
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_gem_object *msm_obj;
struct drm_gem_object *obj = NULL;
int ret;
@@ -1251,7 +1272,10 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t
if (ret)
return ERR_PTR(ret);
msm_obj = to_msm_bo(obj);
if (flags & MSM_BO_NO_SHARE) {
drm_gem_object_get(r_obj);
obj->resv = r_obj->resv;
}
ret = drm_gem_object_init(dev, obj, size);
if (ret)
@@ -1264,13 +1288,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t
*/
mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER);
drm_gem_lru_move_tail(&priv->lru.unbacked, obj);
mutex_lock(&priv->obj_lock);
list_add_tail(&msm_obj->node, &priv->objects);
mutex_unlock(&priv->obj_lock);
ret = drm_gem_create_mmap_offset(obj);
ret = msm_gem_init_bookkeeping(obj);
if (ret)
goto fail;
@@ -1282,11 +1300,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, size_t size, uint32_t
}
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
struct dma_buf *dmabuf, struct sg_table *sgt)
struct dma_buf_attachment *attach,
struct sg_table *sgt)
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_gem_object *msm_obj;
struct drm_gem_object *obj;
struct dma_buf *dmabuf = attach->dmabuf;
size_t size, npages;
int ret;
@@ -1296,38 +1315,35 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
if (ret)
return ERR_PTR(ret);
/*
* Set import_attach here in case we hit an error path that ends
* up in drm_gem_object_put() -> msm_gem_free_object()
*/
obj->import_attach = attach;
obj->resv = dmabuf->resv;
drm_gem_private_object_init(dev, obj, size);
npages = size / PAGE_SIZE;
msm_obj = to_msm_bo(obj);
msm_gem_lock(obj);
msm_obj->sgt = sgt;
msm_obj->pages = kvmalloc_objs(struct page *, npages);
if (!msm_obj->pages) {
msm_gem_unlock(obj);
ret = -ENOMEM;
goto fail;
}
ret = drm_prime_sg_to_page_array(sgt, msm_obj->pages, npages);
if (ret) {
msm_gem_unlock(obj);
goto fail;
}
msm_gem_unlock(obj);
drm_gem_lru_move_tail(&priv->lru.pinned, obj);
mutex_lock(&priv->obj_lock);
list_add_tail(&msm_obj->node, &priv->objects);
mutex_unlock(&priv->obj_lock);
ret = drm_gem_create_mmap_offset(obj);
ret = msm_gem_init_bookkeeping(obj);
if (ret)
goto fail;
/* Now that we are past potential failure points, set sgt: */
msm_obj->sgt = sgt;
return obj;
fail:
@@ -1340,7 +1356,7 @@ void *msm_gem_kernel_new(struct drm_device *dev, size_t size, uint32_t flags,
uint64_t *iova)
{
void *vaddr;
struct drm_gem_object *obj = msm_gem_new(dev, size, flags);
struct drm_gem_object *obj = msm_gem_new(dev, size, flags, NULL);
int ret;
if (IS_ERR(obj))

View File

@@ -296,13 +296,14 @@ int msm_gem_cpu_fini(struct drm_gem_object *obj);
int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
size_t size, uint32_t flags, uint32_t *handle, char *name);
struct drm_gem_object *msm_gem_new(struct drm_device *dev,
size_t size, uint32_t flags);
size_t size, uint32_t flags, struct drm_gem_object *r_obj);
void *msm_gem_kernel_new(struct drm_device *dev, size_t size, uint32_t flags,
struct drm_gpuvm *vm, struct drm_gem_object **bo,
uint64_t *iova);
void msm_gem_kernel_put(struct drm_gem_object *bo, struct drm_gpuvm *vm);
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
struct dma_buf *dmabuf, struct sg_table *sgt);
struct dma_buf_attachment *attach,
struct sg_table *sgt);
__printf(2, 3)
void msm_gem_object_set_name(struct drm_gem_object *bo, const char *fmt, ...);

View File

@@ -83,7 +83,7 @@ struct drm_gem_object *msm_gem_prime_import(struct drm_device *dev,
struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct sg_table *sg)
{
return msm_gem_import(dev, attach->dmabuf, sg);
return msm_gem_import(dev, attach, sg);
}
struct dma_buf *msm_gem_prime_export(struct drm_gem_object *obj, int flags)

View File

@@ -30,20 +30,17 @@
*/
static struct msm_gem_submit *submit_create(struct drm_device *dev,
struct msm_gpu *gpu,
struct msm_gpu *gpu, struct drm_gpuvm *vm,
struct msm_gpu_submitqueue *queue, uint32_t nr_bos,
uint32_t nr_cmds, u64 drm_client_id)
{
static atomic_t ident = ATOMIC_INIT(0);
struct msm_gem_submit *submit;
uint64_t sz;
size_t sz;
int ret;
sz = struct_size(submit, bos, nr_bos) +
((u64)nr_cmds * sizeof(submit->cmd[0]));
if (sz > SIZE_MAX)
return ERR_PTR(-ENOMEM);
sz = size_add(struct_size(submit, bos, nr_bos),
array_size(sizeof(submit->cmd[0]), nr_cmds));
submit = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN);
if (!submit)
@@ -66,7 +63,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
kref_init(&submit->ref);
submit->dev = dev;
submit->vm = msm_context_vm(dev, queue->ctx);
submit->vm = vm;
submit->gpu = gpu;
submit->cmd = (void *)&submit->bos[nr_bos];
submit->queue = queue;
@@ -250,16 +247,14 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit,
sz = array_size(submit_cmd.nr_relocs,
sizeof(struct drm_msm_gem_submit_reloc));
/* check for overflow: */
if (sz == SIZE_MAX) {
ret = -ENOMEM;
goto out;
}
submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL | __GFP_NOWARN);
if (!submit->cmd[i].relocs) {
ret = -ENOMEM;
goto out;
}
submit->nr_cmds = i + 1;
ret = copy_from_user(submit->cmd[i].relocs, userptr, sz);
if (ret) {
ret = -EFAULT;
@@ -554,6 +549,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
struct msm_drm_private *priv = dev->dev_private;
struct drm_msm_gem_submit *args = data;
struct msm_context *ctx = file->driver_priv;
struct drm_gpuvm *vm = msm_context_vm(dev, ctx);
struct msm_gem_submit *submit = NULL;
struct msm_gpu *gpu = priv->gpu;
struct msm_gpu_submitqueue *queue;
@@ -569,10 +565,13 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
if (!gpu)
return -ENXIO;
if (!vm)
return UERR(ENOMEM, dev, "no VM");
if (args->pad)
return -EINVAL;
if (to_msm_vm(ctx->vm)->unusable)
if (to_msm_vm(vm)->unusable)
return UERR(EPIPE, dev, "context is unusable");
/* for now, we just have 3d pipe.. eventually this would need to
@@ -609,7 +608,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
}
}
submit = submit_create(dev, gpu, queue, args->nr_bos, args->nr_cmds,
submit = submit_create(dev, gpu, vm, queue, args->nr_bos, args->nr_cmds,
file->client_id);
if (IS_ERR(submit)) {
ret = PTR_ERR(submit);
@@ -719,8 +718,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
goto out;
}
submit->nr_cmds = args->nr_cmds;
idr_preload(GFP_KERNEL);
spin_lock(&queue->idr_lock);

View File

@@ -458,6 +458,8 @@ msm_gem_vm_bo_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
return ret;
}
drm_gpuvm_bo_evict(vm_bo, false);
return 0;
}
@@ -955,7 +957,7 @@ msm_gem_vm_close(struct drm_gpuvm *gpuvm)
static struct msm_vm_bind_job *
vm_bind_job_create(struct drm_device *dev, struct drm_file *file,
vm_bind_job_create(struct drm_device *dev, struct drm_file *file, struct drm_gpuvm *vm,
struct msm_gpu_submitqueue *queue, uint32_t nr_ops)
{
struct msm_vm_bind_job *job;
@@ -972,7 +974,7 @@ vm_bind_job_create(struct drm_device *dev, struct drm_file *file,
return ERR_PTR(ret);
}
job->vm = msm_context_vm(dev, queue->ctx);
job->vm = vm;
job->queue = queue;
INIT_LIST_HEAD(&job->vm_ops);
@@ -1431,6 +1433,7 @@ msm_ioctl_vm_bind(struct drm_device *dev, void *data, struct drm_file *file)
struct msm_drm_private *priv = dev->dev_private;
struct drm_msm_vm_bind *args = data;
struct msm_context *ctx = file->driver_priv;
struct drm_gpuvm *vm = msm_context_vm(dev, ctx);
struct msm_vm_bind_job *job = NULL;
struct msm_gpu *gpu = priv->gpu;
struct msm_gpu_submitqueue *queue;
@@ -1445,11 +1448,14 @@ msm_ioctl_vm_bind(struct drm_device *dev, void *data, struct drm_file *file)
if (!gpu)
return -ENXIO;
if (!vm)
return UERR(ENOMEM, dev, "no VM");
/*
* Maybe we could allow just UNMAP ops? OTOH userspace should just
* immediately close the device file and all will be torn down.
*/
if (to_msm_vm(msm_context_vm(dev, ctx))->unusable)
if (to_msm_vm(vm)->unusable)
return UERR(EPIPE, dev, "context is unusable");
/*
@@ -1480,7 +1486,7 @@ msm_ioctl_vm_bind(struct drm_device *dev, void *data, struct drm_file *file)
}
}
job = vm_bind_job_create(dev, file, queue, args->nr_ops);
job = vm_bind_job_create(dev, file, vm, queue, args->nr_ops);
if (IS_ERR(job)) {
ret = PTR_ERR(job);
goto out_post_unlock;

View File

@@ -505,6 +505,8 @@ static void recover_worker(struct kthread_work *work)
*/
if (!vm->managed)
msm_gem_vm_unusable(submit->vm);
put_task_struct(task);
}
noreclaim_flag = memalloc_noreclaim_save();
@@ -552,11 +554,13 @@ static void recover_worker(struct kthread_work *work)
msm_update_fence(ring->fctx, fence);
}
/* retire completed submits, plus the one that hung: */
retire_submits(gpu);
priv->disable_err_irq = false;
gpu->funcs->recover(gpu);
/* retire completed submits, plus the one that hung: */
retire_submits(gpu);
/*
* Replay all remaining submits starting with highest priority
* ring
@@ -875,7 +879,7 @@ msm_gpu_create_private_vm(struct msm_gpu *gpu, struct task_struct *task,
to_msm_vm(vm)->pid = get_pid(task_pid(task));
}
if (IS_ERR_OR_NULL(vm))
if (IS_ERR_OR_NULL(vm) && kernel_managed)
vm = drm_gpuvm_get(gpu->vm);
return vm;

View File

@@ -392,8 +392,8 @@ msm_gpu_sysprof_no_ifpc(struct msm_gpu *gpu)
* struct msm_context - per-drm_file context
*/
struct msm_context {
/** @queuelock: synchronizes access to submitqueues list */
rwlock_t queuelock;
/** @ctxlock: synchronizes access to submitqueues list, etc */
struct rw_semaphore ctxlock;
/** @submitqueues: list of &msm_gpu_submitqueue created by userspace */
struct list_head submitqueues;
/**

View File

@@ -7,6 +7,15 @@
#include <linux/adreno-smmu-priv.h>
#include <linux/io-pgtable.h>
#include <linux/kmemleak.h>
#if defined(CONFIG_ARM_DMA_USE_IOMMU)
#include <asm/dma-iommu.h>
#else
#define arm_iommu_detach_device(...) ({ })
#define arm_iommu_release_mapping(...) ({ })
#define to_dma_iommu_mapping(dev) NULL
#endif
#include "msm_drv.h"
#include "msm_gpu_trace.h"
#include "msm_mmu.h"
@@ -749,6 +758,19 @@ struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks)
mutex_init(&iommu->init_lock);
/*
* ARM32 attaches a DMA mapping domain to every IOMMU-backed device,
* which would make attaching our own domain fail with -EBUSY.
*/
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
if (mapping) {
arm_iommu_detach_device(dev);
arm_iommu_release_mapping(mapping);
}
}
ret = iommu_attach_device(iommu->domain, dev);
if (ret) {
iommu_domain_free(domain);

View File

@@ -109,9 +109,9 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
ring->memptrs_iova = memptrs_iova;
ret = drm_sched_init(&ring->sched, &args);
if (ret) {
if (ret)
goto fail;
}
ring->sched_initialized = true;
INIT_LIST_HEAD(&ring->submits);
spin_lock_init(&ring->submit_lock);
@@ -133,7 +133,8 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring)
if (IS_ERR_OR_NULL(ring))
return;
drm_sched_fini(&ring->sched);
if (ring->sched_initialized)
drm_sched_fini(&ring->sched);
msm_fence_context_free(ring->fctx);

View File

@@ -56,6 +56,7 @@ struct msm_ringbuffer {
* The job scheduler for this ring.
*/
struct drm_gpu_scheduler sched;
bool sched_initialized;
/*
* List of in-flight submits on this ring. Protected by submit_lock.

View File

@@ -9,6 +9,8 @@
int msm_context_set_sysprof(struct msm_context *ctx, struct msm_gpu *gpu, int sysprof)
{
guard(rwsem_write)(&ctx->ctxlock);
/*
* Since pm_runtime and sysprof_active are both refcounts, we
* call apply the new value first, and then unwind the previous
@@ -93,18 +95,15 @@ struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_context *ctx,
if (!ctx)
return NULL;
read_lock(&ctx->queuelock);
guard(rwsem_read)(&ctx->ctxlock);
list_for_each_entry(entry, &ctx->submitqueues, node) {
if (entry->id == id) {
kref_get(&entry->ref);
read_unlock(&ctx->queuelock);
return entry;
}
}
read_unlock(&ctx->queuelock);
return NULL;
}
@@ -175,6 +174,7 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
struct msm_drm_private *priv = drm->dev_private;
struct msm_gpu_submitqueue *queue;
enum drm_sched_priority sched_prio;
struct drm_gpuvm *vm = NULL;
unsigned ring_nr;
int ret;
@@ -187,6 +187,11 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
if (flags & MSM_SUBMITQUEUE_VM_BIND) {
unsigned sz;
vm = msm_context_vm(drm, ctx);
if (!vm)
return UERR(ENOMEM, drm, "no VM");
/* Not allowed for kernel managed VMs (ie. kernel allocs VA) */
if (!msm_context_is_vmbind(ctx))
return -EINVAL;
@@ -218,7 +223,7 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
queue->flags = flags;
if (flags & MSM_SUBMITQUEUE_VM_BIND) {
struct drm_gpu_scheduler *sched = &to_msm_vm(msm_context_vm(drm, ctx))->sched;
struct drm_gpu_scheduler *sched = &to_msm_vm(vm)->sched;
queue->entity = &queue->_vm_bind_entity[0];
@@ -237,7 +242,7 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
return ret;
}
write_lock(&ctx->queuelock);
guard(rwsem_write)(&ctx->ctxlock);
queue->ctx = msm_context_get(ctx);
queue->id = ctx->queueid++;
@@ -251,8 +256,6 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
list_add_tail(&queue->node, &ctx->submitqueues);
write_unlock(&ctx->queuelock);
return 0;
}
@@ -335,19 +338,16 @@ int msm_submitqueue_remove(struct msm_context *ctx, u32 id)
if (!id)
return -ENOENT;
write_lock(&ctx->queuelock);
guard(rwsem_write)(&ctx->ctxlock);
list_for_each_entry(entry, &ctx->submitqueues, node) {
if (entry->id == id) {
list_del(&entry->node);
write_unlock(&ctx->queuelock);
msm_submitqueue_put(entry);
return 0;
}
}
write_unlock(&ctx->queuelock);
return -ENOENT;
}

View File

@@ -1495,6 +1495,8 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
<reg32 offset="0x3058" name="VBIF_OUT_AXI_AMEMTYPE_CONF0"/>
<reg32 offset="0x305e" name="VBIF_OUT_AXI_AOOO_EN"/>
<reg32 offset="0x305f" name="VBIF_OUT_AXI_AOOO"/>
<reg32 offset="0x3080" name="VBIF_XIN_HALT_CTRL0"/>
<reg32 offset="0x3081" name="VBIF_XIN_HALT_CTRL1"/>
<bitset name="a3xx_vbif_perf_cnt" inline="yes">
<bitfield name="CNT0" pos="0" type="boolean"/>

View File

@@ -1268,7 +1268,7 @@ by a particular renderpass/blit.
<reg32 offset="0x3119" name="VBIF_PERF_PWR_CNT_HIGH1" variants="A6XX"/>
<reg32 offset="0x311a" name="VBIF_PERF_PWR_CNT_HIGH2" variants="A6XX"/>
<reg32 offset="0x3c00" name="GBIF_CX_CONFIG" variants="A8XX-"/>
<reg32 offset="0x3c00" name="GBIF_CX_CONFIG" variants="A6XX-"/>
<reg32 offset="0x3c01" name="GBIF_SCACHE_CNTL0"/>
<reg32 offset="0x3c02" name="GBIF_SCACHE_CNTL1"/>
<reg32 offset="0x3c03" name="GBIF_QSB_SIDE0"/>

View File

@@ -228,7 +228,7 @@ struct drm_msm_gem_cpu_fini {
struct drm_msm_syncobj {
__u32 handle; /* in, syncobj handle. */
__u32 flags; /* in, from MSM_SUBMIT_SYNCOBJ_FLAGS */
__u32 flags; /* in, from MSM_SYNCOBJ_FLAGS */
__u64 point; /* in, timepoint for timeline syncobjs. */
};
@@ -393,9 +393,9 @@ struct drm_msm_vm_bind {
__s32 fence_fd;
/** @queue_id: in, submitqueue id */
__u32 queue_id;
/** @in_syncobjs: in, ptr to array of drm_msm_gem_syncobj */
/** @in_syncobjs: in, ptr to array of drm_msm_syncobj */
__u64 in_syncobjs;
/** @out_syncobjs: in, ptr to array of drm_msm_gem_syncobj */
/** @out_syncobjs: in, ptr to array of drm_msm_syncobj */
__u64 out_syncobjs;
/** @nr_in_syncobjs: in, number of entries in in_syncobj */
__u32 nr_in_syncobjs;