Commit cdf1d28c authored by Dave Airlie's avatar Dave Airlie

Merge branch 'linux-5.5' of git://github.com/skeggsb/linux into drm-fixes

Bunch of random nouveau fixes.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
From: Ben Skeggs <skeggsb@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/ <CACAvsv56Am90okV334eXgxDuK228sb9UJxMiOYjNAMShvvv4cg@mail.gmail.com
parents 5ba04748 3d1890ef
...@@ -114,6 +114,7 @@ struct nv50_head_atom { ...@@ -114,6 +114,7 @@ struct nv50_head_atom {
u8 nhsync:1; u8 nhsync:1;
u8 nvsync:1; u8 nvsync:1;
u8 depth:4; u8 depth:4;
u8 bpc;
} or; } or;
/* Currently only used for MST */ /* Currently only used for MST */
......
...@@ -326,9 +326,9 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder, ...@@ -326,9 +326,9 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder,
* same size as the native one (e.g. different * same size as the native one (e.g. different
* refresh rate) * refresh rate)
*/ */
if (adjusted_mode->hdisplay == native_mode->hdisplay && if (mode->hdisplay == native_mode->hdisplay &&
adjusted_mode->vdisplay == native_mode->vdisplay && mode->vdisplay == native_mode->vdisplay &&
adjusted_mode->type & DRM_MODE_TYPE_DRIVER) mode->type & DRM_MODE_TYPE_DRIVER)
break; break;
mode = native_mode; mode = native_mode;
asyc->scaler.full = true; asyc->scaler.full = true;
...@@ -353,10 +353,20 @@ nv50_outp_atomic_check(struct drm_encoder *encoder, ...@@ -353,10 +353,20 @@ nv50_outp_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state, struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state) struct drm_connector_state *conn_state)
{ {
struct nouveau_connector *nv_connector = struct drm_connector *connector = conn_state->connector;
nouveau_connector(conn_state->connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
nv_connector->native_mode); int ret;
ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
nv_connector->native_mode);
if (ret)
return ret;
if (crtc_state->mode_changed || crtc_state->connectors_changed)
asyh->or.bpc = connector->display_info.bpc;
return 0;
} }
/****************************************************************************** /******************************************************************************
...@@ -770,32 +780,54 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, ...@@ -770,32 +780,54 @@ nv50_msto_atomic_check(struct drm_encoder *encoder,
struct nv50_mstm *mstm = mstc->mstm; struct nv50_mstm *mstm = mstc->mstm;
struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
int slots; int slots;
int ret;
ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
mstc->native);
if (ret)
return ret;
if (!crtc_state->mode_changed && !crtc_state->connectors_changed)
return 0;
/*
* 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) {
const int clock = crtc_state->adjusted_mode.clock;
if (crtc_state->mode_changed || crtc_state->connectors_changed) {
/* /*
* When restoring duplicated states, we need to make sure that * XXX: Since we don't use HDR in userspace quite yet, limit
* the bw remains the same and avoid recalculating it, as the * the bpc to 8 to save bandwidth on the topology. In the
* connector's bpc may have changed after the state was * future, we'll want to properly fix this by dynamically
* duplicated * selecting the highest possible bpc that would fit in the
* topology
*/ */
if (!state->duplicated) { asyh->or.bpc = min(connector->display_info.bpc, 8U);
const int bpp = connector->display_info.bpc * 3; asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3);
const int clock = crtc_state->adjusted_mode.clock; }
asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, bpp); slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port,
} asyh->dp.pbn);
if (slots < 0)
return slots;
slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, asyh->dp.tu = slots;
mstc->port,
asyh->dp.pbn);
if (slots < 0)
return slots;
asyh->dp.tu = slots; return 0;
} }
return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, static u8
mstc->native); nv50_dp_bpc_to_depth(unsigned int bpc)
{
switch (bpc) {
case 6: return 0x2;
case 8: return 0x5;
case 10: /* fall-through */
default: return 0x6;
}
} }
static void static void
...@@ -808,7 +840,7 @@ nv50_msto_enable(struct drm_encoder *encoder) ...@@ -808,7 +840,7 @@ nv50_msto_enable(struct drm_encoder *encoder)
struct nv50_mstm *mstm = NULL; struct nv50_mstm *mstm = NULL;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter; struct drm_connector_list_iter conn_iter;
u8 proto, depth; u8 proto;
bool r; bool r;
drm_connector_list_iter_begin(encoder->dev, &conn_iter); drm_connector_list_iter_begin(encoder->dev, &conn_iter);
...@@ -837,14 +869,8 @@ nv50_msto_enable(struct drm_encoder *encoder) ...@@ -837,14 +869,8 @@ nv50_msto_enable(struct drm_encoder *encoder)
else else
proto = 0x9; proto = 0x9;
switch (mstc->connector.display_info.bpc) { mstm->outp->update(mstm->outp, head->base.index, armh, proto,
case 6: depth = 0x2; break; nv50_dp_bpc_to_depth(armh->or.bpc));
case 8: depth = 0x5; break;
case 10:
default: depth = 0x6; break;
}
mstm->outp->update(mstm->outp, head->base.index, armh, proto, depth);
msto->head = head; msto->head = head;
msto->mstc = mstc; msto->mstc = mstc;
...@@ -1498,20 +1524,14 @@ nv50_sor_enable(struct drm_encoder *encoder) ...@@ -1498,20 +1524,14 @@ nv50_sor_enable(struct drm_encoder *encoder)
lvds.lvds.script |= 0x0200; lvds.lvds.script |= 0x0200;
} }
if (nv_connector->base.display_info.bpc == 8) if (asyh->or.bpc == 8)
lvds.lvds.script |= 0x0200; lvds.lvds.script |= 0x0200;
} }
nvif_mthd(&disp->disp->object, 0, &lvds, sizeof(lvds)); nvif_mthd(&disp->disp->object, 0, &lvds, sizeof(lvds));
break; break;
case DCB_OUTPUT_DP: case DCB_OUTPUT_DP:
if (nv_connector->base.display_info.bpc == 6) depth = nv50_dp_bpc_to_depth(asyh->or.bpc);
depth = 0x2;
else
if (nv_connector->base.display_info.bpc == 8)
depth = 0x5;
else
depth = 0x6;
if (nv_encoder->link & 1) if (nv_encoder->link & 1)
proto = 0x8; proto = 0x8;
...@@ -1662,7 +1682,7 @@ nv50_pior_enable(struct drm_encoder *encoder) ...@@ -1662,7 +1682,7 @@ nv50_pior_enable(struct drm_encoder *encoder)
nv50_outp_acquire(nv_encoder); nv50_outp_acquire(nv_encoder);
nv_connector = nouveau_encoder_connector_get(nv_encoder); nv_connector = nouveau_encoder_connector_get(nv_encoder);
switch (nv_connector->base.display_info.bpc) { switch (asyh->or.bpc) {
case 10: asyh->or.depth = 0x6; break; case 10: asyh->or.depth = 0x6; break;
case 8: asyh->or.depth = 0x5; break; case 8: asyh->or.depth = 0x5; break;
case 6: asyh->or.depth = 0x2; break; case 6: asyh->or.depth = 0x2; break;
......
...@@ -81,18 +81,17 @@ nv50_head_atomic_check_dither(struct nv50_head_atom *armh, ...@@ -81,18 +81,17 @@ nv50_head_atomic_check_dither(struct nv50_head_atom *armh,
struct nv50_head_atom *asyh, struct nv50_head_atom *asyh,
struct nouveau_conn_atom *asyc) struct nouveau_conn_atom *asyc)
{ {
struct drm_connector *connector = asyc->state.connector;
u32 mode = 0x00; u32 mode = 0x00;
if (asyc->dither.mode == DITHERING_MODE_AUTO) { if (asyc->dither.mode == DITHERING_MODE_AUTO) {
if (asyh->base.depth > connector->display_info.bpc * 3) if (asyh->base.depth > asyh->or.bpc * 3)
mode = DITHERING_MODE_DYNAMIC2X2; mode = DITHERING_MODE_DYNAMIC2X2;
} else { } else {
mode = asyc->dither.mode; mode = asyc->dither.mode;
} }
if (asyc->dither.depth == DITHERING_DEPTH_AUTO) { if (asyc->dither.depth == DITHERING_DEPTH_AUTO) {
if (connector->display_info.bpc >= 8) if (asyh->or.bpc >= 8)
mode |= DITHERING_DEPTH_8BPC; mode |= DITHERING_DEPTH_8BPC;
} else { } else {
mode |= asyc->dither.depth; mode |= asyc->dither.depth;
......
...@@ -245,14 +245,22 @@ nouveau_conn_atomic_duplicate_state(struct drm_connector *connector) ...@@ -245,14 +245,22 @@ nouveau_conn_atomic_duplicate_state(struct drm_connector *connector)
void void
nouveau_conn_reset(struct drm_connector *connector) nouveau_conn_reset(struct drm_connector *connector)
{ {
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_conn_atom *asyc; struct nouveau_conn_atom *asyc;
if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL)))) if (drm_drv_uses_atomic_modeset(connector->dev)) {
return; if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL))))
return;
if (connector->state)
nouveau_conn_atomic_destroy_state(connector,
connector->state);
__drm_atomic_helper_connector_reset(connector, &asyc->state);
} else {
asyc = &nv_connector->properties_state;
}
if (connector->state)
nouveau_conn_atomic_destroy_state(connector, connector->state);
__drm_atomic_helper_connector_reset(connector, &asyc->state);
asyc->dither.mode = DITHERING_MODE_AUTO; asyc->dither.mode = DITHERING_MODE_AUTO;
asyc->dither.depth = DITHERING_DEPTH_AUTO; asyc->dither.depth = DITHERING_DEPTH_AUTO;
asyc->scaler.mode = DRM_MODE_SCALE_NONE; asyc->scaler.mode = DRM_MODE_SCALE_NONE;
...@@ -276,8 +284,14 @@ void ...@@ -276,8 +284,14 @@ void
nouveau_conn_attach_properties(struct drm_connector *connector) nouveau_conn_attach_properties(struct drm_connector *connector)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state);
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_conn_atom *armc;
if (drm_drv_uses_atomic_modeset(connector->dev))
armc = nouveau_conn_atom(connector->state);
else
armc = &nv_connector->properties_state;
/* Init DVI-I specific properties. */ /* Init DVI-I specific properties. */
if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) if (connector->connector_type == DRM_MODE_CONNECTOR_DVII)
...@@ -748,9 +762,9 @@ static int ...@@ -748,9 +762,9 @@ static int
nouveau_connector_set_property(struct drm_connector *connector, nouveau_connector_set_property(struct drm_connector *connector,
struct drm_property *property, uint64_t value) struct drm_property *property, uint64_t value)
{ {
struct nouveau_conn_atom *asyc = nouveau_conn_atom(connector->state);
struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct nouveau_conn_atom *asyc = &nv_connector->properties_state;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder); struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
int ret; int ret;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <nvif/notify.h> #include <nvif/notify.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_encoder.h> #include <drm/drm_encoder.h>
#include <drm/drm_dp_helper.h> #include <drm/drm_dp_helper.h>
...@@ -44,6 +45,60 @@ struct dcb_output; ...@@ -44,6 +45,60 @@ struct dcb_output;
struct nouveau_backlight; struct nouveau_backlight;
#endif #endif
#define nouveau_conn_atom(p) \
container_of((p), struct nouveau_conn_atom, state)
struct nouveau_conn_atom {
struct drm_connector_state state;
struct {
/* The enum values specifically defined here match nv50/gf119
* hw values, and the code relies on this.
*/
enum {
DITHERING_MODE_OFF = 0x00,
DITHERING_MODE_ON = 0x01,
DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON,
DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON,
DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON,
DITHERING_MODE_AUTO
} mode;
enum {
DITHERING_DEPTH_6BPC = 0x00,
DITHERING_DEPTH_8BPC = 0x02,
DITHERING_DEPTH_AUTO
} depth;
} dither;
struct {
int mode; /* DRM_MODE_SCALE_* */
struct {
enum {
UNDERSCAN_OFF,
UNDERSCAN_ON,
UNDERSCAN_AUTO,
} mode;
u32 hborder;
u32 vborder;
} underscan;
bool full;
} scaler;
struct {
int color_vibrance;
int vibrant_hue;
} procamp;
union {
struct {
bool dither:1;
bool scaler:1;
bool procamp:1;
};
u8 mask;
} set;
};
struct nouveau_connector { struct nouveau_connector {
struct drm_connector base; struct drm_connector base;
enum dcb_connector_type type; enum dcb_connector_type type;
...@@ -63,6 +118,12 @@ struct nouveau_connector { ...@@ -63,6 +118,12 @@ struct nouveau_connector {
#ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
struct nouveau_backlight *backlight; struct nouveau_backlight *backlight;
#endif #endif
/*
* Our connector property code expects a nouveau_conn_atom struct
* even on pre-nv50 where we do not support atomic. This embedded
* version gets used in the non atomic modeset case.
*/
struct nouveau_conn_atom properties_state;
}; };
static inline struct nouveau_connector *nouveau_connector( static inline struct nouveau_connector *nouveau_connector(
...@@ -121,61 +182,6 @@ extern int nouveau_ignorelid; ...@@ -121,61 +182,6 @@ extern int nouveau_ignorelid;
extern int nouveau_duallink; extern int nouveau_duallink;
extern int nouveau_hdmimhz; extern int nouveau_hdmimhz;
#include <drm/drm_crtc.h>
#define nouveau_conn_atom(p) \
container_of((p), struct nouveau_conn_atom, state)
struct nouveau_conn_atom {
struct drm_connector_state state;
struct {
/* The enum values specifically defined here match nv50/gf119
* hw values, and the code relies on this.
*/
enum {
DITHERING_MODE_OFF = 0x00,
DITHERING_MODE_ON = 0x01,
DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON,
DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON,
DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON,
DITHERING_MODE_AUTO
} mode;
enum {
DITHERING_DEPTH_6BPC = 0x00,
DITHERING_DEPTH_8BPC = 0x02,
DITHERING_DEPTH_AUTO
} depth;
} dither;
struct {
int mode; /* DRM_MODE_SCALE_* */
struct {
enum {
UNDERSCAN_OFF,
UNDERSCAN_ON,
UNDERSCAN_AUTO,
} mode;
u32 hborder;
u32 vborder;
} underscan;
bool full;
} scaler;
struct {
int color_vibrance;
int vibrant_hue;
} procamp;
union {
struct {
bool dither:1;
bool scaler:1;
bool procamp:1;
};
u8 mask;
} set;
};
void nouveau_conn_attach_properties(struct drm_connector *); void nouveau_conn_attach_properties(struct drm_connector *);
void nouveau_conn_reset(struct drm_connector *); void nouveau_conn_reset(struct drm_connector *);
struct drm_connector_state * struct drm_connector_state *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment