Message ID | 1487682670-4164-1-git-send-email-vzakhar@synopsys.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
SGkgTWljaGFlbCwgU3RlcGhlbiwNCg0KT24gVHVlLCAyMDE3LTAyLTIxIGF0IDE2OjExICswMzAw LCBWbGFkIFpha2hhcm92IHdyb3RlOg0KPiBBWFMxMFggYm9hcmRzIG1hbmFnZXMgaXQncyBjbG9j a3MgdXNpbmcgdmFyaW91cyBQTExzLiBUaGVzZSBQTEwgaGFzIHNhbWUNCj4gZGl2aWRlcnMgYW5k IGNvcnJlc3BvbmRpbmcgY29udHJvbCByZWdpc3RlcnMgbWFwcGVkIHRvIGRpZmZlcmVudCBhZGRy ZXNzZXMuDQo+IFNvIHdlIGFkZCBvbmUgY29tbW9uIGRyaXZlciBmb3Igc3VjaCBQTExzLg0KPiAN Cj4gRWFjaCBQTEwgb24gQVhTMTBYIGJvYXJkIGNvbnNpc3Qgb2YgdGhyZWUgZGl2aWRlcnM6IElE SVYsIEZCRElWIGFuZA0KPiBPRElWLiBPdXRwdXQgY2xvY2sgdmFsdWUgaXMgbWFuYWdlZCB1c2lu ZyB0aGVzZSBkaXZpZGVycy4NCj4gDQo+IFdlIGFkZCBwcmUtZGVmaW5lZCB0YWJsZXMgd2l0aCBz dXBwb3J0ZWQgcmF0ZSB2YWx1ZXMgYW5kIGFwcHJvcHJpYXRlDQo+IGNvbmZpZ3VyYXRpb25zIG9m IElESVYsIEZCRElWIGFuZCBPRElWIGZvciBlYWNoIHZhbHVlLg0KPiANCj4gQXMgb2YgdG9kYXkg d2UgYWRkIHN1cHBvcnQgZm9yIFBMTHMgdGhhdCBnZW5lcmF0ZSBjbG9jayBmb3IgdGhlDQo+IGZv bGxvd2luZyBkZXZpY2VzOg0KPiDCoCogQVJDIGNvcmUgb24gQVhDIENQVSB0aWxlcy4NCj4gwqAq IEFSQyBQR1Ugb24gQVJDIFNEUCBNYWluYm9hcmQuDQo+IGFuZCBtb3JlIHRvIGNvbWUgbGF0ZXIu DQo+IA0KPiBBY2tlZC1ieTogUm9iIEhlcnJpbmcgPHJvYmhAa2VybmVsLm9yZz4NCj4gU2lnbmVk LW9mZi1ieTogVmxhZCBaYWtoYXJvdiA8dnpha2hhckBzeW5vcHN5cy5jb20+DQo+IFNpZ25lZC1v ZmYtYnk6IEpvc2UgQWJyZXUgPGpvYWJyZXVAc3lub3BzeXMuY29tPg0KPiBDYzogTWljaGFlbCBU dXJxdWV0dGUgPG10dXJxdWV0dGVAYmF5bGlicmUuY29tPg0KPiBDYzogU3RlcGhlbiBCb3lkIDxz Ym95ZEBjb2RlYXVyb3JhLm9yZz4NCj4gQ2M6IE1hcmsgUnV0bGFuZCA8bWFyay5ydXRsYW5kQGFy bS5jb20+DQo+IC0tLQ0KPiBDYzogUm9iIEhlcnJpbmcgPHJvYmhAa2VybmVsLm9yZz4NCj4gQ2hh bmdlcyB2MS4udjINCj4gwqAtIFJlcGxhY2UgJ18nIHdpdGggJy0nIGluIGRldmljZSB0cmVlIG5v ZGVzDQo+IA0KPiDCoC4uLi9kZXZpY2V0cmVlL2JpbmRpbmdzL2Nsb2NrL3NucHMscGxsLWNsb2Nr LnR4dMKgwqDCoHzCoMKgMjggKysNCj4gwqBNQUlOVEFJTkVSU8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgfMKgwqDCoDYgKw0KPiDCoGRyaXZlcnMvY2xrL2F4czEweC9NYWtlZmlsZcKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHzCoMKgwqAxICsNCj4gwqBkcml2 ZXJzL2Nsay9heHMxMHgvcGxsX2Nsb2NrLmPCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqB8IDM4NCArKysrKysrKysrKysrKysrKysrKysNCj4gwqA0IGZpbGVzIGNoYW5n ZWQsIDQxOSBpbnNlcnRpb25zKCspDQo+IMKgY3JlYXRlIG1vZGUgMTAwNjQ0IERvY3VtZW50YXRp b24vZGV2aWNldHJlZS9iaW5kaW5ncy9jbG9jay9zbnBzLHBsbC1jbG9jay50eHQNCj4gwqBjcmVh dGUgbW9kZSAxMDA2NDQgZHJpdmVycy9jbGsvYXhzMTB4L3BsbF9jbG9jay5jDQo+IA0KPiBkaWZm IC0tZ2l0IGEvRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL2Nsb2NrL3NucHMscGxs LWNsb2NrLnR4dA0KPiBiL0RvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9jbG9jay9z bnBzLHBsbC1jbG9jay50eHQNCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gaW5kZXggMDAwMDAw MC4uNTcwNjI0Ng0KPiAtLS0gL2Rldi9udWxsDQo+ICsrKyBiL0RvY3VtZW50YXRpb24vZGV2aWNl dHJlZS9iaW5kaW5ncy9jbG9jay9zbnBzLHBsbC1jbG9jay50eHQNCj4gQEAgLTAsMCArMSwyOCBA QA0KPiArQmluZGluZyBmb3IgdGhlIEFYUzEwWCBHZW5lcmljIFBMTCBjbG9jaw0KPiArDQo+ICtU aGlzIGJpbmRpbmcgdXNlcyB0aGUgY29tbW9uIGNsb2NrIGJpbmRpbmdbMV0uDQo+ICsNCj4gK1sx XSBEb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvY2xvY2svY2xvY2stYmluZGluZ3Mu dHh0DQo+ICsNCj4gK1JlcXVpcmVkIHByb3BlcnRpZXM6DQo+ICstIGNvbXBhdGlibGU6IHNob3Vs ZCBiZSAic25wcyxheHMxMHgtPG5hbWU+LXBsbC1jbG9jayINCj4gK8KgwqAic25wcyxheHMxMHgt YXJjLXBsbC1jbG9jayINCj4gK8KgwqAic25wcyxheHMxMHgtcGd1LXBsbC1jbG9jayINCj4gKy0g cmVnOiBzaG91bGQgYWx3YXlzIGNvbnRhaW4gMiBwYWlycyBhZGRyZXNzIC0gbGVuZ3RoOiBmaXJz dCBmb3IgUExMIGNvbmZpZw0KPiArcmVnaXN0ZXJzIGFuZCBzZWNvbmQgZm9yIGNvcnJlc3BvbmRp bmcgTE9DSyBDR1UgcmVnaXN0ZXIuDQo+ICstIGNsb2Nrczogc2hhbGwgYmUgdGhlIGlucHV0IHBh cmVudCBjbG9jayBwaGFuZGxlIGZvciB0aGUgUExMLg0KPiArLSAjY2xvY2stY2VsbHM6IGZyb20g Y29tbW9uIGNsb2NrIGJpbmRpbmc7IFNob3VsZCBhbHdheXMgYmUgc2V0IHRvIDAuDQo+ICsNCj4g K0V4YW1wbGU6DQo+ICsJaW5wdXQtY2xrOiBpbnB1dC1jbGsgew0KPiArCQljbG9jay1mcmVxdWVu Y3kgPSA8MzMzMzMzMzM+Ow0KPiArCQljb21wYXRpYmxlID0gImZpeGVkLWNsb2NrIjsNCj4gKwkJ I2Nsb2NrLWNlbGxzID0gPDA+Ow0KPiArCX07DQo+ICsNCj4gKwljb3JlLWNsazogY29yZS1jbGtA ODAgew0KPiArCQljb21wYXRpYmxlID0gInNucHMsYXhzMTB4LWFyYy1wbGwtY2xvY2siOw0KPiAr CQlyZWcgPSA8MHg4MCAweDEwIDB4MTAwIDB4MTA+Ow0KPiArCQkjY2xvY2stY2VsbHMgPSA8MD47 DQo+ICsJCWNsb2NrcyA9IDwmaW5wdXQtY2xrPjsNCj4gKwl9Ow0KPiBkaWZmIC0tZ2l0IGEvTUFJ TlRBSU5FUlMgYi9NQUlOVEFJTkVSUw0KPiBpbmRleCAzOTYwZTdmLi41ODA1ODMzIDEwMDY0NA0K PiAtLS0gYS9NQUlOVEFJTkVSUw0KPiArKysgYi9NQUlOVEFJTkVSUw0KPiBAQCAtMTE5MTAsNiAr MTE5MTAsMTIgQEAgRjoJYXJjaC9hcmMvcGxhdC1heHMxMHgNCj4gwqBGOglhcmNoL2FyYy9ib290 L2R0cy9heCoNCj4gwqBGOglEb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvYXJjL2F4 czEwKg0KPiDCoA0KPiArU1lOT1BTWVMgQVJDIFNEUCBjbG9jayBkcml2ZXINCj4gK006CVZsYWQg WmFraGFyb3YgPHZ6YWtoYXJAc3lub3BzeXMuY29tPg0KPiArUzoJU3VwcG9ydGVkDQo+ICtGOglk cml2ZXJzL2Nsay9heHMxMHgvKg0KPiArRjoJRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRp bmdzL2Nsb2NrL3NucHMscGxsLWNsb2NrLnR4dA0KPiArDQo+IMKgU1lTVEVNIENPTkZJR1VSQVRJ T04gKFNZU0NPTikNCj4gwqBNOglMZWUgSm9uZXMgPGxlZS5qb25lc0BsaW5hcm8ub3JnPg0KPiDC oE06CUFybmQgQmVyZ21hbm4gPGFybmRAYXJuZGIuZGU+DQo+IGRpZmYgLS1naXQgYS9kcml2ZXJz L2Nsay9heHMxMHgvTWFrZWZpbGUgYi9kcml2ZXJzL2Nsay9heHMxMHgvTWFrZWZpbGUNCj4gaW5k ZXggMDE5OTZiOC4uZDc0N2RlYSAxMDA2NDQNCj4gLS0tIGEvZHJpdmVycy9jbGsvYXhzMTB4L01h a2VmaWxlDQo+ICsrKyBiL2RyaXZlcnMvY2xrL2F4czEweC9NYWtlZmlsZQ0KPiBAQCAtMSArMSwy IEBADQo+IMKgb2JqLXkgKz0gaTJzX3BsbF9jbG9jay5vDQo+ICtvYmoteSArPSBwbGxfY2xvY2su bw0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9jbGsvYXhzMTB4L3BsbF9jbG9jay5jIGIvZHJpdmVy cy9jbGsvYXhzMTB4L3BsbF9jbG9jay5jDQo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0DQo+IGluZGV4 IDAwMDAwMDAuLjc4NGEwYTINCj4gLS0tIC9kZXYvbnVsbA0KPiArKysgYi9kcml2ZXJzL2Nsay9h eHMxMHgvcGxsX2Nsb2NrLmMNCj4gQEAgLTAsMCArMSwzODQgQEANCj4gKy8qDQo+ICsgKiBTeW5v cHN5cyBBWFMxMFggU0RQIEdlbmVyaWMgUExMIGNsb2NrIGRyaXZlcg0KPiArICoNCj4gKyAqIENv cHlyaWdodCAoQykgMjAxNyBTeW5vcHN5cw0KPiArICoNCj4gKyAqIFRoaXMgZmlsZSBpcyBsaWNl bnNlZCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYw0KPiArICogTGlj ZW5zZSB2ZXJzaW9uIDIuIFRoaXMgcHJvZ3JhbSBpcyBsaWNlbnNlZCAiYXMgaXMiIHdpdGhvdXQg YW55DQo+ICsgKiB3YXJyYW50eSBvZiBhbnkga2luZCwgd2hldGhlciBleHByZXNzIG9yIGltcGxp ZWQuDQo+ICsgKi8NCj4gKw0KPiArI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPg0K PiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2Nsay1wcm92 aWRlci5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgv ZXJyLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvZGV2aWNlLmg+DQo+ICsjaW5jbHVkZSA8bGludXgv b2ZfYWRkcmVzcy5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L29mX2RldmljZS5oPg0KPiArI2luY2x1 ZGUgPGxpbnV4L3NsYWIuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9vZi5oPg0KPiArDQo+ICsvKiBQ TEwgcmVnaXN0ZXJzIGFkZHJlc3NlcyAqLw0KPiArI2RlZmluZSBQTExfUkVHX0lESVYJMHgwDQo+ ICsjZGVmaW5lIFBMTF9SRUdfRkJESVYJMHg0DQo+ICsjZGVmaW5lIFBMTF9SRUdfT0RJVgkweDgN Cj4gKw0KPiArLyoNCj4gKyAqIEJpdCBmaWVsZHMgb2YgdGhlIFBMTCBJRElWL0ZCRElWL09ESVYg cmVnaXN0ZXJzOg0KPiArICrCoMKgX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQo+ICsgKiB8MzHCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoDE1fMKgwqDCoMKgMTTCoMKgwqDCoHzCoMKgwqAxM8KgwqDC oHzCoMKgMTLCoMKgfDExwqDCoMKgwqDCoMKgwqDCoMKgNnw1wqDCoMKgwqDCoMKgwqDCoMKgMHwN Cj4gKyAqIHwtLS0tLS0tUkVTUlZFRC0tLS0tLXwtTk9VUERBVEUtfC1CWVBBU1MtfC1FREdFLXwt LUhJR0hUSU1FLS18LS1MT1dUSU1FLS18DQo+ICsgKiB8X19fX19fX19fX19fX19fX19fX198X19f X19fX19fX3xfX19fX19fX3xfX19fX198X19fX19fX19fX19ffF9fX19fX19fX19ffA0KPiArICoN Cj4gKyAqIEZvbGxvd2luZyBtYWNyb3MgZGV0aXJtaW5lIHRoZSB3YXkgb2YgYWNjZXNzIHRvIHRo ZXNlIHJlZ2lzdGVycw0KPiArICogVGhleSBzaG91bGQgYmUgc2V0IHVwIG9ubHkgdXNpbmcgdGhl IG1hY3Jvcy4NCj4gKyAqIHJlZyBzaG91bGQgYmUgYW5kIHVpbnQzMl90IHZhcmlhYmxlLg0KPiAr ICovDQo+ICsNCj4gKyNkZWZpbmUgUExMX1JFR19HRVRfTE9XKHJlZykJCQlcDQo+ICsJKCgocmVn KSAmICgweDNGIDw8IDApKSA+PiAwKQ0KPiArI2RlZmluZSBQTExfUkVHX0dFVF9ISUdIKHJlZykJ CQlcDQo+ICsJKCgocmVnKSAmICgweDNGIDw8IDYpKSA+PiA2KQ0KPiArI2RlZmluZSBQTExfUkVH X0dFVF9FREdFKHJlZykJCQlcDQo+ICsJKCgocmVnKSAmIChCSVQoMTIpKSkgPyAxIDogMCkNCj4g KyNkZWZpbmUgUExMX1JFR19HRVRfQllQQVNTKHJlZykJCQlcDQo+ICsJKCgocmVnKSAmIChCSVQo MTMpKSkgPyAxIDogMCkNCj4gKyNkZWZpbmUgUExMX1JFR19HRVRfTk9VUEQocmVnKQkJCVwNCj4g KwkoKChyZWcpICYgKEJJVCgxNCkpKSA/IDEgOiAwKQ0KPiArI2RlZmluZSBQTExfUkVHX0dFVF9Q QUQocmVnKQkJCVwNCj4gKwkoKChyZWcpICYgKDB4MUZGRkYgPDwgMTUpKSA+PiAxNSkNCj4gKw0K PiArI2RlZmluZSBQTExfUkVHX1NFVF9MT1cocmVnLCB2YWx1ZSkJCVwNCj4gKwl7IHJlZyB8PSAo KCh2YWx1ZSkgJiAweDNGKSA8PCAwKTsgfQ0KPiArI2RlZmluZSBQTExfUkVHX1NFVF9ISUdIKHJl ZywgdmFsdWUpCVwNCj4gKwl7IHJlZyB8PSAoKCh2YWx1ZSkgJiAweDNGKSA8PCA2KTsgfQ0KPiAr I2RlZmluZSBQTExfUkVHX1NFVF9FREdFKHJlZywgdmFsdWUpCVwNCj4gKwl7IHJlZyB8PSAoKCh2 YWx1ZSkgJiAweDAxKSA8PCAxMik7IH0NCj4gKyNkZWZpbmUgUExMX1JFR19TRVRfQllQQVNTKHJl ZywgdmFsdWUpCVwNCj4gKwl7IHJlZyB8PSAoKCh2YWx1ZSkgJiAweDAxKSA8PCAxMyk7IH0NCj4g KyNkZWZpbmUgUExMX1JFR19TRVRfTk9VUEQocmVnLCB2YWx1ZSkJXA0KPiArCXsgcmVnIHw9ICgo KHZhbHVlKSAmIDB4MDEpIDw8IDE0KTsgfQ0KPiArI2RlZmluZSBQTExfUkVHX1NFVF9QQUQocmVn LCB2YWx1ZSkJCVwNCj4gKwl7IHJlZyB8PSAoKCh2YWx1ZSkgJiAweDFGRkZGKSA8PCAxNSk7IH0N Cj4gKw0KPiArI2RlZmluZSBQTExfTE9DSwkweDENCj4gKyNkZWZpbmUgUExMX01BWF9MT0NLX1RJ TUUgMTAwIC8qIDEwMCB1cyAqLw0KPiArDQo+ICtzdHJ1Y3QgcGxsX2NmZyB7DQo+ICsJdTMyIHJh dGU7DQo+ICsJdTMyIGlkaXY7DQo+ICsJdTMyIGZiZGl2Ow0KPiArCXUzMiBvZGl2Ow0KPiArfTsN Cj4gKw0KPiArc3RydWN0IHBsbF9vZl90YWJsZSB7DQo+ICsJdW5zaWduZWQgbG9uZyBwcmF0ZTsN Cj4gKwlzdHJ1Y3QgcGxsX2NmZyAqcGxsX2NmZ190YWJsZTsNCj4gK307DQo+ICsNCj4gK3N0cnVj dCBwbGxfb2ZfZGF0YSB7DQo+ICsJc3RydWN0IHBsbF9vZl90YWJsZSAqcGxsX3RhYmxlOw0KPiAr fTsNCj4gKw0KPiArc3RhdGljIHN0cnVjdCBwbGxfb2ZfZGF0YSBwZ3VfcGxsX2RhdGEgPSB7DQo+ ICsJLnBsbF90YWJsZSA9IChzdHJ1Y3QgcGxsX29mX3RhYmxlIFtdKXsNCj4gKwkJew0KPiArCQkJ LnByYXRlID0gMjcwMDAwMDAsDQo+ICsJCQkucGxsX2NmZ190YWJsZSA9IChzdHJ1Y3QgcGxsX2Nm ZyBbXSl7DQo+ICsJCQkJeyAyNTIwMDAwMCwgMSwgODQsIDkwIH0sDQo+ICsJCQkJeyA1MDAwMDAw MCwgMSwgMTAwLCA1NCB9LA0KPiArCQkJCXsgNzQyNTAwMDAsIDEsIDQ0LCAxNiB9LA0KPiArCQkJ CXsgfSwNCj4gKwkJCX0sDQo+ICsJCX0sDQo+ICsJCS8qIFVzZWQgYXMgbGlzdCBsaW1pdGVyICov DQo+ICsJCXsgfSwNCj4gKwl9LA0KPiArfTsNCj4gKw0KPiArc3RhdGljIHN0cnVjdCBwbGxfb2Zf ZGF0YSBhcmNfcGxsX2RhdGEgPSB7DQo+ICsJLnBsbF90YWJsZSA9IChzdHJ1Y3QgcGxsX29mX3Rh YmxlIFtdKXsNCj4gKwkJew0KPiArCQkJLnByYXRlID0gMzMzMzMzMzMsDQo+ICsJCQkucGxsX2Nm Z190YWJsZSA9IChzdHJ1Y3QgcGxsX2NmZyBbXSl7DQo+ICsJCQkJeyAzMzMzMzMzMyzCoMKgMSwg MSzCoMKgMSB9LA0KPiArCQkJCXsgNTAwMDAwMDAswqDCoDEsIDMwLCAyMCB9LA0KPiArCQkJCXsg NzUwMDAwMDAswqDCoDIsIDQ1LCAxMCB9LA0KPiArCQkJCXsgOTAwMDAwMDAswqDCoDIsIDU0LCAx MCB9LA0KPiArCQkJCXsgMTAwMDAwMDAwLCAxLCAzMCwgMTAgfSwNCj4gKwkJCQl7IDEyNTAwMDAw MCwgMiwgNDUsIDYgfSwNCj4gKwkJCQl7IH0sDQo+ICsJCQl9LA0KPiArCQl9LA0KPiArCQkvKiBV c2VkIGFzIGxpc3QgbGltaXRlciAqLw0KPiArCQl7IH0sDQo+ICsJfSwNCj4gK307DQo+ICsNCj4g K3N0cnVjdCBwbGxfY2xrIHsNCj4gKwl2b2lkIF9faW9tZW0gKmJhc2U7DQo+ICsJdm9pZCBfX2lv bWVtICpsb2NrOw0KPiArCWNvbnN0IHN0cnVjdCBwbGxfb2ZfZGF0YSAqcGxsX2RhdGE7DQo+ICsJ c3RydWN0IGNsa19odyBodzsNCj4gKwlzdHJ1Y3QgZGV2aWNlICpkZXY7DQo+ICt9Ow0KPiArDQo+ ICtzdGF0aWMgaW5saW5lIHZvaWQgcGxsX3dyaXRlKHN0cnVjdCBwbGxfY2xrICpjbGssIHVuc2ln bmVkIGludCByZWcsDQo+ICsJCXVuc2lnbmVkIGludCB2YWwpDQo+ICt7DQo+ICsJaW93cml0ZTMy KHZhbCwgY2xrLT5iYXNlICsgcmVnKTsNCj4gK30NCj4gKw0KPiArc3RhdGljIGlubGluZSB1MzIg cGxsX3JlYWQoc3RydWN0IHBsbF9jbGsgKmNsaywNCj4gKwkJdW5zaWduZWQgaW50IHJlZykNCj4g K3sNCj4gKwlyZXR1cm4gaW9yZWFkMzIoY2xrLT5iYXNlICsgcmVnKTsNCj4gK30NCj4gKw0KPiAr c3RhdGljIGlubGluZSBzdHJ1Y3QgcGxsX2NsayAqdG9fcGxsX2NsayhzdHJ1Y3QgY2xrX2h3ICpo dykNCj4gK3sNCj4gKwlyZXR1cm4gY29udGFpbmVyX29mKGh3LCBzdHJ1Y3QgcGxsX2NsaywgaHcp Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW5saW5lIHUzMiBkaXZfZ2V0X3ZhbHVlKHVuc2lnbmVk IGludCByZWcpDQo+ICt7DQo+ICsJaWYgKFBMTF9SRUdfR0VUX0JZUEFTUyhyZWcpKQ0KPiArCQly ZXR1cm4gMTsNCj4gKw0KPiArCXJldHVybiAoUExMX1JFR19HRVRfSElHSChyZWcpICsgUExMX1JF R19HRVRfTE9XKHJlZykpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW5saW5lIHUzMiBlbmNvZGVf ZGl2KHVuc2lnbmVkIGludCBpZCwgaW50IHVwZCkNCj4gK3sNCj4gKwl1aW50MzJfdCBkaXYgPSAw Ow0KPiArDQo+ICsJUExMX1JFR19TRVRfTE9XKGRpdiwgKGlkJTIgPT0gMCkgPyBpZCA+PiAxIDog KGlkID4+IDEpICsgMSk7DQo+ICsJUExMX1JFR19TRVRfSElHSChkaXYsIGlkID4+IDEpOw0KPiAr CVBMTF9SRUdfU0VUX0VER0UoZGl2LCBpZCUyKTsNCj4gKwlQTExfUkVHX1NFVF9CWVBBU1MoZGl2 LCBpZCA9PSAxID8gMSA6IDApOw0KPiArCVBMTF9SRUdfU0VUX05PVVBEKGRpdiwgIXVwZCk7DQo+ ICsNCj4gKwlyZXR1cm4gZGl2Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IHBs bF9jZmcgKnBsbF9nZXRfY2ZnKHVuc2lnbmVkIGxvbmcgcHJhdGUsDQo+ICsJCWNvbnN0IHN0cnVj dCBwbGxfb2ZfdGFibGUgKnBsbF90YWJsZSkNCj4gK3sNCj4gKwlpbnQgaTsNCj4gKw0KPiArCWZv ciAoaSA9IDA7IHBsbF90YWJsZVtpXS5wcmF0ZSAhPSAwOyBpKyspDQo+ICsJCWlmIChwbGxfdGFi bGVbaV0ucHJhdGUgPT0gcHJhdGUpDQo+ICsJCQlyZXR1cm4gcGxsX3RhYmxlW2ldLnBsbF9jZmdf dGFibGU7DQo+ICsNCj4gKwlyZXR1cm4gTlVMTDsNCj4gK30NCj4gKw0KPiArc3RhdGljIHVuc2ln bmVkIGxvbmcgcGxsX3JlY2FsY19yYXRlKHN0cnVjdCBjbGtfaHcgKmh3LA0KPiArCQkJdW5zaWdu ZWQgbG9uZyBwYXJlbnRfcmF0ZSkNCj4gK3sNCj4gKwl1NjQgcmF0ZTsNCj4gKwl1MzIgaWRpdiwg ZmJkaXYsIG9kaXY7DQo+ICsJc3RydWN0IHBsbF9jbGsgKmNsayA9IHRvX3BsbF9jbGsoaHcpOw0K PiArDQo+ICsJaWRpdiA9IGRpdl9nZXRfdmFsdWUocGxsX3JlYWQoY2xrLCBQTExfUkVHX0lESVYp KTsNCj4gKwlmYmRpdiA9IGRpdl9nZXRfdmFsdWUocGxsX3JlYWQoY2xrLCBQTExfUkVHX0ZCRElW KSk7DQo+ICsJb2RpdiA9IGRpdl9nZXRfdmFsdWUocGxsX3JlYWQoY2xrLCBQTExfUkVHX09ESVYp KTsNCj4gKw0KPiArCXJhdGUgPSAodTY0KXBhcmVudF9yYXRlICogZmJkaXY7DQo+ICsJZG9fZGl2 KHJhdGUsIGlkaXYgKiBvZGl2KTsNCj4gKw0KPiArCXJldHVybiAodW5zaWduZWQgbG9uZylyYXRl Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgbG9uZyBwbGxfcm91bmRfcmF0ZShzdHJ1Y3QgY2xrX2h3 ICpodywgdW5zaWduZWQgbG9uZyByYXRlLA0KPiArCQkJdW5zaWduZWQgbG9uZyAqcHJhdGUpDQo+ ICt7DQo+ICsJaW50IGk7DQo+ICsJbG9uZyBiZXN0X3JhdGU7DQo+ICsJc3RydWN0IHBsbF9jbGsg KmNsayA9IHRvX3BsbF9jbGsoaHcpOw0KPiArCWNvbnN0IHN0cnVjdCBwbGxfY2ZnICpwbGxfY2Zn ID0gcGxsX2dldF9jZmcoKnByYXRlLA0KPiArCQkJY2xrLT5wbGxfZGF0YS0+cGxsX3RhYmxlKTsN Cj4gKw0KPiArCWlmICghcGxsX2NmZykgew0KPiArCQlkZXZfZXJyKGNsay0+ZGV2LCAiaW52YWxp ZCBwYXJlbnQgcmF0ZT0lbGRcbiIsICpwcmF0ZSk7DQo+ICsJCXJldHVybiAtRUlOVkFMOw0KPiAr CX0NCj4gKw0KPiArCWlmIChwbGxfY2ZnWzBdLnJhdGUgPT0gMCkNCj4gKwkJcmV0dXJuIC1FSU5W QUw7DQo+ICsNCj4gKwliZXN0X3JhdGUgPSBwbGxfY2ZnWzBdLnJhdGU7DQo+ICsNCj4gKwlmb3Ig KGkgPSAxOyBwbGxfY2ZnW2ldLnJhdGUgIT0gMDsgaSsrKSB7DQo+ICsJCWlmIChhYnMocmF0ZSAt IHBsbF9jZmdbaV0ucmF0ZSkgPCBhYnMocmF0ZSAtIGJlc3RfcmF0ZSkpDQo+ICsJCQliZXN0X3Jh dGUgPSBwbGxfY2ZnW2ldLnJhdGU7DQo+ICsJfQ0KPiArDQo+ICsJcmV0dXJuIGJlc3RfcmF0ZTsN Cj4gK30NCj4gKw0KPiArc3RhdGljIGludCBwbGxfc2V0X3JhdGUoc3RydWN0IGNsa19odyAqaHcs IHVuc2lnbmVkIGxvbmcgcmF0ZSwNCj4gKwkJCXVuc2lnbmVkIGxvbmcgcGFyZW50X3JhdGUpDQo+ ICt7DQo+ICsJaW50IGk7DQo+ICsJc3RydWN0IHBsbF9jbGsgKmNsayA9IHRvX3BsbF9jbGsoaHcp Ow0KPiArCWNvbnN0IHN0cnVjdCBwbGxfY2ZnICpwbGxfY2ZnID0gcGxsX2dldF9jZmcocGFyZW50 X3JhdGUsDQo+ICsJCQljbGstPnBsbF9kYXRhLT5wbGxfdGFibGUpOw0KPiArDQo+ICsJaWYgKCFw bGxfY2ZnKSB7DQo+ICsJCWRldl9lcnIoY2xrLT5kZXYsICJpbnZhbGlkIHBhcmVudCByYXRlPSVs ZFxuIiwgcGFyZW50X3JhdGUpOw0KPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gKwl9DQo+ICsNCj4g Kwlmb3IgKGkgPSAwOyBwbGxfY2ZnW2ldLnJhdGUgIT0gMDsgaSsrKSB7DQo+ICsJCWlmIChwbGxf Y2ZnW2ldLnJhdGUgPT0gcmF0ZSkgew0KPiArCQkJcGxsX3dyaXRlKGNsaywgUExMX1JFR19JRElW LA0KPiArCQkJCQllbmNvZGVfZGl2KHBsbF9jZmdbaV0uaWRpdiwgMCkpOw0KPiArCQkJcGxsX3dy aXRlKGNsaywgUExMX1JFR19GQkRJViwNCj4gKwkJCQkJZW5jb2RlX2RpdihwbGxfY2ZnW2ldLmZi ZGl2LCAwKSk7DQo+ICsJCQlwbGxfd3JpdGUoY2xrLCBQTExfUkVHX09ESVYsDQo+ICsJCQkJCWVu Y29kZV9kaXYocGxsX2NmZ1tpXS5vZGl2LCAxKSk7DQo+ICsNCj4gKwkJCS8qDQo+ICsJCQnCoCog V2FpdCB1bnRpbCBDR1UgcmVsb2Nrcy4NCj4gKwkJCcKgKiBJZiBhZnRlciB0aW1lb3V0IENHVSBp cyB1bmxvY2tlZCB5ZXQgcmV0dXJuIGVycm9yDQo+ICsJCQnCoCovDQo+ICsJCQl1ZGVsYXkoUExM X01BWF9MT0NLX1RJTUUpOw0KPiArCQkJaWYgKGlvcmVhZDMyKGNsay0+bG9jaykgJiBQTExfTE9D SykNCj4gKwkJCQlyZXR1cm4gMDsNCj4gKwkJCWVsc2UNCj4gKwkJCQlyZXR1cm4gLUVUSU1FRE9V VDsNCj4gKwkJfQ0KPiArCX0NCj4gKw0KPiArCWRldl9lcnIoY2xrLT5kZXYsICJpbnZhbGlkIHJh dGU9JWxkLCBwYXJlbnRfcmF0ZT0lbGRcbiIsIHJhdGUsDQo+ICsJCQlwYXJlbnRfcmF0ZSk7DQo+ ICsJcmV0dXJuIC1FSU5WQUw7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgY2xr X29wcyBwbGxfb3BzID0gew0KPiArCS5yZWNhbGNfcmF0ZSA9IHBsbF9yZWNhbGNfcmF0ZSwNCj4g Kwkucm91bmRfcmF0ZSA9IHBsbF9yb3VuZF9yYXRlLA0KPiArCS5zZXRfcmF0ZSA9IHBsbF9zZXRf cmF0ZSwNCj4gK307DQo+ICsNCj4gK3N0YXRpYyBpbnQgcGxsX2Nsa19wcm9iZShzdHJ1Y3QgcGxh dGZvcm1fZGV2aWNlICpwZGV2KQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwZGV2 LT5kZXY7DQo+ICsJY29uc3QgY2hhciAqcGFyZW50X25hbWU7DQo+ICsJc3RydWN0IGNsayAqY2xr Ow0KPiArCXN0cnVjdCBwbGxfY2xrICpwbGxfY2xrOw0KPiArCXN0cnVjdCByZXNvdXJjZSAqbWVt Ow0KPiArCXN0cnVjdCBjbGtfaW5pdF9kYXRhIGluaXQgPSB7IH07DQo+ICsNCj4gKwlwbGxfY2xr ID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKCpwbGxfY2xrKSwgR0ZQX0tFUk5FTCk7DQo+ICsJ aWYgKCFwbGxfY2xrKQ0KPiArCQlyZXR1cm4gLUVOT01FTTsNCj4gKw0KPiArCW1lbSA9IHBsYXRm b3JtX2dldF9yZXNvdXJjZShwZGV2LCBJT1JFU09VUkNFX01FTSwgMCk7DQo+ICsJcGxsX2Nsay0+ YmFzZSA9IGRldm1faW9yZW1hcF9yZXNvdXJjZShkZXYsIG1lbSk7DQo+ICsJaWYgKElTX0VSUihw bGxfY2xrLT5iYXNlKSkNCj4gKwkJcmV0dXJuIFBUUl9FUlIocGxsX2Nsay0+YmFzZSk7DQo+ICsN Cj4gKwltZW0gPSBwbGF0Zm9ybV9nZXRfcmVzb3VyY2UocGRldiwgSU9SRVNPVVJDRV9NRU0sIDEp Ow0KPiArCXBsbF9jbGstPmxvY2sgPSBkZXZtX2lvcmVtYXBfcmVzb3VyY2UoZGV2LCBtZW0pOw0K PiArCWlmIChJU19FUlIocGxsX2Nsay0+bG9jaykpDQo+ICsJCXJldHVybiBQVFJfRVJSKHBsbF9j bGstPmJhc2UpOw0KPiArDQo+ICsJaW5pdC5uYW1lID0gZGV2LT5vZl9ub2RlLT5uYW1lOw0KPiAr CWluaXQub3BzID0gJnBsbF9vcHM7DQo+ICsJcGFyZW50X25hbWUgPSBvZl9jbGtfZ2V0X3BhcmVu dF9uYW1lKGRldi0+b2Zfbm9kZSwgMCk7DQo+ICsJaW5pdC5wYXJlbnRfbmFtZXMgPSAmcGFyZW50 X25hbWU7DQo+ICsJaW5pdC5udW1fcGFyZW50cyA9IDE7DQo+ICsJcGxsX2Nsay0+aHcuaW5pdCA9 ICZpbml0Ow0KPiArCXBsbF9jbGstPmRldiA9IGRldjsNCj4gKwlwbGxfY2xrLT5wbGxfZGF0YSA9 IG9mX2RldmljZV9nZXRfbWF0Y2hfZGF0YShkZXYpOw0KPiArDQo+ICsJaWYgKCFwbGxfY2xrLT5w bGxfZGF0YSkgew0KPiArCQlkZXZfZXJyKGRldiwgIk5vIE9GIG1hdGNoIGRhdGEgcHJvdmlkZWRc biIpOw0KPiArCQkJcmV0dXJuIC1FSU5WQUw7DQo+ICsJfQ0KPiArDQo+ICsJY2xrID0gZGV2bV9j bGtfcmVnaXN0ZXIoZGV2LCAmcGxsX2Nsay0+aHcpOw0KPiArCWlmIChJU19FUlIoY2xrKSkgew0K PiArCQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byByZWdpc3RlciAlcyBjbG9jayAoJWxkKVxuIiwN Cj4gKwkJCQlpbml0Lm5hbWUsIFBUUl9FUlIoY2xrKSk7DQo+ICsJCXJldHVybiBQVFJfRVJSKGNs ayk7DQo+ICsJfQ0KPiArDQo+ICsJcmV0dXJuIG9mX2Nsa19hZGRfcHJvdmlkZXIoZGV2LT5vZl9u b2RlLCBvZl9jbGtfc3JjX3NpbXBsZV9nZXQsIGNsayk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBp bnQgcGxsX2Nsa19yZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikNCj4gK3sNCj4g KwlvZl9jbGtfZGVsX3Byb3ZpZGVyKHBkZXYtPmRldi5vZl9ub2RlKTsNCj4gKwlyZXR1cm4gMDsN Cj4gK30NCj4gKw0KPiArc3RhdGljIHZvaWQgX19pbml0IG9mX3BsbF9jbGtfc2V0dXAoc3RydWN0 IGRldmljZV9ub2RlICpub2RlKQ0KPiArew0KPiArCWNvbnN0IGNoYXIgKnBhcmVudF9uYW1lOw0K PiArCXN0cnVjdCBjbGsgKmNsazsNCj4gKwlzdHJ1Y3QgcGxsX2NsayAqcGxsX2NsazsNCj4gKwlz dHJ1Y3QgY2xrX2luaXRfZGF0YSBpbml0ID0geyB9Ow0KPiArDQo+ICsJcGxsX2NsayA9IGt6YWxs b2Moc2l6ZW9mKCpwbGxfY2xrKSwgR0ZQX0tFUk5FTCk7DQo+ICsJaWYgKCFwbGxfY2xrKQ0KPiAr CQlyZXR1cm47DQo+ICsNCj4gKwlwbGxfY2xrLT5iYXNlID0gb2ZfaW9tYXAobm9kZSwgMCk7DQo+ ICsJaWYgKCFwbGxfY2xrLT5iYXNlKSB7DQo+ICsJCXByX2VycigiZmFpbGVkIHRvIG1hcCBwbGwg ZGl2IHJlZ2lzdGVyc1xuIik7DQo+ICsJCWlvdW5tYXAocGxsX2Nsay0+YmFzZSk7DQo+ICsJCXJl dHVybjsNCj4gKwl9DQo+ICsNCj4gKwlwbGxfY2xrLT5sb2NrID0gb2ZfaW9tYXAobm9kZSwgMSk7 DQo+ICsJaWYgKCFwbGxfY2xrLT5sb2NrKSB7DQo+ICsJCXByX2VycigiZmFpbGVkIHRvIG1hcCBw bGwgbG9jayByZWdpc3RlclxuIik7DQo+ICsJCWlvdW5tYXAocGxsX2Nsay0+bG9jayk7DQo+ICsJ CXJldHVybjsNCj4gKwl9DQo+ICsNCj4gKwlpbml0Lm5hbWUgPSBub2RlLT5uYW1lOw0KPiArCWlu aXQub3BzID0gJnBsbF9vcHM7DQo+ICsJcGFyZW50X25hbWUgPSBvZl9jbGtfZ2V0X3BhcmVudF9u YW1lKG5vZGUsIDApOw0KPiArCWluaXQucGFyZW50X25hbWVzID0gJnBhcmVudF9uYW1lOw0KPiAr CWluaXQubnVtX3BhcmVudHMgPSBwYXJlbnRfbmFtZSA/IDEgOiAwOw0KPiArCXBsbF9jbGstPmh3 LmluaXQgPSAmaW5pdDsNCj4gKwlwbGxfY2xrLT5wbGxfZGF0YSA9ICZhcmNfcGxsX2RhdGE7DQo+ ICsNCj4gKwljbGsgPSBjbGtfcmVnaXN0ZXIoTlVMTCwgJnBsbF9jbGstPmh3KTsNCj4gKwlpZiAo SVNfRVJSKGNsaykpIHsNCj4gKwkJcHJfZXJyKCJmYWlsZWQgdG8gcmVnaXN0ZXIgJXMgY2xvY2sg KCVsZClcbiIsDQo+ICsJCQkJbm9kZS0+bmFtZSwgUFRSX0VSUihjbGspKTsNCj4gKwkJa2ZyZWUo cGxsX2Nsayk7DQo+ICsJCXJldHVybjsNCj4gKwl9DQo+ICsNCj4gKwlvZl9jbGtfYWRkX3Byb3Zp ZGVyKG5vZGUsIG9mX2Nsa19zcmNfc2ltcGxlX2dldCwgY2xrKTsNCj4gK30NCj4gKw0KPiArQ0xL X09GX0RFQ0xBUkUoYXhzMTB4X3BsbF9jbG9jaywgInNucHMsYXhzMTB4LWFyYy1wbGwtY2xvY2si LCBvZl9wbGxfY2xrX3NldHVwKTsNCj4gKw0KPiArc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZp Y2VfaWQgcGxsX2Nsa19pZFtdID0gew0KPiArCXsgLmNvbXBhdGlibGUgPSAic25wcyxheHMxMHgt YXJjLXBsbC1jbG9jayIsIC5kYXRhID0gJmFyY19wbGxfZGF0YX0sDQo+ICsJeyAuY29tcGF0aWJs ZSA9ICJzbnBzLGF4czEweC1wZ3UtcGxsLWNsb2NrIiwgLmRhdGEgPSAmcGd1X3BsbF9kYXRhfSwN Cj4gKwl7IH0sDQo+ICt9Ow0KPiArTU9EVUxFX0RFVklDRV9UQUJMRShvZiwgcGxsX2Nsa19pZCk7 DQo+ICsNCj4gK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIHBsbF9jbGtfZHJpdmVyID0g ew0KPiArCS5kcml2ZXIgPSB7DQo+ICsJCS5uYW1lID0gImF4czEweC1wbGwtY2xvY2siLA0KPiAr CQkub2ZfbWF0Y2hfdGFibGUgPSBwbGxfY2xrX2lkLA0KPiArCX0sDQo+ICsJLnByb2JlID0gcGxs X2Nsa19wcm9iZSwNCj4gKwkucmVtb3ZlID0gcGxsX2Nsa19yZW1vdmUsDQo+ICt9Ow0KPiArYnVp bHRpbl9wbGF0Zm9ybV9kcml2ZXIocGxsX2Nsa19kcml2ZXIpOw0KPiArDQo+ICtNT0RVTEVfQVVU SE9SKCJWbGFkIFpha2hhcm92IDx2emFraGFyQHN5bm9wc3lzLmNvbT4iKTsNCj4gK01PRFVMRV9E RVNDUklQVElPTigiU3lub3BzeXMgQVhTMTBYIFNEUCBHZW5lcmljIFBMTCBDbG9jayBEcml2ZXIi KTsNCj4gK01PRFVMRV9MSUNFTlNFKCJHUEwgdjIiKTsNCg0KTWF5YmUgeW91IGhhdmUgYW55IGNv bW1lbnRzIG9yIHJlbWFya3MgYWJvdXQgdGhpcyBwYXRjaD8gQW5kIGlmIHlvdSBkb24ndCBjb3Vs ZCB5b3UgcGxlYXNlIGFwcGx5IGl0Lg0KDQpUaGFua3MhDQoNCi0tIA0KQmVzdCByZWdhcmRzLA0K VmxhZCBaYWtoYXJvdiA8dnpha2hhckBzeW5vcHN5cy5jb20+ -- To unsubscribe from this list: send the line "unsubscribe linux-clk" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 03/03, Vlad Zakharov wrote: > Hi Michael, Stephen, > > On Tue, 2017-02-21 at 16:11 +0300, Vlad Zakharov wrote: > > AXS10X boards manages it's clocks using various PLLs. These PLL has same > > dividers and corresponding control registers mapped to different addresses. > > So we add one common driver for such PLLs. > > > > Each PLL on AXS10X board consist of three dividers: IDIV, FBDIV and > > ODIV. Output clock value is managed using these dividers. > > > > We add pre-defined tables with supported rate values and appropriate > > configurations of IDIV, FBDIV and ODIV for each value. > > > > As of today we add support for PLLs that generate clock for the > > following devices: > > * ARC core on AXC CPU tiles. > > * ARC PGU on ARC SDP Mainboard. > > and more to come later. > > > > Acked-by: Rob Herring <robh@kernel.org> > > Signed-off-by: Vlad Zakharov <vzakhar@synopsys.com> > > Signed-off-by: Jose Abreu <joabreu@synopsys.com> > > Cc: Michael Turquette <mturquette@baylibre.com> > > Cc: Stephen Boyd <sboyd@codeaurora.org> > > Cc: Mark Rutland <mark.rutland@arm.com> > > Maybe you have any comments or remarks about this patch? And if you don't could you please apply it. > I haven't reviewed it yet. The merge window is upon us right now so I'll probably get to going through the queue this weekend/next week.
Hi Stephen, Michael, On Fri, 2017-03-03 at 15:50 -0800, Stephen Boyd wrote: > On 03/03, Vlad Zakharov wrote: > > > > Hi Michael, Stephen, > > > > On Tue, 2017-02-21 at 16:11 +0300, Vlad Zakharov wrote: > > > > > > AXS10X boards manages it's clocks using various PLLs. These PLL has same > > > dividers and corresponding control registers mapped to different addresses. > > > So we add one common driver for such PLLs. > > > > > > Each PLL on AXS10X board consist of three dividers: IDIV, FBDIV and > > > ODIV. Output clock value is managed using these dividers. > > > > > > We add pre-defined tables with supported rate values and appropriate > > > configurations of IDIV, FBDIV and ODIV for each value. > > > > > > As of today we add support for PLLs that generate clock for the > > > following devices: > > > * ARC core on AXC CPU tiles. > > > * ARC PGU on ARC SDP Mainboard. > > > and more to come later. > > > > > > Acked-by: Rob Herring <robh@kernel.org> > > > Signed-off-by: Vlad Zakharov <vzakhar@synopsys.com> > > > Signed-off-by: Jose Abreu <joabreu@synopsys.com> > > > Cc: Michael Turquette <mturquette@baylibre.com> > > > Cc: Stephen Boyd <sboyd@codeaurora.org> > > > Cc: Mark Rutland <mark.rutland@arm.com> > > > > Maybe you have any comments or remarks about this patch? And if you don't could you please apply it. > > > > I haven't reviewed it yet. The merge window is upon us right now > so I'll probably get to going through the queue this weekend/next > week. > Please treat this message as a polite reminder to review my patch. It is required for some subsystems on our boards, e.g. for ARC PGU. Thanks. -- Best regards, Vlad Zakharov <vzakhar@synopsys.com>
Hi Vlad, On 21-02-2017 13:11, Vlad Zakharov wrote: > AXS10X boards manages it's clocks using various PLLs. These PLL has same > dividers and corresponding control registers mapped to different addresses. > So we add one common driver for such PLLs. > > Each PLL on AXS10X board consist of three dividers: IDIV, FBDIV and > ODIV. Output clock value is managed using these dividers. > > We add pre-defined tables with supported rate values and appropriate > configurations of IDIV, FBDIV and ODIV for each value. > > As of today we add support for PLLs that generate clock for the > following devices: > * ARC core on AXC CPU tiles. > * ARC PGU on ARC SDP Mainboard. > and more to come later. > > Acked-by: Rob Herring <robh@kernel.org> > Signed-off-by: Vlad Zakharov <vzakhar@synopsys.com> > Signed-off-by: Jose Abreu <joabreu@synopsys.com> > Cc: Michael Turquette <mturquette@baylibre.com> > Cc: Stephen Boyd <sboyd@codeaurora.org> > Cc: Mark Rutland <mark.rutland@arm.com> > --- > Cc: Rob Herring <robh@kernel.org> > Changes v1..v2 > - Replace '_' with '-' in device tree nodes > > .../devicetree/bindings/clock/snps,pll-clock.txt | 28 ++ > MAINTAINERS | 6 + > drivers/clk/axs10x/Makefile | 1 + > drivers/clk/axs10x/pll_clock.c | 384 +++++++++++++++++++++ > 4 files changed, 419 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/snps,pll-clock.txt > create mode 100644 drivers/clk/axs10x/pll_clock.c > > diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt > new file mode 100644 > index 0000000..5706246 > --- /dev/null > +++ b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt > @@ -0,0 +1,28 @@ > +Binding for the AXS10X Generic PLL clock > + > +This binding uses the common clock binding[1]. > + > +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt > + > +Required properties: > +- compatible: should be "snps,axs10x-<name>-pll-clock" > + "snps,axs10x-arc-pll-clock" > + "snps,axs10x-pgu-pll-clock" > +- reg: should always contain 2 pairs address - length: first for PLL config > +registers and second for corresponding LOCK CGU register. > +- clocks: shall be the input parent clock phandle for the PLL. > +- #clock-cells: from common clock binding; Should always be set to 0. > + > +Example: > + input-clk: input-clk { > + clock-frequency = <33333333>; > + compatible = "fixed-clock"; > + #clock-cells = <0>; > + }; > + > + core-clk: core-clk@80 { > + compatible = "snps,axs10x-arc-pll-clock"; > + reg = <0x80 0x10 0x100 0x10>; > + #clock-cells = <0>; > + clocks = <&input-clk>; > + }; > diff --git a/MAINTAINERS b/MAINTAINERS > index 3960e7f..5805833 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -11910,6 +11910,12 @@ F: arch/arc/plat-axs10x > F: arch/arc/boot/dts/ax* > F: Documentation/devicetree/bindings/arc/axs10* > > +SYNOPSYS ARC SDP clock driver > +M: Vlad Zakharov <vzakhar@synopsys.com> > +S: Supported > +F: drivers/clk/axs10x/* > +F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt > + > SYSTEM CONFIGURATION (SYSCON) > M: Lee Jones <lee.jones@linaro.org> > M: Arnd Bergmann <arnd@arndb.de> > diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile > index 01996b8..d747dea 100644 > --- a/drivers/clk/axs10x/Makefile > +++ b/drivers/clk/axs10x/Makefile > @@ -1 +1,2 @@ > obj-y += i2s_pll_clock.o > +obj-y += pll_clock.o > diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c > new file mode 100644 > index 0000000..784a0a2 > --- /dev/null > +++ b/drivers/clk/axs10x/pll_clock.c > @@ -0,0 +1,384 @@ > +/* > + * Synopsys AXS10X SDP Generic PLL clock driver > + * > + * Copyright (C) 2017 Synopsys > + * > + * This file is licensed under the terms of the GNU General Public > + * License version 2. This program is licensed "as is" without any > + * warranty of any kind, whether express or implied. > + */ > + > +#include <linux/platform_device.h> > +#include <linux/module.h> > +#include <linux/clk-provider.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/device.h> > +#include <linux/of_address.h> > +#include <linux/of_device.h> > +#include <linux/slab.h> > +#include <linux/of.h> > + > +/* PLL registers addresses */ > +#define PLL_REG_IDIV 0x0 > +#define PLL_REG_FBDIV 0x4 > +#define PLL_REG_ODIV 0x8 > + > +/* > + * Bit fields of the PLL IDIV/FBDIV/ODIV registers: > + * ________________________________________________________________________ > + * |31 15| 14 | 13 | 12 |11 6|5 0| > + * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--| > + * |____________________|__________|________|______|____________|___________| > + * > + * Following macros detirmine the way of access to these registers > + * They should be set up only using the macros. > + * reg should be and uint32_t variable. > + */ > + > +#define PLL_REG_GET_LOW(reg) \ > + (((reg) & (0x3F << 0)) >> 0) > +#define PLL_REG_GET_HIGH(reg) \ > + (((reg) & (0x3F << 6)) >> 6) > +#define PLL_REG_GET_EDGE(reg) \ > + (((reg) & (BIT(12))) ? 1 : 0) > +#define PLL_REG_GET_BYPASS(reg) \ > + (((reg) & (BIT(13))) ? 1 : 0) > +#define PLL_REG_GET_NOUPD(reg) \ > + (((reg) & (BIT(14))) ? 1 : 0) > +#define PLL_REG_GET_PAD(reg) \ > + (((reg) & (0x1FFFF << 15)) >> 15) > + > +#define PLL_REG_SET_LOW(reg, value) \ > + { reg |= (((value) & 0x3F) << 0); } > +#define PLL_REG_SET_HIGH(reg, value) \ > + { reg |= (((value) & 0x3F) << 6); } > +#define PLL_REG_SET_EDGE(reg, value) \ > + { reg |= (((value) & 0x01) << 12); } > +#define PLL_REG_SET_BYPASS(reg, value) \ > + { reg |= (((value) & 0x01) << 13); } > +#define PLL_REG_SET_NOUPD(reg, value) \ > + { reg |= (((value) & 0x01) << 14); } > +#define PLL_REG_SET_PAD(reg, value) \ > + { reg |= (((value) & 0x1FFFF) << 15); } > + > +#define PLL_LOCK 0x1 > +#define PLL_MAX_LOCK_TIME 100 /* 100 us */ > + > +struct pll_cfg { > + u32 rate; > + u32 idiv; > + u32 fbdiv; > + u32 odiv; > +}; > + > +struct pll_of_table { > + unsigned long prate; > + struct pll_cfg *pll_cfg_table; > +}; > + > +struct pll_of_data { > + struct pll_of_table *pll_table; > +}; > + > +static struct pll_of_data pgu_pll_data = { > + .pll_table = (struct pll_of_table []){ > + { > + .prate = 27000000, > + .pll_cfg_table = (struct pll_cfg []){ > + { 25200000, 1, 84, 90 }, > + { 50000000, 1, 100, 54 }, > + { 74250000, 1, 44, 16 }, > + { }, > + }, > + }, > + /* Used as list limiter */ > + { }, > + }, > +}; > + > +static struct pll_of_data arc_pll_data = { > + .pll_table = (struct pll_of_table []){ > + { > + .prate = 33333333, > + .pll_cfg_table = (struct pll_cfg []){ > + { 33333333, 1, 1, 1 }, > + { 50000000, 1, 30, 20 }, > + { 75000000, 2, 45, 10 }, > + { 90000000, 2, 54, 10 }, > + { 100000000, 1, 30, 10 }, > + { 125000000, 2, 45, 6 }, > + { }, > + }, > + }, > + /* Used as list limiter */ > + { }, > + }, > +}; > + > +struct pll_clk { > + void __iomem *base; > + void __iomem *lock; > + const struct pll_of_data *pll_data; > + struct clk_hw hw; > + struct device *dev; > +}; > + > +static inline void pll_write(struct pll_clk *clk, unsigned int reg, > + unsigned int val) > +{ > + iowrite32(val, clk->base + reg); > +} > + > +static inline u32 pll_read(struct pll_clk *clk, > + unsigned int reg) > +{ > + return ioread32(clk->base + reg); > +} > + > +static inline struct pll_clk *to_pll_clk(struct clk_hw *hw) > +{ > + return container_of(hw, struct pll_clk, hw); > +} > + > +static inline u32 div_get_value(unsigned int reg) > +{ > + if (PLL_REG_GET_BYPASS(reg)) > + return 1; > + > + return (PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg)); > +} > + > +static inline u32 encode_div(unsigned int id, int upd) > +{ > + uint32_t div = 0; "uint32_t" -> "u32" > + > + PLL_REG_SET_LOW(div, (id%2 == 0) ? id >> 1 : (id >> 1) + 1); > + PLL_REG_SET_HIGH(div, id >> 1); > + PLL_REG_SET_EDGE(div, id%2); > + PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0); > + PLL_REG_SET_NOUPD(div, !upd); > + > + return div; > +} > + > +static const struct pll_cfg *pll_get_cfg(unsigned long prate, > + const struct pll_of_table *pll_table) > +{ > + int i; > + > + for (i = 0; pll_table[i].prate != 0; i++) > + if (pll_table[i].prate == prate) > + return pll_table[i].pll_cfg_table; > + > + return NULL; > +} > + > +static unsigned long pll_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + u64 rate; > + u32 idiv, fbdiv, odiv; > + struct pll_clk *clk = to_pll_clk(hw); > + > + idiv = div_get_value(pll_read(clk, PLL_REG_IDIV)); > + fbdiv = div_get_value(pll_read(clk, PLL_REG_FBDIV)); > + odiv = div_get_value(pll_read(clk, PLL_REG_ODIV)); > + > + rate = (u64)parent_rate * fbdiv; > + do_div(rate, idiv * odiv); > + > + return (unsigned long)rate; > +} > + > +static long pll_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *prate) > +{ > + int i; > + long best_rate; > + struct pll_clk *clk = to_pll_clk(hw); > + const struct pll_cfg *pll_cfg = pll_get_cfg(*prate, > + clk->pll_data->pll_table); > + > + if (!pll_cfg) { > + dev_err(clk->dev, "invalid parent rate=%ld\n", *prate); > + return -EINVAL; > + } > + > + if (pll_cfg[0].rate == 0) > + return -EINVAL; > + > + best_rate = pll_cfg[0].rate; > + > + for (i = 1; pll_cfg[i].rate != 0; i++) { > + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) > + best_rate = pll_cfg[i].rate; > + } > + > + return best_rate; > +} > + > +static int pll_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + int i; > + struct pll_clk *clk = to_pll_clk(hw); > + const struct pll_cfg *pll_cfg = pll_get_cfg(parent_rate, > + clk->pll_data->pll_table); > + > + if (!pll_cfg) { > + dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate); > + return -EINVAL; > + } > + > + for (i = 0; pll_cfg[i].rate != 0; i++) { > + if (pll_cfg[i].rate == rate) { > + pll_write(clk, PLL_REG_IDIV, > + encode_div(pll_cfg[i].idiv, 0)); > + pll_write(clk, PLL_REG_FBDIV, > + encode_div(pll_cfg[i].fbdiv, 0)); > + pll_write(clk, PLL_REG_ODIV, > + encode_div(pll_cfg[i].odiv, 1)); > + > + /* > + * Wait until CGU relocks. > + * If after timeout CGU is unlocked yet return error > + */ > + udelay(PLL_MAX_LOCK_TIME); > + if (ioread32(clk->lock) & PLL_LOCK) > + return 0; > + else > + return -ETIMEDOUT; > + } > + } > + > + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate, > + parent_rate); > + return -EINVAL; > +} > + > +static const struct clk_ops pll_ops = { > + .recalc_rate = pll_recalc_rate, > + .round_rate = pll_round_rate, > + .set_rate = pll_set_rate, > +}; > + > +static int pll_clk_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + const char *parent_name; > + struct clk *clk; > + struct pll_clk *pll_clk; > + struct resource *mem; > + struct clk_init_data init = { }; > + > + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL); > + if (!pll_clk) > + return -ENOMEM; > + > + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + pll_clk->base = devm_ioremap_resource(dev, mem); > + if (IS_ERR(pll_clk->base)) > + return PTR_ERR(pll_clk->base); > + > + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); > + pll_clk->lock = devm_ioremap_resource(dev, mem); > + if (IS_ERR(pll_clk->lock)) > + return PTR_ERR(pll_clk->base); Typo: should be "return PTR_ERR(pll_clk->lock);" > + > + init.name = dev->of_node->name; > + init.ops = &pll_ops; > + parent_name = of_clk_get_parent_name(dev->of_node, 0); > + init.parent_names = &parent_name; > + init.num_parents = 1; > + pll_clk->hw.init = &init; > + pll_clk->dev = dev; > + pll_clk->pll_data = of_device_get_match_data(dev); > + > + if (!pll_clk->pll_data) { > + dev_err(dev, "No OF match data provided\n"); > + return -EINVAL; > + } > + > + clk = devm_clk_register(dev, &pll_clk->hw); > + if (IS_ERR(clk)) { > + dev_err(dev, "failed to register %s clock (%ld)\n", > + init.name, PTR_ERR(clk)); > + return PTR_ERR(clk); > + } > + > + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, clk); > +} > + > +static int pll_clk_remove(struct platform_device *pdev) > +{ > + of_clk_del_provider(pdev->dev.of_node); > + return 0; > +} > + > +static void __init of_pll_clk_setup(struct device_node *node) > +{ > + const char *parent_name; > + struct clk *clk; > + struct pll_clk *pll_clk; > + struct clk_init_data init = { }; > + > + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); > + if (!pll_clk) > + return; > + > + pll_clk->base = of_iomap(node, 0); > + if (!pll_clk->base) { > + pr_err("failed to map pll div registers\n"); > + iounmap(pll_clk->base); > + return; > + } > + > + pll_clk->lock = of_iomap(node, 1); > + if (!pll_clk->lock) { > + pr_err("failed to map pll lock register\n"); > + iounmap(pll_clk->lock); > + return; > + } > + > + init.name = node->name; > + init.ops = &pll_ops; > + parent_name = of_clk_get_parent_name(node, 0); > + init.parent_names = &parent_name; > + init.num_parents = parent_name ? 1 : 0; > + pll_clk->hw.init = &init; > + pll_clk->pll_data = &arc_pll_data; > + > + clk = clk_register(NULL, &pll_clk->hw); > + if (IS_ERR(clk)) { > + pr_err("failed to register %s clock (%ld)\n", > + node->name, PTR_ERR(clk)); > + kfree(pll_clk); > + return; > + } > + > + of_clk_add_provider(node, of_clk_src_simple_get, clk); > +} > + > +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup); > + > +static const struct of_device_id pll_clk_id[] = { > + { .compatible = "snps,axs10x-arc-pll-clock", .data = &arc_pll_data}, > + { .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_data}, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, pll_clk_id); > + > +static struct platform_driver pll_clk_driver = { > + .driver = { > + .name = "axs10x-pll-clock", > + .of_match_table = pll_clk_id, > + }, > + .probe = pll_clk_probe, > + .remove = pll_clk_remove, > +}; > +builtin_platform_driver(pll_clk_driver); > + > +MODULE_AUTHOR("Vlad Zakharov <vzakhar@synopsys.com>"); > +MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver"); > +MODULE_LICENSE("GPL v2"); -- To unsubscribe from this list: send the line "unsubscribe linux-clk" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 02/21, Vlad Zakharov wrote: > diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt > new file mode 100644 > index 0000000..5706246 > --- /dev/null > +++ b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt > @@ -0,0 +1,28 @@ > +Binding for the AXS10X Generic PLL clock > + > +This binding uses the common clock binding[1]. > + > +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt > + > +Required properties: > +- compatible: should be "snps,axs10x-<name>-pll-clock" > + "snps,axs10x-arc-pll-clock" > + "snps,axs10x-pgu-pll-clock" > +- reg: should always contain 2 pairs address - length: first for PLL config > +registers and second for corresponding LOCK CGU register. > +- clocks: shall be the input parent clock phandle for the PLL. > +- #clock-cells: from common clock binding; Should always be set to 0. > + > +Example: > + input-clk: input-clk { > + clock-frequency = <33333333>; > + compatible = "fixed-clock"; > + #clock-cells = <0>; > + }; > + > + core-clk: core-clk@80 { > + compatible = "snps,axs10x-arc-pll-clock"; > + reg = <0x80 0x10 0x100 0x10>; Can you add the braces around register pairs in the example? Makes it clearer with a quick glance. > + #clock-cells = <0>; > + clocks = <&input-clk>; > + }; > diff --git a/MAINTAINERS b/MAINTAINERS > index 3960e7f..5805833 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -11910,6 +11910,12 @@ F: arch/arc/plat-axs10x > F: arch/arc/boot/dts/ax* > F: Documentation/devicetree/bindings/arc/axs10* > > +SYNOPSYS ARC SDP clock driver This also includes the existing driver there. Jose can ack this? > +M: Vlad Zakharov <vzakhar@synopsys.com> > +S: Supported > +F: drivers/clk/axs10x/* > +F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt > + > SYSTEM CONFIGURATION (SYSCON) > M: Lee Jones <lee.jones@linaro.org> > M: Arnd Bergmann <arnd@arndb.de> > diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile > index 01996b8..d747dea 100644 > --- a/drivers/clk/axs10x/Makefile > +++ b/drivers/clk/axs10x/Makefile > @@ -1 +1,2 @@ > obj-y += i2s_pll_clock.o > +obj-y += pll_clock.o > diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c > new file mode 100644 > index 0000000..784a0a2 > --- /dev/null > +++ b/drivers/clk/axs10x/pll_clock.c > @@ -0,0 +1,384 @@ > +/* > + * Synopsys AXS10X SDP Generic PLL clock driver > + * > + * Copyright (C) 2017 Synopsys > + * > + * This file is licensed under the terms of the GNU General Public > + * License version 2. This program is licensed "as is" without any > + * warranty of any kind, whether express or implied. > + */ > + > +#include <linux/platform_device.h> > +#include <linux/module.h> > +#include <linux/clk-provider.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/device.h> > +#include <linux/of_address.h> > +#include <linux/of_device.h> > +#include <linux/slab.h> > +#include <linux/of.h> > + > +/* PLL registers addresses */ > +#define PLL_REG_IDIV 0x0 > +#define PLL_REG_FBDIV 0x4 > +#define PLL_REG_ODIV 0x8 > + > +/* > + * Bit fields of the PLL IDIV/FBDIV/ODIV registers: > + * ________________________________________________________________________ > + * |31 15| 14 | 13 | 12 |11 6|5 0| > + * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--| > + * |____________________|__________|________|______|____________|___________| > + * > + * Following macros detirmine the way of access to these registers s/detirmine/determine/ > + * They should be set up only using the macros. > + * reg should be and uint32_t variable. s/and/an/? > + */ > + > +#define PLL_REG_GET_LOW(reg) \ > + (((reg) & (0x3F << 0)) >> 0) > +#define PLL_REG_GET_HIGH(reg) \ > + (((reg) & (0x3F << 6)) >> 6) > +#define PLL_REG_GET_EDGE(reg) \ > + (((reg) & (BIT(12))) ? 1 : 0) > +#define PLL_REG_GET_BYPASS(reg) \ > + (((reg) & (BIT(13))) ? 1 : 0) > +#define PLL_REG_GET_NOUPD(reg) \ > + (((reg) & (BIT(14))) ? 1 : 0) > +#define PLL_REG_GET_PAD(reg) \ > + (((reg) & (0x1FFFF << 15)) >> 15) > + > +#define PLL_REG_SET_LOW(reg, value) \ > + { reg |= (((value) & 0x3F) << 0); } > +#define PLL_REG_SET_HIGH(reg, value) \ > + { reg |= (((value) & 0x3F) << 6); } > +#define PLL_REG_SET_EDGE(reg, value) \ > + { reg |= (((value) & 0x01) << 12); } > +#define PLL_REG_SET_BYPASS(reg, value) \ > + { reg |= (((value) & 0x01) << 13); } > +#define PLL_REG_SET_NOUPD(reg, value) \ > + { reg |= (((value) & 0x01) << 14); } > +#define PLL_REG_SET_PAD(reg, value) \ > + { reg |= (((value) & 0x1FFFF) << 15); } > + > +#define PLL_LOCK 0x1 > +#define PLL_MAX_LOCK_TIME 100 /* 100 us */ > + > +struct pll_cfg { > + u32 rate; > + u32 idiv; > + u32 fbdiv; > + u32 odiv; > +}; > + > +struct pll_of_table { > + unsigned long prate; > + struct pll_cfg *pll_cfg_table; const? > +}; > + > +struct pll_of_data { > + struct pll_of_table *pll_table; > +}; Why the structure for another structure pointer? Just use pll_of_table for now? > + > +static struct pll_of_data pgu_pll_data = { const? > + .pll_table = (struct pll_of_table []){ > + { > + .prate = 27000000, Can this be another clk in the framework instead of hardcoding the parent rate? > + .pll_cfg_table = (struct pll_cfg []){ > + { 25200000, 1, 84, 90 }, > + { 50000000, 1, 100, 54 }, > + { 74250000, 1, 44, 16 }, > + { }, > + }, > + }, > + /* Used as list limiter */ > + { }, There's only ever one, so I'm confused why we're making a list. > + }, > +}; > + > +static struct pll_of_data arc_pll_data = { const? > + .pll_table = (struct pll_of_table []){ > + { > + .prate = 33333333, > + .pll_cfg_table = (struct pll_cfg []){ > + { 33333333, 1, 1, 1 }, > + { 50000000, 1, 30, 20 }, > + { 75000000, 2, 45, 10 }, > + { 90000000, 2, 54, 10 }, > + { 100000000, 1, 30, 10 }, > + { 125000000, 2, 45, 6 }, > + { }, > + }, > + }, > + /* Used as list limiter */ > + { }, > + }, > +}; > + > +struct pll_clk { > + void __iomem *base; > + void __iomem *lock; > + const struct pll_of_data *pll_data; > + struct clk_hw hw; > + struct device *dev; > +}; > + > +static inline void pll_write(struct pll_clk *clk, unsigned int reg, > + unsigned int val) > +{ > + iowrite32(val, clk->base + reg); > +} > + > +static inline u32 pll_read(struct pll_clk *clk, > + unsigned int reg) reg can go on the same line as clk? > +{ > + return ioread32(clk->base + reg); > +} > + > +static inline struct pll_clk *to_pll_clk(struct clk_hw *hw) > +{ > + return container_of(hw, struct pll_clk, hw); > +} > + > +static inline u32 div_get_value(unsigned int reg) > +{ > + if (PLL_REG_GET_BYPASS(reg)) > + return 1; > + > + return (PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg)); Useless parenthesis. > +} > + > +static inline u32 encode_div(unsigned int id, int upd) > +{ > + uint32_t div = 0; > + > + PLL_REG_SET_LOW(div, (id%2 == 0) ? id >> 1 : (id >> 1) + 1); > + PLL_REG_SET_HIGH(div, id >> 1); > + PLL_REG_SET_EDGE(div, id%2); > + PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0); > + PLL_REG_SET_NOUPD(div, !upd); > + > + return div; > +} > + > +static const struct pll_cfg *pll_get_cfg(unsigned long prate, > + const struct pll_of_table *pll_table) > +{ > + int i; > + > + for (i = 0; pll_table[i].prate != 0; i++) > + if (pll_table[i].prate == prate) > + return pll_table[i].pll_cfg_table; > + > + return NULL; > +} > + > +static unsigned long pll_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + u64 rate; > + u32 idiv, fbdiv, odiv; > + struct pll_clk *clk = to_pll_clk(hw); > + > + idiv = div_get_value(pll_read(clk, PLL_REG_IDIV)); > + fbdiv = div_get_value(pll_read(clk, PLL_REG_FBDIV)); > + odiv = div_get_value(pll_read(clk, PLL_REG_ODIV)); > + > + rate = (u64)parent_rate * fbdiv; > + do_div(rate, idiv * odiv); > + > + return (unsigned long)rate; Useless cast? > +} > + > +static long pll_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *prate) > +{ > + int i; > + long best_rate; > + struct pll_clk *clk = to_pll_clk(hw); > + const struct pll_cfg *pll_cfg = pll_get_cfg(*prate, > + clk->pll_data->pll_table); > + > + if (!pll_cfg) { > + dev_err(clk->dev, "invalid parent rate=%ld\n", *prate); > + return -EINVAL; > + } > + > + if (pll_cfg[0].rate == 0) > + return -EINVAL; > + > + best_rate = pll_cfg[0].rate; > + > + for (i = 1; pll_cfg[i].rate != 0; i++) { > + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) > + best_rate = pll_cfg[i].rate; > + } > + > + return best_rate; > +} > + > +static int pll_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + int i; > + struct pll_clk *clk = to_pll_clk(hw); > + const struct pll_cfg *pll_cfg = pll_get_cfg(parent_rate, > + clk->pll_data->pll_table); > + > + if (!pll_cfg) { > + dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate); > + return -EINVAL; > + } > + > + for (i = 0; pll_cfg[i].rate != 0; i++) { > + if (pll_cfg[i].rate == rate) { > + pll_write(clk, PLL_REG_IDIV, > + encode_div(pll_cfg[i].idiv, 0)); > + pll_write(clk, PLL_REG_FBDIV, > + encode_div(pll_cfg[i].fbdiv, 0)); > + pll_write(clk, PLL_REG_ODIV, > + encode_div(pll_cfg[i].odiv, 1)); > + > + /* > + * Wait until CGU relocks. > + * If after timeout CGU is unlocked yet return error > + */ > + udelay(PLL_MAX_LOCK_TIME); > + if (ioread32(clk->lock) & PLL_LOCK) > + return 0; > + else > + return -ETIMEDOUT; Can just be a return without the else part. > + } > + } > + > + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate, > + parent_rate); > + return -EINVAL; > +} > + > +static const struct clk_ops pll_ops = { > + .recalc_rate = pll_recalc_rate, > + .round_rate = pll_round_rate, > + .set_rate = pll_set_rate, > +}; > + > +static int pll_clk_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + const char *parent_name; > + struct clk *clk; > + struct pll_clk *pll_clk; > + struct resource *mem; > + struct clk_init_data init = { }; > + > + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL); > + if (!pll_clk) > + return -ENOMEM; > + > + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + pll_clk->base = devm_ioremap_resource(dev, mem); > + if (IS_ERR(pll_clk->base)) > + return PTR_ERR(pll_clk->base); > + > + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); > + pll_clk->lock = devm_ioremap_resource(dev, mem); > + if (IS_ERR(pll_clk->lock)) > + return PTR_ERR(pll_clk->base); > + > + init.name = dev->of_node->name; > + init.ops = &pll_ops; > + parent_name = of_clk_get_parent_name(dev->of_node, 0); > + init.parent_names = &parent_name; > + init.num_parents = 1; > + pll_clk->hw.init = &init; > + pll_clk->dev = dev; > + pll_clk->pll_data = of_device_get_match_data(dev); > + > + if (!pll_clk->pll_data) { > + dev_err(dev, "No OF match data provided\n"); > + return -EINVAL; > + } > + > + clk = devm_clk_register(dev, &pll_clk->hw); > + if (IS_ERR(clk)) { > + dev_err(dev, "failed to register %s clock (%ld)\n", > + init.name, PTR_ERR(clk)); > + return PTR_ERR(clk); > + } > + > + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, clk); > +} > + > +static int pll_clk_remove(struct platform_device *pdev) > +{ > + of_clk_del_provider(pdev->dev.of_node); > + return 0; > +} > + > +static void __init of_pll_clk_setup(struct device_node *node) > +{ > + const char *parent_name; > + struct clk *clk; > + struct pll_clk *pll_clk; > + struct clk_init_data init = { }; > + > + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); > + if (!pll_clk) > + return; > + > + pll_clk->base = of_iomap(node, 0); > + if (!pll_clk->base) { > + pr_err("failed to map pll div registers\n"); > + iounmap(pll_clk->base); > + return; > + } > + > + pll_clk->lock = of_iomap(node, 1); > + if (!pll_clk->lock) { > + pr_err("failed to map pll lock register\n"); > + iounmap(pll_clk->lock); > + return; > + } > + > + init.name = node->name; > + init.ops = &pll_ops; > + parent_name = of_clk_get_parent_name(node, 0); > + init.parent_names = &parent_name; > + init.num_parents = parent_name ? 1 : 0; > + pll_clk->hw.init = &init; > + pll_clk->pll_data = &arc_pll_data; > + > + clk = clk_register(NULL, &pll_clk->hw); > + if (IS_ERR(clk)) { > + pr_err("failed to register %s clock (%ld)\n", > + node->name, PTR_ERR(clk)); > + kfree(pll_clk); > + return; > + } > + > + of_clk_add_provider(node, of_clk_src_simple_get, clk); Can you please use the clk_hw based provider and clk registration functions? > +} > + > +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup); Does this need to be CLK_OF_DECLARE_DRIVER? I mean does the driver need to probe and also have this of declare happen? Is the PLL special and needs to be used for the timers?
SGkgU3RlcGhlbiwNCg0KT24gVHVlLCAyMDE3LTA0LTA0IGF0IDE4OjM1IC0wNzAwLCBTdGVwaGVu IEJveWQgd3JvdGU6DQo+ID4gK8KgwqDCoMKgwqAucGxsX3RhYmxlID0gKHN0cnVjdCBwbGxfb2Zf dGFibGUgW10pew0KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHsNCj4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgLnByYXRlID0gMjcwMDAwMDAsDQo+ IA0KPiBDYW4gdGhpcyBiZSBhbm90aGVyIGNsayBpbiB0aGUgZnJhbWV3b3JrIGluc3RlYWQgb2Yg aGFyZGNvZGluZw0KPiB0aGUgcGFyZW50IHJhdGU/DQoNCkluIGZhY3QgdGhlcmUgaXMgYW5vdGhl ciBjbGsgaW4gdGhlIGZyYW1ld29yayB0aGF0IHJlcHJlc2VudHMgdGhpcyBwYXJlbnQgY2xvY2su IEJ1dCB0aGlzIGZpZWxkIGlzIG5lZWRlZCB0byBnZXQNCmFwcHJvcHJpYXRlIHBsbF9jZmdfdGFi bGUgYXMgaXQgZGVwZW5kcyBvbiBwYXJlbnQgY2xvY2sgZnJlcXVlbmN5LiBCZWxvdyBpbiBwbGxf Y2ZnX2dldCBmdW5jdGlvbiB3ZSBhcmUgc2VhcmNoaW5nIGZvcg0KdGhlIGNvcnJlY3QgdGFibGUg Y29tcGFyaW5nIC5wYXJlbnRfbm9kZSBmaWVsZCB3aXRoIHJlYWwgaGFyZHdhcmUgcGFyZW50IGNs b2NrIGZyZXF1ZW5jeToNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+OC0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KZm9yIChpID0gMDsgcGxsX3RhYmxlW2ld LnByYXRlICE9IDA7IGkrKykNCsKgIMKgIGlmIChwbGxfdGFibGVbaV0ucHJhdGUgPT0gcHJhdGUp DQrCoCDCoCDCoCDCoCByZXR1cm4gcGxsX3RhYmxlW2ldLnBsbF9jZmdfdGFibGU7DQotLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPjgtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0NCg0KPiANCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgLnBsbF9jZmdfdGFibGUgPSAoc3RydWN0IHBsbF9jZmcgW10pew0KPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgeyAyNTIw MDAwMCwgMSwgODQsIDkwIH0sDQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqB7IDUwMDAwMDAwLCAxLCAxMDAsIDU0IH0sDQo+ID4g K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqB7IDc0MjUwMDAwLCAxLCA0NCwgMTYgfSwNCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHsgfSwNCj4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgfSwNCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqB9LA0KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoC8qIFVzZWQgYXMgbGlz dCBsaW1pdGVyICovDQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgeyB9LA0KPiANCj4g VGhlcmUncyBvbmx5IGV2ZXIgb25lLCBzbyBJJ20gY29uZnVzZWQgd2h5IHdlJ3JlIG1ha2luZyBh IGxpc3QuDQoNCkJ5IHRoaXMgcGF0Y2ggd2Ugb25seSBhZGQgc3VwcG9ydCBvZiBjb3JlIGFyYyBw bGwgYW5kIHBndSBwbGwgYW5kIHRvZGF5IHRoZXkgYXJlIGNsb2NrZWQgYnkgdGhlIG9ubHkgcGFy ZW50IGNsb2Nrcw0KaW50cm9kdWNlZCBoZXJlLiBCdXQgb3RoZXIgcGxscyBvbiBheHMxMHggbWF5 IGJlIGRyaXZlbiBieSBkaWZmZXJlbnQgb3IgY29uZmlndXJhYmxlIGNsb2Nrcywgc28gaW4gc3Vj aCBjYXNlcyB3ZSB3aWxsDQpoYXZlIG1vcmUgdGhhbiBvbmUgZW50cnkgaW4gdGhpcyBsaXN0LiBB bmQgd2UgYXJlIGdvaW5nIHRvIGFkZCBtb3JlIHN1cHBvcnRlZCBwbGxzIHRvIHRoaXMgZHJpdmVy IGluIHRoZSBuZWFyZXN0IGZ1dHVyZS4NCg0KPiA+ICsNCj4gPiArwqDCoMKgwqDCoGNsayA9IGNs a19yZWdpc3RlcihOVUxMLCAmcGxsX2Nsay0+aHcpOw0KPiA+ICvCoMKgwqDCoMKgaWYgKElTX0VS UihjbGspKSB7DQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgcHJfZXJyKCJmYWlsZWQg dG8gcmVnaXN0ZXIgJXMgY2xvY2sgKCVsZClcbiIsDQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqBub2RlLT5uYW1lLCBQVFJfRVJS KGNsaykpOw0KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoGtmcmVlKHBsbF9jbGspOw0K PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHJldHVybjsNCj4gPiArwqDCoMKgwqDCoH0N Cj4gPiArDQo+ID4gK8KgwqDCoMKgwqBvZl9jbGtfYWRkX3Byb3ZpZGVyKG5vZGUsIG9mX2Nsa19z cmNfc2ltcGxlX2dldCwgY2xrKTsNCj4gDQo+IENhbiB5b3UgcGxlYXNlIHVzZSB0aGUgY2xrX2h3 IGJhc2VkIHByb3ZpZGVyIGFuZCBjbGsgcmVnaXN0cmF0aW9uDQo+IGZ1bmN0aW9ucz8NCg0KU3Vy ZS4gQ291bGQgeW91IGJlIHNvIGtpbmQgdG8gZXhwbGFpbiB3aGF0IGlzIHRoZSBkaWZmZXJlbmNl IGJldHdlZW4gaHcgYW5kIG5vbi1odyBiYXNlZCBwcm92aWRlciBhbmQgY2xrIHJlZ2lzdHJhdGlv bg0KZnVuY3Rpb25zIHBsZWFzZT8gSW4gd2hpY2ggY2FzZXMgdGhleSBhcmUgcHJlZmVycmVkP8Kg DQoNCj4gDQo+ID4gK30NCj4gPiArDQo+ID4gK0NMS19PRl9ERUNMQVJFKGF4czEweF9wbGxfY2xv Y2ssICJzbnBzLGF4czEweC1hcmMtcGxsLWNsb2NrIiwgb2ZfcGxsX2Nsa19zZXR1cCk7DQo+IA0K PiBEb2VzIHRoaXMgbmVlZCB0byBiZSBDTEtfT0ZfREVDTEFSRV9EUklWRVI/IEkgbWVhbiBkb2Vz IHRoZQ0KPiBkcml2ZXIgbmVlZCB0byBwcm9iZSBhbmQgYWxzbyBoYXZlIHRoaXMgb2YgZGVjbGFy ZSBoYXBwZW4/IElzIHRoZQ0KPiBQTEwgc3BlY2lhbCBhbmQgbmVlZHMgdG8gYmUgdXNlZCBmb3Ig dGhlIHRpbWVycz8NCg0KSXQgaXMgc3BlY2lhbCBhbmQgaXMgdXNlZCBmb3IgdGhlIHRpbWVycywg c28gd2UgaGF2ZSB0byBDTEtfT0ZfREVDTEFSRSBpdC4gT24gdGhlIG90aGVyIGhhbmQgc2ltaWxh ciBwbGwgaXMgdXNlZCB0bw0KZHJpdmUgUEdVIGNsb2NrIGZyZXF1ZW5jeSBhbmQgb3RoZXIgc3Vi c3lzdGVtcyBhbmQgc28gd2UgYWRkIHVzdWFsIHByb2JlIGZ1bmMuDQoNCi0tIA0KQmVzdCByZWdh cmRzLA0KVmxhZCBaYWtoYXJvdiA8dnpha2hhckBzeW5vcHN5cy5jb20+ -- To unsubscribe from this list: send the line "unsubscribe linux-clk" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 04/05, Vlad Zakharov wrote: > Hi Stephen, > > On Tue, 2017-04-04 at 18:35 -0700, Stephen Boyd wrote: > > > + .pll_table = (struct pll_of_table []){ > > > + { > > > + .prate = 27000000, > > > > Can this be another clk in the framework instead of hardcoding > > the parent rate? > > In fact there is another clk in the framework that represents this parent clock. But this field is needed to get > appropriate pll_cfg_table as it depends on parent clock frequency. Below in pll_cfg_get function we are searching for > the correct table comparing .parent_node field with real hardware parent clock frequency: > ---------------------------------->8------------------------------------ > for (i = 0; pll_table[i].prate != 0; i++) > if (pll_table[i].prate == prate) > return pll_table[i].pll_cfg_table; > ---------------------------------->8------------------------------------ When is that done though? During round_rate and recalc_rate the parent frequency is passed into the function, so it should be possible to use that if the tree is properly expressed. > > > > > > + .pll_cfg_table = (struct pll_cfg []){ > > > + { 25200000, 1, 84, 90 }, > > > + { 50000000, 1, 100, 54 }, > > > + { 74250000, 1, 44, 16 }, > > > + { }, > > > + }, > > > + }, > > > + /* Used as list limiter */ > > > + { }, > > > > There's only ever one, so I'm confused why we're making a list. > > By this patch we only add support of core arc pll and pgu pll and today they are clocked by the only parent clocks > introduced here. But other plls on axs10x may be driven by different or configurable clocks, so in such cases we will > have more than one entry in this list. And we are going to add more supported plls to this driver in the nearest future. Ok. > > > > + > > > + clk = clk_register(NULL, &pll_clk->hw); > > > + if (IS_ERR(clk)) { > > > + pr_err("failed to register %s clock (%ld)\n", > > > + node->name, PTR_ERR(clk)); > > > + kfree(pll_clk); > > > + return; > > > + } > > > + > > > + of_clk_add_provider(node, of_clk_src_simple_get, clk); > > > > Can you please use the clk_hw based provider and clk registration > > functions? > > Sure. Could you be so kind to explain what is the difference between hw and non-hw based provider and clk registration > functions please? In which cases they are preferred? > We're trying to split the consumer and provider APIs along struct clk_hw and struct clk respectively. If we can have drivers only registers clk_hw pointers and never get back anything but an error code, then we can force consumers to always go through the clk_get() family of APIs. Then we can easily tell who is a provider, who is a consumer, and who is a provider + a consumer. Right now this isn't always clear cut because clk_hw has access to struct clk, and also clk_register() returns a clk pointer, but it doesn't really get used by anything in a provider driver, unless provider drivers are doing something with the consumer API. > > > > > +} > > > + > > > +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup); > > > > Does this need to be CLK_OF_DECLARE_DRIVER? I mean does the > > driver need to probe and also have this of declare happen? Is the > > PLL special and needs to be used for the timers? > > It is special and is used for the timers, so we have to CLK_OF_DECLARE it. On the other hand similar pll is used to > drive PGU clock frequency and other subsystems and so we add usual probe func. > Presumably we'll have different compatible strings for the different PLLs then? CLK_OF_DECLARE() will make it so that the device node that matches never gets a ->probe() from a platform_driver called on it. If you want it to be called twice, then you need to use CLK_OF_DECLARE_DRIVER() instead.
SGkgU3RlcGhlbiwNCg0KT24gV2VkLCAyMDE3LTA0LTE5IGF0IDA5OjQ5IC0wNzAwLCBzYm95ZEBj b2RlYXVyb3JhLm9yZyB3cm90ZToNCj4gT24gMDQvMDUsIFZsYWQgWmFraGFyb3Ygd3JvdGU6DQo+ ID4gDQo+ID4gSGkgU3RlcGhlbiwNCj4gPiANCj4gPiBPbiBUdWUsIDIwMTctMDQtMDQgYXQgMTg6 MzUgLTA3MDAsIFN0ZXBoZW4gQm95ZCB3cm90ZToNCj4gPiA+IA0KPiA+ID4gPiANCj4gPiA+ID4g K8KgwqDCoMKgwqAucGxsX3RhYmxlID0gKHN0cnVjdCBwbGxfb2ZfdGFibGUgW10pew0KPiA+ID4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqB7DQo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAucHJhdGUgPSAyNzAwMDAwMCwNCj4gPiA+IA0KPiA+ ID4gQ2FuIHRoaXMgYmUgYW5vdGhlciBjbGsgaW4gdGhlIGZyYW1ld29yayBpbnN0ZWFkIG9mIGhh cmRjb2RpbmcNCj4gPiA+IHRoZSBwYXJlbnQgcmF0ZT8NCj4gPiANCj4gPiBJbiBmYWN0IHRoZXJl IGlzIGFub3RoZXIgY2xrIGluIHRoZSBmcmFtZXdvcmsgdGhhdCByZXByZXNlbnRzIHRoaXMgcGFy ZW50IGNsb2NrLiBCdXQgdGhpcyBmaWVsZCBpcyBuZWVkZWQgdG8gZ2V0DQo+ID4gYXBwcm9wcmlh dGUgcGxsX2NmZ190YWJsZSBhcyBpdCBkZXBlbmRzIG9uIHBhcmVudCBjbG9jayBmcmVxdWVuY3ku IEJlbG93IGluIHBsbF9jZmdfZ2V0IGZ1bmN0aW9uIHdlIGFyZSBzZWFyY2hpbmcNCj4gPiBmb3IN Cj4gPiB0aGUgY29ycmVjdCB0YWJsZSBjb21wYXJpbmcgLnBhcmVudF9ub2RlIGZpZWxkIHdpdGgg cmVhbCBoYXJkd2FyZSBwYXJlbnQgY2xvY2sgZnJlcXVlbmN5Og0KPiA+IC0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0+OC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LQ0KPiA+IGZvciAoaSA9IDA7IHBsbF90YWJsZVtpXS5wcmF0ZSAhPSAwOyBpKyspDQo+ID4gwqAg wqAgaWYgKHBsbF90YWJsZVtpXS5wcmF0ZSA9PSBwcmF0ZSkNCj4gPiDCoCDCoCDCoCDCoCByZXR1 cm4gcGxsX3RhYmxlW2ldLnBsbF9jZmdfdGFibGU7DQo+ID4gLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLT44LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQo+IA0K PiBXaGVuIGlzIHRoYXQgZG9uZSB0aG91Z2g/IER1cmluZyByb3VuZF9yYXRlIGFuZCByZWNhbGNf cmF0ZSB0aGUNCj4gcGFyZW50IGZyZXF1ZW5jeSBpcyBwYXNzZWQgaW50byB0aGUgZnVuY3Rpb24s IHNvIGl0IHNob3VsZCBiZQ0KPiBwb3NzaWJsZSB0byB1c2UgdGhhdCBpZiB0aGUgdHJlZSBpcyBw cm9wZXJseSBleHByZXNzZWQuDQo+IA0KDQpJIHRoaW5rIHRoYXQgd2UgaGF2ZW4ndCB1bmRlcnN0 b29kIGVhY2ggb3RoZXIgY29ycmVjdGx5Lg0KQW55d2F5IEkgaGF2ZSBjaGVja2VkIG91dCBvdXIg aGFyZHdhcmUgZG9jdW1lbnRhdGlvbnMgYW5kIGZpbmQgb3V0IHRoYXQgaW4gZmFjdCBmb3IgdG9k YXkncyB2ZXJzaW9uIG9mIGhhcmR3YXJlIHdlIGRvbid0DQpoYXZlIHNpdHVhdGlvbnMgd2hlbiBz dWNoIHBsbHMgY2FuIGJlIGRyaXZlbiBieSBkaWZmZXJlbnQgcGFyZW50IGNsb2NrLiBTbyB0aGlz IGFwcHJvYWNoIGlzIG5vdCByZXF1aXJlZCBhdCB0aGUgbW9tZW50Lg0KSSBhbSBnb2luZyB0byBz aW1wbGlmeSBteSBkcml2ZXIgc28gaXQgd2lsbCByZWZsZWN0IGN1cnJlbnQgdmVyc2lvbiBvZiBo YXJkd2FyZSBhbmQgaWYgYW55dGhpbmcgY2hhbmdlcyBJIHdpbGwgYmV0dGVyDQpwcm92aWRlIGEg bmV3IHBhdGNoLg0KDQo+ID4gU3VyZS4gQ291bGQgeW91IGJlIHNvIGtpbmQgdG8gZXhwbGFpbiB3 aGF0IGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gaHcgYW5kIG5vbi1odyBiYXNlZCBwcm92aWRl ciBhbmQgY2xrDQo+ID4gcmVnaXN0cmF0aW9uDQo+ID4gZnVuY3Rpb25zIHBsZWFzZT8gSW4gd2hp Y2ggY2FzZXMgdGhleSBhcmUgcHJlZmVycmVkP8KgDQo+ID4gDQo+IA0KPiBXZSdyZSB0cnlpbmcg dG8gc3BsaXQgdGhlIGNvbnN1bWVyIGFuZCBwcm92aWRlciBBUElzIGFsb25nIHN0cnVjdA0KPiBj bGtfaHcgYW5kIHN0cnVjdCBjbGsgcmVzcGVjdGl2ZWx5LiBJZiB3ZSBjYW4gaGF2ZSBkcml2ZXJz IG9ubHkNCj4gcmVnaXN0ZXJzIGNsa19odyBwb2ludGVycyBhbmQgbmV2ZXIgZ2V0IGJhY2sgYW55 dGhpbmcgYnV0IGFuDQo+IGVycm9yIGNvZGUsIHRoZW4gd2UgY2FuIGZvcmNlIGNvbnN1bWVycyB0 byBhbHdheXMgZ28gdGhyb3VnaCB0aGUNCj4gY2xrX2dldCgpIGZhbWlseSBvZiBBUElzLiBUaGVu IHdlIGNhbiBlYXNpbHkgdGVsbCB3aG8gaXMgYQ0KPiBwcm92aWRlciwgd2hvIGlzIGEgY29uc3Vt ZXIsIGFuZCB3aG8gaXMgYSBwcm92aWRlciArIGEgY29uc3VtZXIuDQo+IFJpZ2h0IG5vdyB0aGlz IGlzbid0IGFsd2F5cyBjbGVhciBjdXQgYmVjYXVzZSBjbGtfaHcgaGFzIGFjY2Vzcw0KPiB0byBz dHJ1Y3QgY2xrLCBhbmQgYWxzbyBjbGtfcmVnaXN0ZXIoKSByZXR1cm5zIGEgY2xrIHBvaW50ZXIs IGJ1dA0KPiBpdCBkb2Vzbid0IHJlYWxseSBnZXQgdXNlZCBieSBhbnl0aGluZyBpbiBhIHByb3Zp ZGVyIGRyaXZlciwNCj4gdW5sZXNzIHByb3ZpZGVyIGRyaXZlcnMgYXJlIGRvaW5nIHNvbWV0aGlu ZyB3aXRoIHRoZSBjb25zdW1lcg0KPiBBUEkuDQoNCkkgYW0gc29ycnkgZm9yIG15IGZvb2xpc2gg cXVlc3Rpb25zLCBidXQgYXMgSSB1bmRlcnN0YW5kIEkgc2hvdWxkIHVzZSBody1iYXNlZCBmdW5j dGlvbnMgZm9yIGNsayBwcm92aWRlcnMgYnV0IGl0IGlzIG5vdA0Kc3RpbGwgY2xlYXIgZW5vdWdo IGZvciBtZSB3aGVuIHNob3VsZCBJIHVzZSBub24taHcgZnVuY3Rpb25zPyBEb2VzIGFueSBkcml2 ZXJzIG5lZWQgc3RydWN0IGNsayB3aGVuIHRoZXkgYXJlIGluaXRpYXRpbmcNCm9yIHByb2Jpbmcg dGhlbXNlbHZlcz8gQW5kIHdoYXQgY2xrIGNvbnN1bWVyIGNhbiBiZSB1c2VkIGZvcj8NCg0KPiAN Cj4gPiANCj4gPiA+IA0KPiA+ID4gDQo+ID4gPiA+IA0KPiA+ID4gPiArfQ0KPiA+ID4gPiArDQo+ ID4gPiA+ICtDTEtfT0ZfREVDTEFSRShheHMxMHhfcGxsX2Nsb2NrLCAic25wcyxheHMxMHgtYXJj LXBsbC1jbG9jayIsIG9mX3BsbF9jbGtfc2V0dXApOw0KPiA+ID4gDQo+ID4gPiBEb2VzIHRoaXMg bmVlZCB0byBiZSBDTEtfT0ZfREVDTEFSRV9EUklWRVI/IEkgbWVhbiBkb2VzIHRoZQ0KPiA+ID4g ZHJpdmVyIG5lZWQgdG8gcHJvYmUgYW5kIGFsc28gaGF2ZSB0aGlzIG9mIGRlY2xhcmUgaGFwcGVu PyBJcyB0aGUNCj4gPiA+IFBMTCBzcGVjaWFsIGFuZCBuZWVkcyB0byBiZSB1c2VkIGZvciB0aGUg dGltZXJzPw0KPiA+IA0KPiA+IEl0IGlzIHNwZWNpYWwgYW5kIGlzIHVzZWQgZm9yIHRoZSB0aW1l cnMsIHNvIHdlIGhhdmUgdG8gQ0xLX09GX0RFQ0xBUkUgaXQuIE9uIHRoZSBvdGhlciBoYW5kIHNp bWlsYXIgcGxsIGlzIHVzZWQgdG8NCj4gPiBkcml2ZSBQR1UgY2xvY2sgZnJlcXVlbmN5IGFuZCBv dGhlciBzdWJzeXN0ZW1zIGFuZCBzbyB3ZSBhZGQgdXN1YWwgcHJvYmUgZnVuYy4NCj4gPiANCj4g DQo+IFByZXN1bWFibHkgd2UnbGwgaGF2ZSBkaWZmZXJlbnQgY29tcGF0aWJsZSBzdHJpbmdzIGZv ciB0aGUNCj4gZGlmZmVyZW50IFBMTHMgdGhlbj8gQ0xLX09GX0RFQ0xBUkUoKSB3aWxsIG1ha2Ug aXQgc28gdGhhdCB0aGUNCj4gZGV2aWNlIG5vZGUgdGhhdCBtYXRjaGVzIG5ldmVyIGdldHMgYSAt PnByb2JlKCkgZnJvbSBhDQo+IHBsYXRmb3JtX2RyaXZlciBjYWxsZWQgb24gaXQuIElmIHlvdSB3 YW50IGl0IHRvIGJlIGNhbGxlZCB0d2ljZSwNCj4gdGhlbiB5b3UgbmVlZCB0byB1c2UgQ0xLX09G X0RFQ0xBUkVfRFJJVkVSKCkgaW5zdGVhZC4NCj4gDQoNCkluIGZhY3Qgd2UgZG9uJ3QgbmVlZCBp dCB0byBiZSBjYWxsZWQgdHdpY2UuIEFuZCBhcyB5b3UgY2FuIHNlZSBJIGRvIHByYWN0aWNhbGx5 IHRoZSBzYW1lIHRoaW5ncyBpbiBzZXR1cCBhbmQgcHJvYmUNCmZ1bmN0aW9ucy4gU28gbWF5YmUg SSBjYW4gc29tZWhvdyBhdm9pZCB0aGlzIGNvZGUgZHVwbGljYXRpb24/wqANCkkgbWVhbiB0aGF0 IHRoaXMgZHJpdmVyIGlzIGdvaW5nIGVpdGhlciB0byBiZSB1c2VkIGZvciB0aGUgdGltZXJzIG9y IGFzIGEgc2ltcGxlIHBsYXRmb3JtIGRyaXZlciBmb3IgY2xvY2tpbmcgc29tZQ0KcGVyaXBoZXJh cy4gU28gZm9yIHRoZSBmaXJzdCBjYXNlIEkgaGF2ZSB3cml0dGVuIGEgc2V0dXAgZnVuY3Rpb24g dG8gQ0xLX09GX0RFQ0xBUkUgbXkgZHJpdmVyIGFuZCBmb3IgdGhlIHNlY29uZCBjYXNlDQpJJ3Zl IHdyaXR0ZW4gdXN1YWwgcHJvYmUgZnVuY3Rpb24uIE1heWJlIEkgYW0gbWlzdGFrZW4gYW5kIGl0 IGlzIG5vdCB0aGUgcmlnaHQgd2F5Pw0KDQpUaGFuayB5b3UgZm9yIHlvdSBhbnN3ZXJzLsKgDQoN Ci0tIA0KQmVzdCByZWdhcmRzLA0KVmxhZCBaYWtoYXJvdiA8dnpha2hhckBzeW5vcHN5cy5jb20+ -- To unsubscribe from this list: send the line "unsubscribe linux-clk" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt new file mode 100644 index 0000000..5706246 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt @@ -0,0 +1,28 @@ +Binding for the AXS10X Generic PLL clock + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: should be "snps,axs10x-<name>-pll-clock" + "snps,axs10x-arc-pll-clock" + "snps,axs10x-pgu-pll-clock" +- reg: should always contain 2 pairs address - length: first for PLL config +registers and second for corresponding LOCK CGU register. +- clocks: shall be the input parent clock phandle for the PLL. +- #clock-cells: from common clock binding; Should always be set to 0. + +Example: + input-clk: input-clk { + clock-frequency = <33333333>; + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + core-clk: core-clk@80 { + compatible = "snps,axs10x-arc-pll-clock"; + reg = <0x80 0x10 0x100 0x10>; + #clock-cells = <0>; + clocks = <&input-clk>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 3960e7f..5805833 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11910,6 +11910,12 @@ F: arch/arc/plat-axs10x F: arch/arc/boot/dts/ax* F: Documentation/devicetree/bindings/arc/axs10* +SYNOPSYS ARC SDP clock driver +M: Vlad Zakharov <vzakhar@synopsys.com> +S: Supported +F: drivers/clk/axs10x/* +F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt + SYSTEM CONFIGURATION (SYSCON) M: Lee Jones <lee.jones@linaro.org> M: Arnd Bergmann <arnd@arndb.de> diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile index 01996b8..d747dea 100644 --- a/drivers/clk/axs10x/Makefile +++ b/drivers/clk/axs10x/Makefile @@ -1 +1,2 @@ obj-y += i2s_pll_clock.o +obj-y += pll_clock.o diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c new file mode 100644 index 0000000..784a0a2 --- /dev/null +++ b/drivers/clk/axs10x/pll_clock.c @@ -0,0 +1,384 @@ +/* + * Synopsys AXS10X SDP Generic PLL clock driver + * + * Copyright (C) 2017 Synopsys + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/device.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/slab.h> +#include <linux/of.h> + +/* PLL registers addresses */ +#define PLL_REG_IDIV 0x0 +#define PLL_REG_FBDIV 0x4 +#define PLL_REG_ODIV 0x8 + +/* + * Bit fields of the PLL IDIV/FBDIV/ODIV registers: + * ________________________________________________________________________ + * |31 15| 14 | 13 | 12 |11 6|5 0| + * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--| + * |____________________|__________|________|______|____________|___________| + * + * Following macros detirmine the way of access to these registers + * They should be set up only using the macros. + * reg should be and uint32_t variable. + */ + +#define PLL_REG_GET_LOW(reg) \ + (((reg) & (0x3F << 0)) >> 0) +#define PLL_REG_GET_HIGH(reg) \ + (((reg) & (0x3F << 6)) >> 6) +#define PLL_REG_GET_EDGE(reg) \ + (((reg) & (BIT(12))) ? 1 : 0) +#define PLL_REG_GET_BYPASS(reg) \ + (((reg) & (BIT(13))) ? 1 : 0) +#define PLL_REG_GET_NOUPD(reg) \ + (((reg) & (BIT(14))) ? 1 : 0) +#define PLL_REG_GET_PAD(reg) \ + (((reg) & (0x1FFFF << 15)) >> 15) + +#define PLL_REG_SET_LOW(reg, value) \ + { reg |= (((value) & 0x3F) << 0); } +#define PLL_REG_SET_HIGH(reg, value) \ + { reg |= (((value) & 0x3F) << 6); } +#define PLL_REG_SET_EDGE(reg, value) \ + { reg |= (((value) & 0x01) << 12); } +#define PLL_REG_SET_BYPASS(reg, value) \ + { reg |= (((value) & 0x01) << 13); } +#define PLL_REG_SET_NOUPD(reg, value) \ + { reg |= (((value) & 0x01) << 14); } +#define PLL_REG_SET_PAD(reg, value) \ + { reg |= (((value) & 0x1FFFF) << 15); } + +#define PLL_LOCK 0x1 +#define PLL_MAX_LOCK_TIME 100 /* 100 us */ + +struct pll_cfg { + u32 rate; + u32 idiv; + u32 fbdiv; + u32 odiv; +}; + +struct pll_of_table { + unsigned long prate; + struct pll_cfg *pll_cfg_table; +}; + +struct pll_of_data { + struct pll_of_table *pll_table; +}; + +static struct pll_of_data pgu_pll_data = { + .pll_table = (struct pll_of_table []){ + { + .prate = 27000000, + .pll_cfg_table = (struct pll_cfg []){ + { 25200000, 1, 84, 90 }, + { 50000000, 1, 100, 54 }, + { 74250000, 1, 44, 16 }, + { }, + }, + }, + /* Used as list limiter */ + { }, + }, +}; + +static struct pll_of_data arc_pll_data = { + .pll_table = (struct pll_of_table []){ + { + .prate = 33333333, + .pll_cfg_table = (struct pll_cfg []){ + { 33333333, 1, 1, 1 }, + { 50000000, 1, 30, 20 }, + { 75000000, 2, 45, 10 }, + { 90000000, 2, 54, 10 }, + { 100000000, 1, 30, 10 }, + { 125000000, 2, 45, 6 }, + { }, + }, + }, + /* Used as list limiter */ + { }, + }, +}; + +struct pll_clk { + void __iomem *base; + void __iomem *lock; + const struct pll_of_data *pll_data; + struct clk_hw hw; + struct device *dev; +}; + +static inline void pll_write(struct pll_clk *clk, unsigned int reg, + unsigned int val) +{ + iowrite32(val, clk->base + reg); +} + +static inline u32 pll_read(struct pll_clk *clk, + unsigned int reg) +{ + return ioread32(clk->base + reg); +} + +static inline struct pll_clk *to_pll_clk(struct clk_hw *hw) +{ + return container_of(hw, struct pll_clk, hw); +} + +static inline u32 div_get_value(unsigned int reg) +{ + if (PLL_REG_GET_BYPASS(reg)) + return 1; + + return (PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg)); +} + +static inline u32 encode_div(unsigned int id, int upd) +{ + uint32_t div = 0; + + PLL_REG_SET_LOW(div, (id%2 == 0) ? id >> 1 : (id >> 1) + 1); + PLL_REG_SET_HIGH(div, id >> 1); + PLL_REG_SET_EDGE(div, id%2); + PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0); + PLL_REG_SET_NOUPD(div, !upd); + + return div; +} + +static const struct pll_cfg *pll_get_cfg(unsigned long prate, + const struct pll_of_table *pll_table) +{ + int i; + + for (i = 0; pll_table[i].prate != 0; i++) + if (pll_table[i].prate == prate) + return pll_table[i].pll_cfg_table; + + return NULL; +} + +static unsigned long pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u64 rate; + u32 idiv, fbdiv, odiv; + struct pll_clk *clk = to_pll_clk(hw); + + idiv = div_get_value(pll_read(clk, PLL_REG_IDIV)); + fbdiv = div_get_value(pll_read(clk, PLL_REG_FBDIV)); + odiv = div_get_value(pll_read(clk, PLL_REG_ODIV)); + + rate = (u64)parent_rate * fbdiv; + do_div(rate, idiv * odiv); + + return (unsigned long)rate; +} + +static long pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + long best_rate; + struct pll_clk *clk = to_pll_clk(hw); + const struct pll_cfg *pll_cfg = pll_get_cfg(*prate, + clk->pll_data->pll_table); + + if (!pll_cfg) { + dev_err(clk->dev, "invalid parent rate=%ld\n", *prate); + return -EINVAL; + } + + if (pll_cfg[0].rate == 0) + return -EINVAL; + + best_rate = pll_cfg[0].rate; + + for (i = 1; pll_cfg[i].rate != 0; i++) { + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) + best_rate = pll_cfg[i].rate; + } + + return best_rate; +} + +static int pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int i; + struct pll_clk *clk = to_pll_clk(hw); + const struct pll_cfg *pll_cfg = pll_get_cfg(parent_rate, + clk->pll_data->pll_table); + + if (!pll_cfg) { + dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate); + return -EINVAL; + } + + for (i = 0; pll_cfg[i].rate != 0; i++) { + if (pll_cfg[i].rate == rate) { + pll_write(clk, PLL_REG_IDIV, + encode_div(pll_cfg[i].idiv, 0)); + pll_write(clk, PLL_REG_FBDIV, + encode_div(pll_cfg[i].fbdiv, 0)); + pll_write(clk, PLL_REG_ODIV, + encode_div(pll_cfg[i].odiv, 1)); + + /* + * Wait until CGU relocks. + * If after timeout CGU is unlocked yet return error + */ + udelay(PLL_MAX_LOCK_TIME); + if (ioread32(clk->lock) & PLL_LOCK) + return 0; + else + return -ETIMEDOUT; + } + } + + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate, + parent_rate); + return -EINVAL; +} + +static const struct clk_ops pll_ops = { + .recalc_rate = pll_recalc_rate, + .round_rate = pll_round_rate, + .set_rate = pll_set_rate, +}; + +static int pll_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const char *parent_name; + struct clk *clk; + struct pll_clk *pll_clk; + struct resource *mem; + struct clk_init_data init = { }; + + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL); + if (!pll_clk) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pll_clk->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(pll_clk->base)) + return PTR_ERR(pll_clk->base); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + pll_clk->lock = devm_ioremap_resource(dev, mem); + if (IS_ERR(pll_clk->lock)) + return PTR_ERR(pll_clk->base); + + init.name = dev->of_node->name; + init.ops = &pll_ops; + parent_name = of_clk_get_parent_name(dev->of_node, 0); + init.parent_names = &parent_name; + init.num_parents = 1; + pll_clk->hw.init = &init; + pll_clk->dev = dev; + pll_clk->pll_data = of_device_get_match_data(dev); + + if (!pll_clk->pll_data) { + dev_err(dev, "No OF match data provided\n"); + return -EINVAL; + } + + clk = devm_clk_register(dev, &pll_clk->hw); + if (IS_ERR(clk)) { + dev_err(dev, "failed to register %s clock (%ld)\n", + init.name, PTR_ERR(clk)); + return PTR_ERR(clk); + } + + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, clk); +} + +static int pll_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +static void __init of_pll_clk_setup(struct device_node *node) +{ + const char *parent_name; + struct clk *clk; + struct pll_clk *pll_clk; + struct clk_init_data init = { }; + + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); + if (!pll_clk) + return; + + pll_clk->base = of_iomap(node, 0); + if (!pll_clk->base) { + pr_err("failed to map pll div registers\n"); + iounmap(pll_clk->base); + return; + } + + pll_clk->lock = of_iomap(node, 1); + if (!pll_clk->lock) { + pr_err("failed to map pll lock register\n"); + iounmap(pll_clk->lock); + return; + } + + init.name = node->name; + init.ops = &pll_ops; + parent_name = of_clk_get_parent_name(node, 0); + init.parent_names = &parent_name; + init.num_parents = parent_name ? 1 : 0; + pll_clk->hw.init = &init; + pll_clk->pll_data = &arc_pll_data; + + clk = clk_register(NULL, &pll_clk->hw); + if (IS_ERR(clk)) { + pr_err("failed to register %s clock (%ld)\n", + node->name, PTR_ERR(clk)); + kfree(pll_clk); + return; + } + + of_clk_add_provider(node, of_clk_src_simple_get, clk); +} + +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup); + +static const struct of_device_id pll_clk_id[] = { + { .compatible = "snps,axs10x-arc-pll-clock", .data = &arc_pll_data}, + { .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_data}, + { }, +}; +MODULE_DEVICE_TABLE(of, pll_clk_id); + +static struct platform_driver pll_clk_driver = { + .driver = { + .name = "axs10x-pll-clock", + .of_match_table = pll_clk_id, + }, + .probe = pll_clk_probe, + .remove = pll_clk_remove, +}; +builtin_platform_driver(pll_clk_driver); + +MODULE_AUTHOR("Vlad Zakharov <vzakhar@synopsys.com>"); +MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver"); +MODULE_LICENSE("GPL v2");