Commit 8780d138 authored by Dave Jones's avatar Dave Jones

[PATCH] Add support for National Semiconductor x86's.

These are mostly Cyrix-alike, but for some quirks we work around.
parent db8b4099
...@@ -99,6 +99,8 @@ ...@@ -99,6 +99,8 @@
#endif #endif
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/console.h> #include <linux/console.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -1244,7 +1246,7 @@ static int __init init_amd(struct cpuinfo_x86 *c) ...@@ -1244,7 +1246,7 @@ static int __init init_amd(struct cpuinfo_x86 *c)
} }
/* /*
* Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
*/ */
static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
{ {
...@@ -1319,7 +1321,7 @@ extern void calibrate_delay(void) __init; ...@@ -1319,7 +1321,7 @@ extern void calibrate_delay(void) __init;
static void __init check_cx686_slop(struct cpuinfo_x86 *c) static void __init check_cx686_slop(struct cpuinfo_x86 *c)
{ {
unsigned long flags; unsigned long flags;
if (Cx86_dir0_msb == 3) { if (Cx86_dir0_msb == 3) {
unsigned char ccr3, ccr5; unsigned char ccr3, ccr5;
...@@ -1329,7 +1331,7 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c) ...@@ -1329,7 +1331,7 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c)
ccr5 = getCx86(CX86_CCR5); ccr5 = getCx86(CX86_CCR5);
if (ccr5 & 2) if (ccr5 & 2)
setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */ setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */
setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
local_irq_restore(flags); local_irq_restore(flags);
if (ccr5 & 2) { /* possible wrong calibration done */ if (ccr5 & 2) { /* possible wrong calibration done */
...@@ -1340,6 +1342,7 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c) ...@@ -1340,6 +1342,7 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c)
} }
} }
static void __init init_cyrix(struct cpuinfo_x86 *c) static void __init init_cyrix(struct cpuinfo_x86 *c)
{ {
unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
...@@ -1406,17 +1409,12 @@ static void __init init_cyrix(struct cpuinfo_x86 *c) ...@@ -1406,17 +1409,12 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
break; break;
case 4: /* MediaGX/GXm */ case 4: /* MediaGX/GXm */
/*
* Life sometimes gets weiiiiiiiird if we use this
* on the MediaGX. So we turn it off for now.
*/
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
/* It isnt really a PCI quirk directly, but the cure is the /* It isn't really a PCI quirk directly, but the cure is the
same. The MediaGX has deep magic SMM stuff that handles the same. The MediaGX has deep magic SMM stuff that handles the
SB emulation. It thows away the fifo on disable_dma() which SB emulation. It thows away the fifo on disable_dma() which
is wrong and ruins the audio. is wrong and ruins the audio.
Bug2: VSA1 has a wrap bug so that using maximum sized DMA Bug2: VSA1 has a wrap bug so that using maximum sized DMA
causes bad things. According to NatSemi VSA2 has another causes bad things. According to NatSemi VSA2 has another
bug to do with 'hlt'. I've not seen any boards using VSA2 bug to do with 'hlt'. I've not seen any boards using VSA2
...@@ -1431,15 +1429,26 @@ static void __init init_cyrix(struct cpuinfo_x86 *c) ...@@ -1431,15 +1429,26 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
/* GXm supports extended cpuid levels 'ala' AMD */ /* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) { if (c->cpuid_level == 2) {
/* Enable Natsemi MMX extensions */
setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
get_model_name(c); /* get CPU marketing name */ get_model_name(c); /* get CPU marketing name */
clear_bit(X86_FEATURE_TSC, c->x86_capability); /*
* The 5510/5520 companion chips have a funky PIT
* that breaks the TSC synchronizing, so turn it off
*/
if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
clear_bit(X86_FEATURE_TSC, c->x86_capability);
return; return;
} }
else { /* MediaGX */ else { /* MediaGX */
Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4'; Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
p = Cx86_cb+2; p = Cx86_cb+2;
c->x86_model = (dir1 & 0x20) ? 1 : 2; c->x86_model = (dir1 & 0x20) ? 1 : 2;
#ifndef CONFIG_CS5520
clear_bit(X86_FEATURE_TSC, &c->x86_capability); clear_bit(X86_FEATURE_TSC, &c->x86_capability);
#endif
} }
break; break;
...@@ -1457,7 +1466,7 @@ static void __init init_cyrix(struct cpuinfo_x86 *c) ...@@ -1457,7 +1466,7 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
p = Cx86_cb+tmp; p = Cx86_cb+tmp;
if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
(c->x86_model)++; (c->x86_model)++;
/* Emulate MTRRs using Cyrix's ARRs. */ /* Emulate MTRRs using Cyrix's ARRs. */
set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability); set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
...@@ -2100,7 +2109,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) ...@@ -2100,7 +2109,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
} }
if ( l1i || l1d ) if ( l1i || l1d )
printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n", printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
l1i, l1d); l1i, l1d);
if ( l2 ) if ( l2 )
printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
if ( l3 ) if ( l3 )
...@@ -2207,6 +2216,8 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c) ...@@ -2207,6 +2216,8 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c)
c->x86_vendor = X86_VENDOR_AMD; c->x86_vendor = X86_VENDOR_AMD;
else if (!strcmp(v, "CyrixInstead")) else if (!strcmp(v, "CyrixInstead"))
c->x86_vendor = X86_VENDOR_CYRIX; c->x86_vendor = X86_VENDOR_CYRIX;
else if (!strcmp(v, "Geode by NSC"))
c->x86_vendor = X86_VENDOR_NSC;
else if (!strcmp(v, "UMC UMC UMC ")) else if (!strcmp(v, "UMC UMC UMC "))
c->x86_vendor = X86_VENDOR_UMC; c->x86_vendor = X86_VENDOR_UMC;
else if (!strcmp(v, "CentaurHauls")) else if (!strcmp(v, "CentaurHauls"))
...@@ -2532,24 +2543,6 @@ void __init identify_cpu(struct cpuinfo_x86 *c) ...@@ -2532,24 +2543,6 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
* indicate the features this CPU genuinely supports! * indicate the features this CPU genuinely supports!
*/ */
switch ( c->x86_vendor ) { switch ( c->x86_vendor ) {
case X86_VENDOR_UNKNOWN:
default:
/* Not much we can do here... */
/* Check if at least it has cpuid */
if (c->cpuid_level == -1)
{
/* No cpuid. It must be an ancient CPU */
if (c->x86 == 4)
strcpy(c->x86_model_id, "486");
else if (c->x86 == 3)
strcpy(c->x86_model_id, "386");
}
break;
case X86_VENDOR_CYRIX:
init_cyrix(c);
break;
case X86_VENDOR_AMD: case X86_VENDOR_AMD:
init_amd(c); init_amd(c);
break; break;
...@@ -2558,6 +2551,10 @@ void __init identify_cpu(struct cpuinfo_x86 *c) ...@@ -2558,6 +2551,10 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
init_centaur(c); init_centaur(c);
break; break;
case X86_VENDOR_CYRIX:
init_cyrix(c);
break;
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
init_intel(c); init_intel(c);
break; break;
...@@ -2566,13 +2563,32 @@ void __init identify_cpu(struct cpuinfo_x86 *c) ...@@ -2566,13 +2563,32 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
c->x86_cache_size = 256; /* A few had 1 MB... */ c->x86_cache_size = 256; /* A few had 1 MB... */
break; break;
case X86_VENDOR_TRANSMETA: case X86_VENDOR_NSC:
init_transmeta(c); init_cyrix(c);
break; break;
case X86_VENDOR_RISE: case X86_VENDOR_RISE:
init_rise(c); init_rise(c);
break; break;
case X86_VENDOR_TRANSMETA:
init_transmeta(c);
break;
case X86_VENDOR_UNKNOWN:
default:
/* Not much we can do here... */
/* Check if at least it has cpuid */
if (c->cpuid_level == -1)
{
/* No cpuid. It must be an ancient CPU */
if (c->x86 == 4)
strcpy(c->x86_model_id, "486");
else if (c->x86 == 3)
strcpy(c->x86_model_id, "386");
}
break;
} }
printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n", printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
...@@ -2650,14 +2666,15 @@ void __init dodgy_tsc(void) ...@@ -2650,14 +2666,15 @@ void __init dodgy_tsc(void)
{ {
get_cpu_vendor(&boot_cpu_data); get_cpu_vendor(&boot_cpu_data);
if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
( boot_cpu_data.x86_vendor == X86_VENDOR_NSC ))
init_cyrix(&boot_cpu_data); init_cyrix(&boot_cpu_data);
} }
/* These need to match <asm/processor.h> */ /* These need to match <asm/processor.h> */
static char *cpu_vendor_names[] __initdata = { static char *cpu_vendor_names[] __initdata = {
"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" }; "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta", "NSC" };
void __init print_cpu_info(struct cpuinfo_x86 *c) void __init print_cpu_info(struct cpuinfo_x86 *c)
...@@ -2698,10 +2715,10 @@ static int show_cpuinfo(struct seq_file *m, void *v) ...@@ -2698,10 +2715,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
*/ */
static char *x86_cap_flags[] = { static char *x86_cap_flags[] = {
/* Intel-defined */ /* Intel-defined */
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
"fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
/* AMD-defined */ /* AMD-defined */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
......
...@@ -59,6 +59,7 @@ struct cpuinfo_x86 { ...@@ -59,6 +59,7 @@ struct cpuinfo_x86 {
#define X86_VENDOR_CENTAUR 5 #define X86_VENDOR_CENTAUR 5
#define X86_VENDOR_RISE 6 #define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7 #define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NSC 8
#define X86_VENDOR_UNKNOWN 0xff #define X86_VENDOR_UNKNOWN 0xff
/* /*
...@@ -216,7 +217,7 @@ static inline void clear_in_cr4 (unsigned long mask) ...@@ -216,7 +217,7 @@ static inline void clear_in_cr4 (unsigned long mask)
} }
/* /*
* Cyrix CPU configuration register indexes * NSC/Cyrix CPU configuration register indexes
*/ */
#define CX86_CCR0 0xc0 #define CX86_CCR0 0xc0
#define CX86_CCR1 0xc1 #define CX86_CCR1 0xc1
...@@ -232,7 +233,7 @@ static inline void clear_in_cr4 (unsigned long mask) ...@@ -232,7 +233,7 @@ static inline void clear_in_cr4 (unsigned long mask)
#define CX86_RCR_BASE 0xdc #define CX86_RCR_BASE 0xdc
/* /*
* Cyrix CPU indexed register access macros * NSC/Cyrix CPU indexed register access macros
*/ */
#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); }) #define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment