~ubuntu-branches/ubuntu/maverick/u-boot-omap3/maverick

« back to all changes in this revision

Viewing changes to cpu/mpc85xx/mp.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2010-03-22 15:06:23 UTC
  • Revision ID: james.westby@ubuntu.com-20100322150623-i21g8rgiyl5dohag
Tags: upstream-2010.3git20100315
ImportĀ upstreamĀ versionĀ 2010.3git20100315

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2008-2010 Freescale Semiconductor, Inc.
 
3
 *
 
4
 * See file CREDITS for list of people who contributed to this
 
5
 * project.
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License as
 
9
 * published by the Free Software Foundation; either version 2 of
 
10
 * the License, or (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 
20
 * MA 02111-1307 USA
 
21
 */
 
22
 
 
23
#include <common.h>
 
24
#include <asm/processor.h>
 
25
#include <ioports.h>
 
26
#include <lmb.h>
 
27
#include <asm/io.h>
 
28
#include <asm/mmu.h>
 
29
#include <asm/fsl_law.h>
 
30
#include "mp.h"
 
31
 
 
32
DECLARE_GLOBAL_DATA_PTR;
 
33
 
 
34
u32 get_my_id()
 
35
{
 
36
        return mfspr(SPRN_PIR);
 
37
}
 
38
 
 
39
int cpu_reset(int nr)
 
40
{
 
41
        volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
 
42
        out_be32(&pic->pir, 1 << nr);
 
43
        /* the dummy read works around an errata on early 85xx MP PICs */
 
44
        (void)in_be32(&pic->pir);
 
45
        out_be32(&pic->pir, 0x0);
 
46
 
 
47
        return 0;
 
48
}
 
49
 
 
50
int cpu_status(int nr)
 
51
{
 
52
        u32 *table, id = get_my_id();
 
53
 
 
54
        if (nr == id) {
 
55
                table = (u32 *)get_spin_virt_addr();
 
56
                printf("table base @ 0x%p\n", table);
 
57
        } else {
 
58
                table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY;
 
59
                printf("Running on cpu %d\n", id);
 
60
                printf("\n");
 
61
                printf("table @ 0x%p\n", table);
 
62
                printf("   addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]);
 
63
                printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]);
 
64
                printf("   r3   - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]);
 
65
                printf("   r6   - 0x%08x\n", table[BOOT_ENTRY_R6_LOWER]);
 
66
        }
 
67
 
 
68
        return 0;
 
69
}
 
70
 
 
71
#ifdef CONFIG_FSL_CORENET
 
72
int cpu_disable(int nr)
 
73
{
 
74
        volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
 
75
 
 
76
        setbits_be32(&gur->coredisrl, 1 << nr);
 
77
 
 
78
        return 0;
 
79
}
 
80
#else
 
81
int cpu_disable(int nr)
 
82
{
 
83
        volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
 
84
 
 
85
        switch (nr) {
 
86
        case 0:
 
87
                setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0);
 
88
                break;
 
89
        case 1:
 
90
                setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1);
 
91
                break;
 
92
        default:
 
93
                printf("Invalid cpu number for disable %d\n", nr);
 
94
                return 1;
 
95
        }
 
96
 
 
97
        return 0;
 
98
}
 
99
#endif
 
100
 
 
101
static u8 boot_entry_map[4] = {
 
102
        0,
 
103
        BOOT_ENTRY_PIR,
 
104
        BOOT_ENTRY_R3_LOWER,
 
105
        BOOT_ENTRY_R6_LOWER,
 
106
};
 
107
 
 
108
int cpu_release(int nr, int argc, char *argv[])
 
109
{
 
110
        u32 i, val, *table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY;
 
111
        u64 boot_addr;
 
112
 
 
113
        if (nr == get_my_id()) {
 
114
                printf("Invalid to release the boot core.\n\n");
 
115
                return 1;
 
116
        }
 
117
 
 
118
        if (argc != 4) {
 
119
                printf("Invalid number of arguments to release.\n\n");
 
120
                return 1;
 
121
        }
 
122
 
 
123
        boot_addr = simple_strtoull(argv[0], NULL, 16);
 
124
 
 
125
        /* handle pir, r3, r6 */
 
126
        for (i = 1; i < 4; i++) {
 
127
                if (argv[i][0] != '-') {
 
128
                        u8 entry = boot_entry_map[i];
 
129
                        val = simple_strtoul(argv[i], NULL, 16);
 
130
                        table[entry] = val;
 
131
                }
 
132
        }
 
133
 
 
134
        table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32);
 
