1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Hisilicon Hibmc SoC drm driver
3  *
4  * Based on the bochs drm driver.
5  *
6  * Copyright (c) 2016 Huawei Limited.
7  *
8  * Author:
9  *	Rongrong Zou <zourongrong@huawei.com>
10  *	Rongrong Zou <zourongrong@gmail.com>
11  *	Jianhua Li <lijianhua@huawei.com>
12  */
13 
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_probe_helper.h>
16 #include <drm/drm_print.h>
17 
18 #include "hibmc_drm_drv.h"
19 #include "hibmc_drm_regs.h"
20 
21 static int hibmc_connector_get_modes(struct drm_connector *connector)
22 {
23 	int count;
24 	void *edid;
25 	struct hibmc_connector *hibmc_connector = to_hibmc_connector(connector);
26 
27 	edid = drm_get_edid(connector, &hibmc_connector->adapter);
28 	if (edid) {
29 		drm_connector_update_edid_property(connector, edid);
30 		count = drm_add_edid_modes(connector, edid);
31 		if (count)
32 			goto out;
33 	}
34 
35 	count = drm_add_modes_noedid(connector,
36 				     connector->dev->mode_config.max_width,
37 				     connector->dev->mode_config.max_height);
38 	drm_set_preferred_mode(connector, 1024, 768);
39 
40 out:
41 	kfree(edid);
42 	return count;
43 }
44 
45 static enum drm_mode_status hibmc_connector_mode_valid(struct drm_connector *connector,
46 						       struct drm_display_mode *mode)
47 {
48 	return MODE_OK;
49 }
50 
51 static void hibmc_connector_destroy(struct drm_connector *connector)
52 {
53 	struct hibmc_connector *hibmc_connector = to_hibmc_connector(connector);
54 
55 	i2c_del_adapter(&hibmc_connector->adapter);
56 	drm_connector_cleanup(connector);
57 }
58 
59 static const struct drm_connector_helper_funcs
60 	hibmc_connector_helper_funcs = {
61 	.get_modes = hibmc_connector_get_modes,
62 	.mode_valid = hibmc_connector_mode_valid,
63 };
64 
65 static const struct drm_connector_funcs hibmc_connector_funcs = {
66 	.fill_modes = drm_helper_probe_single_connector_modes,
67 	.destroy = hibmc_connector_destroy,
68 	.reset = drm_atomic_helper_connector_reset,
69 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
70 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
71 };
72 
73 static void hibmc_encoder_mode_set(struct drm_encoder *encoder,
74 				   struct drm_display_mode *mode,
75 				   struct drm_display_mode *adj_mode)
76 {
77 	u32 reg;
78 	struct drm_device *dev = encoder->dev;
79 	struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
80 
81 	reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
82 	reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1);
83 	reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1);
84 	reg |= HIBMC_DISPLAY_CONTROL_FPEN(1);
85 	reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1);
86 	writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
87 }
88 
89 static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
90 	.mode_set = hibmc_encoder_mode_set,
91 };
92 
93 static const struct drm_encoder_funcs hibmc_encoder_funcs = {
94 	.destroy = drm_encoder_cleanup,
95 };
96 
97 int hibmc_vdac_init(struct hibmc_drm_private *priv)
98 {
99 	struct drm_device *dev = priv->dev;
100 	struct hibmc_connector *hibmc_connector = &priv->connector;
101 	struct drm_encoder *encoder = &priv->encoder;
102 	struct drm_connector *connector = &hibmc_connector->base;
103 	int ret;
104 
105 	ret = hibmc_ddc_create(dev, hibmc_connector);
106 	if (ret) {
107 		drm_err(dev, "failed to create ddc: %d\n", ret);
108 		return ret;
109 	}
110 
111 	encoder->possible_crtcs = 0x1;
112 	ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs,
113 			       DRM_MODE_ENCODER_DAC, NULL);
114 	if (ret) {
115 		drm_err(dev, "failed to init encoder: %d\n", ret);
116 		return ret;
117 	}
118 
119 	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
120 
121 	ret = drm_connector_init_with_ddc(dev, connector,
122 					  &hibmc_connector_funcs,
123 					  DRM_MODE_CONNECTOR_VGA,
124 					  &hibmc_connector->adapter);
125 	if (ret) {
126 		drm_err(dev, "failed to init connector: %d\n", ret);
127 		return ret;
128 	}
129 
130 	drm_connector_helper_add(connector, &hibmc_connector_helper_funcs);
131 
132 	drm_connector_attach_encoder(connector, encoder);
133 
134 	return 0;
135 }
136