Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
26516 views
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
19
static 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
25
static 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
36
static 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
89
static 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
126
int 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
186
int 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
232
int 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
300
int 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
335
static 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
349
int 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
379
err_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
}
384
385