mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
Most of BIOS parsing code is not specific to any particular GPU. Move most of the code to generic files, and leave only chip specific parts dealing with microcontroller boot into chip specific files. As most of the parsing is generic, they do not need to be called via HALs so remove the HALs and change the calls into direct function calls. All definitions meant to be used outside BIOS code itself are now in <nvgpu/bios.h> Change-Id: Id48e94c74511d6e95645e90e5bba5c12ef8da45d Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1302222 GVS: Gerrit_Virtual_Submit
1110 lines
31 KiB
C
1110 lines
31 KiB
C
/*
|
|
* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*/
|
|
|
|
#include <nvgpu/bios.h>
|
|
|
|
#include "gk20a/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"
|
|
#include "gk20a/pmu_gk20a.h"
|
|
|
|
static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs);
|
|
|
|
static u32 devinit_get_clocks_table(struct gk20a *g,
|
|
struct clk_domains *pdomainobjs);
|
|
|
|
static u32 clk_domain_pmudatainit_super(struct gk20a *g, struct boardobj
|
|
*board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
|
|
|
|
const struct vbios_clocks_table_1x_hal_clock_entry vbiosclktbl1xhalentry[] = {
|
|
{ clkwhich_gpc2clk, true, },
|
|
{ clkwhich_xbar2clk, true, },
|
|
{ clkwhich_mclk, false, },
|
|
{ clkwhich_sys2clk, true, },
|
|
{ clkwhich_hub2clk, false, },
|
|
{ clkwhich_nvdclk, false, },
|
|
{ clkwhich_pwrclk, false, },
|
|
{ clkwhich_dispclk, false, },
|
|
{ clkwhich_pciegenclk, false, }
|
|
};
|
|
|
|
static u32 clktranslatehalmumsettoapinumset(u32 clkhaldomains)
|
|
{
|
|
u32 clkapidomains = 0;
|
|
|
|
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 u32 _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;
|
|
u32 status = 0;
|
|
|
|
status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
|
|
if (status) {
|
|
gk20a_err(dev_from_gk20a(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->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;
|
|
pset->volt_rails_max = 2;
|
|
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 u32 _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;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
/*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;
|
|
gk20a_dbg_info(" Done");
|
|
return 0;
|
|
}
|
|
|
|
u32 clk_domain_sw_setup(struct gk20a *g)
|
|
{
|
|
u32 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;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
status = boardobjgrpconstruct_e32(&g->clk_pmu.clk_domainobjs.super);
|
|
if (status) {
|
|
gk20a_err(dev_from_gk20a(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) {
|
|
gk20a_err(dev_from_gk20a(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:
|
|
gk20a_dbg_info(" done status %x", status);
|
|
return status;
|
|
}
|
|
|
|
u32 clk_domain_pmu_setup(struct gk20a *g)
|
|
{
|
|
u32 status;
|
|
struct boardobjgrp *pboardobjgrp = NULL;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
|
|
|
|
if (!pboardobjgrp->bconstructed)
|
|
return -EINVAL;
|
|
|
|
status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
|
|
|
|
gk20a_dbg_info("Done");
|
|
return status;
|
|
}
|
|
|
|
static u32 devinit_get_clocks_table(struct gk20a *g,
|
|
struct clk_domains *pclkdomainobjs)
|
|
{
|
|
u32 status = 0;
|
|
u8 *clocks_table_ptr = NULL;
|
|
struct vbios_clocks_table_1x_header clocks_table_header = { 0 };
|
|
struct vbios_clocks_table_1x_entry clocks_table_entry = { 0 };
|
|
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;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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.header_size <
|
|
VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) {
|
|
status = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
if (clocks_table_header.entry_size <
|
|
VBIOS_CLOCKS_TABLE_1X_ENTRY_SIZE_09) {
|
|
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(&clocks_table_entry, clocks_tbl_entry_ptr,
|
|
clocks_table_header.entry_size);
|
|
clk_domain_data.clk_domain.domain =
|
|
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_offset_khz = 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_offset_khz = 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:
|
|
gk20a_err(dev_from_gk20a(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) {
|
|
gk20a_err(dev_from_gk20a(g),
|
|
"unable to construct clock domain boardobj for %d",
|
|
index);
|
|
status = -EINVAL;
|
|
goto done;
|
|
}
|
|
status = boardobjgrp_objinsert(&pclkdomainobjs->super.super,
|
|
(struct boardobj *)pclkdomain_dev, index);
|
|
if (status) {
|
|
gk20a_err(dev_from_gk20a(g),
|
|
"unable to insert clock domain boardobj for %d", index);
|
|
status = -EINVAL;
|
|
goto done;
|
|
}
|
|
clocks_tbl_entry_ptr += clocks_table_header.entry_size;
|
|
}
|
|
|
|
done:
|
|
gk20a_dbg_info(" done status %x", status);
|
|
return status;
|
|
}
|
|
|
|
static u32 clkdomainclkproglink_not_supported(struct gk20a *g,
|
|
struct clk_pmupstate *pclk,
|
|
struct clk_domain *pdomain)
|
|
{
|
|
gk20a_dbg_info("");
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int clkdomainvfsearch_stub(
|
|
struct gk20a *g,
|
|
struct clk_pmupstate *pclk,
|
|
struct clk_domain *pdomain,
|
|
u16 *clkmhz,
|
|
u32 *voltuv,
|
|
u8 rail)
|
|
|
|
{
|
|
gk20a_dbg_info("");
|
|
return -EINVAL;
|
|
}
|
|
|
|
static u32 clkdomaingetfpoints_stub(
|
|
struct gk20a *g,
|
|
struct clk_pmupstate *pclk,
|
|
struct clk_domain *pdomain,
|
|
u32 *pfpointscount,
|
|
u16 *pfreqpointsinmhz,
|
|
u8 rail)
|
|
{
|
|
gk20a_dbg_info("");
|
|
return -EINVAL;
|
|
}
|
|
|
|
|
|
static u32 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;
|
|
u32 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 u32 _clk_domain_pmudatainit_3x(struct gk20a *g,
|
|
struct boardobj *board_obj_ptr,
|
|
struct nv_pmu_boardobj *ppmudata)
|
|
{
|
|
u32 status = 0;
|
|
struct clk_domain_3x *pclk_domain_3x;
|
|
struct nv_pmu_clk_clk_domain_3x_boardobj_set *pset;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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 u32 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;
|
|
u32 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 u32 clkdomainclkproglink_3x_prog(struct gk20a *g,
|
|
struct clk_pmupstate *pclk,
|
|
struct clk_domain *pdomain)
|
|
{
|
|
u32 status = 0;
|
|
struct clk_domain_3x_prog *p3xprog =
|
|
(struct clk_domain_3x_prog *)pdomain;
|
|
struct clk_prog *pprog = NULL;
|
|
u8 i;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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:
|
|
gk20a_dbg_info("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;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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:
|
|
gk20a_dbg_info("done status %x", status);
|
|
return status;
|
|
}
|
|
|
|
static u32 _clk_domain_pmudatainit_3x_prog(struct gk20a *g,
|
|
struct boardobj *board_obj_ptr,
|
|
struct nv_pmu_boardobj *ppmudata)
|
|
{
|
|
u32 status = 0;
|
|
struct clk_domain_3x_prog *pclk_domain_3x_prog;
|
|
struct nv_pmu_clk_clk_domain_3x_prog_boardobj_set *pset;
|
|
struct clk_domains *pdomains = &(g->clk_pmu.clk_domainobjs);
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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_3x_prog_boardobj_set *)
|
|
ppmudata;
|
|
|
|
pset->clk_prog_idx_first = pclk_domain_3x_prog->clk_prog_idx_first;
|
|
pset->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->b_force_noise_unaware_ordering =
|
|
pclk_domain_3x_prog->b_force_noise_unaware_ordering;
|
|
pset->factory_offset_khz = pclk_domain_3x_prog->factory_offset_khz;
|
|
pset->freq_delta_min_mhz = pclk_domain_3x_prog->freq_delta_min_mhz;
|
|
pset->freq_delta_max_mhz = pclk_domain_3x_prog->freq_delta_max_mhz;
|
|
memcpy(&pset->deltas, &pdomains->deltas,
|
|
(sizeof(struct ctrl_clk_clk_delta)));
|
|
|
|
return status;
|
|
}
|
|
|
|
static u32 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;
|
|
u32 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_offset_khz = ptmpdomain->factory_offset_khz;
|
|
pdomain->freq_delta_min_mhz = ptmpdomain->freq_delta_min_mhz;
|
|
pdomain->freq_delta_max_mhz = ptmpdomain->freq_delta_max_mhz;
|
|
|
|
return status;
|
|
}
|
|
|
|
static u32 _clk_domain_pmudatainit_3x_slave(struct gk20a *g,
|
|
struct boardobj *board_obj_ptr,
|
|
struct nv_pmu_boardobj *ppmudata)
|
|
{
|
|
u32 status = 0;
|
|
struct clk_domain_3x_slave *pclk_domain_3x_slave;
|
|
struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *pset;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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 u32 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;
|
|
u32 status = 0;
|
|
|
|
if (BOARDOBJ_GET_TYPE(pargs) != 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)
|
|
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 u32 clkdomainclkproglink_3x_master(struct gk20a *g,
|
|
struct clk_pmupstate *pclk,
|
|
struct clk_domain *pdomain)
|
|
{
|
|
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;
|
|
u16 freq_max_last_mhz = 0;
|
|
u8 i;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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:
|
|
gk20a_dbg_info("done status %x", status);
|
|
return status;
|
|
}
|
|
|
|
static u32 _clk_domain_pmudatainit_3x_master(struct gk20a *g,
|
|
struct boardobj *board_obj_ptr,
|
|
struct nv_pmu_boardobj *ppmudata)
|
|
{
|
|
u32 status = 0;
|
|
struct clk_domain_3x_master *pclk_domain_3x_master;
|
|
struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *pset;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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 u32 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;
|
|
u32 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 u32 clkdomainclkproglink_fixed(struct gk20a *g,
|
|
struct clk_pmupstate *pclk,
|
|
struct clk_domain *pdomain)
|
|
{
|
|
gk20a_dbg_info("");
|
|
return 0;
|
|
}
|
|
|
|
static u32 _clk_domain_pmudatainit_3x_fixed(struct gk20a *g,
|
|
struct boardobj *board_obj_ptr,
|
|
struct nv_pmu_boardobj *ppmudata)
|
|
{
|
|
u32 status = 0;
|
|
struct clk_domain_3x_fixed *pclk_domain_3x_fixed;
|
|
struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *pset;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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 u32 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;
|
|
u32 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;
|
|
|
|
gk20a_dbg_info(" %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_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_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;
|
|
|
|
gk20a_dbg_info(" Done");
|
|
|
|
return (struct clk_domain *)board_obj_ptr;
|
|
}
|
|
|
|
static u32 clk_domain_pmudatainit_super(struct gk20a *g,
|
|
struct boardobj *board_obj_ptr,
|
|
struct nv_pmu_boardobj *ppmudata)
|
|
{
|
|
u32 status = 0;
|
|
struct clk_domain *pclk_domain;
|
|
struct nv_pmu_clk_clk_domain_boardobj_set *pset;
|
|
|
|
gk20a_dbg_info("");
|
|
|
|
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;
|
|
}
|
|
|
|
u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk)
|
|
{
|
|
u32 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) {
|
|
gk20a_err(dev_from_gk20a(g),
|
|
"error flattening VF for CLK DOMAIN - 0x%x",
|
|
pdomain->domain);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
return status;
|
|
}
|