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

Commit c1e3c140 authored by Vijayanand Jitta's avatar Vijayanand Jitta Committed by Gerrit - the friendly Code Review server
Browse files

iommu: arm-smmu: add option to distinguish testbus implementations



testbus implementation is different in some hardware add an option
qcom,testbus-version to select testbus version from device tree to
support testbus interface in such hardware.

Change-Id: I826898c16783b08b2609309774b9177009cf9110
Signed-off-by: default avatarVijayanand Jitta <vjitta@codeaurora.org>
parent da30a199
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -146,6 +146,13 @@ conditions.
		  we can choose to have a single ASID associated with all domains
		  for a context bank.

- qcom,testbus-version:
		  Testbus implementation is different in some hardware for eg some doesn't
		  have a separate register for programming tbu testbuses so, they share the
		  same register to program both tcu and tbu testbuses. on such hardware this
		  option can be used to specify the testbus version to support testbus interface.
		  Type is <u32>.

- clocks        : List of clocks to be used during SMMU register access. See
                  Documentation/devicetree/bindings/clock/clock-bindings.txt
                  for information about the format. For each clock specified
+64 −29
Original line number Diff line number Diff line
@@ -18,21 +18,37 @@
#include "arm-smmu-debug.h"

u32 arm_smmu_debug_tbu_testbus_select(void __iomem *tbu_base,
		void __iomem *tcu_base, u32 testbus_version,
		bool write, u32 val)
{
	void __iomem *base;
	int offset;

	if (testbus_version == 1) {
		base = tcu_base;
		offset = ARM_SMMU_TESTBUS_SEL_HLOS1_NS;
	} else {
		base = tbu_base;
		offset = DEBUG_TESTBUS_SEL_TBU;
	}

	if (write) {
		writel_relaxed(val, tbu_base + DEBUG_TESTBUS_SEL_TBU);
		writel_relaxed(val, base + offset);
		/* Make sure tbu select register is written to */
		wmb();
	} else {
		return readl_relaxed(tbu_base + DEBUG_TESTBUS_SEL_TBU);
		return readl_relaxed(base + offset);
	}
	return 0;
}

u32 arm_smmu_debug_tbu_testbus_output(void __iomem *tbu_base)
u32 arm_smmu_debug_tbu_testbus_output(void __iomem *tbu_base,
			u32 testbus_version)
{
	return readl_relaxed(tbu_base + DEBUG_TESTBUS_TBU);
	int offset = (testbus_version == 1) ?
			CLIENT_DEBUG_SR_HALT_ACK : DEBUG_TESTBUS_TBU;

	return readl_relaxed(tbu_base + offset);
}

u32 arm_smmu_debug_tcu_testbus_select(void __iomem *base,
@@ -65,67 +81,86 @@ u32 arm_smmu_debug_tcu_testbus_output(void __iomem *base)
}

static void arm_smmu_debug_dump_tbu_qns4_testbus(struct device *dev,
					void __iomem *tbu_base)
			void __iomem *tbu_base, void __iomem *tcu_base,
			u32  testbus_version)
{
	int i;
	u32 reg;

	for (i = 0 ; i < TBU_QNS4_BRIDGE_SIZE; ++i) {
		reg = arm_smmu_debug_tbu_testbus_select(tbu_base, READ, 0);
		reg = arm_smmu_debug_tbu_testbus_select(tbu_base, tcu_base,
				testbus_version, READ, 0);
		reg = (reg & ~GENMASK(4, 0)) | i << 0;
		arm_smmu_debug_tbu_testbus_select(tbu_base, WRITE, reg);
		arm_smmu_debug_tbu_testbus_select(tbu_base, tcu_base,
				testbus_version, WRITE, reg);
		dev_info(dev, "testbus_sel: 0x%lx Index: %d val: 0x%llx\n",
			arm_smmu_debug_tbu_testbus_select(tbu_base,
						READ, 0), i,
			arm_smmu_debug_tbu_testbus_output(tbu_base));
			arm_smmu_debug_tbu_testbus_select(tbu_base, tcu_base,
				testbus_version, READ, 0), i,
			arm_smmu_debug_tbu_testbus_output(tbu_base,
							testbus_version));
	}
}

