summaryrefslogtreecommitdiff
path: root/release/src/linux/linux/arch/mips/sgi-ip22/ip22-mc.c
blob: 1a632113c0e5819f85054ee33cf45ee9a2292fe5 (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
/*
 * ip22-mc.c: Routines for manipulating the INDY memory controller.
 *
 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes
 */

#include <linux/init.h>
#include <linux/kernel.h>

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

/* #define DEBUG_SGIMC */

#ifdef DEBUG_SGIMC
extern void prom_printf(char *fmt, ...);
#endif

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

#ifdef DEBUG_SGIMC
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";
	}
}
#endif

void __init sgimc_init(void)
{
	unsigned long tmpreg;

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

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


#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 0: Make sure we turn off the watchdog in case it's
	 *         still running (which might be the case after a
	 *         soft reboot).
	 */
	tmpreg = mcmisc_regs->cpuctrl0;
	tmpreg &= ~SGIMC_CCTRL0_WDOG;
	mcmisc_regs->cpuctrl0 = tmpreg;

	/* 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 */
			tmpreg |= SGIMC_GIOPARM_GFX64; 	/* GFX at 64 bits */
		}
	}
	mcmisc_regs->gioparm = tmpreg; /* poof */
}