[PATCH v2 5/6] drm/etnaviv: Add PPU flop reset

Lucas Stach l.stach at pengutronix.de
Fri Jun 20 20:22:30 UTC 2025


Am Mittwoch, dem 18.06.2025 um 22:43 +0200 schrieb Gert Wollny:
> The PPU flop reset is required on some hardware to clear the
> temporary registers. This implementation follows the code
> implemented in the public galcore kernel module code to this
> for the PPU.
> 
> v2: - Move flop reset data to etnaviv_drm_private and initialize it
>       from etnaviv_gpu_bind (Lucas)
>     - Prepare code for more chip IDs and other flop reset types
>     - do some cleanups and function name renaming
> 
> Signed-off-by: Gert Wollny <gert.wollny at collabora.com>
> ---
>  drivers/gpu/drm/etnaviv/Makefile             |   1 +
>  drivers/gpu/drm/etnaviv/etnaviv_buffer.c     |   6 +
>  drivers/gpu/drm/etnaviv/etnaviv_drv.c        |   2 +
>  drivers/gpu/drm/etnaviv/etnaviv_drv.h        |   3 +
>  drivers/gpu/drm/etnaviv/etnaviv_flop_reset.c | 205 +++++++++++++++++++
>  drivers/gpu/drm/etnaviv/etnaviv_flop_reset.h |  25 +++
>  drivers/gpu/drm/etnaviv/etnaviv_gpu.c        |   6 +
>  7 files changed, 248 insertions(+)
>  create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_flop_reset.c
>  create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_flop_reset.h
> 
> diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
> index 46e5ffad69a6..903101e8751a 100644
> --- a/drivers/gpu/drm/etnaviv/Makefile
> +++ b/drivers/gpu/drm/etnaviv/Makefile
> @@ -14,6 +14,7 @@ etnaviv-y := \
>  	etnaviv_iommu.o \
>  	etnaviv_mmu.o \
>  	etnaviv_perfmon.o \
> +	etnaviv_flop_reset.o \
>  	etnaviv_sched.o
>  
>  obj-$(CONFIG_DRM_ETNAVIV)	+= etnaviv.o
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
> index 9e007d977efe..a2da3212592f 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
> @@ -18,6 +18,8 @@
>  #include "state_3d.xml.h"
>  #include "cmdstream.xml.h"
>  
> +#include "etnaviv_flop_reset.h"
> +
>  static void etnaviv_cmd_select_pipe(struct etnaviv_gpu *gpu,
>  	struct etnaviv_cmdbuf *buffer, u8 pipe)
>  {
> @@ -100,6 +102,10 @@ u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
>  	/* initialize buffer */
>  	buffer->user_size = 0;
>  
> +	/* Queue in PPU flop reset */
> +	if (etnaviv_flop_reset_ppu_require(&gpu->identity))
> +		etnaviv_flop_reset_ppu_run(gpu);
> +
>  	CMD_WAIT(buffer, gpu->fe_waitcycles);
>  	CMD_LINK(buffer, 2,
>  		 etnaviv_cmdbuf_get_va(buffer, &gpu->mmu_context->cmdbuf_mapping)
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> index 3e91747ed339..73dc1c00c027 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
> @@ -604,6 +604,8 @@ static void etnaviv_unbind(struct device *dev)
>  
>  	xa_destroy(&priv->active_contexts);
>  
> +	kfree(priv->flop_reset_data_ppu);
> +
Missing etnaviv_cmdbuf_free().

>  	drm->dev_private = NULL;
>  	kfree(priv);
>  
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> index b3eb1662e90c..20dad16fd554 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
> @@ -48,6 +48,9 @@ struct etnaviv_drm_private {
>  	/* list of GEM objects: */
>  	struct mutex gem_lock;
>  	struct list_head gem_list;
> +
> +	/* ppu flop reset data */
> +	struct etnaviv_cmdbuf *flop_reset_data_ppu;
>  };
>  
>  int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_flop_reset.c b/drivers/gpu/drm/etnaviv/etnaviv_flop_reset.c
> new file mode 100644
> index 000000000000..c33647e96636
> --- /dev/null
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_flop_reset.c
> @@ -0,0 +1,205 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2025 Etnaviv Project
> + */
> +
> +#include "asm-generic/int-ll64.h"
> +#include "etnaviv_buffer.h"
> +#include "etnaviv_cmdbuf.h"
> +#include "state_3d.xml.h"
> +
> +#include "etnaviv_flop_reset.h"
> +
> +enum etnaviv_flop_reset_type {
> +	flop_reset_ppu = 1 << 0,
> +	flop_reset_nn = 1 << 1,
> +	flop_reset_tp = 1 << 2
> +};
> +
> +#define PPU_IMAGE_STRIDE 64
> +#define PPU_IMAGE_XSIZE 64
> +#define PPU_IMAGE_YSIZE 6
> +
> +#define PPU_FLOP_RESET_INSTR_DWORD_COUNT 16
> +
> +static void
> +etnaviv_emit_flop_reset_state_ppu(struct etnaviv_cmdbuf *cmdbuf,
> +				  u32 buffer_base,
> +				  u32 input_offset,
> +				  u32 output_offset,
> +				  u32 shader_offset,
> +				  u32 shader_size,
> +				  u32 shader_register_count)
> +{
> +	CMD_LOAD_STATE(cmdbuf, VIVS_GL_API_MODE,
> +		               VIVS_GL_API_MODE_OPENCL);
> +	CMD_SEM(cmdbuf, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
> +	CMD_STALL(cmdbuf, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
> +
> +	CMD_LOAD_STATES_START(cmdbuf, VIVS_SH_HALTI5_UNIFORMS(0), 4);
> +
> +	OUT(cmdbuf, buffer_base + input_offset);
> +	OUT(cmdbuf, PPU_IMAGE_STRIDE);
> +	OUT(cmdbuf, PPU_IMAGE_XSIZE | (PPU_IMAGE_YSIZE  << 16));
> +	OUT(cmdbuf, 0x444051f0);
> +	OUT(cmdbuf, 0xffffffff);
> +
> +	CMD_LOAD_STATES_START(cmdbuf, VIVS_SH_HALTI5_UNIFORMS(4), 4);
> +	OUT(cmdbuf, buffer_base + output_offset);
> +	OUT(cmdbuf, PPU_IMAGE_STRIDE);
> +	OUT(cmdbuf, PPU_IMAGE_XSIZE | (PPU_IMAGE_YSIZE  << 16));
> +	OUT(cmdbuf, 0x444051f0);
> +	OUT(cmdbuf, 0xffffffff);
> +
> +	CMD_LOAD_STATE(cmdbuf, VIVS_CL_CONFIG,
> +		               VIVS_CL_CONFIG_DIMENSIONS(2) |
> +		               VIVS_CL_CONFIG_VALUE_ORDER(3));
> +	CMD_LOAD_STATE(cmdbuf, VIVS_VS_ICACHE_INVALIDATE, 0x1f);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_VARYING_NUM_COMPONENTS(0), 0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_TEMP_REGISTER_CONTROL,
> +		               shader_register_count);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_SAMPLER_BASE, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_UNIFORM_BASE, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_NEWRANGE_LOW, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_NEWRANGE_HIGH,
> +		               shader_size / 16);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_INST_ADDR,
> +		               buffer_base + shader_offset);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_SH_CONFIG,
> +		               VIVS_SH_CONFIG_RTNE_ROUNDING);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_VS_ICACHE_CONTROL,
> +		               VIVS_VS_ICACHE_CONTROL_ENABLE);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_ICACHE_COUNT,
> +		               shader_size / 16 - 1);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_INPUT_COUNT, 0x1f01);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_VS_HALTI5_UNK008A0, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PA_VS_OUTPUT_COUNT, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_GL_VARYING_TOTAL_COMPONENTS, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_CONTROL_EXT, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_VS_OUTPUT_COUNT, 0x1);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_GL_HALTI5_SH_SPECIALS, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_PS_ICACHE_PREFETCH, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_CL_UNK00924, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_CL_THREAD_ALLOCATION, 0x1);
> +
> +	CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_X, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_Y, 0x0);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_Z, 0x0);
> +
> +	CMD_LOAD_STATES_START(cmdbuf, VIVS_CL_WORKGROUP_COUNT_X, 9);
> +	OUT(cmdbuf, 0xf);
> +	OUT(cmdbuf, 0x5);
> +	OUT(cmdbuf, 0xffffffff);
> +	OUT(cmdbuf, 0x0);
> +	OUT(cmdbuf, 0x0);
> +	OUT(cmdbuf, 0x3ff);
> +	OUT(cmdbuf, 0x0);
> +	OUT(cmdbuf, 0x4);
> +	OUT(cmdbuf, 0x1);
> +	OUT(cmdbuf, 0x0);
> +
> +	CMD_LOAD_STATE(cmdbuf, VIVS_CL_KICKER, 0xbadabeeb);
> +	CMD_LOAD_STATE(cmdbuf, VIVS_GL_FLUSH_CACHE,
> +		               VIVS_GL_FLUSH_CACHE_SHADER_L1 |
> +		               VIVS_GL_FLUSH_CACHE_UNK10 |
> +		               VIVS_GL_FLUSH_CACHE_UNK11);
> +}
> +
> +static void
> +etnaviv_flop_reset_ppu_fill_input(u32 *buffer, u32 size)
> +{
> +	for (int i = 0; i < size/4; ++i, ++buffer)
> +		*buffer = 0x01010101;
> +}
> +
> +static void
> +etnaviv_flop_reset_ppu_set_shader(u8 *dest)
> +{
> +	const u32 inst[PPU_FLOP_RESET_INSTR_DWORD_COUNT] = {
> +		/* img_load.u8 r1, c0, r0.xy */
> +		0x78011779, 0x39000804, 0x00A90050, 0x00000000,
> +		/* img_load.u8 r2, c0, r0.xy */
> +		0x78021779, 0x39000804, 0x00A90050, 0x00000000,
> +		/* dp2x8 r1, r1, r2, c3_512 */
> +		0xB8017145, 0x390018FC, 0x01C90140, 0x40390028,
> +		/* img_store.u8 r1, c2, r0.xy, r1 */
> +		0x380007BA, 0x39001804, 0x00A90050, 0x00390018,
> +	};
> +	memcpy(dest, inst, sizeof(inst));
> +}
> +
> +static struct etnaviv_flop_reset_entry {
> +	u16 chip_model;
> +	u16 revision;
> +	u32 flags;
> +} etnaviv_flop_reset_db [] = {
> +	{
> +		.chip_model = 0x8000,
> +		.revision = 0x6205,
> +		.flags = flop_reset_ppu
> +	},
> +};
> +
> +bool
> +etnaviv_flop_reset_ppu_require(const struct etnaviv_chip_identity *chip_id)
> +{
> +	const struct etnaviv_flop_reset_entry *e = etnaviv_flop_reset_db;
> +
> +	for (int i = 0; i < ARRAY_SIZE(etnaviv_flop_reset_db); ++i, ++e) {
> +		if (chip_id->model == e->chip_model &&
> +		    chip_id->revision == e->revision)
> +			return (e->flags & flop_reset_ppu) != 0;
> +	}
> +
> +	return false;
> +}
> +
> +static const u32 image_data_size = PPU_IMAGE_STRIDE * PPU_IMAGE_YSIZE;
> +static const u32 output_offset = ALIGN(image_data_size, 64);
> +static const u32 shader_offset = ALIGN(output_offset + image_data_size, 64);
> +static const u32 shader_size = PPU_FLOP_RESET_INSTR_DWORD_COUNT * sizeof(u32);
> +static const u32 shader_register_count = 3;
> +static const u32 buffer_size = shader_offset + shader_size;
> +
> +void
> +etnaviv_flop_reset_ppu_init(struct etnaviv_drm_private *priv)
> +{
> +	/* Get some space from the rung buffer to put the payload
                                   ^ ring
> +	   (input and output image, and shader), we keep this buffer
> +	   for the whole life time the driver is bound */

This isn't the comment style used throughout the driver.

> +	priv->flop_reset_data_ppu =
> +	  kzalloc(sizeof(*priv->flop_reset_data_ppu), GFP_KERNEL);
> +
> +	etnaviv_cmdbuf_init(priv->cmdbuf_suballoc,
> +			    priv->flop_reset_data_ppu, buffer_size);
> +
> +	void *buffer_base = priv->flop_reset_data_ppu->vaddr;
> +
> +	u32 *input_data = (u32 *)buffer_base;
> +	etnaviv_flop_reset_ppu_fill_input(input_data, image_data_size);
> +
> +	u8 *shader_data = (u8 *)buffer_base + shader_offset;
> +	etnaviv_flop_reset_ppu_set_shader(shader_data);
> +}
> +
> +void
> +etnaviv_flop_reset_ppu_run(struct etnaviv_gpu *gpu)
> +{
> +	struct etnaviv_drm_private *priv = gpu->drm->dev_private;
> +
> +	if (!priv->flop_reset_data_ppu) {
> +		pr_err("Flop reset data was not initialized, skipping\n");
> +		return;
> +	}
> +
> +	u32 buffer_base = etnaviv_cmdbuf_get_va(priv->flop_reset_data_ppu,
> +						&gpu->mmu_context->cmdbuf_mapping);
> +
> +	etnaviv_emit_flop_reset_state_ppu(&gpu->buffer,
> +					  buffer_base,
> +					  0,
> +					  output_offset,
> +					  shader_offset,
> +					  shader_size,
> +					  shader_register_count);
> +}
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_flop_reset.h b/drivers/gpu/drm/etnaviv/etnaviv_flop_reset.h
> new file mode 100644
> index 000000000000..f51cece75507
> --- /dev/null
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_flop_reset.h
> @@ -0,0 +1,25 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2025 Etnaviv Project
> + */
> +
> +
> +#ifndef etnaviv_flop_reset_h
> +#define etnaviv_flop_reset_h
> +
> +#include <linux/types.h>
> +
> +struct etnaviv_chip_identity;
> +struct etnaviv_drm_private;
> +struct etnaviv_gpu;
> +
> +bool
> +etnaviv_flop_reset_ppu_require(const struct etnaviv_chip_identity *chip_id);
> +
> +void
> +etnaviv_flop_reset_ppu_init(struct etnaviv_drm_private *priv);
> +
> +void
> +etnaviv_flop_reset_ppu_run(struct etnaviv_gpu *gpu);
> +
> +#endif
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
> index dc8a7ff3e797..0d1dc1b1d98d 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
> @@ -18,6 +18,7 @@
>  
>  #include "etnaviv_cmdbuf.h"
>  #include "etnaviv_dump.h"
> +#include "etnaviv_flop_reset.h"
>  #include "etnaviv_gpu.h"
>  #include "etnaviv_gem.h"
>  #include "etnaviv_mmu.h"
> @@ -1807,6 +1808,11 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
>  		ret = -ENXIO;
>  		goto out_sched;
>  	}
> +
> +	if (etnaviv_flop_reset_ppu_require(&gpu->identity) &&
> +	    !priv->flop_reset_data_ppu)
> +		etnaviv_flop_reset_ppu_init(priv);
> +
I don't see why you would need to do this in the bind callback. You
should be able to move this to etnaviv_gpu_init(), so you have the
needed identification data. gpu_init is also executed serially over all
GPUs in the device, so there is no problem with potential races there.

Regards,
Lucas

>  	priv->gpu[priv->num_gpus++] = gpu;
>  
>  	return 0;



More information about the etnaviv mailing list