1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
5 #include <linux/version.h>
6 #include <linux/component.h>
7 #include <linux/of_device.h>
8 #if KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE
9 #include <linux/module.h>
11 #include <drm/drm_bridge.h>
16 #include <drm/drm_crtc_helper.h>
17 #include <drm/drm_of.h>
18 #include <linux/regmap.h>
19 #include <linux/mfd/syscon.h>
22 #include "vs_simple_enc.h"
24 static const struct simple_encoder_priv hdmi_priv = {
25 .encoder_type = DRM_MODE_ENCODER_TMDS
28 static const struct simple_encoder_priv dsi_priv = {
29 .encoder_type = DRM_MODE_ENCODER_DSI
32 static const struct drm_encoder_funcs encoder_funcs = {
33 .destroy = drm_encoder_cleanup
36 static inline struct simple_encoder *to_simple_encoder(struct drm_encoder *enc)
38 return container_of(enc, struct simple_encoder, encoder);
42 static int encoder_parse_dt(struct device *dev)
44 struct simple_encoder *simple = dev_get_drvdata(dev);
50 simple->dss_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
51 "verisilicon,dss-syscon");
53 if (IS_ERR(simple->dss_regmap)) {
54 if (PTR_ERR(simple->dss_regmap) != -ENODEV) {
55 dev_err(dev, "failed to get dss-syscon\n");
56 ret = PTR_ERR(simple->dss_regmap);
59 simple->dss_regmap = NULL;
63 cnt = of_property_count_elems_of_size(dev->of_node,
64 "verisilicon,mux-mask", 4);
70 simple->dss_regdatas = devm_kzalloc(dev,
71 sizeof(*simple->dss_regdatas) * cnt, GFP_KERNEL);
73 masks = kcalloc(cnt, sizeof(*masks), GFP_KERNEL);
79 vals = kcalloc(cnt, sizeof(*vals), GFP_KERNEL);
85 ret = of_property_read_u32_array(
86 dev->of_node, "verisilicon,mux-mask", masks, cnt);
90 ret = of_property_read_u32_array(
91 dev->of_node, "verisilicon,mux-val", vals, cnt);
95 for (i = 0; i < cnt; i++) {
96 simple->dss_regdatas[i].mask = masks[i];
97 simple->dss_regdatas[i].value = vals[i];
109 #define DOM_VOUT_SYSCON_8 0x8U
110 #define U0_LCD_DATA_MAPPING_DPI_DP_SEL_SHIFT 0x2U
111 #define U0_LCD_DATA_MAPPING_DPI_DP_SEL_MASK 0x4U
113 #define DOM_VOUT_SYSCON_4 0x4U
114 #define U0_DISPLAY_PANEL_MUX_PANEL_SEL_SHIFT 0x14U
115 #define U0_DISPLAY_PANEL_MUX_PANEL_SEL_MASK 0x100000U
117 void encoder_atomic_enable(struct drm_encoder *encoder,
118 struct drm_atomic_state *state)
123 int encoder_atomic_check(struct drm_encoder *encoder,
124 struct drm_crtc_state *crtc_state,
125 struct drm_connector_state *conn_state)
127 struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc_state);
128 struct drm_connector *connector = conn_state->connector;
130 #if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
131 struct drm_bridge *first_bridge = drm_bridge_chain_get_first_bridge(encoder);
132 struct drm_bridge_state *bridge_state = ERR_PTR(-EINVAL);
135 vs_crtc_state->encoder_type = encoder->encoder_type;
137 #if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
138 if (first_bridge && first_bridge->funcs->atomic_duplicate_state)
139 bridge_state = drm_atomic_get_bridge_state(
140 crtc_state->state, first_bridge);
142 if (IS_ERR(bridge_state)) {
143 if (connector->display_info.num_bus_formats)
144 vs_crtc_state->output_fmt = connector->display_info.bus_formats[0];
146 vs_crtc_state->output_fmt = MEDIA_BUS_FMT_FIXED;
148 vs_crtc_state->output_fmt = bridge_state->input_bus_cfg.format;
151 if (connector->display_info.num_bus_formats)
152 vs_crtc_state->output_fmt = connector->display_info.bus_formats[0];
154 vs_crtc_state->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
157 switch (vs_crtc_state->output_fmt) {
158 case MEDIA_BUS_FMT_FIXED:
159 case MEDIA_BUS_FMT_RGB565_1X16:
160 case MEDIA_BUS_FMT_RGB666_1X18:
161 case MEDIA_BUS_FMT_RGB888_1X24:
162 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
163 case MEDIA_BUS_FMT_RGB101010_1X30:
164 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
165 case MEDIA_BUS_FMT_UYVY8_1X16:
166 case MEDIA_BUS_FMT_YUV8_1X24:
167 case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
168 case MEDIA_BUS_FMT_UYVY10_1X20:
169 case MEDIA_BUS_FMT_YUV10_1X30:
177 /* If MEDIA_BUS_FMT_FIXED, set it to default value */
178 if (vs_crtc_state->output_fmt == MEDIA_BUS_FMT_FIXED)
179 vs_crtc_state->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
184 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
185 .atomic_enable = encoder_atomic_enable,
186 .atomic_check = encoder_atomic_check,
189 static int encoder_bind(struct device *dev, struct device *master, void *data)
192 struct drm_device *drm_dev = data;
193 struct simple_encoder *simple = dev_get_drvdata(dev);
194 struct drm_encoder *encoder;
195 struct drm_bridge *bridge;
199 encoder = &simple->encoder;
203 ret = drm_encoder_init(drm_dev, encoder, &encoder_funcs,
204 simple->priv->encoder_type, NULL);
208 drm_encoder_helper_add(encoder, &encoder_helper_funcs);
210 encoder->possible_crtcs =
211 drm_of_find_possible_crtcs(drm_dev, dev->of_node);
212 encoder->possible_crtcs = 3;
214 /* output port is port1*/
216 #ifdef CONFIG_STARFIVE_DSI
217 struct drm_panel *tmp_panel;
219 ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0,&tmp_panel, &bridge);
221 printk("==no panel, %d\n",ret);
222 //dev_err_probe(dev, ret, "endpoint returns %d\n", ret);
226 dev_err(dev, "found panel on endpoint\n");
228 ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL, &bridge);
232 #if KERNEL_VERSION(5, 7, 0) <= LINUX_VERSION_CODE
233 ret = drm_bridge_attach(encoder, bridge, NULL, 0);
235 ret = drm_bridge_attach(encoder, bridge, NULL);
242 drm_encoder_cleanup(encoder);
247 static void encoder_unbind(struct device *dev, struct device *master,
250 struct simple_encoder *simple = dev_get_drvdata(dev);
252 drm_encoder_cleanup(&simple->encoder);
255 static const struct component_ops encoder_component_ops = {
256 .bind = encoder_bind,
257 .unbind = encoder_unbind,
260 static const struct of_device_id simple_encoder_dt_match[] = {
261 { .compatible = "verisilicon,hdmi-encoder", .data = &hdmi_priv},
262 { .compatible = "verisilicon,dp-encoder", .data = &hdmi_priv},
263 { .compatible = "verisilicon,dsi-encoder", .data = &dsi_priv},
266 MODULE_DEVICE_TABLE(of, simple_encoder_dt_match);
268 static int encoder_probe(struct platform_device *pdev)
270 struct device *dev = &pdev->dev;
271 struct simple_encoder *simple;
273 simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
277 simple->priv = of_device_get_match_data(dev);
281 dev_set_drvdata(dev, simple);
283 ret = encoder_parse_dt(dev);
287 return component_add(dev, &encoder_component_ops);
290 static int encoder_remove(struct platform_device *pdev)
292 struct device *dev = &pdev->dev;
294 component_del(dev, &encoder_component_ops);
296 dev_set_drvdata(dev, NULL);
301 struct platform_driver simple_encoder_driver = {
302 .probe = encoder_probe,
303 .remove = encoder_remove,
305 .name = "vs-simple-encoder",
306 .of_match_table = of_match_ptr(simple_encoder_dt_match),
310 MODULE_DESCRIPTION("Simple Encoder Driver");
311 MODULE_LICENSE("GPL v2");