1 // SPDX-License-Identifier: GPL-2.0-only 2 /************************************************************************** 3 * Copyright (c) 2011, Intel Corporation. 4 * All Rights Reserved. 5 * 6 **************************************************************************/ 7 8 #include <drm/drm.h> 9 #include <drm/drm_crtc_helper.h> 10 11 #include "gma_device.h" 12 #include "intel_bios.h" 13 #include "psb_device.h" 14 #include "psb_drv.h" 15 #include "psb_intel_reg.h" 16 #include "psb_reg.h" 17 18 static int psb_output_init(struct drm_device *dev) 19 { 20 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 21 psb_intel_lvds_init(dev, &dev_priv->mode_dev); 22 psb_intel_sdvo_init(dev, SDVOB); 23 return 0; 24 } 25 26 /* 27 * Poulsbo Backlight Interfaces 28 */ 29 30 #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ 31 #define BLC_PWM_FREQ_CALC_CONSTANT 32 32 #define MHz 1000000 33 34 #define PSB_BLC_PWM_PRECISION_FACTOR 10 35 #define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE 36 #define PSB_BLC_MIN_PWM_REG_FREQ 0x2 37 38 #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) 39 #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) 40 41 static int psb_backlight_setup(struct drm_device *dev) 42 { 43 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 44 unsigned long core_clock; 45 /* u32 bl_max_freq; */ 46 /* unsigned long value; */ 47 u16 bl_max_freq; 48 uint32_t value; 49 uint32_t blc_pwm_precision_factor; 50 51 /* get bl_max_freq and pol from dev_priv*/ 52 if (!dev_priv->lvds_bl) { 53 dev_err(dev->dev, "Has no valid LVDS backlight info\n"); 54 return -ENOENT; 55 } 56 bl_max_freq = dev_priv->lvds_bl->freq; 57 blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR; 58 59 core_clock = dev_priv->core_freq; 60 61 value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; 62 value *= blc_pwm_precision_factor; 63 value /= bl_max_freq; 64 value /= blc_pwm_precision_factor; 65 66 if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ || 67 value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ) 68 return -ERANGE; 69 else { 70 value &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; 71 REG_WRITE(BLC_PWM_CTL, 72 (value << PSB_BACKLIGHT_PWM_CTL_SHIFT) | (value)); 73 } 74 75 psb_intel_lvds_set_brightness(dev, PSB_MAX_BRIGHTNESS); 76 /* This must occur after the backlight is properly initialised */ 77 psb_lid_timer_init(dev_priv); 78 return 0; 79 } 80 81 /* 82 * Provide the Poulsbo specific chip logic and low level methods 83 * for power management 84 */ 85 86 static void psb_init_pm(struct drm_device *dev) 87 { 88 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 89 90 u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL); 91 gating &= ~3; /* Disable 2D clock gating */ 92 gating |= 1; 93 PSB_WSGX32(gating, PSB_CR_CLKGATECTL); 94 PSB_RSGX32(PSB_CR_CLKGATECTL); 95 } 96 97 /** 98 * psb_save_display_registers - save registers lost on suspend 99 * @dev: our DRM device 100 * 101 * Save the state we need in order to be able to restore the interface 102 * upon resume from suspend 103 */ 104 static int psb_save_display_registers(struct drm_device *dev) 105 { 106 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 107 struct gma_connector *gma_connector; 108 struct drm_crtc *crtc; 109 struct drm_connector_list_iter conn_iter; 110 struct drm_connector *connector; 111 struct psb_state *regs = &dev_priv->regs.psb; 112 113 /* Display arbitration control + watermarks */ 114 regs->saveDSPARB = PSB_RVDC32(DSPARB); 115 regs->saveDSPFW1 = PSB_RVDC32(DSPFW1); 116 regs->saveDSPFW2 = PSB_RVDC32(DSPFW2); 117 regs->saveDSPFW3 = PSB_RVDC32(DSPFW3); 118 regs->saveDSPFW4 = PSB_RVDC32(DSPFW4); 119 regs->saveDSPFW5 = PSB_RVDC32(DSPFW5); 120 regs->saveDSPFW6 = PSB_RVDC32(DSPFW6); 121 regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT); 122 123 /* Save crtc and output state */ 124 drm_modeset_lock_all(dev); 125 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 126 if (drm_helper_crtc_in_use(crtc)) 127 dev_priv->ops->save_crtc(crtc); 128 } 129 130 drm_connector_list_iter_begin(dev, &conn_iter); 131 drm_for_each_connector_iter(connector, &conn_iter) { 132 gma_connector = to_gma_connector(connector); 133 if (gma_connector->save) 134 gma_connector->save(connector); 135 } 136 drm_connector_list_iter_end(&conn_iter); 137 138 drm_modeset_unlock_all(dev); 139 return 0; 140 } 141 142 /** 143 * psb_restore_display_registers - restore lost register state 144 * @dev: our DRM device 145 * 146 * Restore register state that was lost during suspend and resume. 147 */ 148 static int psb_restore_display_registers(struct drm_device *dev) 149 { 150 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 151 struct gma_connector *gma_connector; 152 struct drm_crtc *crtc; 153 struct drm_connector_list_iter conn_iter; 154 struct drm_connector *connector; 155 struct psb_state *regs = &dev_priv->regs.psb; 156 157 /* Display arbitration + watermarks */ 158 PSB_WVDC32(regs->saveDSPARB, DSPARB); 159 PSB_WVDC32(regs->saveDSPFW1, DSPFW1); 160 PSB_WVDC32(regs->saveDSPFW2, DSPFW2); 161 PSB_WVDC32(regs->saveDSPFW3, DSPFW3); 162 PSB_WVDC32(regs->saveDSPFW4, DSPFW4); 163 PSB_WVDC32(regs->saveDSPFW5, DSPFW5); 164 PSB_WVDC32(regs->saveDSPFW6, DSPFW6); 165 PSB_WVDC32(regs->saveCHICKENBIT, DSPCHICKENBIT); 166 167 /*make sure VGA plane is off. it initializes to on after reset!*/ 168 PSB_WVDC32(0x80000000, VGACNTRL); 169 170 drm_modeset_lock_all(dev); 171 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 172 if (drm_helper_crtc_in_use(crtc)) 173 dev_priv->ops->restore_crtc(crtc); 174 175 drm_connector_list_iter_begin(dev, &conn_iter); 176 drm_for_each_connector_iter(connector, &conn_iter) { 177 gma_connector = to_gma_connector(connector); 178 if (gma_connector->restore) 179 gma_connector->restore(connector); 180 } 181 drm_connector_list_iter_end(&conn_iter); 182 183 drm_modeset_unlock_all(dev); 184 return 0; 185 } 186 187 static int psb_power_down(struct drm_device *dev) 188 { 189 return 0; 190 } 191 192 static int psb_power_up(struct drm_device *dev) 193 { 194 return 0; 195 } 196 197 /* Poulsbo */ 198 static const struct psb_offset psb_regmap[2] = { 199 { 200 .fp0 = FPA0, 201 .fp1 = FPA1, 202 .cntr = DSPACNTR, 203 .conf = PIPEACONF, 204 .src = PIPEASRC, 205 .dpll = DPLL_A, 206 .htotal = HTOTAL_A, 207 .hblank = HBLANK_A, 208 .hsync = HSYNC_A, 209 .vtotal = VTOTAL_A, 210 .vblank = VBLANK_A, 211 .vsync = VSYNC_A, 212 .stride = DSPASTRIDE, 213 .size = DSPASIZE, 214 .pos = DSPAPOS, 215 .base = DSPABASE, 216 .surf = DSPASURF, 217 .addr = DSPABASE, 218 .status = PIPEASTAT, 219 .linoff = DSPALINOFF, 220 .tileoff = DSPATILEOFF, 221 .palette = PALETTE_A, 222 }, 223 { 224 .fp0 = FPB0, 225 .fp1 = FPB1, 226 .cntr = DSPBCNTR, 227 .conf = PIPEBCONF, 228 .src = PIPEBSRC, 229 .dpll = DPLL_B, 230 .htotal = HTOTAL_B, 231 .hblank = HBLANK_B, 232 .hsync = HSYNC_B, 233 .vtotal = VTOTAL_B, 234 .vblank = VBLANK_B, 235 .vsync = VSYNC_B, 236 .stride = DSPBSTRIDE, 237 .size = DSPBSIZE, 238 .pos = DSPBPOS, 239 .base = DSPBBASE, 240 .surf = DSPBSURF, 241 .addr = DSPBBASE, 242 .status = PIPEBSTAT, 243 .linoff = DSPBLINOFF, 244 .tileoff = DSPBTILEOFF, 245 .palette = PALETTE_B, 246 } 247 }; 248 249 static int psb_chip_setup(struct drm_device *dev) 250 { 251 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 252 dev_priv->regmap = psb_regmap; 253 gma_get_core_freq(dev); 254 gma_intel_setup_gmbus(dev); 255 psb_intel_opregion_init(dev); 256 psb_intel_init_bios(dev); 257 return 0; 258 } 259 260 static void psb_chip_teardown(struct drm_device *dev) 261 { 262 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 263 psb_lid_timer_takedown(dev_priv); 264 gma_intel_teardown_gmbus(dev); 265 } 266 267 const struct psb_ops psb_chip_ops = { 268 .name = "Poulsbo", 269 .pipes = 2, 270 .crtcs = 2, 271 .hdmi_mask = (1 << 0), 272 .lvds_mask = (1 << 1), 273 .sdvo_mask = (1 << 0), 274 .cursor_needs_phys = 1, 275 .sgx_offset = PSB_SGX_OFFSET, 276 .chip_setup = psb_chip_setup, 277 .chip_teardown = psb_chip_teardown, 278 279 .crtc_helper = &psb_intel_helper_funcs, 280 .clock_funcs = &psb_clock_funcs, 281 282 .output_init = psb_output_init, 283 284 .backlight_init = psb_backlight_setup, 285 .backlight_set = psb_intel_lvds_set_brightness, 286 .backlight_name = "psb-bl", 287 288 .init_pm = psb_init_pm, 289 .save_regs = psb_save_display_registers, 290 .restore_regs = psb_restore_display_registers, 291 .save_crtc = gma_crtc_save, 292 .restore_crtc = gma_crtc_restore, 293 .power_down = psb_power_down, 294 .power_up = psb_power_up, 295 }; 296 297