1 /* 2 * Copyright (c) 2024, Rockchip, Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 10 #include <arch_helpers.h> 11 #include <bl31/bl31.h> 12 #include <common/debug.h> 13 #include <drivers/console.h> 14 #include <drivers/delay_timer.h> 15 #include <lib/mmio.h> 16 #include <plat/common/platform.h> 17 #include <platform_def.h> 18 19 #include <plat_pm_helpers.h> 20 21 #define ROCKCHIP_PM_REG_REGION_MEM_LEN (ROCKCHIP_PM_REG_REGION_MEM_SIZE / sizeof(uint32_t)) 22 23 /* REG region */ 24 #define RGN_LEN(_rgn) (((_rgn)->end - (_rgn)->start) / (_rgn)->stride + 1) 25 26 #ifndef ROCKCHIP_PM_REG_REGION_MEM_SIZE 27 #define ROCKCHIP_PM_REG_REGION_MEM_SIZE 0 28 #endif 29 30 #ifdef ROCKCHIP_REG_RGN_MEM_BASE 31 static uint32_t *region_mem = (uint32_t *)ROCKCHIP_REG_RGN_MEM_BASE; 32 #else 33 static uint32_t region_mem[ROCKCHIP_PM_REG_REGION_MEM_LEN]; 34 #endif 35 36 static int region_mem_idx; 37 38 static int alloc_region_mem(uint32_t *buf, int max_len, 39 struct reg_region *rgns, uint32_t rgn_num) 40 { 41 int i; 42 int total_len = 0, len = 0; 43 struct reg_region *r = rgns; 44 45 assert(buf && rgns && rgn_num); 46 47 for (i = 0; i < rgn_num; i++, r++) { 48 if (total_len < max_len) 49 r->buf = &buf[total_len]; 50 51 len = RGN_LEN(r); 52 total_len += len; 53 } 54 55 if (total_len > max_len) { 56 ERROR("%s The buffer remain length:%d is too small for region:0x%x, at least %d\n", 57 __func__, max_len, rgns[0].start, total_len); 58 panic(); 59 } 60 61 return total_len; 62 } 63 64 /** 65 * Alloc memory to reg_region->buf from region_mem. 66 * @rgns - struct reg_region array. 67 * @rgn_num - struct reg_region array length. 68 */ 69 void rockchip_alloc_region_mem(struct reg_region *rgns, uint32_t rgn_num) 70 { 71 int max_len = 0, len; 72 73 assert(rgns && rgn_num); 74 75 max_len = ROCKCHIP_PM_REG_REGION_MEM_LEN - region_mem_idx; 76 77 len = alloc_region_mem(region_mem + region_mem_idx, max_len, 78 rgns, rgn_num); 79 80 region_mem_idx += len; 81 } 82 83 /** 84 * Save (reg_region->start ~ reg_region->end) to reg_region->buf. 85 * @rgns - struct reg_region array. 86 * @rgn_num - struct reg_region array length. 87 */ 88 void rockchip_reg_rgn_save(struct reg_region *rgns, uint32_t rgn_num) 89 { 90 struct reg_region *r; 91 uint32_t addr; 92 int i, j; 93 94 assert(rgns && rgn_num); 95 96 for (i = 0; i < rgn_num; i++) { 97 r = &rgns[i]; 98 for (j = 0, addr = r->start; addr <= r->end; addr += r->stride, j++) 99 r->buf[j] = mmio_read_32(addr); 100 } 101 } 102 103 /** 104 * Restore reg_region->buf to (reg_region->start ~ reg_region->end). 105 * @rgns - struct reg_region array. 106 * @rgn_num - struct reg_region array length. 107 */ 108 void rockchip_reg_rgn_restore(struct reg_region *rgns, uint32_t rgn_num) 109 { 110 struct reg_region *r; 111 uint32_t addr; 112 int i, j; 113 114 assert(rgns && rgn_num); 115 116 for (i = 0; i < rgn_num; i++) { 117 r = &rgns[i]; 118 for (j = 0, addr = r->start; addr <= r->end; addr += r->stride, j++) 119 mmio_write_32(addr, r->buf[j] | r->wmsk); 120 121 dsb(); 122 } 123 } 124 125 /** 126 * Restore reg_region->buf to (reg_region->start ~ reg_region->end) reversely. 127 * @rgns - struct reg_region array. 128 * @rgn_num - struct reg_region array length. 129 */ 130 void rockchip_reg_rgn_restore_reverse(struct reg_region *rgns, uint32_t rgn_num) 131 { 132 struct reg_region *r; 133 uint32_t addr; 134 int i, j; 135 136 assert(rgns && rgn_num); 137 138 for (i = rgn_num - 1; i >= 0; i--) { 139 r = &rgns[i]; 140 j = RGN_LEN(r) - 1; 141 for (addr = r->end; addr >= r->start; addr -= r->stride, j--) 142 mmio_write_32(addr, r->buf[j] | r->wmsk); 143 144 dsb(); 145 } 146 } 147 148 static void rockchip_print_hex(uint32_t val) 149 { 150 int i; 151 unsigned char tmp; 152 153 putchar('0'); 154 putchar('x'); 155 for (i = 0; i < 8; val <<= 4, ++i) { 156 tmp = (val & 0xf0000000) >> 28; 157 if (tmp < 10) 158 putchar('0' + tmp); 159 else 160 putchar('a' + tmp - 10); 161 } 162 } 163 164 /** 165 * Dump registers (base + start_offset ~ base + end_offset) 166 * @base - the base addr of the register. 167 * @start_offset - the start offset to dump. 168 * @end_offset - the end offset to dump. 169 * @stride - the stride of the registers. 170 */ 171 void rockchip_regs_dump(uint32_t base, 172 uint32_t start_offset, 173 uint32_t end_offset, 174 uint32_t stride) 175 { 176 uint32_t i; 177 178 for (i = start_offset; i <= end_offset; i += stride) { 179 if ((i - start_offset) % 16 == 0) { 180 putchar('\n'); 181 rockchip_print_hex(base + i); 182 putchar(':'); 183 putchar(' '); 184 putchar(' '); 185 putchar(' '); 186 putchar(' '); 187 } 188 rockchip_print_hex(mmio_read_32(base + i)); 189 putchar(' '); 190 putchar(' '); 191 putchar(' '); 192 putchar(' '); 193 } 194 putchar('\n'); 195 } 196 197 /** 198 * Dump reg regions 199 * @rgns - struct reg_region array. 200 * @rgn_num - struct reg_region array length. 201 */ 202 void rockchip_dump_reg_rgns(struct reg_region *rgns, uint32_t rgn_num) 203 { 204 struct reg_region *r; 205 int i; 206 207 assert(rgns && rgn_num); 208 209 for (i = 0; i < rgn_num; i++) { 210 r = &rgns[i]; 211 rockchip_regs_dump(0x0, r->start, r->end, r->stride); 212 } 213 } 214