2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2016-10-05 18:18:20 +01:00
/*
* Copyright ( C ) 2016 Imagination Technologies
2017-10-25 17:04:33 -07:00
* Author : Paul Burton < paul . burton @ mips . com >
2016-10-05 18:18:20 +01:00
*/
# include <linux/clk.h>
# include <linux/clocksource.h>
# include <linux/init.h>
# include <linux/irqchip.h>
2020-02-12 11:15:40 +01:00
# include <linux/of_clk.h>
2016-10-05 18:18:20 +01:00
# include <linux/of_fdt.h>
2017-08-23 11:17:44 -07:00
# include <asm/bootinfo.h>
2016-10-05 18:18:20 +01:00
# include <asm/fw/fw.h>
# include <asm/irq_cpu.h>
# include <asm/machine.h>
2017-10-16 11:06:49 +01:00
# include <asm/mips-cps.h>
2016-10-05 18:18:20 +01:00
# include <asm/prom.h>
# include <asm/smp-ops.h>
# include <asm/time.h>
2019-10-09 00:15:09 +08:00
static __initconst const void * fdt ;
static __initconst const struct mips_machine * mach ;
static __initconst const void * mach_match_data ;
2016-10-05 18:18:20 +01:00
void __init prom_init ( void )
2016-10-17 17:25:24 +01:00
{
plat_get_fdt ( ) ;
BUG_ON ( ! fdt ) ;
}
void __init * plat_get_fdt ( void )
2016-10-05 18:18:20 +01:00
{
const struct mips_machine * check_mach ;
const struct of_device_id * match ;
2016-10-17 17:25:24 +01:00
if ( fdt )
/* Already set up */
return ( void * ) fdt ;
2019-05-13 14:32:43 +02:00
if ( ( fw_arg0 = = - 2 ) & & ! fdt_check_header ( ( void * ) fw_passed_dtb ) ) {
2016-10-05 18:18:20 +01:00
/*
* We booted using the UHI boot protocol , so we have been
* provided with the appropriate device tree for the board .
* Make use of it & search for any machine struct based upon
* the root compatible string .
*/
2019-05-13 14:32:43 +02:00
fdt = ( void * ) fw_passed_dtb ;
2016-10-05 18:18:20 +01:00
for_each_mips_machine ( check_mach ) {
match = mips_machine_is_compatible ( check_mach , fdt ) ;
if ( match ) {
mach = check_mach ;
mach_match_data = match - > data ;
break ;
}
}
} else if ( IS_ENABLED ( CONFIG_LEGACY_BOARDS ) ) {
/*
* We weren ' t booted using the UHI boot protocol , but do
* support some number of boards with legacy boot protocols .
* Attempt to find the right one .
*/
for_each_mips_machine ( check_mach ) {
if ( ! check_mach - > detect )
continue ;
if ( ! check_mach - > detect ( ) )
continue ;
mach = check_mach ;
}
/*
* If we don ' t recognise the machine then we can ' t continue , so
* die here .
*/
BUG_ON ( ! mach ) ;
/* Retrieve the machine's FDT */
fdt = mach - > fdt ;
}
return ( void * ) fdt ;
}
2017-08-23 11:17:44 -07:00
# ifdef CONFIG_RELOCATABLE
2016-11-23 14:43:47 +01:00
void __init plat_fdt_relocated ( void * new_location )
{
/*
* reset fdt as the cached value would point to the location
* before relocations happened and update the location argument
* if it was passed using UHI
*/
fdt = NULL ;
if ( fw_arg0 = = - 2 )
fw_arg1 = ( unsigned long ) new_location ;
}
2017-08-23 11:17:44 -07:00
# endif /* CONFIG_RELOCATABLE */
2016-10-05 18:18:20 +01:00
void __init plat_mem_setup ( void )
{
if ( mach & & mach - > fixup_fdt )
fdt = mach - > fixup_fdt ( fdt , mach_match_data ) ;
strlcpy ( arcs_cmdline , boot_command_line , COMMAND_LINE_SIZE ) ;
__dt_setup_arch ( ( void * ) fdt ) ;
}
void __init device_tree_init ( void )
{
int err ;
unflatten_and_copy_device_tree ( ) ;
mips_cpc_probe ( ) ;
err = register_cps_smp_ops ( ) ;
if ( err )
err = register_up_smp_ops ( ) ;
}
2017-06-02 12:29:54 -07:00
int __init apply_mips_fdt_fixups ( void * fdt_out , size_t fdt_out_size ,
const void * fdt_in ,
const struct mips_fdt_fixup * fixups )
{
int err ;
err = fdt_open_into ( fdt_in , fdt_out , fdt_out_size ) ;
if ( err ) {
pr_err ( " Failed to open FDT \n " ) ;
return err ;
}
for ( ; fixups - > apply ; fixups + + ) {
err = fixups - > apply ( fdt_out ) ;
if ( err ) {
pr_err ( " Failed to apply FDT fixup \" %s \" \n " ,
fixups - > description ) ;
return err ;
}
}
err = fdt_pack ( fdt_out ) ;
if ( err )
pr_err ( " Failed to pack FDT \n " ) ;
return err ;
}
2016-10-05 18:18:20 +01:00
void __init plat_time_init ( void )
{
struct device_node * np ;
struct clk * clk ;
of_clk_init ( NULL ) ;
if ( ! cpu_has_counter ) {
mips_hpt_frequency = 0 ;
} else if ( mach & & mach - > measure_hpt_freq ) {
mips_hpt_frequency = mach - > measure_hpt_freq ( ) ;
} else {
np = of_get_cpu_node ( 0 , NULL ) ;
if ( ! np ) {
pr_err ( " Failed to get CPU node \n " ) ;
return ;
}
clk = of_clk_get ( np , 0 ) ;
if ( IS_ERR ( clk ) ) {
pr_err ( " Failed to get CPU clock: %ld \n " , PTR_ERR ( clk ) ) ;
return ;
}
mips_hpt_frequency = clk_get_rate ( clk ) ;
clk_put ( clk ) ;
switch ( boot_cpu_type ( ) ) {
case CPU_20KC :
case CPU_25KF :
/* The counter runs at the CPU clock rate */
break ;
default :
/* The counter runs at half the CPU clock rate */
mips_hpt_frequency / = 2 ;
break ;
}
}
2017-05-26 17:40:46 +02:00
timer_probe ( ) ;
2016-10-05 18:18:20 +01:00
}
void __init arch_init_irq ( void )
{
struct device_node * intc_node ;
intc_node = of_find_compatible_node ( NULL , NULL ,
" mti,cpu-interrupt-controller " ) ;
if ( ! cpu_has_veic & & ! intc_node )
mips_cpu_irq_init ( ) ;
2018-07-11 20:32:45 +02:00
of_node_put ( intc_node ) ;
2016-10-05 18:18:20 +01:00
irqchip_init ( ) ;
}
void __init prom_free_prom_memory ( void )
{
}