summaryrefslogtreecommitdiff
path: root/drivers/arm/ccn/ccn_private.h
blob: f71597c1ce4486421f9fa7fd12f9f9b3f91f869e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
 * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef __CCN_PRIVATE_H__
#define __CCN_PRIVATE_H__

/*
 * A CCN implementation can have a maximum of 64 Request nodes with node IDs
 * from 0-63. These IDs are split across the three types of Request nodes
 * i.e. RN-F, RN-D and RN-I.
 */
#define MAX_RN_NODES		64

/* Enum used to loop through the 3 types of Request nodes */
typedef enum rn_types {
	RN_TYPE_RNF = 0,
	RN_TYPE_RNI,
	RN_TYPE_RND,
	NUM_RN_TYPES
} rn_types_t;

/* Macro to convert a region id to its base address */
#define region_id_to_base(id)	((id) << 16)

/*
 * Macro to calculate the number of master interfaces resident on a RN-I/RN-D.
 * Value of first two bits of the RN-I/D node type + 1 == Maximum number of
 * ACE-Lite or ACE-Lite+DVM interfaces supported on this node. E.g.
 *
 * 0x14 : RN-I with 1 ACE-Lite interface
 * 0x15 : RN-I with 2 ACE-Lite interfaces
 * 0x16 : RN-I with 3 ACE-Lite interfaces
 */
#define rn_type_id_to_master_cnt(id)	(((id) & 0x3) + 1)

/*
 * Constants used to identify a region in the programmer's view. These are
 * common for all regions.
 */
#define REGION_ID_LIMIT		256
#define REGION_ID_OFFSET	0xFF00

#define REGION_NODE_ID_SHIFT	8
#define REGION_NODE_ID_MASK	0x7f
#define get_node_id(id_reg)	(((id_reg) >> REGION_NODE_ID_SHIFT) \
				 & REGION_NODE_ID_MASK)

#define REGION_NODE_TYPE_SHIFT	0
#define REGION_NODE_TYPE_MASK	0x1f
#define get_node_type(id_reg)	(((id_reg) >> REGION_NODE_TYPE_SHIFT) \
				 & REGION_NODE_TYPE_MASK)

/* Common offsets of registers to enter or exit a snoop/dvm domain */
#define DOMAIN_CTRL_STAT_OFFSET	0x0200
#define DOMAIN_CTRL_SET_OFFSET	0x0210
#define DOMAIN_CTRL_CLR_OFFSET	0x0220

/*
 * Thess macros are used to determine if an operation to add or remove a Request
 * node from the snoop/dvm domain has completed. 'rn_id_map' is a bit map of
 * nodes. It was used to program the SET or CLEAR control register. The type of
 * register is specified by 'op_reg_offset'. 'status_reg' is the bit map of
 * nodes currently present in the snoop/dvm domain. 'rn_id_map' and 'status_reg'
 * are logically ANDed and the result it stored back in the 'status_reg'. There
 * are two outcomes of this operation:
 *
 * 1. If the DOMAIN_CTRL_SET_OFFSET register was programmed, then the set bits in
 *    'rn_id_map' should appear in 'status_reg' when the operation completes. So
 *    after the AND operation, at some point of time 'status_reg' should equal
 *    'rn_id_map'.
 *
 * 2. If the DOMAIN_CTRL_CLR_OFFSET register was programmed, then the set bits in
 *    'rn_id_map' should disappear in 'status_reg' when the operation
 *    completes. So after the AND operation, at some point of time 'status_reg'
 *    should equal 0.
 */
#define WAIT_FOR_DOMAIN_CTRL_OP_COMPLETION(region_id, stat_reg_offset,		\
					   op_reg_offset, rn_id_map)		\
	{									\
		unsigned long long status_reg;						\
		do {								\
			status_reg = ccn_reg_read((ccn_plat_desc->periphbase),	\
						  (region_id),			\
						  (stat_reg_offset));		\
			status_reg &= (rn_id_map);				\
		} while ((op_reg_offset) == DOMAIN_CTRL_SET_OFFSET ?		\
			 (rn_id_map) != status_reg : status_reg);		\
	}

/*
 * Region ID of the Miscellaneous Node is always 0 as its located at the base of
 * the programmer's view.
 */
#define MN_REGION_ID		0

#define MN_REGION_ID_START	0
#define DEBUG_REGION_ID_START	1
#define HNI_REGION_ID_START	8
#define SBSX_REGION_ID_START	16
#define HNF_REGION_ID_START	32
#define XP_REGION_ID_START	64
#define RNI_REGION_ID_START	128

/* Selected register offsets from the base of a HNF region */
#define HNF_CFG_CTRL_OFFSET	0x0000
#define HNF_SAM_CTRL_OFFSET	0x0008
#define HNF_PSTATE_REQ_OFFSET	0x0010
#define HNF_PSTATE_STAT_OFFSET	0x0018
#define HNF_SDC_STAT_OFFSET	DOMAIN_CTRL_STAT_OFFSET
#define HNF_SDC_SET_OFFSET	DOMAIN_CTRL_SET_OFFSET
#define HNF_SDC_CLR_OFFSET	DOMAIN_CTRL_CLR_OFFSET
#define HNF_AUX_CTRL_OFFSET	0x0500

