xref: /rk3399_ARM-atf/plat/mediatek/drivers/spmi/pmif_common.c (revision 52e486f6a6192bd18d36cdcbc35c59092eefc810)
1 /*
2  * Copyright (c) 2025, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <errno.h>
8 #include <stdint.h>
9 #include <string.h>
10 
11 #include <lib/mmio.h>
12 #include <lib/spinlock.h>
13 
14 #include <pmif.h>
15 #include "pmif_common.h"
16 #include "spmi_common.h"
17 #include "spmi_sw.h"
18 
19 #define PMIF_CMD_REG_0			0
20 #define PMIF_CMD_REG			1
21 #define PMIF_CMD_EXT_REG		2
22 #define PMIF_CMD_EXT_REG_LONG		3
23 #define PMIF_READ_CMD_MIN		0x60
24 #define PMIF_READ_CMD_MAX		0x7F
25 #define PMIF_READ_CMD_EXT_MIN		0x20
26 #define PMIF_READ_CMD_EXT_MAX		0x2F
27 #define PMIF_READ_CMD_EXT_LONG_MIN	0x38
28 #define PMIF_READ_CMD_EXT_LONG_MAX	0x3F
29 #define PMIF_WRITE_CMD_MIN		0x40
30 #define PMIF_WRITE_CMD_MAX		0x5F
31 #define PMIF_WRITE_CMD_EXT_MAX		0xF
32 #define PMIF_WRITE_CMD_EXT_LONG_MIN	0x30
33 #define PMIF_WRITE_CMD_EXT_LONG_MAX	0x37
34 #define PMIF_WRITE_CMD_0_MIN		0x80
35 
36 /* macro for SWINF_FSM */
37 #define SWINF_FSM_IDLE			0x00
38 #define SWINF_FSM_REQ			0x02
39 #define SWINF_FSM_WFDLE			0x04
40 #define SWINF_FSM_WFVLDCLR		0x06
41 
42 #define GET_SWINF_FSM(x)		(((x) >> 1) & 0x7)
43 #define GET_PMIF_INIT_DONE(x)		(((x) >> 15) & 0x1)
44 #define TIMEOUT_WAIT_IDLE_US		10000 /* 10ms */
45 
46 #define PMIF_RW_CMD_SET(opc, rw, sid, bc, addr)	\
47 	(((opc) << 30) | ((rw) << 29) | ((sid) << 24) | ((bc) << 16) | (addr))
48 
49 static spinlock_t pmif_lock;
50 
51 struct pmif *get_pmif_controller(int inf, int mstid)
52 {
53 	return &pmif_spmi_arb[mstid];
54 }
55 
56 static int pmif_check_idle(int mstid)
57 {
58 	struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid);
59 	unsigned int reg_rdata, offset = 0;
60 
61 	do {
62 		offset = arb->regs[PMIF_SWINF_3_STA];
63 		reg_rdata = mmio_read_32((uintptr_t)(arb->base + offset));
64 	} while (GET_SWINF_FSM(reg_rdata) != SWINF_FSM_IDLE);
65 
66 	return 0;
67 }
68 
69 static int pmif_check_vldclr(int mstid)
70 {
71 	struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid);
72 	unsigned int reg_rdata, offset = 0;
73 
74 	do {
75 		offset = arb->regs[PMIF_SWINF_3_STA];
76 		reg_rdata = mmio_read_32((uintptr_t)(arb->base + offset));
77 	} while (GET_SWINF_FSM(reg_rdata) != SWINF_FSM_WFVLDCLR);
78 
79 	return 0;
80 }
81 
82 int pmif_spmi_read_cmd(struct pmif *arb, uint8_t opc, uint8_t sid,
83 		       uint16_t addr, uint8_t *buf, uint8_t len)
84 {
85 	int ret;
86 	uint32_t offset = 0, data = 0;
87 	uint8_t bc = len - 1;
88 
89 	if (sid > SPMI_MAX_SLAVE_ID || len > PMIF_BYTECNT_MAX)
90 		return -EINVAL;
91 
92 	/* Check the opcode */
93 	if (opc >= PMIF_READ_CMD_MIN && opc <= PMIF_READ_CMD_MAX)
94 		opc = PMIF_CMD_REG;
95 	else if (opc >= PMIF_READ_CMD_EXT_MIN && opc <= PMIF_READ_CMD_EXT_MAX)
96 		opc = PMIF_CMD_EXT_REG;
97 	else if (opc >= PMIF_READ_CMD_EXT_LONG_MIN && opc <= PMIF_READ_CMD_EXT_LONG_MAX)
98 		opc = PMIF_CMD_EXT_REG_LONG;
99 	else
100 		return -EINVAL;
101 
102 	spin_lock(&pmif_lock);
103 
104 	/* Wait for Software Interface FSM state to be IDLE. */
105 	ret = pmif_check_idle(arb->mstid);
106 	if (ret)
107 		goto done;
108 
109 	/* Send the command. */
110 	offset = arb->regs[PMIF_SWINF_3_ACC];
111 	mmio_write_32((uintptr_t)(arb->base + offset), PMIF_RW_CMD_SET(opc, 0, sid, bc, addr));
112 	/*
113 	 * Wait for Software Interface FSM state to be WFVLDCLR,
114 	 * read the data and clear the valid flag.
115 	 */
116 	ret = pmif_check_vldclr(arb->mstid);
117 	if (ret)
118 		goto done;
119 
120 	offset = arb->regs[PMIF_SWINF_3_RDATA_31_0];
121 
122 	data = mmio_read_32((uintptr_t)(arb->base + offset));
123 	memcpy(buf, &data, (bc & 3) + 1);
124 
125 	offset = arb->regs[PMIF_SWINF_3_VLD_CLR];
126 	mmio_write_32((uintptr_t)(arb->base + offset), 0x1);
127 
128 done:
129 	spin_unlock(&pmif_lock);
130 	return ret;
131 }
132 
133 int pmif_spmi_write_cmd(struct pmif *arb, uint8_t opc, uint8_t sid, uint16_t addr,
134 			const uint8_t *buf, uint8_t len)
135 {
136 	int ret;
137 	uint32_t offset = 0, data = 0;
138 	uint8_t bc = len - 1;
139 
140 	if (sid > SPMI_MAX_SLAVE_ID || len > PMIF_BYTECNT_MAX)
141 		return -EINVAL;
142 
143 	/* Check the opcode */
144 	if (opc >= PMIF_WRITE_CMD_MIN && opc <= PMIF_WRITE_CMD_MAX)
145 		opc = PMIF_CMD_REG;
146 	else if (opc <= PMIF_WRITE_CMD_EXT_MAX)
147 		opc = PMIF_CMD_EXT_REG;
148 	else if (opc >= PMIF_WRITE_CMD_EXT_LONG_MIN && opc <= PMIF_WRITE_CMD_EXT_LONG_MAX)
149 		opc = PMIF_CMD_EXT_REG_LONG;
150 	else if (opc >= PMIF_WRITE_CMD_0_MIN)
151 		opc = PMIF_CMD_REG_0;
152 	else
153 		return -EINVAL;
154 
155 	spin_lock(&pmif_lock);
156 
157 	/* Wait for Software Interface FSM state to be IDLE. */
158 	ret = pmif_check_idle(arb->mstid);
159 	if (ret)
160 		goto done;
161 
162 	/* Set the write data. */
163 	offset = arb->regs[PMIF_SWINF_3_WDATA_31_0];
164 	memcpy(&data, buf, (bc & 3) + 1);
165 	mmio_write_32((uintptr_t)(arb->base + offset), data);
166 	/* Send the command. */
167 	offset = arb->regs[PMIF_SWINF_3_ACC];
168 	mmio_write_32((uintptr_t)(arb->base + offset), PMIF_RW_CMD_SET(opc, 1, sid, bc, addr));
169 
170 done:
171 	spin_unlock(&pmif_lock);
172 	return ret;
173 }
174