/*
 * Copyright (C) 2013-2015 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 __PLATFORM_SOC_PMGR_H
#define __PLATFORM_SOC_PMGR_H

#include <lib/devicetree.h>
#include <platform.h>
#include <platform/soc/hwregbase.h>
#include SUB_PLATFORM_SPDS_HEADER(minipmgr)
#include SUB_PLATFORM_SPDS_HEADER(pmgr)

enum {
    PMGR_CLK_OSC = 0,
    PMGR_CLK_PLL0,
    PMGR_CLK_PLL1,
    PMGR_CLK_GPIO,    
    PMGR_CLK_SOURCE_FIRST = PMGR_CLK_GPIO,
    PMGR_CLK_CPU,
    PMGR_CLK_MCU_REF,        
    PMGR_CLK_GFX,
    PMGR_CLK_MEDIA_FAB,
    PMGR_CLK_PIO,
    PMGR_CLK_SDIO,
    PMGR_CLK_LIO,           // 0xa
    PMGR_CLK_AES,
    PMGR_CLK_AUE,
    PMGR_CLK_SPI0_N,
    PMGR_CLK_SPI1_N,
    PMGR_CLK_NCO_REF0,
    PMGR_CLK_NCO_REF1,      // 0x10
    PMGR_CLK_NCO_ALG0,
    PMGR_CLK_NCO_ALG1,
    PMGR_CLK_MCA0_M,
    PMGR_CLK_MCA1_M,
    PMGR_CLK_MCA2_M,
    PMGR_CLK_TMPS,
    PMGR_CLK_UVD,
    PMGR_CLK_ISP_C,
    PMGR_CLK_ISP,
    PMGR_CLK_RT_FAB,        // 0x1a
    PMGR_CLK_ISP_SENSOR0,   
    PMGR_CLK_VENC,
    PMGR_CLK_SEP,
    PMGR_CLK_SEP_FAB,
    PMGR_CLK_ANS,
    PMGR_CLK_ANC_LINK,      // 0x20
    PMGR_CLK_VDEC,          
    PMGR_CLK_MSR,
    PMGR_CLK_AJPEG_IP,
    PMGR_CLK_AJPEG_WRAP,
    PMGR_CLK_DISP,
    PMGR_CLK_MIPI_DSI,
    PMGR_CLK_VID,
    PMGR_CLK_HFD,
    PMGR_CLK_HSICPHY_REF_12M,
    PMGR_CLK_USB480_0,      // 0x2a
    PMGR_CLK_USB_EHCI,
    PMGR_CLK_SOURCE_LAST = PMGR_CLK_USB_EHCI, 
    PMGR_CLK_S0,
    PMGR_CLK_SPARE_FIRST = PMGR_CLK_S0,
    PMGR_CLK_S1,            
    PMGR_CLK_ISP_REF0,      
    PMGR_CLK_SPARE_LAST = PMGR_CLK_ISP_REF0,
    PMGR_CLK_LPPLL,
    PMGR_CLK_AOP,           // 0x30
    PMGR_CLK_MINI_FIRST = PMGR_CLK_AOP,
    PMGR_CLK_UART0,        
    PMGR_CLK_UART1,
    PMGR_CLK_UART2,        
    PMGR_CLK_SENSE_X2,     
    PMGR_CLK_DETECT,         
    PMGR_CLK_I2CM,  
    PMGR_CLK_I2CM1,         
    PMGR_CLK_PROXY_FABRIC, 
    PMGR_CLK_PROXY_MCU_REF, // 0x3a
    PMGR_CLK_MINI_LAST = PMGR_CLK_PROXY_MCU_REF,
    PMGR_CLK_COUNT,
    PMGR_CLK_NOT_SUPPORTED,
};

// PLL
static const int PMGR_PLL_COUNT         = 2;
#define PMGR_PLL_REG_STRIDE             (PMGR_PLL1_OFFSET - PMGR_PLL0_OFFSET)
#define rPMGR_PLL_CTL(_p)               (*(volatile uint32_t *)(PMGR_BASE_ADDR + ((_p) * PMGR_PLL_REG_STRIDE)))
#define rPMGR_PLL_CFG(_p)               (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_PLL0_CFG_OFFSET + ((_p) * PMGR_PLL_REG_STRIDE)))

#define PMGR_PLL_CTL_PRE_DIVN_INSRT(_f)         PMGR_PLL0_CTL_PRE_DIVN_INSRT(_f)
#define PMGR_PLL_CTL_FB_DIVN_INSRT(_f)          PMGR_PLL0_CTL_FB_DIVN_INSRT(_f)
#define PMGR_PLL_CTL_OP_DIVN_INSRT(_f)          PMGR_PLL0_CTL_OP_DIVN_INSRT(_f)
#define PMGR_PLL_CTL_ENABLE_INSRT(_f)           PMGR_PLL0_CTL_ENABLE_INSRT(_f)
#define PMGR_PLL_CTL_LOAD_INSRT(_f)             PMGR_PLL0_CTL_LOAD_INSRT(_f)
#define PMGR_PLL_CTL_BYPASS_INSRT(_f)           PMGR_PLL0_CTL_BYPASS_INSRT(_f)
#define PMGR_PLL_CFG_VCO_OUT_SEL_INSRT(_f)      PMGR_PLL0_CFG_VCO_OUT_SEL_INSRT(_f)
#define PMGR_PLL_CFG_OFF_MODE_INSRT(_f)         PMGR_PLL0_CFG_OFF_MODE_INSRT(_f)
#define PMGR_PLL_CFG_FRAC_LOCK_TIME_INSRT(_f)   PMGR_PLL0_CFG_FRAC_LOCK_TIME_INSRT(_f)
#define PMGR_PLL_CFG_LOCK_TIME_INSRT(_f)        PMGR_PLL0_CFG_LOCK_TIME_INSRT(_f)

#define PMGR_PLL_CTL_PENDING_XTRCT(_f)      PMGR_PLL0_CTL_PLL_PENDING_XTRCT(_f)
#define PMGR_PLL_CTL_ENABLE_XTRCT(_f)       PMGR_PLL0_CTL_ENABLE_XTRCT(_f)
#define PMGR_PLL_CTL_BYPASS_XTRCT(_f)       PMGR_PLL0_CTL_BYPASS_XTRCT(_f)
#define PMGR_PLL_CTL_PRE_DIVN_XTRCT(_f)     PMGR_PLL0_CTL_PRE_DIVN_XTRCT(_f)
#define PMGR_PLL_CTL_FB_DIVN_XTRCT(_f)      PMGR_PLL0_CTL_FB_DIVN_XTRCT(_f)
#define PMGR_PLL_CTL_OP_DIVN_XTRCT(_f)      PMGR_PLL0_CTL_OP_DIVN_XTRCT(_f)
#define PMGR_PLL_CFG_VCO_OUT_SEL_XTRCT(_f)  PMGR_PLL0_CFG_VCO_OUT_SEL_XTRCT(_f)

enum pmgr_pll_off_mode {
    PMGR_PLL_OFF_MODE_RESET         = 0,
    PMGR_PLL_OFF_MODE_CLOCK_GATED,
    PMGR_PLL_OFF_MODE_POWER_DOWN
};

enum pmgr_pll_lock_mode {
    PMGR_PLL_LOCK_MODE_COUNTER      = 0,
    PMGR_PLL_LOCK_MODE_LOCK
};

enum pmgr_pll_relock_mode {
    PMGR_PLL_RELOCK_MODE_STOP       = 0,
    PMGR_PLL_RELOCK_MODE_BYPASS
};

// PS
#define rPMGR_PS(_x)               (*(volatile uint32_t *)(PMGR_BASE_ADDR + PMGR_PS_##_x##_PS_OFFSET))

#define PMGR_PS_MANUAL_PS_XTRCT(_f)     PMGR_PS_DISP_PS_MANUAL_PS_XTRCT(_f)
#define PMGR_PS_ACTUAL_PS_XTRCT(_f)     PMGR_PS_DISP_PS_ACTUAL_PS_XTRCT(_f)
#define PMGR_PS_MANUAL_PS_INSRT(_f)     PMGR_PS_DISP_PS_MANUAL_PS_INSRT(_f)
#define PMGR_PS_RESET_INSRT(_f)         PMGR_PS_DISP_PS_RESET_INSRT(_f)

enum pmgr_ps_state {
    PMGR_PS_RUN_MAX   =   0xF,
    PMGR_PS_CLOCK_OFF =   0x4,
    PMGR_PS_POWER_OFF =   0x0
};

#define rPMGR_CLK_CFG(_x)           (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_CLKCFG_##_x##_CLK_CFG_OFFSET))
#define PMGR_FIRST_CLK_CFG          (&rPMGR_CLK_CFG(GPIO))
#define PMGR_LAST_CLK_CFG           (&rPMGR_CLK_CFG(USB_EHCI))
#define PMGR_FIRST_SPARE_CLK_CFG    (&rPMGR_CLK_CFG(S0))
#define PMGR_LAST_SPARE_CLK_CFG     (&rPMGR_CLK_CFG(ISP_REF0))

#define PMGR_CLKCFG_ENABLE_UMASK        PMGR_CLKCFG_S0_CLK_CFG_ENABLE_UMASK
#define PMGR_CLKCFG_SRC_SEL_UMASK       PMGR_CLKCFG_MCU_REF_CLK_CFG_SRC_SEL_UMASK // Must have the max width of any CLKCFG SRC_SEL field
#define PMGR_CLKCFG_DIVISOR_UMASK       PMGR_CLKCFG_S0_CLK_CFG_DIVISOR_UMASK
#define PMGR_CLKCFG_WAIT_COUNTER_UMASK  PMGR_CLKCFG_MCU_REF_CLK_CFG_WAIT_COUNTER_UMASK
#define PMGR_CLKCFG_PENDING_XTRCT(_f)   PMGR_CLKCFG_S0_CLK_CFG_PENDING_XTRCT(_f)
#define PMGR_CLKCFG_SRC_SEL_XTRCT(_f)   PMGR_CLKCFG_MCU_REF_CLK_CFG_SRC_SEL_XTRCT(_f) // Must have the max width of any CLKCFG SRC_SEL field
#define PMGR_CLKCFG_ENABLE_XTRCT(_f)    PMGR_CLKCFG_MCU_REF_CLK_CFG_ENABLE_XTRCT(_f)
#define PMGR_CLKCFG_DIVISOR_XTRCT(_f)   PMGR_CLKCFG_S0_CLK_CFG_DIVISOR_XTRCT(_f)
#define PMGR_CLKCFG_SRC_SEL_INSRT(_f)   PMGR_CLKCFG_MCU_REF_CLK_CFG_SRC_SEL_INSRT(_f) // Must have the max width of any CLKCFG SRC_SEL field

#define rPMGR_MISC_CFG_ACG                  (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_MISC_CFG_ACG_OFFSET))
#define rPMGR_MISC_CFG_ASYNC_XOVER_ACG      (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_MISC_CFG_ASYNC_XOVER_ACG_OFFSET))

// MiniPMGR PS
#define rMINIPMGR_PS(_x)            (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_MINI_PS_##_x##_PS_OFFSET))

#define rMINIPMGR_CLK_CFG(_x)           (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_MINI_CLKCFG_##_x##_CLK_CFG_OFFSET))
#define rMINIPMGR_CLK_DIVIDER_ACG_CFG   (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_MINI_CLKCFG_CLK_DIVIDER_ACG_CFG_OFFSET))

#define rMINIPMGR_MISC_CFG_ACG      (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_MINI_MISC_CFG_ACG_OFFSET))

#define rMINIPMGR_LPPLL_CTL        (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_LPPLL_CTL_OFFSET))
#define rMINIPMGR_LPPLL_CFG        (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_LPPLL_CFG_OFFSET))

// MiniPMGR Watchdog
#define rPMGR_CHIP_WDOG_TMR         (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_WATCHDOG_CHIP_WATCHDOG_TIMER_OFFSET))
#define rPMGR_CHIP_WDOG_RST_CNT     (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_WATCHDOG_CHIP_WATCHDOG_RESET_COUNT_OFFSET))
#define rPMGR_CHIP_WDOG_INTR_CNT    (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_WATCHDOG_CHIP_WATCHDOG_INTERRUPT_COUNT_OFFSET))
#define rPMGR_CHIP_WDOG_CTL         (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_WATCHDOG_CHIP_WATCHDOG_CONTROL_OFFSET))
#define rPMGR_SYS_WDOG_TMR          (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_WATCHDOG_SYS_WATCHDOG_TIMER_OFFSET))
#define rPMGR_SYS_WDOG_RST_CNT      (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_WATCHDOG_SYS_WATCHDOG_RESET_COUNT_OFFSET))
#define rPMGR_SYS_WDOG_CTL          (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_WATCHDOG_SYS_WATCHDOG_CONTROL_OFFSET))

// PMGR Event Timer
#define rPMGR_EVENT_TMR             (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_TIMERS_EVENT_TIMER_OFFSET))
#define rPMGR_EVENT_TMR_PERIOD      (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_TIMERS_EVENT_TIMER_PERIOD_OFFSET))
#define rPMGR_EVENT_TMR_CTL         (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_TIMERS_EVENT_TIMER_CTL_OFFSET))

// NCO Config block
#define rPMGR_NCO_CLK_CFG(_n)       (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_NCO_##_n##_CLK_CFG_OFFSET))

// Misc Clock Tree Power Saving Regs
#define rPMGR_CLK_DIVIDER_ACG_CFG   (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_CLKCFG_CLK_DIVIDER_ACG_CFG_OFFSET))
#define rPMGR_CLK_POWER_CONFIG      (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_CLKCFG_CLK_POWER_CONFIG_OFFSET))

// SOC Perf State
static const int PMGR_SOC_PERF_STATE_ENTRY_COUNT    = 8;
static const int PMGR_SOC_PERF_STATE_STRIDE         = (PMGR_SOC_PERF_STATE_ENTRY_1A_OFFSET - PMGR_SOC_PERF_STATE_ENTRY_0A_OFFSET);
static const int kSOC_PERF_STATE_MAX_CNT            = 6;
#define rPMGR_SOC_PERF_STATE_ENTRY_A(_n)        (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_SOC_PERF_STATE_ENTRY_0A_OFFSET + (_n) * PMGR_SOC_PERF_STATE_STRIDE))
#define rPMGR_SOC_PERF_STATE_CTL                (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_SOC_PERF_STATE_CTL_OFFSET))

#define PMGR_SOC_PERF_STATE_ENTRY_MCU_REF_MASK          (PMGR_SOC_PERF_STATE_ENTRY_0A_MCU_REF_SRC_SEL_UMASK | PMGR_SOC_PERF_STATE_ENTRY_0A_MCU_REF_CFG_SEL_UMASK)
#define PMGR_SOC_PERF_STATE_ENTRY_MCU_REF(_cfg, _src)   (PMGR_SOC_PERF_STATE_ENTRY_0A_MCU_REF_CFG_SEL_INSRT(_cfg) | PMGR_SOC_PERF_STATE_ENTRY_0A_MCU_REF_SRC_SEL_INSRT(_src))

// First two entries used by AOP Config Engine
#define PMGR_SOC_PERF_STATE_FIRST_ENTRY     (PMGR_SOC_PERF_STATE_ENTRY_COUNT - kSOC_PERF_STATE_MAX_CNT)
#define PMGR_SOC_PERF_STATE_TO_ENTRY(_s)    (PMGR_SOC_PERF_STATE_ENTRY_COUNT - (_s) - 1)

enum pmgr_soc_perf_state_index {
    kSOC_PERF_STATE_BYPASS      = 0,
    kSOC_PERF_STATE_SECUREROM,
    kSOC_PERF_STATE_IBOOT,
    kSOC_PERF_STATE_VMIN        = kSOC_PERF_STATE_IBOOT,
    kSOC_PERF_STATE_IBOOT_CNT
};

static const int PMGR_SCRATCH_REG_STRIDE    = (PMGR_SCRATCH_1_OFFSET - PMGR_SCRATCH_0_OFFSET);
#define rPMGR_SCRATCH(_n)	    (*(volatile uint32_t *) (PMGR_BASE_ADDR + PMGR_SCRATCH_0_OFFSET + ((_n) * PMGR_SCRATCH_REG_STRIDE)))
#define rPMGR_SCRATCH0          rPMGR_SCRATCH(0)			/* Flags */
#define rPMGR_SCRATCH1          rPMGR_SCRATCH(1)
#define rPMGR_SCRATCH2          rPMGR_SCRATCH(2)
#define rPMGR_SCRATCH3          rPMGR_SCRATCH(3)
#define rPMGR_SCRATCH4          rPMGR_SCRATCH(4)
#define rPMGR_SCRATCH5          rPMGR_SCRATCH(5)
#define rPMGR_SCRATCH6          rPMGR_SCRATCH(6)
#define rPMGR_SCRATCH7          rPMGR_SCRATCH(7)			/* Consistent debug root pointer */
#define rPMGR_SCRATCH8          rPMGR_SCRATCH(8)

