Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cad1c57a authored by Ananta Kishore K's avatar Ananta Kishore K
Browse files

msm: kgsl: Add support for iommu V2 programming for A4xx



Add GPU self programming support for page table updates and
TLB flushes for IOMMU-v2 in A4xx. Also use VBIF recoverable HALT
feature to prevent the GPU from accessing the IOMMU while updates
are being done via dedicated AHB path. Identify GPU type in adreno_probe().
This is required to set SMMU AHB base for A405 to 0x48000.
Use CP_WIDE_REG_WRITE PM4 packet for IOMMU programming.
This is required to overcome limitation of type0 packet which allows
max register address 0x7FFF.

Change-Id: I58822204297ef69f15e30b25ab0dda72def43712
Signed-off-by: default avatarAnanta Kishore K <akollipa@codeaurora.org>
parent 656f2e31
Loading
Loading
Loading
Loading
+132 −10
Original line number Diff line number Diff line
@@ -950,7 +950,8 @@ static unsigned int _adreno_iommu_setstate_v1(struct kgsl_device *device,
	return cmds - cmds_orig;
}

static unsigned int _adreno_iommu_setstate_v2(struct kgsl_device *device,

static unsigned int _adreno_iommu_setstate_v2_a3xx(struct kgsl_device *device,
					unsigned int *cmds_orig,
					phys_addr_t pt_val,
					int num_iommu_units, uint32_t flags)
@@ -1048,10 +1049,6 @@ static unsigned int _adreno_iommu_setstate_v2(struct kgsl_device *device,
			tlbstatus = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
					KGSL_IOMMU_CONTEXT_USER,
					KGSL_IOMMU_CTX_TLBSTATUS) >> 2;
			if (adreno_is_a4xx(adreno_dev))
				cmds += adreno_wait_reg_mem(cmds, tlbstatus, 0,
					KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE, 0xF);
			else
			cmds += adreno_wait_reg_eq(cmds, tlbstatus, 0,
					KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE, 0xF);
			/* release all commands with wait_for_me */
@@ -1064,6 +1061,127 @@ static unsigned int _adreno_iommu_setstate_v2(struct kgsl_device *device,

	return cmds - cmds_orig;
}


static unsigned int _adreno_iommu_setstate_v2_a4xx(struct kgsl_device *device,
					unsigned int *cmds_orig,
					phys_addr_t pt_val,
					int num_iommu_units, uint32_t flags)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	uint64_t ttbr0_val;
	unsigned int reg_pt_val;
	unsigned int *cmds = cmds_orig;
	int i;
	unsigned int ttbr0, tlbiall, tlbstatus, tlbsync;

	cmds += adreno_add_idle_cmds(adreno_dev, cmds);

	for (i = 0; i < num_iommu_units; i++) {
		ttbr0_val = kgsl_mmu_get_default_ttbr0(&device->mmu,
				i, KGSL_IOMMU_CONTEXT_USER);
		ttbr0_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
		ttbr0_val |= (pt_val & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK);
		if (flags & KGSL_MMUFLAGS_PTUPDATE) {

			ttbr0 = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
						KGSL_IOMMU_CONTEXT_USER,
						KGSL_IOMMU_CTX_TTBR0) >> 2;

			/*
			 * glue commands together until next
			 * WAIT_FOR_ME
			 */
			cmds += adreno_wait_reg_mem(cmds,
					adreno_getreg(adreno_dev,
						ADRENO_REG_CP_WFI_PEND_CTR),
						1, 0xFFFFFFFF, 0xF);

			/* MMU-500 VBIF stall */
			*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
			*cmds++ = A3XX_VBIF_DDR_OUTPUT_RECOVERABLE_HALT_CTRL0;
			/* AND to unmask the HALT bit */
			*cmds++ = ~(VBIF_RECOVERABLE_HALT_CTRL);
			/* OR to set the HALT bit */
			*cmds++ = 0x1;

			/* Wait for acknowledgement */
			cmds += adreno_wait_reg_mem(cmds,
				A3XX_VBIF_DDR_OUTPUT_RECOVERABLE_HALT_CTRL1,
					1, 0xFFFFFFFF, 0xF);

			/* set ttbr0 */
			if (sizeof(phys_addr_t) >
				sizeof(unsigned int)) {

				reg_pt_val =
					ttbr0_val & 0xFFFFFFFF;
				*cmds++ =
				cp_type3_packet(CP_WIDE_REG_WRITE, 2);
				*cmds++ = ttbr0;
				*cmds++ = reg_pt_val;

				reg_pt_val = (unsigned int)
				((ttbr0_val &
				0xFFFFFFFF00000000ULL) >> 32);
				*cmds++ =
				cp_type3_packet(CP_WIDE_REG_WRITE, 2);
				*cmds++ = ttbr0+1;
				*cmds++ = reg_pt_val;
			} else {

				reg_pt_val = ttbr0_val;
				*cmds++ =
				cp_type3_packet(CP_WIDE_REG_WRITE, 2);
				*cmds++ = ttbr0;
				*cmds++ = reg_pt_val;
			}

			/* MMU-500 VBIF unstall */
			*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
			*cmds++ = A3XX_VBIF_DDR_OUTPUT_RECOVERABLE_HALT_CTRL0;
			/* AND to unmask the HALT bit */
			*cmds++ = ~(VBIF_RECOVERABLE_HALT_CTRL);
			/* OR to reset the HALT bit */
			*cmds++ = 0;

			/* release all commands with wait_for_me */
			*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
			*cmds++ = 0;

		}
		if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
			tlbiall = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
						KGSL_IOMMU_CONTEXT_USER,
						KGSL_IOMMU_CTX_TLBIALL) >> 2;

			*cmds++ = cp_type3_packet(CP_WIDE_REG_WRITE, 2);
			*cmds++ = tlbiall;
			*cmds++ = 1;

			tlbsync = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
						KGSL_IOMMU_CONTEXT_USER,
						KGSL_IOMMU_CTX_TLBSYNC) >> 2;

			*cmds++ = cp_type3_packet(CP_WIDE_REG_WRITE, 2);
			*cmds++ = tlbsync;
			*cmds++ = 0;

			tlbstatus = kgsl_mmu_get_reg_ahbaddr(&device->mmu, i,
					KGSL_IOMMU_CONTEXT_USER,
					KGSL_IOMMU_CTX_TLBSTATUS) >> 2;
			cmds += adreno_wait_reg_mem(cmds, tlbstatus, 0,
					KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE, 0xF);
			/* release all commands with wait_for_me */
			*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
			*cmds++ = 0;
		}
	}

	cmds += adreno_add_idle_cmds(adreno_dev, cmds);

	return cmds - cmds_orig;
}
/**
 * adreno_use_default_setstate() - Use CPU instead of the GPU to manage the mmu?
 * @adreno_dev: the device
@@ -1128,8 +1246,12 @@ static int adreno_iommu_setstate(struct kgsl_device *device,
		KGSL_IOMMU_SETSTATE_NOP_OFFSET);

	if (kgsl_msm_supports_iommu_v2())
		cmds += _adreno_iommu_setstate_v2(device, cmds, pt_val,
						num_iommu_units, flags);
		if (adreno_is_a4xx(adreno_dev))
			cmds += _adreno_iommu_setstate_v2_a4xx(device, cmds,
					pt_val, num_iommu_units, flags);
		else
			cmds += _adreno_iommu_setstate_v2_a3xx(device, cmds,
					pt_val, num_iommu_units, flags);
	else if (msm_soc_version_supports_iommu_v0())
		cmds += _adreno_iommu_setstate_v0(device, cmds, pt_val,
						num_iommu_units, flags);
@@ -1553,6 +1675,9 @@ int adreno_probe(struct platform_device *pdev)
		return status;
	}

	/* Identify the specific GPU */
	adreno_identify_gpu(adreno_dev);

	status = kgsl_device_platform_probe(device);
	if (status) {
		device->pdev = NULL;
@@ -1639,9 +1764,6 @@ static int adreno_init(struct kgsl_device *device)
	if (test_bit(ADRENO_DEVICE_INITIALIZED, &adreno_dev->priv))
		return 0;

	/* Identify the specific GPU */
	adreno_identify_gpu(adreno_dev);

	gpudev = ADRENO_GPU_DEVICE(adreno_dev);

	/* Power up the device */
+7 −0
Original line number Diff line number Diff line
@@ -153,6 +153,13 @@
/* Write register, ignoring context state for context sensitive registers */
#define CP_REG_WR_NO_CTXT  0x78

/*
 * for A4xx
 * Write to register with address that does not fit into type-0 pkt
 */
#define CP_WIDE_REG_WRITE           0x74


/* PFP waits until the FIFO between the PFP and the ME is empty */
#define CP_WAIT_FOR_ME		0x13

+16 −3
Original line number Diff line number Diff line
@@ -1179,6 +1179,8 @@ static int kgsl_set_register_map(struct kgsl_mmu *mmu)
	struct kgsl_iommu *iommu = mmu->device->mmu.priv;
	struct kgsl_iommu_unit *iommu_unit;
	int i = 0, ret = 0;
	struct kgsl_device *device = mmu->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	for (; i < pdata->iommu_count; i++) {
		struct kgsl_device_iommu_data data = pdata->iommu_data[i];
@@ -1214,6 +1216,10 @@ static int kgsl_set_register_map(struct kgsl_mmu *mmu)
			iommu_unit->iommu_halt_enable = 1;

		if (kgsl_msm_supports_iommu_v2())
			if (adreno_is_a405(adreno_dev)) {
				iommu_unit->ahb_base =
					KGSL_IOMMU_V2_AHB_BASE_A405;
			} else
				iommu_unit->ahb_base = KGSL_IOMMU_V2_AHB_BASE;
		else
			iommu_unit->ahb_base =
@@ -2156,12 +2162,19 @@ static void kgsl_iommu_set_pagefault(struct kgsl_mmu *mmu)
struct kgsl_protected_registers *kgsl_iommu_get_prot_regs(struct kgsl_mmu *mmu)
{
	static struct kgsl_protected_registers iommuv1_regs = { 0x4000, 14 };
	static struct kgsl_protected_registers iommuv2_regs = { 0x2800, 10 };
	static struct kgsl_protected_registers iommuv2_regs;

	if (msm_soc_version_supports_iommu_v0())
		return NULL;
	if (kgsl_msm_supports_iommu_v2())
	if (kgsl_msm_supports_iommu_v2()) {

		struct kgsl_iommu *iommu = mmu->priv;

		/* For V2 there is only one instance of iommu */
		iommuv2_regs.base = iommu->iommu_units[0].ahb_base >> 2;
		iommuv2_regs.range = 10;
		return &iommuv2_regs;
	}
	else
		return &iommuv1_regs;
}
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

/* IOMMU V2 AHB base is fixed */
#define KGSL_IOMMU_V2_AHB_BASE		0xA000
#define KGSL_IOMMU_V2_AHB_BASE_A405  0x48000
/* IOMMU_V2 AHB base points to ContextBank1 */
#define KGSL_IOMMU_CTX_AHB_OFFSET_V2   0