| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd |
|---|
| 3 | 4 | * Author: Chris Zhong <zyw@rock-chips.com> |
|---|
| 4 | | - * |
|---|
| 5 | | - * This software is licensed under the terms of the GNU General Public |
|---|
| 6 | | - * License version 2, as published by the Free Software Foundation, and |
|---|
| 7 | | - * may be copied, distributed, and modified under those terms. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 10 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 | | - * GNU General Public License for more details. |
|---|
| 13 | 5 | */ |
|---|
| 14 | 6 | |
|---|
| 15 | 7 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 189 | 181 | return 0; |
|---|
| 190 | 182 | } |
|---|
| 191 | 183 | |
|---|
| 192 | | -int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) |
|---|
| 184 | +static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) |
|---|
| 193 | 185 | { |
|---|
| 194 | 186 | u8 msg[6]; |
|---|
| 195 | 187 | |
|---|
| .. | .. |
|---|
| 221 | 213 | sizeof(field), field); |
|---|
| 222 | 214 | } |
|---|
| 223 | 215 | |
|---|
| 224 | | -/* |
|---|
| 225 | | - * Returns the number of bytes transferred on success, or a negative |
|---|
| 226 | | - * error code on failure. -ETIMEDOUT is returned if mailbox message was |
|---|
| 227 | | - * not send successfully; |
|---|
| 228 | | - */ |
|---|
| 229 | | -ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) |
|---|
| 216 | +int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) |
|---|
| 230 | 217 | { |
|---|
| 231 | 218 | u8 msg[5], reg[5]; |
|---|
| 232 | 219 | int ret; |
|---|
| .. | .. |
|---|
| 252 | 239 | goto err_dpcd_read; |
|---|
| 253 | 240 | |
|---|
| 254 | 241 | ret = cdn_dp_mailbox_read_receive(dp, data, len); |
|---|
| 255 | | - if (!ret) |
|---|
| 256 | | - return len; |
|---|
| 257 | 242 | |
|---|
| 258 | 243 | err_dpcd_read: |
|---|
| 259 | | - DRM_DEV_ERROR(dp->dev, "dpcd read failed: %d\n", ret); |
|---|
| 260 | 244 | return ret; |
|---|
| 261 | 245 | } |
|---|
| 262 | 246 | |
|---|
| 263 | | -#define CDN_AUX_HEADER_SIZE 5 |
|---|
| 264 | | -#define CDN_AUX_MSG_SIZE 20 |
|---|
| 265 | | -/* |
|---|
| 266 | | - * Returns the number of bytes transferred on success, or a negative error |
|---|
| 267 | | - * code on failure. -ETIMEDOUT is returned if mailbox message was not send |
|---|
| 268 | | - * success; -EINVAL is returned if get the wrong data size after message |
|---|
| 269 | | - * is sent |
|---|
| 270 | | - */ |
|---|
| 271 | | -ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) |
|---|
| 247 | +int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) |
|---|
| 272 | 248 | { |
|---|
| 273 | | - u8 msg[CDN_AUX_MSG_SIZE + CDN_AUX_HEADER_SIZE]; |
|---|
| 274 | | - u8 reg[CDN_AUX_HEADER_SIZE]; |
|---|
| 249 | + u8 msg[6], reg[5]; |
|---|
| 275 | 250 | int ret; |
|---|
| 276 | 251 | |
|---|
| 277 | | - if (WARN_ON(len > CDN_AUX_MSG_SIZE) || WARN_ON(len <= 0)) |
|---|
| 278 | | - return -EINVAL; |
|---|
| 279 | | - |
|---|
| 280 | | - msg[0] = (len >> 8) & 0xff; |
|---|
| 281 | | - msg[1] = len & 0xff; |
|---|
| 252 | + msg[0] = 0; |
|---|
| 253 | + msg[1] = 1; |
|---|
| 282 | 254 | msg[2] = (addr >> 16) & 0xff; |
|---|
| 283 | 255 | msg[3] = (addr >> 8) & 0xff; |
|---|
| 284 | 256 | msg[4] = addr & 0xff; |
|---|
| 285 | | - |
|---|
| 286 | | - memcpy(msg + CDN_AUX_HEADER_SIZE, data, len); |
|---|
| 287 | | - |
|---|
| 257 | + msg[5] = value; |
|---|
| 288 | 258 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD, |
|---|
| 289 | | - CDN_AUX_HEADER_SIZE + len, msg); |
|---|
| 259 | + sizeof(msg), msg); |
|---|
| 290 | 260 | if (ret) |
|---|
| 291 | 261 | goto err_dpcd_write; |
|---|
| 292 | 262 | |
|---|
| .. | .. |
|---|
| 299 | 269 | if (ret) |
|---|
| 300 | 270 | goto err_dpcd_write; |
|---|
| 301 | 271 | |
|---|
| 302 | | - if ((len != (reg[0] << 8 | reg[1])) || |
|---|
| 303 | | - (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))) { |
|---|
| 272 | + if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) |
|---|
| 304 | 273 | ret = -EINVAL; |
|---|
| 305 | | - } else { |
|---|
| 306 | | - return len; |
|---|
| 307 | | - } |
|---|
| 308 | 274 | |
|---|
| 309 | 275 | err_dpcd_write: |
|---|
| 310 | 276 | if (ret) |
|---|
| 311 | 277 | DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret); |
|---|
| 312 | | - return ret; |
|---|
| 313 | | -} |
|---|
| 314 | | - |
|---|
| 315 | | -int cdn_dp_get_aux_status(struct cdn_dp_device *dp) |
|---|
| 316 | | -{ |
|---|
| 317 | | - u8 status; |
|---|
| 318 | | - int ret; |
|---|
| 319 | | - |
|---|
| 320 | | - ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, |
|---|
| 321 | | - DPTX_GET_LAST_AUX_STAUS, 0, NULL); |
|---|
| 322 | | - if (ret) |
|---|
| 323 | | - goto err_get_hpd; |
|---|
| 324 | | - |
|---|
| 325 | | - ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, |
|---|
| 326 | | - DPTX_GET_LAST_AUX_STAUS, |
|---|
| 327 | | - sizeof(status)); |
|---|
| 328 | | - if (ret) |
|---|
| 329 | | - goto err_get_hpd; |
|---|
| 330 | | - |
|---|
| 331 | | - ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status)); |
|---|
| 332 | | - if (ret) |
|---|
| 333 | | - goto err_get_hpd; |
|---|
| 334 | | - |
|---|
| 335 | | - return status; |
|---|
| 336 | | - |
|---|
| 337 | | -err_get_hpd: |
|---|
| 338 | | - DRM_DEV_ERROR(dp->dev, "get aux status failed: %d\n", ret); |
|---|
| 339 | 278 | return ret; |
|---|
| 340 | 279 | } |
|---|
| 341 | 280 | |
|---|
| .. | .. |
|---|
| 596 | 535 | if (ret) |
|---|
| 597 | 536 | goto err_get_training_status; |
|---|
| 598 | 537 | |
|---|
| 599 | | - dp->link.rate = status[0]; |
|---|
| 600 | | - dp->link.num_lanes = status[1]; |
|---|
| 538 | + dp->max_rate = drm_dp_bw_code_to_link_rate(status[0]); |
|---|
| 539 | + dp->max_lanes = status[1]; |
|---|
| 601 | 540 | |
|---|
| 602 | 541 | err_get_training_status: |
|---|
| 603 | 542 | if (ret) |
|---|
| .. | .. |
|---|
| 609 | 548 | { |
|---|
| 610 | 549 | int ret; |
|---|
| 611 | 550 | |
|---|
| 612 | | - /* |
|---|
| 613 | | - * DP firmware uses fixed phy config values to do training, but some |
|---|
| 614 | | - * boards need to adjust these values to fit for their unique hardware |
|---|
| 615 | | - * design. So if the phy is using custom config values, do software |
|---|
| 616 | | - * link training instead of relying on firmware, if software training |
|---|
| 617 | | - * fail, keep firmware training as a fallback if sw training fails. |
|---|
| 618 | | - */ |
|---|
| 619 | | - ret = cdn_dp_software_train_link(dp); |
|---|
| 620 | | - if (ret) { |
|---|
| 621 | | - DRM_DEV_ERROR(dp->dev, |
|---|
| 622 | | - "Failed to do software training %d\n", ret); |
|---|
| 623 | | - goto do_fw_training; |
|---|
| 624 | | - } |
|---|
| 625 | | - ret = cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf); |
|---|
| 626 | | - if (ret) { |
|---|
| 627 | | - DRM_DEV_ERROR(dp->dev, |
|---|
| 628 | | - "Failed to write SOURCE_HDTX_CAR register %d\n", ret); |
|---|
| 629 | | - goto do_fw_training; |
|---|
| 630 | | - } |
|---|
| 631 | | - dp->use_fw_training = false; |
|---|
| 632 | | - return 0; |
|---|
| 633 | | - |
|---|
| 634 | | -do_fw_training: |
|---|
| 635 | | - dp->use_fw_training = true; |
|---|
| 636 | | - DRM_DEV_DEBUG_KMS(dp->dev, "use fw training\n"); |
|---|
| 637 | 551 | ret = cdn_dp_training_start(dp); |
|---|
| 638 | 552 | if (ret) { |
|---|
| 639 | 553 | DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); |
|---|
| .. | .. |
|---|
| 646 | 560 | return ret; |
|---|
| 647 | 561 | } |
|---|
| 648 | 562 | |
|---|
| 649 | | - DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate, |
|---|
| 650 | | - dp->link.num_lanes); |
|---|
| 651 | | - return 0; |
|---|
| 563 | + DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->max_rate, |
|---|
| 564 | + dp->max_lanes); |
|---|
| 565 | + return ret; |
|---|
| 652 | 566 | } |
|---|
| 653 | 567 | |
|---|
| 654 | 568 | int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active) |
|---|
| .. | .. |
|---|
| 687 | 601 | case YCBCR_4_2_0: |
|---|
| 688 | 602 | val[0] = 5; |
|---|
| 689 | 603 | break; |
|---|
| 690 | | - }; |
|---|
| 604 | + } |
|---|
| 691 | 605 | |
|---|
| 692 | 606 | switch (video->color_depth) { |
|---|
| 693 | 607 | case 6: |
|---|
| .. | .. |
|---|
| 705 | 619 | case 16: |
|---|
| 706 | 620 | val[1] = 4; |
|---|
| 707 | 621 | break; |
|---|
| 708 | | - }; |
|---|
| 622 | + } |
|---|
| 709 | 623 | |
|---|
| 710 | 624 | msa_misc = 2 * val[0] + 32 * val[1] + |
|---|
| 711 | 625 | ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); |
|---|
| .. | .. |
|---|
| 725 | 639 | bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? |
|---|
| 726 | 640 | (video->color_depth * 2) : (video->color_depth * 3); |
|---|
| 727 | 641 | |
|---|
| 728 | | - link_rate = drm_dp_bw_code_to_link_rate(dp->link.rate) / 1000; |
|---|
| 642 | + link_rate = dp->max_rate / 1000; |
|---|
| 729 | 643 | |
|---|
| 730 | 644 | ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); |
|---|
| 731 | 645 | if (ret) |
|---|
| .. | .. |
|---|
| 744 | 658 | */ |
|---|
| 745 | 659 | do { |
|---|
| 746 | 660 | tu_size_reg += 2; |
|---|
| 747 | | - symbol = tu_size_reg * mode->clock * bit_per_pix; |
|---|
| 748 | | - do_div(symbol, dp->link.num_lanes * link_rate * 8); |
|---|
| 661 | + symbol = (u64)tu_size_reg * mode->clock * bit_per_pix; |
|---|
| 662 | + do_div(symbol, dp->max_lanes * link_rate * 8); |
|---|
| 749 | 663 | rem = do_div(symbol, 1000); |
|---|
| 750 | 664 | if (tu_size_reg > 64) { |
|---|
| 751 | 665 | ret = -EINVAL; |
|---|
| 752 | 666 | DRM_DEV_ERROR(dp->dev, |
|---|
| 753 | 667 | "tu error, clk:%d, lanes:%d, rate:%d\n", |
|---|
| 754 | | - mode->clock, dp->link.num_lanes, |
|---|
| 755 | | - link_rate); |
|---|
| 668 | + mode->clock, dp->max_lanes, link_rate); |
|---|
| 756 | 669 | goto err_config_video; |
|---|
| 757 | 670 | } |
|---|
| 758 | 671 | } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || |
|---|
| .. | .. |
|---|
| 766 | 679 | |
|---|
| 767 | 680 | /* set the FIFO Buffer size */ |
|---|
| 768 | 681 | val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; |
|---|
| 769 | | - val /= (dp->link.num_lanes * link_rate); |
|---|
| 682 | + val /= (dp->max_lanes * link_rate); |
|---|
| 770 | 683 | val = div_u64(8 * (symbol + 1), bit_per_pix) - val; |
|---|
| 771 | 684 | val += 2; |
|---|
| 772 | 685 | ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); |
|---|
| .. | .. |
|---|
| 787 | 700 | case 16: |
|---|
| 788 | 701 | val = BCS_16; |
|---|
| 789 | 702 | break; |
|---|
| 790 | | - }; |
|---|
| 703 | + } |
|---|
| 791 | 704 | |
|---|
| 792 | 705 | val += video->color_fmt << 8; |
|---|
| 793 | 706 | ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val); |
|---|
| .. | .. |
|---|
| 919 | 832 | u32 val; |
|---|
| 920 | 833 | |
|---|
| 921 | 834 | if (audio->channels == 2) { |
|---|
| 922 | | - if (dp->link.num_lanes == 1) |
|---|
| 835 | + if (dp->max_lanes == 1) |
|---|
| 923 | 836 | sub_pckt_num = 2; |
|---|
| 924 | 837 | else |
|---|
| 925 | 838 | sub_pckt_num = 4; |
|---|
| .. | .. |
|---|
| 998 | 911 | writel(I2S_DEC_START, dp->regs + AUDIO_SRC_CNTL); |
|---|
| 999 | 912 | } |
|---|
| 1000 | 913 | |
|---|
| 1001 | | -static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp, |
|---|
| 1002 | | - struct audio_info *audio) |
|---|
| 914 | +static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) |
|---|
| 1003 | 915 | { |
|---|
| 1004 | 916 | u32 val; |
|---|
| 1005 | | - int sub_pckt_num = 1; |
|---|
| 1006 | 917 | |
|---|
| 1007 | | - if (audio->channels == 2) { |
|---|
| 1008 | | - if (dp->link.num_lanes == 1) |
|---|
| 1009 | | - sub_pckt_num = 2; |
|---|
| 1010 | | - else |
|---|
| 1011 | | - sub_pckt_num = 4; |
|---|
| 1012 | | - } |
|---|
| 1013 | 918 | writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); |
|---|
| 1014 | 919 | |
|---|
| 1015 | | - val = MAX_NUM_CH(audio->channels); |
|---|
| 1016 | | - val |= AUDIO_TYPE_LPCM; |
|---|
| 1017 | | - val |= CFG_SUB_PCKT_NUM(sub_pckt_num); |
|---|
| 920 | + val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); |
|---|
| 1018 | 921 | writel(val, dp->regs + SMPL2PKT_CNFG); |
|---|
| 1019 | 922 | writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); |
|---|
| 1020 | 923 | |
|---|
| .. | .. |
|---|
| 1023 | 926 | |
|---|
| 1024 | 927 | clk_prepare_enable(dp->spdif_clk); |
|---|
| 1025 | 928 | clk_set_rate(dp->spdif_clk, CDN_DP_SPDIF_CLK); |
|---|
| 1026 | | -} |
|---|
| 1027 | | - |
|---|
| 1028 | | -void cdn_dp_infoframe_set(struct cdn_dp_device *dp, int entry_id, |
|---|
| 1029 | | - u8 *buf, u32 len, int type) |
|---|
| 1030 | | -{ |
|---|
| 1031 | | - unsigned int idx; |
|---|
| 1032 | | - u32 *packet = (u32 *)buf; |
|---|
| 1033 | | - u32 length = len / 4; |
|---|
| 1034 | | - |
|---|
| 1035 | | - for (idx = 0; idx < length; idx++) |
|---|
| 1036 | | - writel(cpu_to_le32(*packet++), dp->regs + SOURCE_PIF_DATA_WR); |
|---|
| 1037 | | - |
|---|
| 1038 | | - writel(entry_id, dp->regs + SOURCE_PIF_WR_ADDR); |
|---|
| 1039 | | - writel(HOST_WR, dp->regs + SOURCE_PIF_WR_REQ); |
|---|
| 1040 | | - writel(ACTIVE_IDLE_TYPE(1) | TYPE_VALID | |
|---|
| 1041 | | - PACKET_TYPE(type) | PKT_ALLOC_ADDRESS(entry_id), |
|---|
| 1042 | | - dp->regs + SOURCE_PIF_PKT_ALLOC_REG); |
|---|
| 1043 | | - writel(PKT_ALLOC_WR_EN, dp->regs + SOURCE_PIF_PKT_ALLOC_WR_EN); |
|---|
| 1044 | 929 | } |
|---|
| 1045 | 930 | |
|---|
| 1046 | 931 | int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio) |
|---|
| .. | .. |
|---|
| 1064 | 949 | if (audio->format == AFMT_I2S) |
|---|
| 1065 | 950 | cdn_dp_audio_config_i2s(dp, audio); |
|---|
| 1066 | 951 | else if (audio->format == AFMT_SPDIF) |
|---|
| 1067 | | - cdn_dp_audio_config_spdif(dp, audio); |
|---|
| 952 | + cdn_dp_audio_config_spdif(dp); |
|---|
| 1068 | 953 | |
|---|
| 1069 | 954 | ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); |
|---|
| 1070 | 955 | |
|---|