priv_state = drm_atomic_get_new_private_obj_state(state, &priv->private_obj); if (!priv_state) return NULL;
return to_ingenic_ipu_priv_state(priv_state);
}
/* * Apply conventional cubic convolution kernel. Both parameters * and return value are 15.16 signed fixed-point. * * @f_a: Sharpness factor, typically in range [-4.0, -0.25]. * A larger magnitude increases perceived sharpness, but going past * -2.0 might cause ringing artifacts to outweigh any improvement. * Nice values on a 320x240 LCD are between -0.75 and -2.0. * * @f_x: Absolute distance in pixels from 'pixel 0' sample position * along horizontal (or vertical) source axis. Range is [0, +2.0]. * * returns: Weight of this pixel within 4-pixel sample group. Range is * [-2.0, +2.0]. For moderate (i.e. > -3.0) sharpness factors, * range is within [-1.0, +1.0].
*/ staticinline s32 cubic_conv(s32 f_a, s32 f_x)
{ const s32 f_1 = I2F(1); const s32 f_2 = I2F(2); const s32 f_3 = I2F(3); const s32 f_4 = I2F(4); const s32 f_x2 = FMUL(f_x, f_x); const s32 f_x3 = FMUL(f_x, f_x2);
/* * On entry, "weight" is a coefficient suitable for bilinear mode, * which is converted to a set of four suitable for bicubic mode. * * "weight 512" means all of pixel 0; * "weight 256" means half of pixel 0 and half of pixel 1; * "weight 0" means all of pixel 1; * * "offset" is increment to next source pixel sample location.
*/ staticvoid jz4760_set_coefs(struct ingenic_ipu *ipu, unsignedint reg, unsignedint sharpness, bool downscale, unsignedint weight, unsignedint offset)
{
u32 val;
s32 w0, w1, w2, w3; /* Pixel weights at X (or Y) offsets -1,0,1,2 */
weight = clamp_val(weight, 0, 512);
if (sharpness < 2) { /* * When sharpness setting is 0, emulate nearest-neighbor. * When sharpness setting is 1, emulate bilinear.
*/
/* * Note that always rounding towards +infinity here is intended. * The resulting coefficients match a round-to-nearest-int * double floating-point implementation.
*/
staticvoid ingenic_ipu_set_integer_upscale_coefs(struct ingenic_ipu *ipu, unsignedint reg, unsignedint num)
{ /* * Force nearest-neighbor scaling and use simple math when upscaling * by an integer ratio. It looks better, and fixes a few problem cases.
*/ unsignedint i;
for (i = 0; i < num; i++)
ipu->soc_info->set_coefs(ipu, reg, 0, false, 512, i == num - 1);
}
if (!ipu->clk_enabled) {
err = clk_enable(ipu->clk); if (err) {
dev_err(ipu->dev, "Unable to enable clock: %d\n", err); return;
}
ipu->clk_enabled = true;
}
/* Reset all the registers if needed */
needs_modeset = drm_atomic_crtc_needs_modeset(newstate->crtc->state); if (needs_modeset) {
regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RST);
if (ingenic_drm_map_noncoherent(ipu->master))
drm_fb_dma_sync_non_coherent(ipu->drm, oldstate, newstate);
/* New addresses will be committed in vblank handler... */
ipu->addr_y = drm_fb_dma_get_gem_addr(newstate->fb, newstate, 0); if (finfo->num_planes > 1)
ipu->addr_u = drm_fb_dma_get_gem_addr(newstate->fb, newstate,
1); if (finfo->num_planes > 2)
ipu->addr_v = drm_fb_dma_get_gem_addr(newstate->fb, newstate,
2);
if (!needs_modeset) return;
/* Or right here if we're doing a full modeset. */
regmap_write(ipu->map, JZ_REG_IPU_Y_ADDR, ipu->addr_y);
regmap_write(ipu->map, JZ_REG_IPU_U_ADDR, ipu->addr_u);
regmap_write(ipu->map, JZ_REG_IPU_V_ADDR, ipu->addr_v);
if (finfo->num_planes == 1)
regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_SPKG_SEL);
switch (finfo->format) { case DRM_FORMAT_XRGB1555:
format = JZ_IPU_D_FMT_IN_FMT_RGB555 |
JZ_IPU_D_FMT_RGB_OUT_OFT_RGB; break; case DRM_FORMAT_XBGR1555:
format = JZ_IPU_D_FMT_IN_FMT_RGB555 |
JZ_IPU_D_FMT_RGB_OUT_OFT_BGR; break; case DRM_FORMAT_RGB565:
format = JZ_IPU_D_FMT_IN_FMT_RGB565 |
JZ_IPU_D_FMT_RGB_OUT_OFT_RGB; break; case DRM_FORMAT_BGR565:
format = JZ_IPU_D_FMT_IN_FMT_RGB565 |
JZ_IPU_D_FMT_RGB_OUT_OFT_BGR; break; case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XYUV8888:
format = JZ_IPU_D_FMT_IN_FMT_RGB888 |
JZ_IPU_D_FMT_RGB_OUT_OFT_RGB; break; case DRM_FORMAT_XBGR8888:
format = JZ_IPU_D_FMT_IN_FMT_RGB888 |
JZ_IPU_D_FMT_RGB_OUT_OFT_BGR; break; case DRM_FORMAT_YUYV:
format = JZ_IPU_D_FMT_IN_FMT_YUV422 |
JZ_IPU_D_FMT_YUV_VY1UY0; break; case DRM_FORMAT_YVYU:
format = JZ_IPU_D_FMT_IN_FMT_YUV422 |
JZ_IPU_D_FMT_YUV_UY1VY0; break; case DRM_FORMAT_UYVY:
format = JZ_IPU_D_FMT_IN_FMT_YUV422 |
JZ_IPU_D_FMT_YUV_Y1VY0U; break; case DRM_FORMAT_VYUY:
format = JZ_IPU_D_FMT_IN_FMT_YUV422 |
JZ_IPU_D_FMT_YUV_Y1UY0V; break; case DRM_FORMAT_YUV411:
format = JZ_IPU_D_FMT_IN_FMT_YUV411; break; case DRM_FORMAT_YUV420:
format = JZ_IPU_D_FMT_IN_FMT_YUV420; break; case DRM_FORMAT_YUV422:
format = JZ_IPU_D_FMT_IN_FMT_YUV422; break; case DRM_FORMAT_YUV444:
format = JZ_IPU_D_FMT_IN_FMT_YUV444; break; default:
WARN_ONCE(1, "Unsupported format"); break;
}
/* Fix output to RGB888 */
format |= JZ_IPU_D_FMT_OUT_FMT_RGB888;
/* Set pixel format */
regmap_write(ipu->map, JZ_REG_IPU_D_FMT, format);
if (finfo->is_yuv) {
regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_CSC_EN);
/* * Offsets for Chroma/Luma. * y = source Y - LUMA, * u = source Cb - CHROMA, * v = source Cr - CHROMA
*/
regmap_write(ipu->map, JZ_REG_IPU_CSC_OFFSET,
128 << JZ_IPU_CSC_OFFSET_CHROMA_LSB |
0 << JZ_IPU_CSC_OFFSET_LUMA_LSB);
/* * YUV422 to RGB conversion table. * R = C0 / 0x400 * y + C1 / 0x400 * v * G = C0 / 0x400 * y - C2 / 0x400 * u - C3 / 0x400 * v * B = C0 / 0x400 * y + C4 / 0x400 * u
*/
regmap_write(ipu->map, JZ_REG_IPU_CSC_C0_COEF, 0x4a8);
regmap_write(ipu->map, JZ_REG_IPU_CSC_C1_COEF, 0x662);
regmap_write(ipu->map, JZ_REG_IPU_CSC_C2_COEF, 0x191);
regmap_write(ipu->map, JZ_REG_IPU_CSC_C3_COEF, 0x341);
regmap_write(ipu->map, JZ_REG_IPU_CSC_C4_COEF, 0x811);
}
ctrl = 0;
/* * Must set ZOOM_SEL before programming bicubic LUTs. * If the IPU supports bicubic, we enable it unconditionally, since it * can do anything bilinear can and more.
*/ if (ipu->soc_info->has_bicubic)
ctrl |= JZ_IPU_CTRL_ZOOM_SEL;
upscaling_w = ipu_state->num_w > ipu_state->denom_w; if (upscaling_w)
ctrl |= JZ_IPU_CTRL_HSCALE;
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); if (WARN_ON(!crtc_state)) return -EINVAL;
ipu_state = ingenic_ipu_get_priv_state(ipu, state); if (IS_ERR(ipu_state)) return PTR_ERR(ipu_state);
/* Request a full modeset if we are enabling or disabling the IPU. */ if (!old_plane_state->crtc ^ !new_plane_state->crtc)
crtc_state->mode_changed = true;
if (!new_plane_state->crtc ||
!crtc_state->mode.hdisplay || !crtc_state->mode.vdisplay) goto out_check_damage;
/* Plane must be fully visible */ if (new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0 ||
new_plane_state->crtc_x + new_plane_state->crtc_w > crtc_state->mode.hdisplay ||
new_plane_state->crtc_y + new_plane_state->crtc_h > crtc_state->mode.vdisplay) return -EINVAL;
/* Minimum size is 4x4 */ if ((new_plane_state->src_w >> 16) < 4 || (new_plane_state->src_h >> 16) < 4) return -EINVAL;
/* Input and output lines must have an even number of pixels. */ if (((new_plane_state->src_w >> 16) & 1) || (new_plane_state->crtc_w & 1)) return -EINVAL;
if (!osd_changed(new_plane_state, old_plane_state)) goto out_check_damage;
/* * Increase the scaled image's theorical width/height until we find a * configuration that has valid scaling coefficients, up to 102% of the * screen's resolution. This makes sure that we can scale from almost * every resolution possible at the cost of a very small distorsion. * The CRTC_W / CRTC_H are not modified.
*/
max_w = crtc_state->mode.hdisplay * 102 / 100;
max_h = crtc_state->mode.vdisplay * 102 / 100;
for (denom_w = xres, num_w = new_plane_state->crtc_w; num_w <= max_w; num_w++) if (!reduce_fraction(&num_w, &denom_w)) break; if (num_w > max_w) return -EINVAL;
for (denom_h = yres, num_h = new_plane_state->crtc_h; num_h <= max_h; num_h++) if (!reduce_fraction(&num_h, &denom_h)) break; if (num_h > max_h) return -EINVAL;
staticconst u32 jz4725b_ipu_formats[] = { /* * While officially supported, packed YUV 4:2:2 formats can cause * random hardware crashes on JZ4725B under certain circumstances. * It seems to happen with some specific resize ratios. * Until a proper workaround or fix is found, disable these formats. DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, DRM_FORMAT_UYVY, DRM_FORMAT_VYUY,
*/
DRM_FORMAT_YUV411,
DRM_FORMAT_YUV420,
DRM_FORMAT_YUV422,
DRM_FORMAT_YUV444,
};
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.