summaryrefslogblamecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
blob: 29293406d71a95e55e04fb72cdd3d619d3fe2525 (plain) (tree)
1
2
3
4
5
6




                                              
                                                                     

















                                                                               
                                                           

























                                                                     
                                        
                                        
                                    
                                    
                                    

                                    
                              













































































































































































































                                                                                
                                                                     





























                                                                         










                                            




                 








                                              












                       





                                      



                                                                                
                                 










                                                                                






















                                                                                










                                                                                











                                                                                








                                                                                
                                                                                



               
                                                     





























                                                                                                                           
                                              
                                      
                                      
                                      
                                      
                                              








                                                                        
                                           



































                                                      


                                     
                                          


                




















































































































































                                                            
                                   









                      




                                   




                                         

  



                                       

                                           








                                                        










                                                    

                                                                  
                                            
                                                              




                                            




                                                       

                                                  




















                                     










                                               


                                                      
 




                                                                     
                                                                           
















































                                                                               








                                          









                                                 





                                                 
                  












                                                            







                                               



















                                               










                                               


























                                                         
                                                         


                                                       
                                                       





































                                                   
                                       









                                               
                                       










































































































                                                                                                                      















































                                                                           
                                               



                                                
                                                





                              
                        
























                                                                 

  

































































                                                                                                      

                                                          
                                                                         





                                                                         
 
 
 
                  

                                    
                              
 
                               
                                                  

                                  
                                
























                                                    
                      

                      

                                                            
                                   


                                                                                         



                                                                 








                                                      
                        
                     

                               

                         



                                                   
                                                   
                                                   
                                                   
          

                                         

                                                 
                           

  
                                            
                                              



















                                                                                 
                                           



                                                                   






                                                     
                                         




                                                     


                                          



                                                             
                                                        

                                                             

                                                                       


                                                                         
                          
/*
 * drivers/video/tegra/host/gk20a/pmu_gk20a.h
 *
 * GK20A PMU (aka. gPMU outside gk20a context)
 *
 * Copyright (c) 2011-2015, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 */
#ifndef __PMU_GK20A_H__
#define __PMU_GK20A_H__

/* defined by pmu hw spec */
#define GK20A_PMU_VA_SIZE		(512 * 1024 * 1024)
#define GK20A_PMU_UCODE_SIZE_MAX	(256 * 1024)
#define GK20A_PMU_SEQ_BUF_SIZE		4096

#define ZBC_MASK(i)			(~(~(0) << ((i)+1)) & 0xfffe)

/* PMU Command/Message Interfaces for Adaptive Power */
/* Macro to get Histogram index */
#define PMU_AP_HISTOGRAM(idx)		(idx)
#define PMU_AP_HISTOGRAM_CONT		(4)

/* Total number of histogram bins */
#define PMU_AP_CFG_HISTOGRAM_BIN_N	(16)

/* Mapping between Idle counters and histograms */
#define PMU_AP_IDLE_MASK_HIST_IDX_0		(2)
#define PMU_AP_IDLE_MASK_HIST_IDX_1		(3)
#define PMU_AP_IDLE_MASK_HIST_IDX_2		(5)
#define PMU_AP_IDLE_MASK_HIST_IDX_3		(6)


/* Mapping between AP_CTRLs and Histograms */
#define PMU_AP_HISTOGRAM_IDX_GRAPHICS	(PMU_AP_HISTOGRAM(1))

/* Mapping between AP_CTRLs and Idle counters */
#define PMU_AP_IDLE_MASK_GRAPHICS	(PMU_AP_IDLE_MASK_HIST_IDX_1)

#define APP_VERSION_T186_1	19870492
#define APP_VERSION_T186_0	19842227
#define APP_VERSION_GM20B_4 19008461
#define APP_VERSION_GM20B_3 18935575
#define APP_VERSION_GM20B_2 18694072
#define APP_VERSION_GM20B_1 18547257
#define APP_VERSION_GM20B 17615280
#define APP_VERSION_2 18542378
#define APP_VERSION_1 17997577
#define APP_VERSION_0 16856675


enum pmu_perfmon_cmd_start_fields {
	COUNTER_ALLOC
};

/* Adaptive Power Controls (AP_CTRL) */
enum {
	PMU_AP_CTRL_ID_GRAPHICS = 0x0,
	/* PMU_AP_CTRL_ID_MS         ,*/
	PMU_AP_CTRL_ID_MAX           ,
};

/* AP_CTRL Statistics */
struct pmu_ap_ctrl_stat {
	/*
	 * Represents whether AP is active or not
	 * TODO: This is NvBool in RM; is that 1 byte of 4 bytes?
	 */
	u8	b_active;

	/* Idle filter represented by histogram bin index */
	u8	idle_filter_x;
	u8	rsvd[2];

	/* Total predicted power saving cycles. */
	s32	power_saving_h_cycles;

	/* Counts how many times AP gave us -ve power benefits. */
	u32	bad_decision_count;

	/*
	 * Number of times ap structure needs to skip AP iterations
	 * KICK_CTRL from kernel updates this parameter.
	 */
	u32	skip_count;
	u8	bin[PMU_AP_CFG_HISTOGRAM_BIN_N];
};

/* Parameters initialized by INITn APCTRL command */
struct pmu_ap_ctrl_init_params {
	/* Minimum idle filter value in Us */
	u32	min_idle_filter_us;

	/*
	 * Minimum Targeted Saving in Us. AP will update idle thresholds only
	 * if power saving achieved by updating idle thresholds is greater than
	 * Minimum targeted saving.
	 */
	u32	min_target_saving_us;

	/* Minimum targeted residency of power feature in Us */
	u32	power_break_even_us;

	/*
	 * Maximum number of allowed power feature cycles per sample.
	 *
	 * We are allowing at max "pgPerSampleMax" cycles in one iteration of AP
	 * AKA pgPerSampleMax in original algorithm.
	 */
	u32	cycles_per_sample_max;
};

/* AP Commands/Message structures */

/*
 * Structure for Generic AP Commands
 */
struct pmu_ap_cmd_common {
	u8	cmd_type;
	u16	cmd_id;
};

/*
 * Structure for INIT AP command
 */
