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 <core/object.h> 26 #include <core/class.h> 27 28 #include <drm/drmP.h> 29 #include <drm/drm_crtc_helper.h> 30 31 #include "nouveau_drm.h" 32 #include "nouveau_reg.h" 33 #include "hw.h" 34 #include "nouveau_encoder.h" 35 #include "nouveau_connector.h" 36 37 #include <subdev/i2c.h> 38 39 int 40 nv04_display_early_init(struct drm_device *dev) 41 { 42 /* 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 49 return 0; 50 } 51 52 void 53 nv04_display_late_takedown(struct drm_device *dev) 54 { 55 } 56 57 int 58 nv04_display_create(struct drm_device *dev) 59 { 60 struct nouveau_drm *drm = nouveau_drm(dev); 61 struct nouveau_i2c *i2c = nouveau_i2c(drm->device); 62 struct dcb_table *dcb = &drm->vbios.dcb; 63 struct drm_connector *connector, *ct; 64 struct drm_encoder *encoder; 65 struct drm_crtc *crtc; 66 struct nv04_display *disp; 67 int i, ret; 68 69 disp = kzalloc(sizeof(*disp), GFP_KERNEL); 70 if (!disp) 71 return -ENOMEM; 72 73 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; 77 78 nouveau_hw_save_vga_fonts(dev, 1); 79 80 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++) { 85 struct dcb_output *dcbent = &dcb->entry[i]; 86 87 connector = nouveau_connector_create(dev, dcbent->connector); 88 if (IS_ERR(connector)) 89 continue; 90 91 switch (dcbent->type) { 92 case DCB_OUTPUT_ANALOG: 93 ret = nv04_dac_create(connector, dcbent); 94 break; 95 case DCB_OUTPUT_LVDS: 96 case DCB_OUTPUT_TMDS: 97 ret = nv04_dfp_create(connector, dcbent); 98 break; 99 case DCB_OUTPUT_TV: 100 if (dcbent->location == DCB_LOC_ON_CHIP) 101 ret = nv17_tv_create(connector, dcbent); 102 else 103 ret = nv04_tv_create(connector, dcbent); 104 break; 105 default: 106 NV_WARN(drm, "DCB type %d not known\n", dcbent->type); 107 continue; 108 } 109 110 if (ret) 111 continue; 112 } 113 114 list_for_each_entry_safe(connector, ct, 115 &dev->mode_config.connector_list, head) { 116 if (!connector->encoder_ids[0]) { 117 NV_WARN(drm, "%s has no encoders, removing\n", 118 connector->name); 119 connector->funcs->destroy(connector); 120 } 121 } 122 123 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 128 /* Save previous state */ 129 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 138 nouveau_overlay_init(dev); 139 140 return 0; 141 } 142 143 void 144 nv04_display_destroy(struct drm_device *dev) 145 { 146 struct nv04_display *disp = nv04_display(dev); 147 struct drm_encoder *encoder; 148 struct drm_crtc *crtc; 149 150 /* 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 156 drm_mode_set_config_internal(&modeset); 157 } 158 159 /* Restore state */ 160 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 169 nouveau_hw_save_vga_fonts(dev, 0); 170 171 nouveau_display(dev)->priv = NULL; 172 kfree(disp); 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