summaryrefslogtreecommitdiffstats
path: root/src/lib/gpe_control.pS
blob: 3f3c7904c94fc071c0e02e16abc428574b942df3 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// $Id: gpe_control.pS,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/gpe_control.pS,v $
//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2013
// *! All Rights Reserved -- Property of IBM
// *! *** IBM Confidential ***
//-----------------------------------------------------------------------------
        
/// \file gpe_control.S
/// \brief GPE procedures for control

        .nolist

#include "ssx.h"
#include "pgas.h"
#include "gpe.h"
#include "gpe_control.h"

        .list

        .oci
        .text.pore

/// \fn gpe_set_pstates(GpeSetPstatesParms *parms)
/// \brief Set core chiplet Pstate registers
///
/// This routine loops through an array of PcbsPstateRegs structures
/// holding the register images to be actuated.  A pointer to the array is
/// provided as the \a registers parameter. For every core chiplet
/// appearing in the \a cfg parameter, those registers marked in the \a select
/// parameter are updated.
///  
/// When the PMBR is being updated, an option is provided to
/// set PCBS_PCBSPM_MODE_REG[enable_pmax_sync_interrupt] around the
/// update of PMBR.  This will cause a SYNC interrupt from each
/// core. This mode currently does not set up the sync protocol in the PMC -
/// the caller must do that.
///
/// Note that actuating the PMCR and PMICR using this method requires that the
/// PCB Slave bit PMGP0_REG.pm_spr_override_en is set.
#ifdef DOXYGEN_ONLY
void gpe_set_pstates(GpeSetPstatesParms *parms);
#endif
/// \cond
        
        // Register usage:
        //
        // A1 :  Holds the (constant) pointer to the paramaters
        // A0 :  Holds the (varying) pointer to the next register block
        // D1 :  Holds the (varying) ChipConfig mask
        // D0 :  Scratch
        // P0 :  Holds the (varying) chiplet id

        .global gpe_set_pstates

gpe_set_pstates:
                
        // Set up registers.  The chiplet part of the ChipConfig is left
        // justified in D1, which will be rotated on each loop.
        
        mr      A1, ETR
        ld      D0, GPESETPSTATESPARMS_REGS, A1
        mr      A0, D0
        ld      D0, GPESETPSTATESPARMS_CONFIG, A1
        mr      D1, D0
        left_justify_core_config D1
        lpcs    P0, 0x10000000  # Load P0 with core chiplet 0 address
        ls      CTR, PGP_NCORES
        bra     start_loop

set_pstates_loop:
        // If the chiplet is not configured, simply continue
        
        andi    D0, D1, 0x8000000000000000
        braz    D0, set_pstates_continue

        // Test/actuate each register in order

        ldandi  D0, GPESETPSTATESPARMS_SELECT, A1, GPE_SET_PSTATES_PMBR
        braz    D0, pmicr

        // PMBR.  
        
        // If SYNCing, the register write is wrapped by a read-modify-write of
        // the PCBS_PCBSPM_MODE_REG which enables the PMAX Sync
        // acknowledge. Note that the original PCBSPM mode reg is saved and
        // restored.
pmbr:   
        ldandi  D0, GPESETPSTATESPARMS_SELECT, A1, GPE_SET_PSTATES_SYNC
        braz    D0, nosync

sync:
        ld      D0, PCBS_PCBSPM_MODE_REG, P0
        la      A1, gsp_pcbs_pcbspm_mode_reg
        std     D0, 0, A1
        ori     D0, D0, PCBS_PCBSPM_MODE_REG_ENABLE_PMC_PMAX_SYNC_NOTIFICATION
        std     D0, PCBS_PCBSPM_MODE_REG, P0

        ld      D0, PCBSPSTATEREGS_PMBR, A0
        std     D0, PCBS_POWER_MANAGEMENT_BOUNDS_REG, P0

        ld      D0, 0, A1
        std     D0, PCBS_PCBSPM_MODE_REG, P0
        // restore A1
        mr      A1, ETR
        bra     pmicr   

nosync: 
        ld      D0, PCBSPSTATEREGS_PMBR, A0
        std     D0, PCBS_POWER_MANAGEMENT_BOUNDS_REG, P0

        // PMICR
pmicr:
        ldandi  D0, GPESETPSTATESPARMS_SELECT, A1, GPE_SET_PSTATES_PMICR
        braz    D0, pmcr
        ld      D0, PCBSPSTATEREGS_PMICR, A0
        std     D0, PCBS_POWER_MANAGEMENT_IDLE_CONTROL_REG, P0

        // PMCR
pmcr:   
        ldandi  D0, GPESETPSTATESPARMS_SELECT, A1, GPE_SET_PSTATES_PMCR
        braz    D0, set_pstates_continue
        ld      D0, PCBSPSTATEREGS_PMCR, A0
        std     D0, PCBS_POWER_MANAGEMENT_CONTROL_REG, P0

set_pstates_continue:   

        // Increment the chiplet index and data pointer, then loop or halt. 

        adds    P0, P0, 1
        adds    A0, A0, SIZEOF_PCBSPSTATEREGS
        rotldi  D1, D1, 1
start_loop:             
        loop    set_pstates_loop

        halt

        .epilogue gpe_set_pstates

/// \endcond

/// Data storage for procedures.
/// Placing data in the .rodata section to prevent the 405 from stomping them.
        .section .rodata
        .balign 8
/// data for gpe_set_pstates









/// \cond

gsp_pcbs_pcbspm_mode_reg:
        .quad   0
/// \endcond
OpenPOWER on IntegriCloud