2009-07-02 19:22:36 +04:00
/*
* Based on Ocelot Linux port , which is
* Copyright 2001 MontaVista Software Inc .
* Author : jsun @ mvista . com or jsun @ junsun . net
*
* Copyright 2003 ICT CAS
* Author : Michael Guo < guoyi @ ict . ac . cn >
*
2015-07-07 21:56:04 +03:00
* Copyright ( C ) 2007 Lemote Inc . & Institute of Computing Technology
2009-07-02 19:22:36 +04:00
* Author : Fuxin Zhang , zhangfx @ lemote . com
*
2010-01-04 12:16:51 +03:00
* Copyright ( C ) 2009 Lemote Inc .
* Author : Wu Zhangjin , wuzhangjin @ gmail . com
2009-07-02 19:22:36 +04:00
*
2013-01-22 15:59:30 +04:00
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
2009-07-02 19:22:36 +04:00
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
2009-11-16 20:32:59 +03:00
# include <linux/module.h>
2009-07-02 19:22:36 +04:00
# include <asm/bootinfo.h>
2009-07-02 19:23:03 +04:00
# include <loongson.h>
2014-03-21 14:44:02 +04:00
# include <boot_param.h>
2014-11-04 09:13:27 +03:00
# include <workarounds.h>
2009-07-02 19:23:03 +04:00
2014-03-21 14:44:02 +04:00
u32 cpu_clock_freq ;
2009-11-16 20:32:59 +03:00
EXPORT_SYMBOL ( cpu_clock_freq ) ;
2014-03-21 14:44:02 +04:00
struct efi_memory_map_loongson * loongson_memmap ;
struct loongson_system_configuration loongson_sysconf ;
2009-07-02 19:22:36 +04:00
2014-06-26 07:41:27 +04:00
u64 loongson_chipcfg [ MAX_PACKAGES ] = { 0xffffffffbfc00180 } ;
2015-03-29 05:54:09 +03:00
u64 loongson_chiptemp [ MAX_PACKAGES ] ;
2014-06-26 07:41:30 +04:00
u64 loongson_freqctrl [ MAX_PACKAGES ] ;
unsigned long long smp_group [ 4 ] ;
2014-06-26 07:41:27 +04:00
2009-07-02 19:22:36 +04:00
# define parse_even_earlier(res, option, p) \
do { \
2011-03-29 14:32:55 +04:00
unsigned int tmp __maybe_unused ; \
\
2009-07-02 19:22:36 +04:00
if ( strncmp ( option , ( char * ) p , strlen ( option ) ) = = 0 ) \
2014-03-21 14:44:02 +04:00
tmp = kstrtou32 ( ( char * ) p + strlen ( option " = " ) , 10 , & res ) ; \
2009-07-02 19:22:36 +04:00
} while ( 0 )
void __init prom_init_env ( void )
{
2010-01-04 12:16:48 +03:00
/* pmon passes arguments in 32bit pointers */
unsigned int processor_id ;
2014-03-21 14:44:02 +04:00
# ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
int * _prom_envp ;
2009-07-02 19:22:36 +04:00
long l ;
/* firmware arguments are initialized in head.S */
_prom_envp = ( int * ) fw_arg2 ;
l = ( long ) * _prom_envp ;
while ( l ! = 0 ) {
parse_even_earlier ( cpu_clock_freq , " cpuclock " , l ) ;
parse_even_earlier ( memsize , " memsize " , l ) ;
parse_even_earlier ( highmemsize , " highmemsize " , l ) ;
_prom_envp + + ;
l = ( long ) * _prom_envp ;
}
if ( memsize = = 0 )
memsize = 256 ;
2015-08-31 07:19:58 +03:00
loongson_sysconf . nr_uarts = 1 ;
2014-03-21 14:44:02 +04:00
pr_info ( " memsize=%u, highmemsize=%u \n " , memsize , highmemsize ) ;
# else
struct boot_params * boot_p ;
struct loongson_params * loongson_p ;
2014-11-04 09:13:27 +03:00
struct system_loongson * esys ;
2014-03-21 14:44:02 +04:00
struct efi_cpuinfo_loongson * ecpu ;
struct irq_source_routing_table * eirq_source ;
/* firmware arguments are initialized in head.S */
boot_p = ( struct boot_params * ) fw_arg2 ;
loongson_p = & ( boot_p - > efi . smbios . lp ) ;
2014-11-04 09:13:27 +03:00
esys = ( struct system_loongson * )
( ( u64 ) loongson_p + loongson_p - > system_offset ) ;
2014-03-21 14:44:02 +04:00
ecpu = ( struct efi_cpuinfo_loongson * )
( ( u64 ) loongson_p + loongson_p - > cpu_offset ) ;
eirq_source = ( struct irq_source_routing_table * )
( ( u64 ) loongson_p + loongson_p - > irq_offset ) ;
loongson_memmap = ( struct efi_memory_map_loongson * )
( ( u64 ) loongson_p + loongson_p - > memory_offset ) ;
cpu_clock_freq = ecpu - > cpu_clock_freq ;
loongson_sysconf . cputype = ecpu - > cputype ;
2014-06-26 07:41:27 +04:00
if ( ecpu - > cputype = = Loongson_3A ) {
2014-06-26 07:41:28 +04:00
loongson_sysconf . cores_per_node = 4 ;
loongson_sysconf . cores_per_package = 4 ;
2014-06-26 07:41:30 +04:00
smp_group [ 0 ] = 0x900000003ff01000 ;
smp_group [ 1 ] = 0x900010003ff01000 ;
smp_group [ 2 ] = 0x900020003ff01000 ;
smp_group [ 3 ] = 0x900030003ff01000 ;
2014-06-26 07:41:27 +04:00
loongson_chipcfg [ 0 ] = 0x900000001fe00180 ;
loongson_chipcfg [ 1 ] = 0x900010001fe00180 ;
loongson_chipcfg [ 2 ] = 0x900020001fe00180 ;
loongson_chipcfg [ 3 ] = 0x900030001fe00180 ;
2015-03-29 05:54:09 +03:00
loongson_chiptemp [ 0 ] = 0x900000001fe0019c ;
loongson_chiptemp [ 1 ] = 0x900010001fe0019c ;
loongson_chiptemp [ 2 ] = 0x900020001fe0019c ;
loongson_chiptemp [ 3 ] = 0x900030001fe0019c ;
2016-03-03 04:45:09 +03:00
loongson_freqctrl [ 0 ] = 0x900000001fe001d0 ;
loongson_freqctrl [ 1 ] = 0x900010001fe001d0 ;
loongson_freqctrl [ 2 ] = 0x900020001fe001d0 ;
loongson_freqctrl [ 3 ] = 0x900030001fe001d0 ;
2014-06-26 07:41:30 +04:00
loongson_sysconf . ht_control_base = 0x90000EFDFB000000 ;
2014-11-04 09:13:27 +03:00
loongson_sysconf . workarounds = WORKAROUND_CPUFREQ ;
2014-06-26 07:41:30 +04:00
} else if ( ecpu - > cputype = = Loongson_3B ) {
loongson_sysconf . cores_per_node = 4 ; /* One chip has 2 nodes */
loongson_sysconf . cores_per_package = 8 ;
smp_group [ 0 ] = 0x900000003ff01000 ;
smp_group [ 1 ] = 0x900010003ff05000 ;
smp_group [ 2 ] = 0x900020003ff09000 ;
smp_group [ 3 ] = 0x900030003ff0d000 ;
loongson_chipcfg [ 0 ] = 0x900000001fe00180 ;
loongson_chipcfg [ 1 ] = 0x900020001fe00180 ;
loongson_chipcfg [ 2 ] = 0x900040001fe00180 ;
loongson_chipcfg [ 3 ] = 0x900060001fe00180 ;
2015-03-29 05:54:09 +03:00
loongson_chiptemp [ 0 ] = 0x900000001fe0019c ;
loongson_chiptemp [ 1 ] = 0x900020001fe0019c ;
loongson_chiptemp [ 2 ] = 0x900040001fe0019c ;
loongson_chiptemp [ 3 ] = 0x900060001fe0019c ;
2014-06-26 07:41:30 +04:00
loongson_freqctrl [ 0 ] = 0x900000001fe001d0 ;
loongson_freqctrl [ 1 ] = 0x900020001fe001d0 ;
loongson_freqctrl [ 2 ] = 0x900040001fe001d0 ;
loongson_freqctrl [ 3 ] = 0x900060001fe001d0 ;
loongson_sysconf . ht_control_base = 0x90001EFDFB000000 ;
2014-11-04 09:13:27 +03:00
loongson_sysconf . workarounds = WORKAROUND_CPUHOTPLUG ;
2014-06-26 07:41:27 +04:00
} else {
2014-06-26 07:41:28 +04:00
loongson_sysconf . cores_per_node = 1 ;
loongson_sysconf . cores_per_package = 1 ;
2014-06-26 07:41:27 +04:00
loongson_chipcfg [ 0 ] = 0x900000001fe00180 ;
}
2014-03-21 14:44:02 +04:00
loongson_sysconf . nr_cpus = ecpu - > nr_cpus ;
2014-11-04 09:13:26 +03:00
loongson_sysconf . boot_cpu_id = ecpu - > cpu_startup_core_id ;
loongson_sysconf . reserved_cpus_mask = ecpu - > reserved_cores_mask ;
2014-03-21 14:44:02 +04:00
if ( ecpu - > nr_cpus > NR_CPUS | | ecpu - > nr_cpus = = 0 )
loongson_sysconf . nr_cpus = NR_CPUS ;
2014-06-26 07:41:28 +04:00
loongson_sysconf . nr_nodes = ( loongson_sysconf . nr_cpus +
loongson_sysconf . cores_per_node - 1 ) /
loongson_sysconf . cores_per_node ;
2014-03-21 14:44:02 +04:00
loongson_sysconf . pci_mem_start_addr = eirq_source - > pci_mem_start_addr ;
loongson_sysconf . pci_mem_end_addr = eirq_source - > pci_mem_end_addr ;
loongson_sysconf . pci_io_base = eirq_source - > pci_io_start_addr ;
loongson_sysconf . dma_mask_bits = eirq_source - > dma_mask_bits ;
if ( loongson_sysconf . dma_mask_bits < 32 | |
loongson_sysconf . dma_mask_bits > 64 )
loongson_sysconf . dma_mask_bits = 32 ;
loongson_sysconf . restart_addr = boot_p - > reset_system . ResetWarm ;
loongson_sysconf . poweroff_addr = boot_p - > reset_system . Shutdown ;
loongson_sysconf . suspend_addr = boot_p - > reset_system . DoSuspend ;
loongson_sysconf . vgabios_addr = boot_p - > efi . smbios . vga_bios ;
pr_debug ( " Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx \n " ,
loongson_sysconf . poweroff_addr , loongson_sysconf . restart_addr ,
loongson_sysconf . vgabios_addr ) ;
2014-11-04 09:13:27 +03:00
memset ( loongson_sysconf . ecname , 0 , 32 ) ;
if ( esys - > has_ec )
memcpy ( loongson_sysconf . ecname , esys - > ec_name , 32 ) ;
loongson_sysconf . workarounds | = esys - > workarounds ;
loongson_sysconf . nr_uarts = esys - > nr_uarts ;
if ( esys - > nr_uarts < 1 | | esys - > nr_uarts > MAX_UARTS )
loongson_sysconf . nr_uarts = 1 ;
memcpy ( loongson_sysconf . uarts , esys - > uarts ,
sizeof ( struct uart_device ) * loongson_sysconf . nr_uarts ) ;
loongson_sysconf . nr_sensors = esys - > nr_sensors ;
if ( loongson_sysconf . nr_sensors > MAX_SENSORS )
loongson_sysconf . nr_sensors = 0 ;
if ( loongson_sysconf . nr_sensors )
memcpy ( loongson_sysconf . sensors , esys - > sensors ,
sizeof ( struct sensor_device ) * loongson_sysconf . nr_sensors ) ;
2014-03-21 14:44:02 +04:00
# endif
2010-01-04 12:16:48 +03:00
if ( cpu_clock_freq = = 0 ) {
processor_id = ( & current_cpu_data ) - > processor_id ;
switch ( processor_id & PRID_REV_MASK ) {
case PRID_REV_LOONGSON2E :
cpu_clock_freq = 533080000 ;
break ;
case PRID_REV_LOONGSON2F :
cpu_clock_freq = 797000000 ;
break ;
2016-03-03 04:45:09 +03:00
case PRID_REV_LOONGSON3A_R1 :
case PRID_REV_LOONGSON3A_R2 :
2014-03-21 14:44:02 +04:00
cpu_clock_freq = 900000000 ;
break ;
2014-06-26 07:41:30 +04:00
case PRID_REV_LOONGSON3B_R1 :
case PRID_REV_LOONGSON3B_R2 :
cpu_clock_freq = 1000000000 ;
break ;
2010-01-04 12:16:48 +03:00
default :
cpu_clock_freq = 100000000 ;
break ;
}
}
2014-03-21 14:44:02 +04:00
pr_info ( " CpuClock = %u \n " , cpu_clock_freq ) ;
2009-07-02 19:22:36 +04:00
}