feat(gpt): statically allocate bitlocks array

Statically allocate 'gpt_bitlock' array of fine-grained
'bitlock_t' data structures in arm_bl31_setup.c.
The amount of memory needed for this array is controlled
by 'RME_GPT_BITLOCK_BLOCK' build option and 'PLAT_ARM_PPS'
macro defined in platform_def.h which specifies the size
of protected physical address space in bytes.
'PLAT_ARM_PPS' takes values from 4GB to 4PB supported by
Arm architecture.

Change-Id: Icf620b5039e45df6828d58fca089cad83b0bc669
Signed-off-by: AlexeiFedorov <Alexei.Fedorov@arm.com>
diff --git a/docs/components/granule-protection-tables-design.rst b/docs/components/granule-protection-tables-design.rst
index 78d2f12..91673c6 100644
--- a/docs/components/granule-protection-tables-design.rst
+++ b/docs/components/granule-protection-tables-design.rst
@@ -124,10 +124,7 @@
 
 The GPT initialization APIs require memory to be passed in for the tables to be
 constructed. The ``gpt_init_l0_tables`` API takes a memory address and size for
-building the level 0 tables and also memory for allocating the fine-grained bitlock
-data structure. The amount of memory needed for bitlock structure is controlled via
-``RME_GPT_BITLOCK_BLOCK`` config which defines the block size for each bit of the
-the bitlock.
+building the level 0 tables.
 
 The ``gpt_init_pas_l1_tables`` API takes an address and size for
 building the level 1 tables which are linked from level 0 descriptors. The
@@ -156,7 +153,7 @@
 During Granule Transition access to L1 tables is controlled by a lock to ensure
 that no more than one CPU is allowed to make changes at any given time.
 The granularity of the lock is defined by ``RME_GPT_BITLOCK_BLOCK`` build option
-which defines the size of the memory block protected by one bit of ``bitlock``
+which defines the size of the memory block protected by one bit of ``bitlock_t``
 structure. Setting this option to 0 chooses a single spinlock for all GPT L1
 table entries.
 
@@ -185,6 +182,10 @@
 #. In systems that make use of the granule transition service, runtime
    firmware must call ``gpt_runtime_init`` to set up the data structures needed
    by the GTSI to find the tables and transition granules between PAS types.
+   The base address of bitlocks array and its size are provided to this function
+   as arguments. These parameters are not used in case of a single spinlock for
+   all GPT L1 table entries(``RME_GPT_BITLOCK_BLOCK`` is 0) and are passed as zero
+   values.
 
 API Constraints
 ~~~~~~~~~~~~~~~
@@ -225,9 +226,6 @@
   is greater. L0 table size is the total protected space (PPS) divided by the
   size of each L0 region (L0GPTSZ) multiplied by the size of each L0 descriptor
   (8 bytes). ((PPS / L0GPTSZ) * 8)
-* The L0 memory size must be greater than the table size and have enough space
-  to allocate array of ``bitlock`` structures at the end of L0 table if
-  required (``RME_GPT_BITLOCK_BLOCK`` is not 0).
 * The L0 memory must fall within a PAS of type GPT_GPI_ROOT.
 
 The L1 memory also has some constraints.
@@ -237,6 +235,10 @@
   the granules controlled in each byte (2). ((L0GPTSZ / PGS) / 2)
 * There must be enough L1 memory supplied to build all requested L1 tables.
 * The L1 memory must fall within a PAS of type GPT_GPI_ROOT.
+* The platform allocates the bitlock array which contains fine-grained
+  ``bitlock_t`` data structures. The RME GPT library will check that the array
+  has at least the amount of memory defined by PPS and ``RME_GPT_BITLOCK_BLOCK``
+  value.
 
 If an invalid combination of parameters is supplied, the APIs will print an
 error message and return a negative value. The return values of APIs should be
@@ -245,7 +247,7 @@
 Sample Calculation for L0 memory size and alignment
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Let PPS=GPCCR_PPS_4GB and L0GPTSZ=GPCCR_L0GPTSZ_30BITS
+Let PPS=4GB and L0GPTSZ=GPCCR_L0GPTSZ_30BITS
 
 We can find the total L0 table size with ((PPS / L0GPTSZ) * 8)
 
