From mboxrd@z Thu Jan 1 00:00:00 1970 From: Chanwoo Choi Subject: Re: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc Date: Mon, 01 Aug 2016 19:28:21 +0900 Message-ID: <579F2445.1020200@samsung.com> References: <1469779021-10426-1-git-send-email-hl@rock-chips.com> <1469779021-10426-7-git-send-email-hl@rock-chips.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: In-reply-to: <1469779021-10426-7-git-send-email-hl-TNX95d0MmH7DzftRWevZcw@public.gmane.org> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+glpar-linux-rockchip=m.gmane.org-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org To: Lin Huang , heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org Cc: tixy-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org, typ-TNX95d0MmH7DzftRWevZcw@public.gmane.org, airlied-cv59FeDIM0c@public.gmane.org, mturquette-rdvid1DuHRBWk0Htik3J/w@public.gmane.org, dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org, sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org, dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org, myungjoo.ham-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, mark.yao-TNX95d0MmH7DzftRWevZcw@public.gmane.org List-Id: linux-rockchip.vger.kernel.org SGkgTGluLAoKQXMgSSBtZW50aW9uZWQgb24gcGF0Y2g1LCB5b3UgYmV0dGVyIHRvIG1ha2UgdGhl IGRvY3VtZW50YXRpb24gYXMgZm9sbG93aW5nOiAKLSBEb2N1bWVudGF0aW9uL2RldmljZXRyZWUv YmluZGluZ3MvZGV2ZnJlcS9yazMzOTlfZG1jLnR4dApBbmQsIEkgYWRkIHRoZSBjb21tZW50cy4K CgpPbiAyMDE264WEIDA37JuUIDI57J28IDE2OjU3LCBMaW4gSHVhbmcgd3JvdGU6Cj4gYmFzZSBv biBkZmkgcmVzdWx0LCB3ZSBkbyBkZHIgZnJlcXVlbmN5IHNjYWxpbmcsIHJlZ2lzdGVyCj4gZG1j IGRyaXZlciB0byBkZXZmcmVxIGZyYW1ld29yaywgYW5kIHVzZSBzaW1wbGUtb25kZW1hbmQKPiBw b2xpY3kuCj4gCj4gU2lnbmVkLW9mZi1ieTogTGluIEh1YW5nIDxobEByb2NrLWNoaXBzLmNvbT4K PiAtLS0KPiBDaGFuZ2VzIGluIHY0Ogo+IC0gdXNlIGFybV9zbWNjY19zbWMoKSBmdW5jdGlvbiB0 YWxrIHRvIGJsMzEKPiAtIGRlbGV0ZSByb2NrY2hpcF9kbWMuYyBmaWxlIGFuZCBjb25maWcKPiAt IGRlbGV0ZSBkbWNfbm90aWZ5Cj4gLSBhZGp1c3QgcHJvYmUgb3JkZXIKPiAgCj4gQ2hhbmdlcyBp biB2MzoKPiAtIG9wZXJhdGUgZHJhbSBzZXR0aW5nIHRocm91Z2ggc2lwIGNhbGwKPiAtIGltcG9y dmUgc2V0IHJhdGUgZmxvdwo+IAo+IENoYW5nZXMgaW4gdjI6Cj4gLSBOb25lCj4gIAo+IENoYW5n ZXMgaW4gdjE6Cj4gLSBtb3ZlIGRmaSBjb250cm9sbGVyIHRvIGV2ZW50Cj4gLSBmaXggc2V0IHZv bHRhZ2Ugc2VxdWVuY2Ugd2hlbiBzZXQgcmF0ZSBmYWlsCj4gLSBjaGFuZ2UgS2NvbmZpZyB0eXBl IGZyb20gdHJpc3RhdGUgdG8gYm9vbAo+IC0gbW92ZSB1bnVzZSBFWFBPUlRfU1lNQk9MX0dQTCgp Cj4gCj4gIGRyaXZlcnMvZGV2ZnJlcS9LY29uZmlnICAgICAgICAgICAgICAgfCAgIDEgKwo+ICBk cml2ZXJzL2RldmZyZXEvTWFrZWZpbGUgICAgICAgICAgICAgIHwgICAxICsKPiAgZHJpdmVycy9k ZXZmcmVxL3JvY2tjaGlwL0tjb25maWcgICAgICB8ICAgOCArCj4gIGRyaXZlcnMvZGV2ZnJlcS9y b2NrY2hpcC9NYWtlZmlsZSAgICAgfCAgIDEgKwo+ICBkcml2ZXJzL2RldmZyZXEvcm9ja2NoaXAv cmszMzk5X2RtYy5jIHwgNDczICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKPiAg NSBmaWxlcyBjaGFuZ2VkLCA0ODQgaW5zZXJ0aW9ucygrKQo+ICBjcmVhdGUgbW9kZSAxMDA2NDQg ZHJpdmVycy9kZXZmcmVxL3JvY2tjaGlwL0tjb25maWcKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRy aXZlcnMvZGV2ZnJlcS9yb2NrY2hpcC9NYWtlZmlsZQo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJp dmVycy9kZXZmcmVxL3JvY2tjaGlwL3JrMzM5OV9kbWMuYwo+IAo+IGRpZmYgLS1naXQgYS9kcml2 ZXJzL2RldmZyZXEvS2NvbmZpZyBiL2RyaXZlcnMvZGV2ZnJlcS9LY29uZmlnCj4gaW5kZXggNjQy ODFiYi4uYWNiMmE1NyAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL2RldmZyZXEvS2NvbmZpZwo+ICsr KyBiL2RyaXZlcnMvZGV2ZnJlcS9LY29uZmlnCj4gQEAgLTk5LDUgKzk5LDYgQEAgY29uZmlnIEFS TV9URUdSQV9ERVZGUkVRCj4gICAgICAgICAgIG9wZXJhdGluZyBmcmVxdWVuY2llcyBhbmQgdm9s dGFnZXMgd2l0aCBPUFAgc3VwcG9ydC4KPiAgCj4gIHNvdXJjZSAiZHJpdmVycy9kZXZmcmVxL2V2 ZW50L0tjb25maWciCj4gK3NvdXJjZSAiZHJpdmVycy9kZXZmcmVxL3JvY2tjaGlwL0tjb25maWci CgpUaGlzIHBhdGNoIGluY2x1ZGUgdGhlIG9ubHkgb25lIHBhdGNoLiBTbywgSSB0aGluayB0aGF0 CnlvdSBkb24ndCBuZWVkIHRvIGNyZWF0ZSB0aGUgJ3JvY2tjaGlwJyBkaXJlY3RvcnkuCgo+ICAK PiAgZW5kaWYgIyBQTV9ERVZGUkVRCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZGV2ZnJlcS9NYWtl ZmlsZSBiL2RyaXZlcnMvZGV2ZnJlcS9NYWtlZmlsZQo+IGluZGV4IDUxMzRmOWUuLmQ4NDRlMjMg MTAwNjQ0Cj4gLS0tIGEvZHJpdmVycy9kZXZmcmVxL01ha2VmaWxlCj4gKysrIGIvZHJpdmVycy9k ZXZmcmVxL01ha2VmaWxlCj4gQEAgLTksNiArOSw3IEBAIG9iai0kKENPTkZJR19ERVZGUkVRX0dP Vl9VU0VSU1BBQ0UpCSs9IGdvdmVybm9yX3VzZXJzcGFjZS5vCj4gIG9iai0kKENPTkZJR19BUk1f RVhZTk9TNF9CVVNfREVWRlJFUSkJKz0gZXh5bm9zLwo+ICBvYmotJChDT05GSUdfQVJNX0VYWU5P UzVfQlVTX0RFVkZSRVEpCSs9IGV4eW5vcy8KPiAgb2JqLSQoQ09ORklHX0FSTV9URUdSQV9ERVZG UkVRKQkJKz0gdGVncmEtZGV2ZnJlcS5vCj4gK29iai0kKENPTkZJR19BUkNIX1JPQ0tDSElQKQkJ Kz0gcm9ja2NoaXAvCgpkaXR0by4KCj4gIAo+ICAjIERFVkZSRVEgRXZlbnQgRHJpdmVycwo+ICBv YmotJChDT05GSUdfUE1fREVWRlJFUV9FVkVOVCkJCSs9IGV2ZW50Lwo+IGRpZmYgLS1naXQgYS9k cml2ZXJzL2RldmZyZXEvcm9ja2NoaXAvS2NvbmZpZyBiL2RyaXZlcnMvZGV2ZnJlcS9yb2NrY2hp cC9LY29uZmlnCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwLi5kOGY5ZTY2 Cj4gLS0tIC9kZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvZGV2ZnJlcS9yb2NrY2hpcC9LY29uZmln Cj4gQEAgLTAsMCArMSw4IEBACj4gK2NvbmZpZyBBUk1fUkszMzk5X0RNQ19ERVZGUkVRCj4gKwl0 cmlzdGF0ZSAiQVJNIFJLMzM5OSBETUMgREVWRlJFUSBEcml2ZXIiCj4gKwlzZWxlY3QgUE1fT1BQ Cj4gKwlzZWxlY3QgREVWRlJFUV9HT1ZfU0lNUExFX09OREVNQU5ECj4gKwloZWxwCj4gKyAgICAg ICAgICBUaGlzIGFkZHMgdGhlIERFVkZSRVEgZHJpdmVyIGZvciB0aGUgUkszMzk5IGRtYy4gSXQg c2V0cyB0aGUgZnJlcXVlbmN5CgpJZiB5b3UgYWRkIHRoZSBmdWxsIGRlc2NyaXB0aW9uIGZvciAn ZG1jJyBhcyBmb2xsb3dpbmcsCml0IGlzIGVhc3kgdG8gdW5kZXJzdGFuZCB0aGUgb3BlcmF0aW9u IG9mIHRoaXMgZGV2aWNlIGRyaXZlci4KLSBETUMgKER5bmFtaWMgTWVtb3J5IENvbnRyb2xsZXIp Cgo+ICsgICAgICAgICAgZm9yIHRoZSBtZW1vcnkgY29udHJvbGxlciBhbmQgcmVhZHMgdGhlIHVz YWdlIGNvdW50cyBmcm9tIGhhcmR3YXJlLgo+ICsKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9kZXZm cmVxL3JvY2tjaGlwL01ha2VmaWxlIGIvZHJpdmVycy9kZXZmcmVxL3JvY2tjaGlwL01ha2VmaWxl Cj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwLi5jNjJjMTA1Cj4gLS0tIC9k ZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvZGV2ZnJlcS9yb2NrY2hpcC9NYWtlZmlsZQo+IEBAIC0w LDAgKzEgQEAKPiArb2JqLSQoQ09ORklHX0FSTV9SSzMzOTlfRE1DX0RFVkZSRVEpCSs9IHJrMzM5 OV9kbWMubwo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2RldmZyZXEvcm9ja2NoaXAvcmszMzk5X2Rt Yy5jIGIvZHJpdmVycy9kZXZmcmVxL3JvY2tjaGlwL3JrMzM5OV9kbWMuYwo+IG5ldyBmaWxlIG1v ZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMC4uNTI3YWExMQo+IC0tLSAvZGV2L251bGwKPiArKysg Yi9kcml2ZXJzL2RldmZyZXEvcm9ja2NoaXAvcmszMzk5X2RtYy5jCj4gQEAgLTAsMCArMSw0NzMg QEAKPiArLyoKPiArICogQ29weXJpZ2h0IChjKSAyMDE2LCBGdXpob3UgUm9ja2NoaXAgRWxlY3Ry b25pY3MgQ28uLCBMdGQKCllvdSBtaXNzIHRoZSAnLicgYXQgdGhlIGVuZCBvZiB0aGUgY29weWxp Z2h0LiAKV2hlbiB5b3UgdXNlIGFuIGFiYnJldmlhdGlvbiwgeW91IHNob3VsZCBhZGQgJy4nIGZv ciBMdGQuCi0gcy9MdGQvTHRkLgoKCj4gKyAqIEF1dGhvcjogTGluIEh1YW5nIDxobEByb2NrLWNo aXBzLmNvbT4KPiArICoKPiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBj YW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXQKPiArICogdW5kZXIgdGhlIHRlcm1z IGFuZCBjb25kaXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSwKPiArICog dmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbi4K PiArICoKPiArICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIGl0IHdp bGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVAo+ICsgKiBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZl biB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFkgb3IKPiArICogRklUTkVT UyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBM aWNlbnNlIGZvcgo+ICsgKiBtb3JlIGRldGFpbHMuCj4gKyAqLwo+ICsKPiArI2luY2x1ZGUgPGxp bnV4L2FybS1zbWNjYy5oPgo+ICsjaW5jbHVkZSA8bGludXgvY2xrLmg+Cj4gKyNpbmNsdWRlIDxs aW51eC9jb21wbGV0aW9uLmg+CgpZb3UgZG9uJ3QgbmVlZCB0byBpbmNsdWRlIHRoZSAiY29tcGxl dGlvbi5oIi4KV2l0aG91dCAiY29tcGxldGlvbi5oIiwgdGhlIGJ1aWxkIGlzIHdvcmtpbmcuCgo+ ICsjaW5jbHVkZSA8bGludXgvZGVsYXkuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2RldmZyZXEuaD4K PiArI2luY2x1ZGUgPGxpbnV4L2RldmZyZXEtZXZlbnQuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2lu dGVycnVwdC5oPgo+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+Cj4gKyNpbmNsdWRlIDxsaW51 eC9vZi5oPgo+ICsjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1fZGV2aWNlLmg+Cj4gKyNpbmNsdWRl IDxsaW51eC9wbV9vcHAuaD4KPiArI2luY2x1ZGUgPGxpbnV4L3JlZ3VsYXRvci9jb25zdW1lci5o Pgo+ICsjaW5jbHVkZSA8bGludXgvcndzZW0uaD4KPiArI2luY2x1ZGUgPGxpbnV4L3N1c3BlbmQu aD4KPiArI2luY2x1ZGUgPGxpbnV4L3N5c2NvcmVfb3BzLmg+CgpZb3UgZG9uJ3QgbmVlZCB0byBp bmNsdWRlIHRoZSAic3lzY29yZV9vcHMuaCIuCldpdGhvdXQgInN5c2NvcmVfb3BzLmgiLCB0aGUg YnVpbGQgaXMgd29ya2luZy4KCj4gKwo+ICsjaW5jbHVkZSA8c29jL3JvY2tjaGlwL3JvY2tjaGlw X3NpcC5oPgo+ICsKPiArc3RydWN0IGRyYW1fdGltaW5nIHsKPiArCXVuc2lnbmVkIGludCBkZHIz X3NwZWVkX2JpbjsKPiArCXVuc2lnbmVkIGludCBwZF9pZGxlOwo+ICsJdW5zaWduZWQgaW50IHNy X2lkbGU7Cj4gKwl1bnNpZ25lZCBpbnQgc3JfbWNfZ2F0ZV9pZGxlOwo+ICsJdW5zaWduZWQgaW50 IHNycGRfbGl0ZV9pZGxlOwo+ICsJdW5zaWduZWQgaW50IHN0YW5kYnlfaWRsZTsKPiArCXVuc2ln bmVkIGludCBkcmFtX2RsbF9kaXNfZnJlcTsKPiArCXVuc2lnbmVkIGludCBwaHlfZGxsX2Rpc19m cmVxOwo+ICsJdW5zaWduZWQgaW50IGRkcjNfb2R0X2Rpc19mcmVxOwo+ICsJdW5zaWduZWQgaW50 IGRkcjNfZHJ2Owo+ICsJdW5zaWduZWQgaW50IGRkcjNfb2R0Owo+ICsJdW5zaWduZWQgaW50IHBo eV9kZHIzX2NhX2RydjsKPiArCXVuc2lnbmVkIGludCBwaHlfZGRyM19kcV9kcnY7Cj4gKwl1bnNp Z25lZCBpbnQgcGh5X2RkcjNfb2R0Owo+ICsJdW5zaWduZWQgaW50IGxwZGRyM19vZHRfZGlzX2Zy ZXE7Cj4gKwl1bnNpZ25lZCBpbnQgbHBkZHIzX2RydjsKPiArCXVuc2lnbmVkIGludCBscGRkcjNf b2R0Owo+ICsJdW5zaWduZWQgaW50IHBoeV9scGRkcjNfY2FfZHJ2Owo+ICsJdW5zaWduZWQgaW50 IHBoeV9scGRkcjNfZHFfZHJ2Owo+ICsJdW5zaWduZWQgaW50IHBoeV9scGRkcjNfb2R0Owo+ICsJ dW5zaWduZWQgaW50IGxwZGRyNF9vZHRfZGlzX2ZyZXE7Cj4gKwl1bnNpZ25lZCBpbnQgbHBkZHI0 X2RydjsKPiArCXVuc2lnbmVkIGludCBscGRkcjRfZHFfb2R0Owo+ICsJdW5zaWduZWQgaW50IGxw ZGRyNF9jYV9vZHQ7Cj4gKwl1bnNpZ25lZCBpbnQgcGh5X2xwZGRyNF9jYV9kcnY7Cj4gKwl1bnNp Z25lZCBpbnQgcGh5X2xwZGRyNF9ja19jc19kcnY7Cj4gKwl1bnNpZ25lZCBpbnQgcGh5X2xwZGRy NF9kcV9kcnY7Cj4gKwl1bnNpZ25lZCBpbnQgcGh5X2xwZGRyNF9vZHQ7Cj4gK307CgpUaGUgZHJh bV90aW1pbmcgaXMgdXNlZCBmb3IgU01DIChTZWN1cmUgTW9uaXRvciBDYWxsKT8gCkkgcmVjb21t ZW5kIHRoYXQgeW91IGFkZCB0aGUgZGV0YWlsZWQgZGVzY3JpcHRpb24gYWJvdXQgdGhpcyBwcm9w ZXJ0eQpvbiBEb2N1bWVudGF0aW9uLgoKPiArCj4gK3N0cnVjdCByazMzOTlfZG1jZnJlcSB7Cj4g KwlzdHJ1Y3QgZGV2aWNlICpkZXY7Cj4gKwlzdHJ1Y3QgZGV2ZnJlcSAqZGV2ZnJlcTsKPiArCXN0 cnVjdCBkZXZmcmVxX3NpbXBsZV9vbmRlbWFuZF9kYXRhIG9uZGVtYW5kX2RhdGE7Cj4gKwlzdHJ1 Y3QgY2xrICpkbWNfY2xrOwo+ICsJc3RydWN0IGRldmZyZXFfZXZlbnRfZGV2ICplZGV2Owo+ICsJ c3RydWN0IG11dGV4IGxvY2s7Cj4gKwlzdHJ1Y3QgZHJhbV90aW1pbmcgKnRpbWluZzsKPiArCXdh aXRfcXVldWVfaGVhZF90CXdhaXRfZGNmX3F1ZXVlOwo+ICsJaW50IGlycTsKPiArCWludCB3YWl0 X2RjZl9mbGFnOwoKSSB3YW50IHRvIGFkZCB0aGUgZnVsbCBuYW1lIGFuZCBkZXNjcmlwdGlvbiBv ZiAnZGNmJy4KSXQgaXMgdW5rbm93biB3b3JkLgoKPiArCXN0cnVjdCByZWd1bGF0b3IgKnZkZF9j ZW50ZXI7Cj4gKwl1bnNpZ25lZCBsb25nIHJhdGUsIHRhcmdldF9yYXRlOwo+ICsJdW5zaWduZWQg bG9uZyB2b2x0LCB0YXJnZXRfdm9sdDsKCkkgdGhpbmsgdGhhdCBpZiB5b3UgYWRkICdjdXJyX29w cCcgdmFyaWFibGUsCnlvdSBjYW4gcmVkdWNlIHRoZSBjYWxsaW5nIG9mIGRldmZyZXFfcmVjb21t ZW5kZWRfb3BwKCkgaW4gcmszMzk5X2RtY2ZyZXFfdGFyZ2V0KCkKCXN0cnVjdCBkZXZfcG1fb3Bw ICpjdXJyX29wcDsKCj4gK307Cj4gKwo+ICtzdGF0aWMgaW50IHJrMzM5OV9kbWNmcmVxX3Rhcmdl dChzdHJ1Y3QgZGV2aWNlICpkZXYsIHVuc2lnbmVkIGxvbmcgKmZyZXEsCj4gKwkJCQkgdTMyIGZs YWdzKQo+ICt7Cj4gKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2ID0gY29udGFpbmVyX29m KGRldiwgc3RydWN0IHBsYXRmb3JtX2RldmljZSwKPiArCQkJCQkJICAgIGRldik7Cj4gKwlzdHJ1 Y3QgcmszMzk5X2RtY2ZyZXEgKmRtY2ZyZXEgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsK CllvdSBjYW4gdXNlIHRoZSAnZGV2X2dldF9kcnZkYXRhKCknIHRvIHNpbXBsaWZ5IGl0IGluc3Rl YWQgb2YgJ3BsYXRmb3JtX2dldF9kcnZkYXRhKCknLgoKCXN0cnVjdCByazMzOTlfZG1jZnJlcSAq ZG1jZnJlcSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwoKPiArCXN0cnVjdCBkZXZfcG1fb3BwICpv cHA7Cj4gKwl1bnNpZ25lZCBsb25nIG9sZF9jbGtfcmF0ZSA9IGRtY2ZyZXEtPnJhdGU7Cj4gKwl1 bnNpZ25lZCBsb25nIHRhcmdldF92b2x0LCB0YXJnZXRfcmF0ZTsKPiArCWludCBlcnI7Cj4gKwo+ ICsJcmN1X3JlYWRfbG9jaygpOwo+ICsJb3BwID0gZGV2ZnJlcV9yZWNvbW1lbmRlZF9vcHAoZGV2 LCBmcmVxLCBmbGFncyk7Cj4gKwlpZiAoSVNfRVJSKG9wcCkpIHsKPiArCQlyY3VfcmVhZF91bmxv Y2soKTsKPiArCQlyZXR1cm4gUFRSX0VSUihvcHApOwo+ICsJfQo+ICsKPiArCXRhcmdldF9yYXRl ID0gZGV2X3BtX29wcF9nZXRfZnJlcShvcHApOwo+ICsJdGFyZ2V0X3ZvbHQgPSBkZXZfcG1fb3Bw X2dldF92b2x0YWdlKG9wcCk7Cj4gKwlvcHAgPSBkZXZmcmVxX3JlY29tbWVuZGVkX29wcChkZXYs ICZkbWNmcmVxLT5yYXRlLCBmbGFncyk7Cj4gKwlpZiAoSVNfRVJSKG9wcCkpIHsKPiArCQlyY3Vf cmVhZF91bmxvY2soKTsKPiArCQlyZXR1cm4gUFRSX0VSUihvcHApOwo+ICsJfQo+ICsJZG1jZnJl cS0+dm9sdCA9IGRldl9wbV9vcHBfZ2V0X3ZvbHRhZ2Uob3BwKTsKCklmIHlvdSBhZGQgdGhlICdj dXJyX29wcCcgdmFyaWFibGUgdG8gc3RydWN0IHJrMzM5OV9kbWNmcmVxLAp5b3UgY2FuIHJlbW92 ZSB0aGUgY2FsbGluZyBvZiBkZXZmcmVxX3JlY29tbWVuZGVkX29wcCgpLgoJZG1jZnJlcS0+cmF0 ZSA9IGRldl9wbV9vcHBfZ2V0X2ZyZXEoZG1jZnJlcS0+Y3Vycl9vcHApOwoJZG1jZnJlcS0+dm9s dCA9IGRldl9wbV9vcHBfZ2V0X2ZyZXEoZG1jZnJlcS0+Y3Vycl9vcHApOwoKQmVjYXVzZSB0aGUg Y3VycmVudCByYXRlIGFuZCB2b2x0YWdlIGlzIGFscmVhZHkgZGVjaWRlZCBvbiBwcmV2aW91cyBw b2xsaW5nIGN5Y2xlLApTbyB3ZSBkb24ndCBuZWVkIHRvIGdldCB0aGUgb3BwIHdpdGggZGV2ZnJl cV9yZWNvbW1lbmRlZF9vcHAoKS4KCj4gKwlyY3VfcmVhZF91bmxvY2soKTsKPiArCj4gKwlpZiAo ZG1jZnJlcS0+cmF0ZSA9PSB0YXJnZXRfcmF0ZSkKPiArCQlyZXR1cm4gMDsKPiArCj4gKwltdXRl eF9sb2NrKCZkbWNmcmVxLT5sb2NrKTsKPiArCj4gKwkvKgo+ICsJICogaWYgZnJlcXVlbmN5IHNj YWxpbmcgZnJvbSBsb3cgdG8gaGlnaCwgYWRqdXN0IHZvbHRhZ2UgZmlyc3Q7Cj4gKwkgKiBpZiBm cmVxdWVuY3kgc2NhbGluZyBmcm9tIGhpZ2ggdG8gbG93LCBhZGp1c2V0IGZyZXF1ZW5jeSBmaXJz dDsKPiArCSAqLwoKcy9hZGp1c2V0L2FkanVzdAoKSSByZWNvbW1lbmQgdGhhdCB5b3UgdXNlIGEg Y2FwdGl0YWwgbGV0dGVyIGZvciBmaXJzdCBjaGFyYWN0ZXIgYW5kIHVzZSB0aGUgJy4nCmluc3Rl YWQgb2YgJzsnLgoKPiArCWlmIChvbGRfY2xrX3JhdGUgPCB0YXJnZXRfcmF0ZSkgewo+ICsJCWVy ciA9IHJlZ3VsYXRvcl9zZXRfdm9sdGFnZShkbWNmcmVxLT52ZGRfY2VudGVyLCB0YXJnZXRfdm9s dCwKPiArCQkJCQkgICAgdGFyZ2V0X3ZvbHQpOwo+ICsJCWlmIChlcnIpIHsKPiArCQkJZGV2X2Vy cihkZXYsICJVbmFibGUgdG8gc2V0IHZvbCAlbHVcbiIsIHRhcmdldF92b2x0KTsKClRvIHJlYWRh YmlsaXR5LCB5b3UgYmV0dGVyIHRvIHVzZSB0aGUgY29ycmVudCB3b3JkIHRvIHBhc3MgdGhlIHBy ZWNpc2UgdGhlIGxvZyBtZXNzYWdlLgotIHMvdm9sL3ZvbHRhZ2UKCkFuZCwgdGhpcyBwYXRjaCB1 c2VzIHRoZSAnVW5hYmxlIHRvJyBvciAnQ2Fubm90JyB0byBzaG93IHRoZSBlcnJvciBsb2cuCkkg cmVjb21tZW5kIHRoYXQgeW91IHVzZSB0aGUgY29uc2lzdGVudCBleHByZXNzaW9uIGlmIHRoZXJl IGlzIG5vdCBhbnkgc3BlY2lmaWMgcmVhc29uLgoKCWRldl9lcnIoZGV2LCAiQ2Fubm90IHNldCB0 aGUgdm9sdGFnZSAlbHUgdVZcbiIsIHRhcmdldF92b2x0KTsKCj4gKwkJCWdvdG8gb3V0Owo+ICsJ CX0KPiArCX0KPiArCWRtY2ZyZXEtPndhaXRfZGNmX2ZsYWcgPSAxOwo+ICsJZXJyID0gY2xrX3Nl dF9yYXRlKGRtY2ZyZXEtPmRtY19jbGssIHRhcmdldF9yYXRlKTsKPiArCWlmIChlcnIpIHsKPiAr CQlkZXZfZXJyKGRldiwKPiArCQkJIlVuYWJsZSB0byBzZXQgZnJlcSAlbHUuIEN1cnJlbnQgZnJl cSAlbHUuIEVycm9yICVkXG4iLAo+ICsJCQl0YXJnZXRfcmF0ZSwgb2xkX2Nsa19yYXRlLCBlcnIp OwoKCWRldl9lcnIoZGV2LCAiQ2Fubm90IHNldCB0aGUgZnJlcXVlbmN5ICVsdSAoJWQpXG4iLCB0 YXJnZXRfcmF0ZSwgZXJyKTsKCj4gKwkJcmVndWxhdG9yX3NldF92b2x0YWdlKGRtY2ZyZXEtPnZk ZF9jZW50ZXIsIGRtY2ZyZXEtPnZvbHQsCj4gKwkJCQkgICAgICBkbWNmcmVxLT52b2x0KTsKPiAr CQlnb3RvIG91dDsKPiArCX0KPiArCj4gKwkvKgo+ICsJICogd2FpdCB1bnRpbCBiY2YgaXJxIGhh cHBlbiwgaXQgbWVhbnMgZnJlcSBzY2FsaW5nIGZpbmlzaCBpbiBibDMxLAoKZGl0dG8uCgo+ICsJ ICogdXNlIDEwMG1zIGFzIHRpbWVvdXQgdGltZQoKcy90aW1lL3RpbWUuCgo+ICsJICovCj4gKwlp ZiAoIXdhaXRfZXZlbnRfdGltZW91dChkbWNmcmVxLT53YWl0X2RjZl9xdWV1ZSwKPiArCQkJCSFk bWNmcmVxLT53YWl0X2RjZl9mbGFnLCBIWiAvIDEwKSkKPiArCQlkZXZfd2FybihkZXYsICJUaW1l b3V0IHdhaXRpbmcgZm9yIGRjZiBpcnFcbiIpOwoKSWYgdGhlIHRpbWVvdXQgaGFwcGVuLCBhcmUg dGhlcmUgYW55IHByb2JsZW0/CgpBZnRlciBzZXR0aW5nIHRoZSBmcmVxdWVuY3kgYW5kIHZvbHRh Z2UsIHN0b3JlIHRoZSBjdXJyZW50IG9wcCBlbnRyeSBvbiAuY3Vycl9vcHAuCglkbWNmcmVxLT5j dXJyX29wcCA9IG9wcDsKCj4gKwkvKgo+ICsJICogY2hlY2sgdGhlIGRwbGwgcmF0ZQo+ICsJICog dGhlcmUgb25seSB0d28gcmVzdWx0IHdlIHdpbGwgZ2V0LAo+ICsJICogMS4gZGRyIGZyZXF1ZW5j eSBzY2FsaW5nIGZhaWwsIHdlIHN0aWxsIGdldCB0aGUgb2xkIHJhdGUKPiArCSAqIDIsIGRkciBm cmVxdWVuY3kgc2NhbGluZyBzdWNlc3NmdWwsIHdlIGdldCB0aGUgcmF0ZSB3ZSBzZXQKPiArCSAq Lwo+ICsJZG1jZnJlcS0+cmF0ZSA9IGNsa19nZXRfcmF0ZShkbWNmcmVxLT5kbWNfY2xrKTsKPiAr Cj4gKwkvKiBpZiBnZXQgdGhlIGluY29ycmVjdCByYXRlLCBzZXQgdm9sdGFnZSB0byBvbGQgdmFs dWUgKi8KPiArCWlmIChkbWNmcmVxLT5yYXRlICE9IHRhcmdldF9yYXRlKSB7Cj4gKwkJZGV2X2Vy cihkZXYsICJnZXQgd3JvbmcgZGRyIGZyZXF1ZW5jeSwgUmVxdWVzdCBmcmVxICVsdSxcCj4gKwkJ CUN1cnJlbnQgZnJlcSAlbHVcbiIsIHRhcmdldF9yYXRlLCBkbWNmcmVxLT5yYXRlKTsKPiArCQly ZWd1bGF0b3Jfc2V0X3ZvbHRhZ2UoZG1jZnJlcS0+dmRkX2NlbnRlciwgZG1jZnJlcS0+dm9sdCwK PiArCQkJCSAgICAgIGRtY2ZyZXEtPnZvbHQpOwoKW1dpdGhvdXQgZm9yY2UsIGl0IGlzIGp1c3Qg bXkgb3Bpb24gYWJvdXQgdGhpcyBjb2RlOl0KSSB0aGluayB0aGF0IHRoaXMgY2hlY2tpbmcgY29k ZSBpdCBpcyB1bi1uZWVkZWQuCklmIHRoaXMgY2FzZSBvY2N1ciwgdGhlIHJrMzM5OV9kbWMuYyBu ZXZlciBzZXQgdGhlIHNwZWNpZmljIGZyZXF1ZW5jeQpiZWNhdXNlIHRoZSByazMzOTkgY2xvY2sg ZG9uJ3Qgc3VwcG9ydCB0aGUgc3BlY2lmaWMgZnJlcXVlbmN5IGZvciByazMzOTkgZG1jLgoKSWYg eW91IHdhbnQgdG8gc2V0IHRoZSBjb3JyZWN0IGZyZXF1ZW5jeSwKV2hlbiB2ZXJpZnlpbmcgdGhl IHJrMzM5OSBkbWMgZHJpdmVyLCB5b3Ugc2hvdWxkIGNoZWNrIHRoZSByazMzOTkgY2xvY2sgZHJp dmVyLgoKQmFzaWNhbGx5LCBpZiB0aGUgdGhlIGNsb2NrIGRyaXZlciBkb24ndCBzdXBwb3J0IHRo ZSBjb3JyZWN0IHNhbWUgZnJlcXVlbmN5ICwKQ0NGKENvbW1vbiBDbG9jayBGcmFtZXdvcmspIHNl dCB0aGUgY2xvc2UgZnJlcXVlbmN5LiBJdCBpcyBub3QgYSBiYWQgdGhpbmcuCgoKPiArCX0gZWxz ZSBpZiAob2xkX2Nsa19yYXRlID4gdGFyZ2V0X3JhdGUpCj4gKwkJZXJyID0gcmVndWxhdG9yX3Nl dF92b2x0YWdlKGRtY2ZyZXEtPnZkZF9jZW50ZXIsIHRhcmdldF92b2x0LAo+ICsJCQkJCSAgICB0 YXJnZXRfdm9sdCk7Cj4gKwlpZiAoZXJyKQo+ICsJCWRldl9lcnIoZGV2LCAiVW5hYmxlIHRvIHNl dCB2b2wgJWx1XG4iLCB0YXJnZXRfdm9sdCk7CgkKZGl0dG8uIFlvdSBiZXR0ZXIgdG8gdXNlIHRo ZSBjb25zaXN0ZW50IGV4cHJlc3Npb24gZm9yIGVycm9yIGxvZyBhcyBmb2xsb3dpbmc6CglkZXZf ZXJyKGRldiwgIkNhbm5vdCBzZXQgdGhlIHZvbHRhZ2UgJWx1IHVWXG4iLCB0YXJnZXRfdm9sdCk7 CgoKPiArCj4gK291dDoKPiArCW11dGV4X3VubG9jaygmZG1jZnJlcS0+bG9jayk7Cj4gKwlyZXR1 cm4gZXJyOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHJrMzM5OV9kbWNmcmVxX2dldF9kZXZfc3Rh dHVzKHN0cnVjdCBkZXZpY2UgKmRldiwKPiArCQkJCQkgc3RydWN0IGRldmZyZXFfZGV2X3N0YXR1 cyAqc3RhdCkKPiArewo+ICsJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldiA9IGNvbnRhaW5l cl9vZihkZXYsIHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UsCj4gKwkJCQkJCSAgICBkZXYpOwo+ICsJ c3RydWN0IHJrMzM5OV9kbWNmcmVxICpkbWNmcmVxID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRl dik7Cj4gKwlzdHJ1Y3QgZGV2ZnJlcV9ldmVudF9kYXRhIGVkYXRhOwoKZGl0dG8uIFVzZSB0aGUg ZGV2X2dldF9kcnZkYXRhKGRldikuCgo+ICsKPiArCWRldmZyZXFfZXZlbnRfZ2V0X2V2ZW50KGRt Y2ZyZXEtPmVkZXYsICZlZGF0YSk7CgpZb3UgbmVlZCB0byBjaGVjayB0aGUgcmV0dXJuIHZhbHVl IGZvciBleGNlcHRpb24gaGFuZGxpbmcuCgo+ICsKPiArCXN0YXQtPmN1cnJlbnRfZnJlcXVlbmN5 ID0gZG1jZnJlcS0+cmF0ZTsKPiArCXN0YXQtPmJ1c3lfdGltZSA9IGVkYXRhLmxvYWRfY291bnQ7 Cj4gKwlzdGF0LT50b3RhbF90aW1lID0gZWRhdGEudG90YWxfY291bnQ7Cj4gKwo+ICsJcmV0dXJu IDA7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgcmszMzk5X2RtY2ZyZXFfZ2V0X2N1cl9mcmVxKHN0 cnVjdCBkZXZpY2UgKmRldiwgdW5zaWduZWQgbG9uZyAqZnJlcSkKPiArewo+ICsJc3RydWN0IHBs YXRmb3JtX2RldmljZSAqcGRldiA9IGNvbnRhaW5lcl9vZihkZXYsIHN0cnVjdCBwbGF0Zm9ybV9k ZXZpY2UsCj4gKwkJCQkJCSAgICBkZXYpOwo+ICsJc3RydWN0IHJrMzM5OV9kbWNmcmVxICpkbWNm cmVxID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRldik7CgpkaXR0by4gVXNlIHRoZSBkZXZfZ2V0 X2RydmRhdGEoZGV2KS4KCj4gKwo+ICsJKmZyZXEgPSBkbWNmcmVxLT5yYXRlOwo+ICsKPiArCXJl dHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCByazMzOTlfZG1jZnJlcV9leGl0KHN0cnVj dCBkZXZpY2UgKmRldikKPiArewo+ICsJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldiA9IGNv bnRhaW5lcl9vZihkZXYsCj4gKwkJCQkJCSAgICBzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlLAo+ICsJ CQkJCQkgICAgZGV2KTsKPiArCXN0cnVjdCByazMzOTlfZG1jZnJlcSAqZG1jZnJlcSA9IHBsYXRm b3JtX2dldF9kcnZkYXRhKHBkZXYpOwo+ICsKPiArCWRldmZyZXFfdW5yZWdpc3Rlcl9vcHBfbm90 aWZpZXIoZGV2LCBkbWNmcmVxLT5kZXZmcmVxKTsKClVzZSB0aGUgZGV2bV9kZXZmcmVxX3JlZ2lz dGVyX29wcF9ub3RpZmllcigpLiBZb3UgZG9uJ3QgbmVlZCB0byBoYW5kbGUgaXQuCgo+ICt9Cj4g Kwo+ICtzdGF0aWMgc3RydWN0IGRldmZyZXFfZGV2X3Byb2ZpbGUgcmszMzk5X2RldmZyZXFfZG1j X3Byb2ZpbGUgPSB7Cj4gKwkucG9sbGluZ19tcwk9IDIwMCwKPiArCS50YXJnZXQJCT0gcmszMzk5 X2RtY2ZyZXFfdGFyZ2V0LAo+ICsJLmdldF9kZXZfc3RhdHVzCT0gcmszMzk5X2RtY2ZyZXFfZ2V0 X2Rldl9zdGF0dXMsCj4gKwkuZ2V0X2N1cl9mcmVxCT0gcmszMzk5X2RtY2ZyZXFfZ2V0X2N1cl9m cmVxLAo+ICsJLmV4aXQJCT0gcmszMzk5X2RtY2ZyZXFfZXhpdCwKPiArfTsKPiArCj4gK3N0YXRp YyBfX21heWJlX3VudXNlZCBpbnQgcmszMzk5X2RtY2ZyZXFfc3VzcGVuZChzdHJ1Y3QgZGV2aWNl ICpkZXYpCj4gK3sKPiArCXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYgPSBjb250YWluZXJf b2YoZGV2LAo+ICsJCQkJCQkgICAgc3RydWN0IHBsYXRmb3JtX2RldmljZSwKPiArCQkJCQkJICAg IGRldik7Cj4gKwlzdHJ1Y3QgcmszMzk5X2RtY2ZyZXEgKmRtY2ZyZXEgPSBwbGF0Zm9ybV9nZXRf ZHJ2ZGF0YShwZGV2KTsKCmRpdHRvLiBVc2UgdGhlIGRldl9nZXRfZHJ2ZGF0YShkZXYpLgoKPiAr Cj4gKwlkZXZmcmVxX2V2ZW50X2Rpc2FibGVfZWRldihkbWNmcmVxLT5lZGV2KTsKPiArCWRldmZy ZXFfc3VzcGVuZF9kZXZpY2UoZG1jZnJlcS0+ZGV2ZnJlcSk7CgpkaXR0by4geW91IG5lZWQgdG8g Y2hlY2sgdGhlIHJldHVybiB2YWx1ZS4KCj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gK3N0 YXRpYyBfX21heWJlX3VudXNlZCBpbnQgcmszMzk5X2RtY2ZyZXFfcmVzdW1lKHN0cnVjdCBkZXZp Y2UgKmRldikKPiArewo+ICsJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldiA9IGNvbnRhaW5l cl9vZihkZXYsCj4gKwkJCQkJCSAgICBzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlLAo+ICsJCQkJCQkg ICAgZGV2KTsKPiArCXN0cnVjdCByazMzOTlfZG1jZnJlcSAqZG1jZnJlcSA9IHBsYXRmb3JtX2dl dF9kcnZkYXRhKHBkZXYpOwoKZGl0dG8uCgo+ICsKPiArCWRldmZyZXFfZXZlbnRfZW5hYmxlX2Vk ZXYoZG1jZnJlcS0+ZWRldik7Cj4gKwlkZXZmcmVxX3Jlc3VtZV9kZXZpY2UoZG1jZnJlcS0+ZGV2 ZnJlcSk7CgpkaXR0by4KCj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gK3N0YXRpYyBTSU1Q TEVfREVWX1BNX09QUyhyazMzOTlfZG1jZnJlcV9wbSwgcmszMzk5X2RtY2ZyZXFfc3VzcGVuZCwK PiArCQkJIHJrMzM5OV9kbWNmcmVxX3Jlc3VtZSk7Cj4gKwo+ICtzdGF0aWMgaXJxcmV0dXJuX3Qg cmszMzk5X2RtY19pcnEoaW50IGlycSwgdm9pZCAqZGV2X2lkKQo+ICt7Cj4gKwlzdHJ1Y3Qgcmsz Mzk5X2RtY2ZyZXEgKmRtY2ZyZXEgPSBkZXZfaWQ7Cj4gKwlzdHJ1Y3QgYXJtX3NtY2NjX3JlcyBy ZXM7Cj4gKwo+ICsJZG1jZnJlcS0+d2FpdF9kY2ZfZmxhZyA9IDA7Cj4gKwl3YWtlX3VwKCZkbWNm cmVxLT53YWl0X2RjZl9xdWV1ZSk7Cj4gKwo+ICsJLyogY2xyIGRjZiBpcnEgKi8KCnMvIGNsciBk Y2YgaXJxIC0+ICJDbGVhciB0aGUgRENGIEludGVycnVwdCIKCj4gKwlhcm1fc21jY2Nfc21jKFNJ UF9ERFJfRlJFUSwgMCwgMCwgQ09ORklHX0RSQU1fQ0xSX0lSUSwKPiArCQkgICAgICAwLCAwLCAw LCAwLCAmcmVzKTsKPiArCj4gKwlyZXR1cm4gSVJRX0hBTkRMRUQ7Cj4gK30KPiArCj4gK3N0YXRp YyBpbnQgb2ZfZG9fZ2V0X3RpbWluZyhzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wLAo+ICsJCXN0cnVj dCBkcmFtX3RpbWluZyAqdGltaW5nKQo+ICt7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCXJldCA9IG9m X3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAiZGRyM19zcGVlZF9iaW4iLAo+ICsJCQkJICAgJnRpbWlu Zy0+ZGRyM19zcGVlZF9iaW4pOwo+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAi cGRfaWRsZSIsICZ0aW1pbmctPnBkX2lkbGUpOwo+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRf dTMyKG5wLCAic3JfaWRsZSIsICZ0aW1pbmctPnNyX2lkbGUpOwo+ICsJcmV0IHw9IG9mX3Byb3Bl cnR5X3JlYWRfdTMyKG5wLCAic3JfbWNfZ2F0ZV9pZGxlIiwKPiArCQkJCSAgICAmdGltaW5nLT5z cl9tY19nYXRlX2lkbGUpOwo+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAic3Jw ZF9saXRlX2lkbGUiLAo+ICsJCQkJICAgICZ0aW1pbmctPnNycGRfbGl0ZV9pZGxlKTsKPiArCXJl dCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInN0YW5kYnlfaWRsZSIsICZ0aW1pbmctPnN0 YW5kYnlfaWRsZSk7Cj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJkcmFtX2Rs bF9kaXNfZnJlcSIsCj4gKwkJCQkgICAgJnRpbWluZy0+ZHJhbV9kbGxfZGlzX2ZyZXEpOwo+ICsJ cmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAicGh5X2RsbF9kaXNfZnJlcSIsCj4gKwkJ CQkgICAgJnRpbWluZy0+cGh5X2RsbF9kaXNfZnJlcSk7Cj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlf cmVhZF91MzIobnAsICJkZHIzX29kdF9kaXNfZnJlcSIsCj4gKwkJCQkgICAgJnRpbWluZy0+ZGRy M19vZHRfZGlzX2ZyZXEpOwo+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAiZGRy M19kcnYiLCAmdGltaW5nLT5kZHIzX2Rydik7Cj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91 MzIobnAsICJkZHIzX29kdCIsICZ0aW1pbmctPmRkcjNfb2R0KTsKPiArCXJldCB8PSBvZl9wcm9w ZXJ0eV9yZWFkX3UzMihucCwgInBoeV9kZHIzX2NhX2RydiIsCj4gKwkJCQkgICAgJnRpbWluZy0+ cGh5X2RkcjNfY2FfZHJ2KTsKPiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInBo eV9kZHIzX2RxX2RydiIsCj4gKwkJCQkgICAgJnRpbWluZy0+cGh5X2RkcjNfZHFfZHJ2KTsKPiAr CXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInBoeV9kZHIzX29kdCIsICZ0aW1pbmct PnBoeV9kZHIzX29kdCk7Cj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJscGRk cjNfb2R0X2Rpc19mcmVxIiwKPiArCQkJCSAgICAmdGltaW5nLT5scGRkcjNfb2R0X2Rpc19mcmVx KTsKPiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgImxwZGRyM19kcnYiLCAmdGlt aW5nLT5scGRkcjNfZHJ2KTsKPiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgImxw ZGRyM19vZHQiLCAmdGltaW5nLT5scGRkcjNfb2R0KTsKPiArCXJldCB8PSBvZl9wcm9wZXJ0eV9y ZWFkX3UzMihucCwgInBoeV9scGRkcjNfY2FfZHJ2IiwKPiArCQkJCSAgICAmdGltaW5nLT5waHlf bHBkZHIzX2NhX2Rydik7Cj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJwaHlf bHBkZHIzX2RxX2RydiIsCj4gKwkJCQkgICAgJnRpbWluZy0+cGh5X2xwZGRyM19kcV9kcnYpOwo+ ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAicGh5X2xwZGRyM19vZHQiLAo+ICsJ CQkJICAgICZ0aW1pbmctPnBoeV9scGRkcjNfb2R0KTsKPiArCXJldCB8PSBvZl9wcm9wZXJ0eV9y ZWFkX3UzMihucCwgImxwZGRyNF9vZHRfZGlzX2ZyZXEiLAo+ICsJCQkJICAgICZ0aW1pbmctPmxw ZGRyNF9vZHRfZGlzX2ZyZXEpOwo+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAi bHBkZHI0X2RydiIsCj4gKwkJCQkgICAgJnRpbWluZy0+bHBkZHI0X2Rydik7Cj4gKwlyZXQgfD0g b2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJscGRkcjRfZHFfb2R0IiwKPiArCQkJCSAgICAmdGlt aW5nLT5scGRkcjRfZHFfb2R0KTsKPiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwg ImxwZGRyNF9jYV9vZHQiLAo+ICsJCQkJICAgICZ0aW1pbmctPmxwZGRyNF9jYV9vZHQpOwo+ICsJ cmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAicGh5X2xwZGRyNF9jYV9kcnYiLAo+ICsJ CQkJICAgICZ0aW1pbmctPnBoeV9scGRkcjRfY2FfZHJ2KTsKPiArCXJldCB8PSBvZl9wcm9wZXJ0 eV9yZWFkX3UzMihucCwgInBoeV9scGRkcjRfY2tfY3NfZHJ2IiwKPiArCQkJCSAgICAmdGltaW5n LT5waHlfbHBkZHI0X2NrX2NzX2Rydik7Cj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIo bnAsICJwaHlfbHBkZHI0X2RxX2RydiIsCj4gKwkJCQkgICAgJnRpbWluZy0+cGh5X2xwZGRyNF9k cV9kcnYpOwo+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAicGh5X2xwZGRyNF9v ZHQiLAo+ICsJCQkJICAgICZ0aW1pbmctPnBoeV9scGRkcjRfb2R0KTsKPiArCj4gKwlyZXR1cm4g cmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgc3RydWN0IGRyYW1fdGltaW5nICpvZl9nZXRfZGRyX3Rp bWluZ3Moc3RydWN0IGRldmljZSAqZGV2LAo+ICsJCQkJCSAgICAgIHN0cnVjdCBkZXZpY2Vfbm9k ZSAqbnApCj4gK3sKPiArCXN0cnVjdCBkcmFtX3RpbWluZwkqdGltaW5nID0gTlVMTDsKPiArCXN0 cnVjdCBkZXZpY2Vfbm9kZQkqbnBfdGltOwo+ICsKPiArCW5wX3RpbSA9IG9mX3BhcnNlX3BoYW5k bGUobnAsICJkZHJfdGltaW5nIiwgMCk7CgpBcyBJIGFscmVhZHkgbWVudGlvbmVkLCB5b3UgbmVl ZCB0byBhZGQgdGhlIGRldGFpbGVkIGRvY3VtZXRhdGlvbiBhYm91dCB0aGUgcHJvcGVydHkuCgo+ ICsJaWYgKG5wX3RpbSkgewo+ICsJCXRpbWluZyA9IGRldm1fa3phbGxvYyhkZXYsIHNpemVvZigq dGltaW5nKSwgR0ZQX0tFUk5FTCk7Cj4gKwkJaWYgKCF0aW1pbmcpCj4gKwkJCWdvdG8gZXJyOwo+ ICsJCWlmIChvZl9kb19nZXRfdGltaW5nKG5wX3RpbSwgdGltaW5nKSkgewoKSSByZWNvbW1lbmQg dGhhdCB5b3UgYmV0dGVyIHRvIHNxdWFzaCBmb2xsb3dpbmcgdHdvIGZ1bmN0aW9ucwpiZWNhdXNl IG9mX2RvX2dldF90aW1pbmcoKSBpcyBub3QgdXNlZCBvbiBvdGhlciBwb2ludCBvZiB0aGlzIGRy aXZlci4KLSBvZl9kb19nZXRfdGltaW5nKCkKLSBvZl9nZXRfZGRyX3RpbWluZ3MoKQoKPiArCQkJ ZGV2bV9rZnJlZShkZXYsIHRpbWluZyk7Cj4gKwkJCWdvdG8gZXJyOwo+ICsJCX0KCllvdSdyZSBt aXNzaW5nIHRoZSAnb2Zfbm9kZV9wdXQnLgoJCW9mX25vZGVfcHV0KG5wX3RpbSk7Cgo+ICsJCXJl dHVybiB0aW1pbmc7Cj4gKwl9Cj4gKwo+ICtlcnI6Cj4gKwlpZiAodGltaW5nKSB7Cj4gKwkJZGV2 bV9rZnJlZShkZXYsIHRpbWluZyk7Cj4gKwkJdGltaW5nID0gTlVMTDsKPiArCX0KPiArCgpkaXR0 by4KCW9mX25vZGVfcHV0KG5wX3RpbSk7Cgo+ICsJcmV0dXJuIHRpbWluZzsKPiArfQo+ICsKPiAr c3RhdGljIGludCByazMzOTlfZG1jZnJlcV9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpw ZGV2KQo+ICt7Cj4gKwlzdHJ1Y3QgYXJtX3NtY2NjX3JlcyByZXM7Cj4gKwlzdHJ1Y3QgZGV2aWNl ICpkZXYgPSAmcGRldi0+ZGV2Owo+ICsJc3RydWN0IGRldmljZV9ub2RlICpucCA9IHBkZXYtPmRl di5vZl9ub2RlOwo+ICsJdWludDY0X3QgcGFyYW0gPSAwOwo+ICsJc3RydWN0IHJrMzM5OV9kbWNm cmVxICpkYXRhOwo+ICsJaW50IHJldCwgaXJxLCBpbmRleDsKPiArCXVpbnQzMl90ICp0aW1pbmc7 Cj4gKwo+ICsJaXJxID0gcGxhdGZvcm1fZ2V0X2lycShwZGV2LCAwKTsKPiArCWlmIChpcnEgPCAw KSB7Cj4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAibm8gZG1jIGlycSByZXNvdXJjZVxuIik7CgpX ZSBuZWVkIHRvIG1haW50YWluIHRoZSBjb25zaXN0ZW50IGV4cHJlc3Npb24gZm9yIGVycm9yIGxv Zy4KCQlkZXZfZXJyKCZwZGV2LT5kZXYsICIiQ2Fubm90IGdldCB0aGUgaW50ZXJydXB0IHJlc291 cmNlIlxuIik7CgkJCj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9Cj4gKwlkYXRhID0gZGV2bV9r emFsbG9jKGRldiwgc2l6ZW9mKHN0cnVjdCByazMzOTlfZG1jZnJlcSksIEdGUF9LRVJORUwpOwo+ ICsJaWYgKCFkYXRhKQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiArCW11dGV4X2luaXQoJmRh dGEtPmxvY2spOwo+ICsKPiArCWRhdGEtPnZkZF9jZW50ZXIgPSBkZXZtX3JlZ3VsYXRvcl9nZXQo ZGV2LCAiY2VudGVyIik7Cj4gKwlpZiAoSVNfRVJSKGRhdGEtPnZkZF9jZW50ZXIpKSB7Cj4gKwkJ ZGV2X2VycihkZXYsICJDYW5ub3QgZ2V0IHRoZSByZWd1bGF0b3IgXCJjZW50ZXJcIlxuIik7Cj4g KwkJcmV0dXJuIFBUUl9FUlIoZGF0YS0+dmRkX2NlbnRlcik7Cj4gKwl9Cj4gKwo+ICsJZGF0YS0+ ZG1jX2NsayA9IGRldm1fY2xrX2dldChkZXYsICJkbWNfY2xrIik7Cj4gKwlpZiAoSVNfRVJSKGRh dGEtPmRtY19jbGspKSB7Cj4gKwkJZGV2X2VycihkZXYsICJDYW5ub3QgZ2V0IHRoZSBjbGsgZG1j X2Nsa1xuIik7Cj4gKwkJcmV0dXJuIFBUUl9FUlIoZGF0YS0+ZG1jX2Nsayk7Cj4gKwl9Owo+ICsK PiArCWRhdGEtPmlycSA9IGlycTsKPiArCXJldCA9IGRldm1fcmVxdWVzdF9pcnEoZGV2LCBpcnEs IHJrMzM5OV9kbWNfaXJxLCAwLAo+ICsJCQkgICAgICAgZGV2X25hbWUoZGV2KSwgZGF0YSk7Cj4g KwlpZiAocmV0KSB7Cj4gKwkJZGV2X2VycihkZXYsICJmYWlsZWQgdG8gcmVxdWVzdCBkbWMgaXJx OiAlZFxuIiwgcmV0KTsKCmRpdHRvLiAiRmFpbGVkIHRvIHJlcXVlc3QgdGhlIGRtYyBpcnEiIG9y ICJDYW5ub3QgcmVxdWVzdCB0aGUgZG1jIGlycSIKCj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiAr Cj4gKwkvKiBnZXQgZHJhbSB0aW1pbmcgYW5kIHBhc3MgaXQgdG8gYmwzMSAqLwoKSSB3YW50IHRv IGFkZCB0aGUgbW9yZSBkZXRhaWxlZCBkZXNjcmlwdGlvbiB3aHkgdGhpcyBjb2RlIGlzIG5lY2Vz c2FyeS4KQmVjYXVzZSB0aGUgU01DIGlzIHVzdWFsbHkgYmxhY2sgYm94LiBTbywgSWYgeW91IGFk ZCB0aGUgbW9yZSBleHBsYW5hdGlvbiwKaXQgaGVscCBwZW9wbGUgdG8gdW5kZXJzdGFuZCB0aGlz IGNvZGUuIAoKPiArCWRhdGEtPnRpbWluZyA9IG9mX2dldF9kZHJfdGltaW5ncyhkZXYsIG5wKTsK PiArCWlmIChkYXRhLT50aW1pbmcpIHsKPiArCQl0aW1pbmcgPSAodWludDMyX3QgKilkYXRhLT50 aW1pbmc7Cj4gKwkJZm9yIChpbmRleCA9IDA7IGluZGV4IDwgKHNpemVvZihzdHJ1Y3QgZHJhbV90 aW1pbmcpIC8gNCk7Cj4gKwkJICAgICBpbmRleCsrKSB7CgpZb3UgYmV0dGVyIHRvIHVzZSBmb2xs b3dpbmcgY29kZS4gSXQgaXMgYmV0dGVyIHdheSB0byB1c2UKdGhlIG9ubHkgb25lIGxpbmUgZm9y ICdmb3InIHN0YXRlbWVudC4KCgkJc2l6ZSA9IHNpemVvZihzdHJ1Y3QgZHJhbV90aW1pbmcpIC8g NDsKCQlmb3IgKGluZGV4ID0gMDsgaW5kZXggPCBzaXplOyBpbmRleCsrKSB7Cgo+ICsJCQlwYXJh bSA9IGluZGV4Owo+ICsJCQlwYXJhbSA9IHBhcmFtIDw8IDMyIHwgKnRpbWluZysrOwo+ICsJCQlh cm1fc21jY2Nfc21jKFNJUF9ERFJfRlJFUSwgcGFyYW0sIDAsCj4gKwkJCQkgICAgICBDT05GSUdf RFJBTV9TRVRfUEFSQU0sIDAsIDAsIDAsIDAsICZyZXMpOwo+ICsJCQlpZiAocmVzLmEwKSB7Cj4g KwkJCQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byBzZXQgZHJhbSBwYXJhbTogJWxkXG4iLAo+ICsJ CQkJCXJlcy5hMCk7Cj4gKwkJCQlyZXR1cm4gLUVJTlZBTDsKPiArCQkJfQo+ICsJCQlwYXJhbSA9 IDA7Cj4gKwkJfQo+ICsJfQo+ICsKPiArCWFybV9zbWNjY19zbWMoU0lQX0REUl9GUkVRLCAwLCAw LCBDT05GSUdfRFJBTV9JTklULAo+ICsJCSAgICAgIDAsIDAsIDAsIDAsICZyZXMpOwoKZGl0dG8u IFlvdSBuZWVkIHRvIGFkZCB0aGUgZGVzY3JpcHRpb24uCgo+ICsKPiArCWluaXRfd2FpdHF1ZXVl X2hlYWQoJmRhdGEtPndhaXRfZGNmX3F1ZXVlKTsKPiArCWRhdGEtPndhaXRfZGNmX2ZsYWcgPSAw Owo+ICsKPiArCWRhdGEtPmVkZXYgPSBkZXZmcmVxX2V2ZW50X2dldF9lZGV2X2J5X3BoYW5kbGUo ZGV2LCAwKTsKPiArCWlmIChJU19FUlIoZGF0YS0+ZWRldikpCj4gKwkJcmV0dXJuIC1FUFJPQkVf REVGRVI7Cj4gKwo+ICsJcmV0ID0gZGV2ZnJlcV9ldmVudF9lbmFibGVfZWRldihkYXRhLT5lZGV2 KTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJZGV2X2VycihkZXYsICJmYWlsZWQgdG8gZW5hYmxl IGRldmZyZXEtZXZlbnQgZGV2aWNlc1xuIik7CgpzL2ZhaWxlZC9GYWlsZWQuIFVzZSBhIGNhcGl0 YWwgbGV0dGVyIGZvciB0aGUgZmlyc3QgY2hhci4KCj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiAr Cj4gKwkvKgo+ICsJICogV2UgYWRkIGEgZGV2ZnJlcSBkcml2ZXIgdG8gb3VyIHBhcmVudCBzaW5j ZSBpdCBoYXMgYSBkZXZpY2UgdHJlZSBub2RlCj4gKwkgKiB3aXRoIG9wZXJhdGluZyBwb2ludHMu Cj4gKwkgKi8KCllvdSBzaG91bGQgd3JhcCB0aGUgcmN1IGxvY2sgYmVmb3JlIGNhbGxpbmcgdGhl IGRldl9wbV9vcHBfb2ZfYWRkX3RhYmxlKCkuCgo+ICsJaWYgKGRldl9wbV9vcHBfb2ZfYWRkX3Rh YmxlKGRldikpIHsKPiArCQlkZXZfZXJyKGRldiwgIkludmFsaWQgb3BlcmF0aW5nLXBvaW50cyBp biBkZXZpY2UgdHJlZS5cbiIpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsJb2ZfcHJv cGVydHlfcmVhZF91MzIobnAsICJ1cHRocmVzaG9sZCIsCj4gKwkJCSAgICAgJmRhdGEtPm9uZGVt YW5kX2RhdGEudXB0aHJlc2hvbGQpOwo+ICsJb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJkb3du ZGlmZmVyZW50aWFsIiwKPiArCQkJICAgICAmZGF0YS0+b25kZW1hbmRfZGF0YS5kb3duZGlmZmVy ZW50aWFsKTsKCk5lZWQgb25lIGJsYW5rIGxpbmUuCk1heWJlIHRoaXMgY29kZSB0byBnZXQgdGhl IHByb3BlcmZ5IGZvciBvbmRlbWFuZCBnb3Zlcm5vciwKdGhlIGRldmZyZXEgd2lsbCBzdXBwb3J0 IGluIHRoZSBmdXR1cmUuCgo+ICsJZGF0YS0+cmF0ZSA9IGNsa19nZXRfcmF0ZShkYXRhLT5kbWNf Y2xrKTsKPiArCXJrMzM5OV9kZXZmcmVxX2RtY19wcm9maWxlLmluaXRpYWxfZnJlcSA9IGRhdGEt PnJhdGU7CgpOZWVkIG9uZSBibGFuayBsaW5lLgoKPiArCWRhdGEtPmRldmZyZXEgPSBkZXZmcmVx X2FkZF9kZXZpY2UoZGV2LAo+ICsJCQkJCSAgICZyazMzOTlfZGV2ZnJlcV9kbWNfcHJvZmlsZSwK PiArCQkJCQkgICAic2ltcGxlX29uZGVtYW5kIiwKPiArCQkJCQkgICAmZGF0YS0+b25kZW1hbmRf ZGF0YSk7Cj4gKwlpZiAoSVNfRVJSKGRhdGEtPmRldmZyZXEpKQo+ICsJCXJldHVybiBQVFJfRVJS KGRhdGEtPmRldmZyZXEpOwo+ICsJZGV2ZnJlcV9yZWdpc3Rlcl9vcHBfbm90aWZpZXIoZGV2LCBk YXRhLT5kZXZmcmVxKTsKClVzZSB0aGUgZGV2bV9kZXZmcmVxX3JlZ2lzdGVyX29wcF9ub3RpZmll cigpLgoKPiArCj4gKwlkYXRhLT5kZXYgPSBkZXY7Cj4gKwlwbGF0Zm9ybV9zZXRfZHJ2ZGF0YShw ZGV2LCBkYXRhKTsKPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIGludCByazMz OTlfZG1jZnJlcV9yZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKPiArewo+ICsJ c3RydWN0IHJrMzM5OV9kbWNmcmVxICpkbWNmcmVxID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRl dik7Cj4gKwo+ICsJZGV2ZnJlcV9yZW1vdmVfZGV2aWNlKGRtY2ZyZXEtPmRldmZyZXEpOwo+ICsJ cmVndWxhdG9yX3B1dChkbWNmcmVxLT52ZGRfY2VudGVyKTsKPiArCj4gKwlyZXR1cm4gMDsKPiAr fQo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgcmszMzk5ZG1jX2RldmZy ZXFfb2ZfbWF0Y2hbXSA9IHsKPiArCXsgLmNvbXBhdGlibGUgPSAicm9ja2NoaXAscmszMzk5LWRt YyIgfSwKPiArCXsgfSwKPiArfTsKPiArCj4gK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVy IHJrMzM5OV9kbWNmcmVxX2RyaXZlciA9IHsKPiArCS5wcm9iZQk9IHJrMzM5OV9kbWNmcmVxX3By b2JlLAo+ICsJLnJlbW92ZQk9IHJrMzM5OV9kbWNmcmVxX3JlbW92ZSwKPiArCS5kcml2ZXIgPSB7 Cj4gKwkJLm5hbWUJPSAicmszMzk5LWRtYy1mcmVxIiwKPiArCQkucG0JPSAmcmszMzk5X2RtY2Zy ZXFfcG0sCj4gKwkJLm9mX21hdGNoX3RhYmxlID0gcmszMzk5ZG1jX2RldmZyZXFfb2ZfbWF0Y2gs Cj4gKwl9LAo+ICt9Owo+ICttb2R1bGVfcGxhdGZvcm1fZHJpdmVyKHJrMzM5OV9kbWNmcmVxX2Ry aXZlcik7Cj4gKwo+ICtNT0RVTEVfTElDRU5TRSgiR1BMIHYyIik7Cj4gK01PRFVMRV9ERVNDUklQ VElPTigiUkszMzk5IGRtY2ZyZXEgZHJpdmVyIHdpdGggZGV2ZnJlcSBmcmFtZXdvcmsiKTsKCllv dSBuZWVkIHRvIGFkZCB0aGUgTU9EVUxFX0FVVEhPUiBpbmZvcm1hdGlvbi4KClJlZ2FyZHMsCkNo YW53b28gQ2hvaQoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X18KTGludXgtcm9ja2NoaXAgbWFpbGluZyBsaXN0CkxpbnV4LXJvY2tjaGlwQGxpc3RzLmluZnJh ZGVhZC5vcmcKaHR0cDovL2xpc3RzLmluZnJhZGVhZC5vcmcvbWFpbG1hbi9saXN0aW5mby9saW51 eC1yb2NrY2hpcAo= From mboxrd@z Thu Jan 1 00:00:00 1970 From: cw00.choi@samsung.com (Chanwoo Choi) Date: Mon, 01 Aug 2016 19:28:21 +0900 Subject: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc In-Reply-To: <1469779021-10426-7-git-send-email-hl@rock-chips.com> References: <1469779021-10426-1-git-send-email-hl@rock-chips.com> <1469779021-10426-7-git-send-email-hl@rock-chips.com> Message-ID: <579F2445.1020200@samsung.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi Lin, As I mentioned on patch5, you better to make the documentation as following: - Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt And, I add the comments. On 2016? 07? 29? 16:57, Lin Huang wrote: > base on dfi result, we do ddr frequency scaling, register > dmc driver to devfreq framework, and use simple-ondemand > policy. > > Signed-off-by: Lin Huang > --- > Changes in v4: > - use arm_smccc_smc() function talk to bl31 > - delete rockchip_dmc.c file and config > - delete dmc_notify > - adjust probe order > > Changes in v3: > - operate dram setting through sip call > - imporve set rate flow > > Changes in v2: > - None > > Changes in v1: > - move dfi controller to event > - fix set voltage sequence when set rate fail > - change Kconfig type from tristate to bool > - move unuse EXPORT_SYMBOL_GPL() > > drivers/devfreq/Kconfig | 1 + > drivers/devfreq/Makefile | 1 + > drivers/devfreq/rockchip/Kconfig | 8 + > drivers/devfreq/rockchip/Makefile | 1 + > drivers/devfreq/rockchip/rk3399_dmc.c | 473 ++++++++++++++++++++++++++++++++++ > 5 files changed, 484 insertions(+) > create mode 100644 drivers/devfreq/rockchip/Kconfig > create mode 100644 drivers/devfreq/rockchip/Makefile > create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c > > diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig > index 64281bb..acb2a57 100644 > --- a/drivers/devfreq/Kconfig > +++ b/drivers/devfreq/Kconfig > @@ -99,5 +99,6 @@ config ARM_TEGRA_DEVFREQ > operating frequencies and voltages with OPP support. > > source "drivers/devfreq/event/Kconfig" > +source "drivers/devfreq/rockchip/Kconfig" This patch include the only one patch. So, I think that you don't need to create the 'rockchip' directory. > > endif # PM_DEVFREQ > diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile > index 5134f9e..d844e23 100644 > --- a/drivers/devfreq/Makefile > +++ b/drivers/devfreq/Makefile > @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o > obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/ > obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/ > obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o > +obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ ditto. > > # DEVFREQ Event Drivers > obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ > diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig > new file mode 100644 > index 0000000..d8f9e66 > --- /dev/null > +++ b/drivers/devfreq/rockchip/Kconfig > @@ -0,0 +1,8 @@ > +config ARM_RK3399_DMC_DEVFREQ > + tristate "ARM RK3399 DMC DEVFREQ Driver" > + select PM_OPP > + select DEVFREQ_GOV_SIMPLE_ONDEMAND > + help > + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency If you add the full description for 'dmc' as following, it is easy to understand the operation of this device driver. - DMC (Dynamic Memory Controller) > + for the memory controller and reads the usage counts from hardware. > + > diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile > new file mode 100644 > index 0000000..c62c105 > --- /dev/null > +++ b/drivers/devfreq/rockchip/Makefile > @@ -0,0 +1 @@ > +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o > diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c > new file mode 100644 > index 0000000..527aa11 > --- /dev/null > +++ b/drivers/devfreq/rockchip/rk3399_dmc.c > @@ -0,0 +1,473 @@ > +/* > + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd You miss the '.' at the end of the copylight. When you use an abbreviation, you should add '.' for Ltd. - s/Ltd/Ltd. > + * Author: Lin Huang > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + */ > + > +#include > +#include > +#include You don't need to include the "completion.h". Without "completion.h", the build is working. > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include You don't need to include the "syscore_ops.h". Without "syscore_ops.h", the build is working. > + > +#include > + > +struct dram_timing { > + unsigned int ddr3_speed_bin; > + unsigned int pd_idle; > + unsigned int sr_idle; > + unsigned int sr_mc_gate_idle; > + unsigned int srpd_lite_idle; > + unsigned int standby_idle; > + unsigned int dram_dll_dis_freq; > + unsigned int phy_dll_dis_freq; > + unsigned int ddr3_odt_dis_freq; > + unsigned int ddr3_drv; > + unsigned int ddr3_odt; > + unsigned int phy_ddr3_ca_drv; > + unsigned int phy_ddr3_dq_drv; > + unsigned int phy_ddr3_odt; > + unsigned int lpddr3_odt_dis_freq; > + unsigned int lpddr3_drv; > + unsigned int lpddr3_odt; > + unsigned int phy_lpddr3_ca_drv; > + unsigned int phy_lpddr3_dq_drv; > + unsigned int phy_lpddr3_odt; > + unsigned int lpddr4_odt_dis_freq; > + unsigned int lpddr4_drv; > + unsigned int lpddr4_dq_odt; > + unsigned int lpddr4_ca_odt; > + unsigned int phy_lpddr4_ca_drv; > + unsigned int phy_lpddr4_ck_cs_drv; > + unsigned int phy_lpddr4_dq_drv; > + unsigned int phy_lpddr4_odt; > +}; The dram_timing is used for SMC (Secure Monitor Call)? I recommend that you add the detailed description about this property on Documentation. > + > +struct rk3399_dmcfreq { > + struct device *dev; > + struct devfreq *devfreq; > + struct devfreq_simple_ondemand_data ondemand_data; > + struct clk *dmc_clk; > + struct devfreq_event_dev *edev; > + struct mutex lock; > + struct dram_timing *timing; > + wait_queue_head_t wait_dcf_queue; > + int irq; > + int wait_dcf_flag; I want to add the full name and description of 'dcf'. It is unknown word. > + struct regulator *vdd_center; > + unsigned long rate, target_rate; > + unsigned long volt, target_volt; I think that if you add 'curr_opp' variable, you can reduce the calling of devfreq_recommended_opp() in rk3399_dmcfreq_target() struct dev_pm_opp *curr_opp; > +}; > + > +static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq, > + u32 flags) > +{ > + struct platform_device *pdev = container_of(dev, struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); You can use the 'dev_get_drvdata()' to simplify it instead of 'platform_get_drvdata()'. struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev); > + struct dev_pm_opp *opp; > + unsigned long old_clk_rate = dmcfreq->rate; > + unsigned long target_volt, target_rate; > + int err; > + > + rcu_read_lock(); > + opp = devfreq_recommended_opp(dev, freq, flags); > + if (IS_ERR(opp)) { > + rcu_read_unlock(); > + return PTR_ERR(opp); > + } > + > + target_rate = dev_pm_opp_get_freq(opp); > + target_volt = dev_pm_opp_get_voltage(opp); > + opp = devfreq_recommended_opp(dev, &dmcfreq->rate, flags); > + if (IS_ERR(opp)) { > + rcu_read_unlock(); > + return PTR_ERR(opp); > + } > + dmcfreq->volt = dev_pm_opp_get_voltage(opp); If you add the 'curr_opp' variable to struct rk3399_dmcfreq, you can remove the calling of devfreq_recommended_opp(). dmcfreq->rate = dev_pm_opp_get_freq(dmcfreq->curr_opp); dmcfreq->volt = dev_pm_opp_get_freq(dmcfreq->curr_opp); Because the current rate and voltage is already decided on previous polling cycle, So we don't need to get the opp with devfreq_recommended_opp(). > + rcu_read_unlock(); > + > + if (dmcfreq->rate == target_rate) > + return 0; > + > + mutex_lock(&dmcfreq->lock); > + > + /* > + * if frequency scaling from low to high, adjust voltage first; > + * if frequency scaling from high to low, adjuset frequency first; > + */ s/adjuset/adjust I recommend that you use a captital letter for first character and use the '.' instead of ';'. > + if (old_clk_rate < target_rate) { > + err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, > + target_volt); > + if (err) { > + dev_err(dev, "Unable to set vol %lu\n", target_volt); To readability, you better to use the corrent word to pass the precise the log message. - s/vol/voltage And, this patch uses the 'Unable to' or 'Cannot' to show the error log. I recommend that you use the consistent expression if there is not any specific reason. dev_err(dev, "Cannot set the voltage %lu uV\n", target_volt); > + goto out; > + } > + } > + dmcfreq->wait_dcf_flag = 1; > + err = clk_set_rate(dmcfreq->dmc_clk, target_rate); > + if (err) { > + dev_err(dev, > + "Unable to set freq %lu. Current freq %lu. Error %d\n", > + target_rate, old_clk_rate, err); dev_err(dev, "Cannot set the frequency %lu (%d)\n", target_rate, err); > + regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt, > + dmcfreq->volt); > + goto out; > + } > + > + /* > + * wait until bcf irq happen, it means freq scaling finish in bl31, ditto. > + * use 100ms as timeout time s/time/time. > + */ > + if (!wait_event_timeout(dmcfreq->wait_dcf_queue, > + !dmcfreq->wait_dcf_flag, HZ / 10)) > + dev_warn(dev, "Timeout waiting for dcf irq\n"); If the timeout happen, are there any problem? After setting the frequency and voltage, store the current opp entry on .curr_opp. dmcfreq->curr_opp = opp; > + /* > + * check the dpll rate > + * there only two result we will get, > + * 1. ddr frequency scaling fail, we still get the old rate > + * 2, ddr frequency scaling sucessful, we get the rate we set > + */ > + dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk); > + > + /* if get the incorrect rate, set voltage to old value */ > + if (dmcfreq->rate != target_rate) { > + dev_err(dev, "get wrong ddr frequency, Request freq %lu,\ > + Current freq %lu\n", target_rate, dmcfreq->rate); > + regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt, > + dmcfreq->volt); [Without force, it is just my opion about this code:] I think that this checking code it is un-needed. If this case occur, the rk3399_dmc.c never set the specific frequency because the rk3399 clock don't support the specific frequency for rk3399 dmc. If you want to set the correct frequency, When verifying the rk3399 dmc driver, you should check the rk3399 clock driver. Basically, if the the clock driver don't support the correct same frequency , CCF(Common Clock Framework) set the close frequency. It is not a bad thing. > + } else if (old_clk_rate > target_rate) > + err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, > + target_volt); > + if (err) > + dev_err(dev, "Unable to set vol %lu\n", target_volt); ditto. You better to use the consistent expression for error log as following: dev_err(dev, "Cannot set the voltage %lu uV\n", target_volt); > + > +out: > + mutex_unlock(&dmcfreq->lock); > + return err; > +} > + > +static int rk3399_dmcfreq_get_dev_status(struct device *dev, > + struct devfreq_dev_status *stat) > +{ > + struct platform_device *pdev = container_of(dev, struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); > + struct devfreq_event_data edata; ditto. Use the dev_get_drvdata(dev). > + > + devfreq_event_get_event(dmcfreq->edev, &edata); You need to check the return value for exception handling. > + > + stat->current_frequency = dmcfreq->rate; > + stat->busy_time = edata.load_count; > + stat->total_time = edata.total_count; > + > + return 0; > +} > + > +static int rk3399_dmcfreq_get_cur_freq(struct device *dev, unsigned long *freq) > +{ > + struct platform_device *pdev = container_of(dev, struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); ditto. Use the dev_get_drvdata(dev). > + > + *freq = dmcfreq->rate; > + > + return 0; > +} > + > +static void rk3399_dmcfreq_exit(struct device *dev) > +{ > + struct platform_device *pdev = container_of(dev, > + struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); > + > + devfreq_unregister_opp_notifier(dev, dmcfreq->devfreq); Use the devm_devfreq_register_opp_notifier(). You don't need to handle it. > +} > + > +static struct devfreq_dev_profile rk3399_devfreq_dmc_profile = { > + .polling_ms = 200, > + .target = rk3399_dmcfreq_target, > + .get_dev_status = rk3399_dmcfreq_get_dev_status, > + .get_cur_freq = rk3399_dmcfreq_get_cur_freq, > + .exit = rk3399_dmcfreq_exit, > +}; > + > +static __maybe_unused int rk3399_dmcfreq_suspend(struct device *dev) > +{ > + struct platform_device *pdev = container_of(dev, > + struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); ditto. Use the dev_get_drvdata(dev). > + > + devfreq_event_disable_edev(dmcfreq->edev); > + devfreq_suspend_device(dmcfreq->devfreq); ditto. you need to check the return value. > + > + return 0; > +} > + > +static __maybe_unused int rk3399_dmcfreq_resume(struct device *dev) > +{ > + struct platform_device *pdev = container_of(dev, > + struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); ditto. > + > + devfreq_event_enable_edev(dmcfreq->edev); > + devfreq_resume_device(dmcfreq->devfreq); ditto. > + > + return 0; > +} > + > +static SIMPLE_DEV_PM_OPS(rk3399_dmcfreq_pm, rk3399_dmcfreq_suspend, > + rk3399_dmcfreq_resume); > + > +static irqreturn_t rk3399_dmc_irq(int irq, void *dev_id) > +{ > + struct rk3399_dmcfreq *dmcfreq = dev_id; > + struct arm_smccc_res res; > + > + dmcfreq->wait_dcf_flag = 0; > + wake_up(&dmcfreq->wait_dcf_queue); > + > + /* clr dcf irq */ s/ clr dcf irq -> "Clear the DCF Interrupt" > + arm_smccc_smc(SIP_DDR_FREQ, 0, 0, CONFIG_DRAM_CLR_IRQ, > + 0, 0, 0, 0, &res); > + > + return IRQ_HANDLED; > +} > + > +static int of_do_get_timing(struct device_node *np, > + struct dram_timing *timing) > +{ > + int ret; > + > + ret = of_property_read_u32(np, "ddr3_speed_bin", > + &timing->ddr3_speed_bin); > + ret |= of_property_read_u32(np, "pd_idle", &timing->pd_idle); > + ret |= of_property_read_u32(np, "sr_idle", &timing->sr_idle); > + ret |= of_property_read_u32(np, "sr_mc_gate_idle", > + &timing->sr_mc_gate_idle); > + ret |= of_property_read_u32(np, "srpd_lite_idle", > + &timing->srpd_lite_idle); > + ret |= of_property_read_u32(np, "standby_idle", &timing->standby_idle); > + ret |= of_property_read_u32(np, "dram_dll_dis_freq", > + &timing->dram_dll_dis_freq); > + ret |= of_property_read_u32(np, "phy_dll_dis_freq", > + &timing->phy_dll_dis_freq); > + ret |= of_property_read_u32(np, "ddr3_odt_dis_freq", > + &timing->ddr3_odt_dis_freq); > + ret |= of_property_read_u32(np, "ddr3_drv", &timing->ddr3_drv); > + ret |= of_property_read_u32(np, "ddr3_odt", &timing->ddr3_odt); > + ret |= of_property_read_u32(np, "phy_ddr3_ca_drv", > + &timing->phy_ddr3_ca_drv); > + ret |= of_property_read_u32(np, "phy_ddr3_dq_drv", > + &timing->phy_ddr3_dq_drv); > + ret |= of_property_read_u32(np, "phy_ddr3_odt", &timing->phy_ddr3_odt); > + ret |= of_property_read_u32(np, "lpddr3_odt_dis_freq", > + &timing->lpddr3_odt_dis_freq); > + ret |= of_property_read_u32(np, "lpddr3_drv", &timing->lpddr3_drv); > + ret |= of_property_read_u32(np, "lpddr3_odt", &timing->lpddr3_odt); > + ret |= of_property_read_u32(np, "phy_lpddr3_ca_drv", > + &timing->phy_lpddr3_ca_drv); > + ret |= of_property_read_u32(np, "phy_lpddr3_dq_drv", > + &timing->phy_lpddr3_dq_drv); > + ret |= of_property_read_u32(np, "phy_lpddr3_odt", > + &timing->phy_lpddr3_odt); > + ret |= of_property_read_u32(np, "lpddr4_odt_dis_freq", > + &timing->lpddr4_odt_dis_freq); > + ret |= of_property_read_u32(np, "lpddr4_drv", > + &timing->lpddr4_drv); > + ret |= of_property_read_u32(np, "lpddr4_dq_odt", > + &timing->lpddr4_dq_odt); > + ret |= of_property_read_u32(np, "lpddr4_ca_odt", > + &timing->lpddr4_ca_odt); > + ret |= of_property_read_u32(np, "phy_lpddr4_ca_drv", > + &timing->phy_lpddr4_ca_drv); > + ret |= of_property_read_u32(np, "phy_lpddr4_ck_cs_drv", > + &timing->phy_lpddr4_ck_cs_drv); > + ret |= of_property_read_u32(np, "phy_lpddr4_dq_drv", > + &timing->phy_lpddr4_dq_drv); > + ret |= of_property_read_u32(np, "phy_lpddr4_odt", > + &timing->phy_lpddr4_odt); > + > + return ret; > +} > + > +static struct dram_timing *of_get_ddr_timings(struct device *dev, > + struct device_node *np) > +{ > + struct dram_timing *timing = NULL; > + struct device_node *np_tim; > + > + np_tim = of_parse_phandle(np, "ddr_timing", 0); As I already mentioned, you need to add the detailed documetation about the property. > + if (np_tim) { > + timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); > + if (!timing) > + goto err; > + if (of_do_get_timing(np_tim, timing)) { I recommend that you better to squash following two functions because of_do_get_timing() is not used on other point of this driver. - of_do_get_timing() - of_get_ddr_timings() > + devm_kfree(dev, timing); > + goto err; > + } You're missing the 'of_node_put'. of_node_put(np_tim); > + return timing; > + } > + > +err: > + if (timing) { > + devm_kfree(dev, timing); > + timing = NULL; > + } > + ditto. of_node_put(np_tim); > + return timing; > +} > + > +static int rk3399_dmcfreq_probe(struct platform_device *pdev) > +{ > + struct arm_smccc_res res; > + struct device *dev = &pdev->dev; > + struct device_node *np = pdev->dev.of_node; > + uint64_t param = 0; > + struct rk3399_dmcfreq *data; > + int ret, irq, index; > + uint32_t *timing; > + > + irq = platform_get_irq(pdev, 0); > + if (irq < 0) { > + dev_err(&pdev->dev, "no dmc irq resource\n"); We need to maintain the consistent expression for error log. dev_err(&pdev->dev, ""Cannot get the interrupt resource"\n"); > + return -EINVAL; > + } > + data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + mutex_init(&data->lock); > + > + data->vdd_center = devm_regulator_get(dev, "center"); > + if (IS_ERR(data->vdd_center)) { > + dev_err(dev, "Cannot get the regulator \"center\"\n"); > + return PTR_ERR(data->vdd_center); > + } > + > + data->dmc_clk = devm_clk_get(dev, "dmc_clk"); > + if (IS_ERR(data->dmc_clk)) { > + dev_err(dev, "Cannot get the clk dmc_clk\n"); > + return PTR_ERR(data->dmc_clk); > + }; > + > + data->irq = irq; > + ret = devm_request_irq(dev, irq, rk3399_dmc_irq, 0, > + dev_name(dev), data); > + if (ret) { > + dev_err(dev, "failed to request dmc irq: %d\n", ret); ditto. "Failed to request the dmc irq" or "Cannot request the dmc irq" > + return ret; > + } > + > + /* get dram timing and pass it to bl31 */ I want to add the more detailed description why this code is necessary. Because the SMC is usually black box. So, If you add the more explanation, it help people to understand this code. > + data->timing = of_get_ddr_timings(dev, np); > + if (data->timing) { > + timing = (uint32_t *)data->timing; > + for (index = 0; index < (sizeof(struct dram_timing) / 4); > + index++) { You better to use following code. It is better way to use the only one line for 'for' statement. size = sizeof(struct dram_timing) / 4; for (index = 0; index < size; index++) { > + param = index; > + param = param << 32 | *timing++; > + arm_smccc_smc(SIP_DDR_FREQ, param, 0, > + CONFIG_DRAM_SET_PARAM, 0, 0, 0, 0, &res); > + if (res.a0) { > + dev_err(dev, "failed to set dram param: %ld\n", > + res.a0); > + return -EINVAL; > + } > + param = 0; > + } > + } > + > + arm_smccc_smc(SIP_DDR_FREQ, 0, 0, CONFIG_DRAM_INIT, > + 0, 0, 0, 0, &res); ditto. You need to add the description. > + > + init_waitqueue_head(&data->wait_dcf_queue); > + data->wait_dcf_flag = 0; > + > + data->edev = devfreq_event_get_edev_by_phandle(dev, 0); > + if (IS_ERR(data->edev)) > + return -EPROBE_DEFER; > + > + ret = devfreq_event_enable_edev(data->edev); > + if (ret < 0) { > + dev_err(dev, "failed to enable devfreq-event devices\n"); s/failed/Failed. Use a capital letter for the first char. > + return ret; > + } > + > + /* > + * We add a devfreq driver to our parent since it has a device tree node > + * with operating points. > + */ You should wrap the rcu lock before calling the dev_pm_opp_of_add_table(). > + if (dev_pm_opp_of_add_table(dev)) { > + dev_err(dev, "Invalid operating-points in device tree.\n"); > + return -EINVAL; > + } > + of_property_read_u32(np, "upthreshold", > + &data->ondemand_data.upthreshold); > + of_property_read_u32(np, "downdifferential", > + &data->ondemand_data.downdifferential); Need one blank line. Maybe this code to get the properfy for ondemand governor, the devfreq will support in the future. > + data->rate = clk_get_rate(data->dmc_clk); > + rk3399_devfreq_dmc_profile.initial_freq = data->rate; Need one blank line. > + data->devfreq = devfreq_add_device(dev, > + &rk3399_devfreq_dmc_profile, > + "simple_ondemand", > + &data->ondemand_data); > + if (IS_ERR(data->devfreq)) > + return PTR_ERR(data->devfreq); > + devfreq_register_opp_notifier(dev, data->devfreq); Use the devm_devfreq_register_opp_notifier(). > + > + data->dev = dev; > + platform_set_drvdata(pdev, data); > + > + return 0; > +} > + > +static int rk3399_dmcfreq_remove(struct platform_device *pdev) > +{ > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); > + > + devfreq_remove_device(dmcfreq->devfreq); > + regulator_put(dmcfreq->vdd_center); > + > + return 0; > +} > + > +static const struct of_device_id rk3399dmc_devfreq_of_match[] = { > + { .compatible = "rockchip,rk3399-dmc" }, > + { }, > +}; > + > +static struct platform_driver rk3399_dmcfreq_driver = { > + .probe = rk3399_dmcfreq_probe, > + .remove = rk3399_dmcfreq_remove, > + .driver = { > + .name = "rk3399-dmc-freq", > + .pm = &rk3399_dmcfreq_pm, > + .of_match_table = rk3399dmc_devfreq_of_match, > + }, > +}; > +module_platform_driver(rk3399_dmcfreq_driver); > + > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("RK3399 dmcfreq driver with devfreq framework"); You need to add the MODULE_AUTHOR information. Regards, Chanwoo Choi From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752518AbcHAKjg (ORCPT ); Mon, 1 Aug 2016 06:39:36 -0400 Received: from mailout4.samsung.com ([203.254.224.34]:38666 "EHLO mailout4.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752017AbcHAKj0 convert rfc822-to-8bit (ORCPT ); Mon, 1 Aug 2016 06:39:26 -0400 X-AuditID: cbfee68d-f79286d000007a9a-b5-579f2445d3d2 MIME-version: 1.0 Content-type: text/plain; charset=UTF-8 Content-transfer-encoding: 8BIT Message-id: <579F2445.1020200@samsung.com> Date: Mon, 01 Aug 2016 19:28:21 +0900 From: Chanwoo Choi User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 To: Lin Huang , heiko@sntech.de Cc: tixy@linaro.org, dbasehore@chromium.org, airlied@linux.ie, mturquette@baylibre.com, typ@rock-chips.com, sboyd@codeaurora.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, dianders@chromium.org, linux-rockchip@lists.infradead.org, kyungmin.park@samsung.com, myungjoo.ham@samsung.com, linux-arm-kernel@lists.infradead.org, mark.yao@rock-chips.com Subject: Re: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc References: <1469779021-10426-1-git-send-email-hl@rock-chips.com> <1469779021-10426-7-git-send-email-hl@rock-chips.com> In-reply-to: <1469779021-10426-7-git-send-email-hl@rock-chips.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmphleLIzCtJLcpLzFFi42JZI2JSqOumMj/cYOZcZovecyeZLF5t3sNm cXbZQTaLK1/fs1n8f/Sa1eLHhlPMFmeb3rBbbHp8jdXi8q45bBafHvxnttgx5QCTxcVTrha3 G1ewWfw4081isXD+fXaL2avrHAQ83t9oZfeY3XCRxeNyXy+Tx51re9g8tn97wOpxv/s4k8fm JfUef2ftZ/Ho27KK0WP7tXnMHp83yQVwR3HZpKTmZJalFunbJXBlnF6xlb3g7y7Giq/rG1ga GL9MZexi5OSQEDCR2HhiFjOELSZx4d56NhBbSGAFo8TqXZwwNX/mLAOKcwHFlzJK/L/7jBUk wSsgKPFj8j0WEJtZQF1i0rxFzBC2qMSyxgVQcW2JZQtfM0M0P2CU+H10MRNEs5bEg3/zwBpY BFQlpnVuA7PZgOL7X9wA2sbBISoQIdF9ohIkLCJgJHH2y3wmkDnMAj+YJD7sXA12qbBAuMTn o1+YIK4+yygx/5UqiM0p4CQxcecUVogPTnBILDnmDLFLQOLb5EMsIPMlBGQlNh2Ael5S4uCK GywTGMVnIXltFpLXZiF5bRaS1xYwsqxiFE0tSC4oTkovMtQrTswtLs1L10vOz93ECEwcp/89 693BePuA9SFGAQ5GJR7eG7nzwoVYE8uKK3MPMZoCXTSRWUo0OR+YnvJK4g2NzYwsTE1MjY3M Lc2UxHkVpX4GCwmkJ5akZqemFqQWxReV5qQWH2Jk4uCUamC8tNe1P3LuMcu9CaYK31Q1LMtC L/FdWf/Icffym5e6Ms/POvx+6obqf3bmSYFzdVaZCh7c4zFhtX+L0lv1jmdzpfcrXmJsezJ1 xsKd9Tz6K3hK2RptvFi3xihYMM1ISz8ikzZ3nef6F2zrG+xSPI8W3w8/sT6n0/1Vk9uNqZat /a+fST+497FFiaU4I9FQi7moOBEARWkjRhcDAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrJKsWRmVeSWpSXmKPExsVy+t9jAV1XlfnhBje3mVn0njvJZPFq8x42 i7PLDrJZXPn6ns3i/6PXrBY/Npxitjjb9IbdYtPja6wWl3fNYbP49OA/s8WOKQeYLC6ecrW4 3biCzeLHmW4Wi4Xz77NbzF5d5yDg8f5GK7vH7IaLLB6X+3qZPO5c28Pmsf3bA1aP+93HmTw2 L6n3+DtrP4tH35ZVjB7br81j9vi8SS6AO6qB0SYjNTEltUghNS85PyUzL91WyTs43jne1MzA UNfQ0sJcSSEvMTfVVsnFJ0DXLTMH6B8lhbLEnFKgUEBicbGSvh2mCaEhbroWMI0Rur4hQXA9 RgZoIGENY8aaW5NZChp3Mlase/aTvYHxx2TGLkZODgkBE4k/c5axQdhiEhfurQeyuTiEBJYy Svy/+4wVJMErICjxY/I9li5GDg5mAXmJI5eyQcLMAuoSk+YtYoaof8Ao8fvoYiaIei2JB//m MYPYLAKqEtM6t4HZbEDx/S9usIHMERWIkOg+UQkSFhEwkjj7ZT4TyBxmgR9MEh92rgY7SFgg XOLz0S9gM4UEzjJKzH+lCmJzCjhJTNw5hXUCo8AsJOfNQjhvFpLzFjAyr2KUSC1ILihOSs81 zEst1ytOzC0uzUvXS87P3cQITjbPpHYwHtzlfohRgINRiYc3wX9euBBrYllxZe4hRgkOZiUR XgeF+eFCvCmJlVWpRfnxRaU5qcWHGE2B/pvILCWanA9MhHkl8YbGJmZGlkbmhhZGxuZK4ryP /68LExJITyxJzU5NLUgtgulj4uCUamDsXH9l25cdGbxXMnpS0htsONq5+1aIz4lO37dl5d0N s/kiDrHm2005bb6Hz4ShZON/jssmMoaPzgus0O34VXIztqXqmKPnnfd+E/e7ZyiYJUk2ypUx syy7Y38oYt/kRzdOObYwXXjlwP3X6tV138PvFr2v0L5ZvvjiLttSfj1G5qP9HP9n6zkpsRRn JBpqMRcVJwIAou14N0wDAAA= DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Lin, As I mentioned on patch5, you better to make the documentation as following: - Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt And, I add the comments. On 2016년 07월 29일 16:57, Lin Huang wrote: > base on dfi result, we do ddr frequency scaling, register > dmc driver to devfreq framework, and use simple-ondemand > policy. > > Signed-off-by: Lin Huang > --- > Changes in v4: > - use arm_smccc_smc() function talk to bl31 > - delete rockchip_dmc.c file and config > - delete dmc_notify > - adjust probe order > > Changes in v3: > - operate dram setting through sip call > - imporve set rate flow > > Changes in v2: > - None > > Changes in v1: > - move dfi controller to event > - fix set voltage sequence when set rate fail > - change Kconfig type from tristate to bool > - move unuse EXPORT_SYMBOL_GPL() > > drivers/devfreq/Kconfig | 1 + > drivers/devfreq/Makefile | 1 + > drivers/devfreq/rockchip/Kconfig | 8 + > drivers/devfreq/rockchip/Makefile | 1 + > drivers/devfreq/rockchip/rk3399_dmc.c | 473 ++++++++++++++++++++++++++++++++++ > 5 files changed, 484 insertions(+) > create mode 100644 drivers/devfreq/rockchip/Kconfig > create mode 100644 drivers/devfreq/rockchip/Makefile > create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c > > diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig > index 64281bb..acb2a57 100644 > --- a/drivers/devfreq/Kconfig > +++ b/drivers/devfreq/Kconfig > @@ -99,5 +99,6 @@ config ARM_TEGRA_DEVFREQ > operating frequencies and voltages with OPP support. > > source "drivers/devfreq/event/Kconfig" > +source "drivers/devfreq/rockchip/Kconfig" This patch include the only one patch. So, I think that you don't need to create the 'rockchip' directory. > > endif # PM_DEVFREQ > diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile > index 5134f9e..d844e23 100644 > --- a/drivers/devfreq/Makefile > +++ b/drivers/devfreq/Makefile > @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o > obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/ > obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/ > obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o > +obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ ditto. > > # DEVFREQ Event Drivers > obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ > diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig > new file mode 100644 > index 0000000..d8f9e66 > --- /dev/null > +++ b/drivers/devfreq/rockchip/Kconfig > @@ -0,0 +1,8 @@ > +config ARM_RK3399_DMC_DEVFREQ > + tristate "ARM RK3399 DMC DEVFREQ Driver" > + select PM_OPP > + select DEVFREQ_GOV_SIMPLE_ONDEMAND > + help > + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency If you add the full description for 'dmc' as following, it is easy to understand the operation of this device driver. - DMC (Dynamic Memory Controller) > + for the memory controller and reads the usage counts from hardware. > + > diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile > new file mode 100644 > index 0000000..c62c105 > --- /dev/null > +++ b/drivers/devfreq/rockchip/Makefile > @@ -0,0 +1 @@ > +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o > diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c > new file mode 100644 > index 0000000..527aa11 > --- /dev/null > +++ b/drivers/devfreq/rockchip/rk3399_dmc.c > @@ -0,0 +1,473 @@ > +/* > + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd You miss the '.' at the end of the copylight. When you use an abbreviation, you should add '.' for Ltd. - s/Ltd/Ltd. > + * Author: Lin Huang > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + */ > + > +#include > +#include > +#include You don't need to include the "completion.h". Without "completion.h", the build is working. > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include You don't need to include the "syscore_ops.h". Without "syscore_ops.h", the build is working. > + > +#include > + > +struct dram_timing { > + unsigned int ddr3_speed_bin; > + unsigned int pd_idle; > + unsigned int sr_idle; > + unsigned int sr_mc_gate_idle; > + unsigned int srpd_lite_idle; > + unsigned int standby_idle; > + unsigned int dram_dll_dis_freq; > + unsigned int phy_dll_dis_freq; > + unsigned int ddr3_odt_dis_freq; > + unsigned int ddr3_drv; > + unsigned int ddr3_odt; > + unsigned int phy_ddr3_ca_drv; > + unsigned int phy_ddr3_dq_drv; > + unsigned int phy_ddr3_odt; > + unsigned int lpddr3_odt_dis_freq; > + unsigned int lpddr3_drv; > + unsigned int lpddr3_odt; > + unsigned int phy_lpddr3_ca_drv; > + unsigned int phy_lpddr3_dq_drv; > + unsigned int phy_lpddr3_odt; > + unsigned int lpddr4_odt_dis_freq; > + unsigned int lpddr4_drv; > + unsigned int lpddr4_dq_odt; > + unsigned int lpddr4_ca_odt; > + unsigned int phy_lpddr4_ca_drv; > + unsigned int phy_lpddr4_ck_cs_drv; > + unsigned int phy_lpddr4_dq_drv; > + unsigned int phy_lpddr4_odt; > +}; The dram_timing is used for SMC (Secure Monitor Call)? I recommend that you add the detailed description about this property on Documentation. > + > +struct rk3399_dmcfreq { > + struct device *dev; > + struct devfreq *devfreq; > + struct devfreq_simple_ondemand_data ondemand_data; > + struct clk *dmc_clk; > + struct devfreq_event_dev *edev; > + struct mutex lock; > + struct dram_timing *timing; > + wait_queue_head_t wait_dcf_queue; > + int irq; > + int wait_dcf_flag; I want to add the full name and description of 'dcf'. It is unknown word. > + struct regulator *vdd_center; > + unsigned long rate, target_rate; > + unsigned long volt, target_volt; I think that if you add 'curr_opp' variable, you can reduce the calling of devfreq_recommended_opp() in rk3399_dmcfreq_target() struct dev_pm_opp *curr_opp; > +}; > + > +static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq, > + u32 flags) > +{ > + struct platform_device *pdev = container_of(dev, struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); You can use the 'dev_get_drvdata()' to simplify it instead of 'platform_get_drvdata()'. struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev); > + struct dev_pm_opp *opp; > + unsigned long old_clk_rate = dmcfreq->rate; > + unsigned long target_volt, target_rate; > + int err; > + > + rcu_read_lock(); > + opp = devfreq_recommended_opp(dev, freq, flags); > + if (IS_ERR(opp)) { > + rcu_read_unlock(); > + return PTR_ERR(opp); > + } > + > + target_rate = dev_pm_opp_get_freq(opp); > + target_volt = dev_pm_opp_get_voltage(opp); > + opp = devfreq_recommended_opp(dev, &dmcfreq->rate, flags); > + if (IS_ERR(opp)) { > + rcu_read_unlock(); > + return PTR_ERR(opp); > + } > + dmcfreq->volt = dev_pm_opp_get_voltage(opp); If you add the 'curr_opp' variable to struct rk3399_dmcfreq, you can remove the calling of devfreq_recommended_opp(). dmcfreq->rate = dev_pm_opp_get_freq(dmcfreq->curr_opp); dmcfreq->volt = dev_pm_opp_get_freq(dmcfreq->curr_opp); Because the current rate and voltage is already decided on previous polling cycle, So we don't need to get the opp with devfreq_recommended_opp(). > + rcu_read_unlock(); > + > + if (dmcfreq->rate == target_rate) > + return 0; > + > + mutex_lock(&dmcfreq->lock); > + > + /* > + * if frequency scaling from low to high, adjust voltage first; > + * if frequency scaling from high to low, adjuset frequency first; > + */ s/adjuset/adjust I recommend that you use a captital letter for first character and use the '.' instead of ';'. > + if (old_clk_rate < target_rate) { > + err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, > + target_volt); > + if (err) { > + dev_err(dev, "Unable to set vol %lu\n", target_volt); To readability, you better to use the corrent word to pass the precise the log message. - s/vol/voltage And, this patch uses the 'Unable to' or 'Cannot' to show the error log. I recommend that you use the consistent expression if there is not any specific reason. dev_err(dev, "Cannot set the voltage %lu uV\n", target_volt); > + goto out; > + } > + } > + dmcfreq->wait_dcf_flag = 1; > + err = clk_set_rate(dmcfreq->dmc_clk, target_rate); > + if (err) { > + dev_err(dev, > + "Unable to set freq %lu. Current freq %lu. Error %d\n", > + target_rate, old_clk_rate, err); dev_err(dev, "Cannot set the frequency %lu (%d)\n", target_rate, err); > + regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt, > + dmcfreq->volt); > + goto out; > + } > + > + /* > + * wait until bcf irq happen, it means freq scaling finish in bl31, ditto. > + * use 100ms as timeout time s/time/time. > + */ > + if (!wait_event_timeout(dmcfreq->wait_dcf_queue, > + !dmcfreq->wait_dcf_flag, HZ / 10)) > + dev_warn(dev, "Timeout waiting for dcf irq\n"); If the timeout happen, are there any problem? After setting the frequency and voltage, store the current opp entry on .curr_opp. dmcfreq->curr_opp = opp; > + /* > + * check the dpll rate > + * there only two result we will get, > + * 1. ddr frequency scaling fail, we still get the old rate > + * 2, ddr frequency scaling sucessful, we get the rate we set > + */ > + dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk); > + > + /* if get the incorrect rate, set voltage to old value */ > + if (dmcfreq->rate != target_rate) { > + dev_err(dev, "get wrong ddr frequency, Request freq %lu,\ > + Current freq %lu\n", target_rate, dmcfreq->rate); > + regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt, > + dmcfreq->volt); [Without force, it is just my opion about this code:] I think that this checking code it is un-needed. If this case occur, the rk3399_dmc.c never set the specific frequency because the rk3399 clock don't support the specific frequency for rk3399 dmc. If you want to set the correct frequency, When verifying the rk3399 dmc driver, you should check the rk3399 clock driver. Basically, if the the clock driver don't support the correct same frequency , CCF(Common Clock Framework) set the close frequency. It is not a bad thing. > + } else if (old_clk_rate > target_rate) > + err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, > + target_volt); > + if (err) > + dev_err(dev, "Unable to set vol %lu\n", target_volt); ditto. You better to use the consistent expression for error log as following: dev_err(dev, "Cannot set the voltage %lu uV\n", target_volt); > + > +out: > + mutex_unlock(&dmcfreq->lock); > + return err; > +} > + > +static int rk3399_dmcfreq_get_dev_status(struct device *dev, > + struct devfreq_dev_status *stat) > +{ > + struct platform_device *pdev = container_of(dev, struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); > + struct devfreq_event_data edata; ditto. Use the dev_get_drvdata(dev). > + > + devfreq_event_get_event(dmcfreq->edev, &edata); You need to check the return value for exception handling. > + > + stat->current_frequency = dmcfreq->rate; > + stat->busy_time = edata.load_count; > + stat->total_time = edata.total_count; > + > + return 0; > +} > + > +static int rk3399_dmcfreq_get_cur_freq(struct device *dev, unsigned long *freq) > +{ > + struct platform_device *pdev = container_of(dev, struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); ditto. Use the dev_get_drvdata(dev). > + > + *freq = dmcfreq->rate; > + > + return 0; > +} > + > +static void rk3399_dmcfreq_exit(struct device *dev) > +{ > + struct platform_device *pdev = container_of(dev, > + struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); > + > + devfreq_unregister_opp_notifier(dev, dmcfreq->devfreq); Use the devm_devfreq_register_opp_notifier(). You don't need to handle it. > +} > + > +static struct devfreq_dev_profile rk3399_devfreq_dmc_profile = { > + .polling_ms = 200, > + .target = rk3399_dmcfreq_target, > + .get_dev_status = rk3399_dmcfreq_get_dev_status, > + .get_cur_freq = rk3399_dmcfreq_get_cur_freq, > + .exit = rk3399_dmcfreq_exit, > +}; > + > +static __maybe_unused int rk3399_dmcfreq_suspend(struct device *dev) > +{ > + struct platform_device *pdev = container_of(dev, > + struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); ditto. Use the dev_get_drvdata(dev). > + > + devfreq_event_disable_edev(dmcfreq->edev); > + devfreq_suspend_device(dmcfreq->devfreq); ditto. you need to check the return value. > + > + return 0; > +} > + > +static __maybe_unused int rk3399_dmcfreq_resume(struct device *dev) > +{ > + struct platform_device *pdev = container_of(dev, > + struct platform_device, > + dev); > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); ditto. > + > + devfreq_event_enable_edev(dmcfreq->edev); > + devfreq_resume_device(dmcfreq->devfreq); ditto. > + > + return 0; > +} > + > +static SIMPLE_DEV_PM_OPS(rk3399_dmcfreq_pm, rk3399_dmcfreq_suspend, > + rk3399_dmcfreq_resume); > + > +static irqreturn_t rk3399_dmc_irq(int irq, void *dev_id) > +{ > + struct rk3399_dmcfreq *dmcfreq = dev_id; > + struct arm_smccc_res res; > + > + dmcfreq->wait_dcf_flag = 0; > + wake_up(&dmcfreq->wait_dcf_queue); > + > + /* clr dcf irq */ s/ clr dcf irq -> "Clear the DCF Interrupt" > + arm_smccc_smc(SIP_DDR_FREQ, 0, 0, CONFIG_DRAM_CLR_IRQ, > + 0, 0, 0, 0, &res); > + > + return IRQ_HANDLED; > +} > + > +static int of_do_get_timing(struct device_node *np, > + struct dram_timing *timing) > +{ > + int ret; > + > + ret = of_property_read_u32(np, "ddr3_speed_bin", > + &timing->ddr3_speed_bin); > + ret |= of_property_read_u32(np, "pd_idle", &timing->pd_idle); > + ret |= of_property_read_u32(np, "sr_idle", &timing->sr_idle); > + ret |= of_property_read_u32(np, "sr_mc_gate_idle", > + &timing->sr_mc_gate_idle); > + ret |= of_property_read_u32(np, "srpd_lite_idle", > + &timing->srpd_lite_idle); > + ret |= of_property_read_u32(np, "standby_idle", &timing->standby_idle); > + ret |= of_property_read_u32(np, "dram_dll_dis_freq", > + &timing->dram_dll_dis_freq); > + ret |= of_property_read_u32(np, "phy_dll_dis_freq", > + &timing->phy_dll_dis_freq); > + ret |= of_property_read_u32(np, "ddr3_odt_dis_freq", > + &timing->ddr3_odt_dis_freq); > + ret |= of_property_read_u32(np, "ddr3_drv", &timing->ddr3_drv); > + ret |= of_property_read_u32(np, "ddr3_odt", &timing->ddr3_odt); > + ret |= of_property_read_u32(np, "phy_ddr3_ca_drv", > + &timing->phy_ddr3_ca_drv); > + ret |= of_property_read_u32(np, "phy_ddr3_dq_drv", > + &timing->phy_ddr3_dq_drv); > + ret |= of_property_read_u32(np, "phy_ddr3_odt", &timing->phy_ddr3_odt); > + ret |= of_property_read_u32(np, "lpddr3_odt_dis_freq", > + &timing->lpddr3_odt_dis_freq); > + ret |= of_property_read_u32(np, "lpddr3_drv", &timing->lpddr3_drv); > + ret |= of_property_read_u32(np, "lpddr3_odt", &timing->lpddr3_odt); > + ret |= of_property_read_u32(np, "phy_lpddr3_ca_drv", > + &timing->phy_lpddr3_ca_drv); > + ret |= of_property_read_u32(np, "phy_lpddr3_dq_drv", > + &timing->phy_lpddr3_dq_drv); > + ret |= of_property_read_u32(np, "phy_lpddr3_odt", > + &timing->phy_lpddr3_odt); > + ret |= of_property_read_u32(np, "lpddr4_odt_dis_freq", > + &timing->lpddr4_odt_dis_freq); > + ret |= of_property_read_u32(np, "lpddr4_drv", > + &timing->lpddr4_drv); > + ret |= of_property_read_u32(np, "lpddr4_dq_odt", > + &timing->lpddr4_dq_odt); > + ret |= of_property_read_u32(np, "lpddr4_ca_odt", > + &timing->lpddr4_ca_odt); > + ret |= of_property_read_u32(np, "phy_lpddr4_ca_drv", > + &timing->phy_lpddr4_ca_drv); > + ret |= of_property_read_u32(np, "phy_lpddr4_ck_cs_drv", > + &timing->phy_lpddr4_ck_cs_drv); > + ret |= of_property_read_u32(np, "phy_lpddr4_dq_drv", > + &timing->phy_lpddr4_dq_drv); > + ret |= of_property_read_u32(np, "phy_lpddr4_odt", > + &timing->phy_lpddr4_odt); > + > + return ret; > +} > + > +static struct dram_timing *of_get_ddr_timings(struct device *dev, > + struct device_node *np) > +{ > + struct dram_timing *timing = NULL; > + struct device_node *np_tim; > + > + np_tim = of_parse_phandle(np, "ddr_timing", 0); As I already mentioned, you need to add the detailed documetation about the property. > + if (np_tim) { > + timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); > + if (!timing) > + goto err; > + if (of_do_get_timing(np_tim, timing)) { I recommend that you better to squash following two functions because of_do_get_timing() is not used on other point of this driver. - of_do_get_timing() - of_get_ddr_timings() > + devm_kfree(dev, timing); > + goto err; > + } You're missing the 'of_node_put'. of_node_put(np_tim); > + return timing; > + } > + > +err: > + if (timing) { > + devm_kfree(dev, timing); > + timing = NULL; > + } > + ditto. of_node_put(np_tim); > + return timing; > +} > + > +static int rk3399_dmcfreq_probe(struct platform_device *pdev) > +{ > + struct arm_smccc_res res; > + struct device *dev = &pdev->dev; > + struct device_node *np = pdev->dev.of_node; > + uint64_t param = 0; > + struct rk3399_dmcfreq *data; > + int ret, irq, index; > + uint32_t *timing; > + > + irq = platform_get_irq(pdev, 0); > + if (irq < 0) { > + dev_err(&pdev->dev, "no dmc irq resource\n"); We need to maintain the consistent expression for error log. dev_err(&pdev->dev, ""Cannot get the interrupt resource"\n"); > + return -EINVAL; > + } > + data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + mutex_init(&data->lock); > + > + data->vdd_center = devm_regulator_get(dev, "center"); > + if (IS_ERR(data->vdd_center)) { > + dev_err(dev, "Cannot get the regulator \"center\"\n"); > + return PTR_ERR(data->vdd_center); > + } > + > + data->dmc_clk = devm_clk_get(dev, "dmc_clk"); > + if (IS_ERR(data->dmc_clk)) { > + dev_err(dev, "Cannot get the clk dmc_clk\n"); > + return PTR_ERR(data->dmc_clk); > + }; > + > + data->irq = irq; > + ret = devm_request_irq(dev, irq, rk3399_dmc_irq, 0, > + dev_name(dev), data); > + if (ret) { > + dev_err(dev, "failed to request dmc irq: %d\n", ret); ditto. "Failed to request the dmc irq" or "Cannot request the dmc irq" > + return ret; > + } > + > + /* get dram timing and pass it to bl31 */ I want to add the more detailed description why this code is necessary. Because the SMC is usually black box. So, If you add the more explanation, it help people to understand this code. > + data->timing = of_get_ddr_timings(dev, np); > + if (data->timing) { > + timing = (uint32_t *)data->timing; > + for (index = 0; index < (sizeof(struct dram_timing) / 4); > + index++) { You better to use following code. It is better way to use the only one line for 'for' statement. size = sizeof(struct dram_timing) / 4; for (index = 0; index < size; index++) { > + param = index; > + param = param << 32 | *timing++; > + arm_smccc_smc(SIP_DDR_FREQ, param, 0, > + CONFIG_DRAM_SET_PARAM, 0, 0, 0, 0, &res); > + if (res.a0) { > + dev_err(dev, "failed to set dram param: %ld\n", > + res.a0); > + return -EINVAL; > + } > + param = 0; > + } > + } > + > + arm_smccc_smc(SIP_DDR_FREQ, 0, 0, CONFIG_DRAM_INIT, > + 0, 0, 0, 0, &res); ditto. You need to add the description. > + > + init_waitqueue_head(&data->wait_dcf_queue); > + data->wait_dcf_flag = 0; > + > + data->edev = devfreq_event_get_edev_by_phandle(dev, 0); > + if (IS_ERR(data->edev)) > + return -EPROBE_DEFER; > + > + ret = devfreq_event_enable_edev(data->edev); > + if (ret < 0) { > + dev_err(dev, "failed to enable devfreq-event devices\n"); s/failed/Failed. Use a capital letter for the first char. > + return ret; > + } > + > + /* > + * We add a devfreq driver to our parent since it has a device tree node > + * with operating points. > + */ You should wrap the rcu lock before calling the dev_pm_opp_of_add_table(). > + if (dev_pm_opp_of_add_table(dev)) { > + dev_err(dev, "Invalid operating-points in device tree.\n"); > + return -EINVAL; > + } > + of_property_read_u32(np, "upthreshold", > + &data->ondemand_data.upthreshold); > + of_property_read_u32(np, "downdifferential", > + &data->ondemand_data.downdifferential); Need one blank line. Maybe this code to get the properfy for ondemand governor, the devfreq will support in the future. > + data->rate = clk_get_rate(data->dmc_clk); > + rk3399_devfreq_dmc_profile.initial_freq = data->rate; Need one blank line. > + data->devfreq = devfreq_add_device(dev, > + &rk3399_devfreq_dmc_profile, > + "simple_ondemand", > + &data->ondemand_data); > + if (IS_ERR(data->devfreq)) > + return PTR_ERR(data->devfreq); > + devfreq_register_opp_notifier(dev, data->devfreq); Use the devm_devfreq_register_opp_notifier(). > + > + data->dev = dev; > + platform_set_drvdata(pdev, data); > + > + return 0; > +} > + > +static int rk3399_dmcfreq_remove(struct platform_device *pdev) > +{ > + struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); > + > + devfreq_remove_device(dmcfreq->devfreq); > + regulator_put(dmcfreq->vdd_center); > + > + return 0; > +} > + > +static const struct of_device_id rk3399dmc_devfreq_of_match[] = { > + { .compatible = "rockchip,rk3399-dmc" }, > + { }, > +}; > + > +static struct platform_driver rk3399_dmcfreq_driver = { > + .probe = rk3399_dmcfreq_probe, > + .remove = rk3399_dmcfreq_remove, > + .driver = { > + .name = "rk3399-dmc-freq", > + .pm = &rk3399_dmcfreq_pm, > + .of_match_table = rk3399dmc_devfreq_of_match, > + }, > +}; > +module_platform_driver(rk3399_dmcfreq_driver); > + > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("RK3399 dmcfreq driver with devfreq framework"); You need to add the MODULE_AUTHOR information. Regards, Chanwoo Choi