18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 48c2ecf20Sopenharmony_ci * Author: Chris Zhong <zyw@rock-chips.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 128c2ecf20Sopenharmony_ci#include <linux/reset.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "cdn-dp-core.h" 158c2ecf20Sopenharmony_ci#include "cdn-dp-reg.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define CDN_DP_SPDIF_CLK 200000000 188c2ecf20Sopenharmony_ci#define FW_ALIVE_TIMEOUT_US 1000000 198c2ecf20Sopenharmony_ci#define MAILBOX_RETRY_US 1000 208c2ecf20Sopenharmony_ci#define MAILBOX_TIMEOUT_US 5000000 218c2ecf20Sopenharmony_ci#define LINK_TRAINING_RETRY_MS 20 228c2ecf20Sopenharmony_ci#define LINK_TRAINING_TIMEOUT_MS 500 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_civoid cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci writel(clk / 1000000, dp->regs + SW_CLK_H); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_civoid cdn_dp_clock_reset(struct cdn_dp_device *dp) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci u32 val; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci val = DPTX_FRMR_DATA_CLK_RSTN_EN | 348c2ecf20Sopenharmony_ci DPTX_FRMR_DATA_CLK_EN | 358c2ecf20Sopenharmony_ci DPTX_PHY_DATA_RSTN_EN | 368c2ecf20Sopenharmony_ci DPTX_PHY_DATA_CLK_EN | 378c2ecf20Sopenharmony_ci DPTX_PHY_CHAR_RSTN_EN | 388c2ecf20Sopenharmony_ci DPTX_PHY_CHAR_CLK_EN | 398c2ecf20Sopenharmony_ci SOURCE_AUX_SYS_CLK_RSTN_EN | 408c2ecf20Sopenharmony_ci SOURCE_AUX_SYS_CLK_EN | 418c2ecf20Sopenharmony_ci DPTX_SYS_CLK_RSTN_EN | 428c2ecf20Sopenharmony_ci DPTX_SYS_CLK_EN | 438c2ecf20Sopenharmony_ci CFG_DPTX_VIF_CLK_RSTN_EN | 448c2ecf20Sopenharmony_ci CFG_DPTX_VIF_CLK_EN; 458c2ecf20Sopenharmony_ci writel(val, dp->regs + SOURCE_DPTX_CAR); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN; 488c2ecf20Sopenharmony_ci writel(val, dp->regs + SOURCE_PHY_CAR); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci val = SOURCE_PKT_SYS_RSTN_EN | 518c2ecf20Sopenharmony_ci SOURCE_PKT_SYS_CLK_EN | 528c2ecf20Sopenharmony_ci SOURCE_PKT_DATA_RSTN_EN | 538c2ecf20Sopenharmony_ci SOURCE_PKT_DATA_CLK_EN; 548c2ecf20Sopenharmony_ci writel(val, dp->regs + SOURCE_PKT_CAR); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci val = SPDIF_CDR_CLK_RSTN_EN | 578c2ecf20Sopenharmony_ci SPDIF_CDR_CLK_EN | 588c2ecf20Sopenharmony_ci SOURCE_AIF_SYS_RSTN_EN | 598c2ecf20Sopenharmony_ci SOURCE_AIF_SYS_CLK_EN | 608c2ecf20Sopenharmony_ci SOURCE_AIF_CLK_RSTN_EN | 618c2ecf20Sopenharmony_ci SOURCE_AIF_CLK_EN; 628c2ecf20Sopenharmony_ci writel(val, dp->regs + SOURCE_AIF_CAR); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN | 658c2ecf20Sopenharmony_ci SOURCE_CIPHER_SYS_CLK_EN | 668c2ecf20Sopenharmony_ci SOURCE_CIPHER_CHAR_CLK_RSTN_EN | 678c2ecf20Sopenharmony_ci SOURCE_CIPHER_CHAR_CLK_EN; 688c2ecf20Sopenharmony_ci writel(val, dp->regs + SOURCE_CIPHER_CAR); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN | 718c2ecf20Sopenharmony_ci SOURCE_CRYPTO_SYS_CLK_EN; 728c2ecf20Sopenharmony_ci writel(val, dp->regs + SOURCE_CRYPTO_CAR); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* enable Mailbox and PIF interrupt */ 758c2ecf20Sopenharmony_ci writel(0, dp->regs + APB_INT_MASK); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int cdn_dp_mailbox_read(struct cdn_dp_device *dp) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int val, ret; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR, 838c2ecf20Sopenharmony_ci val, !val, MAILBOX_RETRY_US, 848c2ecf20Sopenharmony_ci MAILBOX_TIMEOUT_US); 858c2ecf20Sopenharmony_ci if (ret < 0) 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci int ret, full; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR, 968c2ecf20Sopenharmony_ci full, !full, MAILBOX_RETRY_US, 978c2ecf20Sopenharmony_ci MAILBOX_TIMEOUT_US); 988c2ecf20Sopenharmony_ci if (ret < 0) 998c2ecf20Sopenharmony_ci return ret; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci writel(val, dp->regs + MAILBOX0_WR_DATA); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp, 1078c2ecf20Sopenharmony_ci u8 module_id, u8 opcode, 1088c2ecf20Sopenharmony_ci u16 req_size) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci u32 mbox_size, i; 1118c2ecf20Sopenharmony_ci u8 header[4]; 1128c2ecf20Sopenharmony_ci int ret; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* read the header of the message */ 1158c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 1168c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read(dp); 1178c2ecf20Sopenharmony_ci if (ret < 0) 1188c2ecf20Sopenharmony_ci return ret; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci header[i] = ret; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci mbox_size = (header[2] << 8) | header[3]; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (opcode != header[0] || module_id != header[1] || 1268c2ecf20Sopenharmony_ci req_size != mbox_size) { 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * If the message in mailbox is not what we want, we need to 1298c2ecf20Sopenharmony_ci * clear the mailbox by reading its contents. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci for (i = 0; i < mbox_size; i++) 1328c2ecf20Sopenharmony_ci if (cdn_dp_mailbox_read(dp) < 0) 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return -EINVAL; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp, 1428c2ecf20Sopenharmony_ci u8 *buff, u16 buff_size) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci u32 i; 1458c2ecf20Sopenharmony_ci int ret; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci for (i = 0; i < buff_size; i++) { 1488c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read(dp); 1498c2ecf20Sopenharmony_ci if (ret < 0) 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci buff[i] = ret; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, 1598c2ecf20Sopenharmony_ci u8 opcode, u16 size, u8 *message) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci u8 header[4]; 1628c2ecf20Sopenharmony_ci int ret, i; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci header[0] = opcode; 1658c2ecf20Sopenharmony_ci header[1] = module_id; 1668c2ecf20Sopenharmony_ci header[2] = (size >> 8) & 0xff; 1678c2ecf20Sopenharmony_ci header[3] = size & 0xff; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 1708c2ecf20Sopenharmony_ci ret = cdp_dp_mailbox_write(dp, header[i]); 1718c2ecf20Sopenharmony_ci if (ret) 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 1768c2ecf20Sopenharmony_ci ret = cdp_dp_mailbox_write(dp, message[i]); 1778c2ecf20Sopenharmony_ci if (ret) 1788c2ecf20Sopenharmony_ci return ret; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci u8 msg[6]; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci msg[0] = (addr >> 8) & 0xff; 1898c2ecf20Sopenharmony_ci msg[1] = addr & 0xff; 1908c2ecf20Sopenharmony_ci msg[2] = (val >> 24) & 0xff; 1918c2ecf20Sopenharmony_ci msg[3] = (val >> 16) & 0xff; 1928c2ecf20Sopenharmony_ci msg[4] = (val >> 8) & 0xff; 1938c2ecf20Sopenharmony_ci msg[5] = val & 0xff; 1948c2ecf20Sopenharmony_ci return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER, 1958c2ecf20Sopenharmony_ci sizeof(msg), msg); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, 1998c2ecf20Sopenharmony_ci u8 start_bit, u8 bits_no, u32 val) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci u8 field[8]; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci field[0] = (addr >> 8) & 0xff; 2048c2ecf20Sopenharmony_ci field[1] = addr & 0xff; 2058c2ecf20Sopenharmony_ci field[2] = start_bit; 2068c2ecf20Sopenharmony_ci field[3] = bits_no; 2078c2ecf20Sopenharmony_ci field[4] = (val >> 24) & 0xff; 2088c2ecf20Sopenharmony_ci field[5] = (val >> 16) & 0xff; 2098c2ecf20Sopenharmony_ci field[6] = (val >> 8) & 0xff; 2108c2ecf20Sopenharmony_ci field[7] = val & 0xff; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD, 2138c2ecf20Sopenharmony_ci sizeof(field), field); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ciint cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci u8 msg[5], reg[5]; 2198c2ecf20Sopenharmony_ci int ret; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci msg[0] = (len >> 8) & 0xff; 2228c2ecf20Sopenharmony_ci msg[1] = len & 0xff; 2238c2ecf20Sopenharmony_ci msg[2] = (addr >> 16) & 0xff; 2248c2ecf20Sopenharmony_ci msg[3] = (addr >> 8) & 0xff; 2258c2ecf20Sopenharmony_ci msg[4] = addr & 0xff; 2268c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD, 2278c2ecf20Sopenharmony_ci sizeof(msg), msg); 2288c2ecf20Sopenharmony_ci if (ret) 2298c2ecf20Sopenharmony_ci goto err_dpcd_read; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, 2328c2ecf20Sopenharmony_ci DPTX_READ_DPCD, 2338c2ecf20Sopenharmony_ci sizeof(reg) + len); 2348c2ecf20Sopenharmony_ci if (ret) 2358c2ecf20Sopenharmony_ci goto err_dpcd_read; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); 2388c2ecf20Sopenharmony_ci if (ret) 2398c2ecf20Sopenharmony_ci goto err_dpcd_read; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read_receive(dp, data, len); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cierr_dpcd_read: 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciint cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci u8 msg[6], reg[5]; 2508c2ecf20Sopenharmony_ci int ret; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci msg[0] = 0; 2538c2ecf20Sopenharmony_ci msg[1] = 1; 2548c2ecf20Sopenharmony_ci msg[2] = (addr >> 16) & 0xff; 2558c2ecf20Sopenharmony_ci msg[3] = (addr >> 8) & 0xff; 2568c2ecf20Sopenharmony_ci msg[4] = addr & 0xff; 2578c2ecf20Sopenharmony_ci msg[5] = value; 2588c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD, 2598c2ecf20Sopenharmony_ci sizeof(msg), msg); 2608c2ecf20Sopenharmony_ci if (ret) 2618c2ecf20Sopenharmony_ci goto err_dpcd_write; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, 2648c2ecf20Sopenharmony_ci DPTX_WRITE_DPCD, sizeof(reg)); 2658c2ecf20Sopenharmony_ci if (ret) 2668c2ecf20Sopenharmony_ci goto err_dpcd_write; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); 2698c2ecf20Sopenharmony_ci if (ret) 2708c2ecf20Sopenharmony_ci goto err_dpcd_write; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) 2738c2ecf20Sopenharmony_ci ret = -EINVAL; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cierr_dpcd_write: 2768c2ecf20Sopenharmony_ci if (ret) 2778c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret); 2788c2ecf20Sopenharmony_ci return ret; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ciint cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, 2828c2ecf20Sopenharmony_ci u32 i_size, const u32 *d_mem, u32 d_size) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci u32 reg; 2858c2ecf20Sopenharmony_ci int i, ret; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* reset ucpu before load firmware*/ 2888c2ecf20Sopenharmony_ci writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET, 2898c2ecf20Sopenharmony_ci dp->regs + APB_CTRL); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci for (i = 0; i < i_size; i += 4) 2928c2ecf20Sopenharmony_ci writel(*i_mem++, dp->regs + ADDR_IMEM + i); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci for (i = 0; i < d_size; i += 4) 2958c2ecf20Sopenharmony_ci writel(*d_mem++, dp->regs + ADDR_DMEM + i); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* un-reset ucpu */ 2988c2ecf20Sopenharmony_ci writel(0, dp->regs + APB_CTRL); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* check the keep alive register to make sure fw working */ 3018c2ecf20Sopenharmony_ci ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE, 3028c2ecf20Sopenharmony_ci reg, reg, 2000, FW_ALIVE_TIMEOUT_US); 3038c2ecf20Sopenharmony_ci if (ret < 0) { 3048c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "failed to loaded the FW reg = %x\n", 3058c2ecf20Sopenharmony_ci reg); 3068c2ecf20Sopenharmony_ci return -EINVAL; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci reg = readl(dp->regs + VER_L) & 0xff; 3108c2ecf20Sopenharmony_ci dp->fw_version = reg; 3118c2ecf20Sopenharmony_ci reg = readl(dp->regs + VER_H) & 0xff; 3128c2ecf20Sopenharmony_ci dp->fw_version |= reg << 8; 3138c2ecf20Sopenharmony_ci reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff; 3148c2ecf20Sopenharmony_ci dp->fw_version |= reg << 16; 3158c2ecf20Sopenharmony_ci reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff; 3168c2ecf20Sopenharmony_ci dp->fw_version |= reg << 24; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci DRM_DEV_DEBUG(dp->dev, "firmware version: %x\n", dp->fw_version); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ciint cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci u8 msg[5]; 3268c2ecf20Sopenharmony_ci int ret, i; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci msg[0] = GENERAL_MAIN_CONTROL; 3298c2ecf20Sopenharmony_ci msg[1] = MB_MODULE_ID_GENERAL; 3308c2ecf20Sopenharmony_ci msg[2] = 0; 3318c2ecf20Sopenharmony_ci msg[3] = 1; 3328c2ecf20Sopenharmony_ci msg[4] = enable ? FW_ACTIVE : FW_STANDBY; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(msg); i++) { 3358c2ecf20Sopenharmony_ci ret = cdp_dp_mailbox_write(dp, msg[i]); 3368c2ecf20Sopenharmony_ci if (ret) 3378c2ecf20Sopenharmony_ci goto err_set_firmware_active; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* read the firmware state */ 3418c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(msg); i++) { 3428c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read(dp); 3438c2ecf20Sopenharmony_ci if (ret < 0) 3448c2ecf20Sopenharmony_ci goto err_set_firmware_active; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci msg[i] = ret; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci ret = 0; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cierr_set_firmware_active: 3528c2ecf20Sopenharmony_ci if (ret < 0) 3538c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "set firmware active failed\n"); 3548c2ecf20Sopenharmony_ci return ret; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ciint cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci u8 msg[8]; 3608c2ecf20Sopenharmony_ci int ret; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci msg[0] = CDN_DP_MAX_LINK_RATE; 3638c2ecf20Sopenharmony_ci msg[1] = lanes | SCRAMBLER_EN; 3648c2ecf20Sopenharmony_ci msg[2] = VOLTAGE_LEVEL_2; 3658c2ecf20Sopenharmony_ci msg[3] = PRE_EMPHASIS_LEVEL_3; 3668c2ecf20Sopenharmony_ci msg[4] = PTS1 | PTS2 | PTS3 | PTS4; 3678c2ecf20Sopenharmony_ci msg[5] = FAST_LT_NOT_SUPPORT; 3688c2ecf20Sopenharmony_ci msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; 3698c2ecf20Sopenharmony_ci msg[7] = ENHANCED; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, 3728c2ecf20Sopenharmony_ci DPTX_SET_HOST_CAPABILITIES, 3738c2ecf20Sopenharmony_ci sizeof(msg), msg); 3748c2ecf20Sopenharmony_ci if (ret) 3758c2ecf20Sopenharmony_ci goto err_set_host_cap; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL, 3788c2ecf20Sopenharmony_ci AUX_HOST_INVERT); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cierr_set_host_cap: 3818c2ecf20Sopenharmony_ci if (ret) 3828c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "set host cap failed: %d\n", ret); 3838c2ecf20Sopenharmony_ci return ret; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ciint cdn_dp_event_config(struct cdn_dp_device *dp) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci u8 msg[5]; 3898c2ecf20Sopenharmony_ci int ret; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci memset(msg, 0, sizeof(msg)); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT, 3968c2ecf20Sopenharmony_ci sizeof(msg), msg); 3978c2ecf20Sopenharmony_ci if (ret) 3988c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "set event config failed: %d\n", ret); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return ret; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ciu32 cdn_dp_get_event(struct cdn_dp_device *dp) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci return readl(dp->regs + SW_EVENTS0); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ciint cdn_dp_get_hpd_status(struct cdn_dp_device *dp) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci u8 status; 4118c2ecf20Sopenharmony_ci int ret; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE, 4148c2ecf20Sopenharmony_ci 0, NULL); 4158c2ecf20Sopenharmony_ci if (ret) 4168c2ecf20Sopenharmony_ci goto err_get_hpd; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, 4198c2ecf20Sopenharmony_ci DPTX_HPD_STATE, sizeof(status)); 4208c2ecf20Sopenharmony_ci if (ret) 4218c2ecf20Sopenharmony_ci goto err_get_hpd; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status)); 4248c2ecf20Sopenharmony_ci if (ret) 4258c2ecf20Sopenharmony_ci goto err_get_hpd; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return status; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cierr_get_hpd: 4308c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "get hpd status failed: %d\n", ret); 4318c2ecf20Sopenharmony_ci return ret; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ciint cdn_dp_get_edid_block(void *data, u8 *edid, 4358c2ecf20Sopenharmony_ci unsigned int block, size_t length) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct cdn_dp_device *dp = data; 4388c2ecf20Sopenharmony_ci u8 msg[2], reg[2], i; 4398c2ecf20Sopenharmony_ci int ret; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 4428c2ecf20Sopenharmony_ci msg[0] = block / 2; 4438c2ecf20Sopenharmony_ci msg[1] = block % 2; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID, 4468c2ecf20Sopenharmony_ci sizeof(msg), msg); 4478c2ecf20Sopenharmony_ci if (ret) 4488c2ecf20Sopenharmony_ci continue; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, 4518c2ecf20Sopenharmony_ci DPTX_GET_EDID, 4528c2ecf20Sopenharmony_ci sizeof(reg) + length); 4538c2ecf20Sopenharmony_ci if (ret) 4548c2ecf20Sopenharmony_ci continue; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); 4578c2ecf20Sopenharmony_ci if (ret) 4588c2ecf20Sopenharmony_ci continue; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read_receive(dp, edid, length); 4618c2ecf20Sopenharmony_ci if (ret) 4628c2ecf20Sopenharmony_ci continue; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (reg[0] == length && reg[1] == block / 2) 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (ret) 4698c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "get block[%d] edid failed: %d\n", block, 4708c2ecf20Sopenharmony_ci ret); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int cdn_dp_training_start(struct cdn_dp_device *dp) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci unsigned long timeout; 4788c2ecf20Sopenharmony_ci u8 msg, event[2]; 4798c2ecf20Sopenharmony_ci int ret; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci msg = LINK_TRAINING_RUN; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* start training */ 4848c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL, 4858c2ecf20Sopenharmony_ci sizeof(msg), &msg); 4868c2ecf20Sopenharmony_ci if (ret) 4878c2ecf20Sopenharmony_ci goto err_training_start; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); 4908c2ecf20Sopenharmony_ci while (time_before(jiffies, timeout)) { 4918c2ecf20Sopenharmony_ci msleep(LINK_TRAINING_RETRY_MS); 4928c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, 4938c2ecf20Sopenharmony_ci DPTX_READ_EVENT, 0, NULL); 4948c2ecf20Sopenharmony_ci if (ret) 4958c2ecf20Sopenharmony_ci goto err_training_start; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, 4988c2ecf20Sopenharmony_ci DPTX_READ_EVENT, 4998c2ecf20Sopenharmony_ci sizeof(event)); 5008c2ecf20Sopenharmony_ci if (ret) 5018c2ecf20Sopenharmony_ci goto err_training_start; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read_receive(dp, event, sizeof(event)); 5048c2ecf20Sopenharmony_ci if (ret) 5058c2ecf20Sopenharmony_ci goto err_training_start; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (event[1] & EQ_PHASE_FINISHED) 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cierr_training_start: 5148c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "training failed: %d\n", ret); 5158c2ecf20Sopenharmony_ci return ret; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int cdn_dp_get_training_status(struct cdn_dp_device *dp) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci u8 status[10]; 5218c2ecf20Sopenharmony_ci int ret; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT, 5248c2ecf20Sopenharmony_ci 0, NULL); 5258c2ecf20Sopenharmony_ci if (ret) 5268c2ecf20Sopenharmony_ci goto err_get_training_status; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, 5298c2ecf20Sopenharmony_ci DPTX_READ_LINK_STAT, 5308c2ecf20Sopenharmony_ci sizeof(status)); 5318c2ecf20Sopenharmony_ci if (ret) 5328c2ecf20Sopenharmony_ci goto err_get_training_status; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_read_receive(dp, status, sizeof(status)); 5358c2ecf20Sopenharmony_ci if (ret) 5368c2ecf20Sopenharmony_ci goto err_get_training_status; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci dp->max_rate = drm_dp_bw_code_to_link_rate(status[0]); 5398c2ecf20Sopenharmony_ci dp->max_lanes = status[1]; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cierr_get_training_status: 5428c2ecf20Sopenharmony_ci if (ret) 5438c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "get training status failed: %d\n", ret); 5448c2ecf20Sopenharmony_ci return ret; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ciint cdn_dp_train_link(struct cdn_dp_device *dp) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci int ret; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci ret = cdn_dp_training_start(dp); 5528c2ecf20Sopenharmony_ci if (ret) { 5538c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); 5548c2ecf20Sopenharmony_ci return ret; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci ret = cdn_dp_get_training_status(dp); 5588c2ecf20Sopenharmony_ci if (ret) { 5598c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "Failed to get training stat %d\n", ret); 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->max_rate, 5648c2ecf20Sopenharmony_ci dp->max_lanes); 5658c2ecf20Sopenharmony_ci return ret; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ciint cdn_dp_set_video_status(struct cdn_dp_device *dp, int active) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci u8 msg; 5718c2ecf20Sopenharmony_ci int ret; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci msg = !!active; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO, 5768c2ecf20Sopenharmony_ci sizeof(msg), &msg); 5778c2ecf20Sopenharmony_ci if (ret) 5788c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "set video status failed: %d\n", ret); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int cdn_dp_get_msa_misc(struct video_info *video, 5848c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci u32 msa_misc; 5878c2ecf20Sopenharmony_ci u8 val[2] = {0}; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci switch (video->color_fmt) { 5908c2ecf20Sopenharmony_ci case PXL_RGB: 5918c2ecf20Sopenharmony_ci case Y_ONLY: 5928c2ecf20Sopenharmony_ci val[0] = 0; 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci /* set YUV default color space conversion to BT601 */ 5958c2ecf20Sopenharmony_ci case YCBCR_4_4_4: 5968c2ecf20Sopenharmony_ci val[0] = 6 + BT_601 * 8; 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci case YCBCR_4_2_2: 5998c2ecf20Sopenharmony_ci val[0] = 5 + BT_601 * 8; 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci case YCBCR_4_2_0: 6028c2ecf20Sopenharmony_ci val[0] = 5; 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci switch (video->color_depth) { 6078c2ecf20Sopenharmony_ci case 6: 6088c2ecf20Sopenharmony_ci val[1] = 0; 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case 8: 6118c2ecf20Sopenharmony_ci val[1] = 1; 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci case 10: 6148c2ecf20Sopenharmony_ci val[1] = 2; 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci case 12: 6178c2ecf20Sopenharmony_ci val[1] = 3; 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci case 16: 6208c2ecf20Sopenharmony_ci val[1] = 4; 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci msa_misc = 2 * val[0] + 32 * val[1] + 6258c2ecf20Sopenharmony_ci ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return msa_misc; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ciint cdn_dp_config_video(struct cdn_dp_device *dp) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct video_info *video = &dp->video_info; 6338c2ecf20Sopenharmony_ci struct drm_display_mode *mode = &dp->mode; 6348c2ecf20Sopenharmony_ci u64 symbol; 6358c2ecf20Sopenharmony_ci u32 val, link_rate, rem; 6368c2ecf20Sopenharmony_ci u8 bit_per_pix, tu_size_reg = TU_SIZE; 6378c2ecf20Sopenharmony_ci int ret; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? 6408c2ecf20Sopenharmony_ci (video->color_depth * 2) : (video->color_depth * 3); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci link_rate = dp->max_rate / 1000; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); 6458c2ecf20Sopenharmony_ci if (ret) 6468c2ecf20Sopenharmony_ci goto err_config_video; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0); 6498c2ecf20Sopenharmony_ci if (ret) 6508c2ecf20Sopenharmony_ci goto err_config_video; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* 6538c2ecf20Sopenharmony_ci * get a best tu_size and valid symbol: 6548c2ecf20Sopenharmony_ci * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 6558c2ecf20Sopenharmony_ci * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) 6568c2ecf20Sopenharmony_ci * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set 6578c2ecf20Sopenharmony_ci * TU += 2 and repeat 2nd step. 6588c2ecf20Sopenharmony_ci */ 6598c2ecf20Sopenharmony_ci do { 6608c2ecf20Sopenharmony_ci tu_size_reg += 2; 6618c2ecf20Sopenharmony_ci symbol = (u64)tu_size_reg * mode->clock * bit_per_pix; 6628c2ecf20Sopenharmony_ci do_div(symbol, dp->max_lanes * link_rate * 8); 6638c2ecf20Sopenharmony_ci rem = do_div(symbol, 1000); 6648c2ecf20Sopenharmony_ci if (tu_size_reg > 64) { 6658c2ecf20Sopenharmony_ci ret = -EINVAL; 6668c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, 6678c2ecf20Sopenharmony_ci "tu error, clk:%d, lanes:%d, rate:%d\n", 6688c2ecf20Sopenharmony_ci mode->clock, dp->max_lanes, link_rate); 6698c2ecf20Sopenharmony_ci goto err_config_video; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || 6728c2ecf20Sopenharmony_ci (rem > 850) || (rem < 100)); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci val = symbol + (tu_size_reg << 8); 6758c2ecf20Sopenharmony_ci val |= TU_CNT_RST_EN; 6768c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_FRAMER_TU, val); 6778c2ecf20Sopenharmony_ci if (ret) 6788c2ecf20Sopenharmony_ci goto err_config_video; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* set the FIFO Buffer size */ 6818c2ecf20Sopenharmony_ci val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; 6828c2ecf20Sopenharmony_ci val /= (dp->max_lanes * link_rate); 6838c2ecf20Sopenharmony_ci val = div_u64(8 * (symbol + 1), bit_per_pix) - val; 6848c2ecf20Sopenharmony_ci val += 2; 6858c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci switch (video->color_depth) { 6888c2ecf20Sopenharmony_ci case 6: 6898c2ecf20Sopenharmony_ci val = BCS_6; 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci case 8: 6928c2ecf20Sopenharmony_ci val = BCS_8; 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci case 10: 6958c2ecf20Sopenharmony_ci val = BCS_10; 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci case 12: 6988c2ecf20Sopenharmony_ci val = BCS_12; 6998c2ecf20Sopenharmony_ci break; 7008c2ecf20Sopenharmony_ci case 16: 7018c2ecf20Sopenharmony_ci val = BCS_16; 7028c2ecf20Sopenharmony_ci break; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci val += video->color_fmt << 8; 7068c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val); 7078c2ecf20Sopenharmony_ci if (ret) 7088c2ecf20Sopenharmony_ci goto err_config_video; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0; 7118c2ecf20Sopenharmony_ci val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0; 7128c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_FRAMER_SP, val); 7138c2ecf20Sopenharmony_ci if (ret) 7148c2ecf20Sopenharmony_ci goto err_config_video; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci val = (mode->hsync_start - mode->hdisplay) << 16; 7178c2ecf20Sopenharmony_ci val |= mode->htotal - mode->hsync_end; 7188c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val); 7198c2ecf20Sopenharmony_ci if (ret) 7208c2ecf20Sopenharmony_ci goto err_config_video; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci val = mode->hdisplay * bit_per_pix / 8; 7238c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_BYTE_COUNT, val); 7248c2ecf20Sopenharmony_ci if (ret) 7258c2ecf20Sopenharmony_ci goto err_config_video; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); 7288c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val); 7298c2ecf20Sopenharmony_ci if (ret) 7308c2ecf20Sopenharmony_ci goto err_config_video; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci val = mode->hsync_end - mode->hsync_start; 7338c2ecf20Sopenharmony_ci val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15); 7348c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val); 7358c2ecf20Sopenharmony_ci if (ret) 7368c2ecf20Sopenharmony_ci goto err_config_video; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci val = mode->vtotal; 7398c2ecf20Sopenharmony_ci val |= (mode->vtotal - mode->vsync_start) << 16; 7408c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, MSA_VERTICAL_0, val); 7418c2ecf20Sopenharmony_ci if (ret) 7428c2ecf20Sopenharmony_ci goto err_config_video; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci val = mode->vsync_end - mode->vsync_start; 7458c2ecf20Sopenharmony_ci val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15); 7468c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, MSA_VERTICAL_1, val); 7478c2ecf20Sopenharmony_ci if (ret) 7488c2ecf20Sopenharmony_ci goto err_config_video; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci val = cdn_dp_get_msa_misc(video, mode); 7518c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, MSA_MISC, val); 7528c2ecf20Sopenharmony_ci if (ret) 7538c2ecf20Sopenharmony_ci goto err_config_video; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, STREAM_CONFIG, 1); 7568c2ecf20Sopenharmony_ci if (ret) 7578c2ecf20Sopenharmony_ci goto err_config_video; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci val = mode->hsync_end - mode->hsync_start; 7608c2ecf20Sopenharmony_ci val |= mode->hdisplay << 16; 7618c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_HORIZONTAL, val); 7628c2ecf20Sopenharmony_ci if (ret) 7638c2ecf20Sopenharmony_ci goto err_config_video; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci val = mode->vdisplay; 7668c2ecf20Sopenharmony_ci val |= (mode->vtotal - mode->vsync_start) << 16; 7678c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_VERTICAL_0, val); 7688c2ecf20Sopenharmony_ci if (ret) 7698c2ecf20Sopenharmony_ci goto err_config_video; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci val = mode->vtotal; 7728c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, DP_VERTICAL_1, val); 7738c2ecf20Sopenharmony_ci if (ret) 7748c2ecf20Sopenharmony_ci goto err_config_video; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, 0); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cierr_config_video: 7798c2ecf20Sopenharmony_ci if (ret) 7808c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "config video failed: %d\n", ret); 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ciint cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci int ret; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0); 7898c2ecf20Sopenharmony_ci if (ret) { 7908c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "audio stop failed: %d\n", ret); 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci writel(0, dp->regs + SPDIF_CTRL_ADDR); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* clearn the audio config and reset */ 7978c2ecf20Sopenharmony_ci writel(0, dp->regs + AUDIO_SRC_CNTL); 7988c2ecf20Sopenharmony_ci writel(0, dp->regs + AUDIO_SRC_CNFG); 7998c2ecf20Sopenharmony_ci writel(AUDIO_SW_RST, dp->regs + AUDIO_SRC_CNTL); 8008c2ecf20Sopenharmony_ci writel(0, dp->regs + AUDIO_SRC_CNTL); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* reset smpl2pckt component */ 8038c2ecf20Sopenharmony_ci writel(0, dp->regs + SMPL2PKT_CNTL); 8048c2ecf20Sopenharmony_ci writel(AUDIO_SW_RST, dp->regs + SMPL2PKT_CNTL); 8058c2ecf20Sopenharmony_ci writel(0, dp->regs + SMPL2PKT_CNTL); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* reset FIFO */ 8088c2ecf20Sopenharmony_ci writel(AUDIO_SW_RST, dp->regs + FIFO_CNTL); 8098c2ecf20Sopenharmony_ci writel(0, dp->regs + FIFO_CNTL); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (audio->format == AFMT_SPDIF) 8128c2ecf20Sopenharmony_ci clk_disable_unprepare(dp->spdif_clk); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return 0; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ciint cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci int ret; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, enable); 8228c2ecf20Sopenharmony_ci if (ret) 8238c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "audio mute failed: %d\n", ret); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return ret; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp, 8298c2ecf20Sopenharmony_ci struct audio_info *audio) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; 8328c2ecf20Sopenharmony_ci u32 val; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (audio->channels == 2) { 8358c2ecf20Sopenharmony_ci if (dp->max_lanes == 1) 8368c2ecf20Sopenharmony_ci sub_pckt_num = 2; 8378c2ecf20Sopenharmony_ci else 8388c2ecf20Sopenharmony_ci sub_pckt_num = 4; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci i2s_port_en_val = 1; 8418c2ecf20Sopenharmony_ci } else if (audio->channels == 4) { 8428c2ecf20Sopenharmony_ci i2s_port_en_val = 3; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci writel(0x0, dp->regs + SPDIF_CTRL_ADDR); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci val = MAX_NUM_CH(audio->channels); 8508c2ecf20Sopenharmony_ci val |= NUM_OF_I2S_PORTS(audio->channels); 8518c2ecf20Sopenharmony_ci val |= AUDIO_TYPE_LPCM; 8528c2ecf20Sopenharmony_ci val |= CFG_SUB_PCKT_NUM(sub_pckt_num); 8538c2ecf20Sopenharmony_ci writel(val, dp->regs + SMPL2PKT_CNFG); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (audio->sample_width == 16) 8568c2ecf20Sopenharmony_ci val = 0; 8578c2ecf20Sopenharmony_ci else if (audio->sample_width == 24) 8588c2ecf20Sopenharmony_ci val = 1 << 9; 8598c2ecf20Sopenharmony_ci else 8608c2ecf20Sopenharmony_ci val = 2 << 9; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci val |= AUDIO_CH_NUM(audio->channels); 8638c2ecf20Sopenharmony_ci val |= I2S_DEC_PORT_EN(i2s_port_en_val); 8648c2ecf20Sopenharmony_ci val |= TRANS_SMPL_WIDTH_32; 8658c2ecf20Sopenharmony_ci writel(val, dp->regs + AUDIO_SRC_CNFG); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci for (i = 0; i < (audio->channels + 1) / 2; i++) { 8688c2ecf20Sopenharmony_ci if (audio->sample_width == 16) 8698c2ecf20Sopenharmony_ci val = (0x02 << 8) | (0x02 << 20); 8708c2ecf20Sopenharmony_ci else if (audio->sample_width == 24) 8718c2ecf20Sopenharmony_ci val = (0x0b << 8) | (0x0b << 20); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci val |= ((2 * i) << 4) | ((2 * i + 1) << 16); 8748c2ecf20Sopenharmony_ci writel(val, dp->regs + STTS_BIT_CH(i)); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci switch (audio->sample_rate) { 8788c2ecf20Sopenharmony_ci case 32000: 8798c2ecf20Sopenharmony_ci val = SAMPLING_FREQ(3) | 8808c2ecf20Sopenharmony_ci ORIGINAL_SAMP_FREQ(0xc); 8818c2ecf20Sopenharmony_ci break; 8828c2ecf20Sopenharmony_ci case 44100: 8838c2ecf20Sopenharmony_ci val = SAMPLING_FREQ(0) | 8848c2ecf20Sopenharmony_ci ORIGINAL_SAMP_FREQ(0xf); 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci case 48000: 8878c2ecf20Sopenharmony_ci val = SAMPLING_FREQ(2) | 8888c2ecf20Sopenharmony_ci ORIGINAL_SAMP_FREQ(0xd); 8898c2ecf20Sopenharmony_ci break; 8908c2ecf20Sopenharmony_ci case 88200: 8918c2ecf20Sopenharmony_ci val = SAMPLING_FREQ(8) | 8928c2ecf20Sopenharmony_ci ORIGINAL_SAMP_FREQ(0x7); 8938c2ecf20Sopenharmony_ci break; 8948c2ecf20Sopenharmony_ci case 96000: 8958c2ecf20Sopenharmony_ci val = SAMPLING_FREQ(0xa) | 8968c2ecf20Sopenharmony_ci ORIGINAL_SAMP_FREQ(5); 8978c2ecf20Sopenharmony_ci break; 8988c2ecf20Sopenharmony_ci case 176400: 8998c2ecf20Sopenharmony_ci val = SAMPLING_FREQ(0xc) | 9008c2ecf20Sopenharmony_ci ORIGINAL_SAMP_FREQ(3); 9018c2ecf20Sopenharmony_ci break; 9028c2ecf20Sopenharmony_ci case 192000: 9038c2ecf20Sopenharmony_ci val = SAMPLING_FREQ(0xe) | 9048c2ecf20Sopenharmony_ci ORIGINAL_SAMP_FREQ(1); 9058c2ecf20Sopenharmony_ci break; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci val |= 4; 9088c2ecf20Sopenharmony_ci writel(val, dp->regs + COM_CH_STTS_BITS); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); 9118c2ecf20Sopenharmony_ci writel(I2S_DEC_START, dp->regs + AUDIO_SRC_CNTL); 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci u32 val; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); 9218c2ecf20Sopenharmony_ci writel(val, dp->regs + SMPL2PKT_CNFG); 9228c2ecf20Sopenharmony_ci writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; 9258c2ecf20Sopenharmony_ci writel(val, dp->regs + SPDIF_CTRL_ADDR); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci clk_prepare_enable(dp->spdif_clk); 9288c2ecf20Sopenharmony_ci clk_set_rate(dp->spdif_clk, CDN_DP_SPDIF_CLK); 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ciint cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci int ret; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* reset the spdif clk before config */ 9368c2ecf20Sopenharmony_ci if (audio->format == AFMT_SPDIF) { 9378c2ecf20Sopenharmony_ci reset_control_assert(dp->spdif_rst); 9388c2ecf20Sopenharmony_ci reset_control_deassert(dp->spdif_rst); 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, CM_LANE_CTRL, LANE_REF_CYC); 9428c2ecf20Sopenharmony_ci if (ret) 9438c2ecf20Sopenharmony_ci goto err_audio_config; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, CM_CTRL, 0); 9468c2ecf20Sopenharmony_ci if (ret) 9478c2ecf20Sopenharmony_ci goto err_audio_config; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (audio->format == AFMT_I2S) 9508c2ecf20Sopenharmony_ci cdn_dp_audio_config_i2s(dp, audio); 9518c2ecf20Sopenharmony_ci else if (audio->format == AFMT_SPDIF) 9528c2ecf20Sopenharmony_ci cdn_dp_audio_config_spdif(dp); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cierr_audio_config: 9578c2ecf20Sopenharmony_ci if (ret) 9588c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dp->dev, "audio config failed: %d\n", ret); 9598c2ecf20Sopenharmony_ci return ret; 9608c2ecf20Sopenharmony_ci} 961