/* Later we can separate the rotation and scaler calc. If * rotation is enabled, simply swap the destination dimension. * And then pass the already swapped output size to this * function. */ static int vpe_update_scaler(struct video_crop_t *pcrop) { uint32_t out_ROI_width, out_ROI_height; uint32_t src_ROI_width, src_ROI_height; uint32_t rc = 0; /* default to no zoom. */ /* * phase_step_x, phase_step_y, phase_init_x and phase_init_y * are represented in fixed-point, unsigned 3.29 format */ uint32_t phase_step_x = 0; uint32_t phase_step_y = 0; uint32_t phase_init_x = 0; uint32_t phase_init_y = 0; uint32_t src_roi, src_x, src_y, src_xy, temp; uint32_t yscale_filter_sel, xscale_filter_sel; uint32_t scale_unit_sel_x, scale_unit_sel_y; uint64_t numerator, denominator; if ((pcrop->in2_w >= pcrop->out2_w) && (pcrop->in2_h >= pcrop->out2_h)) { CDBG(" =======VPE no zoom needed.\n"); temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) & 0xfffffffc; msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET); msm_io_w(0, vpe_device->vpebase + VPE_SRC_XY_OFFSET); CDBG("vpe_ctrl->in_h_w = %d \n", vpe_ctrl->in_h_w); msm_io_w(vpe_ctrl->in_h_w , vpe_device->vpebase + VPE_SRC_SIZE_OFFSET); return rc; } /* If fall through then scaler is needed.*/ CDBG("========VPE zoom needed.\n"); /* assumption is both direction need zoom. this can be improved. */ temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) | 0x3; msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET); src_ROI_width = pcrop->in2_w; src_ROI_height = pcrop->in2_h; out_ROI_width = pcrop->out2_w; out_ROI_height = pcrop->out2_h; CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n", src_ROI_width, src_ROI_height, out_ROI_width, out_ROI_height); src_roi = (src_ROI_height << 16) + src_ROI_width; msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET); src_x = (out_ROI_width - src_ROI_width)/2; src_y = (out_ROI_height - src_ROI_height)/2; CDBG("src_x = %d, src_y=%d.\n", src_x, src_y); src_xy = src_y*(1<<16) + src_x; msm_io_w(src_xy, vpe_device->vpebase + VPE_SRC_XY_OFFSET); CDBG("src_xy = %d, src_roi=%d.\n", src_xy, src_roi); /* decide whether to use FIR or M/N for scaling */ if ((out_ROI_width == 1 && src_ROI_width < 4) || (src_ROI_width < 4 * out_ROI_width - 3)) scale_unit_sel_x = 0;/* use FIR scalar */ else scale_unit_sel_x = 1;/* use M/N scalar */ if ((out_ROI_height == 1 && src_ROI_height < 4) || (src_ROI_height < 4 * out_ROI_height - 3)) scale_unit_sel_y = 0;/* use FIR scalar */ else scale_unit_sel_y = 1;/* use M/N scalar */ /* calculate phase step for the x direction */ /* if destination is only 1 pixel wide, the value of phase_step_x is unimportant. Assigning phase_step_x to src ROI width as an arbitrary value. */ if (out_ROI_width == 1) phase_step_x = (uint32_t) ((src_ROI_width) << SCALER_PHASE_BITS); /* if using FIR scalar */ else if (scale_unit_sel_x == 0) { /* Calculate the quotient ( src_ROI_width - 1 ) / ( out_ROI_width - 1) with u3.29 precision. Quotient is rounded up to the larger 29th decimal point. */ numerator = (uint64_t)(src_ROI_width - 1) << SCALER_PHASE_BITS; /* never equals to 0 because of the "(out_ROI_width == 1 )"*/ denominator = (uint64_t)(out_ROI_width - 1); /* divide and round up to the larger 29th decimal point. */ phase_step_x = (uint32_t) vpe_do_div((numerator + denominator - 1), denominator); } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ /* Calculate the quotient ( src_ROI_width ) / ( out_ROI_width) with u3.29 precision. Quotient is rounded down to the smaller 29th decimal point. */ numerator = (uint64_t)(src_ROI_width) << SCALER_PHASE_BITS; denominator = (uint64_t)(out_ROI_width); phase_step_x = (uint32_t) vpe_do_div(numerator, denominator); } /* calculate phase step for the y direction */ /* if destination is only 1 pixel wide, the value of phase_step_x is unimportant. Assigning phase_step_x to src ROI width as an arbitrary value. */ if (out_ROI_height == 1) phase_step_y = (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); /* if FIR scalar */ else if (scale_unit_sel_y == 0) { /* Calculate the quotient ( src_ROI_height - 1 ) / ( out_ROI_height - 1) with u3.29 precision. Quotient is rounded up to the larger 29th decimal point. */ numerator = (uint64_t)(src_ROI_height - 1) << SCALER_PHASE_BITS; /* never equals to 0 because of the " ( out_ROI_height == 1 )" case */ denominator = (uint64_t)(out_ROI_height - 1); /* Quotient is rounded up to the larger 29th decimal point. */ phase_step_y = (uint32_t) vpe_do_div( (numerator + denominator - 1), denominator); } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ /* Calculate the quotient ( src_ROI_height ) / ( out_ROI_height) with u3.29 precision. Quotient is rounded down to the smaller 29th decimal point. */ numerator = (uint64_t)(src_ROI_height) << SCALER_PHASE_BITS; denominator = (uint64_t)(out_ROI_height); phase_step_y = (uint32_t) vpe_do_div( numerator, denominator); } /* decide which set of FIR coefficients to use */ if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) xscale_filter_sel = 0; else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) xscale_filter_sel = 1; else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) xscale_filter_sel = 2; else xscale_filter_sel = 3; if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) yscale_filter_sel = 0; else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) yscale_filter_sel = 1; else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) yscale_filter_sel = 2; else yscale_filter_sel = 3; /* calculate phase init for the x direction */ /* if using FIR scalar */ if (scale_unit_sel_x == 0) { if (out_ROI_width == 1) phase_init_x = (uint32_t) ((src_ROI_width - 1) << SCALER_PHASE_BITS); else phase_init_x = 0; } else if (scale_unit_sel_x == 1) /* M over N scalar */ phase_init_x = 0; /* calculate phase init for the y direction if using FIR scalar */ if (scale_unit_sel_y == 0) { if (out_ROI_height == 1) phase_init_y = (uint32_t) ((src_ROI_height - 1) << SCALER_PHASE_BITS); else phase_init_y = 0; } else if (scale_unit_sel_y == 1) /* M over N scalar */ phase_init_y = 0; CDBG("phase step x = %d, step y = %d.\n", phase_step_x, phase_step_y); CDBG("phase init x = %d, init y = %d.\n", phase_init_x, phase_init_y); msm_io_w(phase_step_x, vpe_device->vpebase + VPE_SCALE_PHASEX_STEP_OFFSET); msm_io_w(phase_step_y, vpe_device->vpebase + VPE_SCALE_PHASEY_STEP_OFFSET); msm_io_w(phase_init_x, vpe_device->vpebase + VPE_SCALE_PHASEX_INIT_OFFSET); msm_io_w(phase_init_y, vpe_device->vpebase + VPE_SCALE_PHASEY_INIT_OFFSET); return 1; }
static int vpe_update_scaler_with_dis(struct video_crop_t *pcrop, struct dis_offset_type *dis_offset) { uint32_t out_ROI_width, out_ROI_height; uint32_t src_ROI_width, src_ROI_height; uint32_t rc = 0; /* default to no zoom. */ /* * phase_step_x, phase_step_y, phase_init_x and phase_init_y * are represented in fixed-point, unsigned 3.29 format */ uint32_t phase_step_x = 0; uint32_t phase_step_y = 0; uint32_t phase_init_x = 0; uint32_t phase_init_y = 0; uint32_t src_roi, temp; int32_t src_x, src_y, src_xy; uint32_t yscale_filter_sel, xscale_filter_sel; uint32_t scale_unit_sel_x, scale_unit_sel_y; uint64_t numerator, denominator; int32_t zoom_dis_x, zoom_dis_y; CDBG("%s: pcrop->in2_w = %d, pcrop->in2_h = %d\n", __func__, pcrop->in2_w, pcrop->in2_h); CDBG("%s: pcrop->out2_w = %d, pcrop->out2_h = %d\n", __func__, pcrop->out2_w, pcrop->out2_h); if ((pcrop->in2_w >= pcrop->out2_w) && (pcrop->in2_h >= pcrop->out2_h)) { CDBG(" =======VPE no zoom needed, DIS is still enabled. \n"); temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) & 0xfffffffc; msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET); /* no zoom, use dis offset directly. */ src_xy = dis_offset->dis_offset_y * (1<<16) + dis_offset->dis_offset_x; msm_io_w(src_xy, vpe_device->vpebase + VPE_SRC_XY_OFFSET); CDBG("vpe_ctrl->in_h_w = 0x%x \n", vpe_ctrl->in_h_w); msm_io_w(vpe_ctrl->in_h_w, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET); return rc; } /* If fall through then scaler is needed.*/ CDBG("========VPE zoom needed + DIS enabled.\n"); /* assumption is both direction need zoom. this can be improved. */ temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) | 0x3; msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET); zoom_dis_x = dis_offset->dis_offset_x * pcrop->in2_w / pcrop->out2_w; zoom_dis_y = dis_offset->dis_offset_y * pcrop->in2_h / pcrop->out2_h; src_x = zoom_dis_x + (pcrop->out2_w-pcrop->in2_w)/2; src_y = zoom_dis_y + (pcrop->out2_h-pcrop->in2_h)/2; out_ROI_width = vpe_ctrl->out_w; out_ROI_height = vpe_ctrl->out_h; src_ROI_width = out_ROI_width * pcrop->in2_w / pcrop->out2_w; src_ROI_height = out_ROI_height * pcrop->in2_h / pcrop->out2_h; /* clamp to output size. This is because along processing, we mostly do truncation, therefore dis_offset tends to be smaller values. The intention was to make sure that the offset does not exceed margin. But in the case it could result src_roi bigger, due to subtract a smaller value. */ CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n", src_ROI_width, src_ROI_height, out_ROI_width, out_ROI_height); src_roi = (src_ROI_height << 16) + src_ROI_width; msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET); CDBG("src_x = %d, src_y=%d.\n", src_x, src_y); src_xy = src_y*(1<<16) + src_x; msm_io_w(src_xy, vpe_device->vpebase + VPE_SRC_XY_OFFSET); CDBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi); /* decide whether to use FIR or M/N for scaling */ if ((out_ROI_width == 1 && src_ROI_width < 4) || (src_ROI_width < 4 * out_ROI_width - 3)) scale_unit_sel_x = 0;/* use FIR scalar */ else scale_unit_sel_x = 1;/* use M/N scalar */ if ((out_ROI_height == 1 && src_ROI_height < 4) || (src_ROI_height < 4 * out_ROI_height - 3)) scale_unit_sel_y = 0;/* use FIR scalar */ else scale_unit_sel_y = 1;/* use M/N scalar */ /* calculate phase step for the x direction */ /* if destination is only 1 pixel wide, the value of phase_step_x is unimportant. Assigning phase_step_x to src ROI width as an arbitrary value. */ if (out_ROI_width == 1) phase_step_x = (uint32_t) ((src_ROI_width) << SCALER_PHASE_BITS); else if (scale_unit_sel_x == 0) { /* if using FIR scalar */ /* Calculate the quotient ( src_ROI_width - 1 ) / ( out_ROI_width - 1)with u3.29 precision. Quotient is rounded up to the larger 29th decimal point. */ numerator = (uint64_t)(src_ROI_width - 1) << SCALER_PHASE_BITS; /* never equals to 0 because of the " (out_ROI_width == 1 )"*/ denominator = (uint64_t)(out_ROI_width - 1); /* divide and round up to the larger 29th decimal point. */ phase_step_x = (uint32_t) vpe_do_div( (numerator + denominator - 1), denominator); } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ /* Calculate the quotient ( src_ROI_width ) / ( out_ROI_width) with u3.29 precision. Quotient is rounded down to the smaller 29th decimal point. */ numerator = (uint64_t)(src_ROI_width) << SCALER_PHASE_BITS; denominator = (uint64_t)(out_ROI_width); phase_step_x = (uint32_t) vpe_do_div(numerator, denominator); } /* calculate phase step for the y direction */ /* if destination is only 1 pixel wide, the value of phase_step_x is unimportant. Assigning phase_step_x to src ROI width as an arbitrary value. */ if (out_ROI_height == 1) phase_step_y = (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); else if (scale_unit_sel_y == 0) { /* if FIR scalar */ /* Calculate the quotient ( src_ROI_height - 1 ) / ( out_ROI_height - 1) with u3.29 precision. Quotient is rounded up to the larger 29th decimal point. */ numerator = (uint64_t)(src_ROI_height - 1) << SCALER_PHASE_BITS; /* never equals to 0 because of the "( out_ROI_height == 1 )" case */ denominator = (uint64_t)(out_ROI_height - 1); /* Quotient is rounded up to the larger 29th decimal point. */ phase_step_y = (uint32_t) vpe_do_div( (numerator + denominator - 1), denominator); } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ /* Calculate the quotient ( src_ROI_height ) / ( out_ROI_height) with u3.29 precision. Quotient is rounded down to the smaller 29th decimal point. */ numerator = (uint64_t)(src_ROI_height) << SCALER_PHASE_BITS; denominator = (uint64_t)(out_ROI_height); phase_step_y = (uint32_t) vpe_do_div( numerator, denominator); } /* decide which set of FIR coefficients to use */ if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) xscale_filter_sel = 0; else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) xscale_filter_sel = 1; else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) xscale_filter_sel = 2; else xscale_filter_sel = 3; if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) yscale_filter_sel = 0; else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) yscale_filter_sel = 1; else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) yscale_filter_sel = 2; else yscale_filter_sel = 3; /* calculate phase init for the x direction */ /* if using FIR scalar */ if (scale_unit_sel_x == 0) { if (out_ROI_width == 1) phase_init_x = (uint32_t) ((src_ROI_width - 1) << SCALER_PHASE_BITS); else phase_init_x = 0; } else if (scale_unit_sel_x == 1) /* M over N scalar */ phase_init_x = 0; /* calculate phase init for the y direction if using FIR scalar */ if (scale_unit_sel_y == 0) { if (out_ROI_height == 1) phase_init_y = (uint32_t) ((src_ROI_height - 1) << SCALER_PHASE_BITS); else phase_init_y = 0; } else if (scale_unit_sel_y == 1) /* M over N scalar */ phase_init_y = 0; CDBG("phase step x = %d, step y = %d.\n", phase_step_x, phase_step_y); CDBG("phase init x = %d, init y = %d.\n", phase_init_x, phase_init_y); msm_io_w(phase_step_x, vpe_device->vpebase + VPE_SCALE_PHASEX_STEP_OFFSET); msm_io_w(phase_step_y, vpe_device->vpebase + VPE_SCALE_PHASEY_STEP_OFFSET); msm_io_w(phase_init_x, vpe_device->vpebase + VPE_SCALE_PHASEX_INIT_OFFSET); msm_io_w(phase_init_y, vpe_device->vpebase + VPE_SCALE_PHASEY_INIT_OFFSET); return 1; }
static int vpe_update_scaler(struct msm_pp_crop *pcrop) { uint32_t out_ROI_width, out_ROI_height; uint32_t src_ROI_width, src_ROI_height; uint32_t phase_step_x = 0; uint32_t phase_step_y = 0; uint32_t phase_init_x = 0; uint32_t phase_init_y = 0; uint32_t src_roi, src_x, src_y, src_xy, temp; uint32_t yscale_filter_sel, xscale_filter_sel; uint32_t scale_unit_sel_x, scale_unit_sel_y; uint64_t numerator, denominator; temp = msm_io_r(vpe_ctrl->vpebase + VPE_OP_MODE_OFFSET) | 0x3; msm_io_w(temp, vpe_ctrl->vpebase + VPE_OP_MODE_OFFSET); src_ROI_width = pcrop->src_w; src_ROI_height = pcrop->src_h; out_ROI_width = pcrop->dst_w; out_ROI_height = pcrop->dst_h; CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n", src_ROI_width, src_ROI_height, out_ROI_width, out_ROI_height); src_roi = (src_ROI_height << 16) + src_ROI_width; msm_io_w(src_roi, vpe_ctrl->vpebase + VPE_SRC_SIZE_OFFSET); src_x = pcrop->src_x; src_y = pcrop->src_y; CDBG("src_x = %d, src_y=%d.\n", src_x, src_y); src_xy = src_y*(1<<16) + src_x; msm_io_w(src_xy, vpe_ctrl->vpebase + VPE_SRC_XY_OFFSET); CDBG("src_xy = %d, src_roi=%d.\n", src_xy, src_roi); if ((out_ROI_width == 1 && src_ROI_width < 4) || (src_ROI_width < 4 * out_ROI_width - 3)) scale_unit_sel_x = 0; else scale_unit_sel_x = 1; if ((out_ROI_height == 1 && src_ROI_height < 4) || (src_ROI_height < 4 * out_ROI_height - 3)) scale_unit_sel_y = 0; else scale_unit_sel_y = 1; if (out_ROI_width == 1) phase_step_x = (uint32_t) ((src_ROI_width) << SCALER_PHASE_BITS); else if (scale_unit_sel_x == 0) { numerator = (uint64_t)(src_ROI_width - 1) << SCALER_PHASE_BITS; denominator = (uint64_t)(out_ROI_width - 1); phase_step_x = (uint32_t) vpe_do_div((numerator + denominator - 1), denominator); } else if (scale_unit_sel_x == 1) { numerator = (uint64_t)(src_ROI_width) << SCALER_PHASE_BITS; denominator = (uint64_t)(out_ROI_width); phase_step_x = (uint32_t) vpe_do_div(numerator, denominator); } if (out_ROI_height == 1) phase_step_y = (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); else if (scale_unit_sel_y == 0) { numerator = (uint64_t)(src_ROI_height - 1) << SCALER_PHASE_BITS; denominator = (uint64_t)(out_ROI_height - 1); phase_step_y = (uint32_t) vpe_do_div( (numerator + denominator - 1), denominator); } else if (scale_unit_sel_y == 1) { numerator = (uint64_t)(src_ROI_height) << SCALER_PHASE_BITS; denominator = (uint64_t)(out_ROI_height); phase_step_y = (uint32_t) vpe_do_div( numerator, denominator); } if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) xscale_filter_sel = 0; else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) xscale_filter_sel = 1; else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) xscale_filter_sel = 2; else xscale_filter_sel = 3; if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) yscale_filter_sel = 0; else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) yscale_filter_sel = 1; else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) yscale_filter_sel = 2; else yscale_filter_sel = 3; if (scale_unit_sel_x == 0) { if (out_ROI_width == 1) phase_init_x = (uint32_t) ((src_ROI_width - 1) << SCALER_PHASE_BITS); else phase_init_x = 0; } else if (scale_unit_sel_x == 1) phase_init_x = 0; if (scale_unit_sel_y == 0) { if (out_ROI_height == 1) phase_init_y = (uint32_t) ((src_ROI_height - 1) << SCALER_PHASE_BITS); else phase_init_y = 0; } else if (scale_unit_sel_y == 1) phase_init_y = 0; CDBG("phase step x = %d, step y = %d.\n", phase_step_x, phase_step_y); CDBG("phase init x = %d, init y = %d.\n", phase_init_x, phase_init_y); msm_io_w(phase_step_x, vpe_ctrl->vpebase + VPE_SCALE_PHASEX_STEP_OFFSET); msm_io_w(phase_step_y, vpe_ctrl->vpebase + VPE_SCALE_PHASEY_STEP_OFFSET); msm_io_w(phase_init_x, vpe_ctrl->vpebase + VPE_SCALE_PHASEX_INIT_OFFSET); msm_io_w(phase_init_y, vpe_ctrl->vpebase + VPE_SCALE_PHASEY_INIT_OFFSET); return 1; }