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 "drmP.h" 26#include "drm.h" 27#include "drm_crtc_helper.h" 28 29#include "nouveau_drv.h" 30#include "nouveau_fb.h" 31#include "nouveau_hw.h" 32#include "nouveau_encoder.h" 33#include "nouveau_connector.h" 34 35static void nv04_vblank_crtc0_isr(struct drm_device *); 36static void nv04_vblank_crtc1_isr(struct drm_device *); 37 38static void 39nv04_display_store_initial_head_owner(struct drm_device *dev) 40{ 41 struct drm_nouveau_private *dev_priv = dev->dev_private; 42 43 if (dev_priv->chipset != 0x11) { 44 dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44); 45 return; 46 } 47 48 /* reading CR44 is broken on nv11, so we attempt to infer it */ 49 if (nvReadMC(dev, NV_PBUS_DEBUG_1) & (1 << 28)) /* heads tied, restore both */ 50 dev_priv->crtc_owner = 0x4; 51 else { 52 uint8_t slaved_on_A, slaved_on_B; 53 bool tvA = false; 54 bool tvB = false; 55 56 slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) & 57 0x80; 58 if (slaved_on_B) 59 tvB = !(NVReadVgaCrtc(dev, 1, NV_CIO_CRE_LCD__INDEX) & 60 MASK(NV_CIO_CRE_LCD_LCD_SELECT)); 61 62 slaved_on_A = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX) & 63 0x80; 64 if (slaved_on_A) 65 tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) & 66 MASK(NV_CIO_CRE_LCD_LCD_SELECT)); 67 68 if (slaved_on_A && !tvA) 69 dev_priv->crtc_owner = 0x0; 70 else if (slaved_on_B && !tvB) 71 dev_priv->crtc_owner = 0x3; 72 else if (slaved_on_A) 73 dev_priv->crtc_owner = 0x0; 74 else if (slaved_on_B) 75 dev_priv->crtc_owner = 0x3; 76 else 77 dev_priv->crtc_owner = 0x0; 78 } 79} 80 81int 82nv04_display_early_init(struct drm_device *dev) 83{ 84 /* Make the I2C buses accessible. */ 85 if (!nv_gf4_disp_arch(dev)) { 86 uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); 87 88 if (!(pmc_enable & 1)) 89 nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1); 90 } 91 92 /* Unlock the VGA CRTCs. */ 93 NVLockVgaCrtcs(dev, false); 94 95 /* Make sure the CRTCs aren't in slaved mode. */ 96 if (nv_two_heads(dev)) { 97 nv04_display_store_initial_head_owner(dev); 98 NVSetOwner(dev, 0); 99 } 100 101 return 0; 102} 103 104void 105nv04_display_late_takedown(struct drm_device *dev) 106{ 107 struct drm_nouveau_private *dev_priv = dev->dev_private; 108 109 if (nv_two_heads(dev)) 110 NVSetOwner(dev, dev_priv->crtc_owner); 111 112 NVLockVgaCrtcs(dev, true); 113} 114 115int 116nv04_display_create(struct drm_device *dev) 117{ 118 struct drm_nouveau_private *dev_priv = dev->dev_private; 119 struct dcb_table *dcb = &dev_priv->vbios.dcb; 120 struct drm_connector *connector, *ct; 121 struct drm_encoder *encoder; 122 struct drm_crtc *crtc; 123 int i, ret; 124 125 NV_DEBUG_KMS(dev, "\n"); 126 127 nouveau_hw_save_vga_fonts(dev, 1); 128 129 nv04_crtc_create(dev, 0); 130 if (nv_two_heads(dev)) 131 nv04_crtc_create(dev, 1); 132 133 for (i = 0; i < dcb->entries; i++) { 134 struct dcb_entry *dcbent = &dcb->entry[i]; 135 136 connector = nouveau_connector_create(dev, dcbent->connector); 137 if (IS_ERR(connector)) 138 continue; 139 140 switch (dcbent->type) { 141 case OUTPUT_ANALOG: 142 ret = nv04_dac_create(connector, dcbent); 143 break; 144 case OUTPUT_LVDS: 145 case OUTPUT_TMDS: 146 ret = nv04_dfp_create(connector, dcbent); 147 break; 148 case OUTPUT_TV: 149 if (dcbent->location == DCB_LOC_ON_CHIP) 150 ret = nv17_tv_create(connector, dcbent); 151 else 152 ret = nv04_tv_create(connector, dcbent); 153 break; 154 default: 155 NV_WARN(dev, "DCB type %d not known\n", dcbent->type); 156 continue; 157 } 158 159 if (ret) 160 continue; 161 } 162 163 list_for_each_entry_safe(connector, ct, 164 &dev->mode_config.connector_list, head) { 165 if (!connector->encoder_ids[0]) { 166 NV_WARN(dev, "%s has no encoders, removing\n", 167 drm_get_connector_name(connector)); 168 connector->funcs->destroy(connector); 169 } 170 } 171 172 /* Save previous state */ 173 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 174 crtc->funcs->save(crtc); 175 176 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 177 struct drm_encoder_helper_funcs *func = encoder->helper_private; 178 179 func->save(encoder); 180 } 181 182 nouveau_irq_register(dev, 24, nv04_vblank_crtc0_isr); 183 nouveau_irq_register(dev, 25, nv04_vblank_crtc1_isr); 184 return 0; 185} 186 187void 188nv04_display_destroy(struct drm_device *dev) 189{ 190 struct drm_encoder *encoder; 191 struct drm_crtc *crtc; 192 193 NV_DEBUG_KMS(dev, "\n"); 194 195 nouveau_irq_unregister(dev, 24); 196 nouveau_irq_unregister(dev, 25); 197 198 /* Turn every CRTC off. */ 199 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 200 struct drm_mode_set modeset = { 201 .crtc = crtc, 202 }; 203 204 crtc->funcs->set_config(&modeset); 205 } 206 207 /* Restore state */ 208 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 209 struct drm_encoder_helper_funcs *func = encoder->helper_private; 210 211 func->restore(encoder); 212 } 213 214 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 215 crtc->funcs->restore(crtc); 216 217 nouveau_hw_save_vga_fonts(dev, 0); 218} 219 220int 221nv04_display_init(struct drm_device *dev) 222{ 223 struct drm_encoder *encoder; 224 struct drm_crtc *crtc; 225 226 /* meh.. modeset apparently doesn't setup all the regs and depends 227 * on pre-existing state, for now load the state of the card *before* 228 * nouveau was loaded, and then do a modeset. 229 * 230 * best thing to do probably is to make save/restore routines not 231 * save/restore "pre-load" state, but more general so we can save 232 * on suspend too. 233 */ 234 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 235 struct drm_encoder_helper_funcs *func = encoder->helper_private; 236 237 func->restore(encoder); 238 } 239 240 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 241 crtc->funcs->restore(crtc); 242 243 return 0; 244} 245 246void 247nv04_display_fini(struct drm_device *dev) 248{ 249} 250 251static void 252nv04_vblank_crtc0_isr(struct drm_device *dev) 253{ 254 nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); 255 drm_handle_vblank(dev, 0); 256} 257 258static void 259nv04_vblank_crtc1_isr(struct drm_device *dev) 260{ 261 nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK); 262 drm_handle_vblank(dev, 1); 263} 264