• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Red Hat
3  * Author: Rob Clark <robdclark@gmail.com>
4  * Author: Vinay Simha <vinaysimha@inforcecomputing.com>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by
8  * the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <linux/gpio.h>
20 
21 #include "mdp4_kms.h"
22 
23 struct mdp4_lvds_connector {
24 	struct drm_connector base;
25 	struct drm_encoder *encoder;
26 	struct drm_panel *panel;
27 };
28 #define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
29 
mdp4_lvds_connector_detect(struct drm_connector * connector,bool force)30 static enum drm_connector_status mdp4_lvds_connector_detect(
31 		struct drm_connector *connector, bool force)
32 {
33 	struct mdp4_lvds_connector *mdp4_lvds_connector =
34 			to_mdp4_lvds_connector(connector);
35 
36 	return mdp4_lvds_connector->panel ?
37 			connector_status_connected :
38 			connector_status_disconnected;
39 }
40 
mdp4_lvds_connector_destroy(struct drm_connector * connector)41 static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
42 {
43 	struct mdp4_lvds_connector *mdp4_lvds_connector =
44 			to_mdp4_lvds_connector(connector);
45 	struct drm_panel *panel = mdp4_lvds_connector->panel;
46 
47 	if (panel)
48 		drm_panel_detach(panel);
49 
50 	drm_connector_unregister(connector);
51 	drm_connector_cleanup(connector);
52 
53 	kfree(mdp4_lvds_connector);
54 }
55 
mdp4_lvds_connector_get_modes(struct drm_connector * connector)56 static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
57 {
58 	struct mdp4_lvds_connector *mdp4_lvds_connector =
59 			to_mdp4_lvds_connector(connector);
60 	struct drm_panel *panel = mdp4_lvds_connector->panel;
61 	int ret = 0;
62 
63 	if (panel)
64 		ret = panel->funcs->get_modes(panel);
65 
66 	return ret;
67 }
68 
mdp4_lvds_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)69 static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
70 				 struct drm_display_mode *mode)
71 {
72 	struct mdp4_lvds_connector *mdp4_lvds_connector =
73 			to_mdp4_lvds_connector(connector);
74 	struct drm_encoder *encoder = mdp4_lvds_connector->encoder;
75 	long actual, requested;
76 
77 	requested = 1000 * mode->clock;
78 	actual = mdp4_lcdc_round_pixclk(encoder, requested);
79 
80 	DBG("requested=%ld, actual=%ld", requested, actual);
81 
82 	if (actual != requested)
83 		return MODE_CLOCK_RANGE;
84 
85 	return MODE_OK;
86 }
87 
88 static struct drm_encoder *
mdp4_lvds_connector_best_encoder(struct drm_connector * connector)89 mdp4_lvds_connector_best_encoder(struct drm_connector *connector)
90 {
91 	struct mdp4_lvds_connector *mdp4_lvds_connector =
92 			to_mdp4_lvds_connector(connector);
93 	return mdp4_lvds_connector->encoder;
94 }
95 
96 static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
97 	.dpms = drm_helper_connector_dpms,
98 	.detect = mdp4_lvds_connector_detect,
99 	.fill_modes = drm_helper_probe_single_connector_modes,
100 	.destroy = mdp4_lvds_connector_destroy,
101 };
102 
103 static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs = {
104 	.get_modes = mdp4_lvds_connector_get_modes,
105 	.mode_valid = mdp4_lvds_connector_mode_valid,
106 	.best_encoder = mdp4_lvds_connector_best_encoder,
107 };
108 
109 /* initialize connector */
mdp4_lvds_connector_init(struct drm_device * dev,struct drm_panel * panel,struct drm_encoder * encoder)110 struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
111 		struct drm_panel *panel, struct drm_encoder *encoder)
112 {
113 	struct drm_connector *connector = NULL;
114 	struct mdp4_lvds_connector *mdp4_lvds_connector;
115 	int ret;
116 
117 	mdp4_lvds_connector = kzalloc(sizeof(*mdp4_lvds_connector), GFP_KERNEL);
118 	if (!mdp4_lvds_connector) {
119 		ret = -ENOMEM;
120 		goto fail;
121 	}
122 
123 	mdp4_lvds_connector->encoder = encoder;
124 	mdp4_lvds_connector->panel = panel;
125 
126 	connector = &mdp4_lvds_connector->base;
127 
128 	drm_connector_init(dev, connector, &mdp4_lvds_connector_funcs,
129 			DRM_MODE_CONNECTOR_LVDS);
130 	drm_connector_helper_add(connector, &mdp4_lvds_connector_helper_funcs);
131 
132 	connector->polled = 0;
133 
134 	connector->interlace_allowed = 0;
135 	connector->doublescan_allowed = 0;
136 
137 	drm_connector_register(connector);
138 
139 	drm_mode_connector_attach_encoder(connector, encoder);
140 
141 	if (panel)
142 		drm_panel_attach(panel, connector);
143 
144 	return connector;
145 
146 fail:
147 	if (connector)
148 		mdp4_lvds_connector_destroy(connector);
149 
150 	return ERR_PTR(ret);
151 }
152