drm/amd/display: move dpcd logic from dc_link_dpcd to link_dpcd
authorWenjing Liu <wenjing.liu@amd.com>
Tue, 13 Dec 2022 22:26:13 +0000 (17:26 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 13 Jan 2023 19:57:51 +0000 (14:57 -0500)
[why]
Moving dpcd logic from dc_link_dpcd to link_dpcd as part of link file
restructure

Tested-by: Daniel Wheeler <Daniel.Wheeler@amd.com>
Reviewed-by: George Shen <George.Shen@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
20 files changed:
drivers/gpu/drm/amd/display/dc/Makefile
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c [deleted file]
drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c
drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/Makefile
drivers/gpu/drm/amd/display/dc/link/link_dpcd.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/link_dpcd.h [new file with mode: 0644]

index 4438f3c16636b1c753da31e8923768cdf02cb582..c5b7bcba5a3d580ac59576e6b1e49a67b945a0e6 100644 (file)
@@ -66,7 +66,7 @@ include $(AMD_DC)
 
 DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
 dc_surface.o dc_link_dp.o dc_debug.o dc_stream.o \
-dc_link_enc_cfg.o dc_link_dpia.o dc_link_dpcd.o
+dc_link_enc_cfg.o dc_link_dpia.o
 
 DISPLAY_CORE += dc_vm_helper.o
 
index b5572f5202ca5ffcbff2d97f86fbc8545a099f53..b20dde4b05d54d32c6806e61a6bb67d2d240a863 100644 (file)
@@ -51,7 +51,7 @@
 #include "dmub/dmub_srv.h"
 #include "inc/hw/panel_cntl.h"
 #include "inc/link_enc_cfg.h"
-#include "inc/link_dpcd.h"
+#include "link/link_dpcd.h"
 #include "link/link_dp_trace.h"
 #include "link/link_hpd.h"
 
index 815652da41265c516637433401b59167a641b2cc..9f2f10a957f6ed454fca06f8f78f5a4c5ecc826a 100644 (file)
@@ -50,7 +50,7 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
        link->ctx->logger
 #define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
 
-#include "link_dpcd.h"
+#include "link/link_dpcd.h"
 
 #ifndef MAX
 #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c
deleted file mode 100644 (file)
index af110bf..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2021 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#include <inc/core_status.h>
-#include <dc_link.h>
-#include <inc/link_hwss.h>
-#include <inc/link_dpcd.h>
-#include <dc_dp_types.h>
-#include <drm/display/drm_dp_helper.h>
-#include "dm_helpers.h"
-
-#define END_ADDRESS(start, size) (start + size - 1)
-#define ADDRESS_RANGE_SIZE(start, end) (end - start + 1)
-struct dpcd_address_range {
-       uint32_t start;
-       uint32_t end;
-};
-
-static enum dc_status internal_link_read_dpcd(
-       struct dc_link *link,
-       uint32_t address,
-       uint8_t *data,
-       uint32_t size)
-{
-       if (!link->aux_access_disabled &&
-                       !dm_helpers_dp_read_dpcd(link->ctx,
-                       link, address, data, size)) {
-               return DC_ERROR_UNEXPECTED;
-       }
-
-       return DC_OK;
-}
-
-static enum dc_status internal_link_write_dpcd(
-       struct dc_link *link,
-       uint32_t address,
-       const uint8_t *data,
-       uint32_t size)
-{
-       if (!link->aux_access_disabled &&
-                       !dm_helpers_dp_write_dpcd(link->ctx,
-                       link, address, data, size)) {
-               return DC_ERROR_UNEXPECTED;
-       }
-
-       return DC_OK;
-}
-
-/*
- * Partition the entire DPCD address space
- * XXX: This partitioning must cover the entire DPCD address space,
- * and must contain no gaps or overlapping address ranges.
- */
-static const struct dpcd_address_range mandatory_dpcd_partitions[] = {
-       { 0, DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1) - 1},
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 },
-       /*
-        * The FEC registers are contiguous
-        */
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR8), DP_LTTPR_MAX_ADD },
-       /* all remaining DPCD addresses */
-       { DP_LTTPR_MAX_ADD + 1, DP_DPCD_MAX_ADD } };
-
-static inline bool do_addresses_intersect_with_range(
-               const struct dpcd_address_range *range,
-               const uint32_t start_address,
-               const uint32_t end_address)
-{
-       return start_address <= range->end && end_address >= range->start;
-}
-
-static uint32_t dpcd_get_next_partition_size(const uint32_t address, const uint32_t size)
-{
-       const uint32_t end_address = END_ADDRESS(address, size);
-       uint32_t partition_iterator = 0;
-
-       /*
-        * find current partition
-        * this loop spins forever if partition map above is not surjective
-        */
-       while (!do_addresses_intersect_with_range(&mandatory_dpcd_partitions[partition_iterator],
-                               address, end_address))
-               partition_iterator++;
-       if (end_address < mandatory_dpcd_partitions[partition_iterator].end)
-               return size;
-       return ADDRESS_RANGE_SIZE(address, mandatory_dpcd_partitions[partition_iterator].end);
-}
-
-/*
- * Ranges of DPCD addresses that must be read in a single transaction
- * XXX: Do not allow any two address ranges in this array to overlap
- */
-static const struct dpcd_address_range mandatory_dpcd_blocks[] = {
-       { DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT }};
-
-/*
- * extend addresses to read all mandatory blocks together
- */
-static void dpcd_extend_address_range(
-               const uint32_t in_address,
-               uint8_t * const in_data,
-               const uint32_t in_size,
-               uint32_t *out_address,
-               uint8_t **out_data,
-               uint32_t *out_size)
-{
-       const uint32_t end_address = END_ADDRESS(in_address, in_size);
-       const struct dpcd_address_range *addr_range;
-       struct dpcd_address_range new_addr_range;
-       uint32_t i;
-
-       new_addr_range.start = in_address;
-       new_addr_range.end = end_address;
-       for (i = 0; i < ARRAY_SIZE(mandatory_dpcd_blocks); i++) {
-               addr_range = &mandatory_dpcd_blocks[i];
-               if (addr_range->start <= in_address && addr_range->end >= in_address)
-                       new_addr_range.start = addr_range->start;
-
-               if (addr_range->start <= end_address && addr_range->end >= end_address)
-                       new_addr_range.end = addr_range->end;
-       }
-       *out_address = in_address;
-       *out_size = in_size;
-       *out_data = in_data;
-       if (new_addr_range.start != in_address || new_addr_range.end != end_address) {
-               *out_address = new_addr_range.start;
-               *out_size = ADDRESS_RANGE_SIZE(new_addr_range.start, new_addr_range.end);
-               *out_data = kzalloc(*out_size * sizeof(**out_data), GFP_KERNEL);
-       }
-}
-
-/*
- * Reduce the AUX reply down to the values the caller requested
- */
-static void dpcd_reduce_address_range(
-               const uint32_t extended_address,
-               uint8_t * const extended_data,
-               const uint32_t extended_size,
-               const uint32_t reduced_address,
-               uint8_t * const reduced_data,
-               const uint32_t reduced_size)
-{
-       const uint32_t offset = reduced_address - extended_address;
-
-       /*
-        * If the address is same, address was not extended.
-        * So we do not need to free any memory.
-        * The data is in original buffer(reduced_data).
-        */
-       if (extended_data == reduced_data)
-               return;
-
-       memcpy(&extended_data[offset], reduced_data, reduced_size);
-       kfree(extended_data);
-}
-
-enum dc_status core_link_read_dpcd(
-       struct dc_link *link,
-       uint32_t address,
-       uint8_t *data,
-       uint32_t size)
-{
-       uint32_t extended_address;
-       uint32_t partitioned_address;
-       uint8_t *extended_data;
-       uint32_t extended_size;
-       /* size of the remaining partitioned address space */
-       uint32_t size_left_to_read;
-       enum dc_status status;
-       /* size of the next partition to be read from */
-       uint32_t partition_size;
-       uint32_t data_index = 0;
-
-       dpcd_extend_address_range(address, data, size, &extended_address, &extended_data, &extended_size);
-       partitioned_address = extended_address;
-       size_left_to_read = extended_size;
-       while (size_left_to_read) {
-               partition_size = dpcd_get_next_partition_size(partitioned_address, size_left_to_read);
-               status = internal_link_read_dpcd(link, partitioned_address, &extended_data[data_index], partition_size);
-               if (status != DC_OK)
-                       break;
-               partitioned_address += partition_size;
-               data_index += partition_size;
-               size_left_to_read -= partition_size;
-       }
-       dpcd_reduce_address_range(extended_address, extended_data, extended_size, address, data, size);
-       return status;
-}
-
-enum dc_status core_link_write_dpcd(
-       struct dc_link *link,
-       uint32_t address,
-       const uint8_t *data,
-       uint32_t size)
-{
-       uint32_t partition_size;
-       uint32_t data_index = 0;
-       enum dc_status status;
-
-       while (size) {
-               partition_size = dpcd_get_next_partition_size(address, size);
-               status = internal_link_write_dpcd(link, address, &data[data_index], partition_size);
-               if (status != DC_OK)
-                       break;
-               address += partition_size;
-               data_index += partition_size;
-               size -= partition_size;
-       }
-       return status;
-}
index d130d58ac08e7007201d446f71353e2b08e0cb9e..e1db05966d83e7782aa9afee76090ae5f5c73946 100644 (file)
@@ -33,7 +33,7 @@
 #include "link_hwss.h"
 #include "dm_helpers.h"
 #include "dmub/inc/dmub_cmd.h"
