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