xref: /rk3399_ARM-atf/plat/ti/k3low/common/am62l_psc_minimal.c (revision 6c0c3a74dda68e7ffc8bd6c156918ddbfea7e03a)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Minimal PSC driver for AM62L BL1.
4  *
5  * NOTE: This driver exists because the ti-am62l-clk driver (topic:
6  * ti-am62l-clk) is not yet available during BL1 execution.  Once that driver
7  * is integrated, this file should be removed and its callers updated to use
8  * the shared PSC API to avoid duplicate hardware state management.
9  *
10  * Copyright (C) 2025-2026 Texas Instruments Incorporated - https://www.ti.com/
11  */
12 
13 #include <errno.h>
14 
15 #include <common/debug.h>
16 #include <lib/mmio.h>
17 #include <lib/utils_def.h>
18 
19 #include <am62l_psc_minimal.h>
20 
21 /*
22  * Transition a single power domain / module-state pair on the Main PSC.
23  *
24  * Returns 0 on success, -ETIMEDOUT if the hardware fails to complete the
25  * transition within PSC_GOSTAT_RETRY_COUNT polls.
26  */
set_main_psc_state(uint32_t pd_id,uint32_t md_id,uint32_t pd_state,uint32_t md_state)27 int set_main_psc_state(uint32_t pd_id, uint32_t md_id,
28 		       uint32_t pd_state, uint32_t md_state)
29 {
30 	uintptr_t mdctrl_ptr;
31 	volatile uint32_t mdctrl;
32 	uintptr_t mdstat_ptr;
33 	volatile uint32_t mdstat;
34 	uintptr_t pdctrl_ptr;
35 	volatile uint32_t pdctrl;
36 	uintptr_t pdstat_ptr;
37 	volatile uint32_t pdstat;
38 	volatile uint32_t psc_ptstat;
39 	volatile uint32_t psc_ptcmd;
40 	uint32_t retries;
41 
42 	mdctrl_ptr = (uintptr_t)(MAIN_PSC_MDCTL_BASE + (4U * md_id));
43 	mdctrl = mmio_read_32(mdctrl_ptr);
44 	mdstat_ptr = (uintptr_t)(MAIN_PSC_MDSTAT_BASE + (4U * md_id));
45 	mdstat = mmio_read_32(mdstat_ptr);
46 	pdctrl_ptr = (uintptr_t)(MAIN_PSC_PDCTL_BASE + (4U * pd_id));
47 	pdctrl = mmio_read_32(pdctrl_ptr);
48 	pdstat_ptr = (uintptr_t)(MAIN_PSC_PDSTAT_BASE + (4U * pd_id));
49 	pdstat = mmio_read_32(pdstat_ptr);
50 
51 	if (((FIELD_GET(PDSTAT_STATE_MASK, pdstat)) == pd_state) &&
52 			((FIELD_GET(MDSTAT_STATE_MASK, mdstat)) == md_state))
53 		return 0;
54 
55 	psc_ptstat = mmio_read_32(MAIN_PSC_PTSTAT);
56 
57 	/* wait for GOSTAT to get cleared */
58 	retries = PSC_GOSTAT_RETRY_COUNT;
59 	while ((psc_ptstat & (PTSTAT_DOMAIN_GOSTAT << pd_id)) != 0U) {
60 		if (retries == 0U) {
61 			ERROR("PSC: pd %u GOSTAT clear timed out\n", pd_id);
62 			return -ETIMEDOUT;
63 		}
64 		retries--;
65 		psc_ptstat = mmio_read_32(MAIN_PSC_PTSTAT);
66 	}
67 
68 	/* Set PDCTL NEXT to new state */
69 	mmio_write_32(pdctrl_ptr,
70 		      ((pdctrl & ~(PDCTL_NEXT_STATE_MASK)) |
71 		      FIELD_PREP(PDCTL_NEXT_STATE_MASK, pd_state)));
72 
73 	/* Set MDCTL NEXT to new state */
74 	mmio_write_32(mdctrl_ptr,
75 		      ((mdctrl & ~(MDCTL_NEXT_STATE_MASK)) |
76 		      FIELD_PREP(MDCTL_NEXT_STATE_MASK, md_state)));
77 
78 	/* start power transition by setting PTCMD Go to 1 */
79 	psc_ptcmd = mmio_read_32((uintptr_t)MAIN_PSC_PTCMD);
80 	psc_ptcmd |= (PTCMD_DOMAIN_GO << pd_id);
81 	mmio_write_32((uintptr_t)MAIN_PSC_PTCMD, psc_ptcmd);
82 
83 	/* wait for GOSTAT to get cleared */
84 	psc_ptstat = mmio_read_32((uintptr_t)MAIN_PSC_PTSTAT);
85 	retries = PSC_GOSTAT_RETRY_COUNT;
86 	while ((psc_ptstat & (PTSTAT_DOMAIN_GOSTAT << pd_id)) != 0U) {
87 		if (retries == 0U) {
88 			ERROR("PSC: pd %u GOSTAT clear timed out after PTCMD go\n", pd_id);
89 			return -ETIMEDOUT;
90 		}
91 		retries--;
92 		psc_ptstat = mmio_read_32((uintptr_t)MAIN_PSC_PTSTAT);
93 	}
94 
95 	return 0;
96 }
97