LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/display/amdgpu_dm - amdgpu_dm_helpers.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 394 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 36 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 Advanced Micro Devices, Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  * Authors: AMD
      23             :  *
      24             :  */
      25             : 
      26             : #include <linux/string.h>
      27             : #include <linux/acpi.h>
      28             : #include <linux/i2c.h>
      29             : 
      30             : #include <drm/drm_probe_helper.h>
      31             : #include <drm/amdgpu_drm.h>
      32             : #include <drm/drm_edid.h>
      33             : 
      34             : #include "dm_services.h"
      35             : #include "amdgpu.h"
      36             : #include "dc.h"
      37             : #include "amdgpu_dm.h"
      38             : #include "amdgpu_dm_irq.h"
      39             : #include "amdgpu_dm_mst_types.h"
      40             : 
      41             : #include "dm_helpers.h"
      42             : #include "ddc_service_types.h"
      43             : 
      44             : struct monitor_patch_info {
      45             :         unsigned int manufacturer_id;
      46             :         unsigned int product_id;
      47             :         void (*patch_func)(struct dc_edid_caps *edid_caps, unsigned int param);
      48             :         unsigned int patch_param;
      49             : };
      50             : static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param);
      51             : 
      52             : static const struct monitor_patch_info monitor_patch_table[] = {
      53             : {0x6D1E, 0x5BBF, set_max_dsc_bpp_limit, 15},
      54             : {0x6D1E, 0x5B9A, set_max_dsc_bpp_limit, 15},
      55             : };
      56             : 
      57           0 : static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param)
      58             : {
      59           0 :         if (edid_caps)
      60           0 :                 edid_caps->panel_patch.max_dsc_target_bpp_limit = param;
      61           0 : }
      62             : 
      63           0 : static int amdgpu_dm_patch_edid_caps(struct dc_edid_caps *edid_caps)
      64             : {
      65           0 :         int i, ret = 0;
      66             : 
      67           0 :         for (i = 0; i < ARRAY_SIZE(monitor_patch_table); i++)
      68           0 :                 if ((edid_caps->manufacturer_id == monitor_patch_table[i].manufacturer_id)
      69           0 :                         &&  (edid_caps->product_id == monitor_patch_table[i].product_id)) {
      70           0 :                         monitor_patch_table[i].patch_func(edid_caps, monitor_patch_table[i].patch_param);
      71           0 :                         ret++;
      72             :                 }
      73             : 
      74           0 :         return ret;
      75             : }
      76             : 
      77             : /* dm_helpers_parse_edid_caps
      78             :  *
      79             :  * Parse edid caps
      80             :  *
      81             :  * @edid:       [in] pointer to edid
      82             :  *  edid_caps:  [in] pointer to edid caps
      83             :  * @return
      84             :  *      void
      85             :  * */
      86           0 : enum dc_edid_status dm_helpers_parse_edid_caps(
      87             :                 struct dc_link *link,
      88             :                 const struct dc_edid *edid,
      89             :                 struct dc_edid_caps *edid_caps)
      90             : {
      91           0 :         struct amdgpu_dm_connector *aconnector = link->priv;
      92           0 :         struct drm_connector *connector = &aconnector->base;
      93           0 :         struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
      94             :         struct cea_sad *sads;
      95           0 :         int sad_count = -1;
      96           0 :         int sadb_count = -1;
      97           0 :         int i = 0;
      98           0 :         uint8_t *sadb = NULL;
      99             : 
     100           0 :         enum dc_edid_status result = EDID_OK;
     101             : 
     102           0 :         if (!edid_caps || !edid)
     103             :                 return EDID_BAD_INPUT;
     104             : 
     105           0 :         if (!drm_edid_is_valid(edid_buf))
     106           0 :                 result = EDID_BAD_CHECKSUM;
     107             : 
     108           0 :         edid_caps->manufacturer_id = (uint16_t) edid_buf->mfg_id[0] |
     109           0 :                                         ((uint16_t) edid_buf->mfg_id[1])<<8;
     110           0 :         edid_caps->product_id = (uint16_t) edid_buf->prod_code[0] |
     111           0 :                                         ((uint16_t) edid_buf->prod_code[1])<<8;
     112           0 :         edid_caps->serial_number = edid_buf->serial;
     113           0 :         edid_caps->manufacture_week = edid_buf->mfg_week;
     114           0 :         edid_caps->manufacture_year = edid_buf->mfg_year;
     115             : 
     116           0 :         drm_edid_get_monitor_name(edid_buf,
     117           0 :                                   edid_caps->display_name,
     118             :                                   AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
     119             : 
     120           0 :         edid_caps->edid_hdmi = connector->display_info.is_hdmi;
     121             : 
     122           0 :         sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
     123           0 :         if (sad_count <= 0)
     124             :                 return result;
     125             : 
     126           0 :         edid_caps->audio_mode_count = sad_count < DC_MAX_AUDIO_DESC_COUNT ? sad_count : DC_MAX_AUDIO_DESC_COUNT;
     127           0 :         for (i = 0; i < edid_caps->audio_mode_count; ++i) {
     128           0 :                 struct cea_sad *sad = &sads[i];
     129             : 
     130           0 :                 edid_caps->audio_modes[i].format_code = sad->format;
     131           0 :                 edid_caps->audio_modes[i].channel_count = sad->channels + 1;
     132           0 :                 edid_caps->audio_modes[i].sample_rate = sad->freq;
     133           0 :                 edid_caps->audio_modes[i].sample_size = sad->byte2;
     134             :         }
     135             : 
     136           0 :         sadb_count = drm_edid_to_speaker_allocation((struct edid *) edid->raw_edid, &sadb);
     137             : 
     138           0 :         if (sadb_count < 0) {
     139           0 :                 DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sadb_count);
     140           0 :                 sadb_count = 0;
     141             :         }
     142             : 
     143           0 :         if (sadb_count)
     144           0 :                 edid_caps->speaker_flags = sadb[0];
     145             :         else
     146           0 :                 edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
     147             : 
     148           0 :         kfree(sads);
     149           0 :         kfree(sadb);
     150             : 
     151           0 :         amdgpu_dm_patch_edid_caps(edid_caps);
     152             : 
     153           0 :         return result;
     154             : }
     155             : 
     156           0 : static void get_payload_table(
     157             :                 struct amdgpu_dm_connector *aconnector,
     158             :                 struct dp_mst_stream_allocation_table *proposed_table)
     159             : {
     160             :         int i;
     161           0 :         struct drm_dp_mst_topology_mgr *mst_mgr =
     162           0 :                         &aconnector->mst_port->mst_mgr;
     163             : 
     164           0 :         mutex_lock(&mst_mgr->payload_lock);
     165             : 
     166           0 :         proposed_table->stream_count = 0;
     167             : 
     168             :         /* number of active streams */
     169           0 :         for (i = 0; i < mst_mgr->max_payloads; i++) {
     170           0 :                 if (mst_mgr->payloads[i].num_slots == 0)
     171             :                         break; /* end of vcp_id table */
     172             : 
     173           0 :                 ASSERT(mst_mgr->payloads[i].payload_state !=
     174             :                                 DP_PAYLOAD_DELETE_LOCAL);
     175             : 
     176           0 :                 if (mst_mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL ||
     177             :                         mst_mgr->payloads[i].payload_state ==
     178             :                                         DP_PAYLOAD_REMOTE) {
     179             : 
     180           0 :                         struct dp_mst_stream_allocation *sa =
     181             :                                         &proposed_table->stream_allocations[
     182           0 :                                                 proposed_table->stream_count];
     183             : 
     184           0 :                         sa->slot_count = mst_mgr->payloads[i].num_slots;
     185           0 :                         sa->vcp_id = mst_mgr->proposed_vcpis[i]->vcpi;
     186           0 :                         proposed_table->stream_count++;
     187             :                 }
     188             :         }
     189             : 
     190           0 :         mutex_unlock(&mst_mgr->payload_lock);
     191           0 : }
     192             : 
     193           0 : void dm_helpers_dp_update_branch_info(
     194             :         struct dc_context *ctx,
     195             :         const struct dc_link *link)
     196           0 : {}
     197             : 
     198             : /*
     199             :  * Writes payload allocation table in immediate downstream device.
     200             :  */
     201           0 : bool dm_helpers_dp_mst_write_payload_allocation_table(
     202             :                 struct dc_context *ctx,
     203             :                 const struct dc_stream_state *stream,
     204             :                 struct dp_mst_stream_allocation_table *proposed_table,
     205             :                 bool enable)
     206             : {
     207             :         struct amdgpu_dm_connector *aconnector;
     208             :         struct dm_connector_state *dm_conn_state;
     209             :         struct drm_dp_mst_topology_mgr *mst_mgr;
     210             :         struct drm_dp_mst_port *mst_port;
     211             :         bool ret;
     212           0 :         u8 link_coding_cap = DP_8b_10b_ENCODING;
     213             : 
     214           0 :         aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
     215             :         /* Accessing the connector state is required for vcpi_slots allocation
     216             :          * and directly relies on behaviour in commit check
     217             :          * that blocks before commit guaranteeing that the state
     218             :          * is not gonna be swapped while still in use in commit tail */
     219             : 
     220           0 :         if (!aconnector || !aconnector->mst_port)
     221             :                 return false;
     222             : 
     223           0 :         dm_conn_state = to_dm_connector_state(aconnector->base.state);
     224             : 
     225           0 :         mst_mgr = &aconnector->mst_port->mst_mgr;
     226             : 
     227           0 :         if (!mst_mgr->mst_state)
     228             :                 return false;
     229             : 
     230           0 :         mst_port = aconnector->port;
     231             : 
     232             : #if defined(CONFIG_DRM_AMD_DC_DCN)
     233           0 :         link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link);
     234             : #endif
     235             : 
     236           0 :         if (enable) {
     237             : 
     238           0 :                 ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port,
     239           0 :                                                dm_conn_state->pbn,
     240             :                                                dm_conn_state->vcpi_slots);
     241           0 :                 if (!ret)
     242             :                         return false;
     243             : 
     244             :         } else {
     245           0 :                 drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port);
     246             :         }
     247             : 
     248             :         /* It's OK for this to fail */
     249           0 :         drm_dp_update_payload_part1(mst_mgr, (link_coding_cap == DP_CAP_ANSI_128B132B) ? 0:1);
     250             : 
     251             :         /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
     252             :          * AUX message. The sequence is slot 1-63 allocated sequence for each
     253             :          * stream. AMD ASIC stream slot allocation should follow the same
     254             :          * sequence. copy DRM MST allocation to dc */
     255             : 
     256           0 :         get_payload_table(aconnector, proposed_table);
     257             : 
     258           0 :         return true;
     259             : }
     260             : 
     261             : /*
     262             :  * poll pending down reply
     263             :  */
     264           0 : void dm_helpers_dp_mst_poll_pending_down_reply(
     265             :         struct dc_context *ctx,
     266             :         const struct dc_link *link)
     267           0 : {}
     268             : 
     269             : /*
     270             :  * Clear payload allocation table before enable MST DP link.
     271             :  */
     272           0 : void dm_helpers_dp_mst_clear_payload_allocation_table(
     273             :         struct dc_context *ctx,
     274             :         const struct dc_link *link)
     275           0 : {}
     276             : 
     277             : /*
     278             :  * Polls for ACT (allocation change trigger) handled and sends
     279             :  * ALLOCATE_PAYLOAD message.
     280             :  */
     281           0 : enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger(
     282             :                 struct dc_context *ctx,
     283             :                 const struct dc_stream_state *stream)
     284             : {
     285             :         struct amdgpu_dm_connector *aconnector;
     286             :         struct drm_dp_mst_topology_mgr *mst_mgr;
     287             :         int ret;
     288             : 
     289           0 :         aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
     290             : 
     291           0 :         if (!aconnector || !aconnector->mst_port)
     292             :                 return ACT_FAILED;
     293             : 
     294           0 :         mst_mgr = &aconnector->mst_port->mst_mgr;
     295             : 
     296           0 :         if (!mst_mgr->mst_state)
     297             :                 return ACT_FAILED;
     298             : 
     299           0 :         ret = drm_dp_check_act_status(mst_mgr);
     300             : 
     301           0 :         if (ret)
     302             :                 return ACT_FAILED;
     303             : 
     304           0 :         return ACT_SUCCESS;
     305             : }
     306             : 
     307           0 : bool dm_helpers_dp_mst_send_payload_allocation(
     308             :                 struct dc_context *ctx,
     309             :                 const struct dc_stream_state *stream,
     310             :                 bool enable)
     311             : {
     312             :         struct amdgpu_dm_connector *aconnector;
     313             :         struct drm_dp_mst_topology_mgr *mst_mgr;
     314             :         struct drm_dp_mst_port *mst_port;
     315           0 :         enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD;
     316           0 :         enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
     317             : 
     318           0 :         aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
     319             : 
     320           0 :         if (!aconnector || !aconnector->mst_port)
     321             :                 return false;
     322             : 
     323           0 :         mst_port = aconnector->port;
     324             : 
     325           0 :         mst_mgr = &aconnector->mst_port->mst_mgr;
     326             : 
     327           0 :         if (!mst_mgr->mst_state)
     328             :                 return false;
     329             : 
     330           0 :         if (!enable) {
     331           0 :                 set_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
     332           0 :                 clr_flag = MST_ALLOCATE_NEW_PAYLOAD;
     333             :         }
     334             : 
     335           0 :         if (drm_dp_update_payload_part2(mst_mgr)) {
     336           0 :                 amdgpu_dm_set_mst_status(&aconnector->mst_status,
     337             :                         set_flag, false);
     338             :         } else {
     339           0 :                 amdgpu_dm_set_mst_status(&aconnector->mst_status,
     340             :                         set_flag, true);
     341           0 :                 amdgpu_dm_set_mst_status(&aconnector->mst_status,
     342             :                         clr_flag, false);
     343             :         }
     344             : 
     345           0 :         if (!enable)
     346           0 :                 drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port);
     347             : 
     348             :         return true;
     349             : }
     350             : 
     351           0 : void dm_dtn_log_begin(struct dc_context *ctx,
     352             :         struct dc_log_buffer_ctx *log_ctx)
     353             : {
     354             :         static const char msg[] = "[dtn begin]\n";
     355             : 
     356           0 :         if (!log_ctx) {
     357           0 :                 pr_info("%s", msg);
     358           0 :                 return;
     359             :         }
     360             : 
     361           0 :         dm_dtn_log_append_v(ctx, log_ctx, "%s", msg);
     362             : }
     363             : 
     364             : __printf(3, 4)
     365           0 : void dm_dtn_log_append_v(struct dc_context *ctx,
     366             :         struct dc_log_buffer_ctx *log_ctx,
     367             :         const char *msg, ...)
     368             : {
     369             :         va_list args;
     370             :         size_t total;
     371             :         int n;
     372             : 
     373           0 :         if (!log_ctx) {
     374             :                 /* No context, redirect to dmesg. */
     375             :                 struct va_format vaf;
     376             : 
     377           0 :                 vaf.fmt = msg;
     378           0 :                 vaf.va = &args;
     379             : 
     380           0 :                 va_start(args, msg);
     381           0 :                 pr_info("%pV", &vaf);
     382           0 :                 va_end(args);
     383             : 
     384             :                 return;
     385             :         }
     386             : 
     387             :         /* Measure the output. */
     388           0 :         va_start(args, msg);
     389           0 :         n = vsnprintf(NULL, 0, msg, args);
     390           0 :         va_end(args);
     391             : 
     392           0 :         if (n <= 0)
     393             :                 return;
     394             : 
     395             :         /* Reallocate the string buffer as needed. */
     396           0 :         total = log_ctx->pos + n + 1;
     397             : 
     398           0 :         if (total > log_ctx->size) {
     399           0 :                 char *buf = (char *)kvcalloc(total, sizeof(char), GFP_KERNEL);
     400             : 
     401           0 :                 if (buf) {
     402           0 :                         memcpy(buf, log_ctx->buf, log_ctx->pos);
     403           0 :                         kfree(log_ctx->buf);
     404             : 
     405           0 :                         log_ctx->buf = buf;
     406           0 :                         log_ctx->size = total;
     407             :                 }
     408             :         }
     409             : 
     410           0 :         if (!log_ctx->buf)
     411             :                 return;
     412             : 
     413             :         /* Write the formatted string to the log buffer. */
     414           0 :         va_start(args, msg);
     415           0 :         n = vscnprintf(
     416           0 :                 log_ctx->buf + log_ctx->pos,
     417           0 :                 log_ctx->size - log_ctx->pos,
     418             :                 msg,
     419             :                 args);
     420           0 :         va_end(args);
     421             : 
     422           0 :         if (n > 0)
     423           0 :                 log_ctx->pos += n;
     424             : }
     425             : 
     426           0 : void dm_dtn_log_end(struct dc_context *ctx,
     427             :         struct dc_log_buffer_ctx *log_ctx)
     428             : {
     429             :         static const char msg[] = "[dtn end]\n";
     430             : 
     431           0 :         if (!log_ctx) {
     432           0 :                 pr_info("%s", msg);
     433           0 :                 return;
     434             :         }
     435             : 
     436           0 :         dm_dtn_log_append_v(ctx, log_ctx, "%s", msg);
     437             : }
     438             : 
     439           0 : bool dm_helpers_dp_mst_start_top_mgr(
     440             :                 struct dc_context *ctx,
     441             :                 const struct dc_link *link,
     442             :                 bool boot)
     443             : {
     444           0 :         struct amdgpu_dm_connector *aconnector = link->priv;
     445             : 
     446           0 :         if (!aconnector) {
     447           0 :                 DRM_ERROR("Failed to find connector for link!");
     448           0 :                 return false;
     449             :         }
     450             : 
     451           0 :         if (boot) {
     452           0 :                 DRM_INFO("DM_MST: Differing MST start on aconnector: %p [id: %d]\n",
     453             :                                         aconnector, aconnector->base.base.id);
     454           0 :                 return true;
     455             :         }
     456             : 
     457           0 :         DRM_INFO("DM_MST: starting TM on aconnector: %p [id: %d]\n",
     458             :                         aconnector, aconnector->base.base.id);
     459             : 
     460           0 :         return (drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true) == 0);
     461             : }
     462             : 
     463           0 : bool dm_helpers_dp_mst_stop_top_mgr(
     464             :                 struct dc_context *ctx,
     465             :                 struct dc_link *link)
     466             : {
     467           0 :         struct amdgpu_dm_connector *aconnector = link->priv;
     468             : 
     469           0 :         if (!aconnector) {
     470           0 :                 DRM_ERROR("Failed to find connector for link!");
     471           0 :                 return false;
     472             :         }
     473             : 
     474           0 :         DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n",
     475             :                         aconnector, aconnector->base.base.id);
     476             : 
     477           0 :         if (aconnector->mst_mgr.mst_state == true) {
     478           0 :                 drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, false);
     479           0 :                 link->cur_link_settings.lane_count = 0;
     480             :         }
     481             : 
     482             :         return false;
     483             : }
     484             : 
     485           0 : bool dm_helpers_dp_read_dpcd(
     486             :                 struct dc_context *ctx,
     487             :                 const struct dc_link *link,
     488             :                 uint32_t address,
     489             :                 uint8_t *data,
     490             :                 uint32_t size)
     491             : {
     492             : 
     493           0 :         struct amdgpu_dm_connector *aconnector = link->priv;
     494             : 
     495           0 :         if (!aconnector) {
     496           0 :                 DC_LOG_DC("Failed to find connector for link!\n");
     497           0 :                 return false;
     498             :         }
     499             : 
     500           0 :         return drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, address,
     501           0 :                         data, size) > 0;
     502             : }
     503             : 
     504           0 : bool dm_helpers_dp_write_dpcd(
     505             :                 struct dc_context *ctx,
     506             :                 const struct dc_link *link,
     507             :                 uint32_t address,
     508             :                 const uint8_t *data,
     509             :                 uint32_t size)
     510             : {
     511           0 :         struct amdgpu_dm_connector *aconnector = link->priv;
     512             : 
     513           0 :         if (!aconnector) {
     514           0 :                 DRM_ERROR("Failed to find connector for link!");
     515           0 :                 return false;
     516             :         }
     517             : 
     518           0 :         return drm_dp_dpcd_write(&aconnector->dm_dp_aux.aux,
     519           0 :                         address, (uint8_t *)data, size) > 0;
     520             : }
     521             : 
     522           0 : bool dm_helpers_submit_i2c(
     523             :                 struct dc_context *ctx,
     524             :                 const struct dc_link *link,
     525             :                 struct i2c_command *cmd)
     526             : {
     527           0 :         struct amdgpu_dm_connector *aconnector = link->priv;
     528             :         struct i2c_msg *msgs;
     529           0 :         int i = 0;
     530           0 :         int num = cmd->number_of_payloads;
     531             :         bool result;
     532             : 
     533           0 :         if (!aconnector) {
     534           0 :                 DRM_ERROR("Failed to find connector for link!");
     535           0 :                 return false;
     536             :         }
     537             : 
     538           0 :         msgs = kcalloc(num, sizeof(struct i2c_msg), GFP_KERNEL);
     539             : 
     540           0 :         if (!msgs)
     541             :                 return false;
     542             : 
     543           0 :         for (i = 0; i < num; i++) {
     544           0 :                 msgs[i].flags = cmd->payloads[i].write ? 0 : I2C_M_RD;
     545           0 :                 msgs[i].addr = cmd->payloads[i].address;
     546           0 :                 msgs[i].len = cmd->payloads[i].length;
     547           0 :                 msgs[i].buf = cmd->payloads[i].data;
     548             :         }
     549             : 
     550           0 :         result = i2c_transfer(&aconnector->i2c->base, msgs, num) == num;
     551             : 
     552           0 :         kfree(msgs);
     553             : 
     554           0 :         return result;
     555             : }
     556             : 
     557             : #if defined(CONFIG_DRM_AMD_DC_DCN)
     558           0 : static bool execute_synaptics_rc_command(struct drm_dp_aux *aux,
     559             :                 bool is_write_cmd,
     560             :                 unsigned char cmd,
     561             :                 unsigned int length,
     562             :                 unsigned int offset,
     563             :                 unsigned char *data)
     564             : {
     565           0 :         bool success = false;
     566           0 :         unsigned char rc_data[16] = {0};
     567           0 :         unsigned char rc_offset[4] = {0};
     568           0 :         unsigned char rc_length[2] = {0};
     569           0 :         unsigned char rc_cmd = 0;
     570           0 :         unsigned char rc_result = 0xFF;
     571           0 :         unsigned char i = 0;
     572             :         int ret;
     573             : 
     574           0 :         if (is_write_cmd) {
     575             :                 // write rc data
     576           0 :                 memmove(rc_data, data, length);
     577           0 :                 ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_DATA, rc_data, sizeof(rc_data));
     578             :         }
     579             : 
     580             :         // write rc offset
     581           0 :         rc_offset[0] = (unsigned char) offset & 0xFF;
     582           0 :         rc_offset[1] = (unsigned char) (offset >> 8) & 0xFF;
     583           0 :         rc_offset[2] = (unsigned char) (offset >> 16) & 0xFF;
     584           0 :         rc_offset[3] = (unsigned char) (offset >> 24) & 0xFF;
     585           0 :         ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_OFFSET, rc_offset, sizeof(rc_offset));
     586             : 
     587             :         // write rc length
     588           0 :         rc_length[0] = (unsigned char) length & 0xFF;
     589           0 :         rc_length[1] = (unsigned char) (length >> 8) & 0xFF;
     590           0 :         ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_LENGTH, rc_length, sizeof(rc_length));
     591             : 
     592             :         // write rc cmd
     593           0 :         rc_cmd = cmd | 0x80;
     594           0 :         ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_COMMAND, &rc_cmd, sizeof(rc_cmd));
     595             : 
     596           0 :         if (ret < 0) {
     597           0 :                 DRM_ERROR("        execute_synaptics_rc_command - write cmd ..., err = %d\n", ret);
     598           0 :                 return false;
     599             :         }
     600             : 
     601             :         // poll until active is 0
     602           0 :         for (i = 0; i < 10; i++) {
     603           0 :                 drm_dp_dpcd_read(aux, SYNAPTICS_RC_COMMAND, &rc_cmd, sizeof(rc_cmd));
     604           0 :                 if (rc_cmd == cmd)
     605             :                         // active is 0
     606             :                         break;
     607           0 :                 msleep(10);
     608             :         }
     609             : 
     610             :         // read rc result
     611           0 :         drm_dp_dpcd_read(aux, SYNAPTICS_RC_RESULT, &rc_result, sizeof(rc_result));
     612           0 :         success = (rc_result == 0);
     613             : 
     614           0 :         if (success && !is_write_cmd) {
     615             :                 // read rc data
     616           0 :                 drm_dp_dpcd_read(aux, SYNAPTICS_RC_DATA, data, length);
     617             :         }
     618             : 
     619           0 :         DC_LOG_DC("        execute_synaptics_rc_command - success = %d\n", success);
     620             : 
     621           0 :         return success;
     622             : }
     623             : 
     624           0 : static void apply_synaptics_fifo_reset_wa(struct drm_dp_aux *aux)
     625             : {
     626           0 :         unsigned char data[16] = {0};
     627             : 
     628           0 :         DC_LOG_DC("Start apply_synaptics_fifo_reset_wa\n");
     629             : 
     630             :         // Step 2
     631           0 :         data[0] = 'P';
     632           0 :         data[1] = 'R';
     633           0 :         data[2] = 'I';
     634           0 :         data[3] = 'U';
     635           0 :         data[4] = 'S';
     636             : 
     637           0 :         if (!execute_synaptics_rc_command(aux, true, 0x01, 5, 0, data))
     638           0 :                 return;
     639             : 
     640             :         // Step 3 and 4
     641           0 :         if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x220998, data))
     642             :                 return;
     643             : 
     644           0 :         data[0] &= (~(1 << 1)); // set bit 1 to 0
     645           0 :         if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x220998, data))
     646             :                 return;
     647             : 
     648           0 :         if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x220D98, data))
     649             :                 return;
     650             : 
     651           0 :         data[0] &= (~(1 << 1)); // set bit 1 to 0
     652           0 :         if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x220D98, data))
     653             :                 return;
     654             : 
     655           0 :         if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x221198, data))
     656             :                 return;
     657             : 
     658           0 :         data[0] &= (~(1 << 1)); // set bit 1 to 0
     659           0 :         if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x221198, data))
     660             :                 return;
     661             : 
     662             :         // Step 3 and 5
     663           0 :         if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x220998, data))
     664             :                 return;
     665             : 
     666           0 :         data[0] |= (1 << 1); // set bit 1 to 1
     667           0 :         if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x220998, data))
     668             :                 return;
     669             : 
     670           0 :         if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x220D98, data))
     671             :                 return;
     672             : 
     673             :         data[0] |= (1 << 1); // set bit 1 to 1
     674             :                 return;
     675             : 
     676             :         if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x221198, data))
     677             :                 return;
     678             : 
     679             :         data[0] |= (1 << 1); // set bit 1 to 1
     680             :         if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x221198, data))
     681             :                 return;
     682             : 
     683             :         // Step 6
     684             :         if (!execute_synaptics_rc_command(aux, true, 0x02, 0, 0, NULL))
     685             :                 return;
     686             : 
     687             :         DC_LOG_DC("Done apply_synaptics_fifo_reset_wa\n");
     688             : }
     689             : 
     690           0 : static uint8_t write_dsc_enable_synaptics_non_virtual_dpcd_mst(
     691             :                 struct drm_dp_aux *aux,
     692             :                 const struct dc_stream_state *stream,
     693             :                 bool enable)
     694             : {
     695           0 :         uint8_t ret = 0;
     696             : 
     697           0 :         DC_LOG_DC("Configure DSC to non-virtual dpcd synaptics\n");
     698             : 
     699           0 :         if (enable) {
     700             :                 /* When DSC is enabled on previous boot and reboot with the hub,
     701             :                  * there is a chance that Synaptics hub gets stuck during reboot sequence.
     702             :                  * Applying a workaround to reset Synaptics SDP fifo before enabling the first stream
     703             :                  */
     704           0 :                 if (!stream->link->link_status.link_active &&
     705           0 :                         memcmp(stream->link->dpcd_caps.branch_dev_name,
     706             :                                 (int8_t *)SYNAPTICS_DEVICE_ID, 4) == 0)
     707           0 :                         apply_synaptics_fifo_reset_wa(aux);
     708             : 
     709           0 :                 ret = drm_dp_dpcd_write(aux, DP_DSC_ENABLE, &enable, 1);
     710           0 :                 DRM_INFO("Send DSC enable to synaptics\n");
     711             : 
     712             :         } else {
     713             :                 /* Synaptics hub not support virtual dpcd,
     714             :                  * external monitor occur garbage while disable DSC,
     715             :                  * Disable DSC only when entire link status turn to false,
     716             :                  */
     717           0 :                 if (!stream->link->link_status.link_active) {
     718           0 :                         ret = drm_dp_dpcd_write(aux, DP_DSC_ENABLE, &enable, 1);
     719           0 :                         DRM_INFO("Send DSC disable to synaptics\n");
     720             :                 }
     721             :         }
     722             : 
     723           0 :         return ret;
     724             : }
     725             : #endif
     726             : 
     727           0 : bool dm_helpers_dp_write_dsc_enable(
     728             :                 struct dc_context *ctx,
     729             :                 const struct dc_stream_state *stream,
     730             :                 bool enable)
     731             : {
     732             :         static const uint8_t DSC_DISABLE;
     733             :         static const uint8_t DSC_DECODING = 0x01;
     734             :         static const uint8_t DSC_PASSTHROUGH = 0x02;
     735             : 
     736             :         struct amdgpu_dm_connector *aconnector;
     737             :         struct drm_dp_mst_port *port;
     738           0 :         uint8_t enable_dsc = enable ? DSC_DECODING : DSC_DISABLE;
     739           0 :         uint8_t enable_passthrough = enable ? DSC_PASSTHROUGH : DSC_DISABLE;
     740           0 :         uint8_t ret = 0;
     741             : 
     742           0 :         if (!stream)
     743             :                 return false;
     744             : 
     745           0 :         if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
     746           0 :                 aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
     747             : 
     748           0 :                 if (!aconnector->dsc_aux)
     749             :                         return false;
     750             : 
     751             : #if defined(CONFIG_DRM_AMD_DC_DCN)
     752             :                 // apply w/a to synaptics
     753           0 :                 if (needs_dsc_aux_workaround(aconnector->dc_link) &&
     754           0 :                     (aconnector->mst_downstream_port_present.byte & 0x7) != 0x3)
     755           0 :                         return write_dsc_enable_synaptics_non_virtual_dpcd_mst(
     756             :                                 aconnector->dsc_aux, stream, enable_dsc);
     757             : #endif
     758             : 
     759           0 :                 port = aconnector->port;
     760             : 
     761           0 :                 if (enable) {
     762           0 :                         if (port->passthrough_aux) {
     763           0 :                                 ret = drm_dp_dpcd_write(port->passthrough_aux,
     764             :                                                         DP_DSC_ENABLE,
     765             :                                                         &enable_passthrough, 1);
     766           0 :                                 DC_LOG_DC("Sent DSC pass-through enable to virtual dpcd port, ret = %u\n",
     767             :                                           ret);
     768             :                         }
     769             : 
     770           0 :                         ret = drm_dp_dpcd_write(aconnector->dsc_aux,
     771             :                                                 DP_DSC_ENABLE, &enable_dsc, 1);
     772           0 :                         DC_LOG_DC("Sent DSC decoding enable to %s port, ret = %u\n",
     773             :                                   (port->passthrough_aux) ? "remote RX" :
     774             :                                   "virtual dpcd",
     775             :                                   ret);
     776             :                 } else {
     777           0 :                         ret = drm_dp_dpcd_write(aconnector->dsc_aux,
     778             :                                                 DP_DSC_ENABLE, &enable_dsc, 1);
     779           0 :                         DC_LOG_DC("Sent DSC decoding disable to %s port, ret = %u\n",
     780             :                                   (port->passthrough_aux) ? "remote RX" :
     781             :                                   "virtual dpcd",
     782             :                                   ret);
     783             : 
     784           0 :                         if (port->passthrough_aux) {
     785           0 :                                 ret = drm_dp_dpcd_write(port->passthrough_aux,
     786             :                                                         DP_DSC_ENABLE,
     787             :                                                         &enable_passthrough, 1);
     788           0 :                                 DC_LOG_DC("Sent DSC pass-through disable to virtual dpcd port, ret = %u\n",
     789             :                                           ret);
     790             :                         }
     791             :                 }
     792             :         }
     793             : 
     794           0 :         if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT || stream->signal == SIGNAL_TYPE_EDP) {
     795             : #if defined(CONFIG_DRM_AMD_DC_DCN)
     796           0 :                 if (stream->sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) {
     797             : #endif
     798           0 :                         ret = dm_helpers_dp_write_dpcd(ctx, stream->link, DP_DSC_ENABLE, &enable_dsc, 1);
     799           0 :                         DC_LOG_DC("Send DSC %s to SST RX\n", enable_dsc ? "enable" : "disable");
     800             : #if defined(CONFIG_DRM_AMD_DC_DCN)
     801           0 :                 } else if (stream->sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
     802           0 :                         ret = dm_helpers_dp_write_dpcd(ctx, stream->link, DP_DSC_ENABLE, &enable_dsc, 1);
     803           0 :                         DC_LOG_DC("Send DSC %s to DP-HDMI PCON\n", enable_dsc ? "enable" : "disable");
     804             :                 }
     805             : #endif
     806             :         }
     807             : 
     808           0 :         return ret;
     809             : }
     810             : 
     811           0 : bool dm_helpers_is_dp_sink_present(struct dc_link *link)
     812             : {
     813             :         bool dp_sink_present;
     814           0 :         struct amdgpu_dm_connector *aconnector = link->priv;
     815             : 
     816           0 :         if (!aconnector) {
     817           0 :                 BUG_ON("Failed to find connector for link!");
     818             :                 return true;
     819             :         }
     820             : 
     821           0 :         mutex_lock(&aconnector->dm_dp_aux.aux.hw_mutex);
     822           0 :         dp_sink_present = dc_link_is_dp_sink_present(link);
     823           0 :         mutex_unlock(&aconnector->dm_dp_aux.aux.hw_mutex);
     824             :         return dp_sink_present;
     825             : }
     826             : 
     827           0 : enum dc_edid_status dm_helpers_read_local_edid(
     828             :                 struct dc_context *ctx,
     829             :                 struct dc_link *link,
     830             :                 struct dc_sink *sink)
     831             : {
     832           0 :         struct amdgpu_dm_connector *aconnector = link->priv;
     833           0 :         struct drm_connector *connector = &aconnector->base;
     834             :         struct i2c_adapter *ddc;
     835           0 :         int retry = 3;
     836             :         enum dc_edid_status edid_status;
     837             :         struct edid *edid;
     838             : 
     839           0 :         if (link->aux_mode)
     840           0 :                 ddc = &aconnector->dm_dp_aux.aux.ddc;
     841             :         else
     842           0 :                 ddc = &aconnector->i2c->base;
     843             : 
     844             :         /* some dongles read edid incorrectly the first time,
     845             :          * do check sum and retry to make sure read correct edid.
     846             :          */
     847             :         do {
     848             : 
     849           0 :                 edid = drm_get_edid(&aconnector->base, ddc);
     850             : 
     851             :                 /* DP Compliance Test 4.2.2.6 */
     852           0 :                 if (link->aux_mode && connector->edid_corrupt)
     853           0 :                         drm_dp_send_real_edid_checksum(&aconnector->dm_dp_aux.aux, connector->real_edid_checksum);
     854             : 
     855           0 :                 if (!edid && connector->edid_corrupt) {
     856           0 :                         connector->edid_corrupt = false;
     857           0 :                         return EDID_BAD_CHECKSUM;
     858             :                 }
     859             : 
     860           0 :                 if (!edid)
     861             :                         return EDID_NO_RESPONSE;
     862             : 
     863           0 :                 sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
     864           0 :                 memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length);
     865             : 
     866             :                 /* We don't need the original edid anymore */
     867           0 :                 kfree(edid);
     868             : 
     869           0 :                 edid_status = dm_helpers_parse_edid_caps(
     870             :                                                 link,
     871           0 :                                                 &sink->dc_edid,
     872             :                                                 &sink->edid_caps);
     873             : 
     874           0 :         } while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
     875             : 
     876           0 :         if (edid_status != EDID_OK)
     877           0 :                 DRM_ERROR("EDID err: %d, on connector: %s",
     878             :                                 edid_status,
     879             :                                 aconnector->base.name);
     880             : 
     881             :         /* DP Compliance Test 4.2.2.3 */
     882           0 :         if (link->aux_mode)
     883           0 :                 drm_dp_send_real_edid_checksum(&aconnector->dm_dp_aux.aux, sink->dc_edid.raw_edid[sink->dc_edid.length-1]);
     884             : 
     885             :         return edid_status;
     886             : }
     887           0 : int dm_helper_dmub_aux_transfer_sync(
     888             :                 struct dc_context *ctx,
     889             :                 const struct dc_link *link,
     890             :                 struct aux_payload *payload,
     891             :                 enum aux_return_code_type *operation_result)
     892             : {
     893           0 :         return amdgpu_dm_process_dmub_aux_transfer_sync(true, ctx,
     894             :                         link->link_index, (void *)payload,
     895             :                         (void *)operation_result);
     896             : }
     897             : 
     898           0 : int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
     899             :                 const struct dc_link *link,
     900             :                 struct set_config_cmd_payload *payload,
     901             :                 enum set_config_status *operation_result)
     902             : {
     903           0 :         return amdgpu_dm_process_dmub_aux_transfer_sync(false, ctx,
     904             :                         link->link_index, (void *)payload,
     905             :                         (void *)operation_result);
     906             : }
     907             : 
     908           0 : void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks)
     909             : {
     910             :         /* TODO: something */
     911           0 : }
     912             : 
     913           0 : void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us)
     914             : {
     915             :         // TODO:
     916             :         //amdgpu_device_gpu_recover(dc_context->driver-context, NULL);
     917           0 : }
     918             : 
     919           0 : void dm_helpers_init_panel_settings(
     920             :         struct dc_context *ctx,
     921             :         struct dc_panel_config *panel_config)
     922             : {
     923             :         // Feature DSC
     924           0 :         panel_config->dsc.disable_dsc_edp = false;
     925           0 :         panel_config->dsc.force_dsc_edp_policy = 0;
     926           0 : }
     927             : 
     928           0 : void dm_helpers_override_panel_settings(
     929             :         struct dc_context *ctx,
     930             :         struct dc_panel_config *panel_config)
     931             : {
     932             :         // Feature DSC
     933           0 :         if (amdgpu_dc_debug_mask & DC_DISABLE_DSC) {
     934           0 :                 panel_config->dsc.disable_dsc_edp = true;
     935             :         }
     936           0 : }
     937             : 
     938           0 : void *dm_helpers_allocate_gpu_mem(
     939             :                 struct dc_context *ctx,
     940             :                 enum dc_gpu_mem_alloc_type type,
     941             :                 size_t size,
     942             :                 long long *addr)
     943             : {
     944           0 :         struct amdgpu_device *adev = ctx->driver_context;
     945             :         struct dal_allocation *da;
     946           0 :         u32 domain = (type == DC_MEM_ALLOC_TYPE_GART) ?
     947           0 :                 AMDGPU_GEM_DOMAIN_GTT : AMDGPU_GEM_DOMAIN_VRAM;
     948             :         int ret;
     949             : 
     950           0 :         da = kzalloc(sizeof(struct dal_allocation), GFP_KERNEL);
     951           0 :         if (!da)
     952             :                 return NULL;
     953             : 
     954           0 :         ret = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE,
     955             :                                       domain, &da->bo,
     956             :                                       &da->gpu_addr, &da->cpu_ptr);
     957             : 
     958           0 :         *addr = da->gpu_addr;
     959             : 
     960           0 :         if (ret) {
     961           0 :                 kfree(da);
     962           0 :                 return NULL;
     963             :         }
     964             : 
     965             :         /* add da to list in dm */
     966           0 :         list_add(&da->list, &adev->dm.da_list);
     967             : 
     968           0 :         return da->cpu_ptr;
     969             : }
     970             : 
     971           0 : void dm_helpers_free_gpu_mem(
     972             :                 struct dc_context *ctx,
     973             :                 enum dc_gpu_mem_alloc_type type,
     974             :                 void *pvMem)
     975             : {
     976           0 :         struct amdgpu_device *adev = ctx->driver_context;
     977             :         struct dal_allocation *da;
     978             : 
     979             :         /* walk the da list in DM */
     980           0 :         list_for_each_entry(da, &adev->dm.da_list, list) {
     981           0 :                 if (pvMem == da->cpu_ptr) {
     982           0 :                         amdgpu_bo_free_kernel(&da->bo, &da->gpu_addr, &da->cpu_ptr);
     983           0 :                         list_del(&da->list);
     984           0 :                         kfree(da);
     985           0 :                         break;
     986             :                 }
     987             :         }
     988           0 : }
     989             : 
     990           0 : bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable)
     991             : {
     992             :         enum dc_irq_source irq_source;
     993             :         bool ret;
     994             : 
     995           0 :         irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
     996             : 
     997           0 :         ret = dc_interrupt_set(ctx->dc, irq_source, enable);
     998             : 
     999           0 :         DRM_DEBUG_DRIVER("Dmub trace irq %sabling: r=%d\n",
    1000             :                          enable ? "en" : "dis", ret);
    1001           0 :         return ret;
    1002             : }
    1003             : 
    1004           0 : void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream)
    1005             : {
    1006             :         /* TODO: virtual DPCD */
    1007           0 :         struct dc_link *link = stream->link;
    1008             :         union down_spread_ctrl old_downspread;
    1009             :         union down_spread_ctrl new_downspread;
    1010             : 
    1011           0 :         if (link->aux_access_disabled)
    1012           0 :                 return;
    1013             : 
    1014           0 :         if (!dm_helpers_dp_read_dpcd(link->ctx, link, DP_DOWNSPREAD_CTRL,
    1015             :                                      &old_downspread.raw,
    1016             :                                      sizeof(old_downspread)))
    1017             :                 return;
    1018             : 
    1019           0 :         new_downspread.raw = old_downspread.raw;
    1020           0 :         new_downspread.bits.IGNORE_MSA_TIMING_PARAM =
    1021           0 :                 (stream->ignore_msa_timing_param) ? 1 : 0;
    1022             : 
    1023           0 :         if (new_downspread.raw != old_downspread.raw)
    1024           0 :                 dm_helpers_dp_write_dpcd(link->ctx, link, DP_DOWNSPREAD_CTRL,
    1025             :                                          &new_downspread.raw,
    1026             :                                          sizeof(new_downspread));
    1027             : }
    1028             : 
    1029           0 : void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
    1030             : {
    1031             :        // TODO
    1032           0 : }
    1033             : 
    1034           0 : void dm_helpers_enable_periodic_detection(struct dc_context *ctx, bool enable)
    1035             : {
    1036             :         /* TODO: add periodic detection implementation */
    1037           0 : }

Generated by: LCOV version 1.14