iommu/arm-smmu, ACPI: Enable Cavium SMMU-v3

In next IORT spec release there will be a definition of a Cavium
specific model. Until then, enable the Cavium SMMU using cpu id
registers. Early silicon versions (A1) of Cavium's CN99xx SMMUv3
implementation must be enabled. For later silicon versions (B0) the
iort change will be in place.

Signed-off-by: Robert Richter <rrichter@cavium.com>
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index a3215ee..b603af9 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -26,6 +26,8 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
+#include <asm/cputype.h>
+
 #define IORT_TYPE_MASK(type)	(1 << (type))
 #define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
 #define IORT_IOMMU_TYPE		((1 << ACPI_IORT_NODE_SMMU) |	\
@@ -824,13 +826,22 @@
 	return num_res;
 }
 
+static bool is_cavium_cn99xx_smmu_v3(void)
+{
+	u32 cpu_model = read_cpuid_id() & MIDR_CPU_MODEL_MASK;
+
+	return cpu_model == MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM,
+					   BRCM_CPU_PART_VULCAN);
+}
+
 static bool arm_smmu_v3_is_combined_irq(struct acpi_iort_smmu_v3 *smmu)
 {
 	/*
 	 * Cavium ThunderX2 implementation doesn't not support unique
 	 * irq line. Use single irq line for all the SMMUv3 interrupts.
 	 */
-	if (smmu->model != ACPI_IORT_SMMU_V3_CAVIUM_CN99XX)
+	if (smmu->model != ACPI_IORT_SMMU_V3_CAVIUM_CN99XX
+	    && !is_cavium_cn99xx_smmu_v3())
 		return false;
 
 	/*
@@ -848,7 +859,8 @@
 	 * Override the size, for Cavium ThunderX2 implementation
 	 * which doesn't support the page 1 SMMU register space.
 	 */
-	if (smmu->model == ACPI_IORT_SMMU_V3_CAVIUM_CN99XX)
+	if (smmu->model == ACPI_IORT_SMMU_V3_CAVIUM_CN99XX
+	    || is_cavium_cn99xx_smmu_v3())
 		return SZ_64K;
 
 	return SZ_128K;
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 568c400..d147cb5 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -39,6 +39,8 @@
 
 #include <linux/amba/bus.h>
 
+#include <asm/cputype.h>
+
 #include "io-pgtable.h"
 
 /* MMIO registers */
@@ -2659,6 +2661,21 @@
 }
 
 #ifdef CONFIG_ACPI
+
+static void acpi_smmu_enable_cavium(struct arm_smmu_device *smmu)
+{
+	u32 cpu_model;
+
+	if (!IS_ENABLED(CONFIG_ARM64))
+		return;
+
+	cpu_model = read_cpuid_id() & MIDR_CPU_MODEL_MASK;
+	if (cpu_model != MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_VULCAN))
+		return;
+
+	smmu->options |= ARM_SMMU_OPT_PAGE0_REGS_ONLY;
+}
+
 static void acpi_smmu_get_options(u32 model, struct arm_smmu_device *smmu)
 {
 	switch (model) {
@@ -2670,6 +2687,8 @@
 		break;
 	}
 
+	acpi_smmu_enable_cavium(smmu);
+
 	dev_notice(smmu->dev, "option mask 0x%x\n", smmu->options);
 }