/*
 * Copyright 2014, 2022-2024, BlackBerry Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You
 * may not reproduce, modify or distribute this software except in
 * compliance with the License. You may obtain a copy of the License
 * at: http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OF ANY KIND, either express or implied.
 *
 * This file may contain contributions from others, either as
 * contributors under the License or as licensors under other terms.
 * Please review this entire file for other proprietary rights or license
 * notices, as well as the QNX Development Suite License Guide at
 * http://licensing.qnx.com/license-guide/ for other information.
 */

#ifndef _STARTUP_H_INCLUDED
#define _STARTUP_H_INCLUDED

//
// Other includes which most everyone needs
//
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <gulliver.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/image.h>
#include <sys/startup.h>
#include <sys/neutrino.h>
#define SYSPAGE_SIZED_ARRAYS

#if __PTR_BITS__ > 32
/* If we're on a 64 bit system, include all the architecture targets
 * so that we have access to the cpu feature flags for the 32 bit version
 * of the architecture
 */
#define SYSPAGE_TARGET_ALL
#endif

#include <sys/syspage.h>
#include <sys/elf.h>
#include <hw/sysinfo.h>
#include <confname.h>

#if __PTR_BITS__+0 == 32
#define PADDR_T  paddr32_t
#else
#define PADDR_T paddr_t
#endif

#define PROCESSORS_MAX	64	// set this to match kernel (at least a search will find this now)

/* this ASSERT is intentionally meant to not be conditionally implemented */
#define _ASSERT(_c_, _extra_text_) \
		do { \
			if (!(_c_)) \
			{ \
				const char *s = strrchr(__FILE__, '/'); \
				const char * const msg = (_extra_text_); /* for when _extra_text_ is a function call */ \
				crash("%s:%d -- ASSERT(%s) failed!\n%s", \
						(s != NULL) ? s + 1 : __FILE__, __LINE__, #_c_, (msg != NULL) ? msg : "\n"); \
			} \
		} while(0)
#define ASSERT(_c_)		_ASSERT(_c_, NULL)

/*
 * if alloca() fails, un-comment the TRACE_ALLOCA macro and clean compile
 * startup/lib if you want to see exactly where alloca()'s are coming from
 * and by how much the request exceeded the available stack space
 */
//#define TRACE_ALLOCA
#ifdef TRACE_ALLOCA
/*
 * ALLOCA macro wraps alloca() and asserts if allocation will be outside the
 * stack.
 * Implemented as it is so that the assertion can be done in the context of the
 * allocator/offender
 */
extern void *__alloca_tmp;
extern const char * const blown_startup_stack(const size_t req_sz, const uintptr_t sp);
#define ALLOCA(_sz_) \
		(__alloca_tmp = alloca(_sz_)); \
		_ASSERT(__alloca_tmp != NULL, blown_startup_stack(_sz_, rdsp()))
#else
#define ALLOCA(_sz_)	alloca(_sz_)
#endif

#define SYSPAGE_TYPED_SECTION(type, field)	\
		struct field##_section {			\
			type			*p;				\
			unsigned		size;			\
		}						field

#define SYSPAGE_SECTION(field)	SYSPAGE_TYPED_SECTION(struct field##_entry, field)

struct callout_rtn {
	unsigned	*rw_size;
	void		(*patcher)(PADDR_T paddr, uintptr_t vaddr, unsigned rtn_offset, unsigned rw_offset, void *data, const struct callout_rtn *src);
	unsigned	rtn_size;
	uint8_t		rtn_code[1];
};

struct callout_slot {
	unsigned					offset;
	const struct callout_rtn	*callout;
};

#define CALLOUT_SLOT( name, suffix ) \
	offsetof( struct callout_entry, name ), &name##suffix

#if defined(__x86_64__)
#include <x86_64/cpu_startup.h>
#elif defined(__aarch64__)
#include <aarch64/cpu_startup.h>
#endif
#include <sys/restore_ifs.h>

