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 int mdp4_hw_init(struct msm_kms *kms) { struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); struct drm_device *dev = mdp4_kms->dev; uint32_t version, major, minor, dmap_cfg, vg_cfg; unsigned long clk; int ret = 0; pm_runtime_get_sync(dev->dev); mdp4_enable(mdp4_kms); version = mdp4_read(mdp4_kms, REG_MDP4_VERSION); mdp4_disable(mdp4_kms); major = FIELD(version, MDP4_VERSION_MAJOR); minor = FIELD(version, MDP4_VERSION_MINOR); DBG("found MDP4 version v%d.%d", major, minor); if (major != 4) { dev_err(dev->dev, "unexpected MDP version: v%d.%d\n", major, minor); ret = -ENXIO; goto out; } mdp4_kms->rev = minor; if (mdp4_kms->rev > 1) { mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER0, 0x0707ffff); mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER1, 0x03073f3f); } mdp4_write(mdp4_kms, REG_MDP4_PORTMAP_MODE, 0x3); /* max read pending cmd config, 3 pending requests: */ mdp4_write(mdp4_kms, REG_MDP4_READ_CNFG, 0x02222); clk = clk_get_rate(mdp4_kms->clk); if ((mdp4_kms->rev >= 1) || (clk >= 90000000)) { dmap_cfg = 0x47; /* 16 bytes-burst x 8 req */ vg_cfg = 0x47; /* 16 bytes-burs x 8 req */ } else { dmap_cfg = 0x27; /* 8 bytes-burst x 8 req */ vg_cfg = 0x43; /* 16 bytes-burst x 4 req */ } DBG("fetch config: dmap=%02x, vg=%02x", dmap_cfg, vg_cfg); mdp4_write(mdp4_kms, REG_MDP4_DMA_FETCH_CONFIG(DMA_P), dmap_cfg); mdp4_write(mdp4_kms, REG_MDP4_DMA_FETCH_CONFIG(DMA_E), dmap_cfg); mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(VG1), vg_cfg); mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(VG2), vg_cfg); mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(RGB1), vg_cfg); mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(RGB2), vg_cfg); if (mdp4_kms->rev >= 2) mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD, 1); mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, 0); /* disable CSC matrix / YUV by default: */ mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0); mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG2), 0); mdp4_write(mdp4_kms, REG_MDP4_DMA_P_OP_MODE, 0); mdp4_write(mdp4_kms, REG_MDP4_DMA_S_OP_MODE, 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_CSC_CONFIG(1), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_CSC_CONFIG(2), 0); if (mdp4_kms->rev > 1) mdp4_write(mdp4_kms, REG_MDP4_RESET_STATUS, 1); dev->mode_config.allow_fb_modifiers = true; out: pm_runtime_put_sync(dev->dev); return ret; }
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; }