mirror of
https://github.com/CTCaer/switch-l4t-atf.git
synced 2024-12-14 14:18:43 +00:00
gic/gic600: add support for multichip configuration
Add support to configure GIC-600's multichip routing table registers. Introduce a new gic600 multichip structure in order to support platforms to pass their GIC-600 multichip information such as routing table owner, SPI blocks ownership. This driver is currently experimental and the driver api may change in the future. Change-Id: Id409d0bc07843e271ead3fc2f6e3cb38b317878d Signed-off-by: Vijayenthiran Subramaniam <vijayenthiran.subramaniam@arm.com>
This commit is contained in:
parent
74c2124400
commit
fcc337cf49
240
drivers/arm/gic/v3/gic600_multichip.c
Normal file
240
drivers/arm/gic/v3/gic600_multichip.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Arm Limited. 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/gicv3.h>
|
||||
#include <drivers/arm/gic600_multichip.h>
|
||||
|
||||
#include "gic600_multichip_private.h"
|
||||
#include "../common/gic_common_private.h"
|
||||
|
||||
#warning "GIC-600 Multichip driver is currently experimental and the API may change in future."
|
||||
|
||||
/*******************************************************************************
|
||||
* 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-- == 0) {
|
||||
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 intiating 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;
|
||||
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;
|
||||
}
|
||||
|
||||
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(chip_addr, spi_block_min, spi_blocks)) |
|
||||
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 = 0; i < multichip_data->chip_count; i++) {
|
||||
spi_id_min = multichip_data->spi_ids[i][SPI_MIN_INDEX];
|
||||
spi_id_max = multichip_data->spi_ids[i][SPI_MAX_INDEX];
|
||||
|
||||
if ((spi_id_min != 0) || (spi_id_max != 0)) {
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Intialize GIC-600 Multichip operation.
|
||||
******************************************************************************/
|
||||
void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
gic600_multichip_validate_data(multichip_data);
|
||||
|
||||
INFO("GIC-600 Multichip driver is experimental\n");
|
||||
|
||||
/*
|
||||
* 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_MIN_INDEX],
|
||||
multichip_data->
|
||||
spi_ids[multichip_data->rt_owner][SPI_MAX_INDEX]);
|
||||
|
||||
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_MIN_INDEX],
|
||||
multichip_data->spi_ids[i][SPI_MAX_INDEX]);
|
||||
}
|
||||
}
|
97
drivers/arm/gic/v3/gic600_multichip_private.h
Normal file
97
drivers/arm/gic/v3/gic600_multichip_private.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef GIC600_MULTICHIP_PRIVATE_H
|
||||
#define GIC600_MULTICHIP_PRIVATE_H
|
||||
|
||||
#include <drivers/arm/gic600_multichip.h>
|
||||
|
||||
#include "gicv3_private.h"
|
||||
|
||||
/* GIC600 GICD multichip related offsets */
|
||||
#define GICD_CHIPSR U(0xC000)
|
||||
#define GICD_DCHIPR U(0xC004)
|
||||
#define GICD_CHIPR U(0xC008)
|
||||
|
||||
/* GIC600 GICD multichip related masks */
|
||||
#define GICD_CHIPRx_PUP_BIT BIT_64(1)
|
||||
#define GICD_CHIPRx_SOCKET_STATE BIT_64(0)
|
||||
#define GICD_DCHIPR_PUP_BIT BIT_32(0)
|
||||
#define GICD_CHIPSR_RTS_MASK (BIT_32(4) | BIT_32(5))
|
||||
|
||||
/* GIC600 GICD multichip related shifts */
|
||||
#define GICD_CHIPRx_ADDR_SHIFT 16
|
||||
#define GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT 10
|
||||
#define GICD_CHIPRx_SPI_BLOCKS_SHIFT 5
|
||||
#define GICD_CHIPSR_RTS_SHIFT 4
|
||||
#define GICD_DCHIPR_RT_OWNER_SHIFT 4
|
||||
|
||||
#define GICD_CHIPSR_RTS_STATE_DISCONNECTED U(0)
|
||||
#define GICD_CHIPSR_RTS_STATE_UPDATING U(1)
|
||||
#define GICD_CHIPSR_RTS_STATE_CONSISTENT U(2)
|
||||
|
||||
/* SPI interrupt id minimum and maximum range */
|
||||
#define GIC600_SPI_ID_MIN 32
|
||||
#define GIC600_SPI_ID_MAX 960
|
||||
|
||||
/* Number of retries for PUP update */
|
||||
#define GICD_PUP_UPDATE_RETRIES 10000
|
||||
|
||||
#define SPI_MIN_INDEX 0
|
||||
#define SPI_MAX_INDEX 1
|
||||
|
||||
#define SPI_BLOCK_MIN_VALUE(spi_id_min) \
|
||||
(((spi_id_min) - GIC600_SPI_ID_MIN) / \
|
||||
GIC600_SPI_ID_MIN)
|
||||
#define SPI_BLOCKS_VALUE(spi_id_min, spi_id_max) \
|
||||
(((spi_id_max) - (spi_id_min) + 1) / \
|
||||
GIC600_SPI_ID_MIN)
|
||||
#define GICD_CHIPR_VALUE(chip_addr, spi_block_min, spi_blocks) \
|
||||
(((chip_addr) << GICD_CHIPRx_ADDR_SHIFT) | \
|
||||
((spi_block_min) << GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT) | \
|
||||
((spi_blocks) << GICD_CHIPRx_SPI_BLOCKS_SHIFT))
|
||||
|
||||
/*
|
||||
* Multichip data assertion macros
|
||||
*/
|
||||
/* Set bits from 0 to ((spi_id_max + 1) / 32) */
|
||||
#define SPI_BLOCKS_TILL_MAX(spi_id_max) ((1 << (((spi_id_max) + 1) >> 5)) - 1)
|
||||
/* Set bits from 0 to (spi_id_min / 32) */
|
||||
#define SPI_BLOCKS_TILL_MIN(spi_id_min) ((1 << ((spi_id_min) >> 5)) - 1)
|
||||
/* Set bits from (spi_id_min / 32) to ((spi_id_max + 1) / 32) */
|
||||
#define BLOCKS_OF_32(spi_id_min, spi_id_max) \
|
||||
SPI_BLOCKS_TILL_MAX(spi_id_max) ^ \
|
||||
SPI_BLOCKS_TILL_MIN(spi_id_min)
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC-600 multichip operation related helper functions
|
||||
******************************************************************************/
|
||||
static inline uint32_t read_gicd_dchipr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICD_DCHIPR);
|
||||
}
|
||||
|
||||
static inline uint64_t read_gicd_chipr_n(uintptr_t base, uint8_t n)
|
||||
{
|
||||
return mmio_read_64(base + (GICD_CHIPR + (8U * n)));
|
||||
}
|
||||
|
||||
static inline uint32_t read_gicd_chipsr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICD_CHIPSR);
|
||||
}
|
||||
|
||||
static inline void write_gicd_dchipr(uintptr_t base, uint32_t val)
|
||||
{
|
||||
mmio_write_32(base + GICD_DCHIPR, val);
|
||||
}
|
||||
|
||||
static inline void write_gicd_chipr_n(uintptr_t base, uint8_t n, uint64_t val)
|
||||
{
|
||||
mmio_write_64(base + (GICD_CHIPR + (8U * n)), val);
|
||||
}
|
||||
|
||||
#endif /* GIC600_MULTICHIP_PRIVATE_H */
|
55
include/drivers/arm/gic600_multichip.h
Normal file
55
include/drivers/arm/gic600_multichip.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2019, ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef GIC600_MULTICHIP_H
|
||||
#define GIC600_MULTICHIP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* GIC-600 microarchitecture supports coherent multichip environments containing
|
||||
* up to 16 chips.
|
||||
*/
|
||||
#define GIC600_MAX_MULTICHIP 16
|
||||
|
||||
/* SPI IDs array consist of min and max ids */
|
||||
#define GIC600_SPI_IDS_SIZE 2
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC-600 multichip data structure describes platform specific attributes
|
||||
* related to GIC-600 multichip. Platform port is expected to define these
|
||||
* attributes to initialize the multichip related registers and create
|
||||
* successful connections between the GIC-600s in a multichip system.
|
||||
*
|
||||
* The 'rt_owner_base' field contains the base address of the GIC Distributor
|
||||
* which owns the routing table.
|
||||
*
|
||||
* The 'rt_owner' field contains the chip number which owns the routing table.
|
||||
* Chip number or chip_id starts from 0.
|
||||
*
|
||||
* The 'chip_count' field contains the total number of chips in a multichip
|
||||
* system. This should match the number of entries in 'chip_addrs' and 'spi_ids'
|
||||
* fields.
|
||||
*
|
||||
* The 'chip_addrs' field contains array of chip addresses. These addresses are
|
||||
* implementation specific values.
|
||||
*
|
||||
* The 'spi_ids' field contains array of minimum and maximum SPI interrupt ids
|
||||
* that each chip owns. Note that SPI interrupt ids can range from 32 to 960 and
|
||||
* it should be group of 32 (i.e., SPI minimum and (SPI maximum + 1) should be
|
||||
* a multiple of 32). If a chip doesn't own any SPI interrupts a value of {0, 0}
|
||||
* should be passed.
|
||||
******************************************************************************/
|
||||
struct gic600_multichip_data {
|
||||
uintptr_t rt_owner_base;
|
||||
unsigned int rt_owner;
|
||||
unsigned int chip_count;
|
||||
uint64_t chip_addrs[GIC600_MAX_MULTICHIP];
|
||||
unsigned int spi_ids[GIC600_MAX_MULTICHIP][GIC600_SPI_IDS_SIZE];
|
||||
};
|
||||
|
||||
void gic600_multichip_init(struct gic600_multichip_data *multichip_data);
|
||||
#endif /* GIC600_MULTICHIP_H */
|
Loading…
Reference in New Issue
Block a user