123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
- * Copyright (c) 2022-2023, NVIDIA Corporation. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- /*
- * GIC-600 driver extension for multichip setup
- */
- #include <assert.h>
- #include <common/debug.h>
- #include <drivers/arm/arm_gicv3_common.h>
- #include <drivers/arm/gic600_multichip.h>
- #include <drivers/arm/gicv3.h>
- #include "../common/gic_common_private.h"
- #include "gic600_multichip_private.h"
- static struct gic600_multichip_data *plat_gic_multichip_data;
- /*******************************************************************************
- * Retrieve the address of the chip owner for a given SPI ID
- ******************************************************************************/
- uintptr_t gic600_multichip_gicd_base_for_spi(uint32_t spi_id)
- {
- unsigned int i;
- /* Find the multichip instance */
- for (i = 0U; i < GIC600_MAX_MULTICHIP; i++) {
- if ((spi_id <= plat_gic_multichip_data->spi_ids[i].spi_id_max) &&
- (spi_id >= plat_gic_multichip_data->spi_ids[i].spi_id_min)) {
- break;
- }
- }
- /* Ensure that plat_gic_multichip_data contains valid values */
- assert(i < GIC600_MAX_MULTICHIP);
- return plat_gic_multichip_data->spi_ids[i].gicd_base;
- }
- /*******************************************************************************
- * GIC-600 multichip operation related helper functions
- ******************************************************************************/
- static void gicd_dchipr_wait_for_power_update_progress(uintptr_t base)
- {
- unsigned int retry = GICD_PUP_UPDATE_RETRIES;
- while ((read_gicd_dchipr(base) & GICD_DCHIPR_PUP_BIT) != 0U) {
- if (retry-- == 0U) {
- ERROR("GIC-600 connection to Routing Table Owner timed "
- "out\n");
- panic();
- }
- }
- }
- /*******************************************************************************
- * Sets up the routing table owner.
- ******************************************************************************/
- static void set_gicd_dchipr_rt_owner(uintptr_t base, unsigned int rt_owner)
- {
- /*
- * Ensure that Group enables in GICD_CTLR are disabled and no pending
- * register writes to GICD_CTLR.
- */
- if ((gicd_read_ctlr(base) &
- (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
- CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
- ERROR("GICD_CTLR group interrupts are either enabled or have "
- "pending writes. Cannot set RT owner.\n");
- panic();
- }
- /* Poll till PUP is zero before initiating write */
- gicd_dchipr_wait_for_power_update_progress(base);
- write_gicd_dchipr(base, read_gicd_dchipr(base) |
- (rt_owner << GICD_DCHIPR_RT_OWNER_SHIFT));
- /* Poll till PUP is zero to ensure write is complete */
- gicd_dchipr_wait_for_power_update_progress(base);
- }
- /*******************************************************************************
- * Configures the Chip Register to make connections to GICDs on
- * a multichip platform.
- ******************************************************************************/
- static void set_gicd_chipr_n(uintptr_t base,
- unsigned int chip_id,
- uint64_t chip_addr,
- unsigned int spi_id_min,
- unsigned int spi_id_max)
- {
- unsigned int spi_block_min, spi_blocks;
- unsigned int gicd_iidr_val = gicd_read_iidr(base);
- uint64_t chipr_n_val;
- /*
- * Ensure that group enables in GICD_CTLR are disabled and no pending
- * register writes to GICD_CTLR.
- */
- if ((gicd_read_ctlr(base) &
- (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
- CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
- ERROR("GICD_CTLR group interrupts are either enabled or have "
- "pending writes. Cannot set CHIPR register.\n");
- panic();
- }
- /*
- * spi_id_min and spi_id_max of value 0 is used to intidicate that the
- * chip doesn't own any SPI block. Re-assign min and max values as SPI
- * id starts from 32.
- */
- if (spi_id_min == 0 && spi_id_max == 0) {
- spi_id_min = GIC600_SPI_ID_MIN;
- spi_id_max = GIC600_SPI_ID_MIN;
- }
- switch ((gicd_iidr_val & IIDR_MODEL_MASK)) {
- case IIDR_MODEL_ARM_GIC_600:
- spi_block_min = SPI_BLOCK_MIN_VALUE(spi_id_min);
- spi_blocks = SPI_BLOCKS_VALUE(spi_id_min, spi_id_max);
- chipr_n_val = GICD_CHIPR_VALUE_GIC_600(chip_addr,
- spi_block_min,
- spi_blocks);
- break;
- case IIDR_MODEL_ARM_GIC_700:
- /* Calculate the SPI_ID_MIN value for ESPI */
- if (spi_id_min >= GIC700_ESPI_ID_MIN) {
- spi_block_min = ESPI_BLOCK_MIN_VALUE(spi_id_min);
- spi_block_min += SPI_BLOCKS_VALUE(GIC700_SPI_ID_MIN,
- GIC700_SPI_ID_MAX);
- } else {
- spi_block_min = SPI_BLOCK_MIN_VALUE(spi_id_min);
- }
- /* Calculate the total number of blocks */
- spi_blocks = SPI_BLOCKS_VALUE(spi_id_min, spi_id_max);
- chipr_n_val = GICD_CHIPR_VALUE_GIC_700(chip_addr,
- spi_block_min,
- spi_blocks);
- break;
- default:
- ERROR("Unsupported GIC model 0x%x for multichip setup.\n",
- gicd_iidr_val);
- panic();
- break;
- }
- chipr_n_val |= GICD_CHIPRx_SOCKET_STATE;
- /*
- * Wait for DCHIPR.PUP to be zero before commencing writes to
- * GICD_CHIPRx.
- */
- gicd_dchipr_wait_for_power_update_progress(base);
- /*
- * Assign chip addr, spi min block, number of spi blocks and bring chip
- * online by setting SocketState.
- */
- write_gicd_chipr_n(base, chip_id, chipr_n_val);
- /*
- * Poll until DCHIP.PUP is zero to verify connection to rt_owner chip
- * is complete.
- */
- gicd_dchipr_wait_for_power_update_progress(base);
- /*
- * Ensure that write to GICD_CHIPRx is successful and the chip_n came
- * online.
- */
- if (read_gicd_chipr_n(base, chip_id) != chipr_n_val) {
- ERROR("GICD_CHIPR%u write failed\n", chip_id);
- panic();
- }
- /* Ensure that chip is in consistent state */
- if (((read_gicd_chipsr(base) & GICD_CHIPSR_RTS_MASK) >>
- GICD_CHIPSR_RTS_SHIFT) !=
- GICD_CHIPSR_RTS_STATE_CONSISTENT) {
- ERROR("Chip %u routing table is not in consistent state\n",
- chip_id);
- panic();
- }
- }
- /*******************************************************************************
- * Validates the GIC-600 Multichip data structure passed by the platform.
- ******************************************************************************/
- static void gic600_multichip_validate_data(
- struct gic600_multichip_data *multichip_data)
- {
- unsigned int i, spi_id_min, spi_id_max, blocks_of_32;
- unsigned int multichip_spi_blocks = 0;
- assert(multichip_data != NULL);
- if (multichip_data->chip_count > GIC600_MAX_MULTICHIP) {
- ERROR("GIC-600 Multichip count should not exceed %d\n",
- GIC600_MAX_MULTICHIP);
- panic();
- }
- for (i = 0U; i < multichip_data->chip_count; i++) {
- spi_id_min = multichip_data->spi_ids[i].spi_id_min;
- spi_id_max = multichip_data->spi_ids[i].spi_id_max;
- if ((spi_id_min != 0U) || (spi_id_max != 0U)) {
- /* SPI IDs range check */
- if (!(spi_id_min >= GIC600_SPI_ID_MIN) ||
- !(spi_id_max <= GIC600_SPI_ID_MAX) ||
- !(spi_id_min <= spi_id_max) ||
- !((spi_id_max - spi_id_min + 1) % 32 == 0)) {
- ERROR("Invalid SPI IDs {%u, %u} passed for "
- "Chip %u\n", spi_id_min,
- spi_id_max, i);
- panic();
- }
- /* SPI IDs overlap check */
- blocks_of_32 = BLOCKS_OF_32(spi_id_min, spi_id_max);
- if ((multichip_spi_blocks & blocks_of_32) != 0) {
- ERROR("SPI IDs of Chip %u overlapping\n", i);
- panic();
- }
- multichip_spi_blocks |= blocks_of_32;
- }
- }
- }
- /*******************************************************************************
- * Validates the GIC-700 Multichip data structure passed by the platform.
- ******************************************************************************/
- static void gic700_multichip_validate_data(
- struct gic600_multichip_data *multichip_data)
- {
- unsigned int i, spi_id_min, spi_id_max, blocks_of_32;
- unsigned int multichip_spi_blocks = 0U, multichip_espi_blocks = 0U;
- assert(multichip_data != NULL);
- if (multichip_data->chip_count > GIC600_MAX_MULTICHIP) {
- ERROR("GIC-700 Multichip count (%u) should not exceed %u\n",
- multichip_data->chip_count, GIC600_MAX_MULTICHIP);
- panic();
- }
- for (i = 0U; i < multichip_data->chip_count; i++) {
- spi_id_min = multichip_data->spi_ids[i].spi_id_min;
- spi_id_max = multichip_data->spi_ids[i].spi_id_max;
- if ((spi_id_min == 0U) || (spi_id_max == 0U)) {
- continue;
- }
- /* MIN SPI ID check */
- if ((spi_id_min < GIC700_SPI_ID_MIN) ||
- ((spi_id_min >= GIC700_SPI_ID_MAX) &&
- (spi_id_min < GIC700_ESPI_ID_MIN))) {
- ERROR("Invalid MIN SPI ID {%u} passed for "
- "Chip %u\n", spi_id_min, i);
- panic();
- }
- if ((spi_id_min > spi_id_max) ||
- ((spi_id_max - spi_id_min + 1) % 32 != 0)) {
- ERROR("Unaligned SPI IDs {%u, %u} passed for "
- "Chip %u\n", spi_id_min,
- spi_id_max, i);
- panic();
- }
- /* ESPI IDs range check */
- if ((spi_id_min >= GIC700_ESPI_ID_MIN) &&
- (spi_id_max > GIC700_ESPI_ID_MAX)) {
- ERROR("Invalid ESPI IDs {%u, %u} passed for "
- "Chip %u\n", spi_id_min,
- spi_id_max, i);
- panic();
- }
- /* SPI IDs range check */
- if (((spi_id_min < GIC700_SPI_ID_MAX) &&
- (spi_id_max > GIC700_SPI_ID_MAX))) {
- ERROR("Invalid SPI IDs {%u, %u} passed for "
- "Chip %u\n", spi_id_min,
- spi_id_max, i);
- panic();
- }
- /* SPI IDs overlap check */
- if (spi_id_max < GIC700_SPI_ID_MAX) {
- blocks_of_32 = BLOCKS_OF_32(spi_id_min, spi_id_max);
- if ((multichip_spi_blocks & blocks_of_32) != 0) {
- ERROR("SPI IDs of Chip %u overlapping\n", i);
- panic();
- }
- multichip_spi_blocks |= blocks_of_32;
- }
- /* ESPI IDs overlap check */
- if (spi_id_max > GIC700_ESPI_ID_MIN) {
- blocks_of_32 = BLOCKS_OF_32(spi_id_min - GIC700_ESPI_ID_MIN,
- spi_id_max - GIC700_ESPI_ID_MIN);
- if ((multichip_espi_blocks & blocks_of_32) != 0) {
- ERROR("SPI IDs of Chip %u overlapping\n", i);
- panic();
- }
- multichip_espi_blocks |= blocks_of_32;
- }
- }
- }
- /*******************************************************************************
- * Initialize GIC-600 and GIC-700 Multichip operation.
- ******************************************************************************/
- void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
- {
- unsigned int i;
- uint32_t gicd_iidr_val = gicd_read_iidr(multichip_data->rt_owner_base);
- if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) {
- gic600_multichip_validate_data(multichip_data);
- }
- if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700) {
- gic700_multichip_validate_data(multichip_data);
- }
- /*
- * Ensure that G0/G1S/G1NS interrupts are disabled. This also ensures
- * that GIC-600 Multichip configuration is done first.
- */
- if ((gicd_read_ctlr(multichip_data->rt_owner_base) &
- (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
- CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
- ERROR("GICD_CTLR group interrupts are either enabled or have "
- "pending writes.\n");
- panic();
- }
- /* Ensure that the routing table owner is in disconnected state */
- if (((read_gicd_chipsr(multichip_data->rt_owner_base) &
- GICD_CHIPSR_RTS_MASK) >> GICD_CHIPSR_RTS_SHIFT) !=
- GICD_CHIPSR_RTS_STATE_DISCONNECTED) {
- ERROR("GIC-600 routing table owner is not in disconnected "
- "state to begin multichip configuration\n");
- panic();
- }
- /* Initialize the GICD which is marked as routing table owner first */
- set_gicd_dchipr_rt_owner(multichip_data->rt_owner_base,
- multichip_data->rt_owner);
- set_gicd_chipr_n(multichip_data->rt_owner_base, multichip_data->rt_owner,
- multichip_data->chip_addrs[multichip_data->rt_owner],
- multichip_data->
- spi_ids[multichip_data->rt_owner].spi_id_min,
- multichip_data->
- spi_ids[multichip_data->rt_owner].spi_id_max);
- for (i = 0; i < multichip_data->chip_count; i++) {
- if (i == multichip_data->rt_owner)
- continue;
- set_gicd_chipr_n(multichip_data->rt_owner_base, i,
- multichip_data->chip_addrs[i],
- multichip_data->spi_ids[i].spi_id_min,
- multichip_data->spi_ids[i].spi_id_max);
- }
- plat_gic_multichip_data = multichip_data;
- }
- /*******************************************************************************
- * Allow a way to query the status of the GIC600 multichip driver
- ******************************************************************************/
- bool gic600_multichip_is_initialized(void)
- {
- return (plat_gic_multichip_data != NULL);
- }
|