struct pmu_ap_cmd_init {
	u8	cmd_type;
	u16	cmd_id;
	u8	rsvd;
	u32	pg_sampling_period_us;
};

/*
 * Structure for Enable/Disable ApCtrl Commands
 */
struct pmu_ap_cmd_enable_ctrl {
	u8	cmd_type;
	u16	cmd_id;

	u8	ctrl_id;
};

struct pmu_ap_cmd_disable_ctrl {
	u8	cmd_type;
	u16	cmd_id;

	u8	ctrl_id;
};

/*
 * Structure for INIT command
 */
struct pmu_ap_cmd_init_ctrl {
	u8				cmd_type;
	u16				cmd_id;
	u8				ctrl_id;
	struct pmu_ap_ctrl_init_params	params;
};

struct pmu_ap_cmd_init_and_enable_ctrl {
	u8				cmd_type;
	u16				cmd_id;
	u8				ctrl_id;
	struct pmu_ap_ctrl_init_params	params;
};

/*
 * Structure for KICK_CTRL command
 */
struct pmu_ap_cmd_kick_ctrl {
	u8	cmd_type;
	u16	cmd_id;
	u8	ctrl_id;

	u32	skip_count;
};

/*
 * Structure for PARAM command
 */
struct pmu_ap_cmd_param {
	u8	cmd_type;
	u16	cmd_id;
	u8	ctrl_id;

	u32	data;
};

/*
 * Defines for AP commands
 */
enum {
	PMU_AP_CMD_ID_INIT = 0x0          ,
	PMU_AP_CMD_ID_INIT_AND_ENABLE_CTRL,
	PMU_AP_CMD_ID_ENABLE_CTRL         ,
	PMU_AP_CMD_ID_DISABLE_CTRL        ,
	PMU_AP_CMD_ID_KICK_CTRL           ,
};

/*
 * AP Command
 */
union pmu_ap_cmd {
	u8					cmd_type;
	struct pmu_ap_cmd_common		cmn;
	struct pmu_ap_cmd_init			init;
	struct pmu_ap_cmd_init_and_enable_ctrl	init_and_enable_ctrl;
	struct pmu_ap_cmd_enable_ctrl		enable_ctrl;
	struct pmu_ap_cmd_disable_ctrl		disable_ctrl;
	struct pmu_ap_cmd_kick_ctrl		kick_ctrl;
};

/*
 * Structure for generic AP Message
 */
struct pmu_ap_msg_common {
	u8	msg_type;
	u16	msg_id;
};

/*
 * Structure for INIT_ACK Message
 */
struct pmu_ap_msg_init_ack {
	u8	msg_type;
	u16	msg_id;
	u8	ctrl_id;
	u32	stats_dmem_offset;
};

/*
 * Defines for AP messages
 */
enum {
	PMU_AP_MSG_ID_INIT_ACK = 0x0,
};

/*
 * AP Message
 */
union pmu_ap_msg {
	u8				msg_type;
	struct pmu_ap_msg_common	cmn;
	struct pmu_ap_msg_init_ack	init_ack;
};

/* Default Sampling Period of AELPG */
#define APCTRL_SAMPLING_PERIOD_PG_DEFAULT_US                    (1000000)

/* Default values of APCTRL parameters */
#define APCTRL_MINIMUM_IDLE_FILTER_DEFAULT_US                   (100)
#define APCTRL_MINIMUM_TARGET_SAVING_DEFAULT_US                 (10000)
#define APCTRL_POWER_BREAKEVEN_DEFAULT_US                       (2000)
#define APCTRL_CYCLES_PER_SAMPLE_MAX_DEFAULT                    (200)

/*
 * Disable reason for Adaptive Power Controller
 */
enum {
	APCTRL_DISABLE_REASON_RM_UNLOAD,
	APCTRL_DISABLE_REASON_RMCTRL,
};

/*
 * Adaptive Power Controller
 */
struct ap_ctrl {
	u32			stats_dmem_offset;
	u32			disable_reason_mask;
	struct pmu_ap_ctrl_stat	stat_cache;
	u8			b_ready;
};

/*
 * Adaptive Power structure
 *
 * ap structure provides generic infrastructure to make any power feature
 * adaptive.
 */
struct pmu_ap {
	u32			supported_mask;
	struct ap_ctrl		ap_ctrl[PMU_AP_CTRL_ID_MAX];
};

enum {
	GK20A_PMU_DMAIDX_UCODE		= 0,
	GK20A_PMU_DMAIDX_VIRT		= 1,
	GK20A_PMU_DMAIDX_PHYS_VID	= 2,
	GK20A_PMU_DMAIDX_PHYS_SYS_COH	= 3,
	GK20A_PMU_DMAIDX_PHYS_SYS_NCOH	= 4,
	GK20A_PMU_DMAIDX_RSVD		= 5,
	GK20A_PMU_DMAIDX_PELPG		= 6,
	GK20A_PMU_DMAIDX_END		= 7
};

struct falc_u64 {
	u32 lo;
	u32 hi;
};

struct falc_dma_addr {
	u32 dma_base;
	/*dma_base1 is 9-bit MSB for FB Base
	 *address for the transfer in FB after
	 *address using 49b FB address*/
	u16 dma_base1;
	u8 dma_offset;
};

struct pmu_mem_v0 {
	u32 dma_base;
	u8  dma_offset;
	u8  dma_idx;
};

struct pmu_mem_v1 {
	u32 dma_base;
	u8  dma_offset;
	u8  dma_idx;
	u16 fb_size;
};

struct pmu_mem_v2 {
	struct falc_dma_addr dma_addr;
	u8  dma_idx;
	u16 fb_size;
};

struct pmu_mem_desc_v0 {
    /*!
     * Start address of memory surface that is being communicated to the falcon.
     */
	struct falc_u64 dma_addr;
    /*!
     * Max allowed DMA transfer size (size of the memory surface). Accesses past
     * this point may result in page faults and/or memory corruptions.
     */
	u16       dma_sizemax;
    /*!
     * DMA channel index to be used when accessing this surface.
     */
	u8        dma_idx;
};

struct pmu_dmem {
	u16 size;
	u32 offset;
};

/* Make sure size of this structure is a multiple of 4 bytes */
struct pmu_cmdline_args_v0 {
	u32 cpu_freq_hz;		/* Frequency of the clock driving PMU */
	u32 falc_trace_size;		/* falctrace buffer size (bytes) */
	u32 falc_trace_dma_base;	/* 256-byte block address */
	u32 falc_trace_dma_idx;		/* dmaIdx for DMA operations */
	struct pmu_mem_v0 gc6_ctx;		/* dmem offset of gc6 context */
};

struct pmu_cmdline_args_v1 {
	u32 cpu_freq_hz;		/* Frequency of the clock driving PMU */
	u32 falc_trace_size;		/* falctrace buffer size (bytes) */
	u32 falc_trace_dma_base;	/* 256-byte block address */
	u32 falc_trace_dma_idx;		/* dmaIdx for DMA operations */
	u8 secure_mode;
	struct pmu_mem_v1 gc6_ctx;		/* dmem offset of gc6 context */
};

struct pmu_cmdline_args_v2 {
	u32 cpu_freq_hz;		/* Frequency of the clock driving PMU */
	u32 falc_trace_size;		/* falctrace buffer size (bytes) */
	u32 falc_trace_dma_base;	/* 256-byte block address */
	u32 falc_trace_dma_idx;		/* dmaIdx for DMA operations */
	u8 secure_mode;
	u8 raise_priv_sec;     /*Raise priv level required for desired
					registers*/
	struct pmu_mem_v1 gc6_ctx;		/* dmem offset of gc6 context */
};

struct pmu_cmdline_args_v3 {
	u32 reserved;
	u32 cpu_freq_hz;		/* Frequency of the clock driving PMU */
	u32 falc_trace_size;		/* falctrace buffer size (bytes) */
	u32 falc_trace_dma_base;	/* 256-byte block address */
	u32 falc_trace_dma_idx;		/* dmaIdx for DMA operations */
	u8 secure_mode;
	u8 raise_priv_sec;     /*Raise priv level required for desired
					registers*/
	struct pmu_mem_v1 gc6_ctx;		/* dmem offset of gc6 context */
};

struct pmu_cmdline_args_v4 {
	u32 reserved;
	u32 cpu_freq_hz;		/* Frequency of the clock driving PMU */
	u32 falc_trace_size;		/* falctrace buffer size (bytes) */
	struct falc_dma_addr dma_addr;	/* 256-byte block address */
	u32 falc_trace_dma_idx;		/* dmaIdx for DMA operations */
	u8 secure_mode;
	u8 raise_priv_sec;     /*Raise priv level required for desired
					registers*/
	struct pmu_mem_desc_v0 gc6_ctx;		/* dmem offset of gc6 context */
	u8 pad;
};


#define GK20A_PMU_TRACE_BUFSIZE     0x4000   /* 4K */
#define GK20A_PMU_DMEM_BLKSIZE2		8

#define GK20A_PMU_UCODE_NB_MAX_OVERLAY	    32
#define GK20A_PMU_UCODE_NB_MAX_DATE_LENGTH  64

struct pmu_ucode_desc {
	u32 descriptor_size;
	u32 image_size;
	u32 tools_version;
	u32 app_version;
	char date[GK20A_PMU_UCODE_NB_MAX_DATE_LENGTH];
	u32 bootloader_start_offset;
	u32 bootloader_size;
	u32 bootloader_imem_offset;
	u32 bootloader_entry_point;
	u32 app_start_offset;
	u32 app_size;
	u32 app_imem_offset;
	u32 app_imem_entry;
	u32 app_dmem_offset;
	u32 app_resident_code_offset;  /* Offset from appStartOffset */
	u32 app_resident_code_size;    /* Exact size of the resident code ( potentially contains CRC inside at the end ) */
	u32 app_resident_data_offset;  /* Offset from appStartOffset */
	u32 app_resident_data_size;    /* Exact size of the resident code ( potentially contains CRC inside at the end ) */
	u32 nb_overlays;
	struct {u32 start; u32 size;} load_ovl[GK20A_PMU_UCODE_NB_MAX_OVERLAY];
	u32 compressed;
};

#define PMU_UNIT_REWIND		(0x00)
#define PMU_UNIT_PG			(0x03)
#define PMU_UNIT_INIT		(0x07)
#define PMU_UNIT_ACR		(0x0A)
#define PMU_UNIT_PERFMON_T18X	(0x11)
#define PMU_UNIT_PERFMON	(0x12)
#define PMU_UNIT_RC			(0x1F)
#define PMU_UNIT_END		(0x23)

#define PMU_UNIT_TEST_START	(0xFE)
#define PMU_UNIT_END_SIM	(0xFF)
#define PMU_UNIT_TEST_END	(0xFF)

#define PMU_UNIT_ID_IS_VALID(id)		\
		(((id) < PMU_UNIT_END) || ((id) >= PMU_UNIT_TEST_START))

#define PMU_DMEM_ALLOC_ALIGNMENT	(4)
#define PMU_DMEM_ALIGNMENT		(4)

#define PMU_CMD_FLAGS_PMU_MASK		(0xF0)

#define PMU_CMD_FLAGS_STATUS		BIT(0)
#define PMU_CMD_FLAGS_INTR		BIT(1)
#define PMU_CMD_FLAGS_EVENT		BIT(2)
#define PMU_CMD_FLAGS_WATERMARK		BIT(3)

struct pmu_hdr {
	u8 unit_id;
	u8 size;
	u8 ctrl_flags;
	u8 seq_id;
};
#define PMU_MSG_HDR_SIZE	sizeof(struct pmu_hdr)
#define PMU_CMD_HDR_SIZE	sizeof(struct pmu_hdr)

#define PMU_QUEUE_COUNT		5

struct pmu_allocation_v0 {
	u8 pad[3];
	u8 fb_mem_use;
	struct {
		struct pmu_dmem dmem;
		struct pmu_mem_v0 fb;
	} alloc;
};

struct pmu_allocation_v1 {
	struct {
		struct pmu_dmem dmem;
		struct pmu_mem_v1 fb;
	} alloc;
};

