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