1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** USBX Component                                                        */
17 /**                                                                       */
18 /**   OHCI Controller Driver                                              */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 
24 /* Include necessary system files.  */
25 
26 #define UX_SOURCE_CODE
27 
28 #include "ux_api.h"
29 #include "ux_hcd_ohci.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_hcd_ohci_power_root_hubs                        PORTABLE C      */
38 /*                                                           6.1.2        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*     This function powers individually or in gang mode the root HUBs    */
46 /*     attached to the OHCI controller.                                   */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    hcd_ohci                              Pointer to OHCI controller    */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    None                                                                */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _ux_hcd_ohci_register_read            OHCI register read            */
59 /*    _ux_hcd_ohci_register_write           OHCI register write           */
60 /*    _ux_utility_delay_ms                  Delay                         */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    OHCI Controller Driver                                              */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
71 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*  11-09-2020     Chaoqiong Xiao           Modified comment(s),          */
74 /*                                            fixed compile warnings,     */
75 /*                                            resulting in version 6.1.2  */
76 /*                                                                        */
77 /**************************************************************************/
_ux_hcd_ohci_power_root_hubs(UX_HCD_OHCI * hcd_ohci)78 VOID  _ux_hcd_ohci_power_root_hubs(UX_HCD_OHCI *hcd_ohci)
79 {
80 
81 ULONG       ohci_register_a;
82 ULONG       ohci_register_b;
83 ULONG       ohci_register_port_status;
84 UINT        port_index;
85 
86 
87     /* Read the RH descriptor A. This will tell us if ports are always powered or not.  */
88     ohci_register_a =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_RH_DESCRIPTOR_A);
89     if (ohci_register_a & OHCI_HC_RH_NPS)
90         return;
91 
92     /* Read the RH descriptor B. It will give us the characteristics of the root HUB.  */
93     ohci_register_b =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_RH_DESCRIPTOR_B);
94 
95     /* The ports must be power switched. There are 3 possibilities:
96 
97             1) individual
98             2) gang mode
99             3) a combination of both
100 
101        The logic is as follows:
102 
103        If the PSM bit is not set, gang mode is forced and we use the global power (LPSC) command.
104        If PSM is set, each port is powered individually.
105 
106        BUT we also need to look into the PPCM field to check if there is any ports
107        that may still want to be powered by the global power command. If the bit for a port in
108        the mask is set, the power is applied by the local port command in the RH port status (PPS).  */
109     if (ohci_register_a & OHCI_HC_RH_PSM)
110     {
111 
112         /* Check the PPCM field to see if some existing ports need to be powered by the LPSC command.  */
113         for (port_index = 0; port_index < hcd_ohci -> ux_hcd_ohci_nb_root_hubs; port_index++)
114         {
115 
116             if ((ohci_register_b & (0x20000u << port_index)) == 0)
117             {
118 
119                 _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_RH_STATUS, OHCI_HC_RS_LPSC);
120                 break;
121             }
122         }
123 
124         /* Ports have to be powered individually. This is done for each of the ports whose bit mask is
125            set in the PPCM field.  */
126         for (port_index = 0; port_index < hcd_ohci -> ux_hcd_ohci_nb_root_hubs; port_index++)
127         {
128 
129             if ((ohci_register_b & (0x20000u << port_index)) != 0)
130             {
131 
132                 ohci_register_port_status =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_RH_PORT_STATUS + port_index);
133 
134                 ohci_register_port_status |=  OHCI_HC_PS_PPS;
135                 _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_RH_PORT_STATUS + port_index, ohci_register_port_status);
136             }
137         }
138     }
139     else
140     {
141 
142         /* Ports have to be powered all at the same time.  */
143         _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_RH_STATUS, OHCI_HC_RS_LPSC);
144     }
145 
146     /* Wait for the power to be stable. the RH  descriptor contains the value POTPGT. We multiply this value by 2
147        and this is the number of milliseconds to wait for power to set.  */
148     _ux_utility_delay_ms(ohci_register_a >> (OHCI_HC_RH_POTPGT - 1));
149 
150     /* Return to caller.  */
151     return;
152 }
153 
154