summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm63xx/files/arch/mips/bcm963xx/setup.c
blob: 70c6ebe6013cc2661dca3d5f03959db543fe755e (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
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/*
<:copyright-gpl 
 Copyright 2002 Broadcom Corp. All Rights Reserved. 
 
 This program is free software; you can distribute it and/or modify it 
 under the terms of the GNU General Public License (Version 2) as 
 published by the Free Software Foundation. 
 
 This program is distributed in the hope it will be useful, but WITHOUT 
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
 for more details. 
 
 You should have received a copy of the GNU General Public License along 
 with this program; if not, write to the Free Software Foundation, Inc., 
 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
:>
*/
/*
 * Generic setup routines for Broadcom 963xx MIPS boards
 */

#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/console.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/bootmem.h>

#include <asm/addrspace.h>
#include <asm/bcache.h>
#include <asm/irq.h>
#include <asm/time.h>
#include <asm/reboot.h>
#include <asm/gdb-stub.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
#include <asm/mach-bcm963xx/bootloaders.h>

extern void brcm_time_init(void);
extern int boot_loader_type;

#include <linux/pci.h>
#include <linux/delay.h>
#include <bcm_map_part.h>
#include <6348_map_part.h>
#include <bcmpci.h>

static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);

/* This function should be in a board specific directory.  For now,
 * assume that all boards that include this file use a Broadcom chip
 * with a soft reset bit in the PLL control register.
 */
static void brcm_machine_restart(char *command)
{
	const unsigned long ulSoftReset = 0x00000001;
	unsigned long *pulPllCtrl = (unsigned long *) 0xfffe0008;
	*pulPllCtrl |= ulSoftReset;
}

static void brcm_machine_halt(void)
{
	printk("System halted\n");
	while (1);
}

static void mpi_SetLocalPciConfigReg(uint32 reg, uint32 value)
{
    /* write index then value */
    mpi->pcicfgcntrl = PCI_CFG_REG_WRITE_EN + reg;;
    mpi->pcicfgdata = value;
}

static uint32 mpi_GetLocalPciConfigReg(uint32 reg)
{
    /* write index then get value */
    mpi->pcicfgcntrl = PCI_CFG_REG_WRITE_EN + reg;;
    return mpi->pcicfgdata;
}

/*
 * mpi_ResetPcCard: Set/Reset the PcCard
 */
static void mpi_ResetPcCard(int cardtype, BOOL bReset)
{
    if (cardtype == MPI_CARDTYPE_NONE) {
        return;
    }

    if (cardtype == MPI_CARDTYPE_CARDBUS) {
        bReset = ! bReset;
    }

    if (bReset) {
        mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & ~PCCARD_CARD_RESET);
    } else {
        mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 | PCCARD_CARD_RESET);
    }
}

/*
 * mpi_ConfigCs: Configure an MPI/EBI chip select
 */
static void mpi_ConfigCs(uint32 cs, uint32 base, uint32 size, uint32 flags)
{
    mpi->cs[cs].base = ((base & 0x1FFFFFFF) | size);
    mpi->cs[cs].config = flags;
}

/*
 * mpi_InitPcmciaSpace
 */
static void mpi_InitPcmciaSpace(void)
{
    // ChipSelect 4 controls PCMCIA Memory accesses
    mpi_ConfigCs(PCMCIA_COMMON_BASE, pcmciaMem, EBI_SIZE_1M, (EBI_WORD_WIDE|EBI_ENABLE));
    // ChipSelect 5 controls PCMCIA Attribute accesses
    mpi_ConfigCs(PCMCIA_ATTRIBUTE_BASE, pcmciaAttr, EBI_SIZE_1M, (EBI_WORD_WIDE|EBI_ENABLE));
    // ChipSelect 6 controls PCMCIA I/O accesses
    mpi_ConfigCs(PCMCIA_IO_BASE, pcmciaIo, EBI_SIZE_64K, (EBI_WORD_WIDE|EBI_ENABLE));

    mpi->pcmcia_cntl2 = ((PCMCIA_ATTR_ACTIVE << RW_ACTIVE_CNT_BIT) | 
                         (PCMCIA_ATTR_INACTIVE << INACTIVE_CNT_BIT) | 
                         (PCMCIA_ATTR_CE_SETUP << CE_SETUP_CNT_BIT) | 
                         (PCMCIA_ATTR_CE_HOLD << CE_HOLD_CNT_BIT));

    mpi->pcmcia_cntl2 |= (PCMCIA_HALFWORD_EN | PCMCIA_BYTESWAP_DIS);
}

