/* Copyright 2012 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* System module for Chrome EC */

#ifndef __CROS_EC_SYSTEM_H
#define __CROS_EC_SYSTEM_H

#include <stdnoreturn.h>

#include "atomic.h"
#include "common.h"
#include "compile_time_macros.h"
#include "console.h"
#include "ec_commands.h"
#include "timer.h"

#ifdef CONFIG_ZEPHYR
#ifdef CONFIG_CPU_CORTEX_M
/*
 * For cortex-m we cannot use irq_lock() for disabling all the interrupts
 * because it leaves some (NMI and faults) still enabled.
 */
#define interrupt_disable_all() __asm__("cpsid i")
#elif CONFIG_ZTEST
#define interrupt_disable_all()
#else /* !CONFIG_CPU_CORTEX_M */
#define interrupt_disable_all() irq_lock()
#endif
#else /* !CONFIG_ZEPHYR */
#define interrupt_disable_all() interrupt_disable()
#endif /* CONFIG_ZEPHYR */

/* Per chip implementation to save/read raw EC_RESET_FLAG_ flags. */
void chip_save_reset_flags(uint32_t flags);
uint32_t chip_read_reset_flags(void);

/**
 * Checks if running image is RW or not
 *
 * @return True if system is running in a RW image or false otherwise.
 */
int system_is_in_rw(void);

/**
 * Pre-initializes the module.  This occurs before clocks or tasks are
 * set up.
 */
void system_pre_init(void);

/**
 * System common pre-initialization; called after chip-specific
 * system_pre_init().
 */
void system_common_pre_init(void);

/**
 * Checks if manual recovery is detected or not
 *
 * @return Non zero if manual recovery is detected or zero otherwise.
 */
int system_is_manual_recovery(void);

/**
 * Set a flag indicating system is in recovery mode.
 */
void system_enter_manual_recovery(void);

/**
 * Set a flag indicating system left recovery mode.
 *
 * WARNING: This flag should be cleared right after a shutdown from recovery
 *          boot. You most likely shouldn't call this elsewhere.
 */
void system_exit_manual_recovery(void);

/**
 * Make sure AP shutdown completely, before call system_hibernate
 */
void system_enter_hibernate(uint32_t seconds, uint32_t microseconds);

/**
 * System common re-initialization; called to reset persistent state
 * left by system_common_pre_init().  This is useful for testing
 * scenarios calling system_common_pre_init() multiple times.
 */
__test_only void system_common_reset_state(void);

/**
 * @brief Allow tests to manually set the jump data address.
 *
 * This function allows an override of the location of the jump data (which is
 * normally set by either a panic or at the end of RAM). This function is used
 * by the zephyr integration to test the shim layer of the system module.
 *
 * @param test_jdata Pointer to the jump data memory allocated by the test.
 */
__test_only void system_override_jdata(void *test_jdata);

/**
 * Set up flags that should be saved to battery backed RAM.
 *
 * @param flags - flags passed into system_reset (i.e. SYSTEM_RESET_*)
 * @param *save_flags - flags to be saved in battery backed RAM
 */
void system_encode_save_flags(int flags, uint32_t *save_flags);

/**
 * Get the reset flags.
 *
 * @return Reset flags (EC_RESET_FLAG_*), or 0 if the cause is unknown.
 */
uint32_t system_get_reset_flags(void);

/**
 * Set reset flags.
 *
 * @param flags        Flags to set in reset flags
 */
void system_set_reset_flags(uint32_t flags);

/**
 * Clear reset flags.
 *
 * @param flags        Flags to clear in reset flags
 */
void system_clear_reset_flags(uint32_t flags);

/**
 * Print a description of the reset flags to the console.
 */
void system_print_reset_flags(void);

/**
 * Print a banner at boot, including image type, version, and reset type
 */
void system_print_banner(void);

/**
 * Check if system is locked down for normal consumer use.
 *
 * @return non-zero if the system is locked down for normal consumer use.
 * Potentially-dangerous developer and/or factory commands must be disabled
 * unless this command returns 0.
 *
 * This should be controlled by the same mechanism which write-protects the
 * read-only image (so that the only way to unlock the system is to unprotect
 * the read-only image).
 */
int system_is_locked(void);

/**
 * Disable jumping between images for the rest of this boot.
 */
void system_disable_jump(void);

/**
 * Return the image copy which is currently running.
 */
enum ec_image system_get_image_copy(void);

/**
 * Return the active RO image copy so that if we're in RW, we can know how we
 * got there. Only needed when there are multiple RO images.
 */
