mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-02-01 07:42:18 +00:00
LXQT for Sinclair progressive mode line support
This commit is contained in:
parent
c26fcb19b5
commit
4fc17d7ce7
@ -2140,10 +2140,6 @@ static void __execlists_unhold(struct i915_request *rq)
|
||||
if (p->flags & I915_DEPENDENCY_WEAK)
|
||||
continue;
|
||||
|
||||
/* Propagate any change in error status */
|
||||
if (rq->fence.error)
|
||||
i915_request_set_error_once(w, rq->fence.error);
|
||||
|
||||
if (w->engine != rq->engine)
|
||||
continue;
|
||||
|
||||
|
@ -294,6 +294,23 @@ struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define drm_for_each_connector_mask(connector, dev, connector_mask) \
|
||||
list_for_each_entry((connector), &(dev)->mode_config.connector_list, head) \
|
||||
for_each_if ((connector_mask) & drm_connector_mask(connector))
|
||||
|
||||
struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
|
||||
WARN_ON(hweight32(state->connector_mask) > 1);
|
||||
|
||||
drm_for_each_connector_mask(connector, crtc->dev, state->connector_mask)
|
||||
return connector;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
@ -393,6 +410,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
CRTC_WRITE(PV_V_CONTROL,
|
||||
PV_VCONTROL_CONTINUOUS |
|
||||
(is_dsi ? PV_VCONTROL_DSI : 0));
|
||||
CRTC_WRITE(PV_VSYNCD_EVEN, 0);
|
||||
}
|
||||
|
||||
CRTC_WRITE(PV_VERTA,
|
||||
@ -1162,20 +1180,43 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
|
||||
|
||||
if (!vc4->hvs->hvs5) {
|
||||
drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
|
||||
} else {
|
||||
/* This is a lie for hvs5 which uses a 16 point PWL, but it
|
||||
* allows for something smarter than just 16 linearly spaced
|
||||
* segments. Conversion is done in vc5_hvs_update_gamma_lut.
|
||||
*/
|
||||
drm_mode_crtc_set_gamma_size(crtc, 256);
|
||||
}
|
||||
|
||||
drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
|
||||
|
||||
if (!vc4->hvs->hvs5) {
|
||||
/* We support CTM, but only for one CRTC at a time. It's therefore
|
||||
* implemented as private driver state in vc4_kms, not here.
|
||||
*/
|
||||
drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size);
|
||||
}
|
||||
|
||||
/* Initialize the VC4 gamma LUTs */
|
||||
for (i = 0; i < crtc->gamma_size; i++) {
|
||||
vc4_crtc->lut_r[i] = i;
|
||||
vc4_crtc->lut_g[i] = i;
|
||||
vc4_crtc->lut_b[i] = i;
|
||||
}
|
||||
} else {
|
||||
/* Initialize the VC5 gamma PWL entries. Assume 12-bit pipeline,
|
||||
* evenly spread over full range.
|
||||
*/
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) {
|
||||
vc4_crtc->pwl_r[i] =
|
||||
VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8);
|
||||
vc4_crtc->pwl_g[i] =
|
||||
VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8);
|
||||
vc4_crtc->pwl_b[i] =
|
||||
VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8);
|
||||
vc4_crtc->pwl_a[i] =
|
||||
VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <drm/drm_modeset_lock.h>
|
||||
|
||||
#include "uapi/drm/vc4_drm.h"
|
||||
#include "vc4_regs.h"
|
||||
|
||||
struct drm_device;
|
||||
struct drm_gem_object;
|
||||
@ -325,7 +326,6 @@ struct vc4_hvs {
|
||||
u32 __iomem *dlist;
|
||||
|
||||
struct clk *core_clk;
|
||||
struct clk_request *core_req;
|
||||
|
||||
/* Memory manager for CRTCs to allocate space in the display
|
||||
* list. Units are dwords.
|
||||
@ -481,6 +481,17 @@ struct vc4_pv_data {
|
||||
|
||||
};
|
||||
|
||||
struct vc5_gamma_entry {
|
||||
u32 x_c_terms;
|
||||
u32 grad_term;
|
||||
};
|
||||
|
||||
#define VC5_HVS_SET_GAMMA_ENTRY(x, c, g) (struct vc5_gamma_entry){ \
|
||||
.x_c_terms = VC4_SET_FIELD((x), SCALER5_DSPGAMMA_OFF_X) | \
|
||||
VC4_SET_FIELD((c), SCALER5_DSPGAMMA_OFF_C), \
|
||||
.grad_term = (g) \
|
||||
}
|
||||
|
||||
struct vc4_crtc {
|
||||
struct drm_crtc base;
|
||||
struct platform_device *pdev;
|
||||
@ -490,9 +501,19 @@ struct vc4_crtc {
|
||||
/* Timestamp at start of vblank irq - unaffected by lock delays. */
|
||||
ktime_t t_vblank;
|
||||
|
||||
union {
|
||||
struct { /* VC4 gamma LUT */
|
||||
u8 lut_r[256];
|
||||
u8 lut_g[256];
|
||||
u8 lut_b[256];
|
||||
};
|
||||
struct { /* VC5 gamma PWL entries */
|
||||
struct vc5_gamma_entry pwl_r[SCALER5_DSPGAMMA_NUM_POINTS];
|
||||
struct vc5_gamma_entry pwl_g[SCALER5_DSPGAMMA_NUM_POINTS];
|
||||
struct vc5_gamma_entry pwl_b[SCALER5_DSPGAMMA_NUM_POINTS];
|
||||
struct vc5_gamma_entry pwl_a[SCALER5_DSPGAMMA_NUM_POINTS];
|
||||
};
|
||||
};
|
||||
|
||||
struct drm_pending_vblank_event *event;
|
||||
|
||||
@ -546,6 +567,9 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc)
|
||||
return container_of(data, struct vc4_pv_data, base);
|
||||
}
|
||||
|
||||
struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state);
|
||||
|
||||
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state);
|
||||
|
||||
|
@ -134,6 +134,84 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc5_hvs_debugfs_gamma(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
unsigned int i, chan;
|
||||
u32 dispstat, dispbkgndx;
|
||||
|
||||
for (chan = 0; chan < SCALER_CHANNELS_COUNT; chan++) {
|
||||
u32 x_c, grad;
|
||||
u32 offset = SCALER5_DSPGAMMA_START +
|
||||
chan * SCALER5_DSPGAMMA_CHAN_OFFSET;
|
||||
|
||||
dispstat = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)),
|
||||
SCALER_DISPSTATX_MODE);
|
||||
if (dispstat == SCALER_DISPSTATX_MODE_DISABLED ||
|
||||
dispstat == SCALER_DISPSTATX_MODE_EOF) {
|
||||
drm_printf(&p, "HVS channel %u: Channel disabled\n", chan);
|
||||
continue;
|
||||
}
|
||||
|
||||
dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan));
|
||||
if (!(dispbkgndx & SCALER_DISPBKGND_GAMMA)) {
|
||||
drm_printf(&p, "HVS channel %u: Gamma disabled\n", chan);
|
||||
continue;
|
||||
}
|
||||
|
||||
drm_printf(&p, "HVS channel %u:\n", chan);
|
||||
drm_printf(&p, " red:\n");
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) {
|
||||
x_c = HVS_READ(offset);
|
||||
grad = HVS_READ(offset + 4);
|
||||
drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n",
|
||||
x_c, grad,
|
||||
VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X),
|
||||
VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C),
|
||||
grad);
|
||||
}
|
||||
drm_printf(&p, " green:\n");
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) {
|
||||
x_c = HVS_READ(offset);
|
||||
grad = HVS_READ(offset + 4);
|
||||
drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n",
|
||||
x_c, grad,
|
||||
VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X),
|
||||
VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C),
|
||||
grad);
|
||||
}
|
||||
drm_printf(&p, " blue:\n");
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) {
|
||||
x_c = HVS_READ(offset);
|
||||
grad = HVS_READ(offset + 4);
|
||||
drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n",
|
||||
x_c, grad,
|
||||
VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X),
|
||||
VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C),
|
||||
grad);
|
||||
}
|
||||
|
||||
/* Alpha only valid on channel 2 */
|
||||
if (chan != 2)
|
||||
continue;
|
||||
|
||||
drm_printf(&p, " alpha:\n");
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) {
|
||||
x_c = HVS_READ(offset);
|
||||
grad = HVS_READ(offset + 4);
|
||||
drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n",
|
||||
x_c, grad,
|
||||
VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X),
|
||||
VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C),
|
||||
grad);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The filter kernel is composed of dwords each containing 3 9-bit
|
||||
* signed integers packed next to each other.
|
||||
*/
|
||||
@ -236,6 +314,80 @@ static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc)
|
||||
vc4_hvs_lut_load(crtc);
|
||||
}
|
||||
|
||||
static void vc5_hvs_write_gamma_entry(struct vc4_dev *vc4,
|
||||
u32 offset,
|
||||
struct vc5_gamma_entry *gamma)
|
||||
{
|
||||
HVS_WRITE(offset, gamma->x_c_terms);
|
||||
HVS_WRITE(offset + 4, gamma->grad_term);
|
||||
}
|
||||
|
||||
static void vc5_hvs_lut_load(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
u32 i;
|
||||
u32 offset = SCALER5_DSPGAMMA_START +
|
||||
vc4_state->assigned_channel * SCALER5_DSPGAMMA_CHAN_OFFSET;
|
||||
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8)
|
||||
vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_r[i]);
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8)
|
||||
vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_g[i]);
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8)
|
||||
vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_b[i]);
|
||||
|
||||
if (vc4_state->assigned_channel == 2) {
|
||||
/* Alpha only valid on channel 2 */
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8)
|
||||
vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_a[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void vc5_hvs_update_gamma_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
struct drm_color_lut *lut = crtc->state->gamma_lut->data;
|
||||
unsigned int step, i;
|
||||
u32 start, end;
|
||||
|
||||
#define VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl, chan) \
|
||||
start = drm_color_lut_extract(lut[i * step].chan, 12); \
|
||||
end = drm_color_lut_extract(lut[(i + 1) * step - 1].chan, 12); \
|
||||
\
|
||||
/* Negative gradients not permitted by the hardware, so \
|
||||
* flatten such points out. \
|
||||
*/ \
|
||||
if (end < start) \
|
||||
end = start; \
|
||||
\
|
||||
/* Assume 12bit pipeline. \
|
||||
* X evenly spread over full range (12 bit). \
|
||||
* C as U12.4 format. \
|
||||
* Gradient as U4.8 format. \
|
||||
*/ \
|
||||
vc4_crtc->pwl[i] = \
|
||||
VC5_HVS_SET_GAMMA_ENTRY(i << 8, start << 4, \
|
||||
((end - start) << 4) / (step - 1))
|
||||
|
||||
/* HVS5 has a 16 point piecewise linear function for each colour
|
||||
* channel (including alpha on channel 2) on each display channel.
|
||||
*
|
||||
* Currently take a crude subsample of the gamma LUT, but this could
|
||||
* be improved to implement curve fitting.
|
||||
*/
|
||||
step = crtc->gamma_size / SCALER5_DSPGAMMA_NUM_POINTS;
|
||||
for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) {
|
||||
VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_r, red);
|
||||
VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_g, green);
|
||||
VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_b, blue);
|
||||
}
|
||||
|
||||
vc5_hvs_lut_load(crtc);
|
||||
}
|
||||
|
||||
int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
@ -329,14 +481,16 @@ static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc,
|
||||
dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE;
|
||||
|
||||
HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx |
|
||||
SCALER_DISPBKGND_AUTOHS |
|
||||
((!vc4->hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) |
|
||||
SCALER_DISPBKGND_AUTOHS | SCALER_DISPBKGND_GAMMA |
|
||||
(interlace ? SCALER_DISPBKGND_INTERLACE : 0));
|
||||
|
||||
/* Reload the LUT, since the SRAMs would have been disabled if
|
||||
* all CRTCs had SCALER_DISPBKGND_GAMMA unset at once.
|
||||
*/
|
||||
if (!vc4->hvs->hvs5)
|
||||
vc4_hvs_lut_load(crtc);
|
||||
else
|
||||
vc5_hvs_lut_load(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -365,6 +519,36 @@ void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int chan)
|
||||
SCALER_DISPSTATX_EMPTY);
|
||||
}
|
||||
|
||||
static int vc4_hvs_gamma_check(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
struct drm_connector_state *conn_state;
|
||||
struct drm_connector *connector;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
if (!vc4->hvs->hvs5)
|
||||
return 0;
|
||||
|
||||
if (!crtc_state->color_mgmt_changed)
|
||||
return 0;
|
||||
|
||||
connector = vc4_get_crtc_connector(crtc, crtc_state);
|
||||
if (!connector)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
|
||||
return 0;
|
||||
|
||||
conn_state = drm_atomic_get_connector_state(state, connector);
|
||||
if (!conn_state)
|
||||
return -EINVAL;
|
||||
|
||||
crtc_state->mode_changed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
@ -395,7 +579,7 @@ int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return vc4_hvs_gamma_check(crtc, state);
|
||||
}
|
||||
|
||||
static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
@ -534,7 +718,10 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
|
||||
u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel));
|
||||
|
||||
if (crtc->state->gamma_lut) {
|
||||
if (!vc4->hvs->hvs5)
|
||||
vc4_hvs_update_gamma_lut(crtc);
|
||||
else
|
||||
vc5_hvs_update_gamma_lut(crtc);
|
||||
dispbkgndx |= SCALER_DISPBKGND_GAMMA;
|
||||
} else {
|
||||
/* Unsetting DISPBKGND_GAMMA skips the gamma lut step
|
||||
@ -730,6 +917,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
|
||||
NULL);
|
||||
vc4_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist,
|
||||
NULL);
|
||||
if (hvs->hvs5)
|
||||
vc4_debugfs_add_file(drm, "hvs_gamma", vc5_hvs_debugfs_gamma,
|
||||
NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv)
|
||||
struct vc4_hvs_state {
|
||||
struct drm_private_state base;
|
||||
unsigned long core_clock_rate;
|
||||
struct clk_request *core_req;
|
||||
|
||||
struct {
|
||||
unsigned in_use: 1;
|
||||
@ -343,20 +344,20 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
struct drm_device *dev = state->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_hvs *hvs = vc4->hvs;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
struct vc4_hvs_state *new_hvs_state;
|
||||
struct drm_crtc *crtc;
|
||||
struct vc4_hvs_state *old_hvs_state;
|
||||
struct clk_request *core_req;
|
||||
unsigned int channel;
|
||||
int i;
|
||||
|
||||
old_hvs_state = vc4_hvs_get_old_global_state(state);
|
||||
if (WARN_ON(!old_hvs_state))
|
||||
if (WARN_ON(IS_ERR(old_hvs_state)))
|
||||
return;
|
||||
|
||||
new_hvs_state = vc4_hvs_get_new_global_state(state);
|
||||
if (WARN_ON(!new_hvs_state))
|
||||
if (WARN_ON(IS_ERR(new_hvs_state)))
|
||||
return;
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||
@ -369,16 +370,10 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
|
||||
}
|
||||
|
||||
for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state =
|
||||
to_vc4_crtc_state(old_crtc_state);
|
||||
for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) {
|
||||
struct drm_crtc_commit *commit;
|
||||
unsigned int channel = vc4_crtc_state->assigned_channel;
|
||||
int ret;
|
||||
|
||||
if (channel == VC4_HVS_CHANNEL_DISABLED)
|
||||
continue;
|
||||
|
||||
if (!old_hvs_state->fifo_state[channel].in_use)
|
||||
continue;
|
||||
|
||||
@ -389,6 +384,9 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
ret = drm_crtc_commit_wait(commit);
|
||||
if (ret)
|
||||
drm_err(dev, "Timed out waiting for commit\n");
|
||||
|
||||
drm_crtc_commit_put(commit);
|
||||
old_hvs_state->fifo_state[channel].pending_commit = NULL;
|
||||
}
|
||||
|
||||
if (vc4->hvs && vc4->hvs->hvs5) {
|
||||
@ -408,7 +406,8 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
* And remove the previous one based on the HVS
|
||||
* requirements if any.
|
||||
*/
|
||||
clk_request_done(hvs->core_req);
|
||||
clk_request_done(old_hvs_state->core_req);
|
||||
old_hvs_state->core_req = NULL;
|
||||
}
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
@ -442,7 +441,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
* Request a clock rate based on the current HVS
|
||||
* requirements.
|
||||
*/
|
||||
hvs->core_req = clk_request_start(hvs->core_clk,
|
||||
new_hvs_state->core_req = clk_request_start(hvs->core_clk,
|
||||
new_hvs_state->core_clock_rate);
|
||||
|
||||
/* And drop the temporary request */
|
||||
@ -468,8 +467,8 @@ static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
|
||||
state->legacy_cursor_update = false;
|
||||
|
||||
hvs_state = vc4_hvs_get_new_global_state(state);
|
||||
if (!hvs_state)
|
||||
return -EINVAL;
|
||||
if (WARN_ON(IS_ERR(hvs_state)))
|
||||
return PTR_ERR(hvs_state);
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state =
|
||||
@ -717,12 +716,6 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
|
||||
for (i = 0; i < HVS_NUM_CHANNELS; i++) {
|
||||
state->fifo_state[i].in_use = old_state->fifo_state[i].in_use;
|
||||
state->fifo_state[i].fifo_load = old_state->fifo_state[i].fifo_load;
|
||||
|
||||
if (!old_state->fifo_state[i].pending_commit)
|
||||
continue;
|
||||
|
||||
state->fifo_state[i].pending_commit =
|
||||
drm_crtc_commit_get(old_state->fifo_state[i].pending_commit);
|
||||
}
|
||||
|
||||
state->core_clock_rate = old_state->core_clock_rate;
|
||||
@ -814,8 +807,8 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
|
||||
unsigned int i;
|
||||
|
||||
hvs_new_state = vc4_hvs_get_global_state(state);
|
||||
if (!hvs_new_state)
|
||||
return -EINVAL;
|
||||
if (IS_ERR(hvs_new_state))
|
||||
return PTR_ERR(hvs_new_state);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hvs_new_state->fifo_state); i++)
|
||||
if (!hvs_new_state->fifo_state[i].in_use)
|
||||
@ -907,8 +900,8 @@ vc4_core_clock_atomic_check(struct drm_atomic_state *state)
|
||||
load_state = to_vc4_load_tracker_state(priv_state);
|
||||
|
||||
hvs_new_state = vc4_hvs_get_global_state(state);
|
||||
if (!hvs_new_state)
|
||||
return -EINVAL;
|
||||
if (IS_ERR(hvs_new_state))
|
||||
return PTR_ERR(hvs_new_state);
|
||||
|
||||
for_each_oldnew_crtc_in_state(state, crtc,
|
||||
old_crtc_state,
|
||||
|
@ -491,6 +491,28 @@
|
||||
#define SCALER_DLIST_START 0x00002000
|
||||
#define SCALER_DLIST_SIZE 0x00004000
|
||||
|
||||
/* Gamma PWL for each channel. 16 points for each of 4 colour channels (alpha
|
||||
* only on channel 2). 8 bytes per entry, offsets first, then gradient:
|
||||
* Y = GRAD * X + C
|
||||
*
|
||||
* Values for X and C are left justified, and vary depending on the width of
|
||||
* the HVS channel:
|
||||
* 8-bit pipeline: X uses [31:24], C is U8.8 format, and GRAD is U4.8.
|
||||
* 12-bit pipeline: X uses [31:20], C is U12.4 format, and GRAD is U4.8.
|
||||
*
|
||||
* The 3 HVS channels start at 0x400 offsets (ie chan 1 starts at 0x2400, and
|
||||
* chan 2 at 0x2800).
|
||||
*/
|
||||
#define SCALER5_DSPGAMMA_NUM_POINTS 16
|
||||
#define SCALER5_DSPGAMMA_START 0x00002000
|
||||
#define SCALER5_DSPGAMMA_CHAN_OFFSET 0x400
|
||||
# define SCALER5_DSPGAMMA_OFF_X_MASK VC4_MASK(31, 20)
|
||||
# define SCALER5_DSPGAMMA_OFF_X_SHIFT 20
|
||||
# define SCALER5_DSPGAMMA_OFF_C_MASK VC4_MASK(15, 0)
|
||||
# define SCALER5_DSPGAMMA_OFF_C_SHIFT 0
|
||||
# define SCALER5_DSPGAMMA_GRAD_MASK VC4_MASK(11, 0)
|
||||
# define SCALER5_DSPGAMMA_GRAD_SHIFT 0
|
||||
|
||||
#define SCALER5_DLIST_START 0x00004000
|
||||
|
||||
# define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1)
|
||||
|
@ -245,7 +245,8 @@ enum vc4_vec_tv_mode_id {
|
||||
};
|
||||
|
||||
struct vc4_vec_tv_mode {
|
||||
const struct drm_display_mode *mode;
|
||||
const struct drm_display_mode *interlaced_mode;
|
||||
const struct drm_display_mode *progressive_mode;
|
||||
u32 config0;
|
||||
u32 config1;
|
||||
u32 custom_freq;
|
||||
@ -279,61 +280,81 @@ static const struct debugfs_reg32 vec_regs[] = {
|
||||
};
|
||||
|
||||
static const struct drm_display_mode drm_mode_480i = {
|
||||
DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
|
||||
480, 480 + 7, 480 + 7 + 6, 525, 0,
|
||||
DRM_MODE_FLAG_INTERLACE)
|
||||
};
|
||||
|
||||
static const struct drm_display_mode drm_mode_240p = {
|
||||
DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
|
||||
240, 240 + 3, 240 + 3 + 3, 262, 0, 0)
|
||||
};
|
||||
|
||||
static const struct drm_display_mode drm_mode_576i = {
|
||||
DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
|
||||
576, 576 + 4, 576 + 4 + 6, 625, 0,
|
||||
DRM_MODE_FLAG_INTERLACE)
|
||||
};
|
||||
|
||||
static const struct drm_display_mode drm_mode_288p = {
|
||||
DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
|
||||
288, 288 + 2, 288 + 2 + 3, 312, 0, 0)
|
||||
};
|
||||
|
||||
static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
|
||||
[VC4_VEC_TV_MODE_NTSC] = {
|
||||
.mode = &drm_mode_480i,
|
||||
.interlaced_mode = &drm_mode_480i,
|
||||
.progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_NTSC_J] = {
|
||||
.mode = &drm_mode_480i,
|
||||
.interlaced_mode = &drm_mode_480i,
|
||||
.progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_NTSC_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_NTSC_443] = {
|
||||
/* NTSC with PAL chroma frequency */
|
||||
.mode = &drm_mode_480i,
|
||||
.interlaced_mode = &drm_mode_480i,
|
||||
.progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_NTSC_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
|
||||
.custom_freq = 0x2a098acb,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL] = {
|
||||
.mode = &drm_mode_576i,
|
||||
.interlaced_mode = &drm_mode_576i,
|
||||
.progressive_mode = &drm_mode_288p,
|
||||
.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL_M] = {
|
||||
.mode = &drm_mode_480i,
|
||||
.interlaced_mode = &drm_mode_480i,
|
||||
.progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_PAL_M_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL_N] = {
|
||||
.mode = &drm_mode_576i,
|
||||
.interlaced_mode = &drm_mode_576i,
|
||||
.progressive_mode = &drm_mode_288p,
|
||||
.config0 = VEC_CONFIG0_PAL_N_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL60] = {
|
||||
/* PAL-M with chroma frequency of regular PAL */
|
||||
.mode = &drm_mode_480i,
|
||||
.interlaced_mode = &drm_mode_480i,
|
||||
.progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_PAL_M_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
|
||||
.custom_freq = 0x2a098acb,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_SECAM] = {
|
||||
.mode = &drm_mode_576i,
|
||||
.interlaced_mode = &drm_mode_576i,
|
||||
.progressive_mode = &drm_mode_288p,
|
||||
.config0 = VEC_CONFIG0_SECAM_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
.custom_freq = 0x29c71c72,
|
||||
@ -393,16 +414,32 @@ static void vc4_vec_connector_destroy(struct drm_connector *connector)
|
||||
static int vc4_vec_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_connector_state *state = connector->state;
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_display_mode *interlaced_mode, *progressive_mode;
|
||||
|
||||
mode = drm_mode_duplicate(connector->dev,
|
||||
vc4_vec_tv_modes[state->tv.mode].mode);
|
||||
if (!mode) {
|
||||
interlaced_mode =
|
||||
drm_mode_duplicate(connector->dev,
|
||||
vc4_vec_tv_modes[state->tv.mode].interlaced_mode);
|
||||
progressive_mode =
|
||||
drm_mode_duplicate(connector->dev,
|
||||
vc4_vec_tv_modes[state->tv.mode].progressive_mode);
|
||||
if (!interlaced_mode || !progressive_mode) {
|
||||
DRM_ERROR("Failed to create a new display mode\n");
|
||||
drm_mode_destroy(connector->dev, interlaced_mode);
|
||||
drm_mode_destroy(connector->dev, progressive_mode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
drm_mode_probed_add(connector, mode);
|
||||
if (connector->cmdline_mode.specified &&
|
||||
connector->cmdline_mode.refresh_specified &&
|
||||
!connector->cmdline_mode.interlace)
|
||||
/* progressive mode set at boot, let's make it preferred */
|
||||
progressive_mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
else
|
||||
/* otherwise, interlaced mode is preferred */
|
||||
interlaced_mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
drm_mode_probed_add(connector, interlaced_mode);
|
||||
drm_mode_probed_add(connector, progressive_mode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -423,17 +460,10 @@ static int vc4_vec_connector_atomic_check(struct drm_connector *conn,
|
||||
struct drm_connector_state *new_state =
|
||||
drm_atomic_get_new_connector_state(state, conn);
|
||||
|
||||
const struct vc4_vec_tv_mode *vec_mode =
|
||||
&vc4_vec_tv_modes[new_state->tv.mode];
|
||||
|
||||
if (new_state->crtc) {
|
||||
if (new_state->crtc && old_state->tv.mode != new_state->tv.mode) {
|
||||
struct drm_crtc_state *crtc_state =
|
||||
drm_atomic_get_new_crtc_state(state, new_state->crtc);
|
||||
|
||||
if (!drm_mode_equal(vec_mode->mode, &crtc_state->mode))
|
||||
return -EINVAL;
|
||||
|
||||
if (old_state->tv.mode != new_state->tv.mode)
|
||||
crtc_state->mode_changed = true;
|
||||
}
|
||||
|
||||
@ -559,7 +589,10 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
|
||||
VEC_WRITE(VEC_CLMP0_START, 0xac);
|
||||
VEC_WRITE(VEC_CLMP0_END, 0xec);
|
||||
VEC_WRITE(VEC_CONFIG2,
|
||||
VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
|
||||
VEC_CONFIG2_UV_DIG_DIS |
|
||||
VEC_CONFIG2_RGB_DIG_DIS |
|
||||
((encoder->crtc->state->adjusted_mode.flags &
|
||||
DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN));
|
||||
VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
|
||||
VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
|
||||
|
||||
@ -582,17 +615,88 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
|
||||
}
|
||||
|
||||
|
||||
static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
return true;
|
||||
const struct drm_display_mode *reference_mode =
|
||||
vc4_vec_tv_modes[conn_state->tv.mode].interlaced_mode;
|
||||
|
||||
if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock ||
|
||||
crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal ||
|
||||
crtc_state->adjusted_mode.crtc_hdisplay % 4 != 0 ||
|
||||
crtc_state->adjusted_mode.crtc_hsync_end -
|
||||
crtc_state->adjusted_mode.crtc_hsync_start < 1)
|
||||
return -EINVAL;
|
||||
|
||||
switch (reference_mode->vtotal) {
|
||||
case 525:
|
||||
if (crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
|
||||
crtc_state->adjusted_mode.crtc_vdisplay > 253 ||
|
||||
crtc_state->adjusted_mode.crtc_vsync_start -
|
||||
crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
|
||||
crtc_state->adjusted_mode.crtc_vsync_end -
|
||||
crtc_state->adjusted_mode.crtc_vsync_start != 3 ||
|
||||
crtc_state->adjusted_mode.crtc_vtotal -
|
||||
crtc_state->adjusted_mode.crtc_vsync_end < 4 ||
|
||||
crtc_state->adjusted_mode.crtc_vtotal > 262)
|
||||
return -EINVAL;
|
||||
|
||||
if ((crtc_state->adjusted_mode.flags &
|
||||
DRM_MODE_FLAG_INTERLACE) &&
|
||||
(crtc_state->adjusted_mode.vdisplay % 2 != 0 ||
|
||||
crtc_state->adjusted_mode.vsync_start % 2 != 1 ||
|
||||
crtc_state->adjusted_mode.vsync_end % 2 != 1 ||
|
||||
crtc_state->adjusted_mode.vtotal % 2 != 1))
|
||||
return -EINVAL;
|
||||
|
||||
/* progressive mode is hard-wired to 262 total lines */
|
||||
if (!(crtc_state->adjusted_mode.flags &
|
||||
DRM_MODE_FLAG_INTERLACE) &&
|
||||
crtc_state->adjusted_mode.crtc_vtotal != 262)
|
||||
return -EINVAL;
|
||||
|
||||
break;
|
||||
|
||||
case 625:
|
||||
if (crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
|
||||
crtc_state->adjusted_mode.crtc_vdisplay > 305 ||
|
||||
crtc_state->adjusted_mode.crtc_vsync_start -
|
||||
crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
|
||||
crtc_state->adjusted_mode.crtc_vsync_end -
|
||||
crtc_state->adjusted_mode.crtc_vsync_start != 3 ||
|
||||
crtc_state->adjusted_mode.crtc_vtotal -
|
||||
crtc_state->adjusted_mode.crtc_vsync_end < 2 ||
|
||||
crtc_state->adjusted_mode.crtc_vtotal > 312)
|
||||
return -EINVAL;
|
||||
|
||||
if ((crtc_state->adjusted_mode.flags &
|
||||
DRM_MODE_FLAG_INTERLACE) &&
|
||||
(crtc_state->adjusted_mode.vdisplay % 2 != 0 ||
|
||||
crtc_state->adjusted_mode.vsync_start % 2 != 0 ||
|
||||
crtc_state->adjusted_mode.vsync_end % 2 != 0 ||
|
||||
crtc_state->adjusted_mode.vtotal % 2 != 1))
|
||||
return -EINVAL;
|
||||
|
||||
/* progressive mode is hard-wired to 312 total lines */
|
||||
if (!(crtc_state->adjusted_mode.flags &
|
||||
DRM_MODE_FLAG_INTERLACE) &&
|
||||
crtc_state->adjusted_mode.crtc_vtotal != 312)
|
||||
return -EINVAL;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
|
||||
.disable = vc4_vec_encoder_disable,
|
||||
.enable = vc4_vec_encoder_enable,
|
||||
.mode_fixup = vc4_vec_encoder_mode_fixup,
|
||||
.atomic_check = vc4_vec_encoder_atomic_check,
|
||||
};
|
||||
|
||||
static const struct vc4_vec_variant bcm2835_vec_variant = {
|
||||
|
Loading…
Reference in New Issue
Block a user