brintos

brintos / linux-shallow public Read only

0
0
Text · 14.4 KiB · 1618cca Raw
608 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2023, Intel Corporation.4 * Intel Visual Sensing Controller Transport Layer Linux driver5 */6 7#include <linux/acpi.h>8#include <linux/cleanup.h>9#include <linux/crc32.h>10#include <linux/delay.h>11#include <linux/device.h>12#include <linux/interrupt.h>13#include <linux/iopoll.h>14#include <linux/irq.h>15#include <linux/irqreturn.h>16#include <linux/module.h>17#include <linux/mutex.h>18#include <linux/platform_device.h>19#include <linux/spi/spi.h>20#include <linux/types.h>21 22#include "vsc-tp.h"23 24#define VSC_TP_RESET_PIN_TOGGLE_INTERVAL_MS	2025#define VSC_TP_ROM_BOOTUP_DELAY_MS		1026#define VSC_TP_ROM_XFER_POLL_TIMEOUT_US		(500 * USEC_PER_MSEC)27#define VSC_TP_ROM_XFER_POLL_DELAY_US		(20 * USEC_PER_MSEC)28#define VSC_TP_WAIT_FW_POLL_TIMEOUT		(2 * HZ)29#define VSC_TP_WAIT_FW_POLL_DELAY_US		(20 * USEC_PER_MSEC)30#define VSC_TP_MAX_XFER_COUNT			531 32#define VSC_TP_PACKET_SYNC			0x3133#define VSC_TP_CRC_SIZE				sizeof(u32)34#define VSC_TP_MAX_MSG_SIZE			204835/* SPI xfer timeout size */36#define VSC_TP_XFER_TIMEOUT_BYTES		70037#define VSC_TP_PACKET_PADDING_SIZE		138#define VSC_TP_PACKET_SIZE(pkt) \39	(sizeof(struct vsc_tp_packet) + le16_to_cpu((pkt)->len) + VSC_TP_CRC_SIZE)40#define VSC_TP_MAX_PACKET_SIZE \41	(sizeof(struct vsc_tp_packet) + VSC_TP_MAX_MSG_SIZE + VSC_TP_CRC_SIZE)42#define VSC_TP_MAX_XFER_SIZE \43	(VSC_TP_MAX_PACKET_SIZE + VSC_TP_XFER_TIMEOUT_BYTES)44#define VSC_TP_NEXT_XFER_LEN(len, offset) \45	(len + sizeof(struct vsc_tp_packet) + VSC_TP_CRC_SIZE - offset + VSC_TP_PACKET_PADDING_SIZE)46 47struct vsc_tp_packet {48	__u8 sync;49	__u8 cmd;50	__le16 len;51	__le32 seq;52	__u8 buf[] __counted_by(len);53};54 55struct vsc_tp {56	/* do the actual data transfer */57	struct spi_device *spi;58 59	/* bind with mei framework */60	struct platform_device *pdev;61 62	struct gpio_desc *wakeuphost;63	struct gpio_desc *resetfw;64	struct gpio_desc *wakeupfw;65 66	/* command sequence number */67	u32 seq;68 69	/* command buffer */70	void *tx_buf;71	void *rx_buf;72 73	atomic_t assert_cnt;74	wait_queue_head_t xfer_wait;75 76	vsc_tp_event_cb_t event_notify;77	void *event_notify_context;78 79	/* used to protect command download */80	struct mutex mutex;81};82 83/* GPIO resources */84static const struct acpi_gpio_params wakeuphost_gpio = { 0, 0, false };85static const struct acpi_gpio_params wakeuphostint_gpio = { 1, 0, false };86static const struct acpi_gpio_params resetfw_gpio = { 2, 0, false };87static const struct acpi_gpio_params wakeupfw = { 3, 0, false };88 89static const struct acpi_gpio_mapping vsc_tp_acpi_gpios[] = {90	{ "wakeuphost-gpios", &wakeuphost_gpio, 1 },91	{ "wakeuphostint-gpios", &wakeuphostint_gpio, 1 },92	{ "resetfw-gpios", &resetfw_gpio, 1 },93	{ "wakeupfw-gpios", &wakeupfw, 1 },94	{}95};96 97static irqreturn_t vsc_tp_isr(int irq, void *data)98{99	struct vsc_tp *tp = data;100 101	atomic_inc(&tp->assert_cnt);102 103	wake_up(&tp->xfer_wait);104 105	return IRQ_WAKE_THREAD;106}107 108static irqreturn_t vsc_tp_thread_isr(int irq, void *data)109{110	struct vsc_tp *tp = data;111 112	if (tp->event_notify)113		tp->event_notify(tp->event_notify_context);114 115	return IRQ_HANDLED;116}117 118/* wakeup firmware and wait for response */119static int vsc_tp_wakeup_request(struct vsc_tp *tp)120{121	int ret;122 123	gpiod_set_value_cansleep(tp->wakeupfw, 0);124 125	ret = wait_event_timeout(tp->xfer_wait,126				 atomic_read(&tp->assert_cnt),127				 VSC_TP_WAIT_FW_POLL_TIMEOUT);128	if (!ret)129		return -ETIMEDOUT;130 131	return read_poll_timeout(gpiod_get_value_cansleep, ret, ret,132				 VSC_TP_WAIT_FW_POLL_DELAY_US,133				 VSC_TP_WAIT_FW_POLL_TIMEOUT, false,134				 tp->wakeuphost);135}136 137static void vsc_tp_wakeup_release(struct vsc_tp *tp)138{139	atomic_dec_if_positive(&tp->assert_cnt);140 141	gpiod_set_value_cansleep(tp->wakeupfw, 1);142}143 144static int vsc_tp_dev_xfer(struct vsc_tp *tp, void *obuf, void *ibuf, size_t len)145{146	struct spi_message msg = { 0 };147	struct spi_transfer xfer = {148		.tx_buf = obuf,149		.rx_buf = ibuf,150		.len = len,151	};152 153	spi_message_init_with_transfers(&msg, &xfer, 1);154 155	return spi_sync_locked(tp->spi, &msg);156}157 158static int vsc_tp_xfer_helper(struct vsc_tp *tp, struct vsc_tp_packet *pkt,159			      void *ibuf, u16 ilen)160{161	int ret, offset = 0, cpy_len, src_len, dst_len = sizeof(struct vsc_tp_packet);162	int next_xfer_len = VSC_TP_PACKET_SIZE(pkt) + VSC_TP_XFER_TIMEOUT_BYTES;163	u8 *src, *crc_src, *rx_buf = tp->rx_buf;164	int count_down = VSC_TP_MAX_XFER_COUNT;165	u32 recv_crc = 0, crc = ~0;166	struct vsc_tp_packet ack;167	u8 *dst = (u8 *)&ack;168	bool synced = false;169 170	do {171		ret = vsc_tp_dev_xfer(tp, pkt, rx_buf, next_xfer_len);172		if (ret)173			return ret;174		memset(pkt, 0, VSC_TP_MAX_XFER_SIZE);175 176		if (synced) {177			src = rx_buf;178			src_len = next_xfer_len;179		} else {180			src = memchr(rx_buf, VSC_TP_PACKET_SYNC, next_xfer_len);181			if (!src)182				continue;183			synced = true;184			src_len = next_xfer_len - (src - rx_buf);185		}186 187		/* traverse received data */188		while (src_len > 0) {189			cpy_len = min(src_len, dst_len);190			memcpy(dst, src, cpy_len);191			crc_src = src;192			src += cpy_len;193			src_len -= cpy_len;194			dst += cpy_len;195			dst_len -= cpy_len;196 197			if (offset < sizeof(ack)) {198				offset += cpy_len;199				crc = crc32(crc, crc_src, cpy_len);200 201				if (!src_len)202					continue;203 204				if (le16_to_cpu(ack.len)) {205					dst = ibuf;206					dst_len = min(ilen, le16_to_cpu(ack.len));207				} else {208					dst = (u8 *)&recv_crc;209					dst_len = sizeof(recv_crc);210				}211			} else if (offset < sizeof(ack) + le16_to_cpu(ack.len)) {212				offset += cpy_len;213				crc = crc32(crc, crc_src, cpy_len);214 215				if (src_len) {216					int remain = sizeof(ack) + le16_to_cpu(ack.len) - offset;217 218					cpy_len = min(src_len, remain);219					offset += cpy_len;220					crc = crc32(crc, src, cpy_len);221					src += cpy_len;222					src_len -= cpy_len;223					if (src_len) {224						dst = (u8 *)&recv_crc;225						dst_len = sizeof(recv_crc);226						continue;227					}228				}229				next_xfer_len = VSC_TP_NEXT_XFER_LEN(le16_to_cpu(ack.len), offset);230			} else if (offset < sizeof(ack) + le16_to_cpu(ack.len) + VSC_TP_CRC_SIZE) {231				offset += cpy_len;232 233				if (src_len) {234					/* terminate the traverse */235					next_xfer_len = 0;236					break;237				}238				next_xfer_len = VSC_TP_NEXT_XFER_LEN(le16_to_cpu(ack.len), offset);239			}240		}241	} while (next_xfer_len > 0 && --count_down);242 243	if (next_xfer_len > 0)244		return -EAGAIN;245 246	if (~recv_crc != crc || le32_to_cpu(ack.seq) != tp->seq) {247		dev_err(&tp->spi->dev, "recv crc or seq error\n");248		return -EINVAL;249	}250 251	if (ack.cmd == VSC_TP_CMD_ACK || ack.cmd == VSC_TP_CMD_NACK ||252	    ack.cmd == VSC_TP_CMD_BUSY) {253		dev_err(&tp->spi->dev, "recv cmd ack error\n");254		return -EAGAIN;255	}256 257	return min(le16_to_cpu(ack.len), ilen);258}259 260/**261 * vsc_tp_xfer - transfer data to firmware262 * @tp: vsc_tp device handle263 * @cmd: the command to be sent to the device264 * @obuf: the tx buffer to be sent to the device265 * @olen: the length of tx buffer266 * @ibuf: the rx buffer to receive from the device267 * @ilen: the length of rx buffer268 * Return: the length of received data in case of success,269 *	otherwise negative value270 */271int vsc_tp_xfer(struct vsc_tp *tp, u8 cmd, const void *obuf, size_t olen,272		void *ibuf, size_t ilen)273{274	struct vsc_tp_packet *pkt = tp->tx_buf;275	u32 crc;276	int ret;277 278	if (!obuf || !ibuf || olen > VSC_TP_MAX_MSG_SIZE)279		return -EINVAL;280 281	guard(mutex)(&tp->mutex);282 283	pkt->sync = VSC_TP_PACKET_SYNC;284	pkt->cmd = cmd;285	pkt->len = cpu_to_le16(olen);286	pkt->seq = cpu_to_le32(++tp->seq);287	memcpy(pkt->buf, obuf, olen);288 289	crc = ~crc32(~0, (u8 *)pkt, sizeof(pkt) + olen);290	memcpy(pkt->buf + olen, &crc, sizeof(crc));291 292	ret = vsc_tp_wakeup_request(tp);293	if (unlikely(ret))294		dev_err(&tp->spi->dev, "wakeup firmware failed ret: %d\n", ret);295	else296		ret = vsc_tp_xfer_helper(tp, pkt, ibuf, ilen);297 298	vsc_tp_wakeup_release(tp);299 300	return ret;301}302EXPORT_SYMBOL_NS_GPL(vsc_tp_xfer, VSC_TP);303 304/**305 * vsc_tp_rom_xfer - transfer data to rom code306 * @tp: vsc_tp device handle307 * @obuf: the data buffer to be sent to the device308 * @ibuf: the buffer to receive data from the device309 * @len: the length of tx buffer and rx buffer310 * Return: 0 in case of success, negative value in case of error311 */312int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf, size_t len)313{314	size_t words = len / sizeof(__be32);315	int ret;316 317	if (len % sizeof(__be32) || len > VSC_TP_MAX_MSG_SIZE)318		return -EINVAL;319 320	guard(mutex)(&tp->mutex);321 322	/* rom xfer is big endian */323	cpu_to_be32_array(tp->tx_buf, obuf, words);324 325	ret = read_poll_timeout(gpiod_get_value_cansleep, ret,326				!ret, VSC_TP_ROM_XFER_POLL_DELAY_US,327				VSC_TP_ROM_XFER_POLL_TIMEOUT_US, false,328				tp->wakeuphost);329	if (ret) {330		dev_err(&tp->spi->dev, "wait rom failed ret: %d\n", ret);331		return ret;332	}333 334	ret = vsc_tp_dev_xfer(tp, tp->tx_buf, ibuf ? tp->rx_buf : NULL, len);335	if (ret)336		return ret;337 338	if (ibuf)339		be32_to_cpu_array(ibuf, tp->rx_buf, words);340 341	return ret;342}343 344/**345 * vsc_tp_reset - reset vsc transport layer346 * @tp: vsc_tp device handle347 */348void vsc_tp_reset(struct vsc_tp *tp)349{350	disable_irq(tp->spi->irq);351 352	/* toggle reset pin */353	gpiod_set_value_cansleep(tp->resetfw, 0);354	msleep(VSC_TP_RESET_PIN_TOGGLE_INTERVAL_MS);355	gpiod_set_value_cansleep(tp->resetfw, 1);356 357	/* wait for ROM */358	msleep(VSC_TP_ROM_BOOTUP_DELAY_MS);359 360	/*361	 * Set default host wakeup pin to non-active362	 * to avoid unexpected host irq interrupt.363	 */364	gpiod_set_value_cansleep(tp->wakeupfw, 1);365 366	atomic_set(&tp->assert_cnt, 0);367 368	enable_irq(tp->spi->irq);369}370EXPORT_SYMBOL_NS_GPL(vsc_tp_reset, VSC_TP);371 372/**373 * vsc_tp_need_read - check if device has data to sent374 * @tp: vsc_tp device handle375 * Return: true if device has data to sent, otherwise false376 */377bool vsc_tp_need_read(struct vsc_tp *tp)378{379	if (!atomic_read(&tp->assert_cnt))380		return false;381	if (!gpiod_get_value_cansleep(tp->wakeuphost))382		return false;383	if (!gpiod_get_value_cansleep(tp->wakeupfw))384		return false;385 386	return true;387}388EXPORT_SYMBOL_NS_GPL(vsc_tp_need_read, VSC_TP);389 390/**391 * vsc_tp_register_event_cb - register a callback function to receive event392 * @tp: vsc_tp device handle393 * @event_cb: callback function394 * @context: execution context of event callback395 * Return: 0 in case of success, negative value in case of error396 */397int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb,398			    void *context)399{400	tp->event_notify = event_cb;401	tp->event_notify_context = context;402 403	return 0;404}405EXPORT_SYMBOL_NS_GPL(vsc_tp_register_event_cb, VSC_TP);406 407/**408 * vsc_tp_request_irq - request irq for vsc_tp device409 * @tp: vsc_tp device handle410 */411int vsc_tp_request_irq(struct vsc_tp *tp)412{413	struct spi_device *spi = tp->spi;414	struct device *dev = &spi->dev;415	int ret;416 417	irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY);418	ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr,419				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,420				   dev_name(dev), tp);421	if (ret)422		return ret;423 424	return 0;425}426EXPORT_SYMBOL_NS_GPL(vsc_tp_request_irq, VSC_TP);427 428/**429 * vsc_tp_free_irq - free irq for vsc_tp device430 * @tp: vsc_tp device handle431 */432void vsc_tp_free_irq(struct vsc_tp *tp)433{434	free_irq(tp->spi->irq, tp);435}436EXPORT_SYMBOL_NS_GPL(vsc_tp_free_irq, VSC_TP);437 438/**439 * vsc_tp_intr_synchronize - synchronize vsc_tp interrupt440 * @tp: vsc_tp device handle441 */442void vsc_tp_intr_synchronize(struct vsc_tp *tp)443{444	synchronize_irq(tp->spi->irq);445}446EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_synchronize, VSC_TP);447 448/**449 * vsc_tp_intr_enable - enable vsc_tp interrupt450 * @tp: vsc_tp device handle451 */452void vsc_tp_intr_enable(struct vsc_tp *tp)453{454	enable_irq(tp->spi->irq);455}456EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_enable, VSC_TP);457 458/**459 * vsc_tp_intr_disable - disable vsc_tp interrupt460 * @tp: vsc_tp device handle461 */462void vsc_tp_intr_disable(struct vsc_tp *tp)463{464	disable_irq(tp->spi->irq);465}466EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_disable, VSC_TP);467 468static int vsc_tp_match_any(struct acpi_device *adev, void *data)469{470	struct acpi_device **__adev = data;471 472	*__adev = adev;473 474	return 1;475}476 477static int vsc_tp_probe(struct spi_device *spi)478{479	struct vsc_tp *tp;480	struct platform_device_info pinfo = {481		.name = "intel_vsc",482		.data = &tp,483		.size_data = sizeof(tp),484		.id = PLATFORM_DEVID_NONE,485	};486	struct device *dev = &spi->dev;487	struct platform_device *pdev;488	struct acpi_device *adev;489	int ret;490 491	tp = devm_kzalloc(dev, sizeof(*tp), GFP_KERNEL);492	if (!tp)493		return -ENOMEM;494 495	tp->tx_buf = devm_kzalloc(dev, VSC_TP_MAX_XFER_SIZE, GFP_KERNEL);496	if (!tp->tx_buf)497		return -ENOMEM;498 499	tp->rx_buf = devm_kzalloc(dev, VSC_TP_MAX_XFER_SIZE, GFP_KERNEL);500	if (!tp->rx_buf)501		return -ENOMEM;502 503	ret = devm_acpi_dev_add_driver_gpios(dev, vsc_tp_acpi_gpios);504	if (ret)505		return ret;506 507	tp->wakeuphost = devm_gpiod_get(dev, "wakeuphost", GPIOD_IN);508	if (IS_ERR(tp->wakeuphost))509		return PTR_ERR(tp->wakeuphost);510 511	tp->resetfw = devm_gpiod_get(dev, "resetfw", GPIOD_OUT_HIGH);512	if (IS_ERR(tp->resetfw))513		return PTR_ERR(tp->resetfw);514 515	tp->wakeupfw = devm_gpiod_get(dev, "wakeupfw", GPIOD_OUT_HIGH);516	if (IS_ERR(tp->wakeupfw))517		return PTR_ERR(tp->wakeupfw);518 519	atomic_set(&tp->assert_cnt, 0);520	init_waitqueue_head(&tp->xfer_wait);521	tp->spi = spi;522 523	irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY);524	ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr,525				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,526				   dev_name(dev), tp);527	if (ret)528		return ret;529 530	mutex_init(&tp->mutex);531 532	/* only one child acpi device */533	ret = acpi_dev_for_each_child(ACPI_COMPANION(dev),534				      vsc_tp_match_any, &adev);535	if (!ret) {536		ret = -ENODEV;537		goto err_destroy_lock;538	}539 540	pinfo.fwnode = acpi_fwnode_handle(adev);541	pdev = platform_device_register_full(&pinfo);542	if (IS_ERR(pdev)) {543		ret = PTR_ERR(pdev);544		goto err_destroy_lock;545	}546 547	tp->pdev = pdev;548	spi_set_drvdata(spi, tp);549 550	return 0;551 552err_destroy_lock:553	mutex_destroy(&tp->mutex);554 555	free_irq(spi->irq, tp);556 557	return ret;558}559 560static void vsc_tp_remove(struct spi_device *spi)561{562	struct vsc_tp *tp = spi_get_drvdata(spi);563 564	platform_device_unregister(tp->pdev);565 566	mutex_destroy(&tp->mutex);567 568	free_irq(spi->irq, tp);569}570 571static void vsc_tp_shutdown(struct spi_device *spi)572{573	struct vsc_tp *tp = spi_get_drvdata(spi);574 575	platform_device_unregister(tp->pdev);576 577	mutex_destroy(&tp->mutex);578 579	vsc_tp_reset(tp);580 581	free_irq(spi->irq, tp);582}583 584static const struct acpi_device_id vsc_tp_acpi_ids[] = {585	{ "INTC1009" }, /* Raptor Lake */586	{ "INTC1058" }, /* Tiger Lake */587	{ "INTC1094" }, /* Alder Lake */588	{ "INTC10D0" }, /* Meteor Lake */589	{}590};591MODULE_DEVICE_TABLE(acpi, vsc_tp_acpi_ids);592 593static struct spi_driver vsc_tp_driver = {594	.probe = vsc_tp_probe,595	.remove = vsc_tp_remove,596	.shutdown = vsc_tp_shutdown,597	.driver = {598		.name = "vsc-tp",599		.acpi_match_table = vsc_tp_acpi_ids,600	},601};602module_spi_driver(vsc_tp_driver);603 604MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>");605MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");606MODULE_DESCRIPTION("Intel Visual Sensing Controller Transport Layer");607MODULE_LICENSE("GPL");608