enum ec_image system_get_ro_image_copy(void);

/**
 * Return the program memory address where the image copy begins or should
 * begin. In the case of external storage, the image may or may not currently
 * reside at the location returned. Returns INVALID_ADDR if the image copy is
 * not supported.
 */
uintptr_t get_program_memory_addr(enum ec_image copy);
#define INVALID_ADDR ((uintptr_t)0xffffffff)

/**
 * Return non-zero if the system has switched between image copies at least
 * once since the last real boot.
 *
 * You probably need to call system_jumped_late instead if you're trying to
 * avoid initializing something again in RW.
 */
int system_jumped_to_this_image(void);

/**
 * Return non-zero if late (legacy) sysjump occurred.
 *
 * This happens when EFS failed but RO still jumped to RW late on AP's request.
 * This is typically called to avoid running some code twice (once in RO and
 * again in RW).
 */
int system_jumped_late(void);

/**
 * Preserve data across a jump between images.
 *
 * This may ONLY be called from within a HOOK_SYSJUMP handler.
 *
 * @param tag		Data type
 * @param size          Size of data; must be less than 255 bytes.
 * @param version       Data version, so that tag data can evolve as firmware
 *			is updated.
 * @param data		Pointer to data to save
 * @return EC_SUCCESS, or non-zero if error.
 */
int system_add_jump_tag(uint16_t tag, int version, int size, const void *data);

/**
 * Retrieve previously stored jump data
 *
 * This retrieves data stored by a previous image's call to
 * system_add_jump_tag().
 *
 * @param tag		Data type to retrieve
 * @param version	Set to data version if successful
 * @param size		Set to data size if successful
 * @return		A pointer to the data, or NULL if no matching tag is
 *			found.  This pointer will be 32-bit aligned.
 */
const uint8_t *system_get_jump_tag(uint16_t tag, int *version, int *size);

/**
 * Return the address just past the last usable byte in RAM.
 */
uintptr_t system_usable_ram_end(void);

/**
 * Return non-zero if the given range is overlapped with the active image.
 */
int system_unsafe_to_overwrite(uint32_t offset, uint32_t size);

/**
 * Return a text description of the image copy which is currently running.
 */
const char *system_get_image_copy_string(void);

/**
 * Return a text description of the passed image copy parameter.
 */
const char *ec_image_to_string(enum ec_image copy);

/**
 * Return the number of bytes used in the specified image.
 *
 * This is the actual size of code+data in the image, as opposed to the
 * amount of space reserved in flash for that image.
 *
 * @return actual image size in bytes, 0 if the image contains no content or
 * error.
 */
int system_get_image_used(enum ec_image copy);

/**
 * Jump to the specified image copy.
 */
int system_run_image_copy(enum ec_image copy);

/**
 * Get the rollback version for an image
 *
 * @param copy		Image copy to get version from, or SYSTEM_IMAGE_UNKNOWN
 *			to get the version for the currently running image.
 * @return The rollback version, negative value on error.
 */
int32_t system_get_rollback_version(enum ec_image copy);

/**
 * Get the image data of an image
 *
 * @param copy	Image copy to get the version of.
 * @return	Image data
 */
const struct image_data *system_get_image_data(enum ec_image copy);

/**
 * Get the version string for an image
 *
 * @param copy		Image copy to get version from, or SYSTEM_IMAGE_UNKNOWN
 *			to get the version for the currently running image.
 * @return The version string for the image copy, or an empty string if
 * error.
 */
const char *system_get_version(enum ec_image copy);

/**
 * Get the SKU ID for a device
 *
 * @return A value that identifies the SKU variant of a model. Its meaning and
 * the number of bits actually used is opaque outside board specific code.
 */
uint32_t system_get_sku_id(void);

/**
 * Return the board version number.  The meaning of this number is
 * board-dependent; boards where the code actually cares about this should
 * declare enum board_version in board.h.
 */
int system_get_board_version(void);

/**
 * Return information about the build including the version, build date and
 * user/machine which performed the build.
 */
const char *system_get_build_info(void);

/* Flags for system_reset() */
/*
 * Hard reset.  Cuts power to the entire system.  If not present, does a soft
 * reset which just resets the core and on-chip peripherals.
 */
#define SYSTEM_RESET_HARD               BIT(0)
/*
 * Preserve existing reset flags.  Used by flash pre-init when it discovers it
 * needs to do a hard reset to clear write protect registers.
 */
