mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 04:11:49 +00:00
drm/nouveau/disp/gm200-: enforce identity-mapped SOR assignment for LVDS/eDP panels
Fixes eDP backlight issues on more recent laptops. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
e04cfdc9b7
commit
53b0cc46f2
@ -275,6 +275,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
|
||||
struct nvkm_outp *outp, *outt, *pair;
|
||||
struct nvkm_conn *conn;
|
||||
struct nvkm_head *head;
|
||||
struct nvkm_ior *ior;
|
||||
struct nvbios_connE connE;
|
||||
struct dcb_output dcbE;
|
||||
u8 hpd = 0, ver, hdr;
|
||||
@ -399,6 +400,19 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enforce identity-mapped SOR assignment for panels, which have
|
||||
* certain bits (ie. backlight controls) wired to a specific SOR.
|
||||
*/
|
||||
list_for_each_entry(outp, &disp->outp, head) {
|
||||
if (outp->conn->info.type == DCB_CONNECTOR_LVDS ||
|
||||
outp->conn->info.type == DCB_CONNECTOR_eDP) {
|
||||
ior = nvkm_ior_find(disp, SOR, ffs(outp->info.or) - 1);
|
||||
if (!WARN_ON(!ior))
|
||||
ior->identity = true;
|
||||
outp->identity = true;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
list_for_each_entry(head, &disp->head, head)
|
||||
i = max(i, head->id + 1);
|
||||
|
@ -16,6 +16,7 @@ struct nvkm_ior {
|
||||
char name[8];
|
||||
|
||||
struct list_head head;
|
||||
bool identity;
|
||||
|
||||
struct nvkm_ior_state {
|
||||
struct nvkm_outp *outp;
|
||||
|
@ -129,17 +129,26 @@ nvkm_outp_acquire(struct nvkm_outp *outp, u8 user)
|
||||
if (proto == UNKNOWN)
|
||||
return -ENOSYS;
|
||||
|
||||
/* Deal with panels requiring identity-mapped SOR assignment. */
|
||||
if (outp->identity) {
|
||||
ior = nvkm_ior_find(outp->disp, SOR, ffs(outp->info.or) - 1);
|
||||
if (WARN_ON(!ior))
|
||||
return -ENOSPC;
|
||||
return nvkm_outp_acquire_ior(outp, user, ior);
|
||||
}
|
||||
|
||||
/* First preference is to reuse the OR that is currently armed
|
||||
* on HW, if any, in order to prevent unnecessary switching.
|
||||
*/
|
||||
list_for_each_entry(ior, &outp->disp->ior, head) {
|
||||
if (!ior->asy.outp && ior->arm.outp == outp)
|
||||
if (!ior->identity && !ior->asy.outp && ior->arm.outp == outp)
|
||||
return nvkm_outp_acquire_ior(outp, user, ior);
|
||||
}
|
||||
|
||||
/* Failing that, a completely unused OR is the next best thing. */
|
||||
list_for_each_entry(ior, &outp->disp->ior, head) {
|
||||
if (!ior->asy.outp && ior->type == type && !ior->arm.outp &&
|
||||
if (!ior->identity &&
|
||||
!ior->asy.outp && ior->type == type && !ior->arm.outp &&
|
||||
(ior->func->route.set || ior->id == __ffs(outp->info.or)))
|
||||
return nvkm_outp_acquire_ior(outp, user, ior);
|
||||
}
|
||||
@ -148,7 +157,7 @@ nvkm_outp_acquire(struct nvkm_outp *outp, u8 user)
|
||||
* but will be released during the next modeset.
|
||||
*/
|
||||
list_for_each_entry(ior, &outp->disp->ior, head) {
|
||||
if (!ior->asy.outp && ior->type == type &&
|
||||
if (!ior->identity && !ior->asy.outp && ior->type == type &&
|
||||
(ior->func->route.set || ior->id == __ffs(outp->info.or)))
|
||||
return nvkm_outp_acquire_ior(outp, user, ior);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ struct nvkm_outp {
|
||||
|
||||
struct list_head head;
|
||||
struct nvkm_conn *conn;
|
||||
bool identity;
|
||||
|
||||
/* Assembly state. */
|
||||
#define NVKM_OUTP_PRIV 1
|
||||
|
Loading…
Reference in New Issue
Block a user