47603cbbdd8c1cb6e12c9306e80111429ee5270e
[sdk/emulator/emulator-kernel.git] / drivers / gpu / drm / vigs / vigs_output.c
1 #include "vigs_output.h"
2 #include "vigs_device.h"
3 #include "drm_crtc_helper.h"
4 #include <linux/init.h>
5
6 #define DPI_DEF_VALUE 316
7 #define DPI_MIN_VALUE 100
8 #define DPI_MAX_VALUE 600
9
10 #ifndef MODULE
11 static int vigs_atoi(const char *str)
12 {
13     int val = 0;
14
15     for (;; ++str) {
16         switch (*str) {
17         case '0' ... '9':
18             val = (10 * val) + (*str - '0');
19             break;
20         default:
21             return val;
22         }
23     }
24 }
25 #endif
26
27 struct vigs_output
28 {
29     /*
30      * 'connector' is the owner of the 'vigs_output', i.e.
31      * when 'connector' is destroyed whole structure is destroyed.
32      */
33     struct drm_connector connector;
34     struct drm_encoder encoder;
35 };
36
37 static inline struct vigs_output *connector_to_vigs_output(struct drm_connector *connector)
38 {
39     return container_of(connector, struct vigs_output, connector);
40 }
41
42 static inline struct vigs_output *encoder_to_vigs_output(struct drm_encoder *encoder)
43 {
44     return container_of(encoder, struct vigs_output, encoder);
45 }
46
47 static void vigs_connector_save(struct drm_connector *connector)
48 {
49     DRM_DEBUG_KMS("enter\n");
50 }
51
52 static void vigs_connector_restore(struct drm_connector *connector)
53 {
54     DRM_DEBUG_KMS("enter\n");
55 }
56
57 static enum drm_connector_status vigs_connector_detect(
58     struct drm_connector *connector,
59     bool force)
60 {
61     DRM_DEBUG_KMS("enter: force = %d\n", force);
62
63     return connector_status_connected;
64 }
65
66 static int vigs_connector_set_property(struct drm_connector *connector,
67                                        struct drm_property *property,
68                                        uint64_t value)
69 {
70     DRM_DEBUG_KMS("enter: %s = %llu\n", property->name, value);
71
72     return 0;
73 }
74
75 static void vigs_connector_destroy(struct drm_connector *connector)
76 {
77     struct vigs_output *vigs_output = connector_to_vigs_output(connector);
78
79     DRM_DEBUG_KMS("enter\n");
80
81     drm_connector_unregister(connector);
82     drm_connector_cleanup(connector);
83
84     kfree(vigs_output);
85 }
86
87 static int vigs_connector_get_modes(struct drm_connector *connector)
88 {
89     struct vigs_output *vigs_output = connector_to_vigs_output(connector);
90     struct drm_device *drm_dev = vigs_output->connector.dev;
91     char *option = NULL;
92
93     DRM_DEBUG_KMS("enter\n");
94
95     if (fb_get_options(connector->name, &option) == 0) {
96         struct drm_cmdline_mode cmdline_mode;
97
98         if (drm_mode_parse_command_line_for_connector(option,
99                                                       connector,
100                                                       &cmdline_mode)) {
101             struct drm_display_mode *preferred_mode =
102                 drm_mode_create_from_cmdline_mode(drm_dev,
103                                                   &cmdline_mode);
104
105             /* qHD workaround (540x960) */
106             if (cmdline_mode.xres == 540 && cmdline_mode.yres == 960) {
107                 preferred_mode->hdisplay = cmdline_mode.xres;
108                 preferred_mode->hsync_start = preferred_mode->hsync_start - 1;
109                 preferred_mode->hsync_end = preferred_mode->hsync_end - 1;
110             }
111
112             preferred_mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
113             drm_mode_set_crtcinfo(preferred_mode, CRTC_INTERLACE_HALVE_V);
114             drm_mode_probed_add(connector, preferred_mode);
115             if (option != NULL)
116               kfree(option);
117             return 1;
118         }
119     }
120
121     return 0;
122 }
123
124 static int vigs_connector_mode_valid(struct drm_connector *connector,
125                                      struct drm_display_mode *mode)
126 {
127     DRM_DEBUG_KMS("enter\n");
128
129     return MODE_OK;
130 }
131
132 struct drm_encoder *vigs_connector_best_encoder(struct drm_connector *connector)
133 {
134     struct vigs_output *vigs_output = connector_to_vigs_output(connector);
135
136     DRM_DEBUG_KMS("enter\n");
137
138     return &vigs_output->encoder;
139 }
140
141 static void vigs_encoder_destroy(struct drm_encoder *encoder)
142 {
143     DRM_DEBUG_KMS("enter\n");
144
145     drm_encoder_cleanup(encoder);
146 }
147
148 static void vigs_encoder_dpms(struct drm_encoder *encoder, int mode)
149 {
150     DRM_DEBUG_KMS("enter: mode = %d\n", mode);
151 }
152
153 static bool vigs_encoder_mode_fixup(struct drm_encoder *encoder,
154                                     const struct drm_display_mode *mode,
155                                     struct drm_display_mode *adjusted_mode)
156 {
157     DRM_DEBUG_KMS("enter\n");
158
159     return true;
160 }
161
162 static void vigs_encoder_prepare(struct drm_encoder *encoder)
163 {
164     DRM_DEBUG_KMS("enter\n");
165 }
166
167 static void vigs_encoder_mode_set(struct drm_encoder *encoder,
168                                   struct drm_display_mode *mode,
169                                   struct drm_display_mode *adjusted_mode)
170 {
171     DRM_DEBUG_KMS("enter\n");
172 }
173
174 static void vigs_encoder_commit(struct drm_encoder *encoder)
175 {
176     DRM_DEBUG_KMS("enter\n");
177 }
178
179 static const struct drm_connector_funcs vigs_connector_funcs =
180 {
181     .dpms = drm_helper_connector_dpms,
182     .save = vigs_connector_save,
183     .restore = vigs_connector_restore,
184     .detect = vigs_connector_detect,
185     .fill_modes = drm_helper_probe_single_connector_modes,
186     .set_property = vigs_connector_set_property,
187     .destroy = vigs_connector_destroy,
188 };
189
190 static const struct drm_connector_helper_funcs vigs_connector_helper_funcs =
191 {
192     .get_modes = vigs_connector_get_modes,
193     .mode_valid = vigs_connector_mode_valid,
194     .best_encoder = vigs_connector_best_encoder,
195 };
196
197 static const struct drm_encoder_funcs vigs_encoder_funcs =
198 {
199     .destroy = vigs_encoder_destroy,
200 };
201
202 static const struct drm_encoder_helper_funcs vigs_encoder_helper_funcs =
203 {
204     .dpms = vigs_encoder_dpms,
205     .mode_fixup = vigs_encoder_mode_fixup,
206     .prepare = vigs_encoder_prepare,
207     .mode_set = vigs_encoder_mode_set,
208     .commit = vigs_encoder_commit,
209 };
210
211 int vigs_output_init(struct vigs_device *vigs_dev)
212 {
213     struct vigs_output *vigs_output;
214     int ret;
215
216     DRM_DEBUG_KMS("enter\n");
217
218     vigs_output = kzalloc(sizeof(*vigs_output), GFP_KERNEL);
219
220     if (!vigs_output) {
221         return -ENOMEM;
222     }
223
224     ret = drm_connector_init(vigs_dev->drm_dev,
225                              &vigs_output->connector,
226                              &vigs_connector_funcs,
227                              DRM_MODE_CONNECTOR_LVDS);
228
229     if (ret != 0) {
230         kfree(vigs_output);
231         return ret;
232     }
233
234     ret = drm_encoder_init(vigs_dev->drm_dev,
235                            &vigs_output->encoder,
236                            &vigs_encoder_funcs,
237                            DRM_MODE_ENCODER_LVDS);
238
239     if (ret != 0) {
240         /*
241          * KMS subsystem will delete 'vigs_output'
242          */
243
244         return ret;
245     }
246
247     /*
248      * We only have a single CRTC.
249      */
250     vigs_output->encoder.possible_crtcs = (1 << 0);
251
252     ret = drm_mode_connector_attach_encoder(&vigs_output->connector,
253                                             &vigs_output->encoder);
254
255     if (ret != 0) {
256         return ret;
257     }
258
259     drm_encoder_helper_add(&vigs_output->encoder, &vigs_encoder_helper_funcs);
260
261     drm_connector_helper_add(&vigs_output->connector, &vigs_connector_helper_funcs);
262
263     ret = drm_connector_register(&vigs_output->connector);
264
265     if (ret != 0) {
266         return ret;
267     }
268
269     return 0;
270 }
271
272 int vigs_output_get_dpi(void)
273 {
274     int dpi = DPI_DEF_VALUE;
275 #ifndef MODULE
276     char *str;
277
278     str = strstr(saved_command_line, "dpi=");
279
280     if (str != NULL) {
281         str += 4;
282         dpi = vigs_atoi(str);
283         if ((dpi < DPI_MIN_VALUE) || (dpi > DPI_MAX_VALUE)) {
284             dpi = DPI_DEF_VALUE;
285         }
286     }
287 #endif
288     return dpi;
289 }
290
291 int vigs_output_get_phys_width(int dpi, u32 width)
292 {
293     return ((width * 254 / dpi) + 5) / 10;
294 }
295
296 int vigs_output_get_phys_height(int dpi, u32 height)
297 {
298     return ((height * 254 / dpi) + 5) / 10;
299 }