blob: 0574cfdf78d432ee31356c8f9bca13b83ea164c1 [file] [log] [blame]
// SPDX-License-Identifier: BSD-Source-Code
/*
* Copyright (c) 2013, Atmel Corporation
* Copyright (c) 2017, Timesys Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <arm32.h>
#include <io.h>
#include <sama5d2.h>
#include <platform_config.h>
#include <stdint.h>
#include <matrix.h>
#include <tz_matrix.h>
#include <trace.h>
#define MATRIX_AXIMX 1
#define MATRIX_H64MX 2
#define MATRIX_H32MX 3
#define SECURITY_TYPE_AS 1
#define SECURITY_TYPE_NS 2
#define SECURITY_TYPE_PS 3
struct peri_security {
unsigned int peri_id;
unsigned int matrix;
unsigned int security_type;
};
static const struct peri_security peri_security_array[] = {
/*
* AT91C_ID_1 - This is a undocumented bit in the datasheet.
* However needs to be set for Linux to boot in "normal world"
*/
{
.peri_id = AT91C_ID_1,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_ARM,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_PIT,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_WDT,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_GMAC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_XDMAC0,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_XDMAC1,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_ICM,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_AES,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_AESB,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_TDES,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SHA,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_MPDDRC,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_MATRIX1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_MATRIX0,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_SECUMOD,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_HSMC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_PIOA,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_FLEXCOM0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_FLEXCOM1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_FLEXCOM2,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_FLEXCOM3,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_FLEXCOM4,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_UART0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_UART1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_UART2,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_UART3,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_UART4,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_TWI0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_TWI1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SDMMC0,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SDMMC1,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SPI0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SPI1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_TC0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_TC1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_PWM,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_ADC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_UHPHS,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_UDPHS,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SSC0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SSC1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_LCDC,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_ISI,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_TRNG,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_PDMIC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_IRQ,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_NS,
},
{
.peri_id = AT91C_ID_SFC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SECURAM,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_QSPI0,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_QSPI1,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_I2SC0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_I2SC1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_CAN0_INT0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_CAN1_INT0,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_CLASSD,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SFR,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SAIC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_AIC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_NS,
},
{
.peri_id = AT91C_ID_L2CC,
.matrix = MATRIX_H64MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_CAN0_INT1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_CAN1_INT1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_GMAC_Q1,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_GMAC_Q2,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_PIOB,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_PIOC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_PIOD,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_AS,
},
{
.peri_id = AT91C_ID_SDMMC0_TIMER,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SDMMC1_TIMER,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SYS,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_ACC,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_RXLP,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_SFRBU,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
{
.peri_id = AT91C_ID_CHIPID,
.matrix = MATRIX_H32MX,
.security_type = SECURITY_TYPE_PS,
},
};
static void matrix_write(unsigned int base,
unsigned int offset,
const unsigned int value)
{
io_write32(offset + base, value);
}
static unsigned int matrix_read(int base, unsigned int offset)
{
return io_read32(offset + base);
}
void matrix_write_protect_enable(unsigned int matrix_base)
{
matrix_write(matrix_base, MATRIX_WPMR,
(MATRIX_WPMR_WPKEY_PASSWD | MATRIX_WPMR_WPEN_ENABLE));
}
void matrix_write_protect_disable(unsigned int matrix_base)
{
matrix_write(matrix_base, MATRIX_WPMR, MATRIX_WPMR_WPKEY_PASSWD);
}
void matrix_configure_slave_security(unsigned int matrix_base,
unsigned int slave,
unsigned int srtop_setting,
unsigned int srsplit_setting,
unsigned int ssr_setting)
{
matrix_write(matrix_base, MATRIX_SSR(slave), ssr_setting);
matrix_write(matrix_base, MATRIX_SRTSR(slave), srtop_setting);
matrix_write(matrix_base, MATRIX_SASSR(slave), srsplit_setting);
}
static const struct peri_security *get_peri_security(unsigned int peri_id)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(peri_security_array); i++) {
if (peri_id == peri_security_array[i].peri_id)
return &peri_security_array[i];
}
return NULL;
}
static int matrix_set_peri_security(unsigned int matrix, unsigned int peri_id)
{
unsigned int base;
unsigned int spselr;
unsigned int idx;
unsigned int bit;
idx = peri_id / 32;
if (idx > 3)
return -1;
bit = (0x01 << (peri_id % 32));
/* The Peripheral ID to SPSELR register bit mapping breaks at ID 73 */
if (peri_id > AT91C_ID_SDMMC1_TIMER)
bit = bit >> 1;
if (matrix == MATRIX_H32MX)
base = matrix32_base();
else if (matrix == MATRIX_H64MX)
base = matrix64_base();
else
return -1;
spselr = matrix_read(base, MATRIX_SPSELR(idx));
spselr |= bit;
matrix_write(base, MATRIX_SPSELR(idx), spselr);
return 0;
}
int matrix_configure_peri_security(unsigned int *peri_id_array,
unsigned int size)
{
unsigned int i;
unsigned int *peri_id_p;
unsigned int matrix;
unsigned int peri_id;
const struct peri_security *peripheral_sec;
int ret;
if (!peri_id_array || !size)
return -1;
peri_id_p = peri_id_array;
for (i = 0; i < size; i++) {
peripheral_sec = get_peri_security(*peri_id_p);
if (!peripheral_sec)
return -1;
if (peripheral_sec->security_type != SECURITY_TYPE_PS)
return -1;
matrix = peripheral_sec->matrix;
peri_id = *peri_id_p;
ret = matrix_set_peri_security(matrix, peri_id);
if (ret)
return -1;
peri_id_p++;
}
return 0;
}