mtl: soc: add TLB driver context save to platform PowerManagement

Connect the TLB context save to MTL suspend power flow

Signed-off-by: Marcin Szkudlinski <marcin.szkudlinski@intel.com>
This commit is contained in:
Marcin Szkudlinski 2022-10-24 12:48:54 +02:00 committed by Anas Nashif
commit 3ee8bf7053
2 changed files with 172 additions and 1 deletions

View file

@ -36,12 +36,17 @@
#include <adsp_memory.h> #include <adsp_memory.h>
#include "mm_drv_common.h" #include "mm_drv_common.h"
#include <drivers/mm/mm_drv_intel_adsp_mtl_tlb.h>
DEVICE_MMIO_TOPLEVEL_STATIC(tlb_regs, DT_DRV_INST(0)); DEVICE_MMIO_TOPLEVEL_STATIC(tlb_regs, DT_DRV_INST(0));
/* base address of TLB table */
#define TLB_BASE \ #define TLB_BASE \
((mm_reg_t)DEVICE_MMIO_TOPLEVEL_GET(tlb_regs)) ((mm_reg_t)DEVICE_MMIO_TOPLEVEL_GET(tlb_regs))
/* size of TLB table */
#define TLB_SIZE DT_REG_SIZE_BY_IDX(DT_INST(0, intel_adsp_mtl_tlb), 0)
/* /*
* Number of significant bits in the page index (defines the size of * Number of significant bits in the page index (defines the size of
* the table) * the table)
@ -702,4 +707,125 @@ static int sys_mm_drv_mm_init(const struct device *dev)
return 0; return 0;
} }
SYS_INIT(sys_mm_drv_mm_init, POST_KERNEL, 0); static void adsp_mm_save_context(void *storage_buffer)
{
uint16_t entry;
uint32_t entry_idx;
int page_idx;
uint32_t phys_addr;
volatile uint16_t *tlb_entries = UINT_TO_POINTER(TLB_BASE);
uint8_t *location = (uint8_t *) storage_buffer;
/* first, store the existing TLB */
memcpy(location, UINT_TO_POINTER(TLB_BASE), TLB_SIZE);
location += TLB_SIZE;
/* save context of all the pages */
for (page_idx = 0; page_idx < L2_SRAM_PAGES_NUM; page_idx++) {
phys_addr = POINTER_TO_UINT(L2_SRAM_BASE) +
CONFIG_MM_DRV_PAGE_SIZE * page_idx;
if (sys_mem_blocks_is_region_free(
&L2_PHYS_SRAM_REGION,
UINT_TO_POINTER(phys_addr), 1)) {
/* skip a free page */
continue;
}
/* map the physical addr 1:1 to virtual address */
entry_idx = get_tlb_entry_idx(phys_addr);
entry = pa_to_tlb_entry(phys_addr);
if ((tlb_entries[entry_idx] & TLB_PADDR_MASK) != entry) {
/* this page needs remapping, invalidate cache to avoid stalled data
* all cache data has been flushed before
* do this for pages to remap only
*/
z_xtensa_cache_inv(UINT_TO_POINTER(phys_addr), CONFIG_MM_DRV_PAGE_SIZE);
/* Enable the translation in the TLB entry */
entry |= TLB_ENABLE_BIT;
/* map the page 1:1 virtual to physical */
tlb_entries[entry_idx] = entry;
}
/* save physical address */
*((uint32_t *) location) = phys_addr;
location += sizeof(uint32_t);
/* save the page */
memcpy(location,
UINT_TO_POINTER(phys_addr),
CONFIG_MM_DRV_PAGE_SIZE);
location += CONFIG_MM_DRV_PAGE_SIZE;
}
/* write end marker - a null address */
*((uint32_t *) location) = 0;
location += sizeof(uint32_t);
z_xtensa_cache_flush(
storage_buffer,
(uint32_t)location - (uint32_t)storage_buffer);
/* system state is frozen, ready to poweroff, no further changes will be stored */
}
__imr void adsp_mm_restore_context(void *storage_buffer)
{
/* at this point system must be in a startup state
* TLB must be set to initial state
* Note! the stack must NOT be in the area being restored
*/
uint32_t phys_addr;
uint8_t *location;
/* restore context of all the pages */
location = (uint8_t *) storage_buffer + TLB_SIZE;
phys_addr = *((uint32_t *) location);
while (phys_addr != 0) {
uint32_t phys_addr_uncached =
POINTER_TO_UINT(z_soc_uncached_ptr(UINT_TO_POINTER(phys_addr)));
uint32_t phys_offset = phys_addr - L2_SRAM_BASE;
uint32_t bank_idx = (phys_offset / SRAM_BANK_SIZE);
location += sizeof(uint32_t);
/* turn on memory bank power, wait till the power is on */
__ASSERT_NO_MSG(bank_idx <= ace_hpsram_get_bank_count());
HPSRAM_REGS(bank_idx)->HSxPGCTL = 0;
while (HPSRAM_REGS(bank_idx)->HSxPGISTS == 1) {
/* k_busy_wait cannot be used here - not available */
}
/* copy data to uncached alias and invalidate cache */
bmemcpy(UINT_TO_POINTER(phys_addr_uncached),
location,
CONFIG_MM_DRV_PAGE_SIZE);
z_xtensa_cache_inv(UINT_TO_POINTER(phys_addr), CONFIG_MM_DRV_PAGE_SIZE);
location += CONFIG_MM_DRV_PAGE_SIZE;
phys_addr = *((uint32_t *) location);
}
/* restore original TLB table */
bmemcpy(UINT_TO_POINTER(TLB_BASE), storage_buffer, TLB_SIZE);
/* HPSRAM memory is restored */
}
static const struct intel_adsp_tlb_api adsp_tlb_api_func = {
.save_context = adsp_mm_save_context
};
DEVICE_DT_DEFINE(DT_INST(0, intel_adsp_mtl_tlb),
sys_mm_drv_mm_init,
NULL,
NULL,
NULL,
POST_KERNEL,
0,
&adsp_tlb_api_func);

View file

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: Apache-2.0 */
/*
* Copyright (c) 2022 Intel Corporation.
*
* Author: Marcin Szkudlinski <marcin.szkudlinski@linux.intel.com>
*
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_INTEL_ADSP_MTL_TLB
#define ZEPHYR_INCLUDE_DRIVERS_INTEL_ADSP_MTL_TLB
/*
* This function will save contents of the physical memory banks into a provided storage buffer
*
* the system must be almost stopped. Operation is destructive - it will change physical to
* virtual addresses mapping leaving the system not operational
* Power states of memory banks will stay not touched
* assuming
* - the dcache memory had been invalidated before
* - no remapping of addresses below unused_l2_sram_start_marker has been made
* (this is ensured by the driver itself - it rejects such remapping request)
*
* at this point the memory is still up&running so its safe to use libraries like memcpy
* and the procedure can be called in a zephyr driver model way
*/
typedef void (*mm_save_context)(void *storage_buffer);
/*
* This function will restore the contents and power state of the physical memory banks
* and recreate physical to virtual mappings
*
* As the system memory is down at this point, the procedure
* - MUST be located in IMR memory region
* - MUST be called using a simple extern procedure call - API table is not yet loaded
* - MUST NOT use libraries, like memcpy, use instead a special version bmemcpy located in IMR
*
*/
void adsp_mm_restore_context(void *storage_buffer);
struct intel_adsp_tlb_api {
mm_save_context save_context;
};
#endif /* ZEPHYR_INCLUDE_DRIVERS_INTEL_ADSP_MTL_TLB */