summaryrefslogtreecommitdiff
path: root/common/usbx_host_controllers/src/ux_hcd_ohci_power_root_hubs.c
blob: aa74856fff6422f441091f78bbd8d724c33a9675 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2026-present Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** USBX Component                                                        */
/**                                                                       */
/**   OHCI Controller Driver                                              */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/


/* Include necessary system files.  */

#define UX_SOURCE_CODE

#include "ux_api.h"
#include "ux_hcd_ohci.h"
#include "ux_host_stack.h"


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _ux_hcd_ohci_power_root_hubs                        PORTABLE C      */
/*                                                           6.1.2        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Chaoqiong Xiao, Microsoft Corporation                               */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*     This function powers individually or in gang mode the root HUBs    */
/*     attached to the OHCI controller.                                   */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    hcd_ohci                              Pointer to OHCI controller    */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _ux_hcd_ohci_register_read            OHCI register read            */
/*    _ux_hcd_ohci_register_write           OHCI register write           */
/*    _ux_utility_delay_ms                  Delay                         */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    OHCI Controller Driver                                              */
/*                                                                        */
/**************************************************************************/
VOID  _ux_hcd_ohci_power_root_hubs(UX_HCD_OHCI *hcd_ohci)
{

ULONG       ohci_register_a;
ULONG       ohci_register_b;
ULONG       ohci_register_port_status;
UINT        port_index;


    /* Read the RH descriptor A. This will tell us if ports are always powered or not.  */
    ohci_register_a =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_RH_DESCRIPTOR_A);
    if (ohci_register_a & OHCI_HC_RH_NPS)
        return;

    /* Read the RH descriptor B. It will give us the characteristics of the root HUB.  */
    ohci_register_b =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_RH_DESCRIPTOR_B);

    /* The ports must be power switched. There are 3 possibilities:

            1) individual
            2) gang mode
            3) a combination of both

       The logic is as follows:

       If the PSM bit is not set, gang mode is forced and we use the global power (LPSC) command.
       If PSM is set, each port is powered individually.

       BUT we also need to look into the PPCM field to check if there is any ports
       that may still want to be powered by the global power command. If the bit for a port in
       the mask is set, the power is applied by the local port command in the RH port status (PPS).  */
    if (ohci_register_a & OHCI_HC_RH_PSM)
    {

        /* Check the PPCM field to see if some existing ports need to be powered by the LPSC command.  */
        for (port_index = 0; port_index < hcd_ohci -> ux_hcd_ohci_nb_root_hubs; port_index++)
        {

            if ((ohci_register_b & (0x20000u << port_index)) == 0)
            {

                _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_RH_STATUS, OHCI_HC_RS_LPSC);
                break;
            }
        }

        /* Ports have to be powered individually. This is done for each of the ports whose bit mask is
           set in the PPCM field.  */
        for (port_index = 0; port_index < hcd_ohci -> ux_hcd_ohci_nb_root_hubs; port_index++)
        {

            if ((ohci_register_b & (0x20000u << port_index)) != 0)
            {

                ohci_register_port_status =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_RH_PORT_STATUS + port_index);

                ohci_register_port_status |=  OHCI_HC_PS_PPS;
                _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_RH_PORT_STATUS + port_index, ohci_register_port_status);
            }
        }
    }
    else
    {

        /* Ports have to be powered all at the same time.  */
        _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_RH_STATUS, OHCI_HC_RS_LPSC);
    }

    /* Wait for the power to be stable. the RH  descriptor contains the value POTPGT. We multiply this value by 2
       and this is the number of milliseconds to wait for power to set.  */
    _ux_utility_delay_ms(ohci_register_a >> (OHCI_HC_RH_POTPGT - 1));

    /* Return to caller.  */
    return;
}