summaryrefslogblamecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_domain.c
blob: 3b64f51935c66c5172a9418fb20d7631f03cefba (plain) (tree)
1
2
3
4
5
6
7
8
9
  
                                                                     
  





                                                                             
  









                                                                             

   
                       
                        
 


                       

                                     

                          


                                                                             
                                                    

                                         
                                                                        

                                                          

                                                   








                                             
  






                                                   









                                             
  




                                                              
                                                   
                                                        

                                                    
                                                         

                                                   
                                                        

                                                   
                                                        

                                                    
                                                         

                                                    
                                                         

                                                     
                                                          

                                                    
                                                         

                                                    
                                                         

                                                   
                                                        

                                                       
                                                            

                                                 
                                                      

                                                   
                                                        

                                                    
                                                         
         



                             
                                                       






                                                                                        
                       


                                                                               
                            






                                                                               
                                                       


                                                                              
                                                                            
                                            
                                         
                
                                         
         











                                                                             
                                                        







                                                                                   
                               


                                                                      
                                                                        
                               
         


                                                       
                                   


                 
                                        
 
                   


                                                

                                                    

             
                               
 
                                                                               
                     
                            












                                                                                     
                            











                                                                                         
                                                        










                                                                    
                     
                          
         


                                                               
                                      



                                                                             
                                     
                                          
                         





                                                                               
                                     
                                          
                         
                 











                                                                              


         
                                                     


                      
                                         
 
                   

                                                
                               


                                                              
                                          
                               
         


                                                              
                                  


                      















































































































































































































                                                                                                                  
 
                       

                                                                        
                                                                            












                                                       
                               
 


                                                              
                                                                    




                                            
                                                       



                                 

                                                 
         

                                                                 
         
                                    
         

                                                                 
         
                
         


                                 
         
 






                                                                           
                                                                                 

                                                                
                                                                         








                                                                                
                 





                                                                                           
                 

                                                                         
                 










                                                                                                             











                                                                                                                       


                                                                                  








                                                                                                           
                 

                                                                        
                 























                                                                                                                       

                                                                                  





                                                                                                 
                 

                        
                 
                                    
                                                                                
                                               
                                  
                 




                                                          
                                    

                                                                                     
                                               


                                                                            

                                                                                  
                                    
                                                                                
                                               





                                                                       
                                                     


                      


























                                                                                 
                                                              


                                                                         
                               


                       
                                  




                                   

                
 
                               


                       





                                    
                
 
                               


                       
 
                                                      




                                                                   
                       



                                                        
                     
                               
         








                                                           


                                               


                                                 







                                                     
                                                      


                                                                       
                       


                                                           
                               

                                                                          
                          
                              
         









                                                                            
                                                   






                                                                
                       



                                                              
                     
                               
         










                                                                           
                                                        


                                                                   
                       




                                                     
                               




                                                  
                                    
                                         
                 



                      




                                                           
 





                                                        
                               
 
                              
                               
         
 
                                
                               
         





















                                                                            











                                                        
                               
 
                                                     
                               
         
 
                                                 
                               
         












                                                               




























                                                                          
                                                         











                                                        
                                                    


                      




















                                                        
                               
 
                                    
                               
         
 
                                                                  
                               
         

                                                         
                                                             
                               
         




















                                                                          
                        
                                         
                 




                                    
                                                    


                      







































                                                                                       
                                                           


                                                                            
                       
                                                       
                                                                

                                                                    
                               

                                                                        
                          
                              
         


                                                                         
                                                                    

                         

                                                                                 



                                                                  
                                                    
                                                                    



                                                                                 




                                                     

















































                                                                                 
                                                        






                                                                     
                       


                                                                     
                     
                               
         








                                                             


                                                   


                                                     







                                                                     
                                                           





                                                                     

























                                                                                  


                                                                             
                       


                                                                 
                               

                                                                             
                          
                              
         










                                                                           
































                                                                                 
                                                         






                                                                      
                       
 
                                                                                 
                               
         


                                                                          
                            
                               
         



                                                            
                                                        


                                                     


                                                     


                      
                                                          


                                                                     
                       






                                                        
                               

                                                                
                     
                          
         
















                                                                         
                             
                                  
                 

         
                                                    


                      

























                                                                                     
                                                             


                                                                              
                       


                                                                  
                               

                                                                             
                          
                              
         










                                                                             





























                                                                                  
                                                          




                                                                       
                       
 
                                                                             
                               
         


                                                                          
                     
                               
         







                                                               
                                     



                      
                                                      


                                                                 
                               


                 
                                                            


                                                                             
                       


                                                                 
                               

                                                                        
                          
                              
         










                                                                           
                                                         






                                                                      
                       
 
                                                                            
                               
         


                                                                     
                     
                               
         


















                                                                            
                                                           





                                                                         





                                                                          




                                                                          




                                                                         








                                                                         
                     
                            
         
 
                                   



                                                  
                                                        


                                                                         
                       


                                                        
                               

                                                                        
                          
                              
         











                                                                     
                                                                         
 
                       







                                                                         
                                    








                                                                              
/*
 * Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include <nvgpu/bios.h>
#include <nvgpu/gk20a.h>

#include "clk.h"
#include "clk_fll.h"
#include "clk_domain.h"
#include "boardobj/boardobjgrp.h"
#include "boardobj/boardobjgrp_e32.h"
#include "ctrl/ctrlclk.h"
#include "ctrl/ctrlvolt.h"

static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs);

static int devinit_get_clocks_table(struct gk20a *g,
	struct clk_domains *pdomainobjs);

static int clk_domain_pmudatainit_super(struct gk20a *g, struct boardobj
	*board_obj_ptr,	struct nv_pmu_boardobj *ppmudata);

static struct vbios_clocks_table_1x_hal_clock_entry
		vbiosclktbl1xhalentry_gp[] = {
	{ clkwhich_gpc2clk,    true,    1, },
	{ clkwhich_xbar2clk,   true,    1, },
	{ clkwhich_mclk,       false,   1, },
	{ clkwhich_sys2clk,    true,    1, },
	{ clkwhich_hub2clk,    false,   1, },
	{ clkwhich_nvdclk,     false,   1, },
	{ clkwhich_pwrclk,     false,   1, },
	{ clkwhich_dispclk,    false,   1, },
	{ clkwhich_pciegenclk, false,   1, }
};
/*
 * Updated from RM devinit_clock.c
 * GV100 is 0x03 and
 * GP10x is 0x02 in clocks_hal.
 */
static struct vbios_clocks_table_1x_hal_clock_entry
		vbiosclktbl1xhalentry_gv[] = {
	{ clkwhich_gpcclk,     true,    2, },
	{ clkwhich_xbarclk,    true,    1, },
	{ clkwhich_mclk,       false,   1, },
	{ clkwhich_sysclk,     true,    1, },
	{ clkwhich_hubclk,     false,   1, },
	{ clkwhich_nvdclk,     true,    1, },
	{ clkwhich_pwrclk,     false,   1, },
	{ clkwhich_dispclk,    false,   1, },
	{ clkwhich_pciegenclk, false,   1, },
	{ clkwhich_hostclk,    true,    1, }
};