#if !defined(MAKE_1TO1_PTR)
	#define MAKE_1TO1_PTR(p)	((void *)((uintptr_t)(p) + shdr->paddr_bias))
#endif

#ifndef __PAGESIZE
  #define __PAGESIZE 4096
#endif

#ifndef CPU_VIRT_PAGESIZE
	#define CPU_VIRT_PAGESIZE __PAGESIZE
#endif

#ifndef CPU_PHYS_PAGESIZE
	#define CPU_PHYS_PAGESIZE 16
#endif

//
// Defines
//
#define NULL_PADDR			(~(paddr_t)0)
#define NULL_PADDR_STARTUP	(~(PADDR_T)0)

#define TRUNC(_x,_a)  ((paddr_t)(_x) &~ (((paddr_t)(_a))-1))
#define ROUND(_x,_a)  TRUNC(((paddr_t)(_x)) + ((paddr_t)(_a)-1), (paddr_t)(_a))

#define TRUNCPG(_x)		TRUNC((_x), __PAGESIZE)
#define ROUNDPG(_x)		ROUND((_x), __PAGESIZE)

#define KILO(k)			((k) * 1024UL)
#define MEG(m)			((m) * (1024UL * 1024UL))
#define GIG(m)			((m) * (1024UL * 1024UL * 1024UL))

#define TOPTR(x)		((void *)(x))

#define PTR_DIFF(a,b)	((uint8_t *)(a) - (uint8_t *)(b))

#define NUM_ELTS(__array)	(sizeof(__array)/sizeof(__array[0]))

#define COMMON_OPTIONS_STRING   CPU_COMMON_OPTIONS_STRING "ACc:D:F:f:I:i:K:M:N:o:P:R:S:Tvr:j:ZH"

struct local_syspage {
	SYSPAGE_SECTION(syspage);
	SYSPAGE_SECTION(system_private);
	SYSPAGE_SECTION(asinfo);
	SYSPAGE_SECTION(hwinfo);
	SYSPAGE_SECTION(cpuinfo);
	SYSPAGE_SECTION(cacheattr);
	SYSPAGE_SECTION(qtime);
	SYSPAGE_SECTION(callout);
	SYSPAGE_SECTION(typed_strings);
	SYSPAGE_SECTION(strings);
	SYSPAGE_SECTION(intrinfo);
	SYSPAGE_SECTION(smp);
    SYSPAGE_SECTION(hypinfo);
    SYSPAGE_SECTION(cluster);
	struct cpu_local_syspage	cpu;
};

struct debug_device {
	const char 					*name;
	const char					*defaults[2];
	void						(*init)(unsigned, const char *, const char *);
	void						(*put)(int);
	const struct callout_rtn	*callouts[3];
};

#define DEBUG_DEV_CONSOLE	0
#define DEBUG_DEV_KDEBUG	1

#define DEBUG_DISPLAY_CHAR	0
#define DEBUG_POLL_KEY		1
#define DEBUG_BREAK_DETECT	2

/*
 *NOTE: The first part has to match one-to-one with struct intrinfo_entry
 *      on the syspage (aside from the type of the function pointers changing).
 */
struct startup_intrgen {
	uint16_t			genflags;
	uint16_t			size;
	struct callout_rtn	*rtn;
};

struct startup_intrinfo {
	uint32_t				vector_base;
	uint32_t				num_vectors;
	uint32_t				cascade_vector;
	uint32_t				cpu_intr_base;
	uint16_t				cpu_intr_stride;
	uint16_t				flags;
	struct startup_intrgen	id;
	struct startup_intrgen	eoi;
	struct callout_rtn		*mask;
	struct callout_rtn		*unmask;
	struct callout_rtn		*config;
	void					*patch_data;
	uint32_t				local_stride;
};

typedef void	(*output_callout_t(int))(int);

typedef struct {
	paddr_t		base;
	unsigned	shift;
} chip_info;


