1 /* 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 25 #include <drm/drmP.h> 26 #include <drm/drm_crtc_helper.h> 27 28 #include "nouveau_drm.h" 29 #include "nouveau_reg.h" 30 #include "hw.h" 31 #include "nouveau_encoder.h" 32 #include "nouveau_connector.h" 33 34 int 35 nv04_display_early_init(struct drm_device *dev) 36 { 37 /* ensure vblank interrupts are off, they can't be enabled until 38 * drm_vblank has been initialised 39 */ 40 NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0); 41 if (nv_two_heads(dev)) 42 NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0); 43 44 return 0; 45 } 46 47 void 48 nv04_display_late_takedown(struct drm_device *dev) 49 { 50 } 51 52 int 53 nv04_display_create(struct drm_device *dev) 54 { 55 struct nouveau_drm *drm = nouveau_drm(dev); 56 struct nouveau_i2c *i2c = nvkm_i2c(&drm->device); 57 struct dcb_table *dcb = &drm->vbios.dcb; 58 struct drm_connector *connector, *ct; 59 struct drm_encoder *encoder; 60 struct drm_crtc *crtc; 61 struct nv04_display *disp; 62 int i, ret; 63 64 disp = kzalloc(sizeof(*disp), GFP_KERNEL); 65 if (!disp) 66 return -ENOMEM; 67 68 nvif_object_map(nvif_object(&drm->device)); 69 70 nouveau_display(dev)->priv = disp; 71 nouveau_display(dev)->dtor = nv04_display_destroy; 72 nouveau_display(dev)->init = nv04_display_init; 73 nouveau_display(dev)->fini = nv04_display_fini; 74 75 nouveau_hw_save_vga_fonts(dev, 1); 76 77 nv04_crtc_create(dev, 0); 78 if (nv_two_heads(dev)) 79 nv04_crtc_create(dev, 1); 80 81 for (i = 0; i < dcb->entries; i++) { 82 struct dcb_output *dcbent = &dcb->entry[i]; 83 84 connector = nouveau_connector_create(dev, dcbent->connector); 85 if (IS_ERR(connector)) 86 continue; 87 88 switch (dcbent->type) { 89 case DCB_OUTPUT_ANALOG: 90 ret = nv04_dac_create(connector, dcbent); 91 break; 92 case DCB_OUTPUT_LVDS: 93 case DCB_OUTPUT_TMDS: 94 ret = nv04_dfp_create(connector, dcbent); 95 break; 96 case DCB_OUTPUT_TV: 97 if (dcbent->location == DCB_LOC_ON_CHIP) 98 ret = nv17_tv_create(connector, dcbent); 99 else 100 ret = nv04_tv_create(connector, dcbent); 101 break; 102 default: 103 NV_WARN(drm, "DCB type %d not known\n", dcbent->type); 104 continue; 105 } 106 107 if (ret) 108 continue; 109 } 110 111 list_for_each_entry_safe(connector, ct, 112 &dev->mode_config.connector_list, head) { 113 if (!connector->encoder_ids[0]) { 114 NV_WARN(drm, "%s has no encoders, removing\n", 115 connector->name); 116 connector->funcs->destroy(connector); 117 } 118 } 119 120 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 121 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 122 nv_encoder->i2c = i2c->find(i2c, nv_encoder->dcb->i2c_index); 123 } 124 125 /* Save previous state */ 126 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 127 crtc->funcs->save(crtc); 128 129 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 130 struct drm_encoder_helper_funcs *func = encoder->helper_private; 131 132 func->save(encoder); 133 } 134 135 nouveau_overlay_init(dev); 136 137 return 0; 138 } 139 140 void 141 nv04_display_destroy(struct drm_device *dev) 142 { 143 struct nv04_display *disp = nv04_display(dev); 144 struct nouveau_drm *drm = nouveau_drm(dev); 145 struct drm_encoder *encoder; 146 struct drm_crtc *crtc; 147 148 /* Turn every CRTC off. */ 149 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 150 struct drm_mode_set modeset = { 151 .crtc = crtc, 152 }; 153 154 drm_mode_set_config_internal(&modeset); 155 } 156 157 /* Restore state */ 158 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 159 struct drm_encoder_helper_funcs *func = encoder->helper_private; 160 161 func->restore(encoder); 162 } 163 164 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 165 crtc->funcs->restore(crtc); 166 167 nouveau_hw_save_vga_fonts(dev, 0); 168 169 nouveau_display(dev)->priv = NULL; 170 kfree(disp); 171 172 nvif_object_unmap(nvif_object(&drm->device)); 173 } 174 175 int 176 nv04_display_init(struct drm_device *dev) 177 { 178 struct drm_encoder *encoder; 179 struct drm_crtc *crtc; 180 181 /* 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); 197 198 return 0; 199 } 200 201 void 202 nv04_display_fini(struct drm_device *dev) 203 { 204 /* 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); 208 } 209