linux/arch/mips/sgi-ip22/ip22-mc.c
<<
>>
Prefs
   1/*
   2 * ip22-mc.c: Routines for manipulating SGI 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 * Copyright (C) 2003 Ladislav Michl  (ladis@linux-mips.org)
   7 * Copyright (C) 2004 Peter Fuerst    (pf@net.alphadv.de) - IP28
   8 */
   9
  10#include <linux/init.h>
  11#include <linux/module.h>
  12#include <linux/kernel.h>
  13
  14#include <asm/io.h>
  15#include <asm/bootinfo.h>
  16#include <asm/sgialib.h>
  17#include <asm/sgi/mc.h>
  18#include <asm/sgi/hpc3.h>
  19#include <asm/sgi/ip22.h>
  20
  21struct sgimc_regs *sgimc;
  22
  23EXPORT_SYMBOL(sgimc);
  24
  25static inline unsigned long get_bank_addr(unsigned int memconfig)
  26{
  27        return ((memconfig & SGIMC_MCONFIG_BASEADDR) <<
  28                ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 24 : 22));
  29}
  30
  31static inline unsigned long get_bank_size(unsigned int memconfig)
  32{
  33        return ((memconfig & SGIMC_MCONFIG_RMASK) + 0x0100) <<
  34                ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 16 : 14);
  35}
  36
  37static inline unsigned int get_bank_config(int bank)
  38{
  39        unsigned int res = bank > 1 ? sgimc->mconfig1 : sgimc->mconfig0;
  40        return bank % 2 ? res & 0xffff : res >> 16;
  41}
  42
  43struct mem {
  44        unsigned long addr;
  45        unsigned long size;
  46};
  47
  48/*
  49 * Detect installed memory, do some sanity checks and notify kernel about it
  50 */
  51static void __init probe_memory(void)
  52{
  53        int i, j, found, cnt = 0;
  54        struct mem bank[4];
  55        struct mem space[2] = {{SGIMC_SEG0_BADDR, 0}, {SGIMC_SEG1_BADDR, 0}};
  56
  57        printk(KERN_INFO "MC: Probing memory configuration:\n");
  58        for (i = 0; i < ARRAY_SIZE(bank); i++) {
  59                unsigned int tmp = get_bank_config(i);
  60                if (!(tmp & SGIMC_MCONFIG_BVALID))
  61                        continue;
  62
  63                bank[cnt].size = get_bank_size(tmp);
  64                bank[cnt].addr = get_bank_addr(tmp);
  65                printk(KERN_INFO " bank%d: %3ldM @ %08lx\n",
  66                        i, bank[cnt].size / 1024 / 1024, bank[cnt].addr);
  67                cnt++;
  68        }
  69
  70        /* And you thought bubble sort is dead algorithm... */
  71        do {
  72                unsigned long addr, size;
  73
  74                found = 0;
  75                for (i = 1; i < cnt; i++)
  76                        if (bank[i-1].addr > bank[i].addr) {
  77                                addr = bank[i].addr;
  78                                size = bank[i].size;
  79                                bank[i].addr = bank[i-1].addr;
  80                                bank[i].size = bank[i-1].size;
  81                                bank[i-1].addr = addr;
  82                                bank[i-1].size = size;
  83                                found = 1;
  84                        }
  85        } while (found);
  86
  87        /* Figure out how are memory banks mapped into spaces */
  88        for (i = 0; i < cnt; i++) {
  89                found = 0;
  90                for (j = 0; j < ARRAY_SIZE(space) && !found; j++)
  91                        if (space[j].addr + space[j].size == bank[i].addr) {
  92                                space[j].size += bank[i].size;
  93                                found = 1;
  94                        }
  95                /* There is either hole or overlapping memory */
  96                if (!found)
  97                        printk(KERN_CRIT "MC: Memory configuration mismatch "
  98                                         "(%08lx), expect Bus Error soon\n",
  99                                         bank[i].addr);
 100        }
 101
 102        for (i = 0; i < ARRAY_SIZE(space); i++)
 103                if (space[i].size)
 104                        add_memory_region(space[i].addr, space[i].size,
 105                                          BOOT_MEM_RAM);
 106}
 107
 108void __init sgimc_init(void)
 109{
 110        u32 tmp;
 111
 112        /* ioremap can't fail */
 113        sgimc = (struct sgimc_regs *)
 114                ioremap(SGIMC_BASE, sizeof(struct sgimc_regs));
 115
 116        printk(KERN_INFO "MC: SGI memory controller Revision %d\n",
 117               (int) sgimc->systemid & SGIMC_SYSID_MASKREV);
 118
 119        /* Place the MC into a known state.  This must be done before
 120         * interrupts are first enabled etc.
 121         */
 122
 123        /* Step 0: Make sure we turn off the watchdog in case it's
 124         *         still running (which might be the case after a
 125         *         soft reboot).
 126         */
 127        tmp = sgimc->cpuctrl0;
 128        tmp &= ~SGIMC_CCTRL0_WDOG;
 129        sgimc->cpuctrl0 = tmp;
 130
 131        /* Step 1: The CPU/GIO error status registers will not latch
 132         *         up a new error status until the register has been
 133         *         cleared by the cpu.  These status registers are
 134         *         cleared by writing any value to them.
 135         */
 136        sgimc->cstat = sgimc->gstat = 0;
 137
 138        /* Step 2: Enable all parity checking in cpu control register
 139         *         zero.
 140         */
 141        /* don't touch parity settings for IP28 */
 142#ifndef CONFIG_SGI_IP28
 143        tmp = sgimc->cpuctrl0;
 144        tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
 145                SGIMC_CCTRL0_R4KNOCHKPARR);
 146#endif
 147        sgimc->cpuctrl0 = tmp;
 148
 149        /* Step 3: Setup the MC write buffer depth, this is controlled
 150         *         in cpu control register 1 in the lower 4 bits.
 151         */
 152        tmp = sgimc->cpuctrl1;
 153        tmp &= ~0xf;
 154        tmp |= 0xd;
 155        sgimc->cpuctrl1 = tmp;
 156
 157        /* Step 4: Initialize the RPSS divider register to run as fast
 158         *         as it can correctly operate.  The register is laid
 159         *         out as follows:
 160         *
 161         *         ----------------------------------------
 162         *         |  RESERVED  |   INCREMENT   | DIVIDER |
 163         *         ----------------------------------------
 164         *          31        16 15            8 7       0
 165         *
 166         *         DIVIDER determines how often a 'tick' happens,
 167         *         INCREMENT determines by how the RPSS increment
 168         *         registers value increases at each 'tick'. Thus,
 169         *         for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101
 170         */
 171        sgimc->divider = 0x101;
 172
 173        /* Step 5: Initialize GIO64 arbitrator configuration register.
 174         *
 175         * NOTE: HPC init code in sgihpc_init() must run before us because
 176         *       we need to know Guiness vs. FullHouse and the board
 177         *       revision on this machine. You have been warned.
 178         */
 179
 180        /* First the basic invariants across all GIO64 implementations. */
 181        tmp = SGIMC_GIOPAR_HPC64;       /* All 1st HPC's interface at 64bits */
 182        tmp |= SGIMC_GIOPAR_ONEBUS;     /* Only one physical GIO bus exists */
 183
 184        if (ip22_is_fullhouse()) {
 185                /* Fullhouse specific settings. */
 186                if (SGIOC_SYSID_BOARDREV(sgioc->sysid) < 2) {
 187                        tmp |= SGIMC_GIOPAR_HPC264;     /* 2nd HPC at 64bits */
 188                        tmp |= SGIMC_GIOPAR_PLINEEXP0;  /* exp0 pipelines */
 189                        tmp |= SGIMC_GIOPAR_MASTEREXP1; /* exp1 masters */
 190                        tmp |= SGIMC_GIOPAR_RTIMEEXP0;  /* exp0 is realtime */
 191                } else {
 192                        tmp |= SGIMC_GIOPAR_HPC264;     /* 2nd HPC 64bits */
 193                        tmp |= SGIMC_GIOPAR_PLINEEXP0;  /* exp[01] pipelined */
 194                        tmp |= SGIMC_GIOPAR_PLINEEXP1;
 195                        tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */
 196                        tmp |= SGIMC_GIOPAR_GFX64;      /* GFX at 64 bits */
 197                }
 198        } else {
 199                /* Guiness specific settings. */
 200                tmp |= SGIMC_GIOPAR_EISA64;     /* MC talks to EISA at 64bits */
 201                tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA bus can act as master */
 202        }
 203        sgimc->giopar = tmp;    /* poof */
 204
 205        probe_memory();
 206}
 207
 208void __init prom_meminit(void) {}
 209void __init prom_free_prom_memory(void)
 210{
 211#ifdef CONFIG_SGI_IP28
 212        u32 mconfig1;
 213        unsigned long flags;
 214        spinlock_t lock;
 215
 216        /*
 217         * because ARCS accesses memory uncached we wait until ARCS
 218         * isn't needed any longer, before we switch from slow to
 219         * normal mode
 220         */
 221        spin_lock_irqsave(&lock, flags);
 222        mconfig1 = sgimc->mconfig1;
 223        /* map ECC register */
 224        sgimc->mconfig1 = (mconfig1 & 0xffff0000) | 0x2060;
 225        iob();
 226        /* switch to normal mode */
 227        *(unsigned long *)PHYS_TO_XKSEG_UNCACHED(0x60000000) = 0;
 228        iob();
 229        /* reduce WR_COL */
 230        sgimc->cmacc = (sgimc->cmacc & ~0xf) | 4;
 231        iob();
 232        /* restore old config */
 233        sgimc->mconfig1 = mconfig1;
 234        iob();
 235        spin_unlock_irqrestore(&lock, flags);
 236#endif
 237}
 238