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