drm/nv50/devinit: reverse the logic for running encoder init scripts
[opensuse:kernel.git] / drivers / gpu / drm / nouveau / core / subdev / devinit / nv50.c
1 /*
2  * Copyright 2012 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 <subdev/bios.h>
26 #include <subdev/bios/dcb.h>
27 #include <subdev/bios/disp.h>
28 #include <subdev/bios/init.h>
29 #include <subdev/devinit.h>
30 #include <subdev/vga.h>
31
32 struct nv50_devinit_priv {
33         struct nouveau_devinit base;
34 };
35
36 static int
37 nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
38                   struct nouveau_oclass *oclass, void *data, u32 size,
39                   struct nouveau_object **pobject)
40 {
41         struct nv50_devinit_priv *priv;
42         int ret;
43
44         ret = nouveau_devinit_create(parent, engine, oclass, &priv);
45         *pobject = nv_object(priv);
46         if (ret)
47                 return ret;
48
49         return 0;
50 }
51
52 static void
53 nv50_devinit_dtor(struct nouveau_object *object)
54 {
55         struct nv50_devinit_priv *priv = (void *)object;
56         nouveau_devinit_destroy(&priv->base);
57 }
58
59 static int
60 nv50_devinit_init(struct nouveau_object *object)
61 {
62         struct nouveau_bios *bios = nouveau_bios(object);
63         struct nv50_devinit_priv *priv = (void *)object;
64         struct nvbios_outp info;
65         struct dcb_output outp;
66         u8  ver = 0xff, hdr, cnt, len;
67         int ret, i = 0;
68
69         if (!priv->base.post) {
70                 if (!nv_rdvgac(priv, 0, 0x00) &&
71                     !nv_rdvgac(priv, 0, 0x1a)) {
72                         nv_info(priv, "adaptor not initialised\n");
73                         priv->base.post = true;
74                 }
75         }
76
77         ret = nouveau_devinit_init(&priv->base);
78         if (ret)
79                 return ret;
80
81         /* if we ran the init tables, we have to execute the first script
82          * pointer of each dcb entry's display encoder table in order
83          * to properly initialise each encoder.
84          */
85         while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
86                 if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
87                                      &ver, &hdr, &cnt, &len, &info)) {
88                         struct nvbios_init init = {
89                                 .subdev = nv_subdev(priv),
90                                 .bios = bios,
91                                 .offset = info.script[0],
92                                 .outp = &outp,
93                                 .crtc = -1,
94                                 .execute = 1,
95                         };
96
97                         nvbios_exec(&init);
98                 }
99                 i++;
100         }
101
102         return 0;
103 }
104
105 static int
106 nv50_devinit_fini(struct nouveau_object *object, bool suspend)
107 {
108         struct nv50_devinit_priv *priv = (void *)object;
109         return nouveau_devinit_fini(&priv->base, suspend);
110 }
111
112 struct nouveau_oclass
113 nv50_devinit_oclass = {
114         .handle = NV_SUBDEV(DEVINIT, 0x50),
115         .ofuncs = &(struct nouveau_ofuncs) {
116                 .ctor = nv50_devinit_ctor,
117                 .dtor = nv50_devinit_dtor,
118                 .init = nv50_devinit_init,
119                 .fini = nv50_devinit_fini,
120         },
121 };