/*  *********************************************************************
 *  ASTRIS - Remote JTAG probe
 *
 *  Astris Apple SOC subclasses		File: astris_applesoc.h
 *
 *  This file provides the abstraction for a debuggable Apple SOC
 *
 *********************************************************************
 *
 *  Copyright (C) 2012-2020 Apple Inc. All rights reserved.
 *
 *  This document is the property of Apple Inc.
 *  It is considered confidential and proprietary.
 *
 *  This document may not be reproduced or transmitted in any form,
 *  in whole or in part, without the express written permission of
 *  Apple Inc.
 ********************************************************************* */

#ifndef _ASTRIS_APPLESOC_H
#define _ASTRIS_APPLESOC_H

#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>

#include "astris_soc.h"
#include "armdap.h"
#include "astris_product.h"

class AppleAcc_t;
class AppleAdvancedCore_t;
class EmuPlatformSlurper_t;
class GatewaySetup_t;
class AuthDebug_t;
class AuthEAM_t;
class SpmiDriver_t;
class SWDBypass;
class AWL_t;

class SoCBaseComponent;
class SoCPmgrComponentV1;

using AppleProductMap_t = std::map <std::string, AppleProduct_t *>;

////////////////////////////////////////////////////////////////////////////////
#pragma mark - AppleSOC
////////////////////////////////////////////////////////////////////////////////