static u32 clktranslatehalmumsettoapinumset(u32 clkhaldomains)
{
	u32   clkapidomains = 0;

	if (clkhaldomains & BIT(clkwhich_gpcclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_GPCCLK;
	}
	if (clkhaldomains & BIT(clkwhich_xbarclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_XBARCLK;
	}
	if (clkhaldomains & BIT(clkwhich_sysclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_SYSCLK;
	}
	if (clkhaldomains & BIT(clkwhich_hubclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_HUBCLK;
	}
	if (clkhaldomains & BIT(clkwhich_hostclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_HOSTCLK;
	}
	if (clkhaldomains & BIT(clkwhich_gpc2clk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_GPC2CLK;
	}
	if (clkhaldomains & BIT(clkwhich_xbar2clk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_XBAR2CLK;
	}
	if (clkhaldomains & BIT(clkwhich_sys2clk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_SYS2CLK;
	}
	if (clkhaldomains & BIT(clkwhich_hub2clk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_HUB2CLK;
	}
	if (clkhaldomains & BIT(clkwhich_pwrclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_PWRCLK;
	}
	if (clkhaldomains & BIT(clkwhich_pciegenclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_PCIEGENCLK;
	}
	if (clkhaldomains & BIT(clkwhich_mclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_MCLK;
	}
	if (clkhaldomains & BIT(clkwhich_nvdclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_NVDCLK;
	}
	if (clkhaldomains & BIT(clkwhich_dispclk)) {
		clkapidomains |= CTRL_CLK_DOMAIN_DISPCLK;
	}

	return clkapidomains;
}

static int _clk_domains_pmudatainit_3x(struct gk20a *g,
				       struct boardobjgrp *pboardobjgrp,
				       struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
{
	struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *pset =
		(struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *)
		pboardobjgrppmu;
	struct clk_domains *pdomains = (struct clk_domains *)pboardobjgrp;
	int status = 0;

	status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
	if (status) {
		nvgpu_err(g,
			  "error updating pmu boardobjgrp for clk domain 0x%x",
			  status);
		goto done;
	}

	pset->vbios_domains = pdomains->vbios_domains;
	pset->cntr_sampling_periodms = pdomains->cntr_sampling_periodms;
	pset->version = CLK_DOMAIN_BOARDOBJGRP_VERSION;
	pset->b_override_o_v_o_c = false;
	pset->b_debug_mode = false;
	pset->b_enforce_vf_monotonicity = pdomains->b_enforce_vf_monotonicity;
	pset->b_enforce_vf_smoothening = pdomains->b_enforce_vf_smoothening;
	if (g->ops.clk.split_rail_support) {
		pset->volt_rails_max = 2;
	} else {
		pset->volt_rails_max = 1;
	}
	status = boardobjgrpmask_export(
				&pdomains->master_domains_mask.super,
				pdomains->master_domains_mask.super.bitcount,
				&pset->master_domains_mask.super);

	memcpy(&pset->deltas, &pdomains->deltas,
		(sizeof(struct ctrl_clk_clk_delta)));

done:
	return status;
}

static int _clk_domains_pmudata_instget(struct gk20a *g,
					struct nv_pmu_boardobjgrp *pmuboardobjgrp,
					struct nv_pmu_boardobj **ppboardobjpmudata,
					u8 idx)
{
	struct nv_pmu_clk_clk_domain_boardobj_grp_set  *pgrp_set =
		(struct nv_pmu_clk_clk_domain_boardobj_grp_set *)
		pmuboardobjgrp;

	nvgpu_log_info(g, " ");

	/*check whether pmuboardobjgrp has a valid boardobj in index*/
	if (((u32)BIT(idx) &
		pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0) {
		return -EINVAL;
	}

	*ppboardobjpmudata = (struct nv_pmu_boardobj *)
		&pgrp_set->objects[idx].data.board_obj;
	nvgpu_log_info(g, " Done");
	return 0;
}

int clk_domain_sw_setup(struct gk20a *g)
{
	int status;
	struct boardobjgrp *pboardobjgrp = NULL;
	struct clk_domains *pclkdomainobjs;
	struct clk_domain *pdomain;
	struct clk_domain_3x_master *pdomain_master;
	struct clk_domain_3x_slave *pdomain_slave;
	u8 i;

	nvgpu_log_info(g, " ");

	status = boardobjgrpconstruct_e32(g, &g->clk_pmu.clk_domainobjs.super);
	if (status) {
		nvgpu_err(g,
			  "error creating boardobjgrp for clk domain, status - 0x%x",
			  status);
		goto done;
	}

	pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
	pclkdomainobjs = &(g->clk_pmu.clk_domainobjs);

	BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_DOMAIN);

	status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
			clk, CLK, clk_domain, CLK_DOMAIN);
	if (status) {
		nvgpu_err(g,
			  "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
			  status);
		goto done;
	}

	pboardobjgrp->pmudatainit  = _clk_domains_pmudatainit_3x;
	pboardobjgrp->pmudatainstget  = _clk_domains_pmudata_instget;

	/* Initialize mask to zero.*/
	boardobjgrpmask_e32_init(&pclkdomainobjs->prog_domains_mask, NULL);
	boardobjgrpmask_e32_init(&pclkdomainobjs->master_domains_mask, NULL);
	pclkdomainobjs->b_enforce_vf_monotonicity = true;
	pclkdomainobjs->b_enforce_vf_smoothening = true;

	memset(&pclkdomainobjs->ordered_noise_aware_list, 0,
		sizeof(pclkdomainobjs->ordered_noise_aware_list));

	memset(&pclkdomainobjs->ordered_noise_unaware_list, 0,
		sizeof(pclkdomainobjs->ordered_noise_unaware_list));

	memset(&pclkdomainobjs->deltas, 0,
		sizeof(struct ctrl_clk_clk_delta));

	status = devinit_get_clocks_table(g, pclkdomainobjs);
	if (status) {
		goto done;
	}

	BOARDOBJGRP_FOR_EACH(&(pclkdomainobjs->super.super),
			     struct clk_domain *, pdomain, i) {
		pdomain_master = NULL;
		if (pdomain->super.implements(g, &pdomain->super,
				CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG)) {
			status = boardobjgrpmask_bitset(
				&pclkdomainobjs->prog_domains_mask.super, i);
			if (status) {
				goto done;
			}
		}

		if (pdomain->super.implements(g, &pdomain->super,
				CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
			status = boardobjgrpmask_bitset(
				&pclkdomainobjs->master_domains_mask.super, i);
			if (status) {
				goto done;
			}
		}

		if (pdomain->super.implements(g, &pdomain->super,
				CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
				pdomain_slave =
					(struct clk_domain_3x_slave *)pdomain;
				pdomain_master =
					(struct clk_domain_3x_master *)
					(CLK_CLK_DOMAIN_GET((&g->clk_pmu),
					pdomain_slave->master_idx));
			pdomain_master->slave_idxs_mask |= BIT(i);
		}

	}

done:
	nvgpu_log_info(g, " done status %x", status);
	return status;
}

int clk_domain_pmu_setup(struct gk20a *g)
{
	int status;
	struct boardobjgrp *pboardobjgrp = NULL;

	nvgpu_log_info(g, " ");

	pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;

	if (!pboardobjgrp->bconstructed) {
		return -EINVAL;
	}

	status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);

	nvgpu_log_info(g, "Done");
	return status;
}

static int devinit_get_clocks_table_35(struct gk20a *g,
				    struct clk_domains *pclkdomainobjs, u8 *clocks_table_ptr)
{
	int status = 0;
	struct vbios_clocks_table_35_header clocks_table_header = { 0 };
	struct vbios_clocks_table_35_entry clocks_table_entry = { 0 };
	struct vbios_clocks_table_1x_hal_clock_entry *vbiosclktbl1xhalentry;
	u8 *clocks_tbl_entry_ptr = NULL;
	u32 index = 0;
	struct clk_domain *pclkdomain_dev;
	union {
		struct boardobj boardobj;
		struct clk_domain clk_domain;
		struct clk_domain_3x v3x;
		struct clk_domain_3x_fixed v3x_fixed;
		struct clk_domain_35_prog v35_prog;
		struct clk_domain_35_master v35_master;
		struct clk_domain_35_slave v35_slave;
	} clk_domain_data;

	nvgpu_log_info(g, " ");

	memcpy(&clocks_table_header, clocks_table_ptr,
			VBIOS_CLOCKS_TABLE_35_HEADER_SIZE_09);
	if (clocks_table_header.header_size <
			(u8) VBIOS_CLOCKS_TABLE_35_HEADER_SIZE_09) {
		status = -EINVAL;
		goto done;
	}

	if (clocks_table_header.entry_size <
			(u8) VBIOS_CLOCKS_TABLE_35_ENTRY_SIZE_11) {
		status = -EINVAL;
		goto done;
	}

	switch (clocks_table_header.clocks_hal) {
	case CLK_TABLE_HAL_ENTRY_GP:
	{
		vbiosclktbl1xhalentry = vbiosclktbl1xhalentry_gp;
		break;
	}
	case CLK_TABLE_HAL_ENTRY_GV:
	{
		vbiosclktbl1xhalentry = vbiosclktbl1xhalentry_gv;
		break;
	}
	default:
	{
		status = -EINVAL;
		goto done;
	}
	}

	pclkdomainobjs->cntr_sampling_periodms =
		(u16)clocks_table_header.cntr_sampling_periodms;

	/* Read table entries*/
	clocks_tbl_entry_ptr = clocks_table_ptr +
			clocks_table_header.header_size;
	for (index = 0; index < clocks_table_header.entry_count; index++) {
		memcpy((void*) &clocks_table_entry, (void*) clocks_tbl_entry_ptr,
				clocks_table_header.entry_size);
		clk_domain_data.clk_domain.domain =
				(u8) vbiosclktbl1xhalentry[index].domain;
		clk_domain_data.clk_domain.api_domain =
				clktranslatehalmumsettoapinumset(
					(u32) BIT(clk_domain_data.clk_domain.domain));
		clk_domain_data.v3x.b_noise_aware_capable =
			vbiosclktbl1xhalentry[index].b_noise_aware_capable;

		switch (BIOS_GET_FIELD(clocks_table_entry.flags0,
				NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE)) {
		case  NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_FIXED:
		{
			clk_domain_data.boardobj.type =
				CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED;
			clk_domain_data.v3x_fixed.freq_mhz = (u16)BIOS_GET_FIELD(
				clocks_table_entry.param1,
				NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ);
			break;
		}

		case  NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASTER:
		{
			clk_domain_data.boardobj.type =
				CTRL_CLK_CLK_DOMAIN_TYPE_35_MASTER;
			clk_domain_data.v35_prog.super.clk_prog_idx_first =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
			clk_domain_data.v35_prog.super.clk_prog_idx_last =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
			clk_domain_data.v35_prog.super.noise_unaware_ordering_index =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
			if (clk_domain_data.v3x.b_noise_aware_capable) {
				clk_domain_data.v35_prog.super.b_force_noise_unaware_ordering =
					(bool)(BIOS_GET_FIELD(clocks_table_entry.param2,
					NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));

			} else {
				clk_domain_data.v35_prog.super.noise_aware_ordering_index =
					CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
				clk_domain_data.v35_prog.super.b_force_noise_unaware_ordering = false;
			}
			clk_domain_data.v35_prog.pre_volt_ordering_index =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
					NV_VBIOS_CLOCKS_TABLE_35_ENTRY_PARAM2_PROG_PRE_VOLT_ORDERING_IDX));

			clk_domain_data.v35_prog.post_volt_ordering_index =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
					NV_VBIOS_CLOCKS_TABLE_35_ENTRY_PARAM2_PROG_POST_VOLT_ORDERING_IDX));

			clk_domain_data.v35_prog.super.factory_delta.data.delta_khz = 0;
			clk_domain_data.v35_prog.super.factory_delta.type = 0;

			clk_domain_data.v35_prog.super.freq_delta_min_mhz =
				(u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
				      NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ));

			clk_domain_data.v35_prog.super.freq_delta_max_mhz =
				(u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
				      NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ));
			clk_domain_data.v35_prog.clk_vf_curve_count =
				vbiosclktbl1xhalentry[index].clk_vf_curve_count;
			break;
		}

		case  NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SLAVE:
		{
			clk_domain_data.boardobj.type =
				CTRL_CLK_CLK_DOMAIN_TYPE_35_SLAVE;
			clk_domain_data.v35_prog.super.clk_prog_idx_first =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
			clk_domain_data.v35_prog.super.clk_prog_idx_last =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
			clk_domain_data.v35_prog.super.noise_unaware_ordering_index =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));

			if (clk_domain_data.v3x.b_noise_aware_capable) {
				clk_domain_data.v35_prog.super.b_force_noise_unaware_ordering =
					(bool)(BIOS_GET_FIELD(clocks_table_entry.param2,
					NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));

			} else {
				clk_domain_data.v35_prog.super.noise_aware_ordering_index =
					CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
				clk_domain_data.v35_prog.super.b_force_noise_unaware_ordering = false;
			}
			clk_domain_data.v35_prog.pre_volt_ordering_index =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
					NV_VBIOS_CLOCKS_TABLE_35_ENTRY_PARAM2_PROG_PRE_VOLT_ORDERING_IDX));

			clk_domain_data.v35_prog.post_volt_ordering_index =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
					NV_VBIOS_CLOCKS_TABLE_35_ENTRY_PARAM2_PROG_POST_VOLT_ORDERING_IDX));

			clk_domain_data.v35_prog.super.factory_delta.data.delta_khz = 0;
			clk_domain_data.v35_prog.super.factory_delta.type = 0;
			clk_domain_data.v35_prog.super.freq_delta_min_mhz = 0;
			clk_domain_data.v35_prog.super.freq_delta_max_mhz = 0;
			clk_domain_data.v35_slave.slave.master_idx =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param1,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN));
			break;
		}

		default:
		{
			nvgpu_err(g,
				  "error reading clock domain entry %d", index);
			status = -EINVAL;
			goto done;
		}

		}
		pclkdomain_dev = construct_clk_domain(g,
				(void *)&clk_domain_data);
		if (pclkdomain_dev == NULL) {
			nvgpu_err(g,
				  "unable to construct clock domain boardobj for %d",
				  index);
			status = -EINVAL;
			goto done;
		}
		status = boardobjgrp_objinsert(
				&pclkdomainobjs->super.super,
				(struct boardobj *)(void*) pclkdomain_dev, index);
		if (status != 0UL) {
			nvgpu_err(g,
			"unable to insert clock domain boardobj for %d", index);
			status = (u32) -EINVAL;
			goto done;
		}
		clocks_tbl_entry_ptr += clocks_table_header.entry_size;
	}

done:
	nvgpu_log_info(g, " done status %x", status);
	return status;
}

