From eb5dfe2a76180d85f33fa2e7ed5131852a003dac Mon Sep 17 00:00:00 2001 From: XiaoDong Huang Date: Sun, 25 Jun 2023 19:23:07 +0800 Subject: [PATCH] feat(rockchip): add some pm helpers functions Some power domains will be powered off when the system suspends, so registers in the power domain need to be save/restore. Now we add some functions to save/restore registers easily: use rockchip_alloc_region_mem to allocate memory to save/restore registers in regions; use rockchip_reg_rgn_save to save registers regions in regions; use rockchip_reg_rgn_restore to restore registers in regions; use rockchip_dump_reg_rgns to dump registers in regions; Signed-off-by: XiaoDong Huang Change-Id: I34f909a103fbe2d51456e1d92df0be570e35e2a1 --- diff --git a/plat/rockchip/common/include/plat_pm_helpers.h b/plat/rockchip/common/include/plat_pm_helpers.h new file mode 100644 index 0000000..2204a65 --- /dev/null +++ b/plat/rockchip/common/include/plat_pm_helpers.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, Rockchip, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_PM_HELPERS_H +#define PLAT_PM_HELPERS_H + +#include + +/** + * Use this macro to define a register region. + * start: start offset from the base address. + * end: end offset from the base address. + * stride: stride of registers in region. + * base: base address of registers in region. + * wmsk: write mask of registers in region. + */ +#define REG_REGION(_start, _end, _stride, _base, _wmsk) \ +{ \ + .start = (_base) + (_start), \ + .end = (_base) + (_end), \ + .stride = _stride, \ + .wmsk = _wmsk \ +} + +struct reg_region { + /* Start address of region */ + uint32_t start; + /* End address of region */ + uint32_t end; + /* Stride of registers in region */ + uint32_t stride; + /* Write mask of registers in region */ + uint32_t wmsk; + /* Buffer to save/restore registers in region */ + uint32_t *buf; +}; + +void rockchip_alloc_region_mem(struct reg_region *rgns, uint32_t rgn_num); +void rockchip_reg_rgn_save(struct reg_region *rgns, uint32_t rgn_num); +void rockchip_reg_rgn_restore(struct reg_region *rgns, uint32_t rgn_num); +void rockchip_reg_rgn_restore_reverse(struct reg_region *rgns, uint32_t rgn_num); +void rockchip_regs_dump(uint32_t base, + uint32_t start_offset, + uint32_t end_offset, + uint32_t stride); +void rockchip_dump_reg_rgns(struct reg_region *rgns, uint32_t rgn_num); + +#endif /* PLAT_PM_HELPERS_H */ diff --git a/plat/rockchip/common/plat_pm_helpers.c b/plat/rockchip/common/plat_pm_helpers.c new file mode 100644 index 0000000..191b0ca --- /dev/null +++ b/plat/rockchip/common/plat_pm_helpers.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2024, Rockchip, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ROCKCHIP_PM_REG_REGION_MEM_LEN (ROCKCHIP_PM_REG_REGION_MEM_SIZE / sizeof(uint32_t)) + +/* REG region */ +#define RGN_LEN(_rgn) (((_rgn)->end - (_rgn)->start) / (_rgn)->stride + 1) + +#ifndef ROCKCHIP_PM_REG_REGION_MEM_SIZE +#define ROCKCHIP_PM_REG_REGION_MEM_SIZE 0 +#endif + +#ifdef ROCKCHIP_REG_RGN_MEM_BASE +static uint32_t *region_mem = (uint32_t *)ROCKCHIP_REG_RGN_MEM_BASE; +#else +static uint32_t region_mem[ROCKCHIP_PM_REG_REGION_MEM_LEN]; +#endif + +static int region_mem_idx; + +static int alloc_region_mem(uint32_t *buf, int max_len, + struct reg_region *rgns, uint32_t rgn_num) +{ + int i; + int total_len = 0, len = 0; + struct reg_region *r = rgns; + + assert(buf && rgns && rgn_num); + + for (i = 0; i < rgn_num; i++, r++) { + if (total_len < max_len) + r->buf = &buf[total_len]; + + len = RGN_LEN(r); + total_len += len; + } + + if (total_len > max_len) { + ERROR("%s The buffer remain length:%d is too small for region:0x%x, at least %d\n", + __func__, max_len, rgns[0].start, total_len); + panic(); + } + + return total_len; +} + +/** + * Alloc memory to reg_region->buf from region_mem. + * @rgns - struct reg_region array. + * @rgn_num - struct reg_region array length. + */ +void rockchip_alloc_region_mem(struct reg_region *rgns, uint32_t rgn_num) +{ + int max_len = 0, len; + + assert(rgns && rgn_num); + + max_len = ROCKCHIP_PM_REG_REGION_MEM_LEN - region_mem_idx; + + len = alloc_region_mem(region_mem + region_mem_idx, max_len, + rgns, rgn_num); + + region_mem_idx += len; +} + +/** + * Save (reg_region->start ~ reg_region->end) to reg_region->buf. + * @rgns - struct reg_region array. + * @rgn_num - struct reg_region array length. + */ +void rockchip_reg_rgn_save(struct reg_region *rgns, uint32_t rgn_num) +{ + struct reg_region *r; + uint32_t addr; + int i, j; + + assert(rgns && rgn_num); + + for (i = 0; i < rgn_num; i++) { + r = &rgns[i]; + for (j = 0, addr = r->start; addr <= r->end; addr += r->stride, j++) + r->buf[j] = mmio_read_32(addr); + } +} + +/** + * Restore reg_region->buf to (reg_region->start ~ reg_region->end). + * @rgns - struct reg_region array. + * @rgn_num - struct reg_region array length. + */ +void rockchip_reg_rgn_restore(struct reg_region *rgns, uint32_t rgn_num) +{ + struct reg_region *r; + uint32_t addr; + int i, j; + + assert(rgns && rgn_num); + + for (i = 0; i < rgn_num; i++) { + r = &rgns[i]; + for (j = 0, addr = r->start; addr <= r->end; addr += r->stride, j++) + mmio_write_32(addr, r->buf[j] | r->wmsk); + + dsb(); + } +} + +/** + * Restore reg_region->buf to (reg_region->start ~ reg_region->end) reversely. + * @rgns - struct reg_region array. + * @rgn_num - struct reg_region array length. + */ +void rockchip_reg_rgn_restore_reverse(struct reg_region *rgns, uint32_t rgn_num) +{ + struct reg_region *r; + uint32_t addr; + int i, j; + + assert(rgns && rgn_num); + + for (i = rgn_num - 1; i >= 0; i--) { + r = &rgns[i]; + j = RGN_LEN(r) - 1; + for (addr = r->end; addr >= r->start; addr -= r->stride, j--) + mmio_write_32(addr, r->buf[j] | r->wmsk); + + dsb(); + } +} + +static void rockchip_print_hex(uint32_t val) +{ + int i; + unsigned char tmp; + + putchar('0'); + putchar('x'); + for (i = 0; i < 8; val <<= 4, ++i) { + tmp = (val & 0xf0000000) >> 28; + if (tmp < 10) + putchar('0' + tmp); + else + putchar('a' + tmp - 10); + } +} + +/** + * Dump registers (base + start_offset ~ base + end_offset) + * @base - the base addr of the register. + * @start_offset - the start offset to dump. + * @end_offset - the end offset to dump. + * @stride - the stride of the registers. + */ +void rockchip_regs_dump(uint32_t base, + uint32_t start_offset, + uint32_t end_offset, + uint32_t stride) +{ + uint32_t i; + + for (i = start_offset; i <= end_offset; i += stride) { + if ((i - start_offset) % 16 == 0) { + putchar('\n'); + rockchip_print_hex(base + i); + putchar(':'); + putchar(' '); + putchar(' '); + putchar(' '); + putchar(' '); + } + rockchip_print_hex(mmio_read_32(base + i)); + putchar(' '); + putchar(' '); + putchar(' '); + putchar(' '); + } + putchar('\n'); +} + +/** + * Dump reg regions + * @rgns - struct reg_region array. + * @rgn_num - struct reg_region array length. + */ +void rockchip_dump_reg_rgns(struct reg_region *rgns, uint32_t rgn_num) +{ + struct reg_region *r; + int i; + + assert(rgns && rgn_num); + + for (i = 0; i < rgn_num; i++) { + r = &rgns[i]; + rockchip_regs_dump(0x0, r->start, r->end, r->stride); + } +}