summaryrefslogtreecommitdiffstats
path: root/src/ssx/occhw/occhw_init.c
blob: 0ac98051a927635314b451d1bf5d6765daa635a2 (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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/ssx/occhw/occhw_init.c $                                  */
/*                                                                        */
/* OpenPOWER OnChipController Project                                     */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2014
// *! All Rights Reserved -- Property of IBM
// *! *** IBM Confidential ***
//-----------------------------------------------------------------------------

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

#include "ssx.h"
#include "occhw_async.h"

//#include "occhw_vrm.h"
#include "simics_stdio.h"
#include "string_stream.h"

#if USE_RTX_IO
    // This file is not avilable to OCC FW builds
    #include "rtx_stdio.h"
#endif

// We need to make sure that the PLB arbiter is set up correctly to obtain
// highest performance in the OCCHW environment, and that PLB error reporting is
// appropriate.

// The PLB arbiter is configured to support fair arbitration of equal-priority
// requests, however we don't set priorities here. The default settings have
// been found to be acceptible so far. We do enable arbiter pipelining however.

// We do set the "plbarb_lockerr" bit so that the PLB arbiter will trap and
// hold the first PLB timeout address.

static void
plb_arbiter_setup()
{
    //TODO: enable this once OCB support is present in simics
#if 0
    ocb_oacr_t oacr;
    ocb_ocichsw_t oo;

    oacr.value = 0;
    oacr.fields.oci_priority_mode = 1;          /* Fair arbitration */
    oacr.fields.oci_hi_bus_mode = 1;            /* High bus utilization */
    oacr.fields.oci_read_pipeline_control = 1;  /* 2-deep read pipelining */
    oacr.fields.oci_write_pipeline_control = 1; /* 2-deep write pipelining */
    mtdcr(OCB_OACR, oacr.value);

    oo.value = in32(OCB_OCICHSW);
    oo.fields.plbarb_lockerr = 1;
    out32(OCB_OCICHSW, oo.value);
#endif
}


#if PPC405_MMU_SUPPORT

#include "ppc405_mmu.h"

// MMU regions
//
// The linker script provides a standard set of symbols that define the base
// address and size of each expected section. Any section with a non-0 size
// will be mapped in the MMU using protection attributes appropriate for the
// section.  All sections requiring different MMU attributes must be
// 1KB-aligned.  The OCI control register space is fixed and also mapped by
// the same mechanism.
//
// By default, caching is enabled for all sections other than the sections
// explicitly cache-inhibited.  Configuration options are provided to disable
// caching of text, data and both.  Note that sections that (may) contain code
// and data will be marked cache-inhibited if either text or data is globally
// configured as cache-inhibited.  Also note that "writethrough" can only be
// defined on cacheable data sections.

#ifdef CACHE_INHIBIT_ALL
    #define CACHE_INHIBIT_TEXT 1
    #define CACHE_INHIBIT_DATA 1
#endif

#if CACHE_INHIBIT_TEXT
    #define TEXT_CACHEABILITY_FLAG TLBLO_I
#else
    #define TEXT_CACHEABILITY_FLAG 0
#endif

#if CACHE_INHIBIT_DATA
    #define DATA_CACHEABILITY_FLAG TLBLO_I
    #define WRITETHROUGH_FLAG 0
#else
    #define DATA_CACHEABILITY_FLAG 0
    #define WRITETHROUGH_FLAG TLBLO_W
#endif


// This structure contains all of the fields necessary to create a MMU
// mapping.

typedef struct
{
    SsxAddress base;
    size_t size;
    uint32_t tlbhi_flags;
    uint32_t tlblo_flags;
    Ppc405MmuMap* map;
} MmuRegion;

// The section table along with (default) MMU characteristics.  Global
// Ppc405MmuMap variables are defined for certain sections so that those
// mappings may be later modified.

Ppc405MmuMap G_ex_free_mmu_map;

static const MmuRegion mmu_regions[] =
{

    {
        (SsxAddress)& _TEXT0_SECTION_BASE,
        (size_t)& _TEXT0_SECTION_SIZE,
        0, TEXT_CACHEABILITY_FLAG | TLBLO_EX, 0
    } ,

    {
        (SsxAddress)& _TEXT1_SECTION_BASE,
        (size_t)& _TEXT1_SECTION_SIZE,
        0, TEXT_CACHEABILITY_FLAG | TLBLO_EX, 0
    } ,

    {
        (SsxAddress)& _RODATA_SECTION_BASE,
        (size_t)& _RODATA_SECTION_SIZE,
        0, DATA_CACHEABILITY_FLAG, 0
    } ,

    {
        (SsxAddress)& _NONCACHEABLE_RO_SECTION_BASE,
        (size_t)& _NONCACHEABLE_RO_SECTION_SIZE,
        0, TLBLO_I, 0
    } ,

    {
        (SsxAddress)& _NONCACHEABLE_SECTION_BASE,
        (size_t)& _NONCACHEABLE_SECTION_SIZE,
        0, TLBLO_I | TLBLO_WR, 0
    } ,

    {
        (SsxAddress)& _WRITETHROUGH_SECTION_BASE,
        (size_t)& _WRITETHROUGH_SECTION_SIZE,
        0, DATA_CACHEABILITY_FLAG | WRITETHROUGH_FLAG | TLBLO_WR, 0
    } ,

    {
        (SsxAddress)& _DATA_SECTION_BASE,
        (size_t)& _DATA_SECTION_SIZE,
        0, DATA_CACHEABILITY_FLAG | TLBLO_WR, 0
    } ,

    {
        (SsxAddress)& _EX_FREE_SECTION_BASE,
        (size_t)& _EX_FREE_SECTION_SIZE,
        0, DATA_CACHEABILITY_FLAG | TEXT_CACHEABILITY_FLAG | TLBLO_EX | TLBLO_WR,
        &G_ex_free_mmu_map
    },

    {
        (SsxAddress)OCI_REGISTER_SPACE_BASE,
        (size_t)OCI_REGISTER_SPACE_SIZE,
        0, TLBLO_WR | TLBLO_I | TLBLO_G, 0
    } ,
};

/// OCCHW MMU setup
///
/// Run down the mmu_regions[] array and map all regions with non-0 sizes.
/// These are direct maps, setting the effective address to the physical
/// address.  Once the MMU is set up MMU protection is enabled.
///
/// Any OCC mappings of PBA space will have to be done elsewhere, as these
/// memory areas are controlled by pHyp, and the product firmware has no plans
/// to access main memory from the OCC.

static void
occhw_mmu_setup()
{
    int i, regions;

    ppc405_mmu_reset();

    regions = sizeof(mmu_regions) / sizeof(MmuRegion);

    for (i = 0; i < regions; i++)
    {
        if (mmu_regions[i].size != 0)
        {
            ppc405_mmu_map(mmu_regions[i].base,
                           mmu_regions[i].base,
                           mmu_regions[i].size,
                           mmu_regions[i].tlbhi_flags,
                           mmu_regions[i].tlblo_flags,
                           mmu_regions[i].map);
        }
    }

    ppc405_mmu_start();
}

#endif  /* PPC405_MMU_SUPPORT */


// I/O Initialization
//
// Initialize the SSX/Simics/Verification Serial I/O channels.  This is done
// early in the initialization to allow initialization code to use printk().
// If the application does not select one of the I/O methods then 'ssxout'
// defaults to the NULL stream and 'stdin', 'stdout' and 'stderr' are
// undefined.

#if USE_TRACE_IO || USE_EPM_IO

WrappingStream G_ssxout
SECTION_ATTRIBUTE(".noncacheable") = {{0}};

uint8_t G_ssxout_buffer[SSXOUT_TRACE_BUFFER_SIZE]
SECTION_ATTRIBUTE(".noncacheable") = {0};

#endif  // USE_TRACE_IO || USE_EPM_IO

static void
io_setup()
{
    //NB: These I/O options are listed in priority order - multiple options may
    //be selected.
#if USE_TRACE_IO

    // If the application chooses to use trace buffer output, the application
    // must define SSXOUT_TRACE_BUFFER_SIZE, and all output streams are merged
    // into a single trace buffer which locks low-level file operations in an
    // SSX_CRITICAL critical secton.

    /// \todo Split trace I/O mode into multiple streams

    wrapping_stream_create(&G_ssxout, &G_ssxout_buffer,
                           SSXOUT_TRACE_BUFFER_SIZE,
                           SSX_FILE_OP_LOCK_CRITICAL);

    stdout = (FILE*)(&G_ssxout);
    stderr = (FILE*)(&G_ssxout);
    ssxout = (FILE*)(&G_ssxout);

#elif USE_EPM_IO

    linear_stream_create(&G_ssxout, &G_ssxout_buffer,
                         SSXOUT_TRACE_BUFFER_SIZE,
                         SSX_FILE_OP_LOCK_CRITICAL);

    stdout = (FILE*)(&G_ssxout);
    stderr = (FILE*)(&G_ssxout);
    ssxout = (FILE*)(&G_ssxout);

#elif USE_RTX_IO

    rtx_stdin_create(&rtx_stdin);
    rtx_stdout_create(&rtx_stdout);
    rtx_stderr_create(&rtx_stderr);

    stdin = (FILE*)(&rtx_stdin);
    stdout = (FILE*)(&rtx_stdout);
    stderr = (FILE*)(&rtx_stderr);
    ssxout = (FILE*)(&rtx_stdout);

    printf("Initialize the RTX stdio.\n");
    printf("RTX stdin is not implemented.\n");

#elif USE_SIMICS_IO

    simics_stdin_create(&simics_stdin);
    simics_stdout_create(&simics_stdout);
    simics_stderr_create(&simics_stderr);

    stdin = (FILE*)(&simics_stdin);
    stdout = (FILE*)(&simics_stdout);
    stderr = (FILE*)(&simics_stderr);
    ssxout = (FILE*)(&simics_stdout);

    printf("Initialize the Simics stdio.\n");

#endif // I/O Configuration
}

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

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

#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.
    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);

    //Note: all interrupts are left in the masked state at this point
#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 owned by the 405 will not have a bit set in routeA
    owned_actual = ~oirrA;

    //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.
        SSX_PANIC(OCCHW_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);


    // Setup requires SCOM, which requires a timeout. Therefore we need to set
    // up a default timebase frequency, which may be overridden during
    // ssx_initialize().

    __ssx_timebase_frequency_hz = 600000000;
    __ssx_timebase_frequency_khz = 600000;
    __ssx_timebase_frequency_mhz = 600;

    // Set up I/O.  This is done early in the initialization so that
    // initialization drivers can use printk().

    io_setup();

    // TODO: enable once chip id support is present
#if 0
    // Cache the device identification and chip configuration
    _occhw_get_ids();
    _occhw_get_chip_configuration();
#endif

    // Set up the PLB arbiter

    plb_arbiter_setup();

    // If the MMU is enabled the base image MMU programming is set up, and the
    // MMU is activated.

#if PPC405_MMU_SUPPORT
    occhw_mmu_setup();
#endif

    // The Async drivers are initialized.
    async_initialize();
}
OpenPOWER on IntegriCloud