linux/drivers/gpu/drm/nouveau/core/engine/disp/base.c
<<
>>
Prefs
   1/*
   2 * Copyright 2013 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 * Authors: Ben Skeggs
  23 */
  24
  25#include "priv.h"
  26#include "outp.h"
  27#include "conn.h"
  28
  29static int
  30nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index)
  31{
  32        struct nouveau_disp *disp = event->priv;
  33        struct nvkm_output *outp;
  34        list_for_each_entry(outp, &disp->outp, head) {
  35                if (outp->conn->index == index) {
  36                        if (outp->conn->hpd.event)
  37                                return 0;
  38                        break;
  39                }
  40        }
  41        return -ENOSYS;
  42}
  43
  44int
  45_nouveau_disp_fini(struct nouveau_object *object, bool suspend)
  46{
  47        struct nouveau_disp *disp = (void *)object;
  48        struct nvkm_output *outp;
  49        int ret;
  50
  51        list_for_each_entry(outp, &disp->outp, head) {
  52                ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
  53                if (ret && suspend)
  54                        goto fail_outp;
  55        }
  56
  57        return nouveau_engine_fini(&disp->base, suspend);
  58
  59fail_outp:
  60        list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
  61                nv_ofuncs(outp)->init(nv_object(outp));
  62        }
  63
  64        return ret;
  65}
  66
  67int
  68_nouveau_disp_init(struct nouveau_object *object)
  69{
  70        struct nouveau_disp *disp = (void *)object;
  71        struct nvkm_output *outp;
  72        int ret;
  73
  74        ret = nouveau_engine_init(&disp->base);
  75        if (ret)
  76                return ret;
  77
  78        list_for_each_entry(outp, &disp->outp, head) {
  79                ret = nv_ofuncs(outp)->init(nv_object(outp));
  80                if (ret)
  81                        goto fail_outp;
  82        }
  83
  84        return ret;
  85
  86fail_outp:
  87        list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
  88                nv_ofuncs(outp)->fini(nv_object(outp), false);
  89        }
  90
  91        return ret;
  92}
  93
  94void
  95_nouveau_disp_dtor(struct nouveau_object *object)
  96{
  97        struct nouveau_disp *disp = (void *)object;
  98        struct nvkm_output *outp, *outt;
  99
 100        nouveau_event_destroy(&disp->vblank);
 101
 102        if (disp->outp.next) {
 103                list_for_each_entry_safe(outp, outt, &disp->outp, head) {
 104                        nouveau_object_ref(NULL, (struct nouveau_object **)&outp);
 105                }
 106        }
 107
 108        nouveau_engine_destroy(&disp->base);
 109}
 110
 111int
 112nouveau_disp_create_(struct nouveau_object *parent,
 113                     struct nouveau_object *engine,
 114                     struct nouveau_oclass *oclass, int heads,
 115                     const char *intname, const char *extname,
 116                     int length, void **pobject)
 117{
 118        struct nouveau_disp_impl *impl = (void *)oclass;
 119        struct nouveau_bios *bios = nouveau_bios(parent);
 120        struct nouveau_disp *disp;
 121        struct nouveau_oclass **sclass;
 122        struct nouveau_object *object;
 123        struct dcb_output dcbE;
 124        u8  hpd = 0, ver, hdr;
 125        u32 data;
 126        int ret, i;
 127
 128        ret = nouveau_engine_create_(parent, engine, oclass, true,
 129                                     intname, extname, length, pobject);
 130        disp = *pobject;
 131        if (ret)
 132                return ret;
 133
 134        INIT_LIST_HEAD(&disp->outp);
 135
 136        /* create output objects for each display path in the vbios */
 137        i = -1;
 138        while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
 139                if (dcbE.type == DCB_OUTPUT_UNUSED)
 140                        continue;
 141                if (dcbE.type == DCB_OUTPUT_EOL)
 142                        break;
 143                data = dcbE.location << 4 | dcbE.type;
 144
 145                oclass = nvkm_output_oclass;
 146                sclass = impl->outp;
 147                while (sclass && sclass[0]) {
 148                        if (sclass[0]->handle == data) {
 149                                oclass = sclass[0];
 150                                break;
 151                        }
 152                        sclass++;
 153                }
 154
 155                nouveau_object_ctor(*pobject, *pobject, oclass,
 156                                    &dcbE, i, &object);
 157                hpd = max(hpd, (u8)(dcbE.connector + 1));
 158        }
 159
 160        ret = nouveau_event_create(3, hpd, &disp->hpd);
 161        if (ret)
 162                return ret;
 163
 164        disp->hpd->priv = disp;
 165        disp->hpd->check = nouveau_disp_hpd_check;
 166
 167        ret = nouveau_event_create(1, heads, &disp->vblank);
 168        if (ret)
 169                return ret;
 170
 171        return 0;
 172}
 173