/*
 * cardtype_vcc_detect: PC Card's card detect and voltage sense connection
 * 
 *   CD1#/      CD2#/     VS1#/     VS2#/    Card       Initial Vcc
 *  CCD1#      CCD2#     CVS1      CVS2      Type
 *
 *   GND        GND       open      open     16-bit     5 vdc
 *
 *   GND        GND       GND       open     16-bit     3.3 vdc
 *
 *   GND        GND       open      GND      16-bit     x.x vdc
 *
 *   GND        GND       GND       GND      16-bit     3.3 & x.x vdc
 *
 *====================================================================
 *
 *   CVS1       GND       CCD1#     open     CardBus    3.3 vdc
 *
 *   GND        CVS2      open      CCD2#    CardBus    x.x vdc
 *
 *   GND        CVS1      CCD2#     open     CardBus    y.y vdc
 *
 *   GND        CVS2      GND       CCD2#    CardBus    3.3 & x.x vdc
 *
 *   CVS2       GND       open      CCD1#    CardBus    x.x & y.y vdc
 *
 *   GND        CVS1      CCD2#     open     CardBus    3.3, x.x & y.y vdc
 *
 */
static int cardtype_vcc_detect(void)
{
    uint32 data32;
    int cardtype;

    cardtype = MPI_CARDTYPE_NONE;
    mpi->pcmcia_cntl1 = 0x0000A000; // Turn on the output enables and drive
                                        // the CVS pins to 0.
    data32 = mpi->pcmcia_cntl1;
    switch (data32 & 0x00000003)  // Test CD1# and CD2#, see if card is plugged in.
    {
    case 0x00000003:  // No Card is in the slot.
        printk("mpi: No Card is in the PCMCIA slot\n");
        break;

    case 0x00000002:  // Partial insertion, No CD2#.
        printk("mpi: Card in the PCMCIA slot partial insertion, no CD2 signal\n");
        break;

    case 0x00000001:  // Partial insertion, No CD1#.
        printk("mpi: Card in the PCMCIA slot partial insertion, no CD1 signal\n");
        break;

    case 0x00000000:
        mpi->pcmcia_cntl1 = 0x0000A0C0; // Turn off the CVS output enables and
                                        // float the CVS pins.
        mdelay(1);
        data32 = mpi->pcmcia_cntl1;
        // Read the Register.
        switch (data32 & 0x0000000C)  // See what is on the CVS pins.
        {
        case 0x00000000: // CVS1 and CVS2 are tied to ground, only 1 option.
            printk("mpi: Detected 3.3 & x.x 16-bit PCMCIA card\n");
            cardtype = MPI_CARDTYPE_PCMCIA;
            break;
          
        case 0x00000004: // CVS1 is open or tied to CCD1/CCD2 and CVS2 is tied to ground.
                         // 2 valid voltage options.
        switch (data32 & 0x00000003)  // Test the values of CCD1 and CCD2.
        {
            case 0x00000003:  // CCD1 and CCD2 are tied to 1 of the CVS pins.
                              // This is not a valid combination.
                printk("mpi: Unknown card plugged into slot\n"); 
                break;
      
            case 0x00000002:  // CCD2 is tied to either CVS1 or CVS2. 
                mpi->pcmcia_cntl1 = 0x0000A080; // Drive CVS1 to a 0.
                mdelay(1);
                data32 = mpi->pcmcia_cntl1;
                if (data32 & 0x00000002) { // CCD2 is tied to CVS2, not valid.
                    printk("mpi: Unknown card plugged into slot\n"); 
                } else {                   // CCD2 is tied to CVS1.
                    printk("mpi: Detected 3.3, x.x and y.y Cardbus card\n");
                    cardtype = MPI_CARDTYPE_CARDBUS;
                }
                break;
                
            case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
                             // This is not a valid combination.
                printk("mpi: Unknown card plugged into slot\n"); 
                break;
                
            case 0x00000000:  // CCD1 and CCD2 are tied to ground.
                printk("mpi: Detected x.x vdc 16-bit PCMCIA card\n");
                cardtype = MPI_CARDTYPE_PCMCIA;
                break;
            }
            break;
          
        case 0x00000008: // CVS2 is open or tied to CCD1/CCD2 and CVS1 is tied to ground.
                         // 2 valid voltage options.
            switch (data32 & 0x00000003)  // Test the values of CCD1 and CCD2.
            {
            case 0x00000003:  // CCD1 and CCD2 are tied to 1 of the CVS pins.
                              // This is not a valid combination.
                printk("mpi: Unknown card plugged into slot\n"); 
                break;
      
            case 0x00000002:  // CCD2 is tied to either CVS1 or CVS2.
                mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
                mdelay(1);
                data32 = mpi->pcmcia_cntl1;
                if (data32 & 0x00000002) { // CCD2 is tied to CVS1, not valid.
                    printk("mpi: Unknown card plugged into slot\n"); 
                } else {// CCD2 is tied to CVS2.
                    printk("mpi: Detected 3.3 and x.x Cardbus card\n");
                    cardtype = MPI_CARDTYPE_CARDBUS;
                }
                break;

            case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
                             // This is not a valid combination.
                printk("mpi: Unknown card plugged into slot\n"); 
                break;

            case 0x00000000:  // CCD1 and CCD2 are tied to ground.
                cardtype = MPI_CARDTYPE_PCMCIA;
                printk("mpi: Detected 3.3 vdc 16-bit PCMCIA card\n");
                break;
            }
            break;
          
        case 0x0000000C:  // CVS1 and CVS2 are open or tied to CCD1/CCD2.
                          // 5 valid voltage options.
      
            switch (data32 & 0x00000003)  // Test the values of CCD1 and CCD2.
            {
            case 0x00000003:  // CCD1 and CCD2 are tied to 1 of the CVS pins.
                              // This is not a valid combination.
                printk("mpi: Unknown card plugged into slot\n"); 
                break;
      
            case 0x00000002:  // CCD2 is tied to either CVS1 or CVS2.
                              // CCD1 is tied to ground.
                mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
                mdelay(1);
                data32 = mpi->pcmcia_cntl1;
                if (data32 & 0x00000002) {  // CCD2 is tied to CVS1.
                    printk("mpi: Detected y.y vdc Cardbus card\n");
                } else {                    // CCD2 is tied to CVS2.
                    printk("mpi: Detected x.x vdc Cardbus card\n");
                }
                cardtype = MPI_CARDTYPE_CARDBUS;
                break;
      
            case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
                             // CCD2 is tied to ground.
      
                mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
                mdelay(1);
                data32 = mpi->pcmcia_cntl1;
                if (data32 & 0x00000001) {// CCD1 is tied to CVS1.
                    printk("mpi: Detected 3.3 vdc Cardbus card\n");
                } else {                    // CCD1 is tied to CVS2.
                    printk("mpi: Detected x.x and y.y Cardbus card\n");
                }
                cardtype = MPI_CARDTYPE_CARDBUS;
                break;
      
            case 0x00000000:  // CCD1 and CCD2 are tied to ground.
                cardtype = MPI_CARDTYPE_PCMCIA;
                printk("mpi: Detected 5 vdc 16-bit PCMCIA card\n");
                break;
            }
            break;
      
        default:
            printk("mpi: Unknown card plugged into slot\n"); 
            break;
        
        }
    }
    return cardtype;
}