static void arm_smmu_debug_program_tbu_testbus(void __iomem *tbu_base,
				void __iomem *tcu_base, u32 testbus_version,
				int tbu_testbus)
{
	u32 reg;

	reg = arm_smmu_debug_tbu_testbus_select(tbu_base, READ, 0);
	reg = (reg & ~GENMASK(7, 0)) | tbu_testbus;
	arm_smmu_debug_tbu_testbus_select(tbu_base, WRITE, reg);
	reg = arm_smmu_debug_tbu_testbus_select(tbu_base, tcu_base,
						testbus_version, READ, 0);
	if (testbus_version == 1)
		reg = (reg & ~GENMASK(9, 0));
	else
		reg = (reg & ~GENMASK(7, 0));

	reg |= tbu_testbus;
	arm_smmu_debug_tbu_testbus_select(tbu_base, tcu_base,
						testbus_version, WRITE, reg);
}

void arm_smmu_debug_dump_tbu_testbus(struct device *dev, void __iomem *tbu_base,
			int tbu_testbus_sel)
		void __iomem *tcu_base, int tbu_testbus_sel,
		u32 testbus_version)
{
	if (tbu_testbus_sel & TBU_CLK_GATE_CONTROLLER_TESTBUS_SEL) {
		dev_info(dev, "Dumping TBU clk gate controller:");
		arm_smmu_debug_program_tbu_testbus(tbu_base,
		arm_smmu_debug_program_tbu_testbus(tbu_base, tcu_base,
				testbus_version,
				TBU_CLK_GATE_CONTROLLER_TESTBUS);
		dev_info(dev, "testbus_sel: 0x%lx val: 0x%llx\n",
			arm_smmu_debug_tbu_testbus_select(tbu_base,
						READ, 0),
			arm_smmu_debug_tbu_testbus_output(tbu_base));
			arm_smmu_debug_tbu_testbus_select(tbu_base, tcu_base,
						testbus_version, READ, 0),
			arm_smmu_debug_tbu_testbus_output(tbu_base,
							testbus_version));
	}

	if (tbu_testbus_sel & TBU_QNS4_A2Q_TESTBUS_SEL) {
		dev_info(dev, "Dumping TBU qns4 a2q test bus");
		arm_smmu_debug_program_tbu_testbus(tbu_base,
				TBU_QNS4_A2Q_TESTBUS);
		arm_smmu_debug_dump_tbu_qns4_testbus(dev, tbu_base);
		arm_smmu_debug_program_tbu_testbus(tbu_base, tcu_base,
				testbus_version, TBU_QNS4_A2Q_TESTBUS);
		arm_smmu_debug_dump_tbu_qns4_testbus(dev, tbu_base,
				tcu_base, testbus_version);
	}

	if (tbu_testbus_sel & TBU_QNS4_Q2A_TESTBUS_SEL) {
		dev_info(dev, "Dumping qns4 q2a test bus");
		arm_smmu_debug_program_tbu_testbus(tbu_base,
				TBU_QNS4_Q2A_TESTBUS);
		arm_smmu_debug_dump_tbu_qns4_testbus(dev, tbu_base);
		arm_smmu_debug_program_tbu_testbus(tbu_base, tcu_base,
				testbus_version, TBU_QNS4_Q2A_TESTBUS);
		arm_smmu_debug_dump_tbu_qns4_testbus(dev, tbu_base,
				tcu_base, testbus_version);
	}

	if (tbu_testbus_sel & TBU_MULTIMASTER_QCHANNEL_TESTBUS_SEL) {
		dev_info(dev, "Dumping multi master qchannel:");
		arm_smmu_debug_program_tbu_testbus(tbu_base,
		arm_smmu_debug_program_tbu_testbus(tbu_base, tcu_base,
				testbus_version,
				TBU_MULTIMASTER_QCHANNEL_TESTBUS);
		dev_info(dev, "testbus_sel: 0x%lx val: 0x%llx\n",
			arm_smmu_debug_tbu_testbus_select(tbu_base,
						READ, 0),
			arm_smmu_debug_tbu_testbus_output(tbu_base));
				tcu_base, testbus_version, READ, 0),
			arm_smmu_debug_tbu_testbus_output(tbu_base,
							testbus_version));
	}
}

