/*
 * milo/identify.c -- Identify the system we're running on
 *
 * Copyright (C) 1994, 1995 by Waldorf Electronics,
 * written by Andreas Busse and Ralf Baechle
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License. See the file COPYING in the main directory of this archive for more
 * details.
 */
#include <linux/string.h>

#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/segment.h>

#include <arc/arc.h>
#include <stand/identify.h>

extern int __hw_type;

/*
 * Prototypes
 */
int cputype(int id);
char *cpuname(int type);

extern struct bootinfo bi;

unsigned int icache_size     = 0; /* FIXME: cachectl.S needs these */
unsigned int icache_linesize = 0;
unsigned int dcache_size     = 0;
unsigned int dcache_linesize = 0;
unsigned int scache_size     = 0;
unsigned int scache_linesize = 0;


/*
 * identify()
 */
void identify(void)
{
  char *VendorId;		/* ARC vendor ID */
  char *ProductId;		/* ARC product ID */
  char *SystemId;		/* ARC system ID */
  int  prid;
  int  type;
  int  config;
  int i;
  
  /*
   * Get system information from ARC BIOS 
   */
  VendorId = getVendorId();
  ProductId = getProductId();
  printf("ARC Vendor  ID          : [%s]\r\n",VendorId);
  printf("ARC Product ID          : [");
  for(i=0; i<8; i++)
    printf("%02x",(unsigned char)ProductId[i]);
  printf("]\r\n");
  SystemId = getSystemId();
  printf("ARC System  ID          : [%s]\r\n",SystemId);

  /*
   * Get CPU Info
   */
  printf("ARC CPU ID              : [%s]\r\n",getCpuType());
  prid = read_32bit_cp0_register(CP0_PRID);
  type = cputype(prid);
  printf("Processor type          : [%s I%02x V%d.%d]\r\n",
	 cpuname(type),
	 prid >> 8, (prid & 0xf0) >> 4,prid & 0x0f);

  /*
   * Get cache and cache line sizes
   */
  config = read_32bit_cp0_register(CP0_CONFIG);
  icache_size = bi.icache_size = 1 << (12 + ((config & 0xe00) >> 9));
  dcache_size = bi.dcache_size = 1 << (12 + ((config & 0x1c0) >> 6));
  icache_linesize = bi.icache_linesize = 16 << ((config & 0x20) >> 5);
  dcache_linesize = bi.dcache_linesize = 16 << ((config & 0x10) >> 4);
  
  printf("Primary ICache size     : [0x%04x bytes]\r\n",icache_size);
  printf("Primary ICache line size: [0x%04x bytes]\r\n",icache_linesize);
  printf("Primary DCache size     : [0x%04x bytes]\r\n",dcache_size);
  printf("Primary DCache line size: [0x%04x bytes]\r\n",dcache_linesize);

  printf("Secondary cache size    : ");
  if ((bi.scache_size = getSecondaryCacheSize()) != SIZE_UNKNOWN)
    printf("[0x%4x]\r\n",bi.scache_size);
  else
    printf("[unknown]\r\n");

  /*
   * print some nice info about the system we have identified.
   * FIXME: this should go into a global array some time...
   * And we still need a way to find out how many memory we have!
   */
  
  printf("ARC system identified as: ");
  if (!strcmp("PICA-61",SystemId))
  {
      printf("ACER PICA-61\r\n");
      bi.machtype        = MACH_ACER_PICA_61;
      bi.cputype         = type;
      bi.memlower        = KSEG0;
      bi.memupper        = KSEG0 + acer_pica_61_mem();
      bi.scache_size     = 512*1024;
      bi.dma_cache_size  = 0;
      bi.vram_base       = 0xe08b8000; /* for 80x25, 640x480 */
      bi.tlb_entries     = 48;
  }
  else if (!strcmp("DESKTECH-ARCStation I",SystemId))
  {
      /*
       * RB: This entry is absolutly untested - I don't have
       * even a hint about how the L2 cache works, so I make
       * the guess that it works just like the Tyne board.
       */
      printf("DeskStation rPC44\r\n");
      bi.machtype        = MACH_DESKSTATION_RPC44;
      bi.cputype         = type;
      bi.memlower        = KSEG0;
      bi.memupper        = 0x80800000;
      bi.scache_size     = 512*1024;
      bi.dma_cache_size  = 512*1024;
      bi.vram_base       = 0xe10a0000;
      bi.tlb_entries     = 48;
  }
  else if (!strcmp("DESKTECH-TYNE",SystemId))
  {
      printf("DeskStation Tyne\r\n");
      bi.machtype        = MACH_DESKSTATION_TYNE;
      bi.cputype         = type;
      bi.memlower        = KSEG0;
      bi.memupper        = 0x80800000;
      bi.scache_size     = 512*1024;
      bi.dma_cache_size  = 512*1024;
      bi.vram_base       = 0xe10a0000;
      bi.tlb_entries     = 48;
  }
  else if (!strcmp("Microsoft-Jazz",SystemId))
  {
      printf("Mips Magnum 4000 (Jazz)\r\n");
      bi.machtype        = MACH_MIPS_MAGNUM_4000;
      bi.cputype         = type;
      bi.memlower        = KSEG0;
      bi.memupper        = 0x80800000;
      bi.scache_size     = 0;
      bi.dma_cache_size  = 0;
      bi.vram_base       = 0xe0800000; /* FIXME: true for 1024x768 only */
      bi.tlb_entries     = 48;
  }
  else
  {
      /*
       * You don't really hope that Linux boot on such a system, don't you?
       */
      printf(" Not identified -- using default parameters\r\n");
      bi.machtype        = MACH_UNKNOWN;
      bi.cputype         = CPU_UNKNOWN;
      bi.memlower        = KSEG0;
      bi.memupper        = 0x80800000;
      bi.scache_size     = 0;
      bi.dma_cache_size  = 0;
      bi.vram_base       = 0;
      bi.tlb_entries     = 48;	/* true for all R4x00 except R4300i (32) */
  }

  __hw_type = bi.machtype;	/* let the library know about the hardware */
}

/*
 * cputype()
 * Extract cpu type from Processor Id
 * NOTE: This is not complete. Fill in here anything you know about.
 *
 * ID is organized as follows:
 *   Bits 31:16   always 0
 *   Bits 15:08   CPU Implementation
 *   Bits 07:04   CPU Version
 *   Bits 03:00   CPU Revision
 *
 * FIXME: CPU dependent stuff should go into a global array.
 */
int cputype(int id)
{
  switch (id >> 8)
    {
    case 0x01:
      return(CPU_R2000);

    case 0x02:
      return(CPU_R3000);

    case 0x03:
      return(CPU_R6000);
      
    case 0x04:			/* any of R4000xx and R4400xx */
      switch (id & 0xf0)
	{
	case 0x00:		/* R4000 */
	case 0x10:
	case 0x20:
	case 0x30:
	  return(CPU_R4000PC);
	  
	case 0x40:		/* R4400 V4.x with daddiu bug */
	case 0x50:		/* R4400 V5.x */
	  return(CPU_R4400PC);
	  
	default:
	  return(CPU_UNKNOWN);
	}
      break;

    case 0x05:			/* LSI Logic R3000 derivative */
      return(CPU_R3000);

    case 0x06:
      return(CPU_R6000A);

    case 0x07:
      return(CPU_R3051);		/* IDT 3051,3052 etc. */

    case 0x09:
      return(CPU_R10000);

    case 0x0a:
      return(CPU_R4200);

    case 0x10:
      return(CPU_R8000);

    case 0x20:
      return(CPU_R4600);	/* R4600 V1.x has an icache bug! */

    case 0x21:
      return(CPU_R3000);	/* Sony R3000 derivative */

    case 0x22:
      return(CPU_R3000);	/* Toshiba R3000 derivate */

    case 0x23:
      return(CPU_R3000);	/* NKK R3000 derivative */
      
    default:
      return(CPU_UNKNOWN);
      
    }
}

static char *cpu_name_strings[] = CPU_NAMES;
/*
 * cpuname()
 * Translate cputype into a processor name
 * FIXME: This should also go into a global array of cpu informations.
 *        Some of these CPUs are too stupid (no MMU) to run Linux.
 */
char *cpuname(int type)
{
    if(type >= CPU_LAST)
        type = CPU_UNKNOWN;

    return cpu_name_strings[type];
}