/*
 * mpi_DetectPcCard: Detect the plugged in PC-Card
 * Return: < 0 => Unknown card detected
 *         0 => No card detected
 *         1 => 16-bit card detected
 *         2 => 32-bit CardBus card detected
 */
static int mpi_DetectPcCard(void)
{
    int cardtype;

    cardtype = cardtype_vcc_detect();
    switch(cardtype) {
        case MPI_CARDTYPE_PCMCIA:
            mpi->pcmcia_cntl1 &= ~0x0000e000; // disable enable bits
            //mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & ~PCCARD_CARD_RESET);
            mpi->pcmcia_cntl1 |= (PCMCIA_ENABLE | PCMCIA_GPIO_ENABLE);
            mpi_InitPcmciaSpace();
            mpi_ResetPcCard(cardtype, FALSE);
            // Hold card in reset for 10ms
            mdelay(10);
            mpi_ResetPcCard(cardtype, TRUE);
            // Let card come out of reset
            mdelay(100);
            break;
        case MPI_CARDTYPE_CARDBUS:
            // 8 => CardBus Enable
            // 1 => PCI Slot Number
            // C => Float VS1 & VS2
            mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & 0xFFFF0000) | 
                                CARDBUS_ENABLE | 
                                (CARDBUS_SLOT << 8)| 
                                VS2_OEN |
                                VS1_OEN;
            /* access to this memory window will be to/from CardBus */
            mpi->l2pmremap1 |= CARDBUS_MEM;

            // Need to reset the Cardbus Card. There's no CardManager to do this, 
            // and we need to be ready for PCI configuration. 
            mpi_ResetPcCard(cardtype, FALSE);
            // Hold card in reset for 10ms
            mdelay(10);
            mpi_ResetPcCard(cardtype, TRUE);
            // Let card come out of reset
            mdelay(100);
            break;
        default:
            break;
    }
    return cardtype;
}