#define SYSTEM_RESET_PRESERVE_FLAGS     BIT(1)
/*
 * Leave AP off on next reboot, instead of powering it on to do EC software
 * sync.
 */
#define SYSTEM_RESET_LEAVE_AP_OFF       BIT(2)
/*
 * Indicate that this was a manually triggered reset.
 */
#define SYSTEM_RESET_MANUALLY_TRIGGERED BIT(3)
/*
 * Wait for reset pin to be driven, rather that resetting ourselves.
 */
#define SYSTEM_RESET_WAIT_EXT           BIT(4)
/*
 * Indicate that this reset was triggered by an AP watchdog
 */
#define SYSTEM_RESET_AP_WATCHDOG        BIT(5)
/*
 * Stay in RO next reboot, instead of potentially selecting RW during EFS.
 */
#define SYSTEM_RESET_STAY_IN_RO         BIT(6)

/**
 * Reset the system.
 *
 * @param flags		Reset flags; see SYSTEM_RESET_* above.
 */
#ifndef TEST_FUZZ
noreturn
#endif
void system_reset(int flags);

/**
 * Set a scratchpad register to the specified value.
 *
 * The scratchpad register must maintain its contents across a
 * software-requested warm reset.
 *
 * @param value		Value to store.
 * @return EC_SUCCESS, or non-zero if error.
 */
int system_set_scratchpad(uint32_t value);

/**
 * Return the current scratchpad register value.
 */
uint32_t system_get_scratchpad(void);

/**
 * Return the chip vendor/name/revision string.
 */
const char *system_get_chip_vendor(void);
const char *system_get_chip_name(void);
const char *system_get_chip_revision(void);

/**
 * Get a unique per-chip id.
 *
 * @param id		Set to the address of the unique id data (statically
 *			allocated, or register-backed).
 * @return Number of bytes available at the provided address.
 */
int system_get_chip_unique_id(uint8_t **id);

/**
 * Optional board-level function to read SKU ID.
 */
__override_proto uint32_t board_get_sku_id(void);

/**
 * Optional board-level function to read board version.
 */
__override_proto int board_get_version(void);

/**
 * Optional board-level function to pulse EC_ENTERING_RW.
 *
 * This should ONLY be overridden in very rare circumstances! AKA there better
 * be a good reason why you're overriding this!
 * The function ***MUST*** assert EC_ENTERING_RW for 1ms and then deassert it.
 */
__override_proto void board_pulse_entering_rw(void);

/**
 * Optional board-level callback functions to read a unique serial number per
 * chip. Default implementation reads from flash/otp (flash/otp_read_serial).
 */
__override_proto const char *board_read_serial(void);

/**
 * Optional board-level callback functions to write a unique serial number per
 * chip. Default implementation reads from flash/otp (flash/otp_write_serial).
 */
__override_proto int board_write_serial(const char *serial);


/**
 * Optional board-level callback functions to read a unique MAC address per
 * chip. Default implementation reads from flash.
 */
__override_proto const char *board_read_mac_addr(void);

/**
 * Optional board-level callback functions to write a unique MAC address per
 * chip. Default implementation reads from flash.
 */
__override_proto int board_write_mac_addr(const char *mac_addr);

/*
 * Common bbram entries. Chips don't necessarily need to implement
 * all of these, error will be returned from system_get/set_bbram if
 * not implemented.
 */
enum system_bbram_idx {
	/* PD state for CONFIG_USB_PD_DUAL_ROLE uses one byte per port */
	SYSTEM_BBRAM_IDX_PD0,
	SYSTEM_BBRAM_IDX_PD1,
	SYSTEM_BBRAM_IDX_PD2,
	SYSTEM_BBRAM_IDX_TRY_SLOT,
};

/* Maximum number of bbram indexes allotted for PD port state data */
#define MAX_SYSTEM_BBRAM_IDX_PD_PORTS 3

/**
 * Get/Set byte in battery-backed storage.
 *
 * @param idx		bbram byte to get / set.
 * @param value		byte to read / write from / to bbram.
 * @return		0 on success, !0 on error.
 */
int system_get_bbram(enum system_bbram_idx idx, uint8_t *value);
int system_set_bbram(enum system_bbram_idx idx, uint8_t value);

