Commit 1f8c29e8 authored by Konrad Dybcio's avatar Konrad Dybcio Committed by Rob Clark
Browse files

drm/msm/a6xx: Add A740 support



A740 builds upon the A730 IP, shuffling some values and registers
around. More differences will appear when things like BCL are
implemented.

adreno_is_a740_family is added in preparation for more A7xx GPUs,
the logic checks will be valid resulting in smaller diffs.

Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> # sm8450
Signed-off-by: default avatarKonrad Dybcio <konrad.dybcio@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/559291/


Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 9588d2f8
Loading
Loading
Loading
Loading
+61 −27
Original line number Diff line number Diff line
@@ -519,6 +519,7 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
	struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
	struct platform_device *pdev = to_platform_device(gmu->dev);
	void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc");
	u32 seqmem0_drv0_reg = REG_A6XX_RSCC_SEQ_MEM_0_DRV0;
	void __iomem *seqptr = NULL;
	uint32_t pdc_address_offset;
	bool pdc_in_aop = false;
@@ -552,21 +553,26 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu)
	gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0);
	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, 0x80000000);
	gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 4,
		       adreno_is_a740_family(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);
	gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510);
	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))
		seqmem0_drv0_reg = REG_A7XX_RSCC_SEQ_MEM_0_DRV0_A740;

	/* Load RSC sequencer uCode for sleep and wakeup */
	if (adreno_is_a650_family(adreno_gpu) ||
	    adreno_is_a7xx(adreno_gpu)) {
		gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0, 0xeaaae5a0);
		gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xe1a1ebab);
		gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xa2e0a581);
		gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xecac82e2);
		gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020edad);
		gmu_write_rscc(gmu, seqmem0_drv0_reg, 0xeaaae5a0);
		gmu_write_rscc(gmu, seqmem0_drv0_reg + 1, 0xe1a1ebab);
		gmu_write_rscc(gmu, seqmem0_drv0_reg + 2, 0xa2e0a581);
		gmu_write_rscc(gmu, seqmem0_drv0_reg + 3, 0xecac82e2);
		gmu_write_rscc(gmu, seqmem0_drv0_reg + 4, 0x0020edad);
	} else {
		gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0, 0xa7a506a0);
		gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xa1e6a6e7);
@@ -764,8 +770,8 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
	struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
	struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
	u32 fence_range_lower, fence_range_upper;
	u32 chipid, chipid_min = 0;
	int ret;
	u32 chipid;

	/* Vote veto for FAL10 */
	if (adreno_is_a650_family(adreno_gpu) || adreno_is_a7xx(adreno_gpu)) {
@@ -824,6 +830,26 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
	 */
	gmu_write(gmu, REG_A6XX_GMU_CM3_CFG, 0x4052);

	/* NOTE: A730 may also fall in this if-condition with a future GMU fw update. */
	if (adreno_is_a7xx(adreno_gpu) && !adreno_is_a730(adreno_gpu)) {
		/* A7xx GPUs have obfuscated chip IDs. Use constant maj = 7 */
		chipid = FIELD_PREP(GENMASK(31, 24), 0x7);

		/*
		 * The min part has a 1-1 mapping for each GPU SKU.
		 * This chipid that the GMU expects corresponds to the "GENX_Y_Z" naming,
		 * where X = major, Y = minor, Z = patchlevel, e.g. GEN7_2_1 for prod A740.
		 */
		if (adreno_is_a740(adreno_gpu))
			chipid_min = 2;
		else
			return -EINVAL;

		chipid |= FIELD_PREP(GENMASK(23, 16), chipid_min);

		/* Get the patchid (which may vary) from the device tree */
		chipid |= FIELD_PREP(GENMASK(15, 8), adreno_patchid(adreno_gpu));
	} else {
		/*
		 * Note that the GMU has a slightly different layout for
		 * chip_id, for whatever reason, so a bit of massaging
@@ -834,6 +860,7 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
		chipid  = adreno_gpu->chip_id & 0xffff0000;
		chipid |= (adreno_gpu->chip_id << 4) & 0xf000; /* minor */
		chipid |= (adreno_gpu->chip_id << 8) & 0x0f00; /* patchid */
	}

	if (adreno_is_a7xx(adreno_gpu)) {
		gmu_write(gmu, REG_A6XX_GMU_GENERAL_10, chipid);
@@ -896,17 +923,23 @@ static void a6xx_gmu_irq_disable(struct a6xx_gmu *gmu)

static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
{
	u32 val;
	struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
	struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
	u32 val, seqmem_off = 0;

	/* The second spin of A7xx GPUs messed with some register offsets.. */
	if (adreno_is_a740_family(adreno_gpu))
		seqmem_off = 4;

	/* Make sure there are no outstanding RPMh votes */
	gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS0_DRV0_STATUS, val,
		(val & 1), 100, 10000);
	gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS1_DRV0_STATUS, val,
		(val & 1), 100, 10000);
	gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS2_DRV0_STATUS, val,
		(val & 1), 100, 10000);
	gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS, val,
		(val & 1), 100, 1000);
	gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS0_DRV0_STATUS + seqmem_off,
		val, (val & 1), 100, 10000);
	gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS1_DRV0_STATUS + seqmem_off,
		val, (val & 1), 100, 10000);
	gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS2_DRV0_STATUS + seqmem_off,
		val, (val & 1), 100, 10000);
	gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS + seqmem_off,
		val, (val & 1), 100, 1000);
}

