U85 OFM dimensions are specified before transposition, while
tile bases and strides address the transposed feature map. Permute
the output endpoint before validating its tile and stride accesses.

Allow the defined U85 transpose encodings and reject the two
reserved encodings.

Signed-off-by: Rob Herring (Arm) <[email protected]>
---
v4:
 - Allow only HWC, HCW, and CHW output layouts for elementwise ops
 - Don't allow 64-bit output precision and chained output storage

v2:
 - no change
---
 drivers/accel/ethosu/ethosu_device.h |  1 +
 drivers/accel/ethosu/ethosu_gem.c    | 69 ++++++++++++++++++++++++++++++++++--
 2 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/drivers/accel/ethosu/ethosu_device.h 
b/drivers/accel/ethosu/ethosu_device.h
index d3df6720085d..c3789474fa7b 100644
--- a/drivers/accel/ethosu/ethosu_device.h
+++ b/drivers/accel/ethosu/ethosu_device.h
@@ -92,6 +92,7 @@ struct gen_pool;
 #define NPU_OP_CONV_WEIGHTS_IFM2       BIT(0)
 #define NPU_KERNEL_DILATION_X          BIT(3)
 #define NPU_KERNEL_DILATION_Y          BIT(4)
+#define NPU_OFM_TRANSPOSE_MASK         GENMASK(13, 11)
 
 #define NPU_CMD_CTRL_CMD1              BIT(14)
 
diff --git a/drivers/accel/ethosu/ethosu_gem.c 
b/drivers/accel/ethosu/ethosu_gem.c
index 04c0de8336cd..fe6bf1a2f8cb 100644
--- a/drivers/accel/ethosu/ethosu_gem.c
+++ b/drivers/accel/ethosu/ethosu_gem.c
@@ -422,6 +422,52 @@ static int feat_matrix_validate(struct ethosu_device *edev,
 
        return 0;
 }
+
+static int feat_matrix_permute(struct ethosu_device *edev,
+                              struct feat_matrix *fm, u32 *x, u32 *y,
+                              u32 *c, bool ofm)
+{
+       u32 width = *x;
+       u32 height = *y;
+       u32 depth = *c;
+       u32 transpose;
+
+       if (ethosu_is_u65(edev) || !ofm)
+               return 0;
+
+       transpose = FIELD_GET(NPU_OFM_TRANSPOSE_MASK, fm->precision);
+
+       switch (transpose) {
+       case 0: /* HWC */
+               break;
+       case 1: /* WHC */
+               *x = height;
+               *y = width;
+               break;
+       case 2: /* HCW */
+               *x = depth;
+               *c = width;
+               break;
+       case 3: /* WCH */
+               *x = depth;
+               *y = width;
+               *c = height;
+               break;
+       case 6: /* CHW */
+               *x = height;
+               *y = depth;
+               *c = width;
+               break;
+       case 7: /* CWH */
+               *y = depth;
+               *c = height;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
 static u64 feat_matrix_length(struct ethosu_device *edev,
                              struct ethosu_validated_cmdstream_info *info,
                              struct cmd_state *st, struct feat_matrix *fm,
@@ -528,6 +574,9 @@ static int feat_matrix_size(struct ethosu_device *edev,
        int ret;
 
        *max_len = 0;
+       ret = feat_matrix_permute(edev, fm, &x, &y, &c, ofm);
+       if (ret)
+               return ret;
 
        if (storage == 0) {
                ret = feat_matrix_check_location(edev, info, st, fm, type, 0, 0,
@@ -900,6 +949,11 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct 
drm_device *ddev,
                                return ret;
                        break;
                case NPU_OP_ELEMENTWISE:
+                       if (!ethosu_is_u65(edev) &&
+                           FIELD_GET(NPU_OFM_TRANSPOSE_MASK, st.ofm.precision) 
!= 0 &&
+                           FIELD_GET(NPU_OFM_TRANSPOSE_MASK, st.ofm.precision) 
!= 2 &&
+                           FIELD_GET(NPU_OFM_TRANSPOSE_MASK, st.ofm.precision) 
!= 6)
+                               return -EINVAL;
                        if (!ethosu_is_u65(edev) &&
                            !cmd_state_reg_is_set(&st, NPU_SET_IFM_BROADCAST))
                                return -EINVAL;
@@ -1000,8 +1054,19 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct 
drm_device *ddev,
                case NPU_SET_OFM_PRECISION:
                        if (((param >> 6) & 0x3) > 1)
                                return -EINVAL;
-                       if (!ethosu_is_u65(edev) && (param & GENMASK(13, 11)))
-                               return -EINVAL;
+                       if (!ethosu_is_u65(edev)) {
+                               u32 transpose = 
FIELD_GET(NPU_OFM_TRANSPOSE_MASK, param);
+
+                               switch (transpose) {
+                               case 4:
+                               case 5:
+                                       return -EINVAL;
+                               }
+                               if (transpose && ((param >> 1) & 0x3) == 3)
+                                       return -EINVAL;
+                               if ((param >> 14) == 2 && transpose)
+                                       return -EINVAL;
+                       }
                        st.ofm.precision = param;
                        break;
                case NPU_SET_OFM_REGION:

-- 
2.53.0

Reply via email to