294 lines
7.5 KiB
Diff
294 lines
7.5 KiB
Diff
From eb5dfe2a76180d85f33fa2e7ed5131852a003dac Mon Sep 17 00:00:00 2001
|
|
From: XiaoDong Huang <derrick.huang@rock-chips.com>
|
|
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 <derrick.huang@rock-chips.com>
|
|
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 <stdint.h>
|
|
+
|
|
+/**
|
|
+ * 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 <assert.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <bl31/bl31.h>
|
|
+#include <common/debug.h>
|
|
+#include <drivers/console.h>
|
|
+#include <drivers/delay_timer.h>
|
|
+#include <lib/mmio.h>
|
|
+#include <plat/common/platform.h>
|
|
+#include <platform_def.h>
|
|
+
|
|
+#include <plat_pm_helpers.h>
|
|
+
|
|
+#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);
|
|
+ }
|
|
+}
|