-#include "inc/link_dpcd.h"
+#include "link/link_dpcd.h"
 #include "dc_dmub_srv.h"
 
 #define DC_LOGGER \
index 358431f0d98ad05547c44434c2133d8fb54afb47..833a1c37cbe4959f12e535e8b27f4fec19e92b39 100644 (file)
@@ -55,7 +55,6 @@
 #include "audio.h"
 #include "reg_helper.h"
 #include "panel_cntl.h"
-#include "inc/link_dpcd.h"
 #include "dpcd_defs.h"
 /* include DCE11 register header files */
 #include "dce/dce_11_0_d.h"
index fe2023f18b7d0b1b9f487e14dea0541ef705caf2..c1d4e66b413f11c9b56d1071431da5e27dc6eaca 100644 (file)
@@ -57,7 +57,6 @@
 #include "dc_trace.h"
 #include "dce/dmub_outbox.h"
 #include "inc/dc_link_dp.h"
-#include "inc/link_dpcd.h"
 
 #define DC_LOGGER_INIT(logger)
 
index 484e7cdf00b8c875844251cade3ff35ed100fa44..1527c3b4fb19777a31379f43f93dec8bc27107a8 100644 (file)
@@ -28,7 +28,7 @@
 #include "dcn10_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
-#include "inc/link_dpcd.h"
+#include "dc_link_dp.h"
 #include "dpcd_defs.h"
 #include "dcn30/dcn30_afmt.h"
 
