cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

adv7511_cec.c (10597B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * adv7511_cec.c - Analog Devices ADV7511/33 cec driver
      4 *
      5 * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
      6 */
      7
      8#include <linux/device.h>
      9#include <linux/module.h>
     10#include <linux/of_device.h>
     11#include <linux/slab.h>
     12#include <linux/clk.h>
     13
     14#include <media/cec.h>
     15
     16#include "adv7511.h"
     17
     18#define ADV7511_INT1_CEC_MASK \
     19	(ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \
     20	 ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1 | \
     21	 ADV7511_INT1_CEC_RX_READY2 | ADV7511_INT1_CEC_RX_READY3)
     22
     23static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
     24{
     25	unsigned int offset = adv7511->reg_cec_offset;
     26	unsigned int val;
     27
     28	if (regmap_read(adv7511->regmap_cec,
     29			ADV7511_REG_CEC_TX_ENABLE + offset, &val))
     30		return;
     31
     32	if ((val & 0x01) == 0)
     33		return;
     34
     35	if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) {
     36		cec_transmit_attempt_done(adv7511->cec_adap,
     37					  CEC_TX_STATUS_ARB_LOST);
     38		return;
     39	}
     40	if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) {
     41		u8 status;
     42		u8 err_cnt = 0;
     43		u8 nack_cnt = 0;
     44		u8 low_drive_cnt = 0;
     45		unsigned int cnt;
     46
     47		/*
     48		 * We set this status bit since this hardware performs
     49		 * retransmissions.
     50		 */
     51		status = CEC_TX_STATUS_MAX_RETRIES;
     52		if (regmap_read(adv7511->regmap_cec,
     53			    ADV7511_REG_CEC_TX_LOW_DRV_CNT + offset, &cnt)) {
     54			err_cnt = 1;
     55			status |= CEC_TX_STATUS_ERROR;
     56		} else {
     57			nack_cnt = cnt & 0xf;
     58			if (nack_cnt)
     59				status |= CEC_TX_STATUS_NACK;
     60			low_drive_cnt = cnt >> 4;
     61			if (low_drive_cnt)
     62				status |= CEC_TX_STATUS_LOW_DRIVE;
     63		}
     64		cec_transmit_done(adv7511->cec_adap, status,
     65				  0, nack_cnt, low_drive_cnt, err_cnt);
     66		return;
     67	}
     68	if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) {
     69		cec_transmit_attempt_done(adv7511->cec_adap, CEC_TX_STATUS_OK);
     70		return;
     71	}
     72}
     73
     74static void adv7511_cec_rx(struct adv7511 *adv7511, int rx_buf)
     75{
     76	unsigned int offset = adv7511->reg_cec_offset;
     77	struct cec_msg msg = {};
     78	unsigned int len;
     79	unsigned int val;
     80	u8 i;
     81
     82	if (regmap_read(adv7511->regmap_cec,
     83			ADV7511_REG_CEC_RX_FRAME_LEN[rx_buf] + offset, &len))
     84		return;
     85
     86	msg.len = len & 0x1f;
     87
     88	if (msg.len > 16)
     89		msg.len = 16;
     90
     91	if (!msg.len)
     92		return;
     93
     94	for (i = 0; i < msg.len; i++) {
     95		regmap_read(adv7511->regmap_cec,
     96			    i + ADV7511_REG_CEC_RX_FRAME_HDR[rx_buf] + offset,
     97			    &val);
     98		msg.msg[i] = val;
     99	}
    100
    101	/* Toggle RX Ready Clear bit to re-enable this RX buffer */
    102	regmap_update_bits(adv7511->regmap_cec,
    103			   ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf),
    104			   BIT(rx_buf));
    105	regmap_update_bits(adv7511->regmap_cec,
    106			   ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf), 0);
    107
    108	cec_received_msg(adv7511->cec_adap, &msg);
    109}
    110
    111void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
    112{
    113	unsigned int offset = adv7511->reg_cec_offset;
    114	const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |
    115				ADV7511_INT1_CEC_TX_ARBIT_LOST |
    116				ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;
    117	const u32 irq_rx_mask = ADV7511_INT1_CEC_RX_READY1 |
    118				ADV7511_INT1_CEC_RX_READY2 |
    119				ADV7511_INT1_CEC_RX_READY3;
    120	unsigned int rx_status;
    121	int rx_order[3] = { -1, -1, -1 };
    122	int i;
    123
    124	if (irq1 & irq_tx_mask)
    125		adv_cec_tx_raw_status(adv7511, irq1);
    126
    127	if (!(irq1 & irq_rx_mask))
    128		return;
    129
    130	if (regmap_read(adv7511->regmap_cec,
    131			ADV7511_REG_CEC_RX_STATUS + offset, &rx_status))
    132		return;
    133
    134	/*
    135	 * ADV7511_REG_CEC_RX_STATUS[5:0] contains the reception order of RX
    136	 * buffers 0, 1, and 2 in bits [1:0], [3:2], and [5:4] respectively.
    137	 * The values are to be interpreted as follows:
    138	 *
    139	 *   0 = buffer unused
    140	 *   1 = buffer contains oldest received frame (if applicable)
    141	 *   2 = buffer contains second oldest received frame (if applicable)
    142	 *   3 = buffer contains third oldest received frame (if applicable)
    143	 *
    144	 * Fill rx_order with the sequence of RX buffer indices to
    145	 * read from in order, where -1 indicates that there are no
    146	 * more buffers to process.
    147	 */
    148	for (i = 0; i < 3; i++) {
    149		unsigned int timestamp = (rx_status >> (2 * i)) & 0x3;
    150
    151		if (timestamp)
    152			rx_order[timestamp - 1] = i;
    153	}
    154
    155	/* Read CEC RX buffers in the appropriate order as prescribed above */
    156	for (i = 0; i < 3; i++) {
    157		int rx_buf = rx_order[i];
    158
    159		if (rx_buf < 0)
    160			break;
    161
    162		adv7511_cec_rx(adv7511, rx_buf);
    163	}
    164}
    165
    166static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
    167{
    168	struct adv7511 *adv7511 = cec_get_drvdata(adap);
    169	unsigned int offset = adv7511->reg_cec_offset;
    170
    171	if (adv7511->i2c_cec == NULL)
    172		return -EIO;
    173
    174	if (!adv7511->cec_enabled_adap && enable) {
    175		/* power up cec section */
    176		regmap_update_bits(adv7511->regmap_cec,
    177				   ADV7511_REG_CEC_CLK_DIV + offset,
    178				   0x03, 0x01);
    179		/* non-legacy mode and clear all rx buffers */
    180		regmap_write(adv7511->regmap_cec,
    181			     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x0f);
    182		regmap_write(adv7511->regmap_cec,
    183			     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);
    184		/* initially disable tx */
    185		regmap_update_bits(adv7511->regmap_cec,
    186				   ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);
    187		/* enabled irqs: */
    188		/* tx: ready */
    189		/* tx: arbitration lost */
    190		/* tx: retry timeout */
    191		/* rx: ready 1-3 */
    192		regmap_update_bits(adv7511->regmap,
    193				   ADV7511_REG_INT_ENABLE(1), 0x3f,
    194				   ADV7511_INT1_CEC_MASK);
    195	} else if (adv7511->cec_enabled_adap && !enable) {
    196		regmap_update_bits(adv7511->regmap,
    197				   ADV7511_REG_INT_ENABLE(1), 0x3f, 0);
    198		/* disable address mask 1-3 */
    199		regmap_update_bits(adv7511->regmap_cec,
    200				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
    201				   0x70, 0x00);
    202		/* power down cec section */
    203		regmap_update_bits(adv7511->regmap_cec,
    204				   ADV7511_REG_CEC_CLK_DIV + offset,
    205				   0x03, 0x00);
    206		adv7511->cec_valid_addrs = 0;
    207	}
    208	adv7511->cec_enabled_adap = enable;
    209	return 0;
    210}
    211
    212static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
    213{
    214	struct adv7511 *adv7511 = cec_get_drvdata(adap);
    215	unsigned int offset = adv7511->reg_cec_offset;
    216	unsigned int i, free_idx = ADV7511_MAX_ADDRS;
    217
    218	if (!adv7511->cec_enabled_adap)
    219		return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;
    220
    221	if (addr == CEC_LOG_ADDR_INVALID) {
    222		regmap_update_bits(adv7511->regmap_cec,
    223				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
    224				   0x70, 0);
    225		adv7511->cec_valid_addrs = 0;
    226		return 0;
    227	}
    228
    229	for (i = 0; i < ADV7511_MAX_ADDRS; i++) {
    230		bool is_valid = adv7511->cec_valid_addrs & (1 << i);
    231
    232		if (free_idx == ADV7511_MAX_ADDRS && !is_valid)
    233			free_idx = i;
    234		if (is_valid && adv7511->cec_addr[i] == addr)
    235			return 0;
    236	}
    237	if (i == ADV7511_MAX_ADDRS) {
    238		i = free_idx;
    239		if (i == ADV7511_MAX_ADDRS)
    240			return -ENXIO;
    241	}
    242	adv7511->cec_addr[i] = addr;
    243	adv7511->cec_valid_addrs |= 1 << i;
    244
    245	switch (i) {
    246	case 0:
    247		/* enable address mask 0 */
    248		regmap_update_bits(adv7511->regmap_cec,
    249				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
    250				   0x10, 0x10);
    251		/* set address for mask 0 */
    252		regmap_update_bits(adv7511->regmap_cec,
    253				   ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
    254				   0x0f, addr);
    255		break;
    256	case 1:
    257		/* enable address mask 1 */
    258		regmap_update_bits(adv7511->regmap_cec,
    259				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
    260				   0x20, 0x20);
    261		/* set address for mask 1 */
    262		regmap_update_bits(adv7511->regmap_cec,
    263				   ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,
    264				   0xf0, addr << 4);
    265		break;
    266	case 2:
    267		/* enable address mask 2 */
    268		regmap_update_bits(adv7511->regmap_cec,
    269				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,
    270				   0x40, 0x40);
    271		/* set address for mask 1 */
    272		regmap_update_bits(adv7511->regmap_cec,
    273				   ADV7511_REG_CEC_LOG_ADDR_2 + offset,
    274				   0x0f, addr);
    275		break;
    276	}
    277	return 0;
    278}
    279
    280static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
    281				     u32 signal_free_time, struct cec_msg *msg)
    282{
    283	struct adv7511 *adv7511 = cec_get_drvdata(adap);
    284	unsigned int offset = adv7511->reg_cec_offset;
    285	u8 len = msg->len;
    286	unsigned int i;
    287
    288	/*
    289	 * The number of retries is the number of attempts - 1, but retry
    290	 * at least once. It's not clear if a value of 0 is allowed, so
    291	 * let's do at least one retry.
    292	 */
    293	regmap_update_bits(adv7511->regmap_cec,
    294			   ADV7511_REG_CEC_TX_RETRY + offset,
    295			   0x70, max(1, attempts - 1) << 4);
    296
    297	/* blocking, clear cec tx irq status */
    298	regmap_update_bits(adv7511->regmap, ADV7511_REG_INT(1), 0x38, 0x38);
    299
    300	/* write data */
    301	for (i = 0; i < len; i++)
    302		regmap_write(adv7511->regmap_cec,
    303			     i + ADV7511_REG_CEC_TX_FRAME_HDR + offset,
    304			     msg->msg[i]);
    305
    306	/* set length (data + header) */
    307	regmap_write(adv7511->regmap_cec,
    308		     ADV7511_REG_CEC_TX_FRAME_LEN + offset, len);
    309	/* start transmit, enable tx */
    310	regmap_write(adv7511->regmap_cec,
    311		     ADV7511_REG_CEC_TX_ENABLE + offset, 0x01);
    312	return 0;
    313}
    314
    315static const struct cec_adap_ops adv7511_cec_adap_ops = {
    316	.adap_enable = adv7511_cec_adap_enable,
    317	.adap_log_addr = adv7511_cec_adap_log_addr,
    318	.adap_transmit = adv7511_cec_adap_transmit,
    319};
    320
    321static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
    322{
    323	adv7511->cec_clk = devm_clk_get(dev, "cec");
    324	if (IS_ERR(adv7511->cec_clk)) {
    325		int ret = PTR_ERR(adv7511->cec_clk);
    326
    327		adv7511->cec_clk = NULL;
    328		return ret;
    329	}
    330	clk_prepare_enable(adv7511->cec_clk);
    331	adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);
    332	return 0;
    333}
    334
    335int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
    336{
    337	unsigned int offset = adv7511->reg_cec_offset;
    338	int ret = adv7511_cec_parse_dt(dev, adv7511);
    339
    340	if (ret)
    341		goto err_cec_parse_dt;
    342
    343	adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,
    344		adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
    345	if (IS_ERR(adv7511->cec_adap)) {
    346		ret = PTR_ERR(adv7511->cec_adap);
    347		goto err_cec_alloc;
    348	}
    349
    350	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0);
    351	/* cec soft reset */
    352	regmap_write(adv7511->regmap_cec,
    353		     ADV7511_REG_CEC_SOFT_RESET + offset, 0x01);
    354	regmap_write(adv7511->regmap_cec,
    355		     ADV7511_REG_CEC_SOFT_RESET + offset, 0x00);
    356
    357	/* non-legacy mode - use all three RX buffers */
    358	regmap_write(adv7511->regmap_cec,
    359		     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);
    360
    361	regmap_write(adv7511->regmap_cec,
    362		     ADV7511_REG_CEC_CLK_DIV + offset,
    363		     ((adv7511->cec_clk_freq / 750000) - 1) << 2);
    364
    365	ret = cec_register_adapter(adv7511->cec_adap, dev);
    366	if (ret)
    367		goto err_cec_register;
    368	return 0;
    369
    370err_cec_register:
    371	cec_delete_adapter(adv7511->cec_adap);
    372	adv7511->cec_adap = NULL;
    373err_cec_alloc:
    374	dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
    375		 ret);
    376err_cec_parse_dt:
    377	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
    378		     ADV7511_CEC_CTRL_POWER_DOWN);
    379	return ret == -EPROBE_DEFER ? ret : 0;
    380}