123e47edeSVikram Kanigiri /*
2d7b5f408SJimmy Brisson * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
323e47edeSVikram Kanigiri *
482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause
523e47edeSVikram Kanigiri */
623e47edeSVikram Kanigiri
723e47edeSVikram Kanigiri #include <assert.h>
84213e9baSAntonio Nino Diaz #include <stdbool.h>
902462972SJuan Castillo #include <stdint.h>
1023e47edeSVikram Kanigiri
1109d40e0eSAntonio Nino Diaz #include <arch.h>
1209d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
1309d40e0eSAntonio Nino Diaz #include <common/debug.h>
1409d40e0eSAntonio Nino Diaz #include <drivers/arm/cci.h>
1509d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
1609d40e0eSAntonio Nino Diaz
174213e9baSAntonio Nino Diaz #define MAKE_CCI_PART_NUMBER(hi, lo) (((hi) << 8) | (lo))
184213e9baSAntonio Nino Diaz #define CCI_PART_LO_MASK U(0xff)
194213e9baSAntonio Nino Diaz #define CCI_PART_HI_MASK U(0xf)
20e33fd445SJeenu Viswambharan
21e33fd445SJeenu Viswambharan /* CCI part number codes read from Peripheral ID registers 0 and 1 */
22e33fd445SJeenu Viswambharan #define CCI400_PART_NUM 0x420
23e33fd445SJeenu Viswambharan #define CCI500_PART_NUM 0x422
24e33fd445SJeenu Viswambharan #define CCI550_PART_NUM 0x423
25e33fd445SJeenu Viswambharan
26e33fd445SJeenu Viswambharan #define CCI400_SLAVE_PORTS 5
27e33fd445SJeenu Viswambharan #define CCI500_SLAVE_PORTS 7
28e33fd445SJeenu Viswambharan #define CCI550_SLAVE_PORTS 7
29e33fd445SJeenu Viswambharan
30e33fd445SJeenu Viswambharan static uintptr_t cci_base;
31e33fd445SJeenu Viswambharan static const int *cci_slave_if_map;
3223e47edeSVikram Kanigiri
33aa61368eSAntonio Nino Diaz #if ENABLE_ASSERTIONS
343d7caf47SMaheedhar Bollapalli static size_t max_master_id;
35e33fd445SJeenu Viswambharan static int cci_num_slave_ports;
36e33fd445SJeenu Viswambharan
validate_cci_map(const int * map)374213e9baSAntonio Nino Diaz static bool validate_cci_map(const int *map)
3823e47edeSVikram Kanigiri {
394213e9baSAntonio Nino Diaz unsigned int valid_cci_map = 0U;
4023e47edeSVikram Kanigiri int slave_if_id;
413d7caf47SMaheedhar Bollapalli size_t i;
4223e47edeSVikram Kanigiri
4323e47edeSVikram Kanigiri /* Validate the map */
444213e9baSAntonio Nino Diaz for (i = 0U; i <= max_master_id; i++) {
4523e47edeSVikram Kanigiri slave_if_id = map[i];
4623e47edeSVikram Kanigiri
47*21b7d860SSaivardhan Thatikonda if (slave_if_id < 0) {
4823e47edeSVikram Kanigiri continue;
49*21b7d860SSaivardhan Thatikonda }
5023e47edeSVikram Kanigiri
51e33fd445SJeenu Viswambharan if (slave_if_id >= cci_num_slave_ports) {
5238aecbb4SAntonio Nino Diaz ERROR("Slave interface ID is invalid\n");
534213e9baSAntonio Nino Diaz return false;
5423e47edeSVikram Kanigiri }
5523e47edeSVikram Kanigiri
56d7b5f408SJimmy Brisson if ((valid_cci_map & (1UL << slave_if_id)) != 0U) {
5738aecbb4SAntonio Nino Diaz ERROR("Multiple masters are assigned same slave interface ID\n");
584213e9baSAntonio Nino Diaz return false;
5923e47edeSVikram Kanigiri }
60d7b5f408SJimmy Brisson valid_cci_map |= 1UL << slave_if_id;
6123e47edeSVikram Kanigiri }
6223e47edeSVikram Kanigiri
634213e9baSAntonio Nino Diaz if (valid_cci_map == 0U) {
6438aecbb4SAntonio Nino Diaz ERROR("No master is assigned a valid slave interface\n");
654213e9baSAntonio Nino Diaz return false;
6623e47edeSVikram Kanigiri }
6723e47edeSVikram Kanigiri
684213e9baSAntonio Nino Diaz return true;
6923e47edeSVikram Kanigiri }
70e33fd445SJeenu Viswambharan
71e33fd445SJeenu Viswambharan /*
72e33fd445SJeenu Viswambharan * Read CCI part number from Peripheral ID registers
73e33fd445SJeenu Viswambharan */
read_cci_part_number(uintptr_t base)74e33fd445SJeenu Viswambharan static unsigned int read_cci_part_number(uintptr_t base)
75e33fd445SJeenu Viswambharan {
76e33fd445SJeenu Viswambharan unsigned int part_lo, part_hi;
77e33fd445SJeenu Viswambharan
78e33fd445SJeenu Viswambharan part_lo = mmio_read_32(base + PERIPHERAL_ID0) & CCI_PART_LO_MASK;
79e33fd445SJeenu Viswambharan part_hi = mmio_read_32(base + PERIPHERAL_ID1) & CCI_PART_HI_MASK;
80e33fd445SJeenu Viswambharan
81e33fd445SJeenu Viswambharan return MAKE_CCI_PART_NUMBER(part_hi, part_lo);
82e33fd445SJeenu Viswambharan }
83e33fd445SJeenu Viswambharan
84e33fd445SJeenu Viswambharan /*
85e33fd445SJeenu Viswambharan * Identify a CCI device, and return the number of slaves. Return -1 for an
86e33fd445SJeenu Viswambharan * unidentified device.
87e33fd445SJeenu Viswambharan */
get_slave_ports(unsigned int part_num)88e33fd445SJeenu Viswambharan static int get_slave_ports(unsigned int part_num)
89e33fd445SJeenu Viswambharan {
905aa7498aSJonathan Wright int num_slave_ports = -1;
91e33fd445SJeenu Viswambharan
92e33fd445SJeenu Viswambharan switch (part_num) {
93e33fd445SJeenu Viswambharan
945aa7498aSJonathan Wright case CCI400_PART_NUM:
955aa7498aSJonathan Wright num_slave_ports = CCI400_SLAVE_PORTS;
965aa7498aSJonathan Wright break;
975aa7498aSJonathan Wright case CCI500_PART_NUM:
985aa7498aSJonathan Wright num_slave_ports = CCI500_SLAVE_PORTS;
995aa7498aSJonathan Wright break;
1005aa7498aSJonathan Wright case CCI550_PART_NUM:
1015aa7498aSJonathan Wright num_slave_ports = CCI550_SLAVE_PORTS;
1025aa7498aSJonathan Wright break;
103e33fd445SJeenu Viswambharan default:
1045aa7498aSJonathan Wright /* Do nothing in default case */
1055aa7498aSJonathan Wright break;
106e33fd445SJeenu Viswambharan }
107e33fd445SJeenu Viswambharan
1085aa7498aSJonathan Wright return num_slave_ports;
109e33fd445SJeenu Viswambharan }
110aa61368eSAntonio Nino Diaz #endif /* ENABLE_ASSERTIONS */
11123e47edeSVikram Kanigiri
cci_init(uintptr_t base,const int * map,size_t num_cci_masters)112c9263e62SDaniel Boulby void __init cci_init(uintptr_t base, const int *map,
1133d7caf47SMaheedhar Bollapalli size_t num_cci_masters)
11423e47edeSVikram Kanigiri {
1154213e9baSAntonio Nino Diaz assert(map != NULL);
1164213e9baSAntonio Nino Diaz assert(base != 0U);
11723e47edeSVikram Kanigiri
118e33fd445SJeenu Viswambharan cci_base = base;
119e33fd445SJeenu Viswambharan cci_slave_if_map = map;
12023e47edeSVikram Kanigiri
121e33fd445SJeenu Viswambharan #if ENABLE_ASSERTIONS
12223e47edeSVikram Kanigiri /*
12323e47edeSVikram Kanigiri * Master Id's are assigned from zero, So in an array of size n
12423e47edeSVikram Kanigiri * the max master id is (n - 1).
12523e47edeSVikram Kanigiri */
1264213e9baSAntonio Nino Diaz max_master_id = num_cci_masters - 1U;
127e33fd445SJeenu Viswambharan cci_num_slave_ports = get_slave_ports(read_cci_part_number(base));
128e33fd445SJeenu Viswambharan #endif
129e33fd445SJeenu Viswambharan assert(cci_num_slave_ports >= 0);
13023e47edeSVikram Kanigiri
13123e47edeSVikram Kanigiri assert(validate_cci_map(map));
13223e47edeSVikram Kanigiri }
13323e47edeSVikram Kanigiri
cci_enable_snoop_dvm_reqs(size_t master_id)1343d7caf47SMaheedhar Bollapalli void cci_enable_snoop_dvm_reqs(size_t master_id)
13523e47edeSVikram Kanigiri {
136e33fd445SJeenu Viswambharan int slave_if_id = cci_slave_if_map[master_id];
13723e47edeSVikram Kanigiri
138e33fd445SJeenu Viswambharan assert(master_id <= max_master_id);
139e33fd445SJeenu Viswambharan assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0));
1404213e9baSAntonio Nino Diaz assert(cci_base != 0U);
14123e47edeSVikram Kanigiri
14223e47edeSVikram Kanigiri /*
14323e47edeSVikram Kanigiri * Enable Snoops and DVM messages, no need for Read/Modify/Write as
14423e47edeSVikram Kanigiri * rest of bits are write ignore
14523e47edeSVikram Kanigiri */
146e33fd445SJeenu Viswambharan mmio_write_32(cci_base +
147edecc703SNithin G SLAVE_IFACE_OFFSET((u_register_t)slave_if_id) + SNOOP_CTRL_REG,
148e33fd445SJeenu Viswambharan DVM_EN_BIT | SNOOP_EN_BIT);
14923e47edeSVikram Kanigiri
150ae551a13SRoberto Vargas /*
151ae551a13SRoberto Vargas * Wait for the completion of the write to the Snoop Control Register
152ae551a13SRoberto Vargas * before testing the change_pending bit
153ae551a13SRoberto Vargas */
154fcb52dbfSRoberto Vargas dsbish();
155ae551a13SRoberto Vargas
15623e47edeSVikram Kanigiri /* Wait for the dust to settle down */
15703c6bb0eSMaheedhar Bollapalli while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U) {
15823e47edeSVikram Kanigiri ;
15923e47edeSVikram Kanigiri }
16003c6bb0eSMaheedhar Bollapalli }
16123e47edeSVikram Kanigiri
cci_disable_snoop_dvm_reqs(size_t master_id)1623d7caf47SMaheedhar Bollapalli void cci_disable_snoop_dvm_reqs(size_t master_id)
16323e47edeSVikram Kanigiri {
164e33fd445SJeenu Viswambharan int slave_if_id = cci_slave_if_map[master_id];
16523e47edeSVikram Kanigiri
166e33fd445SJeenu Viswambharan assert(master_id <= max_master_id);
167e33fd445SJeenu Viswambharan assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0));
1684213e9baSAntonio Nino Diaz assert(cci_base != 0U);
16923e47edeSVikram Kanigiri
17023e47edeSVikram Kanigiri /*
17123e47edeSVikram Kanigiri * Disable Snoops and DVM messages, no need for Read/Modify/Write as
17223e47edeSVikram Kanigiri * rest of bits are write ignore.
17323e47edeSVikram Kanigiri */
174e33fd445SJeenu Viswambharan mmio_write_32(cci_base +
175edecc703SNithin G SLAVE_IFACE_OFFSET((u_register_t)slave_if_id) + SNOOP_CTRL_REG,
176e33fd445SJeenu Viswambharan ~(DVM_EN_BIT | SNOOP_EN_BIT));
17723e47edeSVikram Kanigiri
178ae551a13SRoberto Vargas /*
179ae551a13SRoberto Vargas * Wait for the completion of the write to the Snoop Control Register
180ae551a13SRoberto Vargas * before testing the change_pending bit
181ae551a13SRoberto Vargas */
182fcb52dbfSRoberto Vargas dsbish();
183ae551a13SRoberto Vargas
18423e47edeSVikram Kanigiri /* Wait for the dust to settle down */
18503c6bb0eSMaheedhar Bollapalli while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U) {
18623e47edeSVikram Kanigiri ;
18723e47edeSVikram Kanigiri }
18803c6bb0eSMaheedhar Bollapalli }
18923e47edeSVikram Kanigiri
190