/* Force the GMU off in case it isn't responsive */
@@ -1010,7 +1043,8 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)

	/* Use a known rate to bring up the GMU */
	clk_set_rate(gmu->core_clk, 200000000);
	clk_set_rate(gmu->hub_clk, 150000000);
	clk_set_rate(gmu->hub_clk, adreno_is_a740_family(adreno_gpu) ?
		     200000000 : 150000000);
	ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks);
	if (ret) {
		pm_runtime_put(gmu->gxpd);
+74 −8
Original line number Diff line number Diff line
@@ -894,6 +894,64 @@ const struct adreno_reglist a730_hwcg[] = {
	{},
};

const struct adreno_reglist a740_hwcg[] = {
	{ REG_A6XX_RBBM_CLOCK_CNTL_SP0, 0x02222222 },
	{ REG_A6XX_RBBM_CLOCK_CNTL2_SP0, 0x22022222 },
	{ REG_A6XX_RBBM_CLOCK_HYST_SP0, 0x003cf3cf },
	{ 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_CNTL4_TP0, 0x00222222 },
	{ REG_A6XX_RBBM_CLOCK_HYST_TP0, 0x77777777 },
	{ REG_A6XX_RBBM_CLOCK_HYST2_TP0, 0x77777777 },
	{ REG_A6XX_RBBM_CLOCK_HYST3_TP0, 0x77777777 },
	{ REG_A6XX_RBBM_CLOCK_HYST4_TP0, 0x00077777 },
	{ REG_A6XX_RBBM_CLOCK_DELAY_TP0, 0x11111111 },
	{ REG_A6XX_RBBM_CLOCK_DELAY2_TP0, 0x11111111 },
	{ REG_A6XX_RBBM_CLOCK_DELAY3_TP0, 0x11111111 },
	{ REG_A6XX_RBBM_CLOCK_DELAY4_TP0, 0x00011111 },
	{ REG_A6XX_RBBM_CLOCK_CNTL_UCHE, 0x22222222 },
	{ REG_A6XX_RBBM_CLOCK_CNTL2_UCHE, 0x00222222 },
	{ REG_A6XX_RBBM_CLOCK_HYST_UCHE, 0x00000444 },
	{ REG_A6XX_RBBM_CLOCK_DELAY_UCHE, 0x00000222 },
	{ REG_A6XX_RBBM_CLOCK_CNTL_RB0, 0x22222222 },
	{ REG_A6XX_RBBM_CLOCK_CNTL2_RB0, 0x01002222 },
	{ REG_A6XX_RBBM_CLOCK_CNTL_CCU0, 0x00002220 },
	{ REG_A6XX_RBBM_CLOCK_HYST_RB_CCU0, 0x44000f00 },
	{ REG_A6XX_RBBM_CLOCK_CNTL_RAC, 0x25222022 },
	{ REG_A6XX_RBBM_CLOCK_CNTL2_RAC, 0x00555555 },
	{ REG_A6XX_RBBM_CLOCK_DELAY_RAC, 0x00000011 },
	{ REG_A6XX_RBBM_CLOCK_HYST_RAC, 0x00440044 },
	{ REG_A6XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM, 0x04222222 },
	{ REG_A7XX_RBBM_CLOCK_MODE2_GRAS, 0x00000222 },
	{ REG_A7XX_RBBM_CLOCK_MODE_BV_GRAS, 0x00222222 },
	{ REG_A6XX_RBBM_CLOCK_MODE_GPC, 0x02222223 },
	{ REG_A6XX_RBBM_CLOCK_MODE_VFD, 0x00222222 },
	{ REG_A7XX_RBBM_CLOCK_MODE_BV_GPC, 0x00222222 },
	{ REG_A7XX_RBBM_CLOCK_MODE_BV_VFD, 0x00002222 },
	{ REG_A6XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00000000 },
	{ REG_A6XX_RBBM_CLOCK_HYST_GPC, 0x04104004 },
	{ REG_A6XX_RBBM_CLOCK_HYST_VFD, 0x00000000 },
	{ REG_A6XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00000000 },
	{ REG_A6XX_RBBM_CLOCK_DELAY_GPC, 0x00000200 },
	{ REG_A6XX_RBBM_CLOCK_DELAY_VFD, 0x00000000 },
	{ REG_A6XX_RBBM_CLOCK_MODE_HLSQ, 0x00002222 },
	{ REG_A6XX_RBBM_CLOCK_DELAY_HLSQ, 0x00000000 },
	{ REG_A6XX_RBBM_CLOCK_HYST_HLSQ, 0x00000000 },
	{ REG_A7XX_RBBM_CLOCK_MODE_BV_LRZ, 0x55555552 },
	{ REG_A7XX_RBBM_CLOCK_HYST2_VFD, 0x00000000 },
	{ REG_A7XX_RBBM_CLOCK_MODE_CP, 0x00000222 },
	{ REG_A6XX_RBBM_CLOCK_CNTL, 0x8aa8aa82 },
	{ REG_A6XX_RBBM_ISDB_CNT, 0x00000182 },
	{ REG_A6XX_RBBM_RAC_THRESHOLD_CNT, 0x00000000 },
	{ REG_A6XX_RBBM_SP_HYST_CNT, 0x00000000 },
	{ REG_A6XX_RBBM_CLOCK_CNTL_GMU_GX, 0x00000222 },
	{ REG_A6XX_RBBM_CLOCK_DELAY_GMU_GX, 0x00000111 },
	{ REG_A6XX_RBBM_CLOCK_HYST_GMU_GX, 0x00000555 },
	{},
};

static void a6xx_set_hwcg(struct msm_gpu *gpu, bool state)
{
	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -901,7 +959,7 @@ static void a6xx_set_hwcg(struct msm_gpu *gpu, bool state)
	struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
	const struct adreno_reglist *reg;
	unsigned int i;
	u32 val, clock_cntl_on;
	u32 val, clock_cntl_on, cgc_mode;

	if (!adreno_gpu->info->hwcg)
		return;
@@ -914,8 +972,10 @@ static void a6xx_set_hwcg(struct msm_gpu *gpu, bool state)
		clock_cntl_on = 0x8aa8aa82;

	if (adreno_is_a7xx(adreno_gpu)) {
		cgc_mode = adreno_is_a740_family(adreno_gpu) ? 0x20222 : 0x20000;

		gmu_write(&a6xx_gpu->gmu, REG_A6XX_GPU_GMU_AO_GMU_CGC_MODE_CNTL,
			  state ? 0x20000 : 0);
			  state ? cgc_mode : 0);
		gmu_write(&a6xx_gpu->gmu, REG_A6XX_GPU_GMU_AO_GMU_CGC_DELAY_CNTL,
			  state ? 0x10111 : 0);
		gmu_write(&a6xx_gpu->gmu, REG_A6XX_GPU_GMU_AO_GMU_CGC_HYST_CNTL,
@@ -1179,7 +1239,7 @@ static void a6xx_set_cp_protect(struct msm_gpu *gpu)
		count = ARRAY_SIZE(a660_protect);
		count_max = 48;
		BUILD_BUG_ON(ARRAY_SIZE(a660_protect) > 48);
	} else if (adreno_is_a730(adreno_gpu)) {
	} else if (adreno_is_a730(adreno_gpu) || adreno_is_a740(adreno_gpu)) {
		regs = a730_protect;
		count = ARRAY_SIZE(a730_protect);
		count_max = 48;
@@ -1252,7 +1312,8 @@ static void a6xx_set_ubwc_config(struct msm_gpu *gpu)

	if (adreno_is_a650(adreno_gpu) ||
	    adreno_is_a660(adreno_gpu) ||
	    adreno_is_a730(adreno_gpu)) {
	    adreno_is_a730(adreno_gpu) ||
	    adreno_is_a740_family(adreno_gpu)) {
		/* TODO: get ddr type from bootloader and use 2 for LPDDR4 */
		hbb_lo = 3;
		amsbc = 1;
@@ -1545,6 +1606,7 @@ static int hw_init(struct msm_gpu *gpu)
	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
	struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
	u64 gmem_range_min;
	int ret;

	if (!adreno_has_gmu_wrapper(adreno_gpu)) {
@@ -1635,11 +1697,13 @@ static int hw_init(struct msm_gpu *gpu)

	if (!(adreno_is_a650_family(adreno_gpu) ||
	      adreno_is_a730(adreno_gpu))) {
		gmem_range_min = adreno_is_a740_family(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, 0x00100000);
		gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN, gmem_range_min);

		gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MAX,
			0x00100000 + adreno_gpu->info->gmem - 1);
			gmem_range_min + adreno_gpu->info->gmem - 1);
	}

	if (adreno_is_a7xx(adreno_gpu))
@@ -1704,7 +1768,8 @@ static int hw_init(struct msm_gpu *gpu)
	a6xx_set_ubwc_config(gpu);

	/* Enable fault detection */
	if (adreno_is_a730(adreno_gpu))
	if (adreno_is_a730(adreno_gpu) ||
	    adreno_is_a740_family(adreno_gpu))
		gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0xcfffff);
	else if (adreno_is_a619(adreno_gpu))
		gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0x3fffff);
