Merge branch 'linux-5.5' of git://github.com/skeggsb/linux into drm-fixes
Bunch of random nouveau fixes. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Ben Skeggs <skeggsb@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/ <CACAvsv56Am90okV334eXgxDuK228sb9UJxMiOYjNAMShvvv4cg@mail.gmail.com
This commit is contained in:
commit
cdf1d28ced
|
@ -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,
|
||||||
* 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,
|
||||||
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,
|
||||||
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;
|
|
||||||
|
|
||||||
asyh->dp.tu = slots;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
|
slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port,
|
||||||
mstc->native);
|
asyh->dp.pbn);
|
||||||
|
if (slots < 0)
|
||||||
|
return slots;
|
||||||
|
|
||||||
|
asyh->dp.tu = slots;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8
|
||||||
|
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
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
|
||||||
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
|
||||||
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 @@
|
||||||
|
|
||||||
#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;
|
||||||
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 {
|
||||||
#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;
|
||||||
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 *
|
||||||
|
|
Loading…
Reference in New Issue