1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2016 BayLibre, SAS
4  * Author: Neil Armstrong <narmstrong@baylibre.com>
5  * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
6  */
7 
8 #include <linux/clk.h>
9 #include <linux/component.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/of_device.h>
13 #include <linux/of_graph.h>
14 #include <linux/regulator/consumer.h>
15 #include <linux/reset.h>
16 
17 #include <drm/drm_atomic_helper.h>
18 #include <drm/drm_bridge.h>
19 #include <drm/drm_device.h>
20 #include <drm/drm_edid.h>
21 #include <drm/drm_probe_helper.h>
22 #include <drm/drm_simple_kms_helper.h>
23 
24 #include <linux/media-bus-format.h>
25 #include <linux/videodev2.h>
26 
27 #include "meson_drv.h"
28 #include "meson_registers.h"
29 #include "meson_vclk.h"
30 #include "meson_venc.h"
31 #include "meson_encoder_hdmi.h"
32 
33 struct meson_encoder_hdmi {
34 	struct drm_encoder encoder;
35 	struct drm_bridge bridge;
36 	struct drm_bridge *next_bridge;
37 	struct meson_drm *priv;
38 	unsigned long output_bus_fmt;
39 };
40 
41 #define bridge_to_meson_encoder_hdmi(x) \
42 	container_of(x, struct meson_encoder_hdmi, bridge)
43 
44 static int meson_encoder_hdmi_attach(struct drm_bridge *bridge,
45 				     enum drm_bridge_attach_flags flags)
46 {
47 	struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
48 
49 	return drm_bridge_attach(bridge->encoder, encoder_hdmi->next_bridge,
50 				 &encoder_hdmi->bridge, flags);
51 }
52 
53 static void meson_encoder_hdmi_set_vclk(struct meson_encoder_hdmi *encoder_hdmi,
54 					const struct drm_display_mode *mode)
55 {
56 	struct meson_drm *priv = encoder_hdmi->priv;
57 	int vic = drm_match_cea_mode(mode);
58 	unsigned int phy_freq;
59 	unsigned int vclk_freq;
60 	unsigned int venc_freq;
61 	unsigned int hdmi_freq;
62 
63 	vclk_freq = mode->clock;
64 
65 	/* For 420, pixel clock is half unlike venc clock */
66 	if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
67 		vclk_freq /= 2;
68 
69 	/* TMDS clock is pixel_clock * 10 */
70 	phy_freq = vclk_freq * 10;
71 
72 	if (!vic) {
73 		meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq,
74 				 vclk_freq, vclk_freq, vclk_freq, false);
75 		return;
76 	}
77 
78 	/* 480i/576i needs global pixel doubling */
79 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
80 		vclk_freq *= 2;
81 
82 	venc_freq = vclk_freq;
83 	hdmi_freq = vclk_freq;
84 
85 	/* VENC double pixels for 1080i, 720p and YUV420 modes */
86 	if (meson_venc_hdmi_venc_repeat(vic) ||
87 	    encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
88 		venc_freq *= 2;
89 
90 	vclk_freq = max(venc_freq, hdmi_freq);
91 
92 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
93 		venc_freq /= 2;
94 
95 	dev_dbg(priv->dev, "vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n",
96 		phy_freq, vclk_freq, venc_freq, hdmi_freq,
97 		priv->venc.hdmi_use_enci);
98 
99 	meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq,
100 			 venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
101 }
102 
103 static enum drm_mode_status meson_encoder_hdmi_mode_valid(struct drm_bridge *bridge,
104 					const struct drm_display_info *display_info,
105 					const struct drm_display_mode *mode)
106 {
107 	struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
108 	struct meson_drm *priv = encoder_hdmi->priv;
109 	bool is_hdmi2_sink = display_info->hdmi.scdc.supported;
110 	unsigned int phy_freq;
111 	unsigned int vclk_freq;
112 	unsigned int venc_freq;
113 	unsigned int hdmi_freq;
114 	int vic = drm_match_cea_mode(mode);
115 	enum drm_mode_status status;
116 
117 	dev_dbg(priv->dev, "Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
118 
119 	/* If sink does not support 540MHz, reject the non-420 HDMI2 modes */
120 	if (display_info->max_tmds_clock &&
121 	    mode->clock > display_info->max_tmds_clock &&
122 	    !drm_mode_is_420_only(display_info, mode) &&
123 	    !drm_mode_is_420_also(display_info, mode))
124 		return MODE_BAD;
125 
126 	/* Check against non-VIC supported modes */
127 	if (!vic) {
128 		status = meson_venc_hdmi_supported_mode(mode);
129 		if (status != MODE_OK)
130 			return status;
131 
132 		return meson_vclk_dmt_supported_freq(priv, mode->clock);
133 	/* Check against supported VIC modes */
134 	} else if (!meson_venc_hdmi_supported_vic(vic))
135 		return MODE_BAD;
136 
137 	vclk_freq = mode->clock;
138 
139 	/* For 420, pixel clock is half unlike venc clock */
140 	if (drm_mode_is_420_only(display_info, mode) ||
141 	    (!is_hdmi2_sink &&
142 	     drm_mode_is_420_also(display_info, mode)))
143 		vclk_freq /= 2;
144 
145 	/* TMDS clock is pixel_clock * 10 */
146 	phy_freq = vclk_freq * 10;
147 
148 	/* 480i/576i needs global pixel doubling */
149 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
150 		vclk_freq *= 2;
151 
152 	venc_freq = vclk_freq;
153 	hdmi_freq = vclk_freq;
154 
155 	/* VENC double pixels for 1080i, 720p and YUV420 modes */
156 	if (meson_venc_hdmi_venc_repeat(vic) ||
157 	    drm_mode_is_420_only(display_info, mode) ||
158 	    (!is_hdmi2_sink &&
159 	     drm_mode_is_420_also(display_info, mode)))
160 		venc_freq *= 2;
161 
162 	vclk_freq = max(venc_freq, hdmi_freq);
163 
164 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
165 		venc_freq /= 2;
166 
167 	dev_dbg(priv->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
168 		__func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
169 
170 	return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq);
171 }
172 
173 static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge,
174 					     struct drm_bridge_state *bridge_state)
175 {
176 	struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
177 	struct drm_atomic_state *state = bridge_state->base.state;
178 	unsigned int ycrcb_map = VPU_HDMI_OUTPUT_CBYCR;
179 	struct meson_drm *priv = encoder_hdmi->priv;
180 	struct drm_connector_state *conn_state;
181 	const struct drm_display_mode *mode;
182 	struct drm_crtc_state *crtc_state;
183 	struct drm_connector *connector;
184 	bool yuv420_mode = false;
185 	int vic;
186 
187 	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
188 	if (WARN_ON(!connector))
189 		return;
190 
191 	conn_state = drm_atomic_get_new_connector_state(state, connector);
192 	if (WARN_ON(!conn_state))
193 		return;
194 
195 	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
196 	if (WARN_ON(!crtc_state))
197 		return;
198 
199 	mode = &crtc_state->adjusted_mode;
200 
201 	vic = drm_match_cea_mode(mode);
202 
203 	dev_dbg(priv->dev, "\"%s\" vic %d\n", mode->name, vic);
204 
205 	if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) {
206 		ycrcb_map = VPU_HDMI_OUTPUT_CRYCB;
207 		yuv420_mode = true;
208 	}
209 
210 	/* VENC + VENC-DVI Mode setup */
211 	meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode);
212 
213 	/* VCLK Set clock */
214 	meson_encoder_hdmi_set_vclk(encoder_hdmi, mode);
215 
216 	if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
217 		/* Setup YUV420 to HDMI-TX, no 10bit diphering */
218 		writel_relaxed(2 | (2 << 2),
219 			       priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
220 	else
221 		/* Setup YUV444 to HDMI-TX, no 10bit diphering */
222 		writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
223 
224 	dev_dbg(priv->dev, "%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
225 
226 	if (priv->venc.hdmi_use_enci)
227 		writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
228 	else
229 		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
230 }
231 
232 static void meson_encoder_hdmi_atomic_disable(struct drm_bridge *bridge,
233 					     struct drm_bridge_state *bridge_state)
234 {
235 	struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
236 	struct meson_drm *priv = encoder_hdmi->priv;
237 
238 	writel_bits_relaxed(0x3, 0,
239 			    priv->io_base + _REG(VPU_HDMI_SETTING));
240 
241 	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
242 	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
243 }
244 
245 static const u32 meson_encoder_hdmi_out_bus_fmts[] = {
246 	MEDIA_BUS_FMT_YUV8_1X24,
247 	MEDIA_BUS_FMT_UYYVYY8_0_5X24,
248 };
249 
250 static u32 *
251 meson_encoder_hdmi_get_inp_bus_fmts(struct drm_bridge *bridge,
252 					struct drm_bridge_state *bridge_state,
253 					struct drm_crtc_state *crtc_state,
254 					struct drm_connector_state *conn_state,
255 					u32 output_fmt,
256 					unsigned int *num_input_fmts)
257 {
258 	u32 *input_fmts = NULL;
259 	int i;
260 
261 	*num_input_fmts = 0;
262 
263 	for (i = 0 ; i < ARRAY_SIZE(meson_encoder_hdmi_out_bus_fmts) ; ++i) {
264 		if (output_fmt == meson_encoder_hdmi_out_bus_fmts[i]) {
265 			*num_input_fmts = 1;
266 			input_fmts = kcalloc(*num_input_fmts,
267 					     sizeof(*input_fmts),
268 					     GFP_KERNEL);
269 			if (!input_fmts)
270 				return NULL;
271 
272 			input_fmts[0] = output_fmt;
273 
274 			break;
275 		}
276 	}
277 
278 	return input_fmts;
279 }
280 
281 static int meson_encoder_hdmi_atomic_check(struct drm_bridge *bridge,
282 					struct drm_bridge_state *bridge_state,
283 					struct drm_crtc_state *crtc_state,
284 					struct drm_connector_state *conn_state)
285 {
286 	struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
287 	struct drm_connector_state *old_conn_state =
288 		drm_atomic_get_old_connector_state(conn_state->state, conn_state->connector);
289 	struct meson_drm *priv = encoder_hdmi->priv;
290 
291 	encoder_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format;
292 
293 	dev_dbg(priv->dev, "output_bus_fmt %lx\n", encoder_hdmi->output_bus_fmt);
294 
295 	if (!drm_connector_atomic_hdr_metadata_equal(old_conn_state, conn_state))
296 		crtc_state->mode_changed = true;
297 
298 	return 0;
299 }
300 
301 static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs = {
302 	.attach = meson_encoder_hdmi_attach,
303 	.mode_valid = meson_encoder_hdmi_mode_valid,
304 	.atomic_enable = meson_encoder_hdmi_atomic_enable,
305 	.atomic_disable = meson_encoder_hdmi_atomic_disable,
306 	.atomic_get_input_bus_fmts = meson_encoder_hdmi_get_inp_bus_fmts,
307 	.atomic_check = meson_encoder_hdmi_atomic_check,
308 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
309 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
310 	.atomic_reset = drm_atomic_helper_bridge_reset,
311 };
312 
313 int meson_encoder_hdmi_init(struct meson_drm *priv)
314 {
315 	struct meson_encoder_hdmi *meson_encoder_hdmi;
316 	struct device_node *remote;
317 	int ret;
318 
319 	meson_encoder_hdmi = devm_kzalloc(priv->dev, sizeof(*meson_encoder_hdmi), GFP_KERNEL);
320 	if (!meson_encoder_hdmi)
321 		return -ENOMEM;
322 
323 	/* HDMI Transceiver Bridge */
324 	remote = of_graph_get_remote_node(priv->dev->of_node, 1, 0);
325 	if (!remote) {
326 		dev_err(priv->dev, "HDMI transceiver device is disabled");
327 		return 0;
328 	}
329 
330 	meson_encoder_hdmi->next_bridge = of_drm_find_bridge(remote);
331 	if (!meson_encoder_hdmi->next_bridge) {
332 		dev_err(priv->dev, "Failed to find HDMI transceiver bridge\n");
333 		return -EPROBE_DEFER;
334 	}
335 
336 	/* HDMI Encoder Bridge */
337 	meson_encoder_hdmi->bridge.funcs = &meson_encoder_hdmi_bridge_funcs;
338 	meson_encoder_hdmi->bridge.of_node = priv->dev->of_node;
339 	meson_encoder_hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
340 
341 	drm_bridge_add(&meson_encoder_hdmi->bridge);
342 
343 	meson_encoder_hdmi->priv = priv;
344 
345 	/* Encoder */
346 	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder,
347 				      DRM_MODE_ENCODER_TMDS);
348 	if (ret) {
349 		dev_err(priv->dev, "Failed to init HDMI encoder: %d\n", ret);
350 		return ret;
351 	}
352 
353 	meson_encoder_hdmi->encoder.possible_crtcs = BIT(0);
354 
355 	/* Attach HDMI Encoder Bridge to Encoder */
356 	ret = drm_bridge_attach(&meson_encoder_hdmi->encoder, &meson_encoder_hdmi->bridge, NULL, 0);
357 	if (ret) {
358 		dev_err(priv->dev, "Failed to attach bridge: %d\n", ret);
359 		return ret;
360 	}
361 
362 	/*
363 	 * We should have now in place:
364 	 * encoder->[hdmi encoder bridge]->[dw-hdmi bridge]->[dw-hdmi connector]
365 	 */
366 
367 	dev_dbg(priv->dev, "HDMI encoder initialized\n");
368 
369 	return 0;
370 }
371