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" 24f1ae32a1SGerd Hoffmann #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 386f1ae32a1SGerd Hoffmann usb_bus_new(&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; 557f1ae32a1SGerd Hoffmann else 558f1ae32a1SGerd Hoffmann return musb_cb_tick(ep); 559f1ae32a1SGerd Hoffmann 560f1ae32a1SGerd Hoffmann if (!ep->intv_timer[dir]) 561f1ae32a1SGerd Hoffmann ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, ep); 562f1ae32a1SGerd Hoffmann 563f1ae32a1SGerd Hoffmann qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock_ns(vm_clock) + 564f1ae32a1SGerd Hoffmann muldiv64(timeout, get_ticks_per_sec(), 8000)); 565f1ae32a1SGerd Hoffmann } 566f1ae32a1SGerd Hoffmann 567f1ae32a1SGerd Hoffmann static int musb_timeout(int ttype, int speed, int val) 568f1ae32a1SGerd Hoffmann { 569f1ae32a1SGerd Hoffmann #if 1 570f1ae32a1SGerd Hoffmann return val << 3; 571f1ae32a1SGerd Hoffmann #endif 572f1ae32a1SGerd Hoffmann 573f1ae32a1SGerd Hoffmann switch (ttype) { 574f1ae32a1SGerd Hoffmann case USB_ENDPOINT_XFER_CONTROL: 575f1ae32a1SGerd Hoffmann if (val < 2) 576f1ae32a1SGerd Hoffmann return 0; 577f1ae32a1SGerd Hoffmann else if (speed == USB_SPEED_HIGH) 578f1ae32a1SGerd Hoffmann return 1 << (val - 1); 579f1ae32a1SGerd Hoffmann else 580f1ae32a1SGerd Hoffmann return 8 << (val - 1); 581f1ae32a1SGerd Hoffmann 582f1ae32a1SGerd Hoffmann case USB_ENDPOINT_XFER_INT: 583f1ae32a1SGerd Hoffmann if (speed == USB_SPEED_HIGH) 584f1ae32a1SGerd Hoffmann if (val < 2) 585f1ae32a1SGerd Hoffmann return 0; 586f1ae32a1SGerd Hoffmann else 587f1ae32a1SGerd Hoffmann return 1 << (val - 1); 588f1ae32a1SGerd Hoffmann else 589f1ae32a1SGerd Hoffmann return val << 3; 590f1ae32a1SGerd Hoffmann 591f1ae32a1SGerd Hoffmann case USB_ENDPOINT_XFER_BULK: 592f1ae32a1SGerd Hoffmann case USB_ENDPOINT_XFER_ISOC: 593f1ae32a1SGerd Hoffmann if (val < 2) 594f1ae32a1SGerd Hoffmann return 0; 595f1ae32a1SGerd Hoffmann else if (speed == USB_SPEED_HIGH) 596f1ae32a1SGerd Hoffmann return 1 << (val - 1); 597f1ae32a1SGerd Hoffmann else 598f1ae32a1SGerd Hoffmann return 8 << (val - 1); 599f1ae32a1SGerd Hoffmann /* TODO: what with low-speed Bulk and Isochronous? */ 600f1ae32a1SGerd Hoffmann } 601f1ae32a1SGerd Hoffmann 602f1ae32a1SGerd Hoffmann hw_error("bad interval\n"); 603f1ae32a1SGerd Hoffmann } 604f1ae32a1SGerd Hoffmann 605f1ae32a1SGerd Hoffmann static void musb_packet(MUSBState *s, MUSBEndPoint *ep, 606f1ae32a1SGerd Hoffmann int epnum, int pid, int len, USBCallback cb, int dir) 607f1ae32a1SGerd Hoffmann { 608f1ae32a1SGerd Hoffmann USBDevice *dev; 609f1ae32a1SGerd Hoffmann USBEndpoint *uep; 610f1ae32a1SGerd Hoffmann int ret; 611f1ae32a1SGerd Hoffmann int idx = epnum && dir; 612f1ae32a1SGerd Hoffmann int ttype; 613f1ae32a1SGerd Hoffmann 614f1ae32a1SGerd Hoffmann /* ep->type[0,1] contains: 615f1ae32a1SGerd Hoffmann * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow) 616f1ae32a1SGerd Hoffmann * in bits 5:4 the transfer type (BULK / INT) 617f1ae32a1SGerd Hoffmann * in bits 3:0 the EP num 618f1ae32a1SGerd Hoffmann */ 619f1ae32a1SGerd Hoffmann ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0; 620f1ae32a1SGerd Hoffmann 621f1ae32a1SGerd Hoffmann ep->timeout[dir] = musb_timeout(ttype, 622f1ae32a1SGerd Hoffmann ep->type[idx] >> 6, ep->interval[idx]); 623f1ae32a1SGerd Hoffmann ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT; 624f1ae32a1SGerd Hoffmann ep->delayed_cb[dir] = cb; 625f1ae32a1SGerd Hoffmann 626f1ae32a1SGerd Hoffmann /* A wild guess on the FADDR semantics... */ 627f1ae32a1SGerd Hoffmann dev = usb_find_device(&s->port, ep->faddr[idx]); 628f1ae32a1SGerd Hoffmann uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf); 629e983395dSGerd Hoffmann usb_packet_setup(&ep->packey[dir].p, pid, uep, 630e983395dSGerd Hoffmann (dev->addr << 16) | (uep->nr << 8) | pid); 631f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len); 632f1ae32a1SGerd Hoffmann ep->packey[dir].ep = ep; 633f1ae32a1SGerd Hoffmann ep->packey[dir].dir = dir; 634f1ae32a1SGerd Hoffmann 635f1ae32a1SGerd Hoffmann ret = usb_handle_packet(dev, &ep->packey[dir].p); 636f1ae32a1SGerd Hoffmann 637f1ae32a1SGerd Hoffmann if (ret == USB_RET_ASYNC) { 638*36dfe324SHans de Goede usb_device_flush_ep_queue(dev, uep); 639f1ae32a1SGerd Hoffmann ep->status[dir] = len; 640f1ae32a1SGerd Hoffmann return; 641f1ae32a1SGerd Hoffmann } 642f1ae32a1SGerd Hoffmann 643f1ae32a1SGerd Hoffmann ep->status[dir] = ret; 644f1ae32a1SGerd Hoffmann musb_schedule_cb(&s->port, &ep->packey[dir].p); 645f1ae32a1SGerd Hoffmann } 646f1ae32a1SGerd Hoffmann 647f1ae32a1SGerd Hoffmann static void musb_tx_packet_complete(USBPacket *packey, void *opaque) 648f1ae32a1SGerd Hoffmann { 649f1ae32a1SGerd Hoffmann /* Unfortunately we can't use packey->devep because that's the remote 650f1ae32a1SGerd Hoffmann * endpoint number and may be different than our local. */ 651f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = (MUSBEndPoint *) opaque; 652f1ae32a1SGerd Hoffmann int epnum = ep->epnum; 653f1ae32a1SGerd Hoffmann MUSBState *s = ep->musb; 654f1ae32a1SGerd Hoffmann 655f1ae32a1SGerd Hoffmann ep->fifostart[0] = 0; 656f1ae32a1SGerd Hoffmann ep->fifolen[0] = 0; 657f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 658f1ae32a1SGerd Hoffmann if (ep->status[0] != USB_RET_NAK) { 659f1ae32a1SGerd Hoffmann #endif 660f1ae32a1SGerd Hoffmann if (epnum) 661f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY); 662f1ae32a1SGerd Hoffmann else 663f1ae32a1SGerd Hoffmann ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY; 664f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 665f1ae32a1SGerd Hoffmann } 666f1ae32a1SGerd Hoffmann #endif 667f1ae32a1SGerd Hoffmann 668f1ae32a1SGerd Hoffmann /* Clear all of the error bits first */ 669f1ae32a1SGerd Hoffmann if (epnum) 670f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL | 671f1ae32a1SGerd Hoffmann MGC_M_TXCSR_H_NAKTIMEOUT); 672f1ae32a1SGerd Hoffmann else 673f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | 674f1ae32a1SGerd Hoffmann MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); 675f1ae32a1SGerd Hoffmann 676f1ae32a1SGerd Hoffmann if (ep->status[0] == USB_RET_STALL) { 677f1ae32a1SGerd Hoffmann /* Command not supported by target! */ 678f1ae32a1SGerd Hoffmann ep->status[0] = 0; 679f1ae32a1SGerd Hoffmann 680f1ae32a1SGerd Hoffmann if (epnum) 681f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL; 682f1ae32a1SGerd Hoffmann else 683f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_RXSTALL; 684f1ae32a1SGerd Hoffmann } 685f1ae32a1SGerd Hoffmann 686f1ae32a1SGerd Hoffmann if (ep->status[0] == USB_RET_NAK) { 687f1ae32a1SGerd Hoffmann ep->status[0] = 0; 688f1ae32a1SGerd Hoffmann 689f1ae32a1SGerd Hoffmann /* NAK timeouts are only generated in Bulk transfers and 690f1ae32a1SGerd Hoffmann * Data-errors in Isochronous. */ 691f1ae32a1SGerd Hoffmann if (ep->interrupt[0]) { 692f1ae32a1SGerd Hoffmann return; 693f1ae32a1SGerd Hoffmann } 694f1ae32a1SGerd Hoffmann 695f1ae32a1SGerd Hoffmann if (epnum) 696f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT; 697f1ae32a1SGerd Hoffmann else 698f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT; 699f1ae32a1SGerd Hoffmann } 700f1ae32a1SGerd Hoffmann 701f1ae32a1SGerd Hoffmann if (ep->status[0] < 0) { 702f1ae32a1SGerd Hoffmann if (ep->status[0] == USB_RET_BABBLE) 703f1ae32a1SGerd Hoffmann musb_intr_set(s, musb_irq_rst_babble, 1); 704f1ae32a1SGerd Hoffmann 705f1ae32a1SGerd Hoffmann /* Pretend we've tried three times already and failed (in 706f1ae32a1SGerd Hoffmann * case of USB_TOKEN_SETUP). */ 707f1ae32a1SGerd Hoffmann if (epnum) 708f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_TXCSR_H_ERROR; 709f1ae32a1SGerd Hoffmann else 710f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_ERROR; 711f1ae32a1SGerd Hoffmann 712f1ae32a1SGerd Hoffmann musb_tx_intr_set(s, epnum, 1); 713f1ae32a1SGerd Hoffmann return; 714f1ae32a1SGerd Hoffmann } 715f1ae32a1SGerd Hoffmann /* TODO: check len for over/underruns of an OUT packet? */ 716f1ae32a1SGerd Hoffmann 717f1ae32a1SGerd Hoffmann #ifdef SETUPLEN_HACK 718f1ae32a1SGerd Hoffmann if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP) 719f1ae32a1SGerd Hoffmann s->setup_len = ep->packey[0].data[6]; 720f1ae32a1SGerd Hoffmann #endif 721f1ae32a1SGerd Hoffmann 722f1ae32a1SGerd Hoffmann /* In DMA mode: if no error, assert DMA request for this EP, 723f1ae32a1SGerd Hoffmann * and skip the interrupt. */ 724f1ae32a1SGerd Hoffmann musb_tx_intr_set(s, epnum, 1); 725f1ae32a1SGerd Hoffmann } 726f1ae32a1SGerd Hoffmann 727f1ae32a1SGerd Hoffmann static void musb_rx_packet_complete(USBPacket *packey, void *opaque) 728f1ae32a1SGerd Hoffmann { 729f1ae32a1SGerd Hoffmann /* Unfortunately we can't use packey->devep because that's the remote 730f1ae32a1SGerd Hoffmann * endpoint number and may be different than our local. */ 731f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = (MUSBEndPoint *) opaque; 732f1ae32a1SGerd Hoffmann int epnum = ep->epnum; 733f1ae32a1SGerd Hoffmann MUSBState *s = ep->musb; 734f1ae32a1SGerd Hoffmann 735f1ae32a1SGerd Hoffmann ep->fifostart[1] = 0; 736f1ae32a1SGerd Hoffmann ep->fifolen[1] = 0; 737f1ae32a1SGerd Hoffmann 738f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 739f1ae32a1SGerd Hoffmann if (ep->status[1] != USB_RET_NAK) { 740f1ae32a1SGerd Hoffmann #endif 741f1ae32a1SGerd Hoffmann ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT; 742f1ae32a1SGerd Hoffmann if (!epnum) 743f1ae32a1SGerd Hoffmann ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT; 744f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 745f1ae32a1SGerd Hoffmann } 746f1ae32a1SGerd Hoffmann #endif 747f1ae32a1SGerd Hoffmann 748f1ae32a1SGerd Hoffmann /* Clear all of the imaginable error bits first */ 749f1ae32a1SGerd Hoffmann ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL | 750f1ae32a1SGerd Hoffmann MGC_M_RXCSR_DATAERROR); 751f1ae32a1SGerd Hoffmann if (!epnum) 752f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | 753f1ae32a1SGerd Hoffmann MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); 754f1ae32a1SGerd Hoffmann 755f1ae32a1SGerd Hoffmann if (ep->status[1] == USB_RET_STALL) { 756f1ae32a1SGerd Hoffmann ep->status[1] = 0; 757f1ae32a1SGerd Hoffmann packey->result = 0; 758f1ae32a1SGerd Hoffmann 759f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL; 760f1ae32a1SGerd Hoffmann if (!epnum) 761f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_RXSTALL; 762f1ae32a1SGerd Hoffmann } 763f1ae32a1SGerd Hoffmann 764f1ae32a1SGerd Hoffmann if (ep->status[1] == USB_RET_NAK) { 765f1ae32a1SGerd Hoffmann ep->status[1] = 0; 766f1ae32a1SGerd Hoffmann 767f1ae32a1SGerd Hoffmann /* NAK timeouts are only generated in Bulk transfers and 768f1ae32a1SGerd Hoffmann * Data-errors in Isochronous. */ 769f1ae32a1SGerd Hoffmann if (ep->interrupt[1]) 770f1ae32a1SGerd Hoffmann return musb_packet(s, ep, epnum, USB_TOKEN_IN, 771f1ae32a1SGerd Hoffmann packey->iov.size, musb_rx_packet_complete, 1); 772f1ae32a1SGerd Hoffmann 773f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_DATAERROR; 774f1ae32a1SGerd Hoffmann if (!epnum) 775f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT; 776f1ae32a1SGerd Hoffmann } 777f1ae32a1SGerd Hoffmann 778f1ae32a1SGerd Hoffmann if (ep->status[1] < 0) { 779f1ae32a1SGerd Hoffmann if (ep->status[1] == USB_RET_BABBLE) { 780f1ae32a1SGerd Hoffmann musb_intr_set(s, musb_irq_rst_babble, 1); 781f1ae32a1SGerd Hoffmann return; 782f1ae32a1SGerd Hoffmann } 783f1ae32a1SGerd Hoffmann 784f1ae32a1SGerd Hoffmann /* Pretend we've tried three times already and failed (in 785f1ae32a1SGerd Hoffmann * case of a control transfer). */ 786f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_H_ERROR; 787f1ae32a1SGerd Hoffmann if (!epnum) 788f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_H_ERROR; 789f1ae32a1SGerd Hoffmann 790f1ae32a1SGerd Hoffmann musb_rx_intr_set(s, epnum, 1); 791f1ae32a1SGerd Hoffmann return; 792f1ae32a1SGerd Hoffmann } 793f1ae32a1SGerd Hoffmann /* TODO: check len for over/underruns of an OUT packet? */ 794f1ae32a1SGerd Hoffmann /* TODO: perhaps make use of e->ext_size[1] here. */ 795f1ae32a1SGerd Hoffmann 796f1ae32a1SGerd Hoffmann packey->result = ep->status[1]; 797f1ae32a1SGerd Hoffmann 798f1ae32a1SGerd Hoffmann if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) { 799f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY; 800f1ae32a1SGerd Hoffmann if (!epnum) 801f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_RXPKTRDY; 802f1ae32a1SGerd Hoffmann 803f1ae32a1SGerd Hoffmann ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */ 804f1ae32a1SGerd Hoffmann /* In DMA mode: assert DMA request for this EP */ 805f1ae32a1SGerd Hoffmann } 806f1ae32a1SGerd Hoffmann 807f1ae32a1SGerd Hoffmann /* Only if DMA has not been asserted */ 808f1ae32a1SGerd Hoffmann musb_rx_intr_set(s, epnum, 1); 809f1ae32a1SGerd Hoffmann } 810f1ae32a1SGerd Hoffmann 811f1ae32a1SGerd Hoffmann static void musb_async_cancel_device(MUSBState *s, USBDevice *dev) 812f1ae32a1SGerd Hoffmann { 813f1ae32a1SGerd Hoffmann int ep, dir; 814f1ae32a1SGerd Hoffmann 815f1ae32a1SGerd Hoffmann for (ep = 0; ep < 16; ep++) { 816f1ae32a1SGerd Hoffmann for (dir = 0; dir < 2; dir++) { 817f1ae32a1SGerd Hoffmann if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) || 818f1ae32a1SGerd Hoffmann s->ep[ep].packey[dir].p.ep->dev != dev) { 819f1ae32a1SGerd Hoffmann continue; 820f1ae32a1SGerd Hoffmann } 821f1ae32a1SGerd Hoffmann usb_cancel_packet(&s->ep[ep].packey[dir].p); 822f1ae32a1SGerd Hoffmann /* status updates needed here? */ 823f1ae32a1SGerd Hoffmann } 824f1ae32a1SGerd Hoffmann } 825f1ae32a1SGerd Hoffmann } 826f1ae32a1SGerd Hoffmann 827f1ae32a1SGerd Hoffmann static void musb_tx_rdy(MUSBState *s, int epnum) 828f1ae32a1SGerd Hoffmann { 829f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = s->ep + epnum; 830f1ae32a1SGerd Hoffmann int pid; 831f1ae32a1SGerd Hoffmann int total, valid = 0; 832f1ae32a1SGerd Hoffmann TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] ); 833f1ae32a1SGerd Hoffmann ep->fifostart[0] += ep->fifolen[0]; 834f1ae32a1SGerd Hoffmann ep->fifolen[0] = 0; 835f1ae32a1SGerd Hoffmann 836f1ae32a1SGerd Hoffmann /* XXX: how's the total size of the packet retrieved exactly in 837f1ae32a1SGerd Hoffmann * the generic case? */ 838f1ae32a1SGerd Hoffmann total = ep->maxp[0] & 0x3ff; 839f1ae32a1SGerd Hoffmann 840f1ae32a1SGerd Hoffmann if (ep->ext_size[0]) { 841f1ae32a1SGerd Hoffmann total = ep->ext_size[0]; 842f1ae32a1SGerd Hoffmann ep->ext_size[0] = 0; 843f1ae32a1SGerd Hoffmann valid = 1; 844f1ae32a1SGerd Hoffmann } 845f1ae32a1SGerd Hoffmann 846f1ae32a1SGerd Hoffmann /* If the packet is not fully ready yet, wait for a next segment. */ 847f1ae32a1SGerd Hoffmann if (epnum && (ep->fifostart[0]) < total) 848f1ae32a1SGerd Hoffmann return; 849f1ae32a1SGerd Hoffmann 850f1ae32a1SGerd Hoffmann if (!valid) 851f1ae32a1SGerd Hoffmann total = ep->fifostart[0]; 852f1ae32a1SGerd Hoffmann 853f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 854f1ae32a1SGerd Hoffmann if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) { 855f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 856f1ae32a1SGerd Hoffmann if (total != 8) { 857f1ae32a1SGerd Hoffmann TRACE("illegal SETUPPKT length of %i bytes", total); 858f1ae32a1SGerd Hoffmann } 859f1ae32a1SGerd Hoffmann /* Controller should retry SETUP packets three times on errors 860f1ae32a1SGerd Hoffmann * but it doesn't make sense for us to do that. */ 861f1ae32a1SGerd Hoffmann } 862f1ae32a1SGerd Hoffmann 863f1ae32a1SGerd Hoffmann return musb_packet(s, ep, epnum, pid, 864f1ae32a1SGerd Hoffmann total, musb_tx_packet_complete, 0); 865f1ae32a1SGerd Hoffmann } 866f1ae32a1SGerd Hoffmann 867f1ae32a1SGerd Hoffmann static void musb_rx_req(MUSBState *s, int epnum) 868f1ae32a1SGerd Hoffmann { 869f1ae32a1SGerd Hoffmann MUSBEndPoint *ep = s->ep + epnum; 870f1ae32a1SGerd Hoffmann int total; 871f1ae32a1SGerd Hoffmann 872f1ae32a1SGerd Hoffmann /* If we already have a packet, which didn't fit into the 873f1ae32a1SGerd Hoffmann * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */ 874f1ae32a1SGerd Hoffmann if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 && 875f1ae32a1SGerd Hoffmann (ep->fifostart[1]) + ep->rxcount < 876f1ae32a1SGerd Hoffmann ep->packey[1].p.iov.size) { 877f1ae32a1SGerd Hoffmann TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount ); 878f1ae32a1SGerd Hoffmann ep->fifostart[1] += ep->rxcount; 879f1ae32a1SGerd Hoffmann ep->fifolen[1] = 0; 880f1ae32a1SGerd Hoffmann 881f1ae32a1SGerd Hoffmann ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]), 882f1ae32a1SGerd Hoffmann ep->maxp[1]); 883f1ae32a1SGerd Hoffmann 884f1ae32a1SGerd Hoffmann ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT; 885f1ae32a1SGerd Hoffmann if (!epnum) 886f1ae32a1SGerd Hoffmann ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT; 887f1ae32a1SGerd Hoffmann 888f1ae32a1SGerd Hoffmann /* Clear all of the error bits first */ 889f1ae32a1SGerd Hoffmann ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL | 890f1ae32a1SGerd Hoffmann MGC_M_RXCSR_DATAERROR); 891f1ae32a1SGerd Hoffmann if (!epnum) 892f1ae32a1SGerd Hoffmann ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL | 893f1ae32a1SGerd Hoffmann MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING); 894f1ae32a1SGerd Hoffmann 895f1ae32a1SGerd Hoffmann ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY; 896f1ae32a1SGerd Hoffmann if (!epnum) 897f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_CSR0_RXPKTRDY; 898f1ae32a1SGerd Hoffmann musb_rx_intr_set(s, epnum, 1); 899f1ae32a1SGerd Hoffmann return; 900f1ae32a1SGerd Hoffmann } 901f1ae32a1SGerd Hoffmann 902f1ae32a1SGerd Hoffmann /* The driver sets maxp[1] to 64 or less because it knows the hardware 903f1ae32a1SGerd Hoffmann * FIFO is this deep. Bigger packets get split in 904f1ae32a1SGerd Hoffmann * usb_generic_handle_packet but we can also do the splitting locally 905f1ae32a1SGerd Hoffmann * for performance. It turns out we can also have a bigger FIFO and 906f1ae32a1SGerd Hoffmann * ignore the limit set in ep->maxp[1]. The Linux MUSB driver deals 907f1ae32a1SGerd Hoffmann * OK with single packets of even 32KB and we avoid splitting, however 908f1ae32a1SGerd Hoffmann * usb_msd.c sometimes sends a packet bigger than what Linux expects 909f1ae32a1SGerd Hoffmann * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN. Splitting 910f1ae32a1SGerd Hoffmann * hides this overrun from Linux. Up to 4096 everything is fine 911f1ae32a1SGerd Hoffmann * though. Currently this is disabled. 912f1ae32a1SGerd Hoffmann * 913f1ae32a1SGerd Hoffmann * XXX: mind ep->fifosize. */ 914f1ae32a1SGerd Hoffmann total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf)); 915f1ae32a1SGerd Hoffmann 916f1ae32a1SGerd Hoffmann #ifdef SETUPLEN_HACK 917f1ae32a1SGerd Hoffmann /* Why should *we* do that instead of Linux? */ 918f1ae32a1SGerd Hoffmann if (!epnum) { 919f1ae32a1SGerd Hoffmann if (ep->packey[0].p.devaddr == 2) { 920f1ae32a1SGerd Hoffmann total = MIN(s->setup_len, 8); 921f1ae32a1SGerd Hoffmann } else { 922f1ae32a1SGerd Hoffmann total = MIN(s->setup_len, 64); 923f1ae32a1SGerd Hoffmann } 924f1ae32a1SGerd Hoffmann s->setup_len -= total; 925f1ae32a1SGerd Hoffmann } 926f1ae32a1SGerd Hoffmann #endif 927f1ae32a1SGerd Hoffmann 928f1ae32a1SGerd Hoffmann return musb_packet(s, ep, epnum, USB_TOKEN_IN, 929f1ae32a1SGerd Hoffmann total, musb_rx_packet_complete, 1); 930f1ae32a1SGerd Hoffmann } 931f1ae32a1SGerd Hoffmann 932f1ae32a1SGerd Hoffmann static uint8_t musb_read_fifo(MUSBEndPoint *ep) 933f1ae32a1SGerd Hoffmann { 934f1ae32a1SGerd Hoffmann uint8_t value; 935f1ae32a1SGerd Hoffmann if (ep->fifolen[1] >= 64) { 936f1ae32a1SGerd Hoffmann /* We have a FIFO underrun */ 937f1ae32a1SGerd Hoffmann TRACE("EP%d FIFO is now empty, stop reading", ep->epnum); 938f1ae32a1SGerd Hoffmann return 0x00000000; 939f1ae32a1SGerd Hoffmann } 940f1ae32a1SGerd Hoffmann /* In DMA mode clear RXPKTRDY and set REQPKT automatically 941f1ae32a1SGerd Hoffmann * (if AUTOREQ is set) */ 942f1ae32a1SGerd Hoffmann 943f1ae32a1SGerd Hoffmann ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL; 944f1ae32a1SGerd Hoffmann value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++]; 945f1ae32a1SGerd Hoffmann TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] ); 946f1ae32a1SGerd Hoffmann return value; 947f1ae32a1SGerd Hoffmann } 948f1ae32a1SGerd Hoffmann 949f1ae32a1SGerd Hoffmann static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value) 950f1ae32a1SGerd Hoffmann { 951f1ae32a1SGerd Hoffmann TRACE("EP%d = %02x", ep->epnum, value); 952f1ae32a1SGerd Hoffmann if (ep->fifolen[0] >= 64) { 953f1ae32a1SGerd Hoffmann /* We have a FIFO overrun */ 954f1ae32a1SGerd Hoffmann TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum); 955f1ae32a1SGerd Hoffmann return; 956f1ae32a1SGerd Hoffmann } 957f1ae32a1SGerd Hoffmann 958f1ae32a1SGerd Hoffmann ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value; 959f1ae32a1SGerd Hoffmann ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY; 960f1ae32a1SGerd Hoffmann } 961f1ae32a1SGerd Hoffmann 962f1ae32a1SGerd Hoffmann static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir) 963f1ae32a1SGerd Hoffmann { 964f1ae32a1SGerd Hoffmann if (ep->intv_timer[dir]) 965f1ae32a1SGerd Hoffmann qemu_del_timer(ep->intv_timer[dir]); 966f1ae32a1SGerd Hoffmann } 967f1ae32a1SGerd Hoffmann 968f1ae32a1SGerd Hoffmann /* Bus control */ 969f1ae32a1SGerd Hoffmann static uint8_t musb_busctl_readb(void *opaque, int ep, int addr) 970f1ae32a1SGerd Hoffmann { 971f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 972f1ae32a1SGerd Hoffmann 973f1ae32a1SGerd Hoffmann switch (addr) { 974f1ae32a1SGerd Hoffmann /* For USB2.0 HS hubs only */ 975f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXHUBADDR: 976f1ae32a1SGerd Hoffmann return s->ep[ep].haddr[0]; 977f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXHUBPORT: 978f1ae32a1SGerd Hoffmann return s->ep[ep].hport[0]; 979f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXHUBADDR: 980f1ae32a1SGerd Hoffmann return s->ep[ep].haddr[1]; 981f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXHUBPORT: 982f1ae32a1SGerd Hoffmann return s->ep[ep].hport[1]; 983f1ae32a1SGerd Hoffmann 984f1ae32a1SGerd Hoffmann default: 985f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", addr); 986f1ae32a1SGerd Hoffmann return 0x00; 987f1ae32a1SGerd Hoffmann }; 988f1ae32a1SGerd Hoffmann } 989f1ae32a1SGerd Hoffmann 990f1ae32a1SGerd Hoffmann static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value) 991f1ae32a1SGerd Hoffmann { 992f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 993f1ae32a1SGerd Hoffmann 994f1ae32a1SGerd Hoffmann switch (addr) { 995f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFUNCADDR: 996f1ae32a1SGerd Hoffmann s->ep[ep].faddr[0] = value; 997f1ae32a1SGerd Hoffmann break; 998f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFUNCADDR: 999f1ae32a1SGerd Hoffmann s->ep[ep].faddr[1] = value; 1000f1ae32a1SGerd Hoffmann break; 1001f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXHUBADDR: 1002f1ae32a1SGerd Hoffmann s->ep[ep].haddr[0] = value; 1003f1ae32a1SGerd Hoffmann break; 1004f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXHUBPORT: 1005f1ae32a1SGerd Hoffmann s->ep[ep].hport[0] = value; 1006f1ae32a1SGerd Hoffmann break; 1007f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXHUBADDR: 1008f1ae32a1SGerd Hoffmann s->ep[ep].haddr[1] = value; 1009f1ae32a1SGerd Hoffmann break; 1010f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXHUBPORT: 1011f1ae32a1SGerd Hoffmann s->ep[ep].hport[1] = value; 1012f1ae32a1SGerd Hoffmann break; 1013f1ae32a1SGerd Hoffmann 1014f1ae32a1SGerd Hoffmann default: 1015f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", addr); 1016f1ae32a1SGerd Hoffmann break; 1017f1ae32a1SGerd Hoffmann }; 1018f1ae32a1SGerd Hoffmann } 1019f1ae32a1SGerd Hoffmann 1020f1ae32a1SGerd Hoffmann static uint16_t musb_busctl_readh(void *opaque, int ep, int addr) 1021f1ae32a1SGerd Hoffmann { 1022f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1023f1ae32a1SGerd Hoffmann 1024f1ae32a1SGerd Hoffmann switch (addr) { 1025f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFUNCADDR: 1026f1ae32a1SGerd Hoffmann return s->ep[ep].faddr[0]; 1027f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFUNCADDR: 1028f1ae32a1SGerd Hoffmann return s->ep[ep].faddr[1]; 1029f1ae32a1SGerd Hoffmann 1030f1ae32a1SGerd Hoffmann default: 1031f1ae32a1SGerd Hoffmann return musb_busctl_readb(s, ep, addr) | 1032f1ae32a1SGerd Hoffmann (musb_busctl_readb(s, ep, addr | 1) << 8); 1033f1ae32a1SGerd Hoffmann }; 1034f1ae32a1SGerd Hoffmann } 1035f1ae32a1SGerd Hoffmann 1036f1ae32a1SGerd Hoffmann static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value) 1037f1ae32a1SGerd Hoffmann { 1038f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1039f1ae32a1SGerd Hoffmann 1040f1ae32a1SGerd Hoffmann switch (addr) { 1041f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFUNCADDR: 1042f1ae32a1SGerd Hoffmann s->ep[ep].faddr[0] = value; 1043f1ae32a1SGerd Hoffmann break; 1044f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFUNCADDR: 1045f1ae32a1SGerd Hoffmann s->ep[ep].faddr[1] = value; 1046f1ae32a1SGerd Hoffmann break; 1047f1ae32a1SGerd Hoffmann 1048f1ae32a1SGerd Hoffmann default: 1049f1ae32a1SGerd Hoffmann musb_busctl_writeb(s, ep, addr, value & 0xff); 1050f1ae32a1SGerd Hoffmann musb_busctl_writeb(s, ep, addr | 1, value >> 8); 1051f1ae32a1SGerd Hoffmann }; 1052f1ae32a1SGerd Hoffmann } 1053f1ae32a1SGerd Hoffmann 1054f1ae32a1SGerd Hoffmann /* Endpoint control */ 1055f1ae32a1SGerd Hoffmann static uint8_t musb_ep_readb(void *opaque, int ep, int addr) 1056f1ae32a1SGerd Hoffmann { 1057f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1058f1ae32a1SGerd Hoffmann 1059f1ae32a1SGerd Hoffmann switch (addr) { 1060f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXTYPE: 1061f1ae32a1SGerd Hoffmann return s->ep[ep].type[0]; 1062f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXINTERVAL: 1063f1ae32a1SGerd Hoffmann return s->ep[ep].interval[0]; 1064f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXTYPE: 1065f1ae32a1SGerd Hoffmann return s->ep[ep].type[1]; 1066f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXINTERVAL: 1067f1ae32a1SGerd Hoffmann return s->ep[ep].interval[1]; 1068f1ae32a1SGerd Hoffmann case (MUSB_HDRC_FIFOSIZE & ~1): 1069f1ae32a1SGerd Hoffmann return 0x00; 1070f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFOSIZE: 1071f1ae32a1SGerd Hoffmann return ep ? s->ep[ep].fifosize : s->ep[ep].config; 1072f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCOUNT: 1073f1ae32a1SGerd Hoffmann return s->ep[ep].rxcount; 1074f1ae32a1SGerd Hoffmann 1075f1ae32a1SGerd Hoffmann default: 1076f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", addr); 1077f1ae32a1SGerd Hoffmann return 0x00; 1078f1ae32a1SGerd Hoffmann }; 1079f1ae32a1SGerd Hoffmann } 1080f1ae32a1SGerd Hoffmann 1081f1ae32a1SGerd Hoffmann static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value) 1082f1ae32a1SGerd Hoffmann { 1083f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1084f1ae32a1SGerd Hoffmann 1085f1ae32a1SGerd Hoffmann switch (addr) { 1086f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXTYPE: 1087f1ae32a1SGerd Hoffmann s->ep[ep].type[0] = value; 1088f1ae32a1SGerd Hoffmann break; 1089f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXINTERVAL: 1090f1ae32a1SGerd Hoffmann s->ep[ep].interval[0] = value; 1091f1ae32a1SGerd Hoffmann musb_ep_frame_cancel(&s->ep[ep], 0); 1092f1ae32a1SGerd Hoffmann break; 1093f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXTYPE: 1094f1ae32a1SGerd Hoffmann s->ep[ep].type[1] = value; 1095f1ae32a1SGerd Hoffmann break; 1096f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXINTERVAL: 1097f1ae32a1SGerd Hoffmann s->ep[ep].interval[1] = value; 1098f1ae32a1SGerd Hoffmann musb_ep_frame_cancel(&s->ep[ep], 1); 1099f1ae32a1SGerd Hoffmann break; 1100f1ae32a1SGerd Hoffmann case (MUSB_HDRC_FIFOSIZE & ~1): 1101f1ae32a1SGerd Hoffmann break; 1102f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFOSIZE: 1103f1ae32a1SGerd Hoffmann TRACE("somebody messes with fifosize (now %i bytes)", value); 1104f1ae32a1SGerd Hoffmann s->ep[ep].fifosize = value; 1105f1ae32a1SGerd Hoffmann break; 1106f1ae32a1SGerd Hoffmann default: 1107f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", addr); 1108f1ae32a1SGerd Hoffmann break; 1109f1ae32a1SGerd Hoffmann }; 1110f1ae32a1SGerd Hoffmann } 1111f1ae32a1SGerd Hoffmann 1112f1ae32a1SGerd Hoffmann static uint16_t musb_ep_readh(void *opaque, int ep, int addr) 1113f1ae32a1SGerd Hoffmann { 1114f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1115f1ae32a1SGerd Hoffmann uint16_t ret; 1116f1ae32a1SGerd Hoffmann 1117f1ae32a1SGerd Hoffmann switch (addr) { 1118f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXMAXP: 1119f1ae32a1SGerd Hoffmann return s->ep[ep].maxp[0]; 1120f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXCSR: 1121f1ae32a1SGerd Hoffmann return s->ep[ep].csr[0]; 1122f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXMAXP: 1123f1ae32a1SGerd Hoffmann return s->ep[ep].maxp[1]; 1124f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCSR: 1125f1ae32a1SGerd Hoffmann ret = s->ep[ep].csr[1]; 1126f1ae32a1SGerd Hoffmann 1127f1ae32a1SGerd Hoffmann /* TODO: This and other bits probably depend on 1128f1ae32a1SGerd Hoffmann * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR. */ 1129f1ae32a1SGerd Hoffmann if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR) 1130f1ae32a1SGerd Hoffmann s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY; 1131f1ae32a1SGerd Hoffmann 1132f1ae32a1SGerd Hoffmann return ret; 1133f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCOUNT: 1134f1ae32a1SGerd Hoffmann return s->ep[ep].rxcount; 1135f1ae32a1SGerd Hoffmann 1136f1ae32a1SGerd Hoffmann default: 1137f1ae32a1SGerd Hoffmann return musb_ep_readb(s, ep, addr) | 1138f1ae32a1SGerd Hoffmann (musb_ep_readb(s, ep, addr | 1) << 8); 1139f1ae32a1SGerd Hoffmann }; 1140f1ae32a1SGerd Hoffmann } 1141f1ae32a1SGerd Hoffmann 1142f1ae32a1SGerd Hoffmann static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value) 1143f1ae32a1SGerd Hoffmann { 1144f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1145f1ae32a1SGerd Hoffmann 1146f1ae32a1SGerd Hoffmann switch (addr) { 1147f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXMAXP: 1148f1ae32a1SGerd Hoffmann s->ep[ep].maxp[0] = value; 1149f1ae32a1SGerd Hoffmann break; 1150f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXCSR: 1151f1ae32a1SGerd Hoffmann if (ep) { 1152f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] &= value & 0xa6; 1153f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] |= value & 0xff59; 1154f1ae32a1SGerd Hoffmann } else { 1155f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] &= value & 0x85; 1156f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] |= value & 0xf7a; 1157f1ae32a1SGerd Hoffmann } 1158f1ae32a1SGerd Hoffmann 1159f1ae32a1SGerd Hoffmann musb_ep_frame_cancel(&s->ep[ep], 0); 1160f1ae32a1SGerd Hoffmann 1161f1ae32a1SGerd Hoffmann if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) || 1162f1ae32a1SGerd Hoffmann (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) { 1163f1ae32a1SGerd Hoffmann s->ep[ep].fifolen[0] = 0; 1164f1ae32a1SGerd Hoffmann s->ep[ep].fifostart[0] = 0; 1165f1ae32a1SGerd Hoffmann if (ep) 1166f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] &= 1167f1ae32a1SGerd Hoffmann ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY); 1168f1ae32a1SGerd Hoffmann else 1169f1ae32a1SGerd Hoffmann s->ep[ep].csr[0] &= 1170f1ae32a1SGerd Hoffmann ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY); 1171f1ae32a1SGerd Hoffmann } 1172f1ae32a1SGerd Hoffmann if ( 1173f1ae32a1SGerd Hoffmann (ep && 1174f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 1175f1ae32a1SGerd Hoffmann (value & MGC_M_TXCSR_TXPKTRDY) && 1176f1ae32a1SGerd Hoffmann !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) || 1177f1ae32a1SGerd Hoffmann #else 1178f1ae32a1SGerd Hoffmann (value & MGC_M_TXCSR_TXPKTRDY)) || 1179f1ae32a1SGerd Hoffmann #endif 1180f1ae32a1SGerd Hoffmann (!ep && 1181f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 1182f1ae32a1SGerd Hoffmann (value & MGC_M_CSR0_TXPKTRDY) && 1183f1ae32a1SGerd Hoffmann !(value & MGC_M_CSR0_H_NAKTIMEOUT))) 1184f1ae32a1SGerd Hoffmann #else 1185f1ae32a1SGerd Hoffmann (value & MGC_M_CSR0_TXPKTRDY))) 1186f1ae32a1SGerd Hoffmann #endif 1187f1ae32a1SGerd Hoffmann musb_tx_rdy(s, ep); 1188f1ae32a1SGerd Hoffmann if (!ep && 1189f1ae32a1SGerd Hoffmann (value & MGC_M_CSR0_H_REQPKT) && 1190f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 1191f1ae32a1SGerd Hoffmann !(value & (MGC_M_CSR0_H_NAKTIMEOUT | 1192f1ae32a1SGerd Hoffmann MGC_M_CSR0_RXPKTRDY))) 1193f1ae32a1SGerd Hoffmann #else 1194f1ae32a1SGerd Hoffmann !(value & MGC_M_CSR0_RXPKTRDY)) 1195f1ae32a1SGerd Hoffmann #endif 1196f1ae32a1SGerd Hoffmann musb_rx_req(s, ep); 1197f1ae32a1SGerd Hoffmann break; 1198f1ae32a1SGerd Hoffmann 1199f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXMAXP: 1200f1ae32a1SGerd Hoffmann s->ep[ep].maxp[1] = value; 1201f1ae32a1SGerd Hoffmann break; 1202f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCSR: 1203f1ae32a1SGerd Hoffmann /* (DMA mode only) */ 1204f1ae32a1SGerd Hoffmann if ( 1205f1ae32a1SGerd Hoffmann (value & MGC_M_RXCSR_H_AUTOREQ) && 1206f1ae32a1SGerd Hoffmann !(value & MGC_M_RXCSR_RXPKTRDY) && 1207f1ae32a1SGerd Hoffmann (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY)) 1208f1ae32a1SGerd Hoffmann value |= MGC_M_RXCSR_H_REQPKT; 1209f1ae32a1SGerd Hoffmann 1210f1ae32a1SGerd Hoffmann s->ep[ep].csr[1] &= 0x102 | (value & 0x4d); 1211f1ae32a1SGerd Hoffmann s->ep[ep].csr[1] |= value & 0xfeb0; 1212f1ae32a1SGerd Hoffmann 1213f1ae32a1SGerd Hoffmann musb_ep_frame_cancel(&s->ep[ep], 1); 1214f1ae32a1SGerd Hoffmann 1215f1ae32a1SGerd Hoffmann if (value & MGC_M_RXCSR_FLUSHFIFO) { 1216f1ae32a1SGerd Hoffmann s->ep[ep].fifolen[1] = 0; 1217f1ae32a1SGerd Hoffmann s->ep[ep].fifostart[1] = 0; 1218f1ae32a1SGerd Hoffmann s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY); 1219f1ae32a1SGerd Hoffmann /* If double buffering and we have two packets ready, flush 1220f1ae32a1SGerd Hoffmann * only the first one and set up the fifo at the second packet. */ 1221f1ae32a1SGerd Hoffmann } 1222f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK 1223f1ae32a1SGerd Hoffmann if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR)) 1224f1ae32a1SGerd Hoffmann #else 1225f1ae32a1SGerd Hoffmann if (value & MGC_M_RXCSR_H_REQPKT) 1226f1ae32a1SGerd Hoffmann #endif 1227f1ae32a1SGerd Hoffmann musb_rx_req(s, ep); 1228f1ae32a1SGerd Hoffmann break; 1229f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXCOUNT: 1230f1ae32a1SGerd Hoffmann s->ep[ep].rxcount = value; 1231f1ae32a1SGerd Hoffmann break; 1232f1ae32a1SGerd Hoffmann 1233f1ae32a1SGerd Hoffmann default: 1234f1ae32a1SGerd Hoffmann musb_ep_writeb(s, ep, addr, value & 0xff); 1235f1ae32a1SGerd Hoffmann musb_ep_writeb(s, ep, addr | 1, value >> 8); 1236f1ae32a1SGerd Hoffmann }; 1237f1ae32a1SGerd Hoffmann } 1238f1ae32a1SGerd Hoffmann 1239f1ae32a1SGerd Hoffmann /* Generic control */ 1240a8170e5eSAvi Kivity static uint32_t musb_readb(void *opaque, hwaddr addr) 1241f1ae32a1SGerd Hoffmann { 1242f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1243f1ae32a1SGerd Hoffmann int ep, i; 1244f1ae32a1SGerd Hoffmann uint8_t ret; 1245f1ae32a1SGerd Hoffmann 1246f1ae32a1SGerd Hoffmann switch (addr) { 1247f1ae32a1SGerd Hoffmann case MUSB_HDRC_FADDR: 1248f1ae32a1SGerd Hoffmann return s->faddr; 1249f1ae32a1SGerd Hoffmann case MUSB_HDRC_POWER: 1250f1ae32a1SGerd Hoffmann return s->power; 1251f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRUSB: 1252f1ae32a1SGerd Hoffmann ret = s->intr; 1253f1ae32a1SGerd Hoffmann for (i = 0; i < sizeof(ret) * 8; i ++) 1254f1ae32a1SGerd Hoffmann if (ret & (1 << i)) 1255f1ae32a1SGerd Hoffmann musb_intr_set(s, i, 0); 1256f1ae32a1SGerd Hoffmann return ret; 1257f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRUSBE: 1258f1ae32a1SGerd Hoffmann return s->mask; 1259f1ae32a1SGerd Hoffmann case MUSB_HDRC_INDEX: 1260f1ae32a1SGerd Hoffmann return s->idx; 1261f1ae32a1SGerd Hoffmann case MUSB_HDRC_TESTMODE: 1262f1ae32a1SGerd Hoffmann return 0x00; 1263f1ae32a1SGerd Hoffmann 1264f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): 1265f1ae32a1SGerd Hoffmann return musb_ep_readb(s, s->idx, addr & 0xf); 1266f1ae32a1SGerd Hoffmann 1267f1ae32a1SGerd Hoffmann case MUSB_HDRC_DEVCTL: 1268f1ae32a1SGerd Hoffmann return s->devctl; 1269f1ae32a1SGerd Hoffmann 1270f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFIFOSZ: 1271f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFIFOSZ: 1272f1ae32a1SGerd Hoffmann case MUSB_HDRC_VCTRL: 1273f1ae32a1SGerd Hoffmann /* TODO */ 1274f1ae32a1SGerd Hoffmann return 0x00; 1275f1ae32a1SGerd Hoffmann 1276f1ae32a1SGerd Hoffmann case MUSB_HDRC_HWVERS: 1277f1ae32a1SGerd Hoffmann return (1 << 10) | 400; 1278f1ae32a1SGerd Hoffmann 1279f1ae32a1SGerd Hoffmann case (MUSB_HDRC_VCTRL | 1): 1280f1ae32a1SGerd Hoffmann case (MUSB_HDRC_HWVERS | 1): 1281f1ae32a1SGerd Hoffmann case (MUSB_HDRC_DEVCTL | 1): 1282f1ae32a1SGerd Hoffmann return 0x00; 1283f1ae32a1SGerd Hoffmann 1284f1ae32a1SGerd Hoffmann case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): 1285f1ae32a1SGerd Hoffmann ep = (addr >> 3) & 0xf; 1286f1ae32a1SGerd Hoffmann return musb_busctl_readb(s, ep, addr & 0x7); 1287f1ae32a1SGerd Hoffmann 1288f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): 1289f1ae32a1SGerd Hoffmann ep = (addr >> 4) & 0xf; 1290f1ae32a1SGerd Hoffmann return musb_ep_readb(s, ep, addr & 0xf); 1291f1ae32a1SGerd Hoffmann 1292f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1293f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1294f1ae32a1SGerd Hoffmann return musb_read_fifo(s->ep + ep); 1295f1ae32a1SGerd Hoffmann 1296f1ae32a1SGerd Hoffmann default: 1297f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", (int) addr); 1298f1ae32a1SGerd Hoffmann return 0x00; 1299f1ae32a1SGerd Hoffmann }; 1300f1ae32a1SGerd Hoffmann } 1301f1ae32a1SGerd Hoffmann 1302a8170e5eSAvi Kivity static void musb_writeb(void *opaque, hwaddr addr, uint32_t value) 1303f1ae32a1SGerd Hoffmann { 1304f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1305f1ae32a1SGerd Hoffmann int ep; 1306f1ae32a1SGerd Hoffmann 1307f1ae32a1SGerd Hoffmann switch (addr) { 1308f1ae32a1SGerd Hoffmann case MUSB_HDRC_FADDR: 1309f1ae32a1SGerd Hoffmann s->faddr = value & 0x7f; 1310f1ae32a1SGerd Hoffmann break; 1311f1ae32a1SGerd Hoffmann case MUSB_HDRC_POWER: 1312f1ae32a1SGerd Hoffmann s->power = (value & 0xef) | (s->power & 0x10); 1313f1ae32a1SGerd Hoffmann /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */ 1314f1ae32a1SGerd Hoffmann if ((value & MGC_M_POWER_RESET) && s->port.dev) { 1315f1ae32a1SGerd Hoffmann usb_device_reset(s->port.dev); 1316f1ae32a1SGerd Hoffmann /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */ 1317f1ae32a1SGerd Hoffmann if ((value & MGC_M_POWER_HSENAB) && 1318f1ae32a1SGerd Hoffmann s->port.dev->speed == USB_SPEED_HIGH) 1319f1ae32a1SGerd Hoffmann s->power |= MGC_M_POWER_HSMODE; /* Success */ 1320f1ae32a1SGerd Hoffmann /* Restart frame counting. */ 1321f1ae32a1SGerd Hoffmann } 1322f1ae32a1SGerd Hoffmann if (value & MGC_M_POWER_SUSPENDM) { 1323f1ae32a1SGerd Hoffmann /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND 1324f1ae32a1SGerd Hoffmann * is set, also go into low power mode. Frame counting stops. */ 1325f1ae32a1SGerd Hoffmann /* XXX: Cleared when the interrupt register is read */ 1326f1ae32a1SGerd Hoffmann } 1327f1ae32a1SGerd Hoffmann if (value & MGC_M_POWER_RESUME) { 1328f1ae32a1SGerd Hoffmann /* Wait 20ms and signal resuming on the bus. Frame counting 1329f1ae32a1SGerd Hoffmann * restarts. */ 1330f1ae32a1SGerd Hoffmann } 1331f1ae32a1SGerd Hoffmann break; 1332f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRUSB: 1333f1ae32a1SGerd Hoffmann break; 1334f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRUSBE: 1335f1ae32a1SGerd Hoffmann s->mask = value & 0xff; 1336f1ae32a1SGerd Hoffmann break; 1337f1ae32a1SGerd Hoffmann case MUSB_HDRC_INDEX: 1338f1ae32a1SGerd Hoffmann s->idx = value & 0xf; 1339f1ae32a1SGerd Hoffmann break; 1340f1ae32a1SGerd Hoffmann case MUSB_HDRC_TESTMODE: 1341f1ae32a1SGerd Hoffmann break; 1342f1ae32a1SGerd Hoffmann 1343f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): 1344f1ae32a1SGerd Hoffmann musb_ep_writeb(s, s->idx, addr & 0xf, value); 1345f1ae32a1SGerd Hoffmann break; 1346f1ae32a1SGerd Hoffmann 1347f1ae32a1SGerd Hoffmann case MUSB_HDRC_DEVCTL: 1348f1ae32a1SGerd Hoffmann s->session = !!(value & MGC_M_DEVCTL_SESSION); 1349f1ae32a1SGerd Hoffmann musb_session_update(s, 1350f1ae32a1SGerd Hoffmann !!s->port.dev, 1351f1ae32a1SGerd Hoffmann !!(s->devctl & MGC_M_DEVCTL_SESSION)); 1352f1ae32a1SGerd Hoffmann 1353f1ae32a1SGerd Hoffmann /* It seems this is the only R/W bit in this register? */ 1354f1ae32a1SGerd Hoffmann s->devctl &= ~MGC_M_DEVCTL_SESSION; 1355f1ae32a1SGerd Hoffmann s->devctl |= value & MGC_M_DEVCTL_SESSION; 1356f1ae32a1SGerd Hoffmann break; 1357f1ae32a1SGerd Hoffmann 1358f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFIFOSZ: 1359f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFIFOSZ: 1360f1ae32a1SGerd Hoffmann case MUSB_HDRC_VCTRL: 1361f1ae32a1SGerd Hoffmann /* TODO */ 1362f1ae32a1SGerd Hoffmann break; 1363f1ae32a1SGerd Hoffmann 1364f1ae32a1SGerd Hoffmann case (MUSB_HDRC_VCTRL | 1): 1365f1ae32a1SGerd Hoffmann case (MUSB_HDRC_DEVCTL | 1): 1366f1ae32a1SGerd Hoffmann break; 1367f1ae32a1SGerd Hoffmann 1368f1ae32a1SGerd Hoffmann case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): 1369f1ae32a1SGerd Hoffmann ep = (addr >> 3) & 0xf; 1370f1ae32a1SGerd Hoffmann musb_busctl_writeb(s, ep, addr & 0x7, value); 1371f1ae32a1SGerd Hoffmann break; 1372f1ae32a1SGerd Hoffmann 1373f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): 1374f1ae32a1SGerd Hoffmann ep = (addr >> 4) & 0xf; 1375f1ae32a1SGerd Hoffmann musb_ep_writeb(s, ep, addr & 0xf, value); 1376f1ae32a1SGerd Hoffmann break; 1377f1ae32a1SGerd Hoffmann 1378f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1379f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1380f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, value & 0xff); 1381f1ae32a1SGerd Hoffmann break; 1382f1ae32a1SGerd Hoffmann 1383f1ae32a1SGerd Hoffmann default: 1384f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", (int) addr); 1385f1ae32a1SGerd Hoffmann break; 1386f1ae32a1SGerd Hoffmann }; 1387f1ae32a1SGerd Hoffmann } 1388f1ae32a1SGerd Hoffmann 1389a8170e5eSAvi Kivity static uint32_t musb_readh(void *opaque, hwaddr addr) 1390f1ae32a1SGerd Hoffmann { 1391f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1392f1ae32a1SGerd Hoffmann int ep, i; 1393f1ae32a1SGerd Hoffmann uint16_t ret; 1394f1ae32a1SGerd Hoffmann 1395f1ae32a1SGerd Hoffmann switch (addr) { 1396f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRTX: 1397f1ae32a1SGerd Hoffmann ret = s->tx_intr; 1398f1ae32a1SGerd Hoffmann /* Auto clear */ 1399f1ae32a1SGerd Hoffmann for (i = 0; i < sizeof(ret) * 8; i ++) 1400f1ae32a1SGerd Hoffmann if (ret & (1 << i)) 1401f1ae32a1SGerd Hoffmann musb_tx_intr_set(s, i, 0); 1402f1ae32a1SGerd Hoffmann return ret; 1403f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRRX: 1404f1ae32a1SGerd Hoffmann ret = s->rx_intr; 1405f1ae32a1SGerd Hoffmann /* Auto clear */ 1406f1ae32a1SGerd Hoffmann for (i = 0; i < sizeof(ret) * 8; i ++) 1407f1ae32a1SGerd Hoffmann if (ret & (1 << i)) 1408f1ae32a1SGerd Hoffmann musb_rx_intr_set(s, i, 0); 1409f1ae32a1SGerd Hoffmann return ret; 1410f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRTXE: 1411f1ae32a1SGerd Hoffmann return s->tx_mask; 1412f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRRXE: 1413f1ae32a1SGerd Hoffmann return s->rx_mask; 1414f1ae32a1SGerd Hoffmann 1415f1ae32a1SGerd Hoffmann case MUSB_HDRC_FRAME: 1416f1ae32a1SGerd Hoffmann /* TODO */ 1417f1ae32a1SGerd Hoffmann return 0x0000; 1418f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFIFOADDR: 1419f1ae32a1SGerd Hoffmann return s->ep[s->idx].fifoaddr[0]; 1420f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFIFOADDR: 1421f1ae32a1SGerd Hoffmann return s->ep[s->idx].fifoaddr[1]; 1422f1ae32a1SGerd Hoffmann 1423f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): 1424f1ae32a1SGerd Hoffmann return musb_ep_readh(s, s->idx, addr & 0xf); 1425f1ae32a1SGerd Hoffmann 1426f1ae32a1SGerd Hoffmann case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): 1427f1ae32a1SGerd Hoffmann ep = (addr >> 3) & 0xf; 1428f1ae32a1SGerd Hoffmann return musb_busctl_readh(s, ep, addr & 0x7); 1429f1ae32a1SGerd Hoffmann 1430f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): 1431f1ae32a1SGerd Hoffmann ep = (addr >> 4) & 0xf; 1432f1ae32a1SGerd Hoffmann return musb_ep_readh(s, ep, addr & 0xf); 1433f1ae32a1SGerd Hoffmann 1434f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1435f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1436f1ae32a1SGerd Hoffmann return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8); 1437f1ae32a1SGerd Hoffmann 1438f1ae32a1SGerd Hoffmann default: 1439f1ae32a1SGerd Hoffmann return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8); 1440f1ae32a1SGerd Hoffmann }; 1441f1ae32a1SGerd Hoffmann } 1442f1ae32a1SGerd Hoffmann 1443a8170e5eSAvi Kivity static void musb_writeh(void *opaque, hwaddr addr, uint32_t value) 1444f1ae32a1SGerd Hoffmann { 1445f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1446f1ae32a1SGerd Hoffmann int ep; 1447f1ae32a1SGerd Hoffmann 1448f1ae32a1SGerd Hoffmann switch (addr) { 1449f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRTXE: 1450f1ae32a1SGerd Hoffmann s->tx_mask = value; 1451f1ae32a1SGerd Hoffmann /* XXX: the masks seem to apply on the raising edge like with 1452f1ae32a1SGerd Hoffmann * edge-triggered interrupts, thus no need to update. I may be 1453f1ae32a1SGerd Hoffmann * wrong though. */ 1454f1ae32a1SGerd Hoffmann break; 1455f1ae32a1SGerd Hoffmann case MUSB_HDRC_INTRRXE: 1456f1ae32a1SGerd Hoffmann s->rx_mask = value; 1457f1ae32a1SGerd Hoffmann break; 1458f1ae32a1SGerd Hoffmann 1459f1ae32a1SGerd Hoffmann case MUSB_HDRC_FRAME: 1460f1ae32a1SGerd Hoffmann /* TODO */ 1461f1ae32a1SGerd Hoffmann break; 1462f1ae32a1SGerd Hoffmann case MUSB_HDRC_TXFIFOADDR: 1463f1ae32a1SGerd Hoffmann s->ep[s->idx].fifoaddr[0] = value; 1464f1ae32a1SGerd Hoffmann s->ep[s->idx].buf[0] = 1465f1ae32a1SGerd Hoffmann s->buf + ((value << 3) & 0x7ff ); 1466f1ae32a1SGerd Hoffmann break; 1467f1ae32a1SGerd Hoffmann case MUSB_HDRC_RXFIFOADDR: 1468f1ae32a1SGerd Hoffmann s->ep[s->idx].fifoaddr[1] = value; 1469f1ae32a1SGerd Hoffmann s->ep[s->idx].buf[1] = 1470f1ae32a1SGerd Hoffmann s->buf + ((value << 3) & 0x7ff); 1471f1ae32a1SGerd Hoffmann break; 1472f1ae32a1SGerd Hoffmann 1473f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): 1474f1ae32a1SGerd Hoffmann musb_ep_writeh(s, s->idx, addr & 0xf, value); 1475f1ae32a1SGerd Hoffmann break; 1476f1ae32a1SGerd Hoffmann 1477f1ae32a1SGerd Hoffmann case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f): 1478f1ae32a1SGerd Hoffmann ep = (addr >> 3) & 0xf; 1479f1ae32a1SGerd Hoffmann musb_busctl_writeh(s, ep, addr & 0x7, value); 1480f1ae32a1SGerd Hoffmann break; 1481f1ae32a1SGerd Hoffmann 1482f1ae32a1SGerd Hoffmann case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff): 1483f1ae32a1SGerd Hoffmann ep = (addr >> 4) & 0xf; 1484f1ae32a1SGerd Hoffmann musb_ep_writeh(s, ep, addr & 0xf, value); 1485f1ae32a1SGerd Hoffmann break; 1486f1ae32a1SGerd Hoffmann 1487f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1488f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1489f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, value & 0xff); 1490f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, (value >> 8) & 0xff); 1491f1ae32a1SGerd Hoffmann break; 1492f1ae32a1SGerd Hoffmann 1493f1ae32a1SGerd Hoffmann default: 1494f1ae32a1SGerd Hoffmann musb_writeb(s, addr, value & 0xff); 1495f1ae32a1SGerd Hoffmann musb_writeb(s, addr | 1, value >> 8); 1496f1ae32a1SGerd Hoffmann }; 1497f1ae32a1SGerd Hoffmann } 1498f1ae32a1SGerd Hoffmann 1499a8170e5eSAvi Kivity static uint32_t musb_readw(void *opaque, hwaddr addr) 1500f1ae32a1SGerd Hoffmann { 1501f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1502f1ae32a1SGerd Hoffmann int ep; 1503f1ae32a1SGerd Hoffmann 1504f1ae32a1SGerd Hoffmann switch (addr) { 1505f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1506f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1507f1ae32a1SGerd Hoffmann return ( musb_read_fifo(s->ep + ep) | 1508f1ae32a1SGerd Hoffmann musb_read_fifo(s->ep + ep) << 8 | 1509f1ae32a1SGerd Hoffmann musb_read_fifo(s->ep + ep) << 16 | 1510f1ae32a1SGerd Hoffmann musb_read_fifo(s->ep + ep) << 24 ); 1511f1ae32a1SGerd Hoffmann default: 1512f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", (int) addr); 1513f1ae32a1SGerd Hoffmann return 0x00000000; 1514f1ae32a1SGerd Hoffmann }; 1515f1ae32a1SGerd Hoffmann } 1516f1ae32a1SGerd Hoffmann 1517a8170e5eSAvi Kivity static void musb_writew(void *opaque, hwaddr addr, uint32_t value) 1518f1ae32a1SGerd Hoffmann { 1519f1ae32a1SGerd Hoffmann MUSBState *s = (MUSBState *) opaque; 1520f1ae32a1SGerd Hoffmann int ep; 1521f1ae32a1SGerd Hoffmann 1522f1ae32a1SGerd Hoffmann switch (addr) { 1523f1ae32a1SGerd Hoffmann case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): 1524f1ae32a1SGerd Hoffmann ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; 1525f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, value & 0xff); 1526f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff); 1527f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, (value >> 16) & 0xff); 1528f1ae32a1SGerd Hoffmann musb_write_fifo(s->ep + ep, (value >> 24) & 0xff); 1529f1ae32a1SGerd Hoffmann break; 1530f1ae32a1SGerd Hoffmann default: 1531f1ae32a1SGerd Hoffmann TRACE("unknown register 0x%02x", (int) addr); 1532f1ae32a1SGerd Hoffmann break; 1533f1ae32a1SGerd Hoffmann }; 1534f1ae32a1SGerd Hoffmann } 1535f1ae32a1SGerd Hoffmann 1536f1ae32a1SGerd Hoffmann CPUReadMemoryFunc * const musb_read[] = { 1537f1ae32a1SGerd Hoffmann musb_readb, 1538f1ae32a1SGerd Hoffmann musb_readh, 1539f1ae32a1SGerd Hoffmann musb_readw, 1540f1ae32a1SGerd Hoffmann }; 1541f1ae32a1SGerd Hoffmann 1542f1ae32a1SGerd Hoffmann CPUWriteMemoryFunc * const musb_write[] = { 1543f1ae32a1SGerd Hoffmann musb_writeb, 1544f1ae32a1SGerd Hoffmann musb_writeh, 1545f1ae32a1SGerd Hoffmann musb_writew, 1546f1ae32a1SGerd Hoffmann }; 1547