1 /* 2 Copyright (c) 2002, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 Display Power Management (DPMS) support 8 */ 9 10 #include "radeon_accelerant.h" 11 #include "mmio.h" 12 #include "crtc_regs.h" 13 #include "fp_regs.h" 14 #include "GlobalData.h" 15 16 // these static functions are moved to end of file to 17 // make sure gcc doesn't inline them - we prefer size and not 18 // speed for this file 19 static status_t Radeon_SetDPMS_CRTC1( accelerator_info *di, int mode ); 20 static status_t Radeon_SetDPMS_CRTC2( accelerator_info *di, int mode ); 21 static uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di ); 22 static uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di ); 23 24 status_t SET_DPMS_MODE(uint32 dpms_flags); 25 uint32 DPMS_CAPABILITIES(void); 26 uint32 DPMS_MODE(void); 27 28 29 // public function: set DPMS mode 30 status_t SET_DPMS_MODE(uint32 dpms_flags) 31 { 32 virtual_card *vc = ai->vc; 33 status_t result1, result2; 34 35 result1 = Radeon_SetDPMS( ai, &vc->ports[0], dpms_flags ); 36 37 if( vc->independant_ports > 1 ) 38 result2 = Radeon_SetDPMS( ai, &vc->ports[1], dpms_flags ); 39 else 40 result2 = B_OK; 41 42 if( result1 == B_OK && result2 == B_OK ) 43 return B_OK; 44 else 45 return B_ERROR; 46 } 47 48 // public function: report DPMS capabilities 49 uint32 DPMS_CAPABILITIES(void) 50 { 51 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 52 } 53 54 55 // public function: get current DPMS mode 56 uint32 DPMS_MODE(void) 57 { 58 // we just ask the primary port what status it is in 59 return Radeon_GetDPMS( ai, &ai->vc->ports[0] ); 60 } 61 62 63 // set DPMS mode of one port 64 status_t Radeon_SetDPMS( accelerator_info *ai, virtual_port *port, int mode ) 65 { 66 // if we have a laptop panel 67 // and we have a second screen connected 68 // and they both show the same content, 69 // then switch the laptop display always off 70 if( ai->si->ports[port->physical_port].disp_type == dt_lvds && 71 ai->vc->independant_ports > 1 && 72 ai->vc->different_ports == 1 ) 73 { 74 mode = B_DPMS_OFF; 75 } 76 77 if( port->is_crtc2 ) 78 return Radeon_SetDPMS_CRTC2( ai, mode ); 79 else 80 return Radeon_SetDPMS_CRTC1( ai, mode ); 81 } 82 83 84 // get DPMS mode of one port 85 uint32 Radeon_GetDPMS( accelerator_info *ai, virtual_port *port ) 86 { 87 if( port->is_crtc2 ) 88 return Radeon_GetDPMS_CRTC2( ai ); 89 else 90 return Radeon_GetDPMS_CRTC1( ai ); 91 } 92 93 94 // set DPMS mode for first port 95 status_t Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode ) 96 { 97 vuint8 *regs = ai->regs; 98 shared_info *si = ai->si; 99 100 int mask = RADEON_CRTC_DISPLAY_DIS 101 | RADEON_CRTC_HSYNC_DIS 102 | RADEON_CRTC_VSYNC_DIS; 103 104 switch( mode ) { 105 case B_DPMS_ON: 106 /* Screen: On; HSync: On, VSync: On */ 107 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, ~mask ); 108 break; 109 case B_DPMS_STAND_BY: 110 /* Screen: Off; HSync: Off, VSync: On */ 111 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 112 RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS, ~mask ); 113 break; 114 case B_DPMS_SUSPEND: 115 /* Screen: Off; HSync: On, VSync: Off */ 116 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 117 RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS, ~mask ); 118 break; 119 case B_DPMS_OFF: 120 /* Screen: Off; HSync: Off, VSync: Off */ 121 OUTREGP( regs, RADEON_CRTC_EXT_CNTL, mask, ~mask ); 122 break; 123 default: 124 return B_BAD_VALUE; 125 } 126 127 // if this is a flat panel, switch off backlight too 128 if( si->ports[0].disp_type == dt_dvi_1 || si->ports[0].disp_type == dt_lvds ) { 129 switch( mode ) { 130 case B_DPMS_ON: 131 // on my laptop, the display has problems to wake-up, this 132 // should hopefully cure that 133 // (you get a dark picture first that becomes brighter step by step, 134 // after a couple of seconds you have full brightness again) 135 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON, ~RADEON_LVDS_BLON ); 136 //snooze( ai->si->fp_port.panel_pwr_delay * 1000 ); 137 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON | RADEON_LVDS_ON, 138 ~(RADEON_LVDS_DISPLAY_DIS | RADEON_LVDS_BLON | RADEON_LVDS_ON) ); 139 break; 140 case B_DPMS_STAND_BY: 141 case B_DPMS_SUSPEND: 142 case B_DPMS_OFF: 143 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_DISPLAY_DIS, 144 ~(RADEON_LVDS_DISPLAY_DIS | RADEON_LVDS_BLON | RADEON_LVDS_ON) ); 145 break; 146 } 147 } 148 149 // it seems that DPMS doesn't work on DVI, so we disable FP completely 150 // (according to specs this is the official way to handle DVI though DPMS 151 // *should* be supported as well) 152 if( si->ports[0].disp_type == dt_dvi_1 ) { 153 switch( mode ) { 154 case B_DPMS_ON: 155 OUTREGP( regs, RADEON_FP_GEN_CNTL, RADEON_FP_FPON, ~RADEON_FP_FPON ); 156 break; 157 case B_DPMS_STAND_BY: 158 case B_DPMS_SUSPEND: 159 case B_DPMS_OFF: 160 OUTREGP( regs, RADEON_FP_GEN_CNTL, 0, ~RADEON_FP_FPON ); 161 break; 162 } 163 } 164 165 return B_OK; 166 } 167 168 169 // set DPMS mode of second port 170 status_t Radeon_SetDPMS_CRTC2( accelerator_info *di, int mode ) 171 { 172 vuint8 *regs = di->regs; 173 174 int mask = RADEON_CRTC2_DISP_DIS 175 | RADEON_CRTC2_HSYNC_DIS 176 | RADEON_CRTC2_VSYNC_DIS; 177 178 switch( mode ) { 179 case B_DPMS_ON: 180 /* Screen: On; HSync: On, VSync: On */ 181 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~mask ); 182 break; 183 case B_DPMS_STAND_BY: 184 /* Screen: Off; HSync: Off, VSync: On */ 185 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 186 RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS, ~mask ); 187 break; 188 case B_DPMS_SUSPEND: 189 /* Screen: Off; HSync: On, VSync: Off */ 190 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 191 RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS, ~mask ); 192 break; 193 case B_DPMS_OFF: 194 /* Screen: Off; HSync: Off, VSync: Off */ 195 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, mask, ~mask ); 196 break; 197 default: 198 return B_BAD_VALUE; 199 } 200 201 return B_OK; 202 } 203 204 205 // get DPMS mode of first port 206 uint32 Radeon_GetDPMS_CRTC1( accelerator_info *di ) 207 { 208 uint32 tmp; 209 210 tmp = INREG( di->regs, RADEON_CRTC_EXT_CNTL ); 211 212 if( (tmp & RADEON_CRTC_DISPLAY_DIS) == 0 ) 213 return B_DPMS_ON; 214 215 if( (tmp & RADEON_CRTC_VSYNC_DIS) == 0 ) 216 return B_DPMS_STAND_BY; 217 218 if( (tmp & RADEON_CRTC_HSYNC_DIS) == 0 ) 219 return B_DPMS_SUSPEND; 220 221 return B_DPMS_OFF; 222 } 223 224 225 // get DPMS mode of second port 226 uint32 Radeon_GetDPMS_CRTC2( accelerator_info *di ) 227 { 228 uint32 tmp; 229 230 tmp = INREG( di->regs, RADEON_CRTC2_GEN_CNTL ); 231 232 if( (tmp & RADEON_CRTC2_DISP_DIS) == 0 ) 233 return B_DPMS_ON; 234 235 if( (tmp & RADEON_CRTC2_VSYNC_DIS) == 0 ) 236 return B_DPMS_STAND_BY; 237 238 if( (tmp & RADEON_CRTC2_HSYNC_DIS) == 0 ) 239 return B_DPMS_SUSPEND; 240 241 return B_DPMS_OFF; 242 } 243