static int devinit_get_clocks_table_1x(struct gk20a *g,
				    struct clk_domains *pclkdomainobjs, u8 *clocks_table_ptr)
{
	int status = 0;
	struct vbios_clocks_table_1x_header clocks_table_header = { 0 };
	struct vbios_clocks_table_1x_entry clocks_table_entry = { 0 };
	struct vbios_clocks_table_1x_hal_clock_entry *vbiosclktbl1xhalentry;
	u8 *clocks_tbl_entry_ptr = NULL;
	u32 index = 0;
	struct clk_domain *pclkdomain_dev;
	union {
		struct boardobj boardobj;
		struct clk_domain clk_domain;
		struct clk_domain_3x v3x;
		struct clk_domain_3x_fixed v3x_fixed;
		struct clk_domain_3x_prog v3x_prog;
		struct clk_domain_3x_master v3x_master;
		struct clk_domain_3x_slave v3x_slave;
	} clk_domain_data;

	nvgpu_log_info(g, " ");

	memcpy(&clocks_table_header, clocks_table_ptr,
			VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
	if (clocks_table_header.header_size <
			(u8) VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) {
		status = -EINVAL;
		goto done;
	}

	if (clocks_table_header.entry_size <
	    (u8) VBIOS_CLOCKS_TABLE_1X_ENTRY_SIZE_09) {
		status = -EINVAL;
		goto done;
	}

	switch (clocks_table_header.clocks_hal) {
	case CLK_TABLE_HAL_ENTRY_GP:
	{
		vbiosclktbl1xhalentry = vbiosclktbl1xhalentry_gp;
		break;
	}
	case CLK_TABLE_HAL_ENTRY_GV:
	{
		vbiosclktbl1xhalentry = vbiosclktbl1xhalentry_gv;
		break;
	}
	default:
	{
		status = -EINVAL;
		goto done;
	}
	}

	pclkdomainobjs->cntr_sampling_periodms =
		(u16)clocks_table_header.cntr_sampling_periodms;

	/* Read table entries*/
	clocks_tbl_entry_ptr = clocks_table_ptr +
		VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07;
	for (index = 0; index < clocks_table_header.entry_count; index++) {
		memcpy((void*) &clocks_table_entry, (void*) clocks_tbl_entry_ptr,
				clocks_table_header.entry_size);
		clk_domain_data.clk_domain.domain =
				(u8) vbiosclktbl1xhalentry[index].domain;
		clk_domain_data.clk_domain.api_domain =
				clktranslatehalmumsettoapinumset(
					BIT(clk_domain_data.clk_domain.domain));
		clk_domain_data.v3x.b_noise_aware_capable =
			vbiosclktbl1xhalentry[index].b_noise_aware_capable;

		switch (BIOS_GET_FIELD(clocks_table_entry.flags0,
				NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE)) {
		case  NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_FIXED:
		{
			clk_domain_data.boardobj.type =
				CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED;
			clk_domain_data.v3x_fixed.freq_mhz = (u16)BIOS_GET_FIELD(
				clocks_table_entry.param1,
				NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ);
			break;
		}

		case  NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASTER:
		{
			clk_domain_data.boardobj.type =
				CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER;
			clk_domain_data.v3x_prog.clk_prog_idx_first =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
			clk_domain_data.v3x_prog.clk_prog_idx_last =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
			clk_domain_data.v3x_prog.noise_unaware_ordering_index =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
			if (clk_domain_data.v3x.b_noise_aware_capable) {
				clk_domain_data.v3x_prog.noise_aware_ordering_index =
					(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
					     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
				clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
					(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
					     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
			} else {
				clk_domain_data.v3x_prog.noise_aware_ordering_index =
					CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
				clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
			}

			clk_domain_data.v3x_prog.factory_delta.data.delta_khz = 0;
			clk_domain_data.v3x_prog.factory_delta.type = 0;

			clk_domain_data.v3x_prog.freq_delta_min_mhz =
				(u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
				      NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ));

			clk_domain_data.v3x_prog.freq_delta_max_mhz =
				(u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
				      NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ));
			break;
		}

		case  NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SLAVE:
		{
			clk_domain_data.boardobj.type =
				CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE;
			clk_domain_data.v3x_prog.clk_prog_idx_first =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
			clk_domain_data.v3x_prog.clk_prog_idx_last =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
			clk_domain_data.v3x_prog.noise_unaware_ordering_index =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));

			if (clk_domain_data.v3x.b_noise_aware_capable) {
				clk_domain_data.v3x_prog.noise_aware_ordering_index =
					(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
					     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
				clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
					(u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
					     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
			} else {
				clk_domain_data.v3x_prog.noise_aware_ordering_index =
					CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
				clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
			}
			clk_domain_data.v3x_prog.factory_delta.data.delta_khz = 0;
			clk_domain_data.v3x_prog.factory_delta.type = 0;
			clk_domain_data.v3x_prog.freq_delta_min_mhz = 0;
			clk_domain_data.v3x_prog.freq_delta_max_mhz = 0;
			clk_domain_data.v3x_slave.master_idx =
				(u8)(BIOS_GET_FIELD(clocks_table_entry.param1,
				     NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN));
			break;
		}

		default:
		{
			nvgpu_err(g,
				  "error reading clock domain entry %d", index);
			status = (u32) -EINVAL;
			goto done;
		}

		}
		pclkdomain_dev = construct_clk_domain(g,
				(void *)&clk_domain_data);
		if (pclkdomain_dev == NULL) {
			nvgpu_err(g,
				  "unable to construct clock domain boardobj for %d",
				  index);
			status = (u32) -EINVAL;
			goto done;
		}
		status = boardobjgrp_objinsert(&pclkdomainobjs->super.super,
				(struct boardobj *)(void *)pclkdomain_dev, index);
		if (status != 0UL) {
			nvgpu_err(g,
			"unable to insert clock domain boardobj for %d", index);
			status = (u32) -EINVAL;
			goto done;
		}
		clocks_tbl_entry_ptr += clocks_table_header.entry_size;
	}

done:
	nvgpu_log_info(g, " done status %x", status);
	return status;
}

static int devinit_get_clocks_table(struct gk20a *g,
	    struct clk_domains *pclkdomainobjs)
{
	int status = 0;
	u8 *clocks_table_ptr = NULL;
	struct vbios_clocks_table_1x_header clocks_table_header = { 0 };
	nvgpu_log_info(g, " ");