index 20c85ef2a957f0d19d1deb962f69ee6847c63e41..c2066a5057e815ef133303561879264cd6a7a7cb 100644 (file)
@@ -52,7 +52,6 @@
 #include "dc_dmub_srv.h"
 #include "dce/dmub_hw_lock_mgr.h"
 #include "hw_sequencer.h"
-#include "inc/link_dpcd.h"
 #include "dpcd_defs.h"
 #include "inc/link_enc_cfg.h"
 #include "link_hwss.h"
index b40489e678f904e21b46aa1b56afcce341e251de..cacf3f5298b099448ecb76b78db957ad790a8352 100644 (file)
@@ -29,7 +29,7 @@
 #include "dcn20_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
-#include "inc/link_dpcd.h"
+#include "dc_link_dp.h"
 #include "dpcd_defs.h"
 
 #define DC_LOGGER \
index 8c504571126499467c23c0bd98f972490fee75a0..7360b3ce4283c64f23f131e43b78661b70165d7d 100644 (file)
@@ -51,7 +51,6 @@
 #include "../dcn20/dcn20_hwseq.h"
 #include "dcn30_resource.h"
 #include "inc/dc_link_dp.h"
-#include "inc/link_dpcd.h"
 
 
 
index 165c920ca77669ec2cd94a2b1dddcbde440fcd35..3b354f0db2a56ce9b067edd8e8a9882423e92f1b 100644 (file)
@@ -46,7 +46,6 @@
 #include "dpcd_defs.h"
 #include "dce/dmub_outbox.h"
 #include "dc_link_dp.h"
