123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056 |
- /*
- * Copyright (c) 2020 Actions Corporation.
- * Author: Jinang Lv <lvjinang@actions-semi.com>
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @file
- * @brief Actions USB OTG controller driver
- *
- * Actions USB OTG controller driver. The driver implements
- * the low level control routines to deal directly with the hardware.
- */
- #include <kernel.h>
- #include <sys/sys_io.h>
- #include <board.h>
- #include <init.h>
- #include <drivers/dma.h>
- #include <string.h>
- #include <stdio.h>
- #include <errno.h>
- #include <sys/byteorder.h>
- #include <devicetree.h>
- #include <drivers/usb/usb_dc.h>
- #include <drivers/usb/usb_hc.h>
- #include <drivers/usb/usb_phy.h>
- #include <soc_clock.h>
- #include <soc_reset.h>
- #include <soc_pmu.h>
- #include "usb_otg_aotg.h"
- #include <logging/log.h>
- #define LOG_LEVEL CONFIG_SYS_LOG_USB_OTG_DRIVER_LEVEL
- LOG_MODULE_REGISTER(usb_otg_aotg);
- #define DMA_ID_USB0 4
- #define DMA_IRQ_TC (0) /* DMA completion flag */
- #define DMA_IRQ_HF (1) /* DMA half-full flag */
- #define USB_AOTG_DMA_BURST8_LEN 32
- #define USB_AOTG_DMA_MAX_SIZE (128 * 1024)
- #define USB_AOTG_DMA_MAX_LEN (64 * 1024)
- #ifdef CONFIG_USB_AOTG_UDC_DMA
- #define USB_EP_OUT_DMA_CAP(ep_idx) (ep_idx == USB_AOTG_OUT_EP_2)
- #define USB_EP_IN_DMA_CAP(ep_idx) (ep_idx == USB_AOTG_IN_EP_1)
- #else
- #define USB_EP_OUT_DMA_CAP(ep) (false)
- #define USB_EP_IN_DMA_CAP(ep) (false)
- #endif
- /*
- * USB device controller endpoint private structure.
- */
- struct aotg_dc_ep_ctrl_prv {
- uint8_t ep_ena; /* Endpoint Enabled */
- uint8_t ep_type;
- uint16_t mps; /* Endpoint Max packet size */
- usb_dc_ep_callback cb; /* Endpoint callback function */
- /*
- * "data_len" has different meanings in different cases.
- *
- * for ep0-in: set in setup phase.
- * for ep0-out: set in setup or data phase.
- * for epX-in legacy mode: not used.
- * for epX-in new mode: set by upper layer, update in epin interrupt.
- * for epX-in DMA: set by upper layer to help if need to set busy.
- * for epX-out: set in epout interrupt.
- * for epX-out async: set by upper layer, update in epout interrupt
- * for epX-out DMA: set by upper layer.
- */
- uint32_t data_len;
- uint32_t actual; /* actual length: only for epX-out async */
- /*
- * "data" has different meanings in different cases.
- *
- * for ep0-in: not used.
- * for ep0-out: not used.
- * for epX-in legacy mode: not used.
- * for epX-in new mode: set by upper layer, update in epin interrupt.
- * for epX-out: not used.
- * for epX-out async: set by upper layer, update in epout interrupt.
- */
- uint8_t *data;
- uint8_t multi; /* multi-fifo */
- };
- /*
- * USB device controller private structure.
- */
- struct usb_aotg_dc_prv {
- usb_dc_status_callback status_cb;
- struct aotg_dc_ep_ctrl_prv in_ep_ctrl[USB_AOTG_IN_EP_NUM+1];
- struct aotg_dc_ep_ctrl_prv out_ep_ctrl[USB_AOTG_OUT_EP_NUM+1];
- uint8_t attached;
- uint8_t phase; /* Control transfer stage */
- uint8_t speed;
- union {
- uint8_t raw_setup[sizeof(struct usb_setup_packet)];
- struct usb_setup_packet setup;
- };
- };
- /*
- * USB host controller endpoint private structure.
- */
- struct aotg_hc_ep_ctrl_prv {
- uint8_t ep_ena; /* Endpoint Enabled */
- uint8_t ep_type;
- uint16_t mps; /* Endpoint Max packet size */
- struct usb_request *urb;
- uint8_t ep_addr; /* Endpoint Address */
- uint8_t err_count;
- };
- /*
- * USB host controller private structure.
- */
- struct usb_aotg_hc_prv {
- uint32_t port;
- struct aotg_hc_ep_ctrl_prv in_ep_ctrl[USB_AOTG_IN_EP_NUM];
- struct aotg_hc_ep_ctrl_prv out_ep_ctrl[USB_AOTG_OUT_EP_NUM];
- uint8_t attached;
- uint8_t phase; /* Control transfer stage */
- uint8_t speed;
- };
- struct usb_aotg_otg_prv {
- union {
- #ifdef CONFIG_USB_AOTG_DC_ENABLED
- struct usb_aotg_dc_prv dc;
- #endif
- #ifdef CONFIG_USB_AOTG_HC_ENABLED
- struct usb_aotg_hc_prv hc;
- #endif
- };
- };
- static struct usb_aotg_otg_prv usb_aotg;
- static uint8_t usb_aotg_mode;
- #ifdef CONFIG_USB_AOTG_DC_ENABLED
- #define usb_aotg_dc (usb_aotg.dc)
- #endif
- #ifdef CONFIG_USB_AOTG_HC_ENABLED
- #define usb_aotg_hc (usb_aotg.hc)
- #endif
- #ifdef CONFIG_USB_AOTG_UDC_DMA
- struct usb_aotg_dma_prv {
- const struct device *dma_dev;
- int epin_dma;
- int epout_dma_single;
- int epout_dma_burst8;
- struct dma_config epin_dma_config;
- struct dma_config epout_dma_config_single;
- struct dma_config epout_dma_config_burst8;
- struct dma_block_config epin_dma_block;
- struct dma_block_config epout_dma_block_single;
- struct dma_block_config epout_dma_block_burst8;
- };
- static struct usb_aotg_dma_prv usb_aotg_dma;
- #endif
- /*
- * Dump aotg registers
- */
- static inline void usb_aotg_reg_dump(void)
- {
- LOG_DBG("USB AOTG registers:");
- LOG_DBG("IDVBUSCTRL: 0x%x", usb_read8(IDVBUSCTRL));
- LOG_DBG("DPDMCTRL: 0x%x", usb_read8(DPDMCTRL));
- LOG_DBG("LINESTATUS: 0x%x", usb_read8(LINESTATUS));
- LOG_DBG("USBIEN: 0x%x", usb_read8(USBIEN));
- LOG_DBG("OTGIEN: 0x%x", usb_read8(OTGIEN));
- LOG_DBG("USBEIEN: 0x%x", usb_read8(USBEIEN));
- LOG_DBG("USBIRQ: 0x%x", usb_read8(USBIRQ));
- LOG_DBG("OTGIRQ: 0x%x", usb_read8(OTGIRQ));
- LOG_DBG("USBEIRQ: 0x%x", usb_read8(USBEIRQ));
- LOG_DBG("OTGSTATE: 0x%x", usb_read8(OTGSTATE));
- }
- /*
- * Dump aotg endpoint registers
- */
- static inline void usb_aotg_ep_reg_dump(uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- ARG_UNUSED(ep_idx);
- LOG_DBG("USB AOTG EP 0x%x registers:", ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- LOG_DBG("HCINCTRL: 0x%x", usb_read8(HCINxCTRL(ep_idx)));
- LOG_DBG("STADDR: 0x%x", usb_read32(EPxOUT_STADDR(ep_idx)));
- LOG_DBG("OUT_CTRL: 0x%x", usb_read8(OUTxCTRL(ep_idx)));
- LOG_DBG("OUT_MAXPKT: 0x%x", usb_read16(OUTxMAXPKT(ep_idx)));
- LOG_DBG("OUT_IEN: 0x%x", usb_read8(OUTIEN));
- LOG_DBG("OUT_CS: 0x%x", usb_read8(OUTxCS(ep_idx)));
- LOG_DBG("OUT_SHTPKT: 0x%x", usb_read8(OUT_SHTPKT));
- LOG_DBG("OUT_BC: 0x%x", usb_read16(OUTxBC(ep_idx)));
- LOG_DBG("OUT_IRQ: 0x%x", usb_read8(OUTIRQ));
- } else {
- LOG_DBG("HCOUTCTRL: 0x%x", usb_read8(HCOUTxCTRL(ep_idx)));
- LOG_DBG("STADDR: 0x%x", usb_read32(EPxIN_STADDR(ep_idx)));
- LOG_DBG("IN_CTRL: 0x%x", usb_read8(INxCTRL(ep_idx)));
- LOG_DBG("IN_MAXPKT: 0x%x", usb_read16(INxMAXPKT(ep_idx)));
- LOG_DBG("IN_IEN: 0x%x", usb_read8(INIEN));
- LOG_DBG("IN_CS: 0x%x", usb_read8(INxCS(ep_idx)));
- LOG_DBG("IN_IRQ: 0x%x", usb_read8(INIRQ));
- }
- }
- /*
- * Check if the address of endpoint is valid
- *
- * NOTE: we don't check if the address of control endpoint is non-zero!
- */
- static inline bool usb_aotg_ep_addr_valid(uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep) && (ep_idx < USB_AOTG_OUT_EP_NUM)) {
- return true;
- } else if (USB_EP_DIR_IS_IN(ep) && (ep_idx < USB_AOTG_IN_EP_NUM)) {
- return true;
- }
- return false;
- }
- /*
- * Enable USB controller clock
- */
- static inline void usb_aotg_clock_enable(void)
- {
- acts_clock_peripheral_enable(CLOCK_ID_USB);
- }
- /*
- * Disable USB controller clock
- */
- static inline void usb_aotg_clock_disable(void)
- {
- acts_clock_peripheral_disable(CLOCK_ID_USB);
- }
- /*
- * Reset USB controller
- */
- static inline int usb_aotg_reset(void)
- {
- acts_reset_peripheral(RESET_ID_USB2);
- acts_reset_peripheral(RESET_ID_USB);
- usb_aotg_reset_specific();
- /* Wait for USB controller until reset done */
- while (usb_read8(LINESTATUS) & BIT(OTGRESET)) {
- ;
- }
- return 0;
- }
- /*
- * Enable controller
- */
- static inline void usb_aotg_enable(void)
- {
- usb_aotg_power_on();
- usb_aotg_clock_enable();
- usb_aotg_dpdm_init();
- usb_aotg_reset();
- }
- /*
- * Disable controller
- */
- static inline void usb_aotg_disable(void)
- {
- usb_aotg_disable_specific();
- usb_aotg_clock_disable();
- usb_aotg_power_off();
- }
- /*
- * Reset specific endpoint
- */
- static inline int usb_aotg_ep_reset(uint8_t aotg_ep, uint8_t type)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- if (!ep_idx) {
- LOG_DBG("Ep reset all endpoints");
- }
- /* Select specific endpoint */
- if (USB_EP_DIR_IS_OUT(aotg_ep)) {
- usb_write8(EPRST, ep_idx);
- } else {
- usb_write8(EPRST, ep_idx | BIT(EPRST_IO_IN));
- }
- if (type == USB_AOTG_EP_FIFO_RESET) {
- usb_set_bit8(EPRST, EPRST_FIFORST);
- } else if (type == USB_AOTG_EP_TOGGLE_RESET) {
- usb_set_bit8(EPRST, EPRST_TOGRST);
- } else if (type == USB_AOTG_EP_RESET) {
- usb_set_bit8(EPRST, EPRST_FIFORST);
- usb_set_bit8(EPRST, EPRST_TOGRST);
- } else {
- LOG_ERR("Ep reset type: %d", type);
- return -EINVAL;
- }
- return 0;
- }
- static inline int usb_aotg_exit(void)
- {
- usb_aotg_enable();
- usb_aotg_disable();
- return 0;
- }
- /*
- * Write data to EPx FIFO
- *
- * @return Actual length
- */
- static inline int ep_write_fifo(uint8_t ep, const uint8_t *const data,
- uint32_t data_len)
- {
- uint32_t i;
- uint32_t len;
- uint8_t left;
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- const uint8_t *buf = (const uint8_t *)data;
- uint8_t count = 0;
- if (USB_EP_IN_DMA_CAP(ep_idx)) {
- /* FIXME: wait 100us at most */
- while (usb_read8(INxCS(ep_idx)) & BIT(EPCS_BUSY)) {
- if (++count > 100) {
- break;
- }
- k_busy_wait(1);
- }
- }
- /* Check Busy */
- if (usb_read8(INxCS(ep_idx)) & BIT(EPCS_BUSY)) {
- LOG_DBG("EP 0x%x still busy", ep);
- return -EAGAIN;
- }
- if (USB_EP_IN_DMA_CAP(ep_idx)) {
- usb_write8(INIRQ, BIT(ep_idx));
- usb_set_bit8(INIEN, ep_idx);
- }
- /* 32-bit alignment */
- if (((long)buf & 0x3) == 0) {
- len = data_len >> 2;
- left = data_len & 0x3;
- for (i = 0; i < len; i++, buf += 4) {
- usb_write32(FIFOxDAT(ep_idx), *(uint32_t *)buf);
- }
- /* 16-bit alignment */
- } else if (((long)buf & 0x1) == 0) {
- len = data_len >> 1;
- left = data_len & 0x1;
- for (i = 0; i < len; i++, buf += 2) {
- usb_write16(FIFOxDAT(ep_idx), *(uint16_t *)buf);
- }
- } else {
- len = data_len;
- left = 0;
- for (i = 0; i < len; i++, buf++) {
- usb_write8(FIFOxDAT(ep_idx), *buf);
- }
- }
- /* Handle left byte(s) */
- for (i = 0; i < left; i++, buf++) {
- usb_write8(FIFOxDAT(ep_idx), *buf);
- }
- /* Set Byte Counter */
- usb_write16(INxBC(ep_idx), data_len);
- /* Set busy */
- usb_set_bit8(INxCS(ep_idx), EPCS_BUSY);
- return data_len;
- }
- /*
- * Read data from EP FIFO
- *
- * @return Actual length
- */
- static inline int ep_read_fifo(uint8_t ep, uint8_t *data, uint32_t data_len)
- {
- uint32_t i;
- uint32_t len;
- uint8_t left;
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- uint32_t addr = FIFOxDAT(ep_idx);
- uint8_t *buf = (uint8_t *)data;
- /* Check Busy */
- if (usb_read8(OUTxCS(ep_idx)) & BIT(EPCS_BUSY)) {
- LOG_DBG("EP 0x%x still busy", ep);
- return -EBUSY;
- }
- /* 32-bit alignment */
- if (((long)buf & 0x3) == 0) {
- len = data_len >> 2;
- left = data_len & 0x3;
- for (i = 0; i < len; i++, buf += 4) {
- *(uint32_t *)buf = usb_read32(addr);
- }
- /* 16-bit alignment */
- } else if (((long)buf & 0x1) == 0) {
- len = data_len >> 1;
- left = data_len & 0x1;
- for (i = 0; i < len; i++, buf += 2) {
- *(uint16_t *)buf = usb_read16(addr);
- }
- } else {
- len = data_len;
- left = 0;
- for (i = 0; i < len; i++, buf++) {
- *buf = usb_read8(addr);
- }
- }
- /* Handle left byte(s) */
- for (i = 0; i < left; i++, buf++) {
- *buf = usb_read8(addr);
- }
- return data_len;
- }
- /*
- * Data stage: write data to EP0 FIFO
- *
- * @return Actual length
- */
- static inline int ep0_write_fifo(const uint8_t *const data, uint32_t data_len)
- {
- uint32_t i;
- uint8_t j;
- uint32_t addr = EP0IN_FIFO;
- /* Check Busy */
- if (usb_read8(EP0CS) & BIT(EP0CS_INBUSY)) {
- LOG_DBG("still busy");
- return -EAGAIN;
- }
- /* 32-bit alignment */
- if (((long)data & 0x3) == 0) {
- for (i = 0; i < (data_len & ~0x3); i += 4) {
- usb_write32(addr + i, *(uint32_t *)(data + i));
- }
- for (j = 0; j < (data_len & 0x3); j++) {
- usb_write8(addr + i + j, *(data + i + j));
- }
- /* 16-bit alignment */
- } else if (((long)data & 0x1) == 0) {
- for (i = 0; i < (data_len & ~0x1); i += 2) {
- usb_write16(addr + i, *(uint16_t *)(data + i));
- }
- /* The last byte */
- if (data_len & 0x1) {
- usb_write8(addr + i, *(data + i));
- }
- } else {
- for (i = 0; i < data_len; i++) {
- usb_write8(addr + i, *(data + i));
- }
- }
- /* Set Byte Counter: set busy */
- usb_write8(IN0BC, data_len);
- return data_len;
- }
- /*
- * Data stage: read data from EP0 FIFO
- *
- * @return Actual length
- */
- static inline int ep0_read_fifo(uint8_t *data, uint32_t data_len)
- {
- uint32_t i;
- uint8_t j;
- uint8_t len;
- uint32_t addr = EP0OUT_FIFO;
- /* Check Busy */
- if (usb_read8(EP0CS) & BIT(EP0CS_OUTBUSY)) {
- LOG_DBG("still busy");
- return -EBUSY;
- }
- /* Get Actual length */
- len = usb_read8(OUT0BC);
- if (data_len < len) {
- len = data_len;
- }
- /* 32-bit alignment */
- if (((long)data & 0x3) == 0) {
- for (i = 0; i < (len & ~0x3); i += 4) {
- *(uint32_t *)(data + i) = usb_read32(addr + i);
- }
- for (j = 0; j < (len & 0x3); j++) {
- *(data + i + j) = usb_read8(addr + i + j);
- }
- /* 16-bit alignment */
- } else if (((long)data & 0x1) == 0) {
- for (i = 0; i < (len & ~0x1); i += 2) {
- *(uint16_t *)(data + i) = usb_read16(addr + i);
- }
- /* The last byte */
- if (len & 0x1) {
- *(data + i) = usb_read8(addr + i);
- }
- } else {
- for (i = 0; i < len; i++) {
- *(data + i) = usb_read8(addr + i);
- }
- }
- return len;
- }
- /*
- * Device related
- */
- #ifdef CONFIG_USB_AOTG_DC_ENABLED
- /*
- * Check if the MaxPacketSize of endpoint is valid
- */
- static inline bool aotg_dc_ep_mps_valid(uint16_t ep_mps,
- enum usb_dc_ep_type ep_type)
- {
- enum usb_device_speed speed = usb_aotg_dc.speed;
- switch (ep_type) {
- case USB_DC_EP_CONTROL:
- return ep_mps <= USB_MAX_CTRL_MPS;
- case USB_DC_EP_BULK:
- if (speed == USB_SPEED_HIGH) {
- return ep_mps == USB_MAX_HS_BULK_MPS;
- } else {
- return ep_mps <= USB_MAX_FS_BULK_MPS;
- }
- case USB_DC_EP_INTERRUPT:
- if (speed == USB_SPEED_HIGH) {
- return ep_mps <= USB_MAX_HS_INTR_MPS;
- } else {
- return ep_mps <= USB_MAX_FS_INTR_MPS;
- }
- case USB_DC_EP_ISOCHRONOUS:
- if (speed == USB_SPEED_HIGH) {
- return ep_mps <= USB_MAX_HS_ISOC_MPS;
- } else {
- return ep_mps <= USB_MAX_FS_ISOC_MPS;
- }
- }
- return false;
- }
- /*
- * Check if the endpoint is enabled
- */
- static inline bool aotg_dc_ep_is_enabled(uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep) && usb_aotg_dc.out_ep_ctrl[ep_idx].ep_ena) {
- return true;
- }
- if (USB_EP_DIR_IS_IN(ep) && usb_aotg_dc.in_ep_ctrl[ep_idx].ep_ena) {
- return true;
- }
- return false;
- }
- /*
- * Using single FIFO for every endpoint (except for ep0) by default
- */
- static inline int aotg_dc_ep_alloc_fifo(uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- if (!ep_idx) {
- return 0;
- }
- if (USB_EP_DIR_IS_OUT(ep)) {
- if (ep_idx >= USB_AOTG_OUT_EP_NUM) {
- return -EINVAL;
- }
- return aotg_dc_epout_alloc_fifo_specific(ep_idx);
- }
- if (ep_idx >= USB_AOTG_IN_EP_NUM) {
- return -EINVAL;
- }
- return aotg_dc_epin_alloc_fifo_specific(ep_idx);
- }
- /*
- * Max Packet Size Limit
- */
- static inline int aotg_dc_set_max_packet(uint8_t ep, uint16_t ep_mps,
- enum usb_dc_ep_type ep_type)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- /*
- * NOTE: If the MaxPacketSize is beyond the limit, we won't try to
- * assign a valid value, because it will fail anyway when the upper
- * layer try to check capacity of the endpoint!
- */
- if (!aotg_dc_ep_mps_valid(ep_mps, ep_type)) {
- return -EINVAL;
- }
- if (USB_EP_DIR_IS_OUT(ep)) {
- usb_write16(OUTxMAXPKT(ep_idx), ep_mps);
- usb_aotg_dc.out_ep_ctrl[ep_idx].mps = ep_mps;
- } else {
- usb_write16(INxMAXPKT(ep_idx), ep_mps);
- usb_aotg_dc.in_ep_ctrl[ep_idx].mps = ep_mps;
- }
- return 0;
- }
- /*
- * Endpoint type
- */
- static inline void aotg_dc_set_ep_type(uint8_t ep, enum usb_dc_ep_type ep_type)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- usb_aotg_dc.out_ep_ctrl[ep_idx].ep_type = ep_type;
- } else {
- usb_aotg_dc.in_ep_ctrl[ep_idx].ep_type = ep_type;
- }
- }
- /*
- * Initialize AOTG hardware endpoint.
- *
- * Set FIFO address, endpoint type, FIFO type, max packet size
- */
- static inline int aotg_dc_ep_set(uint8_t ep, uint16_t ep_mps,
- enum usb_dc_ep_type ep_type)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- int ret;
- LOG_DBG("Ep setup 0x%x, mps %d, type %d", ep, ep_mps, ep_type);
- /* Set FIFO address */
- ret = aotg_dc_ep_alloc_fifo(ep);
- if (ret) {
- return ret;
- }
- /* Set Max Packet */
- ret = aotg_dc_set_max_packet(ep, ep_mps, ep_type);
- if (ret) {
- return ret;
- }
- /* Set EP type */
- aotg_dc_set_ep_type(ep, ep_type);
- /* No need to set for endpoint 0 */
- if (!ep_idx) {
- return 0;
- }
- if (USB_EP_DIR_IS_OUT(ep)) {
- ep_ctrl = &usb_aotg_dc.out_ep_ctrl[ep_idx];
- if (ep_ctrl->multi) {
- /* Set endpoint type and FIFO type */
- usb_write8(OUTxCTRL(ep_idx),
- (ep_type << 2) | USB_AOTG_FIFO_DOUBLE);
- /* Set FIFOCTRL */
- usb_write8(FIFOCTRL, ep_idx | BIT(FIFOCTRL_AUTO));
- } else {
- usb_write8(OUTxCTRL(ep_idx),
- (ep_type << 2) | USB_AOTG_FIFO_SINGLE);
- /* Set FIFOCTRL */
- if (USB_EP_OUT_DMA_CAP(ep_idx)) {
- usb_write8(FIFOCTRL, ep_idx | BIT(FIFOCTRL_AUTO));
- } else {
- usb_write8(FIFOCTRL, ep_idx);
- }
- }
- } else {
- ep_ctrl = &usb_aotg_dc.in_ep_ctrl[ep_idx];
- if (ep_ctrl->multi) {
- usb_write8(INxCTRL(ep_idx),
- (ep_type << 2) | USB_AOTG_FIFO_DOUBLE);
- } else {
- usb_write8(INxCTRL(ep_idx),
- (ep_type << 2) | USB_AOTG_FIFO_SINGLE);
- if (USB_EP_IN_DMA_CAP(ep_idx)) {
- usb_write8(FIFOCTRL, ep_idx | BIT(FIFOCTRL_IO_IN) | BIT(FIFOCTRL_AUTO));
- } else {
- usb_write8(FIFOCTRL, ep_idx | BIT(FIFOCTRL_IO_IN));
- }
- }
- }
- return 0;
- }
- /*
- * Prepare for the next OUT transaction
- *
- * There are two ways: write OUTxBC or set busy for EPxCS.
- * I don't know which one is better really, just keep it both.
- */
- static inline void aotg_dc_prep_rx(uint8_t ep_idx)
- {
- /* Set busy */
- if (!ep_idx) {
- #if 0
- usb_set_bit8(EP0CS, EP0CS_OUTBUSY);
- #endif
- usb_write8(OUT0BC, 0x0);
- } else {
- #if 0
- usb_write8(OUTxCS(ep_idx), 0);
- #endif
- if (!(usb_read8(OUTxCS(ep_idx)) & BIT(EPCS_BUSY))) {
- usb_set_bit8(OUTxCS(ep_idx), EPCS_BUSY);
- }
- }
- }
- /*
- * Setup stage: read data from Setup FIFO
- */
- static inline int ep0_read_setup(uint8_t *data, uint32_t data_len)
- {
- uint8_t len = data_len;
- if (data_len > sizeof(struct usb_setup_packet)) {
- len = sizeof(struct usb_setup_packet);
- }
- memcpy(data, usb_aotg_dc.raw_setup, len);
- return len;
- }
- /*
- * Status stage
- */
- static inline void handle_status(void)
- {
- usb_set_bit8(EP0CS, EP0CS_NAK);
- }
- /*
- * Receive data from host: could be Setup, Data or Status
- *
- * @return transfer length
- */
- static inline int aotg_dc_rx(uint8_t ep, uint8_t *data, uint32_t data_len)
- {
- int act_len = 0;
- /* Endpoint 0 */
- if (!USB_EP_ADDR2IDX(ep)) {
- if (usb_aotg_dc.phase == USB_AOTG_SETUP) {
- act_len = ep0_read_setup(data, data_len);
- } else if (usb_aotg_dc.phase == USB_AOTG_OUT_DATA) {
- act_len = ep0_read_fifo(data, data_len);
- #if 0
- } else if (usb_aotg_dc.phase == USB_AOTG_OUT_STATUS) {
- /*
- * Case 1: Setup, In Data, Out Status
- */
- handle_status();
- #endif
- }
- } else {
- act_len = ep_read_fifo(ep, data, data_len);
- }
- return act_len;
- }
- /*
- * Send data to host
- *
- * @return transfer length
- */
- static inline int aotg_dc_tx(uint8_t ep, const uint8_t *const data,
- uint32_t data_len)
- {
- uint32_t act_len = 0;
- /* Endpoint 0 */
- if (!USB_EP_ADDR2IDX(ep)) {
- if ((usb_aotg_dc.phase == USB_AOTG_IN_DATA) && !data_len) {
- /*
- * Handling zero-length packet for In-data phase
- */
- act_len = ep0_write_fifo(data, data_len);
- } else if (!data_len) {
- /*
- * Handling in-status stage
- * Case 2: Setup, In Status
- * Case 3: Setup, Out Data, In Status
- */
- if (usb_aotg_dc.phase != USB_AOTG_SET_ADDRESS) {
- handle_status();
- }
- usb_aotg_dc.phase = USB_AOTG_IN_STATUS;
- } else {
- act_len = ep0_write_fifo(data, data_len);
- usb_aotg_dc.phase = USB_AOTG_IN_DATA;
- }
- } else {
- act_len = ep_write_fifo(ep, data, data_len);
- }
- return act_len;
- }
- static inline void aotg_dc_handle_otg(void)
- {
- uint8_t tmp;
- uint8_t state;
- /* Clear OTG IRQ(s) */
- tmp = usb_read8(OTGIEN) & usb_read8(OTGIRQ);
- usb_write8(OTGIRQ, tmp);
- state = usb_read8(OTGSTATE);
- /* If AOTG enters b_peripheral state, enable Core interrupts */
- if (state == OTG_B_PERIPHERAL) {
- #ifdef CONFIG_USB_AOTG_OTG_SUPPORT_HS
- usb_set_bit8(USBIEN, USBIEN_HS);
- #endif
- usb_set_bit8(USBIEN, USBIEN_RESET);
- usb_set_bit8(USBIEN, USBIEN_SETUP);
- }
- LOG_DBG("State: 0x%x, irq: 0x%x", state, tmp);
- }
- static inline void aotg_dc_handle_reset(void)
- {
- /* Clear USB Reset IRQ */
- usb_write8(USBIRQ, BIT(USBIRQ_RESET));
- usb_aotg_dc.speed = USB_SPEED_UNKNOWN;
- /* Clear USB SOF IRQ */
- usb_write8(USBIRQ, BIT(USBIRQ_SOF));
- /* Enable USB SOF IRQ */
- usb_set_bit8(USBIEN, USBIEN_SOF);
- LOG_DBG("");
- #ifdef CONFIG_USB_AOTG_UDC_DMA
- dma_stop(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_single);
- dma_stop(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_burst8);
- dma_stop(usb_aotg_dma.dma_dev, usb_aotg_dma.epin_dma);
- #endif
- /* Inform upper layers */
- if (usb_aotg_dc.status_cb) {
- usb_aotg_dc.status_cb(USB_DC_RESET, NULL);
- }
- }
- #ifdef CONFIG_USB_AOTG_OTG_SUPPORT_HS
- static inline void aotg_dc_handle_hs(void)
- {
- /* Clear USB high-speed IRQ */
- usb_write8(USBIRQ, BIT(USBIRQ_HS));
- usb_aotg_dc.speed = USB_SPEED_HIGH;
- LOG_DBG("");
- /* Inform upper layers */
- if (usb_aotg_dc.status_cb) {
- usb_aotg_dc.status_cb(USB_DC_HIGHSPEED, NULL);
- }
- }
- #endif
- static inline void aotg_dc_handle_sof(void)
- {
- /* Clear USB SOF IRQ */
- usb_write8(USBIRQ, BIT(USBIRQ_SOF));
- /* Disable USB SOF IRQ */
- usb_clear_bit8(USBIEN, USBIEN_SOF);
- if (usb_aotg_dc.speed == USB_SPEED_UNKNOWN) {
- usb_aotg_dc.speed = USB_SPEED_FULL;
- }
- LOG_DBG("");
- /* Inform upper layers */
- if (usb_aotg_dc.status_cb) {
- usb_aotg_dc.status_cb(USB_DC_SOF, NULL);
- }
- }
- static inline void aotg_dc_handle_resume(uint8_t usbeien)
- {
- /* clear resume */
- usb_write8(USBEIRQ, BIT(USBEIRQ_RESUME) | usbeien);
- /* disable resume */
- usb_write8(USBEIEN, (~BIT(USBEIEN_RESUME)) & usbeien);
- if (usb_aotg_dc.status_cb) {
- usb_aotg_dc.status_cb(USB_DC_RESUME, NULL);
- }
- }
- static inline void aotg_dc_handle_suspend(uint8_t usbeien)
- {
- usb_write8(USBIRQ, BIT(USBIRQ_SUSPEND));
- /* clear resume */
- usb_write8(USBEIRQ, BIT(USBEIRQ_RESUME) | usbeien);
- /* enable resume */
- usb_write8(USBEIEN, BIT(USBEIEN_RESUME) | usbeien);
- if (usb_aotg_dc.status_cb) {
- usb_aotg_dc.status_cb(USB_DC_SUSPEND, NULL);
- }
- }
- /*
- * Handle SETUP packet
- */
- static inline void aotg_dc_handle_setup(void)
- {
- usb_dc_ep_callback ep_cb;
- uint32_t addr = SETUP_FIFO;
- uint8_t i;
- /* Clear SETUP IRQ */
- usb_write8(USBIRQ, BIT(USBIRQ_SETUP));
- /* Fetch setup packet */
- for (i = 0; i < sizeof(struct usb_setup_packet); i++, addr++) {
- *(usb_aotg_dc.raw_setup + i) = usb_read8(addr);
- }
- /* Set setup data length */
- usb_aotg_dc.out_ep_ctrl[USB_AOTG_OUT_EP_0].data_len =
- sizeof(struct usb_setup_packet);
- /* Set in data length */
- if (USB_REQ_DIR_IN(usb_aotg_dc.setup.bmRequestType)) {
- usb_aotg_dc.in_ep_ctrl[USB_AOTG_IN_EP_0].data_len =
- usb_aotg_dc.setup.wLength;
- }
- usb_aotg_dc.phase = USB_AOTG_SETUP;
- ep_cb = usb_aotg_dc.out_ep_ctrl[USB_AOTG_OUT_EP_0].cb;
- /* Call the registered callback if any */
- if (ep_cb) {
- ep_cb(USB_AOTG_OUT_EP_0, USB_DC_EP_SETUP);
- }
- }
- /*
- * Handle EPxOUT data
- */
- static inline void aotg_dc_handle_epout(uint8_t ep_idx)
- {
- uint8_t ep = USB_EP_IDX2ADDR(ep_idx, USB_EP_DIR_OUT);
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint16_t len;
- /* Clear EPxOUT IRQ */
- usb_write8(OUTIRQ, BIT(ep_idx));
- ep_ctrl = &usb_aotg_dc.out_ep_ctrl[ep_idx];
- /* Get Actual Length */
- if (!ep_idx) {
- /* Check phase before checking byte counter */
- if (usb_aotg_dc.phase == USB_AOTG_OUT_STATUS) {
- return;
- }
- /*
- * EP0OUT data irq may come before EPxOUT token irq in
- * out-status phase, filter it otherwise it will be disturbed.
- * It may come even in in-data phase, can't explain!
- *
- * Keep it (only for record), we will check setup packet!
- */
- if (usb_aotg_dc.phase == USB_AOTG_IN_DATA) {
- return;
- }
- /* Filter by direction and length of setup packet */
- if (USB_REQ_DIR_IN(usb_aotg_dc.setup.bmRequestType)) {
- return;
- } else if (usb_aotg_dc.setup.wLength == 0) {
- return;
- }
- /* NOTICE: OUT0BC will be set in setup phase and data phase */
- len = usb_read8(OUT0BC);
- if (len == 0) {
- return;
- }
- usb_aotg_dc.phase = USB_AOTG_OUT_DATA;
- } else {
- len = usb_read16(OUTxBC(ep_idx));
- if (len == 0) {
- LOG_DBG("ep 0x%x recv zero-length packet", ep);
- }
- if (ep_ctrl->data) {
- /* Disable interrupt if received all data to support auto-mode */
- if ((ep_ctrl->data_len == len) ||
- (len < ep_ctrl->mps)) {
- usb_clear_bit8(OUTIEN, ep_idx);
- LOG_DBG("Disable irq");
- }
- /* FIXME: leave it to upper layer, should we clear fifo? */
- if (len > ep_ctrl->data_len) {
- LOG_DBG("babble: %d, %d", len, ep_ctrl->data_len);
- len = ep_ctrl->data_len;
- }
- ep_read_fifo(ep, ep_ctrl->data, len);
- ep_ctrl->actual += len;
- ep_ctrl->data_len -= len;
- ep_ctrl->data += len;
- if (ep_ctrl->data_len == 0) {
- LOG_DBG("0x%x done 0x%x", ep, usb_read8(OUTxCS(ep_idx)));
- ep_ctrl->data = NULL;
- goto done;
- } else if (len < ep_ctrl->mps) {
- LOG_DBG("0x%x short %d", ep, len);
- ep_ctrl->data = NULL;
- goto done;
- } else {
- /* read continue */
- if (!(usb_read8(OUTxCS(ep_idx)) & BIT(EPCS_BUSY))) {
- usb_set_bit8(OUTxCS(ep_idx), EPCS_BUSY);
- }
- return;
- }
- }
- }
- ep_ctrl->data_len = len;
- done:
- /* Call the registered callback if any */
- if (ep_ctrl->cb) {
- ep_ctrl->cb(ep, USB_DC_EP_DATA_OUT);
- }
- }
- /*
- * Handle EPxIN data
- */
- static inline void aotg_dc_handle_epin(uint8_t ep_idx)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint32_t len;
- uint8_t ep;
- /* Clear EPxIN IRQ */
- usb_write8(INIRQ, BIT(ep_idx));
- ep_ctrl = &usb_aotg_dc.in_ep_ctrl[ep_idx];
- ep = USB_EP_IDX2ADDR(ep_idx, USB_EP_DIR_IN);
- if (ep_idx == 0) {
- goto done;
- }
- /* NOTICE: should never happen! */
- if (ep_ctrl->data == NULL) {
- LOG_DBG("0x%x", ep_idx);
- goto done;
- }
- if (ep_ctrl->data_len == 0) {
- LOG_DBG("0x%x done", ep);
- ep_ctrl->data = NULL;
- goto done;
- }
- if (ep_ctrl->data_len > ep_ctrl->mps) {
- len = ep_ctrl->mps;
- } else {
- len = ep_ctrl->data_len;
- }
- ep_write_fifo(ep, ep_ctrl->data, len);
- ep_ctrl->data_len -= len;
- ep_ctrl->data += len;
- return;
- done:
- /* Call the registered callback if any */
- if (ep_ctrl->cb) {
- ep_ctrl->cb(ep, USB_DC_EP_DATA_IN);
- }
- }
- /*
- * Handle EPxIN empty
- */
- static inline void aotg_dc_handle_epin_empty(void)
- {
- uint8_t ien = (usb_read8(INEMPTY_IEN) & INEMPTY_IEN_MASK) >> INEMPTY_IEN_SHIFT;
- uint8_t irq = (usb_read8(INEMPTY_IRQ) & INEMPTY_IRQ_MASK) >> INEMPTY_IRQ_SHIFT;
- uint8_t ep_msk = ien & irq;
- usb_dc_ep_callback ep_cb;
- uint8_t ep_idx, ep;
- uint8_t i;
- /* clear all pendings */
- usb_write8(INEMPTY_IRQ, INEMPTY_IRQ_MASK);
- /* disable all interrupts */
- usb_write8(INEMPTY_IEN, 0);
- for (i = 0; i < USB_AOTG_IN_EP_NUM; i++) {
- if (ep_msk & BIT(i)) {
- ep_idx = INEMPTY_IRQ2ADDR(i) & USB_EP_NUM_MASK;
- ep = USB_EP_IDX2ADDR(ep_idx, USB_EP_DIR_IN);
- LOG_DBG("ep: 0x%x", ep);
- ep_cb = usb_aotg_dc.in_ep_ctrl[ep_idx].cb;
- /* Call the registered callback if any */
- if (ep_cb) {
- ep_cb(ep, USB_DC_EP_DATA_IN);
- }
- }
- }
- }
- static inline void aotg_dc_handle_out_token_internal(uint8_t ep_idx)
- {
- if (ep_idx == USB_AOTG_OUT_EP_0) {
- /*
- * We may get one or more OUT token(s) even though
- * we have set ACK bit already, filter the case!
- */
- if (usb_aotg_dc.phase == USB_AOTG_OUT_STATUS) {
- return;
- }
- /*
- * Case 1: Setup, In Data, Out Status
- *
- * Status stage: no need to check busy
- */
- if (usb_aotg_dc.phase == USB_AOTG_IN_DATA) {
- handle_status();
- usb_aotg_dc.phase = USB_AOTG_OUT_STATUS;
- return;
- }
- }
- /* Do nothing */
- return;
- /*
- * NOTE: out token only take cares of out status phase, don't
- * use it for out data phase, because ep0 may be busy all the
- * time and can never complete!
- */
- #if 0
- usb_dc_ep_callback ep_cb;
- while (usb_read8(EP0CS) & BIT(EP0CS_OUTBUSY)) {
- ;
- }
- usb_aotg_dc.out_ep_ctrl[ep_idx].data_len = usb_read8(OUT0BC);
- usb_aotg_dc.phase = USB_AOTG_OUT_DATA;
- ep_cb = usb_aotg_dc.out_ep_ctrl[ep_idx].cb;
- ep_idx = USB_EP_IDX2ADDR(ep_idx, USB_EP_DIR_OUT);
- /* Call the registered callback if any */
- if (ep_cb) {
- ep_cb(ep_idx, USB_DC_EP_DATA_OUT);
- }
- #endif
- }
- /*
- * Handle EPxOUT Token
- */
- static inline void aotg_dc_handle_out_token(void)
- {
- uint8_t ep_msk, i;
- /* Get endpoint mask */
- ep_msk = (usb_read8(OUT_TOKIRQ) & usb_read8(OUT_TOKIEN));
- /* NOTE: There may be more than one out token irqs simutaneously */
- for (i = 0; i < EPOUT_TOKEN_NUM; i++) {
- if (ep_msk & BIT(i)) {
- /* Clear IRQ */
- usb_write8(OUT_TOKIRQ, BIT(i));
- aotg_dc_handle_out_token_internal(i);
- }
- }
- }
- /*
- * Handle EPxIN Token
- */
- static inline void aotg_dc_handle_in_token(void)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep_msk, i;
- /* Get endpoint mask */
- ep_msk = usb_read8(IN_TOKIRQ) & usb_read8(IN_TOKIEN);
- /* NOTE: There may be more than one in token irqs simutaneously */
- for (i = 0; i < EPIN_TOKEN_NUM; i++) {
- if (ep_msk & BIT(i)) {
- /* Clear IRQ */
- usb_write8(IN_TOKIRQ, BIT(i));
- ep_ctrl = &usb_aotg_dc.in_ep_ctrl[i];
- /* Call the registered callback if any */
- if (ep_ctrl->cb) {
- ep_ctrl->cb(i, USB_DC_EP_DATA_IN);
- }
- }
- }
- }
- /*
- * Handle EPxOUT Short Packet
- */
- static inline void aotg_dc_handle_short_packet(void)
- {
- usb_write8(OUT_SHTPKT, usb_read8(OUT_SHTPKT));
- LOG_DBG("aotg short packet");
- }
- static inline void aotg_dc_isr_dispatch(uint8_t vector)
- {
- uint8_t usbeien = usb_read8(USBEIEN) & USBEIEN_MASK;
- /* USB Resume */
- if (vector == UIV_RESUME) {
- aotg_dc_handle_resume(usbeien);
- return;
- }
- /*
- * Make sure external IRQ has been cleared right!
- *
- * TODO: If two or more IRQs are pending simultaneously,
- * EIRQ will be pending immediately after cleared or not?
- */
- while (usb_read8(USBEIRQ) & BIT(USBEIRQ_EXTERN)) {
- usb_write8(USBEIRQ, BIT(USBEIRQ_EXTERN) | usbeien);
- }
- switch (vector) {
- /* OTG */
- case UIV_OTGIRQ:
- aotg_dc_handle_otg();
- break;
- /* USB Reset */
- case UIV_USBRST:
- aotg_dc_handle_reset();
- break;
- #ifdef CONFIG_USB_AOTG_OTG_SUPPORT_HS
- /* High-speed */
- case UIV_HSPEED:
- aotg_dc_handle_hs();
- break;
- #endif
- /* SOF */
- case UIV_SOF:
- aotg_dc_handle_sof();
- break;
- /* USB Suspend */
- case UIV_SUSPEND:
- aotg_dc_handle_suspend(usbeien);
- break;
- /* SETUP */
- case UIV_SUDAV:
- aotg_dc_handle_setup();
- break;
- /* EPxOUT */
- case UIV_EP0OUT:
- case UIV_EP1OUT:
- case UIV_EP2OUT:
- case UIV_EP3OUT:
- #if (CONFIG_USB_AOTG_OTG_VERSION == USB_AOTG_VERSION_LEOPARD)
- case UIV_EP4OUT:
- case UIV_EP5OUT:
- case UIV_EP6OUT:
- #endif
- aotg_dc_handle_epout(UIV_EPOUT_VEC2ADDR(vector));
- break;
- /* EPxIN */
- case UIV_EP0IN:
- case UIV_EP1IN:
- case UIV_EP2IN:
- case UIV_EP3IN:
- #if (CONFIG_USB_AOTG_OTG_VERSION == USB_AOTG_VERSION_LEOPARD)
- case UIV_EP4IN:
- case UIV_EP5IN:
- case UIV_EP6IN:
- #endif
- aotg_dc_handle_epin(UIV_EPIN_VEC2ADDR(vector));
- break;
- /* EPxIN empty */
- case UIV_HCOUTEMPTY:
- aotg_dc_handle_epin_empty();
- break;
- /*
- * Using OUT Token for EP0OUT data transfer for assistance.
- *
- * AOTG handles in/out status by software (handle_status()),
- * which means it depends on USB core totally. But USB core
- * thinks that controller should take care of out status by
- * itself (excluding int status phase). That means EP0 Data
- * IRQ will never be pending until handle_status() called!
- */
- case UIV_OUTTOKEN:
- aotg_dc_handle_out_token();
- break;
- case UIV_INTOKEN:
- aotg_dc_handle_in_token();
- break;
- /* Short Packet */
- case UIV_EPOUTSHTPKT:
- aotg_dc_handle_short_packet();
- break;
- default:
- break;
- }
- }
- /* Disable soft disconnect */
- static inline void aotg_dc_connect(void)
- {
- usb_clear_bit8(USBCS, USBCS_DISCONN);
- }
- /* Enable soft disconnect */
- static inline void aotg_dc_disconnect(void)
- {
- usb_set_bit8(USBCS, USBCS_DISCONN);
- }
- static void usb_dc_hardware_init(void)
- {
- usb_write32(AVDDLDO_CTL, 0x05);
- k_msleep(1);
- usb_write32(SPLL_CTL, sys_read32(SPLL_CTL)|0x01);
- k_msleep(1);
- LOG_DBG("SPLL_CTL: 0x%x", sys_read32(SPLL_CTL));
- acts_clock_peripheral_enable(CLOCK_ID_USB);
- acts_clock_peripheral_enable(CLOCK_ID_USB2);
- LOG_DBG("CMU_DEVCLKEN0: 0x%x", sys_read32(CMU_DEVCLKEN0));
- }
- int usb_dc_attach(void)
- {
- if (usb_aotg_dc.attached) {
- LOG_DBG("already");
- return 0;
- }
- usb_dc_hardware_init();
- aotg_dc_fifo_enable();
- usb_aotg_enable();
- usb_write8(IDVBUSCTRL, IDVBUS_DEVICE);
- usb_write8(DPDMCTRL, DPDM_HOST);
- aotg_dc_phy_init();
- #ifdef CONFIG_USB_AOTG_DC_FS
- aotg_dc_force_fs();
- #endif
- /* Enable OTG(b_peripheral) interrupt */
- usb_set_bit8(OTGIEN, OTGIEN_PERIPHERAL);
- /* Enable external interrupt */
- usb_set_bit8(USBEIEN, USBEIEN_EXTERN);
- irq_enable(USB_AOTG_IRQ);
- aotg_dc_connect();
- usb_aotg_reg_dump();
- /* status_cb is registered */
- usb_aotg_dc.speed = USB_SPEED_UNKNOWN;
- usb_aotg_dc.attached = 1;
- LOG_DBG("");
- return 0;
- }
- int usb_dc_detach(void)
- {
- unsigned int key = irq_lock();
- uint8_t speed;
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- LOG_DBG("already");
- return 0;
- }
- irq_disable(USB_AOTG_IRQ);
- aotg_dc_disconnect();
- #ifdef CONFIG_USB_AOTG_UDC_DMA
- dma_stop(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_single);
- dma_stop(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_burst8);
- dma_stop(usb_aotg_dma.dma_dev, usb_aotg_dma.epin_dma);
- #endif
- /* recover speed */
- speed = usb_aotg_dc.speed;
- memset(&usb_aotg_dc, 0, sizeof(usb_aotg_dc));
- usb_aotg_dc.speed = speed;
- usb_aotg_reset();
- usb_aotg_disable();
- aotg_dc_fifo_disable();
- irq_unlock(key);
- LOG_DBG("");
- return 0;
- }
- int usb_dc_reset(void)
- {
- LOG_DBG("");
- /* Clear private data */
- memset(&usb_aotg_dc, 0, sizeof(usb_aotg_dc));
- return 0;
- }
- int usb_dc_set_address(const uint8_t addr)
- {
- if (addr > USB_AOTG_MAX_ADDR) {
- return -EINVAL;
- }
- /* Respond "Set Address" automatically in device mode */
- LOG_DBG("Set Address: %d", usb_read8(FNADDR));
- /* Set Address phase */
- usb_aotg_dc.phase = USB_AOTG_SET_ADDRESS;
- /* Enable suspend */
- usb_write8(USBIRQ, BIT(USBIRQ_SUSPEND));
- usb_set_bit8(USBIEN, USBIEN_SUSPEND);
- return 0;
- }
- int usb_dc_set_status_callback(const usb_dc_status_callback cb)
- {
- usb_aotg_dc.status_cb = cb;
- return 0;
- }
- int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)
- {
- LOG_DBG("ep %x, mps %d, type %d", cfg->ep_addr, cfg->ep_mps,
- cfg->ep_type);
- /*
- * Check if the address of control endpoint is non-zero!
- */
- if ((cfg->ep_type == USB_DC_EP_CONTROL)
- && USB_EP_ADDR2IDX(cfg->ep_addr)) {
- LOG_ERR("invalid endpoint configuration");
- return -EINVAL;
- }
- if (!aotg_dc_ep_mps_valid(cfg->ep_mps, cfg->ep_type)) {
- LOG_WRN("unsupported packet size");
- return -EINVAL;
- }
- if (!usb_aotg_ep_addr_valid(cfg->ep_addr)) {
- LOG_WRN("endpoint 0x%x address out of range", cfg->ep_addr);
- return -EINVAL;
- }
- return 0;
- }
- int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg)
- {
- if (!usb_aotg_dc.attached || !usb_aotg_ep_addr_valid(ep_cfg->ep_addr))
- return -EINVAL;
- return aotg_dc_ep_set(ep_cfg->ep_addr, ep_cfg->ep_mps,
- ep_cfg->ep_type);
- }
- int usb_dc_ep_set_stall(const uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- unsigned int key;
- if (!usb_aotg_ep_addr_valid(ep)) {
- return -EINVAL;
- }
- key = irq_lock();
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- return -ENODEV;
- }
- /* Endpoint 0 */
- if (!ep_idx) {
- usb_set_bit8(EP0CS, EP0CS_STALL);
- irq_unlock(key);
- return 0;
- }
- if (USB_EP_DIR_IS_OUT(ep)) {
- usb_set_bit8(OUTxCTRL(ep_idx), EPCTRL_STALL);
- /* clear pending in case data received before stalled */
- usb_write8(OUTIRQ, BIT(ep_idx));
- } else {
- usb_set_bit8(INxCTRL(ep_idx), EPCTRL_STALL);
- }
- /* Reset the data toggle */
- usb_aotg_ep_reset(ep, USB_AOTG_EP_TOGGLE_RESET);
- irq_unlock(key);
- return 0;
- }
- int usb_dc_ep_clear_stall(const uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- unsigned int key;
- if (!usb_aotg_ep_addr_valid(ep)) {
- return -EINVAL;
- }
- key = irq_lock();
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- return -ENODEV;
- }
- if (!ep_idx) {
- /*
- * case 1: EP0 stall will be cleared when SETUP token comes
- * case 2: we can clear EP0CS_STALL bit to clear stall
- */
- usb_clear_bit8(EP0CS, EP0CS_STALL);
- irq_unlock(key);
- return 0;
- }
- if (USB_EP_DIR_IS_OUT(ep)) {
- usb_clear_bit8(OUTxCTRL(ep_idx), EPCTRL_STALL);
- } else {
- usb_clear_bit8(INxCTRL(ep_idx), EPCTRL_STALL);
- }
- irq_unlock(key);
- return 0;
- }
- int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- unsigned int key;
- if (!usb_aotg_ep_addr_valid(ep)) {
- return -EINVAL;
- }
- if (!stalled) {
- return -EINVAL;
- }
- key = irq_lock();
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- return -ENODEV;
- }
- *stalled = 0;
- /* Endpoint 0 */
- if (!ep_idx && (usb_read8(EP0CS) & BIT(EP0CS_STALL))) {
- *stalled = 1;
- irq_unlock(key);
- return 0;
- }
- if (USB_EP_DIR_IS_OUT(ep)) {
- if (usb_read8(OUTxCTRL(ep_idx)) & BIT(EPCTRL_STALL)) {
- *stalled = 1;
- }
- } else {
- if (usb_read8(INxCTRL(ep_idx)) & BIT(EPCTRL_STALL)) {
- *stalled = 1;
- }
- }
- irq_unlock(key);
- return 0;
- }
- int usb_dc_ep_halt(const uint8_t ep)
- {
- /*
- * Just set stall, by the way no clear halt operation?
- */
- return usb_dc_ep_set_stall(ep);
- }
- int usb_dc_ep_enable(const uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- bool dir_out = USB_EP_DIR_IS_OUT(ep);
- if (!usb_aotg_dc.attached || !usb_aotg_ep_addr_valid(ep)) {
- return -EINVAL;
- }
- if (usb_aotg_ep_reset(ep, USB_AOTG_EP_RESET)) {
- return -EINVAL;
- }
- /* Enable EP interrupts */
- if (dir_out) {
- /* EP0 OUT uses OUT Token IRQ for assistance */
- if (!ep_idx) {
- usb_set_bit8(OUT_TOKIEN, EP0OUT_TOKEN);
- }
- if (!USB_EP_OUT_DMA_CAP(ep_idx)) {
- usb_set_bit8(OUTIEN, ep_idx);
- }
- usb_aotg_dc.out_ep_ctrl[ep_idx].ep_ena = 1;
- } else {
- #if 0
- /* Using In Token IRQ for isochronous transfer */
- if (ep_type_isoc(usb_aotg_dc.in_ep_ctrl[ep_idx].ep_type)) {
- usb_set_bit8(IN_TOKIEN, ep_idx);
- } else {
- usb_set_bit8(INIEN, ep_idx);
- }
- #else
- if (!USB_EP_IN_DMA_CAP(ep_idx)) {
- usb_set_bit8(INIEN, ep_idx);
- }
- #endif
- usb_aotg_dc.in_ep_ctrl[ep_idx].ep_ena = 1;
- }
- /* Endpoint 0 */
- if (!ep_idx) {
- return 0;
- }
- if (dir_out) {
- /* Activate Ep */
- usb_set_bit8(OUTxCTRL(ep_idx), EPCTRL_VALID);
- /* Short Packet */
- /* usb_set_bit8(OUT_SHTPKT, ep_idx); */
- } else {
- usb_set_bit8(INxCTRL(ep_idx), EPCTRL_VALID);
- }
- /* Prepare EP for rx */
- if (dir_out) {
- aotg_dc_prep_rx(ep_idx);
- }
- usb_aotg_ep_reg_dump(ep);
- return 0;
- }
- int usb_dc_ep_disable(const uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- bool dir_out = USB_EP_DIR_IS_OUT(ep);
- if (!usb_aotg_dc.attached || !usb_aotg_ep_addr_valid(ep)) {
- return -EINVAL;
- }
- /* Disable EP interrupts */
- if (dir_out) {
- if (!ep_idx) {
- usb_clear_bit8(OUT_TOKIEN, EP0OUT_TOKEN);
- }
- usb_clear_bit8(OUTIEN, ep_idx);
- usb_aotg_dc.out_ep_ctrl[ep_idx].ep_ena = 0;
- } else {
- usb_clear_bit8(INIEN, ep_idx);
- usb_aotg_dc.in_ep_ctrl[ep_idx].ep_ena = 0;
- }
- /* Endpoint 0 */
- if (!ep_idx) {
- return 0;
- }
- /* De-activate Ep */
- if (dir_out) {
- usb_clear_bit8(OUTxCTRL(ep_idx), EPCTRL_VALID);
- } else {
- usb_clear_bit8(INxCTRL(ep_idx), EPCTRL_VALID);
- }
- return 0;
- }
- int usb_dc_ep_flush(const uint8_t ep)
- {
- unsigned int key;
- int ret;
- if (!usb_aotg_ep_addr_valid(ep)) {
- return -EINVAL;
- }
- key = irq_lock();
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- return -ENODEV;
- }
- ret = usb_aotg_ep_reset(ep, USB_AOTG_EP_FIFO_RESET);
- irq_unlock(key);
- return ret;
- }
- /*
- * legacy mode: write mps at most and depends on upper layer to write again
- * if data_len >= mps for all out endpoints.
- * new mode: write once (controller will handle if data_len >= mps) for all
- * non-control endpoints, control endpoints still works in legacy
- * mode.
- */
- int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data,
- const uint32_t data_len, uint32_t * const ret_bytes)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- unsigned int key;
- int ret;
- uint32_t len;
- if (!usb_aotg_ep_addr_valid(ep)) {
- LOG_ERR("No valid endpoint");
- return -EINVAL;
- }
- /* Check if IN ep */
- if (!USB_EP_DIR_IS_IN(ep)) {
- LOG_ERR("Wrong endpoint direction");
- return -EINVAL;
- }
- /* Check if ep enabled */
- if (!aotg_dc_ep_is_enabled(ep)) {
- LOG_ERR("Not enabled endpoint");
- return -EINVAL;
- }
- key = irq_lock();
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- return -ENODEV;
- }
- ep_ctrl = &usb_aotg_dc.in_ep_ctrl[ep_idx];
- #ifdef CONFIG_USB_AOTG_UDC_DMA
- /* need 32-bit alignment */
- if (((long)data & 0x3) != 0) {
- goto cpu_write;
- }
- if (USB_EP_IN_DMA_CAP(ep_idx)) {
- if ((data_len < USB_AOTG_DMA_BURST8_LEN) ||
- (data_len % USB_AOTG_DMA_BURST8_LEN)) {
- goto cpu_write;
- }
- if (data_len >= USB_AOTG_DMA_MAX_SIZE) {
- len = USB_AOTG_DMA_MAX_LEN;
- } else {
- len = data_len;
- }
- ep_ctrl->data_len = len;
- /* Disable EP interrupt */
- usb_clear_bit8(INIEN, ep_idx);
- usb_write8(IN1_DMACTL, BIT(DMACTL_FIFORST));
- usb_write8(IN1_DMACTL, 0);
- usb_write8(IN1_DMALEN1L, (uint8_t)len);
- usb_write8(IN1_DMALEN1M, (uint8_t)(len >> 8));
- usb_write8(IN1_DMALEN1H, (uint8_t)(len >> 16) | (0x1 << 1));
- usb_write8(IN1_DMALEN2H, 0);
- usb_write8(IN1_DMACTL, BIT(DMACTL_START));
- dma_reload(usb_aotg_dma.dma_dev, usb_aotg_dma.epin_dma,
- (uint32_t)data, FIFO1DAT, len);
- dma_start(usb_aotg_dma.dma_dev, usb_aotg_dma.epin_dma);
- if (ret_bytes) {
- *ret_bytes = len;
- }
- irq_unlock(key);
- return 0;
- }
- cpu_write:
- #endif
- ep_ctrl->data = NULL;
- len = data_len > ep_ctrl->mps ? ep_ctrl->mps : data_len;
- if (ep_idx != 0) {
- goto new_mode;
- }
- ret = aotg_dc_tx(ep, data, len);
- if (ret < 0) {
- irq_unlock(key);
- return ret;
- }
- if (ret_bytes) {
- *ret_bytes = ret;
- }
- if (usb_aotg_dc.phase != USB_AOTG_IN_DATA) {
- irq_unlock(key);
- return 0;
- }
- usb_aotg_dc.in_ep_ctrl[ep_idx].data_len -= ret;
- if ((usb_aotg_dc.in_ep_ctrl[ep_idx].data_len == 0) ||
- (ret < MAX_PACKET_SIZE0)) {
- /* Case 1: Setup, In Data, Out Status */
- handle_status();
- usb_aotg_dc.phase = USB_AOTG_OUT_STATUS;
- }
- irq_unlock(key);
- return 0;
- new_mode:
- LOG_DBG("%d", data_len);
- ep_ctrl->data_len = data_len - len;
- ep_ctrl->data = (uint8_t *)data + len;
- ret = ep_write_fifo(ep, data, len);
- if (ret < 0) {
- irq_unlock(key);
- return ret;
- }
- if (ret_bytes) {
- *ret_bytes = data_len;
- }
- irq_unlock(key);
- return 0;
- }
- int usb_dc_ep_read(const uint8_t ep, uint8_t *const data,
- const uint32_t max_data_len, uint32_t * const read_bytes)
- {
- if (usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes) != 0) {
- return -EINVAL;
- }
- if (!data && !max_data_len) {
- /* When both buffer and max data to read are zero the above
- * call would fetch the data len and we simply return.
- */
- return 0;
- }
- if (usb_dc_ep_read_continue(ep) != 0) {
- return -EINVAL;
- }
- return 0;
- }
- int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- if (!usb_aotg_dc.attached || !usb_aotg_ep_addr_valid(ep)) {
- return -EINVAL;
- }
- if (USB_EP_DIR_IS_IN(ep)) {
- usb_aotg_dc.in_ep_ctrl[ep_idx].cb = cb;
- } else {
- usb_aotg_dc.out_ep_ctrl[ep_idx].cb = cb;
- }
- return 0;
- }
- /*
- * read() and read_async() co-exist, which means fisrt read_async() should be
- * called ASAP to make sure outirq is after read_async(). It is recommended
- * called in status_cb().
- */
- int usb_dc_ep_read_async(uint8_t ep, uint8_t *data, uint32_t max_data_len,
- uint32_t *read_bytes)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- unsigned int key;
- if (!usb_aotg_ep_addr_valid(ep)) {
- LOG_ERR("No valid endpoint");
- return -EINVAL;
- }
- /* Check if OUT ep */
- if (!USB_EP_DIR_IS_OUT(ep)) {
- LOG_ERR("Wrong endpoint direction");
- return -EINVAL;
- }
- /* Allow to read 0 bytes */
- if (!data && max_data_len) {
- LOG_ERR("Wrong arguments");
- return -EINVAL;
- }
- /* Check if ep enabled */
- if (!aotg_dc_ep_is_enabled(ep)) {
- LOG_ERR("Not enabled endpoint");
- return -EINVAL;
- }
- key = irq_lock();
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- return -ENODEV;
- }
- ep_ctrl = &usb_aotg_dc.out_ep_ctrl[ep_idx];
- #ifdef CONFIG_USB_AOTG_UDC_DMA
- /* need 32-bit alignment */
- if (((long)data & 0x3) != 0) {
- goto cpu_mode;
- }
- if (!USB_EP_OUT_DMA_CAP(ep_idx)) {
- LOG_DBG("for DMA only");
- goto cpu_mode;
- }
- if (max_data_len >= USB_AOTG_DMA_MAX_SIZE) {
- max_data_len = USB_AOTG_DMA_MAX_LEN;
- }
- ep_ctrl->data_len = max_data_len;
- ep_ctrl->actual = 0;
- usb_write8(OUT2_DMACTL, BIT(DMACTL_FIFORST));
- usb_write8(OUT2_DMACTL, 0);
- usb_write8(OUT2_DMALENL, (uint8_t)max_data_len);
- usb_write8(OUT2_DMALENM, (uint8_t)(max_data_len >> 8));
- usb_write8(OUT2_DMALENH, (uint8_t)(max_data_len >> 16));
- if ((max_data_len >= USB_AOTG_DMA_BURST8_LEN) &&
- !(max_data_len % USB_AOTG_DMA_BURST8_LEN)) {
- usb_write8(OUT2_DMACTL, BIT(DMACTL_START));
- dma_reload(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_burst8,
- FIFO2DAT, (uint32_t)data, max_data_len);
- dma_start(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_burst8);
- } else {
- usb_write8(OUT2_DMACTL, BIT(DMACTL_MODE) | BIT(DMACTL_START));
- dma_reload(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_single,
- FIFO2DAT, (uint32_t)data, max_data_len);
- dma_start(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_single);
- }
- if (read_bytes) {
- *read_bytes = max_data_len;
- }
- irq_unlock(key);
- return 0;
- cpu_mode:
- #endif
- /* FIXME: always return max_data_len */
- if (read_bytes) {
- *read_bytes = max_data_len;
- }
- LOG_DBG("%d", max_data_len);
- ep_ctrl = &usb_aotg_dc.out_ep_ctrl[ep_idx];
- ep_ctrl->data_len = max_data_len;
- ep_ctrl->data = data;
- ep_ctrl->actual = 0;
- /* Enable interrupt */
- usb_set_bit8(OUTIEN, ep_idx);
- aotg_dc_prep_rx(ep_idx);
- irq_unlock(key);
- return 0;
- }
- int usb_dc_ep_read_actual(uint8_t ep, uint32_t *read_bytes)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep_idx;
- if (!USB_EP_DIR_IS_OUT(ep)) {
- return -EINVAL;
- }
- ep_idx = USB_EP_ADDR2IDX(ep) & USB_EP_NUM_MASK;
- ep_ctrl = &usb_aotg_dc.out_ep_ctrl[ep_idx];
- if (read_bytes) {
- *read_bytes = ep_ctrl->actual;
- }
- return 0;
- }
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- static uint8_t usb_dc_ep_io_cancelled;
- int usb_dc_ep_set_multi_fifo(uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- usb_aotg_dc.out_ep_ctrl[ep_idx].multi = 1;
- } else {
- usb_aotg_dc.in_ep_ctrl[ep_idx].multi = 1;
- }
- return 0;
- }
- /*
- * Specific for epin multi-fito non-auto mode, depends on class driver heavily!
- * Until now, only tested for mass storage.
- *
- * for short packet: just like write() with new mode.
- * for others: write data_len bytes synchronously.
- */
- int usb_dc_ep_write_pending(const uint8_t ep, uint8_t *data,
- uint32_t data_len, uint32_t * const ret_bytes)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- int ret;
- uint32_t len;
- uint16_t count;
- uint8_t in_empty;
- uint8_t npak;
- uint32_t left;
- if (!usb_aotg_dc.attached || !usb_aotg_ep_addr_valid(ep)) {
- LOG_ERR("No valid endpoint");
- return -EINVAL;
- }
- /* for non-control endpoints */
- if (ep_idx == 0) {
- LOG_ERR("control endpoint");
- return -EINVAL;
- }
- /* Check if IN ep */
- if (!USB_EP_DIR_IS_IN(ep)) {
- LOG_ERR("Wrong endpoint direction");
- return -EINVAL;
- }
- /* Check if ep enabled */
- if (!aotg_dc_ep_is_enabled(ep)) {
- LOG_ERR("Not enabled endpoint");
- return -EINVAL;
- }
- LOG_DBG("%d", data_len);
- /* Disable interrupt always */
- usb_clear_bit8(INIEN, ep_idx);
- ep_ctrl = &usb_aotg_dc.in_ep_ctrl[ep_idx];
- if (data_len < ep_ctrl->mps) {
- goto write;
- }
- usb_dc_ep_io_cancelled = 0;
- npak = usb_read8(INxCS(ep_idx)) & EPCS_NPAK_MASK;
- left = data_len;
- while (left) {
- if (left >= ep_ctrl->mps) {
- len = ep_ctrl->mps;
- } else {
- len = left;
- }
- ep_write_fifo(ep, data, len);
- left -= len;
- data += len;
- LOG_DBG("CS: 0x%x", usb_read8(INxCS(ep_idx)));
- count = 0;
- while (usb_read8(INxCS(ep_idx)) & BIT(EPCS_BUSY)) {
- if (usb_dc_ep_io_cancelled) {
- goto exit;
- }
- if (++count < 1000) {
- k_busy_wait(1);
- continue;
- }
- k_sleep(K_MSEC(20));
- /* timeout: 1000us + 200ms */
- if (count > 1010) {
- LOG_ERR("timeout: 0x%x", usb_read8(INxCS(ep_idx)));
- goto exit;
- }
- }
- }
- /* wait for fifo empty */
- count = 0;
- while (1) {
- LOG_DBG("last CS: 0x%x", usb_read8(INxCS(ep_idx)));
- if ((usb_read8(INxCS(ep_idx)) & EPCS_NPAK_MASK) == npak) {
- break;
- }
- if (usb_dc_ep_io_cancelled) {
- goto exit;
- }
- if (++count < 1000) {
- k_busy_wait(1);
- continue;
- }
- k_sleep(K_MSEC(20));
- /* timeout: 1000us + 200ms */
- if (count > 1010) {
- LOG_ERR("last timeout 0x%x", usb_read8(INxCS(ep_idx)));
- goto exit;
- }
- }
- /* Call the registered callback if any */
- if (ep_ctrl->cb) {
- ep_ctrl->cb(ep, USB_DC_EP_DATA_IN);
- }
- exit:
- if (ret_bytes) {
- *ret_bytes = data_len - left;
- }
- LOG_DBG("done CS: 0x%x", usb_read8(INxCS(ep_idx)));
- return 0;
- write:
- in_empty = usb_read8(INEMPTY_IEN) & INEMPTY_IEN_MASK;
- /* clear pending */
- usb_write8(INEMPTY_IRQ, BIT(IRQ_INxEMPTY(ep_idx)) | in_empty);
- ret = ep_write_fifo(ep, data, data_len);
- if (ret < 0) {
- return ret;
- }
- /* enable empty */
- usb_write8(INEMPTY_IEN, BIT(IEN_INxEMPTY(ep_idx)) | in_empty);
- if (ret_bytes) {
- *ret_bytes = data_len;
- }
- return 0;
- }
- /*
- * Specific for epout multi-fito auto mode, depends on class driver heavily!
- * Until now, only tested for mass storage.
- *
- * for short packet: just like read_async(), but no need to set busy.
- * for others: read max_data_len bytes synchronously.
- */
- int usb_dc_ep_read_pending(uint8_t ep, uint8_t *data, uint32_t data_len,
- uint32_t *read_bytes)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- uint32_t len;
- uint16_t count;
- uint32_t left;
- if (!usb_aotg_dc.attached || !usb_aotg_ep_addr_valid(ep)) {
- LOG_ERR("No valid endpoint");
- return -EINVAL;
- }
- /* for non-control endpoints */
- if (ep_idx == 0) {
- LOG_ERR("control endpoint");
- return -EINVAL;
- }
- /* Check if OUT ep */
- if (!USB_EP_DIR_IS_OUT(ep)) {
- LOG_ERR("Wrong endpoint direction");
- return -EINVAL;
- }
- /* Allow to read 0 bytes */
- if (!data && data_len) {
- LOG_ERR("Wrong arguments");
- return -EINVAL;
- }
- /* Check if ep enabled */
- if (!aotg_dc_ep_is_enabled(ep)) {
- LOG_ERR("Not enabled endpoint");
- return -EINVAL;
- }
- LOG_DBG("%d", data_len);
- ep_ctrl = &usb_aotg_dc.out_ep_ctrl[ep_idx];
- if (data_len < ep_ctrl->mps) {
- goto read_async;
- }
- /* Disable interrupt */
- usb_clear_bit8(OUTIEN, ep_idx);
- usb_dc_ep_io_cancelled = 0;
- left = data_len;
- while (left) {
- count = 0;
- while (usb_read8(OUTxCS(ep_idx)) & BIT(EPCS_BUSY)) {
- if (usb_dc_ep_io_cancelled) {
- goto exit;
- }
- if (++count < 1000) {
- k_busy_wait(1);
- continue;
- }
- k_sleep(K_MSEC(20));
- /* timeout: 1000us + 200ms */
- if (count > 1010) {
- LOG_ERR("timeout: 0x%x left: %d",
- usb_read8(OUTxCS(ep_idx)), left);
- goto exit;
- }
- }
- len = usb_read16(OUTxBC(ep_idx));
- LOG_DBG("BC: %d", len);
- ep_read_fifo(ep, data, len);
- left -= len;
- data += len;
- LOG_DBG("CS: 0x%x", usb_read8(OUTxCS(ep_idx)));
- }
- exit:
- if (read_bytes) {
- *read_bytes = data_len - left;
- }
- /* Clear EPxIN IRQ */
- usb_write8(OUTIRQ, BIT(ep_idx));
- /* Call the registered callback if any */
- if (ep_ctrl->cb) {
- ep_ctrl->cb(ep, USB_DC_EP_DATA_OUT);
- }
- return 0;
- read_async:
- /* FIXME: always return max_data_len */
- if (read_bytes) {
- *read_bytes = data_len;
- }
- ep_ctrl->data_len = data_len;
- ep_ctrl->data = data;
- /* Enable interrupt */
- usb_set_bit8(OUTIEN, ep_idx);
- return 0;
- }
- int usb_dc_ep_io_cancel(void)
- {
- usb_dc_ep_io_cancelled = 1;
- return 0;
- }
- #endif /* CONFIG_USB_AOTG_DC_MULTI_FIFO */
- int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len,
- uint32_t *read_bytes)
- {
- uint32_t data_len, bytes_to_copy;
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- unsigned int key;
- if (!usb_aotg_ep_addr_valid(ep)) {
- LOG_ERR("No valid endpoint");
- return -EINVAL;
- }
- /* Check if OUT ep */
- if (!USB_EP_DIR_IS_OUT(ep)) {
- LOG_ERR("Wrong endpoint direction");
- return -EINVAL;
- }
- /* Allow to read 0 bytes */
- if (!data && max_data_len) {
- LOG_ERR("Wrong arguments");
- return -EINVAL;
- }
- /* Check if ep enabled */
- if (!aotg_dc_ep_is_enabled(ep)) {
- LOG_ERR("Not enabled endpoint");
- return -EINVAL;
- }
- data_len = usb_aotg_dc.out_ep_ctrl[ep_idx].data_len;
- if (!data && !max_data_len) {
- /* When both buffer and max data to read are zero return
- * the available data in buffer
- */
- if (read_bytes) {
- *read_bytes = data_len;
- }
- return 0;
- }
- if (data_len > max_data_len) {
- LOG_ERR("Not enough room (%d) to copy all the rcvd data(%d)!",
- max_data_len, data_len);
- bytes_to_copy = max_data_len;
- } else {
- bytes_to_copy = data_len;
- }
- LOG_DBG("Read EP%d, req %d, read %d bytes",
- ep, max_data_len, bytes_to_copy);
- key = irq_lock();
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- return -ENODEV;
- }
- aotg_dc_rx(ep, data, bytes_to_copy);
- irq_unlock(key);
- usb_aotg_dc.out_ep_ctrl[ep_idx].data_len -= bytes_to_copy;
- if (read_bytes) {
- *read_bytes = bytes_to_copy;
- }
- return 0;
- }
- int usb_dc_ep_read_continue(uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- unsigned int key;
- if (!usb_aotg_ep_addr_valid(ep)) {
- LOG_ERR("No valid endpoint");
- return -EINVAL;
- }
- /* Check if OUT ep */
- if (!USB_EP_DIR_IS_OUT(ep)) {
- LOG_ERR("Wrong endpoint direction");
- return -EINVAL;
- }
- if (!usb_aotg_dc.out_ep_ctrl[ep_idx].data_len) {
- key = irq_lock();
- if (!usb_aotg_dc.attached) {
- irq_unlock(key);
- return -ENODEV;
- }
- aotg_dc_prep_rx(ep_idx);
- irq_unlock(key);
- }
- return 0;
- }
- int usb_dc_ep_mps(const uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- return usb_aotg_dc.out_ep_ctrl[ep_idx].mps;
- } else {
- return usb_aotg_dc.in_ep_ctrl[ep_idx].mps;
- }
- }
- #ifdef CONFIG_USB_AOTG_UDC_DMA
- static void usb_aotg_epin_dma_callback(const struct device *dev, void *data,
- uint32_t channel, int reason)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep;
- if (reason != DMA_IRQ_TC) {
- return;
- }
- ep_ctrl = &usb_aotg_dc.in_ep_ctrl[USB_AOTG_IN_EP_1];
- /* Set busy */
- if (ep_ctrl->data_len < ep_ctrl->mps) {
- usb_set_bit8(INxCS(USB_AOTG_IN_EP_1), EPCS_BUSY);
- }
- ep = USB_EP_IDX2ADDR(USB_AOTG_IN_EP_1, USB_EP_DIR_IN);
- /* Call the registered callback if any */
- if (ep_ctrl->cb) {
- ep_ctrl->cb(ep, USB_DC_EP_DATA_IN);
- }
- }
- static void usb_aotg_epout_dma_callback(const struct device *dev, void *data,
- uint32_t channel, int reason)
- {
- struct aotg_dc_ep_ctrl_prv *ep_ctrl;
- if (reason != DMA_IRQ_TC) {
- return;
- }
- ep_ctrl = &usb_aotg_dc.out_ep_ctrl[USB_AOTG_OUT_EP_2];
- ep_ctrl->actual = ep_ctrl->data_len;
- /* Call the registered callback if any */
- if (ep_ctrl->cb) {
- ep_ctrl->cb(USB_AOTG_OUT_EP_2, USB_DC_EP_DATA_OUT);
- }
- }
- static int usb_aotg_dma_init(void)
- {
- int ret;
- usb_aotg_dma.dma_dev = device_get_binding(CONFIG_DMA_0_NAME);
- if (!usb_aotg_dma.dma_dev) {
- printk("%s no dma_dev\n", __func__);
- return -ENODEV;
- }
- /*
- * USB epout single DMA
- */
- usb_aotg_dma.epout_dma_single = dma_request(usb_aotg_dma.dma_dev, 0xff);
- if (usb_aotg_dma.epout_dma_single < 0) {
- printk("%s epout single dma_request\n", __func__);
- return -EINVAL;
- }
- usb_aotg_dma.epout_dma_config_single.channel_direction = PERIPHERAL_TO_MEMORY;
- usb_aotg_dma.epout_dma_config_single.dma_callback = usb_aotg_epout_dma_callback;
- usb_aotg_dma.epout_dma_config_single.source_data_size = 1;
- usb_aotg_dma.epout_dma_config_single.source_burst_length = 1;
- usb_aotg_dma.epout_dma_config_single.dma_slot = DMA_ID_USB0;
- usb_aotg_dma.epout_dma_config_single.complete_callback_en = 1;
- usb_aotg_dma.epout_dma_config_single.head_block = &usb_aotg_dma.epout_dma_block_single;
- ret = dma_config(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_single,
- &usb_aotg_dma.epout_dma_config_single);
- if (ret) {
- printk("%s epout single dma_config %d\n", __func__, ret);
- return -EINVAL;
- }
- /*
- * USB epout burst8 DMA
- */
- usb_aotg_dma.epout_dma_burst8 = dma_request(usb_aotg_dma.dma_dev, 0xff);
- if (usb_aotg_dma.epout_dma_burst8 < 0) {
- printk("%s epout burst8 dma_request\n", __func__);
- return -EINVAL;
- }
- usb_aotg_dma.epout_dma_config_burst8.channel_direction = PERIPHERAL_TO_MEMORY;
- usb_aotg_dma.epout_dma_config_burst8.dma_callback = usb_aotg_epout_dma_callback;
- usb_aotg_dma.epout_dma_config_burst8.source_data_size = 4;
- usb_aotg_dma.epout_dma_config_burst8.source_burst_length = 0;
- usb_aotg_dma.epout_dma_config_burst8.dma_slot = DMA_ID_USB0;
- usb_aotg_dma.epout_dma_config_burst8.complete_callback_en = 1;
- usb_aotg_dma.epout_dma_config_burst8.head_block = &usb_aotg_dma.epout_dma_block_burst8;
- ret = dma_config(usb_aotg_dma.dma_dev, usb_aotg_dma.epout_dma_burst8,
- &usb_aotg_dma.epout_dma_config_burst8);
- if (ret) {
- printk("%s epout burst8 dma_config %d\n", __func__, ret);
- return -EINVAL;
- }
- /*
- * USB epin burst8 DMA
- */
- usb_aotg_dma.epin_dma = dma_request(usb_aotg_dma.dma_dev, 0xff);
- if (usb_aotg_dma.epin_dma < 0) {
- printk("%s epin dma_request\n", __func__);
- return -EINVAL;
- }
- usb_aotg_dma.epin_dma_config.channel_direction = MEMORY_TO_PERIPHERAL;
- usb_aotg_dma.epin_dma_config.dma_callback = usb_aotg_epin_dma_callback;
- usb_aotg_dma.epin_dma_config.source_data_size = 4;
- usb_aotg_dma.epout_dma_config_burst8.source_burst_length = 0;
- usb_aotg_dma.epin_dma_config.dma_slot = DMA_ID_USB0;
- usb_aotg_dma.epin_dma_config.complete_callback_en = 1;
- usb_aotg_dma.epin_dma_config.head_block = &usb_aotg_dma.epin_dma_block;
- ret = dma_config(usb_aotg_dma.dma_dev, usb_aotg_dma.epin_dma,
- &usb_aotg_dma.epin_dma_config);
- if (ret) {
- printk("%s epin dma_config %d\n", __func__, ret);
- return -EINVAL;
- }
- return 0;
- }
- #endif
- enum usb_device_speed usb_dc_maxspeed(void)
- {
- #ifdef CONFIG_USB_AOTG_OTG_SUPPORT_HS
- #ifdef CONFIG_USB_AOTG_DC_FS
- return USB_SPEED_FULL;
- #else
- return USB_SPEED_HIGH;
- #endif
- #else
- return USB_SPEED_FULL;
- #endif
- }
- enum usb_device_speed usb_dc_speed(void)
- {
- return usb_aotg_dc.speed;
- }
- int usb_dc_do_remote_wakeup(void)
- {
- usb_set_bit8(USBCS, USBCS_WAKEUP);
- return 0;
- }
- #endif /* CONFIG_USB_AOTG_DC_ENABLED */
- /*
- * Host related
- */
- #ifdef CONFIG_USB_AOTG_HC_ENABLED
- static inline void aotg_hc_handle_reset(void);
- /*
- * Map endpoint address of peripheral to controller's
- *
- * mapping rules:
- * 1. out_ep_ctrl[idx] used for peripheral's ep-in
- * 2. in_ep_ctrl[idx] used for peripheral's ep-out
- *
- * for examples:
- * 1. 0x81(peri_ep) -- 0x01(aotg_ep) -- dir_out -- out_ep_ctrl
- * 2. 0x01(peri_ep) -- 0x81(aotg_ep) -- dir_in --in_ep_ctrl
- * 3. 0x80(peri_ep) -- 0x00(aotg_ep) -- dir_out -- out_ep_ctrl
- * 4. 0x00(peri_ep) -- 0x80(aotg_ep) -- dir_in --in_ep_ctrl
- */
- static inline int ep_map(uint8_t ep)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- uint8_t i;
- /* suppose ep0-in is 0x80 and ep0-out is 0x0 always */
- if (ep == USB_CONTROL_OUT_EP0) {
- usb_aotg_hc.in_ep_ctrl[0].ep_addr = ep;
- return 0;
- } else if (ep == USB_CONTROL_IN_EP0) {
- usb_aotg_hc.out_ep_ctrl[0].ep_addr = ep;
- return 0;
- }
- if (USB_EP_DIR_IS_OUT(ep)) {
- for (i = USB_AOTG_IN_EP_NUM - 1; i > USB_AOTG_EP0_IDX; i--) {
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[i];
- if (ep_ctrl->ep_ena) {
- continue;
- }
- ep_ctrl->ep_addr = ep;
- return 0;
- }
- } else {
- for (i = USB_AOTG_OUT_EP_1; i < USB_AOTG_OUT_EP_NUM; i++) {
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[i];
- if (ep_ctrl->ep_ena) {
- continue;
- }
- ep_ctrl->ep_addr = ep;
- return 0;
- }
- }
- return -EINVAL;
- }
- /*
- * Convert endpoint address of peripheral to controller's
- */
- static inline uint8_t find_ep(uint8_t ep)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- uint8_t i;
- if (ep == USB_CONTROL_OUT_EP0) {
- return USB_CONTROL_IN_EP0;
- } else if (ep == USB_CONTROL_IN_EP0) {
- return USB_CONTROL_OUT_EP0;
- }
- if (USB_EP_DIR_IS_OUT(ep)) {
- for (i = USB_AOTG_IN_EP_NUM - 1; i > USB_AOTG_EP0_IDX; i--) {
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[i];
- if (ep_ctrl->ep_addr != ep) {
- continue;
- }
- return USB_EP_IDX2ADDR(i, USB_EP_DIR_IN);
- }
- } else {
- for (i = USB_AOTG_OUT_EP_NUM - 1; i > USB_AOTG_EP0_IDX; i--) {
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[i];
- if (ep_ctrl->ep_addr != ep) {
- continue;
- }
- return i;
- }
- }
- /* never */
- return 0;
- }
- /*
- * Check if the MaxPacketSize of endpoint is valid
- */
- static inline bool aotg_hc_ep_mps_valid(uint16_t ep_mps, enum usb_ep_type ep_type)
- {
- enum usb_device_speed speed = usb_aotg_hc.speed;
- switch (ep_type) {
- case USB_EP_CONTROL:
- /* Arbitrary: speed may be unknown */
- return ep_mps <= USB_MAX_CTRL_MPS;
- case USB_EP_BULK:
- if (speed == USB_SPEED_HIGH) {
- return ep_mps == USB_MAX_HS_BULK_MPS;
- } else if (speed == USB_SPEED_FULL) {
- return ep_mps <= USB_MAX_FS_BULK_MPS;
- }
- break;
- case USB_EP_INTERRUPT:
- if (speed == USB_SPEED_HIGH) {
- return ep_mps <= USB_MAX_HS_INTR_MPS;
- } else if (speed == USB_SPEED_FULL) {
- return ep_mps <= USB_MAX_FS_INTR_MPS;
- }
- break;
- case USB_EP_ISOCHRONOUS:
- if (speed == USB_SPEED_HIGH) {
- return ep_mps <= USB_MAX_HS_ISOC_MPS;
- } else if (speed == USB_SPEED_FULL) {
- return ep_mps <= USB_MAX_FS_ISOC_MPS;
- }
- break;
- }
- return false;
- }
- static inline bool aotg_hc_ep_is_enabled(uint8_t aotg_ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- if (USB_EP_DIR_IS_OUT(aotg_ep) &&
- usb_aotg_hc.out_ep_ctrl[ep_idx].ep_ena) {
- return true;
- }
- if (USB_EP_DIR_IS_IN(aotg_ep) &&
- usb_aotg_hc.in_ep_ctrl[ep_idx].ep_ena) {
- return true;
- }
- return false;
- }
- /*
- * Using single FIFO for every endpoint (except for ep0) by default
- */
- static inline int aotg_hc_ep_alloc_fifo(uint8_t aotg_ep)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- if (!ep_idx) {
- return 0;
- }
- if (USB_EP_DIR_IS_OUT(aotg_ep)) {
- if (ep_idx >= USB_AOTG_OUT_EP_NUM) {
- return -EINVAL;
- }
- return aotg_hc_epout_alloc_fifo_specific(ep_idx);
- }
- if (ep_idx >= USB_AOTG_IN_EP_NUM) {
- return -EINVAL;
- }
- return aotg_hc_epin_alloc_fifo_specific(ep_idx);
- }
- /*
- * Max Packet Size Limit
- */
- static inline int aotg_hc_set_max_packet(uint8_t aotg_ep, uint16_t ep_mps,
- enum usb_ep_type ep_type)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- if (!aotg_hc_ep_mps_valid(ep_mps, ep_type)) {
- return -EINVAL;
- }
- if (USB_EP_DIR_IS_OUT(aotg_ep)) {
- usb_write16(OUTxMAXPKT(ep_idx), ep_mps);
- usb_aotg_hc.out_ep_ctrl[ep_idx].mps = ep_mps;
- } else {
- usb_write16(INxMAXPKT(ep_idx), ep_mps);
- usb_aotg_hc.in_ep_ctrl[ep_idx].mps = ep_mps;
- }
- return 0;
- }
- /*
- * Endpoint type
- */
- static inline void aotg_hc_set_ep_type(uint8_t aotg_ep, enum usb_ep_type ep_type)
- {
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- if (USB_EP_DIR_IS_OUT(aotg_ep)) {
- usb_aotg_hc.out_ep_ctrl[ep_idx].ep_type = ep_type;
- } else {
- usb_aotg_hc.in_ep_ctrl[ep_idx].ep_type = ep_type;
- }
- }
- static inline int aotg_hc_ep_set(uint8_t ep, uint16_t ep_mps,
- enum usb_ep_type ep_type)
- {
- uint8_t aotg_ep = find_ep(ep);
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- int ret;
- LOG_DBG("0x%x(0x%x), mps %d, type %d", aotg_ep, ep, ep_mps,
- ep_type);
- /* Set FIFO address */
- ret = aotg_hc_ep_alloc_fifo(aotg_ep);
- if (ret) {
- return ret;
- }
- /* Set Max Packet */
- ret = aotg_hc_set_max_packet(aotg_ep, ep_mps, ep_type);
- if (ret) {
- return ret;
- }
- /* Set EP type */
- aotg_hc_set_ep_type(aotg_ep, ep_type);
- /* No need to set for endpoint 0 */
- if (!ep_idx) {
- usb_write8(EP0MAXPKT, ep_mps);
- return 0;
- }
- if (USB_EP_DIR_IS_OUT(aotg_ep)) {
- usb_write8(HCINxCTRL(ep_idx), ep);
- /* Set endpoint type and FIFO type */
- usb_write8(OUTxCTRL(ep_idx),
- (ep_type << 2) | USB_AOTG_FIFO_SINGLE);
- } else {
- usb_write8(HCOUTxCTRL(ep_idx), USB_EP_ADDR2IDX(ep));
- usb_write8(INxCTRL(ep_idx),
- (ep_type << 2) | USB_AOTG_FIFO_SINGLE);
- }
- return 0;
- }
- int usb_hc_ep_configure(const struct usb_hc_ep_cfg_data * const ep_cfg)
- {
- if (!usb_aotg_hc.attached || ep_map(ep_cfg->ep_addr)) {
- return -EINVAL;
- }
- return aotg_hc_ep_set(ep_cfg->ep_addr, ep_cfg->ep_mps,
- ep_cfg->ep_type);
- }
- int usb_hc_ep_enable(const uint8_t ep)
- {
- uint8_t aotg_ep = find_ep(ep);
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- bool dir_out = USB_EP_DIR_IS_OUT(aotg_ep);
- if (!usb_aotg_hc.attached || !usb_aotg_ep_addr_valid(aotg_ep)) {
- return -EINVAL;
- }
- /* NOTE: re-enable is allowed */
- if (dir_out) {
- usb_write8(OUTIRQ, BIT(IRQ_EPxOUT(ep_idx)));
- usb_set_bit8(OUTIEN, ep_idx);
- usb_set_bit8(HCINEPERRIEN, ep_idx);
- usb_aotg_hc.out_ep_ctrl[ep_idx].ep_ena = 1;
- } else {
- usb_write8(INIRQ, BIT(IRQ_EPxIN(ep_idx)));
- usb_set_bit8(INIEN, ep_idx);
- usb_set_bit8(HCOUTEPERRIEN, ep_idx);
- usb_aotg_hc.in_ep_ctrl[ep_idx].ep_ena = 1;
- }
- /* Endpoint 0 */
- if (!ep_idx) {
- return 0;
- }
- if (usb_aotg_ep_reset(aotg_ep, USB_AOTG_EP_RESET)) {
- return -EINVAL;
- }
- /* Activate endpoint and set FIFOCTRL */
- if (dir_out) {
- usb_set_bit8(OUTxCTRL(ep_idx), EPCTRL_VALID);
- usb_write8(FIFOCTRL, ep_idx);
- } else {
- usb_set_bit8(INxCTRL(ep_idx), EPCTRL_VALID);
- usb_write8(FIFOCTRL, ep_idx | BIT(FIFOCTRL_IO_IN));
- }
- usb_aotg_ep_reg_dump(aotg_ep);
- return 0;
- }
- static int aotg_hc_ep_disable(const uint8_t aotg_ep)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- bool dir_out = USB_EP_DIR_IS_OUT(aotg_ep);
- struct usb_request *urb;
- if (!usb_aotg_hc.attached || !usb_aotg_ep_addr_valid(aotg_ep)) {
- return -EINVAL;
- }
- if (dir_out) {
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[ep_idx];
- } else {
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[ep_idx];
- }
- /* Already disabled */
- if (ep_ctrl->ep_ena == 0) {
- return 0;
- }
- ep_ctrl->ep_ena = 0;
- /* Disable EP interrupts */
- if (dir_out) {
- usb_clear_bit8(OUTIEN, ep_idx);
- usb_clear_bit8(HCINEPERRIEN, ep_idx);
- } else {
- usb_clear_bit8(INIEN, ep_idx);
- usb_clear_bit8(HCOUTEPERRIEN, ep_idx);
- }
- /* Endpoint 0 */
- if (!ep_idx) {
- goto done;
- }
- /* De-activate Ep */
- if (dir_out) {
- usb_clear_bit8(OUTxCTRL(ep_idx), EPCTRL_VALID);
- } else {
- usb_clear_bit8(INxCTRL(ep_idx), EPCTRL_VALID);
- }
- done:
- urb = ep_ctrl->urb;
- if (urb) {
- ep_ctrl->urb = NULL;
- urb->status = -ENODEV;
- urb->complete(urb);
- }
- return 0;
- }
- int usb_hc_ep_disable(const uint8_t ep)
- {
- const uint8_t aotg_ep = find_ep(ep);
- return aotg_hc_ep_disable(aotg_ep);
- }
- int usb_hc_ep_flush(const uint8_t ep)
- {
- uint8_t aotg_ep = find_ep(ep);
- if (!usb_aotg_hc.attached || !usb_aotg_ep_addr_valid(aotg_ep)) {
- return -EINVAL;
- }
- return usb_aotg_ep_reset(aotg_ep, USB_AOTG_EP_FIFO_RESET);
- }
- int usb_hc_ep_reset(const uint8_t ep)
- {
- uint8_t aotg_ep = find_ep(ep);
- if (!usb_aotg_hc.attached || !usb_aotg_ep_addr_valid(aotg_ep)) {
- return -EINVAL;
- }
- return usb_aotg_ep_reset(aotg_ep, USB_AOTG_EP_RESET);
- }
- int usb_hc_set_address(const uint8_t addr)
- {
- if (addr > USB_AOTG_MAX_ADDR) {
- return -EINVAL;
- }
- usb_write8(FNADDR, addr);
- return 0;
- }
- static inline bool bus_reset_done(void)
- {
- /* reset done after sending a SOF packet */
- if ((usb_read8(USBIRQ) & (BIT(USBIRQ_SOF) | BIT(USBIRQ_RESET))) ==
- (BIT(USBIRQ_SOF) | BIT(USBIRQ_RESET))) {
- usb_write8(USBIRQ, usb_read8(USBIRQ));
- return true;
- } else {
- return false;
- }
- }
- /* FIXME: support port status only */
- int usb_hc_root_control(void *buf, int len, struct usb_setup_packet *setup,
- int timeout)
- {
- uint16_t req, value;
- int ret = -EPIPE;
- if (!usb_aotg_hc.attached) {
- return -ENODEV;
- }
- req = (setup->bmRequestType << 8) | setup->bRequest;
- value = sys_le16_to_cpu(setup->wValue);
- switch (req) {
- case GetPortStatus:
- if (bus_reset_done()) {
- aotg_hc_handle_reset();
- }
- *(uint32_t *)buf = sys_cpu_to_le32(usb_aotg_hc.port);
- return 4;
- case SetPortFeature:
- if (value == USB_PORT_FEAT_RESET) {
- usb_aotg_hc.port &= ~(USB_PORT_STAT_ENABLE
- | USB_PORT_STAT_LOW_SPEED
- | USB_PORT_STAT_HIGH_SPEED);
- usb_aotg_hc.port |= USB_PORT_STAT_RESET;
- /* port reset */
- usb_set_bit8(HCPORTCTRL, PORTRST);
- return 0;
- }
- break;
- default:
- break;
- }
- return ret;
- }
- static inline int aotg_hc_control_urb(struct usb_request *urb)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- if (urb->len == 0) {
- /* setup, in status */
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[USB_AOTG_EP0_IDX];
- } else if (urb->ep == USB_CONTROL_OUT_EP0) {
- /* setup, out data, in status */
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[USB_AOTG_EP0_IDX];
- } else {
- /* setup, in data, out status */
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[USB_AOTG_EP0_IDX];
- }
- if (ep_ctrl->urb != NULL) {
- return -EBUSY;
- }
- ep_ctrl->urb = urb;
- /* SETUP */
- usb_aotg_hc.phase = USB_AOTG_SETUP;
- usb_set_bit8(EP0CS, EP0CS_HCSET);
- ep0_write_fifo((const uint8_t *const)urb->setup_packet,
- sizeof(struct usb_setup_packet));
- return 0;
- }
- static inline void aotg_hc_tx_in_pkt(uint8_t ep_idx, uint16_t num_of_pkt)
- {
- LOG_DBG("ep_idx: %d, num_of_pkt: %d", ep_idx, num_of_pkt);
- /* set the number of IN Packet(s) */
- usb_write8(HCINxCNTL(ep_idx), (uint8_t)num_of_pkt);
- usb_write8(HCINxCNTH(ep_idx), (uint8_t)(num_of_pkt >> 8));
- /* set busy */
- if (!(usb_read8(OUTxCS(ep_idx)) & BIT(EPCS_BUSY))) {
- usb_set_bit8(OUTxCS(ep_idx), EPCS_BUSY);
- }
- /* short packet control */
- /* usb_set_bit8(HCINCTRL, HCINx_SHORT(ep_idx)); */
- /* send IN Token */
- usb_set_bit8(HCINCTRL, HCINx_START(ep_idx));
- }
- int usb_hc_submit_urb(struct usb_request *urb)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- uint8_t aotg_ep = find_ep(urb->ep);
- unsigned int key;
- uint8_t ep_idx;
- int ret;
- if (!usb_aotg_hc.attached || !usb_aotg_ep_addr_valid(aotg_ep)) {
- return -EINVAL;
- }
- /* disconnect may happen */
- key = irq_lock();
- /* Check if ep enabled */
- if (!aotg_hc_ep_is_enabled(aotg_ep)) {
- irq_unlock(key);
- return -ENODEV;
- }
- ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- if (!ep_idx) {
- ret = aotg_hc_control_urb(urb);
- irq_unlock(key);
- return ret;
- }
- if (USB_EP_DIR_IS_IN(aotg_ep)) {
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[ep_idx];
- if (ep_ctrl->urb != NULL) {
- irq_unlock(key);
- return -EBUSY;
- }
- ep_ctrl->urb = urb;
- urb->actual = urb->len > ep_ctrl->mps ? ep_ctrl->mps : urb->len;
- /* set actual before write, actual may not correct if error */
- if (ep_write_fifo(aotg_ep, urb->buf, urb->actual) < 0) {
- ep_ctrl->urb = NULL; /* reset if failed */
- urb->actual = 0;
- irq_unlock(key);
- return -EAGAIN;
- }
- urb->buf += urb->actual;
- } else {
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[ep_idx];
- if (ep_ctrl->urb != NULL) {
- irq_unlock(key);
- return -EBUSY;
- }
- ep_ctrl->urb = urb;
- aotg_hc_tx_in_pkt(ep_idx, DIV_ROUND_UP(urb->len, ep_ctrl->mps));
- }
- irq_unlock(key);
- return 0;
- }
- int usb_hc_cancel_urb(struct usb_request *urb)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- uint8_t aotg_ep = find_ep(urb->ep);
- uint8_t ep_idx = USB_EP_ADDR2IDX(aotg_ep);
- bool dir_out = USB_EP_DIR_IS_OUT(aotg_ep);
- if (!usb_aotg_hc.attached || !usb_aotg_ep_addr_valid(aotg_ep)) {
- return -EINVAL;
- }
- if (dir_out) {
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[ep_idx];
- } else {
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[ep_idx];
- }
- /* Already disabled */
- if (ep_ctrl->ep_ena == 0) {
- return 0;
- }
- if (!ep_idx) {
- goto done;
- }
- if (dir_out) {
- usb_clear_bit8(HCINCTRL, HCINx_START(ep_idx));
- }
- usb_aotg_ep_reset(aotg_ep, USB_AOTG_EP_FIFO_RESET);
- done:
- ep_ctrl->urb = NULL;
- urb->complete(urb);
- return 0;
- }
- static inline void aotg_hc_handle_otg(void)
- {
- u8_t tmp;
- u8_t state;
- /* Clear OTG IRQ(s) */
- tmp = usb_read8(OTGIEN) & usb_read8(OTGIRQ);
- usb_write8(OTGIRQ, tmp);
- state = usb_read8(OTGSTATE);
- /* If AOTG enters a_host state, enable state change irq(a_host->a_wait_bcon) */
- if (state == OTG_A_HOST) {
- usb_set_bit8(OTGSTATE_IEN, OTGSTATE_A_WAIT_BCON);
- }
- LOG_DBG("State: 0x%x, irq: 0x%x", state, tmp);
- }
- static inline void aotg_hc_handle_otg_state(void)
- {
- u8_t i;
- /* clear interrupt request */
- usb_set_bit8(OTGSTATE_IRQ, OTGSTATE_A_WAIT_BCON);
- if (usb_read8(OTGSTATE) == OTG_A_WAIT_BCON) {
- for (i = 0; i < USB_AOTG_IN_EP_NUM; i++) {
- aotg_hc_ep_disable(USB_EP_IDX2ADDR(i, USB_EP_DIR_IN));
- }
- for (i = 0; i < USB_AOTG_OUT_EP_NUM; i++) {
- aotg_hc_ep_disable(USB_EP_IDX2ADDR(i, USB_EP_DIR_OUT));
- }
- }
- }
- static inline void aotg_hc_handle_reset(void)
- {
- uint8_t usbcs;
- /* Clear USB Reset IRQ */
- usb_write8(USBIRQ, BIT(USBIRQ_RESET));
- usb_aotg_hc.port &= ~USB_PORT_STAT_RESET;
- usb_aotg_hc.port |= USB_PORT_STAT_ENABLE;
- /* reset all ep-in */
- usb_aotg_ep_reset(0x80, USB_AOTG_EP_RESET);
- /* reset all ep-out */
- usb_aotg_ep_reset(0x0, USB_AOTG_EP_RESET);
- usbcs = usb_read8(USBCS);
- if (usbcs & BIT(USBCS_SPEED)) {
- usb_aotg_hc.speed = USB_SPEED_HIGH;
- usb_aotg_hc.port |= USB_PORT_STAT_HIGH_SPEED;
- } else if (usb_read8(USBCS) & BIT(USBCS_LS)) {
- usb_aotg_hc.speed = USB_SPEED_LOW;
- usb_aotg_hc.port |= USB_PORT_STAT_LOW_SPEED;
- } else {
- usb_aotg_hc.speed = USB_SPEED_FULL;
- }
- LOG_DBG("USBCS: 0x%x", usbcs);
- }
- static inline void aotg_hc_handle_sof(void)
- {
- usb_set_bit8(USBIRQ, USBIRQ_SOF);
- }
- static inline void aotg_hc_handle_ep0out(void)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- struct usb_request *urb;
- uint8_t rx_len, mps;
- /* find urb */
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[USB_AOTG_EP0_IDX];
- urb = ep_ctrl->urb;
- if (!urb) {
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[USB_AOTG_EP0_IDX];
- urb = ep_ctrl->urb;
- if (!urb) {
- return;
- }
- }
- ep_ctrl->err_count = 0;
- switch (usb_aotg_hc.phase) {
- case USB_AOTG_IN_DATA:
- mps = usb_aotg_hc.out_ep_ctrl[USB_AOTG_EP0_IDX].mps;
- rx_len = urb->len > mps ? mps : urb->len;
- rx_len = ep0_read_fifo(urb->buf, rx_len);
- urb->buf += rx_len;
- urb->actual += rx_len;
- /* FIXME: handle babble */
- /* short packet or complete */
- if ((rx_len < mps) || (urb->actual == urb->len)) {
- usb_aotg_hc.phase = USB_AOTG_OUT_STATUS;
- usb_clear_bit8(EP0CS, EP0CS_HCSET);
- usb_set_bit8(EP0CS, EP0CS_SETTOGGLE);
- usb_write8(IN0BC, 0);
- } else {
- usb_write8(OUT0BC, 0x0);
- }
- break;
- case USB_AOTG_IN_STATUS:
- usb_aotg_hc.in_ep_ctrl[USB_AOTG_EP0_IDX].urb = NULL;
- urb->status = 0;
- urb->complete(urb);
- break;
- default:
- break;
- }
- }
- /*
- * Handle EPxOUT data
- */
- static inline void aotg_hc_handle_epout(uint8_t ep_idx)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- struct usb_request *urb;
- bool done = false;
- uint16_t rx_len;
- uint8_t aotg_ep;
- usb_write8(OUTIRQ, BIT(IRQ_EPxOUT(ep_idx)));
- if (!ep_idx) {
- return aotg_hc_handle_ep0out();
- }
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[ep_idx];
- urb = ep_ctrl->urb;
- if (!urb) {
- LOG_DBG("ep_idx: %d no urb", ep_idx);
- return;
- }
- ep_ctrl->err_count = 0;
- LOG_DBG("hcepin ep_idx: %d, urb->actual: %d, urb->len: %d",
- ep_idx, urb->actual, urb->len);
- aotg_ep = USB_EP_IDX2ADDR(ep_idx, USB_EP_DIR_OUT);
- rx_len = usb_read16(OUTxBC(ep_idx));
- ep_read_fifo(aotg_ep, urb->buf + urb->actual, rx_len);
- urb->actual += rx_len;
- if (urb->actual > urb->len) {
- LOG_DBG("0x%x(0x%x) babble", aotg_ep, ep_ctrl->ep_addr);
- urb->status = -EIO;
- done = true;
- } else if (urb->actual == urb->len) {
- urb->status = 0;
- done = true;
- } else if (rx_len < ep_ctrl->mps) {
- LOG_DBG("0x%x(0x%x) short %d", aotg_ep, ep_ctrl->ep_addr,
- rx_len);
- urb->status = 0;
- done = true;
- } else {
- usb_set_bit8(OUTxCS(ep_idx), EPCS_BUSY);
- }
- if (done) {
- ep_ctrl->urb = NULL;
- urb->complete(urb);
- }
- }
- static inline void aotg_hc_handle_ep0in(void)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- struct usb_request *urb;
- uint8_t tx_len, mps;
- /* find urb */
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[USB_AOTG_EP0_IDX];
- urb = ep_ctrl->urb;
- if (!urb) {
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[USB_AOTG_EP0_IDX];
- urb = ep_ctrl->urb;
- if (!urb) {
- return;
- }
- }
- ep_ctrl->err_count = 0;
- switch (usb_aotg_hc.phase) {
- case USB_AOTG_SETUP:
- if (urb->len == 0) {
- usb_aotg_hc.phase = USB_AOTG_IN_STATUS;
- usb_set_bit8(EP0CS, EP0CS_SETTOGGLE);
- usb_write8(OUT0BC, 0x0);
- break;
- }
- if (urb->ep == USB_CONTROL_IN_EP0) {
- usb_aotg_hc.phase = USB_AOTG_IN_DATA;
- /* send IN token */
- usb_write8(OUT0BC, 0x0);
- } else {
- usb_aotg_hc.phase = USB_AOTG_OUT_DATA;
- mps = usb_aotg_hc.in_ep_ctrl[USB_AOTG_EP0_IDX].mps;
- urb->actual = urb->len > mps ? mps : urb->len;
- usb_clear_bit8(EP0CS, EP0CS_HCSET);
- ep0_write_fifo(urb->buf, urb->actual);
- urb->buf += urb->actual;
- }
- break;
- case USB_AOTG_OUT_DATA:
- if (urb->actual == urb->len) {
- usb_aotg_hc.phase = USB_AOTG_IN_STATUS;
- usb_set_bit8(EP0CS, EP0CS_SETTOGGLE);
- usb_write8(OUT0BC, 0x0);
- } else {
- mps = usb_aotg_hc.in_ep_ctrl[USB_AOTG_EP0_IDX].mps;
- tx_len = urb->len > mps ? mps : urb->len;
- if ((urb->len - urb->actual) > mps) {
- tx_len = mps;
- } else {
- tx_len = urb->len - urb->actual;
- }
- usb_clear_bit8(EP0CS, EP0CS_HCSET);
- ep0_write_fifo(urb->buf, tx_len);
- urb->buf += tx_len;
- urb->actual += tx_len;
- }
- break;
- case USB_AOTG_OUT_STATUS:
- usb_aotg_hc.out_ep_ctrl[USB_AOTG_EP0_IDX].urb = NULL;
- urb->status = 0;
- urb->complete(urb);
- break;
- default:
- break;
- }
- }
- /*
- * Handle EPxIN data
- */
- static inline void aotg_hc_handle_epin(uint8_t ep_idx)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- struct usb_request *urb;
- uint16_t tx_len;
- uint8_t aotg_ep;
- usb_write8(INIRQ, BIT(IRQ_EPxIN(ep_idx)));
- if (!ep_idx) {
- return aotg_hc_handle_ep0in();
- }
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[ep_idx];
- urb = ep_ctrl->urb;
- if (!urb) {
- LOG_DBG("ep_idx: %d no urb", ep_idx);
- return;
- }
- ep_ctrl->err_count = 0;
- LOG_DBG("ep_idx: %d, urb->actual: %d, urb->len: %d",
- ep_idx, urb->actual, urb->len);
- if (urb->actual == urb->len) {
- ep_ctrl->urb = NULL;
- urb->status = 0;
- urb->complete(urb);
- return;
- }
- aotg_ep = USB_EP_IDX2ADDR(ep_idx, USB_EP_DIR_IN);
- tx_len = urb->len - urb->actual;
- tx_len = tx_len > ep_ctrl->mps ? ep_ctrl->mps : tx_len;
- ep_write_fifo(aotg_ep, urb->buf, tx_len);
- urb->buf += tx_len;
- urb->actual += tx_len;
- }
- static inline void aotg_hc_handle_epout_err(uint8_t ep_idx)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- struct usb_request *urb;
- uint8_t type;
- usb_write8(HCINEPERRIRQ, BIT(HCEPxERRIRQ(ep_idx)));
- ep_ctrl = &usb_aotg_hc.out_ep_ctrl[ep_idx];
- urb = ep_ctrl->urb;
- if (!urb) {
- return;
- }
- type = usb_read8(HCINxERR(ep_idx)) & HCEPERR_TYPE_MASK;
- LOG_DBG("ep_idx: %d, type: 0x%x", ep_idx, type);
- switch (type) {
- default:
- if (++ep_ctrl->err_count < ERR_COUNT_MAX) {
- /* resend or try again */
- usb_set_bit8(HCINxERR(ep_idx), HCEPERR_RESEND);
- } else {
- usb_clear_bit8(HCINCTRL, HCINx_START(ep_idx));
- ep_ctrl->err_count = 0;
- ep_ctrl->urb = NULL;
- urb->status = -EIO;
- urb->complete(urb);
- }
- break;
- /* could it happen? */
- case NO_ERR:
- break;
- /* stall */
- case ERR_STALL:
- usb_clear_bit8(HCINCTRL, HCINx_START(ep_idx));
- ep_ctrl->urb = NULL;
- urb->status = -EPIPE;
- urb->complete(urb);
- break;
- }
- }
- static inline void aotg_hc_handle_epin_err(uint8_t ep_idx)
- {
- struct aotg_hc_ep_ctrl_prv *ep_ctrl;
- struct usb_request *urb;
- uint8_t type;
- usb_write8(HCOUTEPERRIRQ, BIT(HCEPxERRIRQ(ep_idx)));
- ep_ctrl = &usb_aotg_hc.in_ep_ctrl[ep_idx];
- urb = ep_ctrl->urb;
- if (!urb) {
- return;
- }
- type = usb_read8(HCOUTxERR(ep_idx)) & HCEPERR_TYPE_MASK;
- LOG_DBG("ep_idx: %d, type: 0x%x", ep_idx, type);
- switch (usb_read8(HCOUTxERR(ep_idx)) & HCEPERR_TYPE_MASK) {
- default:
- if (++ep_ctrl->err_count < ERR_COUNT_MAX) {
- /* resend or try again */
- usb_set_bit8(HCOUTxERR(ep_idx), HCEPERR_RESEND);
- } else {
- ep_ctrl->err_count = 0;
- ep_ctrl->urb = NULL;
- urb->status = -EIO;
- urb->complete(urb);
- }
- break;
- /* could it happen? */
- case NO_ERR:
- break;
- /* stall */
- case ERR_STALL:
- ep_ctrl->urb = NULL;
- urb->status = -EPIPE;
- urb->complete(urb);
- break;
- }
- }
- static inline void aotg_hc_isr_dispatch(uint8_t vector)
- {
- uint8_t usbeien = usb_read8(USBEIEN) & USBEIEN_MASK;
- /*
- * Make sure external IRQ has been cleared right!
- *
- * TODO: If two or more IRQs are pending simultaneously,
- * EIRQ will be pending immediately after cleared or not?
- */
- while (usb_read8(USBEIRQ) & BIT(USBEIRQ_EXTERN)) {
- usb_write8(USBEIRQ, BIT(USBEIRQ_EXTERN) | usbeien);
- }
- switch (vector) {
- /* OTG */
- case UIV_OTGIRQ:
- aotg_hc_handle_otg();
- break;
- case UIV_OTGSTATE:
- aotg_hc_handle_otg_state();
- break;
- /* USB Reset */
- case UIV_USBRST:
- aotg_hc_handle_reset();
- break;
- case UIV_SOF:
- aotg_hc_handle_sof();
- break;
- /* HCINx */
- case UIV_EP0OUT:
- case UIV_EP1OUT:
- case UIV_EP2OUT:
- case UIV_EP3OUT:
- #if (CONFIG_USB_AOTG_OTG_VERSION == USB_AOTG_VERSION_LEOPARD)
- case UIV_EP4OUT:
- case UIV_EP5OUT:
- case UIV_EP6OUT:
- #endif
- aotg_hc_handle_epout(UIV_EPOUT_VEC2ADDR(vector));
- break;
- /* HCOUTx */
- case UIV_EP0IN:
- case UIV_EP1IN:
- case UIV_EP2IN:
- case UIV_EP3IN:
- #if (CONFIG_USB_AOTG_OTG_VERSION == USB_AOTG_VERSION_LEOPARD)
- case UIV_EP4IN:
- case UIV_EP5IN:
- case UIV_EP6IN:
- #endif
- aotg_hc_handle_epin(UIV_EPIN_VEC2ADDR(vector));
- break;
- /* HCINxERR */
- case UIV_HCIN0ERR:
- case UIV_HCIN1ERR:
- case UIV_HCIN2ERR:
- case UIV_HCIN3ERR:
- #if (CONFIG_USB_AOTG_OTG_VERSION == USB_AOTG_VERSION_LEOPARD)
- case UIV_HCIN4ERR:
- case UIV_HCIN5ERR:
- case UIV_HCIN6ERR:
- #endif
- aotg_hc_handle_epout_err(UIV_HCINERR_VEC2ADDR(vector));
- break;
- /* HCOUTxERR */
- case UIV_HCOUT0ERR:
- case UIV_HCOUT1ERR:
- case UIV_HCOUT2ERR:
- case UIV_HCOUT3ERR:
- #if (CONFIG_USB_AOTG_OTG_VERSION == USB_AOTG_VERSION_LEOPARD)
- case UIV_HCOUT4ERR:
- case UIV_HCOUT5ERR:
- case UIV_HCOUT6ERR:
- #endif
- aotg_hc_handle_epin_err(UIV_HCOUTERR_VEC2ADDR(vector));
- break;
- default:
- break;
- }
- }
- int usb_hc_reset(void)
- {
- int ret;
- ret = usb_aotg_reset();
- /* Clear private data */
- memset(&usb_aotg_hc, 0, sizeof(usb_aotg_hc));
- return ret;
- }
- int usb_hc_enable(void)
- {
- if (usb_aotg_hc.attached) {
- LOG_DBG("already");
- return 0;
- }
- aotg_hc_fifo_enable();
- /* Enable OTG(a_host) interrupt */
- usb_set_bit8(OTGIEN, OTGIEN_LOCSOF);
- /* Enable external interrupt */
- usb_set_bit8(USBEIEN, USBEIEN_EXTERN);
- irq_enable(USB_AOTG_IRQ);
- memset(&usb_aotg_hc, 0, sizeof(usb_aotg_hc));
- usb_aotg_hc.port = USB_PORT_STAT_CONNECTION;
- usb_aotg_hc.attached = 1;
- usb_aotg_reg_dump();
- LOG_DBG("");
- return 0;
- }
- int usb_hc_disable(void)
- {
- if (!usb_aotg_hc.attached) {
- LOG_DBG("already");
- return 0;
- }
- irq_disable(USB_AOTG_IRQ);
- memset(&usb_aotg_hc, 0, sizeof(usb_aotg_hc));
- usb_aotg_disable();
- aotg_hc_fifo_disable();
- LOG_DBG("");
- return 0;
- }
- /* usb ram alloc/free */
- int usb_hc_fifo_control(bool enable)
- {
- if (enable) {
- return aotg_hc_fifo_enable();
- } else {
- return aotg_hc_fifo_disable();
- }
- return 0;
- }
- #endif /* CONFIG_USB_AOTG_HC_ENABLED */
- uint8_t usb_phy_get_id(void)
- {
- return USB_ID_INVALID;
- }
- uint8_t usb_phy_get_vbus(void)
- {
- if(soc_pmu_get_dc5v_status()){
- return USB_VBUS_HIGH;
- }
- return USB_VBUS_LOW;
- }
- bool usb_phy_hc_attached(void)
- {
- /* full-speed or high-speed */
- if ((usb_read8(LINESTATUS) & LINESTATE_MASK) == LINESTATE_DP) {
- return true;
- }
- return false;
- }
- bool usb_phy_hc_connected(void)
- {
- #ifdef CONFIG_USB_AOTG_HC_ENABLED
- if ((usb_read8(USBSTATE) == OTG_A_HOST) && bus_reset_done()) {
- return true;
- }
- #endif
- return false;
- }
- bool usb_phy_hc_disconnected(void)
- {
- if (usb_read8(USBSTATE) != OTG_A_HOST) {
- return true;
- }
- return false;
- }
- bool usb_phy_dc_attached(void)
- {
- return ((usb_read8(DPDMCTRL) & BIT(PLUGIN)) &&
- !(usb_read8(LINESTATUS) & LINESTATE_MASK));
- }
- bool usb_phy_dc_detached(void)
- {
- #ifdef CONFIG_USB_AOTG_DC_ENABLED
- return usb_aotg_dc.attached == 0;
- #else
- return true;
- #endif
- }
- bool usb_phy_dc_connected(void)
- {
- #ifdef CONFIG_USB_AOTG_DC_ENABLED
- return usb_aotg_dc.speed != USB_SPEED_UNKNOWN;
- #else
- return false;
- #endif
- }
- bool usb_phy_dc_disconnected(void)
- {
- return !(usb_read8(DPDMCTRL) & BIT(PLUGIN));
- }
- void usb_phy_dc_disconnect(void)
- {
- #ifdef CONFIG_USB_AOTG_DC_ENABLED
- aotg_dc_disconnect();
- #endif
- }
- int usb_phy_enter_a_idle(void)
- {
- usb_aotg_mode = USB_OTG_HOST;
- usb_aotg_clock_enable();
- usb_aotg_dpdm_init();
- acts_reset_peripheral(RESET_ID_USB2);
- usb_write8(IDVBUSCTRL, IDVBUS_HOST);
- usb_write8(DPDMCTRL, DPDM_HOST);
- return 0;
- }
- int usb_phy_enter_b_idle(void)
- {
- usb_aotg_mode = USB_OTG_DEVICE;
- usb_dc_hardware_init();
- usb_aotg_clock_enable();
- usb_aotg_dpdm_init();
- acts_reset_peripheral(RESET_ID_USB2);
- usb_write8(IDVBUSCTRL, IDVBUS_DEVICE);
- usb_write8(DPDMCTRL, DPDM_DEVICE);
- return 0;
- }
- int usb_phy_enter_a_wait_bcon(void)
- {
- #ifdef CONFIG_USB_AOTG_HC_ENABLED
- usb_aotg_enable();
- usb_write8(IDVBUSCTRL, IDVBUS_HOST);
- usb_write8(DPDMCTRL, DPDM_HOST);
- aotg_hc_phy_init();
- usb_set_bit8(OTGCTRL, OTGCTRL_BUSREQ);
- #endif
- return 0;
- }
- static void usb_aotg_isr_handler(void)
- {
- /* IRQ Vector */
- uint8_t vector = usb_read8(IVECT);
- LOG_DBG("vector: 0x%x", vector);
- if (usb_aotg_mode == USB_OTG_HOST) {
- #ifdef CONFIG_USB_AOTG_HC_ENABLED
- aotg_hc_isr_dispatch(vector);
- #endif
- } else if (usb_aotg_mode == USB_OTG_DEVICE) {
- #ifdef CONFIG_USB_AOTG_DC_ENABLED
- aotg_dc_isr_dispatch(vector);
- #endif
- }
- }
- int usb_phy_reset(void)
- {
- usb_aotg_exit();
- return 0;
- }
- int usb_phy_init(void)
- {
- usb_aotg_exit();
- /* Connect and enable USB interrupt */
- IRQ_CONNECT(USB_AOTG_IRQ, CONFIG_USB_AOTG_OTG_IRQ_PRIO,
- usb_aotg_isr_handler, 0, 0);
- irq_disable(USB_AOTG_IRQ);
- return 0;
- }
- int usb_phy_exit(void)
- {
- usb_aotg_exit();
- usb_aotg_dpdm_exit();
- return 0;
- }
- static int usb_aotg_pre_init(const struct device *dev)
- {
- ARG_UNUSED(dev);
- #ifdef CONFIG_USB_AOTG_UDC_DMA
- usb_aotg_dma_init();
- #endif
- return 0;
- }
- SYS_INIT(usb_aotg_pre_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|