struct pmu_allocation_v2 {
	struct {
		struct pmu_dmem dmem;
		struct pmu_mem_desc_v0 fb;
	} alloc;
};

enum {
	PMU_INIT_MSG_TYPE_PMU_INIT = 0,
};

struct pmu_init_msg_pmu_v0 {
	u8 msg_type;
	u8 pad;

	struct {
		u16 size;
		u16 offset;
		u8  index;
		u8  pad;
	} queue_info[PMU_QUEUE_COUNT];

	u16 sw_managed_area_offset;
	u16 sw_managed_area_size;
};

struct pmu_init_msg_pmu_v1 {
	u8 msg_type;
	u8 pad;
	u16  os_debug_entry_point;

	struct {
		u16 size;
		u16 offset;
		u8  index;
		u8  pad;
	} queue_info[PMU_QUEUE_COUNT];

	u16 sw_managed_area_offset;
	u16 sw_managed_area_size;
};

union pmu_init_msg_pmu {
	struct pmu_init_msg_pmu_v0 v0;
	struct pmu_init_msg_pmu_v1 v1;
};

struct pmu_init_msg {
	union {
		u8 msg_type;
		struct pmu_init_msg_pmu_v1 pmu_init_v1;
		struct pmu_init_msg_pmu_v0 pmu_init_v0;
	};
};

enum {
	PMU_PG_ELPG_MSG_INIT_ACK,
	PMU_PG_ELPG_MSG_DISALLOW_ACK,
	PMU_PG_ELPG_MSG_ALLOW_ACK,
	PMU_PG_ELPG_MSG_FREEZE_ACK,
	PMU_PG_ELPG_MSG_FREEZE_ABORT,
	PMU_PG_ELPG_MSG_UNFREEZE_ACK,
};

struct pmu_pg_msg_elpg_msg {
	u8 msg_type;
	u8 engine_id;
	u16 msg;
};

enum {
	PMU_PG_STAT_MSG_RESP_DMEM_OFFSET = 0,
};

struct pmu_pg_msg_stat {
	u8 msg_type;
	u8 engine_id;
	u16 sub_msg_id;
	u32 data;
};

enum {
	PMU_PG_MSG_ENG_BUF_LOADED,
	PMU_PG_MSG_ENG_BUF_UNLOADED,
	PMU_PG_MSG_ENG_BUF_FAILED,
};

struct pmu_pg_msg_eng_buf_stat {
	u8 msg_type;
	u8 engine_id;
	u8 buf_idx;
	u8 status;
};

struct pmu_pg_msg {
	union {
		u8 msg_type;
		struct pmu_pg_msg_elpg_msg elpg_msg;
		struct pmu_pg_msg_stat stat;
		struct pmu_pg_msg_eng_buf_stat eng_buf_stat;
		/* TBD: other pg messages */
		union pmu_ap_msg ap_msg;
	};
};

enum {
	PMU_RC_MSG_TYPE_UNHANDLED_CMD = 0,
};

struct pmu_rc_msg_unhandled_cmd {
	u8 msg_type;
	u8 unit_id;
};

struct pmu_rc_msg {
	u8 msg_type;
	struct pmu_rc_msg_unhandled_cmd unhandled_cmd;
};

enum {
	PMU_PG_CMD_ID_ELPG_CMD = 0,
	PMU_PG_CMD_ID_ENG_BUF_LOAD,
	PMU_PG_CMD_ID_ENG_BUF_UNLOAD,
	PMU_PG_CMD_ID_PG_STAT,
	PMU_PG_CMD_ID_PG_LOG_INIT,
	PMU_PG_CMD_ID_PG_LOG_FLUSH,
	PMU_PG_CMD_ID_PG_PARAM,
	PMU_PG_CMD_ID_ELPG_INIT,
	PMU_PG_CMD_ID_ELPG_POLL_CTXSAVE,
	PMU_PG_CMD_ID_ELPG_ABORT_POLL,
	PMU_PG_CMD_ID_ELPG_PWR_UP,
	PMU_PG_CMD_ID_ELPG_DISALLOW,
	PMU_PG_CMD_ID_ELPG_ALLOW,
	PMU_PG_CMD_ID_AP,
	RM_PMU_PG_CMD_ID_PSI,
	RM_PMU_PG_CMD_ID_CG,
	PMU_PG_CMD_ID_ZBC_TABLE_UPDATE,
	PMU_PG_CMD_ID_PWR_RAIL_GATE_DISABLE = 0x20,
	PMU_PG_CMD_ID_PWR_RAIL_GATE_ENABLE,
	PMU_PG_CMD_ID_PWR_RAIL_SMU_MSG_DISABLE
};

enum {
	PMU_PG_ELPG_CMD_INIT,
	PMU_PG_ELPG_CMD_DISALLOW,
	PMU_PG_ELPG_CMD_ALLOW,
	PMU_PG_ELPG_CMD_FREEZE,
	PMU_PG_ELPG_CMD_UNFREEZE,
};

struct pmu_pg_cmd_elpg_cmd {
	u8 cmd_type;
	u8 engine_id;
	u16 cmd;
};

struct pmu_pg_cmd_eng_buf_load_v0 {
	u8 cmd_type;
	u8 engine_id;
	u8 buf_idx;
	u8 pad;
	u16 buf_size;
	u32 dma_base;
	u8 dma_offset;
	u8 dma_idx;
};

struct pmu_pg_cmd_eng_buf_load_v1 {
	u8 cmd_type;
	u8 engine_id;
	u8 buf_idx;
	u8 pad;
	struct flcn_mem_desc {
		struct falc_u64 dma_addr;
		u16 dma_size;
		u8 dma_idx;
	} dma_desc;
};

enum {
	PMU_PG_STAT_CMD_ALLOC_DMEM = 0,
};

#define PMU_PG_PARAM_CMD_GR_INIT_PARAM  0x0

#define PMU_PG_FEATURE_GR_SDIV_SLOWDOWN_ENABLED	(1 << 0)
#define PMU_PG_FEATURE_GR_POWER_GATING_ENABLED	(1 << 2)

struct pmu_pg_cmd_gr_init_param {
	u8 cmd_type;
	u16 sub_cmd_id;
	u8 featuremask;
};

