diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 9ba677b2ac..c84284c533 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -791,6 +791,12 @@ config MPFS_ETHMAC_REGDEBUG endmenu +config MPFS_MPUCFG + bool "Enable MPUCFG driver" + default n + ---help--- + Enable driver to set MPUCFG entries. + config MPFS_HAVE_CORERMII bool "CoreRMII FPGA IP block configured" default n diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index 6e060cef60..60f7fef85c 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -108,3 +108,7 @@ ifeq ($(CONFIG_MPFS_CORESPI),y) CHIP_CSRCS += mpfs_corespi.c endif +ifeq ($(CONFIG_MPFS_MPUCFG),y) +CHIP_CSRCS += mpfs_mpu.c +endif + diff --git a/arch/risc-v/src/mpfs/mpfs_mpu.c b/arch/risc-v/src/mpfs/mpfs_mpu.c new file mode 100644 index 0000000000..58bc30f4e8 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_mpu.c @@ -0,0 +1,243 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_mpu.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include + +#include "riscv_internal.h" +#include "mpfs_memorymap.h" + +#include "hardware/mpfs_mpucfg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* MPUCFG entry is 64-bits */ + +#define MPFS_MPUCFG_WIDTH 64 + +/* Mode bits [63:56] */ + +#define MPFS_MPUCFG_MODE_SHIFT 56 +#define MPFS_MPUCFG_MODE_WIDTH 8 +#define MPFS_MPUCFG_MODE_MASK \ + (((1ul << MPFS_MPUCFG_MODE_WIDTH) - 1) << MPFS_MPUCFG_MODE_SHIFT) + +/* PMP entry bits [35:0] */ + +#define MPFS_MPUCFG_PMP_SHIFT 0 +#define MPFS_MPUCFG_PMP_WIDTH 36 +#define MPFS_MPUCFG_PMP_MASK \ + (((1ul << MPFS_MPUCFG_PMP_WIDTH) - 1) << MPFS_MPUCFG_PMP_SHIFT) + +/* Encode the MPUCFG register value */ + +#define MPFS_MPUCFG_ENCODE(mode, napot) \ + (((mode << MPFS_MPUCFG_MODE_SHIFT) & MPFS_MPUCFG_MODE_MASK) | \ + ((napot << MPFS_MPUCFG_PMP_SHIFT) & MPFS_MPUCFG_PMP_MASK)) + +/* Decode the MPUCFG register value */ + +#define MPFS_MPUCFG_DECODE(reg, mode, napot) \ + do \ + { \ + uintptr_t val = getreg64(reg); \ + *(mode) = (val & MPFS_MPUCFG_MODE_MASK) >> MPFS_MPUCFG_MODE_SHIFT; \ + *(napot) = (val & MPFS_MPUCFG_PMP_MASK) >> MPFS_MPUCFG_PMP_SHIFT; \ + } \ + while(0) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: napot_decode + * + * Description: + * Decode base and size from NAPOT value + * + * Input Parameters: + * val - Value to decode. + * size - Size out. + * + * Returned Value: + * Base address + * + ****************************************************************************/ + +static void napot_decode(uintptr_t val, uintptr_t *base, uintptr_t *size) +{ + uintptr_t mask = (uintptr_t)(-1) >> 1; + uintptr_t pot = MPFS_MPUCFG_WIDTH + 2; + + while (mask) + { + if ((val & mask) == mask) + { + break; + } + + pot--; + mask >>= 1; + } + + *size = UINT64_C(1) << pot; + *base = (val & ~mask) << 2; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_mpu_set + * + * Description: + * Set value to MPFS MPUCFG register. + * + * Input Parameters: + * reg - The MPUCFG register to write. + * perm - The region permissions. + * base - The base address of the region. + * size - The length of the region. + * + * Note: + * Only NAPOT encoded regions are supported, thus the base address and + * size must align with each other. + * + * Returned Value: + * 0 on success; negated error on failure + * + ****************************************************************************/ + +int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, + uintptr_t size) +{ + uintptr_t mode; + uintptr_t napot; + + /* Read the the permission and napot fields */ + + MPFS_MPUCFG_DECODE(reg, &mode, &napot); + + /* First, check that the register is not already configured */ + + if ((mode & PMPCFG_L) != 0) + { + /* The entry is locked, get out */ + + return -EACCES; + } + + /* Base must be word aligned, minimum size is 4K */ + + if ((base & 0x07) != 0 || size < 0x1000) + { + return -EINVAL; + } + + /* Make sure the base + size are NAPOT encodable */ + + if ((base & ((UINT64_C(1) << log2ceil(size)) - 1)) != 0) + { + /* The start address is not properly aligned with size */ + + return -EINVAL; + } + + /* Sanity check the register */ + + if (reg < MPFS_MPUCFG_BASE || reg >= MPFS_MPUCFG_END) + { + return -EINVAL; + } + + /* Calculate mode (RWX), only NAPOT encoding is supported */ + + mode = (perm & PMPCFG_RWX_MASK) | PMPCFG_A_NAPOT; + + /* Do the NAPOT encoding */ + + napot = (base >> 2) | ((size - 1) >> 3); + + /* Then set the value */ + + putreg64(MPFS_MPUCFG_ENCODE(mode, napot), reg); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_mpu_access_ok + * + * Description: + * Check if MPFS MPUCFG access is OK for register. + * + * Input Parameters: + * reg - The MPUCFG register to check. + * perm - The region permissions. + * base - The base address of the region. + * size - The length of the region. + * + * Returned Value: + * true if access OK; false if not + * + ****************************************************************************/ + +bool mpfs_mpu_access_ok(uintptr_t reg, uintptr_t perm, uintptr_t base, + uintptr_t size) +{ + uintptr_t mode; + uintptr_t napot; + uintptr_t reg_base; + uintptr_t reg_size; + + /* Read the the permission and napot fields */ + + MPFS_MPUCFG_DECODE(reg, &mode, &napot); + + /* Check for permission match */ + + if ((mode & PMPCFG_RWX_MASK) != perm) + { + return false; + } + + /* Decode the napot field */ + + napot_decode(napot, ®_base, ®_size); + + /* Then check if the area fits */ + + return (base >= reg_base && (base + size) <= (reg_base + reg_size)); +} diff --git a/arch/risc-v/src/mpfs/mpfs_mpu.h b/arch/risc-v/src/mpfs/mpfs_mpu.h new file mode 100644 index 0000000000..6bef8fe5f4 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_mpu.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_mpu.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H +#define __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_mpu_set + * + * Description: + * Set value to MPFS MPUCFG register. + * + * Input Parameters: + * reg - The MPUCFG register to write. + * perm - The region permissions. + * base - The base address of the region. + * size - The length of the region. + * + * Note: + * Only NAPOT encoded regions are supported, thus the base address and + * size must align with each other. + * + * Returned Value: + * 0 on success; negated error on failure + * + ****************************************************************************/ + +int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, + uintptr_t size); + +/**************************************************************************** + * Name: mpfs_mpu_access_ok + * + * Description: + * Check if MPFS MPUCFG access is OK for register. + * + * Input Parameters: + * reg - The MPUCFG register to check. + * perm - The region permissions. + * base - The base address of the region. + * size - The length of the region. + * + * Returned Value: + * true if access OK; false if not + * + ****************************************************************************/ + +bool mpfs_mpu_access_ok(uintptr_t reg, uintptr_t perm, uintptr_t base, + uintptr_t size); + +#endif /* __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H */