#ifdef __STRICT_PROTYPES__
/*
 * This really isn't correct, since there is no 'one' signature for a callout fp,
 * but this silences the compiler's complaints for those who really must compile with
 * -fstrict-prototypes
 */
typedef void (*callout_fp_t)(void);
#else
typedef void (*callout_fp_t)();
#endif
typedef __cache_rtn	cache_rtn;

//
// Function prototypes
//

//
//These are board specific routines that need to be implemented. There
//may be more syspage sections that need to be implemented for a
//particular CPU. Check the appropriate cpu_startup.h. There may be
//default implementations of these routines in the startup library that
//will work for a particular board, or set of boards.
//
void init_raminfo(void);
void init_intrinfo(void);
void init_qtime(void);
void init_cacheattr(void);
void init_cpuinfo(void);
void init_hwinfo(void);
void init_asinfo(unsigned mem);
void init_nanospin(void);
void init_mitigation_mem(void);


// Only needed for SMP systems
void init_smp(void);
unsigned board_smp_num_cpu(void);
void board_smp_init(struct smp_entry *, unsigned num_cpus);
int board_smp_start(unsigned cpu, void (*start)(void));
unsigned board_smp_adjust_num(unsigned);
extern void	(*smp_spin_vaddr)(void);
int cpu_cluster_add(const char *name, uint64_t cpumask);

// Only needed on systems with an MMU.
void init_mmu(void);
void board_mmu_enable(void);
void board_mmu_disable(void);
void board_alignment_check_enable(void);
void board_alignment_check_disable(void);
void board_dcache_enable(void);
void board_dcache_disable(void);
void board_icache_enable(void);
void board_icache_disable(void);
void board_enable_caches(void);
void board_disable_caches(void);

//
//These are CPU specific routines that are implemented by the startup library.
//Users shouldn't have to call these directly.
//
void cpu_startup(void);
void cpu_one_startup(int __cpu);
void cpu_init_syspage_memory(void);
struct syspage_entry *cpu_alloc_syspage_memory(PADDR_T *, PADDR_T *, unsigned);
void cpu_write_syspage_memory(PADDR_T, unsigned, unsigned);
void cpu_syspage_remap(uintptr_t vaddr, paddr_t paddr, size_t size, int flags);
void cpu_print_callout(struct callout_entry *call);
void cpu_startnext(uintptr_t eip,unsigned cpu);


int	is_elf(paddr_t addr);
int	is_elf32(paddr_t addr);
int	is_elf64(paddr_t addr);
uintptr_t load_elf(paddr_t addr);

void elf_map(uintptr_t vaddr, PADDR_T paddr,size_t size,int flags);
paddr_t elf_vaddr_to_paddr(uintptr_t vaddr);

uintptr_t load_elf32(paddr32_t addr);

uintptr_t load_elf64(paddr_t addr);

int load_elf64mmu_4m(paddr_t addr, Elf64_Ehdr *hdr, Elf64_Phdr *phdr);

void startnext(void);

extern struct callout_rtn	cache_dummy;

//
// These are CPU/board independent routines that can be used 'as is'.
//
void init_system_private(void);
void do_init_system_private(void);
void load_ifs(paddr_t);
struct pminfo_entry *init_pminfo(unsigned managed_size);

void copy_memory(PADDR_T dst, PADDR_T src, size_t len);

paddr_t strtopaddr(const char *nptr, char **endptr, int base);
unsigned calc_cksum(const void *start, unsigned nbytes);
void chip_access(paddr_t base, unsigned reg_shift, unsigned mem_mapped, unsigned size);
unsigned chip_read8(unsigned off);
void chip_write8(unsigned off, unsigned val);
void chip_write16(unsigned off, unsigned val) ;
void chip_write32(unsigned off, unsigned val) ;
unsigned chip_read16(unsigned off);
unsigned chip_read32(unsigned off);
uint64_t chip_read64(unsigned off);
void chip_write64(unsigned off, uint64_t val);
void chip_done(void);
const struct armv_chip *armv_chip_detect(void);
unsigned long arm_cpuspeed(void);
unsigned get_processor_base_freq(void);



