Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  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 */
 32enum 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 */
 40enum 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 */
 63struct sbrmi_data {
 64	struct i2c_client *client;
 65	struct mutex lock;
 66	u32 pwr_limit_max;
 67};
 68
 69struct sbrmi_mailbox_msg {
 70	u8 cmd;
 71	bool read;
 72	u32 data_in;
 73	u32 data_out;
 74};
 75
 76static 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
 97static 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
186exit_unlock:
187	mutex_unlock(&data->lock);
188	return ret;
189}
190
191static 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
225static 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
248static 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
268static const struct hwmon_channel_info *sbrmi_info[] = {
269	HWMON_CHANNEL_INFO(power,
270			   HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
271	NULL
272};
273
274static const struct hwmon_ops sbrmi_hwmon_ops = {
275	.is_visible = sbrmi_is_visible,
276	.read = sbrmi_read,
277	.write = sbrmi_write,
278};
279
280static const struct hwmon_chip_info sbrmi_chip_info = {
281	.ops = &sbrmi_hwmon_ops,
282	.info = sbrmi_info,
283};
284
285static 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
300static 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
330static const struct i2c_device_id sbrmi_id[] = {
331	{"sbrmi", 0},
332	{}
333};
334MODULE_DEVICE_TABLE(i2c, sbrmi_id);
335
336static const struct of_device_id __maybe_unused sbrmi_of_match[] = {
337	{
338		.compatible = "amd,sbrmi",
339	},
340	{ },
341};
342MODULE_DEVICE_TABLE(of, sbrmi_of_match);
343
344static 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
354module_i2c_driver(sbrmi_driver);
355
356MODULE_AUTHOR("Akshay Gupta <akshay.gupta@amd.com>");
357MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor");
358MODULE_LICENSE("GPL");