From 5d51f6c0da1b563e2f8eb5022a4d7748aa687be4 Mon Sep 17 00:00:00 2001 From: "james qian wang (Arm Technology China)" Date: Thu, 23 May 2019 10:36:38 +0100 Subject: drm/komeda: Add writeback support Komeda driver uses a individual component to describe the HW's writeback caps, but drivers doesn't define a new structure and still uses the existing "struct komeda_layer" to describe this new component. The detailed changes as follow: 1. Initialize wb_layer according to HW and report it to CORE. 2. CORE exposes wb_layer as a resource to KMS by private_obj. 3. Report writeback supporting by add a wb_connector to KMS, and then wb_connector will take act as a component resources user, so the func komeda_wb_encoder_atomic_check claims komeda resources (scaler and wb_layer) accroding to its state configuration to the wb_connector. and the wb_state configuration will be validated on the specific component resources to see if the caps of component can meet the requirement of wb_connector. if not check failed. 4. Update irq_handler to notify the completion of writeback. NOTE: This change doesn't add scaling writeback support, that support will be added in the future after the scaler support. v2: Rebase v3: Rebase and constify the d71_wb_layer_funcs v4: Addressed Ayan's comments Depends on: - https://patchwork.freedesktop.org/series/59915/ Signed-off-by: James Qian Wang (Arm Technology China) Acked-by: Ayan Kumar Halder Signed-off-by: Liviu Dudau --- drivers/gpu/drm/arm/display/komeda/Makefile | 1 + .../gpu/drm/arm/display/komeda/d71/d71_component.c | 90 +++++++++- drivers/gpu/drm/arm/display/komeda/komeda_crtc.c | 15 ++ .../drm/arm/display/komeda/komeda_framebuffer.c | 19 +++ drivers/gpu/drm/arm/display/komeda/komeda_kms.c | 4 + drivers/gpu/drm/arm/display/komeda/komeda_kms.h | 27 +++ .../gpu/drm/arm/display/komeda/komeda_pipeline.h | 7 + .../drm/arm/display/komeda/komeda_pipeline_state.c | 51 +++++- .../drm/arm/display/komeda/komeda_private_obj.c | 6 + .../drm/arm/display/komeda/komeda_wb_connector.c | 181 +++++++++++++++++++++ 10 files changed, 398 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile index 412eeba8c39f..16a1ea443de2 100644 --- a/drivers/gpu/drm/arm/display/komeda/Makefile +++ b/drivers/gpu/drm/arm/display/komeda/Makefile @@ -14,6 +14,7 @@ komeda-y := \ komeda_kms.o \ komeda_crtc.o \ komeda_plane.o \ + komeda_wb_connector.o \ komeda_private_obj.o komeda-y += \ diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c index 6bab816ed8e7..323e5994a55c 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c @@ -288,10 +288,98 @@ static int d71_layer_init(struct d71_dev *d71, return 0; } +static void d71_wb_layer_update(struct komeda_component *c, + struct komeda_component_state *state) +{ + struct komeda_layer_state *st = to_layer_st(state); + struct drm_connector_state *conn_st = state->wb_conn->state; + struct drm_framebuffer *fb = conn_st->writeback_job->fb; + struct komeda_fb *kfb = to_kfb(fb); + u32 __iomem *reg = c->reg; + u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN; + int i; + + for (i = 0; i < fb->format->num_planes; i++) { + malidp_write32(reg + i * LAYER_PER_PLANE_REGS, BLK_P0_PTR_LOW, + lower_32_bits(st->addr[i])); + malidp_write32(reg + i * LAYER_PER_PLANE_REGS, BLK_P0_PTR_HIGH, + upper_32_bits(st->addr[i])); + + malidp_write32(reg + i * LAYER_PER_PLANE_REGS, BLK_P0_STRIDE, + fb->pitches[i] & 0xFFFF); + } + + malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id); + malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize)); + malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0])); + malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); +} + +static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf) +{ + u32 v[12], i; + + dump_block_header(sf, c->reg); + + get_values_from_reg(c->reg, 0x80, 1, v); + seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]); + + get_values_from_reg(c->reg, 0xD0, 3, v); + seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]); + seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]); + seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]); + + get_values_from_reg(c->reg, 0xE0, 1, v); + seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]); + + for (i = 0; i < 2; i++) { + get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v); + seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]); + seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]); + seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]); + } + + get_values_from_reg(c->reg, 0x130, 12, v); + for (i = 0; i < 12; i++) + seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]); +} + +static void d71_wb_layer_disable(struct komeda_component *c) +{ + malidp_write32(c->reg, BLK_INPUT_ID0, 0); + malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0); +} + +static const struct komeda_component_funcs d71_wb_layer_funcs = { + .update = d71_wb_layer_update, + .disable = d71_wb_layer_disable, + .dump_register = d71_wb_layer_dump, +}; + static int d71_wb_layer_init(struct d71_dev *d71, struct block_header *blk, u32 __iomem *reg) { - DRM_DEBUG("Detect D71_Wb_Layer.\n"); + struct komeda_component *c; + struct komeda_layer *wb_layer; + u32 pipe_id, layer_id; + + get_resources_id(blk->block_info, &pipe_id, &layer_id); + + c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer), + layer_id, BLOCK_INFO_INPUT_ID(blk->block_info), + &d71_wb_layer_funcs, + 1, get_valid_inputs(blk), 0, reg, + "LPU%d_LAYER_WR", pipe_id); + if (IS_ERR(c)) { + DRM_ERROR("Failed to add wb_layer component\n"); + return PTR_ERR(c); + } + + wb_layer = to_layer(c); + wb_layer->layer_type = KOMEDA_FMT_WB_LAYER; + + set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size); + set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize); return 0; } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 284ce079d8c4..6712603b8c7a 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -165,6 +165,15 @@ void komeda_crtc_handle_event(struct komeda_crtc *kcrtc, if (events & KOMEDA_EVENT_VSYNC) drm_crtc_handle_vblank(crtc); + if (events & KOMEDA_EVENT_EOW) { + struct komeda_wb_connector *wb_conn = kcrtc->wb_conn; + + if (wb_conn) + drm_writeback_signal_completion(&wb_conn->base, 0); + else + DRM_WARN("CRTC[%d]: EOW happen but no wb_connector.\n", + drm_crtc_index(&kcrtc->base)); + } /* will handle it together with the write back support */ if (events & KOMEDA_EVENT_EOW) DRM_DEBUG("EOW.\n"); @@ -201,6 +210,8 @@ komeda_crtc_do_flush(struct drm_crtc *crtc, struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc->state); struct komeda_dev *mdev = kcrtc->base.dev->dev_private; struct komeda_pipeline *master = kcrtc->master; + struct komeda_wb_connector *wb_conn = kcrtc->wb_conn; + struct drm_connector_state *conn_st; DRM_DEBUG_ATOMIC("CRTC%d_FLUSH: active_pipes: 0x%x, affected: 0x%x.\n", drm_crtc_index(crtc), @@ -210,6 +221,10 @@ komeda_crtc_do_flush(struct drm_crtc *crtc, if (has_bit(master->id, kcrtc_st->affected_pipes)) komeda_pipeline_update(master, old->state); + conn_st = wb_conn ? wb_conn->base.base.state : NULL; + if (conn_st && conn_st->writeback_job) + drm_writeback_queue_job(&wb_conn->base, conn_st); + /* step 2: notify the HW to kickoff the update */ mdev->funcs->flush(mdev, master->id, kcrtc_st->active_pipes); } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c index 9cc9935024f7..4d8160cf09c3 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c @@ -165,3 +165,22 @@ komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane) return obj->paddr + offset; } + +/* if the fb can be supported by a specific layer */ +bool komeda_fb_is_layer_supported(struct komeda_fb *kfb, u32 layer_type) +{ + struct drm_framebuffer *fb = &kfb->base; + struct komeda_dev *mdev = fb->dev->dev_private; + const struct komeda_format_caps *caps; + u32 fourcc = fb->format->format; + u64 modifier = fb->modifier; + + caps = komeda_get_format_caps(&mdev->fmt_tbl, fourcc, modifier); + if (!caps) + return false; + + if (!(caps->supported_layer_types & layer_type)) + return false; + + return true; +} diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 86f6542afb40..3e58901fb776 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -188,6 +188,10 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) if (err) goto cleanup_mode_config; + err = komeda_kms_add_wb_connectors(kms, mdev); + if (err) + goto cleanup_mode_config; + err = component_bind_all(mdev->dev, kms); if (err) goto cleanup_mode_config; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h index ac3d9209b4d9..f16e9e577593 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h @@ -12,6 +12,7 @@ #include #include #include +#include #include