void add_callout_array(const struct callout_slot *slots, unsigned size);
void * add_callout(unsigned offset, const struct callout_rtn *callout);
void callout_output_one(int sizing, void *rp);
unsigned output_callouts(unsigned *const rwsize);
void callout_register_data(void *rp, void *data);
void callout_reloc_data(void *base, unsigned len, ptrdiff_t diff);

unsigned long timer_ns2tick(unsigned long ns);
unsigned long timer_tick2ns(unsigned long ticks);
unsigned long calc_time_t(const struct tm *tm);
unsigned bcd2bin(unsigned a);
unsigned long rtc_time(void);
unsigned long rtc_time_none(void);
unsigned long rtc_time_mc146818(paddr_t base, unsigned reg_shift, int mmap, int cent_reg);
unsigned long rtc_time_ds1386(paddr_t base, unsigned reg_shift, int mmap, int cent_reg);
unsigned long rtc_time_ds15x1(paddr_t base, unsigned reg_shift, int mmap, int cent_reg);
unsigned long rtc_time_ds1743(paddr_t base, unsigned reg_shift, int mmap, int cent_reg);
unsigned long rtc_time_rtc72423(paddr_t base, unsigned reg_shift, int mmap, int cent_reg);
unsigned long rtc_time_m48t5x(paddr_t base, unsigned reg_shift, int mmap, int cent_reg);
unsigned long rtc_time_m48t37(paddr_t base, unsigned reg_shift, int mmap, int cent_reg);

void invert_timer_freq(struct qtime_entry *qtime, unsigned freq);
void init_qtime_v7glob(void);
struct qtime_entry * alloc_qtime(void);

void		*ws_alloc(size_t);
void		add_sysram(void);
void		avoid_ram(PADDR_T, size_t size);
void		add_ram(paddr_t start, paddr_t size);
void		watch_add_ram(void (*)(paddr_t, paddr_t));
paddr_t		alloc_ram(paddr_t addr, paddr_t size, unsigned align);
paddr_t		find_top_ram(paddr_t size);
paddr_t		find_top_ram_aligned(paddr_t size, unsigned align, unsigned pagesize);
paddr_t		find_top_ram_aligned_limit(paddr_t size, unsigned align,
                                     unsigned pagesize, paddr_t limit);
int			init_raminfo_uefi(void);
paddr_t     find_ram_in_range(paddr_t range_start, paddr_t range_end, size_t size,
                              unsigned align, unsigned colour, unsigned mask);
PADDR_T	find_ram(size_t size, unsigned align, unsigned colour, unsigned mask);
PADDR_T	calloc_ram(size_t size, unsigned align);
void            reserve_ram(unsigned size, unsigned align, const char *, unsigned pagesize, const unsigned low_region);
int         is_addr_in_ram(paddr_t start, size_t size);

int getopt(int argc, char * const argv[] , char const * opts);
int cpu_handle_common_option(int opt);
void handle_common_option(int opt);
paddr_t getsize(char *, char **);

void tweak_cmdline(struct bootargs_entry *bap, const char *);
void cpu_tweak_cmdline(struct bootargs_entry *bap, const char *);
int bootstrap_arg_adjust(struct bootargs_entry *bap, const char *old, const char *new);
int bootstrap_env_adjust(struct bootargs_entry *bap, const char *old, const char *new);

struct tm *_gmtime(const time_t *timer,struct tm *tmbuf);

void kprintf(const char *fmt,... );
void ksprintf(char *buff, const char *fmt,... );
void crash(const char *fmt,... ) __attribute__((__noreturn__));
void set_print_char(void (*)(int));
void (*get_print_char(void))(int);
void set_debug(unsigned channel, const struct debug_device *dev, const char *options);
void select_debug(const struct debug_device *dev, unsigned size);
void print_syspage(void);
void print_syspage_enable(const char *name);
void print_syspage_sections(void);
void __ssp_fail(const char *msg) __attribute__((__noreturn__));

