xtensa/esp32: Add high memory support to work with PSRAM

This commit is contained in:
Alan C. Assis
2020-11-11 16:22:31 -03:00
committed by Abdelatif Guettouche
parent cbd4e90781
commit f09d103528
7 changed files with 1268 additions and 0 deletions
+31
View File
@@ -591,6 +591,37 @@ config ESP32_SPIRAM_2T_MODE
Applications will not be affected unless the use the esp_himem
APIs, which are not supported in 2T mode.
config SPIRAM_BANKSWITCH_ENABLE
bool "Enable bank switching for >4MiB external RAM"
default y
help
The ESP32 only supports 4MiB of external RAM in its address
space. The hardware does support larger memories, but these
have to be bank-switched in and out of this address space.
Enabling this allows you to reserve some MMU pages for this,
which allows the use of the esp_himem api to manage these
banks.
#Note that this is limited to 62 banks, as
#esp_spiram_writeback_cache needs some kind of mapping of
#some banks below that mark to work. We cannot at this
#moment guarantee this to exist when himem is enabled.
If spiram 2T mode is enabled, the size of 64Mbit psram will
be changed as 32Mbit, so himem will be unusable.
config SPIRAM_BANKSWITCH_RESERVE
int "Amount of 32K pages to reserve for bank switching"
depends on SPIRAM_BANKSWITCH_ENABLE
default 8
range 1 62
help
Select the amount of banks reserved for bank switching. Note
that the amount of RAM allocatable with malloc will decrease
by 32K for each page reserved here.
Note that this reservation is only actually done if your
program actually uses the himem API. Without any himem
calls, the reservation is not done and the original amount
of memory will be available.
endmenu #SPI RAM Config
menu "Ethernet configuration"
+1
View File
@@ -121,6 +121,7 @@ endif
ifeq ($(CONFIG_ESP32_SPIRAM),y)
CHIP_CSRCS += esp32_spiram.c
CHIP_CSRCS += esp32_psram.c
CHIP_CSRCS += esp32_himem.c
endif
ifeq ($(CONFIG_ESP32_EMAC),y)
File diff suppressed because it is too large Load Diff
+193
View File
@@ -0,0 +1,193 @@
/****************************************************************************
* arch/xtensa/src/esp32/esp32_himem.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_XTENSA_SRC_ESP32_ESP32_HIMEM_H
#define __ARCH_XTENSA_SRC_ESP32_ESP32_HIMEM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stddef.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* Indicates that a mapping will only be read from. Note that this is unused
* for now.
*/
#define ESP_HIMEM_MAPFLAG_RO 1
/* Allocate a block in high memory
*
* params:
* size Size of the to-be-allocated block, in bytes. Note that this
* needs to be a multiple of the external RAM mmu block size
* (32K).
* [out] handle_out Handle to be returned
*
* returns:
* - ESP_OK if succesful
* - ESP_ERR_NO_MEM if out of memory
* - ESP_ERR_INVALID_SIZE if size is not a multiple of 32K
*/
int esp_himem_alloc(size_t size, esp_himem_handle_t *handle_out);
/* Description: Allocate a memory region to map blocks into
*
* This allocates a contiguous CPU memory region that can be used to map
* blocks of physical memory into.
*
* params:
* size Size of the range to be allocated. Note this needs to be a multiple
* of the external RAM mmu block size (32K).
* [out] handle_out Handle to be returned
*
* returns:
* - ESP_OK if succesful
* - ESP_ERR_NO_MEM if out of memory or address space
* - ESP_ERR_INVALID_SIZE if size is not a multiple of 32K
*/
int esp_himem_alloc_map_range(size_t size, esp_himem_rangehandle_t
*handle_out);
/* Description: Map a block of high memory into the CPUs address space
*
* This effectively makes the block available for read/write operations.
*
* Note: The region to be mapped needs to have offsets and sizes that are
* aligned to the SPI RAM MMU block size (32K)
*
* params:
* handle Handle to the block of memory, as given by esp_himem_alloc
* range Range handle to map the memory in
* ram_offset Offset into the block of physical memory of the block to
* map
* range_offset Offset into the address range where the block will be
* mapped,
* len Length of region to map
* flags One of ESP_HIMEM_MAPFLAG_*
* [out] out_ptr Pointer to variable to store resulting memory pointer in
*
* returns:
* - ESP_OK if the memory could be mapped
* - ESP_ERR_INVALID_ARG if offset, range or len aren't MMU-block-aligned
* (32K)
* - ESP_ERR_INVALID_SIZE if the offsets/lengths don't fit in the allocated
* memory or range
* - ESP_ERR_INVALID_STATE if a block in the selected ram offset/length is
* already mapped, or if a block in the selected range offset/length
* already has a mapping.
*/
int esp_himem_map(esp_himem_handle_t handle,
esp_himem_rangehandle_t range,
size_t ram_offset,
size_t range_offset,
size_t len,
int flags,
void **out_ptr);
/* Description: Free a block of physical memory
*
* This clears out the associated handle making the memory available for
* re-allocation again.
* This will only succeed if none of the memory blocks currently have a
* mapping.
*
* params:
* handle Handle to the block of memory, as given by esp_himem_alloc
*
* returns:
* - ESP_OK if the memory is succesfully freed
* - ESP_ERR_INVALID_ARG if the handle still is (partially) mapped
*/
int esp_himem_free(esp_himem_handle_t handle);
/* Description: Free a mapping range
*
* This clears out the associated handle making the range available for
* re-allocation again.
* This will only succeed if none of the range blocks currently are used for
* a mapping.
*
* params:
* handle Handle to the range block, as given by esp_himem_alloc_map_range
*
* returns:
* - ESP_OK if the memory is succesfully freed
* - ESP_ERR_INVALID_ARG if the handle still is (partially) mapped to
*/
int esp_himem_free_map_range(esp_himem_rangehandle_t handle);
/* Description: Unmap a region
*
* params:
* range Range handle
* ptr Pointer returned by esp_himem_map
* len Length of the block to be unmapped. Must be aligned to the SPI RAM
* MMU blocksize (32K)
* returns:
* - ESP_OK if the memory is succesfully unmapped,
* - ESP_ERR_INVALID_ARG if ptr or len are invalid.
*/
int esp_himem_unmap(esp_himem_rangehandle_t range, void *ptr,
size_t len);
/* Description: Get total amount of memory under control of himem API
*
* returns:
* Amount of memory, in bytes
*/
size_t esp_himem_get_phys_size(void);
/* Description: Get free amount of memory under control of himem API
*
* returns:
* Amount of free memory, in bytes
*/
size_t esp_himem_get_free_size(void);
/* Description: Get amount of SPI memory address space needed for
* bankswitching
*
* Note: This is also weakly defined in esp32/spiram.c and returns 0 there,
* so if no other function in this file is used, no memory is reserved.
*
* return:
* Amount of reserved area, in bytes
*/
size_t esp_himem_reserved_area_size(void);
#ifdef __cplusplus
}
#endif
#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_HIMEM_H */
@@ -61,6 +61,7 @@
#include <syslog.h>
#include <sys/errno.h>
#include <nuttx/himem/himem.h>
#include "esp32_procfs_imm.h"
#include "esp32-core.h"
@@ -142,6 +143,14 @@ int esp32_bringup(void)
#endif
#if defined(CONFIG_ESP32_SPIRAM)
ret = esp_himem_init();
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to init HIMEM: %d\n", ret);
}
#endif
#ifdef CONFIG_FS_PROCFS
/* Mount the procfs file system */
+6
View File
@@ -100,6 +100,7 @@
#define _NOTECTLBASE (0x2c00) /* Note filter control ioctl commands*/
#define _NOTERAMBASE (0x2d00) /* Noteram device ioctl commands*/
#define _RCIOCBASE (0x2e00) /* Remote Control device ioctl commands */
#define _HIMEMBASE (0x2f00) /* Himem device ioctl commands*/
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
/* boardctl() commands share the same number space */
@@ -545,6 +546,11 @@
#define _RCIOCVALID(c) (_IOC_TYPE(c)==_RCIOCBASE)
#define _RCIOC(nr) _IOC(_RCIOCBASE,nr)
/* Hime drivers **********************************************************/
#define _HIMEMIOCVALID(c) (_IOC_TYPE(c) == _HIMEMBASE)
#define _HIMEMIOC(nr) _IOC(_HIMEMBASE, nr)
/* Wireless driver network ioctl definitions ********************************/
/* (see nuttx/include/wireless/wireless.h */
+173
View File
@@ -0,0 +1,173 @@
/****************************************************************************
* include/nuttx/himem/himem.h
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_HIMEM_HIMEM_H
#define __INCLUDE_NUTTX_HIMEM_HIMEM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/fs/ioctl.h>
#include <signal.h>
#ifdef CONFIG_ESP32_SPIRAM
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* ESP32 MMU block size */
#define ESP_HIMEM_BLKSZ (0x8000)
/* Command: HIMEMIOC_ALLOC_BLOCKS
* Description: Allocate a certain number of physical RAM blocks.
* Arguments: A structure containing the size of physical block to allocate
* and its esp_himem_handle_t.
* Return: Zero (OK) on success. Minus one will be returned on failure
* with the errno value set appropriately.
*/
#define HIMEMIOC_ALLOC_BLOCKS _HIMEMIOC(0x0001)
/* Command: HIMEMIOC_FREE_BLOCKS
* Description: Free a certain number of physical RAM blocks.
* Arguments: A structure containing the size of physical block to allocate
* and its esp_himem_handle_t.
* Return: Zero (OK) on success. Minus one will be returned on failure
* with the errno value set appropriately.
*/
#define HIMEMIOC_FREE_BLOCKS _HIMEMIOC(0x0002)
/* Command: HIMEMIOC_ALLOC_MAP_RANGE
* Description: Free the physical RAM blocks
* Arguments: A structure containing the block size and its
* esp_himem_rangehandle_t.
* Return: Zero (OK) on success. Minus one will be returned on failure
* with the errno value set appropriately.
*/
#define HIMEMIOC_ALLOC_MAP_RANGE _HIMEMIOC(0x0003)
/* Command: HIMEMIOC_FREE_MAP_RANGE
* Description: Maps the memory addresses to the physical psram range.
* Arguments: A structure containing the esp_himem_handle_t handle, the
* esp_himem_rangehandle_t, the ram offset, the range offset,
* the length, the memory flags and the output pointer.
* Return: Zero (OK) on success. Minus one will be returned on failure
* with the errno value set appropriately.
*/
#define HIMEMIOC_FREE_MAP_RANGE _HIMEMIOC(0x0004)
/* Command: HIMEMIOC_MAP
* Description: Maps the memory addresses to the physical psram range.
* Arguments: A structure containing the esp_himem_handle_t handle, the
* esp_himem_rangehandle_t, the ram offset, the range offset,
* the length, the memory flags and the output pointer.
* Return: Zero (OK) on success. Minus one will be returned on failure
* with the errno value set appropriately.
*/
#define HIMEMIOC_MAP _HIMEMIOC(0x0005)
/* Command: HIMEMIOC_UNMAP
* Description: Unmaps the memory addresses to the physical psram range.
* Arguments: A structure containing the esp_himem_rangehandle_t, the
* memory pointer and the memory length.
* the length, the memory flags and the output pointer.
* Return: Zero (OK) on success. Minus one will be returned on failure
* with the errno value set appropriately.
*/
#define HIMEMIOC_UNMAP _HIMEMIOC(0x0006)
/* Command: HIMEMIOC_GET_PHYS_SIZE
* Description: Get the size of physical external memory
* Arguments: None
* Return: Zero (OK) on success. Minus one will be returned on failure
* with the errno value set appropriately.
*/
#define HIMEMIOC_GET_PHYS_SIZE _HIMEMIOC(0x0007)
/* Command: HIMEMIOC_GET_FREE_SIZE
* Description: Get the amount of free memory
* Arguments: None
* Return: Zero (OK) on success. Minus one will be returned on failure
* with the errno value set appropriately.
*/
#define HIMEMIOC_GET_FREE_SIZE _HIMEMIOC(0x0008)
/****************************************************************************
* Public Types
****************************************************************************/
/* Handle for a window of address space */
typedef struct esp_himem_rangedata_t
{
int block_ct;
int block_start;
} esp_himem_rangedata_t;
/* Handle for a range of physical memory */
typedef struct esp_himem_ramdata_t
{
int block_ct;
uint16_t *block;
} esp_himem_ramdata_t;
/* Opaque pointers as handles for ram/range data */
typedef struct esp_himem_ramdata_t *esp_himem_handle_t;
typedef struct esp_himem_rangedata_t *esp_himem_rangehandle_t;
/* Structs with the parameters passed to the IOCTLs */
struct esp_himem_par
{
esp_himem_handle_t handle;
esp_himem_rangehandle_t range;
size_t ram_offset;
size_t range_offset;
size_t memfree;
size_t memcnt;
size_t len;
int flags;
uint32_t *ptr;
};
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int esp_himem_init(void);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_ESP32_SPIRAM */
#endif /* __INCLUDE_NUTTX_HIMEM_HIMEM_H */