#define rPMGR_SCRATCH_MEM_INFO			rPMGR_SCRATCH(9)
#define rPMGR_SCRATCH_BOOT_NONCE_0		rPMGR_SCRATCH(10)
#define rPMGR_SCRATCH_BOOT_NONCE_1		rPMGR_SCRATCH(11)
#define rPMGR_SCRATCH_BOOT_MANIFEST_HASH_FIRST	rPMGR_SCRATCH(12)
#define rPMGR_SCRATCH_BOOT_MANIFEST_HASH_LAST	rPMGR_SCRATCH(23)
#define PMGR_SCRATCH_BOOT_MANIFEST_REGISTERS	(384 / 32)

static const int MINIPMGR_SCRATCH_REG_STRIDE    = (MINIPMGR_MINI_SCRATCH_SCRATCH1_OFFSET - MINIPMGR_MINI_SCRATCH_SCRATCH0_OFFSET);
#define rMINIPMGR_SCRATCH(_n)	(*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_MINI_SCRATCH_OFFSET + ((_n) * MINIPMGR_SCRATCH_REG_STRIDE)))
#define rMINIPMGR_SCRATCH0		rMINIPMGR_SCRATCH(0)
#define rMINIPMGR_SCRATCH1		rMINIPMGR_SCRATCH(1)		/* Consistent debug root pointer */
#define rMINIPMGR_SCRATCH2		rMINIPMGR_SCRATCH(2)
#define rMINIPMGR_SCRATCH3		rMINIPMGR_SCRATCH(3)
#define rMINIPMGR_SCRATCH4		rMINIPMGR_SCRATCH(4)
#define rMINIPMGR_SCRATCH5		rMINIPMGR_SCRATCH(5)
#define rMINIPMGR_SCRATCH6		rMINIPMGR_SCRATCH(6)
#define rMINIPMGR_SCRATCH7		rMINIPMGR_SCRATCH(7)
#define rMINIPMGR_SCRATCH8		rMINIPMGR_SCRATCH(8)
#define rMINIPMGR_SCRATCH9		rMINIPMGR_SCRATCH(9)
#define rMINIPMGR_SCRATCH10		rMINIPMGR_SCRATCH(10)
#define rMINIPMGR_SCRATCH11		rMINIPMGR_SCRATCH(11)

#define rPMGR_SECURITY          (*(volatile uint32_t *) (AOP_MINIPMGR_BASE_ADDR + MINIPMGR_SECURITY_OFFSET))

extern void pmgr_update_device_tree(DTNode *pmgr_node);

#endif /* ! __PLATFORM_SOC_PMGR_H */