/**
 * Put the EC in hibernate (lowest EC power state).
 *
 * @param seconds	Number of seconds to hibernate.
 * @param microseconds	Number of microseconds to hibernate.
 *
 * The EC will hibernate until the wake pin is asserted.  If seconds and/or
 * microseconds is non-zero, the EC will also automatically wake after that
 * period.  If both are zero, the EC will only wake on a wake pin assert.  Very
 * short hibernation delays do not work well; if non-zero, the delays must be
 * at least SYSTEM_HIB_MINIMUM_DURATION.
 *
 * Note although the name is similar, EC hibernate is NOT the same as chipset
 * S4/hibernate.
 */
void system_hibernate(uint32_t seconds, uint32_t microseconds);

/**
 * Optional board-level callback functions called before and after initiating
 * chip-level hibernate sequence. These function may or may not return,
 * depending if the board implements an alternate hibernate method.  The _late
 * version is called after interrupts are disabled.
 */
void board_hibernate(void) __attribute__((weak));
void board_hibernate_late(void) __attribute__((weak));

/* Minimum duration to get proper hibernation */
#define SYSTEM_HIB_MINIMUM_DURATION 0, 150000

#ifdef CONFIG_RTC
/**
 * Read the real-time clock.
 *
 * @return The real-time clock value as a timestamp.
 */
timestamp_t system_get_rtc(void);
#endif /* defined(CONFIG_RTC) */

/**
 * Print out the current real-time clock value to the console.
 *
 * @param channel	Console channel to print on.
 */
#ifdef CONFIG_RTC
void print_system_rtc(enum console_channel channel);
#else
static inline void print_system_rtc(enum console_channel channel) { }
#endif /* !defined(CONFIG_RTC) */

/**
 * Enable hibernate interrupt
 */
void system_enable_hib_interrupt(void);

/* Low power modes for idle API */
enum {
	/*
	 * Sleep masks to prevent going in to deep sleep.
	 */
	SLEEP_MASK_AP_RUN     = BIT(0), /* the main CPU is running */
	SLEEP_MASK_UART       = BIT(1), /* UART communication ongoing */
	SLEEP_MASK_I2C_CONTROLLER = BIT(2), /* I2C controller comms ongoing */
	SLEEP_MASK_CHARGING   = BIT(3), /* Charging loop ongoing */
	SLEEP_MASK_USB_PWR    = BIT(4), /* USB power loop ongoing */
	SLEEP_MASK_USB_PD     = BIT(5), /* USB PD device connected */
	SLEEP_MASK_SPI        = BIT(6), /* SPI communications ongoing */
	SLEEP_MASK_I2C_PERIPHERAL = BIT(7), /* I2C peripheral comms ongoing */
	SLEEP_MASK_FAN        = BIT(8), /* Fan control loop ongoing */
	SLEEP_MASK_USB_DEVICE = BIT(9), /* Generic USB device in use */
	SLEEP_MASK_PWM        = BIT(10), /* PWM output is enabled */
	SLEEP_MASK_PHYSICAL_PRESENCE  = BIT(11), /* Physical presence
						    * detection ongoing */
	SLEEP_MASK_PLL        = BIT(12), /* High-speed PLL in-use */
	SLEEP_MASK_ADC        = BIT(13), /* ADC conversion ongoing */
	SLEEP_MASK_EMMC       = BIT(14), /* eMMC emulation ongoing */
	SLEEP_MASK_FORCE_NO_DSLEEP    = BIT(15), /* Force disable. */


	/*
	 * Sleep masks to prevent using slow speed clock in deep sleep.
	 */
	SLEEP_MASK_JTAG     = BIT(16), /* JTAG is in use. */
	SLEEP_MASK_CONSOLE  = BIT(17), /* Console is in use. */

	SLEEP_MASK_FORCE_NO_LOW_SPEED = BIT(31)  /* Force disable. */
};

/*
 * Current sleep mask. You may read from this variable, but must NOT
 * modify it; use enable_sleep() or disable_sleep() to do that.
 */
extern uint32_t sleep_mask;

/*
 * Macros to use to get whether deep sleep is allowed or whether
 * low speed deep sleep is allowed.
 */

#ifndef CONFIG_LOW_POWER_S0
#define DEEP_SLEEP_ALLOWED           (!(sleep_mask & 0x0000ffff))
#else
#define DEEP_SLEEP_ALLOWED           (!(sleep_mask & 0x0000ffff & \
				       (~SLEEP_MASK_AP_RUN)))
#endif
#define LOW_SPEED_DEEP_SLEEP_ALLOWED (!(sleep_mask & 0xffff0000))

/**
 * Enable low power sleep mask. For low power sleep to take affect, all masks
 * in the sleep mask enum above must be enabled.
 *
 * @param Sleep mask to enable.
 */
