Commit 32030592 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'du-next-20220907' of git://linuxtv.org/pinchartl/media into drm-next

- Misc fixes and improvements to the R-Car DU driver
- Synopsys DW HDMI bridge DT bindings update
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/YxkL+tRI8uXDCvj9@pendragon.ideasonboard.com
parents 849b1f33 cee3e583
......@@ -38,6 +38,9 @@ properties:
clock-names:
maxItems: 2
resets:
maxItems: 1
ports:
$ref: /schemas/graph.yaml#/properties/ports
......@@ -67,6 +70,7 @@ required:
- reg
- clocks
- clock-names
- resets
- interrupts
- ports
......@@ -85,6 +89,7 @@ examples:
clocks = <&cpg CPG_CORE R8A7795_CLK_S0D4>, <&cpg CPG_MOD 729>;
clock-names = "iahb", "isfr";
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 729>;
ports {
#address-cells = <1>;
......
......@@ -14,10 +14,3 @@ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o
obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o
obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o
obj-$(CONFIG_DRM_RCAR_MIPI_DSI) += rcar_mipi_dsi.o
# 'remote-endpoint' is fixed up at run-time
DTC_FLAGS_rcar_du_of_lvds_r8a7790 += -Wno-graph_endpoint
DTC_FLAGS_rcar_du_of_lvds_r8a7791 += -Wno-graph_endpoint
DTC_FLAGS_rcar_du_of_lvds_r8a7793 += -Wno-graph_endpoint
DTC_FLAGS_rcar_du_of_lvds_r8a7795 += -Wno-graph_endpoint
DTC_FLAGS_rcar_du_of_lvds_r8a7796 += -Wno-graph_endpoint
......@@ -29,6 +29,7 @@
#include "rcar_du_regs.h"
#include "rcar_du_vsp.h"
#include "rcar_lvds.h"
#include "rcar_mipi_dsi.h"
static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg)
{
......@@ -744,7 +745,19 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
const struct drm_display_mode *mode =
&crtc->state->adjusted_mode;
rcar_lvds_clk_enable(bridge, mode->clock * 1000);
rcar_lvds_pclk_enable(bridge, mode->clock * 1000);
}
/*
* Similarly to LVDS, on V3U the dot clock is provided by the DSI
* encoder, and we need to enable the DSI clocks before enabling the CRTC.
*/
if ((rcdu->info->dsi_clk_mask & BIT(rcrtc->index)) &&
(rstate->outputs &
(BIT(RCAR_DU_OUTPUT_DSI0) | BIT(RCAR_DU_OUTPUT_DSI1)))) {
struct drm_bridge *bridge = rcdu->dsi[rcrtc->index];
rcar_mipi_dsi_pclk_enable(bridge, state);
}
rcar_du_crtc_start(rcrtc);
......@@ -777,7 +790,20 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
* Disable the LVDS clock output, see
* rcar_du_crtc_atomic_enable().
*/
rcar_lvds_clk_disable(bridge);
rcar_lvds_pclk_disable(bridge);
}
if ((rcdu->info->dsi_clk_mask & BIT(rcrtc->index)) &&
(rstate->outputs &
(BIT(RCAR_DU_OUTPUT_DSI0) | BIT(RCAR_DU_OUTPUT_DSI1)))) {
struct drm_bridge *bridge = rcdu->dsi[rcrtc->index];
/*
* Disable the DSI clock output, see
* rcar_du_crtc_atomic_enable().
*/
rcar_mipi_dsi_pclk_disable(bridge);
}
spin_lock_irq(&crtc->dev->event_lock);
......
......@@ -27,7 +27,6 @@
#include "rcar_du_drv.h"
#include "rcar_du_kms.h"
#include "rcar_du_regs.h"
/* -----------------------------------------------------------------------------
* Device Information
......@@ -507,7 +506,8 @@ static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
.gen = 3,
.features = RCAR_DU_FEATURE_CRTC_IRQ
| RCAR_DU_FEATURE_VSP1_SOURCE,
| RCAR_DU_FEATURE_VSP1_SOURCE
| RCAR_DU_FEATURE_NO_BLENDING,
.channels_mask = BIT(1) | BIT(0),
.routes = {
/* R8A779A0 has two MIPI DSI outputs. */
......
......@@ -31,6 +31,7 @@ struct rcar_du_device;
#define RCAR_DU_FEATURE_VSP1_SOURCE BIT(2) /* Has inputs from VSP1 */
#define RCAR_DU_FEATURE_INTERLACED BIT(3) /* HW supports interlaced */
#define RCAR_DU_FEATURE_TVM_SYNC BIT(4) /* Has TV switch/sync modes */
#define RCAR_DU_FEATURE_NO_BLENDING BIT(5) /* PnMR.SPIM does not have ALP nor EOR bits */
#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */
......@@ -91,6 +92,7 @@ struct rcar_du_device_info {
#define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2)
#define RCAR_DU_MAX_VSPS 4
#define RCAR_DU_MAX_LVDS 2
#define RCAR_DU_MAX_DSI 2
struct rcar_du_device {
struct device *dev;
......@@ -107,6 +109,7 @@ struct rcar_du_device {
struct platform_device *cmms[RCAR_DU_MAX_CRTCS];
struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS];
struct drm_bridge *lvds[RCAR_DU_MAX_LVDS];
struct drm_bridge *dsi[RCAR_DU_MAX_DSI];
struct {
struct drm_property *colorkey;
......
......@@ -9,18 +9,13 @@
#include <linux/export.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_panel.h>
#include "rcar_du_drv.h"
#include "rcar_du_encoder.h"
#include "rcar_du_kms.h"
#include "rcar_lvds.h"
/* -----------------------------------------------------------------------------
......@@ -84,6 +79,10 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
if (output == RCAR_DU_OUTPUT_LVDS0 ||
output == RCAR_DU_OUTPUT_LVDS1)
rcdu->lvds[output - RCAR_DU_OUTPUT_LVDS0] = bridge;
if (output == RCAR_DU_OUTPUT_DSI0 ||
output == RCAR_DU_OUTPUT_DSI1)
rcdu->dsi[output - RCAR_DU_OUTPUT_DSI0] = bridge;
}
/*
......
......@@ -405,8 +405,8 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
format = rcar_du_format_info(mode_cmd->pixel_format);
if (format == NULL) {
dev_dbg(dev->dev, "unsupported pixel format %08x\n",
mode_cmd->pixel_format);
dev_dbg(dev->dev, "unsupported pixel format %p4cc\n",
&mode_cmd->pixel_format);
return ERR_PTR(-EINVAL);
}
......
......@@ -506,8 +506,15 @@ static void rcar_du_plane_setup_format_gen3(struct rcar_du_group *rgrp,
unsigned int index,
const struct rcar_du_plane_state *state)
{
rcar_du_plane_write(rgrp, index, PnMR,
PnMR_SPIM_TP_OFF | state->format->pnmr);
struct rcar_du_device *rcdu = rgrp->dev;
u32 pnmr = state->format->pnmr | PnMR_SPIM_TP_OFF;
if (rcdu->info->features & RCAR_DU_FEATURE_NO_BLENDING) {
/* No blending. ALP and EOR are not supported. */
pnmr &= ~(PnMR_SPIM_ALP | PnMR_SPIM_EOR);
}
rcar_du_plane_write(rgrp, index, PnMR, pnmr);
rcar_du_plane_write(rgrp, index, PnDDCR4,
state->format->edf | PnDDCR4_CODE);
......@@ -521,7 +528,6 @@ static void rcar_du_plane_setup_format_gen3(struct rcar_du_group *rgrp,
* register to 0 to avoid this.
*/
/* TODO: Check if alpha-blending should be disabled in PnMR. */
rcar_du_plane_write(rgrp, index, PnALPHAR, 0);
}
......@@ -619,8 +625,8 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane,
*format = rcar_du_format_info(state->fb->format->format);
if (*format == NULL) {
dev_dbg(dev->dev, "%s: unsupported format %08x\n", __func__,
state->fb->format->format);
dev_dbg(dev->dev, "%s: unsupported format %p4cc\n", __func__,
&state->fb->format->format);
return -EINVAL;
}
......
......@@ -152,6 +152,7 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
.alpha = state->state.alpha >> 8,
.zpos = state->state.zpos,
};
u32 fourcc = state->format->fourcc;
unsigned int i;
cfg.src.left = state->state.src.x1 >> 16;
......@@ -168,9 +169,27 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
cfg.mem[i] = sg_dma_address(state->sg_tables[i].sgl)
+ fb->offsets[i];
format = rcar_du_format_info(state->format->fourcc);
if (state->state.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE) {
switch (fourcc) {
case DRM_FORMAT_ARGB1555:
fourcc = DRM_FORMAT_XRGB1555;
break;
case DRM_FORMAT_ARGB4444:
fourcc = DRM_FORMAT_XRGB4444;
break;
case DRM_FORMAT_ARGB8888:
fourcc = DRM_FORMAT_XRGB8888;
break;
}
}
format = rcar_du_format_info(fourcc);
cfg.pixelformat = format->v4l2;
cfg.premult = state->state.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI;
vsp1_du_atomic_update(plane->vsp->vsp, crtc->vsp_pipe,
plane->index, &cfg);
}
......@@ -436,6 +455,11 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
drm_plane_create_zpos_property(&plane->plane, i, 0,
num_planes - 1);
drm_plane_create_blend_mode_property(&plane->plane,
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE));
vsp->num_planes++;
}
......
......@@ -166,8 +166,8 @@ static int rcar_du_wb_enc_atomic_check(struct drm_encoder *encoder,
wb_state->format = rcar_du_format_info(fb->format->format);
if (wb_state->format == NULL) {
dev_dbg(dev->dev, "%s: unsupported format %08x\n", __func__,
fb->format->format);
dev_dbg(dev->dev, "%s: unsupported format %p4cc\n", __func__,
&fb->format->format);
return -EINVAL;
}
......
......@@ -306,7 +306,7 @@ static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
* Clock - D3/E3 only
*/
int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq)
int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq)
{
struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
int ret;
......@@ -324,9 +324,9 @@ int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq)
return 0;
}
EXPORT_SYMBOL_GPL(rcar_lvds_clk_enable);
EXPORT_SYMBOL_GPL(rcar_lvds_pclk_enable);
void rcar_lvds_clk_disable(struct drm_bridge *bridge)
void rcar_lvds_pclk_disable(struct drm_bridge *bridge)
{
struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
......@@ -339,7 +339,7 @@ void rcar_lvds_clk_disable(struct drm_bridge *bridge)
clk_disable_unprepare(lvds->clocks.mod);
}
EXPORT_SYMBOL_GPL(rcar_lvds_clk_disable);
EXPORT_SYMBOL_GPL(rcar_lvds_pclk_disable);
/* -----------------------------------------------------------------------------
* Bridge
......
......@@ -13,17 +13,17 @@
struct drm_bridge;
#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq);
void rcar_lvds_clk_disable(struct drm_bridge *bridge);
int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq);
void rcar_lvds_pclk_disable(struct drm_bridge *bridge);
bool rcar_lvds_dual_link(struct drm_bridge *bridge);
bool rcar_lvds_is_connected(struct drm_bridge *bridge);
#else
static inline int rcar_lvds_clk_enable(struct drm_bridge *bridge,
static inline int rcar_lvds_pclk_enable(struct drm_bridge *bridge,
unsigned long freq)
{
return -ENOSYS;
}
static inline void rcar_lvds_clk_disable(struct drm_bridge *bridge) { }
static inline void rcar_lvds_pclk_disable(struct drm_bridge *bridge) { }
static inline bool rcar_lvds_dual_link(struct drm_bridge *bridge)
{
return false;
......
......@@ -25,6 +25,7 @@
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include "rcar_mipi_dsi.h"
#include "rcar_mipi_dsi_regs.h"
struct rcar_mipi_dsi {
......@@ -414,7 +415,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
/* Enable DOT clock */
vclkset = VCLKSET_CKEN;
rcar_mipi_dsi_set(dsi, VCLKSET, vclkset);
rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
if (dsi_format == 24)
vclkset |= VCLKSET_BPP_24;
......@@ -429,7 +430,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
| VCLKSET_LANE(dsi->lanes - 1);
rcar_mipi_dsi_set(dsi, VCLKSET, vclkset);
rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
/* After setting VCLKSET register, enable VCLKEN */
rcar_mipi_dsi_set(dsi, VCLKEN, VCLKEN_CKEN);
......@@ -441,9 +442,21 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
static void rcar_mipi_dsi_shutdown(struct rcar_mipi_dsi *dsi)
{
/* Disable VCLKEN */
rcar_mipi_dsi_write(dsi, VCLKSET, 0);
/* Disable DOT clock */
rcar_mipi_dsi_write(dsi, VCLKSET, 0);
rcar_mipi_dsi_clr(dsi, PHYSETUP, PHYSETUP_RSTZ);
rcar_mipi_dsi_clr(dsi, PHYSETUP, PHYSETUP_SHUTDOWNZ);
/* CFGCLK disable */
rcar_mipi_dsi_clr(dsi, CFGCLKSET, CFGCLKSET_CKEN);
/* LPCLK disable */
rcar_mipi_dsi_clr(dsi, LPCLKSET, LPCLKSET_CKEN);
dev_dbg(dsi->dev, "DSI device is shutdown\n");
}
......@@ -542,6 +555,34 @@ static int rcar_mipi_dsi_start_video(struct rcar_mipi_dsi *dsi)
return 0;
}
static void rcar_mipi_dsi_stop_video(struct rcar_mipi_dsi *dsi)
{
u32 status;
int ret;
/* Disable transmission in video mode. */
rcar_mipi_dsi_clr(dsi, TXVMCR, TXVMCR_EN_VIDEO);
ret = read_poll_timeout(rcar_mipi_dsi_read, status,
!(status & TXVMSR_ACT),
2000, 100000, false, dsi, TXVMSR);
if (ret < 0) {
dev_err(dsi->dev, "Failed to disable video transmission\n");
return;
}
/* Assert video FIFO clear. */
rcar_mipi_dsi_set(dsi, TXVMCR, TXVMCR_VFCLR);
ret = read_poll_timeout(rcar_mipi_dsi_read, status,
!(status & TXVMSR_VFRDY),
2000, 100000, false, dsi, TXVMSR);
if (ret < 0) {
dev_err(dsi->dev, "Failed to assert video FIFO clear\n");
return;
}
}
/* -----------------------------------------------------------------------------
* Bridge
*/
......@@ -558,7 +599,22 @@ static int rcar_mipi_dsi_attach(struct drm_bridge *bridge,
static void rcar_mipi_dsi_atomic_enable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct drm_atomic_state *state = old_bridge_state->base.state;
struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge);
rcar_mipi_dsi_start_video(dsi);
}
static void rcar_mipi_dsi_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge);
rcar_mipi_dsi_stop_video(dsi);
}
void rcar_mipi_dsi_pclk_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge);
const struct drm_display_mode *mode;
struct drm_connector *connector;
......@@ -586,8 +642,6 @@ static void rcar_mipi_dsi_atomic_enable(struct drm_bridge *bridge,
if (ret < 0)
goto err_dsi_start_hs;
rcar_mipi_dsi_start_video(dsi);
return;
err_dsi_start_hs:
......@@ -595,15 +649,16 @@ static void rcar_mipi_dsi_atomic_enable(struct drm_bridge *bridge,
err_dsi_startup:
rcar_mipi_dsi_clk_disable(dsi);
}
EXPORT_SYMBOL_GPL(rcar_mipi_dsi_pclk_enable);
static void rcar_mipi_dsi_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
void rcar_mipi_dsi_pclk_disable(struct drm_bridge *bridge)
{
struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge);
rcar_mipi_dsi_shutdown(dsi);
rcar_mipi_dsi_clk_disable(dsi);
}
EXPORT_SYMBOL_GPL(rcar_mipi_dsi_pclk_disable);
static enum drm_mode_status
rcar_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* R-Car DSI Encoder
*
* Copyright (C) 2022 Renesas Electronics Corporation
*
* Contact: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
*/
#ifndef __RCAR_MIPI_DSI_H__
#define __RCAR_MIPI_DSI_H__
struct drm_atomic_state;
struct drm_bridge;
#if IS_ENABLED(CONFIG_DRM_RCAR_MIPI_DSI)
void rcar_mipi_dsi_pclk_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state);
void rcar_mipi_dsi_pclk_disable(struct drm_bridge *bridge);
#else
static inline void rcar_mipi_dsi_pclk_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
}
static inline void rcar_mipi_dsi_pclk_disable(struct drm_bridge *bridge)
{
}
#endif /* CONFIG_DRM_RCAR_MIPI_DSI */
#endif /* __RCAR_MIPI_DSI_H__ */
......@@ -856,6 +856,8 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
rpf->mem.addr[1] = cfg->mem[1];
rpf->mem.addr[2] = cfg->mem[2];
rpf->format.flags = cfg->premult ? V4L2_PIX_FMT_FLAG_PREMUL_ALPHA : 0;
vsp1->drm->inputs[rpf_index].crop = cfg->src;
vsp1->drm->inputs[rpf_index].compose = cfg->dst;
vsp1->drm->inputs[rpf_index].zpos = cfg->zpos;
......
......@@ -51,6 +51,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
* @dst: destination rectangle on the display (integer coordinates)
* @alpha: alpha value (0: fully transparent, 255: fully opaque)
* @zpos: Z position of the plane (from 0 to number of planes minus 1)
* @premult: true for premultiplied alpha
*/
struct vsp1_du_atomic_config {
u32 pixelformat;
......@@ -60,6 +61,7 @@ struct vsp1_du_atomic_config {
struct v4l2_rect dst;
unsigned int alpha;
unsigned int zpos;
bool premult;
};
/**
......
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