blob: 8321238b3fe7cf9f4b7d6c271fe1084c04b0b069 [file] [log] [blame]
Thomas Gleixnercaab2772019-06-03 07:44:50 +02001// SPDX-License-Identifier: GPL-2.0-only
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002/*
3 * Copyright (C) 2015 Broadcom
4 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
5 * Copyright (C) 2013 Red Hat
6 * Author: Rob Clark <robdclark@gmail.com>
Eric Anholtc8b75bc2015-03-02 13:01:12 -08007 */
8
9/**
10 * DOC: VC4 Falcon HDMI module
11 *
Eric Anholtf6c01532017-02-27 12:11:43 -080012 * The HDMI core has a state machine and a PHY. On BCM2835, most of
13 * the unit operates off of the HSM clock from CPRMAN. It also
14 * internally uses the PLLH_PIX clock for the PHY.
15 *
16 * HDMI infoframes are kept within a small packet ram, where each
17 * packet can be individually enabled for including in a frame.
18 *
19 * HDMI audio is implemented entirely within the HDMI IP block. A
20 * register in the HDMI encoder takes SPDIF frames from the DMA engine
21 * and transfers them over an internal MAI (multi-channel audio
22 * interconnect) bus to the encoder side for insertion into the video
23 * blank regions.
24 *
25 * The driver's HDMI encoder does not yet support power management.
26 * The HDMI encoder's power domain and the HSM/pixel clocks are kept
27 * continuously running, and only the HDMI logic and packet ram are
28 * powered off/on at disable/enable time.
29 *
30 * The driver does not yet support CEC control, though the HDMI
31 * encoder block has CEC support.
Eric Anholtc8b75bc2015-03-02 13:01:12 -080032 */
33
Masahiro Yamadab7e8e252017-05-18 13:29:38 +090034#include <drm/drm_atomic_helper.h>
Masahiro Yamadab7e8e252017-05-18 13:29:38 +090035#include <drm/drm_edid.h>
Daniel Vetterfcd70cd2019-01-17 22:03:34 +010036#include <drm/drm_probe_helper.h>
Thomas Zimmermannf6ebc1b2020-03-05 16:59:46 +010037#include <drm/drm_simple_kms_helper.h>
Maxime Ripardc85695a2021-05-07 17:05:13 +020038#include <drm/drm_scdc_helper.h>
Masahiro Yamadab7e8e252017-05-18 13:29:38 +090039#include <linux/clk.h>
40#include <linux/component.h>
41#include <linux/i2c.h>
42#include <linux/of_address.h>
43#include <linux/of_gpio.h>
44#include <linux/of_platform.h>
45#include <linux/pm_runtime.h>
46#include <linux/rational.h>
Maxime Ripard83239892020-09-03 10:01:48 +020047#include <linux/reset.h>
Masahiro Yamadab7e8e252017-05-18 13:29:38 +090048#include <sound/dmaengine_pcm.h>
Maxime Ripard91e99e12021-05-25 15:23:52 +020049#include <sound/hdmi-codec.h>
Masahiro Yamadab7e8e252017-05-18 13:29:38 +090050#include <sound/pcm_drm_eld.h>
51#include <sound/pcm_params.h>
52#include <sound/soc.h>
Hans Verkuil15b45112017-07-16 12:48:04 +020053#include "media/cec.h"
Eric Anholtc8b75bc2015-03-02 13:01:12 -080054#include "vc4_drv.h"
Maxime Ripardf73100c2020-09-03 10:01:11 +020055#include "vc4_hdmi.h"
Maxime Ripard311e3052020-09-03 10:01:23 +020056#include "vc4_hdmi_regs.h"
Eric Anholtc8b75bc2015-03-02 13:01:12 -080057#include "vc4_regs.h"
58
Maxime Ripard83239892020-09-03 10:01:48 +020059#define VC5_HDMI_HORZA_HFP_SHIFT 16
60#define VC5_HDMI_HORZA_HFP_MASK VC4_MASK(28, 16)
61#define VC5_HDMI_HORZA_VPOS BIT(15)
62#define VC5_HDMI_HORZA_HPOS BIT(14)
63#define VC5_HDMI_HORZA_HAP_SHIFT 0
64#define VC5_HDMI_HORZA_HAP_MASK VC4_MASK(13, 0)
65
66#define VC5_HDMI_HORZB_HBP_SHIFT 16
67#define VC5_HDMI_HORZB_HBP_MASK VC4_MASK(26, 16)
68#define VC5_HDMI_HORZB_HSP_SHIFT 0
69#define VC5_HDMI_HORZB_HSP_MASK VC4_MASK(10, 0)
70
71#define VC5_HDMI_VERTA_VSP_SHIFT 24
72#define VC5_HDMI_VERTA_VSP_MASK VC4_MASK(28, 24)
73#define VC5_HDMI_VERTA_VFP_SHIFT 16
74#define VC5_HDMI_VERTA_VFP_MASK VC4_MASK(22, 16)
75#define VC5_HDMI_VERTA_VAL_SHIFT 0
76#define VC5_HDMI_VERTA_VAL_MASK VC4_MASK(12, 0)
77
78#define VC5_HDMI_VERTB_VSPO_SHIFT 16
79#define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16)
80
Maxime Ripardc85695a2021-05-07 17:05:13 +020081#define VC5_HDMI_SCRAMBLER_CTL_ENABLE BIT(0)
82
Maxime Ripardba8c0fa2020-12-15 16:42:43 +010083#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT 8
84#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK VC4_MASK(10, 8)
85
86#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_SHIFT 0
87#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK VC4_MASK(3, 0)
88
89#define VC5_HDMI_GCP_CONFIG_GCP_ENABLE BIT(31)
90
91#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_SHIFT 8
92#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK VC4_MASK(15, 8)
93
Maxime Ripard83239892020-09-03 10:01:48 +020094# define VC4_HD_M_SW_RST BIT(2)
95# define VC4_HD_M_ENABLE BIT(0)
96
Hans Verkuil15b45112017-07-16 12:48:04 +020097#define CEC_CLOCK_FREQ 40000
Eric Anholtc8b75bc2015-03-02 13:01:12 -080098
Maxime Ripard24169a22020-12-15 16:42:42 +010099#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
100
Maxime Ripard86e3a652021-05-07 17:05:12 +0200101static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode)
102{
103 return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK;
104}
105
Eric Anholtc9be8042019-04-01 11:35:58 -0700106static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800107{
108 struct drm_info_node *node = (struct drm_info_node *)m->private;
Maxime Ripard3408cc22020-09-03 10:01:14 +0200109 struct vc4_hdmi *vc4_hdmi = node->info_ent->data;
Eric Anholt30517192019-02-20 13:03:38 -0800110 struct drm_printer p = drm_seq_file_printer(m);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800111
Maxime Ripard3408cc22020-09-03 10:01:14 +0200112 drm_print_regset32(&p, &vc4_hdmi->hdmi_regset);
113 drm_print_regset32(&p, &vc4_hdmi->hd_regset);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800114
115 return 0;
116}
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800117
Maxime Ripard9045e912020-09-03 10:01:24 +0200118static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
119{
120 HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST);
121 udelay(1);
122 HDMI_WRITE(HDMI_M_CTL, 0);
123
124 HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_ENABLE);
125
126 HDMI_WRITE(HDMI_SW_RESET_CONTROL,
127 VC4_HDMI_SW_RESET_HDMI |
128 VC4_HDMI_SW_RESET_FORMAT_DETECT);
129
130 HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0);
131}
132
Maxime Ripard83239892020-09-03 10:01:48 +0200133static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
134{
135 reset_control_reset(vc4_hdmi->reset);
136
137 HDMI_WRITE(HDMI_DVP_CTL, 0);
138
139 HDMI_WRITE(HDMI_CLOCK_STOP,
140 HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL);
141}
142
Maxime Ripard47fa9a82021-01-11 15:23:01 +0100143#ifdef CONFIG_DRM_VC4_HDMI_CEC
144static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
145{
146 u16 clk_cnt;
147 u32 value;
148
149 value = HDMI_READ(HDMI_CEC_CNTRL_1);
150 value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
151
152 /*
153 * Set the clock divider: the hsm_clock rate and this divider
154 * setting will give a 40 kHz CEC clock.
155 */
Maxime Ripard23b7eb52021-01-11 15:23:02 +0100156 clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ;
Maxime Ripard47fa9a82021-01-11 15:23:01 +0100157 value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT;
158 HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
159}
160#else
161static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
162#endif
163
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800164static enum drm_connector_status
165vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
166{
Maxime Ripard5dfbcae2020-09-03 10:01:17 +0200167 struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
Dom Cobley4d8602b2021-01-11 15:22:59 +0100168 bool connected = false;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800169
Maxime Ripard9984d662021-05-25 11:10:59 +0200170 WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
171
Maxime Ripard68002342021-05-24 15:18:52 +0200172 if (vc4_hdmi->hpd_gpio &&
173 gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
174 connected = true;
Dom Cobley4d8602b2021-01-11 15:22:59 +0100175 } else if (drm_probe_ddc(vc4_hdmi->ddc)) {
176 connected = true;
177 } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
178 connected = true;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800179 }
180
Dom Cobley4d8602b2021-01-11 15:22:59 +0100181 if (connected) {
182 if (connector->status != connector_status_connected) {
183 struct edid *edid = drm_get_edid(connector, vc4_hdmi->ddc);
Eric Anholt9d44abb2016-09-14 19:21:29 +0100184
Dom Cobley4d8602b2021-01-11 15:22:59 +0100185 if (edid) {
186 cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
187 vc4_hdmi->encoder.hdmi_monitor = drm_detect_hdmi_monitor(edid);
188 kfree(edid);
189 }
190 }
191
Maxime Ripard9984d662021-05-25 11:10:59 +0200192 pm_runtime_put(&vc4_hdmi->pdev->dev);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800193 return connector_status_connected;
Dom Cobley4d8602b2021-01-11 15:22:59 +0100194 }
195
Maxime Ripardb10db9a2020-09-03 10:01:16 +0200196 cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
Maxime Ripard9984d662021-05-25 11:10:59 +0200197 pm_runtime_put(&vc4_hdmi->pdev->dev);
Hans Verkuil15b45112017-07-16 12:48:04 +0200198 return connector_status_disconnected;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800199}
200
201static void vc4_hdmi_connector_destroy(struct drm_connector *connector)
202{
203 drm_connector_unregister(connector);
204 drm_connector_cleanup(connector);
205}
206
207static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
208{
Maxime Ripard5dfbcae2020-09-03 10:01:17 +0200209 struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
210 struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800211 int ret = 0;
212 struct edid *edid;
213
Maxime Ripard5dfbcae2020-09-03 10:01:17 +0200214 edid = drm_get_edid(connector, vc4_hdmi->ddc);
215 cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800216 if (!edid)
217 return -ENODEV;
218
219 vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
Eric Anholt21317b32016-09-29 15:34:43 -0700220
Daniel Vetterc555f022018-07-09 10:40:06 +0200221 drm_connector_update_edid_property(connector, edid);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800222 ret = drm_add_edid_modes(connector, edid);
Eric Anholt5afe0e62017-08-08 13:56:05 -0700223 kfree(edid);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800224
Maxime Ripard86e3a652021-05-07 17:05:12 +0200225 if (vc4_hdmi->disable_4kp60) {
226 struct drm_device *drm = connector->dev;
227 struct drm_display_mode *mode;
228
229 list_for_each_entry(mode, &connector->probed_modes, head) {
230 if (vc4_hdmi_mode_needs_scrambling(mode)) {
231 drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
232 drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
233 }
234 }
235 }
236
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800237 return ret;
238}
239
Dave Stevensonbccd5c52021-04-30 11:44:49 +0200240static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector,
241 struct drm_atomic_state *state)
242{
243 struct drm_connector_state *old_state =
244 drm_atomic_get_old_connector_state(state, connector);
245 struct drm_connector_state *new_state =
246 drm_atomic_get_new_connector_state(state, connector);
247 struct drm_crtc *crtc = new_state->crtc;
248
249 if (!crtc)
250 return 0;
251
Maxime Ripard76a262d2021-04-30 11:44:51 +0200252 if (old_state->colorspace != new_state->colorspace ||
253 !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) {
Dave Stevensonbccd5c52021-04-30 11:44:49 +0200254 struct drm_crtc_state *crtc_state;
255
256 crtc_state = drm_atomic_get_crtc_state(state, crtc);
257 if (IS_ERR(crtc_state))
258 return PTR_ERR(crtc_state);
259
260 crtc_state->mode_changed = true;
261 }
262
263 return 0;
264}
265
Maxime Ripard90b2df52019-06-19 12:17:53 +0200266static void vc4_hdmi_connector_reset(struct drm_connector *connector)
267{
Maxime Ripardfbe72712020-12-15 16:42:39 +0100268 struct vc4_hdmi_connector_state *old_state =
269 conn_state_to_vc4_hdmi_conn_state(connector->state);
270 struct vc4_hdmi_connector_state *new_state =
271 kzalloc(sizeof(*new_state), GFP_KERNEL);
Maxime Riparde55a0772020-12-15 16:42:38 +0100272
273 if (connector->state)
Maxime Ripardfbe72712020-12-15 16:42:39 +0100274 __drm_atomic_helper_connector_destroy_state(connector->state);
275
276 kfree(old_state);
277 __drm_atomic_helper_connector_reset(connector, &new_state->base);
278
279 if (!new_state)
280 return;
281
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100282 new_state->base.max_bpc = 8;
283 new_state->base.max_requested_bpc = 8;
Maxime Ripardfbe72712020-12-15 16:42:39 +0100284 drm_atomic_helper_connector_tv_reset(connector);
285}
286
287static struct drm_connector_state *
288vc4_hdmi_connector_duplicate_state(struct drm_connector *connector)
289{
290 struct drm_connector_state *conn_state = connector->state;
291 struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(conn_state);
292 struct vc4_hdmi_connector_state *new_state;
293
294 new_state = kzalloc(sizeof(*new_state), GFP_KERNEL);
295 if (!new_state)
296 return NULL;
297
Maxime Ripardf6237462020-12-15 16:42:40 +0100298 new_state->pixel_rate = vc4_state->pixel_rate;
Maxime Ripardfbe72712020-12-15 16:42:39 +0100299 __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
300
301 return &new_state->base;
Maxime Ripard90b2df52019-06-19 12:17:53 +0200302}
303
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800304static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800305 .detect = vc4_hdmi_connector_detect,
Eric Anholt682e62c2016-09-28 17:30:25 -0700306 .fill_modes = drm_helper_probe_single_connector_modes,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800307 .destroy = vc4_hdmi_connector_destroy,
Maxime Ripard90b2df52019-06-19 12:17:53 +0200308 .reset = vc4_hdmi_connector_reset,
Maxime Ripardfbe72712020-12-15 16:42:39 +0100309 .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800310 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
311};
312
313static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
314 .get_modes = vc4_hdmi_connector_get_modes,
Dave Stevensonbccd5c52021-04-30 11:44:49 +0200315 .atomic_check = vc4_hdmi_connector_atomic_check,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800316};
317
Maxime Ripardc98c85b2020-09-03 10:01:12 +0200318static int vc4_hdmi_connector_init(struct drm_device *dev,
Maxime Ripardb052e702020-09-03 10:01:13 +0200319 struct vc4_hdmi *vc4_hdmi)
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800320{
Maxime Ripard0532e5e2020-09-03 10:01:21 +0200321 struct drm_connector *connector = &vc4_hdmi->connector;
Maxime Ripardc98c85b2020-09-03 10:01:12 +0200322 struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
Boris Brezillondb999532018-12-06 15:24:39 +0100323 int ret;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800324
Andrzej Pietrasiewicz04a880f2020-01-02 14:22:58 +0100325 drm_connector_init_with_ddc(dev, connector,
326 &vc4_hdmi_connector_funcs,
327 DRM_MODE_CONNECTOR_HDMIA,
Maxime Ripardb052e702020-09-03 10:01:13 +0200328 vc4_hdmi->ddc);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800329 drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
330
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100331 /*
332 * Some of the properties below require access to state, like bpc.
333 * Allocate some default initial connector state with our reset helper.
334 */
335 if (connector->funcs->reset)
336 connector->funcs->reset(connector);
337
Boris Brezillondb999532018-12-06 15:24:39 +0100338 /* Create and attach TV margin props to this connector. */
339 ret = drm_mode_create_tv_margin_properties(dev);
340 if (ret)
Maxime Ripardc98c85b2020-09-03 10:01:12 +0200341 return ret;
Boris Brezillondb999532018-12-06 15:24:39 +0100342
Maxime Ripard76a262d2021-04-30 11:44:51 +0200343 ret = drm_mode_create_hdmi_colorspace_property(connector);
344 if (ret)
345 return ret;
346
347 drm_connector_attach_colorspace_property(connector);
Boris Brezillondb999532018-12-06 15:24:39 +0100348 drm_connector_attach_tv_margin_properties(connector);
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100349 drm_connector_attach_max_bpc_property(connector, 8, 12);
Boris Brezillondb999532018-12-06 15:24:39 +0100350
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800351 connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
352 DRM_CONNECTOR_POLL_DISCONNECT);
353
Mario Kleineracc1be12016-07-19 20:58:58 +0200354 connector->interlace_allowed = 1;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800355 connector->doublescan_allowed = 0;
356
Dave Stevensonbccd5c52021-04-30 11:44:49 +0200357 if (vc4_hdmi->variant->supports_hdr)
358 drm_connector_attach_hdr_output_metadata_property(connector);
359
Daniel Vettercde4c442018-07-09 10:40:07 +0200360 drm_connector_attach_encoder(connector, encoder);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800361
Maxime Ripardc98c85b2020-09-03 10:01:12 +0200362 return 0;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800363}
364
Eric Anholt21317b32016-09-29 15:34:43 -0700365static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
Maxime Riparde2f9b2e2020-12-03 08:46:24 +0100366 enum hdmi_infoframe_type type,
367 bool poll)
Eric Anholt21317b32016-09-29 15:34:43 -0700368{
Maxime Ripard5dfbcae2020-09-03 10:01:17 +0200369 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Eric Anholt21317b32016-09-29 15:34:43 -0700370 u32 packet_id = type - 0x80;
371
Maxime Ripard311e3052020-09-03 10:01:23 +0200372 HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
373 HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
Eric Anholt21317b32016-09-29 15:34:43 -0700374
Maxime Riparde2f9b2e2020-12-03 08:46:24 +0100375 if (!poll)
376 return 0;
377
Maxime Ripard311e3052020-09-03 10:01:23 +0200378 return wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) &
Eric Anholt21317b32016-09-29 15:34:43 -0700379 BIT(packet_id)), 100);
380}
381
382static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
383 union hdmi_infoframe *frame)
384{
Maxime Ripard5dfbcae2020-09-03 10:01:17 +0200385 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Eric Anholt21317b32016-09-29 15:34:43 -0700386 u32 packet_id = frame->any.type - 0x80;
Maxime Ripard311e3052020-09-03 10:01:23 +0200387 const struct vc4_hdmi_register *ram_packet_start =
388 &vc4_hdmi->variant->registers[HDMI_RAM_PACKET_START];
389 u32 packet_reg = ram_packet_start->offset + VC4_HDMI_PACKET_STRIDE * packet_id;
390 void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi,
391 ram_packet_start->reg);
Eric Anholt21317b32016-09-29 15:34:43 -0700392 uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
393 ssize_t len, i;
394 int ret;
395
Maxime Ripard311e3052020-09-03 10:01:23 +0200396 WARN_ONCE(!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
Eric Anholt21317b32016-09-29 15:34:43 -0700397 VC4_HDMI_RAM_PACKET_ENABLE),
398 "Packet RAM has to be on to store the packet.");
399
400 len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
401 if (len < 0)
402 return;
403
Maxime Riparde2f9b2e2020-12-03 08:46:24 +0100404 ret = vc4_hdmi_stop_packet(encoder, frame->any.type, true);
Eric Anholt21317b32016-09-29 15:34:43 -0700405 if (ret) {
406 DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
407 return;
408 }
409
410 for (i = 0; i < len; i += 7) {
Maxime Ripard311e3052020-09-03 10:01:23 +0200411 writel(buffer[i + 0] << 0 |
412 buffer[i + 1] << 8 |
413 buffer[i + 2] << 16,
414 base + packet_reg);
Eric Anholt21317b32016-09-29 15:34:43 -0700415 packet_reg += 4;
416
Maxime Ripard311e3052020-09-03 10:01:23 +0200417 writel(buffer[i + 3] << 0 |
418 buffer[i + 4] << 8 |
419 buffer[i + 5] << 16 |
420 buffer[i + 6] << 24,
421 base + packet_reg);
Eric Anholt21317b32016-09-29 15:34:43 -0700422 packet_reg += 4;
423 }
424
Maxime Ripard311e3052020-09-03 10:01:23 +0200425 HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
426 HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
427 ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) &
Eric Anholt21317b32016-09-29 15:34:43 -0700428 BIT(packet_id)), 100);
429 if (ret)
430 DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
431}
432
433static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
434{
Maxime Ripard5dfbcae2020-09-03 10:01:17 +0200435 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Eric Anholt21317b32016-09-29 15:34:43 -0700436 struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
Maxime Ripard0532e5e2020-09-03 10:01:21 +0200437 struct drm_connector *connector = &vc4_hdmi->connector;
Maxime Ripardc98c85b2020-09-03 10:01:12 +0200438 struct drm_connector_state *cstate = connector->state;
Maxime Ripard27da3702021-07-07 16:19:30 +0200439 struct drm_crtc *crtc = cstate->crtc;
Eric Anholt21317b32016-09-29 15:34:43 -0700440 const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
441 union hdmi_infoframe frame;
442 int ret;
443
Ville Syrjälä13d0add2019-01-08 19:28:25 +0200444 ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
Maxime Ripardc98c85b2020-09-03 10:01:12 +0200445 connector, mode);
Eric Anholt21317b32016-09-29 15:34:43 -0700446 if (ret < 0) {
447 DRM_ERROR("couldn't fill AVI infoframe\n");
448 return;
449 }
450
Ville Syrjälä13d0add2019-01-08 19:28:25 +0200451 drm_hdmi_avi_infoframe_quant_range(&frame.avi,
Maxime Ripardc98c85b2020-09-03 10:01:12 +0200452 connector, mode,
Ville Syrjäläa2ce26f2017-01-11 14:57:23 +0200453 vc4_encoder->limited_rgb_range ?
454 HDMI_QUANTIZATION_RANGE_LIMITED :
Ville Syrjälä1581b2d2019-01-08 19:28:28 +0200455 HDMI_QUANTIZATION_RANGE_FULL);
Maxime Ripard76a262d2021-04-30 11:44:51 +0200456 drm_hdmi_avi_infoframe_colorspace(&frame.avi, cstate);
Ville Syrjäläcb876372019-10-08 19:48:14 +0300457 drm_hdmi_avi_infoframe_bars(&frame.avi, cstate);
Boris Brezillondb999532018-12-06 15:24:39 +0100458
Eric Anholt21317b32016-09-29 15:34:43 -0700459 vc4_hdmi_write_infoframe(encoder, &frame);
460}
461
462static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
463{
464 union hdmi_infoframe frame;
465 int ret;
466
467 ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
468 if (ret < 0) {
469 DRM_ERROR("couldn't fill SPD infoframe\n");
470 return;
471 }
472
473 frame.spd.sdi = HDMI_SPD_SDI_PC;
474
475 vc4_hdmi_write_infoframe(encoder, &frame);
476}
477
Eric Anholtbb7d7852017-02-27 12:28:02 -0800478static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder)
479{
Maxime Ripard5dfbcae2020-09-03 10:01:17 +0200480 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Maxime Ripard91e99e12021-05-25 15:23:52 +0200481 struct hdmi_audio_infoframe *audio = &vc4_hdmi->audio.infoframe;
Eric Anholtbb7d7852017-02-27 12:28:02 -0800482 union hdmi_infoframe frame;
Eric Anholtbb7d7852017-02-27 12:28:02 -0800483
Maxime Ripard91e99e12021-05-25 15:23:52 +0200484 memcpy(&frame.audio, audio, sizeof(*audio));
Eric Anholtbb7d7852017-02-27 12:28:02 -0800485 vc4_hdmi_write_infoframe(encoder, &frame);
486}
487
Dave Stevensonbccd5c52021-04-30 11:44:49 +0200488static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder)
489{
490 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
491 struct drm_connector *connector = &vc4_hdmi->connector;
492 struct drm_connector_state *conn_state = connector->state;
493 union hdmi_infoframe frame;
494
495 if (!vc4_hdmi->variant->supports_hdr)
496 return;
497
498 if (!conn_state->hdr_output_metadata)
499 return;
500
501 if (drm_hdmi_infoframe_set_hdr_metadata(&frame.drm, conn_state))
502 return;
503
504 vc4_hdmi_write_infoframe(encoder, &frame);
505}
506
Eric Anholt21317b32016-09-29 15:34:43 -0700507static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
508{
Dave Stevenson6ac1c752020-09-03 10:01:38 +0200509 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
510
Eric Anholt21317b32016-09-29 15:34:43 -0700511 vc4_hdmi_set_avi_infoframe(encoder);
512 vc4_hdmi_set_spd_infoframe(encoder);
Dave Stevenson6ac1c752020-09-03 10:01:38 +0200513 /*
514 * If audio was streaming, then we need to reenabled the audio
515 * infoframe here during encoder_enable.
516 */
517 if (vc4_hdmi->audio.streaming)
518 vc4_hdmi_set_audio_infoframe(encoder);
Dave Stevensonbccd5c52021-04-30 11:44:49 +0200519
520 vc4_hdmi_set_hdr_infoframe(encoder);
Eric Anholt21317b32016-09-29 15:34:43 -0700521}
522
Maxime Ripardc85695a2021-05-07 17:05:13 +0200523static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
524 struct drm_display_mode *mode)
525{
526 struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
527 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
528 struct drm_display_info *display = &vc4_hdmi->connector.display_info;
529
530 if (!vc4_encoder->hdmi_monitor)
531 return false;
532
533 if (!display->hdmi.scdc.supported ||
534 !display->hdmi.scdc.scrambling.supported)
535 return false;
536
537 return true;
538}
539
Maxime Ripard257d36d2021-05-07 17:05:14 +0200540#define SCRAMBLING_POLLING_DELAY_MS 1000
541
Maxime Ripardc85695a2021-05-07 17:05:13 +0200542static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
543{
Maxime Ripardc85695a2021-05-07 17:05:13 +0200544 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Maxime Ripard27da3702021-07-07 16:19:30 +0200545 struct drm_connector *connector = &vc4_hdmi->connector;
546 struct drm_connector_state *cstate = connector->state;
547 struct drm_crtc *crtc = cstate->crtc;
548 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
Maxime Ripardc85695a2021-05-07 17:05:13 +0200549
550 if (!vc4_hdmi_supports_scrambling(encoder, mode))
551 return;
552
553 if (!vc4_hdmi_mode_needs_scrambling(mode))
554 return;
555
556 drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
557 drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
558
559 HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
560 VC5_HDMI_SCRAMBLER_CTL_ENABLE);
Maxime Ripard257d36d2021-05-07 17:05:14 +0200561
562 queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
563 msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
Maxime Ripardc85695a2021-05-07 17:05:13 +0200564}
565
566static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
567{
568 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Maxime Ripard27da3702021-07-07 16:19:30 +0200569 struct drm_connector *connector = &vc4_hdmi->connector;
570 struct drm_connector_state *cstate = connector->state;
Maxime Ripardc85695a2021-05-07 17:05:13 +0200571
572 /*
Maxime Ripard27da3702021-07-07 16:19:30 +0200573 * At boot, connector->state will be NULL. Since we don't know the
Maxime Ripardc85695a2021-05-07 17:05:13 +0200574 * state of the scrambler and in order to avoid any
575 * inconsistency, let's disable it all the time.
576 */
Maxime Ripard27da3702021-07-07 16:19:30 +0200577 if (cstate && !vc4_hdmi_supports_scrambling(encoder, &cstate->crtc->mode))
Maxime Ripardc85695a2021-05-07 17:05:13 +0200578 return;
579
Maxime Ripard27da3702021-07-07 16:19:30 +0200580 if (cstate && !vc4_hdmi_mode_needs_scrambling(&cstate->crtc->mode))
Maxime Ripardc85695a2021-05-07 17:05:13 +0200581 return;
582
Maxime Ripard257d36d2021-05-07 17:05:14 +0200583 if (delayed_work_pending(&vc4_hdmi->scrambling_work))
584 cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
585
Maxime Ripardc85695a2021-05-07 17:05:13 +0200586 HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
587 ~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
588
589 drm_scdc_set_scrambling(vc4_hdmi->ddc, false);
590 drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
591}
592
Maxime Ripard257d36d2021-05-07 17:05:14 +0200593static void vc4_hdmi_scrambling_wq(struct work_struct *work)
594{
595 struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
596 struct vc4_hdmi,
597 scrambling_work);
598
599 if (drm_scdc_get_scrambling_status(vc4_hdmi->ddc))
600 return;
601
602 drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
603 drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
604
605 queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
606 msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800607}
608
Maxime Ripard8d914742020-12-15 16:42:36 +0100609static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
610 struct drm_atomic_state *state)
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800611{
Maxime Ripard09c43812020-09-03 10:01:44 +0200612 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
613
614 HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
Maxime Ripard81d83012020-09-03 10:01:46 +0200615
Tim Gover0b066a62021-06-28 15:05:33 +0200616 HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB);
617
618 mdelay(1);
Maxime Ripard81d83012020-09-03 10:01:46 +0200619
620 HDMI_WRITE(HDMI_VID_CTL,
Tim Gover0b066a62021-06-28 15:05:33 +0200621 HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
Maxime Ripardc85695a2021-05-07 17:05:13 +0200622 vc4_hdmi_disable_scrambling(encoder);
Maxime Ripard09c43812020-09-03 10:01:44 +0200623}
624
Maxime Ripard8d914742020-12-15 16:42:36 +0100625static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
626 struct drm_atomic_state *state)
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800627{
Maxime Ripard5dfbcae2020-09-03 10:01:17 +0200628 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Boris Brezillon4f6e3d62017-04-11 18:39:25 +0200629 int ret;
630
Tim Gover0b066a62021-06-28 15:05:33 +0200631 HDMI_WRITE(HDMI_VID_CTL,
632 HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
633
Maxime Ripardc457b8a2020-09-03 10:01:25 +0200634 if (vc4_hdmi->variant->phy_disable)
635 vc4_hdmi->variant->phy_disable(vc4_hdmi);
Boris Brezillon4f6e3d62017-04-11 18:39:25 +0200636
Hoegeun Kwon37387422020-09-03 10:01:47 +0200637 clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
Maxime Ripard3408cc22020-09-03 10:01:14 +0200638 clk_disable_unprepare(vc4_hdmi->pixel_clock);
Boris Brezillon4f6e3d62017-04-11 18:39:25 +0200639
Maxime Ripard3408cc22020-09-03 10:01:14 +0200640 ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
Boris Brezillon4f6e3d62017-04-11 18:39:25 +0200641 if (ret < 0)
642 DRM_ERROR("Failed to release power domain: %d\n", ret);
643}
644
Maxime Ripard09c43812020-09-03 10:01:44 +0200645static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
Boris Brezillon4f6e3d62017-04-11 18:39:25 +0200646{
Maxime Ripard09c43812020-09-03 10:01:44 +0200647}
648
Maxime Ripard89f31a22020-09-03 10:01:27 +0200649static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
650{
651 u32 csc_ctl;
652
653 csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
654 VC4_HD_CSC_CTL_ORDER);
655
656 if (enable) {
657 /* CEA VICs other than #1 requre limited range RGB
658 * output unless overridden by an AVI infoframe.
659 * Apply a colorspace conversion to squash 0-255 down
660 * to 16-235. The matrix here is:
661 *
662 * [ 0 0 0.8594 16]
663 * [ 0 0.8594 0 16]
664 * [ 0.8594 0 0 16]
665 * [ 0 0 0 1]
666 */
667 csc_ctl |= VC4_HD_CSC_CTL_ENABLE;
668 csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC;
669 csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
670 VC4_HD_CSC_CTL_MODE);
671
672 HDMI_WRITE(HDMI_CSC_12_11, (0x000 << 16) | 0x000);
673 HDMI_WRITE(HDMI_CSC_14_13, (0x100 << 16) | 0x6e0);
674 HDMI_WRITE(HDMI_CSC_22_21, (0x6e0 << 16) | 0x000);
675 HDMI_WRITE(HDMI_CSC_24_23, (0x100 << 16) | 0x000);
676 HDMI_WRITE(HDMI_CSC_32_31, (0x000 << 16) | 0x6e0);
677 HDMI_WRITE(HDMI_CSC_34_33, (0x100 << 16) | 0x000);
678 }
679
680 /* The RGB order applies even when CSC is disabled. */
681 HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
682}
683
Maxime Ripard83239892020-09-03 10:01:48 +0200684static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
685{
686 u32 csc_ctl;
687
688 csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */
689
690 if (enable) {
691 /* CEA VICs other than #1 requre limited range RGB
692 * output unless overridden by an AVI infoframe.
693 * Apply a colorspace conversion to squash 0-255 down
694 * to 16-235. The matrix here is:
695 *
696 * [ 0.8594 0 0 16]
697 * [ 0 0.8594 0 16]
698 * [ 0 0 0.8594 16]
699 * [ 0 0 0 1]
700 * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
701 */
702 HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80);
703 HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000);
704 HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000);
705 HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000);
706 HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000);
707 HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80);
708 } else {
709 /* Still use the matrix for full range, but make it unity.
710 * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
711 */
712 HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000);
713 HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000);
714 HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000);
715 HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000);
716 HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000);
717 HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000);
718 }
719
720 HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
721}
722
Maxime Ripard904f6682020-09-03 10:01:28 +0200723static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100724 struct drm_connector_state *state,
Maxime Ripard904f6682020-09-03 10:01:28 +0200725 struct drm_display_mode *mode)
Boris Brezillon4f6e3d62017-04-11 18:39:25 +0200726{
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800727 bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
728 bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
Eric Anholt682e62c2016-09-28 17:30:25 -0700729 bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
Eric Anholtdfccd932016-09-29 15:34:44 -0700730 u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
Eric Anholt682e62c2016-09-28 17:30:25 -0700731 u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800732 VC4_HDMI_VERTA_VSP) |
Eric Anholt682e62c2016-09-28 17:30:25 -0700733 VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800734 VC4_HDMI_VERTA_VFP) |
Eric Anholt682e62c2016-09-28 17:30:25 -0700735 VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL));
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800736 u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
Eric Anholt682e62c2016-09-28 17:30:25 -0700737 VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800738 VC4_HDMI_VERTB_VBP));
Eric Anholt682e62c2016-09-28 17:30:25 -0700739 u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
740 VC4_SET_FIELD(mode->crtc_vtotal -
741 mode->crtc_vsync_end -
742 interlaced,
743 VC4_HDMI_VERTB_VBP));
Boris Brezillon4f6e3d62017-04-11 18:39:25 +0200744
Maxime Ripard904f6682020-09-03 10:01:28 +0200745 HDMI_WRITE(HDMI_HORZA,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800746 (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
747 (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) |
Eric Anholtdfccd932016-09-29 15:34:44 -0700748 VC4_SET_FIELD(mode->hdisplay * pixel_rep,
749 VC4_HDMI_HORZA_HAP));
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800750
Maxime Ripard904f6682020-09-03 10:01:28 +0200751 HDMI_WRITE(HDMI_HORZB,
Eric Anholtdfccd932016-09-29 15:34:44 -0700752 VC4_SET_FIELD((mode->htotal -
753 mode->hsync_end) * pixel_rep,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800754 VC4_HDMI_HORZB_HBP) |
Eric Anholtdfccd932016-09-29 15:34:44 -0700755 VC4_SET_FIELD((mode->hsync_end -
756 mode->hsync_start) * pixel_rep,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800757 VC4_HDMI_HORZB_HSP) |
Eric Anholtdfccd932016-09-29 15:34:44 -0700758 VC4_SET_FIELD((mode->hsync_start -
759 mode->hdisplay) * pixel_rep,
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800760 VC4_HDMI_HORZB_HFP));
761
Maxime Ripard904f6682020-09-03 10:01:28 +0200762 HDMI_WRITE(HDMI_VERTA0, verta);
763 HDMI_WRITE(HDMI_VERTA1, verta);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800764
Maxime Ripard904f6682020-09-03 10:01:28 +0200765 HDMI_WRITE(HDMI_VERTB0, vertb_even);
766 HDMI_WRITE(HDMI_VERTB1, vertb);
Maxime Ripard904f6682020-09-03 10:01:28 +0200767}
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100768
Maxime Ripard83239892020-09-03 10:01:48 +0200769static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100770 struct drm_connector_state *state,
Maxime Ripard83239892020-09-03 10:01:48 +0200771 struct drm_display_mode *mode)
772{
773 bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
774 bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
775 bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
776 u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
777 u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
778 VC5_HDMI_VERTA_VSP) |
779 VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
780 VC5_HDMI_VERTA_VFP) |
781 VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL));
782 u32 vertb = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
783 VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
784 VC4_HDMI_VERTB_VBP));
785 u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
786 VC4_SET_FIELD(mode->crtc_vtotal -
787 mode->crtc_vsync_end -
788 interlaced,
789 VC4_HDMI_VERTB_VBP));
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100790 unsigned char gcp;
791 bool gcp_en;
792 u32 reg;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800793
Maxime Ripard83239892020-09-03 10:01:48 +0200794 HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
795 HDMI_WRITE(HDMI_HORZA,
796 (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) |
797 (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) |
798 VC4_SET_FIELD(mode->hdisplay * pixel_rep,
799 VC5_HDMI_HORZA_HAP) |
800 VC4_SET_FIELD((mode->hsync_start -
801 mode->hdisplay) * pixel_rep,
802 VC5_HDMI_HORZA_HFP));
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800803
Maxime Ripard83239892020-09-03 10:01:48 +0200804 HDMI_WRITE(HDMI_HORZB,
805 VC4_SET_FIELD((mode->htotal -
806 mode->hsync_end) * pixel_rep,
807 VC5_HDMI_HORZB_HBP) |
808 VC4_SET_FIELD((mode->hsync_end -
809 mode->hsync_start) * pixel_rep,
810 VC5_HDMI_HORZB_HSP));
Eric Anholt6e1cbba2016-09-16 10:59:45 +0100811
Maxime Ripard83239892020-09-03 10:01:48 +0200812 HDMI_WRITE(HDMI_VERTA0, verta);
813 HDMI_WRITE(HDMI_VERTA1, verta);
Eric Anholt6e1cbba2016-09-16 10:59:45 +0100814
Maxime Ripard83239892020-09-03 10:01:48 +0200815 HDMI_WRITE(HDMI_VERTB0, vertb_even);
816 HDMI_WRITE(HDMI_VERTB1, vertb);
Eric Anholt6e1cbba2016-09-16 10:59:45 +0100817
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100818 switch (state->max_bpc) {
819 case 12:
820 gcp = 6;
821 gcp_en = true;
822 break;
823 case 10:
824 gcp = 5;
825 gcp_en = true;
826 break;
827 case 8:
828 default:
829 gcp = 4;
830 gcp_en = false;
831 break;
832 }
833
834 reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1);
835 reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK |
836 VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK);
837 reg |= VC4_SET_FIELD(2, VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE) |
838 VC4_SET_FIELD(gcp, VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH);
839 HDMI_WRITE(HDMI_DEEP_COLOR_CONFIG_1, reg);
840
841 reg = HDMI_READ(HDMI_GCP_WORD_1);
842 reg &= ~VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK;
843 reg |= VC4_SET_FIELD(gcp, VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1);
844 HDMI_WRITE(HDMI_GCP_WORD_1, reg);
845
846 reg = HDMI_READ(HDMI_GCP_CONFIG);
847 reg &= ~VC5_HDMI_GCP_CONFIG_GCP_ENABLE;
848 reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0;
849 HDMI_WRITE(HDMI_GCP_CONFIG, reg);
850
Maxime Ripard83239892020-09-03 10:01:48 +0200851 HDMI_WRITE(HDMI_CLOCK_STOP, 0);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800852}
853
Maxime Ripard691456f2020-09-03 10:01:43 +0200854static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
Eric Anholt32e823c2017-09-20 15:59:34 -0700855{
Maxime Ripard691456f2020-09-03 10:01:43 +0200856 u32 drift;
857 int ret;
858
859 drift = HDMI_READ(HDMI_FIFO_CTL);
860 drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
861
862 HDMI_WRITE(HDMI_FIFO_CTL,
863 drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
864 HDMI_WRITE(HDMI_FIFO_CTL,
865 drift | VC4_HDMI_FIFO_CTL_RECENTER);
866 usleep_range(1000, 1100);
867 HDMI_WRITE(HDMI_FIFO_CTL,
868 drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
869 HDMI_WRITE(HDMI_FIFO_CTL,
870 drift | VC4_HDMI_FIFO_CTL_RECENTER);
871
872 ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) &
873 VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1);
874 WARN_ONCE(ret, "Timeout waiting for "
875 "VC4_HDMI_FIFO_CTL_RECENTER_DONE");
876}
877
Maxime Ripardf6237462020-12-15 16:42:40 +0100878static struct drm_connector_state *
879vc4_hdmi_encoder_get_connector_state(struct drm_encoder *encoder,
880 struct drm_atomic_state *state)
881{
882 struct drm_connector_state *conn_state;
883 struct drm_connector *connector;
884 unsigned int i;
885
886 for_each_new_connector_in_state(state, connector, conn_state, i) {
887 if (conn_state->best_encoder == encoder)
888 return conn_state;
889 }
890
891 return NULL;
892}
893
Maxime Ripard8d914742020-12-15 16:42:36 +0100894static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
895 struct drm_atomic_state *state)
Maxime Ripard904f6682020-09-03 10:01:28 +0200896{
Maxime Ripardf6237462020-12-15 16:42:40 +0100897 struct drm_connector_state *conn_state =
898 vc4_hdmi_encoder_get_connector_state(encoder, state);
899 struct vc4_hdmi_connector_state *vc4_conn_state =
900 conn_state_to_vc4_hdmi_conn_state(conn_state);
Maxime Ripard27da3702021-07-07 16:19:30 +0200901 struct drm_crtc_state *crtc_state =
902 drm_atomic_get_new_crtc_state(state, conn_state->crtc);
903 struct drm_display_mode *mode = &crtc_state->adjusted_mode;
Maxime Ripard904f6682020-09-03 10:01:28 +0200904 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Maxime Ripard7d9061e2021-05-07 17:05:11 +0200905 unsigned long bvb_rate, pixel_rate, hsm_rate;
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800906 int ret;
907
Zou Wei5e4322a2021-05-24 15:20:54 +0800908 ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800909 if (ret < 0) {
910 DRM_ERROR("Failed to retain power domain: %d\n", ret);
911 return;
912 }
913
Maxime Ripardf6237462020-12-15 16:42:40 +0100914 pixel_rate = vc4_conn_state->pixel_rate;
Maxime Ripardcd4cb492020-09-03 10:01:35 +0200915 ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800916 if (ret) {
917 DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
918 return;
919 }
920
Maxime Ripard3408cc22020-09-03 10:01:14 +0200921 ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800922 if (ret) {
923 DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
924 return;
925 }
926
Nicolas Saenz Julienneb1e73962020-03-26 13:20:01 +0100927 /*
928 * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
929 * be faster than pixel clock, infinitesimally faster, tested in
930 * simulation. Otherwise, exact value is unimportant for HDMI
931 * operation." This conflicts with bcm2835's vc4 documentation, which
932 * states HSM's clock has to be at least 108% of the pixel clock.
933 *
934 * Real life tests reveal that vc4's firmware statement holds up, and
935 * users are able to use pixel clocks closer to HSM's, namely for
936 * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
937 * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
938 * 162MHz.
939 *
940 * Additionally, the AXI clock needs to be at least 25% of
941 * pixel clock, but HSM ends up being the limiting factor.
Eric Anholt32e823c2017-09-20 15:59:34 -0700942 */
Maxime Ripardcd4cb492020-09-03 10:01:35 +0200943 hsm_rate = max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
Maxime Ripardd5d5ce82020-09-03 10:01:36 +0200944 ret = clk_set_min_rate(vc4_hdmi->hsm_clock, hsm_rate);
Maxime Ripardcd4cb492020-09-03 10:01:35 +0200945 if (ret) {
946 DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
947 return;
948 }
949
Maxime Ripard47fa9a82021-01-11 15:23:01 +0100950 vc4_hdmi_cec_update_clk_div(vc4_hdmi);
951
Maxime Ripard7d9061e2021-05-07 17:05:11 +0200952 if (pixel_rate > 297000000)
953 bvb_rate = 300000000;
954 else if (pixel_rate > 148500000)
955 bvb_rate = 150000000;
956 else
957 bvb_rate = 75000000;
958
959 ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, bvb_rate);
Hoegeun Kwon37387422020-09-03 10:01:47 +0200960 if (ret) {
961 DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
Hoegeun Kwon37387422020-09-03 10:01:47 +0200962 clk_disable_unprepare(vc4_hdmi->pixel_clock);
963 return;
964 }
965
966 ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
967 if (ret) {
968 DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
Hoegeun Kwon37387422020-09-03 10:01:47 +0200969 clk_disable_unprepare(vc4_hdmi->pixel_clock);
970 return;
971 }
972
Maxime Ripardc457b8a2020-09-03 10:01:25 +0200973 if (vc4_hdmi->variant->phy_init)
Maxime Ripardd2a7dd02020-12-15 16:42:41 +0100974 vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800975
Maxime Ripard311e3052020-09-03 10:01:23 +0200976 HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
977 HDMI_READ(HDMI_SCHEDULER_CONTROL) |
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800978 VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT |
979 VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);
980
Maxime Ripard904f6682020-09-03 10:01:28 +0200981 if (vc4_hdmi->variant->set_timings)
Maxime Ripardba8c0fa2020-12-15 16:42:43 +0100982 vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
Maxime Ripard09c43812020-09-03 10:01:44 +0200983}
984
Maxime Ripard8d914742020-12-15 16:42:36 +0100985static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
986 struct drm_atomic_state *state)
Maxime Ripard09c43812020-09-03 10:01:44 +0200987{
Maxime Ripard27da3702021-07-07 16:19:30 +0200988 struct drm_connector_state *conn_state =
989 vc4_hdmi_encoder_get_connector_state(encoder, state);
990 struct drm_crtc_state *crtc_state =
991 drm_atomic_get_new_crtc_state(state, conn_state->crtc);
992 struct drm_display_mode *mode = &crtc_state->adjusted_mode;
Maxime Ripard09c43812020-09-03 10:01:44 +0200993 struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
994 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Eric Anholtc8b75bc2015-03-02 13:01:12 -0800995
996 if (vc4_encoder->hdmi_monitor &&
Maxime Ripard89f31a22020-09-03 10:01:27 +0200997 drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
998 if (vc4_hdmi->variant->csc_setup)
999 vc4_hdmi->variant->csc_setup(vc4_hdmi, true);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001000
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001001 vc4_encoder->limited_rgb_range = true;
1002 } else {
Maxime Ripard89f31a22020-09-03 10:01:27 +02001003 if (vc4_hdmi->variant->csc_setup)
1004 vc4_hdmi->variant->csc_setup(vc4_hdmi, false);
1005
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001006 vc4_encoder->limited_rgb_range = false;
1007 }
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001008
Maxime Ripard311e3052020-09-03 10:01:23 +02001009 HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
Maxime Ripard09c43812020-09-03 10:01:44 +02001010}
1011
Maxime Ripard8d914742020-12-15 16:42:36 +01001012static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
1013 struct drm_atomic_state *state)
Maxime Ripard09c43812020-09-03 10:01:44 +02001014{
Maxime Ripard27da3702021-07-07 16:19:30 +02001015 struct drm_connector_state *conn_state =
1016 vc4_hdmi_encoder_get_connector_state(encoder, state);
1017 struct drm_crtc_state *crtc_state =
1018 drm_atomic_get_new_crtc_state(state, conn_state->crtc);
1019 struct drm_display_mode *mode = &crtc_state->adjusted_mode;
Maxime Ripard09c43812020-09-03 10:01:44 +02001020 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
1021 struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
Maxime Ripard8b3f90e2020-09-03 10:01:45 +02001022 bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
1023 bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
Maxime Ripard09c43812020-09-03 10:01:44 +02001024 int ret;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001025
Maxime Ripard311e3052020-09-03 10:01:23 +02001026 HDMI_WRITE(HDMI_VID_CTL,
Maxime Ripard311e3052020-09-03 10:01:23 +02001027 VC4_HD_VID_CTL_ENABLE |
Tim Gover0b066a62021-06-28 15:05:33 +02001028 VC4_HD_VID_CTL_CLRRGB |
Maxime Ripard311e3052020-09-03 10:01:23 +02001029 VC4_HD_VID_CTL_UNDERFLOW_ENABLE |
Maxime Ripard8b3f90e2020-09-03 10:01:45 +02001030 VC4_HD_VID_CTL_FRAME_COUNTER_RESET |
1031 (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
1032 (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001033
Maxime Ripard81d83012020-09-03 10:01:46 +02001034 HDMI_WRITE(HDMI_VID_CTL,
1035 HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_BLANKPIX);
1036
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001037 if (vc4_encoder->hdmi_monitor) {
Maxime Ripard311e3052020-09-03 10:01:23 +02001038 HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
1039 HDMI_READ(HDMI_SCHEDULER_CONTROL) |
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001040 VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
1041
Maxime Ripard311e3052020-09-03 10:01:23 +02001042 ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001043 VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
1044 WARN_ONCE(ret, "Timeout waiting for "
1045 "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
1046 } else {
Maxime Ripard311e3052020-09-03 10:01:23 +02001047 HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
1048 HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001049 ~(VC4_HDMI_RAM_PACKET_ENABLE));
Maxime Ripard311e3052020-09-03 10:01:23 +02001050 HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
1051 HDMI_READ(HDMI_SCHEDULER_CONTROL) &
Eric Anholt851479a2016-02-12 14:15:14 -08001052 ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
1053
Maxime Ripard311e3052020-09-03 10:01:23 +02001054 ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
Eric Anholt851479a2016-02-12 14:15:14 -08001055 VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
1056 WARN_ONCE(ret, "Timeout waiting for "
1057 "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
1058 }
1059
1060 if (vc4_encoder->hdmi_monitor) {
Maxime Ripard311e3052020-09-03 10:01:23 +02001061 WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001062 VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE));
Maxime Ripard311e3052020-09-03 10:01:23 +02001063 HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
1064 HDMI_READ(HDMI_SCHEDULER_CONTROL) |
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001065 VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
1066
Maxime Ripard311e3052020-09-03 10:01:23 +02001067 HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001068 VC4_HDMI_RAM_PACKET_ENABLE);
1069
Eric Anholt0b06e0a2016-02-29 17:53:01 -08001070 vc4_hdmi_set_infoframes(encoder);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001071 }
Maxime Ripard691456f2020-09-03 10:01:43 +02001072
1073 vc4_hdmi_recenter_fifo(vc4_hdmi);
Maxime Ripardc85695a2021-05-07 17:05:13 +02001074 vc4_hdmi_enable_scrambling(encoder);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001075}
1076
Maxime Ripard09c43812020-09-03 10:01:44 +02001077static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
1078{
1079}
1080
Maxime Ripard9fa1d7e2020-10-29 14:40:17 +01001081#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
1082#define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL
1083
Maxime Ripard63495f6b2020-10-29 13:25:21 +01001084static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
1085 struct drm_crtc_state *crtc_state,
1086 struct drm_connector_state *conn_state)
1087{
Maxime Ripardf6237462020-12-15 16:42:40 +01001088 struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(conn_state);
Maxime Ripard63495f6b2020-10-29 13:25:21 +01001089 struct drm_display_mode *mode = &crtc_state->adjusted_mode;
1090 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
1091 unsigned long long pixel_rate = mode->clock * 1000;
Maxime Ripard9fa1d7e2020-10-29 14:40:17 +01001092 unsigned long long tmds_rate;
Maxime Ripard63495f6b2020-10-29 13:25:21 +01001093
Maxime Ripard57fb32e2020-10-29 13:25:22 +01001094 if (vc4_hdmi->variant->unsupported_odd_h_timings &&
1095 ((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
1096 (mode->hsync_end % 2) || (mode->htotal % 2)))
1097 return -EINVAL;
1098
Maxime Ripard9fa1d7e2020-10-29 14:40:17 +01001099 /*
1100 * The 1440p@60 pixel rate is in the same range than the first
1101 * WiFi channel (between 2.4GHz and 2.422GHz with 22MHz
1102 * bandwidth). Slightly lower the frequency to bring it out of
1103 * the WiFi range.
1104 */
1105 tmds_rate = pixel_rate * 10;
1106 if (vc4_hdmi->disable_wifi_frequencies &&
1107 (tmds_rate >= WIFI_2_4GHz_CH1_MIN_FREQ &&
1108 tmds_rate <= WIFI_2_4GHz_CH1_MAX_FREQ)) {
1109 mode->clock = 238560;
1110 pixel_rate = mode->clock * 1000;
1111 }
1112
Maxime Ripardba8c0fa2020-12-15 16:42:43 +01001113 if (conn_state->max_bpc == 12) {
1114 pixel_rate = pixel_rate * 150;
1115 do_div(pixel_rate, 100);
1116 } else if (conn_state->max_bpc == 10) {
1117 pixel_rate = pixel_rate * 125;
1118 do_div(pixel_rate, 100);
1119 }
1120
Maxime Ripard320e84d2020-12-15 16:42:37 +01001121 if (mode->flags & DRM_MODE_FLAG_DBLCLK)
1122 pixel_rate = pixel_rate * 2;
1123
Maxime Ripard63495f6b2020-10-29 13:25:21 +01001124 if (pixel_rate > vc4_hdmi->variant->max_pixel_clock)
1125 return -EINVAL;
1126
Maxime Ripard86e3a652021-05-07 17:05:12 +02001127 if (vc4_hdmi->disable_4kp60 && (pixel_rate > HDMI_14_MAX_TMDS_CLK))
1128 return -EINVAL;
1129
Maxime Ripardf6237462020-12-15 16:42:40 +01001130 vc4_state->pixel_rate = pixel_rate;
1131
Maxime Ripard63495f6b2020-10-29 13:25:21 +01001132 return 0;
1133}
1134
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001135static enum drm_mode_status
Maxime Ripard11a17312020-09-03 10:01:34 +02001136vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001137 const struct drm_display_mode *mode)
1138{
Maxime Ripardcd4cb492020-09-03 10:01:35 +02001139 struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
1140
Maxime Ripard57fb32e2020-10-29 13:25:22 +01001141 if (vc4_hdmi->variant->unsupported_odd_h_timings &&
1142 ((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
1143 (mode->hsync_end % 2) || (mode->htotal % 2)))
1144 return MODE_H_ILLEGAL;
1145
Maxime Ripardcd4cb492020-09-03 10:01:35 +02001146 if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock)
Eric Anholt32e823c2017-09-20 15:59:34 -07001147 return MODE_CLOCK_HIGH;
1148
Maxime Ripard86e3a652021-05-07 17:05:12 +02001149 if (vc4_hdmi->disable_4kp60 && vc4_hdmi_mode_needs_scrambling(mode))
1150 return MODE_CLOCK_HIGH;
1151
Eric Anholt32e823c2017-09-20 15:59:34 -07001152 return MODE_OK;
1153}
1154
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001155static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = {
Maxime Ripard63495f6b2020-10-29 13:25:21 +01001156 .atomic_check = vc4_hdmi_encoder_atomic_check,
Eric Anholt32e823c2017-09-20 15:59:34 -07001157 .mode_valid = vc4_hdmi_encoder_mode_valid,
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001158 .disable = vc4_hdmi_encoder_disable,
1159 .enable = vc4_hdmi_encoder_enable,
1160};
1161
Dave Stevenson632ee3a2020-09-03 10:01:40 +02001162static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
Eric Anholtbb7d7852017-02-27 12:28:02 -08001163{
Dave Stevenson632ee3a2020-09-03 10:01:40 +02001164 int i;
1165 u32 channel_map = 0;
1166
1167 for (i = 0; i < 8; i++) {
1168 if (channel_mask & BIT(i))
1169 channel_map |= i << (3 * i);
1170 }
1171 return channel_map;
1172}
1173
Maxime Ripard83239892020-09-03 10:01:48 +02001174static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
1175{
1176 int i;
1177 u32 channel_map = 0;
1178
1179 for (i = 0; i < 8; i++) {
1180 if (channel_mask & BIT(i))
1181 channel_map |= i << (4 * i);
1182 }
1183 return channel_map;
1184}
1185
Eric Anholtbb7d7852017-02-27 12:28:02 -08001186/* HDMI audio codec callbacks */
Maxime Ripardf1437782021-07-07 11:36:31 +02001187static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
1188 unsigned int samplerate)
Eric Anholtbb7d7852017-02-27 12:28:02 -08001189{
Dave Stevenson632ee3a2020-09-03 10:01:40 +02001190 u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001191 unsigned long n, m;
1192
Maxime Ripardf1437782021-07-07 11:36:31 +02001193 rational_best_approximation(hsm_clock, samplerate,
Eric Anholtbb7d7852017-02-27 12:28:02 -08001194 VC4_HD_MAI_SMP_N_MASK >>
1195 VC4_HD_MAI_SMP_N_SHIFT,
1196 (VC4_HD_MAI_SMP_M_MASK >>
1197 VC4_HD_MAI_SMP_M_SHIFT) + 1,
1198 &n, &m);
1199
Maxime Ripard311e3052020-09-03 10:01:23 +02001200 HDMI_WRITE(HDMI_MAI_SMP,
1201 VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) |
1202 VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
Eric Anholtbb7d7852017-02-27 12:28:02 -08001203}
1204
Maxime Ripardf1437782021-07-07 11:36:31 +02001205static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate)
Eric Anholtbb7d7852017-02-27 12:28:02 -08001206{
Maxime Ripard27da3702021-07-07 16:19:30 +02001207 struct drm_connector *connector = &vc4_hdmi->connector;
1208 struct drm_crtc *crtc = connector->state->crtc;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001209 const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001210 u32 n, cts;
1211 u64 tmp;
1212
1213 n = 128 * samplerate / 1000;
1214 tmp = (u64)(mode->clock * 1000) * n;
1215 do_div(tmp, 128 * samplerate);
1216 cts = tmp;
1217
Maxime Ripard311e3052020-09-03 10:01:23 +02001218 HDMI_WRITE(HDMI_CRP_CFG,
Eric Anholtbb7d7852017-02-27 12:28:02 -08001219 VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN |
1220 VC4_SET_FIELD(n, VC4_HDMI_CRP_CFG_N));
1221
1222 /*
1223 * We could get slightly more accurate clocks in some cases by
1224 * providing a CTS_1 value. The two CTS values are alternated
1225 * between based on the period fields
1226 */
Maxime Ripard311e3052020-09-03 10:01:23 +02001227 HDMI_WRITE(HDMI_CTS_0, cts);
1228 HDMI_WRITE(HDMI_CTS_1, cts);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001229}
1230
1231static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
1232{
1233 struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
1234
1235 return snd_soc_card_get_drvdata(card);
1236}
1237
Maxime Ripard91e99e12021-05-25 15:23:52 +02001238static int vc4_hdmi_audio_startup(struct device *dev, void *data)
Eric Anholtbb7d7852017-02-27 12:28:02 -08001239{
Maxime Ripard91e99e12021-05-25 15:23:52 +02001240 struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
Maxime Ripard0532e5e2020-09-03 10:01:21 +02001241 struct drm_connector *connector = &vc4_hdmi->connector;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001242
1243 /*
1244 * If the HDMI encoder hasn't probed, or the encoder is
1245 * currently in DVI mode, treat the codec dai as missing.
1246 */
Maxime Ripard27da3702021-07-07 16:19:30 +02001247 if (!connector->state || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
Eric Anholtbb7d7852017-02-27 12:28:02 -08001248 VC4_HDMI_RAM_PACKET_ENABLE))
1249 return -ENODEV;
1250
Maxime Ripard91e99e12021-05-25 15:23:52 +02001251 vc4_hdmi->audio.streaming = true;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001252
Maxime Ripard91e99e12021-05-25 15:23:52 +02001253 HDMI_WRITE(HDMI_MAI_CTL,
1254 VC4_HD_MAI_CTL_RESET |
1255 VC4_HD_MAI_CTL_FLUSH |
1256 VC4_HD_MAI_CTL_DLATE |
1257 VC4_HD_MAI_CTL_ERRORE |
1258 VC4_HD_MAI_CTL_ERRORF);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001259
Maxime Ripard91e99e12021-05-25 15:23:52 +02001260 if (vc4_hdmi->variant->phy_rng_enable)
1261 vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
1262
Eric Anholtbb7d7852017-02-27 12:28:02 -08001263 return 0;
1264}
1265
Maxime Ripard3408cc22020-09-03 10:01:14 +02001266static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi)
Eric Anholtbb7d7852017-02-27 12:28:02 -08001267{
Maxime Ripard3408cc22020-09-03 10:01:14 +02001268 struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
Maxime Ripard3408cc22020-09-03 10:01:14 +02001269 struct device *dev = &vc4_hdmi->pdev->dev;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001270 int ret;
1271
Dave Stevenson6ac1c752020-09-03 10:01:38 +02001272 vc4_hdmi->audio.streaming = false;
Maxime Riparde2f9b2e2020-12-03 08:46:24 +01001273 ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO, false);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001274 if (ret)
1275 dev_err(dev, "Failed to stop audio infoframe: %d\n", ret);
1276
Maxime Ripard311e3052020-09-03 10:01:23 +02001277 HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET);
1278 HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF);
1279 HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001280}
1281
Maxime Ripard91e99e12021-05-25 15:23:52 +02001282static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
Eric Anholtbb7d7852017-02-27 12:28:02 -08001283{
Maxime Ripard91e99e12021-05-25 15:23:52 +02001284 struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001285
Maxime Ripard311e3052020-09-03 10:01:23 +02001286 HDMI_WRITE(HDMI_MAI_CTL,
Maxime Ripard311e3052020-09-03 10:01:23 +02001287 VC4_HD_MAI_CTL_DLATE |
1288 VC4_HD_MAI_CTL_ERRORE |
1289 VC4_HD_MAI_CTL_ERRORF);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001290
Maxime Ripard91e99e12021-05-25 15:23:52 +02001291 if (vc4_hdmi->variant->phy_rng_disable)
1292 vc4_hdmi->variant->phy_rng_disable(vc4_hdmi);
1293
1294 vc4_hdmi->audio.streaming = false;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001295 vc4_hdmi_audio_reset(vc4_hdmi);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001296}
1297
Dom Cobley82bd6072021-05-25 15:23:49 +02001298static int sample_rate_to_mai_fmt(int samplerate)
1299{
1300 switch (samplerate) {
1301 case 8000:
1302 return VC4_HDMI_MAI_SAMPLE_RATE_8000;
1303 case 11025:
1304 return VC4_HDMI_MAI_SAMPLE_RATE_11025;
1305 case 12000:
1306 return VC4_HDMI_MAI_SAMPLE_RATE_12000;
1307 case 16000:
1308 return VC4_HDMI_MAI_SAMPLE_RATE_16000;
1309 case 22050:
1310 return VC4_HDMI_MAI_SAMPLE_RATE_22050;
1311 case 24000:
1312 return VC4_HDMI_MAI_SAMPLE_RATE_24000;
1313 case 32000:
1314 return VC4_HDMI_MAI_SAMPLE_RATE_32000;
1315 case 44100:
1316 return VC4_HDMI_MAI_SAMPLE_RATE_44100;
1317 case 48000:
1318 return VC4_HDMI_MAI_SAMPLE_RATE_48000;
1319 case 64000:
1320 return VC4_HDMI_MAI_SAMPLE_RATE_64000;
1321 case 88200:
1322 return VC4_HDMI_MAI_SAMPLE_RATE_88200;
1323 case 96000:
1324 return VC4_HDMI_MAI_SAMPLE_RATE_96000;
1325 case 128000:
1326 return VC4_HDMI_MAI_SAMPLE_RATE_128000;
1327 case 176400:
1328 return VC4_HDMI_MAI_SAMPLE_RATE_176400;
1329 case 192000:
1330 return VC4_HDMI_MAI_SAMPLE_RATE_192000;
1331 default:
1332 return VC4_HDMI_MAI_SAMPLE_RATE_NOT_INDICATED;
1333 }
1334}
1335
Eric Anholtbb7d7852017-02-27 12:28:02 -08001336/* HDMI audio codec callbacks */
Maxime Ripard91e99e12021-05-25 15:23:52 +02001337static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
1338 struct hdmi_codec_daifmt *daifmt,
1339 struct hdmi_codec_params *params)
Eric Anholtbb7d7852017-02-27 12:28:02 -08001340{
Maxime Ripard91e99e12021-05-25 15:23:52 +02001341 struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001342 struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
Maxime Ripardf1437782021-07-07 11:36:31 +02001343 unsigned int sample_rate = params->sample_rate;
1344 unsigned int channels = params->channels;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001345 u32 audio_packet_config, channel_mask;
1346 u32 channel_map;
Dom Cobley82bd6072021-05-25 15:23:49 +02001347 u32 mai_audio_format;
1348 u32 mai_sample_rate;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001349
Eric Anholtbb7d7852017-02-27 12:28:02 -08001350 dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
Maxime Ripardf1437782021-07-07 11:36:31 +02001351 sample_rate, params->sample_width, channels);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001352
1353 HDMI_WRITE(HDMI_MAI_CTL,
Maxime Ripardf1437782021-07-07 11:36:31 +02001354 VC4_SET_FIELD(channels, VC4_HD_MAI_CTL_CHNUM) |
Maxime Ripard91e99e12021-05-25 15:23:52 +02001355 VC4_HD_MAI_CTL_WHOLSMP |
1356 VC4_HD_MAI_CTL_CHALIGN |
1357 VC4_HD_MAI_CTL_ENABLE);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001358
Maxime Ripardf1437782021-07-07 11:36:31 +02001359 vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001360
Maxime Ripardf1437782021-07-07 11:36:31 +02001361 mai_sample_rate = sample_rate_to_mai_fmt(sample_rate);
Maxime Ripard91e99e12021-05-25 15:23:52 +02001362 if (params->iec.status[0] & IEC958_AES0_NONAUDIO &&
1363 params->channels == 8)
1364 mai_audio_format = VC4_HDMI_MAI_FORMAT_HBR;
1365 else
1366 mai_audio_format = VC4_HDMI_MAI_FORMAT_PCM;
Dom Cobley82bd6072021-05-25 15:23:49 +02001367 HDMI_WRITE(HDMI_MAI_FMT,
1368 VC4_SET_FIELD(mai_sample_rate,
1369 VC4_HDMI_MAI_FORMAT_SAMPLE_RATE) |
1370 VC4_SET_FIELD(mai_audio_format,
1371 VC4_HDMI_MAI_FORMAT_AUDIO_FORMAT));
1372
Dave Stevensonb9b8bac2020-09-03 10:01:39 +02001373 /* The B frame identifier should match the value used by alsa-lib (8) */
Eric Anholtbb7d7852017-02-27 12:28:02 -08001374 audio_packet_config =
1375 VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT |
1376 VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS |
Dave Stevensonb9b8bac2020-09-03 10:01:39 +02001377 VC4_SET_FIELD(0x8, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001378
Maxime Ripardf1437782021-07-07 11:36:31 +02001379 channel_mask = GENMASK(channels - 1, 0);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001380 audio_packet_config |= VC4_SET_FIELD(channel_mask,
1381 VC4_HDMI_AUDIO_PACKET_CEA_MASK);
1382
Dom Cobley84341112021-05-25 15:23:51 +02001383 /* Set the MAI threshold */
1384 HDMI_WRITE(HDMI_MAI_THR,
1385 VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) |
1386 VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) |
1387 VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) |
1388 VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW));
Eric Anholtbb7d7852017-02-27 12:28:02 -08001389
Maxime Ripard311e3052020-09-03 10:01:23 +02001390 HDMI_WRITE(HDMI_MAI_CONFIG,
Eric Anholtbb7d7852017-02-27 12:28:02 -08001391 VC4_HDMI_MAI_CONFIG_BIT_REVERSE |
Dom Cobley9a8fd2772021-05-25 15:23:50 +02001392 VC4_HDMI_MAI_CONFIG_FORMAT_REVERSE |
Eric Anholtbb7d7852017-02-27 12:28:02 -08001393 VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK));
1394
Dave Stevenson632ee3a2020-09-03 10:01:40 +02001395 channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask);
Maxime Ripard311e3052020-09-03 10:01:23 +02001396 HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map);
1397 HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
Maxime Ripardf1437782021-07-07 11:36:31 +02001398 vc4_hdmi_set_n_cts(vc4_hdmi, sample_rate);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001399
Maxime Ripard91e99e12021-05-25 15:23:52 +02001400 memcpy(&vc4_hdmi->audio.infoframe, &params->cea, sizeof(params->cea));
Maxime Ripard58d04362020-10-27 11:15:58 +01001401 vc4_hdmi_set_audio_infoframe(encoder);
1402
Eric Anholtbb7d7852017-02-27 12:28:02 -08001403 return 0;
1404}
1405
Eric Anholtbb7d7852017-02-27 12:28:02 -08001406static const struct snd_soc_dapm_widget vc4_hdmi_audio_widgets[] = {
1407 SND_SOC_DAPM_OUTPUT("TX"),
1408};
1409
1410static const struct snd_soc_dapm_route vc4_hdmi_audio_routes[] = {
1411 { "TX", NULL, "Playback" },
1412};
1413
Kuninori Morimoto635b1c12018-01-29 04:35:04 +00001414static const struct snd_soc_component_driver vc4_hdmi_audio_component_drv = {
Maxime Riparda3a0ded2020-07-08 16:45:55 +02001415 .name = "vc4-hdmi-codec-dai-component",
Kuninori Morimoto635b1c12018-01-29 04:35:04 +00001416 .dapm_widgets = vc4_hdmi_audio_widgets,
1417 .num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets),
1418 .dapm_routes = vc4_hdmi_audio_routes,
1419 .num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes),
1420 .idle_bias_on = 1,
1421 .use_pmdown_time = 1,
1422 .endianness = 1,
1423 .non_legacy_dai_naming = 1,
Eric Anholtbb7d7852017-02-27 12:28:02 -08001424};
1425
Eric Anholtbb7d7852017-02-27 12:28:02 -08001426static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = {
1427 .name = "vc4-hdmi-cpu-dai-component",
1428};
1429
1430static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai)
1431{
Maxime Ripard3408cc22020-09-03 10:01:14 +02001432 struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001433
Maxime Ripard3408cc22020-09-03 10:01:14 +02001434 snd_soc_dai_init_dma_data(dai, &vc4_hdmi->audio.dma_data, NULL);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001435
1436 return 0;
1437}
1438
1439static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = {
1440 .name = "vc4-hdmi-cpu-dai",
1441 .probe = vc4_hdmi_audio_cpu_dai_probe,
1442 .playback = {
1443 .stream_name = "Playback",
1444 .channels_min = 1,
1445 .channels_max = 8,
1446 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
1447 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
1448 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
1449 SNDRV_PCM_RATE_192000,
1450 .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
1451 },
Eric Anholtbb7d7852017-02-27 12:28:02 -08001452};
1453
1454static const struct snd_dmaengine_pcm_config pcm_conf = {
1455 .chan_names[SNDRV_PCM_STREAM_PLAYBACK] = "audio-rx",
1456 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
1457};
1458
Maxime Ripard91e99e12021-05-25 15:23:52 +02001459static int vc4_hdmi_audio_get_eld(struct device *dev, void *data,
1460 uint8_t *buf, size_t len)
1461{
1462 struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
1463 struct drm_connector *connector = &vc4_hdmi->connector;
1464
1465 memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
1466
1467 return 0;
1468}
1469
1470static const struct hdmi_codec_ops vc4_hdmi_codec_ops = {
1471 .get_eld = vc4_hdmi_audio_get_eld,
1472 .prepare = vc4_hdmi_audio_prepare,
1473 .audio_shutdown = vc4_hdmi_audio_shutdown,
1474 .audio_startup = vc4_hdmi_audio_startup,
1475};
1476
1477struct hdmi_codec_pdata vc4_hdmi_codec_pdata = {
1478 .ops = &vc4_hdmi_codec_ops,
1479 .max_i2s_channels = 8,
1480 .i2s = 1,
1481};
1482
Maxime Ripard3408cc22020-09-03 10:01:14 +02001483static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
Eric Anholtbb7d7852017-02-27 12:28:02 -08001484{
Maxime Ripard311e3052020-09-03 10:01:23 +02001485 const struct vc4_hdmi_register *mai_data =
1486 &vc4_hdmi->variant->registers[HDMI_MAI_DATA];
Maxime Ripard3408cc22020-09-03 10:01:14 +02001487 struct snd_soc_dai_link *dai_link = &vc4_hdmi->audio.link;
1488 struct snd_soc_card *card = &vc4_hdmi->audio.card;
1489 struct device *dev = &vc4_hdmi->pdev->dev;
Maxime Ripard91e99e12021-05-25 15:23:52 +02001490 struct platform_device *codec_pdev;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001491 const __be32 *addr;
Dave Stevenson094864b2020-09-03 10:01:37 +02001492 int index;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001493 int ret;
1494
1495 if (!of_find_property(dev->of_node, "dmas", NULL)) {
1496 dev_warn(dev,
1497 "'dmas' DT property is missing, no HDMI audio\n");
1498 return 0;
1499 }
1500
Maxime Ripard311e3052020-09-03 10:01:23 +02001501 if (mai_data->reg != VC4_HD) {
1502 WARN_ONCE(true, "MAI isn't in the HD block\n");
1503 return -EINVAL;
1504 }
1505
Eric Anholtbb7d7852017-02-27 12:28:02 -08001506 /*
1507 * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve
1508 * the bus address specified in the DT, because the physical address
1509 * (the one returned by platform_get_resource()) is not appropriate
1510 * for DMA transfers.
1511 * This VC/MMU should probably be exposed to avoid this kind of hacks.
1512 */
Dave Stevenson094864b2020-09-03 10:01:37 +02001513 index = of_property_match_string(dev->of_node, "reg-names", "hd");
1514 /* Before BCM2711, we don't have a named register range */
1515 if (index < 0)
1516 index = 1;
1517
1518 addr = of_get_address(dev->of_node, index, NULL, NULL);
1519
Maxime Ripard311e3052020-09-03 10:01:23 +02001520 vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset;
Maxime Ripard3408cc22020-09-03 10:01:14 +02001521 vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1522 vc4_hdmi->audio.dma_data.maxburst = 2;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001523
1524 ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0);
1525 if (ret) {
1526 dev_err(dev, "Could not register PCM component: %d\n", ret);
1527 return ret;
1528 }
1529
1530 ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_cpu_dai_comp,
1531 &vc4_hdmi_audio_cpu_dai_drv, 1);
1532 if (ret) {
1533 dev_err(dev, "Could not register CPU DAI: %d\n", ret);
1534 return ret;
1535 }
1536
Maxime Ripard91e99e12021-05-25 15:23:52 +02001537 codec_pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
1538 PLATFORM_DEVID_AUTO,
1539 &vc4_hdmi_codec_pdata,
1540 sizeof(vc4_hdmi_codec_pdata));
1541 if (IS_ERR(codec_pdev)) {
1542 dev_err(dev, "Couldn't register the HDMI codec: %ld\n", PTR_ERR(codec_pdev));
1543 return PTR_ERR(codec_pdev);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001544 }
1545
Maxime Ripard3408cc22020-09-03 10:01:14 +02001546 dai_link->cpus = &vc4_hdmi->audio.cpu;
1547 dai_link->codecs = &vc4_hdmi->audio.codec;
1548 dai_link->platforms = &vc4_hdmi->audio.platform;
Kuninori Morimoto0467d8e2019-06-06 13:19:19 +09001549
1550 dai_link->num_cpus = 1;
1551 dai_link->num_codecs = 1;
Kuninori Morimoto8a90efd2019-06-28 10:46:14 +09001552 dai_link->num_platforms = 1;
Kuninori Morimoto0467d8e2019-06-06 13:19:19 +09001553
Eric Anholtbb7d7852017-02-27 12:28:02 -08001554 dai_link->name = "MAI";
1555 dai_link->stream_name = "MAI PCM";
Maxime Ripard91e99e12021-05-25 15:23:52 +02001556 dai_link->codecs->dai_name = "i2s-hifi";
Kuninori Morimoto0467d8e2019-06-06 13:19:19 +09001557 dai_link->cpus->dai_name = dev_name(dev);
Maxime Ripard91e99e12021-05-25 15:23:52 +02001558 dai_link->codecs->name = dev_name(&codec_pdev->dev);
Kuninori Morimoto8a90efd2019-06-28 10:46:14 +09001559 dai_link->platforms->name = dev_name(dev);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001560
1561 card->dai_link = dai_link;
1562 card->num_links = 1;
Maxime Ripard9be43a52020-09-03 10:01:41 +02001563 card->name = vc4_hdmi->variant->card_name;
Nicolas Saenz Julienne33c74532021-01-15 20:12:09 +01001564 card->driver_name = "vc4-hdmi";
Eric Anholtbb7d7852017-02-27 12:28:02 -08001565 card->dev = dev;
Marek Szyprowskiec653df2020-07-01 09:39:49 +02001566 card->owner = THIS_MODULE;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001567
1568 /*
1569 * Be careful, snd_soc_register_card() calls dev_set_drvdata() and
1570 * stores a pointer to the snd card object in dev->driver_data. This
1571 * means we cannot use it for something else. The hdmi back-pointer is
1572 * now stored in card->drvdata and should be retrieved with
1573 * snd_soc_card_get_drvdata() if needed.
1574 */
Maxime Ripard3408cc22020-09-03 10:01:14 +02001575 snd_soc_card_set_drvdata(card, vc4_hdmi);
Eric Anholtbb7d7852017-02-27 12:28:02 -08001576 ret = devm_snd_soc_register_card(dev, card);
Kuninori Morimoto635b1c12018-01-29 04:35:04 +00001577 if (ret)
Nicolas Saenz Julienne9d9fb752021-06-29 14:17:23 +02001578 dev_err_probe(dev, ret, "Could not register sound card\n");
Eric Anholtbb7d7852017-02-27 12:28:02 -08001579
1580 return ret;
Eric Anholtbb7d7852017-02-27 12:28:02 -08001581
Eric Anholtbb7d7852017-02-27 12:28:02 -08001582}
1583
Maxime Ripardf4790082021-05-24 15:20:18 +02001584static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
1585{
1586 struct vc4_hdmi *vc4_hdmi = priv;
1587 struct drm_device *dev = vc4_hdmi->connector.dev;
1588
Maxime Ripard44fe9f902021-07-07 11:51:12 +02001589 if (dev && dev->registered)
Maxime Ripardf4790082021-05-24 15:20:18 +02001590 drm_kms_helper_hotplug_event(dev);
1591
1592 return IRQ_HANDLED;
1593}
1594
1595static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi)
1596{
1597 struct drm_connector *connector = &vc4_hdmi->connector;
1598 struct platform_device *pdev = vc4_hdmi->pdev;
Maxime Ripardf4790082021-05-24 15:20:18 +02001599 int ret;
1600
1601 if (vc4_hdmi->variant->external_irq_controller) {
Maxime Ripard776efe82021-07-07 11:51:11 +02001602 unsigned int hpd_con = platform_get_irq_byname(pdev, "hpd-connected");
1603 unsigned int hpd_rm = platform_get_irq_byname(pdev, "hpd-removed");
1604
1605 ret = request_threaded_irq(hpd_con,
1606 NULL,
1607 vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
1608 "vc4 hdmi hpd connected", vc4_hdmi);
Maxime Ripardf4790082021-05-24 15:20:18 +02001609 if (ret)
1610 return ret;
1611
Maxime Ripard776efe82021-07-07 11:51:11 +02001612 ret = request_threaded_irq(hpd_rm,
1613 NULL,
1614 vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
1615 "vc4 hdmi hpd disconnected", vc4_hdmi);
1616 if (ret) {
1617 free_irq(hpd_con, vc4_hdmi);
Maxime Ripardf4790082021-05-24 15:20:18 +02001618 return ret;
Maxime Ripard776efe82021-07-07 11:51:11 +02001619 }
Maxime Ripardf4790082021-05-24 15:20:18 +02001620
1621 connector->polled = DRM_CONNECTOR_POLL_HPD;
1622 }
1623
1624 return 0;
1625}
1626
Maxime Ripard776efe82021-07-07 11:51:11 +02001627static void vc4_hdmi_hotplug_exit(struct vc4_hdmi *vc4_hdmi)
1628{
1629 struct platform_device *pdev = vc4_hdmi->pdev;
1630
1631 if (vc4_hdmi->variant->external_irq_controller) {
1632 free_irq(platform_get_irq_byname(pdev, "hpd-connected"), vc4_hdmi);
1633 free_irq(platform_get_irq_byname(pdev, "hpd-removed"), vc4_hdmi);
1634 }
1635}
1636
Hans Verkuil15b45112017-07-16 12:48:04 +02001637#ifdef CONFIG_DRM_VC4_HDMI_CEC
Maxime Riparded4a6bb2021-01-11 15:23:03 +01001638static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv)
Hans Verkuil15b45112017-07-16 12:48:04 +02001639{
Maxime Ripard66bf1c32020-09-03 10:01:18 +02001640 struct vc4_hdmi *vc4_hdmi = priv;
Hans Verkuil15b45112017-07-16 12:48:04 +02001641
Maxime Riparded4a6bb2021-01-11 15:23:03 +01001642 if (vc4_hdmi->cec_rx_msg.len)
1643 cec_received_msg(vc4_hdmi->cec_adap,
1644 &vc4_hdmi->cec_rx_msg);
1645
1646 return IRQ_HANDLED;
1647}
1648
1649static irqreturn_t vc4_cec_irq_handler_tx_thread(int irq, void *priv)
1650{
1651 struct vc4_hdmi *vc4_hdmi = priv;
1652
1653 if (vc4_hdmi->cec_tx_ok) {
Maxime Ripard3408cc22020-09-03 10:01:14 +02001654 cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_OK,
Hans Verkuil15b45112017-07-16 12:48:04 +02001655 0, 0, 0, 0);
1656 } else {
1657 /*
1658 * This CEC implementation makes 1 retry, so if we
1659 * get a NACK, then that means it made 2 attempts.
1660 */
Maxime Ripard3408cc22020-09-03 10:01:14 +02001661 cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_NACK,
Hans Verkuil15b45112017-07-16 12:48:04 +02001662 0, 2, 0, 0);
1663 }
1664 return IRQ_HANDLED;
1665}
1666
Maxime Riparded4a6bb2021-01-11 15:23:03 +01001667static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
1668{
1669 struct vc4_hdmi *vc4_hdmi = priv;
1670 irqreturn_t ret;
1671
1672 if (vc4_hdmi->cec_irq_was_rx)
1673 ret = vc4_cec_irq_handler_rx_thread(irq, priv);
1674 else
1675 ret = vc4_cec_irq_handler_tx_thread(irq, priv);
1676
1677 return ret;
1678}
1679
Maxime Ripard66bf1c32020-09-03 10:01:18 +02001680static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
Hans Verkuil15b45112017-07-16 12:48:04 +02001681{
Dom Cobley4a59ed52021-01-11 15:22:57 +01001682 struct drm_device *dev = vc4_hdmi->connector.dev;
Maxime Ripard13311452020-09-03 10:01:15 +02001683 struct cec_msg *msg = &vc4_hdmi->cec_rx_msg;
Hans Verkuil15b45112017-07-16 12:48:04 +02001684 unsigned int i;
1685
1686 msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >>
1687 VC4_HDMI_CEC_REC_WRD_CNT_SHIFT);
Dom Cobley4a59ed52021-01-11 15:22:57 +01001688
1689 if (msg->len > 16) {
1690 drm_err(dev, "Attempting to read too much data (%d)\n", msg->len);
1691 return;
1692 }
1693
Hans Verkuil15b45112017-07-16 12:48:04 +02001694 for (i = 0; i < msg->len; i += 4) {
Dom Cobley4a59ed52021-01-11 15:22:57 +01001695 u32 val = HDMI_READ(HDMI_CEC_RX_DATA_1 + (i >> 2));
Hans Verkuil15b45112017-07-16 12:48:04 +02001696
1697 msg->msg[i] = val & 0xff;
1698 msg->msg[i + 1] = (val >> 8) & 0xff;
1699 msg->msg[i + 2] = (val >> 16) & 0xff;
1700 msg->msg[i + 3] = (val >> 24) & 0xff;
1701 }
1702}
1703
Maxime Riparded4a6bb2021-01-11 15:23:03 +01001704static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
1705{
1706 struct vc4_hdmi *vc4_hdmi = priv;
1707 u32 cntrl1;
1708
1709 cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
1710 vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
1711 cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
1712 HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
1713
1714 return IRQ_WAKE_THREAD;
1715}
1716
1717static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
1718{
1719 struct vc4_hdmi *vc4_hdmi = priv;
1720 u32 cntrl1;
1721
1722 vc4_hdmi->cec_rx_msg.len = 0;
1723 cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
1724 vc4_cec_read_msg(vc4_hdmi, cntrl1);
1725 cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
1726 HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
1727 cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
1728
1729 HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
1730
1731 return IRQ_WAKE_THREAD;
1732}
1733
Hans Verkuil15b45112017-07-16 12:48:04 +02001734static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
1735{
Maxime Ripard66bf1c32020-09-03 10:01:18 +02001736 struct vc4_hdmi *vc4_hdmi = priv;
Maxime Ripard311e3052020-09-03 10:01:23 +02001737 u32 stat = HDMI_READ(HDMI_CEC_CPU_STATUS);
Maxime Riparded4a6bb2021-01-11 15:23:03 +01001738 irqreturn_t ret;
1739 u32 cntrl5;
Hans Verkuil15b45112017-07-16 12:48:04 +02001740
1741 if (!(stat & VC4_HDMI_CPU_CEC))
1742 return IRQ_NONE;
Maxime Riparded4a6bb2021-01-11 15:23:03 +01001743
Maxime Ripard311e3052020-09-03 10:01:23 +02001744 cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
Maxime Ripard3408cc22020-09-03 10:01:14 +02001745 vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
Maxime Riparded4a6bb2021-01-11 15:23:03 +01001746 if (vc4_hdmi->cec_irq_was_rx)
1747 ret = vc4_cec_irq_handler_rx_bare(irq, priv);
1748 else
1749 ret = vc4_cec_irq_handler_tx_bare(irq, priv);
Hans Verkuil15b45112017-07-16 12:48:04 +02001750
Maxime Riparded4a6bb2021-01-11 15:23:03 +01001751 HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
1752 return ret;
Hans Verkuil15b45112017-07-16 12:48:04 +02001753}
1754
1755static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
1756{
Maxime Ripard66bf1c32020-09-03 10:01:18 +02001757 struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
Hans Verkuil15b45112017-07-16 12:48:04 +02001758 /* clock period in microseconds */
1759 const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
Maxime Ripard311e3052020-09-03 10:01:23 +02001760 u32 val = HDMI_READ(HDMI_CEC_CNTRL_5);
Hans Verkuil15b45112017-07-16 12:48:04 +02001761
1762 val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
1763 VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
1764 VC4_HDMI_CEC_CNT_TO_4500_US_MASK);
1765 val |= ((4700 / usecs) << VC4_HDMI_CEC_CNT_TO_4700_US_SHIFT) |
1766 ((4500 / usecs) << VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT);
1767
1768 if (enable) {
Maxime Ripard311e3052020-09-03 10:01:23 +02001769 HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
Hans Verkuil15b45112017-07-16 12:48:04 +02001770 VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
Maxime Ripard311e3052020-09-03 10:01:23 +02001771 HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
1772 HDMI_WRITE(HDMI_CEC_CNTRL_2,
1773 ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
1774 ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
1775 ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
1776 ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
1777 ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
1778 HDMI_WRITE(HDMI_CEC_CNTRL_3,
1779 ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
1780 ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
1781 ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
1782 ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
1783 HDMI_WRITE(HDMI_CEC_CNTRL_4,
1784 ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
1785 ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
1786 ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
1787 ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
Hans Verkuil15b45112017-07-16 12:48:04 +02001788
Maxime Ripard185e98b2021-01-11 15:23:04 +01001789 if (!vc4_hdmi->variant->external_irq_controller)
1790 HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
Hans Verkuil15b45112017-07-16 12:48:04 +02001791 } else {
Maxime Ripard185e98b2021-01-11 15:23:04 +01001792 if (!vc4_hdmi->variant->external_irq_controller)
1793 HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
Maxime Ripard311e3052020-09-03 10:01:23 +02001794 HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
Hans Verkuil15b45112017-07-16 12:48:04 +02001795 VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
1796 }
1797 return 0;
1798}
1799
1800static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
1801{
Maxime Ripard66bf1c32020-09-03 10:01:18 +02001802 struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
Hans Verkuil15b45112017-07-16 12:48:04 +02001803
Maxime Ripard311e3052020-09-03 10:01:23 +02001804 HDMI_WRITE(HDMI_CEC_CNTRL_1,
1805 (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
Hans Verkuil15b45112017-07-16 12:48:04 +02001806 (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT);
1807 return 0;
1808}
1809
1810static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
1811 u32 signal_free_time, struct cec_msg *msg)
1812{
Maxime Ripard66bf1c32020-09-03 10:01:18 +02001813 struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
Dom Cobley4a59ed52021-01-11 15:22:57 +01001814 struct drm_device *dev = vc4_hdmi->connector.dev;
Hans Verkuil15b45112017-07-16 12:48:04 +02001815 u32 val;
1816 unsigned int i;
1817
Dom Cobley4a59ed52021-01-11 15:22:57 +01001818 if (msg->len > 16) {
1819 drm_err(dev, "Attempting to transmit too much data (%d)\n", msg->len);
1820 return -ENOMEM;
1821 }
1822
Hans Verkuil15b45112017-07-16 12:48:04 +02001823 for (i = 0; i < msg->len; i += 4)
Dom Cobley4a59ed52021-01-11 15:22:57 +01001824 HDMI_WRITE(HDMI_CEC_TX_DATA_1 + (i >> 2),
Hans Verkuil15b45112017-07-16 12:48:04 +02001825 (msg->msg[i]) |
1826 (msg->msg[i + 1] << 8) |
1827 (msg->msg[i + 2] << 16) |
1828 (msg->msg[i + 3] << 24));
1829
Maxime Ripard311e3052020-09-03 10:01:23 +02001830 val = HDMI_READ(HDMI_CEC_CNTRL_1);
Hans Verkuil15b45112017-07-16 12:48:04 +02001831 val &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
Maxime Ripard311e3052020-09-03 10:01:23 +02001832 HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
Hans Verkuil15b45112017-07-16 12:48:04 +02001833 val &= ~VC4_HDMI_CEC_MESSAGE_LENGTH_MASK;
1834 val |= (msg->len - 1) << VC4_HDMI_CEC_MESSAGE_LENGTH_SHIFT;
1835 val |= VC4_HDMI_CEC_START_XMIT_BEGIN;
1836
Maxime Ripard311e3052020-09-03 10:01:23 +02001837 HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
Hans Verkuil15b45112017-07-16 12:48:04 +02001838 return 0;
1839}
1840
1841static const struct cec_adap_ops vc4_hdmi_cec_adap_ops = {
1842 .adap_enable = vc4_hdmi_cec_adap_enable,
1843 .adap_log_addr = vc4_hdmi_cec_adap_log_addr,
1844 .adap_transmit = vc4_hdmi_cec_adap_transmit,
1845};
Hans Verkuil15b45112017-07-16 12:48:04 +02001846
Maxime Ripardc0791e02020-09-03 10:01:31 +02001847static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001848{
Dariusz Marcinkiewicz66c2dee2019-08-23 13:24:25 +02001849 struct cec_connector_info conn_info;
Maxime Ripardc0791e02020-09-03 10:01:31 +02001850 struct platform_device *pdev = vc4_hdmi->pdev;
Maxime Ripardae442bf2021-01-11 15:23:06 +01001851 struct device *dev = &pdev->dev;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001852 u32 value;
1853 int ret;
1854
Maxime Ripardae442bf2021-01-11 15:23:06 +01001855 if (!of_find_property(dev->of_node, "interrupts", NULL)) {
1856 dev_warn(dev, "'interrupts' DT property is missing, no CEC\n");
1857 return 0;
1858 }
1859
Maxime Ripardc0791e02020-09-03 10:01:31 +02001860 vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
1861 vc4_hdmi, "vc4",
1862 CEC_CAP_DEFAULTS |
1863 CEC_CAP_CONNECTOR_INFO, 1);
1864 ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap);
Hans Verkuil15b45112017-07-16 12:48:04 +02001865 if (ret < 0)
Maxime Ripardc0791e02020-09-03 10:01:31 +02001866 return ret;
Dariusz Marcinkiewicz66c2dee2019-08-23 13:24:25 +02001867
Maxime Ripardc0791e02020-09-03 10:01:31 +02001868 cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
1869 cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
Dariusz Marcinkiewicz66c2dee2019-08-23 13:24:25 +02001870
Maxime Ripardc0791e02020-09-03 10:01:31 +02001871 value = HDMI_READ(HDMI_CEC_CNTRL_1);
Maxime Ripard47fa9a82021-01-11 15:23:01 +01001872 /* Set the logical address to Unregistered */
1873 value |= VC4_HDMI_CEC_ADDR_MASK;
Maxime Ripardc0791e02020-09-03 10:01:31 +02001874 HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
Maxime Ripard47fa9a82021-01-11 15:23:01 +01001875
1876 vc4_hdmi_cec_update_clk_div(vc4_hdmi);
1877
Maxime Ripard185e98b2021-01-11 15:23:04 +01001878 if (vc4_hdmi->variant->external_irq_controller) {
Maxime Ripard32a19de2021-07-07 11:51:10 +02001879 ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-rx"),
1880 vc4_cec_irq_handler_rx_bare,
1881 vc4_cec_irq_handler_rx_thread, 0,
1882 "vc4 hdmi cec rx", vc4_hdmi);
Maxime Ripard185e98b2021-01-11 15:23:04 +01001883 if (ret)
1884 goto err_delete_cec_adap;
1885
Maxime Ripard32a19de2021-07-07 11:51:10 +02001886 ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-tx"),
1887 vc4_cec_irq_handler_tx_bare,
1888 vc4_cec_irq_handler_tx_thread, 0,
1889 "vc4 hdmi cec tx", vc4_hdmi);
Maxime Ripard185e98b2021-01-11 15:23:04 +01001890 if (ret)
Maxime Ripard32a19de2021-07-07 11:51:10 +02001891 goto err_remove_cec_rx_handler;
Maxime Ripard185e98b2021-01-11 15:23:04 +01001892 } else {
1893 HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
1894
Maxime Ripard32a19de2021-07-07 11:51:10 +02001895 ret = request_threaded_irq(platform_get_irq(pdev, 0),
1896 vc4_cec_irq_handler,
1897 vc4_cec_irq_handler_thread, 0,
1898 "vc4 hdmi cec", vc4_hdmi);
Maxime Ripard185e98b2021-01-11 15:23:04 +01001899 if (ret)
1900 goto err_delete_cec_adap;
1901 }
Maxime Ripardc0791e02020-09-03 10:01:31 +02001902
1903 ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
Hans Verkuil15b45112017-07-16 12:48:04 +02001904 if (ret < 0)
Maxime Ripard32a19de2021-07-07 11:51:10 +02001905 goto err_remove_handlers;
Eric Anholtc9be8042019-04-01 11:35:58 -07001906
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001907 return 0;
1908
Maxime Ripard32a19de2021-07-07 11:51:10 +02001909err_remove_handlers:
1910 if (vc4_hdmi->variant->external_irq_controller)
1911 free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
1912 else
1913 free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
1914
1915err_remove_cec_rx_handler:
1916 if (vc4_hdmi->variant->external_irq_controller)
1917 free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
1918
Hans Verkuil15b45112017-07-16 12:48:04 +02001919err_delete_cec_adap:
Maxime Ripardc0791e02020-09-03 10:01:31 +02001920 cec_delete_adapter(vc4_hdmi->cec_adap);
1921
1922 return ret;
1923}
1924
1925static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi)
1926{
Maxime Ripard32a19de2021-07-07 11:51:10 +02001927 struct platform_device *pdev = vc4_hdmi->pdev;
1928
1929 if (vc4_hdmi->variant->external_irq_controller) {
1930 free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
1931 free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
1932 } else {
1933 free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
1934 }
1935
Maxime Ripardc0791e02020-09-03 10:01:31 +02001936 cec_unregister_adapter(vc4_hdmi->cec_adap);
1937}
1938#else
1939static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
1940{
1941 return 0;
1942}
1943
1944static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) {};
1945
Hans Verkuil15b45112017-07-16 12:48:04 +02001946#endif
Eric Anholtc8b75bc2015-03-02 13:01:12 -08001947
Maxime Ripard311e3052020-09-03 10:01:23 +02001948static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi,
1949 struct debugfs_regset32 *regset,
1950 enum vc4_hdmi_regs reg)
1951{
1952 const struct vc4_hdmi_variant *variant = vc4_hdmi->variant;
1953 struct debugfs_reg32 *regs, *new_regs;
1954 unsigned int count = 0;
1955 unsigned int i;
1956
1957 regs = kcalloc(variant->num_registers, sizeof(*regs),
1958 GFP_KERNEL);
1959 if (!regs)
1960 return -ENOMEM;
1961
1962 for (i = 0; i < variant->num_registers; i++) {
1963 const struct vc4_hdmi_register *field = &variant->registers[i];
1964
1965 if (field->reg != reg)
1966 continue;
1967
1968 regs[count].name = field->name;
1969 regs[count].offset = field->offset;
1970 count++;
1971 }
1972
1973 new_regs = krealloc(regs, count * sizeof(*regs), GFP_KERNEL);
1974 if (!new_regs)
1975 return -ENOMEM;
1976
1977 regset->base = __vc4_hdmi_get_field_base(vc4_hdmi, reg);
1978 regset->regs = new_regs;
1979 regset->nregs = count;
1980
1981 return 0;
1982}
1983
Maxime Ripard33c773e2020-09-03 10:01:22 +02001984static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
1985{
1986 struct platform_device *pdev = vc4_hdmi->pdev;
1987 struct device *dev = &pdev->dev;
1988 int ret;
1989
1990 vc4_hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0);
1991 if (IS_ERR(vc4_hdmi->hdmicore_regs))
1992 return PTR_ERR(vc4_hdmi->hdmicore_regs);
1993
1994 vc4_hdmi->hd_regs = vc4_ioremap_regs(pdev, 1);
1995 if (IS_ERR(vc4_hdmi->hd_regs))
1996 return PTR_ERR(vc4_hdmi->hd_regs);
1997
Maxime Ripard311e3052020-09-03 10:01:23 +02001998 ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD);
1999 if (ret)
2000 return ret;
Maxime Ripard33c773e2020-09-03 10:01:22 +02002001
Maxime Ripard311e3052020-09-03 10:01:23 +02002002 ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI);
2003 if (ret)
2004 return ret;
Maxime Ripard33c773e2020-09-03 10:01:22 +02002005
2006 vc4_hdmi->pixel_clock = devm_clk_get(dev, "pixel");
2007 if (IS_ERR(vc4_hdmi->pixel_clock)) {
2008 ret = PTR_ERR(vc4_hdmi->pixel_clock);
2009 if (ret != -EPROBE_DEFER)
2010 DRM_ERROR("Failed to get pixel clock\n");
2011 return ret;
2012 }
2013
2014 vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi");
2015 if (IS_ERR(vc4_hdmi->hsm_clock)) {
2016 DRM_ERROR("Failed to get HDMI state machine clock\n");
2017 return PTR_ERR(vc4_hdmi->hsm_clock);
2018 }
Dave Stevenson632ee3a2020-09-03 10:01:40 +02002019 vc4_hdmi->audio_clock = vc4_hdmi->hsm_clock;
Maxime Ripard23b7eb52021-01-11 15:23:02 +01002020 vc4_hdmi->cec_clock = vc4_hdmi->hsm_clock;
Maxime Ripard33c773e2020-09-03 10:01:22 +02002021
2022 return 0;
2023}
2024
Maxime Ripard83239892020-09-03 10:01:48 +02002025static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
2026{
2027 struct platform_device *pdev = vc4_hdmi->pdev;
2028 struct device *dev = &pdev->dev;
2029 struct resource *res;
2030
2031 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi");
2032 if (!res)
2033 return -ENODEV;
2034
2035 vc4_hdmi->hdmicore_regs = devm_ioremap(dev, res->start,
2036 resource_size(res));
Dan Carpenter14929c52020-09-10 13:08:25 +03002037 if (!vc4_hdmi->hdmicore_regs)
2038 return -ENOMEM;
Maxime Ripard83239892020-09-03 10:01:48 +02002039
2040 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hd");
2041 if (!res)
2042 return -ENODEV;
2043
2044 vc4_hdmi->hd_regs = devm_ioremap(dev, res->start, resource_size(res));
Dan Carpenter14929c52020-09-10 13:08:25 +03002045 if (!vc4_hdmi->hd_regs)
2046 return -ENOMEM;
Maxime Ripard83239892020-09-03 10:01:48 +02002047
2048 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cec");
2049 if (!res)
2050 return -ENODEV;
2051
2052 vc4_hdmi->cec_regs = devm_ioremap(dev, res->start, resource_size(res));
Dan Carpenter14929c52020-09-10 13:08:25 +03002053 if (!vc4_hdmi->cec_regs)
2054 return -ENOMEM;
Maxime Ripard83239892020-09-03 10:01:48 +02002055
2056 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csc");
2057 if (!res)
2058 return -ENODEV;
2059
2060 vc4_hdmi->csc_regs = devm_ioremap(dev, res->start, resource_size(res));
Dan Carpenter14929c52020-09-10 13:08:25 +03002061 if (!vc4_hdmi->csc_regs)
2062 return -ENOMEM;
Maxime Ripard83239892020-09-03 10:01:48 +02002063
2064 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvp");
2065 if (!res)
2066 return -ENODEV;
2067
2068 vc4_hdmi->dvp_regs = devm_ioremap(dev, res->start, resource_size(res));
Dan Carpenter14929c52020-09-10 13:08:25 +03002069 if (!vc4_hdmi->dvp_regs)
2070 return -ENOMEM;
Maxime Ripard83239892020-09-03 10:01:48 +02002071
2072 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
2073 if (!res)
2074 return -ENODEV;
2075
2076 vc4_hdmi->phy_regs = devm_ioremap(dev, res->start, resource_size(res));
Dan Carpenter14929c52020-09-10 13:08:25 +03002077 if (!vc4_hdmi->phy_regs)
2078 return -ENOMEM;
Maxime Ripard83239892020-09-03 10:01:48 +02002079
2080 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "packet");
2081 if (!res)
2082 return -ENODEV;
2083
2084 vc4_hdmi->ram_regs = devm_ioremap(dev, res->start, resource_size(res));
Dan Carpenter14929c52020-09-10 13:08:25 +03002085 if (!vc4_hdmi->ram_regs)
2086 return -ENOMEM;
Maxime Ripard83239892020-09-03 10:01:48 +02002087
2088 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rm");
2089 if (!res)
2090 return -ENODEV;
2091
2092 vc4_hdmi->rm_regs = devm_ioremap(dev, res->start, resource_size(res));
Dan Carpenter14929c52020-09-10 13:08:25 +03002093 if (!vc4_hdmi->rm_regs)
2094 return -ENOMEM;
Maxime Ripard83239892020-09-03 10:01:48 +02002095
2096 vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi");
2097 if (IS_ERR(vc4_hdmi->hsm_clock)) {
2098 DRM_ERROR("Failed to get HDMI state machine clock\n");
2099 return PTR_ERR(vc4_hdmi->hsm_clock);
2100 }
2101
2102 vc4_hdmi->pixel_bvb_clock = devm_clk_get(dev, "bvb");
2103 if (IS_ERR(vc4_hdmi->pixel_bvb_clock)) {
2104 DRM_ERROR("Failed to get pixel bvb clock\n");
2105 return PTR_ERR(vc4_hdmi->pixel_bvb_clock);
2106 }
2107
2108 vc4_hdmi->audio_clock = devm_clk_get(dev, "audio");
2109 if (IS_ERR(vc4_hdmi->audio_clock)) {
2110 DRM_ERROR("Failed to get audio clock\n");
2111 return PTR_ERR(vc4_hdmi->audio_clock);
2112 }
2113
Maxime Ripard23b7eb52021-01-11 15:23:02 +01002114 vc4_hdmi->cec_clock = devm_clk_get(dev, "cec");
2115 if (IS_ERR(vc4_hdmi->cec_clock)) {
2116 DRM_ERROR("Failed to get CEC clock\n");
2117 return PTR_ERR(vc4_hdmi->cec_clock);
2118 }
2119
Maxime Ripard83239892020-09-03 10:01:48 +02002120 vc4_hdmi->reset = devm_reset_control_get(dev, NULL);
2121 if (IS_ERR(vc4_hdmi->reset)) {
2122 DRM_ERROR("Failed to get HDMI reset line\n");
2123 return PTR_ERR(vc4_hdmi->reset);
2124 }
2125
2126 return 0;
2127}
2128
Maxime Ripard411efa12021-05-25 11:10:58 +02002129#ifdef CONFIG_PM
2130static int vc4_hdmi_runtime_suspend(struct device *dev)
2131{
2132 struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
2133
2134 clk_disable_unprepare(vc4_hdmi->hsm_clock);
2135
2136 return 0;
2137}
2138
2139static int vc4_hdmi_runtime_resume(struct device *dev)
2140{
2141 struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
2142 int ret;
2143
2144 ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
2145 if (ret)
2146 return ret;
2147
2148 return 0;
2149}
2150#endif
2151
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002152static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
2153{
Maxime Ripard33c773e2020-09-03 10:01:22 +02002154 const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002155 struct platform_device *pdev = to_platform_device(dev);
2156 struct drm_device *drm = dev_get_drvdata(master);
Maxime Ripard3408cc22020-09-03 10:01:14 +02002157 struct vc4_hdmi *vc4_hdmi;
Maxime Ripardc98c85b2020-09-03 10:01:12 +02002158 struct drm_encoder *encoder;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002159 struct device_node *ddc_node;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002160 int ret;
2161
Maxime Ripard3408cc22020-09-03 10:01:14 +02002162 vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
2163 if (!vc4_hdmi)
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002164 return -ENOMEM;
Maxime Ripard257d36d2021-05-07 17:05:14 +02002165 INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002166
Maxime Ripard47c167b2020-09-03 10:01:19 +02002167 dev_set_drvdata(dev, vc4_hdmi);
Maxime Ripard3408cc22020-09-03 10:01:14 +02002168 encoder = &vc4_hdmi->encoder.base.base;
Maxime Ripard7d732992020-09-03 10:01:29 +02002169 vc4_hdmi->encoder.base.type = variant->encoder_type;
Maxime Ripard09c43812020-09-03 10:01:44 +02002170 vc4_hdmi->encoder.base.pre_crtc_configure = vc4_hdmi_encoder_pre_crtc_configure;
2171 vc4_hdmi->encoder.base.pre_crtc_enable = vc4_hdmi_encoder_pre_crtc_enable;
2172 vc4_hdmi->encoder.base.post_crtc_enable = vc4_hdmi_encoder_post_crtc_enable;
2173 vc4_hdmi->encoder.base.post_crtc_disable = vc4_hdmi_encoder_post_crtc_disable;
2174 vc4_hdmi->encoder.base.post_crtc_powerdown = vc4_hdmi_encoder_post_crtc_powerdown;
Maxime Ripard3408cc22020-09-03 10:01:14 +02002175 vc4_hdmi->pdev = pdev;
Maxime Ripard33c773e2020-09-03 10:01:22 +02002176 vc4_hdmi->variant = variant;
Maxime Ripardc98c85b2020-09-03 10:01:12 +02002177
Maxime Ripard33c773e2020-09-03 10:01:22 +02002178 ret = variant->init_resources(vc4_hdmi);
2179 if (ret)
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002180 return ret;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002181
2182 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2183 if (!ddc_node) {
2184 DRM_ERROR("Failed to find ddc node in device tree\n");
2185 return -ENODEV;
2186 }
2187
Maxime Ripard3408cc22020-09-03 10:01:14 +02002188 vc4_hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002189 of_node_put(ddc_node);
Maxime Ripard3408cc22020-09-03 10:01:14 +02002190 if (!vc4_hdmi->ddc) {
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002191 DRM_DEBUG("Failed to get ddc i2c adapter by node\n");
2192 return -EPROBE_DEFER;
2193 }
2194
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002195 /* Only use the GPIO HPD pin if present in the DT, otherwise
2196 * we'll use the HDMI core's register.
2197 */
Maxime Ripard68002342021-05-24 15:18:52 +02002198 vc4_hdmi->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
2199 if (IS_ERR(vc4_hdmi->hpd_gpio)) {
2200 ret = PTR_ERR(vc4_hdmi->hpd_gpio);
2201 goto err_put_ddc;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002202 }
2203
Maxime Ripard9fa1d7e2020-10-29 14:40:17 +01002204 vc4_hdmi->disable_wifi_frequencies =
2205 of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence");
2206
Maxime Ripard86e3a652021-05-07 17:05:12 +02002207 if (variant->max_pixel_clock == 600000000) {
2208 struct vc4_dev *vc4 = to_vc4_dev(drm);
2209 long max_rate = clk_round_rate(vc4->hvs->core_clk, 550000000);
2210
2211 if (max_rate < 550000000)
2212 vc4_hdmi->disable_4kp60 = true;
2213 }
2214
Dom Cobley902dc5c12021-01-11 15:22:56 +01002215 if (vc4_hdmi->variant->reset)
2216 vc4_hdmi->variant->reset(vc4_hdmi);
2217
Maxime Ripard5b006002021-05-07 17:05:09 +02002218 if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") ||
2219 of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) &&
2220 HDMI_READ(HDMI_VID_CTL) & VC4_HD_VID_CTL_ENABLE) {
2221 clk_prepare_enable(vc4_hdmi->pixel_clock);
2222 clk_prepare_enable(vc4_hdmi->hsm_clock);
2223 clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
2224 }
2225
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002226 pm_runtime_enable(dev);
2227
Maxime Ripardc98c85b2020-09-03 10:01:12 +02002228 drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
2229 drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002230
Maxime Ripard3408cc22020-09-03 10:01:14 +02002231 ret = vc4_hdmi_connector_init(drm, vc4_hdmi);
Maxime Ripardc98c85b2020-09-03 10:01:12 +02002232 if (ret)
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002233 goto err_destroy_encoder;
Maxime Ripardc98c85b2020-09-03 10:01:12 +02002234
Maxime Ripardf4790082021-05-24 15:20:18 +02002235 ret = vc4_hdmi_hotplug_init(vc4_hdmi);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002236 if (ret)
Maxime Ripardc0791e02020-09-03 10:01:31 +02002237 goto err_destroy_conn;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002238
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002239 ret = vc4_hdmi_cec_init(vc4_hdmi);
2240 if (ret)
Maxime Ripard776efe82021-07-07 11:51:11 +02002241 goto err_free_hotplug;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002242
Maxime Ripard3408cc22020-09-03 10:01:14 +02002243 ret = vc4_hdmi_audio_init(vc4_hdmi);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002244 if (ret)
Maxime Ripardc0791e02020-09-03 10:01:31 +02002245 goto err_free_cec;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002246
Maxime Ripardb2405c92020-09-03 10:01:30 +02002247 vc4_debugfs_add_file(drm, variant->debugfs_name,
2248 vc4_hdmi_debugfs_regs,
2249 vc4_hdmi);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002250
2251 return 0;
2252
Maxime Ripardc0791e02020-09-03 10:01:31 +02002253err_free_cec:
2254 vc4_hdmi_cec_exit(vc4_hdmi);
Maxime Ripard776efe82021-07-07 11:51:11 +02002255err_free_hotplug:
2256 vc4_hdmi_hotplug_exit(vc4_hdmi);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002257err_destroy_conn:
Maxime Ripard0532e5e2020-09-03 10:01:21 +02002258 vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002259err_destroy_encoder:
Maxime Ripardc98c85b2020-09-03 10:01:12 +02002260 drm_encoder_cleanup(encoder);
Boris Brezillon4f6e3d62017-04-11 18:39:25 +02002261 pm_runtime_disable(dev);
Maxime Riparde075a782021-05-24 15:18:51 +02002262err_put_ddc:
Maxime Ripard3408cc22020-09-03 10:01:14 +02002263 put_device(&vc4_hdmi->ddc->dev);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002264
2265 return ret;
2266}
2267
2268static void vc4_hdmi_unbind(struct device *dev, struct device *master,
2269 void *data)
2270{
Maxime Ripard47c167b2020-09-03 10:01:19 +02002271 struct vc4_hdmi *vc4_hdmi;
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002272
Maxime Ripard47c167b2020-09-03 10:01:19 +02002273 /*
2274 * ASoC makes it a bit hard to retrieve a pointer to the
2275 * vc4_hdmi structure. Registering the card will overwrite our
2276 * device drvdata with a pointer to the snd_soc_card structure,
2277 * which can then be used to retrieve whatever drvdata we want
2278 * to associate.
2279 *
2280 * However, that doesn't fly in the case where we wouldn't
2281 * register an ASoC card (because of an old DT that is missing
2282 * the dmas properties for example), then the card isn't
2283 * registered and the device drvdata wouldn't be set.
2284 *
2285 * We can deal with both cases by making sure a snd_soc_card
2286 * pointer and a vc4_hdmi structure are pointing to the same
2287 * memory address, so we can treat them indistinctly without any
2288 * issue.
2289 */
2290 BUILD_BUG_ON(offsetof(struct vc4_hdmi_audio, card) != 0);
2291 BUILD_BUG_ON(offsetof(struct vc4_hdmi, audio) != 0);
2292 vc4_hdmi = dev_get_drvdata(dev);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002293
Maxime Ripard311e3052020-09-03 10:01:23 +02002294 kfree(vc4_hdmi->hdmi_regset.regs);
2295 kfree(vc4_hdmi->hd_regset.regs);
2296
Maxime Ripardc0791e02020-09-03 10:01:31 +02002297 vc4_hdmi_cec_exit(vc4_hdmi);
Maxime Ripard776efe82021-07-07 11:51:11 +02002298 vc4_hdmi_hotplug_exit(vc4_hdmi);
Maxime Ripard0532e5e2020-09-03 10:01:21 +02002299 vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
Maxime Ripard3408cc22020-09-03 10:01:14 +02002300 drm_encoder_cleanup(&vc4_hdmi->encoder.base.base);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002301
Boris Brezillon4f6e3d62017-04-11 18:39:25 +02002302 pm_runtime_disable(dev);
2303
Maxime Ripard3408cc22020-09-03 10:01:14 +02002304 put_device(&vc4_hdmi->ddc->dev);
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002305}
2306
2307static const struct component_ops vc4_hdmi_ops = {
2308 .bind = vc4_hdmi_bind,
2309 .unbind = vc4_hdmi_unbind,
2310};
2311
2312static int vc4_hdmi_dev_probe(struct platform_device *pdev)
2313{
2314 return component_add(&pdev->dev, &vc4_hdmi_ops);
2315}
2316
2317static int vc4_hdmi_dev_remove(struct platform_device *pdev)
2318{
2319 component_del(&pdev->dev, &vc4_hdmi_ops);
2320 return 0;
2321}
2322
Maxime Ripard33c773e2020-09-03 10:01:22 +02002323static const struct vc4_hdmi_variant bcm2835_variant = {
Maxime Ripard7d732992020-09-03 10:01:29 +02002324 .encoder_type = VC4_ENCODER_TYPE_HDMI0,
Maxime Ripardb2405c92020-09-03 10:01:30 +02002325 .debugfs_name = "hdmi_regs",
Maxime Ripard9be43a52020-09-03 10:01:41 +02002326 .card_name = "vc4-hdmi",
Maxime Ripardcd4cb492020-09-03 10:01:35 +02002327 .max_pixel_clock = 162000000,
Maxime Ripard311e3052020-09-03 10:01:23 +02002328 .registers = vc4_hdmi_fields,
2329 .num_registers = ARRAY_SIZE(vc4_hdmi_fields),
2330
Maxime Ripard33c773e2020-09-03 10:01:22 +02002331 .init_resources = vc4_hdmi_init_resources,
Maxime Ripard89f31a22020-09-03 10:01:27 +02002332 .csc_setup = vc4_hdmi_csc_setup,
Maxime Ripard9045e912020-09-03 10:01:24 +02002333 .reset = vc4_hdmi_reset,
Maxime Ripard904f6682020-09-03 10:01:28 +02002334 .set_timings = vc4_hdmi_set_timings,
Maxime Ripardc457b8a2020-09-03 10:01:25 +02002335 .phy_init = vc4_hdmi_phy_init,
2336 .phy_disable = vc4_hdmi_phy_disable,
Maxime Ripard647b9652020-09-03 10:01:26 +02002337 .phy_rng_enable = vc4_hdmi_phy_rng_enable,
2338 .phy_rng_disable = vc4_hdmi_phy_rng_disable,
Dave Stevenson632ee3a2020-09-03 10:01:40 +02002339 .channel_map = vc4_hdmi_channel_map,
Dave Stevensonbccd5c52021-04-30 11:44:49 +02002340 .supports_hdr = false,
Maxime Ripard33c773e2020-09-03 10:01:22 +02002341};
2342
Maxime Ripard83239892020-09-03 10:01:48 +02002343static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
2344 .encoder_type = VC4_ENCODER_TYPE_HDMI0,
2345 .debugfs_name = "hdmi0_regs",
2346 .card_name = "vc4-hdmi-0",
Maxime Ripard24169a22020-12-15 16:42:42 +01002347 .max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
Maxime Ripard83239892020-09-03 10:01:48 +02002348 .registers = vc5_hdmi_hdmi0_fields,
2349 .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
2350 .phy_lane_mapping = {
2351 PHY_LANE_0,
2352 PHY_LANE_1,
2353 PHY_LANE_2,
2354 PHY_LANE_CK,
2355 },
Maxime Ripard57fb32e2020-10-29 13:25:22 +01002356 .unsupported_odd_h_timings = true,
Maxime Ripard185e98b2021-01-11 15:23:04 +01002357 .external_irq_controller = true,
Maxime Ripard83239892020-09-03 10:01:48 +02002358
2359 .init_resources = vc5_hdmi_init_resources,
2360 .csc_setup = vc5_hdmi_csc_setup,
2361 .reset = vc5_hdmi_reset,
2362 .set_timings = vc5_hdmi_set_timings,
2363 .phy_init = vc5_hdmi_phy_init,
2364 .phy_disable = vc5_hdmi_phy_disable,
2365 .phy_rng_enable = vc5_hdmi_phy_rng_enable,
2366 .phy_rng_disable = vc5_hdmi_phy_rng_disable,
2367 .channel_map = vc5_hdmi_channel_map,
Dave Stevensonbccd5c52021-04-30 11:44:49 +02002368 .supports_hdr = true,
Maxime Ripard83239892020-09-03 10:01:48 +02002369};
2370
2371static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
2372 .encoder_type = VC4_ENCODER_TYPE_HDMI1,
2373 .debugfs_name = "hdmi1_regs",
2374 .card_name = "vc4-hdmi-1",
Maxime Ripard24169a22020-12-15 16:42:42 +01002375 .max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
Maxime Ripard83239892020-09-03 10:01:48 +02002376 .registers = vc5_hdmi_hdmi1_fields,
2377 .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
2378 .phy_lane_mapping = {
2379 PHY_LANE_1,
2380 PHY_LANE_0,
2381 PHY_LANE_CK,
2382 PHY_LANE_2,
2383 },
Maxime Ripard57fb32e2020-10-29 13:25:22 +01002384 .unsupported_odd_h_timings = true,
Maxime Ripard185e98b2021-01-11 15:23:04 +01002385 .external_irq_controller = true,
Maxime Ripard83239892020-09-03 10:01:48 +02002386
2387 .init_resources = vc5_hdmi_init_resources,
2388 .csc_setup = vc5_hdmi_csc_setup,
2389 .reset = vc5_hdmi_reset,
2390 .set_timings = vc5_hdmi_set_timings,
2391 .phy_init = vc5_hdmi_phy_init,
2392 .phy_disable = vc5_hdmi_phy_disable,
2393 .phy_rng_enable = vc5_hdmi_phy_rng_enable,
2394 .phy_rng_disable = vc5_hdmi_phy_rng_disable,
2395 .channel_map = vc5_hdmi_channel_map,
Dave Stevensonbccd5c52021-04-30 11:44:49 +02002396 .supports_hdr = true,
Maxime Ripard83239892020-09-03 10:01:48 +02002397};
2398
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002399static const struct of_device_id vc4_hdmi_dt_match[] = {
Maxime Ripard33c773e2020-09-03 10:01:22 +02002400 { .compatible = "brcm,bcm2835-hdmi", .data = &bcm2835_variant },
Maxime Ripard83239892020-09-03 10:01:48 +02002401 { .compatible = "brcm,bcm2711-hdmi0", .data = &bcm2711_hdmi0_variant },
2402 { .compatible = "brcm,bcm2711-hdmi1", .data = &bcm2711_hdmi1_variant },
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002403 {}
2404};
2405
Maxime Ripard411efa12021-05-25 11:10:58 +02002406static const struct dev_pm_ops vc4_hdmi_pm_ops = {
2407 SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend,
2408 vc4_hdmi_runtime_resume,
2409 NULL)
2410};
2411
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002412struct platform_driver vc4_hdmi_driver = {
2413 .probe = vc4_hdmi_dev_probe,
2414 .remove = vc4_hdmi_dev_remove,
2415 .driver = {
2416 .name = "vc4_hdmi",
2417 .of_match_table = vc4_hdmi_dt_match,
Maxime Ripard411efa12021-05-25 11:10:58 +02002418 .pm = &vc4_hdmi_pm_ops,
Eric Anholtc8b75bc2015-03-02 13:01:12 -08002419 },
2420};