Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev into drm-next
* 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev: drm: rcar-du: Implement support for interlaced modes drm: rcar-du: Clamp DPMS states to on and off drm: rcar-du: Enable hotplug detection on HDMI connector drm: rcar-du: Output HSYNC instead of CSYNC drm: rcar-du: Add support for external pixel clock drm: rcar-du: Refactor DEFR8 feature drm: rcar-du: Remove LVDS and HDMI encoders chaining restriction drm: rcar-du: Configure pitch for chroma plane of multiplanar formats drm: rcar-du: Don't fail probe in case of partial encoder init error drm: adv7511: Remove interlaced mode check
This commit is contained in:
commit
b2eb048980
|
@ -26,6 +26,10 @@ Required Properties:
|
|||
per LVDS encoder. The functional clocks must be named "du.x" with "x"
|
||||
being the channel numerical index. The LVDS clocks must be named
|
||||
"lvds.x" with "x" being the LVDS encoder numerical index.
|
||||
- In addition to the functional and encoder clocks, all DU versions also
|
||||
support externally supplied pixel clocks. Those clocks are optional.
|
||||
When supplied they must be named "dclkin.x" with "x" being the input
|
||||
clock numerical index.
|
||||
|
||||
Required nodes:
|
||||
|
||||
|
|
|
@ -644,9 +644,6 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
|
|||
if (mode->clock > 165000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
return MODE_NO_INTERLACE;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,39 +74,77 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(rcrtc->extclock);
|
||||
if (ret < 0)
|
||||
goto error_clock;
|
||||
|
||||
ret = rcar_du_group_get(rcrtc->group);
|
||||
if (ret < 0)
|
||||
clk_disable_unprepare(rcrtc->clock);
|
||||
goto error_group;
|
||||
|
||||
return 0;
|
||||
|
||||
error_group:
|
||||
clk_disable_unprepare(rcrtc->extclock);
|
||||
error_clock:
|
||||
clk_disable_unprepare(rcrtc->clock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
|
||||
{
|
||||
rcar_du_group_put(rcrtc->group);
|
||||
|
||||
clk_disable_unprepare(rcrtc->extclock);
|
||||
clk_disable_unprepare(rcrtc->clock);
|
||||
}
|
||||
|
||||
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
|
||||
{
|
||||
const struct drm_display_mode *mode = &rcrtc->crtc.mode;
|
||||
unsigned long mode_clock = mode->clock * 1000;
|
||||
unsigned long clk;
|
||||
u32 value;
|
||||
u32 escr;
|
||||
u32 div;
|
||||
|
||||
/* Dot clock */
|
||||
/* Compute the clock divisor and select the internal or external dot
|
||||
* clock based on the requested frequency.
|
||||
*/
|
||||
clk = clk_get_rate(rcrtc->clock);
|
||||
div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000);
|
||||
div = DIV_ROUND_CLOSEST(clk, mode_clock);
|
||||
div = clamp(div, 1U, 64U) - 1;
|
||||
escr = div | ESCR_DCLKSEL_CLKS;
|
||||
|
||||
if (rcrtc->extclock) {
|
||||
unsigned long extclk;
|
||||
unsigned long extrate;
|
||||
unsigned long rate;
|
||||
u32 extdiv;
|
||||
|
||||
extclk = clk_get_rate(rcrtc->extclock);
|
||||
extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
|
||||
extdiv = clamp(extdiv, 1U, 64U) - 1;
|
||||
|
||||
rate = clk / (div + 1);
|
||||
extrate = extclk / (extdiv + 1);
|
||||
|
||||
if (abs((long)extrate - (long)mode_clock) <
|
||||
abs((long)rate - (long)mode_clock)) {
|
||||
dev_dbg(rcrtc->group->dev->dev,
|
||||
"crtc%u: using external clock\n", rcrtc->index);
|
||||
escr = extdiv | ESCR_DCLKSEL_DCLKIN;
|
||||
}
|
||||
}
|
||||
|
||||
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
|
||||
ESCR_DCLKSEL_CLKS | div);
|
||||
escr);
|
||||
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
|
||||
|
||||
/* Signal polarities */
|
||||
value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
|
||||
| ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
|
||||
| DSMR_DIPM_DE;
|
||||
| DSMR_DIPM_DE | DSMR_CSPM;
|
||||
rcar_du_crtc_write(rcrtc, DSMR, value);
|
||||
|
||||
/* Display timings */
|
||||
|
@ -117,12 +155,15 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
|
|||
mode->hsync_start - 1);
|
||||
rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1);
|
||||
|
||||
rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2);
|
||||
rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end +
|
||||
mode->vdisplay - 2);
|
||||
rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end +
|
||||
mode->vsync_start - 1);
|
||||
rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1);
|
||||
rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal -
|
||||
mode->crtc_vsync_end - 2);
|
||||
rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal -
|
||||
mode->crtc_vsync_end +
|
||||
mode->crtc_vdisplay - 2);
|
||||
rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal -
|
||||
mode->crtc_vsync_end +
|
||||
mode->crtc_vsync_start - 1);
|
||||
rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1);
|
||||
|
||||
rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start);
|
||||
rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
|
||||
|
@ -139,9 +180,10 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
|
|||
*/
|
||||
rcrtc->outputs |= BIT(output);
|
||||
|
||||
/* Store RGB routing to DPAD0 for R8A7790. */
|
||||
if (rcar_du_has(rcdu, RCAR_DU_FEATURE_DEFR8) &&
|
||||
output == RCAR_DU_OUTPUT_DPAD0)
|
||||
/* Store RGB routing to DPAD0, the hardware will be configured when
|
||||
* starting the CRTC.
|
||||
*/
|
||||
if (output == RCAR_DU_OUTPUT_DPAD0)
|
||||
rcdu->dpad0_source = rcrtc->index;
|
||||
}
|
||||
|
||||
|
@ -217,6 +259,7 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
|
|||
static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
|
||||
{
|
||||
struct drm_crtc *crtc = &rcrtc->crtc;
|
||||
bool interlaced;
|
||||
unsigned int i;
|
||||
|
||||
if (rcrtc->started)
|
||||
|
@ -252,7 +295,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
|
|||
* sync mode (with the HSYNC and VSYNC signals configured as outputs and
|
||||
* actively driven).
|
||||
*/
|
||||
rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
|
||||
interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
|
||||
rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
|
||||
(interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
|
||||
DSYSR_TVM_MASTER);
|
||||
|
||||
rcar_du_group_start_stop(rcrtc->group, true);
|
||||
|
||||
|
@ -308,6 +354,9 @@ static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
{
|
||||
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (rcrtc->dpms == mode)
|
||||
return;
|
||||
|
||||
|
@ -486,7 +535,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
|
|||
status = rcar_du_crtc_read(rcrtc, DSSR);
|
||||
rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
|
||||
|
||||
if (status & DSSR_VBK) {
|
||||
if (status & DSSR_FRM) {
|
||||
drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
|
||||
rcar_du_crtc_finish_page_flip(rcrtc);
|
||||
ret = IRQ_HANDLED;
|
||||
|
@ -542,12 +591,13 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
|
|||
struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
|
||||
struct drm_crtc *crtc = &rcrtc->crtc;
|
||||
unsigned int irqflags;
|
||||
char clk_name[5];
|
||||
struct clk *clk;
|
||||
char clk_name[9];
|
||||
char *name;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
/* Get the CRTC clock. */
|
||||
/* Get the CRTC clock and the optional external clock. */
|
||||
if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) {
|
||||
sprintf(clk_name, "du.%u", index);
|
||||
name = clk_name;
|
||||
|
@ -561,6 +611,15 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
|
|||
return PTR_ERR(rcrtc->clock);
|
||||
}
|
||||
|
||||
sprintf(clk_name, "dclkin.%u", index);
|
||||
clk = devm_clk_get(rcdu->dev, clk_name);
|
||||
if (!IS_ERR(clk)) {
|
||||
rcrtc->extclock = clk;
|
||||
} else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) {
|
||||
dev_info(rcdu->dev, "can't get external clock %u\n", index);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
rcrtc->group = rgrp;
|
||||
rcrtc->mmio_offset = mmio_offsets[index];
|
||||
rcrtc->index = index;
|
||||
|
|
|
@ -26,6 +26,7 @@ struct rcar_du_crtc {
|
|||
struct drm_crtc crtc;
|
||||
|
||||
struct clk *clock;
|
||||
struct clk *extclock;
|
||||
unsigned int mmio_offset;
|
||||
unsigned int index;
|
||||
bool started;
|
||||
|
|
|
@ -56,7 +56,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = {
|
|||
};
|
||||
|
||||
static const struct rcar_du_device_info rcar_du_r8a7790_info = {
|
||||
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
|
||||
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
|
||||
| RCAR_DU_FEATURE_EXT_CTRL_REGS,
|
||||
.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
|
||||
.num_crtcs = 3,
|
||||
.routes = {
|
||||
|
@ -83,7 +84,8 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
|
|||
};
|
||||
|
||||
static const struct rcar_du_device_info rcar_du_r8a7791_info = {
|
||||
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
|
||||
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
|
||||
| RCAR_DU_FEATURE_EXT_CTRL_REGS,
|
||||
.num_crtcs = 2,
|
||||
.routes = {
|
||||
/* R8A7791 has one RGB output, one LVDS output and one
|
||||
|
|
|
@ -27,7 +27,7 @@ struct rcar_du_device;
|
|||
struct rcar_du_lvdsenc;
|
||||
|
||||
#define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */
|
||||
#define RCAR_DU_FEATURE_DEFR8 (1 << 1) /* Has DEFR8 register */
|
||||
#define RCAR_DU_FEATURE_EXT_CTRL_REGS (1 << 1) /* Has extended control registers */
|
||||
|
||||
#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */
|
||||
#define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */
|
||||
|
|
|
@ -46,6 +46,9 @@ static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|||
{
|
||||
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (renc->lvds)
|
||||
rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode);
|
||||
}
|
||||
|
@ -190,35 +193,42 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
|
|||
}
|
||||
|
||||
if (type == RCAR_DU_ENCODER_HDMI) {
|
||||
if (renc->lvds) {
|
||||
dev_err(rcdu->dev,
|
||||
"Chaining LVDS and HDMI encoders not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = rcar_du_hdmienc_init(rcdu, renc, enc_node);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto done;
|
||||
} else {
|
||||
ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
|
||||
encoder_type);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto done;
|
||||
|
||||
drm_encoder_helper_add(encoder, &encoder_helper_funcs);
|
||||
}
|
||||
|
||||
switch (encoder_type) {
|
||||
case DRM_MODE_ENCODER_LVDS:
|
||||
return rcar_du_lvds_connector_init(rcdu, renc, con_node);
|
||||
ret = rcar_du_lvds_connector_init(rcdu, renc, con_node);
|
||||
break;
|
||||
|
||||
case DRM_MODE_ENCODER_DAC:
|
||||
return rcar_du_vga_connector_init(rcdu, renc);
|
||||
ret = rcar_du_vga_connector_init(rcdu, renc);
|
||||
break;
|
||||
|
||||
case DRM_MODE_ENCODER_TMDS:
|
||||
return rcar_du_hdmi_connector_init(rcdu, renc);
|
||||
ret = rcar_du_hdmi_connector_init(rcdu, renc);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
if (ret < 0) {
|
||||
if (encoder->name)
|
||||
encoder->funcs->destroy(encoder);
|
||||
devm_kfree(rcdu->dev, renc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -48,9 +48,6 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
|
|||
{
|
||||
u32 defr8 = DEFR8_CODE | DEFR8_DEFE8;
|
||||
|
||||
if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_DEFR8))
|
||||
return;
|
||||
|
||||
/* The DEFR8 register for the first group also controls RGB output
|
||||
* routing to DPAD0
|
||||
*/
|
||||
|
@ -69,7 +66,20 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
|
|||
rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE);
|
||||
rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
|
||||
|
||||
rcar_du_group_setup_defr8(rgrp);
|
||||
if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) {
|
||||
rcar_du_group_setup_defr8(rgrp);
|
||||
|
||||
/* Configure input dot clock routing. We currently hardcode the
|
||||
* configuration to routing DOTCLKINn to DUn.
|
||||
*/
|
||||
rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE |
|
||||
DIDSR_LCDS_DCLKIN(2) |
|
||||
DIDSR_LCDS_DCLKIN(1) |
|
||||
DIDSR_LCDS_DCLKIN(0) |
|
||||
DIDSR_PDCS_CLK(2, 0) |
|
||||
DIDSR_PDCS_CLK(1, 0) |
|
||||
DIDSR_PDCS_CLK(0, 0));
|
||||
}
|
||||
|
||||
/* Use DS1PR and DS2PR to configure planes priorities and connects the
|
||||
* superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
|
||||
|
@ -149,6 +159,9 @@ static int rcar_du_set_dpad0_routing(struct rcar_du_device *rcdu)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS))
|
||||
return 0;
|
||||
|
||||
/* RGB output routing to DPAD0 is configured in the DEFR8 register of
|
||||
* the first group. As this function can be called with the DU0 and DU1
|
||||
* CRTCs disabled, we need to enable the first group clock before
|
||||
|
|
|
@ -95,6 +95,8 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
|
|||
connector = &rcon->connector;
|
||||
connector->display_info.width_mm = 0;
|
||||
connector->display_info.height_mm = 0;
|
||||
connector->interlace_allowed = true;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "rcar_du_drv.h"
|
||||
#include "rcar_du_encoder.h"
|
||||
#include "rcar_du_hdmienc.h"
|
||||
#include "rcar_du_lvdsenc.h"
|
||||
|
||||
struct rcar_du_hdmienc {
|
||||
struct rcar_du_encoder *renc;
|
||||
|
@ -36,12 +37,21 @@ static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode)
|
|||
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
|
||||
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (hdmienc->dpms == mode)
|
||||
return;
|
||||
|
||||
if (mode == DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
|
||||
rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
|
||||
|
||||
if (sfuncs->dpms)
|
||||
sfuncs->dpms(encoder, mode);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
|
||||
rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
|
||||
|
||||
hdmienc->dpms = mode;
|
||||
}
|
||||
|
||||
|
@ -49,8 +59,16 @@ static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,
|
|||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
|
||||
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
|
||||
|
||||
/* The internal LVDS encoder has a clock frequency operating range of
|
||||
* 30MHz to 150MHz. Clamp the clock accordingly.
|
||||
*/
|
||||
if (hdmienc->renc->lvds)
|
||||
adjusted_mode->clock = clamp(adjusted_mode->clock,
|
||||
30000, 150000);
|
||||
|
||||
if (sfuncs->mode_fixup == NULL)
|
||||
return true;
|
||||
|
||||
|
|
|
@ -346,8 +346,14 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
|
|||
/* Process the output pipeline. */
|
||||
ret = rcar_du_encoders_init_one(rcdu, output, &ep);
|
||||
if (ret < 0) {
|
||||
of_node_put(ep_node);
|
||||
return ret;
|
||||
if (ret == -EPROBE_DEFER) {
|
||||
of_node_put(ep_node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(rcdu->dev,
|
||||
"encoder initialization failed, skipping\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
num_encoders += ret;
|
||||
|
@ -413,6 +419,11 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret == 0) {
|
||||
dev_err(rcdu->dev, "error: no encoder could be initialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_encoders = ret;
|
||||
|
||||
/* Set the possible CRTCs and possible clones. There's always at least
|
||||
|
|
|
@ -104,14 +104,22 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
|
|||
{
|
||||
struct rcar_du_group *rgrp = plane->group;
|
||||
unsigned int index = plane->hwindex;
|
||||
bool interlaced;
|
||||
u32 mwr;
|
||||
|
||||
/* Memory pitch (expressed in pixels) */
|
||||
interlaced = plane->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
|
||||
|
||||
/* Memory pitch (expressed in pixels). Must be doubled for interlaced
|
||||
* operation with 32bpp formats.
|
||||
*/
|
||||
if (plane->format->planes == 2)
|
||||
mwr = plane->pitch;
|
||||
else
|
||||
mwr = plane->pitch * 8 / plane->format->bpp;
|
||||
|
||||
if (interlaced && plane->format->bpp == 32)
|
||||
mwr *= 2;
|
||||
|
||||
rcar_du_plane_write(rgrp, index, PnMWR, mwr);
|
||||
|
||||
/* The Y position is expressed in raster line units and must be doubled
|
||||
|
@ -119,17 +127,23 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
|
|||
* doubling the Y position is found in the R8A7779 datasheet, but the
|
||||
* rule seems to apply there as well.
|
||||
*
|
||||
* Despite not being documented, doubling seem not to be needed when
|
||||
* operating in interlaced mode.
|
||||
*
|
||||
* Similarly, for the second plane, NV12 and NV21 formats seem to
|
||||
* require a halved Y position value.
|
||||
* require a halved Y position value, in both progressive and interlaced
|
||||
* modes.
|
||||
*/
|
||||
rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
|
||||
rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
|
||||
(plane->format->bpp == 32 ? 2 : 1));
|
||||
(!interlaced && plane->format->bpp == 32 ? 2 : 1));
|
||||
rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
|
||||
|
||||
if (plane->format->planes == 2) {
|
||||
index = (index + 1) % 8;
|
||||
|
||||
rcar_du_plane_write(rgrp, index, PnMWR, plane->pitch);
|
||||
|
||||
rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
|
||||
rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
|
||||
(plane->format->bpp == 16 ? 2 : 1) / 2);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define DSYSR_SCM_INT_NONE (0 << 4)
|
||||
#define DSYSR_SCM_INT_SYNC (2 << 4)
|
||||
#define DSYSR_SCM_INT_VIDEO (3 << 4)
|
||||
#define DSYSR_SCM_MASK (3 << 4)
|
||||
|
||||
#define DSMR 0x00004
|
||||
#define DSMR_VSPM (1 << 28)
|
||||
|
@ -256,8 +257,8 @@
|
|||
#define DIDSR_LCDS_LVDS0(n) (2 << (8 + (n) * 2))
|
||||
#define DIDSR_LCDS_LVDS1(n) (3 << (8 + (n) * 2))
|
||||
#define DIDSR_LCDS_MASK(n) (3 << (8 + (n) * 2))
|
||||
#define DIDSR_PCDS_CLK(n, clk) (clk << ((n) * 2))
|
||||
#define DIDSR_PCDS_MASK(n) (3 << ((n) * 2))
|
||||
#define DIDSR_PDCS_CLK(n, clk) (clk << ((n) * 2))
|
||||
#define DIDSR_PDCS_MASK(n) (3 << ((n) * 2))
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Display Timing Generation Registers
|
||||
|
|
|
@ -64,6 +64,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
|
|||
connector = &rcon->connector;
|
||||
connector->display_info.width_mm = 0;
|
||||
connector->display_info.height_mm = 0;
|
||||
connector->interlace_allowed = true;
|
||||
|
||||
ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
|
||||
DRM_MODE_CONNECTOR_VGA);
|
||||
|
|
Loading…
Reference in New Issue