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