| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941 |
- /*
- * Copyright (c) 2012 MediaTek Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #include <sys/types.h>
- #include <string.h>
- #include <stdlib.h>
- #include <debug.h>
- #include <reg.h>
- #include <platform/bitops.h>
- #include <platform/errno.h>
- #include <platform/mt_irq.h>
- #include <platform/mt_reg_base.h>
- #include <platform/mt_typedefs.h>
- #include <platform/timer.h>
- #include <kernel/thread.h>
- #include <mt_gic.h>
- #include <dev/udc.h>
- #include <mt_ssusb.h>
- #include <mt_ssusb_sifslv_ippc.h>
- #include <mt_ssusb_usb3_mac_csr.h>
- #ifdef SUPPORT_QMU
- #include <mt_ssusb_qmu.h>
- #include <mt_mu3d_hal_qmu_drv.h>
- #endif
- #define USB_GINTR
- /* DEBUG INFO Sections */
- #ifdef USB_DEBUG
- #define DBG_USB_DUMP_DESC 0
- #define DBG_USB_DUMP_DATA 0
- #define DBG_USB_DUMP_SETUP 1
- #define DBG_USB_FIFO 0
- #define DBG_USB_GENERAL 1
- #define DBG_USB_IRQ 0
- #define DBG_PHY_CALIBRATION 0
- #endif
- #define DBG_C(x...) dprintf(CRITICAL, "[USB] " x)
- #define DBG_I(x...) dprintf(INFO, "[USB] " x)
- #define DBG_S(x...) dprintf(SPEW, "[USB] " x)
- #if DBG_USB_GENERAL
- #define DBG_IRQ(x...) dprintf(INFO, x)
- #else
- #define DBG_IRQ(x...) do{} while(0)
- #endif
- /* bits used in all the endpoint status registers */
- #define EPT_TX(n) (1 << ((n) + 16))
- #define EPT_RX(n) (1 << (n))
- /* udc.h wrapper for usbdcore */
- static unsigned char usb_config_value = 0;
- EP0_STATE ep0_state = EP0_IDLE;
- int set_address = 0;
- u8 g_qmu_init = 0;
- #define EP0 0
- /* USB transfer directions */
- #define USB_DIR_IN DEVICE_WRITE /* val: 0x80 */
- #define USB_DIR_OUT DEVICE_READ /* val: 0x00 */
- /* Request types */
- #define USB_TYPE_STANDARD (0x00 << 5)
- #define USB_TYPE_CLASS (0x01 << 5)
- #define USB_TYPE_VENDOR (0x02 << 5)
- #define USB_TYPE_RESERVED (0x03 << 5)
- /* values used in GET_STATUS requests */
- #define USB_STAT_SELFPOWERED 0x01
- /* USB recipients */
- #define USB_RECIP_DEVICE 0x00
- #define USB_RECIP_INTERFACE 0x01
- #define USB_RECIP_ENDPOINT 0x02
- #define USB_RECIP_OTHER 0x03
- /* Endpoints */
- #define USB_EP_NUM_MASK 0x0f /* in bEndpointAddress */
- #define USB_EP_DIR_MASK 0x80
- #define USB_TYPE_MASK 0x60
- #define USB_RECIP_MASK 0x1f
- #if CFG_FPGA_PLATFORM
- /* for usb phy */
- #include <platform/mt_i2c.h>
- #endif
- #define URB_BUF_SIZE 512
- #define EP0_BUF_SZ 4096
- /* function prototype */
- /* usbphy.c */
- extern void mt_usb_phy_recover(void);
- extern void mt_usb_phy_savecurrent(void);
- extern void mt_usb_phy_poweron(void);
- static struct udc_endpoint *ep0in, *ep0out;
- static struct udc_request *ep0req;
- struct urb mt_ep0_urb;
- struct urb mt_tx_urb;
- struct urb mt_rx_urb;
- struct urb *ep0_urb = &mt_ep0_urb;
- struct urb *tx_urb = &mt_tx_urb;
- struct urb *rx_urb = &mt_rx_urb;
- /* mt_usb related function declaration */
- void mt_setup_ep(unsigned int ep, struct udc_endpoint *endpoint);
- /* from mt_usbtty.h */
- #define NUM_ENDPOINTS 3
- /* origin endpoint_array */
- struct udc_endpoint ep_list[NUM_ENDPOINTS + 1]; /* one extra for control endpoint */
- static int usb_online = 0;
- u32 g_speed = 0;
- static u8 dev_address = 0;
- u32 g_tx_fifo_addr = USB_TX_FIFO_START_ADDRESS;
- u32 g_rx_fifo_addr = USB_RX_FIFO_START_ADDRESS;
- int g_enable_u3 = 0;
- static struct udc_device *the_device;
- static struct udc_gadget *the_gadget;
- /* end from hsusb.c */
- /* declare ept_complete handle */
- static void handle_ept_complete(struct udc_endpoint *ept);
- extern void mt_usb_phy_poweron(void);
- extern void mt_usb_phy_savecurrent(void);
- extern void mt_usb_phy_recover(void);
- /* get_max_packet_size */
- int get_max_packet_size(int enable_u3)
- {
- if (enable_u3 != 0) {
- return EP0_MAX_PACKET_SIZE;
- } else {
- return EP0_MAX_PACKET_SIZE_U3;
- }
- }
- void board_usb_init(void)
- {
- mt_usb_phy_poweron();
- mt_usb_phy_savecurrent();
- }
- struct udc_descriptor {
- struct udc_descriptor *next;
- unsigned short tag; /* ((TYPE << 8) | NUM) */
- unsigned short len; /* total length */
- unsigned char data[0];
- };
- #if DBG_USB_DUMP_SETUP
- static void dump_setup_packet(char *str, struct setup_packet *sp)
- {
- DBG_I("\n");
- DBG_I("%s", str);
- DBG_I(" bmRequestType = %x\n", sp->type);
- DBG_I(" bRequest = %x\n", sp->request);
- DBG_I(" wValue = %x\n", sp->value);
- DBG_I(" wIndex = %x\n", sp->index);
- DBG_I(" wLength = %x\n", sp->length);
- }
- #else
- static void dump_setup_packet(char *str, struct setup_packet *sp) {}
- #endif
- #if defined(DBG_USB_EP0CSR)
- void explain_csr0(u32 csr0)
- {
- if (csr0 & EP0_EP_RESET) {
- DBG_I("EP0_EP_RESET is set");
- }
- if (csr0 & EP0_AUTOCLEAR) {
- DBG_I("EP0_AUTOCLEAR is set");
- }
- if (csr0 & EP0_AUTOSET) {
- DBG_I("EP0_AUTOSET is set");
- }
- if (csr0 & EP0_DMAREQEN) {
- DBG_I("EP0_DMAREQEN is set");
- }
- if (csr0 & EP0_SENDSTALL) {
- DBG_I("EP0_SENDSTALL is set");
- }
- if (csr0 & EP0_FIFOFULL) {
- DBG_I("EP0_FIFOFULL is set");
- }
- if (csr0 & EP0_SENTSTALL) {
- DBG_I("EP0_SENTSTALL is set");
- }
- if (csr0 & EP0_DPHTX) {
- DBG_I("EP0_DPHTX is set");
- }
- if (csr0 & EP0_DATAEND) {
- DBG_I("EP0_DATAEND is set");
- }
- if (csr0 & EP0_TXPKTRDY) {
- DBG_I("EP0_TXPKTRDY is set");
- }
- if (csr0 & EP0_SETUPPKTRDY) {
- DBG_I("EP0_SETUPPKTRDY is set");
- }
- if (csr0 & EP0_RXPKTRDY) {
- DBG_I("EP0_RXPKTRDY is set");
- }
- }
- #endif
- static void copy_desc(struct urb *urb, void *data, int length)
- {
- #if DBG_USB_FIFO
- DBG_I("%s: urb: %p, data %p, length: %d, actual_length: %d\n",
- __func__, urb->buf, data, length, urb->actual_length);
- #endif
- //memcpy(urb->buf + urb->actual_length, data, length);
- memcpy(urb->buf, data, length);
- //urb->actual_length += length;
- urb->actual_length = length;
- #if DBG_USB_FIFO
- DBG_I("%s: urb: %p, data %p, length: %d, actual_length: %d\n",
- __func__, urb->buf, data, length, urb->actual_length);
- #endif
- }
- struct udc_descriptor *udc_descriptor_alloc(unsigned type, unsigned num,
- unsigned len)
- {
- struct udc_descriptor *desc;
- if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
- return 0;
- if (!(desc = malloc(sizeof(struct udc_descriptor) + len)))
- return 0;
- desc->next = 0;
- desc->tag = (type << 8) | num;
- desc->len = len;
- desc->data[0] = len;
- desc->data[1] = type;
- return desc;
- }
- static struct udc_descriptor *desc_list = 0;
- static unsigned next_string_id = 1;
- #ifdef SUPPORT_U3
- static struct udc_descriptor *desc_list_u3 = 0;
- static unsigned next_string_id_u3 = 1;
- #endif
- void udc_descriptor_register(struct udc_descriptor *desc)
- {
- desc->next = desc_list;
- desc_list = desc;
- }
- #ifdef SUPPORT_U3
- void udc_descriptor_register_u3(struct udc_descriptor *desc)
- {
- desc->next = desc_list_u3;
- desc_list_u3 = desc;
- }
- #endif
- unsigned udc_string_desc_alloc(const char *str)
- {
- unsigned len;
- struct udc_descriptor *desc;
- unsigned char *data;
- if (next_string_id > 255)
- return 0;
- if (!str)
- return 0;
- len = strlen(str);
- desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
- if (!desc)
- return 0;
- next_string_id++;
- /* expand ascii string to utf16 */
- data = desc->data + 2;
- while (len-- > 0) {
- *data++ = *str++;
- *data++ = 0;
- }
- udc_descriptor_register(desc);
- return desc->tag & 0xff;
- }
- #ifdef SUPPORT_U3
- unsigned udc_string_desc_alloc_u3(const char *str)
- {
- unsigned len;
- struct udc_descriptor *desc;
- unsigned char *data;
- if (next_string_id_u3 > 255)
- return 0;
- if (!str)
- return 0;
- len = strlen(str);
- desc = udc_descriptor_alloc(TYPE_STRING, next_string_id_u3, len * 2 + 2);
- if (!desc)
- return 0;
- next_string_id_u3++;
- /* expand ascii string to utf16 */
- data = desc->data + 2;
- while (len-- > 0) {
- *data++ = *str++;
- *data++ = 0;
- }
- udc_descriptor_register_u3(desc);
- return desc->tag & 0xff;
- }
- #endif
- /* mt_udc_state related functions */
- /*
- * If abnormal DATA transfer happened, like USB unplugged,
- * we cannot fix this after mt_udc_reset().
- * Because sometimes there will come reset twice.
- */
- static void mt_udc_suspend(void)
- {
- /* handle abnormal DATA transfer if we had any */
- struct udc_endpoint *endpoint;
- int i;
- /* initialize flags */
- usb_online = 0;
- usb_config_value = 0;
- the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
- /* error out any pending reqs */
- for (i = 1; i < MT_EP_NUM; i++) {
- /* ensure that ept_complete considers
- * this to be an error state
- */
- /* End operation when encounter uninitialized ept */
- if (ep_list[i].num == 0)
- break;
- #if DBG_USB_GENERAL
- DBG_I("%s: ep: %i, in: %s, req: %p\n",
- __func__, ep_list[i].num, ep_list[i].in ? "IN" : "OUT", ep_list[i].req);
- #endif
- /* do nothing if usb_online == 0 */
- if ((ep_list[i].req && (ep_list[i].in == 0)) || /* USB_DIR_OUT */
- (ep_list[i].req && (ep_list[i].in == 1))) { /* USB_DIR_IN */
- ep_list[i].status = -1; /* HALT */
- endpoint = &ep_list[i];
- handle_ept_complete(endpoint);
- }
- }
- /* this is required for error handling during data transfer */
- txn_status = -1;
- #if defined(SUPPORT_QMU)
- /* stop qmu engine */
- mu3d_hal_stop_qmu(1, USB_DIR_IN);
- mu3d_hal_stop_qmu(1, USB_DIR_OUT);
- /* disable qmu interrupts */
- writel(0x0, U3D_QGCSR);
- writel(0x0, U3D_QIESR0);
- writel(0x0, U3D_QIESR1);
- /* do qmu flush */
- mu3d_hal_flush_qmu(1, USB_DIR_IN);
- mu3d_hal_flush_qmu(1, USB_DIR_OUT);
- /* mu3d_hal_reset_ep: we do reset here only, do not start qmu here */
- mu3d_hal_reset_qmu_ep(1, USB_DIR_IN);
- mu3d_hal_reset_qmu_ep(1, USB_DIR_OUT);
- #endif
- }
- /* mu3d hal related functions */
- /* functinos used by mu3d hal functions */
- int wait_for_value(int addr, unsigned int msk, unsigned int value, int ms_intvl, int count)
- {
- int i;
- for (i = 0; i < count; i++) {
- if ((readl(addr) & msk) == value)
- return RET_SUCCESS;
- mdelay(ms_intvl);
- }
- return RET_FAIL;
- }
- /*
- * mu3d_hal_pio_read_fifo - pio read one packet
- * @args - arg1: ep number, arg2: data buffer
- */
- int mu3d_hal_pio_read_fifo(int ep_num, u8 *p_buf)
- {
- u32 count = 0, residue = 0;
- u32 temp = 0;
- u8 *p_tmpbuf = p_buf;
- if (ep_num == 0) {
- residue = count = readl(U3D_RXCOUNT0);
- } else {
- residue = count = USB_READCSR32(U3D_RX1CSR3, ep_num) >> 16;
- }
- while (residue > 0) {
- temp = readl(USB_FIFO(ep_num));
- *p_tmpbuf = temp&0xFF;
- if (residue > 1)
- *(p_tmpbuf + 1) = (temp >> 8)&0xFF;
- if (residue > 2)
- *(p_tmpbuf + 2) = (temp >> 16)&0xFF;
- if (residue > 3)
- *(p_tmpbuf + 3) = (temp >> 24)&0xFF;
- if (residue > 4) {
- p_tmpbuf = p_tmpbuf + 4;
- residue -= 4;
- } else {
- residue = 0;
- }
- }
- return count;
- }
- /*
- * mu3d_hal_pio_write_fifo - pio write one packet
- * @args - arg1: ep number, arg2: data buffer
- */
- int mu3d_hal_pio_write_fifo(int ep_num, int length, u8 *p_buf, int maxp)
- {
- u32 residue = length;
- u32 temp = 0;
- #if DBG_USB_FIFO
- DBG_I("%s process p_num: %d, length: %d, buf: %p, maxp: %d\n",
- __func__, ep_num, length, p_buf, maxp);
- #endif
- while (residue > 0) {
- switch (residue) {
- case 1:
- temp = ((*p_buf) & 0xFF);
- writeb(temp, USB_FIFO(ep_num));
- p_buf += 1;
- residue -= 1;
- break;
- case 2:
- temp = ((*p_buf) & 0xFF)
- + (((*(p_buf + 1)) << 8)&0xFF00);
- writew(temp, USB_FIFO(ep_num));
- p_buf += 2;
- residue -= 2;
- udelay(50);
- break;
- case 3:
- temp = ((*p_buf) & 0xFF)
- + (((*(p_buf+1)) << 8)&0xFF00);
- writew(temp, USB_FIFO(ep_num));
- p_buf += 2;
- temp = ((*p_buf)&0xFF);
- writeb(temp, USB_FIFO(ep_num));
- p_buf += 1;
- residue -= 3;
- break;
- default:
- temp = ((*p_buf) & 0xFF)
- + (((*(p_buf + 1)) << 8)&0xFF00)
- + (((*(p_buf + 2)) << 16)&0xFF0000)
- + (((unsigned)(*(p_buf + 3)) << 24)&0xFF000000);
- writel(temp, USB_FIFO(ep_num));
- p_buf += 4;
- residue -= 4;
- break;
- };
- }
- return length;
- }
- /*
- * mu3d_hal_check_clk_sts - check sys125,u3 mac,u2 mac clock status
- */
- int mu3d_hal_check_clk_sts(void)
- {
- int ret;
- ret = wait_for_value(U3D_SSUSB_IP_PW_STS1, SSUSB_SYS125_RST_B_STS, SSUSB_SYS125_RST_B_STS, 1, 10);
- if (ret == RET_FAIL) {
- DBG_I("SSUSB_SYS125_RST_B_STS NG\n");
- goto CHECK_ERROR;
- } else {
- DBG_I("clk sys125:OK\n");
- }
- #ifdef SUPPORT_U3
- ret = wait_for_value(U3D_SSUSB_IP_PW_STS1, SSUSB_U3_MAC_RST_B_STS, SSUSB_U3_MAC_RST_B_STS, 1, 10);
- if (ret == RET_FAIL) {
- DBG_I("SSUSB_U3_MAC_RST_B_STS NG\n");
- goto CHECK_ERROR;
- } else {
- DBG_I("clk mac3:OK\n");
- }
- #endif
- ret = wait_for_value(U3D_SSUSB_IP_PW_STS2, SSUSB_U2_MAC_SYS_RST_B_STS, SSUSB_U2_MAC_SYS_RST_B_STS, 1, 10);
- if (ret == RET_FAIL) {
- DBG_I("SSUSB_U2_MAC_SYS_RST_B_STS NG\n");
- goto CHECK_ERROR;
- } else {
- DBG_I("clk mac2:OK\n");
- }
- return RET_SUCCESS;
- CHECK_ERROR:
- DBG_I("Reference clock stability check failed!\n");
- return RET_FAIL;
- }
- /*
- * mu3d_hal_ssusb_en - disable ssusb power down & enable u2/u3 ports
- */
- void mu3d_hal_ssusb_en(void)
- {
- clrbits(U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
- clrbits(U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
- #if defined(SUPPORT_U3) || defined(CFG_FPGA_PLATFORM)
- clrbits(U3D_SSUSB_U3_CTRL_0P, (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_HOST_SEL));
- #endif
- clrbits(U3D_SSUSB_U2_CTRL_0P, (SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_HOST_SEL));
- setbits(U3D_SSUSB_REF_CK_CTRL, (SSUSB_REF_MAC_CK_GATE_EN | SSUSB_REF_PHY_CK_GATE_EN | SSUSB_REF_CK_GATE_EN | SSUSB_REF_MAC3_CK_GATE_EN));
- /* check U3D sys125,u3 mac,u2 mac clock status. */
- mu3d_hal_check_clk_sts();
- }
- /*
- * mu3d_hal_u2dev_connect - u2 device softconnect
- */
- void mu3d_hal_u2dev_connect(void)
- {
- setbits(U3D_POWER_MANAGEMENT, SOFT_CONN);
- }
- void mu3d_hal_u2dev_disconnect(void)
- {
- clrbits(U3D_POWER_MANAGEMENT, SOFT_CONN);
- }
- void mu3d_hal_u3dev_connect(void)
- {
- #ifdef SUPPORT_U3
- setbits(U3D_USB3_CONFIG, USB3_EN);
- mdelay(40);
- #endif
- }
- void mu3d_hal_u3dev_disconnect(void)
- {
- #ifdef SUPPORT_U3
- clrbits(U3D_USB3_CONFIG, USB3_EN);
- #endif
- }
- /*
- * mu3d_hal_set_speed - enable ss or connect to hs/fs
- * @args - arg1: speed
- */
- void mu3d_hal_set_speed(USB_SPEED speed)
- {
- /* clear ltssm state */
- #ifdef DBG_USB_GENERAL
- DBG_I("%s\n", __func__);
- #endif
- switch (speed) {
- case SSUSB_SPEED_FULL:
- clrbits(U3D_POWER_MANAGEMENT, HS_ENABLE);
- break;
- case SSUSB_SPEED_HIGH:
- enable_highspeed(); /* usbtty.c */
- setbits(U3D_POWER_MANAGEMENT, HS_ENABLE);
- DBG_C("USB: speed HS!!\n");
- break;
- #if defined(SUPPORT_U3)
- case SSUSB_SPEED_SUPER:
- enable_superspeed(); /* usbtty.c */
- setbits(U3D_POWER_MANAGEMENT, HS_ENABLE);
- g_enable_u3 = true;
- DBG_C("USB: speed SS!!\n");
- break;
- #endif
- default:
- DBG_C("Unsupported speed %d!!\n", speed);
- /*
- * work around: Disconnect U3 will stop here,
- * we need to call mt_udc_suspend since there
- * is no SUSPEND interrupt when U3 was connected before.
- */
- mt_udc_suspend();
- break;
- };
- }
- void mu3d_hal_rst_dev(void)
- {
- int ret;
- writel(SSUSB_DEV_SW_RST, U3D_SSUSB_DEV_RST_CTRL);
- writel(0, U3D_SSUSB_DEV_RST_CTRL);
- /* do not check when SSUSB_U2_PORT_DIS = 1, because U2 port stays in reset state */
- if (!(readl(U3D_SSUSB_U2_CTRL_0P) & SSUSB_U2_PORT_DIS)) {
- ret = wait_for_value(U3D_SSUSB_IP_PW_STS2, SSUSB_U2_MAC_SYS_RST_B_STS, SSUSB_U2_MAC_SYS_RST_B_STS, 1, 10);
- if (ret == RET_FAIL)
- DBG_C("[ERR]: SSUSB_U2_MAC_SYS_RST_B_STS NG\n");
- }
- #ifdef SUPPORT_U3
- /* do not check when SSUSB_U3_PORT_PDN = 1, because U3 port stays in reset state */
- if (!(readl(U3D_SSUSB_U3_CTRL_0P) & SSUSB_U3_PORT_PDN)) {
- ret = wait_for_value(U3D_SSUSB_IP_PW_STS1, SSUSB_U3_MAC_RST_B_STS, SSUSB_U3_MAC_RST_B_STS, 1, 10);
- if (ret == RET_FAIL)
- DBG_C("[ERR]: SSUSB_U3_MAC_RST_B_STS NG\n");
- }
- #endif
- ret = wait_for_value(U3D_SSUSB_IP_PW_STS1, SSUSB_DEV_QMU_RST_B_STS, SSUSB_DEV_QMU_RST_B_STS, 1, 10);
- if (ret == RET_FAIL)
- DBG_C("[ERR]: %d SSUSB_DEV_QMU_RST_B_STS NG\n", __LINE__);
- ret = wait_for_value(U3D_SSUSB_IP_PW_STS1, SSUSB_DEV_BMU_RST_B_STS, SSUSB_DEV_BMU_RST_B_STS, 1, 10);
- if (ret == RET_FAIL)
- DBG_C("[ERR]: %d SSUSB_DEV_BMU_RST_B_STS NG\n", __LINE__);
- ret = wait_for_value(U3D_SSUSB_IP_PW_STS1, SSUSB_DEV_RST_B_STS, SSUSB_DEV_RST_B_STS, 1, 10);
- if (ret == RET_FAIL)
- DBG_C("[ERR]: %d SSUSB_DEV_RST_B_STS NG\n", __LINE__);
- mdelay(50);
- }
- /*
- * mu3d_hal_system_intr_en - enable system global interrupt
- */
- void mu3d_hal_system_intr_en(void)
- {
- u32 int_en;
- #ifdef SUPPORT_U3
- u32 ltssm_int_en;
- #endif
- writel(readl(U3D_EPIER), U3D_EPIECR);
- writel(readl(U3D_DMAIER), U3D_DMAIECR);
- /* clear and enable common USB interrupts */
- writel(0, U3D_COMMON_USB_INTR_ENABLE);
- writel(readl(U3D_COMMON_USB_INTR), U3D_COMMON_USB_INTR);
- int_en = SUSPEND_INTR_EN | RESUME_INTR_EN | RESET_INTR_EN | CONN_INTR_EN |
- DISCONN_INTR_EN | VBUSERR_INTR_EN | LPM_INTR_EN | LPM_RESUME_INTR_EN;
- writel(int_en, U3D_COMMON_USB_INTR_ENABLE);
- #ifdef SUPPORT_U3
- /* clear and enable LTSSM interrupts */
- writel(0, U3D_LTSSM_INTR_ENABLE);
- writel(readl(U3D_LTSSM_INTR), U3D_LTSSM_INTR);
- ltssm_int_en = SS_INACTIVE_INTR_EN | SS_DISABLE_INTR_EN | COMPLIANCE_INTR_EN |
- LOOPBACK_INTR_EN | HOT_RST_INTR_EN | WARM_RST_INTR_EN | RECOVERY_INTR_EN |
- ENTER_U0_INTR_EN | ENTER_U1_INTR_EN | ENTER_U2_INTR_EN | ENTER_U3_INTR_EN |
- EXIT_U1_INTR_EN | EXIT_U2_INTR_EN | EXIT_U3_INTR_EN | RXDET_SUCCESS_INTR_EN |
- VBUS_RISE_INTR_EN | VBUS_FALL_INTR_EN | U3_LFPS_TMOUT_INTR_EN |
- U3_RESUME_INTR_EN;
- writel(ltssm_int_en, U3D_LTSSM_INTR_ENABLE);
- #endif
- writel(SSUSB_DEV_SPEED_CHG_INTR_EN, U3D_DEV_LINK_INTR_ENABLE);
- }
- void mu3d_hal_disable_intr(void)
- {
- writel(0xffffffff, U3D_EPISR);
- writel(0xffffffff, U3D_DMAISR);
- writel(0xffffffff, U3D_QISAR0);
- writel(0xffffffff, U3D_QISAR1);
- writel(0xffffffff, U3D_QEMIR);
- writel(0xffffffff, U3D_TQERRIR0);
- writel(0xffffffff, U3D_RQERRIR0);
- writel(0xffffffff, U3D_RQERRIR1);
- writel(0xffffffff, U3D_LV1IECR);
- writel(0xffffffff, U3D_EPIECR);
- writel(0xffffffff, U3D_DMAIECR);
- /* clear registers */
- writel(0xffffffff, U3D_QIECR0);
- writel(0xffffffff, U3D_QIECR1);
- writel(0xffffffff, U3D_QEMIECR);
- writel(0xffffffff, U3D_TQERRIECR0);
- writel(0xffffffff, U3D_RQERRIECR0);
- writel(0xffffffff, U3D_RQERRIECR1);
- }
- /* usb generic functions */
- static int mt_read_fifo(struct udc_endpoint *endpoint)
- {
- struct urb *urb = endpoint->rcv_urb;
- int len = 0, count = 0;
- int ep_num = endpoint->num;
- unsigned char *cp;
- if (ep_num == EP0)
- urb = ep0_urb;
- if (urb) {
- cp = (u8 *) (urb->buf + urb->actual_length);
- #if DBG_USB_FIFO
- DBG_I("%s: ep_num: %d, urb: %p, urb->buf: %p, urb->actual_length = %d\n",
- __func__, ep_num, urb, urb->buf, urb->actual_length);
- #endif
- count = len = mu3d_hal_pio_read_fifo(ep_num, cp);
- if (ep_num != 0) {
- #if DBG_USB_FIFO
- DBG_I("%s: ep_num: %d count = %d\n",
- __func__, ep_num, count);
- #endif
- }
- #if DBG_USB_DUMP_DATA
- if (ep_num != 0) {
- DBG_I("%s: &urb->buf: %p\n", __func__, urb->buf);
- DBG_I("dump data:\n");
- hexdump8(urb->buf, count);
- }
- #endif
- urb->actual_length += count;
- }
- return count;
- }
- /* Linux txstate() ?? */
- static int mt_write_fifo(struct udc_endpoint *ept)
- {
- int ep_num = ept->num;
- struct urb *urb = ept->tx_urb;
- int last = 0, count = 0;
- unsigned char *buf = NULL;
- u32 wrote = 0;
- if (ep_num == EP0)
- urb = ep0_urb;
- if (urb) {
- #if DBG_USB_DUMP_DESC
- DBG_I("%s: dump desc\n", __func__);
- hexdump8(urb->buf, urb->actual_length);
- #endif
- #if DBG_USB_FIFO
- DBG_I("%s: ep_num: %d urb: %p, actual_length: %d\n",
- __func__, ep_num, urb, urb->actual_length);
- DBG_I("%s: sent: %d, tx_pkt_size: %d\n", __func__, ept->sent, ept->maxpkt);
- #endif
- count = last = MIN (urb->actual_length - ept->sent, ept->maxpkt);
- #if DBG_USB_FIFO
- DBG_I ("[%s] urb->actual_length = %d, ept->sent = %d\n",
- __func__, urb->actual_length, ept->sent);
- #endif
- do {
- buf = urb->buf + ept->sent;
- /* do not use "urb->ept->tx_pktsz */
- wrote = mu3d_hal_pio_write_fifo(ep_num, count, buf, ept->maxpkt);
- count -= wrote;
- } while (count > 0);
- ept->last = last;
- ept->sent += last;
- }
- return last;
- }
- struct udc_endpoint *mt_find_ep(int ep_num, u8 dir)
- {
- int i;
- u8 in;
- /* convert dir to in */
- if (dir == USB_DIR_IN) /* dir == USB_DIR_IN */
- in = 1;
- else
- in = 0;
- for (i = 0; i < MT_EP_NUM; i++) {
- if ((ep_list[i].num == ep_num) && (ep_list[i].in == in)) {
- #if DBG_USB_GENERAL
- DBG_I("%s: find ep!\n", __func__);
- #endif
- return &ep_list[i];
- }
- }
- return NULL;
- }
- static void mt_udc_flush_fifo(u8 ep_num, u8 dir)
- {
- struct udc_endpoint *endpoint;
- if (ep_num == 0) {
- setbits(U3D_EP_RST, EP0_RST);
- clrbits(U3D_EP_RST, EP0_RST);
- } else {
- endpoint = mt_find_ep(ep_num, dir);
- if (endpoint == NULL) {
- DBG_C("Error : cant find endpoint!\n");
- return;
- }
- if (endpoint->in == 0) { /* USB_DIR_OUT: val is 0x0; in == 0 here */
- setbits(U3D_EP_RST, (1 << ep_num));//reset RX EP
- clrbits(U3D_EP_RST, (1 << ep_num));//reset reset RX EP
- } else {
- setbits(U3D_EP_RST, (BIT16 << ep_num));//reset TX EP
- clrbits(U3D_EP_RST, (BIT16 << ep_num));//reset reset TX EP
- }
- }
- }
- static void mt_udc_flush_ep0_fifo(void)
- {
- mt_udc_flush_fifo(0, 0);
- }
- /* is_tx_ep_busy: used by usbtty.c */
- int mt_ep_busy(struct udc_endpoint *endpoint)
- {
- int ep_num = endpoint->num;
- u32 csr = 0;
- if (endpoint->in == 0) { /* USB_DIR_OUT: val is 0x0; in == 0 here */
- DBG_I("mt_ep_busy: ep%d is RX endpoint\n", ep_num);
- } else {
- csr = USB_READCSR32(U3D_TX1CSR0, ep_num);
- }
- return (csr & TX_TXPKTRDY);
- }
- static void udc_clean_sentstall(unsigned int ep_num, u8 dir)
- {
- if (ep_num == 0) {
- ep0csr_setbits(EP0_SENDSTALL);
- } else {
- if (dir == USB_DIR_OUT) {
- USB_WRITECSR32(U3D_RX1CSR0, ep_num, USB_READCSR32(U3D_RX1CSR0, ep_num) | RX_SENTSTALL);
- USB_WRITECSR32(U3D_RX1CSR0, ep_num, USB_READCSR32(U3D_RX1CSR0, ep_num) &~ RX_SENDSTALL);
- } else {
- USB_WRITECSR32(U3D_TX1CSR0, ep_num, USB_READCSR32(U3D_TX1CSR0, ep_num) | TX_SENTSTALL);
- USB_WRITECSR32(U3D_TX1CSR0, ep_num, USB_READCSR32(U3D_TX1CSR0, ep_num) &~ TX_SENDSTALL);
- }
- }
- }
- /* the endpoint does not support the received command, stall it!! */
- static void udc_stall_ep(unsigned int ep_num, u8 dir)
- {
- struct udc_endpoint *endpoint = mt_find_ep(ep_num, dir);
- u32 csr;
- if (endpoint == NULL) {
- DBG_C("Error : cant find endpoint!\n");
- return;
- }
- DBG_C("%s\n", __func__);
- if (ep_num == 0) {
- csr = 0;
- mt_udc_flush_ep0_fifo();
- ep0csr_setbits(EP0_SENDSTALL);
- //TODO: check whether we have to wait for SENTSTALL here
- while (!(readl(U3D_EP0CSR) & EP0_SENTSTALL));
- udc_clean_sentstall(0, USB_DIR_OUT);
- } else {
- if (endpoint->in == 0) { /* USB_DIR_OUT: val is 0x0; in == 0 here */
- csr = USB_READCSR32(U3D_RX1CSR0, ep_num);
- csr &= RX_W1C_BITS;
- csr |= RX_SENDSTALL;
- USB_WRITECSR32(U3D_RX1CSR0, ep_num, csr);
- //TODO: do we have to wait for SENTSTALL here?
- while (!(USB_READCSR32(U3D_RX1CSR0, ep_num) & RX_SENTSTALL));
- udc_clean_sentstall(ep_num, USB_DIR_OUT);
- mt_udc_flush_fifo(ep_num, USB_DIR_OUT);
- } else {
- csr = USB_READCSR32(U3D_TX1CSR0, ep_num);
- csr &= TX_W1C_BITS;
- csr |= TX_SENDSTALL;
- USB_WRITECSR32(U3D_TX1CSR0, ep_num, csr);
- //TODO: do we have to wait for SENTSTALL here?
- while (!(USB_READCSR32(U3D_TX1CSR0, ep_num) & TX_SENTSTALL));
- udc_clean_sentstall(ep_num, USB_DIR_IN);
- mt_udc_flush_fifo(ep_num, USB_DIR_IN);
- }
- }
- ep0_state = EP0_IDLE;
- return;
- }
- /*
- * mu3d_hal_dft_reg() - apply default register settings
- * no use? deleted
- */
- /* from mt_usbtty.c - start */
- void enable_highspeed(void)
- {
- int i;
- g_enable_u3 = 0;
- g_speed = SSUSB_SPEED_HIGH;
- for (i = 1; i < MT_EP_NUM; i++) {
- if (ep_list[i].num != 0) { /* allocated */
- ep_list[i].maxpkt = 512;
- mt_setup_ep(ep_list[i].num, &ep_list[i]);
- }
- }
- }
- void enable_superspeed(void)
- {
- int i;
- g_enable_u3 = true;
- g_speed = SSUSB_SPEED_SUPER;
- for (i = 1; i < MT_EP_NUM; i++) {
- if (ep_list[i].num != 0) { /* allocated */
- ep_list[i].maxpkt = 1024;
- mt_setup_ep(ep_list[i].num, &ep_list[i]);
- }
- }
- }
- /* from mt_usbtty.c - end */
- USB_SPEED mt_udc_get_speed(void)
- {
- u32 speed = readl(U3D_DEVICE_CONF) & SSUSB_DEV_SPEED;
- switch (speed) {
- case 1:
- DBG_I("FS is detected\n");
- return SSUSB_SPEED_FULL;
- break;
- case 3:
- DBG_I("HS is detected\n");
- return SSUSB_SPEED_HIGH;
- break;
- case 4:
- DBG_I("SS is detected\n");
- return SSUSB_SPEED_SUPER;
- break;
- default:
- DBG_I("Unrecognized Speed %d\n", speed);
- break;
- };
- return SSUSB_SPEED_UNKNOWN;
- }
- /*
- * u3d_ep0en - enable ep0 function
- */
- void u3d_ep0en(void)
- {
- u32 temp = 0;
- struct udc_endpoint *ep0 = &ep_list[EP0];
- if (mt_udc_get_speed() == SSUSB_SPEED_SUPER) {
- ep0->maxpkt = EP0_MAX_PACKET_SIZE_U3;
- } else {
- ep0->maxpkt = EP0_MAX_PACKET_SIZE;
- }
- /* EP0CSR */
- temp = readl(U3D_EP0CSR);
- temp = ((temp & ~0x3ff) | (ep0->maxpkt & 0x3ff));
- //No DMA
- //temp |= EP0_DMAREQEN;
- writel(temp, U3D_EP0CSR);
- /* enable EP0 interrupts */
- setbits(U3D_EPIESR, (EP0ISR | SETUPENDISR));
- }
- void u3d_irq_en()
- {
- writel(0xFFFFFFFF, U3D_LV1IESR);
- }
- void mu3d_initialize_drv(void)
- {
- /* enable LV1 ISR */
- u3d_irq_en();
- writel(readl(U3D_POWER_MANAGEMENT) & ~LPM_MODE, U3D_POWER_MANAGEMENT);
- writel(readl(U3D_POWER_MANAGEMENT) | (LPM_MODE&0x1), U3D_POWER_MANAGEMENT);
- #ifdef EXT_VBUS_DET
- /* force VBUS on */
- writel(0x3, U3D_MISC_CTRL);
- #else
- writel(0x0, U3D_MISC_CTRL);
- #endif
- /* enable common USB ISR and L3 LTSSM ISR */
- mu3d_hal_system_intr_en();
- u3d_ep0en();
- }
- /* reset USB hardware */
- void mt_udc_reset(USB_SPEED speed)
- {
- u32 dwtmp1 = 0, dwtmp2 = 0, dwtmp3 = 0;
- dwtmp1 = readl(U3D_SSUSB_PRB_CTRL1);
- dwtmp2 = readl(U3D_SSUSB_PRB_CTRL2);
- dwtmp3 = readl(U3D_SSUSB_PRB_CTRL3);
- mu3d_hal_rst_dev();
- writel(dwtmp1, U3D_SSUSB_PRB_CTRL1);
- writel(dwtmp2, U3D_SSUSB_PRB_CTRL2);
- writel(dwtmp3, U3D_SSUSB_PRB_CTRL3);
- mdelay(50);
- mu3d_hal_ssusb_en();
- mu3d_hal_set_speed(speed);
- //TODO: Any more global variable needs to be reset here?
- dev_address = 0;
- g_tx_fifo_addr = USB_TX_FIFO_START_ADDRESS;
- g_rx_fifo_addr = USB_RX_FIFO_START_ADDRESS;
- txn_status = 0;
- mu3d_initialize_drv();
- }
- static void mt_udc_ep0_write(void)
- {
- struct udc_endpoint *ept = &ep_list[EP0];
- unsigned int count = 0;
- u32 csr0;
- csr0 = readl(U3D_EP0CSR);
- if (csr0 & EP0_TXPKTRDY) {
- DBG_I("mt_udc_ep0_write: ep0 is not ready to be written\n");
- return;
- }
- count = mt_write_fifo(ept);
- #if DBG_USB_GENERAL
- DBG_I("%s: count = %d\n", __func__, count);
- #endif
- /* hardware limitiation: can't set (EP0_TXPKTRDY | EP0_DATAEND) at same time */
- csr0 |= (EP0_TXPKTRDY);
- writel(csr0, U3D_EP0CSR);
- if (count <= ept->maxpkt) {
- /* last packet */
- ep0_urb->actual_length = 0;
- ept->sent = 0;
- } else {
- DBG_C(" %s wrote %d bytes n there's more, maxp is %d",
- __func__, count, ept->maxpkt);
- }
- }
- static void mt_udc_ep0_read(void)
- {
- struct udc_endpoint *ept = &ep_list[EP0];
- unsigned int count = 0;
- u32 csr0 = 0;
- csr0 = readl(U3D_EP0CSR);
- /* erroneous ep0 interrupt */
- if (!(csr0 & EP0_RXPKTRDY)) {
- return;
- }
- count = mt_read_fifo(ept);
- /* work around: cannot set (EP0_RXPKTRDY | EP0_DATAEND) at same time */
- csr0 |= (EP0_RXPKTRDY);
- writel(csr0, U3D_EP0CSR);
- if (count <= ept->maxpkt) {
- /* last packet */
- csr0 |= EP0_DATAEND;
- ep0_state = EP0_IDLE;
- } else {
- /* more packets are waiting to be transferred */
- DBG_C(" %s wrote %d bytes n there's more, maxp is %d",
- __func__, count, ept->maxpkt);
- csr0 |= EP0_RXPKTRDY;
- }
- udelay(100);
- writel(csr0, U3D_EP0CSR);
- }
- static void u3d_set_address(int addr)
- {
- writel((addr << DEV_ADDR_OFST), U3D_DEVICE_CONF);
- }
- static int ep0_standard_setup(struct urb *urb)
- {
- struct setup_packet *request;
- struct udc_descriptor *desc;
- u8 *cp = urb->buf;
- /* for CLEAR FEATURE */
- u8 ep_num; /* ep number */
- u8 dir; /* DIR */
- u32 csr;
- request = &urb->device_request;
- dump_setup_packet("Device Request\n", request);
- if ((request->type & USB_TYPE_MASK) != 0) {
- return false; /* Class-specific requests are handled elsewhere */
- }
- /* handle all requests that return data (direction bit set on bm RequestType) */
- if ((request->type & USB_EP_DIR_MASK)) {
- /* send the descriptor */
- ep0_state = EP0_TX;
- switch (request->request) {
- /* data stage: from device to host */
- case GET_STATUS:
- #if DBG_USB_GENERAL
- DBG_I("GET_STATUS\n");
- #endif
- urb->actual_length = 2;
- cp[0] = cp[1] = 0;
- switch (request->type & USB_RECIP_MASK) {
- case USB_RECIP_DEVICE:
- cp[0] = USB_STAT_SELFPOWERED;
- break;
- case USB_RECIP_OTHER:
- urb->actual_length = 0;
- break;
- default:
- break;
- }
- return 0;
- case GET_DESCRIPTOR:
- #if DBG_USB_GENERAL
- DBG_I("GET_DESCRIPTOR\n");
- #endif
- /* usb_highspeed? */
- #ifdef SUPPORT_U3
- if (g_enable_u3 == true) {
- desc = desc_list_u3;
- #ifdef DBG_USB_GENERAL
- DBG_I("g_enable_u3 == true, g_speed: %d\n", g_speed);
- #endif
- } else {
- desc = desc_list;
- #ifdef DBG_USB_GENERAL
- DBG_I("g_enable_u3 != true, g_speed: %d\n", g_speed);
- #endif
- }
- /* fix build warning here: using "desc = desc" */
- for (desc = desc; desc; desc = desc->next) {
- #else
- for (desc = desc_list; desc; desc = desc->next) {
- #endif
- #if DBG_USB_DUMP_DESC
- DBG_I("desc->tag: %x: request->value: %x\n", desc->tag, request->value);
- #endif
- if (desc->tag == request->value) {
- #if DBG_USB_DUMP_DESC
- DBG_I("Find packet!\n");
- #endif
- unsigned len = desc->len;
- if (len > request->length)
- len = request->length;
- #if DBG_USB_GENERAL
- DBG_I("%s: urb: %p, cp: %p\n", __func__, urb, cp);
- #endif
- copy_desc(urb, desc->data, len);
- return 0;
- }
- }
- /* descriptor lookup failed */
- return false;
- case GET_CONFIGURATION:
- #if DBG_USB_GENERAL
- DBG_I("GET_CONFIGURATION\n");
- #endif
- urb->actual_length = 1;
- cp[0] = 1;
- return 0;
- case GET_INTERFACE:
- #if DBG_USB_GENERAL
- DBG_I("GET_INTERFACE\n");
- #endif
- default:
- DBG_C("Unsupported command with TX data stage\n");
- break;
- }
- }
- else {
- switch (request->request) {
- case SET_ADDRESS:
- #if DBG_USB_GENERAL
- DBG_I("SET_ADDRESS\n");
- #endif
- dev_address = (request->value);
- set_address = 1;
- u3d_set_address(dev_address);
- return 0;
- case SET_CONFIGURATION:
- #if DBG_USB_GENERAL
- DBG_I("SET_CONFIGURATION\n");
- #endif
- if (request->value == 1) {
- usb_config_value = 1;
- /* work around: restore epx status after BUS RESET?? */
- mu3d_hal_set_speed(g_speed);
- udelay(50);
- /* restore QMU */
- #ifdef SUPPORT_QMU
- usb_initialize_qmu();
- mu3d_hal_start_qmu(1, USB_DIR_OUT);
- mu3d_hal_start_qmu(1, USB_DIR_IN);
- udelay(50);
- #endif
- the_gadget->notify(the_gadget, UDC_EVENT_ONLINE);
- } else {
- usb_config_value = 0;
- the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
- }
- usb_online = request->value ? 1 : 0;
- #ifdef DBG_USB_GENERAL
- DBG_I("usb_online: %d\n", usb_online);
- #endif
- return 0;
- #ifdef SUPPORT_U3
- case SET_SEL:
- ep0_state = EP0_RX;
- return 0;
- case SET_FEATURE:
- if (request->value == USB3_U1_ENABLE)
- #if DBG_USB_GENERAL
- DBG_I("USB3_U1_ENABLE\n");
- #endif
- if (request->value == USB3_U2_ENABLE)
- #if DBG_USB_GENERAL
- DBG_I("USB3_U2_ENABLE\n");
- #endif
- return 0;
- #endif
- case CLEAR_FEATURE:
- #if DBG_USB_GENERAL
- DBG_I("CLEAR_FEATURE\n");
- #endif
- ep_num = request->index & 0xf;
- dir = request->index & 0x80;
- if ((request->value == 0) && (request->length == 0)) {
- #if DBG_USB_GENERAL
- DBG_I("Clear Feature: ep: %d dir: %d\n", ep_num, dir);
- #endif
- switch (dir) {
- case USB_DIR_OUT:
- csr = USB_READCSR32(U3D_TX1CSR0, ep_num) & TX_W1C_BITS;
- csr = (csr & (~TX_SENDSTALL)) | TX_SENTSTALL;
- USB_WRITECSR32(U3D_TX1CSR0, ep_num, csr);
- #if DBG_USB_GENERAL
- DBG_I("clear tx stall ep: %d dir: %d\n", ep_num, dir);
- #endif
- setbits(U3D_EP_RST, (BIT16 << ep_num));//reset TX EP
- clrbits(U3D_EP_RST, (BIT16 << ep_num));//reset reset TX EP
- break;
- case USB_DIR_IN:
- csr = USB_READCSR32(U3D_RX1CSR0, ep_num) & RX_W1C_BITS;
- csr = (csr & (~RX_SENDSTALL)) | RX_SENTSTALL;
- USB_WRITECSR32(U3D_RX1CSR0, ep_num, csr);
- #if DBG_USB_GENERAL
- DBG_I("clear rx stall ep: %d dir: %d\n", ep_num, dir);
- #endif
- setbits(U3D_EP_RST, (1 << ep_num));//reset RX EP
- clrbits(U3D_EP_RST, (1 << ep_num));//reset reset RX EP
- break;
- default:
- break;
- }
- return 0;
- }
- default:
- #ifdef DBG_USB_DUMP_SETUP
- DBG_I("desc->tag: %x: request->request: %x, request->value: %x\n", desc->tag, request->request, request->value);
- DBG_C("Unsupported command with RX data stage\n");
- #endif
- break;
- } /* switch request */
- }
- return FALSE;
- }
- static void mt_udc_ep0_setup(void) {
- struct udc_endpoint *endpoint = &ep_list[0];
- u8 stall = 0;
- u32 csr0;
- struct setup_packet *request;
- #ifdef USB_DEBUG
- u16 count;
- #endif
- /* Read control status register for endpiont 0 */
- csr0 = readl(U3D_EP0CSR);
- /* check whether RxPktRdy is set? */
- if (!(csr0 & EP0_SETUPPKTRDY))
- return;
- /* unload fifo */
- ep0_urb->actual_length = 0;
- #ifndef USB_DEBUG
- mt_read_fifo(endpoint);
- #else
- count = mt_read_fifo(endpoint);
- #if DBG_USB_FIFO
- DBG_I("%s: mt_read_fifo count = %d\n", __func__, count);
- #endif
- #endif
- /* decode command */
- request = &ep0_urb->device_request;
- memcpy(request, ep0_urb->buf, sizeof(struct setup_packet));
- if (((request->type) & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
- #if DBG_USB_GENERAL
- DBG_I("Standard Request\n");
- #endif
- stall = ep0_standard_setup(ep0_urb);
- if (stall) {
- dump_setup_packet("STANDARD REQUEST NOT SUPPORTED\n", request);
- }
- } else if (((request->type) & USB_TYPE_MASK) == USB_TYPE_CLASS) {
- #if DBG_USB_GENERAL
- DBG_I("Class-Specific Request\n");
- #endif
- if (stall) {
- dump_setup_packet("CLASS REQUEST NOT SUPPORTED\n", request);
- }
- } else if (((request->type) & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
- #if DBG_USB_GENERAL
- DBG_I("Vendor-Specific Request\n");
- /* do nothing now */
- DBG_I("ALL VENDOR-SPECIFIC REQUESTS ARE NOT SUPPORTED!!\n");
- #endif
- }
- if (stall) {
- /* the received command is not supported */
- udc_stall_ep(0, USB_DIR_OUT);
- return;
- }
- /* handle EP0 state */
- csr0 = readl(U3D_EP0CSR);
- switch (ep0_state) {
- case EP0_TX:
- /* data stage: from device to host */
- #if DBG_USB_GENERAL
- DBG_I("%s: EP0_TX\n", __func__);
- #endif
- /* move out from udc_chg_ep0_state() */
- csr0 = readl(U3D_EP0CSR);
- csr0 |= (EP0_SETUPPKTRDY | EP0_DPHTX);
- writel(csr0, U3D_EP0CSR);
- mt_udc_ep0_write();
- break;
- case EP0_RX:
- /* data stage: from host to device */
- #if DBG_USB_GENERAL
- DBG_I("%s: EP0_RX\n", __func__);
- #endif
- /* move out from udc_chg_ep0_state(): no need? */
- csr0 = readl(U3D_EP0CSR);
- csr0 |= (EP0_SETUPPKTRDY);
- writel(csr0, U3D_EP0CSR);
- break;
- case EP0_IDLE:
- /* no data stage */
- #if DBG_USB_GENERAL
- DBG_I("%s: EP0_IDLE\n", __func__);
- #endif
- csr0 = readl(U3D_EP0CSR);
- csr0 |= (EP0_RXPKTRDY | EP0_DATAEND);
- writel(csr0, U3D_EP0CSR);
- break;
- default:
- break;
- }
- }
- static void mt_udc_ep0_handler(void) {
- u32 csr0;
- /*
- * EP0 interrupt is generated when
- * - EP0CSR.RxPktRdy bit is set after data packet has been received and stored into FIFO0
- * - data packet in FIFO0 has been sent to host successfully
- * - EP0CSR.SentStall bit is set after host receives STALL
- * - EP0CSR.SetupEnd bit is set after receiving SETUP transaction in DATA/STATUS phase
- */
- csr0 = readl(U3D_EP0CSR);
- if (csr0 & EP0_SENTSTALL) {
- #if DBG_USB_GENERAL
- DBG_I("USB: [EP0] SENTSTALL\n");
- #endif
- /* needs implementation for exception handling here */
- //ep0_state = EP0_IDLE;
- // writel((readl(U3D_EP0CSR) & EP0_W1C_BITS) | EP0_SENTSTALL, U3D_EP0CSR);
- //udc_chg_ep0_state(EP0_IDLE);
- ep0_state = EP0_IDLE;
- ep0csr_setbits(EP0_SENTSTALL);
- }
- switch (ep0_state) {
- case EP0_IDLE:
- #if DBG_USB_GENERAL
- DBG_I("%s: EP0_IDLE\n", __func__);
- #endif
- if (set_address) {
- u3d_set_address(dev_address);
- set_address = 0;
- }
- mt_udc_ep0_setup();
- break;
- case EP0_TX:
- #if DBG_USB_GENERAL
- DBG_I("%s: EP0_TX\n", __func__);
- #endif
- /* complete and sendout buffer */
- csr0 |= EP0_DATAEND;
- writel(csr0, U3D_EP0CSR);
- ep0_state = EP0_IDLE;
- break;
- case EP0_RX:
- #if DBG_USB_GENERAL
- DBG_I("%s: EP0_RX\n", __func__);
- #endif
- mt_udc_ep0_read();
- ep0_state = EP0_IDLE;
- break;
- default:
- DBG_I("[ERR]: Unrecognized ep0 state%d", ep0_state);
- break;
- }
- return;
- }
- static void mt_udc_epx_handler(u8 ep_num, u8 dir) {
- u32 csr;
- u32 count;
- struct udc_endpoint *ept;
- struct urb *urb;
- struct udc_request *req; /* for event signaling */
- ept = mt_find_ep(ep_num, dir);
- if (ept == NULL) {
- DBG_C("Error : cant find endpoint!\n");
- return;
- }
- #if DBG_USB_GENERAL
- DBG_I("EP%d Interrupt\n", ep_num);
- DBG_I("dir: %x\n", dir);
- #endif
- switch (dir) {
- case USB_DIR_OUT:
- /* transfer direction is from host to device */
- /* from the view of usb device, it's RX */
- csr = USB_READCSR32(U3D_RX1CSR0, ep_num);
- if (csr & RX_SENTSTALL) {
- DBG_C("EP %d(RX): STALL\n", ep_num);
- /* exception handling: implement this!! */
- return;
- }
- #ifdef SUPPORT_QMU /* SUPPORT_QMU */
- count = ept->rcv_urb->actual_length;
- #ifdef DBG_USB_QMU
- DBG_I("%s: QMU: count: %d\n", __func__, count);
- #endif
- #else /* PIO MODE */
- if (!(csr & RX_RXPKTRDY)) {
- #if DBG_USB_GENERAL
- DBG_I("EP %d: ERRONEOUS INTERRUPT\n", ep_num); // normal
- #endif
- return;
- }
- count = mt_read_fifo(ept);
- #if DBG_USB_GENERAL
- DBG_I("EP%d(RX), count = %d\n", ep_num, count);
- #endif
- /* write 1 to clear RXPKTRDY */
- csr |= RX_RXPKTRDY;
- USB_WRITECSR32(U3D_RX1CSR0, ep_num, csr);
- if (USB_READCSR32(U3D_RX1CSR0, ep_num) & RX_RXPKTRDY) {
- #if DBG_USB_GENERAL
- DBG_I("%s: rxpktrdy clear failed\n", __func__);
- #endif
- }
- #endif /* ifndef SUPPORT_QMU */
- /* do signaling */
- req = ept->req;
- /* workaround: if req->lenth == 64 bytes (not huge data transmission)
- * do normal return */
- #if DBG_USB_GENERAL
- DBG_I("%s: req->length: %x, ept->rcv_urb->actual_length: %x\n",
- __func__, req->length, ept->rcv_urb->actual_length);
- #endif
- /* Deal with FASTBOOT command */
- if ((req->length >= ept->rcv_urb->actual_length) && req->length == 64) {
- req->length = count;
- /* mask EPx INTRRXE */
- /* The buffer is passed from the AP caller.
- * It happens that AP is dealing with the buffer filled data by driver,
- * but the driver is still receiving the next data packets onto the buffer.
- * Data corrupted happens if the every request use the same buffer.
- * Mask the EPx to ensure that AP and driver are not accessing the buffer parallely.
- */
- /* set 1 to disable (clear) enable mask */
- writel((BIT16 << ep_num), U3D_EPIECR);
- }
- /* Deal with DATA transfer */
- if ((req->length == ept->rcv_urb->actual_length) ||
- ((req->length >= ept->rcv_urb->actual_length) && req->length == 64)) {
- handle_ept_complete(ept);
- /* mask EPx INTRRXE */
- /* The buffer is passed from the AP caller.
- * It happens that AP is dealing with the buffer filled data by driver,
- * but the driver is still receiving the next data packets onto the buffer.
- * Data corrupted happens if the every request use the same buffer.
- * Mask the EPx to ensure that AP and driver are not accessing the buffer parallely.
- */
- /* set 1 to disable (clear) enable mask */
- writel((BIT16 << ep_num), U3D_EPIECR);
- }
- break;
- case USB_DIR_IN:
- /* transfer direction is from device to host */
- /* from the view of usb device, it's tx */
- csr = USB_READCSR32(U3D_TX1CSR0, ep_num);
- if (csr & TX_SENTSTALL) {
- DBG_C("EP %d(TX): STALL\n", ep_num);
- ept->status = -1;
- handle_ept_complete(ept);
- /* exception handling: implement this!! */
- return;
- }
- #ifndef SUPPORT_QMU
- if (csr & TX_TXPKTRDY) {
- DBG_C
- ("%s: ep%d is not ready to be written\n",
- __func__, ep_num);
- return;
- }
- #endif
- urb = ept->tx_urb;
- if (ept->sent == urb->actual_length) {
- /* do signaling */
- handle_ept_complete(ept);
- break;
- }
- /* send next packet of the same urb */
- #ifndef SUPPORT_QMU
- count = mt_write_fifo(ept);
- #if DBG_USB_GENERAL
- DBG_I("EP%d(TX), count = %d\n", ep_num, ept->sent);
- #endif
- if (count != 0) {
- /* not the interrupt generated by the last tx packet of the transfer */
- csr |= TX_TXPKTRDY;
- USB_WRITECSR32(TX_TXPKTRDY, ep_num, csr);
- }
- #endif
- break;
- default:
- break;
- }
- }
- #if defined(DBG_USB_LTSSM)
- void report_ltssm_type(u32 ltssm) {
- if (ltssm & RXDET_SUCCESS_INTR) {
- DBG_I("RXDET_SUCCESS_INTR\n");
- }
- if (ltssm & HOT_RST_INTR) {
- DBG_I("HOT_RST_INTR\n");
- }
- if (ltssm & WARM_RST_INTR) {
- DBG_I("WARM_RST_INTR\n");
- }
- if (ltssm & ENTER_U0_INTR) {
- DBG_I("ENTER_U0_INTR\n");
- }
- if (ltssm & VBUS_RISE_INTR) {
- DBG_I("VBUS_RISE_INTR\n");
- }
- if (ltssm & VBUS_FALL_INTR) {
- DBG_I("VBUS_FALL_INTR\n");
- }
- if (ltssm & ENTER_U1_INTR) {
- DBG_I("ENTER_U1_INTR\n");
- }
- if (ltssm & ENTER_U2_INTR) {
- DBG_I("ENTER_U2_INTR\n");
- }
- if (ltssm & ENTER_U3_INTR) {
- DBG_I("ENTER_U3_INTR\n");
- }
- if (ltssm & EXIT_U1_INTR) {
- DBG_I("EXIT_U1_INTR\n");
- }
- if (ltssm & EXIT_U2_INTR) {
- DBG_I("EXIT_U2_INTR\n");
- }
- if (ltssm & EXIT_U3_INTR) {
- DBG_I("EXIT_U3_INTR\n");
- }
- }
- #endif
- /*
- * get_seg_size()
- *
- * Return value indicates the TxFIFO size of 2^n bytes, (ex: value 10 means 2^10 =
- * 1024 bytes.) TXFIFOSEGSIZE should be equal or bigger than 4. The TxFIFO size of
- * 2^n bytes also should be equal or bigger than TXMAXPKTSZ. This EndPoint occupy
- * total memory size (TX_SLOT + 1 )*2^TXFIFOSEGSIZE bytes.
- */
- u8 get_seg_size(u32 max_packet_size) {
- /* Set fifo size(double buffering is currently not enabled) */
- switch (max_packet_size) {
- case 8:
- case 16:
- return USB_FIFOSZ_SIZE_16;
- case 32:
- return USB_FIFOSZ_SIZE_32;
- case 64:
- return USB_FIFOSZ_SIZE_64;
- case 128:
- return USB_FIFOSZ_SIZE_128;
- case 256:
- return USB_FIFOSZ_SIZE_256;
- case 512:
- return USB_FIFOSZ_SIZE_512;
- case 1023:
- case 1024:
- case 2048:
- case 3072:
- case 4096:
- return USB_FIFOSZ_SIZE_1024;
- default:
- DBG_I("The max_packet_size %d is not supported\n", max_packet_size);
- return USB_FIFOSZ_SIZE_512;
- }
- }
- /*
- * udc_setup_ep - setup endpoint
- *
- * Associate a physical endpoint with endpoint_instance and initialize FIFO
- */
- void mt_setup_ep(unsigned int ep_num, struct udc_endpoint *endpoint) {
- u32 csr0, csr1, csr2;
- u32 max_packet_size;
- u8 seg_size;
- u8 max_pkt;
- u8 burst = endpoint->burst;
- u8 mult = endpoint->mult;
- u8 type = endpoint->type;
- u8 slot = endpoint->slot;
- /* EP table records in bits hence bit 1 is ep0 */
- /* Nothing needs to be done for ep0 */
- if (ep_num == 0) { // or (endpoint->type == USB_EP_XFER_CTRL)
- return;
- }
- /* Configure endpoint fifo */
- /* Set fifo address, fifo size, and fifo max packet size */
- #if DBG_USB_GENERAL
- DBG_I("%s: endpoint->in: %d, maxpkt: %d\n",
- __func__, endpoint->in, endpoint->maxpkt);
- #endif
- if (endpoint->in == 0) { /* USB_DIR_OUT: val is 0x0; in == 0 here */
- /* RX case */
- mt_udc_flush_fifo(ep_num, USB_DIR_OUT);
- max_packet_size = endpoint->maxpkt;
- /* Set fifo size(double buffering is currently not enabled) */
- seg_size = get_seg_size(max_packet_size);
- /* CSR0 */
- csr0 = USB_READCSR32(U3D_RX1CSR0, ep_num) &~ RX_RXMAXPKTSZ;
- csr0 |= (max_packet_size & RX_RXMAXPKTSZ);
- #ifndef SUPPORT_QMU /* PIO_MODE */
- csr0 &= ~RX_DMAREQEN;
- #endif
- /* CSR1 */
- max_pkt = (burst + 1) * (mult + 1) - 1;
- csr1 = (burst & SS_RX_BURST);
- csr1 |= (slot << RX_SLOT_OFST) & RX_SLOT;
- csr1 |= (max_pkt << RX_MAX_PKT_OFST) & RX_MAX_PKT;
- csr1 |= (mult << RX_MULT_OFST) & RX_MULT;
- /* CSR2 */
- csr2 = (g_rx_fifo_addr >> 4) & RXFIFOADDR;
- csr2 |= (seg_size << RXFIFOSEGSIZE_OFST) & RXFIFOSEGSIZE;
- /* In LK (FASTBOOT) will use BULK transfer only */
- if (type == USB_EP_XFER_BULK) {
- csr1 |= TYPE_BULK;
- } else if (type == USB_EP_XFER_INT) {
- csr1 |= TYPE_INT;
- csr2 |= (endpoint->binterval << RXBINTERVAL_OFST) & RXBINTERVAL;
- }
- /* Write 1 to clear EPIER */
- setbits(U3D_EPIECR, (BIT16 << ep_num));
- USB_WRITECSR32(U3D_RX1CSR0, ep_num, csr0);
- USB_WRITECSR32(U3D_RX1CSR1, ep_num, csr1);
- USB_WRITECSR32(U3D_RX1CSR2, ep_num, csr2);
- /* Write 1 to set EPIER */
- #ifndef SUPPORT_QMU /* For QMU, we don't enable EP interrupts. */
- writel(readl(U3D_EPIER) | (BIT16 << ep_num), U3D_EPIESR);
- #endif
- if (max_packet_size == 1023) {
- g_rx_fifo_addr += (1024 * (slot + 1));
- } else {
- g_rx_fifo_addr += (max_packet_size * (slot + 1));
- }
- if (g_rx_fifo_addr > readl(U3D_CAP_EPNRXFFSZ)) {
- DBG_I("[ERR]g_rx_fifo_addr is %x and U3D_CAP_EPNTXFFSZ is %x for ep%d\n",
- g_rx_fifo_addr, readl(U3D_CAP_EPNRXFFSZ), ep_num);
- DBG_I("max_packet_size = %d\n", max_packet_size);
- DBG_I("slot = %d\n", slot);
- }
- } else { /* USB_DIR_IN: val is 0x80; in == 1 here */
- /* TX case */
- mt_udc_flush_fifo(ep_num, USB_DIR_IN);
- max_packet_size = endpoint->maxpkt;
- /* Set fifo size(double buffering is currently not enabled) */
- seg_size = get_seg_size(max_packet_size);
- /* CSR0 */
- csr0 = USB_READCSR32(U3D_TX1CSR0, ep_num) &~ TX_TXMAXPKTSZ;
- csr0 |= (max_packet_size & TX_TXMAXPKTSZ);
- #ifndef SUPPORT_QMU /* PIO_MODE */
- csr0 &= ~TX_DMAREQEN;
- #endif
- /* CSR1 */
- max_pkt = (burst + 1)*(mult + 1) - 1;
- csr1 = (burst & SS_TX_BURST);
- csr1 |= (slot << TX_SLOT_OFST) & TX_SLOT;
- csr1 |= (max_pkt << TX_MAX_PKT_OFST) & TX_MAX_PKT;
- csr1 |= (mult << TX_MULT_OFST) & TX_MULT;
- /* CSR2 */
- csr2 = (g_tx_fifo_addr >> 4) & TXFIFOADDR;
- csr2 |= (seg_size << TXFIFOSEGSIZE_OFST) & TXFIFOSEGSIZE;
- /* In LK (FASTBOOT) will use BULK transfer only */
- if (type == USB_EP_XFER_BULK) {
- csr1 |= TYPE_BULK;
- } else if (type == USB_EP_XFER_INT) {
- csr1 |= TYPE_INT;
- csr2 |= (endpoint->binterval << TXBINTERVAL_OFST) & TXBINTERVAL;
- }
- /* Write 1 to clear EPIER */
- setbits(U3D_EPIECR, (BIT0 << ep_num));
- USB_WRITECSR32(U3D_TX1CSR0, ep_num, csr0);
- USB_WRITECSR32(U3D_TX1CSR1, ep_num, csr1);
- USB_WRITECSR32(U3D_TX1CSR2, ep_num, csr2);
- /* Write 1 to set EPIER */
- #ifndef SUPPORT_QMU /* For QMU, we don't enable EP interrupts. */
- writel(readl(U3D_EPIER) | (BIT0 << ep_num), U3D_EPIESR);
- #endif
- if (max_packet_size == 1023) {
- g_tx_fifo_addr += (1024 * (slot + 1));
- } else {
- g_tx_fifo_addr += (max_packet_size * (slot + 1));
- }
- if (g_tx_fifo_addr > readl(U3D_CAP_EPNTXFFSZ)) {
- DBG_I("[ERR]g_tx_fifo_addr is %x and U3D_CAP_EPNTXFFSZ is %x for ep%d",
- g_tx_fifo_addr, readl(U3D_CAP_EPNTXFFSZ), ep_num);
- DBG_I("max_packet_size = %d\n", max_packet_size);
- DBG_I("slot = %d]n", slot);
- }
- }
- }
- struct udc_endpoint *_udc_endpoint_alloc(unsigned char num, unsigned char in,
- unsigned short max_pkt) {
- int i;
- /*
- * find an unused slot in ep_list from EP1 to MAX_EP
- * for example, EP1 will use 2 slot one for IN and the other for OUT
- */
- if (num != EP0) {
- for (i = 1; i < MT_EP_NUM; i++) {
- if (ep_list[i].num == 0) /* usable */
- break;
- }
- if (i == MT_EP_NUM) /* ep has been exhausted. */
- return NULL;
- /* EPx Type */
- ep_list[i].type = USB_EP_XFER_BULK;
- /* set urb */
- if (in) { /* usb EP1 tx */
- ep_list[i].tx_urb = tx_urb;
- tx_urb->ept = &ep_list[i];
- } else { /* usb EP1 rx */
- ep_list[i].rcv_urb = rx_urb;
- rx_urb->ept = &ep_list[i];
- }
- } else {
- i = EP0; /* EP0 */
- }
- ep_list[i].maxpkt = max_pkt;
- ep_list[i].num = num;
- ep_list[i].in = in;
- ep_list[i].req = NULL;
- ep_list[i].slot = 1; /* USB burst mode: 1: enable, 0: disable */
- /* store EPT_TX/RX info */
- if (ep_list[i].in) {
- ep_list[i].bit = EPT_TX(num);
- } else {
- ep_list[i].bit = EPT_RX(num);
- }
- /* write parameters to this ep (write to hardware) */
- mt_setup_ep(num, &ep_list[i]);
- DBG_I("ept%d %s @%p/%p max=%d bit=%x\n",
- num, in ? "in" : "out", &ep_list[i], &ep_list, max_pkt, ep_list[i].bit);
- return &ep_list[i];
- }
- #define SETUP(type,request) (((type) << 8) | (request))
- static unsigned long ept_alloc_table = EPT_TX(0) | EPT_RX(0);
- struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt) {
- struct udc_endpoint *ept;
- unsigned n;
- unsigned in;
- if (type == UDC_TYPE_BULK_IN) {
- in = 1;
- } else if (type == UDC_TYPE_BULK_OUT) {
- in = 0;
- } else {
- return 0;
- }
- /* udc_endpoint_alloc is used for EPx except EP0 */
- for (n = 1; n < 16; n++) {
- unsigned long bit = in ? EPT_TX(n) : EPT_RX(n);
- if (ept_alloc_table & bit)
- continue;
- ept = _udc_endpoint_alloc(n, in, maxpkt);
- if (ept)
- ept_alloc_table |= bit;
- return ept;
- }
- return 0;
- }
- /* must use with request. If req == NULL should be error handling */
- static void handle_ept_complete(struct udc_endpoint *ept) {
- unsigned int actual;
- int status;
- struct udc_request *req;
- req = ept->req;
- if (req) {
- #if DBG_USB_GENERAL
- DBG_I("%s: req: %p: req->length: %d: status: %d\n", __func__, req, req->length, ept->status);
- #endif
- /*
- * This request releasement will cause udc_request_queue abnormal when INTR comes later.
- * but will only affect QMU mode because signal didn't return correctly.
- */
- ept->req = NULL;
- if (ept->status == -1) {
- actual = 0;
- status = -1; /* txn_status */
- DBG_C("%s: EP%d/%s FAIL status: %x\n",
- __func__, ept->num, ept->in ? "in" : "out", status);
- } else {
- actual = req->length;
- status = 0;
- }
- /* clean chache because CPU may prefetch request buffer to cache */
- arch_clean_invalidate_cache_range((addr_t) req->buf, req->length);
- if (req->complete)
- req->complete(req, actual, status);
- }
- }
- void mt_udc_irq(u32 ltssm, u32 intrusb, u32 dmaintr, u16 intrtx, u16 intrrx,
- u32 intrqmu, u32 intrqmudone, u32 linkint) {
- u32 temp = 0;
- u32 ep_num = 0;
- #if DBG_USB_IRQ
- DBG_I("mt_udc_irq\n");
- DBG_I("ltssm : %x\n", ltssm);
- DBG_I("intrusb : %x\n", intrusb);
- DBG_I("dmaintr : %x\n", dmaintr);
- DBG_I("intrtx : %x\n", intrtx);
- DBG_I("intrrx : %x\n", intrrx);
- DBG_I("intrqmu : %x\n", intrqmu);
- DBG_I("intrqmudone : %x\n", intrqmudone);
- DBG_I("linkint : %x\n", linkint);
- #ifdef DBG_EP0ISR
- DBG_I("U3D_EP0CSR : %x\n", readl(U3D_EP0CSR));
- DBG_I("USB_EPIER : %x\n", readl(U3D_EPIER));
- DBG_I("USB_EPISR :%x\n", readl(U3D_EPISR));
- DBG_I("U3D_DEVICE_CONF: %x\n", readl(U3D_DEVICE_CONF));
- DBG_I("U3D_DEVICE_MONITOR: %x\n", readl(U3D_DEVICE_MONITOR));
- #endif
- #ifdef SBG_EP1ISR
- DBG_I("[CSR] U3D_RX1CSR0: %p: val: %x\n", (void *)U3D_RX1CSR0, USB_READCSR32(U3D_RX1CSR0, 1));
- DBG_I("[CSR] U3D_RX1CSR1: %p: val: %x\n", (void *)U3D_RX1CSR1, USB_READCSR32(U3D_RX1CSR1, 1));
- DBG_I("[CSR] U3D_RX1CSR2: %p: val: %x\n", (void *)U3D_RX1CSR2, USB_READCSR32(U3D_RX1CSR2, 1));
- DBG_I("[CSR] U3D_TX1CSR0: %p: val: %x\n", (void *)U3D_TX1CSR0, USB_READCSR32(U3D_TX1CSR0, 1));
- DBG_I("[CSR] U3D_TX1CSR1: %p: val: %x\n", (void *)U3D_TX1CSR1, USB_READCSR32(U3D_TX1CSR1, 1));
- DBG_I("[CSR] U3D_TX1CSR2: %p: val: %x\n", (void *)U3D_TX1CSR2, USB_READCSR32(U3D_TX1CSR2, 1));
- #endif
- #ifdef DBG_USB_QMU
- DBG_I("U3D_RXQCSR1: %p, val: %x\n", (void *)U3D_RXQCSR(1), readl(U3D_RXQCSR(1)));
- DBG_I("U3D_RXQSAR1: %p, val: %x\n", (void *)U3D_RXQSAR(1), readl(U3D_RXQSAR(1)));
- DBG_I("U3D_RXQCPR1: %p, val: %x\n", (void *)U3D_RXQCPR(1), readl(U3D_RXQCPR(1)));
- DBG_I("U3D_RXQLDPR1: %p, val: %x\n", (void *)U3D_RXQLDPR(1), readl(U3D_RXQLDPR(1)));
- DBG_I("U3D_TXQCSR1: %p, val: %x\n", (void *)U3D_TXQCSR(1), readl(U3D_TXQCSR(1)));
- DBG_I("U3D_TXQSAR1: %p, val: %x\n", (void *)U3D_TXQSAR(1), readl(U3D_TXQSAR(1)));
- DBG_I("U3D_TXQCPR1: %p, val: %x\n", (void *)U3D_TXQCPR(1), readl(U3D_TXQCPR(1)));
- #endif /* ifdef DBG_USB_QMU */
- #endif /* ifdef DBG_USB_IRQ */
- #ifdef SUPPORT_QMU
- if (intrqmudone) {
- qmu_done_interrupt(intrqmudone);
- if (intrqmudone & QMU_RX_DONE(1)) {
- mt_udc_epx_handler(1, USB_DIR_OUT);
- }
- if (intrqmudone & QMU_TX_DONE(1)) {
- mt_udc_epx_handler(1, USB_DIR_IN);
- }
- }
- if (intrqmu) {
- qmu_handler(intrqmu);
- }
- #endif
- if (linkint & SSUSB_DEV_SPEED_CHG_INTR) {
- DBG_I("[INTR] Speed Change\n");
- g_speed = mt_udc_get_speed();
- mu3d_hal_set_speed(g_speed);
- }
- /* Check for reset interrupt */
- if (intrusb & RESET_INTR) {
- DBG_I("[INTR] Reset\n");
- udelay(20);
- /* set device address to 0 after reset */
- set_address = 0;
- intrtx = 0;
- intrrx = 0;
- }
- #ifdef SUPPORT_U3
- if (ltssm) {
- if (ltssm & SS_DISABLE_INTR) {
- DBG_I("[INTR] SS is Disabled, %d\n",
- (readl(U3D_LTSSM_INFO) & DISABLE_CNT) >> DISABLE_CNT_OFST);
- /* Set soft_conn to enable U2 termination */
- mu3d_hal_u2dev_connect();
- u3d_ep0en(); /* u3d_ep0en will update g_speed. */
- mu3d_hal_set_speed(g_speed); /* do we really need set speed here ?? */
- ltssm = 0;
- }
- #if defined(DBG_USB_LTSSM)
- report_ltssm_type(ltssm);
- #endif
- if (ltssm & ENTER_U0_INTR) {
- #if DBG_USB_IRQ
- DBG_I("ENTER_U0_INTR");
- #endif
- mu3d_initialize_drv();
- g_tx_fifo_addr = USB_TX_FIFO_START_ADDRESS;
- g_rx_fifo_addr = USB_RX_FIFO_START_ADDRESS;
- set_address = 0;
- intrtx = 0;
- intrrx = 0;
- }
- #ifndef POWER_SAVING_MODE
- if (ltssm & U3_RESUME_INTR) {
- DBG_I("[INTR] Resume \n");
- clrbits(U3D_SSUSB_U3_CTRL_0P, SSUSB_U3_PORT_PDN);
- clrbits(U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
- while (!(readl(U3D_SSUSB_IP_PW_STS1) & SSUSB_U3_MAC_RST_B_STS));
- setbits(U3D_LINK_POWER_CONTROL, UX_EXIT);
- }
- #endif
- } // ltssm
- #endif // #if SUPPORT_U3
- if (intrusb & DISCONN_INTR) {
- DBG_I("[INTR] DISCONN_INTR\n");
- }
- if (intrusb & CONN_INTR) {
- DBG_I("[INTR] CONN_INTR\n");
- }
- if (intrusb & SUSPEND_INTR) {
- DBG_I("[INTR] SUSPEND_INTR\n");
- /* mt_udc_suspend will also call stop qmu */
- mt_udc_suspend();
- /*
- * work around: Only disconnect U2 will stop here,
- * Deal with 1. U2->U2 or U2->U3
- * we need to "reset" or to "clean" SSUSB fail counnter
- * to enable U3 for next enumeration.
- *
- * Otherwise U3 cannot detect speed.
- */
- #if defined(USB_RESET_AFTER_SUSPEND)
- mt_udc_reset(U3D_DFT_SPEED);
- mt_usb_disconnect_internal();
- /* soft connect U2 or U3 by g_speed */
- mt_usb_connect_internal();
- #else
- mt_usb_disconnect_internal();
- mu3d_hal_u3dev_connect();
- #endif
- }
- //TODO: Possibly don't need to handle this interrupt
- if (intrusb & LPM_INTR) {
- DBG_I("[INTR] LPM Interrupt\n");
- temp = readl(U3D_USB20_LPM_PARAM);
- DBG_I("[INTR] %x, BESL: %x, x <= %x <= %x\n",
- temp&0xf, (temp >> 8) & 0xf, (temp >> 12) & 0xf, (temp >> 4) & 0xf);
- temp = readl(U3D_POWER_MANAGEMENT);
- DBG_I("[RWP]: %x\n", (temp & LPM_RWP) >> 11);
- //if (g_sw_rw)
- {
- // s/w LPM only
- setbits(U3D_USB20_MISC_CONTROL, LPM_U3_ACK_EN);
- //wait a while before remote wakeup, so xHCI PLS status is not affected
- mdelay(20);
- setbits(U3D_POWER_MANAGEMENT, RESUME);
- DBG_I("RESUME: %d\n", readl(U3D_POWER_MANAGEMENT) & RESUME);
- }
- }
- if (intrusb & LPM_RESUME_INTR) {
- DBG_I("[INTR] LPM Resume\n");
- if (!(readl(U3D_POWER_MANAGEMENT) & LPM_HRWE)) {
- setbits(U3D_USB20_MISC_CONTROL, LPM_U3_ACK_EN);
- }
- }
- /* Check for resume from suspend mode */
- if (intrusb & RESUME_INTR) {
- DBG_I("[INTR] Resume Interrupt\n");
- }
- #ifdef SUPPORT_DMA
- if (dmaintr) {
- u3d_dma_handler(dmaintr);
- }
- #endif
- /* For EP0 */
- if ((intrtx & 0x1) || (intrrx & 0x1)) {
- if (intrrx & 0x1) {
- DBG_I("Service SETUPEND");
- intrrx = intrrx & ~0x1; //SETUPENDISR of EP0
- }
- mt_udc_ep0_handler();
- intrtx = intrtx & ~0x1; //EPISR
- //intrrx = intrrx & ~0x1; //SETUPENDISR of EP0
- //ep0_state = EP0_IDLE;
- }
- /* For EPx (TX) */
- if (intrtx) {
- for (ep_num = 1; ep_num < MT_EP_NUM; ep_num++) {
- if (intrtx & EPMASK(ep_num)) {
- mt_udc_epx_handler(ep_num, USB_DIR_IN);
- }
- }
- }
- /* For EPx (RX) */
- if (intrrx) {
- for (ep_num = 1; ep_num < MT_EP_NUM; ep_num++) {
- if (intrrx & EPMASK(ep_num)) {
- mt_udc_epx_handler(ep_num, USB_DIR_OUT);
- }
- }
- }
- }
- /* from usbtty.c */
- void service_interrupts(void) {
- u32 ltssm;
- u32 intrusb;
- u32 dmaintr;
- u16 intrtx;
- u16 intrrx;
- u32 intrqmu;
- u32 intrqmudone;
- u32 linkint;
- u32 intrep;
- u32 lv1_isr;
- /* give ltssm and intrusb initial value */
- ltssm = 0;
- intrusb = 0;
- intrqmu = 0;
- intrqmudone = 0;
- /* read */
- lv1_isr = readl(U3D_LV1ISR);
- if (lv1_isr & MAC2_INTR) {
- intrusb = readl(U3D_COMMON_USB_INTR) & readl(U3D_COMMON_USB_INTR_ENABLE);
- }
- #ifdef SUPPORT_U3
- if (lv1_isr & MAC3_INTR) {
- ltssm = readl(U3D_LTSSM_INTR) & readl(U3D_LTSSM_INTR_ENABLE);
- }
- #endif
- dmaintr = readl(U3D_DMAISR) & readl(U3D_DMAIER);
- intrep = readl(U3D_EPISR) & readl(U3D_EPIER);
- #ifdef SUPPORT_QMU
- intrqmu = readl(U3D_QISAR1);
- intrqmudone = readl(U3D_QISAR0) & readl(U3D_QIER0);
- #endif
- intrtx = intrep & 0xffff;
- intrrx = (intrep >> 16);
- linkint = readl(U3D_DEV_LINK_INTR) & readl(U3D_DEV_LINK_INTR_ENABLE);
- #if DBG_USB_IRQ
- DBG_I("intrqmudone: %x\n",intrqmudone);
- DBG_I("intrep: %x\n",intrep);
- DBG_I("interrupt: intrusb [%x] intrtx[%x] intrrx [%x] intrdma[%x] intrqmu [%x] intrltssm [%x]\r\n"
- , intrusb, intrtx, intrrx, dmaintr, intrqmu, ltssm);
- #endif
- if (!(intrusb || intrep || dmaintr || intrqmu || ltssm || intrqmudone)) {
- DBG_I("[NULL INTR] REG_INTRL1 = 0x%08X\n",
- (u32)lv1_isr);
- }
- #ifdef SUPPORT_QMU
- writel(intrqmudone, U3D_QISAR0);
- #endif
- if (lv1_isr & MAC2_INTR) {
- writel(intrusb, U3D_COMMON_USB_INTR);
- }
- #ifdef SUPPORT_U3
- if (lv1_isr & MAC3_INTR) {
- writel(ltssm, U3D_LTSSM_INTR);
- }
- #endif
- writel(intrep, U3D_EPISR);
- writel(linkint, U3D_DEV_LINK_INTR);
- if (ltssm | intrusb | dmaintr | intrtx
- | intrrx | intrqmu | intrqmudone | linkint) {
- mt_udc_irq(ltssm, intrusb, dmaintr, intrtx, intrrx,
- intrqmu, intrqmudone, linkint);
- }
- }
- void lk_usb_scheduler(void) {
- mt_irq_ack(MT_USB0_IRQ_ID);
- service_interrupts();
- return;
- }
- int mt_usb_irq_init(void) {
- /* disable all endpoint interrupts */
- mu3d_hal_disable_intr();
- /* 2. Ack all gpt irq if needed */
- //writel(0x3F, GPT_IRQ_ACK);
- /* 3. Register usb irq */
- mt_irq_set_sens(MT_USB0_IRQ_ID, MT65xx_LEVEL_SENSITIVE);
- mt_irq_set_polarity(MT_USB0_IRQ_ID, MT65xx_POLARITY_LOW);
- return 0;
- }
- /* Turn on the USB connection by enabling the pullup resistor */
- void mt_usb_connect_internal(void) {
- if (g_speed != SSUSB_SPEED_SUPER) {
- mu3d_hal_u2dev_connect();
- } else {
- mu3d_hal_u3dev_connect();
- }
- }
- /* Turn off the USB connection by disabling the pullup resistor */
- void mt_usb_disconnect_internal(void) {
- mu3d_hal_u2dev_disconnect();
- mu3d_hal_u3dev_disconnect();
- }
- int udc_init(struct udc_device *dev) {
- struct udc_descriptor *desc = NULL;
- #ifdef USB_GINTR
- #ifdef USB_HSDMA_ISR
- u32 usb_dmaintr;
- #endif
- #endif
- DBG_I("%s:\n", __func__);
- DBG_I("ep0_urb: %p\n", ep0_urb);
- /* RESET */
- /*
- * mt_usb_disconnect_internal can be removed:
- * if we call udc_stop() in cmd_reboot and cmd_reboot_bootloader.
- */
- //mt_usb_disconnect_internal();
- thread_sleep(20);
- /* usb phy init */
- board_usb_init();
- thread_sleep(20);
- /* allocate ep0 */
- ep0out = _udc_endpoint_alloc(EP0, 0, EP0_MAX_PACKET_SIZE);
- ep0in = _udc_endpoint_alloc(EP0, 1, EP0_MAX_PACKET_SIZE);
- ep0req = udc_request_alloc();
- ep0req->buf = malloc(EP0_BUF_SZ);
- if (!ep0req->buf)
- return -ENOMEM;
- ep0_urb->buf = malloc(EP0_BUF_SZ);
- if (!ep0_urb->buf)
- return -ENOMEM;
- /* create and register a language table descriptor */
- /* language 0x0409 is US English */
- desc = udc_descriptor_alloc(TYPE_STRING, EP0, 4);
- if (desc == NULL) {
- DBG_I("%s:alloc descriptor return NULL\n", __func__);
- return FALSE;
- }
- desc->data[2] = 0x09;
- desc->data[3] = 0x04;
- udc_descriptor_register(desc);
- #ifdef SUPPORT_U3
- /* allocate this twice otherwise desc_list and desc_list_u3 will have 2 same head */
- desc = udc_descriptor_alloc(TYPE_STRING, EP0, 4);
- desc->data[2] = 0x09;
- desc->data[3] = 0x04;
- udc_descriptor_register_u3(desc);
- #endif
- #ifdef SUPPORT_QMU
- mu3d_hal_alloc_qmu_mem();
- #endif
- #ifdef USB_HSDMA_ISR
- /* setting HSDMA interrupt register */
- usb_dmaintr = (0xff | 0xff << USB_DMA_INTR_UNMASK_SET_OFFSET);
- writel(usb_dmaintr, USB_DMA_INTR);
- #endif
- the_device = dev;
- return 0;
- }
- void udc_endpoint_free(struct udc_endpoint *ept) {
- /* todo */
- }
- struct udc_request *udc_request_alloc(void) {
- struct udc_request *req;
- req = malloc(sizeof(*req));
- if (!req)
- panic("%s cannot allocate memory!\n", __func__);
- req->buf = NULL;
- req->length = 0;
- return req;
- }
- void udc_request_free(struct udc_request *req) {
- free(req);
- }
- /* Called to start packet transmission. */
- /*
- * It must be applied in udc_request_queue when polling mode is used.
- * (When USB_GINTR is undefined).
- * If interrupt mode is used, you can use
- * mt_udc_epx_handler(ept->num, USB_DIR_IN); to replace mt_ep_write make ISR
- * do it for you.
- */
- static int mt_ep_write(struct udc_endpoint *ept) {
- int ep_num = ept->num;
- int count;
- u32 csr;
- /* udc_endpoint_write: cannot write ep0 */
- if (ep_num == 0)
- return FALSE;
- /* udc_endpoint_write: cannot write USB_DIR_OUT */
- if (ept->in == 0) /* USB_DIR_OUT: val is 0x0; in == 0 here */
- return FALSE;
- csr = USB_READCSR32(U3D_TX1CSR0, ep_num);
- if (csr & TX_TXPKTRDY) {
- #if DBG_USB_GENERAL
- DBG_I("udc_endpoint_write: ep%d is not ready to be written\n",
- ep_num);
- #endif
- return FALSE;
- }
- count = mt_write_fifo(ept);
- csr |= TX_TXPKTRDY;
- USB_WRITECSR32(U3D_TX1CSR0, ep_num, csr);
- return count;
- }
- int udc_request_queue(struct udc_endpoint *ept, struct udc_request *req) {
- #ifdef SUPPORT_QMU
- u8 *pbuf;
- #endif
- #ifdef SUPPORT_QMU
- /* don't dump debug message here, will cause ISR fail */
- /* work around for abnormal disconnect line during qmu transfer */
- if (!usb_online)
- return 0;
- #endif
- #if DBG_USB_GENERAL
- DBG_I("%s: ept %d %s queue req=%p, req->length=%x\n",
- __func__, ept->num, ept->in ? "in" : "out", req, req->length);
- DBG_I("%s: ept %d: %p, ept->in: %s, ept->rcv_urb->buf: %p, ept->tx_urb->buf: %p, req->buf: %p\n",
- __func__, ept->num, ept, ept->in ? "IN" : "OUT" , ept->rcv_urb->buf, ept->tx_urb->buf, req->buf);
- #endif
- enter_critical_section();
- ept->req = req;
- ept->status = 0; /* ACTIVE */
- ept->sent = 0;
- ept->last = 0;
- /* read */
- if (!ept->in) {
- /* update dst buffer with request's address */
- ept->rcv_urb->buf = req->buf;
- ept->rcv_urb->actual_length = 0;
- /* unmask EPx INTRRXE */
- /*
- * To avoid the parallely access the buffer,
- * it is umasked here and umask at complete.
- */
- #ifdef SUPPORT_QMU /* For QMU, don't enable EP interrupts. */
- pbuf = ept->rcv_urb->buf;
- /* FASTBOOT COMMAND */
- if (req->length <= GPD_BUF_SIZE_ALIGN) {
- mu3d_hal_insert_transfer_gpd(ept->num, USB_DIR_OUT, pbuf, req->length, true, true, false, (ept->type == USB_EP_XFER_ISO ? 0 : 1), ept->maxpkt);
- } else { /* FASTBOOT DATA */
- DBG_C("udc_request exceeded the maximum QMU buffer size GPD_BUF_SIZE_ALIGN\n");
- }
- /* start transfer */
- arch_clean_invalidate_cache_range((addr_t) ept->rcv_urb->buf, req->length);
- mu3d_hal_resume_qmu(ept->num, USB_DIR_OUT);
- #else /* For PIO, enable EP interrupts */
- writel(readl(U3D_EPIER) | (BIT16 << ept->num), U3D_EPIESR);
- #endif
- }
- /* write */
- if (ept->in) {
- ept->tx_urb->buf = req->buf;
- ept->tx_urb->actual_length = req->length;
- #ifdef SUPPORT_QMU /* For QMU, we don't call mt_ep_write() */
- //mu3d_hal_insert_transfer_gpd(ept->num, USB_DIR_IN, ept->tx_urb->buf, req->length, true, true, false, (ept->type == USB_EP_XFER_ISO ? 0 : 1), ept->maxpkt);
- /* According to usb_read implementation on PC side, ZLP flag should not be set */
- mu3d_hal_insert_transfer_gpd(ept->num, USB_DIR_IN, ept->tx_urb->buf, req->length, true, true, false, 0, ept->maxpkt);
- arch_clean_invalidate_cache_range((addr_t) ept->tx_urb->buf, req->length);
- mu3d_hal_resume_qmu(ept->num, USB_DIR_IN);
- #else /* For PIO, call mt_ep_write() */
- mt_ep_write(ept);
- #endif
- }
- exit_critical_section();
- return 0;
- }
- int udc_register_gadget(struct udc_gadget *gadget) {
- if (the_gadget) {
- DBG_C("only one gadget supported\n");
- return FALSE;
- }
- the_gadget = gadget;
- return 0;
- }
- static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data) {
- data[0] = 7;
- data[1] = TYPE_ENDPOINT;
- data[2] = ept->num | (ept->in ? USB_DIR_IN : USB_DIR_OUT);
- data[3] = 0x02; /* bulk -- the only kind we support */
- data[4] = 0x00; // ept->maxpkt; 512bytes
- data[5] = 0x02; // ept->maxpkt >> 8; 512bytes
- data[6] = ept->in ? 0x00 : 0x01;
- }
- #ifdef SUPPORT_U3
- static void udc_ept_desc_fill_u3(struct udc_endpoint *ept, unsigned char *data) {
- data[0] = 7;
- data[1] = TYPE_ENDPOINT;
- data[2] = ept->num | (ept->in ? USB_DIR_IN : USB_DIR_OUT);
- data[3] = 0x02; /* bulk -- the only kind we support */
- data[4] = 0x00; /* ept->maxpkt; 1024bytes */
- data[5] = 0x04; /* ept->maxpkt >> 8; 1024bytes */
- data[6] = ept->in ? 0x00 : 0x01;
- }
- #endif
- static unsigned udc_ifc_desc_size(struct udc_gadget *g) {
- return 9 + g->ifc_endpoints * 7;
- }
- static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data) {
- unsigned n;
- data[0] = 0x09;
- data[1] = TYPE_INTERFACE;
- data[2] = 0x00; /* ifc number */
- data[3] = 0x00; /* alt number */
- data[4] = g->ifc_endpoints; /* 0x02 */
- data[5] = g->ifc_class; /* 0xff */
- data[6] = g->ifc_subclass; /* 0x42 */
- data[7] = g->ifc_protocol; /* 0x03 */
- data[8] = udc_string_desc_alloc(g->ifc_string);
- data += 9;
- for (n = 0; n < g->ifc_endpoints; n++) {
- udc_ept_desc_fill(g->ept[n], data);
- data += 7;
- }
- }
- #ifdef SUPPORT_U3
- static void udc_companion_desc_fill(unsigned char *data) {
- data[0] = 6;
- data[1] = TYPE_SS_EP_COMP;
- data[2] = 0x0f; /* max burst: 0x0~0xf */
- data[3] = 0x00;
- data[4] = 0x00;
- data[5] = 0x00;
- }
- static unsigned udc_ifc_desc_size_u3(struct udc_gadget *g) {
- return 9 + g->ifc_endpoints * (7 + 6); /* Endpoint + Companion desc */
- }
- static void udc_ifc_desc_fill_u3(struct udc_gadget *g, unsigned char *data) {
- unsigned n;
- data[0] = 0x09;
- data[1] = TYPE_INTERFACE;
- data[2] = 0x00; /* ifc number */
- data[3] = 0x00; /* alt number */
- data[4] = g->ifc_endpoints; /* 0x02 */
- data[5] = g->ifc_class; /* 0xFF */
- data[6] = g->ifc_subclass; /* 0x42 */
- data[7] = g->ifc_protocol; /* 0x03 <-> ref: 0x01 */
- data[8] = udc_string_desc_alloc_u3(g->ifc_string);
- data += 9;
- for (n = 0; n < g->ifc_endpoints; n++) {
- udc_ept_desc_fill_u3(g->ept[n], data);
- data += 7;
- udc_companion_desc_fill(data);
- data += 6;
- }
- }
- static void udc_devcapa_desc_fill_u2(unsigned char *data) {
- /* data 0-6 (BOS 5-11) */
- data[0] = 0x07; /* bLength: 7 */
- data[1] = 0x10; /* bDescriptorType: DEVICE CAPABILITY */
- data[2] = 0x02; /* bDevCapabilityType: USB 2.0 Ext Descriptor */
- data[3] = 0x02; /* bmAttributes[4]: LPM (SuperSpeed) */
- data[4] = 0x00;
- data[5] = 0x00;
- data[6] = 0x00;
- }
- static void udc_devcapa_desc_fill_u3(unsigned char *data) {
- /* data 0-9 (BOS 12-21) */
- data[0] = 0x0A; /* bLength: 10 */
- data[1] = 0x10; /* bDescriptorType: DEVICE CAPABILITY */
- data[2] = 0x03; /* bDevCapabilityType: SuperSpeed */
- data[3] = 0x00; /* bmAttributes: Don't support LTM */
- data[4] = 0x0E; /* wSpeedsSupported[0]: b'1110 */
- data[5] = 0x00; /* wSpeedsSupported[1] */
- data[6] = 0x01; /* bFunctionalitySupport */
- data[7] = 0x0A; /* bU1DevExitLat: Less than 10us */
- data[8] = 0x20; /* wU2DevExitLat[0]: 32us */
- data[9] = 0x00; /* wU2DevExitLat[1] */
- }
- #endif
- int udc_start(void) {
- struct udc_descriptor *desc;
- unsigned char *data;
- unsigned size;
- if (!the_device) {
- DBG_C("udc cannot start before init\n");
- return FALSE;
- }
- if (!the_gadget) {
- DBG_C("udc has no gadget registered\n");
- return FALSE;
- }
- /* create our device descriptor - USB2 */
- desc = udc_descriptor_alloc(TYPE_DEVICE, EP0, 18);
- if (desc == NULL) {
- DBG_C("desc is NULL!\n");
- return FALSE;
- }
- data = desc->data;
- data[2] = 0x00; /* usb spec minor rev */
- data[3] = 0x02; /* usb spec major rev */
- data[4] = 0x00; /* class */
- data[5] = 0x00; /* subclass */
- data[6] = 0x00; /* protocol */
- data[7] = 0x40; /* max packet size on ept 0 */
- memcpy(data + 8, &the_device->vendor_id, sizeof(short));
- memcpy(data + 10, &the_device->product_id, sizeof(short));
- memcpy(data + 12, &the_device->version_id, sizeof(short));
- data[14] = udc_string_desc_alloc(the_device->manufacturer);
- data[15] = udc_string_desc_alloc(the_device->product);
- data[16] = udc_string_desc_alloc(the_device->serialno);
- data[17] = 1; /* number of configurations */
- udc_descriptor_register(desc);
- #ifdef SUPPORT_U3
- /* create our device descriptor - USB3 */
- desc = udc_descriptor_alloc(TYPE_DEVICE, EP0, 18);
- data = desc->data;
- data[2] = 0x00; /* usb spec minor rev */
- data[3] = 0x03; /* usb spec major rev */
- data[4] = 0x00; /* class */
- data[5] = 0x00; /* subclass */
- data[6] = 0x00; /* protocol */
- data[7] = 0x09; /* max packet size on ept 0 (USB3) */
- memcpy(data + 8, &the_device->vendor_id, sizeof(short));
- memcpy(data + 10, &the_device->product_id, sizeof(short));
- memcpy(data + 12, &the_device->version_id, sizeof(short));
- data[14] = udc_string_desc_alloc_u3(the_device->manufacturer);
- data[15] = udc_string_desc_alloc_u3(the_device->product);
- data[16] = udc_string_desc_alloc_u3(the_device->serialno);
- data[17] = 1; /* number of configurations */
- udc_descriptor_register_u3(desc);
- /* create our BOS Binary Device Object descriptor - USB3 */
- desc = udc_descriptor_alloc(TYPE_BOS, EP0, 5);
- data = desc->data;
- /* wTotalLength: Length of this descriptor and all of its sub descriptors */
- data[2] = 0x16; /* wTotalLength[0] */
- data[3] = 0x00; /* wTotalLength[1] */
- data[4] = 0x02; /* bNumDeviceCaps: number of separate device capability descriptors in BOS */
- udc_descriptor_register_u3(desc);
- /* create our BOS Binary Device Object descriptor - USB3 (FULL) */
- desc = udc_descriptor_alloc(TYPE_BOS, EP0, 22);
- data = desc->data;
- data[0] = 0x05; /* bLength of BOS Header */
- data[2] = 0x16; /* wTotalLength[0] */
- data[3] = 0x00; /* wTotalLength[1] */
- data[4] = 0x02; /* bNumDeviceCaps: number of separate device capability descriptors in BOS */
- /* BOS 1 */
- udc_devcapa_desc_fill_u2(data + 5);
- /* BOS 2 */
- udc_devcapa_desc_fill_u3(data + 5 + 7);
- udc_descriptor_register_u3(desc);
- #endif
- /* create our configuration descriptor */
- size = 9 + udc_ifc_desc_size(the_gadget);
- desc = udc_descriptor_alloc(TYPE_CONFIGURATION, EP0, size);
- if (desc == NULL) {
- DBG_I("%s: alloc descriptor return NULL\n", __func__);
- return FALSE;
- }
- data = desc->data;
- data[0] = 0x09;
- data[2] = size;
- data[3] = size >> 8;
- data[4] = 0x01; /* number of interfaces */
- data[5] = 0x01; /* configuration value */
- data[6] = 0x00; /* configuration string */
- data[7] = 0x80; /* attributes */
- data[8] = 0x80; /* max power (250ma) -- todo fix this */
- udc_ifc_desc_fill(the_gadget, data + 9);
- udc_descriptor_register(desc);
- #ifdef SUPPORT_U3
- /* create our configuration descriptor - USB3 */
- size = 9 + udc_ifc_desc_size_u3(the_gadget);
- desc = udc_descriptor_alloc(TYPE_CONFIGURATION, EP0, size);
- data = desc->data;
- data[0] = 0x09;
- data[2] = size;
- data[3] = size >> 8;
- data[4] = 0x01; /* number of interfaces */
- data[5] = 0x01; /* configuration value */
- data[6] = 0x00; /* configuration string */
- data[7] = 0x80; /* attrib-power: bus: 0x80, self: 0xC0 */
- data[8] = 0x32; /* max power: bus: 0x32, self: 0x18 */
- udc_ifc_desc_fill_u3(the_gadget, data + 9);
- udc_descriptor_register_u3(desc);
- #endif
- #if DBG_USB_DUMP_DESC
- DBG_I("%s: dump desc_list\n", __func__);
- for (desc = desc_list; desc; desc = desc->next) {
- DBG_I("tag: %04x\n", desc->tag);
- DBG_I("len: %d\n", desc->len);
- DBG_I("data:");
- hexdump8(desc->data, desc->len);
- }
- #ifdef SUPPORT_U3
- DBG_I("%s: dump desc_list_u3\n", __func__);
- for (desc = desc_list_u3; desc; desc = desc->next) {
- DBG_I("tag: %04x\n", desc->tag);
- DBG_I("len: %d\n", desc->len);
- DBG_I("data:");
- hexdump8(desc->data, desc->len);
- }
- #endif /* ifdef SUPPORT_U3 */
- #endif
- /* register interrupt handler */
- mt_usb_irq_init();
- /* config_redriver for U3 */
- #if defined(SUPPORT_U3) && defined(HAS_REDRIVER)
- config_redriver();
- #endif
- /* go to RUN mode */
- mt_usb_phy_recover();
- /* unmask usb irq */
- #ifdef USB_GINTR
- mt_irq_unmask(MT_USB0_IRQ_ID);
- #endif
- /* udc_enable end */
- mt_udc_reset(U3D_DFT_SPEED);
- udelay(100);
- /* usb_disconnect */
- mt_usb_disconnect_internal();
- /* usb_connect */
- mt_usb_connect_internal();
- #ifndef USB_GINTR
- while (1) {
- service_interrupts();
- }
- #endif
- return 0;
- }
- int udc_stop(void) {
- thread_sleep(10);
- mt_usb_disconnect_internal();
- mt_usb_phy_savecurrent();
- return 0;
- }
|