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 #ifdef CONFIG_STARFIVE_DSI
200 struct drm_panel *tmp_panel;
203 encoder = &simple->encoder;
206 dev_info(dev,"encoder_bind begin\n");
208 ret = drm_encoder_init(drm_dev, encoder, &encoder_funcs,
209 simple->priv->encoder_type, NULL);
213 drm_encoder_helper_add(encoder, &encoder_helper_funcs);
215 encoder->possible_crtcs =
216 drm_of_find_possible_crtcs(drm_dev, dev->of_node);
217 encoder->possible_crtcs = 2;
219 /* output port is port1*/
221 #ifdef CONFIG_STARFIVE_DSI
222 ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0,&tmp_panel, &bridge);
224 printk("==no panel, %d\n",ret);
225 //dev_err_probe(dev, ret, "endpoint returns %d\n", ret);
229 dev_err(dev, "found panel on endpoint\n");
231 ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL, &bridge);
235 #if KERNEL_VERSION(5, 7, 0) <= LINUX_VERSION_CODE
236 ret = drm_bridge_attach(encoder, bridge, NULL, 0);
238 ret = drm_bridge_attach(encoder, bridge, NULL);
243 dev_info(dev,"encoder_bind end\n");
246 drm_encoder_cleanup(encoder);
247 dev_info(dev,"encoder_bind error\n");
253 static void encoder_unbind(struct device *dev, struct device *master,
256 struct simple_encoder *simple = dev_get_drvdata(dev);
258 drm_encoder_cleanup(&simple->encoder);
261 static const struct component_ops encoder_component_ops = {
262 .bind = encoder_bind,
263 .unbind = encoder_unbind,
266 static const struct of_device_id simple_encoder_dt_match[] = {
267 { .compatible = "verisilicon,rgb-encoder", .data = &hdmi_priv},
268 { .compatible = "verisilicon,dp-encoder", .data = &hdmi_priv},
269 { .compatible = "verisilicon,dsi-encoder", .data = &dsi_priv},
272 MODULE_DEVICE_TABLE(of, simple_encoder_dt_match);
274 static int encoder_probe(struct platform_device *pdev)
276 struct device *dev = &pdev->dev;
277 struct simple_encoder *simple;
279 simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
283 simple->priv = of_device_get_match_data(dev);
287 dev_set_drvdata(dev, simple);
289 ret = encoder_parse_dt(dev);
293 return component_add(dev, &encoder_component_ops);
296 static int encoder_remove(struct platform_device *pdev)
298 struct device *dev = &pdev->dev;
300 component_del(dev, &encoder_component_ops);
302 dev_set_drvdata(dev, NULL);
307 struct platform_driver simple_encoder_driver = {
308 .probe = encoder_probe,
309 .remove = encoder_remove,
311 .name = "vs-simple-encoder",
312 .of_match_table = of_match_ptr(simple_encoder_dt_match),
316 MODULE_DESCRIPTION("Simple Encoder Driver");
317 MODULE_LICENSE("GPL v2");