struct pmu_pg_cmd_stat {
	u8 cmd_type;
	u8 engine_id;
	u16 sub_cmd_id;
	u32 data;
};

struct pmu_pg_cmd {
	union {
		u8 cmd_type;
		struct pmu_pg_cmd_elpg_cmd elpg_cmd;
		struct pmu_pg_cmd_eng_buf_load_v0 eng_buf_load_v0;
		struct pmu_pg_cmd_eng_buf_load_v1 eng_buf_load_v1;
		struct pmu_pg_cmd_stat stat;
		struct pmu_pg_cmd_gr_init_param gr_init_param;
		/* TBD: other pg commands */
		union pmu_ap_cmd ap_cmd;
	};
};

/* ACR Commands/Message structures */

enum {
	PMU_ACR_CMD_ID_INIT_WPR_REGION = 0x0          ,
	PMU_ACR_CMD_ID_BOOTSTRAP_FALCON,
	PMU_ACR_CMD_ID_RESERVED,
	PMU_ACR_CMD_ID_BOOTSTRAP_MULTIPLE_FALCONS,
};

/*
 * Initializes the WPR region details
 */
struct pmu_acr_cmd_init_wpr_details {
	u8  cmd_type;
	u32 regionid;
	u32 wproffset;

};

/*
 * falcon ID to bootstrap
 */
struct pmu_acr_cmd_bootstrap_falcon {
	u8 cmd_type;
	u32 flags;
	u32 falconid;
};

/*
 * falcon ID to bootstrap
 */
struct pmu_acr_cmd_bootstrap_multiple_falcons {
	u8 cmd_type;
	u32 flags;
	u32 falconidmask;
	u32 usevamask;
	struct falc_u64 wprvirtualbase;
};

#define PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO  1
#define PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0


struct pmu_acr_cmd {
	union {
		u8 cmd_type;
		struct pmu_acr_cmd_bootstrap_falcon bootstrap_falcon;
		struct pmu_acr_cmd_init_wpr_details init_wpr;
		struct pmu_acr_cmd_bootstrap_multiple_falcons boot_falcons;
	};
};

/* acr messages */

/*
 * returns the WPR region init information
 */
#define PMU_ACR_MSG_ID_INIT_WPR_REGION   0

/*
 * Returns the Bootstrapped falcon ID to RM
 */
#define PMU_ACR_MSG_ID_BOOTSTRAP_FALCON  1

/*
 * Returns the WPR init status
 */
#define PMU_ACR_SUCCESS                  0
#define PMU_ACR_ERROR                    1

/*
 * PMU notifies about bootstrap status of falcon
 */
struct pmu_acr_msg_bootstrap_falcon {
	u8 msg_type;
	union {
		u32 errorcode;
		u32 falconid;
	};
};

struct pmu_acr_msg {
	union {
		u8 msg_type;
		struct pmu_acr_msg_bootstrap_falcon acrmsg;
	};
};

/***************************** ACR ERROR CODES  ******************************/
/*!
 * Error codes used in PMU-ACR Task
 *
 * LSF_ACR_INVALID_TRANSCFG_SETUP : Indicates that TRANSCFG Setup is not valid
 *  MAILBOX1 returns the CTXDMA ID of invalid setup
 *
 */
#define ACR_ERROR_INVALID_TRANSCFG_SETUP        (0xAC120001)

/* PERFMON */
#define PMU_DOMAIN_GROUP_PSTATE		0
#define PMU_DOMAIN_GROUP_GPC2CLK	1
#define PMU_DOMAIN_GROUP_NUM		2

/* TBD: smart strategy */
#define PMU_PERFMON_PCT_TO_INC		58
#define PMU_PERFMON_PCT_TO_DEC		23

struct pmu_perfmon_counter_v0 {
	u8 index;
	u8 flags;
	u8 group_id;
	u8 valid;
	u16 upper_threshold; /* units of 0.01% */
	u16 lower_threshold; /* units of 0.01% */
};

struct pmu_perfmon_counter_v2 {
	u8 index;
	u8 flags;
	u8 group_id;
	u8 valid;
	u16 upper_threshold; /* units of 0.01% */
	u16 lower_threshold; /* units of 0.01% */
	u32 scale;
};

#define PMU_PERFMON_FLAG_ENABLE_INCREASE	(0x00000001)
#define PMU_PERFMON_FLAG_ENABLE_DECREASE	(0x00000002)
#define PMU_PERFMON_FLAG_CLEAR_PREV		(0x00000004)

/* PERFMON CMD */
enum {
	PMU_PERFMON_CMD_ID_START = 0,
	PMU_PERFMON_CMD_ID_STOP  = 1,
	PMU_PERFMON_CMD_ID_INIT  = 2
};

struct pmu_perfmon_cmd_start_v2 {
	u8 cmd_type;
	u8 group_id;
	u8 state_id;
	u8 flags;
	struct pmu_allocation_v2 counter_alloc;
};

struct pmu_perfmon_cmd_start_v1 {
	u8 cmd_type;
	u8 group_id;
	u8 state_id;
	u8 flags;
	struct pmu_allocation_v1 counter_alloc;
};

struct pmu_perfmon_cmd_start_v0 {
	u8 cmd_type;
	u8 group_id;
	u8 state_id;
	u8 flags;
	struct pmu_allocation_v0 counter_alloc;
};

struct pmu_perfmon_cmd_stop {
	u8 cmd_type;
};

struct pmu_perfmon_cmd_init_v2 {
	u8 cmd_type;
	u8 to_decrease_count;
	u8 base_counter_id;
	u32 sample_period_us;
	struct pmu_allocation_v2 counter_alloc;
	u8 num_counters;
	u8 samples_in_moving_avg;
	u16 sample_buffer;
};

struct pmu_perfmon_cmd_init_v1 {
	u8 cmd_type;
	u8 to_decrease_count;
	u8 base_counter_id;
	u32 sample_period_us;
	struct pmu_allocation_v1 counter_alloc;
	u8 num_counters;
	u8 samples_in_moving_avg;
	u16 sample_buffer;
};