char *ultoa_end(unsigned long int v, char *d, int radix);

void init_syspage_memory(void *, unsigned max_size);
void *grow_syspage_section(void *, unsigned size);
void *set_syspage_section(void *, unsigned size);
void reloc_syspage_memory(void *, unsigned max_size);
void alloc_syspage_memory(void);
void write_syspage_memory(void);

void jtag_store_syspage_addr(void);
void jtag_reserve_syspage_addr(paddr_t jtag_syspage_addr);
void jtag_reserve_memory(paddr_t resmem_addr, size_t resmem_size, uint8_t resmem_flag);

paddr_t	acpi_find_table_next(unsigned table_name, unsigned *lenp, paddr_t start_search);
paddr_t	acpi_find_table(unsigned table_name, unsigned *lenp);
void add_acpi_table(void);
void *board_find_acpi_rsdp(void);
void *board_find_acpi_rsdp_bios(void);
void *board_find_acpi_rsdp_uefi(void);
void acpi_spcr_parse(struct debug_device *dbgdev);

void board_cpuconfig1(int cpu);
void board_cpuconfig2(int cpu);

const void *find_startup_info(const void *start, unsigned type);
int find_typed_string(int type_index);
int del_typed_string(int type_index);
unsigned add_typed_string(int type_index, const char *name);
unsigned add_string(const char *name);
int add_cache(int next, unsigned flags, unsigned line_size, unsigned num_lines, const struct callout_rtn *rtn);
int add_cache_ways(int next, unsigned flags, unsigned line_size, unsigned num_lines, unsigned ways, const struct callout_rtn *rtn);

struct intrinfo_entry *add_interrupt(const struct startup_intrinfo *);
void add_interrupt_array(const struct startup_intrinfo *intrs, unsigned size);
void gicv_asinfo(paddr_t gicv, paddr_t banked_gich, paddr_t direct_gich, unsigned direct_num, unsigned direct_spacing);
int init_intrinfo_msi(int vector_base);
int interrupt_valid(int intr);

