From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [RFC,v2,07/15] usb:cdns3: Adds Device mode support - initialization. From: Roger Quadros Message-Id: <5BFE7D2E.7030702@ti.com> Date: Wed, 28 Nov 2018 13:34:06 +0200 To: Pawel Laszczak , devicetree@vger.kernel.org, Felipe Balbi Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, adouglas@cadence.com, jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com, sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com, kurahul@cadence.com List-ID: K0ZlbGlwZS4KClBhd2VsLAoKUGxlYXNlIGNvcHkgRmVsaXBlIEJhbGJpIGFzIGhlIG1haW50YWlu cyB0aGUgVVNCIGdhZGdldCBzdGFjay4KCk9uIDE4LzExLzE4IDEyOjA5LCBQYXdlbCBMYXN6Y3ph ayB3cm90ZToKPiBQYXRjaCBpbXBsZW1lbnRzIGEgc2V0IG9mIGZ1bmN0aW9ucyByZXNwb25zaWJs ZSBmb3IgaW5pdGlhbGl6YXRpb24sCj4gY29uZmlndXJhdGlvbiwgc3RhcnRpbmcgYW5kIHN0b3Bw aW5nIGRldmljZSBtb2RlLgo+IFRoaXMgcGF0Y2ggYWxzbyBhZGRzIG5ldyBlcDAuYyB0aGF0IGhv bGRzIGFsbCBmdW5jdGlvbnMgcmVsYXRlZAo+IHRvIGVuZHBvaW50IDAuCj4gCj4gU2lnbmVkLW9m Zi1ieTogUGF3ZWwgTGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4KPiAtLS0KPiAgZHJpdmVy cy91c2IvY2RuczMvS2NvbmZpZyAgICAgICAgIHwgIDEwICsKPiAgZHJpdmVycy91c2IvY2RuczMv TWFrZWZpbGUgICAgICAgIHwgICAxICsKPiAgZHJpdmVycy91c2IvY2RuczMvY29yZS5jICAgICAg ICAgIHwgICA1ICstCj4gIGRyaXZlcnMvdXNiL2NkbnMzL2VwMC5jICAgICAgICAgICB8IDEwNSAr KysrKysrKwo+ICBkcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQtZXhwb3J0LmggfCAgMjcgKysrCj4g IGRyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5jICAgICAgICB8IDM5MCArKysrKysrKysrKysrKysr KysrKysrKysrKysrKysKPiAgZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmggICAgICAgIHwgICA0 ICsKPiAgNyBmaWxlcyBjaGFuZ2VkLCA1NDEgaW5zZXJ0aW9ucygrKSwgMSBkZWxldGlvbigtKQo+ ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvZXAwLmMKPiAgY3JlYXRlIG1v ZGUgMTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC1leHBvcnQuaAo+ICBjcmVhdGUgbW9k ZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmMKPiAKPiBkaWZmIC0tZ2l0IGEvZHJp dmVycy91c2IvY2RuczMvS2NvbmZpZyBiL2RyaXZlcnMvdXNiL2NkbnMzL0tjb25maWcKPiBpbmRl eCBkOTJiYzNkNjhlYjAuLmI3ZDcxYjVjNGY2MCAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL3VzYi9j ZG5zMy9LY29uZmlnCj4gKysrIGIvZHJpdmVycy91c2IvY2RuczMvS2NvbmZpZwo+IEBAIC0xMCw2 ICsxMCwxNiBAQCBjb25maWcgVVNCX0NETlMzCj4gIAo+ICBpZiBVU0JfQ0ROUzMKPiAgCj4gK2Nv bmZpZyBVU0JfQ0ROUzNfR0FER0VUCj4gKyAgICAgICAgYm9vbCAiQ2FkZW5jZSBVU0IzIGRldmlj ZSBjb250cm9sbGVyIgo+ICsgICAgICAgIGRlcGVuZHMgb24gVVNCX0dBREdFVAo+ICsgICAgICAg IGhlbHAKPiArICAgICAgICAgIFNheSBZIGhlcmUgdG8gZW5hYmxlIGRldmljZSBjb250cm9sbGVy IGZ1bmN0aW9uYWxpdHkgb2YgdGhlCj4gKyAgICAgICAgICBjYWRlbmNlIFVTQlNTLURFViBkcml2 ZXIuCj4gKwo+ICsgICAgICAgICAgVGhpcyBjb250cm9sbGVyIHN1cHBvcnQgRkYsIEhTIGFuZCBT UyBtb2RlLiBJdCBkb2Vhc24ndCBzdXBwb3J0CgpzL3N1cHBvcnQvc3VwcG9ydHMKcy9kb2Vhc24n dC9kb2Vzbid0Cgo+ICsgICAgICAgICAgTFMgYW5kIFNTUCBtb2RlCj4gKwo+ICBjb25maWcgVVNC X0NETlMzX0hPU1QKPiAgICAgICAgICBib29sICJDYWRlbmNlIFVTQjMgaG9zdCBjb250cm9sbGVy Igo+ICAgICAgICAgIGRlcGVuZHMgb24gVVNCX1hIQ0lfSENECj4gZGlmZiAtLWdpdCBhL2RyaXZl cnMvdXNiL2NkbnMzL01ha2VmaWxlIGIvZHJpdmVycy91c2IvY2RuczMvTWFrZWZpbGUKPiBpbmRl eCA5NzYxMTdiYTY3ZmYuLmJlYTYxNzNiZjM3ZiAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL3VzYi9j ZG5zMy9NYWtlZmlsZQo+ICsrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL01ha2VmaWxlCj4gQEAgLTIs NSArMiw2IEBAIG9iai0kKENPTkZJR19VU0JfQ0ROUzMpCQkJKz0gY2RuczMubwo+ICBvYmotJChD T05GSUdfVVNCX0NETlMzX1BDSV9XUkFQKQkrPSBjZG5zMy1wY2kubwo+ICAKPiAgY2RuczMteQkJ CQkJOj0gY29yZS5vIGRyZC5vCj4gK2NkbnMzLSQoQ09ORklHX1VTQl9DRE5TM19HQURHRVQpCSs9 IGdhZGdldC5vIGVwMC5vCj4gIGNkbnMzLSQoQ09ORklHX1VTQl9DRE5TM19IT1NUKSAgICAgICAg ICArPSBob3N0Lm8KPiAgY2RuczMtcGNpLXkJCSAJCTo9IGNkbnMzLXBjaS13cmFwLm8KPiBkaWZm IC0tZ2l0IGEvZHJpdmVycy91c2IvY2RuczMvY29yZS5jIGIvZHJpdmVycy91c2IvY2RuczMvY29y ZS5jCj4gaW5kZXggNGNiODIwYmU5ZmYzLi4xZmEyMzM0MTU5MDEgMTAwNjQ0Cj4gLS0tIGEvZHJp dmVycy91c2IvY2RuczMvY29yZS5jCj4gKysrIGIvZHJpdmVycy91c2IvY2RuczMvY29yZS5jCj4g QEAgLTE4LDYgKzE4LDcgQEAKPiAgI2luY2x1ZGUgImdhZGdldC5oIgo+ICAjaW5jbHVkZSAiY29y ZS5oIgo+ICAjaW5jbHVkZSAiaG9zdC1leHBvcnQuaCIKPiArI2luY2x1ZGUgImdhZGdldC1leHBv cnQuaCIKPiAgI2luY2x1ZGUgImRyZC5oIgo+ICAKPiAgc3RhdGljIGlubGluZSBzdHJ1Y3QgY2Ru czNfcm9sZV9kcml2ZXIgKmNkbnMzX2dldF9jdXJyZW50X3JvbGVfZHJpdmVyKHN0cnVjdCBjZG5z MyAqY2RucykKPiBAQCAtMTA0LDcgKzEwNSw4IEBAIHN0YXRpYyBpbnQgY2RuczNfY29yZV9pbml0 X3JvbGUoc3RydWN0IGNkbnMzICpjZG5zKQo+ICAJfQo+ICAKPiAgCWlmIChkcl9tb2RlID09IFVT Ql9EUl9NT0RFX09URyB8fCBkcl9tb2RlID09IFVTQl9EUl9NT0RFX1BFUklQSEVSQUwpIHsKPiAt CQkvL1RPRE86IGltcGxlbWVudHMgZGV2aWNlIGluaXRpYWxpemF0aW9uCj4gKwkJaWYgKGNkbnMz X2dhZGdldF9pbml0KGNkbnMpKQo+ICsJCQlkZXZfaW5mbyhkZXYsICJkb2Vzbid0IHN1cHBvcnQg Z2FkZ2V0XG4iKTsKCmRldl9lcnIoKSBhbmQgd2Ugc2hvdWxkIHNob3VsZCBlcnJvciBvdXQgd2l0 aCBlcnJvciBjb2RlIHJldHVybmVkIGJ5IGNkbnMzX2dhZGdldF9pbml0KCkuCgo+ICAJfQo+ICAK PiAgCWlmICghY2Rucy0+cm9sZXNbQ0ROUzNfUk9MRV9IT1NUXSAmJiAhY2Rucy0+cm9sZXNbQ0RO UzNfUk9MRV9HQURHRVRdKSB7Cj4gQEAgLTE0NCw2ICsxNDYsNyBAQCBzdGF0aWMgaXJxcmV0dXJu X3QgY2RuczNfaXJxKGludCBpcnEsIHZvaWQgKmRhdGEpCj4gIAo+ICBzdGF0aWMgdm9pZCBjZG5z M19yZW1vdmVfcm9sZXMoc3RydWN0IGNkbnMzICpjZG5zKQo+ICB7CgppZiAoZHJfbW9kZSA9PSBV U0JfRFJfTU9ERV9PVEcgfHwgZHJfbW9kZSA9PSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMKQoKPiAr CWNkbnMzX2dhZGdldF9yZW1vdmUoY2Rucyk7Cj4gIAljZG5zM19ob3N0X3JlbW92ZShjZG5zKTsK PiAgfQo+ICAKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvY2RuczMvZXAwLmMgYi9kcml2ZXJz L3VzYi9jZG5zMy9lcDAuYwo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAw MDAwLi5jMDhkMDI2NjVmOWQKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVycy91c2IvY2Ru czMvZXAwLmMKPiBAQCAtMCwwICsxLDEwNSBAQAo+ICsvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmll cjogR1BMLTIuMAo+ICsvKgo+ICsgKiBDYWRlbmNlIFVTQlNTIERSRCBEcml2ZXIgLSBnYWRnZXQg c2lkZS4KPiArICoKPiArICogQ29weXJpZ2h0IChDKSAyMDE4IENhZGVuY2UgRGVzaWduIFN5c3Rl bXMuCj4gKyAqIENvcHlyaWdodCAoQykgMjAxNyBOWFAKPiArICoKPiArICogQXV0aG9yczogUGF3 ZWwgSmV6IDxwamV6QGNhZGVuY2UuY29tPiwKPiArICogICAgICAgICAgUGF3ZWwgTGFzemN6YWsg PHBhd2VsbEBjYWRlbmNlLmNvbT4KPiArICoJICAgIFBldGVyIENoZW4gPHBldGVyLmNoZW5Abnhw LmNvbT4KPiArICovCj4gKwo+ICsjaW5jbHVkZSAiZ2FkZ2V0LmgiCj4gKwo+ICtzdGF0aWMgc3Ry dWN0IHVzYl9lbmRwb2ludF9kZXNjcmlwdG9yIGNkbnMzX2dhZGdldF9lcDBfZGVzYyA9IHsKPiAr CS5iTGVuZ3RoID0gVVNCX0RUX0VORFBPSU5UX1NJWkUsCj4gKwkuYkRlc2NyaXB0b3JUeXBlID0g VVNCX0RUX0VORFBPSU5ULAo+ICsJLmJtQXR0cmlidXRlcyA9CVVTQl9FTkRQT0lOVF9YRkVSX0NP TlRST0wsCj4gK307Cj4gKwo+ICtzdGF0aWMgdm9pZCBjZG5zM19wcmVwYXJlX3NldHVwX3BhY2tl dChzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldikKPiArewo+ICsJLy9UT0RPOiBJbXBsZW1l bnRzIHRoaXMgZnVuY3Rpb24KPiArfQo+ICsKPiArLyoqCj4gKyAqIGNkbnMzX2VwMF9jb25maWcg LSBDb25maWd1cmVzIGRlZmF1bHQgZW5kcG9pbnQKPiArICogQHByaXZfZGV2OiBleHRlbmRlZCBn YWRnZXQgb2JqZWN0Cj4gKyAqCj4gKyAqIEZ1bmN0aW9ucyBzZXRzIHBhcmFtZXRlcnM6IG1heGlt YWwgcGFja2V0IHNpemUgYW5kIGVuYWJsZXMgaW50ZXJydXB0cwo+ICsgKi8KPiArdm9pZCBjZG5z M19lcDBfY29uZmlnKHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2KQo+ICt7Cj4gKwlzdHJ1 Y3QgY2RuczNfdXNiX3JlZ3MgX19pb21lbSAqcmVnczsKPiArCXUzMiBtYXhfcGFja2V0X3NpemUg PSA2NDsKPiArCj4gKwlyZWdzID0gcHJpdl9kZXYtPnJlZ3M7Cj4gKwo+ICsJaWYgKHByaXZfZGV2 LT5nYWRnZXQuc3BlZWQgPT0gVVNCX1NQRUVEX1NVUEVSKQo+ICsJCW1heF9wYWNrZXRfc2l6ZSA9 IDUxMjsKCmlzIGdhZGdldC5zcGVlZCBrbm93biBhdCB0aGlzIHBvaW50PyBJIHRoaW5rIGl0IHdp bGwgb25seSBiZSBrbm93biBhZnRlciBhIGNvbm5lY3Rpb24KaXMgbWFkZS4KCj4gKwo+ICsJaWYg KHByaXZfZGV2LT5lcDBfcmVxdWVzdCkgewo+ICsJCWxpc3RfZGVsX2luaXQoJnByaXZfZGV2LT5l cDBfcmVxdWVzdC0+bGlzdCk7Cj4gKwkJcHJpdl9kZXYtPmVwMF9yZXF1ZXN0ID0gTlVMTDsKPiAr CX0KPiArCj4gKwlwcml2X2Rldi0+Z2FkZ2V0LmVwMC0+bWF4cGFja2V0ID0gbWF4X3BhY2tldF9z aXplOwo+ICsJY2RuczNfZ2FkZ2V0X2VwMF9kZXNjLndNYXhQYWNrZXRTaXplID0gY3B1X3RvX2xl MTYobWF4X3BhY2tldF9zaXplKTsKPiArCj4gKwkvKiBpbml0IGVwIG91dCAqLwo+ICsJY2RuczNf c2VsZWN0X2VwKHByaXZfZGV2LCBVU0JfRElSX09VVCk7Cj4gKwo+ICsJd3JpdGVsKEVQX0NGR19F TkFCTEUgfCBFUF9DRkdfTUFYUEtUU0laRShtYXhfcGFja2V0X3NpemUpLAo+ICsJICAgICAgICZy ZWdzLT5lcF9jZmcpOwo+ICsKPiArCXdyaXRlbChFUF9TVFNfRU5fU0VUVVBFTiB8IEVQX1NUU19F Tl9ERVNDTUlTRU4gfCBFUF9TVFNfRU5fVFJCRVJSRU4sCj4gKwkgICAgICAgJnJlZ3MtPmVwX3N0 c19lbik7Cj4gKwo+ICsJLyogaW5pdCBlcCBpbiAqLwo+ICsJY2RuczNfc2VsZWN0X2VwKHByaXZf ZGV2LCBVU0JfRElSX0lOKTsKPiArCj4gKwl3cml0ZWwoRVBfQ0ZHX0VOQUJMRSB8IEVQX0NGR19N QVhQS1RTSVpFKG1heF9wYWNrZXRfc2l6ZSksCj4gKwkgICAgICAgJnJlZ3MtPmVwX2NmZyk7Cj4g Kwo+ICsJd3JpdGVsKEVQX1NUU19FTl9TRVRVUEVOIHwgRVBfU1RTX0VOX1RSQkVSUkVOLCAmcmVn cy0+ZXBfc3RzX2VuKTsKPiArCj4gKwljZG5zM19zZXRfcmVnaXN0ZXJfYml0KCZyZWdzLT51c2Jf Y29uZiwgVVNCX0NPTkZfVTFEUyB8IFVTQl9DT05GX1UyRFMpOwo+ICsJY2RuczNfcHJlcGFyZV9z ZXR1cF9wYWNrZXQocHJpdl9kZXYpOwoKV2hhdCBoYXBwZW5zIGlmIGdhZGdldC5zcGVlZCBpcyBV U0JfU1BFRURfU1VQRVIsIGJ1dCB3YXMgY29ubmVjdGVkIHRvIGEgaGlnaC1zcGVlZCBob3N0PwpB cmUgeW91IHVwZGF0aW5nIHRoZSBtYXhfcGFja2V0X3NpemUgb24gY29ubmVjdGlvbiBkb25lPwoK PiArfQo+ICsKPiArLyoqCj4gKyAqIGNkbnMzX2luaXRfZXAwIEluaXRpYWxpemVzIHNvZnR3YXJl IGVuZHBvaW50IDAgb2YgZ2FkZ2V0Cj4gKyAqIEBjZG5zMzogZXh0ZW5kZWQgZ2FkZ2V0IG9iamVj dAo+ICsgKgo+ICsgKiBSZXR1cm5zIDAgb24gc3VjY2VzcywgZXJyb3IgY29kZSBlbHNld2hlcmUK PiArICovCj4gK2ludCBjZG5zM19pbml0X2VwMChzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2Rl dikKPiArewo+ICsJc3RydWN0IGNkbnMzX2VuZHBvaW50ICplcDA7Cj4gKwo+ICsJZXAwID0gZGV2 bV9remFsbG9jKCZwcml2X2Rldi0+ZGV2LCBzaXplb2Yoc3RydWN0IGNkbnMzX2VuZHBvaW50KSwK PiArCQkJICAgR0ZQX0tFUk5FTCk7Cj4gKwo+ICsJaWYgKCFlcDApCj4gKwkJcmV0dXJuIC1FTk9N RU07Cj4gKwo+ICsJZXAwLT5jZG5zM19kZXYgPSBwcml2X2RldjsKPiArCXNwcmludGYoZXAwLT5u YW1lLCAiZXAwIik7Cj4gKwo+ICsJLyogZmlsbCBsaW51eCBmaWVsZHMgKi8KPiArCS8vVE9ETzog aW1wbGVtZW50cyBjZG5zM19nYWRnZXRfZXAwX29wcyBvYmplY3QKPiArCS8vZXAwLT5lbmRwb2lu dC5vcHMgPSAmY2RuczNfZ2FkZ2V0X2VwMF9vcHM7Cj4gKwllcDAtPmVuZHBvaW50Lm1heGJ1cnN0 ID0gMTsKPiArCXVzYl9lcF9zZXRfbWF4cGFja2V0X2xpbWl0KCZlcDAtPmVuZHBvaW50LCBFTkRQ T0lOVDBfTUFYX1BBQ0tFVF9MSU1JVCk7Cj4gKwllcDAtPmVuZHBvaW50LmFkZHJlc3MgPSAwOwo+ ICsJZXAwLT5lbmRwb2ludC5jYXBzLnR5cGVfY29udHJvbCA9IDE7Cj4gKwllcDAtPmVuZHBvaW50 LmNhcHMuZGlyX2luID0gMTsKPiArCWVwMC0+ZW5kcG9pbnQuY2Fwcy5kaXJfb3V0ID0gMTsKPiAr CWVwMC0+ZW5kcG9pbnQubmFtZSA9IGVwMC0+bmFtZTsKPiArCWVwMC0+ZW5kcG9pbnQuZGVzYyA9 ICZjZG5zM19nYWRnZXRfZXAwX2Rlc2M7Cj4gKwlwcml2X2Rldi0+Z2FkZ2V0LmVwMCA9ICZlcDAt PmVuZHBvaW50Owo+ICsJSU5JVF9MSVNUX0hFQUQoJmVwMC0+cmVxdWVzdF9saXN0KTsKPiArCj4g KwlyZXR1cm4gMDsKPiArfQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQt ZXhwb3J0LmggYi9kcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQtZXhwb3J0LmgKPiBuZXcgZmlsZSBt b2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAwMC4uMjU3ZTVlMGVlZjMxCj4gLS0tIC9kZXYv bnVsbAo+ICsrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC1leHBvcnQuaAo+IEBAIC0wLDAg KzEsMjcgQEAKPiArLyogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAgKi8KPiArLyoK PiArICogQ2FkZW5jZSBVU0JTUyBEUkQgRHJpdmVyIC1HYWRnZXQgRXhwb3J0IEFQSXMKPiArICoK PiArICogQ29weXJpZ2h0IChDKSAyMDE3IE5YUAo+ICsgKgo+ICsgKiBBdXRob3JzOiBQZXRlciBD aGVuIDxwZXRlci5jaGVuQG54cC5jb20+Cj4gKyAqLwo+ICsjaWZuZGVmIF9fTElOVVhfQ0ROUzNf R0FER0VUX0VYUE9SVAo+ICsjZGVmaW5lIF9fTElOVVhfQ0ROUzNfR0FER0VUX0VYUE9SVAo+ICsK PiArI2lmZGVmIENPTkZJR19VU0JfQ0ROUzNfR0FER0VUCj4gKwo+ICtpbnQgY2RuczNfZ2FkZ2V0 X2luaXQoc3RydWN0IGNkbnMzICpjZG5zKTsKPiArdm9pZCBjZG5zM19nYWRnZXRfcmVtb3ZlKHN0 cnVjdCBjZG5zMyAqY2Rucyk7Cj4gKyNlbHNlCj4gKwo+ICtzdGF0aWMgaW5saW5lIGludCBjZG5z M19nYWRnZXRfaW5pdChzdHJ1Y3QgY2RuczMgKmNkbnMpCj4gK3sKPiArCXJldHVybiAtRU5YSU87 Cj4gK30KPiArCj4gK3N0YXRpYyBpbmxpbmUgdm9pZCBjZG5zM19nYWRnZXRfcmVtb3ZlKHN0cnVj dCBjZG5zMyAqY2RucykgeyB9Cj4gKwo+ICsjZW5kaWYKPiArCj4gKyNlbmRpZiAvKiBfX0xJTlVY X0NETlMzX0dBREdFVF9FWFBPUlQgKi8KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvY2RuczMv Z2FkZ2V0LmMgYi9kcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQuYwo+IG5ldyBmaWxlIG1vZGUgMTAw NjQ0Cj4gaW5kZXggMDAwMDAwMDAwMDAwLi4zNzZiNjhiMTNkMWIKPiAtLS0gL2Rldi9udWxsCj4g KysrIGIvZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmMKPiBAQCAtMCwwICsxLDM5MCBAQAo+ICsv LyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMAo+ICsvKgo+ICsgKiBDYWRlbmNlIFVT QlNTIERSRCBEcml2ZXIgLSBnYWRnZXQgc2lkZS4KPiArICoKPiArICogQ29weXJpZ2h0IChDKSAy MDE4IENhZGVuY2UgRGVzaWduIFN5c3RlbXMuCj4gKyAqIENvcHlyaWdodCAoQykgMjAxNyBOWFAK PiArICoKPiArICogQXV0aG9yczogUGF3ZWwgSmV6IDxwamV6QGNhZGVuY2UuY29tPiwKPiArICog ICAgICAgICAgUGF3ZWwgTGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4KPiArICoJICAgIFBl dGVyIENoZW4gPHBldGVyLmNoZW5AbnhwLmNvbT4KPiArICovCj4gKwo+ICsjaW5jbHVkZSA8bGlu dXgvZG1hLW1hcHBpbmcuaD4KPiArI2luY2x1ZGUgPGxpbnV4L3VzYi9nYWRnZXQuaD4KPiArCj4g KyNpbmNsdWRlICJjb3JlLmgiCj4gKyNpbmNsdWRlICJnYWRnZXQtZXhwb3J0LmgiCj4gKyNpbmNs dWRlICJnYWRnZXQuaCIKPiArCj4gKy8qKgo+ICsgKiBjZG5zM19zZXRfcmVnaXN0ZXJfYml0IC0g c2V0IGJpdCBpbiBnaXZlbiByZWdpc3Rlci4KPiArICogQHB0cjogYWRkcmVzcyBvZiBkZXZpY2Ug Y29udHJvbGxlciByZWdpc3RlciB0byBiZSByZWFkIGFuZCBjaGFuZ2VkCj4gKyAqIEBtYXNrOiBi aXRzIHJlcXVlc3RlZCB0byBzZXQKPiArICovCj4gK3ZvaWQgY2RuczNfc2V0X3JlZ2lzdGVyX2Jp dCh2b2lkIF9faW9tZW0gKnB0ciwgdTMyIG1hc2spCj4gK3sKPiArCW1hc2sgPSByZWFkbChwdHIp IHwgbWFzazsKPiArCXdyaXRlbChtYXNrLCBwdHIpOwo+ICt9CgpzdGF0aWMgaW5saW5lPwpJJ2Qg Z2V0IHJpZCBvZiB0aGlzIGZ1bmN0aW9uIGlmIHBvc3NpYmxlLiBZb3UgYXJlIHVzaW5nIGl0IG9u bHkgb25jZQphbmQgaXQgaXMgZWFzaWVyIHRvIHJlYWQgY29kZSBpZiBzZXR0aW5nIHRoZSBiaXRt YXNrIGlzIGRvbmUgcGxhaW5seQppbnN0ZWFkIG9mIGhpZGluZyBpdCBiZWhpbmQgYSBmdW5jdGlv bi4KCj4gKwo+ICsvKioKPiArICogc2VsZWN0X2VwIC0gc2VsZWN0cyBlbmRwb2ludAo+ICsgKiBA cHJpdl9kZXY6ICBleHRlbmRlZCBnYWRnZXQgb2JqZWN0Cj4gKyAqIEBlcDogZW5kcG9pbnQgYWRk cmVzcwo+ICsgKi8KPiArdm9pZCBjZG5zM19zZWxlY3RfZXAoc3RydWN0IGNkbnMzX2RldmljZSAq cHJpdl9kZXYsIHUzMiBlcCkKPiArewo+ICsJaWYgKHByaXZfZGV2LT5zZWxlY3RlZF9lcCA9PSBl cCkKPiArCQlyZXR1cm47CgpJIGRpZG4ndCB1bmRlcnN0YW5kIHRoZSBwdXJwb3NlIG9mIHRoaXMg ZnVuY3Rpb24uIFlvdSBjYW4gb25seSBzZWxlY3QgdGhlIEVQIG9uY2U/Cgo+ICsKPiArCWRldl9k YmcoJnByaXZfZGV2LT5kZXYsICJFcCBzZWw6IDB4JTAyeFxuIiwgZXApOwoKWW91IHNob3VsZCBt b3ZlIHRvIHVzZSB0cmFjZS1wb2ludHMgaW5zdGVhZCBvZiBkZXZfZGJnLgoKPiArCXByaXZfZGV2 LT5zZWxlY3RlZF9lcCA9IGVwOwo+ICsJd3JpdGVsKGVwLCAmcHJpdl9kZXYtPnJlZ3MtPmVwX3Nl bCk7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBjZG5zM19pcnFfaGFuZGxlciAtIGlycSBsaW5lIGlu dGVycnVwdCBoYW5kbGVyCj4gKyAqIEBjZG5zOiBjZG5zMyBpbnN0YW5jZQo+ICsgKgo+ICsgKiBS ZXR1cm5zIElSUV9IQU5ETEVEIHdoZW4gaW50ZXJydXB0IHJhaXNlZCBieSBVU0JTU19ERVYsCj4g KyAqIElSUV9OT05FIHdoZW4gaW50ZXJydXB0IHJhaXNlZCBieSBvdGhlciBkZXZpY2UgY29ubmVj dGVkCj4gKyAqIHRvIHRoZSBpcnEgbGluZQo+ICsgKi8KPiArc3RhdGljIGlycXJldHVybl90IGNk bnMzX2lycV9oYW5kbGVyX3RocmVhZChzdHJ1Y3QgY2RuczMgKmNkbnMpCj4gK3sKPiArCWlycXJl dHVybl90IHJldCA9IElSUV9OT05FOwo+ICsJLy9UT0RPOiBpbXBsZW1lbnRzIHRoaXMgZnVuY3Rp b24KPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGNkbnMzX2dhZGdldF9j b25maWcoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYpCj4gK3sKPiArCXN0cnVjdCBjZG5z M191c2JfcmVncyBfX2lvbWVtICpyZWdzID0gcHJpdl9kZXYtPnJlZ3M7Cj4gKwo+ICsJY2RuczNf ZXAwX2NvbmZpZyhwcml2X2Rldik7Cj4gKwo+ICsJLyogZW5hYmxlIGludGVycnVwdHMgZm9yIGVu ZHBvaW50IDAgKGluIGFuZCBvdXQpICovCj4gKwl3cml0ZWwoRVBfSUVOX0VQX09VVDAgfCBFUF9J RU5fRVBfSU4wLCAmcmVncy0+ZXBfaWVuKTsKPiArCj4gKwkvKiBlbmFibGUgZ2VuZXJpYyBpbnRl cnJ1cHQqLwo+ICsJd3JpdGVsKFVTQl9JRU5fSU5JVCwgJnJlZ3MtPnVzYl9pZW4pOwo+ICsJd3Jp dGVsKFVTQl9DT05GX0NMSzJPRkZEUyB8IFVTQl9DT05GX0wxRFMsICZyZWdzLT51c2JfY29uZik7 Cj4gKwl3cml0ZWwoVVNCX0NPTkZfRE1VTFQsICZyZWdzLT51c2JfY29uZik7Cj4gKwl3cml0ZWwo VVNCX0NPTkZfREVWRU4sICZyZWdzLT51c2JfY29uZik7CgpJZiB5b3UgYXJlIGVuYWJsaW5nIGlu dGVycnVwdHMgaW4gdGhpcyBwYXRjaCB5b3Ugc2hvdWxkIGhhbmRsZSB0aGVtIGluIHRoZSBJU1Iu Cgo+ICt9Cj4gKwo+ICsvKioKPiArICogY2RuczNfaW5pdF9lcCBJbml0aWFsaXplcyBzb2Z0d2Fy ZSBlbmRwb2ludHMgb2YgZ2FkZ2V0Cj4gKyAqIEBjZG5zMzogZXh0ZW5kZWQgZ2FkZ2V0IG9iamVj dAo+ICsgKgo+ICsgKiBSZXR1cm5zIDAgb24gc3VjY2VzcywgZXJyb3IgY29kZSBlbHNld2hlcmUK PiArICovCj4gK3N0YXRpYyBpbnQgY2RuczNfaW5pdF9lcChzdHJ1Y3QgY2RuczNfZGV2aWNlICpw cml2X2RldikKPiArewo+ICsJdTMyIGVwX2VuYWJsZWRfcmVnLCBpc29fZXBfcmVnOwo+ICsJc3Ry dWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwOwo+ICsJaW50IGZvdW5kX2VuZHBvaW50cyA9IDA7 Cj4gKwlpbnQgZXBfZGlyLCBlcF9udW1iZXI7Cj4gKwl1MzIgZXBfbWFzazsKPiArCWludCBpOwo+ ICsKPiArCS8qIFJlYWQgaXQgZnJvbSBVU0JfQ0FQMyB0byBVU0JfQ0FQNSAqLwo+ICsJZXBfZW5h YmxlZF9yZWcgPSByZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9jYXAzKTsKPiArCWlzb19lcF9y ZWcgPSByZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9jYXA0KTsKPiArCj4gKwlkZXZfZGJnKCZw cml2X2Rldi0+ZGV2LCAiSW5pdGlhbGl6aW5nIG5vbi16ZXJvIGVuZHBvaW50c1xuIik7Cj4gKwo+ ICsJZm9yIChpID0gMDsgaSA8IFVTQl9TU19FTkRQT0lOVFNfTUFYX0NPVU5UOyBpKyspIHsKCkNE TlMzX1VTQl9TU19FTkRQT0lOVFNfTUFYX0NPVU5UCgo+ICsJCWVwX251bWJlciA9IChpIC8gMikg KyAxOwo+ICsJCWVwX2RpciA9IGkgJSAyOwo+ICsJCWVwX21hc2sgPSBCSVQoKDE2ICogZXBfZGly KSArIGVwX251bWJlcik7Cj4gKwo+ICsJCWlmICghKGVwX2VuYWJsZWRfcmVnICYgZXBfbWFzaykp Cj4gKwkJCWNvbnRpbnVlOwo+ICsKPiArCQlwcml2X2VwID0gZGV2bV9remFsbG9jKCZwcml2X2Rl di0+ZGV2LCBzaXplb2YoKnByaXZfZXApLAo+ICsJCQkJICAgICAgIEdGUF9LRVJORUwpOwo+ICsJ CWlmICghcHJpdl9lcCkKPiArCQkJcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsJCS8qIHNldCBwYXJl bnQgb2YgZW5kcG9pbnQgb2JqZWN0ICovCj4gKwkJcHJpdl9lcC0+Y2RuczNfZGV2ID0gcHJpdl9k ZXY7Cj4gKwkJcHJpdl9kZXYtPmVwc1tmb3VuZF9lbmRwb2ludHMrK10gPSBwcml2X2VwOwo+ICsK PiArCQlzbnByaW50Zihwcml2X2VwLT5uYW1lLCBzaXplb2YocHJpdl9lcC0+bmFtZSksICJlcCVk JXMiLAo+ICsJCQkgZXBfbnVtYmVyLCAhIWVwX2RpciA/ICJpbiIgOiAib3V0Iik7Cj4gKwkJcHJp dl9lcC0+ZW5kcG9pbnQubmFtZSA9IHByaXZfZXAtPm5hbWU7Cj4gKwo+ICsJCXVzYl9lcF9zZXRf bWF4cGFja2V0X2xpbWl0KCZwcml2X2VwLT5lbmRwb2ludCwKPiArCQkJCQkgICBFTkRQT0lOVF9N QVhfUEFDS0VUX0xJTUlUKTsKCkNETlMzX0VORFBPSU5UX01BWF9QQUNLRVRfTElNSVQKCj4gKwkJ cHJpdl9lcC0+ZW5kcG9pbnQubWF4X3N0cmVhbXMgPSBFTkRQT0lOVF9NQVhfU1RSRUFNUzsKCkNE TlMzX0VORFBPSU5UX01BWF9TVFJFQU1TCgo+ICsJCS8vVE9ETzogQWRkIGltcGxlbWVudGF0aW9u IG9mIGNkbnMzX2dhZGdldF9lcF9vcHMKPiArCQkvL3ByaXZfZXAtPmVuZHBvaW50Lm9wcyA9ICZj ZG5zM19nYWRnZXRfZXBfb3BzOwo+ICsJCWlmIChlcF9kaXIpCj4gKwkJCXByaXZfZXAtPmVuZHBv aW50LmNhcHMuZGlyX2luID0gMTsKPiArCQllbHNlCj4gKwkJCXByaXZfZXAtPmVuZHBvaW50LmNh cHMuZGlyX291dCA9IDE7Cj4gKwo+ICsJCWlmIChpc29fZXBfcmVnICYgZXBfbWFzaykKPiArCQkJ cHJpdl9lcC0+ZW5kcG9pbnQuY2Fwcy50eXBlX2lzbyA9IDE7Cj4gKwo+ICsJCXByaXZfZXAtPmVu ZHBvaW50LmNhcHMudHlwZV9idWxrID0gMTsKPiArCQlwcml2X2VwLT5lbmRwb2ludC5jYXBzLnR5 cGVfaW50ID0gMTsKPiArCQlwcml2X2VwLT5lbmRwb2ludC5tYXhidXJzdCA9IENETlMzX0VQX0JV Rl9TSVpFIC0gMTsKPiArCj4gKwkJcHJpdl9lcC0+ZmxhZ3MgPSAwOwo+ICsKPiArCQlkZXZfaW5m bygmcHJpdl9kZXYtPmRldiwgIkluaXRpYWxpemVkICAlcyBzdXBwb3J0OiAlcyAlc1xuIiwKPiAr CQkJIHByaXZfZXAtPm5hbWUsCj4gKwkJCSBwcml2X2VwLT5lbmRwb2ludC5jYXBzLnR5cGVfYnVs ayA/ICJCVUxLLCBJTlQiIDogIiIsCj4gKwkJCSBwcml2X2VwLT5lbmRwb2ludC5jYXBzLnR5cGVf aXNvID8gIklTTyIgOiAiIik7Cj4gKwo+ICsJCWxpc3RfYWRkX3RhaWwoJnByaXZfZXAtPmVuZHBv aW50LmVwX2xpc3QsCj4gKwkJCSAgICAgICZwcml2X2Rldi0+Z2FkZ2V0LmVwX2xpc3QpOwo+ICsJ CUlOSVRfTElTVF9IRUFEKCZwcml2X2VwLT5yZXF1ZXN0X2xpc3QpOwo+ICsJCUlOSVRfTElTVF9I RUFEKCZwcml2X2VwLT5lcF9tYXRjaF9wZW5kaW5nX2xpc3QpOwo+ICsJfQo+ICsKPiArCXByaXZf ZGV2LT5lcF9udW1zID0gZm91bmRfZW5kcG9pbnRzOwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4g K3N0YXRpYyB2b2lkIGNkbnMzX2dhZGdldF9yZWxlYXNlKHN0cnVjdCBkZXZpY2UgKmRldikKPiAr ewo+ICsJc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXY7Cj4gKwo+ICsJcHJpdl9kZXYgPSBj b250YWluZXJfb2YoZGV2LCBzdHJ1Y3QgY2RuczNfZGV2aWNlLCBkZXYpOwo+ICsJa2ZyZWUocHJp dl9kZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IF9fY2RuczNfZ2FkZ2V0X2luaXQoc3RydWN0 IGNkbnMzICpjZG5zKQo+ICt7Cj4gKwlzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldjsKPiAr CXN0cnVjdCBkZXZpY2UgKmRldjsKPiArCWludCByZXQ7Cj4gKwo+ICsJcHJpdl9kZXYgPSBremFs bG9jKHNpemVvZigqcHJpdl9kZXYpLCBHRlBfS0VSTkVMKTsKPiArCWlmICghcHJpdl9kZXYpCj4g KwkJcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsJZGV2ID0gJnByaXZfZGV2LT5kZXY7Cj4gKwlkZXYt PnJlbGVhc2UgPSBjZG5zM19nYWRnZXRfcmVsZWFzZTsKPiArCWRldi0+cGFyZW50ID0gY2Rucy0+ ZGV2Owo+ICsJZGV2X3NldF9uYW1lKGRldiwgImdhZGdldC1jZG5zMyIpOwo+ICsJY2Rucy0+Z2Fk Z2V0X2RldiA9IGRldjsKPiArCj4gKwlwcml2X2Rldi0+c3lzZGV2ID0gY2Rucy0+ZGV2Owo+ICsJ cmV0ID0gZGV2aWNlX3JlZ2lzdGVyKGRldik7CgpXaHkgZG8geW91IG5lZWQgdG8gY3JlYXRlIHRo aXMgZHVtbXkgZGV2aWNlPyB5b3UgY291bGQganVzdCB1c2UgY2RuczMtPmRldi4KCj4gKwlpZiAo cmV0KQo+ICsJCWdvdG8gZXJyMTsKPiArCj4gKwlwcml2X2Rldi0+cmVncyA9IGNkbnMtPmRldl9y ZWdzOwo+ICsKPiArCS8qIGZpbGwgZ2FkZ2V0IGZpZWxkcyAqLwo+ICsJcHJpdl9kZXYtPmdhZGdl dC5tYXhfc3BlZWQgPSBVU0JfU1BFRURfU1VQRVI7Cj4gKwlwcml2X2Rldi0+Z2FkZ2V0LnNwZWVk ID0gVVNCX1NQRUVEX1VOS05PV047Cj4gKwkvL1RPRE86IEFkZCBpbXBsZW1lbnRhdGlvbiBvZiBj ZG5zM19nYWRnZXRfb3BzCj4gKwkvL3ByaXZfZGV2LT5nYWRnZXQub3BzID0gJmNkbnMzX2dhZGdl dF9vcHM7Cj4gKwlwcml2X2Rldi0+Z2FkZ2V0Lm5hbWUgPSAidXNiLXNzLWdhZGdldCI7Cj4gKwlw cml2X2Rldi0+Z2FkZ2V0LnNnX3N1cHBvcnRlZCA9IDE7Cj4gKwlwcml2X2Rldi0+aXNfY29ubmVj dGVkID0gMDsKPiArCj4gKwlzcGluX2xvY2tfaW5pdCgmcHJpdl9kZXYtPmxvY2spOwo+ICsKPiAr CXByaXZfZGV2LT5pbl9zdGFuZGJ5X21vZGUgPSAxOwo+ICsKPiArCS8qIGluaXRpYWxpemUgZW5k cG9pbnQgY29udGFpbmVyICovCj4gKwlJTklUX0xJU1RfSEVBRCgmcHJpdl9kZXYtPmdhZGdldC5l cF9saXN0KTsKPiArCUlOSVRfTElTVF9IRUFEKCZwcml2X2Rldi0+ZXBfbWF0Y2hfbGlzdCk7Cj4g Kwo+ICsJcmV0ID0gY2RuczNfaW5pdF9lcDAocHJpdl9kZXYpOwo+ICsJaWYgKHJldCkgewo+ICsJ CWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIGNyZWF0ZSBlbmRwb2ludCAwXG4iKTsKPiArCQlyZXQg PSAtRU5PTUVNOwoKd2h5IG5vdCBqdXN0IHVzZSB0aGUgcmV0IGFzIGlzLgoKPiArCQlnb3RvIGVy cjI7Cj4gKwl9Cj4gKwo+ICsJcmV0ID0gY2RuczNfaW5pdF9lcChwcml2X2Rldik7Cj4gKwlpZiAo cmV0KSB7Cj4gKwkJZGV2X2VycihkZXYsICJGYWlsZWQgdG8gY3JlYXRlIG5vbiB6ZXJvIGVuZHBv aW50c1xuIik7Cj4gKwkJcmV0ID0gLUVOT01FTTsKCmhlcmUgdG9vCgo+ICsJCWdvdG8gZXJyMjsK PiArCX0KPiArCj4gKwkvKiBhbGxvY2F0ZSBtZW1vcnkgZm9yIGRlZmF1bHQgZW5kcG9pbnQgVFJC ICovCj4gKwlwcml2X2Rldi0+dHJiX2VwMCA9IGRtYV9hbGxvY19jb2hlcmVudChwcml2X2Rldi0+ c3lzZGV2LCAyNCwKCndoYXQgaXMgMjQ/CkluIGVycm9yIHBhdGggeW91IGFyZSB1c2luZyBUUkJf U0laRSAqIDIuIFNob3VsZCB3ZSBiZSB1c2luZyB0aGF0IGhlcmUgdG9vPwoKCj4gKwkJCQkJICAg ICAgICZwcml2X2Rldi0+dHJiX2VwMF9kbWEsIEdGUF9ETUEpOwo+ICsJaWYgKCFwcml2X2Rldi0+ dHJiX2VwMCkgewo+ICsJCWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIGFsbG9jYXRlIG1lbW9yeSBm b3IgZXAwIFRSQlxuIik7Cj4gKwkJcmV0ID0gLUVOT01FTTsKPiArCQlnb3RvIGVycjI7Cj4gKwl9 Cj4gKwo+ICsJLyogYWxsb2NhdGUgbWVtb3J5IGZvciBzZXR1cCBwYWNrZXQgYnVmZmVyICovCj4g Kwlwcml2X2Rldi0+c2V0dXAgPSBkbWFfYWxsb2NfY29oZXJlbnQocHJpdl9kZXYtPnN5c2Rldiwg OCwKCmlzIDggZW5vdWdoIGZvciBhbGwgdXNlIGNhc2VzPyBXaGF0IGFib3V0IHZlbmRvciBzcGVj aWZpYyBzZXR1cCByZXF1ZXN0cz8KCj4gKwkJCQkJICAgICAmcHJpdl9kZXYtPnNldHVwX2RtYSwg R0ZQX0RNQSk7Cj4gKwlpZiAoIXByaXZfZGV2LT5zZXR1cCkgewo+ICsJCWRldl9lcnIoZGV2LCAi RmFpbGVkIHRvIGFsbG9jYXRlIG1lbW9yeSBmb3IgU0VUVVAgYnVmZmVyXG4iKTsKPiArCQlyZXQg PSAtRU5PTUVNOwo+ICsJCWdvdG8gZXJyMzsKPiArCX0KPiArCj4gKwlkZXZfZGJnKGRldiwgIkRl dmljZSBDb250cm9sbGVyIHZlcnNpb246ICUwOHhcbiIsCj4gKwkJcmVhZGwoJnByaXZfZGV2LT5y ZWdzLT51c2JfY2FwNikpOwo+ICsJZGV2X2RiZyhkZXYsICJVU0IgQ2FwYWJpbGl0aWVzOjogJTA4 eFxuIiwKPiArCQlyZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9jYXAxKSk7Cj4gKwlkZXZfZGJn KGRldiwgIk9uLUNoaXAgbWVtb3J5IGNuZmlndXJhdGlvbjogJTA4eFxuIiwKPiArCQlyZWFkbCgm cHJpdl9kZXYtPnJlZ3MtPnVzYl9jYXAyKSk7Cj4gKwo+ICsJLyogYWRkIFVTQiBnYWRnZXQgZGV2 aWNlICovCj4gKwlyZXQgPSB1c2JfYWRkX2dhZGdldF91ZGMoJnByaXZfZGV2LT5kZXYsICZwcml2 X2Rldi0+Z2FkZ2V0KTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJZGV2X2VycihkZXYsICJGYWls ZWQgdG8gcmVnaXN0ZXIgVVNCIGRldmljZSBjb250cm9sbGVyXG4iKTsKPiArCQlnb3RvIGVycjQ7 Cj4gKwl9Cj4gKwo+ICsJcHJpdl9kZXYtPnpscF9idWYgPSBremFsbG9jKEVORFBPSU5UX1pMUF9C VUZfU0laRSwgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAoIXByaXZfZGV2LT56bHBfYnVmKSB7Cj4gKwkJ cmV0ID0gLUVOT01FTTsKPiArCQlnb3RvIGVycjQ7Cj4gKwl9Cgpob3cgYWJvdXQgYWxsb2NhdGlu ZyB6bHBfYnVmIGJlZm9yZSB1c2JfYWRkX2dhZGdldF91ZGMoKT8KCj4gKwo+ICsJcmV0dXJuIDA7 Cj4gK2VycjQ6Cj4gKwlkbWFfZnJlZV9jb2hlcmVudChwcml2X2Rldi0+c3lzZGV2LCA4LCBwcml2 X2Rldi0+c2V0dXAsCj4gKwkJCSAgcHJpdl9kZXYtPnNldHVwX2RtYSk7Cj4gK2VycjM6Cj4gKwlk bWFfZnJlZV9jb2hlcmVudChwcml2X2Rldi0+c3lzZGV2LCBUUkJfU0laRSAqIDIsIHByaXZfZGV2 LT50cmJfZXAwLAo+ICsJCQkgIHByaXZfZGV2LT50cmJfZXAwX2RtYSk7Cj4gK2VycjI6Cj4gKwlk ZXZpY2VfZGVsKGRldik7Cj4gK2VycjE6Cj4gKwlwdXRfZGV2aWNlKGRldik7Cj4gKwljZG5zLT5n YWRnZXRfZGV2ID0gTlVMTDsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gKy8qKgo+ICsgKiBj ZG5zM19nYWRnZXRfcmVtb3ZlOiBwYXJlbnQgbXVzdCBjYWxsIHRoaXMgdG8gcmVtb3ZlIFVEQwo+ ICsgKgo+ICsgKiBjZG5zOiBjZG5zMyBpbnN0YW5jZQo+ICsgKi8KPiArdm9pZCBjZG5zM19nYWRn ZXRfcmVtb3ZlKHN0cnVjdCBjZG5zMyAqY2RucykKCmhvdyBhYm91dCBjYWxsaW5nIHRoaXMgY2Ru czNfZ2FkZ2V0X2V4aXQoKSB0byBjb21wbGVtZW1udCBjZG5zM19nYWRnZXRfaW5pdCgpCgo+ICt7 Cj4gKwlzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldjsKPiArCj4gKwlpZiAoIWNkbnMtPnJv bGVzW0NETlMzX1JPTEVfR0FER0VUXSkKPiArCQlyZXR1cm47Cgp3aHkgdGhpcyBjaGVjaz8gSXQg d2lsbCBsZWFkIHRvIGFuIHVuYmFsYW5jZWQgZXhpdCgpIGFuZCBmdXR1cmUgaW5pdCgpLgoKPiAr Cj4gKwlwcml2X2RldiA9IGNvbnRhaW5lcl9vZihjZG5zLT5nYWRnZXRfZGV2LCBzdHJ1Y3QgY2Ru czNfZGV2aWNlLCBkZXYpOwo+ICsJdXNiX2RlbF9nYWRnZXRfdWRjKCZwcml2X2Rldi0+Z2FkZ2V0 KTsKPiArCWRtYV9mcmVlX2NvaGVyZW50KHByaXZfZGV2LT5zeXNkZXYsIDgsIHByaXZfZGV2LT5z ZXR1cCwKPiArCQkJICBwcml2X2Rldi0+c2V0dXBfZG1hKTsKPiArCWRtYV9mcmVlX2NvaGVyZW50 KHByaXZfZGV2LT5zeXNkZXYsIFRSQl9TSVpFICogMiwgcHJpdl9kZXYtPnRyYl9lcDAsCj4gKwkJ CSAgcHJpdl9kZXYtPnRyYl9lcDBfZG1hKTsKCllvdSBuZWVkIHRvIGZyZWUgYWxsIG1lbW9yeSBh bGxvY2F0aW9uIGRvbmUgaW4gY2RuczNfaW5pdF9lcDAoKSBhbmQgY2RuczNfaW5pdF9lcCgpCmVs c2Ugd2UgZWF0IG1lbW9yeSBvbiBldmVyeSByb2xlIHN3aXRjaCBpZiB3ZSBwbGFuIG9uIGdldHRp bmcgcmlkIG9mIHRoZSBkdW1teSBnYWRnZXRfZGV2LgoKPiArCWRldmljZV91bnJlZ2lzdGVyKGNk bnMtPmdhZGdldF9kZXYpOwo+ICsJY2Rucy0+Z2FkZ2V0X2RldiA9IE5VTEw7Cj4gKwlrZnJlZShw cml2X2Rldi0+emxwX2J1Zik7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgY2RuczNfZ2FkZ2V0X3N0 YXJ0KHN0cnVjdCBjZG5zMyAqY2RucykKPiArewo+ICsJc3RydWN0IGNkbnMzX2RldmljZSAqcHJp dl9kZXYgPSBjb250YWluZXJfb2YoY2Rucy0+Z2FkZ2V0X2RldiwKPiArCQkJc3RydWN0IGNkbnMz X2RldmljZSwgZGV2KTsKPiArCXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gKwo+ICsJcG1fcnVudGlt ZV9nZXRfc3luYyhjZG5zLT5kZXYpOwoKVGhpcyBpcyBhbm90aGVyIHJlYXNvbiB3aHkgd2Ugc2hv dWxkbid0IGJlIGNyZWF0aW5nIGEgZHVtbXkgZ2FkZ2V0X2Rldi4KUE0gaXMgdGllZCB0byBjZG5z LT5kZXYuCgo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7Cj4g Kwlwcml2X2Rldi0+c3RhcnRfZ2FkZ2V0ID0gMTsKPiArCj4gKwlpZiAoIXByaXZfZGV2LT5nYWRn ZXRfZHJpdmVyKSB7Cj4gKwkJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmcHJpdl9kZXYtPmxvY2ss IGZsYWdzKTsKPiArCQlyZXR1cm4gMDsKPiArCX0KPiArCj4gKwljZG5zM19nYWRnZXRfY29uZmln KHByaXZfZGV2KTsKPiArCXByaXZfZGV2LT5pbl9zdGFuZGJ5X21vZGUgPSAwOwo+ICsJc3Bpbl91 bmxvY2tfaXJxcmVzdG9yZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKPiArCXJldHVybiAwOwo+ ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBfX2NkbnMzX2dhZGdldF9zdG9wKHN0cnVjdCBjZG5zMyAq Y2RucykKPiArewo+ICsJc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXY7Cj4gKwl1bnNpZ25l ZCBsb25nIGZsYWdzOwo+ICsKPiArCXByaXZfZGV2ID0gY29udGFpbmVyX29mKGNkbnMtPmdhZGdl dF9kZXYsIHN0cnVjdCBjZG5zM19kZXZpY2UsIGRldik7Cj4gKwo+ICsJaWYgKHByaXZfZGV2LT5n YWRnZXRfZHJpdmVyKQo+ICsJCXByaXZfZGV2LT5nYWRnZXRfZHJpdmVyLT5kaXNjb25uZWN0KCZw cml2X2Rldi0+Z2FkZ2V0KTsKPiArCj4gKwl1c2JfZ2FkZ2V0X2Rpc2Nvbm5lY3QoJnByaXZfZGV2 LT5nYWRnZXQpOwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7 Cj4gKwlwcml2X2Rldi0+Z2FkZ2V0LnNwZWVkID0gVVNCX1NQRUVEX1VOS05PV047Cj4gKwo+ICsJ LyogZGlzYWJsZSBpbnRlcnJ1cHQgZm9yIGRldmljZSAqLwo+ICsJd3JpdGVsKDAsICZwcml2X2Rl di0+cmVncy0+dXNiX2llbik7Cj4gKwl3cml0ZWwoVVNCX0NPTkZfREVWRFMsICZwcml2X2Rldi0+ cmVncy0+dXNiX2NvbmYpOwo+ICsJcHJpdl9kZXYtPnN0YXJ0X2dhZGdldCA9IDA7Cj4gKwlzcGlu X3VubG9ja19pcnFyZXN0b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOwo+ICt9Cj4gKwo+ICtz dGF0aWMgdm9pZCBjZG5zM19nYWRnZXRfc3RvcChzdHJ1Y3QgY2RuczMgKmNkbnMpCj4gK3sKPiAr CWlmIChjZG5zLT5yb2xlID09IENETlMzX1JPTEVfR0FER0VUKQo+ICsJCV9fY2RuczNfZ2FkZ2V0 X3N0b3AoY2Rucyk7CgpXaHkgd29ycnkgYWJvdXQgcm9sZSBoZXJlPyBUaGF0IHNob3VsZCBiZSBq b2Igb2YgY29yZS9kcmQgZHJpdmVyLgoKPiArCj4gKwlwbV9ydW50aW1lX21hcmtfbGFzdF9idXN5 KGNkbnMtPmRldik7Cj4gKwlwbV9ydW50aW1lX3B1dF9hdXRvc3VzcGVuZChjZG5zLT5kZXYpOwo+ ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGNkbnMzX2dhZGdldF9zdXNwZW5kKHN0cnVjdCBjZG5zMyAq Y2RucywgYm9vbCBkb193YWtldXApCj4gK3sKPiArCV9fY2RuczNfZ2FkZ2V0X3N0b3AoY2Rucyk7 Cj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIGludCBjZG5zM19nYWRnZXRfcmVzdW1l KHN0cnVjdCBjZG5zMyAqY2RucywgYm9vbCBoaWJlcm5hdGVkKQo+ICt7Cj4gKwlzdHJ1Y3QgY2Ru czNfZGV2aWNlICpwcml2X2RldjsKPiArCXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gKwo+ICsJcHJp dl9kZXYgPSBjb250YWluZXJfb2YoY2Rucy0+Z2FkZ2V0X2Rldiwgc3RydWN0IGNkbnMzX2Rldmlj ZSwgZGV2KTsKPiArCXNwaW5fbG9ja19pcnFzYXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOwo+ ICsJcHJpdl9kZXYtPnN0YXJ0X2dhZGdldCA9IDE7Cgp3aG8gaXMgdXNpbmcgdGhpcyBzdGFydF9n YWRnZXQgZmxhZz8KCj4gKwlpZiAoIXByaXZfZGV2LT5nYWRnZXRfZHJpdmVyKSB7Cj4gKwkJc3Bp bl91bmxvY2tfaXJxcmVzdG9yZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKPiArCQlyZXR1cm4g MDsKPiArCX0KPiArCj4gKwljZG5zM19nYWRnZXRfY29uZmlnKHByaXZfZGV2KTsKPiArCXByaXZf ZGV2LT5pbl9zdGFuZGJ5X21vZGUgPSAwOwo+ICsJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmcHJp dl9kZXYtPmxvY2ssIGZsYWdzKTsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICsvKioKPiArICog Y2RuczNfZ2FkZ2V0X2luaXQgLSBpbml0aWFsaXplIGRldmljZSBzdHJ1Y3R1cmUKPiArICoKPiAr ICogY2RuczogY2RuczMgaW5zdGFuY2UKPiArICoKPiArICogVGhpcyBmdW5jdGlvbiBpbml0aWFs aXplcyB0aGUgZ2FkZ2V0Lgo+ICsgKi8KPiAraW50IGNkbnMzX2dhZGdldF9pbml0KHN0cnVjdCBj ZG5zMyAqY2RucykKPiArewo+ICsJc3RydWN0IGNkbnMzX3JvbGVfZHJpdmVyICpyZHJ2Owo+ICsK PiArCXJkcnYgPSBkZXZtX2t6YWxsb2MoY2Rucy0+ZGV2LCBzaXplb2YoKnJkcnYpLCBHRlBfS0VS TkVMKTsKPiArCWlmICghcmRydikKPiArCQlyZXR1cm4gLUVOT01FTTsKPiArCj4gKwlyZHJ2LT5z dGFydAk9IGNkbnMzX2dhZGdldF9zdGFydDsKPiArCXJkcnYtPnN0b3AJPSBjZG5zM19nYWRnZXRf c3RvcDsKCldoeSBub3QgdXNlIGdhZGdldF9pbml0KCkvZ2FkZ2V0X2V4aXQoKSBoZXJlPyBUaGF0 IHNvdW5kcyBtdWNoIGNsZWFuZXIKYXMgeW91IHdvbid0IGhhdmUgSVNSJ3MgYWN0aXZlIGFmdGVy IGEgcm9sZSBzdG9wLgoKPiArCXJkcnYtPnN1c3BlbmQJPSBjZG5zM19nYWRnZXRfc3VzcGVuZDsK PiArCXJkcnYtPnJlc3VtZQk9IGNkbnMzX2dhZGdldF9yZXN1bWU7Cj4gKwlyZHJ2LT5pcnEJPSBj ZG5zM19pcnFfaGFuZGxlcl90aHJlYWQ7Cj4gKwlyZHJ2LT5uYW1lCT0gImdhZGdldCI7Cj4gKwlj ZG5zLT5yb2xlc1tDRE5TM19ST0xFX0dBREdFVF0gPSByZHJ2Owo+ICsJcmV0dXJuIF9fY2RuczNf Z2FkZ2V0X2luaXQoY2Rucyk7Cj4gK30KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvY2RuczMv Z2FkZ2V0LmggYi9kcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQuaAo+IGluZGV4IDc1Y2E2MjE0ZTc5 YS4uM2IwZDRkMmU0ODMxIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5o Cj4gKysrIGIvZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmgKPiBAQCAtMTA2OCw0ICsxMDY4LDgg QEAgc3RydWN0IGNkbnMzX2RldmljZSB7Cj4gIAlzdHJ1Y3QgdXNiX3JlcXVlc3QJCSpwZW5kaW5n X3N0YXR1c19yZXF1ZXN0Owo+ICB9Owo+ICAKPiArdm9pZCBjZG5zM19zZXRfcmVnaXN0ZXJfYml0 KHZvaWQgX19pb21lbSAqcHRyLCB1MzIgbWFzayk7Cj4gK2ludCBjZG5zM19pbml0X2VwMChzdHJ1 Y3QgY2RuczNfZGV2aWNlICpwcml2X2Rldik7Cj4gK3ZvaWQgY2RuczNfZXAwX2NvbmZpZyhzdHJ1 Y3QgY2RuczNfZGV2aWNlICpwcml2X2Rldik7Cj4gK3ZvaWQgY2RuczNfc2VsZWN0X2VwKHN0cnVj dCBjZG5zM19kZXZpY2UgKnByaXZfZGV2LCB1MzIgZXApOwo+ICAjZW5kaWYgLyogX19MSU5VWF9D RE5TM19HQURHRVQgKi8KPiAKCmNoZWVycywKLXJvZ2VyCg== From mboxrd@z Thu Jan 1 00:00:00 1970 From: Roger Quadros Subject: Re: [RFC PATCH v2 07/15] usb:cdns3: Adds Device mode support - initialization. Date: Wed, 28 Nov 2018 13:34:06 +0200 Message-ID: <5BFE7D2E.7030702@ti.com> References: <1542535751-16079-1-git-send-email-pawell@cadence.com> <1542535751-16079-8-git-send-email-pawell@cadence.com> Mime-Version: 1.0 Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1542535751-16079-8-git-send-email-pawell@cadence.com> Sender: linux-kernel-owner@vger.kernel.org To: Pawel Laszczak , devicetree@vger.kernel.org, Felipe Balbi Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, adouglas@cadence.com, jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com, sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com, kurahul@cadence.com List-Id: devicetree@vger.kernel.org +Felipe. Pawel, Please copy Felipe Balbi as he maintains the USB gadget stack. On 18/11/18 12:09, Pawel Laszczak wrote: > Patch implements a set of functions responsible for initialization, > configuration, starting and stopping device mode. > This patch also adds new ep0.c that holds all functions related > to endpoint 0. > > Signed-off-by: Pawel Laszczak > --- > drivers/usb/cdns3/Kconfig | 10 + > drivers/usb/cdns3/Makefile | 1 + > drivers/usb/cdns3/core.c | 5 +- > drivers/usb/cdns3/ep0.c | 105 ++++++++ > drivers/usb/cdns3/gadget-export.h | 27 +++ > drivers/usb/cdns3/gadget.c | 390 ++++++++++++++++++++++++++++++ > drivers/usb/cdns3/gadget.h | 4 + > 7 files changed, 541 insertions(+), 1 deletion(-) > create mode 100644 drivers/usb/cdns3/ep0.c > create mode 100644 drivers/usb/cdns3/gadget-export.h > create mode 100644 drivers/usb/cdns3/gadget.c > > diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig > index d92bc3d68eb0..b7d71b5c4f60 100644 > --- a/drivers/usb/cdns3/Kconfig > +++ b/drivers/usb/cdns3/Kconfig > @@ -10,6 +10,16 @@ config USB_CDNS3 > > if USB_CDNS3 > > +config USB_CDNS3_GADGET > + bool "Cadence USB3 device controller" > + depends on USB_GADGET > + help > + Say Y here to enable device controller functionality of the > + cadence USBSS-DEV driver. > + > + This controller support FF, HS and SS mode. It doeasn't support s/support/supports s/doeasn't/doesn't > + LS and SSP mode > + > config USB_CDNS3_HOST > bool "Cadence USB3 host controller" > depends on USB_XHCI_HCD > diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile > index 976117ba67ff..bea6173bf37f 100644 > --- a/drivers/usb/cdns3/Makefile > +++ b/drivers/usb/cdns3/Makefile > @@ -2,5 +2,6 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o > obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o > > cdns3-y := core.o drd.o > +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o > cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o > cdns3-pci-y := cdns3-pci-wrap.o > diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c > index 4cb820be9ff3..1fa233415901 100644 > --- a/drivers/usb/cdns3/core.c > +++ b/drivers/usb/cdns3/core.c > @@ -18,6 +18,7 @@ > #include "gadget.h" > #include "core.h" > #include "host-export.h" > +#include "gadget-export.h" > #include "drd.h" > > static inline struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) > @@ -104,7 +105,8 @@ static int cdns3_core_init_role(struct cdns3 *cdns) > } > > if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { > - //TODO: implements device initialization > + if (cdns3_gadget_init(cdns)) > + dev_info(dev, "doesn't support gadget\n"); dev_err() and we should should error out with error code returned by cdns3_gadget_init(). > } > > if (!cdns->roles[CDNS3_ROLE_HOST] && !cdns->roles[CDNS3_ROLE_GADGET]) { > @@ -144,6 +146,7 @@ static irqreturn_t cdns3_irq(int irq, void *data) > > static void cdns3_remove_roles(struct cdns3 *cdns) > { if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) > + cdns3_gadget_remove(cdns); > cdns3_host_remove(cdns); > } > > diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c > new file mode 100644 > index 000000000000..c08d02665f9d > --- /dev/null > +++ b/drivers/usb/cdns3/ep0.c > @@ -0,0 +1,105 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver - gadget side. > + * > + * Copyright (C) 2018 Cadence Design Systems. > + * Copyright (C) 2017 NXP > + * > + * Authors: Pawel Jez , > + * Pawel Laszczak > + * Peter Chen > + */ > + > +#include "gadget.h" > + > +static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { > + .bLength = USB_DT_ENDPOINT_SIZE, > + .bDescriptorType = USB_DT_ENDPOINT, > + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, > +}; > + > +static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) > +{ > + //TODO: Implements this function > +} > + > +/** > + * cdns3_ep0_config - Configures default endpoint > + * @priv_dev: extended gadget object > + * > + * Functions sets parameters: maximal packet size and enables interrupts > + */ > +void cdns3_ep0_config(struct cdns3_device *priv_dev) > +{ > + struct cdns3_usb_regs __iomem *regs; > + u32 max_packet_size = 64; > + > + regs = priv_dev->regs; > + > + if (priv_dev->gadget.speed == USB_SPEED_SUPER) > + max_packet_size = 512; is gadget.speed known at this point? I think it will only be known after a connection is made. > + > + if (priv_dev->ep0_request) { > + list_del_init(&priv_dev->ep0_request->list); > + priv_dev->ep0_request = NULL; > + } > + > + priv_dev->gadget.ep0->maxpacket = max_packet_size; > + cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size); > + > + /* init ep out */ > + cdns3_select_ep(priv_dev, USB_DIR_OUT); > + > + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), > + ®s->ep_cfg); > + > + writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN, > + ®s->ep_sts_en); > + > + /* init ep in */ > + cdns3_select_ep(priv_dev, USB_DIR_IN); > + > + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), > + ®s->ep_cfg); > + > + writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, ®s->ep_sts_en); > + > + cdns3_set_register_bit(®s->usb_conf, USB_CONF_U1DS | USB_CONF_U2DS); > + cdns3_prepare_setup_packet(priv_dev); What happens if gadget.speed is USB_SPEED_SUPER, but was connected to a high-speed host? Are you updating the max_packet_size on connection done? > +} > + > +/** > + * cdns3_init_ep0 Initializes software endpoint 0 of gadget > + * @cdns3: extended gadget object > + * > + * Returns 0 on success, error code elsewhere > + */ > +int cdns3_init_ep0(struct cdns3_device *priv_dev) > +{ > + struct cdns3_endpoint *ep0; > + > + ep0 = devm_kzalloc(&priv_dev->dev, sizeof(struct cdns3_endpoint), > + GFP_KERNEL); > + > + if (!ep0) > + return -ENOMEM; > + > + ep0->cdns3_dev = priv_dev; > + sprintf(ep0->name, "ep0"); > + > + /* fill linux fields */ > + //TODO: implements cdns3_gadget_ep0_ops object > + //ep0->endpoint.ops = &cdns3_gadget_ep0_ops; > + ep0->endpoint.maxburst = 1; > + usb_ep_set_maxpacket_limit(&ep0->endpoint, ENDPOINT0_MAX_PACKET_LIMIT); > + ep0->endpoint.address = 0; > + ep0->endpoint.caps.type_control = 1; > + ep0->endpoint.caps.dir_in = 1; > + ep0->endpoint.caps.dir_out = 1; > + ep0->endpoint.name = ep0->name; > + ep0->endpoint.desc = &cdns3_gadget_ep0_desc; > + priv_dev->gadget.ep0 = &ep0->endpoint; > + INIT_LIST_HEAD(&ep0->request_list); > + > + return 0; > +} > diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h > new file mode 100644 > index 000000000000..257e5e0eef31 > --- /dev/null > +++ b/drivers/usb/cdns3/gadget-export.h > @@ -0,0 +1,27 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Cadence USBSS DRD Driver -Gadget Export APIs > + * > + * Copyright (C) 2017 NXP > + * > + * Authors: Peter Chen > + */ > +#ifndef __LINUX_CDNS3_GADGET_EXPORT > +#define __LINUX_CDNS3_GADGET_EXPORT > + > +#ifdef CONFIG_USB_CDNS3_GADGET > + > +int cdns3_gadget_init(struct cdns3 *cdns); > +void cdns3_gadget_remove(struct cdns3 *cdns); > +#else > + > +static inline int cdns3_gadget_init(struct cdns3 *cdns) > +{ > + return -ENXIO; > +} > + > +static inline void cdns3_gadget_remove(struct cdns3 *cdns) { } > + > +#endif > + > +#endif /* __LINUX_CDNS3_GADGET_EXPORT */ > diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c > new file mode 100644 > index 000000000000..376b68b13d1b > --- /dev/null > +++ b/drivers/usb/cdns3/gadget.c > @@ -0,0 +1,390 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver - gadget side. > + * > + * Copyright (C) 2018 Cadence Design Systems. > + * Copyright (C) 2017 NXP > + * > + * Authors: Pawel Jez , > + * Pawel Laszczak > + * Peter Chen > + */ > + > +#include > +#include > + > +#include "core.h" > +#include "gadget-export.h" > +#include "gadget.h" > + > +/** > + * cdns3_set_register_bit - set bit in given register. > + * @ptr: address of device controller register to be read and changed > + * @mask: bits requested to set > + */ > +void cdns3_set_register_bit(void __iomem *ptr, u32 mask) > +{ > + mask = readl(ptr) | mask; > + writel(mask, ptr); > +} static inline? I'd get rid of this function if possible. You are using it only once and it is easier to read code if setting the bitmask is done plainly instead of hiding it behind a function. > + > +/** > + * select_ep - selects endpoint > + * @priv_dev: extended gadget object > + * @ep: endpoint address > + */ > +void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) > +{ > + if (priv_dev->selected_ep == ep) > + return; I didn't understand the purpose of this function. You can only select the EP once? > + > + dev_dbg(&priv_dev->dev, "Ep sel: 0x%02x\n", ep); You should move to use trace-points instead of dev_dbg. > + priv_dev->selected_ep = ep; > + writel(ep, &priv_dev->regs->ep_sel); > +} > + > +/** > + * cdns3_irq_handler - irq line interrupt handler > + * @cdns: cdns3 instance > + * > + * Returns IRQ_HANDLED when interrupt raised by USBSS_DEV, > + * IRQ_NONE when interrupt raised by other device connected > + * to the irq line > + */ > +static irqreturn_t cdns3_irq_handler_thread(struct cdns3 *cdns) > +{ > + irqreturn_t ret = IRQ_NONE; > + //TODO: implements this function > + return ret; > +} > + > +static void cdns3_gadget_config(struct cdns3_device *priv_dev) > +{ > + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; > + > + cdns3_ep0_config(priv_dev); > + > + /* enable interrupts for endpoint 0 (in and out) */ > + writel(EP_IEN_EP_OUT0 | EP_IEN_EP_IN0, ®s->ep_ien); > + > + /* enable generic interrupt*/ > + writel(USB_IEN_INIT, ®s->usb_ien); > + writel(USB_CONF_CLK2OFFDS | USB_CONF_L1DS, ®s->usb_conf); > + writel(USB_CONF_DMULT, ®s->usb_conf); > + writel(USB_CONF_DEVEN, ®s->usb_conf); If you are enabling interrupts in this patch you should handle them in the ISR. > +} > + > +/** > + * cdns3_init_ep Initializes software endpoints of gadget > + * @cdns3: extended gadget object > + * > + * Returns 0 on success, error code elsewhere > + */ > +static int cdns3_init_ep(struct cdns3_device *priv_dev) > +{ > + u32 ep_enabled_reg, iso_ep_reg; > + struct cdns3_endpoint *priv_ep; > + int found_endpoints = 0; > + int ep_dir, ep_number; > + u32 ep_mask; > + int i; > + > + /* Read it from USB_CAP3 to USB_CAP5 */ > + ep_enabled_reg = readl(&priv_dev->regs->usb_cap3); > + iso_ep_reg = readl(&priv_dev->regs->usb_cap4); > + > + dev_dbg(&priv_dev->dev, "Initializing non-zero endpoints\n"); > + > + for (i = 0; i < USB_SS_ENDPOINTS_MAX_COUNT; i++) { CDNS3_USB_SS_ENDPOINTS_MAX_COUNT > + ep_number = (i / 2) + 1; > + ep_dir = i % 2; > + ep_mask = BIT((16 * ep_dir) + ep_number); > + > + if (!(ep_enabled_reg & ep_mask)) > + continue; > + > + priv_ep = devm_kzalloc(&priv_dev->dev, sizeof(*priv_ep), > + GFP_KERNEL); > + if (!priv_ep) > + return -ENOMEM; > + > + /* set parent of endpoint object */ > + priv_ep->cdns3_dev = priv_dev; > + priv_dev->eps[found_endpoints++] = priv_ep; > + > + snprintf(priv_ep->name, sizeof(priv_ep->name), "ep%d%s", > + ep_number, !!ep_dir ? "in" : "out"); > + priv_ep->endpoint.name = priv_ep->name; > + > + usb_ep_set_maxpacket_limit(&priv_ep->endpoint, > + ENDPOINT_MAX_PACKET_LIMIT); CDNS3_ENDPOINT_MAX_PACKET_LIMIT > + priv_ep->endpoint.max_streams = ENDPOINT_MAX_STREAMS; CDNS3_ENDPOINT_MAX_STREAMS > + //TODO: Add implementation of cdns3_gadget_ep_ops > + //priv_ep->endpoint.ops = &cdns3_gadget_ep_ops; > + if (ep_dir) > + priv_ep->endpoint.caps.dir_in = 1; > + else > + priv_ep->endpoint.caps.dir_out = 1; > + > + if (iso_ep_reg & ep_mask) > + priv_ep->endpoint.caps.type_iso = 1; > + > + priv_ep->endpoint.caps.type_bulk = 1; > + priv_ep->endpoint.caps.type_int = 1; > + priv_ep->endpoint.maxburst = CDNS3_EP_BUF_SIZE - 1; > + > + priv_ep->flags = 0; > + > + dev_info(&priv_dev->dev, "Initialized %s support: %s %s\n", > + priv_ep->name, > + priv_ep->endpoint.caps.type_bulk ? "BULK, INT" : "", > + priv_ep->endpoint.caps.type_iso ? "ISO" : ""); > + > + list_add_tail(&priv_ep->endpoint.ep_list, > + &priv_dev->gadget.ep_list); > + INIT_LIST_HEAD(&priv_ep->request_list); > + INIT_LIST_HEAD(&priv_ep->ep_match_pending_list); > + } > + > + priv_dev->ep_nums = found_endpoints; > + return 0; > +} > + > +static void cdns3_gadget_release(struct device *dev) > +{ > + struct cdns3_device *priv_dev; > + > + priv_dev = container_of(dev, struct cdns3_device, dev); > + kfree(priv_dev); > +} > + > +static int __cdns3_gadget_init(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + struct device *dev; > + int ret; > + > + priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); > + if (!priv_dev) > + return -ENOMEM; > + > + dev = &priv_dev->dev; > + dev->release = cdns3_gadget_release; > + dev->parent = cdns->dev; > + dev_set_name(dev, "gadget-cdns3"); > + cdns->gadget_dev = dev; > + > + priv_dev->sysdev = cdns->dev; > + ret = device_register(dev); Why do you need to create this dummy device? you could just use cdns3->dev. > + if (ret) > + goto err1; > + > + priv_dev->regs = cdns->dev_regs; > + > + /* fill gadget fields */ > + priv_dev->gadget.max_speed = USB_SPEED_SUPER; > + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; > + //TODO: Add implementation of cdns3_gadget_ops > + //priv_dev->gadget.ops = &cdns3_gadget_ops; > + priv_dev->gadget.name = "usb-ss-gadget"; > + priv_dev->gadget.sg_supported = 1; > + priv_dev->is_connected = 0; > + > + spin_lock_init(&priv_dev->lock); > + > + priv_dev->in_standby_mode = 1; > + > + /* initialize endpoint container */ > + INIT_LIST_HEAD(&priv_dev->gadget.ep_list); > + INIT_LIST_HEAD(&priv_dev->ep_match_list); > + > + ret = cdns3_init_ep0(priv_dev); > + if (ret) { > + dev_err(dev, "Failed to create endpoint 0\n"); > + ret = -ENOMEM; why not just use the ret as is. > + goto err2; > + } > + > + ret = cdns3_init_ep(priv_dev); > + if (ret) { > + dev_err(dev, "Failed to create non zero endpoints\n"); > + ret = -ENOMEM; here too > + goto err2; > + } > + > + /* allocate memory for default endpoint TRB */ > + priv_dev->trb_ep0 = dma_alloc_coherent(priv_dev->sysdev, 24, what is 24? In error path you are using TRB_SIZE * 2. Should we be using that here too? > + &priv_dev->trb_ep0_dma, GFP_DMA); > + if (!priv_dev->trb_ep0) { > + dev_err(dev, "Failed to allocate memory for ep0 TRB\n"); > + ret = -ENOMEM; > + goto err2; > + } > + > + /* allocate memory for setup packet buffer */ > + priv_dev->setup = dma_alloc_coherent(priv_dev->sysdev, 8, is 8 enough for all use cases? What about vendor specific setup requests? > + &priv_dev->setup_dma, GFP_DMA); > + if (!priv_dev->setup) { > + dev_err(dev, "Failed to allocate memory for SETUP buffer\n"); > + ret = -ENOMEM; > + goto err3; > + } > + > + dev_dbg(dev, "Device Controller version: %08x\n", > + readl(&priv_dev->regs->usb_cap6)); > + dev_dbg(dev, "USB Capabilities:: %08x\n", > + readl(&priv_dev->regs->usb_cap1)); > + dev_dbg(dev, "On-Chip memory cnfiguration: %08x\n", > + readl(&priv_dev->regs->usb_cap2)); > + > + /* add USB gadget device */ > + ret = usb_add_gadget_udc(&priv_dev->dev, &priv_dev->gadget); > + if (ret < 0) { > + dev_err(dev, "Failed to register USB device controller\n"); > + goto err4; > + } > + > + priv_dev->zlp_buf = kzalloc(ENDPOINT_ZLP_BUF_SIZE, GFP_KERNEL); > + if (!priv_dev->zlp_buf) { > + ret = -ENOMEM; > + goto err4; > + } how about allocating zlp_buf before usb_add_gadget_udc()? > + > + return 0; > +err4: > + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup, > + priv_dev->setup_dma); > +err3: > + dma_free_coherent(priv_dev->sysdev, TRB_SIZE * 2, priv_dev->trb_ep0, > + priv_dev->trb_ep0_dma); > +err2: > + device_del(dev); > +err1: > + put_device(dev); > + cdns->gadget_dev = NULL; > + return ret; > +} > + > +/** > + * cdns3_gadget_remove: parent must call this to remove UDC > + * > + * cdns: cdns3 instance > + */ > +void cdns3_gadget_remove(struct cdns3 *cdns) how about calling this cdns3_gadget_exit() to complememnt cdns3_gadget_init() > +{ > + struct cdns3_device *priv_dev; > + > + if (!cdns->roles[CDNS3_ROLE_GADGET]) > + return; why this check? It will lead to an unbalanced exit() and future init(). > + > + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev); > + usb_del_gadget_udc(&priv_dev->gadget); > + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup, > + priv_dev->setup_dma); > + dma_free_coherent(priv_dev->sysdev, TRB_SIZE * 2, priv_dev->trb_ep0, > + priv_dev->trb_ep0_dma); You need to free all memory allocation done in cdns3_init_ep0() and cdns3_init_ep() else we eat memory on every role switch if we plan on getting rid of the dummy gadget_dev. > + device_unregister(cdns->gadget_dev); > + cdns->gadget_dev = NULL; > + kfree(priv_dev->zlp_buf); > +} > + > +static int cdns3_gadget_start(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev = container_of(cdns->gadget_dev, > + struct cdns3_device, dev); > + unsigned long flags; > + > + pm_runtime_get_sync(cdns->dev); This is another reason why we shouldn't be creating a dummy gadget_dev. PM is tied to cdns->dev. > + spin_lock_irqsave(&priv_dev->lock, flags); > + priv_dev->start_gadget = 1; > + > + if (!priv_dev->gadget_driver) { > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > + } > + > + cdns3_gadget_config(priv_dev); > + priv_dev->in_standby_mode = 0; > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > +} > + > +static void __cdns3_gadget_stop(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + unsigned long flags; > + > + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev); > + > + if (priv_dev->gadget_driver) > + priv_dev->gadget_driver->disconnect(&priv_dev->gadget); > + > + usb_gadget_disconnect(&priv_dev->gadget); > + spin_lock_irqsave(&priv_dev->lock, flags); > + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; > + > + /* disable interrupt for device */ > + writel(0, &priv_dev->regs->usb_ien); > + writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf); > + priv_dev->start_gadget = 0; > + spin_unlock_irqrestore(&priv_dev->lock, flags); > +} > + > +static void cdns3_gadget_stop(struct cdns3 *cdns) > +{ > + if (cdns->role == CDNS3_ROLE_GADGET) > + __cdns3_gadget_stop(cdns); Why worry about role here? That should be job of core/drd driver. > + > + pm_runtime_mark_last_busy(cdns->dev); > + pm_runtime_put_autosuspend(cdns->dev); > +} > + > +static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup) > +{ > + __cdns3_gadget_stop(cdns); > + return 0; > +} > + > +static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated) > +{ > + struct cdns3_device *priv_dev; > + unsigned long flags; > + > + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev); > + spin_lock_irqsave(&priv_dev->lock, flags); > + priv_dev->start_gadget = 1; who is using this start_gadget flag? > + if (!priv_dev->gadget_driver) { > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > + } > + > + cdns3_gadget_config(priv_dev); > + priv_dev->in_standby_mode = 0; > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > +} > + > +/** > + * cdns3_gadget_init - initialize device structure > + * > + * cdns: cdns3 instance > + * > + * This function initializes the gadget. > + */ > +int cdns3_gadget_init(struct cdns3 *cdns) > +{ > + struct cdns3_role_driver *rdrv; > + > + rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); > + if (!rdrv) > + return -ENOMEM; > + > + rdrv->start = cdns3_gadget_start; > + rdrv->stop = cdns3_gadget_stop; Why not use gadget_init()/gadget_exit() here? That sounds much cleaner as you won't have ISR's active after a role stop. > + rdrv->suspend = cdns3_gadget_suspend; > + rdrv->resume = cdns3_gadget_resume; > + rdrv->irq = cdns3_irq_handler_thread; > + rdrv->name = "gadget"; > + cdns->roles[CDNS3_ROLE_GADGET] = rdrv; > + return __cdns3_gadget_init(cdns); > +} > diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h > index 75ca6214e79a..3b0d4d2e4831 100644 > --- a/drivers/usb/cdns3/gadget.h > +++ b/drivers/usb/cdns3/gadget.h > @@ -1068,4 +1068,8 @@ struct cdns3_device { > struct usb_request *pending_status_request; > }; > > +void cdns3_set_register_bit(void __iomem *ptr, u32 mask); > +int cdns3_init_ep0(struct cdns3_device *priv_dev); > +void cdns3_ep0_config(struct cdns3_device *priv_dev); > +void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep); > #endif /* __LINUX_CDNS3_GADGET */ > cheers, -roger -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki 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=-8.6 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED 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 97265C43441 for ; Wed, 28 Nov 2018 11:34:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 30E682081B for ; Wed, 28 Nov 2018 11:34:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="bb4cl1ZI" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 30E682081B Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728262AbeK1Wfj (ORCPT ); Wed, 28 Nov 2018 17:35:39 -0500 Received: from fllv0016.ext.ti.com ([198.47.19.142]:45742 "EHLO fllv0016.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727673AbeK1Wfi (ORCPT ); Wed, 28 Nov 2018 17:35:38 -0500 Received: from fllv0034.itg.ti.com ([10.64.40.246]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id wASBYAg2064624; Wed, 28 Nov 2018 05:34:10 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1543404850; bh=17Y8UiWEuQkFJE3aNBiS1u5lA1A4pMFg6zjLpNMJtT4=; h=Subject:To:References:CC:From:Date:In-Reply-To; b=bb4cl1ZIj7ZXJzSSdOTV4EXbAvYXSHkfCW7HwR8BhKvwumhZKpCXzgsal+U1Xs1Fw YzJLSfoxWXUmqUGWl9Nzu17xvUNVRLzYvsQhSEGk/YRvlcTNn7M6dI96aWdLtc6dP+ TuKkUKHSsJ4M1ZGT6gGdvMOBI5CCbZvTYnpoeACM= Received: from DLEE109.ent.ti.com (dlee109.ent.ti.com [157.170.170.41]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id wASBYA6v010881 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 28 Nov 2018 05:34:10 -0600 Received: from DLEE114.ent.ti.com (157.170.170.25) by DLEE109.ent.ti.com (157.170.170.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Wed, 28 Nov 2018 05:34:10 -0600 Received: from dlep32.itg.ti.com (157.170.170.100) by DLEE114.ent.ti.com (157.170.170.25) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Wed, 28 Nov 2018 05:34:10 -0600 Received: from [192.168.2.6] (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id wASBY6IJ018558; Wed, 28 Nov 2018 05:34:07 -0600 Subject: Re: [RFC PATCH v2 07/15] usb:cdns3: Adds Device mode support - initialization. To: Pawel Laszczak , , Felipe Balbi References: <1542535751-16079-1-git-send-email-pawell@cadence.com> <1542535751-16079-8-git-send-email-pawell@cadence.com> CC: , , , , , , , , , , From: Roger Quadros Message-ID: <5BFE7D2E.7030702@ti.com> Date: Wed, 28 Nov 2018 13:34:06 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.6.0 MIME-Version: 1.0 In-Reply-To: <1542535751-16079-8-git-send-email-pawell@cadence.com> Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org +Felipe. Pawel, Please copy Felipe Balbi as he maintains the USB gadget stack. On 18/11/18 12:09, Pawel Laszczak wrote: > Patch implements a set of functions responsible for initialization, > configuration, starting and stopping device mode. > This patch also adds new ep0.c that holds all functions related > to endpoint 0. > > Signed-off-by: Pawel Laszczak > --- > drivers/usb/cdns3/Kconfig | 10 + > drivers/usb/cdns3/Makefile | 1 + > drivers/usb/cdns3/core.c | 5 +- > drivers/usb/cdns3/ep0.c | 105 ++++++++ > drivers/usb/cdns3/gadget-export.h | 27 +++ > drivers/usb/cdns3/gadget.c | 390 ++++++++++++++++++++++++++++++ > drivers/usb/cdns3/gadget.h | 4 + > 7 files changed, 541 insertions(+), 1 deletion(-) > create mode 100644 drivers/usb/cdns3/ep0.c > create mode 100644 drivers/usb/cdns3/gadget-export.h > create mode 100644 drivers/usb/cdns3/gadget.c > > diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig > index d92bc3d68eb0..b7d71b5c4f60 100644 > --- a/drivers/usb/cdns3/Kconfig > +++ b/drivers/usb/cdns3/Kconfig > @@ -10,6 +10,16 @@ config USB_CDNS3 > > if USB_CDNS3 > > +config USB_CDNS3_GADGET > + bool "Cadence USB3 device controller" > + depends on USB_GADGET > + help > + Say Y here to enable device controller functionality of the > + cadence USBSS-DEV driver. > + > + This controller support FF, HS and SS mode. It doeasn't support s/support/supports s/doeasn't/doesn't > + LS and SSP mode > + > config USB_CDNS3_HOST > bool "Cadence USB3 host controller" > depends on USB_XHCI_HCD > diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile > index 976117ba67ff..bea6173bf37f 100644 > --- a/drivers/usb/cdns3/Makefile > +++ b/drivers/usb/cdns3/Makefile > @@ -2,5 +2,6 @@ obj-$(CONFIG_USB_CDNS3) += cdns3.o > obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o > > cdns3-y := core.o drd.o > +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o > cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o > cdns3-pci-y := cdns3-pci-wrap.o > diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c > index 4cb820be9ff3..1fa233415901 100644 > --- a/drivers/usb/cdns3/core.c > +++ b/drivers/usb/cdns3/core.c > @@ -18,6 +18,7 @@ > #include "gadget.h" > #include "core.h" > #include "host-export.h" > +#include "gadget-export.h" > #include "drd.h" > > static inline struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) > @@ -104,7 +105,8 @@ static int cdns3_core_init_role(struct cdns3 *cdns) > } > > if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { > - //TODO: implements device initialization > + if (cdns3_gadget_init(cdns)) > + dev_info(dev, "doesn't support gadget\n"); dev_err() and we should should error out with error code returned by cdns3_gadget_init(). > } > > if (!cdns->roles[CDNS3_ROLE_HOST] && !cdns->roles[CDNS3_ROLE_GADGET]) { > @@ -144,6 +146,7 @@ static irqreturn_t cdns3_irq(int irq, void *data) > > static void cdns3_remove_roles(struct cdns3 *cdns) > { if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) > + cdns3_gadget_remove(cdns); > cdns3_host_remove(cdns); > } > > diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c > new file mode 100644 > index 000000000000..c08d02665f9d > --- /dev/null > +++ b/drivers/usb/cdns3/ep0.c > @@ -0,0 +1,105 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver - gadget side. > + * > + * Copyright (C) 2018 Cadence Design Systems. > + * Copyright (C) 2017 NXP > + * > + * Authors: Pawel Jez , > + * Pawel Laszczak > + * Peter Chen > + */ > + > +#include "gadget.h" > + > +static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { > + .bLength = USB_DT_ENDPOINT_SIZE, > + .bDescriptorType = USB_DT_ENDPOINT, > + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, > +}; > + > +static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) > +{ > + //TODO: Implements this function > +} > + > +/** > + * cdns3_ep0_config - Configures default endpoint > + * @priv_dev: extended gadget object > + * > + * Functions sets parameters: maximal packet size and enables interrupts > + */ > +void cdns3_ep0_config(struct cdns3_device *priv_dev) > +{ > + struct cdns3_usb_regs __iomem *regs; > + u32 max_packet_size = 64; > + > + regs = priv_dev->regs; > + > + if (priv_dev->gadget.speed == USB_SPEED_SUPER) > + max_packet_size = 512; is gadget.speed known at this point? I think it will only be known after a connection is made. > + > + if (priv_dev->ep0_request) { > + list_del_init(&priv_dev->ep0_request->list); > + priv_dev->ep0_request = NULL; > + } > + > + priv_dev->gadget.ep0->maxpacket = max_packet_size; > + cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size); > + > + /* init ep out */ > + cdns3_select_ep(priv_dev, USB_DIR_OUT); > + > + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), > + ®s->ep_cfg); > + > + writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN, > + ®s->ep_sts_en); > + > + /* init ep in */ > + cdns3_select_ep(priv_dev, USB_DIR_IN); > + > + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), > + ®s->ep_cfg); > + > + writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, ®s->ep_sts_en); > + > + cdns3_set_register_bit(®s->usb_conf, USB_CONF_U1DS | USB_CONF_U2DS); > + cdns3_prepare_setup_packet(priv_dev); What happens if gadget.speed is USB_SPEED_SUPER, but was connected to a high-speed host? Are you updating the max_packet_size on connection done? > +} > + > +/** > + * cdns3_init_ep0 Initializes software endpoint 0 of gadget > + * @cdns3: extended gadget object > + * > + * Returns 0 on success, error code elsewhere > + */ > +int cdns3_init_ep0(struct cdns3_device *priv_dev) > +{ > + struct cdns3_endpoint *ep0; > + > + ep0 = devm_kzalloc(&priv_dev->dev, sizeof(struct cdns3_endpoint), > + GFP_KERNEL); > + > + if (!ep0) > + return -ENOMEM; > + > + ep0->cdns3_dev = priv_dev; > + sprintf(ep0->name, "ep0"); > + > + /* fill linux fields */ > + //TODO: implements cdns3_gadget_ep0_ops object > + //ep0->endpoint.ops = &cdns3_gadget_ep0_ops; > + ep0->endpoint.maxburst = 1; > + usb_ep_set_maxpacket_limit(&ep0->endpoint, ENDPOINT0_MAX_PACKET_LIMIT); > + ep0->endpoint.address = 0; > + ep0->endpoint.caps.type_control = 1; > + ep0->endpoint.caps.dir_in = 1; > + ep0->endpoint.caps.dir_out = 1; > + ep0->endpoint.name = ep0->name; > + ep0->endpoint.desc = &cdns3_gadget_ep0_desc; > + priv_dev->gadget.ep0 = &ep0->endpoint; > + INIT_LIST_HEAD(&ep0->request_list); > + > + return 0; > +} > diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h > new file mode 100644 > index 000000000000..257e5e0eef31 > --- /dev/null > +++ b/drivers/usb/cdns3/gadget-export.h > @@ -0,0 +1,27 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Cadence USBSS DRD Driver -Gadget Export APIs > + * > + * Copyright (C) 2017 NXP > + * > + * Authors: Peter Chen > + */ > +#ifndef __LINUX_CDNS3_GADGET_EXPORT > +#define __LINUX_CDNS3_GADGET_EXPORT > + > +#ifdef CONFIG_USB_CDNS3_GADGET > + > +int cdns3_gadget_init(struct cdns3 *cdns); > +void cdns3_gadget_remove(struct cdns3 *cdns); > +#else > + > +static inline int cdns3_gadget_init(struct cdns3 *cdns) > +{ > + return -ENXIO; > +} > + > +static inline void cdns3_gadget_remove(struct cdns3 *cdns) { } > + > +#endif > + > +#endif /* __LINUX_CDNS3_GADGET_EXPORT */ > diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c > new file mode 100644 > index 000000000000..376b68b13d1b > --- /dev/null > +++ b/drivers/usb/cdns3/gadget.c > @@ -0,0 +1,390 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Cadence USBSS DRD Driver - gadget side. > + * > + * Copyright (C) 2018 Cadence Design Systems. > + * Copyright (C) 2017 NXP > + * > + * Authors: Pawel Jez , > + * Pawel Laszczak > + * Peter Chen > + */ > + > +#include > +#include > + > +#include "core.h" > +#include "gadget-export.h" > +#include "gadget.h" > + > +/** > + * cdns3_set_register_bit - set bit in given register. > + * @ptr: address of device controller register to be read and changed > + * @mask: bits requested to set > + */ > +void cdns3_set_register_bit(void __iomem *ptr, u32 mask) > +{ > + mask = readl(ptr) | mask; > + writel(mask, ptr); > +} static inline? I'd get rid of this function if possible. You are using it only once and it is easier to read code if setting the bitmask is done plainly instead of hiding it behind a function. > + > +/** > + * select_ep - selects endpoint > + * @priv_dev: extended gadget object > + * @ep: endpoint address > + */ > +void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) > +{ > + if (priv_dev->selected_ep == ep) > + return; I didn't understand the purpose of this function. You can only select the EP once? > + > + dev_dbg(&priv_dev->dev, "Ep sel: 0x%02x\n", ep); You should move to use trace-points instead of dev_dbg. > + priv_dev->selected_ep = ep; > + writel(ep, &priv_dev->regs->ep_sel); > +} > + > +/** > + * cdns3_irq_handler - irq line interrupt handler > + * @cdns: cdns3 instance > + * > + * Returns IRQ_HANDLED when interrupt raised by USBSS_DEV, > + * IRQ_NONE when interrupt raised by other device connected > + * to the irq line > + */ > +static irqreturn_t cdns3_irq_handler_thread(struct cdns3 *cdns) > +{ > + irqreturn_t ret = IRQ_NONE; > + //TODO: implements this function > + return ret; > +} > + > +static void cdns3_gadget_config(struct cdns3_device *priv_dev) > +{ > + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; > + > + cdns3_ep0_config(priv_dev); > + > + /* enable interrupts for endpoint 0 (in and out) */ > + writel(EP_IEN_EP_OUT0 | EP_IEN_EP_IN0, ®s->ep_ien); > + > + /* enable generic interrupt*/ > + writel(USB_IEN_INIT, ®s->usb_ien); > + writel(USB_CONF_CLK2OFFDS | USB_CONF_L1DS, ®s->usb_conf); > + writel(USB_CONF_DMULT, ®s->usb_conf); > + writel(USB_CONF_DEVEN, ®s->usb_conf); If you are enabling interrupts in this patch you should handle them in the ISR. > +} > + > +/** > + * cdns3_init_ep Initializes software endpoints of gadget > + * @cdns3: extended gadget object > + * > + * Returns 0 on success, error code elsewhere > + */ > +static int cdns3_init_ep(struct cdns3_device *priv_dev) > +{ > + u32 ep_enabled_reg, iso_ep_reg; > + struct cdns3_endpoint *priv_ep; > + int found_endpoints = 0; > + int ep_dir, ep_number; > + u32 ep_mask; > + int i; > + > + /* Read it from USB_CAP3 to USB_CAP5 */ > + ep_enabled_reg = readl(&priv_dev->regs->usb_cap3); > + iso_ep_reg = readl(&priv_dev->regs->usb_cap4); > + > + dev_dbg(&priv_dev->dev, "Initializing non-zero endpoints\n"); > + > + for (i = 0; i < USB_SS_ENDPOINTS_MAX_COUNT; i++) { CDNS3_USB_SS_ENDPOINTS_MAX_COUNT > + ep_number = (i / 2) + 1; > + ep_dir = i % 2; > + ep_mask = BIT((16 * ep_dir) + ep_number); > + > + if (!(ep_enabled_reg & ep_mask)) > + continue; > + > + priv_ep = devm_kzalloc(&priv_dev->dev, sizeof(*priv_ep), > + GFP_KERNEL); > + if (!priv_ep) > + return -ENOMEM; > + > + /* set parent of endpoint object */ > + priv_ep->cdns3_dev = priv_dev; > + priv_dev->eps[found_endpoints++] = priv_ep; > + > + snprintf(priv_ep->name, sizeof(priv_ep->name), "ep%d%s", > + ep_number, !!ep_dir ? "in" : "out"); > + priv_ep->endpoint.name = priv_ep->name; > + > + usb_ep_set_maxpacket_limit(&priv_ep->endpoint, > + ENDPOINT_MAX_PACKET_LIMIT); CDNS3_ENDPOINT_MAX_PACKET_LIMIT > + priv_ep->endpoint.max_streams = ENDPOINT_MAX_STREAMS; CDNS3_ENDPOINT_MAX_STREAMS > + //TODO: Add implementation of cdns3_gadget_ep_ops > + //priv_ep->endpoint.ops = &cdns3_gadget_ep_ops; > + if (ep_dir) > + priv_ep->endpoint.caps.dir_in = 1; > + else > + priv_ep->endpoint.caps.dir_out = 1; > + > + if (iso_ep_reg & ep_mask) > + priv_ep->endpoint.caps.type_iso = 1; > + > + priv_ep->endpoint.caps.type_bulk = 1; > + priv_ep->endpoint.caps.type_int = 1; > + priv_ep->endpoint.maxburst = CDNS3_EP_BUF_SIZE - 1; > + > + priv_ep->flags = 0; > + > + dev_info(&priv_dev->dev, "Initialized %s support: %s %s\n", > + priv_ep->name, > + priv_ep->endpoint.caps.type_bulk ? "BULK, INT" : "", > + priv_ep->endpoint.caps.type_iso ? "ISO" : ""); > + > + list_add_tail(&priv_ep->endpoint.ep_list, > + &priv_dev->gadget.ep_list); > + INIT_LIST_HEAD(&priv_ep->request_list); > + INIT_LIST_HEAD(&priv_ep->ep_match_pending_list); > + } > + > + priv_dev->ep_nums = found_endpoints; > + return 0; > +} > + > +static void cdns3_gadget_release(struct device *dev) > +{ > + struct cdns3_device *priv_dev; > + > + priv_dev = container_of(dev, struct cdns3_device, dev); > + kfree(priv_dev); > +} > + > +static int __cdns3_gadget_init(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + struct device *dev; > + int ret; > + > + priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); > + if (!priv_dev) > + return -ENOMEM; > + > + dev = &priv_dev->dev; > + dev->release = cdns3_gadget_release; > + dev->parent = cdns->dev; > + dev_set_name(dev, "gadget-cdns3"); > + cdns->gadget_dev = dev; > + > + priv_dev->sysdev = cdns->dev; > + ret = device_register(dev); Why do you need to create this dummy device? you could just use cdns3->dev. > + if (ret) > + goto err1; > + > + priv_dev->regs = cdns->dev_regs; > + > + /* fill gadget fields */ > + priv_dev->gadget.max_speed = USB_SPEED_SUPER; > + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; > + //TODO: Add implementation of cdns3_gadget_ops > + //priv_dev->gadget.ops = &cdns3_gadget_ops; > + priv_dev->gadget.name = "usb-ss-gadget"; > + priv_dev->gadget.sg_supported = 1; > + priv_dev->is_connected = 0; > + > + spin_lock_init(&priv_dev->lock); > + > + priv_dev->in_standby_mode = 1; > + > + /* initialize endpoint container */ > + INIT_LIST_HEAD(&priv_dev->gadget.ep_list); > + INIT_LIST_HEAD(&priv_dev->ep_match_list); > + > + ret = cdns3_init_ep0(priv_dev); > + if (ret) { > + dev_err(dev, "Failed to create endpoint 0\n"); > + ret = -ENOMEM; why not just use the ret as is. > + goto err2; > + } > + > + ret = cdns3_init_ep(priv_dev); > + if (ret) { > + dev_err(dev, "Failed to create non zero endpoints\n"); > + ret = -ENOMEM; here too > + goto err2; > + } > + > + /* allocate memory for default endpoint TRB */ > + priv_dev->trb_ep0 = dma_alloc_coherent(priv_dev->sysdev, 24, what is 24? In error path you are using TRB_SIZE * 2. Should we be using that here too? > + &priv_dev->trb_ep0_dma, GFP_DMA); > + if (!priv_dev->trb_ep0) { > + dev_err(dev, "Failed to allocate memory for ep0 TRB\n"); > + ret = -ENOMEM; > + goto err2; > + } > + > + /* allocate memory for setup packet buffer */ > + priv_dev->setup = dma_alloc_coherent(priv_dev->sysdev, 8, is 8 enough for all use cases? What about vendor specific setup requests? > + &priv_dev->setup_dma, GFP_DMA); > + if (!priv_dev->setup) { > + dev_err(dev, "Failed to allocate memory for SETUP buffer\n"); > + ret = -ENOMEM; > + goto err3; > + } > + > + dev_dbg(dev, "Device Controller version: %08x\n", > + readl(&priv_dev->regs->usb_cap6)); > + dev_dbg(dev, "USB Capabilities:: %08x\n", > + readl(&priv_dev->regs->usb_cap1)); > + dev_dbg(dev, "On-Chip memory cnfiguration: %08x\n", > + readl(&priv_dev->regs->usb_cap2)); > + > + /* add USB gadget device */ > + ret = usb_add_gadget_udc(&priv_dev->dev, &priv_dev->gadget); > + if (ret < 0) { > + dev_err(dev, "Failed to register USB device controller\n"); > + goto err4; > + } > + > + priv_dev->zlp_buf = kzalloc(ENDPOINT_ZLP_BUF_SIZE, GFP_KERNEL); > + if (!priv_dev->zlp_buf) { > + ret = -ENOMEM; > + goto err4; > + } how about allocating zlp_buf before usb_add_gadget_udc()? > + > + return 0; > +err4: > + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup, > + priv_dev->setup_dma); > +err3: > + dma_free_coherent(priv_dev->sysdev, TRB_SIZE * 2, priv_dev->trb_ep0, > + priv_dev->trb_ep0_dma); > +err2: > + device_del(dev); > +err1: > + put_device(dev); > + cdns->gadget_dev = NULL; > + return ret; > +} > + > +/** > + * cdns3_gadget_remove: parent must call this to remove UDC > + * > + * cdns: cdns3 instance > + */ > +void cdns3_gadget_remove(struct cdns3 *cdns) how about calling this cdns3_gadget_exit() to complememnt cdns3_gadget_init() > +{ > + struct cdns3_device *priv_dev; > + > + if (!cdns->roles[CDNS3_ROLE_GADGET]) > + return; why this check? It will lead to an unbalanced exit() and future init(). > + > + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev); > + usb_del_gadget_udc(&priv_dev->gadget); > + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup, > + priv_dev->setup_dma); > + dma_free_coherent(priv_dev->sysdev, TRB_SIZE * 2, priv_dev->trb_ep0, > + priv_dev->trb_ep0_dma); You need to free all memory allocation done in cdns3_init_ep0() and cdns3_init_ep() else we eat memory on every role switch if we plan on getting rid of the dummy gadget_dev. > + device_unregister(cdns->gadget_dev); > + cdns->gadget_dev = NULL; > + kfree(priv_dev->zlp_buf); > +} > + > +static int cdns3_gadget_start(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev = container_of(cdns->gadget_dev, > + struct cdns3_device, dev); > + unsigned long flags; > + > + pm_runtime_get_sync(cdns->dev); This is another reason why we shouldn't be creating a dummy gadget_dev. PM is tied to cdns->dev. > + spin_lock_irqsave(&priv_dev->lock, flags); > + priv_dev->start_gadget = 1; > + > + if (!priv_dev->gadget_driver) { > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > + } > + > + cdns3_gadget_config(priv_dev); > + priv_dev->in_standby_mode = 0; > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > +} > + > +static void __cdns3_gadget_stop(struct cdns3 *cdns) > +{ > + struct cdns3_device *priv_dev; > + unsigned long flags; > + > + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev); > + > + if (priv_dev->gadget_driver) > + priv_dev->gadget_driver->disconnect(&priv_dev->gadget); > + > + usb_gadget_disconnect(&priv_dev->gadget); > + spin_lock_irqsave(&priv_dev->lock, flags); > + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; > + > + /* disable interrupt for device */ > + writel(0, &priv_dev->regs->usb_ien); > + writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf); > + priv_dev->start_gadget = 0; > + spin_unlock_irqrestore(&priv_dev->lock, flags); > +} > + > +static void cdns3_gadget_stop(struct cdns3 *cdns) > +{ > + if (cdns->role == CDNS3_ROLE_GADGET) > + __cdns3_gadget_stop(cdns); Why worry about role here? That should be job of core/drd driver. > + > + pm_runtime_mark_last_busy(cdns->dev); > + pm_runtime_put_autosuspend(cdns->dev); > +} > + > +static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup) > +{ > + __cdns3_gadget_stop(cdns); > + return 0; > +} > + > +static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated) > +{ > + struct cdns3_device *priv_dev; > + unsigned long flags; > + > + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev); > + spin_lock_irqsave(&priv_dev->lock, flags); > + priv_dev->start_gadget = 1; who is using this start_gadget flag? > + if (!priv_dev->gadget_driver) { > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > + } > + > + cdns3_gadget_config(priv_dev); > + priv_dev->in_standby_mode = 0; > + spin_unlock_irqrestore(&priv_dev->lock, flags); > + return 0; > +} > + > +/** > + * cdns3_gadget_init - initialize device structure > + * > + * cdns: cdns3 instance > + * > + * This function initializes the gadget. > + */ > +int cdns3_gadget_init(struct cdns3 *cdns) > +{ > + struct cdns3_role_driver *rdrv; > + > + rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); > + if (!rdrv) > + return -ENOMEM; > + > + rdrv->start = cdns3_gadget_start; > + rdrv->stop = cdns3_gadget_stop; Why not use gadget_init()/gadget_exit() here? That sounds much cleaner as you won't have ISR's active after a role stop. > + rdrv->suspend = cdns3_gadget_suspend; > + rdrv->resume = cdns3_gadget_resume; > + rdrv->irq = cdns3_irq_handler_thread; > + rdrv->name = "gadget"; > + cdns->roles[CDNS3_ROLE_GADGET] = rdrv; > + return __cdns3_gadget_init(cdns); > +} > diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h > index 75ca6214e79a..3b0d4d2e4831 100644 > --- a/drivers/usb/cdns3/gadget.h > +++ b/drivers/usb/cdns3/gadget.h > @@ -1068,4 +1068,8 @@ struct cdns3_device { > struct usb_request *pending_status_request; > }; > > +void cdns3_set_register_bit(void __iomem *ptr, u32 mask); > +int cdns3_init_ep0(struct cdns3_device *priv_dev); > +void cdns3_ep0_config(struct cdns3_device *priv_dev); > +void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep); > #endif /* __LINUX_CDNS3_GADGET */ > cheers, -roger -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki