ccn: Introduce API to set and read value of node register

Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
diff --git a/drivers/arm/ccn/ccn.c b/drivers/arm/ccn/ccn.c
index 910cd7c..59a7576 100644
--- a/drivers/arm/ccn/ccn.c
+++ b/drivers/arm/ccn/ccn.c
@@ -11,6 +11,7 @@
 #include <debug.h>
 #include <errno.h>
 #include <mmio.h>
+#include <stdbool.h>
 #include "ccn_private.h"
 
 static const ccn_desc_t *ccn_plat_desc;
@@ -490,3 +491,123 @@
 	return (int)(mmio_read_64(periphbase
 			+ MN_PERIPH_ID_0_1_OFFSET) & 0xFF);
 }
+
+/*******************************************************************************
+ * This function returns the region id corresponding to a node_id of node_type.
+ ******************************************************************************/
+static unsigned int get_region_id_for_node(node_types_t node_type,
+						unsigned int node_id)
+{
+	unsigned int mn_reg_off, region_id;
+	unsigned long long node_bitmap;
+	unsigned int loc_node_id, node_pos_in_map = 0;
+
+	assert(node_type < NUM_NODE_TYPES);
+	assert(node_id < MAX_RN_NODES);
+
+	switch (node_type) {
+	case NODE_TYPE_RNI:
+		region_id = RNI_REGION_ID_START;
+		break;
+	case NODE_TYPE_HNF:
+		region_id = HNF_REGION_ID_START;
+		break;
+	case NODE_TYPE_HNI:
+		region_id = HNI_REGION_ID_START;
+		break;
+	case NODE_TYPE_SN:
+		region_id = SBSX_REGION_ID_START;
+		break;
+	default:
+		ERROR("Un-supported Node Type = %d.\n", node_type);
+		assert(false);
+		return REGION_ID_LIMIT;
+	}
+	/*
+	 * RN-I, HN-F, HN-I, SN node registers in the MN region
+	 * occupy contiguous 16 byte apart offsets.
+	 *
+	 * RN-F and RN-D node are not supported as
+	 * none of them exposes any memory map to
+	 * configure any of their offset registers.
+	 */
+
+	mn_reg_off = MN_RNF_NODEID_OFFSET + (node_type << 4);
+	node_bitmap = ccn_reg_read(ccn_plat_desc->periphbase,
+					MN_REGION_ID, mn_reg_off);
+
+	assert((node_bitmap & (1ULL << (node_id))) != 0U);
+
+
+	FOR_EACH_PRESENT_NODE_ID(loc_node_id, node_bitmap) {
+		INFO("Index = %u with loc_nod=%u and input nod=%u\n",
+					node_pos_in_map, loc_node_id, node_id);
+		if (loc_node_id == node_id)
+			break;
+		node_pos_in_map++;
+	}
+
+	if (node_pos_in_map == CCN_MAX_RN_MASTERS) {
+		ERROR("Node Id = %d, is not found.\n", node_id);
+		assert(false);
+		return REGION_ID_LIMIT;
+	}
+
+	region_id += node_pos_in_map;
+
+	return region_id;
+}
+
+/*******************************************************************************
+ * This function sets the value 'val' to the register at register_offset from
+ * the base address pointed to by the region_id.
+ * where, region id is mapped to a node_id of node_type.
+ ******************************************************************************/
+void ccn_write_node_reg(node_types_t node_type, unsigned int node_id,
+			unsigned int reg_offset, unsigned long long val)
+{
+	unsigned int region_id = get_region_id_for_node(node_type, node_id);
+
+	if (reg_offset > REGION_ID_OFFSET) {
+		ERROR("Invalid Register offset 0x%x is provided.\n",
+								reg_offset);
+		assert(false);
+		return;
+	}
+
+	/* Setting the value of Auxilary Control Register of the Node */
+	ccn_reg_write(ccn_plat_desc->periphbase, region_id, reg_offset, val);
+	VERBOSE("Value is successfully written at address 0x%lx.\n",
+			(ccn_plat_desc->periphbase
+			+ region_id_to_base(region_id))
+			+ reg_offset);
+}
+
+/*******************************************************************************
+ * This function read the value 'val' stored in the register at register_offset
+ * from the base address pointed to by the region_id.
+ * where, region id is mapped to a node_id of node_type.
+ ******************************************************************************/
+unsigned long long ccn_read_node_reg(node_types_t node_type,
+					unsigned int node_id,
+					unsigned int reg_offset)
+{
+	unsigned long long val;
+	unsigned int region_id = get_region_id_for_node(node_type, node_id);
+
+	if (reg_offset > REGION_ID_OFFSET) {
+		ERROR("Invalid Register offset 0x%x is provided.\n",
+								reg_offset);
+		assert(false);
+		return ULL(0);
+	}
+
+	/* Setting the value of Auxilary Control Register of the Node */
+	val = ccn_reg_read(ccn_plat_desc->periphbase, region_id, reg_offset);
+	VERBOSE("Value is successfully read from address 0x%lx.\n",
+			(ccn_plat_desc->periphbase
+			+ region_id_to_base(region_id))
+			+ reg_offset);
+
+	return val;
+}
diff --git a/include/drivers/arm/ccn.h b/include/drivers/arm/ccn.h
index eba974d..9c3abac 100644
--- a/include/drivers/arm/ccn.h
+++ b/include/drivers/arm/ccn.h
@@ -76,6 +76,16 @@
 	uintptr_t periphbase;
 } ccn_desc_t;
 
+/* Enum used to loop through all types of nodes in CCN*/
+typedef enum node_types {
+	NODE_TYPE_RNF = 0,
+	NODE_TYPE_RNI,
+	NODE_TYPE_RND,
+	NODE_TYPE_HNF,
+	NODE_TYPE_HNI,
+	NODE_TYPE_SN,
+	NUM_NODE_TYPES
+} node_types_t;
 
 void ccn_init(const ccn_desc_t *plat_ccn_desc);
 void ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map);
@@ -92,5 +102,12 @@
 unsigned int ccn_get_l3_run_mode(void);
 int ccn_get_part0_id(uintptr_t periphbase);
 
+void ccn_write_node_reg(node_types_t node_type, unsigned int node_id,
+				unsigned int reg_offset,
+				unsigned long long val);
+unsigned long long ccn_read_node_reg(node_types_t node_type,
+					unsigned int node_id,
+					unsigned int reg_offset);
+
 #endif /* __ASSEMBLY__ */
 #endif /* CCN_H */