From mboxrd@z Thu Jan 1 00:00:00 1970 From: hl Subject: Re: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc Date: Tue, 2 Aug 2016 09:03:32 +0800 Message-ID: <579FF164.2000907@rock-chips.com> References: <1469779021-10426-1-git-send-email-hl@rock-chips.com> <1469779021-10426-7-git-send-email-hl@rock-chips.com> <579F2445.1020200@samsung.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8"; Format="flowed" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <579F2445.1020200-Sze3O3UU22JBDgjK7y7TUQ@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: Chanwoo Choi , 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 SGkgQ2hhbndvbyBDaG9pLAoKICAgICBUaGFua3MgZm9yIHJldmlld2luZyBzbyBjYXJlZnVsbHku IEFuZCBpIGhhdmUgc29tZSBxdWVzdGlvbjoKCk9uIDIwMTblubQwOOaciDAx5pelIDE4OjI4LCBD aGFud29vIENob2kgd3JvdGU6Cj4gSGkgTGluLAo+Cj4gQXMgSSBtZW50aW9uZWQgb24gcGF0Y2g1 LCB5b3UgYmV0dGVyIHRvIG1ha2UgdGhlIGRvY3VtZW50YXRpb24gYXMgZm9sbG93aW5nOgo+IC0g RG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL2RldmZyZXEvcmszMzk5X2RtYy50eHQK PiBBbmQsIEkgYWRkIHRoZSBjb21tZW50cy4KPgo+Cj4gT24gMjAxNuuFhCAwN+yblCAyOeydvCAx Njo1NywgTGluIEh1YW5nIHdyb3RlOgo+PiBiYXNlIG9uIGRmaSByZXN1bHQsIHdlIGRvIGRkciBm cmVxdWVuY3kgc2NhbGluZywgcmVnaXN0ZXIKPj4gZG1jIGRyaXZlciB0byBkZXZmcmVxIGZyYW1l d29yaywgYW5kIHVzZSBzaW1wbGUtb25kZW1hbmQKPj4gcG9saWN5Lgo+Pgo+PiBTaWduZWQtb2Zm LWJ5OiBMaW4gSHVhbmcgPGhsQHJvY2stY2hpcHMuY29tPgo+PiAtLS0KPj4gQ2hhbmdlcyBpbiB2 NDoKPj4gLSB1c2UgYXJtX3NtY2NjX3NtYygpIGZ1bmN0aW9uIHRhbGsgdG8gYmwzMQo+PiAtIGRl bGV0ZSByb2NrY2hpcF9kbWMuYyBmaWxlIGFuZCBjb25maWcKPj4gLSBkZWxldGUgZG1jX25vdGlm eQo+PiAtIGFkanVzdCBwcm9iZSBvcmRlcgo+PiAgIAo+PiBDaGFuZ2VzIGluIHYzOgo+PiAtIG9w ZXJhdGUgZHJhbSBzZXR0aW5nIHRocm91Z2ggc2lwIGNhbGwKPj4gLSBpbXBvcnZlIHNldCByYXRl IGZsb3cKPj4KPj4gQ2hhbmdlcyBpbiB2MjoKPj4gLSBOb25lCj4+ICAgCj4+IENoYW5nZXMgaW4g djE6Cj4+IC0gbW92ZSBkZmkgY29udHJvbGxlciB0byBldmVudAo+PiAtIGZpeCBzZXQgdm9sdGFn ZSBzZXF1ZW5jZSB3aGVuIHNldCByYXRlIGZhaWwKPj4gLSBjaGFuZ2UgS2NvbmZpZyB0eXBlIGZy b20gdHJpc3RhdGUgdG8gYm9vbAo+PiAtIG1vdmUgdW51c2UgRVhQT1JUX1NZTUJPTF9HUEwoKQo+ Pgo+PiAgIGRyaXZlcnMvZGV2ZnJlcS9LY29uZmlnICAgICAgICAgICAgICAgfCAgIDEgKwo+PiAg IGRyaXZlcnMvZGV2ZnJlcS9NYWtlZmlsZSAgICAgICAgICAgICAgfCAgIDEgKwo+PiAgIGRyaXZl cnMvZGV2ZnJlcS9yb2NrY2hpcC9LY29uZmlnICAgICAgfCAgIDggKwo+PiAgIGRyaXZlcnMvZGV2 ZnJlcS9yb2NrY2hpcC9NYWtlZmlsZSAgICAgfCAgIDEgKwo+PiAgIGRyaXZlcnMvZGV2ZnJlcS9y b2NrY2hpcC9yazMzOTlfZG1jLmMgfCA0NzMgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr KysrKwo+PiAgIDUgZmlsZXMgY2hhbmdlZCwgNDg0IGluc2VydGlvbnMoKykKPj4gICBjcmVhdGUg bW9kZSAxMDA2NDQgZHJpdmVycy9kZXZmcmVxL3JvY2tjaGlwL0tjb25maWcKPj4gICBjcmVhdGUg bW9kZSAxMDA2NDQgZHJpdmVycy9kZXZmcmVxL3JvY2tjaGlwL01ha2VmaWxlCj4+ICAgY3JlYXRl IG1vZGUgMTAwNjQ0IGRyaXZlcnMvZGV2ZnJlcS9yb2NrY2hpcC9yazMzOTlfZG1jLmMKPj4KPj4g ZGlmZiAtLWdpdCBhL2RyaXZlcnMvZGV2ZnJlcS9LY29uZmlnIGIvZHJpdmVycy9kZXZmcmVxL0tj b25maWcKPj4gaW5kZXggNjQyODFiYi4uYWNiMmE1NyAxMDA2NDQKPj4gLS0tIGEvZHJpdmVycy9k ZXZmcmVxL0tjb25maWcKPj4gKysrIGIvZHJpdmVycy9kZXZmcmVxL0tjb25maWcKPj4gQEAgLTk5 LDUgKzk5LDYgQEAgY29uZmlnIEFSTV9URUdSQV9ERVZGUkVRCj4+ICAgICAgICAgICAgb3BlcmF0 aW5nIGZyZXF1ZW5jaWVzIGFuZCB2b2x0YWdlcyB3aXRoIE9QUCBzdXBwb3J0Lgo+PiAgIAo+PiAg IHNvdXJjZSAiZHJpdmVycy9kZXZmcmVxL2V2ZW50L0tjb25maWciCj4+ICtzb3VyY2UgImRyaXZl cnMvZGV2ZnJlcS9yb2NrY2hpcC9LY29uZmlnIgo+IFRoaXMgcGF0Y2ggaW5jbHVkZSB0aGUgb25s eSBvbmUgcGF0Y2guIFNvLCBJIHRoaW5rIHRoYXQKPiB5b3UgZG9uJ3QgbmVlZCB0byBjcmVhdGUg dGhlICdyb2NrY2hpcCcgZGlyZWN0b3J5Lgo+Cj4+ICAgCj4+ICAgZW5kaWYgIyBQTV9ERVZGUkVR Cj4+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2RldmZyZXEvTWFrZWZpbGUgYi9kcml2ZXJzL2RldmZy ZXEvTWFrZWZpbGUKPj4gaW5kZXggNTEzNGY5ZS4uZDg0NGUyMyAxMDA2NDQKPj4gLS0tIGEvZHJp dmVycy9kZXZmcmVxL01ha2VmaWxlCj4+ICsrKyBiL2RyaXZlcnMvZGV2ZnJlcS9NYWtlZmlsZQo+ PiBAQCAtOSw2ICs5LDcgQEAgb2JqLSQoQ09ORklHX0RFVkZSRVFfR09WX1VTRVJTUEFDRSkJKz0g Z292ZXJub3JfdXNlcnNwYWNlLm8KPj4gICBvYmotJChDT05GSUdfQVJNX0VYWU5PUzRfQlVTX0RF VkZSRVEpCSs9IGV4eW5vcy8KPj4gICBvYmotJChDT05GSUdfQVJNX0VYWU5PUzVfQlVTX0RFVkZS RVEpCSs9IGV4eW5vcy8KPj4gICBvYmotJChDT05GSUdfQVJNX1RFR1JBX0RFVkZSRVEpCQkrPSB0 ZWdyYS1kZXZmcmVxLm8KPj4gK29iai0kKENPTkZJR19BUkNIX1JPQ0tDSElQKQkJKz0gcm9ja2No aXAvCj4gZGl0dG8uCj4KPj4gICAKPj4gICAjIERFVkZSRVEgRXZlbnQgRHJpdmVycwo+PiAgIG9i ai0kKENPTkZJR19QTV9ERVZGUkVRX0VWRU5UKQkJKz0gZXZlbnQvCj4+IGRpZmYgLS1naXQgYS9k cml2ZXJzL2RldmZyZXEvcm9ja2NoaXAvS2NvbmZpZyBiL2RyaXZlcnMvZGV2ZnJlcS9yb2NrY2hp cC9LY29uZmlnCj4+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4+IGluZGV4IDAwMDAwMDAuLmQ4Zjll NjYKPj4gLS0tIC9kZXYvbnVsbAo+PiArKysgYi9kcml2ZXJzL2RldmZyZXEvcm9ja2NoaXAvS2Nv bmZpZwo+PiBAQCAtMCwwICsxLDggQEAKPj4gK2NvbmZpZyBBUk1fUkszMzk5X0RNQ19ERVZGUkVR Cj4+ICsJdHJpc3RhdGUgIkFSTSBSSzMzOTkgRE1DIERFVkZSRVEgRHJpdmVyIgo+PiArCXNlbGVj dCBQTV9PUFAKPj4gKwlzZWxlY3QgREVWRlJFUV9HT1ZfU0lNUExFX09OREVNQU5ECj4+ICsJaGVs cAo+PiArICAgICAgICAgIFRoaXMgYWRkcyB0aGUgREVWRlJFUSBkcml2ZXIgZm9yIHRoZSBSSzMz OTkgZG1jLiBJdCBzZXRzIHRoZSBmcmVxdWVuY3kKPiBJZiB5b3UgYWRkIHRoZSBmdWxsIGRlc2Ny aXB0aW9uIGZvciAnZG1jJyBhcyBmb2xsb3dpbmcsCj4gaXQgaXMgZWFzeSB0byB1bmRlcnN0YW5k IHRoZSBvcGVyYXRpb24gb2YgdGhpcyBkZXZpY2UgZHJpdmVyLgo+IC0gRE1DIChEeW5hbWljIE1l bW9yeSBDb250cm9sbGVyKQo+Cj4+ICsgICAgICAgICAgZm9yIHRoZSBtZW1vcnkgY29udHJvbGxl ciBhbmQgcmVhZHMgdGhlIHVzYWdlIGNvdW50cyBmcm9tIGhhcmR3YXJlLgo+PiArCj4+IGRpZmYg LS1naXQgYS9kcml2ZXJzL2RldmZyZXEvcm9ja2NoaXAvTWFrZWZpbGUgYi9kcml2ZXJzL2RldmZy ZXEvcm9ja2NoaXAvTWFrZWZpbGUKPj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPj4gaW5kZXggMDAw MDAwMC4uYzYyYzEwNQo+PiAtLS0gL2Rldi9udWxsCj4+ICsrKyBiL2RyaXZlcnMvZGV2ZnJlcS9y b2NrY2hpcC9NYWtlZmlsZQo+PiBAQCAtMCwwICsxIEBACj4+ICtvYmotJChDT05GSUdfQVJNX1JL MzM5OV9ETUNfREVWRlJFUSkJKz0gcmszMzk5X2RtYy5vCj4+IGRpZmYgLS1naXQgYS9kcml2ZXJz L2RldmZyZXEvcm9ja2NoaXAvcmszMzk5X2RtYy5jIGIvZHJpdmVycy9kZXZmcmVxL3JvY2tjaGlw L3JrMzM5OV9kbWMuYwo+PiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+PiBpbmRleCAwMDAwMDAwLi41 MjdhYTExCj4+IC0tLSAvZGV2L251bGwKPj4gKysrIGIvZHJpdmVycy9kZXZmcmVxL3JvY2tjaGlw L3JrMzM5OV9kbWMuYwo+PiBAQCAtMCwwICsxLDQ3MyBAQAo+PiArLyoKPj4gKyAqIENvcHlyaWdo dCAoYykgMjAxNiwgRnV6aG91IFJvY2tjaGlwIEVsZWN0cm9uaWNzIENvLiwgTHRkCj4gWW91IG1p c3MgdGhlICcuJyBhdCB0aGUgZW5kIG9mIHRoZSBjb3B5bGlnaHQuCj4gV2hlbiB5b3UgdXNlIGFu IGFiYnJldmlhdGlvbiwgeW91IHNob3VsZCBhZGQgJy4nIGZvciBMdGQuCj4gLSBzL0x0ZC9MdGQu Cj4KPgo+PiArICogQXV0aG9yOiBMaW4gSHVhbmcgPGhsQHJvY2stY2hpcHMuY29tPgo+PiArICoK Pj4gKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0 ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0Cj4+ICsgKiB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv bnMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLAo+PiArICogdmVyc2lvbiAyLCBh cyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbi4KPj4gKyAqCj4+ICsg KiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgaXQgd2lsbCBiZSB1c2Vm dWwsIGJ1dCBXSVRIT1VUCj4+ICsgKiBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1w bGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFkgb3IKPj4gKyAqIEZJVE5FU1MgRk9SIEEg UEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBm b3IKPj4gKyAqIG1vcmUgZGV0YWlscy4KPj4gKyAqLwo+PiArCj4+ICsjaW5jbHVkZSA8bGludXgv YXJtLXNtY2NjLmg+Cj4+ICsjaW5jbHVkZSA8bGludXgvY2xrLmg+Cj4+ICsjaW5jbHVkZSA8bGlu dXgvY29tcGxldGlvbi5oPgo+IFlvdSBkb24ndCBuZWVkIHRvIGluY2x1ZGUgdGhlICJjb21wbGV0 aW9uLmgiLgo+IFdpdGhvdXQgImNvbXBsZXRpb24uaCIsIHRoZSBidWlsZCBpcyB3b3JraW5nLgo+ Cj4+ICsjaW5jbHVkZSA8bGludXgvZGVsYXkuaD4KPj4gKyNpbmNsdWRlIDxsaW51eC9kZXZmcmVx Lmg+Cj4+ICsjaW5jbHVkZSA8bGludXgvZGV2ZnJlcS1ldmVudC5oPgo+PiArI2luY2x1ZGUgPGxp bnV4L2ludGVycnVwdC5oPgo+PiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgo+PiArI2luY2x1 ZGUgPGxpbnV4L29mLmg+Cj4+ICsjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1fZGV2aWNlLmg+Cj4+ ICsjaW5jbHVkZSA8bGludXgvcG1fb3BwLmg+Cj4+ICsjaW5jbHVkZSA8bGludXgvcmVndWxhdG9y L2NvbnN1bWVyLmg+Cj4+ICsjaW5jbHVkZSA8bGludXgvcndzZW0uaD4KPj4gKyNpbmNsdWRlIDxs aW51eC9zdXNwZW5kLmg+Cj4+ICsjaW5jbHVkZSA8bGludXgvc3lzY29yZV9vcHMuaD4KPiBZb3Ug ZG9uJ3QgbmVlZCB0byBpbmNsdWRlIHRoZSAic3lzY29yZV9vcHMuaCIuCj4gV2l0aG91dCAic3lz Y29yZV9vcHMuaCIsIHRoZSBidWlsZCBpcyB3b3JraW5nLgo+Cj4+ICsKPj4gKyNpbmNsdWRlIDxz b2Mvcm9ja2NoaXAvcm9ja2NoaXBfc2lwLmg+Cj4+ICsKPj4gK3N0cnVjdCBkcmFtX3RpbWluZyB7 Cj4+ICsJdW5zaWduZWQgaW50IGRkcjNfc3BlZWRfYmluOwo+PiArCXVuc2lnbmVkIGludCBwZF9p ZGxlOwo+PiArCXVuc2lnbmVkIGludCBzcl9pZGxlOwo+PiArCXVuc2lnbmVkIGludCBzcl9tY19n YXRlX2lkbGU7Cj4+ICsJdW5zaWduZWQgaW50IHNycGRfbGl0ZV9pZGxlOwo+PiArCXVuc2lnbmVk IGludCBzdGFuZGJ5X2lkbGU7Cj4+ICsJdW5zaWduZWQgaW50IGRyYW1fZGxsX2Rpc19mcmVxOwo+ PiArCXVuc2lnbmVkIGludCBwaHlfZGxsX2Rpc19mcmVxOwo+PiArCXVuc2lnbmVkIGludCBkZHIz X29kdF9kaXNfZnJlcTsKPj4gKwl1bnNpZ25lZCBpbnQgZGRyM19kcnY7Cj4+ICsJdW5zaWduZWQg aW50IGRkcjNfb2R0Owo+PiArCXVuc2lnbmVkIGludCBwaHlfZGRyM19jYV9kcnY7Cj4+ICsJdW5z aWduZWQgaW50IHBoeV9kZHIzX2RxX2RydjsKPj4gKwl1bnNpZ25lZCBpbnQgcGh5X2RkcjNfb2R0 Owo+PiArCXVuc2lnbmVkIGludCBscGRkcjNfb2R0X2Rpc19mcmVxOwo+PiArCXVuc2lnbmVkIGlu dCBscGRkcjNfZHJ2Owo+PiArCXVuc2lnbmVkIGludCBscGRkcjNfb2R0Owo+PiArCXVuc2lnbmVk IGludCBwaHlfbHBkZHIzX2NhX2RydjsKPj4gKwl1bnNpZ25lZCBpbnQgcGh5X2xwZGRyM19kcV9k cnY7Cj4+ICsJdW5zaWduZWQgaW50IHBoeV9scGRkcjNfb2R0Owo+PiArCXVuc2lnbmVkIGludCBs cGRkcjRfb2R0X2Rpc19mcmVxOwo+PiArCXVuc2lnbmVkIGludCBscGRkcjRfZHJ2Owo+PiArCXVu c2lnbmVkIGludCBscGRkcjRfZHFfb2R0Owo+PiArCXVuc2lnbmVkIGludCBscGRkcjRfY2Ffb2R0 Owo+PiArCXVuc2lnbmVkIGludCBwaHlfbHBkZHI0X2NhX2RydjsKPj4gKwl1bnNpZ25lZCBpbnQg cGh5X2xwZGRyNF9ja19jc19kcnY7Cj4+ICsJdW5zaWduZWQgaW50IHBoeV9scGRkcjRfZHFfZHJ2 Owo+PiArCXVuc2lnbmVkIGludCBwaHlfbHBkZHI0X29kdDsKPj4gK307Cj4gVGhlIGRyYW1fdGlt aW5nIGlzIHVzZWQgZm9yIFNNQyAoU2VjdXJlIE1vbml0b3IgQ2FsbCk/Cj4gSSByZWNvbW1lbmQg dGhhdCB5b3UgYWRkIHRoZSBkZXRhaWxlZCBkZXNjcmlwdGlvbiBhYm91dCB0aGlzIHByb3BlcnR5 Cj4gb24gRG9jdW1lbnRhdGlvbi4KPgo+PiArCj4+ICtzdHJ1Y3QgcmszMzk5X2RtY2ZyZXEgewo+ PiArCXN0cnVjdCBkZXZpY2UgKmRldjsKPj4gKwlzdHJ1Y3QgZGV2ZnJlcSAqZGV2ZnJlcTsKPj4g KwlzdHJ1Y3QgZGV2ZnJlcV9zaW1wbGVfb25kZW1hbmRfZGF0YSBvbmRlbWFuZF9kYXRhOwo+PiAr CXN0cnVjdCBjbGsgKmRtY19jbGs7Cj4+ICsJc3RydWN0IGRldmZyZXFfZXZlbnRfZGV2ICplZGV2 Owo+PiArCXN0cnVjdCBtdXRleCBsb2NrOwo+PiArCXN0cnVjdCBkcmFtX3RpbWluZyAqdGltaW5n Owo+PiArCXdhaXRfcXVldWVfaGVhZF90CXdhaXRfZGNmX3F1ZXVlOwo+PiArCWludCBpcnE7Cj4+ ICsJaW50IHdhaXRfZGNmX2ZsYWc7Cj4gSSB3YW50IHRvIGFkZCB0aGUgZnVsbCBuYW1lIGFuZCBk ZXNjcmlwdGlvbiBvZiAnZGNmJy4KPiBJdCBpcyB1bmtub3duIHdvcmQuCj4KPj4gKwlzdHJ1Y3Qg cmVndWxhdG9yICp2ZGRfY2VudGVyOwo+PiArCXVuc2lnbmVkIGxvbmcgcmF0ZSwgdGFyZ2V0X3Jh dGU7Cj4+ICsJdW5zaWduZWQgbG9uZyB2b2x0LCB0YXJnZXRfdm9sdDsKPiBJIHRoaW5rIHRoYXQg aWYgeW91IGFkZCAnY3Vycl9vcHAnIHZhcmlhYmxlLAo+IHlvdSBjYW4gcmVkdWNlIHRoZSBjYWxs aW5nIG9mIGRldmZyZXFfcmVjb21tZW5kZWRfb3BwKCkgaW4gcmszMzk5X2RtY2ZyZXFfdGFyZ2V0 KCkKPiAJc3RydWN0IGRldl9wbV9vcHAgKmN1cnJfb3BwOwo+Cj4+ICt9Owo+PiArCj4+ICtzdGF0 aWMgaW50IHJrMzM5OV9kbWNmcmVxX3RhcmdldChzdHJ1Y3QgZGV2aWNlICpkZXYsIHVuc2lnbmVk IGxvbmcgKmZyZXEsCj4+ICsJCQkJIHUzMiBmbGFncykKPj4gK3sKPj4gKwlzdHJ1Y3QgcGxhdGZv cm1fZGV2aWNlICpwZGV2ID0gY29udGFpbmVyX29mKGRldiwgc3RydWN0IHBsYXRmb3JtX2Rldmlj ZSwKPj4gKwkJCQkJCSAgICBkZXYpOwo+PiArCXN0cnVjdCByazMzOTlfZG1jZnJlcSAqZG1jZnJl cSA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKHBkZXYpOwo+IFlvdSBjYW4gdXNlIHRoZSAnZGV2X2dl dF9kcnZkYXRhKCknIHRvIHNpbXBsaWZ5IGl0IGluc3RlYWQgb2YgJ3BsYXRmb3JtX2dldF9kcnZk YXRhKCknLgo+Cj4gCXN0cnVjdCByazMzOTlfZG1jZnJlcSAqZG1jZnJlcSA9IGRldl9nZXRfZHJ2 ZGF0YShkZXYpOwo+Cj4+ICsJc3RydWN0IGRldl9wbV9vcHAgKm9wcDsKPj4gKwl1bnNpZ25lZCBs b25nIG9sZF9jbGtfcmF0ZSA9IGRtY2ZyZXEtPnJhdGU7Cj4+ICsJdW5zaWduZWQgbG9uZyB0YXJn ZXRfdm9sdCwgdGFyZ2V0X3JhdGU7Cj4+ICsJaW50IGVycjsKPj4gKwo+PiArCXJjdV9yZWFkX2xv Y2soKTsKPj4gKwlvcHAgPSBkZXZmcmVxX3JlY29tbWVuZGVkX29wcChkZXYsIGZyZXEsIGZsYWdz KTsKPj4gKwlpZiAoSVNfRVJSKG9wcCkpIHsKPj4gKwkJcmN1X3JlYWRfdW5sb2NrKCk7Cj4+ICsJ CXJldHVybiBQVFJfRVJSKG9wcCk7Cj4+ICsJfQo+PiArCj4+ICsJdGFyZ2V0X3JhdGUgPSBkZXZf cG1fb3BwX2dldF9mcmVxKG9wcCk7Cj4+ICsJdGFyZ2V0X3ZvbHQgPSBkZXZfcG1fb3BwX2dldF92 b2x0YWdlKG9wcCk7Cj4+ICsJb3BwID0gZGV2ZnJlcV9yZWNvbW1lbmRlZF9vcHAoZGV2LCAmZG1j ZnJlcS0+cmF0ZSwgZmxhZ3MpOwo+PiArCWlmIChJU19FUlIob3BwKSkgewo+PiArCQlyY3VfcmVh ZF91bmxvY2soKTsKPj4gKwkJcmV0dXJuIFBUUl9FUlIob3BwKTsKPj4gKwl9Cj4+ICsJZG1jZnJl cS0+dm9sdCA9IGRldl9wbV9vcHBfZ2V0X3ZvbHRhZ2Uob3BwKTsKPiBJZiB5b3UgYWRkIHRoZSAn Y3Vycl9vcHAnIHZhcmlhYmxlIHRvIHN0cnVjdCByazMzOTlfZG1jZnJlcSwKPiB5b3UgY2FuIHJl bW92ZSB0aGUgY2FsbGluZyBvZiBkZXZmcmVxX3JlY29tbWVuZGVkX29wcCgpLgo+IAlkbWNmcmVx LT5yYXRlID0gZGV2X3BtX29wcF9nZXRfZnJlcShkbWNmcmVxLT5jdXJyX29wcCk7Cj4gCWRtY2Zy ZXEtPnZvbHQgPSBkZXZfcG1fb3BwX2dldF9mcmVxKGRtY2ZyZXEtPmN1cnJfb3BwKTsKPgo+IEJl Y2F1c2UgdGhlIGN1cnJlbnQgcmF0ZSBhbmQgdm9sdGFnZSBpcyBhbHJlYWR5IGRlY2lkZWQgb24g cHJldmlvdXMgcG9sbGluZyBjeWNsZSwKPiBTbyB3ZSBkb24ndCBuZWVkIHRvIGdldCB0aGUgb3Bw IHdpdGggZGV2ZnJlcV9yZWNvbW1lbmRlZF9vcHAoKS4KSSBwcmVmZXIgdGhlIHdheSBub3cgdXNl LCBzaW5jZSB3ZSBnZXQgdGhlIGRtY2ZyZXEtPnJhdGUgdXNlIApjbGtfZ2V0X3JhdGUoKSBhZnRl ciwKQmFzZSBvbiB0aGF0LCAgaSBkbyBub3QgY2FyZSB0aGUgc2V0X3JhdGUgc3VjY2VzcyBvciBm YWlsLiB1c2UgY3Vycl9vcHAgCmkgbmVlZCB0bwpjYXJlIGFib3V0IHNldF9yYXRlIHN0YXR1cywg d2hlbiBmYWlsLCBpIG11c3Qgc2V0IHNvbWUgcmF0ZSwgd2hlbiAKc3VjY2VzcyBpIG11c3QKc2V0 IG90aGVyIHJhdGUuCj4+ICsJcmN1X3JlYWRfdW5sb2NrKCk7Cj4+ICsKPj4gKwlpZiAoZG1jZnJl cS0+cmF0ZSA9PSB0YXJnZXRfcmF0ZSkKPj4gKwkJcmV0dXJuIDA7Cj4+ICsKPj4gKwltdXRleF9s b2NrKCZkbWNmcmVxLT5sb2NrKTsKPj4gKwo+PiArCS8qCj4+ICsJICogaWYgZnJlcXVlbmN5IHNj YWxpbmcgZnJvbSBsb3cgdG8gaGlnaCwgYWRqdXN0IHZvbHRhZ2UgZmlyc3Q7Cj4+ICsJICogaWYg ZnJlcXVlbmN5IHNjYWxpbmcgZnJvbSBoaWdoIHRvIGxvdywgYWRqdXNldCBmcmVxdWVuY3kgZmly c3Q7Cj4+ICsJICovCj4gcy9hZGp1c2V0L2FkanVzdAo+Cj4gSSByZWNvbW1lbmQgdGhhdCB5b3Ug dXNlIGEgY2FwdGl0YWwgbGV0dGVyIGZvciBmaXJzdCBjaGFyYWN0ZXIgYW5kIHVzZSB0aGUgJy4n Cj4gaW5zdGVhZCBvZiAnOycuCj4KPj4gKwlpZiAob2xkX2Nsa19yYXRlIDwgdGFyZ2V0X3JhdGUp IHsKPj4gKwkJZXJyID0gcmVndWxhdG9yX3NldF92b2x0YWdlKGRtY2ZyZXEtPnZkZF9jZW50ZXIs IHRhcmdldF92b2x0LAo+PiArCQkJCQkgICAgdGFyZ2V0X3ZvbHQpOwo+PiArCQlpZiAoZXJyKSB7 Cj4+ICsJCQlkZXZfZXJyKGRldiwgIlVuYWJsZSB0byBzZXQgdm9sICVsdVxuIiwgdGFyZ2V0X3Zv bHQpOwo+IFRvIHJlYWRhYmlsaXR5LCB5b3UgYmV0dGVyIHRvIHVzZSB0aGUgY29ycmVudCB3b3Jk IHRvIHBhc3MgdGhlIHByZWNpc2UgdGhlIGxvZyBtZXNzYWdlLgo+IC0gcy92b2wvdm9sdGFnZQo+ Cj4gQW5kLCB0aGlzIHBhdGNoIHVzZXMgdGhlICdVbmFibGUgdG8nIG9yICdDYW5ub3QnIHRvIHNo b3cgdGhlIGVycm9yIGxvZy4KPiBJIHJlY29tbWVuZCB0aGF0IHlvdSB1c2UgdGhlIGNvbnNpc3Rl bnQgZXhwcmVzc2lvbiBpZiB0aGVyZSBpcyBub3QgYW55IHNwZWNpZmljIHJlYXNvbi4KPgo+IAlk ZXZfZXJyKGRldiwgIkNhbm5vdCBzZXQgdGhlIHZvbHRhZ2UgJWx1IHVWXG4iLCB0YXJnZXRfdm9s dCk7Cj4KPj4gKwkJCWdvdG8gb3V0Owo+PiArCQl9Cj4+ICsJfQo+PiArCWRtY2ZyZXEtPndhaXRf ZGNmX2ZsYWcgPSAxOwo+PiArCWVyciA9IGNsa19zZXRfcmF0ZShkbWNmcmVxLT5kbWNfY2xrLCB0 YXJnZXRfcmF0ZSk7Cj4+ICsJaWYgKGVycikgewo+PiArCQlkZXZfZXJyKGRldiwKPj4gKwkJCSJV bmFibGUgdG8gc2V0IGZyZXEgJWx1LiBDdXJyZW50IGZyZXEgJWx1LiBFcnJvciAlZFxuIiwKPj4g KwkJCXRhcmdldF9yYXRlLCBvbGRfY2xrX3JhdGUsIGVycik7Cj4gCWRldl9lcnIoZGV2LCAiQ2Fu bm90IHNldCB0aGUgZnJlcXVlbmN5ICVsdSAoJWQpXG4iLCB0YXJnZXRfcmF0ZSwgZXJyKTsKPgo+ PiArCQlyZWd1bGF0b3Jfc2V0X3ZvbHRhZ2UoZG1jZnJlcS0+dmRkX2NlbnRlciwgZG1jZnJlcS0+ dm9sdCwKPj4gKwkJCQkgICAgICBkbWNmcmVxLT52b2x0KTsKPj4gKwkJZ290byBvdXQ7Cj4+ICsJ fQo+PiArCj4+ICsJLyoKPj4gKwkgKiB3YWl0IHVudGlsIGJjZiBpcnEgaGFwcGVuLCBpdCBtZWFu cyBmcmVxIHNjYWxpbmcgZmluaXNoIGluIGJsMzEsCj4gZGl0dG8uCj4KPj4gKwkgKiB1c2UgMTAw bXMgYXMgdGltZW91dCB0aW1lCj4gcy90aW1lL3RpbWUuCj4KPj4gKwkgKi8KPj4gKwlpZiAoIXdh aXRfZXZlbnRfdGltZW91dChkbWNmcmVxLT53YWl0X2RjZl9xdWV1ZSwKPj4gKwkJCQkhZG1jZnJl cS0+d2FpdF9kY2ZfZmxhZywgSFogLyAxMCkpCj4+ICsJCWRldl93YXJuKGRldiwgIlRpbWVvdXQg d2FpdGluZyBmb3IgZGNmIGlycVxuIik7Cj4gSWYgdGhlIHRpbWVvdXQgaGFwcGVuLCBhcmUgdGhl cmUgYW55IHByb2JsZW0/CldoZW4gdGltZW91dCBoYXBwZW4gLCBtYXkgYmUgd2UgbWlzcyBpbnRl cnJ1cHQsIGJ1dCBpdCBkbyBub3QgYWZmZWN0IHRoaXMKcHJvY2Vzcywgc2luY2Ugd2Ugd2lsbCBj aGVjayB0aGUgcmF0ZSB3aGV0aGVyIHN1Y2Nlc3MgbGF0ZXIuCj4gQWZ0ZXIgc2V0dGluZyB0aGUg ZnJlcXVlbmN5IGFuZCB2b2x0YWdlLCBzdG9yZSB0aGUgY3VycmVudCBvcHAgZW50cnkgb24gLmN1 cnJfb3BwLgo+IAlkbWNmcmVxLT5jdXJyX29wcCA9IG9wcDsKPgo+PiArCS8qCj4+ICsJICogY2hl Y2sgdGhlIGRwbGwgcmF0ZQo+PiArCSAqIHRoZXJlIG9ubHkgdHdvIHJlc3VsdCB3ZSB3aWxsIGdl dCwKPj4gKwkgKiAxLiBkZHIgZnJlcXVlbmN5IHNjYWxpbmcgZmFpbCwgd2Ugc3RpbGwgZ2V0IHRo ZSBvbGQgcmF0ZQo+PiArCSAqIDIsIGRkciBmcmVxdWVuY3kgc2NhbGluZyBzdWNlc3NmdWwsIHdl IGdldCB0aGUgcmF0ZSB3ZSBzZXQKPj4gKwkgKi8KPj4gKwlkbWNmcmVxLT5yYXRlID0gY2xrX2dl dF9yYXRlKGRtY2ZyZXEtPmRtY19jbGspOwo+PiArCj4+ICsJLyogaWYgZ2V0IHRoZSBpbmNvcnJl Y3QgcmF0ZSwgc2V0IHZvbHRhZ2UgdG8gb2xkIHZhbHVlICovCj4+ICsJaWYgKGRtY2ZyZXEtPnJh dGUgIT0gdGFyZ2V0X3JhdGUpIHsKPj4gKwkJZGV2X2VycihkZXYsICJnZXQgd3JvbmcgZGRyIGZy ZXF1ZW5jeSwgUmVxdWVzdCBmcmVxICVsdSxcCj4+ICsJCQlDdXJyZW50IGZyZXEgJWx1XG4iLCB0 YXJnZXRfcmF0ZSwgZG1jZnJlcS0+cmF0ZSk7Cj4+ICsJCXJlZ3VsYXRvcl9zZXRfdm9sdGFnZShk bWNmcmVxLT52ZGRfY2VudGVyLCBkbWNmcmVxLT52b2x0LAo+PiArCQkJCSAgICAgIGRtY2ZyZXEt PnZvbHQpOwo+IFtXaXRob3V0IGZvcmNlLCBpdCBpcyBqdXN0IG15IG9waW9uIGFib3V0IHRoaXMg Y29kZTpdCj4gSSB0aGluayB0aGF0IHRoaXMgY2hlY2tpbmcgY29kZSBpdCBpcyB1bi1uZWVkZWQu Cj4gSWYgdGhpcyBjYXNlIG9jY3VyLCB0aGUgcmszMzk5X2RtYy5jIG5ldmVyIHNldCB0aGUgc3Bl Y2lmaWMgZnJlcXVlbmN5Cj4gYmVjYXVzZSB0aGUgcmszMzk5IGNsb2NrIGRvbid0IHN1cHBvcnQg dGhlIHNwZWNpZmljIGZyZXF1ZW5jeSBmb3IgcmszMzk5IGRtYy4KPgo+IElmIHlvdSB3YW50IHRv IHNldCB0aGUgY29ycmVjdCBmcmVxdWVuY3ksCj4gV2hlbiB2ZXJpZnlpbmcgdGhlIHJrMzM5OSBk bWMgZHJpdmVyLCB5b3Ugc2hvdWxkIGNoZWNrIHRoZSByazMzOTkgY2xvY2sgZHJpdmVyLgo+Cj4g QmFzaWNhbGx5LCBpZiB0aGUgdGhlIGNsb2NrIGRyaXZlciBkb24ndCBzdXBwb3J0IHRoZSBjb3Jy ZWN0IHNhbWUgZnJlcXVlbmN5ICwKPiBDQ0YoQ29tbW9uIENsb2NrIEZyYW1ld29yaykgc2V0IHRo ZSBjbG9zZSBmcmVxdWVuY3kuIEl0IGlzIG5vdCBhIGJhZCB0aGluZy4KTWF5IGJlIGkgc2hvdWxk IHJlbW92ZSB0aGUgcmVndWxhdG9yX3NldF92b2x0YWdlKCkgaGVyZSwgYnV0IHN0aWxsIG5lZWQg dG8KY2hlY2sgd2hldGhlciB3ZSBnZXQgdGhlIHJpZ2h0IGZyZXF1ZW5jeSwgc2luY2UgaWYgd2Ug ZG8gbm90IGdldCB0aGUgCnJpZ2h0IGZyZXF1ZW5jeSwKd2Ugc2hvdWxkIHNlbmQgYSB3YXJuIG1l c3NhZ2UsIHRvIHJlbWluZCB0aGF0IG1heWJlIHlvdSBwYXNzIGEgZnJlcXVlbmN5IAp3aGljaApk byBub3Qgc3VwcG9ydCBpbiBibDMxLgo+Cj4KPj4gKwl9IGVsc2UgaWYgKG9sZF9jbGtfcmF0ZSA+ IHRhcmdldF9yYXRlKQo+PiArCQllcnIgPSByZWd1bGF0b3Jfc2V0X3ZvbHRhZ2UoZG1jZnJlcS0+ dmRkX2NlbnRlciwgdGFyZ2V0X3ZvbHQsCj4+ICsJCQkJCSAgICB0YXJnZXRfdm9sdCk7Cj4+ICsJ aWYgKGVycikKPj4gKwkJZGV2X2VycihkZXYsICJVbmFibGUgdG8gc2V0IHZvbCAlbHVcbiIsIHRh cmdldF92b2x0KTsKPiAJCj4gZGl0dG8uIFlvdSBiZXR0ZXIgdG8gdXNlIHRoZSBjb25zaXN0ZW50 IGV4cHJlc3Npb24gZm9yIGVycm9yIGxvZyBhcyBmb2xsb3dpbmc6Cj4gCWRldl9lcnIoZGV2LCAi Q2Fubm90IHNldCB0aGUgdm9sdGFnZSAlbHUgdVZcbiIsIHRhcmdldF92b2x0KTsKPgo+Cj4+ICsK Pj4gK291dDoKPj4gKwltdXRleF91bmxvY2soJmRtY2ZyZXEtPmxvY2spOwo+PiArCXJldHVybiBl cnI7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBpbnQgcmszMzk5X2RtY2ZyZXFfZ2V0X2Rldl9zdGF0 dXMoc3RydWN0IGRldmljZSAqZGV2LAo+PiArCQkJCQkgc3RydWN0IGRldmZyZXFfZGV2X3N0YXR1 cyAqc3RhdCkKPj4gK3sKPj4gKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2ID0gY29udGFp bmVyX29mKGRldiwgc3RydWN0IHBsYXRmb3JtX2RldmljZSwKPj4gKwkJCQkJCSAgICBkZXYpOwo+ PiArCXN0cnVjdCByazMzOTlfZG1jZnJlcSAqZG1jZnJlcSA9IHBsYXRmb3JtX2dldF9kcnZkYXRh KHBkZXYpOwo+PiArCXN0cnVjdCBkZXZmcmVxX2V2ZW50X2RhdGEgZWRhdGE7Cj4gZGl0dG8uIFVz ZSB0aGUgZGV2X2dldF9kcnZkYXRhKGRldikuCj4KPj4gKwo+PiArCWRldmZyZXFfZXZlbnRfZ2V0 X2V2ZW50KGRtY2ZyZXEtPmVkZXYsICZlZGF0YSk7Cj4gWW91IG5lZWQgdG8gY2hlY2sgdGhlIHJl dHVybiB2YWx1ZSBmb3IgZXhjZXB0aW9uIGhhbmRsaW5nLgo+Cj4+ICsKPj4gKwlzdGF0LT5jdXJy ZW50X2ZyZXF1ZW5jeSA9IGRtY2ZyZXEtPnJhdGU7Cj4+ICsJc3RhdC0+YnVzeV90aW1lID0gZWRh dGEubG9hZF9jb3VudDsKPj4gKwlzdGF0LT50b3RhbF90aW1lID0gZWRhdGEudG90YWxfY291bnQ7 Cj4+ICsKPj4gKwlyZXR1cm4gMDsKPj4gK30KPj4gKwo+PiArc3RhdGljIGludCByazMzOTlfZG1j ZnJlcV9nZXRfY3VyX2ZyZXEoc3RydWN0IGRldmljZSAqZGV2LCB1bnNpZ25lZCBsb25nICpmcmVx KQo+PiArewo+PiArCXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYgPSBjb250YWluZXJfb2Yo ZGV2LCBzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlLAo+PiArCQkJCQkJICAgIGRldik7Cj4+ICsJc3Ry dWN0IHJrMzM5OV9kbWNmcmVxICpkbWNmcmVxID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRldik7 Cj4gZGl0dG8uIFVzZSB0aGUgZGV2X2dldF9kcnZkYXRhKGRldikuCj4KPj4gKwo+PiArCSpmcmVx ID0gZG1jZnJlcS0+cmF0ZTsKPj4gKwo+PiArCXJldHVybiAwOwo+PiArfQo+PiArCj4+ICtzdGF0 aWMgdm9pZCByazMzOTlfZG1jZnJlcV9leGl0KHN0cnVjdCBkZXZpY2UgKmRldikKPj4gK3sKPj4g KwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2ID0gY29udGFpbmVyX29mKGRldiwKPj4gKwkJ CQkJCSAgICBzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlLAo+PiArCQkJCQkJICAgIGRldik7Cj4+ICsJ c3RydWN0IHJrMzM5OV9kbWNmcmVxICpkbWNmcmVxID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRl dik7Cj4+ICsKPj4gKwlkZXZmcmVxX3VucmVnaXN0ZXJfb3BwX25vdGlmaWVyKGRldiwgZG1jZnJl cS0+ZGV2ZnJlcSk7Cj4gVXNlIHRoZSBkZXZtX2RldmZyZXFfcmVnaXN0ZXJfb3BwX25vdGlmaWVy KCkuIFlvdSBkb24ndCBuZWVkIHRvIGhhbmRsZSBpdC4KPgo+PiArfQo+PiArCj4+ICtzdGF0aWMg c3RydWN0IGRldmZyZXFfZGV2X3Byb2ZpbGUgcmszMzk5X2RldmZyZXFfZG1jX3Byb2ZpbGUgPSB7 Cj4+ICsJLnBvbGxpbmdfbXMJPSAyMDAsCj4+ICsJLnRhcmdldAkJPSByazMzOTlfZG1jZnJlcV90 YXJnZXQsCj4+ICsJLmdldF9kZXZfc3RhdHVzCT0gcmszMzk5X2RtY2ZyZXFfZ2V0X2Rldl9zdGF0 dXMsCj4+ICsJLmdldF9jdXJfZnJlcQk9IHJrMzM5OV9kbWNmcmVxX2dldF9jdXJfZnJlcSwKPj4g KwkuZXhpdAkJPSByazMzOTlfZG1jZnJlcV9leGl0LAo+PiArfTsKPj4gKwo+PiArc3RhdGljIF9f bWF5YmVfdW51c2VkIGludCByazMzOTlfZG1jZnJlcV9zdXNwZW5kKHN0cnVjdCBkZXZpY2UgKmRl dikKPj4gK3sKPj4gKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2ID0gY29udGFpbmVyX29m KGRldiwKPj4gKwkJCQkJCSAgICBzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlLAo+PiArCQkJCQkJICAg IGRldik7Cj4+ICsJc3RydWN0IHJrMzM5OV9kbWNmcmVxICpkbWNmcmVxID0gcGxhdGZvcm1fZ2V0 X2RydmRhdGEocGRldik7Cj4gZGl0dG8uIFVzZSB0aGUgZGV2X2dldF9kcnZkYXRhKGRldikuCj4K Pj4gKwo+PiArCWRldmZyZXFfZXZlbnRfZGlzYWJsZV9lZGV2KGRtY2ZyZXEtPmVkZXYpOwo+PiAr CWRldmZyZXFfc3VzcGVuZF9kZXZpY2UoZG1jZnJlcS0+ZGV2ZnJlcSk7Cj4gZGl0dG8uIHlvdSBu ZWVkIHRvIGNoZWNrIHRoZSByZXR1cm4gdmFsdWUuCj4KPj4gKwo+PiArCXJldHVybiAwOwo+PiAr fQo+PiArCj4+ICtzdGF0aWMgX19tYXliZV91bnVzZWQgaW50IHJrMzM5OV9kbWNmcmVxX3Jlc3Vt ZShzdHJ1Y3QgZGV2aWNlICpkZXYpCj4+ICt7Cj4+ICsJc3RydWN0IHBsYXRmb3JtX2RldmljZSAq cGRldiA9IGNvbnRhaW5lcl9vZihkZXYsCj4+ICsJCQkJCQkgICAgc3RydWN0IHBsYXRmb3JtX2Rl dmljZSwKPj4gKwkJCQkJCSAgICBkZXYpOwo+PiArCXN0cnVjdCByazMzOTlfZG1jZnJlcSAqZG1j ZnJlcSA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKHBkZXYpOwo+IGRpdHRvLgo+Cj4+ICsKPj4gKwlk ZXZmcmVxX2V2ZW50X2VuYWJsZV9lZGV2KGRtY2ZyZXEtPmVkZXYpOwo+PiArCWRldmZyZXFfcmVz dW1lX2RldmljZShkbWNmcmVxLT5kZXZmcmVxKTsKPiBkaXR0by4KPgo+PiArCj4+ICsJcmV0dXJu IDA7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBTSU1QTEVfREVWX1BNX09QUyhyazMzOTlfZG1jZnJl cV9wbSwgcmszMzk5X2RtY2ZyZXFfc3VzcGVuZCwKPj4gKwkJCSByazMzOTlfZG1jZnJlcV9yZXN1 bWUpOwo+PiArCj4+ICtzdGF0aWMgaXJxcmV0dXJuX3QgcmszMzk5X2RtY19pcnEoaW50IGlycSwg dm9pZCAqZGV2X2lkKQo+PiArewo+PiArCXN0cnVjdCByazMzOTlfZG1jZnJlcSAqZG1jZnJlcSA9 IGRldl9pZDsKPj4gKwlzdHJ1Y3QgYXJtX3NtY2NjX3JlcyByZXM7Cj4+ICsKPj4gKwlkbWNmcmVx LT53YWl0X2RjZl9mbGFnID0gMDsKPj4gKwl3YWtlX3VwKCZkbWNmcmVxLT53YWl0X2RjZl9xdWV1 ZSk7Cj4+ICsKPj4gKwkvKiBjbHIgZGNmIGlycSAqLwo+IHMvIGNsciBkY2YgaXJxIC0+ICJDbGVh ciB0aGUgRENGIEludGVycnVwdCIKPgo+PiArCWFybV9zbWNjY19zbWMoU0lQX0REUl9GUkVRLCAw LCAwLCBDT05GSUdfRFJBTV9DTFJfSVJRLAo+PiArCQkgICAgICAwLCAwLCAwLCAwLCAmcmVzKTsK Pj4gKwo+PiArCXJldHVybiBJUlFfSEFORExFRDsKPj4gK30KPj4gKwo+PiArc3RhdGljIGludCBv Zl9kb19nZXRfdGltaW5nKHN0cnVjdCBkZXZpY2Vfbm9kZSAqbnAsCj4+ICsJCXN0cnVjdCBkcmFt X3RpbWluZyAqdGltaW5nKQo+PiArewo+PiArCWludCByZXQ7Cj4+ICsKPj4gKwlyZXQgPSBvZl9w cm9wZXJ0eV9yZWFkX3UzMihucCwgImRkcjNfc3BlZWRfYmluIiwKPj4gKwkJCQkgICAmdGltaW5n LT5kZHIzX3NwZWVkX2Jpbik7Cj4+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAi cGRfaWRsZSIsICZ0aW1pbmctPnBkX2lkbGUpOwo+PiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFk X3UzMihucCwgInNyX2lkbGUiLCAmdGltaW5nLT5zcl9pZGxlKTsKPj4gKwlyZXQgfD0gb2ZfcHJv cGVydHlfcmVhZF91MzIobnAsICJzcl9tY19nYXRlX2lkbGUiLAo+PiArCQkJCSAgICAmdGltaW5n LT5zcl9tY19nYXRlX2lkbGUpOwo+PiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwg InNycGRfbGl0ZV9pZGxlIiwKPj4gKwkJCQkgICAgJnRpbWluZy0+c3JwZF9saXRlX2lkbGUpOwo+ PiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInN0YW5kYnlfaWRsZSIsICZ0aW1p bmctPnN0YW5kYnlfaWRsZSk7Cj4+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAi ZHJhbV9kbGxfZGlzX2ZyZXEiLAo+PiArCQkJCSAgICAmdGltaW5nLT5kcmFtX2RsbF9kaXNfZnJl cSk7Cj4+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAicGh5X2RsbF9kaXNfZnJl cSIsCj4+ICsJCQkJICAgICZ0aW1pbmctPnBoeV9kbGxfZGlzX2ZyZXEpOwo+PiArCXJldCB8PSBv Zl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgImRkcjNfb2R0X2Rpc19mcmVxIiwKPj4gKwkJCQkgICAg JnRpbWluZy0+ZGRyM19vZHRfZGlzX2ZyZXEpOwo+PiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFk X3UzMihucCwgImRkcjNfZHJ2IiwgJnRpbWluZy0+ZGRyM19kcnYpOwo+PiArCXJldCB8PSBvZl9w cm9wZXJ0eV9yZWFkX3UzMihucCwgImRkcjNfb2R0IiwgJnRpbWluZy0+ZGRyM19vZHQpOwo+PiAr CXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInBoeV9kZHIzX2NhX2RydiIsCj4+ICsJ CQkJICAgICZ0aW1pbmctPnBoeV9kZHIzX2NhX2Rydik7Cj4+ICsJcmV0IHw9IG9mX3Byb3BlcnR5 X3JlYWRfdTMyKG5wLCAicGh5X2RkcjNfZHFfZHJ2IiwKPj4gKwkJCQkgICAgJnRpbWluZy0+cGh5 X2RkcjNfZHFfZHJ2KTsKPj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJwaHlf ZGRyM19vZHQiLCAmdGltaW5nLT5waHlfZGRyM19vZHQpOwo+PiArCXJldCB8PSBvZl9wcm9wZXJ0 eV9yZWFkX3UzMihucCwgImxwZGRyM19vZHRfZGlzX2ZyZXEiLAo+PiArCQkJCSAgICAmdGltaW5n LT5scGRkcjNfb2R0X2Rpc19mcmVxKTsKPj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIo bnAsICJscGRkcjNfZHJ2IiwgJnRpbWluZy0+bHBkZHIzX2Rydik7Cj4+ICsJcmV0IHw9IG9mX3By b3BlcnR5X3JlYWRfdTMyKG5wLCAibHBkZHIzX29kdCIsICZ0aW1pbmctPmxwZGRyM19vZHQpOwo+ PiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInBoeV9scGRkcjNfY2FfZHJ2IiwK Pj4gKwkJCQkgICAgJnRpbWluZy0+cGh5X2xwZGRyM19jYV9kcnYpOwo+PiArCXJldCB8PSBvZl9w cm9wZXJ0eV9yZWFkX3UzMihucCwgInBoeV9scGRkcjNfZHFfZHJ2IiwKPj4gKwkJCQkgICAgJnRp bWluZy0+cGh5X2xwZGRyM19kcV9kcnYpOwo+PiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3Uz MihucCwgInBoeV9scGRkcjNfb2R0IiwKPj4gKwkJCQkgICAgJnRpbWluZy0+cGh5X2xwZGRyM19v ZHQpOwo+PiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgImxwZGRyNF9vZHRfZGlz X2ZyZXEiLAo+PiArCQkJCSAgICAmdGltaW5nLT5scGRkcjRfb2R0X2Rpc19mcmVxKTsKPj4gKwly ZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJscGRkcjRfZHJ2IiwKPj4gKwkJCQkgICAg JnRpbWluZy0+bHBkZHI0X2Rydik7Cj4+ICsJcmV0IHw9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKG5w LCAibHBkZHI0X2RxX29kdCIsCj4+ICsJCQkJICAgICZ0aW1pbmctPmxwZGRyNF9kcV9vZHQpOwo+ PiArCXJldCB8PSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgImxwZGRyNF9jYV9vZHQiLAo+PiAr CQkJCSAgICAmdGltaW5nLT5scGRkcjRfY2Ffb2R0KTsKPj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlf cmVhZF91MzIobnAsICJwaHlfbHBkZHI0X2NhX2RydiIsCj4+ICsJCQkJICAgICZ0aW1pbmctPnBo eV9scGRkcjRfY2FfZHJ2KTsKPj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJw aHlfbHBkZHI0X2NrX2NzX2RydiIsCj4+ICsJCQkJICAgICZ0aW1pbmctPnBoeV9scGRkcjRfY2tf Y3NfZHJ2KTsKPj4gKwlyZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJwaHlfbHBkZHI0 X2RxX2RydiIsCj4+ICsJCQkJICAgICZ0aW1pbmctPnBoeV9scGRkcjRfZHFfZHJ2KTsKPj4gKwly ZXQgfD0gb2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJwaHlfbHBkZHI0X29kdCIsCj4+ICsJCQkJ ICAgICZ0aW1pbmctPnBoeV9scGRkcjRfb2R0KTsKPj4gKwo+PiArCXJldHVybiByZXQ7Cj4+ICt9 Cj4+ICsKPj4gK3N0YXRpYyBzdHJ1Y3QgZHJhbV90aW1pbmcgKm9mX2dldF9kZHJfdGltaW5ncyhz dHJ1Y3QgZGV2aWNlICpkZXYsCj4+ICsJCQkJCSAgICAgIHN0cnVjdCBkZXZpY2Vfbm9kZSAqbnAp Cj4+ICt7Cj4+ICsJc3RydWN0IGRyYW1fdGltaW5nCSp0aW1pbmcgPSBOVUxMOwo+PiArCXN0cnVj dCBkZXZpY2Vfbm9kZQkqbnBfdGltOwo+PiArCj4+ICsJbnBfdGltID0gb2ZfcGFyc2VfcGhhbmRs ZShucCwgImRkcl90aW1pbmciLCAwKTsKPiBBcyBJIGFscmVhZHkgbWVudGlvbmVkLCB5b3UgbmVl ZCB0byBhZGQgdGhlIGRldGFpbGVkIGRvY3VtZXRhdGlvbiBhYm91dCB0aGUgcHJvcGVydHkuCj4K Pj4gKwlpZiAobnBfdGltKSB7Cj4+ICsJCXRpbWluZyA9IGRldm1fa3phbGxvYyhkZXYsIHNpemVv ZigqdGltaW5nKSwgR0ZQX0tFUk5FTCk7Cj4+ICsJCWlmICghdGltaW5nKQo+PiArCQkJZ290byBl cnI7Cj4+ICsJCWlmIChvZl9kb19nZXRfdGltaW5nKG5wX3RpbSwgdGltaW5nKSkgewo+IEkgcmVj b21tZW5kIHRoYXQgeW91IGJldHRlciB0byBzcXVhc2ggZm9sbG93aW5nIHR3byBmdW5jdGlvbnMK PiBiZWNhdXNlIG9mX2RvX2dldF90aW1pbmcoKSBpcyBub3QgdXNlZCBvbiBvdGhlciBwb2ludCBv ZiB0aGlzIGRyaXZlci4KPiAtIG9mX2RvX2dldF90aW1pbmcoKQo+IC0gb2ZfZ2V0X2Rkcl90aW1p bmdzKCkKPgo+PiArCQkJZGV2bV9rZnJlZShkZXYsIHRpbWluZyk7Cj4+ICsJCQlnb3RvIGVycjsK Pj4gKwkJfQo+IFlvdSdyZSBtaXNzaW5nIHRoZSAnb2Zfbm9kZV9wdXQnLgo+IAkJb2Zfbm9kZV9w dXQobnBfdGltKTsKPgo+PiArCQlyZXR1cm4gdGltaW5nOwo+PiArCX0KPj4gKwo+PiArZXJyOgo+ PiArCWlmICh0aW1pbmcpIHsKPj4gKwkJZGV2bV9rZnJlZShkZXYsIHRpbWluZyk7Cj4+ICsJCXRp bWluZyA9IE5VTEw7Cj4+ICsJfQo+PiArCj4gZGl0dG8uCj4gCW9mX25vZGVfcHV0KG5wX3RpbSk7 Cj4KPj4gKwlyZXR1cm4gdGltaW5nOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgaW50IHJrMzM5OV9k bWNmcmVxX3Byb2JlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpCj4+ICt7Cj4+ICsJc3Ry dWN0IGFybV9zbWNjY19yZXMgcmVzOwo+PiArCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwZGV2LT5k ZXY7Cj4+ICsJc3RydWN0IGRldmljZV9ub2RlICpucCA9IHBkZXYtPmRldi5vZl9ub2RlOwo+PiAr CXVpbnQ2NF90IHBhcmFtID0gMDsKPj4gKwlzdHJ1Y3QgcmszMzk5X2RtY2ZyZXEgKmRhdGE7Cj4+ ICsJaW50IHJldCwgaXJxLCBpbmRleDsKPj4gKwl1aW50MzJfdCAqdGltaW5nOwo+PiArCj4+ICsJ aXJxID0gcGxhdGZvcm1fZ2V0X2lycShwZGV2LCAwKTsKPj4gKwlpZiAoaXJxIDwgMCkgewo+PiAr CQlkZXZfZXJyKCZwZGV2LT5kZXYsICJubyBkbWMgaXJxIHJlc291cmNlXG4iKTsKPiBXZSBuZWVk IHRvIG1haW50YWluIHRoZSBjb25zaXN0ZW50IGV4cHJlc3Npb24gZm9yIGVycm9yIGxvZy4KPiAJ CWRldl9lcnIoJnBkZXYtPmRldiwgIiJDYW5ub3QgZ2V0IHRoZSBpbnRlcnJ1cHQgcmVzb3VyY2Ui XG4iKTsKPiAJCQo+PiArCQlyZXR1cm4gLUVJTlZBTDsKPj4gKwl9Cj4+ICsJZGF0YSA9IGRldm1f a3phbGxvYyhkZXYsIHNpemVvZihzdHJ1Y3QgcmszMzk5X2RtY2ZyZXEpLCBHRlBfS0VSTkVMKTsK Pj4gKwlpZiAoIWRhdGEpCj4+ICsJCXJldHVybiAtRU5PTUVNOwo+PiArCj4+ICsJbXV0ZXhfaW5p dCgmZGF0YS0+bG9jayk7Cj4+ICsKPj4gKwlkYXRhLT52ZGRfY2VudGVyID0gZGV2bV9yZWd1bGF0 b3JfZ2V0KGRldiwgImNlbnRlciIpOwo+PiArCWlmIChJU19FUlIoZGF0YS0+dmRkX2NlbnRlcikp IHsKPj4gKwkJZGV2X2VycihkZXYsICJDYW5ub3QgZ2V0IHRoZSByZWd1bGF0b3IgXCJjZW50ZXJc IlxuIik7Cj4+ICsJCXJldHVybiBQVFJfRVJSKGRhdGEtPnZkZF9jZW50ZXIpOwo+PiArCX0KPj4g Kwo+PiArCWRhdGEtPmRtY19jbGsgPSBkZXZtX2Nsa19nZXQoZGV2LCAiZG1jX2NsayIpOwo+PiAr CWlmIChJU19FUlIoZGF0YS0+ZG1jX2NsaykpIHsKPj4gKwkJZGV2X2VycihkZXYsICJDYW5ub3Qg Z2V0IHRoZSBjbGsgZG1jX2Nsa1xuIik7Cj4+ICsJCXJldHVybiBQVFJfRVJSKGRhdGEtPmRtY19j bGspOwo+PiArCX07Cj4+ICsKPj4gKwlkYXRhLT5pcnEgPSBpcnE7Cj4+ICsJcmV0ID0gZGV2bV9y ZXF1ZXN0X2lycShkZXYsIGlycSwgcmszMzk5X2RtY19pcnEsIDAsCj4+ICsJCQkgICAgICAgZGV2 X25hbWUoZGV2KSwgZGF0YSk7Cj4+ICsJaWYgKHJldCkgewo+PiArCQlkZXZfZXJyKGRldiwgImZh aWxlZCB0byByZXF1ZXN0IGRtYyBpcnE6ICVkXG4iLCByZXQpOwo+IGRpdHRvLiAiRmFpbGVkIHRv IHJlcXVlc3QgdGhlIGRtYyBpcnEiIG9yICJDYW5ub3QgcmVxdWVzdCB0aGUgZG1jIGlycSIKPgo+ PiArCQlyZXR1cm4gcmV0Owo+PiArCX0KPj4gKwo+PiArCS8qIGdldCBkcmFtIHRpbWluZyBhbmQg cGFzcyBpdCB0byBibDMxICovCj4gSSB3YW50IHRvIGFkZCB0aGUgbW9yZSBkZXRhaWxlZCBkZXNj cmlwdGlvbiB3aHkgdGhpcyBjb2RlIGlzIG5lY2Vzc2FyeS4KPiBCZWNhdXNlIHRoZSBTTUMgaXMg dXN1YWxseSBibGFjayBib3guIFNvLCBJZiB5b3UgYWRkIHRoZSBtb3JlIGV4cGxhbmF0aW9uLAo+ IGl0IGhlbHAgcGVvcGxlIHRvIHVuZGVyc3RhbmQgdGhpcyBjb2RlLgo+Cj4+ICsJZGF0YS0+dGlt aW5nID0gb2ZfZ2V0X2Rkcl90aW1pbmdzKGRldiwgbnApOwo+PiArCWlmIChkYXRhLT50aW1pbmcp IHsKPj4gKwkJdGltaW5nID0gKHVpbnQzMl90ICopZGF0YS0+dGltaW5nOwo+PiArCQlmb3IgKGlu ZGV4ID0gMDsgaW5kZXggPCAoc2l6ZW9mKHN0cnVjdCBkcmFtX3RpbWluZykgLyA0KTsKPj4gKwkJ ICAgICBpbmRleCsrKSB7Cj4gWW91IGJldHRlciB0byB1c2UgZm9sbG93aW5nIGNvZGUuIEl0IGlz IGJldHRlciB3YXkgdG8gdXNlCj4gdGhlIG9ubHkgb25lIGxpbmUgZm9yICdmb3InIHN0YXRlbWVu dC4KPgo+IAkJc2l6ZSA9IHNpemVvZihzdHJ1Y3QgZHJhbV90aW1pbmcpIC8gNDsKPiAJCWZvciAo aW5kZXggPSAwOyBpbmRleCA8IHNpemU7IGluZGV4KyspIHsKPgo+PiArCQkJcGFyYW0gPSBpbmRl eDsKPj4gKwkJCXBhcmFtID0gcGFyYW0gPDwgMzIgfCAqdGltaW5nKys7Cj4+ICsJCQlhcm1fc21j Y2Nfc21jKFNJUF9ERFJfRlJFUSwgcGFyYW0sIDAsCj4+ICsJCQkJICAgICAgQ09ORklHX0RSQU1f U0VUX1BBUkFNLCAwLCAwLCAwLCAwLCAmcmVzKTsKPj4gKwkJCWlmIChyZXMuYTApIHsKPj4gKwkJ CQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byBzZXQgZHJhbSBwYXJhbTogJWxkXG4iLAo+PiArCQkJ CQlyZXMuYTApOwo+PiArCQkJCXJldHVybiAtRUlOVkFMOwo+PiArCQkJfQo+PiArCQkJcGFyYW0g PSAwOwo+PiArCQl9Cj4+ICsJfQo+PiArCj4+ICsJYXJtX3NtY2NjX3NtYyhTSVBfRERSX0ZSRVEs IDAsIDAsIENPTkZJR19EUkFNX0lOSVQsCj4+ICsJCSAgICAgIDAsIDAsIDAsIDAsICZyZXMpOwo+ IGRpdHRvLiBZb3UgbmVlZCB0byBhZGQgdGhlIGRlc2NyaXB0aW9uLgo+Cj4+ICsKPj4gKwlpbml0 X3dhaXRxdWV1ZV9oZWFkKCZkYXRhLT53YWl0X2RjZl9xdWV1ZSk7Cj4+ICsJZGF0YS0+d2FpdF9k Y2ZfZmxhZyA9IDA7Cj4+ICsKPj4gKwlkYXRhLT5lZGV2ID0gZGV2ZnJlcV9ldmVudF9nZXRfZWRl dl9ieV9waGFuZGxlKGRldiwgMCk7Cj4+ICsJaWYgKElTX0VSUihkYXRhLT5lZGV2KSkKPj4gKwkJ cmV0dXJuIC1FUFJPQkVfREVGRVI7Cj4+ICsKPj4gKwlyZXQgPSBkZXZmcmVxX2V2ZW50X2VuYWJs ZV9lZGV2KGRhdGEtPmVkZXYpOwo+PiArCWlmIChyZXQgPCAwKSB7Cj4+ICsJCWRldl9lcnIoZGV2 LCAiZmFpbGVkIHRvIGVuYWJsZSBkZXZmcmVxLWV2ZW50IGRldmljZXNcbiIpOwo+IHMvZmFpbGVk L0ZhaWxlZC4gVXNlIGEgY2FwaXRhbCBsZXR0ZXIgZm9yIHRoZSBmaXJzdCBjaGFyLgo+Cj4+ICsJ CXJldHVybiByZXQ7Cj4+ICsJfQo+PiArCj4+ICsJLyoKPj4gKwkgKiBXZSBhZGQgYSBkZXZmcmVx IGRyaXZlciB0byBvdXIgcGFyZW50IHNpbmNlIGl0IGhhcyBhIGRldmljZSB0cmVlIG5vZGUKPj4g KwkgKiB3aXRoIG9wZXJhdGluZyBwb2ludHMuCj4+ICsJICovCj4gWW91IHNob3VsZCB3cmFwIHRo ZSByY3UgbG9jayBiZWZvcmUgY2FsbGluZyB0aGUgZGV2X3BtX29wcF9vZl9hZGRfdGFibGUoKS4K Pgo+PiArCWlmIChkZXZfcG1fb3BwX29mX2FkZF90YWJsZShkZXYpKSB7Cj4+ICsJCWRldl9lcnIo ZGV2LCAiSW52YWxpZCBvcGVyYXRpbmctcG9pbnRzIGluIGRldmljZSB0cmVlLlxuIik7Cj4+ICsJ CXJldHVybiAtRUlOVkFMOwo+PiArCX0KPj4gKwlvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgInVw dGhyZXNob2xkIiwKPj4gKwkJCSAgICAgJmRhdGEtPm9uZGVtYW5kX2RhdGEudXB0aHJlc2hvbGQp Owo+PiArCW9mX3Byb3BlcnR5X3JlYWRfdTMyKG5wLCAiZG93bmRpZmZlcmVudGlhbCIsCj4+ICsJ CQkgICAgICZkYXRhLT5vbmRlbWFuZF9kYXRhLmRvd25kaWZmZXJlbnRpYWwpOwo+IE5lZWQgb25l IGJsYW5rIGxpbmUuCj4gTWF5YmUgdGhpcyBjb2RlIHRvIGdldCB0aGUgcHJvcGVyZnkgZm9yIG9u ZGVtYW5kIGdvdmVybm9yLAo+IHRoZSBkZXZmcmVxIHdpbGwgc3VwcG9ydCBpbiB0aGUgZnV0dXJl Lgo+Cj4+ICsJZGF0YS0+cmF0ZSA9IGNsa19nZXRfcmF0ZShkYXRhLT5kbWNfY2xrKTsKPj4gKwly azMzOTlfZGV2ZnJlcV9kbWNfcHJvZmlsZS5pbml0aWFsX2ZyZXEgPSBkYXRhLT5yYXRlOwo+IE5l ZWQgb25lIGJsYW5rIGxpbmUuCj4KPj4gKwlkYXRhLT5kZXZmcmVxID0gZGV2ZnJlcV9hZGRfZGV2 aWNlKGRldiwKPj4gKwkJCQkJICAgJnJrMzM5OV9kZXZmcmVxX2RtY19wcm9maWxlLAo+PiArCQkJ CQkgICAic2ltcGxlX29uZGVtYW5kIiwKPj4gKwkJCQkJICAgJmRhdGEtPm9uZGVtYW5kX2RhdGEp Owo+PiArCWlmIChJU19FUlIoZGF0YS0+ZGV2ZnJlcSkpCj4+ICsJCXJldHVybiBQVFJfRVJSKGRh dGEtPmRldmZyZXEpOwo+PiArCWRldmZyZXFfcmVnaXN0ZXJfb3BwX25vdGlmaWVyKGRldiwgZGF0 YS0+ZGV2ZnJlcSk7Cj4gVXNlIHRoZSBkZXZtX2RldmZyZXFfcmVnaXN0ZXJfb3BwX25vdGlmaWVy KCkuCj4KPj4gKwo+PiArCWRhdGEtPmRldiA9IGRldjsKPj4gKwlwbGF0Zm9ybV9zZXRfZHJ2ZGF0 YShwZGV2LCBkYXRhKTsKPj4gKwo+PiArCXJldHVybiAwOwo+PiArfQo+PiArCj4+ICtzdGF0aWMg aW50IHJrMzM5OV9kbWNmcmVxX3JlbW92ZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQo+ PiArewo+PiArCXN0cnVjdCByazMzOTlfZG1jZnJlcSAqZG1jZnJlcSA9IHBsYXRmb3JtX2dldF9k cnZkYXRhKHBkZXYpOwo+PiArCj4+ICsJZGV2ZnJlcV9yZW1vdmVfZGV2aWNlKGRtY2ZyZXEtPmRl dmZyZXEpOwo+PiArCXJlZ3VsYXRvcl9wdXQoZG1jZnJlcS0+dmRkX2NlbnRlcik7Cj4+ICsKPj4g KwlyZXR1cm4gMDsKPj4gK30KPj4gKwo+PiArc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2Vf aWQgcmszMzk5ZG1jX2RldmZyZXFfb2ZfbWF0Y2hbXSA9IHsKPj4gKwl7IC5jb21wYXRpYmxlID0g InJvY2tjaGlwLHJrMzM5OS1kbWMiIH0sCj4+ICsJeyB9LAo+PiArfTsKPj4gKwo+PiArc3RhdGlj IHN0cnVjdCBwbGF0Zm9ybV9kcml2ZXIgcmszMzk5X2RtY2ZyZXFfZHJpdmVyID0gewo+PiArCS5w cm9iZQk9IHJrMzM5OV9kbWNmcmVxX3Byb2JlLAo+PiArCS5yZW1vdmUJPSByazMzOTlfZG1jZnJl cV9yZW1vdmUsCj4+ICsJLmRyaXZlciA9IHsKPj4gKwkJLm5hbWUJPSAicmszMzk5LWRtYy1mcmVx IiwKPj4gKwkJLnBtCT0gJnJrMzM5OV9kbWNmcmVxX3BtLAo+PiArCQkub2ZfbWF0Y2hfdGFibGUg PSByazMzOTlkbWNfZGV2ZnJlcV9vZl9tYXRjaCwKPj4gKwl9LAo+PiArfTsKPj4gK21vZHVsZV9w bGF0Zm9ybV9kcml2ZXIocmszMzk5X2RtY2ZyZXFfZHJpdmVyKTsKPj4gKwo+PiArTU9EVUxFX0xJ Q0VOU0UoIkdQTCB2MiIpOwo+PiArTU9EVUxFX0RFU0NSSVBUSU9OKCJSSzMzOTkgZG1jZnJlcSBk cml2ZXIgd2l0aCBkZXZmcmVxIGZyYW1ld29yayIpOwo+IFlvdSBuZWVkIHRvIGFkZCB0aGUgTU9E VUxFX0FVVEhPUiBpbmZvcm1hdGlvbi4KPgo+IFJlZ2FyZHMsCj4gQ2hhbndvbyBDaG9pCj4KPgo+ CgotLSAKTGluIEh1YW5nCgoKCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fCkxpbnV4LXJvY2tjaGlwIG1haWxpbmcgbGlzdApMaW51eC1yb2NrY2hpcEBsaXN0 cy5pbmZyYWRlYWQub3JnCmh0dHA6Ly9saXN0cy5pbmZyYWRlYWQub3JnL21haWxtYW4vbGlzdGlu Zm8vbGludXgtcm9ja2NoaXAK From mboxrd@z Thu Jan 1 00:00:00 1970 From: hl@rock-chips.com (hl) Date: Tue, 2 Aug 2016 09:03:32 +0800 Subject: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc In-Reply-To: <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> <579F2445.1020200@samsung.com> Message-ID: <579FF164.2000907@rock-chips.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi Chanwoo Choi, Thanks for reviewing so carefully. And i have some question: On 2016?08?01? 18:28, Chanwoo Choi wrote: > 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(). I prefer the way now use, since we get the dmcfreq->rate use clk_get_rate() after, Base on that, i do not care the set_rate success or fail. use curr_opp i need to care about set_rate status, when fail, i must set some rate, when success i must set other rate. >> + 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? When timeout happen , may be we miss interrupt, but it do not affect this process, since we will check the rate whether success later. > 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. May be i should remove the regulator_set_voltage() here, but still need to check whether we get the right frequency, since if we do not get the right frequency, we should send a warn message, to remind that maybe you pass a frequency which do not support in bl31. > > >> + } 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 > > > -- Lin Huang From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932131AbcHBBQW (ORCPT ); Mon, 1 Aug 2016 21:16:22 -0400 Received: from lucky1.263xmail.com ([211.157.147.132]:56604 "EHLO lucky1.263xmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932110AbcHBBQN (ORCPT ); Mon, 1 Aug 2016 21:16:13 -0400 X-263anti-spam: KSV:0; X-MAIL-GRAY: 1 X-MAIL-DELIVERY: 0 X-KSVirus-check: 0 X-ABS-CHECKED: 4 X-ADDR-CHECKED: 0 X-RL-SENDER: hl@rock-chips.com X-FST-TO: mark.yao@rock-chips.com X-SENDER-IP: 103.29.142.67 X-LOGIN-NAME: hl@rock-chips.com X-UNIQUE-TAG: <525451c4701216a96729b3a03951d654> X-ATTACHMENT-NUM: 0 X-DNS-TYPE: 0 Subject: Re: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc To: Chanwoo Choi , heiko@sntech.de References: <1469779021-10426-1-git-send-email-hl@rock-chips.com> <1469779021-10426-7-git-send-email-hl@rock-chips.com> <579F2445.1020200@samsung.com> 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 From: hl Message-ID: <579FF164.2000907@rock-chips.com> Date: Tue, 2 Aug 2016 09:03:32 +0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.4.0 MIME-Version: 1.0 In-Reply-To: <579F2445.1020200@samsung.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Chanwoo Choi, Thanks for reviewing so carefully. And i have some question: On 2016年08月01日 18:28, Chanwoo Choi wrote: > 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(). I prefer the way now use, since we get the dmcfreq->rate use clk_get_rate() after, Base on that, i do not care the set_rate success or fail. use curr_opp i need to care about set_rate status, when fail, i must set some rate, when success i must set other rate. >> + 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? When timeout happen , may be we miss interrupt, but it do not affect this process, since we will check the rate whether success later. > 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. May be i should remove the regulator_set_voltage() here, but still need to check whether we get the right frequency, since if we do not get the right frequency, we should send a warn message, to remind that maybe you pass a frequency which do not support in bl31. > > >> + } 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 > > > -- Lin Huang