brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · a895e42 Raw
420 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Microchip / Atmel ECC (I2C) driver.4 *5 * Copyright (c) 2017, Microchip Technology Inc.6 * Author: Tudor Ambarus7 */8 9#include <linux/bitrev.h>10#include <linux/crc16.h>11#include <linux/delay.h>12#include <linux/device.h>13#include <linux/err.h>14#include <linux/errno.h>15#include <linux/i2c.h>16#include <linux/init.h>17#include <linux/kernel.h>18#include <linux/module.h>19#include <linux/scatterlist.h>20#include <linux/slab.h>21#include <linux/workqueue.h>22#include "atmel-i2c.h"23 24static const struct {25	u8 value;26	const char *error_text;27} error_list[] = {28	{ 0x01, "CheckMac or Verify miscompare" },29	{ 0x03, "Parse Error" },30	{ 0x05, "ECC Fault" },31	{ 0x0F, "Execution Error" },32	{ 0xEE, "Watchdog about to expire" },33	{ 0xFF, "CRC or other communication error" },34};35 36/**37 * atmel_i2c_checksum() - Generate 16-bit CRC as required by ATMEL ECC.38 * CRC16 verification of the count, opcode, param1, param2 and data bytes.39 * The checksum is saved in little-endian format in the least significant40 * two bytes of the command. CRC polynomial is 0x8005 and the initial register41 * value should be zero.42 *43 * @cmd : structure used for communicating with the device.44 */45static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd)46{47	u8 *data = &cmd->count;48	size_t len = cmd->count - CRC_SIZE;49	__le16 *__crc16 = (__le16 *)(data + len);50 51	*__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len)));52}53 54void atmel_i2c_init_read_config_cmd(struct atmel_i2c_cmd *cmd)55{56	cmd->word_addr = COMMAND;57	cmd->opcode = OPCODE_READ;58	/*59	 * Read the word from Configuration zone that contains the lock bytes60	 * (UserExtra, Selector, LockValue, LockConfig).61	 */62	cmd->param1 = CONFIGURATION_ZONE;63	cmd->param2 = cpu_to_le16(DEVICE_LOCK_ADDR);64	cmd->count = READ_COUNT;65 66	atmel_i2c_checksum(cmd);67 68	cmd->msecs = MAX_EXEC_TIME_READ;69	cmd->rxsize = READ_RSP_SIZE;70}71EXPORT_SYMBOL(atmel_i2c_init_read_config_cmd);72 73int atmel_i2c_init_read_otp_cmd(struct atmel_i2c_cmd *cmd, u16 addr)74{75	if (addr < 0 || addr > OTP_ZONE_SIZE)76		return -1;77 78	cmd->word_addr = COMMAND;79	cmd->opcode = OPCODE_READ;80	/*81	 * Read the word from OTP zone that may contain e.g. serial82	 * numbers or similar if persistently pre-initialized and locked83	 */84	cmd->param1 = OTP_ZONE;85	cmd->param2 = cpu_to_le16(addr);86	cmd->count = READ_COUNT;87 88	atmel_i2c_checksum(cmd);89 90	cmd->msecs = MAX_EXEC_TIME_READ;91	cmd->rxsize = READ_RSP_SIZE;92 93	return 0;94}95EXPORT_SYMBOL(atmel_i2c_init_read_otp_cmd);96 97void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd)98{99	cmd->word_addr = COMMAND;100	cmd->opcode = OPCODE_RANDOM;101	cmd->param1 = 0;102	cmd->param2 = 0;103	cmd->count = RANDOM_COUNT;104 105	atmel_i2c_checksum(cmd);106 107	cmd->msecs = MAX_EXEC_TIME_RANDOM;108	cmd->rxsize = RANDOM_RSP_SIZE;109}110EXPORT_SYMBOL(atmel_i2c_init_random_cmd);111 112void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid)113{114	cmd->word_addr = COMMAND;115	cmd->count = GENKEY_COUNT;116	cmd->opcode = OPCODE_GENKEY;117	cmd->param1 = GENKEY_MODE_PRIVATE;118	/* a random private key will be generated and stored in slot keyID */119	cmd->param2 = cpu_to_le16(keyid);120 121	atmel_i2c_checksum(cmd);122 123	cmd->msecs = MAX_EXEC_TIME_GENKEY;124	cmd->rxsize = GENKEY_RSP_SIZE;125}126EXPORT_SYMBOL(atmel_i2c_init_genkey_cmd);127 128int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,129			    struct scatterlist *pubkey)130{131	size_t copied;132 133	cmd->word_addr = COMMAND;134	cmd->count = ECDH_COUNT;135	cmd->opcode = OPCODE_ECDH;136	cmd->param1 = ECDH_PREFIX_MODE;137	/* private key slot */138	cmd->param2 = cpu_to_le16(DATA_SLOT_2);139 140	/*141	 * The device only supports NIST P256 ECC keys. The public key size will142	 * always be the same. Use a macro for the key size to avoid unnecessary143	 * computations.144	 */145	copied = sg_copy_to_buffer(pubkey,146				   sg_nents_for_len(pubkey,147						    ATMEL_ECC_PUBKEY_SIZE),148				   cmd->data, ATMEL_ECC_PUBKEY_SIZE);149	if (copied != ATMEL_ECC_PUBKEY_SIZE)150		return -EINVAL;151 152	atmel_i2c_checksum(cmd);153 154	cmd->msecs = MAX_EXEC_TIME_ECDH;155	cmd->rxsize = ECDH_RSP_SIZE;156 157	return 0;158}159EXPORT_SYMBOL(atmel_i2c_init_ecdh_cmd);160 161/*162 * After wake and after execution of a command, there will be error, status, or163 * result bytes in the device's output register that can be retrieved by the164 * system. When the length of that group is four bytes, the codes returned are165 * detailed in error_list.166 */167static int atmel_i2c_status(struct device *dev, u8 *status)168{169	size_t err_list_len = ARRAY_SIZE(error_list);170	int i;171	u8 err_id = status[1];172 173	if (*status != STATUS_SIZE)174		return 0;175 176	if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR)177		return 0;178 179	for (i = 0; i < err_list_len; i++)180		if (error_list[i].value == err_id)181			break;182 183	/* if err_id is not in the error_list then ignore it */184	if (i != err_list_len) {185		dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text);186		return err_id;187	}188 189	return 0;190}191 192static int atmel_i2c_wakeup(struct i2c_client *client)193{194	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);195	u8 status[STATUS_RSP_SIZE];196	int ret;197 198	/*199	 * The device ignores any levels or transitions on the SCL pin when the200	 * device is idle, asleep or during waking up. Don't check for error201	 * when waking up the device.202	 */203	i2c_transfer_buffer_flags(client, i2c_priv->wake_token,204				i2c_priv->wake_token_sz, I2C_M_IGNORE_NAK);205 206	/*207	 * Wait to wake the device. Typical execution times for ecdh and genkey208	 * are around tens of milliseconds. Delta is chosen to 50 microseconds.209	 */210	usleep_range(TWHI_MIN, TWHI_MAX);211 212	ret = i2c_master_recv(client, status, STATUS_SIZE);213	if (ret < 0)214		return ret;215 216	return atmel_i2c_status(&client->dev, status);217}218 219static int atmel_i2c_sleep(struct i2c_client *client)220{221	u8 sleep = SLEEP_TOKEN;222 223	return i2c_master_send(client, &sleep, 1);224}225 226/*227 * atmel_i2c_send_receive() - send a command to the device and receive its228 *                            response.229 * @client: i2c client device230 * @cmd   : structure used to communicate with the device231 *232 * After the device receives a Wake token, a watchdog counter starts within the233 * device. After the watchdog timer expires, the device enters sleep mode234 * regardless of whether some I/O transmission or command execution is in235 * progress. If a command is attempted when insufficient time remains prior to236 * watchdog timer execution, the device will return the watchdog timeout error237 * code without attempting to execute the command. There is no way to reset the238 * counter other than to put the device into sleep or idle mode and then239 * wake it up again.240 */241int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd)242{243	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);244	int ret;245 246	mutex_lock(&i2c_priv->lock);247 248	ret = atmel_i2c_wakeup(client);249	if (ret)250		goto err;251 252	/* send the command */253	ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE);254	if (ret < 0)255		goto err;256 257	/* delay the appropriate amount of time for command to execute */258	msleep(cmd->msecs);259 260	/* receive the response */261	ret = i2c_master_recv(client, cmd->data, cmd->rxsize);262	if (ret < 0)263		goto err;264 265	/* put the device into low-power mode */266	ret = atmel_i2c_sleep(client);267	if (ret < 0)268		goto err;269 270	mutex_unlock(&i2c_priv->lock);271	return atmel_i2c_status(&client->dev, cmd->data);272err:273	mutex_unlock(&i2c_priv->lock);274	return ret;275}276EXPORT_SYMBOL(atmel_i2c_send_receive);277 278static void atmel_i2c_work_handler(struct work_struct *work)279{280	struct atmel_i2c_work_data *work_data =281			container_of(work, struct atmel_i2c_work_data, work);282	struct atmel_i2c_cmd *cmd = &work_data->cmd;283	struct i2c_client *client = work_data->client;284	int status;285 286	status = atmel_i2c_send_receive(client, cmd);287	work_data->cbk(work_data, work_data->areq, status);288}289 290static struct workqueue_struct *atmel_wq;291 292void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data,293		       void (*cbk)(struct atmel_i2c_work_data *work_data,294				   void *areq, int status),295		       void *areq)296{297	work_data->cbk = (void *)cbk;298	work_data->areq = areq;299 300	INIT_WORK(&work_data->work, atmel_i2c_work_handler);301	queue_work(atmel_wq, &work_data->work);302}303EXPORT_SYMBOL(atmel_i2c_enqueue);304 305void atmel_i2c_flush_queue(void)306{307	flush_workqueue(atmel_wq);308}309EXPORT_SYMBOL(atmel_i2c_flush_queue);310 311static inline size_t atmel_i2c_wake_token_sz(u32 bus_clk_rate)312{313	u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC);314 315	/* return the size of the wake_token in bytes */316	return DIV_ROUND_UP(no_of_bits, 8);317}318 319static int device_sanity_check(struct i2c_client *client)320{321	struct atmel_i2c_cmd *cmd;322	int ret;323 324	cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);325	if (!cmd)326		return -ENOMEM;327 328	atmel_i2c_init_read_config_cmd(cmd);329 330	ret = atmel_i2c_send_receive(client, cmd);331	if (ret)332		goto free_cmd;333 334	/*335	 * It is vital that the Configuration, Data and OTP zones be locked336	 * prior to release into the field of the system containing the device.337	 * Failure to lock these zones may permit modification of any secret338	 * keys and may lead to other security problems.339	 */340	if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) {341		dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n");342		ret = -ENOTSUPP;343	}344 345	/* fall through */346free_cmd:347	kfree(cmd);348	return ret;349}350 351int atmel_i2c_probe(struct i2c_client *client)352{353	struct atmel_i2c_client_priv *i2c_priv;354	struct device *dev = &client->dev;355	int ret;356	u32 bus_clk_rate;357 358	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {359		dev_err(dev, "I2C_FUNC_I2C not supported\n");360		return -ENODEV;361	}362 363	bus_clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev);364	if (!bus_clk_rate) {365		ret = device_property_read_u32(&client->adapter->dev,366					       "clock-frequency", &bus_clk_rate);367		if (ret) {368			dev_err(dev, "failed to read clock-frequency property\n");369			return ret;370		}371	}372 373	if (bus_clk_rate > 1000000L) {374		dev_err(dev, "%u exceeds maximum supported clock frequency (1MHz)\n",375			bus_clk_rate);376		return -EINVAL;377	}378 379	i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL);380	if (!i2c_priv)381		return -ENOMEM;382 383	i2c_priv->client = client;384	mutex_init(&i2c_priv->lock);385 386	/*387	 * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate -388	 * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz389	 * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE.390	 */391	i2c_priv->wake_token_sz = atmel_i2c_wake_token_sz(bus_clk_rate);392 393	memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token));394 395	atomic_set(&i2c_priv->tfm_count, 0);396 397	i2c_set_clientdata(client, i2c_priv);398 399	return device_sanity_check(client);400}401EXPORT_SYMBOL(atmel_i2c_probe);402 403static int __init atmel_i2c_init(void)404{405	atmel_wq = alloc_workqueue("atmel_wq", 0, 0);406	return atmel_wq ? 0 : -ENOMEM;407}408 409static void __exit atmel_i2c_exit(void)410{411	destroy_workqueue(atmel_wq);412}413 414module_init(atmel_i2c_init);415module_exit(atmel_i2c_exit);416 417MODULE_AUTHOR("Tudor Ambarus");418MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");419MODULE_LICENSE("GPL v2");420