1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * vivid-cec.c - A Virtual Video Test Driver, cec emulation
4 *
5 * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 */
7
8#include <linux/delay.h>
9#include <media/cec.h>
10
11#include "vivid-core.h"
12#include "vivid-cec.h"
13
14#define CEC_START_BIT_US 4500
15#define CEC_DATA_BIT_US 2400
16#define CEC_MARGIN_US 350
17
18struct xfer_on_bus {
19 struct cec_adapter *adap;
20 u8 status;
21};
22
23static bool find_dest_adap(struct vivid_dev *dev,
24 struct cec_adapter *adap, u8 dest)
25{
26 unsigned int i;
27
28 if (dest >= 0xf)
29 return false;
30
31 if (adap != dev->cec_rx_adap && dev->cec_rx_adap &&
32 dev->cec_rx_adap->is_configured &&
33 cec_has_log_addr(adap: dev->cec_rx_adap, log_addr: dest))
34 return true;
35
36 for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) {
37 if (adap == dev->cec_tx_adap[i])
38 continue;
39 if (!dev->cec_tx_adap[i]->is_configured)
40 continue;
41 if (cec_has_log_addr(adap: dev->cec_tx_adap[i], log_addr: dest))
42 return true;
43 }
44 return false;
45}
46
47static bool xfer_ready(struct vivid_dev *dev)
48{
49 unsigned int i;
50 bool ready = false;
51
52 spin_lock(lock: &dev->cec_xfers_slock);
53 for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
54 if (dev->xfers[i].sft &&
55 dev->xfers[i].sft <= dev->cec_sft) {
56 ready = true;
57 break;
58 }
59 }
60 spin_unlock(lock: &dev->cec_xfers_slock);
61
62 return ready;
63}
64
65/*
66 * If an adapter tries to send successive messages, it must wait for the
67 * longest signal-free time between its transmissions. But, if another
68 * adapter sends a message in the interim, then the wait can be reduced
69 * because the messages are no longer successive. Make these adjustments
70 * if necessary. Should be called holding cec_xfers_slock.
71 */
72static void adjust_sfts(struct vivid_dev *dev)
73{
74 unsigned int i;
75 u8 initiator;
76
77 for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
78 if (dev->xfers[i].sft <= CEC_SIGNAL_FREE_TIME_RETRY)
79 continue;
80 initiator = dev->xfers[i].msg[0] >> 4;
81 if (initiator == dev->last_initiator)
82 dev->xfers[i].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
83 else
84 dev->xfers[i].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
85 }
86}
87
88/*
89 * The main emulation of the bus on which CEC adapters attempt to send
90 * messages to each other. The bus keeps track of how long it has been
91 * signal-free and accepts a pending transmission only if the state of
92 * the bus matches the transmission's signal-free requirements. It calls
93 * cec_transmit_attempt_done() for all transmits that enter the bus and
94 * cec_received_msg() for successful transmits.
95 */
96int vivid_cec_bus_thread(void *_dev)
97{
98 u32 last_sft;
99 unsigned int i;
100 unsigned int dest;
101 ktime_t start, end;
102 s64 delta_us, retry_us;
103 struct vivid_dev *dev = _dev;
104
105 dev->cec_sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
106 for (;;) {
107 bool first = true;
108 int wait_xfer_us = 0;
109 bool valid_dest = false;
110 int wait_arb_lost_us = 0;
111 unsigned int first_idx = 0;
112 unsigned int first_status = 0;
113 struct cec_msg first_msg = {};
114 struct xfer_on_bus xfers_on_bus[MAX_OUTPUTS] = {};
115
116 wait_event_interruptible(dev->kthread_waitq_cec, xfer_ready(dev) ||
117 kthread_should_stop());
118 if (kthread_should_stop())
119 break;
120 last_sft = dev->cec_sft;
121 dev->cec_sft = 0;
122 /*
123 * Move the messages that are ready onto the bus. The adapter with
124 * the most leading zeros will win control of the bus and any other
125 * adapters will lose arbitration.
126 */
127 spin_lock(lock: &dev->cec_xfers_slock);
128 for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
129 if (!dev->xfers[i].sft || dev->xfers[i].sft > last_sft)
130 continue;
131 if (first) {
132 first = false;
133 first_idx = i;
134 xfers_on_bus[first_idx].adap = dev->xfers[i].adap;
135 memcpy(first_msg.msg, dev->xfers[i].msg, dev->xfers[i].len);
136 first_msg.len = dev->xfers[i].len;
137 } else {
138 xfers_on_bus[i].adap = dev->xfers[i].adap;
139 xfers_on_bus[i].status = CEC_TX_STATUS_ARB_LOST;
140 /*
141 * For simplicity wait for all 4 bits of the initiator's
142 * address even though HDMI specification uses bit-level
143 * precision.
144 */
145 wait_arb_lost_us = 4 * CEC_DATA_BIT_US + CEC_START_BIT_US;
146 }
147 dev->xfers[i].sft = 0;
148 }
149 dev->last_initiator = cec_msg_initiator(msg: &first_msg);
150 adjust_sfts(dev);
151 spin_unlock(lock: &dev->cec_xfers_slock);
152
153 dest = cec_msg_destination(msg: &first_msg);
154 valid_dest = cec_msg_is_broadcast(msg: &first_msg);
155 if (!valid_dest)
156 valid_dest = find_dest_adap(dev, adap: xfers_on_bus[first_idx].adap, dest);
157 if (valid_dest) {
158 first_status = CEC_TX_STATUS_OK;
159 /*
160 * Message length is in bytes, but each byte is transmitted in
161 * a block of 10 bits.
162 */
163 wait_xfer_us = first_msg.len * 10 * CEC_DATA_BIT_US;
164 } else {
165 first_status = CEC_TX_STATUS_NACK;
166 /*
167 * A message that is not acknowledged stops transmitting after
168 * the header block of 10 bits.
169 */
170 wait_xfer_us = 10 * CEC_DATA_BIT_US;
171 }
172 wait_xfer_us += CEC_START_BIT_US;
173 xfers_on_bus[first_idx].status = first_status;
174
175 /* Sleep as if sending messages on a real hardware bus. */
176 start = ktime_get();
177 if (wait_arb_lost_us) {
178 usleep_range(min: wait_arb_lost_us - CEC_MARGIN_US, max: wait_arb_lost_us);
179 for (i = 0; i < ARRAY_SIZE(xfers_on_bus); i++) {
180 if (xfers_on_bus[i].status != CEC_TX_STATUS_ARB_LOST)
181 continue;
182 cec_transmit_attempt_done(adap: xfers_on_bus[i].adap,
183 CEC_TX_STATUS_ARB_LOST);
184 }
185 if (kthread_should_stop())
186 break;
187 }
188 wait_xfer_us -= wait_arb_lost_us;
189 usleep_range(min: wait_xfer_us - CEC_MARGIN_US, max: wait_xfer_us);
190 cec_transmit_attempt_done(adap: xfers_on_bus[first_idx].adap, status: first_status);
191 if (kthread_should_stop())
192 break;
193 if (first_status == CEC_TX_STATUS_OK) {
194 if (xfers_on_bus[first_idx].adap != dev->cec_rx_adap)
195 cec_received_msg(adap: dev->cec_rx_adap, msg: &first_msg);
196 for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
197 if (xfers_on_bus[first_idx].adap != dev->cec_tx_adap[i])
198 cec_received_msg(adap: dev->cec_tx_adap[i], msg: &first_msg);
199 }
200 end = ktime_get();
201 /*
202 * If the emulated transfer took more or less time than it should
203 * have, then compensate by adjusting the wait time needed for the
204 * bus to be signal-free for 3 bit periods (the retry time).
205 */
206 delta_us = div_s64(dividend: end - start, divisor: 1000);
207 delta_us -= wait_xfer_us + wait_arb_lost_us;
208 retry_us = CEC_SIGNAL_FREE_TIME_RETRY * CEC_DATA_BIT_US - delta_us;
209 if (retry_us > CEC_MARGIN_US)
210 usleep_range(min: retry_us - CEC_MARGIN_US, max: retry_us);
211 dev->cec_sft = CEC_SIGNAL_FREE_TIME_RETRY;
212 /*
213 * If there are no messages that need to be retried, check if any
214 * adapters that did not just transmit a message are ready to
215 * transmit. If none of these adapters are ready, then increase
216 * the signal-free time so that the bus is available to all
217 * adapters and go back to waiting for a transmission.
218 */
219 while (dev->cec_sft >= CEC_SIGNAL_FREE_TIME_RETRY &&
220 dev->cec_sft < CEC_SIGNAL_FREE_TIME_NEXT_XFER &&
221 !xfer_ready(dev) && !kthread_should_stop()) {
222 usleep_range(min: 2 * CEC_DATA_BIT_US - CEC_MARGIN_US,
223 max: 2 * CEC_DATA_BIT_US);
224 dev->cec_sft += 2;
225 }
226 }
227 return 0;
228}
229
230static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable)
231{
232 adap->cec_pin_is_high = true;
233 return 0;
234}
235
236static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
237{
238 return 0;
239}
240
241static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
242 u32 signal_free_time, struct cec_msg *msg)
243{
244 struct vivid_dev *dev = cec_get_drvdata(adap);
245 u8 idx = cec_msg_initiator(msg);
246
247 spin_lock(lock: &dev->cec_xfers_slock);
248 dev->xfers[idx].adap = adap;
249 memcpy(dev->xfers[idx].msg, msg->msg, CEC_MAX_MSG_SIZE);
250 dev->xfers[idx].len = msg->len;
251 dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_RETRY;
252 if (signal_free_time > CEC_SIGNAL_FREE_TIME_RETRY) {
253 if (idx == dev->last_initiator)
254 dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
255 else
256 dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
257 }
258 spin_unlock(lock: &dev->cec_xfers_slock);
259 wake_up_interruptible(&dev->kthread_waitq_cec);
260
261 return 0;
262}
263
264static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
265{
266 struct vivid_dev *dev = cec_get_drvdata(adap);
267 struct cec_msg reply;
268 u8 dest = cec_msg_destination(msg);
269 u8 disp_ctl;
270 char osd[14];
271
272 if (cec_msg_is_broadcast(msg))
273 dest = adap->log_addrs.log_addr[0];
274 cec_msg_init(msg: &reply, initiator: dest, destination: cec_msg_initiator(msg));
275
276 switch (cec_msg_opcode(msg)) {
277 case CEC_MSG_SET_OSD_STRING:
278 if (!cec_is_sink(adap))
279 return -ENOMSG;
280 cec_ops_set_osd_string(msg, disp_ctl: &disp_ctl, osd);
281 switch (disp_ctl) {
282 case CEC_OP_DISP_CTL_DEFAULT:
283 strscpy(dev->osd, osd, sizeof(dev->osd));
284 dev->osd_jiffies = jiffies;
285 break;
286 case CEC_OP_DISP_CTL_UNTIL_CLEARED:
287 strscpy(dev->osd, osd, sizeof(dev->osd));
288 dev->osd_jiffies = 0;
289 break;
290 case CEC_OP_DISP_CTL_CLEAR:
291 dev->osd[0] = 0;
292 dev->osd_jiffies = 0;
293 break;
294 default:
295 cec_msg_feature_abort(msg: &reply, abort_msg: cec_msg_opcode(msg),
296 CEC_OP_ABORT_INVALID_OP);
297 cec_transmit_msg(adap, msg: &reply, block: false);
298 break;
299 }
300 break;
301 default:
302 return -ENOMSG;
303 }
304 return 0;
305}
306
307static const struct cec_adap_ops vivid_cec_adap_ops = {
308 .adap_enable = vivid_cec_adap_enable,
309 .adap_log_addr = vivid_cec_adap_log_addr,
310 .adap_transmit = vivid_cec_adap_transmit,
311 .received = vivid_received,
312};
313
314struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
315 unsigned int idx,
316 bool is_source)
317{
318 u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
319 char name[32];
320
321 snprintf(buf: name, size: sizeof(name), fmt: "vivid-%03d-vid-%s%d",
322 dev->inst, is_source ? "out" : "cap", idx);
323 return cec_allocate_adapter(ops: &vivid_cec_adap_ops, priv: dev,
324 name, caps, CEC_MAX_LOG_ADDRS);
325}
326

source code of linux/drivers/media/test-drivers/vivid/vivid-cec.c