/* * 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); } }