18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Chrontel CH7033 Video Encoder Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2019,2020 Lubomir Rintel
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/regmap.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
138c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h>
148c2ecf20Sopenharmony_ci#include <drm/drm_edid.h>
158c2ecf20Sopenharmony_ci#include <drm/drm_of.h>
168c2ecf20Sopenharmony_ci#include <drm/drm_print.h>
178c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* Page 0, Register 0x07 */
208c2ecf20Sopenharmony_cienum {
218c2ecf20Sopenharmony_ci	DRI_PD		= BIT(3),
228c2ecf20Sopenharmony_ci	IO_PD		= BIT(5),
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* Page 0, Register 0x08 */
268c2ecf20Sopenharmony_cienum {
278c2ecf20Sopenharmony_ci	DRI_PDDRI	= GENMASK(7, 4),
288c2ecf20Sopenharmony_ci	PDDAC		= GENMASK(3, 1),
298c2ecf20Sopenharmony_ci	PANEN		= BIT(0),
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/* Page 0, Register 0x09 */
338c2ecf20Sopenharmony_cienum {
348c2ecf20Sopenharmony_ci	DPD		= BIT(7),
358c2ecf20Sopenharmony_ci	GCKOFF		= BIT(6),
368c2ecf20Sopenharmony_ci	TV_BP		= BIT(5),
378c2ecf20Sopenharmony_ci	SCLPD		= BIT(4),
388c2ecf20Sopenharmony_ci	SDPD		= BIT(3),
398c2ecf20Sopenharmony_ci	VGA_PD		= BIT(2),
408c2ecf20Sopenharmony_ci	HDBKPD		= BIT(1),
418c2ecf20Sopenharmony_ci	HDMI_PD		= BIT(0),
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* Page 0, Register 0x0a */
458c2ecf20Sopenharmony_cienum {
468c2ecf20Sopenharmony_ci	MEMINIT		= BIT(7),
478c2ecf20Sopenharmony_ci	MEMIDLE		= BIT(6),
488c2ecf20Sopenharmony_ci	MEMPD		= BIT(5),
498c2ecf20Sopenharmony_ci	STOP		= BIT(4),
508c2ecf20Sopenharmony_ci	LVDS_PD		= BIT(3),
518c2ecf20Sopenharmony_ci	HD_DVIB		= BIT(2),
528c2ecf20Sopenharmony_ci	HDCP_PD		= BIT(1),
538c2ecf20Sopenharmony_ci	MCU_PD		= BIT(0),
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/* Page 0, Register 0x18 */
578c2ecf20Sopenharmony_cienum {
588c2ecf20Sopenharmony_ci	IDF		= GENMASK(7, 4),
598c2ecf20Sopenharmony_ci	INTEN		= BIT(3),
608c2ecf20Sopenharmony_ci	SWAP		= GENMASK(2, 0),
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cienum {
648c2ecf20Sopenharmony_ci	BYTE_SWAP_RGB	= 0,
658c2ecf20Sopenharmony_ci	BYTE_SWAP_RBG	= 1,
668c2ecf20Sopenharmony_ci	BYTE_SWAP_GRB	= 2,
678c2ecf20Sopenharmony_ci	BYTE_SWAP_GBR	= 3,
688c2ecf20Sopenharmony_ci	BYTE_SWAP_BRG	= 4,
698c2ecf20Sopenharmony_ci	BYTE_SWAP_BGR	= 5,
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* Page 0, Register 0x19 */
738c2ecf20Sopenharmony_cienum {
748c2ecf20Sopenharmony_ci	HPO_I		= BIT(5),
758c2ecf20Sopenharmony_ci	VPO_I		= BIT(4),
768c2ecf20Sopenharmony_ci	DEPO_I		= BIT(3),
778c2ecf20Sopenharmony_ci	CRYS_EN		= BIT(2),
788c2ecf20Sopenharmony_ci	GCLKFREQ	= GENMASK(2, 0),
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/* Page 0, Register 0x2e */
828c2ecf20Sopenharmony_cienum {
838c2ecf20Sopenharmony_ci	HFLIP		= BIT(7),
848c2ecf20Sopenharmony_ci	VFLIP		= BIT(6),
858c2ecf20Sopenharmony_ci	DEPO_O		= BIT(5),
868c2ecf20Sopenharmony_ci	HPO_O		= BIT(4),
878c2ecf20Sopenharmony_ci	VPO_O		= BIT(3),
888c2ecf20Sopenharmony_ci	TE		= GENMASK(2, 0),
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* Page 0, Register 0x2b */
928c2ecf20Sopenharmony_cienum {
938c2ecf20Sopenharmony_ci	SWAPS		= GENMASK(7, 4),
948c2ecf20Sopenharmony_ci	VFMT		= GENMASK(3, 0),
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* Page 0, Register 0x54 */
988c2ecf20Sopenharmony_cienum {
998c2ecf20Sopenharmony_ci	COMP_BP		= BIT(7),
1008c2ecf20Sopenharmony_ci	DAC_EN_T	= BIT(6),
1018c2ecf20Sopenharmony_ci	HWO_HDMI_HI	= GENMASK(5, 3),
1028c2ecf20Sopenharmony_ci	HOO_HDMI_HI	= GENMASK(2, 0),
1038c2ecf20Sopenharmony_ci};
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* Page 0, Register 0x57 */
1068c2ecf20Sopenharmony_cienum {
1078c2ecf20Sopenharmony_ci	FLDSEN		= BIT(7),
1088c2ecf20Sopenharmony_ci	VWO_HDMI_HI	= GENMASK(5, 3),
1098c2ecf20Sopenharmony_ci	VOO_HDMI_HI	= GENMASK(2, 0),
1108c2ecf20Sopenharmony_ci};
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* Page 0, Register 0x7e */
1138c2ecf20Sopenharmony_cienum {
1148c2ecf20Sopenharmony_ci	HDMI_LVDS_SEL	= BIT(7),
1158c2ecf20Sopenharmony_ci	DE_GEN		= BIT(6),
1168c2ecf20Sopenharmony_ci	PWM_INDEX_HI	= BIT(5),
1178c2ecf20Sopenharmony_ci	USE_DE		= BIT(4),
1188c2ecf20Sopenharmony_ci	R_INT		= GENMASK(3, 0),
1198c2ecf20Sopenharmony_ci};
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/* Page 1, Register 0x07 */
1228c2ecf20Sopenharmony_cienum {
1238c2ecf20Sopenharmony_ci	BPCKSEL		= BIT(7),
1248c2ecf20Sopenharmony_ci	DRI_CMFB_EN	= BIT(6),
1258c2ecf20Sopenharmony_ci	CEC_PUEN	= BIT(5),
1268c2ecf20Sopenharmony_ci	CEC_T		= BIT(3),
1278c2ecf20Sopenharmony_ci	CKINV		= BIT(2),
1288c2ecf20Sopenharmony_ci	CK_TVINV	= BIT(1),
1298c2ecf20Sopenharmony_ci	DRI_CKS2	= BIT(0),
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* Page 1, Register 0x08 */
1338c2ecf20Sopenharmony_cienum {
1348c2ecf20Sopenharmony_ci	DACG		= BIT(6),
1358c2ecf20Sopenharmony_ci	DACKTST		= BIT(5),
1368c2ecf20Sopenharmony_ci	DEDGEB		= BIT(4),
1378c2ecf20Sopenharmony_ci	SYO		= BIT(3),
1388c2ecf20Sopenharmony_ci	DRI_IT_LVDS	= GENMASK(2, 1),
1398c2ecf20Sopenharmony_ci	DISPON		= BIT(0),
1408c2ecf20Sopenharmony_ci};
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/* Page 1, Register 0x0c */
1438c2ecf20Sopenharmony_cienum {
1448c2ecf20Sopenharmony_ci	DRI_PLL_CP	= GENMASK(7, 6),
1458c2ecf20Sopenharmony_ci	DRI_PLL_DIVSEL	= BIT(5),
1468c2ecf20Sopenharmony_ci	DRI_PLL_N1_1	= BIT(4),
1478c2ecf20Sopenharmony_ci	DRI_PLL_N1_0	= BIT(3),
1488c2ecf20Sopenharmony_ci	DRI_PLL_N3_1	= BIT(2),
1498c2ecf20Sopenharmony_ci	DRI_PLL_N3_0	= BIT(1),
1508c2ecf20Sopenharmony_ci	DRI_PLL_CKTSTEN = BIT(0),
1518c2ecf20Sopenharmony_ci};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/* Page 1, Register 0x6b */
1548c2ecf20Sopenharmony_cienum {
1558c2ecf20Sopenharmony_ci	VCO3CS		= GENMASK(7, 6),
1568c2ecf20Sopenharmony_ci	ICPGBK2_0	= GENMASK(5, 3),
1578c2ecf20Sopenharmony_ci	DRI_VCO357SC	= BIT(2),
1588c2ecf20Sopenharmony_ci	PDPLL2		= BIT(1),
1598c2ecf20Sopenharmony_ci	DRI_PD_SER	= BIT(0),
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci/* Page 1, Register 0x6c */
1638c2ecf20Sopenharmony_cienum {
1648c2ecf20Sopenharmony_ci	PLL2N11		= GENMASK(7, 4),
1658c2ecf20Sopenharmony_ci	PLL2N5_4	= BIT(3),
1668c2ecf20Sopenharmony_ci	PLL2N5_TOP	= BIT(2),
1678c2ecf20Sopenharmony_ci	DRI_PLL_PD	= BIT(1),
1688c2ecf20Sopenharmony_ci	PD_I2CM		= BIT(0),
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/* Page 3, Register 0x28 */
1728c2ecf20Sopenharmony_cienum {
1738c2ecf20Sopenharmony_ci	DIFF_EN		= GENMASK(7, 6),
1748c2ecf20Sopenharmony_ci	CORREC_EN	= GENMASK(5, 4),
1758c2ecf20Sopenharmony_ci	VGACLK_BP	= BIT(3),
1768c2ecf20Sopenharmony_ci	HM_LV_SEL	= BIT(2),
1778c2ecf20Sopenharmony_ci	HD_VGA_SEL	= BIT(1),
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/* Page 3, Register 0x2a */
1818c2ecf20Sopenharmony_cienum {
1828c2ecf20Sopenharmony_ci	LVDSCLK_BP	= BIT(7),
1838c2ecf20Sopenharmony_ci	HDTVCLK_BP	= BIT(6),
1848c2ecf20Sopenharmony_ci	HDMICLK_BP	= BIT(5),
1858c2ecf20Sopenharmony_ci	HDTV_BP		= BIT(4),
1868c2ecf20Sopenharmony_ci	HDMI_BP		= BIT(3),
1878c2ecf20Sopenharmony_ci	THRWL		= GENMASK(2, 0),
1888c2ecf20Sopenharmony_ci};
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci/* Page 4, Register 0x52 */
1918c2ecf20Sopenharmony_cienum {
1928c2ecf20Sopenharmony_ci	PGM_ARSTB	= BIT(7),
1938c2ecf20Sopenharmony_ci	MCU_ARSTB	= BIT(6),
1948c2ecf20Sopenharmony_ci	MCU_RETB	= BIT(2),
1958c2ecf20Sopenharmony_ci	RESETIB		= BIT(1),
1968c2ecf20Sopenharmony_ci	RESETDB		= BIT(0),
1978c2ecf20Sopenharmony_ci};
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistruct ch7033_priv {
2008c2ecf20Sopenharmony_ci	struct regmap *regmap;
2018c2ecf20Sopenharmony_ci	struct drm_bridge *next_bridge;
2028c2ecf20Sopenharmony_ci	struct drm_bridge bridge;
2038c2ecf20Sopenharmony_ci	struct drm_connector connector;
2048c2ecf20Sopenharmony_ci};
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci#define conn_to_ch7033_priv(x) \
2078c2ecf20Sopenharmony_ci	container_of(x, struct ch7033_priv, connector)
2088c2ecf20Sopenharmony_ci#define bridge_to_ch7033_priv(x) \
2098c2ecf20Sopenharmony_ci	container_of(x, struct ch7033_priv, bridge)
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic enum drm_connector_status ch7033_connector_detect(
2138c2ecf20Sopenharmony_ci	struct drm_connector *connector, bool force)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return drm_bridge_detect(priv->next_bridge);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs ch7033_connector_funcs = {
2218c2ecf20Sopenharmony_ci	.reset = drm_atomic_helper_connector_reset,
2228c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
2238c2ecf20Sopenharmony_ci	.detect = ch7033_connector_detect,
2248c2ecf20Sopenharmony_ci	.destroy = drm_connector_cleanup,
2258c2ecf20Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
2268c2ecf20Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
2278c2ecf20Sopenharmony_ci};
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int ch7033_connector_get_modes(struct drm_connector *connector)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
2328c2ecf20Sopenharmony_ci	struct edid *edid;
2338c2ecf20Sopenharmony_ci	int ret;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	edid = drm_bridge_get_edid(priv->next_bridge, connector);
2368c2ecf20Sopenharmony_ci	drm_connector_update_edid_property(connector, edid);
2378c2ecf20Sopenharmony_ci	if (edid) {
2388c2ecf20Sopenharmony_ci		ret = drm_add_edid_modes(connector, edid);
2398c2ecf20Sopenharmony_ci		kfree(edid);
2408c2ecf20Sopenharmony_ci	} else {
2418c2ecf20Sopenharmony_ci		ret = drm_add_modes_noedid(connector, 1920, 1080);
2428c2ecf20Sopenharmony_ci		drm_set_preferred_mode(connector, 1024, 768);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return ret;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic struct drm_encoder *ch7033_connector_best_encoder(
2498c2ecf20Sopenharmony_ci			struct drm_connector *connector)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return priv->bridge.encoder;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs ch7033_connector_helper_funcs = {
2578c2ecf20Sopenharmony_ci	.get_modes = ch7033_connector_get_modes,
2588c2ecf20Sopenharmony_ci	.best_encoder = ch7033_connector_best_encoder,
2598c2ecf20Sopenharmony_ci};
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic void ch7033_hpd_event(void *arg, enum drm_connector_status status)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = arg;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (priv->bridge.dev)
2668c2ecf20Sopenharmony_ci		drm_helper_hpd_irq_event(priv->connector.dev);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic int ch7033_bridge_attach(struct drm_bridge *bridge,
2708c2ecf20Sopenharmony_ci				enum drm_bridge_attach_flags flags)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
2738c2ecf20Sopenharmony_ci	struct drm_connector *connector = &priv->connector;
2748c2ecf20Sopenharmony_ci	int ret;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	ret = drm_bridge_attach(bridge->encoder, priv->next_bridge, bridge,
2778c2ecf20Sopenharmony_ci				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
2788c2ecf20Sopenharmony_ci	if (ret)
2798c2ecf20Sopenharmony_ci		return ret;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
2828c2ecf20Sopenharmony_ci		return 0;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (priv->next_bridge->ops & DRM_BRIDGE_OP_DETECT) {
2858c2ecf20Sopenharmony_ci		connector->polled = DRM_CONNECTOR_POLL_HPD;
2868c2ecf20Sopenharmony_ci	} else {
2878c2ecf20Sopenharmony_ci		connector->polled = DRM_CONNECTOR_POLL_CONNECT |
2888c2ecf20Sopenharmony_ci				    DRM_CONNECTOR_POLL_DISCONNECT;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD) {
2928c2ecf20Sopenharmony_ci		drm_bridge_hpd_enable(priv->next_bridge, ch7033_hpd_event,
2938c2ecf20Sopenharmony_ci				      priv);
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	drm_connector_helper_add(connector,
2978c2ecf20Sopenharmony_ci				 &ch7033_connector_helper_funcs);
2988c2ecf20Sopenharmony_ci	ret = drm_connector_init_with_ddc(bridge->dev, &priv->connector,
2998c2ecf20Sopenharmony_ci					  &ch7033_connector_funcs,
3008c2ecf20Sopenharmony_ci					  priv->next_bridge->type,
3018c2ecf20Sopenharmony_ci					  priv->next_bridge->ddc);
3028c2ecf20Sopenharmony_ci	if (ret) {
3038c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to initialize connector\n");
3048c2ecf20Sopenharmony_ci		return ret;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return drm_connector_attach_encoder(&priv->connector, bridge->encoder);
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic void ch7033_bridge_detach(struct drm_bridge *bridge)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD)
3158c2ecf20Sopenharmony_ci		drm_bridge_hpd_disable(priv->next_bridge);
3168c2ecf20Sopenharmony_ci	drm_connector_cleanup(&priv->connector);
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge,
3208c2ecf20Sopenharmony_ci				     const struct drm_display_info *info,
3218c2ecf20Sopenharmony_ci				     const struct drm_display_mode *mode)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	if (mode->clock > 165000)
3248c2ecf20Sopenharmony_ci		return MODE_CLOCK_HIGH;
3258c2ecf20Sopenharmony_ci	if (mode->hdisplay >= 1920)
3268c2ecf20Sopenharmony_ci		return MODE_BAD_HVALUE;
3278c2ecf20Sopenharmony_ci	if (mode->vdisplay >= 1080)
3288c2ecf20Sopenharmony_ci		return MODE_BAD_VVALUE;
3298c2ecf20Sopenharmony_ci	return MODE_OK;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic void ch7033_bridge_disable(struct drm_bridge *bridge)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x03, 0x04);
3378c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x52, RESETDB, 0x00);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic void ch7033_bridge_enable(struct drm_bridge *bridge)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x03, 0x04);
3458c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x52, RESETDB, RESETDB);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic void ch7033_bridge_mode_set(struct drm_bridge *bridge,
3498c2ecf20Sopenharmony_ci				   const struct drm_display_mode *mode,
3508c2ecf20Sopenharmony_ci				   const struct drm_display_mode *adjusted_mode)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
3538c2ecf20Sopenharmony_ci	int hbporch = mode->hsync_start - mode->hdisplay;
3548c2ecf20Sopenharmony_ci	int hsynclen = mode->hsync_end - mode->hsync_start;
3558c2ecf20Sopenharmony_ci	int vbporch = mode->vsync_start - mode->vdisplay;
3568c2ecf20Sopenharmony_ci	int vsynclen = mode->vsync_end - mode->vsync_start;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/*
3598c2ecf20Sopenharmony_ci	 * Page 4
3608c2ecf20Sopenharmony_ci	 */
3618c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x03, 0x04);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* Turn everything off to set all the registers to their defaults. */
3648c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x52, 0x00);
3658c2ecf20Sopenharmony_ci	/* Bring I/O block up. */
3668c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x52, RESETIB);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/*
3698c2ecf20Sopenharmony_ci	 * Page 0
3708c2ecf20Sopenharmony_ci	 */
3718c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x03, 0x00);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* Bring up parts we need from the power down. */
3748c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x07, DRI_PD | IO_PD, 0);
3758c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x08, DRI_PDDRI | PDDAC | PANEN, 0);
3768c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x09, DPD | GCKOFF |
3778c2ecf20Sopenharmony_ci					       HDMI_PD | VGA_PD, 0);
3788c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x0a, HD_DVIB, 0);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/* Horizontal input timing. */
3818c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x0b, (mode->htotal >> 8) << 3 |
3828c2ecf20Sopenharmony_ci					 (mode->hdisplay >> 8));
3838c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x0c, mode->hdisplay);
3848c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x0d, mode->htotal);
3858c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x0e, (hsynclen >> 8) << 3 |
3868c2ecf20Sopenharmony_ci					 (hbporch >> 8));
3878c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x0f, hbporch);
3888c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x10, hsynclen);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	/* Vertical input timing. */
3918c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x11, (mode->vtotal >> 8) << 3 |
3928c2ecf20Sopenharmony_ci					 (mode->vdisplay >> 8));
3938c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x12, mode->vdisplay);
3948c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x13, mode->vtotal);
3958c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x14, ((vsynclen >> 8) << 3) |
3968c2ecf20Sopenharmony_ci					 (vbporch >> 8));
3978c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x15, vbporch);
3988c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x16, vsynclen);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	/* Input color swap. */
4018c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* Input clock and sync polarity. */
4048c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x19, 0x1, mode->clock >> 16);
4058c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x19, HPO_I | VPO_I | GCLKFREQ,
4068c2ecf20Sopenharmony_ci			   (mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_I : 0 |
4078c2ecf20Sopenharmony_ci			   (mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_I : 0 |
4088c2ecf20Sopenharmony_ci			   mode->clock >> 16);
4098c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x1a, mode->clock >> 8);
4108c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x1b, mode->clock);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* Horizontal output timing. */
4138c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x1f, (mode->htotal >> 8) << 3 |
4148c2ecf20Sopenharmony_ci					 (mode->hdisplay >> 8));
4158c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x20, mode->hdisplay);
4168c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x21, mode->htotal);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* Vertical output timing. */
4198c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x25, (mode->vtotal >> 8) << 3 |
4208c2ecf20Sopenharmony_ci					 (mode->vdisplay >> 8));
4218c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x26, mode->vdisplay);
4228c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x27, mode->vtotal);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* VGA channel bypass */
4258c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x2b, VFMT, 9);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/* Output sync polarity. */
4288c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x2e, HPO_O | VPO_O,
4298c2ecf20Sopenharmony_ci			   (mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_O : 0 |
4308c2ecf20Sopenharmony_ci			   (mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_O : 0);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/* HDMI horizontal output timing. */
4338c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x54, HWO_HDMI_HI | HOO_HDMI_HI,
4348c2ecf20Sopenharmony_ci					       (hsynclen >> 8) << 3 |
4358c2ecf20Sopenharmony_ci					       (hbporch >> 8));
4368c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x55, hbporch);
4378c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x56, hsynclen);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* HDMI vertical output timing. */
4408c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x57, VWO_HDMI_HI | VOO_HDMI_HI,
4418c2ecf20Sopenharmony_ci					       (vsynclen >> 8) << 3 |
4428c2ecf20Sopenharmony_ci					       (vbporch >> 8));
4438c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x58, vbporch);
4448c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x59, vsynclen);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/* Pick HDMI, not LVDS. */
4478c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x7e, HDMI_LVDS_SEL, HDMI_LVDS_SEL);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/*
4508c2ecf20Sopenharmony_ci	 * Page 1
4518c2ecf20Sopenharmony_ci	 */
4528c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x03, 0x01);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* No idea what these do, but VGA is wobbly and blinky without them. */
4558c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x07, CKINV, CKINV);
4568c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x08, DISPON, DISPON);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/* DRI PLL */
4598c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_DIVSEL, DRI_PLL_DIVSEL);
4608c2ecf20Sopenharmony_ci	if (mode->clock <= 40000) {
4618c2ecf20Sopenharmony_ci		regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
4628c2ecf20Sopenharmony_ci						       DRI_PLL_N1_0 |
4638c2ecf20Sopenharmony_ci						       DRI_PLL_N3_1 |
4648c2ecf20Sopenharmony_ci						       DRI_PLL_N3_0,
4658c2ecf20Sopenharmony_ci						       0);
4668c2ecf20Sopenharmony_ci	} else if (mode->clock < 80000) {
4678c2ecf20Sopenharmony_ci		regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
4688c2ecf20Sopenharmony_ci						       DRI_PLL_N1_0 |
4698c2ecf20Sopenharmony_ci						       DRI_PLL_N3_1 |
4708c2ecf20Sopenharmony_ci						       DRI_PLL_N3_0,
4718c2ecf20Sopenharmony_ci						       DRI_PLL_N3_0 |
4728c2ecf20Sopenharmony_ci						       DRI_PLL_N1_0);
4738c2ecf20Sopenharmony_ci	} else {
4748c2ecf20Sopenharmony_ci		regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
4758c2ecf20Sopenharmony_ci						       DRI_PLL_N1_0 |
4768c2ecf20Sopenharmony_ci						       DRI_PLL_N3_1 |
4778c2ecf20Sopenharmony_ci						       DRI_PLL_N3_0,
4788c2ecf20Sopenharmony_ci						       DRI_PLL_N3_1 |
4798c2ecf20Sopenharmony_ci						       DRI_PLL_N1_1);
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	/* This seems to be color calibration for VGA. */
4838c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x64, 0x29); /* LSB Blue */
4848c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x65, 0x29); /* LSB Green */
4858c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x66, 0x29); /* LSB Red */
4868c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x67, 0x00); /* MSB Blue */
4878c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x68, 0x00); /* MSB Green */
4888c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x69, 0x00); /* MSB Red */
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x6b, DRI_PD_SER, 0x00);
4918c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x6c, DRI_PLL_PD, 0x00);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	/*
4948c2ecf20Sopenharmony_ci	 * Page 3
4958c2ecf20Sopenharmony_ci	 */
4968c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x03, 0x03);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	/* More bypasses and apparently another HDMI/LVDS selector. */
4998c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x28, VGACLK_BP | HM_LV_SEL,
5008c2ecf20Sopenharmony_ci					       VGACLK_BP | HM_LV_SEL);
5018c2ecf20Sopenharmony_ci	regmap_update_bits(priv->regmap, 0x2a, HDMICLK_BP | HDMI_BP,
5028c2ecf20Sopenharmony_ci					       HDMICLK_BP | HDMI_BP);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	/*
5058c2ecf20Sopenharmony_ci	 * Page 4
5068c2ecf20Sopenharmony_ci	 */
5078c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x03, 0x04);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	/* Output clock. */
5108c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x10, mode->clock >> 16);
5118c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x11, mode->clock >> 8);
5128c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x12, mode->clock);
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs ch7033_bridge_funcs = {
5168c2ecf20Sopenharmony_ci	.attach = ch7033_bridge_attach,
5178c2ecf20Sopenharmony_ci	.detach = ch7033_bridge_detach,
5188c2ecf20Sopenharmony_ci	.mode_valid = ch7033_bridge_mode_valid,
5198c2ecf20Sopenharmony_ci	.disable = ch7033_bridge_disable,
5208c2ecf20Sopenharmony_ci	.enable = ch7033_bridge_enable,
5218c2ecf20Sopenharmony_ci	.mode_set = ch7033_bridge_mode_set,
5228c2ecf20Sopenharmony_ci};
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic const struct regmap_config ch7033_regmap_config = {
5258c2ecf20Sopenharmony_ci	.reg_bits = 8,
5268c2ecf20Sopenharmony_ci	.val_bits = 8,
5278c2ecf20Sopenharmony_ci	.max_register = 0x7f,
5288c2ecf20Sopenharmony_ci};
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic int ch7033_probe(struct i2c_client *client,
5318c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
5348c2ecf20Sopenharmony_ci	struct ch7033_priv *priv;
5358c2ecf20Sopenharmony_ci	unsigned int val;
5368c2ecf20Sopenharmony_ci	int ret;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5398c2ecf20Sopenharmony_ci	if (!priv)
5408c2ecf20Sopenharmony_ci		return -ENOMEM;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, priv);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,
5458c2ecf20Sopenharmony_ci					  &priv->next_bridge);
5468c2ecf20Sopenharmony_ci	if (ret)
5478c2ecf20Sopenharmony_ci		return ret;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	priv->regmap = devm_regmap_init_i2c(client, &ch7033_regmap_config);
5508c2ecf20Sopenharmony_ci	if (IS_ERR(priv->regmap)) {
5518c2ecf20Sopenharmony_ci		dev_err(&client->dev, "regmap init failed\n");
5528c2ecf20Sopenharmony_ci		return PTR_ERR(priv->regmap);
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	ret = regmap_read(priv->regmap, 0x00, &val);
5568c2ecf20Sopenharmony_ci	if (ret < 0) {
5578c2ecf20Sopenharmony_ci		dev_err(&client->dev, "error reading the model id: %d\n", ret);
5588c2ecf20Sopenharmony_ci		return ret;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci	if ((val & 0xf7) != 0x56) {
5618c2ecf20Sopenharmony_ci		dev_err(&client->dev, "the device is not a ch7033\n");
5628c2ecf20Sopenharmony_ci		return -ENODEV;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	regmap_write(priv->regmap, 0x03, 0x04);
5668c2ecf20Sopenharmony_ci	ret = regmap_read(priv->regmap, 0x51, &val);
5678c2ecf20Sopenharmony_ci	if (ret < 0) {
5688c2ecf20Sopenharmony_ci		dev_err(&client->dev, "error reading the model id: %d\n", ret);
5698c2ecf20Sopenharmony_ci		return ret;
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci	if ((val & 0x0f) != 3) {
5728c2ecf20Sopenharmony_ci		dev_err(&client->dev, "unknown revision %u\n", val);
5738c2ecf20Sopenharmony_ci		return -ENODEV;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&priv->bridge.list);
5778c2ecf20Sopenharmony_ci	priv->bridge.funcs = &ch7033_bridge_funcs;
5788c2ecf20Sopenharmony_ci	priv->bridge.of_node = dev->of_node;
5798c2ecf20Sopenharmony_ci	drm_bridge_add(&priv->bridge);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	dev_info(dev, "Chrontel CH7033 Video Encoder\n");
5828c2ecf20Sopenharmony_ci	return 0;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic int ch7033_remove(struct i2c_client *client)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
5888c2ecf20Sopenharmony_ci	struct ch7033_priv *priv = dev_get_drvdata(dev);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	drm_bridge_remove(&priv->bridge);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	return 0;
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic const struct of_device_id ch7033_dt_ids[] = {
5968c2ecf20Sopenharmony_ci	{ .compatible = "chrontel,ch7033", },
5978c2ecf20Sopenharmony_ci	{ }
5988c2ecf20Sopenharmony_ci};
5998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ch7033_dt_ids);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic const struct i2c_device_id ch7033_ids[] = {
6028c2ecf20Sopenharmony_ci	{ "ch7033", 0 },
6038c2ecf20Sopenharmony_ci	{ }
6048c2ecf20Sopenharmony_ci};
6058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ch7033_ids);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic struct i2c_driver ch7033_driver = {
6088c2ecf20Sopenharmony_ci	.probe = ch7033_probe,
6098c2ecf20Sopenharmony_ci	.remove = ch7033_remove,
6108c2ecf20Sopenharmony_ci	.driver = {
6118c2ecf20Sopenharmony_ci		.name = "ch7033",
6128c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(ch7033_dt_ids),
6138c2ecf20Sopenharmony_ci	},
6148c2ecf20Sopenharmony_ci	.id_table = ch7033_ids,
6158c2ecf20Sopenharmony_ci};
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_cimodule_i2c_driver(ch7033_driver);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
6208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Chrontel CH7033 Video Encoder Driver");
6218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
622