1780e3f24SHeiko Stuebner /*
2780e3f24SHeiko Stuebner * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3780e3f24SHeiko Stuebner *
4780e3f24SHeiko Stuebner * SPDX-License-Identifier: BSD-3-Clause
5780e3f24SHeiko Stuebner */
6780e3f24SHeiko Stuebner
7780e3f24SHeiko Stuebner #include <platform_def.h>
8780e3f24SHeiko Stuebner
9780e3f24SHeiko Stuebner #include <arch_helpers.h>
10780e3f24SHeiko Stuebner #include <common/debug.h>
11780e3f24SHeiko Stuebner #include <lib/mmio.h>
12780e3f24SHeiko Stuebner
13780e3f24SHeiko Stuebner #include <plat_private.h>
14780e3f24SHeiko Stuebner #include <rk3288_def.h>
15780e3f24SHeiko Stuebner #include <soc.h>
16780e3f24SHeiko Stuebner #include <secure.h>
17780e3f24SHeiko Stuebner
18780e3f24SHeiko Stuebner /* sleep data for pll suspend */
19780e3f24SHeiko Stuebner static struct deepsleep_data_s slp_data;
20780e3f24SHeiko Stuebner
21780e3f24SHeiko Stuebner /* Table of regions to map using the MMU. */
22780e3f24SHeiko Stuebner const mmap_region_t plat_rk_mmap[] = {
23780e3f24SHeiko Stuebner MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE,
24780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
25780e3f24SHeiko Stuebner MAP_REGION_FLAT(STIME_BASE, STIME_SIZE,
26780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
27780e3f24SHeiko Stuebner MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE,
28780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
29780e3f24SHeiko Stuebner MAP_REGION_FLAT(TZPC_BASE, TZPC_SIZE,
30780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
31780e3f24SHeiko Stuebner MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
32780e3f24SHeiko Stuebner MT_MEMORY | MT_RW | MT_SECURE),
33780e3f24SHeiko Stuebner MAP_REGION_FLAT(SRAM_BASE, SRAM_SIZE,
34780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
35780e3f24SHeiko Stuebner MAP_REGION_FLAT(PMU_BASE, PMU_SIZE,
36780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
370957b9b2SChristoph Müllner MAP_REGION_FLAT(UART0_BASE, UART0_SIZE,
380957b9b2SChristoph Müllner MT_DEVICE | MT_RW | MT_SECURE),
390957b9b2SChristoph Müllner MAP_REGION_FLAT(UART1_BASE, UART1_SIZE,
400957b9b2SChristoph Müllner MT_DEVICE | MT_RW | MT_SECURE),
410957b9b2SChristoph Müllner MAP_REGION_FLAT(UART2_BASE, UART2_SIZE,
420957b9b2SChristoph Müllner MT_DEVICE | MT_RW | MT_SECURE),
430957b9b2SChristoph Müllner MAP_REGION_FLAT(UART3_BASE, UART3_SIZE,
440957b9b2SChristoph Müllner MT_DEVICE | MT_RW | MT_SECURE),
450957b9b2SChristoph Müllner MAP_REGION_FLAT(UART4_BASE, UART4_SIZE,
46780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
47780e3f24SHeiko Stuebner MAP_REGION_FLAT(CRU_BASE, CRU_SIZE,
48780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
49780e3f24SHeiko Stuebner MAP_REGION_FLAT(GRF_BASE, GRF_SIZE,
50780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
51780e3f24SHeiko Stuebner MAP_REGION_FLAT(DDR_PCTL0_BASE, DDR_PCTL0_SIZE,
52780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
53780e3f24SHeiko Stuebner MAP_REGION_FLAT(DDR_PHY0_BASE, DDR_PHY0_SIZE,
54780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
55780e3f24SHeiko Stuebner MAP_REGION_FLAT(DDR_PCTL1_BASE, DDR_PCTL1_SIZE,
56780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
57780e3f24SHeiko Stuebner MAP_REGION_FLAT(DDR_PHY1_BASE, DDR_PHY1_SIZE,
58780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
59780e3f24SHeiko Stuebner MAP_REGION_FLAT(SERVICE_BUS_BASE, SERVICE_BUS_SIZE,
60780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
61780e3f24SHeiko Stuebner MAP_REGION_FLAT(CORE_AXI_BUS_BASE, CORE_AXI_BUS_SIZE,
62780e3f24SHeiko Stuebner MT_DEVICE | MT_RW | MT_SECURE),
63780e3f24SHeiko Stuebner { 0 }
64780e3f24SHeiko Stuebner };
65780e3f24SHeiko Stuebner
66780e3f24SHeiko Stuebner /* The RockChip power domain tree descriptor */
67780e3f24SHeiko Stuebner const unsigned char rockchip_power_domain_tree_desc[] = {
68780e3f24SHeiko Stuebner /* No of root nodes */
69780e3f24SHeiko Stuebner PLATFORM_SYSTEM_COUNT,
70780e3f24SHeiko Stuebner /* No of children for the root node */
71780e3f24SHeiko Stuebner PLATFORM_CLUSTER_COUNT,
72780e3f24SHeiko Stuebner /* No of children for the first cluster node */
73780e3f24SHeiko Stuebner PLATFORM_CLUSTER0_CORE_COUNT,
74780e3f24SHeiko Stuebner };
75780e3f24SHeiko Stuebner
plat_rockchip_soc_init(void)76780e3f24SHeiko Stuebner void plat_rockchip_soc_init(void)
77780e3f24SHeiko Stuebner {
78780e3f24SHeiko Stuebner secure_timer_init();
79780e3f24SHeiko Stuebner secure_sgrf_init();
80780e3f24SHeiko Stuebner /*
81780e3f24SHeiko Stuebner * We cannot enable ddr security at this point, as the kernel
82780e3f24SHeiko Stuebner * seems to have an issue with it even living in the same 128MB
83780e3f24SHeiko Stuebner * memory block. Only when moving the kernel to the second
84780e3f24SHeiko Stuebner * 128MB block does it not conflict, but then we'd loose this
85780e3f24SHeiko Stuebner * memory area for use. Late maybe enable
86780e3f24SHeiko Stuebner * secure_sgrf_ddr_rgn_init();
87780e3f24SHeiko Stuebner */
88780e3f24SHeiko Stuebner }
89780e3f24SHeiko Stuebner
regs_update_bits(uintptr_t addr,uint32_t val,uint32_t mask,uint32_t shift)90780e3f24SHeiko Stuebner void regs_update_bits(uintptr_t addr, uint32_t val,
91780e3f24SHeiko Stuebner uint32_t mask, uint32_t shift)
92780e3f24SHeiko Stuebner {
93780e3f24SHeiko Stuebner uint32_t tmp, orig;
94780e3f24SHeiko Stuebner
95780e3f24SHeiko Stuebner orig = mmio_read_32(addr);
96780e3f24SHeiko Stuebner
97780e3f24SHeiko Stuebner tmp = orig & ~(mask << shift);
98780e3f24SHeiko Stuebner tmp |= (val & mask) << shift;
99780e3f24SHeiko Stuebner
100780e3f24SHeiko Stuebner if (tmp != orig)
101780e3f24SHeiko Stuebner mmio_write_32(addr, tmp);
102780e3f24SHeiko Stuebner dsb();
103780e3f24SHeiko Stuebner }
104780e3f24SHeiko Stuebner
pll_save(uint32_t pll_id)105780e3f24SHeiko Stuebner static void pll_save(uint32_t pll_id)
106780e3f24SHeiko Stuebner {
107780e3f24SHeiko Stuebner uint32_t *pll = slp_data.pll_con[pll_id];
108780e3f24SHeiko Stuebner
109780e3f24SHeiko Stuebner pll[0] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 0));
110780e3f24SHeiko Stuebner pll[1] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 1));
111780e3f24SHeiko Stuebner pll[2] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 2));
112780e3f24SHeiko Stuebner pll[3] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 3));
113780e3f24SHeiko Stuebner }
114780e3f24SHeiko Stuebner
clk_plls_suspend(void)115780e3f24SHeiko Stuebner void clk_plls_suspend(void)
116780e3f24SHeiko Stuebner {
117780e3f24SHeiko Stuebner pll_save(NPLL_ID);
118780e3f24SHeiko Stuebner pll_save(CPLL_ID);
119780e3f24SHeiko Stuebner pll_save(GPLL_ID);
120780e3f24SHeiko Stuebner pll_save(APLL_ID);
121780e3f24SHeiko Stuebner slp_data.pll_mode = mmio_read_32(CRU_BASE + PLL_MODE_CON);
122780e3f24SHeiko Stuebner
123780e3f24SHeiko Stuebner /*
124780e3f24SHeiko Stuebner * Switch PLLs other than DPLL (for SDRAM) to slow mode to
125780e3f24SHeiko Stuebner * avoid crashes on resume. The Mask ROM on the system will
126780e3f24SHeiko Stuebner * put APLL, CPLL, and GPLL into slow mode at resume time
127780e3f24SHeiko Stuebner * anyway (which is why we restore them), but we might not
128780e3f24SHeiko Stuebner * even make it to the Mask ROM if this isn't done at suspend
129780e3f24SHeiko Stuebner * time.
130780e3f24SHeiko Stuebner *
131780e3f24SHeiko Stuebner * NOTE: only APLL truly matters here, but we'll do them all.
132780e3f24SHeiko Stuebner */
133780e3f24SHeiko Stuebner mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000);
134780e3f24SHeiko Stuebner }
135780e3f24SHeiko Stuebner
clk_plls_resume(void)136780e3f24SHeiko Stuebner void clk_plls_resume(void)
137780e3f24SHeiko Stuebner {
138780e3f24SHeiko Stuebner /* restore pll-modes */
139780e3f24SHeiko Stuebner mmio_write_32(CRU_BASE + PLL_MODE_CON,
140780e3f24SHeiko Stuebner slp_data.pll_mode | REG_SOC_WMSK);
141780e3f24SHeiko Stuebner }
142780e3f24SHeiko Stuebner
clk_gate_con_save(void)143780e3f24SHeiko Stuebner void clk_gate_con_save(void)
144780e3f24SHeiko Stuebner {
145780e3f24SHeiko Stuebner uint32_t i = 0;
146780e3f24SHeiko Stuebner
147780e3f24SHeiko Stuebner for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
148780e3f24SHeiko Stuebner slp_data.cru_gate_con[i] =
149780e3f24SHeiko Stuebner mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
150780e3f24SHeiko Stuebner }
151780e3f24SHeiko Stuebner
clk_gate_con_disable(void)152780e3f24SHeiko Stuebner void clk_gate_con_disable(void)
153780e3f24SHeiko Stuebner {
154780e3f24SHeiko Stuebner uint32_t i;
155780e3f24SHeiko Stuebner
156780e3f24SHeiko Stuebner for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
157780e3f24SHeiko Stuebner mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), REG_SOC_WMSK);
158780e3f24SHeiko Stuebner }
159780e3f24SHeiko Stuebner
clk_gate_con_restore(void)160780e3f24SHeiko Stuebner void clk_gate_con_restore(void)
161780e3f24SHeiko Stuebner {
162780e3f24SHeiko Stuebner uint32_t i;
163780e3f24SHeiko Stuebner
164780e3f24SHeiko Stuebner for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
165780e3f24SHeiko Stuebner mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
166780e3f24SHeiko Stuebner REG_SOC_WMSK | slp_data.cru_gate_con[i]);
167780e3f24SHeiko Stuebner }
168780e3f24SHeiko Stuebner
clk_sel_con_save(void)169780e3f24SHeiko Stuebner void clk_sel_con_save(void)
170780e3f24SHeiko Stuebner {
171780e3f24SHeiko Stuebner uint32_t i = 0;
172780e3f24SHeiko Stuebner
173780e3f24SHeiko Stuebner for (i = 0; i < CRU_CLKSELS_CON_CNT; i++)
174780e3f24SHeiko Stuebner slp_data.cru_sel_con[i] =
175780e3f24SHeiko Stuebner mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(i));
176780e3f24SHeiko Stuebner }
177780e3f24SHeiko Stuebner
clk_sel_con_restore(void)178780e3f24SHeiko Stuebner void clk_sel_con_restore(void)
179780e3f24SHeiko Stuebner {
180780e3f24SHeiko Stuebner uint32_t i, val;
181780e3f24SHeiko Stuebner
182780e3f24SHeiko Stuebner for (i = 0; i < CRU_CLKSELS_CON_CNT; i++) {
183780e3f24SHeiko Stuebner /* fractional dividers don't have write-masks */
184780e3f24SHeiko Stuebner if ((i >= 7 && i <= 9) ||
185780e3f24SHeiko Stuebner (i >= 17 && i <= 20) ||
186780e3f24SHeiko Stuebner (i == 23) || (i == 41))
187780e3f24SHeiko Stuebner val = slp_data.cru_sel_con[i];
188780e3f24SHeiko Stuebner else
189780e3f24SHeiko Stuebner val = slp_data.cru_sel_con[i] | REG_SOC_WMSK;
190780e3f24SHeiko Stuebner
191780e3f24SHeiko Stuebner mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(i), val);
192780e3f24SHeiko Stuebner }
193780e3f24SHeiko Stuebner }
194780e3f24SHeiko Stuebner
rockchip_soc_soft_reset(void)195780e3f24SHeiko Stuebner void __dead2 rockchip_soc_soft_reset(void)
196780e3f24SHeiko Stuebner {
197780e3f24SHeiko Stuebner uint32_t temp_val;
198780e3f24SHeiko Stuebner
199780e3f24SHeiko Stuebner /*
200780e3f24SHeiko Stuebner * Switch PLLs other than DPLL (for SDRAM) to slow mode to
201780e3f24SHeiko Stuebner * avoid crashes on resume. The Mask ROM on the system will
202780e3f24SHeiko Stuebner * put APLL, CPLL, and GPLL into slow mode at resume time
203780e3f24SHeiko Stuebner * anyway (which is why we restore them), but we might not
204780e3f24SHeiko Stuebner * even make it to the Mask ROM if this isn't done at suspend
205780e3f24SHeiko Stuebner * time.
206780e3f24SHeiko Stuebner *
207780e3f24SHeiko Stuebner * NOTE: only APLL truly matters here, but we'll do them all.
208780e3f24SHeiko Stuebner */
209780e3f24SHeiko Stuebner mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000);
210780e3f24SHeiko Stuebner
211780e3f24SHeiko Stuebner temp_val = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON);
212780e3f24SHeiko Stuebner temp_val &= ~PMU_RST_MASK;
213780e3f24SHeiko Stuebner temp_val |= PMU_RST_BY_SECOND_SFT;
214780e3f24SHeiko Stuebner mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, temp_val);
215780e3f24SHeiko Stuebner mmio_write_32(CRU_BASE + CRU_GLB_SRST_SND, 0xeca8);
216780e3f24SHeiko Stuebner
217780e3f24SHeiko Stuebner /*
218780e3f24SHeiko Stuebner * Maybe the HW needs some times to reset the system,
219*1b491eeaSElyes Haouas * so we do not hope the core to execute valid codes.
220780e3f24SHeiko Stuebner */
221780e3f24SHeiko Stuebner while (1)
222780e3f24SHeiko Stuebner ;
223780e3f24SHeiko Stuebner }
224