-#include "inc/link_dpcd.h"
 #include "dcn10/dcn10_hw_sequencer.h"
 #include "inc/link_enc_cfg.h"
 #include "dcn30/dcn30_vpg.h"
index 0926db018338398a79bbe1478798ecc245a7c921..9c9875368beaca0a885e9ed64b9556fd57113830 100644 (file)
@@ -30,7 +30,7 @@
 #include "dcn314_dio_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
-#include "inc/link_dpcd.h"
+#include "dc_link_dp.h"
 #include "dpcd_defs.h"
 
 #define DC_LOGGER \
index a0741794db62aa77af7a3be1c8c75485e149a0e7..edc2c08939b074e132d6f9658e128ad685646605 100644 (file)
@@ -48,7 +48,6 @@
 #include "dce/dmub_outbox.h"
 #include "dc_link_dp.h"
 #include "inc/dc_link_dp.h"
-#include "inc/link_dpcd.h"
 #include "dcn10/dcn10_hw_sequencer.h"
 #include "inc/link_enc_cfg.h"
 #include "dcn30/dcn30_vpg.h"
index 7d09c62a405aea332eb6b12ab38344ce48615e1b..f01968f6d18263bb9c024538f6b21f3e3551d252 100644 (file)
@@ -29,7 +29,7 @@
 #include "dcn32_dio_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
-#include "inc/link_dpcd.h"
+#include "dc_link_dp.h"
 #include "dpcd_defs.h"
 
 #define DC_LOGGER \
index 6c4b47f90d499e5f35c05637a93cbec5fcdf7803..906a43e85f6dbadfef123f0df1c0f61f36ad6e9a 100644 (file)
@@ -32,7 +32,7 @@
 #include "core_types.h"
 #include "link.h"
 #include "link_hwss.h"
-#include "inc/link_dpcd.h"
+#include "link/link_dpcd.h"
 
 #define DC_LOGGER \
        link->ctx->logger
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h b/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h
deleted file mode 100644 (file)
index d561f86..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2021 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __LINK_DPCD_H__
-#define __LINK_DPCD_H__
-#include <inc/core_status.h>
-#include <dc_link.h>
-#include <dc_link_dp.h>
-
-enum dc_status core_link_read_dpcd(
-               struct dc_link *link,
-               uint32_t address,
-               uint8_t *data,
-               uint32_t size);
-
-enum dc_status core_link_write_dpcd(
-               struct dc_link *link,
-               uint32_t address,
-               const uint8_t *data,
-               uint32_t size);
-#endif
index d1b1bb3c53525e2638322e733dfdcf016a45716e..b905c53e738bd4f1681d058467e19c87ab23488a 100644 (file)
@@ -24,7 +24,7 @@
 # PHY, HPD, DDC and etc).
 
 LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o \
