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