struct pmu_perfmon_cmd_init_v0 {
	u8 cmd_type;
	u8 to_decrease_count;
	u8 base_counter_id;
	u32 sample_period_us;
	struct pmu_allocation_v0 counter_alloc;
	u8 num_counters;
	u8 samples_in_moving_avg;
	u16 sample_buffer;
};

struct pmu_perfmon_cmd {
	union {
		u8 cmd_type;
		struct pmu_perfmon_cmd_start_v0 start_v0;
		struct pmu_perfmon_cmd_start_v1 start_v1;
		struct pmu_perfmon_cmd_start_v2 start_v2;
		struct pmu_perfmon_cmd_stop stop;
		struct pmu_perfmon_cmd_init_v0 init_v0;
		struct pmu_perfmon_cmd_init_v1 init_v1;
		struct pmu_perfmon_cmd_init_v2 init_v2;
	};
};

struct pmu_zbc_cmd {
	u8 cmd_type;
	u8 pad;
	u16 entry_mask;
};

/* PERFMON MSG */
enum {
	PMU_PERFMON_MSG_ID_INCREASE_EVENT = 0,
	PMU_PERFMON_MSG_ID_DECREASE_EVENT = 1,
	PMU_PERFMON_MSG_ID_INIT_EVENT     = 2,
	PMU_PERFMON_MSG_ID_ACK            = 3
};

struct pmu_perfmon_msg_generic {
	u8 msg_type;
	u8 state_id;
	u8 group_id;
	u8 data;
};

struct pmu_perfmon_msg {
	union {
		u8 msg_type;
		struct pmu_perfmon_msg_generic gen;
	};
};


struct pmu_cmd {
	struct pmu_hdr hdr;
	union {
		struct pmu_perfmon_cmd perfmon;
		struct pmu_pg_cmd pg;
		struct pmu_zbc_cmd zbc;
		struct pmu_acr_cmd acr;
	} cmd;
};

struct pmu_msg {
	struct pmu_hdr hdr;
	union {
		struct pmu_init_msg init;
		struct pmu_perfmon_msg perfmon;
		struct pmu_pg_msg pg;
		struct pmu_rc_msg rc;
		struct pmu_acr_msg acr;
	} msg;
};

#define PMU_SHA1_GID_SIGNATURE		0xA7C66AD2
#define PMU_SHA1_GID_SIGNATURE_SIZE	4

#define PMU_SHA1_GID_SIZE	16

struct pmu_sha1_gid {
	bool valid;
	u8 gid[PMU_SHA1_GID_SIZE];
};

struct pmu_sha1_gid_data {
	u8 signature[PMU_SHA1_GID_SIGNATURE_SIZE];
	u8 gid[PMU_SHA1_GID_SIZE];
};

#define PMU_COMMAND_QUEUE_HPQ		0	/* write by sw, read by pmu, protected by sw mutex lock */
#define PMU_COMMAND_QUEUE_LPQ		1	/* write by sw, read by pmu, protected by sw mutex lock */
#define PMU_COMMAND_QUEUE_BIOS		2	/* read/write by sw/hw, protected by hw pmu mutex, id = 2 */
#define PMU_COMMAND_QUEUE_SMI		3	/* read/write by sw/hw, protected by hw pmu mutex, id = 3 */
#define PMU_MESSAGE_QUEUE		4	/* write by pmu, read by sw, accessed by interrupt handler, no lock */
#define PMU_QUEUE_COUNT			5

enum {
	PMU_MUTEX_ID_RSVD1 = 0	,
	PMU_MUTEX_ID_GPUSER	,
	PMU_MUTEX_ID_QUEUE_BIOS	,
	PMU_MUTEX_ID_QUEUE_SMI	,
	PMU_MUTEX_ID_GPMUTEX	,
	PMU_MUTEX_ID_I2C	,
	PMU_MUTEX_ID_RMLOCK	,
	PMU_MUTEX_ID_MSGBOX	,
	PMU_MUTEX_ID_FIFO	,
	PMU_MUTEX_ID_PG		,
	PMU_MUTEX_ID_GR		,
	PMU_MUTEX_ID_CLK	,
	PMU_MUTEX_ID_RSVD6	,
	PMU_MUTEX_ID_RSVD7	,
	PMU_MUTEX_ID_RSVD8	,
	PMU_MUTEX_ID_RSVD9	,
	PMU_MUTEX_ID_INVALID
};

#define PMU_IS_COMMAND_QUEUE(id)	\
		((id)  < PMU_MESSAGE_QUEUE)

#define PMU_IS_SW_COMMAND_QUEUE(id)	\
		(((id) == PMU_COMMAND_QUEUE_HPQ) || \
		 ((id) == PMU_COMMAND_QUEUE_LPQ))

#define  PMU_IS_MESSAGE_QUEUE(id)	\
		((id) == PMU_MESSAGE_QUEUE)

enum
{
	OFLAG_READ = 0,
	OFLAG_WRITE
};

#define QUEUE_SET		(true)
#define QUEUE_GET		(false)

#define QUEUE_ALIGNMENT		(4)

#define PMU_PGENG_GR_BUFFER_IDX_INIT	(0)
#define PMU_PGENG_GR_BUFFER_IDX_ZBC	(1)
#define PMU_PGENG_GR_BUFFER_IDX_FECS	(2)

enum
{
    PMU_DMAIDX_UCODE         = 0,
    PMU_DMAIDX_VIRT          = 1,
    PMU_DMAIDX_PHYS_VID      = 2,
    PMU_DMAIDX_PHYS_SYS_COH  = 3,
    PMU_DMAIDX_PHYS_SYS_NCOH = 4,
    PMU_DMAIDX_RSVD          = 5,
    PMU_DMAIDX_PELPG         = 6,
    PMU_DMAIDX_END           = 7
};

struct pmu_gk20a;
struct pmu_queue;

struct pmu_queue {

	/* used by hw, for BIOS/SMI queue */
	u32 mutex_id;
	u32 mutex_lock;
	/* used by sw, for LPQ/HPQ queue */
	struct mutex mutex;

	/* current write position */
	u32 position;
	/* physical dmem offset where this queue begins */
	u32 offset;
	/* logical queue identifier */
	u32 id;
	/* physical queue index */
	u32 index;
	/* in bytes */
	u32 size;

