1/*
2 * ip22-mc.c: Routines for manipulating the INDY memory controller.
3 *
4 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
5 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes
6 */
7
8#include <linux/init.h>
9#include <linux/kernel.h>
10
11#include <asm/addrspace.h>
12#include <asm/ptrace.h>
13#include <asm/sgialib.h>
14#include <asm/sgi/sgimc.h>
15#include <asm/sgi/sgihpc.h>
16
17/* #define DEBUG_SGIMC */
18
19#ifdef DEBUG_SGIMC
20extern void prom_printf(char *fmt, ...);
21#endif
22
23struct sgimc_misc_ctrl *mcmisc_regs;
24struct sgimc_dma_ctrl *dmactrlregs;
25u32 *rpsscounter;
26
27#ifdef DEBUG_SGIMC
28static inline char *mconfig_string(unsigned long val)
29{
30	switch(val & SGIMC_MCONFIG_RMASK) {
31	case SGIMC_MCONFIG_FOURMB:
32		return "4MB";
33
34	case SGIMC_MCONFIG_EIGHTMB:
35		return "8MB";
36
37	case SGIMC_MCONFIG_SXTEENMB:
38		return "16MB";
39
40	case SGIMC_MCONFIG_TTWOMB:
41		return "32MB";
42
43	case SGIMC_MCONFIG_SFOURMB:
44		return "64MB";
45
46	case SGIMC_MCONFIG_OTEIGHTMB:
47		return "128MB";
48
49	default:
50		return "wheee, unknown";
51	}
52}
53#endif
54
55void __init sgimc_init(void)
56{
57	unsigned long tmpreg;
58
59	mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
60	rpsscounter = (unsigned int *)(KSEG1+0x1fa01004);
61	dmactrlregs = (struct sgimc_dma_ctrl *)(KSEG1+0x1fa02000);
62
63	printk(KERN_INFO "MC: SGI memory controller Revision %d\n",
64	       (int) mcmisc_regs->systemid & SGIMC_SYSID_MASKREV);
65
66
67#ifdef DEBUG_SGIMC
68	prom_printf("sgimc_init: memconfig0<%s> mconfig1<%s>\n",
69		    mconfig_string(mcmisc_regs->mconfig0),
70		    mconfig_string(mcmisc_regs->mconfig1));
71
72	prom_printf("mcdump: cpuctrl0<%08lx> cpuctrl1<%08lx>\n",
73		    mcmisc_regs->cpuctrl0, mcmisc_regs->cpuctrl1);
74	prom_printf("mcdump: divider<%08lx>, gioparm<%04x>\n",
75		    mcmisc_regs->divider, mcmisc_regs->gioparm);
76#endif
77
78	/* Place the MC into a known state.  This must be done before
79	 * interrupts are first enabled etc.
80	 */
81
82	/* Step 0: Make sure we turn off the watchdog in case it's
83	 *         still running (which might be the case after a
84	 *         soft reboot).
85	 */
86	tmpreg = mcmisc_regs->cpuctrl0;
87	tmpreg &= ~SGIMC_CCTRL0_WDOG;
88	mcmisc_regs->cpuctrl0 = tmpreg;
89
90	/* Step 1: The CPU/GIO error status registers will not latch
91	 *         up a new error status until the register has been
92	 *         cleared by the cpu.  These status registers are
93	 *         cleared by writing any value to them.
94	 */
95	mcmisc_regs->cstat = mcmisc_regs->gstat = 0;
96
97	/* Step 2: Enable all parity checking in cpu control register
98	 *         zero.
99	 */
100	tmpreg = mcmisc_regs->cpuctrl0;
101	tmpreg |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
102		   SGIMC_CCTRL0_R4KNOCHKPARR);
103	mcmisc_regs->cpuctrl0 = tmpreg;
104
105	/* Step 3: Setup the MC write buffer depth, this is controlled
106	 *         in cpu control register 1 in the lower 4 bits.
107	 */
108	tmpreg = mcmisc_regs->cpuctrl1;
109	tmpreg &= ~0xf;
110	tmpreg |= 0xd;
111	mcmisc_regs->cpuctrl1 = tmpreg;
112
113	/* Step 4: Initialize the RPSS divider register to run as fast
114	 *         as it can correctly operate.  The register is laid
115	 *         out as follows:
116	 *
117	 *         ----------------------------------------
118	 *         |  RESERVED  |   INCREMENT   | DIVIDER |
119	 *         ----------------------------------------
120	 *          31        16 15            8 7       0
121	 *
122	 *         DIVIDER determines how often a 'tick' happens,
123	 *         INCREMENT determines by how the RPSS increment
124	 *         registers value increases at each 'tick'. Thus,
125	 *         for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101
126	 */
127	mcmisc_regs->divider = 0x101;
128
129	/* Step 5: Initialize GIO64 arbitrator configuration register.
130	 *
131	 * NOTE: If you dork with startup code the HPC init code in
132	 *       sgihpc_init() must run before us because of how we
133	 *       need to know Guiness vs. FullHouse and the board
134	 *       revision on this machine.  You have been warned.
135	 */
136
137	/* First the basic invariants across all GIO64 implementations. */
138	tmpreg = SGIMC_GIOPARM_HPC64;    /* All 1st HPC's interface at 64bits. */
139	tmpreg |= SGIMC_GIOPARM_ONEBUS;  /* Only one physical GIO bus exists. */
140
141	if(sgi_guiness) {
142		/* Guiness specific settings. */
143		tmpreg |= SGIMC_GIOPARM_EISA64;     /* MC talks to EISA at 64bits */
144		tmpreg |= SGIMC_GIOPARM_MASTEREISA; /* EISA bus can act as master */
145	} else {
146		/* Fullhouse specific settings. */
147		if(sgi_boardid < 2) {
148			tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC at 64bits */
149			tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp0 pipelines */
150			tmpreg |= SGIMC_GIOPARM_MASTEREXP1;/* exp1 masters */
151			tmpreg |= SGIMC_GIOPARM_RTIMEEXP0; /* exp0 is realtime */
152		} else {
153			tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC 64bits */
154			tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp[01] pipelined */
155			tmpreg |= SGIMC_GIOPARM_PLINEEXP1;
156			tmpreg |= SGIMC_GIOPARM_MASTEREISA;/* EISA masters */
157			tmpreg |= SGIMC_GIOPARM_GFX64; 	/* GFX at 64 bits */
158		}
159	}
160	mcmisc_regs->gioparm = tmpreg; /* poof */
161}
162