xref: /openbmc/linux/drivers/hwmon/sbrmi.c (revision f4356947)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * sbrmi.c - hwmon driver for a SB-RMI mailbox
4  *           compliant AMD SoC device.
5  *
6  * Copyright (C) 2020-2021 Advanced Micro Devices, Inc.
7  */
8 
9 #include <linux/delay.h>
10 #include <linux/err.h>
11 #include <linux/hwmon.h>
12 #include <linux/i2c.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/mutex.h>
16 #include <linux/of.h>
17 
18 /* Do not allow setting negative power limit */
19 #define SBRMI_PWR_MIN	0
20 /* Mask for Status Register bit[1] */
21 #define SW_ALERT_MASK	0x2
22 
23 /* Software Interrupt for triggering */
24 #define START_CMD	0x80
25 #define TRIGGER_MAILBOX	0x01
26 
27 /*
28  * SB-RMI supports soft mailbox service request to MP1 (power management
29  * firmware) through SBRMI inbound/outbound message registers.
30  * SB-RMI message IDs
31  */
32 enum sbrmi_msg_id {
33 	SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1,
34 	SBRMI_WRITE_PKG_PWR_LIMIT,
35 	SBRMI_READ_PKG_PWR_LIMIT,
36 	SBRMI_READ_PKG_MAX_PWR_LIMIT,
37 };
38 
39 /* SB-RMI registers */
40 enum sbrmi_reg {
41 	SBRMI_CTRL		= 0x01,
42 	SBRMI_STATUS,
43 	SBRMI_OUTBNDMSG0	= 0x30,
44 	SBRMI_OUTBNDMSG1,
45 	SBRMI_OUTBNDMSG2,
46 	SBRMI_OUTBNDMSG3,
47 	SBRMI_OUTBNDMSG4,
48 	SBRMI_OUTBNDMSG5,
49 	SBRMI_OUTBNDMSG6,
50 	SBRMI_OUTBNDMSG7,
51 	SBRMI_INBNDMSG0,
52 	SBRMI_INBNDMSG1,
53 	SBRMI_INBNDMSG2,
54 	SBRMI_INBNDMSG3,
55 	SBRMI_INBNDMSG4,
56 	SBRMI_INBNDMSG5,
57 	SBRMI_INBNDMSG6,
58 	SBRMI_INBNDMSG7,
59 	SBRMI_SW_INTERRUPT,
60 };
61 
62 /* Each client has this additional data */
63 struct sbrmi_data {
64 	struct i2c_client *client;
65 	struct mutex lock;
66 	u32 pwr_limit_max;
67 };
68 
69 struct sbrmi_mailbox_msg {
70 	u8 cmd;
71 	bool read;
72 	u32 data_in;
73 	u32 data_out;
74 };
75 
76 static int sbrmi_enable_alert(struct i2c_client *client)
77 {
78 	int ctrl;
79 
80 	/*
81 	 * Enable the SB-RMI Software alert status
82 	 * by writing 0 to bit 4 of Control register(0x1)
83 	 */
84 	ctrl = i2c_smbus_read_byte_data(client, SBRMI_CTRL);
85 	if (ctrl < 0)
86 		return ctrl;
87 
88 	if (ctrl & 0x10) {
89 		ctrl &= ~0x10;
90 		return i2c_smbus_write_byte_data(client,
91 						 SBRMI_CTRL, ctrl);
92 	}
93 
94 	return 0;
95 }
96 
97 static int rmi_mailbox_xfer(struct sbrmi_data *data,
98 			    struct sbrmi_mailbox_msg *msg)
99 {
100 	int i, ret, retry = 10;
101 	int sw_status;
102 	u8 byte;
103 
104 	mutex_lock(&data->lock);
105 
106 	/* Indicate firmware a command is to be serviced */
107 	ret = i2c_smbus_write_byte_data(data->client,
108 					SBRMI_INBNDMSG7, START_CMD);
109 	if (ret < 0)
110 		goto exit_unlock;
111 
112 	/* Write the command to SBRMI::InBndMsg_inst0 */
113 	ret = i2c_smbus_write_byte_data(data->client,
114 					SBRMI_INBNDMSG0, msg->cmd);
115 	if (ret < 0)
116 		goto exit_unlock;
117 
118 	/*
119 	 * For both read and write the initiator (BMC) writes
120 	 * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1]
121 	 * SBRMI_x3C(MSB):SBRMI_x39(LSB)
122 	 */
123 	for (i = 0; i < 4; i++) {
124 		byte = (msg->data_in >> i * 8) & 0xff;
125 		ret = i2c_smbus_write_byte_data(data->client,
126 						SBRMI_INBNDMSG1 + i, byte);
127 		if (ret < 0)
128 			goto exit_unlock;
129 	}
130 
131 	/*
132 	 * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to
133 	 * perform the requested read or write command
134 	 */
135 	ret = i2c_smbus_write_byte_data(data->client,
136 					SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX);
137 	if (ret < 0)
138 		goto exit_unlock;
139 
140 	/*
141 	 * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate
142 	 * an ALERT (if enabled) to initiator (BMC) to indicate completion
143 	 * of the requested command
144 	 */
145 	do {
146 		sw_status = i2c_smbus_read_byte_data(data->client,
147 						     SBRMI_STATUS);
148 		if (sw_status < 0) {
149 			ret = sw_status;
150 			goto exit_unlock;
151 		}
152 		if (sw_status & SW_ALERT_MASK)
153 			break;
154 		usleep_range(50, 100);
155 	} while (retry--);
156 
157 	if (retry < 0) {
158 		dev_err(&data->client->dev,
159 			"Firmware fail to indicate command completion\n");
160 		ret = -EIO;
161 		goto exit_unlock;
162 	}
163 
164 	/*
165 	 * For a read operation, the initiator (BMC) reads the firmware
166 	 * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1]
167 	 * {SBRMI_x34(MSB):SBRMI_x31(LSB)}.
168 	 */
169 	if (msg->read) {
170 		for (i = 0; i < 4; i++) {
171 			ret = i2c_smbus_read_byte_data(data->client,
172 						       SBRMI_OUTBNDMSG1 + i);
173 			if (ret < 0)
174 				goto exit_unlock;
175 			msg->data_out |= ret << i * 8;
176 		}
177 	}
178 
179 	/*
180 	 * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the
181 	 * ALERT to initiator
182 	 */
183 	ret = i2c_smbus_write_byte_data(data->client, SBRMI_STATUS,
184 					sw_status | SW_ALERT_MASK);
185 
186 exit_unlock:
187 	mutex_unlock(&data->lock);
188 	return ret;
189 }
190 
191 static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type,
192 		      u32 attr, int channel, long *val)
193 {
194 	struct sbrmi_data *data = dev_get_drvdata(dev);
195 	struct sbrmi_mailbox_msg msg = { 0 };
196 	int ret;
197 
198 	if (type != hwmon_power)
199 		return -EINVAL;
200 
201 	msg.read = true;
202 	switch (attr) {
203 	case hwmon_power_input:
204 		msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION;
205 		ret = rmi_mailbox_xfer(data, &msg);
206 		break;
207 	case hwmon_power_cap:
208 		msg.cmd = SBRMI_READ_PKG_PWR_LIMIT;
209 		ret = rmi_mailbox_xfer(data, &msg);
210 		break;
211 	case hwmon_power_cap_max:
212 		msg.data_out = data->pwr_limit_max;
213 		ret = 0;
214 		break;
215 	default:
216 		return -EINVAL;
217 	}
218 	if (ret < 0)
219 		return ret;
220 	/* hwmon power attributes are in microWatt */
221 	*val = (long)msg.data_out * 1000;
222 	return ret;
223 }
224 
225 static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type,
226 		       u32 attr, int channel, long val)
227 {
228 	struct sbrmi_data *data = dev_get_drvdata(dev);
229 	struct sbrmi_mailbox_msg msg = { 0 };
230 
231 	if (type != hwmon_power && attr != hwmon_power_cap)
232 		return -EINVAL;
233 	/*
234 	 * hwmon power attributes are in microWatt
235 	 * mailbox read/write is in mWatt
236 	 */
237 	val /= 1000;
238 
239 	val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max);
240 
241 	msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT;
242 	msg.data_in = val;
243 	msg.read = false;
244 
245 	return rmi_mailbox_xfer(data, &msg);
246 }
247 
248 static umode_t sbrmi_is_visible(const void *data,
249 				enum hwmon_sensor_types type,
250 				u32 attr, int channel)
251 {
252 	switch (type) {
253 	case hwmon_power:
254 		switch (attr) {
255 		case hwmon_power_input:
256 		case hwmon_power_cap_max:
257 			return 0444;
258 		case hwmon_power_cap:
259 			return 0644;
260 		}
261 		break;
262 	default:
263 		break;
264 	}
265 	return 0;
266 }
267 
268 static const struct hwmon_channel_info * const sbrmi_info[] = {
269 	HWMON_CHANNEL_INFO(power,
270 			   HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
271 	NULL
272 };
273 
274 static const struct hwmon_ops sbrmi_hwmon_ops = {
275 	.is_visible = sbrmi_is_visible,
276 	.read = sbrmi_read,
277 	.write = sbrmi_write,
278 };
279 
280 static const struct hwmon_chip_info sbrmi_chip_info = {
281 	.ops = &sbrmi_hwmon_ops,
282 	.info = sbrmi_info,
283 };
284 
285 static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data)
286 {
287 	struct sbrmi_mailbox_msg msg = { 0 };
288 	int ret;
289 
290 	msg.cmd = SBRMI_READ_PKG_MAX_PWR_LIMIT;
291 	msg.read = true;
292 	ret = rmi_mailbox_xfer(data, &msg);
293 	if (ret < 0)
294 		return ret;
295 	data->pwr_limit_max = msg.data_out;
296 
297 	return ret;
298 }
299 
300 static int sbrmi_probe(struct i2c_client *client)
301 {
302 	struct device *dev = &client->dev;
303 	struct device *hwmon_dev;
304 	struct sbrmi_data *data;
305 	int ret;
306 
307 	data = devm_kzalloc(dev, sizeof(struct sbrmi_data), GFP_KERNEL);
308 	if (!data)
309 		return -ENOMEM;
310 
311 	data->client = client;
312 	mutex_init(&data->lock);
313 
314 	/* Enable alert for SB-RMI sequence */
315 	ret = sbrmi_enable_alert(client);
316 	if (ret < 0)
317 		return ret;
318 
319 	/* Cache maximum power limit */
320 	ret = sbrmi_get_max_pwr_limit(data);
321 	if (ret < 0)
322 		return ret;
323 
324 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
325 							 &sbrmi_chip_info, NULL);
326 
327 	return PTR_ERR_OR_ZERO(hwmon_dev);
328 }
329 
330 static const struct i2c_device_id sbrmi_id[] = {
331 	{"sbrmi", 0},
332 	{}
333 };
334 MODULE_DEVICE_TABLE(i2c, sbrmi_id);
335 
336 static const struct of_device_id __maybe_unused sbrmi_of_match[] = {
337 	{
338 		.compatible = "amd,sbrmi",
339 	},
340 	{ },
341 };
342 MODULE_DEVICE_TABLE(of, sbrmi_of_match);
343 
344 static struct i2c_driver sbrmi_driver = {
345 	.class = I2C_CLASS_HWMON,
346 	.driver = {
347 		.name = "sbrmi",
348 		.of_match_table = of_match_ptr(sbrmi_of_match),
349 	},
350 	.probe_new = sbrmi_probe,
351 	.id_table = sbrmi_id,
352 };
353 
354 module_i2c_driver(sbrmi_driver);
355 
356 MODULE_AUTHOR("Akshay Gupta <akshay.gupta@amd.com>");
357 MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor");
358 MODULE_LICENSE("GPL");
359