@@ -2796,7 +2861,8 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
		!!(config->info->quirks & ADRENO_QUIRK_HAS_HW_APRIV);

	/* gpu->info only gets assigned in adreno_gpu_init() */
	is_a7xx = config->info->family == ADRENO_7XX_GEN1;
	is_a7xx = config->info->family == ADRENO_7XX_GEN1 ||
		  config->info->family == ADRENO_7XX_GEN2;

	a6xx_llc_slices_init(pdev, a6xx_gpu, is_a7xx);

+27 −0
Original line number Diff line number Diff line
@@ -565,6 +565,31 @@ static void a730_build_bw_table(struct a6xx_hfi_msg_bw_table *msg)
	msg->cnoc_cmds_data[1][0] = 0x60000001;
}

static void a740_build_bw_table(struct a6xx_hfi_msg_bw_table *msg)
{
	msg->bw_level_num = 1;

	msg->ddr_cmds_num = 3;
	msg->ddr_wait_bitmask = 0x7;

	msg->ddr_cmds_addrs[0] = cmd_db_read_addr("SH0");
	msg->ddr_cmds_addrs[1] = cmd_db_read_addr("MC0");
	msg->ddr_cmds_addrs[2] = cmd_db_read_addr("ACV");

	msg->ddr_cmds_data[0][0] = 0x40000000;
	msg->ddr_cmds_data[0][1] = 0x40000000;
	msg->ddr_cmds_data[0][2] = 0x40000000;

	/* TODO: add a proper dvfs table */

	msg->cnoc_cmds_num = 1;
	msg->cnoc_wait_bitmask = 0x1;

	msg->cnoc_cmds_addrs[0] = cmd_db_read_addr("CN0");
	msg->cnoc_cmds_data[0][0] = 0x40000000;
	msg->cnoc_cmds_data[1][0] = 0x60000001;
}

