root/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nv50_disp_root_mthd_
  2. nv50_disp_root_child_new_
  3. nv50_disp_root_child_get_
  4. nv50_disp_root_dtor_
  5. nv50_disp_root_new_
  6. nv50_disp_root_new

   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 #include "rootnv50.h"
  25 #include "channv50.h"
  26 #include "dp.h"
  27 #include "head.h"
  28 #include "ior.h"
  29 
  30 #include <core/client.h>
  31 
  32 #include <nvif/class.h>
  33 #include <nvif/cl5070.h>
  34 #include <nvif/unpack.h>
  35 
  36 static int
  37 nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
  38 {
  39         union {
  40                 struct nv50_disp_mthd_v0 v0;
  41                 struct nv50_disp_mthd_v1 v1;
  42         } *args = data;
  43         struct nv50_disp_root *root = nv50_disp_root(object);
  44         struct nv50_disp *disp = root->disp;
  45         struct nvkm_outp *temp, *outp = NULL;
  46         struct nvkm_head *head;
  47         u16 type, mask = 0;
  48         int hidx, ret = -ENOSYS;
  49 
  50         if (mthd != NV50_DISP_MTHD)
  51                 return -EINVAL;
  52 
  53         nvif_ioctl(object, "disp mthd size %d\n", size);
  54         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
  55                 nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
  56                            args->v0.version, args->v0.method, args->v0.head);
  57                 mthd = args->v0.method;
  58                 hidx = args->v0.head;
  59         } else
  60         if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
  61                 nvif_ioctl(object, "disp mthd vers %d mthd %02x "
  62                                    "type %04x mask %04x\n",
  63                            args->v1.version, args->v1.method,
  64                            args->v1.hasht, args->v1.hashm);
  65                 mthd = args->v1.method;
  66                 type = args->v1.hasht;
  67                 mask = args->v1.hashm;
  68                 hidx = ffs((mask >> 8) & 0x0f) - 1;
  69         } else
  70                 return ret;
  71 
  72         if (!(head = nvkm_head_find(&disp->base, hidx)))
  73                 return -ENXIO;
  74 
  75         if (mask) {
  76                 list_for_each_entry(temp, &disp->base.outp, head) {
  77                         if ((temp->info.hasht         == type) &&
  78                             (temp->info.hashm & mask) == mask) {
  79                                 outp = temp;
  80                                 break;
  81                         }
  82                 }
  83                 if (outp == NULL)
  84                         return -ENXIO;
  85         }
  86 
  87         switch (mthd) {
  88         case NV50_DISP_SCANOUTPOS: {
  89                 return nvkm_head_mthd_scanoutpos(object, head, data, size);
  90         }
  91         default:
  92                 break;
  93         }
  94 
  95         switch (mthd * !!outp) {
  96         case NV50_DISP_MTHD_V1_ACQUIRE: {
  97                 union {
  98                         struct nv50_disp_acquire_v0 v0;
  99                 } *args = data;
 100                 int ret = -ENOSYS;
 101                 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 102                         ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER);
 103                         if (ret == 0) {
 104                                 args->v0.or = outp->ior->id;
 105                                 args->v0.link = outp->ior->asy.link;
 106                         }
 107                 }
 108                 return ret;
 109         }
 110                 break;
 111         case NV50_DISP_MTHD_V1_RELEASE:
 112                 nvkm_outp_release(outp, NVKM_OUTP_USER);
 113                 return 0;
 114         case NV50_DISP_MTHD_V1_DAC_LOAD: {
 115                 union {
 116                         struct nv50_disp_dac_load_v0 v0;
 117                 } *args = data;
 118                 int ret = -ENOSYS;
 119                 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 120                         if (args->v0.data & 0xfff00000)
 121                                 return -EINVAL;
 122                         ret = nvkm_outp_acquire(outp, NVKM_OUTP_PRIV);
 123                         if (ret)
 124                                 return ret;
 125                         ret = outp->ior->func->sense(outp->ior, args->v0.data);
 126                         nvkm_outp_release(outp, NVKM_OUTP_PRIV);
 127                         if (ret < 0)
 128                                 return ret;
 129                         args->v0.load = ret;
 130                         return 0;
 131                 } else
 132                         return ret;
 133         }
 134                 break;
 135         case NV50_DISP_MTHD_V1_SOR_HDA_ELD: {
 136                 union {
 137                         struct nv50_disp_sor_hda_eld_v0 v0;
 138                 } *args = data;
 139                 struct nvkm_ior *ior = outp->ior;
 140                 int ret = -ENOSYS;
 141 
 142                 nvif_ioctl(object, "disp sor hda eld size %d\n", size);
 143                 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
 144                         nvif_ioctl(object, "disp sor hda eld vers %d\n",
 145                                    args->v0.version);
 146                         if (size > 0x60)
 147                                 return -E2BIG;
 148                 } else
 149                         return ret;
 150 
 151                 if (!ior->func->hda.hpd)
 152                         return -ENODEV;
 153 
 154                 if (size && args->v0.data[0]) {
 155                         if (outp->info.type == DCB_OUTPUT_DP)
 156                                 ior->func->dp.audio(ior, hidx, true);
 157                         ior->func->hda.hpd(ior, hidx, true);
 158                         ior->func->hda.eld(ior, data, size);
 159                 } else {
 160                         if (outp->info.type == DCB_OUTPUT_DP)
 161                                 ior->func->dp.audio(ior, hidx, false);
 162                         ior->func->hda.hpd(ior, hidx, false);
 163                 }
 164 
 165                 return 0;
 166         }
 167                 break;
 168         case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: {
 169                 union {
 170                         struct nv50_disp_sor_hdmi_pwr_v0 v0;
 171                 } *args = data;
 172                 u8 *vendor, vendor_size;
 173                 u8 *avi, avi_size;
 174                 int ret = -ENOSYS;
 175 
 176                 nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
 177                 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
 178                         nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
 179                                            "max_ac_packet %d rekey %d scdc %d\n",
 180                                    args->v0.version, args->v0.state,
 181                                    args->v0.max_ac_packet, args->v0.rekey,
 182                                    args->v0.scdc);
 183                         if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
 184                                 return -EINVAL;
 185                         if ((args->v0.avi_infoframe_length
 186                              + args->v0.vendor_infoframe_length) > size)
 187                                 return -EINVAL;
 188                         else
 189                         if ((args->v0.avi_infoframe_length
 190                              + args->v0.vendor_infoframe_length) < size)
 191                                 return -E2BIG;
 192                         avi = data;
 193                         avi_size = args->v0.avi_infoframe_length;
 194                         vendor = avi + avi_size;
 195                         vendor_size = args->v0.vendor_infoframe_length;
 196                 } else
 197                         return ret;
 198 
 199                 if (!outp->ior->func->hdmi.ctrl)
 200                         return -ENODEV;
 201 
 202                 outp->ior->func->hdmi.ctrl(outp->ior, hidx, args->v0.state,
 203                                            args->v0.max_ac_packet,
 204                                            args->v0.rekey, avi, avi_size,
 205                                            vendor, vendor_size);
 206 
 207                 if (outp->ior->func->hdmi.scdc)
 208                         outp->ior->func->hdmi.scdc(
 209                                         outp->ior, hidx, args->v0.scdc);
 210 
 211                 return 0;
 212         }
 213                 break;
 214         case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
 215                 union {
 216                         struct nv50_disp_sor_lvds_script_v0 v0;
 217                 } *args = data;
 218                 int ret = -ENOSYS;
 219                 nvif_ioctl(object, "disp sor lvds script size %d\n", size);
 220                 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 221                         nvif_ioctl(object, "disp sor lvds script "
 222                                            "vers %d name %04x\n",
 223                                    args->v0.version, args->v0.script);
 224                         disp->sor.lvdsconf = args->v0.script;
 225                         return 0;
 226                 } else
 227                         return ret;
 228         }
 229                 break;
 230         case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: {
 231                 struct nvkm_dp *dp = nvkm_dp(outp);
 232                 union {
 233                         struct nv50_disp_sor_dp_mst_link_v0 v0;
 234                 } *args = data;
 235                 int ret = -ENOSYS;
 236                 nvif_ioctl(object, "disp sor dp mst link size %d\n", size);
 237                 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 238                         nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n",
 239                                    args->v0.version, args->v0.state);
 240                         dp->lt.mst = !!args->v0.state;
 241                         return 0;
 242                 } else
 243                         return ret;
 244         }
 245                 break;
 246         case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: {
 247                 union {
 248                         struct nv50_disp_sor_dp_mst_vcpi_v0 v0;
 249                 } *args = data;
 250                 int ret = -ENOSYS;
 251                 nvif_ioctl(object, "disp sor dp mst vcpi size %d\n", size);
 252                 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 253                         nvif_ioctl(object, "disp sor dp mst vcpi vers %d "
 254                                            "slot %02x/%02x pbn %04x/%04x\n",
 255                                    args->v0.version, args->v0.start_slot,
 256                                    args->v0.num_slots, args->v0.pbn,
 257                                    args->v0.aligned_pbn);
 258                         if (!outp->ior->func->dp.vcpi)
 259                                 return -ENODEV;
 260                         outp->ior->func->dp.vcpi(outp->ior, hidx,
 261                                                  args->v0.start_slot,
 262                                                  args->v0.num_slots,
 263                                                  args->v0.pbn,
 264                                                  args->v0.aligned_pbn);
 265                         return 0;
 266                 } else
 267                         return ret;
 268         }
 269                 break;
 270         default:
 271                 break;
 272         }
 273 
 274         return -EINVAL;
 275 }
 276 
 277 static int
 278 nv50_disp_root_child_new_(const struct nvkm_oclass *oclass,
 279                           void *argv, u32 argc, struct nvkm_object **pobject)
 280 {
 281         struct nv50_disp *disp = nv50_disp_root(oclass->parent)->disp;
 282         const struct nv50_disp_user *user = oclass->priv;
 283         return user->ctor(oclass, argv, argc, disp, pobject);
 284 }
 285 
 286 static int
 287 nv50_disp_root_child_get_(struct nvkm_object *object, int index,
 288                           struct nvkm_oclass *sclass)
 289 {
 290         struct nv50_disp_root *root = nv50_disp_root(object);
 291 
 292         if (root->func->user[index].ctor) {
 293                 sclass->base = root->func->user[index].base;
 294                 sclass->priv = root->func->user + index;
 295                 sclass->ctor = nv50_disp_root_child_new_;
 296                 return 0;
 297         }
 298 
 299         return -EINVAL;
 300 }
 301 
 302 static void *
 303 nv50_disp_root_dtor_(struct nvkm_object *object)
 304 {
 305         struct nv50_disp_root *root = nv50_disp_root(object);
 306         return root;
 307 }
 308 
 309 static const struct nvkm_object_func
 310 nv50_disp_root_ = {
 311         .dtor = nv50_disp_root_dtor_,
 312         .mthd = nv50_disp_root_mthd_,
 313         .ntfy = nvkm_disp_ntfy,
 314         .sclass = nv50_disp_root_child_get_,
 315 };
 316 
 317 int
 318 nv50_disp_root_new_(const struct nv50_disp_root_func *func,
 319                     struct nvkm_disp *base, const struct nvkm_oclass *oclass,
 320                     void *data, u32 size, struct nvkm_object **pobject)
 321 {
 322         struct nv50_disp *disp = nv50_disp(base);
 323         struct nv50_disp_root *root;
 324 
 325         if (!(root = kzalloc(sizeof(*root), GFP_KERNEL)))
 326                 return -ENOMEM;
 327         *pobject = &root->object;
 328 
 329         nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object);
 330         root->func = func;
 331         root->disp = disp;
 332         return 0;
 333 }
 334 
 335 static const struct nv50_disp_root_func
 336 nv50_disp_root = {
 337         .user = {
 338                 {{0,0,NV50_DISP_CURSOR             }, nv50_disp_curs_new },
 339                 {{0,0,NV50_DISP_OVERLAY            }, nv50_disp_oimm_new },
 340                 {{0,0,NV50_DISP_BASE_CHANNEL_DMA   }, nv50_disp_base_new },
 341                 {{0,0,NV50_DISP_CORE_CHANNEL_DMA   }, nv50_disp_core_new },
 342                 {{0,0,NV50_DISP_OVERLAY_CHANNEL_DMA}, nv50_disp_ovly_new },
 343                 {}
 344         },
 345 };
 346 
 347 static int
 348 nv50_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
 349                    void *data, u32 size, struct nvkm_object **pobject)
 350 {
 351         return nv50_disp_root_new_(&nv50_disp_root, disp, oclass,
 352                                    data, size, pobject);
 353 }
 354 
 355 const struct nvkm_disp_oclass
 356 nv50_disp_root_oclass = {
 357         .base.oclass = NV50_DISP,
 358         .base.minver = -1,
 359         .base.maxver = -1,
 360         .ctor = nv50_disp_root_new,
 361 };

/* [<][>][^][v][top][bottom][index][help] */