mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-05 03:59:04 -04:00
drm/nouveau/disp: move outp/conn construction to chipset code
- pre-nv5x doesn't use any of this, has its own version DRM-side - preparation for GSP-RM Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Reviewed-by: Lyude Paul <lyude@redhat.com> Acked-by: Danilo Krummrich <me@dakr.org> Signed-off-by: Lyude Paul <lyude@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230919220442.202488-37-lyude@redhat.com
This commit is contained in:
@@ -23,15 +23,12 @@
|
||||
*/
|
||||
#include "priv.h"
|
||||
#include "conn.h"
|
||||
#include "dp.h"
|
||||
#include "head.h"
|
||||
#include "ior.h"
|
||||
#include "outp.h"
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/ramht.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/dcb.h>
|
||||
|
||||
#include <nvif/class.h>
|
||||
#include <nvif/cl0046.h>
|
||||
@@ -159,123 +156,11 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
|
||||
{
|
||||
struct nvkm_disp *disp = nvkm_disp(engine);
|
||||
struct nvkm_subdev *subdev = &disp->engine.subdev;
|
||||
struct nvkm_bios *bios = subdev->device->bios;
|
||||
struct nvkm_outp *outp, *outt, *pair;
|
||||
struct nvkm_conn *conn;
|
||||
struct nvkm_outp *outp;
|
||||
struct nvkm_head *head;
|
||||
struct nvkm_ior *ior;
|
||||
struct nvbios_connE connE;
|
||||
struct dcb_output dcbE;
|
||||
u8 hpd = 0, ver, hdr;
|
||||
u32 data;
|
||||
int ret, i;
|
||||
|
||||
/* Create output path objects for each VBIOS display path. */
|
||||
i = -1;
|
||||
while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
|
||||
if (ver < 0x40) /* No support for chipsets prior to NV50. */
|
||||
break;
|
||||
if (dcbE.type == DCB_OUTPUT_UNUSED)
|
||||
continue;
|
||||
if (dcbE.type == DCB_OUTPUT_EOL)
|
||||
break;
|
||||
outp = NULL;
|
||||
|
||||
switch (dcbE.type) {
|
||||
case DCB_OUTPUT_ANALOG:
|
||||
case DCB_OUTPUT_TV:
|
||||
case DCB_OUTPUT_TMDS:
|
||||
case DCB_OUTPUT_LVDS:
|
||||
ret = nvkm_outp_new(disp, i, &dcbE, &outp);
|
||||
break;
|
||||
case DCB_OUTPUT_DP:
|
||||
ret = nvkm_dp_new(disp, i, &dcbE, &outp);
|
||||
break;
|
||||
case DCB_OUTPUT_WFD:
|
||||
/* No support for WFD yet. */
|
||||
ret = -ENODEV;
|
||||
continue;
|
||||
default:
|
||||
nvkm_warn(subdev, "dcb %d type %d unknown\n",
|
||||
i, dcbE.type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (outp) {
|
||||
if (ret != -ENODEV)
|
||||
OUTP_ERR(outp, "ctor failed: %d", ret);
|
||||
else
|
||||
OUTP_DBG(outp, "not supported");
|
||||
nvkm_outp_del(&outp);
|
||||
continue;
|
||||
}
|
||||
nvkm_error(subdev, "failed to create outp %d\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
list_add_tail(&outp->head, &disp->outps);
|
||||
hpd = max(hpd, (u8)(dcbE.connector + 1));
|
||||
}
|
||||
|
||||
/* Create connector objects based on available output paths. */
|
||||
list_for_each_entry_safe(outp, outt, &disp->outps, head) {
|
||||
/* VBIOS data *should* give us the most useful information. */
|
||||
data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
|
||||
&connE);
|
||||
|
||||
/* No bios connector data... */
|
||||
if (!data) {
|
||||
/* Heuristic: anything with the same ccb index is
|
||||
* considered to be on the same connector, any
|
||||
* output path without an associated ccb entry will
|
||||
* be put on its own connector.
|
||||
*/
|
||||
int ccb_index = outp->info.i2c_index;
|
||||
if (ccb_index != 0xf) {
|
||||
list_for_each_entry(pair, &disp->outps, head) {
|
||||
if (pair->info.i2c_index == ccb_index) {
|
||||
outp->conn = pair->conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Connector shared with another output path. */
|
||||
if (outp->conn)
|
||||
continue;
|
||||
|
||||
memset(&connE, 0x00, sizeof(connE));
|
||||
connE.type = DCB_CONNECTOR_NONE;
|
||||
i = -1;
|
||||
} else {
|
||||
i = outp->info.connector;
|
||||
}
|
||||
|
||||
/* Check that we haven't already created this connector. */
|
||||
list_for_each_entry(conn, &disp->conns, head) {
|
||||
if (conn->index == outp->info.connector) {
|
||||
outp->conn = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (outp->conn)
|
||||
continue;
|
||||
|
||||
/* Apparently we need to create a new one! */
|
||||
ret = nvkm_conn_new(disp, i, &connE, &outp->conn);
|
||||
if (ret) {
|
||||
nvkm_error(subdev, "failed to create outp %d conn: %d\n", outp->index, ret);
|
||||
nvkm_conn_del(&outp->conn);
|
||||
list_del(&outp->head);
|
||||
nvkm_outp_del(&outp);
|
||||
continue;
|
||||
}
|
||||
|
||||
list_add_tail(&outp->conn->head, &disp->conns);
|
||||
}
|
||||
|
||||
if (disp->func->oneinit) {
|
||||
ret = disp->func->oneinit(disp);
|
||||
if (ret)
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
*/
|
||||
#include "priv.h"
|
||||
#include "chan.h"
|
||||
#include "conn.h"
|
||||
#include "head.h"
|
||||
#include "dp.h"
|
||||
#include "ior.h"
|
||||
#include "outp.h"
|
||||
|
||||
@@ -1581,7 +1583,14 @@ nv50_disp_oneinit(struct nvkm_disp *disp)
|
||||
const struct nvkm_disp_func *func = disp->func;
|
||||
struct nvkm_subdev *subdev = &disp->engine.subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
struct nvkm_bios *bios = device->bios;
|
||||
struct nvkm_outp *outp, *outt, *pair;
|
||||
struct nvkm_conn *conn;
|
||||
int ret, i;
|
||||
u8 ver, hdr;
|
||||
u32 data;
|
||||
struct dcb_output dcbE;
|
||||
struct nvbios_connE connE;
|
||||
|
||||
if (func->wndw.cnt) {
|
||||
disp->wndw.nr = func->wndw.cnt(disp, &disp->wndw.mask);
|
||||
@@ -1628,8 +1637,117 @@ nv50_disp_oneinit(struct nvkm_disp *disp)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return nvkm_ramht_new(device, func->ramht_size ? func->ramht_size :
|
||||
0x1000, 0, disp->inst, &disp->ramht);
|
||||
ret = nvkm_ramht_new(device, func->ramht_size ? func->ramht_size : 0x1000, 0, disp->inst,
|
||||
&disp->ramht);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Create output path objects for each VBIOS display path. */
|
||||
i = -1;
|
||||
while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
|
||||
if (WARN_ON((ver & 0xf0) != 0x40))
|
||||
return -EINVAL;
|
||||
if (dcbE.type == DCB_OUTPUT_UNUSED)
|
||||
continue;
|
||||
if (dcbE.type == DCB_OUTPUT_EOL)
|
||||
break;
|
||||
outp = NULL;
|
||||
|
||||
switch (dcbE.type) {
|
||||
case DCB_OUTPUT_ANALOG:
|
||||
case DCB_OUTPUT_TV:
|
||||
case DCB_OUTPUT_TMDS:
|
||||
case DCB_OUTPUT_LVDS:
|
||||
ret = nvkm_outp_new(disp, i, &dcbE, &outp);
|
||||
break;
|
||||
case DCB_OUTPUT_DP:
|
||||
ret = nvkm_dp_new(disp, i, &dcbE, &outp);
|
||||
break;
|
||||
case DCB_OUTPUT_WFD:
|
||||
/* No support for WFD yet. */
|
||||
ret = -ENODEV;
|
||||
continue;
|
||||
default:
|
||||
nvkm_warn(subdev, "dcb %d type %d unknown\n",
|
||||
i, dcbE.type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (outp) {
|
||||
if (ret != -ENODEV)
|
||||
OUTP_ERR(outp, "ctor failed: %d", ret);
|
||||
else
|
||||
OUTP_DBG(outp, "not supported");
|
||||
nvkm_outp_del(&outp);
|
||||
continue;
|
||||
}
|
||||
nvkm_error(subdev, "failed to create outp %d\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
list_add_tail(&outp->head, &disp->outps);
|
||||
}
|
||||
|
||||
/* Create connector objects based on available output paths. */
|
||||
list_for_each_entry_safe(outp, outt, &disp->outps, head) {
|
||||
/* VBIOS data *should* give us the most useful information. */
|
||||
data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
|
||||
&connE);
|
||||
|
||||
/* No bios connector data... */
|
||||
if (!data) {
|
||||
/* Heuristic: anything with the same ccb index is
|
||||
* considered to be on the same connector, any
|
||||
* output path without an associated ccb entry will
|
||||
* be put on its own connector.
|
||||
*/
|
||||
int ccb_index = outp->info.i2c_index;
|
||||
if (ccb_index != 0xf) {
|
||||
list_for_each_entry(pair, &disp->outps, head) {
|
||||
if (pair->info.i2c_index == ccb_index) {
|
||||
outp->conn = pair->conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Connector shared with another output path. */
|
||||
if (outp->conn)
|
||||
continue;
|
||||
|
||||
memset(&connE, 0x00, sizeof(connE));
|
||||
connE.type = DCB_CONNECTOR_NONE;
|
||||
i = -1;
|
||||
} else {
|
||||
i = outp->info.connector;
|
||||
}
|
||||
|
||||
/* Check that we haven't already created this connector. */
|
||||
list_for_each_entry(conn, &disp->conns, head) {
|
||||
if (conn->index == outp->info.connector) {
|
||||
outp->conn = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (outp->conn)
|
||||
continue;
|
||||
|
||||
/* Apparently we need to create a new one! */
|
||||
ret = nvkm_conn_new(disp, i, &connE, &outp->conn);
|
||||
if (ret) {
|
||||
nvkm_error(subdev, "failed to create outp %d conn: %d\n", outp->index, ret);
|
||||
nvkm_conn_del(&outp->conn);
|
||||
list_del(&outp->head);
|
||||
nvkm_outp_del(&outp);
|
||||
continue;
|
||||
}
|
||||
|
||||
list_add_tail(&outp->conn->head, &disp->conns);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nvkm_disp_func
|
||||
|
||||
Reference in New Issue
Block a user