	/* open-flag */
	u32 oflag;
	bool opened; /* opened implies locked */
};


#define PMU_MUTEX_ID_IS_VALID(id)	\
		((id) < PMU_MUTEX_ID_INVALID)

#define PMU_INVALID_MUTEX_OWNER_ID	(0)

struct pmu_mutex {
	u32 id;
	u32 index;
	u32 ref_cnt;
};

#define PMU_MAX_NUM_SEQUENCES		(256)
#define PMU_SEQ_BIT_SHIFT		(5)
#define PMU_SEQ_TBL_SIZE	\
		(PMU_MAX_NUM_SEQUENCES >> PMU_SEQ_BIT_SHIFT)

#define PMU_INVALID_SEQ_DESC		(~0)

enum
{
	PMU_SEQ_STATE_FREE = 0,
	PMU_SEQ_STATE_PENDING,
	PMU_SEQ_STATE_USED,
	PMU_SEQ_STATE_CANCELLED
};

struct pmu_payload {
	struct {
		void *buf;
		u32 offset;
		u32 size;
	} in, out;
};

typedef void (*pmu_callback)(struct gk20a *, struct pmu_msg *, void *, u32,
	u32);

struct pmu_sequence {
	u8 id;
	u32 state;
	u32 desc;
	struct pmu_msg *msg;
	union {
		struct pmu_allocation_v0 in_v0;
		struct pmu_allocation_v1 in_v1;
		struct pmu_allocation_v2 in_v2;
	};
	union {
		struct pmu_allocation_v0 out_v0;
		struct pmu_allocation_v1 out_v1;
		struct pmu_allocation_v2 out_v2;
	};
	u8 *out_payload;
	pmu_callback callback;
	void* cb_params;
};

struct pmu_pg_stats_v1 {
	/* Number of time PMU successfully engaged sleep state */
	u32 entry_count;
	/* Number of time PMU exit sleep state */
	u32 exit_count;
	/* Number of time PMU aborted in entry sequence */
	u32 abort_count;
	/*
	* Time for which GPU was neither in Sleep state not
	* executing sleep sequence.
	* */
	u32 poweredup_timeus;
	/* Entry and exit latency of current sleep cycle */
	u32 entry_latency_us;
	u32 exitlatencyus;
	/* Resident time for current sleep cycle. */
	u32 resident_timeus;
	/* Rolling average entry and exit latencies */
	u32 entrylatency_avgus;
	u32 exitlatency_avgus;
	/* Max entry and exit latencies */
	u32 entrylatency_maxus;
	u32 exitlatency_maxus;
	/* Total time spent in sleep and non-sleep state */
	u32 total_sleep_timeus;
	u32 total_nonsleep_timeus;
};

struct pmu_pg_stats {
	u64 pg_entry_start_timestamp;
	u64 pg_ingating_start_timestamp;
	u64 pg_exit_start_timestamp;
	u64 pg_ungating_start_timestamp;
	u32 pg_avg_entry_time_us;
	u32 pg_ingating_cnt;
	u32 pg_ingating_time_us;
	u32 pg_avg_exit_time_us;
	u32 pg_ungating_count;
	u32 pg_ungating_time_us;
	u32 pg_gating_cnt;
	u32 pg_gating_deny_cnt;
};

#define PMU_PG_IDLE_THRESHOLD_SIM		1000
#define PMU_PG_POST_POWERUP_IDLE_THRESHOLD_SIM	4000000
/* TBD: QT or else ? */
#define PMU_PG_IDLE_THRESHOLD			15000
#define PMU_PG_POST_POWERUP_IDLE_THRESHOLD	1000000

/* state transition :
    OFF => [OFF_ON_PENDING optional] => ON_PENDING => ON => OFF
    ON => OFF is always synchronized */
#define PMU_ELPG_STAT_OFF		0   /* elpg is off */
#define PMU_ELPG_STAT_ON		1   /* elpg is on */
#define PMU_ELPG_STAT_ON_PENDING	2   /* elpg is off, ALLOW cmd has been sent, wait for ack */
#define PMU_ELPG_STAT_OFF_PENDING	3   /* elpg is on, DISALLOW cmd has been sent, wait for ack */
#define PMU_ELPG_STAT_OFF_ON_PENDING	4   /* elpg is off, caller has requested on, but ALLOW
					       cmd hasn't been sent due to ENABLE_ALLOW delay */

/* Falcon Register index */
#define PMU_FALCON_REG_R0		(0)
#define PMU_FALCON_REG_R1		(1)
#define PMU_FALCON_REG_R2		(2)
#define PMU_FALCON_REG_R3		(3)
#define PMU_FALCON_REG_R4		(4)
#define PMU_FALCON_REG_R5		(5)
#define PMU_FALCON_REG_R6		(6)
#define PMU_FALCON_REG_R7		(7)
#define PMU_FALCON_REG_R8		(8)
#define PMU_FALCON_REG_R9		(9)
#define PMU_FALCON_REG_R10		(10)
#define PMU_FALCON_REG_R11		(11)
#define PMU_FALCON_REG_R12		(12)
#define PMU_FALCON_REG_R13		(13)
#define PMU_FALCON_REG_R14		(14)
#define PMU_FALCON_REG_R15		(15)
#define PMU_FALCON_REG_IV0		(16)
#define PMU_FALCON_REG_IV1		(17)
#define PMU_FALCON_REG_UNDEFINED	(18)
#define PMU_FALCON_REG_EV		(19)
#define PMU_FALCON_REG_SP		(20)
#define PMU_FALCON_REG_PC		(21)
#define PMU_FALCON_REG_IMB		(22)
#define PMU_FALCON_REG_DMB		(23)
#define PMU_FALCON_REG_CSW		(24)
#define PMU_FALCON_REG_CCR		(25)
#define PMU_FALCON_REG_SEC		(26)
#define PMU_FALCON_REG_CTX		(27)
#define PMU_FALCON_REG_EXCI		(28)
#define PMU_FALCON_REG_RSVD0		(29)
#define PMU_FALCON_REG_RSVD1		(30)
#define PMU_FALCON_REG_RSVD2		(31)
#define PMU_FALCON_REG_SIZE		(32)