@@ -254,19 +256,19 @@
 And solve to get 32 bytes. In this case, 4096 is greater than 32, so the L0
 tables must be aligned to 4096 bytes.
 
-Sample calculation for bitlock array size
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Sample calculation for bitlocks array size
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Let PGS=GPCCR_PPS_256TB and RME_GPT_BITLOCK_BLOCK=1
+Let PPS=256TB and RME_GPT_BITLOCK_BLOCK=1
 
-The size of bit lock array in bits is the total protected space (PPS) divided
+The size of bitlocks array in bits is the total protected space (PPS) divided
 by the size of memory block per bit. The size of memory block
 is ``RME_GPT_BITLOCK_BLOCK`` (number of 512MB blocks per bit) times
-512MB (0x20000000). This is then divided by the number of bits in ``bitlock``
-structure (8) to get the size of bit array in bytes.
+512MB (0x20000000). This is then divided by the number of bits in ``bitlock_t``
+structure (8) to get the size of array in bytes.
 
-In other words, we can find the total size of ``bitlock`` array
-in bytes with PPS / (RME_GPT_BITLOCK_BLOCK * 0x20000000 *  8).
+In other words, we can find the total size of ``bitlock_t`` array
+in bytes with PPS / (RME_GPT_BITLOCK_BLOCK * 0x20000000 * 8).
 
 Substitute values to get this: 0x1000000000000 / (1 * 0x20000000 * 8)
 
diff --git a/include/lib/gpt_rme/gpt_rme.h b/include/lib/gpt_rme/gpt_rme.h
index 94a88b0..135a948 100644
--- a/include/lib/gpt_rme/gpt_rme.h
+++ b/include/lib/gpt_rme/gpt_rme.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,13 +8,20 @@
 #define GPT_RME_H
 
 #include <stdint.h>
-
-#include <arch.h>
+#include <lib/spinlock.h>
 
 /******************************************************************************/
 /* GPT helper macros and definitions                                          */
 /******************************************************************************/
 
+#if (RME_GPT_BITLOCK_BLOCK != 0)
+#define LOCK_SIZE	sizeof(((bitlock_t *)NULL)->lock)
+#define LOCK_TYPE	typeof(((bitlock_t *)NULL)->lock)
+#define LOCK_BITS	(LOCK_SIZE * UL(8))
+
+CASSERT((UL(1) == LOCK_SIZE), assert_bitlock_type_not_uint8_t);
+#endif /* RME_GPT_BITLOCK_BLOCK */
+
 /*
  * Structure for specifying a mapping range and it's properties. This should not
  * be manually initialized, using the MAP_GPT_REGION_x macros is recommended as
@@ -238,10 +245,14 @@
  * initialization from a previous stage. Granule protection checks must be
  * enabled already or this function will return an error.
  *
+ * Parameters
+ *   l1_bitlocks_base	Base address of memory for L1 tables bitlocks.
+ *   l1_bitlocks_size	Total size of memory available for L1 tables bitlocks.
+ *
  * Return
  *   Negative Linux error code in the event of a failure, 0 for success.
  */
-int gpt_runtime_init(void);
+int gpt_runtime_init(uintptr_t l1_bitlocks_base, size_t l1_bitlocks_size);
 
 /*
  * Public API to enable granule protection checks once the tables have all been
diff --git a/lib/gpt_rme/gpt_rme.c b/lib/gpt_rme/gpt_rme.c
index 79c4ea5..115f50d 100644
--- a/lib/gpt_rme/gpt_rme.c
+++ b/lib/gpt_rme/gpt_rme.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,14 +12,13 @@
 
 #include <arch.h>
 #include <arch_features.h>
-#include <arch_helpers.h>
 #include <common/debug.h>
-#include "gpt_rme_private.h"
 #include <lib/gpt_rme/gpt_rme.h>
 #include <lib/smccc.h>
-#include <lib/spinlock.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 
+#include "gpt_rme_private.h"
+
 #if !ENABLE_RME
 #error "ENABLE_RME must be enabled to use the GPT library"
 #endif
@@ -123,25 +122,19 @@
 #define GPT_L1_INDEX(_pa)	\
 	(((_pa) >> (unsigned int)GPT_L1_IDX_SHIFT(gpt_config.p)) & gpt_l1_index_mask)
 
-/* These variables are used during initialization of the L1 tables */
+/* This variable is used during initialization of the L1 tables */
 static uintptr_t gpt_l1_tbl;
 