static inline void enable_sleep(uint32_t mask)
{
	atomic_clear_bits(&sleep_mask, mask);
}

/**
 * Disable low power sleep mask. For low power sleep to take affect, all masks
 * in the sleep mask enum above must be enabled.
 *
 * @param Sleep mask to enable.
 */
static inline void disable_sleep(uint32_t mask)
{
	atomic_or(&sleep_mask, mask);
}

#ifdef CONFIG_LOW_POWER_IDLE_LIMITED
/*
 * If this variable is nonzero, all levels of idle modes are disabled.
 * Do NOT access it directly. Use idle_is_disabled() to read it and
 * enable_idle()/disable_idle() to write it.
 */
extern uint32_t idle_disabled;

static inline uint32_t idle_is_disabled(void)
{
	return idle_disabled;
}

static inline void disable_idle(void)
{
	atomic_or(&idle_disabled, 1);
}

static inline void enable_idle(void)
{
	atomic_clear_bits(&idle_disabled, 1);
}
#endif

/* The following three functions are not available on all chips. */
/**
 * Postpone sleeping for at least this long, regardless of sleep_mask.
 *
 * @param Amount of time to postpone sleeping
 */
void delay_sleep_by(uint32_t us);

/*
 **
 * Functions to control deep sleep behavior. When disabled - the device never
 * falls into deep sleep (the lowest power consumption state exit of which
 * usually happens through the regular reset vector with just a few bits of
 * state preserved).
 */
void disable_deep_sleep(void);
void enable_deep_sleep(void);

/**
 * Use hibernate module to set up an RTC interrupt at a given
 * time from now
 *
 * Note: If time given is less than HIB_SET_RTC_MATCH_DELAY_USEC, then it will
 * set the interrupt at exactly HIB_SET_RTC_MATCH_DELAY_USEC.
 *
 * @param seconds      Number of seconds before RTC interrupt
 * @param microseconds Number of microseconds before RTC interrupt
 */
void system_set_rtc_alarm(uint32_t seconds, uint32_t microseconds);

/**
 * Disable and clear the RTC interrupt.
 */
void system_reset_rtc_alarm(void);

/**
 * Return address of little FW to prepare for sysjump
 *
 * Note: This feature is used for code ram arch
 *
 */
uint32_t system_get_lfw_address(void);

/**
 * Setup the destination image for a sysjump
 *
 * Note: This is called for devices with code ram arc by system code
 * just before the jump to the little firmware. It should store the
 * destination image so that it will be available to the little
 * firmware after the jump.
 *
 * @param copy		Region - (RO/RW) to use in code ram
 */
void system_set_image_copy(enum ec_image copy);

/**
 * Return which region is used in Code RAM
 *
 * Note: This feature is used for code ram arch
 *
 */
enum ec_image system_get_shrspi_image_copy(void);

/**
 * Determine reset vector will be jumped to the assigned address.
 *
 * @return The address of the reset vector for RO/RW firmware image jump.
 */
uintptr_t system_get_fw_reset_vector(uintptr_t base);

/**
 * Check if the EC is warm booting.
 *
 * @return true if the EC is warm booting.
 */
int system_is_reboot_warm(void);

#ifdef CONFIG_EXTENDED_VERSION_INFO
void system_print_extended_version_info(void);
#else
static inline void system_print_extended_version_info(void)
{
}
#endif

/**
 * Check if the system can supply enough power to boot AP
 *
 * @return true if the system is powered enough or false otherwise
 */
int system_can_boot_ap(void);

/**
 * Get active image copy
 *
 * Active slot contains an image which is being executed or will be executed
 * after sysjump.
 *
 * @return Active copy index
 */
enum ec_image system_get_active_copy(void);

/**
 * Get updatable (non-active) image copy
 *
 * @return Updatable copy index
 */
enum ec_image system_get_update_copy(void);

/**
 * Set active image copy
 *
 * @param copy Copy id to be activated.
 * @return     Non-zero if error.
 */
int system_set_active_copy(enum ec_image copy);

/**
 * Get flash offset of a RW copy
 *
 * @param copy Copy index to get the flash offset of.
 * @return     Flash offset of the slot storing <copy>
 */
uint32_t flash_get_rw_offset(enum ec_image copy);

/**
 * Compensate for the RTC after hibernation wake-up.
 */
void system_compensate_rtc(void);

#endif  /* __CROS_EC_SYSTEM_H */
