1 // SPDX-License-Identifier: GPL-2.0-only
3 * Tegra CEC implementation
5 * The original 3.10 CEC driver using a custom API:
7 * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved.
9 * Conversion to the CEC framework and to the mainline kernel:
11 * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/err.h>
17 #include <linux/errno.h>
18 #include <linux/interrupt.h>
19 #include <linux/slab.h>
21 #include <linux/clk.h>
22 #include <linux/delay.h>
25 #include <linux/of_platform.h>
26 #include <linux/platform_device.h>
27 #include <linux/clk/tegra.h>
29 #include <media/cec-notifier.h>
31 #include "tegra_cec.h"
33 #define TEGRA_CEC_NAME "tegra-cec"
36 struct cec_adapter
*adap
;
39 void __iomem
*cec_base
;
40 struct cec_notifier
*notifier
;
45 u8 rx_buf
[CEC_MAX_MSG_SIZE
];
47 u32 tx_buf
[CEC_MAX_MSG_SIZE
];
52 static inline u32
cec_read(struct tegra_cec
*cec
, u32 reg
)
54 return readl(cec
->cec_base
+ reg
);
57 static inline void cec_write(struct tegra_cec
*cec
, u32 reg
, u32 val
)
59 writel(val
, cec
->cec_base
+ reg
);
62 static void tegra_cec_error_recovery(struct tegra_cec
*cec
)
66 hw_ctrl
= cec_read(cec
, TEGRA_CEC_HW_CONTROL
);
67 cec_write(cec
, TEGRA_CEC_HW_CONTROL
, 0);
68 cec_write(cec
, TEGRA_CEC_INT_STAT
, 0xffffffff);
69 cec_write(cec
, TEGRA_CEC_HW_CONTROL
, hw_ctrl
);
72 static irqreturn_t
tegra_cec_irq_thread_handler(int irq
, void *data
)
74 struct device
*dev
= data
;
75 struct tegra_cec
*cec
= dev_get_drvdata(dev
);
78 cec_transmit_attempt_done(cec
->adap
, cec
->tx_status
);
82 struct cec_msg msg
= {};
84 msg
.len
= cec
->rx_buf_cnt
;
85 memcpy(msg
.msg
, cec
->rx_buf
, msg
.len
);
86 cec_received_msg(cec
->adap
, &msg
);
93 static irqreturn_t
tegra_cec_irq_handler(int irq
, void *data
)
95 struct device
*dev
= data
;
96 struct tegra_cec
*cec
= dev_get_drvdata(dev
);
99 status
= cec_read(cec
, TEGRA_CEC_INT_STAT
);
100 mask
= cec_read(cec
, TEGRA_CEC_INT_MASK
);
107 if (status
& TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN
) {
108 dev_err(dev
, "TX underrun, interrupt timing issue!\n");
110 tegra_cec_error_recovery(cec
);
111 cec_write(cec
, TEGRA_CEC_INT_MASK
,
112 mask
& ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY
);
115 cec
->tx_status
= CEC_TX_STATUS_ERROR
;
116 return IRQ_WAKE_THREAD
;
119 if ((status
& TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED
) ||
120 (status
& TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED
)) {
121 tegra_cec_error_recovery(cec
);
122 cec_write(cec
, TEGRA_CEC_INT_MASK
,
123 mask
& ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY
);
126 if (status
& TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED
)
127 cec
->tx_status
= CEC_TX_STATUS_LOW_DRIVE
;
129 cec
->tx_status
= CEC_TX_STATUS_ARB_LOST
;
130 return IRQ_WAKE_THREAD
;
133 if (status
& TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED
) {
134 cec_write(cec
, TEGRA_CEC_INT_STAT
,
135 TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED
);
137 if (status
& TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD
) {
138 tegra_cec_error_recovery(cec
);
141 cec
->tx_status
= CEC_TX_STATUS_NACK
;
144 cec
->tx_status
= CEC_TX_STATUS_OK
;
146 return IRQ_WAKE_THREAD
;
149 if (status
& TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD
)
150 dev_warn(dev
, "TX NAKed on the fly!\n");
152 if (status
& TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY
) {
153 if (cec
->tx_buf_cur
== cec
->tx_buf_cnt
) {
154 cec_write(cec
, TEGRA_CEC_INT_MASK
,
155 mask
& ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY
);
157 cec_write(cec
, TEGRA_CEC_TX_REGISTER
,
158 cec
->tx_buf
[cec
->tx_buf_cur
++]);
159 cec_write(cec
, TEGRA_CEC_INT_STAT
,
160 TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY
);
164 if (status
& TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED
) {
165 cec_write(cec
, TEGRA_CEC_INT_STAT
,
166 TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED
);
167 cec
->rx_done
= false;
170 if (status
& TEGRA_CEC_INT_STAT_RX_REGISTER_FULL
) {
173 cec_write(cec
, TEGRA_CEC_INT_STAT
,
174 TEGRA_CEC_INT_STAT_RX_REGISTER_FULL
);
175 v
= cec_read(cec
, TEGRA_CEC_RX_REGISTER
);
176 if (cec
->rx_buf_cnt
< CEC_MAX_MSG_SIZE
)
177 cec
->rx_buf
[cec
->rx_buf_cnt
++] = v
& 0xff;
178 if (v
& TEGRA_CEC_RX_REGISTER_EOM
) {
180 return IRQ_WAKE_THREAD
;
187 static int tegra_cec_adap_enable(struct cec_adapter
*adap
, bool enable
)
189 struct tegra_cec
*cec
= adap
->priv
;
195 cec_write(cec
, TEGRA_CEC_HW_CONTROL
, 0);
196 cec_write(cec
, TEGRA_CEC_INT_MASK
, 0);
197 cec_write(cec
, TEGRA_CEC_INT_STAT
, 0xffffffff);
198 cec_write(cec
, TEGRA_CEC_SW_CONTROL
, 0);
203 cec_write(cec
, TEGRA_CEC_INPUT_FILTER
, (1U << 31) | 0x20);
205 cec_write(cec
, TEGRA_CEC_RX_TIMING_0
,
206 (0x7a << TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT
) |
207 (0x6d << TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT
) |
208 (0x93 << TEGRA_CEC_RX_TIM0_START_BIT_MAX_DURATION_SHIFT
) |
209 (0x86 << TEGRA_CEC_RX_TIM0_START_BIT_MIN_DURATION_SHIFT
));
211 cec_write(cec
, TEGRA_CEC_RX_TIMING_1
,
212 (0x35 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_LO_TIME_SHIFT
) |
213 (0x21 << TEGRA_CEC_RX_TIM1_DATA_BIT_SAMPLE_TIME_SHIFT
) |
214 (0x56 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_DURATION_SHIFT
) |
215 (0x40 << TEGRA_CEC_RX_TIM1_DATA_BIT_MIN_DURATION_SHIFT
));
217 cec_write(cec
, TEGRA_CEC_RX_TIMING_2
,
218 (0x50 << TEGRA_CEC_RX_TIM2_END_OF_BLOCK_TIME_SHIFT
));
220 cec_write(cec
, TEGRA_CEC_TX_TIMING_0
,
221 (0x74 << TEGRA_CEC_TX_TIM0_START_BIT_LO_TIME_SHIFT
) |
222 (0x8d << TEGRA_CEC_TX_TIM0_START_BIT_DURATION_SHIFT
) |
223 (0x08 << TEGRA_CEC_TX_TIM0_BUS_XITION_TIME_SHIFT
) |
224 (0x71 << TEGRA_CEC_TX_TIM0_BUS_ERROR_LO_TIME_SHIFT
));
226 cec_write(cec
, TEGRA_CEC_TX_TIMING_1
,
227 (0x2f << TEGRA_CEC_TX_TIM1_LO_DATA_BIT_LO_TIME_SHIFT
) |
228 (0x13 << TEGRA_CEC_TX_TIM1_HI_DATA_BIT_LO_TIME_SHIFT
) |
229 (0x4b << TEGRA_CEC_TX_TIM1_DATA_BIT_DURATION_SHIFT
) |
230 (0x21 << TEGRA_CEC_TX_TIM1_ACK_NAK_BIT_SAMPLE_TIME_SHIFT
));
232 cec_write(cec
, TEGRA_CEC_TX_TIMING_2
,
233 (0x07 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_ADDITIONAL_FRAME_SHIFT
) |
234 (0x05 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT
) |
235 (0x03 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT
));
237 cec_write(cec
, TEGRA_CEC_INT_MASK
,
238 TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN
|
239 TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD
|
240 TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED
|
241 TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED
|
242 TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED
|
243 TEGRA_CEC_INT_MASK_RX_REGISTER_FULL
|
244 TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED
);
246 cec_write(cec
, TEGRA_CEC_HW_CONTROL
, TEGRA_CEC_HWCTRL_TX_RX_MODE
);
250 static int tegra_cec_adap_log_addr(struct cec_adapter
*adap
, u8 logical_addr
)
252 struct tegra_cec
*cec
= adap
->priv
;
253 u32 state
= cec_read(cec
, TEGRA_CEC_HW_CONTROL
);
255 if (logical_addr
== CEC_LOG_ADDR_INVALID
)
256 state
&= ~TEGRA_CEC_HWCTRL_RX_LADDR_MASK
;
258 state
|= TEGRA_CEC_HWCTRL_RX_LADDR((1 << logical_addr
));
260 cec_write(cec
, TEGRA_CEC_HW_CONTROL
, state
);
264 static int tegra_cec_adap_monitor_all_enable(struct cec_adapter
*adap
,
267 struct tegra_cec
*cec
= adap
->priv
;
268 u32 reg
= cec_read(cec
, TEGRA_CEC_HW_CONTROL
);
271 reg
|= TEGRA_CEC_HWCTRL_RX_SNOOP
;
273 reg
&= ~TEGRA_CEC_HWCTRL_RX_SNOOP
;
274 cec_write(cec
, TEGRA_CEC_HW_CONTROL
, reg
);
278 static int tegra_cec_adap_transmit(struct cec_adapter
*adap
, u8 attempts
,
279 u32 signal_free_time_ms
, struct cec_msg
*msg
)
281 bool retry_xfer
= signal_free_time_ms
== CEC_SIGNAL_FREE_TIME_RETRY
;
282 struct tegra_cec
*cec
= adap
->priv
;
287 if (cec_msg_is_broadcast(msg
))
288 mode
= TEGRA_CEC_TX_REG_BCAST
;
291 cec
->tx_buf_cnt
= msg
->len
;
293 for (i
= 0; i
< msg
->len
; i
++) {
294 cec
->tx_buf
[i
] = mode
| msg
->msg
[i
];
296 cec
->tx_buf
[i
] |= TEGRA_CEC_TX_REG_START_BIT
;
297 if (i
== msg
->len
- 1)
298 cec
->tx_buf
[i
] |= TEGRA_CEC_TX_REG_EOM
;
299 if (i
== 0 && retry_xfer
)
300 cec
->tx_buf
[i
] |= TEGRA_CEC_TX_REG_RETRY
;
303 mask
= cec_read(cec
, TEGRA_CEC_INT_MASK
);
304 cec_write(cec
, TEGRA_CEC_INT_MASK
,
305 mask
| TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY
);
310 static const struct cec_adap_ops tegra_cec_ops
= {
311 .adap_enable
= tegra_cec_adap_enable
,
312 .adap_log_addr
= tegra_cec_adap_log_addr
,
313 .adap_transmit
= tegra_cec_adap_transmit
,
314 .adap_monitor_all_enable
= tegra_cec_adap_monitor_all_enable
,
317 static int tegra_cec_probe(struct platform_device
*pdev
)
319 struct device
*hdmi_dev
;
320 struct tegra_cec
*cec
;
321 struct resource
*res
;
324 hdmi_dev
= cec_notifier_parse_hdmi_phandle(&pdev
->dev
);
326 if (IS_ERR(hdmi_dev
))
327 return PTR_ERR(hdmi_dev
);
329 cec
= devm_kzalloc(&pdev
->dev
, sizeof(struct tegra_cec
), GFP_KERNEL
);
334 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
338 "Unable to allocate resources for device\n");
342 if (!devm_request_mem_region(&pdev
->dev
, res
->start
, resource_size(res
),
345 "Unable to request mem region for device\n");
349 cec
->tegra_cec_irq
= platform_get_irq(pdev
, 0);
351 if (cec
->tegra_cec_irq
<= 0)
354 cec
->cec_base
= devm_ioremap(&pdev
->dev
, res
->start
,
357 if (!cec
->cec_base
) {
358 dev_err(&pdev
->dev
, "Unable to grab IOs for device\n");
362 cec
->clk
= devm_clk_get(&pdev
->dev
, "cec");
364 if (IS_ERR_OR_NULL(cec
->clk
)) {
365 dev_err(&pdev
->dev
, "Can't get clock for CEC\n");
369 clk_prepare_enable(cec
->clk
);
371 /* set context info. */
372 cec
->dev
= &pdev
->dev
;
374 platform_set_drvdata(pdev
, cec
);
376 ret
= devm_request_threaded_irq(&pdev
->dev
, cec
->tegra_cec_irq
,
377 tegra_cec_irq_handler
, tegra_cec_irq_thread_handler
,
378 0, "cec_irq", &pdev
->dev
);
382 "Unable to request interrupt for device\n");
386 cec
->adap
= cec_allocate_adapter(&tegra_cec_ops
, cec
, TEGRA_CEC_NAME
,
387 CEC_CAP_DEFAULTS
| CEC_CAP_MONITOR_ALL
|
388 CEC_CAP_CONNECTOR_INFO
,
390 if (IS_ERR(cec
->adap
)) {
392 dev_err(&pdev
->dev
, "Couldn't create cec adapter\n");
396 cec
->notifier
= cec_notifier_cec_adap_register(hdmi_dev
, NULL
,
398 if (!cec
->notifier
) {
403 ret
= cec_register_adapter(cec
->adap
, &pdev
->dev
);
405 dev_err(&pdev
->dev
, "Couldn't register device\n");
412 cec_notifier_cec_adap_unregister(cec
->notifier
, cec
->adap
);
414 cec_delete_adapter(cec
->adap
);
416 clk_disable_unprepare(cec
->clk
);
420 static int tegra_cec_remove(struct platform_device
*pdev
)
422 struct tegra_cec
*cec
= platform_get_drvdata(pdev
);
424 clk_disable_unprepare(cec
->clk
);
426 cec_notifier_cec_adap_unregister(cec
->notifier
, cec
->adap
);
427 cec_unregister_adapter(cec
->adap
);
433 static int tegra_cec_suspend(struct platform_device
*pdev
, pm_message_t state
)
435 struct tegra_cec
*cec
= platform_get_drvdata(pdev
);
437 clk_disable_unprepare(cec
->clk
);
439 dev_notice(&pdev
->dev
, "suspended\n");
443 static int tegra_cec_resume(struct platform_device
*pdev
)
445 struct tegra_cec
*cec
= platform_get_drvdata(pdev
);
447 dev_notice(&pdev
->dev
, "Resuming\n");
449 clk_prepare_enable(cec
->clk
);
455 static const struct of_device_id tegra_cec_of_match
[] = {
456 { .compatible
= "nvidia,tegra114-cec", },
457 { .compatible
= "nvidia,tegra124-cec", },
458 { .compatible
= "nvidia,tegra210-cec", },
462 static struct platform_driver tegra_cec_driver
= {
464 .name
= TEGRA_CEC_NAME
,
465 .of_match_table
= of_match_ptr(tegra_cec_of_match
),
467 .probe
= tegra_cec_probe
,
468 .remove
= tegra_cec_remove
,
471 .suspend
= tegra_cec_suspend
,
472 .resume
= tegra_cec_resume
,
476 module_platform_driver(tegra_cec_driver
);
478 MODULE_DESCRIPTION("Tegra HDMI CEC driver");
479 MODULE_AUTHOR("NVIDIA CORPORATION");
480 MODULE_AUTHOR("Cisco Systems, Inc. and/or its affiliates");
481 MODULE_LICENSE("GPL v2");