1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406 |
- /* ==========================================================================
- * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
- * $Revision: #104 $
- * $Date: 2011/10/24 $
- * $Change: 1871159 $
- *
- * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
- * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
- * otherwise expressly agreed to in writing between Synopsys and you.
- *
- * The Software IS NOT an item of Licensed Software or Licensed Product under
- * any End User Software License Agreement or Agreement for Licensed Product
- * with Synopsys or any supplement thereto. You are permitted to use and
- * redistribute this Software in source and binary forms, with or without
- * modification, provided that redistributions of source code must retain this
- * notice. You may not view, use, disclose, copy or distribute this file or
- * any information contained herein except pursuant to this license grant from
- * Synopsys. If you do not agree with this notice, including the disclaimer
- * below, then you are not authorized to use the Software.
- *
- * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- * ========================================================================== */
- #ifndef DWC_DEVICE_ONLY
- /** @file
- * This file implements HCD Core. All code in this file is portable and doesn't
- * use any OS specific functions.
- * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
- * header file.
- */
- #include "dwc_otg_hcd.h"
- #include "dwc_otg_regs.h"
- dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
- {
- return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
- }
- /**
- * Connection timeout function. An OTG host is required to display a
- * message if the device does not connect within 10 seconds.
- */
- void dwc_otg_hcd_connect_timeout(void *ptr)
- {
- DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
- DWC_PRINTF("Connect Timeout\n");
- __DWC_ERROR("Device Not Connected/Responding\n");
- }
- #ifdef DEBUG
- static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
- {
- if (qh->channel != NULL) {
- dwc_hc_t *hc = qh->channel;
- dwc_list_link_t *item;
- dwc_otg_qh_t *qh_item;
- int num_channels = hcd->core_if->core_params->host_channels;
- int i;
- dwc_otg_hc_regs_t *hc_regs;
- hcchar_data_t hcchar;
- hcsplt_data_t hcsplt;
- hctsiz_data_t hctsiz;
- uint32_t hcdma;
- hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
- hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
- hcdma = DWC_READ_REG32(&hc_regs->hcdma);
- DWC_PRINTF(" Assigned to channel %p:\n", hc);
- DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
- hcsplt.d32);
- DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
- hcdma);
- DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
- hc->dev_addr, hc->ep_num, hc->ep_is_in);
- DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
- DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
- DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
- DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
- DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
- DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
- DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
- DWC_PRINTF(" qh: %p\n", hc->qh);
- DWC_PRINTF(" NP inactive sched:\n");
- DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
- qh_item =
- DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
- DWC_PRINTF(" %p\n", qh_item);
- }
- DWC_PRINTF(" NP active sched:\n");
- DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
- qh_item =
- DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
- DWC_PRINTF(" %p\n", qh_item);
- }
- DWC_PRINTF(" Channels: \n");
- for (i = 0; i < num_channels; i++) {
- dwc_hc_t *hc = hcd->hc_ptr_array[i];
- DWC_PRINTF(" %2d: %p\n", i, hc);
- }
- }
- }
- #endif /* DEBUG */
- /**
- * Work queue function for starting the HCD when A-Cable is connected.
- * The hcd_start() must be called in a process context.
- */
- static void hcd_start_func(void *_vp)
- {
- dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
- DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
- if (hcd) {
- hcd->fops->start(hcd);
- }
- }
- static void del_xfer_timers(dwc_otg_hcd_t * hcd)
- {
- #ifdef DEBUG
- int i;
- int num_channels = hcd->core_if->core_params->host_channels;
- for (i = 0; i < num_channels; i++) {
- DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
- }
- #endif
- }
- static void del_timers(dwc_otg_hcd_t * hcd)
- {
- del_xfer_timers(hcd);
- DWC_TIMER_CANCEL(hcd->conn_timer);
- }
- /**
- * Processes all the URBs in a single list of QHs. Completes them with
- * -ETIMEDOUT and frees the QTD.
- */
- static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
- {
- dwc_list_link_t *qh_item;
- dwc_otg_qh_t *qh;
- dwc_otg_qtd_t *qtd, *qtd_tmp;
- DWC_LIST_FOREACH(qh_item, qh_list) {
- qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
- DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
- &qh->qtd_list, qtd_list_entry) {
- qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
- if (qtd->urb != NULL) {
- hcd->fops->complete(hcd, qtd->urb->priv,
- qtd->urb, -DWC_E_TIMEOUT);
- dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
- }
- }
- }
- }
- /**
- * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
- * and periodic schedules. The QTD associated with each URB is removed from
- * the schedule and freed. This function may be called when a disconnect is
- * detected or when the HCD is being stopped.
- */
- static void kill_all_urbs(dwc_otg_hcd_t * hcd)
- {
- kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
- kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
- kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
- kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
- kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
- kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
- }
- /**
- * Start the connection timer. An OTG host is required to display a
- * message if the device does not connect within 10 seconds. The
- * timer is deleted if a port connect interrupt occurs before the
- * timer expires.
- */
- static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
- {
- DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
- }
- /**
- * HCD Callback function for disconnect of the HCD.
- *
- * @param p void pointer to the <code>struct usb_hcd</code>
- */
- static int32_t dwc_otg_hcd_session_start_cb(void *p)
- {
- dwc_otg_hcd_t *dwc_otg_hcd;
- DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
- dwc_otg_hcd = p;
- dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
- return 1;
- }
- /**
- * HCD Callback function for starting the HCD when A-Cable is
- * connected.
- *
- * @param p void pointer to the <code>struct usb_hcd</code>
- */
- static int32_t dwc_otg_hcd_start_cb(void *p)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = p;
- dwc_otg_core_if_t *core_if;
- hprt0_data_t hprt0;
- core_if = dwc_otg_hcd->core_if;
- if (core_if->op_state == B_HOST) {
- /*
- * Reset the port. During a HNP mode switch the reset
- * needs to occur within 1ms and have a duration of at
- * least 50ms.
- */
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtrst = 1;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- }
- DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
- hcd_start_func, dwc_otg_hcd, 50,
- "start hcd");
- return 1;
- }
- /**
- * HCD Callback function for disconnect of the HCD.
- *
- * @param p void pointer to the <code>struct usb_hcd</code>
- */
- static int32_t dwc_otg_hcd_disconnect_cb(void *p)
- {
- gintsts_data_t intr;
- dwc_otg_hcd_t *dwc_otg_hcd = p;
- /*
- * Set status flags for the hub driver.
- */
- dwc_otg_hcd->flags.b.port_connect_status_change = 1;
- dwc_otg_hcd->flags.b.port_connect_status = 0;
- /*
- * Shutdown any transfers in process by clearing the Tx FIFO Empty
- * interrupt mask and status bits and disabling subsequent host
- * channel interrupts.
- */
- intr.d32 = 0;
- intr.b.nptxfempty = 1;
- intr.b.ptxfempty = 1;
- intr.b.hcintr = 1;
- DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
- intr.d32, 0);
- DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
- intr.d32, 0);
- del_timers(dwc_otg_hcd);
- /*
- * Turn off the vbus power only if the core has transitioned to device
- * mode. If still in host mode, need to keep power on to detect a
- * reconnection.
- */
- if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
- if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
- hprt0_data_t hprt0 = {.d32 = 0 };
- DWC_PRINTF("Disconnect: PortPower off\n");
- hprt0.b.prtpwr = 0;
- DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
- hprt0.d32);
- dwc_otg_set_vbus_power(dwc_otg_hcd->core_if, 0); //Power off VBus
- }
- dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
- }
- /* Respond with an error status to all URBs in the schedule. */
- kill_all_urbs(dwc_otg_hcd);
- if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
- /* Clean up any host channels that were in use. */
- int num_channels;
- int i;
- dwc_hc_t *channel;
- dwc_otg_hc_regs_t *hc_regs;
- hcchar_data_t hcchar;
- num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
- if (!dwc_otg_hcd->core_if->dma_enable) {
- /* Flush out any channel requests in slave mode. */
- for (i = 0; i < num_channels; i++) {
- channel = dwc_otg_hcd->hc_ptr_array[i];
- if (DWC_CIRCLEQ_EMPTY_ENTRY
- (channel, hc_list_entry)) {
- hc_regs =
- dwc_otg_hcd->core_if->
- host_if->hc_regs[i];
- hcchar.d32 =
- DWC_READ_REG32(&hc_regs->hcchar);
- if (hcchar.b.chen) {
- hcchar.b.chen = 0;
- hcchar.b.chdis = 1;
- hcchar.b.epdir = 0;
- DWC_WRITE_REG32
- (&hc_regs->hcchar,
- hcchar.d32);
- }
- }
- }
- }
- for (i = 0; i < num_channels; i++) {
- channel = dwc_otg_hcd->hc_ptr_array[i];
- if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
- hc_regs =
- dwc_otg_hcd->core_if->host_if->hc_regs[i];
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- if (hcchar.b.chen) {
- /* Halt the channel. */
- hcchar.b.chdis = 1;
- DWC_WRITE_REG32(&hc_regs->hcchar,
- hcchar.d32);
- }
- dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
- channel);
- DWC_CIRCLEQ_INSERT_TAIL
- (&dwc_otg_hcd->free_hc_list, channel,
- hc_list_entry);
- /* Take back a non_periodic_channel */
- switch (channel->ep_type) {
- case DWC_OTG_EP_TYPE_CONTROL:
- case DWC_OTG_EP_TYPE_BULK:
- dwc_otg_hcd->non_periodic_channels--;
- break;
- default:
- break;
- }
-
- /*
- * Added for Descriptor DMA to prevent channel double cleanup
- * in release_channel_ddma(). Which called from ep_disable
- * when device disconnect.
- */
- channel->qh = NULL;
- }
- }
- }
- if (dwc_otg_hcd->fops->disconnect) {
- dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
- }
- return 1;
- }
- /**
- * HCD Callback function for stopping the HCD.
- *
- * @param p void pointer to the <code>struct usb_hcd</code>
- */
- static int32_t dwc_otg_hcd_stop_cb(void *p)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = p;
- DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
- dwc_otg_hcd_stop(dwc_otg_hcd);
- return 1;
- }
- #ifdef CONFIG_USB_DWC_OTG_LPM
- /**
- * HCD Callback function for sleep of HCD.
- *
- * @param p void pointer to the <code>struct usb_hcd</code>
- */
- static int dwc_otg_hcd_sleep_cb(void *p)
- {
- dwc_otg_hcd_t *hcd = p;
- dwc_otg_hcd_free_hc_from_lpm(hcd);
- return 0;
- }
- #endif
- /**
- * HCD Callback function for Remote Wakeup.
- *
- * @param p void pointer to the <code>struct usb_hcd</code>
- */
- static int dwc_otg_hcd_rem_wakeup_cb(void *p)
- {
- dwc_otg_hcd_t *hcd = p;
- if (hcd->core_if->lx_state == DWC_OTG_L2) {
- hcd->flags.b.port_suspend_change = 1;
- }
- #ifdef CONFIG_USB_DWC_OTG_LPM
- else {
- hcd->flags.b.port_l1_change = 1;
- }
- #endif
- return 0;
- }
- /**
- * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
- * stopped.
- */
- void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
- {
- hprt0_data_t hprt0 = {.d32 = 0 };
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
- /*
- * The root hub should be disconnected before this function is called.
- * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
- * and the QH lists (via ..._hcd_endpoint_disable).
- */
- /* Turn off all host-specific interrupts. */
- dwc_otg_disable_host_interrupts(hcd->core_if);
- /* Turn off the vbus power */
- DWC_PRINTF("PortPower off\n");
- hprt0.b.prtpwr = 0;
- DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
- /* control the GPIO the power off VBUS */
- dwc_otg_set_vbus_power(hcd->core_if, 0);
-
- dwc_mdelay(1);
- }
- /** dwc_otg_hcd suspend */
- int dwc_otg_hcd_suspend(dwc_otg_hcd_t * hcd)
- {
- usb_dbg_uart_data_t uart = {.d32 = 0 };
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD SUSPEND\n");
-
- uart.d32 = DWC_READ_REG32(&hcd->core_if->usb_peri_reg->dbg_uart);
- uart.b.set_iddq = 1;
- DWC_WRITE_REG32(&hcd->core_if->usb_peri_reg->dbg_uart,uart.d32);
-
- return 0;
- }
- /** dwc_otg_hcd resume */
- int dwc_otg_hcd_resume(dwc_otg_hcd_t *hcd)
- {
- usb_dbg_uart_data_t uart = {.d32 = 0 };
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD SUSPEND\n");
- uart.d32 = DWC_READ_REG32(&hcd->core_if->usb_peri_reg->dbg_uart);
- uart.b.set_iddq = 0;
- DWC_WRITE_REG32(&hcd->core_if->usb_peri_reg->dbg_uart,uart.d32);
- return 0;
- }
- int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
- dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
- int atomic_alloc)
- {
- dwc_irqflags_t flags;
- int retval = 0;
- int bulk_not_asap = 0;
- dwc_otg_qtd_t *qtd;
- gintmsk_data_t intr_mask = {.d32 = 0 };
- if (!hcd->flags.b.port_connect_status) {
- /* No longer connected. */
- DWC_ERROR("Not connected\n");
- return -DWC_E_NO_DEVICE;
- }
- if((dwc_otg_urb->pipe_info.pipe_type == UE_BULK)
- && !(dwc_otg_urb->flags & URB_GIVEBACK_ASAP))
- bulk_not_asap = 1;
-
- qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
- if (qtd == NULL) {
- DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
- retval = -DWC_E_NO_MEMORY;
- goto OUT;
- }
- retval =
- dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
- if (retval < 0) {
- DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
- "Error status %d\n", retval);
- dwc_otg_hcd_qtd_free(qtd);
- }
-
- intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
- if (!intr_mask.b.sofintr && retval == 0) {
- dwc_otg_transaction_type_e tr_type;
- if (bulk_not_asap) {
- /* Do not schedule SG transcations until qtd has URB_GIVEBACK_ASAP set */
- retval = 0;
- goto OUT;
- }
- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
- tr_type = dwc_otg_hcd_select_transactions(hcd);
- if (tr_type != DWC_OTG_TRANSACTION_NONE) {
- dwc_otg_hcd_queue_transactions(hcd, tr_type);
- }
- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
- }
-
- OUT:
- return retval;
- }
- int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
- dwc_otg_hcd_urb_t * dwc_otg_urb)
- {
- dwc_otg_qh_t *qh;
- dwc_otg_qtd_t *urb_qtd;
- urb_qtd = dwc_otg_urb->qtd;
- if(urb_qtd && urb_qtd->qh)
- qh = urb_qtd->qh;
- else{
- DWC_ERROR("DWC OTG HCD URB Dequeue.NO QTD\n");
- return 0;
- }
- #ifdef DEBUG
- if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
- if (urb_qtd->in_process) {
- dump_channel_info(hcd, qh);
- }
- }
- #endif
- if (urb_qtd->in_process && qh->channel) {
- /* The QTD is in process (it has been assigned to a channel). */
- if (hcd->flags.b.port_connect_status) {
- /*
- * If still connected (i.e. in host mode), halt the
- * channel so it can be used for other transfers. If
- * no longer connected, the host registers can't be
- * written to halt the channel since the core is in
- * device mode.
- */
- dwc_otg_hc_halt(hcd->core_if, qh->channel,
- DWC_OTG_HC_XFER_URB_DEQUEUE);
- }
- }
- /*
- * Free the QTD and clean up the associated QH. Leave the QH in the
- * schedule if it has any remaining QTDs.
- */
- if (!hcd->core_if->dma_desc_enable) {
- uint8_t b = urb_qtd->in_process;
- dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
- if (b) {
- dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
- qh->channel = NULL;
- } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
- dwc_otg_hcd_qh_remove(hcd, qh);
- }
- } else {
- dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
- }
- return 0;
- }
- int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
- int retry)
- {
- dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
- int retval = 0;
- dwc_irqflags_t flags;
- if (retry < 0) {
- retval = -DWC_E_INVALID;
- goto done;
- }
- if (!qh) {
- retval = -DWC_E_INVALID;
- goto done;
- }
- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
- while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
- retry--;
- dwc_msleep(5);
- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
- }
- dwc_otg_hcd_qh_remove(hcd, qh);
- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
- /*
- * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
- * and qh_free to prevent stack dump on DWC_DMA_FREE() with
- * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
- * and dwc_otg_hcd_frame_list_alloc().
- */
- dwc_otg_hcd_qh_free(hcd, qh);
- done:
- return retval;
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
- int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
- {
- int retval = 0;
- dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
- if (!qh)
- return -DWC_E_INVALID;
- qh->data_toggle = DWC_OTG_HC_PID_DATA0;
- return retval;
- }
- #endif
- /**
- * HCD Callback structure for handling mode switching.
- */
- static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
- .start = dwc_otg_hcd_start_cb,
- .stop = dwc_otg_hcd_stop_cb,
- .disconnect = dwc_otg_hcd_disconnect_cb,
- .session_start = dwc_otg_hcd_session_start_cb,
- .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
- #ifdef CONFIG_USB_DWC_OTG_LPM
- .sleep = dwc_otg_hcd_sleep_cb,
- #endif
- };
- /**
- * Reset tasklet function
- */
- static void reset_tasklet_func(void *data)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
- dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
- hprt0_data_t hprt0;
- DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtrst = 1;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- dwc_mdelay(60);
- hprt0.b.prtrst = 0;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- dwc_otg_hcd->flags.b.port_reset_change = 1;
- }
- static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
- {
- dwc_list_link_t *item;
- dwc_otg_qh_t *qh;
- dwc_irqflags_t flags;
- if (!qh_list->next) {
- /* The list hasn't been initialized yet. */
- return;
- }
- /*
- * Hold spinlock here. Not needed in that case if bellow
- * function is being called from ISR
- */
- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
- /* Ensure there are no QTDs or URBs left. */
- kill_urbs_in_qh_list(hcd, qh_list);
- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
- DWC_LIST_FOREACH(item, qh_list) {
- qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
- dwc_otg_hcd_qh_remove_and_free(hcd, qh);
- }
- }
- /**
- * Exit from Hibernation if Host did not detect SRP from connected SRP capable
- * Device during SRP time by host power up.
- */
- void dwc_otg_hcd_power_up(void *ptr)
- {
- gpwrdn_data_t gpwrdn = {.d32 = 0 };
- dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
- DWC_PRINTF("%s called\n", __FUNCTION__);
- if (!core_if->hibernation_suspend) {
- DWC_PRINTF("Already exited from Hibernation\n");
- return;
- }
- /* Switch on the voltage to the core */
- gpwrdn.b.pwrdnswtch = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
- dwc_udelay(10);
- /* Reset the core */
- gpwrdn.d32 = 0;
- gpwrdn.b.pwrdnrstn = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
- dwc_udelay(10);
- /* Disable power clamps */
- gpwrdn.d32 = 0;
- gpwrdn.b.pwrdnclmp = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
- /* Remove reset the core signal */
- gpwrdn.d32 = 0;
- gpwrdn.b.pwrdnrstn = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
- dwc_udelay(10);
- /* Disable PMU interrupt */
- gpwrdn.d32 = 0;
- gpwrdn.b.pmuintsel = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
- core_if->hibernation_suspend = 0;
- /* Disable PMU */
- gpwrdn.d32 = 0;
- gpwrdn.b.pmuactv = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
- dwc_udelay(10);
- /* Enable VBUS */
- gpwrdn.d32 = 0;
- gpwrdn.b.dis_vbus = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
- core_if->op_state = A_HOST;
- dwc_otg_core_init(core_if);
- dwc_otg_enable_global_interrupts(core_if);
- cil_hcd_start(core_if);
- }
- /**
- * Frees secondary storage associated with the dwc_otg_hcd structure contained
- * in the struct usb_hcd field.
- */
- static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
- {
- int i;
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
- del_timers(dwc_otg_hcd);
- /* Free memory for QH/QTD lists */
- qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
- qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
- qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
- qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
- qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
- qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
- /* Free memory for the host channels. */
- for (i = 0; i < MAX_EPS_CHANNELS; i++) {
- dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
- #ifdef DEBUG
- if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
- DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
- }
- #endif
- if (hc != NULL) {
- DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
- i, hc);
- DWC_FREE(hc);
- }
- }
- if (dwc_otg_hcd->core_if->dma_enable) {
- if (dwc_otg_hcd->status_buf_dma) {
- DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
- dwc_otg_hcd->status_buf,
- dwc_otg_hcd->status_buf_dma);
- }
- } else if (dwc_otg_hcd->status_buf != NULL) {
- DWC_FREE(dwc_otg_hcd->status_buf);
- }
- DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
- /* Set core_if's lock pointer to NULL */
- dwc_otg_hcd->core_if->lock = NULL;
- DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
- DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
- #ifdef DWC_DEV_SRPCAP
- if (dwc_otg_hcd->core_if->power_down == 2 &&
- dwc_otg_hcd->core_if->pwron_timer) {
- DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
- }
- #endif
- DWC_FREE(dwc_otg_hcd);
- }
- int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
- {
- int retval = 0;
- int num_channels;
- int i;
- dwc_hc_t *channel;
- hcd->lock = DWC_SPINLOCK_ALLOC();
- if (!hcd->lock) {
- DWC_ERROR("Could not allocate lock for pcd");
- DWC_FREE(hcd);
- retval = -DWC_E_NO_MEMORY;
- goto out;
- }
- hcd->core_if = core_if;
- /* Register the HCD CIL Callbacks */
- dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
- &hcd_cil_callbacks, hcd);
- /* Initialize the non-periodic schedule. */
- DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
- DWC_LIST_INIT(&hcd->non_periodic_sched_active);
- /* Initialize the periodic schedule. */
- DWC_LIST_INIT(&hcd->periodic_sched_inactive);
- DWC_LIST_INIT(&hcd->periodic_sched_ready);
- DWC_LIST_INIT(&hcd->periodic_sched_assigned);
- DWC_LIST_INIT(&hcd->periodic_sched_queued);
- /*
- * Create a host channel descriptor for each host channel implemented
- * in the controller. Initialize the channel descriptor array.
- */
- DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
- num_channels = hcd->core_if->core_params->host_channels;
- DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
- for (i = 0; i < num_channels; i++) {
- channel = DWC_ALLOC(sizeof(dwc_hc_t));
- if (channel == NULL) {
- retval = -DWC_E_NO_MEMORY;
- DWC_ERROR("%s: host channel allocation failed\n",
- __func__);
- dwc_otg_hcd_free(hcd);
- goto out;
- }
- channel->hc_num = i;
- hcd->hc_ptr_array[i] = channel;
- #ifdef DEBUG
- hcd->core_if->hc_xfer_timer[i] =
- DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
- &hcd->core_if->hc_xfer_info[i]);
- #endif
- DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
- channel);
- }
- /* Initialize the Connection timeout timer. */
- hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
- dwc_otg_hcd_connect_timeout, 0);
- /* Initialize reset tasklet. */
- hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
- #ifdef DWC_DEV_SRPCAP
- if (hcd->core_if->power_down == 2) {
- /* Initialize Power on timer for Host power up in case hibernation */
- hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
- dwc_otg_hcd_power_up, core_if);
- }
- #endif
- /*
- * Allocate space for storing data on status transactions. Normally no
- * data is sent, but this space acts as a bit bucket. This must be
- * done after usb_add_hcd since that function allocates the DMA buffer
- * pool.
- */
- if (hcd->core_if->dma_enable) {
- hcd->status_buf =
- DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
- &hcd->status_buf_dma);
- } else {
- hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
- }
- if (!hcd->status_buf) {
- retval = -DWC_E_NO_MEMORY;
- DWC_ERROR("%s: status_buf allocation failed\n", __func__);
- dwc_otg_hcd_free(hcd);
- goto out;
- }
- hcd->otg_port = 1;
- hcd->frame_list = NULL;
- hcd->frame_list_dma = 0;
- hcd->periodic_qh_count = 0;
- out:
- return retval;
- }
- void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
- {
- /* Turn off all host-specific interrupts. */
- dwc_otg_disable_host_interrupts(hcd->core_if);
- dwc_otg_hcd_free(hcd);
- }
- /**
- * Initializes dynamic portions of the DWC_otg HCD state.
- */
- static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
- {
- int num_channels;
- int i;
- dwc_hc_t *channel;
- dwc_hc_t *channel_tmp;
- hcd->flags.d32 = 0;
- hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
- hcd->non_periodic_channels = 0;
- hcd->periodic_channels = 0;
- /*
- * Put all channels in the free channel list and clean up channel
- * states.
- */
- DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
- &hcd->free_hc_list, hc_list_entry) {
- DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
- }
- num_channels = hcd->core_if->core_params->host_channels;
- for (i = 0; i < num_channels; i++) {
- channel = hcd->hc_ptr_array[i];
- DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
- hc_list_entry);
- dwc_otg_hc_cleanup(hcd->core_if, channel);
- }
- /* Initialize the DWC core for host mode operation. */
- dwc_otg_core_host_init(hcd->core_if);
- /* Set core_if's lock pointer to the hcd->lock */
- hcd->core_if->lock = hcd->lock;
- }
- /**
- * Assigns transactions from a QTD to a free host channel and initializes the
- * host channel to perform the transactions. The host channel is removed from
- * the free list.
- *
- * @param hcd The HCD state structure.
- * @param qh Transactions from the first QTD for this QH are selected and
- * assigned to a free host channel.
- */
- static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
- {
- dwc_hc_t *hc;
- dwc_otg_qtd_t *qtd;
- dwc_otg_hcd_urb_t *urb;
- void* ptr = NULL;
- DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, hcd, qh);
- hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
- /* Remove the host channel from the free list. */
- DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
- qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
- urb = qtd->urb;
- qh->channel = hc;
- qtd->in_process = 1;
- /*
- * Use usb_pipedevice to determine device address. This address is
- * 0 before the SET_ADDRESS command and the correct address afterward.
- */
- hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
- hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
- hc->speed = qh->dev_speed;
- hc->max_packet = dwc_max_packet(qh->maxp);
- hc->xfer_started = 0;
- hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
- hc->error_state = (qtd->error_count > 0);
- hc->halt_on_queue = 0;
- hc->halt_pending = 0;
- hc->requests = 0;
- /*
- * The following values may be modified in the transfer type section
- * below. The xfer_len value may be reduced when the transfer is
- * started to accommodate the max widths of the XferSize and PktCnt
- * fields in the HCTSIZn register.
- */
- hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
- if (hc->ep_is_in) {
- hc->do_ping = 0;
- } else {
- hc->do_ping = qh->ping_state;
- }
- hc->data_pid_start = qh->data_toggle;
- hc->multi_count = 1;
- if (hcd->core_if->dma_enable) {
- hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
- /* For non-dword aligned case */
- if (((unsigned long)hc->xfer_buff & 0x3)
- && !hcd->core_if->dma_desc_enable) {
- ptr = (uint8_t *) urb->buf + urb->actual_length;
- }
- } else {
- hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
- }
- hc->xfer_len = urb->length - urb->actual_length;
- hc->xfer_count = 0;
- /*
- * Set the split attributes
- */
- hc->do_split = 0;
- if (qh->do_split) {
- uint32_t hub_addr, port_addr;
- hc->do_split = 1;
- hc->xact_pos = qtd->isoc_split_pos;
- hc->complete_split = qtd->complete_split;
- hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
- hc->hub_addr = (uint8_t) hub_addr;
- hc->port_addr = (uint8_t) port_addr;
- }
- switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
- case UE_CONTROL:
- hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
- switch (qtd->control_phase) {
- case DWC_OTG_CONTROL_SETUP:
- DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
- hc->do_ping = 0;
- hc->ep_is_in = 0;
- hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
- if (hcd->core_if->dma_enable) {
- hc->xfer_buff = (uint8_t *) urb->setup_dma;
- } else {
- hc->xfer_buff = (uint8_t *) urb->setup_packet;
- }
- hc->xfer_len = 8;
- ptr = NULL;
- break;
- case DWC_OTG_CONTROL_DATA:
- DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
- hc->data_pid_start = qtd->data_toggle;
- break;
- case DWC_OTG_CONTROL_STATUS:
- /*
- * Direction is opposite of data direction or IN if no
- * data.
- */
- DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
- if (urb->length == 0) {
- hc->ep_is_in = 1;
- } else {
- hc->ep_is_in =
- dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
- }
- if (hc->ep_is_in) {
- hc->do_ping = 0;
- }
- hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
- hc->xfer_len = 0;
- if (hcd->core_if->dma_enable) {
- hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
- } else {
- hc->xfer_buff = (uint8_t *) hcd->status_buf;
- }
- ptr = NULL;
- break;
- }
- break;
- case UE_BULK:
- hc->ep_type = DWC_OTG_EP_TYPE_BULK;
- break;
- case UE_INTERRUPT:
- hc->ep_type = DWC_OTG_EP_TYPE_INTR;
- break;
- case UE_ISOCHRONOUS:
- {
- struct dwc_otg_hcd_iso_packet_desc *frame_desc;
- hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
- if (hcd->core_if->dma_desc_enable)
- break;
- frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
- frame_desc->status = 0;
- if (hcd->core_if->dma_enable) {
- hc->xfer_buff = (uint8_t *) urb->dma;
- } else {
- hc->xfer_buff = (uint8_t *) urb->buf;
- }
- hc->xfer_buff +=
- frame_desc->offset + qtd->isoc_split_offset;
- hc->xfer_len =
- frame_desc->length - qtd->isoc_split_offset;
- /* For non-dword aligned buffers */
- if (((unsigned long)hc->xfer_buff & 0x3)
- && hcd->core_if->dma_enable) {
- ptr =
- (uint8_t *) urb->buf + frame_desc->offset +
- qtd->isoc_split_offset;
- } else
- ptr = NULL;
- if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
- if (hc->xfer_len <= 188) {
- hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
- } else {
- hc->xact_pos =
- DWC_HCSPLIT_XACTPOS_BEGIN;
- }
- }
- }
- break;
- }
- /* non DWORD-aligned buffer case */
- if (ptr) {
- uint32_t buf_size;
- if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
- buf_size = hcd->core_if->core_params->max_transfer_size;
- } else {
- buf_size = 4096;
- }
- if (!qh->dw_align_buf) {
- qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
- &qh->dw_align_buf_dma);
- if (!qh->dw_align_buf) {
- DWC_ERROR
- ("%s: Failed to allocate memory to handle "
- "non-dword aligned buffer case\n",
- __func__);
- return;
- }
- }
- if (!hc->ep_is_in) {
- dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
- }
- hc->align_buff = qh->dw_align_buf_dma;
- } else {
- hc->align_buff = 0;
- }
- if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
- hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
- /*
- * This value may be modified when the transfer is started to
- * reflect the actual transfer length.
- */
- hc->multi_count = dwc_hb_mult(qh->maxp);
- }
- if (hcd->core_if->dma_desc_enable)
- hc->desc_list_addr = qh->desc_list_dma;
- dwc_otg_hc_init(hcd->core_if, hc);
- hc->qh = qh;
- }
- /**
- * This function selects transactions from the HCD transfer schedule and
- * assigns them to available host channels. It is called from HCD interrupt
- * handler functions.
- *
- * @param hcd The HCD state structure.
- *
- * @return The types of new transactions that were assigned to host channels.
- */
- dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
- {
- dwc_list_link_t *qh_ptr;
- dwc_otg_qh_t *qh;
- int num_channels;
- dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
- #ifdef DEBUG_SOF
- DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
- #endif
- /* Process entries in the periodic ready list. */
- qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
- while (qh_ptr != &hcd->periodic_sched_ready &&
- !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
- qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
- assign_and_init_hc(hcd, qh);
- /*
- * Move the QH from the periodic ready schedule to the
- * periodic assigned schedule.
- */
- qh_ptr = DWC_LIST_NEXT(qh_ptr);
- DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
- &qh->qh_list_entry);
- ret_val = DWC_OTG_TRANSACTION_PERIODIC;
- }
- /*
- * Process entries in the inactive portion of the non-periodic
- * schedule. Some free host channels may not be used if they are
- * reserved for periodic transfers.
- */
- qh_ptr = hcd->non_periodic_sched_inactive.next;
- num_channels = hcd->core_if->core_params->host_channels;
- while (qh_ptr != &hcd->non_periodic_sched_inactive &&
- (hcd->non_periodic_channels <
- num_channels - hcd->periodic_channels) &&
- !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
- qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
- assign_and_init_hc(hcd, qh);
- /*
- * Move the QH from the non-periodic inactive schedule to the
- * non-periodic active schedule.
- */
- qh_ptr = DWC_LIST_NEXT(qh_ptr);
- DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
- &qh->qh_list_entry);
- if (ret_val == DWC_OTG_TRANSACTION_NONE) {
- ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
- } else {
- ret_val = DWC_OTG_TRANSACTION_ALL;
- }
- hcd->non_periodic_channels++;
- }
- return ret_val;
- }
- /**
- * Attempts to queue a single transaction request for a host channel
- * associated with either a periodic or non-periodic transfer. This function
- * assumes that there is space available in the appropriate request queue. For
- * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
- * is available in the appropriate Tx FIFO.
- *
- * @param hcd The HCD state structure.
- * @param hc Host channel descriptor associated with either a periodic or
- * non-periodic transfer.
- * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
- * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
- * transfers.
- *
- * @return 1 if a request is queued and more requests may be needed to
- * complete the transfer, 0 if no more requests are required for this
- * transfer, -1 if there is insufficient space in the Tx FIFO.
- */
- static int queue_transaction(dwc_otg_hcd_t * hcd,
- dwc_hc_t * hc, uint16_t fifo_dwords_avail)
- {
- int retval;
- if (hcd->core_if->dma_enable) {
- if (hcd->core_if->dma_desc_enable) {
- if (!hc->xfer_started
- || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
- dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
- hc->qh->ping_state = 0;
- }
- } else if (!hc->xfer_started) {
- dwc_otg_hc_start_transfer(hcd->core_if, hc);
- hc->qh->ping_state = 0;
- }
- retval = 0;
- } else if (hc->halt_pending) {
- /* Don't queue a request if the channel has been halted. */
- retval = 0;
- } else if (hc->halt_on_queue) {
- dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
- retval = 0;
- } else if (hc->do_ping) {
- if (!hc->xfer_started) {
- dwc_otg_hc_start_transfer(hcd->core_if, hc);
- }
- retval = 0;
- } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
- if ((fifo_dwords_avail * 4) >= hc->max_packet) {
- if (!hc->xfer_started) {
- dwc_otg_hc_start_transfer(hcd->core_if, hc);
- retval = 1;
- } else {
- retval =
- dwc_otg_hc_continue_transfer(hcd->core_if,
- hc);
- }
- } else {
- retval = -1;
- }
- } else {
- if (!hc->xfer_started) {
- dwc_otg_hc_start_transfer(hcd->core_if, hc);
- retval = 1;
- } else {
- retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
- }
- }
- return retval;
- }
- /**
- * Processes periodic channels for the next frame and queues transactions for
- * these channels to the DWC_otg controller. After queueing transactions, the
- * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
- * to queue as Periodic Tx FIFO or request queue space becomes available.
- * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
- */
- static void process_periodic_channels(dwc_otg_hcd_t * hcd)
- {
- hptxsts_data_t tx_status;
- dwc_list_link_t *qh_ptr;
- dwc_otg_qh_t *qh;
- int status;
- int no_queue_space = 0;
- int no_fifo_space = 0;
- dwc_otg_host_global_regs_t *host_regs;
- host_regs = hcd->core_if->host_if->host_global_regs;
- DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
- #ifdef DEBUG
- tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
- DWC_DEBUGPL(DBG_HCDV,
- " P Tx Req Queue Space Avail (before queue): %d\n",
- tx_status.b.ptxqspcavail);
- DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
- tx_status.b.ptxfspcavail);
- #endif
- qh_ptr = hcd->periodic_sched_assigned.next;
- while (qh_ptr != &hcd->periodic_sched_assigned) {
- tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
- if (tx_status.b.ptxqspcavail == 0) {
- no_queue_space = 1;
- break;
- }
- qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
- /*
- * Set a flag if we're queuing high-bandwidth in slave mode.
- * The flag prevents any halts to get into the request queue in
- * the middle of multiple high-bandwidth packets getting queued.
- */
- if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
- hcd->core_if->queuing_high_bandwidth = 1;
- }
- status =
- queue_transaction(hcd, qh->channel,
- tx_status.b.ptxfspcavail);
- if (status < 0) {
- no_fifo_space = 1;
- break;
- }
- /*
- * In Slave mode, stay on the current transfer until there is
- * nothing more to do or the high-bandwidth request count is
- * reached. In DMA mode, only need to queue one request. The
- * controller automatically handles multiple packets for
- * high-bandwidth transfers.
- */
- if (hcd->core_if->dma_enable || status == 0 ||
- qh->channel->requests == qh->channel->multi_count) {
- qh_ptr = qh_ptr->next;
- /*
- * Move the QH from the periodic assigned schedule to
- * the periodic queued schedule.
- */
- DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
- &qh->qh_list_entry);
- /* done queuing high bandwidth */
- hcd->core_if->queuing_high_bandwidth = 0;
- }
- }
- if (!hcd->core_if->dma_enable) {
- dwc_otg_core_global_regs_t *global_regs;
- gintmsk_data_t intr_mask = {.d32 = 0 };
- global_regs = hcd->core_if->core_global_regs;
- intr_mask.b.ptxfempty = 1;
- #ifdef DEBUG
- tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
- DWC_DEBUGPL(DBG_HCDV,
- " P Tx Req Queue Space Avail (after queue): %d\n",
- tx_status.b.ptxqspcavail);
- DWC_DEBUGPL(DBG_HCDV,
- " P Tx FIFO Space Avail (after queue): %d\n",
- tx_status.b.ptxfspcavail);
- #endif
- if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
- no_queue_space || no_fifo_space) {
- /*
- * May need to queue more transactions as the request
- * queue or Tx FIFO empties. Enable the periodic Tx
- * FIFO empty interrupt. (Always use the half-empty
- * level to ensure that new requests are loaded as
- * soon as possible.)
- */
- DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
- intr_mask.d32);
- } else {
- /*
- * Disable the Tx FIFO empty interrupt since there are
- * no more transactions that need to be queued right
- * now. This function is called from interrupt
- * handlers to queue more transactions as transfer
- * states change.
- */
- DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
- 0);
- }
- }
- }
- /**
- * Processes active non-periodic channels and queues transactions for these
- * channels to the DWC_otg controller. After queueing transactions, the NP Tx
- * FIFO Empty interrupt is enabled if there are more transactions to queue as
- * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
- * FIFO Empty interrupt is disabled.
- */
- static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
- {
- gnptxsts_data_t tx_status;
- dwc_list_link_t *orig_qh_ptr;
- dwc_otg_qh_t *qh;
- int status;
- int no_queue_space = 0;
- int no_fifo_space = 0;
- int more_to_do = 0;
- dwc_otg_core_global_regs_t *global_regs =
- hcd->core_if->core_global_regs;
- DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
- #ifdef DEBUG
- tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
- DWC_DEBUGPL(DBG_HCDV,
- " NP Tx Req Queue Space Avail (before queue): %d\n",
- tx_status.b.nptxqspcavail);
- DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
- tx_status.b.nptxfspcavail);
- #endif
- /*
- * Keep track of the starting point. Skip over the start-of-list
- * entry.
- */
- if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
- hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
- }
- orig_qh_ptr = hcd->non_periodic_qh_ptr;
- /*
- * Process once through the active list or until no more space is
- * available in the request queue or the Tx FIFO.
- */
- do {
- tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
- if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
- no_queue_space = 1;
- break;
- }
- qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
- qh_list_entry);
- status =
- queue_transaction(hcd, qh->channel,
- tx_status.b.nptxfspcavail);
- if (status > 0) {
- more_to_do = 1;
- } else if (status < 0) {
- no_fifo_space = 1;
- break;
- }
- /* Advance to next QH, skipping start-of-list entry. */
- hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
- if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
- hcd->non_periodic_qh_ptr =
- hcd->non_periodic_qh_ptr->next;
- }
- } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
- if (!hcd->core_if->dma_enable) {
- gintmsk_data_t intr_mask = {.d32 = 0 };
- intr_mask.b.nptxfempty = 1;
- #ifdef DEBUG
- tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
- DWC_DEBUGPL(DBG_HCDV,
- " NP Tx Req Queue Space Avail (after queue): %d\n",
- tx_status.b.nptxqspcavail);
- DWC_DEBUGPL(DBG_HCDV,
- " NP Tx FIFO Space Avail (after queue): %d\n",
- tx_status.b.nptxfspcavail);
- #endif
- if (more_to_do || no_queue_space || no_fifo_space) {
- /*
- * May need to queue more transactions as the request
- * queue or Tx FIFO empties. Enable the non-periodic
- * Tx FIFO empty interrupt. (Always use the half-empty
- * level to ensure that new requests are loaded as
- * soon as possible.)
- */
- DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
- intr_mask.d32);
- } else {
- /*
- * Disable the Tx FIFO empty interrupt since there are
- * no more transactions that need to be queued right
- * now. This function is called from interrupt
- * handlers to queue more transactions as transfer
- * states change.
- */
- DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
- 0);
- }
- }
- }
- /**
- * This function processes the currently active host channels and queues
- * transactions for these channels to the DWC_otg controller. It is called
- * from HCD interrupt handler functions.
- *
- * @param hcd The HCD state structure.
- * @param tr_type The type(s) of transactions to queue (non-periodic,
- * periodic, or both).
- */
- void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
- dwc_otg_transaction_type_e tr_type)
- {
- #ifdef DEBUG_SOF
- DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
- #endif
- /* Process host channels associated with periodic transfers. */
- if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
- tr_type == DWC_OTG_TRANSACTION_ALL) &&
- !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
- process_periodic_channels(hcd);
- }
- /* Process host channels associated with non-periodic transfers. */
- if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
- tr_type == DWC_OTG_TRANSACTION_ALL) {
- if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
- process_non_periodic_channels(hcd);
- } else {
- /*
- * Ensure NP Tx FIFO empty interrupt is disabled when
- * there are no non-periodic transfers to process.
- */
- gintmsk_data_t gintmsk = {.d32 = 0 };
- gintmsk.b.nptxfempty = 1;
- DWC_MODIFY_REG32(&hcd->core_if->
- core_global_regs->gintmsk, gintmsk.d32,
- 0);
- }
- }
- }
- #ifdef DWC_HS_ELECT_TST
- /*
- * Quick and dirty hack to implement the HS Electrical Test
- * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
- *
- * This code was copied from our userspace app "hset". It sends a
- * Get Device Descriptor control sequence in two parts, first the
- * Setup packet by itself, followed some time later by the In and
- * Ack packets. Rather than trying to figure out how to add this
- * functionality to the normal driver code, we just hijack the
- * hardware, using these two function to drive the hardware
- * directly.
- */
- static dwc_otg_core_global_regs_t *global_regs;
- static dwc_otg_host_global_regs_t *hc_global_regs;
- static dwc_otg_hc_regs_t *hc_regs;
- static uint32_t *data_fifo;
- static void do_setup(void)
- {
- gintsts_data_t gintsts;
- hctsiz_data_t hctsiz;
- hcchar_data_t hcchar;
- haint_data_t haint;
- hcint_data_t hcint;
- /* Enable HAINTs */
- DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
- /* Enable HCINTs */
- DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /*
- * Send Setup packet (Get Device Descriptor)
- */
- /* Make sure channel is disabled */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- if (hcchar.b.chen) {
- hcchar.b.chdis = 1;
- // hcchar.b.chen = 1;
- DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
- //sleep(1);
- dwc_mdelay(1000);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- }
- /* Set HCTSIZ */
- hctsiz.d32 = 0;
- hctsiz.b.xfersize = 8;
- hctsiz.b.pktcnt = 1;
- hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
- DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
- /* Set HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
- hcchar.b.epdir = 0;
- hcchar.b.epnum = 0;
- hcchar.b.mps = 8;
- hcchar.b.chen = 1;
- DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
- /* Fill FIFO with Setup data for Get Device Descriptor */
- data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
- DWC_WRITE_REG32(data_fifo++, 0x01000680);
- DWC_WRITE_REG32(data_fifo++, 0x00080000);
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Wait for host channel interrupt */
- do {
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- } while (gintsts.b.hcintr == 0);
- /* Disable HCINTs */
- DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
- /* Disable HAINTs */
- DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- }
- static void do_in_ack(void)
- {
- gintsts_data_t gintsts;
- hctsiz_data_t hctsiz;
- hcchar_data_t hcchar;
- haint_data_t haint;
- hcint_data_t hcint;
- host_grxsts_data_t grxsts;
- /* Enable HAINTs */
- DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
- /* Enable HCINTs */
- DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /*
- * Receive Control In packet
- */
- /* Make sure channel is disabled */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- if (hcchar.b.chen) {
- hcchar.b.chdis = 1;
- hcchar.b.chen = 1;
- DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
- //sleep(1);
- dwc_mdelay(1000);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- }
- /* Set HCTSIZ */
- hctsiz.d32 = 0;
- hctsiz.b.xfersize = 8;
- hctsiz.b.pktcnt = 1;
- hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
- DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
- /* Set HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
- hcchar.b.epdir = 1;
- hcchar.b.epnum = 0;
- hcchar.b.mps = 8;
- hcchar.b.chen = 1;
- DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Wait for receive status queue interrupt */
- do {
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- } while (gintsts.b.rxstsqlvl == 0);
- /* Read RXSTS */
- grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
- /* Clear RXSTSQLVL in GINTSTS */
- gintsts.d32 = 0;
- gintsts.b.rxstsqlvl = 1;
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- switch (grxsts.b.pktsts) {
- case DWC_GRXSTS_PKTSTS_IN:
- /* Read the data into the host buffer */
- if (grxsts.b.bcnt > 0) {
- int i;
- int word_count = (grxsts.b.bcnt + 3) / 4;
- data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
- for (i = 0; i < word_count; i++) {
- (void)DWC_READ_REG32(data_fifo++);
- }
- }
- break;
- default:
- break;
- }
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Wait for receive status queue interrupt */
- do {
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- } while (gintsts.b.rxstsqlvl == 0);
- /* Read RXSTS */
- grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
- /* Clear RXSTSQLVL in GINTSTS */
- gintsts.d32 = 0;
- gintsts.b.rxstsqlvl = 1;
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- switch (grxsts.b.pktsts) {
- case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
- break;
- default:
- break;
- }
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Wait for host channel interrupt */
- do {
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- } while (gintsts.b.hcintr == 0);
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- // usleep(100000);
- // mdelay(100);
- dwc_mdelay(1);
- /*
- * Send handshake packet
- */
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Make sure channel is disabled */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- if (hcchar.b.chen) {
- hcchar.b.chdis = 1;
- hcchar.b.chen = 1;
- DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
- //sleep(1);
- dwc_mdelay(1000);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- }
- /* Set HCTSIZ */
- hctsiz.d32 = 0;
- hctsiz.b.xfersize = 0;
- hctsiz.b.pktcnt = 1;
- hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
- DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
- /* Set HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
- hcchar.b.epdir = 0;
- hcchar.b.epnum = 0;
- hcchar.b.mps = 8;
- hcchar.b.chen = 1;
- DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- /* Wait for host channel interrupt */
- do {
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- } while (gintsts.b.hcintr == 0);
- /* Disable HCINTs */
- DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
- /* Disable HAINTs */
- DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
- /* Read HAINT */
- haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
- /* Read HCINT */
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
- /* Read HCCHAR */
- hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
- /* Clear HCINT */
- DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
- /* Clear HAINT */
- DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
- /* Clear GINTSTS */
- DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
- /* Read GINTSTS */
- gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
- }
- #endif
- /** Handles hub class-specific requests. */
- int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
- uint16_t typeReq,
- uint16_t wValue,
- uint16_t wIndex, uint8_t * buf, uint16_t wLength)
- {
- int retval = 0;
- dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
- usb_hub_descriptor_t *hub_desc;
- hprt0_data_t hprt0 = {.d32 = 0 };
- uint32_t port_status;
- switch (typeReq) {
- case UCR_CLEAR_HUB_FEATURE:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearHubFeature 0x%x\n", wValue);
- switch (wValue) {
- case UHF_C_HUB_LOCAL_POWER:
- case UHF_C_HUB_OVER_CURRENT:
- /* Nothing required here */
- break;
- default:
- retval = -DWC_E_INVALID;
- DWC_ERROR("DWC OTG HCD - "
- "ClearHubFeature request %xh unknown\n",
- wValue);
- }
- break;
- case UCR_CLEAR_PORT_FEATURE:
- #ifdef CONFIG_USB_DWC_OTG_LPM
- if (wValue != UHF_PORT_L1)
- #endif
- if (!wIndex || wIndex > 1)
- goto error;
- switch (wValue) {
- case UHF_PORT_ENABLE:
- DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtena = 1;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- break;
- case UHF_PORT_SUSPEND:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
- if (core_if->power_down == 2) {
- dwc_otg_host_hibernation_restore(core_if, 0, 0);
- } else {
- DWC_WRITE_REG32(core_if->pcgcctl, 0);
- dwc_mdelay(5);
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtres = 1;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- hprt0.b.prtsusp = 0;
- /* Clear Resume bit */
- dwc_mdelay(100);
- hprt0.b.prtres = 0;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- }
- break;
- #ifdef CONFIG_USB_DWC_OTG_LPM
- case UHF_PORT_L1:
- {
- pcgcctl_data_t pcgcctl = {.d32 = 0 };
- glpmcfg_data_t lpmcfg = {.d32 = 0 };
- lpmcfg.d32 =
- DWC_READ_REG32(&core_if->
- core_global_regs->glpmcfg);
- lpmcfg.b.en_utmi_sleep = 0;
- lpmcfg.b.hird_thres &= (~(1 << 4));
- lpmcfg.b.prt_sleep_sts = 1;
- DWC_WRITE_REG32(&core_if->
- core_global_regs->glpmcfg,
- lpmcfg.d32);
- /* Clear Enbl_L1Gating bit. */
- pcgcctl.b.enbl_sleep_gating = 1;
- DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
- 0);
- dwc_mdelay(5);
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtres = 1;
- DWC_WRITE_REG32(core_if->host_if->hprt0,
- hprt0.d32);
- /* This bit will be cleared in wakeup interrupt handle */
- break;
- }
- #endif
- case UHF_PORT_POWER:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_POWER\n");
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtpwr = 0;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- break;
- case UHF_PORT_INDICATOR:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
- /* Port inidicator not supported */
- break;
- case UHF_C_PORT_CONNECTION:
- /* Clears drivers internal connect status change
- * flag */
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
- dwc_otg_hcd->flags.b.port_connect_status_change = 0;
- break;
- case UHF_C_PORT_RESET:
- /* Clears the driver's internal Port Reset Change
- * flag */
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
- dwc_otg_hcd->flags.b.port_reset_change = 0;
- break;
- case UHF_C_PORT_ENABLE:
- /* Clears the driver's internal Port
- * Enable/Disable Change flag */
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
- dwc_otg_hcd->flags.b.port_enable_change = 0;
- break;
- case UHF_C_PORT_SUSPEND:
- /* Clears the driver's internal Port Suspend
- * Change flag, which is set when resume signaling on
- * the host port is complete */
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
- dwc_otg_hcd->flags.b.port_suspend_change = 0;
- break;
- #ifdef CONFIG_USB_DWC_OTG_LPM
- case UHF_C_PORT_L1:
- dwc_otg_hcd->flags.b.port_l1_change = 0;
- break;
- #endif
- case UHF_C_PORT_OVER_CURRENT:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
- dwc_otg_hcd->flags.b.port_over_current_change = 0;
- break;
- default:
- retval = -DWC_E_INVALID;
- DWC_ERROR("DWC OTG HCD - "
- "ClearPortFeature request %xh "
- "unknown or unsupported\n", wValue);
- }
- break;
- case UCR_GET_HUB_DESCRIPTOR:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "GetHubDescriptor\n");
- hub_desc = (usb_hub_descriptor_t *) buf;
- hub_desc->bDescLength = 9;
- hub_desc->bDescriptorType = 0x29;
- hub_desc->bNbrPorts = 1;
- USETW(hub_desc->wHubCharacteristics, 0x08);
- hub_desc->bPwrOn2PwrGood = 1;
- hub_desc->bHubContrCurrent = 0;
- hub_desc->DeviceRemovable[0] = 0;
- hub_desc->DeviceRemovable[1] = 0xff;
- break;
- case UCR_GET_HUB_STATUS:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "GetHubStatus\n");
- DWC_MEMSET(buf, 0, 4);
- break;
- case UCR_GET_PORT_STATUS:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
- wIndex, dwc_otg_hcd->flags.d32);
- if (!wIndex || wIndex > 1)
- goto error;
- port_status = 0;
- if (dwc_otg_hcd->flags.b.port_connect_status_change)
- port_status |= (1 << UHF_C_PORT_CONNECTION);
- if (dwc_otg_hcd->flags.b.port_enable_change)
- port_status |= (1 << UHF_C_PORT_ENABLE);
- if (dwc_otg_hcd->flags.b.port_suspend_change)
- port_status |= (1 << UHF_C_PORT_SUSPEND);
- if (dwc_otg_hcd->flags.b.port_l1_change)
- port_status |= (1 << UHF_C_PORT_L1);
- if (dwc_otg_hcd->flags.b.port_reset_change) {
- port_status |= (1 << UHF_C_PORT_RESET);
- }
- if (dwc_otg_hcd->flags.b.port_over_current_change) {
- DWC_WARN("Overcurrent change detected\n");
- port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
- }
- if (!dwc_otg_hcd->flags.b.port_connect_status) {
- /*
- * The port is disconnected, which means the core is
- * either in device mode or it soon will be. Just
- * return 0's for the remainder of the port status
- * since the port register can't be read if the core
- * is in device mode.
- */
- *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
- break;
- }
- hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
- DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
- if (hprt0.b.prtconnsts)
- port_status |= (1 << UHF_PORT_CONNECTION);
- if (hprt0.b.prtena)
- port_status |= (1 << UHF_PORT_ENABLE);
- if (hprt0.b.prtsusp)
- port_status |= (1 << UHF_PORT_SUSPEND);
- if (hprt0.b.prtovrcurract)
- port_status |= (1 << UHF_PORT_OVER_CURRENT);
- if (hprt0.b.prtrst)
- port_status |= (1 << UHF_PORT_RESET);
- if (hprt0.b.prtpwr)
- port_status |= (1 << UHF_PORT_POWER);
- if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
- port_status |= (1 << UHF_PORT_HIGH_SPEED);
- else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
- port_status |= (1 << UHF_PORT_LOW_SPEED);
- if (hprt0.b.prttstctl)
- port_status |= (1 << UHF_PORT_TEST);
- if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
- port_status |= (1 << UHF_PORT_L1);
- }
- /*
- For Synopsys HW emulation of Power down wkup_control asserts the
- hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
- We intentionally tell the software that port is in L2Suspend state.
- Only for STE.
- */
- if ((core_if->power_down == 2)
- && (core_if->hibernation_suspend == 1)) {
- port_status |= (1 << UHF_PORT_SUSPEND);
- }
- /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
- *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
- break;
- case UCR_SET_HUB_FEATURE:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "SetHubFeature\n");
- /* No HUB features supported */
- break;
- case UCR_SET_PORT_FEATURE:
- if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
- goto error;
- if (!dwc_otg_hcd->flags.b.port_connect_status) {
- /*
- * The port is disconnected, which means the core is
- * either in device mode or it soon will be. Just
- * return without doing anything since the port
- * register can't be written if the core is in device
- * mode.
- */
- break;
- }
- switch (wValue) {
- case UHF_PORT_SUSPEND:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
- if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
- goto error;
- }
- if (core_if->power_down == 2) {
- int timeout = 300;
- dwc_irqflags_t flags;
- pcgcctl_data_t pcgcctl = {.d32 = 0 };
- gpwrdn_data_t gpwrdn = {.d32 = 0 };
- gusbcfg_data_t gusbcfg = {.d32 = 0 };
- #ifdef DWC_DEV_SRPCAP
- int32_t otg_cap_param = core_if->core_params->otg_cap;
- #endif
- DWC_PRINTF("Preparing for complete power-off\n");
- /* Save registers before hibernation */
- dwc_otg_save_global_regs(core_if);
- dwc_otg_save_host_regs(core_if);
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtsusp = 1;
- hprt0.b.prtena = 0;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- /* Spin hprt0.b.prtsusp to became 1 */
- do {
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- if (hprt0.b.prtsusp) {
- break;
- }
- dwc_mdelay(1);
- } while (--timeout);
- if (!timeout) {
- DWC_WARN("Suspend wasn't genereted\n");
- }
- dwc_udelay(10);
- /*
- * We need to disable interrupts to prevent servicing of any IRQ
- * during going to hibernation
- */
- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
- core_if->lx_state = DWC_OTG_L2;
- #ifdef DWC_DEV_SRPCAP
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtpwr = 0;
- hprt0.b.prtena = 0;
- DWC_WRITE_REG32(core_if->host_if->hprt0,
- hprt0.d32);
- #endif
- gusbcfg.d32 =
- DWC_READ_REG32(&core_if->core_global_regs->
- gusbcfg);
- if (gusbcfg.b.ulpi_utmi_sel == 1) {
- /* ULPI interface */
- /* Suspend the Phy Clock */
- pcgcctl.d32 = 0;
- pcgcctl.b.stoppclk = 1;
- DWC_MODIFY_REG32(core_if->pcgcctl, 0,
- pcgcctl.d32);
- dwc_udelay(10);
- gpwrdn.b.pmuactv = 1;
- DWC_MODIFY_REG32(&core_if->
- core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- } else {
- /* UTMI+ Interface */
- gpwrdn.b.pmuactv = 1;
- DWC_MODIFY_REG32(&core_if->
- core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- dwc_udelay(10);
- pcgcctl.b.stoppclk = 1;
- DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
- dwc_udelay(10);
- }
- #ifdef DWC_DEV_SRPCAP
- gpwrdn.d32 = 0;
- gpwrdn.b.dis_vbus = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- #endif
- gpwrdn.d32 = 0;
- gpwrdn.b.pmuintsel = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- dwc_udelay(10);
- gpwrdn.d32 = 0;
- #ifdef DWC_DEV_SRPCAP
- gpwrdn.b.srp_det_msk = 1;
- #endif
- gpwrdn.b.disconn_det_msk = 1;
- gpwrdn.b.lnstchng_msk = 1;
- gpwrdn.b.sts_chngint_msk = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- dwc_udelay(10);
- /* Enable Power Down Clamp and all interrupts in GPWRDN */
- gpwrdn.d32 = 0;
- gpwrdn.b.pwrdnclmp = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- dwc_udelay(10);
- /* Switch off VDD */
- gpwrdn.d32 = 0;
- gpwrdn.b.pwrdnswtch = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- #ifdef DWC_DEV_SRPCAP
- if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
- {
- core_if->pwron_timer_started = 1;
- DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
- }
- #endif
- /* Save gpwrdn register for further usage if stschng interrupt */
- core_if->gr_backup->gpwrdn_local =
- DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
- /* Set flag to indicate that we are in hibernation */
- core_if->hibernation_suspend = 1;
- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
- DWC_PRINTF("Host hibernation completed\n");
- // Exit from case statement
- break;
- }
- if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
- dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
- gotgctl_data_t gotgctl = {.d32 = 0 };
- gotgctl.b.hstsethnpen = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gotgctl, 0, gotgctl.d32);
- core_if->op_state = A_SUSPEND;
- }
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtsusp = 1;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- {
- dwc_irqflags_t flags;
- /* Update lx_state */
- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
- core_if->lx_state = DWC_OTG_L2;
- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
- }
- /* Suspend the Phy Clock */
- {
- pcgcctl_data_t pcgcctl = {.d32 = 0 };
- pcgcctl.b.stoppclk = 1;
- DWC_MODIFY_REG32(core_if->pcgcctl, 0,
- pcgcctl.d32);
- dwc_udelay(10);
- }
- /* For HNP the bus must be suspended for at least 200ms. */
- if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
- pcgcctl_data_t pcgcctl = {.d32 = 0 };
- pcgcctl.b.stoppclk = 1;
- DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
- dwc_mdelay(200);
- }
- /** @todo - check how sw can wait for 1 sec to check asesvld??? */
- #if 0 //vahrama !!!!!!!!!!!!!!!!!!
- if (core_if->adp_enable) {
- gotgctl_data_t gotgctl = {.d32 = 0 };
- gpwrdn_data_t gpwrdn;
- while (gotgctl.b.asesvld == 1) {
- gotgctl.d32 =
- DWC_READ_REG32(&core_if->
- core_global_regs->
- gotgctl);
- dwc_mdelay(100);
- }
- /* Enable Power Down Logic */
- gpwrdn.d32 = 0;
- gpwrdn.b.pmuactv = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- /* Unmask SRP detected interrupt from Power Down Logic */
- gpwrdn.d32 = 0;
- gpwrdn.b.srp_det_msk = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, 0, gpwrdn.d32);
- dwc_otg_adp_probe_start(core_if);
- }
- #endif
- break;
- case UHF_PORT_POWER:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "SetPortFeature - USB_PORT_FEAT_POWER\n");
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prtpwr = 1;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- break;
- case UHF_PORT_RESET:
- if ((core_if->power_down == 2)
- && (core_if->hibernation_suspend == 1)) {
- /* If we are going to exit from Hibernated
- * state via USB RESET.
- */
- dwc_otg_host_hibernation_restore(core_if, 0, 1);
- } else {
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- DWC_DEBUGPL(DBG_HCD,
- "DWC OTG HCD HUB CONTROL - "
- "SetPortFeature - USB_PORT_FEAT_RESET\n");
- {
- pcgcctl_data_t pcgcctl = {.d32 = 0 };
- pcgcctl.b.enbl_sleep_gating = 1;
- pcgcctl.b.stoppclk = 1;
- DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
- DWC_WRITE_REG32(core_if->pcgcctl, 0);
- }
- #ifdef CONFIG_USB_DWC_OTG_LPM
- {
- glpmcfg_data_t lpmcfg;
- lpmcfg.d32 =
- DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
- if (lpmcfg.b.prt_sleep_sts) {
- lpmcfg.b.en_utmi_sleep = 0;
- lpmcfg.b.hird_thres &= (~(1 << 4));
- DWC_WRITE_REG32
- (&core_if->core_global_regs->glpmcfg,
- lpmcfg.d32);
- dwc_mdelay(1);
- }
- }
- #endif
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- /* Clear suspend bit if resetting from suspended state. */
- hprt0.b.prtsusp = 0;
- /* When B-Host the Port reset bit is set in
- * the Start HCD Callback function, so that
- * the reset is started within 1ms of the HNP
- * success interrupt. */
- if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
- hprt0.b.prtpwr = 1;
- hprt0.b.prtrst = 1;
- DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
- DWC_WRITE_REG32(core_if->host_if->hprt0,
- hprt0.d32);
- }
- /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
- dwc_mdelay(60);
- hprt0.b.prtrst = 0;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
- }
- break;
- #ifdef DWC_HS_ELECT_TST
- case UHF_PORT_TEST:
- {
- uint32_t t;
- gintmsk_data_t gintmsk;
- t = (wIndex >> 8); /* MSB wIndex USB */
- DWC_DEBUGPL(DBG_HCD,
- "DWC OTG HCD HUB CONTROL - "
- "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
- t);
- DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
- if (t < 6) {
- hprt0.d32 = dwc_otg_read_hprt0(core_if);
- hprt0.b.prttstctl = t;
- DWC_WRITE_REG32(core_if->host_if->hprt0,
- hprt0.d32);
- } else {
- /* Setup global vars with reg addresses (quick and
- * dirty hack, should be cleaned up)
- */
- global_regs = core_if->core_global_regs;
- hc_global_regs =
- core_if->host_if->host_global_regs;
- hc_regs =
- (dwc_otg_hc_regs_t *) ((char *)
- global_regs +
- 0x500);
- data_fifo =
- (uint32_t *) ((char *)global_regs +
- 0x1000);
- if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
- /* Save current interrupt mask */
- gintmsk.d32 =
- DWC_READ_REG32
- (&global_regs->gintmsk);
- /* Disable all interrupts while we muck with
- * the hardware directly
- */
- DWC_WRITE_REG32(&global_regs->gintmsk, 0);
- /* 15 second delay per the test spec */
- dwc_mdelay(15000);
- /* Drive suspend on the root port */
- hprt0.d32 =
- dwc_otg_read_hprt0(core_if);
- hprt0.b.prtsusp = 1;
- hprt0.b.prtres = 0;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- /* 15 second delay per the test spec */
- dwc_mdelay(15000);
- /* Drive resume on the root port */
- hprt0.d32 =
- dwc_otg_read_hprt0(core_if);
- hprt0.b.prtsusp = 0;
- hprt0.b.prtres = 1;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- dwc_mdelay(100);
- /* Clear the resume bit */
- hprt0.b.prtres = 0;
- DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
- /* Restore interrupts */
- DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
- } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
- /* Save current interrupt mask */
- gintmsk.d32 =
- DWC_READ_REG32
- (&global_regs->gintmsk);
- /* Disable all interrupts while we muck with
- * the hardware directly
- */
- DWC_WRITE_REG32(&global_regs->gintmsk, 0);
- /* 15 second delay per the test spec */
- dwc_mdelay(15000);
- /* Send the Setup packet */
- do_setup();
- /* 15 second delay so nothing else happens for awhile */
- dwc_mdelay(15000);
- /* Restore interrupts */
- DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
- } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
- /* Save current interrupt mask */
- gintmsk.d32 =
- DWC_READ_REG32
- (&global_regs->gintmsk);
- /* Disable all interrupts while we muck with
- * the hardware directly
- */
- DWC_WRITE_REG32(&global_regs->gintmsk, 0);
- /* Send the Setup packet */
- do_setup();
- /* 15 second delay so nothing else happens for awhile */
- dwc_mdelay(15000);
- /* Send the In and Ack packets */
- do_in_ack();
- /* 15 second delay so nothing else happens for awhile */
- dwc_mdelay(15000);
- /* Restore interrupts */
- DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
- }
- }
- break;
- }
- #endif /* DWC_HS_ELECT_TST */
- case UHF_PORT_INDICATOR:
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
- "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
- /* Not supported */
- break;
- default:
- retval = -DWC_E_INVALID;
- DWC_ERROR("DWC OTG HCD - "
- "SetPortFeature request %xh "
- "unknown or unsupported\n", wValue);
- break;
- }
- break;
- #ifdef CONFIG_USB_DWC_OTG_LPM
- case UCR_SET_AND_TEST_PORT_FEATURE:
- if (wValue != UHF_PORT_L1) {
- goto error;
- }
- {
- int portnum, hird, devaddr, remwake;
- glpmcfg_data_t lpmcfg;
- uint32_t time_usecs;
- gintsts_data_t gintsts;
- gintmsk_data_t gintmsk;
- if (!dwc_otg_get_param_lpm_enable(core_if)) {
- goto error;
- }
- if (wValue != UHF_PORT_L1 || wLength != 1) {
- goto error;
- }
- /* Check if the port currently is in SLEEP state */
- lpmcfg.d32 =
- DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
- if (lpmcfg.b.prt_sleep_sts) {
- DWC_INFO("Port is already in sleep mode\n");
- buf[0] = 0; /* Return success */
- break;
- }
- portnum = wIndex & 0xf;
- hird = (wIndex >> 4) & 0xf;
- devaddr = (wIndex >> 8) & 0x7f;
- remwake = (wIndex >> 15);
- if (portnum != 1) {
- retval = -DWC_E_INVALID;
- DWC_WARN
- ("Wrong port number(%d) in SetandTestPortFeature request\n",
- portnum);
- break;
- }
- DWC_PRINTF
- ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
- portnum, hird, devaddr, remwake);
- /* Disable LPM interrupt */
- gintmsk.d32 = 0;
- gintmsk.b.lpmtranrcvd = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
- gintmsk.d32, 0);
- if (dwc_otg_hcd_send_lpm
- (dwc_otg_hcd, devaddr, hird, remwake)) {
- retval = -DWC_E_INVALID;
- break;
- }
- time_usecs = 10 * (lpmcfg.b.retry_count + 1);
- /* We will consider timeout if time_usecs microseconds pass,
- * and we don't receive LPM transaction status.
- * After receiving non-error responce(ACK/NYET/STALL) from device,
- * core will set lpmtranrcvd bit.
- */
- do {
- gintsts.d32 =
- DWC_READ_REG32(&core_if->core_global_regs->gintsts);
- if (gintsts.b.lpmtranrcvd) {
- break;
- }
- dwc_udelay(1);
- } while (--time_usecs);
- /* lpm_int bit will be cleared in LPM interrupt handler */
- /* Now fill status
- * 0x00 - Success
- * 0x10 - NYET
- * 0x11 - Timeout
- */
- if (!gintsts.b.lpmtranrcvd) {
- buf[0] = 0x3; /* Completion code is Timeout */
- dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
- } else {
- lpmcfg.d32 =
- DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
- if (lpmcfg.b.lpm_resp == 0x3) {
- /* ACK responce from the device */
- buf[0] = 0x00; /* Success */
- } else if (lpmcfg.b.lpm_resp == 0x2) {
- /* NYET responce from the device */
- buf[0] = 0x2;
- } else {
- /* Otherwise responce with Timeout */
- buf[0] = 0x3;
- }
- }
- DWC_PRINTF("Device responce to LPM trans is %x\n",
- lpmcfg.b.lpm_resp);
- DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
- gintmsk.d32);
- break;
- }
- #endif /* CONFIG_USB_DWC_OTG_LPM */
- default:
- error:
- retval = -DWC_E_INVALID;
- DWC_WARN("DWC OTG HCD - "
- "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
- typeReq, wIndex, wValue);
- break;
- }
- return retval;
- }
- #ifdef CONFIG_USB_DWC_OTG_LPM
- /** Returns index of host channel to perform LPM transaction. */
- int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
- {
- dwc_otg_core_if_t *core_if = hcd->core_if;
- dwc_hc_t *hc;
- hcchar_data_t hcchar;
- gintmsk_data_t gintmsk = {.d32 = 0 };
- if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
- DWC_PRINTF("No free channel to select for LPM transaction\n");
- return -1;
- }
- hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
- /* Mask host channel interrupts. */
- gintmsk.b.hcintr = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
- /* Fill fields that core needs for LPM transaction */
- hcchar.b.devaddr = devaddr;
- hcchar.b.epnum = 0;
- hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
- hcchar.b.mps = 64;
- hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
- hcchar.b.epdir = 0; /* OUT */
- DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
- hcchar.d32);
- /* Remove the host channel from the free list. */
- DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
- DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
- return hc->hc_num;
- }
- /** Release hc after performing LPM transaction */
- void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
- {
- dwc_hc_t *hc;
- glpmcfg_data_t lpmcfg;
- uint8_t hc_num;
- lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
- hc_num = lpmcfg.b.lpm_chan_index;
- hc = hcd->hc_ptr_array[hc_num];
- DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
- /* Return host channel to free list */
- DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
- }
- int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
- uint8_t bRemoteWake)
- {
- glpmcfg_data_t lpmcfg;
- pcgcctl_data_t pcgcctl = {.d32 = 0 };
- int channel;
- channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
- if (channel < 0) {
- return channel;
- }
- pcgcctl.b.enbl_sleep_gating = 1;
- DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
- /* Read LPM config register */
- lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
- /* Program LPM transaction fields */
- lpmcfg.b.rem_wkup_en = bRemoteWake;
- lpmcfg.b.hird = hird;
- lpmcfg.b.hird_thres = 0x1c;
- lpmcfg.b.lpm_chan_index = channel;
- lpmcfg.b.en_utmi_sleep = 1;
- /* Program LPM config register */
- DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
- /* Send LPM transaction */
- lpmcfg.b.send_lpm = 1;
- DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
- return 0;
- }
- #endif /* CONFIG_USB_DWC_OTG_LPM */
- int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
- {
- int retval;
- if (port != 1) {
- return -DWC_E_INVALID;
- }
- retval = (hcd->flags.b.port_connect_status_change ||
- hcd->flags.b.port_reset_change ||
- hcd->flags.b.port_enable_change ||
- hcd->flags.b.port_suspend_change ||
- hcd->flags.b.port_over_current_change);
- #ifdef DEBUG
- if (retval) {
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
- " Root port status changed\n");
- DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
- hcd->flags.b.port_connect_status_change);
- DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
- hcd->flags.b.port_reset_change);
- DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
- hcd->flags.b.port_enable_change);
- DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
- hcd->flags.b.port_suspend_change);
- DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
- hcd->flags.b.port_over_current_change);
- }
- #endif
- return retval;
- }
- int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
- {
- hfnum_data_t hfnum;
- hfnum.d32 =
- DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
- hfnum);
- #ifdef DEBUG_SOF
- DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
- hfnum.b.frnum);
- #endif
- return hfnum.b.frnum;
- }
- int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
- struct dwc_otg_hcd_function_ops *fops)
- {
- int retval = 0;
- hcd->fops = fops;
- if (!dwc_otg_is_device_mode(hcd->core_if) &&
- (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
- dwc_otg_hcd_reinit(hcd);
- } else {
- retval = -DWC_E_NO_DEVICE;
- }
- return retval;
- }
- void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
- {
- return hcd->priv;
- }
- void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
- {
- hcd->priv = priv_data;
- }
- uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
- {
- return hcd->otg_port;
- }
- uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
- {
- uint32_t is_b_host;
- if (hcd->core_if->op_state == B_HOST) {
- is_b_host = 1;
- } else {
- is_b_host = 0;
- }
- return is_b_host;
- }
- dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
- int iso_desc_count, int atomic_alloc)
- {
- dwc_otg_hcd_urb_t *dwc_otg_urb;
- uint32_t size;
- size =
- sizeof(*dwc_otg_urb) +
- iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
- if (atomic_alloc)
- dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
- else
- dwc_otg_urb = DWC_ALLOC(size);
- dwc_otg_urb->packet_count = iso_desc_count;
- return dwc_otg_urb;
- }
- void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
- uint8_t dev_addr, uint8_t ep_num,
- uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
- {
- dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
- ep_type, ep_dir, mps);
- #if 0
- DWC_PRINTF
- ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
- dev_addr, ep_num, ep_dir, ep_type, mps);
- #endif
- }
- void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
- void *urb_handle, void *buf, dwc_dma_t dma,
- uint32_t buflen, void *setup_packet,
- dwc_dma_t setup_dma, uint32_t flags,
- uint16_t interval)
- {
- dwc_otg_urb->priv = urb_handle;
- dwc_otg_urb->buf = buf;
- dwc_otg_urb->dma = dma;
- dwc_otg_urb->length = buflen;
- dwc_otg_urb->setup_packet = setup_packet;
- dwc_otg_urb->setup_dma = setup_dma;
- dwc_otg_urb->flags = flags;
- dwc_otg_urb->interval = interval;
- dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
- }
- uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
- {
- return dwc_otg_urb->status;
- }
- uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
- {
- return dwc_otg_urb->actual_length;
- }
- uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
- {
- return dwc_otg_urb->error_count;
- }
- void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
- int desc_num, uint32_t offset,
- uint32_t length)
- {
- dwc_otg_urb->iso_descs[desc_num].offset = offset;
- dwc_otg_urb->iso_descs[desc_num].length = length;
- }
- uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
- int desc_num)
- {
- return dwc_otg_urb->iso_descs[desc_num].status;
- }
- uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
- dwc_otg_urb, int desc_num)
- {
- return dwc_otg_urb->iso_descs[desc_num].actual_length;
- }
- int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
- {
- int allocated = 0;
- dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
- if (qh) {
- if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
- allocated = 1;
- }
- }
- return allocated;
- }
- int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
- {
- dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
- int freed = 0;
- DWC_ASSERT(qh, "qh is not allocated\n");
- if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
- freed = 1;
- }
- return freed;
- }
- uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
- {
- dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
- DWC_ASSERT(qh, "qh is not allocated\n");
- return qh->usecs;
- }
- void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
- {
- #ifdef DEBUG
- int num_channels;
- int i;
- gnptxsts_data_t np_tx_status;
- hptxsts_data_t p_tx_status;
- num_channels = hcd->core_if->core_params->host_channels;
- DWC_PRINTF("\n");
- DWC_PRINTF
- ("************************************************************\n");
- DWC_PRINTF("HCD State:\n");
- DWC_PRINTF(" Num channels: %d\n", num_channels);
- for (i = 0; i < num_channels; i++) {
- dwc_hc_t *hc = hcd->hc_ptr_array[i];
- DWC_PRINTF(" Channel %d:\n", i);
- DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
- hc->dev_addr, hc->ep_num, hc->ep_is_in);
- DWC_PRINTF(" speed: %d\n", hc->speed);
- DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
- DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
- DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
- DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
- DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
- DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
- DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
- DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
- DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
- DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
- DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
- DWC_PRINTF(" do_split: %d\n", hc->do_split);
- DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
- DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
- DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
- DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
- DWC_PRINTF(" requests: %d\n", hc->requests);
- DWC_PRINTF(" qh: %p\n", hc->qh);
- if (hc->xfer_started) {
- hfnum_data_t hfnum;
- hcchar_data_t hcchar;
- hctsiz_data_t hctsiz;
- hcint_data_t hcint;
- hcintmsk_data_t hcintmsk;
- hfnum.d32 =
- DWC_READ_REG32(&hcd->core_if->
- host_if->host_global_regs->hfnum);
- hcchar.d32 =
- DWC_READ_REG32(&hcd->core_if->host_if->
- hc_regs[i]->hcchar);
- hctsiz.d32 =
- DWC_READ_REG32(&hcd->core_if->host_if->
- hc_regs[i]->hctsiz);
- hcint.d32 =
- DWC_READ_REG32(&hcd->core_if->host_if->
- hc_regs[i]->hcint);
- hcintmsk.d32 =
- DWC_READ_REG32(&hcd->core_if->host_if->
- hc_regs[i]->hcintmsk);
- DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
- DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
- DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
- DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
- DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
- }
- if (hc->xfer_started && hc->qh) {
- dwc_otg_qtd_t *qtd;
- dwc_otg_hcd_urb_t *urb;
-
- DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
- if (!qtd->in_process)
- break;
-
- urb = qtd->urb;
- DWC_PRINTF(" URB Info:\n");
- DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
- if (urb) {
- DWC_PRINTF(" Dev: %d, EP: %d %s\n",
- dwc_otg_hcd_get_dev_addr(&urb->
- pipe_info),
- dwc_otg_hcd_get_ep_num(&urb->
- pipe_info),
- dwc_otg_hcd_is_pipe_in(&urb->
- pipe_info) ?
- "IN" : "OUT");
- DWC_PRINTF(" Max packet size: %d\n",
- dwc_otg_hcd_get_mps(&urb->
- pipe_info));
- DWC_PRINTF(" transfer_buffer: %p\n",
- urb->buf);
- DWC_PRINTF(" transfer_dma: %p\n",
- (void *)urb->dma);
- DWC_PRINTF(" transfer_buffer_length: %d\n",
- urb->length);
- DWC_PRINTF(" actual_length: %d\n",
- urb->actual_length);
- }
- }
- }
- }
- DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
- DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
- DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
- np_tx_status.d32 =
- DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
- DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
- np_tx_status.b.nptxqspcavail);
- DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
- np_tx_status.b.nptxfspcavail);
- p_tx_status.d32 =
- DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
- DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
- p_tx_status.b.ptxqspcavail);
- DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
- dwc_otg_hcd_dump_frrem(hcd);
- dwc_otg_dump_global_registers(hcd->core_if);
- dwc_otg_dump_host_registers(hcd->core_if);
- DWC_PRINTF
- ("************************************************************\n");
- DWC_PRINTF("\n");
- #endif
- }
- #ifdef DEBUG
- void dwc_print_setup_data(uint8_t * setup)
- {
- int i;
- if (CHK_DEBUG_LEVEL(DBG_HCD)) {
- DWC_PRINTF("Setup Data = MSB ");
- for (i = 7; i >= 0; i--)
- DWC_PRINTF("%02x ", setup[i]);
- DWC_PRINTF("\n");
- DWC_PRINTF(" bmRequestType Tranfer = %s\n",
- (setup[0] & 0x80) ? "Device-to-Host" :
- "Host-to-Device");
- DWC_PRINTF(" bmRequestType Type = ");
- switch ((setup[0] & 0x60) >> 5) {
- case 0:
- DWC_PRINTF("Standard\n");
- break;
- case 1:
- DWC_PRINTF("Class\n");
- break;
- case 2:
- DWC_PRINTF("Vendor\n");
- break;
- case 3:
- DWC_PRINTF("Reserved\n");
- break;
- }
- DWC_PRINTF(" bmRequestType Recipient = ");
- switch (setup[0] & 0x1f) {
- case 0:
- DWC_PRINTF("Device\n");
- break;
- case 1:
- DWC_PRINTF("Interface\n");
- break;
- case 2:
- DWC_PRINTF("Endpoint\n");
- break;
- case 3:
- DWC_PRINTF("Other\n");
- break;
- default:
- DWC_PRINTF("Reserved\n");
- break;
- }
- DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
- DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
- DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
- DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
- }
- }
- #endif
- void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
- {
- #if 0
- DWC_PRINTF("Frame remaining at SOF:\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->frrem_samples, hcd->frrem_accum,
- (hcd->frrem_samples > 0) ?
- hcd->frrem_accum / hcd->frrem_samples : 0);
- DWC_PRINTF("\n");
- DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->core_if->hfnum_7_samples,
- hcd->core_if->hfnum_7_frrem_accum,
- (hcd->core_if->hfnum_7_samples >
- 0) ? hcd->core_if->hfnum_7_frrem_accum /
- hcd->core_if->hfnum_7_samples : 0);
- DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->core_if->hfnum_0_samples,
- hcd->core_if->hfnum_0_frrem_accum,
- (hcd->core_if->hfnum_0_samples >
- 0) ? hcd->core_if->hfnum_0_frrem_accum /
- hcd->core_if->hfnum_0_samples : 0);
- DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->core_if->hfnum_other_samples,
- hcd->core_if->hfnum_other_frrem_accum,
- (hcd->core_if->hfnum_other_samples >
- 0) ? hcd->core_if->hfnum_other_frrem_accum /
- hcd->core_if->hfnum_other_samples : 0);
- DWC_PRINTF("\n");
- DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
- (hcd->hfnum_7_samples_a > 0) ?
- hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
- DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
- (hcd->hfnum_0_samples_a > 0) ?
- hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
- DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
- (hcd->hfnum_other_samples_a > 0) ?
- hcd->hfnum_other_frrem_accum_a /
- hcd->hfnum_other_samples_a : 0);
- DWC_PRINTF("\n");
- DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
- (hcd->hfnum_7_samples_b > 0) ?
- hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
- DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
- (hcd->hfnum_0_samples_b > 0) ?
- hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
- DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
- DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
- hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
- (hcd->hfnum_other_samples_b > 0) ?
- hcd->hfnum_other_frrem_accum_b /
- hcd->hfnum_other_samples_b : 0);
- #endif
- }
- #endif /* DWC_DEVICE_ONLY */
|