	clocks_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
			g->bios.clock_token, CLOCKS_TABLE);
	if (clocks_table_ptr == NULL) {
		status = -EINVAL;
		goto done;
	}
	memcpy(&clocks_table_header, clocks_table_ptr,
			VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
	if (clocks_table_header.version == 0x35U) {
		devinit_get_clocks_table_35(g, pclkdomainobjs, clocks_table_ptr);
	}
	else {
		devinit_get_clocks_table_1x(g, pclkdomainobjs, clocks_table_ptr);
	}
	done:
	return status;

}

static int clkdomainclkproglink_not_supported(struct gk20a *g,
					      struct clk_pmupstate *pclk,
					      struct clk_domain *pdomain)
{
	nvgpu_log_info(g, " ");
	return -EINVAL;
}

static int clkdomainvfsearch_stub(
	struct gk20a *g,
	struct clk_pmupstate *pclk,
	struct clk_domain *pdomain,
	u16 *clkmhz,
	u32 *voltuv,
	u8 rail)

{
	nvgpu_log_info(g, " ");
	return -EINVAL;
}

static u32 clkdomaingetfpoints_stub(
	struct gk20a *g,
	struct clk_pmupstate *pclk,
	struct clk_domain *pdomain,
	u32 *pfpointscount,
	u16 *pfreqpointsinmhz,
	u8 rail)
{
	nvgpu_log_info(g, " ");
	return -EINVAL;
}


static int clk_domain_construct_super(struct gk20a *g,
				      struct boardobj **ppboardobj,
				      u16 size, void *pargs)
{
	struct clk_domain *pdomain;
	struct clk_domain *ptmpdomain = (struct clk_domain *)pargs;
	int status = 0;

	status = boardobj_construct_super(g, ppboardobj,
		size, pargs);

	if (status) {
		return -EINVAL;
	}

	pdomain = (struct clk_domain *)*ppboardobj;

	pdomain->super.pmudatainit =
			clk_domain_pmudatainit_super;

	pdomain->clkdomainclkproglink =
			clkdomainclkproglink_not_supported;

	pdomain->clkdomainclkvfsearch =
			clkdomainvfsearch_stub;

	pdomain->clkdomainclkgetfpoints =
			clkdomaingetfpoints_stub;

	pdomain->api_domain = ptmpdomain->api_domain;
	pdomain->domain = ptmpdomain->domain;
	pdomain->perf_domain_grp_idx =
		ptmpdomain->perf_domain_grp_idx;

	return status;
}

static int _clk_domain_pmudatainit_3x(struct gk20a *g,
				      struct boardobj *board_obj_ptr,
				      struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain_3x *pclk_domain_3x;
	struct nv_pmu_clk_clk_domain_3x_boardobj_set *pset;

	nvgpu_log_info(g, " ");

	status = clk_domain_pmudatainit_super(g, board_obj_ptr, ppmudata);
	if (status != 0) {
		return status;
	}

	pclk_domain_3x = (struct clk_domain_3x *)board_obj_ptr;

	pset = (struct nv_pmu_clk_clk_domain_3x_boardobj_set *)ppmudata;

	pset->b_noise_aware_capable = pclk_domain_3x->b_noise_aware_capable;

	return status;
}

static int clk_domain_construct_3x(struct gk20a *g,
				   struct boardobj **ppboardobj,
				   u16 size, void *pargs)
{
	struct boardobj *ptmpobj = (struct boardobj *)pargs;
	struct clk_domain_3x *pdomain;
	struct clk_domain_3x *ptmpdomain =
			(struct clk_domain_3x *)pargs;
	int status = 0;

	ptmpobj->type_mask = BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X);
	status = clk_domain_construct_super(g, ppboardobj,
					size, pargs);
	if (status) {
		return -EINVAL;
	}

