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