/* Choices for pmu_state */
#define PMU_STATE_OFF			0 /* PMU is off */
#define PMU_STATE_STARTING		1 /* PMU is on, but not booted */
#define PMU_STATE_INIT_RECEIVED		2 /* PMU init message received */
#define PMU_STATE_ELPG_BOOTING		3 /* PMU is booting */
#define PMU_STATE_ELPG_BOOTED		4 /* ELPG is initialized */
#define PMU_STATE_LOADING_PG_BUF	5 /* Loading PG buf */
#define PMU_STATE_LOADING_ZBC		6 /* Loading ZBC buf */
#define PMU_STATE_STARTED		7 /* Fully unitialized */



struct pmu_gk20a {

	struct pmu_ucode_desc *desc;
	struct mem_desc ucode;

	struct mem_desc pg_buf;
	/* TBD: remove this if ZBC seq is fixed */
	struct mem_desc seq_buf;
	struct mem_desc trace_buf;
	struct mem_desc wpr_buf;
	bool buf_loaded;

	struct pmu_sha1_gid gid_info;

	struct pmu_queue queue[PMU_QUEUE_COUNT];

	struct pmu_sequence *seq;
	unsigned long pmu_seq_tbl[PMU_SEQ_TBL_SIZE];
	u32 next_seq_desc;

	struct pmu_mutex *mutex;
	u32 mutex_cnt;

	struct mutex pmu_copy_lock;
	struct mutex pmu_seq_lock;

	struct gk20a_allocator dmem;

	u32 *ucode_image;
	bool pmu_ready;

	u32 zbc_save_done;

	u32 stat_dmem_offset;

	u32 elpg_stat;

	int pmu_state;

#define PMU_ELPG_ENABLE_ALLOW_DELAY_MSEC	1 /* msec */
	struct work_struct pg_init;
	struct mutex elpg_mutex; /* protect elpg enable/disable */
	int elpg_refcnt; /* disable -1, enable +1, <=0 elpg disabled, > 0 elpg enabled */

	union {
		struct pmu_perfmon_counter_v2 perfmon_counter_v2;
		struct pmu_perfmon_counter_v0 perfmon_counter_v0;
	};
	u32 perfmon_state_id[PMU_DOMAIN_GROUP_NUM];

	bool initialized;

	void (*remove_support)(struct pmu_gk20a *pmu);
	bool sw_ready;
	bool perfmon_ready;

	u32 sample_buffer;
	u32 load_shadow;
	u32 load_avg;

	struct mutex isr_mutex;
	bool isr_enabled;

	bool zbc_ready;
	union {
		struct pmu_cmdline_args_v0 args_v0;
		struct pmu_cmdline_args_v1 args_v1;
		struct pmu_cmdline_args_v2 args_v2;
		struct pmu_cmdline_args_v3 args_v3;
		struct pmu_cmdline_args_v4 args_v4;
	};
	unsigned long perfmon_events_cnt;
	bool perfmon_sampling_enabled;
	u8 pmu_mode; /*Added for GM20b, and ACR*/
	u32 falcon_id;
	u32 aelpg_param[5];
};

int gk20a_init_pmu_support(struct gk20a *g);
int gk20a_init_pmu_bind_fecs(struct gk20a *g);

void gk20a_pmu_isr(struct gk20a *g);

/* send a cmd to pmu */
int gk20a_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, struct pmu_msg *msg,
		struct pmu_payload *payload, u32 queue_id,
		pmu_callback callback, void* cb_param,
		u32 *seq_desc, unsigned long timeout);

int gk20a_pmu_enable_elpg(struct gk20a *g);
int gk20a_pmu_disable_elpg(struct gk20a *g);

void gk20a_pmu_save_zbc(struct gk20a *g, u32 entries);

int gk20a_pmu_perfmon_enable(struct gk20a *g, bool enable);

int pmu_mutex_acquire(struct pmu_gk20a *pmu, u32 id, u32 *token);
int pmu_mutex_release(struct pmu_gk20a *pmu, u32 id, u32 *token);
int gk20a_pmu_destroy(struct gk20a *g);
int gk20a_pmu_load_norm(struct gk20a *g, u32 *load);
int gk20a_pmu_load_update(struct gk20a *g);
int gk20a_pmu_debugfs_init(struct platform_device *dev);
void gk20a_pmu_reset_load_counters(struct gk20a *g);
void gk20a_pmu_get_load_counters(struct gk20a *g, u32 *busy_cycles,
		u32 *total_cycles);
void gk20a_init_pmu_ops(struct gpu_ops *gops);

void pmu_copy_to_dmem(struct pmu_gk20a *pmu,
		u32 dst, u8 *src, u32 size, u8 port);
void pmu_copy_from_dmem(struct pmu_gk20a *pmu,
		u32 src, u8 *dst, u32 size, u8 port);
int pmu_reset(struct pmu_gk20a *pmu);
int pmu_bootstrap(struct pmu_gk20a *pmu);
int gk20a_init_pmu(struct pmu_gk20a *pmu);
void pmu_dump_falcon_stats(struct pmu_gk20a *pmu);
void gk20a_remove_pmu_support(struct pmu_gk20a *pmu);
void pmu_setup_hw(struct work_struct *work);
void pmu_seq_init(struct pmu_gk20a *pmu);

int gk20a_init_pmu(struct pmu_gk20a *pmu);

int gk20a_pmu_ap_send_command(struct gk20a *g,
		union pmu_ap_cmd *p_ap_cmd, bool b_block);
int gk20a_aelpg_init(struct gk20a *g);
int gk20a_aelpg_init_and_enable(struct gk20a *g, u8 ctrl_id);
void pmu_enable_irq(struct pmu_gk20a *pmu, bool enable);
int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout,
				 u32 *var, u32 val);
void pmu_handle_fecs_boot_acr_msg(struct gk20a *g, struct pmu_msg *msg,
				void *param, u32 handle, u32 status);
void gk20a_pmu_elpg_statistics(struct gk20a *g,
		u32 *ingating_time, u32 *ungating_time, u32 *gating_cnt);

#endif /*__PMU_GK20A_H__*/