135
 
 
136
        /* ensure all table updates complete before final address write */
 
137
        eieio();
 
138
 
 
139
        table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff);
 
140
 
 
141
        return 0;
 
142
}
 
143
 
 
144
u32 determine_mp_bootpg(void)
 
145
{
 
146
        /* if we have 4G or more of memory, put the boot page at 4Gb-4k */
 
147
        if ((u64)gd->ram_size > 0xfffff000)
 
148
                return (0xfffff000);
 
149
 
 
150
        return (gd->ram_size - 4096);
 
151
}
 
152
 
 
153
ulong get_spin_phys_addr(void)
 
154
{
 
155
        extern ulong __secondary_start_page;
 
156
        extern ulong __spin_table;
 
157
 
 
158
        return (determine_mp_bootpg() +
 
159
                (ulong)&__spin_table - (ulong)&__secondary_start_page);
 
160
}
 
161
 
 
162
ulong get_spin_virt_addr(void)
 
163
{
 
164
        extern ulong __secondary_start_page;
 
165
        extern ulong __spin_table;
 
166
 
 
167
        return (CONFIG_BPTR_VIRT_ADDR +
 
168
                (ulong)&__spin_table - (ulong)&__secondary_start_page);
 
169
}
 
170
 
 
171
#ifdef CONFIG_FSL_CORENET
 
172
static void plat_mp_up(unsigned long bootpg)
 
173
{
 
174
        u32 up, cpu_up_mask, whoami;
 
175
        u32 *table = (u32 *)get_spin_virt_addr();
 
176
        volatile ccsr_gur_t *gur;
 
177
        volatile ccsr_local_t *ccm;
 
178
        volatile ccsr_rcpm_t *rcpm;
 
179
        volatile ccsr_pic_t *pic;
 
180
        int timeout = 10;
 
181
        u32 nr_cpus;
 
182
        struct law_entry e;
 
183
 
 
184
        gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
 
185
        ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
 
186
        rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR);
 
187
        pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
 
188
 
 
189
        nr_cpus = ((in_be32(&pic->frr) >> 8) & 0xff) + 1;
 
190
 
 
191
        whoami = in_be32(&pic->whoami);
 
192
        cpu_up_mask = 1 << whoami;
 
193
        out_be32(&ccm->bstrl, bootpg);
 
194
 
 
195
        e = find_law(bootpg);
 
196
        out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | LAW_SIZE_4K);
 
197
 
 
198
        /* readback to sync write */
 
199
        in_be32(&ccm->bstrar);
 
200
 
 
201
        /* disable time base at the platform */
 
202
        out_be32(&rcpm->ctbenrl, cpu_up_mask);
 
203
 
 
204
        /* release the hounds */
 
205
        up = ((1 << nr_cpus) - 1);
 
206
        out_be32(&gur->brrl, up);
 
207
 
 
208
        /* wait for everyone */
 
209
        while (timeout) {
 
210
                int i;
 
211
                for (i = 0; i < nr_cpus; i++) {
 
212
                        if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
 
213
                                cpu_up_mask |= (1 << i);
 
214
                };
 
215
 
 
216
                if ((cpu_up_mask & up) == up)
 
217
                        break;
 
218
 
 
219
                udelay(100);
 
220
                timeout--;
 
221
        }
 
222
 
 
223
        if (timeout == 0)
 
224
                printf("CPU up timeout. CPU up mask is %x should be %x\n",
 
225
                        cpu_up_mask, up);
 
226
 
 
227
        /* enable time base at the platform */
 
228
        out_be32(&rcpm->ctbenrl, 0);
 
229
        mtspr(SPRN_TBWU, 0);
 
230
        mtspr(SPRN_TBWL, 0);
 
231
        out_be32(&rcpm->ctbenrl, (1 << nr_cpus) - 1);
 
232
 
 
233
#ifdef CONFIG_MPC8xxx_DISABLE_BPTR
 
234
        /*
 
235
         * Disabling Boot Page Translation allows the memory region 0xfffff000
 
236
         * to 0xffffffff to be used normally.  Leaving Boot Page Translation
 
237
         * enabled remaps 0xfffff000 to SDRAM which makes that memory region
 
238
         * unusable for normal operation but it does allow OSes to easily
 
239
         * reset a processor core to put it back into U-Boot's spinloop.
 
240
         */
 
241
        clrbits_be32(&ecm->bptr, 0x80000000);
 
242
#endif
 
243
}
 
244
#else
 
