.. | .. |
---|
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) |
---|