Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /**************************************************************************
0003  * Copyright (c) 2011, Intel Corporation.
0004  * All Rights Reserved.
0005  *
0006  **************************************************************************/
0007 
0008 #include <linux/backlight.h>
0009 
0010 #include <drm/drm.h>
0011 
0012 #include "gma_device.h"
0013 #include "intel_bios.h"
0014 #include "psb_device.h"
0015 #include "psb_drv.h"
0016 #include "psb_intel_reg.h"
0017 #include "psb_reg.h"
0018 
0019 static int psb_output_init(struct drm_device *dev)
0020 {
0021     struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0022     psb_intel_lvds_init(dev, &dev_priv->mode_dev);
0023     psb_intel_sdvo_init(dev, SDVOB);
0024     return 0;
0025 }
0026 
0027 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
0028 
0029 /*
0030  *  Poulsbo Backlight Interfaces
0031  */
0032 
0033 #define BLC_PWM_PRECISION_FACTOR 100    /* 10000000 */
0034 #define BLC_PWM_FREQ_CALC_CONSTANT 32
0035 #define MHz 1000000
0036 
0037 #define PSB_BLC_PWM_PRECISION_FACTOR    10
0038 #define PSB_BLC_MAX_PWM_REG_FREQ        0xFFFE
0039 #define PSB_BLC_MIN_PWM_REG_FREQ        0x2
0040 
0041 #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
0042 #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16)
0043 
0044 static int psb_brightness;
0045 static struct backlight_device *psb_backlight_device;
0046 
0047 static int psb_get_brightness(struct backlight_device *bd)
0048 {
0049     /* return locally cached var instead of HW read (due to DPST etc.) */
0050     /* FIXME: ideally return actual value in case firmware fiddled with
0051        it */
0052     return psb_brightness;
0053 }
0054 
0055 
0056 static int psb_backlight_setup(struct drm_device *dev)
0057 {
0058     struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0059     unsigned long core_clock;
0060     /* u32 bl_max_freq; */
0061     /* unsigned long value; */
0062     u16 bl_max_freq;
0063     uint32_t value;
0064     uint32_t blc_pwm_precision_factor;
0065 
0066     /* get bl_max_freq and pol from dev_priv*/
0067     if (!dev_priv->lvds_bl) {
0068         dev_err(dev->dev, "Has no valid LVDS backlight info\n");
0069         return -ENOENT;
0070     }
0071     bl_max_freq = dev_priv->lvds_bl->freq;
0072     blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR;
0073 
0074     core_clock = dev_priv->core_freq;
0075 
0076     value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT;
0077     value *= blc_pwm_precision_factor;
0078     value /= bl_max_freq;
0079     value /= blc_pwm_precision_factor;
0080 
0081     if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ ||
0082          value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ)
0083                 return -ERANGE;
0084     else {
0085         value &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR;
0086         REG_WRITE(BLC_PWM_CTL,
0087             (value << PSB_BACKLIGHT_PWM_CTL_SHIFT) | (value));
0088     }
0089     return 0;
0090 }
0091 
0092 static int psb_set_brightness(struct backlight_device *bd)
0093 {
0094     struct drm_device *dev = bl_get_data(psb_backlight_device);
0095     int level = bd->props.brightness;
0096 
0097     /* Percentage 1-100% being valid */
0098     if (level < 1)
0099         level = 1;
0100 
0101     psb_intel_lvds_set_brightness(dev, level);
0102     psb_brightness = level;
0103     return 0;
0104 }
0105 
0106 static const struct backlight_ops psb_ops = {
0107     .get_brightness = psb_get_brightness,
0108     .update_status  = psb_set_brightness,
0109 };
0110 
0111 static int psb_backlight_init(struct drm_device *dev)
0112 {
0113     struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0114     int ret;
0115     struct backlight_properties props;
0116 
0117     memset(&props, 0, sizeof(struct backlight_properties));
0118     props.max_brightness = 100;
0119     props.type = BACKLIGHT_PLATFORM;
0120 
0121     psb_backlight_device = backlight_device_register("psb-bl",
0122                     NULL, (void *)dev, &psb_ops, &props);
0123     if (IS_ERR(psb_backlight_device))
0124         return PTR_ERR(psb_backlight_device);
0125 
0126     ret = psb_backlight_setup(dev);
0127     if (ret < 0) {
0128         backlight_device_unregister(psb_backlight_device);
0129         psb_backlight_device = NULL;
0130         return ret;
0131     }
0132     psb_backlight_device->props.brightness = 100;
0133     psb_backlight_device->props.max_brightness = 100;
0134     backlight_update_status(psb_backlight_device);
0135     dev_priv->backlight_device = psb_backlight_device;
0136 
0137     /* This must occur after the backlight is properly initialised */
0138     psb_lid_timer_init(dev_priv);
0139 
0140     return 0;
0141 }
0142 
0143 #endif
0144 
0145 /*
0146  *  Provide the Poulsbo specific chip logic and low level methods
0147  *  for power management
0148  */
0149 
0150 static void psb_init_pm(struct drm_device *dev)
0151 {
0152     struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0153 
0154     u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL);
0155     gating &= ~3;   /* Disable 2D clock gating */
0156     gating |= 1;
0157     PSB_WSGX32(gating, PSB_CR_CLKGATECTL);
0158     PSB_RSGX32(PSB_CR_CLKGATECTL);
0159 }
0160 
0161 /**
0162  *  psb_save_display_registers  -   save registers lost on suspend
0163  *  @dev: our DRM device
0164  *
0165  *  Save the state we need in order to be able to restore the interface
0166  *  upon resume from suspend
0167  */
0168 static int psb_save_display_registers(struct drm_device *dev)
0169 {
0170     struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0171     struct gma_connector *gma_connector;
0172     struct drm_crtc *crtc;
0173     struct drm_connector_list_iter conn_iter;
0174     struct drm_connector *connector;
0175     struct psb_state *regs = &dev_priv->regs.psb;
0176 
0177     /* Display arbitration control + watermarks */
0178     regs->saveDSPARB = PSB_RVDC32(DSPARB);
0179     regs->saveDSPFW1 = PSB_RVDC32(DSPFW1);
0180     regs->saveDSPFW2 = PSB_RVDC32(DSPFW2);
0181     regs->saveDSPFW3 = PSB_RVDC32(DSPFW3);
0182     regs->saveDSPFW4 = PSB_RVDC32(DSPFW4);
0183     regs->saveDSPFW5 = PSB_RVDC32(DSPFW5);
0184     regs->saveDSPFW6 = PSB_RVDC32(DSPFW6);
0185     regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
0186 
0187     /* Save crtc and output state */
0188     drm_modeset_lock_all(dev);
0189     list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
0190         if (drm_helper_crtc_in_use(crtc))
0191             dev_priv->ops->save_crtc(crtc);
0192     }
0193 
0194     drm_connector_list_iter_begin(dev, &conn_iter);
0195     drm_for_each_connector_iter(connector, &conn_iter) {
0196         gma_connector = to_gma_connector(connector);
0197         if (gma_connector->save)
0198             gma_connector->save(connector);
0199     }
0200     drm_connector_list_iter_end(&conn_iter);
0201 
0202     drm_modeset_unlock_all(dev);
0203     return 0;
0204 }
0205 
0206 /**
0207  *  psb_restore_display_registers   -   restore lost register state
0208  *  @dev: our DRM device
0209  *
0210  *  Restore register state that was lost during suspend and resume.
0211  */
0212 static int psb_restore_display_registers(struct drm_device *dev)
0213 {
0214     struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0215     struct gma_connector *gma_connector;
0216     struct drm_crtc *crtc;
0217     struct drm_connector_list_iter conn_iter;
0218     struct drm_connector *connector;
0219     struct psb_state *regs = &dev_priv->regs.psb;
0220 
0221     /* Display arbitration + watermarks */
0222     PSB_WVDC32(regs->saveDSPARB, DSPARB);
0223     PSB_WVDC32(regs->saveDSPFW1, DSPFW1);
0224     PSB_WVDC32(regs->saveDSPFW2, DSPFW2);
0225     PSB_WVDC32(regs->saveDSPFW3, DSPFW3);
0226     PSB_WVDC32(regs->saveDSPFW4, DSPFW4);
0227     PSB_WVDC32(regs->saveDSPFW5, DSPFW5);
0228     PSB_WVDC32(regs->saveDSPFW6, DSPFW6);
0229     PSB_WVDC32(regs->saveCHICKENBIT, DSPCHICKENBIT);
0230 
0231     /*make sure VGA plane is off. it initializes to on after reset!*/
0232     PSB_WVDC32(0x80000000, VGACNTRL);
0233 
0234     drm_modeset_lock_all(dev);
0235     list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
0236         if (drm_helper_crtc_in_use(crtc))
0237             dev_priv->ops->restore_crtc(crtc);
0238 
0239     drm_connector_list_iter_begin(dev, &conn_iter);
0240     drm_for_each_connector_iter(connector, &conn_iter) {
0241         gma_connector = to_gma_connector(connector);
0242         if (gma_connector->restore)
0243             gma_connector->restore(connector);
0244     }
0245     drm_connector_list_iter_end(&conn_iter);
0246 
0247     drm_modeset_unlock_all(dev);
0248     return 0;
0249 }
0250 
0251 static int psb_power_down(struct drm_device *dev)
0252 {
0253     return 0;
0254 }
0255 
0256 static int psb_power_up(struct drm_device *dev)
0257 {
0258     return 0;
0259 }
0260 
0261 /* Poulsbo */
0262 static const struct psb_offset psb_regmap[2] = {
0263     {
0264         .fp0 = FPA0,
0265         .fp1 = FPA1,
0266         .cntr = DSPACNTR,
0267         .conf = PIPEACONF,
0268         .src = PIPEASRC,
0269         .dpll = DPLL_A,
0270         .htotal = HTOTAL_A,
0271         .hblank = HBLANK_A,
0272         .hsync = HSYNC_A,
0273         .vtotal = VTOTAL_A,
0274         .vblank = VBLANK_A,
0275         .vsync = VSYNC_A,
0276         .stride = DSPASTRIDE,
0277         .size = DSPASIZE,
0278         .pos = DSPAPOS,
0279         .base = DSPABASE,
0280         .surf = DSPASURF,
0281         .addr = DSPABASE,
0282         .status = PIPEASTAT,
0283         .linoff = DSPALINOFF,
0284         .tileoff = DSPATILEOFF,
0285         .palette = PALETTE_A,
0286     },
0287     {
0288         .fp0 = FPB0,
0289         .fp1 = FPB1,
0290         .cntr = DSPBCNTR,
0291         .conf = PIPEBCONF,
0292         .src = PIPEBSRC,
0293         .dpll = DPLL_B,
0294         .htotal = HTOTAL_B,
0295         .hblank = HBLANK_B,
0296         .hsync = HSYNC_B,
0297         .vtotal = VTOTAL_B,
0298         .vblank = VBLANK_B,
0299         .vsync = VSYNC_B,
0300         .stride = DSPBSTRIDE,
0301         .size = DSPBSIZE,
0302         .pos = DSPBPOS,
0303         .base = DSPBBASE,
0304         .surf = DSPBSURF,
0305         .addr = DSPBBASE,
0306         .status = PIPEBSTAT,
0307         .linoff = DSPBLINOFF,
0308         .tileoff = DSPBTILEOFF,
0309         .palette = PALETTE_B,
0310     }
0311 };
0312 
0313 static int psb_chip_setup(struct drm_device *dev)
0314 {
0315     struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0316     dev_priv->regmap = psb_regmap;
0317     gma_get_core_freq(dev);
0318     gma_intel_setup_gmbus(dev);
0319     psb_intel_opregion_init(dev);
0320     psb_intel_init_bios(dev);
0321     return 0;
0322 }
0323 
0324 static void psb_chip_teardown(struct drm_device *dev)
0325 {
0326     struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
0327     psb_lid_timer_takedown(dev_priv);
0328     gma_intel_teardown_gmbus(dev);
0329 }
0330 
0331 const struct psb_ops psb_chip_ops = {
0332     .name = "Poulsbo",
0333     .pipes = 2,
0334     .crtcs = 2,
0335     .hdmi_mask = (1 << 0),
0336     .lvds_mask = (1 << 1),
0337     .sdvo_mask = (1 << 0),
0338     .cursor_needs_phys = 1,
0339     .sgx_offset = PSB_SGX_OFFSET,
0340     .chip_setup = psb_chip_setup,
0341     .chip_teardown = psb_chip_teardown,
0342 
0343     .crtc_helper = &psb_intel_helper_funcs,
0344     .clock_funcs = &psb_clock_funcs,
0345 
0346     .output_init = psb_output_init,
0347 
0348 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
0349     .backlight_init = psb_backlight_init,
0350 #endif
0351 
0352     .init_pm = psb_init_pm,
0353     .save_regs = psb_save_display_registers,
0354     .restore_regs = psb_restore_display_registers,
0355     .save_crtc = gma_crtc_save,
0356     .restore_crtc = gma_crtc_restore,
0357     .power_down = psb_power_down,
0358     .power_up = psb_power_up,
0359 };
0360