1*f1ae32a1SGerd Hoffmann /* 2*f1ae32a1SGerd Hoffmann * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics, 3*f1ae32a1SGerd Hoffmann * USB2.0 OTG compliant core used in various chips. 4*f1ae32a1SGerd Hoffmann * 5*f1ae32a1SGerd Hoffmann * Copyright (C) 2008 Nokia Corporation 6*f1ae32a1SGerd Hoffmann * Written by Andrzej Zaborowski <andrew@openedhand.com> 7*f1ae32a1SGerd Hoffmann * 8*f1ae32a1SGerd Hoffmann * This program is free software; you can redistribute it and/or 9*f1ae32a1SGerd Hoffmann * modify it under the terms of the GNU General Public License as 10*f1ae32a1SGerd Hoffmann * published by the Free Software Foundation; either version 2 or 11*f1ae32a1SGerd Hoffmann * (at your option) version 3 of the License. 12*f1ae32a1SGerd Hoffmann * 13*f1ae32a1SGerd Hoffmann * This program is distributed in the hope that it will be useful, 14*f1ae32a1SGerd Hoffmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*f1ae32a1SGerd Hoffmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*f1ae32a1SGerd Hoffmann * GNU General Public License for more details. 17*f1ae32a1SGerd Hoffmann * 18*f1ae32a1SGerd Hoffmann * You should have received a copy of the GNU General Public License along 19*f1ae32a1SGerd Hoffmann * with this program; if not, see <http://www.gnu.org/licenses/>. 20*f1ae32a1SGerd Hoffmann * 21*f1ae32a1SGerd Hoffmann * Only host-mode and non-DMA accesses are currently supported. 22*f1ae32a1SGerd Hoffmann */ 23*f1ae32a1SGerd Hoffmann #include "qemu-common.h" 24*f1ae32a1SGerd Hoffmann #include "qemu-timer.h" 25*f1ae32a1SGerd Hoffmann #include "hw/usb.h" 26*f1ae32a1SGerd Hoffmann #include "hw/irq.h" 27*f1ae32a1SGerd Hoffmann #include "hw/hw.h" 28*f1ae32a1SGerd Hoffmann 29*f1ae32a1SGerd Hoffmann /* Common USB registers */ 30*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FADDR 0x00 /* 8-bit */ 31*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_POWER 0x01 /* 8-bit */ 32*f1ae32a1SGerd Hoffmann 33*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRTX 0x02 /* 16-bit */ 34*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRRX 0x04 35*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRTXE 0x06 36*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRRXE 0x08 37*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */ 38*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */ 39*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FRAME 0x0c /* 16-bit */ 40*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INDEX 0x0e /* 8 bit */ 41*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */ 42*f1ae32a1SGerd Hoffmann 43*f1ae32a1SGerd Hoffmann /* Per-EP registers in indexed mode */ 44*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */ 45*f1ae32a1SGerd Hoffmann 46*f1ae32a1SGerd Hoffmann /* EP FIFOs */ 47*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FIFO 0x20 48*f1ae32a1SGerd Hoffmann 49*f1ae32a1SGerd Hoffmann /* Additional Control Registers */ 50*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */ 51*f1ae32a1SGerd Hoffmann 52*f1ae32a1SGerd Hoffmann /* These are indexed */ 53*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */ 54*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */ 55*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */ 56*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */ 57*f1ae32a1SGerd Hoffmann 58*f1ae32a1SGerd Hoffmann /* Some more registers */ 59*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_VCTRL 0x68 /* 8 bit */ 60*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_HWVERS 0x6c /* 8 bit */ 61*f1ae32a1SGerd Hoffmann 62*f1ae32a1SGerd Hoffmann /* Added in HDRC 1.9(?) & MHDRC 1.4 */ 63*f1ae32a1SGerd Hoffmann /* ULPI pass-through */ 64*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ULPI_VBUSCTL 0x70 65*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ULPI_REGDATA 0x74 66*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ULPI_REGADDR 0x75 67*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ULPI_REGCTL 0x76 68*f1ae32a1SGerd Hoffmann 69*f1ae32a1SGerd Hoffmann /* Extended config & PHY control */ 70*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */ 71*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */ 72*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */ 73*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */ 74*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */ 75*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */ 76*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */ 77*f1ae32a1SGerd Hoffmann 78*f1ae32a1SGerd Hoffmann /* Per-EP BUSCTL registers */ 79*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_BUSCTL 0x80 80*f1ae32a1SGerd Hoffmann 81*f1ae32a1SGerd Hoffmann /* Per-EP registers in flat mode */ 82*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_EP 0x100 83*f1ae32a1SGerd Hoffmann 84*f1ae32a1SGerd Hoffmann /* offsets to registers in flat model */ 85*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */ 86*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */ 87*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */ 88*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */ 89*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */ 90*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */ 91*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */ 92*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */ 93*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */ 94*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */ 95*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */ 96*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */ 97*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */ 98*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */ 99*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */ 100*f1ae32a1SGerd Hoffmann 101*f1ae32a1SGerd Hoffmann /* "Bus control" registers */ 102*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXFUNCADDR 0x00 103*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXHUBADDR 0x02 104*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXHUBPORT 0x03 105*f1ae32a1SGerd Hoffmann 106*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXFUNCADDR 0x04 107*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXHUBADDR 0x06 108*f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXHUBPORT 0x07 109*f1ae32a1SGerd Hoffmann 110*f1ae32a1SGerd Hoffmann /* 111*f1ae32a1SGerd Hoffmann * MUSBHDRC Register bit masks 112*f1ae32a1SGerd Hoffmann */ 113*f1ae32a1SGerd Hoffmann 114*f1ae32a1SGerd Hoffmann /* POWER */ 115*f1ae32a1SGerd Hoffmann #define MGC_M_POWER_ISOUPDATE 0x80 116*f1ae32a1SGerd Hoffmann #define MGC_M_POWER_SOFTCONN 0x40 117*f1ae32a1SGerd Hoffmann #define MGC_M_POWER_HSENAB 0x20 118*f1ae32a1SGerd Hoffmann #define MGC_M_POWER_HSMODE 0x10 119*f1ae32a1SGerd Hoffmann #define MGC_M_POWER_RESET 0x08 120*f1ae32a1SGerd Hoffmann #define MGC_M_POWER_RESUME 0x04 121*f1ae32a1SGerd Hoffmann #define MGC_M_POWER_SUSPENDM 0x02 122*f1ae32a1SGerd Hoffmann #define MGC_M_POWER_ENSUSPEND 0x01 123*f1ae32a1SGerd Hoffmann 124*f1ae32a1SGerd Hoffmann /* INTRUSB */ 125*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_SUSPEND 0x01 126*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_RESUME 0x02 127*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_RESET 0x04 128*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_BABBLE 0x04 129*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_SOF 0x08 130*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_CONNECT 0x10 131*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_DISCONNECT 0x20 132*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_SESSREQ 0x40 133*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */ 134*f1ae32a1SGerd Hoffmann #define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */ 135*f1ae32a1SGerd Hoffmann 136*f1ae32a1SGerd Hoffmann /* DEVCTL */ 137*f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_BDEVICE 0x80 138*f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_FSDEV 0x40 139*f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_LSDEV 0x20 140*f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_VBUS 0x18 141*f1ae32a1SGerd Hoffmann #define MGC_S_DEVCTL_VBUS 3 142*f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_HM 0x04 143*f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_HR 0x02 144*f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_SESSION 0x01 145*f1ae32a1SGerd Hoffmann 146*f1ae32a1SGerd Hoffmann /* TESTMODE */ 147*f1ae32a1SGerd Hoffmann #define MGC_M_TEST_FORCE_HOST 0x80 148*f1ae32a1SGerd Hoffmann #define MGC_M_TEST_FIFO_ACCESS 0x40 149*f1ae32a1SGerd Hoffmann #define MGC_M_TEST_FORCE_FS 0x20 150*f1ae32a1SGerd Hoffmann #define MGC_M_TEST_FORCE_HS 0x10 151*f1ae32a1SGerd Hoffmann #define MGC_M_TEST_PACKET 0x08 152*f1ae32a1SGerd Hoffmann #define MGC_M_TEST_K 0x04 153*f1ae32a1SGerd Hoffmann #define MGC_M_TEST_J 0x02 154*f1ae32a1SGerd Hoffmann #define MGC_M_TEST_SE0_NAK 0x01 155*f1ae32a1SGerd Hoffmann 156*f1ae32a1SGerd Hoffmann /* CSR0 */ 157*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_FLUSHFIFO 0x0100 158*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_TXPKTRDY 0x0002 159*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_RXPKTRDY 0x0001 160*f1ae32a1SGerd Hoffmann 161*f1ae32a1SGerd Hoffmann /* CSR0 in Peripheral mode */ 162*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SVDSETUPEND 0x0080 163*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040 164*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SENDSTALL 0x0020 165*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SETUPEND 0x0010 166*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_DATAEND 0x0008 167*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SENTSTALL 0x0004 168*f1ae32a1SGerd Hoffmann 169*f1ae32a1SGerd Hoffmann /* CSR0 in Host mode */ 170*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_NO_PING 0x0800 171*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */ 172*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */ 173*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_NAKTIMEOUT 0x0080 174*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_STATUSPKT 0x0040 175*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_REQPKT 0x0020 176*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_ERROR 0x0010 177*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_SETUPPKT 0x0008 178*f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_RXSTALL 0x0004 179*f1ae32a1SGerd Hoffmann 180*f1ae32a1SGerd Hoffmann /* CONFIGDATA */ 181*f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */ 182*f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */ 183*f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_BIGENDIAN 0x20 184*f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ 185*f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ 186*f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */ 187*f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ 188*f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */ 189*f1ae32a1SGerd Hoffmann 190*f1ae32a1SGerd Hoffmann /* TXCSR in Peripheral and Host mode */ 191*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_AUTOSET 0x8000 192*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_ISO 0x4000 193*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_MODE 0x2000 194*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_DMAENAB 0x1000 195*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_FRCDATATOG 0x0800 196*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_DMAMODE 0x0400 197*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_CLRDATATOG 0x0040 198*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_FLUSHFIFO 0x0008 199*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_FIFONOTEMPTY 0x0002 200*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_TXPKTRDY 0x0001 201*f1ae32a1SGerd Hoffmann 202*f1ae32a1SGerd Hoffmann /* TXCSR in Peripheral mode */ 203*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_P_INCOMPTX 0x0080 204*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_P_SENTSTALL 0x0020 205*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_P_SENDSTALL 0x0010 206*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_P_UNDERRUN 0x0004 207*f1ae32a1SGerd Hoffmann 208*f1ae32a1SGerd Hoffmann /* TXCSR in Host mode */ 209*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200 210*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_DATATOGGLE 0x0100 211*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080 212*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_RXSTALL 0x0020 213*f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_ERROR 0x0004 214*f1ae32a1SGerd Hoffmann 215*f1ae32a1SGerd Hoffmann /* RXCSR in Peripheral and Host mode */ 216*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_AUTOCLEAR 0x8000 217*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_DMAENAB 0x2000 218*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_DISNYET 0x1000 219*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_DMAMODE 0x0800 220*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_INCOMPRX 0x0100 221*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_CLRDATATOG 0x0080 222*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_FLUSHFIFO 0x0010 223*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_DATAERROR 0x0008 224*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_FIFOFULL 0x0002 225*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_RXPKTRDY 0x0001 226*f1ae32a1SGerd Hoffmann 227*f1ae32a1SGerd Hoffmann /* RXCSR in Peripheral mode */ 228*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_P_ISO 0x4000 229*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_P_SENTSTALL 0x0040 230*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_P_SENDSTALL 0x0020 231*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_P_OVERRUN 0x0004 232*f1ae32a1SGerd Hoffmann 233*f1ae32a1SGerd Hoffmann /* RXCSR in Host mode */ 234*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_AUTOREQ 0x4000 235*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400 236*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_DATATOGGLE 0x0200 237*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_RXSTALL 0x0040 238*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_REQPKT 0x0020 239*f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_ERROR 0x0004 240*f1ae32a1SGerd Hoffmann 241*f1ae32a1SGerd Hoffmann /* HUBADDR */ 242*f1ae32a1SGerd Hoffmann #define MGC_M_HUBADDR_MULTI_TT 0x80 243*f1ae32a1SGerd Hoffmann 244*f1ae32a1SGerd Hoffmann /* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */ 245*f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02 246*f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01 247*f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08 248*f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04 249*f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_REGCTL_COMPLETE 0x02 250*f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_REGCTL_REG 0x01 251*f1ae32a1SGerd Hoffmann 252*f1ae32a1SGerd Hoffmann /* #define MUSB_DEBUG */ 253*f1ae32a1SGerd Hoffmann 254*f1ae32a1SGerd Hoffmann #ifdef MUSB_DEBUG 255*f1ae32a1SGerd Hoffmann #define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \ 256*f1ae32a1SGerd Hoffmann __LINE__, ##__VA_ARGS__) 257*f1ae32a1SGerd Hoffmann #else 258*f1ae32a1SGerd Hoffmann #define TRACE(...) 259*f1ae32a1SGerd Hoffmann #endif 260*f1ae32a1SGerd Hoffmann 261*f1ae32a1SGerd Hoffmann 262*f1ae32a1SGerd Hoffmann static void musb_attach(USBPort *port); 263*f1ae32a1SGerd Hoffmann static void musb_detach(USBPort *port); 264*f1ae32a1SGerd Hoffmann static void musb_child_detach(USBPort *port, USBDevice *child); 265*f1ae32a1SGerd Hoffmann static void musb_schedule_cb(USBPort *port, USBPacket *p); 266*f1ae32a1SGerd Hoffmann static void musb_async_cancel_device(MUSBState *s, USBDevice *dev); 267*f1ae32a1SGerd Hoffmann 268*f1ae32a1SGerd Hoffmann static USBPortOps musb_port_ops = { 269*f1ae32a1SGerd Hoffmann .attach = musb_attach, 270*f1ae32a1SGerd Hoffmann .detach = musb_detach, 271*f1ae32a1SGerd Hoffmann .child_detach = musb_child_detach, 272*f1ae32a1SGerd Hoffmann .complete = musb_schedule_cb, 273*f1ae32a1SGerd Hoffmann }; 274*f1ae32a1SGerd Hoffmann 275*f1ae32a1SGerd Hoffmann static USBBusOps musb_bus_ops = { 276*f1ae32a1SGerd Hoffmann }; 277*f1ae32a1SGerd Hoffmann 278*f1ae32a1SGerd Hoffmann typedef struct MUSBPacket MUSBPacket; 279*f1ae32a1SGerd Hoffmann typedef struct MUSBEndPoint MUSBEndPoint; 280*f1ae32a1SGerd Hoffmann 281*f1ae32a1SGerd Hoffmann struct MUSBPacket { 282*f1ae32a1SGerd Hoffmann USBPacket p; 283*f1ae32a1SGerd Hoffmann MUSBEndPoint *ep; 284*f1ae32a1SGerd Hoffmann int dir; 285*f1ae32a1SGerd Hoffmann }; 286*f1ae32a1SGerd Hoffmann 287*f1ae32a1SGerd Hoffmann struct MUSBEndPoint { 288*f1ae32a1SGerd Hoffmann uint16_t faddr[2]; 289*f1ae32a1SGerd Hoffmann uint8_t haddr[2]; 290*f1ae32a1SGerd Hoffmann uint8_t hport[2]; 291*f1ae32a1SGerd Hoffmann uint16_t csr[2]; 292*f1ae32a1SGerd Hoffmann uint16_t maxp[2]; 293*f1ae32a1SGerd Hoffmann uint16_t rxcount; 294*f1ae32a1SGerd Hoffmann uint8_t type[2]; 295*f1ae32a1SGerd Hoffmann uint8_t interval[2]; 296*f1ae32a1SGerd Hoffmann uint8_t config; 297*f1ae32a1SGerd Hoffmann uint8_t fifosize; 298*f1ae32a1SGerd Hoffmann int timeout[2]; /* Always in microframes */ 299*f1ae32a1SGerd Hoffmann 300*f1ae32a1SGerd Hoffmann uint8_t *buf[2]; 301*f1ae32a1SGerd Hoffmann int fifolen[2]; 302*f1ae32a1SGerd Hoffmann int fifostart[2]; 303*f1ae32a1SGerd Hoffmann int fifoaddr[2]; 304*f1ae32a1SGerd Hoffmann MUSBPacket packey[2]; 305*f1ae32a1SGerd Hoffmann int status[2]; 306*f1ae32a1SGerd Hoffmann int ext_size[2]; 307*f1ae32a1SGerd Hoffmann 308*f1ae32a1SGerd Hoffmann /* For callbacks' use */ 309*f1ae32a1SGerd Hoffmann int epnum; 310*f1ae32a1SGerd Hoffmann int interrupt[2]; 311*f1ae32a1SGerd Hoffmann MUSBState *musb; 312*f1ae32a1SGerd Hoffmann USBCallback *delayed_cb[2]; 313*f1ae32a1SGerd Hoffmann QEMUTimer *intv_timer[2]; 314*f1ae32a1SGerd Hoffmann }; 315*f1ae32a1SGerd Hoffmann 316*f1ae32a1SGerd Hoffmann struct MUSBState { 317*f1ae32a1SGerd Hoffmann qemu_irq irqs[musb_irq_max]; 318*f1ae32a1SGerd Hoffmann USBBus bus; 319*f1ae32a1SGerd Hoffmann USBPort port; 320*f1ae32a1SGerd Hoffmann 321*f1ae32a1SGerd Hoffmann int idx; 322*f1ae32a1SGerd Hoffmann uint8_t devctl; 323*f1ae32a1SGerd Hoffmann uint8_t power; 324*f1ae32a1SGerd Hoffmann uint8_t faddr; 325*f1ae32a1SGerd Hoffmann 326*f1ae32a1SGerd Hoffmann uint8_t intr; 327*f1ae32a1SGerd Hoffmann uint8_t mask; 328*f1ae32a1SGerd Hoffmann uint16_t tx_intr; 329*f1ae32a1SGerd Hoffmann uint16_t tx_mask; 330*f1ae32a1SGerd Hoffmann uint16_t rx_intr; 331*f1ae32a1SGerd Hoffmann uint16_t rx_mask; 332*f1ae32a1SGerd Hoffmann 333*f1ae32a1SGerd Hoffmann int setup_len; 334*f1ae32a1SGerd Hoffmann int session; 335*f1ae32a1SGerd Hoffmann 336*f1ae32a1SGerd Hoffmann uint8_t buf[0x8000]; 337*f1ae32a1SGerd Hoffmann 338*f1ae32a1SGerd Hoffmann /* Duplicating the world since 2008!... probably we should have 32 339*f1ae32a1SGerd Hoffmann * logical, single endpoints instead. */ 340*f1ae32a1SGerd Hoffmann MUSBEndPoint ep[16]; 341*f1ae32a1SGerd Hoffmann }; 342*f1ae32a1SGerd Hoffmann 343*f1ae32a1SGerd Hoffmann void musb_reset(MUSBState *s) 344*f1ae32a1SGerd Hoffmann { 345*f1ae32a1SGerd Hoffmann int i; 346*f1ae32a1SGerd Hoffmann 347*f1ae32a1SGerd Hoffmann s->faddr = 0x00; 348*f1ae32a1SGerd Hoffmann s->devctl = 0; 349*f1ae32a1SGerd Hoffmann s->power = MGC_M_POWER_HSENAB; 350*f1ae32a1SGerd Hoffmann s->tx_intr = 0x0000; 351*f1ae32a1SGerd Hoffmann s->rx_intr = 0x0000; 352*f1ae32a1SGerd Hoffmann s->tx_mask = 0xffff; 353*f1ae32a1SGerd Hoffmann s->rx_mask = 0xffff; 354*f1ae32a1SGerd Hoffmann s->intr = 0x00; 355*f1ae32a1SGerd Hoffmann s->mask = 0x06; 356*f1ae32a1SGerd Hoffmann s->idx = 0; 357*f1ae32a1SGerd Hoffmann 358*f1ae32a1SGerd Hoffmann s->setup_len = 0; 359*f1ae32a1SGerd Hoffmann s->session = 0; 360*f1ae32a1SGerd Hoffmann memset(s->buf, 0, sizeof(s->buf)); 361*f1ae32a1SGerd Hoffmann 362*f1ae32a1SGerd Hoffmann /* TODO: _DW */ 363*f1ae32a1SGerd Hoffmann s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO; 364*f1ae32a1SGerd Hoffmann for (i = 0; i < 16; i ++) { 365*f1ae32a1SGerd Hoffmann s->ep[i].fifosize = 64; 366*f1ae32a1SGerd Hoffmann s->ep[i].maxp[0] = 0x40; 367*f1ae32a1SGerd Hoffmann s->ep[i].maxp[1] = 0x40; 368*f1ae32a1SGerd Hoffmann s->ep[i].musb = s; 369*f1ae32a1SGerd Hoffmann s->ep[i].epnum = i; 370*f1ae32a1SGerd Hoffmann usb_packet_init(&s->ep[i].packey[0].p); 371*f1ae32a1SGerd Hoffmann usb_packet_init(&s->ep[i].packey[1].p); 372*f1ae32a1SGerd Hoffmann } 373*f1ae32a1SGerd Hoffmann } 374*f1ae32a1SGerd Hoffmann 375*f1ae32a1SGerd Hoffmann struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base) 376*f1ae32a1SGerd Hoffmann { 377*f1ae32a1SGerd Hoffmann MUSBState *s = g_malloc0(sizeof(*s)); 378*f1ae32a1SGerd Hoffmann int i; 379*f1ae32a1SGerd Hoffmann 380*f1ae32a1SGerd Hoffmann for (i = 0; i < musb_irq_max; i++) { 381*f1ae32a1SGerd Hoffmann s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i); 382*f1ae32a1SGerd Hoffmann } 383*f1ae32a1SGerd Hoffmann 384*f1ae32a1SGerd Hoffmann musb_reset(s); 385*f1ae32a1SGerd Hoffmann 386*f1ae32a1SGerd Hoffmann usb_bus_new(&s->bus, &musb_bus_ops, parent_device); 387*f1ae32a1SGerd Hoffmann usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops, 388*f1ae32a1SGerd Hoffmann USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); 389*f1ae32a1SGerd Hoffmann 390*f1ae32a1SGerd Hoffmann return s; 391*f1ae32a1SGerd Hoffmann } 392*f1ae32a1SGerd Hoffmann 393*f1ae32a1SGerd Hoffmann static void musb_vbus_set(MUSBState *s, int level) 394*f1ae32a1SGerd Hoffmann { 395*f1ae32a1SGerd Hoffmann if (level) 396*f1ae32a1SGerd Hoffmann s->devctl |= 3 << MGC_S_DEVCTL_VBUS; 397*f1ae32a1SGerd Hoffmann else 398*f1ae32a1SGerd Hoffmann s->devctl &= ~MGC_M_DEVCTL_VBUS; 399*f1ae32a1SGerd Hoffmann 400*f1ae32a1SGerd Hoffmann qemu_set_irq(s->irqs[musb_set_vbus], level); 401*f1ae32a1SGerd Hoffmann } 402*f1ae32a1SGerd Hoffmann 403*f1ae32a1SGerd Hoffmann static void musb_intr_set(MUSBState *s, int line, int level) 404*f1ae32a1SGerd Hoffmann { 405*f1ae32a1SGerd Hoffmann if (!level) { 406*f1ae32a1SGerd Hoffmann s->intr &= ~(1 << line); 407*f1ae32a1SGerd Hoffmann qemu_irq_lower(s->irqs[line]); 408*f1ae32a1SGerd Hoffmann } else if (s->mask & (1 << line)) { 409*f1ae32a1SGerd Hoffmann s->intr |= 1 << line; 410*f1ae32a1SGerd Hoffmann qemu_irq_raise(s->irqs[line]); 411*f1ae32a1SGerd Hoffmann } 412*f1ae32a1SGerd Hoffmann } 413*f1ae32a1SGerd Hoffmann 414*f1ae32a1SGerd Hoffmann static void musb_tx_intr_set(MUSBState *s, int line, int level) 415*f1ae32a1SGerd Hoffmann { 416*f1ae32a1SGerd Hoffmann if (!level) { 417*f1ae32a1SGerd Hoffmann s->tx_intr &= ~(1 << line); 418*f1ae32a1SGerd Hoffmann if (!s->tx_intr) 419*f1ae32a1SGerd Hoffmann qemu_irq_lower(s->irqs[musb_irq_tx]); 420*f1ae32a1SGerd Hoffmann } else if (s->tx_mask & (1 << line)) { 421*f1ae32a1SGerd Hoffmann s->tx_intr |= 1 << line; 422*f1ae32a1SGerd Hoffmann qemu_irq_raise(s->irqs[musb_irq_tx]); 423*f1ae32a1SGerd Hoffmann } 424*f1ae32a1SGerd Hoffmann } 425*f1ae32a1SGerd Hoffmann 426*f1ae32a1SGerd Hoffmann static void musb_rx_intr_set(MUSBState *s, int line, int level) 427*f1ae32a1SGerd Hoffmann { 428*f1ae32a1SGerd Hoffmann if (line) { 429*f1ae32a1SGerd Hoffmann if (!level) { 430*f1ae32a1SGerd Hoffmann s->rx_intr &= ~(1 << line); 431*f1ae32a1SGerd Hoffmann if (!s->rx_intr) 432*f1ae32a1SGerd Hoffmann qemu_irq_lower(s->irqs[musb_irq_rx]); 433*f1ae32a1SGerd Hoffmann } else if (s->rx_mask & (1 << line)) { 434*f1ae32a1SGerd Hoffmann s->rx_intr |= 1 << line; 435*f1ae32a1SGerd Hoffmann qemu_irq_raise(s->irqs[musb_irq_rx]); 436*f1ae32a1SGerd Hoffmann } 437*f1ae32a1SGerd Hoffmann } else 438*f1ae32a1SGerd Hoffmann musb_tx_intr_set(s, line, level); 439*f1ae32a1SGerd Hoffmann } 440*f1ae32a1SGerd Hoffmann 441*f1ae32a1SGerd Hoffmann uint32_t musb_core_intr_get(MUSBState *s) 442*f1ae32a1SGerd Hoffmann { 443*f1ae32a1SGerd Hoffmann return (s->rx_intr << 15) | s->tx_intr; 444*f1ae32a1SGerd Hoffmann } 445*f1ae32a1SGerd Hoffmann 446*f1ae32a1SGerd Hoffmann void musb_core_intr_clear(MUSBState *s, uint32_t mask) 447*f1ae32a1SGerd Hoffmann { 448*f1ae32a1SGerd Hoffmann if (s->rx_intr) { 449*f1ae32a1SGerd Hoffmann s->rx_intr &= mask >> 15; 450*f1ae32a1SGerd Hoffmann if (!s->rx_intr) 451*f1ae32a1SGerd Hoffmann qemu_irq_lower(s->irqs[musb_irq_rx]); 452*f1ae32a1SGerd Hoffmann } 453*f1ae32a1SGerd Hoffmann 454*f1ae32a1SGerd Hoffmann if (s->tx_intr) { 455*f1ae32a1SGerd Hoffmann s->tx_intr &= mask & 0xffff; 456*f1ae32a1SGerd Hoffmann if (!s->tx_intr) 457*f1ae32a1SGerd Hoffmann qemu_irq_lower(s->irqs[musb_irq_tx]); 458*f1ae32a1SGerd Hoffmann } 459*f1ae32a1SGerd Hoffmann } 460*f1ae32a1SGerd Hoffmann 461*f1ae32a1SGerd Hoffmann void musb_set_size(MUSBState *s, int epnum, int size, int is_tx) 462*f1ae32a1SGerd Hoffmann { 463*f1ae32a1SGerd Hoffmann s->ep[epnum].ext_size[!is_tx] = size; 464*f1ae32a1SGerd Hoffmann s->ep[epnum].fifostart[0] = 0; 465*f1ae32a1SGerd Hoffmann s->ep[epnum].fifostart[1] = 0; 466*f1ae32a1SGerd Hoffmann s->ep[epnum].fifolen[0] = 0; 467*f1ae32a1SGerd Hoffmann s->ep[epnum].fifolen[1] = 0; 468*f1ae32a1SGerd Hoffmann } 469*f1ae32a1SGerd Hoffmann 470*f1ae32a1SGerd Hoffmann static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess) 471*f1ae32a1SGerd Hoffmann { 472*f1ae32a1SGerd Hoffmann int detect_prev = prev_dev && prev_sess; 473*f1ae32a1SGerd Hoffmann int detect = !!s->port.dev && s->session; 474*f1ae32a1SGerd Hoffmann 475*f1ae32a1SGerd Hoffmann if (detect && !detect_prev) { 476*f1ae32a1SGerd Hoffmann /* Let's skip the ID pin sense and VBUS sense formalities and 477*f1ae32a1SGerd Hoffmann * and signal a successful SRP directly. This should work at least 478*f1ae32a1SGerd Hoffmann * for the Linux driver stack. */ 479*f1ae32a1SGerd Hoffmann musb_intr_set(s, musb_irq_connect, 1); 480*f1ae32a1SGerd Hoffmann 481*f1ae32a1SGerd Hoffmann if (s->port.dev->speed == USB_SPEED_LOW) { 482*f1ae32a1SGerd Hoffmann s->devctl &= ~MGC_M_DEVCTL_FSDEV; 483*f1ae32a1SGerd Hoffmann s->devctl |= MGC_M_DEVCTL_LSDEV; 484*f1ae32a1SGerd Hoffmann } else { 485*f1ae32a1SGerd Hoffmann s->devctl |= MGC_M_DEVCTL_FSDEV; 486*f1ae32a1SGerd Hoffmann s->devctl &= ~MGC_M_DEVCTL_LSDEV; 487*f1ae32a1SGerd Hoffmann } 488*f1ae32a1SGerd Hoffmann 489*f1ae32a1SGerd Hoffmann /* A-mode? */ 490*f1ae32a1SGerd Hoffmann s->devctl &= ~MGC_M_DEVCTL_BDEVICE; 491*f1ae32a1SGerd Hoffmann 492*f1ae32a1SGerd Hoffmann /* Host-mode bit? */ 493*f1ae32a1SGerd Hoffmann s->devctl |= MGC_M_DEVCTL_HM; 494*f1ae32a1SGerd Hoffmann #if 1 495*f1ae32a1SGerd Hoffmann musb_vbus_set(s, 1); 496*f1ae32a1SGerd Hoffmann #endif 497*f1ae32a1SGerd Hoffmann } else if (!detect && detect_prev) { 498*f1ae32a1SGerd Hoffmann #if 1 499*f1ae32a1SGerd Hoffmann musb_vbus_set(s, 0); 500*f1ae32a1SGerd Hoffmann #endif 501*f1ae32a1SGerd Hoffmann } 502*f1ae32a1SGerd Hoffmann } 503*f1ae32a1SGerd Hoffmann 504*f1ae32a1SGerd Hoffmann /* Attach or detach a device on our only port. */ 505*f1ae32a1SGerd Hoffmann static void musb_attach(USBPort *port) 506*f1ae32a1SGerd Hoffmann { 507*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) port->opaque; 508*f1ae32a1SGerd Hoffmann 509*f1ae32a1SGerd Hoffmann musb_intr_set(s, musb_irq_vbus_request, 1); 510*f1ae32a1SGerd Hoffmann musb_session_update(s, 0, s->session); 511*f1ae32a1SGerd Hoffmann } 512*f1ae32a1SGerd Hoffmann 513*f1ae32a1SGerd Hoffmann static void musb_detach(USBPort *port) 514*f1ae32a1SGerd Hoffmann { 515*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) port->opaque; 516*f1ae32a1SGerd Hoffmann 517*f1ae32a1SGerd Hoffmann musb_async_cancel_device(s, port->dev); 518*f1ae32a1SGerd Hoffmann 519*f1ae32a1SGerd Hoffmann musb_intr_set(s, musb_irq_disconnect, 1); 520*f1ae32a1SGerd Hoffmann musb_session_update(s, 1, s->session); 521*f1ae32a1SGerd Hoffmann } 522*f1ae32a1SGerd Hoffmann 523*f1ae32a1SGerd Hoffmann static void musb_child_detach(USBPort *port, USBDevice *child) 524*f1ae32a1SGerd Hoffmann { 525*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) port->opaque; 526*f1ae32a1SGerd Hoffmann 527*f1ae32a1SGerd Hoffmann musb_async_cancel_device(s, child); 528*f1ae32a1SGerd Hoffmann } 529*f1ae32a1SGerd Hoffmann 530*f1ae32a1SGerd Hoffmann static void musb_cb_tick0(void *opaque) 531*f1ae32a1SGerd Hoffmann { 532*f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = (MUSBEndPoint *) opaque; 533*f1ae32a1SGerd Hoffmann 534*f1ae32a1SGerd Hoffmann ep->delayed_cb[0](&ep->packey[0].p, opaque); 535*f1ae32a1SGerd Hoffmann } 536*f1ae32a1SGerd Hoffmann 537*f1ae32a1SGerd Hoffmann static void musb_cb_tick1(void *opaque) 538*f1ae32a1SGerd Hoffmann { 539*f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = (MUSBEndPoint *) opaque; 540*f1ae32a1SGerd Hoffmann 541*f1ae32a1SGerd Hoffmann ep->delayed_cb[1](&ep->packey[1].p, opaque); 542*f1ae32a1SGerd Hoffmann } 543*f1ae32a1SGerd Hoffmann 544*f1ae32a1SGerd Hoffmann #define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0) 545*f1ae32a1SGerd Hoffmann 546*f1ae32a1SGerd Hoffmann static void musb_schedule_cb(USBPort *port, USBPacket *packey) 547*f1ae32a1SGerd Hoffmann { 548*f1ae32a1SGerd Hoffmann MUSBPacket *p = container_of(packey, MUSBPacket, p); 549*f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = p->ep; 550*f1ae32a1SGerd Hoffmann int dir = p->dir; 551*f1ae32a1SGerd Hoffmann int timeout = 0; 552*f1ae32a1SGerd Hoffmann 553*f1ae32a1SGerd Hoffmann if (ep->status[dir] == USB_RET_NAK) 554*f1ae32a1SGerd Hoffmann timeout = ep->timeout[dir]; 555*f1ae32a1SGerd Hoffmann else if (ep->interrupt[dir]) 556*f1ae32a1SGerd Hoffmann timeout = 8; 557*f1ae32a1SGerd Hoffmann else 558*f1ae32a1SGerd Hoffmann return musb_cb_tick(ep); 559*f1ae32a1SGerd Hoffmann 560*f1ae32a1SGerd Hoffmann if (!ep->intv_timer[dir]) 561*f1ae32a1SGerd Hoffmann ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, ep); 562*f1ae32a1SGerd Hoffmann 563*f1ae32a1SGerd Hoffmann qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock_ns(vm_clock) + 564*f1ae32a1SGerd Hoffmann muldiv64(timeout, get_ticks_per_sec(), 8000)); 565*f1ae32a1SGerd Hoffmann } 566*f1ae32a1SGerd Hoffmann 567*f1ae32a1SGerd Hoffmann static int musb_timeout(int ttype, int speed, int val) 568*f1ae32a1SGerd Hoffmann { 569*f1ae32a1SGerd Hoffmann #if 1 570*f1ae32a1SGerd Hoffmann return val << 3; 571*f1ae32a1SGerd Hoffmann #endif 572*f1ae32a1SGerd Hoffmann 573*f1ae32a1SGerd Hoffmann switch (ttype) { 574*f1ae32a1SGerd Hoffmann case USB_ENDPOINT_XFER_CONTROL: 575*f1ae32a1SGerd Hoffmann if (val < 2) 576*f1ae32a1SGerd Hoffmann return 0; 577*f1ae32a1SGerd Hoffmann else if (speed == USB_SPEED_HIGH) 578*f1ae32a1SGerd Hoffmann return 1 << (val - 1); 579*f1ae32a1SGerd Hoffmann else 580*f1ae32a1SGerd Hoffmann return 8 << (val - 1); 581*f1ae32a1SGerd Hoffmann 582*f1ae32a1SGerd Hoffmann case USB_ENDPOINT_XFER_INT: 583*f1ae32a1SGerd Hoffmann if (speed == USB_SPEED_HIGH) 584*f1ae32a1SGerd Hoffmann if (val < 2) 585*f1ae32a1SGerd Hoffmann return 0; 586*f1ae32a1SGerd Hoffmann else 587*f1ae32a1SGerd Hoffmann return 1 << (val - 1); 588*f1ae32a1SGerd Hoffmann else 589*f1ae32a1SGerd Hoffmann return val << 3; 590*f1ae32a1SGerd Hoffmann 591*f1ae32a1SGerd Hoffmann case USB_ENDPOINT_XFER_BULK: 592*f1ae32a1SGerd Hoffmann case USB_ENDPOINT_XFER_ISOC: 593*f1ae32a1SGerd Hoffmann if (val < 2) 594*f1ae32a1SGerd Hoffmann return 0; 595*f1ae32a1SGerd Hoffmann else if (speed == USB_SPEED_HIGH) 596*f1ae32a1SGerd Hoffmann return 1 << (val - 1); 597*f1ae32a1SGerd Hoffmann else 598*f1ae32a1SGerd Hoffmann return 8 << (val - 1); 599*f1ae32a1SGerd Hoffmann /* TODO: what with low-speed Bulk and Isochronous? */ 600*f1ae32a1SGerd Hoffmann } 601*f1ae32a1SGerd Hoffmann 602*f1ae32a1SGerd Hoffmann hw_error("bad interval\n"); 603*f1ae32a1SGerd Hoffmann } 604*f1ae32a1SGerd Hoffmann 605*f1ae32a1SGerd Hoffmann static void musb_packet(MUSBState *s, MUSBEndPoint *ep, 606*f1ae32a1SGerd Hoffmann int epnum, int pid, int len, USBCallback cb, int dir) 607*f1ae32a1SGerd Hoffmann { 608*f1ae32a1SGerd Hoffmann USBDevice *dev; 609*f1ae32a1SGerd Hoffmann USBEndpoint *uep; 610*f1ae32a1SGerd Hoffmann int ret; 611*f1ae32a1SGerd Hoffmann int idx = epnum && dir; 612*f1ae32a1SGerd Hoffmann int ttype; 613*f1ae32a1SGerd Hoffmann 614*f1ae32a1SGerd Hoffmann /* ep->type[0,1] contains: 615*f1ae32a1SGerd Hoffmann * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow) 616*f1ae32a1SGerd Hoffmann * in bits 5:4 the transfer type (BULK / INT) 617*f1ae32a1SGerd Hoffmann * in bits 3:0 the EP num 618*f1ae32a1SGerd Hoffmann */ 619*f1ae32a1SGerd Hoffmann ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0; 620*f1ae32a1SGerd Hoffmann 621*f1ae32a1SGerd Hoffmann ep->timeout[dir] = musb_timeout(ttype, 622*f1ae32a1SGerd Hoffmann ep->type[idx] >> 6, ep->interval[idx]); 623*f1ae32a1SGerd Hoffmann ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT; 624*f1ae32a1SGerd Hoffmann ep->delayed_cb[dir] = cb; 625*f1ae32a1SGerd Hoffmann 626*f1ae32a1SGerd Hoffmann /* A wild guess on the FADDR semantics... */ 627*f1ae32a1SGerd Hoffmann dev = usb_find_device(&s->port, ep->faddr[idx]); 628*f1ae32a1SGerd Hoffmann uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf); 629*f1ae32a1SGerd Hoffmann usb_packet_setup(&ep->packey[dir].p, pid, uep); 630*f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len); 631*f1ae32a1SGerd Hoffmann ep->packey[dir].ep = ep; 632*f1ae32a1SGerd Hoffmann ep->packey[dir].dir = dir; 633*f1ae32a1SGerd Hoffmann 634*f1ae32a1SGerd Hoffmann ret = usb_handle_packet(dev, &ep->packey[dir].p); 635*f1ae32a1SGerd Hoffmann 636*f1ae32a1SGerd Hoffmann if (ret == USB_RET_ASYNC) { 637*f1ae32a1SGerd Hoffmann ep->status[dir] = len; 638*f1ae32a1SGerd Hoffmann return; 639*f1ae32a1SGerd Hoffmann } 640*f1ae32a1SGerd Hoffmann 641*f1ae32a1SGerd Hoffmann ep->status[dir] = ret; 642*f1ae32a1SGerd Hoffmann musb_schedule_cb(&s->port, &ep->packey[dir].p); 643*f1ae32a1SGerd Hoffmann } 644*f1ae32a1SGerd Hoffmann 645*f1ae32a1SGerd Hoffmann static void musb_tx_packet_complete(USBPacket *packey, void *opaque) 646*f1ae32a1SGerd Hoffmann { 647*f1ae32a1SGerd Hoffmann /* Unfortunately we can't use packey->devep because that's the remote 648*f1ae32a1SGerd Hoffmann * endpoint number and may be different than our local. */ 649*f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = (MUSBEndPoint *) opaque; 650*f1ae32a1SGerd Hoffmann int epnum = ep->epnum; 651*f1ae32a1SGerd Hoffmann MUSBState *s = ep->musb; 652*f1ae32a1SGerd Hoffmann 653*f1ae32a1SGerd Hoffmann ep->fifostart[0] = 0; 654*f1ae32a1SGerd Hoffmann ep->fifolen[0] = 0; 655*f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 656*f1ae32a1SGerd Hoffmann if (ep->status[0] != USB_RET_NAK) { 657*f1ae32a1SGerd Hoffmann #endif 658*f1ae32a1SGerd Hoffmann if (epnum) 659*f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY); 660*f1ae32a1SGerd Hoffmann else 661*f1ae32a1SGerd Hoffmann ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY; 662*f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 663*f1ae32a1SGerd Hoffmann } 664*f1ae32a1SGerd Hoffmann #endif 665*f1ae32a1SGerd Hoffmann 666*f1ae32a1SGerd Hoffmann /* Clear all of the error bits first */ 667*f1ae32a1SGerd Hoffmann if (epnum) 668*f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL | 669*f1ae32a1SGerd Hoffmann MGC_M_TXCSR_H_NAKTIMEOUT); 670*f1ae32a1SGerd Hoffmann else 671*f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | 672*f1ae32a1SGerd Hoffmann MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); 673*f1ae32a1SGerd Hoffmann 674*f1ae32a1SGerd Hoffmann if (ep->status[0] == USB_RET_STALL) { 675*f1ae32a1SGerd Hoffmann /* Command not supported by target! */ 676*f1ae32a1SGerd Hoffmann ep->status[0] = 0; 677*f1ae32a1SGerd Hoffmann 678*f1ae32a1SGerd Hoffmann if (epnum) 679*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL; 680*f1ae32a1SGerd Hoffmann else 681*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_RXSTALL; 682*f1ae32a1SGerd Hoffmann } 683*f1ae32a1SGerd Hoffmann 684*f1ae32a1SGerd Hoffmann if (ep->status[0] == USB_RET_NAK) { 685*f1ae32a1SGerd Hoffmann ep->status[0] = 0; 686*f1ae32a1SGerd Hoffmann 687*f1ae32a1SGerd Hoffmann /* NAK timeouts are only generated in Bulk transfers and 688*f1ae32a1SGerd Hoffmann * Data-errors in Isochronous. */ 689*f1ae32a1SGerd Hoffmann if (ep->interrupt[0]) { 690*f1ae32a1SGerd Hoffmann return; 691*f1ae32a1SGerd Hoffmann } 692*f1ae32a1SGerd Hoffmann 693*f1ae32a1SGerd Hoffmann if (epnum) 694*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT; 695*f1ae32a1SGerd Hoffmann else 696*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT; 697*f1ae32a1SGerd Hoffmann } 698*f1ae32a1SGerd Hoffmann 699*f1ae32a1SGerd Hoffmann if (ep->status[0] < 0) { 700*f1ae32a1SGerd Hoffmann if (ep->status[0] == USB_RET_BABBLE) 701*f1ae32a1SGerd Hoffmann musb_intr_set(s, musb_irq_rst_babble, 1); 702*f1ae32a1SGerd Hoffmann 703*f1ae32a1SGerd Hoffmann /* Pretend we've tried three times already and failed (in 704*f1ae32a1SGerd Hoffmann * case of USB_TOKEN_SETUP). */ 705*f1ae32a1SGerd Hoffmann if (epnum) 706*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_TXCSR_H_ERROR; 707*f1ae32a1SGerd Hoffmann else 708*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_ERROR; 709*f1ae32a1SGerd Hoffmann 710*f1ae32a1SGerd Hoffmann musb_tx_intr_set(s, epnum, 1); 711*f1ae32a1SGerd Hoffmann return; 712*f1ae32a1SGerd Hoffmann } 713*f1ae32a1SGerd Hoffmann /* TODO: check len for over/underruns of an OUT packet? */ 714*f1ae32a1SGerd Hoffmann 715*f1ae32a1SGerd Hoffmann #ifdef SETUPLEN_HACK 716*f1ae32a1SGerd Hoffmann if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP) 717*f1ae32a1SGerd Hoffmann s->setup_len = ep->packey[0].data[6]; 718*f1ae32a1SGerd Hoffmann #endif 719*f1ae32a1SGerd Hoffmann 720*f1ae32a1SGerd Hoffmann /* In DMA mode: if no error, assert DMA request for this EP, 721*f1ae32a1SGerd Hoffmann * and skip the interrupt. */ 722*f1ae32a1SGerd Hoffmann musb_tx_intr_set(s, epnum, 1); 723*f1ae32a1SGerd Hoffmann } 724*f1ae32a1SGerd Hoffmann 725*f1ae32a1SGerd Hoffmann static void musb_rx_packet_complete(USBPacket *packey, void *opaque) 726*f1ae32a1SGerd Hoffmann { 727*f1ae32a1SGerd Hoffmann /* Unfortunately we can't use packey->devep because that's the remote 728*f1ae32a1SGerd Hoffmann * endpoint number and may be different than our local. */ 729*f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = (MUSBEndPoint *) opaque; 730*f1ae32a1SGerd Hoffmann int epnum = ep->epnum; 731*f1ae32a1SGerd Hoffmann MUSBState *s = ep->musb; 732*f1ae32a1SGerd Hoffmann 733*f1ae32a1SGerd Hoffmann ep->fifostart[1] = 0; 734*f1ae32a1SGerd Hoffmann ep->fifolen[1] = 0; 735*f1ae32a1SGerd Hoffmann 736*f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 737*f1ae32a1SGerd Hoffmann if (ep->status[1] != USB_RET_NAK) { 738*f1ae32a1SGerd Hoffmann #endif 739*f1ae32a1SGerd Hoffmann ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT; 740*f1ae32a1SGerd Hoffmann if (!epnum) 741*f1ae32a1SGerd Hoffmann ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT; 742*f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 743*f1ae32a1SGerd Hoffmann } 744*f1ae32a1SGerd Hoffmann #endif 745*f1ae32a1SGerd Hoffmann 746*f1ae32a1SGerd Hoffmann /* Clear all of the imaginable error bits first */ 747*f1ae32a1SGerd Hoffmann ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL | 748*f1ae32a1SGerd Hoffmann MGC_M_RXCSR_DATAERROR); 749*f1ae32a1SGerd Hoffmann if (!epnum) 750*f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | 751*f1ae32a1SGerd Hoffmann MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); 752*f1ae32a1SGerd Hoffmann 753*f1ae32a1SGerd Hoffmann if (ep->status[1] == USB_RET_STALL) { 754*f1ae32a1SGerd Hoffmann ep->status[1] = 0; 755*f1ae32a1SGerd Hoffmann packey->result = 0; 756*f1ae32a1SGerd Hoffmann 757*f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL; 758*f1ae32a1SGerd Hoffmann if (!epnum) 759*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_RXSTALL; 760*f1ae32a1SGerd Hoffmann } 761*f1ae32a1SGerd Hoffmann 762*f1ae32a1SGerd Hoffmann if (ep->status[1] == USB_RET_NAK) { 763*f1ae32a1SGerd Hoffmann ep->status[1] = 0; 764*f1ae32a1SGerd Hoffmann 765*f1ae32a1SGerd Hoffmann /* NAK timeouts are only generated in Bulk transfers and 766*f1ae32a1SGerd Hoffmann * Data-errors in Isochronous. */ 767*f1ae32a1SGerd Hoffmann if (ep->interrupt[1]) 768*f1ae32a1SGerd Hoffmann return musb_packet(s, ep, epnum, USB_TOKEN_IN, 769*f1ae32a1SGerd Hoffmann packey->iov.size, musb_rx_packet_complete, 1); 770*f1ae32a1SGerd Hoffmann 771*f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_DATAERROR; 772*f1ae32a1SGerd Hoffmann if (!epnum) 773*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT; 774*f1ae32a1SGerd Hoffmann } 775*f1ae32a1SGerd Hoffmann 776*f1ae32a1SGerd Hoffmann if (ep->status[1] < 0) { 777*f1ae32a1SGerd Hoffmann if (ep->status[1] == USB_RET_BABBLE) { 778*f1ae32a1SGerd Hoffmann musb_intr_set(s, musb_irq_rst_babble, 1); 779*f1ae32a1SGerd Hoffmann return; 780*f1ae32a1SGerd Hoffmann } 781*f1ae32a1SGerd Hoffmann 782*f1ae32a1SGerd Hoffmann /* Pretend we've tried three times already and failed (in 783*f1ae32a1SGerd Hoffmann * case of a control transfer). */ 784*f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_H_ERROR; 785*f1ae32a1SGerd Hoffmann if (!epnum) 786*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_ERROR; 787*f1ae32a1SGerd Hoffmann 788*f1ae32a1SGerd Hoffmann musb_rx_intr_set(s, epnum, 1); 789*f1ae32a1SGerd Hoffmann return; 790*f1ae32a1SGerd Hoffmann } 791*f1ae32a1SGerd Hoffmann /* TODO: check len for over/underruns of an OUT packet? */ 792*f1ae32a1SGerd Hoffmann /* TODO: perhaps make use of e->ext_size[1] here. */ 793*f1ae32a1SGerd Hoffmann 794*f1ae32a1SGerd Hoffmann packey->result = ep->status[1]; 795*f1ae32a1SGerd Hoffmann 796*f1ae32a1SGerd Hoffmann if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) { 797*f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY; 798*f1ae32a1SGerd Hoffmann if (!epnum) 799*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_RXPKTRDY; 800*f1ae32a1SGerd Hoffmann 801*f1ae32a1SGerd Hoffmann ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */ 802*f1ae32a1SGerd Hoffmann /* In DMA mode: assert DMA request for this EP */ 803*f1ae32a1SGerd Hoffmann } 804*f1ae32a1SGerd Hoffmann 805*f1ae32a1SGerd Hoffmann /* Only if DMA has not been asserted */ 806*f1ae32a1SGerd Hoffmann musb_rx_intr_set(s, epnum, 1); 807*f1ae32a1SGerd Hoffmann } 808*f1ae32a1SGerd Hoffmann 809*f1ae32a1SGerd Hoffmann static void musb_async_cancel_device(MUSBState *s, USBDevice *dev) 810*f1ae32a1SGerd Hoffmann { 811*f1ae32a1SGerd Hoffmann int ep, dir; 812*f1ae32a1SGerd Hoffmann 813*f1ae32a1SGerd Hoffmann for (ep = 0; ep < 16; ep++) { 814*f1ae32a1SGerd Hoffmann for (dir = 0; dir < 2; dir++) { 815*f1ae32a1SGerd Hoffmann if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) || 816*f1ae32a1SGerd Hoffmann s->ep[ep].packey[dir].p.ep->dev != dev) { 817*f1ae32a1SGerd Hoffmann continue; 818*f1ae32a1SGerd Hoffmann } 819*f1ae32a1SGerd Hoffmann usb_cancel_packet(&s->ep[ep].packey[dir].p); 820*f1ae32a1SGerd Hoffmann /* status updates needed here? */ 821*f1ae32a1SGerd Hoffmann } 822*f1ae32a1SGerd Hoffmann } 823*f1ae32a1SGerd Hoffmann } 824*f1ae32a1SGerd Hoffmann 825*f1ae32a1SGerd Hoffmann static void musb_tx_rdy(MUSBState *s, int epnum) 826*f1ae32a1SGerd Hoffmann { 827*f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = s->ep + epnum; 828*f1ae32a1SGerd Hoffmann int pid; 829*f1ae32a1SGerd Hoffmann int total, valid = 0; 830*f1ae32a1SGerd Hoffmann TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] ); 831*f1ae32a1SGerd Hoffmann ep->fifostart[0] += ep->fifolen[0]; 832*f1ae32a1SGerd Hoffmann ep->fifolen[0] = 0; 833*f1ae32a1SGerd Hoffmann 834*f1ae32a1SGerd Hoffmann /* XXX: how's the total size of the packet retrieved exactly in 835*f1ae32a1SGerd Hoffmann * the generic case? */ 836*f1ae32a1SGerd Hoffmann total = ep->maxp[0] & 0x3ff; 837*f1ae32a1SGerd Hoffmann 838*f1ae32a1SGerd Hoffmann if (ep->ext_size[0]) { 839*f1ae32a1SGerd Hoffmann total = ep->ext_size[0]; 840*f1ae32a1SGerd Hoffmann ep->ext_size[0] = 0; 841*f1ae32a1SGerd Hoffmann valid = 1; 842*f1ae32a1SGerd Hoffmann } 843*f1ae32a1SGerd Hoffmann 844*f1ae32a1SGerd Hoffmann /* If the packet is not fully ready yet, wait for a next segment. */ 845*f1ae32a1SGerd Hoffmann if (epnum && (ep->fifostart[0]) < total) 846*f1ae32a1SGerd Hoffmann return; 847*f1ae32a1SGerd Hoffmann 848*f1ae32a1SGerd Hoffmann if (!valid) 849*f1ae32a1SGerd Hoffmann total = ep->fifostart[0]; 850*f1ae32a1SGerd Hoffmann 851*f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 852*f1ae32a1SGerd Hoffmann if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) { 853*f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 854*f1ae32a1SGerd Hoffmann if (total != 8) { 855*f1ae32a1SGerd Hoffmann TRACE("illegal SETUPPKT length of %i bytes", total); 856*f1ae32a1SGerd Hoffmann } 857*f1ae32a1SGerd Hoffmann /* Controller should retry SETUP packets three times on errors 858*f1ae32a1SGerd Hoffmann * but it doesn't make sense for us to do that. */ 859*f1ae32a1SGerd Hoffmann } 860*f1ae32a1SGerd Hoffmann 861*f1ae32a1SGerd Hoffmann return musb_packet(s, ep, epnum, pid, 862*f1ae32a1SGerd Hoffmann total, musb_tx_packet_complete, 0); 863*f1ae32a1SGerd Hoffmann } 864*f1ae32a1SGerd Hoffmann 865*f1ae32a1SGerd Hoffmann static void musb_rx_req(MUSBState *s, int epnum) 866*f1ae32a1SGerd Hoffmann { 867*f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = s->ep + epnum; 868*f1ae32a1SGerd Hoffmann int total; 869*f1ae32a1SGerd Hoffmann 870*f1ae32a1SGerd Hoffmann /* If we already have a packet, which didn't fit into the 871*f1ae32a1SGerd Hoffmann * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */ 872*f1ae32a1SGerd Hoffmann if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 && 873*f1ae32a1SGerd Hoffmann (ep->fifostart[1]) + ep->rxcount < 874*f1ae32a1SGerd Hoffmann ep->packey[1].p.iov.size) { 875*f1ae32a1SGerd Hoffmann TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount ); 876*f1ae32a1SGerd Hoffmann ep->fifostart[1] += ep->rxcount; 877*f1ae32a1SGerd Hoffmann ep->fifolen[1] = 0; 878*f1ae32a1SGerd Hoffmann 879*f1ae32a1SGerd Hoffmann ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]), 880*f1ae32a1SGerd Hoffmann ep->maxp[1]); 881*f1ae32a1SGerd Hoffmann 882*f1ae32a1SGerd Hoffmann ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT; 883*f1ae32a1SGerd Hoffmann if (!epnum) 884*f1ae32a1SGerd Hoffmann ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT; 885*f1ae32a1SGerd Hoffmann 886*f1ae32a1SGerd Hoffmann /* Clear all of the error bits first */ 887*f1ae32a1SGerd Hoffmann ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL | 888*f1ae32a1SGerd Hoffmann MGC_M_RXCSR_DATAERROR); 889*f1ae32a1SGerd Hoffmann if (!epnum) 890*f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | 891*f1ae32a1SGerd Hoffmann MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); 892*f1ae32a1SGerd Hoffmann 893*f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY; 894*f1ae32a1SGerd Hoffmann if (!epnum) 895*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_RXPKTRDY; 896*f1ae32a1SGerd Hoffmann musb_rx_intr_set(s, epnum, 1); 897*f1ae32a1SGerd Hoffmann return; 898*f1ae32a1SGerd Hoffmann } 899*f1ae32a1SGerd Hoffmann 900*f1ae32a1SGerd Hoffmann /* The driver sets maxp[1] to 64 or less because it knows the hardware 901*f1ae32a1SGerd Hoffmann * FIFO is this deep. Bigger packets get split in 902*f1ae32a1SGerd Hoffmann * usb_generic_handle_packet but we can also do the splitting locally 903*f1ae32a1SGerd Hoffmann * for performance. It turns out we can also have a bigger FIFO and 904*f1ae32a1SGerd Hoffmann * ignore the limit set in ep->maxp[1]. The Linux MUSB driver deals 905*f1ae32a1SGerd Hoffmann * OK with single packets of even 32KB and we avoid splitting, however 906*f1ae32a1SGerd Hoffmann * usb_msd.c sometimes sends a packet bigger than what Linux expects 907*f1ae32a1SGerd Hoffmann * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN. Splitting 908*f1ae32a1SGerd Hoffmann * hides this overrun from Linux. Up to 4096 everything is fine 909*f1ae32a1SGerd Hoffmann * though. Currently this is disabled. 910*f1ae32a1SGerd Hoffmann * 911*f1ae32a1SGerd Hoffmann * XXX: mind ep->fifosize. */ 912*f1ae32a1SGerd Hoffmann total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf)); 913*f1ae32a1SGerd Hoffmann 914*f1ae32a1SGerd Hoffmann #ifdef SETUPLEN_HACK 915*f1ae32a1SGerd Hoffmann /* Why should *we* do that instead of Linux? */ 916*f1ae32a1SGerd Hoffmann if (!epnum) { 917*f1ae32a1SGerd Hoffmann if (ep->packey[0].p.devaddr == 2) { 918*f1ae32a1SGerd Hoffmann total = MIN(s->setup_len, 8); 919*f1ae32a1SGerd Hoffmann } else { 920*f1ae32a1SGerd Hoffmann total = MIN(s->setup_len, 64); 921*f1ae32a1SGerd Hoffmann } 922*f1ae32a1SGerd Hoffmann s->setup_len -= total; 923*f1ae32a1SGerd Hoffmann } 924*f1ae32a1SGerd Hoffmann #endif 925*f1ae32a1SGerd Hoffmann 926*f1ae32a1SGerd Hoffmann return musb_packet(s, ep, epnum, USB_TOKEN_IN, 927*f1ae32a1SGerd Hoffmann total, musb_rx_packet_complete, 1); 928*f1ae32a1SGerd Hoffmann } 929*f1ae32a1SGerd Hoffmann 930*f1ae32a1SGerd Hoffmann static uint8_t musb_read_fifo(MUSBEndPoint *ep) 931*f1ae32a1SGerd Hoffmann { 932*f1ae32a1SGerd Hoffmann uint8_t value; 933*f1ae32a1SGerd Hoffmann if (ep->fifolen[1] >= 64) { 934*f1ae32a1SGerd Hoffmann /* We have a FIFO underrun */ 935*f1ae32a1SGerd Hoffmann TRACE("EP%d FIFO is now empty, stop reading", ep->epnum); 936*f1ae32a1SGerd Hoffmann return 0x00000000; 937*f1ae32a1SGerd Hoffmann } 938*f1ae32a1SGerd Hoffmann /* In DMA mode clear RXPKTRDY and set REQPKT automatically 939*f1ae32a1SGerd Hoffmann * (if AUTOREQ is set) */ 940*f1ae32a1SGerd Hoffmann 941*f1ae32a1SGerd Hoffmann ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL; 942*f1ae32a1SGerd Hoffmann value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++]; 943*f1ae32a1SGerd Hoffmann TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] ); 944*f1ae32a1SGerd Hoffmann return value; 945*f1ae32a1SGerd Hoffmann } 946*f1ae32a1SGerd Hoffmann 947*f1ae32a1SGerd Hoffmann static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value) 948*f1ae32a1SGerd Hoffmann { 949*f1ae32a1SGerd Hoffmann TRACE("EP%d = %02x", ep->epnum, value); 950*f1ae32a1SGerd Hoffmann if (ep->fifolen[0] >= 64) { 951*f1ae32a1SGerd Hoffmann /* We have a FIFO overrun */ 952*f1ae32a1SGerd Hoffmann TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum); 953*f1ae32a1SGerd Hoffmann return; 954*f1ae32a1SGerd Hoffmann } 955*f1ae32a1SGerd Hoffmann 956*f1ae32a1SGerd Hoffmann ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value; 957*f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY; 958*f1ae32a1SGerd Hoffmann } 959*f1ae32a1SGerd Hoffmann 960*f1ae32a1SGerd Hoffmann static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir) 961*f1ae32a1SGerd Hoffmann { 962*f1ae32a1SGerd Hoffmann if (ep->intv_timer[dir]) 963*f1ae32a1SGerd Hoffmann qemu_del_timer(ep->intv_timer[dir]); 964*f1ae32a1SGerd Hoffmann } 965*f1ae32a1SGerd Hoffmann 966*f1ae32a1SGerd Hoffmann /* Bus control */ 967*f1ae32a1SGerd Hoffmann static uint8_t musb_busctl_readb(void *opaque, int ep, int addr) 968*f1ae32a1SGerd Hoffmann { 969*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 970*f1ae32a1SGerd Hoffmann 971*f1ae32a1SGerd Hoffmann switch (addr) { 972*f1ae32a1SGerd Hoffmann /* For USB2.0 HS hubs only */ 973*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXHUBADDR: 974*f1ae32a1SGerd Hoffmann return s->ep[ep].haddr[0]; 975*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXHUBPORT: 976*f1ae32a1SGerd Hoffmann return s->ep[ep].hport[0]; 977*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXHUBADDR: 978*f1ae32a1SGerd Hoffmann return s->ep[ep].haddr[1]; 979*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXHUBPORT: 980*f1ae32a1SGerd Hoffmann return s->ep[ep].hport[1]; 981*f1ae32a1SGerd Hoffmann 982*f1ae32a1SGerd Hoffmann default: 983*f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", addr); 984*f1ae32a1SGerd Hoffmann return 0x00; 985*f1ae32a1SGerd Hoffmann }; 986*f1ae32a1SGerd Hoffmann } 987*f1ae32a1SGerd Hoffmann 988*f1ae32a1SGerd Hoffmann static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value) 989*f1ae32a1SGerd Hoffmann { 990*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 991*f1ae32a1SGerd Hoffmann 992*f1ae32a1SGerd Hoffmann switch (addr) { 993*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFUNCADDR: 994*f1ae32a1SGerd Hoffmann s->ep[ep].faddr[0] = value; 995*f1ae32a1SGerd Hoffmann break; 996*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFUNCADDR: 997*f1ae32a1SGerd Hoffmann s->ep[ep].faddr[1] = value; 998*f1ae32a1SGerd Hoffmann break; 999*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXHUBADDR: 1000*f1ae32a1SGerd Hoffmann s->ep[ep].haddr[0] = value; 1001*f1ae32a1SGerd Hoffmann break; 1002*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXHUBPORT: 1003*f1ae32a1SGerd Hoffmann s->ep[ep].hport[0] = value; 1004*f1ae32a1SGerd Hoffmann break; 1005*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXHUBADDR: 1006*f1ae32a1SGerd Hoffmann s->ep[ep].haddr[1] = value; 1007*f1ae32a1SGerd Hoffmann break; 1008*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXHUBPORT: 1009*f1ae32a1SGerd Hoffmann s->ep[ep].hport[1] = value; 1010*f1ae32a1SGerd Hoffmann break; 1011*f1ae32a1SGerd Hoffmann 1012*f1ae32a1SGerd Hoffmann default: 1013*f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", addr); 1014*f1ae32a1SGerd Hoffmann break; 1015*f1ae32a1SGerd Hoffmann }; 1016*f1ae32a1SGerd Hoffmann } 1017*f1ae32a1SGerd Hoffmann 1018*f1ae32a1SGerd Hoffmann static uint16_t musb_busctl_readh(void *opaque, int ep, int addr) 1019*f1ae32a1SGerd Hoffmann { 1020*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1021*f1ae32a1SGerd Hoffmann 1022*f1ae32a1SGerd Hoffmann switch (addr) { 1023*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFUNCADDR: 1024*f1ae32a1SGerd Hoffmann return s->ep[ep].faddr[0]; 1025*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFUNCADDR: 1026*f1ae32a1SGerd Hoffmann return s->ep[ep].faddr[1]; 1027*f1ae32a1SGerd Hoffmann 1028*f1ae32a1SGerd Hoffmann default: 1029*f1ae32a1SGerd Hoffmann return musb_busctl_readb(s, ep, addr) | 1030*f1ae32a1SGerd Hoffmann (musb_busctl_readb(s, ep, addr | 1) << 8); 1031*f1ae32a1SGerd Hoffmann }; 1032*f1ae32a1SGerd Hoffmann } 1033*f1ae32a1SGerd Hoffmann 1034*f1ae32a1SGerd Hoffmann static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value) 1035*f1ae32a1SGerd Hoffmann { 1036*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1037*f1ae32a1SGerd Hoffmann 1038*f1ae32a1SGerd Hoffmann switch (addr) { 1039*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFUNCADDR: 1040*f1ae32a1SGerd Hoffmann s->ep[ep].faddr[0] = value; 1041*f1ae32a1SGerd Hoffmann break; 1042*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFUNCADDR: 1043*f1ae32a1SGerd Hoffmann s->ep[ep].faddr[1] = value; 1044*f1ae32a1SGerd Hoffmann break; 1045*f1ae32a1SGerd Hoffmann 1046*f1ae32a1SGerd Hoffmann default: 1047*f1ae32a1SGerd Hoffmann musb_busctl_writeb(s, ep, addr, value & 0xff); 1048*f1ae32a1SGerd Hoffmann musb_busctl_writeb(s, ep, addr | 1, value >> 8); 1049*f1ae32a1SGerd Hoffmann }; 1050*f1ae32a1SGerd Hoffmann } 1051*f1ae32a1SGerd Hoffmann 1052*f1ae32a1SGerd Hoffmann /* Endpoint control */ 1053*f1ae32a1SGerd Hoffmann static uint8_t musb_ep_readb(void *opaque, int ep, int addr) 1054*f1ae32a1SGerd Hoffmann { 1055*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1056*f1ae32a1SGerd Hoffmann 1057*f1ae32a1SGerd Hoffmann switch (addr) { 1058*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXTYPE: 1059*f1ae32a1SGerd Hoffmann return s->ep[ep].type[0]; 1060*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXINTERVAL: 1061*f1ae32a1SGerd Hoffmann return s->ep[ep].interval[0]; 1062*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXTYPE: 1063*f1ae32a1SGerd Hoffmann return s->ep[ep].type[1]; 1064*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXINTERVAL: 1065*f1ae32a1SGerd Hoffmann return s->ep[ep].interval[1]; 1066*f1ae32a1SGerd Hoffmann case (MUSB_HDRC_FIFOSIZE & ~1): 1067*f1ae32a1SGerd Hoffmann return 0x00; 1068*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFOSIZE: 1069*f1ae32a1SGerd Hoffmann return ep ? s->ep[ep].fifosize : s->ep[ep].config; 1070*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCOUNT: 1071*f1ae32a1SGerd Hoffmann return s->ep[ep].rxcount; 1072*f1ae32a1SGerd Hoffmann 1073*f1ae32a1SGerd Hoffmann default: 1074*f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", addr); 1075*f1ae32a1SGerd Hoffmann return 0x00; 1076*f1ae32a1SGerd Hoffmann }; 1077*f1ae32a1SGerd Hoffmann } 1078*f1ae32a1SGerd Hoffmann 1079*f1ae32a1SGerd Hoffmann static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value) 1080*f1ae32a1SGerd Hoffmann { 1081*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1082*f1ae32a1SGerd Hoffmann 1083*f1ae32a1SGerd Hoffmann switch (addr) { 1084*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXTYPE: 1085*f1ae32a1SGerd Hoffmann s->ep[ep].type[0] = value; 1086*f1ae32a1SGerd Hoffmann break; 1087*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXINTERVAL: 1088*f1ae32a1SGerd Hoffmann s->ep[ep].interval[0] = value; 1089*f1ae32a1SGerd Hoffmann musb_ep_frame_cancel(&s->ep[ep], 0); 1090*f1ae32a1SGerd Hoffmann break; 1091*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXTYPE: 1092*f1ae32a1SGerd Hoffmann s->ep[ep].type[1] = value; 1093*f1ae32a1SGerd Hoffmann break; 1094*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXINTERVAL: 1095*f1ae32a1SGerd Hoffmann s->ep[ep].interval[1] = value; 1096*f1ae32a1SGerd Hoffmann musb_ep_frame_cancel(&s->ep[ep], 1); 1097*f1ae32a1SGerd Hoffmann break; 1098*f1ae32a1SGerd Hoffmann case (MUSB_HDRC_FIFOSIZE & ~1): 1099*f1ae32a1SGerd Hoffmann break; 1100*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFOSIZE: 1101*f1ae32a1SGerd Hoffmann TRACE("somebody messes with fifosize (now %i bytes)", value); 1102*f1ae32a1SGerd Hoffmann s->ep[ep].fifosize = value; 1103*f1ae32a1SGerd Hoffmann break; 1104*f1ae32a1SGerd Hoffmann default: 1105*f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", addr); 1106*f1ae32a1SGerd Hoffmann break; 1107*f1ae32a1SGerd Hoffmann }; 1108*f1ae32a1SGerd Hoffmann } 1109*f1ae32a1SGerd Hoffmann 1110*f1ae32a1SGerd Hoffmann static uint16_t musb_ep_readh(void *opaque, int ep, int addr) 1111*f1ae32a1SGerd Hoffmann { 1112*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1113*f1ae32a1SGerd Hoffmann uint16_t ret; 1114*f1ae32a1SGerd Hoffmann 1115*f1ae32a1SGerd Hoffmann switch (addr) { 1116*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXMAXP: 1117*f1ae32a1SGerd Hoffmann return s->ep[ep].maxp[0]; 1118*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXCSR: 1119*f1ae32a1SGerd Hoffmann return s->ep[ep].csr[0]; 1120*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXMAXP: 1121*f1ae32a1SGerd Hoffmann return s->ep[ep].maxp[1]; 1122*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCSR: 1123*f1ae32a1SGerd Hoffmann ret = s->ep[ep].csr[1]; 1124*f1ae32a1SGerd Hoffmann 1125*f1ae32a1SGerd Hoffmann /* TODO: This and other bits probably depend on 1126*f1ae32a1SGerd Hoffmann * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR. */ 1127*f1ae32a1SGerd Hoffmann if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR) 1128*f1ae32a1SGerd Hoffmann s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY; 1129*f1ae32a1SGerd Hoffmann 1130*f1ae32a1SGerd Hoffmann return ret; 1131*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCOUNT: 1132*f1ae32a1SGerd Hoffmann return s->ep[ep].rxcount; 1133*f1ae32a1SGerd Hoffmann 1134*f1ae32a1SGerd Hoffmann default: 1135*f1ae32a1SGerd Hoffmann return musb_ep_readb(s, ep, addr) | 1136*f1ae32a1SGerd Hoffmann (musb_ep_readb(s, ep, addr | 1) << 8); 1137*f1ae32a1SGerd Hoffmann }; 1138*f1ae32a1SGerd Hoffmann } 1139*f1ae32a1SGerd Hoffmann 1140*f1ae32a1SGerd Hoffmann static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value) 1141*f1ae32a1SGerd Hoffmann { 1142*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1143*f1ae32a1SGerd Hoffmann 1144*f1ae32a1SGerd Hoffmann switch (addr) { 1145*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXMAXP: 1146*f1ae32a1SGerd Hoffmann s->ep[ep].maxp[0] = value; 1147*f1ae32a1SGerd Hoffmann break; 1148*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXCSR: 1149*f1ae32a1SGerd Hoffmann if (ep) { 1150*f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] &= value & 0xa6; 1151*f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] |= value & 0xff59; 1152*f1ae32a1SGerd Hoffmann } else { 1153*f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] &= value & 0x85; 1154*f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] |= value & 0xf7a; 1155*f1ae32a1SGerd Hoffmann } 1156*f1ae32a1SGerd Hoffmann 1157*f1ae32a1SGerd Hoffmann musb_ep_frame_cancel(&s->ep[ep], 0); 1158*f1ae32a1SGerd Hoffmann 1159*f1ae32a1SGerd Hoffmann if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) || 1160*f1ae32a1SGerd Hoffmann (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) { 1161*f1ae32a1SGerd Hoffmann s->ep[ep].fifolen[0] = 0; 1162*f1ae32a1SGerd Hoffmann s->ep[ep].fifostart[0] = 0; 1163*f1ae32a1SGerd Hoffmann if (ep) 1164*f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] &= 1165*f1ae32a1SGerd Hoffmann ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY); 1166*f1ae32a1SGerd Hoffmann else 1167*f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] &= 1168*f1ae32a1SGerd Hoffmann ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY); 1169*f1ae32a1SGerd Hoffmann } 1170*f1ae32a1SGerd Hoffmann if ( 1171*f1ae32a1SGerd Hoffmann (ep && 1172*f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 1173*f1ae32a1SGerd Hoffmann (value & MGC_M_TXCSR_TXPKTRDY) && 1174*f1ae32a1SGerd Hoffmann !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) || 1175*f1ae32a1SGerd Hoffmann #else 1176*f1ae32a1SGerd Hoffmann (value & MGC_M_TXCSR_TXPKTRDY)) || 1177*f1ae32a1SGerd Hoffmann #endif 1178*f1ae32a1SGerd Hoffmann (!ep && 1179*f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 1180*f1ae32a1SGerd Hoffmann (value & MGC_M_CSR0_TXPKTRDY) && 1181*f1ae32a1SGerd Hoffmann !(value & MGC_M_CSR0_H_NAKTIMEOUT))) 1182*f1ae32a1SGerd Hoffmann #else 1183*f1ae32a1SGerd Hoffmann (value & MGC_M_CSR0_TXPKTRDY))) 1184*f1ae32a1SGerd Hoffmann #endif 1185*f1ae32a1SGerd Hoffmann musb_tx_rdy(s, ep); 1186*f1ae32a1SGerd Hoffmann if (!ep && 1187*f1ae32a1SGerd Hoffmann (value & MGC_M_CSR0_H_REQPKT) && 1188*f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 1189*f1ae32a1SGerd Hoffmann !(value & (MGC_M_CSR0_H_NAKTIMEOUT | 1190*f1ae32a1SGerd Hoffmann MGC_M_CSR0_RXPKTRDY))) 1191*f1ae32a1SGerd Hoffmann #else 1192*f1ae32a1SGerd Hoffmann !(value & MGC_M_CSR0_RXPKTRDY)) 1193*f1ae32a1SGerd Hoffmann #endif 1194*f1ae32a1SGerd Hoffmann musb_rx_req(s, ep); 1195*f1ae32a1SGerd Hoffmann break; 1196*f1ae32a1SGerd Hoffmann 1197*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXMAXP: 1198*f1ae32a1SGerd Hoffmann s->ep[ep].maxp[1] = value; 1199*f1ae32a1SGerd Hoffmann break; 1200*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCSR: 1201*f1ae32a1SGerd Hoffmann /* (DMA mode only) */ 1202*f1ae32a1SGerd Hoffmann if ( 1203*f1ae32a1SGerd Hoffmann (value & MGC_M_RXCSR_H_AUTOREQ) && 1204*f1ae32a1SGerd Hoffmann !(value & MGC_M_RXCSR_RXPKTRDY) && 1205*f1ae32a1SGerd Hoffmann (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY)) 1206*f1ae32a1SGerd Hoffmann value |= MGC_M_RXCSR_H_REQPKT; 1207*f1ae32a1SGerd Hoffmann 1208*f1ae32a1SGerd Hoffmann s->ep[ep].csr[1] &= 0x102 | (value & 0x4d); 1209*f1ae32a1SGerd Hoffmann s->ep[ep].csr[1] |= value & 0xfeb0; 1210*f1ae32a1SGerd Hoffmann 1211*f1ae32a1SGerd Hoffmann musb_ep_frame_cancel(&s->ep[ep], 1); 1212*f1ae32a1SGerd Hoffmann 1213*f1ae32a1SGerd Hoffmann if (value & MGC_M_RXCSR_FLUSHFIFO) { 1214*f1ae32a1SGerd Hoffmann s->ep[ep].fifolen[1] = 0; 1215*f1ae32a1SGerd Hoffmann s->ep[ep].fifostart[1] = 0; 1216*f1ae32a1SGerd Hoffmann s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY); 1217*f1ae32a1SGerd Hoffmann /* If double buffering and we have two packets ready, flush 1218*f1ae32a1SGerd Hoffmann * only the first one and set up the fifo at the second packet. */ 1219*f1ae32a1SGerd Hoffmann } 1220*f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 1221*f1ae32a1SGerd Hoffmann if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR)) 1222*f1ae32a1SGerd Hoffmann #else 1223*f1ae32a1SGerd Hoffmann if (value & MGC_M_RXCSR_H_REQPKT) 1224*f1ae32a1SGerd Hoffmann #endif 1225*f1ae32a1SGerd Hoffmann musb_rx_req(s, ep); 1226*f1ae32a1SGerd Hoffmann break; 1227*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCOUNT: 1228*f1ae32a1SGerd Hoffmann s->ep[ep].rxcount = value; 1229*f1ae32a1SGerd Hoffmann break; 1230*f1ae32a1SGerd Hoffmann 1231*f1ae32a1SGerd Hoffmann default: 1232*f1ae32a1SGerd Hoffmann musb_ep_writeb(s, ep, addr, value & 0xff); 1233*f1ae32a1SGerd Hoffmann musb_ep_writeb(s, ep, addr | 1, value >> 8); 1234*f1ae32a1SGerd Hoffmann }; 1235*f1ae32a1SGerd Hoffmann } 1236*f1ae32a1SGerd Hoffmann 1237*f1ae32a1SGerd Hoffmann /* Generic control */ 1238*f1ae32a1SGerd Hoffmann static uint32_t musb_readb(void *opaque, target_phys_addr_t addr) 1239*f1ae32a1SGerd Hoffmann { 1240*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1241*f1ae32a1SGerd Hoffmann int ep, i; 1242*f1ae32a1SGerd Hoffmann uint8_t ret; 1243*f1ae32a1SGerd Hoffmann 1244*f1ae32a1SGerd Hoffmann switch (addr) { 1245*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FADDR: 1246*f1ae32a1SGerd Hoffmann return s->faddr; 1247*f1ae32a1SGerd Hoffmann case MUSB_HDRC_POWER: 1248*f1ae32a1SGerd Hoffmann return s->power; 1249*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRUSB: 1250*f1ae32a1SGerd Hoffmann ret = s->intr; 1251*f1ae32a1SGerd Hoffmann for (i = 0; i < sizeof(ret) * 8; i ++) 1252*f1ae32a1SGerd Hoffmann if (ret & (1 << i)) 1253*f1ae32a1SGerd Hoffmann musb_intr_set(s, i, 0); 1254*f1ae32a1SGerd Hoffmann return ret; 1255*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRUSBE: 1256*f1ae32a1SGerd Hoffmann return s->mask; 1257*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INDEX: 1258*f1ae32a1SGerd Hoffmann return s->idx; 1259*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TESTMODE: 1260*f1ae32a1SGerd Hoffmann return 0x00; 1261*f1ae32a1SGerd Hoffmann 1262*f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): 1263*f1ae32a1SGerd Hoffmann return musb_ep_readb(s, s->idx, addr & 0xf); 1264*f1ae32a1SGerd Hoffmann 1265*f1ae32a1SGerd Hoffmann case MUSB_HDRC_DEVCTL: 1266*f1ae32a1SGerd Hoffmann return s->devctl; 1267*f1ae32a1SGerd Hoffmann 1268*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFIFOSZ: 1269*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFIFOSZ: 1270*f1ae32a1SGerd Hoffmann case MUSB_HDRC_VCTRL: 1271*f1ae32a1SGerd Hoffmann /* TODO */ 1272*f1ae32a1SGerd Hoffmann return 0x00; 1273*f1ae32a1SGerd Hoffmann 1274*f1ae32a1SGerd Hoffmann case MUSB_HDRC_HWVERS: 1275*f1ae32a1SGerd Hoffmann return (1 << 10) | 400; 1276*f1ae32a1SGerd Hoffmann 1277*f1ae32a1SGerd Hoffmann case (MUSB_HDRC_VCTRL | 1): 1278*f1ae32a1SGerd Hoffmann case (MUSB_HDRC_HWVERS | 1): 1279*f1ae32a1SGerd Hoffmann case (MUSB_HDRC_DEVCTL | 1): 1280*f1ae32a1SGerd Hoffmann return 0x00; 1281*f1ae32a1SGerd Hoffmann 1282*f1ae32a1SGerd Hoffmann case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): 1283*f1ae32a1SGerd Hoffmann ep = (addr >> 3) & 0xf; 1284*f1ae32a1SGerd Hoffmann return musb_busctl_readb(s, ep, addr & 0x7); 1285*f1ae32a1SGerd Hoffmann 1286*f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): 1287*f1ae32a1SGerd Hoffmann ep = (addr >> 4) & 0xf; 1288*f1ae32a1SGerd Hoffmann return musb_ep_readb(s, ep, addr & 0xf); 1289*f1ae32a1SGerd Hoffmann 1290*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1291*f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1292*f1ae32a1SGerd Hoffmann return musb_read_fifo(s->ep + ep); 1293*f1ae32a1SGerd Hoffmann 1294*f1ae32a1SGerd Hoffmann default: 1295*f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", (int) addr); 1296*f1ae32a1SGerd Hoffmann return 0x00; 1297*f1ae32a1SGerd Hoffmann }; 1298*f1ae32a1SGerd Hoffmann } 1299*f1ae32a1SGerd Hoffmann 1300*f1ae32a1SGerd Hoffmann static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) 1301*f1ae32a1SGerd Hoffmann { 1302*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1303*f1ae32a1SGerd Hoffmann int ep; 1304*f1ae32a1SGerd Hoffmann 1305*f1ae32a1SGerd Hoffmann switch (addr) { 1306*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FADDR: 1307*f1ae32a1SGerd Hoffmann s->faddr = value & 0x7f; 1308*f1ae32a1SGerd Hoffmann break; 1309*f1ae32a1SGerd Hoffmann case MUSB_HDRC_POWER: 1310*f1ae32a1SGerd Hoffmann s->power = (value & 0xef) | (s->power & 0x10); 1311*f1ae32a1SGerd Hoffmann /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */ 1312*f1ae32a1SGerd Hoffmann if ((value & MGC_M_POWER_RESET) && s->port.dev) { 1313*f1ae32a1SGerd Hoffmann usb_device_reset(s->port.dev); 1314*f1ae32a1SGerd Hoffmann /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */ 1315*f1ae32a1SGerd Hoffmann if ((value & MGC_M_POWER_HSENAB) && 1316*f1ae32a1SGerd Hoffmann s->port.dev->speed == USB_SPEED_HIGH) 1317*f1ae32a1SGerd Hoffmann s->power |= MGC_M_POWER_HSMODE; /* Success */ 1318*f1ae32a1SGerd Hoffmann /* Restart frame counting. */ 1319*f1ae32a1SGerd Hoffmann } 1320*f1ae32a1SGerd Hoffmann if (value & MGC_M_POWER_SUSPENDM) { 1321*f1ae32a1SGerd Hoffmann /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND 1322*f1ae32a1SGerd Hoffmann * is set, also go into low power mode. Frame counting stops. */ 1323*f1ae32a1SGerd Hoffmann /* XXX: Cleared when the interrupt register is read */ 1324*f1ae32a1SGerd Hoffmann } 1325*f1ae32a1SGerd Hoffmann if (value & MGC_M_POWER_RESUME) { 1326*f1ae32a1SGerd Hoffmann /* Wait 20ms and signal resuming on the bus. Frame counting 1327*f1ae32a1SGerd Hoffmann * restarts. */ 1328*f1ae32a1SGerd Hoffmann } 1329*f1ae32a1SGerd Hoffmann break; 1330*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRUSB: 1331*f1ae32a1SGerd Hoffmann break; 1332*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRUSBE: 1333*f1ae32a1SGerd Hoffmann s->mask = value & 0xff; 1334*f1ae32a1SGerd Hoffmann break; 1335*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INDEX: 1336*f1ae32a1SGerd Hoffmann s->idx = value & 0xf; 1337*f1ae32a1SGerd Hoffmann break; 1338*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TESTMODE: 1339*f1ae32a1SGerd Hoffmann break; 1340*f1ae32a1SGerd Hoffmann 1341*f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): 1342*f1ae32a1SGerd Hoffmann musb_ep_writeb(s, s->idx, addr & 0xf, value); 1343*f1ae32a1SGerd Hoffmann break; 1344*f1ae32a1SGerd Hoffmann 1345*f1ae32a1SGerd Hoffmann case MUSB_HDRC_DEVCTL: 1346*f1ae32a1SGerd Hoffmann s->session = !!(value & MGC_M_DEVCTL_SESSION); 1347*f1ae32a1SGerd Hoffmann musb_session_update(s, 1348*f1ae32a1SGerd Hoffmann !!s->port.dev, 1349*f1ae32a1SGerd Hoffmann !!(s->devctl & MGC_M_DEVCTL_SESSION)); 1350*f1ae32a1SGerd Hoffmann 1351*f1ae32a1SGerd Hoffmann /* It seems this is the only R/W bit in this register? */ 1352*f1ae32a1SGerd Hoffmann s->devctl &= ~MGC_M_DEVCTL_SESSION; 1353*f1ae32a1SGerd Hoffmann s->devctl |= value & MGC_M_DEVCTL_SESSION; 1354*f1ae32a1SGerd Hoffmann break; 1355*f1ae32a1SGerd Hoffmann 1356*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFIFOSZ: 1357*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFIFOSZ: 1358*f1ae32a1SGerd Hoffmann case MUSB_HDRC_VCTRL: 1359*f1ae32a1SGerd Hoffmann /* TODO */ 1360*f1ae32a1SGerd Hoffmann break; 1361*f1ae32a1SGerd Hoffmann 1362*f1ae32a1SGerd Hoffmann case (MUSB_HDRC_VCTRL | 1): 1363*f1ae32a1SGerd Hoffmann case (MUSB_HDRC_DEVCTL | 1): 1364*f1ae32a1SGerd Hoffmann break; 1365*f1ae32a1SGerd Hoffmann 1366*f1ae32a1SGerd Hoffmann case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): 1367*f1ae32a1SGerd Hoffmann ep = (addr >> 3) & 0xf; 1368*f1ae32a1SGerd Hoffmann musb_busctl_writeb(s, ep, addr & 0x7, value); 1369*f1ae32a1SGerd Hoffmann break; 1370*f1ae32a1SGerd Hoffmann 1371*f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): 1372*f1ae32a1SGerd Hoffmann ep = (addr >> 4) & 0xf; 1373*f1ae32a1SGerd Hoffmann musb_ep_writeb(s, ep, addr & 0xf, value); 1374*f1ae32a1SGerd Hoffmann break; 1375*f1ae32a1SGerd Hoffmann 1376*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1377*f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1378*f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, value & 0xff); 1379*f1ae32a1SGerd Hoffmann break; 1380*f1ae32a1SGerd Hoffmann 1381*f1ae32a1SGerd Hoffmann default: 1382*f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", (int) addr); 1383*f1ae32a1SGerd Hoffmann break; 1384*f1ae32a1SGerd Hoffmann }; 1385*f1ae32a1SGerd Hoffmann } 1386*f1ae32a1SGerd Hoffmann 1387*f1ae32a1SGerd Hoffmann static uint32_t musb_readh(void *opaque, target_phys_addr_t addr) 1388*f1ae32a1SGerd Hoffmann { 1389*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1390*f1ae32a1SGerd Hoffmann int ep, i; 1391*f1ae32a1SGerd Hoffmann uint16_t ret; 1392*f1ae32a1SGerd Hoffmann 1393*f1ae32a1SGerd Hoffmann switch (addr) { 1394*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRTX: 1395*f1ae32a1SGerd Hoffmann ret = s->tx_intr; 1396*f1ae32a1SGerd Hoffmann /* Auto clear */ 1397*f1ae32a1SGerd Hoffmann for (i = 0; i < sizeof(ret) * 8; i ++) 1398*f1ae32a1SGerd Hoffmann if (ret & (1 << i)) 1399*f1ae32a1SGerd Hoffmann musb_tx_intr_set(s, i, 0); 1400*f1ae32a1SGerd Hoffmann return ret; 1401*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRRX: 1402*f1ae32a1SGerd Hoffmann ret = s->rx_intr; 1403*f1ae32a1SGerd Hoffmann /* Auto clear */ 1404*f1ae32a1SGerd Hoffmann for (i = 0; i < sizeof(ret) * 8; i ++) 1405*f1ae32a1SGerd Hoffmann if (ret & (1 << i)) 1406*f1ae32a1SGerd Hoffmann musb_rx_intr_set(s, i, 0); 1407*f1ae32a1SGerd Hoffmann return ret; 1408*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRTXE: 1409*f1ae32a1SGerd Hoffmann return s->tx_mask; 1410*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRRXE: 1411*f1ae32a1SGerd Hoffmann return s->rx_mask; 1412*f1ae32a1SGerd Hoffmann 1413*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FRAME: 1414*f1ae32a1SGerd Hoffmann /* TODO */ 1415*f1ae32a1SGerd Hoffmann return 0x0000; 1416*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFIFOADDR: 1417*f1ae32a1SGerd Hoffmann return s->ep[s->idx].fifoaddr[0]; 1418*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFIFOADDR: 1419*f1ae32a1SGerd Hoffmann return s->ep[s->idx].fifoaddr[1]; 1420*f1ae32a1SGerd Hoffmann 1421*f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): 1422*f1ae32a1SGerd Hoffmann return musb_ep_readh(s, s->idx, addr & 0xf); 1423*f1ae32a1SGerd Hoffmann 1424*f1ae32a1SGerd Hoffmann case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): 1425*f1ae32a1SGerd Hoffmann ep = (addr >> 3) & 0xf; 1426*f1ae32a1SGerd Hoffmann return musb_busctl_readh(s, ep, addr & 0x7); 1427*f1ae32a1SGerd Hoffmann 1428*f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): 1429*f1ae32a1SGerd Hoffmann ep = (addr >> 4) & 0xf; 1430*f1ae32a1SGerd Hoffmann return musb_ep_readh(s, ep, addr & 0xf); 1431*f1ae32a1SGerd Hoffmann 1432*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1433*f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1434*f1ae32a1SGerd Hoffmann return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8); 1435*f1ae32a1SGerd Hoffmann 1436*f1ae32a1SGerd Hoffmann default: 1437*f1ae32a1SGerd Hoffmann return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8); 1438*f1ae32a1SGerd Hoffmann }; 1439*f1ae32a1SGerd Hoffmann } 1440*f1ae32a1SGerd Hoffmann 1441*f1ae32a1SGerd Hoffmann static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) 1442*f1ae32a1SGerd Hoffmann { 1443*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1444*f1ae32a1SGerd Hoffmann int ep; 1445*f1ae32a1SGerd Hoffmann 1446*f1ae32a1SGerd Hoffmann switch (addr) { 1447*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRTXE: 1448*f1ae32a1SGerd Hoffmann s->tx_mask = value; 1449*f1ae32a1SGerd Hoffmann /* XXX: the masks seem to apply on the raising edge like with 1450*f1ae32a1SGerd Hoffmann * edge-triggered interrupts, thus no need to update. I may be 1451*f1ae32a1SGerd Hoffmann * wrong though. */ 1452*f1ae32a1SGerd Hoffmann break; 1453*f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRRXE: 1454*f1ae32a1SGerd Hoffmann s->rx_mask = value; 1455*f1ae32a1SGerd Hoffmann break; 1456*f1ae32a1SGerd Hoffmann 1457*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FRAME: 1458*f1ae32a1SGerd Hoffmann /* TODO */ 1459*f1ae32a1SGerd Hoffmann break; 1460*f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFIFOADDR: 1461*f1ae32a1SGerd Hoffmann s->ep[s->idx].fifoaddr[0] = value; 1462*f1ae32a1SGerd Hoffmann s->ep[s->idx].buf[0] = 1463*f1ae32a1SGerd Hoffmann s->buf + ((value << 3) & 0x7ff ); 1464*f1ae32a1SGerd Hoffmann break; 1465*f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFIFOADDR: 1466*f1ae32a1SGerd Hoffmann s->ep[s->idx].fifoaddr[1] = value; 1467*f1ae32a1SGerd Hoffmann s->ep[s->idx].buf[1] = 1468*f1ae32a1SGerd Hoffmann s->buf + ((value << 3) & 0x7ff); 1469*f1ae32a1SGerd Hoffmann break; 1470*f1ae32a1SGerd Hoffmann 1471*f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): 1472*f1ae32a1SGerd Hoffmann musb_ep_writeh(s, s->idx, addr & 0xf, value); 1473*f1ae32a1SGerd Hoffmann break; 1474*f1ae32a1SGerd Hoffmann 1475*f1ae32a1SGerd Hoffmann case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): 1476*f1ae32a1SGerd Hoffmann ep = (addr >> 3) & 0xf; 1477*f1ae32a1SGerd Hoffmann musb_busctl_writeh(s, ep, addr & 0x7, value); 1478*f1ae32a1SGerd Hoffmann break; 1479*f1ae32a1SGerd Hoffmann 1480*f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): 1481*f1ae32a1SGerd Hoffmann ep = (addr >> 4) & 0xf; 1482*f1ae32a1SGerd Hoffmann musb_ep_writeh(s, ep, addr & 0xf, value); 1483*f1ae32a1SGerd Hoffmann break; 1484*f1ae32a1SGerd Hoffmann 1485*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1486*f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1487*f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, value & 0xff); 1488*f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, (value >> 8) & 0xff); 1489*f1ae32a1SGerd Hoffmann break; 1490*f1ae32a1SGerd Hoffmann 1491*f1ae32a1SGerd Hoffmann default: 1492*f1ae32a1SGerd Hoffmann musb_writeb(s, addr, value & 0xff); 1493*f1ae32a1SGerd Hoffmann musb_writeb(s, addr | 1, value >> 8); 1494*f1ae32a1SGerd Hoffmann }; 1495*f1ae32a1SGerd Hoffmann } 1496*f1ae32a1SGerd Hoffmann 1497*f1ae32a1SGerd Hoffmann static uint32_t musb_readw(void *opaque, target_phys_addr_t addr) 1498*f1ae32a1SGerd Hoffmann { 1499*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1500*f1ae32a1SGerd Hoffmann int ep; 1501*f1ae32a1SGerd Hoffmann 1502*f1ae32a1SGerd Hoffmann switch (addr) { 1503*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1504*f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1505*f1ae32a1SGerd Hoffmann return ( musb_read_fifo(s->ep + ep) | 1506*f1ae32a1SGerd Hoffmann musb_read_fifo(s->ep + ep) << 8 | 1507*f1ae32a1SGerd Hoffmann musb_read_fifo(s->ep + ep) << 16 | 1508*f1ae32a1SGerd Hoffmann musb_read_fifo(s->ep + ep) << 24 ); 1509*f1ae32a1SGerd Hoffmann default: 1510*f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", (int) addr); 1511*f1ae32a1SGerd Hoffmann return 0x00000000; 1512*f1ae32a1SGerd Hoffmann }; 1513*f1ae32a1SGerd Hoffmann } 1514*f1ae32a1SGerd Hoffmann 1515*f1ae32a1SGerd Hoffmann static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) 1516*f1ae32a1SGerd Hoffmann { 1517*f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1518*f1ae32a1SGerd Hoffmann int ep; 1519*f1ae32a1SGerd Hoffmann 1520*f1ae32a1SGerd Hoffmann switch (addr) { 1521*f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1522*f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1523*f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, value & 0xff); 1524*f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff); 1525*f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, (value >> 16) & 0xff); 1526*f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, (value >> 24) & 0xff); 1527*f1ae32a1SGerd Hoffmann break; 1528*f1ae32a1SGerd Hoffmann default: 1529*f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", (int) addr); 1530*f1ae32a1SGerd Hoffmann break; 1531*f1ae32a1SGerd Hoffmann }; 1532*f1ae32a1SGerd Hoffmann } 1533*f1ae32a1SGerd Hoffmann 1534*f1ae32a1SGerd Hoffmann CPUReadMemoryFunc * const musb_read[] = { 1535*f1ae32a1SGerd Hoffmann musb_readb, 1536*f1ae32a1SGerd Hoffmann musb_readh, 1537*f1ae32a1SGerd Hoffmann musb_readw, 1538*f1ae32a1SGerd Hoffmann }; 1539*f1ae32a1SGerd Hoffmann 1540*f1ae32a1SGerd Hoffmann CPUWriteMemoryFunc * const musb_write[] = { 1541*f1ae32a1SGerd Hoffmann musb_writeb, 1542*f1ae32a1SGerd Hoffmann musb_writeh, 1543*f1ae32a1SGerd Hoffmann musb_writew, 1544*f1ae32a1SGerd Hoffmann }; 1545