linux/drivers/gpu/drm/nouveau/dispnv04/disp.c
<<
>>
Prefs
   1/*
   2 * Copyright 2009 Red Hat Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Author: Ben Skeggs
  23 */
  24
  25#include <drm/drm_crtc_helper.h>
  26
  27#include "nouveau_drv.h"
  28#include "nouveau_reg.h"
  29#include "hw.h"
  30#include "nouveau_encoder.h"
  31#include "nouveau_connector.h"
  32#include "nouveau_bo.h"
  33#include "nouveau_gem.h"
  34#include "nouveau_chan.h"
  35
  36#include <nvif/if0004.h>
  37
  38struct nouveau_connector *
  39nv04_encoder_get_connector(struct nouveau_encoder *encoder)
  40{
  41        struct drm_device *dev = to_drm_encoder(encoder)->dev;
  42        struct drm_connector *connector;
  43        struct drm_connector_list_iter conn_iter;
  44        struct nouveau_connector *nv_connector = NULL;
  45
  46        drm_connector_list_iter_begin(dev, &conn_iter);
  47        drm_for_each_connector_iter(connector, &conn_iter) {
  48                if (connector->encoder == to_drm_encoder(encoder))
  49                        nv_connector = nouveau_connector(connector);
  50        }
  51        drm_connector_list_iter_end(&conn_iter);
  52
  53        return nv_connector;
  54}
  55
  56static void
  57nv04_display_fini(struct drm_device *dev, bool runtime, bool suspend)
  58{
  59        struct nouveau_drm *drm = nouveau_drm(dev);
  60        struct nv04_display *disp = nv04_display(dev);
  61        struct drm_crtc *crtc;
  62
  63        /* Disable flip completion events. */
  64        nvif_notify_put(&disp->flip);
  65
  66        /* Disable vblank interrupts. */
  67        NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
  68        if (nv_two_heads(dev))
  69                NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
  70
  71        if (!runtime)
  72                cancel_work_sync(&drm->hpd_work);
  73
  74        if (!suspend)
  75                return;
  76
  77        /* Un-pin FB and cursors so they'll be evicted to system memory. */
  78        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
  79                struct drm_framebuffer *fb = crtc->primary->fb;
  80                struct nouveau_bo *nvbo;
  81
  82                if (!fb || !fb->obj[0])
  83                        continue;
  84                nvbo = nouveau_gem_object(fb->obj[0]);
  85                nouveau_bo_unpin(nvbo);
  86        }
  87
  88        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
  89                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
  90                if (nv_crtc->cursor.nvbo) {
  91                        if (nv_crtc->cursor.set_offset)
  92                                nouveau_bo_unmap(nv_crtc->cursor.nvbo);
  93                        nouveau_bo_unpin(nv_crtc->cursor.nvbo);
  94                }
  95        }
  96}
  97
  98static int
  99nv04_display_init(struct drm_device *dev, bool resume, bool runtime)
 100{
 101        struct nv04_display *disp = nv04_display(dev);
 102        struct nouveau_drm *drm = nouveau_drm(dev);
 103        struct nouveau_encoder *encoder;
 104        struct drm_crtc *crtc;
 105        int ret;
 106
 107        /* meh.. modeset apparently doesn't setup all the regs and depends
 108         * on pre-existing state, for now load the state of the card *before*
 109         * nouveau was loaded, and then do a modeset.
 110         *
 111         * best thing to do probably is to make save/restore routines not
 112         * save/restore "pre-load" state, but more general so we can save
 113         * on suspend too.
 114         */
 115        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 116                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 117                nv_crtc->save(&nv_crtc->base);
 118        }
 119
 120        list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
 121                encoder->enc_save(&encoder->base.base);
 122
 123        /* Enable flip completion events. */
 124        nvif_notify_get(&disp->flip);
 125
 126        if (!resume)
 127                return 0;
 128
 129        /* Re-pin FB/cursors. */
 130        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 131                struct drm_framebuffer *fb = crtc->primary->fb;
 132                struct nouveau_bo *nvbo;
 133
 134                if (!fb || !fb->obj[0])
 135                        continue;
 136                nvbo = nouveau_gem_object(fb->obj[0]);
 137                ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, true);
 138                if (ret)
 139                        NV_ERROR(drm, "Could not pin framebuffer\n");
 140        }
 141
 142        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 143                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 144                if (!nv_crtc->cursor.nvbo)
 145                        continue;
 146
 147                ret = nouveau_bo_pin(nv_crtc->cursor.nvbo,
 148                                     NOUVEAU_GEM_DOMAIN_VRAM, true);
 149                if (!ret && nv_crtc->cursor.set_offset)
 150                        ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
 151                if (ret)
 152                        NV_ERROR(drm, "Could not pin/map cursor.\n");
 153        }
 154
 155        /* Force CLUT to get re-loaded during modeset. */
 156        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 157                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 158
 159                nv_crtc->lut.depth = 0;
 160        }
 161
 162        /* This should ensure we don't hit a locking problem when someone
 163         * wakes us up via a connector.  We should never go into suspend
 164         * while the display is on anyways.
 165         */
 166        if (runtime)
 167                return 0;
 168
 169        /* Restore mode. */
 170        drm_helper_resume_force_mode(dev);
 171
 172        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 173                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 174
 175                if (!nv_crtc->cursor.nvbo)
 176                        continue;
 177
 178                if (nv_crtc->cursor.set_offset)
 179                        nv_crtc->cursor.set_offset(nv_crtc,
 180                                                   nv_crtc->cursor.nvbo->offset);
 181                nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
 182                                                 nv_crtc->cursor_saved_y);
 183        }
 184
 185        return 0;
 186}
 187
 188static void
 189nv04_display_destroy(struct drm_device *dev)
 190{
 191        struct nv04_display *disp = nv04_display(dev);
 192        struct nouveau_drm *drm = nouveau_drm(dev);
 193        struct nouveau_encoder *encoder;
 194        struct nouveau_crtc *nv_crtc;
 195
 196        /* Restore state */
 197        list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
 198                encoder->enc_restore(&encoder->base.base);
 199
 200        list_for_each_entry(nv_crtc, &dev->mode_config.crtc_list, base.head)
 201                nv_crtc->restore(&nv_crtc->base);
 202
 203        nouveau_hw_save_vga_fonts(dev, 0);
 204
 205        nvif_notify_dtor(&disp->flip);
 206
 207        nouveau_display(dev)->priv = NULL;
 208        vfree(disp);
 209
 210        nvif_object_unmap(&drm->client.device.object);
 211}
 212
 213int
 214nv04_display_create(struct drm_device *dev)
 215{
 216        struct nouveau_drm *drm = nouveau_drm(dev);
 217        struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device);
 218        struct dcb_table *dcb = &drm->vbios.dcb;
 219        struct drm_connector *connector, *ct;
 220        struct drm_encoder *encoder;
 221        struct nouveau_encoder *nv_encoder;
 222        struct nouveau_crtc *crtc;
 223        struct nv04_display *disp;
 224        int i, ret;
 225
 226        disp = vzalloc(sizeof(*disp));
 227        if (!disp)
 228                return -ENOMEM;
 229
 230        nvif_object_map(&drm->client.device.object, NULL, 0);
 231
 232        nouveau_display(dev)->priv = disp;
 233        nouveau_display(dev)->dtor = nv04_display_destroy;
 234        nouveau_display(dev)->init = nv04_display_init;
 235        nouveau_display(dev)->fini = nv04_display_fini;
 236
 237        /* Pre-nv50 doesn't support atomic, so don't expose the ioctls */
 238        dev->driver_features &= ~DRIVER_ATOMIC;
 239
 240        /* Request page flip completion event. */
 241        if (drm->channel) {
 242                nvif_notify_ctor(&drm->channel->nvsw, "kmsFlip", nv04_flip_complete,
 243                                 false, NV04_NVSW_NTFY_UEVENT,
 244                                 NULL, 0, 0, &disp->flip);
 245        }
 246
 247        nouveau_hw_save_vga_fonts(dev, 1);
 248
 249        nv04_crtc_create(dev, 0);
 250        if (nv_two_heads(dev))
 251                nv04_crtc_create(dev, 1);
 252
 253        for (i = 0; i < dcb->entries; i++) {
 254                struct dcb_output *dcbent = &dcb->entry[i];
 255
 256                connector = nouveau_connector_create(dev, dcbent);
 257                if (IS_ERR(connector))
 258                        continue;
 259
 260                switch (dcbent->type) {
 261                case DCB_OUTPUT_ANALOG:
 262                        ret = nv04_dac_create(connector, dcbent);
 263                        break;
 264                case DCB_OUTPUT_LVDS:
 265                case DCB_OUTPUT_TMDS:
 266                        ret = nv04_dfp_create(connector, dcbent);
 267                        break;
 268                case DCB_OUTPUT_TV:
 269                        if (dcbent->location == DCB_LOC_ON_CHIP)
 270                                ret = nv17_tv_create(connector, dcbent);
 271                        else
 272                                ret = nv04_tv_create(connector, dcbent);
 273                        break;
 274                default:
 275                        NV_WARN(drm, "DCB type %d not known\n", dcbent->type);
 276                        continue;
 277                }
 278
 279                if (ret)
 280                        continue;
 281        }
 282
 283        list_for_each_entry_safe(connector, ct,
 284                                 &dev->mode_config.connector_list, head) {
 285                if (!connector->possible_encoders) {
 286                        NV_WARN(drm, "%s has no encoders, removing\n",
 287                                connector->name);
 288                        connector->funcs->destroy(connector);
 289                }
 290        }
 291
 292        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 293                struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 294                struct nvkm_i2c_bus *bus =
 295                        nvkm_i2c_bus_find(i2c, nv_encoder->dcb->i2c_index);
 296                nv_encoder->i2c = bus ? &bus->i2c : NULL;
 297        }
 298
 299        /* Save previous state */
 300        list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
 301                crtc->save(&crtc->base);
 302
 303        list_for_each_entry(nv_encoder, &dev->mode_config.encoder_list, base.base.head)
 304                nv_encoder->enc_save(&nv_encoder->base.base);
 305
 306        nouveau_overlay_init(dev);
 307
 308        return 0;
 309}
 310