linux/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Test cases for for the DRM DP MST helpers
   4 */
   5
   6#define PREFIX_STR "[drm_dp_mst_helper]"
   7
   8#include <linux/random.h>
   9
  10#include <drm/drm_dp_mst_helper.h>
  11#include <drm/drm_print.h>
  12
  13#include "../drm_dp_mst_topology_internal.h"
  14#include "test-drm_modeset_common.h"
  15
  16int igt_dp_mst_calc_pbn_mode(void *ignored)
  17{
  18        int pbn, i;
  19        const struct {
  20                int rate;
  21                int bpp;
  22                int expected;
  23                bool dsc;
  24        } test_params[] = {
  25                { 154000, 30, 689, false },
  26                { 234000, 30, 1047, false },
  27                { 297000, 24, 1063, false },
  28                { 332880, 24, 50, true },
  29                { 324540, 24, 49, true },
  30        };
  31
  32        for (i = 0; i < ARRAY_SIZE(test_params); i++) {
  33                pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
  34                                           test_params[i].bpp,
  35                                           test_params[i].dsc);
  36                FAIL(pbn != test_params[i].expected,
  37                     "Expected PBN %d for clock %d bpp %d, got %d\n",
  38                     test_params[i].expected, test_params[i].rate,
  39                     test_params[i].bpp, pbn);
  40        }
  41
  42        return 0;
  43}
  44
  45static bool
  46sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
  47                       const struct drm_dp_sideband_msg_req_body *out)
  48{
  49        const struct drm_dp_remote_i2c_read_tx *txin, *txout;
  50        int i;
  51
  52        if (in->req_type != out->req_type)
  53                return false;
  54
  55        switch (in->req_type) {
  56        /*
  57         * Compare struct members manually for request types which can't be
  58         * compared simply using memcmp(). This is because said request types
  59         * contain pointers to other allocated structs
  60         */
  61        case DP_REMOTE_I2C_READ:
  62#define IN in->u.i2c_read
  63#define OUT out->u.i2c_read
  64                if (IN.num_bytes_read != OUT.num_bytes_read ||
  65                    IN.num_transactions != OUT.num_transactions ||
  66                    IN.port_number != OUT.port_number ||
  67                    IN.read_i2c_device_id != OUT.read_i2c_device_id)
  68                        return false;
  69
  70                for (i = 0; i < IN.num_transactions; i++) {
  71                        txin = &IN.transactions[i];
  72                        txout = &OUT.transactions[i];
  73
  74                        if (txin->i2c_dev_id != txout->i2c_dev_id ||
  75                            txin->no_stop_bit != txout->no_stop_bit ||
  76                            txin->num_bytes != txout->num_bytes ||
  77                            txin->i2c_transaction_delay !=
  78                            txout->i2c_transaction_delay)
  79                                return false;
  80
  81                        if (memcmp(txin->bytes, txout->bytes,
  82                                   txin->num_bytes) != 0)
  83                                return false;
  84                }
  85                break;
  86#undef IN
  87#undef OUT
  88
  89        case DP_REMOTE_DPCD_WRITE:
  90#define IN in->u.dpcd_write
  91#define OUT out->u.dpcd_write
  92                if (IN.dpcd_address != OUT.dpcd_address ||
  93                    IN.num_bytes != OUT.num_bytes ||
  94                    IN.port_number != OUT.port_number)
  95                        return false;
  96
  97                return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
  98#undef IN
  99#undef OUT
 100
 101        case DP_REMOTE_I2C_WRITE:
 102#define IN in->u.i2c_write
 103#define OUT out->u.i2c_write
 104                if (IN.port_number != OUT.port_number ||
 105                    IN.write_i2c_device_id != OUT.write_i2c_device_id ||
 106                    IN.num_bytes != OUT.num_bytes)
 107                        return false;
 108
 109                return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
 110#undef IN
 111#undef OUT
 112
 113        default:
 114                return memcmp(in, out, sizeof(*in)) == 0;
 115        }
 116
 117        return true;
 118}
 119
 120static bool
 121sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
 122{
 123        struct drm_dp_sideband_msg_req_body out = {0};
 124        struct drm_printer p = drm_err_printer(PREFIX_STR);
 125        struct drm_dp_sideband_msg_tx txmsg;
 126        int i, ret;
 127
 128        drm_dp_encode_sideband_req(in, &txmsg);
 129        ret = drm_dp_decode_sideband_req(&txmsg, &out);
 130        if (ret < 0) {
 131                drm_printf(&p, "Failed to decode sideband request: %d\n",
 132                           ret);
 133                return false;
 134        }
 135
 136        if (!sideband_msg_req_equal(in, &out)) {
 137                drm_printf(&p, "Encode/decode failed, expected:\n");
 138                drm_dp_dump_sideband_msg_req_body(in, 1, &p);
 139                drm_printf(&p, "Got:\n");
 140                drm_dp_dump_sideband_msg_req_body(&out, 1, &p);
 141                return false;
 142        }
 143
 144        switch (in->req_type) {
 145        case DP_REMOTE_DPCD_WRITE:
 146                kfree(out.u.dpcd_write.bytes);
 147                break;
 148        case DP_REMOTE_I2C_READ:
 149                for (i = 0; i < out.u.i2c_read.num_transactions; i++)
 150                        kfree(out.u.i2c_read.transactions[i].bytes);
 151                break;
 152        case DP_REMOTE_I2C_WRITE:
 153                kfree(out.u.i2c_write.bytes);
 154                break;
 155        }
 156
 157        /* Clear everything but the req_type for the input */
 158        memset(&in->u, 0, sizeof(in->u));
 159
 160        return true;
 161}
 162
 163int igt_dp_mst_sideband_msg_req_decode(void *unused)
 164{
 165        struct drm_dp_sideband_msg_req_body in = { 0 };
 166        u8 data[] = { 0xff, 0x0, 0xdd };
 167        int i;
 168
 169#define DO_TEST() FAIL_ON(!sideband_msg_req_encode_decode(&in))
 170
 171        in.req_type = DP_ENUM_PATH_RESOURCES;
 172        in.u.port_num.port_number = 5;
 173        DO_TEST();
 174
 175        in.req_type = DP_POWER_UP_PHY;
 176        in.u.port_num.port_number = 5;
 177        DO_TEST();
 178
 179        in.req_type = DP_POWER_DOWN_PHY;
 180        in.u.port_num.port_number = 5;
 181        DO_TEST();
 182
 183        in.req_type = DP_ALLOCATE_PAYLOAD;
 184        in.u.allocate_payload.number_sdp_streams = 3;
 185        for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
 186                in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
 187        DO_TEST();
 188        in.u.allocate_payload.port_number = 0xf;
 189        DO_TEST();
 190        in.u.allocate_payload.vcpi = 0x7f;
 191        DO_TEST();
 192        in.u.allocate_payload.pbn = U16_MAX;
 193        DO_TEST();
 194
 195        in.req_type = DP_QUERY_PAYLOAD;
 196        in.u.query_payload.port_number = 0xf;
 197        DO_TEST();
 198        in.u.query_payload.vcpi = 0x7f;
 199        DO_TEST();
 200
 201        in.req_type = DP_REMOTE_DPCD_READ;
 202        in.u.dpcd_read.port_number = 0xf;
 203        DO_TEST();
 204        in.u.dpcd_read.dpcd_address = 0xfedcb;
 205        DO_TEST();
 206        in.u.dpcd_read.num_bytes = U8_MAX;
 207        DO_TEST();
 208
 209        in.req_type = DP_REMOTE_DPCD_WRITE;
 210        in.u.dpcd_write.port_number = 0xf;
 211        DO_TEST();
 212        in.u.dpcd_write.dpcd_address = 0xfedcb;
 213        DO_TEST();
 214        in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
 215        in.u.dpcd_write.bytes = data;
 216        DO_TEST();
 217
 218        in.req_type = DP_REMOTE_I2C_READ;
 219        in.u.i2c_read.port_number = 0xf;
 220        DO_TEST();
 221        in.u.i2c_read.read_i2c_device_id = 0x7f;
 222        DO_TEST();
 223        in.u.i2c_read.num_transactions = 3;
 224        in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
 225        for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
 226                in.u.i2c_read.transactions[i].bytes = data;
 227                in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
 228                in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
 229                in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
 230        }
 231        DO_TEST();
 232
 233        in.req_type = DP_REMOTE_I2C_WRITE;
 234        in.u.i2c_write.port_number = 0xf;
 235        DO_TEST();
 236        in.u.i2c_write.write_i2c_device_id = 0x7f;
 237        DO_TEST();
 238        in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
 239        in.u.i2c_write.bytes = data;
 240        DO_TEST();
 241
 242        in.req_type = DP_QUERY_STREAM_ENC_STATUS;
 243        in.u.enc_status.stream_id = 1;
 244        DO_TEST();
 245        get_random_bytes(in.u.enc_status.client_id,
 246                         sizeof(in.u.enc_status.client_id));
 247        DO_TEST();
 248        in.u.enc_status.stream_event = 3;
 249        DO_TEST();
 250        in.u.enc_status.valid_stream_event = 0;
 251        DO_TEST();
 252        in.u.enc_status.stream_behavior = 3;
 253        DO_TEST();
 254        in.u.enc_status.valid_stream_behavior = 1;
 255        DO_TEST();
 256
 257#undef DO_TEST
 258        return 0;
 259}
 260