245
static void plat_mp_up(unsigned long bootpg)
 
246
{
 
247
        u32 up, cpu_up_mask, whoami;
 
248
        u32 *table = (u32 *)get_spin_virt_addr();
 
249
        volatile u32 bpcr;
 
250
        volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
 
251
        volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
 
252
        volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR);
 
253
        u32 devdisr;
 
254
        int timeout = 10;
 
255
 
 
256
        whoami = in_be32(&pic->whoami);
 
257
        out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12));
 
258
 
 
259
        /* disable time base at the platform */
 
260
        devdisr = in_be32(&gur->devdisr);
 
261
        if (whoami)
 
262
                devdisr |= MPC85xx_DEVDISR_TB0;
 
263
        else
 
264
                devdisr |= MPC85xx_DEVDISR_TB1;
 
265
        out_be32(&gur->devdisr, devdisr);
 
266
 
 
267
        /* release the hounds */
 
268
        up = ((1 << cpu_numcores()) - 1);
 
269
        bpcr = in_be32(&ecm->eebpcr);
 
270
        bpcr |= (up << 24);
 
271
        out_be32(&ecm->eebpcr, bpcr);
 
272
        asm("sync; isync; msync");
 
273
 
 
274
        cpu_up_mask = 1 << whoami;
 
275
        /* wait for everyone */
 
276
        while (timeout) {
 
277
                int i;
 
278
                for (i = 0; i < cpu_numcores(); i++) {
 
279
                        if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
 
280
                                cpu_up_mask |= (1 << i);
 
281
                };
 
282
 
 
283
                if ((cpu_up_mask & up) == up)
 
284
                        break;
 
285
 
 
286
                udelay(100);
 
287
                timeout--;
 
288
        }
 
289
 
 
290
        if (timeout == 0)
 
291
                printf("CPU up timeout. CPU up mask is %x should be %x\n",
 
292
                        cpu_up_mask, up);
 
293
 
 
294
        /* enable time base at the platform */
 
295
        if (whoami)
 
296
                devdisr |= MPC85xx_DEVDISR_TB1;
 
297
        else
 
298
                devdisr |= MPC85xx_DEVDISR_TB0;
 
299
        out_be32(&gur->devdisr, devdisr);
 
300
        mtspr(SPRN_TBWU, 0);
 
301
        mtspr(SPRN_TBWL, 0);
 
302
 
 
303
        devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1);
 
304
        out_be32(&gur->devdisr, devdisr);
 
305
 
 
306
#ifdef CONFIG_MPC8xxx_DISABLE_BPTR
 
307
        /*
 
308
         * Disabling Boot Page Translation allows the memory region 0xfffff000
 
309
         * to 0xffffffff to be used normally.  Leaving Boot Page Translation
 
310
         * enabled remaps 0xfffff000 to SDRAM which makes that memory region
 
311
         * unusable for normal operation but it does allow OSes to easily
 
312
         * reset a processor core to put it back into U-Boot's spinloop.
 
313
         */
 
314
        clrbits_be32(&ecm->bptr, 0x80000000);
 
315
#endif
 
316
}
 
317
#endif
 
318
 
 
319
void cpu_mp_lmb_reserve(struct lmb *lmb)
 
320
{
 
321
        u32 bootpg = determine_mp_bootpg();
 
322
 
 
323
        lmb_reserve(lmb, bootpg, 4096);
 
324
}
 
325
 
 
326
void setup_mp(void)
 
327
{
 
328
        extern ulong __secondary_start_page;
 
329
        extern ulong __bootpg_addr;
 
330
        ulong fixup = (ulong)&__secondary_start_page;
 
331
        u32 bootpg = determine_mp_bootpg();
 
332
 
 
333
        /* Store the bootpg's SDRAM address for use by secondary CPU cores */
 
334
        __bootpg_addr = bootpg;
 
335
 
 
336
        /* look for the tlb covering the reset page, there better be one */
 
337
        int i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1);
 
338
 
 
339
        /* we found a match */
 
340
        if (i != -1) {
 
341
                /* map reset page to bootpg so we can copy code there */
 
342
                disable_tlb(i);
 
343
 
 
344
                set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */
 
345
                        MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */
 
346
                        0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */
 
347
 
 
348
                memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096);
 
349
 
 
350
                plat_mp_up(bootpg);
 
351
        } else {
 
352
                puts("WARNING: No reset page TLB. "
 
353
                        "Skipping secondary core setup\n");
 
354
        }
 
355
}