	pdomain = (struct clk_domain_3x *)*ppboardobj;

	pdomain->super.super.pmudatainit =
			_clk_domain_pmudatainit_3x;

	pdomain->b_noise_aware_capable = ptmpdomain->b_noise_aware_capable;

	return status;
}

static int clkdomainclkproglink_3x_prog(struct gk20a *g,
					struct clk_pmupstate *pclk,
					struct clk_domain *pdomain)
{
	int status = 0;
	struct clk_domain_3x_prog *p3xprog =
		(struct clk_domain_3x_prog *)pdomain;
	struct clk_prog *pprog = NULL;
	u8 i;

	nvgpu_log_info(g, " ");

	for (i = p3xprog->clk_prog_idx_first;
	     i <= p3xprog->clk_prog_idx_last;
	     i++) {
		pprog = CLK_CLK_PROG_GET(pclk, i);
		if (pprog == NULL) {
			status = -EINVAL;
		}
	}
	return status;
}

static int clkdomaingetslaveclk(struct gk20a *g,
				struct clk_pmupstate *pclk,
				struct clk_domain *pdomain,
				u16 *pclkmhz,
				u16 masterclkmhz)
{
	int status = 0;
	struct clk_prog *pprog = NULL;
	struct clk_prog_1x_master *pprog1xmaster = NULL;
	u8 slaveidx;
	struct clk_domain_3x_master *p3xmaster;

	nvgpu_log_info(g, " ");

	if (pclkmhz == NULL) {
		return -EINVAL;
	}

	if (masterclkmhz == 0) {
		return -EINVAL;
	}

	slaveidx = BOARDOBJ_GET_IDX(pdomain);
	p3xmaster = (struct clk_domain_3x_master *)
			CLK_CLK_DOMAIN_GET(pclk,
			((struct clk_domain_3x_slave *)
				pdomain)->master_idx);
	pprog = CLK_CLK_PROG_GET(pclk, p3xmaster->super.clk_prog_idx_first);
	pprog1xmaster = (struct clk_prog_1x_master *)pprog;

	status = pprog1xmaster->getslaveclk(g, pclk, pprog1xmaster,
			slaveidx, pclkmhz, masterclkmhz);
	return status;
}

