diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/805-display-0003-drm-bridge-add-Cadence-MHDP-HDMI-DP-API.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/805-display-0003-drm-bridge-add-Cadence-MHDP-HDMI-DP-API.patch | 4241 |
1 files changed, 4241 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/805-display-0003-drm-bridge-add-Cadence-MHDP-HDMI-DP-API.patch b/target/linux/layerscape/patches-5.4/805-display-0003-drm-bridge-add-Cadence-MHDP-HDMI-DP-API.patch new file mode 100644 index 0000000000..19e762618a --- /dev/null +++ b/target/linux/layerscape/patches-5.4/805-display-0003-drm-bridge-add-Cadence-MHDP-HDMI-DP-API.patch @@ -0,0 +1,4241 @@ +From d94a1a8c31cab273b3409c9c380a8089a794f592 Mon Sep 17 00:00:00 2001 +From: Sandor Yu <Sandor.yu@nxp.com> +Date: Wed, 10 Jul 2019 14:22:12 +0800 +Subject: [PATCH] drm: bridge: add Cadence MHDP HDMI/DP API + +Changes made in the low level driver (cdn-dp-reg.*): +- moved it to from drivers/gpu/drm/rockchip to + drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c and + include/drm/bridge/cdns-mhdp-common.h +- functions for sending/receiving commands are now public +- added functions for reading registers and link training adjustment + +Changes made in RK's driver (cdn-dp-core.*): +- Moved audio_info and audio_pdev fields from cdn_dp_device to + cdns_mhdp_device structure. + +Signed-off-by: Quentin Schulz<quentin.schulz@free-electrons.com> +Signed-off-by: Piotr Sroka <piotrs@cadence.com> +Signed-off-by: Damian Kos <dkos@cadence.com> +Signed-off-by: Sandor Yu <Sandor.yu@nxp.com> +--- + drivers/gpu/drm/bridge/Kconfig | 2 + + drivers/gpu/drm/bridge/Makefile | 1 + + drivers/gpu/drm/bridge/cadence/Kconfig | 7 + + drivers/gpu/drm/bridge/cadence/Makefile | 3 + + drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 1165 +++++++++++++++++++++ + drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c | 296 ++++++ + drivers/gpu/drm/bridge/cadence/cdns-mhdp.h | 209 ++++ + drivers/gpu/drm/rockchip/Kconfig | 4 +- + drivers/gpu/drm/rockchip/Makefile | 2 +- + drivers/gpu/drm/rockchip/cdn-dp-core.c | 48 +- + drivers/gpu/drm/rockchip/cdn-dp-core.h | 5 +- + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 968 ----------------- + drivers/gpu/drm/rockchip/cdn-dp-reg.h | 546 ---------- + include/drm/bridge/cdns-mhdp-cbs.h | 29 + + include/drm/bridge/cdns-mhdp-common.h | 704 +++++++++++++ + 15 files changed, 2446 insertions(+), 1543 deletions(-) + create mode 100644 drivers/gpu/drm/bridge/cadence/Kconfig + create mode 100644 drivers/gpu/drm/bridge/cadence/Makefile + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp.h + delete mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c + delete mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h + create mode 100644 include/drm/bridge/cdns-mhdp-cbs.h + create mode 100644 include/drm/bridge/cdns-mhdp-common.h + +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -154,6 +154,8 @@ source "drivers/gpu/drm/bridge/analogix/ + + source "drivers/gpu/drm/bridge/adv7511/Kconfig" + ++source "drivers/gpu/drm/bridge/cadence/Kconfig" ++ + source "drivers/gpu/drm/bridge/synopsys/Kconfig" + + endmenu +--- a/drivers/gpu/drm/bridge/Makefile ++++ b/drivers/gpu/drm/bridge/Makefile +@@ -16,4 +16,5 @@ obj-$(CONFIG_DRM_ANALOGIX_DP) += analogi + obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ + obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o + obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o ++obj-y += cadence/ + obj-y += synopsys/ +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/Kconfig +@@ -0,0 +1,7 @@ ++config DRM_CDNS_MHDP ++ tristate "Cadence MHDP COMMON API driver" ++ select DRM_KMS_HELPER ++ select DRM_PANEL_BRIDGE ++ depends on OF ++ help ++ Support Cadence MHDP API library. +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/Makefile +@@ -0,0 +1,3 @@ ++#ccflags-y := -Iinclude/drm ++ ++obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp-common.o cdns-mhdp-hdmi.o +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c +@@ -0,0 +1,1165 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd ++ * Author: Chris Zhong <zyw@rock-chips.com> ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/io.h> ++#include <linux/iopoll.h> ++#include <linux/reset.h> ++ ++#include <asm/unaligned.h> ++ ++#include <drm/bridge/cdns-mhdp-common.h> ++#include <drm/drm_modes.h> ++#include <drm/drm_print.h> ++ ++#define CDNS_DP_SPDIF_CLK 200000000 ++#define FW_ALIVE_TIMEOUT_US 1000000 ++#define MAILBOX_RETRY_US 1000 ++#define MAILBOX_TIMEOUT_US 5000000 ++#define LINK_TRAINING_RETRY_MS 20 ++#define LINK_TRAINING_TIMEOUT_MS 500 ++ ++static inline u32 get_unaligned_be24(const void *p) ++{ ++ const u8 *_p = p; ++ ++ return _p[0] << 16 | _p[1] << 8 | _p[2]; ++} ++ ++static inline void put_unaligned_be24(u32 val, void *p) ++{ ++ u8 *_p = p; ++ ++ _p[0] = val >> 16; ++ _p[1] = val >> 8; ++ _p[2] = val; ++} ++ ++void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk) ++{ ++ writel(clk / 1000000, mhdp->regs + SW_CLK_H); ++} ++EXPORT_SYMBOL(cdns_mhdp_set_fw_clk); ++ ++void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp) ++{ ++ u32 val; ++ ++ val = DPTX_FRMR_DATA_CLK_RSTN_EN | ++ DPTX_FRMR_DATA_CLK_EN | ++ DPTX_PHY_DATA_RSTN_EN | ++ DPTX_PHY_DATA_CLK_EN | ++ DPTX_PHY_CHAR_RSTN_EN | ++ DPTX_PHY_CHAR_CLK_EN | ++ SOURCE_AUX_SYS_CLK_RSTN_EN | ++ SOURCE_AUX_SYS_CLK_EN | ++ DPTX_SYS_CLK_RSTN_EN | ++ DPTX_SYS_CLK_EN | ++ CFG_DPTX_VIF_CLK_RSTN_EN | ++ CFG_DPTX_VIF_CLK_EN; ++ writel(val, mhdp->regs + SOURCE_DPTX_CAR); ++ ++ val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN; ++ writel(val, mhdp->regs + SOURCE_PHY_CAR); ++ ++ val = SOURCE_PKT_SYS_RSTN_EN | ++ SOURCE_PKT_SYS_CLK_EN | ++ SOURCE_PKT_DATA_RSTN_EN | ++ SOURCE_PKT_DATA_CLK_EN; ++ writel(val, mhdp->regs + SOURCE_PKT_CAR); ++ ++ val = SPDIF_CDR_CLK_RSTN_EN | ++ SPDIF_CDR_CLK_EN | ++ SOURCE_AIF_SYS_RSTN_EN | ++ SOURCE_AIF_SYS_CLK_EN | ++ SOURCE_AIF_CLK_RSTN_EN | ++ SOURCE_AIF_CLK_EN; ++ writel(val, mhdp->regs + SOURCE_AIF_CAR); ++ ++ val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN | ++ SOURCE_CIPHER_SYS_CLK_EN | ++ SOURCE_CIPHER_CHAR_CLK_RSTN_EN | ++ SOURCE_CIPHER_CHAR_CLK_EN; ++ writel(val, mhdp->regs + SOURCE_CIPHER_CAR); ++ ++ val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN | ++ SOURCE_CRYPTO_SYS_CLK_EN; ++ writel(val, mhdp->regs + SOURCE_CRYPTO_CAR); ++ ++ /* enable Mailbox and PIF interrupt */ ++ writel(0, mhdp->regs + APB_INT_MASK); ++} ++EXPORT_SYMBOL(cdns_mhdp_clock_reset); ++ ++int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp) ++{ ++ int val, ret; ++ ++ ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_EMPTY_ADDR, ++ val, !val, MAILBOX_RETRY_US, ++ MAILBOX_TIMEOUT_US); ++ if (ret < 0) ++ return ret; ++ ++ return readl(mhdp->regs + MAILBOX0_RD_DATA) & 0xff; ++} ++EXPORT_SYMBOL(cdns_mhdp_mailbox_read); ++ ++static int cdp_dp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val) ++{ ++ int ret, full; ++ ++ ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_FULL_ADDR, ++ full, !full, MAILBOX_RETRY_US, ++ MAILBOX_TIMEOUT_US); ++ if (ret < 0) ++ return ret; ++ ++ writel(val, mhdp->regs + MAILBOX0_WR_DATA); ++ ++ return 0; ++} ++ ++int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp, ++ u8 module_id, u8 opcode, ++ u16 req_size) ++{ ++ u32 mbox_size, i; ++ u8 header[4]; ++ int ret; ++ ++ /* read the header of the message */ ++ for (i = 0; i < 4; i++) { ++ ret = cdns_mhdp_mailbox_read(mhdp); ++ if (ret < 0) ++ return ret; ++ ++ header[i] = ret; ++ } ++ ++ mbox_size = get_unaligned_be16(header + 2); ++ ++ if (opcode != header[0] || module_id != header[1] || ++ req_size != mbox_size) { ++ /* ++ * If the message in mailbox is not what we want, we need to ++ * clear the mailbox by reading its contents. ++ */ ++ for (i = 0; i < mbox_size; i++) ++ if (cdns_mhdp_mailbox_read(mhdp) < 0) ++ break; ++ ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(cdns_mhdp_mailbox_validate_receive); ++ ++int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp, ++ u8 *buff, u16 buff_size) ++{ ++ u32 i; ++ int ret; ++ ++ for (i = 0; i < buff_size; i++) { ++ ret = cdns_mhdp_mailbox_read(mhdp); ++ if (ret < 0) ++ return ret; ++ ++ buff[i] = ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(cdns_mhdp_mailbox_read_receive); ++ ++int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id, ++ u8 opcode, u16 size, u8 *message) ++{ ++ u8 header[4]; ++ int ret, i; ++ ++ header[0] = opcode; ++ header[1] = module_id; ++ put_unaligned_be16(size, header + 2); ++ ++ for (i = 0; i < 4; i++) { ++ ret = cdp_dp_mailbox_write(mhdp, header[i]); ++ if (ret) ++ return ret; ++ } ++ ++ for (i = 0; i < size; i++) { ++ ret = cdp_dp_mailbox_write(mhdp, message[i]); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(cdns_mhdp_mailbox_send); ++ ++int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr) ++{ ++ u8 msg[4], resp[8]; ++ u32 val; ++ int ret; ++ ++ if (addr == 0) { ++ ret = -EINVAL; ++ goto err_reg_read; ++ } ++ ++ put_unaligned_be32(addr, msg); ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, ++ GENERAL_READ_REGISTER, ++ sizeof(msg), msg); ++ if (ret) ++ goto err_reg_read; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL, ++ GENERAL_READ_REGISTER, ++ sizeof(resp)); ++ if (ret) ++ goto err_reg_read; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, resp, sizeof(resp)); ++ if (ret) ++ goto err_reg_read; ++ ++ /* Returned address value should be the same as requested */ ++ if (memcmp(msg, resp, sizeof(msg))) { ++ ret = -EINVAL; ++ goto err_reg_read; ++ } ++ ++ val = get_unaligned_be32(resp + 4); ++ ++ return val; ++err_reg_read: ++ DRM_DEV_ERROR(mhdp->dev, "Failed to read register.\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_reg_read); ++ ++int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val) ++{ ++ u8 msg[8]; ++ ++ put_unaligned_be32(addr, msg); ++ put_unaligned_be32(val, msg + 4); ++ ++ return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, ++ GENERAL_WRITE_REGISTER, sizeof(msg), msg); ++} ++EXPORT_SYMBOL(cdns_mhdp_reg_write); ++ ++int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr, ++ u8 start_bit, u8 bits_no, u32 val) ++{ ++ u8 field[8]; ++ ++ put_unaligned_be16(addr, field); ++ field[2] = start_bit; ++ field[3] = bits_no; ++ put_unaligned_be32(val, field + 4); ++ ++ return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_WRITE_FIELD, sizeof(field), field); ++} ++EXPORT_SYMBOL(cdns_mhdp_reg_write_bit); ++ ++int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp, ++ u32 addr, u8 *data, u16 len) ++{ ++ u8 msg[5], reg[5]; ++ int ret; ++ ++ put_unaligned_be16(len, msg); ++ put_unaligned_be24(addr, msg + 2); ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_READ_DPCD, sizeof(msg), msg); ++ if (ret) ++ goto err_dpcd_read; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_READ_DPCD, ++ sizeof(reg) + len); ++ if (ret) ++ goto err_dpcd_read; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); ++ if (ret) ++ goto err_dpcd_read; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len); ++ ++err_dpcd_read: ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_dpcd_read); ++ ++int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value) ++{ ++ u8 msg[6], reg[5]; ++ int ret; ++ ++ put_unaligned_be16(1, msg); ++ put_unaligned_be24(addr, msg + 2); ++ msg[5] = value; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_WRITE_DPCD, sizeof(msg), msg); ++ if (ret) ++ goto err_dpcd_write; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_WRITE_DPCD, sizeof(reg)); ++ if (ret) ++ goto err_dpcd_write; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); ++ if (ret) ++ goto err_dpcd_write; ++ ++ if (addr != get_unaligned_be24(reg + 2)) ++ ret = -EINVAL; ++ ++err_dpcd_write: ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret); ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_dpcd_write); ++ ++int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem, ++ u32 i_size, const u32 *d_mem, u32 d_size) ++{ ++ u32 reg; ++ int i, ret; ++ ++ /* reset ucpu before load firmware*/ ++ writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET, ++ mhdp->regs + APB_CTRL); ++ ++ for (i = 0; i < i_size; i += 4) ++ writel(*i_mem++, mhdp->regs + ADDR_IMEM + i); ++ ++ for (i = 0; i < d_size; i += 4) ++ writel(*d_mem++, mhdp->regs + ADDR_DMEM + i); ++ ++ /* un-reset ucpu */ ++ writel(0, mhdp->regs + APB_CTRL); ++ ++ /* check the keep alive register to make sure fw working */ ++ ret = readx_poll_timeout(readl, mhdp->regs + KEEP_ALIVE, ++ reg, reg, 2000, FW_ALIVE_TIMEOUT_US); ++ if (ret < 0) { ++ DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n", ++ reg); ++ return -EINVAL; ++ } ++ ++ reg = readl(mhdp->regs + VER_L) & 0xff; ++ mhdp->fw_version = reg; ++ reg = readl(mhdp->regs + VER_H) & 0xff; ++ mhdp->fw_version |= reg << 8; ++ reg = readl(mhdp->regs + VER_LIB_L_ADDR) & 0xff; ++ mhdp->fw_version |= reg << 16; ++ reg = readl(mhdp->regs + VER_LIB_H_ADDR) & 0xff; ++ mhdp->fw_version |= reg << 24; ++ ++ DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version); ++ ++ return 0; ++} ++EXPORT_SYMBOL(cdns_mhdp_load_firmware); ++ ++int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable) ++{ ++ u8 msg[5]; ++ int ret, i; ++ ++ msg[0] = GENERAL_MAIN_CONTROL; ++ msg[1] = MB_MODULE_ID_GENERAL; ++ msg[2] = 0; ++ msg[3] = 1; ++ msg[4] = enable ? FW_ACTIVE : FW_STANDBY; ++ ++ for (i = 0; i < sizeof(msg); i++) { ++ ret = cdp_dp_mailbox_write(mhdp, msg[i]); ++ if (ret) ++ goto err_set_firmware_active; ++ } ++ ++ /* read the firmware state */ ++ for (i = 0; i < sizeof(msg); i++) { ++ ret = cdns_mhdp_mailbox_read(mhdp); ++ if (ret < 0) ++ goto err_set_firmware_active; ++ ++ msg[i] = ret; ++ } ++ ++ ret = 0; ++ ++err_set_firmware_active: ++ if (ret < 0) ++ DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n"); ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_set_firmware_active); ++ ++int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip) ++{ ++ u8 msg[8]; ++ int ret; ++ ++ msg[0] = CDNS_DP_MAX_LINK_RATE; ++ msg[1] = lanes | SCRAMBLER_EN; ++ msg[2] = VOLTAGE_LEVEL_2; ++ msg[3] = PRE_EMPHASIS_LEVEL_3; ++ msg[4] = PTS1 | PTS2 | PTS3 | PTS4; ++ msg[5] = FAST_LT_NOT_SUPPORT; ++ msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; ++ msg[7] = ENHANCED; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_SET_HOST_CAPABILITIES, ++ sizeof(msg), msg); ++ if (ret) ++ goto err_set_host_cap; ++ ++/* TODO Sandor */ ++// ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL, ++// AUX_HOST_INVERT); ++ ++err_set_host_cap: ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret); ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_set_host_cap); ++ ++int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp) ++{ ++ u8 msg[5]; ++ int ret; ++ ++ memset(msg, 0, sizeof(msg)); ++ ++ msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_ENABLE_EVENT, sizeof(msg), msg); ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "set event config failed: %d\n", ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_event_config); ++ ++u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp) ++{ ++ return readl(mhdp->regs + SW_EVENTS0); ++} ++EXPORT_SYMBOL(cdns_mhdp_get_event); ++ ++int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp) ++{ ++ u8 status; ++ int ret; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_HPD_STATE, 0, NULL); ++ if (ret) ++ goto err_get_hpd; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_HPD_STATE, ++ sizeof(status)); ++ if (ret) ++ goto err_get_hpd; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status)); ++ if (ret) ++ goto err_get_hpd; ++ ++ return status; ++ ++err_get_hpd: ++ DRM_DEV_ERROR(mhdp->dev, "get hpd status failed: %d\n", ret); ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_get_hpd_status); ++ ++int cdns_mhdp_get_edid_block(void *data, u8 *edid, ++ unsigned int block, size_t length) ++{ ++ struct cdns_mhdp_device *mhdp = data; ++ u8 msg[2], reg[2], i; ++ int ret; ++ ++ for (i = 0; i < 4; i++) { ++ msg[0] = block / 2; ++ msg[1] = block % 2; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_GET_EDID, sizeof(msg), msg); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, ++ MB_MODULE_ID_DP_TX, ++ DPTX_GET_EDID, ++ sizeof(reg) + length); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length); ++ if (ret) ++ continue; ++ ++ if (reg[0] == length && reg[1] == block / 2) ++ break; ++ } ++ ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n", ++ block, ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_get_edid_block); ++ ++static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp) ++{ ++ unsigned long timeout; ++ u8 msg, event[2]; ++ int ret; ++ ++ msg = LINK_TRAINING_RUN; ++ ++ /* start training */ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_TRAINING_CONTROL, sizeof(msg), &msg); ++ if (ret) ++ goto err_training_start; ++ ++ timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); ++ while (time_before(jiffies, timeout)) { ++ msleep(LINK_TRAINING_RETRY_MS); ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_READ_EVENT, 0, NULL); ++ if (ret) ++ goto err_training_start; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, ++ MB_MODULE_ID_DP_TX, ++ DPTX_READ_EVENT, ++ sizeof(event)); ++ if (ret) ++ goto err_training_start; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, event, ++ sizeof(event)); ++ if (ret) ++ goto err_training_start; ++ ++ if (event[1] & EQ_PHASE_FINISHED) ++ return 0; ++ } ++ ++ ret = -ETIMEDOUT; ++ ++err_training_start: ++ DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret); ++ return ret; ++} ++ ++static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp) ++{ ++ u8 status[10]; ++ int ret; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_READ_LINK_STAT, 0, NULL); ++ if (ret) ++ goto err_get_training_status; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_READ_LINK_STAT, ++ sizeof(status)); ++ if (ret) ++ goto err_get_training_status; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status)); ++ if (ret) ++ goto err_get_training_status; ++ ++ mhdp->dp.link.rate = drm_dp_bw_code_to_link_rate(status[0]); ++ mhdp->dp.link.num_lanes = status[1]; ++ ++err_get_training_status: ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n", ++ ret); ++ return ret; ++} ++ ++int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp) ++{ ++ int ret; ++ ++ ret = cdns_mhdp_training_start(mhdp); ++ if (ret) { ++ DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n", ++ ret); ++ return ret; ++ } ++ ++ ret = cdns_mhdp_get_training_status(mhdp); ++ if (ret) { ++ DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n", ++ ret); ++ return ret; ++ } ++ ++ DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->dp.link.rate, ++ mhdp->dp.link.num_lanes); ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_train_link); ++ ++int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active) ++{ ++ u8 msg; ++ int ret; ++ ++ msg = !!active; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_SET_VIDEO, sizeof(msg), &msg); ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "set video status failed: %d\n", ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_set_video_status); ++ ++static int cdns_mhdp_get_msa_misc(struct video_info *video, ++ struct drm_display_mode *mode) ++{ ++ u32 msa_misc; ++ u8 val[2] = {0}; ++ ++ switch (video->color_fmt) { ++ case PXL_RGB: ++ case Y_ONLY: ++ val[0] = 0; ++ break; ++ /* set YUV default color space conversion to BT601 */ ++ case YCBCR_4_4_4: ++ val[0] = 6 + BT_601 * 8; ++ break; ++ case YCBCR_4_2_2: ++ val[0] = 5 + BT_601 * 8; ++ break; ++ case YCBCR_4_2_0: ++ val[0] = 5; ++ break; ++ }; ++ ++ switch (video->color_depth) { ++ case 6: ++ val[1] = 0; ++ break; ++ case 8: ++ val[1] = 1; ++ break; ++ case 10: ++ val[1] = 2; ++ break; ++ case 12: ++ val[1] = 3; ++ break; ++ case 16: ++ val[1] = 4; ++ break; ++ }; ++ ++ msa_misc = 2 * val[0] + 32 * val[1] + ++ ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); ++ ++ return msa_misc; ++} ++ ++int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp) ++{ ++ struct video_info *video = &mhdp->video_info; ++ struct drm_display_mode *mode = &mhdp->mode; ++ u64 symbol; ++ u32 val, link_rate, rem; ++ u8 bit_per_pix, tu_size_reg = TU_SIZE; ++ int ret; ++ ++ bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? ++ (video->color_depth * 2) : (video->color_depth * 3); ++ ++ link_rate = mhdp->dp.link.rate / 1000; ++ ++ ret = cdns_mhdp_reg_write(mhdp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); ++ if (ret) ++ goto err_config_video; ++ ++ ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, 0); ++ if (ret) ++ goto err_config_video; ++ ++ /* ++ * get a best tu_size and valid symbol: ++ * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 ++ * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) ++ * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set ++ * TU += 2 and repeat 2nd step. ++ */ ++ do { ++ tu_size_reg += 2; ++ symbol = tu_size_reg * mode->clock * bit_per_pix; ++ do_div(symbol, mhdp->dp.link.num_lanes * link_rate * 8); ++ rem = do_div(symbol, 1000); ++ if (tu_size_reg > 64) { ++ ret = -EINVAL; ++ DRM_DEV_ERROR(mhdp->dev, ++ "tu error, clk:%d, lanes:%d, rate:%d\n", ++ mode->clock, mhdp->dp.link.num_lanes, ++ link_rate); ++ goto err_config_video; ++ } ++ } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || ++ (rem > 850) || (rem < 100)); ++ ++ val = symbol + (tu_size_reg << 8); ++ val |= TU_CNT_RST_EN; ++ ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_TU, val); ++ if (ret) ++ goto err_config_video; ++ ++ /* set the FIFO Buffer size */ ++ val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; ++ val /= (mhdp->dp.link.num_lanes * link_rate); ++ val = div_u64(8 * (symbol + 1), bit_per_pix) - val; ++ val += 2; ++ ret = cdns_mhdp_reg_write(mhdp, DP_VC_TABLE(15), val); ++ ++ switch (video->color_depth) { ++ case 6: ++ val = BCS_6; ++ break; ++ case 8: ++ val = BCS_8; ++ break; ++ case 10: ++ val = BCS_10; ++ break; ++ case 12: ++ val = BCS_12; ++ break; ++ case 16: ++ val = BCS_16; ++ break; ++ }; ++ ++ val += video->color_fmt << 8; ++ ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_PXL_REPR, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0; ++ val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0; ++ ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_SP, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = (mode->hsync_start - mode->hdisplay) << 16; ++ val |= mode->htotal - mode->hsync_end; ++ ret = cdns_mhdp_reg_write(mhdp, DP_FRONT_BACK_PORCH, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->hdisplay * bit_per_pix / 8; ++ ret = cdns_mhdp_reg_write(mhdp, DP_BYTE_COUNT, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); ++ ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_0, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->hsync_end - mode->hsync_start; ++ val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15); ++ ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_1, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->vtotal; ++ val |= (mode->vtotal - mode->vsync_start) << 16; ++ ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_0, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->vsync_end - mode->vsync_start; ++ val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15); ++ ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_1, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = cdns_mhdp_get_msa_misc(video, mode); ++ ret = cdns_mhdp_reg_write(mhdp, MSA_MISC, val); ++ if (ret) ++ goto err_config_video; ++ ++ ret = cdns_mhdp_reg_write(mhdp, STREAM_CONFIG, 1); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->hsync_end - mode->hsync_start; ++ val |= mode->hdisplay << 16; ++ ret = cdns_mhdp_reg_write(mhdp, DP_HORIZONTAL, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->vdisplay; ++ val |= (mode->vtotal - mode->vsync_start) << 16; ++ ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_0, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->vtotal; ++ ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_1, val); ++ if (ret) ++ goto err_config_video; ++ ++ ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 2, 1, 0); ++ ++err_config_video: ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret); ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_config_video); ++ ++int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, ++ struct audio_info *audio) ++{ ++ int ret; ++ ++ ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0); ++ if (ret) { ++ DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret); ++ return ret; ++ } ++ ++ writel(0, mhdp->regs + SPDIF_CTRL_ADDR); ++ ++ /* clearn the audio config and reset */ ++ writel(0, mhdp->regs + AUDIO_SRC_CNTL); ++ writel(0, mhdp->regs + AUDIO_SRC_CNFG); ++ writel(AUDIO_SW_RST, mhdp->regs + AUDIO_SRC_CNTL); ++ writel(0, mhdp->regs + AUDIO_SRC_CNTL); ++ ++ /* reset smpl2pckt component */ ++ writel(0, mhdp->regs + SMPL2PKT_CNTL); ++ writel(AUDIO_SW_RST, mhdp->regs + SMPL2PKT_CNTL); ++ writel(0, mhdp->regs + SMPL2PKT_CNTL); ++ ++ /* reset FIFO */ ++ writel(AUDIO_SW_RST, mhdp->regs + FIFO_CNTL); ++ writel(0, mhdp->regs + FIFO_CNTL); ++ ++ if (audio->format == AFMT_SPDIF) ++ clk_disable_unprepare(mhdp->spdif_clk); ++ ++ return 0; ++} ++EXPORT_SYMBOL(cdns_mhdp_audio_stop); ++ ++int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable) ++{ ++ int ret; ++ ++ ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable); ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_audio_mute); ++ ++static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp, ++ struct audio_info *audio) ++{ ++ int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; ++ u32 val; ++ ++ if (audio->channels == 2) { ++ if (mhdp->dp.link.num_lanes == 1) ++ sub_pckt_num = 2; ++ else ++ sub_pckt_num = 4; ++ ++ i2s_port_en_val = 1; ++ } else if (audio->channels == 4) { ++ i2s_port_en_val = 3; ++ } ++ ++ writel(0x0, mhdp->regs + SPDIF_CTRL_ADDR); ++ ++ writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL); ++ ++ val = MAX_NUM_CH(audio->channels); ++ val |= NUM_OF_I2S_PORTS(audio->channels); ++ val |= AUDIO_TYPE_LPCM; ++ val |= CFG_SUB_PCKT_NUM(sub_pckt_num); ++ writel(val, mhdp->regs + SMPL2PKT_CNFG); ++ ++ if (audio->sample_width == 16) ++ val = 0; ++ else if (audio->sample_width == 24) ++ val = 1 << 9; ++ else ++ val = 2 << 9; ++ ++ val |= AUDIO_CH_NUM(audio->channels); ++ val |= I2S_DEC_PORT_EN(i2s_port_en_val); ++ val |= TRANS_SMPL_WIDTH_32; ++ writel(val, mhdp->regs + AUDIO_SRC_CNFG); ++ ++ for (i = 0; i < (audio->channels + 1) / 2; i++) { ++ if (audio->sample_width == 16) ++ val = (0x02 << 8) | (0x02 << 20); ++ else if (audio->sample_width == 24) ++ val = (0x0b << 8) | (0x0b << 20); ++ ++ val |= ((2 * i) << 4) | ((2 * i + 1) << 16); ++ writel(val, mhdp->regs + STTS_BIT_CH(i)); ++ } ++ ++ switch (audio->sample_rate) { ++ case 32000: ++ val = SAMPLING_FREQ(3) | ++ ORIGINAL_SAMP_FREQ(0xc); ++ break; ++ case 44100: ++ val = SAMPLING_FREQ(0) | ++ ORIGINAL_SAMP_FREQ(0xf); ++ break; ++ case 48000: ++ val = SAMPLING_FREQ(2) | ++ ORIGINAL_SAMP_FREQ(0xd); ++ break; ++ case 88200: ++ val = SAMPLING_FREQ(8) | ++ ORIGINAL_SAMP_FREQ(0x7); ++ break; ++ case 96000: ++ val = SAMPLING_FREQ(0xa) | ++ ORIGINAL_SAMP_FREQ(5); ++ break; ++ case 176400: ++ val = SAMPLING_FREQ(0xc) | ++ ORIGINAL_SAMP_FREQ(3); ++ break; ++ case 192000: ++ val = SAMPLING_FREQ(0xe) | ++ ORIGINAL_SAMP_FREQ(1); ++ break; ++ } ++ val |= 4; ++ writel(val, mhdp->regs + COM_CH_STTS_BITS); ++ ++ writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL); ++ writel(I2S_DEC_START, mhdp->regs + AUDIO_SRC_CNTL); ++} ++ ++static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp) ++{ ++ u32 val; ++ ++ writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL); ++ ++ val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); ++ writel(val, mhdp->regs + SMPL2PKT_CNFG); ++ writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL); ++ ++ val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; ++ writel(val, mhdp->regs + SPDIF_CTRL_ADDR); ++ ++ clk_prepare_enable(mhdp->spdif_clk); ++ clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK); ++} ++ ++int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp, ++ struct audio_info *audio) ++{ ++ int ret; ++ ++ /* reset the spdif clk before config */ ++ if (audio->format == AFMT_SPDIF) { ++ reset_control_assert(mhdp->spdif_rst); ++ reset_control_deassert(mhdp->spdif_rst); ++ } ++ ++ ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC); ++ if (ret) ++ goto err_audio_config; ++ ++ ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0); ++ if (ret) ++ goto err_audio_config; ++ ++ if (audio->format == AFMT_I2S) ++ cdns_mhdp_audio_config_i2s(mhdp, audio); ++ else if (audio->format == AFMT_SPDIF) ++ cdns_mhdp_audio_config_spdif(mhdp); ++ ++ ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); ++ ++err_audio_config: ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret); ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_audio_config); ++ ++int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp, ++ u8 nlanes, u16 udelay, u8 *lanes_data, u8 *dpcd) ++{ ++ u8 payload[7]; ++ u8 hdr[5]; /* For DPCD read response header */ ++ u32 addr; ++ u8 const nregs = 6; /* Registers 0x202-0x207 */ ++ int ret; ++ ++ if (nlanes != 4 && nlanes != 2 && nlanes != 1) { ++ DRM_DEV_ERROR(mhdp->dev, "invalid number of lanes: %d\n", ++ nlanes); ++ ret = -EINVAL; ++ goto err_adjust_lt; ++ } ++ ++ payload[0] = nlanes; ++ put_unaligned_be16(udelay, payload + 1); ++ memcpy(payload + 3, lanes_data, nlanes); ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_ADJUST_LT, ++ sizeof(payload), payload); ++ if (ret) ++ goto err_adjust_lt; ++ ++ /* Yes, read the DPCD read command response */ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, ++ DPTX_READ_DPCD, ++ sizeof(hdr) + nregs); ++ if (ret) ++ goto err_adjust_lt; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, hdr, sizeof(hdr)); ++ if (ret) ++ goto err_adjust_lt; ++ ++ addr = get_unaligned_be24(hdr + 2); ++ if (addr != DP_LANE0_1_STATUS) ++ goto err_adjust_lt; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, dpcd, nregs); ++ ++err_adjust_lt: ++ if (ret) ++ DRM_DEV_ERROR(mhdp->dev, "Failed to adjust Link Training.\n"); ++ ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_adjust_lt); ++ ++int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val) ++{ ++ return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2), val); ++} ++EXPORT_SYMBOL(cdns_phy_reg_write); ++ ++u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr) ++{ ++ return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2)); ++} ++EXPORT_SYMBOL(cdns_phy_reg_read); ++ ++int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp) ++{ ++ u8 status; ++ int ret; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE, ++ 0, NULL); ++ if (ret) ++ goto err_get_hpd; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL, ++ GENERAL_GET_HPD_STATE, sizeof(status)); ++ if (ret) ++ goto err_get_hpd; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status)); ++ if (ret) ++ goto err_get_hpd; ++ ++ return status; ++ ++err_get_hpd: ++ DRM_ERROR("read hpd failed: %d\n", ret); ++ return ret; ++} ++EXPORT_SYMBOL(cdns_mhdp_read_hpd); ++ ++bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp) ++{ ++ u32 alive, newalive; ++ u8 retries_left = 10; ++ ++ alive = readl(mhdp->regs + KEEP_ALIVE); ++ ++ while (retries_left--) { ++ udelay(2); ++ ++ newalive = readl(mhdp->regs + KEEP_ALIVE); ++ if (alive == newalive) ++ continue; ++ return true; ++ } ++ return false; ++} ++EXPORT_SYMBOL(cdns_mhdp_check_alive); +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c +@@ -0,0 +1,296 @@ ++/* ++ * Copyright (C) 2019 NXP Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <drm/drmP.h> ++#include <linux/io.h> ++#include <drm/bridge/cdns-mhdp-common.h> ++ ++int cdns_hdmi_get_edid_block(void *data, u8 *edid, ++ u32 block, size_t length) ++{ ++ struct cdns_mhdp_device *mhdp = data; ++ u8 msg[2], reg[5], i; ++ int ret; ++ ++ for (i = 0; i < 4; i++) { ++ msg[0] = block / 2; ++ msg[1] = block % 2; ++ ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_EDID, ++ sizeof(msg), msg); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX, ++ HDMI_TX_EDID, sizeof(reg) + length); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length); ++ if (ret) ++ continue; ++ ++ if ((reg[3] << 8 | reg[4]) == length) ++ break; ++ } ++ ++ if (ret) ++ DRM_ERROR("get block[%d] edid failed: %d\n", block, ret); ++ return ret; ++} ++ ++int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data) ++{ ++ u8 msg[4], reg[6]; ++ int ret; ++ ++ msg[0] = 0x54; ++ msg[1] = addr; ++ msg[2] = 0; ++ msg[3] = 1; ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_READ, ++ sizeof(msg), msg); ++ if (ret) ++ goto err_scdc_read; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX, ++ HDMI_TX_READ, sizeof(reg)); ++ if (ret) ++ goto err_scdc_read; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); ++ if (ret) ++ goto err_scdc_read; ++ ++ *data = reg[5]; ++ ++err_scdc_read: ++ if (ret) ++ DRM_ERROR("scdc read failed: %d\n", ret); ++ return ret; ++} ++ ++int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value) ++{ ++ u8 msg[5], reg[5]; ++ int ret; ++ ++ msg[0] = 0x54; ++ msg[1] = addr; ++ msg[2] = 0; ++ msg[3] = 1; ++ msg[4] = value; ++ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_WRITE, ++ sizeof(msg), msg); ++ if (ret) ++ goto err_scdc_write; ++ ++ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX, ++ HDMI_TX_WRITE, sizeof(reg)); ++ if (ret) ++ goto err_scdc_write; ++ ++ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); ++ if (ret) ++ goto err_scdc_write; ++ ++ if (reg[0] != 0) ++ ret = -EINVAL; ++ ++err_scdc_write: ++ if (ret) ++ DRM_ERROR("scdc write failed: %d\n", ret); ++ return ret; ++} ++ ++int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp, ++ int protocol, ++ u32 char_rate) ++{ ++ u32 reg0; ++ u32 reg1; ++ u32 val; ++ int ret; ++ ++ /* Set PHY to HDMI data */ ++ ret = cdns_mhdp_reg_write(mhdp, PHY_DATA_SEL, F_SOURCE_PHY_MHDP_SEL(1)); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_HPD, ++ F_HPD_VALID_WIDTH(4) | F_HPD_GLITCH_WIDTH(0)); ++ if (ret < 0) ++ return ret; ++ ++ /* open CARS */ ++ ret = cdns_mhdp_reg_write(mhdp, SOURCE_PHY_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, 0xFF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(mhdp, SOURCE_PKT_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(mhdp, SOURCE_AIF_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(mhdp, SOURCE_CIPHER_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(mhdp, SOURCE_CRYPTO_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(mhdp, SOURCE_CEC_CAR, 3); ++ if (ret < 0) ++ return ret; ++ ++ reg0 = reg1 = 0x7c1f; ++ if (protocol == MODE_HDMI_2_0 && char_rate >= 340000) { ++ reg0 = 0; ++ reg1 = 0xFFFFF; ++ } ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_0, reg0); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_1, reg1); ++ if (ret < 0) ++ return ret; ++ ++ /* set hdmi mode and preemble mode data enable */ ++ val = F_HDMI_MODE(protocol) | F_HDMI2_PREAMBLE_EN(1) | F_DATA_EN(1) | ++ F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) | F_PIC_3D(0XF); ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); ++ ++ return ret; ++} ++ ++int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp, ++ struct drm_display_mode *mode, ++ struct video_info *video_info) ++{ ++ int ret; ++ u32 val; ++ u32 vsync_lines = mode->vsync_end - mode->vsync_start; ++ u32 eof_lines = mode->vsync_start - mode->vdisplay; ++ u32 sof_lines = mode->vtotal - mode->vsync_end; ++ u32 hblank = mode->htotal - mode->hdisplay; ++ u32 hactive = mode->hdisplay; ++ u32 vblank = mode->vtotal - mode->vdisplay; ++ u32 vactive = mode->vdisplay; ++ u32 hfront = mode->hsync_start - mode->hdisplay; ++ u32 hback = mode->htotal - mode->hsync_end; ++ u32 vfront = eof_lines; ++ u32 hsync = hblank - hfront - hback; ++ u32 vsync = vsync_lines; ++ u32 vback = sof_lines; ++ u32 v_h_polarity = ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1) + ++ ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : 2); ++ ++ ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_H_SIZE, (hactive << 16) + hblank); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_V_SIZE, (vactive << 16) + vblank); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_FRONT_WIDTH, (vfront << 16) + hfront); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_SYNC_WIDTH, (vsync << 16) + hsync); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_BACK_WIDTH, (vback << 16) + hback); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, v_h_polarity); ++ if (ret < 0) ++ return ret; ++ ++ /* Reset Data Enable */ ++ val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER); ++ val &= ~F_DATA_EN(1); ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); ++ if (ret < 0) ++ return ret; ++ ++ /* Set bpc */ ++ val &= ~F_VIF_DATA_WIDTH(3); ++ switch (video_info->color_depth) { ++ case 10: ++ val |= F_VIF_DATA_WIDTH(1); ++ break; ++ case 12: ++ val |= F_VIF_DATA_WIDTH(2); ++ break; ++ case 16: ++ val |= F_VIF_DATA_WIDTH(3); ++ break; ++ case 8: ++ default: ++ val |= F_VIF_DATA_WIDTH(0); ++ break; ++ } ++ ++ /* select color encoding */ ++ val &= ~F_HDMI_ENCODING(3); ++ switch (video_info->color_fmt) { ++ case YCBCR_4_4_4: ++ val |= F_HDMI_ENCODING(2); ++ break; ++ case YCBCR_4_2_2: ++ val |= F_HDMI_ENCODING(1); ++ break; ++ case YCBCR_4_2_0: ++ val |= F_HDMI_ENCODING(3); ++ break; ++ case PXL_RGB: ++ default: ++ val |= F_HDMI_ENCODING(0); ++ break; ++ } ++ ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); ++ if (ret < 0) ++ return ret; ++ ++ /* set data enable */ ++ val |= F_DATA_EN(1); ++ ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); ++ ++ return ret; ++} ++ ++int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp) ++{ ++ u32 val; ++ ++ val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER); ++ val &= ~F_GCP_EN(1); ++ ++ return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); ++} ++ ++int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp) ++{ ++ u32 val; ++ ++ val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER); ++ val |= F_GCP_EN(1); ++ ++ return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); ++} +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h +@@ -0,0 +1,209 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Cadence MHDP DP MST bridge driver. ++ * ++ * Copyright: 2018 Cadence Design Systems, Inc. ++ * ++ * Author: Quentin Schulz <quentin.schulz@free-electrons.com> ++ */ ++ ++ ++#ifndef CDNS_MHDP_H ++#define CDNS_MHDP_H ++ ++#include <drm/drm_dp_mst_helper.h> ++ ++#define CDNS_APB_CFG 0x00000 ++#define CDNS_APB_CTRL (CDNS_APB_CFG + 0x00) ++#define CDNS_MAILBOX_FULL (CDNS_APB_CFG + 0x08) ++#define CDNS_MAILBOX_EMPTY (CDNS_APB_CFG + 0x0c) ++#define CDNS_MAILBOX_TX_DATA (CDNS_APB_CFG + 0x10) ++#define CDNS_MAILBOX_RX_DATA (CDNS_APB_CFG + 0x14) ++#define CDNS_KEEP_ALIVE (CDNS_APB_CFG + 0x18) ++#define CDNS_KEEP_ALIVE_MASK GENMASK(7, 0) ++ ++#define CDNS_MB_INT_MASK (CDNS_APB_CFG + 0x34) ++ ++#define CDNS_SW_CLK_L (CDNS_APB_CFG + 0x3c) ++#define CDNS_SW_CLK_H (CDNS_APB_CFG + 0x40) ++#define CDNS_SW_EVENT0 (CDNS_APB_CFG + 0x44) ++#define CDNS_DPTX_HPD BIT(0) ++ ++#define CDNS_SW_EVENT1 (CDNS_APB_CFG + 0x48) ++#define CDNS_SW_EVENT2 (CDNS_APB_CFG + 0x4c) ++#define CDNS_SW_EVENT3 (CDNS_APB_CFG + 0x50) ++ ++#define CDNS_APB_INT_MASK (CDNS_APB_CFG + 0x6C) ++#define CDNS_APB_INT_MASK_MAILBOX_INT BIT(0) ++#define CDNS_APB_INT_MASK_SW_EVENT_INT BIT(1) ++ ++#define CDNS_DPTX_CAR (CDNS_APB_CFG + 0x904) ++#define CDNS_VIF_CLK_EN BIT(0) ++#define CDNS_VIF_CLK_RSTN BIT(1) ++ ++#define CDNS_SOURCE_VIDEO_IF(s) (0x00b00 + (s * 0x20)) ++#define CDNS_BND_HSYNC2VSYNC(s) (CDNS_SOURCE_VIDEO_IF(s) + \ ++ 0x00) ++#define CDNS_IP_DTCT_WIN GENMASK(11, 0) ++#define CDNS_IP_DET_INTERLACE_FORMAT BIT(12) ++#define CDNS_IP_BYPASS_V_INTERFACE BIT(13) ++ ++#define CDNS_HSYNC2VSYNC_POL_CTRL(s) (CDNS_SOURCE_VIDEO_IF(s) + \ ++ 0x10) ++#define CDNS_H2V_HSYNC_POL_ACTIVE_LOW BIT(1) ++#define CDNS_H2V_VSYNC_POL_ACTIVE_LOW BIT(2) ++ ++#define CDNS_DPTX_PHY_CONFIG 0x02000 ++#define CDNS_PHY_TRAINING_EN BIT(0) ++#define CDNS_PHY_TRAINING_TYPE(x) (((x) & GENMASK(3, 0)) << 1) ++#define CDNS_PHY_SCRAMBLER_BYPASS BIT(5) ++#define CDNS_PHY_ENCODER_BYPASS BIT(6) ++#define CDNS_PHY_SKEW_BYPASS BIT(7) ++#define CDNS_PHY_TRAINING_AUTO BIT(8) ++#define CDNS_PHY_LANE0_SKEW(x) (((x) & GENMASK(2, 0)) << 9) ++#define CDNS_PHY_LANE1_SKEW(x) (((x) & GENMASK(2, 0)) << 12) ++#define CDNS_PHY_LANE2_SKEW(x) (((x) & GENMASK(2, 0)) << 15) ++#define CDNS_PHY_LANE3_SKEW(x) (((x) & GENMASK(2, 0)) << 18) ++#define CDNS_PHY_COMMON_CONFIG (CDNS_PHY_LANE1_SKEW(1) | \ ++ CDNS_PHY_LANE2_SKEW(2) | \ ++ CDNS_PHY_LANE3_SKEW(3)) ++#define CDNS_PHY_10BIT_EN BIT(21) ++ ++#define CDNS_DPTX_FRAMER 0x02200 ++#define CDNS_DP_FRAMER_GLOBAL_CONFIG (CDNS_DPTX_FRAMER + 0x00) ++#define CDNS_DP_NUM_LANES(x) (x - 1) ++#define CDNS_DP_MST_EN BIT(2) ++#define CDNS_DP_FRAMER_EN BIT(3) ++#define CDNS_DP_RATE_GOVERNOR_EN BIT(4) ++#define CDNS_DP_NO_VIDEO_MODE BIT(5) ++#define CDNS_DP_DISABLE_PHY_RST BIT(6) ++#define CDNS_DP_WR_FAILING_EDGE_VSYNC BIT(7) ++ ++#define CDNS_DP_SW_RESET (CDNS_DPTX_FRAMER + 0x04) ++#define CDNS_DP_FRAMER_TU (CDNS_DPTX_FRAMER + 0x08) ++#define CDNS_DP_FRAMER_TU_SIZE(x) (((x) & GENMASK(6, 0)) << 8) ++#define CDNS_DP_FRAMER_TU_VS(x) ((x) & GENMASK(5, 0)) ++#define CDNS_DP_FRAMER_TU_CNT_RST_EN BIT(15) ++ ++#define CDNS_DPTX_STREAM(s) (0x03000 + s * 0x80) ++#define CDNS_DP_MSA_HORIZONTAL_0(s) (CDNS_DPTX_STREAM(s) + 0x00) ++#define CDNS_DP_MSAH0_H_TOTAL(x) (x) ++#define CDNS_DP_MSAH0_HSYNC_START(x) ((x) << 16) ++ ++#define CDNS_DP_MSA_HORIZONTAL_1(s) (CDNS_DPTX_STREAM(s) + 0x04) ++#define CDNS_DP_MSAH1_HSYNC_WIDTH(x) (x) ++#define CDNS_DP_MSAH1_HSYNC_POL_LOW BIT(15) ++#define CDNS_DP_MSAH1_HDISP_WIDTH(x) ((x) << 16) ++ ++#define CDNS_DP_MSA_VERTICAL_0(s) (CDNS_DPTX_STREAM(s) + 0x08) ++#define CDNS_DP_MSAV0_V_TOTAL(x) (x) ++#define CDNS_DP_MSAV0_VSYNC_START(x) ((x) << 16) ++ ++#define CDNS_DP_MSA_VERTICAL_1(s) (CDNS_DPTX_STREAM(s) + 0x0c) ++#define CDNS_DP_MSAV1_VSYNC_WIDTH(x) (x) ++#define CDNS_DP_MSAV1_VSYNC_POL_LOW BIT(15) ++#define CDNS_DP_MSAV1_VDISP_WIDTH(x) ((x) << 16) ++ ++#define CDNS_DP_MSA_MISC(s) (CDNS_DPTX_STREAM(s) + 0x10) ++#define CDNS_DP_STREAM_CONFIGs(s) (CDNS_DPTX_STREAM(s) + 0x14) ++#define CDNS_DP_STREAM_CONFIG_2(s) (CDNS_DPTX_STREAM(s) + 0x2c) ++#define CDNS_DP_SC2_TU_VS_DIFF(x) ((x) << 8) ++ ++#define CDNS_DP_HORIZONTAL(s) (CDNS_DPTX_STREAM(s) + 0x30) ++#define CDNS_DP_H_HSYNC_WIDTH(x) (x) ++#define CDNS_DP_H_H_TOTAL(x) ((x) << 16) ++ ++#define CDNS_DP_VERTICAL_0(s) (CDNS_DPTX_STREAM(s) + 0x34) ++#define CDNS_DP_V0_VHEIGHT(x) (x) ++#define CDNS_DP_V0_VSTART(x) ((x) << 16) ++ ++#define CDNS_DP_VERTICAL_1(s) (CDNS_DPTX_STREAM(s) + 0x38) ++#define CDNS_DP_V1_VTOTAL(x) (x) ++#define CDNS_DP_V1_VTOTAL_EVEN BIT(16) ++ ++#define CDNS_DP_FRAMER_PXL_REPR(s) (CDNS_DPTX_STREAM(s) + 0x4c) ++#define CDNS_DP_FRAMER_6_BPC BIT(0) ++#define CDNS_DP_FRAMER_8_BPC BIT(1) ++#define CDNS_DP_FRAMER_10_BPC BIT(2) ++#define CDNS_DP_FRAMER_12_BPC BIT(3) ++#define CDNS_DP_FRAMER_16_BPC BIT(4) ++#define CDNS_DP_FRAMER_PXL_FORMAT 0x8 ++#define CDNS_DP_FRAMER_RGB BIT(0) ++#define CDNS_DP_FRAMER_YCBCR444 BIT(1) ++#define CDNS_DP_FRAMER_YCBCR422 BIT(2) ++#define CDNS_DP_FRAMER_YCBCR420 BIT(3) ++#define CDNS_DP_FRAMER_Y_ONLY BIT(4) ++ ++#define CDNS_DP_FRAMER_SP(s) (CDNS_DPTX_STREAM(s) + 0x10) ++#define CDNS_DP_FRAMER_VSYNC_POL_LOW BIT(0) ++#define CDNS_DP_FRAMER_HSYNC_POL_LOW BIT(1) ++#define CDNS_DP_FRAMER_INTERLACE BIT(2) ++ ++#define CDNS_DP_LINE_THRESH(s) (CDNS_DPTX_STREAM(s) + 0x64) ++#define CDNS_DP_ACTIVE_LINE_THRESH(x) (x) ++ ++#define CDNS_DP_VB_ID(s) (CDNS_DPTX_STREAM(s) + 0x68) ++#define CDNS_DP_VB_ID_INTERLACED BIT(2) ++#define CDNS_DP_VB_ID_COMPRESSED BIT(6) ++ ++#define CDNS_DP_FRONT_BACK_PORCH(s) (CDNS_DPTX_STREAM(s) + 0x78) ++#define CDNS_DP_BACK_PORCH(x) (x) ++#define CDNS_DP_FRONT_PORCH(x) ((x) << 16) ++ ++#define CDNS_DP_BYTE_COUNT(s) (CDNS_DPTX_STREAM(s) + 0x7c) ++#define CDNS_DP_BYTE_COUNT_BYTES_IN_CHUNK_SHIFT 16 ++ ++#define CDNS_DP_MST_STREAM_CONFIG(s) (CDNS_DPTX_STREAM(s) + 0x14) ++#define CDNS_DP_MST_STRM_CFG_STREAM_EN BIT(0) ++#define CDNS_DP_MST_STRM_CFG_NO_VIDEO BIT(1) ++ ++#define CDNS_DP_MST_SLOT_ALLOCATE(s) (CDNS_DPTX_STREAM(s) + 0x44) ++#define CDNS_DP_S_ALLOC_START_SLOT(x) (x) ++#define CDNS_DP_S_ALLOC_END_SLOT(x) ((x) << 8) ++ ++#define CDNS_DP_RATE_GOVERNING(s) (CDNS_DPTX_STREAM(s) + 0x48) ++#define CDNS_DP_RG_TARG_AV_SLOTS_Y(x) (x) ++#define CDNS_DP_RG_TARG_AV_SLOTS_X(x) (x << 4) ++#define CDNS_DP_RG_ENABLE BIT(10) ++ ++#define CDNS_DP_MTPH_CONTROL 0x2264 ++#define CDNS_DP_MTPH_ECF_EN BIT(0) ++#define CDNS_DP_MTPH_ACT_EN BIT(1) ++#define CDNS_DP_MTPH_LVP_EN BIT(2) ++ ++#define CDNS_DP_MTPH_STATUS 0x226C ++#define CDNS_DP_MTPH_ACT_STATUS BIT(0) ++ ++ ++#define CDNS_DPTX_GLOBAL 0x02300 ++#define CDNS_DP_LANE_EN (CDNS_DPTX_GLOBAL + 0x00) ++#define CDNS_DP_LANE_EN_LANES(x) GENMASK(x - 1, 0) ++#define CDNS_DP_ENHNCD (CDNS_DPTX_GLOBAL + 0x04) ++ ++ ++#define to_mhdp_connector(x) container_of(x, struct cdns_mhdp_connector, base) ++#define to_mhdp_bridge(x) container_of(x, struct cdns_mhdp_bridge, base) ++#define mgr_to_mhdp(x) container_of(x, struct cdns_mhdp_device, mst_mgr) ++ ++#define CDNS_MHDP_MAX_STREAMS 4 ++ ++enum pixel_format { ++ PIXEL_FORMAT_RGB = 1, ++ PIXEL_FORMAT_YCBCR_444 = 2, ++ PIXEL_FORMAT_YCBCR_422 = 4, ++ PIXEL_FORMAT_YCBCR_420 = 8, ++ PIXEL_FORMAT_Y_ONLY = 16, ++}; ++ ++ ++int cdns_mhdp_mst_init(struct cdns_mhdp_device *mhdp); ++void cdns_mhdp_mst_deinit(struct cdns_mhdp_device *mhdp); ++bool cdns_mhdp_mst_probe(struct cdns_mhdp_device *mhdp); ++enum pixel_format cdns_mhdp_get_pxlfmt(u32 color_formats); ++u32 cdns_mhdp_get_bpp(u32 bpc, u32 color_formats); ++void cdns_mhdp_configure_video(struct drm_bridge *bridge); ++void cdns_mhdp_mst_enable(struct drm_bridge *bridge); ++void cdns_mhdp_mst_disable(struct drm_bridge *bridge); ++void cdns_mhdp_enable(struct drm_bridge *bridge); ++ ++#endif +--- a/drivers/gpu/drm/rockchip/Kconfig ++++ b/drivers/gpu/drm/rockchip/Kconfig +@@ -29,7 +29,9 @@ config ROCKCHIP_ANALOGIX_DP + + config ROCKCHIP_CDN_DP + bool "Rockchip cdn DP" +- depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m) ++ depends on DRM_ROCKCHIP ++ select EXTCON ++ select DRM_CDNS_MHDP + help + This selects support for Rockchip SoC specific extensions + for the cdn DP driver. If you want to enable Dp on +--- a/drivers/gpu/drm/rockchip/Makefile ++++ b/drivers/gpu/drm/rockchip/Makefile +@@ -8,7 +8,7 @@ rockchipdrm-y := rockchip_drm_drv.o rock + rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o + + rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o +-rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o ++rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o + rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o + rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o + rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o +--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c ++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c +@@ -25,7 +25,7 @@ + #include "rockchip_drm_vop.h" + + #define connector_to_dp(c) \ +- container_of(c, struct cdn_dp_device, mhdp.connector) ++ container_of(c, struct cdn_dp_device, mhdp.connector.base) + + #define encoder_to_dp(c) \ + container_of(c, struct cdn_dp_device, encoder) +@@ -282,7 +282,7 @@ static int cdn_dp_connector_mode_valid(s + { + struct cdn_dp_device *dp = connector_to_dp(connector); + struct drm_display_info *display_info = +- &dp->mhdp.connector.display_info; ++ &dp->mhdp.connector.base.display_info; + u32 requested, actual, rate, sink_max, source_max = 0; + u8 lanes, bpc; + +@@ -378,7 +378,7 @@ static int cdn_dp_get_sink_capability(st + } + + kfree(dp->edid); +- dp->edid = drm_do_get_edid(&dp->mhdp.connector, ++ dp->edid = drm_do_get_edid(&dp->mhdp.connector.base, + cdns_mhdp_get_edid_block, &dp->mhdp); + return 0; + } +@@ -484,8 +484,8 @@ static int cdn_dp_disable(struct cdn_dp_ + cdns_mhdp_set_firmware_active(&dp->mhdp, false); + cdn_dp_clk_disable(dp); + dp->active = false; +- dp->mhdp.link.rate = 0; +- dp->mhdp.link.num_lanes = 0; ++ dp->mhdp.dp.link.rate = 0; ++ dp->mhdp.dp.link.num_lanes = 0; + if (!dp->connected) { + kfree(dp->edid); + dp->edid = NULL; +@@ -550,7 +550,7 @@ static void cdn_dp_encoder_mode_set(stru + { + struct cdn_dp_device *dp = encoder_to_dp(encoder); + struct drm_display_info *display_info = +- &dp->mhdp.connector.display_info; ++ &dp->mhdp.connector.base.display_info; + struct video_info *video = &dp->mhdp.video_info; + + switch (display_info->bpc) { +@@ -578,7 +578,7 @@ static bool cdn_dp_check_link_status(str + struct cdn_dp_port *port = cdn_dp_connected_port(dp); + u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd); + +- if (!port || !dp->mhdp.link.rate || !dp->mhdp.link.num_lanes) ++ if (!port || !dp->mhdp.dp.link.rate || !dp->mhdp.dp.link.num_lanes) + return false; + + if (cdns_mhdp_dpcd_read(&dp->mhdp, DP_LANE0_1_STATUS, link_status, +@@ -807,7 +807,7 @@ static int cdn_dp_audio_hw_params(struct + + ret = cdns_mhdp_audio_config(&dp->mhdp, &audio); + if (!ret) +- dp->audio_info = audio; ++ dp->mhdp.audio_info = audio; + + out: + mutex_unlock(&dp->lock); +@@ -823,9 +823,9 @@ static void cdn_dp_audio_shutdown(struct + if (!dp->active) + goto out; + +- ret = cdns_mhdp_audio_stop(&dp->mhdp, &dp->audio_info); ++ ret = cdns_mhdp_audio_stop(&dp->mhdp, &dp->mhdp.audio_info); + if (!ret) +- dp->audio_info.format = AFMT_UNUSED; ++ dp->mhdp.audio_info.format = AFMT_UNUSED; + out: + mutex_unlock(&dp->lock); + } +@@ -854,8 +854,8 @@ static int cdn_dp_audio_get_eld(struct d + { + struct cdn_dp_device *dp = dev_get_drvdata(dev); + +- memcpy(buf, dp->mhdp.connector.eld, +- min(sizeof(dp->mhdp.connector.eld), len)); ++ memcpy(buf, dp->mhdp.connector.base.eld, ++ min(sizeof(dp->mhdp.connector.base.eld), len)); + + return 0; + } +@@ -877,11 +877,11 @@ static int cdn_dp_audio_codec_init(struc + .max_i2s_channels = 8, + }; + +- dp->audio_pdev = platform_device_register_data( +- dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, +- &codec_data, sizeof(codec_data)); ++ dp->mhdp.audio_pdev = platform_device_register_data( ++ dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, ++ &codec_data, sizeof(codec_data)); + +- return PTR_ERR_OR_ZERO(dp->audio_pdev); ++ return PTR_ERR_OR_ZERO(dp->mhdp.audio_pdev); + } + + static int cdn_dp_request_firmware(struct cdn_dp_device *dp) +@@ -927,7 +927,7 @@ static void cdn_dp_pd_event_work(struct + { + struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device, + event_work); +- struct drm_connector *connector = &dp->mhdp.connector; ++ struct drm_connector *connector = &dp->mhdp.connector.base; + enum drm_connector_status old_status; + struct device *dev = dp->mhdp.dev; + +@@ -965,8 +965,8 @@ static void cdn_dp_pd_event_work(struct + + /* Enabled and connected with a sink, re-train if requested */ + } else if (!cdn_dp_check_link_status(dp)) { +- unsigned int rate = dp->mhdp.link.rate; +- unsigned int lanes = dp->mhdp.link.num_lanes; ++ unsigned int rate = dp->mhdp.dp.link.rate; ++ unsigned int lanes = dp->mhdp.dp.link.num_lanes; + struct drm_display_mode *mode = &dp->mhdp.mode; + + DRM_DEV_INFO(dev, "Connected with sink. Re-train link\n"); +@@ -979,8 +979,8 @@ static void cdn_dp_pd_event_work(struct + + /* If training result is changed, update the video config */ + if (mode->clock && +- (rate != dp->mhdp.link.rate || +- lanes != dp->mhdp.link.num_lanes)) { ++ (rate != dp->mhdp.dp.link.rate || ++ lanes != dp->mhdp.dp.link.num_lanes)) { + ret = cdns_mhdp_config_video(&dp->mhdp); + if (ret) { + dp->connected = false; +@@ -1053,7 +1053,7 @@ static int cdn_dp_bind(struct device *de + + drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs); + +- connector = &dp->mhdp.connector; ++ connector = &dp->mhdp.connector.base; + connector->polled = DRM_CONNECTOR_POLL_HPD; + connector->dpms = DRM_MODE_DPMS_OFF; + +@@ -1104,7 +1104,7 @@ static void cdn_dp_unbind(struct device + { + struct cdn_dp_device *dp = dev_get_drvdata(dev); + struct drm_encoder *encoder = &dp->encoder; +- struct drm_connector *connector = &dp->mhdp.connector; ++ struct drm_connector *connector = &dp->mhdp.connector.base; + + cancel_work_sync(&dp->event_work); + cdn_dp_encoder_disable(encoder); +@@ -1208,7 +1208,7 @@ static int cdn_dp_remove(struct platform + { + struct cdn_dp_device *dp = platform_get_drvdata(pdev); + +- platform_device_unregister(dp->audio_pdev); ++ platform_device_unregister(dp->mhdp.audio_pdev); + cdn_dp_suspend(dp->mhdp.dev); + component_del(&pdev->dev, &cdn_dp_component_ops); + +--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h ++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h +@@ -7,12 +7,13 @@ + #ifndef _CDN_DP_CORE_H + #define _CDN_DP_CORE_H + ++#include <drm/bridge/cdns-mhdp-common.h> ++#include <drm/drmP.h> + #include <drm/drm_dp_helper.h> + #include <drm/drm_panel.h> + #include <drm/drm_probe_helper.h> + + #include "rockchip_drm_drv.h" +-#include "cdn-dp-reg.h" + + #define MAX_PHY 2 + +@@ -37,7 +38,6 @@ struct cdn_dp_device { + struct cdns_mhdp_device mhdp; + struct drm_device *drm_dev; + struct drm_encoder encoder; +- struct platform_device *audio_pdev; + struct work_struct event_work; + struct edid *edid; + +@@ -56,7 +56,6 @@ struct cdn_dp_device { + struct reset_control *dptx_rst; + struct reset_control *apb_rst; + struct reset_control *core_rst; +- struct audio_info audio_info; + struct cdn_dp_port *port[MAX_PHY]; + u8 ports; + u8 lanes; +--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c ++++ /dev/null +@@ -1,968 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/* +- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd +- * Author: Chris Zhong <zyw@rock-chips.com> +- */ +- +-#include <linux/clk.h> +-#include <linux/device.h> +-#include <linux/delay.h> +-#include <linux/io.h> +-#include <linux/iopoll.h> +-#include <linux/reset.h> +- +-#include "cdn-dp-core.h" +-#include "cdn-dp-reg.h" +- +-#define CDNS_DP_SPDIF_CLK 200000000 +-#define FW_ALIVE_TIMEOUT_US 1000000 +-#define MAILBOX_RETRY_US 1000 +-#define MAILBOX_TIMEOUT_US 5000000 +-#define LINK_TRAINING_RETRY_MS 20 +-#define LINK_TRAINING_TIMEOUT_MS 500 +- +-void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk) +-{ +- writel(clk / 1000000, mhdp->regs + SW_CLK_H); +-} +- +-void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp) +-{ +- u32 val; +- +- val = DPTX_FRMR_DATA_CLK_RSTN_EN | +- DPTX_FRMR_DATA_CLK_EN | +- DPTX_PHY_DATA_RSTN_EN | +- DPTX_PHY_DATA_CLK_EN | +- DPTX_PHY_CHAR_RSTN_EN | +- DPTX_PHY_CHAR_CLK_EN | +- SOURCE_AUX_SYS_CLK_RSTN_EN | +- SOURCE_AUX_SYS_CLK_EN | +- DPTX_SYS_CLK_RSTN_EN | +- DPTX_SYS_CLK_EN | +- CFG_DPTX_VIF_CLK_RSTN_EN | +- CFG_DPTX_VIF_CLK_EN; +- writel(val, mhdp->regs + SOURCE_DPTX_CAR); +- +- val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN; +- writel(val, mhdp->regs + SOURCE_PHY_CAR); +- +- val = SOURCE_PKT_SYS_RSTN_EN | +- SOURCE_PKT_SYS_CLK_EN | +- SOURCE_PKT_DATA_RSTN_EN | +- SOURCE_PKT_DATA_CLK_EN; +- writel(val, mhdp->regs + SOURCE_PKT_CAR); +- +- val = SPDIF_CDR_CLK_RSTN_EN | +- SPDIF_CDR_CLK_EN | +- SOURCE_AIF_SYS_RSTN_EN | +- SOURCE_AIF_SYS_CLK_EN | +- SOURCE_AIF_CLK_RSTN_EN | +- SOURCE_AIF_CLK_EN; +- writel(val, mhdp->regs + SOURCE_AIF_CAR); +- +- val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN | +- SOURCE_CIPHER_SYS_CLK_EN | +- SOURCE_CIPHER_CHAR_CLK_RSTN_EN | +- SOURCE_CIPHER_CHAR_CLK_EN; +- writel(val, mhdp->regs + SOURCE_CIPHER_CAR); +- +- val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN | +- SOURCE_CRYPTO_SYS_CLK_EN; +- writel(val, mhdp->regs + SOURCE_CRYPTO_CAR); +- +- /* enable Mailbox and PIF interrupt */ +- writel(0, mhdp->regs + APB_INT_MASK); +-} +- +-static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp) +-{ +- int val, ret; +- +- ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_EMPTY_ADDR, +- val, !val, MAILBOX_RETRY_US, +- MAILBOX_TIMEOUT_US); +- if (ret < 0) +- return ret; +- +- return readl(mhdp->regs + MAILBOX0_RD_DATA) & 0xff; +-} +- +-static int cdp_dp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val) +-{ +- int ret, full; +- +- ret = readx_poll_timeout(readl, mhdp->regs + MAILBOX_FULL_ADDR, +- full, !full, MAILBOX_RETRY_US, +- MAILBOX_TIMEOUT_US); +- if (ret < 0) +- return ret; +- +- writel(val, mhdp->regs + MAILBOX0_WR_DATA); +- +- return 0; +-} +- +-static int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp, +- u8 module_id, u8 opcode, +- u16 req_size) +-{ +- u32 mbox_size, i; +- u8 header[4]; +- int ret; +- +- /* read the header of the message */ +- for (i = 0; i < 4; i++) { +- ret = cdns_mhdp_mailbox_read(mhdp); +- if (ret < 0) +- return ret; +- +- header[i] = ret; +- } +- +- mbox_size = (header[2] << 8) | header[3]; +- +- if (opcode != header[0] || module_id != header[1] || +- req_size != mbox_size) { +- /* +- * If the message in mailbox is not what we want, we need to +- * clear the mailbox by reading its contents. +- */ +- for (i = 0; i < mbox_size; i++) +- if (cdns_mhdp_mailbox_read(mhdp) < 0) +- break; +- +- return -EINVAL; +- } +- +- return 0; +-} +- +-static int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp, +- u8 *buff, u16 buff_size) +-{ +- u32 i; +- int ret; +- +- for (i = 0; i < buff_size; i++) { +- ret = cdns_mhdp_mailbox_read(mhdp); +- if (ret < 0) +- return ret; +- +- buff[i] = ret; +- } +- +- return 0; +-} +- +-static int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id, +- u8 opcode, u16 size, u8 *message) +-{ +- u8 header[4]; +- int ret, i; +- +- header[0] = opcode; +- header[1] = module_id; +- header[2] = (size >> 8) & 0xff; +- header[3] = size & 0xff; +- +- for (i = 0; i < 4; i++) { +- ret = cdp_dp_mailbox_write(mhdp, header[i]); +- if (ret) +- return ret; +- } +- +- for (i = 0; i < size; i++) { +- ret = cdp_dp_mailbox_write(mhdp, message[i]); +- if (ret) +- return ret; +- } +- +- return 0; +-} +- +-static int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u16 addr, u32 val) +-{ +- u8 msg[6]; +- +- msg[0] = (addr >> 8) & 0xff; +- msg[1] = addr & 0xff; +- msg[2] = (val >> 24) & 0xff; +- msg[3] = (val >> 16) & 0xff; +- msg[4] = (val >> 8) & 0xff; +- msg[5] = val & 0xff; +- return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_WRITE_REGISTER, sizeof(msg), msg); +-} +- +-static int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr, +- u8 start_bit, u8 bits_no, u32 val) +-{ +- u8 field[8]; +- +- field[0] = (addr >> 8) & 0xff; +- field[1] = addr & 0xff; +- field[2] = start_bit; +- field[3] = bits_no; +- field[4] = (val >> 24) & 0xff; +- field[5] = (val >> 16) & 0xff; +- field[6] = (val >> 8) & 0xff; +- field[7] = val & 0xff; +- +- return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_WRITE_FIELD, sizeof(field), field); +-} +- +-int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp, +- u32 addr, u8 *data, u16 len) +-{ +- u8 msg[5], reg[5]; +- int ret; +- +- msg[0] = (len >> 8) & 0xff; +- msg[1] = len & 0xff; +- msg[2] = (addr >> 16) & 0xff; +- msg[3] = (addr >> 8) & 0xff; +- msg[4] = addr & 0xff; +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_READ_DPCD, sizeof(msg), msg); +- if (ret) +- goto err_dpcd_read; +- +- ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_READ_DPCD, +- sizeof(reg) + len); +- if (ret) +- goto err_dpcd_read; +- +- ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); +- if (ret) +- goto err_dpcd_read; +- +- ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len); +- +-err_dpcd_read: +- return ret; +-} +- +-int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value) +-{ +- u8 msg[6], reg[5]; +- int ret; +- +- msg[0] = 0; +- msg[1] = 1; +- msg[2] = (addr >> 16) & 0xff; +- msg[3] = (addr >> 8) & 0xff; +- msg[4] = addr & 0xff; +- msg[5] = value; +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_WRITE_DPCD, sizeof(msg), msg); +- if (ret) +- goto err_dpcd_write; +- +- ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_WRITE_DPCD, sizeof(reg)); +- if (ret) +- goto err_dpcd_write; +- +- ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); +- if (ret) +- goto err_dpcd_write; +- +- if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) +- ret = -EINVAL; +- +-err_dpcd_write: +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret); +- return ret; +-} +- +-int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem, +- u32 i_size, const u32 *d_mem, u32 d_size) +-{ +- u32 reg; +- int i, ret; +- +- /* reset ucpu before load firmware*/ +- writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET, +- mhdp->regs + APB_CTRL); +- +- for (i = 0; i < i_size; i += 4) +- writel(*i_mem++, mhdp->regs + ADDR_IMEM + i); +- +- for (i = 0; i < d_size; i += 4) +- writel(*d_mem++, mhdp->regs + ADDR_DMEM + i); +- +- /* un-reset ucpu */ +- writel(0, mhdp->regs + APB_CTRL); +- +- /* check the keep alive register to make sure fw working */ +- ret = readx_poll_timeout(readl, mhdp->regs + KEEP_ALIVE, +- reg, reg, 2000, FW_ALIVE_TIMEOUT_US); +- if (ret < 0) { +- DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n", +- reg); +- return -EINVAL; +- } +- +- reg = readl(mhdp->regs + VER_L) & 0xff; +- mhdp->fw_version = reg; +- reg = readl(mhdp->regs + VER_H) & 0xff; +- mhdp->fw_version |= reg << 8; +- reg = readl(mhdp->regs + VER_LIB_L_ADDR) & 0xff; +- mhdp->fw_version |= reg << 16; +- reg = readl(mhdp->regs + VER_LIB_H_ADDR) & 0xff; +- mhdp->fw_version |= reg << 24; +- +- DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version); +- +- return 0; +-} +- +-int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable) +-{ +- u8 msg[5]; +- int ret, i; +- +- msg[0] = GENERAL_MAIN_CONTROL; +- msg[1] = MB_MODULE_ID_GENERAL; +- msg[2] = 0; +- msg[3] = 1; +- msg[4] = enable ? FW_ACTIVE : FW_STANDBY; +- +- for (i = 0; i < sizeof(msg); i++) { +- ret = cdp_dp_mailbox_write(mhdp, msg[i]); +- if (ret) +- goto err_set_firmware_active; +- } +- +- /* read the firmware state */ +- for (i = 0; i < sizeof(msg); i++) { +- ret = cdns_mhdp_mailbox_read(mhdp); +- if (ret < 0) +- goto err_set_firmware_active; +- +- msg[i] = ret; +- } +- +- ret = 0; +- +-err_set_firmware_active: +- if (ret < 0) +- DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n"); +- return ret; +-} +- +-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip) +-{ +- u8 msg[8]; +- int ret; +- +- msg[0] = CDNS_DP_MAX_LINK_RATE; +- msg[1] = lanes | SCRAMBLER_EN; +- msg[2] = VOLTAGE_LEVEL_2; +- msg[3] = PRE_EMPHASIS_LEVEL_3; +- msg[4] = PTS1 | PTS2 | PTS3 | PTS4; +- msg[5] = FAST_LT_NOT_SUPPORT; +- msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; +- msg[7] = ENHANCED; +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_SET_HOST_CAPABILITIES, +- sizeof(msg), msg); +- if (ret) +- goto err_set_host_cap; +- +- ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL, +- AUX_HOST_INVERT); +- +-err_set_host_cap: +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret); +- return ret; +-} +- +-int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp) +-{ +- u8 msg[5]; +- int ret; +- +- memset(msg, 0, sizeof(msg)); +- +- msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING; +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_ENABLE_EVENT, sizeof(msg), msg); +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "set event config failed: %d\n", ret); +- +- return ret; +-} +- +-u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp) +-{ +- return readl(mhdp->regs + SW_EVENTS0); +-} +- +-int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp) +-{ +- u8 status; +- int ret; +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_HPD_STATE, 0, NULL); +- if (ret) +- goto err_get_hpd; +- +- ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_HPD_STATE, +- sizeof(status)); +- if (ret) +- goto err_get_hpd; +- +- ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status)); +- if (ret) +- goto err_get_hpd; +- +- return status; +- +-err_get_hpd: +- DRM_DEV_ERROR(mhdp->dev, "get hpd status failed: %d\n", ret); +- return ret; +-} +- +-int cdns_mhdp_get_edid_block(void *data, u8 *edid, +- unsigned int block, size_t length) +-{ +- struct cdns_mhdp_device *mhdp = data; +- u8 msg[2], reg[2], i; +- int ret; +- +- for (i = 0; i < 4; i++) { +- msg[0] = block / 2; +- msg[1] = block % 2; +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_GET_EDID, sizeof(msg), msg); +- if (ret) +- continue; +- +- ret = cdns_mhdp_mailbox_validate_receive(mhdp, +- MB_MODULE_ID_DP_TX, +- DPTX_GET_EDID, +- sizeof(reg) + length); +- if (ret) +- continue; +- +- ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); +- if (ret) +- continue; +- +- ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length); +- if (ret) +- continue; +- +- if (reg[0] == length && reg[1] == block / 2) +- break; +- } +- +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n", +- block, ret); +- +- return ret; +-} +- +-static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp) +-{ +- unsigned long timeout; +- u8 msg, event[2]; +- int ret; +- +- msg = LINK_TRAINING_RUN; +- +- /* start training */ +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_TRAINING_CONTROL, sizeof(msg), &msg); +- if (ret) +- goto err_training_start; +- +- timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); +- while (time_before(jiffies, timeout)) { +- msleep(LINK_TRAINING_RETRY_MS); +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_READ_EVENT, 0, NULL); +- if (ret) +- goto err_training_start; +- +- ret = cdns_mhdp_mailbox_validate_receive(mhdp, +- MB_MODULE_ID_DP_TX, +- DPTX_READ_EVENT, +- sizeof(event)); +- if (ret) +- goto err_training_start; +- +- ret = cdns_mhdp_mailbox_read_receive(mhdp, event, +- sizeof(event)); +- if (ret) +- goto err_training_start; +- +- if (event[1] & EQ_PHASE_FINISHED) +- return 0; +- } +- +- ret = -ETIMEDOUT; +- +-err_training_start: +- DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret); +- return ret; +-} +- +-static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp) +-{ +- u8 status[10]; +- int ret; +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT, +- 0, NULL); +- if (ret) +- goto err_get_training_status; +- +- ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_READ_LINK_STAT, +- sizeof(status)); +- if (ret) +- goto err_get_training_status; +- +- ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status)); +- if (ret) +- goto err_get_training_status; +- +- mhdp->link.rate = drm_dp_bw_code_to_link_rate(status[0]); +- mhdp->link.num_lanes = status[1]; +- +-err_get_training_status: +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n", ret); +- return ret; +-} +- +-int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp) +-{ +- int ret; +- +- ret = cdns_mhdp_training_start(mhdp); +- if (ret) { +- DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n", ret); +- return ret; +- } +- +- ret = cdns_mhdp_get_training_status(mhdp); +- if (ret) { +- DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n", ret); +- return ret; +- } +- +- DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->link.rate, +- mhdp->link.num_lanes); +- return ret; +-} +- +-int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active) +-{ +- u8 msg; +- int ret; +- +- msg = !!active; +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO, +- sizeof(msg), &msg); +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "set video status failed: %d\n", ret); +- +- return ret; +-} +- +-static int cdns_mhdp_get_msa_misc(struct video_info *video, +- struct drm_display_mode *mode) +-{ +- u32 msa_misc; +- u8 val[2] = {0}; +- +- switch (video->color_fmt) { +- case PXL_RGB: +- case Y_ONLY: +- val[0] = 0; +- break; +- /* set YUV default color space conversion to BT601 */ +- case YCBCR_4_4_4: +- val[0] = 6 + BT_601 * 8; +- break; +- case YCBCR_4_2_2: +- val[0] = 5 + BT_601 * 8; +- break; +- case YCBCR_4_2_0: +- val[0] = 5; +- break; +- }; +- +- switch (video->color_depth) { +- case 6: +- val[1] = 0; +- break; +- case 8: +- val[1] = 1; +- break; +- case 10: +- val[1] = 2; +- break; +- case 12: +- val[1] = 3; +- break; +- case 16: +- val[1] = 4; +- break; +- }; +- +- msa_misc = 2 * val[0] + 32 * val[1] + +- ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); +- +- return msa_misc; +-} +- +-int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp) +-{ +- struct video_info *video = &mhdp->video_info; +- struct drm_display_mode *mode = &mhdp->mode; +- u64 symbol; +- u32 val, link_rate, rem; +- u8 bit_per_pix, tu_size_reg = TU_SIZE; +- int ret; +- +- bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? +- (video->color_depth * 2) : (video->color_depth * 3); +- +- link_rate = mhdp->link.rate / 1000; +- +- ret = cdns_mhdp_reg_write(mhdp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); +- if (ret) +- goto err_config_video; +- +- ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, 0); +- if (ret) +- goto err_config_video; +- +- /* +- * get a best tu_size and valid symbol: +- * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 +- * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) +- * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set +- * TU += 2 and repeat 2nd step. +- */ +- do { +- tu_size_reg += 2; +- symbol = tu_size_reg * mode->clock * bit_per_pix; +- do_div(symbol, mhdp->link.num_lanes * link_rate * 8); +- rem = do_div(symbol, 1000); +- if (tu_size_reg > 64) { +- ret = -EINVAL; +- DRM_DEV_ERROR(mhdp->dev, +- "tu error, clk:%d, lanes:%d, rate:%d\n", +- mode->clock, mhdp->link.num_lanes, +- link_rate); +- goto err_config_video; +- } +- } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || +- (rem > 850) || (rem < 100)); +- +- val = symbol + (tu_size_reg << 8); +- val |= TU_CNT_RST_EN; +- ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_TU, val); +- if (ret) +- goto err_config_video; +- +- /* set the FIFO Buffer size */ +- val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; +- val /= (mhdp->link.num_lanes * link_rate); +- val = div_u64(8 * (symbol + 1), bit_per_pix) - val; +- val += 2; +- ret = cdns_mhdp_reg_write(mhdp, DP_VC_TABLE(15), val); +- +- switch (video->color_depth) { +- case 6: +- val = BCS_6; +- break; +- case 8: +- val = BCS_8; +- break; +- case 10: +- val = BCS_10; +- break; +- case 12: +- val = BCS_12; +- break; +- case 16: +- val = BCS_16; +- break; +- }; +- +- val += video->color_fmt << 8; +- ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_PXL_REPR, val); +- if (ret) +- goto err_config_video; +- +- val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0; +- val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0; +- ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_SP, val); +- if (ret) +- goto err_config_video; +- +- val = (mode->hsync_start - mode->hdisplay) << 16; +- val |= mode->htotal - mode->hsync_end; +- ret = cdns_mhdp_reg_write(mhdp, DP_FRONT_BACK_PORCH, val); +- if (ret) +- goto err_config_video; +- +- val = mode->hdisplay * bit_per_pix / 8; +- ret = cdns_mhdp_reg_write(mhdp, DP_BYTE_COUNT, val); +- if (ret) +- goto err_config_video; +- +- val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); +- ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_0, val); +- if (ret) +- goto err_config_video; +- +- val = mode->hsync_end - mode->hsync_start; +- val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15); +- ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_1, val); +- if (ret) +- goto err_config_video; +- +- val = mode->vtotal; +- val |= (mode->vtotal - mode->vsync_start) << 16; +- ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_0, val); +- if (ret) +- goto err_config_video; +- +- val = mode->vsync_end - mode->vsync_start; +- val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15); +- ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_1, val); +- if (ret) +- goto err_config_video; +- +- val = cdns_mhdp_get_msa_misc(video, mode); +- ret = cdns_mhdp_reg_write(mhdp, MSA_MISC, val); +- if (ret) +- goto err_config_video; +- +- ret = cdns_mhdp_reg_write(mhdp, STREAM_CONFIG, 1); +- if (ret) +- goto err_config_video; +- +- val = mode->hsync_end - mode->hsync_start; +- val |= mode->hdisplay << 16; +- ret = cdns_mhdp_reg_write(mhdp, DP_HORIZONTAL, val); +- if (ret) +- goto err_config_video; +- +- val = mode->vdisplay; +- val |= (mode->vtotal - mode->vsync_start) << 16; +- ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_0, val); +- if (ret) +- goto err_config_video; +- +- val = mode->vtotal; +- ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_1, val); +- if (ret) +- goto err_config_video; +- +- ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 2, 1, 0); +- +-err_config_video: +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret); +- return ret; +-} +- +-int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, +- struct audio_info *audio) +-{ +- int ret; +- +- ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0); +- if (ret) { +- DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret); +- return ret; +- } +- +- writel(0, mhdp->regs + SPDIF_CTRL_ADDR); +- +- /* clearn the audio config and reset */ +- writel(0, mhdp->regs + AUDIO_SRC_CNTL); +- writel(0, mhdp->regs + AUDIO_SRC_CNFG); +- writel(AUDIO_SW_RST, mhdp->regs + AUDIO_SRC_CNTL); +- writel(0, mhdp->regs + AUDIO_SRC_CNTL); +- +- /* reset smpl2pckt component */ +- writel(0, mhdp->regs + SMPL2PKT_CNTL); +- writel(AUDIO_SW_RST, mhdp->regs + SMPL2PKT_CNTL); +- writel(0, mhdp->regs + SMPL2PKT_CNTL); +- +- /* reset FIFO */ +- writel(AUDIO_SW_RST, mhdp->regs + FIFO_CNTL); +- writel(0, mhdp->regs + FIFO_CNTL); +- +- if (audio->format == AFMT_SPDIF) +- clk_disable_unprepare(mhdp->spdif_clk); +- +- return 0; +-} +- +-int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable) +-{ +- int ret; +- +- ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable); +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret); +- +- return ret; +-} +- +-static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp, +- struct audio_info *audio) +-{ +- int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; +- u32 val; +- +- if (audio->channels == 2) { +- if (mhdp->link.num_lanes == 1) +- sub_pckt_num = 2; +- else +- sub_pckt_num = 4; +- +- i2s_port_en_val = 1; +- } else if (audio->channels == 4) { +- i2s_port_en_val = 3; +- } +- +- writel(0x0, mhdp->regs + SPDIF_CTRL_ADDR); +- +- writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL); +- +- val = MAX_NUM_CH(audio->channels); +- val |= NUM_OF_I2S_PORTS(audio->channels); +- val |= AUDIO_TYPE_LPCM; +- val |= CFG_SUB_PCKT_NUM(sub_pckt_num); +- writel(val, mhdp->regs + SMPL2PKT_CNFG); +- +- if (audio->sample_width == 16) +- val = 0; +- else if (audio->sample_width == 24) +- val = 1 << 9; +- else +- val = 2 << 9; +- +- val |= AUDIO_CH_NUM(audio->channels); +- val |= I2S_DEC_PORT_EN(i2s_port_en_val); +- val |= TRANS_SMPL_WIDTH_32; +- writel(val, mhdp->regs + AUDIO_SRC_CNFG); +- +- for (i = 0; i < (audio->channels + 1) / 2; i++) { +- if (audio->sample_width == 16) +- val = (0x02 << 8) | (0x02 << 20); +- else if (audio->sample_width == 24) +- val = (0x0b << 8) | (0x0b << 20); +- +- val |= ((2 * i) << 4) | ((2 * i + 1) << 16); +- writel(val, mhdp->regs + STTS_BIT_CH(i)); +- } +- +- switch (audio->sample_rate) { +- case 32000: +- val = SAMPLING_FREQ(3) | +- ORIGINAL_SAMP_FREQ(0xc); +- break; +- case 44100: +- val = SAMPLING_FREQ(0) | +- ORIGINAL_SAMP_FREQ(0xf); +- break; +- case 48000: +- val = SAMPLING_FREQ(2) | +- ORIGINAL_SAMP_FREQ(0xd); +- break; +- case 88200: +- val = SAMPLING_FREQ(8) | +- ORIGINAL_SAMP_FREQ(0x7); +- break; +- case 96000: +- val = SAMPLING_FREQ(0xa) | +- ORIGINAL_SAMP_FREQ(5); +- break; +- case 176400: +- val = SAMPLING_FREQ(0xc) | +- ORIGINAL_SAMP_FREQ(3); +- break; +- case 192000: +- val = SAMPLING_FREQ(0xe) | +- ORIGINAL_SAMP_FREQ(1); +- break; +- } +- val |= 4; +- writel(val, mhdp->regs + COM_CH_STTS_BITS); +- +- writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL); +- writel(I2S_DEC_START, mhdp->regs + AUDIO_SRC_CNTL); +-} +- +-static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp) +-{ +- u32 val; +- +- writel(SYNC_WR_TO_CH_ZERO, mhdp->regs + FIFO_CNTL); +- +- val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); +- writel(val, mhdp->regs + SMPL2PKT_CNFG); +- writel(SMPL2PKT_EN, mhdp->regs + SMPL2PKT_CNTL); +- +- val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; +- writel(val, mhdp->regs + SPDIF_CTRL_ADDR); +- +- clk_prepare_enable(mhdp->spdif_clk); +- clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK); +-} +- +-int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp, +- struct audio_info *audio) +-{ +- int ret; +- +- /* reset the spdif clk before config */ +- if (audio->format == AFMT_SPDIF) { +- reset_control_assert(mhdp->spdif_rst); +- reset_control_deassert(mhdp->spdif_rst); +- } +- +- ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC); +- if (ret) +- goto err_audio_config; +- +- ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0); +- if (ret) +- goto err_audio_config; +- +- if (audio->format == AFMT_I2S) +- cdns_mhdp_audio_config_i2s(mhdp, audio); +- else if (audio->format == AFMT_SPDIF) +- cdns_mhdp_audio_config_spdif(mhdp); +- +- ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); +- +-err_audio_config: +- if (ret) +- DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret); +- return ret; +-} +--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h ++++ /dev/null +@@ -1,546 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd +- * Author: Chris Zhong <zyw@rock-chips.com> +- */ +- +-#ifndef _CDN_DP_REG_H +-#define _CDN_DP_REG_H +- +-#include <linux/bitops.h> +- +-#define ADDR_IMEM 0x10000 +-#define ADDR_DMEM 0x20000 +- +-/* APB CFG addr */ +-#define APB_CTRL 0 +-#define XT_INT_CTRL 0x04 +-#define MAILBOX_FULL_ADDR 0x08 +-#define MAILBOX_EMPTY_ADDR 0x0c +-#define MAILBOX0_WR_DATA 0x10 +-#define MAILBOX0_RD_DATA 0x14 +-#define KEEP_ALIVE 0x18 +-#define VER_L 0x1c +-#define VER_H 0x20 +-#define VER_LIB_L_ADDR 0x24 +-#define VER_LIB_H_ADDR 0x28 +-#define SW_DEBUG_L 0x2c +-#define SW_DEBUG_H 0x30 +-#define MAILBOX_INT_MASK 0x34 +-#define MAILBOX_INT_STATUS 0x38 +-#define SW_CLK_L 0x3c +-#define SW_CLK_H 0x40 +-#define SW_EVENTS0 0x44 +-#define SW_EVENTS1 0x48 +-#define SW_EVENTS2 0x4c +-#define SW_EVENTS3 0x50 +-#define XT_OCD_CTRL 0x60 +-#define APB_INT_MASK 0x6c +-#define APB_STATUS_MASK 0x70 +- +-/* audio decoder addr */ +-#define AUDIO_SRC_CNTL 0x30000 +-#define AUDIO_SRC_CNFG 0x30004 +-#define COM_CH_STTS_BITS 0x30008 +-#define STTS_BIT_CH(x) (0x3000c + ((x) << 2)) +-#define SPDIF_CTRL_ADDR 0x3004c +-#define SPDIF_CH1_CS_3100_ADDR 0x30050 +-#define SPDIF_CH1_CS_6332_ADDR 0x30054 +-#define SPDIF_CH1_CS_9564_ADDR 0x30058 +-#define SPDIF_CH1_CS_12796_ADDR 0x3005c +-#define SPDIF_CH1_CS_159128_ADDR 0x30060 +-#define SPDIF_CH1_CS_191160_ADDR 0x30064 +-#define SPDIF_CH2_CS_3100_ADDR 0x30068 +-#define SPDIF_CH2_CS_6332_ADDR 0x3006c +-#define SPDIF_CH2_CS_9564_ADDR 0x30070 +-#define SPDIF_CH2_CS_12796_ADDR 0x30074 +-#define SPDIF_CH2_CS_159128_ADDR 0x30078 +-#define SPDIF_CH2_CS_191160_ADDR 0x3007c +-#define SMPL2PKT_CNTL 0x30080 +-#define SMPL2PKT_CNFG 0x30084 +-#define FIFO_CNTL 0x30088 +-#define FIFO_STTS 0x3008c +- +-/* source pif addr */ +-#define SOURCE_PIF_WR_ADDR 0x30800 +-#define SOURCE_PIF_WR_REQ 0x30804 +-#define SOURCE_PIF_RD_ADDR 0x30808 +-#define SOURCE_PIF_RD_REQ 0x3080c +-#define SOURCE_PIF_DATA_WR 0x30810 +-#define SOURCE_PIF_DATA_RD 0x30814 +-#define SOURCE_PIF_FIFO1_FLUSH 0x30818 +-#define SOURCE_PIF_FIFO2_FLUSH 0x3081c +-#define SOURCE_PIF_STATUS 0x30820 +-#define SOURCE_PIF_INTERRUPT_SOURCE 0x30824 +-#define SOURCE_PIF_INTERRUPT_MASK 0x30828 +-#define SOURCE_PIF_PKT_ALLOC_REG 0x3082c +-#define SOURCE_PIF_PKT_ALLOC_WR_EN 0x30830 +-#define SOURCE_PIF_SW_RESET 0x30834 +- +-/* bellow registers need access by mailbox */ +-/* source car addr */ +-#define SOURCE_HDTX_CAR 0x0900 +-#define SOURCE_DPTX_CAR 0x0904 +-#define SOURCE_PHY_CAR 0x0908 +-#define SOURCE_CEC_CAR 0x090c +-#define SOURCE_CBUS_CAR 0x0910 +-#define SOURCE_PKT_CAR 0x0918 +-#define SOURCE_AIF_CAR 0x091c +-#define SOURCE_CIPHER_CAR 0x0920 +-#define SOURCE_CRYPTO_CAR 0x0924 +- +-/* clock meters addr */ +-#define CM_CTRL 0x0a00 +-#define CM_I2S_CTRL 0x0a04 +-#define CM_SPDIF_CTRL 0x0a08 +-#define CM_VID_CTRL 0x0a0c +-#define CM_LANE_CTRL 0x0a10 +-#define I2S_NM_STABLE 0x0a14 +-#define I2S_NCTS_STABLE 0x0a18 +-#define SPDIF_NM_STABLE 0x0a1c +-#define SPDIF_NCTS_STABLE 0x0a20 +-#define NMVID_MEAS_STABLE 0x0a24 +-#define I2S_MEAS 0x0a40 +-#define SPDIF_MEAS 0x0a80 +-#define NMVID_MEAS 0x0ac0 +- +-/* source vif addr */ +-#define BND_HSYNC2VSYNC 0x0b00 +-#define HSYNC2VSYNC_F1_L1 0x0b04 +-#define HSYNC2VSYNC_F2_L1 0x0b08 +-#define HSYNC2VSYNC_STATUS 0x0b0c +-#define HSYNC2VSYNC_POL_CTRL 0x0b10 +- +-/* dptx phy addr */ +-#define DP_TX_PHY_CONFIG_REG 0x2000 +-#define DP_TX_PHY_SW_RESET 0x2004 +-#define DP_TX_PHY_SCRAMBLER_SEED 0x2008 +-#define DP_TX_PHY_TRAINING_01_04 0x200c +-#define DP_TX_PHY_TRAINING_05_08 0x2010 +-#define DP_TX_PHY_TRAINING_09_10 0x2014 +-#define TEST_COR 0x23fc +- +-/* dptx hpd addr */ +-#define HPD_IRQ_DET_MIN_TIMER 0x2100 +-#define HPD_IRQ_DET_MAX_TIMER 0x2104 +-#define HPD_UNPLGED_DET_MIN_TIMER 0x2108 +-#define HPD_STABLE_TIMER 0x210c +-#define HPD_FILTER_TIMER 0x2110 +-#define HPD_EVENT_MASK 0x211c +-#define HPD_EVENT_DET 0x2120 +- +-/* dpyx framer addr */ +-#define DP_FRAMER_GLOBAL_CONFIG 0x2200 +-#define DP_SW_RESET 0x2204 +-#define DP_FRAMER_TU 0x2208 +-#define DP_FRAMER_PXL_REPR 0x220c +-#define DP_FRAMER_SP 0x2210 +-#define AUDIO_PACK_CONTROL 0x2214 +-#define DP_VC_TABLE(x) (0x2218 + ((x) << 2)) +-#define DP_VB_ID 0x2258 +-#define DP_MTPH_LVP_CONTROL 0x225c +-#define DP_MTPH_SYMBOL_VALUES 0x2260 +-#define DP_MTPH_ECF_CONTROL 0x2264 +-#define DP_MTPH_ACT_CONTROL 0x2268 +-#define DP_MTPH_STATUS 0x226c +-#define DP_INTERRUPT_SOURCE 0x2270 +-#define DP_INTERRUPT_MASK 0x2274 +-#define DP_FRONT_BACK_PORCH 0x2278 +-#define DP_BYTE_COUNT 0x227c +- +-/* dptx stream addr */ +-#define MSA_HORIZONTAL_0 0x2280 +-#define MSA_HORIZONTAL_1 0x2284 +-#define MSA_VERTICAL_0 0x2288 +-#define MSA_VERTICAL_1 0x228c +-#define MSA_MISC 0x2290 +-#define STREAM_CONFIG 0x2294 +-#define AUDIO_PACK_STATUS 0x2298 +-#define VIF_STATUS 0x229c +-#define PCK_STUFF_STATUS_0 0x22a0 +-#define PCK_STUFF_STATUS_1 0x22a4 +-#define INFO_PACK_STATUS 0x22a8 +-#define RATE_GOVERNOR_STATUS 0x22ac +-#define DP_HORIZONTAL 0x22b0 +-#define DP_VERTICAL_0 0x22b4 +-#define DP_VERTICAL_1 0x22b8 +-#define DP_BLOCK_SDP 0x22bc +- +-/* dptx glbl addr */ +-#define DPTX_LANE_EN 0x2300 +-#define DPTX_ENHNCD 0x2304 +-#define DPTX_INT_MASK 0x2308 +-#define DPTX_INT_STATUS 0x230c +- +-/* dp aux addr */ +-#define DP_AUX_HOST_CONTROL 0x2800 +-#define DP_AUX_INTERRUPT_SOURCE 0x2804 +-#define DP_AUX_INTERRUPT_MASK 0x2808 +-#define DP_AUX_SWAP_INVERSION_CONTROL 0x280c +-#define DP_AUX_SEND_NACK_TRANSACTION 0x2810 +-#define DP_AUX_CLEAR_RX 0x2814 +-#define DP_AUX_CLEAR_TX 0x2818 +-#define DP_AUX_TIMER_STOP 0x281c +-#define DP_AUX_TIMER_CLEAR 0x2820 +-#define DP_AUX_RESET_SW 0x2824 +-#define DP_AUX_DIVIDE_2M 0x2828 +-#define DP_AUX_TX_PREACHARGE_LENGTH 0x282c +-#define DP_AUX_FREQUENCY_1M_MAX 0x2830 +-#define DP_AUX_FREQUENCY_1M_MIN 0x2834 +-#define DP_AUX_RX_PRE_MIN 0x2838 +-#define DP_AUX_RX_PRE_MAX 0x283c +-#define DP_AUX_TIMER_PRESET 0x2840 +-#define DP_AUX_NACK_FORMAT 0x2844 +-#define DP_AUX_TX_DATA 0x2848 +-#define DP_AUX_RX_DATA 0x284c +-#define DP_AUX_TX_STATUS 0x2850 +-#define DP_AUX_RX_STATUS 0x2854 +-#define DP_AUX_RX_CYCLE_COUNTER 0x2858 +-#define DP_AUX_MAIN_STATES 0x285c +-#define DP_AUX_MAIN_TIMER 0x2860 +-#define DP_AUX_AFE_OUT 0x2864 +- +-/* crypto addr */ +-#define CRYPTO_HDCP_REVISION 0x5800 +-#define HDCP_CRYPTO_CONFIG 0x5804 +-#define CRYPTO_INTERRUPT_SOURCE 0x5808 +-#define CRYPTO_INTERRUPT_MASK 0x580c +-#define CRYPTO22_CONFIG 0x5818 +-#define CRYPTO22_STATUS 0x581c +-#define SHA_256_DATA_IN 0x583c +-#define SHA_256_DATA_OUT_(x) (0x5850 + ((x) << 2)) +-#define AES_32_KEY_(x) (0x5870 + ((x) << 2)) +-#define AES_32_DATA_IN 0x5880 +-#define AES_32_DATA_OUT_(x) (0x5884 + ((x) << 2)) +-#define CRYPTO14_CONFIG 0x58a0 +-#define CRYPTO14_STATUS 0x58a4 +-#define CRYPTO14_PRNM_OUT 0x58a8 +-#define CRYPTO14_KM_0 0x58ac +-#define CRYPTO14_KM_1 0x58b0 +-#define CRYPTO14_AN_0 0x58b4 +-#define CRYPTO14_AN_1 0x58b8 +-#define CRYPTO14_YOUR_KSV_0 0x58bc +-#define CRYPTO14_YOUR_KSV_1 0x58c0 +-#define CRYPTO14_MI_0 0x58c4 +-#define CRYPTO14_MI_1 0x58c8 +-#define CRYPTO14_TI_0 0x58cc +-#define CRYPTO14_KI_0 0x58d0 +-#define CRYPTO14_KI_1 0x58d4 +-#define CRYPTO14_BLOCKS_NUM 0x58d8 +-#define CRYPTO14_KEY_MEM_DATA_0 0x58dc +-#define CRYPTO14_KEY_MEM_DATA_1 0x58e0 +-#define CRYPTO14_SHA1_MSG_DATA 0x58e4 +-#define CRYPTO14_SHA1_V_VALUE_(x) (0x58e8 + ((x) << 2)) +-#define TRNG_CTRL 0x58fc +-#define TRNG_DATA_RDY 0x5900 +-#define TRNG_DATA 0x5904 +- +-/* cipher addr */ +-#define HDCP_REVISION 0x60000 +-#define INTERRUPT_SOURCE 0x60004 +-#define INTERRUPT_MASK 0x60008 +-#define HDCP_CIPHER_CONFIG 0x6000c +-#define AES_128_KEY_0 0x60010 +-#define AES_128_KEY_1 0x60014 +-#define AES_128_KEY_2 0x60018 +-#define AES_128_KEY_3 0x6001c +-#define AES_128_RANDOM_0 0x60020 +-#define AES_128_RANDOM_1 0x60024 +-#define CIPHER14_KM_0 0x60028 +-#define CIPHER14_KM_1 0x6002c +-#define CIPHER14_STATUS 0x60030 +-#define CIPHER14_RI_PJ_STATUS 0x60034 +-#define CIPHER_MODE 0x60038 +-#define CIPHER14_AN_0 0x6003c +-#define CIPHER14_AN_1 0x60040 +-#define CIPHER22_AUTH 0x60044 +-#define CIPHER14_R0_DP_STATUS 0x60048 +-#define CIPHER14_BOOTSTRAP 0x6004c +- +-#define DPTX_FRMR_DATA_CLK_RSTN_EN BIT(11) +-#define DPTX_FRMR_DATA_CLK_EN BIT(10) +-#define DPTX_PHY_DATA_RSTN_EN BIT(9) +-#define DPTX_PHY_DATA_CLK_EN BIT(8) +-#define DPTX_PHY_CHAR_RSTN_EN BIT(7) +-#define DPTX_PHY_CHAR_CLK_EN BIT(6) +-#define SOURCE_AUX_SYS_CLK_RSTN_EN BIT(5) +-#define SOURCE_AUX_SYS_CLK_EN BIT(4) +-#define DPTX_SYS_CLK_RSTN_EN BIT(3) +-#define DPTX_SYS_CLK_EN BIT(2) +-#define CFG_DPTX_VIF_CLK_RSTN_EN BIT(1) +-#define CFG_DPTX_VIF_CLK_EN BIT(0) +- +-#define SOURCE_PHY_RSTN_EN BIT(1) +-#define SOURCE_PHY_CLK_EN BIT(0) +- +-#define SOURCE_PKT_SYS_RSTN_EN BIT(3) +-#define SOURCE_PKT_SYS_CLK_EN BIT(2) +-#define SOURCE_PKT_DATA_RSTN_EN BIT(1) +-#define SOURCE_PKT_DATA_CLK_EN BIT(0) +- +-#define SPDIF_CDR_CLK_RSTN_EN BIT(5) +-#define SPDIF_CDR_CLK_EN BIT(4) +-#define SOURCE_AIF_SYS_RSTN_EN BIT(3) +-#define SOURCE_AIF_SYS_CLK_EN BIT(2) +-#define SOURCE_AIF_CLK_RSTN_EN BIT(1) +-#define SOURCE_AIF_CLK_EN BIT(0) +- +-#define SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN BIT(3) +-#define SOURCE_CIPHER_SYS_CLK_EN BIT(2) +-#define SOURCE_CIPHER_CHAR_CLK_RSTN_EN BIT(1) +-#define SOURCE_CIPHER_CHAR_CLK_EN BIT(0) +- +-#define SOURCE_CRYPTO_SYS_CLK_RSTN_EN BIT(1) +-#define SOURCE_CRYPTO_SYS_CLK_EN BIT(0) +- +-#define APB_IRAM_PATH BIT(2) +-#define APB_DRAM_PATH BIT(1) +-#define APB_XT_RESET BIT(0) +- +-#define MAILBOX_INT_MASK_BIT BIT(1) +-#define PIF_INT_MASK_BIT BIT(0) +-#define ALL_INT_MASK 3 +- +-/* mailbox */ +-#define MB_OPCODE_ID 0 +-#define MB_MODULE_ID 1 +-#define MB_SIZE_MSB_ID 2 +-#define MB_SIZE_LSB_ID 3 +-#define MB_DATA_ID 4 +- +-#define MB_MODULE_ID_DP_TX 0x01 +-#define MB_MODULE_ID_HDCP_TX 0x07 +-#define MB_MODULE_ID_HDCP_RX 0x08 +-#define MB_MODULE_ID_HDCP_GENERAL 0x09 +-#define MB_MODULE_ID_GENERAL 0x0a +- +-/* general opcode */ +-#define GENERAL_MAIN_CONTROL 0x01 +-#define GENERAL_TEST_ECHO 0x02 +-#define GENERAL_BUS_SETTINGS 0x03 +-#define GENERAL_TEST_ACCESS 0x04 +- +-#define DPTX_SET_POWER_MNG 0x00 +-#define DPTX_SET_HOST_CAPABILITIES 0x01 +-#define DPTX_GET_EDID 0x02 +-#define DPTX_READ_DPCD 0x03 +-#define DPTX_WRITE_DPCD 0x04 +-#define DPTX_ENABLE_EVENT 0x05 +-#define DPTX_WRITE_REGISTER 0x06 +-#define DPTX_READ_REGISTER 0x07 +-#define DPTX_WRITE_FIELD 0x08 +-#define DPTX_TRAINING_CONTROL 0x09 +-#define DPTX_READ_EVENT 0x0a +-#define DPTX_READ_LINK_STAT 0x0b +-#define DPTX_SET_VIDEO 0x0c +-#define DPTX_SET_AUDIO 0x0d +-#define DPTX_GET_LAST_AUX_STAUS 0x0e +-#define DPTX_SET_LINK_BREAK_POINT 0x0f +-#define DPTX_FORCE_LANES 0x10 +-#define DPTX_HPD_STATE 0x11 +- +-#define FW_STANDBY 0 +-#define FW_ACTIVE 1 +- +-#define DPTX_EVENT_ENABLE_HPD BIT(0) +-#define DPTX_EVENT_ENABLE_TRAINING BIT(1) +- +-#define LINK_TRAINING_NOT_ACTIVE 0 +-#define LINK_TRAINING_RUN 1 +-#define LINK_TRAINING_RESTART 2 +- +-#define CONTROL_VIDEO_IDLE 0 +-#define CONTROL_VIDEO_VALID 1 +- +-#define TU_CNT_RST_EN BIT(15) +-#define VIF_BYPASS_INTERLACE BIT(13) +-#define INTERLACE_FMT_DET BIT(12) +-#define INTERLACE_DTCT_WIN 0x20 +- +-#define DP_FRAMER_SP_INTERLACE_EN BIT(2) +-#define DP_FRAMER_SP_HSP BIT(1) +-#define DP_FRAMER_SP_VSP BIT(0) +- +-/* capability */ +-#define AUX_HOST_INVERT 3 +-#define FAST_LT_SUPPORT 1 +-#define FAST_LT_NOT_SUPPORT 0 +-#define LANE_MAPPING_NORMAL 0x1b +-#define LANE_MAPPING_FLIPPED 0xe4 +-#define ENHANCED 1 +-#define SCRAMBLER_EN BIT(4) +- +-#define FULL_LT_STARTED BIT(0) +-#define FASE_LT_STARTED BIT(1) +-#define CLK_RECOVERY_FINISHED BIT(2) +-#define EQ_PHASE_FINISHED BIT(3) +-#define FASE_LT_START_FINISHED BIT(4) +-#define CLK_RECOVERY_FAILED BIT(5) +-#define EQ_PHASE_FAILED BIT(6) +-#define FASE_LT_FAILED BIT(7) +- +-#define DPTX_HPD_EVENT BIT(0) +-#define DPTX_TRAINING_EVENT BIT(1) +-#define HDCP_TX_STATUS_EVENT BIT(4) +-#define HDCP2_TX_IS_KM_STORED_EVENT BIT(5) +-#define HDCP2_TX_STORE_KM_EVENT BIT(6) +-#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT BIT(7) +- +-#define TU_SIZE 30 +-#define CDNS_DP_MAX_LINK_RATE DP_LINK_BW_5_4 +- +-/* audio */ +-#define AUDIO_PACK_EN BIT(8) +-#define SAMPLING_FREQ(x) (((x) & 0xf) << 16) +-#define ORIGINAL_SAMP_FREQ(x) (((x) & 0xf) << 24) +-#define SYNC_WR_TO_CH_ZERO BIT(1) +-#define I2S_DEC_START BIT(1) +-#define AUDIO_SW_RST BIT(0) +-#define SMPL2PKT_EN BIT(1) +-#define MAX_NUM_CH(x) (((x) & 0x1f) - 1) +-#define NUM_OF_I2S_PORTS(x) ((((x) / 2 - 1) & 0x3) << 5) +-#define AUDIO_TYPE_LPCM (2 << 7) +-#define CFG_SUB_PCKT_NUM(x) ((((x) - 1) & 0x7) << 11) +-#define AUDIO_CH_NUM(x) ((((x) - 1) & 0x1f) << 2) +-#define TRANS_SMPL_WIDTH_16 0 +-#define TRANS_SMPL_WIDTH_24 BIT(11) +-#define TRANS_SMPL_WIDTH_32 (2 << 11) +-#define I2S_DEC_PORT_EN(x) (((x) & 0xf) << 17) +-#define SPDIF_ENABLE BIT(21) +-#define SPDIF_AVG_SEL BIT(20) +-#define SPDIF_JITTER_BYPASS BIT(19) +-#define SPDIF_FIFO_MID_RANGE(x) (((x) & 0xff) << 11) +-#define SPDIF_JITTER_THRSH(x) (((x) & 0xff) << 3) +-#define SPDIF_JITTER_AVG_WIN(x) ((x) & 0x7) +- +-/* Reference cycles when using lane clock as reference */ +-#define LANE_REF_CYC 0x8000 +- +-enum voltage_swing_level { +- VOLTAGE_LEVEL_0, +- VOLTAGE_LEVEL_1, +- VOLTAGE_LEVEL_2, +- VOLTAGE_LEVEL_3, +-}; +- +-enum pre_emphasis_level { +- PRE_EMPHASIS_LEVEL_0, +- PRE_EMPHASIS_LEVEL_1, +- PRE_EMPHASIS_LEVEL_2, +- PRE_EMPHASIS_LEVEL_3, +-}; +- +-enum pattern_set { +- PTS1 = BIT(0), +- PTS2 = BIT(1), +- PTS3 = BIT(2), +- PTS4 = BIT(3), +- DP_NONE = BIT(4) +-}; +- +-enum vic_color_depth { +- BCS_6 = 0x1, +- BCS_8 = 0x2, +- BCS_10 = 0x4, +- BCS_12 = 0x8, +- BCS_16 = 0x10, +-}; +- +-enum vic_bt_type { +- BT_601 = 0x0, +- BT_709 = 0x1, +-}; +- +-enum audio_format { +- AFMT_I2S = 0, +- AFMT_SPDIF = 1, +- AFMT_UNUSED, +-}; +- +-struct audio_info { +- enum audio_format format; +- int sample_rate; +- int channels; +- int sample_width; +-}; +- +-enum vic_pxl_encoding_format { +- PXL_RGB = 0x1, +- YCBCR_4_4_4 = 0x2, +- YCBCR_4_2_2 = 0x4, +- YCBCR_4_2_0 = 0x8, +- Y_ONLY = 0x10, +-}; +- +-struct video_info { +- bool h_sync_polarity; +- bool v_sync_polarity; +- bool interlaced; +- int color_depth; +- enum vic_pxl_encoding_format color_fmt; +-}; +- +-struct cdns_mhdp_host { +- unsigned int link_rate; +- u8 lanes_cnt; +- u8 volt_swing; +- u8 pre_emphasis; +- u8 pattern_supp; +- u8 fast_link; +- u8 lane_mapping; +- u8 enhanced; +-}; +- +-struct cdns_mhdp_sink { +- unsigned int link_rate; +- u8 lanes_cnt; +- u8 pattern_supp; +- u8 fast_link; +- u8 enhanced; +-}; +- +-struct cdns_mhdp_device { +- void __iomem *regs; +- +- struct device *dev; +- +- struct drm_dp_link link; +- struct drm_connector connector; +- struct clk *spdif_clk; +- struct reset_control *spdif_rst; +- +- struct drm_dp_aux aux; +- struct cdns_mhdp_host host; +- struct cdns_mhdp_sink sink; +- struct drm_bridge bridge; +- struct phy *phy; +- void __iomem *dbg_regs; +- +- struct video_info video_info; +- struct drm_display_mode mode; +- unsigned int fw_version; +-}; +- +-void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp); +-void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk); +-int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem, +- u32 i_size, const u32 *d_mem, u32 d_size); +-int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable); +-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip); +-int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp); +-u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp); +-int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp); +-int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value); +-int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp, +- u32 addr, u8 *data, u16 len); +-int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid, +- unsigned int block, size_t length); +-int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp); +-int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active); +-int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp); +-int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, +- struct audio_info *audio); +-int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable); +-int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp, +- struct audio_info *audio); +-#endif /* _CDN_DP_REG_H */ +--- /dev/null ++++ b/include/drm/bridge/cdns-mhdp-cbs.h +@@ -0,0 +1,29 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Cadence MHDP DP bridge callbacks. ++ * ++ * Copyright: 2018 Cadence Design Systems, Inc. ++ * ++ * Author: Piotr Sroka <piotrs@cadence.com> ++ */ ++ ++#ifndef CDNS_MHDP_CBS_H ++#define CDNS_MHDP_CBS_H ++ ++#include <drm/drm_bridge.h> ++ ++struct cdns_mhdp_mst_cbs_funcs { ++ struct drm_encoder *(*create_mst_encoder)(void *priv_data, ++ struct drm_bridge *bridge); ++ void (*destroy_mst_encoder)(void *priv_data, struct drm_bridge *bridge); ++}; ++ ++struct cdns_mhdp_mst_cbs { ++ struct cdns_mhdp_mst_cbs_funcs funcs; ++ void *priv_data; ++}; ++ ++int mhdp_bridge_attach_mst_cbs(struct drm_bridge *bridge, ++ struct cdns_mhdp_mst_cbs *cbs); ++ ++#endif +--- /dev/null ++++ b/include/drm/bridge/cdns-mhdp-common.h +@@ -0,0 +1,704 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd ++ * Author: Chris Zhong <zyw@rock-chips.com> ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef CDNS_MHDP_COMMON_H_ ++#define CDNS_MHDP_COMMON_H_ ++ ++#include <drm/bridge/cdns-mhdp-cbs.h> ++#include <drm/drm_bridge.h> ++#include <drm/drm_connector.h> ++#include <drm/drm_dp_helper.h> ++#include <drm/drm_dp_mst_helper.h> ++ ++#include <linux/bitops.h> ++ ++#define ADDR_IMEM 0x10000 ++#define ADDR_DMEM 0x20000 ++#define ADDR_PHY_AFE 0x80000 ++ ++/* APB CFG addr */ ++#define APB_CTRL 0 ++#define XT_INT_CTRL 0x04 ++#define MAILBOX_FULL_ADDR 0x08 ++#define MAILBOX_EMPTY_ADDR 0x0c ++#define MAILBOX0_WR_DATA 0x10 ++#define MAILBOX0_RD_DATA 0x14 ++#define KEEP_ALIVE 0x18 ++#define VER_L 0x1c ++#define VER_H 0x20 ++#define VER_LIB_L_ADDR 0x24 ++#define VER_LIB_H_ADDR 0x28 ++#define SW_DEBUG_L 0x2c ++#define SW_DEBUG_H 0x30 ++#define MAILBOX_INT_MASK 0x34 ++#define MAILBOX_INT_STATUS 0x38 ++#define SW_CLK_L 0x3c ++#define SW_CLK_H 0x40 ++#define SW_EVENTS0 0x44 ++#define SW_EVENTS1 0x48 ++#define SW_EVENTS2 0x4c ++#define SW_EVENTS3 0x50 ++#define XT_OCD_CTRL 0x60 ++#define APB_INT_MASK 0x6c ++#define APB_STATUS_MASK 0x70 ++ ++/* audio decoder addr */ ++#define AUDIO_SRC_CNTL 0x30000 ++#define AUDIO_SRC_CNFG 0x30004 ++#define COM_CH_STTS_BITS 0x30008 ++#define STTS_BIT_CH(x) (0x3000c + ((x) << 2)) ++#define SPDIF_CTRL_ADDR 0x3004c ++#define SPDIF_CH1_CS_3100_ADDR 0x30050 ++#define SPDIF_CH1_CS_6332_ADDR 0x30054 ++#define SPDIF_CH1_CS_9564_ADDR 0x30058 ++#define SPDIF_CH1_CS_12796_ADDR 0x3005c ++#define SPDIF_CH1_CS_159128_ADDR 0x30060 ++#define SPDIF_CH1_CS_191160_ADDR 0x30064 ++#define SPDIF_CH2_CS_3100_ADDR 0x30068 ++#define SPDIF_CH2_CS_6332_ADDR 0x3006c ++#define SPDIF_CH2_CS_9564_ADDR 0x30070 ++#define SPDIF_CH2_CS_12796_ADDR 0x30074 ++#define SPDIF_CH2_CS_159128_ADDR 0x30078 ++#define SPDIF_CH2_CS_191160_ADDR 0x3007c ++#define SMPL2PKT_CNTL 0x30080 ++#define SMPL2PKT_CNFG 0x30084 ++#define FIFO_CNTL 0x30088 ++#define FIFO_STTS 0x3008c ++ ++/* source pif addr */ ++#define SOURCE_PIF_WR_ADDR 0x30800 ++#define SOURCE_PIF_WR_REQ 0x30804 ++#define SOURCE_PIF_RD_ADDR 0x30808 ++#define SOURCE_PIF_RD_REQ 0x3080c ++#define SOURCE_PIF_DATA_WR 0x30810 ++#define SOURCE_PIF_DATA_RD 0x30814 ++#define SOURCE_PIF_FIFO1_FLUSH 0x30818 ++#define SOURCE_PIF_FIFO2_FLUSH 0x3081c ++#define SOURCE_PIF_STATUS 0x30820 ++#define SOURCE_PIF_INTERRUPT_SOURCE 0x30824 ++#define SOURCE_PIF_INTERRUPT_MASK 0x30828 ++#define SOURCE_PIF_PKT_ALLOC_REG 0x3082c ++#define SOURCE_PIF_PKT_ALLOC_WR_EN 0x30830 ++#define SOURCE_PIF_SW_RESET 0x30834 ++ ++/* bellow registers need access by mailbox */ ++/* source phy comp */ ++#define PHY_DATA_SEL 0x0818 ++#define LANES_CONFIG 0x0814 ++ ++/* source car addr */ ++#define SOURCE_HDTX_CAR 0x0900 ++#define SOURCE_DPTX_CAR 0x0904 ++#define SOURCE_PHY_CAR 0x0908 ++#define SOURCE_CEC_CAR 0x090c ++#define SOURCE_CBUS_CAR 0x0910 ++#define SOURCE_PKT_CAR 0x0918 ++#define SOURCE_AIF_CAR 0x091c ++#define SOURCE_CIPHER_CAR 0x0920 ++#define SOURCE_CRYPTO_CAR 0x0924 ++ ++/* mhdp tx_top_comp */ ++#define SCHEDULER_H_SIZE 0x1000 ++#define SCHEDULER_V_SIZE 0x1004 ++#define HDTX_SIGNAL_FRONT_WIDTH 0x100c ++#define HDTX_SIGNAL_SYNC_WIDTH 0x1010 ++#define HDTX_SIGNAL_BACK_WIDTH 0x1014 ++#define HDTX_CONTROLLER 0x1018 ++#define HDTX_HPD 0x1020 ++#define HDTX_CLOCK_REG_0 0x1024 ++#define HDTX_CLOCK_REG_1 0x1028 ++ ++/* clock meters addr */ ++#define CM_CTRL 0x0a00 ++#define CM_I2S_CTRL 0x0a04 ++#define CM_SPDIF_CTRL 0x0a08 ++#define CM_VID_CTRL 0x0a0c ++#define CM_LANE_CTRL 0x0a10 ++#define I2S_NM_STABLE 0x0a14 ++#define I2S_NCTS_STABLE 0x0a18 ++#define SPDIF_NM_STABLE 0x0a1c ++#define SPDIF_NCTS_STABLE 0x0a20 ++#define NMVID_MEAS_STABLE 0x0a24 ++#define I2S_MEAS 0x0a40 ++#define SPDIF_MEAS 0x0a80 ++#define NMVID_MEAS 0x0ac0 ++ ++/* source vif addr */ ++#define BND_HSYNC2VSYNC 0x0b00 ++#define HSYNC2VSYNC_F1_L1 0x0b04 ++#define HSYNC2VSYNC_F2_L1 0x0b08 ++#define HSYNC2VSYNC_STATUS 0x0b0c ++#define HSYNC2VSYNC_POL_CTRL 0x0b10 ++ ++/* dptx phy addr */ ++#define DP_TX_PHY_CONFIG_REG 0x2000 ++#define DP_TX_PHY_SW_RESET 0x2004 ++#define DP_TX_PHY_SCRAMBLER_SEED 0x2008 ++#define DP_TX_PHY_TRAINING_01_04 0x200c ++#define DP_TX_PHY_TRAINING_05_08 0x2010 ++#define DP_TX_PHY_TRAINING_09_10 0x2014 ++#define TEST_COR 0x23fc ++ ++/* dptx hpd addr */ ++#define HPD_IRQ_DET_MIN_TIMER 0x2100 ++#define HPD_IRQ_DET_MAX_TIMER 0x2104 ++#define HPD_UNPLGED_DET_MIN_TIMER 0x2108 ++#define HPD_STABLE_TIMER 0x210c ++#define HPD_FILTER_TIMER 0x2110 ++#define HPD_EVENT_MASK 0x211c ++#define HPD_EVENT_DET 0x2120 ++ ++/* dpyx framer addr */ ++#define DP_FRAMER_GLOBAL_CONFIG 0x2200 ++#define DP_SW_RESET 0x2204 ++#define DP_FRAMER_TU 0x2208 ++#define DP_FRAMER_PXL_REPR 0x220c ++#define DP_FRAMER_SP 0x2210 ++#define AUDIO_PACK_CONTROL 0x2214 ++#define DP_VC_TABLE(x) (0x2218 + ((x) << 2)) ++#define DP_VB_ID 0x2258 ++#define DP_MTPH_LVP_CONTROL 0x225c ++#define DP_MTPH_SYMBOL_VALUES 0x2260 ++#define DP_MTPH_ECF_CONTROL 0x2264 ++#define DP_MTPH_ACT_CONTROL 0x2268 ++#define DP_MTPH_STATUS 0x226c ++#define DP_INTERRUPT_SOURCE 0x2270 ++#define DP_INTERRUPT_MASK 0x2274 ++#define DP_FRONT_BACK_PORCH 0x2278 ++#define DP_BYTE_COUNT 0x227c ++ ++/* dptx stream addr */ ++#define MSA_HORIZONTAL_0 0x2280 ++#define MSA_HORIZONTAL_1 0x2284 ++#define MSA_VERTICAL_0 0x2288 ++#define MSA_VERTICAL_1 0x228c ++#define MSA_MISC 0x2290 ++#define STREAM_CONFIG 0x2294 ++#define AUDIO_PACK_STATUS 0x2298 ++#define VIF_STATUS 0x229c ++#define PCK_STUFF_STATUS_0 0x22a0 ++#define PCK_STUFF_STATUS_1 0x22a4 ++#define INFO_PACK_STATUS 0x22a8 ++#define RATE_GOVERNOR_STATUS 0x22ac ++#define DP_HORIZONTAL 0x22b0 ++#define DP_VERTICAL_0 0x22b4 ++#define DP_VERTICAL_1 0x22b8 ++#define DP_BLOCK_SDP 0x22bc ++ ++/* dptx glbl addr */ ++#define DPTX_LANE_EN 0x2300 ++#define DPTX_ENHNCD 0x2304 ++#define DPTX_INT_MASK 0x2308 ++#define DPTX_INT_STATUS 0x230c ++ ++/* dp aux addr */ ++#define DP_AUX_HOST_CONTROL 0x2800 ++#define DP_AUX_INTERRUPT_SOURCE 0x2804 ++#define DP_AUX_INTERRUPT_MASK 0x2808 ++#define DP_AUX_SWAP_INVERSION_CONTROL 0x280c ++#define DP_AUX_SEND_NACK_TRANSACTION 0x2810 ++#define DP_AUX_CLEAR_RX 0x2814 ++#define DP_AUX_CLEAR_TX 0x2818 ++#define DP_AUX_TIMER_STOP 0x281c ++#define DP_AUX_TIMER_CLEAR 0x2820 ++#define DP_AUX_RESET_SW 0x2824 ++#define DP_AUX_DIVIDE_2M 0x2828 ++#define DP_AUX_TX_PREACHARGE_LENGTH 0x282c ++#define DP_AUX_FREQUENCY_1M_MAX 0x2830 ++#define DP_AUX_FREQUENCY_1M_MIN 0x2834 ++#define DP_AUX_RX_PRE_MIN 0x2838 ++#define DP_AUX_RX_PRE_MAX 0x283c ++#define DP_AUX_TIMER_PRESET 0x2840 ++#define DP_AUX_NACK_FORMAT 0x2844 ++#define DP_AUX_TX_DATA 0x2848 ++#define DP_AUX_RX_DATA 0x284c ++#define DP_AUX_TX_STATUS 0x2850 ++#define DP_AUX_RX_STATUS 0x2854 ++#define DP_AUX_RX_CYCLE_COUNTER 0x2858 ++#define DP_AUX_MAIN_STATES 0x285c ++#define DP_AUX_MAIN_TIMER 0x2860 ++#define DP_AUX_AFE_OUT 0x2864 ++ ++/* crypto addr */ ++#define CRYPTO_HDCP_REVISION 0x5800 ++#define HDCP_CRYPTO_CONFIG 0x5804 ++#define CRYPTO_INTERRUPT_SOURCE 0x5808 ++#define CRYPTO_INTERRUPT_MASK 0x580c ++#define CRYPTO22_CONFIG 0x5818 ++#define CRYPTO22_STATUS 0x581c ++#define SHA_256_DATA_IN 0x583c ++#define SHA_256_DATA_OUT_(x) (0x5850 + ((x) << 2)) ++#define AES_32_KEY_(x) (0x5870 + ((x) << 2)) ++#define AES_32_DATA_IN 0x5880 ++#define AES_32_DATA_OUT_(x) (0x5884 + ((x) << 2)) ++#define CRYPTO14_CONFIG 0x58a0 ++#define CRYPTO14_STATUS 0x58a4 ++#define CRYPTO14_PRNM_OUT 0x58a8 ++#define CRYPTO14_KM_0 0x58ac ++#define CRYPTO14_KM_1 0x58b0 ++#define CRYPTO14_AN_0 0x58b4 ++#define CRYPTO14_AN_1 0x58b8 ++#define CRYPTO14_YOUR_KSV_0 0x58bc ++#define CRYPTO14_YOUR_KSV_1 0x58c0 ++#define CRYPTO14_MI_0 0x58c4 ++#define CRYPTO14_MI_1 0x58c8 ++#define CRYPTO14_TI_0 0x58cc ++#define CRYPTO14_KI_0 0x58d0 ++#define CRYPTO14_KI_1 0x58d4 ++#define CRYPTO14_BLOCKS_NUM 0x58d8 ++#define CRYPTO14_KEY_MEM_DATA_0 0x58dc ++#define CRYPTO14_KEY_MEM_DATA_1 0x58e0 ++#define CRYPTO14_SHA1_MSG_DATA 0x58e4 ++#define CRYPTO14_SHA1_V_VALUE_(x) (0x58e8 + ((x) << 2)) ++#define TRNG_CTRL 0x58fc ++#define TRNG_DATA_RDY 0x5900 ++#define TRNG_DATA 0x5904 ++ ++/* cipher addr */ ++#define HDCP_REVISION 0x60000 ++#define INTERRUPT_SOURCE 0x60004 ++#define INTERRUPT_MASK 0x60008 ++#define HDCP_CIPHER_CONFIG 0x6000c ++#define AES_128_KEY_0 0x60010 ++#define AES_128_KEY_1 0x60014 ++#define AES_128_KEY_2 0x60018 ++#define AES_128_KEY_3 0x6001c ++#define AES_128_RANDOM_0 0x60020 ++#define AES_128_RANDOM_1 0x60024 ++#define CIPHER14_KM_0 0x60028 ++#define CIPHER14_KM_1 0x6002c ++#define CIPHER14_STATUS 0x60030 ++#define CIPHER14_RI_PJ_STATUS 0x60034 ++#define CIPHER_MODE 0x60038 ++#define CIPHER14_AN_0 0x6003c ++#define CIPHER14_AN_1 0x60040 ++#define CIPHER22_AUTH 0x60044 ++#define CIPHER14_R0_DP_STATUS 0x60048 ++#define CIPHER14_BOOTSTRAP 0x6004c ++ ++#define DPTX_FRMR_DATA_CLK_RSTN_EN BIT(11) ++#define DPTX_FRMR_DATA_CLK_EN BIT(10) ++#define DPTX_PHY_DATA_RSTN_EN BIT(9) ++#define DPTX_PHY_DATA_CLK_EN BIT(8) ++#define DPTX_PHY_CHAR_RSTN_EN BIT(7) ++#define DPTX_PHY_CHAR_CLK_EN BIT(6) ++#define SOURCE_AUX_SYS_CLK_RSTN_EN BIT(5) ++#define SOURCE_AUX_SYS_CLK_EN BIT(4) ++#define DPTX_SYS_CLK_RSTN_EN BIT(3) ++#define DPTX_SYS_CLK_EN BIT(2) ++#define CFG_DPTX_VIF_CLK_RSTN_EN BIT(1) ++#define CFG_DPTX_VIF_CLK_EN BIT(0) ++ ++#define SOURCE_PHY_RSTN_EN BIT(1) ++#define SOURCE_PHY_CLK_EN BIT(0) ++ ++#define SOURCE_PKT_SYS_RSTN_EN BIT(3) ++#define SOURCE_PKT_SYS_CLK_EN BIT(2) ++#define SOURCE_PKT_DATA_RSTN_EN BIT(1) ++#define SOURCE_PKT_DATA_CLK_EN BIT(0) ++ ++#define SPDIF_CDR_CLK_RSTN_EN BIT(5) ++#define SPDIF_CDR_CLK_EN BIT(4) ++#define SOURCE_AIF_SYS_RSTN_EN BIT(3) ++#define SOURCE_AIF_SYS_CLK_EN BIT(2) ++#define SOURCE_AIF_CLK_RSTN_EN BIT(1) ++#define SOURCE_AIF_CLK_EN BIT(0) ++ ++#define SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN BIT(3) ++#define SOURCE_CIPHER_SYS_CLK_EN BIT(2) ++#define SOURCE_CIPHER_CHAR_CLK_RSTN_EN BIT(1) ++#define SOURCE_CIPHER_CHAR_CLK_EN BIT(0) ++ ++#define SOURCE_CRYPTO_SYS_CLK_RSTN_EN BIT(1) ++#define SOURCE_CRYPTO_SYS_CLK_EN BIT(0) ++ ++#define APB_IRAM_PATH BIT(2) ++#define APB_DRAM_PATH BIT(1) ++#define APB_XT_RESET BIT(0) ++ ++#define MAILBOX_INT_MASK_BIT BIT(1) ++#define PIF_INT_MASK_BIT BIT(0) ++#define ALL_INT_MASK 3 ++ ++/* mailbox */ ++#define MB_OPCODE_ID 0 ++#define MB_MODULE_ID 1 ++#define MB_SIZE_MSB_ID 2 ++#define MB_SIZE_LSB_ID 3 ++#define MB_DATA_ID 4 ++ ++#define MB_MODULE_ID_DP_TX 0x01 ++#define MB_MODULE_ID_HDMI_TX 0x03 ++#define MB_MODULE_ID_HDCP_TX 0x07 ++#define MB_MODULE_ID_HDCP_RX 0x08 ++#define MB_MODULE_ID_HDCP_GENERAL 0x09 ++#define MB_MODULE_ID_GENERAL 0x0A ++ ++/* general opcode */ ++#define GENERAL_MAIN_CONTROL 0x01 ++#define GENERAL_TEST_ECHO 0x02 ++#define GENERAL_BUS_SETTINGS 0x03 ++#define GENERAL_TEST_ACCESS 0x04 ++#define GENERAL_WRITE_REGISTER 0x05 ++#define GENERAL_WRITE_FIELD 0x06 ++#define GENERAL_READ_REGISTER 0x07 ++#define GENERAL_GET_HPD_STATE 0x11 ++ ++/* DPTX opcode */ ++#define DPTX_SET_POWER_MNG 0x00 ++#define DPTX_SET_HOST_CAPABILITIES 0x01 ++#define DPTX_GET_EDID 0x02 ++#define DPTX_READ_DPCD 0x03 ++#define DPTX_WRITE_DPCD 0x04 ++#define DPTX_ENABLE_EVENT 0x05 ++#define DPTX_WRITE_REGISTER 0x06 ++#define DPTX_READ_REGISTER 0x07 ++#define DPTX_WRITE_FIELD 0x08 ++#define DPTX_TRAINING_CONTROL 0x09 ++#define DPTX_READ_EVENT 0x0a ++#define DPTX_READ_LINK_STAT 0x0b ++#define DPTX_SET_VIDEO 0x0c ++#define DPTX_SET_AUDIO 0x0d ++#define DPTX_GET_LAST_AUX_STAUS 0x0e ++#define DPTX_SET_LINK_BREAK_POINT 0x0f ++#define DPTX_FORCE_LANES 0x10 ++#define DPTX_HPD_STATE 0x11 ++#define DPTX_ADJUST_LT 0x12 ++ ++/* HDMI TX opcode */ ++#define HDMI_TX_READ 0x00 ++#define HDMI_TX_WRITE 0x01 ++#define HDMI_TX_UPDATE_READ 0x02 ++#define HDMI_TX_EDID 0x03 ++#define HDMI_TX_EVENTS 0x04 ++#define HDMI_TX_HPD_STATUS 0x05 ++#define HDMI_TX_DEBUG_ECHO 0xAA ++#define HDMI_TX_TEST 0xBB ++#define HDMI_TX_EDID_INTERNAL 0xF0 ++ ++#define FW_STANDBY 0 ++#define FW_ACTIVE 1 ++ ++#define DPTX_EVENT_ENABLE_HPD BIT(0) ++#define DPTX_EVENT_ENABLE_TRAINING BIT(1) ++ ++#define LINK_TRAINING_NOT_ACTIVE 0 ++#define LINK_TRAINING_RUN 1 ++#define LINK_TRAINING_RESTART 2 ++ ++#define CONTROL_VIDEO_IDLE 0 ++#define CONTROL_VIDEO_VALID 1 ++ ++#define TU_CNT_RST_EN BIT(15) ++#define VIF_BYPASS_INTERLACE BIT(13) ++#define INTERLACE_FMT_DET BIT(12) ++#define INTERLACE_DTCT_WIN 0x20 ++ ++#define DP_FRAMER_SP_INTERLACE_EN BIT(2) ++#define DP_FRAMER_SP_HSP BIT(1) ++#define DP_FRAMER_SP_VSP BIT(0) ++ ++/* capability */ ++#define AUX_HOST_INVERT 3 ++#define FAST_LT_SUPPORT 1 ++#define FAST_LT_NOT_SUPPORT 0 ++#define LANE_MAPPING_NORMAL 0x1b ++#define LANE_MAPPING_FLIPPED 0xe4 ++#define ENHANCED 1 ++#define SCRAMBLER_EN BIT(4) ++ ++#define FULL_LT_STARTED BIT(0) ++#define FASE_LT_STARTED BIT(1) ++#define CLK_RECOVERY_FINISHED BIT(2) ++#define EQ_PHASE_FINISHED BIT(3) ++#define FASE_LT_START_FINISHED BIT(4) ++#define CLK_RECOVERY_FAILED BIT(5) ++#define EQ_PHASE_FAILED BIT(6) ++#define FASE_LT_FAILED BIT(7) ++ ++#define DPTX_HPD_EVENT BIT(0) ++#define DPTX_TRAINING_EVENT BIT(1) ++#define HDCP_TX_STATUS_EVENT BIT(4) ++#define HDCP2_TX_IS_KM_STORED_EVENT BIT(5) ++#define HDCP2_TX_STORE_KM_EVENT BIT(6) ++#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT BIT(7) ++ ++#define TU_SIZE 30 ++#define CDNS_DP_MAX_LINK_RATE DP_LINK_BW_5_4 ++ ++#define F_HDMI_ENCODING(x) (((x) & ((1 << 2) - 1)) << 16) ++#define F_VIF_DATA_WIDTH(x) (((x) & ((1 << 2) - 1)) << 2) ++#define F_HDMI_MODE(x) (((x) & ((1 << 2) - 1)) << 0) ++#define F_GCP_EN(x) (((x) & ((1 << 1) - 1)) << 12) ++#define F_DATA_EN(x) (((x) & ((1 << 1) - 1)) << 15) ++#define F_HDMI2_PREAMBLE_EN(x) (((x) & ((1 << 1) - 1)) << 18) ++#define F_PIC_3D(x) (((x) & ((1 << 4) - 1)) << 7) ++#define F_BCH_EN(x) (((x) & ((1 << 1) - 1)) << 11) ++#define F_SOURCE_PHY_MHDP_SEL(x) (((x) & ((1 << 2) - 1)) << 3) ++#define F_HPD_VALID_WIDTH(x) (((x) & ((1 << 12) - 1)) << 0) ++#define F_HPD_GLITCH_WIDTH(x) (((x) & ((1 << 8) - 1)) << 12) ++#define F_HDMI2_CTRL_IL_MODE(x) (((x) & ((1 << 1) - 1)) << 19) ++#define F_SOURCE_PHY_LANE0_SWAP(x) (((x) & ((1 << 2) - 1)) << 0) ++#define F_SOURCE_PHY_LANE1_SWAP(x) (((x) & ((1 << 2) - 1)) << 2) ++#define F_SOURCE_PHY_LANE2_SWAP(x) (((x) & ((1 << 2) - 1)) << 4) ++#define F_SOURCE_PHY_LANE3_SWAP(x) (((x) & ((1 << 2) - 1)) << 6) ++#define F_SOURCE_PHY_COMB_BYPASS(x) (((x) & ((1 << 1) - 1)) << 21) ++#define F_SOURCE_PHY_20_10(x) (((x) & ((1 << 1) - 1)) << 22) ++#define F_PKT_ALLOC_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 0) ++#define F_ACTIVE_IDLE_TYPE(x) (((x) & ((1 << 1) - 1)) << 17) ++#define F_FIFO1_FLUSH(x) (((x) & ((1 << 1) - 1)) << 0) ++#define F_PKT_ALLOC_WR_EN(x) (((x) & ((1 << 1) - 1)) << 0) ++#define F_DATA_WR(x) (x) ++#define F_WR_ADDR(x) (((x) & ((1 << 4) - 1)) << 0) ++#define F_HOST_WR(x) (((x) & ((1 << 1) - 1)) << 0) ++#define F_TYPE_VALID(x) (((x) & ((1 << 1) - 1)) << 16) ++#define F_PACKET_TYPE(x) (((x) & ((1 << 8) - 1)) << 8) ++ ++/* audio */ ++#define AUDIO_PACK_EN BIT(8) ++#define SAMPLING_FREQ(x) (((x) & 0xf) << 16) ++#define ORIGINAL_SAMP_FREQ(x) (((x) & 0xf) << 24) ++#define SYNC_WR_TO_CH_ZERO BIT(1) ++#define I2S_DEC_START BIT(1) ++#define AUDIO_SW_RST BIT(0) ++#define SMPL2PKT_EN BIT(1) ++#define MAX_NUM_CH(x) (((x) & 0x1f) - 1) ++#define NUM_OF_I2S_PORTS(x) ((((x) / 2 - 1) & 0x3) << 5) ++#define AUDIO_TYPE_LPCM (2 << 7) ++#define CFG_SUB_PCKT_NUM(x) ((((x) - 1) & 0x7) << 11) ++#define AUDIO_CH_NUM(x) ((((x) - 1) & 0x1f) << 2) ++#define TRANS_SMPL_WIDTH_16 0 ++#define TRANS_SMPL_WIDTH_24 BIT(11) ++#define TRANS_SMPL_WIDTH_32 (2 << 11) ++#define I2S_DEC_PORT_EN(x) (((x) & 0xf) << 17) ++#define SPDIF_ENABLE BIT(21) ++#define SPDIF_AVG_SEL BIT(20) ++#define SPDIF_JITTER_BYPASS BIT(19) ++#define SPDIF_FIFO_MID_RANGE(x) (((x) & 0xff) << 11) ++#define SPDIF_JITTER_THRSH(x) (((x) & 0xff) << 3) ++#define SPDIF_JITTER_AVG_WIN(x) ((x) & 0x7) ++ ++/* Reference cycles when using lane clock as reference */ ++#define LANE_REF_CYC 0x8000 ++ ++#define HOTPLUG_DEBOUNCE_MS 200 ++ ++enum voltage_swing_level { ++ VOLTAGE_LEVEL_0, ++ VOLTAGE_LEVEL_1, ++ VOLTAGE_LEVEL_2, ++ VOLTAGE_LEVEL_3, ++}; ++ ++enum pre_emphasis_level { ++ PRE_EMPHASIS_LEVEL_0, ++ PRE_EMPHASIS_LEVEL_1, ++ PRE_EMPHASIS_LEVEL_2, ++ PRE_EMPHASIS_LEVEL_3, ++}; ++ ++enum pattern_set { ++ PTS1 = BIT(0), ++ PTS2 = BIT(1), ++ PTS3 = BIT(2), ++ PTS4 = BIT(3), ++ DP_NONE = BIT(4) ++}; ++ ++enum vic_color_depth { ++ BCS_6 = 0x1, ++ BCS_8 = 0x2, ++ BCS_10 = 0x4, ++ BCS_12 = 0x8, ++ BCS_16 = 0x10, ++}; ++ ++enum vic_bt_type { ++ BT_601 = 0x0, ++ BT_709 = 0x1, ++}; ++ ++enum audio_format { ++ AFMT_I2S = 0, ++ AFMT_SPDIF = 1, ++ AFMT_UNUSED, ++}; ++ ++enum { ++ MODE_DVI, ++ MODE_HDMI_1_4, ++ MODE_HDMI_2_0, ++}; ++ ++struct audio_info { ++ enum audio_format format; ++ int sample_rate; ++ int channels; ++ int sample_width; ++}; ++ ++enum vic_pxl_encoding_format { ++ PXL_RGB = 0x1, ++ YCBCR_4_4_4 = 0x2, ++ YCBCR_4_2_2 = 0x4, ++ YCBCR_4_2_0 = 0x8, ++ Y_ONLY = 0x10, ++}; ++ ++struct video_info { ++ bool h_sync_polarity; ++ bool v_sync_polarity; ++ bool interlaced; ++ int color_depth; ++ enum vic_pxl_encoding_format color_fmt; ++}; ++ ++struct cdns_mhdp_host { ++ unsigned int link_rate; ++ u8 lanes_cnt; ++ u8 volt_swing; ++ u8 pre_emphasis; ++ u8 pattern_supp; ++ u8 fast_link; ++ u8 lane_mapping; ++ u8 enhanced; ++}; ++ ++struct cdns_mhdp_sink { ++ unsigned int link_rate; ++ u8 lanes_cnt; ++ u8 pattern_supp; ++ u8 fast_link; ++ u8 enhanced; ++}; ++ ++struct cdns_mhdp_bridge; ++struct cdns_mhdp_connector; ++ ++struct cdns_mhdp_bridge { ++ struct cdns_mhdp_device *mhdp; ++ struct drm_bridge base; ++ int pbn; ++ int8_t stream_id; ++ struct cdns_mhdp_connector *connector; ++ bool is_active; ++}; ++ ++struct cdns_mhdp_connector { ++ struct drm_connector base; ++ bool is_mst_connector; ++ struct drm_dp_mst_port *port; ++ struct cdns_mhdp_bridge *bridge; ++}; ++ ++struct cdns_mhdp_device { ++ void __iomem *regs; ++ ++ struct device *dev; ++ ++ struct cdns_mhdp_connector connector; ++ struct clk *spdif_clk; ++ struct reset_control *spdif_rst; ++ ++ struct platform_device *audio_pdev; ++ struct audio_info audio_info; ++ ++ struct cdns_mhdp_bridge bridge; ++ struct phy *phy; ++ ++ struct video_info video_info; ++ struct drm_display_mode mode; ++ unsigned int fw_version; ++ ++ struct drm_dp_mst_topology_mgr mst_mgr; ++ struct delayed_work hotplug_work; ++ ++ bool link_up; ++ bool power_up; ++ bool plugged; ++ ++ union { ++ struct _dp_data { ++ struct drm_dp_link link; ++ struct drm_dp_aux aux; ++ struct cdns_mhdp_host host; ++ struct cdns_mhdp_sink sink; ++ struct cdns_mhdp_mst_cbs cbs; ++ bool is_mst; ++ bool can_mst; ++ u32 lane_mapping; ++ u32 link_rate; ++ u32 num_lanes; ++ } dp; ++ struct _hdmi_data { ++ u32 char_rate; ++ u32 hdmi_type; ++ } hdmi; ++ }; ++}; ++ ++void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp); ++void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk); ++int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem, ++ u32 i_size, const u32 *d_mem, u32 d_size); ++int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable); ++int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, u8 lanes, bool flip); ++int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp); ++u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp); ++int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp); ++int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value); ++int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp, ++ u32 addr, u8 *data, u16 len); ++int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid, ++ unsigned int block, size_t length); ++int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp); ++int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active); ++int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp); ++int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, ++ struct audio_info *audio); ++int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable); ++int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp, ++ struct audio_info *audio); ++int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr); ++int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val); ++int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr, ++ u8 start_bit, u8 bits_no, u32 val); ++int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp, u8 nlanes, ++ u16 udelay, u8 *lanes_data, ++ u8 *dpcd); ++ ++int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp); ++u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr); ++int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val); ++int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id, ++ u8 opcode, u16 size, u8 *message); ++int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp, ++ u8 *buff, u16 buff_size); ++int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp, ++ u8 module_id, u8 opcode, ++ u16 req_size); ++int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp); ++ ++int cdns_hdmi_get_edid_block(void *data, u8 *edid, u32 block, size_t length); ++int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data); ++int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value); ++int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp, int protocol, u32 char_rate); ++int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp, struct drm_display_mode *mode, ++ struct video_info *video_info); ++int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp); ++int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp); ++ ++bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp); ++#endif /* CDNS_MHDP_COMMON_H_ */ |