/* * OPTC uses ODM_MEM sub block to merge pixel data coming from different OPPs * into unified memory location per horizontal line. ODM_MEM contains shared * memory resources global to the ASIC. Each memory resource is capable of * storing 2048 pixels independent from actual pixel data size. Total number of * memory allocated must be even. The memory resource allocation is described in * a memory bit map per OPTC instance. Driver has to make sure that there is no * double allocation across different OPTC instances. Bit offset in the map * represents memory instance id. Driver allocates a memory instance to the * current OPTC by setting the bit with offset associated with the desired * memory instance to 1 in the current OPTC memory map register. * * It is upto software to decide how to allocate the shared memory resources * across different OPTC instances. Driver understands that the total number * of memory available is always 2 times the max number of OPP pipes. So each * OPP pipe can be mapped 2 pieces of memory. However there exists cases such as * 11520x2160 which could use 6 pieces of memory for 2 OPP pipes i.e. 3 pieces * for each OPP pipe. * * Driver will reserve the first and second preferred memory instances for each * OPP pipe. For example, OPP0's first and second preferred memory is ODM_MEM0 * and ODM_MEM1. OPP1's first and second preferred memory is ODM_MEM2 and * ODM_MEM3 so on so forth. * * Driver will first allocate from first preferred memory instances associated * with current OPP pipes in use. If needed driver will then allocate from * second preferred memory instances associated with current OPP pipes in use. * Finally if still needed, driver will allocate from second preferred memory * instances not associated with current OPP pipes. So if memory instances are * enough other OPTCs can still allocate from their OPPs' first preferred memory * instances without worrying about double allocation.
*/
static uint32_t decide_odm_mem_bit_map(int *opp_id, int opp_cnt, int h_active)
{ bool first_preferred_memory_for_opp[MAX_PIPES] = {0}; bool second_preferred_memory_for_opp[MAX_PIPES] = {0};
uint32_t memory_bit_map = 0; int total_required = ((h_active + 4095) / 4096) * 2; int total_allocated = 0; int i;
for (i = 0; i < opp_cnt; i++) {
first_preferred_memory_for_opp[opp_id[i]] = true;
total_allocated++; if (total_required == total_allocated) break;
}
if (total_required > total_allocated) { for (i = 0; i < opp_cnt; i++) {
second_preferred_memory_for_opp[opp_id[i]] = true;
total_allocated++; if (total_required == total_allocated) break;
}
}
if (total_required > total_allocated) { for (i = 0; i < MAX_PIPES; i++) { if (second_preferred_memory_for_opp[i] == false) {
second_preferred_memory_for_opp[i] = true;
total_allocated++; if (total_required == total_allocated) break;
}
}
}
ASSERT(total_required == total_allocated);
for (i = 0; i < MAX_PIPES; i++) { if (first_preferred_memory_for_opp[i])
memory_bit_map |= 0x1 << (i * 2); if (second_preferred_memory_for_opp[i])
memory_bit_map |= 0x2 << (i * 2);
}
return memory_bit_map;
}
void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, int segment_width, int last_segment_width)
{ struct optc *optc1 = DCN10TG_FROM_TG(optc);
uint32_t h_active = segment_width * (opp_cnt - 1) + last_segment_width;
uint32_t odm_mem_bit_map = decide_odm_mem_bit_map(
opp_id, opp_cnt, h_active);
/* only to be used when FAMS2 is disabled or unsupported */ void optc401_setup_manual_trigger(struct timing_generator *optc)
{ struct optc *optc1 = DCN10TG_FROM_TG(optc); struct dc *dc = optc->ctx->dc;
if (dc->caps.dmub_caps.fams_ver == 1 && !dc->debug.disable_fams) /* FAMS */
dc_dmub_srv_set_drr_manual_trigger_cmd(dc, optc->inst); else { /* * MIN_MASK_EN is gone and MASK is now always enabled. * * To get it to it work with manual trigger we need to make sure * we program the correct bit.
*/
REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
OTG_V_TOTAL_MIN_SEL, 1,
OTG_V_TOTAL_MAX_SEL, 1,
OTG_FORCE_LOCK_ON_EVENT, 0,
OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */
}
}
void optc401_program_global_sync( struct timing_generator *optc, int vready_offset, int vstartup_start, int vupdate_offset, int vupdate_width, int pstate_keepout)
{ struct optc *optc1 = DCN10TG_FROM_TG(optc);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.