int dpu_format_populate_layout( struct msm_gem_address_space *aspace, struct drm_framebuffer *fb, struct dpu_hw_fmt_layout *layout) { uint32_t plane_addr[DPU_MAX_PLANES]; int i, ret; if (!fb || !layout) { DRM_ERROR("invalid arguments\n"); return -EINVAL; } if ((fb->width > DPU_MAX_IMG_WIDTH) || (fb->height > DPU_MAX_IMG_HEIGHT)) { DRM_ERROR("image dimensions outside max range\n"); return -ERANGE; } layout->format = to_dpu_format(msm_framebuffer_format(fb)); /* Populate the plane sizes etc via get_format */ ret = dpu_format_get_plane_sizes(layout->format, fb->width, fb->height, layout, fb->pitches); if (ret) return ret; for (i = 0; i < DPU_MAX_PLANES; ++i) plane_addr[i] = layout->plane_addr[i]; /* Populate the addresses given the fb */ if (DPU_FORMAT_IS_UBWC(layout->format) || DPU_FORMAT_IS_TILE(layout->format)) ret = _dpu_format_populate_addrs_ubwc(aspace, fb, layout); else ret = _dpu_format_populate_addrs_linear(aspace, fb, layout); /* check if anything changed */ if (!ret && !memcmp(plane_addr, layout->plane_addr, sizeof(plane_addr))) ret = -EAGAIN; return ret; }
int mdp4_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); enum mpd4_pipe pipe = mdp4_plane->pipe; const struct mdp4_format *format; uint32_t op_mode = 0; uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; /* src values are in Q16 fixed point, convert to integer: */ src_x = src_x >> 16; src_y = src_y >> 16; src_w = src_w >> 16; src_h = src_h >> 16; if (src_w != crtc_w) { op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN; /* TODO calc phasex_step */ } if (src_h != crtc_h) { op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN; /* TODO calc phasey_step */ } mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe), MDP4_PIPE_SRC_SIZE_WIDTH(src_w) | MDP4_PIPE_SRC_SIZE_HEIGHT(src_h)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_XY(pipe), MDP4_PIPE_SRC_XY_X(src_x) | MDP4_PIPE_SRC_XY_Y(src_y)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_SIZE(pipe), MDP4_PIPE_DST_SIZE_WIDTH(crtc_w) | MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe), MDP4_PIPE_SRC_XY_X(crtc_x) | MDP4_PIPE_SRC_XY_Y(crtc_y)); mdp4_plane_set_scanout(plane, fb); format = to_mdp4_format(msm_framebuffer_format(fb)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe), MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | MDP4_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | MDP4_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) | MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe), MDP4_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | MDP4_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step); plane->crtc = crtc; return 0; }
static void blend_setup(struct drm_crtc *crtc) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct mdp4_kms *mdp4_kms = get_kms(crtc); int i, ovlp = mdp4_crtc->ovlp; uint32_t mixer_cfg = 0; static const enum mdp_mixer_stage_id stages[] = { STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3, }; /* statically (for now) map planes to mixer stage (z-order): */ static const int idxs[] = { [VG1] = 1, [VG2] = 2, [RGB1] = 0, [RGB2] = 0, [RGB3] = 0, [VG3] = 3, [VG4] = 4, }; bool alpha[4]= { false, false, false, false }; mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0); /* TODO single register for all CRTCs, so this won't work properly * when multiple CRTCs are active.. */ for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { struct drm_plane *plane = mdp4_crtc->planes[i]; if (plane) { enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); int idx = idxs[pipe_id]; if (idx > 0) { const struct mdp_format *format = to_mdp_format(msm_framebuffer_format(plane->fb)); alpha[idx-1] = format->alpha_enable; } mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]); } } /* this shouldn't happen.. and seems to cause underflow: */ WARN_ON(!mixer_cfg); for (i = 0; i < 4; i++) { uint32_t op; if (alpha[i]) { op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_PIXEL) | MDP4_OVLP_STAGE_OP_BG_ALPHA(FG_PIXEL) | MDP4_OVLP_STAGE_OP_BG_INV_ALPHA; } else { op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) | MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST); } mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0xff); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0x00); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i), op); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 1); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW0(ovlp, i), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW1(ovlp, i), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(ovlp, i), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0); } mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg); }
int mdp5_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); struct mdp5_kms *mdp5_kms = get_kms(plane); enum mdp5_pipe pipe = mdp5_plane->pipe; const struct mdp_format *format; uint32_t nplanes, config = 0; uint32_t phasex_step = 0, phasey_step = 0; uint32_t hdecm = 0, vdecm = 0; int i, nblks; nplanes = drm_format_num_planes(fb->pixel_format); /* bad formats should already be rejected: */ if (WARN_ON(nplanes > pipe2nclients(pipe))) return -EINVAL; /* src values are in Q16 fixed point, convert to integer: */ src_x = src_x >> 16; src_y = src_y >> 16; src_w = src_w >> 16; src_h = src_h >> 16; DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name, fb->base.id, src_x, src_y, src_w, src_h, crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); /* * Calculate and request required # of smp blocks: */ nblks = request_smp_blocks(plane, fb->pixel_format, nplanes, src_w); if (nblks < 0) return nblks; /* * Currently we update the hw for allocations/requests immediately, * but once atomic modeset/pageflip is in place, the allocation * would move into atomic->check_plane_state(), while updating the * hw would remain here: */ for (i = 0; i < pipe2nclients(pipe); i++) mdp5_smp_configure(mdp5_kms, pipe2client(pipe, i)); if (src_w != crtc_w) { config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN; /* TODO calc phasex_step, hdecm */ } if (src_h != crtc_h) { config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN; /* TODO calc phasey_step, vdecm */ } mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe), MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_w) | MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_h)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe), MDP5_PIPE_SRC_SIZE_WIDTH(src_w) | MDP5_PIPE_SRC_SIZE_HEIGHT(src_h)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe), MDP5_PIPE_SRC_XY_X(src_x) | MDP5_PIPE_SRC_XY_Y(src_y)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe), MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) | MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe), MDP5_PIPE_OUT_XY_X(crtc_x) | MDP5_PIPE_OUT_XY_Y(crtc_y)); mdp5_plane_set_scanout(plane, fb); format = to_mdp_format(msm_framebuffer_format(fb)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) | MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | MDP5_PIPE_SRC_FORMAT_NUM_PLANES(nplanes - 1) | MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS)); /* not using secure mode: */ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step); mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), MDP5_PIPE_DECIMATION_VERT(vdecm) | MDP5_PIPE_DECIMATION_HORZ(hdecm)); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) | MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) | MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) | MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) | MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) | MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST)); set_fifo_thresholds(plane, nblks); /* TODO detach from old crtc (if we had more than one) */ mdp5_crtc_attach(crtc, plane); return 0; }
static int mdp4_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { struct drm_device *dev = plane->dev; struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); enum mdp4_pipe pipe = mdp4_plane->pipe; const struct mdp_format *format; uint32_t op_mode = 0; uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; enum mdp4_frame_format frame_type; if (!(crtc && fb)) { DBG("%s: disabled!", mdp4_plane->name); return 0; } frame_type = mdp4_get_frame_format(fb); /* src values are in Q16 fixed point, convert to integer: */ src_x = src_x >> 16; src_y = src_y >> 16; src_w = src_w >> 16; src_h = src_h >> 16; DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name, fb->base.id, src_x, src_y, src_w, src_h, crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); format = to_mdp_format(msm_framebuffer_format(fb)); if (src_w > (crtc_w * DOWN_SCALE_MAX)) { dev_err(dev->dev, "Width down scaling exceeds limits!\n"); return -ERANGE; } if (src_h > (crtc_h * DOWN_SCALE_MAX)) { dev_err(dev->dev, "Height down scaling exceeds limits!\n"); return -ERANGE; } if (crtc_w > (src_w * UP_SCALE_MAX)) { dev_err(dev->dev, "Width up scaling exceeds limits!\n"); return -ERANGE; } if (crtc_h > (src_h * UP_SCALE_MAX)) { dev_err(dev->dev, "Height up scaling exceeds limits!\n"); return -ERANGE; } if (src_w != crtc_w) { uint32_t sel_unit = SCALE_FIR; op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN; if (MDP_FORMAT_IS_YUV(format)) { if (crtc_w > src_w) sel_unit = SCALE_PIXEL_RPT; else if (crtc_w <= (src_w / 4)) sel_unit = SCALE_MN_PHASE; op_mode |= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit); phasex_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT, src_w, crtc_w); } } if (src_h != crtc_h) { uint32_t sel_unit = SCALE_FIR; op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN; if (MDP_FORMAT_IS_YUV(format)) { if (crtc_h > src_h) sel_unit = SCALE_PIXEL_RPT; else if (crtc_h <= (src_h / 4)) sel_unit = SCALE_MN_PHASE; op_mode |= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit); phasey_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT, src_h, crtc_h); } } mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe), MDP4_PIPE_SRC_SIZE_WIDTH(src_w) | MDP4_PIPE_SRC_SIZE_HEIGHT(src_h)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_XY(pipe), MDP4_PIPE_SRC_XY_X(src_x) | MDP4_PIPE_SRC_XY_Y(src_y)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_SIZE(pipe), MDP4_PIPE_DST_SIZE_WIDTH(crtc_w) | MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe), MDP4_PIPE_DST_XY_X(crtc_x) | MDP4_PIPE_DST_XY_Y(crtc_y)); mdp4_plane_set_scanout(plane, fb); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe), MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | MDP4_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | MDP4_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) | MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format->fetch_type) | MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample) | MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(frame_type) | COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe), MDP4_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | MDP4_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); if (MDP_FORMAT_IS_YUV(format)) { struct csc_cfg *csc = mdp_get_default_csc_cfg(CSC_YUV2RGB); op_mode |= MDP4_PIPE_OP_MODE_SRC_YCBCR; op_mode |= MDP4_PIPE_OP_MODE_CSC_EN; mdp4_write_csc_config(mdp4_kms, pipe, csc); } mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step); if (frame_type != FRAME_LINEAR) mdp4_write(mdp4_kms, REG_MDP4_PIPE_SSTILE_FRAME_SIZE(pipe), MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(src_w) | MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(src_h)); return 0; }