2673 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Cadence MHDP8546 DP bridge driver.4 *5 * Copyright (C) 2020 Cadence Design Systems, Inc.6 *7 * Authors: Quentin Schulz <quentin.schulz@free-electrons.com>8 * Swapnil Jakhade <sjakhade@cadence.com>9 * Yuti Amonkar <yamonkar@cadence.com>10 * Tomi Valkeinen <tomi.valkeinen@ti.com>11 * Jyri Sarha <jsarha@ti.com>12 *13 * TODO:14 * - Implement optimized mailbox communication using mailbox interrupts15 * - Add support for power management16 * - Add support for features like audio, MST and fast link training17 * - Implement request_fw_cancel to handle HW_STATE18 * - Fix asynchronous loading of firmware implementation19 * - Add DRM helper function for cdns_mhdp_lower_link_rate20 */21 22#include <linux/clk.h>23#include <linux/delay.h>24#include <linux/err.h>25#include <linux/firmware.h>26#include <linux/io.h>27#include <linux/iopoll.h>28#include <linux/irq.h>29#include <linux/media-bus-format.h>30#include <linux/module.h>31#include <linux/of.h>32#include <linux/phy/phy.h>33#include <linux/phy/phy-dp.h>34#include <linux/platform_device.h>35#include <linux/slab.h>36#include <linux/wait.h>37 38#include <drm/display/drm_dp_helper.h>39#include <drm/display/drm_hdcp_helper.h>40#include <drm/drm_atomic.h>41#include <drm/drm_atomic_helper.h>42#include <drm/drm_atomic_state_helper.h>43#include <drm/drm_bridge.h>44#include <drm/drm_connector.h>45#include <drm/drm_edid.h>46#include <drm/drm_modeset_helper_vtables.h>47#include <drm/drm_print.h>48#include <drm/drm_probe_helper.h>49 50#include <linux/unaligned.h>51 52#include "cdns-mhdp8546-core.h"53#include "cdns-mhdp8546-hdcp.h"54#include "cdns-mhdp8546-j721e.h"55 56static void cdns_mhdp_bridge_hpd_enable(struct drm_bridge *bridge)57{58 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);59 60 /* Enable SW event interrupts */61 if (mhdp->bridge_attached)62 writel(readl(mhdp->regs + CDNS_APB_INT_MASK) &63 ~CDNS_APB_INT_MASK_SW_EVENT_INT,64 mhdp->regs + CDNS_APB_INT_MASK);65}66 67static void cdns_mhdp_bridge_hpd_disable(struct drm_bridge *bridge)68{69 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);70 71 writel(readl(mhdp->regs + CDNS_APB_INT_MASK) |72 CDNS_APB_INT_MASK_SW_EVENT_INT,73 mhdp->regs + CDNS_APB_INT_MASK);74}75 76static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)77{78 int ret, empty;79 80 WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));81 82 ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_EMPTY,83 empty, !empty, MAILBOX_RETRY_US,84 MAILBOX_TIMEOUT_US);85 if (ret < 0)86 return ret;87 88 return readl(mhdp->regs + CDNS_MAILBOX_RX_DATA) & 0xff;89}90 91static int cdns_mhdp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val)92{93 int ret, full;94 95 WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));96 97 ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_FULL,98 full, !full, MAILBOX_RETRY_US,99 MAILBOX_TIMEOUT_US);100 if (ret < 0)101 return ret;102 103 writel(val, mhdp->regs + CDNS_MAILBOX_TX_DATA);104 105 return 0;106}107 108static int cdns_mhdp_mailbox_recv_header(struct cdns_mhdp_device *mhdp,109 u8 module_id, u8 opcode,110 u16 req_size)111{112 u32 mbox_size, i;113 u8 header[4];114 int ret;115 116 /* read the header of the message */117 for (i = 0; i < sizeof(header); i++) {118 ret = cdns_mhdp_mailbox_read(mhdp);119 if (ret < 0)120 return ret;121 122 header[i] = ret;123 }124 125 mbox_size = get_unaligned_be16(header + 2);126 127 if (opcode != header[0] || module_id != header[1] ||128 req_size != mbox_size) {129 /*130 * If the message in mailbox is not what we want, we need to131 * clear the mailbox by reading its contents.132 */133 for (i = 0; i < mbox_size; i++)134 if (cdns_mhdp_mailbox_read(mhdp) < 0)135 break;136 137 return -EINVAL;138 }139 140 return 0;141}142 143static int cdns_mhdp_mailbox_recv_data(struct cdns_mhdp_device *mhdp,144 u8 *buff, u16 buff_size)145{146 u32 i;147 int ret;148 149 for (i = 0; i < buff_size; i++) {150 ret = cdns_mhdp_mailbox_read(mhdp);151 if (ret < 0)152 return ret;153 154 buff[i] = ret;155 }156 157 return 0;158}159 160static int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,161 u8 opcode, u16 size, u8 *message)162{163 u8 header[4];164 int ret, i;165 166 header[0] = opcode;167 header[1] = module_id;168 put_unaligned_be16(size, header + 2);169 170 for (i = 0; i < sizeof(header); i++) {171 ret = cdns_mhdp_mailbox_write(mhdp, header[i]);172 if (ret)173 return ret;174 }175 176 for (i = 0; i < size; i++) {177 ret = cdns_mhdp_mailbox_write(mhdp, message[i]);178 if (ret)179 return ret;180 }181 182 return 0;183}184 185static186int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr, u32 *value)187{188 u8 msg[4], resp[8];189 int ret;190 191 put_unaligned_be32(addr, msg);192 193 mutex_lock(&mhdp->mbox_mutex);194 195 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,196 GENERAL_REGISTER_READ,197 sizeof(msg), msg);198 if (ret)199 goto out;200 201 ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_GENERAL,202 GENERAL_REGISTER_READ,203 sizeof(resp));204 if (ret)205 goto out;206 207 ret = cdns_mhdp_mailbox_recv_data(mhdp, resp, sizeof(resp));208 if (ret)209 goto out;210 211 /* Returned address value should be the same as requested */212 if (memcmp(msg, resp, sizeof(msg))) {213 ret = -EINVAL;214 goto out;215 }216 217 *value = get_unaligned_be32(resp + 4);218 219out:220 mutex_unlock(&mhdp->mbox_mutex);221 if (ret) {222 dev_err(mhdp->dev, "Failed to read register\n");223 *value = 0;224 }225 226 return ret;227}228 229static230int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u16 addr, u32 val)231{232 u8 msg[6];233 int ret;234 235 put_unaligned_be16(addr, msg);236 put_unaligned_be32(val, msg + 2);237 238 mutex_lock(&mhdp->mbox_mutex);239 240 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,241 DPTX_WRITE_REGISTER, sizeof(msg), msg);242 243 mutex_unlock(&mhdp->mbox_mutex);244 245 return ret;246}247 248static249int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,250 u8 start_bit, u8 bits_no, u32 val)251{252 u8 field[8];253 int ret;254 255 put_unaligned_be16(addr, field);256 field[2] = start_bit;257 field[3] = bits_no;258 put_unaligned_be32(val, field + 4);259 260 mutex_lock(&mhdp->mbox_mutex);261 262 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,263 DPTX_WRITE_FIELD, sizeof(field), field);264 265 mutex_unlock(&mhdp->mbox_mutex);266 267 return ret;268}269 270static271int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,272 u32 addr, u8 *data, u16 len)273{274 u8 msg[5], reg[5];275 int ret;276 277 put_unaligned_be16(len, msg);278 put_unaligned_be24(addr, msg + 2);279 280 mutex_lock(&mhdp->mbox_mutex);281 282 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,283 DPTX_READ_DPCD, sizeof(msg), msg);284 if (ret)285 goto out;286 287 ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX,288 DPTX_READ_DPCD,289 sizeof(reg) + len);290 if (ret)291 goto out;292 293 ret = cdns_mhdp_mailbox_recv_data(mhdp, reg, sizeof(reg));294 if (ret)295 goto out;296 297 ret = cdns_mhdp_mailbox_recv_data(mhdp, data, len);298 299out:300 mutex_unlock(&mhdp->mbox_mutex);301 302 return ret;303}304 305static306int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)307{308 u8 msg[6], reg[5];309 int ret;310 311 put_unaligned_be16(1, msg);312 put_unaligned_be24(addr, msg + 2);313 msg[5] = value;314 315 mutex_lock(&mhdp->mbox_mutex);316 317 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,318 DPTX_WRITE_DPCD, sizeof(msg), msg);319 if (ret)320 goto out;321 322 ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX,323 DPTX_WRITE_DPCD, sizeof(reg));324 if (ret)325 goto out;326 327 ret = cdns_mhdp_mailbox_recv_data(mhdp, reg, sizeof(reg));328 if (ret)329 goto out;330 331 if (addr != get_unaligned_be24(reg + 2))332 ret = -EINVAL;333 334out:335 mutex_unlock(&mhdp->mbox_mutex);336 337 if (ret)338 dev_err(mhdp->dev, "dpcd write failed: %d\n", ret);339 return ret;340}341 342static343int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)344{345 u8 msg[5];346 int ret, i;347 348 msg[0] = GENERAL_MAIN_CONTROL;349 msg[1] = MB_MODULE_ID_GENERAL;350 msg[2] = 0;351 msg[3] = 1;352 msg[4] = enable ? FW_ACTIVE : FW_STANDBY;353 354 mutex_lock(&mhdp->mbox_mutex);355 356 for (i = 0; i < sizeof(msg); i++) {357 ret = cdns_mhdp_mailbox_write(mhdp, msg[i]);358 if (ret)359 goto out;360 }361 362 /* read the firmware state */363 ret = cdns_mhdp_mailbox_recv_data(mhdp, msg, sizeof(msg));364 if (ret)365 goto out;366 367 ret = 0;368 369out:370 mutex_unlock(&mhdp->mbox_mutex);371 372 if (ret < 0)373 dev_err(mhdp->dev, "set firmware active failed\n");374 return ret;375}376 377static378int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp)379{380 u8 status;381 int ret;382 383 mutex_lock(&mhdp->mbox_mutex);384 385 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,386 DPTX_HPD_STATE, 0, NULL);387 if (ret)388 goto err_get_hpd;389 390 ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX,391 DPTX_HPD_STATE,392 sizeof(status));393 if (ret)394 goto err_get_hpd;395 396 ret = cdns_mhdp_mailbox_recv_data(mhdp, &status, sizeof(status));397 if (ret)398 goto err_get_hpd;399 400 mutex_unlock(&mhdp->mbox_mutex);401 402 dev_dbg(mhdp->dev, "%s: HPD %splugged\n", __func__,403 status ? "" : "un");404 405 return status;406 407err_get_hpd:408 mutex_unlock(&mhdp->mbox_mutex);409 410 return ret;411}412 413static414int cdns_mhdp_get_edid_block(void *data, u8 *edid,415 unsigned int block, size_t length)416{417 struct cdns_mhdp_device *mhdp = data;418 u8 msg[2], reg[2], i;419 int ret;420 421 mutex_lock(&mhdp->mbox_mutex);422 423 for (i = 0; i < 4; i++) {424 msg[0] = block / 2;425 msg[1] = block % 2;426 427 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,428 DPTX_GET_EDID, sizeof(msg), msg);429 if (ret)430 continue;431 432 ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX,433 DPTX_GET_EDID,434 sizeof(reg) + length);435 if (ret)436 continue;437 438 ret = cdns_mhdp_mailbox_recv_data(mhdp, reg, sizeof(reg));439 if (ret)440 continue;441 442 ret = cdns_mhdp_mailbox_recv_data(mhdp, edid, length);443 if (ret)444 continue;445 446 if (reg[0] == length && reg[1] == block / 2)447 break;448 }449 450 mutex_unlock(&mhdp->mbox_mutex);451 452 if (ret)453 dev_err(mhdp->dev, "get block[%d] edid failed: %d\n",454 block, ret);455 456 return ret;457}458 459static460int cdns_mhdp_read_hpd_event(struct cdns_mhdp_device *mhdp)461{462 u8 event = 0;463 int ret;464 465 mutex_lock(&mhdp->mbox_mutex);466 467 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,468 DPTX_READ_EVENT, 0, NULL);469 if (ret)470 goto out;471 472 ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX,473 DPTX_READ_EVENT, sizeof(event));474 if (ret < 0)475 goto out;476 477 ret = cdns_mhdp_mailbox_recv_data(mhdp, &event, sizeof(event));478out:479 mutex_unlock(&mhdp->mbox_mutex);480 481 if (ret < 0)482 return ret;483 484 dev_dbg(mhdp->dev, "%s: %s%s%s%s\n", __func__,485 (event & DPTX_READ_EVENT_HPD_TO_HIGH) ? "TO_HIGH " : "",486 (event & DPTX_READ_EVENT_HPD_TO_LOW) ? "TO_LOW " : "",487 (event & DPTX_READ_EVENT_HPD_PULSE) ? "PULSE " : "",488 (event & DPTX_READ_EVENT_HPD_STATE) ? "HPD_STATE " : "");489 490 return event;491}492 493static494int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp, unsigned int nlanes,495 unsigned int udelay, const u8 *lanes_data,496 u8 link_status[DP_LINK_STATUS_SIZE])497{498 u8 payload[7];499 u8 hdr[5]; /* For DPCD read response header */500 u32 addr;501 int ret;502 503 if (nlanes != 4 && nlanes != 2 && nlanes != 1) {504 dev_err(mhdp->dev, "invalid number of lanes: %u\n", nlanes);505 ret = -EINVAL;506 goto out;507 }508 509 payload[0] = nlanes;510 put_unaligned_be16(udelay, payload + 1);511 memcpy(payload + 3, lanes_data, nlanes);512 513 mutex_lock(&mhdp->mbox_mutex);514 515 ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,516 DPTX_ADJUST_LT,517 sizeof(payload), payload);518 if (ret)519 goto out;520 521 /* Yes, read the DPCD read command response */522 ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX,523 DPTX_READ_DPCD,524 sizeof(hdr) + DP_LINK_STATUS_SIZE);525 if (ret)526 goto out;527 528 ret = cdns_mhdp_mailbox_recv_data(mhdp, hdr, sizeof(hdr));529 if (ret)530 goto out;531 532 addr = get_unaligned_be24(hdr + 2);533 if (addr != DP_LANE0_1_STATUS)534 goto out;535 536 ret = cdns_mhdp_mailbox_recv_data(mhdp, link_status,537 DP_LINK_STATUS_SIZE);538 539out:540 mutex_unlock(&mhdp->mbox_mutex);541 542 if (ret)543 dev_err(mhdp->dev, "Failed to adjust Link Training.\n");544 545 return ret;546}547 548/**549 * cdns_mhdp_link_power_up() - power up a DisplayPort link550 * @aux: DisplayPort AUX channel551 * @link: pointer to a structure containing the link configuration552 *553 * Returns 0 on success or a negative error code on failure.554 */555static556int cdns_mhdp_link_power_up(struct drm_dp_aux *aux, struct cdns_mhdp_link *link)557{558 u8 value;559 int err;560 561 /* DP_SET_POWER register is only available on DPCD v1.1 and later */562 if (link->revision < 0x11)563 return 0;564 565 err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);566 if (err < 0)567 return err;568 569 value &= ~DP_SET_POWER_MASK;570 value |= DP_SET_POWER_D0;571 572 err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);573 if (err < 0)574 return err;575 576 /*577 * According to the DP 1.1 specification, a "Sink Device must exit the578 * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink579 * Control Field" (register 0x600).580 */581 usleep_range(1000, 2000);582 583 return 0;584}585 586/**587 * cdns_mhdp_link_power_down() - power down a DisplayPort link588 * @aux: DisplayPort AUX channel589 * @link: pointer to a structure containing the link configuration590 *591 * Returns 0 on success or a negative error code on failure.592 */593static594int cdns_mhdp_link_power_down(struct drm_dp_aux *aux,595 struct cdns_mhdp_link *link)596{597 u8 value;598 int err;599 600 /* DP_SET_POWER register is only available on DPCD v1.1 and later */601 if (link->revision < 0x11)602 return 0;603 604 err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);605 if (err < 0)606 return err;607 608 value &= ~DP_SET_POWER_MASK;609 value |= DP_SET_POWER_D3;610 611 err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);612 if (err < 0)613 return err;614 615 return 0;616}617 618/**619 * cdns_mhdp_link_configure() - configure a DisplayPort link620 * @aux: DisplayPort AUX channel621 * @link: pointer to a structure containing the link configuration622 *623 * Returns 0 on success or a negative error code on failure.624 */625static626int cdns_mhdp_link_configure(struct drm_dp_aux *aux,627 struct cdns_mhdp_link *link)628{629 u8 values[2];630 int err;631 632 values[0] = drm_dp_link_rate_to_bw_code(link->rate);633 values[1] = link->num_lanes;634 635 if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING)636 values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;637 638 err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));639 if (err < 0)640 return err;641 642 return 0;643}644 645static unsigned int cdns_mhdp_max_link_rate(struct cdns_mhdp_device *mhdp)646{647 return min(mhdp->host.link_rate, mhdp->sink.link_rate);648}649 650static u8 cdns_mhdp_max_num_lanes(struct cdns_mhdp_device *mhdp)651{652 return min(mhdp->sink.lanes_cnt, mhdp->host.lanes_cnt);653}654 655static u8 cdns_mhdp_eq_training_pattern_supported(struct cdns_mhdp_device *mhdp)656{657 return fls(mhdp->host.pattern_supp & mhdp->sink.pattern_supp);658}659 660static bool cdns_mhdp_get_ssc_supported(struct cdns_mhdp_device *mhdp)661{662 /* Check if SSC is supported by both sides */663 return mhdp->host.ssc && mhdp->sink.ssc;664}665 666static enum drm_connector_status cdns_mhdp_detect(struct cdns_mhdp_device *mhdp)667{668 dev_dbg(mhdp->dev, "%s: %d\n", __func__, mhdp->plugged);669 670 if (mhdp->plugged)671 return connector_status_connected;672 else673 return connector_status_disconnected;674}675 676static int cdns_mhdp_check_fw_version(struct cdns_mhdp_device *mhdp)677{678 u32 major_num, minor_num, revision;679 u32 fw_ver, lib_ver;680 681 fw_ver = (readl(mhdp->regs + CDNS_VER_H) << 8)682 | readl(mhdp->regs + CDNS_VER_L);683 684 lib_ver = (readl(mhdp->regs + CDNS_LIB_H_ADDR) << 8)685 | readl(mhdp->regs + CDNS_LIB_L_ADDR);686 687 if (lib_ver < 33984) {688 /*689 * Older FW versions with major number 1, used to store FW690 * version information by storing repository revision number691 * in registers. This is for identifying these FW versions.692 */693 major_num = 1;694 minor_num = 2;695 if (fw_ver == 26098) {696 revision = 15;697 } else if (lib_ver == 0 && fw_ver == 0) {698 revision = 17;699 } else {700 dev_err(mhdp->dev, "Unsupported FW version: fw_ver = %u, lib_ver = %u\n",701 fw_ver, lib_ver);702 return -ENODEV;703 }704 } else {705 /* To identify newer FW versions with major number 2 onwards. */706 major_num = fw_ver / 10000;707 minor_num = (fw_ver / 100) % 100;708 revision = (fw_ver % 10000) % 100;709 }710 711 dev_dbg(mhdp->dev, "FW version: v%u.%u.%u\n", major_num, minor_num,712 revision);713 return 0;714}715 716static int cdns_mhdp_fw_activate(const struct firmware *fw,717 struct cdns_mhdp_device *mhdp)718{719 unsigned int reg;720 int ret;721 722 /* Release uCPU reset and stall it. */723 writel(CDNS_CPU_STALL, mhdp->regs + CDNS_APB_CTRL);724 725 memcpy_toio(mhdp->regs + CDNS_MHDP_IMEM, fw->data, fw->size);726 727 /* Leave debug mode, release stall */728 writel(0, mhdp->regs + CDNS_APB_CTRL);729 730 /*731 * Wait for the KEEP_ALIVE "message" on the first 8 bits.732 * Updated each sched "tick" (~2ms)733 */734 ret = readl_poll_timeout(mhdp->regs + CDNS_KEEP_ALIVE, reg,735 reg & CDNS_KEEP_ALIVE_MASK, 500,736 CDNS_KEEP_ALIVE_TIMEOUT);737 if (ret) {738 dev_err(mhdp->dev,739 "device didn't give any life sign: reg %d\n", reg);740 return ret;741 }742 743 ret = cdns_mhdp_check_fw_version(mhdp);744 if (ret)745 return ret;746 747 /* Init events to 0 as it's not cleared by FW at boot but on read */748 readl(mhdp->regs + CDNS_SW_EVENT0);749 readl(mhdp->regs + CDNS_SW_EVENT1);750 readl(mhdp->regs + CDNS_SW_EVENT2);751 readl(mhdp->regs + CDNS_SW_EVENT3);752 753 /* Activate uCPU */754 ret = cdns_mhdp_set_firmware_active(mhdp, true);755 if (ret)756 return ret;757 758 spin_lock(&mhdp->start_lock);759 760 mhdp->hw_state = MHDP_HW_READY;761 762 /*763 * Here we must keep the lock while enabling the interrupts764 * since it would otherwise be possible that interrupt enable765 * code is executed after the bridge is detached. The similar766 * situation is not possible in attach()/detach() callbacks767 * since the hw_state changes from MHDP_HW_READY to768 * MHDP_HW_STOPPED happens only due to driver removal when769 * bridge should already be detached.770 */771 cdns_mhdp_bridge_hpd_enable(&mhdp->bridge);772 773 spin_unlock(&mhdp->start_lock);774 775 wake_up(&mhdp->fw_load_wq);776 dev_dbg(mhdp->dev, "DP FW activated\n");777 778 return 0;779}780 781static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context)782{783 struct cdns_mhdp_device *mhdp = context;784 bool bridge_attached;785 int ret;786 787 dev_dbg(mhdp->dev, "firmware callback\n");788 789 if (!fw || !fw->data) {790 dev_err(mhdp->dev, "%s: No firmware.\n", __func__);791 return;792 }793 794 ret = cdns_mhdp_fw_activate(fw, mhdp);795 796 release_firmware(fw);797 798 if (ret)799 return;800 801 /*802 * XXX how to make sure the bridge is still attached when803 * calling drm_kms_helper_hotplug_event() after releasing804 * the lock? We should not hold the spin lock when805 * calling drm_kms_helper_hotplug_event() since it may806 * cause a dead lock. FB-dev console calls detect from the807 * same thread just down the call stack started here.808 */809 spin_lock(&mhdp->start_lock);810 bridge_attached = mhdp->bridge_attached;811 spin_unlock(&mhdp->start_lock);812 if (bridge_attached) {813 if (mhdp->connector.dev)814 drm_kms_helper_hotplug_event(mhdp->bridge.dev);815 else816 drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));817 }818}819 820static int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp)821{822 int ret;823 824 ret = request_firmware_nowait(THIS_MODULE, true, FW_NAME, mhdp->dev,825 GFP_KERNEL, mhdp, cdns_mhdp_fw_cb);826 if (ret) {827 dev_err(mhdp->dev, "failed to load firmware (%s), ret: %d\n",828 FW_NAME, ret);829 return ret;830 }831 832 return 0;833}834 835static ssize_t cdns_mhdp_transfer(struct drm_dp_aux *aux,836 struct drm_dp_aux_msg *msg)837{838 struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);839 int ret;840 841 if (msg->request != DP_AUX_NATIVE_WRITE &&842 msg->request != DP_AUX_NATIVE_READ)843 return -EOPNOTSUPP;844 845 if (msg->request == DP_AUX_NATIVE_WRITE) {846 const u8 *buf = msg->buffer;847 unsigned int i;848 849 for (i = 0; i < msg->size; ++i) {850 ret = cdns_mhdp_dpcd_write(mhdp,851 msg->address + i, buf[i]);852 if (!ret)853 continue;854 855 dev_err(mhdp->dev,856 "Failed to write DPCD addr %u\n",857 msg->address + i);858 859 return ret;860 }861 } else {862 ret = cdns_mhdp_dpcd_read(mhdp, msg->address,863 msg->buffer, msg->size);864 if (ret) {865 dev_err(mhdp->dev,866 "Failed to read DPCD addr %u\n",867 msg->address);868 869 return ret;870 }871 }872 873 return msg->size;874}875 876static int cdns_mhdp_link_training_init(struct cdns_mhdp_device *mhdp)877{878 union phy_configure_opts phy_cfg;879 u32 reg32;880 int ret;881 882 drm_dp_dpcd_writeb(&mhdp->aux, DP_TRAINING_PATTERN_SET,883 DP_TRAINING_PATTERN_DISABLE);884 885 /* Reset PHY configuration */886 reg32 = CDNS_PHY_COMMON_CONFIG | CDNS_PHY_TRAINING_TYPE(1);887 if (!mhdp->host.scrambler)888 reg32 |= CDNS_PHY_SCRAMBLER_BYPASS;889 890 cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, reg32);891 892 cdns_mhdp_reg_write(mhdp, CDNS_DP_ENHNCD,893 mhdp->sink.enhanced & mhdp->host.enhanced);894 895 cdns_mhdp_reg_write(mhdp, CDNS_DP_LANE_EN,896 CDNS_DP_LANE_EN_LANES(mhdp->link.num_lanes));897 898 cdns_mhdp_link_configure(&mhdp->aux, &mhdp->link);899 phy_cfg.dp.link_rate = mhdp->link.rate / 100;900 phy_cfg.dp.lanes = mhdp->link.num_lanes;901 902 memset(phy_cfg.dp.voltage, 0, sizeof(phy_cfg.dp.voltage));903 memset(phy_cfg.dp.pre, 0, sizeof(phy_cfg.dp.pre));904 905 phy_cfg.dp.ssc = cdns_mhdp_get_ssc_supported(mhdp);906 phy_cfg.dp.set_lanes = true;907 phy_cfg.dp.set_rate = true;908 phy_cfg.dp.set_voltages = true;909 ret = phy_configure(mhdp->phy, &phy_cfg);910 if (ret) {911 dev_err(mhdp->dev, "%s: phy_configure() failed: %d\n",912 __func__, ret);913 return ret;914 }915 916 cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG,917 CDNS_PHY_COMMON_CONFIG |918 CDNS_PHY_TRAINING_EN |919 CDNS_PHY_TRAINING_TYPE(1) |920 CDNS_PHY_SCRAMBLER_BYPASS);921 922 drm_dp_dpcd_writeb(&mhdp->aux, DP_TRAINING_PATTERN_SET,923 DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE);924 925 return 0;926}927 928static void cdns_mhdp_get_adjust_train(struct cdns_mhdp_device *mhdp,929 u8 link_status[DP_LINK_STATUS_SIZE],930 u8 lanes_data[CDNS_DP_MAX_NUM_LANES],931 union phy_configure_opts *phy_cfg)932{933 u8 adjust, max_pre_emph, max_volt_swing;934 u8 set_volt, set_pre;935 unsigned int i;936 937 max_pre_emph = CDNS_PRE_EMPHASIS(mhdp->host.pre_emphasis)938 << DP_TRAIN_PRE_EMPHASIS_SHIFT;939 max_volt_swing = CDNS_VOLT_SWING(mhdp->host.volt_swing);940 941 for (i = 0; i < mhdp->link.num_lanes; i++) {942 /* Check if Voltage swing and pre-emphasis are within limits */943 adjust = drm_dp_get_adjust_request_voltage(link_status, i);944 set_volt = min(adjust, max_volt_swing);945 946 adjust = drm_dp_get_adjust_request_pre_emphasis(link_status, i);947 set_pre = min(adjust, max_pre_emph)948 >> DP_TRAIN_PRE_EMPHASIS_SHIFT;949 950 /*951 * Voltage swing level and pre-emphasis level combination is952 * not allowed: leaving pre-emphasis as-is, and adjusting953 * voltage swing.954 */955 if (set_volt + set_pre > 3)956 set_volt = 3 - set_pre;957 958 phy_cfg->dp.voltage[i] = set_volt;959 lanes_data[i] = set_volt;960 961 if (set_volt == max_volt_swing)962 lanes_data[i] |= DP_TRAIN_MAX_SWING_REACHED;963 964 phy_cfg->dp.pre[i] = set_pre;965 lanes_data[i] |= (set_pre << DP_TRAIN_PRE_EMPHASIS_SHIFT);966 967 if (set_pre == (max_pre_emph >> DP_TRAIN_PRE_EMPHASIS_SHIFT))968 lanes_data[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;969 }970}971 972static973void cdns_mhdp_set_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],974 unsigned int lane, u8 volt)975{976 unsigned int s = ((lane & 1) ?977 DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :978 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);979 unsigned int idx = DP_ADJUST_REQUEST_LANE0_1 - DP_LANE0_1_STATUS + (lane >> 1);980 981 link_status[idx] &= ~(DP_ADJUST_VOLTAGE_SWING_LANE0_MASK << s);982 link_status[idx] |= volt << s;983}984 985static986void cdns_mhdp_set_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],987 unsigned int lane, u8 pre_emphasis)988{989 unsigned int s = ((lane & 1) ?990 DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :991 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);992 unsigned int idx = DP_ADJUST_REQUEST_LANE0_1 - DP_LANE0_1_STATUS + (lane >> 1);993 994 link_status[idx] &= ~(DP_ADJUST_PRE_EMPHASIS_LANE0_MASK << s);995 link_status[idx] |= pre_emphasis << s;996}997 998static void cdns_mhdp_adjust_requested_eq(struct cdns_mhdp_device *mhdp,999 u8 link_status[DP_LINK_STATUS_SIZE])1000{1001 u8 max_pre = CDNS_PRE_EMPHASIS(mhdp->host.pre_emphasis);1002 u8 max_volt = CDNS_VOLT_SWING(mhdp->host.volt_swing);1003 unsigned int i;1004 u8 volt, pre;1005 1006 for (i = 0; i < mhdp->link.num_lanes; i++) {1007 volt = drm_dp_get_adjust_request_voltage(link_status, i);1008 pre = drm_dp_get_adjust_request_pre_emphasis(link_status, i);1009 if (volt + pre > 3)1010 cdns_mhdp_set_adjust_request_voltage(link_status, i,1011 3 - pre);1012 if (mhdp->host.volt_swing & CDNS_FORCE_VOLT_SWING)1013 cdns_mhdp_set_adjust_request_voltage(link_status, i,1014 max_volt);1015 if (mhdp->host.pre_emphasis & CDNS_FORCE_PRE_EMPHASIS)1016 cdns_mhdp_set_adjust_request_pre_emphasis(link_status,1017 i, max_pre);1018 }1019}1020 1021static void cdns_mhdp_print_lt_status(const char *prefix,1022 struct cdns_mhdp_device *mhdp,1023 union phy_configure_opts *phy_cfg)1024{1025 char vs[8] = "0/0/0/0";1026 char pe[8] = "0/0/0/0";1027 unsigned int i;1028 1029 for (i = 0; i < mhdp->link.num_lanes; i++) {1030 vs[i * 2] = '0' + phy_cfg->dp.voltage[i];1031 pe[i * 2] = '0' + phy_cfg->dp.pre[i];1032 }1033 1034 vs[i * 2 - 1] = '\0';1035 pe[i * 2 - 1] = '\0';1036 1037 dev_dbg(mhdp->dev, "%s, %u lanes, %u Mbps, vs %s, pe %s\n",1038 prefix,1039 mhdp->link.num_lanes, mhdp->link.rate / 100,1040 vs, pe);1041}1042 1043static bool cdns_mhdp_link_training_channel_eq(struct cdns_mhdp_device *mhdp,1044 u8 eq_tps,1045 unsigned int training_interval)1046{1047 u8 lanes_data[CDNS_DP_MAX_NUM_LANES], fail_counter_short = 0;1048 u8 link_status[DP_LINK_STATUS_SIZE];1049 union phy_configure_opts phy_cfg;1050 u32 reg32;1051 int ret;1052 bool r;1053 1054 dev_dbg(mhdp->dev, "Starting EQ phase\n");1055 1056 /* Enable link training TPS[eq_tps] in PHY */1057 reg32 = CDNS_PHY_COMMON_CONFIG | CDNS_PHY_TRAINING_EN |1058 CDNS_PHY_TRAINING_TYPE(eq_tps);1059 if (eq_tps != 4)1060 reg32 |= CDNS_PHY_SCRAMBLER_BYPASS;1061 cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, reg32);1062 1063 drm_dp_dpcd_writeb(&mhdp->aux, DP_TRAINING_PATTERN_SET,1064 (eq_tps != 4) ? eq_tps | DP_LINK_SCRAMBLING_DISABLE :1065 CDNS_DP_TRAINING_PATTERN_4);1066 1067 drm_dp_dpcd_read_link_status(&mhdp->aux, link_status);1068 1069 do {1070 cdns_mhdp_get_adjust_train(mhdp, link_status, lanes_data,1071 &phy_cfg);1072 phy_cfg.dp.lanes = mhdp->link.num_lanes;1073 phy_cfg.dp.ssc = cdns_mhdp_get_ssc_supported(mhdp);1074 phy_cfg.dp.set_lanes = false;1075 phy_cfg.dp.set_rate = false;1076 phy_cfg.dp.set_voltages = true;1077 ret = phy_configure(mhdp->phy, &phy_cfg);1078 if (ret) {1079 dev_err(mhdp->dev, "%s: phy_configure() failed: %d\n",1080 __func__, ret);1081 goto err;1082 }1083 1084 cdns_mhdp_adjust_lt(mhdp, mhdp->link.num_lanes,1085 training_interval, lanes_data, link_status);1086 1087 r = drm_dp_clock_recovery_ok(link_status, mhdp->link.num_lanes);1088 if (!r)1089 goto err;1090 1091 if (drm_dp_channel_eq_ok(link_status, mhdp->link.num_lanes)) {1092 cdns_mhdp_print_lt_status("EQ phase ok", mhdp,1093 &phy_cfg);1094 return true;1095 }1096 1097 fail_counter_short++;1098 1099 cdns_mhdp_adjust_requested_eq(mhdp, link_status);1100 } while (fail_counter_short < 5);1101 1102err:1103 cdns_mhdp_print_lt_status("EQ phase failed", mhdp, &phy_cfg);1104 1105 return false;1106}1107 1108static void cdns_mhdp_adjust_requested_cr(struct cdns_mhdp_device *mhdp,1109 u8 link_status[DP_LINK_STATUS_SIZE],1110 u8 *req_volt, u8 *req_pre)1111{1112 const u8 max_volt = CDNS_VOLT_SWING(mhdp->host.volt_swing);1113 const u8 max_pre = CDNS_PRE_EMPHASIS(mhdp->host.pre_emphasis);1114 unsigned int i;1115 1116 for (i = 0; i < mhdp->link.num_lanes; i++) {1117 u8 val;1118 1119 val = mhdp->host.volt_swing & CDNS_FORCE_VOLT_SWING ?1120 max_volt : req_volt[i];1121 cdns_mhdp_set_adjust_request_voltage(link_status, i, val);1122 1123 val = mhdp->host.pre_emphasis & CDNS_FORCE_PRE_EMPHASIS ?1124 max_pre : req_pre[i];1125 cdns_mhdp_set_adjust_request_pre_emphasis(link_status, i, val);1126 }1127}1128 1129static1130void cdns_mhdp_validate_cr(struct cdns_mhdp_device *mhdp, bool *cr_done,1131 bool *same_before_adjust, bool *max_swing_reached,1132 u8 before_cr[CDNS_DP_MAX_NUM_LANES],1133 u8 after_cr[DP_LINK_STATUS_SIZE], u8 *req_volt,1134 u8 *req_pre)1135{1136 const u8 max_volt = CDNS_VOLT_SWING(mhdp->host.volt_swing);1137 const u8 max_pre = CDNS_PRE_EMPHASIS(mhdp->host.pre_emphasis);1138 bool same_pre, same_volt;1139 unsigned int i;1140 u8 adjust;1141 1142 *same_before_adjust = false;1143 *max_swing_reached = false;1144 *cr_done = drm_dp_clock_recovery_ok(after_cr, mhdp->link.num_lanes);1145 1146 for (i = 0; i < mhdp->link.num_lanes; i++) {1147 adjust = drm_dp_get_adjust_request_voltage(after_cr, i);1148 req_volt[i] = min(adjust, max_volt);1149 1150 adjust = drm_dp_get_adjust_request_pre_emphasis(after_cr, i) >>1151 DP_TRAIN_PRE_EMPHASIS_SHIFT;1152 req_pre[i] = min(adjust, max_pre);1153 1154 same_pre = (before_cr[i] & DP_TRAIN_PRE_EMPHASIS_MASK) ==1155 req_pre[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT;1156 same_volt = (before_cr[i] & DP_TRAIN_VOLTAGE_SWING_MASK) ==1157 req_volt[i];1158 if (same_pre && same_volt)1159 *same_before_adjust = true;1160 1161 /* 3.1.5.2 in DP Standard v1.4. Table 3-1 */1162 if (!*cr_done && req_volt[i] + req_pre[i] >= 3) {1163 *max_swing_reached = true;1164 return;1165 }1166 }1167}1168 1169static bool cdns_mhdp_link_training_cr(struct cdns_mhdp_device *mhdp)1170{1171 u8 lanes_data[CDNS_DP_MAX_NUM_LANES],1172 fail_counter_short = 0, fail_counter_cr_long = 0;1173 u8 link_status[DP_LINK_STATUS_SIZE];1174 bool cr_done;1175 union phy_configure_opts phy_cfg;1176 int ret;1177 1178 dev_dbg(mhdp->dev, "Starting CR phase\n");1179 1180 ret = cdns_mhdp_link_training_init(mhdp);1181 if (ret)1182 goto err;1183 1184 drm_dp_dpcd_read_link_status(&mhdp->aux, link_status);1185 1186 do {1187 u8 requested_adjust_volt_swing[CDNS_DP_MAX_NUM_LANES] = {};1188 u8 requested_adjust_pre_emphasis[CDNS_DP_MAX_NUM_LANES] = {};1189 bool same_before_adjust, max_swing_reached;1190 1191 cdns_mhdp_get_adjust_train(mhdp, link_status, lanes_data,1192 &phy_cfg);1193 phy_cfg.dp.lanes = mhdp->link.num_lanes;1194 phy_cfg.dp.ssc = cdns_mhdp_get_ssc_supported(mhdp);1195 phy_cfg.dp.set_lanes = false;1196 phy_cfg.dp.set_rate = false;1197 phy_cfg.dp.set_voltages = true;1198 ret = phy_configure(mhdp->phy, &phy_cfg);1199 if (ret) {1200 dev_err(mhdp->dev, "%s: phy_configure() failed: %d\n",1201 __func__, ret);1202 goto err;1203 }1204 1205 cdns_mhdp_adjust_lt(mhdp, mhdp->link.num_lanes, 100,1206 lanes_data, link_status);1207 1208 cdns_mhdp_validate_cr(mhdp, &cr_done, &same_before_adjust,1209 &max_swing_reached, lanes_data,1210 link_status,1211 requested_adjust_volt_swing,1212 requested_adjust_pre_emphasis);1213 1214 if (max_swing_reached) {1215 dev_err(mhdp->dev, "CR: max swing reached\n");1216 goto err;1217 }1218 1219 if (cr_done) {1220 cdns_mhdp_print_lt_status("CR phase ok", mhdp,1221 &phy_cfg);1222 return true;1223 }1224 1225 /* Not all CR_DONE bits set */1226 fail_counter_cr_long++;1227 1228 if (same_before_adjust) {1229 fail_counter_short++;1230 continue;1231 }1232 1233 fail_counter_short = 0;1234 /*1235 * Voltage swing/pre-emphasis adjust requested1236 * during CR phase1237 */1238 cdns_mhdp_adjust_requested_cr(mhdp, link_status,1239 requested_adjust_volt_swing,1240 requested_adjust_pre_emphasis);1241 } while (fail_counter_short < 5 && fail_counter_cr_long < 10);1242 1243err:1244 cdns_mhdp_print_lt_status("CR phase failed", mhdp, &phy_cfg);1245 1246 return false;1247}1248 1249static void cdns_mhdp_lower_link_rate(struct cdns_mhdp_link *link)1250{1251 switch (drm_dp_link_rate_to_bw_code(link->rate)) {1252 case DP_LINK_BW_2_7:1253 link->rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_1_62);1254 break;1255 case DP_LINK_BW_5_4:1256 link->rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_2_7);1257 break;1258 case DP_LINK_BW_8_1:1259 link->rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4);1260 break;1261 }1262}1263 1264static int cdns_mhdp_link_training(struct cdns_mhdp_device *mhdp,1265 unsigned int training_interval)1266{1267 u32 reg32;1268 const u8 eq_tps = cdns_mhdp_eq_training_pattern_supported(mhdp);1269 int ret;1270 1271 while (1) {1272 if (!cdns_mhdp_link_training_cr(mhdp)) {1273 if (drm_dp_link_rate_to_bw_code(mhdp->link.rate) !=1274 DP_LINK_BW_1_62) {1275 dev_dbg(mhdp->dev,1276 "Reducing link rate during CR phase\n");1277 cdns_mhdp_lower_link_rate(&mhdp->link);1278 1279 continue;1280 } else if (mhdp->link.num_lanes > 1) {1281 dev_dbg(mhdp->dev,1282 "Reducing lanes number during CR phase\n");1283 mhdp->link.num_lanes >>= 1;1284 mhdp->link.rate = cdns_mhdp_max_link_rate(mhdp);1285 1286 continue;1287 }1288 1289 dev_err(mhdp->dev,1290 "Link training failed during CR phase\n");1291 goto err;1292 }1293 1294 if (cdns_mhdp_link_training_channel_eq(mhdp, eq_tps,1295 training_interval))1296 break;1297 1298 if (mhdp->link.num_lanes > 1) {1299 dev_dbg(mhdp->dev,1300 "Reducing lanes number during EQ phase\n");1301 mhdp->link.num_lanes >>= 1;1302 1303 continue;1304 } else if (drm_dp_link_rate_to_bw_code(mhdp->link.rate) !=1305 DP_LINK_BW_1_62) {1306 dev_dbg(mhdp->dev,1307 "Reducing link rate during EQ phase\n");1308 cdns_mhdp_lower_link_rate(&mhdp->link);1309 mhdp->link.num_lanes = cdns_mhdp_max_num_lanes(mhdp);1310 1311 continue;1312 }1313 1314 dev_err(mhdp->dev, "Link training failed during EQ phase\n");1315 goto err;1316 }1317 1318 dev_dbg(mhdp->dev, "Link training ok. Lanes: %u, Rate %u Mbps\n",1319 mhdp->link.num_lanes, mhdp->link.rate / 100);1320 1321 drm_dp_dpcd_writeb(&mhdp->aux, DP_TRAINING_PATTERN_SET,1322 mhdp->host.scrambler ? 0 :1323 DP_LINK_SCRAMBLING_DISABLE);1324 1325 ret = cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, ®32);1326 if (ret < 0) {1327 dev_err(mhdp->dev,1328 "Failed to read CDNS_DP_FRAMER_GLOBAL_CONFIG %d\n",1329 ret);1330 return ret;1331 }1332 reg32 &= ~GENMASK(1, 0);1333 reg32 |= CDNS_DP_NUM_LANES(mhdp->link.num_lanes);1334 reg32 |= CDNS_DP_WR_FAILING_EDGE_VSYNC;1335 reg32 |= CDNS_DP_FRAMER_EN;1336 cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, reg32);1337 1338 /* Reset PHY config */1339 reg32 = CDNS_PHY_COMMON_CONFIG | CDNS_PHY_TRAINING_TYPE(1);1340 if (!mhdp->host.scrambler)1341 reg32 |= CDNS_PHY_SCRAMBLER_BYPASS;1342 cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, reg32);1343 1344 return 0;1345err:1346 /* Reset PHY config */1347 reg32 = CDNS_PHY_COMMON_CONFIG | CDNS_PHY_TRAINING_TYPE(1);1348 if (!mhdp->host.scrambler)1349 reg32 |= CDNS_PHY_SCRAMBLER_BYPASS;1350 cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, reg32);1351 1352 drm_dp_dpcd_writeb(&mhdp->aux, DP_TRAINING_PATTERN_SET,1353 DP_TRAINING_PATTERN_DISABLE);1354 1355 return -EIO;1356}1357 1358static u32 cdns_mhdp_get_training_interval_us(struct cdns_mhdp_device *mhdp,1359 u32 interval)1360{1361 if (interval == 0)1362 return 400;1363 if (interval < 5)1364 return 4000 << (interval - 1);1365 dev_err(mhdp->dev,1366 "wrong training interval returned by DPCD: %d\n", interval);1367 return 0;1368}1369 1370static void cdns_mhdp_fill_host_caps(struct cdns_mhdp_device *mhdp)1371{1372 unsigned int link_rate;1373 1374 /* Get source capabilities based on PHY attributes */1375 1376 mhdp->host.lanes_cnt = mhdp->phy->attrs.bus_width;1377 if (!mhdp->host.lanes_cnt)1378 mhdp->host.lanes_cnt = 4;1379 1380 link_rate = mhdp->phy->attrs.max_link_rate;1381 if (!link_rate)1382 link_rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_8_1);1383 else1384 /* PHY uses Mb/s, DRM uses tens of kb/s. */1385 link_rate *= 100;1386 1387 mhdp->host.link_rate = link_rate;1388 mhdp->host.volt_swing = CDNS_VOLT_SWING(3);1389 mhdp->host.pre_emphasis = CDNS_PRE_EMPHASIS(3);1390 mhdp->host.pattern_supp = CDNS_SUPPORT_TPS(1) |1391 CDNS_SUPPORT_TPS(2) | CDNS_SUPPORT_TPS(3) |1392 CDNS_SUPPORT_TPS(4);1393 mhdp->host.lane_mapping = CDNS_LANE_MAPPING_NORMAL;1394 mhdp->host.fast_link = false;1395 mhdp->host.enhanced = true;1396 mhdp->host.scrambler = true;1397 mhdp->host.ssc = false;1398}1399 1400static void cdns_mhdp_fill_sink_caps(struct cdns_mhdp_device *mhdp,1401 u8 dpcd[DP_RECEIVER_CAP_SIZE])1402{1403 mhdp->sink.link_rate = mhdp->link.rate;1404 mhdp->sink.lanes_cnt = mhdp->link.num_lanes;1405 mhdp->sink.enhanced = !!(mhdp->link.capabilities &1406 DP_LINK_CAP_ENHANCED_FRAMING);1407 1408 /* Set SSC support */1409 mhdp->sink.ssc = !!(dpcd[DP_MAX_DOWNSPREAD] &1410 DP_MAX_DOWNSPREAD_0_5);1411 1412 /* Set TPS support */1413 mhdp->sink.pattern_supp = CDNS_SUPPORT_TPS(1) | CDNS_SUPPORT_TPS(2);1414 if (drm_dp_tps3_supported(dpcd))1415 mhdp->sink.pattern_supp |= CDNS_SUPPORT_TPS(3);1416 if (drm_dp_tps4_supported(dpcd))1417 mhdp->sink.pattern_supp |= CDNS_SUPPORT_TPS(4);1418 1419 /* Set fast link support */1420 mhdp->sink.fast_link = !!(dpcd[DP_MAX_DOWNSPREAD] &1421 DP_NO_AUX_HANDSHAKE_LINK_TRAINING);1422}1423 1424static int cdns_mhdp_link_up(struct cdns_mhdp_device *mhdp)1425{1426 u8 dpcd[DP_RECEIVER_CAP_SIZE], amp[2];1427 u32 resp, interval, interval_us;1428 u8 ext_cap_chk = 0;1429 unsigned int addr;1430 int err;1431 1432 WARN_ON(!mutex_is_locked(&mhdp->link_mutex));1433 1434 drm_dp_dpcd_readb(&mhdp->aux, DP_TRAINING_AUX_RD_INTERVAL,1435 &ext_cap_chk);1436 1437 if (ext_cap_chk & DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT)1438 addr = DP_DP13_DPCD_REV;1439 else1440 addr = DP_DPCD_REV;1441 1442 err = drm_dp_dpcd_read(&mhdp->aux, addr, dpcd, DP_RECEIVER_CAP_SIZE);1443 if (err < 0) {1444 dev_err(mhdp->dev, "Failed to read receiver capabilities\n");1445 return err;1446 }1447 1448 mhdp->link.revision = dpcd[0];1449 mhdp->link.rate = drm_dp_bw_code_to_link_rate(dpcd[1]);1450 mhdp->link.num_lanes = dpcd[2] & DP_MAX_LANE_COUNT_MASK;1451 1452 if (dpcd[2] & DP_ENHANCED_FRAME_CAP)1453 mhdp->link.capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;1454 1455 dev_dbg(mhdp->dev, "Set sink device power state via DPCD\n");1456 cdns_mhdp_link_power_up(&mhdp->aux, &mhdp->link);1457 1458 cdns_mhdp_fill_sink_caps(mhdp, dpcd);1459 1460 mhdp->link.rate = cdns_mhdp_max_link_rate(mhdp);1461 mhdp->link.num_lanes = cdns_mhdp_max_num_lanes(mhdp);1462 1463 /* Disable framer for link training */1464 err = cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp);1465 if (err < 0) {1466 dev_err(mhdp->dev,1467 "Failed to read CDNS_DP_FRAMER_GLOBAL_CONFIG %d\n",1468 err);1469 return err;1470 }1471 1472 resp &= ~CDNS_DP_FRAMER_EN;1473 cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, resp);1474 1475 /* Spread AMP if required, enable 8b/10b coding */1476 amp[0] = cdns_mhdp_get_ssc_supported(mhdp) ? DP_SPREAD_AMP_0_5 : 0;1477 amp[1] = DP_SET_ANSI_8B10B;1478 drm_dp_dpcd_write(&mhdp->aux, DP_DOWNSPREAD_CTRL, amp, 2);1479 1480 if (mhdp->host.fast_link & mhdp->sink.fast_link) {1481 dev_err(mhdp->dev, "fastlink not supported\n");1482 return -EOPNOTSUPP;1483 }1484 1485 interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & DP_TRAINING_AUX_RD_MASK;1486 interval_us = cdns_mhdp_get_training_interval_us(mhdp, interval);1487 if (!interval_us ||1488 cdns_mhdp_link_training(mhdp, interval_us)) {1489 dev_err(mhdp->dev, "Link training failed. Exiting.\n");1490 return -EIO;1491 }1492 1493 mhdp->link_up = true;1494 1495 return 0;1496}1497 1498static void cdns_mhdp_link_down(struct cdns_mhdp_device *mhdp)1499{1500 WARN_ON(!mutex_is_locked(&mhdp->link_mutex));1501 1502 if (mhdp->plugged)1503 cdns_mhdp_link_power_down(&mhdp->aux, &mhdp->link);1504 1505 mhdp->link_up = false;1506}1507 1508static const struct drm_edid *cdns_mhdp_edid_read(struct cdns_mhdp_device *mhdp,1509 struct drm_connector *connector)1510{1511 if (!mhdp->plugged)1512 return NULL;1513 1514 return drm_edid_read_custom(connector, cdns_mhdp_get_edid_block, mhdp);1515}1516 1517static int cdns_mhdp_get_modes(struct drm_connector *connector)1518{1519 struct cdns_mhdp_device *mhdp = connector_to_mhdp(connector);1520 const struct drm_edid *drm_edid;1521 int num_modes;1522 1523 if (!mhdp->plugged)1524 return 0;1525 1526 drm_edid = cdns_mhdp_edid_read(mhdp, connector);1527 1528 drm_edid_connector_update(connector, drm_edid);1529 1530 if (!drm_edid) {1531 dev_err(mhdp->dev, "Failed to read EDID\n");1532 return 0;1533 }1534 1535 num_modes = drm_edid_connector_add_modes(connector);1536 drm_edid_free(drm_edid);1537 1538 /*1539 * HACK: Warn about unsupported display formats until we deal1540 * with them correctly.1541 */1542 if (connector->display_info.color_formats &&1543 !(connector->display_info.color_formats &1544 mhdp->display_fmt.color_format))1545 dev_warn(mhdp->dev,1546 "%s: No supported color_format found (0x%08x)\n",1547 __func__, connector->display_info.color_formats);1548 1549 if (connector->display_info.bpc &&1550 connector->display_info.bpc < mhdp->display_fmt.bpc)1551 dev_warn(mhdp->dev, "%s: Display bpc only %d < %d\n",1552 __func__, connector->display_info.bpc,1553 mhdp->display_fmt.bpc);1554 1555 return num_modes;1556}1557 1558static int cdns_mhdp_connector_detect(struct drm_connector *conn,1559 struct drm_modeset_acquire_ctx *ctx,1560 bool force)1561{1562 struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn);1563 1564 return cdns_mhdp_detect(mhdp);1565}1566 1567static u32 cdns_mhdp_get_bpp(struct cdns_mhdp_display_fmt *fmt)1568{1569 u32 bpp;1570 1571 if (fmt->y_only)1572 return fmt->bpc;1573 1574 switch (fmt->color_format) {1575 case DRM_COLOR_FORMAT_RGB444:1576 case DRM_COLOR_FORMAT_YCBCR444:1577 bpp = fmt->bpc * 3;1578 break;1579 case DRM_COLOR_FORMAT_YCBCR422:1580 bpp = fmt->bpc * 2;1581 break;1582 case DRM_COLOR_FORMAT_YCBCR420:1583 bpp = fmt->bpc * 3 / 2;1584 break;1585 default:1586 bpp = fmt->bpc * 3;1587 WARN_ON(1);1588 }1589 return bpp;1590}1591 1592static1593bool cdns_mhdp_bandwidth_ok(struct cdns_mhdp_device *mhdp,1594 const struct drm_display_mode *mode,1595 unsigned int lanes, unsigned int rate)1596{1597 u32 max_bw, req_bw, bpp;1598 1599 /*1600 * mode->clock is expressed in kHz. Multiplying by bpp and dividing by 81601 * we get the number of kB/s. DisplayPort applies a 8b-10b encoding, the1602 * value thus equals the bandwidth in 10kb/s units, which matches the1603 * units of the rate parameter.1604 */1605 1606 bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt);1607 req_bw = mode->clock * bpp / 8;1608 max_bw = lanes * rate;1609 if (req_bw > max_bw) {1610 dev_dbg(mhdp->dev,1611 "Unsupported Mode: %s, Req BW: %u, Available Max BW:%u\n",1612 mode->name, req_bw, max_bw);1613 1614 return false;1615 }1616 1617 return true;1618}1619 1620static1621enum drm_mode_status cdns_mhdp_mode_valid(struct drm_connector *conn,1622 struct drm_display_mode *mode)1623{1624 struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn);1625 1626 mutex_lock(&mhdp->link_mutex);1627 1628 if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes,1629 mhdp->link.rate)) {1630 mutex_unlock(&mhdp->link_mutex);1631 return MODE_CLOCK_HIGH;1632 }1633 1634 mutex_unlock(&mhdp->link_mutex);1635 return MODE_OK;1636}1637 1638static int cdns_mhdp_connector_atomic_check(struct drm_connector *conn,1639 struct drm_atomic_state *state)1640{1641 struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn);1642 struct drm_connector_state *old_state, *new_state;1643 struct drm_crtc_state *crtc_state;1644 u64 old_cp, new_cp;1645 1646 if (!mhdp->hdcp_supported)1647 return 0;1648 1649 old_state = drm_atomic_get_old_connector_state(state, conn);1650 new_state = drm_atomic_get_new_connector_state(state, conn);1651 old_cp = old_state->content_protection;1652 new_cp = new_state->content_protection;1653 1654 if (old_state->hdcp_content_type != new_state->hdcp_content_type &&1655 new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {1656 new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;1657 goto mode_changed;1658 }1659 1660 if (!new_state->crtc) {1661 if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)1662 new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;1663 return 0;1664 }1665 1666 if (old_cp == new_cp ||1667 (old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&1668 new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED))1669 return 0;1670 1671mode_changed:1672 crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);1673 crtc_state->mode_changed = true;1674 1675 return 0;1676}1677 1678static const struct drm_connector_helper_funcs cdns_mhdp_conn_helper_funcs = {1679 .detect_ctx = cdns_mhdp_connector_detect,1680 .get_modes = cdns_mhdp_get_modes,1681 .mode_valid = cdns_mhdp_mode_valid,1682 .atomic_check = cdns_mhdp_connector_atomic_check,1683};1684 1685static const struct drm_connector_funcs cdns_mhdp_conn_funcs = {1686 .fill_modes = drm_helper_probe_single_connector_modes,1687 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,1688 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,1689 .reset = drm_atomic_helper_connector_reset,1690 .destroy = drm_connector_cleanup,1691};1692 1693static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp)1694{1695 u32 bus_format = MEDIA_BUS_FMT_RGB121212_1X36;1696 struct drm_connector *conn = &mhdp->connector;1697 struct drm_bridge *bridge = &mhdp->bridge;1698 int ret;1699 1700 conn->polled = DRM_CONNECTOR_POLL_HPD;1701 1702 ret = drm_connector_init(bridge->dev, conn, &cdns_mhdp_conn_funcs,1703 DRM_MODE_CONNECTOR_DisplayPort);1704 if (ret) {1705 dev_err(mhdp->dev, "Failed to initialize connector with drm\n");1706 return ret;1707 }1708 1709 drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs);1710 1711 ret = drm_display_info_set_bus_formats(&conn->display_info,1712 &bus_format, 1);1713 if (ret)1714 return ret;1715 1716 ret = drm_connector_attach_encoder(conn, bridge->encoder);1717 if (ret) {1718 dev_err(mhdp->dev, "Failed to attach connector to encoder\n");1719 return ret;1720 }1721 1722 if (mhdp->hdcp_supported)1723 ret = drm_connector_attach_content_protection_property(conn, true);1724 1725 return ret;1726}1727 1728static int cdns_mhdp_attach(struct drm_bridge *bridge,1729 enum drm_bridge_attach_flags flags)1730{1731 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);1732 bool hw_ready;1733 int ret;1734 1735 dev_dbg(mhdp->dev, "%s\n", __func__);1736 1737 mhdp->aux.drm_dev = bridge->dev;1738 ret = drm_dp_aux_register(&mhdp->aux);1739 if (ret < 0)1740 return ret;1741 1742 if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {1743 ret = cdns_mhdp_connector_init(mhdp);1744 if (ret)1745 goto aux_unregister;1746 }1747 1748 spin_lock(&mhdp->start_lock);1749 1750 mhdp->bridge_attached = true;1751 hw_ready = mhdp->hw_state == MHDP_HW_READY;1752 1753 spin_unlock(&mhdp->start_lock);1754 1755 /* Enable SW event interrupts */1756 if (hw_ready)1757 cdns_mhdp_bridge_hpd_enable(bridge);1758 1759 return 0;1760aux_unregister:1761 drm_dp_aux_unregister(&mhdp->aux);1762 return ret;1763}1764 1765static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp,1766 const struct drm_display_mode *mode)1767{1768 unsigned int dp_framer_sp = 0, msa_horizontal_1,1769 msa_vertical_1, bnd_hsync2vsync, hsync2vsync_pol_ctrl,1770 misc0 = 0, misc1 = 0, pxl_repr,1771 front_porch, back_porch, msa_h0, msa_v0, hsync, vsync,1772 dp_vertical_1;1773 u8 stream_id = mhdp->stream_id;1774 u32 bpp, bpc, pxlfmt, framer;1775 int ret;1776 1777 pxlfmt = mhdp->display_fmt.color_format;1778 bpc = mhdp->display_fmt.bpc;1779 1780 /*1781 * If YCBCR supported and stream not SD, use ITU7091782 * Need to handle ITU version with YCBCR420 when supported1783 */1784 if ((pxlfmt == DRM_COLOR_FORMAT_YCBCR444 ||1785 pxlfmt == DRM_COLOR_FORMAT_YCBCR422) && mode->crtc_vdisplay >= 720)1786 misc0 = DP_YCBCR_COEFFICIENTS_ITU709;1787 1788 bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt);1789 1790 switch (pxlfmt) {1791 case DRM_COLOR_FORMAT_RGB444:1792 pxl_repr = CDNS_DP_FRAMER_RGB << CDNS_DP_FRAMER_PXL_FORMAT;1793 misc0 |= DP_COLOR_FORMAT_RGB;1794 break;1795 case DRM_COLOR_FORMAT_YCBCR444:1796 pxl_repr = CDNS_DP_FRAMER_YCBCR444 << CDNS_DP_FRAMER_PXL_FORMAT;1797 misc0 |= DP_COLOR_FORMAT_YCbCr444 | DP_TEST_DYNAMIC_RANGE_CEA;1798 break;1799 case DRM_COLOR_FORMAT_YCBCR422:1800 pxl_repr = CDNS_DP_FRAMER_YCBCR422 << CDNS_DP_FRAMER_PXL_FORMAT;1801 misc0 |= DP_COLOR_FORMAT_YCbCr422 | DP_TEST_DYNAMIC_RANGE_CEA;1802 break;1803 case DRM_COLOR_FORMAT_YCBCR420:1804 pxl_repr = CDNS_DP_FRAMER_YCBCR420 << CDNS_DP_FRAMER_PXL_FORMAT;1805 break;1806 default:1807 pxl_repr = CDNS_DP_FRAMER_Y_ONLY << CDNS_DP_FRAMER_PXL_FORMAT;1808 }1809 1810 switch (bpc) {1811 case 6:1812 misc0 |= DP_TEST_BIT_DEPTH_6;1813 pxl_repr |= CDNS_DP_FRAMER_6_BPC;1814 break;1815 case 8:1816 misc0 |= DP_TEST_BIT_DEPTH_8;1817 pxl_repr |= CDNS_DP_FRAMER_8_BPC;1818 break;1819 case 10:1820 misc0 |= DP_TEST_BIT_DEPTH_10;1821 pxl_repr |= CDNS_DP_FRAMER_10_BPC;1822 break;1823 case 12:1824 misc0 |= DP_TEST_BIT_DEPTH_12;1825 pxl_repr |= CDNS_DP_FRAMER_12_BPC;1826 break;1827 case 16:1828 misc0 |= DP_TEST_BIT_DEPTH_16;1829 pxl_repr |= CDNS_DP_FRAMER_16_BPC;1830 break;1831 }1832 1833 bnd_hsync2vsync = CDNS_IP_BYPASS_V_INTERFACE;1834 if (mode->flags & DRM_MODE_FLAG_INTERLACE)1835 bnd_hsync2vsync |= CDNS_IP_DET_INTERLACE_FORMAT;1836 1837 cdns_mhdp_reg_write(mhdp, CDNS_BND_HSYNC2VSYNC(stream_id),1838 bnd_hsync2vsync);1839 1840 hsync2vsync_pol_ctrl = 0;1841 if (mode->flags & DRM_MODE_FLAG_NHSYNC)1842 hsync2vsync_pol_ctrl |= CDNS_H2V_HSYNC_POL_ACTIVE_LOW;1843 if (mode->flags & DRM_MODE_FLAG_NVSYNC)1844 hsync2vsync_pol_ctrl |= CDNS_H2V_VSYNC_POL_ACTIVE_LOW;1845 cdns_mhdp_reg_write(mhdp, CDNS_HSYNC2VSYNC_POL_CTRL(stream_id),1846 hsync2vsync_pol_ctrl);1847 1848 cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_PXL_REPR(stream_id), pxl_repr);1849 1850 if (mode->flags & DRM_MODE_FLAG_INTERLACE)1851 dp_framer_sp |= CDNS_DP_FRAMER_INTERLACE;1852 if (mode->flags & DRM_MODE_FLAG_NHSYNC)1853 dp_framer_sp |= CDNS_DP_FRAMER_HSYNC_POL_LOW;1854 if (mode->flags & DRM_MODE_FLAG_NVSYNC)1855 dp_framer_sp |= CDNS_DP_FRAMER_VSYNC_POL_LOW;1856 cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_SP(stream_id), dp_framer_sp);1857 1858 front_porch = mode->crtc_hsync_start - mode->crtc_hdisplay;1859 back_porch = mode->crtc_htotal - mode->crtc_hsync_end;1860 cdns_mhdp_reg_write(mhdp, CDNS_DP_FRONT_BACK_PORCH(stream_id),1861 CDNS_DP_FRONT_PORCH(front_porch) |1862 CDNS_DP_BACK_PORCH(back_porch));1863 1864 cdns_mhdp_reg_write(mhdp, CDNS_DP_BYTE_COUNT(stream_id),1865 mode->crtc_hdisplay * bpp / 8);1866 1867 msa_h0 = mode->crtc_htotal - mode->crtc_hsync_start;1868 cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_HORIZONTAL_0(stream_id),1869 CDNS_DP_MSAH0_H_TOTAL(mode->crtc_htotal) |1870 CDNS_DP_MSAH0_HSYNC_START(msa_h0));1871 1872 hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;1873 msa_horizontal_1 = CDNS_DP_MSAH1_HSYNC_WIDTH(hsync) |1874 CDNS_DP_MSAH1_HDISP_WIDTH(mode->crtc_hdisplay);1875 if (mode->flags & DRM_MODE_FLAG_NHSYNC)1876 msa_horizontal_1 |= CDNS_DP_MSAH1_HSYNC_POL_LOW;1877 cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_HORIZONTAL_1(stream_id),1878 msa_horizontal_1);1879 1880 msa_v0 = mode->crtc_vtotal - mode->crtc_vsync_start;1881 cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_VERTICAL_0(stream_id),1882 CDNS_DP_MSAV0_V_TOTAL(mode->crtc_vtotal) |1883 CDNS_DP_MSAV0_VSYNC_START(msa_v0));1884 1885 vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;1886 msa_vertical_1 = CDNS_DP_MSAV1_VSYNC_WIDTH(vsync) |1887 CDNS_DP_MSAV1_VDISP_WIDTH(mode->crtc_vdisplay);1888 if (mode->flags & DRM_MODE_FLAG_NVSYNC)1889 msa_vertical_1 |= CDNS_DP_MSAV1_VSYNC_POL_LOW;1890 cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_VERTICAL_1(stream_id),1891 msa_vertical_1);1892 1893 if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&1894 mode->crtc_vtotal % 2 == 0)1895 misc1 = DP_TEST_INTERLACED;1896 if (mhdp->display_fmt.y_only)1897 misc1 |= CDNS_DP_TEST_COLOR_FORMAT_RAW_Y_ONLY;1898 /* Use VSC SDP for Y420 */1899 if (pxlfmt == DRM_COLOR_FORMAT_YCBCR420)1900 misc1 = CDNS_DP_TEST_VSC_SDP;1901 1902 cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_MISC(stream_id),1903 misc0 | (misc1 << 8));1904 1905 cdns_mhdp_reg_write(mhdp, CDNS_DP_HORIZONTAL(stream_id),1906 CDNS_DP_H_HSYNC_WIDTH(hsync) |1907 CDNS_DP_H_H_TOTAL(mode->crtc_hdisplay));1908 1909 cdns_mhdp_reg_write(mhdp, CDNS_DP_VERTICAL_0(stream_id),1910 CDNS_DP_V0_VHEIGHT(mode->crtc_vdisplay) |1911 CDNS_DP_V0_VSTART(msa_v0));1912 1913 dp_vertical_1 = CDNS_DP_V1_VTOTAL(mode->crtc_vtotal);1914 if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&1915 mode->crtc_vtotal % 2 == 0)1916 dp_vertical_1 |= CDNS_DP_V1_VTOTAL_EVEN;1917 1918 cdns_mhdp_reg_write(mhdp, CDNS_DP_VERTICAL_1(stream_id), dp_vertical_1);1919 1920 cdns_mhdp_reg_write_bit(mhdp, CDNS_DP_VB_ID(stream_id), 2, 1,1921 (mode->flags & DRM_MODE_FLAG_INTERLACE) ?1922 CDNS_DP_VB_ID_INTERLACED : 0);1923 1924 ret = cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &framer);1925 if (ret < 0) {1926 dev_err(mhdp->dev,1927 "Failed to read CDNS_DP_FRAMER_GLOBAL_CONFIG %d\n",1928 ret);1929 return;1930 }1931 framer |= CDNS_DP_FRAMER_EN;1932 framer &= ~CDNS_DP_NO_VIDEO_MODE;1933 cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, framer);1934}1935 1936static void cdns_mhdp_sst_enable(struct cdns_mhdp_device *mhdp,1937 const struct drm_display_mode *mode)1938{1939 u32 rate, vs, required_bandwidth, available_bandwidth;1940 s32 line_thresh1, line_thresh2, line_thresh = 0;1941 int pxlclock = mode->crtc_clock;1942 u32 tu_size = 64;1943 u32 bpp;1944 1945 /* Get rate in MSymbols per second per lane */1946 rate = mhdp->link.rate / 1000;1947 1948 bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt);1949 1950 required_bandwidth = pxlclock * bpp / 8;1951 available_bandwidth = mhdp->link.num_lanes * rate;1952 1953 vs = tu_size * required_bandwidth / available_bandwidth;1954 vs /= 1000;1955 1956 if (vs == tu_size)1957 vs = tu_size - 1;1958 1959 line_thresh1 = ((vs + 1) << 5) * 8 / bpp;1960 line_thresh2 = (pxlclock << 5) / 1000 / rate * (vs + 1) - (1 << 5);1961 line_thresh = line_thresh1 - line_thresh2 / (s32)mhdp->link.num_lanes;1962 line_thresh = (line_thresh >> 5) + 2;1963 1964 mhdp->stream_id = 0;1965 1966 cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_TU,1967 CDNS_DP_FRAMER_TU_VS(vs) |1968 CDNS_DP_FRAMER_TU_SIZE(tu_size) |1969 CDNS_DP_FRAMER_TU_CNT_RST_EN);1970 1971 cdns_mhdp_reg_write(mhdp, CDNS_DP_LINE_THRESH(0),1972 line_thresh & GENMASK(5, 0));1973 1974 cdns_mhdp_reg_write(mhdp, CDNS_DP_STREAM_CONFIG_2(0),1975 CDNS_DP_SC2_TU_VS_DIFF((tu_size - vs > 3) ?1976 0 : tu_size - vs));1977 1978 cdns_mhdp_configure_video(mhdp, mode);1979}1980 1981static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge,1982 struct drm_bridge_state *bridge_state)1983{1984 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);1985 struct drm_atomic_state *state = bridge_state->base.state;1986 struct cdns_mhdp_bridge_state *mhdp_state;1987 struct drm_crtc_state *crtc_state;1988 struct drm_connector *connector;1989 struct drm_connector_state *conn_state;1990 struct drm_bridge_state *new_state;1991 const struct drm_display_mode *mode;1992 u32 resp;1993 int ret;1994 1995 dev_dbg(mhdp->dev, "bridge enable\n");1996 1997 mutex_lock(&mhdp->link_mutex);1998 1999 if (mhdp->plugged && !mhdp->link_up) {2000 ret = cdns_mhdp_link_up(mhdp);2001 if (ret < 0)2002 goto out;2003 }2004 2005 if (mhdp->info && mhdp->info->ops && mhdp->info->ops->enable)2006 mhdp->info->ops->enable(mhdp);2007 2008 /* Enable VIF clock for stream 0 */2009 ret = cdns_mhdp_reg_read(mhdp, CDNS_DPTX_CAR, &resp);2010 if (ret < 0) {2011 dev_err(mhdp->dev, "Failed to read CDNS_DPTX_CAR %d\n", ret);2012 goto out;2013 }2014 2015 cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR,2016 resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN);2017 2018 connector = drm_atomic_get_new_connector_for_encoder(state,2019 bridge->encoder);2020 if (WARN_ON(!connector))2021 goto out;2022 2023 conn_state = drm_atomic_get_new_connector_state(state, connector);2024 if (WARN_ON(!conn_state))2025 goto out;2026 2027 if (mhdp->hdcp_supported &&2028 mhdp->hw_state == MHDP_HW_READY &&2029 conn_state->content_protection ==2030 DRM_MODE_CONTENT_PROTECTION_DESIRED) {2031 mutex_unlock(&mhdp->link_mutex);2032 cdns_mhdp_hdcp_enable(mhdp, conn_state->hdcp_content_type);2033 mutex_lock(&mhdp->link_mutex);2034 }2035 2036 crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);2037 if (WARN_ON(!crtc_state))2038 goto out;2039 2040 mode = &crtc_state->adjusted_mode;2041 2042 new_state = drm_atomic_get_new_bridge_state(state, bridge);2043 if (WARN_ON(!new_state))2044 goto out;2045 2046 if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes,2047 mhdp->link.rate)) {2048 ret = -EINVAL;2049 goto out;2050 }2051 2052 cdns_mhdp_sst_enable(mhdp, mode);2053 2054 mhdp_state = to_cdns_mhdp_bridge_state(new_state);2055 2056 mhdp_state->current_mode = drm_mode_duplicate(bridge->dev, mode);2057 if (!mhdp_state->current_mode)2058 return;2059 2060 drm_mode_set_name(mhdp_state->current_mode);2061 2062 dev_dbg(mhdp->dev, "%s: Enabling mode %s\n", __func__, mode->name);2063 2064 mhdp->bridge_enabled = true;2065 2066out:2067 mutex_unlock(&mhdp->link_mutex);2068 if (ret < 0)2069 schedule_work(&mhdp->modeset_retry_work);2070}2071 2072static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge,2073 struct drm_bridge_state *bridge_state)2074{2075 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);2076 u32 resp;2077 2078 dev_dbg(mhdp->dev, "%s\n", __func__);2079 2080 mutex_lock(&mhdp->link_mutex);2081 2082 if (mhdp->hdcp_supported)2083 cdns_mhdp_hdcp_disable(mhdp);2084 2085 mhdp->bridge_enabled = false;2086 cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp);2087 resp &= ~CDNS_DP_FRAMER_EN;2088 resp |= CDNS_DP_NO_VIDEO_MODE;2089 cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, resp);2090 2091 cdns_mhdp_link_down(mhdp);2092 2093 /* Disable VIF clock for stream 0 */2094 cdns_mhdp_reg_read(mhdp, CDNS_DPTX_CAR, &resp);2095 cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR,2096 resp & ~(CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN));2097 2098 if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable)2099 mhdp->info->ops->disable(mhdp);2100 2101 mutex_unlock(&mhdp->link_mutex);2102}2103 2104static void cdns_mhdp_detach(struct drm_bridge *bridge)2105{2106 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);2107 2108 dev_dbg(mhdp->dev, "%s\n", __func__);2109 2110 drm_dp_aux_unregister(&mhdp->aux);2111 2112 spin_lock(&mhdp->start_lock);2113 2114 mhdp->bridge_attached = false;2115 2116 spin_unlock(&mhdp->start_lock);2117 2118 writel(~0, mhdp->regs + CDNS_APB_INT_MASK);2119}2120 2121static struct drm_bridge_state *2122cdns_mhdp_bridge_atomic_duplicate_state(struct drm_bridge *bridge)2123{2124 struct cdns_mhdp_bridge_state *state;2125 2126 state = kzalloc(sizeof(*state), GFP_KERNEL);2127 if (!state)2128 return NULL;2129 2130 __drm_atomic_helper_bridge_duplicate_state(bridge, &state->base);2131 2132 return &state->base;2133}2134 2135static void2136cdns_mhdp_bridge_atomic_destroy_state(struct drm_bridge *bridge,2137 struct drm_bridge_state *state)2138{2139 struct cdns_mhdp_bridge_state *cdns_mhdp_state;2140 2141 cdns_mhdp_state = to_cdns_mhdp_bridge_state(state);2142 2143 if (cdns_mhdp_state->current_mode) {2144 drm_mode_destroy(bridge->dev, cdns_mhdp_state->current_mode);2145 cdns_mhdp_state->current_mode = NULL;2146 }2147 2148 kfree(cdns_mhdp_state);2149}2150 2151static struct drm_bridge_state *2152cdns_mhdp_bridge_atomic_reset(struct drm_bridge *bridge)2153{2154 struct cdns_mhdp_bridge_state *cdns_mhdp_state;2155 2156 cdns_mhdp_state = kzalloc(sizeof(*cdns_mhdp_state), GFP_KERNEL);2157 if (!cdns_mhdp_state)2158 return NULL;2159 2160 __drm_atomic_helper_bridge_reset(bridge, &cdns_mhdp_state->base);2161 2162 return &cdns_mhdp_state->base;2163}2164 2165static u32 *cdns_mhdp_get_input_bus_fmts(struct drm_bridge *bridge,2166 struct drm_bridge_state *bridge_state,2167 struct drm_crtc_state *crtc_state,2168 struct drm_connector_state *conn_state,2169 u32 output_fmt,2170 unsigned int *num_input_fmts)2171{2172 u32 *input_fmts;2173 2174 *num_input_fmts = 0;2175 2176 input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);2177 if (!input_fmts)2178 return NULL;2179 2180 *num_input_fmts = 1;2181 input_fmts[0] = MEDIA_BUS_FMT_RGB121212_1X36;2182 2183 return input_fmts;2184}2185 2186static int cdns_mhdp_atomic_check(struct drm_bridge *bridge,2187 struct drm_bridge_state *bridge_state,2188 struct drm_crtc_state *crtc_state,2189 struct drm_connector_state *conn_state)2190{2191 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);2192 const struct drm_display_mode *mode = &crtc_state->adjusted_mode;2193 2194 mutex_lock(&mhdp->link_mutex);2195 2196 if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes,2197 mhdp->link.rate)) {2198 dev_err(mhdp->dev, "%s: Not enough BW for %s (%u lanes at %u Mbps)\n",2199 __func__, mode->name, mhdp->link.num_lanes,2200 mhdp->link.rate / 100);2201 mutex_unlock(&mhdp->link_mutex);2202 return -EINVAL;2203 }2204 2205 /*2206 * There might be flags negotiation supported in future.2207 * Set the bus flags in atomic_check statically for now.2208 */2209 if (mhdp->info)2210 bridge_state->input_bus_cfg.flags = *mhdp->info->input_bus_flags;2211 2212 mutex_unlock(&mhdp->link_mutex);2213 return 0;2214}2215 2216static enum drm_connector_status cdns_mhdp_bridge_detect(struct drm_bridge *bridge)2217{2218 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);2219 2220 return cdns_mhdp_detect(mhdp);2221}2222 2223static const struct drm_edid *cdns_mhdp_bridge_edid_read(struct drm_bridge *bridge,2224 struct drm_connector *connector)2225{2226 struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);2227 2228 return cdns_mhdp_edid_read(mhdp, connector);2229}2230 2231static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = {2232 .atomic_enable = cdns_mhdp_atomic_enable,2233 .atomic_disable = cdns_mhdp_atomic_disable,2234 .atomic_check = cdns_mhdp_atomic_check,2235 .attach = cdns_mhdp_attach,2236 .detach = cdns_mhdp_detach,2237 .atomic_duplicate_state = cdns_mhdp_bridge_atomic_duplicate_state,2238 .atomic_destroy_state = cdns_mhdp_bridge_atomic_destroy_state,2239 .atomic_reset = cdns_mhdp_bridge_atomic_reset,2240 .atomic_get_input_bus_fmts = cdns_mhdp_get_input_bus_fmts,2241 .detect = cdns_mhdp_bridge_detect,2242 .edid_read = cdns_mhdp_bridge_edid_read,2243 .hpd_enable = cdns_mhdp_bridge_hpd_enable,2244 .hpd_disable = cdns_mhdp_bridge_hpd_disable,2245};2246 2247static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse)2248{2249 int hpd_event, hpd_status;2250 2251 *hpd_pulse = false;2252 2253 hpd_event = cdns_mhdp_read_hpd_event(mhdp);2254 2255 /* Getting event bits failed, bail out */2256 if (hpd_event < 0) {2257 dev_warn(mhdp->dev, "%s: read event failed: %d\n",2258 __func__, hpd_event);2259 return false;2260 }2261 2262 hpd_status = cdns_mhdp_get_hpd_status(mhdp);2263 if (hpd_status < 0) {2264 dev_warn(mhdp->dev, "%s: get hpd status failed: %d\n",2265 __func__, hpd_status);2266 return false;2267 }2268 2269 if (hpd_event & DPTX_READ_EVENT_HPD_PULSE)2270 *hpd_pulse = true;2271 2272 return !!hpd_status;2273}2274 2275static int cdns_mhdp_update_link_status(struct cdns_mhdp_device *mhdp)2276{2277 struct cdns_mhdp_bridge_state *cdns_bridge_state;2278 struct drm_display_mode *current_mode;2279 bool old_plugged = mhdp->plugged;2280 struct drm_bridge_state *state;2281 u8 status[DP_LINK_STATUS_SIZE];2282 bool hpd_pulse;2283 int ret = 0;2284 2285 mutex_lock(&mhdp->link_mutex);2286 2287 mhdp->plugged = cdns_mhdp_detect_hpd(mhdp, &hpd_pulse);2288 2289 if (!mhdp->plugged) {2290 cdns_mhdp_link_down(mhdp);2291 mhdp->link.rate = mhdp->host.link_rate;2292 mhdp->link.num_lanes = mhdp->host.lanes_cnt;2293 goto out;2294 }2295 2296 /*2297 * If we get a HPD pulse event and we were and still are connected,2298 * check the link status. If link status is ok, there's nothing to do2299 * as we don't handle DP interrupts. If link status is bad, continue2300 * with full link setup.2301 */2302 if (hpd_pulse && old_plugged == mhdp->plugged) {2303 ret = drm_dp_dpcd_read_link_status(&mhdp->aux, status);2304 2305 /*2306 * If everything looks fine, just return, as we don't handle2307 * DP IRQs.2308 */2309 if (ret > 0 &&2310 drm_dp_channel_eq_ok(status, mhdp->link.num_lanes) &&2311 drm_dp_clock_recovery_ok(status, mhdp->link.num_lanes))2312 goto out;2313 2314 /* If link is bad, mark link as down so that we do a new LT */2315 mhdp->link_up = false;2316 }2317 2318 if (!mhdp->link_up) {2319 ret = cdns_mhdp_link_up(mhdp);2320 if (ret < 0)2321 goto out;2322 }2323 2324 if (mhdp->bridge_enabled) {2325 state = drm_priv_to_bridge_state(mhdp->bridge.base.state);2326 if (!state) {2327 ret = -EINVAL;2328 goto out;2329 }2330 2331 cdns_bridge_state = to_cdns_mhdp_bridge_state(state);2332 if (!cdns_bridge_state) {2333 ret = -EINVAL;2334 goto out;2335 }2336 2337 current_mode = cdns_bridge_state->current_mode;2338 if (!current_mode) {2339 ret = -EINVAL;2340 goto out;2341 }2342 2343 if (!cdns_mhdp_bandwidth_ok(mhdp, current_mode, mhdp->link.num_lanes,2344 mhdp->link.rate)) {2345 ret = -EINVAL;2346 goto out;2347 }2348 2349 dev_dbg(mhdp->dev, "%s: Enabling mode %s\n", __func__,2350 current_mode->name);2351 2352 cdns_mhdp_sst_enable(mhdp, current_mode);2353 }2354out:2355 mutex_unlock(&mhdp->link_mutex);2356 return ret;2357}2358 2359static void cdns_mhdp_modeset_retry_fn(struct work_struct *work)2360{2361 struct cdns_mhdp_device *mhdp;2362 struct drm_connector *conn;2363 2364 mhdp = container_of(work, typeof(*mhdp), modeset_retry_work);2365 2366 conn = &mhdp->connector;2367 2368 /* Grab the locks before changing connector property */2369 mutex_lock(&conn->dev->mode_config.mutex);2370 2371 /*2372 * Set connector link status to BAD and send a Uevent to notify2373 * userspace to do a modeset.2374 */2375 drm_connector_set_link_status_property(conn, DRM_MODE_LINK_STATUS_BAD);2376 mutex_unlock(&conn->dev->mode_config.mutex);2377 2378 /* Send Hotplug uevent so userspace can reprobe */2379 drm_kms_helper_hotplug_event(mhdp->bridge.dev);2380}2381 2382static irqreturn_t cdns_mhdp_irq_handler(int irq, void *data)2383{2384 struct cdns_mhdp_device *mhdp = data;2385 u32 apb_stat, sw_ev0;2386 bool bridge_attached;2387 2388 apb_stat = readl(mhdp->regs + CDNS_APB_INT_STATUS);2389 if (!(apb_stat & CDNS_APB_INT_MASK_SW_EVENT_INT))2390 return IRQ_NONE;2391 2392 sw_ev0 = readl(mhdp->regs + CDNS_SW_EVENT0);2393 2394 /*2395 * Calling drm_kms_helper_hotplug_event() when not attached2396 * to drm device causes an oops because the drm_bridge->dev2397 * is NULL. See cdns_mhdp_fw_cb() comments for details about the2398 * problems related drm_kms_helper_hotplug_event() call.2399 */2400 spin_lock(&mhdp->start_lock);2401 bridge_attached = mhdp->bridge_attached;2402 spin_unlock(&mhdp->start_lock);2403 2404 if (bridge_attached && (sw_ev0 & CDNS_DPTX_HPD)) {2405 schedule_work(&mhdp->hpd_work);2406 }2407 2408 if (sw_ev0 & ~CDNS_DPTX_HPD) {2409 mhdp->sw_events |= (sw_ev0 & ~CDNS_DPTX_HPD);2410 wake_up(&mhdp->sw_events_wq);2411 }2412 2413 return IRQ_HANDLED;2414}2415 2416u32 cdns_mhdp_wait_for_sw_event(struct cdns_mhdp_device *mhdp, u32 event)2417{2418 u32 ret;2419 2420 ret = wait_event_timeout(mhdp->sw_events_wq,2421 mhdp->sw_events & event,2422 msecs_to_jiffies(500));2423 if (!ret) {2424 dev_dbg(mhdp->dev, "SW event 0x%x timeout\n", event);2425 goto sw_event_out;2426 }2427 2428 ret = mhdp->sw_events;2429 mhdp->sw_events &= ~event;2430 2431sw_event_out:2432 return ret;2433}2434 2435static void cdns_mhdp_hpd_work(struct work_struct *work)2436{2437 struct cdns_mhdp_device *mhdp = container_of(work,2438 struct cdns_mhdp_device,2439 hpd_work);2440 int ret;2441 2442 ret = cdns_mhdp_update_link_status(mhdp);2443 if (mhdp->connector.dev) {2444 if (ret < 0)2445 schedule_work(&mhdp->modeset_retry_work);2446 else2447 drm_kms_helper_hotplug_event(mhdp->bridge.dev);2448 } else {2449 drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));2450 }2451}2452 2453static int cdns_mhdp_probe(struct platform_device *pdev)2454{2455 struct device *dev = &pdev->dev;2456 struct cdns_mhdp_device *mhdp;2457 unsigned long rate;2458 struct clk *clk;2459 int ret;2460 int irq;2461 2462 mhdp = devm_kzalloc(dev, sizeof(*mhdp), GFP_KERNEL);2463 if (!mhdp)2464 return -ENOMEM;2465 2466 clk = devm_clk_get(dev, NULL);2467 if (IS_ERR(clk)) {2468 dev_err(dev, "couldn't get clk: %ld\n", PTR_ERR(clk));2469 return PTR_ERR(clk);2470 }2471 2472 mhdp->clk = clk;2473 mhdp->dev = dev;2474 mutex_init(&mhdp->mbox_mutex);2475 mutex_init(&mhdp->link_mutex);2476 spin_lock_init(&mhdp->start_lock);2477 2478 drm_dp_aux_init(&mhdp->aux);2479 mhdp->aux.dev = dev;2480 mhdp->aux.transfer = cdns_mhdp_transfer;2481 2482 mhdp->regs = devm_platform_ioremap_resource(pdev, 0);2483 if (IS_ERR(mhdp->regs)) {2484 dev_err(dev, "Failed to get memory resource\n");2485 return PTR_ERR(mhdp->regs);2486 }2487 2488 mhdp->sapb_regs = devm_platform_ioremap_resource_byname(pdev, "mhdptx-sapb");2489 if (IS_ERR(mhdp->sapb_regs)) {2490 mhdp->hdcp_supported = false;2491 dev_warn(dev,2492 "Failed to get SAPB memory resource, HDCP not supported\n");2493 } else {2494 mhdp->hdcp_supported = true;2495 }2496 2497 mhdp->phy = devm_of_phy_get_by_index(dev, pdev->dev.of_node, 0);2498 if (IS_ERR(mhdp->phy)) {2499 dev_err(dev, "no PHY configured\n");2500 return PTR_ERR(mhdp->phy);2501 }2502 2503 platform_set_drvdata(pdev, mhdp);2504 2505 mhdp->info = of_device_get_match_data(dev);2506 2507 clk_prepare_enable(clk);2508 2509 pm_runtime_enable(dev);2510 ret = pm_runtime_resume_and_get(dev);2511 if (ret < 0) {2512 dev_err(dev, "pm_runtime_resume_and_get failed\n");2513 pm_runtime_disable(dev);2514 goto clk_disable;2515 }2516 2517 if (mhdp->info && mhdp->info->ops && mhdp->info->ops->init) {2518 ret = mhdp->info->ops->init(mhdp);2519 if (ret != 0) {2520 dev_err(dev, "MHDP platform initialization failed: %d\n",2521 ret);2522 goto runtime_put;2523 }2524 }2525 2526 rate = clk_get_rate(clk);2527 writel(rate % 1000000, mhdp->regs + CDNS_SW_CLK_L);2528 writel(rate / 1000000, mhdp->regs + CDNS_SW_CLK_H);2529 2530 dev_dbg(dev, "func clk rate %lu Hz\n", rate);2531 2532 writel(~0, mhdp->regs + CDNS_APB_INT_MASK);2533 2534 irq = platform_get_irq(pdev, 0);2535 ret = devm_request_threaded_irq(mhdp->dev, irq, NULL,2536 cdns_mhdp_irq_handler, IRQF_ONESHOT,2537 "mhdp8546", mhdp);2538 if (ret) {2539 dev_err(dev, "cannot install IRQ %d\n", irq);2540 ret = -EIO;2541 goto plat_fini;2542 }2543 2544 cdns_mhdp_fill_host_caps(mhdp);2545 2546 /* Initialize link rate and num of lanes to host values */2547 mhdp->link.rate = mhdp->host.link_rate;2548 mhdp->link.num_lanes = mhdp->host.lanes_cnt;2549 2550 /* The only currently supported format */2551 mhdp->display_fmt.y_only = false;2552 mhdp->display_fmt.color_format = DRM_COLOR_FORMAT_RGB444;2553 mhdp->display_fmt.bpc = 8;2554 2555 mhdp->bridge.of_node = pdev->dev.of_node;2556 mhdp->bridge.funcs = &cdns_mhdp_bridge_funcs;2557 mhdp->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |2558 DRM_BRIDGE_OP_HPD;2559 mhdp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;2560 2561 ret = phy_init(mhdp->phy);2562 if (ret) {2563 dev_err(mhdp->dev, "Failed to initialize PHY: %d\n", ret);2564 goto plat_fini;2565 }2566 2567 /* Initialize the work for modeset in case of link train failure */2568 INIT_WORK(&mhdp->modeset_retry_work, cdns_mhdp_modeset_retry_fn);2569 INIT_WORK(&mhdp->hpd_work, cdns_mhdp_hpd_work);2570 2571 init_waitqueue_head(&mhdp->fw_load_wq);2572 init_waitqueue_head(&mhdp->sw_events_wq);2573 2574 ret = cdns_mhdp_load_firmware(mhdp);2575 if (ret)2576 goto phy_exit;2577 2578 if (mhdp->hdcp_supported)2579 cdns_mhdp_hdcp_init(mhdp);2580 2581 drm_bridge_add(&mhdp->bridge);2582 2583 return 0;2584 2585phy_exit:2586 phy_exit(mhdp->phy);2587plat_fini:2588 if (mhdp->info && mhdp->info->ops && mhdp->info->ops->exit)2589 mhdp->info->ops->exit(mhdp);2590runtime_put:2591 pm_runtime_put_sync(dev);2592 pm_runtime_disable(dev);2593clk_disable:2594 clk_disable_unprepare(mhdp->clk);2595 2596 return ret;2597}2598 2599static void cdns_mhdp_remove(struct platform_device *pdev)2600{2601 struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);2602 unsigned long timeout = msecs_to_jiffies(100);2603 int ret;2604 2605 drm_bridge_remove(&mhdp->bridge);2606 2607 ret = wait_event_timeout(mhdp->fw_load_wq,2608 mhdp->hw_state == MHDP_HW_READY,2609 timeout);2610 spin_lock(&mhdp->start_lock);2611 mhdp->hw_state = MHDP_HW_STOPPED;2612 spin_unlock(&mhdp->start_lock);2613 2614 if (ret == 0) {2615 dev_err(mhdp->dev, "%s: Timeout waiting for fw loading\n",2616 __func__);2617 } else {2618 ret = cdns_mhdp_set_firmware_active(mhdp, false);2619 if (ret)2620 dev_err(mhdp->dev, "Failed to stop firmware (%pe)\n",2621 ERR_PTR(ret));2622 }2623 2624 phy_exit(mhdp->phy);2625 2626 if (mhdp->info && mhdp->info->ops && mhdp->info->ops->exit)2627 mhdp->info->ops->exit(mhdp);2628 2629 pm_runtime_put_sync(&pdev->dev);2630 pm_runtime_disable(&pdev->dev);2631 2632 cancel_work_sync(&mhdp->modeset_retry_work);2633 flush_work(&mhdp->hpd_work);2634 /* Ignoring mhdp->hdcp.check_work and mhdp->hdcp.prop_work here. */2635 2636 clk_disable_unprepare(mhdp->clk);2637}2638 2639static const struct of_device_id mhdp_ids[] = {2640 { .compatible = "cdns,mhdp8546", },2641#ifdef CONFIG_DRM_CDNS_MHDP8546_J721E2642 { .compatible = "ti,j721e-mhdp8546",2643 .data = &(const struct cdns_mhdp_platform_info) {2644 .input_bus_flags = &mhdp_ti_j721e_bridge_input_bus_flags,2645 .ops = &mhdp_ti_j721e_ops,2646 },2647 },2648#endif2649 { /* sentinel */ }2650};2651MODULE_DEVICE_TABLE(of, mhdp_ids);2652 2653static struct platform_driver mhdp_driver = {2654 .driver = {2655 .name = "cdns-mhdp8546",2656 .of_match_table = mhdp_ids,2657 },2658 .probe = cdns_mhdp_probe,2659 .remove_new = cdns_mhdp_remove,2660};2661module_platform_driver(mhdp_driver);2662 2663MODULE_FIRMWARE(FW_NAME);2664 2665MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");2666MODULE_AUTHOR("Swapnil Jakhade <sjakhade@cadence.com>");2667MODULE_AUTHOR("Yuti Amonkar <yamonkar@cadence.com>");2668MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");2669MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");2670MODULE_DESCRIPTION("Cadence MHDP8546 DP bridge driver");2671MODULE_LICENSE("GPL");2672MODULE_ALIAS("platform:cdns-mhdp8546");2673