4c09c595b7ba046aca76f8548154fca31bbbb595
[ppcskel.git] / ohci.c
1 /*
2        mini - a Free Software replacement for the Nintendo/BroadOn IOS.
3        ohci hardware support
4
5 Copyright (C) 2009     Bernhard Urban <lewurm@gmx.net>
6 Copyright (C) 2009     Sebastian Falbesoner <sebastian.falbesoner@gmail.com>
7
8 # This code is licensed to you under the terms of the GNU GPL, version 2;
9 # see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
10 */
11
12 #include "bootmii_ppc.h"
13 #include "ohci.h"
14
15 #define gecko_printf printf
16 #define set32(address, flags) write32(address, read32(address) | flags)
17 #define dma_addr(address) (u32)address
18
19 /* stolen from libogc - gc/ogc/machine/processor.h */
20 #define _CPU_ISR_Disable( _isr_cookie ) \
21   { register u32 _disable_mask = 0; \
22         _isr_cookie = 0; \
23     __asm__ __volatile__ ( \
24           "mfmsr %0\n" \
25           "rlwinm %1,%0,0,17,15\n" \
26           "mtmsr %1\n" \
27           "extrwi %0,%0,1,16" \
28           : "=&r" ((_isr_cookie)), "=&r" ((_disable_mask)) \
29           : "0" ((_isr_cookie)), "1" ((_disable_mask)) \
30         ); \
31   }
32
33 #define _CPU_ISR_Restore( _isr_cookie )  \
34   { register u32 _enable_mask = 0; \
35         __asm__ __volatile__ ( \
36     "    cmpwi %0,0\n" \
37         "    beq 1f\n" \
38         "    mfmsr %1\n" \
39         "    ori %1,%1,0x8000\n" \
40         "    mtmsr %1\n" \
41         "1:" \
42         : "=r"((_isr_cookie)),"=&r" ((_enable_mask)) \
43         : "0"((_isr_cookie)),"1" ((_enable_mask)) \
44         ); \
45   }
46
47
48 static struct ohci_hcca hcca_oh0;
49
50 static void dbg_op_state() {
51        switch (read32(OHCI0_HC_CONTROL) & OHCI_CTRL_HCFS) {
52                case OHCI_USB_SUSPEND:
53                        gecko_printf("ohci-- OHCI_USB_SUSPEND\n");
54                        break;
55                case OHCI_USB_RESET:
56                        gecko_printf("ohci-- OHCI_USB_RESET\n");
57                        break;
58                case OHCI_USB_OPER:
59                        gecko_printf("ohci-- OHCI_USB_OPER\n");
60                        break;
61                case OHCI_USB_RESUME:
62                        gecko_printf("ohci-- OHCI_USB_RESUME\n");
63                        break;
64        }
65 }
66
67 void ohci_init() {
68        gecko_printf("ohci-- init\n");
69        dbg_op_state();
70        /*
71        u32 i = 0;
72        for(; i <= 0x200; i+=4) {
73                gecko_printf("0x0d050000 + %X: %X\n", i, read32(0x0d050000+i));
74                udelay(10000); //'cause usb gecko is lame
75        }
76        * see output in ohci.default
77        */
78
79        /* enable interrupts of both usb host controllers */
80        set32(EHCI_CTL, EHCI_CTL_OH0INTE | EHCI_CTL_OH1INTE | 0xe0000);
81
82        /* reset HC */
83        set32(OHCI0_HC_COMMAND_STATUS, OHCI_HCR);
84
85        /* wait max. 30us */
86        u32 ts = 30;
87        while ((read32(OHCI0_HC_COMMAND_STATUS) & OHCI_HCR) != 0) {
88                if(--ts == 0) {
89                        gecko_printf("ohci-- FAILED");
90                        return;
91                }
92                udelay(1);
93        }
94
95        /* disable interrupts; 2ms timelimit here! 
96           now we're in the SUSPEND state ... must go OPERATIONAL
97           within 2msec else HC enters RESUME */
98
99
100        //u32 cookie = irq_kill();
101        u32 cookie;
102        _CPU_ISR_Disable(cookie);
103
104
105        /* Tell the controller where the control and bulk lists are
106         * The lists are empty now. */
107        write32(OHCI0_HC_CTRL_HEAD_ED, 0);
108        write32(OHCI0_HC_BULK_HEAD_ED, 0);
109
110        /* set hcca adress */
111        write32(OHCI0_HC_HCCA, dma_addr(&hcca_oh0));
112
113        /* set periodicstart */
114 #define FIT (1<<31)
115        u32 fmInterval = read32(OHCI0_HC_FM_INTERVAL) &0x3fff;
116        u32 fit = read32(OHCI0_HC_FM_INTERVAL) & FIT;
117
118        write32(OHCI0_HC_FM_INTERVAL, read32(OHCI0_HC_FM_INTERVAL) | (fit ^ FIT));
119        write32(OHCI0_HC_PERIODIC_START, ((9*fmInterval)/10)&0x3fff);
120
121        /* testing bla */
122        if ((read32(OHCI0_HC_FM_INTERVAL) & 0x3fff0000) == 0 || !read32(OHCI0_HC_PERIODIC_START)) {
123                gecko_printf("ohci-- w00t, fail!! see ohci-hcd.c:669\n");
124        }
125        
126        /* start HC operations */
127        set32(OHCI0_HC_CONTROL, OHCI_CONTROL_INIT | OHCI_USB_OPER);
128
129        /* wake on ConnectStatusChange, matching external hubs */
130        set32(OHCI0_HC_RH_STATUS, RH_HS_DRWE);
131
132        /* Choose the interrupts we care about now, others later on demand */
133        write32(OHCI0_HC_INT_STATUS, ~0);
134        write32(OHCI0_HC_INT_ENABLE, OHCI_INTR_INIT);
135
136
137        //irq_restore(cookie);
138        _CPU_ISR_Restore(cookie);
139
140
141        dbg_op_state();
142
143 }
144