class AppleSOC_t:
    public SOC_t {
public:

    AppleSOC_t(AXchip_t *chip, int aptype);

    virtual ~AppleSOC_t();

    // Specifiers for the platform runtime environment
    typedef enum class RuntimeEnv_e {
        kSilicon = 0x0,
        kFpga    = 0x2,
        kEmuFpga = 0x3,
        kPxp     = 0x4,
        kFastsim = 0x8,
        kHybrid  = 0xF,
    } RuntimeEnv;

    // Specifiers for the platform integration
    typedef enum class Integration_e {
        kUndef   = 0x0,
        kInt2    = 0x1,
        kInt2Gfx = 0x2,
        kInt2Pup = 0x4,
        kInt3    = 0x8,
        kInt3Gfx = 0xA,
    } Integration;

    /*!
     @enum ModelType_e
     @typedef ModelType
     @discussion Defines the model type for a subsystem
     @const kFastsim Present and is modeled by Fastsim
     @const kFPGA Present and is modeled in an FPGA using real RTL, but possibly FPGA-specific timing
     @const kRTL Present and is modeled in an emulation using real RTL
     @const kNotPresent Not implemented in the model
     @const kSilicon Not a real value, but is used by the implementation
     */
    typedef enum class ModelType_e {
        kFastsim = 0,
        kFPGA,
        kRTL,
        kNotPresent,
        kSilicon,
    } ModelType;

    const char *get_rev();

    // Assume all Apple SoCs are running XNU unless otherwise specified
    virtual int get_target_os(astris_target_os_t *os)
    {
        *os = ASTRIS_TARGET_OS_XNU;
        return ASTRIS_ERR_OK;
    }

    // It will init asc_dbgwrap_block and add it to SoC
    int asc_dbgwrap_block_init(AppleAdvancedCore_t *asc_dbgwrap_block);

    // Will handle disabling SMC watchdog and halt ASC cpus
    virtual int dbgwrap_block_asc_halt(AppleAdvancedCore_t *asc_dbgwrap_block, bool dump_regs, bool force_halt);

    /*!
     @function acc_halt
     @discussion Halt execution of the ACC cores. This is not necessarily
     implemented for all SoC types that are a subclass of SOC_t.
     @param dump_regs Dump registers to stdout on halt
     @param force_halt Forcibly halt the CPUs
     @result astris error code
     */
    virtual int acc_halt(bool dump_regs, bool force_halt);

    /*!
     @function acc_go
     @discussion Resume execution of the ACC cores. This is not necessarily
     implemented for all SoC types that are a subclass of SOC_t.
     @result astris error code
     */
    virtual int acc_go();

    int  attach_ps_register_to_cpu(const char *name, AXmemaddr_t ps_register);
    int  attach_ascreg_offset_to_cpu(const char *cpu_name, int offset);
    int  attach_asc_dbgack_to_cpu(const char *cpu_name, AXmemaddr_t dbgack);

    int  attach_dart(Dart *dart);
    int  find_dart_by_address(AXmemaddr_t dart_address, Dart * &out_dart);
    int  check_if_subsystem_present(const char *cpu_name);
    bool is_current_runtime(const char *runtime);
    bool is_current_integration(const char *integration);

    bool is_applesoc() {return true;}
    bool should_create_cpu(const struct cpu_desc_t &cpu_desc);

    virtual bool is_ide_explore_supported();

    virtual int switch_acg(bool on);
    virtual int restore_acg();

    virtual int acg_switch_preflight(bool on) {return ASTRIS_ERR_OK;}
    virtual int acg_restore_postflight()      {return ASTRIS_ERR_OK;}

    virtual int switch_dcs(bool on);
    virtual int restore_dcs();

    // crashlog information
    virtual int rtkos_reg_crash_log_base(AXmemaddr_t *reg_base) {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int rtkos_reg_crash_log_size(AXmemaddr_t *reg_sz)   {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int rtkos_buffer_remap(uint32_t *reg_base)          {return ASTRIS_ERR_OK;}

    virtual int is_kis_supported();

    virtual int platform_nmi(nmi_type_t nmi);
    virtual int platform_dfu();

    // These two functions sets up SoC to take coredump and cleans up once
    // coredump is taken
    virtual int setup_coredump(const char *cpuname)   {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int cleanup_coredump(const char *cpuname) {return ASTRIS_ERR_NOTSUPPORTED;}

    /*!
     @function get_dockch_list
     @discussion Returns list dock channel config.
     @param dockch_list list contains dock channel configuration of SoC
     @param dockch_count length of dock_list
     @result An ASTRIS_ERR code
    */
    virtual int get_dockch_list(const AXkisdockchannel_t **dockch_list, uint32_t *dockch_count) {dockch_list = NULL; dockch_count = 0; return ASTRIS_ERR_NOTSUPPORTED;}

    AXruntime_env_t get_ax_runtime_env();

    SWDBypass *m_bypass = NULL;

    // Enums for configuration of SMC Watchdog(s)
    enum wd_sel_e {
        SMC_WD_HW,   // SMC HW (hardware) watchdog
        SMC_WD_TASK, // SMC Task/SW (software) watchdog
        SMC_WD_AP    // Application Processor watchdog
    };

    virtual int debug_auth();

    virtual AuthDebug_t *get_debug_auth() {return m_auth_debug;}

    virtual AuthEAM_t *get_auth_eam() {return m_auth_eam;}

    /*!
     @function get_product_info
     @brief Access product info on this system, i.e. product name, PMU, DFU, etc
     @param[in,out] product_info pointer to AppleProduct_t to be filled in
     @return Astris Error Code
     */
    int get_product_info(AppleProduct_t * &product_info);
    int get_product_info_for_name(const char *name, AppleProduct_t * &product_info);
    int get_product_info_for_bid(uint32_t bid, AppleProduct_t * &product_info);

    int add_apple_product(prod_desc_t &prod);

    virtual int ap_wd_status(bool &expired);
    virtual int smc_slp_status(bool &is_panic);
    virtual int disable_watchdog(int wd_sel);

    // This struct will be filled in for SoCs that support doing SMBus operations
    //  (set all unused values to zero!) for each bus. For Apple SoCs, the logic
    //  for doing SMB operations is the same, so that code is shared.
    // Note: the values of the register addresses and values to be written for PS
    //  configuration are arbitrary. The SMB code initializes a bus by writing the
    //  specified values to registers, in the order here. So the table filled-in
    //  by the SoC-specific code can assign initialization registers/values as
    //  needed for each bus.
    // Also, even though each bus gets inited only once, the specified PS registers
    //  will get written each time another bus gets inited. That is, we only do
    //  the init as-needed, so you can't count on the PS registers being "already
    //  set up when an earlier bus was initialized". Buses will not be inited in
    //  a particular order, so each one needs to list all necessary PS registers.
    struct smb_init_reg_entry_t {
        AXmemaddr_t reg_addr;
        uint32_t    reg_value;
    };
    // For each SMBus, there must be a corresponding control structure that specifies
    // which registers to init and where the SMB control registers are.
    // The array of SMB control structs is indexed by bus number.
    // (The numbering is determined by the System EE team somewhat arbitrarily.)
    struct smb_control_t {
        const struct smb_init_reg_entry_t ps_init_array[8];   // Zeroes for unused entries
        const struct smb_init_reg_entry_t gpio_init_array[2]; // SDA and SCL pins
        const AXmemaddr_t                 smb_reg_base;       // SouthBridge.ASIO.ASIO_SMB[3], for example
    };

    int get_current_die() const {return m_soc_die;}

    /*!
     @function swtich_taps
     @discussion Default implementation returns ASTRIS_ERR_NOTSUPPORTED. SoC implementations override this function
        to allow bypassing JTAG to different TAPS.
     @param tap_to_switch_to TAP number to switch to.
     */
    virtual int switch_taps(unsigned int tap_to_switch_to);

    /*!
     @function dock_disconnect_mode
     @discussion Default implementation returns ASTRIS_ERR_NOTSUPPORTED. SoC implementations override this function to allow specific dock disconnect settings.
     @param[in] operation a dock disconnect mode operation to perform. See ax_dock_operation_t in astris_api.h.
     @param[out] previous the value of the dock disconnect mode prior to performing requested operation.
     @return Astris error code.

     */
    virtual int dock_disconnect_mode(ax_dock_operation_t operation, ax_dock_operation_t *previous);

    virtual int platform_dfu_eam();
    virtual int platform_dfu_dcm();

    virtual int memap_bus_read(unsigned int select, AXmemaddr_t addr, uint8_t *vals, int size, int *count, unsigned flags);
    virtual int memap_bus_write(unsigned int select, AXmemaddr_t addr, uint8_t *vals, int size, int *count, unsigned flags);

    AWL_t *get_awl() {return m_awl;}

    virtual int get_ecid(uint64_t *ecid);

    virtual int platform_get_sdom(uint8_t *sdom);

    SoCPmgrComponentV1 *getPMGRComp();

    virtual int spmi_read(astris_spmi_dev_addr_t dev_addr, astris_spmi_reg_addr_t reg_addr, uint64_t *value, uint8_t count);
    virtual int spmi_write(astris_spmi_dev_addr_t dev_addr, astris_spmi_reg_addr_t reg_addr, uint64_t value, uint8_t count);

protected:

    virtual uint32_t get_idcode();

    virtual int _query_soc_rev()                                   {return ASTRIS_ERR_OK;}
    virtual int _stop_clock_check()                                {return ASTRIS_ERR_OK;}
    virtual int get_platform_vers_reg(AXmemaddr_t &addr)           {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int get_platform_subsystem_info_reg(AXmemaddr_t &addr) {addr = 0; return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int dfu_check_reg(AXap_t *ap, AXmemaddr_t dfu_address, bool *isdfu);
    virtual int get_gd_bus(int *bus);
    virtual int get_match_info_from_soc(std::shared_ptr <MatchType_t> match_info);
    void        convert_product_info();

    /*
    @var _product_info
    Holds info for the cunrrently connected product. Check the product_name
    to see if this is actually filled out.
    */
    AppleProduct_t *_product_info = NULL;

    // Map to hold list of SOC product info tuples,
    // board_id maps to PMU type enum, product name, and DFU type
    std::map <uint16_t, std::tuple <pmu_type_e, std::string, AXdfu_type_t> > _soc_product_map;

    // match_info -> AppleProduct_t*
    AppleProductMap_t m_apple_product_map;

    int query_soc_rev_reg(AXap_t *ap, AXmemaddr_t addr, int shift_letter, int shift_number, int mask_letter = SOC_REV_DEFAULT_MASK, int mask_number = SOC_REV_DEFAULT_MASK);
    int stop_clock_check_reg(AXap_t *ap, AXmemaddr_t stop_clock_address);
    int query_platform_vers();
    int attach_ps_register_to_latest_cpu(AXmemaddr_t ps_register);
    int check_eam_dfu();

    static const uint32_t PLATFORM_VERS_RUNTIME_ENV_SHIFT = 28;
    static const uint32_t PLATFORM_VERS_RUNTIME_ENV_MASK  = (0xF << PLATFORM_VERS_RUNTIME_ENV_SHIFT);

    static const uint32_t PLATFORM_VERS_INTEGRATION_SHIFT = 18;
    static const uint32_t PLATFORM_VERS_INTEGRATION_MASK  = (0xF << PLATFORM_VERS_INTEGRATION_SHIFT);

    virtual uint32_t extract_integration(uint32_t platform_vers)
    {
        return (platform_vers & PLATFORM_VERS_INTEGRATION_MASK) >> PLATFORM_VERS_INTEGRATION_SHIFT;
    }

    static const std::map <RuntimeEnv, std::string> m_runtime_env_names;
    static const std::map <int, std::string> K_GENERIC_INTEGRATION_NAMES;

    // std::map <int, std::string> m_integration_names;
    virtual const std::map <int, std::string> get_integration_names() {return K_GENERIC_INTEGRATION_NAMES;}

    RuntimeEnv m_runtime_env = RuntimeEnv::kSilicon;                    // Assume we're on a silicon platform -- instantiate all cores
    int m_integration        = static_cast <int> (Integration::kUndef); // Integration doesn't have much meaning on a silicon target

    EmuPlatformSlurper_t *m_platform_slurper = NULL;
    std::map <std::string, ModelType> m_subsystem_info;

    //for use in getting SoC Revision from Live chip
    const int K_REVISION_NOT_YET_FETCHED = 0xFFFF;
    int m_revision_num                   = K_REVISION_NOT_YET_FETCHED;
    char m_revision_str[4]               = {0};

    virtual int get_acg_reg(AXmemaddr_t &addr) {return ASTRIS_ERR_NOTSUPPORTED;}
    const uint32_t K_ACG_NOT_CACHED = 0xFFFFFFFF;
    uint32_t m_cached_acg           = K_ACG_NOT_CACHED;

    virtual int get_dcs_register_addrs(const std::vector <AXmemaddr_t> * &regs) {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int get_dcs_register_cached(std::vector <uint32_t> * &cached)       {return ASTRIS_ERR_NOTSUPPORTED;}

    bool m_cached_dcs = false;

    static const uint32_t MCUBCGPwrGateEn = _MM_MAKEMASK1(12);

    GatewaySetup_t *m_gateway_setup = NULL;
    virtual int _take_gateway_control();
    virtual int _release_gateway_control();

    virtual int  get_defected_cpus(uint32_t *defected_cpus)                                      {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int  get_defected_cpus_asc(int group, const char *cpu_name, uint32_t *defected_cpus) {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual bool is_cpu_defected(const struct cpu_desc_t &cpu_desc);

    virtual int get_asc_dbgwrap_block_reg(AXmemaddr_t &addr) {return ASTRIS_ERR_NOTSUPPORTED;}

    int m_soc_die             = 0;
    AuthDebug_t *m_auth_debug = NULL;

    AuthEAM_t *m_auth_eam = NULL;

    virtual int get_nmi_reg(AXmemaddr_t &nmi_reg) {return ASTRIS_ERR_NOTSUPPORTED;}

    // Pointer to the currently initialized SPMI driver instance
    SpmiDriver_t *m_spmi = NULL;

    // Pointer to the currently initialized AWL instance
    AWL_t *m_awl = NULL;

    /*!
     @function init_spmi_driver
     @brief Create a new SpmiDriver_t class for this SoC and initialize its state so it is ready to use
     @param[in,out] driver Address of the SpmiDriver_t pointer to be initialized
     @return Astris Error Code
     */
    virtual int init_spmi_driver(SpmiDriver_t **driver) {*driver = NULL; return ASTRIS_ERR_NOTSUPPORTED;}

    virtual int set_spmi_interface(uint8_t bus_sel) {return bus_sel == 0 ? ASTRIS_ERR_OK : ASTRIS_ERR_NOTSUPPORTED;}

    // SOCD interface functions inherit from astris_soc.h
    virtual int get_socd_buffer(char *socd[], uint32_t socd_size[]);
    virtual int get_socd_info(bool valid[], uint32_t socd_size[]);
    virtual int invalidate_socd_info();

    virtual int smb_read(uint8_t bus, uint32_t dev_addr, uint32_t reg_addr, uint8_t addr_len, uint8_t *data, size_t *count);
    virtual int smb_write(uint8_t bus, uint32_t dev_addr, uint8_t *data, size_t *count);
    virtual int smb_init(uint8_t bus);

    virtual int read_eeprom_i2c(uint8_t smb_bus, uint8_t dev_addr, uint16_t reg_addr, uint16_t bytes, uint8_t * &buf);

    static const uint16_t MAX_SMB_READ_SIZE    = 128;
    const struct smb_control_t *m_smb_controls = NULL; // array indexed by bus #
    uint8_t m_num_smb_buses                    = 0;
    bool *m_smb_inited                         = NULL;
    int m_gd_bus                               = -1;

    // Update for soc-specific values in SoC constructor
    AXmemaddr_t _ap_watchdog_status_register_address = 0;
    uint16_t _ap_watchdog_expired_bit_shift          = 0;
    AXmemaddr_t _smc_slp_status_register_address     = 0;
    uint16_t _smc_slp_ispanic_bit_shift              = 0;
    AXmemaddr_t _smc_watchdog_timer_ctrl_reg_addr    = 0;
    uint32_t _smc_wd_hw_disable_value                = 0;
    AXmemaddr_t _smc_wd_task_ctrl_reg_addr           = 0;
    uint16_t _smc_wd_task_disable_bit_shift          = 0;
    AXmemaddr_t _ap_watchdog_ctrl_reg_addr           = 0;
    uint16_t _ap_watchdog_disable_bit_shift          = 0;

    /*!
     @function is_dbgwrap_loopback_allowed
     @brief Returns if SoC allows a memap 4 access generated by the debugger,
     to loopback into dbgwrap. On modern socs, this is not allowed because the
     access itself is initiated from dbgwrap (DAP) and comes back in, this can
     cause issues like hangs.
     @return boolean that says if loopback is allowed
     */
    virtual bool is_dbgwrap_loopback_allowed() {return true;}

    /*!
     @function dbgwrap_loopback_access_remap
     @brief This function is called within memap_bus_read and memap_bus_write
     and will remap the address from memap 4 to memap 1 if loopback is not allowed.
     @param[in,out] select Select used for the access
     @param[in,out] addr Address of the access
     */
    virtual void dbgwrap_loopback_access_remap(unsigned int &select, AXmemaddr_t &addr);

    /*!
     @function  check_and_clear_cpu_impl_pio
     @brief Apple ISA Extensions to ARMv8 : version H16
     13.3 Implementation Defined Register Write Locks
     On Ibiza+ we are enabling implementation defined register
     locks (non ARM-ISA) for MSR and most PIO writes.
     Before writing to ACC_OVRD, DBG_WRAP, DBG_WRAP_GLB
     registers astris needs to check and clear RO fields in IMPL_CPU_PIO_RO_CTL0
     and IMPL_ACC_PIO_RO_CTL0 rdar://103933784
     In Donan+ DBG_WRAP register moved to a block protected by
     AP_DEBUG_EN and no longer needs to be checked.
     This function is called memap_bus_write
     and will check and unlock any impl_cpu_pio_ro fields
     @param[in] addr Address of the write access
     */
    virtual int check_and_clear_cpu_impl_pio(AXmemaddr_t addr);
    bool m_cpu_impl_ro_cleared = false;

    // ISA registers that need to be unlocked before write
    std::unordered_set<AXmemaddr_t> m_impl_cpu_pio_reg;
    // ISA Unlock registers to lock mask
    std::unordered_map<AXmemaddr_t, uint64_t> m_impl_cpu_pio_ctl;
    
    int addComponent(SoCBaseComponent * newComponent);
    
private:
    static const int SOC_REV_DEFAULT_MASK = 0x7;
    //Vector to hold components, private so the addComponent is used.
    //Each component is at index of the type it is
    std::vector<SoCBaseComponent*> m_component;

};

#pragma mark AppleSoC Helper Functions
int astris_soc_get_applesoc(AXchip_t *chip, AppleSOC_t * &applesoc);
int astris_soc_convert_to_applesoc(SOC_t *basesoc, AppleSOC_t * &applesoc);

////////////////////////////////////////////////////////////////////////////////
#pragma mark - H5x
////////////////////////////////////////////////////////////////////////////////

class AppleH5x_t:
    public AppleSOC_t {
public:
    AppleH5x_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AHB) {}

protected:
    virtual int _create_cpus();
    virtual int _query_soc_rev();
    virtual int _preinit_hw();
    virtual int _postinit_hw();

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual int cpu_cache_info_group0_level(AXcpu_t *cpu, AXcacheinfo_t *info, AXcpu_cache_level_t cache_level);
    virtual int cpu_cache_clean_group0(AXcpu_t *cpu, AXcpu_cache_level_t cache_level);

private:

    // Nothing to see here...

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - H5P
////////////////////////////////////////////////////////////////////////////////

class AppleH5P_t:
    public AppleH5x_t {
public:
    AppleH5P_t(AXchip_t *chip) :
        AppleH5x_t(chip) {}

    virtual const char *get_name() {return "H5P";}

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x3f10601c; /* PMGR_SCRATCH7 */}
};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Bali
////////////////////////////////////////////////////////////////////////////////

class AppleBali_t:
    public AppleH5x_t {
public:
    AppleBali_t(AXchip_t *chip) :
        AppleH5x_t(chip) {}

    virtual const char *get_name() {return "Bali";}

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x3f10601c; /* PMGR_SCRATCH7 */}
};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Alcatraz
////////////////////////////////////////////////////////////////////////////////

class AppleAlcatraz_t:
    public AppleSOC_t {
public:
    AppleAlcatraz_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name()     {return "Alcatraz";}
    virtual const char *get_gpu_name() {return "g3";}
    virtual bool        is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int         xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x20e02901cULL; /* PMGR_SCRATCH7 */}

protected:
    virtual int  _create_cpus();
    virtual int  _create_acc();
    virtual int  _query_soc_rev();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();
    virtual bool _was_reset();

    static const int K_ID_ACC = 0;

    static const int K_ID_CPU0 = 0;
    static const int K_ID_CPU1 = 1;

    AppleAcc_t *m_acc = NULL;

private:

    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN = 0xCF001030;
    static const uint32_t DbgCsyspwrupreqPwrDownAmc = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqPwrDownCcc = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqPwrDownAcs = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqPwrDownIsp = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqPwrDownAns = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDownSep = (0x1 << 4);

    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE = 0xCF001034;
    static const uint32_t DbgCsyspwrupreqClkGateAmc = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqClkGateAcs = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqClkGateIsp = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqClkGateAns = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqClkGateSep = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqClkGateSio = (0x1 << 0);

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Alcatraz SOC TAP
////////////////////////////////////////////////////////////////////////////////

class AppleAlcatrazTAP_t:
    public SOC_t {
public:
    AppleAlcatrazTAP_t(AXchip_t *chip) :
        SOC_t(chip, -1) {}

    virtual const char *get_name() {return "AlcatrazTAP";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len) {return false;}

protected:
    virtual int _create_cpus();

private:
};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Fiji
////////////////////////////////////////////////////////////////////////////////

class AppleFiji_t:
    public AppleSOC_t {
public:
    AppleFiji_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name()     {return "Fiji";}
    virtual const char *get_gpu_name() {return "g4p";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x20e02901cULL; /* PMGR_SCRATCH7 */}
    virtual bool        has_two_stage_iOS_boot()         {return true;}

protected:
    virtual int  _create_cpus();
    virtual int  _create_acc();
    virtual int  _query_soc_rev();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();
    virtual bool _was_reset();

    static const int K_ID_ACC = 0;

    static const int K_ID_CPU0 = 0;
    static const int K_ID_CPU1 = 1;

    AppleAcc_t *m_acc = NULL;

private:

    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN = 0xCF001030;
    static const uint32_t DbgCsyspwrupreqPwrDownAmc = (0x1 << 28);
    static const uint32_t DbgCsyspwrupreqPwrDownPci = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqPwrDownAcs = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqPwrDownAve = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqPwrDownIsp = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqPwrDownAns = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDownSep = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqPwrDownTcc = (0x1 << 0);

    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE = 0xCF001034;
    static const uint32_t DbgCsyspwrupreqClkGateAmc = (0x1 << 28);
    static const uint32_t DbgCsyspwrupreqClkGatePci = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqClkGateAcs = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqClkGateAve = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqClkGateIsp = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqClkGateAns = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqClkGateSep = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqClkGateSio = (0x1 << 0);

    static const uint32_t PMGR_PS_MEDIA_PS     = 0xCE0202D8;
    static const uint32_t PMGR_PS_VENC_CPU_PS  = 0xCE020300;
    static const uint32_t PMGR_PS_VENC_PIPE_PS = 0xCE021000;
    static const uint32_t PMGR_PS_VENC_ME0_PS  = 0xCE021008;
    static const uint32_t PMGR_PS_VENC_ME1_PS  = 0xCE021010;

    static const uint32_t ave_MbInputMCpu_Ctrl      = 0xC7D32008;
    static const uint32_t ave_IntraEstMCpu_Ctrl     = 0xC7D42008;
    static const uint32_t ave_MotionEstMCpu_Ctrl    = 0xC7D52008;
    static const uint32_t ave_ModeDecisionMCpu_Ctrl = 0xC7D62008;
    static const uint32_t ave_ReconLMCpu_Ctrl       = 0xC7D82008;
    static const uint32_t ave_ReconCMCpu_Ctrl       = 0xC7DA2008;
    static const uint32_t ave_CavlcMCpu_Ctrl        = 0xC7DC2008;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Capri
////////////////////////////////////////////////////////////////////////////////

class AppleCapri_t:
    public AppleFiji_t {
public:
    AppleCapri_t(AXchip_t *chip) :
        AppleFiji_t(chip) {}

    virtual const char *get_name()     {return "Capri";}
    virtual const char *get_gpu_name() {return "g4g";}
    virtual int         xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

protected:
    virtual int _create_cpus();
    virtual int _create_acc();

    static const int K_ID_CPU2 = 2;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - S3E
////////////////////////////////////////////////////////////////////////////////

class AppleS3E_t:
    public AppleSOC_t {
public:
    AppleS3E_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name() {return "S3E";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);

protected:
    virtual int  _create_cpus();
    virtual int  _query_soc_rev();
    virtual int  _preinit_hw();
    virtual bool _cleanup_hw();

private:

    static const uint32_t R_DAPUSER    = 0x74780044;
    static const uint32_t M_DAPUSER_AR = _MM_MAKEMASK1(0);
    static const uint32_t M_DAPUSER_AW = _MM_MAKEMASK1(1);
};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - S3X
////////////////////////////////////////////////////////////////////////////////

class AppleS3X_t:
    public AppleSOC_t {
public:
    AppleS3X_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name() {return "S3X";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);

protected:
    virtual int  _create_cpus();
    virtual int  _query_soc_rev();
    virtual int  _preinit_hw();
    virtual bool _cleanup_hw();

private:

    static const uint32_t R_DBG_ROMENTRY19 = 0x74300064;
};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - S4E
////////////////////////////////////////////////////////////////////////////////

class AppleS4E_t:
    public AppleSOC_t {
public:
    AppleS4E_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name() {return "S4E";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);

protected:
    virtual int  _create_cpus();
    virtual int  _query_soc_rev();
    virtual int  _preinit_hw();
    virtual bool _cleanup_hw();

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - M7
////////////////////////////////////////////////////////////////////////////////

class AppleM7_t:
    public AppleSOC_t {
public:
    AppleM7_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name() {return "M7";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x46c2901c; /* PMGR_SCRATCH7 */}

protected:
    virtual int  _create_cpus();
    virtual int  _query_soc_rev();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();

    virtual int cpu_cache_info_group0_level(AXcpu_t *cpu, AXcacheinfo_t *info, AXcpu_cache_level_t cache_level);
    virtual int cpu_cache_clean_group0(AXcpu_t *cpu, AXcpu_cache_level_t cache_level);

private:

    static const uint32_t dbgWrap_base = 0xC6EB0000;

    static const uint32_t dbgWrap_DBG_CSYSPWRUP = (dbgWrap_base + 0x1030);
    static const uint32_t DbgCsyspwrupSys       = (0x1 << 12);
    static const uint32_t DbgCsyspwrupCpu       = (0x1 << 8);
    static const uint32_t DbgCsyspwrupSpuAkf    = (0x1 << 4);
    static const uint32_t DbgCsyspwrupMem       = (0x1 << 0);

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - M8
////////////////////////////////////////////////////////////////////////////////

class AppleM8_t:
    public AppleSOC_t {
public:
    AppleM8_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name()     {return "M8";}
    virtual const char *get_gpu_name() {return "gx2";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x481b8004; /* miniPMGR_SCRATCH1 */}

protected:
    virtual int  _create_cpus();
    virtual int  _query_soc_rev();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();
    virtual int  _stop_clock_check();

    virtual int cpu_cache_info_group0_level(AXcpu_t *cpu, AXcacheinfo_t *info, AXcpu_cache_level_t cache_level);
    virtual int cpu_cache_clean_group0(AXcpu_t *cpu, AXcpu_cache_level_t cache_level);

    static const uint32_t dbgWrap_base = 0xC8400000; // AOP.dbgWrap

    static const uint32_t dbgWrap_dbg_regs_offset = 0x00010000;

    // AOP.dbgWrap.dbg_regs.DBG_CSYSPWRUPREQ_PWR_DOWN_AKF (override power-downs)
    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN_AKF = (dbgWrap_base + dbgWrap_dbg_regs_offset + 0x0030);
    static const uint32_t DbgCsyspwrupreqPwrDownAop1    = (0x1 << 31);
    static const uint32_t DbgCsyspwrupreqPwrDownAp1     = (0x1 << 28);
    static const uint32_t DbgCsyspwrupreqPwrDownAp0     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqPwrDownAop     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqPwrDownAve     = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqPwrDownIsp     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqPwrDownAns     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDownSep     = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqPwrDownSdio    = (0x1 << 0);

    // AOP.dbgWrap.dbg_regs.DBG_CSYSPWRUPREQ_CLK_GATE_AKF (override clock-gating)
    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE_AKF = (dbgWrap_base + dbgWrap_dbg_regs_offset + 0x0034);
    static const uint32_t DbgCsyspwrupreqClkGateAop1    = (0x1 << 31);
    static const uint32_t DbgCsyspwrupreqClkGateAp1     = (0x1 << 28);
    static const uint32_t DbgCsyspwrupreqClkGateAp0     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqClkGateAop     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqClkGateAve     = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqClkGateIsp     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqClkGateAns     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqClkGateSep     = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqClkGateSdio    = (0x1 << 0);

    // AOP.dbgWrap.dbg_regs.DBG_CSYSPWRUPREQ_PWR_DOWN_PRT (override power-down)
    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN_PRT = (dbgWrap_base + dbgWrap_dbg_regs_offset + 0x0038);
    static const uint32_t DbgCsyspwrupreqPwrDownAp      = (0x1 << 4);

    // STOP CLOCK register to check if the clocks are stopped
    static const AXmemaddr_t DBG_SOC_HALT_ACTIVE = (dbgWrap_base + dbgWrap_dbg_regs_offset + 0x003C);

    // Chip rev is stored in FUSE4 of the MiniPMGR configuration fuse block.
    // The address given below is 0x481BC010 adjusted to use the addressing mode
    // needed to go across DBG-AP.
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE4 = 0xC81BC010ULL;

    // Fuse4[27:25] = base/major/letter ID, Fuse4[24:22] = metal/minor/number ID
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE4_CHIP_REV_BASE_SHIFT  = 25;
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE4_CHIP_REV_METAL_SHIFT = 22;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - M8W
////////////////////////////////////////////////////////////////////////////////

class AppleM8W_t:
    public AppleM8_t {
public:
    AppleM8W_t(AXchip_t *chip) :
        AppleM8_t(chip) {}

    virtual const char *get_name()     {return "M8";}
    virtual const char *get_gpu_name() {return "gx2";}

protected:
    virtual int  _create_cpus();
    virtual int  _preinit_hw();
    virtual bool _cleanup_hw();

    static const uint32_t dbgWrap_base = 0xC8400000;

    // AOP.dbgWrap.dbg_regs.DBG_CSYSPWRUPREQ_PWR_DOWN_HENRY (override power-down)
    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN_HENRY = (dbgWrap_base + dbgWrap_dbg_regs_offset + 0x00a8);
    static const uint32_t DbgCsyspwrupreqPwrDown_wl_phy   = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqPwrDown_wl_mac   = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDown_bt_phy   = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqPwrDown_bt_mac   = (0x1 << 0);

    // AOP.dbgWrap.dbg_regs.DBG_CSYSPWRUPREQ_PWR_DOWN_HENRY (override power-down)
    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE_HENRY = (dbgWrap_base + dbgWrap_dbg_regs_offset + 0x00ac);
    static const uint32_t DbgCsyspwrupreqClkGate_wl_phy   = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqClkGate_wl_mac   = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqClkGate_bt_phy   = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqClkGate_bt_mac   = (0x1 << 0);

private:

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - M8P
////////////////////////////////////////////////////////////////////////////////

class AppleM8P_t:
    public AppleM8_t {
public:
    AppleM8P_t(AXchip_t *chip) :
        AppleM8_t(chip) {}

    virtual const char *get_name()     {return "M8P";}
    virtual const char *get_gpu_name() {return "gx2";}

protected:
    virtual int  _create_cpus();
    virtual int  _preinit_hw();
    virtual bool _cleanup_hw();

    static const uint32_t dbgWrap_base = 0xC8400000;

    // AOP.dbgWrap.dbg_regs.DBG_CSYSPWRUPREQ_PWR_DOWN_HENRY (override power-down)
    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN_HENRY = (dbgWrap_base + dbgWrap_dbg_regs_offset + 0x00a8);
    static const uint32_t DbgCsyspwrupreqPwrDown_wl_phy   = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqPwrDown_wl_mac   = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDown_bt_phy   = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqPwrDown_bt_mac   = (0x1 << 0);

    // AOP.dbgWrap.dbg_regs.DBG_CSYSPWRUPREQ_PWR_DOWN_HENRY (override power-down)
    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE_HENRY = (dbgWrap_base + dbgWrap_dbg_regs_offset + 0x00ac);
    static const uint32_t DbgCsyspwrupreqClkGate_wl_phy   = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqClkGate_wl_mac   = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqClkGate_bt_phy   = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqClkGate_bt_mac   = (0x1 << 0);

private:

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - M9
////////////////////////////////////////////////////////////////////////////////

class AppleM9_t:
    public AppleSOC_t {
public:
    AppleM9_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name()     {return "M9";}
    virtual const char *get_gpu_name() {return "g11m";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x23d2b8004ULL; /* SouthBridge.NUB.PMGR_AON.MINI_SCRATCH.SCRATCH1 */}

protected:
    virtual int  _create_cpus();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();
    virtual int  _stop_clock_check();
    virtual int  _query_soc_rev();

    virtual int get_platform_vers_reg(AXmemaddr_t &addr)
    {
        addr = PMGR_AON_FUSE_ECID_FUSE3;
        return ASTRIS_ERR_OK;
    }

    virtual int get_acg_reg(AXmemaddr_t &addr)
    {
        addr = PMGR_SOC_MISC_CFG_ACG;
        return ASTRIS_ERR_OK;
    }

    virtual int get_dcs_register_addrs(const std::vector <AXmemaddr_t> * &regs)
    {
        regs = &DCS_MCU_AMCGEN_AMCCLK_PWRGATE_REGS;
        return ASTRIS_ERR_OK;
    }

    virtual int get_dcs_register_cached(std::vector <uint32_t> * &cached)
    {
        cached = &DCS_MCU_AMCGEN_AMCCLK_PWRGATE_REGS_CACHED;
        return ASTRIS_ERR_OK;
    }

    virtual int get_nmi_reg(AXmemaddr_t &nmi_reg)
    {
        nmi_reg = ASCWRAP_KIC_SW_GEN_SET_0;
        return ASTRIS_ERR_OK;
    }

    virtual int cpu_cache_info_group0_level(AXcpu_t *cpu, AXcacheinfo_t *info, AXcpu_cache_level_t cache_level);
    virtual int cpu_cache_clean_group0(AXcpu_t *cpu, AXcpu_cache_level_t cache_level);

    static const uint32_t dbgWrap_base = 0xFD300000; // SouthBridge.NUB.dbgWrap

    // power gating defeatures for various blocks in the system
    // (in the SouthBridge.NUB.dbgWrap.DBGWRAP_REGS.Debug_Power_and_Clock_Control block)
    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_1 = 0xFD320200;
    static const uint32_t DbgCsyspwrupReqPwrDownMsp      = (0x1 << 28);
    static const uint32_t DbgCsyspwrupReqPwrDownPcie     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupReqPwrDownDisp     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupReqPwrDownSce      = (0x1 << 16);
    static const uint32_t DbgCsyspwrupReqPwrDownAvd      = (0x1 << 12);
    static const uint32_t DbgCsyspwrupReqPwrDownSdio     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupReqPwrDownAve      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupReqPwrDownIsp      = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_2 = 0xFD320204;
    static const uint32_t DbgCsyspwrupReqPwrDownAne      = (0x1 << 28);
    static const uint32_t DbgCsyspwrupReqPwrDownAns2     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupReqPwrDownGfx      = (0x1 << 20);
    static const uint32_t DbgCsyspwrupReqPwrDownSio      = (0x1 << 16);
    static const uint32_t DbgCsyspwrupReqPwrDownRtp      = (0x1 << 12);
    static const uint32_t DbgCsyspwrupReqPwrDownAop      = (0x1 << 8);
    static const uint32_t DbgCsyspwrupReqPwrDownSmc      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupReqPwrDownSep      = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_3 = 0xFD320208;
    static const uint32_t DbgCsyspwrupReqPwrDownAcs      = (0x1 << 28);
    static const uint32_t DbgCsyspwrupReqPwrDownWlmac    = (0x1 << 24);
    static const uint32_t DbgCsyspwrupReqPwrDownBtmac    = (0x1 << 20);
    static const uint32_t DbgCsyspwrupReqPwrDownHot      = (0x1 << 16);
    static const uint32_t DbgCsyspwrupReqPwrDownAp       = (0x1 << 12);
    static const uint32_t DbgCsyspwrupReqPwrDownSbr      = (0x1 << 8);
    static const uint32_t DbgCsyspwrupReqPwrDownMcc      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupReqPwrDownAcc      = (0x1 << 0);

    // ACK bits for power down of subsystems containing debug components
    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_1 = 0xFD32020C;
    static const uint32_t DbgCsyspwrupAckPwrDownMsp      = (0x1 << 28);
    static const uint32_t DbgCsyspwrupAckPwrDownPcie     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupAckPwrDownDisp     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupAckPwrDownSce      = (0x1 << 16);
    static const uint32_t DbgCsyspwrupAckPwrDownAvd      = (0x1 << 12);
    static const uint32_t DbgCsyspwrupAckPwrDownSdio     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupAckPwrDownAve      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupAckPwrDownIsp      = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_2 = 0xFD320210;
    static const uint32_t DbgCsyspwrupAckPwrDownAne      = (0x1 << 28);
    static const uint32_t DbgCsyspwrupAckPwrDownAns2     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupAckPwrDownGfx      = (0x1 << 20);
    static const uint32_t DbgCsyspwrupAckPwrDownSio      = (0x1 << 16);
    static const uint32_t DbgCsyspwrupAckPwrDownRtp      = (0x1 << 12);
    static const uint32_t DbgCsyspwrupAckPwrDownAop      = (0x1 << 8);
    static const uint32_t DbgCsyspwrupAckPwrDownSmc      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupAckPwrDownSep      = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_3 = 0xFD320214;
    static const uint32_t DbgCsyspwrupAckPwrDownAcs      = (0x1 << 28);
    static const uint32_t DbgCsyspwrupAckPwrDownWlmac    = (0x1 << 24);
    static const uint32_t DbgCsyspwrupAckPwrDownBtmac    = (0x1 << 20);
    static const uint32_t DbgCsyspwrupAckPwrDownHot      = (0x1 << 16);
    static const uint32_t DbgCsyspwrupAckPwrDownAp       = (0x1 << 12);
    static const uint32_t DbgCsyspwrupAckPwrDownSbr      = (0x1 << 8);
    static const uint32_t DbgCsyspwrupAckPwrDownMcc      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupAckPwrDownAcc      = (0x1 << 0);

    // clock gating defeatures for various subsystems
    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_1 = 0xFD320218;
    static const uint32_t DbgCsysclkonReqClkGateMsp      = (0x1 << 28);
    static const uint32_t DbgCsysclkonReqClkGatePcie     = (0x1 << 24);
    static const uint32_t DbgCsysclkonReqClkGateDisp     = (0x1 << 20);
    static const uint32_t DbgCsysclkonReqClkGateSce      = (0x1 << 16);
    static const uint32_t DbgCsysclkonReqClkGateAvd      = (0x1 << 12);
    static const uint32_t DbgCsysclkonReqClkGateSdio     = (0x1 << 8);
    static const uint32_t DbgCsysclkonReqClkGateAve      = (0x1 << 4);
    static const uint32_t DbgCsysclkonReqClkGateIsp      = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_2 = 0xFD32021C;
    static const uint32_t DbgCsysclkonReqClkGateAne      = (0x1 << 28);
    static const uint32_t DbgCsysclkonReqClkGateAns2     = (0x1 << 24);
    static const uint32_t DbgCsysclkonReqClkGateGfx      = (0x1 << 20);
    static const uint32_t DbgCsysclkonReqClkGateSio      = (0x1 << 16);
    static const uint32_t DbgCsysclkonReqClkGateRtp      = (0x1 << 12);
    static const uint32_t DbgCsysclkonReqClkGateAop      = (0x1 << 8);
    static const uint32_t DbgCsysclkonReqClkGateSmc      = (0x1 << 4);
    static const uint32_t DbgCsysclkonReqClkGateSep      = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_3 = 0xFD320220;
    static const uint32_t DbgCsysclkonReqClkGateAcs      = (0x1 << 16);
    static const uint32_t DbgCsysclkonReqClkGateSbr      = (0x1 << 12);
    static const uint32_t DbgCsysclkonReqClkGateMcc      = (0x1 << 8);
    static const uint32_t DbgCsysclkonReqClkGateWlmac    = (0x1 << 4);
    static const uint32_t DbgCsysclkonReqClkGateBtmac    = (0x1 << 0);

    // ACK bits for clock gating of subsystems containing debug components
    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_1 = 0xFD320224;
    static const uint32_t DbgCsysclkonAckClkGateMsp      = (0x1 << 28);
    static const uint32_t DbgCsysclkonAckClkGatePcie     = (0x1 << 24);
    static const uint32_t DbgCsysclkonAckClkGateDisp     = (0x1 << 20);
    static const uint32_t DbgCsysclkonAckClkGateSce      = (0x1 << 16);
    static const uint32_t DbgCsysclkonAckClkGateAvd      = (0x1 << 12);
    static const uint32_t DbgCsysclkonAckClkGateSdio     = (0x1 << 8);
    static const uint32_t DbgCsysclkonAckClkGateAve      = (0x1 << 4);
    static const uint32_t DbgCsysclkonAckClkGateIsp      = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_2 = 0xFD320228;
    static const uint32_t DbgCsysclkonAckClkGateAne      = (0x1 << 28);
    static const uint32_t DbgCsysclkonAckClkGateAns2     = (0x1 << 24);
    static const uint32_t DbgCsysclkonAckClkGateGfx      = (0x1 << 20);
    static const uint32_t DbgCsysclkonAckClkGateSio      = (0x1 << 16);
    static const uint32_t DbgCsysclkonAckClkGateRtp      = (0x1 << 12);
    static const uint32_t DbgCsysclkonAckClkGateAop      = (0x1 << 8);
    static const uint32_t DbgCsysclkonAckClkGateSmc      = (0x1 << 4);
    static const uint32_t DbgCsysclkonAckClkGateSep      = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_3 = 0xFD32022C;
    static const uint32_t DbgCsysclkonAckClkGateAcs      = (0x1 << 16);
    static const uint32_t DbgCsysclkonAckClkGateSbr      = (0x1 << 12);
    static const uint32_t DbgCsysclkonAckClkGateMcc      = (0x1 << 8);
    static const uint32_t DbgCsysclkonAckClkGateWlmac    = (0x1 << 4);
    static const uint32_t DbgCsysclkonAckClkGateBtmac    = (0x1 << 0);

    // STOP CLOCK register to check if the clocks are stopped
    static const AXmemaddr_t DBG_SOC_HALT_ACTIVE = 0xFD320300;

    // PMGR_AON_FUSE_CFG_FUSE3, AKA Platform Version register (APB-DBG addressing)
    // on M9: SouthBridge.NUB.PMGR_AON.FUSE.ECID_FUSE3
    static const AXmemaddr_t PMGR_AON_FUSE_ECID_FUSE3 = 0xFD2BC20C;

    // PMGR_AON_FUSE_CFG_FUSE10, AKA chip revision register (APB-DBG addressing)
    // on M9: SouthBridge.NUB.PMGR_AON.FUSE.CFG_FUSE10
    static const AXmemaddr_t PMGR_AON_FUSE_CFG_FUSE10 = 0xFD2BC028;

    static const AXmemaddr_t PMGR_SOC_MISC_CFG_ACG = 0xED15C000;

    const std::vector <AXmemaddr_t> DCS_MCU_AMCGEN_AMCCLK_PWRGATE_REGS = {0x200200010};

    std::vector <uint32_t> DCS_MCU_AMCGEN_AMCCLK_PWRGATE_REGS_CACHED = {0};

    uint32_t m_dcs_mcu_pwrgate_cached = K_ACG_NOT_CACHED;

    // Major/minor (i.e. letter/number) shifts
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE10_CHIP_REV_BASE_SHIFT  = 9;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE10_CHIP_REV_METAL_SHIFT = 6;

    // Major/minor (i.e. letter/number) masks
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE10_CHIP_REV_BASE_MASK  = 0x7;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE10_CHIP_REV_METAL_MASK = 0x7;

    // These are PMGR/PMGR_AON registers. The names dont specify which is AON.
    static const AXmemaddr_t PMGR_SIO_CPU_PS  = 0x22d1001e8;
    static const AXmemaddr_t PMGR_SMC_CPU_PS  = 0x23d2801b8;
    static const AXmemaddr_t PMGR_SEP_CPU_PS  = 0x22d100400;
    static const AXmemaddr_t PMGR_AOP_CPU_PS  = 0x23d280020;
    static const AXmemaddr_t PMGR_RTP_CPU_PS  = 0x23d280028;
    static const AXmemaddr_t PMGR_ANS2_CPU_PS = 0x22d100320;
    static const AXmemaddr_t PMGR_GFX_CPU_PS  = 0x22d100348;
    static const AXmemaddr_t PMGR_ANE_CPU_PS  = 0x22d100388;

    // Bits for Astris to tell PMGR_AON to keep Tesla alive for us
    static const uint32_t PMGR_AON_MINI_MAR_PWR_STATE_TRANS_MAR_CFG_DBG_SW_CTL = 0xFD2F5030;
    static const uint32_t DbgSwCtl_dbg_active                                  = (0x1 << 1);
    static const uint32_t DbgSwCtl_dbg_off                                     = (0x1 << 0);

    static const AXmemaddr_t ASCWRAP_KIC_SW_GEN_SET_0 = 0x23e400900;
};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - H8Common
////////////////////////////////////////////////////////////////////////////////

class AppleH8Common_t:
    public AppleSOC_t {

public:

    AppleH8Common_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x2102b8004ULL; /* miniPMGR_SCRATCH1 */}
    virtual bool        has_two_stage_iOS_boot()         {return true;}

protected:

    virtual int  _create_cpus();
    virtual int  _create_acc();
    virtual int  _query_soc_rev();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();
    virtual int  _stop_clock_check();

    virtual bool _config_allows_ave_isp() {return false;}

    virtual int get_platform_vers_reg(AXmemaddr_t &addr)
    {
        addr = MINIPMGR_FUSE_ECID_FUSE3;
        return ASTRIS_ERR_OK;
    }

    // MINIPMGR_ECID_FUSE3, AKA platform version register (APB-DBG addressing)
    static const AXmemaddr_t MINIPMGR_FUSE_ECID_FUSE3 = 0xD02BC08CULL;

    // MINIPMGR_ECID_FUSE4, used for runtime environment detection
    static const AXmemaddr_t MINIPMGR_FUSE_ECID_FUSE4 = 0xD02BC090ULL;

    // MINIPMGR_CFG_FUSE4, where the fuse revision is stored
    static const AXmemaddr_t MINIPMGR_FUSE_CFG_FUSE4                = 0xD02BC010ULL;
    static const uint32_t MiniPmgrFuseRevShift                      = 14;
    static const uint32_t MiniPmgrFuseRevMask                       = (0x3F << MiniPmgrFuseRevShift);
    static const uint32_t MiniPmgrFusePcieRefPllFcalVcoDigCtrlShift = 0;
    static const uint32_t MiniPmgrFusePcieRefPllFcalVcoDigCtrlMask  = (0x1F << MiniPmgrFusePcieRefPllFcalVcoDigCtrlShift);

    static const AXmemaddr_t K_ADDR_BASE_ACC       = 0x202000000;
    static const AXmemaddr_t K_ADDR_OFFSET_ACC_DBG = 0x250000;

    static const int K_ID_ACC = 0;

    static const int K_ID_CPU0 = 0;
    static const int K_ID_CPU1 = 1;

    AppleAcc_t *m_acc = NULL;

private:

    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN_AKF = 0xD0301030;
    static const uint32_t DbgCsyspwrupreqPwrDownAop     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqPwrDownAve     = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqPwrDownIsp     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqPwrDownPmp     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDownSep     = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqPwrDownSio     = (0x1 << 0);

    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE_AKF = 0xD0301034;
    static const uint32_t DbgCsyspwrupreqClkGateAop     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqClkGateAve     = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqClkGateIsp     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqClkGatePmp     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqClkGateSep     = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqClkGateSio     = (0x1 << 0);

    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN_PRT = 0xD0301038;
    static const uint32_t DbgCsyspwrupreqPwrDownAcs     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqPwrDownAp      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqPwrDownAcc     = (0x1 << 0);

    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE_PRT = 0xD030103C;
    static const uint32_t DbgCsyspwrupreqClkGateAcs     = (0x1 << 20);

    // STOP CLOCK register to check if the clocks are stopped
    static const AXmemaddr_t DBG_SOC_HALT_ACTIVE = 0xD0301040;

    static const uint32_t DBG_APB_DBG_TIMEOUT_CNT    = 0xD030104C;
    static const uint32_t DbgApbDbgTimeoutCntDisable = 0x0;

    static const uint32_t DBG_AXI_AP_TIMEOUT_CNT    = 0xD0301050;
    static const uint32_t DbgAxiApTimeoutCntDisable = 0x0;

    static const uint32_t MINIPMGR_PWR_STATE_TRANS_DEBUG = 0xD02CC100;
    static const uint32_t MiniPmgrPwrStateTransDebugMask = 0x1F;
    static const uint32_t MiniPmgrPwrStateS2RAop         = 0;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Maui
////////////////////////////////////////////////////////////////////////////////

class AppleMaui_t:
    public AppleH8Common_t {

public:

    AppleMaui_t(AXchip_t *chip) :
        AppleH8Common_t(chip) {}

    virtual const char *get_name()     {return "Maui";}
    virtual const char *get_gpu_name() {return "g5p";}

private:
    // Put private Maui class members here

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Elba
////////////////////////////////////////////////////////////////////////////////

class AppleElba_t:
    public AppleH8Common_t {

public:

    AppleElba_t(AXchip_t *chip) :
        AppleH8Common_t(chip) {}

    virtual const char *get_name()     {return "Elba";}
    virtual const char *get_gpu_name() {return "g5g";}

    virtual int tckrate_check(uint32_t proposed_tckrate, uint32_t *checked_tckrate);

protected:

    virtual bool _config_allows_ave_isp();

private:
    static const uint32_t SOC_TCKRATE_MAX = 6250000;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Malta
////////////////////////////////////////////////////////////////////////////////

class AppleMalta_t:
    public AppleH8Common_t {

public:

    AppleMalta_t(AXchip_t *chip) :
        AppleH8Common_t(chip) {}

    virtual const char *get_name()     {return "Malta";}
    virtual const char *get_gpu_name() {return "g5p";}

protected:

    virtual bool _config_allows_ave_isp();

private:
    // Put private Malta class members here

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Cayman
////////////////////////////////////////////////////////////////////////////////

class AppleCayman_t:
    public AppleSOC_t {

public:

    AppleCayman_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x2102B8004ULL; /* miniPMGR_SCRATCH1 */}

protected:

    virtual int  _create_cpus();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();

    virtual int _with_cpu_thunk(AXcpu_t * cpu, const char *caller, int (^cpu_thunk)(CPU_t *));

    virtual int _query_soc_rev();
    virtual int _stop_clock_check();

    virtual const char *get_name()     {return "Cayman";}
    virtual const char *get_gpu_name() {return "g9p";}

    virtual int get_platform_vers_reg(AXmemaddr_t &addr)
    {
        addr = MINIPMGR_FUSE_ECID_FUSE3;
        return ASTRIS_ERR_OK;
    }

private:

    virtual int _prevent_awake_exit(bool enable);

    virtual int _create_acc();

    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN_AKF = 0xD0310200;
    static const uint32_t DbgCsyspwrupreqPwrDownGfx     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqPwrDownAop     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqPwrDownAve     = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqPwrDownIsp     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqPwrDownPmp     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDownSep     = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqPwrDownSio     = (0x1 << 0);

    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE_AKF = 0xD0310204;
    static const uint32_t DbgCsyspwrupreqClkGateGfx     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqClkGateAop     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqClkGateAve     = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqClkGateIsp     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqClkGatePmp     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqClkGateSep     = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqClkGateSio     = (0x1 << 0);

    static const uint32_t DBG_CSYSPWRUPREQ_PWR_DOWN_PRT = 0xD0310208;
    static const uint32_t DbgCsyspwrupreqPwrDownPcie    = (0x1 << 28);
    static const uint32_t DbgCsyspwrupreqPwrDownUsb     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqPwrDownAcs     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqPwrDownDisp0   = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqPwrDownMcc     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupreqPwrDownAp      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupreqPwrDownAcc     = (0x1 << 0);

    static const uint32_t DBG_CSYSPWRUPREQ_CLK_GATE_PRT = 0xD031020C;
    static const uint32_t DbgCsyspwrupreqClkGatePcie    = (0x1 << 28);
    static const uint32_t DbgCsyspwrupreqClkGateUsb     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupreqClkGateAcs     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupreqClkGateDisp0   = (0x1 << 16);
    static const uint32_t DbgCsyspwrupreqClkGateMcc     = (0x1 << 12);

    // STOP CLOCK register to check if the clocks are stopped
    static const AXmemaddr_t DBG_SOC_HALT_ACTIVE = 0xD0310300;

    // MINIPMGR_ECID_FUSE3, AKA platform version register (APB-DBG addressing)
    static const AXmemaddr_t MINIPMGR_FUSE_ECID_FUSE3 = 0xD02BC08C;

    // Chip rev is stored in FUSE4 of the MiniPMGR configuration fuse block.
    // The address given below is 0x2102BC010 adjusted to use the addressing mode
    // needed to go across DBG-AP.
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE4 = 0xD02BC010ULL;

    // Major/minor (i.e. letter/number) shifts
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE4_CHIP_REV_BASE_SHIFT  = 25;
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE4_CHIP_REV_METAL_SHIFT = 22;

    // Major/minor (i.e. letter/number) masks
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE4_CHIP_REV_BASE_MASK  = 0x7;
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE4_CHIP_REV_METAL_MASK = 0x7;

    static const AXmemaddr_t AGX_FNDR_KF_RESETN_OVERRIDE = 0xC1D02048;
    static const uint32_t AgxFndrKfResetNOverride        = (0x1 << 0);

    static const AXmemaddr_t K_ADDR_BASE_ACC       = 0x202000000;
    static const AXmemaddr_t K_ADDR_OFFSET_ACC_DBG = 0xf50000;

    static const int K_ID_ACC = 0;

    static const int K_ID_CPU0 = 0;
    static const int K_ID_CPU1 = 1;

    AppleAcc_t *m_acc = NULL;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Myst
////////////////////////////////////////////////////////////////////////////////

class AppleMyst_t:
    public AppleCayman_t {

public:
    AppleMyst_t(AXchip_t *chip) :
        AppleCayman_t(chip) {}

    virtual const char *get_name()     {return "Myst";}
    virtual const char *get_gpu_name() {return "g9g";}

protected:
    virtual int _create_cpus();
    virtual int _query_soc_rev();

    virtual int _with_cpu_thunk(AXcpu_t * cpu, const char *caller, int (^cpu_thunk)(CPU_t *));

private:

    virtual int _create_acc();

    // Chip rev is stored in FUSE2 of the MiniPMGR configuration fuse block.
    // The address given below is 0x2102BC008 adjusted to use the addressing mode
    // needed to go across DBG-AP.
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE2 = 0xD02BC008ULL;

    // Major/minor (i.e. letter/number) shifts
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE2_CHIP_REV_BASE_SHIFT  = 30;
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE2_CHIP_REV_METAL_SHIFT = 28;

    // Major/minor (i.e. letter/number) masks, these are 2 bits wide now
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE2_CHIP_REV_BASE_MASK  = 0x3;
    static const uint32_t MINIPMGR_FUSE_CFG_FUSE2_CHIP_REV_METAL_MASK = 0x3;

    static const AXmemaddr_t K_ADDR_BASE_ACC       = 0x202000000;
    static const AXmemaddr_t K_ADDR_OFFSET_ACC_DBG = 0xf50000;

    static const int K_ID_ACC = 0;

    static const int K_ID_CPU0 = 0;
    static const int K_ID_CPU1 = 1;
    static const int K_ID_CPU2 = 2;

    AppleAcc_t *m_acc = NULL;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Skye
////////////////////////////////////////////////////////////////////////////////

class AppleSkye_t:
    public AppleSOC_t {

public:

    AppleSkye_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual const char *get_name()     {return "Skye";}
    virtual const char *get_gpu_name() {return "g10p";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x2352B8004ULL; /* SouthBridge.NUB.PMGR_AON.MINI_SCRATCH.SCRATCH1 */}

    virtual int get_nmi_reg(AXmemaddr_t &nmi_reg)
    {
        nmi_reg = AKF_KIC_SW_GEN_SET_0;
        return ASTRIS_ERR_OK;
    }

protected:

    virtual int  _create_cpus();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();
    virtual int  _stop_clock_check();
    virtual int  _query_soc_rev();

    virtual int get_platform_vers_reg(AXmemaddr_t &addr)
    {
        addr = PMGR_AON_FUSE_ECID_FUSE3;
        return ASTRIS_ERR_OK;
    }

    virtual int get_acg_reg(AXmemaddr_t &addr)
    {
        addr = PMGR_SOC_MISC_CFG_ACG;
        return ASTRIS_ERR_OK;
    }

    virtual int get_dcs_register_addrs(const std::vector <AXmemaddr_t> * &regs)
    {
        regs = &DCS_MCU_AMCGEN_AMCCLK_PWRGATE_REGS;
        return ASTRIS_ERR_OK;
    }

    virtual int get_dcs_register_cached(std::vector <uint32_t> * &cached)
    {
        cached = &DCS_MCU_AMCGEN_AMCCLK_PWRGATE_REGS_CACHED;
        return ASTRIS_ERR_OK;
    }

    /*!
     @function _with_cpu_thunk
     @discussion Intercepts accesses to ACC cores and prevents them from
        happening if the ACC is in an unsafe state.
     @param cpu target CPU
     @param caller caller ID string
     @param cpu_thunk operation to execute
     @result astris error code
     */
    virtual int _with_cpu_thunk(AXcpu_t * cpu, const char *caller, int (^cpu_thunk)(CPU_t *));

    /*!
     @function _with_preflight_for_bus_transaction
     @discussion Intercepts accesses to ACC address space and prevents them
        from happening if the ACC is in an unsafe state.
     @param ap AP to use for the access
     @param addr base address of the access
     @param access_size access size to use
     @param num_words number of words to read
     @param do_access operation to execute
     @result astris error code
     */
    virtual int _with_preflight_for_bus_transaction(AXap_t * ap, AXmemaddr_t addr, int access_size, uint32_t num_words, int (^do_access)(void));

private:

    /*!
     @function _create_acc
     @discussion Create the ACC CPUs for the SoC. If specified, only create
     placeholder objects instead of full CPU objects.
     @param with_placeholders Create placeholder objects instead
     @result astris error code
     */
    virtual int _create_acc(bool with_placeholders);

    /*!
     @function _is_acc_core
     @discussion Determine if the given CPU is in the ACC complex.
     @param cpu the CPU to check
     @result boolean
     */
    bool _is_acc_core(AXcpu_t *cpu);

    /*!
     @function _is_acc_safe_to_access
     @discussion Determine if the SoCs state is safe for ACC access.
     @result boolean
     */
    bool _is_acc_safe_to_access();

    /*!
     @function _is_safe_to_access
     @discussion Determine if it's safe to make the access to the given region
        of memory.
     @param ap AP to use for the access
     @param addr base address of the region to access
     @param access_size size of the access to perform
     @param num_words number of words to read
     @result boolean
     */
    bool _is_safe_to_access(AXap_t *ap, AXmemaddr_t addr, int access_size, uint32_t num_words);

    /*!
     @function _warn_user_about_acc
     @discussion Warn user that the ACC is currently unavailable for access.
     */
    void _warn_user_about_acc();

    // power gating defeatures for various blocks in the system
    // (in the SouthBridge.NUB.dbgWrap.DBGWRAP_REGS.Debug_Power_and_Clock_Control block)
    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_1 = 0xF5320200;
    static const uint32_t DbgCsyspwrupReqPwrDown1Smc     = (0x1 << 28);
    static const uint32_t DbgCsyspwrupReqPwrDown1Gfx     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupReqPwrDown1Aop     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupReqPwrDown1Ave     = (0x1 << 16);
    static const uint32_t DbgCsyspwrupReqPwrDown1Isp     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupReqPwrDown1Pmp     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDown1Sep     = (0x1 << 4);
    static const uint32_t DbgCsyspwrupReqPwrDown1Sio     = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_2 = 0xF5320204;
    static const uint32_t DbgCsyspwrupReqPwrDown2Pcie    = (0x1 << 28);
    static const uint32_t DbgCsyspwrupReqPwrDown2Usb     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupReqPwrDown2Acs     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupReqPwrDown2Disp0   = (0x1 << 16);
    static const uint32_t DbgCsyspwrupReqPwrDown2Mcc     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupReqPwrDown2Avd     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupReqPwrDown2Ap      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupReqPwrDown2Acc     = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_3 = 0xF5320208;
    static const uint32_t DbgCsyspwrupReqPwrDown3Ans2    = (0x1 << 0);

    // ACK bits for power down of subsystems containing debug components
    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_1 = 0xF532020C;
    static const uint32_t DbgCsyspwrupAckPwrDown1Smc     = (0x1 << 28);
    static const uint32_t DbgCsyspwrupAckPwrDown1Gfx     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupAckPwrDown1Aop     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupAckPwrDown1Ave     = (0x1 << 16);
    static const uint32_t DbgCsyspwrupAckPwrDown1Isp     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupAckPwrDown1Pmp     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupAckPwrDown1Sep     = (0x1 << 4);
    static const uint32_t DbgCsyspwrupAckPwrDown1Sio     = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_2 = 0xF5320210;
    static const uint32_t DbgCsyspwrupAckPwrDown2Pcie    = (0x1 << 28);
    static const uint32_t DbgCsyspwrupAckPwrDown2Usb     = (0x1 << 24);
    static const uint32_t DbgCsyspwrupAckPwrDown2Acs     = (0x1 << 20);
    static const uint32_t DbgCsyspwrupAckPwrDown2Disp0   = (0x1 << 16);
    static const uint32_t DbgCsyspwrupAckPwrDown2Mcc     = (0x1 << 12);
    static const uint32_t DbgCsyspwrupAckPwrDown2Avd     = (0x1 << 8);
    static const uint32_t DbgCsyspwrupAckPwrDown2Ap      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupAckPwrDown2Acc     = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_3 = 0xF5320214;
    static const uint32_t DbgCsyspwrupAckPwrDown3Ans2    = (0x1 << 0);

    // clock gating defeatures for various subsystems
    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_1 = 0xF5320218;
    static const uint32_t DbgCsysclkonReqClkGate1Smc     = (0x1 << 28);
    static const uint32_t DbgCsysclkonReqClkGate1Gfx     = (0x1 << 24);
    static const uint32_t DbgCsysclkonReqClkGate1Aop     = (0x1 << 20);
    static const uint32_t DbgCsysclkonReqClkGate1Ave     = (0x1 << 16);
    static const uint32_t DbgCsysclkonReqClkGate1Isp     = (0x1 << 12);
    static const uint32_t DbgCsysclkonReqClkGate1Pmp     = (0x1 << 8);
    static const uint32_t DbgCsysclkonreqClkGate1Sep     = (0x1 << 4);
    static const uint32_t DbgCsysclkonReqClkGate1Sio     = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_2 = 0xF532021C;
    static const uint32_t DbgCsysclkonReqClkGate2Pcie    = (0x1 << 28);
    static const uint32_t DbgCsysclkonReqClkGate2Usb     = (0x1 << 24);
    static const uint32_t DbgCsysclkonReqClkGate2Acs     = (0x1 << 20);
    static const uint32_t DbgCsysclkonReqClkGate2Disp0   = (0x1 << 16);
    static const uint32_t DbgCsysclkonReqClkGate2Mcc     = (0x1 << 12);
    static const uint32_t DbgCsysclkonReqClkGate2Avd     = (0x1 << 8);

    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_3 = 0xF5320220;
    static const uint32_t DbgCsysclkonReqClkGate3Sbr     = (0x1 << 4);
    static const uint32_t DbgCsysclkonReqClkGate3Ans2    = (0x1 << 0);

    // ACK bits for clock gating of subsystems containing debug components
    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_1 = 0xF5320224;
    static const uint32_t DbgCsysclkonAckClkGate1Smc     = (0x1 << 28);
    static const uint32_t DbgCsysclkonAckClkGate1Gfx     = (0x1 << 24);
    static const uint32_t DbgCsysclkonAckClkGate1Aop     = (0x1 << 20);
    static const uint32_t DbgCsysclkonAckClkGate1Ave     = (0x1 << 16);
    static const uint32_t DbgCsysclkonAckClkGate1Isp     = (0x1 << 12);
    static const uint32_t DbgCsysclkonAckClkGate1Pmp     = (0x1 << 8);
    static const uint32_t DbgCsysclkonAckClkGate1Sep     = (0x1 << 4);
    static const uint32_t DbgCsysclkonAckClkGate1Sio     = (0x1 << 0);

    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_2 = 0xF5320228;
    static const uint32_t DbgCsysclkonAckClkGate2Pcie    = (0x1 << 28);
    static const uint32_t DbgCsysclkonAckClkGate2Usb     = (0x1 << 24);
    static const uint32_t DbgCsysclkonAckClkGate2Acs     = (0x1 << 20);
    static const uint32_t DbgCsysclkonAckClkGate2Disp0   = (0x1 << 16);
    static const uint32_t DbgCsysclkonAckClkGate2Mcc     = (0x1 << 12);
    static const uint32_t DbgCsysclkonAckClkGate2Avd     = (0x1 << 8);

    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_3 = 0xF532022C;
    static const uint32_t DbgCsysclkonAckClkGate3Sbr     = (0x1 << 4);
    static const uint32_t DbgCsysclkonAckClkGate3Ans2    = (0x1 << 0);

    // STOP CLOCK register to check if the clocks are stopped
    static const AXmemaddr_t DBG_SOC_HALT_ACTIVE = 0xF5320300;

    // PMGR_AON_FUSE_CFG_FUSE3, AKA Platform Version register (APB-DBG addressing)
    // on Skye: SouthBridge.NUB.PMGR_AON.FUSE.ECID_FUSE3
    static const AXmemaddr_t PMGR_AON_FUSE_ECID_FUSE3 = 0xF52BC08C;

    // PMGR_AON_FUSE_CFG_FUSE6, AKA chip revision register (APB-DBG addressing)
    // on Skye: SouthBridge.NUB.PMGR_AON.FUSE.CFG_FUSE6
    static const AXmemaddr_t PMGR_AON_FUSE_CFG_FUSE6 = 0xF52BC018;

    // Major/minor (i.e. letter/number) shifts
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE6_CHIP_REV_BASE_SHIFT  = 11;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE6_CHIP_REV_METAL_SHIFT = 8;

    // Major/minor (i.e. letter/number) masks
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE6_CHIP_REV_BASE_MASK  = 0x7;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE6_CHIP_REV_METAL_MASK = 0x7;

    // State of the power state FSM. Used for WA for <rdar://problem/30242286>
    static const AXmemaddr_t R_PMGR_AON_MINI_PWR_STATE_TRANS_DEBUG0 = 0x2352C0100ULL;

    static const uint32_t S_PMGR_AON_MINI_PWR_STATE_TRANS_DEBUG0              = 0;
    static const uint32_t M_PMGR_AON_MINI_PWR_STATE_TRANS_DEBUG0__debug_state = 0x3F << S_PMGR_AON_MINI_PWR_STATE_TRANS_DEBUG0;

    static const uint32_t V_PMGR_AON_MINI_PWR_STATE_TRANS_DEBUG0__debug_state_awake = 0x13; // 19 in decimal (see SPDS for enumerations)

    static const AXmemaddr_t PMGR_SOC_MISC_CFG_ACG = 0xF20DC000;

    const std::vector <AXmemaddr_t> DCS_MCU_AMCGEN_AMCCLK_PWRGATE_REGS = {0x200200010, 0x200240010, 0x200280010, 0x2002C0010};
    std::vector <uint32_t> DCS_MCU_AMCGEN_AMCCLK_PWRGATE_REGS_CACHED   = {0, 0, 0, 0};

    /*!
     @const R_ACC_CPM1_DBG_WRAP_GLB
     @discussion R_ACC_CPM1_DBG_WRAP_GLB system address
     */
    static const AXmemaddr_t R_ACC_CPM1_DBG_WRAP_GLB = 0x208ED00B0;
    /*!
     @const M_ACC_CPM1_DBG_WRAP_GLB__dbgHalt
     @discussion Shift value for the dbgHalt bitfield of R_ACC_CPM1_DBG_WRAP_GLB
     */
    static const uint32_t S_ACC_CPM1_DBG_WRAP_GLB__dbgHalt = 0;
    /*!
     @const M_ACC_CPM1_DBG_WRAP_GLB__dbgHalt
     @discussion Mask value for the dbgHalt bitfield of R_ACC_CPM1_DBG_WRAP_GLB
     */
    static const uint32_t M_ACC_CPM1_DBG_WRAP_GLB__dbgHalt = 0xFF << S_ACC_CPM1_DBG_WRAP_GLB__dbgHalt;
    /*!
     @const S_ACC_CPM1_DBG_WRAP_GLB__dbgRestart
     @discussion Shift value for the dbgRestart bitfield of R_ACC_CPM1_DBG_WRAP_GLB
     */
    static const uint32_t S_ACC_CPM1_DBG_WRAP_GLB__dbgRestart = 8;
    /*!
     @const M_ACC_CPM1_DBG_WRAP_GLB__dbgRestart
     @discussion Mask value for the dbgRestart bitfield of R_ACC_CPM1_DBG_WRAP_GLB
     */
    static const uint32_t M_ACC_CPM1_DBG_WRAP_GLB__dbgRestart = 0xFF << S_ACC_CPM1_DBG_WRAP_GLB__dbgRestart;

    static const AXmemaddr_t K_ADDR_BASE_ACC            = 0x208000000;
    static const AXmemaddr_t K_ADDR_OFFSET_ACC_CPM1_DBG = 0xed0000;

    // IDs for each of the ACC cores. The order is a bit strange because of
    // of the fact that the hardware considers pCore0 core 0, while we refer to
    // eCore0 as core 0.
    static const int K_ID_ECORE0 = 4;
    static const int K_ID_ECORE1 = 5;
    static const int K_ID_ECORE2 = 6;
    static const int K_ID_ECORE3 = 7;

    static const int K_ID_PCORE0 = 0;
    static const int K_ID_PCORE1 = 1;

    // ID to give to the ACC object
    static const int K_ID_ACC = 0;

    static const AXmemaddr_t AKF_KIC_SW_GEN_SET_0 = 0x236800900;

    // Pointer to the ACC object for the SoC
    AppleAcc_t *m_acc = NULL;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Gibraltar
////////////////////////////////////////////////////////////////////////////////

class AppleGibraltar_t:
    public AppleSOC_t {

public:

    AppleGibraltar_t(AXchip_t *chip) :
        AppleSOC_t(chip, K_APIDR_TYPE_AXI) {}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
    virtual int  xnu_coredump_info(AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64, bool *sys_snoop_cpu);

    virtual AXmemaddr_t consistent_debug_root_register() {return 0x2112b8004ULL; /* SouthBridge.NUB.PMGR_AON.MINI_SCRATCH.SCRATCH1 */}

protected:

    virtual int  _create_cpus();
    virtual int  _preinit_hw();
    virtual int  _postinit_hw();
    virtual bool _cleanup_hw();
    virtual int  _stop_clock_check();
    virtual int  _query_soc_rev();

    virtual const char *get_name() {return "Gibraltar";}

    virtual int get_platform_vers_reg(AXmemaddr_t &addr)
    {
        addr = PMGR_AON_FUSE_ECID_FUSE3;
        return ASTRIS_ERR_OK;
    }

    virtual int get_nmi_reg(AXmemaddr_t &nmi_reg)
    {
        nmi_reg = AKF_KIC_SW_GEN_SET_0;
        return ASTRIS_ERR_OK;
    }

private:

    virtual int _create_acc();

    // power-gating defeatures for various blocks in the system
    // (in the SouthBridge.NUB.dbgWrap.dbgwrap_regs.Debug_Power_and_Clock_Control block)
    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_1 = 0xD1320200;
    static const uint32_t DbgCsyspwrupReqPwrDownSmc      = (0x1 << 28);
    static const uint32_t DbgCsyspwrupReqPwrDownAop      = (0x1 << 20);
    static const uint32_t DbgCsyspwrupReqPwrDownAve      = (0x1 << 16);
    static const uint32_t DbgCsyspwrupReqPwrDownIsp      = (0x1 << 12);
    static const uint32_t DbgCsyspwrupReqPwrDownPmp      = (0x1 << 8);
    static const uint32_t DbgCsyspwrupreqPwrDownSep      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupReqPwrDownSio      = (0x1 << 0);
    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_2 = 0xD1320204;
    static const uint32_t DbgCsyspwrupReqPwrDownUsb      = (0x1 << 24);
    static const uint32_t DbgCsyspwrupReqPwrDownAcs      = (0x1 << 20);
    static const uint32_t DbgCsyspwrupReqPwrDownDisp0    = (0x1 << 16);
    static const uint32_t DbgCsyspwrupReqPwrDownMcc      = (0x1 << 12);
    static const uint32_t DbgCsyspwrupReqPwrDownAp       = (0x1 << 4);
    static const uint32_t DbgCsyspwrupReqPwrDownAcc      = (0x1 << 0);
    static const AXmemaddr_t DBG_CSYSPWRUPREQ_PWR_DOWN_3 = 0xD1320208;
    static const uint32_t DbgCsyspwrupReqPwrDownPcieStg1 = (0x1 << 20);
    static const uint32_t DbgCsyspwrupReqPwrDownPcieStg0 = (0x1 << 16);
    static const uint32_t DbgCsyspwrupReqPwrDownPcieDn   = (0x1 << 12);
    static const uint32_t DbgCsyspwrupReqPwrDownPcieUp   = (0x1 << 8);
    static const uint32_t DbgCsyspwrupReqPwrDownAns2     = (0x1 << 0);

    // ACK bits for power down of subsystems containing debug components
    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_1 = 0xD132020C;
    static const uint32_t DbgCsyspwrupAckPwrDownSmc      = (0x1 << 28);
    static const uint32_t DbgCsyspwrupAckPwrDownAop      = (0x1 << 20);
    static const uint32_t DbgCsyspwrupAckPwrDownAve      = (0x1 << 16);
    static const uint32_t DbgCsyspwrupAckPwrDownIsp      = (0x1 << 12);
    static const uint32_t DbgCsyspwrupAckPwrDownPmp      = (0x1 << 8);
    static const uint32_t DbgCsyspwrupAckPwrDownSep      = (0x1 << 4);
    static const uint32_t DbgCsyspwrupAckPwrDownSio      = (0x1 << 0);
    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_2 = 0xD1320210;
    static const uint32_t DbgCsyspwrupAckPwrDownUsb      = (0x1 << 24);
    static const uint32_t DbgCsyspwrupAckPwrDownAcs      = (0x1 << 20);
    static const uint32_t DbgCsyspwrupAckPwrDownDisp0    = (0x1 << 16);
    static const uint32_t DbgCsyspwrupAckPwrDownMcc      = (0x1 << 12);
    static const uint32_t DbgCsyspwrupAckPwrDownAp       = (0x1 << 4);
    static const uint32_t DbgCsyspwrupAckPwrDownAcc      = (0x1 << 0);
    static const AXmemaddr_t DBG_CSYSPWRUPACK_PWR_DOWN_3 = 0xD1320214;
    static const uint32_t DbgCsyspwrupAckPwrDownPcieStg1 = (0x1 << 20);
    static const uint32_t DbgCsyspwrupAckPwrDownPcieStg0 = (0x1 << 16);
    static const uint32_t DbgCsyspwrupAckPwrDownPcieDn   = (0x1 << 12);
    static const uint32_t DbgCsyspwrupAckPwrDownPcieUp   = (0x1 << 8);
    static const uint32_t DbgCsyspwrupAckPwrDownAns2     = (0x1 << 0);

    // clock-gating defeatures for various subsystems
    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_1 = 0xD1320218;
    static const uint32_t DbgCsysclkonReqClkGateSmc      = (0x1 << 28);
    static const uint32_t DbgCsysclkonReqClkGateAop      = (0x1 << 20);
    static const uint32_t DbgCsysclkonReqClkGateAve      = (0x1 << 16);
    static const uint32_t DbgCsysclkonReqClkGateIsp      = (0x1 << 12);
    static const uint32_t DbgCsysclkonReqClkGatePmp      = (0x1 << 8);
    static const uint32_t DbgCsysclkonreqClkGateSep      = (0x1 << 4);
    static const uint32_t DbgCsysclkonReqClkGateSio      = (0x1 << 0);
    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_2 = 0xD132021C;
    static const uint32_t DbgCsysclkonReqClkGateUsb      = (0x1 << 24);
    static const uint32_t DbgCsysclkonReqClkGateAcs      = (0x1 << 20);
    static const uint32_t DbgCsysclkonReqClkGateDisp0    = (0x1 << 16);
    static const uint32_t DbgCsysclkonReqClkGateMcc      = (0x1 << 12);
    static const AXmemaddr_t DBG_CSYSCLKONREQ_CLK_GATE_3 = 0xD1320220;
    static const uint32_t DbgCsysclkonReqClkGatePcieStg1 = (0x1 << 20);
    static const uint32_t DbgCsysclkonReqClkGatePcieStg0 = (0x1 << 16);
    static const uint32_t DbgCsysclkonReqClkGatePcieDn   = (0x1 << 12);
    static const uint32_t DbgCsysclkonReqClkGatePcieUp   = (0x1 << 8);
    static const uint32_t DbgCsysclkonReqClkGateAns2     = (0x1 << 0);

    // ACK bits for clock gating of subsystems containing debug components
    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_1 = 0xD1320224;
    static const uint32_t DbgCsysclkonAckClkGateSmc      = (0x1 << 28);
    static const uint32_t DbgCsysclkonAckClkGateAop      = (0x1 << 20);
    static const uint32_t DbgCsysclkonAckClkGateAve      = (0x1 << 16);
    static const uint32_t DbgCsysclkonAckClkGateIsp      = (0x1 << 12);
    static const uint32_t DbgCsysclkonAckClkGatePmp      = (0x1 << 8);
    static const uint32_t DbgCsysclkonAckClkGateSep      = (0x1 << 4);
    static const uint32_t DbgCsysclkonAckClkGateSio      = (0x1 << 0);
    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_2 = 0xD1320228;
    static const uint32_t DbgCsysclkonAckClkGateUsb      = (0x1 << 24);
    static const uint32_t DbgCsysclkonAckClkGateAcs      = (0x1 << 20);
    static const uint32_t DbgCsysclkonAckClkGateDisp0    = (0x1 << 16);
    static const uint32_t DbgCsysclkonAckClkGateMcc      = (0x1 << 12);
    static const AXmemaddr_t DBG_CSYSCLKONACK_CLK_GATE_3 = 0xD132022C;
    static const uint32_t DbgCsysclkonAckClkGatePcieStg1 = (0x1 << 20);
    static const uint32_t DbgCsysclkonAckClkGatePcieStg0 = (0x1 << 16);
    static const uint32_t DbgCsysclkonAckClkGatePcieDn   = (0x1 << 12);
    static const uint32_t DbgCsysclkonAckClkGatePcieUp   = (0x1 << 8);
    static const uint32_t DbgCsysclkonAckClkGateAns2     = (0x1 << 0);

    // STOP CLOCK register to check if the clocks are stopped
    static const AXmemaddr_t DBG_SOC_HALT_ACTIVE = 0xD1320300;

    // Gibraltar has a nifty new way of getting chip-rev via JTAG without going
    // over the Apple Fabric. We ought to consider using it.

    // PMGR_AON_FUSE_CFG_FUSE3, AKA Platform Version register (APB-DBG addressing)
    // on Gibraltar: SouthBridge.NUB.PMGR_AON.FUSE.ECID_FUSE3
    static const AXmemaddr_t PMGR_AON_FUSE_ECID_FUSE3 = 0xD12BC08CULL;

    // PMGR_AON_FUSE_CFG_FUSE6, AKA chip revision register (APB-DBG addressing)
    // on Gibraltar: SouthBridge.NUB.PMGR_AON.FUSE.CFG_FUSE4
    static const AXmemaddr_t PMGR_AON_FUSE_CFG_FUSE4 = 0xD12BC010ULL;

    // Major/minor (i.e. letter/number) shifts
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE4_CHIP_REV_BASE_SHIFT  = 25;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE4_CHIP_REV_METAL_SHIFT = 22;

    // Major/minor (i.e. letter/number) masks
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE4_CHIP_REV_BASE_MASK  = 0x7;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE4_CHIP_REV_METAL_MASK = 0x7;

    static const AXmemaddr_t K_ADDR_BASE_ACC       = 0x202000000;
    static const AXmemaddr_t K_ADDR_OFFSET_ACC_DBG = 0xf50000;

    // IDs for each of the ACC cores. The order is a bit strange because of
    // of the fact that the hardware considers pCore0 core 0, while we refer to
    // eCore0 as core 0.
    static const int K_ID_CPU0 = 0;
    static const int K_ID_CPU1 = 1;

    // ID to give to the ACC object
    static const int K_ID_ACC = 0;

    static const AXmemaddr_t AKF_KIC_SW_GEN_SET_0 = 0x212800900;

    // Pointer to the ACC object for the SoC
    AppleAcc_t *m_acc = NULL;

};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Tesla
////////////////////////////////////////////////////////////////////////////////
class AppleTesla_t:
    public AppleSOC_t {

public:
    AppleTesla_t(AXchip_t *chip) :
        AppleSOC_t(chip, -1) {}

    virtual const char *get_name() {return "Tesla";}
    virtual bool        is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);

protected:
    virtual int _create_cpus();
    virtual int _preinit_hw();
    virtual int _query_soc_rev();

    // virtual int get_platform_vers_reg(AXmemaddr_t &addr) {return ASTRIS_ERR_NOTSUPPORTED; }

    // PMGR_AON_FUSE_CFG_FUSE10, AKA chip revision register (APB-DBG addressing)
    // on Tesla: tesla_periph_bridge.PMGR_AON.FUSE.CFG_FUSE9[29:27] = Major
    // and bits [31:30] are Minor[1:0]
    static const AXmemaddr_t PMGR_AON_FUSE_CFG_FUSE9  = 0x5000C024;
    static const AXmemaddr_t PMGR_AON_FUSE_CFG_FUSE10 = 0x5000C028;

    // Major/minor (i.e. letter/number) shifts
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE9_CHIP_REV_BASE_SHIFT   = 27;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE9_CHIP_REV_METAL_SHIFT  = 30;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE10_CHIP_REV_METAL_SHIFT = 0;

    // Major/minor (i.e. letter/number) masks
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE9_CHIP_REV_BASE_MASK   = 0x7;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE9_CHIP_REV_METAL_MASK  = 0x3;
    static const uint32_t PMGR_AON_FUSE_CFG_FUSE10_CHIP_REV_METAL_MASK = 0x3;
};

////////////////////////////////////////////////////////////////////////////////
#pragma mark - Samsung G1
////////////////////////////////////////////////////////////////////////////////

class SamsungG1_t:
    public SOC_t {
public:
    SamsungG1_t(AXchip_t *chip) :
        SOC_t(chip, K_APIDR_TYPE_AHB) {}

    virtual const char *get_name() {return "G1";}

    virtual bool is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);

protected:
    virtual int _create_cpus();

private:
};

////////////////////////////////////////////////////////////////////////////////
#pragma mark Intel Xgold766
////////////////////////////////////////////////////////////////////////////////

class IntelXgold766_t:
    public SOC_t {
public:
    IntelXgold766_t(AXchip_t *chip) :
        SOC_t(chip, K_APIDR_TYPE_APB) {}

    virtual const char *get_name() {return "IntelXgold766";}
    virtual bool        is_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);

protected:
    virtual int _create_cpus();

};

#endif // ifndef _ASTRIS_APPLESOC_H
