* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: cpu-seeprom.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* - Do no alter or remove copyright notices
* - Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* - Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of Sun Microsystems, Inc. or the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or maintenance of
* ========== Copyright Header End ============================================
* id: @(#)cpu-seeprom.c 1.10 05/11/15
* copyright: Copyright 2005 Sun Microsystems, Inc. All Rights Reserved
* copyright: Use is subject to license terms.
#define ULTRA3_MODE 1 /* Ultra3 */
#define ULTRA3_PLUS 2 /* Ultra3+ in 2way E$ mode */
#define ULTRA3_PLUS_DM 3 /* Ultra3+ in direct mapped mode */
int format_mode
, id_magic
;
static int speed_ratio_max
= 6;
static int speed_ratio_min
= 4;
static int cpu_ratios_min
= 3;
static int cpu_ratios_bits
= 8; /* # of bits in cpu ratios fru parameter */
extern int system_type
, type
;
extern struct fixed_seeprom
*seeprom_data
;
set_magic_bytes(void *data
)
if ((int)data
!= CPU_DEFAULT_MAGIC
) {
set_format_byte(void *data
)
set_clk_div_byte(void *data
)
struct fixed_seeprom cpu_seeprom_data
[] = {
/* name size type value */
{ "id_magic", 2, NUM
, 0, set_magic_bytes
},
{ "id_format", 1, NUM
, 0, set_format_byte
},
{ "cpu_ratios", 1, NUM
, 0, NULL
},
{ "checksum", 2, NUM
, 0, NULL
},
{ "clk_divisor", 1, NUM
, 0, set_clk_div_byte
},
{ "cpu_id", 1, NUM
, 0, NULL
},
{ "dcr", 8, NUM
, 0, NULL
},
{ "lsucr", 8, NUM
, 0, NULL
},
{ "ecache_size", 4, NUM
, 0, NULL
},
{ "stick_divisor", 1, NUM
, 0, NULL
},
{ "speed_table_width", 1, NUM
, 0, NULL
},
{ "num_ecache_cfgs", 1, NUM
, 0, NULL
},
on excal, the next entry is a pad byte. Instead of defining
2 different structs with different names for this byte, we use
num_memc_cfgs and just leave it as 0 for excal.
{ "num_memc_cfgs", 1, NUM
, 0, NULL
},
/* { "pad", 1, NUM, 0, NULL }, */
struct fixed_seeprom gm_cpu_seeprom_data
[] = {
/* name size type value */
{ "id_magic", 2, NUM
, 0, set_magic_bytes
},
{ "id_format", 1, NUM
, 0, set_format_byte
},
{ "cpu_ratios", 1, NUM
, 0, NULL
},
{ "checksum", 2, NUM
, 0, NULL
},
{ "clk_divisor", 1, NUM
, 0, set_clk_div_byte
},
{ "cpu_id", 1, NUM
, 0, NULL
},
{ "dcr", 8, NUM
, 0, NULL
},
{ "lsucr", 8, NUM
, 0, NULL
},
{ "core_config", 8, NUM
, 0, NULL
},
{ "ecache_size", 4, NUM
, 0, NULL
},
{ "stick_divisor", 1, NUM
, 0, NULL
},
{ "speed_table_width", 1, NUM
, 0, NULL
},
{ "num_ecache_cfgs", 1, NUM
, 0, NULL
},
{ "num_memc_cfgs", 1, NUM
, 0, NULL
},
struct fixed_seeprom serrano_cpu_seeprom_data
[] = {
/* name size type value */
{ "id_magic", 2, NUM
, 0, set_magic_bytes
},
{ "id_format", 1, NUM
, 0, set_format_byte
},
{ "cpu_id", 1, NUM
, 0, NULL
},
{ "checksum", 2, NUM
, 0, NULL
},
{ "cpu_ratios", 2, NUM
, 0, NULL
},
{ "dcr", 8, NUM
, 0, NULL
},
{ "lsucr", 8, NUM
, 0, NULL
},
{ "ecache_size", 4, NUM
, 0, NULL
},
{ "clk_divisor", 1, NUM
, 0, set_clk_div_byte
},
{ "stick_divisor", 1, NUM
, 0, NULL
},
{ "speed_table_width", 1, NUM
, 0, NULL
},
{ "num_ecache_cfgs", 1, NUM
, 0, NULL
},
{ "num_memc_cfgs", 1, NUM
, 0, NULL
},
{ "pad", 7, NUM
, 0, NULL
},
struct fixed_seeprom cpu_rw_data
[] = {
/* name size type value */
{ "id_magic", 2, NUM
, 0, NULL
},
{ "id_format", 1, NUM
, 0, set_format_byte
},
{ "num_memc_cfgs", 1, NUM
, 0, NULL
},
static struct ecache_entry
*cpu_ecache_table
= NULL
;
static struct speed_entry
*speed_table
= NULL
;
static struct fiesta_memc_entry
*fiesta_memc
= NULL
;
calculate_mspd(unsigned short mclk
, unsigned long long mcr2
,
#define MEM_SPEED(a, b) ((cpuspeed * a) / b)
unsigned int mspeed
, mcr2_ratio
;
if (system_type
== SERRANO
) {
mcr2_ratio
= mcr2
& 0x1f;
mspeed
= MEM_SPEED(1, 8);
mspeed
= MEM_SPEED(1, 9);
mspeed
= MEM_SPEED(1, 10);
mspeed
= MEM_SPEED(2, 21);
mspeed
= MEM_SPEED(1, 11);
mspeed
= MEM_SPEED(1, 12);
mspeed
= MEM_SPEED(2, 25);
mspeed
= MEM_SPEED(1, 13);
mspeed
= MEM_SPEED(2, 27);
mspeed
= MEM_SPEED(1, 14);
mspeed
= MEM_SPEED(1, 15);
/* following entries with bit 4 set are Serrano only */
mspeed
= MEM_SPEED(1, 16);
mspeed
= MEM_SPEED(2, 33);
mspeed
= MEM_SPEED(2, 35);
mspeed
= MEM_SPEED(1, 18);
"memc_entry: Invalid CPU_SDRAM clk ratio %x",
"memc_entry: calculated mem speed %d exceeds mclk %hd",
* MCR0_CTL_MASK is used to check if following control bits are set
* in the memc_entries, they should be 0:
* X4DIMM, Addr_Gen, DIMMX_bankY, AUTO_REFRESH_EN, CKE_EN, CLK_UPDATE,
* PRECHG_ALL, SET_MODE_REG
#define MCR0_CTL_MASK -1 ^ 0x0ffffb03ff803fffLL
* Get fiesta_memc_entries parameters of format:
* memc_entry bus_max(Mhz) bus_min(Mhz) ratio mspeed mcr0 mcr1 mcr2
fiesta_memc_input(char *line
, struct fiesta_memc_entry
*entry
)
char parameter
[MAXNAMESIZE
];
unsigned short bus_hi
, bus_lo
, entry_id
, ratio
, mclk
;
unsigned long long mcr
[3];
entries
= sscanf(line
, "%32s %hd %hd %hd %hd %hd %llx %llx %llx",
parameter
, &bus_hi
, &bus_lo
, &entry_id
, &ratio
, &mclk
, &mcr
[0],
print_error("memc_entry line incorrectly defined");
print_error("memc_entry.bus_hi must be greater than bus_lo!");
if (entry_id
> FIESTA_MAX_MEMC
) {
sprintf(err_string
, "memc_entry: id cannot exceed %d",
entry
->entry_id
= entry_id
;
if (calculate_mspd(mclk
, mcr
[1], bus_hi
* ratio
)) {
sprintf(err_string
, "Error in memc_entry %d", entry_id
);
if (system_type
!= SERRANO
&& mclk
!= 133) {
print_error("memc_entry.mspd must be 133 only !");
if (mcr
[0] & ((unsigned long long) MCR0_CTL_MASK
)) {
sprintf(err_string
, "memc_entry id %d: "
"MCR0 control bits not zero. "
"Should be %llx\n", entry_id
,
mcr
[0] & (-1 ^ ((unsigned long long) MCR0_CTL_MASK
)));
for (i
= 0; i
< 3; i
++) {
* Get ecache_ctrl_reg parameters of format:
* ecache_ctrl_reg cpu_max(Mhz) cpu_min(Mhz) ecache_ctrl_reg_default
get_ecache_input(char *line
, struct ecache_entry
*entry
)
char parameter
[MAXNAMESIZE
];
unsigned short cpu_max
, cpu_min
;
unsigned long long ecache
[2];
entries
= sscanf(line
, "%32s %hd %hd %llx %llx",
parameter
, &cpu_max
, &cpu_min
, &ecache
[0], &ecache
[1]);
if ((entries
< 4) || (entries
> 5)) {
print_error("ecache_ctrl.reg line incorrectly defined");
print_error("ecache_ctrl.reg.cpu_max must be greater"
entry
->cpu_max
= cpu_max
;
entry
->cpu_min
= cpu_min
;
entry
->ecache_cfg
[0] = ecache
[0];
if (entries
== 5) entry
->ecache_cfg
[1] = ecache
[1];
* Add fiesta_memc_entry to data structure
update_fiesta_memc(struct fiesta_memc_entry
*entry
)
struct fiesta_memc_entry
*ptr
;
fiesta_memc
= malloc(sizeof (struct fiesta_memc_entry
));
while (ptr
->next
!= NULL
)
ptr
->next
= malloc(sizeof (struct fiesta_memc_entry
));
temp
= get_seeprom("num_memc_cfgs");
update_seeprom("num_memc_cfgs", temp
+1);
* Add ecache_ctrl_reg entry to data structure
update_ecache_table(struct ecache_entry
*entry
)
struct ecache_entry
*ptr
;
cpu_ecache_table
= malloc(sizeof (struct ecache_entry
));
*cpu_ecache_table
= *entry
;
while (ptr
->next
!= NULL
)
ptr
->next
= malloc(sizeof (struct ecache_entry
));
temp
= get_seeprom("num_ecache_cfgs");
update_seeprom("num_ecache_cfgs", temp
+1);
* Remove duplicate speed entries and sort from lowest to highest
sort_speed(unsigned short *speed_list
, int num_speeds
)
unsigned short sort_list
[MAXSPEEDLIST
];
if (speed_list
[0] > MAX_SAFARI_SPEED
) {
"cpu_sys_ratio.safari_speed must be <= %dMhz!",
lowest
= MAX_SAFARI_SPEED
;
for (j
= 0; j
< num_speeds
; j
++) {
if (speed_list
[j
] != 0) {
if (speed_list
[j
] > MAX_SAFARI_SPEED
) {
"cpu_sys_ratio.safari_speed "
lowest
= (lowest
<= speed_list
[j
]) ?
for (j
= 0; j
< num_speeds
; j
++) {
if (speed_list
[j
] == lowest
) {
speed_list
[j
] = sort_list
[j
];
* Update data structure with new speed entry
update_speeds(unsigned short *speeds
, unsigned short ratio
, int num_speeds
)
struct speed_entry
*ptr
, *prev
, *temp_ptr
;
unsigned long long cpu_ratios
;
* if we already have entries for this ratio, delete them
if (get_seeprom("cpu_ratios") & (1 << (ratio
- cpu_ratios_min
))) {
ptr
= prev
= speed_table
;
while (ptr
->ratio
!= ratio
) {
while ((ptr
!= NULL
) && (ptr
->ratio
== ratio
)) {
* add speeds for this ratio to the list
for (i
= 0; i
< num_speeds
; i
++) {
temp_ptr
= malloc(sizeof (struct speed_entry
));
temp_ptr
->speed_hi
= temp_ptr
->speed_lo
= speeds
[i
];
if (speed_table
== NULL
) {
while (ptr
->next
!= NULL
) {
cpu_ratios
= get_seeprom("cpu_ratios");
cpu_ratios
|= (1 << (ratio
- cpu_ratios_min
));
update_seeprom("cpu_ratios", cpu_ratios
);
Get cpu_sys_ratio parameters of format:
cpu_sys_ratio cpu/sys_ratio Valid_Safari_speed(Mhz)
Multiple valid Safari speeds may be separated by commas.
get_speed_input(char *line
, unsigned short *speeds
,
unsigned short *ratio
, int *num_speeds
)
char parameter
[MAXNAMESIZE
], speedinfo
[MAXLINE
];
if (sscanf(line
, "%32s %hd %s", parameter
, ratio
, speedinfo
) == 3) {
if ((*ratio
> speed_ratio_max
) || (*ratio
< speed_ratio_min
)) {
sprintf(err_string
, "Invalid cpu_sys_ratio: %d",
temp
= strtok(speedinfo
, ",");
if (sscanf(temp
, "%hd", &speeds
[i
++])) {
temp
= strtok(NULL
, ",");
"Invalid cpu_sys_ratio.safari_speed: %s",
*num_speeds
= sort_speed(speeds
, i
);
Calculate speed table width
static unsigned long long
unsigned short count
, biggest
;
while (ptr
->next
!= NULL
) {
if (ptr
->ratio
== ptr
->next
->ratio
) {
if (count
> biggest
) biggest
= count
;
cpu_dynamic(char *parameter
, char *line
)
if (strcmp(parameter
, "ecache_ctrl_reg") == 0) {
if (system_type
!= GMFIESTA
) {
struct ecache_entry new_ecache_entry
;
if (get_ecache_input(line
, &new_ecache_entry
))
update_ecache_table(&new_ecache_entry
);
} else if (strcmp(parameter
, "cpu_sys_ratio") == 0) {
unsigned short speed_list
[MAXSPEEDLIST
];
if (get_speed_input(line
, speed_list
, &ratio
, &num_speeds
))
update_speeds(speed_list
, ratio
, num_speeds
);
} else if (strcmp(parameter
, "memc_entry") == 0) {
struct fiesta_memc_entry new_memc_entry
;
if (!fiesta_memc_input(line
, &new_memc_entry
))
update_fiesta_memc(&new_memc_entry
);
struct ecache_entry
*ecache
, *tmp1
;
struct speed_entry
*speed
, *tmp2
;
struct fiesta_memc_entry
*memc
, *tmp3
;
if (cpu_ecache_table
!= NULL
) {
ecache
= cpu_ecache_table
;
while (ecache
->next
!= NULL
) {
if (speed_table
!= NULL
) {
while (speed
->next
!= NULL
) {
if (fiesta_memc
!= NULL
) {
while (memc
->next
!= NULL
) {
write_cpu(unsigned char **ptr
)
struct ecache_entry
*ecache
;
struct speed_entry
*speed
;
struct fiesta_memc_entry
*memc
;
ecache
= cpu_ecache_table
;
store_bytes(2, (unsigned long long) ecache
->cpu_max
, ptr
);
store_bytes(2, (unsigned long long) ecache
->cpu_min
, ptr
);
store_bytes(8, ecache
->ecache_cfg
[0], ptr
);
if (format_mode
== 2 || format_mode
== 3) {
store_bytes(8, ecache
->ecache_cfg
[1], ptr
);
if (fixed_parameter("speed_table_width")) {
int width
= (int)get_seeprom("speed_table_width");
for (i
= 0; i
< cpu_ratios_bits
; i
++, found
= 0) {
if (get_seeprom("cpu_ratios") & (1 << i
)) {
ratio
= i
+ cpu_ratios_min
;
* Stay at this ratio until all found and
if (speed
->ratio
== ratio
) {
store_bytes(1, speed
->speed_hi
,
store_bytes(1, speed
->speed_lo
,
while (found
++ < width
) {
store_bytes(2, (unsigned long long) memc
->bus_hi
, ptr
);
store_bytes(2, (unsigned long long) memc
->bus_lo
, ptr
);
store_bytes(1, (unsigned long long) memc
->entry_id
, ptr
);
store_bytes(1, (unsigned long long) memc
->ratio
, ptr
);
store_bytes(2, (unsigned long long) memc
->memclk
, ptr
);
store_bytes(8, memc
->mcr
[i
], ptr
);
struct ecache_entry
*ecache
;
struct speed_entry
*speed
;
struct fiesta_memc_entry
*memc
;
ecache
= cpu_ecache_table
;
printf("ecache_ctrl_reg: "
"cpu_max cpu_min ecache_cfg\n");
ecache
->cpu_max
, ecache
->cpu_min
, ecache
->ecache_cfg
[0]);
if (format_mode
== 2 || format_mode
== 3)
printf(" 0x%llx", ecache
->ecache_cfg
[1]);
printf("cpu_sys_ratio: ratio speed\n");
speed
->ratio
, speed
->speed_hi
);
printf("memc_entries:\n");
printf("hi lo id ratio memclk");
printf(" mcr1 mcr2 mcr3\n");
printf("%-4hd %-4hd %-1hd %-1hd %-4hd",
memc
->bus_hi
, memc
->bus_lo
, memc
->entry_id
,
memc
->ratio
, memc
->memclk
);
printf(" 0x%016llx 0x%016llx 0x%016llx\n",
memc
->mcr
[0], memc
->mcr
[1], memc
->mcr
[2]);
match_ecache_cfg(unsigned short speed
)
struct ecache_entry
*ecache
;
ecache
= cpu_ecache_table
;
if ((speed
>= ecache
->cpu_min
) && (speed
<= ecache
->cpu_max
)) {
sprintf(err_string
, "No ecache cfg entry for cpu speed %d", speed
);
ecache_fmt(unsigned long long e_size
, int format
)
struct ecache_entry
*ecache
;
unsigned int ecache_code
;
ecache_code
= e_size
/ 0x400000;
ecache_code
<<= size_pos
;
ecache
= cpu_ecache_table
;
int cfg
= ecache
->ecache_cfg
[0] &
if (cfg
!= ecache_code
) {
"to match ecache_size!\n");
ecache
->ecache_cfg
[0] &= (-1^(3 << size_pos
));
ecache
->ecache_cfg
[0] |= ecache_code
;
printf("Invalid id_format or ecache size!\n");
match_memc_cfg(unsigned short speed
, unsigned short ratio
)
struct fiesta_memc_entry
*memc_table
;
memc_table
= fiesta_memc
;
while (memc_table
!= NULL
) {
if ((memc_table
->bus_hi
== speed
) &&
(memc_table
->ratio
== ratio
)) {
memc_table
= memc_table
->next
;
sprintf(err_string
, "No memc cfg entry for ratio %d sys speed %d",
struct speed_entry
*speed_ptr
;
if (speed_table
== NULL
) {
print_error("Must specify a cpu_sys_ratio entry!");
update_seeprom("speed_table_width",
while (speed_ptr
!= NULL
) {
if (system_type
!= GMFIESTA
&&
!match_ecache_cfg(speed_ptr
->speed_hi
*
if (system_type
== FIESTA
||
system_type
== GMFIESTA
||
if (!match_memc_cfg(speed_ptr
->speed_hi
,
speed_ptr
= speed_ptr
->next
;
(system_type
== FIESTA
|| system_type
== GMFIESTA
||
system_type
== SERRANO
)) {
print_error("Invalid id_format!");
if (fiesta_memc
== NULL
&&
(system_type
== FIESTA
|| system_type
== GMFIESTA
||
system_type
== SERRANO
)) {
print_error("Must specify a memc entry!");
if (fixed_parameter("ecache_size") && (system_type
== EXCALIBUR
)) {
if (ecache_fmt(get_seeprom("ecache_size"), format_mode
))
if ((type
== CPU
) && (id_magic
!= CPU_DEFAULT_MAGIC
)) {
print_error("Must specify clk_divisor!");
reg_cpu(char *s1
, data_reg
**reg
)
if (strcmp(s1
, "lsucr") == 0) {
count
= sizeof (lsucr
) / sizeof (data_reg
);
} else if (strcmp(s1
, "dcr") == 0) {
count
= sizeof (dcr
) / sizeof (data_reg
);