+13 −7
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#define ARM_SMMU_TESTBUS_SEL_HLOS1_NS		0x8
#define DEBUG_TESTBUS_SEL_TBU			0x50
#define DEBUG_TESTBUS_TBU			0x58
#define CLIENT_DEBUG_SR_HALT_ACK		0x24

#define TCU_PTW_TESTBUS				(0x1 << 8)
#define TCU_CACHE_TESTBUS			~TCU_PTW_TESTBUS
@@ -57,23 +58,28 @@ enum testbus_ops {
#ifdef CONFIG_ARM_SMMU

u32 arm_smmu_debug_tbu_testbus_select(void __iomem *tbu_base,
					bool write, u32 val);
u32 arm_smmu_debug_tbu_testbus_output(void __iomem *tbu_base);
		void __iomem *tcu_base, u32 testbus_version,
		bool write, u32 reg);
u32 arm_smmu_debug_tbu_testbus_output(void __iomem *tbu_base,
					u32 testbus_version);
u32 arm_smmu_debug_tcu_testbus_select(void __iomem *base,
		void __iomem *tcu_base, enum tcu_testbus testbus,
		bool write, u32 val);
u32 arm_smmu_debug_tcu_testbus_output(void __iomem *base);
void arm_smmu_debug_dump_tbu_testbus(struct device *dev, void __iomem *tbu_base,
			int tbu_testbus_sel);
		void __iomem *tcu_base, int tbu_testbus_sel,
		u32 testbus_version);
void arm_smmu_debug_dump_tcu_testbus(struct device *dev, void __iomem *base,
			void __iomem *tcu_base, int tcu_testbus_sel);

