linux/drivers/gpu/drm/gma500/psb_device.c
<<
>>
Prefs
   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
  31static 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
  56static int psb_brightness;
  57static struct backlight_device *psb_backlight_device;
  58
  59static 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
  68static 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
 104static 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
 118static const struct backlight_ops psb_ops = {
 119        .get_brightness = psb_get_brightness,
 120        .update_status  = psb_set_brightness,
 121};
 122
 123static 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
 162static 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 */
 180static 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 drm_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                        crtc->funcs->save(crtc);
 202        }
 203
 204        list_for_each_entry(connector, &dev->mode_config.connector_list, head)
 205                if (connector->funcs->save)
 206                        connector->funcs->save(connector);
 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 */
 218static 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 drm_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                        crtc->funcs->restore(crtc);
 242
 243        list_for_each_entry(connector, &dev->mode_config.connector_list, head)
 244                if (connector->funcs->restore)
 245                        connector->funcs->restore(connector);
 246
 247        drm_modeset_unlock_all(dev);
 248        return 0;
 249}
 250
 251static int psb_power_down(struct drm_device *dev)
 252{
 253        return 0;
 254}
 255
 256static int psb_power_up(struct drm_device *dev)
 257{
 258        return 0;
 259}
 260
 261/* Poulsbo */
 262static 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
 313static 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
 324static 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
 331const 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        .power_down = psb_power_down,
 358        .power_up = psb_power_up,
 359};
 360
 361