1 /*
2 * Copyright (C) 2019 Allwinnertech Co.Ltd
3 * Authors: zhengwanyu
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 */
11 #include <drm/drm_fb_helper.h>
12 #include <drm/drm_plane_helper.h>
13 #include <drm/drm_crtc_helper.h>
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_sysfs.h>
16 #include <drm/drm_print.h>
17 #include <video/sunxi_display2.h>
18
19 #include "drm_internal.h"
20 #include "sunxi_drm_drv.h"
21 #include "sunxi_drm_encoder.h"
22 #include "sunxi_drm_connector.h"
23
24 #include "de/include.h"
25
26 #ifdef CONFIG_AW_DRM_TV
27 #include "sunxi_device/sunxi_tv.h"
28 #endif
29
30 static unsigned int sunxi_conector_cnt;
31 static struct sunxi_drm_connector *sunxi_con[MAX_CONNECTOR_COUNT];
32
sunxi_drm_connector_get_count(void)33 unsigned int sunxi_drm_connector_get_count(void)
34 {
35 return sunxi_conector_cnt;
36 }
37
sunxi_drm_connector_get_connector(int id)38 struct sunxi_drm_connector *sunxi_drm_connector_get_connector(int id)
39 {
40 if (id >= sunxi_conector_cnt) {
41 DRM_ERROR("wrong connector id, out of range\n");
42 return NULL;
43 }
44
45 return sunxi_con[id];
46 }
47
48 void
sunxi_drm_connector_set_connector(int id,struct sunxi_drm_connector * conn)49 sunxi_drm_connector_set_connector(int id, struct sunxi_drm_connector *conn)
50 {
51 if (id >= sunxi_conector_cnt) {
52 DRM_ERROR("wrong connector id, out of range\n");
53 return;
54 }
55
56 sunxi_con[id] = conn;
57 }
58
sunxi_drm_connector_state(char * buf,struct drm_connector_state * state)59 static ssize_t sunxi_drm_connector_state(char *buf, struct drm_connector_state *state)
60 {
61 ssize_t n = 0;
62
63 n += sprintf(n + buf, "[connector_state]:\n");
64
65 if (state->crtc)
66 n += sprintf(n + buf, "attaching crtc index:%d\n", state->crtc->index);
67
68 if (state->best_encoder)
69 n += sprintf(n + buf, "attaching best encoder index:%d\n", state->best_encoder->index);
70
71 return n;
72 }
73
74 /*ssize_t sunxi_drm_connector_show(char *buf, struct drm_device *dev)
75 {
76 int ret;
77 ssize_t n = 0;
78 struct drm_connector *connector;
79 struct sunxi_drm_connector *sconn;
80
81 mutex_lock(&dev->mode_config.mutex);
82 ret = drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
83 if (ret)
84 return n;
85
86 drm_for_each_connector(connector, dev) {
87 sconn = to_sunxi_connector(connector);
88 n += sprintf(n + buf, "connector id:%d\n", connector->index);
89 if (sconn->type == DISP_OUTPUT_TYPE_LCD)
90 n += sprintf(n + buf, "LCD%d\n", sconn->type_id);
91 else if (sconn->type == DISP_OUTPUT_TYPE_HDMI)
92 n += sprintf(n + buf, "HDMI%d\n", sconn->type_id);
93 else if (sconn->type == DISP_OUTPUT_TYPE_TV)
94 n += sprintf(n + buf, "TV%d\n", sconn->type_id);
95 else
96 n += sprintf(n + buf, "Unknow connector type!\n");
97
98 n += sprintf(n + buf, "name:%s\n", connector->name);
99 n += sprintf(n + buf, "allow interlace:%d double_scan:%d stereo:%d\n",
100 connector->interlace_allowed, connector->doublescan_allowed,
101 connector->stereo_allowed);
102 n += sprintf(n + buf, "register:%d\n", connector->registered);
103 n += sprintf(n + buf, "status:%d polled:%d\n",
104 connector->status, connector->polled);
105 n += sprintf(n + buf, "dpms:%s\n", connector->dpms ? "off" : "on");
106 n += sprintf(n + buf, "possible encoder id:%d %d %d\n",
107 connector->encoder_ids[0], connector->encoder_ids[1],
108 connector->encoder_ids[2]);
109 if (connector->encoder)
110 n += sprintf(n + buf, "attached encoder:%d\n", connector->encoder->index);
111 else
112 n += sprintf(n + buf, "No attached encoder\n");
113
114 n += sunxi_drm_connector_state(buf + n, connector->state);
115 n += sprintf(n + buf, "\n");
116 }
117
118 drm_modeset_unlock(&dev->mode_config.connection_mutex);
119 mutex_unlock(&dev->mode_config.mutex);
120
121 return n;
122 }*/
123
124 struct drm_encoder *
sunxi_connector_best_encoder(struct drm_connector * connector)125 sunxi_connector_best_encoder(struct drm_connector *connector)
126 {
127 #if 0
128 struct drm_device *dev = connector->dev;
129 struct drm_mode_object *obj;
130 struct drm_encoder *encoder = NULL, *best_encoder = NULL;
131 struct sunxi_drm_encoder *sencoder;
132 int i;
133
134 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
135 if (connector->encoder_ids[i] != 0) {
136 /*check if it has drm_mode_object*/
137 obj = drm_mode_object_find(dev,
138 NULL,
139 connector->encoder_ids[i],
140 DRM_MODE_OBJECT_ENCODER);
141 if (!obj) {
142 DRM_ERROR("Unknown ENCODER ID %d\n",
143 connector->encoder_ids[i]);
144 continue;
145 }
146
147 encoder = obj_to_encoder(obj);
148 sencoder = to_sunxi_encoder(encoder);
149
150 if (best_encoder == NULL)
151 best_encoder = encoder;
152
153 if (connector->encoder == encoder) {
154 best_encoder = encoder;
155 break;
156 } else {
157 if (!sencoder->is_in_use(sencoder)) {
158 best_encoder = encoder;
159 break;
160 }
161 }
162 }
163 }
164
165 DRM_DEBUG_KMS("GET best encoder id:%d for connector:%d\n",
166 best_encoder->base.id, connector->base.id);
167 return best_encoder;
168 #endif
169 struct drm_encoder *encoder;
170 drm_connector_for_each_possible_encoder(connector, encoder)
171 return encoder;
172
173 return NULL;
174 }
175
sunxi_drm_connector_init(struct drm_device * dev)176 int sunxi_drm_connector_init(struct drm_device *dev)
177 {
178 int i, max_con = 0;
179 struct sunxi_drm_connector *scon = NULL;
180 int sunxi_con_type;
181 #ifdef CONFIG_AW_DRM_LCD
182 int lcd_type_id = 0;
183 #endif
184
185 #ifdef CONFIG_AW_DRM_TV
186 int tv_type_id = 0;
187 #endif
188
189 /* create drm_connectors according boot info,
190 * NOTE: Only surpport single connector display and dual connectors display!!!
191 */
192 max_con = sunxi_drm_get_connector_count();
193 sunxi_conector_cnt = max_con;
194
195 for (i = 0; i < max_con; i++) {
196 sunxi_con_type = sunxi_drm_get_connector_type(i);
197 switch (sunxi_con_type) {
198 /*LCD*/
199 case 1:
200 #ifdef CONFIG_AW_DRM_LCD
201 scon = sunxi_drm_connector_lcd_create(dev,
202 i, lcd_type_id);
203 if (!scon) {
204 DRM_ERROR("create lcd:%d connector failed!\n",
205 lcd_type_id);
206 goto con_err;
207 }
208
209 ++lcd_type_id;
210 #endif
211 break;
212
213 /*TV*/
214 case 2:
215 #ifdef CONFIG_AW_DRM_TV
216 scon = sunxi_drm_connector_tv_create(dev,
217 i, tv_type_id);
218 if (!scon) {
219 DRM_ERROR("create tv:%d connector failed!\n",
220 tv_type_id);
221 goto con_err;
222 }
223
224 ++tv_type_id;
225 #endif
226 break;
227
228 /*HDMI*/
229 case 3:
230 #if defined(CONFIG_AW_DRM_HDMI14) || defined(CONFIG_AW_DRM_HDMI20)
231 scon = sunxi_drm_connector_hdmi_create(dev,
232 i);
233 if (!scon) {
234 DRM_ERROR("create hdmi connector failed!\n");
235 goto con_err;
236 }
237 #endif
238 break;
239
240 default:
241 DRM_ERROR("Unknown connector output type:%d\n", sunxi_con_type);
242 goto con_err;
243 }
244
245 sunxi_con[i] = scon;
246 }
247
248 return 0;
249
250 con_err:
251 DRM_ERROR("sunxi connector init failed\n");
252 return -1;
253 }
254
sunxi_drm_connector_destroy(int conn_id)255 void sunxi_drm_connector_destroy(int conn_id)
256 {
257 struct sunxi_drm_connector *sunxi_conn;
258
259 sunxi_conn = sunxi_drm_connector_get_connector(conn_id);
260 if (!sunxi_conn)
261 return;
262
263 if (sunxi_conn) {
264 drm_connector_cleanup(&sunxi_conn->connector);
265 kfree(sunxi_conn);
266 sunxi_drm_connector_set_connector(conn_id, NULL);
267 }
268 }
269
sunxi_drm_connector_exit(struct drm_device * dev)270 void sunxi_drm_connector_exit(struct drm_device *dev)
271 {
272 int i, max_con;
273
274 max_con = sunxi_drm_connector_get_count();
275
276 for (i = 0; i < max_con; i++)
277 sunxi_drm_connector_destroy(i);
278 }
279
bsp_disp_hdmi_get_color_format(void)280 s32 bsp_disp_hdmi_get_color_format(void)
281 {
282 struct sunxi_drm_connector *sconn;
283 unsigned int i, cnt;
284
285 cnt = sunxi_drm_connector_get_count();
286
287 for (i = 0; i < cnt; i++) {
288 sconn = sunxi_drm_connector_get_connector(i);
289 #if defined(CONFIG_AW_DRM_HDMI14) || defined(CONFIG_AW_DRM_HDMI20)
290 if (sconn->type == DISP_OUTPUT_TYPE_HDMI)
291 return sunxi_drm_connector_hdmi_get_color_format(
292 &sconn->connector);
293 #endif
294 }
295
296 return 0;
297 }
298