294 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/**************************************************************************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 18static 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 Interfaces28 */29 30#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */31#define BLC_PWM_FREQ_CALC_CONSTANT 3232#define MHz 100000033 34#define PSB_BLC_PWM_PRECISION_FACTOR 1035#define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE36#define PSB_BLC_MIN_PWM_REG_FREQ 0x237 38#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)39#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16)40 41static 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 77 return 0;78}79 80/*81 * Provide the Poulsbo specific chip logic and low level methods82 * for power management83 */84 85static void psb_init_pm(struct drm_device *dev)86{87 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);88 89 u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL);90 gating &= ~3; /* Disable 2D clock gating */91 gating |= 1;92 PSB_WSGX32(gating, PSB_CR_CLKGATECTL);93 PSB_RSGX32(PSB_CR_CLKGATECTL);94}95 96/**97 * psb_save_display_registers - save registers lost on suspend98 * @dev: our DRM device99 *100 * Save the state we need in order to be able to restore the interface101 * upon resume from suspend102 */103static int psb_save_display_registers(struct drm_device *dev)104{105 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);106 struct gma_connector *gma_connector;107 struct drm_crtc *crtc;108 struct drm_connector_list_iter conn_iter;109 struct drm_connector *connector;110 struct psb_state *regs = &dev_priv->regs.psb;111 112 /* Display arbitration control + watermarks */113 regs->saveDSPARB = PSB_RVDC32(DSPARB);114 regs->saveDSPFW1 = PSB_RVDC32(DSPFW1);115 regs->saveDSPFW2 = PSB_RVDC32(DSPFW2);116 regs->saveDSPFW3 = PSB_RVDC32(DSPFW3);117 regs->saveDSPFW4 = PSB_RVDC32(DSPFW4);118 regs->saveDSPFW5 = PSB_RVDC32(DSPFW5);119 regs->saveDSPFW6 = PSB_RVDC32(DSPFW6);120 regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);121 122 /* Save crtc and output state */123 drm_modeset_lock_all(dev);124 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {125 if (drm_helper_crtc_in_use(crtc))126 dev_priv->ops->save_crtc(crtc);127 }128 129 drm_connector_list_iter_begin(dev, &conn_iter);130 drm_for_each_connector_iter(connector, &conn_iter) {131 gma_connector = to_gma_connector(connector);132 if (gma_connector->save)133 gma_connector->save(connector);134 }135 drm_connector_list_iter_end(&conn_iter);136 137 drm_modeset_unlock_all(dev);138 return 0;139}140 141/**142 * psb_restore_display_registers - restore lost register state143 * @dev: our DRM device144 *145 * Restore register state that was lost during suspend and resume.146 */147static int psb_restore_display_registers(struct drm_device *dev)148{149 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);150 struct gma_connector *gma_connector;151 struct drm_crtc *crtc;152 struct drm_connector_list_iter conn_iter;153 struct drm_connector *connector;154 struct psb_state *regs = &dev_priv->regs.psb;155 156 /* Display arbitration + watermarks */157 PSB_WVDC32(regs->saveDSPARB, DSPARB);158 PSB_WVDC32(regs->saveDSPFW1, DSPFW1);159 PSB_WVDC32(regs->saveDSPFW2, DSPFW2);160 PSB_WVDC32(regs->saveDSPFW3, DSPFW3);161 PSB_WVDC32(regs->saveDSPFW4, DSPFW4);162 PSB_WVDC32(regs->saveDSPFW5, DSPFW5);163 PSB_WVDC32(regs->saveDSPFW6, DSPFW6);164 PSB_WVDC32(regs->saveCHICKENBIT, DSPCHICKENBIT);165 166 /*make sure VGA plane is off. it initializes to on after reset!*/167 PSB_WVDC32(0x80000000, VGACNTRL);168 169 drm_modeset_lock_all(dev);170 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)171 if (drm_helper_crtc_in_use(crtc))172 dev_priv->ops->restore_crtc(crtc);173 174 drm_connector_list_iter_begin(dev, &conn_iter);175 drm_for_each_connector_iter(connector, &conn_iter) {176 gma_connector = to_gma_connector(connector);177 if (gma_connector->restore)178 gma_connector->restore(connector);179 }180 drm_connector_list_iter_end(&conn_iter);181 182 drm_modeset_unlock_all(dev);183 return 0;184}185 186static int psb_power_down(struct drm_device *dev)187{188 return 0;189}190 191static int psb_power_up(struct drm_device *dev)192{193 return 0;194}195 196/* Poulsbo */197static const struct psb_offset psb_regmap[2] = {198 {199 .fp0 = FPA0,200 .fp1 = FPA1,201 .cntr = DSPACNTR,202 .conf = PIPEACONF,203 .src = PIPEASRC,204 .dpll = DPLL_A,205 .htotal = HTOTAL_A,206 .hblank = HBLANK_A,207 .hsync = HSYNC_A,208 .vtotal = VTOTAL_A,209 .vblank = VBLANK_A,210 .vsync = VSYNC_A,211 .stride = DSPASTRIDE,212 .size = DSPASIZE,213 .pos = DSPAPOS,214 .base = DSPABASE,215 .surf = DSPASURF,216 .addr = DSPABASE,217 .status = PIPEASTAT,218 .linoff = DSPALINOFF,219 .tileoff = DSPATILEOFF,220 .palette = PALETTE_A,221 },222 {223 .fp0 = FPB0,224 .fp1 = FPB1,225 .cntr = DSPBCNTR,226 .conf = PIPEBCONF,227 .src = PIPEBSRC,228 .dpll = DPLL_B,229 .htotal = HTOTAL_B,230 .hblank = HBLANK_B,231 .hsync = HSYNC_B,232 .vtotal = VTOTAL_B,233 .vblank = VBLANK_B,234 .vsync = VSYNC_B,235 .stride = DSPBSTRIDE,236 .size = DSPBSIZE,237 .pos = DSPBPOS,238 .base = DSPBBASE,239 .surf = DSPBSURF,240 .addr = DSPBBASE,241 .status = PIPEBSTAT,242 .linoff = DSPBLINOFF,243 .tileoff = DSPBTILEOFF,244 .palette = PALETTE_B,245 }246};247 248static int psb_chip_setup(struct drm_device *dev)249{250 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);251 dev_priv->regmap = psb_regmap;252 gma_get_core_freq(dev);253 gma_intel_setup_gmbus(dev);254 psb_intel_opregion_init(dev);255 psb_intel_init_bios(dev);256 return 0;257}258 259static void psb_chip_teardown(struct drm_device *dev)260{261 gma_intel_teardown_gmbus(dev);262}263 264const struct psb_ops psb_chip_ops = {265 .name = "Poulsbo",266 .pipes = 2,267 .crtcs = 2,268 .hdmi_mask = (1 << 0),269 .lvds_mask = (1 << 1),270 .sdvo_mask = (1 << 0),271 .cursor_needs_phys = 1,272 .sgx_offset = PSB_SGX_OFFSET,273 .chip_setup = psb_chip_setup,274 .chip_teardown = psb_chip_teardown,275 276 .crtc_helper = &psb_intel_helper_funcs,277 .clock_funcs = &psb_clock_funcs,278 279 .output_init = psb_output_init,280 281 .backlight_init = psb_backlight_setup,282 .backlight_set = psb_intel_lvds_set_brightness,283 .backlight_name = "psb-bl",284 285 .init_pm = psb_init_pm,286 .save_regs = psb_save_display_registers,287 .restore_regs = psb_restore_display_registers,288 .save_crtc = gma_crtc_save,289 .restore_crtc = gma_crtc_restore,290 .power_down = psb_power_down,291 .power_up = psb_power_up,292};293 294