linux/drivers/gpu/drm/nouveau/nv50_dac.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008 Maarten Maathuis.
   3 * All Rights Reserved.
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining
   6 * a copy of this software and associated documentation files (the
   7 * "Software"), to deal in the Software without restriction, including
   8 * without limitation the rights to use, copy, modify, merge, publish,
   9 * distribute, sublicense, and/or sell copies of the Software, and to
  10 * permit persons to whom the Software is furnished to do so, subject to
  11 * the following conditions:
  12 *
  13 * The above copyright notice and this permission notice (including the
  14 * next paragraph) shall be included in all copies or substantial
  15 * portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
  21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24 *
  25 */
  26
  27#include <drm/drmP.h>
  28#include <drm/drm_crtc_helper.h>
  29
  30#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
  31#include "nouveau_reg.h"
  32#include "nouveau_drm.h"
  33#include "nouveau_dma.h"
  34#include "nouveau_encoder.h"
  35#include "nouveau_connector.h"
  36#include "nouveau_crtc.h"
  37#include "nv50_display.h"
  38
  39#include <subdev/timer.h>
  40
  41static void
  42nv50_dac_disconnect(struct drm_encoder *encoder)
  43{
  44        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
  45        struct drm_device *dev = encoder->dev;
  46        struct nouveau_drm *drm = nouveau_drm(dev);
  47        struct nouveau_channel *evo = nv50_display(dev)->master;
  48        int ret;
  49
  50        if (!nv_encoder->crtc)
  51                return;
  52        nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
  53
  54        NV_DEBUG(drm, "Disconnecting DAC %d\n", nv_encoder->or);
  55
  56        ret = RING_SPACE(evo, 4);
  57        if (ret) {
  58                NV_ERROR(drm, "no space while disconnecting DAC\n");
  59                return;
  60        }
  61        BEGIN_NV04(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
  62        OUT_RING  (evo, 0);
  63        BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
  64        OUT_RING  (evo, 0);
  65
  66        nv_encoder->crtc = NULL;
  67}
  68
  69static enum drm_connector_status
  70nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
  71{
  72        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
  73        struct nouveau_device *device = nouveau_dev(encoder->dev);
  74        struct nouveau_drm *drm = nouveau_drm(encoder->dev);
  75        enum drm_connector_status status = connector_status_disconnected;
  76        uint32_t dpms_state, load_pattern, load_state;
  77        int or = nv_encoder->or;
  78
  79        nv_wr32(device, NV50_PDISPLAY_DAC_CLK_CTRL1(or), 0x00000001);
  80        dpms_state = nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or));
  81
  82        nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
  83                0x00150000 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
  84        if (!nv_wait(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
  85                     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
  86                NV_ERROR(drm, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
  87                NV_ERROR(drm, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
  88                          nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)));
  89                return status;
  90        }
  91
  92        /* Use bios provided value if possible. */
  93        if (drm->vbios.dactestval) {
  94                load_pattern = drm->vbios.dactestval;
  95                NV_DEBUG(drm, "Using bios provided load_pattern of %d\n",
  96                          load_pattern);
  97        } else {
  98                load_pattern = 340;
  99                NV_DEBUG(drm, "Using default load_pattern of %d\n",
 100                         load_pattern);
 101        }
 102
 103        nv_wr32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or),
 104                NV50_PDISPLAY_DAC_LOAD_CTRL_ACTIVE | load_pattern);
 105        mdelay(45); /* give it some time to process */
 106        load_state = nv_rd32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or));
 107
 108        nv_wr32(device, NV50_PDISPLAY_DAC_LOAD_CTRL(or), 0);
 109        nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or), dpms_state |
 110                NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
 111
 112        if ((load_state & NV50_PDISPLAY_DAC_LOAD_CTRL_PRESENT) ==
 113                          NV50_PDISPLAY_DAC_LOAD_CTRL_PRESENT)
 114                status = connector_status_connected;
 115
 116        if (status == connector_status_connected)
 117                NV_DEBUG(drm, "Load was detected on output with or %d\n", or);
 118        else
 119                NV_DEBUG(drm, "Load was not detected on output with or %d\n", or);
 120
 121        return status;
 122}
 123
 124static void
 125nv50_dac_dpms(struct drm_encoder *encoder, int mode)
 126{
 127        struct nouveau_device *device = nouveau_dev(encoder->dev);
 128        struct nouveau_drm *drm = nouveau_drm(encoder->dev);
 129        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 130        uint32_t val;
 131        int or = nv_encoder->or;
 132
 133        NV_DEBUG(drm, "or %d mode %d\n", or, mode);
 134
 135        /* wait for it to be done */
 136        if (!nv_wait(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
 137                     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
 138                NV_ERROR(drm, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
 139                NV_ERROR(drm, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
 140                         nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)));
 141                return;
 142        }
 143
 144        val = nv_rd32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or)) & ~0x7F;
 145
 146        if (mode != DRM_MODE_DPMS_ON)
 147                val |= NV50_PDISPLAY_DAC_DPMS_CTRL_BLANKED;
 148
 149        switch (mode) {
 150        case DRM_MODE_DPMS_STANDBY:
 151                val |= NV50_PDISPLAY_DAC_DPMS_CTRL_HSYNC_OFF;
 152                break;
 153        case DRM_MODE_DPMS_SUSPEND:
 154                val |= NV50_PDISPLAY_DAC_DPMS_CTRL_VSYNC_OFF;
 155                break;
 156        case DRM_MODE_DPMS_OFF:
 157                val |= NV50_PDISPLAY_DAC_DPMS_CTRL_OFF;
 158                val |= NV50_PDISPLAY_DAC_DPMS_CTRL_HSYNC_OFF;
 159                val |= NV50_PDISPLAY_DAC_DPMS_CTRL_VSYNC_OFF;
 160                break;
 161        default:
 162                break;
 163        }
 164
 165        nv_wr32(device, NV50_PDISPLAY_DAC_DPMS_CTRL(or), val |
 166                NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
 167}
 168
 169static void
 170nv50_dac_save(struct drm_encoder *encoder)
 171{
 172        struct nouveau_drm *drm = nouveau_drm(encoder->dev);
 173        NV_ERROR(drm, "!!\n");
 174}
 175
 176static void
 177nv50_dac_restore(struct drm_encoder *encoder)
 178{
 179        struct nouveau_drm *drm = nouveau_drm(encoder->dev);
 180        NV_ERROR(drm, "!!\n");
 181}
 182
 183static bool
 184nv50_dac_mode_fixup(struct drm_encoder *encoder,
 185                    const struct drm_display_mode *mode,
 186                    struct drm_display_mode *adjusted_mode)
 187{
 188        struct nouveau_drm *drm = nouveau_drm(encoder->dev);
 189        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 190        struct nouveau_connector *connector;
 191
 192        NV_DEBUG(drm, "or %d\n", nv_encoder->or);
 193
 194        connector = nouveau_encoder_connector_get(nv_encoder);
 195        if (!connector) {
 196                NV_ERROR(drm, "Encoder has no connector\n");
 197                return false;
 198        }
 199
 200        if (connector->scaling_mode != DRM_MODE_SCALE_NONE &&
 201             connector->native_mode)
 202                drm_mode_copy(adjusted_mode, connector->native_mode);
 203
 204        return true;
 205}
 206
 207static void
 208nv50_dac_commit(struct drm_encoder *encoder)
 209{
 210}
 211
 212static void
 213nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 214                  struct drm_display_mode *adjusted_mode)
 215{
 216        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 217        struct nouveau_drm *drm = nouveau_drm(encoder->dev);
 218        struct drm_device *dev = encoder->dev;
 219        struct nouveau_channel *evo = nv50_display(dev)->master;
 220        struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
 221        uint32_t mode_ctl = 0, mode_ctl2 = 0;
 222        int ret;
 223
 224        NV_DEBUG(drm, "or %d type %d crtc %d\n",
 225                     nv_encoder->or, nv_encoder->dcb->type, crtc->index);
 226
 227        nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
 228
 229        if (crtc->index == 1)
 230                mode_ctl |= NV50_EVO_DAC_MODE_CTRL_CRTC1;
 231        else
 232                mode_ctl |= NV50_EVO_DAC_MODE_CTRL_CRTC0;
 233
 234        /* Lacking a working tv-out, this is not a 100% sure. */
 235        if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG)
 236                mode_ctl |= 0x40;
 237        else
 238        if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
 239                mode_ctl |= 0x100;
 240
 241        if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
 242                mode_ctl2 |= NV50_EVO_DAC_MODE_CTRL2_NHSYNC;
 243
 244        if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
 245                mode_ctl2 |= NV50_EVO_DAC_MODE_CTRL2_NVSYNC;
 246
 247        ret = RING_SPACE(evo, 3);
 248        if (ret) {
 249                NV_ERROR(drm, "no space while connecting DAC\n");
 250                return;
 251        }
 252        BEGIN_NV04(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
 253        OUT_RING(evo, mode_ctl);
 254        OUT_RING(evo, mode_ctl2);
 255
 256        nv_encoder->crtc = encoder->crtc;
 257}
 258
 259static struct drm_crtc *
 260nv50_dac_crtc_get(struct drm_encoder *encoder)
 261{
 262        return nouveau_encoder(encoder)->crtc;
 263}
 264
 265static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
 266        .dpms = nv50_dac_dpms,
 267        .save = nv50_dac_save,
 268        .restore = nv50_dac_restore,
 269        .mode_fixup = nv50_dac_mode_fixup,
 270        .prepare = nv50_dac_disconnect,
 271        .commit = nv50_dac_commit,
 272        .mode_set = nv50_dac_mode_set,
 273        .get_crtc = nv50_dac_crtc_get,
 274        .detect = nv50_dac_detect,
 275        .disable = nv50_dac_disconnect
 276};
 277
 278static void
 279nv50_dac_destroy(struct drm_encoder *encoder)
 280{
 281        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 282        struct nouveau_drm *drm = nouveau_drm(encoder->dev);
 283
 284        if (!encoder)
 285                return;
 286
 287        NV_DEBUG(drm, "\n");
 288
 289        drm_encoder_cleanup(encoder);
 290        kfree(nv_encoder);
 291}
 292
 293static const struct drm_encoder_funcs nv50_dac_encoder_funcs = {
 294        .destroy = nv50_dac_destroy,
 295};
 296
 297int
 298nv50_dac_create(struct drm_connector *connector, struct dcb_output *entry)
 299{
 300        struct nouveau_encoder *nv_encoder;
 301        struct drm_encoder *encoder;
 302
 303        nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
 304        if (!nv_encoder)
 305                return -ENOMEM;
 306        encoder = to_drm_encoder(nv_encoder);
 307
 308        nv_encoder->dcb = entry;
 309        nv_encoder->or = ffs(entry->or) - 1;
 310
 311        drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
 312                         DRM_MODE_ENCODER_DAC);
 313        drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
 314
 315        encoder->possible_crtcs = entry->heads;
 316        encoder->possible_clones = 0;
 317
 318        drm_mode_connector_attach_encoder(connector, encoder);
 319        return 0;
 320}
 321
 322