static void a6xx_build_bw_table(struct a6xx_hfi_msg_bw_table *msg)
{
	/* Send a single "off" entry since the 630 GMU doesn't do bus scaling */
@@ -625,6 +650,8 @@ static int a6xx_hfi_send_bw_table(struct a6xx_gmu *gmu)
		a690_build_bw_table(&msg);
	else if (adreno_is_a730(adreno_gpu))
		a730_build_bw_table(&msg);
	else if (adreno_is_a740_family(adreno_gpu))
		a740_build_bw_table(&msg);
	else
		a6xx_build_bw_table(&msg);

+17 −0
Original line number Diff line number Diff line
@@ -499,10 +499,27 @@ static const struct adreno_info gpulist[] = {
		},
		.gmem = SZ_2M,
		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
		.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
			  ADRENO_QUIRK_HAS_HW_APRIV,
		.init = a6xx_gpu_init,
		.zapfw = "a730_zap.mdt",
		.hwcg = a730_hwcg,
		.address_space_size = SZ_16G,
	}, {
		.chip_ids = ADRENO_CHIP_IDS(0x43050a01), /* "C510v2" */
		.family = ADRENO_7XX_GEN2,
		.fw = {
			[ADRENO_FW_SQE] = "a740_sqe.fw",
			[ADRENO_FW_GMU] = "gmu_gen70200.bin",
		},
		.gmem = 3 * SZ_1M,
		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
		.quirks = ADRENO_QUIRK_HAS_CACHED_COHERENT |
			  ADRENO_QUIRK_HAS_HW_APRIV,
		.init = a6xx_gpu_init,
		.zapfw = "a740_zap.mdt",
		.hwcg = a740_hwcg,
		.address_space_size = SZ_16G,
	},
};

+5 −1
Original line number Diff line number Diff line
@@ -323,7 +323,11 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_file_private *ctx,
		*value = adreno_gpu->info->gmem;
		return 0;
	case MSM_PARAM_GMEM_BASE:
		*value = !adreno_is_a650_family(adreno_gpu) ? 0x100000 : 0;
		if (adreno_is_a650_family(adreno_gpu) ||
		    adreno_is_a740_family(adreno_gpu))
			*value = 0;
		else
			*value = 0x100000;
		return 0;
	case MSM_PARAM_CHIP_ID:
		*value = adreno_gpu->chip_id;
Loading