drivers: add a driver for snoop control unit

The SCU connects one to four Cortex-A5/Cortex-A9 processors
to the memory system through the AXI interfaces.

The SCU functions are to:
- maintain data cache coherency between the Cortex-A5/Cortex-A9
  processors
- initiate L2 AXI memory accesses
- arbitrate between Cortex-A5/Cortex-A9 processors requesting
  L2 accesses
- manage ACP accesses.

Snoop Control Unit will enable to snoop on other CPUs caches.
This is very important when it comes to synchronizing data between
CPUs. As an example, there is a high chance that data might be
cache'd and other CPUs can't see the change. In such cases,
if snoop control unit is enabled, data is synchoronized immediately
between CPUs and the changes are visible to other CPUs.

This driver provides functionality to enable SCU as well as enabling
user to know the following
- number of CPUs present
- is a particular CPU operating in SMP mode or AMP mode
- data cache size of a particular CPU
- does SCU has ACP port
- is L2CPRESENT

Change-Id: I0d977970154fa60df57caf449200d471f02312a0
Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
diff --git a/drivers/arm/scu/scu.c b/drivers/arm/scu/scu.c
new file mode 100644
index 0000000..aceac92
--- /dev/null
+++ b/drivers/arm/scu/scu.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <drivers/arm/scu.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Turn ON snoop control unit. This is needed to synchronize the data between
+ * CPU's.
+ ******************************************************************************/
+void enable_snoop_ctrl_unit(uintptr_t base)
+{
+	uint32_t scu_ctrl;
+
+	INFO("[SCU]: enabling snoop control unit ... \n");
+
+	assert(base != 0U);
+	scu_ctrl = mmio_read_32(base + SCU_CTRL_REG);
+
+	/* already enabled? */
+	if ((scu_ctrl & SCU_ENABLE_BIT) != 0) {
+		return;
+	}
+
+	scu_ctrl |= SCU_ENABLE_BIT;
+	mmio_write_32(base + SCU_CTRL_REG, scu_ctrl);
+}
+
+/*******************************************************************************
+ * Snoop Control Unit configuration register. This is read-only register and
+ * contains information such as
+ * - number of CPUs present
+ * - is a particular CPU operating in SMP mode or AMP mode
+ * - data cache size of a particular CPU
+ * - does SCU has ACP port
+ * - is L2CPRESENT
+ * NOTE: user of this API should interpert the bits in this register according
+ * to the TRM
+ ******************************************************************************/
+uint32_t read_snoop_ctrl_unit_cfg(uintptr_t base)
+{
+	assert(base != 0U);
+
+	return mmio_read_32(base + SCU_CFG_REG);
+}
diff --git a/include/drivers/arm/scu.h b/include/drivers/arm/scu.h
new file mode 100644
index 0000000..992539f
--- /dev/null
+++ b/include/drivers/arm/scu.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCU_H
+#define SCU_H
+
+#include <stdint.h>
+
+#define SCU_CTRL_REG	0x00
+#define SCU_CFG_REG	0x04
+
+#define SCU_ENABLE_BIT	(1 << 0)
+
+void enable_snoop_ctrl_unit(uintptr_t base);
+uint32_t read_snoop_ctrl_unit_cfg(uintptr_t base);
+
+#endif /* SCU_H */
diff --git a/plat/arm/board/a5ds/a5ds_pm.c b/plat/arm/board/a5ds/a5ds_pm.c
index cc734b0..7774002 100644
--- a/plat/arm/board/a5ds/a5ds_pm.c
+++ b/plat/arm/board/a5ds/a5ds_pm.c
@@ -4,11 +4,10 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 #include <assert.h>
-
+#include <drivers/arm/gicv2.h>
 #include <lib/psci/psci.h>
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
-#include <drivers/arm/gicv2.h>
 
 /*******************************************************************************
  * Platform handler called when a power domain is about to be turned on. The
diff --git a/plat/arm/board/a5ds/include/platform_def.h b/plat/arm/board/a5ds/include/platform_def.h
index e9e4b9a..d200af6 100644
--- a/plat/arm/board/a5ds/include/platform_def.h
+++ b/plat/arm/board/a5ds/include/platform_def.h
@@ -334,6 +334,9 @@
 #define A5DS_HOLD_STATE_WAIT	0
 #define A5DS_HOLD_STATE_GO	1
 
+/* Snoop Control Unit base address */
+#define A5DS_SCU_BASE			0x1C000000
+
 /*
  * GIC related constants to cater for GICv2
  */
diff --git a/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c b/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
index 8b45af8..a951dc7 100644
--- a/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
+++ b/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
@@ -4,12 +4,17 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <drivers/arm/scu.h>
 #include <plat/arm/common/plat_arm.h>
 
+
 void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
 			u_register_t arg2, u_register_t arg3)
 {
 	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+
+	/* enable snoop control unit */
+	enable_snoop_ctrl_unit(A5DS_SCU_BASE);
 }
 
 /*
diff --git a/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk b/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk
index da1d785..4b0c97d 100644
--- a/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk
+++ b/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk
@@ -5,7 +5,8 @@
 #
 
 # SP_MIN source files specific to A5DS platform
-BL32_SOURCES	+=	drivers/cfi/v2m/v2m_flash.c			\
+BL32_SOURCES	+=	drivers/arm/scu/scu.c                           \
+			drivers/cfi/v2m/v2m_flash.c			\
 			lib/utils/mem_region.c				\
 			lib/aarch32/arm32_aeabi_divmod.c		\
 			lib/aarch32/arm32_aeabi_divmod_a32.S		\