1 /************************************************************************** 2 * Copyright (c) 2011, Intel Corporation. 3 * All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 **************************************************************************/ 19 20 #include <linux/backlight.h> 21 #include <drm/drmP.h> 22 #include <drm/drm.h> 23 #include <drm/gma_drm.h> 24 #include "psb_drv.h" 25 #include "psb_reg.h" 26 #include "psb_intel_reg.h" 27 #include "intel_bios.h" 28 #include "psb_device.h" 29 #include "gma_device.h" 30 31 static int psb_output_init(struct drm_device *dev) 32 { 33 struct drm_psb_private *dev_priv = dev->dev_private; 34 psb_intel_lvds_init(dev, &dev_priv->mode_dev); 35 psb_intel_sdvo_init(dev, SDVOB); 36 return 0; 37 } 38 39 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE 40 41 /* 42 * Poulsbo Backlight Interfaces 43 */ 44 45 #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ 46 #define BLC_PWM_FREQ_CALC_CONSTANT 32 47 #define MHz 1000000 48 49 #define PSB_BLC_PWM_PRECISION_FACTOR 10 50 #define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE 51 #define PSB_BLC_MIN_PWM_REG_FREQ 0x2 52 53 #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) 54 #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) 55 56 static int psb_brightness; 57 static struct backlight_device *psb_backlight_device; 58 59 static int psb_get_brightness(struct backlight_device *bd) 60 { 61 /* return locally cached var instead of HW read (due to DPST etc.) */ 62 /* FIXME: ideally return actual value in case firmware fiddled with 63 it */ 64 return psb_brightness; 65 } 66 67 68 static int psb_backlight_setup(struct drm_device *dev) 69 { 70 struct drm_psb_private *dev_priv = dev->dev_private; 71 unsigned long core_clock; 72 /* u32 bl_max_freq; */ 73 /* unsigned long value; */ 74 u16 bl_max_freq; 75 uint32_t value; 76 uint32_t blc_pwm_precision_factor; 77 78 /* get bl_max_freq and pol from dev_priv*/ 79 if (!dev_priv->lvds_bl) { 80 dev_err(dev->dev, "Has no valid LVDS backlight info\n"); 81 return -ENOENT; 82 } 83 bl_max_freq = dev_priv->lvds_bl->freq; 84 blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR; 85 86 core_clock = dev_priv->core_freq; 87 88 value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; 89 value *= blc_pwm_precision_factor; 90 value /= bl_max_freq; 91 value /= blc_pwm_precision_factor; 92 93 if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ || 94 value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ) 95 return -ERANGE; 96 else { 97 value &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; 98 REG_WRITE(BLC_PWM_CTL, 99 (value << PSB_BACKLIGHT_PWM_CTL_SHIFT) | (value)); 100 } 101 return 0; 102 } 103 104 static int psb_set_brightness(struct backlight_device *bd) 105 { 106 struct drm_device *dev = bl_get_data(psb_backlight_device); 107 int level = bd->props.brightness; 108 109 /* Percentage 1-100% being valid */ 110 if (level < 1) 111 level = 1; 112 113 psb_intel_lvds_set_brightness(dev, level); 114 psb_brightness = level; 115 return 0; 116 } 117 118 static const struct backlight_ops psb_ops = { 119 .get_brightness = psb_get_brightness, 120 .update_status = psb_set_brightness, 121 }; 122 123 static int psb_backlight_init(struct drm_device *dev) 124 { 125 struct drm_psb_private *dev_priv = dev->dev_private; 126 int ret; 127 struct backlight_properties props; 128 129 memset(&props, 0, sizeof(struct backlight_properties)); 130 props.max_brightness = 100; 131 props.type = BACKLIGHT_PLATFORM; 132 133 psb_backlight_device = backlight_device_register("psb-bl", 134 NULL, (void *)dev, &psb_ops, &props); 135 if (IS_ERR(psb_backlight_device)) 136 return PTR_ERR(psb_backlight_device); 137 138 ret = psb_backlight_setup(dev); 139 if (ret < 0) { 140 backlight_device_unregister(psb_backlight_device); 141 psb_backlight_device = NULL; 142 return ret; 143 } 144 psb_backlight_device->props.brightness = 100; 145 psb_backlight_device->props.max_brightness = 100; 146 backlight_update_status(psb_backlight_device); 147 dev_priv->backlight_device = psb_backlight_device; 148 149 /* This must occur after the backlight is properly initialised */ 150 psb_lid_timer_init(dev_priv); 151 152 return 0; 153 } 154 155 #endif 156 157 /* 158 * Provide the Poulsbo specific chip logic and low level methods 159 * for power management 160 */ 161 162 static void psb_init_pm(struct drm_device *dev) 163 { 164 struct drm_psb_private *dev_priv = dev->dev_private; 165 166 u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL); 167 gating &= ~3; /* Disable 2D clock gating */ 168 gating |= 1; 169 PSB_WSGX32(gating, PSB_CR_CLKGATECTL); 170 PSB_RSGX32(PSB_CR_CLKGATECTL); 171 } 172 173 /** 174 * psb_save_display_registers - save registers lost on suspend 175 * @dev: our DRM device 176 * 177 * Save the state we need in order to be able to restore the interface 178 * upon resume from suspend 179 */ 180 static int psb_save_display_registers(struct drm_device *dev) 181 { 182 struct drm_psb_private *dev_priv = dev->dev_private; 183 struct drm_crtc *crtc; 184 struct gma_connector *connector; 185 struct psb_state *regs = &dev_priv->regs.psb; 186 187 /* Display arbitration control + watermarks */ 188 regs->saveDSPARB = PSB_RVDC32(DSPARB); 189 regs->saveDSPFW1 = PSB_RVDC32(DSPFW1); 190 regs->saveDSPFW2 = PSB_RVDC32(DSPFW2); 191 regs->saveDSPFW3 = PSB_RVDC32(DSPFW3); 192 regs->saveDSPFW4 = PSB_RVDC32(DSPFW4); 193 regs->saveDSPFW5 = PSB_RVDC32(DSPFW5); 194 regs->saveDSPFW6 = PSB_RVDC32(DSPFW6); 195 regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT); 196 197 /* Save crtc and output state */ 198 drm_modeset_lock_all(dev); 199 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 200 if (drm_helper_crtc_in_use(crtc)) 201 dev_priv->ops->save_crtc(crtc); 202 } 203 204 list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) 205 if (connector->save) 206 connector->save(&connector->base); 207 208 drm_modeset_unlock_all(dev); 209 return 0; 210 } 211 212 /** 213 * psb_restore_display_registers - restore lost register state 214 * @dev: our DRM device 215 * 216 * Restore register state that was lost during suspend and resume. 217 */ 218 static int psb_restore_display_registers(struct drm_device *dev) 219 { 220 struct drm_psb_private *dev_priv = dev->dev_private; 221 struct drm_crtc *crtc; 222 struct gma_connector *connector; 223 struct psb_state *regs = &dev_priv->regs.psb; 224 225 /* Display arbitration + watermarks */ 226 PSB_WVDC32(regs->saveDSPARB, DSPARB); 227 PSB_WVDC32(regs->saveDSPFW1, DSPFW1); 228 PSB_WVDC32(regs->saveDSPFW2, DSPFW2); 229 PSB_WVDC32(regs->saveDSPFW3, DSPFW3); 230 PSB_WVDC32(regs->saveDSPFW4, DSPFW4); 231 PSB_WVDC32(regs->saveDSPFW5, DSPFW5); 232 PSB_WVDC32(regs->saveDSPFW6, DSPFW6); 233 PSB_WVDC32(regs->saveCHICKENBIT, DSPCHICKENBIT); 234 235 /*make sure VGA plane is off. it initializes to on after reset!*/ 236 PSB_WVDC32(0x80000000, VGACNTRL); 237 238 drm_modeset_lock_all(dev); 239 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 240 if (drm_helper_crtc_in_use(crtc)) 241 dev_priv->ops->restore_crtc(crtc); 242 243 list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) 244 if (connector->restore) 245 connector->restore(&connector->base); 246 247 drm_modeset_unlock_all(dev); 248 return 0; 249 } 250 251 static int psb_power_down(struct drm_device *dev) 252 { 253 return 0; 254 } 255 256 static int psb_power_up(struct drm_device *dev) 257 { 258 return 0; 259 } 260 261 /* Poulsbo */ 262 static const struct psb_offset psb_regmap[2] = { 263 { 264 .fp0 = FPA0, 265 .fp1 = FPA1, 266 .cntr = DSPACNTR, 267 .conf = PIPEACONF, 268 .src = PIPEASRC, 269 .dpll = DPLL_A, 270 .htotal = HTOTAL_A, 271 .hblank = HBLANK_A, 272 .hsync = HSYNC_A, 273 .vtotal = VTOTAL_A, 274 .vblank = VBLANK_A, 275 .vsync = VSYNC_A, 276 .stride = DSPASTRIDE, 277 .size = DSPASIZE, 278 .pos = DSPAPOS, 279 .base = DSPABASE, 280 .surf = DSPASURF, 281 .addr = DSPABASE, 282 .status = PIPEASTAT, 283 .linoff = DSPALINOFF, 284 .tileoff = DSPATILEOFF, 285 .palette = PALETTE_A, 286 }, 287 { 288 .fp0 = FPB0, 289 .fp1 = FPB1, 290 .cntr = DSPBCNTR, 291 .conf = PIPEBCONF, 292 .src = PIPEBSRC, 293 .dpll = DPLL_B, 294 .htotal = HTOTAL_B, 295 .hblank = HBLANK_B, 296 .hsync = HSYNC_B, 297 .vtotal = VTOTAL_B, 298 .vblank = VBLANK_B, 299 .vsync = VSYNC_B, 300 .stride = DSPBSTRIDE, 301 .size = DSPBSIZE, 302 .pos = DSPBPOS, 303 .base = DSPBBASE, 304 .surf = DSPBSURF, 305 .addr = DSPBBASE, 306 .status = PIPEBSTAT, 307 .linoff = DSPBLINOFF, 308 .tileoff = DSPBTILEOFF, 309 .palette = PALETTE_B, 310 } 311 }; 312 313 static int psb_chip_setup(struct drm_device *dev) 314 { 315 struct drm_psb_private *dev_priv = dev->dev_private; 316 dev_priv->regmap = psb_regmap; 317 gma_get_core_freq(dev); 318 gma_intel_setup_gmbus(dev); 319 psb_intel_opregion_init(dev); 320 psb_intel_init_bios(dev); 321 return 0; 322 } 323 324 static void psb_chip_teardown(struct drm_device *dev) 325 { 326 struct drm_psb_private *dev_priv = dev->dev_private; 327 psb_lid_timer_takedown(dev_priv); 328 gma_intel_teardown_gmbus(dev); 329 } 330 331 const struct psb_ops psb_chip_ops = { 332 .name = "Poulsbo", 333 .accel_2d = 1, 334 .pipes = 2, 335 .crtcs = 2, 336 .hdmi_mask = (1 << 0), 337 .lvds_mask = (1 << 1), 338 .sdvo_mask = (1 << 0), 339 .cursor_needs_phys = 1, 340 .sgx_offset = PSB_SGX_OFFSET, 341 .chip_setup = psb_chip_setup, 342 .chip_teardown = psb_chip_teardown, 343 344 .crtc_helper = &psb_intel_helper_funcs, 345 .crtc_funcs = &psb_intel_crtc_funcs, 346 .clock_funcs = &psb_clock_funcs, 347 348 .output_init = psb_output_init, 349 350 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE 351 .backlight_init = psb_backlight_init, 352 #endif 353 354 .init_pm = psb_init_pm, 355 .save_regs = psb_save_display_registers, 356 .restore_regs = psb_restore_display_registers, 357 .save_crtc = gma_crtc_save, 358 .restore_crtc = gma_crtc_restore, 359 .power_down = psb_power_down, 360 .power_up = psb_power_up, 361 }; 362 363