-link_hpd.o link_ddc.o
+link_hpd.o link_ddc.o link_dpcd.o
 
 AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/,$(LINK))
 
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/link_dpcd.c
new file mode 100644 (file)
index 0000000..5c9a302
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ * This file implements basic dpcd read/write functionality. It also does basic
+ * dpcd range check to ensure that every dpcd request is compliant with specs
+ * range requirements.
+ */
+
+#include "link_dpcd.h"
+#include <drm/display/drm_dp_helper.h>
+#include "dm_helpers.h"
+
+#define END_ADDRESS(start, size) (start + size - 1)
+#define ADDRESS_RANGE_SIZE(start, end) (end - start + 1)
+struct dpcd_address_range {
+       uint32_t start;
+       uint32_t end;
+};
+
+static enum dc_status internal_link_read_dpcd(
+       struct dc_link *link,
+       uint32_t address,
+       uint8_t *data,
+       uint32_t size)
+{
+       if (!link->aux_access_disabled &&
+                       !dm_helpers_dp_read_dpcd(link->ctx,
+                       link, address, data, size)) {
+               return DC_ERROR_UNEXPECTED;
+       }
+
+       return DC_OK;
+}
+
+static enum dc_status internal_link_write_dpcd(
+       struct dc_link *link,
+       uint32_t address,
+       const uint8_t *data,
+       uint32_t size)
+{
+       if (!link->aux_access_disabled &&
+                       !dm_helpers_dp_write_dpcd(link->ctx,
+                       link, address, data, size)) {
+               return DC_ERROR_UNEXPECTED;
+       }
+
+       return DC_OK;
+}
+
+/*
+ * Partition the entire DPCD address space
+ * XXX: This partitioning must cover the entire DPCD address space,
+ * and must contain no gaps or overlapping address ranges.
+ */
+static const struct dpcd_address_range mandatory_dpcd_partitions[] = {
+       { 0, DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1) - 1},
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 },
+       /*
+        * The FEC registers are contiguous
+        */
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR8), DP_LTTPR_MAX_ADD },
+       /* all remaining DPCD addresses */
+       { DP_LTTPR_MAX_ADD + 1, DP_DPCD_MAX_ADD } };
+
+static inline bool do_addresses_intersect_with_range(
+               const struct dpcd_address_range *range,
+               const uint32_t start_address,
+               const uint32_t end_address)
+{
+       return start_address <= range->end && end_address >= range->start;
+}
+
+static uint32_t dpcd_get_next_partition_size(const uint32_t address, const uint32_t size)
+{
+       const uint32_t end_address = END_ADDRESS(address, size);
+       uint32_t partition_iterator = 0;
+
+       /*
+        * find current partition
+        * this loop spins forever if partition map above is not surjective
+        */
+       while (!do_addresses_intersect_with_range(&mandatory_dpcd_partitions[partition_iterator],
+                               address, end_address))
+               partition_iterator++;
+       if (end_address < mandatory_dpcd_partitions[partition_iterator].end)
+               return size;
+       return ADDRESS_RANGE_SIZE(address, mandatory_dpcd_partitions[partition_iterator].end);
+}
+
+/*
+ * Ranges of DPCD addresses that must be read in a single transaction
+ * XXX: Do not allow any two address ranges in this array to overlap
+ */
+static const struct dpcd_address_range mandatory_dpcd_blocks[] = {
+       { DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT }};
+
+/*
+ * extend addresses to read all mandatory blocks together
+ */
+static void dpcd_extend_address_range(
+               const uint32_t in_address,
+               uint8_t * const in_data,
+               const uint32_t in_size,
+               uint32_t *out_address,
+               uint8_t **out_data,
+               uint32_t *out_size)
+{
+       const uint32_t end_address = END_ADDRESS(in_address, in_size);
+       const struct dpcd_address_range *addr_range;
+       struct dpcd_address_range new_addr_range;
+       uint32_t i;
+
+       new_addr_range.start = in_address;
+       new_addr_range.end = end_address;
+       for (i = 0; i < ARRAY_SIZE(mandatory_dpcd_blocks); i++) {
+               addr_range = &mandatory_dpcd_blocks[i];
+               if (addr_range->start <= in_address && addr_range->end >= in_address)
+                       new_addr_range.start = addr_range->start;
+
+               if (addr_range->start <= end_address && addr_range->end >= end_address)
+                       new_addr_range.end = addr_range->end;
+       }
+       *out_address = in_address;
+       *out_size = in_size;
+       *out_data = in_data;
+       if (new_addr_range.start != in_address || new_addr_range.end != end_address) {
+               *out_address = new_addr_range.start;
+               *out_size = ADDRESS_RANGE_SIZE(new_addr_range.start, new_addr_range.end);
+               *out_data = kzalloc(*out_size * sizeof(**out_data), GFP_KERNEL);
+       }
+}
+
+/*
+ * Reduce the AUX reply down to the values the caller requested
+ */
+static void dpcd_reduce_address_range(
+               const uint32_t extended_address,
+               uint8_t * const extended_data,
+               const uint32_t extended_size,
+               const uint32_t reduced_address,
+               uint8_t * const reduced_data,
+               const uint32_t reduced_size)
+{
+       const uint32_t offset = reduced_address - extended_address;
+
+       /*
+        * If the address is same, address was not extended.
+        * So we do not need to free any memory.
+        * The data is in original buffer(reduced_data).
+        */
+       if (extended_data == reduced_data)
+               return;
+
+       memcpy(&extended_data[offset], reduced_data, reduced_size);
+       kfree(extended_data);
+}
+
+enum dc_status core_link_read_dpcd(
+       struct dc_link *link,
+       uint32_t address,
+       uint8_t *data,
+       uint32_t size)
+{
+       uint32_t extended_address;
+       uint32_t partitioned_address;
+       uint8_t *extended_data;
+       uint32_t extended_size;
+       /* size of the remaining partitioned address space */
+       uint32_t size_left_to_read;
+       enum dc_status status;
+       /* size of the next partition to be read from */
+       uint32_t partition_size;
+       uint32_t data_index = 0;
+
+       dpcd_extend_address_range(address, data, size, &extended_address, &extended_data, &extended_size);
+       partitioned_address = extended_address;
+       size_left_to_read = extended_size;
+       while (size_left_to_read) {
+               partition_size = dpcd_get_next_partition_size(partitioned_address, size_left_to_read);
+               status = internal_link_read_dpcd(link, partitioned_address, &extended_data[data_index], partition_size);
+               if (status != DC_OK)
+                       break;
+               partitioned_address += partition_size;
+               data_index += partition_size;
+               size_left_to_read -= partition_size;
+       }
+       dpcd_reduce_address_range(extended_address, extended_data, extended_size, address, data, size);
+       return status;
+}
+
+enum dc_status core_link_write_dpcd(
+       struct dc_link *link,
+       uint32_t address,
+       const uint8_t *data,
+       uint32_t size)
+{
+       uint32_t partition_size;
+       uint32_t data_index = 0;
+       enum dc_status status;
+
+       while (size) {
+               partition_size = dpcd_get_next_partition_size(address, size);
+               status = internal_link_write_dpcd(link, address, &data[data_index], partition_size);
+               if (status != DC_OK)
+                       break;
+               address += partition_size;
+               data_index += partition_size;
+               size -= partition_size;
+       }
+       return status;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpcd.h b/drivers/gpu/drm/amd/display/dc/link/link_dpcd.h
new file mode 100644 (file)
index 0000000..27b08cd
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __LINK_DPCD_H__
+#define __LINK_DPCD_H__
+#include "link.h"
+
+enum dc_status core_link_read_dpcd(
+               struct dc_link *link,
+               uint32_t address,
+               uint8_t *data,
+               uint32_t size);
+
+enum dc_status core_link_write_dpcd(
+               struct dc_link *link,
+               uint32_t address,
+               const uint8_t *data,
+               uint32_t size);
+#endif