| .. | .. |
|---|
| 181 | 181 | return 0; |
|---|
| 182 | 182 | } |
|---|
| 183 | 183 | |
|---|
| 184 | | -static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) |
|---|
| 184 | +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) |
|---|
| 185 | 185 | { |
|---|
| 186 | 186 | u8 msg[6]; |
|---|
| 187 | 187 | |
|---|
| .. | .. |
|---|
| 213 | 213 | sizeof(field), field); |
|---|
| 214 | 214 | } |
|---|
| 215 | 215 | |
|---|
| 216 | | -int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) |
|---|
| 216 | +/* |
|---|
| 217 | + * Returns the number of bytes transferred on success, or a negative |
|---|
| 218 | + * error code on failure. -ETIMEDOUT is returned if mailbox message was |
|---|
| 219 | + * not send successfully; |
|---|
| 220 | + */ |
|---|
| 221 | +ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) |
|---|
| 217 | 222 | { |
|---|
| 218 | 223 | u8 msg[5], reg[5]; |
|---|
| 219 | 224 | int ret; |
|---|
| .. | .. |
|---|
| 239 | 244 | goto err_dpcd_read; |
|---|
| 240 | 245 | |
|---|
| 241 | 246 | ret = cdn_dp_mailbox_read_receive(dp, data, len); |
|---|
| 247 | + if (!ret) |
|---|
| 248 | + return len; |
|---|
| 242 | 249 | |
|---|
| 243 | 250 | err_dpcd_read: |
|---|
| 251 | + DRM_DEV_ERROR(dp->dev, "dpcd read failed: %d\n", ret); |
|---|
| 244 | 252 | return ret; |
|---|
| 245 | 253 | } |
|---|
| 246 | 254 | |
|---|
| 247 | | -int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) |
|---|
| 255 | +#define CDN_AUX_HEADER_SIZE 5 |
|---|
| 256 | +#define CDN_AUX_MSG_SIZE 20 |
|---|
| 257 | +/* |
|---|
| 258 | + * Returns the number of bytes transferred on success, or a negative error |
|---|
| 259 | + * code on failure. -ETIMEDOUT is returned if mailbox message was not send |
|---|
| 260 | + * success; -EINVAL is returned if get the wrong data size after message |
|---|
| 261 | + * is sent |
|---|
| 262 | + */ |
|---|
| 263 | +ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) |
|---|
| 248 | 264 | { |
|---|
| 249 | | - u8 msg[6], reg[5]; |
|---|
| 265 | + u8 msg[CDN_AUX_MSG_SIZE + CDN_AUX_HEADER_SIZE]; |
|---|
| 266 | + u8 reg[CDN_AUX_HEADER_SIZE]; |
|---|
| 250 | 267 | int ret; |
|---|
| 251 | 268 | |
|---|
| 252 | | - msg[0] = 0; |
|---|
| 253 | | - msg[1] = 1; |
|---|
| 269 | + if (WARN_ON(len > CDN_AUX_MSG_SIZE) || WARN_ON(len <= 0)) |
|---|
| 270 | + return -EINVAL; |
|---|
| 271 | + |
|---|
| 272 | + msg[0] = (len >> 8) & 0xff; |
|---|
| 273 | + msg[1] = len & 0xff; |
|---|
| 254 | 274 | msg[2] = (addr >> 16) & 0xff; |
|---|
| 255 | 275 | msg[3] = (addr >> 8) & 0xff; |
|---|
| 256 | 276 | msg[4] = addr & 0xff; |
|---|
| 257 | | - msg[5] = value; |
|---|
| 277 | + |
|---|
| 278 | + memcpy(msg + CDN_AUX_HEADER_SIZE, data, len); |
|---|
| 279 | + |
|---|
| 258 | 280 | ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD, |
|---|
| 259 | | - sizeof(msg), msg); |
|---|
| 281 | + CDN_AUX_HEADER_SIZE + len, msg); |
|---|
| 260 | 282 | if (ret) |
|---|
| 261 | 283 | goto err_dpcd_write; |
|---|
| 262 | 284 | |
|---|
| .. | .. |
|---|
| 269 | 291 | if (ret) |
|---|
| 270 | 292 | goto err_dpcd_write; |
|---|
| 271 | 293 | |
|---|
| 272 | | - if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) |
|---|
| 294 | + if ((len != (reg[0] << 8 | reg[1])) || |
|---|
| 295 | + (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))) { |
|---|
| 273 | 296 | ret = -EINVAL; |
|---|
| 297 | + } else { |
|---|
| 298 | + return len; |
|---|
| 299 | + } |
|---|
| 274 | 300 | |
|---|
| 275 | 301 | err_dpcd_write: |
|---|
| 276 | 302 | if (ret) |
|---|
| 277 | 303 | DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret); |
|---|
| 304 | + return ret; |
|---|
| 305 | +} |
|---|
| 306 | + |
|---|
| 307 | +int cdn_dp_get_aux_status(struct cdn_dp_device *dp) |
|---|
| 308 | +{ |
|---|
| 309 | + u8 status; |
|---|
| 310 | + int ret; |
|---|
| 311 | + |
|---|
| 312 | + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, |
|---|
| 313 | + DPTX_GET_LAST_AUX_STAUS, 0, NULL); |
|---|
| 314 | + if (ret) |
|---|
| 315 | + goto err_get_hpd; |
|---|
| 316 | + |
|---|
| 317 | + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, |
|---|
| 318 | + DPTX_GET_LAST_AUX_STAUS, |
|---|
| 319 | + sizeof(status)); |
|---|
| 320 | + if (ret) |
|---|
| 321 | + goto err_get_hpd; |
|---|
| 322 | + |
|---|
| 323 | + ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status)); |
|---|
| 324 | + if (ret) |
|---|
| 325 | + goto err_get_hpd; |
|---|
| 326 | + |
|---|
| 327 | + return status; |
|---|
| 328 | + |
|---|
| 329 | +err_get_hpd: |
|---|
| 330 | + DRM_DEV_ERROR(dp->dev, "get aux status failed: %d\n", ret); |
|---|
| 278 | 331 | return ret; |
|---|
| 279 | 332 | } |
|---|
| 280 | 333 | |
|---|
| .. | .. |
|---|
| 535 | 588 | if (ret) |
|---|
| 536 | 589 | goto err_get_training_status; |
|---|
| 537 | 590 | |
|---|
| 538 | | - dp->max_rate = drm_dp_bw_code_to_link_rate(status[0]); |
|---|
| 591 | + dp->max_rate = status[0]; |
|---|
| 539 | 592 | dp->max_lanes = status[1]; |
|---|
| 540 | 593 | |
|---|
| 541 | 594 | err_get_training_status: |
|---|
| .. | .. |
|---|
| 548 | 601 | { |
|---|
| 549 | 602 | int ret; |
|---|
| 550 | 603 | |
|---|
| 604 | + /* |
|---|
| 605 | + * DP firmware uses fixed phy config values to do training, but some |
|---|
| 606 | + * boards need to adjust these values to fit for their unique hardware |
|---|
| 607 | + * design. So if the phy is using custom config values, do software |
|---|
| 608 | + * link training instead of relying on firmware, if software training |
|---|
| 609 | + * fail, keep firmware training as a fallback if sw training fails. |
|---|
| 610 | + */ |
|---|
| 611 | + ret = cdn_dp_software_train_link(dp); |
|---|
| 612 | + if (ret) { |
|---|
| 613 | + DRM_DEV_ERROR(dp->dev, |
|---|
| 614 | + "Failed to do software training %d\n", ret); |
|---|
| 615 | + goto do_fw_training; |
|---|
| 616 | + } |
|---|
| 617 | + ret = cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf); |
|---|
| 618 | + if (ret) { |
|---|
| 619 | + DRM_DEV_ERROR(dp->dev, |
|---|
| 620 | + "Failed to write SOURCE_HDTX_CAR register %d\n", ret); |
|---|
| 621 | + goto do_fw_training; |
|---|
| 622 | + } |
|---|
| 623 | + dp->use_fw_training = false; |
|---|
| 624 | + return 0; |
|---|
| 625 | + |
|---|
| 626 | +do_fw_training: |
|---|
| 627 | + dp->use_fw_training = true; |
|---|
| 628 | + DRM_DEV_DEBUG_KMS(dp->dev, "use fw training\n"); |
|---|
| 551 | 629 | ret = cdn_dp_training_start(dp); |
|---|
| 552 | 630 | if (ret) { |
|---|
| 553 | 631 | DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); |
|---|
| .. | .. |
|---|
| 639 | 717 | bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? |
|---|
| 640 | 718 | (video->color_depth * 2) : (video->color_depth * 3); |
|---|
| 641 | 719 | |
|---|
| 642 | | - link_rate = dp->max_rate / 1000; |
|---|
| 720 | + link_rate = drm_dp_bw_code_to_link_rate(dp->max_rate) / 1000; |
|---|
| 643 | 721 | |
|---|
| 644 | 722 | ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); |
|---|
| 645 | 723 | if (ret) |
|---|