18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * memory.c: memory initialisation code.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine
68c2ecf20Sopenharmony_ci * Copyright (C) 2000, 2002  Maciej W. Rozycki
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/mm.h>
118c2ecf20Sopenharmony_ci#include <linux/memblock.h>
128c2ecf20Sopenharmony_ci#include <linux/types.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <asm/addrspace.h>
158c2ecf20Sopenharmony_ci#include <asm/dec/machtype.h>
168c2ecf20Sopenharmony_ci#include <asm/dec/prom.h>
178c2ecf20Sopenharmony_ci#include <asm/page.h>
188c2ecf20Sopenharmony_ci#include <asm/sections.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_civolatile unsigned long mem_err;		/* So we know an error occurred */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen
258c2ecf20Sopenharmony_ci * off the end of real memory.  Only suitable for the 2100/3100's (PMAX).
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define CHUNK_SIZE 0x400000
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic __init void pmax_setup_memory_region(void)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	volatile unsigned char *memory_page, dummy;
338c2ecf20Sopenharmony_ci	char old_handler[0x80];
348c2ecf20Sopenharmony_ci	extern char genexcept_early;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	/* Install exception handler */
378c2ecf20Sopenharmony_ci	memcpy(&old_handler, (void *)(CKSEG0 + 0x80), 0x80);
388c2ecf20Sopenharmony_ci	memcpy((void *)(CKSEG0 + 0x80), &genexcept_early, 0x80);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* read unmapped and uncached (KSEG1)
418c2ecf20Sopenharmony_ci	 * DECstations have at least 4MB RAM
428c2ecf20Sopenharmony_ci	 * Assume less than 480MB of RAM, as this is max for 5000/2xx
438c2ecf20Sopenharmony_ci	 * FIXME this should be replaced by the first free page!
448c2ecf20Sopenharmony_ci	 */
458c2ecf20Sopenharmony_ci	for (memory_page = (unsigned char *)CKSEG1 + CHUNK_SIZE;
468c2ecf20Sopenharmony_ci	     mem_err == 0 && memory_page < (unsigned char *)CKSEG1 + 0x1e00000;
478c2ecf20Sopenharmony_ci	     memory_page += CHUNK_SIZE) {
488c2ecf20Sopenharmony_ci		dummy = *memory_page;
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci	memcpy((void *)(CKSEG0 + 0x80), &old_handler, 0x80);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	memblock_add(0, (unsigned long)memory_page - CKSEG1 - CHUNK_SIZE);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/*
568c2ecf20Sopenharmony_ci * Use the REX prom calls to get hold of the memory bitmap, and thence
578c2ecf20Sopenharmony_ci * determine memory size.
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_cistatic __init void rex_setup_memory_region(void)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	int i, bitmap_size;
628c2ecf20Sopenharmony_ci	unsigned long mem_start = 0, mem_size = 0;
638c2ecf20Sopenharmony_ci	memmap *bm;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* some free 64k */
668c2ecf20Sopenharmony_ci	bm = (memmap *)CKSEG0ADDR(0x28000);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	bitmap_size = rex_getbitmap(bm);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	for (i = 0; i < bitmap_size; i++) {
718c2ecf20Sopenharmony_ci		/* FIXME: very simplistically only add full sets of pages */
728c2ecf20Sopenharmony_ci		if (bm->bitmap[i] == 0xff)
738c2ecf20Sopenharmony_ci			mem_size += (8 * bm->pagesize);
748c2ecf20Sopenharmony_ci		else if (!mem_size)
758c2ecf20Sopenharmony_ci			mem_start += (8 * bm->pagesize);
768c2ecf20Sopenharmony_ci		else {
778c2ecf20Sopenharmony_ci			memblock_add(mem_start, mem_size);
788c2ecf20Sopenharmony_ci			mem_start += mem_size + (8 * bm->pagesize);
798c2ecf20Sopenharmony_ci			mem_size = 0;
808c2ecf20Sopenharmony_ci		}
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci	if (mem_size)
838c2ecf20Sopenharmony_ci		memblock_add(mem_start, mem_size);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_civoid __init prom_meminit(u32 magic)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	if (!prom_is_rex(magic))
898c2ecf20Sopenharmony_ci		pmax_setup_memory_region();
908c2ecf20Sopenharmony_ci	else
918c2ecf20Sopenharmony_ci		rex_setup_memory_region();
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_civoid __init prom_free_prom_memory(void)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	unsigned long end;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/*
998c2ecf20Sopenharmony_ci	 * Free everything below the kernel itself but leave
1008c2ecf20Sopenharmony_ci	 * the first page reserved for the exception handlers.
1018c2ecf20Sopenharmony_ci	 */
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DECLANCE)
1048c2ecf20Sopenharmony_ci	/*
1058c2ecf20Sopenharmony_ci	 * Leave 128 KB reserved for Lance memory for
1068c2ecf20Sopenharmony_ci	 * IOASIC DECstations.
1078c2ecf20Sopenharmony_ci	 *
1088c2ecf20Sopenharmony_ci	 * XXX: save this address for use in dec_lance.c?
1098c2ecf20Sopenharmony_ci	 */
1108c2ecf20Sopenharmony_ci	if (IOASIC)
1118c2ecf20Sopenharmony_ci		end = __pa(&_text) - 0x00020000;
1128c2ecf20Sopenharmony_ci	else
1138c2ecf20Sopenharmony_ci#endif
1148c2ecf20Sopenharmony_ci		end = __pa(&_text);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	free_init_pages("unused PROM memory", PAGE_SIZE, end);
1178c2ecf20Sopenharmony_ci}
118