static int clkdomainvfsearch(struct gk20a *g,
				struct clk_pmupstate *pclk,
				struct clk_domain *pdomain,
				u16 *pclkmhz,
				u32 *pvoltuv,
				u8 rail)
{
	int status = 0;
	struct clk_domain_3x_master *p3xmaster  =
		(struct clk_domain_3x_master *)pdomain;
	struct clk_prog *pprog = NULL;
	struct clk_prog_1x_master *pprog1xmaster = NULL;
	u8 i;
	u8 *pslaveidx = NULL;
	u8 slaveidx;
	u16 clkmhz;
	u32 voltuv;
	u16 bestclkmhz;
	u32 bestvoltuv;

	nvgpu_log_info(g, " ");

	if ((pclkmhz == NULL) || (pvoltuv == NULL)) {
		return -EINVAL;
	}

	if ((*pclkmhz != 0) && (*pvoltuv != 0)) {
		return -EINVAL;
	}

	bestclkmhz = *pclkmhz;
	bestvoltuv = *pvoltuv;

	if (pdomain->super.implements(g, &pdomain->super,
			CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
		slaveidx = BOARDOBJ_GET_IDX(pdomain);
		pslaveidx = &slaveidx;
		p3xmaster = (struct clk_domain_3x_master *)
				CLK_CLK_DOMAIN_GET(pclk,
				((struct clk_domain_3x_slave *)
					pdomain)->master_idx);
	}
	/* Iterate over the set of CLK_PROGs pointed at by this domain.*/
	for (i = p3xmaster->super.clk_prog_idx_first;
	     i <= p3xmaster->super.clk_prog_idx_last;
	     i++) {
		clkmhz = *pclkmhz;
		voltuv = *pvoltuv;
		pprog = CLK_CLK_PROG_GET(pclk, i);

		/* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
		if (!pprog->super.implements(g, &pprog->super,
				CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
			status = -EINVAL;
			goto done;
		}

		pprog1xmaster = (struct clk_prog_1x_master *)pprog;
		status = pprog1xmaster->vflookup(g, pclk, pprog1xmaster,
				pslaveidx, &clkmhz, &voltuv, rail);
		/* if look up has found the V or F value matching to other
		 exit */
		if (status == 0) {
			if (*pclkmhz == 0) {
				bestclkmhz = clkmhz;
			} else {
				bestvoltuv = voltuv;
				break;
			}
		}
	}
	/* clk and volt sent as zero to print vf table */
	if ((*pclkmhz == 0) && (*pvoltuv == 0)) {
		status = 0;
		goto done;
	}
	/* atleast one search found a matching value? */
	if ((bestvoltuv != 0) && (bestclkmhz != 0)) {
		*pclkmhz = bestclkmhz;
		*pvoltuv = bestvoltuv;
		status = 0;
		goto done;
	}
done:
	nvgpu_log_info(g, "done status %x", status);
	return status;
}

static u32 clkdomaingetfpoints
(
	struct gk20a *g,
	struct clk_pmupstate *pclk,
	struct clk_domain *pdomain,
	u32 *pfpointscount,
	u16 *pfreqpointsinmhz,
	u8 rail
)
{
	u32 status = 0;
	struct clk_domain_3x_master *p3xmaster  =
		(struct clk_domain_3x_master *)pdomain;
	struct clk_prog *pprog = NULL;
	struct clk_prog_1x_master *pprog1xmaster = NULL;
	u32 fpointscount = 0;
	u32 remainingcount;
	u32 totalcount;
	u16 *freqpointsdata;
	u8 i;

	nvgpu_log_info(g, " ");

	if (pfpointscount == NULL) {
		return -EINVAL;
	}

	if ((pfreqpointsinmhz == NULL) && (*pfpointscount != 0)) {
		return -EINVAL;
	}

	if (pdomain->super.implements(g, &pdomain->super,
			CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
		return -EINVAL;
	}

	freqpointsdata = pfreqpointsinmhz;
	totalcount = 0;
	fpointscount = *pfpointscount;
	remainingcount = fpointscount;
	/* Iterate over the set of CLK_PROGs pointed at by this domain.*/
	for (i = p3xmaster->super.clk_prog_idx_first;
	     i <= p3xmaster->super.clk_prog_idx_last;
	     i++) {
		pprog = CLK_CLK_PROG_GET(pclk, i);
		pprog1xmaster = (struct clk_prog_1x_master *)pprog;
		status = pprog1xmaster->getfpoints(g, pclk, pprog1xmaster,
				&fpointscount, &freqpointsdata, rail);
		if (status) {
			*pfpointscount = 0;
			goto done;
		}
		totalcount += fpointscount;
		if (*pfpointscount) {
			remainingcount -= fpointscount;
			fpointscount = remainingcount;
		} else {
			fpointscount = 0;
		}

	}

	*pfpointscount = totalcount;
done:
	nvgpu_log_info(g, "done status %x", status);
	return status;
}

static int clk_domain_pmudatainit_35_prog(struct gk20a *g,
					   struct boardobj *board_obj_ptr,
					   struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain_35_prog *pclk_domain_35_prog;
	struct clk_domain_3x_prog *pclk_domain_3x_prog;
	struct nv_pmu_clk_clk_domain_35_prog_boardobj_set *pset;
	struct clk_domains *pdomains = &(g->clk_pmu.clk_domainobjs);

	nvgpu_log_info(g, " ");

	status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
	if (status != 0UL) {
		return status;
	}

	pclk_domain_35_prog = (struct clk_domain_35_prog *)(void*)board_obj_ptr;
	pclk_domain_3x_prog = &pclk_domain_35_prog->super;

	pset = (struct nv_pmu_clk_clk_domain_35_prog_boardobj_set *)
		(void*) ppmudata;

	pset->super.clk_prog_idx_first = pclk_domain_3x_prog->clk_prog_idx_first;
	pset->super.clk_prog_idx_last = pclk_domain_3x_prog->clk_prog_idx_last;
	pset->super.b_force_noise_unaware_ordering =
		pclk_domain_3x_prog->b_force_noise_unaware_ordering;
	pset->super.factory_delta = pclk_domain_3x_prog->factory_delta;
	pset->super.freq_delta_min_mhz = pclk_domain_3x_prog->freq_delta_min_mhz;
	pset->super.freq_delta_max_mhz = pclk_domain_3x_prog->freq_delta_max_mhz;
	memcpy(&pset->super.deltas, &pdomains->deltas,
		(sizeof(struct ctrl_clk_clk_delta)));
	pset->pre_volt_ordering_index = pclk_domain_35_prog->pre_volt_ordering_index;
	pset->post_volt_ordering_index = pclk_domain_35_prog->post_volt_ordering_index;
	pset->clk_pos = pclk_domain_35_prog->clk_pos;
	pset->clk_vf_curve_count = pclk_domain_35_prog->clk_vf_curve_count;

	return status;
}

static int _clk_domain_pmudatainit_3x_prog(struct gk20a *g,
					   struct boardobj *board_obj_ptr,
					   struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain_3x_prog *pclk_domain_3x_prog;
	struct nv_pmu_clk_clk_domain_30_prog_boardobj_set *pset;
	struct clk_domains *pdomains = &(g->clk_pmu.clk_domainobjs);

	nvgpu_log_info(g, " ");

	status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
	if (status != 0) {
		return status;
	}

	pclk_domain_3x_prog = (struct clk_domain_3x_prog *)board_obj_ptr;

	pset = (struct nv_pmu_clk_clk_domain_30_prog_boardobj_set *)
		ppmudata;

	pset->super.clk_prog_idx_first = pclk_domain_3x_prog->clk_prog_idx_first;
	pset->super.clk_prog_idx_last = pclk_domain_3x_prog->clk_prog_idx_last;
	pset->noise_unaware_ordering_index =
		pclk_domain_3x_prog->noise_unaware_ordering_index;
	pset->noise_aware_ordering_index =
		pclk_domain_3x_prog->noise_aware_ordering_index;
	pset->super.b_force_noise_unaware_ordering =
		pclk_domain_3x_prog->b_force_noise_unaware_ordering;
	pset->super.factory_delta = pclk_domain_3x_prog->factory_delta;
	pset->super.freq_delta_min_mhz = pclk_domain_3x_prog->freq_delta_min_mhz;
	pset->super.freq_delta_max_mhz = pclk_domain_3x_prog->freq_delta_max_mhz;
	memcpy(&pset->super.deltas, &pdomains->deltas,
		(sizeof(struct ctrl_clk_clk_delta)));

	return status;
}

static int clk_domain_construct_35_prog(struct gk20a *g,
					struct boardobj **ppboardobj,
					u16 size, void *pargs)
{
	struct boardobj *ptmpobj = (struct boardobj *)pargs;
	struct clk_domain_35_prog *pdomain;
	struct clk_domain_35_prog *ptmpdomain =
			(struct clk_domain_35_prog *)pargs;
	int status = 0;

	ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG);
	status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
	if (status != 0UL)
	{
		return (u32) -EINVAL;
	}

	pdomain = (struct clk_domain_35_prog *)(void*) *ppboardobj;

	pdomain->super.super.super.super.pmudatainit =
				clk_domain_pmudatainit_35_prog;

	pdomain->super.super.super.clkdomainclkproglink =
				clkdomainclkproglink_3x_prog;

	pdomain->super.super.super.clkdomainclkvfsearch =
				clkdomainvfsearch;

	pdomain->super.super.super.clkdomainclkgetfpoints =
				clkdomaingetfpoints;

	pdomain->super.clk_prog_idx_first = ptmpdomain->super.clk_prog_idx_first;
	pdomain->super.clk_prog_idx_last = ptmpdomain->super.clk_prog_idx_last;
	pdomain->super.noise_unaware_ordering_index =
		ptmpdomain->super.noise_unaware_ordering_index;
	pdomain->super.noise_aware_ordering_index =
		ptmpdomain->super.noise_aware_ordering_index;
	pdomain->super.b_force_noise_unaware_ordering =
		ptmpdomain->super.b_force_noise_unaware_ordering;
	pdomain->super.factory_delta = ptmpdomain->super.factory_delta;
	pdomain->super.freq_delta_min_mhz = ptmpdomain->super.freq_delta_min_mhz;
	pdomain->super.freq_delta_max_mhz = ptmpdomain->super.freq_delta_max_mhz;
	pdomain->pre_volt_ordering_index = ptmpdomain->pre_volt_ordering_index;
	pdomain->post_volt_ordering_index = ptmpdomain->post_volt_ordering_index;
	pdomain->clk_pos = ptmpdomain->clk_pos;
	pdomain->clk_vf_curve_count = ptmpdomain->clk_vf_curve_count;

	return status;
}

static int clk_domain_construct_3x_prog(struct gk20a *g,
					struct boardobj **ppboardobj,
					u16 size, void *pargs)
{
	struct boardobj *ptmpobj = (struct boardobj *)pargs;
	struct clk_domain_3x_prog *pdomain;
	struct clk_domain_3x_prog *ptmpdomain =
			(struct clk_domain_3x_prog *)pargs;
	int status = 0;

	ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG);
	status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
	if (status) {
		return -EINVAL;
	}

	pdomain = (struct clk_domain_3x_prog *)*ppboardobj;

	pdomain->super.super.super.pmudatainit =
			_clk_domain_pmudatainit_3x_prog;

	pdomain->super.super.clkdomainclkproglink =
				clkdomainclkproglink_3x_prog;

	pdomain->super.super.clkdomainclkvfsearch =
				clkdomainvfsearch;

	pdomain->super.super.clkdomainclkgetfpoints =
				clkdomaingetfpoints;

	pdomain->clk_prog_idx_first = ptmpdomain->clk_prog_idx_first;
	pdomain->clk_prog_idx_last = ptmpdomain->clk_prog_idx_last;
	pdomain->noise_unaware_ordering_index =
		ptmpdomain->noise_unaware_ordering_index;
	pdomain->noise_aware_ordering_index =
		ptmpdomain->noise_aware_ordering_index;
	pdomain->b_force_noise_unaware_ordering =
		ptmpdomain->b_force_noise_unaware_ordering;
	pdomain->factory_delta = ptmpdomain->factory_delta;
	pdomain->freq_delta_min_mhz = ptmpdomain->freq_delta_min_mhz;
	pdomain->freq_delta_max_mhz = ptmpdomain->freq_delta_max_mhz;

	return status;
}

