ofw_machdep.c revision 160714
11590Srgrimes/*-
21590Srgrimes * Copyright (C) 1996 Wolfgang Solfrank.
31590Srgrimes * Copyright (C) 1996 TooLs GmbH.
41590Srgrimes * All rights reserved.
51590Srgrimes *
61590Srgrimes * Redistribution and use in source and binary forms, with or without
71590Srgrimes * modification, are permitted provided that the following conditions
81590Srgrimes * are met:
91590Srgrimes * 1. Redistributions of source code must retain the above copyright
101590Srgrimes *    notice, this list of conditions and the following disclaimer.
111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer in the
131590Srgrimes *    documentation and/or other materials provided with the distribution.
141590Srgrimes * 3. All advertising materials mentioning features or use of this software
151590Srgrimes *    must display the following acknowledgement:
161590Srgrimes *	This product includes software developed by TooLs GmbH.
171590Srgrimes * 4. The name of TooLs GmbH may not be used to endorse or promote products
181590Srgrimes *    derived from this software without specific prior written permission.
191590Srgrimes *
201590Srgrimes * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
211590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
221590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
231590Srgrimes * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
241590Srgrimes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
251590Srgrimes * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
261590Srgrimes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
271590Srgrimes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
281590Srgrimes * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
291590Srgrimes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
301590Srgrimes *
311590Srgrimes * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
321590Srgrimes */
331590Srgrimes
341590Srgrimes#include <sys/cdefs.h>
3541568Sarchie__FBSDID("$FreeBSD: head/sys/powerpc/aim/ofw_machdep.c 160714 2006-07-26 17:12:54Z marcel $");
361590Srgrimes
371590Srgrimes#include <sys/param.h>
3887241Smarkm#include <sys/bus.h>
391590Srgrimes#include <sys/systm.h>
4087628Sdwmalone#include <sys/conf.h>
411590Srgrimes#include <sys/disk.h>
4287628Sdwmalone#include <sys/fcntl.h>
4387241Smarkm#include <sys/malloc.h>
4487628Sdwmalone#include <sys/stat.h>
451590Srgrimes
4687628Sdwmalone#include <net/ethernet.h>
4787628Sdwmalone
4887628Sdwmalone#include <dev/ofw/openfirm.h>
491590Srgrimes
501590Srgrimes#include <vm/vm.h>
511590Srgrimes#include <vm/vm_param.h>
521590Srgrimes#include <vm/vm_page.h>
531590Srgrimes
541590Srgrimes#include <machine/bus.h>
551590Srgrimes#include <machine/md_var.h>
561590Srgrimes#include <machine/powerpc.h>
571590Srgrimes#include <machine/ofw_machdep.h>
581590Srgrimes#include <powerpc/ofw/ofw_pci.h>
591590Srgrimes
601590Srgrimes#define	OFMEM_REGIONS	32
6163157Sbrianstatic struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
621590Srgrimesstatic struct mem_region OFfree[OFMEM_REGIONS + 3];
631590Srgrimes
641590Srgrimesextern register_t ofmsr[5];
651590Srgrimesextern struct   pcpu __pcpu[MAXCPU];
661590Srgrimesextern struct	pmap ofw_pmap;
671590Srgrimesstatic int	(*ofwcall)(void *);
681590Srgrimes
691590Srgrimes/*
701590Srgrimes * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
711590Srgrimes */
721590Srgrimesregister_t	ofw_sprg0_save;
7386099Sdwmalone
741590Srgrimesstatic __inline void
7563157Sbrianofw_sprg_prepare(void)
761590Srgrimes{
771590Srgrimes	/*
781590Srgrimes	 * Assume that interrupt are disabled at this point, or
791590Srgrimes	 * SPRG1-3 could be trashed
801590Srgrimes	 */
811590Srgrimes	__asm __volatile("mfsprg0 %0\n\t"
8263157Sbrian			 "mtsprg0 %1\n\t"
831590Srgrimes	    		 "mtsprg1 %2\n\t"
8460583Sphk	    		 "mtsprg2 %3\n\t"
8560583Sphk			 "mtsprg3 %4\n\t"
8660583Sphk			 : "=&r"(ofw_sprg0_save)
8760583Sphk			 : "r"(ofmsr[1]),
8863157Sbrian			 "r"(ofmsr[2]),
8963157Sbrian			 "r"(ofmsr[3]),
9063157Sbrian			 "r"(ofmsr[4]));
911590Srgrimes}
921590Srgrimes
931590Srgrimesstatic __inline void
941590Srgrimesofw_sprg_restore(void)
951590Srgrimes{
961590Srgrimes	/*
971590Srgrimes	 * Note that SPRG1-3 contents are irrelevant. They are scratch
981590Srgrimes	 * registers used in the early portion of trap handling when
991590Srgrimes	 * interrupts are disabled.
1001590Srgrimes	 *
1011590Srgrimes	 * PCPU data cannot be used until this routine is called !
1021590Srgrimes	 */
10363157Sbrian	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
1041590Srgrimes}
1051590Srgrimes
1061590Srgrimes/*
1071590Srgrimes * Memory region utilities: determine if two regions overlap,
1081590Srgrimes * and merge two overlapping regions into one
1091590Srgrimes */
1101590Srgrimesstatic int
1111590Srgrimesmemr_overlap(struct mem_region *r1, struct mem_region *r2)
1121590Srgrimes{
1131590Srgrimes	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
1141590Srgrimes	    (r2->mr_start + r2->mr_size) < r1->mr_start)
1152149Sjkh		return (FALSE);
1162149Sjkh
1172149Sjkh	return (TRUE);
1182149Sjkh}
1192149Sjkh
1202149Sjkhstatic void
1211590Srgrimesmemr_merge(struct mem_region *from, struct mem_region *to)
1221590Srgrimes{
1231590Srgrimes	int end;
1241590Srgrimes	end = imax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
1251590Srgrimes	to->mr_start = imin(from->mr_start, to->mr_start);
1261590Srgrimes	to->mr_size = end - to->mr_start;
1271590Srgrimes}
1281590Srgrimes
1292149Sjkh/*
1302149Sjkh * This is called during powerpc_init, before the system is really initialized.
1312149Sjkh * It shall provide the total and the available regions of RAM.
1322149Sjkh * Both lists must have a zero-size entry as terminator.
1332149Sjkh * The available regions need not take the kernel into account, but needs
1342149Sjkh * to provide space for two additional entry beyond the terminating one.
1351590Srgrimes */
13628421Sjlemonvoid
13728421Sjlemonmem_regions(struct mem_region **memp, int *memsz,
1381590Srgrimes		struct mem_region **availp, int *availsz)
1391590Srgrimes{
1402149Sjkh	int phandle;
1412149Sjkh	int asz, msz, fsz;
1422149Sjkh	int i, j;
1432149Sjkh	int still_merging;
1442149Sjkh
1452149Sjkh	/*
1461590Srgrimes	 * Get memory.
1471590Srgrimes	 */
1481590Srgrimes	if ((phandle = OF_finddevice("/memory")) == -1
1492149Sjkh	    || (msz = OF_getprop(phandle, "reg",
1502149Sjkh			  OFmem, sizeof OFmem[0] * OFMEM_REGIONS))
1512149Sjkh	       <= 0
1522149Sjkh	    || (asz = OF_getprop(phandle, "available",
1532149Sjkh			  OFavail, sizeof OFavail[0] * OFMEM_REGIONS))
1542149Sjkh	       <= 0)
1551590Srgrimes		panic("no memory?");
1561590Srgrimes	*memp = OFmem;
1571590Srgrimes	*memsz = msz / sizeof(struct mem_region);
1581590Srgrimes
1591590Srgrimes	/*
1601590Srgrimes	 * OFavail may have overlapping regions - collapse these
1611590Srgrimes	 * and copy out remaining regions to OFfree
16263843Ssheldonh	 */
16363157Sbrian	asz /= sizeof(struct mem_region);
16463157Sbrian	do {
16563157Sbrian		still_merging = FALSE;
16663157Sbrian		for (i = 0; i < asz; i++) {
16763157Sbrian			if (OFavail[i].mr_size == 0)
16863157Sbrian				continue;
1691590Srgrimes			for (j = i+1; j < asz; j++) {
1701590Srgrimes				if (OFavail[j].mr_size == 0)
17163843Ssheldonh					continue;
1721590Srgrimes				if (memr_overlap(&OFavail[j], &OFavail[i])) {
1731590Srgrimes					memr_merge(&OFavail[j], &OFavail[i]);
1741590Srgrimes					/* mark inactive */
1751590Srgrimes					OFavail[j].mr_size = 0;
1761590Srgrimes					still_merging = TRUE;
1771590Srgrimes				}
1781590Srgrimes			}
1791590Srgrimes		}
18063157Sbrian	} while (still_merging == TRUE);
1811590Srgrimes
1821590Srgrimes	/* evict inactive ranges */
183	for (i = 0, fsz = 0; i < asz; i++) {
184		if (OFavail[i].mr_size != 0) {
185			OFfree[fsz] = OFavail[i];
186			fsz++;
187		}
188	}
189
190	*availp = OFfree;
191	*availsz = fsz;
192}
193
194void
195set_openfirm_callback(int (*openfirm)(void *))
196{
197
198	ofwcall = openfirm;
199}
200
201int
202openfirmware(void *args)
203{
204	long	oldmsr;
205	int	result;
206	u_int	srsave[16];
207	u_int   i;
208
209	__asm __volatile(	"\t"
210		"sync\n\t"
211		"mfmsr  %0\n\t"
212		"mtmsr  %1\n\t"
213		"isync\n"
214		: "=r" (oldmsr)
215		: "r" (ofmsr[0])
216	);
217
218	ofw_sprg_prepare();
219
220	if (pmap_bootstrapped) {
221		/*
222		 * Swap the kernel's address space with Open Firmware's
223		 */
224		for (i = 0; i < 16; i++) {
225			srsave[i] = mfsrin(i << ADDR_SR_SHFT);
226			mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]);
227		}
228
229		/*
230		 * Clear battable[] translations
231		 */
232		__asm __volatile("mtdbatu 2, %0\n"
233				 "mtdbatu 3, %0" : : "r" (0));
234		isync();
235	}
236
237       	result = ofwcall(args);
238
239	if (pmap_bootstrapped) {
240		/*
241		 * Restore the kernel's addr space. The isync() doesn;t
242		 * work outside the loop unless mtsrin() is open-coded
243		 * in an asm statement :(
244		 */
245		for (i = 0; i < 16; i++) {
246			mtsrin(i << ADDR_SR_SHFT, srsave[i]);
247			isync();
248		}
249	}
250
251	ofw_sprg_restore();
252
253	__asm(	"\t"
254		"mtmsr  %0\n\t"
255		"isync\n"
256		: : "r" (oldmsr)
257	);
258
259	return (result);
260}
261
262void
263OF_halt()
264{
265	int retval;	/* dummy, this may not be needed */
266
267	OF_interpret("shut-down", 1, &retval);
268	for (;;);	/* just in case */
269}
270
271void
272OF_reboot()
273{
274	int retval;	/* dummy, this may not be needed */
275
276	OF_interpret("reset-all", 1, &retval);
277	for (;;);	/* just in case */
278}
279
280void
281OF_getetheraddr(device_t dev, u_char *addr)
282{
283	phandle_t	node;
284
285	node = ofw_pci_find_node(dev);
286	OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
287}
288
289/*
290 * Return the physical address and the bus space to use for a node
291 * referenced by its package handle and the index of the register bank
292 * to decode. Intended to be used by console drivers in early boot only.
293 * Works by mapping the address of the node's bank given in the address
294 * space of its parent upward in the device tree at each bridge along the
295 * path.
296 */
297int
298OF_decode_addr(phandle_t node, int bank, bus_space_tag_t *tag,
299    bus_space_handle_t *handle)
300{
301
302	return (ENXIO);
303}
304
305int
306mem_valid(vm_offset_t addr, int len)
307{
308	int i;
309
310	for (i = 0; i < OFMEM_REGIONS; i++)
311		if ((addr >= OFmem[i].mr_start)
312		    && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size))
313			return (0);
314
315	return (EFAULT);
316}
317