#else
static inline u32 arm_smmu_debug_tbu_testbus_select(void __iomem *tbu_base,
				bool write, u32 val)
		void __iomem *tcu_base,	u32 testbus_version, bool write,
		u32 val)
{
}
static inline u32 arm_smmu_debug_tbu_testbus_output(void __iomem *tbu_base)
static inline u32 arm_smmu_debug_tbu_testbus_output(void __iomem *tbu_base,
						u32 testbus_version)
{
}
u32 arm_smmu_debug_tcu_testbus_select(void __iomem *base,
@@ -85,7 +91,8 @@ static inline u32 arm_smmu_debug_tcu_testbus_output(void __iomem *base)
{
}
static inline void arm_smmu_debug_dump_tbu_testbus(struct device *dev,
			void __iomem *tbu_base, int tbu_testbus_sel)
			void __iomem *tbu_base, void __iomem *tcu_base,
			int tbu_testbus_sel, u32 testbus_version)
{
}
static inline void arm_smmu_debug_dump_tcu_testbus(struct device *dev,
@@ -94,4 +101,3 @@ static inline void arm_smmu_debug_dump_tcu_testbus(struct device *dev,
{
}
#endif
+54 −10
Original line number Diff line number Diff line
@@ -5125,6 +5125,7 @@ struct qsmmuv500_archdata {
	u32				version;
	struct actlr_setting		*actlrs;
	u32				actlr_tbl_size;
	u32				testbus_version;
};
#define get_qsmmuv500_archdata(smmu)				\
	((struct qsmmuv500_archdata *)(smmu->archdata))
@@ -5613,6 +5614,22 @@ static int qsmmuv500_read_actlr_tbl(struct arm_smmu_device *smmu)
	return 0;
}

static int qsmmuv500_get_testbus_version(struct arm_smmu_device *smmu)
{
	struct device *dev = smmu->dev;
	struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
	u32 testbus_version;
	const __be32 *cell;

	cell = of_get_property(dev->of_node, "qcom,testbus-version", NULL);
	if (!cell)
		return 0;

	testbus_version = of_read_number(cell, 1);

	data->testbus_version = testbus_version;
	return 0;
}
static ssize_t arm_smmu_debug_testbus_read(struct file *file,
		char __user *ubuf, size_t count, loff_t *offset,
		enum testbus_sel tbu, enum testbus_ops ops)
@@ -5630,16 +5647,28 @@ static ssize_t arm_smmu_debug_testbus_read(struct file *file,

	if (tbu == SEL_TBU) {
		struct qsmmuv500_tbu_device *tbu = file->private_data;
		struct arm_smmu_device *smmu = tbu->smmu;
		void __iomem *tbu_base = tbu->base;
		struct qsmmuv500_archdata *data = smmu->archdata;
		void __iomem *tcu_base = data->tcu_base;
		u32 testbus_version = data->testbus_version;
		struct arm_smmu_power_resources *pwr;
		long val;

		arm_smmu_power_on(tbu->pwr);
		if (testbus_version == 1)
			pwr = smmu->pwr;
		else
			pwr = tbu->pwr;

		arm_smmu_power_on(pwr);

		if (ops == TESTBUS_SELECT)
			val = arm_smmu_debug_tbu_testbus_select(tbu_base,
							READ, 0);
					tcu_base, testbus_version, READ, 0);
		else
			val = arm_smmu_debug_tbu_testbus_output(tbu_base);
		arm_smmu_power_off(tbu->pwr);
			val = arm_smmu_debug_tbu_testbus_output(tbu_base,
							testbus_version);
		arm_smmu_power_off(pwr);

		snprintf(buf, buf_len, "0x%0x\n", val);
	} else {
@@ -5807,6 +5836,11 @@ static ssize_t arm_smmu_debug_tbu_testbus_sel_write(struct file *file,
{
	struct qsmmuv500_tbu_device *tbu = file->private_data;
	void __iomem *tbu_base = tbu->base;
	struct arm_smmu_device *smmu = tbu->smmu;
	struct arm_smmu_power_resources *pwr;
	struct qsmmuv500_archdata *data = smmu->archdata;
	void __iomem *tcu_base = data->tcu_base;
	u32 testbus_version = data->testbus_version;
	u64 val;

	if (kstrtoull_from_user(ubuf, count, 0, &val)) {
@@ -5814,9 +5848,15 @@ static ssize_t arm_smmu_debug_tbu_testbus_sel_write(struct file *file,
		return -EINVAL;
	}

	arm_smmu_power_on(tbu->pwr);
	arm_smmu_debug_tbu_testbus_select(tbu_base, WRITE, val);
	arm_smmu_power_off(tbu->pwr);
	if (testbus_version == 1)
		pwr = smmu->pwr;
	else
		pwr = tbu->pwr;

	arm_smmu_power_on(pwr);
	arm_smmu_debug_tbu_testbus_select(tbu_base, tcu_base,
			testbus_version, WRITE, val);
	arm_smmu_power_off(pwr);

	return count;
}
@@ -5918,6 +5958,10 @@ static int qsmmuv500_arch_init(struct arm_smmu_device *smmu)
	data->version = readl_relaxed(data->tcu_base + TCU_HW_VERSION_HLOS1);
	smmu->archdata = data;

	ret = qsmmuv500_get_testbus_version(smmu);
	if (ret)
		return ret;

	qsmmuv500_tcu_testbus_init(smmu);

	if (arm_smmu_is_static_cb(smmu))