root/sys/arch/ews4800mips/ews4800mips/sbd.c
/*      $NetBSD: sbd.c,v 1.4 2015/06/23 21:00:23 matt Exp $     */

/*-
 * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by UCHIYAMA Yasushi.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sbd.c,v 1.4 2015/06/23 21:00:23 matt Exp $");

/* System board */
#include "opt_sbd.h"

#include <sys/param.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <mips/locore.h>

#include <machine/sbdvar.h>
#include <machine/sbd.h>

struct sbd platform;            /* System board itself */

void
sbd_init(void)
{

        switch (SBD_INFO->machine) { /* Get model information from ROM */
        default:
                printf("This model is not supported.\n");
                printf("machine [0x%04x] model [0x%04x]\n",
                    SBD_INFO->machine, SBD_INFO->model);
                for (;;)
                        ;
                /* NOTREACHED */
                break;
#ifdef EWS4800_TR2
        case MACHINE_TR2:               /* EWS4800/350 */
                tr2_init();
                break;
#endif
#ifdef EWS4800_TR2A
        case MACHINE_TR2A:
                tr2a_init();            /* EWS4800/360 */
                break;
#endif
        }
}

void
sbd_memcluster_init(uint32_t m)
{
        /* Initialize memory_cluster *** mainfo_type2 only *** */
        size_t size, total = 0;
        int i, j, k, n;
        uint32_t start_addr[] = {
                __M0_BANK0_ADDR,
                __M0_BANK1_ADDR,
                __M1_BANK0_ADDR,
                __M1_BANK1_ADDR,
                __M2_BANK0_ADDR,
                __M2_BANK1_ADDR,
        };
        n = sizeof start_addr / sizeof start_addr[0];

        for (i = 0, k = 0, j = 1; i < 8; i++, m >>= 4) {
                size = m & 0xf ? ((m & 0xf) << 4) : 0;
                if (size == 0)
                        continue;
                if (k == n) {
                        /* don't load over 0x20000000 memory */
                        printf("M%d=%dMB(reserved)\n", i, size);
                        continue;
                }

                switch (size) {
                case 128:       /* oooooooo */
                case 16:        /* o....... */
                        mem_clusters[j].size = size * 1024 * 1024;
                        mem_clusters[j].start = start_addr[k];
                        j += 1;
                        k += 2;
                        break;
                case 32:        /* o...o... */
                        mem_clusters[j].size = 16 * 1024 * 1024;
                        mem_clusters[j].start = start_addr[k++];
                        j++;
                        mem_clusters[j].size = 16 * 1024 * 1024;
                        mem_clusters[j].start = start_addr[k++];
                        j++;
                        break;
                default:
                        printf("UNKNOWN MEMORY CLUSTER SIZE%d\n", size);
                        for (;;)
                                ;
                }
                total += size;
                printf("M%d=%dMB ", i, size);
        }
        printf(" total %dMB\n", total);
        mem_cluster_cnt = j;
        mem_clusters[0].size = total << 20;
}

void
sbd_memcluster_setup(void *kernstart, void *kernend)
{
        paddr_t start;
        size_t size;

        physmem = atop(mem_clusters[0].size);

        start = (paddr_t)round_page(MIPS_KSEG0_TO_PHYS(kernend));
        size = mem_clusters[1].size - start;

        /* kernel itself */
        mem_clusters[0].start = trunc_page(MIPS_KSEG0_TO_PHYS(kernstart));
        mem_clusters[0].size = start - mem_clusters[0].start;

        /* heap start */
        mem_clusters[1].start = start;
        mem_clusters[1].size = size;
}

void
sbd_memcluster_check(void)
{
        uint32_t *m, *mend;
        phys_ram_seg_t *p;
        paddr_t start;
        size_t size;
        size_t i, j;

        /* Very slow */
        for (i = 1; i < mem_cluster_cnt; i++) {
                p = &mem_clusters[i];
                start = p->start;
                size = p->size;
                printf("[%u] %#"PRIxPADDR"-%#"PRIxPADDR", %#x (%uMB)\n",
                    i, start, start + size, size, size >>20);
                m = (uint32_t *)MIPS_PHYS_TO_KSEG1(start);
                mend = (uint32_t *)MIPS_PHYS_TO_KSEG1(start + size);
                for (; m < mend; m++) {
                        uint32_t pattern[4] =
                        { 0xffffffff, 0xa5a5a5a5, 0x5a5a5a5a, 0x00000000 };
                        for (j = 0; j < 4; j++) {
                                *m = pattern[j];
                                if (*m != pattern[j])
                                        panic("memory error %p\n", m);
                        }
                }
                printf("checked.\r");
                memset((void *)MIPS_PHYS_TO_KSEG0(start), 0, size);
                printf("cleared.\r");
        }
}