xref: /rk3399_ARM-atf/plat/mediatek/drivers/spmi/spmi_common.c (revision 79e7aae82dd173d1ccc63e5d553222f1d58f12f5)
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 
9 #include <lib/mmio.h>
10 #include <platform_def.h>
11 
12 #include "spmi_common.h"
13 #include "spmi_sw.h"
14 
15 /* SPMI Commands */
16 #define SPMI_CMD_EXT_WRITE			0x00
17 #define SPMI_CMD_EXT_READ			0x20
18 #define SPMI_CMD_EXT_WRITEL			0x30
19 #define SPMI_CMD_EXT_READL			0x38
20 #define SPMI_CMD_WRITE				0x40
21 #define SPMI_CMD_READ				0x60
22 #define SPMI_CMD_ZERO_WRITE			0x80
23 #define SPMI_READ_ADDR_MAX			0x1F
24 
25 static struct spmi_device *spmi_dev[SPMI_MAX_SLAVE_ID];
26 
27 int spmi_register_zero_write(struct spmi_device *dev, uint8_t data)
28 {
29 	return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_ZERO_WRITE,
30 					dev->slvid, 0, &data, 1);
31 }
32 
33 int spmi_register_read(struct spmi_device *dev, uint8_t addr, uint8_t *buf)
34 {
35 	/* 5-bit register address */
36 	if (addr > SPMI_READ_ADDR_MAX)
37 		return -EINVAL;
38 
39 	return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_READ, dev->slvid, addr, buf, 1);
40 }
41 
42 int spmi_register_write(struct spmi_device *dev, uint8_t addr, uint8_t data)
43 {
44 	/* 5-bit register address */
45 	if (addr > SPMI_READ_ADDR_MAX)
46 		return -EINVAL;
47 
48 	return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_WRITE,
49 					dev->slvid, addr, &data, 1);
50 }
51 
52 int spmi_ext_register_read(struct spmi_device *dev, uint8_t addr, uint8_t *buf,
53 			   uint8_t len)
54 {
55 	/* 8-bit register address, up to 16 bytes */
56 	if (len == 0 || len > 16)
57 		return -EINVAL;
58 
59 	return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READ,
60 				       dev->slvid, addr, buf, len);
61 }
62 
63 int spmi_ext_register_write(struct spmi_device *dev, uint8_t addr,
64 			    const uint8_t *buf, uint8_t len)
65 {
66 	/* 8-bit register address, up to 16 bytes */
67 	if (len == 0 || len > 16)
68 		return -EINVAL;
69 
70 	return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITE,
71 					dev->slvid, addr, buf, len);
72 }
73 
74 int spmi_ext_register_readl(struct spmi_device *dev, uint16_t addr,
75 			    uint8_t *buf, uint8_t len)
76 {
77 	/* 8-bit register address, up to 16 bytes */
78 	if (len == 0 || len > 16)
79 		return -EINVAL;
80 
81 	return dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READL,
82 				       dev->slvid, addr, buf, len);
83 }
84 
85 int spmi_ext_register_writel(struct spmi_device *dev, uint16_t addr,
86 			     const uint8_t *buf, uint8_t len)
87 {
88 	/* 8-bit register address, up to 16 bytes */
89 	if (len == 0 || len > 16)
90 		return -EINVAL;
91 
92 	return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITEL,
93 					dev->slvid, addr, buf, len);
94 }
95 
96 int spmi_ext_register_readl_field(struct spmi_device *dev, uint16_t addr,
97 				  uint8_t *buf, uint16_t mask, uint16_t shift)
98 {
99 	int ret;
100 	uint8_t rdata = 0;
101 
102 	ret = dev->pmif_arb->read_cmd(dev->pmif_arb, SPMI_CMD_EXT_READL,
103 				      dev->slvid, addr, &rdata, 1);
104 	if (!ret)
105 		*buf = (rdata >> shift) & mask;
106 
107 	return ret;
108 }
109 
110 int spmi_ext_register_writel_field(struct spmi_device *dev, uint16_t addr,
111 				   uint8_t data, uint16_t mask, uint16_t shift)
112 {
113 	int ret;
114 	uint8_t tmp = 0;
115 
116 	ret = spmi_ext_register_readl(dev, addr, &tmp, 1);
117 	if (ret)
118 		return ret;
119 
120 	tmp &= ~(mask << shift);
121 	tmp |= (data << shift);
122 	return dev->pmif_arb->write_cmd(dev->pmif_arb, SPMI_CMD_EXT_WRITEL,
123 					dev->slvid, addr, &tmp, 1);
124 }
125 
126 struct spmi_device *get_spmi_device(int mstid, int slvid)
127 {
128 	if (slvid >= SPMI_MAX_SLAVE_ID || slvid < 0) {
129 		SPMI_ERR("failed to get spmi_device with slave id %d\n", slvid);
130 		return NULL;
131 	}
132 	return spmi_dev[slvid];
133 }
134 
135 int spmi_device_register(struct spmi_device *platform_spmi_dev, unsigned int num_devs)
136 {
137 	int i;
138 
139 	if (!platform_spmi_dev || num_devs == 0)
140 		return -EINVAL;
141 
142 	for (i = 0; i < num_devs; i++) {
143 		if (platform_spmi_dev[i].slvid >= SPMI_MAX_SLAVE_ID ||
144 		    platform_spmi_dev[i].slvid < 0) {
145 			SPMI_INFO("invalid slave id %d\n", platform_spmi_dev[i].slvid);
146 			continue;
147 		}
148 		if (!spmi_dev[platform_spmi_dev[i].slvid])
149 			spmi_dev[platform_spmi_dev[i].slvid] = &platform_spmi_dev[i];
150 		else {
151 			SPMI_INFO("duplicated slave id %d\n", platform_spmi_dev[i].slvid);
152 			return -EINVAL;
153 		}
154 	}
155 	return 0;
156 }
157 
158 static int spmi_ctrl_op_st(int mstid, unsigned int grpiden, unsigned int sid,
159 		unsigned int cmd)
160 {
161 	struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid);
162 	unsigned int rdata = 0x0;
163 	uintptr_t spmi_grp_id_en_addr =
164 		(uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_GRP_ID_EN]);
165 	uintptr_t spmi_op_st_ctrl_addr =
166 		(uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_OP_ST_CTRL]);
167 	uintptr_t spmi_op_st_sta_addr =
168 		(uintptr_t)(arb->spmimst_base + arb->spmimst_regs[SPMI_OP_ST_STA]);
169 
170 	/* gid is 0x800 */
171 	mmio_write_32(spmi_grp_id_en_addr, grpiden);
172 
173 	if (grpiden == (1 << SPMI_GROUP_ID))
174 		mmio_write_32(spmi_op_st_ctrl_addr, (cmd << 0x4) | SPMI_GROUP_ID);
175 	else
176 		mmio_write_32(spmi_op_st_ctrl_addr, (cmd << 0x4) | sid);
177 
178 	SPMI_INFO("%s 0x%x\n", __func__, mmio_read_32(spmi_op_st_ctrl_addr));
179 
180 	do {
181 		rdata = mmio_read_32(spmi_op_st_sta_addr);
182 		SPMI_INFO("%s 0x%x\n", __func__, rdata);
183 
184 		if (((rdata >> 0x1) & SPMI_OP_ST_NACK) == SPMI_OP_ST_NACK) {
185 			SPMI_ERR("SPMI_OP_ST_NACK occurs! OP_ST_STA = 0x%x\n", rdata);
186 			break;
187 		}
188 	} while ((rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY);
189 
190 	return 0;
191 }
192 
193 int spmi_command_shutdown(int mstid, struct spmi_device *dev, unsigned int grpiden)
194 {
195 	if (grpiden != (1 << SPMI_GROUP_ID))
196 		dev->slvid = grpiden;
197 
198 	return spmi_ctrl_op_st(mstid, grpiden, dev->slvid, SPMI_SHUTDOWN);
199 }
200