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 | |
18 | struct xfer_on_bus { |
19 | struct cec_adapter *adap; |
20 | u8 status; |
21 | }; |
22 | |
23 | static 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 | |
47 | static 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 | */ |
72 | static 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 | */ |
96 | int 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 | |
230 | static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable) |
231 | { |
232 | adap->cec_pin_is_high = true; |
233 | return 0; |
234 | } |
235 | |
236 | static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) |
237 | { |
238 | return 0; |
239 | } |
240 | |
241 | static 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 | |
264 | static 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 | |
307 | static 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 | |
314 | struct 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 | |