[PATCH 1/3] drm/arcpgu: Make ARC PGU usable on simulation platforms

Daniel Vetter daniel at ffwll.ch
Mon Jun 6 14:13:44 UTC 2016


On Mon, Jun 06, 2016 at 01:56:23PM +0300, Alexey Brodkin wrote:
> From: Ruud Derwig <rderwig at synopsys.com>
> 
> Initially ARC PGU required real encoder/trnasmitter to exist.
> That was fine for real HW such as ARC SDP boards.
> 
> But on some simulaiton platroms like ARC VDK or nSIM OSCI we have model
> of the same ARC PGU and ability to output video data in a virtual LCD.
> 
> To make ARC PGU driver usable in those virtual platforms we need to istantiate
> virtual encoder instead of a real one because in the model's virtual LCD
> we're rendering whatever appears in frame-buffer memory.
> 
> Signed-off-by: Ruud Derwig <rderwig at synopsys.com>
> Signed-off-by: Alexey Brodkin <abrodkin at synopsys.com>
> ---
>  drivers/gpu/drm/arc/Makefile     |   2 +-
>  drivers/gpu/drm/arc/arcpgu.h     |   1 +
>  drivers/gpu/drm/arc/arcpgu_drv.c |  15 ++--
>  drivers/gpu/drm/arc/arcpgu_sim.c | 177 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 187 insertions(+), 8 deletions(-)
>  create mode 100644 drivers/gpu/drm/arc/arcpgu_sim.c
> 
> diff --git a/drivers/gpu/drm/arc/Makefile b/drivers/gpu/drm/arc/Makefile
> index d48fda7..73de56a 100644
> --- a/drivers/gpu/drm/arc/Makefile
> +++ b/drivers/gpu/drm/arc/Makefile
> @@ -1,2 +1,2 @@
> -arcpgu-y := arcpgu_crtc.o arcpgu_hdmi.o arcpgu_drv.o
> +arcpgu-y := arcpgu_crtc.o arcpgu_hdmi.o arcpgu_sim.o arcpgu_drv.o
>  obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
> diff --git a/drivers/gpu/drm/arc/arcpgu.h b/drivers/gpu/drm/arc/arcpgu.h
> index 86574b6..329ac75 100644
> --- a/drivers/gpu/drm/arc/arcpgu.h
> +++ b/drivers/gpu/drm/arc/arcpgu.h
> @@ -43,6 +43,7 @@ static inline u32 arc_pgu_read(struct arcpgu_drm_private *arcpgu,
>  
>  int arc_pgu_setup_crtc(struct drm_device *dev);
>  int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np);
> +int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np);
>  struct drm_fbdev_cma *arcpgu_fbdev_cma_init(struct drm_device *dev,
>  	unsigned int preferred_bpp, unsigned int num_crtc,
>  	unsigned int max_conn_count);
> diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c
> index 69b5be0..5f1f303 100644
> --- a/drivers/gpu/drm/arc/arcpgu_drv.c
> +++ b/drivers/gpu/drm/arc/arcpgu_drv.c
> @@ -149,15 +149,16 @@ static int arcpgu_load(struct drm_device *drm)
>  
>  	/* find the encoder node and initialize it */
>  	encoder_node = of_parse_phandle(drm->dev->of_node, "encoder-slave", 0);
> -	if (!encoder_node) {
> -		dev_err(drm->dev, "failed to get an encoder slave node\n");
> -		return -ENODEV;
> +	if (encoder_node) {
> +		ret = arcpgu_drm_hdmi_init(drm, encoder_node);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		ret = arcpgu_drm_sim_init(drm, 0);
> +		if (ret < 0)
> +			return ret;
>  	}
>  
> -	ret = arcpgu_drm_hdmi_init(drm, encoder_node);
> -	if (ret < 0)
> -		return ret;
> -
>  	drm_mode_config_reset(drm);
>  	drm_kms_helper_poll_init(drm);
>  
> diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c
> new file mode 100644
> index 0000000..122e069
> --- /dev/null
> +++ b/drivers/gpu/drm/arc/arcpgu_sim.c
> @@ -0,0 +1,177 @@
> +/*
> + * ARC PGU DRM driver.
> + *
> + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com)
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_encoder_slave.h>
> +#include <drm/drm_atomic_helper.h>
> +
> +#include "arcpgu.h"
> +
> +#define XRES_DEF	640
> +#define YRES_DEF	480
> +
> +#define XRES_MAX	8192
> +#define YRES_MAX	8192
> +
> +
> +struct arcpgu_drm_connector {
> +	struct drm_connector connector;
> +	struct drm_encoder_slave *encoder_slave;
> +};
> +
> +static int arcpgu_drm_connector_get_modes(struct drm_connector *connector)
> +{
> +	int count;
> +
> +	count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
> +	drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
> +	return count;
> +}
> +
> +static struct drm_encoder *
> +arcpgu_drm_connector_best_encoder(struct drm_connector *connector)
> +{
> +	struct drm_encoder_slave *slave;
> +	struct arcpgu_drm_connector *con =
> +		container_of(connector, struct arcpgu_drm_connector, connector);
> +
> +	slave = con->encoder_slave;
> +	if (slave == NULL) {
> +		dev_err(connector->dev->dev,
> +			"connector_best_encoder: cannot find slave encoder for connector\n");
> +		return NULL;
> +	}
> +
> +	return &slave->base;
> +}
> +
> +static enum drm_connector_status
> +arcpgu_drm_connector_detect(struct drm_connector *connector, bool force)
> +{
> +	return connector_status_connected;
> +}
> +
> +static void arcpgu_drm_connector_destroy(struct drm_connector *connector)
> +{
> +	drm_connector_unregister(connector);
> +	drm_connector_cleanup(connector);
> +}
> +
> +static const struct drm_connector_helper_funcs
> +arcpgu_drm_connector_helper_funcs = {
> +	.get_modes = arcpgu_drm_connector_get_modes,
> +	.best_encoder = arcpgu_drm_connector_best_encoder,
> +};
> +
> +static const struct drm_connector_funcs arcpgu_drm_connector_funcs = {
> +	.dpms = drm_helper_connector_dpms,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.detect = arcpgu_drm_connector_detect,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = arcpgu_drm_connector_destroy,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static bool sim_enc_mode_fixup(struct drm_encoder *encoder,
> +				   const struct drm_display_mode *mode,
> +				   struct drm_display_mode *adjusted_mode)
> +{
> +	return true;
> +}
> +
> +static void sim_enc_mode_set(struct drm_encoder *encoder,
> +				 struct drm_display_mode *mode,
> +				 struct drm_display_mode *adjusted_mode)
> +{
> +}
> +
> +static void sim_enc_enable(struct drm_encoder *encoder)
> +{
> +}
> +
> +static void sim_enc_disable(struct drm_encoder *encoder)
> +{
> +}

There's no more need for dummy functions like these. Please also remove
them from all the other places in your driver if you have them. And if
that means you don't have a helper_funcs table any more, you don't even
need that one.
-Daniel

> +
> +static struct drm_encoder_helper_funcs arcpgu_drm_encoder_helper_funcs = {
> +	.mode_fixup = sim_enc_mode_fixup,
> +	.mode_set   = sim_enc_mode_set,
> +	.enable     = sim_enc_enable,
> +	.disable    = sim_enc_disable,
> +};
> +
> +static struct drm_encoder_funcs arcpgu_drm_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np)
> +{
> +	struct arcpgu_drm_connector *arcpgu_connector;
> +	struct drm_encoder_slave *encoder;
> +	struct drm_connector *connector;
> +	int ret;
> +
> +	encoder = devm_kzalloc(drm->dev, sizeof(*encoder), GFP_KERNEL);
> +	if (encoder == NULL)
> +		return -ENOMEM;
> +
> +	encoder->base.possible_crtcs = 1;
> +	encoder->base.possible_clones = 0;
> +
> +	ret = drm_encoder_init(drm, &encoder->base, &arcpgu_drm_encoder_funcs,
> +			       DRM_MODE_ENCODER_VIRTUAL, NULL);
> +	if (ret)
> +		return ret;
> +
> +	drm_encoder_helper_add(&encoder->base,
> +			       &arcpgu_drm_encoder_helper_funcs);
> +
> +	arcpgu_connector = devm_kzalloc(drm->dev, sizeof(*arcpgu_connector),
> +					GFP_KERNEL);
> +	if (!arcpgu_connector) {
> +		ret = -ENOMEM;
> +		goto error_encoder_cleanup;
> +	}
> +
> +	connector = &arcpgu_connector->connector;
> +	drm_connector_helper_add(connector, &arcpgu_drm_connector_helper_funcs);
> +
> +	ret = drm_connector_init(drm, connector, &arcpgu_drm_connector_funcs,
> +			DRM_MODE_CONNECTOR_VIRTUAL);
> +	if (ret < 0) {
> +		dev_err(drm->dev, "failed to initialize drm connector\n");
> +		goto error_encoder_cleanup;
> +	}
> +
> +	ret = drm_mode_connector_attach_encoder(connector, &encoder->base);
> +	if (ret < 0) {
> +		dev_err(drm->dev, "could not attach connector to encoder\n");
> +		drm_connector_unregister(connector);
> +		goto error_connector_cleanup;
> +	}
> +
> +	arcpgu_connector->encoder_slave = encoder;
> +
> +	return 0;
> +
> +error_connector_cleanup:
> +	drm_connector_cleanup(connector);
> +
> +error_encoder_cleanup:
> +	drm_encoder_cleanup(&encoder->base);
> +	return ret;
> +}
> -- 
> 2.5.5
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the dri-devel mailing list