| .. | .. |
|---|
| 46 | 46 | * This is a workaround for a bug that has existed since R5xx and has not been |
|---|
| 47 | 47 | * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. |
|---|
| 48 | 48 | */ |
|---|
| 49 | | -static void optc1_apply_front_porch_workaround( |
|---|
| 50 | | - struct timing_generator *optc, |
|---|
| 51 | | - struct dc_crtc_timing *timing) |
|---|
| 49 | +static void apply_front_porch_workaround(struct dc_crtc_timing *timing) |
|---|
| 52 | 50 | { |
|---|
| 53 | 51 | if (timing->flags.INTERLACE == 1) { |
|---|
| 54 | 52 | if (timing->v_front_porch < 2) |
|---|
| .. | .. |
|---|
| 60 | 58 | } |
|---|
| 61 | 59 | |
|---|
| 62 | 60 | void optc1_program_global_sync( |
|---|
| 63 | | - struct timing_generator *optc) |
|---|
| 61 | + struct timing_generator *optc, |
|---|
| 62 | + int vready_offset, |
|---|
| 63 | + int vstartup_start, |
|---|
| 64 | + int vupdate_offset, |
|---|
| 65 | + int vupdate_width) |
|---|
| 64 | 66 | { |
|---|
| 65 | 67 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 66 | 68 | |
|---|
| 67 | | - if (optc->dlg_otg_param.vstartup_start == 0) { |
|---|
| 69 | + optc1->vready_offset = vready_offset; |
|---|
| 70 | + optc1->vstartup_start = vstartup_start; |
|---|
| 71 | + optc1->vupdate_offset = vupdate_offset; |
|---|
| 72 | + optc1->vupdate_width = vupdate_width; |
|---|
| 73 | + |
|---|
| 74 | + if (optc1->vstartup_start == 0) { |
|---|
| 68 | 75 | BREAK_TO_DEBUGGER(); |
|---|
| 69 | 76 | return; |
|---|
| 70 | 77 | } |
|---|
| 71 | 78 | |
|---|
| 72 | 79 | REG_SET(OTG_VSTARTUP_PARAM, 0, |
|---|
| 73 | | - VSTARTUP_START, optc->dlg_otg_param.vstartup_start); |
|---|
| 80 | + VSTARTUP_START, optc1->vstartup_start); |
|---|
| 74 | 81 | |
|---|
| 75 | 82 | REG_SET_2(OTG_VUPDATE_PARAM, 0, |
|---|
| 76 | | - VUPDATE_OFFSET, optc->dlg_otg_param.vupdate_offset, |
|---|
| 77 | | - VUPDATE_WIDTH, optc->dlg_otg_param.vupdate_width); |
|---|
| 83 | + VUPDATE_OFFSET, optc1->vupdate_offset, |
|---|
| 84 | + VUPDATE_WIDTH, optc1->vupdate_width); |
|---|
| 78 | 85 | |
|---|
| 79 | 86 | REG_SET(OTG_VREADY_PARAM, 0, |
|---|
| 80 | | - VREADY_OFFSET, optc->dlg_otg_param.vready_offset); |
|---|
| 87 | + VREADY_OFFSET, optc1->vready_offset); |
|---|
| 81 | 88 | } |
|---|
| 82 | 89 | |
|---|
| 83 | 90 | static void optc1_disable_stereo(struct timing_generator *optc) |
|---|
| .. | .. |
|---|
| 87 | 94 | REG_SET(OTG_STEREO_CONTROL, 0, |
|---|
| 88 | 95 | OTG_STEREO_EN, 0); |
|---|
| 89 | 96 | |
|---|
| 90 | | - REG_SET_3(OTG_3D_STRUCTURE_CONTROL, 0, |
|---|
| 97 | + REG_SET_2(OTG_3D_STRUCTURE_CONTROL, 0, |
|---|
| 91 | 98 | OTG_3D_STRUCTURE_EN, 0, |
|---|
| 92 | | - OTG_3D_STRUCTURE_V_UPDATE_MODE, 0, |
|---|
| 93 | 99 | OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0); |
|---|
| 94 | 100 | } |
|---|
| 95 | 101 | |
|---|
| 96 | | -static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing) |
|---|
| 97 | | -{ |
|---|
| 98 | | - struct dc_crtc_timing patched_crtc_timing; |
|---|
| 99 | | - int vesa_sync_start; |
|---|
| 100 | | - int asic_blank_end; |
|---|
| 101 | | - int interlace_factor; |
|---|
| 102 | | - int vertical_line_start; |
|---|
| 103 | | - |
|---|
| 104 | | - patched_crtc_timing = *dc_crtc_timing; |
|---|
| 105 | | - optc1_apply_front_porch_workaround(optc, &patched_crtc_timing); |
|---|
| 106 | | - |
|---|
| 107 | | - vesa_sync_start = patched_crtc_timing.h_addressable + |
|---|
| 108 | | - patched_crtc_timing.h_border_right + |
|---|
| 109 | | - patched_crtc_timing.h_front_porch; |
|---|
| 110 | | - |
|---|
| 111 | | - asic_blank_end = patched_crtc_timing.h_total - |
|---|
| 112 | | - vesa_sync_start - |
|---|
| 113 | | - patched_crtc_timing.h_border_left; |
|---|
| 114 | | - |
|---|
| 115 | | - interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1; |
|---|
| 116 | | - |
|---|
| 117 | | - vesa_sync_start = patched_crtc_timing.v_addressable + |
|---|
| 118 | | - patched_crtc_timing.v_border_bottom + |
|---|
| 119 | | - patched_crtc_timing.v_front_porch; |
|---|
| 120 | | - |
|---|
| 121 | | - asic_blank_end = (patched_crtc_timing.v_total - |
|---|
| 122 | | - vesa_sync_start - |
|---|
| 123 | | - patched_crtc_timing.v_border_top) |
|---|
| 124 | | - * interlace_factor; |
|---|
| 125 | | - |
|---|
| 126 | | - vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; |
|---|
| 127 | | - if (vertical_line_start < 0) { |
|---|
| 128 | | - ASSERT(0); |
|---|
| 129 | | - vertical_line_start = 0; |
|---|
| 130 | | - } |
|---|
| 131 | | - |
|---|
| 132 | | - return vertical_line_start; |
|---|
| 133 | | -} |
|---|
| 134 | | - |
|---|
| 135 | | -void optc1_program_vline_interrupt( |
|---|
| 102 | +void optc1_setup_vertical_interrupt0( |
|---|
| 136 | 103 | struct timing_generator *optc, |
|---|
| 137 | | - const struct dc_crtc_timing *dc_crtc_timing, |
|---|
| 138 | | - unsigned long long vsync_delta) |
|---|
| 104 | + uint32_t start_line, |
|---|
| 105 | + uint32_t end_line) |
|---|
| 139 | 106 | { |
|---|
| 140 | | - |
|---|
| 141 | 107 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 142 | | - |
|---|
| 143 | | - unsigned long long req_delta_tens_of_usec = div64_u64((vsync_delta + 9999), 10000); |
|---|
| 144 | | - unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_khz + 99), 100); |
|---|
| 145 | | - uint32_t req_delta_lines = (uint32_t) div64_u64( |
|---|
| 146 | | - (req_delta_tens_of_usec * pix_clk_hundreds_khz + dc_crtc_timing->h_total - 1), |
|---|
| 147 | | - dc_crtc_timing->h_total); |
|---|
| 148 | | - |
|---|
| 149 | | - uint32_t vsync_line = get_start_vline(optc, dc_crtc_timing); |
|---|
| 150 | | - uint32_t start_line = 0; |
|---|
| 151 | | - uint32_t endLine = 0; |
|---|
| 152 | | - |
|---|
| 153 | | - if (req_delta_lines != 0) |
|---|
| 154 | | - req_delta_lines--; |
|---|
| 155 | | - |
|---|
| 156 | | - if (req_delta_lines > vsync_line) |
|---|
| 157 | | - start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) - 1; |
|---|
| 158 | | - else |
|---|
| 159 | | - start_line = vsync_line - req_delta_lines; |
|---|
| 160 | | - |
|---|
| 161 | | - endLine = start_line + 2; |
|---|
| 162 | | - |
|---|
| 163 | | - if (endLine >= dc_crtc_timing->v_total) |
|---|
| 164 | | - endLine = 2; |
|---|
| 165 | 108 | |
|---|
| 166 | 109 | REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0, |
|---|
| 167 | 110 | OTG_VERTICAL_INTERRUPT0_LINE_START, start_line, |
|---|
| 168 | | - OTG_VERTICAL_INTERRUPT0_LINE_END, endLine); |
|---|
| 111 | + OTG_VERTICAL_INTERRUPT0_LINE_END, end_line); |
|---|
| 112 | +} |
|---|
| 113 | + |
|---|
| 114 | +void optc1_setup_vertical_interrupt1( |
|---|
| 115 | + struct timing_generator *optc, |
|---|
| 116 | + uint32_t start_line) |
|---|
| 117 | +{ |
|---|
| 118 | + struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 119 | + |
|---|
| 120 | + REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0, |
|---|
| 121 | + OTG_VERTICAL_INTERRUPT1_LINE_START, start_line); |
|---|
| 122 | +} |
|---|
| 123 | + |
|---|
| 124 | +void optc1_setup_vertical_interrupt2( |
|---|
| 125 | + struct timing_generator *optc, |
|---|
| 126 | + uint32_t start_line) |
|---|
| 127 | +{ |
|---|
| 128 | + struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 129 | + |
|---|
| 130 | + REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, |
|---|
| 131 | + OTG_VERTICAL_INTERRUPT2_LINE_START, start_line); |
|---|
| 169 | 132 | } |
|---|
| 170 | 133 | |
|---|
| 171 | 134 | /** |
|---|
| .. | .. |
|---|
| 176 | 139 | void optc1_program_timing( |
|---|
| 177 | 140 | struct timing_generator *optc, |
|---|
| 178 | 141 | const struct dc_crtc_timing *dc_crtc_timing, |
|---|
| 142 | + int vready_offset, |
|---|
| 143 | + int vstartup_start, |
|---|
| 144 | + int vupdate_offset, |
|---|
| 145 | + int vupdate_width, |
|---|
| 146 | + const enum signal_type signal, |
|---|
| 179 | 147 | bool use_vbios) |
|---|
| 180 | 148 | { |
|---|
| 181 | 149 | struct dc_crtc_timing patched_crtc_timing; |
|---|
| 182 | | - uint32_t vesa_sync_start; |
|---|
| 183 | 150 | uint32_t asic_blank_end; |
|---|
| 184 | 151 | uint32_t asic_blank_start; |
|---|
| 185 | 152 | uint32_t v_total; |
|---|
| 186 | 153 | uint32_t v_sync_end; |
|---|
| 187 | | - uint32_t v_init, v_fp2; |
|---|
| 188 | 154 | uint32_t h_sync_polarity, v_sync_polarity; |
|---|
| 189 | | - uint32_t interlace_factor; |
|---|
| 190 | 155 | uint32_t start_point = 0; |
|---|
| 191 | 156 | uint32_t field_num = 0; |
|---|
| 192 | | - uint32_t h_div_2; |
|---|
| 193 | | - int32_t vertical_line_start; |
|---|
| 157 | + enum h_timing_div_mode h_div = H_TIMING_NO_DIV; |
|---|
| 194 | 158 | |
|---|
| 195 | 159 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 196 | 160 | |
|---|
| 161 | + optc1->signal = signal; |
|---|
| 162 | + optc1->vready_offset = vready_offset; |
|---|
| 163 | + optc1->vstartup_start = vstartup_start; |
|---|
| 164 | + optc1->vupdate_offset = vupdate_offset; |
|---|
| 165 | + optc1->vupdate_width = vupdate_width; |
|---|
| 197 | 166 | patched_crtc_timing = *dc_crtc_timing; |
|---|
| 198 | | - optc1_apply_front_porch_workaround(optc, &patched_crtc_timing); |
|---|
| 167 | + apply_front_porch_workaround(&patched_crtc_timing); |
|---|
| 199 | 168 | |
|---|
| 200 | 169 | /* Load horizontal timing */ |
|---|
| 201 | 170 | |
|---|
| .. | .. |
|---|
| 208 | 177 | OTG_H_SYNC_A_START, 0, |
|---|
| 209 | 178 | OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width); |
|---|
| 210 | 179 | |
|---|
| 211 | | - /* asic_h_blank_end = HsyncWidth + HbackPorch = |
|---|
| 212 | | - * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart - |
|---|
| 213 | | - * vesa.h_left_border |
|---|
| 214 | | - */ |
|---|
| 215 | | - vesa_sync_start = patched_crtc_timing.h_addressable + |
|---|
| 216 | | - patched_crtc_timing.h_border_right + |
|---|
| 180 | + /* blank_start = line end - front porch */ |
|---|
| 181 | + asic_blank_start = patched_crtc_timing.h_total - |
|---|
| 217 | 182 | patched_crtc_timing.h_front_porch; |
|---|
| 218 | 183 | |
|---|
| 219 | | - asic_blank_end = patched_crtc_timing.h_total - |
|---|
| 220 | | - vesa_sync_start - |
|---|
| 184 | + /* blank_end = blank_start - active */ |
|---|
| 185 | + asic_blank_end = asic_blank_start - |
|---|
| 186 | + patched_crtc_timing.h_border_right - |
|---|
| 187 | + patched_crtc_timing.h_addressable - |
|---|
| 221 | 188 | patched_crtc_timing.h_border_left; |
|---|
| 222 | | - |
|---|
| 223 | | - /* h_blank_start = v_blank_end + v_active */ |
|---|
| 224 | | - asic_blank_start = asic_blank_end + |
|---|
| 225 | | - patched_crtc_timing.h_border_left + |
|---|
| 226 | | - patched_crtc_timing.h_addressable + |
|---|
| 227 | | - patched_crtc_timing.h_border_right; |
|---|
| 228 | 189 | |
|---|
| 229 | 190 | REG_UPDATE_2(OTG_H_BLANK_START_END, |
|---|
| 230 | 191 | OTG_H_BLANK_START, asic_blank_start, |
|---|
| .. | .. |
|---|
| 237 | 198 | REG_UPDATE(OTG_H_SYNC_A_CNTL, |
|---|
| 238 | 199 | OTG_H_SYNC_A_POL, h_sync_polarity); |
|---|
| 239 | 200 | |
|---|
| 240 | | - /* Load vertical timing */ |
|---|
| 201 | + v_total = patched_crtc_timing.v_total - 1; |
|---|
| 241 | 202 | |
|---|
| 242 | | - /* CRTC_V_TOTAL = v_total - 1 */ |
|---|
| 243 | | - if (patched_crtc_timing.flags.INTERLACE) { |
|---|
| 244 | | - interlace_factor = 2; |
|---|
| 245 | | - v_total = 2 * patched_crtc_timing.v_total; |
|---|
| 246 | | - } else { |
|---|
| 247 | | - interlace_factor = 1; |
|---|
| 248 | | - v_total = patched_crtc_timing.v_total - 1; |
|---|
| 249 | | - } |
|---|
| 250 | 203 | REG_SET(OTG_V_TOTAL, 0, |
|---|
| 251 | 204 | OTG_V_TOTAL, v_total); |
|---|
| 252 | 205 | |
|---|
| .. | .. |
|---|
| 259 | 212 | OTG_V_TOTAL_MIN, v_total); |
|---|
| 260 | 213 | |
|---|
| 261 | 214 | /* v_sync_start = 0, v_sync_end = v_sync_width */ |
|---|
| 262 | | - v_sync_end = patched_crtc_timing.v_sync_width * interlace_factor; |
|---|
| 215 | + v_sync_end = patched_crtc_timing.v_sync_width; |
|---|
| 263 | 216 | |
|---|
| 264 | 217 | REG_UPDATE_2(OTG_V_SYNC_A, |
|---|
| 265 | 218 | OTG_V_SYNC_A_START, 0, |
|---|
| 266 | 219 | OTG_V_SYNC_A_END, v_sync_end); |
|---|
| 267 | 220 | |
|---|
| 268 | | - vesa_sync_start = patched_crtc_timing.v_addressable + |
|---|
| 269 | | - patched_crtc_timing.v_border_bottom + |
|---|
| 221 | + /* blank_start = frame end - front porch */ |
|---|
| 222 | + asic_blank_start = patched_crtc_timing.v_total - |
|---|
| 270 | 223 | patched_crtc_timing.v_front_porch; |
|---|
| 271 | 224 | |
|---|
| 272 | | - asic_blank_end = (patched_crtc_timing.v_total - |
|---|
| 273 | | - vesa_sync_start - |
|---|
| 274 | | - patched_crtc_timing.v_border_top) |
|---|
| 275 | | - * interlace_factor; |
|---|
| 276 | | - |
|---|
| 277 | | - /* v_blank_start = v_blank_end + v_active */ |
|---|
| 278 | | - asic_blank_start = asic_blank_end + |
|---|
| 279 | | - (patched_crtc_timing.v_border_top + |
|---|
| 280 | | - patched_crtc_timing.v_addressable + |
|---|
| 281 | | - patched_crtc_timing.v_border_bottom) |
|---|
| 282 | | - * interlace_factor; |
|---|
| 225 | + /* blank_end = blank_start - active */ |
|---|
| 226 | + asic_blank_end = asic_blank_start - |
|---|
| 227 | + patched_crtc_timing.v_border_bottom - |
|---|
| 228 | + patched_crtc_timing.v_addressable - |
|---|
| 229 | + patched_crtc_timing.v_border_top; |
|---|
| 283 | 230 | |
|---|
| 284 | 231 | REG_UPDATE_2(OTG_V_BLANK_START_END, |
|---|
| 285 | 232 | OTG_V_BLANK_START, asic_blank_start, |
|---|
| 286 | 233 | OTG_V_BLANK_END, asic_blank_end); |
|---|
| 287 | | - |
|---|
| 288 | | - /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt, |
|---|
| 289 | | - * program the reg for interrupt postition. |
|---|
| 290 | | - */ |
|---|
| 291 | | - vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; |
|---|
| 292 | | - if (vertical_line_start < 0) { |
|---|
| 293 | | - ASSERT(0); |
|---|
| 294 | | - vertical_line_start = 0; |
|---|
| 295 | | - } |
|---|
| 296 | | - REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, |
|---|
| 297 | | - OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start); |
|---|
| 298 | 234 | |
|---|
| 299 | 235 | /* v_sync polarity */ |
|---|
| 300 | 236 | v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ? |
|---|
| 301 | 237 | 0 : 1; |
|---|
| 302 | 238 | |
|---|
| 303 | 239 | REG_UPDATE(OTG_V_SYNC_A_CNTL, |
|---|
| 304 | | - OTG_V_SYNC_A_POL, v_sync_polarity); |
|---|
| 240 | + OTG_V_SYNC_A_POL, v_sync_polarity); |
|---|
| 305 | 241 | |
|---|
| 306 | | - v_init = asic_blank_start; |
|---|
| 307 | | - if (optc->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT || |
|---|
| 308 | | - optc->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT_MST || |
|---|
| 309 | | - optc->dlg_otg_param.signal == SIGNAL_TYPE_EDP) { |
|---|
| 242 | + if (optc1->signal == SIGNAL_TYPE_DISPLAY_PORT || |
|---|
| 243 | + optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST || |
|---|
| 244 | + optc1->signal == SIGNAL_TYPE_EDP) { |
|---|
| 310 | 245 | start_point = 1; |
|---|
| 311 | 246 | if (patched_crtc_timing.flags.INTERLACE == 1) |
|---|
| 312 | 247 | field_num = 1; |
|---|
| 313 | 248 | } |
|---|
| 314 | | - v_fp2 = 0; |
|---|
| 315 | | - if (optc->dlg_otg_param.vstartup_start > asic_blank_end) |
|---|
| 316 | | - v_fp2 = optc->dlg_otg_param.vstartup_start > asic_blank_end; |
|---|
| 317 | 249 | |
|---|
| 318 | 250 | /* Interlace */ |
|---|
| 319 | | - if (patched_crtc_timing.flags.INTERLACE == 1) { |
|---|
| 320 | | - REG_UPDATE(OTG_INTERLACE_CONTROL, |
|---|
| 321 | | - OTG_INTERLACE_ENABLE, 1); |
|---|
| 322 | | - v_init = v_init / 2; |
|---|
| 323 | | - if ((optc->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end) |
|---|
| 324 | | - v_fp2 = v_fp2 / 2; |
|---|
| 325 | | - } else |
|---|
| 326 | | - REG_UPDATE(OTG_INTERLACE_CONTROL, |
|---|
| 327 | | - OTG_INTERLACE_ENABLE, 0); |
|---|
| 328 | | - |
|---|
| 251 | + if (REG(OTG_INTERLACE_CONTROL)) { |
|---|
| 252 | + if (patched_crtc_timing.flags.INTERLACE == 1) |
|---|
| 253 | + REG_UPDATE(OTG_INTERLACE_CONTROL, |
|---|
| 254 | + OTG_INTERLACE_ENABLE, 1); |
|---|
| 255 | + else |
|---|
| 256 | + REG_UPDATE(OTG_INTERLACE_CONTROL, |
|---|
| 257 | + OTG_INTERLACE_ENABLE, 0); |
|---|
| 258 | + } |
|---|
| 329 | 259 | |
|---|
| 330 | 260 | /* VTG enable set to 0 first VInit */ |
|---|
| 331 | 261 | REG_UPDATE(CONTROL, |
|---|
| 332 | 262 | VTG0_ENABLE, 0); |
|---|
| 333 | | - |
|---|
| 334 | | - REG_UPDATE_2(CONTROL, |
|---|
| 335 | | - VTG0_FP2, v_fp2, |
|---|
| 336 | | - VTG0_VCOUNT_INIT, v_init); |
|---|
| 337 | 263 | |
|---|
| 338 | 264 | /* original code is using VTG offset to address OTG reg, seems wrong */ |
|---|
| 339 | 265 | REG_UPDATE_2(OTG_CONTROL, |
|---|
| 340 | 266 | OTG_START_POINT_CNTL, start_point, |
|---|
| 341 | 267 | OTG_FIELD_NUMBER_CNTL, field_num); |
|---|
| 342 | 268 | |
|---|
| 343 | | - optc1_program_global_sync(optc); |
|---|
| 269 | + optc->funcs->program_global_sync(optc, |
|---|
| 270 | + vready_offset, |
|---|
| 271 | + vstartup_start, |
|---|
| 272 | + vupdate_offset, |
|---|
| 273 | + vupdate_width); |
|---|
| 274 | + |
|---|
| 275 | + optc->funcs->set_vtg_params(optc, dc_crtc_timing); |
|---|
| 344 | 276 | |
|---|
| 345 | 277 | /* TODO |
|---|
| 346 | 278 | * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1 |
|---|
| .. | .. |
|---|
| 352 | 284 | /* Enable stereo - only when we need to pack 3D frame. Other types |
|---|
| 353 | 285 | * of stereo handled in explicit call |
|---|
| 354 | 286 | */ |
|---|
| 355 | | - h_div_2 = (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ? |
|---|
| 356 | | - 1 : 0; |
|---|
| 357 | 287 | |
|---|
| 358 | | - REG_UPDATE(OTG_H_TIMING_CNTL, |
|---|
| 359 | | - OTG_H_TIMING_DIV_BY2, h_div_2); |
|---|
| 288 | + if (optc1_is_two_pixels_per_containter(&patched_crtc_timing) || optc1->opp_count == 2) |
|---|
| 289 | + h_div = H_TIMING_DIV_BY2; |
|---|
| 360 | 290 | |
|---|
| 291 | + if (REG(OPTC_DATA_FORMAT_CONTROL)) { |
|---|
| 292 | + uint32_t data_fmt = 0; |
|---|
| 293 | + |
|---|
| 294 | + if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) |
|---|
| 295 | + data_fmt = 1; |
|---|
| 296 | + else if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) |
|---|
| 297 | + data_fmt = 2; |
|---|
| 298 | + |
|---|
| 299 | + REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt); |
|---|
| 300 | + } |
|---|
| 301 | + |
|---|
| 302 | +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) |
|---|
| 303 | + if (optc1->tg_mask->OTG_H_TIMING_DIV_MODE != 0) { |
|---|
| 304 | + if (optc1->opp_count == 4) |
|---|
| 305 | + h_div = H_TIMING_DIV_BY4; |
|---|
| 306 | + |
|---|
| 307 | + REG_UPDATE(OTG_H_TIMING_CNTL, |
|---|
| 308 | + OTG_H_TIMING_DIV_MODE, h_div); |
|---|
| 309 | + } else |
|---|
| 310 | +#endif |
|---|
| 311 | + { |
|---|
| 312 | + REG_UPDATE(OTG_H_TIMING_CNTL, |
|---|
| 313 | + OTG_H_TIMING_DIV_BY2, h_div); |
|---|
| 314 | + } |
|---|
| 315 | +} |
|---|
| 316 | + |
|---|
| 317 | +void optc1_set_vtg_params(struct timing_generator *optc, |
|---|
| 318 | + const struct dc_crtc_timing *dc_crtc_timing) |
|---|
| 319 | +{ |
|---|
| 320 | + struct dc_crtc_timing patched_crtc_timing; |
|---|
| 321 | + uint32_t asic_blank_end; |
|---|
| 322 | + uint32_t v_init; |
|---|
| 323 | + uint32_t v_fp2 = 0; |
|---|
| 324 | + int32_t vertical_line_start; |
|---|
| 325 | + |
|---|
| 326 | + struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 327 | + |
|---|
| 328 | + patched_crtc_timing = *dc_crtc_timing; |
|---|
| 329 | + apply_front_porch_workaround(&patched_crtc_timing); |
|---|
| 330 | + |
|---|
| 331 | + /* VCOUNT_INIT is the start of blank */ |
|---|
| 332 | + v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch; |
|---|
| 333 | + |
|---|
| 334 | + /* end of blank = v_init - active */ |
|---|
| 335 | + asic_blank_end = v_init - |
|---|
| 336 | + patched_crtc_timing.v_border_bottom - |
|---|
| 337 | + patched_crtc_timing.v_addressable - |
|---|
| 338 | + patched_crtc_timing.v_border_top; |
|---|
| 339 | + |
|---|
| 340 | + /* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */ |
|---|
| 341 | + vertical_line_start = asic_blank_end - optc1->vstartup_start + 1; |
|---|
| 342 | + if (vertical_line_start < 0) |
|---|
| 343 | + v_fp2 = -vertical_line_start; |
|---|
| 344 | + |
|---|
| 345 | + /* Interlace */ |
|---|
| 346 | + if (REG(OTG_INTERLACE_CONTROL)) { |
|---|
| 347 | + if (patched_crtc_timing.flags.INTERLACE == 1) { |
|---|
| 348 | + v_init = v_init / 2; |
|---|
| 349 | + if ((optc1->vstartup_start/2)*2 > asic_blank_end) |
|---|
| 350 | + v_fp2 = v_fp2 / 2; |
|---|
| 351 | + } |
|---|
| 352 | + } |
|---|
| 353 | + |
|---|
| 354 | + REG_UPDATE_2(CONTROL, |
|---|
| 355 | + VTG0_FP2, v_fp2, |
|---|
| 356 | + VTG0_VCOUNT_INIT, v_init); |
|---|
| 361 | 357 | } |
|---|
| 362 | 358 | |
|---|
| 363 | 359 | void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable) |
|---|
| .. | .. |
|---|
| 371 | 367 | } |
|---|
| 372 | 368 | |
|---|
| 373 | 369 | /** |
|---|
| 370 | + * optc1_set_timing_double_buffer() - DRR double buffering control |
|---|
| 371 | + * |
|---|
| 372 | + * Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN, |
|---|
| 373 | + * VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers. |
|---|
| 374 | + * |
|---|
| 375 | + * Options: any time, start of frame, dp start of frame (range timing) |
|---|
| 376 | + */ |
|---|
| 377 | +void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable) |
|---|
| 378 | +{ |
|---|
| 379 | + struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 380 | + uint32_t mode = enable ? 2 : 0; |
|---|
| 381 | + |
|---|
| 382 | + REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, |
|---|
| 383 | + OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mode); |
|---|
| 384 | +} |
|---|
| 385 | + |
|---|
| 386 | +/** |
|---|
| 374 | 387 | * unblank_crtc |
|---|
| 375 | 388 | * Call ASIC Control Object to UnBlank CRTC. |
|---|
| 376 | 389 | */ |
|---|
| 377 | 390 | static void optc1_unblank_crtc(struct timing_generator *optc) |
|---|
| 378 | 391 | { |
|---|
| 379 | 392 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 380 | | - uint32_t vertical_interrupt_enable = 0; |
|---|
| 381 | | - |
|---|
| 382 | | - REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL, |
|---|
| 383 | | - OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &vertical_interrupt_enable); |
|---|
| 384 | | - |
|---|
| 385 | | - /* temporary work around for vertical interrupt, once vertical interrupt enabled, |
|---|
| 386 | | - * this check will be removed. |
|---|
| 387 | | - */ |
|---|
| 388 | | - if (vertical_interrupt_enable) |
|---|
| 389 | | - optc1_set_blank_data_double_buffer(optc, true); |
|---|
| 390 | 393 | |
|---|
| 391 | 394 | REG_UPDATE_2(OTG_BLANK_CONTROL, |
|---|
| 392 | 395 | OTG_BLANK_DATA_EN, 0, |
|---|
| 393 | 396 | OTG_BLANK_DE_MODE, 0); |
|---|
| 397 | + |
|---|
| 398 | + /* W/A for automated testing |
|---|
| 399 | + * Automated testing will fail underflow test as there |
|---|
| 400 | + * sporadic underflows which occur during the optc blank |
|---|
| 401 | + * sequence. As a w/a, clear underflow on unblank. |
|---|
| 402 | + * This prevents the failure, but will not mask actual |
|---|
| 403 | + * underflow that affect real use cases. |
|---|
| 404 | + */ |
|---|
| 405 | + optc1_clear_optc_underflow(optc); |
|---|
| 394 | 406 | } |
|---|
| 395 | 407 | |
|---|
| 396 | 408 | /** |
|---|
| .. | .. |
|---|
| 452 | 464 | OTG_CLOCK_ON, 1, |
|---|
| 453 | 465 | 1, 1000); |
|---|
| 454 | 466 | } else { |
|---|
| 467 | + |
|---|
| 468 | + //last chance to clear underflow, otherwise, it will always there due to clock is off. |
|---|
| 469 | + if (optc->funcs->is_optc_underflow_occurred(optc) == true) |
|---|
| 470 | + optc->funcs->clear_optc_underflow(optc); |
|---|
| 471 | + |
|---|
| 455 | 472 | REG_UPDATE_2(OTG_CLOCK_CONTROL, |
|---|
| 456 | 473 | OTG_CLOCK_GATE_DIS, 0, |
|---|
| 457 | 474 | OTG_CLOCK_EN, 0); |
|---|
| .. | .. |
|---|
| 484 | 501 | REG_UPDATE(CONTROL, |
|---|
| 485 | 502 | VTG0_ENABLE, 1); |
|---|
| 486 | 503 | |
|---|
| 504 | + REG_SEQ_START(); |
|---|
| 505 | + |
|---|
| 487 | 506 | /* Enable CRTC */ |
|---|
| 488 | 507 | REG_UPDATE_2(OTG_CONTROL, |
|---|
| 489 | 508 | OTG_DISABLE_POINT_CNTL, 3, |
|---|
| 490 | 509 | OTG_MASTER_EN, 1); |
|---|
| 510 | + |
|---|
| 511 | + REG_SEQ_SUBMIT(); |
|---|
| 512 | + REG_SEQ_WAIT_DONE(); |
|---|
| 491 | 513 | |
|---|
| 492 | 514 | return true; |
|---|
| 493 | 515 | } |
|---|
| .. | .. |
|---|
| 532 | 554 | struct timing_generator *optc, |
|---|
| 533 | 555 | const struct dc_crtc_timing *timing) |
|---|
| 534 | 556 | { |
|---|
| 535 | | - uint32_t interlace_factor; |
|---|
| 536 | 557 | uint32_t v_blank; |
|---|
| 537 | 558 | uint32_t h_blank; |
|---|
| 538 | 559 | uint32_t min_v_blank; |
|---|
| .. | .. |
|---|
| 540 | 561 | |
|---|
| 541 | 562 | ASSERT(timing != NULL); |
|---|
| 542 | 563 | |
|---|
| 543 | | - interlace_factor = timing->flags.INTERLACE ? 2 : 1; |
|---|
| 544 | 564 | v_blank = (timing->v_total - timing->v_addressable - |
|---|
| 545 | | - timing->v_border_top - timing->v_border_bottom) * |
|---|
| 546 | | - interlace_factor; |
|---|
| 565 | + timing->v_border_top - timing->v_border_bottom); |
|---|
| 547 | 566 | |
|---|
| 548 | 567 | h_blank = (timing->h_total - timing->h_addressable - |
|---|
| 549 | 568 | timing->h_border_right - |
|---|
| .. | .. |
|---|
| 615 | 634 | void optc1_lock(struct timing_generator *optc) |
|---|
| 616 | 635 | { |
|---|
| 617 | 636 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 637 | + uint32_t regval = 0; |
|---|
| 638 | + |
|---|
| 639 | + regval = REG_READ(OTG_CONTROL); |
|---|
| 640 | + |
|---|
| 641 | + /* otg is not running, do not need to be locked */ |
|---|
| 642 | + if ((regval & 0x1) == 0x0) |
|---|
| 643 | + return; |
|---|
| 618 | 644 | |
|---|
| 619 | 645 | REG_SET(OTG_GLOBAL_CONTROL0, 0, |
|---|
| 620 | 646 | OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); |
|---|
| .. | .. |
|---|
| 622 | 648 | OTG_MASTER_UPDATE_LOCK, 1); |
|---|
| 623 | 649 | |
|---|
| 624 | 650 | /* Should be fast, status does not update on maximus */ |
|---|
| 625 | | - if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) |
|---|
| 651 | + if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) { |
|---|
| 652 | + |
|---|
| 626 | 653 | REG_WAIT(OTG_MASTER_UPDATE_LOCK, |
|---|
| 627 | 654 | UPDATE_LOCK_STATUS, 1, |
|---|
| 628 | 655 | 1, 10); |
|---|
| 656 | + } |
|---|
| 629 | 657 | } |
|---|
| 630 | 658 | |
|---|
| 631 | 659 | void optc1_unlock(struct timing_generator *optc) |
|---|
| .. | .. |
|---|
| 805 | 833 | |
|---|
| 806 | 834 | void optc1_set_static_screen_control( |
|---|
| 807 | 835 | struct timing_generator *optc, |
|---|
| 808 | | - uint32_t value) |
|---|
| 836 | + uint32_t event_triggers, |
|---|
| 837 | + uint32_t num_frames) |
|---|
| 809 | 838 | { |
|---|
| 810 | 839 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 840 | + |
|---|
| 841 | + // By register spec, it only takes 8 bit value |
|---|
| 842 | + if (num_frames > 0xFF) |
|---|
| 843 | + num_frames = 0xFF; |
|---|
| 811 | 844 | |
|---|
| 812 | 845 | /* Bit 8 is no longer applicable in RV for PSR case, |
|---|
| 813 | 846 | * set bit 8 to 0 if given |
|---|
| 814 | 847 | */ |
|---|
| 815 | | - if ((value & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN) |
|---|
| 848 | + if ((event_triggers & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN) |
|---|
| 816 | 849 | != 0) |
|---|
| 817 | | - value = value & |
|---|
| 850 | + event_triggers = event_triggers & |
|---|
| 818 | 851 | ~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN; |
|---|
| 819 | 852 | |
|---|
| 820 | 853 | REG_SET_2(OTG_STATIC_SCREEN_CONTROL, 0, |
|---|
| 821 | | - OTG_STATIC_SCREEN_EVENT_MASK, value, |
|---|
| 822 | | - OTG_STATIC_SCREEN_FRAME_COUNT, 2); |
|---|
| 854 | + OTG_STATIC_SCREEN_EVENT_MASK, event_triggers, |
|---|
| 855 | + OTG_STATIC_SCREEN_FRAME_COUNT, num_frames); |
|---|
| 856 | +} |
|---|
| 857 | + |
|---|
| 858 | +void optc1_setup_manual_trigger(struct timing_generator *optc) |
|---|
| 859 | +{ |
|---|
| 860 | + struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 861 | + |
|---|
| 862 | + REG_SET(OTG_GLOBAL_CONTROL2, 0, |
|---|
| 863 | + MANUAL_FLOW_CONTROL_SEL, optc->inst); |
|---|
| 864 | + |
|---|
| 865 | + REG_SET_8(OTG_TRIGA_CNTL, 0, |
|---|
| 866 | + OTG_TRIGA_SOURCE_SELECT, 22, |
|---|
| 867 | + OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, |
|---|
| 868 | + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, |
|---|
| 869 | + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, |
|---|
| 870 | + OTG_TRIGA_POLARITY_SELECT, 0, |
|---|
| 871 | + OTG_TRIGA_FREQUENCY_SELECT, 0, |
|---|
| 872 | + OTG_TRIGA_DELAY, 0, |
|---|
| 873 | + OTG_TRIGA_CLEAR, 1); |
|---|
| 874 | +} |
|---|
| 875 | + |
|---|
| 876 | +void optc1_program_manual_trigger(struct timing_generator *optc) |
|---|
| 877 | +{ |
|---|
| 878 | + struct optc *optc1 = DCN10TG_FROM_TG(optc); |
|---|
| 879 | + |
|---|
| 880 | + REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, |
|---|
| 881 | + MANUAL_FLOW_CONTROL, 1); |
|---|
| 882 | + |
|---|
| 883 | + REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, |
|---|
| 884 | + MANUAL_FLOW_CONTROL, 0); |
|---|
| 823 | 885 | } |
|---|
| 824 | 886 | |
|---|
| 825 | 887 | |
|---|
| .. | .. |
|---|
| 842 | 904 | params->vertical_total_max > 0 && |
|---|
| 843 | 905 | params->vertical_total_min > 0) { |
|---|
| 844 | 906 | |
|---|
| 907 | + if (params->vertical_total_mid != 0) { |
|---|
| 908 | + |
|---|
| 909 | + REG_SET(OTG_V_TOTAL_MID, 0, |
|---|
| 910 | + OTG_V_TOTAL_MID, params->vertical_total_mid - 1); |
|---|
| 911 | + |
|---|
| 912 | + REG_UPDATE_2(OTG_V_TOTAL_CONTROL, |
|---|
| 913 | + OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, |
|---|
| 914 | + OTG_VTOTAL_MID_FRAME_NUM, |
|---|
| 915 | + (uint8_t)params->vertical_total_mid_frame_num); |
|---|
| 916 | + |
|---|
| 917 | + } |
|---|
| 918 | + |
|---|
| 845 | 919 | REG_SET(OTG_V_TOTAL_MAX, 0, |
|---|
| 846 | 920 | OTG_V_TOTAL_MAX, params->vertical_total_max - 1); |
|---|
| 847 | 921 | |
|---|
| .. | .. |
|---|
| 854 | 928 | OTG_FORCE_LOCK_ON_EVENT, 0, |
|---|
| 855 | 929 | OTG_SET_V_TOTAL_MIN_MASK_EN, 0, |
|---|
| 856 | 930 | OTG_SET_V_TOTAL_MIN_MASK, 0); |
|---|
| 931 | + |
|---|
| 932 | + // Setup manual flow control for EOF via TRIG_A |
|---|
| 933 | + optc->funcs->setup_manual_trigger(optc); |
|---|
| 934 | + |
|---|
| 857 | 935 | } else { |
|---|
| 858 | 936 | REG_UPDATE_4(OTG_V_TOTAL_CONTROL, |
|---|
| 859 | 937 | OTG_SET_V_TOTAL_MIN_MASK, 0, |
|---|
| .. | .. |
|---|
| 1161 | 1239 | REG_UPDATE_3(OTG_STEREO_CONTROL, |
|---|
| 1162 | 1240 | OTG_STEREO_EN, stereo_en, |
|---|
| 1163 | 1241 | OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0, |
|---|
| 1164 | | - OTG_STEREO_SYNC_OUTPUT_POLARITY, 0); |
|---|
| 1242 | + OTG_STEREO_SYNC_OUTPUT_POLARITY, flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1); |
|---|
| 1165 | 1243 | |
|---|
| 1166 | 1244 | if (flags->PROGRAM_POLARITY) |
|---|
| 1167 | 1245 | REG_UPDATE(OTG_STEREO_CONTROL, |
|---|
| .. | .. |
|---|
| 1173 | 1251 | OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1); |
|---|
| 1174 | 1252 | |
|---|
| 1175 | 1253 | if (flags->PROGRAM_STEREO) |
|---|
| 1176 | | - REG_UPDATE_3(OTG_3D_STRUCTURE_CONTROL, |
|---|
| 1254 | + REG_UPDATE_2(OTG_3D_STRUCTURE_CONTROL, |
|---|
| 1177 | 1255 | OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED, |
|---|
| 1178 | | - OTG_3D_STRUCTURE_V_UPDATE_MODE, flags->FRAME_PACKED, |
|---|
| 1179 | 1256 | OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED); |
|---|
| 1180 | 1257 | |
|---|
| 1181 | 1258 | } |
|---|
| .. | .. |
|---|
| 1206 | 1283 | |
|---|
| 1207 | 1284 | return ret; |
|---|
| 1208 | 1285 | } |
|---|
| 1286 | + |
|---|
| 1287 | +bool optc1_get_hw_timing(struct timing_generator *tg, |
|---|
| 1288 | + struct dc_crtc_timing *hw_crtc_timing) |
|---|
| 1289 | +{ |
|---|
| 1290 | + struct dcn_otg_state s = {0}; |
|---|
| 1291 | + |
|---|
| 1292 | + if (tg == NULL || hw_crtc_timing == NULL) |
|---|
| 1293 | + return false; |
|---|
| 1294 | + |
|---|
| 1295 | + optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); |
|---|
| 1296 | + |
|---|
| 1297 | + hw_crtc_timing->h_total = s.h_total + 1; |
|---|
| 1298 | + hw_crtc_timing->h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end); |
|---|
| 1299 | + hw_crtc_timing->h_front_porch = s.h_total + 1 - s.h_blank_start; |
|---|
| 1300 | + hw_crtc_timing->h_sync_width = s.h_sync_a_end - s.h_sync_a_start; |
|---|
| 1301 | + |
|---|
| 1302 | + hw_crtc_timing->v_total = s.v_total + 1; |
|---|
| 1303 | + hw_crtc_timing->v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end); |
|---|
| 1304 | + hw_crtc_timing->v_front_porch = s.v_total + 1 - s.v_blank_start; |
|---|
| 1305 | + hw_crtc_timing->v_sync_width = s.v_sync_a_end - s.v_sync_a_start; |
|---|
| 1306 | + |
|---|
| 1307 | + return true; |
|---|
| 1308 | +} |
|---|
| 1309 | + |
|---|
| 1209 | 1310 | |
|---|
| 1210 | 1311 | void optc1_read_otg_state(struct optc *optc1, |
|---|
| 1211 | 1312 | struct dcn_otg_state *s) |
|---|
| .. | .. |
|---|
| 1298 | 1399 | void optc1_tg_init(struct timing_generator *optc) |
|---|
| 1299 | 1400 | { |
|---|
| 1300 | 1401 | optc1_set_blank_data_double_buffer(optc, true); |
|---|
| 1402 | + optc1_set_timing_double_buffer(optc, true); |
|---|
| 1301 | 1403 | optc1_clear_optc_underflow(optc); |
|---|
| 1302 | 1404 | } |
|---|
| 1303 | 1405 | |
|---|
| .. | .. |
|---|
| 1393 | 1495 | static const struct timing_generator_funcs dcn10_tg_funcs = { |
|---|
| 1394 | 1496 | .validate_timing = optc1_validate_timing, |
|---|
| 1395 | 1497 | .program_timing = optc1_program_timing, |
|---|
| 1396 | | - .program_vline_interrupt = optc1_program_vline_interrupt, |
|---|
| 1498 | + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, |
|---|
| 1499 | + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, |
|---|
| 1500 | + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, |
|---|
| 1397 | 1501 | .program_global_sync = optc1_program_global_sync, |
|---|
| 1398 | 1502 | .enable_crtc = optc1_enable_crtc, |
|---|
| 1399 | 1503 | .disable_crtc = optc1_disable_crtc, |
|---|
| .. | .. |
|---|
| 1428 | 1532 | .clear_optc_underflow = optc1_clear_optc_underflow, |
|---|
| 1429 | 1533 | .get_crc = optc1_get_crc, |
|---|
| 1430 | 1534 | .configure_crc = optc1_configure_crc, |
|---|
| 1535 | + .set_vtg_params = optc1_set_vtg_params, |
|---|
| 1536 | + .program_manual_trigger = optc1_program_manual_trigger, |
|---|
| 1537 | + .setup_manual_trigger = optc1_setup_manual_trigger, |
|---|
| 1538 | + .get_hw_timing = optc1_get_hw_timing, |
|---|
| 1431 | 1539 | }; |
|---|
| 1432 | 1540 | |
|---|
| 1433 | 1541 | void dcn10_timing_generator_init(struct optc *optc1) |
|---|
| .. | .. |
|---|
| 1443 | 1551 | optc1->min_h_sync_width = 8; |
|---|
| 1444 | 1552 | optc1->min_v_sync_width = 1; |
|---|
| 1445 | 1553 | } |
|---|
| 1554 | + |
|---|
| 1555 | +/* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this: |
|---|
| 1556 | + * |
|---|
| 1557 | + * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as |
|---|
| 1558 | + * containter rate. |
|---|
| 1559 | + * |
|---|
| 1560 | + * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be |
|---|
| 1561 | + * halved to maintain the correct pixel rate. |
|---|
| 1562 | + * |
|---|
| 1563 | + * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied |
|---|
| 1564 | + * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well. |
|---|
| 1565 | + * |
|---|
| 1566 | + */ |
|---|
| 1567 | +bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) |
|---|
| 1568 | +{ |
|---|
| 1569 | + bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; |
|---|
| 1570 | + |
|---|
| 1571 | + two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 |
|---|
| 1572 | + && !timing->dsc_cfg.ycbcr422_simple); |
|---|
| 1573 | + return two_pix; |
|---|
| 1574 | +} |
|---|
| 1575 | + |
|---|