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