-/* These variable is used during runtime */
+/* These variables are used during runtime */
 #if (RME_GPT_BITLOCK_BLOCK == 0)
 /*
  * The GPTs are protected by a global spinlock to ensure
  * that multiple CPUs do not attempt to change the descriptors at once.
  */
 static spinlock_t gpt_lock;
-#else
 
-/* Bitlocks base address */
-static bitlock_t *gpt_bitlock_base;
-#endif
-
-/* Lock/unlock macros for GPT entries */
-#if (RME_GPT_BITLOCK_BLOCK == 0)
-/*
+/* Lock/unlock macros for GPT entries
+ *
  * Access to GPT is controlled by a global lock to ensure
  * that no more than one CPU is allowed to make changes at any
  * given time.
@@ -149,13 +142,17 @@
 #define GPT_LOCK	spin_lock(&gpt_lock)
 #define GPT_UNLOCK	spin_unlock(&gpt_lock)
 #else
+
+/* Base address of bitlocks array */
+static bitlock_t *gpt_bitlock;
+
 /*
  * Access to a block of memory is controlled by a bitlock.
  * Size of block = RME_GPT_BITLOCK_BLOCK * 512MB.
  */
 #define GPT_LOCK	bit_lock(gpi_info.lock, gpi_info.mask)
 #define GPT_UNLOCK	bit_unlock(gpi_info.lock, gpi_info.mask)
-#endif
+#endif /* RME_GPT_BITLOCK_BLOCK */
 
 static void tlbi_page_dsbosh(uintptr_t base)
 {
@@ -494,8 +491,8 @@
  * This function validates L0 initialization parameters.
  *
  * Parameters
- *   l0_mem_base	Base address of memory used for L0 tables.
- *   l0_mem_size	Size of memory available for L0 tables.
+ *   l0_mem_base	Base address of memory used for L0 table.
+ *   l0_mem_size	Size of memory available for L0 table.
  *
  * Return
  *   Negative Linux error code in the event of a failure, 0 for success.
@@ -503,7 +500,7 @@
 static int validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base,
 				size_t l0_mem_size)
 {
-	size_t l0_alignment, locks_size = 0;
+	size_t l0_alignment;
 
 	/*
 	 * Make sure PPS is valid and then store it since macros need this value
@@ -516,8 +513,8 @@
 	gpt_config.pps = pps;
 	gpt_config.t = gpt_t_lookup[pps];
 
-	/* Alignment must be the greater of 4KB or l0 table size */
-	l0_alignment = PAGE_SIZE_4KB;
+	/* Alignment must be the greater of 4KB or L0 table size */
+	l0_alignment = SZ_4K;
 	if (l0_alignment < GPT_L0_TABLE_SIZE(gpt_config.t)) {
 		l0_alignment = GPT_L0_TABLE_SIZE(gpt_config.t);
 	}
@@ -529,28 +526,11 @@
 		return -EFAULT;
 	}
 
