linux/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
<<
>>
Prefs
   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 "nv50.h"
  25#include "head.h"
  26#include "ior.h"
  27#include "rootnv50.h"
  28
  29#include <core/client.h>
  30#include <core/enum.h>
  31#include <core/gpuobj.h>
  32#include <subdev/bios.h>
  33#include <subdev/bios/disp.h>
  34#include <subdev/bios/init.h>
  35#include <subdev/bios/pll.h>
  36#include <subdev/devinit.h>
  37#include <subdev/timer.h>
  38
  39static const struct nvkm_disp_oclass *
  40nv50_disp_root_(struct nvkm_disp *base)
  41{
  42        return nv50_disp(base)->func->root;
  43}
  44
  45static void
  46nv50_disp_intr_(struct nvkm_disp *base)
  47{
  48        struct nv50_disp *disp = nv50_disp(base);
  49        disp->func->intr(disp);
  50}
  51
  52static void *
  53nv50_disp_dtor_(struct nvkm_disp *base)
  54{
  55        struct nv50_disp *disp = nv50_disp(base);
  56        nvkm_event_fini(&disp->uevent);
  57        if (disp->wq)
  58                destroy_workqueue(disp->wq);
  59        return disp;
  60}
  61
  62static const struct nvkm_disp_func
  63nv50_disp_ = {
  64        .dtor = nv50_disp_dtor_,
  65        .intr = nv50_disp_intr_,
  66        .root = nv50_disp_root_,
  67};
  68
  69int
  70nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device,
  71               int index, int heads, struct nvkm_disp **pdisp)
  72{
  73        struct nv50_disp *disp;
  74        int ret, i;
  75
  76        if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL)))
  77                return -ENOMEM;
  78        disp->func = func;
  79        *pdisp = &disp->base;
  80
  81        ret = nvkm_disp_ctor(&nv50_disp_, device, index, &disp->base);
  82        if (ret)
  83                return ret;
  84
  85        disp->wq = create_singlethread_workqueue("nvkm-disp");
  86        if (!disp->wq)
  87                return -ENOMEM;
  88        INIT_WORK(&disp->supervisor, func->super);
  89
  90        for (i = 0; func->head.new && i < heads; i++) {
  91                ret = func->head.new(&disp->base, i);
  92                if (ret)
  93                        return ret;
  94        }
  95
  96        for (i = 0; func->dac.new && i < func->dac.nr; i++) {
  97                ret = func->dac.new(&disp->base, i);
  98                if (ret)
  99                        return ret;
 100        }
 101
 102        for (i = 0; func->pior.new && i < func->pior.nr; i++) {
 103                ret = func->pior.new(&disp->base, i);
 104                if (ret)
 105                        return ret;
 106        }
 107
 108        for (i = 0; func->sor.new && i < func->sor.nr; i++) {
 109                ret = func->sor.new(&disp->base, i);
 110                if (ret)
 111                        return ret;
 112        }
 113
 114        return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent);
 115}
 116
 117static u32
 118nv50_disp_super_iedt(struct nvkm_head *head, struct nvkm_outp *outp,
 119                     u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
 120                     struct nvbios_outp *iedt)
 121{
 122        struct nvkm_bios *bios = head->disp->engine.subdev.device->bios;
 123        const u8  l = ffs(outp->info.link);
 124        const u16 t = outp->info.hasht;
 125        const u16 m = (0x0100 << head->id) | (l << 6) | outp->info.or;
 126        u32 data = nvbios_outp_match(bios, t, m, ver, hdr, cnt, len, iedt);
 127        if (!data)
 128                OUTP_DBG(outp, "missing IEDT for %04x:%04x", t, m);
 129        return data;
 130}
 131
 132static void
 133nv50_disp_super_ied_on(struct nvkm_head *head,
 134                       struct nvkm_ior *ior, int id, u32 khz)
 135{
 136        struct nvkm_subdev *subdev = &head->disp->engine.subdev;
 137        struct nvkm_bios *bios = subdev->device->bios;
 138        struct nvkm_outp *outp = ior->asy.outp;
 139        struct nvbios_ocfg iedtrs;
 140        struct nvbios_outp iedt;
 141        u8  ver, hdr, cnt, len, flags = 0x00;
 142        u32 data;
 143
 144        if (!outp) {
 145                IOR_DBG(ior, "nothing to attach");
 146                return;
 147        }
 148
 149        /* Lookup IED table for the device. */
 150        data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt);
 151        if (!data)
 152                return;
 153
 154        /* Lookup IEDT runtime settings for the current configuration. */
 155        if (ior->type == SOR) {
 156                if (ior->asy.proto == LVDS) {
 157                        if (head->asy.or.depth == 24)
 158                                flags |= 0x02;
 159                }
 160                if (ior->asy.link == 3)
 161                        flags |= 0x01;
 162        }
 163
 164        data = nvbios_ocfg_match(bios, data, ior->asy.proto_evo, flags,
 165                                 &ver, &hdr, &cnt, &len, &iedtrs);
 166        if (!data) {
 167                OUTP_DBG(outp, "missing IEDT RS for %02x:%02x",
 168                         ior->asy.proto_evo, flags);
 169                return;
 170        }
 171
 172        /* Execute the OnInt[23] script for the current frequency. */
 173        data = nvbios_oclk_match(bios, iedtrs.clkcmp[id], khz);
 174        if (!data) {
 175                OUTP_DBG(outp, "missing IEDT RSS %d for %02x:%02x %d khz",
 176                         id, ior->asy.proto_evo, flags, khz);
 177                return;
 178        }
 179
 180        nvbios_init(subdev, data,
 181                init.outp = &outp->info;
 182                init.or   = ior->id;
 183                init.link = ior->asy.link;
 184                init.head = head->id;
 185        );
 186}
 187
 188static void
 189nv50_disp_super_ied_off(struct nvkm_head *head, struct nvkm_ior *ior, int id)
 190{
 191        struct nvkm_outp *outp = ior->arm.outp;
 192        struct nvbios_outp iedt;
 193        u8  ver, hdr, cnt, len;
 194        u32 data;
 195
 196        if (!outp) {
 197                IOR_DBG(ior, "nothing attached");
 198                return;
 199        }
 200
 201        data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt);
 202        if (!data)
 203                return;
 204
 205        nvbios_init(&head->disp->engine.subdev, iedt.script[id],
 206                init.outp = &outp->info;
 207                init.or   = ior->id;
 208                init.link = ior->arm.link;
 209                init.head = head->id;
 210        );
 211}
 212
 213static struct nvkm_ior *
 214nv50_disp_super_ior_asy(struct nvkm_head *head)
 215{
 216        struct nvkm_ior *ior;
 217        list_for_each_entry(ior, &head->disp->ior, head) {
 218                if (ior->asy.head & (1 << head->id)) {
 219                        HEAD_DBG(head, "to %s", ior->name);
 220                        return ior;
 221                }
 222        }
 223        HEAD_DBG(head, "nothing to attach");
 224        return NULL;
 225}
 226
 227static struct nvkm_ior *
 228nv50_disp_super_ior_arm(struct nvkm_head *head)
 229{
 230        struct nvkm_ior *ior;
 231        list_for_each_entry(ior, &head->disp->ior, head) {
 232                if (ior->arm.head & (1 << head->id)) {
 233                        HEAD_DBG(head, "on %s", ior->name);
 234                        return ior;
 235                }
 236        }
 237        HEAD_DBG(head, "nothing attached");
 238        return NULL;
 239}
 240
 241void
 242nv50_disp_super_3_0(struct nv50_disp *disp, struct nvkm_head *head)
 243{
 244        struct nvkm_ior *ior;
 245
 246        /* Determine which OR, if any, we're attaching to the head. */
 247        HEAD_DBG(head, "supervisor 3.0");
 248        ior = nv50_disp_super_ior_asy(head);
 249        if (!ior)
 250                return;
 251
 252        /* Execute OnInt3 IED script. */
 253        nv50_disp_super_ied_on(head, ior, 1, head->asy.hz / 1000);
 254
 255        /* OR-specific handling. */
 256        if (ior->func->war_3)
 257                ior->func->war_3(ior);
 258}
 259
 260static void
 261nv50_disp_super_2_2_dp(struct nvkm_head *head, struct nvkm_ior *ior)
 262{
 263        struct nvkm_subdev *subdev = &head->disp->engine.subdev;
 264        const u32      khz = head->asy.hz / 1000;
 265        const u32 linkKBps = ior->dp.bw * 27000;
 266        const u32   symbol = 100000;
 267        int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
 268        int TU, VTUi, VTUf, VTUa;
 269        u64 link_data_rate, link_ratio, unk;
 270        u32 best_diff = 64 * symbol;
 271        u64 h, v;
 272
 273        /* symbols/hblank - algorithm taken from comments in tegra driver */
 274        h = head->asy.hblanke + head->asy.htotal - head->asy.hblanks - 7;
 275        h = h * linkKBps;
 276        do_div(h, khz);
 277        h = h - (3 * ior->dp.ef) - (12 / ior->dp.nr);
 278
 279        /* symbols/vblank - algorithm taken from comments in tegra driver */
 280        v = head->asy.vblanks - head->asy.vblanke - 25;
 281        v = v * linkKBps;
 282        do_div(v, khz);
 283        v = v - ((36 / ior->dp.nr) + 3) - 1;
 284
 285        ior->func->dp.audio_sym(ior, head->id, h, v);
 286
 287        /* watermark / activesym */
 288        link_data_rate = (khz * head->asy.or.depth / 8) / ior->dp.nr;
 289
 290        /* calculate ratio of packed data rate to link symbol rate */
 291        link_ratio = link_data_rate * symbol;
 292        do_div(link_ratio, linkKBps);
 293
 294        for (TU = 64; ior->func->dp.activesym && TU >= 32; TU--) {
 295                /* calculate average number of valid symbols in each TU */
 296                u32 tu_valid = link_ratio * TU;
 297                u32 calc, diff;
 298
 299                /* find a hw representation for the fraction.. */
 300                VTUi = tu_valid / symbol;
 301                calc = VTUi * symbol;
 302                diff = tu_valid - calc;
 303                if (diff) {
 304                        if (diff >= (symbol / 2)) {
 305                                VTUf = symbol / (symbol - diff);
 306                                if (symbol - (VTUf * diff))
 307                                        VTUf++;
 308
 309                                if (VTUf <= 15) {
 310                                        VTUa  = 1;
 311                                        calc += symbol - (symbol / VTUf);
 312                                } else {
 313                                        VTUa  = 0;
 314                                        VTUf  = 1;
 315                                        calc += symbol;
 316                                }
 317                        } else {
 318                                VTUa  = 0;
 319                                VTUf  = min((int)(symbol / diff), 15);
 320                                calc += symbol / VTUf;
 321                        }
 322
 323                        diff = calc - tu_valid;
 324                } else {
 325                        /* no remainder, but the hw doesn't like the fractional
 326                         * part to be zero.  decrement the integer part and
 327                         * have the fraction add a whole symbol back
 328                         */
 329                        VTUa = 0;
 330                        VTUf = 1;
 331                        VTUi--;
 332                }
 333
 334                if (diff < best_diff) {
 335                        best_diff = diff;
 336                        bestTU = TU;
 337                        bestVTUa = VTUa;
 338                        bestVTUf = VTUf;
 339                        bestVTUi = VTUi;
 340                        if (diff == 0)
 341                                break;
 342                }
 343        }
 344
 345        if (ior->func->dp.activesym) {
 346                if (!bestTU) {
 347                        nvkm_error(subdev, "unable to determine dp config\n");
 348                        return;
 349                }
 350                ior->func->dp.activesym(ior, head->id, bestTU,
 351                                        bestVTUa, bestVTUf, bestVTUi);
 352        } else {
 353                bestTU = 64;
 354        }
 355
 356        /* XXX close to vbios numbers, but not right */
 357        unk  = (symbol - link_ratio) * bestTU;
 358        unk *= link_ratio;
 359        do_div(unk, symbol);
 360        do_div(unk, symbol);
 361        unk += 6;
 362
 363        ior->func->dp.watermark(ior, head->id, unk);
 364}
 365
 366void
 367nv50_disp_super_2_2(struct nv50_disp *disp, struct nvkm_head *head)
 368{
 369        const u32 khz = head->asy.hz / 1000;
 370        struct nvkm_outp *outp;
 371        struct nvkm_ior *ior;
 372
 373        /* Determine which OR, if any, we're attaching from the head. */
 374        HEAD_DBG(head, "supervisor 2.2");
 375        ior = nv50_disp_super_ior_asy(head);
 376        if (!ior)
 377                return;
 378
 379        /* For some reason, NVIDIA decided not to:
 380         *
 381         * A) Give dual-link LVDS a separate EVO protocol, like for TMDS.
 382         *  and
 383         * B) Use SetControlOutputResource.PixelDepth on LVDS.
 384         *
 385         * Override the values we usually read from HW with the same
 386         * data we pass though an ioctl instead.
 387         */
 388        if (ior->type == SOR && ior->asy.proto == LVDS) {
 389                head->asy.or.depth = (disp->sor.lvdsconf & 0x0200) ? 24 : 18;
 390                ior->asy.link      = (disp->sor.lvdsconf & 0x0100) ? 3  : 1;
 391        }
 392
 393        /* Handle any link training, etc. */
 394        if ((outp = ior->asy.outp) && outp->func->acquire)
 395                outp->func->acquire(outp);
 396
 397        /* Execute OnInt2 IED script. */
 398        nv50_disp_super_ied_on(head, ior, 0, khz);
 399
 400        /* Program RG clock divider. */
 401        head->func->rgclk(head, ior->asy.rgdiv);
 402
 403        /* Mode-specific internal DP configuration. */
 404        if (ior->type == SOR && ior->asy.proto == DP)
 405                nv50_disp_super_2_2_dp(head, ior);
 406
 407        /* OR-specific handling. */
 408        ior->func->clock(ior);
 409        if (ior->func->war_2)
 410                ior->func->war_2(ior);
 411}
 412
 413void
 414nv50_disp_super_2_1(struct nv50_disp *disp, struct nvkm_head *head)
 415{
 416        struct nvkm_devinit *devinit = disp->base.engine.subdev.device->devinit;
 417        const u32 khz = head->asy.hz / 1000;
 418        HEAD_DBG(head, "supervisor 2.1 - %d khz", khz);
 419        if (khz)
 420                nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head->id, khz);
 421}
 422
 423void
 424nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head)
 425{
 426        struct nvkm_outp *outp;
 427        struct nvkm_ior *ior;
 428
 429        /* Determine which OR, if any, we're detaching from the head. */
 430        HEAD_DBG(head, "supervisor 2.0");
 431        ior = nv50_disp_super_ior_arm(head);
 432        if (!ior)
 433                return;
 434
 435        /* Execute OffInt2 IED script. */
 436        nv50_disp_super_ied_off(head, ior, 2);
 437
 438        /* If we're shutting down the OR's only active head, execute
 439         * the output path's release function.
 440         */
 441        if (ior->arm.head == (1 << head->id)) {
 442                if ((outp = ior->arm.outp) && outp->func->release)
 443                        outp->func->release(outp, ior);
 444        }
 445}
 446
 447void
 448nv50_disp_super_1_0(struct nv50_disp *disp, struct nvkm_head *head)
 449{
 450        struct nvkm_ior *ior;
 451
 452        /* Determine which OR, if any, we're detaching from the head. */
 453        HEAD_DBG(head, "supervisor 1.0");
 454        ior = nv50_disp_super_ior_arm(head);
 455        if (!ior)
 456                return;
 457
 458        /* Execute OffInt1 IED script. */
 459        nv50_disp_super_ied_off(head, ior, 1);
 460}
 461
 462void
 463nv50_disp_super_1(struct nv50_disp *disp)
 464{
 465        struct nvkm_head *head;
 466        struct nvkm_ior *ior;
 467
 468        list_for_each_entry(head, &disp->base.head, head) {
 469                head->func->state(head, &head->arm);
 470                head->func->state(head, &head->asy);
 471        }
 472
 473        list_for_each_entry(ior, &disp->base.ior, head) {
 474                ior->func->state(ior, &ior->arm);
 475                ior->func->state(ior, &ior->asy);
 476        }
 477}
 478
 479void
 480nv50_disp_super(struct work_struct *work)
 481{
 482        struct nv50_disp *disp =
 483                container_of(work, struct nv50_disp, supervisor);
 484        struct nvkm_subdev *subdev = &disp->base.engine.subdev;
 485        struct nvkm_device *device = subdev->device;
 486        struct nvkm_head *head;
 487        u32 super = nvkm_rd32(device, 0x610030);
 488
 489        nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super);
 490
 491        if (disp->super & 0x00000010) {
 492                nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG);
 493                nv50_disp_super_1(disp);
 494                list_for_each_entry(head, &disp->base.head, head) {
 495                        if (!(super & (0x00000020 << head->id)))
 496                                continue;
 497                        if (!(super & (0x00000080 << head->id)))
 498                                continue;
 499                        nv50_disp_super_1_0(disp, head);
 500                }
 501        } else
 502        if (disp->super & 0x00000020) {
 503                list_for_each_entry(head, &disp->base.head, head) {
 504                        if (!(super & (0x00000080 << head->id)))
 505                                continue;
 506                        nv50_disp_super_2_0(disp, head);
 507                }
 508                nvkm_outp_route(&disp->base);
 509                list_for_each_entry(head, &disp->base.head, head) {
 510                        if (!(super & (0x00000200 << head->id)))
 511                                continue;
 512                        nv50_disp_super_2_1(disp, head);
 513                }
 514                list_for_each_entry(head, &disp->base.head, head) {
 515                        if (!(super & (0x00000080 << head->id)))
 516                                continue;
 517                        nv50_disp_super_2_2(disp, head);
 518                }
 519        } else
 520        if (disp->super & 0x00000040) {
 521                list_for_each_entry(head, &disp->base.head, head) {
 522                        if (!(super & (0x00000080 << head->id)))
 523                                continue;
 524                        nv50_disp_super_3_0(disp, head);
 525                }
 526        }
 527
 528        nvkm_wr32(device, 0x610030, 0x80000000);
 529}
 530
 531static const struct nvkm_enum
 532nv50_disp_intr_error_type[] = {
 533        { 3, "ILLEGAL_MTHD" },
 534        { 4, "INVALID_VALUE" },
 535        { 5, "INVALID_STATE" },
 536        { 7, "INVALID_HANDLE" },
 537        {}
 538};
 539
 540static const struct nvkm_enum
 541nv50_disp_intr_error_code[] = {
 542        { 0x00, "" },
 543        {}
 544};
 545
 546static void
 547nv50_disp_intr_error(struct nv50_disp *disp, int chid)
 548{
 549        struct nvkm_subdev *subdev = &disp->base.engine.subdev;
 550        struct nvkm_device *device = subdev->device;
 551        u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08));
 552        u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08));
 553        u32 code = (addr & 0x00ff0000) >> 16;
 554        u32 type = (addr & 0x00007000) >> 12;
 555        u32 mthd = (addr & 0x00000ffc);
 556        const struct nvkm_enum *ec, *et;
 557
 558        et = nvkm_enum_find(nv50_disp_intr_error_type, type);
 559        ec = nvkm_enum_find(nv50_disp_intr_error_code, code);
 560
 561        nvkm_error(subdev,
 562                   "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n",
 563                   type, et ? et->name : "", code, ec ? ec->name : "",
 564                   chid, mthd, data);
 565
 566        if (chid < ARRAY_SIZE(disp->chan)) {
 567                switch (mthd) {
 568                case 0x0080:
 569                        nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR);
 570                        break;
 571                default:
 572                        break;
 573                }
 574        }
 575
 576        nvkm_wr32(device, 0x610020, 0x00010000 << chid);
 577        nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000);
 578}
 579
 580void
 581nv50_disp_intr(struct nv50_disp *disp)
 582{
 583        struct nvkm_device *device = disp->base.engine.subdev.device;
 584        u32 intr0 = nvkm_rd32(device, 0x610020);
 585        u32 intr1 = nvkm_rd32(device, 0x610024);
 586
 587        while (intr0 & 0x001f0000) {
 588                u32 chid = __ffs(intr0 & 0x001f0000) - 16;
 589                nv50_disp_intr_error(disp, chid);
 590                intr0 &= ~(0x00010000 << chid);
 591        }
 592
 593        while (intr0 & 0x0000001f) {
 594                u32 chid = __ffs(intr0 & 0x0000001f);
 595                nv50_disp_chan_uevent_send(disp, chid);
 596                intr0 &= ~(0x00000001 << chid);
 597        }
 598
 599        if (intr1 & 0x00000004) {
 600                nvkm_disp_vblank(&disp->base, 0);
 601                nvkm_wr32(device, 0x610024, 0x00000004);
 602        }
 603
 604        if (intr1 & 0x00000008) {
 605                nvkm_disp_vblank(&disp->base, 1);
 606                nvkm_wr32(device, 0x610024, 0x00000008);
 607        }
 608
 609        if (intr1 & 0x00000070) {
 610                disp->super = (intr1 & 0x00000070);
 611                queue_work(disp->wq, &disp->supervisor);
 612                nvkm_wr32(device, 0x610024, disp->super);
 613        }
 614}
 615
 616static const struct nv50_disp_func
 617nv50_disp = {
 618        .intr = nv50_disp_intr,
 619        .uevent = &nv50_disp_chan_uevent,
 620        .super = nv50_disp_super,
 621        .root = &nv50_disp_root_oclass,
 622        .head.new = nv50_head_new,
 623        .dac = { .nr = 3, .new = nv50_dac_new },
 624        .sor = { .nr = 2, .new = nv50_sor_new },
 625        .pior = { .nr = 3, .new = nv50_pior_new },
 626};
 627
 628int
 629nv50_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
 630{
 631        return nv50_disp_new_(&nv50_disp, device, index, 2, pdisp);
 632}
 633