summaryrefslogtreecommitdiffstats
path: root/arch/mips64/sgi-ip22/ip22-mc.c
blob: e8b430fb25c1adfe44a0ceddcdbfc690d302a2f1 (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
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
 * Copyright (C) 2001 Ralf Baechle (ralf@gnu.org)
 */
#include <linux/init.h>
#include <linux/kernel.h>

#include <asm/addrspace.h>
#include <asm/ptrace.h>
#include <asm/sgi/sgimc.h>
#include <asm/sgi/sgihpc.h>

/* #define DEBUG_SGIMC */

struct sgimc_misc_ctrl *mcmisc_regs;
u32 *rpsscounter;
struct sgimc_dma_ctrl *dmactrlregs;

static inline char *mconfig_string(unsigned long val)
{
	switch(val & SGIMC_MCONFIG_RMASK) {
	case SGIMC_MCONFIG_FOURMB:
		return "4MB";

	case SGIMC_MCONFIG_EIGHTMB:
		return "8MB";

	case SGIMC_MCONFIG_SXTEENMB:
		return "16MB";

	case SGIMC_MCONFIG_TTWOMB:
		return "32MB";

	case SGIMC_MCONFIG_SFOURMB:
		return "64MB";

	case SGIMC_MCONFIG_OTEIGHTMB:
		return "128MB";

	default:
		return "wheee, unknown";
	};
}

void __init sgimc_init(void)
{
	unsigned long tmpreg;

	mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
	rpsscounter = (u32 *) (KSEG1 + 0x1fa01004);
	dmactrlregs = (struct sgimc_dma_ctrl *) (KSEG1+0x1fa02000);

	printk("MC: SGI memory controller Revision %d\n",
	       (int) mcmisc_regs->systemid & SGIMC_SYSID_MASKREV);

#if 0 /* XXX Until I figure out what this bit really indicates XXX */
	/* XXX Is this systemid bit reliable? */
	if(mcmisc_regs->systemid & SGIMC_SYSID_EPRESENT) {
		EISA_bus = 1;
		printk("with EISA\n");
	} else {
		EISA_bus = 0;
		printk("no EISA\n");
	}
#endif

#ifdef DEBUG_SGIMC
	prom_printf("sgimc_init: memconfig0<%s> mconfig1<%s>\n",
		    mconfig_string(mcmisc_regs->mconfig0),
		    mconfig_string(mcmisc_regs->mconfig1));

	prom_printf("mcdump: cpuctrl0<%08lx> cpuctrl1<%08lx>\n",
		    mcmisc_regs->cpuctrl0, mcmisc_regs->cpuctrl1);
	prom_printf("mcdump: divider<%08lx>, gioparm<%04x>\n",
		    mcmisc_regs->divider, mcmisc_regs->gioparm);
#endif

	/* Place the MC into a known state.  This must be done before
	 * interrupts are first enabled etc.
	 */

	/* Step 1: The CPU/GIO error status registers will not latch
	 *         up a new error status until the register has been
	 *         cleared by the cpu.  These status registers are
	 *         cleared by writing any value to them.
	 */
	mcmisc_regs->cstat = mcmisc_regs->gstat = 0;

	/* Step 2: Enable all parity checking in cpu control register
	 *         zero.
	 */
	tmpreg = mcmisc_regs->cpuctrl0;
	tmpreg |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
		   SGIMC_CCTRL0_R4KNOCHKPARR);
	mcmisc_regs->cpuctrl0 = tmpreg;

	/* Step 3: Setup the MC write buffer depth, this is controlled
	 *         in cpu control register 1 in the lower 4 bits.
	 */
	tmpreg = mcmisc_regs->cpuctrl1;
	tmpreg &= ~0xf;
	tmpreg |= 0xd;
	mcmisc_regs->cpuctrl1 = tmpreg;

	/* Step 4: Initialize the RPSS divider register to run as fast
	 *         as it can correctly operate.  The register is laid
	 *         out as follows:
	 *
	 *         ----------------------------------------
	 *         |  RESERVED  |   INCREMENT   | DIVIDER |
	 *         ----------------------------------------
	 *          31        16 15            8 7       0
	 *
	 *         DIVIDER determines how often a 'tick' happens,
	 *         INCREMENT determines by how the RPSS increment
	 *         registers value increases at each 'tick'. Thus,
	 *         for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101
	 */
	mcmisc_regs->divider = 0x101;

	/* Step 5: Initialize GIO64 arbitrator configuration register.
	 *
	 * NOTE: If you dork with startup code the HPC init code in
	 *       sgihpc_init() must run before us because of how we
	 *       need to know Guiness vs. FullHouse and the board
	 *       revision on this machine.  You have been warned.
	 */

	/* First the basic invariants across all gio64 implementations. */
	tmpreg = SGIMC_GIOPARM_HPC64;    /* All 1st HPC's interface at 64bits. */
	tmpreg |= SGIMC_GIOPARM_ONEBUS;  /* Only one physical GIO bus exists. */

	if(sgi_guiness) {
		/* Guiness specific settings. */
		tmpreg |= SGIMC_GIOPARM_EISA64;     /* MC talks to EISA at 64bits */
		tmpreg |= SGIMC_GIOPARM_MASTEREISA; /* EISA bus can act as master */
	} else {
		/* Fullhouse specific settings. */
		if(sgi_boardid < 2) {
			tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC at 64bits */
			tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp0 pipelines */
			tmpreg |= SGIMC_GIOPARM_MASTEREXP1;/* exp1 masters */
			tmpreg |= SGIMC_GIOPARM_RTIMEEXP0; /* exp0 is realtime */
		} else {
			tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC 64bits */
			tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp[01] pipelined */
			tmpreg |= SGIMC_GIOPARM_PLINEEXP1;
			tmpreg |= SGIMC_GIOPARM_MASTEREISA;/* EISA masters */
			/* someone forgot this poor little guy... */
			tmpreg |= SGIMC_GIOPARM_GFX64; 	/* GFX at 64 bits */
		}
	}
	mcmisc_regs->gioparm = tmpreg; /* poof */
}