Revision 942ac052
b/Makefile.target | ||
---|---|---|
612 | 612 |
OBJS+= omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o |
613 | 613 |
OBJS+= omap2.o omap_dss.o |
614 | 614 |
OBJS+= palm.o tsc210x.o |
615 |
OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o |
|
615 |
OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
|
|
616 | 616 |
OBJS+= mst_fpga.o mainstone.o |
617 | 617 |
CPPFLAGS += -DHAS_AUDIO |
618 | 618 |
endif |
b/hw/devices.h | ||
---|---|---|
52 | 52 |
|
53 | 53 |
void retu_key_event(void *retu, int state); |
54 | 54 |
|
55 |
/* tusb6010.c */ |
|
56 |
struct tusb_s; |
|
57 |
struct tusb_s *tusb6010_init(qemu_irq intr); |
|
58 |
int tusb6010_sync_io(struct tusb_s *s); |
|
59 |
int tusb6010_async_io(struct tusb_s *s); |
|
60 |
void tusb6010_power(struct tusb_s *s, int on); |
|
61 |
|
|
55 | 62 |
#endif |
b/hw/nseries.c | ||
---|---|---|
42 | 42 |
|
43 | 43 |
int keymap[0x80]; |
44 | 44 |
|
45 |
struct tusb_s *usb; |
|
45 | 46 |
void *retu; |
46 | 47 |
void *tahvo; |
47 | 48 |
}; |
... | ... | |
565 | 566 |
cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1)); |
566 | 567 |
} |
567 | 568 |
|
569 |
static void n800_usb_power_cb(void *opaque, int line, int level) |
|
570 |
{ |
|
571 |
struct n800_s *s = opaque; |
|
572 |
|
|
573 |
tusb6010_power(s->usb, level); |
|
574 |
} |
|
575 |
|
|
576 |
static void n800_usb_setup(struct n800_s *s) |
|
577 |
{ |
|
578 |
qemu_irq tusb_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TUSB_INT_GPIO)[0]; |
|
579 |
qemu_irq tusb_pwr = qemu_allocate_irqs(n800_usb_power_cb, s, 1)[0]; |
|
580 |
struct tusb_s *tusb = tusb6010_init(tusb_irq); |
|
581 |
|
|
582 |
/* Using the NOR interface */ |
|
583 |
omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_ASYNC_CS, |
|
584 |
tusb6010_async_io(tusb), 0, 0, tusb); |
|
585 |
omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_SYNC_CS, |
|
586 |
tusb6010_sync_io(tusb), 0, 0, tusb); |
|
587 |
|
|
588 |
s->usb = tusb; |
|
589 |
omap2_gpio_out_set(s->cpu->gpif, N800_TUSB_ENABLE_GPIO, tusb_pwr); |
|
590 |
} |
|
591 |
|
|
568 | 592 |
/* This task is normally performed by the bootloader. If we're loading |
569 | 593 |
* a kernel directly, we need to set up GPMC mappings ourselves. */ |
570 | 594 |
static void n800_gpmc_init(struct n800_s *s) |
... | ... | |
891 | 915 |
n800_spi_setup(s); |
892 | 916 |
n800_dss_setup(s, ds); |
893 | 917 |
n800_cbus_setup(s); |
918 |
if (usb_enabled) |
|
919 |
n800_usb_setup(s); |
|
894 | 920 |
|
895 | 921 |
/* Setup initial (reset) machine state */ |
896 | 922 |
|
b/hw/tusb6010.c | ||
---|---|---|
1 |
/* |
|
2 |
* Texas Instruments TUSB6010 emulation. |
|
3 |
* Based on reverse-engineering of a linux driver. |
|
4 |
* |
|
5 |
* Copyright (C) 2008 Nokia Corporation |
|
6 |
* Written by Andrzej Zaborowski <andrew@openedhand.com> |
|
7 |
* |
|
8 |
* This program is free software; you can redistribute it and/or |
|
9 |
* modify it under the terms of the GNU General Public License as |
|
10 |
* published by the Free Software Foundation; either version 2 or |
|
11 |
* (at your option) version 3 of the License. |
|
12 |
* |
|
13 |
* This program is distributed in the hope that it will be useful, |
|
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 |
* GNU General Public License for more details. |
|
17 |
* |
|
18 |
* You should have received a copy of the GNU General Public License |
|
19 |
* along with this program; if not, write to the Free Software |
|
20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
|
21 |
* MA 02111-1307 USA |
|
22 |
*/ |
|
23 |
#include "qemu-common.h" |
|
24 |
#include "qemu-timer.h" |
|
25 |
#include "usb.h" |
|
26 |
#include "omap.h" |
|
27 |
#include "irq.h" |
|
28 |
|
|
29 |
struct tusb_s { |
|
30 |
int iomemtype[2]; |
|
31 |
qemu_irq irq; |
|
32 |
struct musb_s *musb; |
|
33 |
QEMUTimer *otg_timer; |
|
34 |
QEMUTimer *pwr_timer; |
|
35 |
|
|
36 |
int power; |
|
37 |
uint32_t scratch; |
|
38 |
uint16_t test_reset; |
|
39 |
uint32_t prcm_config; |
|
40 |
uint32_t prcm_mngmt; |
|
41 |
uint16_t otg_status; |
|
42 |
uint32_t dev_config; |
|
43 |
int host_mode; |
|
44 |
uint32_t intr; |
|
45 |
uint32_t intr_ok; |
|
46 |
uint32_t mask; |
|
47 |
uint32_t usbip_intr; |
|
48 |
uint32_t usbip_mask; |
|
49 |
uint32_t gpio_intr; |
|
50 |
uint32_t gpio_mask; |
|
51 |
uint32_t gpio_config; |
|
52 |
uint32_t dma_intr; |
|
53 |
uint32_t dma_mask; |
|
54 |
uint32_t dma_map; |
|
55 |
uint32_t dma_config; |
|
56 |
uint32_t ep0_config; |
|
57 |
uint32_t rx_config[15]; |
|
58 |
uint32_t tx_config[15]; |
|
59 |
uint32_t wkup_mask; |
|
60 |
uint32_t pullup[2]; |
|
61 |
uint32_t control_config; |
|
62 |
uint32_t otg_timer_val; |
|
63 |
}; |
|
64 |
|
|
65 |
#define TUSB_DEVCLOCK 60000000 /* 60 MHz */ |
|
66 |
|
|
67 |
#define TUSB_VLYNQ_CTRL 0x004 |
|
68 |
|
|
69 |
/* Mentor Graphics OTG core registers. */ |
|
70 |
#define TUSB_BASE_OFFSET 0x400 |
|
71 |
|
|
72 |
/* FIFO registers, 32-bit. */ |
|
73 |
#define TUSB_FIFO_BASE 0x600 |
|
74 |
|
|
75 |
/* Device System & Control registers, 32-bit. */ |
|
76 |
#define TUSB_SYS_REG_BASE 0x800 |
|
77 |
|
|
78 |
#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000) |
|
79 |
#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16) |
|
80 |
#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15) |
|
81 |
#define TUSB_DEV_CONF_SOFT_ID (1 << 1) |
|
82 |
#define TUSB_DEV_CONF_ID_SEL (1 << 0) |
|
83 |
|
|
84 |
#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004) |
|
85 |
#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008) |
|
86 |
#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24) |
|
87 |
#define TUSB_PHY_OTG_CTRL_O_ID_PULLUP (1 << 23) |
|
88 |
#define TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19) |
|
89 |
#define TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18) |
|
90 |
#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17) |
|
91 |
#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16) |
|
92 |
#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15) |
|
93 |
#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14) |
|
94 |
#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13) |
|
95 |
#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12) |
|
96 |
#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11) |
|
97 |
#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10) |
|
98 |
#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9) |
|
99 |
#define TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7) |
|
100 |
#define TUSB_PHY_OTG_CTRL_PD (1 << 6) |
|
101 |
#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5) |
|
102 |
#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4) |
|
103 |
#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3) |
|
104 |
#define TUSB_PHY_OTG_CTRL_RESET (1 << 2) |
|
105 |
#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1) |
|
106 |
#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0) |
|
107 |
|
|
108 |
/* OTG status register */ |
|
109 |
#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c) |
|
110 |
#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8) |
|
111 |
#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7) |
|
112 |
#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6) |
|
113 |
#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5) |
|
114 |
#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4) |
|
115 |
#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3) |
|
116 |
#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2) |
|
117 |
#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0) |
|
118 |
#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1) |
|
119 |
#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0) |
|
120 |
|
|
121 |
#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010) |
|
122 |
#define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31) |
|
123 |
#define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff) |
|
124 |
#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014) |
|
125 |
|
|
126 |
/* PRCM configuration register */ |
|
127 |
#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018) |
|
128 |
#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24) |
|
129 |
#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16) |
|
130 |
|
|
131 |
/* PRCM management register */ |
|
132 |
#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c) |
|
133 |
#define TUSB_PRCM_MNGMT_SRP_FIX_TMR(v) (((v) & 0xf) << 25) |
|
134 |
#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24) |
|
135 |
#define TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20) |
|
136 |
#define TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19) |
|
137 |
#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18) |
|
138 |
#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17) |
|
139 |
#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10) |
|
140 |
#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9) |
|
141 |
#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8) |
|
142 |
#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4) |
|
143 |
#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3) |
|
144 |
#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2) |
|
145 |
#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1) |
|
146 |
#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0) |
|
147 |
|
|
148 |
/* Wake-up source clear and mask registers */ |
|
149 |
#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020) |
|
150 |
#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028) |
|
151 |
#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c) |
|
152 |
#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13) |
|
153 |
#define TUSB_PRCM_WGPIO_7 (1 << 12) |
|
154 |
#define TUSB_PRCM_WGPIO_6 (1 << 11) |
|
155 |
#define TUSB_PRCM_WGPIO_5 (1 << 10) |
|
156 |
#define TUSB_PRCM_WGPIO_4 (1 << 9) |
|
157 |
#define TUSB_PRCM_WGPIO_3 (1 << 8) |
|
158 |
#define TUSB_PRCM_WGPIO_2 (1 << 7) |
|
159 |
#define TUSB_PRCM_WGPIO_1 (1 << 6) |
|
160 |
#define TUSB_PRCM_WGPIO_0 (1 << 5) |
|
161 |
#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */ |
|
162 |
#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */ |
|
163 |
#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */ |
|
164 |
#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */ |
|
165 |
#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */ |
|
166 |
|
|
167 |
#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030) |
|
168 |
#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034) |
|
169 |
#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038) |
|
170 |
#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c) |
|
171 |
#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040) |
|
172 |
#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044) |
|
173 |
#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048) |
|
174 |
#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c) |
|
175 |
#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050) |
|
176 |
#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054) |
|
177 |
#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058) |
|
178 |
#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c) |
|
179 |
#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060) |
|
180 |
#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064) |
|
181 |
#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068) |
|
182 |
#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c) |
|
183 |
|
|
184 |
/* NOR flash interrupt source registers */ |
|
185 |
#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070) |
|
186 |
#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074) |
|
187 |
#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078) |
|
188 |
#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c) |
|
189 |
#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24) |
|
190 |
#define TUSB_INT_SRC_USB_IP_CORE (1 << 17) |
|
191 |
#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16) |
|
192 |
#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15) |
|
193 |
#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14) |
|
194 |
#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13) |
|
195 |
#define TUSB_INT_SRC_DEV_READY (1 << 12) |
|
196 |
#define TUSB_INT_SRC_USB_IP_TX (1 << 9) |
|
197 |
#define TUSB_INT_SRC_USB_IP_RX (1 << 8) |
|
198 |
#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7) |
|
199 |
#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6) |
|
200 |
#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5) |
|
201 |
#define TUSB_INT_SRC_USB_IP_CONN (1 << 4) |
|
202 |
#define TUSB_INT_SRC_USB_IP_SOF (1 << 3) |
|
203 |
#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2) |
|
204 |
#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1) |
|
205 |
#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0) |
|
206 |
|
|
207 |
#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080) |
|
208 |
#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084) |
|
209 |
#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100) |
|
210 |
#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104) |
|
211 |
#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108) |
|
212 |
#define TUSB_EP_IN_SIZE (TUSB_SYS_REG_BASE + 0x10c) |
|
213 |
#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148) |
|
214 |
#define TUSB_EP_OUT_SIZE (TUSB_SYS_REG_BASE + 0x14c) |
|
215 |
#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188) |
|
216 |
#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4) |
|
217 |
#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8) |
|
218 |
#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8) |
|
219 |
|
|
220 |
#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8) |
|
221 |
#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc) |
|
222 |
|
|
223 |
/* Device System & Control register bitfields */ |
|
224 |
#define TUSB_INT_CTRL_CONF_INT_RLCYC(v) (((v) & 0x7) << 18) |
|
225 |
#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17) |
|
226 |
#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16) |
|
227 |
#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24) |
|
228 |
#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26) |
|
229 |
#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20) |
|
230 |
#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v) (((v) & 0xf) << 16) |
|
231 |
#define TUSB_EP0_CONFIG_SW_EN (1 << 8) |
|
232 |
#define TUSB_EP0_CONFIG_DIR_TX (1 << 7) |
|
233 |
#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f) |
|
234 |
#define TUSB_EP_CONFIG_SW_EN (1 << 31) |
|
235 |
#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff) |
|
236 |
#define TUSB_PROD_TEST_RESET_VAL 0xa596 |
|
237 |
|
|
238 |
int tusb6010_sync_io(struct tusb_s *s) |
|
239 |
{ |
|
240 |
return s->iomemtype[0]; |
|
241 |
} |
|
242 |
|
|
243 |
int tusb6010_async_io(struct tusb_s *s) |
|
244 |
{ |
|
245 |
return s->iomemtype[1]; |
|
246 |
} |
|
247 |
|
|
248 |
static void tusb_intr_update(struct tusb_s *s) |
|
249 |
{ |
|
250 |
if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY) |
|
251 |
qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok); |
|
252 |
else |
|
253 |
qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok); |
|
254 |
} |
|
255 |
|
|
256 |
static void tusb_usbip_intr_update(struct tusb_s *s) |
|
257 |
{ |
|
258 |
/* TX interrupt in the MUSB */ |
|
259 |
if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask) |
|
260 |
s->intr |= TUSB_INT_SRC_USB_IP_TX; |
|
261 |
else |
|
262 |
s->intr &= ~TUSB_INT_SRC_USB_IP_TX; |
|
263 |
|
|
264 |
/* RX interrupt in the MUSB */ |
|
265 |
if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask) |
|
266 |
s->intr |= TUSB_INT_SRC_USB_IP_RX; |
|
267 |
else |
|
268 |
s->intr &= ~TUSB_INT_SRC_USB_IP_RX; |
|
269 |
|
|
270 |
/* XXX: What about TUSB_INT_SRC_USB_IP_CORE? */ |
|
271 |
|
|
272 |
tusb_intr_update(s); |
|
273 |
} |
|
274 |
|
|
275 |
static void tusb_dma_intr_update(struct tusb_s *s) |
|
276 |
{ |
|
277 |
if (s->dma_intr & ~s->dma_mask) |
|
278 |
s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE; |
|
279 |
else |
|
280 |
s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE; |
|
281 |
|
|
282 |
tusb_intr_update(s); |
|
283 |
} |
|
284 |
|
|
285 |
static void tusb_gpio_intr_update(struct tusb_s *s) |
|
286 |
{ |
|
287 |
/* TODO: How is this signalled? */ |
|
288 |
} |
|
289 |
|
|
290 |
extern CPUReadMemoryFunc *musb_read[]; |
|
291 |
extern CPUWriteMemoryFunc *musb_write[]; |
|
292 |
|
|
293 |
static uint32_t tusb_async_readb(void *opaque, target_phys_addr_t addr) |
|
294 |
{ |
|
295 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
296 |
|
|
297 |
switch (addr & 0xfff) { |
|
298 |
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): |
|
299 |
return musb_read[0](s->musb, addr & 0x1ff); |
|
300 |
|
|
301 |
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): |
|
302 |
return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c)); |
|
303 |
} |
|
304 |
|
|
305 |
printf("%s: unknown register at %03x\n", |
|
306 |
__FUNCTION__, (int) (addr & 0xfff)); |
|
307 |
return 0; |
|
308 |
} |
|
309 |
|
|
310 |
static uint32_t tusb_async_readh(void *opaque, target_phys_addr_t addr) |
|
311 |
{ |
|
312 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
313 |
|
|
314 |
switch (addr & 0xfff) { |
|
315 |
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): |
|
316 |
return musb_read[1](s->musb, addr & 0x1ff); |
|
317 |
|
|
318 |
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): |
|
319 |
return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c)); |
|
320 |
} |
|
321 |
|
|
322 |
printf("%s: unknown register at %03x\n", |
|
323 |
__FUNCTION__, (int) (addr & 0xfff)); |
|
324 |
return 0; |
|
325 |
} |
|
326 |
|
|
327 |
static uint32_t tusb_async_readw(void *opaque, target_phys_addr_t addr) |
|
328 |
{ |
|
329 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
330 |
int offset = addr & 0xfff; |
|
331 |
int epnum; |
|
332 |
uint32_t ret; |
|
333 |
|
|
334 |
switch (offset) { |
|
335 |
case TUSB_DEV_CONF: |
|
336 |
return s->dev_config; |
|
337 |
|
|
338 |
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): |
|
339 |
return musb_read[2](s->musb, offset & 0x1ff); |
|
340 |
|
|
341 |
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): |
|
342 |
return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c)); |
|
343 |
|
|
344 |
case TUSB_PHY_OTG_CTRL_ENABLE: |
|
345 |
case TUSB_PHY_OTG_CTRL: |
|
346 |
return 0x00; /* TODO */ |
|
347 |
|
|
348 |
case TUSB_DEV_OTG_STAT: |
|
349 |
ret = s->otg_status; |
|
350 |
#if 0 |
|
351 |
if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN)) |
|
352 |
ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID; |
|
353 |
#endif |
|
354 |
return ret; |
|
355 |
case TUSB_DEV_OTG_TIMER: |
|
356 |
return s->otg_timer_val; |
|
357 |
|
|
358 |
case TUSB_PRCM_REV: |
|
359 |
return 0x20; |
|
360 |
case TUSB_PRCM_CONF: |
|
361 |
return s->prcm_config; |
|
362 |
case TUSB_PRCM_MNGMT: |
|
363 |
return s->prcm_mngmt; |
|
364 |
case TUSB_PRCM_WAKEUP_SOURCE: |
|
365 |
case TUSB_PRCM_WAKEUP_CLEAR: /* TODO: What does this one return? */ |
|
366 |
return 0x00000000; |
|
367 |
case TUSB_PRCM_WAKEUP_MASK: |
|
368 |
return s->wkup_mask; |
|
369 |
|
|
370 |
case TUSB_PULLUP_1_CTRL: |
|
371 |
return s->pullup[0]; |
|
372 |
case TUSB_PULLUP_2_CTRL: |
|
373 |
return s->pullup[1]; |
|
374 |
|
|
375 |
case TUSB_INT_CTRL_REV: |
|
376 |
return 0x20; |
|
377 |
case TUSB_INT_CTRL_CONF: |
|
378 |
return s->control_config; |
|
379 |
|
|
380 |
case TUSB_USBIP_INT_SRC: |
|
381 |
case TUSB_USBIP_INT_SET: /* TODO: What do these two return? */ |
|
382 |
case TUSB_USBIP_INT_CLEAR: |
|
383 |
return s->usbip_intr; |
|
384 |
case TUSB_USBIP_INT_MASK: |
|
385 |
return s->usbip_mask; |
|
386 |
|
|
387 |
case TUSB_DMA_INT_SRC: |
|
388 |
case TUSB_DMA_INT_SET: /* TODO: What do these two return? */ |
|
389 |
case TUSB_DMA_INT_CLEAR: |
|
390 |
return s->dma_intr; |
|
391 |
case TUSB_DMA_INT_MASK: |
|
392 |
return s->dma_mask; |
|
393 |
|
|
394 |
case TUSB_GPIO_INT_SRC: /* TODO: What do these two return? */ |
|
395 |
case TUSB_GPIO_INT_SET: |
|
396 |
case TUSB_GPIO_INT_CLEAR: |
|
397 |
return s->gpio_intr; |
|
398 |
case TUSB_GPIO_INT_MASK: |
|
399 |
return s->gpio_mask; |
|
400 |
|
|
401 |
case TUSB_INT_SRC: |
|
402 |
case TUSB_INT_SRC_SET: /* TODO: What do these two return? */ |
|
403 |
case TUSB_INT_SRC_CLEAR: |
|
404 |
return s->intr; |
|
405 |
case TUSB_INT_MASK: |
|
406 |
return s->mask; |
|
407 |
|
|
408 |
case TUSB_GPIO_REV: |
|
409 |
return 0x30; |
|
410 |
case TUSB_GPIO_CONF: |
|
411 |
return s->gpio_config; |
|
412 |
|
|
413 |
case TUSB_DMA_CTRL_REV: |
|
414 |
return 0x30; |
|
415 |
case TUSB_DMA_REQ_CONF: |
|
416 |
return s->dma_config; |
|
417 |
case TUSB_EP0_CONF: |
|
418 |
return s->ep0_config; |
|
419 |
case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b): |
|
420 |
epnum = (offset - TUSB_EP_IN_SIZE) >> 2; |
|
421 |
return s->tx_config[epnum]; |
|
422 |
case TUSB_DMA_EP_MAP: |
|
423 |
return s->dma_map; |
|
424 |
case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b): |
|
425 |
epnum = (offset - TUSB_EP_OUT_SIZE) >> 2; |
|
426 |
return s->rx_config[epnum]; |
|
427 |
case TUSB_EP_MAX_PACKET_SIZE_OFFSET ... |
|
428 |
(TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b): |
|
429 |
epnum = (offset - TUSB_EP_MAX_PACKET_SIZE_OFFSET) >> 2; |
|
430 |
return 0x00000000; /* TODO */ |
|
431 |
case TUSB_WAIT_COUNT: |
|
432 |
return 0x00; /* TODO */ |
|
433 |
|
|
434 |
case TUSB_SCRATCH_PAD: |
|
435 |
return s->scratch; |
|
436 |
|
|
437 |
case TUSB_PROD_TEST_RESET: |
|
438 |
return s->test_reset; |
|
439 |
|
|
440 |
/* DIE IDs */ |
|
441 |
case TUSB_DIDR1_LO: |
|
442 |
return 0xa9453c59; |
|
443 |
case TUSB_DIDR1_HI: |
|
444 |
return 0x54059adf; |
|
445 |
} |
|
446 |
|
|
447 |
printf("%s: unknown register at %03x\n", __FUNCTION__, offset); |
|
448 |
return 0; |
|
449 |
} |
|
450 |
|
|
451 |
static void tusb_async_writeb(void *opaque, target_phys_addr_t addr, |
|
452 |
uint32_t value) |
|
453 |
{ |
|
454 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
455 |
|
|
456 |
switch (addr & 0xfff) { |
|
457 |
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): |
|
458 |
musb_write[0](s->musb, addr & 0x1ff, value); |
|
459 |
break; |
|
460 |
|
|
461 |
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): |
|
462 |
musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value); |
|
463 |
break; |
|
464 |
|
|
465 |
default: |
|
466 |
printf("%s: unknown register at %03x\n", |
|
467 |
__FUNCTION__, (int) (addr & 0xfff)); |
|
468 |
return; |
|
469 |
} |
|
470 |
} |
|
471 |
|
|
472 |
static void tusb_async_writeh(void *opaque, target_phys_addr_t addr, |
|
473 |
uint32_t value) |
|
474 |
{ |
|
475 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
476 |
|
|
477 |
switch (addr & 0xfff) { |
|
478 |
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): |
|
479 |
musb_write[1](s->musb, addr & 0x1ff, value); |
|
480 |
break; |
|
481 |
|
|
482 |
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): |
|
483 |
musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value); |
|
484 |
break; |
|
485 |
|
|
486 |
default: |
|
487 |
printf("%s: unknown register at %03x\n", |
|
488 |
__FUNCTION__, (int) (addr & 0xfff)); |
|
489 |
return; |
|
490 |
} |
|
491 |
} |
|
492 |
|
|
493 |
static void tusb_async_writew(void *opaque, target_phys_addr_t addr, |
|
494 |
uint32_t value) |
|
495 |
{ |
|
496 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
497 |
int offset = addr & 0xfff; |
|
498 |
int epnum; |
|
499 |
|
|
500 |
switch (offset) { |
|
501 |
case TUSB_VLYNQ_CTRL: |
|
502 |
break; |
|
503 |
|
|
504 |
case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff): |
|
505 |
musb_write[2](s->musb, offset & 0x1ff, value); |
|
506 |
break; |
|
507 |
|
|
508 |
case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff): |
|
509 |
musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value); |
|
510 |
break; |
|
511 |
|
|
512 |
case TUSB_DEV_CONF: |
|
513 |
s->dev_config = value; |
|
514 |
s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE); |
|
515 |
if (value & TUSB_DEV_CONF_PROD_TEST_MODE) |
|
516 |
cpu_abort(cpu_single_env, "%s: Product Test mode not allowed\n", |
|
517 |
__FUNCTION__); |
|
518 |
break; |
|
519 |
|
|
520 |
case TUSB_PHY_OTG_CTRL_ENABLE: |
|
521 |
case TUSB_PHY_OTG_CTRL: |
|
522 |
return; /* TODO */ |
|
523 |
case TUSB_DEV_OTG_TIMER: |
|
524 |
s->otg_timer_val = value; |
|
525 |
if (value & TUSB_DEV_OTG_TIMER_ENABLE) |
|
526 |
qemu_mod_timer(s->otg_timer, qemu_get_clock(vm_clock) + |
|
527 |
muldiv64(TUSB_DEV_OTG_TIMER_VAL(value), |
|
528 |
ticks_per_sec, TUSB_DEVCLOCK)); |
|
529 |
else |
|
530 |
qemu_del_timer(s->otg_timer); |
|
531 |
break; |
|
532 |
|
|
533 |
case TUSB_PRCM_CONF: |
|
534 |
s->prcm_config = value; |
|
535 |
break; |
|
536 |
case TUSB_PRCM_MNGMT: |
|
537 |
s->prcm_mngmt = value; |
|
538 |
break; |
|
539 |
case TUSB_PRCM_WAKEUP_CLEAR: |
|
540 |
break; |
|
541 |
case TUSB_PRCM_WAKEUP_MASK: |
|
542 |
s->wkup_mask = value; |
|
543 |
break; |
|
544 |
|
|
545 |
case TUSB_PULLUP_1_CTRL: |
|
546 |
s->pullup[0] = value; |
|
547 |
break; |
|
548 |
case TUSB_PULLUP_2_CTRL: |
|
549 |
s->pullup[1] = value; |
|
550 |
break; |
|
551 |
case TUSB_INT_CTRL_CONF: |
|
552 |
s->control_config = value; |
|
553 |
tusb_intr_update(s); |
|
554 |
break; |
|
555 |
|
|
556 |
case TUSB_USBIP_INT_SET: |
|
557 |
s->usbip_intr |= value; |
|
558 |
tusb_usbip_intr_update(s); |
|
559 |
break; |
|
560 |
case TUSB_USBIP_INT_CLEAR: |
|
561 |
s->usbip_intr &= ~value; |
|
562 |
tusb_usbip_intr_update(s); |
|
563 |
musb_core_intr_clear(s->musb, ~value); |
|
564 |
break; |
|
565 |
case TUSB_USBIP_INT_MASK: |
|
566 |
s->usbip_mask = value; |
|
567 |
tusb_usbip_intr_update(s); |
|
568 |
break; |
|
569 |
|
|
570 |
case TUSB_DMA_INT_SET: |
|
571 |
s->dma_intr |= value; |
|
572 |
tusb_dma_intr_update(s); |
|
573 |
break; |
|
574 |
case TUSB_DMA_INT_CLEAR: |
|
575 |
s->dma_intr &= ~value; |
|
576 |
tusb_dma_intr_update(s); |
|
577 |
break; |
|
578 |
case TUSB_DMA_INT_MASK: |
|
579 |
s->dma_mask = value; |
|
580 |
tusb_dma_intr_update(s); |
|
581 |
break; |
|
582 |
|
|
583 |
case TUSB_GPIO_INT_SET: |
|
584 |
s->gpio_intr |= value; |
|
585 |
tusb_gpio_intr_update(s); |
|
586 |
break; |
|
587 |
case TUSB_GPIO_INT_CLEAR: |
|
588 |
s->gpio_intr &= ~value; |
|
589 |
tusb_gpio_intr_update(s); |
|
590 |
break; |
|
591 |
case TUSB_GPIO_INT_MASK: |
|
592 |
s->gpio_mask = value; |
|
593 |
tusb_gpio_intr_update(s); |
|
594 |
break; |
|
595 |
|
|
596 |
case TUSB_INT_SRC_SET: |
|
597 |
s->intr |= value; |
|
598 |
tusb_intr_update(s); |
|
599 |
break; |
|
600 |
case TUSB_INT_SRC_CLEAR: |
|
601 |
s->intr &= ~value; |
|
602 |
tusb_intr_update(s); |
|
603 |
break; |
|
604 |
case TUSB_INT_MASK: |
|
605 |
s->mask = value; |
|
606 |
tusb_intr_update(s); |
|
607 |
break; |
|
608 |
|
|
609 |
case TUSB_GPIO_CONF: |
|
610 |
s->gpio_config = value; |
|
611 |
break; |
|
612 |
case TUSB_DMA_REQ_CONF: |
|
613 |
s->dma_config = value; |
|
614 |
break; |
|
615 |
case TUSB_EP0_CONF: |
|
616 |
s->ep0_config = value & 0x1ff; |
|
617 |
musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value), |
|
618 |
value & TUSB_EP0_CONFIG_DIR_TX); |
|
619 |
break; |
|
620 |
case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b): |
|
621 |
epnum = (offset - TUSB_EP_IN_SIZE) >> 2; |
|
622 |
s->tx_config[epnum] = value; |
|
623 |
musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1); |
|
624 |
break; |
|
625 |
case TUSB_DMA_EP_MAP: |
|
626 |
s->dma_map = value; |
|
627 |
break; |
|
628 |
case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b): |
|
629 |
epnum = (offset - TUSB_EP_OUT_SIZE) >> 2; |
|
630 |
s->rx_config[epnum] = value; |
|
631 |
musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0); |
|
632 |
break; |
|
633 |
case TUSB_EP_MAX_PACKET_SIZE_OFFSET ... |
|
634 |
(TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b): |
|
635 |
epnum = (offset - TUSB_EP_MAX_PACKET_SIZE_OFFSET) >> 2; |
|
636 |
return; /* TODO */ |
|
637 |
case TUSB_WAIT_COUNT: |
|
638 |
return; /* TODO */ |
|
639 |
|
|
640 |
case TUSB_SCRATCH_PAD: |
|
641 |
s->scratch = value; |
|
642 |
break; |
|
643 |
|
|
644 |
case TUSB_PROD_TEST_RESET: |
|
645 |
s->test_reset = value; |
|
646 |
break; |
|
647 |
|
|
648 |
default: |
|
649 |
printf("%s: unknown register at %03x\n", __FUNCTION__, offset); |
|
650 |
return; |
|
651 |
} |
|
652 |
} |
|
653 |
|
|
654 |
static CPUReadMemoryFunc *tusb_async_readfn[] = { |
|
655 |
tusb_async_readb, |
|
656 |
tusb_async_readh, |
|
657 |
tusb_async_readw, |
|
658 |
}; |
|
659 |
|
|
660 |
static CPUWriteMemoryFunc *tusb_async_writefn[] = { |
|
661 |
tusb_async_writeb, |
|
662 |
tusb_async_writeh, |
|
663 |
tusb_async_writew, |
|
664 |
}; |
|
665 |
|
|
666 |
static void tusb_otg_tick(void *opaque) |
|
667 |
{ |
|
668 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
669 |
|
|
670 |
s->otg_timer_val = 0; |
|
671 |
s->intr |= TUSB_INT_SRC_OTG_TIMEOUT; |
|
672 |
tusb_intr_update(s); |
|
673 |
} |
|
674 |
|
|
675 |
static void tusb_power_tick(void *opaque) |
|
676 |
{ |
|
677 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
678 |
|
|
679 |
if (s->power) { |
|
680 |
s->intr_ok = ~0; |
|
681 |
tusb_intr_update(s); |
|
682 |
} |
|
683 |
} |
|
684 |
|
|
685 |
static void tusb_musb_core_intr(void *opaque, int source, int level) |
|
686 |
{ |
|
687 |
struct tusb_s *s = (struct tusb_s *) opaque; |
|
688 |
uint16_t otg_status = s->otg_status; |
|
689 |
|
|
690 |
switch (source) { |
|
691 |
case musb_set_vbus: |
|
692 |
if (level) |
|
693 |
otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID; |
|
694 |
else |
|
695 |
otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID; |
|
696 |
|
|
697 |
/* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set? */ |
|
698 |
/* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set? */ |
|
699 |
if (s->otg_status != otg_status) { |
|
700 |
s->otg_status = otg_status; |
|
701 |
s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG; |
|
702 |
tusb_intr_update(s); |
|
703 |
} |
|
704 |
break; |
|
705 |
|
|
706 |
case musb_set_session: |
|
707 |
/* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set? */ |
|
708 |
/* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set? */ |
|
709 |
if (level) { |
|
710 |
s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID; |
|
711 |
s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END; |
|
712 |
} else { |
|
713 |
s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID; |
|
714 |
s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END; |
|
715 |
} |
|
716 |
|
|
717 |
/* XXX: some IRQ or anything? */ |
|
718 |
break; |
|
719 |
|
|
720 |
case musb_irq_tx: |
|
721 |
case musb_irq_rx: |
|
722 |
s->usbip_intr = musb_core_intr_get(s->musb); |
|
723 |
/* Fall through. */ |
|
724 |
default: |
|
725 |
if (level) |
|
726 |
s->intr |= 1 << source; |
|
727 |
else |
|
728 |
s->intr &= ~(1 << source); |
|
729 |
tusb_intr_update(s); |
|
730 |
break; |
|
731 |
} |
|
732 |
} |
|
733 |
|
|
734 |
struct tusb_s *tusb6010_init(qemu_irq intr) |
|
735 |
{ |
|
736 |
struct tusb_s *s = qemu_mallocz(sizeof(*s)); |
|
737 |
|
|
738 |
s->test_reset = TUSB_PROD_TEST_RESET_VAL; |
|
739 |
s->host_mode = 0; |
|
740 |
s->dev_config = 0; |
|
741 |
s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */ |
|
742 |
s->power = 0; |
|
743 |
s->mask = 0xffffffff; |
|
744 |
s->intr = 0x00000000; |
|
745 |
s->otg_timer_val = 0; |
|
746 |
s->iomemtype[1] = cpu_register_io_memory(0, tusb_async_readfn, |
|
747 |
tusb_async_writefn, s); |
|
748 |
s->irq = intr; |
|
749 |
s->otg_timer = qemu_new_timer(vm_clock, tusb_otg_tick, s); |
|
750 |
s->pwr_timer = qemu_new_timer(vm_clock, tusb_power_tick, s); |
|
751 |
s->musb = musb_init(qemu_allocate_irqs(tusb_musb_core_intr, s, |
|
752 |
__musb_irq_max)); |
|
753 |
|
|
754 |
return s; |
|
755 |
} |
|
756 |
|
|
757 |
void tusb6010_power(struct tusb_s *s, int on) |
|
758 |
{ |
|
759 |
if (!on) |
|
760 |
s->power = 0; |
|
761 |
else if (!s->power && on) { |
|
762 |
s->power = 1; |
|
763 |
|
|
764 |
/* Pull the interrupt down after TUSB6010 comes up. */ |
|
765 |
s->intr_ok = 0; |
|
766 |
tusb_intr_update(s); |
|
767 |
qemu_mod_timer(s->pwr_timer, |
|
768 |
qemu_get_clock(vm_clock) + ticks_per_sec / 2); |
|
769 |
} |
|
770 |
} |
b/hw/usb-musb.c | ||
---|---|---|
1 |
/* |
|
2 |
* "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics, |
|
3 |
* USB2.0 OTG compliant core used in various chips. |
|
4 |
* |
|
5 |
* Copyright (C) 2008 Nokia Corporation |
|
6 |
* Written by Andrzej Zaborowski <andrew@openedhand.com> |
|
7 |
* |
|
8 |
* This program is free software; you can redistribute it and/or |
|
9 |
* modify it under the terms of the GNU General Public License as |
|
10 |
* published by the Free Software Foundation; either version 2 or |
|
11 |
* (at your option) version 3 of the License. |
|
12 |
* |
|
13 |
* This program is distributed in the hope that it will be useful, |
|
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 |
* GNU General Public License for more details. |
|
17 |
* |
|
18 |
* You should have received a copy of the GNU General Public License |
|
19 |
* along with this program; if not, write to the Free Software |
|
20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
|
21 |
* MA 02111-1307 USA |
|
22 |
* |
|
23 |
* Only host-mode and non-DMA accesses are currently supported. |
|
24 |
*/ |
|
25 |
#include "qemu-common.h" |
|
26 |
#include "qemu-timer.h" |
|
27 |
#include "usb.h" |
|
28 |
#include "irq.h" |
|
29 |
|
|
30 |
/* Common USB registers */ |
|
31 |
#define MUSB_HDRC_FADDR 0x00 /* 8-bit */ |
|
32 |
#define MUSB_HDRC_POWER 0x01 /* 8-bit */ |
|
33 |
|
|
34 |
#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */ |
|
35 |
#define MUSB_HDRC_INTRRX 0x04 |
|
36 |
#define MUSB_HDRC_INTRTXE 0x06 |
|
37 |
#define MUSB_HDRC_INTRRXE 0x08 |
|
38 |
#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */ |
|
39 |
#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */ |
|
40 |
#define MUSB_HDRC_FRAME 0x0c /* 16-bit */ |
|
41 |
#define MUSB_HDRC_INDEX 0x0e /* 8 bit */ |
|
42 |
#define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */ |
|
43 |
|
|
44 |
/* Per-EP registers in indexed mode */ |
|
45 |
#define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */ |
|
46 |
|
|
47 |
/* EP FIFOs */ |
|
48 |
#define MUSB_HDRC_FIFO 0x20 |
|
49 |
|
|
50 |
/* Additional Control Registers */ |
|
51 |
#define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */ |
|
52 |
|
|
53 |
/* These are indexed */ |
|
54 |
#define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */ |
|
55 |
#define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */ |
|
56 |
#define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */ |
|
57 |
#define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */ |
|
58 |
|
|
59 |
/* Some more registers */ |
|
60 |
#define MUSB_HDRC_VCTRL 0x68 /* 8 bit */ |
|
61 |
#define MUSB_HDRC_HWVERS 0x6c /* 8 bit */ |
|
62 |
|
|
63 |
/* Added in HDRC 1.9(?) & MHDRC 1.4 */ |
|
64 |
/* ULPI pass-through */ |
|
65 |
#define MUSB_HDRC_ULPI_VBUSCTL 0x70 |
|
66 |
#define MUSB_HDRC_ULPI_REGDATA 0x74 |
|
67 |
#define MUSB_HDRC_ULPI_REGADDR 0x75 |
|
68 |
#define MUSB_HDRC_ULPI_REGCTL 0x76 |
|
69 |
|
|
70 |
/* Extended config & PHY control */ |
|
71 |
#define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */ |
|
72 |
#define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */ |
|
73 |
#define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */ |
|
74 |
#define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */ |
|
75 |
#define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */ |
|
76 |
#define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */ |
|
77 |
#define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */ |
|
78 |
|
|
79 |
/* Per-EP BUSCTL registers */ |
|
80 |
#define MUSB_HDRC_BUSCTL 0x80 |
|
81 |
|
|
82 |
/* Per-EP registers in flat mode */ |
|
83 |
#define MUSB_HDRC_EP 0x100 |
|
84 |
|
|
85 |
/* offsets to registers in flat model */ |
|
86 |
#define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */ |
|
87 |
#define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */ |
|
88 |
#define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */ |
|
89 |
#define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */ |
|
90 |
#define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */ |
|
91 |
#define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */ |
|
92 |
#define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */ |
|
93 |
#define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */ |
|
94 |
#define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */ |
|
95 |
#define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */ |
|
96 |
#define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */ |
|
97 |
#define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */ |
|
98 |
#define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */ |
|
99 |
#define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */ |
|
100 |
#define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */ |
|
101 |
|
|
102 |
/* "Bus control" registers */ |
|
103 |
#define MUSB_HDRC_TXFUNCADDR 0x00 |
|
104 |
#define MUSB_HDRC_TXHUBADDR 0x02 |
|
105 |
#define MUSB_HDRC_TXHUBPORT 0x03 |
|
106 |
|
|
107 |
#define MUSB_HDRC_RXFUNCADDR 0x04 |
|
108 |
#define MUSB_HDRC_RXHUBADDR 0x06 |
|
109 |
#define MUSB_HDRC_RXHUBPORT 0x07 |
|
110 |
|
|
111 |
/* |
|
112 |
* MUSBHDRC Register bit masks |
|
113 |
*/ |
|
114 |
|
|
115 |
/* POWER */ |
|
116 |
#define MGC_M_POWER_ISOUPDATE 0x80 |
|
117 |
#define MGC_M_POWER_SOFTCONN 0x40 |
|
118 |
#define MGC_M_POWER_HSENAB 0x20 |
|
119 |
#define MGC_M_POWER_HSMODE 0x10 |
|
120 |
#define MGC_M_POWER_RESET 0x08 |
|
121 |
#define MGC_M_POWER_RESUME 0x04 |
|
122 |
#define MGC_M_POWER_SUSPENDM 0x02 |
|
123 |
#define MGC_M_POWER_ENSUSPEND 0x01 |
|
124 |
|
|
125 |
/* INTRUSB */ |
|
126 |
#define MGC_M_INTR_SUSPEND 0x01 |
|
127 |
#define MGC_M_INTR_RESUME 0x02 |
|
128 |
#define MGC_M_INTR_RESET 0x04 |
|
129 |
#define MGC_M_INTR_BABBLE 0x04 |
|
130 |
#define MGC_M_INTR_SOF 0x08 |
|
131 |
#define MGC_M_INTR_CONNECT 0x10 |
|
132 |
#define MGC_M_INTR_DISCONNECT 0x20 |
|
133 |
#define MGC_M_INTR_SESSREQ 0x40 |
|
134 |
#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */ |
|
135 |
#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */ |
|
136 |
|
|
137 |
/* DEVCTL */ |
|
138 |
#define MGC_M_DEVCTL_BDEVICE 0x80 |
|
139 |
#define MGC_M_DEVCTL_FSDEV 0x40 |
|
140 |
#define MGC_M_DEVCTL_LSDEV 0x20 |
|
141 |
#define MGC_M_DEVCTL_VBUS 0x18 |
|
142 |
#define MGC_S_DEVCTL_VBUS 3 |
|
143 |
#define MGC_M_DEVCTL_HM 0x04 |
|
144 |
#define MGC_M_DEVCTL_HR 0x02 |
|
145 |
#define MGC_M_DEVCTL_SESSION 0x01 |
|
146 |
|
|
147 |
/* TESTMODE */ |
|
148 |
#define MGC_M_TEST_FORCE_HOST 0x80 |
|
149 |
#define MGC_M_TEST_FIFO_ACCESS 0x40 |
|
150 |
#define MGC_M_TEST_FORCE_FS 0x20 |
|
151 |
#define MGC_M_TEST_FORCE_HS 0x10 |
|
152 |
#define MGC_M_TEST_PACKET 0x08 |
|
153 |
#define MGC_M_TEST_K 0x04 |
|
154 |
#define MGC_M_TEST_J 0x02 |
|
155 |
#define MGC_M_TEST_SE0_NAK 0x01 |
|
156 |
|
|
157 |
/* CSR0 */ |
|
158 |
#define MGC_M_CSR0_FLUSHFIFO 0x0100 |
|
159 |
#define MGC_M_CSR0_TXPKTRDY 0x0002 |
|
160 |
#define MGC_M_CSR0_RXPKTRDY 0x0001 |
|
161 |
|
|
162 |
/* CSR0 in Peripheral mode */ |
|
163 |
#define MGC_M_CSR0_P_SVDSETUPEND 0x0080 |
|
164 |
#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040 |
|
165 |
#define MGC_M_CSR0_P_SENDSTALL 0x0020 |
|
166 |
#define MGC_M_CSR0_P_SETUPEND 0x0010 |
|
167 |
#define MGC_M_CSR0_P_DATAEND 0x0008 |
|
168 |
#define MGC_M_CSR0_P_SENTSTALL 0x0004 |
|
169 |
|
|
170 |
/* CSR0 in Host mode */ |
|
171 |
#define MGC_M_CSR0_H_NO_PING 0x0800 |
|
172 |
#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */ |
|
173 |
#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */ |
|
174 |
#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080 |
|
175 |
#define MGC_M_CSR0_H_STATUSPKT 0x0040 |
|
176 |
#define MGC_M_CSR0_H_REQPKT 0x0020 |
|
177 |
#define MGC_M_CSR0_H_ERROR 0x0010 |
|
178 |
#define MGC_M_CSR0_H_SETUPPKT 0x0008 |
|
179 |
#define MGC_M_CSR0_H_RXSTALL 0x0004 |
|
180 |
|
|
181 |
/* CONFIGDATA */ |
|
182 |
#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */ |
|
183 |
#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */ |
|
184 |
#define MGC_M_CONFIGDATA_BIGENDIAN 0x20 |
|
185 |
#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ |
|
186 |
#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ |
|
187 |
#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */ |
|
188 |
#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ |
|
189 |
#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */ |
|
190 |
|
|
191 |
/* TXCSR in Peripheral and Host mode */ |
|
192 |
#define MGC_M_TXCSR_AUTOSET 0x8000 |
|
193 |
#define MGC_M_TXCSR_ISO 0x4000 |
|
194 |
#define MGC_M_TXCSR_MODE 0x2000 |
|
195 |
#define MGC_M_TXCSR_DMAENAB 0x1000 |
|
196 |
#define MGC_M_TXCSR_FRCDATATOG 0x0800 |
|
197 |
#define MGC_M_TXCSR_DMAMODE 0x0400 |
|
198 |
#define MGC_M_TXCSR_CLRDATATOG 0x0040 |
|
199 |
#define MGC_M_TXCSR_FLUSHFIFO 0x0008 |
|
200 |
#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002 |
|
201 |
#define MGC_M_TXCSR_TXPKTRDY 0x0001 |
|
202 |
|
|
203 |
/* TXCSR in Peripheral mode */ |
|
204 |
#define MGC_M_TXCSR_P_INCOMPTX 0x0080 |
|
205 |
#define MGC_M_TXCSR_P_SENTSTALL 0x0020 |
|
206 |
#define MGC_M_TXCSR_P_SENDSTALL 0x0010 |
|
207 |
#define MGC_M_TXCSR_P_UNDERRUN 0x0004 |
|
208 |
|
|
209 |
/* TXCSR in Host mode */ |
|
210 |
#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200 |
|
211 |
#define MGC_M_TXCSR_H_DATATOGGLE 0x0100 |
|
212 |
#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080 |
|
213 |
#define MGC_M_TXCSR_H_RXSTALL 0x0020 |
|
214 |
#define MGC_M_TXCSR_H_ERROR 0x0004 |
|
215 |
|
|
216 |
/* RXCSR in Peripheral and Host mode */ |
|
217 |
#define MGC_M_RXCSR_AUTOCLEAR 0x8000 |
|
218 |
#define MGC_M_RXCSR_DMAENAB 0x2000 |
|
219 |
#define MGC_M_RXCSR_DISNYET 0x1000 |
|
220 |
#define MGC_M_RXCSR_DMAMODE 0x0800 |
|
221 |
#define MGC_M_RXCSR_INCOMPRX 0x0100 |
|
222 |
#define MGC_M_RXCSR_CLRDATATOG 0x0080 |
|
223 |
#define MGC_M_RXCSR_FLUSHFIFO 0x0010 |
|
224 |
#define MGC_M_RXCSR_DATAERROR 0x0008 |
|
225 |
#define MGC_M_RXCSR_FIFOFULL 0x0002 |
|
226 |
#define MGC_M_RXCSR_RXPKTRDY 0x0001 |
|
227 |
|
|
228 |
/* RXCSR in Peripheral mode */ |
|
229 |
#define MGC_M_RXCSR_P_ISO 0x4000 |
|
230 |
#define MGC_M_RXCSR_P_SENTSTALL 0x0040 |
|
231 |
#define MGC_M_RXCSR_P_SENDSTALL 0x0020 |
|
232 |
#define MGC_M_RXCSR_P_OVERRUN 0x0004 |
|
233 |
|
|
234 |
/* RXCSR in Host mode */ |
|
235 |
#define MGC_M_RXCSR_H_AUTOREQ 0x4000 |
|
236 |
#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400 |
|
237 |
#define MGC_M_RXCSR_H_DATATOGGLE 0x0200 |
|
238 |
#define MGC_M_RXCSR_H_RXSTALL 0x0040 |
|
239 |
#define MGC_M_RXCSR_H_REQPKT 0x0020 |
|
240 |
#define MGC_M_RXCSR_H_ERROR 0x0004 |
|
241 |
|
|
242 |
/* HUBADDR */ |
|
243 |
#define MGC_M_HUBADDR_MULTI_TT 0x80 |
|
244 |
|
|
245 |
/* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */ |
|
246 |
#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02 |
|
247 |
#define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01 |
|
248 |
#define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08 |
|
249 |
#define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04 |
|
250 |
#define MGC_M_ULPI_REGCTL_COMPLETE 0x02 |
|
251 |
#define MGC_M_ULPI_REGCTL_REG 0x01 |
|
252 |
|
|
253 |
static void musb_attach(USBPort *port, USBDevice *dev); |
|
254 |
|
|
255 |
struct musb_s { |
|
256 |
qemu_irq *irqs; |
|
257 |
USBPort port; |
|
258 |
|
|
259 |
int idx; |
|
260 |
uint8_t devctl; |
|
261 |
uint8_t power; |
|
262 |
uint8_t faddr; |
|
263 |
|
|
264 |
uint8_t intr; |
|
265 |
uint8_t mask; |
|
266 |
uint16_t tx_intr; |
|
267 |
uint16_t tx_mask; |
|
268 |
uint16_t rx_intr; |
|
269 |
uint16_t rx_mask; |
|
270 |
|
|
271 |
int setup_len; |
|
272 |
int session; |
|
273 |
|
|
274 |
uint32_t buf[0x2000]; |
|
275 |
|
|
276 |
struct musb_ep_s { |
|
277 |
uint16_t faddr[2]; |
|
278 |
uint8_t haddr[2]; |
|
279 |
uint8_t hport[2]; |
|
280 |
uint16_t csr[2]; |
|
281 |
uint16_t maxp[2]; |
|
282 |
uint16_t rxcount; |
|
283 |
uint8_t type[2]; |
|
284 |
uint8_t interval[2]; |
|
285 |
uint8_t config; |
|
286 |
uint8_t fifosize; |
|
287 |
int timeout[2]; /* Always in microframes */ |
|
288 |
|
|
289 |
uint32_t *buf[2]; |
|
290 |
int fifolen[2]; |
|
291 |
int fifostart[2]; |
|
292 |
int fifoaddr[2]; |
|
293 |
USBPacket packey[2]; |
|
294 |
int status[2]; |
|
295 |
int ext_size[2]; |
|
296 |
|
|
297 |
/* For callbacks' use */ |
|
298 |
int epnum; |
|
299 |
int interrupt[2]; |
|
300 |
struct musb_s *musb; |
|
301 |
USBCallback *delayed_cb[2]; |
|
302 |
QEMUTimer *intv_timer[2]; |
|
303 |
/* Duplicating the world since 2008!... probably we should have 32 |
|
304 |
* logical, single endpoints instead. */ |
|
305 |
} ep[16]; |
|
306 |
} *musb_init(qemu_irq *irqs) |
|
307 |
{ |
|
308 |
struct musb_s *s = qemu_mallocz(sizeof(*s)); |
|
309 |
int i; |
|
310 |
|
|
311 |
s->irqs = irqs; |
|
312 |
|
|
313 |
s->faddr = 0x00; |
|
314 |
s->power = MGC_M_POWER_HSENAB; |
|
315 |
s->tx_intr = 0x0000; |
|
316 |
s->rx_intr = 0x0000; |
|
317 |
s->tx_mask = 0xffff; |
|
318 |
s->rx_mask = 0xffff; |
|
319 |
s->intr = 0x00; |
|
320 |
s->mask = 0x06; |
|
321 |
s->idx = 0; |
|
322 |
|
|
323 |
/* TODO: _DW */ |
|
324 |
s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO; |
|
325 |
for (i = 0; i < 16; i ++) { |
|
326 |
s->ep[i].fifosize = 64; |
|
327 |
s->ep[i].maxp[0] = 0x40; |
|
328 |
s->ep[i].maxp[1] = 0x40; |
|
329 |
s->ep[i].musb = s; |
|
330 |
s->ep[i].epnum = i; |
|
331 |
} |
|
332 |
|
|
333 |
qemu_register_usb_port(&s->port, s, 0, musb_attach); |
|
334 |
|
|
335 |
return s; |
|
336 |
} |
|
337 |
|
|
338 |
static void musb_vbus_set(struct musb_s *s, int level) |
|
339 |
{ |
|
340 |
if (level) |
|
341 |
s->devctl |= 3 << MGC_S_DEVCTL_VBUS; |
|
342 |
else |
|
343 |
s->devctl &= ~MGC_M_DEVCTL_VBUS; |
|
344 |
|
|
345 |
qemu_set_irq(s->irqs[musb_set_vbus], level); |
|
346 |
} |
|
347 |
|
|
348 |
static void musb_intr_set(struct musb_s *s, int line, int level) |
|
349 |
{ |
|
350 |
if (!level) { |
|
351 |
s->intr &= ~(1 << line); |
|
352 |
qemu_irq_lower(s->irqs[line]); |
|
353 |
} else if (s->mask & (1 << line)) { |
|
354 |
s->intr |= 1 << line; |
|
355 |
qemu_irq_raise(s->irqs[line]); |
|
356 |
} |
|
357 |
} |
|
358 |
|
|
359 |
static void musb_tx_intr_set(struct musb_s *s, int line, int level) |
|
360 |
{ |
|
361 |
if (!level) { |
|
362 |
s->tx_intr &= ~(1 << line); |
|
363 |
if (!s->tx_intr) |
|
364 |
qemu_irq_lower(s->irqs[musb_irq_tx]); |
|
365 |
} else if (s->tx_mask & (1 << line)) { |
|
366 |
s->tx_intr |= 1 << line; |
|
367 |
qemu_irq_raise(s->irqs[musb_irq_tx]); |
|
368 |
} |
|
369 |
} |
|
370 |
|
|
371 |
static void musb_rx_intr_set(struct musb_s *s, int line, int level) |
|
372 |
{ |
|
373 |
if (line) { |
|
374 |
if (!level) { |
|
375 |
s->rx_intr &= ~(1 << line); |
|
376 |
if (!s->rx_intr) |
|
377 |
qemu_irq_lower(s->irqs[musb_irq_rx]); |
|
378 |
} else if (s->rx_mask & (1 << line)) { |
|
379 |
s->rx_intr |= 1 << line; |
|
380 |
qemu_irq_raise(s->irqs[musb_irq_rx]); |
|
381 |
} |
|
382 |
} else |
|
383 |
musb_tx_intr_set(s, line, level); |
|
384 |
} |
|
385 |
|
|
386 |
uint32_t musb_core_intr_get(struct musb_s *s) |
|
387 |
{ |
|
388 |
return (s->rx_intr << 15) | s->tx_intr; |
|
389 |
} |
|
390 |
|
|
391 |
void musb_core_intr_clear(struct musb_s *s, uint32_t mask) |
|
392 |
{ |
|
393 |
if (s->rx_intr) { |
|
394 |
s->rx_intr &= mask >> 15; |
|
395 |
if (!s->rx_intr) |
|
396 |
qemu_irq_lower(s->irqs[musb_irq_rx]); |
|
397 |
} |
|
398 |
|
|
399 |
if (s->tx_intr) { |
|
400 |
s->tx_intr &= mask & 0xffff; |
|
401 |
if (!s->tx_intr) |
|
402 |
qemu_irq_lower(s->irqs[musb_irq_tx]); |
|
403 |
} |
|
404 |
} |
|
405 |
|
|
406 |
void musb_set_size(struct musb_s *s, int epnum, int size, int is_tx) |
|
407 |
{ |
|
408 |
s->ep[epnum].ext_size[!is_tx] = size; |
|
409 |
s->ep[epnum].fifostart[0] = 0; |
|
410 |
s->ep[epnum].fifostart[1] = 0; |
|
411 |
s->ep[epnum].fifolen[0] = 0; |
|
412 |
s->ep[epnum].fifolen[1] = 0; |
|
413 |
} |
|
414 |
|
|
415 |
static void musb_session_update(struct musb_s *s, int prev_dev, int prev_sess) |
|
416 |
{ |
|
417 |
int detect_prev = prev_dev && prev_sess; |
|
418 |
int detect = !!s->port.dev && s->session; |
|
419 |
|
|
420 |
if (detect && !detect_prev) { |
|
421 |
/* Let's skip the ID pin sense and VBUS sense formalities and |
|
422 |
* and signal a successful SRP directly. This should work at least |
|
423 |
* for the Linux driver stack. */ |
|
424 |
musb_intr_set(s, musb_irq_connect, 1); |
|
425 |
|
|
426 |
if (s->port.dev->speed == USB_SPEED_LOW) { |
|
427 |
s->devctl &= ~MGC_M_DEVCTL_FSDEV; |
|
428 |
s->devctl |= MGC_M_DEVCTL_LSDEV; |
|
429 |
} else { |
|
430 |
s->devctl |= MGC_M_DEVCTL_FSDEV; |
|
431 |
s->devctl &= ~MGC_M_DEVCTL_LSDEV; |
|
432 |
} |
|
433 |
|
|
434 |
/* A-mode? */ |
|
435 |
s->devctl &= ~MGC_M_DEVCTL_BDEVICE; |
|
436 |
|
|
437 |
/* Host-mode bit? */ |
|
438 |
s->devctl |= MGC_M_DEVCTL_HM; |
|
439 |
#if 1 |
|
440 |
musb_vbus_set(s, 1); |
|
441 |
#endif |
|
442 |
} else if (!detect && detect_prev) { |
|
443 |
#if 1 |
|
444 |
musb_vbus_set(s, 0); |
|
445 |
#endif |
|
446 |
} |
|
447 |
} |
|
448 |
|
|
449 |
/* Attach or detach a device on our only port. */ |
|
450 |
static void musb_attach(USBPort *port, USBDevice *dev) |
|
451 |
{ |
|
452 |
struct musb_s *s = (struct musb_s *) port->opaque; |
|
453 |
USBDevice *curr; |
|
454 |
|
|
455 |
port = &s->port; |
|
456 |
curr = port->dev; |
|
457 |
|
|
458 |
if (dev) { |
|
459 |
if (curr) { |
|
460 |
usb_attach(port, NULL); |
|
461 |
/* TODO: signal some interrupts */ |
|
462 |
} |
|
463 |
|
|
464 |
musb_intr_set(s, musb_irq_vbus_request, 1); |
|
465 |
|
|
466 |
/* Send the attach message to device */ |
|
467 |
usb_send_msg(dev, USB_MSG_ATTACH); |
|
468 |
} else if (curr) { |
|
469 |
/* Send the detach message */ |
|
470 |
usb_send_msg(curr, USB_MSG_DETACH); |
|
471 |
|
|
472 |
musb_intr_set(s, musb_irq_disconnect, 1); |
|
473 |
} |
|
474 |
|
|
475 |
port->dev = dev; |
|
476 |
|
|
477 |
musb_session_update(s, !!curr, s->session); |
|
478 |
} |
|
479 |
|
|
480 |
static inline void musb_cb_tick0(void *opaque) |
|
481 |
{ |
|
482 |
struct musb_ep_s *ep = (struct musb_ep_s *) opaque; |
|
483 |
|
|
484 |
ep->delayed_cb[0](&ep->packey[0], opaque); |
|
485 |
} |
|
486 |
|
|
487 |
static inline void musb_cb_tick1(void *opaque) |
|
488 |
{ |
|
489 |
struct musb_ep_s *ep = (struct musb_ep_s *) opaque; |
|
490 |
|
|
491 |
ep->delayed_cb[1](&ep->packey[1], opaque); |
|
492 |
} |
|
493 |
|
|
494 |
#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0) |
|
495 |
|
|
496 |
static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir) |
|
497 |
{ |
|
498 |
struct musb_ep_s *ep = (struct musb_ep_s *) opaque; |
|
499 |
int timeout = 0; |
|
500 |
|
|
501 |
if (ep->status[dir] == USB_RET_NAK) |
|
502 |
timeout = ep->timeout[dir]; |
|
503 |
else if (ep->interrupt[dir]) |
|
504 |
timeout = 8; |
|
505 |
else |
|
506 |
return musb_cb_tick(opaque); |
|
507 |
|
|
508 |
if (!ep->intv_timer[dir]) |
|
509 |
ep->intv_timer[dir] = qemu_new_timer(vm_clock, musb_cb_tick, opaque); |
|
510 |
|
|
511 |
qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock(vm_clock) + |
|
512 |
muldiv64(timeout, ticks_per_sec, 8000)); |
|
513 |
} |
|
514 |
|
|
515 |
static void musb_schedule0_cb(USBPacket *packey, void *opaque) |
|
516 |
{ |
|
517 |
return musb_schedule_cb(packey, opaque, 0); |
|
518 |
} |
|
519 |
|
|
520 |
static void musb_schedule1_cb(USBPacket *packey, void *opaque) |
|
521 |
{ |
|
522 |
return musb_schedule_cb(packey, opaque, 1); |
|
523 |
} |
|
524 |
|
|
525 |
static int musb_timeout(int ttype, int speed, int val) |
|
526 |
{ |
|
527 |
#if 1 |
|
528 |
return val << 3; |
|
529 |
#endif |
|
530 |
|
|
531 |
switch (ttype) { |
|
532 |
case USB_ENDPOINT_XFER_CONTROL: |
|
533 |
if (val < 2) |
|
534 |
return 0; |
|
535 |
else if (speed == USB_SPEED_HIGH) |
|
536 |
return 1 << (val - 1); |
|
537 |
else |
|
538 |
return 8 << (val - 1); |
|
539 |
|
|
540 |
case USB_ENDPOINT_XFER_INT: |
|
541 |
if (speed == USB_SPEED_HIGH) |
|
542 |
if (val < 2) |
|
543 |
return 0; |
|
544 |
else |
|
545 |
return 1 << (val - 1); |
|
546 |
else |
|
547 |
return val << 3; |
|
548 |
|
|
549 |
case USB_ENDPOINT_XFER_BULK: |
|
550 |
case USB_ENDPOINT_XFER_ISOC: |
|
551 |
if (val < 2) |
|
552 |
return 0; |
|
553 |
else if (speed == USB_SPEED_HIGH) |
|
554 |
return 1 << (val - 1); |
|
555 |
else |
|
556 |
return 8 << (val - 1); |
|
557 |
/* TODO: what with low-speed Bulk and Isochronous? */ |
|
558 |
} |
|
559 |
|
|
560 |
cpu_abort(cpu_single_env, "bad interval\n"); |
|
561 |
} |
|
562 |
|
|
563 |
static inline void musb_packet(struct musb_s *s, struct musb_ep_s *ep, |
|
564 |
int epnum, int pid, int len, USBCallback cb, int dir) |
|
565 |
{ |
|
566 |
int ret; |
|
567 |
int idx = epnum && dir; |
|
568 |
int ttype; |
|
569 |
|
|
570 |
/* ep->type[0,1] contains: |
|
571 |
* in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow) |
|
572 |
* in bits 5:4 the transfer type (BULK / INT) |
|
573 |
* in bits 3:0 the EP num |
|
574 |
*/ |
|
575 |
ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0; |
|
576 |
|
|
577 |
ep->timeout[dir] = musb_timeout(ttype, |
|
578 |
ep->type[idx] >> 6, ep->interval[idx]); |
|
579 |
ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT; |
|
580 |
ep->delayed_cb[dir] = cb; |
|
581 |
cb = dir ? musb_schedule1_cb : musb_schedule0_cb; |
|
582 |
|
|
583 |
ep->packey[dir].pid = pid; |
|
584 |
/* A wild guess on the FADDR semantics... */ |
|
585 |
ep->packey[dir].devaddr = ep->faddr[idx]; |
|
586 |
ep->packey[dir].devep = ep->type[idx] & 0xf; |
|
587 |
ep->packey[dir].data = (void *) ep->buf[idx]; |
|
588 |
ep->packey[dir].len = len; |
|
589 |
ep->packey[dir].complete_cb = cb; |
|
590 |
ep->packey[dir].complete_opaque = ep; |
|
591 |
|
|
592 |
if (s->port.dev) |
|
593 |
ret = s->port.dev->handle_packet(s->port.dev, &ep->packey[dir]); |
|
594 |
else |
|
595 |
ret = USB_RET_NODEV; |
|
596 |
|
|
597 |
if (ret == USB_RET_ASYNC) { |
|
598 |
ep->status[dir] = len; |
|
599 |
return; |
|
600 |
} |
|
601 |
|
|
602 |
ep->status[dir] = ret; |
|
603 |
usb_packet_complete(&ep->packey[dir]); |
|
604 |
} |
|
605 |
|
|
606 |
static void musb_tx_packet_complete(USBPacket *packey, void *opaque) |
|
607 |
{ |
|
608 |
/* Unfortunately we can't use packey->devep because that's the remote |
|
609 |
* endpoint number and may be different than our local. */ |
|
610 |
struct musb_ep_s *ep = (struct musb_ep_s *) opaque; |
|
611 |
int epnum = ep->epnum; |
|
612 |
struct musb_s *s = ep->musb; |
|
613 |
|
|
614 |
ep->fifostart[0] = 0; |
|
615 |
ep->fifolen[0] = 0; |
|
616 |
#ifdef CLEAR_NAK |
|
617 |
if (ep->status[0] != USB_RET_NAK) { |
|
618 |
#endif |
|
619 |
if (epnum) |
|
620 |
ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY); |
|
621 |
else |
|
622 |
ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY; |
|
623 |
#ifdef CLEAR_NAK |
|
624 |
} |
|
625 |
#endif |
|
626 |
|
|
627 |
/* Clear all of the error bits first */ |
|
628 |
if (epnum) |
|
629 |
ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL | |
|
630 |
MGC_M_TXCSR_H_NAKTIMEOUT); |
Also available in: Unified diff