-#if (RME_GPT_BITLOCK_BLOCK != 0)
-	/*
-	 * Size of bitlocks in bytes for the protected address space
-	 * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
-	 */
-	locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
-			(RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
-
-	/*
-	 * If protected space size is less than the size covered
-	 * by 'bitlock' structure, check for a single bitlock.
-	 */
-	if (locks_size < LOCK_SIZE) {
-		locks_size = LOCK_SIZE;
-	}
-#endif
-	/* Check size for L0 tables and bitlocks */
-	if (l0_mem_size < (GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size)) {
+	/* Check memory size for L0 table */
+	if (l0_mem_size < GPT_L0_TABLE_SIZE(gpt_config.t)) {
 		ERROR("GPT: Inadequate L0 memory\n");
-		ERROR("      Expected 0x%lx bytes, got 0x%lx bytes\n",
-			GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size,
-			l0_mem_size);
+		ERROR("      Expected 0x%lx bytes, got 0x%lx\n",
+				GPT_L0_TABLE_SIZE(gpt_config.t), l0_mem_size);
 		return -ENOMEM;
 	}
 
@@ -600,7 +580,7 @@
 	if (l1_mem_size < l1_gpt_mem_sz) {
 		ERROR("%sL1 GPTs%s", (const char *)"GPT: Inadequate ",
 			(const char *)" memory\n");
-		ERROR("      Expected 0x%lx bytes, got 0x%lx bytes\n",
+		ERROR("      Expected 0x%lx bytes, got 0x%lx\n",
 			l1_gpt_mem_sz, l1_mem_size);
 		return -ENOMEM;
 	}
@@ -623,7 +603,7 @@
 	unsigned long idx, end_idx;
 	uint64_t *l0_gpt_arr;
 
-	assert(gpt_config.plat_gpt_l0_base != 0U);
+	assert(gpt_config.plat_gpt_l0_base != 0UL);
 	assert(pas != NULL);
 
 	/*
@@ -928,7 +908,7 @@
 	uint64_t *l1_gpt_arr;
 	unsigned int l0_idx, gpi;
 
-	assert(gpt_config.plat_gpt_l0_base != 0U);
+	assert(gpt_config.plat_gpt_l0_base != 0UL);
 	assert(pas != NULL);
 
 	/*
@@ -1121,12 +1101,10 @@
 		       size_t l0_mem_size)
 {
 	uint64_t gpt_desc;
-	size_t locks_size = 0;
-	__unused bitlock_t *bit_locks;
 	int ret;
 
 	/* Ensure that MMU and Data caches are enabled */
-	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
 
 	/* Validate other parameters */
 	ret = validate_l0_params(pps, l0_mem_base, l0_mem_size);
@@ -1141,32 +1119,9 @@
 	for (unsigned int i = 0U; i < GPT_L0_REGION_COUNT(gpt_config.t); i++) {
 		((uint64_t *)l0_mem_base)[i] = gpt_desc;
 	}
-
-#if (RME_GPT_BITLOCK_BLOCK != 0)
-	/* Initialise bitlocks at the end of L0 table */
-	bit_locks = (bitlock_t *)(l0_mem_base +
-					GPT_L0_TABLE_SIZE(gpt_config.t));
-
-	/* Size of bitlocks in bytes */
-	locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
-					(RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
-
-	/*
-	 * If protected space size is less than the size covered
-	 * by 'bitlock' structure, initialise a single bitlock.
-	 */
-	if (locks_size < LOCK_SIZE) {
-		locks_size = LOCK_SIZE;
-	}
-
-	for (size_t i = 0UL; i < (locks_size/LOCK_SIZE); i++) {
-		bit_locks[i].lock = 0U;
-	}
-#endif
 
-	/* Flush updated L0 tables and bitlocks to memory */
-	flush_dcache_range((uintptr_t)l0_mem_base,
-				GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size);
+	/* Flush updated L0 table to memory */
+	flush_dcache_range((uintptr_t)l0_mem_base, GPT_L0_TABLE_SIZE(gpt_config.t));
 
 	/* Stash the L0 base address once initial setup is complete */
 	gpt_config.plat_gpt_l0_base = l0_mem_base;
@@ -1202,7 +1157,7 @@
 	int l1_gpt_cnt, ret;
 
 	/* Ensure that MMU and Data caches are enabled */
-	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
 
 	/* PGS is needed for validate_pas_mappings so check it now */
 	if (pgs > GPT_PGS_MAX) {
@@ -1213,7 +1168,7 @@
 	gpt_config.p = gpt_p_lookup[pgs];
 
 	/* Make sure L0 tables have been initialized */
-	if (gpt_config.plat_gpt_l0_base == 0U) {
+	if (gpt_config.plat_gpt_l0_base == 0UL) {
 		ERROR("GPT: L0 tables must be initialized first!\n");
 		return -EPERM;
 	}
@@ -1295,18 +1250,23 @@
  * initialization from a previous stage. Granule protection checks must be
  * enabled already or this function will return an error.
  *
+ * Parameters
+ *   l1_bitlocks_base	Base address of memory for L1 tables bitlocks.
+ *   l1_bitlocks_size	Total size of memory available for L1 tables bitlocks.
+ *
  * Return
  *   Negative Linux error code in the event of a failure, 0 for success.
  */
-int gpt_runtime_init(void)
+int gpt_runtime_init(uintptr_t l1_bitlocks_base, size_t l1_bitlocks_size)
 {
 	u_register_t reg;
+	__unused size_t locks_size;
 
 	/* Ensure that MMU and Data caches are enabled */
-	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
 
 	/* Ensure GPC are already enabled */
-	if ((read_gpccr_el3() & GPCCR_GPC_BIT) == 0U) {
+	if ((read_gpccr_el3() & GPCCR_GPC_BIT) == 0UL) {
 		ERROR("GPT: Granule protection checks are not enabled!\n");
 		return -EPERM;
 	}
@@ -1334,17 +1294,43 @@
 	gpt_l1_index_mask = GPT_L1_IDX_MASK(gpt_config.p);
 
 #if (RME_GPT_BITLOCK_BLOCK != 0)
-	/* Bitlocks at the end of L0 table */
-	gpt_bitlock_base = (bitlock_t *)(gpt_config.plat_gpt_l0_base +
-					GPT_L0_TABLE_SIZE(gpt_config.t));
-#endif
+	/*
+	 * Size of GPT bitlocks in bytes for the protected address space
+	 * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
+	 */
+	locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
+			(RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
+	/*
+	 * If protected space size is less than the size covered
+	 * by 'bitlock' structure, check for a single bitlock.
+	 */
+	if (locks_size < LOCK_SIZE) {
+		locks_size = LOCK_SIZE;
+	/* Check bitlocks array size */
+	} else if (locks_size > l1_bitlocks_size) {
+		ERROR("GPT: Inadequate GPT bitlocks memory\n");
+		ERROR("      Expected 0x%lx bytes, got 0x%lx\n",
+			locks_size, l1_bitlocks_size);
+		return -ENOMEM;
+	}
+
+	gpt_bitlock = (bitlock_t *)l1_bitlocks_base;
+
+	/* Initialise GPT bitlocks */
+	(void)memset((void *)gpt_bitlock, 0, locks_size);
+
+	/* Flush GPT bitlocks to memory */
+	flush_dcache_range((uintptr_t)gpt_bitlock, locks_size);
+#endif /* RME_GPT_BITLOCK_BLOCK */
+
 	VERBOSE("GPT: Runtime Configuration\n");
 	VERBOSE("  PPS/T:     0x%x/%u\n", gpt_config.pps, gpt_config.t);
 	VERBOSE("  PGS/P:     0x%x/%u\n", gpt_config.pgs, gpt_config.p);
 	VERBOSE("  L0GPTSZ/S: 0x%x/%u\n", GPT_L0GPTSZ, GPT_S_VAL);
 	VERBOSE("  L0 base:   0x%"PRIxPTR"\n", gpt_config.plat_gpt_l0_base);
 #if (RME_GPT_BITLOCK_BLOCK != 0)
-	VERBOSE("  Bitlocks:  0x%"PRIxPTR"\n", (uintptr_t)gpt_bitlock_base);
+	VERBOSE("  Bitlocks:  0x%"PRIxPTR"/0x%lx\n", (uintptr_t)gpt_bitlock,
+					locks_size);
 #endif
 	return 0;
 }
@@ -1391,7 +1377,7 @@
 	block_idx = (unsigned int)(base / (RME_GPT_BITLOCK_BLOCK * SZ_512M));
 
 	/* Bitlock address and mask */
-	gpi_info->lock = &gpt_bitlock_base[block_idx / LOCK_BITS];
+	gpi_info->lock = &gpt_bitlock[block_idx / LOCK_BITS];
 	gpi_info->mask = 1U << (block_idx & (LOCK_BITS - 1U));
 #endif
 	return 0;
diff --git a/lib/gpt_rme/gpt_rme.mk b/lib/gpt_rme/gpt_rme.mk
index 7d6b61f..6878489 100644
--- a/lib/gpt_rme/gpt_rme.mk
+++ b/lib/gpt_rme/gpt_rme.mk
@@ -1,19 +1,24 @@
 #
-# Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+# RME_GPT_BITLOCK_BLOCK is the number of 512MB blocks
+# per bit and the value must be power of 2.
+BITLOCK_BLOCK_POWER_2=$(shell echo $$(( ${RME_GPT_BITLOCK_BLOCK} & (${RME_GPT_BITLOCK_BLOCK} - 1) )))
+
 # Process RME_GPT_BITLOCK_BLOCK value
-ifeq ($(filter 0 1 2 4 8 16 32 64 128 256 512, ${RME_GPT_BITLOCK_BLOCK}),)
-    $(error "Invalid value for RME_GPT_BITLOCK_BLOCK: ${RME_GPT_BITLOCK_BLOCK}")
+ifneq (${BITLOCK_BLOCK_POWER_2}, 0)
+    $(error "RME_GPT_BITLOCK_BLOCK must be power of 2. Invalid value ${RME_GPT_BITLOCK_BLOCK}.")
 endif
 
 ifeq (${RME_GPT_BITLOCK_BLOCK},0)
-    $(warning "GPT library uses global spinlock")
+    $(info "GPT library uses global spinlock")
 endif
 
-# Process RME_GPT_MAX_BLOCK value
+# Process the maximum size of supported contiguous blocks
+# RME_GPT_MAX_BLOCK
 ifeq ($(filter 0 2 32 512, ${RME_GPT_MAX_BLOCK}),)
     $(error "Invalid value for RME_GPT_MAX_BLOCK: ${RME_GPT_MAX_BLOCK}")
 endif
diff --git a/lib/gpt_rme/gpt_rme_private.h b/lib/gpt_rme/gpt_rme_private.h
index 31dad20..78d1cec 100644
--- a/lib/gpt_rme/gpt_rme_private.h
+++ b/lib/gpt_rme/gpt_rme_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,9 +7,7 @@
 #ifndef GPT_RME_PRIVATE_H
 #define GPT_RME_PRIVATE_H
 
-#include <arch.h>
 #include <lib/gpt_rme/gpt_rme.h>
-#include <lib/spinlock.h>
 #include <lib/utils_def.h>
 
 /******************************************************************************/
@@ -141,10 +139,6 @@
 	PGS_64KB_P =	16U
 } gpt_p_val_e;
 
-#define LOCK_SIZE	sizeof(((bitlock_t *)NULL)->lock)
-#define LOCK_TYPE	typeof(((bitlock_t *)NULL)->lock)
-#define LOCK_BITS	(LOCK_SIZE * 8U)
-
 /*
  * Internal structure to retrieve the values from get_gpi_params();
  */
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index 25848e4..f597f4b 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -57,7 +57,7 @@
 
 /* Protected physical address size */
 #define PLAT_ARM_PPS			(64 * SZ_1G)
-#endif
+#endif /* ENABLE_RME */
 
 /*
  * Max size of SPMC is 2MB for fvp. With SPMD enabled this value corresponds to
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index ce1545f..0503acf 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -34,9 +34,31 @@
  */
 static entry_point_info_t bl32_image_ep_info;
 static entry_point_info_t bl33_image_ep_info;
+
 #if ENABLE_RME
 static entry_point_info_t rmm_image_ep_info;
+#if (RME_GPT_BITLOCK_BLOCK == 0)
+#define BITLOCK_BASE	UL(0)
+#define BITLOCK_SIZE	UL(0)
+#else
+/*
+ * Number of bitlock_t entries in bitlocks array for PLAT_ARM_PPS
+ * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
+ */
+#if (PLAT_ARM_PPS > (RME_GPT_BITLOCK_BLOCK * SZ_512M * UL(8)))
+#define BITLOCKS_NUM	(PLAT_ARM_PPS) /	\
+			(RME_GPT_BITLOCK_BLOCK * SZ_512M * UL(8))
+#else
+#define BITLOCKS_NUM	U(1)
 #endif
+/*
+ * Bitlocks array
+ */
+static bitlock_t gpt_bitlock[BITLOCKS_NUM];
+#define BITLOCK_BASE	(uintptr_t)gpt_bitlock
+#define BITLOCK_SIZE	sizeof(gpt_bitlock)
+#endif /* RME_GPT_BITLOCK_BLOCK */
+#endif /* ENABLE_RME */
 
 #if !RESET_TO_BL31
 /*
@@ -551,7 +573,7 @@
 	 * stage, so there is no need to provide any PAS here. This function
 	 * sets up pointers to those tables.
 	 */
-	if (gpt_runtime_init() < 0) {
+	if (gpt_runtime_init(BITLOCK_BASE, BITLOCK_SIZE) < 0) {
 		ERROR("gpt_runtime_init() failed!\n");
 		panic();
 	}