blob: 2f1ed61f7c8c9e39d44c1528410eb4aaeb83fe17 [file] [log] [blame]
Ben Skeggs6ee73862009-12-11 19:24:15 +10001/*
2 * Copyright 2009 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Author: Ben Skeggs
23 */
24
Ben Skeggs21a5ace2013-01-31 09:04:48 +100025#include <core/object.h>
26#include <core/class.h>
27
David Howells760285e2012-10-02 18:01:07 +010028#include <drm/drmP.h>
29#include <drm/drm_crtc_helper.h>
Ben Skeggs6ee73862009-12-11 19:24:15 +100030
Ben Skeggs77145f12012-07-31 16:16:21 +100031#include "nouveau_drm.h"
32#include "nouveau_reg.h"
Ben Skeggs1a646342013-03-21 15:45:11 +100033#include "hw.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +100034#include "nouveau_encoder.h"
35#include "nouveau_connector.h"
36
Ben Skeggs5ed50202013-02-11 20:15:03 +100037#include <subdev/i2c.h>
38
Ben Skeggs6ee73862009-12-11 19:24:15 +100039int
Francisco Jerezc88c2e02010-07-24 17:37:33 +020040nv04_display_early_init(struct drm_device *dev)
41{
Ben Skeggsafada5e2011-11-22 13:59:30 +100042 /* ensure vblank interrupts are off, they can't be enabled until
43 * drm_vblank has been initialised
44 */
45 NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
46 if (nv_two_heads(dev))
47 NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
48
Francisco Jerezc88c2e02010-07-24 17:37:33 +020049 return 0;
50}
51
52void
53nv04_display_late_takedown(struct drm_device *dev)
54{
Francisco Jerezc88c2e02010-07-24 17:37:33 +020055}
56
57int
Ben Skeggs6ee73862009-12-11 19:24:15 +100058nv04_display_create(struct drm_device *dev)
59{
Ben Skeggs77145f12012-07-31 16:16:21 +100060 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs5ed50202013-02-11 20:15:03 +100061 struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
Ben Skeggs77145f12012-07-31 16:16:21 +100062 struct dcb_table *dcb = &drm->vbios.dcb;
Ben Skeggs8f1a6082010-06-28 14:35:50 +100063 struct drm_connector *connector, *ct;
Ben Skeggs6ee73862009-12-11 19:24:15 +100064 struct drm_encoder *encoder;
65 struct drm_crtc *crtc;
Ben Skeggs017e6e22012-07-18 10:00:50 +100066 struct nv04_display *disp;
Ben Skeggs6ee73862009-12-11 19:24:15 +100067 int i, ret;
68
Ben Skeggs017e6e22012-07-18 10:00:50 +100069 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
Ben Skeggs017e6e22012-07-18 10:00:50 +100070 if (!disp)
71 return -ENOMEM;
72
Ben Skeggs77145f12012-07-31 16:16:21 +100073 nouveau_display(dev)->priv = disp;
74 nouveau_display(dev)->dtor = nv04_display_destroy;
75 nouveau_display(dev)->init = nv04_display_init;
76 nouveau_display(dev)->fini = nv04_display_fini;
Ben Skeggs6ee73862009-12-11 19:24:15 +100077
Francisco Jerez95f158e2009-12-11 23:44:49 +010078 nouveau_hw_save_vga_fonts(dev, 1);
Ben Skeggs6ee73862009-12-11 19:24:15 +100079
Ben Skeggs6ee73862009-12-11 19:24:15 +100080 nv04_crtc_create(dev, 0);
81 if (nv_two_heads(dev))
82 nv04_crtc_create(dev, 1);
83
84 for (i = 0; i < dcb->entries; i++) {
Ben Skeggscb75d972012-07-11 10:44:20 +100085 struct dcb_output *dcbent = &dcb->entry[i];
Ben Skeggs6ee73862009-12-11 19:24:15 +100086
Ben Skeggs8f1a6082010-06-28 14:35:50 +100087 connector = nouveau_connector_create(dev, dcbent->connector);
88 if (IS_ERR(connector))
89 continue;
90
Ben Skeggs6ee73862009-12-11 19:24:15 +100091 switch (dcbent->type) {
Ben Skeggscb75d972012-07-11 10:44:20 +100092 case DCB_OUTPUT_ANALOG:
Ben Skeggs8f1a6082010-06-28 14:35:50 +100093 ret = nv04_dac_create(connector, dcbent);
Ben Skeggs6ee73862009-12-11 19:24:15 +100094 break;
Ben Skeggscb75d972012-07-11 10:44:20 +100095 case DCB_OUTPUT_LVDS:
96 case DCB_OUTPUT_TMDS:
Ben Skeggs8f1a6082010-06-28 14:35:50 +100097 ret = nv04_dfp_create(connector, dcbent);
Ben Skeggs6ee73862009-12-11 19:24:15 +100098 break;
Ben Skeggscb75d972012-07-11 10:44:20 +100099 case DCB_OUTPUT_TV:
Ben Skeggs6ee73862009-12-11 19:24:15 +1000100 if (dcbent->location == DCB_LOC_ON_CHIP)
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000101 ret = nv17_tv_create(connector, dcbent);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000102 else
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000103 ret = nv04_tv_create(connector, dcbent);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000104 break;
105 default:
Ben Skeggs77145f12012-07-31 16:16:21 +1000106 NV_WARN(drm, "DCB type %d not known\n", dcbent->type);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000107 continue;
108 }
109
110 if (ret)
111 continue;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000112 }
113
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000114 list_for_each_entry_safe(connector, ct,
115 &dev->mode_config.connector_list, head) {
116 if (!connector->encoder_ids[0]) {
Ben Skeggs77145f12012-07-31 16:16:21 +1000117 NV_WARN(drm, "%s has no encoders, removing\n",
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000118 drm_get_connector_name(connector));
119 connector->funcs->destroy(connector);
120 }
121 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000122
Ben Skeggs5ed50202013-02-11 20:15:03 +1000123 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
124 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
125 nv_encoder->i2c = i2c->find(i2c, nv_encoder->dcb->i2c_index);
126 }
127
Ben Skeggs6ee73862009-12-11 19:24:15 +1000128 /* Save previous state */
Ben Skeggs6ee73862009-12-11 19:24:15 +1000129 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
130 crtc->funcs->save(crtc);
131
132 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
133 struct drm_encoder_helper_funcs *func = encoder->helper_private;
134
135 func->save(encoder);
136 }
137
Ilia Mirkin515de6b2013-09-07 20:33:43 -0400138 nouveau_overlay_init(dev);
139
Ben Skeggs6ee73862009-12-11 19:24:15 +1000140 return 0;
141}
142
143void
144nv04_display_destroy(struct drm_device *dev)
145{
Ben Skeggs017e6e22012-07-18 10:00:50 +1000146 struct nv04_display *disp = nv04_display(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000147 struct drm_encoder *encoder;
148 struct drm_crtc *crtc;
149
Ben Skeggs6ee73862009-12-11 19:24:15 +1000150 /* Turn every CRTC off. */
151 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
152 struct drm_mode_set modeset = {
153 .crtc = crtc,
154 };
155
Daniel Vetter2d13b672012-12-11 13:47:23 +0100156 drm_mode_set_config_internal(&modeset);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000157 }
158
159 /* Restore state */
Ben Skeggs6ee73862009-12-11 19:24:15 +1000160 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
161 struct drm_encoder_helper_funcs *func = encoder->helper_private;
162
163 func->restore(encoder);
164 }
165
166 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
167 crtc->funcs->restore(crtc);
168
Francisco Jerez95f158e2009-12-11 23:44:49 +0100169 nouveau_hw_save_vga_fonts(dev, 0);
Ben Skeggs017e6e22012-07-18 10:00:50 +1000170
Ben Skeggs77145f12012-07-31 16:16:21 +1000171 nouveau_display(dev)->priv = NULL;
Ben Skeggs017e6e22012-07-18 10:00:50 +1000172 kfree(disp);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000173}
174
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200175int
176nv04_display_init(struct drm_device *dev)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000177{
Ben Skeggs6ee73862009-12-11 19:24:15 +1000178 struct drm_encoder *encoder;
179 struct drm_crtc *crtc;
180
Ben Skeggs6ee73862009-12-11 19:24:15 +1000181 /* meh.. modeset apparently doesn't setup all the regs and depends
182 * on pre-existing state, for now load the state of the card *before*
183 * nouveau was loaded, and then do a modeset.
184 *
185 * best thing to do probably is to make save/restore routines not
186 * save/restore "pre-load" state, but more general so we can save
187 * on suspend too.
188 */
189 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
190 struct drm_encoder_helper_funcs *func = encoder->helper_private;
191
192 func->restore(encoder);
193 }
194
195 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
196 crtc->funcs->restore(crtc);
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200197
198 return 0;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000199}
200
Ben Skeggs2a44e492011-11-09 11:36:33 +1000201void
202nv04_display_fini(struct drm_device *dev)
203{
Ben Skeggsafada5e2011-11-22 13:59:30 +1000204 /* disable vblank interrupts */
205 NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
206 if (nv_two_heads(dev))
207 NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
Ben Skeggs2a44e492011-11-09 11:36:33 +1000208}