brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · 4d8273b Raw
222 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Mailbox interface for Wilco Embedded Controller4 *5 * Copyright 2018 Google LLC6 *7 * The Wilco EC is similar to a typical ChromeOS embedded controller.8 * It uses the same MEC based low-level communication and a similar9 * protocol, but with some important differences.  The EC firmware does10 * not support the same mailbox commands so it is not registered as a11 * cros_ec device type.12 *13 * Most messages follow a standard format, but there are some exceptions14 * and an interface is provided to do direct/raw transactions that do not15 * make assumptions about byte placement.16 */17 18#include <linux/delay.h>19#include <linux/device.h>20#include <linux/io.h>21#include <linux/platform_data/wilco-ec.h>22#include <linux/platform_device.h>23 24#include "../cros_ec_lpc_mec.h"25 26/* Version of mailbox interface */27#define EC_MAILBOX_VERSION		028 29/* Command to start mailbox transaction */30#define EC_MAILBOX_START_COMMAND	0xda31 32/* Version of EC protocol */33#define EC_MAILBOX_PROTO_VERSION	334 35/* Number of header bytes to be counted as data bytes */36#define EC_MAILBOX_DATA_EXTRA		237 38/* Maximum timeout */39#define EC_MAILBOX_TIMEOUT		HZ40 41/* EC response flags */42#define EC_CMDR_DATA		BIT(0)	/* Data ready for host to read */43#define EC_CMDR_PENDING		BIT(1)	/* Write pending to EC */44#define EC_CMDR_BUSY		BIT(2)	/* EC is busy processing a command */45#define EC_CMDR_CMD		BIT(3)	/* Last host write was a command */46 47/**48 * wilco_ec_response_timed_out() - Wait for EC response.49 * @ec: EC device.50 *51 * Return: true if EC timed out, false if EC did not time out.52 */53static bool wilco_ec_response_timed_out(struct wilco_ec_device *ec)54{55	unsigned long timeout = jiffies + EC_MAILBOX_TIMEOUT;56 57	do {58		if (!(inb(ec->io_command->start) &59		      (EC_CMDR_PENDING | EC_CMDR_BUSY)))60			return false;61		usleep_range(100, 200);62	} while (time_before(jiffies, timeout));63 64	return true;65}66 67/**68 * wilco_ec_checksum() - Compute 8-bit checksum over data range.69 * @data: Data to checksum.70 * @size: Number of bytes to checksum.71 *72 * Return: 8-bit checksum of provided data.73 */74static u8 wilco_ec_checksum(const void *data, size_t size)75{76	u8 *data_bytes = (u8 *)data;77	u8 checksum = 0;78	size_t i;79 80	for (i = 0; i < size; i++)81		checksum += data_bytes[i];82 83	return checksum;84}85 86/**87 * wilco_ec_prepare() - Prepare the request structure for the EC.88 * @msg: EC message with request information.89 * @rq: EC request structure to fill.90 */91static void wilco_ec_prepare(struct wilco_ec_message *msg,92			     struct wilco_ec_request *rq)93{94	memset(rq, 0, sizeof(*rq));95	rq->struct_version = EC_MAILBOX_PROTO_VERSION;96	rq->mailbox_id = msg->type;97	rq->mailbox_version = EC_MAILBOX_VERSION;98	rq->data_size = msg->request_size;99 100	/* Checksum header and data */101	rq->checksum = wilco_ec_checksum(rq, sizeof(*rq));102	rq->checksum += wilco_ec_checksum(msg->request_data, msg->request_size);103	rq->checksum = -rq->checksum;104}105 106/**107 * wilco_ec_transfer() - Perform actual data transfer.108 * @ec: EC device.109 * @msg: EC message data for request and response.110 * @rq: Filled in request structure111 *112 * Context: ec->mailbox_lock should be held while using this function.113 * Return: number of bytes received or negative error code on failure.114 */115static int wilco_ec_transfer(struct wilco_ec_device *ec,116			     struct wilco_ec_message *msg,117			     struct wilco_ec_request *rq)118{119	struct wilco_ec_response *rs;120	int ret;121	u8 flag;122 123	/* Write request header, then data */124	ret = cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, 0, sizeof(*rq), (u8 *)rq);125	if (ret < 0)126		return ret;127	ret = cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, sizeof(*rq), msg->request_size,128				       msg->request_data);129	if (ret < 0)130		return ret;131 132	/* Start the command */133	outb(EC_MAILBOX_START_COMMAND, ec->io_command->start);134 135	/* For some commands (eg shutdown) the EC will not respond, that's OK */136	if (msg->flags & WILCO_EC_FLAG_NO_RESPONSE) {137		dev_dbg(ec->dev, "EC does not respond to this command\n");138		return 0;139	}140 141	/* Wait for it to complete */142	if (wilco_ec_response_timed_out(ec)) {143		dev_dbg(ec->dev, "response timed out\n");144		return -ETIMEDOUT;145	}146 147	/* Check result */148	flag = inb(ec->io_data->start);149	if (flag) {150		dev_dbg(ec->dev, "bad response: 0x%02x\n", flag);151		return -EIO;152	}153 154	/* Read back response */155	rs = ec->data_buffer;156	ret = cros_ec_lpc_io_bytes_mec(MEC_IO_READ, 0,157				       sizeof(*rs) + EC_MAILBOX_DATA_SIZE,158				       (u8 *)rs);159	if (ret < 0)160		return ret;161	if (ret) {162		dev_dbg(ec->dev, "bad packet checksum 0x%02x\n", rs->checksum);163		return -EBADMSG;164	}165 166	if (rs->result) {167		dev_dbg(ec->dev, "EC reported failure: 0x%02x\n", rs->result);168		return -EBADMSG;169	}170 171	if (rs->data_size != EC_MAILBOX_DATA_SIZE) {172		dev_dbg(ec->dev, "unexpected packet size (%u != %u)\n",173			rs->data_size, EC_MAILBOX_DATA_SIZE);174		return -EMSGSIZE;175	}176 177	if (rs->data_size < msg->response_size) {178		dev_dbg(ec->dev, "EC didn't return enough data (%u < %zu)\n",179			rs->data_size, msg->response_size);180		return -EMSGSIZE;181	}182 183	memcpy(msg->response_data, rs->data, msg->response_size);184 185	return rs->data_size;186}187 188/**189 * wilco_ec_mailbox() - Send EC request and receive EC response.190 * @ec: EC device.191 * @msg: EC message data for request and response.192 *193 * On entry msg->type, msg->request_size, and msg->request_data should all be194 * filled in. If desired, msg->flags can be set.195 *196 * If a response is expected, msg->response_size should be set, and197 * msg->response_data should point to a buffer with enough space. On exit198 * msg->response_data will be filled.199 *200 * Return: number of bytes received or negative error code on failure.201 */202int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg)203{204	struct wilco_ec_request *rq;205	int ret;206 207	dev_dbg(ec->dev, "type=%04x flags=%02x rslen=%zu rqlen=%zu\n",208		msg->type, msg->flags, msg->response_size, msg->request_size);209 210	mutex_lock(&ec->mailbox_lock);211	/* Prepare request packet */212	rq = ec->data_buffer;213	wilco_ec_prepare(msg, rq);214 215	ret = wilco_ec_transfer(ec, msg, rq);216	mutex_unlock(&ec->mailbox_lock);217 218	return ret;219 220}221EXPORT_SYMBOL_GPL(wilco_ec_mailbox);222