summaryrefslogtreecommitdiffstats
path: root/pk/gpe/gpe_init.c
blob: b32c875be0ccff6aa87e83913c8f223cea24cec3 (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
//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2014
// *! All Rights Reserved -- Property of IBM
// *! *** IBM Confidential ***
//-----------------------------------------------------------------------------

/// \file gpe_init.c
/// \brief PK initialization for GPE
///
/// The entry points in this routine are used during initialization.  This
/// code space can be deallocated and reassigned after application
/// initialization if required.

#include "pk.h"
#include "ocb_register_addresses.h"

/// GPE environment initial setup.
///
/// This is setup common to all GPE HW Macro applications.  This setup takes place
/// during boot, before main() is called.

void
__hwmacro_setup(void)
{
    uint64_t oirrA;
    uint64_t oirrB;
    uint64_t oirrC;
    uint64_t owned_actual;
    uint64_t reverse_polarity;

    //verify that this code is running on the correct GPE instance (one time check)
    if((mfspr(SPRN_PIR) & PIR_PPE_INSTANCE_MASK) != APPCFG_OCC_INSTANCE_ID)
    {
        //APPCFG_OCC_INSTANCE_ID does not match actual instance ID!
        PK_PANIC(OCCHW_INSTANCE_MISMATCH);
    }

#if (APPCFG_OCC_INSTANCE_ID == OCCHW_IRQ_ROUTE_OWNER)
    //If this instance is the owner of the interrupt routting registers
    //then write the routing registers for all OCC interrupts.
    //This instance must be the first instance to run within the OCC
    //This will be done while all external interrupts are masked.
    PKTRACE("Initializing External Interrupt Routing Registers");
    out32(OCB_OIMR0_OR, 0xffffffff);
    out32(OCB_OIMR1_OR, 0xffffffff);
    out32(OCB_OIRR0A, (uint32_t)(g_ext_irqs_routeA >> 32));
    out32(OCB_OIRR1A, (uint32_t)g_ext_irqs_routeA);
    out32(OCB_OIRR0B, (uint32_t)(g_ext_irqs_routeB >> 32));
    out32(OCB_OIRR1B, (uint32_t)g_ext_irqs_routeB);
    out32(OCB_OIRR0C, (uint32_t)(g_ext_irqs_routeC >> 32));
    out32(OCB_OIRR1C, (uint32_t)g_ext_irqs_routeC);
#endif

    //Determine from the routing registers which irqs are owned by this instance
    //NOTE: If a bit is not set in the routeA register, it is not owned by a GPE

    oirrA = ((uint64_t)in32(OCB_OIRR0A)) << 32;
    oirrA |= in32(OCB_OIRR1A);
    oirrB = ((uint64_t)in32(OCB_OIRR0B)) << 32;
    oirrB |= in32(OCB_OIRR1B);
    oirrC = ((uint64_t)in32(OCB_OIRR0C)) << 32;
    oirrC |= in32(OCB_OIRR1C);

    //All interrupts routed to a GPE will have a bit set in routeA
    owned_actual = oirrA;

    //wittle it down by bits in the routeB register
#if APPCFG_OCC_INSTANCE_ID & 0x2
    owned_actual &= oirrB;
#else
    owned_actual &= ~oirrB;
#endif

    //wittle it down further by bits in the routeC register
#if APPCFG_OCC_INSTANCE_ID & 0x1
    owned_actual &= oirrC;
#else
    owned_actual &= ~oirrC;
#endif

    //Panic if we don't own the irqs we were expecting
    //NOTE: we don't panic if we are given more IRQ's than expected
    if((owned_actual & g_ext_irqs_owned) != g_ext_irqs_owned)
    {
        //IRQ's were not routed to us correctly.
        PK_PANIC(OCC_IRQ_ROUTING_ERROR);
    }

    //Mask all external interrupts owned by this instance
    //(even the ones given to us that we weren't expecting)
    out32(OCB_OIMR0_OR, (uint32_t)(owned_actual >> 32));
    out32(OCB_OIMR1_OR, (uint32_t)owned_actual);

    //Set the interrupt type for all interrupts owned by this instance
    out32(OCB_OITR0_CLR, (uint32_t)(g_ext_irqs_owned >> 32));
    out32(OCB_OITR1_CLR, (uint32_t)g_ext_irqs_owned);
    out32(OCB_OITR0_OR, (uint32_t)(g_ext_irqs_type >> 32));
    out32(OCB_OITR1_OR, (uint32_t)g_ext_irqs_type);

    //Set the interrupt polarity for all interrupts owned by this instance
    out32(OCB_OIEPR0_CLR, (uint32_t)(g_ext_irqs_owned >> 32));
    out32(OCB_OIEPR1_CLR, (uint32_t)g_ext_irqs_owned);
    out32(OCB_OIEPR0_OR, (uint32_t)(g_ext_irqs_polarity >> 32));
    out32(OCB_OIEPR1_OR, (uint32_t)g_ext_irqs_polarity);

    //clear the status of all external interrupts owned by this instance
    out32(OCB_OISR0_CLR, ((uint32_t)(g_ext_irqs_owned >> 32)));
    out32(OCB_OISR1_CLR, ((uint32_t)g_ext_irqs_owned));

    //set the status for interrupts that have reverse polarity
    reverse_polarity = ~g_ext_irqs_polarity & g_ext_irqs_owned;
    out32(OCB_OISR0_OR, ((uint32_t)(reverse_polarity >> 32)));
    out32(OCB_OISR1_OR, ((uint32_t)reverse_polarity));

    //Unmask the interrupts owned by this instance that are to be enabled by default
    out32(OCB_OIMR0_CLR, (uint32_t)(g_ext_irqs_enable >> 32));
    out32(OCB_OIMR1_CLR, (uint32_t)g_ext_irqs_enable);

    //Wait for the last out32 operation to complete
    sync();

}
OpenPOWER on IntegriCloud