Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2c906fc authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/disp: transition outp/conn away from being based on nvkm_object



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 2aa5eac5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ struct nvkm_disp {
	struct nvkm_engine engine;

	struct list_head outp;
	struct list_head conn;

	struct nvkm_event hpd;
	struct nvkm_event vblank;
+13 −8
Original line number Diff line number Diff line
nvkm-y += nvkm/engine/disp/base.o
nvkm-y += nvkm/engine/disp/conn.o
nvkm-y += nvkm/engine/disp/outp.o
nvkm-y += nvkm/engine/disp/outpdp.o
nvkm-y += nvkm/engine/disp/nv04.o
nvkm-y += nvkm/engine/disp/nv50.o
nvkm-y += nvkm/engine/disp/g84.o
@@ -13,17 +10,25 @@ nvkm-y += nvkm/engine/disp/gk104.o
nvkm-y += nvkm/engine/disp/gk110.o
nvkm-y += nvkm/engine/disp/gm107.o
nvkm-y += nvkm/engine/disp/gm204.o

nvkm-y += nvkm/engine/disp/outp.o
nvkm-y += nvkm/engine/disp/outpdp.o
nvkm-y += nvkm/engine/disp/dacnv50.o
nvkm-y += nvkm/engine/disp/piornv50.o
nvkm-y += nvkm/engine/disp/sornv50.o
nvkm-y += nvkm/engine/disp/sorg94.o
nvkm-y += nvkm/engine/disp/sorgf110.o
nvkm-y += nvkm/engine/disp/sorgm204.o
nvkm-y += nvkm/engine/disp/dport.o

nvkm-y += nvkm/engine/disp/conn.o

nvkm-y += nvkm/engine/disp/hdagt215.o
nvkm-y += nvkm/engine/disp/hdagf110.o

nvkm-y += nvkm/engine/disp/hdmig84.o
nvkm-y += nvkm/engine/disp/hdmigt215.o
nvkm-y += nvkm/engine/disp/hdmigf110.o
nvkm-y += nvkm/engine/disp/hdmigk104.o
nvkm-y += nvkm/engine/disp/piornv50.o
nvkm-y += nvkm/engine/disp/sornv50.o
nvkm-y += nvkm/engine/disp/sorg94.o
nvkm-y += nvkm/engine/disp/sorgf110.o
nvkm-y += nvkm/engine/disp/sorgm204.o

nvkm-y += nvkm/engine/disp/vga.o
+130 −36
Original line number Diff line number Diff line
@@ -118,29 +118,25 @@ int
_nvkm_disp_fini(struct nvkm_object *object, bool suspend)
{
	struct nvkm_disp *disp = (void *)object;
	struct nvkm_connector *conn;
	struct nvkm_output *outp;
	int ret;

	list_for_each_entry(outp, &disp->outp, head) {
		ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
		if (ret && suspend)
			goto fail_outp;
		nvkm_output_fini(outp);
	}

	return nvkm_engine_fini(&disp->engine, suspend);

fail_outp:
	list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
		nv_ofuncs(outp)->init(nv_object(outp));
	list_for_each_entry(conn, &disp->conn, head) {
		nvkm_connector_fini(conn);
	}

	return ret;
	return nvkm_engine_fini(&disp->engine, suspend);
}

int
_nvkm_disp_init(struct nvkm_object *object)
{
	struct nvkm_disp *disp = (void *)object;
	struct nvkm_connector *conn;
	struct nvkm_output *outp;
	int ret;

@@ -148,17 +144,12 @@ _nvkm_disp_init(struct nvkm_object *object)
	if (ret)
		return ret;

	list_for_each_entry(outp, &disp->outp, head) {
		ret = nv_ofuncs(outp)->init(nv_object(outp));
		if (ret)
			goto fail_outp;
	list_for_each_entry(conn, &disp->conn, head) {
		nvkm_connector_init(conn);
	}

	return ret;

fail_outp:
	list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
		nv_ofuncs(outp)->fini(nv_object(outp), false);
	list_for_each_entry(outp, &disp->outp, head) {
		nvkm_output_init(outp);
	}

	return ret;
@@ -168,15 +159,22 @@ void
_nvkm_disp_dtor(struct nvkm_object *object)
{
	struct nvkm_disp *disp = (void *)object;
	struct nvkm_output *outp, *outt;
	struct nvkm_connector *conn;
	struct nvkm_output *outp;

	nvkm_event_fini(&disp->vblank);
	nvkm_event_fini(&disp->hpd);

	if (disp->outp.next) {
		list_for_each_entry_safe(outp, outt, &disp->outp, head) {
			nvkm_object_ref(NULL, (struct nvkm_object **)&outp);
	while (!list_empty(&disp->outp)) {
		outp = list_first_entry(&disp->outp, typeof(*outp), head);
		list_del(&outp->head);
		nvkm_output_del(&outp);
	}

	while (!list_empty(&disp->conn)) {
		conn = list_first_entry(&disp->conn, typeof(*conn), head);
		list_del(&conn->head);
		nvkm_connector_del(&conn);
	}

	nvkm_engine_destroy(&disp->engine);
@@ -188,10 +186,12 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine,
		  const char *extname, int length, void **pobject)
{
	struct nvkm_disp_impl *impl = (void *)oclass;
	struct nvkm_bios *bios = nvkm_bios(parent);
	struct nvkm_device *device = (void *)parent;
	struct nvkm_bios *bios = device->bios;
	struct nvkm_disp *disp;
	struct nvkm_oclass **sclass;
	struct nvkm_object *object;
	struct nvkm_connector *conn;
	struct nvkm_output *outp, *outt, *pair;
	struct nvbios_connE connE;
	struct dcb_output dcbE;
	u8  hpd = 0, ver, hdr;
	u32 data;
@@ -204,30 +204,124 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine,
		return ret;

	INIT_LIST_HEAD(&disp->outp);
	INIT_LIST_HEAD(&disp->conn);

	/* create output objects for each display path in the vbios */
	i = -1;
	while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
		const struct nvkm_disp_func_outp *outps;
		int (*ctor)(struct nvkm_disp *, int, struct dcb_output *,
			    struct nvkm_output **);

		if (dcbE.type == DCB_OUTPUT_UNUSED)
			continue;
		if (dcbE.type == DCB_OUTPUT_EOL)
			break;
		data = dcbE.location << 4 | dcbE.type;
		outp = NULL;

		oclass = nvkm_output_oclass;
		sclass = impl->outp;
		while (sclass && sclass[0]) {
			if (sclass[0]->handle == data) {
				oclass = sclass[0];
				break;
		switch (dcbE.location) {
		case 0: outps = &impl->outp.internal; break;
		case 1: outps = &impl->outp.external; break;
		default:
			nvkm_warn(&disp->engine.subdev,
				  "dcb %d locn %d unknown\n", i, dcbE.location);
			continue;
		}
			sclass++;

		switch (dcbE.type) {
		case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break;
		case DCB_OUTPUT_TV    : ctor = outps->tv  ; break;
		case DCB_OUTPUT_TMDS  : ctor = outps->tmds; break;
		case DCB_OUTPUT_LVDS  : ctor = outps->lvds; break;
		case DCB_OUTPUT_DP    : ctor = outps->dp  ; break;
		default:
			nvkm_warn(&disp->engine.subdev,
				  "dcb %d type %d unknown\n", i, dcbE.type);
			continue;
		}

		nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object);
		if (ctor)
			ret = ctor(disp, i, &dcbE, &outp);
		else
			ret = -ENODEV;

		if (ret) {
			if (ret == -ENODEV) {
				nvkm_debug(&disp->engine.subdev,
					   "dcb %d %d/%d not supported\n",
					   i, dcbE.location, dcbE.type);
				continue;
			}
			nvkm_error(&disp->engine.subdev,
				   "failed to create output %d\n", i);
			nvkm_output_del(&outp);
			continue;
		}

		list_add_tail(&outp->head, &disp->outp);
		hpd = max(hpd, (u8)(dcbE.connector + 1));
	}

	/* create connector objects based on the outputs we support */
	list_for_each_entry_safe(outp, outt, &disp->outp, head) {
		/* bios 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->outp, 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->conn, 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_connector_new(disp, i, &connE, &outp->conn);
		if (ret) {
			nvkm_error(&disp->engine.subdev,
				   "failed to create output %d conn: %d\n",
				   outp->index, ret);
			nvkm_connector_del(&outp->conn);
			list_del(&outp->head);
			nvkm_output_del(&outp);
			continue;
		}

		list_add_tail(&outp->conn->head, &disp->conn);
	}

	ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd);
	if (ret)
		return ret;
+36 −78
Original line number Diff line number Diff line
@@ -33,13 +33,13 @@ static int
nvkm_connector_hpd(struct nvkm_notify *notify)
{
	struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
	struct nvkm_disp *disp = nvkm_disp(conn);
	struct nvkm_gpio *gpio = nvkm_gpio(conn);
	struct nvkm_disp *disp = conn->disp;
	struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
	const struct nvkm_gpio_ntfy_rep *line = notify->data;
	struct nvif_notify_conn_rep_v0 rep;
	int index = conn->index;

	DBG("HPD: %d\n", line->mask);
	CONN_DBG(conn, "HPD: %d", line->mask);

	if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
		rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
@@ -51,78 +51,58 @@ nvkm_connector_hpd(struct nvkm_notify *notify)
	return NVKM_NOTIFY_KEEP;
}

int
_nvkm_connector_fini(struct nvkm_object *object, bool suspend)
void
nvkm_connector_fini(struct nvkm_connector *conn)
{
	struct nvkm_connector *conn = (void *)object;
	nvkm_notify_put(&conn->hpd);
	return nvkm_object_fini(&conn->base, suspend);
}

int
_nvkm_connector_init(struct nvkm_object *object)
void
nvkm_connector_init(struct nvkm_connector *conn)
{
	struct nvkm_connector *conn = (void *)object;
	int ret = nvkm_object_init(&conn->base);
	if (ret == 0)
	nvkm_notify_get(&conn->hpd);
	return ret;
}

void
_nvkm_connector_dtor(struct nvkm_object *object)
nvkm_connector_del(struct nvkm_connector **pconn)
{
	struct nvkm_connector *conn = (void *)object;
	struct nvkm_connector *conn = *pconn;
	if (conn) {
		nvkm_notify_fini(&conn->hpd);
	nvkm_object_destroy(&conn->base);
		kfree(*pconn);
		*pconn = NULL;
	}
}

int
nvkm_connector_create_(struct nvkm_object *parent,
		       struct nvkm_object *engine,
		       struct nvkm_oclass *oclass,
		       struct nvbios_connE *info, int index,
		       int length, void **pobject)
static void
nvkm_connector_ctor(struct nvkm_disp *disp, int index,
		    struct nvbios_connE *info, struct nvkm_connector *conn)
{
	static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
	struct nvkm_disp *disp = nvkm_disp(parent);
	struct nvkm_gpio *gpio = nvkm_gpio(parent);
	struct nvkm_connector *conn;
	struct nvkm_output *outp;
	struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
	struct dcb_gpio_func func;
	int ret;

	list_for_each_entry(outp, &disp->outp, head) {
		if (outp->conn && outp->conn->index == index) {
			atomic_inc(&nv_object(outp->conn)->refcount);
			*pobject = outp->conn;
			return 1;
		}
	}

	ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
	conn = *pobject;
	if (ret)
		return ret;

	conn->info = *info;
	conn->disp = disp;
	conn->index = index;
	conn->info = *info;

	DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
	CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x",
		 info->type, info->location, info->hpd, info->dp,
		 info->di, info->sr, info->lcdid);

	if ((info->hpd = ffs(info->hpd))) {
		if (--info->hpd >= ARRAY_SIZE(hpd)) {
			ERR("hpd %02x unknown\n", info->hpd);
			return 0;
			CONN_ERR(conn, "hpd %02x unknown", info->hpd);
			return;
		}
		info->hpd = hpd[info->hpd];

		ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
		if (ret) {
			ERR("func %02x lookup failed, %d\n", info->hpd, ret);
			return 0;
			CONN_ERR(conn, "func %02x lookup failed, %d",
				 info->hpd, ret);
			return;
		}

		ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
@@ -134,41 +114,19 @@ nvkm_connector_create_(struct nvkm_object *parent,
				       sizeof(struct nvkm_gpio_ntfy_rep),
				       &conn->hpd);
		if (ret) {
			ERR("func %02x failed, %d\n", info->hpd, ret);
			CONN_ERR(conn, "func %02x failed, %d", info->hpd, ret);
		} else {
			DBG("func %02x (HPD)\n", info->hpd);
			CONN_DBG(conn, "func %02x (HPD)", info->hpd);
		}
	}

	return 0;
}

int
_nvkm_connector_ctor(struct nvkm_object *parent,
		     struct nvkm_object *engine,
		     struct nvkm_oclass *oclass, void *info, u32 index,
		     struct nvkm_object **pobject)
nvkm_connector_new(struct nvkm_disp *disp, int index,
		   struct nvbios_connE *info, struct nvkm_connector **pconn)
{
	struct nvkm_connector *conn;
	int ret;

	ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
	*pobject = nv_object(conn);
	if (ret)
		return ret;

	if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL)))
		return -ENOMEM;
	nvkm_connector_ctor(disp, index, info, *pconn);
	return 0;
}

struct nvkm_oclass *
nvkm_connector_oclass = &(struct nvkm_connector_impl) {
	.base = {
		.handle = 0,
		.ofuncs = &(struct nvkm_ofuncs) {
			.ctor = _nvkm_connector_ctor,
			.dtor = _nvkm_connector_dtor,
			.init = _nvkm_connector_init,
			.fini = _nvkm_connector_fini,
		},
	},
}.base;
+18 −43
Original line number Diff line number Diff line
#ifndef __NVKM_DISP_CONN_H__
#define __NVKM_DISP_CONN_H__
#include <core/object.h>
#include <core/notify.h>
#include <engine/disp.h>

#include <core/notify.h>
#include <subdev/bios.h>
#include <subdev/bios/conn.h>

struct nvkm_connector {
	struct nvkm_object base;
	struct list_head head;

	struct nvbios_connE info;
	struct nvkm_disp *disp;
	int index;
	struct nvbios_connE info;

	struct nvkm_notify hpd;
};

#define nvkm_connector_create(p,e,c,b,i,d)                                     \
	nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
#define nvkm_connector_destroy(d) ({                                           \
	struct nvkm_connector *disp = (d);                                     \
	_nvkm_connector_dtor(nv_object(disp));                                 \
})
#define nvkm_connector_init(d) ({                                              \
	struct nvkm_connector *disp = (d);                                     \
	_nvkm_connector_init(nv_object(disp));                                 \
})
#define nvkm_connector_fini(d,s) ({                                            \
	struct nvkm_connector *disp = (d);                                     \
	_nvkm_connector_fini(nv_object(disp), (s));                            \
})

int nvkm_connector_create_(struct nvkm_object *, struct nvkm_object *,
			   struct nvkm_oclass *, struct nvbios_connE *,
			   int, int, void **);

int  _nvkm_connector_ctor(struct nvkm_object *, struct nvkm_object *,
			  struct nvkm_oclass *, void *, u32,
			  struct nvkm_object **);
void _nvkm_connector_dtor(struct nvkm_object *);
int  _nvkm_connector_init(struct nvkm_object *);
int  _nvkm_connector_fini(struct nvkm_object *, bool);

struct nvkm_connector_impl {
	struct nvkm_oclass base;
	struct list_head head;
};

#ifndef MSG
#define MSG(l,f,a...) do {                                                     \
	struct nvkm_connector *_conn = (void *)conn;                           \
	nvkm_##l(&nvkm_disp(_conn)->engine.subdev, "%02x:%02x%02x: "f, _conn->index,                      \
		 _conn->info.location, _conn->info.type, ##a);                 \
int  nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *,
			struct nvkm_connector **);
void nvkm_connector_del(struct nvkm_connector **);
void nvkm_connector_init(struct nvkm_connector *);
void nvkm_connector_fini(struct nvkm_connector *);

#define CONN_MSG(c,l,f,a...) do {                                              \
	struct nvkm_connector *_conn = (c);                                    \
	nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n",     \
		 _conn->index, _conn->info.location, _conn->info.type, ##a);   \
} while(0)
#define DBG(f,a...) MSG(debug, f, ##a)
#define ERR(f,a...) MSG(error, f, ##a)
#endif
#define CONN_ERR(c,f,a...) CONN_MSG((c), error, f, ##a)
#define CONN_DBG(c,f,a...) CONN_MSG((c), debug, f, ##a)
#define CONN_TRACE(c,f,a...) CONN_MSG((c), trace, f, ##a)
#endif
Loading