/[pkgs]/devel/kernel/drm-nouveau.patch
ViewVC logotype

Contents of /devel/kernel/drm-nouveau.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.53 - (show annotations) (download) (as text)
Fri Sep 11 07:05:05 2009 UTC (2 months, 1 week ago) by bskeggs
Branch: MAIN
CVS Tags: kernel-2_6_32-0_24_rc4_git0_fc13, kernel-2_6_32-0_48_rc7_git1_fc13, kernel-2_6_32-0_51_rc7_git2_fc13, kernel-2_6_32-0_47_rc7_git1_fc13, kernel-2_6_32-0_46_rc7_git1_fc13, kernel-2_6_32-0_39_rc5_git6_fc13, kernel-2_6_32-0_5_rc0_git4_fc13, kernel-2_6_32-0_15_rc1_git0_fc13, kernel-2_6_32-0_14_rc0_git18_fc13, kernel-2_6_32-0_33_rc5_git1_fc13, F-12-split, HEAD
Changes since 1.52: +161 -6 lines
File MIME type: text/x-patch
* Fri Sep 11 2009 Ben Skeggs <bskeggs@redhat.com>
- nouveau: bring in Matthew Garret's initial switchable graphics support
1 diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
2 index e4d971c..7fe8a4c 100644
3 --- a/drivers/gpu/drm/Kconfig
4 +++ b/drivers/gpu/drm/Kconfig
5 @@ -153,3 +153,48 @@ config DRM_SAVAGE
6 help
7 Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
8 chipset. If M is selected the module will be called savage.
9 +
10 +config DRM_NOUVEAU
11 + tristate "Nouveau (nVidia) cards"
12 + depends on DRM
13 + select DRM_KMS_HELPER
14 + select DRM_TTM
15 + select FB_CFB_FILLRECT
16 + select FB_CFB_COPYAREA
17 + select FB_CFB_IMAGEBLIT
18 + select FB
19 + select FRAMEBUFFER_CONSOLE if !EMBEDDED
20 + select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
21 + help
22 + Choose this option for open-source nVidia support.
23 +
24 +config DRM_NOUVEAU_KMS
25 + bool "Enable modesetting on nouveau by default"
26 + depends on DRM_NOUVEAU
27 + help
28 + Choose this option if you want kernel modesetting enabled by default,
29 + and you have a new enough userspace to support this. Running old
30 + userspaces with this enabled will cause pain.
31 +
32 +config DRM_NOUVEAU_BACKLIGHT
33 + bool "Support for backlight control"
34 + depends on DRM_NOUVEAU
35 + default y
36 + help
37 + Say Y here if you want to control the backlight of your display
38 + (e.g. a laptop panel).
39 +
40 +menu "I2C encoder or helper chips"
41 + depends on DRM
42 +
43 +config DRM_I2C_CH7006
44 + tristate "Chrontel ch7006 TV encoder"
45 + default m if DRM_NOUVEAU
46 + help
47 + Support for Chrontel ch7006 and similar TV encoders, found
48 + on some nVidia video cards.
49 +
50 + This driver is currently only useful if you're also using
51 + the nouveau driver.
52 +
53 +endmenu
54 diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
55 index 3c8827a..d22e64b 100644
56 --- a/drivers/gpu/drm/Makefile
57 +++ b/drivers/gpu/drm/Makefile
58 @@ -31,3 +31,5 @@ obj-$(CONFIG_DRM_I915) += i915/
59 obj-$(CONFIG_DRM_SIS) += sis/
60 obj-$(CONFIG_DRM_SAVAGE)+= savage/
61 obj-$(CONFIG_DRM_VIA) +=via/
62 +obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
63 +obj-y += i2c/
64 diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
65 index 6246e3f..436e2fe 100644
66 --- a/drivers/gpu/drm/drm_bufs.c
67 +++ b/drivers/gpu/drm/drm_bufs.c
68 @@ -51,38 +51,24 @@ resource_size_t drm_get_resource_len(struct drm_device *dev, unsigned int resour
69
70 EXPORT_SYMBOL(drm_get_resource_len);
71
72 -static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
73 - struct drm_local_map *map)
74 +struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
75 + struct drm_local_map *map)
76 {
77 struct drm_map_list *entry;
78 list_for_each_entry(entry, &dev->maplist, head) {
79 - /*
80 - * Because the kernel-userspace ABI is fixed at a 32-bit offset
81 - * while PCI resources may live above that, we ignore the map
82 - * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.
83 - * It is assumed that each driver will have only one resource of
84 - * each type.
85 - */
86 if (!entry->map ||
87 map->type != entry->map->type ||
88 entry->master != dev->primary->master)
89 continue;
90 - switch (map->type) {
91 - case _DRM_SHM:
92 - if (map->flags != _DRM_CONTAINS_LOCK)
93 - break;
94 - case _DRM_REGISTERS:
95 - case _DRM_FRAME_BUFFER:
96 - return entry;
97 - default: /* Make gcc happy */
98 - ;
99 - }
100 - if (entry->map->offset == map->offset)
101 +
102 + if (entry->map->offset == map->offset ||
103 + (map->type == _DRM_SHM && map->flags & _DRM_CONTAINS_LOCK))
104 return entry;
105 }
106
107 return NULL;
108 }
109 +EXPORT_SYMBOL(drm_find_matching_map);
110
111 static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
112 unsigned long user_token, int hashed_handle, int shm)
113 @@ -357,7 +343,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
114 /* We do it here so that dev->struct_mutex protects the increment */
115 user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
116 map->offset;
117 - ret = drm_map_handle(dev, &list->hash, user_token, 0,
118 + ret = drm_map_handle(dev, &list->hash, user_token, 1,
119 (map->type == _DRM_SHM));
120 if (ret) {
121 if (map->type == _DRM_REGISTERS)
122 diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
123 new file mode 100644
124 index 0000000..6d2abaf
125 --- /dev/null
126 +++ b/drivers/gpu/drm/i2c/Makefile
127 @@ -0,0 +1,4 @@
128 +ccflags-y := -Iinclude/drm
129 +
130 +ch7006-y := ch7006_drv.o ch7006_mode.o
131 +obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
132 diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
133 new file mode 100644
134 index 0000000..0a3f7a0
135 --- /dev/null
136 +++ b/drivers/gpu/drm/i2c/ch7006_drv.c
137 @@ -0,0 +1,532 @@
138 +/*
139 + * Copyright (C) 2009 Francisco Jerez.
140 + * All Rights Reserved.
141 + *
142 + * Permission is hereby granted, free of charge, to any person obtaining
143 + * a copy of this software and associated documentation files (the
144 + * "Software"), to deal in the Software without restriction, including
145 + * without limitation the rights to use, copy, modify, merge, publish,
146 + * distribute, sublicense, and/or sell copies of the Software, and to
147 + * permit persons to whom the Software is furnished to do so, subject to
148 + * the following conditions:
149 + *
150 + * The above copyright notice and this permission notice (including the
151 + * next paragraph) shall be included in all copies or substantial
152 + * portions of the Software.
153 + *
154 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
155 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
156 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
157 + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
158 + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
159 + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
160 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
161 + *
162 + */
163 +
164 +#include "ch7006_priv.h"
165 +
166 +/* DRM encoder functions */
167 +
168 +static void ch7006_encoder_set_config(struct drm_encoder *encoder,
169 + void *params)
170 +{
171 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
172 +
173 + priv->params = params;
174 +}
175 +
176 +static void ch7006_encoder_destroy(struct drm_encoder *encoder)
177 +{
178 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
179 +
180 + drm_property_destroy(encoder->dev, priv->scale_property);
181 +
182 + kfree(priv);
183 + to_encoder_slave(encoder)->slave_priv = NULL;
184 +
185 + drm_i2c_encoder_destroy(encoder);
186 +}
187 +
188 +static void ch7006_encoder_dpms(struct drm_encoder *encoder, int mode)
189 +{
190 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
191 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
192 + struct ch7006_state *state = &priv->state;
193 +
194 + ch7006_dbg(client, "\n");
195 +
196 + if (mode == priv->last_dpms)
197 + return;
198 + priv->last_dpms = mode;
199 +
200 + ch7006_setup_power_state(encoder);
201 +
202 + ch7006_load_reg(client, state, CH7006_POWER);
203 +}
204 +
205 +static void ch7006_encoder_save(struct drm_encoder *encoder)
206 +{
207 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
208 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
209 +
210 + ch7006_dbg(client, "\n");
211 +
212 + ch7006_state_save(client, &priv->saved_state);
213 +}
214 +
215 +static void ch7006_encoder_restore(struct drm_encoder *encoder)
216 +{
217 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
218 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
219 +
220 + ch7006_dbg(client, "\n");
221 +
222 + ch7006_state_load(client, &priv->saved_state);
223 +}
224 +
225 +static bool ch7006_encoder_mode_fixup(struct drm_encoder *encoder,
226 + struct drm_display_mode *mode,
227 + struct drm_display_mode *adjusted_mode)
228 +{
229 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
230 +
231 + /* The ch7006 is painfully picky with the input timings so no
232 + * custom modes for now... */
233 +
234 + priv->mode = ch7006_lookup_mode(encoder, mode);
235 +
236 + return !!priv->mode;
237 +}
238 +
239 +static int ch7006_encoder_mode_valid(struct drm_encoder *encoder,
240 + struct drm_display_mode *mode)
241 +{
242 + if (ch7006_lookup_mode(encoder, mode))
243 + return MODE_OK;
244 + else
245 + return MODE_BAD;
246 +}
247 +
248 +static void ch7006_encoder_mode_set(struct drm_encoder *encoder,
249 + struct drm_display_mode *drm_mode,
250 + struct drm_display_mode *adjusted_mode)
251 +{
252 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
253 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
254 + struct ch7006_encoder_params *params = priv->params;
255 + struct ch7006_state *state = &priv->state;
256 + uint8_t *regs = state->regs;
257 + struct ch7006_mode *mode = priv->mode;
258 + struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
259 + int start_active;
260 +
261 + ch7006_dbg(client, "\n");
262 +
263 + regs[CH7006_DISPMODE] = norm->dispmode | mode->dispmode;
264 + regs[CH7006_BWIDTH] = 0;
265 + regs[CH7006_INPUT_FORMAT] = bitf(CH7006_INPUT_FORMAT_FORMAT,
266 + params->input_format);
267 +
268 + regs[CH7006_CLKMODE] = CH7006_CLKMODE_SUBC_LOCK
269 + | bitf(CH7006_CLKMODE_XCM, params->xcm)
270 + | bitf(CH7006_CLKMODE_PCM, params->pcm);
271 + if (params->clock_mode)
272 + regs[CH7006_CLKMODE] |= CH7006_CLKMODE_MASTER;
273 + if (params->clock_edge)
274 + regs[CH7006_CLKMODE] |= CH7006_CLKMODE_POS_EDGE;
275 +
276 + start_active = (drm_mode->htotal & ~0x7) - (drm_mode->hsync_start & ~0x7);
277 + regs[CH7006_POV] = bitf(CH7006_POV_START_ACTIVE_8, start_active);
278 + regs[CH7006_START_ACTIVE] = bitf(CH7006_START_ACTIVE_0, start_active);
279 +
280 + regs[CH7006_INPUT_SYNC] = 0;
281 + if (params->sync_direction)
282 + regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_OUTPUT;
283 + if (params->sync_encoding)
284 + regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_EMBEDDED;
285 + if (drm_mode->flags & DRM_MODE_FLAG_PVSYNC)
286 + regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PVSYNC;
287 + if (drm_mode->flags & DRM_MODE_FLAG_PHSYNC)
288 + regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PHSYNC;
289 +
290 + regs[CH7006_DETECT] = 0;
291 + regs[CH7006_BCLKOUT] = 0;
292 +
293 + regs[CH7006_SUBC_INC3] = 0;
294 + if (params->pout_level)
295 + regs[CH7006_SUBC_INC3] |= CH7006_SUBC_INC3_POUT_3_3V;
296 +
297 + regs[CH7006_SUBC_INC4] = 0;
298 + if (params->active_detect)
299 + regs[CH7006_SUBC_INC4] |= CH7006_SUBC_INC4_DS_INPUT;
300 +
301 + regs[CH7006_PLL_CONTROL] = priv->saved_state.regs[CH7006_PLL_CONTROL];
302 +
303 + ch7006_setup_levels(encoder);
304 + ch7006_setup_subcarrier(encoder);
305 + ch7006_setup_pll(encoder);
306 + ch7006_setup_power_state(encoder);
307 + ch7006_setup_properties(encoder);
308 +
309 + ch7006_state_load(client, state);
310 +}
311 +
312 +static enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encoder,
313 + struct drm_connector *connector)
314 +{
315 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
316 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
317 + struct ch7006_state *state = &priv->state;
318 + int det;
319 +
320 + ch7006_dbg(client, "\n");
321 +
322 + ch7006_save_reg(client, state, CH7006_DETECT);
323 + ch7006_save_reg(client, state, CH7006_POWER);
324 + ch7006_save_reg(client, state, CH7006_CLKMODE);
325 +
326 + ch7006_write(client, CH7006_POWER, CH7006_POWER_RESET |
327 + bitfs(CH7006_POWER_LEVEL, NORMAL));
328 + ch7006_write(client, CH7006_CLKMODE, CH7006_CLKMODE_MASTER);
329 +
330 + ch7006_write(client, CH7006_DETECT, CH7006_DETECT_SENSE);
331 +
332 + ch7006_write(client, CH7006_DETECT, 0);
333 +
334 + det = ch7006_read(client, CH7006_DETECT);
335 +
336 + ch7006_load_reg(client, state, CH7006_CLKMODE);
337 + ch7006_load_reg(client, state, CH7006_POWER);
338 + ch7006_load_reg(client, state, CH7006_DETECT);
339 +
340 + if ((det & (CH7006_DETECT_SVIDEO_Y_TEST|
341 + CH7006_DETECT_SVIDEO_C_TEST|
342 + CH7006_DETECT_CVBS_TEST)) == 0)
343 + priv->subconnector = DRM_MODE_SUBCONNECTOR_SCART;
344 + else if ((det & (CH7006_DETECT_SVIDEO_Y_TEST|
345 + CH7006_DETECT_SVIDEO_C_TEST)) == 0)
346 + priv->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO;
347 + else if ((det & CH7006_DETECT_CVBS_TEST) == 0)
348 + priv->subconnector = DRM_MODE_SUBCONNECTOR_Composite;
349 + else
350 + priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
351 +
352 + drm_connector_property_set_value(connector,
353 + encoder->dev->mode_config.tv_subconnector_property,
354 + priv->subconnector);
355 +
356 + return priv->subconnector?
357 + connector_status_connected
358 + : connector_status_disconnected;
359 +}
360 +
361 +static int ch7006_encoder_get_modes(struct drm_encoder *encoder,
362 + struct drm_connector *connector)
363 +{
364 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
365 + struct ch7006_mode *mode;
366 + int n = 0;
367 +
368 + for (mode = ch7006_modes; mode->mode.clock; mode++) {
369 + if (~mode->valid_scales & 1<<priv->scale ||
370 + ~mode->valid_norms & 1<<priv->norm)
371 + continue;
372 +
373 + drm_mode_probed_add(connector,
374 + drm_mode_duplicate(encoder->dev, &mode->mode));
375 +
376 + n++;
377 + }
378 +
379 + return n;
380 +}
381 +
382 +static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
383 + struct drm_connector *connector)
384 +{
385 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
386 + struct drm_device *dev = encoder->dev;
387 + struct drm_mode_config *conf = &dev->mode_config;
388 +
389 + drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
390 +
391 + priv->scale_property = drm_property_create(dev, DRM_MODE_PROP_RANGE,
392 + "scale", 2);
393 + priv->scale_property->values[0] = 0;
394 + priv->scale_property->values[1] = 2;
395 +
396 + drm_connector_attach_property(connector, conf->tv_select_subconnector_property,
397 + priv->select_subconnector);
398 + drm_connector_attach_property(connector, conf->tv_subconnector_property,
399 + priv->subconnector);
400 + drm_connector_attach_property(connector, conf->tv_left_margin_property,
401 + priv->hmargin);
402 + drm_connector_attach_property(connector, conf->tv_bottom_margin_property,
403 + priv->vmargin);
404 + drm_connector_attach_property(connector, conf->tv_mode_property,
405 + priv->norm);
406 + drm_connector_attach_property(connector, conf->tv_brightness_property,
407 + priv->brightness);
408 + drm_connector_attach_property(connector, conf->tv_contrast_property,
409 + priv->contrast);
410 + drm_connector_attach_property(connector, conf->tv_flicker_reduction_property,
411 + priv->flicker);
412 + drm_connector_attach_property(connector, priv->scale_property,
413 + priv->scale);
414 +
415 + return 0;
416 +}
417 +
418 +static int ch7006_encoder_set_property(struct drm_encoder *encoder,
419 + struct drm_connector *connector,
420 + struct drm_property *property,
421 + uint64_t val)
422 +{
423 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
424 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
425 + struct ch7006_state *state = &priv->state;
426 + struct drm_mode_config *conf = &encoder->dev->mode_config;
427 + struct drm_crtc *crtc = encoder->crtc;
428 + bool modes_changed = false;
429 +
430 + ch7006_dbg(client, "\n");
431 +
432 + if (property == conf->tv_select_subconnector_property) {
433 + priv->select_subconnector = val;
434 +
435 + ch7006_setup_power_state(encoder);
436 +
437 + ch7006_load_reg(client, state, CH7006_POWER);
438 +
439 + } else if (property == conf->tv_left_margin_property) {
440 + priv->hmargin = val;
441 +
442 + ch7006_setup_properties(encoder);
443 +
444 + ch7006_load_reg(client, state, CH7006_POV);
445 + ch7006_load_reg(client, state, CH7006_HPOS);
446 +
447 + } else if (property == conf->tv_bottom_margin_property) {
448 + priv->vmargin = val;
449 +
450 + ch7006_setup_properties(encoder);
451 +
452 + ch7006_load_reg(client, state, CH7006_POV);
453 + ch7006_load_reg(client, state, CH7006_VPOS);
454 +
455 + } else if (property == conf->tv_mode_property) {
456 + if (connector->dpms != DRM_MODE_DPMS_OFF)
457 + return -EINVAL;
458 +
459 + priv->norm = val;
460 +
461 + modes_changed = true;
462 +
463 + } else if (property == conf->tv_brightness_property) {
464 + priv->brightness = val;
465 +
466 + ch7006_setup_levels(encoder);
467 +
468 + ch7006_load_reg(client, state, CH7006_BLACK_LEVEL);
469 +
470 + } else if (property == conf->tv_contrast_property) {
471 + priv->contrast = val;
472 +
473 + ch7006_setup_properties(encoder);
474 +
475 + ch7006_load_reg(client, state, CH7006_CONTRAST);
476 +
477 + } else if (property == conf->tv_flicker_reduction_property) {
478 + priv->flicker = val;
479 +
480 + ch7006_setup_properties(encoder);
481 +
482 + ch7006_load_reg(client, state, CH7006_FFILTER);
483 +
484 + } else if (property == priv->scale_property) {
485 + if (connector->dpms != DRM_MODE_DPMS_OFF)
486 + return -EINVAL;
487 +
488 + priv->scale = val;
489 +
490 + modes_changed = true;
491 +
492 + } else {
493 + return -EINVAL;
494 + }
495 +
496 + if (modes_changed) {
497 + drm_helper_probe_single_connector_modes(connector, 0, 0);
498 +
499 + /* Disable the crtc to ensure a full modeset is
500 + * performed whenever it's turned on again. */
501 + if (crtc) {
502 + struct drm_mode_set modeset = {
503 + .crtc = crtc,
504 + };
505 +
506 + crtc->funcs->set_config(&modeset);
507 + }
508 + }
509 +
510 + return 0;
511 +}
512 +
513 +static struct drm_encoder_slave_funcs ch7006_encoder_funcs = {
514 + .set_config = ch7006_encoder_set_config,
515 + .destroy = ch7006_encoder_destroy,
516 + .dpms = ch7006_encoder_dpms,
517 + .save = ch7006_encoder_save,
518 + .restore = ch7006_encoder_restore,
519 + .mode_fixup = ch7006_encoder_mode_fixup,
520 + .mode_valid = ch7006_encoder_mode_valid,
521 + .mode_set = ch7006_encoder_mode_set,
522 + .detect = ch7006_encoder_detect,
523 + .get_modes = ch7006_encoder_get_modes,
524 + .create_resources = ch7006_encoder_create_resources,
525 + .set_property = ch7006_encoder_set_property,
526 +};
527 +
528 +
529 +/* I2C driver functions */
530 +
531 +static int ch7006_probe(struct i2c_client *client, const struct i2c_device_id *id)
532 +{
533 + uint8_t addr = CH7006_VERSION_ID;
534 + uint8_t val;
535 + int ret;
536 +
537 + ch7006_dbg(client, "\n");
538 +
539 + ret = i2c_master_send(client, &addr, sizeof(addr));
540 + if (ret < 0)
541 + goto fail;
542 +
543 + ret = i2c_master_recv(client, &val, sizeof(val));
544 + if (ret < 0)
545 + goto fail;
546 +
547 + ch7006_info(client, "Detected version ID: %x\n", val);
548 +
549 + return 0;
550 +
551 +fail:
552 + ch7006_err(client, "Error %d reading version ID\n", ret);
553 +
554 + return -ENODEV;
555 +}
556 +
557 +static int ch7006_remove(struct i2c_client *client)
558 +{
559 + ch7006_dbg(client, "\n");
560 +
561 + return 0;
562 +}
563 +
564 +static int ch7006_encoder_init(struct i2c_client *client,
565 + struct drm_device *dev,
566 + struct drm_encoder_slave *encoder)
567 +{
568 + struct ch7006_priv *priv;
569 + int i;
570 +
571 + ch7006_dbg(client, "\n");
572 +
573 + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
574 + if (!priv)
575 + return -ENOMEM;
576 +
577 + encoder->slave_priv = priv;
578 + encoder->slave_funcs = &ch7006_encoder_funcs;
579 +
580 + priv->norm = TV_NORM_PAL;
581 + priv->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic;
582 + priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
583 + priv->scale = 1;
584 + priv->contrast = 50;
585 + priv->brightness = 50;
586 + priv->flicker = 50;
587 + priv->hmargin = 50;
588 + priv->vmargin = 50;
589 + priv->last_dpms = -1;
590 +
591 + if (ch7006_tv_norm) {
592 + for (i = 0; i < NUM_TV_NORMS; i++) {
593 + if (!strcmp(ch7006_tv_norm_names[i], ch7006_tv_norm)) {
594 + priv->norm = i;
595 + break;
596 + }
597 + }
598 +
599 + if (i == NUM_TV_NORMS)
600 + ch7006_err(client, "Invalid TV norm setting \"%s\".\n",
601 + ch7006_tv_norm);
602 + }
603 +
604 + if (ch7006_scale >= 0 && ch7006_scale <= 2)
605 + priv->scale = ch7006_scale;
606 + else
607 + ch7006_err(client, "Invalid scale setting \"%d\".\n",
608 + ch7006_scale);
609 +
610 + return 0;
611 +}
612 +
613 +static struct i2c_device_id ch7006_ids[] = {
614 + { "ch7006", 0 },
615 + { }
616 +};
617 +MODULE_DEVICE_TABLE(i2c, ch7006_ids);
618 +
619 +static struct drm_i2c_encoder_driver ch7006_driver = {
620 + .i2c_driver = {
621 + .probe = ch7006_probe,
622 + .remove = ch7006_remove,
623 +
624 + .driver = {
625 + .name = "ch7006",
626 + },
627 +
628 + .id_table = ch7006_ids,
629 + },
630 +
631 + .encoder_init = ch7006_encoder_init,
632 +};
633 +
634 +
635 +/* Module initialization */
636 +
637 +static int __init ch7006_init(void)
638 +{
639 + return drm_i2c_encoder_register(THIS_MODULE, &ch7006_driver);
640 +}
641 +
642 +static void __exit ch7006_exit(void)
643 +{
644 + drm_i2c_encoder_unregister(&ch7006_driver);
645 +}
646 +
647 +int ch7006_debug = 0;
648 +module_param_named(debug, ch7006_debug, int, 0600);
649 +MODULE_PARM_DESC(debug, "Enable debug output.");
650 +
651 +char *ch7006_tv_norm = NULL;
652 +module_param_named(tv_norm, ch7006_tv_norm, charp, 0600);
653 +MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
654 + "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, PAL-60, NTSC-M, NTSC-J.\n"
655 + "\t\tDefault: PAL");
656 +
657 +int ch7006_scale = 1;
658 +module_param_named(scale, ch7006_scale, int, 0600);
659 +MODULE_PARM_DESC(scale, "Default scale.\n"
660 + "\t\tSupported: 0 -> Select video modes with a higher blanking ratio.\n"
661 + "\t\t\t1 -> Select default video modes.\n"
662 + "\t\t\t2 -> Select video modes with a lower blanking ratio.");
663 +
664 +MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
665 +MODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver");
666 +MODULE_LICENSE("GPL and additional rights");
667 +
668 +module_init(ch7006_init);
669 +module_exit(ch7006_exit);
670 diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c
671 new file mode 100644
672 index 0000000..7ffe0bd
673 --- /dev/null
674 +++ b/drivers/gpu/drm/i2c/ch7006_mode.c
675 @@ -0,0 +1,473 @@
676 +/*
677 + * Copyright (C) 2009 Francisco Jerez.
678 + * All Rights Reserved.
679 + *
680 + * Permission is hereby granted, free of charge, to any person obtaining
681 + * a copy of this software and associated documentation files (the
682 + * "Software"), to deal in the Software without restriction, including
683 + * without limitation the rights to use, copy, modify, merge, publish,
684 + * distribute, sublicense, and/or sell copies of the Software, and to
685 + * permit persons to whom the Software is furnished to do so, subject to
686 + * the following conditions:
687 + *
688 + * The above copyright notice and this permission notice (including the
689 + * next paragraph) shall be included in all copies or substantial
690 + * portions of the Software.
691 + *
692 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
693 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
694 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
695 + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
696 + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
697 + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
698 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
699 + *
700 + */
701 +
702 +#include "ch7006_priv.h"
703 +
704 +char *ch7006_tv_norm_names[] = {
705 + [TV_NORM_PAL] = "PAL",
706 + [TV_NORM_PAL_M] = "PAL-M",
707 + [TV_NORM_PAL_N] = "PAL-N",
708 + [TV_NORM_PAL_NC] = "PAL-Nc",
709 + [TV_NORM_PAL_60] = "PAL-60",
710 + [TV_NORM_NTSC_M] = "NTSC-M",
711 + [TV_NORM_NTSC_J] = "NTSC-J",
712 +};
713 +
714 +#define NTSC_LIKE_TIMINGS .vrefresh = 60 * fixed1/1.001, \
715 + .vdisplay = 480, \
716 + .vtotal = 525, \
717 + .hvirtual = 660
718 +
719 +#define PAL_LIKE_TIMINGS .vrefresh = 50 * fixed1, \
720 + .vdisplay = 576, \
721 + .vtotal = 625, \
722 + .hvirtual = 810
723 +
724 +struct ch7006_tv_norm_info ch7006_tv_norms[] = {
725 + [TV_NORM_NTSC_M] = {
726 + NTSC_LIKE_TIMINGS,
727 + .black_level = 0.339 * fixed1,
728 + .subc_freq = 3579545 * fixed1,
729 + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC),
730 + .voffset = 0,
731 + },
732 + [TV_NORM_NTSC_J] = {
733 + NTSC_LIKE_TIMINGS,
734 + .black_level = 0.286 * fixed1,
735 + .subc_freq = 3579545 * fixed1,
736 + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC_J),
737 + .voffset = 0,
738 + },
739 + [TV_NORM_PAL] = {
740 + PAL_LIKE_TIMINGS,
741 + .black_level = 0.3 * fixed1,
742 + .subc_freq = 4433618.75 * fixed1,
743 + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL),
744 + .voffset = 0,
745 + },
746 + [TV_NORM_PAL_M] = {
747 + NTSC_LIKE_TIMINGS,
748 + .black_level = 0.339 * fixed1,
749 + .subc_freq = 3575611.433 * fixed1,
750 + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M),
751 + .voffset = 16,
752 + },
753 +
754 + /* The following modes seem to work right but they're
755 + * undocumented */
756 +
757 + [TV_NORM_PAL_N] = {
758 + PAL_LIKE_TIMINGS,
759 + .black_level = 0.339 * fixed1,
760 + .subc_freq = 4433618.75 * fixed1,
761 + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL),
762 + .voffset = 0,
763 + },
764 + [TV_NORM_PAL_NC] = {
765 + PAL_LIKE_TIMINGS,
766 + .black_level = 0.3 * fixed1,
767 + .subc_freq = 3582056.25 * fixed1,
768 + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL),
769 + .voffset = 0,
770 + },
771 + [TV_NORM_PAL_60] = {
772 + NTSC_LIKE_TIMINGS,
773 + .black_level = 0.3 * fixed1,
774 + .subc_freq = 4433618.75 * fixed1,
775 + .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M),
776 + .voffset = 16,
777 + },
778 +};
779 +
780 +#define __MODE(f, hd, vd, ht, vt, hsynp, vsynp, \
781 + subc, scale, scale_mask, norm_mask, e_hd, e_vd) { \
782 + .mode = { \
783 + .name = #hd "x" #vd, \
784 + .status = 0, \
785 + .type = DRM_MODE_TYPE_DRIVER, \
786 + .clock = f, \
787 + .hdisplay = hd, \
788 + .hsync_start = e_hd + 16, \
789 + .hsync_end = e_hd + 80, \
790 + .htotal = ht, \
791 + .hskew = 0, \
792 + .vdisplay = vd, \
793 + .vsync_start = vd + 10, \
794 + .vsync_end = vd + 26, \
795 + .vtotal = vt, \
796 + .vscan = 0, \
797 + .flags = DRM_MODE_FLAG_##hsynp##HSYNC | \
798 + DRM_MODE_FLAG_##vsynp##VSYNC, \
799 + .vrefresh = 0, \
800 + }, \
801 + .enc_hdisp = e_hd, \
802 + .enc_vdisp = e_vd, \
803 + .subc_coeff = subc * fixed1, \
804 + .dispmode = bitfs(CH7006_DISPMODE_SCALING_RATIO, scale) | \
805 + bitfs(CH7006_DISPMODE_INPUT_RES, e_hd##x##e_vd), \
806 + .valid_scales = scale_mask, \
807 + .valid_norms = norm_mask \
808 + }
809 +
810 +#define MODE(f, hd, vd, ht, vt, hsynp, vsynp, \
811 + subc, scale, scale_mask, norm_mask) \
812 + __MODE(f, hd, vd, ht, vt, hsynp, vsynp, subc, scale, \
813 + scale_mask, norm_mask, hd, vd)
814 +
815 +#define NTSC_LIKE (1 << TV_NORM_NTSC_M | 1 << TV_NORM_NTSC_J | \
816 + 1 << TV_NORM_PAL_M | 1 << TV_NORM_PAL_60)
817 +
818 +#define PAL_LIKE (1 << TV_NORM_PAL | 1 << TV_NORM_PAL_N | 1 << TV_NORM_PAL_NC)
819 +
820 +struct ch7006_mode ch7006_modes[] = {
821 + MODE(21000, 512, 384, 840, 500, N, N, 181.797557582, 5_4, 0x6, PAL_LIKE),
822 + MODE(26250, 512, 384, 840, 625, N, N, 145.438046066, 1_1, 0x1, PAL_LIKE),
823 + MODE(20140, 512, 384, 800, 420, N, N, 213.257083791, 5_4, 0x4, NTSC_LIKE),
824 + MODE(24671, 512, 384, 784, 525, N, N, 174.0874153, 1_1, 0x3, NTSC_LIKE),
825 + MODE(28125, 720, 400, 1125, 500, N, N, 135.742176298, 5_4, 0x6, PAL_LIKE),
826 + MODE(34875, 720, 400, 1116, 625, N, N, 109.469496898, 1_1, 0x1, PAL_LIKE),
827 + MODE(23790, 720, 400, 945, 420, N, N, 160.475642016, 5_4, 0x4, NTSC_LIKE),
828 + MODE(29455, 720, 400, 936, 525, N, N, 129.614941843, 1_1, 0x3, NTSC_LIKE),
829 + MODE(25000, 640, 400, 1000, 500, N, N, 152.709948279, 5_4, 0x6, PAL_LIKE),
830 + MODE(31500, 640, 400, 1008, 625, N, N, 121.198371646, 1_1, 0x1, PAL_LIKE),
831 + MODE(21147, 640, 400, 840, 420, N, N, 180.535097338, 5_4, 0x4, NTSC_LIKE),
832 + MODE(26434, 640, 400, 840, 525, N, N, 144.42807787, 1_1, 0x2, NTSC_LIKE),
833 + MODE(30210, 640, 400, 840, 600, N, N, 126.374568276, 7_8, 0x1, NTSC_LIKE),
834 + MODE(21000, 640, 480, 840, 500, N, N, 181.797557582, 5_4, 0x4, PAL_LIKE),
835 + MODE(26250, 640, 480, 840, 625, N, N, 145.438046066, 1_1, 0x2, PAL_LIKE),
836 + MODE(31500, 640, 480, 840, 750, N, N, 121.198371646, 5_6, 0x1, PAL_LIKE),
837 + MODE(24671, 640, 480, 784, 525, N, N, 174.0874153, 1_1, 0x4, NTSC_LIKE),
838 + MODE(28196, 640, 480, 784, 600, N, N, 152.326488422, 7_8, 0x2, NTSC_LIKE),
839 + MODE(30210, 640, 480, 800, 630, N, N, 142.171389101, 5_6, 0x1, NTSC_LIKE),
840 + __MODE(29500, 720, 576, 944, 625, P, P, 145.592111636, 1_1, 0x7, PAL_LIKE, 800, 600),
841 + MODE(36000, 800, 600, 960, 750, P, P, 119.304647022, 5_6, 0x6, PAL_LIKE),
842 + MODE(39000, 800, 600, 936, 836, P, P, 110.127366499, 3_4, 0x1, PAL_LIKE),
843 + MODE(39273, 800, 600, 1040, 630, P, P, 145.816809399, 5_6, 0x4, NTSC_LIKE),
844 + MODE(43636, 800, 600, 1040, 700, P, P, 131.235128487, 3_4, 0x2, NTSC_LIKE),
845 + MODE(47832, 800, 600, 1064, 750, P, P, 119.723275165, 7_10, 0x1, NTSC_LIKE),
846 + {}
847 +};
848 +
849 +struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder,
850 + struct drm_display_mode *drm_mode)
851 +{
852 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
853 + struct ch7006_mode *mode;
854 +
855 + for (mode = ch7006_modes; mode->mode.clock; mode++) {
856 +
857 + if (~mode->valid_norms & 1<<priv->norm)
858 + continue;
859 +
860 + if (mode->mode.hdisplay != drm_mode->hdisplay ||
861 + mode->mode.vdisplay != drm_mode->vdisplay ||
862 + mode->mode.vtotal != drm_mode->vtotal ||
863 + mode->mode.htotal != drm_mode->htotal ||
864 + mode->mode.clock != drm_mode->clock)
865 + continue;
866 +
867 + return mode;
868 + }
869 +
870 + return NULL;
871 +}
872 +
873 +/* Some common HW state calculation code */
874 +
875 +void ch7006_setup_levels(struct drm_encoder *encoder)
876 +{
877 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
878 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
879 + uint8_t *regs = priv->state.regs;
880 + struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
881 + int gain;
882 + int black_level;
883 +
884 + /* Set DAC_GAIN if the voltage drop between white and black is
885 + * high enough. */
886 + if (norm->black_level < 339*fixed1/1000) {
887 + gain = 76;
888 +
889 + regs[CH7006_INPUT_FORMAT] |= CH7006_INPUT_FORMAT_DAC_GAIN;
890 + } else {
891 + gain = 71;
892 +
893 + regs[CH7006_INPUT_FORMAT] &= ~CH7006_INPUT_FORMAT_DAC_GAIN;
894 + }
895 +
896 + black_level = round_fixed(norm->black_level*26625)/gain;
897 +
898 + /* Correct it with the specified brightness. */
899 + black_level = interpolate(90, black_level, 208, priv->brightness);
900 +
901 + regs[CH7006_BLACK_LEVEL] = bitf(CH7006_BLACK_LEVEL_0, black_level);
902 +
903 + ch7006_dbg(client, "black level: %d\n", black_level);
904 +}
905 +
906 +void ch7006_setup_subcarrier(struct drm_encoder *encoder)
907 +{
908 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
909 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
910 + struct ch7006_state *state = &priv->state;
911 + struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
912 + struct ch7006_mode *mode = priv->mode;
913 + uint32_t subc_inc;
914 +
915 + subc_inc = round_fixed((mode->subc_coeff >> 8)
916 + * (norm->subc_freq >> 24));
917 +
918 + setbitf(state, CH7006_SUBC_INC0, 28, subc_inc);
919 + setbitf(state, CH7006_SUBC_INC1, 24, subc_inc);
920 + setbitf(state, CH7006_SUBC_INC2, 20, subc_inc);
921 + setbitf(state, CH7006_SUBC_INC3, 16, subc_inc);
922 + setbitf(state, CH7006_SUBC_INC4, 12, subc_inc);
923 + setbitf(state, CH7006_SUBC_INC5, 8, subc_inc);
924 + setbitf(state, CH7006_SUBC_INC6, 4, subc_inc);
925 + setbitf(state, CH7006_SUBC_INC7, 0, subc_inc);
926 +
927 + ch7006_dbg(client, "subcarrier inc: %u\n", subc_inc);
928 +}
929 +
930 +void ch7006_setup_pll(struct drm_encoder *encoder)
931 +{
932 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
933 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
934 + uint8_t *regs = priv->state.regs;
935 + struct ch7006_mode *mode = priv->mode;
936 + int n, best_n = 0;
937 + int m, best_m = 0;
938 + int freq, best_freq = 0;
939 +
940 + for (n = 0; n < CH7006_MAXN; n++) {
941 + for (m = 0; m < CH7006_MAXM; m++) {
942 + freq = CH7006_FREQ0*(n+2)/(m+2);
943 +
944 + if (abs(freq - mode->mode.clock) <
945 + abs(best_freq - mode->mode.clock)) {
946 + best_freq = freq;
947 + best_n = n;
948 + best_m = m;
949 + }
950 + }
951 + }
952 +
953 + regs[CH7006_PLLOV] = bitf(CH7006_PLLOV_N_8, best_n) |
954 + bitf(CH7006_PLLOV_M_8, best_m);
955 +
956 + regs[CH7006_PLLM] = bitf(CH7006_PLLM_0, best_m);
957 + regs[CH7006_PLLN] = bitf(CH7006_PLLN_0, best_n);
958 +
959 + if (best_n < 108)
960 + regs[CH7006_PLL_CONTROL] |= CH7006_PLL_CONTROL_CAPACITOR;
961 + else
962 + regs[CH7006_PLL_CONTROL] &= ~CH7006_PLL_CONTROL_CAPACITOR;
963 +
964 + ch7006_dbg(client, "n=%d m=%d f=%d c=%d\n",
965 + best_n, best_m, best_freq, best_n < 108);
966 +}
967 +
968 +void ch7006_setup_power_state(struct drm_encoder *encoder)
969 +{
970 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
971 + uint8_t *power = &priv->state.regs[CH7006_POWER];
972 + int subconnector;
973 +
974 + subconnector = priv->select_subconnector?
975 + priv->select_subconnector : priv->subconnector;
976 +
977 + *power = CH7006_POWER_RESET;
978 +
979 + if (priv->last_dpms == DRM_MODE_DPMS_ON) {
980 + switch (subconnector) {
981 + case DRM_MODE_SUBCONNECTOR_SVIDEO:
982 + *power |= bitfs(CH7006_POWER_LEVEL, CVBS_OFF);
983 + break;
984 + case DRM_MODE_SUBCONNECTOR_Composite:
985 + *power |= bitfs(CH7006_POWER_LEVEL, SVIDEO_OFF);
986 + break;
987 + case DRM_MODE_SUBCONNECTOR_SCART:
988 + *power |= bitfs(CH7006_POWER_LEVEL, NORMAL) |
989 + CH7006_POWER_SCART;
990 + break;
991 + }
992 +
993 + } else {
994 + *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
995 + }
996 +}
997 +
998 +void ch7006_setup_properties(struct drm_encoder *encoder)
999 +{
1000 + struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
1001 + struct ch7006_priv *priv = to_ch7006_priv(encoder);
1002 + struct ch7006_state *state = &priv->state;
1003 + struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
1004 + struct ch7006_mode *ch_mode = priv->mode;
1005 + struct drm_display_mode *mode = &ch_mode->mode;
1006 + uint8_t *regs = state->regs;
1007 + int flicker, contrast, hpos, vpos;
1008 + uint64_t scale, aspect;
1009 +
1010 + flicker = interpolate(0, 2, 3, priv->flicker);
1011 + regs[CH7006_FFILTER] = bitf(CH7006_FFILTER_TEXT, flicker) |
1012 + bitf(CH7006_FFILTER_LUMA, flicker) |
1013 + bitf(CH7006_FFILTER_CHROMA, 1);
1014 +
1015 + contrast = interpolate(0, 5, 7, priv->contrast);
1016 + regs[CH7006_CONTRAST] = bitf(CH7006_CONTRAST_0, contrast);
1017 +
1018 + scale = norm->vtotal*fixed1;
1019 + do_div(scale, mode->vtotal);
1020 +
1021 + aspect = ch_mode->enc_hdisp*fixed1;
1022 + do_div(aspect, ch_mode->enc_vdisp);
1023 +
1024 + hpos = round_fixed((norm->hvirtual * aspect - mode->hdisplay * scale)
1025 + * priv->hmargin * mode->vtotal) / norm->vtotal / 100 / 4;
1026 +
1027 + setbitf(state, CH7006_POV, HPOS_8, hpos);
1028 + setbitf(state, CH7006_HPOS, 0, hpos);
1029 +
1030 + vpos = max(0, norm->vdisplay - round_fixed(mode->vdisplay*scale)
1031 + + norm->voffset) * priv->vmargin / 100 / 2;
1032 +
1033 + setbitf(state, CH7006_POV, VPOS_8, vpos);
1034 + setbitf(state, CH7006_VPOS, 0, vpos);
1035 +
1036 + ch7006_dbg(client, "hpos: %d, vpos: %d\n", hpos, vpos);
1037 +}
1038 +
1039 +/* HW access functions */
1040 +
1041 +void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val)
1042 +{
1043 + uint8_t buf[] = {addr, val};
1044 + int ret;
1045 +
1046 + ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
1047 + if (ret < 0)
1048 + ch7006_err(client, "Error %d writing to subaddress 0x%x\n",
1049 + ret, addr);
1050 +}
1051 +
1052 +uint8_t ch7006_read(struct i2c_client *client, uint8_t addr)
1053 +{
1054 + uint8_t val;
1055 + int ret;
1056 +
1057 + ret = i2c_master_send(client, &addr, sizeof(addr));
1058 + if (ret < 0)
1059 + goto fail;
1060 +
1061 + ret = i2c_master_recv(client, &val, sizeof(val));
1062 + if (ret < 0)
1063 + goto fail;
1064 +
1065 + return val;
1066 +
1067 +fail:
1068 + ch7006_err(client, "Error %d reading from subaddress 0x%x\n",
1069 + ret, addr);
1070 + return 0;
1071 +}
1072 +
1073 +void ch7006_state_load(struct i2c_client *client,
1074 + struct ch7006_state *state)
1075 +{
1076 + ch7006_load_reg(client, state, CH7006_POWER);
1077 +
1078 + ch7006_load_reg(client, state, CH7006_DISPMODE);
1079 + ch7006_load_reg(client, state, CH7006_FFILTER);
1080 + ch7006_load_reg(client, state, CH7006_BWIDTH);
1081 + ch7006_load_reg(client, state, CH7006_INPUT_FORMAT);
1082 + ch7006_load_reg(client, state, CH7006_CLKMODE);
1083 + ch7006_load_reg(client, state, CH7006_START_ACTIVE);
1084 + ch7006_load_reg(client, state, CH7006_POV);
1085 + ch7006_load_reg(client, state, CH7006_BLACK_LEVEL);
1086 + ch7006_load_reg(client, state, CH7006_HPOS);
1087 + ch7006_load_reg(client, state, CH7006_VPOS);
1088 + ch7006_load_reg(client, state, CH7006_INPUT_SYNC);
1089 + ch7006_load_reg(client, state, CH7006_DETECT);
1090 + ch7006_load_reg(client, state, CH7006_CONTRAST);
1091 + ch7006_load_reg(client, state, CH7006_PLLOV);
1092 + ch7006_load_reg(client, state, CH7006_PLLM);
1093 + ch7006_load_reg(client, state, CH7006_PLLN);
1094 + ch7006_load_reg(client, state, CH7006_BCLKOUT);
1095 + ch7006_load_reg(client, state, CH7006_SUBC_INC0);
1096 + ch7006_load_reg(client, state, CH7006_SUBC_INC1);
1097 + ch7006_load_reg(client, state, CH7006_SUBC_INC2);
1098 + ch7006_load_reg(client, state, CH7006_SUBC_INC3);
1099 + ch7006_load_reg(client, state, CH7006_SUBC_INC4);
1100 + ch7006_load_reg(client, state, CH7006_SUBC_INC5);
1101 + ch7006_load_reg(client, state, CH7006_SUBC_INC6);
1102 + ch7006_load_reg(client, state, CH7006_SUBC_INC7);
1103 + ch7006_load_reg(client, state, CH7006_PLL_CONTROL);
1104 + ch7006_load_reg(client, state, CH7006_CALC_SUBC_INC0);
1105 +
1106 + /* I don't know what this is for, but otherwise I get no
1107 + * signal.
1108 + */
1109 + ch7006_write(client, 0x3d, 0x0);
1110 +}
1111 +
1112 +void ch7006_state_save(struct i2c_client *client,
1113 + struct ch7006_state *state)
1114 +{
1115 + ch7006_save_reg(client, state, CH7006_POWER);
1116 +
1117 + ch7006_save_reg(client, state, CH7006_DISPMODE);
1118 + ch7006_save_reg(client, state, CH7006_FFILTER);
1119 + ch7006_save_reg(client, state, CH7006_BWIDTH);
1120 + ch7006_save_reg(client, state, CH7006_INPUT_FORMAT);
1121 + ch7006_save_reg(client, state, CH7006_CLKMODE);
1122 + ch7006_save_reg(client, state, CH7006_START_ACTIVE);
1123 + ch7006_save_reg(client, state, CH7006_POV);
1124 + ch7006_save_reg(client, state, CH7006_BLACK_LEVEL);
1125 + ch7006_save_reg(client, state, CH7006_HPOS);
1126 + ch7006_save_reg(client, state, CH7006_VPOS);
1127 + ch7006_save_reg(client, state, CH7006_INPUT_SYNC);
1128 + ch7006_save_reg(client, state, CH7006_DETECT);
1129 + ch7006_save_reg(client, state, CH7006_CONTRAST);
1130 + ch7006_save_reg(client, state, CH7006_PLLOV);
1131 + ch7006_save_reg(client, state, CH7006_PLLM);
1132 + ch7006_save_reg(client, state, CH7006_PLLN);
1133 + ch7006_save_reg(client, state, CH7006_BCLKOUT);
1134 + ch7006_save_reg(client, state, CH7006_SUBC_INC0);
1135 + ch7006_save_reg(client, state, CH7006_SUBC_INC1);
1136 + ch7006_save_reg(client, state, CH7006_SUBC_INC2);
1137 + ch7006_save_reg(client, state, CH7006_SUBC_INC3);
1138 + ch7006_save_reg(client, state, CH7006_SUBC_INC4);
1139 + ch7006_save_reg(client, state, CH7006_SUBC_INC5);
1140 + ch7006_save_reg(client, state, CH7006_SUBC_INC6);
1141 + ch7006_save_reg(client, state, CH7006_SUBC_INC7);
1142 + ch7006_save_reg(client, state, CH7006_PLL_CONTROL);
1143 + ch7006_save_reg(client, state, CH7006_CALC_SUBC_INC0);
1144 +
1145 + state->regs[CH7006_FFILTER] = (state->regs[CH7006_FFILTER] & 0xf0) |
1146 + (state->regs[CH7006_FFILTER] & 0x0c) >> 2 |
1147 + (state->regs[CH7006_FFILTER] & 0x03) << 2;
1148 +}
1149 diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h
1150 new file mode 100644
1151 index 0000000..576bbea
1152 --- /dev/null
1153 +++ b/drivers/gpu/drm/i2c/ch7006_priv.h
1154 @@ -0,0 +1,340 @@
1155 +/*
1156 + * Copyright (C) 2009 Francisco Jerez.
1157 + * All Rights Reserved.
1158 + *
1159 + * Permission is hereby granted, free of charge, to any person obtaining
1160 + * a copy of this software and associated documentation files (the
1161 + * "Software"), to deal in the Software without restriction, including
1162 + * without limitation the rights to use, copy, modify, merge, publish,
1163 + * distribute, sublicense, and/or sell copies of the Software, and to
1164 + * permit persons to whom the Software is furnished to do so, subject to
1165 + * the following conditions:
1166 + *
1167 + * The above copyright notice and this permission notice (including the
1168 + * next paragraph) shall be included in all copies or substantial
1169 + * portions of the Software.
1170 + *
1171 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1172 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1173 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1174 + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
1175 + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1176 + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1177 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1178 + *
1179 + */
1180 +
1181 +#ifndef __DRM_I2C_CH7006_PRIV_H__
1182 +#define __DRM_I2C_CH7006_PRIV_H__
1183 +
1184 +#include "drmP.h"
1185 +#include "drm_crtc_helper.h"
1186 +#include "drm_encoder_slave.h"
1187 +#include "i2c/ch7006.h"
1188 +
1189 +typedef int64_t fixed;
1190 +#define fixed1 (1LL << 32)
1191 +
1192 +enum ch7006_tv_norm {
1193 + TV_NORM_PAL,
1194 + TV_NORM_PAL_M,
1195 + TV_NORM_PAL_N,
1196 + TV_NORM_PAL_NC,
1197 + TV_NORM_PAL_60,
1198 + TV_NORM_NTSC_M,
1199 + TV_NORM_NTSC_J,
1200 + NUM_TV_NORMS
1201 +};
1202 +
1203 +struct ch7006_tv_norm_info {
1204 + fixed vrefresh;
1205 + int vdisplay;
1206 + int vtotal;
1207 + int hvirtual;
1208 +
1209 + fixed subc_freq;
1210 + fixed black_level;
1211 +
1212 + uint32_t dispmode;
1213 + int voffset;
1214 +};
1215 +
1216 +struct ch7006_mode {
1217 + struct drm_display_mode mode;
1218 +
1219 + int enc_hdisp;
1220 + int enc_vdisp;
1221 +
1222 + fixed subc_coeff;
1223 + uint32_t dispmode;
1224 +
1225 + uint32_t valid_scales;
1226 + uint32_t valid_norms;
1227 +};
1228 +
1229 +struct ch7006_state {
1230 + uint8_t regs[0x26];
1231 +};
1232 +
1233 +struct ch7006_priv {
1234 + struct ch7006_encoder_params *params;
1235 + struct ch7006_mode *mode;
1236 +
1237 + struct ch7006_state state;
1238 + struct ch7006_state saved_state;
1239 +
1240 + struct drm_property *scale_property;
1241 +
1242 + int select_subconnector;
1243 + int subconnector;
1244 + int hmargin;
1245 + int vmargin;
1246 + enum ch7006_tv_norm norm;
1247 + int brightness;
1248 + int contrast;
1249 + int flicker;
1250 + int scale;
1251 +
1252 + int last_dpms;
1253 +};
1254 +
1255 +#define to_ch7006_priv(x) ((struct ch7006_priv *)to_encoder_slave(x)->slave_priv)
1256 +
1257 +extern int ch7006_debug;
1258 +extern char *ch7006_tv_norm;
1259 +extern int ch7006_scale;
1260 +
1261 +extern char *ch7006_tv_norm_names[];
1262 +extern struct ch7006_tv_norm_info ch7006_tv_norms[];
1263 +extern struct ch7006_mode ch7006_modes[];
1264 +
1265 +struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder,
1266 + struct drm_display_mode *drm_mode);
1267 +
1268 +void ch7006_setup_levels(struct drm_encoder *encoder);
1269 +void ch7006_setup_subcarrier(struct drm_encoder *encoder);
1270 +void ch7006_setup_pll(struct drm_encoder *encoder);
1271 +void ch7006_setup_power_state(struct drm_encoder *encoder);
1272 +void ch7006_setup_properties(struct drm_encoder *encoder);
1273 +
1274 +void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val);
1275 +uint8_t ch7006_read(struct i2c_client *client, uint8_t addr);
1276 +
1277 +void ch7006_state_load(struct i2c_client *client,
1278 + struct ch7006_state *state);
1279 +void ch7006_state_save(struct i2c_client *client,
1280 + struct ch7006_state *state);
1281 +
1282 +/* Some helper macros */
1283 +
1284 +#define ch7006_dbg(client, format, ...) do { \
1285 + if (ch7006_debug) \
1286 + dev_printk(KERN_DEBUG, &client->dev, \
1287 + "%s: " format, __func__, ## __VA_ARGS__); \
1288 + } while (0)
1289 +#define ch7006_info(client, format, ...) dev_info(&client->dev, format, __VA_ARGS__)
1290 +#define ch7006_err(client, format, ...) dev_err(&client->dev, format, __VA_ARGS__)
1291 +
1292 +#define __mask(src, bitfield) (((2 << (1?bitfield)) - 1) & ~((1 << (0?bitfield)) - 1))
1293 +#define mask(bitfield) __mask(bitfield)
1294 +
1295 +#define __bitf(src, bitfield, x) (((x) >> (src) << (0?bitfield)) & \
1296 + __mask(src, bitfield))
1297 +#define bitf(bitfield, x) __bitf(bitfield, x)
1298 +#define bitfs(bitfield, s) __bitf(bitfield, bitfield##_##s)
1299 +#define setbitf(state, reg, bitfield, x) \
1300 + state->regs[reg] = (state->regs[reg] & ~mask(reg##_##bitfield)) \
1301 + | bitf(reg##_##bitfield, x)
1302 +
1303 +#define __unbitf(src, bitfield, x) ((x & __mask(src, bitfield)) \
1304 + >> (0?bitfield) << (src))
1305 +#define unbitf(bitfield, x) __unbitf(bitfield, x)
1306 +
1307 +static inline int interpolate(int y0, int y1, int y2, int x)
1308 +{
1309 + return y1 + (x < 50 ? y1 - y0 : y2 - y1) * (x - 50) / 50;
1310 +}
1311 +
1312 +static inline int32_t round_fixed(fixed x)
1313 +{
1314 + return (x + fixed1/2) >> 32;
1315 +}
1316 +
1317 +#define ch7006_load_reg(client, state, reg) ch7006_write(client, reg, state->regs[reg])
1318 +#define ch7006_save_reg(client, state, reg) state->regs[reg] = ch7006_read(client, reg)
1319 +
1320 +/* Fixed hardware specs */
1321 +
1322 +#define CH7006_FREQ0 14318
1323 +#define CH7006_MAXN 650
1324 +#define CH7006_MAXM 315
1325 +
1326 +/* Register definitions */
1327 +
1328 +#define CH7006_DISPMODE 0x00
1329 +#define CH7006_DISPMODE_INPUT_RES 0, 7:5
1330 +#define CH7006_DISPMODE_INPUT_RES_512x384 0x0
1331 +#define CH7006_DISPMODE_INPUT_RES_720x400 0x1
1332 +#define CH7006_DISPMODE_INPUT_RES_640x400 0x2
1333 +#define CH7006_DISPMODE_INPUT_RES_640x480 0x3
1334 +#define CH7006_DISPMODE_INPUT_RES_800x600 0x4
1335 +#define CH7006_DISPMODE_INPUT_RES_NATIVE 0x5
1336 +#define CH7006_DISPMODE_OUTPUT_STD 0, 4:3
1337 +#define CH7006_DISPMODE_OUTPUT_STD_PAL 0x0
1338 +#define CH7006_DISPMODE_OUTPUT_STD_NTSC 0x1
1339 +#define CH7006_DISPMODE_OUTPUT_STD_PAL_M 0x2
1340 +#define CH7006_DISPMODE_OUTPUT_STD_NTSC_J 0x3
1341 +#define CH7006_DISPMODE_SCALING_RATIO 0, 2:0
1342 +#define CH7006_DISPMODE_SCALING_RATIO_5_4 0x0
1343 +#define CH7006_DISPMODE_SCALING_RATIO_1_1 0x1
1344 +#define CH7006_DISPMODE_SCALING_RATIO_7_8 0x2
1345 +#define CH7006_DISPMODE_SCALING_RATIO_5_6 0x3
1346 +#define CH7006_DISPMODE_SCALING_RATIO_3_4 0x4
1347 +#define CH7006_DISPMODE_SCALING_RATIO_7_10 0x5
1348 +
1349 +#define CH7006_FFILTER 0x01
1350 +#define CH7006_FFILTER_TEXT 0, 5:4
1351 +#define CH7006_FFILTER_LUMA 0, 3:2
1352 +#define CH7006_FFILTER_CHROMA 0, 1:0
1353 +#define CH7006_FFILTER_CHROMA_NO_DCRAWL 0x3
1354 +
1355 +#define CH7006_BWIDTH 0x03
1356 +#define CH7006_BWIDTH_5L_FFILER (1 << 7)
1357 +#define CH7006_BWIDTH_CVBS_NO_CHROMA (1 << 6)
1358 +#define CH7006_BWIDTH_CHROMA 0, 5:4
1359 +#define CH7006_BWIDTH_SVIDEO_YPEAK (1 << 3)
1360 +#define CH7006_BWIDTH_SVIDEO_LUMA 0, 2:1
1361 +#define CH7006_BWIDTH_CVBS_LUMA 0, 0:0
1362 +
1363 +#define CH7006_INPUT_FORMAT 0x04
1364 +#define CH7006_INPUT_FORMAT_DAC_GAIN (1 << 6)
1365 +#define CH7006_INPUT_FORMAT_RGB_PASS_THROUGH (1 << 5)
1366 +#define CH7006_INPUT_FORMAT_FORMAT 0, 3:0
1367 +#define CH7006_INPUT_FORMAT_FORMAT_RGB16 0x0
1368 +#define CH7006_INPUT_FORMAT_FORMAT_YCrCb24m16 0x1
1369 +#define CH7006_INPUT_FORMAT_FORMAT_RGB24m16 0x2
1370 +#define CH7006_INPUT_FORMAT_FORMAT_RGB15 0x3
1371 +#define CH7006_INPUT_FORMAT_FORMAT_RGB24m12C 0x4
1372 +#define CH7006_INPUT_FORMAT_FORMAT_RGB24m12I 0x5
1373 +#define CH7006_INPUT_FORMAT_FORMAT_RGB24m8 0x6
1374 +#define CH7006_INPUT_FORMAT_FORMAT_RGB16m8 0x7
1375 +#define CH7006_INPUT_FORMAT_FORMAT_RGB15m8 0x8
1376 +#define CH7006_INPUT_FORMAT_FORMAT_YCrCb24m8 0x9
1377 +
1378 +#define CH7006_CLKMODE 0x06
1379 +#define CH7006_CLKMODE_SUBC_LOCK (1 << 7)
1380 +#define CH7006_CLKMODE_MASTER (1 << 6)
1381 +#define CH7006_CLKMODE_POS_EDGE (1 << 4)
1382 +#define CH7006_CLKMODE_XCM 0, 3:2
1383 +#define CH7006_CLKMODE_PCM 0, 1:0
1384 +
1385 +#define CH7006_START_ACTIVE 0x07
1386 +#define CH7006_START_ACTIVE_0 0, 7:0
1387 +
1388 +#define CH7006_POV 0x08
1389 +#define CH7006_POV_START_ACTIVE_8 8, 2:2
1390 +#define CH7006_POV_HPOS_8 8, 1:1
1391 +#define CH7006_POV_VPOS_8 8, 0:0
1392 +
1393 +#define CH7006_BLACK_LEVEL 0x09
1394 +#define CH7006_BLACK_LEVEL_0 0, 7:0
1395 +
1396 +#define CH7006_HPOS 0x0a
1397 +#define CH7006_HPOS_0 0, 7:0
1398 +
1399 +#define CH7006_VPOS 0x0b
1400 +#define CH7006_VPOS_0 0, 7:0
1401 +
1402 +#define CH7006_INPUT_SYNC 0x0d
1403 +#define CH7006_INPUT_SYNC_EMBEDDED (1 << 3)
1404 +#define CH7006_INPUT_SYNC_OUTPUT (1 << 2)
1405 +#define CH7006_INPUT_SYNC_PVSYNC (1 << 1)
1406 +#define CH7006_INPUT_SYNC_PHSYNC (1 << 0)
1407 +
1408 +#define CH7006_POWER 0x0e
1409 +#define CH7006_POWER_SCART (1 << 4)
1410 +#define CH7006_POWER_RESET (1 << 3)
1411 +#define CH7006_POWER_LEVEL 0, 2:0
1412 +#define CH7006_POWER_LEVEL_CVBS_OFF 0x0
1413 +#define CH7006_POWER_LEVEL_POWER_OFF 0x1
1414 +#define CH7006_POWER_LEVEL_SVIDEO_OFF 0x2
1415 +#define CH7006_POWER_LEVEL_NORMAL 0x3
1416 +#define CH7006_POWER_LEVEL_FULL_POWER_OFF 0x4
1417 +
1418 +#define CH7006_DETECT 0x10
1419 +#define CH7006_DETECT_SVIDEO_Y_TEST (1 << 3)
1420 +#define CH7006_DETECT_SVIDEO_C_TEST (1 << 2)
1421 +#define CH7006_DETECT_CVBS_TEST (1 << 1)
1422 +#define CH7006_DETECT_SENSE (1 << 0)
1423 +
1424 +#define CH7006_CONTRAST 0x11
1425 +#define CH7006_CONTRAST_0 0, 2:0
1426 +
1427 +#define CH7006_PLLOV 0x13
1428 +#define CH7006_PLLOV_N_8 8, 2:1
1429 +#define CH7006_PLLOV_M_8 8, 0:0
1430 +
1431 +#define CH7006_PLLM 0x14
1432 +#define CH7006_PLLM_0 0, 7:0
1433 +
1434 +#define CH7006_PLLN 0x15
1435 +#define CH7006_PLLN_0 0, 7:0
1436 +
1437 +#define CH7006_BCLKOUT 0x17
1438 +
1439 +#define CH7006_SUBC_INC0 0x18
1440 +#define CH7006_SUBC_INC0_28 28, 3:0
1441 +
1442 +#define CH7006_SUBC_INC1 0x19
1443 +#define CH7006_SUBC_INC1_24 24, 3:0
1444 +
1445 +#define CH7006_SUBC_INC2 0x1a
1446 +#define CH7006_SUBC_INC2_20 20, 3:0
1447 +
1448 +#define CH7006_SUBC_INC3 0x1b
1449 +#define CH7006_SUBC_INC3_GPIO1_VAL (1 << 7)
1450 +#define CH7006_SUBC_INC3_GPIO0_VAL (1 << 6)
1451 +#define CH7006_SUBC_INC3_POUT_3_3V (1 << 5)
1452 +#define CH7006_SUBC_INC3_POUT_INV (1 << 4)
1453 +#define CH7006_SUBC_INC3_16 16, 3:0
1454 +
1455 +#define CH7006_SUBC_INC4 0x1c
1456 +#define CH7006_SUBC_INC4_GPIO1_IN (1 << 7)
1457 +#define CH7006_SUBC_INC4_GPIO0_IN (1 << 6)
1458 +#define CH7006_SUBC_INC4_DS_INPUT (1 << 4)
1459 +#define CH7006_SUBC_INC4_12 12, 3:0
1460 +
1461 +#define CH7006_SUBC_INC5 0x1d
1462 +#define CH7006_SUBC_INC5_8 8, 3:0
1463 +
1464 +#define CH7006_SUBC_INC6 0x1e
1465 +#define CH7006_SUBC_INC6_4 4, 3:0
1466 +
1467 +#define CH7006_SUBC_INC7 0x1f
1468 +#define CH7006_SUBC_INC7_0 0, 3:0
1469 +
1470 +#define CH7006_PLL_CONTROL 0x20
1471 +#define CH7006_PLL_CONTROL_CPI (1 << 5)
1472 +#define CH7006_PLL_CONTROL_CAPACITOR (1 << 4)
1473 +#define CH7006_PLL_CONTROL_7STAGES (1 << 3)
1474 +#define CH7006_PLL_CONTROL_DIGITAL_5V (1 << 2)
1475 +#define CH7006_PLL_CONTROL_ANALOG_5V (1 << 1)
1476 +#define CH7006_PLL_CONTROL_MEMORY_5V (1 << 0)
1477 +
1478 +#define CH7006_CALC_SUBC_INC0 0x21
1479 +#define CH7006_CALC_SUBC_INC0_24 24, 4:3
1480 +#define CH7006_CALC_SUBC_INC0_HYST 0, 2:1
1481 +#define CH7006_CALC_SUBC_INC0_AUTO (1 << 0)
1482 +
1483 +#define CH7006_CALC_SUBC_INC1 0x22
1484 +#define CH7006_CALC_SUBC_INC1_16 16, 7:0
1485 +
1486 +#define CH7006_CALC_SUBC_INC2 0x23
1487 +#define CH7006_CALC_SUBC_INC2_8 8, 7:0
1488 +
1489 +#define CH7006_CALC_SUBC_INC3 0x24
1490 +#define CH7006_CALC_SUBC_INC3_0 0, 7:0
1491 +
1492 +#define CH7006_VERSION_ID 0x25
1493 +
1494 +#endif
1495 diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
1496 new file mode 100644
1497 index 0000000..a4e8223
1498 --- /dev/null
1499 +++ b/drivers/gpu/drm/nouveau/Makefile
1500 @@ -0,0 +1,28 @@
1501 +#
1502 +# Makefile for the drm device driver. This driver provides support for the
1503 +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
1504 +
1505 +ccflags-y := -Iinclude/drm
1506 +nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
1507 + nouveau_object.o nouveau_irq.o nouveau_notifier.o \
1508 + nouveau_sgdma.o nouveau_dma.o \
1509 + nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
1510 + nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
1511 + nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
1512 + nv04_timer.o \
1513 + nv04_mc.o nv40_mc.o nv50_mc.o \
1514 + nv04_fb.o nv10_fb.o nv40_fb.o \
1515 + nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
1516 + nv04_graph.o nv10_graph.o nv20_graph.o \
1517 + nv40_graph.o nv50_graph.o \
1518 + nv04_instmem.o nv50_instmem.o \
1519 + nv50_crtc.o nv50_dac.o nv50_sor.o \
1520 + nv50_cursor.o nv50_display.o nv50_fbcon.o \
1521 + nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
1522 + nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o
1523 +
1524 +nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
1525 +nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
1526 +nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
1527 +
1528 +obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
1529 diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
1530 new file mode 100644
1531 index 0000000..49514c6
1532 --- /dev/null
1533 +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
1534 @@ -0,0 +1,127 @@
1535 +#include <linux/pci.h>
1536 +#include <linux/acpi.h>
1537 +#include <acpi/acpi_drivers.h>
1538 +#include <acpi/acpi_bus.h>
1539 +
1540 +#include "drmP.h"
1541 +#include "drm.h"
1542 +#include "drm_sarea.h"
1543 +#include "drm_crtc_helper.h"
1544 +#include "nouveau_drv.h"
1545 +#include "nouveau_drm.h"
1546 +#include "nv50_display.h"
1547 +
1548 +#define NOUVEAU_DSM_SUPPORTED 0x00
1549 +#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
1550 +
1551 +#define NOUVEAU_DSM_ACTIVE 0x01
1552 +#define NOUVEAU_DSM_ACTIVE_QUERY 0x00
1553 +
1554 +#define NOUVEAU_DSM_LED 0x02
1555 +#define NOUVEAU_DSM_LED_STATE 0x00
1556 +#define NOUVEAU_DSM_LED_OFF 0x10
1557 +#define NOUVEAU_DSM_LED_STAMINA 0x11
1558 +#define NOUVEAU_DSM_LED_SPEED 0x12
1559 +
1560 +#define NOUVEAU_DSM_POWER 0x03
1561 +#define NOUVEAU_DSM_POWER_STATE 0x00
1562 +#define NOUVEAU_DSM_POWER_SPEED 0x01
1563 +#define NOUVEAU_DSM_POWER_STAMINA 0x02
1564 +
1565 +static int nvidia_dsm(struct pci_dev *dev, int func, int arg, int *result)
1566 +{
1567 + static char muid[] = {
1568 + 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
1569 + 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
1570 + };
1571 +
1572 + struct acpi_handle *handle;
1573 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1574 + struct acpi_object_list input;
1575 + union acpi_object params[4];
1576 + union acpi_object *obj;
1577 + int err;
1578 +
1579 + handle = DEVICE_ACPI_HANDLE(&dev->dev);
1580 +
1581 + if (!handle)
1582 + return -ENODEV;
1583 +
1584 + input.count = 4;
1585 + input.pointer = params;
1586 + params[0].type = ACPI_TYPE_BUFFER;
1587 + params[0].buffer.length = sizeof(muid);
1588 + params[0].buffer.pointer = (char *)muid;
1589 + params[1].type = ACPI_TYPE_INTEGER;
1590 + params[1].integer.value = 0x00000102;
1591 + params[2].type = ACPI_TYPE_INTEGER;
1592 + params[2].integer.value = func;
1593 + params[3].type = ACPI_TYPE_INTEGER;
1594 + params[3].integer.value = arg;
1595 +
1596 + err = acpi_evaluate_object(handle, "_DSM", &input, &output);
1597 + if (err) {
1598 + printk(KERN_ERR "nvidia-control: failed to evaluate _DSM: %d\n",
1599 + err);
1600 + return err;
1601 + }
1602 +
1603 + obj = (union acpi_object *)output.pointer;
1604 +
1605 + if (obj->type == ACPI_TYPE_INTEGER)
1606 + if (obj->integer.value == 0x80000002)
1607 + return -ENODEV;
1608 +
1609 + if (obj->type == ACPI_TYPE_BUFFER) {
1610 + if (obj->buffer.length == 4 && result) {
1611 + *result = 0;
1612 + *result |= obj->buffer.pointer[0];
1613 + *result |= (obj->buffer.pointer[1] << 8);
1614 + *result |= (obj->buffer.pointer[2] << 16);
1615 + *result |= (obj->buffer.pointer[3] << 24);
1616 + }
1617 + }
1618 +
1619 + kfree(output.pointer);
1620 + return 0;
1621 +}
1622 +
1623 +int nouveau_hybrid_setup(struct drm_device *dev)
1624 +{
1625 + struct pci_dev *pdev = dev->pdev;
1626 + int result;
1627 +
1628 + if (nvidia_dsm(pdev, NOUVEAU_DSM_ACTIVE, NOUVEAU_DSM_ACTIVE_QUERY,
1629 + &result))
1630 + return -ENODEV;
1631 +
1632 + printk(KERN_INFO "nouveau: _DSM hardware status gave 0x%x\n", result);
1633 +
1634 + if (result &= 0x1) { /* Stamina mode - disable the external GPU */
1635 + nvidia_dsm(pdev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA,
1636 + NULL);
1637 + nvidia_dsm(pdev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA,
1638 + NULL);
1639 + } else { /* Ensure that the external GPU is enabled */
1640 + nvidia_dsm(pdev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL);
1641 + nvidia_dsm(pdev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED,
1642 + NULL);
1643 + }
1644 +
1645 + return 0;
1646 +}
1647 +
1648 +bool nouveau_dsm_probe(struct drm_device *dev)
1649 +{
1650 + struct pci_dev *pdev = dev->pdev;
1651 + int support = 0;
1652 +
1653 + if (nvidia_dsm(pdev, NOUVEAU_DSM_SUPPORTED,
1654 + NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &support))
1655 + return false;
1656 +
1657 + if (!support)
1658 + return false;
1659 +
1660 + return true;
1661 +}
1662 diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
1663 new file mode 100644
1664 index 0000000..20564f8
1665 --- /dev/null
1666 +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
1667 @@ -0,0 +1,155 @@
1668 +/*
1669 + * Copyright (C) 2009 Red Hat <mjg@redhat.com>
1670 + *
1671 + * Permission is hereby granted, free of charge, to any person obtaining
1672 + * a copy of this software and associated documentation files (the
1673 + * "Software"), to deal in the Software without restriction, including
1674 + * without limitation the rights to use, copy, modify, merge, publish,
1675 + * distribute, sublicense, and/or sell copies of the Software, and to
1676 + * permit persons to whom the Software is furnished to do so, subject to
1677 + * the following conditions:
1678 + *
1679 + * The above copyright notice and this permission notice (including the
1680 + * next paragraph) shall be included in all copies or substantial
1681 + * portions of the Software.
1682 + *
1683 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1684 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1685 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1686 + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
1687 + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1688 + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1689 + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1690 + *
1691 + */
1692 +
1693 +/*
1694 + * Authors:
1695 + * Matthew Garrett <mjg@redhat.com>
1696 + *
1697 + * Register locations derived from NVClock by Roderick Colenbrander
1698 + */
1699 +
1700 +#include <linux/backlight.h>
1701 +
1702 +#include "drmP.h"
1703 +#include "nouveau_drv.h"
1704 +#include "nouveau_drm.h"
1705 +#include "nouveau_reg.h"
1706 +
1707 +static int nv40_get_intensity(struct backlight_device *bd)
1708 +{
1709 + struct drm_device *dev = bl_get_data(bd);
1710 + int val = (nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)
1711 + >> 16;
1712 +
1713 + return val;
1714 +}
1715 +
1716 +static int nv40_set_intensity(struct backlight_device *bd)
1717 +{
1718 + struct drm_device *dev = bl_get_data(bd);
1719 + int val = bd->props.brightness;
1720 + int reg = nv_rd32(dev, NV40_PMC_BACKLIGHT);
1721 +
1722 + nv_wr32(dev, NV40_PMC_BACKLIGHT,
1723 + (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK));
1724 +
1725 + return 0;
1726 +}
1727 +
1728 +static struct backlight_ops nv40_bl_ops = {
1729 + .options = BL_CORE_SUSPENDRESUME,
1730 + .get_brightness = nv40_get_intensity,
1731 + .update_status = nv40_set_intensity,
1732 +};
1733 +
1734 +static int nv50_get_intensity(struct backlight_device *bd)
1735 +{
1736 + struct drm_device *dev = bl_get_data(bd);
1737 +
1738 + return nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT);
1739 +}
1740 +
1741 +static int nv50_set_intensity(struct backlight_device *bd)
1742 +{
1743 + struct drm_device *dev = bl_get_data(bd);
1744 + int val = bd->props.brightness;
1745 +
1746 + nv_wr32(dev, NV50_PDISPLAY_SOR_BACKLIGHT,
1747 + val | NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE);
1748 + return 0;
1749 +}
1750 +
1751 +static struct backlight_ops nv50_bl_ops = {
1752 + .options = BL_CORE_SUSPENDRESUME,
1753 + .get_brightness = nv50_get_intensity,
1754 + .update_status = nv50_set_intensity,
1755 +};
1756 +
1757 +static int nouveau_nv40_backlight_init(struct drm_device *dev)
1758 +{
1759 + struct drm_nouveau_private *dev_priv = dev->dev_private;
1760 + struct backlight_device *bd;
1761 +
1762 + if (!(nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK))
1763 + return 0;
1764 +
1765 + bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
1766 + &nv40_bl_ops);
1767 + if (IS_ERR(bd))
1768 + return PTR_ERR(bd);
1769 +
1770 + dev_priv->backlight = bd;
1771 + bd->props.max_brightness = 31;
1772 + bd->props.brightness = nv40_get_intensity(bd);
1773 + backlight_update_status(bd);
1774 +
1775 + return 0;
1776 +}
1777 +
1778 +static int nouveau_nv50_backlight_init(struct drm_device *dev)
1779 +{
1780 + struct drm_nouveau_private *dev_priv = dev->dev_private;
1781 + struct backlight_device *bd;
1782 +
1783 + if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT))
1784 + return 0;
1785 +
1786 + bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
1787 + &nv50_bl_ops);
1788 + if (IS_ERR(bd))
1789 + return PTR_ERR(bd);
1790 +
1791 + dev_priv->backlight = bd;
1792 + bd->props.max_brightness = 1025;
1793 + bd->props.brightness = nv50_get_intensity(bd);
1794 + backlight_update_status(bd);
1795 + return 0;
1796 +}
1797 +
1798 +int nouveau_backlight_init(struct drm_device *dev)
1799 +{
1800 + struct drm_nouveau_private *dev_priv = dev->dev_private;
1801 +
1802 + switch (dev_priv->card_type) {
1803 + case NV_40:
1804 + return nouveau_nv40_backlight_init(dev);
1805 + case NV_50:
1806 + return nouveau_nv50_backlight_init(dev);
1807 + default:
1808 + break;
1809 + }
1810 +
1811 + return 0;
1812 +}
1813 +
1814 +void nouveau_backlight_exit(struct drm_device *dev)
1815 +{
1816 + struct drm_nouveau_private *dev_priv = dev->dev_private;
1817 +
1818 + if (dev_priv->backlight) {
1819 + backlight_device_unregister(dev_priv->backlight);
1820 + dev_priv->backlight = NULL;
1821 + }
1822 +}
1823 diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
1824 new file mode 100644
1825 index 0000000..b37ad94
1826 --- /dev/null
1827 +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
1828 @@ -0,0 +1,5209 @@
1829 +/*
1830 + * Copyright 2005-2006 Erik Waling
1831 + * Copyright 2006 Stephane Marchesin
1832 + * Copyright 2007-2009 Stuart Bennett
1833 + *
1834 + * Permission is hereby granted, free of charge, to any person obtaining a
1835 + * copy of this software and associated documentation files (the "Software"),
1836 + * to deal in the Software without restriction, including without limitation
1837 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1838 + * and/or sell copies of the Software, and to permit persons to whom the
1839 + * Software is furnished to do so, subject to the following conditions:
1840 + *
1841 + * The above copyright notice and this permission notice shall be included in
1842 + * all copies or substantial portions of the Software.
1843 + *
1844 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1845 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1846 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1847 + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1848 + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
1849 + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1850 + * SOFTWARE.
1851 + */
1852 +
1853 +#include "drmP.h"
1854 +#define NV_DEBUG_NOTRACE
1855 +#include "nouveau_drv.h"
1856 +#include "nouveau_hw.h"
1857 +
1858 +/* these defines are made up */
1859 +#define NV_CIO_CRE_44_HEADA 0x0
1860 +#define NV_CIO_CRE_44_HEADB 0x3
1861 +#define FEATURE_MOBILE 0x10 /* also FEATURE_QUADRO for BMP */
1862 +#define LEGACY_I2C_CRT 0x80
1863 +#define LEGACY_I2C_PANEL 0x81
1864 +#define LEGACY_I2C_TV 0x82
1865 +
1866 +#define EDID1_LEN 128
1867 +
1868 +#define BIOSLOG(sip, fmt, arg...) NV_DEBUG(sip->dev, fmt, ##arg)
1869 +#define LOG_OLD_VALUE(x) //x
1870 +
1871 +#define BIOS_USLEEP(n) mdelay((n)/1000)
1872 +
1873 +#define ROM16(x) le16_to_cpu(*(uint16_t *)&(x))
1874 +#define ROM32(x) le32_to_cpu(*(uint32_t *)&(x))
1875 +
1876 +struct init_exec {
1877 + bool execute;
1878 + bool repeat;
1879 +};
1880 +
1881 +static bool nv_cksum(const uint8_t *data, unsigned int length)
1882 +{
1883 + /* there's a few checksums in the BIOS, so here's a generic checking function */
1884 + int i;
1885 + uint8_t sum = 0;
1886 +
1887 + for (i = 0; i < length; i++)
1888 + sum += data[i];
1889 +
1890 + if (sum)
1891 + return true;
1892 +
1893 + return false;
1894 +}
1895 +
1896 +static int
1897 +score_vbios(struct drm_device *dev, const uint8_t *data, const bool writeable)
1898 +{
1899 + if (!(data[0] == 0x55 && data[1] == 0xAA)) {
1900 + NV_TRACEWARN(dev, "... BIOS signature not found\n");
1901 + return 0;
1902 + }
1903 +
1904 + if (nv_cksum(data, data[2] * 512)) {
1905 + NV_TRACEWARN(dev, "... BIOS checksum invalid\n");
1906 + /* if a ro image is somewhat bad, it's probably all rubbish */
1907 + return writeable ? 2 : 1;
1908 + } else
1909 + NV_TRACE(dev, "... appears to be valid\n");
1910 +
1911 + return 3;
1912 +}
1913 +
1914 +static void load_vbios_prom(struct drm_device *dev, uint8_t *data)
1915 +{
1916 + uint32_t pci_nv_20, save_pci_nv_20;
1917 + int pcir_ptr;
1918 + int i;
1919 +
1920 + if (nv_arch(dev) >= NV_50)
1921 + pci_nv_20 = 0x88050;
1922 + else
1923 + pci_nv_20 = NV_PBUS_PCI_NV_20;
1924 +
1925 + /* enable ROM access */
1926 + save_pci_nv_20 = nvReadMC(dev, pci_nv_20);
1927 + nvWriteMC(dev, pci_nv_20,
1928 + save_pci_nv_20 & ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
1929 +
1930 + /* bail if no rom signature */
1931 + if (nv_rd08(dev, NV_PROM_OFFSET) != 0x55 ||
1932 + nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
1933 + goto out;
1934 +
1935 + /* additional check (see note below) - read PCI record header */
1936 + pcir_ptr = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
1937 + nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
1938 + if (nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr) != 'P' ||
1939 + nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 1) != 'C' ||
1940 + nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 2) != 'I' ||
1941 + nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 3) != 'R')
1942 + goto out;
1943 +
1944 + /* on some 6600GT/6800LE prom reads are messed up. nvclock alleges a
1945 + * a good read may be obtained by waiting or re-reading (cargocult: 5x)
1946 + * each byte. we'll hope pramin has something usable instead
1947 + */
1948 + for (i = 0; i < NV_PROM_SIZE; i++)
1949 + data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
1950 +
1951 +out:
1952 + /* disable ROM access */
1953 + nvWriteMC(dev, pci_nv_20,
1954 + save_pci_nv_20 | NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
1955 +}
1956 +
1957 +static void load_vbios_pramin(struct drm_device *dev, uint8_t *data)
1958 +{
1959 + uint32_t old_bar0_pramin = 0;
1960 + int i;
1961 +
1962 + if (nv_arch(dev) >= NV_50) {
1963 + uint32_t vbios_vram = (nv_rd32(dev, 0x619f04) & ~0xff) << 8;
1964 +
1965 + if (!vbios_vram)
1966 + vbios_vram = (nv_rd32(dev, 0x1700) << 16) + 0xf0000;
1967 +
1968 + old_bar0_pramin = nv_rd32(dev, 0x1700);
1969 + nv_wr32(dev, 0x1700, vbios_vram >> 16);
1970 + }
1971 +
1972 + /* bail if no rom signature */
1973 + if (nv_rd08(dev, NV_PRAMIN_OFFSET) != 0x55 ||
1974 + nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa)
1975 + goto out;
1976 +
1977 + for (i = 0; i < NV_PROM_SIZE; i++)
1978 + data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
1979 +
1980 +out:
1981 + if (nv_arch(dev) >= NV_50)
1982 + nv_wr32(dev, 0x1700, old_bar0_pramin);
1983 +}
1984 +
1985 +static void load_vbios_pci(struct drm_device *dev, uint8_t *data)
1986 +{
1987 + void __iomem *rom = NULL;
1988 + size_t rom_len;
1989 + int ret;
1990 +
1991 + ret = pci_enable_rom(dev->pdev);
1992 + if (ret)
1993 + return;
1994 +
1995 + rom = pci_map_rom(dev->pdev, &rom_len);
1996 + if (!rom)
1997 + goto out;
1998 + memcpy_fromio(data, rom, rom_len);
1999 + pci_unmap_rom(dev->pdev, rom);
2000 +
2001 +out:
2002 + pci_disable_rom(dev->pdev);
2003 +}
2004 +
2005 +struct methods {
2006 + const char desc[8];
2007 + void (*loadbios)(struct drm_device *, uint8_t *);
2008 + const bool rw;
2009 + int score;
2010 +};
2011 +
2012 +static struct methods nv04_methods[] = {
2013 + { "PROM", load_vbios_prom, false },
2014 + { "PRAMIN", load_vbios_pramin, true },
2015 + { "PCI ROM", load_vbios_pci, true },
2016 + { }
2017 +};
2018 +
2019 +static struct methods nv50_methods[] = {
2020 + { "PRAMIN", load_vbios_pramin, true },
2021 + { "PROM", load_vbios_prom, false },
2022 + { "PCI ROM", load_vbios_pci, true },
2023 + { }
2024 +};
2025 +
2026 +static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
2027 +{
2028 + struct drm_nouveau_private *dev_priv = dev->dev_private;
2029 + struct methods *methods, *method;
2030 + int testscore = 3;
2031 +
2032 + if (dev_priv->card_type < NV_50)