1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2025 Advanced Micro Devices, Inc.
4
5 #include "reg_helper.h"
6 #include "core_types.h"
7 #include "dcn42/dcn42_dccg.h"
8 #include "dcn60_dccg.h"
9
10 #define TO_DCN_DCCG(dccg)\
11 container_of(dccg, struct dcn_dccg, base)
12
13 #define REG(reg) \
14 (dccg_dcn->regs->reg)
15
16 #undef FN
17 #define FN(reg_name, field_name) \
18 dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
19
20 #define CTX \
21 dccg_dcn->base.ctx
22 #define DC_LOGGER \
23 dccg->ctx->logger
24
dccg60_set_pixel_rate_div(struct dccg * dccg,uint32_t otg_inst,enum pixel_rate_div tmds_div,enum pixel_rate_div unused)25 static void dccg60_set_pixel_rate_div(
26 struct dccg *dccg,
27 uint32_t otg_inst,
28 enum pixel_rate_div tmds_div,
29 enum pixel_rate_div unused)
30 {
31 (void)unused;
32 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
33 uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
34 uint32_t dp_dto_int;
35 uint32_t reg_val;
36
37 // only 2 is valid on dcn401
38 if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) {
39 return;
40 }
41
42 dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int);
43 if (tmds_div == cur_tmds_div)
44 return;
45
46 // encode enum to register value
47 reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0;
48
49 switch (otg_inst) {
50 case 0:
51 REG_UPDATE(OTG_PIXEL_RATE_DIV,
52 OTG0_TMDS_PIXEL_RATE_DIV, reg_val);
53 break;
54 case 1:
55 REG_UPDATE(OTG_PIXEL_RATE_DIV,
56 OTG1_TMDS_PIXEL_RATE_DIV, reg_val);
57 break;
58 case 2:
59 REG_UPDATE(OTG_PIXEL_RATE_DIV,
60 OTG2_TMDS_PIXEL_RATE_DIV, reg_val);
61 break;
62 case 3:
63 REG_UPDATE(OTG_PIXEL_RATE_DIV,
64 OTG3_TMDS_PIXEL_RATE_DIV, reg_val);
65 break;
66 default:
67 BREAK_TO_DEBUGGER();
68 return;
69 }
70 }
71
dccg60_set_dto_dscclk(struct dccg * dccg,uint32_t inst,uint32_t num_slices_h)72 static void dccg60_set_dto_dscclk(struct dccg *dccg, uint32_t inst,
73 uint32_t num_slices_h)
74 {
75 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
76
77 switch (inst) {
78 case 0:
79 REG_UPDATE_2(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, 1,
80 DSCCLK0_DTO_MODULO, 1);
81 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1);
82
83 /*
84 * Source for dscclk should be set when dto tuned clock is used.
85 * For 1 slice config, set src to dprefclk.
86 * For 2 or more slice config, set src to dispclk.
87 */
88 if (num_slices_h == 1)
89 REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, 1);
90 else
91 REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, 0);
92
93 break;
94 case 1:
95 REG_UPDATE_2(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, 1,
96 DSCCLK1_DTO_MODULO, 1);
97 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);
98
99 if (num_slices_h == 1)
100 REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, 1);
101 else
102 REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, 0);
103
104 break;
105 case 2:
106 REG_UPDATE_2(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, 1,
107 DSCCLK2_DTO_MODULO, 1);
108 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);
109
110 if (num_slices_h == 1)
111 REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, 1);
112 else
113 REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, 0);
114
115 break;
116 case 3:
117 REG_UPDATE_2(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, 1,
118 DSCCLK3_DTO_MODULO, 1);
119 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1);
120
121 if (num_slices_h == 1)
122 REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, 1);
123 else
124 REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, 0);
125
126 break;
127 default:
128 BREAK_TO_DEBUGGER();
129 return;
130 }
131 }
132
133 static const struct dccg_funcs dccg60_funcs = {
134 .enable_hdmicharclk = dccg401_enable_hdmicharclk,
135 .disable_hdmicharclk = dccg401_disable_hdmicharclk,
136 .set_hdmistreamclk = dccg401_set_hdmistreamclk,
137 .update_dpp_dto = dccg401_update_dpp_dto,
138 .get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
139 .dccg_init = dccg401_init,
140 .set_dpstreamclk = dccg401_set_dpstreamclk,
141 .enable_symclk32_se = dccg31_enable_symclk32_se,
142 .disable_symclk32_se = dccg31_disable_symclk32_se,
143 .enable_symclk32_le = dccg401_enable_symclk32_le,
144 .disable_symclk32_le = dccg401_disable_symclk32_le,
145 .set_physymclk = dccg401_set_physymclk,
146 .set_dtbclk_dto = NULL,
147 .set_dto_dscclk = dccg60_set_dto_dscclk,
148 .set_ref_dscclk = dccg401_set_ref_dscclk,
149 .set_valid_pixel_rate = NULL,
150 .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
151 .set_audio_dtbclk_dto = NULL,
152 .otg_add_pixel = dccg42_otg_add_pixel,
153 .otg_drop_pixel = dccg42_otg_drop_pixel,
154 .set_pixel_rate_div = dccg60_set_pixel_rate_div,
155 .get_pixel_rate_div = dccg401_get_pixel_rate_div,
156 .set_dp_dto = dccg401_set_dp_dto,
157 .enable_symclk_se = dccg401_enable_symclk_se,
158 .disable_symclk_se = dccg401_disable_symclk_se,
159 .set_dtbclk_p_src = dccg401_set_dtbclk_p_src,
160 .dccg_read_reg_state = dccg31_read_reg_state,
161 .allow_clock_gating = dccg2_allow_clock_gating
162 };
163
dccg60_create(struct dc_context * ctx,const struct dccg_registers * regs,const struct dccg_shift * dccg_shift,const struct dccg_mask * dccg_mask)164 struct dccg *dccg60_create(
165 struct dc_context *ctx,
166 const struct dccg_registers *regs,
167 const struct dccg_shift *dccg_shift,
168 const struct dccg_mask *dccg_mask)
169 {
170 struct dcn_dccg *dccg_dcn = kzalloc_obj(*dccg_dcn);
171 struct dccg *base;
172
173 if (dccg_dcn == NULL) {
174 BREAK_TO_DEBUGGER();
175 return NULL;
176 }
177
178 base = &dccg_dcn->base;
179 base->ctx = ctx;
180 base->funcs = &dccg60_funcs;
181
182 dccg_dcn->regs = regs;
183 dccg_dcn->dccg_shift = dccg_shift;
184 dccg_dcn->dccg_mask = dccg_mask;
185
186 return &dccg_dcn->base;
187 }
188