diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv50')
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/atom.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/core.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/curs.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/disp.c | 145 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/head.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/wimm.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/wndw.c | 2 |
7 files changed, 105 insertions, 55 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h index a194990d2b0d..b5fae5ab3fa8 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/atom.h +++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h @@ -116,6 +116,12 @@ struct nv50_head_atom { u8 depth:4; } or; + /* Currently only used for MST */ + struct { + int pbn; + u8 tu:6; + } dp; + union nv50_head_atom_mask { struct { bool olut:1; diff --git a/drivers/gpu/drm/nouveau/dispnv50/core.c b/drivers/gpu/drm/nouveau/dispnv50/core.c index c25e0ebe3c92..27ea3f34706d 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core.c @@ -42,7 +42,7 @@ nv50_core_new(struct nouveau_drm *drm, struct nv50_core **pcore) int version; int (*new)(struct nouveau_drm *, s32, struct nv50_core **); } cores[] = { - { TU104_DISP_CORE_CHANNEL_DMA, 0, corec57d_new }, + { TU102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new }, { GV100_DISP_CORE_CHANNEL_DMA, 0, corec37d_new }, { GP102_DISP_CORE_CHANNEL_DMA, 0, core917d_new }, { GP100_DISP_CORE_CHANNEL_DMA, 0, core917d_new }, diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs.c b/drivers/gpu/drm/nouveau/dispnv50/curs.c index cb6e4d2b1b45..121c24a18f11 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/curs.c +++ b/drivers/gpu/drm/nouveau/dispnv50/curs.c @@ -31,7 +31,7 @@ nv50_curs_new(struct nouveau_drm *drm, int head, struct nv50_wndw **pwndw) int version; int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **); } curses[] = { - { TU104_DISP_CURSOR, 0, cursc37a_new }, + { TU102_DISP_CURSOR, 0, cursc37a_new }, { GV100_DISP_CURSOR, 0, cursc37a_new }, { GK104_DISP_CURSOR, 0, curs907a_new }, { GF110_DISP_CURSOR, 0, curs907a_new }, diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 134701a837c8..4b1650f51955 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -32,10 +32,10 @@ #include <drm/drmP.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_dp_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_plane_helper.h> +#include <drm/drm_probe_helper.h> #include <drm/drm_scdc_helper.h> #include <drm/drm_edid.h> @@ -561,7 +561,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) u32 max_ac_packet; union hdmi_infoframe avi_frame; union hdmi_infoframe vendor_frame; - bool scdc_supported, high_tmds_clock_ratio = false, scrambling = false; + bool high_tmds_clock_ratio = false, scrambling = false; u8 config; int ret; int size; @@ -571,10 +571,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) return; hdmi = &nv_connector->base.display_info.hdmi; - scdc_supported = hdmi->scdc.supported; - ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode, - scdc_supported); + ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, + &nv_connector->base, mode); if (!ret) { /* We have an AVI InfoFrame, populate it to the display */ args.pwr.avi_infoframe_length @@ -660,8 +659,6 @@ struct nv50_mstc { struct drm_display_mode *native; struct edid *edid; - - int pbn; }; struct nv50_msto { @@ -680,6 +677,8 @@ nv50_msto_payload(struct nv50_msto *msto) struct nv50_mstm *mstm = mstc->mstm; int vcpi = mstc->port->vcpi.vcpi, i; + WARN_ON(!mutex_is_locked(&mstm->mgr.payload_lock)); + NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi); for (i = 0; i < mstm->mgr.max_payloads; i++) { struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; @@ -704,14 +703,16 @@ nv50_msto_cleanup(struct nv50_msto *msto) struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; + if (!msto->disabled) + return; + NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); - if (mstc->port && mstc->port->vcpi.vcpi > 0 && !nv50_msto_payload(msto)) - drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); - if (msto->disabled) { - msto->mstc = NULL; - msto->head = NULL; - msto->disabled = false; - } + + drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); + + msto->mstc = NULL; + msto->head = NULL; + msto->disabled = false; } static void @@ -731,8 +732,10 @@ nv50_msto_prepare(struct nv50_msto *msto) (0x0100 << msto->head->base.index), }; + mutex_lock(&mstm->mgr.payload_lock); + NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); - if (mstc->port && mstc->port->vcpi.vcpi > 0) { + if (mstc->port->vcpi.vcpi > 0) { struct drm_dp_payload *payload = nv50_msto_payload(msto); if (payload) { args.vcpi.start_slot = payload->start_slot; @@ -746,7 +749,9 @@ nv50_msto_prepare(struct nv50_msto *msto) msto->encoder.name, msto->head->base.base.name, args.vcpi.start_slot, args.vcpi.num_slots, args.vcpi.pbn, args.vcpi.aligned_pbn); + nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args)); + mutex_unlock(&mstm->mgr.payload_lock); } static int @@ -754,16 +759,31 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct nv50_mstc *mstc = nv50_mstc(conn_state->connector); + struct drm_atomic_state *state = crtc_state->state; + struct drm_connector *connector = conn_state->connector; + struct nv50_mstc *mstc = nv50_mstc(connector); struct nv50_mstm *mstm = mstc->mstm; - int bpp = conn_state->connector->display_info.bpc * 3; + struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); int slots; - mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, bpp); + /* When restoring duplicated states, we need to make sure that the + * bw remains the same and avoid recalculating it, as the connector's + * bpc may have changed after the state was duplicated + */ + if (!state->duplicated) + asyh->dp.pbn = + drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, + connector->display_info.bpc * 3); + + if (drm_atomic_crtc_needs_modeset(crtc_state)) { + slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, + mstc->port, + asyh->dp.pbn); + if (slots < 0) + return slots; - slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); - if (slots < 0) - return slots; + asyh->dp.tu = slots; + } return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, mstc->native); @@ -773,13 +793,13 @@ static void nv50_msto_enable(struct drm_encoder *encoder) { struct nv50_head *head = nv50_head(encoder->crtc); + struct nv50_head_atom *armh = nv50_head_atom(head->base.base.state); struct nv50_msto *msto = nv50_msto(encoder); struct nv50_mstc *mstc = NULL; struct nv50_mstm *mstm = NULL; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; u8 proto, depth; - int slots; bool r; drm_connector_list_iter_begin(encoder->dev, &conn_iter); @@ -795,9 +815,10 @@ nv50_msto_enable(struct drm_encoder *encoder) if (WARN_ON(!mstc)) return; - slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); - r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots); - WARN_ON(!r); + r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, armh->dp.pbn, + armh->dp.tu); + if (!r) + DRM_DEBUG_KMS("Failed to allocate VCPI\n"); if (!mstm->links++) nv50_outp_acquire(mstm->outp); @@ -814,8 +835,7 @@ nv50_msto_enable(struct drm_encoder *encoder) default: depth = 0x6; break; } - mstm->outp->update(mstm->outp, head->base.index, - nv50_head_atom(head->base.base.state), proto, depth); + mstm->outp->update(mstm->outp, head->base.index, armh, proto, depth); msto->head = head; msto->mstc = mstc; @@ -829,8 +849,7 @@ nv50_msto_disable(struct drm_encoder *encoder) struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; - if (mstc->port) - drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); + drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); mstm->modified = true; @@ -927,12 +946,43 @@ nv50_mstc_get_modes(struct drm_connector *connector) return ret; } +static int +nv50_mstc_atomic_check(struct drm_connector *connector, + struct drm_connector_state *new_conn_state) +{ + struct drm_atomic_state *state = new_conn_state->state; + struct nv50_mstc *mstc = nv50_mstc(connector); + struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr; + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_crtc_state *crtc_state; + struct drm_crtc *new_crtc = new_conn_state->crtc; + + if (!old_conn_state->crtc) + return 0; + + /* We only want to free VCPI if this state disables the CRTC on this + * connector + */ + if (new_crtc) { + crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); + + if (!crtc_state || + !drm_atomic_crtc_needs_modeset(crtc_state) || + crtc_state->enable) + return 0; + } + + return drm_dp_atomic_release_vcpi_slots(state, mgr, mstc->port); +} + static const struct drm_connector_helper_funcs nv50_mstc_help = { .get_modes = nv50_mstc_get_modes, .mode_valid = nv50_mstc_mode_valid, .best_encoder = nv50_mstc_best_encoder, .atomic_best_encoder = nv50_mstc_atomic_best_encoder, + .atomic_check = nv50_mstc_atomic_check, }; static enum drm_connector_status @@ -942,7 +992,7 @@ nv50_mstc_detect(struct drm_connector *connector, bool force) enum drm_connector_status conn_status; int ret; - if (!mstc->port) + if (drm_connector_is_unregistered(connector)) return connector_status_disconnected; ret = pm_runtime_get_sync(connector->dev->dev); @@ -961,7 +1011,10 @@ static void nv50_mstc_destroy(struct drm_connector *connector) { struct nv50_mstc *mstc = nv50_mstc(connector); + drm_connector_cleanup(&mstc->connector); + drm_dp_mst_put_port_malloc(mstc->port); + kfree(mstc); } @@ -1009,6 +1062,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); drm_connector_set_path_property(&mstc->connector, path); + drm_dp_mst_get_port_malloc(port); return 0; } @@ -1063,13 +1117,6 @@ nv50_mstm_prepare(struct nv50_mstm *mstm) } static void -nv50_mstm_hotplug(struct drm_dp_mst_topology_mgr *mgr) -{ - struct nv50_mstm *mstm = nv50_mstm(mgr); - drm_kms_helper_hotplug_event(mstm->outp->base.base.dev); -} - -static void nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_connector *connector) { @@ -1080,10 +1127,6 @@ nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); - drm_modeset_lock(&drm->dev->mode_config.connection_mutex, NULL); - mstc->port = NULL; - drm_modeset_unlock(&drm->dev->mode_config.connection_mutex); - drm_connector_put(&mstc->connector); } @@ -1106,11 +1149,8 @@ nv50_mstm_add_connector(struct drm_dp_mst_topology_mgr *mgr, int ret; ret = nv50_mstc_new(mstm, port, path, &mstc); - if (ret) { - if (mstc) - mstc->connector.funcs->destroy(&mstc->connector); + if (ret) return NULL; - } return &mstc->connector; } @@ -1120,7 +1160,6 @@ nv50_mstm = { .add_connector = nv50_mstm_add_connector, .register_connector = nv50_mstm_register_connector, .destroy_connector = nv50_mstm_destroy_connector, - .hotplug = nv50_mstm_hotplug, }; void @@ -2125,6 +2164,10 @@ nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) return ret; } + ret = drm_dp_mst_atomic_check(state); + if (ret) + return ret; + return 0; } @@ -2178,8 +2221,8 @@ nv50_disp_func = { * Init *****************************************************************************/ -void -nv50_display_fini(struct drm_device *dev) +static void +nv50_display_fini(struct drm_device *dev, bool suspend) { struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; @@ -2200,8 +2243,8 @@ nv50_display_fini(struct drm_device *dev) } } -int -nv50_display_init(struct drm_device *dev) +static int +nv50_display_init(struct drm_device *dev, bool resume, bool runtime) { struct nv50_core *core = nv50_disp(dev)->core; struct drm_encoder *encoder; @@ -2227,7 +2270,7 @@ nv50_display_init(struct drm_device *dev) return 0; } -void +static void nv50_display_destroy(struct drm_device *dev) { struct nv50_disp *disp = nv50_disp(dev); diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index ac97ebce5b35..2e7a0c347ddb 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -413,6 +413,7 @@ nv50_head_atomic_duplicate_state(struct drm_crtc *crtc) asyh->ovly = armh->ovly; asyh->dither = armh->dither; asyh->procamp = armh->procamp; + asyh->dp = armh->dp; asyh->clr.mask = 0; asyh->set.mask = 0; return &asyh->state; diff --git a/drivers/gpu/drm/nouveau/dispnv50/wimm.c b/drivers/gpu/drm/nouveau/dispnv50/wimm.c index bc9eeaf212ae..a1ac153d5e98 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wimm.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wimm.c @@ -31,7 +31,7 @@ nv50_wimm_init(struct nouveau_drm *drm, struct nv50_wndw *wndw) int version; int (*init)(struct nouveau_drm *, s32, struct nv50_wndw *); } wimms[] = { - { TU104_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init }, + { TU102_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init }, { GV100_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init }, {} }; diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index ba9eea2ff16b..b95181027b31 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -626,7 +626,7 @@ nv50_wndw_new(struct nouveau_drm *drm, enum drm_plane_type type, int index, int (*new)(struct nouveau_drm *, enum drm_plane_type, int, s32, struct nv50_wndw **); } wndws[] = { - { TU104_DISP_WINDOW_CHANNEL_DMA, 0, wndwc57e_new }, + { TU102_DISP_WINDOW_CHANNEL_DMA, 0, wndwc57e_new }, { GV100_DISP_WINDOW_CHANNEL_DMA, 0, wndwc37e_new }, {} }; |