From mboxrd@z Thu Jan 1 00:00:00 1970 From: Sean Paul Subject: Re: [PATCH v5 4/4] drm/rockchip: support dp training outside dp firmware Date: Thu, 17 May 2018 09:51:36 -0400 Message-ID: <20180517135136.GD3373@art_vandelay> References: <1526548680-2552-1-git-send-email-hl@rock-chips.com> <1526548680-2552-4-git-send-email-hl@rock-chips.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Content-Disposition: inline In-Reply-To: <1526548680-2552-4-git-send-email-hl@rock-chips.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Lin Huang Cc: devicetree@vger.kernel.org, airlied@linux.ie, briannorris@chromium.org, dianders@chromium.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh+dt@kernel.org, dri-devel@lists.freedesktop.org, zyw@rock-chips.com, daniel.vetter@intel.com, linux-arm-kernel@lists.infradead.org List-Id: linux-rockchip.vger.kernel.org T24gVGh1LCBNYXkgMTcsIDIwMTggYXQgMDU6MTg6MDBQTSArMDgwMCwgTGluIEh1YW5nIHdyb3Rl Ogo+IERQIGZpcm13YXJlIHVzZXMgZml4ZWQgcGh5IGNvbmZpZyB2YWx1ZXMgdG8gZG8gdHJhaW5p bmcsIGJ1dCBzb21lCj4gYm9hcmRzIG5lZWQgdG8gYWRqdXN0IHRoZXNlIHZhbHVlcyB0byBmaXQg Zm9yIHRoZWlyIHVuaXF1ZSBoYXJkd2FyZQo+IGRlc2lnbi4gU28gZ2V0IHBoeSBjb25maWcgdmFs dWVzIGZyb20gZHRzIGFuZCB1c2Ugc29mdHdhcmUgbGluayB0cmFpbmluZwo+IGluc3RlYWQgb2Yg cmVseWluZyBvbiBmaXJtd2FyZSwgaWYgc29mdHdhcmUgdHJhaW5pbmcgZmFpbCwga2VlcCBmaXJt d2FyZQo+IHRyYWluaW5nIGFzIGEgZmFsbGJhY2sgaWYgc3cgdHJhaW5pbmcgZmFpbHMuCj4gCj4g U2lnbmVkLW9mZi1ieTogQ2hyaXMgWmhvbmcgPHp5d0Byb2NrLWNoaXBzLmNvbT4KPiBTaWduZWQt b2ZmLWJ5OiBMaW4gSHVhbmcgPGhsQHJvY2stY2hpcHMuY29tPgo+IC0tLQo+IENoYW5nZXMgaW4g djI6Cj4gLSB1cGRhdGUgcGF0Y2ggZm9sbG93aW5nIEVucmljIHN1Z2dlc3QKPiBDaGFuZ2VzIGlu IHYzOgo+IC0gdXNlIHZhcmlhYmxlIGZ3X3RyYWluaW5nIGluc3RlYWQgc3dfdHJhaW5pbmdfc3Vj Y2Vzcwo+IC0gYmFzZSBvbiBEUCBTUENFLCBpZiB0cmFpbmluZyBmYWlsIHVzZSBsb3dlciBsaW5r IHJhdGUgdG8gcmV0cnkgdHJhaW5pbmcKPiBDaGFuZ2VzIGluIHY0Ogo+IC0gaW1wcm92ZSBjZG5f ZHBfZ2V0X2xvd2VyX2xpbmtfcmF0ZSgpIGFuZCBjZG5fZHBfc29mdHdhcmVfdHJhaW5fbGluaygp IGZvbGxvdyBTZWFuIHN1Z2dlc3QKPiBDaGFuZ2VzIGluIHY1Ogo+IC0gZml4IHNvbWUgd2hpdGVz cGNhZSBpc3N1ZQo+IAo+ICBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvTWFrZWZpbGUgICAgICAg ICAgICAgICB8ICAgMyArLQo+ICBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUu YyAgICAgICAgICB8ICAyNCArLQo+ICBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNv cmUuaCAgICAgICAgICB8ICAgMiArCj4gIGRyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAt bGluay10cmFpbmluZy5jIHwgNDIwICsrKysrKysrKysrKysrKysrKysrKysrKwo+ICBkcml2ZXJz L2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLXJlZy5jICAgICAgICAgICB8ICAzMSArLQo+ICBkcml2 ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLXJlZy5oICAgICAgICAgICB8ICAzOCArKy0KPiAg NiBmaWxlcyBjaGFuZ2VkLCA1MDUgaW5zZXJ0aW9ucygrKSwgMTMgZGVsZXRpb25zKC0pCj4gIGNy ZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWxpbmstdHJh aW5pbmcuYwo+IAo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvTWFrZWZp bGUgYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvTWFrZWZpbGUKPiBpbmRleCBhMzE0ZTIxLi5i OTMyZjYyIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9NYWtlZmlsZQo+ ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9NYWtlZmlsZQo+IEBAIC05LDcgKzksOCBA QCByb2NrY2hpcGRybS15IDo9IHJvY2tjaGlwX2RybV9kcnYubyByb2NrY2hpcF9kcm1fZmIubyBc Cj4gIHJvY2tjaGlwZHJtLSQoQ09ORklHX0RSTV9GQkRFVl9FTVVMQVRJT04pICs9IHJvY2tjaGlw X2RybV9mYmRldi5vCj4gIAo+ICByb2NrY2hpcGRybS0kKENPTkZJR19ST0NLQ0hJUF9BTkFMT0dJ WF9EUCkgKz0gYW5hbG9naXhfZHAtcm9ja2NoaXAubwo+IC1yb2NrY2hpcGRybS0kKENPTkZJR19S T0NLQ0hJUF9DRE5fRFApICs9IGNkbi1kcC1jb3JlLm8gY2RuLWRwLXJlZy5vCj4gK3JvY2tjaGlw ZHJtLSQoQ09ORklHX1JPQ0tDSElQX0NETl9EUCkgKz0gY2RuLWRwLWNvcmUubyBjZG4tZHAtcmVn Lm8gXAo+ICsJCQkJCWNkbi1kcC1saW5rLXRyYWluaW5nLm8KPiAgcm9ja2NoaXBkcm0tJChDT05G SUdfUk9DS0NISVBfRFdfSERNSSkgKz0gZHdfaGRtaS1yb2NrY2hpcC5vCj4gIHJvY2tjaGlwZHJt LSQoQ09ORklHX1JPQ0tDSElQX0RXX01JUElfRFNJKSArPSBkdy1taXBpLWRzaS5vCj4gIHJvY2tj aGlwZHJtLSQoQ09ORklHX1JPQ0tDSElQX0lOTk9fSERNSSkgKz0gaW5ub19oZG1pLm8KPiBkaWZm IC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1jb3JlLmMgYi9kcml2ZXJz L2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUuYwo+IGluZGV4IGNjZTY0YzEuLmQ5ZDBkNGQg MTAwNjQ0Cj4gLS0tIGEvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1jb3JlLmMKPiAr KysgYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLWNvcmUuYwo+IEBAIC02MjksMTEg KzYyOSwxMyBAQCBzdGF0aWMgdm9pZCBjZG5fZHBfZW5jb2Rlcl9lbmFibGUoc3RydWN0IGRybV9l bmNvZGVyICplbmNvZGVyKQo+ICAJCQlnb3RvIG91dDsKPiAgCQl9Cj4gIAl9Cj4gLQo+IC0JcmV0 ID0gY2RuX2RwX3NldF92aWRlb19zdGF0dXMoZHAsIENPTlRST0xfVklERU9fSURMRSk7Cj4gLQlp ZiAocmV0KSB7Cj4gLQkJRFJNX0RFVl9FUlJPUihkcC0+ZGV2LCAiRmFpbGVkIHRvIGlkbGUgdmlk ZW8gJWRcbiIsIHJldCk7Cj4gLQkJZ290byBvdXQ7Cj4gKwlpZiAoZHAtPnVzZV9md190cmFpbmlu ZyA9PSB0cnVlKSB7Cj4gKwkJcmV0ID0gY2RuX2RwX3NldF92aWRlb19zdGF0dXMoZHAsIENPTlRS T0xfVklERU9fSURMRSk7Cj4gKwkJaWYgKHJldCkgewo+ICsJCQlEUk1fREVWX0VSUk9SKGRwLT5k ZXYsCj4gKwkJCQkgICAgICAiRmFpbGVkIHRvIGlkbGUgdmlkZW8gJWRcbiIsIHJldCk7Cj4gKwkJ CWdvdG8gb3V0Owo+ICsJCX0KPiAgCX0KPiAgCj4gIAlyZXQgPSBjZG5fZHBfY29uZmlnX3ZpZGVv KGRwKTsKPiBAQCAtNjQyLDExICs2NDQsMTUgQEAgc3RhdGljIHZvaWQgY2RuX2RwX2VuY29kZXJf ZW5hYmxlKHN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2RlcikKPiAgCQlnb3RvIG91dDsKPiAgCX0K PiAgCj4gLQlyZXQgPSBjZG5fZHBfc2V0X3ZpZGVvX3N0YXR1cyhkcCwgQ09OVFJPTF9WSURFT19W QUxJRCk7Cj4gLQlpZiAocmV0KSB7Cj4gLQkJRFJNX0RFVl9FUlJPUihkcC0+ZGV2LCAiRmFpbGVk IHRvIHZhbGlkIHZpZGVvICVkXG4iLCByZXQpOwo+IC0JCWdvdG8gb3V0Owo+ICsJaWYgKGRwLT51 c2VfZndfdHJhaW5pbmcgPT0gdHJ1ZSkgewo+ICsJCXJldCA9IGNkbl9kcF9zZXRfdmlkZW9fc3Rh dHVzKGRwLCBDT05UUk9MX1ZJREVPX1ZBTElEKTsKPiArCQlpZiAocmV0KSB7Cj4gKwkJCURSTV9E RVZfRVJST1IoZHAtPmRldiwKPiArCQkJCSJGYWlsZWQgdG8gdmFsaWQgdmlkZW8gJWRcbiIsIHJl dCk7Cj4gKwkJCWdvdG8gb3V0Owo+ICsJCX0KPiAgCX0KPiArCj4gIG91dDoKPiAgCW11dGV4X3Vu bG9jaygmZHAtPmxvY2spOwo+ICB9Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9yb2Nr Y2hpcC9jZG4tZHAtY29yZS5oIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1jb3Jl LmgKPiBpbmRleCA0NjE1OWIyLi43N2E5NzkzIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvZ3B1L2Ry bS9yb2NrY2hpcC9jZG4tZHAtY29yZS5oCj4gKysrIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlw L2Nkbi1kcC1jb3JlLmgKPiBAQCAtODQsNiArODQsNyBAQCBzdHJ1Y3QgY2RuX2RwX2RldmljZSB7 Cj4gIAlib29sIGNvbm5lY3RlZDsKPiAgCWJvb2wgYWN0aXZlOwo+ICAJYm9vbCBzdXNwZW5kZWQ7 Cj4gKwlib29sIHVzZV9md190cmFpbmluZzsKPiAgCj4gIAljb25zdCBzdHJ1Y3QgZmlybXdhcmUg KmZ3OwkvKiBjZG4gZHAgZmlybXdhcmUgKi8KPiAgCXVuc2lnbmVkIGludCBmd192ZXJzaW9uOwkv KiBjZG4gZncgdmVyc2lvbiAqLwo+IEBAIC0xMDYsNiArMTA3LDcgQEAgc3RydWN0IGNkbl9kcF9k ZXZpY2Ugewo+ICAJdTggcG9ydHM7Cj4gIAl1OCBsYW5lczsKPiAgCWludCBhY3RpdmVfcG9ydDsK PiArCXU4IHRyYWluX3NldFs0XTsKPiAgCj4gIAl1OCBkcGNkW0RQX1JFQ0VJVkVSX0NBUF9TSVpF XTsKPiAgCWJvb2wgc2lua19oYXNfYXVkaW87Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2Ry bS9yb2NrY2hpcC9jZG4tZHAtbGluay10cmFpbmluZy5jIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tj aGlwL2Nkbi1kcC1saW5rLXRyYWluaW5nLmMKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4 IDAwMDAwMDAuLjczYzMyOTAKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVycy9ncHUvZHJt L3JvY2tjaGlwL2Nkbi1kcC1saW5rLXRyYWluaW5nLmMKPiBAQCAtMCwwICsxLDQyMCBAQAo+ICsv LyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMAo+ICsvKgo+ICsgKiBDb3B5cmlnaHQg KEMpIEZ1emhvdSBSb2NrY2hpcCBFbGVjdHJvbmljcyBDby5MdGQKPiArICogQXV0aG9yOiBDaHJp cyBaaG9uZyA8enl3QHJvY2stY2hpcHMuY29tPgo+ICsgKi8KPiArCj4gKyNpbmNsdWRlIDxsaW51 eC9kZXZpY2UuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+Cj4gKyNpbmNsdWRlIDxsaW51 eC9waHkvcGh5Lmg+Cj4gKyNpbmNsdWRlIDxzb2Mvcm9ja2NoaXAvcm9ja2NoaXBfcGh5X3R5cGVj Lmg+Cj4gKwo+ICsjaW5jbHVkZSAiY2RuLWRwLWNvcmUuaCIKPiArI2luY2x1ZGUgImNkbi1kcC1y ZWcuaCIKPiArCj4gK3N0YXRpYyB2b2lkIGNkbl9kcF9zZXRfc2lnbmFsX2xldmVscyhzdHJ1Y3Qg Y2RuX2RwX2RldmljZSAqZHApCj4gK3sKPiArCXN0cnVjdCBjZG5fZHBfcG9ydCAqcG9ydCA9IGRw LT5wb3J0W2RwLT5hY3RpdmVfcG9ydF07Cj4gKwlzdHJ1Y3Qgcm9ja2NoaXBfdHlwZWNfcGh5ICp0 Y3BoeSA9IHBoeV9nZXRfZHJ2ZGF0YShwb3J0LT5waHkpOwoKWW91IGlnbm9yZWQgQnJpYW4ncyBj b21tZW50IG9uIHRoZSBwcmV2aW91cyBwYXRjaDoKICBUaGlzIGlzIHN0aWxsIGFudGl0aGV0aWNh bCB0byB0aGUgUEhZIGZyYW1ld29yazsgeW91J3JlIGFzc3VtaW5nIHRoYXQKICB0aGlzIGlzIGEg cGFydGljdWxhciB0eXBlIG9mIFBIWSBoZXJlLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAKCkZXSVcsIHRoZSBtZWRpYXRlayBkcm0gZHJpdmVyIGFsc28gYXNzdW1lcyBhIGNlcnRhaW4g UEhZIHR5cGUuIEEgcXVpY2sgZ3JlcCBvZgpkcml2ZXJzLyBzaG93cyB0aGF0IHRoZSBvbmx5IG90 aGVyIG5vbi1waHkvIGRyaXZlciB1c2luZyB0aGlzIGZ1bmN0aW9uCihwaW5jdHJsLXRlZ3JhLXh1 c2IuYykgYWxzbyBjYXN0cyBpdC4KClNlYW4KCj4gKwo+ICsJaW50IHJhdGUgPSBkcm1fZHBfYndf Y29kZV90b19saW5rX3JhdGUoZHAtPmxpbmsucmF0ZSk7Cj4gKwl1OCBzd2luZyA9IChkcC0+dHJh aW5fc2V0WzBdICYgRFBfVFJBSU5fVk9MVEFHRV9TV0lOR19NQVNLKSA+Pgo+ICsJCSAgIERQX1RS QUlOX1ZPTFRBR0VfU1dJTkdfU0hJRlQ7Cj4gKwl1OCBwcmVfZW1waGFzaXMgPSAoZHAtPnRyYWlu X3NldFswXSAmIERQX1RSQUlOX1BSRV9FTVBIQVNJU19NQVNLKQo+ICsJCQkgID4+IERQX1RSQUlO X1BSRV9FTVBIQVNJU19TSElGVDsKPiArCj4gKwl0Y3BoeS0+dHlwZWNfcGh5X2NvbmZpZyhwb3J0 LT5waHksIHJhdGUsIGRwLT5saW5rLm51bV9sYW5lcywKPiArCQkJCXN3aW5nLCBwcmVfZW1waGFz aXMpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGNkbl9kcF9zZXRfcGF0dGVybihzdHJ1Y3QgY2Ru X2RwX2RldmljZSAqZHAsIHVpbnQ4X3QgZHBfdHJhaW5fcGF0KQo+ICt7Cj4gKwl1MzIgcGh5X2Nv bmZpZywgZ2xvYmFsX2NvbmZpZzsKPiArCWludCByZXQ7Cj4gKwl1aW50OF90IHBhdHRlcm4gPSBk cF90cmFpbl9wYXQgJiBEUF9UUkFJTklOR19QQVRURVJOX01BU0s7Cj4gKwo+ICsJZ2xvYmFsX2Nv bmZpZyA9IE5VTV9MQU5FUyhkcC0+bGluay5udW1fbGFuZXMgLSAxKSB8IFNTVF9NT0RFIHwKPiAr CQkJR0xPQkFMX0VOIHwgUkdfRU4gfCBFTkNfUlNUX0RJUyB8IFdSX1ZIU1lOQ19GQUxMOwo+ICsK PiArCXBoeV9jb25maWcgPSBEUF9UWF9QSFlfRU5DT0RFUl9CWVBBU1MoMCkgfAo+ICsJCSAgICAg RFBfVFhfUEhZX1NLRVdfQllQQVNTKDApIHwKPiArCQkgICAgIERQX1RYX1BIWV9ESVNQQVJJVFlf UlNUKDApIHwKPiArCQkgICAgIERQX1RYX1BIWV9MQU5FMF9TS0VXKDApIHwKPiArCQkgICAgIERQ X1RYX1BIWV9MQU5FMV9TS0VXKDEpIHwKPiArCQkgICAgIERQX1RYX1BIWV9MQU5FMl9TS0VXKDIp IHwKPiArCQkgICAgIERQX1RYX1BIWV9MQU5FM19TS0VXKDMpIHwKPiArCQkgICAgIERQX1RYX1BI WV8xMEJJVF9FTkFCTEUoMCk7Cj4gKwo+ICsJaWYgKHBhdHRlcm4gIT0gRFBfVFJBSU5JTkdfUEFU VEVSTl9ESVNBQkxFKSB7Cj4gKwkJZ2xvYmFsX2NvbmZpZyB8PSBOT19WSURFTzsKPiArCQlwaHlf Y29uZmlnIHw9IERQX1RYX1BIWV9UUkFJTklOR19FTkFCTEUoMSkgfAo+ICsJCQkgICAgICBEUF9U WF9QSFlfU0NSQU1CTEVSX0JZUEFTUygxKSB8Cj4gKwkJCSAgICAgIERQX1RYX1BIWV9UUkFJTklO R19QQVRURVJOKHBhdHRlcm4pOwo+ICsJfQo+ICsKPiArCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUo ZHAsIERQX0ZSQU1FUl9HTE9CQUxfQ09ORklHLCBnbG9iYWxfY29uZmlnKTsKPiArCWlmIChyZXQp IHsKPiArCQlEUk1fRVJST1IoImZhaWwgdG8gc2V0IERQX0ZSQU1FUl9HTE9CQUxfQ09ORklHLCBl cnJvcjogJWRcbiIsCj4gKwkJCSAgcmV0KTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiAr CXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIERQX1RYX1BIWV9DT05GSUdfUkVHLCBwaHlfY29u ZmlnKTsKPiArCWlmIChyZXQpIHsKPiArCQlEUk1fRVJST1IoImZhaWwgdG8gc2V0IERQX1RYX1BI WV9DT05GSUdfUkVHLCBlcnJvcjogJWRcbiIsCj4gKwkJCSAgcmV0KTsKPiArCQlyZXR1cm4gcmV0 Owo+ICsJfQo+ICsKPiArCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIERQVFhfTEFORV9FTiwg QklUKGRwLT5saW5rLm51bV9sYW5lcykgLSAxKTsKPiArCWlmIChyZXQpIHsKPiArCQlEUk1fRVJS T1IoImZhaWwgdG8gc2V0IERQVFhfTEFORV9FTiwgZXJyb3I6ICVkXG4iLCByZXQpOwo+ICsJCXJl dHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJaWYgKGRybV9kcF9lbmhhbmNlZF9mcmFtZV9jYXAoZHAt PmRwY2QpKQo+ICsJCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIERQVFhfRU5ITkNELCAxKTsK PiArCWVsc2UKPiArCQlyZXQgPSBjZG5fZHBfcmVnX3dyaXRlKGRwLCBEUFRYX0VOSE5DRCwgMCk7 Cj4gKwlpZiAocmV0KQo+ICsJCURSTV9FUlJPUigiZmFpbGVkIHRvIHNldCBEUFRYX0VOSE5DRCwg ZXJyb3I6ICV4XG4iLCByZXQpOwo+ICsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRp YyB1OCBjZG5fZHBfcHJlX2VtcGhhc2lzX21heCh1OCB2b2x0YWdlX3N3aW5nKQo+ICt7Cj4gKwlz d2l0Y2ggKHZvbHRhZ2Vfc3dpbmcgJiBEUF9UUkFJTl9WT0xUQUdFX1NXSU5HX01BU0spIHsKPiAr CWNhc2UgRFBfVFJBSU5fVk9MVEFHRV9TV0lOR19MRVZFTF8wOgo+ICsJCXJldHVybiBEUF9UUkFJ Tl9QUkVfRU1QSF9MRVZFTF8zOwo+ICsJY2FzZSBEUF9UUkFJTl9WT0xUQUdFX1NXSU5HX0xFVkVM XzE6Cj4gKwkJcmV0dXJuIERQX1RSQUlOX1BSRV9FTVBIX0xFVkVMXzI7Cj4gKwljYXNlIERQX1RS QUlOX1ZPTFRBR0VfU1dJTkdfTEVWRUxfMjoKPiArCQlyZXR1cm4gRFBfVFJBSU5fUFJFX0VNUEhf TEVWRUxfMTsKPiArCWRlZmF1bHQ6Cj4gKwkJcmV0dXJuIERQX1RSQUlOX1BSRV9FTVBIX0xFVkVM XzA7Cj4gKwl9Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGNkbl9kcF9nZXRfYWRqdXN0X3RyYWlu KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCwKPiArCQkJCSAgICB1aW50OF90IGxpbmtfc3RhdHVz W0RQX0xJTktfU1RBVFVTX1NJWkVdKQo+ICt7Cj4gKwlpbnQgaTsKPiArCXVpbnQ4X3QgdiA9IDAs IHAgPSAwOwo+ICsJdWludDhfdCBwcmVlbXBoX21heDsKPiArCj4gKwlmb3IgKGkgPSAwOyBpIDwg ZHAtPmxpbmsubnVtX2xhbmVzOyBpKyspIHsKPiArCQl2ID0gbWF4KHYsIGRybV9kcF9nZXRfYWRq dXN0X3JlcXVlc3Rfdm9sdGFnZShsaW5rX3N0YXR1cywgaSkpOwo+ICsJCXAgPSBtYXgocCwgZHJt X2RwX2dldF9hZGp1c3RfcmVxdWVzdF9wcmVfZW1waGFzaXMobGlua19zdGF0dXMsCj4gKwkJCQkJ CQkJICBpKSk7Cj4gKwl9Cj4gKwo+ICsJaWYgKHYgPj0gVk9MVEFHRV9MRVZFTF8yKQo+ICsJCXYg PSBWT0xUQUdFX0xFVkVMXzIgfCBEUF9UUkFJTl9NQVhfU1dJTkdfUkVBQ0hFRDsKPiArCj4gKwlw cmVlbXBoX21heCA9IGNkbl9kcF9wcmVfZW1waGFzaXNfbWF4KHYpOwo+ICsJaWYgKHAgPj0gcHJl ZW1waF9tYXgpCj4gKwkJcCA9IHByZWVtcGhfbWF4IHwgRFBfVFJBSU5fTUFYX1BSRV9FTVBIQVNJ U19SRUFDSEVEOwo+ICsKPiArCWZvciAoaSA9IDA7IGkgPCBkcC0+bGluay5udW1fbGFuZXM7IGkr KykKPiArCQlkcC0+dHJhaW5fc2V0W2ldID0gdiB8IHA7Cj4gK30KPiArCj4gKy8qCj4gKyAqIFBp Y2sgdHJhaW5pbmcgcGF0dGVybiBmb3IgY2hhbm5lbCBlcXVhbGl6YXRpb24uIFRyYWluaW5nIFBh dHRlcm4gMyBmb3IgSEJSMgo+ICsgKiBvciAxLjIgZGV2aWNlcyB0aGF0IHN1cHBvcnQgaXQsIFRy YWluaW5nIFBhdHRlcm4gMiBvdGhlcndpc2UuCj4gKyAqLwo+ICtzdGF0aWMgdTMyIGNkbl9kcF9z ZWxlY3RfY2hhbmVxX3BhdHRlcm4oc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQo+ICt7Cj4gKwl1 MzIgdHJhaW5pbmdfcGF0dGVybiA9IERQX1RSQUlOSU5HX1BBVFRFUk5fMjsKPiArCj4gKwkvKgo+ ICsJICogY2RuIGRwIHN1cHBvcnQgSEJSMiBhbHNvIHN1cHBvcnQgVFBTMy4gVFBTMyBzdXBwb3J0 IGlzIGFsc28gbWFuZGF0b3J5Cj4gKwkgKiBmb3IgZG93bnN0cmVhbSBkZXZpY2VzIHRoYXQgc3Vw cG9ydCBIQlIyLiBIb3dldmVyLCBub3QgYWxsIHNpbmtzCj4gKwkgKiBmb2xsb3cgdGhlIHNwZWMu Cj4gKwkgKi8KPiArCWlmIChkcm1fZHBfdHBzM19zdXBwb3J0ZWQoZHAtPmRwY2QpKQo+ICsJCXRy YWluaW5nX3BhdHRlcm4gPSBEUF9UUkFJTklOR19QQVRURVJOXzM7Cj4gKwllbHNlCj4gKwkJRFJN X0RFQlVHX0tNUygiNS40IEdicHMgbGluayByYXRlIHdpdGhvdXQgc2luayBUUFMzIHN1cHBvcnRc biIpOwo+ICsKPiArCXJldHVybiB0cmFpbmluZ19wYXR0ZXJuOwo+ICt9Cj4gKwo+ICsKPiArc3Rh dGljIGJvb2wgY2RuX2RwX2xpbmtfbWF4X3Zzd2luZ19yZWFjaGVkKHN0cnVjdCBjZG5fZHBfZGV2 aWNlICpkcCkKPiArewo+ICsJaW50IGxhbmU7Cj4gKwo+ICsJZm9yIChsYW5lID0gMDsgbGFuZSA8 IGRwLT5saW5rLm51bV9sYW5lczsgbGFuZSsrKQo+ICsJCWlmICgoZHAtPnRyYWluX3NldFtsYW5l XSAmIERQX1RSQUlOX01BWF9TV0lOR19SRUFDSEVEKSA9PSAwKQo+ICsJCQlyZXR1cm4gZmFsc2U7 Cj4gKwo+ICsJcmV0dXJuIHRydWU7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgY2RuX2RwX3VwZGF0 ZV9saW5rX3RyYWluKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCkKPiArewo+ICsJaW50IHJldDsK PiArCj4gKwljZG5fZHBfc2V0X3NpZ25hbF9sZXZlbHMoZHApOwo+ICsKPiArCXJldCA9IGRybV9k cF9kcGNkX3dyaXRlKCZkcC0+YXV4LCBEUF9UUkFJTklOR19MQU5FMF9TRVQsCj4gKwkJCQlkcC0+ dHJhaW5fc2V0LCBkcC0+bGluay5udW1fbGFuZXMpOwo+ICsJaWYgKHJldCAhPSBkcC0+bGluay5u dW1fbGFuZXMpCj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiAr Cj4gK3N0YXRpYyBpbnQgY2RuX2RwX3NldF9saW5rX3RyYWluKHN0cnVjdCBjZG5fZHBfZGV2aWNl ICpkcCwKPiArCQkJCSAgdWludDhfdCBkcF90cmFpbl9wYXQpCj4gK3sKPiArCXVpbnQ4X3QgYnVm W3NpemVvZihkcC0+dHJhaW5fc2V0KSArIDFdOwo+ICsJaW50IHJldCwgbGVuOwo+ICsKPiArCWJ1 ZlswXSA9IGRwX3RyYWluX3BhdDsKPiArCWlmICgoZHBfdHJhaW5fcGF0ICYgRFBfVFJBSU5JTkdf UEFUVEVSTl9NQVNLKSA9PQo+ICsJICAgIERQX1RSQUlOSU5HX1BBVFRFUk5fRElTQUJMRSkgewo+ ICsJCS8qIGRvbid0IHdyaXRlIERQX1RSQUlOSU5HX0xBTkV4X1NFVCBvbiBkaXNhYmxlICovCj4g KwkJbGVuID0gMTsKPiArCX0gZWxzZSB7Cj4gKwkJLyogRFBfVFJBSU5JTkdfTEFORXhfU0VUIGZv bGxvdyBEUF9UUkFJTklOR19QQVRURVJOX1NFVCAqLwo+ICsJCW1lbWNweShidWYgKyAxLCBkcC0+ dHJhaW5fc2V0LCBkcC0+bGluay5udW1fbGFuZXMpOwo+ICsJCWxlbiA9IGRwLT5saW5rLm51bV9s YW5lcyArIDE7Cj4gKwl9Cj4gKwo+ICsJcmV0ID0gZHJtX2RwX2RwY2Rfd3JpdGUoJmRwLT5hdXgs IERQX1RSQUlOSU5HX1BBVFRFUk5fU0VULAo+ICsJCQkJYnVmLCBsZW4pOwo+ICsJaWYgKHJldCAh PSBsZW4pCj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4g K3N0YXRpYyBpbnQgY2RuX2RwX3Jlc2V0X2xpbmtfdHJhaW4oc3RydWN0IGNkbl9kcF9kZXZpY2Ug KmRwLAo+ICsJCQkJICAgIHVpbnQ4X3QgZHBfdHJhaW5fcGF0KQo+ICt7Cj4gKwlpbnQgcmV0Owo+ ICsKPiArCW1lbXNldChkcC0+dHJhaW5fc2V0LCAwLCBzaXplb2YoZHAtPnRyYWluX3NldCkpOwo+ ICsKPiArCWNkbl9kcF9zZXRfc2lnbmFsX2xldmVscyhkcCk7Cj4gKwo+ICsJcmV0ID0gY2RuX2Rw X3NldF9wYXR0ZXJuKGRwLCBkcF90cmFpbl9wYXQpOwo+ICsJaWYgKHJldCkKPiArCQlyZXR1cm4g cmV0Owo+ICsKPiArCXJldHVybiBjZG5fZHBfc2V0X2xpbmtfdHJhaW4oZHAsIGRwX3RyYWluX3Bh dCk7Cj4gK30KPiArCj4gKy8qIEVuYWJsZSBjb3JyZXNwb25kaW5nIHBvcnQgYW5kIHN0YXJ0IHRy YWluaW5nIHBhdHRlcm4gMSAqLwo+ICtzdGF0aWMgaW50IGNkbl9kcF9saW5rX3RyYWluaW5nX2Ns b2NrX3JlY292ZXJ5KHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCkKPiArewo+ICsJdTggdm9sdGFn ZTsKPiArCXU4IGxpbmtfc3RhdHVzW0RQX0xJTktfU1RBVFVTX1NJWkVdOwo+ICsJdTMyIHZvbHRh Z2VfdHJpZXMsIG1heF92c3dpbmdfdHJpZXM7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCS8qIGNsb2Nr IHJlY292ZXJ5ICovCj4gKwlyZXQgPSBjZG5fZHBfcmVzZXRfbGlua190cmFpbihkcCwgRFBfVFJB SU5JTkdfUEFUVEVSTl8xIHwKPiArCQkJCQkgIERQX0xJTktfU0NSQU1CTElOR19ESVNBQkxFKTsK PiArCWlmIChyZXQpIHsKPiArCQlEUk1fRVJST1IoImZhaWxlZCB0byBzdGFydCBsaW5rIHRyYWlu XG4iKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXZvbHRhZ2VfdHJpZXMgPSAxOwo+ ICsJbWF4X3Zzd2luZ190cmllcyA9IDA7Cj4gKwlmb3IgKDs7KSB7Cj4gKwkJZHJtX2RwX2xpbmtf dHJhaW5fY2xvY2tfcmVjb3ZlcnlfZGVsYXkoZHAtPmRwY2QpOwo+ICsJCWlmIChkcm1fZHBfZHBj ZF9yZWFkX2xpbmtfc3RhdHVzKCZkcC0+YXV4LCBsaW5rX3N0YXR1cykgIT0KPiArCQkgICAgRFBf TElOS19TVEFUVVNfU0laRSkgewo+ICsJCQlEUk1fRVJST1IoImZhaWxlZCB0byBnZXQgbGluayBz dGF0dXNcbiIpOwo+ICsJCQlyZXR1cm4gLUVJTlZBTDsKPiArCQl9Cj4gKwo+ICsJCWlmIChkcm1f ZHBfY2xvY2tfcmVjb3Zlcnlfb2sobGlua19zdGF0dXMsIGRwLT5saW5rLm51bV9sYW5lcykpIHsK PiArCQkJRFJNX0RFQlVHX0tNUygiY2xvY2sgcmVjb3ZlcnkgT0tcbiIpOwo+ICsJCQlyZXR1cm4g MDsKPiArCQl9Cj4gKwo+ICsJCWlmICh2b2x0YWdlX3RyaWVzID49IDUpIHsKPiArCQkJRFJNX0RF QlVHX0tNUygiU2FtZSB2b2x0YWdlIHRyaWVkIDUgdGltZXNcbiIpOwo+ICsJCQlyZXR1cm4gLUVJ TlZBTDsKPiArCQl9Cj4gKwo+ICsJCWlmIChtYXhfdnN3aW5nX3RyaWVzID49IDEpIHsKPiArCQkJ RFJNX0RFQlVHX0tNUygiTWF4IFZvbHRhZ2UgU3dpbmcgcmVhY2hlZFxuIik7Cj4gKwkJCXJldHVy biAtRUlOVkFMOwo+ICsJCX0KPiArCj4gKwkJdm9sdGFnZSA9IGRwLT50cmFpbl9zZXRbMF0gJiBE UF9UUkFJTl9WT0xUQUdFX1NXSU5HX01BU0s7Cj4gKwo+ICsJCS8qIFVwZGF0ZSB0cmFpbmluZyBz ZXQgYXMgcmVxdWVzdGVkIGJ5IHRhcmdldCAqLwo+ICsJCWNkbl9kcF9nZXRfYWRqdXN0X3RyYWlu KGRwLCBsaW5rX3N0YXR1cyk7Cj4gKwkJaWYgKGNkbl9kcF91cGRhdGVfbGlua190cmFpbihkcCkp IHsKPiArCQkJRFJNX0VSUk9SKCJmYWlsZWQgdG8gdXBkYXRlIGxpbmsgdHJhaW5pbmdcbiIpOwo+ ICsJCQlyZXR1cm4gLUVJTlZBTDsKPiArCQl9Cj4gKwo+ICsJCWlmICgoZHAtPnRyYWluX3NldFsw XSAmIERQX1RSQUlOX1ZPTFRBR0VfU1dJTkdfTUFTSykgPT0KPiArCQkgICAgdm9sdGFnZSkKPiAr CQkJKyt2b2x0YWdlX3RyaWVzOwo+ICsJCWVsc2UKPiArCQkJdm9sdGFnZV90cmllcyA9IDE7Cj4g Kwo+ICsJCWlmIChjZG5fZHBfbGlua19tYXhfdnN3aW5nX3JlYWNoZWQoZHApKQo+ICsJCQkrK21h eF92c3dpbmdfdHJpZXM7Cj4gKwl9Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgY2RuX2RwX2xpbmtf dHJhaW5pbmdfY2hhbm5lbF9lcXVhbGl6YXRpb24oc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQo+ ICt7Cj4gKwlpbnQgdHJpZXMsIHJldDsKPiArCXUzMiB0cmFpbmluZ19wYXR0ZXJuOwo+ICsJdWlu dDhfdCBsaW5rX3N0YXR1c1tEUF9MSU5LX1NUQVRVU19TSVpFXTsKPiArCj4gKwl0cmFpbmluZ19w YXR0ZXJuID0gY2RuX2RwX3NlbGVjdF9jaGFuZXFfcGF0dGVybihkcCk7Cj4gKwl0cmFpbmluZ19w YXR0ZXJuIHw9IERQX0xJTktfU0NSQU1CTElOR19ESVNBQkxFOwo+ICsKPiArCXJldCA9IGNkbl9k cF9zZXRfcGF0dGVybihkcCwgdHJhaW5pbmdfcGF0dGVybik7Cj4gKwlpZiAocmV0KQo+ICsJCXJl dHVybiByZXQ7Cj4gKwo+ICsJcmV0ID0gY2RuX2RwX3NldF9saW5rX3RyYWluKGRwLCB0cmFpbmlu Z19wYXR0ZXJuKTsKPiArCWlmIChyZXQpIHsKPiArCQlEUk1fRVJST1IoImZhaWxlZCB0byBzdGFy dCBjaGFubmVsIGVxdWFsaXphdGlvblxuIik7Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiArCj4g Kwlmb3IgKHRyaWVzID0gMDsgdHJpZXMgPCA1OyB0cmllcysrKSB7Cj4gKwkJZHJtX2RwX2xpbmtf dHJhaW5fY2hhbm5lbF9lcV9kZWxheShkcC0+ZHBjZCk7Cj4gKwkJaWYgKGRybV9kcF9kcGNkX3Jl YWRfbGlua19zdGF0dXMoJmRwLT5hdXgsIGxpbmtfc3RhdHVzKSAhPQo+ICsJCSAgICBEUF9MSU5L X1NUQVRVU19TSVpFKSB7Cj4gKwkJCURSTV9FUlJPUigiZmFpbGVkIHRvIGdldCBsaW5rIHN0YXR1 c1xuIik7Cj4gKwkJCWJyZWFrOwo+ICsJCX0KPiArCj4gKwkJLyogTWFrZSBzdXJlIGNsb2NrIGlz IHN0aWxsIG9rICovCj4gKwkJaWYgKCFkcm1fZHBfY2xvY2tfcmVjb3Zlcnlfb2sobGlua19zdGF0 dXMsCj4gKwkJCQkJICAgICAgZHAtPmxpbmsubnVtX2xhbmVzKSkgewo+ICsJCQlEUk1fREVCVUdf S01TKCJDbG9jayByZWNvdmVyeSBjaGVjayBmYWlsZWRcbiIpOwo+ICsJCQlicmVhazsKPiArCQl9 Cj4gKwo+ICsJCWlmIChkcm1fZHBfY2hhbm5lbF9lcV9vayhsaW5rX3N0YXR1cywgIGRwLT5saW5r Lm51bV9sYW5lcykpIHsKPiArCQkJRFJNX0RFQlVHX0tNUygiQ2hhbm5lbCBFUSBkb25lXG4iKTsK PiArCQkJcmV0dXJuIDA7Cj4gKwkJfQo+ICsKPiArCQkvKiBVcGRhdGUgdHJhaW5pbmcgc2V0IGFz IHJlcXVlc3RlZCBieSB0YXJnZXQgKi8KPiArCQljZG5fZHBfZ2V0X2FkanVzdF90cmFpbihkcCwg bGlua19zdGF0dXMpOwo+ICsJCWlmIChjZG5fZHBfdXBkYXRlX2xpbmtfdHJhaW4oZHApKSB7Cj4g KwkJCURSTV9FUlJPUigiZmFpbGVkIHRvIHVwZGF0ZSBsaW5rIHRyYWluaW5nXG4iKTsKPiArCQkJ YnJlYWs7Cj4gKwkJfQo+ICsJfQo+ICsKPiArCS8qIFRyeSA1IHRpbWVzLCBlbHNlIGZhaWwgYW5k IHRyeSBhdCBsb3dlciBCVyAqLwo+ICsJaWYgKHRyaWVzID09IDUpCj4gKwkJRFJNX0RFQlVHX0tN UygiQ2hhbm5lbCBlcXVhbGl6YXRpb24gZmFpbGVkIDUgdGltZXNcbiIpOwo+ICsKPiArCXJldHVy biAtRUlOVkFMOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGNkbl9kcF9zdG9wX2xpbmtfdHJhaW4o c3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQo+ICt7Cj4gKwlpbnQgcmV0ID0gY2RuX2RwX3NldF9w YXR0ZXJuKGRwLCBEUF9UUkFJTklOR19QQVRURVJOX0RJU0FCTEUpOwo+ICsKPiArCWlmIChyZXQp Cj4gKwkJcmV0dXJuIHJldDsKPiArCj4gKwlyZXR1cm4gY2RuX2RwX3NldF9saW5rX3RyYWluKGRw LCBEUF9UUkFJTklOR19QQVRURVJOX0RJU0FCTEUpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGNk bl9kcF9nZXRfbG93ZXJfbGlua19yYXRlKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCkKPiArewo+ ICsJc3dpdGNoIChkcC0+bGluay5yYXRlKSB7Cj4gKwljYXNlIERQX0xJTktfQldfMV82MjoKPiAr CQlyZXR1cm4gLUVJTlZBTDsKPiArCWNhc2UgRFBfTElOS19CV18yXzc6Cj4gKwkJZHAtPmxpbmsu cmF0ZSA9IERQX0xJTktfQldfMV82MjsKPiArCQlicmVhazsKPiArCWNhc2UgRFBfTElOS19CV181 XzQ6Cj4gKwkJZHAtPmxpbmsucmF0ZSA9IERQX0xJTktfQldfMl83Owo+ICsJCWJyZWFrOwo+ICsJ ZGVmYXVsdDoKPiArCQlkcC0+bGluay5yYXRlID0gRFBfTElOS19CV181XzQ7Cj4gKwkJYnJlYWs7 Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gK2ludCBjZG5fZHBfc29mdHdhcmVf dHJhaW5fbGluayhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApCj4gK3sKPiArCWludCByZXQsIHN0 b3BfZXJyOwo+ICsJdTggbGlua19jb25maWdbMl07Cj4gKwl1MzIgcmF0ZSwgc2lua19tYXgsIHNv dXJjZV9tYXg7Cj4gKwo+ICsJcmV0ID0gZHJtX2RwX2RwY2RfcmVhZCgmZHAtPmF1eCwgRFBfRFBD RF9SRVYsIGRwLT5kcGNkLAo+ICsJCQkgICAgICAgc2l6ZW9mKGRwLT5kcGNkKSk7Cj4gKwlpZiAo cmV0IDwgMCkgewo+ICsJCURSTV9ERVZfRVJST1IoZHAtPmRldiwgIkZhaWxlZCB0byBnZXQgY2Fw cyAlZFxuIiwgcmV0KTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXNvdXJjZV9tYXgg PSBkcC0+bGFuZXM7Cj4gKwlzaW5rX21heCA9IGRybV9kcF9tYXhfbGFuZV9jb3VudChkcC0+ZHBj ZCk7Cj4gKwlkcC0+bGluay5udW1fbGFuZXMgPSBtaW4oc291cmNlX21heCwgc2lua19tYXgpOwo+ ICsKPiArCXNvdXJjZV9tYXggPSBkcm1fZHBfYndfY29kZV90b19saW5rX3JhdGUoQ0ROX0RQX01B WF9MSU5LX1JBVEUpOwo+ICsJc2lua19tYXggPSBkcm1fZHBfbWF4X2xpbmtfcmF0ZShkcC0+ZHBj ZCk7Cj4gKwlyYXRlID0gbWluKHNvdXJjZV9tYXgsIHNpbmtfbWF4KTsKPiArCWRwLT5saW5rLnJh dGUgPSBkcm1fZHBfbGlua19yYXRlX3RvX2J3X2NvZGUocmF0ZSk7Cj4gKwo+ICsJbGlua19jb25m aWdbMF0gPSAwOwo+ICsJbGlua19jb25maWdbMV0gPSAwOwo+ICsJaWYgKGRwLT5kcGNkW0RQX01B SU5fTElOS19DSEFOTkVMX0NPRElOR10gJiAweDAxKQo+ICsJCWxpbmtfY29uZmlnWzFdID0gRFBf U0VUX0FOU0lfOEIxMEI7Cj4gKwlkcm1fZHBfZHBjZF93cml0ZSgmZHAtPmF1eCwgRFBfRE9XTlNQ UkVBRF9DVFJMLCBsaW5rX2NvbmZpZywgMik7Cj4gKwo+ICsJd2hpbGUgKHRydWUpIHsKPiArCj4g KwkJLyogV3JpdGUgdGhlIGxpbmsgY29uZmlndXJhdGlvbiBkYXRhICovCj4gKwkJbGlua19jb25m aWdbMF0gPSBkcC0+bGluay5yYXRlOwo+ICsJCWxpbmtfY29uZmlnWzFdID0gZHAtPmxpbmsubnVt X2xhbmVzOwo+ICsJCWlmIChkcm1fZHBfZW5oYW5jZWRfZnJhbWVfY2FwKGRwLT5kcGNkKSkKPiAr CQkJbGlua19jb25maWdbMV0gfD0gRFBfTEFORV9DT1VOVF9FTkhBTkNFRF9GUkFNRV9FTjsKPiAr CQlkcm1fZHBfZHBjZF93cml0ZSgmZHAtPmF1eCwgRFBfTElOS19CV19TRVQsIGxpbmtfY29uZmln LCAyKTsKPiArCj4gKwkJcmV0ID0gY2RuX2RwX2xpbmtfdHJhaW5pbmdfY2xvY2tfcmVjb3Zlcnko ZHApOwo+ICsJCWlmIChyZXQpIHsKPiArCQkJaWYgKCFjZG5fZHBfZ2V0X2xvd2VyX2xpbmtfcmF0 ZShkcCkpCj4gKwkJCQljb250aW51ZTsKPiArCj4gKwkJCURSTV9FUlJPUigidHJhaW5pbmcgY2xv Y2sgcmVjb3ZlcnkgZmFpbGVkOiAlZFxuIiwgcmV0KTsKPiArCQkJYnJlYWs7Cj4gKwkJfQo+ICsK PiArCQlyZXQgPSBjZG5fZHBfbGlua190cmFpbmluZ19jaGFubmVsX2VxdWFsaXphdGlvbihkcCk7 Cj4gKwkJaWYgKHJldCkgewo+ICsJCQlpZiAoIWNkbl9kcF9nZXRfbG93ZXJfbGlua19yYXRlKGRw KSkKPiArCQkJCWNvbnRpbnVlOwo+ICsKPiArCQkJRFJNX0VSUk9SKCJ0cmFpbmluZyBjaGFubmVs IGVxIGZhaWxlZDogJWRcbiIsIHJldCk7Cj4gKwkJCWJyZWFrOwo+ICsJCX0KPiArCj4gKwkJYnJl YWs7Cj4gKwl9Cj4gKwo+ICsJc3RvcF9lcnIgPSBjZG5fZHBfc3RvcF9saW5rX3RyYWluKGRwKTsK PiArCWlmIChzdG9wX2Vycikgewo+ICsJCURSTV9FUlJPUigic3RvcCB0cmFpbmluZyBmYWlsLCBl cnJvcjogJWRcbiIsIHN0b3BfZXJyKTsKPiArCQlyZXR1cm4gc3RvcF9lcnI7Cj4gKwl9Cj4gKwo+ ICsJcmV0dXJuIHJldDsKPiArfQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vcm9ja2No aXAvY2RuLWRwLXJlZy5jIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1yZWcuYwo+ IGluZGV4IDk3OTM1NWQuLmUxMjczZTYgMTAwNjQ0Cj4gLS0tIGEvZHJpdmVycy9ncHUvZHJtL3Jv Y2tjaGlwL2Nkbi1kcC1yZWcuYwo+ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4t ZHAtcmVnLmMKPiBAQCAtMTcsNyArMTcsOSBAQAo+ICAjaW5jbHVkZSA8bGludXgvZGVsYXkuaD4K PiAgI2luY2x1ZGUgPGxpbnV4L2lvLmg+Cj4gICNpbmNsdWRlIDxsaW51eC9pb3BvbGwuaD4KPiAr I2luY2x1ZGUgPGxpbnV4L3BoeS9waHkuaD4KPiAgI2luY2x1ZGUgPGxpbnV4L3Jlc2V0Lmg+Cj4g KyNpbmNsdWRlIDxzb2Mvcm9ja2NoaXAvcm9ja2NoaXBfcGh5X3R5cGVjLmg+Cj4gIAo+ICAjaW5j bHVkZSAiY2RuLWRwLWNvcmUuaCIKPiAgI2luY2x1ZGUgImNkbi1kcC1yZWcuaCIKPiBAQCAtMTg5 LDcgKzE5MSw3IEBAIHN0YXRpYyBpbnQgY2RuX2RwX21haWxib3hfc2VuZChzdHJ1Y3QgY2RuX2Rw X2RldmljZSAqZHAsIHU4IG1vZHVsZV9pZCwKPiAgCXJldHVybiAwOwo+ICB9Cj4gIAo+IC1zdGF0 aWMgaW50IGNkbl9kcF9yZWdfd3JpdGUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCB1MTYgYWRk ciwgdTMyIHZhbCkKPiAraW50IGNkbl9kcF9yZWdfd3JpdGUoc3RydWN0IGNkbl9kcF9kZXZpY2Ug KmRwLCB1MTYgYWRkciwgdTMyIHZhbCkKPiAgewo+ICAJdTggbXNnWzZdOwo+ICAKPiBAQCAtNjA5 LDYgKzYxMSwzMSBAQCBpbnQgY2RuX2RwX3RyYWluX2xpbmsoc3RydWN0IGNkbl9kcF9kZXZpY2Ug KmRwKQo+ICB7Cj4gIAlpbnQgcmV0Owo+ICAKPiArCS8qCj4gKwkgKiBEUCBmaXJtd2FyZSB1c2Vz IGZpeGVkIHBoeSBjb25maWcgdmFsdWVzIHRvIGRvIHRyYWluaW5nLCBidXQgc29tZQo+ICsJICog Ym9hcmRzIG5lZWQgdG8gYWRqdXN0IHRoZXNlIHZhbHVlcyB0byBmaXQgZm9yIHRoZWlyIHVuaXF1 ZSBoYXJkd2FyZQo+ICsJICogZGVzaWduLiBTbyBpZiB0aGUgcGh5IGlzIHVzaW5nIGN1c3RvbSBj b25maWcgdmFsdWVzLCBkbyBzb2Z0d2FyZQo+ICsJICogbGluayB0cmFpbmluZyBpbnN0ZWFkIG9m IHJlbHlpbmcgb24gZmlybXdhcmUsIGlmIHNvZnR3YXJlIHRyYWluaW5nCj4gKwkgKiBmYWlsLCBr ZWVwIGZpcm13YXJlIHRyYWluaW5nIGFzIGEgZmFsbGJhY2sgaWYgc3cgdHJhaW5pbmcgZmFpbHMu Cj4gKwkgKi8KPiArCXJldCA9IGNkbl9kcF9zb2Z0d2FyZV90cmFpbl9saW5rKGRwKTsKPiArCWlm IChyZXQpIHsKPiArCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsCj4gKwkJCSJGYWlsZWQgdG8gZG8g c29mdHdhcmUgdHJhaW5pbmcgJWRcbiIsIHJldCk7Cj4gKwkJZ290byBkb19md190cmFpbmluZzsK PiArCX0KPiArCXJldCA9IGNkbl9kcF9yZWdfd3JpdGUoZHAsIFNPVVJDRV9IRFRYX0NBUiwgMHhm KTsKPiArCWlmIChyZXQpIHsKPiArCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsCj4gKwkJIkZhaWxl ZCB0byB3cml0ZSBTT1VSQ0VfSERUWF9DQVIgcmVnaXN0ZXIgJWRcbiIsIHJldCk7Cj4gKwkJZ290 byBkb19md190cmFpbmluZzsKPiArCX0KPiArCWRwLT51c2VfZndfdHJhaW5pbmcgPSBmYWxzZTsK PiArCXJldHVybiAwOwo+ICsKPiArZG9fZndfdHJhaW5pbmc6Cj4gKwlkcC0+dXNlX2Z3X3RyYWlu aW5nID0gdHJ1ZTsKPiArCURSTV9ERVZfREVCVUdfS01TKGRwLT5kZXYsICJ1c2UgZncgdHJhaW5p bmdcbiIpOwo+ICAJcmV0ID0gY2RuX2RwX3RyYWluaW5nX3N0YXJ0KGRwKTsKPiAgCWlmIChyZXQp IHsKPiAgCQlEUk1fREVWX0VSUk9SKGRwLT5kZXYsICJGYWlsZWQgdG8gc3RhcnQgdHJhaW5pbmcg JWRcbiIsIHJldCk7Cj4gQEAgLTYyMyw3ICs2NTAsNyBAQCBpbnQgY2RuX2RwX3RyYWluX2xpbmso c3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKQo+ICAKPiAgCURSTV9ERVZfREVCVUdfS01TKGRwLT5k ZXYsICJyYXRlOjB4JXgsIGxhbmVzOiVkXG4iLCBkcC0+bGluay5yYXRlLAo+ICAJCQkgIGRwLT5s aW5rLm51bV9sYW5lcyk7Cj4gLQlyZXR1cm4gcmV0Owo+ICsJcmV0dXJuIDA7Cj4gIH0KPiAgCj4g IGludCBjZG5fZHBfc2V0X3ZpZGVvX3N0YXR1cyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsIGlu dCBhY3RpdmUpCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9yb2NrY2hpcC9jZG4tZHAt cmVnLmggYi9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2RuLWRwLXJlZy5oCj4gaW5kZXggNjU4 MGIxMS4uMzQyMDc3MSAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL2dwdS9kcm0vcm9ja2NoaXAvY2Ru LWRwLXJlZy5oCj4gKysrIGIvZHJpdmVycy9ncHUvZHJtL3JvY2tjaGlwL2Nkbi1kcC1yZWcuaAo+ IEBAIC0xMzcsNyArMTM3LDcgQEAKPiAgI2RlZmluZSBIUERfRVZFTlRfTUFTSwkJCTB4MjExYwo+ ICAjZGVmaW5lIEhQRF9FVkVOVF9ERVQJCQkweDIxMjAKPiAgCj4gLS8qIGRweXggZnJhbWVyIGFk ZHIgKi8KPiArLyogZHB0eCBmcmFtZXIgYWRkciAqLwo+ICAjZGVmaW5lIERQX0ZSQU1FUl9HTE9C QUxfQ09ORklHCQkweDIyMDAKPiAgI2RlZmluZSBEUF9TV19SRVNFVAkJCTB4MjIwNAo+ICAjZGVm aW5lIERQX0ZSQU1FUl9UVQkJCTB4MjIwOAo+IEBAIC00MzEsNiArNDMxLDQwIEBACj4gIC8qIFJl ZmVyZW5jZSBjeWNsZXMgd2hlbiB1c2luZyBsYW5lIGNsb2NrIGFzIHJlZmVyZW5jZSAqLwo+ICAj ZGVmaW5lIExBTkVfUkVGX0NZQwkJCQkweDgwMDAKPiAgCj4gKy8qIHJlZ2lzdGVyIENNX1ZJRF9D VFJMICovCj4gKyNkZWZpbmUgTEFORV9WSURfUkVGX0NZQyh4KSAgICAgICAgICAgICAgICAgICAg KCgoeCkgJiAoQklUKDI0KSAtIDEpKSA8PCAwKQo+ICsjZGVmaW5lIE5NVklEX01FQVNfVE9MRVJB TkNFKHgpICAgICAgICAgICAgICAgICAgICAgICAgKCgoeCkgJiAweGYpIDw8IDI0KQo+ICsKPiAr LyogcmVnaXN0ZXIgRFBfVFhfUEhZX0NPTkZJR19SRUcgKi8KPiArI2RlZmluZSBEUF9UWF9QSFlf VFJBSU5JTkdfRU5BQkxFKHgpICAgICAgICAgICAoKHgpICYgMSkKPiArI2RlZmluZSBEUF9UWF9Q SFlfVFJBSU5JTkdfVFlQRV9QUkJTNyAgICAgICAgICAoMCA8PCAxKQo+ICsjZGVmaW5lIERQX1RY X1BIWV9UUkFJTklOR19UWVBFX1RQUzEgICAgICAgICAgICgxIDw8IDEpCj4gKyNkZWZpbmUgRFBf VFhfUEhZX1RSQUlOSU5HX1RZUEVfVFBTMiAgICAgICAgICAgKDIgPDwgMSkKPiArI2RlZmluZSBE UF9UWF9QSFlfVFJBSU5JTkdfVFlQRV9UUFMzICAgICAgICAgICAoMyA8PCAxKQo+ICsjZGVmaW5l IERQX1RYX1BIWV9UUkFJTklOR19UWVBFX1RQUzQgICAgICAgICAgICg0IDw8IDEpCj4gKyNkZWZp bmUgRFBfVFhfUEhZX1RSQUlOSU5HX1RZUEVfUExUUEFUICAgICAgICAgKDUgPDwgMSkKPiArI2Rl ZmluZSBEUF9UWF9QSFlfVFJBSU5JTkdfVFlQRV9EMTBfMiAgICAgICAgICAoNiA8PCAxKQo+ICsj ZGVmaW5lIERQX1RYX1BIWV9UUkFJTklOR19UWVBFX0hCUjJDUEFUICAgICAgICg4IDw8IDEpCj4g KyNkZWZpbmUgRFBfVFhfUEhZX1RSQUlOSU5HX1BBVFRFUk4oeCkgICAgICAgICAgKCh4KSA8PCAx KQo+ICsjZGVmaW5lIERQX1RYX1BIWV9TQ1JBTUJMRVJfQllQQVNTKHgpICAgICAgICAgICgoKHgp ICYgMSkgPDwgNSkKPiArI2RlZmluZSBEUF9UWF9QSFlfRU5DT0RFUl9CWVBBU1MoeCkgICAgICAg ICAgICAoKCh4KSAmIDEpIDw8IDYpCj4gKyNkZWZpbmUgRFBfVFhfUEhZX1NLRVdfQllQQVNTKHgp ICAgICAgICAgICAgICAgKCgoeCkgJiAxKSA8PCA3KQo+ICsjZGVmaW5lIERQX1RYX1BIWV9ESVNQ QVJJVFlfUlNUKHgpICAgICAgICAgICAgICgoKHgpICYgMSkgPDwgOCkKPiArI2RlZmluZSBEUF9U WF9QSFlfTEFORTBfU0tFVyh4KSAgICAgICAgICAgICAgICAoKCh4KSAmIDcpIDw8IDkpCj4gKyNk ZWZpbmUgRFBfVFhfUEhZX0xBTkUxX1NLRVcoeCkgICAgICAgICAgICAgICAgKCgoeCkgJiA3KSA8 PCAxMikKPiArI2RlZmluZSBEUF9UWF9QSFlfTEFORTJfU0tFVyh4KSAgICAgICAgICAgICAgICAo KCh4KSAmIDcpIDw8IDE1KQo+ICsjZGVmaW5lIERQX1RYX1BIWV9MQU5FM19TS0VXKHgpICAgICAg ICAgICAgICAgICgoKHgpICYgNykgPDwgMTgpCj4gKyNkZWZpbmUgRFBfVFhfUEhZXzEwQklUX0VO QUJMRSh4KSAgICAgICAgICAgICAgKCgoeCkgJiAxKSA8PCAyMSkKPiArCj4gKy8qIHJlZ2lzdGVy IERQX0ZSQU1FUl9HTE9CQUxfQ09ORklHICovCj4gKyNkZWZpbmUgTlVNX0xBTkVTKHgpICAgICAg ICAgICAoKHgpICYgMykKPiArI2RlZmluZSBTU1RfTU9ERSAgICAgICAgICAgICAgICgwIDw8IDIp Cj4gKyNkZWZpbmUgUkdfRU4gICAgICAgICAgICAgICAgICAoMCA8PCA0KQo+ICsjZGVmaW5lIEdM T0JBTF9FTiAgICAgICAgICAgICAgQklUKDMpCj4gKyNkZWZpbmUgTk9fVklERU8gICAgICAgICAg ICAgICBCSVQoNSkKPiArI2RlZmluZSBFTkNfUlNUX0RJUyAgICAgICAgICAgIEJJVCg2KQo+ICsj ZGVmaW5lIFdSX1ZIU1lOQ19GQUxMICAgICAgICAgQklUKDcpCj4gKwo+ICBlbnVtIHZvbHRhZ2Vf c3dpbmdfbGV2ZWwgewo+ICAJVk9MVEFHRV9MRVZFTF8wLAo+ICAJVk9MVEFHRV9MRVZFTF8xLAo+ IEBAIC00NzYsNiArNTEwLDcgQEAgaW50IGNkbl9kcF9zZXRfaG9zdF9jYXAoc3RydWN0IGNkbl9k cF9kZXZpY2UgKmRwLCB1OCBsYW5lcywgYm9vbCBmbGlwKTsKPiAgaW50IGNkbl9kcF9ldmVudF9j b25maWcoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKTsKPiAgdTMyIGNkbl9kcF9nZXRfZXZlbnQo c3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwKTsKPiAgaW50IGNkbl9kcF9nZXRfaHBkX3N0YXR1cyhz dHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApOwo+ICtpbnQgY2RuX2RwX3JlZ193cml0ZShzdHJ1Y3Qg Y2RuX2RwX2RldmljZSAqZHAsIHUxNiBhZGRyLCB1MzIgdmFsKTsKPiAgc3NpemVfdCBjZG5fZHBf ZHBjZF93cml0ZShzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHAsIHUzMiBhZGRyLAo+ICAJCQkgIHU4 ICpkYXRhLCB1MTYgbGVuKTsKPiAgc3NpemVfdCBjZG5fZHBfZHBjZF9yZWFkKHN0cnVjdCBjZG5f ZHBfZGV2aWNlICpkcCwgdTMyIGFkZHIsCj4gQEAgLTQ4OSw0ICs1MjQsNSBAQCBpbnQgY2RuX2Rw X2NvbmZpZ192aWRlbyhzdHJ1Y3QgY2RuX2RwX2RldmljZSAqZHApOwo+ICBpbnQgY2RuX2RwX2F1 ZGlvX3N0b3Aoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCBzdHJ1Y3QgYXVkaW9faW5mbyAqYXVk aW8pOwo+ICBpbnQgY2RuX2RwX2F1ZGlvX211dGUoc3RydWN0IGNkbl9kcF9kZXZpY2UgKmRwLCBi b29sIGVuYWJsZSk7Cj4gIGludCBjZG5fZHBfYXVkaW9fY29uZmlnKHN0cnVjdCBjZG5fZHBfZGV2 aWNlICpkcCwgc3RydWN0IGF1ZGlvX2luZm8gKmF1ZGlvKTsKPiAraW50IGNkbl9kcF9zb2Z0d2Fy ZV90cmFpbl9saW5rKHN0cnVjdCBjZG5fZHBfZGV2aWNlICpkcCk7Cj4gICNlbmRpZiAvKiBfQ0RO X0RQX1JFR19IICovCj4gLS0gCj4gMi43LjQKPiAKCi0tIApTZWFuIFBhdWwsIFNvZnR3YXJlIEVu Z2luZWVyLCBHb29nbGUgLyBDaHJvbWl1bSBPUwpfX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fXwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0 cy5mcmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9s aXN0aW5mby9kcmktZGV2ZWwK From mboxrd@z Thu Jan 1 00:00:00 1970 From: seanpaul@chromium.org (Sean Paul) Date: Thu, 17 May 2018 09:51:36 -0400 Subject: [PATCH v5 4/4] drm/rockchip: support dp training outside dp firmware In-Reply-To: <1526548680-2552-4-git-send-email-hl@rock-chips.com> References: <1526548680-2552-1-git-send-email-hl@rock-chips.com> <1526548680-2552-4-git-send-email-hl@rock-chips.com> Message-ID: <20180517135136.GD3373@art_vandelay> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On Thu, May 17, 2018 at 05:18:00PM +0800, Lin Huang wrote: > DP firmware uses fixed phy config values to do training, but some > boards need to adjust these values to fit for their unique hardware > design. So get phy config values from dts and use software link training > instead of relying on firmware, if software training fail, keep firmware > training as a fallback if sw training fails. > > Signed-off-by: Chris Zhong > Signed-off-by: Lin Huang > --- > Changes in v2: > - update patch following Enric suggest > Changes in v3: > - use variable fw_training instead sw_training_success > - base on DP SPCE, if training fail use lower link rate to retry training > Changes in v4: > - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest > Changes in v5: > - fix some whitespcae issue > > drivers/gpu/drm/rockchip/Makefile | 3 +- > drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- > drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + > drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 ++++++++++++++++++++++++ > drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- > drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- > 6 files changed, 505 insertions(+), 13 deletions(-) > create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c > > diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile > index a314e21..b932f62 100644 > --- a/drivers/gpu/drm/rockchip/Makefile > +++ b/drivers/gpu/drm/rockchip/Makefile > @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ > 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 cdn-dp-reg.o \ > + cdn-dp-link-training.o > rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o > rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o > rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c > index cce64c1..d9d0d4d 100644 > --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c > +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c > @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) > goto out; > } > } > - > - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); > - if (ret) { > - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); > - goto out; > + if (dp->use_fw_training == true) { > + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); > + if (ret) { > + DRM_DEV_ERROR(dp->dev, > + "Failed to idle video %d\n", ret); > + goto out; > + } > } > > ret = cdn_dp_config_video(dp); > @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) > goto out; > } > > - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); > - if (ret) { > - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); > - goto out; > + if (dp->use_fw_training == true) { > + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); > + if (ret) { > + DRM_DEV_ERROR(dp->dev, > + "Failed to valid video %d\n", ret); > + goto out; > + } > } > + > out: > mutex_unlock(&dp->lock); > } > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h > index 46159b2..77a9793 100644 > --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h > +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h > @@ -84,6 +84,7 @@ struct cdn_dp_device { > bool connected; > bool active; > bool suspended; > + bool use_fw_training; > > const struct firmware *fw; /* cdn dp firmware */ > unsigned int fw_version; /* cdn fw version */ > @@ -106,6 +107,7 @@ struct cdn_dp_device { > u8 ports; > u8 lanes; > int active_port; > + u8 train_set[4]; > > u8 dpcd[DP_RECEIVER_CAP_SIZE]; > bool sink_has_audio; > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c > new file mode 100644 > index 0000000..73c3290 > --- /dev/null > +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c > @@ -0,0 +1,420 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd > + * Author: Chris Zhong > + */ > + > +#include > +#include > +#include > +#include > + > +#include "cdn-dp-core.h" > +#include "cdn-dp-reg.h" > + > +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) > +{ > + struct cdn_dp_port *port = dp->port[dp->active_port]; > + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); You ignored Brian's comment on the previous patch: This is still antithetical to the PHY framework; you're assuming that this is a particular type of PHY here. FWIW, the mediatek drm driver also assumes a certain PHY type. A quick grep of drivers/ shows that the only other non-phy/ driver using this function (pinctrl-tegra-xusb.c) also casts it. Sean > + > + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate); > + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >> > + DP_TRAIN_VOLTAGE_SWING_SHIFT; > + u8 pre_emphasis = (dp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) > + >> DP_TRAIN_PRE_EMPHASIS_SHIFT; > + > + tcphy->typec_phy_config(port->phy, rate, dp->link.num_lanes, > + swing, pre_emphasis); > +} > + > +static int cdn_dp_set_pattern(struct cdn_dp_device *dp, uint8_t dp_train_pat) > +{ > + u32 phy_config, global_config; > + int ret; > + uint8_t pattern = dp_train_pat & DP_TRAINING_PATTERN_MASK; > + > + global_config = NUM_LANES(dp->link.num_lanes - 1) | SST_MODE | > + GLOBAL_EN | RG_EN | ENC_RST_DIS | WR_VHSYNC_FALL; > + > + phy_config = DP_TX_PHY_ENCODER_BYPASS(0) | > + DP_TX_PHY_SKEW_BYPASS(0) | > + DP_TX_PHY_DISPARITY_RST(0) | > + DP_TX_PHY_LANE0_SKEW(0) | > + DP_TX_PHY_LANE1_SKEW(1) | > + DP_TX_PHY_LANE2_SKEW(2) | > + DP_TX_PHY_LANE3_SKEW(3) | > + DP_TX_PHY_10BIT_ENABLE(0); > + > + if (pattern != DP_TRAINING_PATTERN_DISABLE) { > + global_config |= NO_VIDEO; > + phy_config |= DP_TX_PHY_TRAINING_ENABLE(1) | > + DP_TX_PHY_SCRAMBLER_BYPASS(1) | > + DP_TX_PHY_TRAINING_PATTERN(pattern); > + } > + > + ret = cdn_dp_reg_write(dp, DP_FRAMER_GLOBAL_CONFIG, global_config); > + if (ret) { > + DRM_ERROR("fail to set DP_FRAMER_GLOBAL_CONFIG, error: %d\n", > + ret); > + return ret; > + } > + > + ret = cdn_dp_reg_write(dp, DP_TX_PHY_CONFIG_REG, phy_config); > + if (ret) { > + DRM_ERROR("fail to set DP_TX_PHY_CONFIG_REG, error: %d\n", > + ret); > + return ret; > + } > + > + ret = cdn_dp_reg_write(dp, DPTX_LANE_EN, BIT(dp->link.num_lanes) - 1); > + if (ret) { > + DRM_ERROR("fail to set DPTX_LANE_EN, error: %d\n", ret); > + return ret; > + } > + > + if (drm_dp_enhanced_frame_cap(dp->dpcd)) > + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 1); > + else > + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 0); > + if (ret) > + DRM_ERROR("failed to set DPTX_ENHNCD, error: %x\n", ret); > + > + return ret; > +} > + > +static u8 cdn_dp_pre_emphasis_max(u8 voltage_swing) > +{ > + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { > + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0: > + return DP_TRAIN_PRE_EMPH_LEVEL_3; > + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1: > + return DP_TRAIN_PRE_EMPH_LEVEL_2; > + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2: > + return DP_TRAIN_PRE_EMPH_LEVEL_1; > + default: > + return DP_TRAIN_PRE_EMPH_LEVEL_0; > + } > +} > + > +static void cdn_dp_get_adjust_train(struct cdn_dp_device *dp, > + uint8_t link_status[DP_LINK_STATUS_SIZE]) > +{ > + int i; > + uint8_t v = 0, p = 0; > + uint8_t preemph_max; > + > + for (i = 0; i < dp->link.num_lanes; i++) { > + v = max(v, drm_dp_get_adjust_request_voltage(link_status, i)); > + p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, > + i)); > + } > + > + if (v >= VOLTAGE_LEVEL_2) > + v = VOLTAGE_LEVEL_2 | DP_TRAIN_MAX_SWING_REACHED; > + > + preemph_max = cdn_dp_pre_emphasis_max(v); > + if (p >= preemph_max) > + p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; > + > + for (i = 0; i < dp->link.num_lanes; i++) > + dp->train_set[i] = v | p; > +} > + > +/* > + * Pick training pattern for channel equalization. Training Pattern 3 for HBR2 > + * or 1.2 devices that support it, Training Pattern 2 otherwise. > + */ > +static u32 cdn_dp_select_chaneq_pattern(struct cdn_dp_device *dp) > +{ > + u32 training_pattern = DP_TRAINING_PATTERN_2; > + > + /* > + * cdn dp support HBR2 also support TPS3. TPS3 support is also mandatory > + * for downstream devices that support HBR2. However, not all sinks > + * follow the spec. > + */ > + if (drm_dp_tps3_supported(dp->dpcd)) > + training_pattern = DP_TRAINING_PATTERN_3; > + else > + DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n"); > + > + return training_pattern; > +} > + > + > +static bool cdn_dp_link_max_vswing_reached(struct cdn_dp_device *dp) > +{ > + int lane; > + > + for (lane = 0; lane < dp->link.num_lanes; lane++) > + if ((dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED) == 0) > + return false; > + > + return true; > +} > + > +static int cdn_dp_update_link_train(struct cdn_dp_device *dp) > +{ > + int ret; > + > + cdn_dp_set_signal_levels(dp); > + > + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, > + dp->train_set, dp->link.num_lanes); > + if (ret != dp->link.num_lanes) > + return -EINVAL; > + > + return 0; > +} > + > +static int cdn_dp_set_link_train(struct cdn_dp_device *dp, > + uint8_t dp_train_pat) > +{ > + uint8_t buf[sizeof(dp->train_set) + 1]; > + int ret, len; > + > + buf[0] = dp_train_pat; > + if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) == > + DP_TRAINING_PATTERN_DISABLE) { > + /* don't write DP_TRAINING_LANEx_SET on disable */ > + len = 1; > + } else { > + /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */ > + memcpy(buf + 1, dp->train_set, dp->link.num_lanes); > + len = dp->link.num_lanes + 1; > + } > + > + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_PATTERN_SET, > + buf, len); > + if (ret != len) > + return -EINVAL; > + > + return 0; > +} > + > +static int cdn_dp_reset_link_train(struct cdn_dp_device *dp, > + uint8_t dp_train_pat) > +{ > + int ret; > + > + memset(dp->train_set, 0, sizeof(dp->train_set)); > + > + cdn_dp_set_signal_levels(dp); > + > + ret = cdn_dp_set_pattern(dp, dp_train_pat); > + if (ret) > + return ret; > + > + return cdn_dp_set_link_train(dp, dp_train_pat); > +} > + > +/* Enable corresponding port and start training pattern 1 */ > +static int cdn_dp_link_training_clock_recovery(struct cdn_dp_device *dp) > +{ > + u8 voltage; > + u8 link_status[DP_LINK_STATUS_SIZE]; > + u32 voltage_tries, max_vswing_tries; > + int ret; > + > + /* clock recovery */ > + ret = cdn_dp_reset_link_train(dp, DP_TRAINING_PATTERN_1 | > + DP_LINK_SCRAMBLING_DISABLE); > + if (ret) { > + DRM_ERROR("failed to start link train\n"); > + return ret; > + } > + > + voltage_tries = 1; > + max_vswing_tries = 0; > + for (;;) { > + drm_dp_link_train_clock_recovery_delay(dp->dpcd); > + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) != > + DP_LINK_STATUS_SIZE) { > + DRM_ERROR("failed to get link status\n"); > + return -EINVAL; > + } > + > + if (drm_dp_clock_recovery_ok(link_status, dp->link.num_lanes)) { > + DRM_DEBUG_KMS("clock recovery OK\n"); > + return 0; > + } > + > + if (voltage_tries >= 5) { > + DRM_DEBUG_KMS("Same voltage tried 5 times\n"); > + return -EINVAL; > + } > + > + if (max_vswing_tries >= 1) { > + DRM_DEBUG_KMS("Max Voltage Swing reached\n"); > + return -EINVAL; > + } > + > + voltage = dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; > + > + /* Update training set as requested by target */ > + cdn_dp_get_adjust_train(dp, link_status); > + if (cdn_dp_update_link_train(dp)) { > + DRM_ERROR("failed to update link training\n"); > + return -EINVAL; > + } > + > + if ((dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == > + voltage) > + ++voltage_tries; > + else > + voltage_tries = 1; > + > + if (cdn_dp_link_max_vswing_reached(dp)) > + ++max_vswing_tries; > + } > +} > + > +static int cdn_dp_link_training_channel_equalization(struct cdn_dp_device *dp) > +{ > + int tries, ret; > + u32 training_pattern; > + uint8_t link_status[DP_LINK_STATUS_SIZE]; > + > + training_pattern = cdn_dp_select_chaneq_pattern(dp); > + training_pattern |= DP_LINK_SCRAMBLING_DISABLE; > + > + ret = cdn_dp_set_pattern(dp, training_pattern); > + if (ret) > + return ret; > + > + ret = cdn_dp_set_link_train(dp, training_pattern); > + if (ret) { > + DRM_ERROR("failed to start channel equalization\n"); > + return ret; > + } > + > + for (tries = 0; tries < 5; tries++) { > + drm_dp_link_train_channel_eq_delay(dp->dpcd); > + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) != > + DP_LINK_STATUS_SIZE) { > + DRM_ERROR("failed to get link status\n"); > + break; > + } > + > + /* Make sure clock is still ok */ > + if (!drm_dp_clock_recovery_ok(link_status, > + dp->link.num_lanes)) { > + DRM_DEBUG_KMS("Clock recovery check failed\n"); > + break; > + } > + > + if (drm_dp_channel_eq_ok(link_status, dp->link.num_lanes)) { > + DRM_DEBUG_KMS("Channel EQ done\n"); > + return 0; > + } > + > + /* Update training set as requested by target */ > + cdn_dp_get_adjust_train(dp, link_status); > + if (cdn_dp_update_link_train(dp)) { > + DRM_ERROR("failed to update link training\n"); > + break; > + } > + } > + > + /* Try 5 times, else fail and try at lower BW */ > + if (tries == 5) > + DRM_DEBUG_KMS("Channel equalization failed 5 times\n"); > + > + return -EINVAL; > +} > + > +static int cdn_dp_stop_link_train(struct cdn_dp_device *dp) > +{ > + int ret = cdn_dp_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE); > + > + if (ret) > + return ret; > + > + return cdn_dp_set_link_train(dp, DP_TRAINING_PATTERN_DISABLE); > +} > + > +static int cdn_dp_get_lower_link_rate(struct cdn_dp_device *dp) > +{ > + switch (dp->link.rate) { > + case DP_LINK_BW_1_62: > + return -EINVAL; > + case DP_LINK_BW_2_7: > + dp->link.rate = DP_LINK_BW_1_62; > + break; > + case DP_LINK_BW_5_4: > + dp->link.rate = DP_LINK_BW_2_7; > + break; > + default: > + dp->link.rate = DP_LINK_BW_5_4; > + break; > + } > + > + return 0; > +} > + > +int cdn_dp_software_train_link(struct cdn_dp_device *dp) > +{ > + int ret, stop_err; > + u8 link_config[2]; > + u32 rate, sink_max, source_max; > + > + ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd, > + sizeof(dp->dpcd)); > + if (ret < 0) { > + DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); > + return ret; > + } > + > + source_max = dp->lanes; > + sink_max = drm_dp_max_lane_count(dp->dpcd); > + dp->link.num_lanes = min(source_max, sink_max); > + > + source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE); > + sink_max = drm_dp_max_link_rate(dp->dpcd); > + rate = min(source_max, sink_max); > + dp->link.rate = drm_dp_link_rate_to_bw_code(rate); > + > + link_config[0] = 0; > + link_config[1] = 0; > + if (dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & 0x01) > + link_config[1] = DP_SET_ANSI_8B10B; > + drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2); > + > + while (true) { > + > + /* Write the link configuration data */ > + link_config[0] = dp->link.rate; > + link_config[1] = dp->link.num_lanes; > + if (drm_dp_enhanced_frame_cap(dp->dpcd)) > + link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; > + drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, link_config, 2); > + > + ret = cdn_dp_link_training_clock_recovery(dp); > + if (ret) { > + if (!cdn_dp_get_lower_link_rate(dp)) > + continue; > + > + DRM_ERROR("training clock recovery failed: %d\n", ret); > + break; > + } > + > + ret = cdn_dp_link_training_channel_equalization(dp); > + if (ret) { > + if (!cdn_dp_get_lower_link_rate(dp)) > + continue; > + > + DRM_ERROR("training channel eq failed: %d\n", ret); > + break; > + } > + > + break; > + } > + > + stop_err = cdn_dp_stop_link_train(dp); > + if (stop_err) { > + DRM_ERROR("stop training fail, error: %d\n", stop_err); > + return stop_err; > + } > + > + return ret; > +} > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c > index 979355d..e1273e6 100644 > --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c > +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c > @@ -17,7 +17,9 @@ > #include > #include > #include > +#include > #include > +#include > > #include "cdn-dp-core.h" > #include "cdn-dp-reg.h" > @@ -189,7 +191,7 @@ static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, > return 0; > } > > -static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) > +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) > { > u8 msg[6]; > > @@ -609,6 +611,31 @@ int cdn_dp_train_link(struct cdn_dp_device *dp) > { > int ret; > > + /* > + * DP firmware uses fixed phy config values to do training, but some > + * boards need to adjust these values to fit for their unique hardware > + * design. So if the phy is using custom config values, do software > + * link training instead of relying on firmware, if software training > + * fail, keep firmware training as a fallback if sw training fails. > + */ > + ret = cdn_dp_software_train_link(dp); > + if (ret) { > + DRM_DEV_ERROR(dp->dev, > + "Failed to do software training %d\n", ret); > + goto do_fw_training; > + } > + ret = cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf); > + if (ret) { > + DRM_DEV_ERROR(dp->dev, > + "Failed to write SOURCE_HDTX_CAR register %d\n", ret); > + goto do_fw_training; > + } > + dp->use_fw_training = false; > + return 0; > + > +do_fw_training: > + dp->use_fw_training = true; > + DRM_DEV_DEBUG_KMS(dp->dev, "use fw training\n"); > ret = cdn_dp_training_start(dp); > if (ret) { > DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); > @@ -623,7 +650,7 @@ int cdn_dp_train_link(struct cdn_dp_device *dp) > > DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate, > dp->link.num_lanes); > - return ret; > + return 0; > } > > int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active) > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h > index 6580b11..3420771 100644 > --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h > +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h > @@ -137,7 +137,7 @@ > #define HPD_EVENT_MASK 0x211c > #define HPD_EVENT_DET 0x2120 > > -/* dpyx framer addr */ > +/* dptx framer addr */ > #define DP_FRAMER_GLOBAL_CONFIG 0x2200 > #define DP_SW_RESET 0x2204 > #define DP_FRAMER_TU 0x2208 > @@ -431,6 +431,40 @@ > /* Reference cycles when using lane clock as reference */ > #define LANE_REF_CYC 0x8000 > > +/* register CM_VID_CTRL */ > +#define LANE_VID_REF_CYC(x) (((x) & (BIT(24) - 1)) << 0) > +#define NMVID_MEAS_TOLERANCE(x) (((x) & 0xf) << 24) > + > +/* register DP_TX_PHY_CONFIG_REG */ > +#define DP_TX_PHY_TRAINING_ENABLE(x) ((x) & 1) > +#define DP_TX_PHY_TRAINING_TYPE_PRBS7 (0 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_TPS1 (1 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_TPS2 (2 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_TPS3 (3 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_TPS4 (4 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_PLTPAT (5 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_D10_2 (6 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_HBR2CPAT (8 << 1) > +#define DP_TX_PHY_TRAINING_PATTERN(x) ((x) << 1) > +#define DP_TX_PHY_SCRAMBLER_BYPASS(x) (((x) & 1) << 5) > +#define DP_TX_PHY_ENCODER_BYPASS(x) (((x) & 1) << 6) > +#define DP_TX_PHY_SKEW_BYPASS(x) (((x) & 1) << 7) > +#define DP_TX_PHY_DISPARITY_RST(x) (((x) & 1) << 8) > +#define DP_TX_PHY_LANE0_SKEW(x) (((x) & 7) << 9) > +#define DP_TX_PHY_LANE1_SKEW(x) (((x) & 7) << 12) > +#define DP_TX_PHY_LANE2_SKEW(x) (((x) & 7) << 15) > +#define DP_TX_PHY_LANE3_SKEW(x) (((x) & 7) << 18) > +#define DP_TX_PHY_10BIT_ENABLE(x) (((x) & 1) << 21) > + > +/* register DP_FRAMER_GLOBAL_CONFIG */ > +#define NUM_LANES(x) ((x) & 3) > +#define SST_MODE (0 << 2) > +#define RG_EN (0 << 4) > +#define GLOBAL_EN BIT(3) > +#define NO_VIDEO BIT(5) > +#define ENC_RST_DIS BIT(6) > +#define WR_VHSYNC_FALL BIT(7) > + > enum voltage_swing_level { > VOLTAGE_LEVEL_0, > VOLTAGE_LEVEL_1, > @@ -476,6 +510,7 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip); > int cdn_dp_event_config(struct cdn_dp_device *dp); > u32 cdn_dp_get_event(struct cdn_dp_device *dp); > int cdn_dp_get_hpd_status(struct cdn_dp_device *dp); > +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val); > ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, > u8 *data, u16 len); > ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, > @@ -489,4 +524,5 @@ int cdn_dp_config_video(struct cdn_dp_device *dp); > int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio); > int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable); > int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio); > +int cdn_dp_software_train_link(struct cdn_dp_device *dp); > #endif /* _CDN_DP_REG_H */ > -- > 2.7.4 > -- Sean Paul, Software Engineer, Google / Chromium OS From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752307AbeEQNvk (ORCPT ); Thu, 17 May 2018 09:51:40 -0400 Received: from mail-yb0-f196.google.com ([209.85.213.196]:35473 "EHLO mail-yb0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752276AbeEQNvj (ORCPT ); Thu, 17 May 2018 09:51:39 -0400 X-Google-Smtp-Source: AB8JxZqsOKJuhB9bGGXpL7QDeK15kqgD72VzxcAbpoyi30N/jikjJLxSPLB0c9F2KbP1V6IhVwUHPw== Date: Thu, 17 May 2018 09:51:36 -0400 From: Sean Paul To: Lin Huang Cc: seanpaul@chromium.org, airlied@linux.ie, zyw@rock-chips.com, dianders@chromium.org, briannorris@chromium.org, linux-rockchip@lists.infradead.org, heiko@sntech.de, daniel.vetter@intel.com, jani.nikula@linux.intel.com, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, eballetbo@gmail.com, robh+dt@kernel.org, devicetree@vger.kernel.org Subject: Re: [PATCH v5 4/4] drm/rockchip: support dp training outside dp firmware Message-ID: <20180517135136.GD3373@art_vandelay> References: <1526548680-2552-1-git-send-email-hl@rock-chips.com> <1526548680-2552-4-git-send-email-hl@rock-chips.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1526548680-2552-4-git-send-email-hl@rock-chips.com> User-Agent: Mutt/1.9.2 (2017-12-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Thu, May 17, 2018 at 05:18:00PM +0800, Lin Huang wrote: > DP firmware uses fixed phy config values to do training, but some > boards need to adjust these values to fit for their unique hardware > design. So get phy config values from dts and use software link training > instead of relying on firmware, if software training fail, keep firmware > training as a fallback if sw training fails. > > Signed-off-by: Chris Zhong > Signed-off-by: Lin Huang > --- > Changes in v2: > - update patch following Enric suggest > Changes in v3: > - use variable fw_training instead sw_training_success > - base on DP SPCE, if training fail use lower link rate to retry training > Changes in v4: > - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest > Changes in v5: > - fix some whitespcae issue > > drivers/gpu/drm/rockchip/Makefile | 3 +- > drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- > drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + > drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 ++++++++++++++++++++++++ > drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- > drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- > 6 files changed, 505 insertions(+), 13 deletions(-) > create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c > > diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile > index a314e21..b932f62 100644 > --- a/drivers/gpu/drm/rockchip/Makefile > +++ b/drivers/gpu/drm/rockchip/Makefile > @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ > 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 cdn-dp-reg.o \ > + cdn-dp-link-training.o > rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o > rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o > rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c > index cce64c1..d9d0d4d 100644 > --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c > +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c > @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) > goto out; > } > } > - > - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); > - if (ret) { > - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); > - goto out; > + if (dp->use_fw_training == true) { > + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); > + if (ret) { > + DRM_DEV_ERROR(dp->dev, > + "Failed to idle video %d\n", ret); > + goto out; > + } > } > > ret = cdn_dp_config_video(dp); > @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) > goto out; > } > > - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); > - if (ret) { > - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); > - goto out; > + if (dp->use_fw_training == true) { > + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); > + if (ret) { > + DRM_DEV_ERROR(dp->dev, > + "Failed to valid video %d\n", ret); > + goto out; > + } > } > + > out: > mutex_unlock(&dp->lock); > } > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h > index 46159b2..77a9793 100644 > --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h > +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h > @@ -84,6 +84,7 @@ struct cdn_dp_device { > bool connected; > bool active; > bool suspended; > + bool use_fw_training; > > const struct firmware *fw; /* cdn dp firmware */ > unsigned int fw_version; /* cdn fw version */ > @@ -106,6 +107,7 @@ struct cdn_dp_device { > u8 ports; > u8 lanes; > int active_port; > + u8 train_set[4]; > > u8 dpcd[DP_RECEIVER_CAP_SIZE]; > bool sink_has_audio; > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c > new file mode 100644 > index 0000000..73c3290 > --- /dev/null > +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c > @@ -0,0 +1,420 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd > + * Author: Chris Zhong > + */ > + > +#include > +#include > +#include > +#include > + > +#include "cdn-dp-core.h" > +#include "cdn-dp-reg.h" > + > +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) > +{ > + struct cdn_dp_port *port = dp->port[dp->active_port]; > + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); You ignored Brian's comment on the previous patch: This is still antithetical to the PHY framework; you're assuming that this is a particular type of PHY here. FWIW, the mediatek drm driver also assumes a certain PHY type. A quick grep of drivers/ shows that the only other non-phy/ driver using this function (pinctrl-tegra-xusb.c) also casts it. Sean > + > + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate); > + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >> > + DP_TRAIN_VOLTAGE_SWING_SHIFT; > + u8 pre_emphasis = (dp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) > + >> DP_TRAIN_PRE_EMPHASIS_SHIFT; > + > + tcphy->typec_phy_config(port->phy, rate, dp->link.num_lanes, > + swing, pre_emphasis); > +} > + > +static int cdn_dp_set_pattern(struct cdn_dp_device *dp, uint8_t dp_train_pat) > +{ > + u32 phy_config, global_config; > + int ret; > + uint8_t pattern = dp_train_pat & DP_TRAINING_PATTERN_MASK; > + > + global_config = NUM_LANES(dp->link.num_lanes - 1) | SST_MODE | > + GLOBAL_EN | RG_EN | ENC_RST_DIS | WR_VHSYNC_FALL; > + > + phy_config = DP_TX_PHY_ENCODER_BYPASS(0) | > + DP_TX_PHY_SKEW_BYPASS(0) | > + DP_TX_PHY_DISPARITY_RST(0) | > + DP_TX_PHY_LANE0_SKEW(0) | > + DP_TX_PHY_LANE1_SKEW(1) | > + DP_TX_PHY_LANE2_SKEW(2) | > + DP_TX_PHY_LANE3_SKEW(3) | > + DP_TX_PHY_10BIT_ENABLE(0); > + > + if (pattern != DP_TRAINING_PATTERN_DISABLE) { > + global_config |= NO_VIDEO; > + phy_config |= DP_TX_PHY_TRAINING_ENABLE(1) | > + DP_TX_PHY_SCRAMBLER_BYPASS(1) | > + DP_TX_PHY_TRAINING_PATTERN(pattern); > + } > + > + ret = cdn_dp_reg_write(dp, DP_FRAMER_GLOBAL_CONFIG, global_config); > + if (ret) { > + DRM_ERROR("fail to set DP_FRAMER_GLOBAL_CONFIG, error: %d\n", > + ret); > + return ret; > + } > + > + ret = cdn_dp_reg_write(dp, DP_TX_PHY_CONFIG_REG, phy_config); > + if (ret) { > + DRM_ERROR("fail to set DP_TX_PHY_CONFIG_REG, error: %d\n", > + ret); > + return ret; > + } > + > + ret = cdn_dp_reg_write(dp, DPTX_LANE_EN, BIT(dp->link.num_lanes) - 1); > + if (ret) { > + DRM_ERROR("fail to set DPTX_LANE_EN, error: %d\n", ret); > + return ret; > + } > + > + if (drm_dp_enhanced_frame_cap(dp->dpcd)) > + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 1); > + else > + ret = cdn_dp_reg_write(dp, DPTX_ENHNCD, 0); > + if (ret) > + DRM_ERROR("failed to set DPTX_ENHNCD, error: %x\n", ret); > + > + return ret; > +} > + > +static u8 cdn_dp_pre_emphasis_max(u8 voltage_swing) > +{ > + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { > + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0: > + return DP_TRAIN_PRE_EMPH_LEVEL_3; > + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1: > + return DP_TRAIN_PRE_EMPH_LEVEL_2; > + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2: > + return DP_TRAIN_PRE_EMPH_LEVEL_1; > + default: > + return DP_TRAIN_PRE_EMPH_LEVEL_0; > + } > +} > + > +static void cdn_dp_get_adjust_train(struct cdn_dp_device *dp, > + uint8_t link_status[DP_LINK_STATUS_SIZE]) > +{ > + int i; > + uint8_t v = 0, p = 0; > + uint8_t preemph_max; > + > + for (i = 0; i < dp->link.num_lanes; i++) { > + v = max(v, drm_dp_get_adjust_request_voltage(link_status, i)); > + p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, > + i)); > + } > + > + if (v >= VOLTAGE_LEVEL_2) > + v = VOLTAGE_LEVEL_2 | DP_TRAIN_MAX_SWING_REACHED; > + > + preemph_max = cdn_dp_pre_emphasis_max(v); > + if (p >= preemph_max) > + p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; > + > + for (i = 0; i < dp->link.num_lanes; i++) > + dp->train_set[i] = v | p; > +} > + > +/* > + * Pick training pattern for channel equalization. Training Pattern 3 for HBR2 > + * or 1.2 devices that support it, Training Pattern 2 otherwise. > + */ > +static u32 cdn_dp_select_chaneq_pattern(struct cdn_dp_device *dp) > +{ > + u32 training_pattern = DP_TRAINING_PATTERN_2; > + > + /* > + * cdn dp support HBR2 also support TPS3. TPS3 support is also mandatory > + * for downstream devices that support HBR2. However, not all sinks > + * follow the spec. > + */ > + if (drm_dp_tps3_supported(dp->dpcd)) > + training_pattern = DP_TRAINING_PATTERN_3; > + else > + DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n"); > + > + return training_pattern; > +} > + > + > +static bool cdn_dp_link_max_vswing_reached(struct cdn_dp_device *dp) > +{ > + int lane; > + > + for (lane = 0; lane < dp->link.num_lanes; lane++) > + if ((dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED) == 0) > + return false; > + > + return true; > +} > + > +static int cdn_dp_update_link_train(struct cdn_dp_device *dp) > +{ > + int ret; > + > + cdn_dp_set_signal_levels(dp); > + > + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, > + dp->train_set, dp->link.num_lanes); > + if (ret != dp->link.num_lanes) > + return -EINVAL; > + > + return 0; > +} > + > +static int cdn_dp_set_link_train(struct cdn_dp_device *dp, > + uint8_t dp_train_pat) > +{ > + uint8_t buf[sizeof(dp->train_set) + 1]; > + int ret, len; > + > + buf[0] = dp_train_pat; > + if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) == > + DP_TRAINING_PATTERN_DISABLE) { > + /* don't write DP_TRAINING_LANEx_SET on disable */ > + len = 1; > + } else { > + /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */ > + memcpy(buf + 1, dp->train_set, dp->link.num_lanes); > + len = dp->link.num_lanes + 1; > + } > + > + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_PATTERN_SET, > + buf, len); > + if (ret != len) > + return -EINVAL; > + > + return 0; > +} > + > +static int cdn_dp_reset_link_train(struct cdn_dp_device *dp, > + uint8_t dp_train_pat) > +{ > + int ret; > + > + memset(dp->train_set, 0, sizeof(dp->train_set)); > + > + cdn_dp_set_signal_levels(dp); > + > + ret = cdn_dp_set_pattern(dp, dp_train_pat); > + if (ret) > + return ret; > + > + return cdn_dp_set_link_train(dp, dp_train_pat); > +} > + > +/* Enable corresponding port and start training pattern 1 */ > +static int cdn_dp_link_training_clock_recovery(struct cdn_dp_device *dp) > +{ > + u8 voltage; > + u8 link_status[DP_LINK_STATUS_SIZE]; > + u32 voltage_tries, max_vswing_tries; > + int ret; > + > + /* clock recovery */ > + ret = cdn_dp_reset_link_train(dp, DP_TRAINING_PATTERN_1 | > + DP_LINK_SCRAMBLING_DISABLE); > + if (ret) { > + DRM_ERROR("failed to start link train\n"); > + return ret; > + } > + > + voltage_tries = 1; > + max_vswing_tries = 0; > + for (;;) { > + drm_dp_link_train_clock_recovery_delay(dp->dpcd); > + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) != > + DP_LINK_STATUS_SIZE) { > + DRM_ERROR("failed to get link status\n"); > + return -EINVAL; > + } > + > + if (drm_dp_clock_recovery_ok(link_status, dp->link.num_lanes)) { > + DRM_DEBUG_KMS("clock recovery OK\n"); > + return 0; > + } > + > + if (voltage_tries >= 5) { > + DRM_DEBUG_KMS("Same voltage tried 5 times\n"); > + return -EINVAL; > + } > + > + if (max_vswing_tries >= 1) { > + DRM_DEBUG_KMS("Max Voltage Swing reached\n"); > + return -EINVAL; > + } > + > + voltage = dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; > + > + /* Update training set as requested by target */ > + cdn_dp_get_adjust_train(dp, link_status); > + if (cdn_dp_update_link_train(dp)) { > + DRM_ERROR("failed to update link training\n"); > + return -EINVAL; > + } > + > + if ((dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == > + voltage) > + ++voltage_tries; > + else > + voltage_tries = 1; > + > + if (cdn_dp_link_max_vswing_reached(dp)) > + ++max_vswing_tries; > + } > +} > + > +static int cdn_dp_link_training_channel_equalization(struct cdn_dp_device *dp) > +{ > + int tries, ret; > + u32 training_pattern; > + uint8_t link_status[DP_LINK_STATUS_SIZE]; > + > + training_pattern = cdn_dp_select_chaneq_pattern(dp); > + training_pattern |= DP_LINK_SCRAMBLING_DISABLE; > + > + ret = cdn_dp_set_pattern(dp, training_pattern); > + if (ret) > + return ret; > + > + ret = cdn_dp_set_link_train(dp, training_pattern); > + if (ret) { > + DRM_ERROR("failed to start channel equalization\n"); > + return ret; > + } > + > + for (tries = 0; tries < 5; tries++) { > + drm_dp_link_train_channel_eq_delay(dp->dpcd); > + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) != > + DP_LINK_STATUS_SIZE) { > + DRM_ERROR("failed to get link status\n"); > + break; > + } > + > + /* Make sure clock is still ok */ > + if (!drm_dp_clock_recovery_ok(link_status, > + dp->link.num_lanes)) { > + DRM_DEBUG_KMS("Clock recovery check failed\n"); > + break; > + } > + > + if (drm_dp_channel_eq_ok(link_status, dp->link.num_lanes)) { > + DRM_DEBUG_KMS("Channel EQ done\n"); > + return 0; > + } > + > + /* Update training set as requested by target */ > + cdn_dp_get_adjust_train(dp, link_status); > + if (cdn_dp_update_link_train(dp)) { > + DRM_ERROR("failed to update link training\n"); > + break; > + } > + } > + > + /* Try 5 times, else fail and try at lower BW */ > + if (tries == 5) > + DRM_DEBUG_KMS("Channel equalization failed 5 times\n"); > + > + return -EINVAL; > +} > + > +static int cdn_dp_stop_link_train(struct cdn_dp_device *dp) > +{ > + int ret = cdn_dp_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE); > + > + if (ret) > + return ret; > + > + return cdn_dp_set_link_train(dp, DP_TRAINING_PATTERN_DISABLE); > +} > + > +static int cdn_dp_get_lower_link_rate(struct cdn_dp_device *dp) > +{ > + switch (dp->link.rate) { > + case DP_LINK_BW_1_62: > + return -EINVAL; > + case DP_LINK_BW_2_7: > + dp->link.rate = DP_LINK_BW_1_62; > + break; > + case DP_LINK_BW_5_4: > + dp->link.rate = DP_LINK_BW_2_7; > + break; > + default: > + dp->link.rate = DP_LINK_BW_5_4; > + break; > + } > + > + return 0; > +} > + > +int cdn_dp_software_train_link(struct cdn_dp_device *dp) > +{ > + int ret, stop_err; > + u8 link_config[2]; > + u32 rate, sink_max, source_max; > + > + ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd, > + sizeof(dp->dpcd)); > + if (ret < 0) { > + DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); > + return ret; > + } > + > + source_max = dp->lanes; > + sink_max = drm_dp_max_lane_count(dp->dpcd); > + dp->link.num_lanes = min(source_max, sink_max); > + > + source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE); > + sink_max = drm_dp_max_link_rate(dp->dpcd); > + rate = min(source_max, sink_max); > + dp->link.rate = drm_dp_link_rate_to_bw_code(rate); > + > + link_config[0] = 0; > + link_config[1] = 0; > + if (dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & 0x01) > + link_config[1] = DP_SET_ANSI_8B10B; > + drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2); > + > + while (true) { > + > + /* Write the link configuration data */ > + link_config[0] = dp->link.rate; > + link_config[1] = dp->link.num_lanes; > + if (drm_dp_enhanced_frame_cap(dp->dpcd)) > + link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; > + drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, link_config, 2); > + > + ret = cdn_dp_link_training_clock_recovery(dp); > + if (ret) { > + if (!cdn_dp_get_lower_link_rate(dp)) > + continue; > + > + DRM_ERROR("training clock recovery failed: %d\n", ret); > + break; > + } > + > + ret = cdn_dp_link_training_channel_equalization(dp); > + if (ret) { > + if (!cdn_dp_get_lower_link_rate(dp)) > + continue; > + > + DRM_ERROR("training channel eq failed: %d\n", ret); > + break; > + } > + > + break; > + } > + > + stop_err = cdn_dp_stop_link_train(dp); > + if (stop_err) { > + DRM_ERROR("stop training fail, error: %d\n", stop_err); > + return stop_err; > + } > + > + return ret; > +} > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c > index 979355d..e1273e6 100644 > --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c > +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c > @@ -17,7 +17,9 @@ > #include > #include > #include > +#include > #include > +#include > > #include "cdn-dp-core.h" > #include "cdn-dp-reg.h" > @@ -189,7 +191,7 @@ static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, > return 0; > } > > -static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) > +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) > { > u8 msg[6]; > > @@ -609,6 +611,31 @@ int cdn_dp_train_link(struct cdn_dp_device *dp) > { > int ret; > > + /* > + * DP firmware uses fixed phy config values to do training, but some > + * boards need to adjust these values to fit for their unique hardware > + * design. So if the phy is using custom config values, do software > + * link training instead of relying on firmware, if software training > + * fail, keep firmware training as a fallback if sw training fails. > + */ > + ret = cdn_dp_software_train_link(dp); > + if (ret) { > + DRM_DEV_ERROR(dp->dev, > + "Failed to do software training %d\n", ret); > + goto do_fw_training; > + } > + ret = cdn_dp_reg_write(dp, SOURCE_HDTX_CAR, 0xf); > + if (ret) { > + DRM_DEV_ERROR(dp->dev, > + "Failed to write SOURCE_HDTX_CAR register %d\n", ret); > + goto do_fw_training; > + } > + dp->use_fw_training = false; > + return 0; > + > +do_fw_training: > + dp->use_fw_training = true; > + DRM_DEV_DEBUG_KMS(dp->dev, "use fw training\n"); > ret = cdn_dp_training_start(dp); > if (ret) { > DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); > @@ -623,7 +650,7 @@ int cdn_dp_train_link(struct cdn_dp_device *dp) > > DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate, > dp->link.num_lanes); > - return ret; > + return 0; > } > > int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active) > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h > index 6580b11..3420771 100644 > --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h > +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h > @@ -137,7 +137,7 @@ > #define HPD_EVENT_MASK 0x211c > #define HPD_EVENT_DET 0x2120 > > -/* dpyx framer addr */ > +/* dptx framer addr */ > #define DP_FRAMER_GLOBAL_CONFIG 0x2200 > #define DP_SW_RESET 0x2204 > #define DP_FRAMER_TU 0x2208 > @@ -431,6 +431,40 @@ > /* Reference cycles when using lane clock as reference */ > #define LANE_REF_CYC 0x8000 > > +/* register CM_VID_CTRL */ > +#define LANE_VID_REF_CYC(x) (((x) & (BIT(24) - 1)) << 0) > +#define NMVID_MEAS_TOLERANCE(x) (((x) & 0xf) << 24) > + > +/* register DP_TX_PHY_CONFIG_REG */ > +#define DP_TX_PHY_TRAINING_ENABLE(x) ((x) & 1) > +#define DP_TX_PHY_TRAINING_TYPE_PRBS7 (0 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_TPS1 (1 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_TPS2 (2 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_TPS3 (3 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_TPS4 (4 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_PLTPAT (5 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_D10_2 (6 << 1) > +#define DP_TX_PHY_TRAINING_TYPE_HBR2CPAT (8 << 1) > +#define DP_TX_PHY_TRAINING_PATTERN(x) ((x) << 1) > +#define DP_TX_PHY_SCRAMBLER_BYPASS(x) (((x) & 1) << 5) > +#define DP_TX_PHY_ENCODER_BYPASS(x) (((x) & 1) << 6) > +#define DP_TX_PHY_SKEW_BYPASS(x) (((x) & 1) << 7) > +#define DP_TX_PHY_DISPARITY_RST(x) (((x) & 1) << 8) > +#define DP_TX_PHY_LANE0_SKEW(x) (((x) & 7) << 9) > +#define DP_TX_PHY_LANE1_SKEW(x) (((x) & 7) << 12) > +#define DP_TX_PHY_LANE2_SKEW(x) (((x) & 7) << 15) > +#define DP_TX_PHY_LANE3_SKEW(x) (((x) & 7) << 18) > +#define DP_TX_PHY_10BIT_ENABLE(x) (((x) & 1) << 21) > + > +/* register DP_FRAMER_GLOBAL_CONFIG */ > +#define NUM_LANES(x) ((x) & 3) > +#define SST_MODE (0 << 2) > +#define RG_EN (0 << 4) > +#define GLOBAL_EN BIT(3) > +#define NO_VIDEO BIT(5) > +#define ENC_RST_DIS BIT(6) > +#define WR_VHSYNC_FALL BIT(7) > + > enum voltage_swing_level { > VOLTAGE_LEVEL_0, > VOLTAGE_LEVEL_1, > @@ -476,6 +510,7 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip); > int cdn_dp_event_config(struct cdn_dp_device *dp); > u32 cdn_dp_get_event(struct cdn_dp_device *dp); > int cdn_dp_get_hpd_status(struct cdn_dp_device *dp); > +int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val); > ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, > u8 *data, u16 len); > ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, > @@ -489,4 +524,5 @@ int cdn_dp_config_video(struct cdn_dp_device *dp); > int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio); > int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable); > int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio); > +int cdn_dp_software_train_link(struct cdn_dp_device *dp); > #endif /* _CDN_DP_REG_H */ > -- > 2.7.4 > -- Sean Paul, Software Engineer, Google / Chromium OS