1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725 |
- /* ==========================================================================
- * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
- * $Revision: #99 $
- * $Date: 2011/10/24 $
- * $Change: 1871160 $
- *
- * 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_HOST_ONLY
- /** @file
- * This file implements PCD Core. All code in this file is portable and doesn't
- * use any OS specific functions.
- * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
- * header file, which can be used to implement OS specific PCD interface.
- *
- * An important function of the PCD is managing interrupts generated
- * by the DWC_otg controller. The implementation of the DWC_otg device
- * mode interrupt service routines is in dwc_otg_pcd_intr.c.
- *
- * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
- * @todo Does it work when the request size is greater than DEPTSIZ
- * transfer size
- *
- */
- #include "dwc_otg_pcd.h"
- #ifdef DWC_UTE_CFI
- #include "dwc_otg_cfi.h"
- extern int init_cfi(cfiobject_t * cfiobj);
- #endif
- static const char * bc_name[]={
- "UNKNOWN (Disconnect)",
- "SDP (PC)",
- "DCP (Charger)",
- "CDP (PC with Charger)",
- };
- #define T_DCD_TIMEOUT 10
- #define T_VDPSRC_ON 40
- #define T_VDMSRC_EN (20 + 5)
- #define T_VDMSRC_DIS (20 + 5)
- #define T_VDMSRC_ON 40
- int dwc_otg_charger_detect(dwc_otg_core_if_t * _core_if)
- {
- usb_peri_reg_t *peri;
- usb_adp_bc_data_t adp_bc;
- int bc_mode = USB_BC_MODE_DISCONNECT;
- int timeout_det;
- peri = _core_if->usb_peri_reg;
- adp_bc.d32 = DWC_READ_REG32(&peri->adp_bc);
- if(adp_bc.b.device_sess_vld){
- DWC_MDELAY(T_DCD_TIMEOUT);
- /* Turn on VDPSRC */
- adp_bc.b.chrgsel = 0;
- adp_bc.b.vdatdetenb = 1;
- adp_bc.b.vdatsrcenb = 1;
- adp_bc.b.dcd_enable = 0;
- DWC_WRITE_REG32(&peri->adp_bc,adp_bc.d32);
- /* SDP and CDP/DCP distinguish */
- timeout_det = T_VDMSRC_EN;
- while(timeout_det--){
- adp_bc.d32 = DWC_READ_REG32(&peri->adp_bc);
- if(adp_bc.b.chg_det)
- break;
- DWC_MDELAY(1);
- };
- if(adp_bc.b.chg_det){
- /* Turn off VDPSRC */
- adp_bc.d32 = DWC_READ_REG32(&peri->adp_bc);
- adp_bc.b.vdatdetenb = 0;
- adp_bc.b.vdatsrcenb = 0;
- DWC_WRITE_REG32(&peri->adp_bc,adp_bc.d32);
- /* Wait VDMSRC_DIS */
- timeout_det = T_VDMSRC_DIS;
- while(timeout_det--){
- adp_bc.d32 = DWC_READ_REG32(&peri->adp_bc);
- if(!adp_bc.b.chg_det)
- break;
- DWC_MDELAY(1);
- };
- if(timeout_det <= 0)
- DWC_WARN("Time out for VDMSRC_DIS!");
- /* Turn on VDMSRC */
- adp_bc.d32 = DWC_READ_REG32(&peri->adp_bc);
- adp_bc.b.chrgsel = 1;
- adp_bc.b.vdatdetenb = 1;
- adp_bc.b.vdatsrcenb = 1;
- DWC_WRITE_REG32(&peri->adp_bc,adp_bc.d32);
- DWC_MDELAY(T_VDMSRC_ON);
- adp_bc.d32 = DWC_READ_REG32(&peri->adp_bc);
- if(adp_bc.b.chg_det)
- bc_mode = USB_BC_MODE_DCP;
- else
- bc_mode = USB_BC_MODE_CDP;
- }
- else{
- bc_mode = USB_BC_MODE_SDP;
- }
- adp_bc.d32 = DWC_READ_REG32(&peri->adp_bc);
- adp_bc.b.vdatdetenb = 0;
- adp_bc.b.vdatsrcenb = 0;
- adp_bc.b.dcd_enable = 0;
- DWC_WRITE_REG32(&peri->adp_bc,adp_bc.d32);
- }
- DWC_PRINTF("detected battery charger type: %s\n",bc_name[bc_mode]);
- return bc_mode;
- }
- /**
- * Choose endpoint from ep arrays using usb_ep structure.
- */
- static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
- {
- int i;
- if (pcd->ep0.priv == handle) {
- return &pcd->ep0;
- }
- for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
- if (pcd->in_ep[i].priv == handle)
- return &pcd->in_ep[i];
- if (pcd->out_ep[i].priv == handle)
- return &pcd->out_ep[i];
- }
- return NULL;
- }
- /**
- * This function completes a request. It call's the request call back.
- */
- void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
- int32_t status)
- {
- unsigned stopped = ep->stopped;
-
- DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
- DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
- /* don't modify queue heads during completion callback */
- ep->stopped = 1;
- /* spin_unlock/spin_lock now done in fops->complete() */
- ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
- req->actual);
- if (ep->pcd->request_pending > 0) {
- --ep->pcd->request_pending;
- }
- ep->stopped = stopped;
- DWC_FREE(req);
- }
- /**
- * This function terminates all the requsts in the EP request queue.
- */
- void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
- {
- dwc_otg_pcd_request_t *req;
- ep->stopped = 1;
- /* called with irqs blocked?? */
- while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
- req = DWC_CIRCLEQ_FIRST(&ep->queue);
- dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
- }
- }
- void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
- const struct dwc_otg_pcd_function_ops *fops)
- {
- pcd->fops = fops;
- }
- /**
- * PCD Callback function for initializing the PCD when switching to
- * device mode.
- *
- * @param p void pointer to the <code>dwc_otg_pcd_t</code>
- */
- static int32_t dwc_otg_pcd_start_cb(void *p)
- {
- dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
- /*
- * Initialized the Core for Device mode.
- */
- if (dwc_otg_is_device_mode(core_if)) {
- dwc_otg_core_dev_init(core_if);
- /* Set core_if's lock pointer to the pcd->lock */
- core_if->lock = pcd->lock;
- }
- return 1;
- }
- /** CFI-specific buffer allocation function for EP */
- #ifdef DWC_UTE_CFI
- uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
- size_t buflen, int flags)
- {
- dwc_otg_pcd_ep_t *ep;
- ep = get_ep_from_handle(pcd, pep);
- if (!ep) {
- DWC_WARN("bad ep\n");
- return -DWC_E_INVALID;
- }
- return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
- flags);
- }
- #else
- uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
- size_t buflen, int flags);
- #endif
- /**
- * PCD Callback function for notifying the PCD when resuming from
- * suspend.
- *
- * @param p void pointer to the <code>dwc_otg_pcd_t</code>
- */
- static int32_t dwc_otg_pcd_resume_cb(void *p)
- {
- dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
- if (pcd->fops->resume) {
- pcd->fops->resume(pcd);
- }
- /* Stop the SRP timeout timer. */
- if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
- || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
- if (GET_CORE_IF(pcd)->srp_timer_started) {
- GET_CORE_IF(pcd)->srp_timer_started = 0;
- DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
- }
- }
- return 1;
- }
- /**
- * PCD Callback function for notifying the PCD device is suspended.
- *
- * @param p void pointer to the <code>dwc_otg_pcd_t</code>
- */
- static int32_t dwc_otg_pcd_suspend_cb(void *p)
- {
- dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
- if (pcd->fops->suspend) {
- /* temporarily remove these unlock/lock */
- //DWC_SPINUNLOCK(pcd->lock);
- pcd->fops->suspend(pcd);
- //DWC_SPINLOCK(pcd->lock);
- }
- return 1;
- }
- /**
- * PCD Callback function for stopping the PCD when switching to Host
- * mode.
- *
- * @param p void pointer to the <code>dwc_otg_pcd_t</code>
- */
- static int32_t dwc_otg_pcd_stop_cb(void *p)
- {
- dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
- extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
- dwc_otg_pcd_stop(pcd);
- return 1;
- }
- /**
- * PCD Callback structure for handling mode switching.
- */
- static dwc_otg_cil_callbacks_t pcd_callbacks = {
- .start = dwc_otg_pcd_start_cb,
- .stop = dwc_otg_pcd_stop_cb,
- .suspend = dwc_otg_pcd_suspend_cb,
- .resume_wakeup = dwc_otg_pcd_resume_cb,
- };
- /**
- * This function allocates a DMA Descriptor chain for the Endpoint
- * buffer to be used for a transfer to/from the specified endpoint.
- */
- dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
- uint32_t count)
- {
- return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t),
- dma_desc_addr);
- }
- /**
- * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
- */
- void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
- uint32_t dma_desc_addr, uint32_t count)
- {
- DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
- dma_desc_addr);
- }
- #ifdef DWC_EN_ISOC
- /**
- * This function initializes a descriptor chain for Isochronous transfer
- *
- * @param core_if Programming view of DWC_otg controller.
- * @param dwc_ep The EP to start the transfer on.
- *
- */
- void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
- dwc_ep_t * dwc_ep)
- {
- dsts_data_t dsts = {.d32 = 0 };
- depctl_data_t depctl = {.d32 = 0 };
- volatile uint32_t *addr;
- int i, j;
- uint32_t len;
- if (dwc_ep->is_in)
- dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
- else
- dwc_ep->desc_cnt =
- dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
- dwc_ep->bInterval;
- /** Allocate descriptors for double buffering */
- dwc_ep->iso_desc_addr =
- dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
- dwc_ep->desc_cnt * 2);
- if (dwc_ep->desc_addr) {
- DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
- return;
- }
- dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
- /** ISO OUT EP */
- if (dwc_ep->is_in == 0) {
- dev_dma_desc_sts_t sts = {.d32 = 0 };
- dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
- dma_addr_t dma_ad;
- uint32_t data_per_desc;
- dwc_otg_dev_out_ep_regs_t *out_regs =
- core_if->dev_if->out_ep_regs[dwc_ep->num];
- int offset;
- addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
- dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
- /** Buffer 0 descriptors setup */
- dma_ad = dwc_ep->dma_addr0;
- sts.b_iso_out.bs = BS_HOST_READY;
- sts.b_iso_out.rxsts = 0;
- sts.b_iso_out.l = 0;
- sts.b_iso_out.sp = 0;
- sts.b_iso_out.ioc = 0;
- sts.b_iso_out.pid = 0;
- sts.b_iso_out.framenum = 0;
- offset = 0;
- for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
- i += dwc_ep->pkt_per_frm) {
- for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
- uint32_t len = (j + 1) * dwc_ep->maxpacket;
- if (len > dwc_ep->data_per_frame)
- data_per_desc =
- dwc_ep->data_per_frame -
- j * dwc_ep->maxpacket;
- else
- data_per_desc = dwc_ep->maxpacket;
- len = data_per_desc % 4;
- if (len)
- data_per_desc += 4 - len;
- sts.b_iso_out.rxbytes = data_per_desc;
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- offset += data_per_desc;
- dma_desc++;
- dma_ad += data_per_desc;
- }
- }
- for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
- uint32_t len = (j + 1) * dwc_ep->maxpacket;
- if (len > dwc_ep->data_per_frame)
- data_per_desc =
- dwc_ep->data_per_frame -
- j * dwc_ep->maxpacket;
- else
- data_per_desc = dwc_ep->maxpacket;
- len = data_per_desc % 4;
- if (len)
- data_per_desc += 4 - len;
- sts.b_iso_out.rxbytes = data_per_desc;
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- offset += data_per_desc;
- dma_desc++;
- dma_ad += data_per_desc;
- }
- sts.b_iso_out.ioc = 1;
- len = (j + 1) * dwc_ep->maxpacket;
- if (len > dwc_ep->data_per_frame)
- data_per_desc =
- dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
- else
- data_per_desc = dwc_ep->maxpacket;
- len = data_per_desc % 4;
- if (len)
- data_per_desc += 4 - len;
- sts.b_iso_out.rxbytes = data_per_desc;
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- dma_desc++;
- /** Buffer 1 descriptors setup */
- sts.b_iso_out.ioc = 0;
- dma_ad = dwc_ep->dma_addr1;
- offset = 0;
- for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
- i += dwc_ep->pkt_per_frm) {
- for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
- uint32_t len = (j + 1) * dwc_ep->maxpacket;
- if (len > dwc_ep->data_per_frame)
- data_per_desc =
- dwc_ep->data_per_frame -
- j * dwc_ep->maxpacket;
- else
- data_per_desc = dwc_ep->maxpacket;
- len = data_per_desc % 4;
- if (len)
- data_per_desc += 4 - len;
- data_per_desc =
- sts.b_iso_out.rxbytes = data_per_desc;
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- offset += data_per_desc;
- dma_desc++;
- dma_ad += data_per_desc;
- }
- }
- for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
- data_per_desc =
- ((j + 1) * dwc_ep->maxpacket >
- dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
- j * dwc_ep->maxpacket : dwc_ep->maxpacket;
- data_per_desc +=
- (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
- sts.b_iso_out.rxbytes = data_per_desc;
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- offset += data_per_desc;
- dma_desc++;
- dma_ad += data_per_desc;
- }
- sts.b_iso_out.ioc = 1;
- sts.b_iso_out.l = 1;
- data_per_desc =
- ((j + 1) * dwc_ep->maxpacket >
- dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
- j * dwc_ep->maxpacket : dwc_ep->maxpacket;
- data_per_desc +=
- (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
- sts.b_iso_out.rxbytes = data_per_desc;
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- dwc_ep->next_frame = 0;
- /** Write dma_ad into DOEPDMA register */
- DWC_WRITE_REG32(&(out_regs->doepdma),
- (uint32_t) dwc_ep->iso_dma_desc_addr);
- }
- /** ISO IN EP */
- else {
- dev_dma_desc_sts_t sts = {.d32 = 0 };
- dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
- dma_addr_t dma_ad;
- dwc_otg_dev_in_ep_regs_t *in_regs =
- core_if->dev_if->in_ep_regs[dwc_ep->num];
- unsigned int frmnumber;
- fifosize_data_t txfifosize, rxfifosize;
- txfifosize.d32 =
- DWC_READ_REG32(&core_if->dev_if->
- in_ep_regs[dwc_ep->num]->dtxfsts);
- rxfifosize.d32 =
- DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
- addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
- dma_ad = dwc_ep->dma_addr0;
- dsts.d32 =
- DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
- sts.b_iso_in.bs = BS_HOST_READY;
- sts.b_iso_in.txsts = 0;
- sts.b_iso_in.sp =
- (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
- sts.b_iso_in.ioc = 0;
- sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
- frmnumber = dwc_ep->next_frame;
- sts.b_iso_in.framenum = frmnumber;
- sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
- sts.b_iso_in.l = 0;
- /** Buffer 0 descriptors setup */
- for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- dma_desc++;
- dma_ad += dwc_ep->data_per_frame;
- sts.b_iso_in.framenum += dwc_ep->bInterval;
- }
- sts.b_iso_in.ioc = 1;
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- ++dma_desc;
- /** Buffer 1 descriptors setup */
- sts.b_iso_in.ioc = 0;
- dma_ad = dwc_ep->dma_addr1;
- for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
- i += dwc_ep->pkt_per_frm) {
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- dma_desc++;
- dma_ad += dwc_ep->data_per_frame;
- sts.b_iso_in.framenum += dwc_ep->bInterval;
- sts.b_iso_in.ioc = 0;
- }
- sts.b_iso_in.ioc = 1;
- sts.b_iso_in.l = 1;
- dma_desc->buf = dma_ad;
- dma_desc->status.d32 = sts.d32;
- dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
- /** Write dma_ad into diepdma register */
- DWC_WRITE_REG32(&(in_regs->diepdma),
- (uint32_t) dwc_ep->iso_dma_desc_addr);
- }
- /** Enable endpoint, clear nak */
- depctl.d32 = 0;
- depctl.b.epena = 1;
- depctl.b.usbactep = 1;
- depctl.b.cnak = 1;
- DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
- depctl.d32 = DWC_READ_REG32(addr);
- }
- /**
- * This function initializes a descriptor chain for Isochronous transfer
- *
- * @param core_if Programming view of DWC_otg controller.
- * @param ep The EP to start the transfer on.
- *
- */
- void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
- dwc_ep_t * ep)
- {
- depctl_data_t depctl = {.d32 = 0 };
- volatile uint32_t *addr;
- if (ep->is_in) {
- addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
- } else {
- addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
- }
- if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
- return;
- } else {
- deptsiz_data_t deptsiz = {.d32 = 0 };
- ep->xfer_len =
- ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
- ep->pkt_cnt =
- (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
- ep->xfer_count = 0;
- ep->xfer_buff =
- (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
- ep->dma_addr =
- (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
- if (ep->is_in) {
- /* Program the transfer size and packet count
- * as follows: xfersize = N * maxpacket +
- * short_packet pktcnt = N + (short_packet
- * exist ? 1 : 0)
- */
- deptsiz.b.mc = ep->pkt_per_frm;
- deptsiz.b.xfersize = ep->xfer_len;
- deptsiz.b.pktcnt =
- (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
- DWC_WRITE_REG32(&core_if->dev_if->
- in_ep_regs[ep->num]->dieptsiz,
- deptsiz.d32);
- /* Write the DMA register */
- DWC_WRITE_REG32(&
- (core_if->dev_if->
- in_ep_regs[ep->num]->diepdma),
- (uint32_t) ep->dma_addr);
- } else {
- deptsiz.b.pktcnt =
- (ep->xfer_len + (ep->maxpacket - 1)) /
- ep->maxpacket;
- deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
- DWC_WRITE_REG32(&core_if->dev_if->
- out_ep_regs[ep->num]->doeptsiz,
- deptsiz.d32);
- /* Write the DMA register */
- DWC_WRITE_REG32(&
- (core_if->dev_if->
- out_ep_regs[ep->num]->doepdma),
- (uint32_t) ep->dma_addr);
- }
- /** Enable endpoint, clear nak */
- depctl.d32 = 0;
- depctl.b.epena = 1;
- depctl.b.cnak = 1;
- DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
- }
- }
- /**
- * This function does the setup for a data transfer for an EP and
- * starts the transfer. For an IN transfer, the packets will be
- * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
- * the packets are unloaded from the Rx FIFO in the ISR.
- *
- * @param core_if Programming view of DWC_otg controller.
- * @param ep The EP to start the transfer on.
- */
- static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
- dwc_ep_t * ep)
- {
- if (core_if->dma_enable) {
- if (core_if->dma_desc_enable) {
- if (ep->is_in) {
- ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
- } else {
- ep->desc_cnt = ep->pkt_cnt;
- }
- dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
- } else {
- if (core_if->pti_enh_enable) {
- dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
- } else {
- ep->cur_pkt_addr =
- (ep->proc_buf_num) ? ep->
- xfer_buff1 : ep->xfer_buff0;
- ep->cur_pkt_dma_addr =
- (ep->proc_buf_num) ? ep->
- dma_addr1 : ep->dma_addr0;
- dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
- }
- }
- } else {
- ep->cur_pkt_addr =
- (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
- ep->cur_pkt_dma_addr =
- (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
- dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
- }
- }
- /**
- * This function stops transfer for an EP and
- * resets the ep's variables.
- *
- * @param core_if Programming view of DWC_otg controller.
- * @param ep The EP to start the transfer on.
- */
- void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
- {
- depctl_data_t depctl = {.d32 = 0 };
- volatile uint32_t *addr;
- if (ep->is_in == 1) {
- addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
- } else {
- addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
- }
- /* disable the ep */
- depctl.d32 = DWC_READ_REG32(addr);
- depctl.b.epdis = 1;
- depctl.b.snak = 1;
- DWC_WRITE_REG32(addr, depctl.d32);
- if (core_if->dma_desc_enable &&
- ep->iso_desc_addr && ep->iso_dma_desc_addr) {
- dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
- ep->iso_dma_desc_addr,
- ep->desc_cnt * 2);
- }
- /* reset varibales */
- ep->dma_addr0 = 0;
- ep->dma_addr1 = 0;
- ep->xfer_buff0 = 0;
- ep->xfer_buff1 = 0;
- ep->data_per_frame = 0;
- ep->data_pattern_frame = 0;
- ep->sync_frame = 0;
- ep->buf_proc_intrvl = 0;
- ep->bInterval = 0;
- ep->proc_buf_num = 0;
- ep->pkt_per_frm = 0;
- ep->pkt_per_frm = 0;
- ep->desc_cnt = 0;
- ep->iso_desc_addr = 0;
- ep->iso_dma_desc_addr = 0;
- }
- int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
- uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
- dwc_dma_t dma1, int sync_frame, int dp_frame,
- int data_per_frame, int start_frame,
- int buf_proc_intrvl, void *req_handle,
- int atomic_alloc)
- {
- dwc_otg_pcd_ep_t *ep;
- dwc_irqflags_t flags = 0;
- dwc_ep_t *dwc_ep;
- int32_t frm_data;
- dsts_data_t dsts;
- dwc_otg_core_if_t *core_if;
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
- DWC_WARN("bad ep\n");
- return -DWC_E_INVALID;
- }
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- core_if = GET_CORE_IF(pcd);
- dwc_ep = &ep->dwc_ep;
- if (ep->iso_req_handle) {
- DWC_WARN("ISO request in progress\n");
- }
- dwc_ep->dma_addr0 = dma0;
- dwc_ep->dma_addr1 = dma1;
- dwc_ep->xfer_buff0 = buf0;
- dwc_ep->xfer_buff1 = buf1;
- dwc_ep->data_per_frame = data_per_frame;
- /** @todo - pattern data support is to be implemented in the future */
- dwc_ep->data_pattern_frame = dp_frame;
- dwc_ep->sync_frame = sync_frame;
- dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
- dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
- dwc_ep->proc_buf_num = 0;
- dwc_ep->pkt_per_frm = 0;
- frm_data = ep->dwc_ep.data_per_frame;
- while (frm_data > 0) {
- dwc_ep->pkt_per_frm++;
- frm_data -= ep->dwc_ep.maxpacket;
- }
- dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
- if (start_frame == -1) {
- dwc_ep->next_frame = dsts.b.soffn + 1;
- if (dwc_ep->bInterval != 1) {
- dwc_ep->next_frame =
- dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
- dwc_ep->next_frame %
- dwc_ep->bInterval);
- }
- } else {
- dwc_ep->next_frame = start_frame;
- }
- if (!core_if->pti_enh_enable) {
- dwc_ep->pkt_cnt =
- dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
- dwc_ep->bInterval;
- } else {
- dwc_ep->pkt_cnt =
- (dwc_ep->data_per_frame *
- (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
- - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
- }
- if (core_if->dma_desc_enable) {
- dwc_ep->desc_cnt =
- dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
- dwc_ep->bInterval;
- }
- if (atomic_alloc) {
- dwc_ep->pkt_info =
- DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
- } else {
- dwc_ep->pkt_info =
- DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
- }
- if (!dwc_ep->pkt_info) {
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- return -DWC_E_NO_MEMORY;
- }
- if (core_if->pti_enh_enable) {
- dwc_memset(dwc_ep->pkt_info, 0,
- sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
- }
- dwc_ep->cur_pkt = 0;
- ep->iso_req_handle = req_handle;
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
- return 0;
- }
- int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
- void *req_handle)
- {
- dwc_irqflags_t flags = 0;
- dwc_otg_pcd_ep_t *ep;
- dwc_ep_t *dwc_ep;
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
- DWC_WARN("bad ep\n");
- return -DWC_E_INVALID;
- }
- dwc_ep = &ep->dwc_ep;
- dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
- DWC_FREE(dwc_ep->pkt_info);
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- if (ep->iso_req_handle != req_handle) {
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- return -DWC_E_INVALID;
- }
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- ep->iso_req_handle = 0;
- return 0;
- }
- /**
- * This function is used for perodical data exchnage between PCD and gadget drivers.
- * for Isochronous EPs
- *
- * - Every time a sync period completes this function is called to
- * perform data exchange between PCD and gadget
- */
- void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
- void *req_handle)
- {
- int i;
- dwc_ep_t *dwc_ep;
- dwc_ep = &ep->dwc_ep;
- DWC_SPINUNLOCK(ep->pcd->lock);
- pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
- dwc_ep->proc_buf_num ^ 0x1);
- DWC_SPINLOCK(ep->pcd->lock);
- for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
- dwc_ep->pkt_info[i].status = 0;
- dwc_ep->pkt_info[i].offset = 0;
- dwc_ep->pkt_info[i].length = 0;
- }
- }
- int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
- void *iso_req_handle)
- {
- dwc_otg_pcd_ep_t *ep;
- dwc_ep_t *dwc_ep;
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep->desc || ep->dwc_ep.num == 0) {
- DWC_WARN("bad ep\n");
- return -DWC_E_INVALID;
- }
- dwc_ep = &ep->dwc_ep;
- return dwc_ep->pkt_cnt;
- }
- void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
- void *iso_req_handle, int packet,
- int *status, int *actual, int *offset)
- {
- dwc_otg_pcd_ep_t *ep;
- dwc_ep_t *dwc_ep;
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep)
- DWC_WARN("bad ep\n");
- dwc_ep = &ep->dwc_ep;
- *status = dwc_ep->pkt_info[packet].status;
- *actual = dwc_ep->pkt_info[packet].length;
- *offset = dwc_ep->pkt_info[packet].offset;
- }
- #endif /* DWC_EN_ISOC */
- static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
- uint32_t is_in, uint32_t ep_num)
- {
- /* Init EP structure */
- pcd_ep->desc = 0;
- pcd_ep->pcd = pcd;
- pcd_ep->stopped = 1;
- pcd_ep->queue_sof = 0;
- /* Init DWC ep structure */
- pcd_ep->dwc_ep.is_in = is_in;
- pcd_ep->dwc_ep.num = ep_num;
- pcd_ep->dwc_ep.active = 0;
- pcd_ep->dwc_ep.tx_fifo_num = 0;
- /* Control until ep is actvated */
- pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
- pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
- pcd_ep->dwc_ep.dma_addr = 0;
- pcd_ep->dwc_ep.start_xfer_buff = 0;
- pcd_ep->dwc_ep.xfer_buff = 0;
- pcd_ep->dwc_ep.xfer_len = 0;
- pcd_ep->dwc_ep.xfer_count = 0;
- pcd_ep->dwc_ep.sent_zlp = 0;
- pcd_ep->dwc_ep.total_len = 0;
- pcd_ep->dwc_ep.desc_addr = 0;
- pcd_ep->dwc_ep.dma_desc_addr = 0;
- DWC_CIRCLEQ_INIT(&pcd_ep->queue);
- }
- /**
- * Initialize ep's
- */
- static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
- {
- int i;
- uint32_t hwcfg1;
- dwc_otg_pcd_ep_t *ep;
- int in_ep_cntr, out_ep_cntr;
- uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
- uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
- /**
- * Initialize the EP0 structure.
- */
- ep = &pcd->ep0;
- dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
- in_ep_cntr = 0;
- hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
- for (i = 1; in_ep_cntr < num_in_eps; i++) {
- if ((hwcfg1 & 0x1) == 0) {
- dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
- in_ep_cntr++;
- /**
- * @todo NGS: Add direction to EP, based on contents
- * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
- * sprintf(";r
- */
- dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
- DWC_CIRCLEQ_INIT(&ep->queue);
- }
- hwcfg1 >>= 2;
- }
- out_ep_cntr = 0;
- hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
- for (i = 1; out_ep_cntr < num_out_eps; i++) {
- if ((hwcfg1 & 0x1) == 0) {
- dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
- out_ep_cntr++;
- /**
- * @todo NGS: Add direction to EP, based on contents
- * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
- * sprintf(";r
- */
- dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
- DWC_CIRCLEQ_INIT(&ep->queue);
- }
- hwcfg1 >>= 2;
- }
- pcd->ep0state = EP0_DISCONNECT;
- pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
- pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
- }
- /**
- * This function is called when the SRP timer expires. The SRP should
- * complete within 6 seconds.
- */
- static void srp_timeout(void *ptr)
- {
- gotgctl_data_t gotgctl;
- dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
- volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
- gotgctl.d32 = DWC_READ_REG32(addr);
- core_if->srp_timer_started = 0;
-
- if (core_if->adp_enable) {
- if (gotgctl.b.bsesvld == 0) {
- gpwrdn_data_t gpwrdn = {.d32 = 0 };
- DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
- /* Power off the core */
- if (core_if->power_down == 2) {
- gpwrdn.b.pwrdnswtch = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, gpwrdn.d32, 0);
- }
- gpwrdn.d32 = 0;
- gpwrdn.b.pmuintsel = 1;
- gpwrdn.b.pmuactv = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
- dwc_otg_adp_probe_start(core_if);
- } else {
- DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
- core_if->op_state = B_PERIPHERAL;
- dwc_otg_core_init(core_if);
- dwc_otg_enable_global_interrupts(core_if);
- cil_pcd_start(core_if);
- }
- }
- if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
- (core_if->core_params->i2c_enable)) {
- DWC_PRINTF("SRP Timeout\n");
- if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
- if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
- core_if->pcd_cb->resume_wakeup(core_if->pcd_cb_p);
- }
- /* Clear Session Request */
- gotgctl.d32 = 0;
- gotgctl.b.sesreq = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
- gotgctl.d32, 0);
- core_if->srp_success = 0;
- } else {
- __DWC_ERROR("Device not connected/responding\n");
- gotgctl.b.sesreq = 0;
- DWC_WRITE_REG32(addr, gotgctl.d32);
- }
- } else if (gotgctl.b.sesreq) {
- DWC_PRINTF("SRP Timeout\n");
- __DWC_ERROR("Device not connected/responding\n");
- gotgctl.b.sesreq = 0;
- DWC_WRITE_REG32(addr, gotgctl.d32);
- } else {
- DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
- }
- }
- /**
- * Tasklet
- *
- */
- extern void start_next_request(dwc_otg_pcd_ep_t * ep);
- static void start_xfer_tasklet_func(void *data)
- {
- dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
- int i;
- depctl_data_t diepctl;
- DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
- diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
- if (pcd->ep0.queue_sof) {
- pcd->ep0.queue_sof = 0;
- start_next_request(&pcd->ep0);
- // break;
- }
- for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
- depctl_data_t diepctl;
- diepctl.d32 =
- DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
- if (pcd->in_ep[i].queue_sof) {
- pcd->in_ep[i].queue_sof = 0;
- start_next_request(&pcd->in_ep[i]);
- // break;
- }
- }
- return;
- }
- /**
- * This function initialized the PCD portion of the driver.
- *
- */
- dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
- {
- dwc_otg_pcd_t *pcd = NULL;
- dwc_otg_dev_if_t *dev_if;
- int i;
- /*
- * Allocate PCD structure
- */
- pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
- if (pcd == NULL) {
- return NULL;
- }
- pcd->lock = DWC_SPINLOCK_ALLOC();
- if (!pcd->lock) {
- DWC_ERROR("Could not allocate lock for pcd");
- DWC_FREE(pcd);
- return NULL;
- }
- /* Set core_if's lock pointer to hcd->lock */
- core_if->lock = pcd->lock;
- pcd->core_if = core_if;
- dev_if = core_if->dev_if;
- dev_if->isoc_ep = NULL;
- if (core_if->hwcfg4.b.ded_fifo_en) {
- DWC_PRINTF("Dedicated Tx FIFOs mode\n");
- } else {
- DWC_PRINTF("Shared Tx FIFO mode\n");
- }
- /*
- * Initialized the Core for Device mode here if there is nod ADP support.
- * Otherwise it will be done later in dwc_otg_adp_start routine.
- */
- if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) {
- dwc_otg_core_dev_init(core_if);
- }
- /*
- * Register the PCD Callbacks.
- */
- dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
- /*
- * Initialize the DMA buffer for SETUP packets
- */
- if (GET_CORE_IF(pcd)->dma_enable) {
- pcd->setup_pkt =
- DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
- &pcd->setup_pkt_dma_handle);
- if (pcd->setup_pkt == NULL) {
- DWC_FREE(pcd);
- return NULL;
- }
- pcd->status_buf =
- DWC_DMA_ALLOC(sizeof(uint16_t),
- &pcd->status_buf_dma_handle);
- if (pcd->status_buf == NULL) {
- DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
- pcd->setup_pkt, pcd->setup_pkt_dma_handle);
- DWC_FREE(pcd);
- return NULL;
- }
- if (GET_CORE_IF(pcd)->dma_desc_enable) {
- dev_if->setup_desc_addr[0] =
- dwc_otg_ep_alloc_desc_chain(&dev_if->
- dma_setup_desc_addr[0],
- 1);
- dev_if->setup_desc_addr[1] =
- dwc_otg_ep_alloc_desc_chain(&dev_if->
- dma_setup_desc_addr[1],
- 1);
- dev_if->in_desc_addr =
- dwc_otg_ep_alloc_desc_chain(&dev_if->
- dma_in_desc_addr, 1);
- dev_if->out_desc_addr =
- dwc_otg_ep_alloc_desc_chain(&dev_if->
- dma_out_desc_addr, 1);
- if (dev_if->setup_desc_addr[0] == 0
- || dev_if->setup_desc_addr[1] == 0
- || dev_if->in_desc_addr == 0
- || dev_if->out_desc_addr == 0) {
- if (dev_if->out_desc_addr)
- dwc_otg_ep_free_desc_chain(dev_if->
- out_desc_addr,
- dev_if->
- dma_out_desc_addr,
- 1);
- if (dev_if->in_desc_addr)
- dwc_otg_ep_free_desc_chain(dev_if->
- in_desc_addr,
- dev_if->
- dma_in_desc_addr,
- 1);
- if (dev_if->setup_desc_addr[1])
- dwc_otg_ep_free_desc_chain(dev_if->
- setup_desc_addr
- [1],
- dev_if->
- dma_setup_desc_addr
- [1], 1);
- if (dev_if->setup_desc_addr[0])
- dwc_otg_ep_free_desc_chain(dev_if->
- setup_desc_addr
- [0],
- dev_if->
- dma_setup_desc_addr
- [0], 1);
- DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
- pcd->setup_pkt,
- pcd->setup_pkt_dma_handle);
- DWC_DMA_FREE(sizeof(*pcd->status_buf),
- pcd->status_buf,
- pcd->status_buf_dma_handle);
- DWC_FREE(pcd);
- return NULL;
- }
- }
- } else {
- pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
- if (pcd->setup_pkt == NULL) {
- DWC_FREE(pcd);
- return NULL;
- }
- pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
- if (pcd->status_buf == NULL) {
- DWC_FREE(pcd->setup_pkt);
- DWC_FREE(pcd);
- return NULL;
- }
- }
- dwc_otg_pcd_reinit(pcd);
- /* Allocate the cfi object for the PCD */
- #ifdef DWC_UTE_CFI
- pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
- if (NULL == pcd->cfi)
- goto fail;
- if (init_cfi(pcd->cfi)) {
- CFI_INFO("%s: Failed to init the CFI object\n", __func__);
- goto fail;
- }
- #endif
- /* Initialize tasklets */
- pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
- start_xfer_tasklet_func, pcd);
- pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
- do_test_mode, pcd);
- /* Initialize SRP timer */
- core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
-
- if (core_if->core_params->dev_out_nak) {
- /**
- * Initialize xfer timeout timer. Implemented for
- * 2.93a feature "Device DDMA OUT NAK Enhancement"
- */
- for(i = 0; i < MAX_EPS_CHANNELS; i++) {
- pcd->core_if->ep_xfer_timer[i] =
- DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
- &pcd->core_if->ep_xfer_info[i]);
- }
- }
-
- return pcd;
- #ifdef DWC_UTE_CFI
- fail:
- #endif
- if (pcd->setup_pkt)
- DWC_FREE(pcd->setup_pkt);
- if (pcd->status_buf)
- DWC_FREE(pcd->status_buf);
- #ifdef DWC_UTE_CFI
- if (pcd->cfi)
- DWC_FREE(pcd->cfi);
- #endif
- if (pcd)
- DWC_FREE(pcd);
- return NULL;
- }
- /**
- * Remove PCD specific data
- */
- void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
- {
- dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
- int i;
- if (pcd->core_if->core_params->dev_out_nak) {
- for (i = 0; i < MAX_EPS_CHANNELS; i++) {
- DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
- pcd->core_if->ep_xfer_info[i].state = 0;
- }
- }
- if (GET_CORE_IF(pcd)->dma_enable) {
- DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
- pcd->setup_pkt_dma_handle);
- DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
- pcd->status_buf_dma_handle);
- if (GET_CORE_IF(pcd)->dma_desc_enable) {
- dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
- dev_if->dma_setup_desc_addr
- [0], 1);
- dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
- dev_if->dma_setup_desc_addr
- [1], 1);
- dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
- dev_if->dma_in_desc_addr, 1);
- dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
- dev_if->dma_out_desc_addr,
- 1);
- }
- } else {
- DWC_FREE(pcd->setup_pkt);
- DWC_FREE(pcd->status_buf);
- }
- DWC_SPINLOCK_FREE(pcd->lock);
- /* Set core_if's lock pointer to NULL */
- pcd->core_if->lock = NULL;
- DWC_TASK_FREE(pcd->start_xfer_tasklet);
- DWC_TASK_FREE(pcd->test_mode_tasklet);
- if (pcd->core_if->core_params->dev_out_nak) {
- for (i = 0; i < MAX_EPS_CHANNELS; i++) {
- if (pcd->core_if->ep_xfer_timer[i]) {
- DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
- }
- }
- }
- /* Release the CFI object's dynamic memory */
- #ifdef DWC_UTE_CFI
- if (pcd->cfi->ops.release) {
- pcd->cfi->ops.release(pcd->cfi);
- }
- #endif
- DWC_FREE(pcd);
- }
- /**
- * Returns whether registered pcd is dual speed or not
- */
- uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
- {
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
- if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
- ((core_if->hwcfg2.b.hs_phy_type == 2) &&
- (core_if->hwcfg2.b.fs_phy_type == 1) &&
- (core_if->core_params->ulpi_fs_ls))) {
- return 0;
- }
- return 1;
- }
- /**
- * Returns whether registered pcd is OTG capable or not
- */
- uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
- {
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
- gusbcfg_data_t usbcfg = {.d32 = 0 };
- usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
- if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
- return 0;
- }
- return 1;
- }
- /**
- * This function assigns periodic Tx FIFO to an periodic EP
- * in shared Tx FIFO mode
- */
- static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
- {
- uint32_t TxMsk = 1;
- int i;
- for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
- if ((TxMsk & core_if->tx_msk) == 0) {
- core_if->tx_msk |= TxMsk;
- return i + 1;
- }
- TxMsk <<= 1;
- }
- return 0;
- }
- /**
- * This function assigns periodic Tx FIFO to an periodic EP
- * in shared Tx FIFO mode
- */
- static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
- {
- uint32_t PerTxMsk = 1;
- int i;
- for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
- if ((PerTxMsk & core_if->p_tx_msk) == 0) {
- core_if->p_tx_msk |= PerTxMsk;
- return i + 1;
- }
- PerTxMsk <<= 1;
- }
- return 0;
- }
- /**
- * This function releases periodic Tx FIFO
- * in shared Tx FIFO mode
- */
- static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
- uint32_t fifo_num)
- {
- core_if->p_tx_msk =
- (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
- }
- /**
- * This function releases periodic Tx FIFO
- * in shared Tx FIFO mode
- */
- static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
- {
- core_if->tx_msk =
- (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
- }
- /**
- * This function is being called from gadget
- * to enable PCD endpoint.
- */
- int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
- const uint8_t * ep_desc, void *usb_ep)
- {
- int num, dir;
- dwc_otg_pcd_ep_t *ep = NULL;
- const usb_endpoint_descriptor_t *desc;
- dwc_irqflags_t flags;
- fifosize_data_t dptxfsiz = {.d32 = 0 };
- gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
- gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
- int retval = 0;
- int i, epcount;
- desc = (const usb_endpoint_descriptor_t *)ep_desc;
- if (!desc) {
- pcd->ep0.priv = usb_ep;
- ep = &pcd->ep0;
- retval = -DWC_E_INVALID;
- goto out;
- }
- num = UE_GET_ADDR(desc->bEndpointAddress);
- dir = UE_GET_DIR(desc->bEndpointAddress);
- if (!desc->wMaxPacketSize) {
- DWC_WARN("bad maxpacketsize\n");
- retval = -DWC_E_INVALID;
- goto out;
- }
- if (dir == UE_DIR_IN) {
- epcount = pcd->core_if->dev_if->num_in_eps;
- for (i = 0; i < epcount; i++) {
- if (num == pcd->in_ep[i].dwc_ep.num) {
- ep = &pcd->in_ep[i];
- break;
- }
- }
- } else {
- epcount = pcd->core_if->dev_if->num_out_eps;
- for (i = 0; i < epcount; i++) {
- if (num == pcd->out_ep[i].dwc_ep.num) {
- ep = &pcd->out_ep[i];
- break;
- }
- }
- }
- if (!ep) {
- DWC_WARN("bad address\n");
- retval = -DWC_E_INVALID;
- goto out;
- }
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- ep->desc = desc;
- ep->priv = usb_ep;
- /*
- * Activate the EP
- */
- ep->stopped = 0;
- ep->dwc_ep.is_in = (dir == UE_DIR_IN);
- ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
- ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
- if (ep->dwc_ep.is_in) {
- if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
- ep->dwc_ep.tx_fifo_num = 0;
- if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
- /*
- * if ISOC EP then assign a Periodic Tx FIFO.
- */
- ep->dwc_ep.tx_fifo_num =
- assign_perio_tx_fifo(GET_CORE_IF(pcd));
- }
- } else {
- /*
- * if Dedicated FIFOs mode is on then assign a Tx FIFO.
- */
- ep->dwc_ep.tx_fifo_num =
- assign_tx_fifo(GET_CORE_IF(pcd));
- }
- /* Calculating EP info controller base address */
- if (ep->dwc_ep.tx_fifo_num && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
- gdfifocfg.d32 =
- DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
- gdfifocfg);
- gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
- dptxfsiz.d32 =
- (DWC_READ_REG32
- (&GET_CORE_IF(pcd)->
- core_global_regs->dtxfsiz[ep->dwc_ep.
- tx_fifo_num-1]) >> 16);
- gdfifocfg.b.epinfobase =
- gdfifocfgbase.d32 + dptxfsiz.d32;
- DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->
- gdfifocfg, gdfifocfg.d32);
- }
- }
- /* Set initial data PID. */
- if (ep->dwc_ep.type == UE_BULK) {
- ep->dwc_ep.data_pid_start = 0;
- }
- /* Alloc DMA Descriptors */
- if (GET_CORE_IF(pcd)->dma_desc_enable) {
- #ifndef DWC_UTE_PER_IO
- if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
- #endif
- ep->dwc_ep.desc_addr =
- dwc_otg_ep_alloc_desc_chain(&ep->
- dwc_ep.dma_desc_addr,
- MAX_DMA_DESC_CNT);
- if (!ep->dwc_ep.desc_addr) {
- DWC_WARN("%s, can't allocate DMA descriptor\n",
- __func__);
- retval = -DWC_E_SHUTDOWN;
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- goto out;
- }
- #ifndef DWC_UTE_PER_IO
- }
- #endif
- }
- DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
- (ep->dwc_ep.is_in ? "IN" : "OUT"),
- ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
- #ifdef DWC_UTE_PER_IO
- ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
- #endif
- if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
- ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
- ep->dwc_ep.frame_num = 0xFFFFFFFF;
- }
- dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
- #ifdef DWC_UTE_CFI
- if (pcd->cfi->ops.ep_enable) {
- pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
- }
- #endif
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- out:
- return retval;
- }
- /**
- * This function is being called from gadget
- * to disable PCD endpoint.
- */
- int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
- {
- dwc_otg_pcd_ep_t *ep;
- dwc_irqflags_t flags;
- dwc_otg_dev_dma_desc_t *desc_addr;
- dwc_dma_t dma_desc_addr;
- gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
- gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
- fifosize_data_t dptxfsiz = {.d32 = 0 };
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep || !ep->desc) {
- DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
- return -DWC_E_INVALID;
- }
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- dwc_otg_request_nuke(ep);
- dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
- if (pcd->core_if->core_params->dev_out_nak)
- {
- DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
- pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
- }
- ep->desc = NULL;
- ep->stopped = 1;
- gdfifocfg.d32 =
- DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
- gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
- if (ep->dwc_ep.is_in) {
- if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
- /* Flush the Tx FIFO */
- dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
- }
- release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
- release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
- if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
- /* Decreasing EPinfo Base Addr */
- dptxfsiz.d32 =
- (DWC_READ_REG32
- (&GET_CORE_IF(pcd)->
- core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
- gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
- DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
- gdfifocfg.d32);
- }
- }
- /* Free DMA Descriptors */
- if (GET_CORE_IF(pcd)->dma_desc_enable) {
- if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
- desc_addr = ep->dwc_ep.desc_addr;
- dma_desc_addr = ep->dwc_ep.dma_desc_addr;
- /* Cannot call dma_free_coherent() with IRQs disabled */
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
- MAX_DMA_DESC_CNT);
- goto out_unlocked;
- }
- }
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- out_unlocked:
- DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
- ep->dwc_ep.is_in ? "IN" : "OUT");
- return 0;
- }
- /******************************************************************************/
- #ifdef DWC_UTE_PER_IO
- /**
- * Free the request and its extended parts
- *
- */
- void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
- {
- DWC_FREE(req->ext_req.per_io_frame_descs);
- DWC_FREE(req);
- }
- /**
- * Start the next request in the endpoint's queue.
- *
- */
- int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
- dwc_otg_pcd_ep_t * ep)
- {
- int i;
- dwc_otg_pcd_request_t *req = NULL;
- dwc_ep_t *dwcep = NULL;
- struct dwc_iso_xreq_port *ereq = NULL;
- struct dwc_iso_pkt_desc_port *ddesc_iso;
- uint16_t nat;
- depctl_data_t diepctl;
- dwcep = &ep->dwc_ep;
- if (dwcep->xiso_active_xfers > 0) {
- #if 0 //Disable this to decrease s/w overhead that is crucial for Isoc transfers
- DWC_WARN("There are currently active transfers for EP%d \
- (active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers,
- dwcep->xiso_queued_xfers);
- #endif
- return 0;
- }
- nat = UGETW(ep->desc->wMaxPacketSize);
- nat = (nat >> 11) & 0x03;
- if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
- req = DWC_CIRCLEQ_FIRST(&ep->queue);
- ereq = &req->ext_req;
- ep->stopped = 0;
- /* Get the frame number */
- dwcep->xiso_frame_num =
- dwc_otg_get_frame_number(GET_CORE_IF(pcd));
- DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
- ddesc_iso = ereq->per_io_frame_descs;
- if (dwcep->is_in) {
- /* Setup DMA Descriptor chain for IN Isoc request */
- for (i = 0; i < ereq->pio_pkt_count; i++) {
- //if ((i % (nat + 1)) == 0)
- if ( i > 0 )
- dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
- dwcep->xiso_frame_num) & 0x3FFF;
- dwcep->desc_addr[i].buf =
- req->dma + ddesc_iso[i].offset;
- dwcep->desc_addr[i].status.b_iso_in.txbytes =
- ddesc_iso[i].length;
- dwcep->desc_addr[i].status.b_iso_in.framenum =
- dwcep->xiso_frame_num;
- dwcep->desc_addr[i].status.b_iso_in.bs =
- BS_HOST_READY;
- dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
- dwcep->desc_addr[i].status.b_iso_in.sp =
- (ddesc_iso[i].length %
- dwcep->maxpacket) ? 1 : 0;
- dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
- dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
- dwcep->desc_addr[i].status.b_iso_in.l = 0;
- /* Process the last descriptor */
- if (i == ereq->pio_pkt_count - 1) {
- dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
- dwcep->desc_addr[i].status.b_iso_in.l = 1;
- }
- }
- /* Setup and start the transfer for this endpoint */
- dwcep->xiso_active_xfers++;
- DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
- in_ep_regs[dwcep->num]->diepdma,
- dwcep->dma_desc_addr);
- diepctl.d32 = 0;
- diepctl.b.epena = 1;
- diepctl.b.cnak = 1;
- DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
- in_ep_regs[dwcep->num]->diepctl, 0,
- diepctl.d32);
- } else {
- /* Setup DMA Descriptor chain for OUT Isoc request */
- for (i = 0; i < ereq->pio_pkt_count; i++) {
- //if ((i % (nat + 1)) == 0)
- dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
- dwcep->xiso_frame_num) & 0x3FFF;
- dwcep->desc_addr[i].buf =
- req->dma + ddesc_iso[i].offset;
- dwcep->desc_addr[i].status.b_iso_out.rxbytes =
- ddesc_iso[i].length;
- dwcep->desc_addr[i].status.b_iso_out.framenum =
- dwcep->xiso_frame_num;
- dwcep->desc_addr[i].status.b_iso_out.bs =
- BS_HOST_READY;
- dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
- dwcep->desc_addr[i].status.b_iso_out.sp =
- (ddesc_iso[i].length %
- dwcep->maxpacket) ? 1 : 0;
- dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
- dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
- dwcep->desc_addr[i].status.b_iso_out.l = 0;
-
- /* Process the last descriptor */
- if (i == ereq->pio_pkt_count - 1) {
- dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
- dwcep->desc_addr[i].status.b_iso_out.l = 1;
- }
- }
-
- /* Setup and start the transfer for this endpoint */
- dwcep->xiso_active_xfers++;
- DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
- out_ep_regs[dwcep->num]->doepdma,
- dwcep->dma_desc_addr);
- diepctl.d32 = 0;
- diepctl.b.epena = 1;
- diepctl.b.cnak = 1;
- DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
- out_ep_regs[dwcep->num]->doepctl, 0,
- diepctl.d32);
- }
- } else {
- ep->stopped = 1;
- }
- return 0;
- }
- /**
- * - Remove the request from the queue
- */
- void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
- {
- dwc_otg_pcd_request_t *req = NULL;
- struct dwc_iso_xreq_port *ereq = NULL;
- struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
- dwc_ep_t *dwcep = NULL;
- int i;
- //DWC_DEBUG();
- dwcep = &ep->dwc_ep;
- /* Get the first pending request from the queue */
- if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
- req = DWC_CIRCLEQ_FIRST(&ep->queue);
- if (!req) {
- DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
- return;
- }
- dwcep->xiso_active_xfers--;
- dwcep->xiso_queued_xfers--;
- /* Remove this request from the queue */
- DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
- } else {
- DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
- return;
- }
- ep->stopped = 1;
- ereq = &req->ext_req;
- ddesc_iso = ereq->per_io_frame_descs;
- if (dwcep->xiso_active_xfers < 0) {
- DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
- dwcep->xiso_active_xfers);
- }
- /* Fill the Isoc descs of portable extended req from dma descriptors */
- for (i = 0; i < ereq->pio_pkt_count; i++) {
- if (dwcep->is_in) { /* IN endpoints */
- ddesc_iso[i].actual_length = ddesc_iso[i].length -
- dwcep->desc_addr[i].status.b_iso_in.txbytes;
- ddesc_iso[i].status =
- dwcep->desc_addr[i].status.b_iso_in.txsts;
- } else { /* OUT endpoints */
- ddesc_iso[i].actual_length = ddesc_iso[i].length -
- dwcep->desc_addr[i].status.b_iso_out.rxbytes;
- ddesc_iso[i].status =
- dwcep->desc_addr[i].status.b_iso_out.rxsts;
- }
- }
- DWC_SPINUNLOCK(ep->pcd->lock);
- /* Call the completion function in the non-portable logic */
- ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
- &req->ext_req);
- DWC_SPINLOCK(ep->pcd->lock);
- /* Free the request - specific freeing needed for extended request object */
- dwc_pcd_xiso_ereq_free(ep, req);
- /* Start the next request */
- dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
- return;
- }
- /**
- * Create and initialize the Isoc pkt descriptors of the extended request.
- *
- */
- static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
- void *ereq_nonport,
- int atomic_alloc)
- {
- struct dwc_iso_xreq_port *ereq = NULL;
- struct dwc_iso_xreq_port *req_mapped = NULL;
- struct dwc_iso_pkt_desc_port *ipds = NULL; /* To be created in this function */
- uint32_t pkt_count;
- int i;
- ereq = &req->ext_req;
- req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
- pkt_count = req_mapped->pio_pkt_count;
- /* Create the isoc descs */
- if (atomic_alloc) {
- ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
- } else {
- ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
- }
- if (!ipds) {
- DWC_ERROR("Failed to allocate isoc descriptors");
- return -DWC_E_NO_MEMORY;
- }
- /* Initialize the extended request fields */
- ereq->per_io_frame_descs = ipds;
- ereq->error_count = 0;
- ereq->pio_alloc_pkt_count = pkt_count;
- ereq->pio_pkt_count = pkt_count;
- ereq->tr_sub_flags = req_mapped->tr_sub_flags;
- /* Init the Isoc descriptors */
- for (i = 0; i < pkt_count; i++) {
- ipds[i].length = req_mapped->per_io_frame_descs[i].length;
- ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
- ipds[i].status = req_mapped->per_io_frame_descs[i].status; /* 0 */
- ipds[i].actual_length =
- req_mapped->per_io_frame_descs[i].actual_length;
- }
- return 0;
- }
- static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
- {
- struct dwc_iso_pkt_desc_port *xfd = NULL;
- int i;
- DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
- DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
- DWC_DEBUG("error_count=%d", ereq->error_count);
- DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
- DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
- DWC_DEBUG("res=%d", ereq->res);
- for (i = 0; i < ereq->pio_pkt_count; i++) {
- xfd = &ereq->per_io_frame_descs[0];
- DWC_DEBUG("FD #%d", i);
- DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
- DWC_DEBUG("xfd->length=%d", xfd->length);
- DWC_DEBUG("xfd->offset=%d", xfd->offset);
- DWC_DEBUG("xfd->status=%d", xfd->status);
- }
- }
- /**
- *
- */
- int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
- uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
- int zero, void *req_handle, int atomic_alloc,
- void *ereq_nonport)
- {
- dwc_otg_pcd_request_t *req = NULL;
- dwc_otg_pcd_ep_t *ep;
- dwc_irqflags_t flags;
- int res;
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep) {
- DWC_WARN("bad ep\n");
- return -DWC_E_INVALID;
- }
- /* We support this extension only for DDMA mode */
- if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
- if (!GET_CORE_IF(pcd)->dma_desc_enable)
- return -DWC_E_INVALID;
- /* Create a dwc_otg_pcd_request_t object */
- if (atomic_alloc) {
- req = DWC_ALLOC_ATOMIC(sizeof(*req));
- } else {
- req = DWC_ALLOC(sizeof(*req));
- }
- if (!req) {
- return -DWC_E_NO_MEMORY;
- }
- /* Create the Isoc descs for this request which shall be the exact match
- * of the structure sent to us from the non-portable logic */
- res =
- dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
- if (res) {
- DWC_WARN("Failed to init the Isoc descriptors");
- DWC_FREE(req);
- return res;
- }
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
- req->buf = buf;
- req->dma = dma_buf;
- req->length = buflen;
- req->sent_zlp = zero;
- req->priv = req_handle;
- //DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- ep->dwc_ep.dma_addr = dma_buf;
- ep->dwc_ep.start_xfer_buff = buf;
- ep->dwc_ep.xfer_buff = buf;
- ep->dwc_ep.xfer_len = 0;
- ep->dwc_ep.xfer_count = 0;
- ep->dwc_ep.sent_zlp = 0;
- ep->dwc_ep.total_len = buflen;
- /* Add this request to the tail */
- DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
- ep->dwc_ep.xiso_queued_xfers++;
- //DWC_DEBUG("CP_0");
- //DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
- //prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
- //prn_ext_request(&req->ext_req);
- //DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- /* If the req->status == ASAP then check if there is any active transfer
- * for this endpoint. If no active transfers, then get the first entry
- * from the queue and start that transfer
- */
- if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
- res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
- if (res) {
- DWC_WARN("Failed to start the next Isoc transfer");
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- DWC_FREE(req);
- return res;
- }
- }
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- return 0;
- }
- #endif
- /* END ifdef DWC_UTE_PER_IO ***************************************************/
- int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
- uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
- int zero, void *req_handle, int atomic_alloc)
- {
- dwc_irqflags_t flags;
- dwc_otg_pcd_request_t *req;
- dwc_otg_pcd_ep_t *ep;
- uint32_t max_transfer;
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
- DWC_WARN("bad ep\n");
- return -DWC_E_INVALID;
- }
- if (atomic_alloc) {
- req = DWC_ALLOC_ATOMIC(sizeof(*req));
- } else {
- req = DWC_ALLOC(sizeof(*req));
- }
- if (!req) {
- return -DWC_E_NO_MEMORY;
- }
- DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
- if (!GET_CORE_IF(pcd)->core_params->opt) {
- if (ep->dwc_ep.num != 0) {
- DWC_ERROR("queue req %p, len %d buf %p\n",
- req_handle, buflen, buf);
- }
- }
- req->buf = buf;
- req->dma = dma_buf;
- req->length = buflen;
- req->sent_zlp = zero;
- req->priv = req_handle;
- req->dw_align_buf = NULL;
- if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
- && !GET_CORE_IF(pcd)->dma_desc_enable)
- req->dw_align_buf = DWC_DMA_ALLOC(buflen,
- &req->dw_align_buf_dma);
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- /*
- * After adding request to the queue for IN ISOC wait for In Token Received
- * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token
- * Received when EP is disabled interrupt to obtain starting microframe
- * (odd/even) start transfer
- */
- if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
- {
- if (req != 0) {
- depctl_data_t depctl = {.d32 = DWC_READ_REG32(&pcd->core_if->dev_if->in_ep_regs[ep->dwc_ep.num]->diepctl)};
- ++pcd->request_pending;
- DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
- if (ep->dwc_ep.is_in)
- {
- depctl.b.cnak = 1;
- DWC_WRITE_REG32(&pcd->core_if->dev_if->in_ep_regs[ep->dwc_ep.num]->diepctl, depctl.d32);
- }
-
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- }
- return 0;
- }
- /*
- * For EP0 IN without premature status, zlp is required?
- */
- if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
- DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
- //_req->zero = 1;
- }
- /* Start the transfer */
- if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
- /* EP0 Transfer? */
- if (ep->dwc_ep.num == 0) {
- switch (pcd->ep0state) {
- case EP0_IN_DATA_PHASE:
- DWC_DEBUGPL(DBG_PCD,
- "%s ep0: EP0_IN_DATA_PHASE\n",
- __func__);
- break;
- case EP0_OUT_DATA_PHASE:
- DWC_DEBUGPL(DBG_PCD,
- "%s ep0: EP0_OUT_DATA_PHASE\n",
- __func__);
- if (pcd->request_config) {
- /* Complete STATUS PHASE */
- ep->dwc_ep.is_in = 1;
- pcd->ep0state = EP0_IN_STATUS_PHASE;
- }
- break;
- case EP0_IN_STATUS_PHASE:
- DWC_DEBUGPL(DBG_PCD,
- "%s ep0: EP0_IN_STATUS_PHASE\n",
- __func__);
- break;
- default:
- DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
- pcd->ep0state);
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- return -DWC_E_SHUTDOWN;
- }
- ep->dwc_ep.dma_addr = dma_buf;
- ep->dwc_ep.start_xfer_buff = buf;
- ep->dwc_ep.xfer_buff = buf;
- ep->dwc_ep.xfer_len = buflen;
- ep->dwc_ep.xfer_count = 0;
- ep->dwc_ep.sent_zlp = 0;
- ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
- if (zero) {
- if ((ep->dwc_ep.xfer_len %
- ep->dwc_ep.maxpacket == 0)
- && (ep->dwc_ep.xfer_len != 0)) {
- ep->dwc_ep.sent_zlp = 1;
- }
- }
- dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
- &ep->dwc_ep);
- } // non-ep0 endpoints
- else {
- #ifdef DWC_UTE_CFI
- if (ep->dwc_ep.buff_mode != BM_STANDARD) {
- /* store the request length */
- ep->dwc_ep.cfi_req_len = buflen;
- pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
- ep, req);
- } else {
- #endif
- max_transfer =
- GET_CORE_IF(ep->pcd)->
- core_params->max_transfer_size;
- /* Setup and start the Transfer */
- if (req->dw_align_buf){
- if (ep->dwc_ep.is_in)
- dwc_memcpy(req->dw_align_buf, buf, buflen);
- ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
- ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
- ep->dwc_ep.xfer_buff = req->dw_align_buf;
- } else {
- ep->dwc_ep.dma_addr = dma_buf;
- ep->dwc_ep.start_xfer_buff = buf;
- ep->dwc_ep.xfer_buff = buf;
- }
- ep->dwc_ep.xfer_len = 0;
- ep->dwc_ep.xfer_count = 0;
- ep->dwc_ep.sent_zlp = 0;
- ep->dwc_ep.total_len = buflen;
- ep->dwc_ep.maxxfer = max_transfer;
- if (GET_CORE_IF(pcd)->dma_desc_enable) {
- uint32_t out_max_xfer =
- DDMA_MAX_TRANSFER_SIZE -
- (DDMA_MAX_TRANSFER_SIZE % 4);
- if (ep->dwc_ep.is_in) {
- if (ep->dwc_ep.maxxfer >
- DDMA_MAX_TRANSFER_SIZE) {
- ep->dwc_ep.maxxfer =
- DDMA_MAX_TRANSFER_SIZE;
- }
- } else {
- if (ep->dwc_ep.maxxfer >
- out_max_xfer) {
- ep->dwc_ep.maxxfer =
- out_max_xfer;
- }
- }
- }
- if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
- ep->dwc_ep.maxxfer -=
- (ep->dwc_ep.maxxfer %
- ep->dwc_ep.maxpacket);
- }
- if (zero) {
- if ((ep->dwc_ep.total_len %
- ep->dwc_ep.maxpacket == 0)
- && (ep->dwc_ep.total_len != 0)) {
- ep->dwc_ep.sent_zlp = 1;
- }
- }
- #ifdef DWC_UTE_CFI
- }
- #endif
- dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
- &ep->dwc_ep);
- }
- }
- if (req != 0) {
- ++pcd->request_pending;
- DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
- if (ep->dwc_ep.is_in && ep->stopped
- && !(GET_CORE_IF(pcd)->dma_enable)) {
- /** @todo NGS Create a function for this. */
- diepmsk_data_t diepmsk = {.d32 = 0 };
- diepmsk.b.intktxfemp = 1;
- if (GET_CORE_IF(pcd)->multiproc_int_enable) {
- DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
- dev_global_regs->
- diepeachintmsk[ep->dwc_ep.num],
- 0, diepmsk.d32);
- } else {
- DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
- dev_global_regs->diepmsk, 0,
- diepmsk.d32);
- }
- }
- }
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- return 0;
- }
- int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
- void *req_handle)
- {
- dwc_irqflags_t flags;
- dwc_otg_pcd_request_t *req;
- dwc_otg_pcd_ep_t *ep;
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
- DWC_WARN("bad argument\n");
- return -DWC_E_INVALID;
- }
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- /* make sure it's actually queued on this endpoint */
- DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
- if (req->priv == (void *)req_handle) {
- break;
- }
- }
- if (req->priv != (void *)req_handle) {
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- return -DWC_E_INVALID;
- }
- if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
- dwc_otg_request_done(ep, req, -DWC_E_RESTART);
- } else {
- req = NULL;
- }
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- return req ? 0 : -DWC_E_SHUTDOWN;
- }
- int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
- {
- dwc_otg_pcd_ep_t *ep;
- dwc_irqflags_t flags;
- int retval = 0;
- ep = get_ep_from_handle(pcd, ep_handle);
- if (!ep || (!ep->desc && ep != &pcd->ep0) ||
- (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
- DWC_WARN("%s, bad ep\n", __func__);
- return -DWC_E_INVALID;
- }
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
- DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
- ep->dwc_ep.is_in ? "IN" : "OUT");
- retval = -DWC_E_AGAIN;
- } else if (value == 0) {
- dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
- } else if (value == 1) {
- if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
- dtxfsts_data_t txstatus;
- fifosize_data_t txfifosize;
- txfifosize.d32 =
- DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
- dtxfsiz[ep->dwc_ep.tx_fifo_num]);
- txstatus.d32 =
- DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
- in_ep_regs[ep->dwc_ep.num]->dtxfsts);
- if (txstatus.b.txfspcavail < txfifosize.b.depth) {
- DWC_WARN("%s() Data In Tx Fifo\n", __func__);
- retval = -DWC_E_AGAIN;
- } else {
- if (ep->dwc_ep.num == 0) {
- pcd->ep0state = EP0_STALL;
- }
- ep->stopped = 1;
- dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
- &ep->dwc_ep);
- }
- } else {
- if (ep->dwc_ep.num == 0) {
- pcd->ep0state = EP0_STALL;
- }
- ep->stopped = 1;
- dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
- }
- } else if (value == 2) {
- ep->dwc_ep.stall_clear_flag = 0;
- } else if (value == 3) {
- ep->dwc_ep.stall_clear_flag = 1;
- }
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- return retval;
- }
- /**
- * This function initiates remote wakeup of the host from suspend state.
- */
- void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
- {
- dctl_data_t dctl = { 0 };
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
- dsts_data_t dsts;
- dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
- if (!dsts.b.suspsts) {
- DWC_WARN("Remote wakeup while is not in suspend state\n");
- }
- /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
- if (pcd->remote_wakeup_enable) {
- if (set) {
- if (core_if->adp_enable) {
- gpwrdn_data_t gpwrdn;
- dwc_otg_adp_probe_stop(core_if);
- /* Mask 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, gpwrdn.d32, 0);
- /* Disable Power Down Logic */
- gpwrdn.d32 = 0;
- gpwrdn.b.pmuactv = 1;
- DWC_MODIFY_REG32(&core_if->core_global_regs->
- gpwrdn, gpwrdn.d32, 0);
- /*
- * Initialize the Core for Device mode.
- */
- core_if->op_state = B_PERIPHERAL;
- dwc_otg_core_init(core_if);
- dwc_otg_enable_global_interrupts(core_if);
- cil_pcd_start(core_if);
- dwc_otg_initiate_srp(core_if);
- }
- dctl.b.rmtwkupsig = 1;
- DWC_MODIFY_REG32(&core_if->dev_if->
- dev_global_regs->dctl, 0, dctl.d32);
- DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
- dwc_mdelay(2);
- DWC_MODIFY_REG32(&core_if->dev_if->
- dev_global_regs->dctl, dctl.d32, 0);
- DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
- }
- } else {
- DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
- }
- }
- #ifdef CONFIG_USB_DWC_OTG_LPM
- /**
- * This function initiates remote wakeup of the host from L1 sleep state.
- */
- void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
- {
- glpmcfg_data_t lpmcfg;
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
- lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
- /* Check if we are in L1 state */
- if (!lpmcfg.b.prt_sleep_sts) {
- DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
- return;
- }
- /* Check if host allows remote wakeup */
- if (!lpmcfg.b.rem_wkup_en) {
- DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
- return;
- }
- /* Check if Resume OK */
- if (!lpmcfg.b.sleep_state_resumeok) {
- DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
- return;
- }
- lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
- lpmcfg.b.en_utmi_sleep = 0;
- lpmcfg.b.hird_thres &= (~(1 << 4));
- DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
- if (set) {
- dctl_data_t dctl = {.d32 = 0 };
- dctl.b.rmtwkupsig = 1;
- /* Set RmtWkUpSig bit to start remote wakup signaling.
- * Hardware will automatically clear this bit.
- */
- DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
- 0, dctl.d32);
- DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
- }
- }
- #endif
- /**
- * Performs remote wakeup.
- */
- void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
- {
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
- dwc_irqflags_t flags;
- if (dwc_otg_is_device_mode(core_if)) {
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- #ifdef CONFIG_USB_DWC_OTG_LPM
- if (core_if->lx_state == DWC_OTG_L1) {
- dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
- } else {
- #endif
- dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
- #ifdef CONFIG_USB_DWC_OTG_LPM
- }
- #endif
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- }
- return;
- }
- void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
- {
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
- //dctl_data_t dctl = { 0 };
- if (dwc_otg_is_device_mode(core_if)) {
- //dctl.b.sftdiscon = 1;
- DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
- //DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
- dwc_otg_device_soft_disconnect(core_if);
- dwc_udelay(no_of_usecs);
- //DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
- dwc_otg_device_soft_connect(core_if);
-
- } else{
- DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
- }
- return;
- }
- int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
- {
- dsts_data_t dsts;
- gotgctl_data_t gotgctl;
- /*
- * This function starts the Protocol if no session is in progress. If
- * a session is already in progress, but the device is suspended,
- * remote wakeup signaling is started.
- */
- /* Check if valid session */
- gotgctl.d32 =
- DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
- if (gotgctl.b.bsesvld) {
- /* Check if suspend state */
- dsts.d32 =
- DWC_READ_REG32(&
- (GET_CORE_IF(pcd)->dev_if->
- dev_global_regs->dsts));
- if (dsts.b.suspsts) {
- dwc_otg_pcd_remote_wakeup(pcd, 1);
- }
- } else {
- dwc_otg_pcd_initiate_srp(pcd);
- }
- return 0;
- }
- /**
- * Start the SRP timer to detect when the SRP does not complete within
- * 6 seconds.
- *
- * @param pcd the pcd structure.
- */
- void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
- {
- dwc_irqflags_t flags;
- DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
- dwc_otg_initiate_srp(GET_CORE_IF(pcd));
- DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
- }
- int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
- {
- return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
- }
- int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
- {
- return GET_CORE_IF(pcd)->core_params->lpm_enable;
- }
- uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
- {
- return pcd->b_hnp_enable;
- }
- uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
- {
- return pcd->a_hnp_support;
- }
- uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
- {
- return pcd->a_alt_hnp_support;
- }
- int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
- {
- return pcd->remote_wakeup_enable;
- }
- #endif /* DWC_HOST_ONLY */
|