From d55a574898c7e1164998972a66020698ff00fdfa Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 14 Apr 2026 09:39:39 -0500 Subject: [PATCH] ethosu: Support element wise op with constant IFM buffer Element wise operations can have a constant data buffer. Re-order things a bit to group all the IFM2 setup together. Signed-off-by: Rob Herring (Arm) Part-of: --- src/gallium/drivers/ethosu/ethosu_cmd.c | 2 +- src/gallium/drivers/ethosu/ethosu_lower.c | 34 +++++++++++++++-------- src/gallium/drivers/ethosu/ethosu_ml.h | 1 + 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/gallium/drivers/ethosu/ethosu_cmd.c b/src/gallium/drivers/ethosu/ethosu_cmd.c index c185e14b0bc..6cf1eaddde2 100644 --- a/src/gallium/drivers/ethosu/ethosu_cmd.c +++ b/src/gallium/drivers/ethosu/ethosu_cmd.c @@ -551,7 +551,7 @@ emit_ifm2(struct ethosu_subgraph *subgraph, struct ethosu_operation *operation, EMIT1(NPU_SET_OP_SCALAR, 0, operation->ifm2.scalar); } } else { - EMIT0(NPU_SET_IFM2_REGION, IO_REGION); + EMIT0(NPU_SET_IFM2_REGION, operation->ifm2.region); emit_addresses(subgraph, &operation->ifm2, NPU_SET_IFM2_BASE0, NPU_SET_IFM2_BASE1, NPU_SET_IFM2_BASE2, NPU_SET_IFM2_BASE3); emit_tiles(subgraph, &operation->ifm2, NPU_SET_IFM2_HEIGHT0_M1, NPU_SET_IFM2_HEIGHT1_M1, NPU_SET_IFM2_WIDTH0_M1); emit_strides(subgraph, &operation->ifm2, NPU_SET_IFM2_STRIDE_C, NPU_SET_IFM2_STRIDE_Y, NPU_SET_IFM2_STRIDE_X); diff --git a/src/gallium/drivers/ethosu/ethosu_lower.c b/src/gallium/drivers/ethosu/ethosu_lower.c index f79ba0bbbe1..16c793a1564 100644 --- a/src/gallium/drivers/ethosu/ethosu_lower.c +++ b/src/gallium/drivers/ethosu/ethosu_lower.c @@ -390,22 +390,34 @@ ethosu_lower_eltwise(struct ethosu_subgraph *subgraph, set_feature_map(subgraph, poperation->input_tensors[ifm2_idx], &operation->ifm2); - if (poperation->input_tensors[ifm2_idx]->data && - operation->ifm2.shape.width == 1 && - operation->ifm2.shape.height == 1 && - operation->ifm2.shape.depth == 1) { - operation->ifm2.scalar = *poperation->input_tensors[ifm2_idx]->data; + if (poperation->input_tensors[ifm2_idx]->data) { + if (operation->ifm2.shape.width == 1 && + operation->ifm2.shape.height == 1 && + operation->ifm2.shape.depth == 1) + operation->ifm2.scalar = *poperation->input_tensors[ifm2_idx]->data; + else { + size_t size = operation->ifm2.shape.height * operation->ifm2.shape.width * + operation->ifm2.shape.depth * poperation->input_tensors[ifm2_idx]->type_size; + + operation->ifm2.region = COEFS_REGION; + operation->ifm2.tiles.addresses[0] = subgraph->coefs_used; + subgraph->coefs_used += size; + subgraph->coefs = realloc(subgraph->coefs, subgraph->coefs_used); + memcpy(subgraph->coefs + operation->ifm2.tiles.addresses[0], + poperation->input_tensors[ifm2_idx]->data, size); + } + } else { + operation->ifm2.region = IO_REGION; + operation->ifm2.tiles.addresses[0] = ethosu_allocate_feature_map(subgraph, operation->ifm2.tensor); } - if (poperation->add.relu) - operation->eltwise.activation_min = operation->ofm.zero_point; - - allocate_feature_maps(subgraph, operation); - - operation->ifm2.tiles.addresses[0] = ethosu_allocate_feature_map(subgraph, operation->ifm2.tensor); operation->ifm2.tiles.height_0 = operation->ifm2.shape.height; operation->ifm2.tiles.height_1 = operation->ifm2.shape.height; operation->ifm2.tiles.width_0 = operation->ifm2.shape.width; + if (poperation->add.relu) + operation->eltwise.activation_min = operation->ofm.zero_point; + + allocate_feature_maps(subgraph, operation); ethosu_sched_operation(subgraph, operation); } diff --git a/src/gallium/drivers/ethosu/ethosu_ml.h b/src/gallium/drivers/ethosu/ethosu_ml.h index 4f7d31ec6fb..4d57d2c924a 100644 --- a/src/gallium/drivers/ethosu/ethosu_ml.h +++ b/src/gallium/drivers/ethosu/ethosu_ml.h @@ -84,6 +84,7 @@ struct ethosu_feature_map { unsigned zero_point; float scale; uint16_t scalar; + uint8_t region; }; struct ethosu_kernel {