Home | History | Annotate | Line # | Download | only in dcn20
      1 /*	$NetBSD: amdgpu_dcn20_dccg.c,v 1.2 2021/12/18 23:45:03 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2018 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: AMD
     25  *
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dcn20_dccg.c,v 1.2 2021/12/18 23:45:03 riastradh Exp $");
     30 
     31 #include <linux/slab.h>
     32 
     33 #include "reg_helper.h"
     34 #include "core_types.h"
     35 #include "dcn20_dccg.h"
     36 
     37 #define TO_DCN_DCCG(dccg)\
     38 	container_of(dccg, struct dcn_dccg, base)
     39 
     40 #define REG(reg) \
     41 	(dccg_dcn->regs->reg)
     42 
     43 #undef FN
     44 #define FN(reg_name, field_name) \
     45 	dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
     46 
     47 #define CTX \
     48 	dccg_dcn->base.ctx
     49 #define DC_LOGGER \
     50 	dccg->ctx->logger
     51 
     52 void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk)
     53 {
     54 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
     55 
     56 	if (dccg->ref_dppclk && req_dppclk) {
     57 		int ref_dppclk = dccg->ref_dppclk;
     58 		int modulo, phase;
     59 
     60 		// phase / modulo = dpp pipe clk / dpp global clk
     61 		modulo = 0xff;   // use FF at the end
     62 		phase = ((modulo * req_dppclk) + ref_dppclk - 1) / ref_dppclk;
     63 
     64 		if (phase > 0xff) {
     65 			ASSERT(false);
     66 			phase = 0xff;
     67 		}
     68 
     69 		REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
     70 				DPPCLK0_DTO_PHASE, phase,
     71 				DPPCLK0_DTO_MODULO, modulo);
     72 		REG_UPDATE(DPPCLK_DTO_CTRL,
     73 				DPPCLK_DTO_ENABLE[dpp_inst], 1);
     74 	} else {
     75 		REG_UPDATE(DPPCLK_DTO_CTRL,
     76 				DPPCLK_DTO_ENABLE[dpp_inst], 0);
     77 	}
     78 }
     79 
     80 void dccg2_get_dccg_ref_freq(struct dccg *dccg,
     81 		unsigned int xtalin_freq_inKhz,
     82 		unsigned int *dccg_ref_freq_inKhz)
     83 {
     84 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
     85 	uint32_t clk_en = 0;
     86 	uint32_t clk_sel = 0;
     87 
     88 	REG_GET_2(REFCLK_CNTL, REFCLK_CLOCK_EN, &clk_en, REFCLK_SRC_SEL, &clk_sel);
     89 
     90 	if (clk_en != 0) {
     91 		// DCN20 has never been validated for non-xtalin as reference
     92 		// frequency.  There's actually no way for DC to determine what
     93 		// frequency a non-xtalin source is.
     94 		ASSERT_CRITICAL(false);
     95 	}
     96 
     97 	*dccg_ref_freq_inKhz = xtalin_freq_inKhz;
     98 
     99 	return;
    100 }
    101 
    102 void dccg2_init(struct dccg *dccg)
    103 {
    104 }
    105 
    106 static const struct dccg_funcs dccg2_funcs = {
    107 	.update_dpp_dto = dccg2_update_dpp_dto,
    108 	.get_dccg_ref_freq = dccg2_get_dccg_ref_freq,
    109 	.dccg_init = dccg2_init
    110 };
    111 
    112 struct dccg *dccg2_create(
    113 	struct dc_context *ctx,
    114 	const struct dccg_registers *regs,
    115 	const struct dccg_shift *dccg_shift,
    116 	const struct dccg_mask *dccg_mask)
    117 {
    118 	struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
    119 	struct dccg *base;
    120 
    121 	if (dccg_dcn == NULL) {
    122 		BREAK_TO_DEBUGGER();
    123 		return NULL;
    124 	}
    125 
    126 	base = &dccg_dcn->base;
    127 	base->ctx = ctx;
    128 	base->funcs = &dccg2_funcs;
    129 
    130 	dccg_dcn->regs = regs;
    131 	dccg_dcn->dccg_shift = dccg_shift;
    132 	dccg_dcn->dccg_mask = dccg_mask;
    133 
    134 	return &dccg_dcn->base;
    135 }
    136 
    137 void dcn_dccg_destroy(struct dccg **dccg)
    138 {
    139 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(*dccg);
    140 
    141 	kfree(dccg_dcn);
    142 	*dccg = NULL;
    143 }
    144