File Index
Files and directories
Sign in
FILE

adv7511_cec.c

File preview with syntax highlighting.

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