From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6296BC43461 for ; Wed, 7 Apr 2021 09:09:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1337261205 for ; Wed, 7 Apr 2021 09:09:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234464AbhDGJJX (ORCPT ); Wed, 7 Apr 2021 05:09:23 -0400 Received: from mailgw01.mediatek.com ([210.61.82.183]:56310 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S229869AbhDGJJT (ORCPT ); Wed, 7 Apr 2021 05:09:19 -0400 X-UUID: 2abe78730a75400eaf660f89d761cdae-20210407 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=grOFFUtINhKpc8Th5j1GB5zb0oqVfOdvcKO8OHgRSbc=; b=WiFYO2cEjdGc7W+xXsvWW6rZSXMO/XPRn1MS12W2ig+z7oW67+BWK4cz0LkwBoc7T8JywIUwYTZhOWDi2UaT3TYtQisiYpZY9cC5Aj9boa0DP5NspW6HIFe4nKWyLo+JQJkX7NK9WbSfnYSn9WyR4EUx80rixmc0DMkOH9RcUwI=; X-UUID: 2abe78730a75400eaf660f89d761cdae-20210407 Received: from mtkcas07.mediatek.inc [(172.21.101.84)] by mailgw01.mediatek.com (envelope-from ) (Cellopoint E-mail Firewall v4.1.14 Build 0819 with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1633732919; Wed, 07 Apr 2021 17:09:08 +0800 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 7 Apr 2021 17:09:06 +0800 Received: from [172.21.84.99] (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 7 Apr 2021 17:09:06 +0800 Message-ID: <1617786546.12846.2.camel@mtksdccf07> Subject: Re: [v3,2/3] thermal: mediatek: Add LVTS drivers for SoC theraml zones From: Michael Kao To: Zhang Rui , Daniel Lezcano CC: , , Eduardo Valentin , Rob Herring , Mark Rutland , Matthias Brugger , , , , , Date: Wed, 7 Apr 2021 17:09:06 +0800 In-Reply-To: <20210312034018.17437-3-michael.kao@mediatek.com> References: <20210312034018.17437-1-michael.kao@mediatek.com> <20210312034018.17437-3-michael.kao@mediatek.com> Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.2.3-0ubuntu6 MIME-Version: 1.0 X-MTK: N Content-Transfer-Encoding: base64 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org SGkgTWFpbnRhaW5lcnMsDQogDQpHZW50bGUgcGluIGZvciB0aGlzIHBhdGNoLg0KIA0KVGhhbmtz DQoNCg0KT24gRnJpLCAyMDIxLTAzLTEyIGF0IDExOjQwICswODAwLCBNaWNoYWVsIEthbyB3cm90 ZToNCj4gQWRkIGEgTFZUUyAoTG93IHZvbHRhZ2UgdGhlcm1hbCBzZW5zb3IpIGRyaXZlciB0byBy ZXBvcnQganVuY3Rpb24NCj4gdGVtcGVyYXR1cmVzIGluIE1lZGlhdGVrIFNvQyBhbmQgcmVnaXN0 ZXIgdGhlIG1heGltdW0gdGVtcGVyYXR1cmUNCj4gb2Ygc2Vuc29ycyBhbmQgZWFjaCBzZW5zb3Ig YXMgYSB0aGVybWFsIHpvbmUuDQo+IA0KPiBTaWduZWQtb2ZmLWJ5OiBZdS1DaGlhIENoYW5nIDxl dGhhbi5jaGFuZ0BtZWRpYXRlay5jb20+DQo+IFNpZ25lZC1vZmYtYnk6IE1pY2hhZWwgS2FvIDxt aWNoYWVsLmthb0BtZWRpYXRlay5jb20+DQo+IC0tLQ0KPiAgZHJpdmVycy90aGVybWFsL21lZGlh dGVrL0tjb25maWcgICAgICAgICB8ICAgMTAgKw0KPiAgZHJpdmVycy90aGVybWFsL21lZGlhdGVr L01ha2VmaWxlICAgICAgICB8ICAgIDEgKw0KPiAgZHJpdmVycy90aGVybWFsL21lZGlhdGVrL3Nv Y190ZW1wX2x2dHMuYyB8IDEyODcgKysrKysrKysrKysrKysrKysrKysrKw0KPiAgZHJpdmVycy90 aGVybWFsL21lZGlhdGVrL3NvY190ZW1wX2x2dHMuaCB8ICAzMTIgKysrKysrDQo+ICA0IGZpbGVz IGNoYW5nZWQsIDE2MTAgaW5zZXJ0aW9ucygrKQ0KPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZl cnMvdGhlcm1hbC9tZWRpYXRlay9zb2NfdGVtcF9sdnRzLmMNCj4gIGNyZWF0ZSBtb2RlIDEwMDY0 NCBkcml2ZXJzL3RoZXJtYWwvbWVkaWF0ZWsvc29jX3RlbXBfbHZ0cy5oDQo+IA0KPiBkaWZmIC0t Z2l0IGEvZHJpdmVycy90aGVybWFsL21lZGlhdGVrL0tjb25maWcgYi9kcml2ZXJzL3RoZXJtYWwv bWVkaWF0ZWsvS2NvbmZpZw0KPiBpbmRleCAwMzUxZTczMTcwYjcuLmQ3MTZkMDM3MmUxZSAxMDA2 NDQNCj4gLS0tIGEvZHJpdmVycy90aGVybWFsL21lZGlhdGVrL0tjb25maWcNCj4gKysrIGIvZHJp dmVycy90aGVybWFsL21lZGlhdGVrL0tjb25maWcNCj4gQEAgLTIwLDQgKzIwLDE0IEBAIGNvbmZp ZyBNVEtfU09DX1RIRVJNQUwNCj4gIAkgIGNvbmZpZ3VyZXMgdGhlcm1hbCBjb250cm9sbGVycyB0 byBjb2xsZWN0IHRlbXBlcmF0dXJlDQo+ICAJICB2aWEgQVVYQURDIGludGVyZmFjZS4NCj4gIA0K PiArY29uZmlnIE1US19TT0NfVEhFUk1BTF9MVlRTDQo+ICsgICAgICAgIHRyaXN0YXRlICJMVlRT IChMb3cgdm9sdGFnZSB0aGVybWFsIHNlbnNvcikgZHJpdmVyIGZvciBNZWRpYXRlayBTb0NzIg0K PiArICAgICAgICBkZXBlbmRzIG9uIEhBU19JT01FTQ0KPiArICAgICAgICBkZXBlbmRzIG9uIE5W TUVNDQo+ICsgICAgICAgIGRlcGVuZHMgb24gUkVTRVRfVElfU1lTQ09ODQo+ICsgICAgICAgIGhl bHANCj4gKyAgICAgICAgICBFbmFibGUgdGhpcyBvcHRpb24gaWYgeW91IHdhbnQgdG8gZ2V0IFNv QyB0ZW1wZXJhdHVyZQ0KPiArICAgICAgICAgIGluZm9ybWF0aW9uIGZvciBNZWRpYXRlayBwbGF0 Zm9ybXMuIFRoaXMgZHJpdmVyDQo+ICsgICAgICAgICAgY29uZmlndXJlcyBMVlRTIHRoZXJtYWwg Y29udHJvbGxlcnMgdG8gY29sbGVjdCB0ZW1wZXJhdHVyZXMNCj4gKyAgICAgICAgICB2aWEgQW5h bG9nIFNlcmlhbCBJbnRlcmZhY2UoQVNJRikuDQo+ICBlbmRpZg0KPiBkaWZmIC0tZ2l0IGEvZHJp dmVycy90aGVybWFsL21lZGlhdGVrL01ha2VmaWxlIGIvZHJpdmVycy90aGVybWFsL21lZGlhdGVr L01ha2VmaWxlDQo+IGluZGV4IGY3NTMxM2RkY2U1ZS4uMTZjZTE2NmU1OTE2IDEwMDY0NA0KPiAt LS0gYS9kcml2ZXJzL3RoZXJtYWwvbWVkaWF0ZWsvTWFrZWZpbGUNCj4gKysrIGIvZHJpdmVycy90 aGVybWFsL21lZGlhdGVrL01ha2VmaWxlDQo+IEBAIC0xICsxLDIgQEANCj4gIG9iai0kKENPTkZJ R19NVEtfU09DX1RIRVJNQUwpCSs9IHNvY190ZW1wLm8NCj4gK29iai0kKENPTkZJR19NVEtfU09D X1RIRVJNQUxfTFZUUykJKz0gc29jX3RlbXBfbHZ0cy5vDQo+IGRpZmYgLS1naXQgYS9kcml2ZXJz L3RoZXJtYWwvbWVkaWF0ZWsvc29jX3RlbXBfbHZ0cy5jIGIvZHJpdmVycy90aGVybWFsL21lZGlh dGVrL3NvY190ZW1wX2x2dHMuYw0KPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiBpbmRleCAwMDAw MDAwMDAwMDAuLjgxNTNlZGFhZjgxNQ0KPiAtLS0gL2Rldi9udWxsDQo+ICsrKyBiL2RyaXZlcnMv dGhlcm1hbC9tZWRpYXRlay9zb2NfdGVtcF9sdnRzLmMNCj4gQEAgLTAsMCArMSwxMjg3IEBADQo+ ICsvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMA0KPiArLyoNCj4gKyAqIENvcHly aWdodCAoYykgMjAyMCBNZWRpYVRlayBJbmMuDQo+ICsgKi8NCj4gKw0KPiArI2luY2x1ZGUgPGxp bnV4L2JpdHMuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9jbGsuaD4NCj4gKyNpbmNsdWRlIDxsaW51 eC9kZWxheS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2ludGVycnVwdC5oPg0KPiArI2luY2x1ZGUg PGxpbnV4L2lvLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvaW9wb2xsLmg+DQo+ICsjaW5jbHVkZSA8 bGludXgva2VybmVsLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+DQo+ICsjaW5jbHVk ZSA8bGludXgvbnZtZW0tY29uc3VtZXIuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9vZi5oPg0KPiAr I2luY2x1ZGUgPGxpbnV4L29mX2FkZHJlc3MuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9vZl9kZXZp Y2UuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9vZl9pcnEuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9w bGF0Zm9ybV9kZXZpY2UuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9yZXNldC5oPg0KPiArI2luY2x1 ZGUgPGxpbnV4L3NsYWIuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9zdHJpbmcuaD4NCj4gKyNpbmNs dWRlIDxsaW51eC90aGVybWFsLmg+DQo+ICsjaW5jbHVkZSAic29jX3RlbXBfbHZ0cy5oIg0KPiAr DQo+ICsvKj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 DQo+ICsgKiBEZWZpbml0aW9uIG9yIG1hY3JvIGZ1bmN0aW9uDQo+ICsgKj09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQo+ICsgKi8NCj4gKyNkZWZpbmUg U1RPUF9DT1VOVElOR19WNCAoREVWSUNFX1dSSVRFIHwgUkdfVFNGTV9DVFJMXzAgPDwgOCB8IDB4 MDApDQo+ICsjZGVmaW5lIFNFVF9SR19UU0ZNX0xQRExZX1Y0IChERVZJQ0VfV1JJVEUgfCBSR19U U0ZNX0NUUkxfNCA8PCA4IHwgMHhBNikNCj4gKyNkZWZpbmUgU0VUX0NPVU5USU5HX1dJTkRPV18y MFVTMV9WNCAoREVWSUNFX1dSSVRFIHwgUkdfVFNGTV9DVFJMXzIgPDwgOCB8IDB4MDApDQo+ICsj ZGVmaW5lIFNFVF9DT1VOVElOR19XSU5ET1dfMjBVUzJfVjQgKERFVklDRV9XUklURSB8IFJHX1RT Rk1fQ1RSTF8xIDw8IDggfCAweDIwKQ0KPiArI2RlZmluZSBUU1YyRl9DSE9QX0NLU0VMX0FORF9U U1YyRl9FTl9WNCAoREVWSUNFX1dSSVRFIHwgUkdfVFNWMkZfQ1RSTF8yIDw8IDggfCAweDg0KQ0K PiArI2RlZmluZSBUU0JHX0RFTV9DS1NFTF9YX1RTQkdfQ0hPUF9FTl9WNCAoREVWSUNFX1dSSVRF IHwgUkdfVFNWMkZfQ1RSTF80IDw8IDggfCAweDdDKQ0KPiArI2RlZmluZSBTRVRfVFNfUlNWX1Y0 IChERVZJQ0VfV1JJVEUgfCBSR19UU1YyRl9DVFJMXzEgPDwgOCB8IDB4OEQpDQo+ICsjZGVmaW5l IFNFVF9UU19FTl9WNCAoREVWSUNFX1dSSVRFIHwgUkdfVFNWMkZfQ1RSTF8wIDw8IDggfCAweEY0 KQ0KPiArI2RlZmluZSBUT0dHTEVfUkdfVFNWMkZfVkNPX1JTVDFfVjQgKERFVklDRV9XUklURSB8 IFJHX1RTVjJGX0NUUkxfMCA8PCA4IHwgMHhGQykNCj4gKyNkZWZpbmUgVE9HR0xFX1JHX1RTVjJG X1ZDT19SU1QyX1Y0IChERVZJQ0VfV1JJVEUgfCBSR19UU1YyRl9DVFJMXzAgPDwgOCB8IDB4RjQp DQo+ICsNCj4gKyNkZWZpbmUgU0VUX0xWVFNfQVVUT19SQ0tfVjQgKERFVklDRV9XUklURSB8IFJH X1RTVjJGX0NUUkxfNiA8PCA4IHwgMHgwMSkNCj4gKyNkZWZpbmUgU0VMRUNUX1NFTlNPUl9SQ0tf VjQoaWQpIChERVZJQ0VfV1JJVEUgfCBSR19UU1YyRl9DVFJMXzUgPDwgOCB8IChpZCkpDQo+ICsj ZGVmaW5lIFNFVF9ERVZJQ0VfU0lOR0xFX01PREVfVjQgKERFVklDRV9XUklURSB8IFJHX1RTRk1f Q1RSTF8zIDw8IDggfCAweDc4KQ0KPiArI2RlZmluZSBLSUNLX09GRl9SQ0tfQ09VTlRJTkdfVjQg KERFVklDRV9XUklURSB8IFJHX1RTRk1fQ1RSTF8wIDw8IDggfCAweDAyKQ0KPiArI2RlZmluZSBT RVRfU0VOU09SX05PX1JDS19WNCAoREVWSUNFX1dSSVRFIHwgUkdfVFNWMkZfQ1RSTF81IDw8IDgg fCAweDEwKQ0KPiArI2RlZmluZSBTRVRfREVWSUNFX0xPV19QT1dFUl9TSU5HTEVfTU9ERV9WNCAo REVWSUNFX1dSSVRFIHwgUkdfVFNGTV9DVFJMXzMgPDwgOAl8IDB4QjgpDQo+ICsNCj4gKyNkZWZp bmUgRU5BQkxFX0ZFQVRVUkUoZmVhdHVyZSkJCShsdnRzX2RhdGEtPmZlYXR1cmVfYml0bWFwIHw9 IChmZWF0dXJlKSkNCj4gKyNkZWZpbmUgRElTQUJMRV9GRUFUVVJFKGZlYXR1cmUpCShsdnRzX2Rh dGEtPmZlYXR1cmVfYml0bWFwICY9ICh+KGZlYXR1cmUpKSkNCj4gKyNkZWZpbmUgSVNfRU5BQkxF KGZlYXR1cmUpCQkobHZ0c19kYXRhLT5mZWF0dXJlX2JpdG1hcCAmIChmZWF0dXJlKSkNCj4gKw0K PiArI2RlZmluZSBESVNBQkxFX1RIRVJNQUxfSFdfUkVCT09UICgtMjc0MDAwKQ0KPiArDQo+ICsj ZGVmaW5lIENMT0NLXzI2TUhaX0NZQ0xFX05TCSgzOCkNCj4gKyNkZWZpbmUgQlVTX0FDQ0VTU19V UwkJKDIpDQo+ICsNCj4gKyNkZWZpbmUgRkVBVFVSRV9ERVZJQ0VfQVVUT19SQ0sJKEJJVCgwKSkN Cj4gKyNkZWZpbmUgRkVBVFVSRV9DSzI2TV9BQ1RJVkUJKEJJVCgxKSkNCj4gKyNkZWZpbmUgQ0sy Nk1fQUNUSVZFICAgKCgobHZ0c19kYXRhLT5mZWF0dXJlX2JpdG1hcCAmIEZFQVRVUkVfQ0syNk1f QUNUSVZFKSAgICBcDQo+ICsJCQk/IDEgOiAwKSA8PCAzMCkNCj4gKyNkZWZpbmUgR0VUX0JBU0Vf QUREUih0Y19pZCkJXA0KPiArCShsdnRzX2RhdGEtPmRvbWFpbltsdnRzX2RhdGEtPnRjW3RjX2lk XS5kb21haW5faW5kZXhdLmJhc2UJXA0KPiArCSsgbHZ0c19kYXRhLT50Y1t0Y19pZF0uYWRkcl9v ZmZzZXQpDQo+ICsNCj4gKyNkZWZpbmUgU0VUX1RDX1NQRUVEX0lOX1VTKHB1LCBnZCwgZmQsIHNk KSBcDQo+ICsJewlcDQo+ICsJCS5wZXJpb2RfdW5pdCA9ICgoKHB1KSAqIDEwMDApIC8gKDI1NiAq IENMT0NLXzI2TUhaX0NZQ0xFX05TKSksCVwNCj4gKwkJLmdyb3VwX2ludGVydmFsX2RlbGF5ID0g KChnZCkgLyAocHUpKSwJXA0KPiArCQkuZmlsdGVyX2ludGVydmFsX2RlbGF5ID0gKChmZCkgLyAo cHUpKSwJXA0KPiArCQkuc2Vuc29yX2ludGVydmFsX2RlbGF5ID0gKChzZCkgLyAocHUpKSwJXA0K PiArCX0NCj4gKw0KPiArI2RlZmluZSBHRVRfQ0FMX0RBVEFfQklUTUFTSyhpbmRleCwgaCwgbCkJ XA0KPiArCSgoKGluZGV4KSA8IGx2dHNfZGF0YS0+bnVtX2VmdXNlX2FkZHIpCVwNCj4gKwk/ICgo bHZ0c19kYXRhLT5lZnVzZVsoaW5kZXgpXSAmIEdFTk1BU0soaCwgbCkpID4+IGwpCVwNCj4gKwk6 IDApDQo+ICsNCj4gKyNkZWZpbmUgR0VUX0NBTF9EQVRBX0JJVChpbmRleCwgYml0KQlcDQo+ICsJ KCgoaW5kZXgpIDwgbHZ0c19kYXRhLT5udW1fZWZ1c2VfYWRkcikJXA0KPiArCT8gKChsdnRzX2Rh dGEtPmVmdXNlW2luZGV4XSAmIEJJVChiaXQpKSA+PiAoYml0KSkJXA0KPiArCTogMCkNCj4gKw0K PiArI2RlZmluZSBHRVRfVENfU0VOU09SX05VTSh0Y19pZCkJXA0KPiArCShsdnRzX2RhdGEtPnRj W3RjX2lkXS5udW1fc2Vuc29yKQ0KPiArDQo+ICsjZGVmaW5lIE9ORV9TQU1QTEUgKGx2dHNfZGF0 YS0+Y291bnRpbmdfd2luZG93X3VzICsgMiAqIEJVU19BQ0NFU1NfVVMpDQo+ICsNCj4gKyNkZWZp bmUgTlVNX09GX1NBTVBMRSh0Y19pZCkJXA0KPiArCSgobHZ0c19kYXRhLT50Y1t0Y19pZF0uaHdf ZmlsdGVyIDwgTFZUU19GSUxURVJfMikgPyAxIDoJXA0KPiArCSgobHZ0c19kYXRhLT50Y1t0Y19p ZF0uaHdfZmlsdGVyID4gTFZUU19GSUxURVJfMTZfT0ZfMTgpID8gMSA6CVwNCj4gKwkoKGx2dHNf ZGF0YS0+dGNbdGNfaWRdLmh3X2ZpbHRlciA9PSBMVlRTX0ZJTFRFUl8xNl9PRl8xOCkgPyAxOCA6 XA0KPiArCSgobHZ0c19kYXRhLT50Y1t0Y19pZF0uaHdfZmlsdGVyID09IExWVFNfRklMVEVSXzhf T0ZfMTApID8gMTAgOglcDQo+ICsJKGx2dHNfZGF0YS0+dGNbdGNfaWRdLmh3X2ZpbHRlciAqIDIp KSkpKQ0KPiArDQo+ICsjZGVmaW5lIFBFUklPRF9VTklUX1VTKHRjX2lkKQlcDQo+ICsJKChsdnRz X2RhdGEtPnRjW3RjX2lkXS50Y19zcGVlZC5wZXJpb2RfdW5pdCAqIDI1NiAqCVwNCj4gKwlDTE9D S18yNk1IWl9DWUNMRV9OUykgLyAxMDAwKQ0KPiArI2RlZmluZSBGSUxURVJfSU5UX1VTKHRjX2lk KQlcDQo+ICsJKGx2dHNfZGF0YS0+dGNbdGNfaWRdLnRjX3NwZWVkLmZpbHRlcl9pbnRlcnZhbF9k ZWxheQlcDQo+ICsJKiBQRVJJT0RfVU5JVF9VUyh0Y19pZCkpDQo+ICsjZGVmaW5lIFNFTlNPUl9J TlRfVVModGNfaWQpCVwNCj4gKwkobHZ0c19kYXRhLT50Y1t0Y19pZF0udGNfc3BlZWQuc2Vuc29y X2ludGVydmFsX2RlbGF5CVwNCj4gKwkqIFBFUklPRF9VTklUX1VTKHRjX2lkKSkNCj4gKyNkZWZp bmUgR1JPVVBfSU5UX1VTKHRjX2lkKQlcDQo+ICsJKGx2dHNfZGF0YS0+dGNbdGNfaWRdLnRjX3Nw ZWVkLmdyb3VwX2ludGVydmFsX2RlbGF5CVwNCj4gKwkqIFBFUklPRF9VTklUX1VTKHRjX2lkKSkN Cj4gKw0KPiArI2RlZmluZSBTRU5TT1JfTEFURU5DWV9VUyh0Y19pZCkgXA0KPiArCSgoTlVNX09G X1NBTVBMRSh0Y19pZCkgLSAxKSAqIEZJTFRFUl9JTlRfVVModGNfaWQpCVwNCj4gKwkrIE5VTV9P Rl9TQU1QTEUodGNfaWQpICogT05FX1NBTVBMRSkNCj4gKw0KPiArI2RlZmluZSBHUk9VUF9MQVRF TkNZX1VTKHRjX2lkKQlcDQo+ICsJKEdFVF9UQ19TRU5TT1JfTlVNKHRjX2lkKSAqIFNFTlNPUl9M QVRFTkNZX1VTKHRjX2lkKQlcDQo+ICsJKyAoR0VUX1RDX1NFTlNPUl9OVU0odGNfaWQpIC0gMSkg KiBTRU5TT1JfSU5UX1VTKHRjX2lkKQlcDQo+ICsJKyBHUk9VUF9JTlRfVVModGNfaWQpKQ0KPiAr DQo+ICsvKj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 DQo+ICsgKiBMVlRTIGxvY2FsIGNvbW1vbiBjb2RlDQo+ICsgKj09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQo+ICsgKi8NCj4gK3N0YXRpYyBpbnQgbHZ0 c19yYXdfdG9fdGVtcChzdHJ1Y3QgZm9ybXVsYV9jb2VmZiAqY28sIHVuc2lnbmVkIGludCBtc3Jf cmF3KQ0KPiArew0KPiArCS8qIFRoaXMgZnVuY3Rpb24gcmV0dXJucyBkZWdyZWUgbUMgKi8NCj4g Kw0KPiArCWludCB0ZW1wOw0KPiArDQo+ICsJdGVtcCA9IChjby0+YSAqICgodW5zaWduZWQgbG9u ZyBsb25nKW1zcl9yYXcpKSA+PiAxNDsNCj4gKwl0ZW1wID0gdGVtcCArIGNvLT5nb2xkZW5fdGVt cCAqIDUwMCArIGNvLT5iOw0KPiArDQo+ICsJcmV0dXJuIHRlbXA7DQo+ICt9DQo+ICsNCj4gK3N0 YXRpYyB1bnNpZ25lZCBpbnQgbHZ0c190ZW1wX3RvX3JhdyhzdHJ1Y3QgZm9ybXVsYV9jb2VmZiAq Y28sIGludCB0ZW1wKQ0KPiArew0KPiArCXVuc2lnbmVkIGludCBtc3JfcmF3Ow0KPiArDQo+ICsJ bXNyX3JhdyA9IGRpdl9zNjQoKHM2NCkoKGNvLT5nb2xkZW5fdGVtcCAqIDUwMCArIGNvLT5iIC0g dGVtcCkpIDw8IDE0LA0KPiArCQkJICgtMSAqIGNvLT5hKSk7DQo+ICsNCj4gKwlyZXR1cm4gbXNy X3JhdzsNCj4gK30NCj4gKw0KPiArc3RhdGljIGludCBsdnRzX3JlYWRfYWxsX3RjX3RlbXBlcmF0 dXJlKHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSkNCj4gK3sNCj4gKwlzdHJ1Y3QgdGNfc2V0 dGluZ3MgKnRjID0gbHZ0c19kYXRhLT50YzsNCj4gKwl1bnNpZ25lZCBpbnQgaSwgaiwgc19pbmRl eCwgbXNyX3JhdzsNCj4gKwlpbnQgbWF4X3RlbXAgPSAwLCBjdXJyZW50X3RlbXA7DQo+ICsJdm9p ZCBfX2lvbWVtICpiYXNlOw0KPiArDQo+ICsJZm9yIChpID0gMDsgaSA8IGx2dHNfZGF0YS0+bnVt X3RjOyBpKyspIHsNCj4gKwkJYmFzZSA9IEdFVF9CQVNFX0FERFIoaSk7DQo+ICsJCWZvciAoaiA9 IDA7IGogPCB0Y1tpXS5udW1fc2Vuc29yOyBqKyspIHsNCj4gKwkJCXNfaW5kZXggPSB0Y1tpXS5z ZW5zb3JfbWFwW2pdOw0KPiArDQo+ICsJCQltc3JfcmF3ID0gcmVhZGwoTFZUU01TUjBfMCArIGJh c2UgKyAweDQgKiBqKSAmIE1SU19SQVdfTUFTSzsNCj4gKwkJCWN1cnJlbnRfdGVtcCA9IGx2dHNf cmF3X3RvX3RlbXAoJmx2dHNfZGF0YS0+Y29lZmYsIG1zcl9yYXcpOw0KPiArDQo+ICsJCQlpZiAo bXNyX3JhdyA9PSAwKQ0KPiArCQkJCWN1cnJlbnRfdGVtcCA9IFRIRVJNQUxfVEVNUF9JTlZBTElE Ow0KPiArDQo+ICsJCQltYXhfdGVtcCA9IG1heChtYXhfdGVtcCwgY3VycmVudF90ZW1wKTsNCj4g Kw0KPiArCQkJbHZ0c19kYXRhLT5zZW5fZGF0YVtzX2luZGV4XS5tc3JfcmF3ID0gbXNyX3JhdzsN Cj4gKwkJCWx2dHNfZGF0YS0+c2VuX2RhdGFbc19pbmRleF0udGVtcCA9IGN1cnJlbnRfdGVtcDsN Cj4gKwkJfQ0KPiArCX0NCj4gKw0KPiArCXJldHVybiBtYXhfdGVtcDsNCj4gK30NCj4gKw0KPiAr c3RhdGljIGludCBzb2NfdGVtcF9sdnRzX3JlYWRfdGVtcCh2b2lkICpkYXRhLCBpbnQgKnRlbXBl cmF0dXJlKQ0KPiArew0KPiArCXN0cnVjdCBzb2NfdGVtcF90eiAqbHZ0c190eiA9IChzdHJ1Y3Qg c29jX3RlbXBfdHogKilkYXRhOw0KPiArCXN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSA9IGx2 dHNfdHotPmx2dHNfZGF0YTsNCj4gKw0KPiArCWlmIChsdnRzX3R6LT5pZCA9PSAwKQ0KPiArCQkq dGVtcGVyYXR1cmUgPSBsdnRzX3JlYWRfYWxsX3RjX3RlbXBlcmF0dXJlKGx2dHNfZGF0YSk7DQo+ ICsJZWxzZSBpZiAobHZ0c190ei0+aWQgLSAxIDwgbHZ0c19kYXRhLT5udW1fc2Vuc29yKQ0KPiAr CQkqdGVtcGVyYXR1cmUgPSBsdnRzX2RhdGEtPnNlbl9kYXRhW2x2dHNfdHotPmlkIC0gMV0udGVt cDsNCj4gKwllbHNlDQo+ICsJCXJldHVybiAtRUlOVkFMOw0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ ICt9DQo+ICsNCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgdGhlcm1hbF96b25lX29mX2RldmljZV9v cHMgc29jX3RlbXBfbHZ0c19vcHMgPSB7DQo+ICsJLmdldF90ZW1wID0gc29jX3RlbXBfbHZ0c19y ZWFkX3RlbXAsDQo+ICt9Ow0KPiArDQo+ICtzdGF0aWMgdm9pZCBsdnRzX3dyaXRlX2RldmljZShz dHJ1Y3QgbHZ0c19kYXRhICpsdnRzX2RhdGEsIHVuc2lnbmVkIGludCBkYXRhLA0KPiArCQkJICAg ICAgaW50IHRjX2lkKQ0KPiArew0KPiArCXZvaWQgX19pb21lbSAqYmFzZTsNCj4gKw0KPiArCWJh c2UgPSBHRVRfQkFTRV9BRERSKHRjX2lkKTsNCj4gKw0KPiArCXdyaXRlbChkYXRhLCBMVlRTX0NP TkZJR18wICsgYmFzZSk7DQo+ICsNCj4gKwl1c2xlZXBfcmFuZ2UoNSwgMTUpOw0KPiArfQ0KPiAr DQo+ICtzdGF0aWMgdW5zaWduZWQgaW50IGx2dHNfcmVhZF9kZXZpY2Uoc3RydWN0IGx2dHNfZGF0 YSAqbHZ0c19kYXRhLA0KPiArCQkJCSAgICAgdW5zaWduZWQgaW50IHJlZ19pZHgsIGludCB0Y19p ZCkNCj4gK3sNCj4gKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSBsdnRzX2RhdGEtPmRldjsNCj4gKwl2 b2lkIF9faW9tZW0gKmJhc2U7DQo+ICsJdW5zaWduZWQgaW50IGRhdGE7DQo+ICsJaW50IHJldDsN Cj4gKw0KPiArCWJhc2UgPSBHRVRfQkFTRV9BRERSKHRjX2lkKTsNCj4gKwl3cml0ZWwoUkVBRF9E RVZJQ0VfUkVHKHJlZ19pZHgpLCBMVlRTX0NPTkZJR18wICsgYmFzZSk7DQo+ICsNCj4gKwlyZXQg PSByZWFkbF9wb2xsX3RpbWVvdXQoTFZUU19DT05GSUdfMCArIGJhc2UsIGRhdGEsDQo+ICsJCQkJ ICEoZGF0YSAmIERFVklDRV9BQ0NFU1NfU1RBUlRVUyksDQo+ICsJCQkJIDIsIDIwMCk7DQo+ICsJ aWYgKHJldCkNCj4gKwkJZGV2X2VycihkZXYsDQo+ICsJCQkiRXJyb3I6IExWVFMgJWQgREVWSUNF X0FDQ0VTU19TVEFSVCBkaWRuJ3QgcmVhZHlcbiIsIHRjX2lkKTsNCj4gKw0KPiArCWRhdGEgPSBy ZWFkbChMVlRTUkRBVEEwXzAgKyBiYXNlKTsNCj4gKw0KPiArCXJldHVybiBkYXRhOw0KPiArfQ0K PiArDQo+ICtzdGF0aWMgdm9pZCB3YWl0X2FsbF90Y19zZW5zaW5nX3BvaW50X2lkbGUoc3RydWN0 IGx2dHNfZGF0YSAqbHZ0c19kYXRhKQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2UgKmRldiA9IGx2 dHNfZGF0YS0+ZGV2Ow0KPiArCXVuc2lnbmVkIGludCBtYXNrLCBlcnJvcl9jb2RlLCBpc19lcnJv cjsNCj4gKwl2b2lkIF9faW9tZW0gKmJhc2U7DQo+ICsJaW50IGksIGNudCwgcmV0Ow0KPiArDQo+ ICsJbWFzayA9IEJJVCgxMCkgfCBCSVQoNykgfCBCSVQoMCk7DQo+ICsNCj4gKwlmb3IgKGNudCA9 IDA7IGNudCA8IDI7IGNudCsrKSB7DQo+ICsJCWlzX2Vycm9yID0gMDsNCj4gKwkJZm9yIChpID0g MDsgaSA8IGx2dHNfZGF0YS0+bnVtX3RjOyBpKyspIHsNCj4gKwkJCWJhc2UgPSBHRVRfQkFTRV9B RERSKGkpOw0KPiArCQkJcmV0ID0gcmVhZGxfcG9sbF90aW1lb3V0KExWVFNNU1JDVEwxXzAgKyBi YXNlLCBlcnJvcl9jb2RlLA0KPiArCQkJCQkJICEoZXJyb3JfY29kZSAmIG1hc2spLCAyLCAyMDAp Ow0KPiArCQkJLyoNCj4gKwkJCSAqIEVycm9yIGNvZGUNCj4gKwkJCSAqIDAwMDogSURMRQ0KPiAr CQkJICogMDAxOiBXcml0ZSB0cmFuc2FjdGlvbg0KPiArCQkJICogMDEwOiBXYWl0aW5nIGZvciBy ZWFkIGFmdGVyIFdyaXRlDQo+ICsJCQkgKiAwMTE6IERpc2FibGUgQ29udGludWUgZmV0Y2hpbmcg b24gRGV2aWNlDQo+ICsJCQkgKiAxMDA6IFJlYWQgdHJhbnNhY3Rpb24NCj4gKwkJCSAqIDEwMTog U2V0IERldmljZSBzcGVjaWFsIFJlZ2lzdGVyIGZvciBWb2x0YWdlIHRocmVzaG9sZA0KPiArCQkJ ICogMTExOiBTZXQgVFNNQ1UgbnVtYmVyIGZvciBGZXRjaA0KPiArCQkJICovDQo+ICsJCQllcnJv cl9jb2RlID0gKChlcnJvcl9jb2RlICYgQklUKDEwKSkgPj4gOCkgKw0KPiArCQkJCSgoZXJyb3Jf Y29kZSAmIEJJVCg3KSkgPj4gNikgKw0KPiArCQkJCShlcnJvcl9jb2RlICYgQklUKDApKTsNCj4g Kw0KPiArCQkJaWYgKHJldCkNCj4gKwkJCQlkZXZfZXJyKGRldiwNCj4gKwkJCQkJIkVycm9yIExW VFMgJWQgc2Vuc2luZyBwb2ludHMgYXJlbid0IGlkbGUsIGVycm9yX2NvZGUgJWRcbiIsDQo+ICsJ CQkJCWksIGVycm9yX2NvZGUpOw0KPiArDQo+ICsJCQlpZiAoZXJyb3JfY29kZSAhPSAwKQ0KPiAr CQkJCWlzX2Vycm9yID0gMTsNCj4gKwkJfQ0KPiArDQo+ICsJCWlmIChpc19lcnJvciA9PSAwKQ0K PiArCQkJYnJlYWs7DQo+ICsJfQ0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBsdnRzX3Jlc2V0 KHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSkNCj4gK3sNCj4gKwlpbnQgaTsNCj4gKw0KPiAr CWZvciAoaSA9IDA7IGkgPCBsdnRzX2RhdGEtPm51bV9kb21haW47IGkrKykgew0KPiArCQlpZiAo bHZ0c19kYXRhLT5kb21haW5baV0ucmVzZXQpDQo+ICsJCQlyZXNldF9jb250cm9sX2Fzc2VydChs dnRzX2RhdGEtPmRvbWFpbltpXS5yZXNldCk7DQo+ICsNCj4gKwkJaWYgKGx2dHNfZGF0YS0+ZG9t YWluW2ldLnJlc2V0KQ0KPiArCQkJcmVzZXRfY29udHJvbF9kZWFzc2VydChsdnRzX2RhdGEtPmRv bWFpbltpXS5yZXNldCk7DQo+ICsJfQ0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBkZXZpY2Vf aWRlbnRpZmljYXRpb24oc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRhKQ0KPiArew0KPiArCXN0 cnVjdCBkZXZpY2UgKmRldiA9IGx2dHNfZGF0YS0+ZGV2Ow0KPiArCXVuc2lnbmVkIGludCBpLCBk YXRhOw0KPiArCXZvaWQgX19pb21lbSAqYmFzZTsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBs dnRzX2RhdGEtPm51bV90YzsgaSsrKSB7DQo+ICsJCWJhc2UgPSBHRVRfQkFTRV9BRERSKGkpOw0K PiArDQo+ICsJCXdyaXRlbChFTkFCTEVfTFZUU19DVFJMX0NMSywgTFZUU0NMS0VOXzAgKyBiYXNl KTsNCj4gKw0KPiArCQlsdnRzX3dyaXRlX2RldmljZShsdnRzX2RhdGEsIFJFU0VUX0FMTF9ERVZJ Q0VTLCBpKTsNCj4gKw0KPiArCQlsdnRzX3dyaXRlX2RldmljZShsdnRzX2RhdGEsIFJFQURfQkFD S19ERVZJQ0VfSUQsIGkpOw0KPiArDQo+ICsJCS8qIENoZWNrIExWVFMgZGV2aWNlIElEICovDQo+ ICsJCWRhdGEgPSAocmVhZGwoTFZUU19JRF8wICsgYmFzZSkgJiBHRU5NQVNLKDcsIDApKTsNCj4g KwkJaWYgKGRhdGEgIT0gKDB4ODEgKyBpKSkNCj4gKwkJCWRldl9lcnIoZGV2LCAiTFZUU19UQ18l ZCwgRGV2aWNlIElEIHNob3VsZCBiZSAweCV4LCBidXQgMHgleFxuIiwNCj4gKwkJCQlpLCAoMHg4 MSArIGkpLCBkYXRhKTsNCj4gKwl9DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyB2b2lkIGRpc2FibGVf YWxsX3NlbnNpbmdfcG9pbnRzKHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSkNCj4gK3sNCj4g Kwl1bnNpZ25lZCBpbnQgaTsNCj4gKwl2b2lkIF9faW9tZW0gKmJhc2U7DQo+ICsNCj4gKwlmb3Ig KGkgPSAwOyBpIDwgbHZ0c19kYXRhLT5udW1fdGM7IGkrKykgew0KPiArCQliYXNlID0gR0VUX0JB U0VfQUREUihpKTsNCj4gKwkJd3JpdGVsKERJU0FCTEVfU0VOU0lOR19QT0lOVCwgTFZUU01PTkNU TDBfMCArIGJhc2UpOw0KPiArCX0NCj4gK30NCj4gKw0KPiArc3RhdGljIHZvaWQgZW5hYmxlX2Fs bF9zZW5zaW5nX3BvaW50cyhzdHJ1Y3QgbHZ0c19kYXRhICpsdnRzX2RhdGEpDQo+ICt7DQo+ICsJ c3RydWN0IGRldmljZSAqZGV2ID0gbHZ0c19kYXRhLT5kZXY7DQo+ICsJc3RydWN0IHRjX3NldHRp bmdzICp0YyA9IGx2dHNfZGF0YS0+dGM7DQo+ICsJdW5zaWduZWQgaW50IGksIG51bTsNCj4gKwl2 b2lkIF9faW9tZW0gKmJhc2U7DQo+ICsNCj4gKwlmb3IgKGkgPSAwOyBpIDwgbHZ0c19kYXRhLT5u dW1fdGM7IGkrKykgew0KPiArCQliYXNlID0gR0VUX0JBU0VfQUREUihpKTsNCj4gKwkJbnVtID0g dGNbaV0ubnVtX3NlbnNvcjsNCj4gKw0KPiArCQlpZiAobnVtID4gQUxMX1NFTlNJTkdfUE9JTlRT KSB7DQo+ICsJCQlkZXZfZXJyKGRldiwNCj4gKwkJCQkiJXMsIExWVFMlZCwgaWxsZWdhbCBudW1i ZXIgb2Ygc2Vuc29yczogJWRcbiIsDQo+ICsJCQkJX19mdW5jX18sIGksIHRjW2ldLm51bV9zZW5z b3IpOw0KPiArCQkJY29udGludWU7DQo+ICsJCX0NCj4gKw0KPiArCQl3cml0ZWwoRU5BQkxFX1NF TlNJTkdfUE9JTlQobnVtKSwgTFZUU01PTkNUTDBfMCArIGJhc2UpOw0KPiArCX0NCj4gK30NCj4g Kw0KPiArc3RhdGljIHZvaWQgc2V0X3BvbGxpbmdfc3BlZWQoc3RydWN0IGx2dHNfZGF0YSAqbHZ0 c19kYXRhLCBpbnQgdGNfaWQpDQo+ICt7DQo+ICsJc3RydWN0IGRldmljZSAqZGV2ID0gbHZ0c19k YXRhLT5kZXY7DQo+ICsJc3RydWN0IHRjX3NldHRpbmdzICp0YyA9IGx2dHNfZGF0YS0+dGM7DQo+ ICsJdW5zaWduZWQgaW50IGx2dHNfbW9uX2N0bF8xLCBsdnRzX21vbl9jdGxfMjsNCj4gKwl2b2lk IF9faW9tZW0gKmJhc2U7DQo+ICsNCj4gKwliYXNlID0gR0VUX0JBU0VfQUREUih0Y19pZCk7DQo+ ICsNCj4gKwlsdnRzX21vbl9jdGxfMSA9ICgodGNbdGNfaWRdLnRjX3NwZWVkLmdyb3VwX2ludGVy dmFsX2RlbGF5IDw8IDIwKSAmIEdFTk1BU0soMjksIDIwKSkgfA0KPiArCQkJKHRjW3RjX2lkXS50 Y19zcGVlZC5wZXJpb2RfdW5pdCAmIEdFTk1BU0soOSwgMCkpOw0KPiArCWx2dHNfbW9uX2N0bF8y ID0gKCh0Y1t0Y19pZF0udGNfc3BlZWQuZmlsdGVyX2ludGVydmFsX2RlbGF5IDw8IDE2KSAmIEdF Tk1BU0soMjUsIDE2KSkgfA0KPiArCQkJKHRjW3RjX2lkXS50Y19zcGVlZC5zZW5zb3JfaW50ZXJ2 YWxfZGVsYXkgJiBHRU5NQVNLKDksIDApKTsNCj4gKwkvKg0KPiArCSAqIENsb2NrIHNvdXJjZSBv ZiBMVlRTIHRoZXJtYWwgY29udHJvbGxlciBpcyAyNk1Iei4NCj4gKwkgKiBQZXJpb2QgdW5pdCBp cyBhIGJhc2UgZm9yIGFsbCBpbnRlcnZhbCBkZWxheXMNCj4gKwkgKiBBbGwgaW50ZXJ2YWwgZGVs YXlzIG11c3QgbXVsdGlwbHkgaXQgdG8gY29udmVydCBhIHNldHRpbmcgdG8gdGltZS4NCj4gKwkg KiBGaWx0ZXIgaW50ZXJ2YWwgZGVsYXkgaXMgYSBkZWxheSBiZXR3ZWVuIHR3byBzYW1wbGVzIG9m IHRoZSBzYW1lIHNlbnNvcg0KPiArCSAqIFNlbnNvciBpbnRlcnZhbCBkZWxheSBpcyBhIGRlbGF5 IGJldHdlZW4gdHdvIHNhbXBsZXMgb2YgZGlmZmVybmV0IHNlbnNvcnMNCj4gKwkgKiBHcm91cCBp bnRlcnZhbCBkZWxheSBpcyBhIGRlbGF5IGJldHdlZW4gZGlmZmVyZW50IHJvdW5kcy4NCj4gKwkg KiBGb3IgZXhhbXBsZToNCj4gKwkgKiAgICAgSWYgUGVyaW9kIHVuaXQgPSBDLCBmaWx0ZXIgZGVs YXkgPSAxLCBzZW5zb3IgZGVsYXkgPSAyLCBncm91cCBkZWxheSA9IDEsDQo+ICsJICogICAgIGFu ZCB0d28gc2Vuc29ycywgVFMxIGFuZCBUUzIsIGFyZSBpbiBhIExWVFMgdGhlcm1hbCBjb250cm9s bGVyDQo+ICsJICogICAgIGFuZCB0aGVuDQo+ICsJICogICAgIFBlcmlvZCB1bml0ID0gQyAqIDEv MjZNICogMjU2ID0gMTIgKiAzOC40Nm5zICogMjU2ID0gMTE4LjE0OXVzDQo+ICsJICogICAgIEZp bHRlciBpbnRlcnZhbCBkZWxheSA9IDEgKiBQZXJpb2QgdW5pdCA9IDExOC4xNDl1cw0KPiArCSAq ICAgICBTZW5zb3IgaW50ZXJ2YWwgZGVsYXkgPSAyICogUGVyaW9kIHVuaXQgPSAyMzYuMjk4dXMN Cj4gKwkgKiAgICAgR3JvdXAgaW50ZXJ2YWwgZGVsYXkgPSAxICogUGVyaW9kIHVuaXQgPSAxMTgu MTQ5dXMNCj4gKwkgKg0KPiArCSAqICAgICBUUzEgICAgVFMxIC4uLiBUUzEgICAgVFMyICAgIFRT MiAuLi4gVFMyICAgIFRTMS4uLg0KPiArCSAqICAgICAgICA8LS0+IEZpbHRlciBpbnRlcnZhbCBk ZWxheQ0KPiArCSAqICAgICAgICAgICAgICAgICAgICAgICA8LS0+IFNlbnNvciBpbnRlcnZhbCBk ZWxheQ0KPiArCSAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg PC0tPiBHcm91cCBpbnRlcnZhbCBkZWxheQ0KPiArCSAqLw0KPiArCXdyaXRlbChsdnRzX21vbl9j dGxfMSwgTFZUU01PTkNUTDFfMCArIGJhc2UpOw0KPiArCXdyaXRlbChsdnRzX21vbl9jdGxfMiwg TFZUU01PTkNUTDJfMCArIGJhc2UpOw0KPiArDQo+ICsJZGV2X2luZm8oZGV2LCAiJXMgJWQsIExW VFNNT05DVEwxXzA9IDB4JXgsTFZUU01PTkNUTDJfMD0gMHgleFxuIiwNCj4gKwkJIF9fZnVuY19f LCB0Y19pZCwgcmVhZGwoTFZUU01PTkNUTDFfMCArIGJhc2UpLA0KPiArCQkgcmVhZGwoTFZUU01P TkNUTDJfMCArIGJhc2UpKTsNCj4gK30NCj4gKw0KPiArc3RhdGljIHZvaWQgc2V0X2h3X2ZpbHRl cihzdHJ1Y3QgbHZ0c19kYXRhICpsdnRzX2RhdGEsIGludCB0Y19pZCkNCj4gK3sNCj4gKwlzdHJ1 Y3QgZGV2aWNlICpkZXYgPSBsdnRzX2RhdGEtPmRldjsNCj4gKwlzdHJ1Y3QgdGNfc2V0dGluZ3Mg KnRjID0gbHZ0c19kYXRhLT50YzsNCj4gKwl1bnNpZ25lZCBpbnQgb3B0aW9uOw0KPiArCXZvaWQg X19pb21lbSAqYmFzZTsNCj4gKw0KPiArCWJhc2UgPSBHRVRfQkFTRV9BRERSKHRjX2lkKTsNCj4g KwlvcHRpb24gPSB0Y1t0Y19pZF0uaHdfZmlsdGVyICYgMHg3Ow0KPiArCS8qIGh3IGZpbHRlcg0K PiArCSAqIDAwMDogR2V0IG9uZSBzYW1wbGUNCj4gKwkgKiAwMDE6IEdldCAyIHNhbXBsZXMgYW5k IGF2ZXJhZ2UgdGhlbQ0KPiArCSAqIDAxMDogR2V0IDQgc2FtcGxlcywgZHJvcCBtYXggYW5kIG1p biwgdGhlbiBhdmVyYWdlIHRoZSByZXN0IG9mIDIgc2FtcGxlcw0KPiArCSAqIDAxMTogR2V0IDYg c2FtcGxlcywgZHJvcCBtYXggYW5kIG1pbiwgdGhlbiBhdmVyYWdlIHRoZSByZXN0IG9mIDQgc2Ft cGxlcw0KPiArCSAqIDEwMDogR2V0IDEwIHNhbXBsZXMsIGRyb3AgbWF4IGFuZCBtaW4sIHRoZW4g YXZlcmFnZSB0aGUgcmVzdCBvZiA4IHNhbXBsZXMNCj4gKwkgKiAxMDE6IEdldCAxOCBzYW1wbGVz LCBkcm9wIG1heCBhbmQgbWluLCB0aGVuIGF2ZXJhZ2UgdGhlIHJlc3Qgb2YgMTYgc2FtcGxlcw0K PiArCSAqLw0KPiArCW9wdGlvbiA9IChvcHRpb24gPDwgOSkgfCAob3B0aW9uIDw8IDYpIHwgKG9w dGlvbiA8PCAzKSB8IG9wdGlvbjsNCj4gKw0KPiArCXdyaXRlbChvcHRpb24sIExWVFNNU1JDVEww XzAgKyBiYXNlKTsNCj4gKwlkZXZfaW5mbyhkZXYsICIlcyAlZCwgTFZUU01TUkNUTDBfMD0gMHgl eFxuIiwNCj4gKwkJIF9fZnVuY19fLCB0Y19pZCwgcmVhZGwoTFZUU01TUkNUTDBfMCArIGJhc2Up KTsNCj4gK30NCj4gKw0KPiArc3RhdGljIGludCBnZXRfZG9taW5hdG9yX2luZGV4KHN0cnVjdCBs dnRzX2RhdGEgKmx2dHNfZGF0YSwgaW50IHRjX2lkKQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2Ug KmRldiA9IGx2dHNfZGF0YS0+ZGV2Ow0KPiArCXN0cnVjdCB0Y19zZXR0aW5ncyAqdGMgPSBsdnRz X2RhdGEtPnRjOw0KPiArCWludCBkX2luZGV4Ow0KPiArDQo+ICsJaWYgKHRjW3RjX2lkXS5kb21p bmF0b3Jfc2Vuc2luZ19wb2ludCA9PSBBTExfU0VOU0lOR19QT0lOVFMpIHsNCj4gKwkJZF9pbmRl eCA9IEFMTF9TRU5TSU5HX1BPSU5UUzsNCj4gKwl9IGVsc2UgaWYgKHRjW3RjX2lkXS5kb21pbmF0 b3Jfc2Vuc2luZ19wb2ludCA8DQo+ICsJCXRjW3RjX2lkXS5udW1fc2Vuc29yKXsNCj4gKwkJZF9p bmRleCA9IHRjW3RjX2lkXS5kb21pbmF0b3Jfc2Vuc2luZ19wb2ludDsNCj4gKwl9IGVsc2Ugew0K PiArCQlkZXZfZXJyKGRldiwNCj4gKwkJCSJFcnJvcjogTFZUUyVkLCBkb21pbmF0b3Jfc2Vuc2lu Z19wb2ludD0gJWQgc2hvdWxkIHNtYWxsZXIgdGhhbiBudW1fc2Vuc29yPSAlZFxuIiwNCj4gKwkJ CXRjX2lkLCB0Y1t0Y19pZF0uZG9taW5hdG9yX3NlbnNpbmdfcG9pbnQsDQo+ICsJCQl0Y1t0Y19p ZF0ubnVtX3NlbnNvcik7DQo+ICsNCj4gKwkJZGV2X2VycihkZXYsICJVc2UgdGhlIHNlbnNpbmcg cG9pbnQgMCBhcyB0aGUgZG9taW5hdGVkIHNlbnNvclxuIik7DQo+ICsJCWRfaW5kZXggPSBTRU5T SU5HX1BPSU5UMDsNCj4gKwl9DQo+ICsNCj4gKwlyZXR1cm4gZF9pbmRleDsNCj4gK30NCj4gKw0K PiArc3RhdGljIHZvaWQgZGlzYWJsZV9od19yZWJvb3RfaW50ZXJydXB0KHN0cnVjdCBsdnRzX2Rh dGEgKmx2dHNfZGF0YSwgaW50IHRjX2lkKQ0KPiArew0KPiArCXVuc2lnbmVkIGludCB0ZW1wOw0K PiArCXZvaWQgX19pb21lbSAqYmFzZTsNCj4gKw0KPiArCWJhc2UgPSBHRVRfQkFTRV9BRERSKHRj X2lkKTsNCj4gKw0KPiArCS8qIExWVFMgdGhlcm1hbCBjb250cm9sbGVyIGhhcyB0d28gaW50ZXJy dXB0cyBmb3IgdGhlcm1hbCBIVyByZWJvb3QNCj4gKwkgKiBPbmUgaXMgZm9yIEFQIFNXIGFuZCB0 aGUgb3RoZXIgaXMgZm9yIFJHVQ0KPiArCSAqIFRoZSBpbnRlcnJ1cHQgb2YgQVAgU1cgY2FuIHR1 cm4gb2ZmIGJ5IGEgYml0IG9mIGEgcmVnaXN0ZXIsIGJ1dA0KPiArCSAqIHRoZSBvdGhlciBmb3Ig UkdVIGNhbm5vdC4NCj4gKwkgKiBUbyBwcmV2ZW50IHJlYm9vdGluZyBkZXZpY2UgYWNjaWRlbnRh bGx5LCB3ZSBhcmUgZ29pbmcgdG8gYWRkDQo+ICsJICogYSBodWdlIG9mZnNldCB0byBMVlRTIGFu ZCBtYWtlIExWVFMgYWx3YXlzIHJlcG9ydCBleHRyZW1lbHkgbG93DQo+ICsJICogdGVtcGVyYXR1 cmUuDQo+ICsJICovDQo+ICsNCj4gKwkvKiBBZnRlciBhZGRpbmcgdGhlIGh1Z2Ugb2Zmc2V0IDB4 M0ZGRiwgTFZUUyBhbGF3eXMgYWRkcyB0aGUNCj4gKwkgKiBvZmZzZXQgdG8gTVNSX1JBVy4NCj4g KwkgKiBXaGVuIE1TUl9SQVcgaXMgbGFyZ2VyLCBTVyB3aWxsIGNvbnZlcnQgbG93ZXIgdGVtcGVy YXR1cmUvDQo+ICsJICovDQo+ICsJdGVtcCA9IHJlYWRsKExWVFNQUk9UQ1RMXzAgKyBiYXNlKTsN Cj4gKwl3cml0ZWwodGVtcCB8IDB4M0ZGRiwgTFZUU1BST1RDVExfMCArIGJhc2UpOw0KPiArDQo+ ICsJLyogRGlzYWJsZSB0aGUgaW50ZXJydXB0IG9mIEFQIFNXICovDQo+ICsJdGVtcCA9IHJlYWRs KExWVFNNT05JTlRfMCArIGJhc2UpOw0KPiArCXdyaXRlbCh0ZW1wICYgfihTVEFHRTNfSU5UX0VO KSwgTFZUU01PTklOVF8wICsgYmFzZSk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyB2b2lkIGVuYWJs ZV9od19yZWJvb3RfaW50ZXJydXB0KHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSwgaW50IHRj X2lkKQ0KPiArew0KPiArCXVuc2lnbmVkIGludCB0ZW1wOw0KPiArCXZvaWQgX19pb21lbSAqYmFz ZTsNCj4gKw0KPiArCWJhc2UgPSBHRVRfQkFTRV9BRERSKHRjX2lkKTsNCj4gKw0KPiArCS8qIEVu YWJsZSB0aGUgaW50ZXJydXB0IG9mIEFQIFNXICovDQo+ICsJdGVtcCA9IHJlYWRsKExWVFNNT05J TlRfMCArIGJhc2UpOw0KPiArCXdyaXRlbCh0ZW1wIHwgU1RBR0UzX0lOVF9FTiwgTFZUU01PTklO VF8wICsgYmFzZSk7DQo+ICsJLyogQ2xlYXIgdGhlIG9mZnNldCAqLw0KPiArCXRlbXAgPSByZWFk bChMVlRTUFJPVENUTF8wICsgYmFzZSk7DQo+ICsJd3JpdGVsKHRlbXAgJiB+UFJPVE9GRlNFVCwg TFZUU1BST1RDVExfMCArIGJhc2UpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBzZXRfdGNf aHdfcmVib290X3RocmVzaG9sZChzdHJ1Y3QgbHZ0c19kYXRhICpsdnRzX2RhdGEsDQo+ICsJCQkJ ICAgICAgIGludCB0cmlwX3BvaW50LCBpbnQgdGNfaWQpDQo+ICt7DQo+ICsJc3RydWN0IGRldmlj ZSAqZGV2ID0gbHZ0c19kYXRhLT5kZXY7DQo+ICsJdW5zaWduZWQgaW50IG1zcl9yYXcsIHRlbXAs IGNvbmZpZywgZF9pbmRleDsNCj4gKwl2b2lkIF9faW9tZW0gKmJhc2U7DQo+ICsNCj4gKwliYXNl ID0gR0VUX0JBU0VfQUREUih0Y19pZCk7DQo+ICsJZF9pbmRleCA9IGdldF9kb21pbmF0b3JfaW5k ZXgobHZ0c19kYXRhLCB0Y19pZCk7DQo+ICsNCj4gKwlkZXZfaW5mbyhkZXYsICIlczogTFZUUyVk LCB0aGUgZG9taW5hdG9yIHNlbnNpbmcgcG9pbnQ9ICVkXG4iLA0KPiArCQkgX19mdW5jX18sIHRj X2lkLCBkX2luZGV4KTsNCj4gKw0KPiArCWRpc2FibGVfaHdfcmVib290X2ludGVycnVwdChsdnRz X2RhdGEsIHRjX2lkKTsNCj4gKw0KPiArCXRlbXAgPSByZWFkbChMVlRTUFJPVENUTF8wICsgYmFz ZSk7DQo+ICsJaWYgKGRfaW5kZXggPT0gQUxMX1NFTlNJTkdfUE9JTlRTKSB7DQo+ICsJCS8qIE1h eGltdW0gb2YgNCBzZW5zaW5nIHBvaW50cyAqLw0KPiArCQljb25maWcgPSAoMHgxIDw8IDE2KTsN Cj4gKwkJd3JpdGVsKGNvbmZpZyB8IHRlbXAsIExWVFNQUk9UQ1RMXzAgKyBiYXNlKTsNCj4gKwl9 IGVsc2Ugew0KPiArCQkvKiBTZWxlY3QgcHJvdGVjdGlvbiBzZW5zb3IgKi8NCj4gKwkJY29uZmln ID0gKChkX2luZGV4IDw8IDIpICsgMHgyKSA8PCAxNjsNCj4gKwkJd3JpdGVsKGNvbmZpZyB8IHRl bXAsIExWVFNQUk9UQ1RMXzAgKyBiYXNlKTsNCj4gKwl9DQo+ICsNCj4gKwltc3JfcmF3ID0gbHZ0 c190ZW1wX3RvX3JhdygmbHZ0c19kYXRhLT5jb2VmZiwgdHJpcF9wb2ludCk7DQo+ICsJd3JpdGVs KG1zcl9yYXcsIExWVFNQUk9UVENfMCArIGJhc2UpOw0KPiArDQo+ICsJZW5hYmxlX2h3X3JlYm9v dF9pbnRlcnJ1cHQobHZ0c19kYXRhLCB0Y19pZCk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyB2b2lk IHNldF9hbGxfdGNfaHdfcmVib290KHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSkNCj4gK3sN Cj4gKwlzdHJ1Y3QgdGNfc2V0dGluZ3MgKnRjID0gbHZ0c19kYXRhLT50YzsNCj4gKwlpbnQgaSwg dHJpcF9wb2ludDsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBsdnRzX2RhdGEtPm51bV90Yzsg aSsrKSB7DQo+ICsJCXRyaXBfcG9pbnQgPSB0Y1tpXS5od19yZWJvb3RfdHJpcF9wb2ludDsNCj4g Kw0KPiArCQlpZiAodGNbaV0ubnVtX3NlbnNvciA9PSAwKQ0KPiArCQkJY29udGludWU7DQo+ICsN Cj4gKwkJaWYgKHRyaXBfcG9pbnQgPT0gRElTQUJMRV9USEVSTUFMX0hXX1JFQk9PVCkNCj4gKwkJ CWNvbnRpbnVlOw0KPiArDQo+ICsJCXNldF90Y19od19yZWJvb3RfdGhyZXNob2xkKGx2dHNfZGF0 YSwgdHJpcF9wb2ludCwgaSk7DQo+ICsJfQ0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IGx2dHNf aW5pdChzdHJ1Y3QgbHZ0c19kYXRhICpsdnRzX2RhdGEpDQo+ICt7DQo+ICsJc3RydWN0IHBsYXRm b3JtX29wcyAqb3BzID0gJmx2dHNfZGF0YS0+b3BzOw0KPiArCXN0cnVjdCBkZXZpY2UgKmRldiA9 IGx2dHNfZGF0YS0+ZGV2Ow0KPiArCWludCByZXQ7DQo+ICsNCj4gKwlyZXQgPSBjbGtfcHJlcGFy ZV9lbmFibGUobHZ0c19kYXRhLT5jbGspOw0KPiArCWlmIChyZXQpIHsNCj4gKwkJZGV2X2Vycihk ZXYsDQo+ICsJCQkiRXJyb3I6IEZhaWxlZCB0byBlbmFibGUgbHZ0cyBjb250cm9sbGVyIGNsb2Nr OiAlZFxuIiwNCj4gKwkJCXJldCk7DQo+ICsJCXJldHVybiByZXQ7DQo+ICsJfQ0KPiArDQo+ICsJ bHZ0c19yZXNldChsdnRzX2RhdGEpOw0KPiArDQo+ICsJZGV2aWNlX2lkZW50aWZpY2F0aW9uKGx2 dHNfZGF0YSk7DQo+ICsJaWYgKG9wcy0+ZGV2aWNlX2VuYWJsZV9hbmRfaW5pdCkNCj4gKwkJb3Bz LT5kZXZpY2VfZW5hYmxlX2FuZF9pbml0KGx2dHNfZGF0YSk7DQo+ICsNCj4gKwlpZiAoSVNfRU5B QkxFKEZFQVRVUkVfREVWSUNFX0FVVE9fUkNLKSkgew0KPiArCQlpZiAob3BzLT5kZXZpY2VfZW5h YmxlX2F1dG9fcmNrKQ0KPiArCQkJb3BzLT5kZXZpY2VfZW5hYmxlX2F1dG9fcmNrKGx2dHNfZGF0 YSk7DQo+ICsJfSBlbHNlIHsNCj4gKwkJaWYgKG9wcy0+ZGV2aWNlX3JlYWRfY291bnRfcmNfbikN Cj4gKwkJCW9wcy0+ZGV2aWNlX3JlYWRfY291bnRfcmNfbihsdnRzX2RhdGEpOw0KPiArCX0NCj4g Kw0KPiArCWlmIChvcHMtPnNldF9jYWxfZGF0YSkNCj4gKwkJb3BzLT5zZXRfY2FsX2RhdGEobHZ0 c19kYXRhKTsNCj4gKw0KPiArCWRpc2FibGVfYWxsX3NlbnNpbmdfcG9pbnRzKGx2dHNfZGF0YSk7 DQo+ICsJd2FpdF9hbGxfdGNfc2Vuc2luZ19wb2ludF9pZGxlKGx2dHNfZGF0YSk7DQo+ICsJaWYg KG9wcy0+aW5pdF9jb250cm9sbGVyKQ0KPiArCQlvcHMtPmluaXRfY29udHJvbGxlcihsdnRzX2Rh dGEpOw0KPiArCWVuYWJsZV9hbGxfc2Vuc2luZ19wb2ludHMobHZ0c19kYXRhKTsNCj4gKw0KPiAr CXNldF9hbGxfdGNfaHdfcmVib290KGx2dHNfZGF0YSk7DQo+ICsNCj4gKwlyZXR1cm4gMDsNCj4g K30NCj4gKw0KPiArc3RhdGljIGludCBwcmVwYXJlX2NhbGlicmF0aW9uX2RhdGEoc3RydWN0IGx2 dHNfZGF0YSAqbHZ0c19kYXRhKQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2UgKmRldiA9IGx2dHNf ZGF0YS0+ZGV2Ow0KPiArCXN0cnVjdCBzZW5zb3JfY2FsX2RhdGEgKmNhbF9kYXRhID0gJmx2dHNf ZGF0YS0+Y2FsX2RhdGE7DQo+ICsJc3RydWN0IHBsYXRmb3JtX29wcyAqb3BzID0gJmx2dHNfZGF0 YS0+b3BzOw0KPiArCWludCBpLCBvZmZzZXQsIHNpemU7DQo+ICsJY2hhciBidWZmZXJbNTEyXTsN Cj4gKw0KPiArCWNhbF9kYXRhLT5jb3VudF9yID0gZGV2bV9rY2FsbG9jKGRldiwgbHZ0c19kYXRh LT5udW1fc2Vuc29yLA0KPiArCQkJCQkgc2l6ZW9mKCpjYWxfZGF0YS0+Y291bnRfciksIEdGUF9L RVJORUwpOw0KPiArCWlmICghY2FsX2RhdGEtPmNvdW50X3IpDQo+ICsJCXJldHVybiAtRU5PTUVN Ow0KPiArDQo+ICsJY2FsX2RhdGEtPmNvdW50X3JjID0gZGV2bV9rY2FsbG9jKGRldiwgbHZ0c19k YXRhLT5udW1fc2Vuc29yLA0KPiArCQkJCQkgIHNpemVvZigqY2FsX2RhdGEtPmNvdW50X3JjKSwg R0ZQX0tFUk5FTCk7DQo+ICsJaWYgKCFjYWxfZGF0YS0+Y291bnRfcmMpDQo+ICsJCXJldHVybiAt RU5PTUVNOw0KPiArDQo+ICsJaWYgKG9wcy0+ZWZ1c2VfdG9fY2FsX2RhdGEpDQo+ICsJCW9wcy0+ ZWZ1c2VfdG9fY2FsX2RhdGEobHZ0c19kYXRhKTsNCj4gKw0KPiArCWNhbF9kYXRhLT51c2VfZmFr ZV9lZnVzZSA9IDE7DQo+ICsJaWYgKGNhbF9kYXRhLT5nb2xkZW5fdGVtcCAhPSAwKSB7DQo+ICsJ CWNhbF9kYXRhLT51c2VfZmFrZV9lZnVzZSA9IDA7DQo+ICsJfSBlbHNlIHsNCj4gKwkJZm9yIChp ID0gMDsgaSA8IGx2dHNfZGF0YS0+bnVtX3NlbnNvcjsgaSsrKSB7DQo+ICsJCQlpZiAoY2FsX2Rh dGEtPmNvdW50X3JbaV0gIT0gMCB8fA0KPiArCQkJICAgIGNhbF9kYXRhLT5jb3VudF9yY1tpXSAh PSAwKSB7DQo+ICsJCQkJY2FsX2RhdGEtPnVzZV9mYWtlX2VmdXNlID0gMDsNCj4gKwkJCQlicmVh azsNCj4gKwkJCX0NCj4gKwkJfQ0KPiArCX0NCj4gKw0KPiArCWlmIChjYWxfZGF0YS0+dXNlX2Zh a2VfZWZ1c2UpIHsNCj4gKwkJLyogSXQgbWVhbnMgYWxsIGVmdXNlIGRhdGEgYXJlIGVxdWFsIHRv IDAgKi8NCj4gKwkJZGV2X2VycihkZXYsDQo+ICsJCQkiW2x2dHNfY2FsXSBUaGlzIHNhbXBsZSBp cyBub3QgY2FsaWJyYXRlZCwgZmFrZSAhIVxuIik7DQo+ICsNCj4gKwkJY2FsX2RhdGEtPmdvbGRl bl90ZW1wID0gY2FsX2RhdGEtPmRlZmF1bHRfZ29sZGVuX3RlbXA7DQo+ICsJCWZvciAoaSA9IDA7 IGkgPCBsdnRzX2RhdGEtPm51bV9zZW5zb3I7IGkrKykgew0KPiArCQkJY2FsX2RhdGEtPmNvdW50 X3JbaV0gPSBjYWxfZGF0YS0+ZGVmYXVsdF9jb3VudF9yOw0KPiArCQkJY2FsX2RhdGEtPmNvdW50 X3JjW2ldID0gY2FsX2RhdGEtPmRlZmF1bHRfY291bnRfcmM7DQo+ICsJCX0NCj4gKwl9DQo+ICsN Cj4gKwlsdnRzX2RhdGEtPmNvZWZmLmdvbGRlbl90ZW1wID0gY2FsX2RhdGEtPmdvbGRlbl90ZW1w Ow0KPiArDQo+ICsJZGV2X2luZm8oZGV2LCAiW2x2dHNfY2FsXSBnb2xkZW5fdGVtcCA9ICVkXG4i LCBjYWxfZGF0YS0+Z29sZGVuX3RlbXApOw0KPiArDQo+ICsJc2l6ZSA9IHNpemVvZihidWZmZXIp Ow0KPiArCW9mZnNldCA9IHNucHJpbnRmKGJ1ZmZlciwgc2l6ZSwgIltsdnRzX2NhbF0gbnVtOmdf Y291bnQ6Z19jb3VudF9yYyAiKTsNCj4gKwlmb3IgKGkgPSAwOyBpIDwgbHZ0c19kYXRhLT5udW1f c2Vuc29yOyBpKyspDQo+ICsJCW9mZnNldCArPSBzbnByaW50ZihidWZmZXIgKyBvZmZzZXQsIHNp emUgLSBvZmZzZXQsICIlZDolZDolZCAiLA0KPiArCQkJCSAgIGksIGNhbF9kYXRhLT5jb3VudF9y W2ldLCBjYWxfZGF0YS0+Y291bnRfcmNbaV0pOw0KPiArDQo+ICsJYnVmZmVyW29mZnNldF0gPSAn XDAnOw0KPiArCWRldl9pbmZvKGRldiwgIiVzXG4iLCBidWZmZXIpOw0KPiArDQo+ICsJcmV0dXJu IDA7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQgZ2V0X2NhbGlicmF0aW9uX2RhdGEoc3RydWN0 IGx2dHNfZGF0YSAqbHZ0c19kYXRhKQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2UgKmRldiA9IGx2 dHNfZGF0YS0+ZGV2Ow0KPiArCWNoYXIgY2VsbF9uYW1lWzhdOw0KPiArCXN0cnVjdCBudm1lbV9j ZWxsICpjZWxsOw0KPiArCXUzMiAqYnVmOw0KPiArCXNpemVfdCBsZW47DQo+ICsJaW50IGksIGos IGluZGV4ID0gMCwgcmV0Ow0KPiArDQo+ICsJbHZ0c19kYXRhLT5lZnVzZSA9IGRldm1fa2NhbGxv YyhkZXYsIGx2dHNfZGF0YS0+bnVtX2VmdXNlX2FkZHIsDQo+ICsJCQkJCXNpemVvZigqbHZ0c19k YXRhLT5lZnVzZSksIEdGUF9LRVJORUwpOw0KPiArCWlmICghbHZ0c19kYXRhLT5lZnVzZSkNCj4g KwkJcmV0dXJuIC1FTk9NRU07DQo+ICsNCj4gKwlmb3IgKGkgPSAwOyBpIDwgbHZ0c19kYXRhLT5u dW1fZWZ1c2VfYmxvY2s7IGkrKykgew0KPiArCQlzbnByaW50ZihjZWxsX25hbWUsIHNpemVvZihj ZWxsX25hbWUpLCAiZV9kYXRhJWQiLCBpICsgMSk7DQo+ICsJCWNlbGwgPSBudm1lbV9jZWxsX2dl dChkZXYsIGNlbGxfbmFtZSk7DQo+ICsJCWlmIChJU19FUlIoY2VsbCkpIHsNCj4gKwkJCWRldl9l cnIoZGV2LCAiRXJyb3I6IEZhaWxlZCB0byBnZXQgbnZtZW0gY2VsbCAlc1xuIiwgY2VsbF9uYW1l KTsNCj4gKwkJCXJldHVybiBQVFJfRVJSKGNlbGwpOw0KPiArCQl9DQo+ICsNCj4gKwkJYnVmID0g KHUzMiAqKW52bWVtX2NlbGxfcmVhZChjZWxsLCAmbGVuKTsNCj4gKwkJbnZtZW1fY2VsbF9wdXQo Y2VsbCk7DQo+ICsNCj4gKwkJaWYgKElTX0VSUihidWYpKQ0KPiArCQkJcmV0dXJuIFBUUl9FUlIo YnVmKTsNCj4gKw0KPiArCQlmb3IgKGogPSAwOyBqIDwgKGxlbiAvIHNpemVvZih1MzIpKTsgaisr KSB7DQo+ICsJCQlpZiAoaW5kZXggPj0gbHZ0c19kYXRhLT5udW1fZWZ1c2VfYWRkcikgew0KPiAr CQkJCWRldl9lcnIoZGV2LCAiQXJyYXkgZWZ1c2UgaXMgZ29pbmcgdG8gb3ZlcmZsb3ciKTsNCj4g KwkJCQlrZnJlZShidWYpOw0KPiArCQkJCXJldHVybiAtRUlOVkFMOw0KPiArCQkJfQ0KPiArDQo+ ICsJCQlsdnRzX2RhdGEtPmVmdXNlW2luZGV4XSA9IGJ1ZltqXTsNCj4gKwkJCWluZGV4Kys7DQo+ ICsJCX0NCj4gKw0KPiArCQlrZnJlZShidWYpOw0KPiArCX0NCj4gKw0KPiArCXJldCA9IHByZXBh cmVfY2FsaWJyYXRpb25fZGF0YShsdnRzX2RhdGEpOw0KPiArDQo+ICsJcmV0dXJuIHJldDsNCj4g K30NCj4gKw0KPiArc3RhdGljIGludCBvZl91cGRhdGVfbHZ0c19kYXRhKHN0cnVjdCBsdnRzX2Rh dGEgKmx2dHNfZGF0YSwNCj4gKwkJCSAgICAgICBzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2 KQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2UgKmRldiA9IGx2dHNfZGF0YS0+ZGV2Ow0KPiArCXN0 cnVjdCBwb3dlcl9kb21haW4gKmRvbWFpbjsNCj4gKwlzdHJ1Y3QgcmVzb3VyY2UgKnJlczsNCj4g Kwl1bnNpZ25lZCBpbnQgaTsNCj4gKwlpbnQgcmV0Ow0KPiArDQo+ICsJbHZ0c19kYXRhLT5jbGsg PSBkZXZtX2Nsa19nZXQoZGV2LCAibHZ0c19jbGsiKTsNCj4gKwlpZiAoSVNfRVJSKGx2dHNfZGF0 YS0+Y2xrKSkNCj4gKwkJcmV0dXJuIFBUUl9FUlIobHZ0c19kYXRhLT5jbGspOw0KPiArDQo+ICsJ ZG9tYWluID0gZGV2bV9rY2FsbG9jKGRldiwgbHZ0c19kYXRhLT5udW1fZG9tYWluLCBzaXplb2Yo KmRvbWFpbiksIEdGUF9LRVJORUwpOw0KPiArCWlmICghZG9tYWluKQ0KPiArCQlyZXR1cm4gLUVO T01FTTsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBsdnRzX2RhdGEtPm51bV9kb21haW47IGkr Kykgew0KPiArCQkvKiBHZXQgYmFzZSBhZGRyZXNzICovDQo+ICsJCXJlcyA9IHBsYXRmb3JtX2dl dF9yZXNvdXJjZShwZGV2LCBJT1JFU09VUkNFX01FTSwgaSk7DQo+ICsJCWlmICghcmVzKSB7DQo+ ICsJCQlkZXZfZXJyKGRldiwgIk5vIElPIHJlc291cmNlLCBpbmRleCAlZFxuIiwgaSk7DQo+ICsJ CQlyZXR1cm4gLUVOWElPOw0KPiArCQl9DQo+ICsNCj4gKwkJZG9tYWluW2ldLmJhc2UgPSBkZXZt X2lvcmVtYXBfcmVzb3VyY2UoZGV2LCByZXMpOw0KPiArCQlpZiAoSVNfRVJSKGRvbWFpbltpXS5i YXNlKSkgew0KPiArCQkJZGV2X2VycihkZXYsICJGYWlsZWQgdG8gcmVtYXAgaW8sIGluZGV4ICVk XG4iLCBpKTsNCj4gKwkJCXJldHVybiBQVFJfRVJSKGRvbWFpbltpXS5iYXNlKTsNCj4gKwkJfQ0K PiArDQo+ICsJCS8qIEdldCBpbnRlcnJ1cHQgbnVtYmVyICovDQo+ICsJCXJlcyA9IHBsYXRmb3Jt X2dldF9yZXNvdXJjZShwZGV2LCBJT1JFU09VUkNFX0lSUSwgaSk7DQo+ICsJCWlmICghcmVzKSB7 DQo+ICsJCQlkZXZfZXJyKGRldiwgIk5vIGlycSByZXNvdXJjZSwgaW5kZXggJWRcbiIsIGkpOw0K PiArCQkJcmV0dXJuIC1FSU5WQUw7DQo+ICsJCX0NCj4gKwkJZG9tYWluW2ldLmlycV9udW0gPSBy ZXMtPnN0YXJ0Ow0KPiArDQo+ICsJCS8qIEdldCByZXNldCBjb250cm9sICovDQo+ICsJCWRvbWFp bltpXS5yZXNldCA9IGRldm1fcmVzZXRfY29udHJvbF9nZXRfYnlfaW5kZXgoZGV2LCBpKTsNCj4g KwkJaWYgKElTX0VSUihkb21haW5baV0ucmVzZXQpKSB7DQo+ICsJCQlkZXZfZXJyKGRldiwgIkZh aWxlZCB0byBnZXQsIGluZGV4ICVkXG4iLCBpKTsNCj4gKwkJCXJldHVybiBQVFJfRVJSKGRvbWFp bltpXS5yZXNldCk7DQo+ICsJCX0NCj4gKwl9DQo+ICsNCj4gKwlsdnRzX2RhdGEtPmRvbWFpbiA9 IGRvbWFpbjsNCj4gKw0KPiArCWx2dHNfZGF0YS0+c2VuX2RhdGEgPSBkZXZtX2tjYWxsb2MoZGV2 LCBsdnRzX2RhdGEtPm51bV9zZW5zb3IsDQo+ICsJCQkJCSAgIHNpemVvZigqbHZ0c19kYXRhLT5z ZW5fZGF0YSksIEdGUF9LRVJORUwpOw0KPiArCWlmICghbHZ0c19kYXRhLT5zZW5fZGF0YSkNCj4g KwkJcmV0dXJuIC1FTk9NRU07DQo+ICsNCj4gKwlyZXQgPSBnZXRfY2FsaWJyYXRpb25fZGF0YShs dnRzX2RhdGEpOw0KPiArCWlmIChyZXQpDQo+ICsJCXJldHVybiByZXQ7DQo+ICsNCj4gKwlyZXR1 cm4gMDsNCj4gK30NCj4gKw0KPiArc3RhdGljIHZvaWQgbHZ0c19kZXZpY2VfY2xvc2Uoc3RydWN0 IGx2dHNfZGF0YSAqbHZ0c19kYXRhKQ0KPiArew0KPiArCXVuc2lnbmVkIGludCBpOw0KPiArCXZv aWQgX19pb21lbSAqYmFzZTsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBsdnRzX2RhdGEtPm51 bV90YzsgaSsrKSB7DQo+ICsJCWJhc2UgPSBHRVRfQkFTRV9BRERSKGkpOw0KPiArCQlsdnRzX3dy aXRlX2RldmljZShsdnRzX2RhdGEsIFJFU0VUX0FMTF9ERVZJQ0VTLCBpKTsNCj4gKwkJd3JpdGVs KERJU0FCTEVfTFZUU19DVFJMX0NMSywgTFZUU0NMS0VOXzAgKyBiYXNlKTsNCj4gKwl9DQo+ICt9 DQo+ICsNCj4gK3N0YXRpYyB2b2lkIGx2dHNfY2xvc2Uoc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19k YXRhKQ0KPiArew0KPiArCWRpc2FibGVfYWxsX3NlbnNpbmdfcG9pbnRzKGx2dHNfZGF0YSk7DQo+ ICsJd2FpdF9hbGxfdGNfc2Vuc2luZ19wb2ludF9pZGxlKGx2dHNfZGF0YSk7DQo+ICsJbHZ0c19k ZXZpY2VfY2xvc2UobHZ0c19kYXRhKTsNCj4gKwljbGtfZGlzYWJsZV91bnByZXBhcmUobHZ0c19k YXRhLT5jbGspOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCB0Y19pcnFfaGFuZGxlcihzdHJ1 Y3QgbHZ0c19kYXRhICpsdnRzX2RhdGEsIGludCB0Y19pZCkNCj4gK3sNCj4gKwlzdHJ1Y3QgZGV2 aWNlICpkZXYgPSBsdnRzX2RhdGEtPmRldjsNCj4gKwl1bnNpZ25lZCBpbnQgcmV0ID0gMDsNCj4g Kwl2b2lkIF9faW9tZW0gKmJhc2U7DQo+ICsNCj4gKwliYXNlID0gR0VUX0JBU0VfQUREUih0Y19p ZCk7DQo+ICsNCj4gKwlyZXQgPSByZWFkbChMVlRTTU9OSU5UU1RTXzAgKyBiYXNlKTsNCj4gKwkv KiBXcml0ZSBiYWNrIHRvIGNsZWFyIGludGVycnVwdCBzdGF0dXMgKi8NCj4gKwl3cml0ZWwocmV0 LCBMVlRTTU9OSU5UU1RTXzAgKyBiYXNlKTsNCj4gKw0KPiArCWRldl9pbmZvKGRldiwgIltUaGVy bWFsIElSUV0gTFZUUyB0aGVybWFsIGNvbnRyb2xsZXIgJWQsIExWVFNNT05JTlRTVFM9MHglMDh4 XG4iLA0KPiArCQkgdGNfaWQsIHJldCk7DQo+ICsNCj4gKwlpZiAocmV0ICYgVEhFUk1BTF9QUk9U RUNUSU9OX1NUQUdFXzMpDQo+ICsJCWRldl9pbmZvKGRldiwNCj4gKwkJCSAiW1RoZXJtYWwgSVJR XTogVGhlcm1hbCBwcm90ZWN0aW9uIHN0YWdlIDMgaW50ZXJydXB0IHRyaWdnZXJlZFxuIik7DQo+ ICt9DQo+ICsNCj4gK3N0YXRpYyBpcnFyZXR1cm5fdCBpcnFfaGFuZGxlcihpbnQgaXJxLCB2b2lk ICpkZXZfaWQpDQo+ICt7DQo+ICsJc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRhID0gKHN0cnVj dCBsdnRzX2RhdGEgKilkZXZfaWQ7DQo+ICsJc3RydWN0IGRldmljZSAqZGV2ID0gbHZ0c19kYXRh LT5kZXY7DQo+ICsJc3RydWN0IHRjX3NldHRpbmdzICp0YyA9IGx2dHNfZGF0YS0+dGM7DQo+ICsJ dW5zaWduZWQgaW50IGksICppcnFfYml0bWFwOw0KPiArCXZvaWQgX19pb21lbSAqYmFzZTsNCj4g Kw0KPiArCWlycV9iaXRtYXAgPSBrY2FsbG9jKGx2dHNfZGF0YS0+bnVtX2RvbWFpbiwgc2l6ZW9m KCppcnFfYml0bWFwKSwgR0ZQX0FUT01JQyk7DQo+ICsNCj4gKwlpZiAoIWlycV9iaXRtYXApDQo+ ICsJCXJldHVybiBJUlFfTk9ORTsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBsdnRzX2RhdGEt Pm51bV9kb21haW47IGkrKykgew0KPiArCQliYXNlID0gbHZ0c19kYXRhLT5kb21haW5baV0uYmFz ZTsNCj4gKwkJaXJxX2JpdG1hcFtpXSA9IHJlYWRsKFRIRVJNSU5UU1QgKyBiYXNlKTsNCj4gKwkJ ZGV2X2luZm8oZGV2LCAiJXMgOiBUSEVSTUlOVFNUID0gMHgleFxuIiwgX19mdW5jX18sIGlycV9i aXRtYXBbaV0pOw0KPiArCX0NCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBsdnRzX2RhdGEtPm51 bV90YzsgaSsrKSB7DQo+ICsJCWlmICgoaXJxX2JpdG1hcFt0Y1tpXS5kb21haW5faW5kZXhdICYg dGNbaV0uaXJxX2JpdCkgPT0gMCkNCj4gKwkJCXRjX2lycV9oYW5kbGVyKGx2dHNfZGF0YSwgaSk7 DQo+ICsJfQ0KPiArDQo+ICsJa2ZyZWUoaXJxX2JpdG1hcCk7DQo+ICsNCj4gKwlyZXR1cm4gSVJR X0hBTkRMRUQ7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQgbHZ0c19yZWdpc3Rlcl9pcnFfaGFu ZGxlcihzdHJ1Y3QgbHZ0c19kYXRhICpsdnRzX2RhdGEpDQo+ICt7DQo+ICsJc3RydWN0IGRldmlj ZSAqZGV2ID0gbHZ0c19kYXRhLT5kZXY7DQo+ICsJdW5zaWduZWQgaW50IGk7DQo+ICsJaW50IHJl dDsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBsdnRzX2RhdGEtPm51bV9kb21haW47IGkrKykg ew0KPiArCQlyZXQgPSBkZXZtX3JlcXVlc3RfaXJxKGRldiwgbHZ0c19kYXRhLT5kb21haW5baV0u aXJxX251bSwgaXJxX2hhbmRsZXIsDQo+ICsJCQkJICAgICAgIElSUUZfVFJJR0dFUl9ISUdILCAi bXRrX2x2dHMiLCBsdnRzX2RhdGEpOw0KPiArDQo+ICsJCWlmIChyZXQpIHsNCj4gKwkJCWRldl9l cnIoZGV2LCAiRmFpbGVkIHRvIHJlZ2lzdGVyIExWVFMgSVJRLCByZXQgJWQsIGRvbWFpbiAlZCBp cnFfbnVtICVkXG4iLA0KPiArCQkJCXJldCwgaSwgbHZ0c19kYXRhLT5kb21haW5baV0uaXJxX251 bSk7DQo+ICsJCQlsdnRzX2Nsb3NlKGx2dHNfZGF0YSk7DQo+ICsJCQlyZXR1cm4gcmV0Ow0KPiAr CQl9DQo+ICsJfQ0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQg bHZ0c19yZWdpc3Rlcl90aGVybWFsX3pvbmVzKHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSkN Cj4gK3sNCj4gKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSBsdnRzX2RhdGEtPmRldjsNCj4gKwlzdHJ1 Y3QgdGhlcm1hbF96b25lX2RldmljZSAqdHpkZXY7DQo+ICsJc3RydWN0IHNvY190ZW1wX3R6ICps dnRzX3R6Ow0KPiArCWludCBpLCByZXQ7DQo+ICsNCj4gKwlmb3IgKGkgPSAwOyBpIDwgbHZ0c19k YXRhLT5udW1fc2Vuc29yICsgMTsgaSsrKSB7DQo+ICsJCWx2dHNfdHogPSBkZXZtX2t6YWxsb2Mo ZGV2LCBzaXplb2YoKmx2dHNfdHopLCBHRlBfS0VSTkVMKTsNCj4gKwkJaWYgKCFsdnRzX3R6KSB7 DQo+ICsJCQlsdnRzX2Nsb3NlKGx2dHNfZGF0YSk7DQo+ICsJCQlyZXR1cm4gLUVOT01FTTsNCj4g KwkJfQ0KPiArDQo+ICsJCWx2dHNfdHotPmlkID0gaTsNCj4gKwkJbHZ0c190ei0+bHZ0c19kYXRh ID0gbHZ0c19kYXRhOw0KPiArDQo+ICsJCXR6ZGV2ID0gZGV2bV90aGVybWFsX3pvbmVfb2Zfc2Vu c29yX3JlZ2lzdGVyKGRldiwgbHZ0c190ei0+aWQsDQo+ICsJCQkJCQkJICAgICBsdnRzX3R6LCAm c29jX3RlbXBfbHZ0c19vcHMpOw0KPiArDQo+ICsJCWlmIChJU19FUlIodHpkZXYpKSB7DQo+ICsJ CQlpZiAobHZ0c190ei0+aWQgIT0gMCkNCj4gKwkJCQlyZXR1cm4gMDsNCj4gKw0KPiArCQkJcmV0 ID0gUFRSX0VSUih0emRldik7DQo+ICsJCQlkZXZfZXJyKGRldiwgIkVycm9yOiBGYWlsZWQgdG8g cmVnaXN0ZXIgbHZ0cyB0eiAlZCwgcmV0ID0gJWRcbiIsDQo+ICsJCQkJbHZ0c190ei0+aWQsIHJl dCk7DQo+ICsJCQlsdnRzX2Nsb3NlKGx2dHNfZGF0YSk7DQo+ICsJCQlyZXR1cm4gcmV0Ow0KPiAr CQl9DQo+ICsJfQ0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQg bHZ0c19wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQ0KPiArew0KPiArCXN0cnVj dCBkZXZpY2UgKmRldiA9ICZwZGV2LT5kZXY7DQo+ICsJc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19k YXRhOw0KPiArCWludCByZXQ7DQo+ICsNCj4gKwlsdnRzX2RhdGEgPSAoc3RydWN0IGx2dHNfZGF0 YSAqKW9mX2RldmljZV9nZXRfbWF0Y2hfZGF0YShkZXYpOw0KPiArDQo+ICsJaWYgKCFsdnRzX2Rh dGEpCXsNCj4gKwkJZGV2X2VycihkZXYsICJFcnJvcjogRmFpbGVkIHRvIGdldCBsdnRzIHBsYXRm b3JtIGRhdGFcbiIpOw0KPiArCQlyZXR1cm4gLUVOT0RBVEE7DQo+ICsJfQ0KPiArDQo+ICsJbHZ0 c19kYXRhLT5kZXYgPSAmcGRldi0+ZGV2Ow0KPiArDQo+ICsJcmV0ID0gb2ZfdXBkYXRlX2x2dHNf ZGF0YShsdnRzX2RhdGEsIHBkZXYpOw0KPiArCWlmIChyZXQpDQo+ICsJCXJldHVybiByZXQ7DQo+ ICsNCj4gKwlwbGF0Zm9ybV9zZXRfZHJ2ZGF0YShwZGV2LCBsdnRzX2RhdGEpOw0KPiArDQo+ICsJ cmV0ID0gbHZ0c19pbml0KGx2dHNfZGF0YSk7DQo+ICsJaWYgKHJldCkNCj4gKwkJcmV0dXJuIHJl dDsNCj4gKw0KPiArCXJldCA9IGx2dHNfcmVnaXN0ZXJfaXJxX2hhbmRsZXIobHZ0c19kYXRhKTsN Cj4gKwlpZiAocmV0KQ0KPiArCQlyZXR1cm4gcmV0Ow0KPiArDQo+ICsJcmV0ID0gbHZ0c19yZWdp c3Rlcl90aGVybWFsX3pvbmVzKGx2dHNfZGF0YSk7DQo+ICsJaWYgKHJldCkNCj4gKwkJcmV0dXJu IHJldDsNCj4gKw0KPiArCXJldHVybiAwOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IGx2dHNf cmVtb3ZlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpDQo+ICt7DQo+ICsJc3RydWN0IGx2 dHNfZGF0YSAqbHZ0c19kYXRhOw0KPiArDQo+ICsJbHZ0c19kYXRhID0gKHN0cnVjdCBsdnRzX2Rh dGEgKilwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsNCj4gKw0KPiArCWx2dHNfY2xvc2UobHZ0 c19kYXRhKTsNCj4gKw0KPiArCXJldHVybiAwOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IGx2 dHNfc3VzcGVuZChzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2LCBwbV9tZXNzYWdlX3Qgc3Rh dGUpDQo+ICt7DQo+ICsJc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRhOw0KPiArDQo+ICsJbHZ0 c19kYXRhID0gKHN0cnVjdCBsdnRzX2RhdGEgKilwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsN Cj4gKw0KPiArCWx2dHNfY2xvc2UobHZ0c19kYXRhKTsNCj4gKw0KPiArCXJldHVybiAwOw0KPiAr fQ0KPiArDQo+ICtzdGF0aWMgaW50IGx2dHNfcmVzdW1lKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2Ug KnBkZXYpDQo+ICt7DQo+ICsJaW50IHJldDsNCj4gKwlzdHJ1Y3QgbHZ0c19kYXRhICpsdnRzX2Rh dGE7DQo+ICsNCj4gKwlsdnRzX2RhdGEgPSAoc3RydWN0IGx2dHNfZGF0YSAqKXBsYXRmb3JtX2dl dF9kcnZkYXRhKHBkZXYpOw0KPiArDQo+ICsJcmV0ID0gbHZ0c19pbml0KGx2dHNfZGF0YSk7DQo+ ICsJaWYgKHJldCkNCj4gKwkJcmV0dXJuIHJldDsNCj4gKw0KPiArCXJldHVybiAwOw0KPiArfQ0K PiArDQo+ICsvKj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09DQo+ICsgKiBMVlRTIHY0IGNvbW1vbiBjb2RlDQo+ICsgKj09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQo+ICsgKi8NCj4gK3N0YXRpYyB2b2lkIGRl dmljZV9lbmFibGVfYW5kX2luaXRfdjQoc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRhKQ0KPiAr ew0KPiArCXVuc2lnbmVkIGludCBpOw0KPiArDQo+ICsJZm9yIChpID0gMDsgaSA8IGx2dHNfZGF0 YS0+bnVtX3RjOyBpKyspIHsNCj4gKwkJbHZ0c193cml0ZV9kZXZpY2UobHZ0c19kYXRhLCBTVE9Q X0NPVU5USU5HX1Y0LCBpKTsNCj4gKwkJbHZ0c193cml0ZV9kZXZpY2UobHZ0c19kYXRhLCBTRVRf UkdfVFNGTV9MUERMWV9WNCwgaSk7DQo+ICsJCWx2dHNfd3JpdGVfZGV2aWNlKGx2dHNfZGF0YSwg U0VUX0NPVU5USU5HX1dJTkRPV18yMFVTMV9WNCwgaSk7DQo+ICsJCWx2dHNfd3JpdGVfZGV2aWNl KGx2dHNfZGF0YSwgU0VUX0NPVU5USU5HX1dJTkRPV18yMFVTMl9WNCwgaSk7DQo+ICsJCWx2dHNf d3JpdGVfZGV2aWNlKGx2dHNfZGF0YSwgVFNWMkZfQ0hPUF9DS1NFTF9BTkRfVFNWMkZfRU5fVjQs IGkpOw0KPiArCQlsdnRzX3dyaXRlX2RldmljZShsdnRzX2RhdGEsIFRTQkdfREVNX0NLU0VMX1hf VFNCR19DSE9QX0VOX1Y0LCBpKTsNCj4gKwkJbHZ0c193cml0ZV9kZXZpY2UobHZ0c19kYXRhLCBT RVRfVFNfUlNWX1Y0LCBpKTsNCj4gKwkJbHZ0c193cml0ZV9kZXZpY2UobHZ0c19kYXRhLCBTRVRf VFNfRU5fVjQsIGkpOw0KPiArCQlsdnRzX3dyaXRlX2RldmljZShsdnRzX2RhdGEsIFRPR0dMRV9S R19UU1YyRl9WQ09fUlNUMV9WNCwgaSk7DQo+ICsJCWx2dHNfd3JpdGVfZGV2aWNlKGx2dHNfZGF0 YSwgVE9HR0xFX1JHX1RTVjJGX1ZDT19SU1QyX1Y0LCBpKTsNCj4gKwl9DQo+ICsNCj4gKwlsdnRz X2RhdGEtPmNvdW50aW5nX3dpbmRvd191cyA9IDIwOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9p ZCBkZXZpY2VfZW5hYmxlX2F1dG9fcmNrX3Y0KHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSkN Cj4gK3sNCj4gKwl1bnNpZ25lZCBpbnQgaTsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBsdnRz X2RhdGEtPm51bV90YzsgaSsrKQ0KPiArCQlsdnRzX3dyaXRlX2RldmljZShsdnRzX2RhdGEsIFNF VF9MVlRTX0FVVE9fUkNLX1Y0LCBpKTsNCj4gK30NCj4gKw0KPiArc3RhdGljIGludCBkZXZpY2Vf cmVhZF9jb3VudF9yY19uX3Y0KHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSkNCj4gK3sNCj4g KwkvKiBSZXNpc3Rvci1DYXBhY2l0b3IgQ2FsaWJyYXRpb24gKi8NCj4gKwkvKiBjb3VudF9SQ19O OiBjb3VudCBSQyBub3cgKi8NCj4gKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSBsdnRzX2RhdGEtPmRl djsNCj4gKwlzdHJ1Y3QgdGNfc2V0dGluZ3MgKnRjID0gbHZ0c19kYXRhLT50YzsNCj4gKwlzdHJ1 Y3Qgc2Vuc29yX2NhbF9kYXRhICpjYWxfZGF0YSA9ICZsdnRzX2RhdGEtPmNhbF9kYXRhOw0KPiAr CXVuc2lnbmVkIGludCBvZmZzZXQsIHNpemUsIHNfaW5kZXgsIGRhdGE7DQo+ICsJdm9pZCBfX2lv bWVtICpiYXNlOw0KPiArCWludCByZXQsIGksIGo7DQo+ICsJY2hhciBidWZmZXJbNTEyXTsNCj4g Kw0KPiArCWNhbF9kYXRhLT5jb3VudF9yY19ub3cgPSBkZXZtX2tjYWxsb2MoZGV2LCBsdnRzX2Rh dGEtPm51bV9zZW5zb3IsDQo+ICsJCQkJCSAgICAgIHNpemVvZigqY2FsX2RhdGEtPmNvdW50X3Jj X25vdyksIEdGUF9LRVJORUwpOw0KPiArCWlmICghY2FsX2RhdGEtPmNvdW50X3JjX25vdykNCj4g KwkJcmV0dXJuIC1FTk9NRU07DQo+ICsNCj4gKwlmb3IgKGkgPSAwOyBpIDwgbHZ0c19kYXRhLT5u dW1fdGM7IGkrKykgew0KPiArCQliYXNlID0gR0VUX0JBU0VfQUREUihpKTsNCj4gKwkJZm9yIChq ID0gMDsgaiA8IHRjW2ldLm51bV9zZW5zb3I7IGorKykgew0KPiArCQkJc19pbmRleCA9IHRjW2ld LnNlbnNvcl9tYXBbal07DQo+ICsNCj4gKwkJCWx2dHNfd3JpdGVfZGV2aWNlKGx2dHNfZGF0YSwg U0VMRUNUX1NFTlNPUl9SQ0tfVjQoaiksIGkpOw0KPiArCQkJbHZ0c193cml0ZV9kZXZpY2UobHZ0 c19kYXRhLCBTRVRfREVWSUNFX1NJTkdMRV9NT0RFX1Y0LCBpKTsNCj4gKwkJCXVzbGVlcF9yYW5n ZSgxMCwgMjApOw0KPiArDQo+ICsJCQlsdnRzX3dyaXRlX2RldmljZShsdnRzX2RhdGEsIEtJQ0tf T0ZGX1JDS19DT1VOVElOR19WNCwgaSk7DQo+ICsJCQl1c2xlZXBfcmFuZ2UoMzAsIDQwKTsNCj4g Kw0KPiArCQkJcmV0ID0gcmVhZGxfcG9sbF90aW1lb3V0KExWVFNfQ09ORklHXzAgKyBiYXNlLCBk YXRhLA0KPiArCQkJCQkJICEoZGF0YSAmIERFVklDRV9TRU5TSU5HX1NUQVRVUyksIDIsIDIwMCk7 DQo+ICsJCQlpZiAocmV0KQ0KPiArCQkJCWRldl9lcnIoZGV2LA0KPiArCQkJCQkiRXJyb3I6IExW VFMgJWQgREVWSUNFX1NFTlNJTkdfU1RBVFVTIGRpZG4ndCByZWFkeVxuIiwgaSk7DQo+ICsNCj4g KwkJCWRhdGEgPSBsdnRzX3JlYWRfZGV2aWNlKGx2dHNfZGF0YSwgMHgwMCwgaSk7DQo+ICsNCj4g KwkJCWNhbF9kYXRhLT5jb3VudF9yY19ub3dbc19pbmRleF0gPSAoZGF0YSAmIEdFTk1BU0soMjMs IDApKTsNCj4gKwkJfQ0KPiArDQo+ICsJCS8qIFJlY292ZXIgU2V0dGluZyBmb3IgTm9ybWFsIEFj Y2VzcyBvbg0KPiArCQkgKiB0ZW1wZXJhdHVyZSBmZXRjaA0KPiArCQkgKi8NCj4gKwkJbHZ0c193 cml0ZV9kZXZpY2UobHZ0c19kYXRhLCBTRVRfU0VOU09SX05PX1JDS19WNCwgaSk7DQo+ICsJCWx2 dHNfd3JpdGVfZGV2aWNlKGx2dHNfZGF0YSwgU0VUX0RFVklDRV9MT1dfUE9XRVJfU0lOR0xFX01P REVfVjQsIGkpOw0KPiArCX0NCj4gKw0KPiArCXNpemUgPSBzaXplb2YoYnVmZmVyKTsNCj4gKwlv ZmZzZXQgPSBzbnByaW50ZihidWZmZXIsIHNpemUsICJbQ09VTlRfUkNfTk9XXSAiKTsNCj4gKwlm b3IgKGkgPSAwOyBpIDwgbHZ0c19kYXRhLT5udW1fc2Vuc29yOyBpKyspDQo+ICsJCW9mZnNldCAr PSBzbnByaW50ZihidWZmZXIgKyBvZmZzZXQsIHNpemUgLSBvZmZzZXQsICIlZDolZCAiLA0KPiAr CQkJCSAgIGksIGNhbF9kYXRhLT5jb3VudF9yY19ub3dbaV0pOw0KPiArDQo+ICsJYnVmZmVyW29m ZnNldF0gPSAnXDAnOw0KPiArCWRldl9pbmZvKGRldiwgIiVzXG4iLCBidWZmZXIpOw0KPiArDQo+ ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyB2b2lkIHNldF9jYWxpYnJhdGlvbl9k YXRhX3Y0KHN0cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YSkNCj4gK3sNCj4gKwlzdHJ1Y3QgdGNf c2V0dGluZ3MgKnRjID0gbHZ0c19kYXRhLT50YzsNCj4gKwlzdHJ1Y3Qgc2Vuc29yX2NhbF9kYXRh ICpjYWxfZGF0YSA9ICZsdnRzX2RhdGEtPmNhbF9kYXRhOw0KPiArCXVuc2lnbmVkIGludCBpLCBq LCBzX2luZGV4LCBlX2RhdGE7DQo+ICsJdm9pZCBfX2lvbWVtICpiYXNlOw0KPiArDQo+ICsJZm9y IChpID0gMDsgaSA8IGx2dHNfZGF0YS0+bnVtX3RjOyBpKyspIHsNCj4gKwkJYmFzZSA9IEdFVF9C QVNFX0FERFIoaSk7DQo+ICsNCj4gKwkJZm9yIChqID0gMDsgaiA8IHRjW2ldLm51bV9zZW5zb3I7 IGorKykgew0KPiArCQkJc19pbmRleCA9IHRjW2ldLnNlbnNvcl9tYXBbal07DQo+ICsJCQlpZiAo SVNfRU5BQkxFKEZFQVRVUkVfREVWSUNFX0FVVE9fUkNLKSkNCj4gKwkJCQllX2RhdGEgPSBjYWxf ZGF0YS0+Y291bnRfcltzX2luZGV4XTsNCj4gKwkJCWVsc2UNCj4gKwkJCQllX2RhdGEgPSAoKCh1 bnNpZ25lZCBsb25nIGxvbmcpDQo+ICsJCQkJCWNhbF9kYXRhLT5jb3VudF9yY19ub3dbc19pbmRl eF0pICoNCj4gKwkJCQkJY2FsX2RhdGEtPmNvdW50X3Jbc19pbmRleF0pID4+IDE0Ow0KPiArDQo+ ICsJCQl3cml0ZWwoZV9kYXRhLCBMVlRTRURBVEEwMF8wICsgYmFzZSArIDB4NCAqIGopOw0KPiAr CQl9DQo+ICsJfQ0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBpbml0X2NvbnRyb2xsZXJfdjQo c3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRhKQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2UgKmRl diA9IGx2dHNfZGF0YS0+ZGV2Ow0KPiArCXVuc2lnbmVkIGludCBpOw0KPiArCXZvaWQgX19pb21l bSAqYmFzZTsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkgPCBsdnRzX2RhdGEtPm51bV90YzsgaSsr KSB7DQo+ICsJCWJhc2UgPSBHRVRfQkFTRV9BRERSKGkpOw0KPiArDQo+ICsJCWx2dHNfd3JpdGVf ZGV2aWNlKGx2dHNfZGF0YSwgU0VUX0RFVklDRV9MT1dfUE9XRVJfU0lOR0xFX01PREVfVjQsIGkp Ow0KPiArDQo+ICsJCXdyaXRlbChTRVRfU0VOU09SX0lOREVYLCBMVlRTVFNTRUxfMCArIGJhc2Up Ow0KPiArCQl3cml0ZWwoU0VUX0NBTENfU0NBTEVfUlVMRVMsIExWVFNDQUxTQ0FMRV8wICsgYmFz ZSk7DQo+ICsNCj4gKwkJc2V0X3BvbGxpbmdfc3BlZWQobHZ0c19kYXRhLCBpKTsNCj4gKwkJc2V0 X2h3X2ZpbHRlcihsdnRzX2RhdGEsIGkpOw0KPiArDQo+ICsJCWRldl9pbmZvKGRldiwgImx2dHMl ZDogcmVhZCBhbGwgJWQgc2Vuc29ycyBpbiAlZCB1cywgb25lIGluICVkIHVzXG4iLA0KPiArCQkJ IGksIEdFVF9UQ19TRU5TT1JfTlVNKGkpLCBHUk9VUF9MQVRFTkNZX1VTKGkpLCBTRU5TT1JfTEFU RU5DWV9VUyhpKSk7DQo+ICsJfQ0KPiArfQ0KPiArDQo+ICsvKj09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQo+ICsgKiBMVlRTIE1UNjg3Mw0KPiArICo9 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KPiArICov DQo+ICsNCj4gKyNkZWZpbmUgTVQ2ODczX05VTV9MVlRTIChBUlJBWV9TSVpFKG10Njg3M190Y19z ZXR0aW5ncykpDQo+ICsNCj4gK2VudW0gbXQ2ODczX2x2dHNfZG9tYWluIHsNCj4gKwlNVDY4NzNf QVBfRE9NQUlOLA0KPiArCU1UNjg3M19NQ1VfRE9NQUlOLA0KPiArCU1UNjg3M19OVU1fRE9NQUlO DQo+ICt9Ow0KPiArDQo+ICtlbnVtIG10Njg3M19sdnRzX3NlbnNvcl9lbnVtIHsNCj4gKwlNVDY4 NzNfVFMxXzAsDQo+ICsJTVQ2ODczX1RTMV8xLA0KPiArCU1UNjg3M19UUzJfMCwNCj4gKwlNVDY4 NzNfVFMyXzEsDQo+ICsJTVQ2ODczX1RTM18wLA0KPiArCU1UNjg3M19UUzNfMSwNCj4gKwlNVDY4 NzNfVFMzXzIsDQo+ICsJTVQ2ODczX1RTM18zLA0KPiArCU1UNjg3M19UUzRfMCwNCj4gKwlNVDY4 NzNfVFM0XzEsDQo+ICsJTVQ2ODczX1RTNV8wLA0KPiArCU1UNjg3M19UUzVfMSwNCj4gKwlNVDY4 NzNfVFM2XzAsDQo+ICsJTVQ2ODczX1RTNl8xLA0KPiArCU1UNjg3M19UUzdfMCwNCj4gKwlNVDY4 NzNfVFM3XzEsDQo+ICsJTVQ2ODczX1RTN18yLA0KPiArCU1UNjg3M19OVU1fVFMNCj4gK307DQo+ ICsNCj4gK3N0YXRpYyB2b2lkIG10Njg3M19lZnVzZV90b19jYWxfZGF0YShzdHJ1Y3QgbHZ0c19k YXRhICpsdnRzX2RhdGEpDQo+ICt7DQo+ICsJc3RydWN0IHNlbnNvcl9jYWxfZGF0YSAqY2FsX2Rh dGEgPSAmbHZ0c19kYXRhLT5jYWxfZGF0YTsNCj4gKw0KPiArCWNhbF9kYXRhLT5nb2xkZW5fdGVt cCA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDAsIDMxLCAyNCk7DQo+ICsJY2FsX2RhdGEtPmNvdW50 X3JbTVQ2ODczX1RTMV8wXSA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDEsIDIzLCAwKTsNCj4gKwlj YWxfZGF0YS0+Y291bnRfcltNVDY4NzNfVFMxXzFdID0gR0VUX0NBTF9EQVRBX0JJVE1BU0soMiwg MjMsIDApOw0KPiArCWNhbF9kYXRhLT5jb3VudF9yW01UNjg3M19UUzJfMF0gPSBHRVRfQ0FMX0RB VEFfQklUTUFTSygzLCAyMywgMCk7DQo+ICsJY2FsX2RhdGEtPmNvdW50X3JbTVQ2ODczX1RTMl8x XSA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDQsIDIzLCAwKTsNCj4gKwljYWxfZGF0YS0+Y291bnRf cltNVDY4NzNfVFMzXzBdID0gR0VUX0NBTF9EQVRBX0JJVE1BU0soNSwgMjMsIDApOw0KPiArCWNh bF9kYXRhLT5jb3VudF9yW01UNjg3M19UUzNfMV0gPSBHRVRfQ0FMX0RBVEFfQklUTUFTSyg2LCAy MywgMCk7DQo+ICsJY2FsX2RhdGEtPmNvdW50X3JbTVQ2ODczX1RTM18yXSA9IEdFVF9DQUxfREFU QV9CSVRNQVNLKDcsIDIzLCAwKTsNCj4gKwljYWxfZGF0YS0+Y291bnRfcltNVDY4NzNfVFMzXzNd ID0gR0VUX0NBTF9EQVRBX0JJVE1BU0soOCwgMjMsIDApOw0KPiArCWNhbF9kYXRhLT5jb3VudF9y W01UNjg3M19UUzRfMF0gPSBHRVRfQ0FMX0RBVEFfQklUTUFTSyg5LCAyMywgMCk7DQo+ICsJY2Fs X2RhdGEtPmNvdW50X3JbTVQ2ODczX1RTNF8xXSA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDEwLCAy MywgMCk7DQo+ICsJY2FsX2RhdGEtPmNvdW50X3JbTVQ2ODczX1RTNV8wXSA9IEdFVF9DQUxfREFU QV9CSVRNQVNLKDExLCAyMywgMCk7DQo+ICsJY2FsX2RhdGEtPmNvdW50X3JbTVQ2ODczX1RTNV8x XSA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDEyLCAyMywgMCk7DQo+ICsJY2FsX2RhdGEtPmNvdW50 X3JbTVQ2ODczX1RTNl8wXSA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDEzLCAyMywgMCk7DQo+ICsJ Y2FsX2RhdGEtPmNvdW50X3JbTVQ2ODczX1RTNl8xXSA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDE0 LCAyMywgMCk7DQo+ICsJY2FsX2RhdGEtPmNvdW50X3JbTVQ2ODczX1RTN18wXSA9IEdFVF9DQUxf REFUQV9CSVRNQVNLKDE1LCAyMywgMCk7DQo+ICsJY2FsX2RhdGEtPmNvdW50X3JbTVQ2ODczX1RT N18xXSA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDE2LCAyMywgMCk7DQo+ICsJY2FsX2RhdGEtPmNv dW50X3JbTVQ2ODczX1RTN18yXSA9IEdFVF9DQUxfREFUQV9CSVRNQVNLKDE3LCAyMywgMCk7DQo+ ICsNCj4gKwljYWxfZGF0YS0+Y291bnRfcmNbTVQ2ODczX1RTMV8wXSA9IEdFVF9DQUxfREFUQV9C SVRNQVNLKDIxLCAyMywgMCk7DQo+ICsNCj4gKwljYWxfZGF0YS0+Y291bnRfcmNbTVQ2ODczX1RT Ml8wXSA9IChHRVRfQ0FMX0RBVEFfQklUTUFTSygxLCAzMSwgMjQpIDw8IDE2KSArDQo+ICsJCQkJ CSAgIChHRVRfQ0FMX0RBVEFfQklUTUFTSygyLCAzMSwgMjQpIDw8IDgpICsNCj4gKwkJCQkJICAg IEdFVF9DQUxfREFUQV9CSVRNQVNLKDMsIDMxLCAyNCk7DQo+ICsNCj4gKwljYWxfZGF0YS0+Y291 bnRfcmNbTVQ2ODczX1RTM18wXSA9IChHRVRfQ0FMX0RBVEFfQklUTUFTSyg0LCAzMSwgMjQpIDw8 IDE2KSArDQo+ICsJCQkJCSAgIChHRVRfQ0FMX0RBVEFfQklUTUFTSyg1LCAzMSwgMjQpIDw8IDgp ICsNCj4gKwkJCQkJICAgIEdFVF9DQUxfREFUQV9CSVRNQVNLKDYsIDMxLCAyNCk7DQo+ICsNCj4g KwljYWxfZGF0YS0+Y291bnRfcmNbTVQ2ODczX1RTNF8wXSA9IChHRVRfQ0FMX0RBVEFfQklUTUFT Syg3LCAzMSwgMjQpIDw8IDE2KSArDQo+ICsJCQkJCSAgIChHRVRfQ0FMX0RBVEFfQklUTUFTSyg4 LCAzMSwgMjQpIDw8IDgpICsNCj4gKwkJCQkJICAgIEdFVF9DQUxfREFUQV9CSVRNQVNLKDksIDMx LCAyNCk7DQo+ICsNCj4gKwljYWxfZGF0YS0+Y291bnRfcmNbTVQ2ODczX1RTNV8wXSA9IChHRVRf Q0FMX0RBVEFfQklUTUFTSygxMCwgMzEsIDI0KSA8PCAxNikgKw0KPiArCQkJCQkgICAoR0VUX0NB TF9EQVRBX0JJVE1BU0soMTEsIDMxLCAyNCkgPDwgOCkgKw0KPiArCQkJCQkgICAgR0VUX0NBTF9E QVRBX0JJVE1BU0soMTIsIDMxLCAyNCk7DQo+ICsNCj4gKwljYWxfZGF0YS0+Y291bnRfcmNbTVQ2 ODczX1RTNl8wXSA9IChHRVRfQ0FMX0RBVEFfQklUTUFTSygxMywgMzEsIDI0KSA8PCAxNikgKw0K PiArCQkJCQkgICAoR0VUX0NBTF9EQVRBX0JJVE1BU0soMTQsIDMxLCAyNCkgPDwgOCkgKw0KPiAr CQkJCQkgICAgR0VUX0NBTF9EQVRBX0JJVE1BU0soMTUsIDMxLCAyNCk7DQo+ICsNCj4gKwljYWxf ZGF0YS0+Y291bnRfcmNbTVQ2ODczX1RTN18wXSA9IChHRVRfQ0FMX0RBVEFfQklUTUFTSygxNiwg MzEsIDI0KSA8PCAxNikgKw0KPiArCQkJCQkgICAoR0VUX0NBTF9EQVRBX0JJVE1BU0soMTcsIDMx LCAyNCkgPDwgOCkgKw0KPiArCQkJCQkgICAgR0VUX0NBTF9EQVRBX0JJVE1BU0soMTgsIDMxLCAy NCk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBzdHJ1Y3QgdGNfc2V0dGluZ3MgbXQ2ODczX3RjX3Nl dHRpbmdzW10gPSB7DQo+ICsJWzBdID0gew0KPiArCQkuZG9tYWluX2luZGV4ID0gTVQ2ODczX01D VV9ET01BSU4sDQo+ICsJCS5hZGRyX29mZnNldCA9IDB4MCwNCj4gKwkJLm51bV9zZW5zb3IgPSAy LA0KPiArCQkuc2Vuc29yX21hcCA9IHtNVDY4NzNfVFMxXzAsIE1UNjg3M19UUzFfMX0sDQo+ICsJ CS50Y19zcGVlZCA9IFNFVF9UQ19TUEVFRF9JTl9VUygxMTgsIDExOCwgMTE4LCAxMTgpLA0KPiAr CQkuaHdfZmlsdGVyID0gTFZUU19GSUxURVJfMl9PRl80LA0KPiArCQkuZG9taW5hdG9yX3NlbnNp bmdfcG9pbnQgPSBTRU5TSU5HX1BPSU5UMSwNCj4gKwkJLmh3X3JlYm9vdF90cmlwX3BvaW50ID0g MTE3MDAwLA0KPiArCQkuaXJxX2JpdCA9IEJJVCgzKSwNCj4gKwl9LA0KPiArCVsxXSA9IHsNCj4g KwkJLmRvbWFpbl9pbmRleCA9IE1UNjg3M19NQ1VfRE9NQUlOLA0KPiArCQkuYWRkcl9vZmZzZXQg PSAweDEwMCwNCj4gKwkJLm51bV9zZW5zb3IgPSAyLA0KPiArCQkuc2Vuc29yX21hcCA9IHtNVDY4 NzNfVFMyXzAsIE1UNjg3M19UUzJfMX0sDQo+ICsJCS50Y19zcGVlZCA9IFNFVF9UQ19TUEVFRF9J Tl9VUygxMTgsIDExOCwgMTE4LCAxMTgpLA0KPiArCQkuaHdfZmlsdGVyID0gTFZUU19GSUxURVJf Ml9PRl80LA0KPiArCQkuZG9taW5hdG9yX3NlbnNpbmdfcG9pbnQgPSBTRU5TSU5HX1BPSU5UMCwN Cj4gKwkJLmh3X3JlYm9vdF90cmlwX3BvaW50ID0gMTE3MDAwLA0KPiArCQkuaXJxX2JpdCA9IEJJ VCg0KSwNCj4gKwl9LA0KPiArCVsyXSA9IHsNCj4gKwkJLmRvbWFpbl9pbmRleCA9IE1UNjg3M19N Q1VfRE9NQUlOLA0KPiArCQkuYWRkcl9vZmZzZXQgPSAweDIwMCwNCj4gKwkJLm51bV9zZW5zb3Ig PSA0LA0KPiArCQkuc2Vuc29yX21hcCA9IHtNVDY4NzNfVFMzXzAsIE1UNjg3M19UUzNfMSwgTVQ2 ODczX1RTM18yLCBNVDY4NzNfVFMzXzN9LA0KPiArCQkudGNfc3BlZWQgPSBTRVRfVENfU1BFRURf SU5fVVMoMTE4LCAxMTgsIDExOCwgMTE4KSwNCj4gKwkJLmh3X2ZpbHRlciA9IExWVFNfRklMVEVS XzJfT0ZfNCwNCj4gKwkJLmRvbWluYXRvcl9zZW5zaW5nX3BvaW50ID0gU0VOU0lOR19QT0lOVDAs DQo+ICsJCS5od19yZWJvb3RfdHJpcF9wb2ludCA9IDExNzAwMCwNCj4gKwkJLmlycV9iaXQgPSBC SVQoNSksDQo+ICsJfSwNCj4gKwlbM10gPSB7DQo+ICsJCS5kb21haW5faW5kZXggPSBNVDY4NzNf QVBfRE9NQUlOLA0KPiArCQkuYWRkcl9vZmZzZXQgPSAweDAsDQo+ICsJCS5udW1fc2Vuc29yID0g MiwNCj4gKwkJLnNlbnNvcl9tYXAgPSB7TVQ2ODczX1RTNF8wLCBNVDY4NzNfVFM0XzF9LA0KPiAr CQkudGNfc3BlZWQgPSBTRVRfVENfU1BFRURfSU5fVVMoMTE4LCAxMTgsIDExOCwgMTE4KSwNCj4g KwkJLmh3X2ZpbHRlciA9IExWVFNfRklMVEVSXzJfT0ZfNCwNCj4gKwkJLmRvbWluYXRvcl9zZW5z aW5nX3BvaW50ID0gU0VOU0lOR19QT0lOVDAsDQo+ICsJCS5od19yZWJvb3RfdHJpcF9wb2ludCA9 IDExNzAwMCwNCj4gKwkJLmlycV9iaXQgPSBCSVQoMyksDQo+ICsJfSwNCj4gKwlbNF0gPSB7DQo+ ICsJCS5kb21haW5faW5kZXggPSBNVDY4NzNfQVBfRE9NQUlOLA0KPiArCQkuYWRkcl9vZmZzZXQg PSAweDEwMCwNCj4gKwkJLm51bV9zZW5zb3IgPSAyLA0KPiArCQkuc2Vuc29yX21hcCA9IHtNVDY4 NzNfVFM1XzAsIE1UNjg3M19UUzVfMX0sDQo+ICsJCS50Y19zcGVlZCA9IFNFVF9UQ19TUEVFRF9J Tl9VUygxMTgsIDExOCwgMTE4LCAxMTgpLA0KPiArCQkuaHdfZmlsdGVyID0gTFZUU19GSUxURVJf Ml9PRl80LA0KPiArCQkuZG9taW5hdG9yX3NlbnNpbmdfcG9pbnQgPSBTRU5TSU5HX1BPSU5UMSwN Cj4gKwkJLmh3X3JlYm9vdF90cmlwX3BvaW50ID0gMTE3MDAwLA0KPiArCQkuaXJxX2JpdCA9IEJJ VCg0KSwNCj4gKwl9LA0KPiArCVs1XSA9IHsNCj4gKwkJLmRvbWFpbl9pbmRleCA9IE1UNjg3M19B UF9ET01BSU4sDQo+ICsJCS5hZGRyX29mZnNldCA9IDB4MjAwLA0KPiArCQkubnVtX3NlbnNvciA9 IDIsDQo+ICsJCS5zZW5zb3JfbWFwID0ge01UNjg3M19UUzZfMCwgTVQ2ODczX1RTNl8xfSwNCj4g KwkJLnRjX3NwZWVkID0gU0VUX1RDX1NQRUVEX0lOX1VTKDExOCwgMTE4LCAxMTgsIDExOCksDQo+ ICsJCS5od19maWx0ZXIgPSBMVlRTX0ZJTFRFUl8yX09GXzQsDQo+ICsJCS5kb21pbmF0b3Jfc2Vu c2luZ19wb2ludCA9IFNFTlNJTkdfUE9JTlQxLA0KPiArCQkuaHdfcmVib290X3RyaXBfcG9pbnQg PSAxMTcwMDAsDQo+ICsJCS5pcnFfYml0ID0gQklUKDUpLA0KPiArCX0sDQo+ICsJWzZdID0gew0K PiArCQkuZG9tYWluX2luZGV4ID0gTVQ2ODczX0FQX0RPTUFJTiwNCj4gKwkJLmFkZHJfb2Zmc2V0 ID0gMHgzMDAsDQo+ICsJCS5udW1fc2Vuc29yID0gMywNCj4gKwkJLnNlbnNvcl9tYXAgPSB7TVQ2 ODczX1RTN18wLCBNVDY4NzNfVFM3XzEsIE1UNjg3M19UUzdfMn0sDQo+ICsJCS50Y19zcGVlZCA9 IFNFVF9UQ19TUEVFRF9JTl9VUygxMTgsIDExOCwgMTE4LCAxMTgpLA0KPiArCQkuaHdfZmlsdGVy ID0gTFZUU19GSUxURVJfMl9PRl80LA0KPiArCQkuZG9taW5hdG9yX3NlbnNpbmdfcG9pbnQgPSBT RU5TSU5HX1BPSU5UMiwNCj4gKwkJLmh3X3JlYm9vdF90cmlwX3BvaW50ID0gMTE3MDAwLA0KPiAr CQkuaXJxX2JpdCA9IEJJVCg2KSwNCj4gKwl9DQo+ICt9Ow0KPiArDQo+ICtzdGF0aWMgc3RydWN0 IGx2dHNfZGF0YSBtdDY4NzNfbHZ0c19kYXRhID0gew0KPiArCS5udW1fZG9tYWluID0gTVQ2ODcz X05VTV9ET01BSU4sDQo+ICsJLm51bV90YyA9IE1UNjg3M19OVU1fTFZUUywNCj4gKwkudGMgPSBt dDY4NzNfdGNfc2V0dGluZ3MsDQo+ICsJLm51bV9zZW5zb3IgPSBNVDY4NzNfTlVNX1RTLA0KPiAr CS5vcHMgPSB7DQo+ICsJCS5lZnVzZV90b19jYWxfZGF0YSA9IG10Njg3M19lZnVzZV90b19jYWxf ZGF0YSwNCj4gKwkJLmRldmljZV9lbmFibGVfYW5kX2luaXQgPSBkZXZpY2VfZW5hYmxlX2FuZF9p bml0X3Y0LA0KPiArCQkuZGV2aWNlX2VuYWJsZV9hdXRvX3JjayA9IGRldmljZV9lbmFibGVfYXV0 b19yY2tfdjQsDQo+ICsJCS5kZXZpY2VfcmVhZF9jb3VudF9yY19uID0gZGV2aWNlX3JlYWRfY291 bnRfcmNfbl92NCwNCj4gKwkJLnNldF9jYWxfZGF0YSA9IHNldF9jYWxpYnJhdGlvbl9kYXRhX3Y0 LA0KPiArCQkuaW5pdF9jb250cm9sbGVyID0gaW5pdF9jb250cm9sbGVyX3Y0LA0KPiArCX0sDQo+ ICsJLmZlYXR1cmVfYml0bWFwID0gRkVBVFVSRV9ERVZJQ0VfQVVUT19SQ0ssDQo+ICsJLm51bV9l ZnVzZV9hZGRyID0gMjIsDQo+ICsJLm51bV9lZnVzZV9ibG9jayA9IDEsDQo+ICsJLmNhbF9kYXRh ID0gew0KPiArCQkuZGVmYXVsdF9nb2xkZW5fdGVtcCA9IDUwLA0KPiArCQkuZGVmYXVsdF9jb3Vu dF9yID0gMzUwMDAsDQo+ICsJCS5kZWZhdWx0X2NvdW50X3JjID0gMjc1MCwNCj4gKwl9LA0KPiAr CS5jb2VmZiA9IHsNCj4gKwkJLmEgPSAtMjUwNDYwLA0KPiArCQkuYiA9IDI1MDQ2MCwNCj4gKwl9 LA0KPiArfTsNCj4gKw0KPiArLyo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PQ0KPiArICo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PQ0KPiArICogU3VwcG9ydCBjaGlwcw0KPiArICo9PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KPiArICovDQo+ICtzdGF0aWMgY29u c3Qgc3RydWN0IG9mX2RldmljZV9pZCBsdnRzX29mX21hdGNoW10gPSB7DQo+ICsJew0KPiArCQku Y29tcGF0aWJsZSA9ICJtZWRpYXRlayxtdDY4NzMtbHZ0cyIsDQo+ICsJCS5kYXRhID0gKHZvaWQg KikmbXQ2ODczX2x2dHNfZGF0YSwNCj4gKwl9LA0KPiArCXsNCj4gKwl9LA0KPiArfTsNCj4gK01P RFVMRV9ERVZJQ0VfVEFCTEUob2YsIGx2dHNfb2ZfbWF0Y2gpOw0KPiArLyo9PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovDQo+ICtzdGF0aWMgc3RydWN0 IHBsYXRmb3JtX2RyaXZlciBzb2NfdGVtcF9sdnRzID0gew0KPiArCS5wcm9iZSA9IGx2dHNfcHJv YmUsDQo+ICsJLnJlbW92ZSA9IGx2dHNfcmVtb3ZlLA0KPiArCS5zdXNwZW5kID0gbHZ0c19zdXNw ZW5kLA0KPiArCS5yZXN1bWUgPSBsdnRzX3Jlc3VtZSwNCj4gKwkuZHJpdmVyID0gew0KPiArCQku bmFtZSA9ICJtdGstc29jLXRlbXAtbHZ0cyIsDQo+ICsJCS5vZl9tYXRjaF90YWJsZSA9IGx2dHNf b2ZfbWF0Y2gsDQo+ICsJfSwNCj4gK307DQo+ICsNCj4gK21vZHVsZV9wbGF0Zm9ybV9kcml2ZXIo c29jX3RlbXBfbHZ0cyk7DQo+ICtNT0RVTEVfQVVUSE9SKCJZdS1DaGlhIENoYW5nIDxldGhhbi5j aGFuZ0BtZWRpYXRlay5jb20+Iik7DQo+ICtNT0RVTEVfQVVUSE9SKCJNaWNoYWVsIEthbyA8bWlj aGFlbC5rYW9AbWVkaWF0ZWsuY29tPiIpOw0KPiArTU9EVUxFX0RFU0NSSVBUSU9OKCJNZWRpYXRl ayBzb2MgdGVtcGVyYXR1cmUgZHJpdmVyIik7DQo+ICtNT0RVTEVfTElDRU5TRSgiR1BMIHYyIik7 DQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3RoZXJtYWwvbWVkaWF0ZWsvc29jX3RlbXBfbHZ0cy5o IGIvZHJpdmVycy90aGVybWFsL21lZGlhdGVrL3NvY190ZW1wX2x2dHMuaA0KPiBuZXcgZmlsZSBt b2RlIDEwMDY0NA0KPiBpbmRleCAwMDAwMDAwMDAwMDAuLjFkOTBiZGVjNTNjNg0KPiAtLS0gL2Rl di9udWxsDQo+ICsrKyBiL2RyaXZlcnMvdGhlcm1hbC9tZWRpYXRlay9zb2NfdGVtcF9sdnRzLmgN Cj4gQEAgLTAsMCArMSwzMTIgQEANCj4gKy8qIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwt Mi4wICovDQo+ICsvKg0KPiArICogQ29weXJpZ2h0IChjKSAyMDIwIE1lZGlhVGVrIEluYy4NCj4g KyAqLw0KPiArDQo+ICsjaWZuZGVmIF9fTVRLX1NPQ19URU1QX0xWVFNfSF9fDQo+ICsjZGVmaW5l IF9fTVRLX1NPQ19URU1QX0xWVFNfSF9fDQo+ICsNCj4gKy8qIExWVFMgSFcgZmlsdGVyIHNldHRp bmdzDQo+ICsgKiAwMDA6IEdldCBvbmUgc2FtcGxlDQo+ICsgKiAwMDE6IEdldCAyIHNhbXBsZXMg YW5kIGF2ZXJhZ2UgdGhlbQ0KPiArICogMDEwOiBHZXQgNCBzYW1wbGVzLCBkcm9wIG1heCBhbmQg bWluLCB0aGVuIGF2ZXJhZ2UgdGhlIHJlc3Qgb2YgMiBzYW1wbGVzDQo+ICsgKiAwMTE6IEdldCA2 IHNhbXBsZXMsIGRyb3AgbWF4IGFuZCBtaW4sIHRoZW4gYXZlcmFnZSB0aGUgcmVzdCBvZiA0IHNh bXBsZXMNCj4gKyAqIDEwMDogR2V0IDEwIHNhbXBsZXMsIGRyb3AgbWF4IGFuZCBtaW4sIHRoZW4g YXZlcmFnZSB0aGUgcmVzdCBvZiA4IHNhbXBsZXMNCj4gKyAqIDEwMTogR2V0IDE4IHNhbXBsZXMs IGRyb3AgbWF4IGFuZCBtaW4sIHRoZW4gYXZlcmFnZSB0aGUgcmVzdCBvZiAxNiBzYW1wbGVzDQo+ ICsgKi8NCj4gK2VudW0gbHZ0c19od19maWx0ZXIgew0KPiArCUxWVFNfRklMVEVSXzEsDQo+ICsJ TFZUU19GSUxURVJfMiwNCj4gKwlMVlRTX0ZJTFRFUl8yX09GXzQsDQo+ICsJTFZUU19GSUxURVJf NF9PRl82LA0KPiArCUxWVFNfRklMVEVSXzhfT0ZfMTAsDQo+ICsJTFZUU19GSUxURVJfMTZfT0Zf MTgNCj4gK307DQo+ICsNCj4gK2VudW0gbHZ0c19zZW5zaW5nX3BvaW50IHsNCj4gKwlTRU5TSU5H X1BPSU5UMCwNCj4gKwlTRU5TSU5HX1BPSU5UMSwNCj4gKwlTRU5TSU5HX1BPSU5UMiwNCj4gKwlT RU5TSU5HX1BPSU5UMywNCj4gKwlBTExfU0VOU0lOR19QT0lOVFMNCj4gK307DQo+ICsNCj4gKy8q PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCj4gKyAq IERhdGEgc3RydWN0dXJlDQo+ICsgKj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09DQo+ICsgKi8NCj4gK3N0cnVjdCBsdnRzX2RhdGE7DQo+ICsNCj4gK3N0 cnVjdCBzcGVlZF9zZXR0aW5ncyB7DQo+ICsJdW5zaWduZWQgaW50IHBlcmlvZF91bml0Ow0KPiAr CXVuc2lnbmVkIGludCBncm91cF9pbnRlcnZhbF9kZWxheTsNCj4gKwl1bnNpZ25lZCBpbnQgZmls dGVyX2ludGVydmFsX2RlbGF5Ow0KPiArCXVuc2lnbmVkIGludCBzZW5zb3JfaW50ZXJ2YWxfZGVs YXk7DQo+ICt9Ow0KPiArDQo+ICtzdHJ1Y3QgdGNfc2V0dGluZ3Mgew0KPiArCXVuc2lnbmVkIGlu dCBkb21haW5faW5kZXg7DQo+ICsJdW5zaWduZWQgaW50IGFkZHJfb2Zmc2V0Ow0KPiArCXVuc2ln bmVkIGludCBudW1fc2Vuc29yOw0KPiArCXVuc2lnbmVkIGludCBzZW5zb3JfbWFwW0FMTF9TRU5T SU5HX1BPSU5UU107IC8qIEluIHNlbnNvciBJRCAqLw0KPiArCXN0cnVjdCBzcGVlZF9zZXR0aW5n cyB0Y19zcGVlZDsNCj4gKwkvKiBIVyBmaWx0ZXIgc2V0dGluZw0KPiArCSAqIDAwMDogR2V0IG9u ZSBzYW1wbGUNCj4gKwkgKiAwMDE6IEdldCAyIHNhbXBsZXMgYW5kIGF2ZXJhZ2UgdGhlbQ0KPiAr CSAqIDAxMDogR2V0IDQgc2FtcGxlcywgZHJvcCBtYXggYW5kIG1pbiwgdGhlbiBhdmVyYWdlIHRo ZSByZXN0IG9mIDIgc2FtcGxlcw0KPiArCSAqIDAxMTogR2V0IDYgc2FtcGxlcywgZHJvcCBtYXgg YW5kIG1pbiwgdGhlbiBhdmVyYWdlIHRoZSByZXN0IG9mIDQgc2FtcGxlcw0KPiArCSAqIDEwMDog R2V0IDEwIHNhbXBsZXMsIGRyb3AgbWF4IGFuZCBtaW4sIHRoZW4gYXZlcmFnZSB0aGUgcmVzdCBv ZiA4IHNhbXBsZXMNCj4gKwkgKiAxMDE6IEdldCAxOCBzYW1wbGVzLCBkcm9wIG1heCBhbmQgbWlu LCB0aGVuIGF2ZXJhZ2UgdGhlIHJlc3Qgb2YgMTYgc2FtcGxlcw0KPiArCSAqLw0KPiArCXVuc2ln bmVkIGludCBod19maWx0ZXI7DQo+ICsJLyogRG9taW5hdG9yX3NlbnNpbmcgcG9pbnQgaXMgdXNl ZCB0byBzZWxlY3QgYSBzZW5zaW5nIHBvaW50DQo+ICsJICogYW5kIHJlZmVyZW5jZSBpdHMgdGVt cGVyYXR1cmUgdG8gdHJpZ2dlciBUaGVybWFsIEhXIFJlYm9vdA0KPiArCSAqIFdoZW4gaXQgaXMg QUxMX1NFTlNJTkdfUE9JTlRTLCBpdCB3aWxsIHNlbGVjdCBhbGwgc2Vuc2luZyBwb2ludHMNCj4g KwkgKi8NCj4gKwlpbnQgZG9taW5hdG9yX3NlbnNpbmdfcG9pbnQ7DQo+ICsJaW50IGh3X3JlYm9v dF90cmlwX3BvaW50OyAvKiAtMjc0MDAwOiBEaXNhYmxlIEhXIHJlYm9vdCAqLw0KPiArCXVuc2ln bmVkIGludCBpcnFfYml0Ow0KPiArfTsNCj4gKw0KPiArc3RydWN0IGZvcm11bGFfY29lZmYgew0K PiArCWludCBhOw0KPiArCWludCBiOw0KPiArCXVuc2lnbmVkIGludCBnb2xkZW5fdGVtcDsNCj4g K307DQo+ICsNCj4gK3N0cnVjdCBzZW5zb3JfY2FsX2RhdGEgew0KPiArCWludCB1c2VfZmFrZV9l ZnVzZTsJLyogMTogVXNlIGZha2UgZWZ1c2UsIDA6IFVzZSByZWFsIGVmdXNlICovDQo+ICsJdW5z aWduZWQgaW50IGdvbGRlbl90ZW1wOw0KPiArCXVuc2lnbmVkIGludCAqY291bnRfcjsNCj4gKwl1 bnNpZ25lZCBpbnQgKmNvdW50X3JjOw0KPiArCXVuc2lnbmVkIGludCAqY291bnRfcmNfbm93Ow0K PiArDQo+ICsJdW5zaWduZWQgaW50IGRlZmF1bHRfZ29sZGVuX3RlbXA7DQo+ICsJdW5zaWduZWQg aW50IGRlZmF1bHRfY291bnRfcjsNCj4gKwl1bnNpZ25lZCBpbnQgZGVmYXVsdF9jb3VudF9yYzsN Cj4gK307DQo+ICsNCj4gK3N0cnVjdCBwbGF0Zm9ybV9vcHMgew0KPiArCXZvaWQgKCplZnVzZV90 b19jYWxfZGF0YSkoc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRhKTsNCj4gKwl2b2lkICgqZGV2 aWNlX2VuYWJsZV9hbmRfaW5pdCkoc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRhKTsNCj4gKwl2 b2lkICgqZGV2aWNlX2VuYWJsZV9hdXRvX3Jjaykoc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRh KTsNCj4gKwlpbnQgKCpkZXZpY2VfcmVhZF9jb3VudF9yY19uKShzdHJ1Y3QgbHZ0c19kYXRhICps dnRzX2RhdGEpOw0KPiArCXZvaWQgKCpzZXRfY2FsX2RhdGEpKHN0cnVjdCBsdnRzX2RhdGEgKmx2 dHNfZGF0YSk7DQo+ICsJdm9pZCAoKmluaXRfY29udHJvbGxlcikoc3RydWN0IGx2dHNfZGF0YSAq bHZ0c19kYXRhKTsNCj4gK307DQo+ICsNCj4gK3N0cnVjdCBwb3dlcl9kb21haW4gew0KPiArCXZv aWQgX19pb21lbSAqYmFzZTsJLyogTFZUUyBiYXNlIGFkZHJlc3NlcyAqLw0KPiArCXVuc2lnbmVk IGludCBpcnFfbnVtOwkvKiBMVlRTIGludGVycnVwdCBudW1iZXJzICovDQo+ICsJc3RydWN0IHJl c2V0X2NvbnRyb2wgKnJlc2V0Ow0KPiArfTsNCj4gKw0KPiArc3RydWN0IHNlbnNvcl9kYXRhIHsN Cj4gKwlpbnQgdGVtcDsJCS8qIEN1cnJlbnQgdGVtcGVyYXR1cmUgKi8NCj4gKwl1bnNpZ25lZCBp bnQgbXNyX3JhdzsJLyogTVNSIHJhdyBkYXRhIGZyb20gTFZUUyAqLw0KPiArfTsNCj4gKw0KPiAr c3RydWN0IGx2dHNfZGF0YSB7DQo+ICsJc3RydWN0IGRldmljZSAqZGV2Ow0KPiArCXN0cnVjdCBj bGsgKmNsazsNCj4gKwl1bnNpZ25lZCBpbnQgbnVtX2RvbWFpbjsNCj4gKwlzdHJ1Y3QgcG93ZXJf ZG9tYWluICpkb21haW47DQo+ICsNCj4gKwlpbnQgbnVtX3RjOwkJCS8qIE51bWJlciBvZiBMVlRT IHRoZXJtYWwgY29udHJvbGxlcnMgKi8NCj4gKwlzdHJ1Y3QgdGNfc2V0dGluZ3MgKnRjOw0KPiAr CWludCBjb3VudGluZ193aW5kb3dfdXM7CQkvKiBMVlRTIGRldmljZSBjb3VudGluZyB3aW5kb3cg Ki8NCj4gKw0KPiArCWludCBudW1fc2Vuc29yOwkJCS8qIE51bWJlciBvZiBzZW5zb3JzIGluIHRo aXMgcGxhdGZvcm0gKi8NCj4gKwlzdHJ1Y3Qgc2Vuc29yX2RhdGEgKnNlbl9kYXRhOw0KPiArDQo+ ICsJc3RydWN0IHBsYXRmb3JtX29wcyBvcHM7DQo+ICsJaW50IGZlYXR1cmVfYml0bWFwOwkJLyog U2hvdyB3aGF0IGZlYXR1cmVzIGFyZSBlbmFibGVkICovDQo+ICsNCj4gKwl1bnNpZ25lZCBpbnQg bnVtX2VmdXNlX2FkZHI7DQo+ICsJdW5zaWduZWQgaW50ICplZnVzZTsNCj4gKwl1bnNpZ25lZCBp bnQgbnVtX2VmdXNlX2Jsb2NrOwkvKiBOdW1iZXIgb2YgY29udGlndW91cyBlZnVzZSBpbmRleGVz ICovDQo+ICsJc3RydWN0IHNlbnNvcl9jYWxfZGF0YSBjYWxfZGF0YTsNCj4gKwlzdHJ1Y3QgZm9y bXVsYV9jb2VmZiBjb2VmZjsNCj4gK307DQo+ICsNCj4gK3N0cnVjdCBzb2NfdGVtcF90eiB7DQo+ ICsJdW5zaWduZWQgaW50IGlkOyAvKiBpZiBpZCBpcyAwLCBnZXQgbWF4IHRlbXBlcmF0dXJlIG9m IGFsbCBzZW5zb3JzICovDQo+ICsJc3RydWN0IGx2dHNfZGF0YSAqbHZ0c19kYXRhOw0KPiArfTsN Cj4gKw0KPiArc3RydWN0IG1hdGNoX2VudHJ5IHsNCj4gKwljaGFyCWNoaXBbMzJdOw0KPiArCXN0 cnVjdCBsdnRzX2RhdGEgKmx2dHNfZGF0YTsNCj4gK307DQo+ICsNCj4gK3N0cnVjdCBsdnRzX21h dGNoX2RhdGEgew0KPiArCXVuc2lnbmVkIGludCBod192ZXJzaW9uOw0KPiArCXN0cnVjdCBtYXRj aF9lbnRyeSAqdGFibGU7DQo+ICsJdm9pZCAoKnNldF91cF9jb21tb25fY2FsbGJhY2tzKShzdHJ1 Y3QgbHZ0c19kYXRhICpsdnRzX2RhdGEpOw0KPiArCXN0cnVjdCBsaXN0X2hlYWQgbm9kZTsNCj4g K307DQo+ICsNCj4gK3N0cnVjdCBsdnRzX2lkIHsNCj4gKwl1bnNpZ25lZCBpbnQgaHdfdmVyc2lv bjsNCj4gKwljaGFyCWNoaXBbMzJdOw0KPiArfTsNCj4gKw0KPiArLyo9PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KPiArICogTFZUUyBkZXZpY2UgcmVn aXN0ZXINCj4gKyAqPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT0NCj4gKyAqLw0KPiArI2RlZmluZSBSR19UU0ZNX0RBVEFfMAkweDAwDQo+ICsjZGVmaW5l IFJHX1RTRk1fREFUQV8xCTB4MDENCj4gKyNkZWZpbmUgUkdfVFNGTV9EQVRBXzIJMHgwMg0KPiAr I2RlZmluZSBSR19UU0ZNX0NUUkxfMAkweDAzDQo+ICsjZGVmaW5lIFJHX1RTRk1fQ1RSTF8xCTB4 MDQNCj4gKyNkZWZpbmUgUkdfVFNGTV9DVFJMXzIJMHgwNQ0KPiArI2RlZmluZSBSR19UU0ZNX0NU UkxfMwkweDA2DQo+ICsjZGVmaW5lIFJHX1RTRk1fQ1RSTF80CTB4MDcNCj4gKyNkZWZpbmUgUkdf VFNWMkZfQ1RSTF8wCTB4MDgNCj4gKyNkZWZpbmUgUkdfVFNWMkZfQ1RSTF8xCTB4MDkNCj4gKyNk ZWZpbmUgUkdfVFNWMkZfQ1RSTF8yCTB4MEENCj4gKyNkZWZpbmUgUkdfVFNWMkZfQ1RSTF8zCTB4 MEINCj4gKyNkZWZpbmUgUkdfVFNWMkZfQ1RSTF80CTB4MEMNCj4gKyNkZWZpbmUgUkdfVFNWMkZf Q1RSTF81CTB4MEQNCj4gKyNkZWZpbmUgUkdfVFNWMkZfQ1RSTF82CTB4MEUNCj4gKyNkZWZpbmUg UkdfVEVNUF9EQVRBXzAJMHgxMA0KPiArI2RlZmluZSBSR19URU1QX0RBVEFfMQkweDExDQo+ICsj ZGVmaW5lIFJHX1RFTVBfREFUQV8yCTB4MTINCj4gKyNkZWZpbmUgUkdfVEVNUF9EQVRBXzMJMHgx Mw0KPiArI2RlZmluZSBSR19SQ19EQVRBXzAJMHgxNA0KPiArI2RlZmluZSBSR19SQ19EQVRBXzEJ MHgxNQ0KPiArI2RlZmluZSBSR19SQ19EQVRBXzIJMHgxNg0KPiArI2RlZmluZSBSR19SQ19EQVRB XzMJMHgxNw0KPiArI2RlZmluZSBSR19ESVZfREFUQV8wCTB4MTgNCj4gKyNkZWZpbmUgUkdfRElW X0RBVEFfMQkweDE5DQo+ICsjZGVmaW5lIFJHX0RJVl9EQVRBXzIJMHgxQQ0KPiArI2RlZmluZSBS R19ESVZfREFUQV8zCTB4MUINCj4gKyNkZWZpbmUgUkdfVFNUX0RBVEFfMAkweDcwDQo+ICsjZGVm aW5lIFJHX1RTVF9EQVRBXzEJMHg3MQ0KPiArI2RlZmluZSBSR19UU1RfREFUQV8yCTB4NzINCj4g KyNkZWZpbmUgUkdfVFNUX0NUUkwJMHg3Mw0KPiArI2RlZmluZSBSR19EQkdfRlFNVFIJMHhGMA0K PiArI2RlZmluZSBSR19EQkdfTFBTRVEJMHhGMQ0KPiArI2RlZmluZSBSR19EQkdfU1RBVEUJMHhG Mg0KPiArI2RlZmluZSBSR19EQkdfQ0hLU1VNCTB4RjMNCj4gKyNkZWZpbmUgUkdfRElEX0xWVFMJ MHhGQw0KPiArI2RlZmluZSBSR19ESURfUkVWCTB4RkQNCj4gKyNkZWZpbmUgUkdfVFNGTV9SU1QJ MHhGRg0KPiArLyo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PQ0KPiArICogTFZUUyBjb250cm9sbGVyIHJlZ2lzdGVyDQo+ICsgKj09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQo+ICsgKi8NCj4gKyNkZWZpbmUg TFZUU01PTkNUTDBfMAkweDAwMA0KPiArI2RlZmluZSBMVlRTX1NJTkdMRV9TRU5TRQlCSVQoOSkN Cj4gKyNkZWZpbmUgRU5BQkxFX1NFTlNJTkdfUE9JTlQobnVtKQkoTFZUU19TSU5HTEVfU0VOU0Ug fCBHRU5NQVNLKCgobnVtKSAtIDEpLCAwKSkNCj4gKyNkZWZpbmUgRElTQUJMRV9TRU5TSU5HX1BP SU5UCShMVlRTX1NJTkdMRV9TRU5TRSB8IDB4MCkNCj4gKyNkZWZpbmUgTFZUU01PTkNUTDFfMAkw eDAwNA0KPiArI2RlZmluZSBMVlRTTU9OQ1RMMl8wCTB4MDA4DQo+ICsjZGVmaW5lIExWVFNNT05J TlRfMAkweDAwQw0KPiArI2RlZmluZSBTVEFHRTNfSU5UX0VOCUJJVCgzMSkNCj4gKyNkZWZpbmUg TFZUU01PTklOVFNUU18wCTB4MDEwDQo+ICsjZGVmaW5lIExWVFNNT05JREVUMF8wCTB4MDE0DQo+ ICsjZGVmaW5lIExWVFNNT05JREVUMV8wCTB4MDE4DQo+ICsjZGVmaW5lIExWVFNNT05JREVUMl8w CTB4MDFDDQo+ICsjZGVmaW5lIExWVFNNT05JREVUM18wCTB4MDIwDQo+ICsjZGVmaW5lIExWVFNI Mk5USFJFXzAJMHgwMjQNCj4gKyNkZWZpbmUgTFZUU0hUSFJFXzAJMHgwMjgNCj4gKyNkZWZpbmUg TFZUU0NUSFJFXzAJMHgwMkMNCj4gKyNkZWZpbmUgTFZUU09GRlNFVEhfMAkweDAzMA0KPiArI2Rl ZmluZSBMVlRTT0ZGU0VUTF8wCTB4MDM0DQo+ICsjZGVmaW5lIExWVFNNU1JDVEwwXzAJMHgwMzgN Cj4gKyNkZWZpbmUgTFZUU01TUkNUTDFfMAkweDAzQw0KPiArI2RlZmluZSBMVlRTVFNTRUxfMAkw eDA0MA0KPiArI2RlZmluZSBTRVRfU0VOU09SX0lOREVYCTB4MTMxMjExMTANCj4gKyNkZWZpbmUg TFZUU0RFVklDRVRPXzAJMHgwNDQNCj4gKyNkZWZpbmUgTFZUU0NBTFNDQUxFXzAJMHgwNDgNCj4g KyNkZWZpbmUgU0VUX0NBTENfU0NBTEVfUlVMRVMJMHgwMDAwMDMwMA0KPiArI2RlZmluZSBMVlRT X0lEXzAJMHgwNEMNCj4gKyNkZWZpbmUgTFZUU19DT05GSUdfMAkweDA1MA0KPiArDQo+ICsjZGVm aW5lIEJST0FEQ0FTVF9JRF9VUERBVEUJQklUKDI2KQ0KPiArI2RlZmluZSBERVZJQ0VfU0VOU0lO R19TVEFUVVMJQklUKDI1KQ0KPiArI2RlZmluZSBERVZJQ0VfQUNDRVNTX1NUQVJUVVMJQklUKDI0 KQ0KPiArI2RlZmluZSBXUklURV9BQ0NFU1MJCUJJVCgxNikNCj4gKyNkZWZpbmUgREVWSUNFX1dS SVRFCQkoQklUKDMxKSB8IENLMjZNX0FDVElWRSB8IERFVklDRV9BQ0NFU1NfU1RBUlRVUyBcDQo+ ICsJCQkJfCBCSVQoMTcpIHwgV1JJVEVfQUNDRVNTKQ0KPiArI2RlZmluZSBERVZJQ0VfUkVBRAkJ KEJJVCgzMSkgfCBDSzI2TV9BQ1RJVkUgfCBERVZJQ0VfQUNDRVNTX1NUQVJUVVMgXA0KPiArCQkJ CXwgMSA8PCAxNykNCj4gKyNkZWZpbmUgUkVTRVRfQUxMX0RFVklDRVMJKERFVklDRV9XUklURSB8 IFJHX1RTRk1fUlNUIDw8IDggfCAweEZGKQ0KPiArI2RlZmluZSBSRUFEX0JBQ0tfREVWSUNFX0lE CShCSVQoMzEpIHwgQ0syNk1fQUNUSVZFIHwgQlJPQURDQVNUX0lEX1VQREFURQlcDQo+ICsJCQkJ fCBERVZJQ0VfQUNDRVNTX1NUQVJUVVMgfCBCSVQoMTcpCVwNCj4gKwkJCQl8IFJHX0RJRF9MVlRT IDw8IDgpDQo+ICsjZGVmaW5lIFJFQURfREVWSUNFX1JFRyhyZWdfaWR4KQkoREVWSUNFX1JFQUQg fCAocmVnX2lkeCkgPDwgOCB8IDB4MDApDQo+ICsjZGVmaW5lIExWVFNFREFUQTAwXzAJMHgwNTQN Cj4gKyNkZWZpbmUgTFZUU0VEQVRBMDFfMAkweDA1OA0KPiArI2RlZmluZSBMVlRTRURBVEEwMl8w CTB4MDVDDQo+ICsjZGVmaW5lIExWVFNFREFUQTAzXzAJMHgwNjANCj4gKyNkZWZpbmUgTFZUU01T UjBfMAkweDA5MA0KPiArI2RlZmluZSBNUlNfUkFXX01BU0sJCUdFTk1BU0soMTUsIDApDQo+ICsj ZGVmaW5lIE1SU19SQVdfVkFMSURfQklUCUJJVCgxNikNCj4gKyNkZWZpbmUgTFZUU01TUjFfMAkw eDA5NA0KPiArI2RlZmluZSBMVlRTTVNSMl8wCTB4MDk4DQo+ICsjZGVmaW5lIExWVFNNU1IzXzAJ MHgwOUMNCj4gKyNkZWZpbmUgTFZUU0lNTUQwXzAJMHgwQTANCj4gKyNkZWZpbmUgTFZUU0lNTUQx XzAJMHgwQTQNCj4gKyNkZWZpbmUgTFZUU0lNTUQyXzAJMHgwQTgNCj4gKyNkZWZpbmUgTFZUU0lN TUQzXzAJMHgwQUMNCj4gKyNkZWZpbmUgTFZUU1JEQVRBMF8wCTB4MEIwDQo+ICsjZGVmaW5lIExW VFNSREFUQTFfMAkweDBCNA0KPiArI2RlZmluZSBMVlRTUkRBVEEyXzAJMHgwQjgNCj4gKyNkZWZp bmUgTFZUU1JEQVRBM18wCTB4MEJDDQo+ICsjZGVmaW5lIExWVFNQUk9UQ1RMXzAJMHgwQzANCj4g KyNkZWZpbmUgUFJPVE9GRlNFVAlHRU5NQVNLKDE1LCAwKQ0KPiArI2RlZmluZSBMVlRTUFJPVFRB XzAJMHgwQzQNCj4gKyNkZWZpbmUgTFZUU1BST1RUQl8wCTB4MEM4DQo+ICsjZGVmaW5lIExWVFNQ Uk9UVENfMAkweDBDQw0KPiArI2RlZmluZSBMVlRTQ0xLRU5fMAkweDBFNA0KPiArI2RlZmluZSBF TkFCTEVfTFZUU19DVFJMX0NMSwkoMSkNCj4gKyNkZWZpbmUgRElTQUJMRV9MVlRTX0NUUkxfQ0xL CSgwKQ0KPiArI2RlZmluZSBMVlRTREJHU0VMXzAJMHgwRTgNCj4gKyNkZWZpbmUgTFZUU0RCR1NJ R18wCTB4MEVDDQo+ICsjZGVmaW5lIExWVFNTUEFSRTBfMAkweDBGMA0KPiArI2RlZmluZSBMVlRT U1BBUkUxXzAJMHgwRjQNCj4gKyNkZWZpbmUgTFZUU1NQQVJFMl8wCTB4MEY4DQo+ICsjZGVmaW5l IExWVFNTUEFSRTNfMAkweDBGQw0KPiArDQo+ICsjZGVmaW5lIFRIRVJNSU5UU1QJMHhGMDQNCj4g Ky8qPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCj4g KyAqIExWVFMgcmVnaXN0ZXIgbWFzaw0KPiArICo9PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PQ0KPiArICovDQo+ICsjZGVmaW5lIFRIRVJNQUxfQ09MRF9J TlRFUlJVUFRfMAkJMHgwMDAwMDAwMQ0KPiArI2RlZmluZSBUSEVSTUFMX0hPVF9JTlRFUlJVUFRf MAkJCTB4MDAwMDAwMDINCj4gKyNkZWZpbmUgVEhFUk1BTF9MT1dfT0ZGU0VUX0lOVEVSUlVQVF8w CQkweDAwMDAwMDA0DQo+ICsjZGVmaW5lIFRIRVJNQUxfSElHSF9PRkZTRVRfSU5URVJSVVBUXzAJ CTB4MDAwMDAwMDgNCj4gKyNkZWZpbmUgVEhFUk1BTF9IT1QyTk9STUFMX0lOVEVSUlVQVF8wCQkw eDAwMDAwMDEwDQo+ICsjZGVmaW5lIFRIRVJNQUxfQ09MRF9JTlRFUlJVUFRfMQkJMHgwMDAwMDAy MA0KPiArI2RlZmluZSBUSEVSTUFMX0hPVF9JTlRFUlJVUFRfMQkJCTB4MDAwMDAwNDANCj4gKyNk ZWZpbmUgVEhFUk1BTF9MT1dfT0ZGU0VUX0lOVEVSUlVQVF8xCQkweDAwMDAwMDgwDQo+ICsjZGVm aW5lIFRIRVJNQUxfSElHSF9PRkZTRVRfSU5URVJSVVBUXzEJCTB4MDAwMDAxMDANCj4gKyNkZWZp bmUgVEhFUk1BTF9IT1QyTk9STUFMX0lOVEVSUlVQVF8xCQkweDAwMDAwMjAwDQo+ICsjZGVmaW5l IFRIRVJNQUxfQ09MRF9JTlRFUlJVUFRfMgkJMHgwMDAwMDQwMA0KPiArI2RlZmluZSBUSEVSTUFM X0hPVF9JTlRFUlJVUFRfMgkJCTB4MDAwMDA4MDANCj4gKyNkZWZpbmUgVEhFUk1BTF9MT1dfT0ZG U0VUX0lOVEVSUlVQVF8yCQkweDAwMDAxMDAwDQo+ICsjZGVmaW5lIFRIRVJNQUxfSElHSF9PRkZT RVRfSU5URVJSVVBUXzIJCTB4MDAwMDIwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9IT1QyTk9STUFM X0lOVEVSUlVQVF8yCQkweDAwMDA0MDAwDQo+ICsjZGVmaW5lIFRIRVJNQUxfQUhCX1RJTUVPVVRf SU5URVJSVVBUCQkweDAwMDA4MDAwDQo+ICsjZGVmaW5lIFRIRVJNQUxfREVWSUNFX1RJTUVPVVRf SU5URVJSVVBUCTB4MDAwMDgwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9JTU1FRElBVEVfSU5URVJS VVBUXzAJCTB4MDAwMTAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9JTU1FRElBVEVfSU5URVJSVVBU XzEJCTB4MDAwMjAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9JTU1FRElBVEVfSU5URVJSVVBUXzIJ CTB4MDAwNDAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9GSUxURVJfSU5URVJSVVBUXzAJCTB4MDAw ODAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9GSUxURVJfSU5URVJSVVBUXzEJCTB4MDAxMDAwMDAN Cj4gKyNkZWZpbmUgVEhFUk1BTF9GSUxURVJfSU5URVJSVVBUXzIJCTB4MDAyMDAwMDANCj4gKyNk ZWZpbmUgVEhFUk1BTF9DT0xEX0lOVEVSUlVQVF8zCQkweDAwNDAwMDAwDQo+ICsjZGVmaW5lIFRI RVJNQUxfSE9UX0lOVEVSUlVQVF8zCQkJMHgwMDgwMDAwMA0KPiArI2RlZmluZSBUSEVSTUFMX0xP V19PRkZTRVRfSU5URVJSVVBUXzMJCTB4MDEwMDAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9ISUdI X09GRlNFVF9JTlRFUlJVUFRfMwkJMHgwMjAwMDAwMA0KPiArI2RlZmluZSBUSEVSTUFMX0hPVDJO T1JNQUxfSU5URVJSVVBUXzMJCTB4MDQwMDAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9JTU1FRElB VEVfSU5URVJSVVBUXzMJCTB4MDgwMDAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9GSUxURVJfSU5U RVJSVVBUXzMJCTB4MTAwMDAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9QUk9URUNUSU9OX1NUQUdF XzEJCTB4MjAwMDAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9QUk9URUNUSU9OX1NUQUdFXzIJCTB4 NDAwMDAwMDANCj4gKyNkZWZpbmUgVEhFUk1BTF9QUk9URUNUSU9OX1NUQUdFXzMJCTB4ODAwMDAw MDANCj4gKyNlbmRpZiAvKiBfX01US19TT0NfVEVNUF9MVlRTX0hfXyAqLw0KDQo= From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 616EDC433B4 for ; Wed, 7 Apr 2021 09:10:59 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9472561205 for ; Wed, 7 Apr 2021 09:10:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9472561205 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Date:CC:To:From: Subject:Message-ID:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=9fQzFdDCgknrhp4DkzRO/rUdwv4BSF0YT9S18/RY004=; b=BBDBhmosEAm0699oy1NQgWVEU vXyNLWr2lYWYrCYxK++gAETKhMpdawyoL6/44SWyVSKBxXGP1asH/2QTXGrCaV/TDMsqah1azsCdk xlxtiUNTE29xMUYLiTr9eDFAeZtxkN6YcvxoD0p2bSmbGugnc73plbOUUex04P0RvTQUY4U4EqZW9 Mo9fi02yhmZ7FkZseFu9dUIkdUAzSOm9wepDfzcfjRwlc744o0m1xqv1viBv0N6QaY5KcNOZFFvO2 C8iytxjz4zXKhZuqrtL5wI5gTifjlhVw5dZorsHMjAw267R8CU/rghW+m6Aioz0a3muvCzs8iNApA AT919Vdsg==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lU4Cu-004Ylb-4B; Wed, 07 Apr 2021 09:10:40 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lU4Bd-004YXg-7S; Wed, 07 Apr 2021 09:09:33 +0000 X-UUID: d14ff8e6388f4133a0a92e76c637196e-20210407 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=grOFFUtINhKpc8Th5j1GB5zb0oqVfOdvcKO8OHgRSbc=; b=QUzWQ/gTAAH9McK3Dw0ycCodpuQwLsbAzrWZjsDGvOLrX1tgZ/HaPig3mZH1cFAWvwajdw5ZbHG46faj8GmoSJeI6Jar6+ViDJaBAxSUgXKY7ozlJ4dkqSqDpGtnlaXYXjVCYObpup2x04bFQBZl2yw8CVvmqTxW295Vy9+jR7s=; X-UUID: d14ff8e6388f4133a0a92e76c637196e-20210407 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1058292320; Wed, 07 Apr 2021 02:09:10 -0700 Received: from MTKMBS07N2.mediatek.inc (172.21.101.141) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 7 Apr 2021 02:09:08 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 7 Apr 2021 17:09:06 +0800 Received: from [172.21.84.99] (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 7 Apr 2021 17:09:06 +0800 Message-ID: <1617786546.12846.2.camel@mtksdccf07> Subject: Re: [v3,2/3] thermal: mediatek: Add LVTS drivers for SoC theraml zones From: Michael Kao To: Zhang Rui , Daniel Lezcano CC: , , "Eduardo Valentin" , Rob Herring , "Mark Rutland" , Matthias Brugger , , , , , Date: Wed, 7 Apr 2021 17:09:06 +0800 In-Reply-To: <20210312034018.17437-3-michael.kao@mediatek.com> References: <20210312034018.17437-1-michael.kao@mediatek.com> <20210312034018.17437-3-michael.kao@mediatek.com> X-Mailer: Evolution 3.2.3-0ubuntu6 MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210407_100923_643820_7843B95A X-CRM114-Status: GOOD ( 28.80 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Hi Maintainers, Gentle pin for this patch. Thanks On Fri, 2021-03-12 at 11:40 +0800, Michael Kao wrote: > Add a LVTS (Low voltage thermal sensor) driver to report junction > temperatures in Mediatek SoC and register the maximum temperature > of sensors and each sensor as a thermal zone. > > Signed-off-by: Yu-Chia Chang > Signed-off-by: Michael Kao > --- > drivers/thermal/mediatek/Kconfig | 10 + > drivers/thermal/mediatek/Makefile | 1 + > drivers/thermal/mediatek/soc_temp_lvts.c | 1287 ++++++++++++++++++++++ > drivers/thermal/mediatek/soc_temp_lvts.h | 312 ++++++ > 4 files changed, 1610 insertions(+) > create mode 100644 drivers/thermal/mediatek/soc_temp_lvts.c > create mode 100644 drivers/thermal/mediatek/soc_temp_lvts.h > > diff --git a/drivers/thermal/mediatek/Kconfig b/drivers/thermal/mediatek/Kconfig > index 0351e73170b7..d716d0372e1e 100644 > --- a/drivers/thermal/mediatek/Kconfig > +++ b/drivers/thermal/mediatek/Kconfig > @@ -20,4 +20,14 @@ config MTK_SOC_THERMAL > configures thermal controllers to collect temperature > via AUXADC interface. > > +config MTK_SOC_THERMAL_LVTS > + tristate "LVTS (Low voltage thermal sensor) driver for Mediatek SoCs" > + depends on HAS_IOMEM > + depends on NVMEM > + depends on RESET_TI_SYSCON > + help > + Enable this option if you want to get SoC temperature > + information for Mediatek platforms. This driver > + configures LVTS thermal controllers to collect temperatures > + via Analog Serial Interface(ASIF). > endif > diff --git a/drivers/thermal/mediatek/Makefile b/drivers/thermal/mediatek/Makefile > index f75313ddce5e..16ce166e5916 100644 > --- a/drivers/thermal/mediatek/Makefile > +++ b/drivers/thermal/mediatek/Makefile > @@ -1 +1,2 @@ > obj-$(CONFIG_MTK_SOC_THERMAL) += soc_temp.o > +obj-$(CONFIG_MTK_SOC_THERMAL_LVTS) += soc_temp_lvts.o > diff --git a/drivers/thermal/mediatek/soc_temp_lvts.c b/drivers/thermal/mediatek/soc_temp_lvts.c > new file mode 100644 > index 000000000000..8153edaaf815 > --- /dev/null > +++ b/drivers/thermal/mediatek/soc_temp_lvts.c > @@ -0,0 +1,1287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 MediaTek Inc. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "soc_temp_lvts.h" > + > +/*================================================== > + * Definition or macro function > + *================================================== > + */ > +#define STOP_COUNTING_V4 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00) > +#define SET_RG_TSFM_LPDLY_V4 (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6) > +#define SET_COUNTING_WINDOW_20US1_V4 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00) > +#define SET_COUNTING_WINDOW_20US2_V4 (DEVICE_WRITE | RG_TSFM_CTRL_1 << 8 | 0x20) > +#define TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_2 << 8 | 0x84) > +#define TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_4 << 8 | 0x7C) > +#define SET_TS_RSV_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_1 << 8 | 0x8D) > +#define SET_TS_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4) > +#define TOGGLE_RG_TSV2F_VCO_RST1_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xFC) > +#define TOGGLE_RG_TSV2F_VCO_RST2_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4) > + > +#define SET_LVTS_AUTO_RCK_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_6 << 8 | 0x01) > +#define SELECT_SENSOR_RCK_V4(id) (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | (id)) > +#define SET_DEVICE_SINGLE_MODE_V4 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0x78) > +#define KICK_OFF_RCK_COUNTING_V4 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x02) > +#define SET_SENSOR_NO_RCK_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | 0x10) > +#define SET_DEVICE_LOW_POWER_SINGLE_MODE_V4 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8) > + > +#define ENABLE_FEATURE(feature) (lvts_data->feature_bitmap |= (feature)) > +#define DISABLE_FEATURE(feature) (lvts_data->feature_bitmap &= (~(feature))) > +#define IS_ENABLE(feature) (lvts_data->feature_bitmap & (feature)) > + > +#define DISABLE_THERMAL_HW_REBOOT (-274000) > + > +#define CLOCK_26MHZ_CYCLE_NS (38) > +#define BUS_ACCESS_US (2) > + > +#define FEATURE_DEVICE_AUTO_RCK (BIT(0)) > +#define FEATURE_CK26M_ACTIVE (BIT(1)) > +#define CK26M_ACTIVE (((lvts_data->feature_bitmap & FEATURE_CK26M_ACTIVE) \ > + ? 1 : 0) << 30) > +#define GET_BASE_ADDR(tc_id) \ > + (lvts_data->domain[lvts_data->tc[tc_id].domain_index].base \ > + + lvts_data->tc[tc_id].addr_offset) > + > +#define SET_TC_SPEED_IN_US(pu, gd, fd, sd) \ > + { \ > + .period_unit = (((pu) * 1000) / (256 * CLOCK_26MHZ_CYCLE_NS)), \ > + .group_interval_delay = ((gd) / (pu)), \ > + .filter_interval_delay = ((fd) / (pu)), \ > + .sensor_interval_delay = ((sd) / (pu)), \ > + } > + > +#define GET_CAL_DATA_BITMASK(index, h, l) \ > + (((index) < lvts_data->num_efuse_addr) \ > + ? ((lvts_data->efuse[(index)] & GENMASK(h, l)) >> l) \ > + : 0) > + > +#define GET_CAL_DATA_BIT(index, bit) \ > + (((index) < lvts_data->num_efuse_addr) \ > + ? ((lvts_data->efuse[index] & BIT(bit)) >> (bit)) \ > + : 0) > + > +#define GET_TC_SENSOR_NUM(tc_id) \ > + (lvts_data->tc[tc_id].num_sensor) > + > +#define ONE_SAMPLE (lvts_data->counting_window_us + 2 * BUS_ACCESS_US) > + > +#define NUM_OF_SAMPLE(tc_id) \ > + ((lvts_data->tc[tc_id].hw_filter < LVTS_FILTER_2) ? 1 : \ > + ((lvts_data->tc[tc_id].hw_filter > LVTS_FILTER_16_OF_18) ? 1 : \ > + ((lvts_data->tc[tc_id].hw_filter == LVTS_FILTER_16_OF_18) ? 18 :\ > + ((lvts_data->tc[tc_id].hw_filter == LVTS_FILTER_8_OF_10) ? 10 : \ > + (lvts_data->tc[tc_id].hw_filter * 2))))) > + > +#define PERIOD_UNIT_US(tc_id) \ > + ((lvts_data->tc[tc_id].tc_speed.period_unit * 256 * \ > + CLOCK_26MHZ_CYCLE_NS) / 1000) > +#define FILTER_INT_US(tc_id) \ > + (lvts_data->tc[tc_id].tc_speed.filter_interval_delay \ > + * PERIOD_UNIT_US(tc_id)) > +#define SENSOR_INT_US(tc_id) \ > + (lvts_data->tc[tc_id].tc_speed.sensor_interval_delay \ > + * PERIOD_UNIT_US(tc_id)) > +#define GROUP_INT_US(tc_id) \ > + (lvts_data->tc[tc_id].tc_speed.group_interval_delay \ > + * PERIOD_UNIT_US(tc_id)) > + > +#define SENSOR_LATENCY_US(tc_id) \ > + ((NUM_OF_SAMPLE(tc_id) - 1) * FILTER_INT_US(tc_id) \ > + + NUM_OF_SAMPLE(tc_id) * ONE_SAMPLE) > + > +#define GROUP_LATENCY_US(tc_id) \ > + (GET_TC_SENSOR_NUM(tc_id) * SENSOR_LATENCY_US(tc_id) \ > + + (GET_TC_SENSOR_NUM(tc_id) - 1) * SENSOR_INT_US(tc_id) \ > + + GROUP_INT_US(tc_id)) > + > +/*================================================== > + * LVTS local common code > + *================================================== > + */ > +static int lvts_raw_to_temp(struct formula_coeff *co, unsigned int msr_raw) > +{ > + /* This function returns degree mC */ > + > + int temp; > + > + temp = (co->a * ((unsigned long long)msr_raw)) >> 14; > + temp = temp + co->golden_temp * 500 + co->b; > + > + return temp; > +} > + > +static unsigned int lvts_temp_to_raw(struct formula_coeff *co, int temp) > +{ > + unsigned int msr_raw; > + > + msr_raw = div_s64((s64)((co->golden_temp * 500 + co->b - temp)) << 14, > + (-1 * co->a)); > + > + return msr_raw; > +} > + > +static int lvts_read_all_tc_temperature(struct lvts_data *lvts_data) > +{ > + struct tc_settings *tc = lvts_data->tc; > + unsigned int i, j, s_index, msr_raw; > + int max_temp = 0, current_temp; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + for (j = 0; j < tc[i].num_sensor; j++) { > + s_index = tc[i].sensor_map[j]; > + > + msr_raw = readl(LVTSMSR0_0 + base + 0x4 * j) & MRS_RAW_MASK; > + current_temp = lvts_raw_to_temp(&lvts_data->coeff, msr_raw); > + > + if (msr_raw == 0) > + current_temp = THERMAL_TEMP_INVALID; > + > + max_temp = max(max_temp, current_temp); > + > + lvts_data->sen_data[s_index].msr_raw = msr_raw; > + lvts_data->sen_data[s_index].temp = current_temp; > + } > + } > + > + return max_temp; > +} > + > +static int soc_temp_lvts_read_temp(void *data, int *temperature) > +{ > + struct soc_temp_tz *lvts_tz = (struct soc_temp_tz *)data; > + struct lvts_data *lvts_data = lvts_tz->lvts_data; > + > + if (lvts_tz->id == 0) > + *temperature = lvts_read_all_tc_temperature(lvts_data); > + else if (lvts_tz->id - 1 < lvts_data->num_sensor) > + *temperature = lvts_data->sen_data[lvts_tz->id - 1].temp; > + else > + return -EINVAL; > + > + return 0; > +} > + > +static const struct thermal_zone_of_device_ops soc_temp_lvts_ops = { > + .get_temp = soc_temp_lvts_read_temp, > +}; > + > +static void lvts_write_device(struct lvts_data *lvts_data, unsigned int data, > + int tc_id) > +{ > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + writel(data, LVTS_CONFIG_0 + base); > + > + usleep_range(5, 15); > +} > + > +static unsigned int lvts_read_device(struct lvts_data *lvts_data, > + unsigned int reg_idx, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + void __iomem *base; > + unsigned int data; > + int ret; > + > + base = GET_BASE_ADDR(tc_id); > + writel(READ_DEVICE_REG(reg_idx), LVTS_CONFIG_0 + base); > + > + ret = readl_poll_timeout(LVTS_CONFIG_0 + base, data, > + !(data & DEVICE_ACCESS_STARTUS), > + 2, 200); > + if (ret) > + dev_err(dev, > + "Error: LVTS %d DEVICE_ACCESS_START didn't ready\n", tc_id); > + > + data = readl(LVTSRDATA0_0 + base); > + > + return data; > +} > + > +static void wait_all_tc_sensing_point_idle(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int mask, error_code, is_error; > + void __iomem *base; > + int i, cnt, ret; > + > + mask = BIT(10) | BIT(7) | BIT(0); > + > + for (cnt = 0; cnt < 2; cnt++) { > + is_error = 0; > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + ret = readl_poll_timeout(LVTSMSRCTL1_0 + base, error_code, > + !(error_code & mask), 2, 200); > + /* > + * Error code > + * 000: IDLE > + * 001: Write transaction > + * 010: Waiting for read after Write > + * 011: Disable Continue fetching on Device > + * 100: Read transaction > + * 101: Set Device special Register for Voltage threshold > + * 111: Set TSMCU number for Fetch > + */ > + error_code = ((error_code & BIT(10)) >> 8) + > + ((error_code & BIT(7)) >> 6) + > + (error_code & BIT(0)); > + > + if (ret) > + dev_err(dev, > + "Error LVTS %d sensing points aren't idle, error_code %d\n", > + i, error_code); > + > + if (error_code != 0) > + is_error = 1; > + } > + > + if (is_error == 0) > + break; > + } > +} > + > +static void lvts_reset(struct lvts_data *lvts_data) > +{ > + int i; > + > + for (i = 0; i < lvts_data->num_domain; i++) { > + if (lvts_data->domain[i].reset) > + reset_control_assert(lvts_data->domain[i].reset); > + > + if (lvts_data->domain[i].reset) > + reset_control_deassert(lvts_data->domain[i].reset); > + } > +} > + > +static void device_identification(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int i, data; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + > + writel(ENABLE_LVTS_CTRL_CLK, LVTSCLKEN_0 + base); > + > + lvts_write_device(lvts_data, RESET_ALL_DEVICES, i); > + > + lvts_write_device(lvts_data, READ_BACK_DEVICE_ID, i); > + > + /* Check LVTS device ID */ > + data = (readl(LVTS_ID_0 + base) & GENMASK(7, 0)); > + if (data != (0x81 + i)) > + dev_err(dev, "LVTS_TC_%d, Device ID should be 0x%x, but 0x%x\n", > + i, (0x81 + i), data); > + } > +} > + > +static void disable_all_sensing_points(struct lvts_data *lvts_data) > +{ > + unsigned int i; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + writel(DISABLE_SENSING_POINT, LVTSMONCTL0_0 + base); > + } > +} > + > +static void enable_all_sensing_points(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + unsigned int i, num; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + num = tc[i].num_sensor; > + > + if (num > ALL_SENSING_POINTS) { > + dev_err(dev, > + "%s, LVTS%d, illegal number of sensors: %d\n", > + __func__, i, tc[i].num_sensor); > + continue; > + } > + > + writel(ENABLE_SENSING_POINT(num), LVTSMONCTL0_0 + base); > + } > +} > + > +static void set_polling_speed(struct lvts_data *lvts_data, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + unsigned int lvts_mon_ctl_1, lvts_mon_ctl_2; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + lvts_mon_ctl_1 = ((tc[tc_id].tc_speed.group_interval_delay << 20) & GENMASK(29, 20)) | > + (tc[tc_id].tc_speed.period_unit & GENMASK(9, 0)); > + lvts_mon_ctl_2 = ((tc[tc_id].tc_speed.filter_interval_delay << 16) & GENMASK(25, 16)) | > + (tc[tc_id].tc_speed.sensor_interval_delay & GENMASK(9, 0)); > + /* > + * Clock source of LVTS thermal controller is 26MHz. > + * Period unit is a base for all interval delays > + * All interval delays must multiply it to convert a setting to time. > + * Filter interval delay is a delay between two samples of the same sensor > + * Sensor interval delay is a delay between two samples of differnet sensors > + * Group interval delay is a delay between different rounds. > + * For example: > + * If Period unit = C, filter delay = 1, sensor delay = 2, group delay = 1, > + * and two sensors, TS1 and TS2, are in a LVTS thermal controller > + * and then > + * Period unit = C * 1/26M * 256 = 12 * 38.46ns * 256 = 118.149us > + * Filter interval delay = 1 * Period unit = 118.149us > + * Sensor interval delay = 2 * Period unit = 236.298us > + * Group interval delay = 1 * Period unit = 118.149us > + * > + * TS1 TS1 ... TS1 TS2 TS2 ... TS2 TS1... > + * <--> Filter interval delay > + * <--> Sensor interval delay > + * <--> Group interval delay > + */ > + writel(lvts_mon_ctl_1, LVTSMONCTL1_0 + base); > + writel(lvts_mon_ctl_2, LVTSMONCTL2_0 + base); > + > + dev_info(dev, "%s %d, LVTSMONCTL1_0= 0x%x,LVTSMONCTL2_0= 0x%x\n", > + __func__, tc_id, readl(LVTSMONCTL1_0 + base), > + readl(LVTSMONCTL2_0 + base)); > +} > + > +static void set_hw_filter(struct lvts_data *lvts_data, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + unsigned int option; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + option = tc[tc_id].hw_filter & 0x7; > + /* hw filter > + * 000: Get one sample > + * 001: Get 2 samples and average them > + * 010: Get 4 samples, drop max and min, then average the rest of 2 samples > + * 011: Get 6 samples, drop max and min, then average the rest of 4 samples > + * 100: Get 10 samples, drop max and min, then average the rest of 8 samples > + * 101: Get 18 samples, drop max and min, then average the rest of 16 samples > + */ > + option = (option << 9) | (option << 6) | (option << 3) | option; > + > + writel(option, LVTSMSRCTL0_0 + base); > + dev_info(dev, "%s %d, LVTSMSRCTL0_0= 0x%x\n", > + __func__, tc_id, readl(LVTSMSRCTL0_0 + base)); > +} > + > +static int get_dominator_index(struct lvts_data *lvts_data, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + int d_index; > + > + if (tc[tc_id].dominator_sensing_point == ALL_SENSING_POINTS) { > + d_index = ALL_SENSING_POINTS; > + } else if (tc[tc_id].dominator_sensing_point < > + tc[tc_id].num_sensor){ > + d_index = tc[tc_id].dominator_sensing_point; > + } else { > + dev_err(dev, > + "Error: LVTS%d, dominator_sensing_point= %d should smaller than num_sensor= %d\n", > + tc_id, tc[tc_id].dominator_sensing_point, > + tc[tc_id].num_sensor); > + > + dev_err(dev, "Use the sensing point 0 as the dominated sensor\n"); > + d_index = SENSING_POINT0; > + } > + > + return d_index; > +} > + > +static void disable_hw_reboot_interrupt(struct lvts_data *lvts_data, int tc_id) > +{ > + unsigned int temp; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + /* LVTS thermal controller has two interrupts for thermal HW reboot > + * One is for AP SW and the other is for RGU > + * The interrupt of AP SW can turn off by a bit of a register, but > + * the other for RGU cannot. > + * To prevent rebooting device accidentally, we are going to add > + * a huge offset to LVTS and make LVTS always report extremely low > + * temperature. > + */ > + > + /* After adding the huge offset 0x3FFF, LVTS alawys adds the > + * offset to MSR_RAW. > + * When MSR_RAW is larger, SW will convert lower temperature/ > + */ > + temp = readl(LVTSPROTCTL_0 + base); > + writel(temp | 0x3FFF, LVTSPROTCTL_0 + base); > + > + /* Disable the interrupt of AP SW */ > + temp = readl(LVTSMONINT_0 + base); > + writel(temp & ~(STAGE3_INT_EN), LVTSMONINT_0 + base); > +} > + > +static void enable_hw_reboot_interrupt(struct lvts_data *lvts_data, int tc_id) > +{ > + unsigned int temp; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + /* Enable the interrupt of AP SW */ > + temp = readl(LVTSMONINT_0 + base); > + writel(temp | STAGE3_INT_EN, LVTSMONINT_0 + base); > + /* Clear the offset */ > + temp = readl(LVTSPROTCTL_0 + base); > + writel(temp & ~PROTOFFSET, LVTSPROTCTL_0 + base); > +} > + > +static void set_tc_hw_reboot_threshold(struct lvts_data *lvts_data, > + int trip_point, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int msr_raw, temp, config, d_index; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + d_index = get_dominator_index(lvts_data, tc_id); > + > + dev_info(dev, "%s: LVTS%d, the dominator sensing point= %d\n", > + __func__, tc_id, d_index); > + > + disable_hw_reboot_interrupt(lvts_data, tc_id); > + > + temp = readl(LVTSPROTCTL_0 + base); > + if (d_index == ALL_SENSING_POINTS) { > + /* Maximum of 4 sensing points */ > + config = (0x1 << 16); > + writel(config | temp, LVTSPROTCTL_0 + base); > + } else { > + /* Select protection sensor */ > + config = ((d_index << 2) + 0x2) << 16; > + writel(config | temp, LVTSPROTCTL_0 + base); > + } > + > + msr_raw = lvts_temp_to_raw(&lvts_data->coeff, trip_point); > + writel(msr_raw, LVTSPROTTC_0 + base); > + > + enable_hw_reboot_interrupt(lvts_data, tc_id); > +} > + > +static void set_all_tc_hw_reboot(struct lvts_data *lvts_data) > +{ > + struct tc_settings *tc = lvts_data->tc; > + int i, trip_point; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + trip_point = tc[i].hw_reboot_trip_point; > + > + if (tc[i].num_sensor == 0) > + continue; > + > + if (trip_point == DISABLE_THERMAL_HW_REBOOT) > + continue; > + > + set_tc_hw_reboot_threshold(lvts_data, trip_point, i); > + } > +} > + > +static int lvts_init(struct lvts_data *lvts_data) > +{ > + struct platform_ops *ops = &lvts_data->ops; > + struct device *dev = lvts_data->dev; > + int ret; > + > + ret = clk_prepare_enable(lvts_data->clk); > + if (ret) { > + dev_err(dev, > + "Error: Failed to enable lvts controller clock: %d\n", > + ret); > + return ret; > + } > + > + lvts_reset(lvts_data); > + > + device_identification(lvts_data); > + if (ops->device_enable_and_init) > + ops->device_enable_and_init(lvts_data); > + > + if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK)) { > + if (ops->device_enable_auto_rck) > + ops->device_enable_auto_rck(lvts_data); > + } else { > + if (ops->device_read_count_rc_n) > + ops->device_read_count_rc_n(lvts_data); > + } > + > + if (ops->set_cal_data) > + ops->set_cal_data(lvts_data); > + > + disable_all_sensing_points(lvts_data); > + wait_all_tc_sensing_point_idle(lvts_data); > + if (ops->init_controller) > + ops->init_controller(lvts_data); > + enable_all_sensing_points(lvts_data); > + > + set_all_tc_hw_reboot(lvts_data); > + > + return 0; > +} > + > +static int prepare_calibration_data(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + struct sensor_cal_data *cal_data = &lvts_data->cal_data; > + struct platform_ops *ops = &lvts_data->ops; > + int i, offset, size; > + char buffer[512]; > + > + cal_data->count_r = devm_kcalloc(dev, lvts_data->num_sensor, > + sizeof(*cal_data->count_r), GFP_KERNEL); > + if (!cal_data->count_r) > + return -ENOMEM; > + > + cal_data->count_rc = devm_kcalloc(dev, lvts_data->num_sensor, > + sizeof(*cal_data->count_rc), GFP_KERNEL); > + if (!cal_data->count_rc) > + return -ENOMEM; > + > + if (ops->efuse_to_cal_data) > + ops->efuse_to_cal_data(lvts_data); > + > + cal_data->use_fake_efuse = 1; > + if (cal_data->golden_temp != 0) { > + cal_data->use_fake_efuse = 0; > + } else { > + for (i = 0; i < lvts_data->num_sensor; i++) { > + if (cal_data->count_r[i] != 0 || > + cal_data->count_rc[i] != 0) { > + cal_data->use_fake_efuse = 0; > + break; > + } > + } > + } > + > + if (cal_data->use_fake_efuse) { > + /* It means all efuse data are equal to 0 */ > + dev_err(dev, > + "[lvts_cal] This sample is not calibrated, fake !!\n"); > + > + cal_data->golden_temp = cal_data->default_golden_temp; > + for (i = 0; i < lvts_data->num_sensor; i++) { > + cal_data->count_r[i] = cal_data->default_count_r; > + cal_data->count_rc[i] = cal_data->default_count_rc; > + } > + } > + > + lvts_data->coeff.golden_temp = cal_data->golden_temp; > + > + dev_info(dev, "[lvts_cal] golden_temp = %d\n", cal_data->golden_temp); > + > + size = sizeof(buffer); > + offset = snprintf(buffer, size, "[lvts_cal] num:g_count:g_count_rc "); > + for (i = 0; i < lvts_data->num_sensor; i++) > + offset += snprintf(buffer + offset, size - offset, "%d:%d:%d ", > + i, cal_data->count_r[i], cal_data->count_rc[i]); > + > + buffer[offset] = '\0'; > + dev_info(dev, "%s\n", buffer); > + > + return 0; > +} > + > +static int get_calibration_data(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + char cell_name[8]; > + struct nvmem_cell *cell; > + u32 *buf; > + size_t len; > + int i, j, index = 0, ret; > + > + lvts_data->efuse = devm_kcalloc(dev, lvts_data->num_efuse_addr, > + sizeof(*lvts_data->efuse), GFP_KERNEL); > + if (!lvts_data->efuse) > + return -ENOMEM; > + > + for (i = 0; i < lvts_data->num_efuse_block; i++) { > + snprintf(cell_name, sizeof(cell_name), "e_data%d", i + 1); > + cell = nvmem_cell_get(dev, cell_name); > + if (IS_ERR(cell)) { > + dev_err(dev, "Error: Failed to get nvmem cell %s\n", cell_name); > + return PTR_ERR(cell); > + } > + > + buf = (u32 *)nvmem_cell_read(cell, &len); > + nvmem_cell_put(cell); > + > + if (IS_ERR(buf)) > + return PTR_ERR(buf); > + > + for (j = 0; j < (len / sizeof(u32)); j++) { > + if (index >= lvts_data->num_efuse_addr) { > + dev_err(dev, "Array efuse is going to overflow"); > + kfree(buf); > + return -EINVAL; > + } > + > + lvts_data->efuse[index] = buf[j]; > + index++; > + } > + > + kfree(buf); > + } > + > + ret = prepare_calibration_data(lvts_data); > + > + return ret; > +} > + > +static int of_update_lvts_data(struct lvts_data *lvts_data, > + struct platform_device *pdev) > +{ > + struct device *dev = lvts_data->dev; > + struct power_domain *domain; > + struct resource *res; > + unsigned int i; > + int ret; > + > + lvts_data->clk = devm_clk_get(dev, "lvts_clk"); > + if (IS_ERR(lvts_data->clk)) > + return PTR_ERR(lvts_data->clk); > + > + domain = devm_kcalloc(dev, lvts_data->num_domain, sizeof(*domain), GFP_KERNEL); > + if (!domain) > + return -ENOMEM; > + > + for (i = 0; i < lvts_data->num_domain; i++) { > + /* Get base address */ > + res = platform_get_resource(pdev, IORESOURCE_MEM, i); > + if (!res) { > + dev_err(dev, "No IO resource, index %d\n", i); > + return -ENXIO; > + } > + > + domain[i].base = devm_ioremap_resource(dev, res); > + if (IS_ERR(domain[i].base)) { > + dev_err(dev, "Failed to remap io, index %d\n", i); > + return PTR_ERR(domain[i].base); > + } > + > + /* Get interrupt number */ > + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); > + if (!res) { > + dev_err(dev, "No irq resource, index %d\n", i); > + return -EINVAL; > + } > + domain[i].irq_num = res->start; > + > + /* Get reset control */ > + domain[i].reset = devm_reset_control_get_by_index(dev, i); > + if (IS_ERR(domain[i].reset)) { > + dev_err(dev, "Failed to get, index %d\n", i); > + return PTR_ERR(domain[i].reset); > + } > + } > + > + lvts_data->domain = domain; > + > + lvts_data->sen_data = devm_kcalloc(dev, lvts_data->num_sensor, > + sizeof(*lvts_data->sen_data), GFP_KERNEL); > + if (!lvts_data->sen_data) > + return -ENOMEM; > + > + ret = get_calibration_data(lvts_data); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static void lvts_device_close(struct lvts_data *lvts_data) > +{ > + unsigned int i; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + lvts_write_device(lvts_data, RESET_ALL_DEVICES, i); > + writel(DISABLE_LVTS_CTRL_CLK, LVTSCLKEN_0 + base); > + } > +} > + > +static void lvts_close(struct lvts_data *lvts_data) > +{ > + disable_all_sensing_points(lvts_data); > + wait_all_tc_sensing_point_idle(lvts_data); > + lvts_device_close(lvts_data); > + clk_disable_unprepare(lvts_data->clk); > +} > + > +static void tc_irq_handler(struct lvts_data *lvts_data, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int ret = 0; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + ret = readl(LVTSMONINTSTS_0 + base); > + /* Write back to clear interrupt status */ > + writel(ret, LVTSMONINTSTS_0 + base); > + > + dev_info(dev, "[Thermal IRQ] LVTS thermal controller %d, LVTSMONINTSTS=0x%08x\n", > + tc_id, ret); > + > + if (ret & THERMAL_PROTECTION_STAGE_3) > + dev_info(dev, > + "[Thermal IRQ]: Thermal protection stage 3 interrupt triggered\n"); > +} > + > +static irqreturn_t irq_handler(int irq, void *dev_id) > +{ > + struct lvts_data *lvts_data = (struct lvts_data *)dev_id; > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + unsigned int i, *irq_bitmap; > + void __iomem *base; > + > + irq_bitmap = kcalloc(lvts_data->num_domain, sizeof(*irq_bitmap), GFP_ATOMIC); > + > + if (!irq_bitmap) > + return IRQ_NONE; > + > + for (i = 0; i < lvts_data->num_domain; i++) { > + base = lvts_data->domain[i].base; > + irq_bitmap[i] = readl(THERMINTST + base); > + dev_info(dev, "%s : THERMINTST = 0x%x\n", __func__, irq_bitmap[i]); > + } > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + if ((irq_bitmap[tc[i].domain_index] & tc[i].irq_bit) == 0) > + tc_irq_handler(lvts_data, i); > + } > + > + kfree(irq_bitmap); > + > + return IRQ_HANDLED; > +} > + > +static int lvts_register_irq_handler(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int i; > + int ret; > + > + for (i = 0; i < lvts_data->num_domain; i++) { > + ret = devm_request_irq(dev, lvts_data->domain[i].irq_num, irq_handler, > + IRQF_TRIGGER_HIGH, "mtk_lvts", lvts_data); > + > + if (ret) { > + dev_err(dev, "Failed to register LVTS IRQ, ret %d, domain %d irq_num %d\n", > + ret, i, lvts_data->domain[i].irq_num); > + lvts_close(lvts_data); > + return ret; > + } > + } > + > + return 0; > +} > + > +static int lvts_register_thermal_zones(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + struct thermal_zone_device *tzdev; > + struct soc_temp_tz *lvts_tz; > + int i, ret; > + > + for (i = 0; i < lvts_data->num_sensor + 1; i++) { > + lvts_tz = devm_kzalloc(dev, sizeof(*lvts_tz), GFP_KERNEL); > + if (!lvts_tz) { > + lvts_close(lvts_data); > + return -ENOMEM; > + } > + > + lvts_tz->id = i; > + lvts_tz->lvts_data = lvts_data; > + > + tzdev = devm_thermal_zone_of_sensor_register(dev, lvts_tz->id, > + lvts_tz, &soc_temp_lvts_ops); > + > + if (IS_ERR(tzdev)) { > + if (lvts_tz->id != 0) > + return 0; > + > + ret = PTR_ERR(tzdev); > + dev_err(dev, "Error: Failed to register lvts tz %d, ret = %d\n", > + lvts_tz->id, ret); > + lvts_close(lvts_data); > + return ret; > + } > + } > + > + return 0; > +} > + > +static int lvts_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct lvts_data *lvts_data; > + int ret; > + > + lvts_data = (struct lvts_data *)of_device_get_match_data(dev); > + > + if (!lvts_data) { > + dev_err(dev, "Error: Failed to get lvts platform data\n"); > + return -ENODATA; > + } > + > + lvts_data->dev = &pdev->dev; > + > + ret = of_update_lvts_data(lvts_data, pdev); > + if (ret) > + return ret; > + > + platform_set_drvdata(pdev, lvts_data); > + > + ret = lvts_init(lvts_data); > + if (ret) > + return ret; > + > + ret = lvts_register_irq_handler(lvts_data); > + if (ret) > + return ret; > + > + ret = lvts_register_thermal_zones(lvts_data); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static int lvts_remove(struct platform_device *pdev) > +{ > + struct lvts_data *lvts_data; > + > + lvts_data = (struct lvts_data *)platform_get_drvdata(pdev); > + > + lvts_close(lvts_data); > + > + return 0; > +} > + > +static int lvts_suspend(struct platform_device *pdev, pm_message_t state) > +{ > + struct lvts_data *lvts_data; > + > + lvts_data = (struct lvts_data *)platform_get_drvdata(pdev); > + > + lvts_close(lvts_data); > + > + return 0; > +} > + > +static int lvts_resume(struct platform_device *pdev) > +{ > + int ret; > + struct lvts_data *lvts_data; > + > + lvts_data = (struct lvts_data *)platform_get_drvdata(pdev); > + > + ret = lvts_init(lvts_data); > + if (ret) > + return ret; > + > + return 0; > +} > + > +/*================================================== > + * LVTS v4 common code > + *================================================== > + */ > +static void device_enable_and_init_v4(struct lvts_data *lvts_data) > +{ > + unsigned int i; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + lvts_write_device(lvts_data, STOP_COUNTING_V4, i); > + lvts_write_device(lvts_data, SET_RG_TSFM_LPDLY_V4, i); > + lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US1_V4, i); > + lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US2_V4, i); > + lvts_write_device(lvts_data, TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4, i); > + lvts_write_device(lvts_data, TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4, i); > + lvts_write_device(lvts_data, SET_TS_RSV_V4, i); > + lvts_write_device(lvts_data, SET_TS_EN_V4, i); > + lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST1_V4, i); > + lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST2_V4, i); > + } > + > + lvts_data->counting_window_us = 20; > +} > + > +static void device_enable_auto_rck_v4(struct lvts_data *lvts_data) > +{ > + unsigned int i; > + > + for (i = 0; i < lvts_data->num_tc; i++) > + lvts_write_device(lvts_data, SET_LVTS_AUTO_RCK_V4, i); > +} > + > +static int device_read_count_rc_n_v4(struct lvts_data *lvts_data) > +{ > + /* Resistor-Capacitor Calibration */ > + /* count_RC_N: count RC now */ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + struct sensor_cal_data *cal_data = &lvts_data->cal_data; > + unsigned int offset, size, s_index, data; > + void __iomem *base; > + int ret, i, j; > + char buffer[512]; > + > + cal_data->count_rc_now = devm_kcalloc(dev, lvts_data->num_sensor, > + sizeof(*cal_data->count_rc_now), GFP_KERNEL); > + if (!cal_data->count_rc_now) > + return -ENOMEM; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + for (j = 0; j < tc[i].num_sensor; j++) { > + s_index = tc[i].sensor_map[j]; > + > + lvts_write_device(lvts_data, SELECT_SENSOR_RCK_V4(j), i); > + lvts_write_device(lvts_data, SET_DEVICE_SINGLE_MODE_V4, i); > + usleep_range(10, 20); > + > + lvts_write_device(lvts_data, KICK_OFF_RCK_COUNTING_V4, i); > + usleep_range(30, 40); > + > + ret = readl_poll_timeout(LVTS_CONFIG_0 + base, data, > + !(data & DEVICE_SENSING_STATUS), 2, 200); > + if (ret) > + dev_err(dev, > + "Error: LVTS %d DEVICE_SENSING_STATUS didn't ready\n", i); > + > + data = lvts_read_device(lvts_data, 0x00, i); > + > + cal_data->count_rc_now[s_index] = (data & GENMASK(23, 0)); > + } > + > + /* Recover Setting for Normal Access on > + * temperature fetch > + */ > + lvts_write_device(lvts_data, SET_SENSOR_NO_RCK_V4, i); > + lvts_write_device(lvts_data, SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i); > + } > + > + size = sizeof(buffer); > + offset = snprintf(buffer, size, "[COUNT_RC_NOW] "); > + for (i = 0; i < lvts_data->num_sensor; i++) > + offset += snprintf(buffer + offset, size - offset, "%d:%d ", > + i, cal_data->count_rc_now[i]); > + > + buffer[offset] = '\0'; > + dev_info(dev, "%s\n", buffer); > + > + return 0; > +} > + > +static void set_calibration_data_v4(struct lvts_data *lvts_data) > +{ > + struct tc_settings *tc = lvts_data->tc; > + struct sensor_cal_data *cal_data = &lvts_data->cal_data; > + unsigned int i, j, s_index, e_data; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + > + for (j = 0; j < tc[i].num_sensor; j++) { > + s_index = tc[i].sensor_map[j]; > + if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK)) > + e_data = cal_data->count_r[s_index]; > + else > + e_data = (((unsigned long long) > + cal_data->count_rc_now[s_index]) * > + cal_data->count_r[s_index]) >> 14; > + > + writel(e_data, LVTSEDATA00_0 + base + 0x4 * j); > + } > + } > +} > + > +static void init_controller_v4(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int i; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + > + lvts_write_device(lvts_data, SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i); > + > + writel(SET_SENSOR_INDEX, LVTSTSSEL_0 + base); > + writel(SET_CALC_SCALE_RULES, LVTSCALSCALE_0 + base); > + > + set_polling_speed(lvts_data, i); > + set_hw_filter(lvts_data, i); > + > + dev_info(dev, "lvts%d: read all %d sensors in %d us, one in %d us\n", > + i, GET_TC_SENSOR_NUM(i), GROUP_LATENCY_US(i), SENSOR_LATENCY_US(i)); > + } > +} > + > +/*================================================== > + * LVTS MT6873 > + *================================================== > + */ > + > +#define MT6873_NUM_LVTS (ARRAY_SIZE(mt6873_tc_settings)) > + > +enum mt6873_lvts_domain { > + MT6873_AP_DOMAIN, > + MT6873_MCU_DOMAIN, > + MT6873_NUM_DOMAIN > +}; > + > +enum mt6873_lvts_sensor_enum { > + MT6873_TS1_0, > + MT6873_TS1_1, > + MT6873_TS2_0, > + MT6873_TS2_1, > + MT6873_TS3_0, > + MT6873_TS3_1, > + MT6873_TS3_2, > + MT6873_TS3_3, > + MT6873_TS4_0, > + MT6873_TS4_1, > + MT6873_TS5_0, > + MT6873_TS5_1, > + MT6873_TS6_0, > + MT6873_TS6_1, > + MT6873_TS7_0, > + MT6873_TS7_1, > + MT6873_TS7_2, > + MT6873_NUM_TS > +}; > + > +static void mt6873_efuse_to_cal_data(struct lvts_data *lvts_data) > +{ > + struct sensor_cal_data *cal_data = &lvts_data->cal_data; > + > + cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24); > + cal_data->count_r[MT6873_TS1_0] = GET_CAL_DATA_BITMASK(1, 23, 0); > + cal_data->count_r[MT6873_TS1_1] = GET_CAL_DATA_BITMASK(2, 23, 0); > + cal_data->count_r[MT6873_TS2_0] = GET_CAL_DATA_BITMASK(3, 23, 0); > + cal_data->count_r[MT6873_TS2_1] = GET_CAL_DATA_BITMASK(4, 23, 0); > + cal_data->count_r[MT6873_TS3_0] = GET_CAL_DATA_BITMASK(5, 23, 0); > + cal_data->count_r[MT6873_TS3_1] = GET_CAL_DATA_BITMASK(6, 23, 0); > + cal_data->count_r[MT6873_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0); > + cal_data->count_r[MT6873_TS3_3] = GET_CAL_DATA_BITMASK(8, 23, 0); > + cal_data->count_r[MT6873_TS4_0] = GET_CAL_DATA_BITMASK(9, 23, 0); > + cal_data->count_r[MT6873_TS4_1] = GET_CAL_DATA_BITMASK(10, 23, 0); > + cal_data->count_r[MT6873_TS5_0] = GET_CAL_DATA_BITMASK(11, 23, 0); > + cal_data->count_r[MT6873_TS5_1] = GET_CAL_DATA_BITMASK(12, 23, 0); > + cal_data->count_r[MT6873_TS6_0] = GET_CAL_DATA_BITMASK(13, 23, 0); > + cal_data->count_r[MT6873_TS6_1] = GET_CAL_DATA_BITMASK(14, 23, 0); > + cal_data->count_r[MT6873_TS7_0] = GET_CAL_DATA_BITMASK(15, 23, 0); > + cal_data->count_r[MT6873_TS7_1] = GET_CAL_DATA_BITMASK(16, 23, 0); > + cal_data->count_r[MT6873_TS7_2] = GET_CAL_DATA_BITMASK(17, 23, 0); > + > + cal_data->count_rc[MT6873_TS1_0] = GET_CAL_DATA_BITMASK(21, 23, 0); > + > + cal_data->count_rc[MT6873_TS2_0] = (GET_CAL_DATA_BITMASK(1, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(2, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(3, 31, 24); > + > + cal_data->count_rc[MT6873_TS3_0] = (GET_CAL_DATA_BITMASK(4, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(5, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(6, 31, 24); > + > + cal_data->count_rc[MT6873_TS4_0] = (GET_CAL_DATA_BITMASK(7, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(8, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(9, 31, 24); > + > + cal_data->count_rc[MT6873_TS5_0] = (GET_CAL_DATA_BITMASK(10, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(11, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(12, 31, 24); > + > + cal_data->count_rc[MT6873_TS6_0] = (GET_CAL_DATA_BITMASK(13, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(14, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(15, 31, 24); > + > + cal_data->count_rc[MT6873_TS7_0] = (GET_CAL_DATA_BITMASK(16, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(17, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(18, 31, 24); > +} > + > +static struct tc_settings mt6873_tc_settings[] = { > + [0] = { > + .domain_index = MT6873_MCU_DOMAIN, > + .addr_offset = 0x0, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS1_0, MT6873_TS1_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT1, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(3), > + }, > + [1] = { > + .domain_index = MT6873_MCU_DOMAIN, > + .addr_offset = 0x100, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS2_0, MT6873_TS2_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT0, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(4), > + }, > + [2] = { > + .domain_index = MT6873_MCU_DOMAIN, > + .addr_offset = 0x200, > + .num_sensor = 4, > + .sensor_map = {MT6873_TS3_0, MT6873_TS3_1, MT6873_TS3_2, MT6873_TS3_3}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT0, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(5), > + }, > + [3] = { > + .domain_index = MT6873_AP_DOMAIN, > + .addr_offset = 0x0, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS4_0, MT6873_TS4_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT0, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(3), > + }, > + [4] = { > + .domain_index = MT6873_AP_DOMAIN, > + .addr_offset = 0x100, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS5_0, MT6873_TS5_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT1, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(4), > + }, > + [5] = { > + .domain_index = MT6873_AP_DOMAIN, > + .addr_offset = 0x200, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS6_0, MT6873_TS6_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT1, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(5), > + }, > + [6] = { > + .domain_index = MT6873_AP_DOMAIN, > + .addr_offset = 0x300, > + .num_sensor = 3, > + .sensor_map = {MT6873_TS7_0, MT6873_TS7_1, MT6873_TS7_2}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT2, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(6), > + } > +}; > + > +static struct lvts_data mt6873_lvts_data = { > + .num_domain = MT6873_NUM_DOMAIN, > + .num_tc = MT6873_NUM_LVTS, > + .tc = mt6873_tc_settings, > + .num_sensor = MT6873_NUM_TS, > + .ops = { > + .efuse_to_cal_data = mt6873_efuse_to_cal_data, > + .device_enable_and_init = device_enable_and_init_v4, > + .device_enable_auto_rck = device_enable_auto_rck_v4, > + .device_read_count_rc_n = device_read_count_rc_n_v4, > + .set_cal_data = set_calibration_data_v4, > + .init_controller = init_controller_v4, > + }, > + .feature_bitmap = FEATURE_DEVICE_AUTO_RCK, > + .num_efuse_addr = 22, > + .num_efuse_block = 1, > + .cal_data = { > + .default_golden_temp = 50, > + .default_count_r = 35000, > + .default_count_rc = 2750, > + }, > + .coeff = { > + .a = -250460, > + .b = 250460, > + }, > +}; > + > +/*================================================== > + *================================================== > + * Support chips > + *================================================== > + */ > +static const struct of_device_id lvts_of_match[] = { > + { > + .compatible = "mediatek,mt6873-lvts", > + .data = (void *)&mt6873_lvts_data, > + }, > + { > + }, > +}; > +MODULE_DEVICE_TABLE(of, lvts_of_match); > +/*==================================================*/ > +static struct platform_driver soc_temp_lvts = { > + .probe = lvts_probe, > + .remove = lvts_remove, > + .suspend = lvts_suspend, > + .resume = lvts_resume, > + .driver = { > + .name = "mtk-soc-temp-lvts", > + .of_match_table = lvts_of_match, > + }, > +}; > + > +module_platform_driver(soc_temp_lvts); > +MODULE_AUTHOR("Yu-Chia Chang "); > +MODULE_AUTHOR("Michael Kao "); > +MODULE_DESCRIPTION("Mediatek soc temperature driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/thermal/mediatek/soc_temp_lvts.h b/drivers/thermal/mediatek/soc_temp_lvts.h > new file mode 100644 > index 000000000000..1d90bdec53c6 > --- /dev/null > +++ b/drivers/thermal/mediatek/soc_temp_lvts.h > @@ -0,0 +1,312 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (c) 2020 MediaTek Inc. > + */ > + > +#ifndef __MTK_SOC_TEMP_LVTS_H__ > +#define __MTK_SOC_TEMP_LVTS_H__ > + > +/* LVTS HW filter settings > + * 000: Get one sample > + * 001: Get 2 samples and average them > + * 010: Get 4 samples, drop max and min, then average the rest of 2 samples > + * 011: Get 6 samples, drop max and min, then average the rest of 4 samples > + * 100: Get 10 samples, drop max and min, then average the rest of 8 samples > + * 101: Get 18 samples, drop max and min, then average the rest of 16 samples > + */ > +enum lvts_hw_filter { > + LVTS_FILTER_1, > + LVTS_FILTER_2, > + LVTS_FILTER_2_OF_4, > + LVTS_FILTER_4_OF_6, > + LVTS_FILTER_8_OF_10, > + LVTS_FILTER_16_OF_18 > +}; > + > +enum lvts_sensing_point { > + SENSING_POINT0, > + SENSING_POINT1, > + SENSING_POINT2, > + SENSING_POINT3, > + ALL_SENSING_POINTS > +}; > + > +/*================================================== > + * Data structure > + *================================================== > + */ > +struct lvts_data; > + > +struct speed_settings { > + unsigned int period_unit; > + unsigned int group_interval_delay; > + unsigned int filter_interval_delay; > + unsigned int sensor_interval_delay; > +}; > + > +struct tc_settings { > + unsigned int domain_index; > + unsigned int addr_offset; > + unsigned int num_sensor; > + unsigned int sensor_map[ALL_SENSING_POINTS]; /* In sensor ID */ > + struct speed_settings tc_speed; > + /* HW filter setting > + * 000: Get one sample > + * 001: Get 2 samples and average them > + * 010: Get 4 samples, drop max and min, then average the rest of 2 samples > + * 011: Get 6 samples, drop max and min, then average the rest of 4 samples > + * 100: Get 10 samples, drop max and min, then average the rest of 8 samples > + * 101: Get 18 samples, drop max and min, then average the rest of 16 samples > + */ > + unsigned int hw_filter; > + /* Dominator_sensing point is used to select a sensing point > + * and reference its temperature to trigger Thermal HW Reboot > + * When it is ALL_SENSING_POINTS, it will select all sensing points > + */ > + int dominator_sensing_point; > + int hw_reboot_trip_point; /* -274000: Disable HW reboot */ > + unsigned int irq_bit; > +}; > + > +struct formula_coeff { > + int a; > + int b; > + unsigned int golden_temp; > +}; > + > +struct sensor_cal_data { > + int use_fake_efuse; /* 1: Use fake efuse, 0: Use real efuse */ > + unsigned int golden_temp; > + unsigned int *count_r; > + unsigned int *count_rc; > + unsigned int *count_rc_now; > + > + unsigned int default_golden_temp; > + unsigned int default_count_r; > + unsigned int default_count_rc; > +}; > + > +struct platform_ops { > + void (*efuse_to_cal_data)(struct lvts_data *lvts_data); > + void (*device_enable_and_init)(struct lvts_data *lvts_data); > + void (*device_enable_auto_rck)(struct lvts_data *lvts_data); > + int (*device_read_count_rc_n)(struct lvts_data *lvts_data); > + void (*set_cal_data)(struct lvts_data *lvts_data); > + void (*init_controller)(struct lvts_data *lvts_data); > +}; > + > +struct power_domain { > + void __iomem *base; /* LVTS base addresses */ > + unsigned int irq_num; /* LVTS interrupt numbers */ > + struct reset_control *reset; > +}; > + > +struct sensor_data { > + int temp; /* Current temperature */ > + unsigned int msr_raw; /* MSR raw data from LVTS */ > +}; > + > +struct lvts_data { > + struct device *dev; > + struct clk *clk; > + unsigned int num_domain; > + struct power_domain *domain; > + > + int num_tc; /* Number of LVTS thermal controllers */ > + struct tc_settings *tc; > + int counting_window_us; /* LVTS device counting window */ > + > + int num_sensor; /* Number of sensors in this platform */ > + struct sensor_data *sen_data; > + > + struct platform_ops ops; > + int feature_bitmap; /* Show what features are enabled */ > + > + unsigned int num_efuse_addr; > + unsigned int *efuse; > + unsigned int num_efuse_block; /* Number of contiguous efuse indexes */ > + struct sensor_cal_data cal_data; > + struct formula_coeff coeff; > +}; > + > +struct soc_temp_tz { > + unsigned int id; /* if id is 0, get max temperature of all sensors */ > + struct lvts_data *lvts_data; > +}; > + > +struct match_entry { > + char chip[32]; > + struct lvts_data *lvts_data; > +}; > + > +struct lvts_match_data { > + unsigned int hw_version; > + struct match_entry *table; > + void (*set_up_common_callbacks)(struct lvts_data *lvts_data); > + struct list_head node; > +}; > + > +struct lvts_id { > + unsigned int hw_version; > + char chip[32]; > +}; > + > +/*================================================== > + * LVTS device register > + *================================================== > + */ > +#define RG_TSFM_DATA_0 0x00 > +#define RG_TSFM_DATA_1 0x01 > +#define RG_TSFM_DATA_2 0x02 > +#define RG_TSFM_CTRL_0 0x03 > +#define RG_TSFM_CTRL_1 0x04 > +#define RG_TSFM_CTRL_2 0x05 > +#define RG_TSFM_CTRL_3 0x06 > +#define RG_TSFM_CTRL_4 0x07 > +#define RG_TSV2F_CTRL_0 0x08 > +#define RG_TSV2F_CTRL_1 0x09 > +#define RG_TSV2F_CTRL_2 0x0A > +#define RG_TSV2F_CTRL_3 0x0B > +#define RG_TSV2F_CTRL_4 0x0C > +#define RG_TSV2F_CTRL_5 0x0D > +#define RG_TSV2F_CTRL_6 0x0E > +#define RG_TEMP_DATA_0 0x10 > +#define RG_TEMP_DATA_1 0x11 > +#define RG_TEMP_DATA_2 0x12 > +#define RG_TEMP_DATA_3 0x13 > +#define RG_RC_DATA_0 0x14 > +#define RG_RC_DATA_1 0x15 > +#define RG_RC_DATA_2 0x16 > +#define RG_RC_DATA_3 0x17 > +#define RG_DIV_DATA_0 0x18 > +#define RG_DIV_DATA_1 0x19 > +#define RG_DIV_DATA_2 0x1A > +#define RG_DIV_DATA_3 0x1B > +#define RG_TST_DATA_0 0x70 > +#define RG_TST_DATA_1 0x71 > +#define RG_TST_DATA_2 0x72 > +#define RG_TST_CTRL 0x73 > +#define RG_DBG_FQMTR 0xF0 > +#define RG_DBG_LPSEQ 0xF1 > +#define RG_DBG_STATE 0xF2 > +#define RG_DBG_CHKSUM 0xF3 > +#define RG_DID_LVTS 0xFC > +#define RG_DID_REV 0xFD > +#define RG_TSFM_RST 0xFF > +/*================================================== > + * LVTS controller register > + *================================================== > + */ > +#define LVTSMONCTL0_0 0x000 > +#define LVTS_SINGLE_SENSE BIT(9) > +#define ENABLE_SENSING_POINT(num) (LVTS_SINGLE_SENSE | GENMASK(((num) - 1), 0)) > +#define DISABLE_SENSING_POINT (LVTS_SINGLE_SENSE | 0x0) > +#define LVTSMONCTL1_0 0x004 > +#define LVTSMONCTL2_0 0x008 > +#define LVTSMONINT_0 0x00C > +#define STAGE3_INT_EN BIT(31) > +#define LVTSMONINTSTS_0 0x010 > +#define LVTSMONIDET0_0 0x014 > +#define LVTSMONIDET1_0 0x018 > +#define LVTSMONIDET2_0 0x01C > +#define LVTSMONIDET3_0 0x020 > +#define LVTSH2NTHRE_0 0x024 > +#define LVTSHTHRE_0 0x028 > +#define LVTSCTHRE_0 0x02C > +#define LVTSOFFSETH_0 0x030 > +#define LVTSOFFSETL_0 0x034 > +#define LVTSMSRCTL0_0 0x038 > +#define LVTSMSRCTL1_0 0x03C > +#define LVTSTSSEL_0 0x040 > +#define SET_SENSOR_INDEX 0x13121110 > +#define LVTSDEVICETO_0 0x044 > +#define LVTSCALSCALE_0 0x048 > +#define SET_CALC_SCALE_RULES 0x00000300 > +#define LVTS_ID_0 0x04C > +#define LVTS_CONFIG_0 0x050 > + > +#define BROADCAST_ID_UPDATE BIT(26) > +#define DEVICE_SENSING_STATUS BIT(25) > +#define DEVICE_ACCESS_STARTUS BIT(24) > +#define WRITE_ACCESS BIT(16) > +#define DEVICE_WRITE (BIT(31) | CK26M_ACTIVE | DEVICE_ACCESS_STARTUS \ > + | BIT(17) | WRITE_ACCESS) > +#define DEVICE_READ (BIT(31) | CK26M_ACTIVE | DEVICE_ACCESS_STARTUS \ > + | 1 << 17) > +#define RESET_ALL_DEVICES (DEVICE_WRITE | RG_TSFM_RST << 8 | 0xFF) > +#define READ_BACK_DEVICE_ID (BIT(31) | CK26M_ACTIVE | BROADCAST_ID_UPDATE \ > + | DEVICE_ACCESS_STARTUS | BIT(17) \ > + | RG_DID_LVTS << 8) > +#define READ_DEVICE_REG(reg_idx) (DEVICE_READ | (reg_idx) << 8 | 0x00) > +#define LVTSEDATA00_0 0x054 > +#define LVTSEDATA01_0 0x058 > +#define LVTSEDATA02_0 0x05C > +#define LVTSEDATA03_0 0x060 > +#define LVTSMSR0_0 0x090 > +#define MRS_RAW_MASK GENMASK(15, 0) > +#define MRS_RAW_VALID_BIT BIT(16) > +#define LVTSMSR1_0 0x094 > +#define LVTSMSR2_0 0x098 > +#define LVTSMSR3_0 0x09C > +#define LVTSIMMD0_0 0x0A0 > +#define LVTSIMMD1_0 0x0A4 > +#define LVTSIMMD2_0 0x0A8 > +#define LVTSIMMD3_0 0x0AC > +#define LVTSRDATA0_0 0x0B0 > +#define LVTSRDATA1_0 0x0B4 > +#define LVTSRDATA2_0 0x0B8 > +#define LVTSRDATA3_0 0x0BC > +#define LVTSPROTCTL_0 0x0C0 > +#define PROTOFFSET GENMASK(15, 0) > +#define LVTSPROTTA_0 0x0C4 > +#define LVTSPROTTB_0 0x0C8 > +#define LVTSPROTTC_0 0x0CC > +#define LVTSCLKEN_0 0x0E4 > +#define ENABLE_LVTS_CTRL_CLK (1) > +#define DISABLE_LVTS_CTRL_CLK (0) > +#define LVTSDBGSEL_0 0x0E8 > +#define LVTSDBGSIG_0 0x0EC > +#define LVTSSPARE0_0 0x0F0 > +#define LVTSSPARE1_0 0x0F4 > +#define LVTSSPARE2_0 0x0F8 > +#define LVTSSPARE3_0 0x0FC > + > +#define THERMINTST 0xF04 > +/*================================================== > + * LVTS register mask > + *================================================== > + */ > +#define THERMAL_COLD_INTERRUPT_0 0x00000001 > +#define THERMAL_HOT_INTERRUPT_0 0x00000002 > +#define THERMAL_LOW_OFFSET_INTERRUPT_0 0x00000004 > +#define THERMAL_HIGH_OFFSET_INTERRUPT_0 0x00000008 > +#define THERMAL_HOT2NORMAL_INTERRUPT_0 0x00000010 > +#define THERMAL_COLD_INTERRUPT_1 0x00000020 > +#define THERMAL_HOT_INTERRUPT_1 0x00000040 > +#define THERMAL_LOW_OFFSET_INTERRUPT_1 0x00000080 > +#define THERMAL_HIGH_OFFSET_INTERRUPT_1 0x00000100 > +#define THERMAL_HOT2NORMAL_INTERRUPT_1 0x00000200 > +#define THERMAL_COLD_INTERRUPT_2 0x00000400 > +#define THERMAL_HOT_INTERRUPT_2 0x00000800 > +#define THERMAL_LOW_OFFSET_INTERRUPT_2 0x00001000 > +#define THERMAL_HIGH_OFFSET_INTERRUPT_2 0x00002000 > +#define THERMAL_HOT2NORMAL_INTERRUPT_2 0x00004000 > +#define THERMAL_AHB_TIMEOUT_INTERRUPT 0x00008000 > +#define THERMAL_DEVICE_TIMEOUT_INTERRUPT 0x00008000 > +#define THERMAL_IMMEDIATE_INTERRUPT_0 0x00010000 > +#define THERMAL_IMMEDIATE_INTERRUPT_1 0x00020000 > +#define THERMAL_IMMEDIATE_INTERRUPT_2 0x00040000 > +#define THERMAL_FILTER_INTERRUPT_0 0x00080000 > +#define THERMAL_FILTER_INTERRUPT_1 0x00100000 > +#define THERMAL_FILTER_INTERRUPT_2 0x00200000 > +#define THERMAL_COLD_INTERRUPT_3 0x00400000 > +#define THERMAL_HOT_INTERRUPT_3 0x00800000 > +#define THERMAL_LOW_OFFSET_INTERRUPT_3 0x01000000 > +#define THERMAL_HIGH_OFFSET_INTERRUPT_3 0x02000000 > +#define THERMAL_HOT2NORMAL_INTERRUPT_3 0x04000000 > +#define THERMAL_IMMEDIATE_INTERRUPT_3 0x08000000 > +#define THERMAL_FILTER_INTERRUPT_3 0x10000000 > +#define THERMAL_PROTECTION_STAGE_1 0x20000000 > +#define THERMAL_PROTECTION_STAGE_2 0x40000000 > +#define THERMAL_PROTECTION_STAGE_3 0x80000000 > +#endif /* __MTK_SOC_TEMP_LVTS_H__ */ _______________________________________________ Linux-mediatek mailing list Linux-mediatek@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-mediatek From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E67D4C433ED for ; Wed, 7 Apr 2021 09:13:24 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 096AE610D0 for ; Wed, 7 Apr 2021 09:13:24 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 096AE610D0 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Date:CC:To:From: Subject:Message-ID:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=H/FL9uHnVQT5SsZs5tHnVeaS0bUTBkpMVdS/5nIzTIw=; b=CitGEkzoCDXaF2YhMLZJJzsvn /l19+EDW+rkxY8joIqtOliAHGseTuljTGVylQ+bg/6XHMoqJ+VH2j63wmgUXb635PGauIWrG0H06t vDedQ3noAIMFrBA2sywqvAuO4eWl0lmLtpMKN/u47YgBRTqIWClPuHCBQqOXe6sb9IgS6bB5qXyFK KC+I9qUcqk3asTOFor8Wn399uSEFwM8/SqBkb0qL5vyBJdnS+UK8OWzSnoHa7nzpkuMsfm5wedlFd FYkmKLlYEmVYx6sKCb3iYYAIw9oo+7nfAMcYR0aCJE0tFE2hYCwLjUlBP+zVADs33jVsRo7EaPSqn lbBe5bzfA==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lU4D6-004Ynb-Bn; Wed, 07 Apr 2021 09:10:52 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lU4Bd-004YXg-7S; Wed, 07 Apr 2021 09:09:33 +0000 X-UUID: d14ff8e6388f4133a0a92e76c637196e-20210407 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=grOFFUtINhKpc8Th5j1GB5zb0oqVfOdvcKO8OHgRSbc=; b=QUzWQ/gTAAH9McK3Dw0ycCodpuQwLsbAzrWZjsDGvOLrX1tgZ/HaPig3mZH1cFAWvwajdw5ZbHG46faj8GmoSJeI6Jar6+ViDJaBAxSUgXKY7ozlJ4dkqSqDpGtnlaXYXjVCYObpup2x04bFQBZl2yw8CVvmqTxW295Vy9+jR7s=; X-UUID: d14ff8e6388f4133a0a92e76c637196e-20210407 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1058292320; Wed, 07 Apr 2021 02:09:10 -0700 Received: from MTKMBS07N2.mediatek.inc (172.21.101.141) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 7 Apr 2021 02:09:08 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 7 Apr 2021 17:09:06 +0800 Received: from [172.21.84.99] (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 7 Apr 2021 17:09:06 +0800 Message-ID: <1617786546.12846.2.camel@mtksdccf07> Subject: Re: [v3,2/3] thermal: mediatek: Add LVTS drivers for SoC theraml zones From: Michael Kao To: Zhang Rui , Daniel Lezcano CC: , , "Eduardo Valentin" , Rob Herring , "Mark Rutland" , Matthias Brugger , , , , , Date: Wed, 7 Apr 2021 17:09:06 +0800 In-Reply-To: <20210312034018.17437-3-michael.kao@mediatek.com> References: <20210312034018.17437-1-michael.kao@mediatek.com> <20210312034018.17437-3-michael.kao@mediatek.com> X-Mailer: Evolution 3.2.3-0ubuntu6 MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210407_100923_643820_7843B95A X-CRM114-Status: GOOD ( 28.80 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Hi Maintainers, Gentle pin for this patch. Thanks On Fri, 2021-03-12 at 11:40 +0800, Michael Kao wrote: > Add a LVTS (Low voltage thermal sensor) driver to report junction > temperatures in Mediatek SoC and register the maximum temperature > of sensors and each sensor as a thermal zone. > > Signed-off-by: Yu-Chia Chang > Signed-off-by: Michael Kao > --- > drivers/thermal/mediatek/Kconfig | 10 + > drivers/thermal/mediatek/Makefile | 1 + > drivers/thermal/mediatek/soc_temp_lvts.c | 1287 ++++++++++++++++++++++ > drivers/thermal/mediatek/soc_temp_lvts.h | 312 ++++++ > 4 files changed, 1610 insertions(+) > create mode 100644 drivers/thermal/mediatek/soc_temp_lvts.c > create mode 100644 drivers/thermal/mediatek/soc_temp_lvts.h > > diff --git a/drivers/thermal/mediatek/Kconfig b/drivers/thermal/mediatek/Kconfig > index 0351e73170b7..d716d0372e1e 100644 > --- a/drivers/thermal/mediatek/Kconfig > +++ b/drivers/thermal/mediatek/Kconfig > @@ -20,4 +20,14 @@ config MTK_SOC_THERMAL > configures thermal controllers to collect temperature > via AUXADC interface. > > +config MTK_SOC_THERMAL_LVTS > + tristate "LVTS (Low voltage thermal sensor) driver for Mediatek SoCs" > + depends on HAS_IOMEM > + depends on NVMEM > + depends on RESET_TI_SYSCON > + help > + Enable this option if you want to get SoC temperature > + information for Mediatek platforms. This driver > + configures LVTS thermal controllers to collect temperatures > + via Analog Serial Interface(ASIF). > endif > diff --git a/drivers/thermal/mediatek/Makefile b/drivers/thermal/mediatek/Makefile > index f75313ddce5e..16ce166e5916 100644 > --- a/drivers/thermal/mediatek/Makefile > +++ b/drivers/thermal/mediatek/Makefile > @@ -1 +1,2 @@ > obj-$(CONFIG_MTK_SOC_THERMAL) += soc_temp.o > +obj-$(CONFIG_MTK_SOC_THERMAL_LVTS) += soc_temp_lvts.o > diff --git a/drivers/thermal/mediatek/soc_temp_lvts.c b/drivers/thermal/mediatek/soc_temp_lvts.c > new file mode 100644 > index 000000000000..8153edaaf815 > --- /dev/null > +++ b/drivers/thermal/mediatek/soc_temp_lvts.c > @@ -0,0 +1,1287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 MediaTek Inc. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "soc_temp_lvts.h" > + > +/*================================================== > + * Definition or macro function > + *================================================== > + */ > +#define STOP_COUNTING_V4 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00) > +#define SET_RG_TSFM_LPDLY_V4 (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6) > +#define SET_COUNTING_WINDOW_20US1_V4 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00) > +#define SET_COUNTING_WINDOW_20US2_V4 (DEVICE_WRITE | RG_TSFM_CTRL_1 << 8 | 0x20) > +#define TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_2 << 8 | 0x84) > +#define TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_4 << 8 | 0x7C) > +#define SET_TS_RSV_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_1 << 8 | 0x8D) > +#define SET_TS_EN_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4) > +#define TOGGLE_RG_TSV2F_VCO_RST1_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xFC) > +#define TOGGLE_RG_TSV2F_VCO_RST2_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4) > + > +#define SET_LVTS_AUTO_RCK_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_6 << 8 | 0x01) > +#define SELECT_SENSOR_RCK_V4(id) (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | (id)) > +#define SET_DEVICE_SINGLE_MODE_V4 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0x78) > +#define KICK_OFF_RCK_COUNTING_V4 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x02) > +#define SET_SENSOR_NO_RCK_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | 0x10) > +#define SET_DEVICE_LOW_POWER_SINGLE_MODE_V4 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8) > + > +#define ENABLE_FEATURE(feature) (lvts_data->feature_bitmap |= (feature)) > +#define DISABLE_FEATURE(feature) (lvts_data->feature_bitmap &= (~(feature))) > +#define IS_ENABLE(feature) (lvts_data->feature_bitmap & (feature)) > + > +#define DISABLE_THERMAL_HW_REBOOT (-274000) > + > +#define CLOCK_26MHZ_CYCLE_NS (38) > +#define BUS_ACCESS_US (2) > + > +#define FEATURE_DEVICE_AUTO_RCK (BIT(0)) > +#define FEATURE_CK26M_ACTIVE (BIT(1)) > +#define CK26M_ACTIVE (((lvts_data->feature_bitmap & FEATURE_CK26M_ACTIVE) \ > + ? 1 : 0) << 30) > +#define GET_BASE_ADDR(tc_id) \ > + (lvts_data->domain[lvts_data->tc[tc_id].domain_index].base \ > + + lvts_data->tc[tc_id].addr_offset) > + > +#define SET_TC_SPEED_IN_US(pu, gd, fd, sd) \ > + { \ > + .period_unit = (((pu) * 1000) / (256 * CLOCK_26MHZ_CYCLE_NS)), \ > + .group_interval_delay = ((gd) / (pu)), \ > + .filter_interval_delay = ((fd) / (pu)), \ > + .sensor_interval_delay = ((sd) / (pu)), \ > + } > + > +#define GET_CAL_DATA_BITMASK(index, h, l) \ > + (((index) < lvts_data->num_efuse_addr) \ > + ? ((lvts_data->efuse[(index)] & GENMASK(h, l)) >> l) \ > + : 0) > + > +#define GET_CAL_DATA_BIT(index, bit) \ > + (((index) < lvts_data->num_efuse_addr) \ > + ? ((lvts_data->efuse[index] & BIT(bit)) >> (bit)) \ > + : 0) > + > +#define GET_TC_SENSOR_NUM(tc_id) \ > + (lvts_data->tc[tc_id].num_sensor) > + > +#define ONE_SAMPLE (lvts_data->counting_window_us + 2 * BUS_ACCESS_US) > + > +#define NUM_OF_SAMPLE(tc_id) \ > + ((lvts_data->tc[tc_id].hw_filter < LVTS_FILTER_2) ? 1 : \ > + ((lvts_data->tc[tc_id].hw_filter > LVTS_FILTER_16_OF_18) ? 1 : \ > + ((lvts_data->tc[tc_id].hw_filter == LVTS_FILTER_16_OF_18) ? 18 :\ > + ((lvts_data->tc[tc_id].hw_filter == LVTS_FILTER_8_OF_10) ? 10 : \ > + (lvts_data->tc[tc_id].hw_filter * 2))))) > + > +#define PERIOD_UNIT_US(tc_id) \ > + ((lvts_data->tc[tc_id].tc_speed.period_unit * 256 * \ > + CLOCK_26MHZ_CYCLE_NS) / 1000) > +#define FILTER_INT_US(tc_id) \ > + (lvts_data->tc[tc_id].tc_speed.filter_interval_delay \ > + * PERIOD_UNIT_US(tc_id)) > +#define SENSOR_INT_US(tc_id) \ > + (lvts_data->tc[tc_id].tc_speed.sensor_interval_delay \ > + * PERIOD_UNIT_US(tc_id)) > +#define GROUP_INT_US(tc_id) \ > + (lvts_data->tc[tc_id].tc_speed.group_interval_delay \ > + * PERIOD_UNIT_US(tc_id)) > + > +#define SENSOR_LATENCY_US(tc_id) \ > + ((NUM_OF_SAMPLE(tc_id) - 1) * FILTER_INT_US(tc_id) \ > + + NUM_OF_SAMPLE(tc_id) * ONE_SAMPLE) > + > +#define GROUP_LATENCY_US(tc_id) \ > + (GET_TC_SENSOR_NUM(tc_id) * SENSOR_LATENCY_US(tc_id) \ > + + (GET_TC_SENSOR_NUM(tc_id) - 1) * SENSOR_INT_US(tc_id) \ > + + GROUP_INT_US(tc_id)) > + > +/*================================================== > + * LVTS local common code > + *================================================== > + */ > +static int lvts_raw_to_temp(struct formula_coeff *co, unsigned int msr_raw) > +{ > + /* This function returns degree mC */ > + > + int temp; > + > + temp = (co->a * ((unsigned long long)msr_raw)) >> 14; > + temp = temp + co->golden_temp * 500 + co->b; > + > + return temp; > +} > + > +static unsigned int lvts_temp_to_raw(struct formula_coeff *co, int temp) > +{ > + unsigned int msr_raw; > + > + msr_raw = div_s64((s64)((co->golden_temp * 500 + co->b - temp)) << 14, > + (-1 * co->a)); > + > + return msr_raw; > +} > + > +static int lvts_read_all_tc_temperature(struct lvts_data *lvts_data) > +{ > + struct tc_settings *tc = lvts_data->tc; > + unsigned int i, j, s_index, msr_raw; > + int max_temp = 0, current_temp; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + for (j = 0; j < tc[i].num_sensor; j++) { > + s_index = tc[i].sensor_map[j]; > + > + msr_raw = readl(LVTSMSR0_0 + base + 0x4 * j) & MRS_RAW_MASK; > + current_temp = lvts_raw_to_temp(&lvts_data->coeff, msr_raw); > + > + if (msr_raw == 0) > + current_temp = THERMAL_TEMP_INVALID; > + > + max_temp = max(max_temp, current_temp); > + > + lvts_data->sen_data[s_index].msr_raw = msr_raw; > + lvts_data->sen_data[s_index].temp = current_temp; > + } > + } > + > + return max_temp; > +} > + > +static int soc_temp_lvts_read_temp(void *data, int *temperature) > +{ > + struct soc_temp_tz *lvts_tz = (struct soc_temp_tz *)data; > + struct lvts_data *lvts_data = lvts_tz->lvts_data; > + > + if (lvts_tz->id == 0) > + *temperature = lvts_read_all_tc_temperature(lvts_data); > + else if (lvts_tz->id - 1 < lvts_data->num_sensor) > + *temperature = lvts_data->sen_data[lvts_tz->id - 1].temp; > + else > + return -EINVAL; > + > + return 0; > +} > + > +static const struct thermal_zone_of_device_ops soc_temp_lvts_ops = { > + .get_temp = soc_temp_lvts_read_temp, > +}; > + > +static void lvts_write_device(struct lvts_data *lvts_data, unsigned int data, > + int tc_id) > +{ > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + writel(data, LVTS_CONFIG_0 + base); > + > + usleep_range(5, 15); > +} > + > +static unsigned int lvts_read_device(struct lvts_data *lvts_data, > + unsigned int reg_idx, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + void __iomem *base; > + unsigned int data; > + int ret; > + > + base = GET_BASE_ADDR(tc_id); > + writel(READ_DEVICE_REG(reg_idx), LVTS_CONFIG_0 + base); > + > + ret = readl_poll_timeout(LVTS_CONFIG_0 + base, data, > + !(data & DEVICE_ACCESS_STARTUS), > + 2, 200); > + if (ret) > + dev_err(dev, > + "Error: LVTS %d DEVICE_ACCESS_START didn't ready\n", tc_id); > + > + data = readl(LVTSRDATA0_0 + base); > + > + return data; > +} > + > +static void wait_all_tc_sensing_point_idle(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int mask, error_code, is_error; > + void __iomem *base; > + int i, cnt, ret; > + > + mask = BIT(10) | BIT(7) | BIT(0); > + > + for (cnt = 0; cnt < 2; cnt++) { > + is_error = 0; > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + ret = readl_poll_timeout(LVTSMSRCTL1_0 + base, error_code, > + !(error_code & mask), 2, 200); > + /* > + * Error code > + * 000: IDLE > + * 001: Write transaction > + * 010: Waiting for read after Write > + * 011: Disable Continue fetching on Device > + * 100: Read transaction > + * 101: Set Device special Register for Voltage threshold > + * 111: Set TSMCU number for Fetch > + */ > + error_code = ((error_code & BIT(10)) >> 8) + > + ((error_code & BIT(7)) >> 6) + > + (error_code & BIT(0)); > + > + if (ret) > + dev_err(dev, > + "Error LVTS %d sensing points aren't idle, error_code %d\n", > + i, error_code); > + > + if (error_code != 0) > + is_error = 1; > + } > + > + if (is_error == 0) > + break; > + } > +} > + > +static void lvts_reset(struct lvts_data *lvts_data) > +{ > + int i; > + > + for (i = 0; i < lvts_data->num_domain; i++) { > + if (lvts_data->domain[i].reset) > + reset_control_assert(lvts_data->domain[i].reset); > + > + if (lvts_data->domain[i].reset) > + reset_control_deassert(lvts_data->domain[i].reset); > + } > +} > + > +static void device_identification(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int i, data; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + > + writel(ENABLE_LVTS_CTRL_CLK, LVTSCLKEN_0 + base); > + > + lvts_write_device(lvts_data, RESET_ALL_DEVICES, i); > + > + lvts_write_device(lvts_data, READ_BACK_DEVICE_ID, i); > + > + /* Check LVTS device ID */ > + data = (readl(LVTS_ID_0 + base) & GENMASK(7, 0)); > + if (data != (0x81 + i)) > + dev_err(dev, "LVTS_TC_%d, Device ID should be 0x%x, but 0x%x\n", > + i, (0x81 + i), data); > + } > +} > + > +static void disable_all_sensing_points(struct lvts_data *lvts_data) > +{ > + unsigned int i; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + writel(DISABLE_SENSING_POINT, LVTSMONCTL0_0 + base); > + } > +} > + > +static void enable_all_sensing_points(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + unsigned int i, num; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + num = tc[i].num_sensor; > + > + if (num > ALL_SENSING_POINTS) { > + dev_err(dev, > + "%s, LVTS%d, illegal number of sensors: %d\n", > + __func__, i, tc[i].num_sensor); > + continue; > + } > + > + writel(ENABLE_SENSING_POINT(num), LVTSMONCTL0_0 + base); > + } > +} > + > +static void set_polling_speed(struct lvts_data *lvts_data, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + unsigned int lvts_mon_ctl_1, lvts_mon_ctl_2; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + lvts_mon_ctl_1 = ((tc[tc_id].tc_speed.group_interval_delay << 20) & GENMASK(29, 20)) | > + (tc[tc_id].tc_speed.period_unit & GENMASK(9, 0)); > + lvts_mon_ctl_2 = ((tc[tc_id].tc_speed.filter_interval_delay << 16) & GENMASK(25, 16)) | > + (tc[tc_id].tc_speed.sensor_interval_delay & GENMASK(9, 0)); > + /* > + * Clock source of LVTS thermal controller is 26MHz. > + * Period unit is a base for all interval delays > + * All interval delays must multiply it to convert a setting to time. > + * Filter interval delay is a delay between two samples of the same sensor > + * Sensor interval delay is a delay between two samples of differnet sensors > + * Group interval delay is a delay between different rounds. > + * For example: > + * If Period unit = C, filter delay = 1, sensor delay = 2, group delay = 1, > + * and two sensors, TS1 and TS2, are in a LVTS thermal controller > + * and then > + * Period unit = C * 1/26M * 256 = 12 * 38.46ns * 256 = 118.149us > + * Filter interval delay = 1 * Period unit = 118.149us > + * Sensor interval delay = 2 * Period unit = 236.298us > + * Group interval delay = 1 * Period unit = 118.149us > + * > + * TS1 TS1 ... TS1 TS2 TS2 ... TS2 TS1... > + * <--> Filter interval delay > + * <--> Sensor interval delay > + * <--> Group interval delay > + */ > + writel(lvts_mon_ctl_1, LVTSMONCTL1_0 + base); > + writel(lvts_mon_ctl_2, LVTSMONCTL2_0 + base); > + > + dev_info(dev, "%s %d, LVTSMONCTL1_0= 0x%x,LVTSMONCTL2_0= 0x%x\n", > + __func__, tc_id, readl(LVTSMONCTL1_0 + base), > + readl(LVTSMONCTL2_0 + base)); > +} > + > +static void set_hw_filter(struct lvts_data *lvts_data, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + unsigned int option; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + option = tc[tc_id].hw_filter & 0x7; > + /* hw filter > + * 000: Get one sample > + * 001: Get 2 samples and average them > + * 010: Get 4 samples, drop max and min, then average the rest of 2 samples > + * 011: Get 6 samples, drop max and min, then average the rest of 4 samples > + * 100: Get 10 samples, drop max and min, then average the rest of 8 samples > + * 101: Get 18 samples, drop max and min, then average the rest of 16 samples > + */ > + option = (option << 9) | (option << 6) | (option << 3) | option; > + > + writel(option, LVTSMSRCTL0_0 + base); > + dev_info(dev, "%s %d, LVTSMSRCTL0_0= 0x%x\n", > + __func__, tc_id, readl(LVTSMSRCTL0_0 + base)); > +} > + > +static int get_dominator_index(struct lvts_data *lvts_data, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + int d_index; > + > + if (tc[tc_id].dominator_sensing_point == ALL_SENSING_POINTS) { > + d_index = ALL_SENSING_POINTS; > + } else if (tc[tc_id].dominator_sensing_point < > + tc[tc_id].num_sensor){ > + d_index = tc[tc_id].dominator_sensing_point; > + } else { > + dev_err(dev, > + "Error: LVTS%d, dominator_sensing_point= %d should smaller than num_sensor= %d\n", > + tc_id, tc[tc_id].dominator_sensing_point, > + tc[tc_id].num_sensor); > + > + dev_err(dev, "Use the sensing point 0 as the dominated sensor\n"); > + d_index = SENSING_POINT0; > + } > + > + return d_index; > +} > + > +static void disable_hw_reboot_interrupt(struct lvts_data *lvts_data, int tc_id) > +{ > + unsigned int temp; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + /* LVTS thermal controller has two interrupts for thermal HW reboot > + * One is for AP SW and the other is for RGU > + * The interrupt of AP SW can turn off by a bit of a register, but > + * the other for RGU cannot. > + * To prevent rebooting device accidentally, we are going to add > + * a huge offset to LVTS and make LVTS always report extremely low > + * temperature. > + */ > + > + /* After adding the huge offset 0x3FFF, LVTS alawys adds the > + * offset to MSR_RAW. > + * When MSR_RAW is larger, SW will convert lower temperature/ > + */ > + temp = readl(LVTSPROTCTL_0 + base); > + writel(temp | 0x3FFF, LVTSPROTCTL_0 + base); > + > + /* Disable the interrupt of AP SW */ > + temp = readl(LVTSMONINT_0 + base); > + writel(temp & ~(STAGE3_INT_EN), LVTSMONINT_0 + base); > +} > + > +static void enable_hw_reboot_interrupt(struct lvts_data *lvts_data, int tc_id) > +{ > + unsigned int temp; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + /* Enable the interrupt of AP SW */ > + temp = readl(LVTSMONINT_0 + base); > + writel(temp | STAGE3_INT_EN, LVTSMONINT_0 + base); > + /* Clear the offset */ > + temp = readl(LVTSPROTCTL_0 + base); > + writel(temp & ~PROTOFFSET, LVTSPROTCTL_0 + base); > +} > + > +static void set_tc_hw_reboot_threshold(struct lvts_data *lvts_data, > + int trip_point, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int msr_raw, temp, config, d_index; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + d_index = get_dominator_index(lvts_data, tc_id); > + > + dev_info(dev, "%s: LVTS%d, the dominator sensing point= %d\n", > + __func__, tc_id, d_index); > + > + disable_hw_reboot_interrupt(lvts_data, tc_id); > + > + temp = readl(LVTSPROTCTL_0 + base); > + if (d_index == ALL_SENSING_POINTS) { > + /* Maximum of 4 sensing points */ > + config = (0x1 << 16); > + writel(config | temp, LVTSPROTCTL_0 + base); > + } else { > + /* Select protection sensor */ > + config = ((d_index << 2) + 0x2) << 16; > + writel(config | temp, LVTSPROTCTL_0 + base); > + } > + > + msr_raw = lvts_temp_to_raw(&lvts_data->coeff, trip_point); > + writel(msr_raw, LVTSPROTTC_0 + base); > + > + enable_hw_reboot_interrupt(lvts_data, tc_id); > +} > + > +static void set_all_tc_hw_reboot(struct lvts_data *lvts_data) > +{ > + struct tc_settings *tc = lvts_data->tc; > + int i, trip_point; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + trip_point = tc[i].hw_reboot_trip_point; > + > + if (tc[i].num_sensor == 0) > + continue; > + > + if (trip_point == DISABLE_THERMAL_HW_REBOOT) > + continue; > + > + set_tc_hw_reboot_threshold(lvts_data, trip_point, i); > + } > +} > + > +static int lvts_init(struct lvts_data *lvts_data) > +{ > + struct platform_ops *ops = &lvts_data->ops; > + struct device *dev = lvts_data->dev; > + int ret; > + > + ret = clk_prepare_enable(lvts_data->clk); > + if (ret) { > + dev_err(dev, > + "Error: Failed to enable lvts controller clock: %d\n", > + ret); > + return ret; > + } > + > + lvts_reset(lvts_data); > + > + device_identification(lvts_data); > + if (ops->device_enable_and_init) > + ops->device_enable_and_init(lvts_data); > + > + if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK)) { > + if (ops->device_enable_auto_rck) > + ops->device_enable_auto_rck(lvts_data); > + } else { > + if (ops->device_read_count_rc_n) > + ops->device_read_count_rc_n(lvts_data); > + } > + > + if (ops->set_cal_data) > + ops->set_cal_data(lvts_data); > + > + disable_all_sensing_points(lvts_data); > + wait_all_tc_sensing_point_idle(lvts_data); > + if (ops->init_controller) > + ops->init_controller(lvts_data); > + enable_all_sensing_points(lvts_data); > + > + set_all_tc_hw_reboot(lvts_data); > + > + return 0; > +} > + > +static int prepare_calibration_data(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + struct sensor_cal_data *cal_data = &lvts_data->cal_data; > + struct platform_ops *ops = &lvts_data->ops; > + int i, offset, size; > + char buffer[512]; > + > + cal_data->count_r = devm_kcalloc(dev, lvts_data->num_sensor, > + sizeof(*cal_data->count_r), GFP_KERNEL); > + if (!cal_data->count_r) > + return -ENOMEM; > + > + cal_data->count_rc = devm_kcalloc(dev, lvts_data->num_sensor, > + sizeof(*cal_data->count_rc), GFP_KERNEL); > + if (!cal_data->count_rc) > + return -ENOMEM; > + > + if (ops->efuse_to_cal_data) > + ops->efuse_to_cal_data(lvts_data); > + > + cal_data->use_fake_efuse = 1; > + if (cal_data->golden_temp != 0) { > + cal_data->use_fake_efuse = 0; > + } else { > + for (i = 0; i < lvts_data->num_sensor; i++) { > + if (cal_data->count_r[i] != 0 || > + cal_data->count_rc[i] != 0) { > + cal_data->use_fake_efuse = 0; > + break; > + } > + } > + } > + > + if (cal_data->use_fake_efuse) { > + /* It means all efuse data are equal to 0 */ > + dev_err(dev, > + "[lvts_cal] This sample is not calibrated, fake !!\n"); > + > + cal_data->golden_temp = cal_data->default_golden_temp; > + for (i = 0; i < lvts_data->num_sensor; i++) { > + cal_data->count_r[i] = cal_data->default_count_r; > + cal_data->count_rc[i] = cal_data->default_count_rc; > + } > + } > + > + lvts_data->coeff.golden_temp = cal_data->golden_temp; > + > + dev_info(dev, "[lvts_cal] golden_temp = %d\n", cal_data->golden_temp); > + > + size = sizeof(buffer); > + offset = snprintf(buffer, size, "[lvts_cal] num:g_count:g_count_rc "); > + for (i = 0; i < lvts_data->num_sensor; i++) > + offset += snprintf(buffer + offset, size - offset, "%d:%d:%d ", > + i, cal_data->count_r[i], cal_data->count_rc[i]); > + > + buffer[offset] = '\0'; > + dev_info(dev, "%s\n", buffer); > + > + return 0; > +} > + > +static int get_calibration_data(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + char cell_name[8]; > + struct nvmem_cell *cell; > + u32 *buf; > + size_t len; > + int i, j, index = 0, ret; > + > + lvts_data->efuse = devm_kcalloc(dev, lvts_data->num_efuse_addr, > + sizeof(*lvts_data->efuse), GFP_KERNEL); > + if (!lvts_data->efuse) > + return -ENOMEM; > + > + for (i = 0; i < lvts_data->num_efuse_block; i++) { > + snprintf(cell_name, sizeof(cell_name), "e_data%d", i + 1); > + cell = nvmem_cell_get(dev, cell_name); > + if (IS_ERR(cell)) { > + dev_err(dev, "Error: Failed to get nvmem cell %s\n", cell_name); > + return PTR_ERR(cell); > + } > + > + buf = (u32 *)nvmem_cell_read(cell, &len); > + nvmem_cell_put(cell); > + > + if (IS_ERR(buf)) > + return PTR_ERR(buf); > + > + for (j = 0; j < (len / sizeof(u32)); j++) { > + if (index >= lvts_data->num_efuse_addr) { > + dev_err(dev, "Array efuse is going to overflow"); > + kfree(buf); > + return -EINVAL; > + } > + > + lvts_data->efuse[index] = buf[j]; > + index++; > + } > + > + kfree(buf); > + } > + > + ret = prepare_calibration_data(lvts_data); > + > + return ret; > +} > + > +static int of_update_lvts_data(struct lvts_data *lvts_data, > + struct platform_device *pdev) > +{ > + struct device *dev = lvts_data->dev; > + struct power_domain *domain; > + struct resource *res; > + unsigned int i; > + int ret; > + > + lvts_data->clk = devm_clk_get(dev, "lvts_clk"); > + if (IS_ERR(lvts_data->clk)) > + return PTR_ERR(lvts_data->clk); > + > + domain = devm_kcalloc(dev, lvts_data->num_domain, sizeof(*domain), GFP_KERNEL); > + if (!domain) > + return -ENOMEM; > + > + for (i = 0; i < lvts_data->num_domain; i++) { > + /* Get base address */ > + res = platform_get_resource(pdev, IORESOURCE_MEM, i); > + if (!res) { > + dev_err(dev, "No IO resource, index %d\n", i); > + return -ENXIO; > + } > + > + domain[i].base = devm_ioremap_resource(dev, res); > + if (IS_ERR(domain[i].base)) { > + dev_err(dev, "Failed to remap io, index %d\n", i); > + return PTR_ERR(domain[i].base); > + } > + > + /* Get interrupt number */ > + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); > + if (!res) { > + dev_err(dev, "No irq resource, index %d\n", i); > + return -EINVAL; > + } > + domain[i].irq_num = res->start; > + > + /* Get reset control */ > + domain[i].reset = devm_reset_control_get_by_index(dev, i); > + if (IS_ERR(domain[i].reset)) { > + dev_err(dev, "Failed to get, index %d\n", i); > + return PTR_ERR(domain[i].reset); > + } > + } > + > + lvts_data->domain = domain; > + > + lvts_data->sen_data = devm_kcalloc(dev, lvts_data->num_sensor, > + sizeof(*lvts_data->sen_data), GFP_KERNEL); > + if (!lvts_data->sen_data) > + return -ENOMEM; > + > + ret = get_calibration_data(lvts_data); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static void lvts_device_close(struct lvts_data *lvts_data) > +{ > + unsigned int i; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + lvts_write_device(lvts_data, RESET_ALL_DEVICES, i); > + writel(DISABLE_LVTS_CTRL_CLK, LVTSCLKEN_0 + base); > + } > +} > + > +static void lvts_close(struct lvts_data *lvts_data) > +{ > + disable_all_sensing_points(lvts_data); > + wait_all_tc_sensing_point_idle(lvts_data); > + lvts_device_close(lvts_data); > + clk_disable_unprepare(lvts_data->clk); > +} > + > +static void tc_irq_handler(struct lvts_data *lvts_data, int tc_id) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int ret = 0; > + void __iomem *base; > + > + base = GET_BASE_ADDR(tc_id); > + > + ret = readl(LVTSMONINTSTS_0 + base); > + /* Write back to clear interrupt status */ > + writel(ret, LVTSMONINTSTS_0 + base); > + > + dev_info(dev, "[Thermal IRQ] LVTS thermal controller %d, LVTSMONINTSTS=0x%08x\n", > + tc_id, ret); > + > + if (ret & THERMAL_PROTECTION_STAGE_3) > + dev_info(dev, > + "[Thermal IRQ]: Thermal protection stage 3 interrupt triggered\n"); > +} > + > +static irqreturn_t irq_handler(int irq, void *dev_id) > +{ > + struct lvts_data *lvts_data = (struct lvts_data *)dev_id; > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + unsigned int i, *irq_bitmap; > + void __iomem *base; > + > + irq_bitmap = kcalloc(lvts_data->num_domain, sizeof(*irq_bitmap), GFP_ATOMIC); > + > + if (!irq_bitmap) > + return IRQ_NONE; > + > + for (i = 0; i < lvts_data->num_domain; i++) { > + base = lvts_data->domain[i].base; > + irq_bitmap[i] = readl(THERMINTST + base); > + dev_info(dev, "%s : THERMINTST = 0x%x\n", __func__, irq_bitmap[i]); > + } > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + if ((irq_bitmap[tc[i].domain_index] & tc[i].irq_bit) == 0) > + tc_irq_handler(lvts_data, i); > + } > + > + kfree(irq_bitmap); > + > + return IRQ_HANDLED; > +} > + > +static int lvts_register_irq_handler(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int i; > + int ret; > + > + for (i = 0; i < lvts_data->num_domain; i++) { > + ret = devm_request_irq(dev, lvts_data->domain[i].irq_num, irq_handler, > + IRQF_TRIGGER_HIGH, "mtk_lvts", lvts_data); > + > + if (ret) { > + dev_err(dev, "Failed to register LVTS IRQ, ret %d, domain %d irq_num %d\n", > + ret, i, lvts_data->domain[i].irq_num); > + lvts_close(lvts_data); > + return ret; > + } > + } > + > + return 0; > +} > + > +static int lvts_register_thermal_zones(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + struct thermal_zone_device *tzdev; > + struct soc_temp_tz *lvts_tz; > + int i, ret; > + > + for (i = 0; i < lvts_data->num_sensor + 1; i++) { > + lvts_tz = devm_kzalloc(dev, sizeof(*lvts_tz), GFP_KERNEL); > + if (!lvts_tz) { > + lvts_close(lvts_data); > + return -ENOMEM; > + } > + > + lvts_tz->id = i; > + lvts_tz->lvts_data = lvts_data; > + > + tzdev = devm_thermal_zone_of_sensor_register(dev, lvts_tz->id, > + lvts_tz, &soc_temp_lvts_ops); > + > + if (IS_ERR(tzdev)) { > + if (lvts_tz->id != 0) > + return 0; > + > + ret = PTR_ERR(tzdev); > + dev_err(dev, "Error: Failed to register lvts tz %d, ret = %d\n", > + lvts_tz->id, ret); > + lvts_close(lvts_data); > + return ret; > + } > + } > + > + return 0; > +} > + > +static int lvts_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct lvts_data *lvts_data; > + int ret; > + > + lvts_data = (struct lvts_data *)of_device_get_match_data(dev); > + > + if (!lvts_data) { > + dev_err(dev, "Error: Failed to get lvts platform data\n"); > + return -ENODATA; > + } > + > + lvts_data->dev = &pdev->dev; > + > + ret = of_update_lvts_data(lvts_data, pdev); > + if (ret) > + return ret; > + > + platform_set_drvdata(pdev, lvts_data); > + > + ret = lvts_init(lvts_data); > + if (ret) > + return ret; > + > + ret = lvts_register_irq_handler(lvts_data); > + if (ret) > + return ret; > + > + ret = lvts_register_thermal_zones(lvts_data); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static int lvts_remove(struct platform_device *pdev) > +{ > + struct lvts_data *lvts_data; > + > + lvts_data = (struct lvts_data *)platform_get_drvdata(pdev); > + > + lvts_close(lvts_data); > + > + return 0; > +} > + > +static int lvts_suspend(struct platform_device *pdev, pm_message_t state) > +{ > + struct lvts_data *lvts_data; > + > + lvts_data = (struct lvts_data *)platform_get_drvdata(pdev); > + > + lvts_close(lvts_data); > + > + return 0; > +} > + > +static int lvts_resume(struct platform_device *pdev) > +{ > + int ret; > + struct lvts_data *lvts_data; > + > + lvts_data = (struct lvts_data *)platform_get_drvdata(pdev); > + > + ret = lvts_init(lvts_data); > + if (ret) > + return ret; > + > + return 0; > +} > + > +/*================================================== > + * LVTS v4 common code > + *================================================== > + */ > +static void device_enable_and_init_v4(struct lvts_data *lvts_data) > +{ > + unsigned int i; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + lvts_write_device(lvts_data, STOP_COUNTING_V4, i); > + lvts_write_device(lvts_data, SET_RG_TSFM_LPDLY_V4, i); > + lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US1_V4, i); > + lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US2_V4, i); > + lvts_write_device(lvts_data, TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4, i); > + lvts_write_device(lvts_data, TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4, i); > + lvts_write_device(lvts_data, SET_TS_RSV_V4, i); > + lvts_write_device(lvts_data, SET_TS_EN_V4, i); > + lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST1_V4, i); > + lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST2_V4, i); > + } > + > + lvts_data->counting_window_us = 20; > +} > + > +static void device_enable_auto_rck_v4(struct lvts_data *lvts_data) > +{ > + unsigned int i; > + > + for (i = 0; i < lvts_data->num_tc; i++) > + lvts_write_device(lvts_data, SET_LVTS_AUTO_RCK_V4, i); > +} > + > +static int device_read_count_rc_n_v4(struct lvts_data *lvts_data) > +{ > + /* Resistor-Capacitor Calibration */ > + /* count_RC_N: count RC now */ > + struct device *dev = lvts_data->dev; > + struct tc_settings *tc = lvts_data->tc; > + struct sensor_cal_data *cal_data = &lvts_data->cal_data; > + unsigned int offset, size, s_index, data; > + void __iomem *base; > + int ret, i, j; > + char buffer[512]; > + > + cal_data->count_rc_now = devm_kcalloc(dev, lvts_data->num_sensor, > + sizeof(*cal_data->count_rc_now), GFP_KERNEL); > + if (!cal_data->count_rc_now) > + return -ENOMEM; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + for (j = 0; j < tc[i].num_sensor; j++) { > + s_index = tc[i].sensor_map[j]; > + > + lvts_write_device(lvts_data, SELECT_SENSOR_RCK_V4(j), i); > + lvts_write_device(lvts_data, SET_DEVICE_SINGLE_MODE_V4, i); > + usleep_range(10, 20); > + > + lvts_write_device(lvts_data, KICK_OFF_RCK_COUNTING_V4, i); > + usleep_range(30, 40); > + > + ret = readl_poll_timeout(LVTS_CONFIG_0 + base, data, > + !(data & DEVICE_SENSING_STATUS), 2, 200); > + if (ret) > + dev_err(dev, > + "Error: LVTS %d DEVICE_SENSING_STATUS didn't ready\n", i); > + > + data = lvts_read_device(lvts_data, 0x00, i); > + > + cal_data->count_rc_now[s_index] = (data & GENMASK(23, 0)); > + } > + > + /* Recover Setting for Normal Access on > + * temperature fetch > + */ > + lvts_write_device(lvts_data, SET_SENSOR_NO_RCK_V4, i); > + lvts_write_device(lvts_data, SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i); > + } > + > + size = sizeof(buffer); > + offset = snprintf(buffer, size, "[COUNT_RC_NOW] "); > + for (i = 0; i < lvts_data->num_sensor; i++) > + offset += snprintf(buffer + offset, size - offset, "%d:%d ", > + i, cal_data->count_rc_now[i]); > + > + buffer[offset] = '\0'; > + dev_info(dev, "%s\n", buffer); > + > + return 0; > +} > + > +static void set_calibration_data_v4(struct lvts_data *lvts_data) > +{ > + struct tc_settings *tc = lvts_data->tc; > + struct sensor_cal_data *cal_data = &lvts_data->cal_data; > + unsigned int i, j, s_index, e_data; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + > + for (j = 0; j < tc[i].num_sensor; j++) { > + s_index = tc[i].sensor_map[j]; > + if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK)) > + e_data = cal_data->count_r[s_index]; > + else > + e_data = (((unsigned long long) > + cal_data->count_rc_now[s_index]) * > + cal_data->count_r[s_index]) >> 14; > + > + writel(e_data, LVTSEDATA00_0 + base + 0x4 * j); > + } > + } > +} > + > +static void init_controller_v4(struct lvts_data *lvts_data) > +{ > + struct device *dev = lvts_data->dev; > + unsigned int i; > + void __iomem *base; > + > + for (i = 0; i < lvts_data->num_tc; i++) { > + base = GET_BASE_ADDR(i); > + > + lvts_write_device(lvts_data, SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i); > + > + writel(SET_SENSOR_INDEX, LVTSTSSEL_0 + base); > + writel(SET_CALC_SCALE_RULES, LVTSCALSCALE_0 + base); > + > + set_polling_speed(lvts_data, i); > + set_hw_filter(lvts_data, i); > + > + dev_info(dev, "lvts%d: read all %d sensors in %d us, one in %d us\n", > + i, GET_TC_SENSOR_NUM(i), GROUP_LATENCY_US(i), SENSOR_LATENCY_US(i)); > + } > +} > + > +/*================================================== > + * LVTS MT6873 > + *================================================== > + */ > + > +#define MT6873_NUM_LVTS (ARRAY_SIZE(mt6873_tc_settings)) > + > +enum mt6873_lvts_domain { > + MT6873_AP_DOMAIN, > + MT6873_MCU_DOMAIN, > + MT6873_NUM_DOMAIN > +}; > + > +enum mt6873_lvts_sensor_enum { > + MT6873_TS1_0, > + MT6873_TS1_1, > + MT6873_TS2_0, > + MT6873_TS2_1, > + MT6873_TS3_0, > + MT6873_TS3_1, > + MT6873_TS3_2, > + MT6873_TS3_3, > + MT6873_TS4_0, > + MT6873_TS4_1, > + MT6873_TS5_0, > + MT6873_TS5_1, > + MT6873_TS6_0, > + MT6873_TS6_1, > + MT6873_TS7_0, > + MT6873_TS7_1, > + MT6873_TS7_2, > + MT6873_NUM_TS > +}; > + > +static void mt6873_efuse_to_cal_data(struct lvts_data *lvts_data) > +{ > + struct sensor_cal_data *cal_data = &lvts_data->cal_data; > + > + cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24); > + cal_data->count_r[MT6873_TS1_0] = GET_CAL_DATA_BITMASK(1, 23, 0); > + cal_data->count_r[MT6873_TS1_1] = GET_CAL_DATA_BITMASK(2, 23, 0); > + cal_data->count_r[MT6873_TS2_0] = GET_CAL_DATA_BITMASK(3, 23, 0); > + cal_data->count_r[MT6873_TS2_1] = GET_CAL_DATA_BITMASK(4, 23, 0); > + cal_data->count_r[MT6873_TS3_0] = GET_CAL_DATA_BITMASK(5, 23, 0); > + cal_data->count_r[MT6873_TS3_1] = GET_CAL_DATA_BITMASK(6, 23, 0); > + cal_data->count_r[MT6873_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0); > + cal_data->count_r[MT6873_TS3_3] = GET_CAL_DATA_BITMASK(8, 23, 0); > + cal_data->count_r[MT6873_TS4_0] = GET_CAL_DATA_BITMASK(9, 23, 0); > + cal_data->count_r[MT6873_TS4_1] = GET_CAL_DATA_BITMASK(10, 23, 0); > + cal_data->count_r[MT6873_TS5_0] = GET_CAL_DATA_BITMASK(11, 23, 0); > + cal_data->count_r[MT6873_TS5_1] = GET_CAL_DATA_BITMASK(12, 23, 0); > + cal_data->count_r[MT6873_TS6_0] = GET_CAL_DATA_BITMASK(13, 23, 0); > + cal_data->count_r[MT6873_TS6_1] = GET_CAL_DATA_BITMASK(14, 23, 0); > + cal_data->count_r[MT6873_TS7_0] = GET_CAL_DATA_BITMASK(15, 23, 0); > + cal_data->count_r[MT6873_TS7_1] = GET_CAL_DATA_BITMASK(16, 23, 0); > + cal_data->count_r[MT6873_TS7_2] = GET_CAL_DATA_BITMASK(17, 23, 0); > + > + cal_data->count_rc[MT6873_TS1_0] = GET_CAL_DATA_BITMASK(21, 23, 0); > + > + cal_data->count_rc[MT6873_TS2_0] = (GET_CAL_DATA_BITMASK(1, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(2, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(3, 31, 24); > + > + cal_data->count_rc[MT6873_TS3_0] = (GET_CAL_DATA_BITMASK(4, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(5, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(6, 31, 24); > + > + cal_data->count_rc[MT6873_TS4_0] = (GET_CAL_DATA_BITMASK(7, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(8, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(9, 31, 24); > + > + cal_data->count_rc[MT6873_TS5_0] = (GET_CAL_DATA_BITMASK(10, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(11, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(12, 31, 24); > + > + cal_data->count_rc[MT6873_TS6_0] = (GET_CAL_DATA_BITMASK(13, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(14, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(15, 31, 24); > + > + cal_data->count_rc[MT6873_TS7_0] = (GET_CAL_DATA_BITMASK(16, 31, 24) << 16) + > + (GET_CAL_DATA_BITMASK(17, 31, 24) << 8) + > + GET_CAL_DATA_BITMASK(18, 31, 24); > +} > + > +static struct tc_settings mt6873_tc_settings[] = { > + [0] = { > + .domain_index = MT6873_MCU_DOMAIN, > + .addr_offset = 0x0, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS1_0, MT6873_TS1_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT1, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(3), > + }, > + [1] = { > + .domain_index = MT6873_MCU_DOMAIN, > + .addr_offset = 0x100, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS2_0, MT6873_TS2_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT0, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(4), > + }, > + [2] = { > + .domain_index = MT6873_MCU_DOMAIN, > + .addr_offset = 0x200, > + .num_sensor = 4, > + .sensor_map = {MT6873_TS3_0, MT6873_TS3_1, MT6873_TS3_2, MT6873_TS3_3}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT0, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(5), > + }, > + [3] = { > + .domain_index = MT6873_AP_DOMAIN, > + .addr_offset = 0x0, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS4_0, MT6873_TS4_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT0, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(3), > + }, > + [4] = { > + .domain_index = MT6873_AP_DOMAIN, > + .addr_offset = 0x100, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS5_0, MT6873_TS5_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT1, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(4), > + }, > + [5] = { > + .domain_index = MT6873_AP_DOMAIN, > + .addr_offset = 0x200, > + .num_sensor = 2, > + .sensor_map = {MT6873_TS6_0, MT6873_TS6_1}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT1, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(5), > + }, > + [6] = { > + .domain_index = MT6873_AP_DOMAIN, > + .addr_offset = 0x300, > + .num_sensor = 3, > + .sensor_map = {MT6873_TS7_0, MT6873_TS7_1, MT6873_TS7_2}, > + .tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118), > + .hw_filter = LVTS_FILTER_2_OF_4, > + .dominator_sensing_point = SENSING_POINT2, > + .hw_reboot_trip_point = 117000, > + .irq_bit = BIT(6), > + } > +}; > + > +static struct lvts_data mt6873_lvts_data = { > + .num_domain = MT6873_NUM_DOMAIN, > + .num_tc = MT6873_NUM_LVTS, > + .tc = mt6873_tc_settings, > + .num_sensor = MT6873_NUM_TS, > + .ops = { > + .efuse_to_cal_data = mt6873_efuse_to_cal_data, > + .device_enable_and_init = device_enable_and_init_v4, > + .device_enable_auto_rck = device_enable_auto_rck_v4, > + .device_read_count_rc_n = device_read_count_rc_n_v4, > + .set_cal_data = set_calibration_data_v4, > + .init_controller = init_controller_v4, > + }, > + .feature_bitmap = FEATURE_DEVICE_AUTO_RCK, > + .num_efuse_addr = 22, > + .num_efuse_block = 1, > + .cal_data = { > + .default_golden_temp = 50, > + .default_count_r = 35000, > + .default_count_rc = 2750, > + }, > + .coeff = { > + .a = -250460, > + .b = 250460, > + }, > +}; > + > +/*================================================== > + *================================================== > + * Support chips > + *================================================== > + */ > +static const struct of_device_id lvts_of_match[] = { > + { > + .compatible = "mediatek,mt6873-lvts", > + .data = (void *)&mt6873_lvts_data, > + }, > + { > + }, > +}; > +MODULE_DEVICE_TABLE(of, lvts_of_match); > +/*==================================================*/ > +static struct platform_driver soc_temp_lvts = { > + .probe = lvts_probe, > + .remove = lvts_remove, > + .suspend = lvts_suspend, > + .resume = lvts_resume, > + .driver = { > + .name = "mtk-soc-temp-lvts", > + .of_match_table = lvts_of_match, > + }, > +}; > + > +module_platform_driver(soc_temp_lvts); > +MODULE_AUTHOR("Yu-Chia Chang "); > +MODULE_AUTHOR("Michael Kao "); > +MODULE_DESCRIPTION("Mediatek soc temperature driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/thermal/mediatek/soc_temp_lvts.h b/drivers/thermal/mediatek/soc_temp_lvts.h > new file mode 100644 > index 000000000000..1d90bdec53c6 > --- /dev/null > +++ b/drivers/thermal/mediatek/soc_temp_lvts.h > @@ -0,0 +1,312 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (c) 2020 MediaTek Inc. > + */ > + > +#ifndef __MTK_SOC_TEMP_LVTS_H__ > +#define __MTK_SOC_TEMP_LVTS_H__ > + > +/* LVTS HW filter settings > + * 000: Get one sample > + * 001: Get 2 samples and average them > + * 010: Get 4 samples, drop max and min, then average the rest of 2 samples > + * 011: Get 6 samples, drop max and min, then average the rest of 4 samples > + * 100: Get 10 samples, drop max and min, then average the rest of 8 samples > + * 101: Get 18 samples, drop max and min, then average the rest of 16 samples > + */ > +enum lvts_hw_filter { > + LVTS_FILTER_1, > + LVTS_FILTER_2, > + LVTS_FILTER_2_OF_4, > + LVTS_FILTER_4_OF_6, > + LVTS_FILTER_8_OF_10, > + LVTS_FILTER_16_OF_18 > +}; > + > +enum lvts_sensing_point { > + SENSING_POINT0, > + SENSING_POINT1, > + SENSING_POINT2, > + SENSING_POINT3, > + ALL_SENSING_POINTS > +}; > + > +/*================================================== > + * Data structure > + *================================================== > + */ > +struct lvts_data; > + > +struct speed_settings { > + unsigned int period_unit; > + unsigned int group_interval_delay; > + unsigned int filter_interval_delay; > + unsigned int sensor_interval_delay; > +}; > + > +struct tc_settings { > + unsigned int domain_index; > + unsigned int addr_offset; > + unsigned int num_sensor; > + unsigned int sensor_map[ALL_SENSING_POINTS]; /* In sensor ID */ > + struct speed_settings tc_speed; > + /* HW filter setting > + * 000: Get one sample > + * 001: Get 2 samples and average them > + * 010: Get 4 samples, drop max and min, then average the rest of 2 samples > + * 011: Get 6 samples, drop max and min, then average the rest of 4 samples > + * 100: Get 10 samples, drop max and min, then average the rest of 8 samples > + * 101: Get 18 samples, drop max and min, then average the rest of 16 samples > + */ > + unsigned int hw_filter; > + /* Dominator_sensing point is used to select a sensing point > + * and reference its temperature to trigger Thermal HW Reboot > + * When it is ALL_SENSING_POINTS, it will select all sensing points > + */ > + int dominator_sensing_point; > + int hw_reboot_trip_point; /* -274000: Disable HW reboot */ > + unsigned int irq_bit; > +}; > + > +struct formula_coeff { > + int a; > + int b; > + unsigned int golden_temp; > +}; > + > +struct sensor_cal_data { > + int use_fake_efuse; /* 1: Use fake efuse, 0: Use real efuse */ > + unsigned int golden_temp; > + unsigned int *count_r; > + unsigned int *count_rc; > + unsigned int *count_rc_now; > + > + unsigned int default_golden_temp; > + unsigned int default_count_r; > + unsigned int default_count_rc; > +}; > + > +struct platform_ops { > + void (*efuse_to_cal_data)(struct lvts_data *lvts_data); > + void (*device_enable_and_init)(struct lvts_data *lvts_data); > + void (*device_enable_auto_rck)(struct lvts_data *lvts_data); > + int (*device_read_count_rc_n)(struct lvts_data *lvts_data); > + void (*set_cal_data)(struct lvts_data *lvts_data); > + void (*init_controller)(struct lvts_data *lvts_data); > +}; > + > +struct power_domain { > + void __iomem *base; /* LVTS base addresses */ > + unsigned int irq_num; /* LVTS interrupt numbers */ > + struct reset_control *reset; > +}; > + > +struct sensor_data { > + int temp; /* Current temperature */ > + unsigned int msr_raw; /* MSR raw data from LVTS */ > +}; > + > +struct lvts_data { > + struct device *dev; > + struct clk *clk; > + unsigned int num_domain; > + struct power_domain *domain; > + > + int num_tc; /* Number of LVTS thermal controllers */ > + struct tc_settings *tc; > + int counting_window_us; /* LVTS device counting window */ > + > + int num_sensor; /* Number of sensors in this platform */ > + struct sensor_data *sen_data; > + > + struct platform_ops ops; > + int feature_bitmap; /* Show what features are enabled */ > + > + unsigned int num_efuse_addr; > + unsigned int *efuse; > + unsigned int num_efuse_block; /* Number of contiguous efuse indexes */ > + struct sensor_cal_data cal_data; > + struct formula_coeff coeff; > +}; > + > +struct soc_temp_tz { > + unsigned int id; /* if id is 0, get max temperature of all sensors */ > + struct lvts_data *lvts_data; > +}; > + > +struct match_entry { > + char chip[32]; > + struct lvts_data *lvts_data; > +}; > + > +struct lvts_match_data { > + unsigned int hw_version; > + struct match_entry *table; > + void (*set_up_common_callbacks)(struct lvts_data *lvts_data); > + struct list_head node; > +}; > + > +struct lvts_id { > + unsigned int hw_version; > + char chip[32]; > +}; > + > +/*================================================== > + * LVTS device register > + *================================================== > + */ > +#define RG_TSFM_DATA_0 0x00 > +#define RG_TSFM_DATA_1 0x01 > +#define RG_TSFM_DATA_2 0x02 > +#define RG_TSFM_CTRL_0 0x03 > +#define RG_TSFM_CTRL_1 0x04 > +#define RG_TSFM_CTRL_2 0x05 > +#define RG_TSFM_CTRL_3 0x06 > +#define RG_TSFM_CTRL_4 0x07 > +#define RG_TSV2F_CTRL_0 0x08 > +#define RG_TSV2F_CTRL_1 0x09 > +#define RG_TSV2F_CTRL_2 0x0A > +#define RG_TSV2F_CTRL_3 0x0B > +#define RG_TSV2F_CTRL_4 0x0C > +#define RG_TSV2F_CTRL_5 0x0D > +#define RG_TSV2F_CTRL_6 0x0E > +#define RG_TEMP_DATA_0 0x10 > +#define RG_TEMP_DATA_1 0x11 > +#define RG_TEMP_DATA_2 0x12 > +#define RG_TEMP_DATA_3 0x13 > +#define RG_RC_DATA_0 0x14 > +#define RG_RC_DATA_1 0x15 > +#define RG_RC_DATA_2 0x16 > +#define RG_RC_DATA_3 0x17 > +#define RG_DIV_DATA_0 0x18 > +#define RG_DIV_DATA_1 0x19 > +#define RG_DIV_DATA_2 0x1A > +#define RG_DIV_DATA_3 0x1B > +#define RG_TST_DATA_0 0x70 > +#define RG_TST_DATA_1 0x71 > +#define RG_TST_DATA_2 0x72 > +#define RG_TST_CTRL 0x73 > +#define RG_DBG_FQMTR 0xF0 > +#define RG_DBG_LPSEQ 0xF1 > +#define RG_DBG_STATE 0xF2 > +#define RG_DBG_CHKSUM 0xF3 > +#define RG_DID_LVTS 0xFC > +#define RG_DID_REV 0xFD > +#define RG_TSFM_RST 0xFF > +/*================================================== > + * LVTS controller register > + *================================================== > + */ > +#define LVTSMONCTL0_0 0x000 > +#define LVTS_SINGLE_SENSE BIT(9) > +#define ENABLE_SENSING_POINT(num) (LVTS_SINGLE_SENSE | GENMASK(((num) - 1), 0)) > +#define DISABLE_SENSING_POINT (LVTS_SINGLE_SENSE | 0x0) > +#define LVTSMONCTL1_0 0x004 > +#define LVTSMONCTL2_0 0x008 > +#define LVTSMONINT_0 0x00C > +#define STAGE3_INT_EN BIT(31) > +#define LVTSMONINTSTS_0 0x010 > +#define LVTSMONIDET0_0 0x014 > +#define LVTSMONIDET1_0 0x018 > +#define LVTSMONIDET2_0 0x01C > +#define LVTSMONIDET3_0 0x020 > +#define LVTSH2NTHRE_0 0x024 > +#define LVTSHTHRE_0 0x028 > +#define LVTSCTHRE_0 0x02C > +#define LVTSOFFSETH_0 0x030 > +#define LVTSOFFSETL_0 0x034 > +#define LVTSMSRCTL0_0 0x038 > +#define LVTSMSRCTL1_0 0x03C > +#define LVTSTSSEL_0 0x040 > +#define SET_SENSOR_INDEX 0x13121110 > +#define LVTSDEVICETO_0 0x044 > +#define LVTSCALSCALE_0 0x048 > +#define SET_CALC_SCALE_RULES 0x00000300 > +#define LVTS_ID_0 0x04C > +#define LVTS_CONFIG_0 0x050 > + > +#define BROADCAST_ID_UPDATE BIT(26) > +#define DEVICE_SENSING_STATUS BIT(25) > +#define DEVICE_ACCESS_STARTUS BIT(24) > +#define WRITE_ACCESS BIT(16) > +#define DEVICE_WRITE (BIT(31) | CK26M_ACTIVE | DEVICE_ACCESS_STARTUS \ > + | BIT(17) | WRITE_ACCESS) > +#define DEVICE_READ (BIT(31) | CK26M_ACTIVE | DEVICE_ACCESS_STARTUS \ > + | 1 << 17) > +#define RESET_ALL_DEVICES (DEVICE_WRITE | RG_TSFM_RST << 8 | 0xFF) > +#define READ_BACK_DEVICE_ID (BIT(31) | CK26M_ACTIVE | BROADCAST_ID_UPDATE \ > + | DEVICE_ACCESS_STARTUS | BIT(17) \ > + | RG_DID_LVTS << 8) > +#define READ_DEVICE_REG(reg_idx) (DEVICE_READ | (reg_idx) << 8 | 0x00) > +#define LVTSEDATA00_0 0x054 > +#define LVTSEDATA01_0 0x058 > +#define LVTSEDATA02_0 0x05C > +#define LVTSEDATA03_0 0x060 > +#define LVTSMSR0_0 0x090 > +#define MRS_RAW_MASK GENMASK(15, 0) > +#define MRS_RAW_VALID_BIT BIT(16) > +#define LVTSMSR1_0 0x094 > +#define LVTSMSR2_0 0x098 > +#define LVTSMSR3_0 0x09C > +#define LVTSIMMD0_0 0x0A0 > +#define LVTSIMMD1_0 0x0A4 > +#define LVTSIMMD2_0 0x0A8 > +#define LVTSIMMD3_0 0x0AC > +#define LVTSRDATA0_0 0x0B0 > +#define LVTSRDATA1_0 0x0B4 > +#define LVTSRDATA2_0 0x0B8 > +#define LVTSRDATA3_0 0x0BC > +#define LVTSPROTCTL_0 0x0C0 > +#define PROTOFFSET GENMASK(15, 0) > +#define LVTSPROTTA_0 0x0C4 > +#define LVTSPROTTB_0 0x0C8 > +#define LVTSPROTTC_0 0x0CC > +#define LVTSCLKEN_0 0x0E4 > +#define ENABLE_LVTS_CTRL_CLK (1) > +#define DISABLE_LVTS_CTRL_CLK (0) > +#define LVTSDBGSEL_0 0x0E8 > +#define LVTSDBGSIG_0 0x0EC > +#define LVTSSPARE0_0 0x0F0 > +#define LVTSSPARE1_0 0x0F4 > +#define LVTSSPARE2_0 0x0F8 > +#define LVTSSPARE3_0 0x0FC > + > +#define THERMINTST 0xF04 > +/*================================================== > + * LVTS register mask > + *================================================== > + */ > +#define THERMAL_COLD_INTERRUPT_0 0x00000001 > +#define THERMAL_HOT_INTERRUPT_0 0x00000002 > +#define THERMAL_LOW_OFFSET_INTERRUPT_0 0x00000004 > +#define THERMAL_HIGH_OFFSET_INTERRUPT_0 0x00000008 > +#define THERMAL_HOT2NORMAL_INTERRUPT_0 0x00000010 > +#define THERMAL_COLD_INTERRUPT_1 0x00000020 > +#define THERMAL_HOT_INTERRUPT_1 0x00000040 > +#define THERMAL_LOW_OFFSET_INTERRUPT_1 0x00000080 > +#define THERMAL_HIGH_OFFSET_INTERRUPT_1 0x00000100 > +#define THERMAL_HOT2NORMAL_INTERRUPT_1 0x00000200 > +#define THERMAL_COLD_INTERRUPT_2 0x00000400 > +#define THERMAL_HOT_INTERRUPT_2 0x00000800 > +#define THERMAL_LOW_OFFSET_INTERRUPT_2 0x00001000 > +#define THERMAL_HIGH_OFFSET_INTERRUPT_2 0x00002000 > +#define THERMAL_HOT2NORMAL_INTERRUPT_2 0x00004000 > +#define THERMAL_AHB_TIMEOUT_INTERRUPT 0x00008000 > +#define THERMAL_DEVICE_TIMEOUT_INTERRUPT 0x00008000 > +#define THERMAL_IMMEDIATE_INTERRUPT_0 0x00010000 > +#define THERMAL_IMMEDIATE_INTERRUPT_1 0x00020000 > +#define THERMAL_IMMEDIATE_INTERRUPT_2 0x00040000 > +#define THERMAL_FILTER_INTERRUPT_0 0x00080000 > +#define THERMAL_FILTER_INTERRUPT_1 0x00100000 > +#define THERMAL_FILTER_INTERRUPT_2 0x00200000 > +#define THERMAL_COLD_INTERRUPT_3 0x00400000 > +#define THERMAL_HOT_INTERRUPT_3 0x00800000 > +#define THERMAL_LOW_OFFSET_INTERRUPT_3 0x01000000 > +#define THERMAL_HIGH_OFFSET_INTERRUPT_3 0x02000000 > +#define THERMAL_HOT2NORMAL_INTERRUPT_3 0x04000000 > +#define THERMAL_IMMEDIATE_INTERRUPT_3 0x08000000 > +#define THERMAL_FILTER_INTERRUPT_3 0x10000000 > +#define THERMAL_PROTECTION_STAGE_1 0x20000000 > +#define THERMAL_PROTECTION_STAGE_2 0x40000000 > +#define THERMAL_PROTECTION_STAGE_3 0x80000000 > +#endif /* __MTK_SOC_TEMP_LVTS_H__ */ _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel