diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/core.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/core507d.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/core827d.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/core907d.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/core917d.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/corec37d.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/corec57d.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/disp.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/disp.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/pior507d.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/sor507d.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/sor907d.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/sorc37d.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_encoder.h | 4 |
15 files changed, 118 insertions, 3 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/core.h b/drivers/gpu/drm/nouveau/dispnv50/core.h index ff94f3f6f264..99157dc94d23 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core.h +++ b/drivers/gpu/drm/nouveau/dispnv50/core.h @@ -2,6 +2,7 @@ #define __NV50_KMS_CORE_H__ #include "disp.h" #include "atom.h" +#include <nouveau_encoder.h> struct nv50_core { const struct nv50_core_func *func; @@ -15,6 +16,7 @@ void nv50_core_del(struct nv50_core **); struct nv50_core_func { void (*init)(struct nv50_core *); void (*ntfy_init)(struct nouveau_bo *, u32 offset); + int (*caps_init)(struct nouveau_drm *, struct nv50_disp *); int (*ntfy_wait_done)(struct nouveau_bo *, u32 offset, struct nvif_device *); void (*update)(struct nv50_core *, u32 *interlock, bool ntfy); @@ -27,6 +29,9 @@ struct nv50_core_func { const struct nv50_outp_func { void (*ctrl)(struct nv50_core *, int or, u32 ctrl, struct nv50_head_atom *); + /* XXX: Only used by SORs and PIORs for now */ + void (*get_caps)(struct nv50_disp *, + struct nouveau_encoder *, int or); } *dac, *pior, *sor; }; @@ -35,6 +40,7 @@ int core507d_new_(const struct nv50_core_func *, struct nouveau_drm *, s32, struct nv50_core **); void core507d_init(struct nv50_core *); void core507d_ntfy_init(struct nouveau_bo *, u32); +int core507d_caps_init(struct nouveau_drm *, struct nv50_disp *); int core507d_ntfy_wait_done(struct nouveau_bo *, u32, struct nvif_device *); void core507d_update(struct nv50_core *, u32 *, bool); @@ -51,6 +57,7 @@ extern const struct nv50_outp_func sor907d; int core917d_new(struct nouveau_drm *, s32, struct nv50_core **); int corec37d_new(struct nouveau_drm *, s32, struct nv50_core **); +int corec37d_caps_init(struct nouveau_drm *, struct nv50_disp *); int corec37d_ntfy_wait_done(struct nouveau_bo *, u32, struct nvif_device *); void corec37d_update(struct nv50_core *, u32 *, bool); void corec37d_wndw_owner(struct nv50_core *); diff --git a/drivers/gpu/drm/nouveau/dispnv50/core507d.c b/drivers/gpu/drm/nouveau/dispnv50/core507d.c index c5152c39c684..e341f572c269 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core507d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core507d.c @@ -62,6 +62,20 @@ core507d_ntfy_init(struct nouveau_bo *bo, u32 offset) nouveau_bo_wr32(bo, offset / 4, 0x00000000); } +int +core507d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp) +{ + u32 *push = evo_wait(&disp->core->chan, 2); + + if (push) { + evo_mthd(push, 0x008c, 1); + evo_data(push, 0x0); + evo_kick(push, &disp->core->chan); + } + + return 0; +} + void core507d_init(struct nv50_core *core) { @@ -77,6 +91,7 @@ static const struct nv50_core_func core507d = { .init = core507d_init, .ntfy_init = core507d_ntfy_init, + .caps_init = core507d_caps_init, .ntfy_wait_done = core507d_ntfy_wait_done, .update = core507d_update, .head = &head507d, diff --git a/drivers/gpu/drm/nouveau/dispnv50/core827d.c b/drivers/gpu/drm/nouveau/dispnv50/core827d.c index 6123a068f836..2e0c1c536afe 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core827d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core827d.c @@ -26,6 +26,7 @@ static const struct nv50_core_func core827d = { .init = core507d_init, .ntfy_init = core507d_ntfy_init, + .caps_init = core507d_caps_init, .ntfy_wait_done = core507d_ntfy_wait_done, .update = core507d_update, .head = &head827d, diff --git a/drivers/gpu/drm/nouveau/dispnv50/core907d.c b/drivers/gpu/drm/nouveau/dispnv50/core907d.c index ef822f813435..271629832629 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core907d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core907d.c @@ -26,6 +26,7 @@ static const struct nv50_core_func core907d = { .init = core507d_init, .ntfy_init = core507d_ntfy_init, + .caps_init = core507d_caps_init, .ntfy_wait_done = core507d_ntfy_wait_done, .update = core507d_update, .head = &head907d, diff --git a/drivers/gpu/drm/nouveau/dispnv50/core917d.c b/drivers/gpu/drm/nouveau/dispnv50/core917d.c index 392338df5bfd..5cc072d4c30f 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core917d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core917d.c @@ -26,6 +26,7 @@ static const struct nv50_core_func core917d = { .init = core507d_init, .ntfy_init = core507d_ntfy_init, + .caps_init = core507d_caps_init, .ntfy_wait_done = core507d_ntfy_wait_done, .update = core507d_update, .head = &head917d, diff --git a/drivers/gpu/drm/nouveau/dispnv50/corec37d.c b/drivers/gpu/drm/nouveau/dispnv50/corec37d.c index c03cb987856b..e0c8811fb8e4 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/corec37d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/corec37d.c @@ -22,6 +22,7 @@ #include "core.h" #include "head.h" +#include <nvif/class.h> #include <nouveau_bo.h> #include <nvif/timer.h> @@ -87,6 +88,30 @@ corec37d_ntfy_init(struct nouveau_bo *bo, u32 offset) nouveau_bo_wr32(bo, offset / 4 + 3, 0x00000000); } +int corec37d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp) +{ + int ret; + + ret = nvif_object_init(&disp->disp->object, 0, GV100_DISP_CAPS, + NULL, 0, &disp->caps); + if (ret) { + NV_ERROR(drm, + "Failed to init notifier caps region: %d\n", + ret); + return ret; + } + + ret = nvif_object_map(&disp->caps, NULL, 0); + if (ret) { + NV_ERROR(drm, + "Failed to map notifier caps region: %d\n", + ret); + return ret; + } + + return 0; +} + static void corec37d_init(struct nv50_core *core) { @@ -111,6 +136,7 @@ static const struct nv50_core_func corec37d = { .init = corec37d_init, .ntfy_init = corec37d_ntfy_init, + .caps_init = corec37d_caps_init, .ntfy_wait_done = corec37d_ntfy_wait_done, .update = corec37d_update, .wndw.owner = corec37d_wndw_owner, diff --git a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c index 147adcd60937..10ba9e9e4ae6 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c @@ -46,6 +46,7 @@ static const struct nv50_core_func corec57d = { .init = corec57d_init, .ntfy_init = corec37d_ntfy_init, + .caps_init = corec37d_caps_init, .ntfy_wait_done = corec37d_ntfy_wait_done, .update = corec37d_update, .wndw.owner = corec37d_wndw_owner, diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index d5488c85eb43..e6a93fdfc6a2 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1663,6 +1663,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device); struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; + struct nv50_disp *disp = nv50_disp(connector->dev); int type, ret; switch (dcbe->type) { @@ -1689,10 +1690,12 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) drm_connector_attach_encoder(connector, encoder); + disp->core->func->sor->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1); + if (dcbe->type == DCB_OUTPUT_DP) { - struct nv50_disp *disp = nv50_disp(encoder->dev); struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbe->i2c_index); + if (aux) { if (disp->disp->object.oclass < GF110_DISP) { /* HW has no support for address-only @@ -1805,7 +1808,9 @@ nv50_pior_func = { static int nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) { - struct nouveau_drm *drm = nouveau_drm(connector->dev); + struct drm_device *dev = connector->dev; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nv50_disp *disp = nv50_disp(dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device); struct nvkm_i2c_bus *bus = NULL; struct nvkm_i2c_aux *aux = NULL; @@ -1844,6 +1849,9 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) drm_encoder_helper_add(encoder, &nv50_pior_help); drm_connector_attach_encoder(connector, encoder); + + disp->core->func->pior->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1); + return 0; } @@ -2401,6 +2409,8 @@ nv50_display_destroy(struct drm_device *dev) nv50_audio_component_fini(nouveau_drm(dev)); + nvif_object_unmap(&disp->caps); + nvif_object_fini(&disp->caps); nv50_core_del(&disp->core); nouveau_bo_unmap(disp->sync); @@ -2462,6 +2472,11 @@ nv50_display_create(struct drm_device *dev) goto out; disp->core->func->init(disp->core); + if (disp->core->func->caps_init) { + ret = disp->core->func->caps_init(drm, disp); + if (ret) + goto out; + } /* Assign the correct format modifiers */ if (disp->disp->object.oclass >= TU102_DISP) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h b/drivers/gpu/drm/nouveau/dispnv50/disp.h index 1743c3a76216..696e70a6b98b 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h @@ -9,6 +9,7 @@ struct nv50_msto; struct nv50_disp { struct nvif_disp *disp; struct nv50_core *core; + struct nvif_object caps; #define NV50_DISP_SYNC(c, o) ((c) * 0x040 + (o)) #define NV50_DISP_CORE_NTFY NV50_DISP_SYNC(0 , 0x00) diff --git a/drivers/gpu/drm/nouveau/dispnv50/pior507d.c b/drivers/gpu/drm/nouveau/dispnv50/pior507d.c index d2bac6a341dc..45d8ce7d2c28 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/pior507d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/pior507d.c @@ -38,7 +38,15 @@ pior507d_ctrl(struct nv50_core *core, int or, u32 ctrl, } } +static void +pior507d_get_caps(struct nv50_disp *disp, struct nouveau_encoder *outp, + int or) +{ + outp->caps.dp_interlace = true; +} + const struct nv50_outp_func pior507d = { .ctrl = pior507d_ctrl, + .get_caps = pior507d_get_caps, }; diff --git a/drivers/gpu/drm/nouveau/dispnv50/sor507d.c b/drivers/gpu/drm/nouveau/dispnv50/sor507d.c index 5222fe6a9b21..9a59fa7da00d 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/sor507d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/sor507d.c @@ -38,7 +38,14 @@ sor507d_ctrl(struct nv50_core *core, int or, u32 ctrl, } } +static void +sor507d_get_caps(struct nv50_disp *core, struct nouveau_encoder *outp, int or) +{ + outp->caps.dp_interlace = true; +} + const struct nv50_outp_func sor507d = { .ctrl = sor507d_ctrl, + .get_caps = sor507d_get_caps, }; diff --git a/drivers/gpu/drm/nouveau/dispnv50/sor907d.c b/drivers/gpu/drm/nouveau/dispnv50/sor907d.c index b0314ec11fb3..9577ccf1c809 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/sor907d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/sor907d.c @@ -21,6 +21,7 @@ */ #include "core.h" +#include <nouveau_bo.h> #include <nvif/class.h> static void @@ -35,7 +36,17 @@ sor907d_ctrl(struct nv50_core *core, int or, u32 ctrl, } } +static void +sor907d_get_caps(struct nv50_disp *disp, struct nouveau_encoder *outp, int or) +{ + const int off = or * 2; + u32 tmp = nouveau_bo_rd32(disp->sync, 0x000014 + off); + + outp->caps.dp_interlace = !!(tmp & 0x04000000); +} + const struct nv50_outp_func sor907d = { .ctrl = sor907d_ctrl, + .get_caps = sor907d_get_caps, }; diff --git a/drivers/gpu/drm/nouveau/dispnv50/sorc37d.c b/drivers/gpu/drm/nouveau/dispnv50/sorc37d.c index dff059241c5d..c86ca955fdcd 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/sorc37d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/sorc37d.c @@ -33,7 +33,16 @@ sorc37d_ctrl(struct nv50_core *core, int or, u32 ctrl, } } +static void +sorc37d_get_caps(struct nv50_disp *disp, struct nouveau_encoder *outp, int or) +{ + u32 tmp = nvif_rd32(&disp->caps, 0x000144 + (or * 8)); + + outp->caps.dp_interlace = !!(tmp & 0x04000000); +} + const struct nv50_outp_func sorc37d = { .ctrl = sorc37d_ctrl, + .get_caps = sorc37d_get_caps, }; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 9a9a7f5003d3..6dae00da5d7e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -509,7 +509,11 @@ nouveau_connector_set_encoder(struct drm_connector *connector, nv_connector->detected_encoder = nv_encoder; if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { - connector->interlace_allowed = true; + if (nv_encoder->dcb->type == DCB_OUTPUT_DP) + connector->interlace_allowed = + nv_encoder->caps.dp_interlace; + else + connector->interlace_allowed = true; connector->doublescan_allowed = true; } else if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS || @@ -1060,6 +1064,10 @@ nouveau_connector_mode_valid(struct drm_connector *connector, case DCB_OUTPUT_TV: return get_slave_funcs(encoder)->mode_valid(encoder, mode); case DCB_OUTPUT_DP: + if (mode->flags & DRM_MODE_FLAG_INTERLACE && + !nv_encoder->caps.dp_interlace) + return MODE_NO_INTERLACE; + max_clock = nv_encoder->dp.link_nr; max_clock *= nv_encoder->dp.link_bw; clock = clock * (connector->display_info.bpc * 3) / 10; diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index 3517f920bf89..3217f587eceb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -66,6 +66,10 @@ struct nouveau_encoder { } dp; }; + struct { + bool dp_interlace : 1; + } caps; + void (*enc_save)(struct drm_encoder *encoder); void (*enc_restore)(struct drm_encoder *encoder); void (*update)(struct nouveau_encoder *, u8 head, |