static int _clk_domain_pmudatainit_35_slave(struct gk20a *g,
					    struct boardobj *board_obj_ptr,
					    struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain_35_slave *pclk_domain_35_slave;
	struct nv_pmu_clk_clk_domain_35_slave_boardobj_set *pset;

	nvgpu_log_info(g, " ");

	status = clk_domain_pmudatainit_35_prog(g, board_obj_ptr, ppmudata);
	if (status != 0UL) {
		return status;
	}

	pclk_domain_35_slave = (struct clk_domain_35_slave *)(void*)board_obj_ptr;

	pset = (struct nv_pmu_clk_clk_domain_35_slave_boardobj_set *)
		(void*) ppmudata;

	pset->slave.master_idx = pclk_domain_35_slave->slave.master_idx;

	return status;
}

static int clk_domain_pmudatainit_3x_slave(struct gk20a *g,
					    struct boardobj *board_obj_ptr,
					    struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain_3x_slave *pclk_domain_3x_slave;
	struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *pset;

	nvgpu_log_info(g, " ");

	status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
	if (status != 0) {
		return status;
	}

	pclk_domain_3x_slave = (struct clk_domain_3x_slave *)board_obj_ptr;

	pset = (struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *)
		ppmudata;

	pset->master_idx = pclk_domain_3x_slave->master_idx;

	return status;
}

static int clk_domain_construct_35_slave(struct gk20a *g,
					 struct boardobj **ppboardobj,
					 u16 size, void *pargs)
{
	struct boardobj *ptmpobj = (struct boardobj *)pargs;
	struct clk_domain_35_slave *pdomain;
	struct clk_domain_35_slave *ptmpdomain =
			(struct clk_domain_35_slave *)pargs;
	int status = 0;

	if (BOARDOBJ_GET_TYPE(pargs) != (u8) CTRL_CLK_CLK_DOMAIN_TYPE_35_SLAVE) {
		return (u32) -EINVAL;
	}

	ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_35_SLAVE);
	status = clk_domain_construct_35_prog(g, ppboardobj, size, pargs);
	if (status != 0UL) {
		return (u32) -EINVAL;
	}

	pdomain = (struct clk_domain_35_slave *)(void*)*ppboardobj;

	pdomain->super.super.super.super.super.pmudatainit =
			_clk_domain_pmudatainit_35_slave;

	pdomain->slave.master_idx = ptmpdomain->slave.master_idx;

	pdomain->slave.clkdomainclkgetslaveclk =
				clkdomaingetslaveclk;

	return status;
}

static int clk_domain_construct_3x_slave(struct gk20a *g,
					 struct boardobj **ppboardobj,
					 u16 size, void *pargs)
{
	struct boardobj *ptmpobj = (struct boardobj *)pargs;
	struct clk_domain_3x_slave *pdomain;
	struct clk_domain_3x_slave *ptmpdomain =
			(struct clk_domain_3x_slave *)pargs;
	int status = 0;

	if (BOARDOBJ_GET_TYPE(pargs) != (u8) CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE) {
		return -EINVAL;
	}

	ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE);
	status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
	if (status != 0UL) {
		return -EINVAL;
	}

	pdomain = (struct clk_domain_3x_slave *)*ppboardobj;

	pdomain->super.super.super.super.pmudatainit =
			clk_domain_pmudatainit_3x_slave;

	pdomain->master_idx = ptmpdomain->master_idx;

	pdomain->clkdomainclkgetslaveclk =
				clkdomaingetslaveclk;

	return status;
}

static int clkdomainclkproglink_3x_master(struct gk20a *g,
					  struct clk_pmupstate *pclk,
					  struct clk_domain *pdomain)
{
	int status = 0;
	struct clk_domain_3x_master *p3xmaster  =
		(struct clk_domain_3x_master *)pdomain;
	struct clk_prog *pprog = NULL;
	struct clk_prog_1x_master *pprog1xmaster = NULL;
	u16 freq_max_last_mhz = 0;
	u8 i;

	nvgpu_log_info(g, " ");

	status = clkdomainclkproglink_3x_prog(g, pclk, pdomain);
	if (status) {
		goto done;
	}

