From 01e6fac4d61fdd7fff5433942ec93fc2ea1e4df1 Mon Sep 17 00:00:00 2001 From: Joshua Bakita Date: Wed, 28 Jun 2023 18:24:25 -0400 Subject: Include nvgpu headers These are needed to build on NVIDIA's Jetson boards for the time being. Only a couple structs are required, so it should be fairly easy to remove this dependency at some point in the future. --- include/clk/clk_domain.c | 1666 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1666 insertions(+) create mode 100644 include/clk/clk_domain.c (limited to 'include/clk/clk_domain.c') diff --git a/include/clk/clk_domain.c b/include/clk/clk_domain.c new file mode 100644 index 0000000..3b64f51 --- /dev/null +++ b/include/clk/clk_domain.c @@ -0,0 +1,1666 @@ +/* + * 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 +#include + +#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; +} -- cgit v1.2.2