| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900 |
- /*
- * 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/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
- /* 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;
- static unsigned char ep0_buf[4096] __attribute__((aligned(32)));
- 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)
- + (((*(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->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;
- 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 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(4096);
- ep0_urb->buf = ep0_buf;
- /* create and register a language table descriptor */
- /* language 0x0409 is US English */
- desc = udc_descriptor_alloc(TYPE_STRING, EP0, 4);
- 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);
- 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);
- 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();
- /* 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;
- }
|