	/* Iterate over the set of CLK_PROGs pointed at by this domain.*/
	for (i = p3xmaster->super.clk_prog_idx_first;
	     i <= p3xmaster->super.clk_prog_idx_last;
	     i++) {
		pprog = CLK_CLK_PROG_GET(pclk, i);

		/* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
		if (!pprog->super.implements(g, &pprog->super,
				CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
			status = -EINVAL;
			goto done;
		}

		pprog1xmaster = (struct clk_prog_1x_master *)pprog;
		status = pprog1xmaster->vfflatten(g, pclk, pprog1xmaster,
			BOARDOBJ_GET_IDX(p3xmaster), &freq_max_last_mhz);
		if (status) {
			goto done;
		}
	}
done:
	nvgpu_log_info(g, "done status %x", status);
	return status;
}

static int clk_domain_pmudatainit_35_master(struct gk20a *g,
					     struct boardobj *board_obj_ptr,
					     struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain_35_master *pclk_domain_35_master;
	struct nv_pmu_clk_clk_domain_35_master_boardobj_set *pset;

	nvgpu_log_info(g, " ");

	status = clk_domain_pmudatainit_35_prog(g, board_obj_ptr, ppmudata);
	if (status != 0UL) {
		return status;
	}

	pclk_domain_35_master = (struct clk_domain_35_master *)
		(void*) board_obj_ptr;

	pset = (struct nv_pmu_clk_clk_domain_35_master_boardobj_set *)
		(void*) ppmudata;

	pset->master.slave_idxs_mask = pclk_domain_35_master->master.slave_idxs_mask;

	return status;
}

static int _clk_domain_pmudatainit_3x_master(struct gk20a *g,
					     struct boardobj *board_obj_ptr,
					     struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain_3x_master *pclk_domain_3x_master;
	struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *pset;

	nvgpu_log_info(g, " ");

	status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
	if (status != 0) {
		return status;
	}

	pclk_domain_3x_master = (struct clk_domain_3x_master *)board_obj_ptr;

	pset = (struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *)
		ppmudata;

	pset->slave_idxs_mask = pclk_domain_3x_master->slave_idxs_mask;

	return status;
}

static int clk_domain_construct_35_master(struct gk20a *g,
					  struct boardobj **ppboardobj,
					  u16 size, void *pargs)
{
	struct boardobj *ptmpobj = (struct boardobj *)pargs;
	struct clk_domain_35_master *pdomain;
	int status = 0;

	if (BOARDOBJ_GET_TYPE(pargs) != (u8) CTRL_CLK_CLK_DOMAIN_TYPE_35_MASTER) {
		return -EINVAL;
	}

	ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_35_MASTER);
	status = clk_domain_construct_35_prog(g, ppboardobj, size, pargs);
	if (status != 0UL) {
		return (u32) -EINVAL;
	}

	pdomain = (struct clk_domain_35_master *)(void*) *ppboardobj;

	pdomain->super.super.super.super.super.pmudatainit =
			clk_domain_pmudatainit_35_master;
	pdomain->super.super.super.super.clkdomainclkproglink =
				clkdomainclkproglink_3x_master;

	pdomain->master.slave_idxs_mask = 0;

	return status;
}

static int clk_domain_construct_3x_master(struct gk20a *g,
					  struct boardobj **ppboardobj,
					  u16 size, void *pargs)
{
	struct boardobj *ptmpobj = (struct boardobj *)pargs;
	struct clk_domain_3x_master *pdomain;
	int status = 0;

	if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER) {
		return -EINVAL;
	}

	ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER);
	status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
	if (status) {
		return -EINVAL;
	}

	pdomain = (struct clk_domain_3x_master *)*ppboardobj;

	pdomain->super.super.super.super.pmudatainit =
			_clk_domain_pmudatainit_3x_master;
	pdomain->super.super.super.clkdomainclkproglink =
				clkdomainclkproglink_3x_master;

	pdomain->slave_idxs_mask = 0;

	return status;
}

static int clkdomainclkproglink_fixed(struct gk20a *g,
				      struct clk_pmupstate *pclk,
				      struct clk_domain *pdomain)
{
	nvgpu_log_info(g, " ");
	return 0;
}

static int _clk_domain_pmudatainit_3x_fixed(struct gk20a *g,
					    struct boardobj *board_obj_ptr,
					    struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain_3x_fixed *pclk_domain_3x_fixed;
	struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *pset;

	nvgpu_log_info(g, " ");

	status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
	if (status != 0) {
		return status;
	}

	pclk_domain_3x_fixed = (struct clk_domain_3x_fixed *)board_obj_ptr;

	pset = (struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *)
		ppmudata;

	pset->freq_mhz = pclk_domain_3x_fixed->freq_mhz;

	return status;
}

static int clk_domain_construct_3x_fixed(struct gk20a *g,
					 struct boardobj **ppboardobj,
					 u16 size, void *pargs)
{
	struct boardobj *ptmpobj = (struct boardobj *)pargs;
	struct clk_domain_3x_fixed *pdomain;
	struct clk_domain_3x_fixed *ptmpdomain =
			(struct clk_domain_3x_fixed *)pargs;
	int status = 0;

	if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED) {
		return -EINVAL;
	}

	ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED);
	status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
	if (status) {
		return -EINVAL;
	}

	pdomain = (struct clk_domain_3x_fixed *)*ppboardobj;

	pdomain->super.super.super.pmudatainit =
			_clk_domain_pmudatainit_3x_fixed;

	pdomain->super.super.clkdomainclkproglink =
			clkdomainclkproglink_fixed;

	pdomain->freq_mhz = ptmpdomain->freq_mhz;

	return status;
}

static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs)
{
	struct boardobj *board_obj_ptr = NULL;
	u32 status;

	nvgpu_log_info(g, " %d", BOARDOBJ_GET_TYPE(pargs));
	switch (BOARDOBJ_GET_TYPE(pargs)) {
	case CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED:
		status = clk_domain_construct_3x_fixed(g, &board_obj_ptr,
			sizeof(struct clk_domain_3x_fixed), pargs);
		break;

	case CTRL_CLK_CLK_DOMAIN_TYPE_35_MASTER:
		status = clk_domain_construct_35_master(g, &board_obj_ptr,
			sizeof(struct clk_domain_35_master), pargs);
		break;


	case CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER:
		status = clk_domain_construct_3x_master(g, &board_obj_ptr,
			sizeof(struct clk_domain_3x_master), pargs);
		break;

	case CTRL_CLK_CLK_DOMAIN_TYPE_35_SLAVE:
		status = clk_domain_construct_35_slave(g, &board_obj_ptr,
			sizeof(struct clk_domain_35_slave), pargs);
		break;

	case CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE:
		status = clk_domain_construct_3x_slave(g, &board_obj_ptr,
			sizeof(struct clk_domain_3x_slave), pargs);
		break;

	default:
		return NULL;
	}

	if (status) {
		return NULL;
	}

	nvgpu_log_info(g, " Done");

	return (struct clk_domain *)board_obj_ptr;
}

static int clk_domain_pmudatainit_super(struct gk20a *g,
					struct boardobj *board_obj_ptr,
					struct nv_pmu_boardobj *ppmudata)
{
	int status = 0;
	struct clk_domain *pclk_domain;
	struct nv_pmu_clk_clk_domain_boardobj_set *pset;

	nvgpu_log_info(g, " ");

	status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
	if (status != 0) {
		return status;
	}

	pclk_domain = (struct clk_domain *)board_obj_ptr;

	pset = (struct nv_pmu_clk_clk_domain_boardobj_set *)ppmudata;

	pset->domain = pclk_domain->domain;
	pset->api_domain = pclk_domain->api_domain;
	pset->perf_domain_grp_idx = pclk_domain->perf_domain_grp_idx;

	return status;
}

int clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk)
{
	int status = 0;
	struct clk_domain *pdomain;
	u8 i;

	/* Iterate over all CLK_DOMAINs and flatten their VF curves.*/
	BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
			struct clk_domain *, pdomain, i) {
		status = pdomain->clkdomainclkproglink(g, pclk, pdomain);
		if (status) {
			nvgpu_err(g,
				  "error flattening VF for CLK DOMAIN - 0x%x",
				  pdomain->domain);
			goto done;
		}
	}

done:
	return status;
}