/* Selected register offsets from the base of a MN region */
#define MN_SAR_OFFSET		0x0000
#define MN_RNF_NODEID_OFFSET	0x0180
#define MN_RNI_NODEID_OFFSET	0x0190
#define MN_RND_NODEID_OFFSET	0x01A0
#define MN_HNF_NODEID_OFFSET	0x01B0
#define MN_HNI_NODEID_OFFSET	0x01C0
#define MN_SN_NODEID_OFFSET	0x01D0
#define MN_DDC_STAT_OFFSET	DOMAIN_CTRL_STAT_OFFSET
#define MN_DDC_SET_OFFSET	DOMAIN_CTRL_SET_OFFSET
#define MN_DDC_CLR_OFFSET	DOMAIN_CTRL_CLR_OFFSET
#define MN_PERIPH_ID_0_1_OFFSET	0xFE0
#define MN_ID_OFFSET		REGION_ID_OFFSET

/* HNF System Address Map register bit masks and shifts */
#define HNF_SAM_CTRL_SN_ID_MASK		0x7f
#define HNF_SAM_CTRL_SN0_ID_SHIFT	0
#define HNF_SAM_CTRL_SN1_ID_SHIFT	8
#define HNF_SAM_CTRL_SN2_ID_SHIFT	16

#define HNF_SAM_CTRL_TAB0_MASK		0x3fUL
#define HNF_SAM_CTRL_TAB0_SHIFT		48
#define HNF_SAM_CTRL_TAB1_MASK		0x3fUL
#define HNF_SAM_CTRL_TAB1_SHIFT		56

#define HNF_SAM_CTRL_3SN_ENB_SHIFT	32
#define HNF_SAM_CTRL_3SN_ENB_MASK	0x01UL

/*
 * Macro to create a value suitable for programming into a HNF SAM Control
 * register for enabling 3SN striping.
 */
#define MAKE_HNF_SAM_CTRL_VALUE(sn0, sn1, sn2, tab0, tab1, three_sn_en)     \
	((((sn0) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN0_ID_SHIFT) | \
	 (((sn1) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN1_ID_SHIFT) | \
	 (((sn2) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN2_ID_SHIFT) | \
	 (((tab0) & HNF_SAM_CTRL_TAB0_MASK) << HNF_SAM_CTRL_TAB0_SHIFT)   | \
	 (((tab1) & HNF_SAM_CTRL_TAB1_MASK) << HNF_SAM_CTRL_TAB1_SHIFT)   | \
	 (((three_sn_en) & HNF_SAM_CTRL_3SN_ENB_MASK) << HNF_SAM_CTRL_3SN_ENB_SHIFT))

/* Mask to read the power state value from an HN-F P-state register */
#define HNF_PSTATE_MASK		0xf

/* Macro to extract the run mode from a p-state value */
#define PSTATE_TO_RUN_MODE(pstate)	(((pstate) & HNF_PSTATE_MASK) >> 2)

/*
 * Helper macro that iterates through a given bit map. In each iteration,
 * it returns the position of the set bit.
 * It can be used by other utility macros to iterates through all nodes
 * or masters given a bit map of them.
 */
#define FOR_EACH_BIT(bit_pos, bit_map)			\
	for (bit_pos = __builtin_ctzll(bit_map);	\
	     bit_map;					\
	     bit_map &= ~(1UL << bit_pos),		\
	     bit_pos = __builtin_ctzll(bit_map))

/*
 * Utility macro that iterates through a bit map of node IDs. In each
 * iteration, it returns the ID of the next present node in the bit map. Node
 * ID of a present node == Position of set bit == Number of zeroes trailing the
 * bit.
 */
#define FOR_EACH_PRESENT_NODE_ID(node_id, bit_map)	\
		FOR_EACH_BIT(node_id, bit_map)

/*
 * Helper function to return number of set bits in bitmap
 */
static inline unsigned int count_set_bits(unsigned long long bitmap)
{
	unsigned int count = 0;

	for (; bitmap; bitmap &= bitmap - 1)
		++count;

	return count;
}

/*
 * Utility macro that iterates through a bit map of node IDs. In each iteration,
 * it returns the ID of the next present region corresponding to a node present
 * in the bit map. Region ID of a present node is in between passed region id
 * and region id + number of set bits in the bitmap i.e. the number of present
 * nodes.
 */
#define FOR_EACH_PRESENT_REGION_ID(region_id, bit_map)				\
	for (unsigned long long region_id_limit = count_set_bits(bit_map)	\
							+ region_id;		\
	    region_id < region_id_limit;					\
	    region_id++)

/*
 * Same macro as FOR_EACH_PRESENT_NODE, but renamed to indicate it traverses
 * through a bit map of master interfaces.
 */
#define FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id, bit_map)	\
			FOR_EACH_BIT(iface_id, bit_map)

/*
 * Macro that returns the node id bit map for the Miscellaneous Node
 */
#define CCN_GET_MN_NODEID_MAP(periphbase)				\
	(1 << get_node_id(ccn_reg_read(periphbase, MN_REGION_ID,	\
						REGION_ID_OFFSET)))

/*
 * This macro returns the bitmap of Home nodes on the basis of the
 * 'mn_hn_id_reg_offset' parameter from the Miscellaneous node's (MN)
 * programmer's view. The MN has a register which carries the bitmap of present
 * Home nodes of each type i.e. HN-Fs, HN-Is & HN-Ds.
 */
#define CCN_GET_HN_NODEID_MAP(periphbase, mn_hn_id_reg_offset)		\
	ccn_reg_read(periphbase, MN_REGION_ID, mn_hn_id_reg_offset)

#endif /* __CCN_PRIVATE_H__ */