xref: /rk3399_ARM-atf/drivers/arm/cci/cci.c (revision 1dcc28cfbac5dae3992ad9581f9ea68f6cb339c1)
1 /*
2  * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <arch.h>
8 #include <arch_helpers.h>
9 #include <assert.h>
10 #include <cci.h>
11 #include <debug.h>
12 #include <mmio.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 
16 #define MAKE_CCI_PART_NUMBER(hi, lo)	(((hi) << 8) | (lo))
17 #define CCI_PART_LO_MASK		U(0xff)
18 #define CCI_PART_HI_MASK		U(0xf)
19 
20 /* CCI part number codes read from Peripheral ID registers 0 and 1 */
21 #define CCI400_PART_NUM		0x420
22 #define CCI500_PART_NUM		0x422
23 #define CCI550_PART_NUM		0x423
24 
25 #define CCI400_SLAVE_PORTS	5
26 #define CCI500_SLAVE_PORTS	7
27 #define CCI550_SLAVE_PORTS	7
28 
29 static uintptr_t cci_base;
30 static const int *cci_slave_if_map;
31 
32 #if ENABLE_ASSERTIONS
33 static unsigned int max_master_id;
34 static int cci_num_slave_ports;
35 
36 static bool validate_cci_map(const int *map)
37 {
38 	unsigned int valid_cci_map = 0U;
39 	int slave_if_id;
40 	unsigned int i;
41 
42 	/* Validate the map */
43 	for (i = 0U; i <= max_master_id; i++) {
44 		slave_if_id = map[i];
45 
46 		if (slave_if_id < 0)
47 			continue;
48 
49 		if (slave_if_id >= cci_num_slave_ports) {
50 			ERROR("Slave interface ID is invalid\n");
51 			return false;
52 		}
53 
54 		if ((valid_cci_map & (1U << slave_if_id)) != 0U) {
55 			ERROR("Multiple masters are assigned same slave interface ID\n");
56 			return false;
57 		}
58 		valid_cci_map |= 1U << slave_if_id;
59 	}
60 
61 	if (valid_cci_map == 0U) {
62 		ERROR("No master is assigned a valid slave interface\n");
63 		return false;
64 	}
65 
66 	return true;
67 }
68 
69 /*
70  * Read CCI part number from Peripheral ID registers
71  */
72 static unsigned int read_cci_part_number(uintptr_t base)
73 {
74 	unsigned int part_lo, part_hi;
75 
76 	part_lo = mmio_read_32(base + PERIPHERAL_ID0) & CCI_PART_LO_MASK;
77 	part_hi = mmio_read_32(base + PERIPHERAL_ID1) & CCI_PART_HI_MASK;
78 
79 	return MAKE_CCI_PART_NUMBER(part_hi, part_lo);
80 }
81 
82 /*
83  * Identify a CCI device, and return the number of slaves. Return -1 for an
84  * unidentified device.
85  */
86 static int get_slave_ports(unsigned int part_num)
87 {
88 	int num_slave_ports = -1;
89 
90 	switch (part_num) {
91 
92 	case CCI400_PART_NUM:
93 		num_slave_ports = CCI400_SLAVE_PORTS;
94 		break;
95 	case CCI500_PART_NUM:
96 		num_slave_ports = CCI500_SLAVE_PORTS;
97 		break;
98 	case CCI550_PART_NUM:
99 		num_slave_ports = CCI550_SLAVE_PORTS;
100 		break;
101 	default:
102 		/* Do nothing in default case */
103 		break;
104 	}
105 
106 	return num_slave_ports;
107 }
108 #endif /* ENABLE_ASSERTIONS */
109 
110 void cci_init(uintptr_t base, const int *map, unsigned int num_cci_masters)
111 {
112 	assert(map != NULL);
113 	assert(base != 0U);
114 
115 	cci_base = base;
116 	cci_slave_if_map = map;
117 
118 #if ENABLE_ASSERTIONS
119 	/*
120 	 * Master Id's are assigned from zero, So in an array of size n
121 	 * the max master id is (n - 1).
122 	 */
123 	max_master_id = num_cci_masters - 1U;
124 	cci_num_slave_ports = get_slave_ports(read_cci_part_number(base));
125 #endif
126 	assert(cci_num_slave_ports >= 0);
127 
128 	assert(validate_cci_map(map));
129 }
130 
131 void cci_enable_snoop_dvm_reqs(unsigned int master_id)
132 {
133 	int slave_if_id = cci_slave_if_map[master_id];
134 
135 	assert(master_id <= max_master_id);
136 	assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0));
137 	assert(cci_base != 0U);
138 
139 	/*
140 	 * Enable Snoops and DVM messages, no need for Read/Modify/Write as
141 	 * rest of bits are write ignore
142 	 */
143 	mmio_write_32(cci_base +
144 		      SLAVE_IFACE_OFFSET(slave_if_id) + SNOOP_CTRL_REG,
145 		      DVM_EN_BIT | SNOOP_EN_BIT);
146 
147 	/*
148 	 * Wait for the completion of the write to the Snoop Control Register
149 	 * before testing the change_pending bit
150 	 */
151 	dsbish();
152 
153 	/* Wait for the dust to settle down */
154 	while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U)
155 		;
156 }
157 
158 void cci_disable_snoop_dvm_reqs(unsigned int master_id)
159 {
160 	int slave_if_id = cci_slave_if_map[master_id];
161 
162 	assert(master_id <= max_master_id);
163 	assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0));
164 	assert(cci_base != 0U);
165 
166 	/*
167 	 * Disable Snoops and DVM messages, no need for Read/Modify/Write as
168 	 * rest of bits are write ignore.
169 	 */
170 	mmio_write_32(cci_base +
171 		      SLAVE_IFACE_OFFSET(slave_if_id) + SNOOP_CTRL_REG,
172 		      ~(DVM_EN_BIT | SNOOP_EN_BIT));
173 
174 	/*
175 	 * Wait for the completion of the write to the Snoop Control Register
176 	 * before testing the change_pending bit
177 	 */
178 	dsbish();
179 
180 	/* Wait for the dust to settle down */
181 	while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U)
182 		;
183 }
184 
185