Tizen 2.1 base
[sdk/emulator/qemu.git] / hw / s5pc1xx_usb_otg.c
1 /*
2  * S5PC1XX UART Emulation
3  *
4  * Copyright (c) 2009 Samsung Electronics.
5  * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
6  */
7
8 #include "sysbus.h"
9 #include "qemu-common.h"
10 #include "qemu-timer.h"
11 #include "usb.h"
12 #include "net.h"
13 #include "irq.h"
14 #include "hw.h"
15 #include "s5pc1xx.h"
16
17
18 /* Interrupts */
19 #define USB_INT_MODEMIS     (1 <<  1) /* Mode Mismatch Interrupt */
20 #define USB_INT_OTGINT      (1 <<  2) /* OTG Interrupt */
21 #define USB_INT_SOF         (1 <<  3) /* Start of (micro) Frame */
22 #define USB_INT_RXFLVL      (1 <<  4) /* RxFIFO Non-Empty */
23 #define USB_INT_NPTXFEMP    (1 <<  5) /* Non-periodic TxFIFO Empty */
24 #define USB_INT_GINNAKEFF   (1 <<  6) /* Global IN Non-periodic NAK Effective */
25 #define USB_INT_GOUTNAKEFF  (1 <<  7) /* Global OUT NAK Effective */
26 #define USB_INT_ERLYSUSP    (1 << 10) /* Early Suspend */
27 #define USB_INT_USBSUSP     (1 << 11) /* USB Suspend */
28 #define USB_INT_USBRST      (1 << 12) /* USB Reset */
29 #define USB_INT_ENUMDONE    (1 << 13) /* Enumeration Done */
30 #define USB_INT_ISOUTDROP   (1 << 14) /* Isochronous OUT Packet Dropped */
31 #define USB_INT_EOPF        (1 << 15) /* End of Periodic Frame */
32 #define USB_INT_IEPINT      (1 << 18) /* IN Endpoints Interrupt */
33 #define USB_INT_OEPINT      (1 << 19) /* OUT Endpoints Interrupt */
34 #define USB_INT_INCOMPLISOIN \
35                             (1 << 20) /* Incomplete Isochronous IN Transfer */
36 #define USB_INT_INCOMPLISOOUT \
37                             (1 << 21) /* Incomplete Isochronous OUT Transfer */
38 #define USB_INT_FETSUSP     (1 << 22) /* Data Fetch Suspended */
39 //#define USB_INT_PRTINT    (1 << 24) /* Host Port Interrupt */
40 //#define USB_INT_HCHINT    (1 << 25) /* Host Channels Interrupt */
41 #define USB_INT_PTXFEMP     (1 << 26) /* Periodic TxFIFO Empty */
42 #define USB_INT_CONIDSTSCHNG \
43                             (1 << 28) /* Connector ID Status Change */
44 #define USB_INT_DISCONINT   (1 << 29) /* Disconnect Detected Interrupt */
45 #define USB_INT_SESSREQINT  (1 << 30) /* New Session Detected Interrupt */
46 #define USB_INT_WKUPINT     (1 << 31) /* Resume Interrupt */
47
48 #define EP_INT_XFERCOMPL    (1 <<  0) /* Transfer complete */
49 #define EP_INT_EPDISABLED   (1 <<  1) /* Endpoint disabled */
50 #define EP_INT_AHBERR       (1 <<  2) /* AHB error */
51 #define EP_INT_SETUP        (1 <<  3) /* [OUT] Setup phase done */
52 #define EP_INT_TIMEOUT      (1 <<  3) /* [IN] Timeout */
53 #define EP_INT_OUTTKNEPDIS  (1 <<  4) /* [OUT] Token Received When EP Disabled */
54 #define EP_INT_INTKNFIFOEMP (1 <<  4) /* [IN] Token Received When FIFO is Empty */
55 #define EP_INT_STSPHSERCVD  (1 <<  5) /* [OUT] Status Phase Received For Control Write */
56 #define EP_INT_INTTKNEPMIS  (1 <<  5) /* [IN] Token Received With EP Missmatch */
57 #define EP_INT_BACK2BACK    (1 <<  6) /* [OUT] Back-to-Back SETUP Packets Receive */
58 #define EP_INT_INEPNAKEFF   (1 <<  6) /* [IN] Endpoint NAK Effective */
59 #define EP_INT_TXFEMP       (1 <<  7) /* Transmit FIFO Empty */
60 #define EP_INT_OUTPKTERR    (1 <<  8) /* [OUT] Packet Error */
61 #define EP_INT_TXFIFOUNDRN  (1 <<  8) /* [IN] FIFO Underrun */
62 #define EP_INT_BNAINTR      (1 <<  9) /* Buffer not Available */
63
64
65 #define OTG_EP_DIR_IN       0x80
66 #define OTG_EP_DIR_OUT      0
67
68 #define OTG_EP_ENABLE       (1U << 31)
69 #define OTG_EP_DISABLE      (1 << 30)
70
71 #define OTG_EP_COUNT        16
72
73
74 typedef enum {
75     OTG_STATE_START = 0,
76     OTG_STATE_RESET,
77     OTG_STATE_SPEEDDETECT,
78     OTG_STATE_SETCONFIG_S,
79     OTG_STATE_SETCONFIG_W,
80     OTG_STATE_SETCONFIG_D,
81     OTG_STATE_SETIFACE_S,
82     OTG_STATE_SETIFACE_W,
83     OTG_STATE_SETIFACE_D,
84     OTG_STATE_OPERATIONAL
85 } OtgLogicalState;
86
87 typedef struct S5pc1xxUsbOtgEndPoint {
88     uint32_t n;
89     uint32_t ctrl;
90     uint32_t interrupt;
91     uint32_t transfer_size;
92     uint32_t dma_addr;
93     uint32_t dma_buf;
94     uint32_t in_fifo_size;
95
96     uint8_t dir;
97
98     struct S5pc1xxUsbOtgState *parent;
99 } S5pc1xxUsbOtgEndPoint;
100
101 typedef struct S5pc1xxUsbOtgState {
102     SysBusDevice busdev;
103
104     struct S5pc1xxPhyState {
105         uint32_t power;
106         uint32_t clock;
107         uint32_t reset;
108         uint32_t tune0;
109         uint32_t tune1;
110     } phy;
111
112     uint32_t gotg_ctl;
113     uint32_t gotg_int;
114     uint32_t gahb_cfg;
115     uint32_t gusb_cfg;
116     uint32_t grst_ctl;
117     uint32_t gint_sts;
118     uint32_t gint_msk;
119     uint32_t grx_stsr;
120     uint32_t grx_stsp;
121     uint32_t grx_fsiz;
122     uint32_t gnptx_fsiz;
123     uint32_t gnptx_sts;
124     uint32_t hnptx_fsiz;
125     uint32_t daint_sts;
126     uint32_t daint_msk;
127     uint32_t diep_msk;
128     uint32_t doep_msk;
129
130     S5pc1xxUsbOtgEndPoint ep_in[OTG_EP_COUNT];
131     S5pc1xxUsbOtgEndPoint ep_out[OTG_EP_COUNT];
132
133     OtgLogicalState state;
134
135     NICState *nic;
136     NICConf conf;
137     qemu_irq irq;
138     uint8_t buf[1600];
139     uint32_t buf_size;
140     uint8_t buf_full;
141 } S5pc1xxUsbOtgState;
142
143
144 static const uint8_t otg_setup_packet[] = {
145     0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00
146 };
147 static const uint8_t otg_setup_iface[] = {
148     0x01, 0x0B, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00
149 };
150 static const uint8_t otg_setup_config[] = {
151     0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
152 };
153
154 static void s5pc1xx_usb_otg_update_irq(S5pc1xxUsbOtgState *s)
155 {
156     if (s->gint_sts & s->gint_msk) {
157         qemu_irq_raise(s->irq);
158     } else {
159         qemu_irq_lower(s->irq);
160     }
161 }
162
163 static void s5pc1xx_usb_otg_initial_reset(DeviceState *d)
164 {
165     S5pc1xxUsbOtgState *s =
166         FROM_SYSBUS(S5pc1xxUsbOtgState, sysbus_from_qdev(d));
167     int i;
168
169     s->phy.power = 0x000001F9;
170     s->phy.clock = 0x00000000;
171     s->phy.reset = 0x00000009; /* TODO: I believe it should be 0 */
172     s->phy.tune0 = 0x000919B3;
173     s->phy.tune1 = 0x000919B3;
174
175     s->gotg_ctl = 0x00010000;
176     s->gotg_int = 0x00000000;
177     s->gahb_cfg = 0x00000000;
178     s->gusb_cfg = 0x00001408;
179     s->grst_ctl = 0x80000000;
180     s->gint_sts = 0x04000020;
181     s->gint_msk = 0x00000000;
182
183     for (i = 0; i < OTG_EP_COUNT; i++) {
184         s->ep_in[i].parent = s;
185         s->ep_in[i].dir = OTG_EP_DIR_IN;
186         s->ep_in[i].n = i;
187         s->ep_out[i].parent = s;
188         s->ep_out[i].dir = OTG_EP_DIR_OUT;
189         s->ep_out[i].n = i;
190     }
191
192     s->state = OTG_STATE_START;
193     s->buf_full = 0;
194 }
195
196 static void s5pc1xx_usb_otg_reset(S5pc1xxUsbOtgState *s)
197 {
198     s5pc1xx_usb_otg_initial_reset(&s->busdev.qdev);
199     s->state = OTG_STATE_RESET;
200     s->gotg_ctl += 0x000C0000;
201     s->gint_sts |= USB_INT_USBRST;
202 }
203
204 static uint32_t s5pc1xx_usb_otg_phy_mm_read(void *opaque,
205                                             target_phys_addr_t offset)
206 {
207     S5pc1xxUsbOtgState *s = (S5pc1xxUsbOtgState *)opaque;
208
209     switch (offset) {
210     case 0x00:
211         return s->phy.power;
212     case 0x04:
213         return s->phy.clock;
214     case 0x08:
215         return s->phy.reset;
216     case 0x20:
217         return s->phy.tune0;
218     case 0x24:
219         return s->phy.tune1;
220     default:
221         hw_error("s5pc1xx.usb_otg: bad read offset 0x" TARGET_FMT_plx "\n",
222                  offset);
223     }
224 }
225
226 static void s5pc1xx_usb_otg_phy_mm_write(void *opaque, target_phys_addr_t offset,
227                                          uint32_t val)
228 {
229     S5pc1xxUsbOtgState *s = (S5pc1xxUsbOtgState *)opaque;
230
231     switch (offset) {
232     case 0x00:
233         s->phy.power = val;
234         break;
235     case 0x04:
236         s->phy.clock = val;
237         break;
238     case 0x08:
239         /* TODO: actually reset USB OTG */
240         if (val & 0x1f) {
241             s5pc1xx_usb_otg_reset(s);
242             s->gint_sts |= USB_INT_USBRST;
243             s5pc1xx_usb_otg_update_irq(s);
244         }
245         break;
246     case 0x20:
247         s->phy.tune0 = val;
248         break;
249     case 0x24:
250         s->phy.tune1 = val;
251         break;
252     default:
253         hw_error("s5pc1xx.usb_otg: bad write offset 0x" TARGET_FMT_plx "\n",
254                  offset);
255     }
256 }
257
258 static void s5pc1xx_usb_otg_ep_update_irq(S5pc1xxUsbOtgEndPoint *s)
259 {
260     if (s->interrupt) {
261         if (s->dir == OTG_EP_DIR_IN) {
262             s->parent->daint_sts |= (1 << s->n);
263             if (s->parent->daint_sts & s->parent->daint_msk & 0xffff) {
264                 s->parent->gint_sts |= USB_INT_IEPINT;
265             } else {
266                 s->parent->gint_sts &= ~USB_INT_IEPINT;
267             }
268         } else {
269             s->parent->daint_sts |= (1 << (s->n + 16));
270             if (s->parent->daint_sts & s->parent->daint_msk & 0xffff0000) {
271                 s->parent->gint_sts |= USB_INT_OEPINT;
272             } else {
273                 s->parent->gint_sts &= ~USB_INT_OEPINT;
274             }
275         }
276     } else {
277         if (s->dir == OTG_EP_DIR_IN) {
278             s->parent->daint_sts &= ~(1 << s->n);
279             if (s->parent->daint_sts & s->parent->daint_msk & 0xffff) {
280                 s->parent->gint_sts |= USB_INT_IEPINT;
281             } else {
282                 s->parent->gint_sts &= ~USB_INT_IEPINT;
283             }
284         } else {
285             s->parent->daint_sts &= ~(1 << (s->n + 16));
286             if (s->parent->daint_sts & s->parent->daint_msk & 0xffff0000) {
287                 s->parent->gint_sts |= USB_INT_OEPINT;
288             } else {
289                 s->parent->gint_sts &= ~USB_INT_OEPINT;
290             }
291         }
292     }
293     s5pc1xx_usb_otg_update_irq(s->parent);
294 }
295
296 static void s5pc1xx_usb_otg_act(S5pc1xxUsbOtgState *s)
297 {
298     switch (s->state) {
299         case OTG_STATE_START:
300         case OTG_STATE_RESET:
301         case OTG_STATE_SPEEDDETECT:
302             break;
303         case OTG_STATE_SETCONFIG_S:
304             if (s->ep_out[0].ctrl & OTG_EP_ENABLE) {
305                 s->state = OTG_STATE_SETCONFIG_W;
306                 cpu_physical_memory_write(s->ep_out[0].dma_addr,
307                                           otg_setup_config, 8);
308                 s->ep_out[0].ctrl &= ~OTG_EP_ENABLE;
309                 s->ep_out[0].interrupt |= EP_INT_SETUP|EP_INT_XFERCOMPL;
310                 s5pc1xx_usb_otg_ep_update_irq(&s->ep_out[0]);
311             }
312             break;
313         case OTG_STATE_SETIFACE_S:
314             if (s->ep_out[0].ctrl & OTG_EP_ENABLE) {
315                 s->state = OTG_STATE_SETIFACE_W;
316                 cpu_physical_memory_write(s->ep_out[0].dma_addr,
317                                           otg_setup_iface, 8);
318                 s->ep_out[0].ctrl &= ~OTG_EP_ENABLE;
319                 s->ep_out[0].interrupt |= EP_INT_SETUP|EP_INT_XFERCOMPL;
320                 s5pc1xx_usb_otg_ep_update_irq(&s->ep_out[0]);
321             }
322             break;
323         default:
324             break;
325     }
326 }
327
328 static void s5pc1xx_usb_otg_data_tx(S5pc1xxUsbOtgEndPoint *s)
329 {
330     uint8_t buf[1600];
331     uint32_t size = s->transfer_size & 0x7ffff;
332
333     cpu_physical_memory_read(s->dma_addr, buf, size);
334     qemu_send_packet(&s->parent->nic->nc, buf, size);
335     s->interrupt |= EP_INT_XFERCOMPL|EP_INT_TXFEMP;
336     s5pc1xx_usb_otg_ep_update_irq(s);
337 }
338
339 static void s5pc1xx_usb_otg_data_rx(S5pc1xxUsbOtgEndPoint *s)
340 {
341     uint32_t size = s->parent->buf_size;
342
343     if (s->parent->buf_size > (s->transfer_size & 0x7ffff)) {
344         s->parent->buf_full = 0;
345         /* Packet dropped */
346         return ;
347     }
348     cpu_physical_memory_write(s->dma_addr, s->parent->buf, size);
349     s->dma_buf = s->dma_addr + size;
350     s->transfer_size -= size;
351     s->ctrl &= ~OTG_EP_ENABLE;
352     s->interrupt |= EP_INT_XFERCOMPL;
353     s->parent->buf_full = 0;
354     s5pc1xx_usb_otg_ep_update_irq(s);
355 }
356
357 static uint32_t s5pc1xx_usb_otg_ep_read(S5pc1xxUsbOtgEndPoint *s,
358                                         target_phys_addr_t addr)
359 {
360     switch (addr) {
361     case 0x00:
362         return s->ctrl;
363     case 0x08:
364         return s->interrupt;
365     case 0x10:
366         return s->transfer_size;
367     case 0x14:
368         return s->dma_addr;
369     case 0x1C:
370         return s->dma_buf;
371     default:
372         hw_error("s5pc1xx.usb_otg: bad write offset 0x" TARGET_FMT_plx "\n",
373                  addr);
374     }
375 }
376
377 static uint32_t s5pc1xx_usb_otg_ep_write(S5pc1xxUsbOtgEndPoint *s,
378                                          target_phys_addr_t addr, uint32_t val)
379 {
380     switch (addr) {
381     case 0x00:
382         if ((val & OTG_EP_DISABLE) && (s->ctrl & OTG_EP_ENABLE)) {
383             s->ctrl &= ~OTG_EP_ENABLE;
384             val &= ~OTG_EP_DISABLE;
385             s->interrupt |= EP_INT_EPDISABLED;
386             s5pc1xx_usb_otg_ep_update_irq(s);
387         }
388         val &= ~OTG_EP_DISABLE;
389         if (val & OTG_EP_ENABLE) {
390             s5pc1xx_usb_otg_act(s->parent);
391             if (s->n == 0 && s->dir == OTG_EP_DIR_IN) {
392                 s->interrupt |= EP_INT_XFERCOMPL|EP_INT_TXFEMP;
393                 if (s->parent->state == OTG_STATE_SETCONFIG_W) {
394                     s->parent->state = OTG_STATE_SETIFACE_S;
395                 } else if (s->parent->state == OTG_STATE_SETIFACE_W) {
396                     s->parent->state = OTG_STATE_OPERATIONAL;
397                 }
398                 s5pc1xx_usb_otg_ep_update_irq(s);
399             }
400             if (s->n != 0 && s->dir == OTG_EP_DIR_IN) {
401                 s5pc1xx_usb_otg_data_tx(s);
402                 val &= ~OTG_EP_ENABLE;
403             }
404             if (s->n != 0 && s->dir == OTG_EP_DIR_OUT &&
405                 s->parent->buf_full == 1) {
406                 s5pc1xx_usb_otg_data_rx(s);
407                 val &= ~OTG_EP_ENABLE;
408             }
409         }
410         val &= ~(0xC << 24); /* TODO: handle NAK? */
411         s->ctrl = val;
412         /* TODO: handle control */
413         break;
414     case 0x08:
415         s->interrupt &= ~val;
416         s5pc1xx_usb_otg_ep_update_irq(s);
417         break;
418     case 0x10:
419         s->transfer_size = val;
420         break;
421     case 0x14:
422         s->dma_addr = val;
423         break;
424     default:
425         hw_error("s5pc1xx.usb_otg: bad write offset 0x" TARGET_FMT_plx "\n",
426                  addr);
427     }
428     return 0;
429 }
430
431 static uint32_t s5pc1xx_usb_otg_read(void *opaque, target_phys_addr_t addr)
432 {
433     S5pc1xxUsbOtgState *s = (S5pc1xxUsbOtgState *)opaque;
434
435     if (addr >= 0x100000 && addr < 0x100028) {
436         return s5pc1xx_usb_otg_phy_mm_read(opaque, addr - 0x100000);
437     }
438
439     switch (addr) {
440     case 0x00:
441         return s->gotg_ctl;
442     case 0x04:
443         return s->gotg_int;
444     case 0x08:
445         return s->gahb_cfg;
446     case 0x0C:
447         return s->gusb_cfg;
448     case 0x10:
449         return s->grst_ctl;
450     case 0x14:
451         return s->gint_sts;
452     case 0x18:
453         return s->gint_msk;
454     case 0x1C:
455         return s->grx_stsr;
456     case 0x20:
457         return s->grx_stsp;
458     case 0x24:
459         return s->grx_fsiz;
460     case 0x28:
461         return s->gnptx_fsiz;
462     case 0x2C:
463         return s->gnptx_sts;
464     case 0x30:
465         return s->hnptx_fsiz;
466     case 0x100 ... 0x13C:
467         return s->ep_in[(addr - 0x100) >> 2].in_fifo_size;
468     case 0x810:
469         return s->diep_msk;
470     case 0x814:
471         return s->doep_msk;
472     case 0x818:
473         return s->daint_sts;
474     case 0x81C:
475         return s->daint_msk;
476     case 0x900 ... 0xAFC:
477         addr -= 0x900;
478         return s5pc1xx_usb_otg_ep_read(&s->ep_in[addr >> 5], addr & 0x1f);
479     case 0xB00 ... 0xCFC:
480         addr -= 0xB00;
481         return s5pc1xx_usb_otg_ep_read(&s->ep_out[addr >> 5], addr & 0x1f);
482     }
483     return 0;
484 }
485
486 static void s5pc1xx_usb_otg_write(void *opaque, target_phys_addr_t addr,
487                                   uint32_t val)
488 {
489     int i;
490     S5pc1xxUsbOtgState *s = (S5pc1xxUsbOtgState *)opaque;
491
492     if (addr >= 0x100000 && addr < 0x100028) {
493         s5pc1xx_usb_otg_phy_mm_write(opaque, addr - 0x100000, val);
494         return;
495     }
496
497     switch (addr) {
498     case 0x00:
499         s->gotg_ctl = val;
500         break;
501     case 0x04:
502         s->gotg_int &= ~val;
503         s5pc1xx_usb_otg_update_irq(s);
504         break;
505     case 0x08:
506         s->gahb_cfg = val;
507         break;
508     case 0x0C:
509         s->gusb_cfg = val;
510         break;
511     case 0x10:
512         if (val & 1) {
513             s5pc1xx_usb_otg_reset(s);
514             s->gint_sts |= USB_INT_USBRST;
515             s->state = OTG_STATE_RESET;
516             s5pc1xx_usb_otg_update_irq(s);
517         } else if (val & 0x0f) {
518             s->gint_sts |= USB_INT_USBRST;
519             s->state = OTG_STATE_RESET;
520             s5pc1xx_usb_otg_update_irq(s);
521         }
522         s->grst_ctl = val & (~0x3f);
523         s5pc1xx_usb_otg_update_irq(s);
524         break;
525     case 0x14:
526         val &= ~(7 << 24);
527         val &= ~(3 << 18);
528         val &= ~(0xf << 4);
529         val &= ~0x5;
530         s->gint_sts &= ~val;
531         if (val == 0x1000) {
532             s->gint_sts |= USB_INT_ENUMDONE;
533             s->state = OTG_STATE_SPEEDDETECT;
534             s5pc1xx_usb_otg_act(s);
535         }
536         if (val == USB_INT_ENUMDONE) {
537             s->state = OTG_STATE_SETCONFIG_S;
538             s5pc1xx_usb_otg_act(s);
539         }
540         s5pc1xx_usb_otg_update_irq(s);
541         break;
542     case 0x18:
543         s->gint_msk = val;
544         break;
545     case 0x24:
546         s->grx_fsiz = val;
547         break;
548     case 0x28:
549         s->gnptx_fsiz = val;
550         break;
551     case 0x30:
552         s->hnptx_fsiz = val;
553         break;
554     case 0x100 ... 0x13C:
555         s->ep_in[(addr - 0x100 ) >> 2].in_fifo_size = val;
556         break;
557     case 0x810:
558         s->diep_msk = val;
559         for (i = 0; i < OTG_EP_COUNT; i++) {
560             s5pc1xx_usb_otg_ep_update_irq(&s->ep_in[i]);
561         }
562         break;
563     case 0x814:
564         s->doep_msk = val;
565         for (i = 0; i < OTG_EP_COUNT; i++) {
566             s5pc1xx_usb_otg_ep_update_irq(&s->ep_out[i]);
567         }
568         break;
569     case 0x81C:
570         s->daint_msk = val;
571         if (s->daint_sts & 0xffff & s->daint_msk) {
572             s->gint_sts |= USB_INT_IEPINT;
573         } else {
574             s->gint_sts &= ~USB_INT_IEPINT;
575         }
576         if ((s->daint_sts & s->daint_msk) >> 16) {
577             s->gint_sts |= USB_INT_OEPINT;
578         } else {
579             s->gint_sts &= ~USB_INT_OEPINT;
580         }
581         s5pc1xx_usb_otg_update_irq(s);
582         break;
583     case 0x900 ... 0xAFC:
584         addr -= 0x900;
585         s5pc1xx_usb_otg_ep_write(&s->ep_in[addr >> 5], addr & 0x1f, val);
586         break;
587     case 0xB00 ... 0xCFC:
588         addr -= 0xB00;
589         s5pc1xx_usb_otg_ep_write(&s->ep_out[addr >> 5], addr & 0x1f, val);
590         break;
591     }
592 }
593
594 static CPUReadMemoryFunc * const s5pc1xx_usb_otg_readfn[] = {
595     s5pc1xx_usb_otg_read,
596     s5pc1xx_usb_otg_read,
597     s5pc1xx_usb_otg_read
598 };
599
600 static CPUWriteMemoryFunc * const s5pc1xx_usb_otg_writefn[] = {
601     s5pc1xx_usb_otg_write,
602     s5pc1xx_usb_otg_write,
603     s5pc1xx_usb_otg_write
604 };
605
606 static void s5pc1xx_usb_otg_save(QEMUFile *f, void *opaque)
607 {
608     S5pc1xxUsbOtgState *s = (S5pc1xxUsbOtgState *)opaque;
609     int i;
610
611     qemu_put_be32s(f, &s->phy.power);
612     qemu_put_be32s(f, &s->phy.clock);
613     qemu_put_be32s(f, &s->phy.reset);
614     qemu_put_be32s(f, &s->phy.tune0);
615     qemu_put_be32s(f, &s->phy.tune1);
616
617     qemu_put_be32s(f, &s->gotg_ctl);
618     qemu_put_be32s(f, &s->gotg_int);
619     qemu_put_be32s(f, &s->gahb_cfg);
620     qemu_put_be32s(f, &s->gusb_cfg);
621     qemu_put_be32s(f, &s->grst_ctl);
622     qemu_put_be32s(f, &s->gint_sts);
623     qemu_put_be32s(f, &s->gint_msk);
624     qemu_put_be32s(f, &s->grx_stsr);
625     qemu_put_be32s(f, &s->grx_stsp);
626     qemu_put_be32s(f, &s->grx_fsiz);
627     qemu_put_be32s(f, &s->gnptx_fsiz);
628     qemu_put_be32s(f, &s->gnptx_sts);
629     qemu_put_be32s(f, &s->hnptx_fsiz);
630     qemu_put_be32s(f, &s->daint_sts);
631     qemu_put_be32s(f, &s->daint_msk);
632     qemu_put_be32s(f, &s->diep_msk);
633     qemu_put_be32s(f, &s->doep_msk);
634     qemu_put_byte (f, (uint8_t) s->state);
635
636     for (i = 0; i < OTG_EP_COUNT; i++) {
637         qemu_put_be32s(f, &s->ep_in[i].ctrl);
638         qemu_put_be32s(f, &s->ep_in[i].interrupt);
639         qemu_put_be32s(f, &s->ep_in[i].transfer_size);
640         qemu_put_be32s(f, &s->ep_in[i].dma_addr);
641         qemu_put_be32s(f, &s->ep_in[i].dma_buf);
642         qemu_put_be32s(f, &s->ep_in[i].in_fifo_size);
643
644         qemu_put_be32s(f, &s->ep_out[i].ctrl);
645         qemu_put_be32s(f, &s->ep_out[i].interrupt);
646         qemu_put_be32s(f, &s->ep_out[i].transfer_size);
647         qemu_put_be32s(f, &s->ep_out[i].dma_addr);
648         qemu_put_be32s(f, &s->ep_out[i].dma_buf);
649         qemu_put_be32s(f, &s->ep_out[i].in_fifo_size);
650     }
651     /* FIXME: must the structure below be saved?
652      * NICState *nic; */
653     qemu_put_be32s (f, &s->buf_size);
654     qemu_put_buffer(f, s->buf, s->buf_size);
655     qemu_put_8s    (f, &s->buf_full);
656 }
657
658 static int s5pc1xx_usb_otg_load(QEMUFile *f, void *opaque, int version_id)
659 {
660     S5pc1xxUsbOtgState *s = (S5pc1xxUsbOtgState *)opaque;
661     int i;
662
663     if (version_id != 1) {
664         return -EINVAL;
665     }
666
667     qemu_get_be32s(f, &s->phy.power);
668     qemu_get_be32s(f, &s->phy.clock);
669     qemu_get_be32s(f, &s->phy.reset);
670     qemu_get_be32s(f, &s->phy.tune0);
671     qemu_get_be32s(f, &s->phy.tune1);
672
673     qemu_get_be32s(f, &s->gotg_ctl);
674     qemu_get_be32s(f, &s->gotg_int);
675     qemu_get_be32s(f, &s->gahb_cfg);
676     qemu_get_be32s(f, &s->gusb_cfg);
677     qemu_get_be32s(f, &s->grst_ctl);
678     qemu_get_be32s(f, &s->gint_sts);
679     qemu_get_be32s(f, &s->gint_msk);
680     qemu_get_be32s(f, &s->grx_stsr);
681     qemu_get_be32s(f, &s->grx_stsp);
682     qemu_get_be32s(f, &s->grx_fsiz);
683     qemu_get_be32s(f, &s->gnptx_fsiz);
684     qemu_get_be32s(f, &s->gnptx_sts);
685     qemu_get_be32s(f, &s->hnptx_fsiz);
686     qemu_get_be32s(f, &s->daint_sts);
687     qemu_get_be32s(f, &s->daint_msk);
688     qemu_get_be32s(f, &s->diep_msk);
689     qemu_get_be32s(f, &s->doep_msk);
690     s->state = qemu_get_byte(f);
691
692     for (i = 0; i < OTG_EP_COUNT; i++) {
693         qemu_get_be32s(f, &s->ep_in[i].ctrl);
694         qemu_get_be32s(f, &s->ep_in[i].interrupt);
695         qemu_get_be32s(f, &s->ep_in[i].transfer_size);
696         qemu_get_be32s(f, &s->ep_in[i].dma_addr);
697         qemu_get_be32s(f, &s->ep_in[i].dma_buf);
698         qemu_get_be32s(f, &s->ep_in[i].in_fifo_size);
699
700         qemu_get_be32s(f, &s->ep_out[i].ctrl);
701         qemu_get_be32s(f, &s->ep_out[i].interrupt);
702         qemu_get_be32s(f, &s->ep_out[i].transfer_size);
703         qemu_get_be32s(f, &s->ep_out[i].dma_addr);
704         qemu_get_be32s(f, &s->ep_out[i].dma_buf);
705         qemu_get_be32s(f, &s->ep_out[i].in_fifo_size);
706     }
707     /* FIXME: NICState *nic; */
708     qemu_get_be32s (f, &s->buf_size);
709     qemu_get_buffer(f, s->buf, s->buf_size);
710     qemu_get_8s    (f, &s->buf_full);
711
712     return 0;
713 }
714
715 static int s5pc1xx_usb_otg_can_receive(VLANClientState *nc)
716 {
717     S5pc1xxUsbOtgState *s = (DO_UPCAST(NICState, nc, nc))->opaque;
718
719     return !s->buf_full;
720 }
721
722 static ssize_t s5pc1xx_usb_otg_receive(VLANClientState *nc, const uint8_t *buf,
723                                        size_t size)
724 {
725     S5pc1xxUsbOtgState *s = (DO_UPCAST(NICState, nc, nc))->opaque;
726     int i;
727
728     s->buf_full = 1;
729     s->buf_size = size;
730     memcpy(s->buf, buf, size);
731     for (i = 0; i < OTG_EP_COUNT; i++) {
732         if (s->ep_out[i].ctrl & OTG_EP_ENABLE) {
733             s5pc1xx_usb_otg_data_rx(&s->ep_out[i]);
734             break;
735         }
736     }
737     return size;
738 }
739
740 static void s5pc1xx_usb_otg_cleanup(VLANClientState *nc)
741 {
742     S5pc1xxUsbOtgState *s = (DO_UPCAST(NICState, nc, nc))->opaque;
743
744     s->nic = NULL;
745 }
746
747 static NetClientInfo net_s5pc1xx_usb_otg_info = {
748     .type = NET_CLIENT_TYPE_NIC,
749     .size = sizeof(NICState),
750     .can_receive = s5pc1xx_usb_otg_can_receive,
751     .receive = s5pc1xx_usb_otg_receive,
752     .cleanup = s5pc1xx_usb_otg_cleanup,
753 };
754
755 static int s5pc1xx_usb_otg_init1(SysBusDevice *dev)
756 {
757     int iomemtype;
758     S5pc1xxUsbOtgState *s = FROM_SYSBUS(S5pc1xxUsbOtgState, dev);
759
760     iomemtype =
761         cpu_register_io_memory(s5pc1xx_usb_otg_readfn,
762                                s5pc1xx_usb_otg_writefn, s, DEVICE_NATIVE_ENDIAN);
763     sysbus_init_mmio(dev, 0x100030, iomemtype);
764     sysbus_init_irq(dev, &s->irq);
765
766     qemu_macaddr_default_if_unset(&s->conf.macaddr);
767
768     s5pc1xx_usb_otg_initial_reset(&s->busdev.qdev);
769
770     s->nic = qemu_new_nic(&net_s5pc1xx_usb_otg_info, &s->conf,
771                           dev->qdev.info->name, dev->qdev.id, s);
772     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
773
774     register_savevm(&dev->qdev, "s5pc1xx.usb.otg", -1, 1,
775                     s5pc1xx_usb_otg_save, s5pc1xx_usb_otg_load, s);
776
777     return 0;
778 }
779
780 static SysBusDeviceInfo s5pc1xx_usb_otg_info = {
781     .init = s5pc1xx_usb_otg_init1,
782     .qdev.name  = "s5pc1xx.usb.otg",
783     .qdev.size  = sizeof(S5pc1xxUsbOtgState),
784     .qdev.reset = s5pc1xx_usb_otg_initial_reset,
785     .qdev.props = (Property[]) {
786         DEFINE_NIC_PROPERTIES(S5pc1xxUsbOtgState, conf),
787         DEFINE_PROP_END_OF_LIST(),
788     }
789 };
790
791 static void s5pc1xx_usb_otg_register_devices(void)
792 {
793     sysbus_register_withprop(&s5pc1xx_usb_otg_info);
794 }
795
796 /* Legacy helper function.  Should go away when machine config files are
797    implemented.  */
798 void s5pc1xx_usb_otg_init(NICInfo *nd, target_phys_addr_t base, qemu_irq irq)
799 {
800     DeviceState *dev;
801     SysBusDevice *s;
802
803     qemu_check_nic_model(nd, "s5pc1xx-usb-otg");
804     dev = qdev_create(NULL, "s5pc1xx.usb.otg");
805     qdev_set_nic_properties(dev, nd);
806     qdev_init_nofail(dev);
807     s = sysbus_from_qdev(dev);
808     sysbus_mmio_map(s, 0, base);
809     sysbus_connect_irq(s, 0, irq);
810 }
811
812 device_init(s5pc1xx_usb_otg_register_devices)