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