18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * idprom.c: Routines to load the idprom into kernel addresses and
48c2ecf20Sopenharmony_ci *           interpret the data contained within.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
78c2ecf20Sopenharmony_ci * Sun3/3x models added by David Monro (davidm@psrg.cs.usyd.edu.au)
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/types.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/string.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <asm/oplib.h>
178c2ecf20Sopenharmony_ci#include <asm/idprom.h>
188c2ecf20Sopenharmony_ci#include <asm/machines.h>  /* Fun with Sun released architectures. */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct idprom *idprom;
218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(idprom);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic struct idprom idprom_buffer;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* Here is the master table of Sun machines which use some implementation
268c2ecf20Sopenharmony_ci * of the Sparc CPU and have a meaningful IDPROM machtype value that we
278c2ecf20Sopenharmony_ci * know about.  See asm-sparc/machines.h for empirical constants.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistatic struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
308c2ecf20Sopenharmony_ci/* First, Sun3's */
318c2ecf20Sopenharmony_ci    { .name = "Sun 3/160 Series",	.id_machtype = (SM_SUN3 | SM_3_160) },
328c2ecf20Sopenharmony_ci    { .name = "Sun 3/50",		.id_machtype = (SM_SUN3 | SM_3_50) },
338c2ecf20Sopenharmony_ci    { .name = "Sun 3/260 Series",	.id_machtype = (SM_SUN3 | SM_3_260) },
348c2ecf20Sopenharmony_ci    { .name = "Sun 3/110 Series",	.id_machtype = (SM_SUN3 | SM_3_110) },
358c2ecf20Sopenharmony_ci    { .name = "Sun 3/60",		.id_machtype = (SM_SUN3 | SM_3_60) },
368c2ecf20Sopenharmony_ci    { .name = "Sun 3/E",		.id_machtype = (SM_SUN3 | SM_3_E) },
378c2ecf20Sopenharmony_ci/* Now, Sun3x's */
388c2ecf20Sopenharmony_ci    { .name = "Sun 3/460 Series",	.id_machtype = (SM_SUN3X | SM_3_460) },
398c2ecf20Sopenharmony_ci    { .name = "Sun 3/80",		.id_machtype = (SM_SUN3X | SM_3_80) },
408c2ecf20Sopenharmony_ci/* Then, Sun4's */
418c2ecf20Sopenharmony_ci// { .name = "Sun 4/100 Series",	.id_machtype = (SM_SUN4 | SM_4_110) },
428c2ecf20Sopenharmony_ci// { .name = "Sun 4/200 Series",	.id_machtype = (SM_SUN4 | SM_4_260) },
438c2ecf20Sopenharmony_ci// { .name = "Sun 4/300 Series",	.id_machtype = (SM_SUN4 | SM_4_330) },
448c2ecf20Sopenharmony_ci// { .name = "Sun 4/400 Series",	.id_machtype = (SM_SUN4 | SM_4_470) },
458c2ecf20Sopenharmony_ci/* And now, Sun4c's */
468c2ecf20Sopenharmony_ci// { .name = "Sun4c SparcStation 1",	.id_machtype = (SM_SUN4C | SM_4C_SS1) },
478c2ecf20Sopenharmony_ci// { .name = "Sun4c SparcStation IPC",	.id_machtype = (SM_SUN4C | SM_4C_IPC) },
488c2ecf20Sopenharmony_ci// { .name = "Sun4c SparcStation 1+",	.id_machtype = (SM_SUN4C | SM_4C_SS1PLUS) },
498c2ecf20Sopenharmony_ci// { .name = "Sun4c SparcStation SLC",	.id_machtype = (SM_SUN4C | SM_4C_SLC) },
508c2ecf20Sopenharmony_ci// { .name = "Sun4c SparcStation 2",	.id_machtype = (SM_SUN4C | SM_4C_SS2) },
518c2ecf20Sopenharmony_ci// { .name = "Sun4c SparcStation ELC",	.id_machtype = (SM_SUN4C | SM_4C_ELC) },
528c2ecf20Sopenharmony_ci// { .name = "Sun4c SparcStation IPX",	.id_machtype = (SM_SUN4C | SM_4C_IPX) },
538c2ecf20Sopenharmony_ci/* Finally, early Sun4m's */
548c2ecf20Sopenharmony_ci// { .name = "Sun4m SparcSystem600",	.id_machtype = (SM_SUN4M | SM_4M_SS60) },
558c2ecf20Sopenharmony_ci// { .name = "Sun4m SparcStation10/20",	.id_machtype = (SM_SUN4M | SM_4M_SS50) },
568c2ecf20Sopenharmony_ci// { .name = "Sun4m SparcStation5",	.id_machtype = (SM_SUN4M | SM_4M_SS40) },
578c2ecf20Sopenharmony_ci/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
588c2ecf20Sopenharmony_ci// { .name = "Sun4M OBP based system",	.id_machtype = (SM_SUN4M_OBP | 0x0) }
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic void __init display_system_type(unsigned char machtype)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	register int i;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_SUN_MACHINES; i++) {
668c2ecf20Sopenharmony_ci		if(Sun_Machines[i].id_machtype == machtype) {
678c2ecf20Sopenharmony_ci			if (machtype != (SM_SUN4M_OBP | 0x00))
688c2ecf20Sopenharmony_ci				pr_info("TYPE: %s\n", Sun_Machines[i].name);
698c2ecf20Sopenharmony_ci			else {
708c2ecf20Sopenharmony_ci#if 0
718c2ecf20Sopenharmony_ci				char sysname[128];
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci				prom_getproperty(prom_root_node, "banner-name",
748c2ecf20Sopenharmony_ci						 sysname, sizeof(sysname));
758c2ecf20Sopenharmony_ci				pr_info("TYPE: %s\n", sysname);
768c2ecf20Sopenharmony_ci#endif
778c2ecf20Sopenharmony_ci			}
788c2ecf20Sopenharmony_ci			return;
798c2ecf20Sopenharmony_ci		}
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	prom_printf("IDPROM: Bogus id_machtype value, 0x%x\n", machtype);
838c2ecf20Sopenharmony_ci	prom_halt();
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_civoid sun3_get_model(unsigned char* model)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	register int i;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_SUN_MACHINES; i++) {
918c2ecf20Sopenharmony_ci		if(Sun_Machines[i].id_machtype == idprom->id_machtype) {
928c2ecf20Sopenharmony_ci		        strcpy(model, Sun_Machines[i].name);
938c2ecf20Sopenharmony_ci			return;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/* Calculate the IDPROM checksum (xor of the data bytes). */
1018c2ecf20Sopenharmony_cistatic unsigned char __init calc_idprom_cksum(struct idprom *idprom)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	unsigned char cksum, i, *ptr = (unsigned char *)idprom;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	for (i = cksum = 0; i <= 0x0E; i++)
1068c2ecf20Sopenharmony_ci		cksum ^= *ptr++;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return cksum;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* Create a local IDPROM copy, verify integrity, and display information. */
1128c2ecf20Sopenharmony_civoid __init idprom_init(void)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	idprom = &idprom_buffer;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (idprom->id_format != 0x01)  {
1198c2ecf20Sopenharmony_ci		prom_printf("IDPROM: Unknown format type!\n");
1208c2ecf20Sopenharmony_ci		prom_halt();
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
1248c2ecf20Sopenharmony_ci		prom_printf("IDPROM: Checksum failure (nvram=%x, calc=%x)!\n",
1258c2ecf20Sopenharmony_ci			    idprom->id_cksum, calc_idprom_cksum(idprom));
1268c2ecf20Sopenharmony_ci		prom_halt();
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	display_system_type(idprom->id_machtype);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	pr_info("Ethernet address: %pM\n", idprom->id_ethaddr);
1328c2ecf20Sopenharmony_ci}
133