#define HWI_TAG_INFO(type)				\
			HWI_TAG_NAME_##type,		\
			sizeof(struct hwi_##type),	\
			HWI_TAG_ALIGN_##type

/* prototypes for generic hwi routines. Note there are specific bus and device
 * add functions defined in startup/lib/public/sys/hwinfo.h */
void		hwi_default(void);
void		*hwi_alloc_tag(const char *tagname, unsigned size, unsigned align);
void		*hwi_alloc_item(const char *tagname, unsigned size, unsigned align, const char *itemname, unsigned owner);
void		*hwi_grow_tag(unsigned offset, unsigned size);

unsigned	hwi_add_synonym(unsigned hwi_off, const char *synonym);
unsigned	hwi_find_as(paddr_t base, int mmap);

/* prototypes for adding buses and devices */
unsigned	hwibus_add(const char *bus_name, unsigned hwi_off);
unsigned	hwidev_add(const char *device_name, unsigned pnp, unsigned bus_hwi_off);

/* prototypes for adding tags */
void		hwitag_add_common(unsigned hwi_off, void *attr);
void		hwitag_add_optstr(unsigned hwi_off, const char *string);
void		hwitag_add_location(const unsigned hwi_off, const _Uint64t base, const _Uint32t len, const _Uint16t reg_shift, const _Uint16t addr_space);
void		hwitag_add_busattr(unsigned hwi_off, struct hwi_busattr *attr);
void		hwitag_add_irq(unsigned hwi_off, unsigned vector);
unsigned	hwitag_add_irq_mapping(unsigned hwi_off, unsigned default_irq);
void		hwitag_add_specific_irq_mapping(unsigned hwi_off, unsigned offset, unsigned devfunc, int adjust);
void		hwitag_add_irqrange(unsigned hwi_off, unsigned start_vector, unsigned num);
void		hwitag_add_inputclk(unsigned hwi_off, unsigned clk, unsigned div);
void		hwitag_add_nicaddr(unsigned hwi_off, const _uint8 *addr, unsigned len);
void		hwitag_add_nicphyaddr(unsigned hwi_off, const _uint32 addr);
void		hwitag_add_regname(unsigned hwi_off, const char *name, unsigned regoffset);

/* prototypes for setting specific tag values */
int			hwitag_set_nicaddr(unsigned hwi_off, unsigned nic_idx, uint8_t *nic_addr);
int			hwitag_set_phyaddr(unsigned hwi_off, unsigned phy_idx, uint32_t phy_addr);
int			hwitag_set_ivec(unsigned hwi_off, unsigned ivec_idx, uint32_t vector);
int			hwitag_set_dma(unsigned hwi_off, unsigned dma_idx, uint32_t chnl);
int			hwitag_set_inputclk(unsigned hwi_off, unsigned clksrc_idx, struct hwi_inputclk *clk);
int			hwitag_set_busattr(unsigned hwi_off, unsigned busattr_idx, struct hwi_busattr *busattr);
int			hwitag_set_ivecrange(unsigned hwi_off, unsigned ivecrange_idx, unsigned start_vector, unsigned num);
int			hwitag_set_avail_ivec(unsigned hwi_off, int ivec_idx, uint32_t vector);
int			hwitag_set_errata(unsigned hwi_off, unsigned errata_idx, uint32_t errata);

/* prototypes for deprecated hwi functions. Kept for backwards compat until all usage is removed */
void		hwi_add_device(const char *bus, const char *class, const char *name, unsigned pnp);
void		hwi_add_location(const _Uint64t base, const _Uint32t len, const _Uint16t reg_shift, const _Uint16t addr_space);
void		hwi_add_irq(unsigned vector);
void		hwi_add_nicaddr(const _uint8 *addr, unsigned len);
void		hwi_add_nicphyaddr(const _uint32 addr);
unsigned	hwi_add_irq_mapping(unsigned default_irq);
void		hwi_add_specific_irq_mapping(unsigned offset, unsigned devfunc, int adjust);
void		hwi_add_inputclk(unsigned clk, unsigned div);
void		hwi_add_rtc(const char *name, paddr_t base, unsigned reg_shift, unsigned len, int mmap, int cent_reg);
void		hwi_add_nanospin(unsigned long hundred_loop_time, unsigned long overhead);

#define AS_ATTR_NONE	0
// Attributes have been removed
#define AS_ATTR_RAM	AS_ATTR_NONE
#define AS_ATTR_ROM	AS_ATTR_NONE
#define AS_ATTR_DEV	AS_ATTR_NONE
#define AS_OVERLAY_IO	0x80000000

unsigned			as_default(void);
unsigned			as_add(paddr_t start, paddr_t end, unsigned attr, const char *name, unsigned owner);
unsigned			as_add64(paddr64_t start, paddr64_t end, unsigned attr, const char *name, unsigned owner);
unsigned			as_add_containing(paddr_t start, paddr_t end, unsigned attr, const char *name, const char *container);
void				as_set_priority(unsigned as_off, unsigned priority);
struct asinfo_entry	*as_off2info(unsigned offset);
unsigned			as_info2off(const struct asinfo_entry *);
unsigned			as_find(unsigned start, ...);
unsigned			as_find_containing(unsigned off, paddr_t start, paddr_t end, const char *container);

void uncompress(int type, PADDR_T dst, PADDR_T src);
void uncompress_zlib(uint8_t *dst, int *dstlen, uint8_t *src, int srclen, uint8_t *win);
void uncompress_lzo(uint8_t *dst, uint8_t *src);
void uncompress_ucl(uint8_t *dst, uint8_t *src);

#define PROT_READ       0x00000100  /* pages can be read      */
#define PROT_WRITE      0x00000200  /* pages can be written   */
#define PROT_EXEC       0x00000400  /* pages can be executed  */
#define PROT_NOCACHE    0x00000800  /* pages are not cached   */
#define PROT_USER	    0x00001000	/* pages are accessable to user */
#define PROT_CALLOUT	0x80000000	/* internal flag */

uintptr_t	startup_io_map(unsigned size, paddr_t phys);
void		startup_io_unmap(uintptr_t port);
void		*startup_memory_map(unsigned size, paddr_t phys, unsigned prot_flags);
void		startup_memory_unmap(void *);
uintptr_t	callout_io_map(unsigned size, paddr_t phys);
void		*callout_memory_map(unsigned size, paddr_t phys, unsigned prot_flags);
uintptr_t	callout_io_map_indirect(unsigned size, paddr_t *phys);
void		*callout_memory_map_indirect(unsigned size, paddr_t *phys, unsigned prot_flags);

#define MISC_FLAG_SUPPRESS_BOOTTIME		0x0001

/*
 * AARCH64 version of u-boot stashes the FDT physical address in x0 (r2 in AARCH32)
 * Then, its register value gets copied to boot_regs[0] (boot_regs[2] in AARCH32)
 */

#if defined(__aarch64__)
	#define FDT_REG 0
#else
	#define FDT_REG 2
#endif

void		fdt_init(paddr_t);
void		fdt_asinfo(void);
int			fdt_init_bootopt(void);
int		init_raminfo_fdt(void);
unsigned	fdt_num_cpu(void);
int		fdt_smp_spin_start(unsigned cpu, void (*const start)(void));
unsigned long	fdt_get_cpu_freq(void);
void 	fdt_tweak_cmdline(struct bootargs_entry *bap, const char *name, paddr_t fdt_paddr);

void		spin_shim_rtn(void);
extern void	(*spin_shim_start)(void);
extern unsigned long spin_shim_id;


/*
 * ------------------------------------------------------------------
 * Hypervisor Support
 * ------------------------------------------------------------------
 */
#define HYP_FLAG_INVALID         (-1)
#define HYP_FLAG_DISABLED        (0)
#define HYP_FLAG_ENABLED         (1)
#define HYP_FLAG_CPU_SPECIFIC_1  (2)
#define HYP_FLAG_CPU_SPECIFIC_2  (4)
// See cpu_startup.h for additional HYP_FLAG_ values

typedef int hyp_flags_t;  // Holds HYP_FLAG_ values

void         hypervisor_init(unsigned  cpunum);
void         hypervisor_set_options(hyp_flags_t  flags);
hyp_flags_t  hypervisor_get_required_flags(void);
void         hypervisor_syspage_init(void);
hyp_flags_t  arch_hypervisor_validate_flags(hyp_flags_t  option_flags);
void         arch_hypervisor_init(unsigned  cpunum, hyp_flags_t  hyp_flags);


extern int  in_hvc;


//
// Variable prototypes
//
extern unsigned						paddr_bits;
extern PADDR_T						syspage_paddr;
extern int 							debug_flag;
extern chip_info					dbg_device[2];
extern chip_info					timer_chip;
extern unsigned						patch_channel;
extern struct local_syspage			lsp;
extern unsigned long				cpu_freq;
extern unsigned long				cycles_freq;
extern unsigned long				timer_freq;
extern unsigned long				timer_prog_time;
extern unsigned					max_cpus;
extern unsigned						system_icache_idx;
extern unsigned						system_dcache_idx;
extern struct startup_header		*shdr;
extern int							_argc;
extern char							**_argv;
extern char 						*optarg;
extern int 							optind;
extern unsigned 					(*timer_start)(void);
extern unsigned 					(*timer_diff)(unsigned start);
extern void							(*smp_hook_rtn)(void);
extern output_callout_t				*callout_output_rtn;
extern unsigned						misc_flags;
extern uintptr_t 					boot_vaddr_base;
extern uintptr_t 					boot_vaddr_end;
extern int							secure_system;
extern uintptr_t					first_bootstrap_start_vaddr;
extern void                         *fdt;
extern paddr_t                      fdt_paddr;
extern size_t						fdt_size;

#define FDT_BOOTOPT_ADDRPASS_BY_REG    0x00000001
#define FDT_BOOTOPT_ADDRPASS_BY_ARGS   0x00000002
extern int							fdt_boot_option;

extern PADDR_T						full_image_paddr;
extern PADDR_T						full_ram_paddr;
extern PADDR_T						full_imagefs_paddr;

#define RESERVED_RAM_MAX_NUM		16

struct reserved_ram {
	struct reserved_ram	*next;
	unsigned		size;
	unsigned		align;
	unsigned		low_region;
	char			*name;

};

extern struct reserved_ram			*reserved_ram_list;


//
// Debugging I/O routines available for many systems
//

/* if the board does not have a UART available for use as a console, use these
 * "dummy" callouts and debug device routines */
void						init_dummy(unsigned channel, const char *init, const char *defaults);
void						put_dummy(int c);
extern struct callout_rtn	display_char_dummy;
extern struct callout_rtn	poll_key_dummy;
extern struct callout_rtn	break_detect_dummy;

void   init_8250(unsigned, const char *, const char *);
void   init_8250_32b(unsigned, const char *, const char *);
void   init_8250_pci(unsigned, const char *, const char *);
void   init_8250_common(unsigned, unsigned long, unsigned long, unsigned long);
void   put_8250(int);
void   put_8250_32b(int);
extern struct callout_rtn	display_char_8250;
extern struct callout_rtn	poll_key_8250;
extern struct callout_rtn	break_detect_8250;
/* 32-bit versions of the above */
extern struct callout_rtn	display_char_8250_32b;
extern struct callout_rtn	poll_key_8250_32b;
extern struct callout_rtn	break_detect_8250_32b;
/* MMIO versions of the above */
extern struct callout_rtn	display_char_8250_mmio;
extern struct callout_rtn	poll_key_8250_mmio;
extern struct callout_rtn	break_detect_8250_mmio;

/*
 * ------------------------------------------------------------------
 * LINFlexD UART support
 * ------------------------------------------------------------------
 */

extern void init_linflexd(unsigned, const char *, const char *);
extern void put_linflexd(int);

extern struct callout_rtn	display_char_linflexd;
extern struct callout_rtn	poll_key_linflexd;
extern struct callout_rtn	break_detect_linflexd;

void 						dummy_print_char(int);

void 						crash_done(void) __attribute__((__noreturn__));
void						ap_fail(int cpu);

void						board_init(void);

//
// Generic PCI routines
//
uint16_t pci_read_cfg16(uint8_t bus, uint8_t dev_number, uint8_t func_number, uint8_t reg_offset);
uint8_t pci_read_cfg8(uint8_t bus, uint8_t dev_number, uint8_t func_number, uint8_t reg_offset);
void pci_write_cfg16(uint8_t bus, uint8_t dev_number, uint8_t func_number, uint8_t reg_offset, uint16_t value);
void pci_write_cfg8(uint8_t bus, uint8_t dev_number, uint8_t func_number, uint8_t reg_offset, uint8_t value);

//
// CPU specific PCI routines. Note that 8 and 16 bit variants are generic and
// implemented in terms of these 32 bit variants which are architecture
// specific.
//
uint32_t pci_read_cfg32(uint8_t bus, uint8_t dev_number, uint8_t func_number, uint8_t reg_offset);
void pci_write_cfg32(uint8_t bus, uint8_t dev_number, uint8_t func_number, uint8_t reg_offset, uint32_t value);

//
// By disabling unused functions they will not be visible during the PCI scan.
//
unsigned tnc_function_disable(unsigned device, unsigned function);
unsigned sch_function_disable(unsigned device, unsigned function);


/* Temp definition until all the header files are caught up 2008/08/20 */
#ifndef CACHE_FLAG_VIRT_IDX
	#define CACHE_FLAG_VIRT_IDX 0x800
#endif

#endif
