blob: 191b0cae076465673438e90560e2062123ac154e [file] [log] [blame]
XiaoDong Huangdcf89f32023-06-26 16:43:30 +08001/*
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
31static uint32_t *region_mem = (uint32_t *)ROCKCHIP_REG_RGN_MEM_BASE;
32#else
33static uint32_t region_mem[ROCKCHIP_PM_REG_REGION_MEM_LEN];
34#endif
35
36static int region_mem_idx;
37
38static 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 */
69void 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 */
88void 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 */
108void 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 */
130void 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
148static 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 */
171void 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 */
202void 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}