18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * inventory.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 1999 The Puffin Group (David Kennedy and Alex deVries)
68c2ecf20Sopenharmony_ci * Copyright (c) 2001 Matthew Wilcox for Hewlett-Packard
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * These are the routines to discover what hardware exists in this box.
98c2ecf20Sopenharmony_ci * This task is complicated by there being 3 different ways of
108c2ecf20Sopenharmony_ci * performing an inventory, depending largely on the age of the box.
118c2ecf20Sopenharmony_ci * The recommended way to do this is to check to see whether the machine
128c2ecf20Sopenharmony_ci * is a `Snake' first, then try System Map, then try PAT.  We try System
138c2ecf20Sopenharmony_ci * Map before checking for a Snake -- this probably doesn't cause any
148c2ecf20Sopenharmony_ci * problems, but...
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/init.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/mm.h>
228c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
238c2ecf20Sopenharmony_ci#include <asm/hardware.h>
248c2ecf20Sopenharmony_ci#include <asm/io.h>
258c2ecf20Sopenharmony_ci#include <asm/mmzone.h>
268c2ecf20Sopenharmony_ci#include <asm/pdc.h>
278c2ecf20Sopenharmony_ci#include <asm/pdcpat.h>
288c2ecf20Sopenharmony_ci#include <asm/processor.h>
298c2ecf20Sopenharmony_ci#include <asm/page.h>
308c2ecf20Sopenharmony_ci#include <asm/parisc-device.h>
318c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci** Debug options
358c2ecf20Sopenharmony_ci** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices.
368c2ecf20Sopenharmony_ci*/
378c2ecf20Sopenharmony_ci#undef DEBUG_PAT
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciint pdc_type __ro_after_init = PDC_TYPE_ILLEGAL;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* cell number and location (PAT firmware only) */
428c2ecf20Sopenharmony_ciunsigned long parisc_cell_num __ro_after_init;
438c2ecf20Sopenharmony_ciunsigned long parisc_cell_loc __ro_after_init;
448c2ecf20Sopenharmony_ciunsigned long parisc_pat_pdc_cap __ro_after_init;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_civoid __init setup_pdc(void)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	long status;
508c2ecf20Sopenharmony_ci	unsigned int bus_id;
518c2ecf20Sopenharmony_ci	struct pdc_system_map_mod_info module_result;
528c2ecf20Sopenharmony_ci	struct pdc_module_path module_path;
538c2ecf20Sopenharmony_ci	struct pdc_model model;
548c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT
558c2ecf20Sopenharmony_ci	struct pdc_pat_cell_num cell_info;
568c2ecf20Sopenharmony_ci#endif
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* Determine the pdc "type" used on this machine */
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	printk(KERN_INFO "Determining PDC firmware type: ");
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	status = pdc_system_map_find_mods(&module_result, &module_path, 0);
638c2ecf20Sopenharmony_ci	if (status == PDC_OK) {
648c2ecf20Sopenharmony_ci		pdc_type = PDC_TYPE_SYSTEM_MAP;
658c2ecf20Sopenharmony_ci		pr_cont("System Map.\n");
668c2ecf20Sopenharmony_ci		return;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/*
708c2ecf20Sopenharmony_ci	 * If the machine doesn't support PDC_SYSTEM_MAP then either it
718c2ecf20Sopenharmony_ci	 * is a pdc pat box, or it is an older box. All 64 bit capable
728c2ecf20Sopenharmony_ci	 * machines are either pdc pat boxes or they support PDC_SYSTEM_MAP.
738c2ecf20Sopenharmony_ci	 */
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/*
768c2ecf20Sopenharmony_ci	 * TODO: We should test for 64 bit capability and give a
778c2ecf20Sopenharmony_ci	 * clearer message.
788c2ecf20Sopenharmony_ci	 */
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT
818c2ecf20Sopenharmony_ci	status = pdc_pat_cell_get_number(&cell_info);
828c2ecf20Sopenharmony_ci	if (status == PDC_OK) {
838c2ecf20Sopenharmony_ci		unsigned long legacy_rev, pat_rev;
848c2ecf20Sopenharmony_ci		pdc_type = PDC_TYPE_PAT;
858c2ecf20Sopenharmony_ci		pr_cont("64 bit PAT.\n");
868c2ecf20Sopenharmony_ci		parisc_cell_num = cell_info.cell_num;
878c2ecf20Sopenharmony_ci		parisc_cell_loc = cell_info.cell_loc;
888c2ecf20Sopenharmony_ci		pr_info("PAT: Running on cell %lu and location %lu.\n",
898c2ecf20Sopenharmony_ci			parisc_cell_num, parisc_cell_loc);
908c2ecf20Sopenharmony_ci		status = pdc_pat_pd_get_pdc_revisions(&legacy_rev,
918c2ecf20Sopenharmony_ci			&pat_rev, &parisc_pat_pdc_cap);
928c2ecf20Sopenharmony_ci		pr_info("PAT: legacy revision 0x%lx, pat_rev 0x%lx, pdc_cap 0x%lx, S-PTLB %d, HPMC_RENDEZ %d.\n",
938c2ecf20Sopenharmony_ci			legacy_rev, pat_rev, parisc_pat_pdc_cap,
948c2ecf20Sopenharmony_ci			parisc_pat_pdc_cap
958c2ecf20Sopenharmony_ci			 & PDC_PAT_CAPABILITY_BIT_SIMULTANEOUS_PTLB ? 1:0,
968c2ecf20Sopenharmony_ci			parisc_pat_pdc_cap
978c2ecf20Sopenharmony_ci			 & PDC_PAT_CAPABILITY_BIT_PDC_HPMC_RENDEZ   ? 1:0);
988c2ecf20Sopenharmony_ci		return;
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci#endif
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* Check the CPU's bus ID.  There's probably a better test.  */
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	status = pdc_model_info(&model);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	bus_id = (model.hversion >> (4 + 7)) & 0x1f;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	switch (bus_id) {
1098c2ecf20Sopenharmony_ci	case 0x4:		/* 720, 730, 750, 735, 755 */
1108c2ecf20Sopenharmony_ci	case 0x6:		/* 705, 710 */
1118c2ecf20Sopenharmony_ci	case 0x7:		/* 715, 725 */
1128c2ecf20Sopenharmony_ci	case 0x8:		/* 745, 747, 742 */
1138c2ecf20Sopenharmony_ci	case 0xA:		/* 712 and similar */
1148c2ecf20Sopenharmony_ci	case 0xC:		/* 715/64, at least */
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		pdc_type = PDC_TYPE_SNAKE;
1178c2ecf20Sopenharmony_ci		pr_cont("Snake.\n");
1188c2ecf20Sopenharmony_ci		return;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	default:		/* Everything else */
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		pr_cont("Unsupported.\n");
1238c2ecf20Sopenharmony_ci		panic("If this is a 64-bit machine, please try a 64-bit kernel.\n");
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define PDC_PAGE_ADJ_SHIFT (PAGE_SHIFT - 12) /* pdc pages are always 4k */
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic void __init
1308c2ecf20Sopenharmony_ciset_pmem_entry(physmem_range_t *pmem_ptr, unsigned long start,
1318c2ecf20Sopenharmony_ci	       unsigned long pages4k)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	/* Rather than aligning and potentially throwing away
1348c2ecf20Sopenharmony_ci	 * memory, we'll assume that any ranges are already
1358c2ecf20Sopenharmony_ci	 * nicely aligned with any reasonable page size, and
1368c2ecf20Sopenharmony_ci	 * panic if they are not (it's more likely that the
1378c2ecf20Sopenharmony_ci	 * pdc info is bad in this case).
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (unlikely( ((start & (PAGE_SIZE - 1)) != 0)
1418c2ecf20Sopenharmony_ci	    || ((pages4k & ((1UL << PDC_PAGE_ADJ_SHIFT) - 1)) != 0) )) {
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		panic("Memory range doesn't align with page size!\n");
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	pmem_ptr->start_pfn = (start >> PAGE_SHIFT);
1478c2ecf20Sopenharmony_ci	pmem_ptr->pages = (pages4k >> PDC_PAGE_ADJ_SHIFT);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic void __init pagezero_memconfig(void)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	unsigned long npages;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* Use the 32 bit information from page zero to create a single
1558c2ecf20Sopenharmony_ci	 * entry in the pmem_ranges[] table.
1568c2ecf20Sopenharmony_ci	 *
1578c2ecf20Sopenharmony_ci	 * We currently don't support machines with contiguous memory
1588c2ecf20Sopenharmony_ci	 * >= 4 Gb, who report that memory using 64 bit only fields
1598c2ecf20Sopenharmony_ci	 * on page zero. It's not worth doing until it can be tested,
1608c2ecf20Sopenharmony_ci	 * and it is not clear we can support those machines for other
1618c2ecf20Sopenharmony_ci	 * reasons.
1628c2ecf20Sopenharmony_ci	 *
1638c2ecf20Sopenharmony_ci	 * If that support is done in the future, this is where it
1648c2ecf20Sopenharmony_ci	 * should be done.
1658c2ecf20Sopenharmony_ci	 */
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	npages = (PAGE_ALIGN(PAGE0->imm_max_mem) >> PAGE_SHIFT);
1688c2ecf20Sopenharmony_ci	set_pmem_entry(pmem_ranges,0UL,npages);
1698c2ecf20Sopenharmony_ci	npmem_ranges = 1;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/* All of the PDC PAT specific code is 64-bit only */
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/*
1778c2ecf20Sopenharmony_ci**  The module object is filled via PDC_PAT_CELL[Return Cell Module].
1788c2ecf20Sopenharmony_ci**  If a module is found, register module will get the IODC bytes via
1798c2ecf20Sopenharmony_ci**  pdc_iodc_read() using the PA view of conf_base_addr for the hpa parameter.
1808c2ecf20Sopenharmony_ci**
1818c2ecf20Sopenharmony_ci**  The IO view can be used by PDC_PAT_CELL[Return Cell Module]
1828c2ecf20Sopenharmony_ci**  only for SBAs and LBAs.  This view will cause an invalid
1838c2ecf20Sopenharmony_ci**  argument error for all other cell module types.
1848c2ecf20Sopenharmony_ci**
1858c2ecf20Sopenharmony_ci*/
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int __init
1888c2ecf20Sopenharmony_cipat_query_module(ulong pcell_loc, ulong mod_index)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;
1918c2ecf20Sopenharmony_ci	unsigned long bytecnt;
1928c2ecf20Sopenharmony_ci	unsigned long temp;	/* 64-bit scratch value */
1938c2ecf20Sopenharmony_ci	long status;		/* PDC return value status */
1948c2ecf20Sopenharmony_ci	struct parisc_device *dev;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL);
1978c2ecf20Sopenharmony_ci	if (!pa_pdc_cell)
1988c2ecf20Sopenharmony_ci		panic("couldn't allocate memory for PDC_PAT_CELL!");
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/* return cell module (PA or Processor view) */
2018c2ecf20Sopenharmony_ci	status = pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
2028c2ecf20Sopenharmony_ci				     PA_VIEW, pa_pdc_cell);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (status != PDC_OK) {
2058c2ecf20Sopenharmony_ci		/* no more cell modules or error */
2068c2ecf20Sopenharmony_ci		kfree(pa_pdc_cell);
2078c2ecf20Sopenharmony_ci		return status;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	temp = pa_pdc_cell->cba;
2118c2ecf20Sopenharmony_ci	dev = alloc_pa_dev(PAT_GET_CBA(temp), &(pa_pdc_cell->mod_path));
2128c2ecf20Sopenharmony_ci	if (!dev) {
2138c2ecf20Sopenharmony_ci		kfree(pa_pdc_cell);
2148c2ecf20Sopenharmony_ci		return PDC_OK;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* alloc_pa_dev sets dev->hpa */
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/*
2208c2ecf20Sopenharmony_ci	** save parameters in the parisc_device
2218c2ecf20Sopenharmony_ci	** (The idea being the device driver will call pdc_pat_cell_module()
2228c2ecf20Sopenharmony_ci	** and store the results in its own data structure.)
2238c2ecf20Sopenharmony_ci	*/
2248c2ecf20Sopenharmony_ci	dev->pcell_loc = pcell_loc;
2258c2ecf20Sopenharmony_ci	dev->mod_index = mod_index;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/* save generic info returned from the call */
2288c2ecf20Sopenharmony_ci	/* REVISIT: who is the consumer of this? not sure yet... */
2298c2ecf20Sopenharmony_ci	dev->mod_info = pa_pdc_cell->mod_info;	/* pass to PAT_GET_ENTITY() */
2308c2ecf20Sopenharmony_ci	dev->pmod_loc = pa_pdc_cell->mod_location;
2318c2ecf20Sopenharmony_ci	dev->mod0 = pa_pdc_cell->mod[0];
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	register_parisc_device(dev);	/* advertise device */
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci#ifdef DEBUG_PAT
2368c2ecf20Sopenharmony_ci	/* dump what we see so far... */
2378c2ecf20Sopenharmony_ci	switch (PAT_GET_ENTITY(dev->mod_info)) {
2388c2ecf20Sopenharmony_ci		pdc_pat_cell_mod_maddr_block_t io_pdc_cell;
2398c2ecf20Sopenharmony_ci		unsigned long i;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	case PAT_ENTITY_PROC:
2428c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PAT_ENTITY_PROC: id_eid 0x%lx\n",
2438c2ecf20Sopenharmony_ci			pa_pdc_cell->mod[0]);
2448c2ecf20Sopenharmony_ci		break;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	case PAT_ENTITY_MEM:
2478c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
2488c2ecf20Sopenharmony_ci			"PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
2498c2ecf20Sopenharmony_ci			pa_pdc_cell->mod[0], pa_pdc_cell->mod[1],
2508c2ecf20Sopenharmony_ci			pa_pdc_cell->mod[2]);
2518c2ecf20Sopenharmony_ci		break;
2528c2ecf20Sopenharmony_ci	case PAT_ENTITY_CA:
2538c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PAT_ENTITY_CA: %ld\n", pcell_loc);
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	case PAT_ENTITY_PBC:
2578c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PAT_ENTITY_PBC: ");
2588c2ecf20Sopenharmony_ci		goto print_ranges;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	case PAT_ENTITY_SBA:
2618c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PAT_ENTITY_SBA: ");
2628c2ecf20Sopenharmony_ci		goto print_ranges;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	case PAT_ENTITY_LBA:
2658c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PAT_ENTITY_LBA: ");
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci print_ranges:
2688c2ecf20Sopenharmony_ci		pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
2698c2ecf20Sopenharmony_ci				    IO_VIEW, &io_pdc_cell);
2708c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell->mod[1]);
2718c2ecf20Sopenharmony_ci		for (i = 0; i < pa_pdc_cell->mod[1]; i++) {
2728c2ecf20Sopenharmony_ci			printk(KERN_DEBUG
2738c2ecf20Sopenharmony_ci				"  PA_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n",
2748c2ecf20Sopenharmony_ci				i, pa_pdc_cell->mod[2 + i * 3],	/* type */
2758c2ecf20Sopenharmony_ci				pa_pdc_cell->mod[3 + i * 3],	/* start */
2768c2ecf20Sopenharmony_ci				pa_pdc_cell->mod[4 + i * 3]);	/* finish (ie end) */
2778c2ecf20Sopenharmony_ci			printk(KERN_DEBUG
2788c2ecf20Sopenharmony_ci				"  IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n",
2798c2ecf20Sopenharmony_ci				i, io_pdc_cell.mod[2 + i * 3],	/* type */
2808c2ecf20Sopenharmony_ci				io_pdc_cell.mod[3 + i * 3],	/* start */
2818c2ecf20Sopenharmony_ci				io_pdc_cell.mod[4 + i * 3]);	/* finish (ie end) */
2828c2ecf20Sopenharmony_ci		}
2838c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "\n");
2848c2ecf20Sopenharmony_ci		break;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci#endif /* DEBUG_PAT */
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	kfree(pa_pdc_cell);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return PDC_OK;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/* pat pdc can return information about a variety of different
2958c2ecf20Sopenharmony_ci * types of memory (e.g. firmware,i/o, etc) but we only care about
2968c2ecf20Sopenharmony_ci * the usable physical ram right now. Since the firmware specific
2978c2ecf20Sopenharmony_ci * information is allocated on the stack, we'll be generous, in
2988c2ecf20Sopenharmony_ci * case there is a lot of other information we don't care about.
2998c2ecf20Sopenharmony_ci */
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci#define PAT_MAX_RANGES (4 * MAX_PHYSMEM_RANGES)
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic void __init pat_memconfig(void)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	unsigned long actual_len;
3068c2ecf20Sopenharmony_ci	struct pdc_pat_pd_addr_map_entry mem_table[PAT_MAX_RANGES+1];
3078c2ecf20Sopenharmony_ci	struct pdc_pat_pd_addr_map_entry *mtbl_ptr;
3088c2ecf20Sopenharmony_ci	physmem_range_t *pmem_ptr;
3098c2ecf20Sopenharmony_ci	long status;
3108c2ecf20Sopenharmony_ci	int entries;
3118c2ecf20Sopenharmony_ci	unsigned long length;
3128c2ecf20Sopenharmony_ci	int i;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	length = (PAT_MAX_RANGES + 1) * sizeof(struct pdc_pat_pd_addr_map_entry);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	status = pdc_pat_pd_get_addr_map(&actual_len, mem_table, length, 0L);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if ((status != PDC_OK)
3198c2ecf20Sopenharmony_ci	    || ((actual_len % sizeof(struct pdc_pat_pd_addr_map_entry)) != 0)) {
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		/* The above pdc call shouldn't fail, but, just in
3228c2ecf20Sopenharmony_ci		 * case, just use the PAGE0 info.
3238c2ecf20Sopenharmony_ci		 */
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		printk("\n\n\n");
3268c2ecf20Sopenharmony_ci		printk(KERN_WARNING "WARNING! Could not get full memory configuration. "
3278c2ecf20Sopenharmony_ci			"All memory may not be used!\n\n\n");
3288c2ecf20Sopenharmony_ci		pagezero_memconfig();
3298c2ecf20Sopenharmony_ci		return;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	entries = actual_len / sizeof(struct pdc_pat_pd_addr_map_entry);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (entries > PAT_MAX_RANGES) {
3358c2ecf20Sopenharmony_ci		printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
3368c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Some memory may not be used!\n");
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* Copy information into the firmware independent pmem_ranges
3408c2ecf20Sopenharmony_ci	 * array, skipping types we don't care about. Notice we said
3418c2ecf20Sopenharmony_ci	 * "may" above. We'll use all the entries that were returned.
3428c2ecf20Sopenharmony_ci	 */
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	npmem_ranges = 0;
3458c2ecf20Sopenharmony_ci	mtbl_ptr = mem_table;
3468c2ecf20Sopenharmony_ci	pmem_ptr = pmem_ranges; /* Global firmware independent table */
3478c2ecf20Sopenharmony_ci	for (i = 0; i < entries; i++,mtbl_ptr++) {
3488c2ecf20Sopenharmony_ci		if (   (mtbl_ptr->entry_type != PAT_MEMORY_DESCRIPTOR)
3498c2ecf20Sopenharmony_ci		    || (mtbl_ptr->memory_type != PAT_MEMTYPE_MEMORY)
3508c2ecf20Sopenharmony_ci		    || (mtbl_ptr->pages == 0)
3518c2ecf20Sopenharmony_ci		    || (   (mtbl_ptr->memory_usage != PAT_MEMUSE_GENERAL)
3528c2ecf20Sopenharmony_ci			&& (mtbl_ptr->memory_usage != PAT_MEMUSE_GI)
3538c2ecf20Sopenharmony_ci			&& (mtbl_ptr->memory_usage != PAT_MEMUSE_GNI) ) ) {
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci			continue;
3568c2ecf20Sopenharmony_ci		}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		if (npmem_ranges == MAX_PHYSMEM_RANGES) {
3598c2ecf20Sopenharmony_ci			printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
3608c2ecf20Sopenharmony_ci			printk(KERN_WARNING "Some memory will not be used!\n");
3618c2ecf20Sopenharmony_ci			break;
3628c2ecf20Sopenharmony_ci		}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
3658c2ecf20Sopenharmony_ci		npmem_ranges++;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic int __init pat_inventory(void)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	int status;
3728c2ecf20Sopenharmony_ci	ulong mod_index = 0;
3738c2ecf20Sopenharmony_ci	struct pdc_pat_cell_num cell_info;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/*
3768c2ecf20Sopenharmony_ci	** Note:  Prelude (and it's successors: Lclass, A400/500) only
3778c2ecf20Sopenharmony_ci	**        implement PDC_PAT_CELL sub-options 0 and 2.
3788c2ecf20Sopenharmony_ci	*/
3798c2ecf20Sopenharmony_ci	status = pdc_pat_cell_get_number(&cell_info);
3808c2ecf20Sopenharmony_ci	if (status != PDC_OK) {
3818c2ecf20Sopenharmony_ci		return 0;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci#ifdef DEBUG_PAT
3858c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_info.cell_num,
3868c2ecf20Sopenharmony_ci	       cell_info.cell_loc);
3878c2ecf20Sopenharmony_ci#endif
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	while (PDC_OK == pat_query_module(cell_info.cell_loc, mod_index)) {
3908c2ecf20Sopenharmony_ci		mod_index++;
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return mod_index;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/* We only look for extended memory ranges on a 64 bit capable box */
3978c2ecf20Sopenharmony_cistatic void __init sprockets_memconfig(void)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct pdc_memory_table_raddr r_addr;
4008c2ecf20Sopenharmony_ci	struct pdc_memory_table mem_table[MAX_PHYSMEM_RANGES];
4018c2ecf20Sopenharmony_ci	struct pdc_memory_table *mtbl_ptr;
4028c2ecf20Sopenharmony_ci	physmem_range_t *pmem_ptr;
4038c2ecf20Sopenharmony_ci	long status;
4048c2ecf20Sopenharmony_ci	int entries;
4058c2ecf20Sopenharmony_ci	int i;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	status = pdc_mem_mem_table(&r_addr,mem_table,
4088c2ecf20Sopenharmony_ci				(unsigned long)MAX_PHYSMEM_RANGES);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (status != PDC_OK) {
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		/* The above pdc call only works on boxes with sprockets
4138c2ecf20Sopenharmony_ci		 * firmware (newer B,C,J class). Other non PAT PDC machines
4148c2ecf20Sopenharmony_ci		 * do support more than 3.75 Gb of memory, but we don't
4158c2ecf20Sopenharmony_ci		 * support them yet.
4168c2ecf20Sopenharmony_ci		 */
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci		pagezero_memconfig();
4198c2ecf20Sopenharmony_ci		return;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (r_addr.entries_total > MAX_PHYSMEM_RANGES) {
4238c2ecf20Sopenharmony_ci		printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
4248c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Some memory will not be used!\n");
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	entries = (int)r_addr.entries_returned;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	npmem_ranges = 0;
4308c2ecf20Sopenharmony_ci	mtbl_ptr = mem_table;
4318c2ecf20Sopenharmony_ci	pmem_ptr = pmem_ranges; /* Global firmware independent table */
4328c2ecf20Sopenharmony_ci	for (i = 0; i < entries; i++,mtbl_ptr++) {
4338c2ecf20Sopenharmony_ci		set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
4348c2ecf20Sopenharmony_ci		npmem_ranges++;
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci#else   /* !CONFIG_64BIT */
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci#define pat_inventory() do { } while (0)
4418c2ecf20Sopenharmony_ci#define pat_memconfig() do { } while (0)
4428c2ecf20Sopenharmony_ci#define sprockets_memconfig() pagezero_memconfig()
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci#endif	/* !CONFIG_64BIT */
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci#ifndef CONFIG_PA20
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci/* Code to support Snake machines (7[2350], 7[235]5, 715/Scorpio) */
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic struct parisc_device * __init
4528c2ecf20Sopenharmony_cilegacy_create_device(struct pdc_memory_map *r_addr,
4538c2ecf20Sopenharmony_ci		struct pdc_module_path *module_path)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct parisc_device *dev;
4568c2ecf20Sopenharmony_ci	int status = pdc_mem_map_hpa(r_addr, module_path);
4578c2ecf20Sopenharmony_ci	if (status != PDC_OK)
4588c2ecf20Sopenharmony_ci		return NULL;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	dev = alloc_pa_dev(r_addr->hpa, &module_path->path);
4618c2ecf20Sopenharmony_ci	if (dev == NULL)
4628c2ecf20Sopenharmony_ci		return NULL;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	register_parisc_device(dev);
4658c2ecf20Sopenharmony_ci	return dev;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci/**
4698c2ecf20Sopenharmony_ci * snake_inventory
4708c2ecf20Sopenharmony_ci *
4718c2ecf20Sopenharmony_ci * Before PDC_SYSTEM_MAP was invented, the PDC_MEM_MAP call was used.
4728c2ecf20Sopenharmony_ci * To use it, we initialise the mod_path.bc to 0xff and try all values of
4738c2ecf20Sopenharmony_ci * mod to get the HPA for the top-level devices.  Bus adapters may have
4748c2ecf20Sopenharmony_ci * sub-devices which are discovered by setting bc[5] to 0 and bc[4] to the
4758c2ecf20Sopenharmony_ci * module, then trying all possible functions.
4768c2ecf20Sopenharmony_ci */
4778c2ecf20Sopenharmony_cistatic void __init snake_inventory(void)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	int mod;
4808c2ecf20Sopenharmony_ci	for (mod = 0; mod < 16; mod++) {
4818c2ecf20Sopenharmony_ci		struct parisc_device *dev;
4828c2ecf20Sopenharmony_ci		struct pdc_module_path module_path;
4838c2ecf20Sopenharmony_ci		struct pdc_memory_map r_addr;
4848c2ecf20Sopenharmony_ci		unsigned int func;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		memset(module_path.path.bc, 0xff, 6);
4878c2ecf20Sopenharmony_ci		module_path.path.mod = mod;
4888c2ecf20Sopenharmony_ci		dev = legacy_create_device(&r_addr, &module_path);
4898c2ecf20Sopenharmony_ci		if ((!dev) || (dev->id.hw_type != HPHW_BA))
4908c2ecf20Sopenharmony_ci			continue;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		memset(module_path.path.bc, 0xff, 4);
4938c2ecf20Sopenharmony_ci		module_path.path.bc[4] = mod;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		for (func = 0; func < 16; func++) {
4968c2ecf20Sopenharmony_ci			module_path.path.bc[5] = 0;
4978c2ecf20Sopenharmony_ci			module_path.path.mod = func;
4988c2ecf20Sopenharmony_ci			legacy_create_device(&r_addr, &module_path);
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci#else /* CONFIG_PA20 */
5048c2ecf20Sopenharmony_ci#define snake_inventory() do { } while (0)
5058c2ecf20Sopenharmony_ci#endif  /* CONFIG_PA20 */
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci/* Common 32/64 bit based code goes here */
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci/**
5108c2ecf20Sopenharmony_ci * add_system_map_addresses - Add additional addresses to the parisc device.
5118c2ecf20Sopenharmony_ci * @dev: The parisc device.
5128c2ecf20Sopenharmony_ci * @num_addrs: Then number of addresses to add;
5138c2ecf20Sopenharmony_ci * @module_instance: The system_map module instance.
5148c2ecf20Sopenharmony_ci *
5158c2ecf20Sopenharmony_ci * This function adds any additional addresses reported by the system_map
5168c2ecf20Sopenharmony_ci * firmware to the parisc device.
5178c2ecf20Sopenharmony_ci */
5188c2ecf20Sopenharmony_cistatic void __init
5198c2ecf20Sopenharmony_ciadd_system_map_addresses(struct parisc_device *dev, int num_addrs,
5208c2ecf20Sopenharmony_ci			 int module_instance)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	int i;
5238c2ecf20Sopenharmony_ci	long status;
5248c2ecf20Sopenharmony_ci	struct pdc_system_map_addr_info addr_result;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	dev->addr = kmalloc_array(num_addrs, sizeof(*dev->addr), GFP_KERNEL);
5278c2ecf20Sopenharmony_ci	if(!dev->addr) {
5288c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s %s(): memory allocation failure\n",
5298c2ecf20Sopenharmony_ci		       __FILE__, __func__);
5308c2ecf20Sopenharmony_ci		return;
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	for(i = 1; i <= num_addrs; ++i) {
5348c2ecf20Sopenharmony_ci		status = pdc_system_map_find_addrs(&addr_result,
5358c2ecf20Sopenharmony_ci						   module_instance, i);
5368c2ecf20Sopenharmony_ci		if(PDC_OK == status) {
5378c2ecf20Sopenharmony_ci			dev->addr[dev->num_addrs] = (unsigned long)addr_result.mod_addr;
5388c2ecf20Sopenharmony_ci			dev->num_addrs++;
5398c2ecf20Sopenharmony_ci		} else {
5408c2ecf20Sopenharmony_ci			printk(KERN_WARNING
5418c2ecf20Sopenharmony_ci			       "Bad PDC_FIND_ADDRESS status return (%ld) for index %d\n",
5428c2ecf20Sopenharmony_ci			       status, i);
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci/**
5488c2ecf20Sopenharmony_ci * system_map_inventory - Retrieve firmware devices via SYSTEM_MAP.
5498c2ecf20Sopenharmony_ci *
5508c2ecf20Sopenharmony_ci * This function attempts to retrieve and register all the devices firmware
5518c2ecf20Sopenharmony_ci * knows about via the SYSTEM_MAP PDC call.
5528c2ecf20Sopenharmony_ci */
5538c2ecf20Sopenharmony_cistatic void __init system_map_inventory(void)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	int i;
5568c2ecf20Sopenharmony_ci	long status = PDC_OK;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++) {
5598c2ecf20Sopenharmony_ci		struct parisc_device *dev;
5608c2ecf20Sopenharmony_ci		struct pdc_system_map_mod_info module_result;
5618c2ecf20Sopenharmony_ci		struct pdc_module_path module_path;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci		status = pdc_system_map_find_mods(&module_result,
5648c2ecf20Sopenharmony_ci				&module_path, i);
5658c2ecf20Sopenharmony_ci		if ((status == PDC_BAD_PROC) || (status == PDC_NE_MOD))
5668c2ecf20Sopenharmony_ci			break;
5678c2ecf20Sopenharmony_ci		if (status != PDC_OK)
5688c2ecf20Sopenharmony_ci			continue;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		dev = alloc_pa_dev(module_result.mod_addr, &module_path.path);
5718c2ecf20Sopenharmony_ci		if (!dev)
5728c2ecf20Sopenharmony_ci			continue;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		register_parisc_device(dev);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		/* if available, get the additional addresses for a module */
5778c2ecf20Sopenharmony_ci		if (!module_result.add_addrs)
5788c2ecf20Sopenharmony_ci			continue;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		add_system_map_addresses(dev, module_result.add_addrs, i);
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	walk_central_bus();
5848c2ecf20Sopenharmony_ci	return;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_civoid __init do_memory_inventory(void)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	switch (pdc_type) {
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	case PDC_TYPE_PAT:
5928c2ecf20Sopenharmony_ci		pat_memconfig();
5938c2ecf20Sopenharmony_ci		break;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	case PDC_TYPE_SYSTEM_MAP:
5968c2ecf20Sopenharmony_ci		sprockets_memconfig();
5978c2ecf20Sopenharmony_ci		break;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	case PDC_TYPE_SNAKE:
6008c2ecf20Sopenharmony_ci		pagezero_memconfig();
6018c2ecf20Sopenharmony_ci		return;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	default:
6048c2ecf20Sopenharmony_ci		panic("Unknown PDC type!\n");
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	if (npmem_ranges == 0 || pmem_ranges[0].start_pfn != 0) {
6088c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Bad memory configuration returned!\n");
6098c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Some memory may not be used!\n");
6108c2ecf20Sopenharmony_ci		pagezero_memconfig();
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_civoid __init do_device_inventory(void)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	printk(KERN_INFO "Searching for devices...\n");
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	init_parisc_bus();
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	switch (pdc_type) {
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	case PDC_TYPE_PAT:
6238c2ecf20Sopenharmony_ci		pat_inventory();
6248c2ecf20Sopenharmony_ci		break;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	case PDC_TYPE_SYSTEM_MAP:
6278c2ecf20Sopenharmony_ci		system_map_inventory();
6288c2ecf20Sopenharmony_ci		break;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	case PDC_TYPE_SNAKE:
6318c2ecf20Sopenharmony_ci		snake_inventory();
6328c2ecf20Sopenharmony_ci		break;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	default:
6358c2ecf20Sopenharmony_ci		panic("Unknown PDC type!\n");
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci	printk(KERN_INFO "Found devices:\n");
6388c2ecf20Sopenharmony_ci	print_parisc_devices();
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
6418c2ecf20Sopenharmony_ci	pa_serialize_tlb_flushes = machine_has_merced_bus();
6428c2ecf20Sopenharmony_ci	if (pa_serialize_tlb_flushes)
6438c2ecf20Sopenharmony_ci		pr_info("Merced bus found: Enable PxTLB serialization.\n");
6448c2ecf20Sopenharmony_ci#endif
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci#if defined(CONFIG_FW_CFG_SYSFS)
6478c2ecf20Sopenharmony_ci	if (running_on_qemu) {
6488c2ecf20Sopenharmony_ci		struct resource res[3] = {0,};
6498c2ecf20Sopenharmony_ci		unsigned int base;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci		base = ((unsigned long long) PAGE0->pad0[2] << 32)
6528c2ecf20Sopenharmony_ci			| PAGE0->pad0[3]; /* SeaBIOS stored it here */
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci		res[0].name = "fw_cfg";
6558c2ecf20Sopenharmony_ci		res[0].start = base;
6568c2ecf20Sopenharmony_ci		res[0].end = base + 8 - 1;
6578c2ecf20Sopenharmony_ci		res[0].flags = IORESOURCE_MEM;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		res[1].name = "ctrl";
6608c2ecf20Sopenharmony_ci		res[1].start = 0;
6618c2ecf20Sopenharmony_ci		res[1].flags = IORESOURCE_REG;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		res[2].name = "data";
6648c2ecf20Sopenharmony_ci		res[2].start = 4;
6658c2ecf20Sopenharmony_ci		res[2].flags = IORESOURCE_REG;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		if (base) {
6688c2ecf20Sopenharmony_ci			pr_info("Found qemu fw_cfg interface at %#08x\n", base);
6698c2ecf20Sopenharmony_ci			platform_device_register_simple("fw_cfg",
6708c2ecf20Sopenharmony_ci				PLATFORM_DEVID_NONE, res, 3);
6718c2ecf20Sopenharmony_ci		}
6728c2ecf20Sopenharmony_ci	}
6738c2ecf20Sopenharmony_ci#endif
6748c2ecf20Sopenharmony_ci}
675