static int mpi_init(void)
{
	unsigned long data;
    	unsigned int chipid, chiprev, sdramsize;

	printk("Broadcom BCM963xx MPI\n");
    	chipid  = (PERF->RevID & 0xFFFF0000) >> 16;
    	chiprev = (PERF->RevID & 0xFF);

	if (boot_loader_type == BOOT_LOADER_CFE)
    		sdramsize = boot_mem_map.map[0].size;
	else
		sdramsize = 0x01000000; 
    	/*
     	 * Init the pci interface 
     	 */
    	data = GPIO->GPIOMode; // GPIO mode register
    	data |= GROUP2_PCI | GROUP1_MII_PCCARD; // PCI internal arbiter + Cardbus
    	GPIO->GPIOMode = data; // PCI internal arbiter

    /*
     * In the BCM6348 CardBus support is defaulted to Slot 0
     * because there is no external IDSEL for CardBus.  To disable
     * the CardBus and allow a standard PCI card in Slot 0 
     * set the cbus_idsel field to 0x1f.
    */
    /*
    uData = mpi->pcmcia_cntl1;
    uData |= CARDBUS_IDSEL;
    mpi->pcmcia_cntl1 = uData;
    */
    // Setup PCI I/O Window range. Give 64K to PCI I/O
    mpi->l2piorange = ~(BCM_PCI_IO_SIZE_64KB-1);
    // UBUS to PCI I/O base address 
    mpi->l2piobase = BCM_PCI_IO_BASE & BCM_PCI_ADDR_MASK;
    // UBUS to PCI I/O Window remap
    mpi->l2pioremap = (BCM_PCI_IO_BASE | MEM_WINDOW_EN);

    // enable PCI related GPIO pins and data swap between system and PCI bus
    mpi->locbuscntrl = (EN_PCI_GPIO | DIR_U2P_NOSWAP);

    /* Enable 6348 BusMaster and Memory access mode */
    data = mpi_GetLocalPciConfigReg(PCI_COMMAND);
    data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
    mpi_SetLocalPciConfigReg(PCI_COMMAND, data);

    /* Configure two 16 MByte PCI to System memory regions. */
    /* These memory regions are used when PCI device is a bus master */
    /* Accesses to the SDRAM from PCI bus will be "byte swapped" for this region */
    mpi_SetLocalPciConfigReg(PCI_BASE_ADDRESS_3, BCM_HOST_MEM_SPACE1);
    mpi->sp0remap = 0x0;

    /* Accesses to the SDRAM from PCI bus will not be "byte swapped" for this region */
    mpi_SetLocalPciConfigReg(PCI_BASE_ADDRESS_4, BCM_HOST_MEM_SPACE2);
    mpi->sp1remap = 0x0;
    mpi->pcimodesel |= (PCI_BAR2_NOSWAP | 0x40);

    if ((chipid == 0x6348) && (chiprev == 0xb0)) {
        mpi->sp0range = ~(sdramsize-1);
        mpi->sp1range = ~(sdramsize-1);
    }
    /*
     * Change 6348 PCI Cfg Reg. offset 0x40 to PCI memory read retry count infinity
     * by set 0 in bit 8~15.  This resolve read Bcm4306 srom return 0xffff in
     * first read.
     */
    data = mpi_GetLocalPciConfigReg(BRCM_PCI_CONFIG_TIMER);
    data &= ~BRCM_PCI_CONFIG_TIMER_RETRY_MASK;
    data |= 0x00000080;
    mpi_SetLocalPciConfigReg(BRCM_PCI_CONFIG_TIMER, data);

    /* enable pci interrupt */
    mpi->locintstat |= (EXT_PCI_INT << 16);

    mpi_DetectPcCard();

    ioport_resource.start = BCM_PCI_IO_BASE;
    ioport_resource.end = BCM_PCI_IO_BASE + BCM_PCI_IO_SIZE_64KB;

#if defined(CONFIG_USB)
    PERF->blkEnables |= USBH_CLK_EN;
    mdelay(100);
    *USBH_NON_OHCI = NON_OHCI_BYTE_SWAP;
#endif

    return 0;
}

void __init plat_mem_setup(void)
{
	_machine_restart = brcm_machine_restart;
	_machine_halt = brcm_machine_halt;
	pm_power_off = brcm_machine_halt;

	board_time_init = brcm_time_init;

    	/* mpi initialization */
    	mpi_init();
}