Path: blob/master/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
54336 views
// SPDX-License-Identifier: GPL-2.01/*2* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.3* Author: James.Qian.Wang <[email protected]>4*5*/6#include <linux/clk.h>7#include <linux/of.h>8#include <linux/pm_runtime.h>9#include <linux/spinlock.h>1011#include <drm/drm_atomic.h>12#include <drm/drm_atomic_helper.h>13#include <drm/drm_print.h>14#include <drm/drm_vblank.h>15#include <drm/drm_simple_kms_helper.h>16#include <drm/drm_bridge.h>1718#include "komeda_dev.h"19#include "komeda_kms.h"2021void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st,22u32 *color_depths, u32 *color_formats)23{24struct drm_connector *conn;25struct drm_connector_state *conn_st;26u32 conn_color_formats = ~0u;27int i, min_bpc = 31, conn_bpc = 0;2829for_each_new_connector_in_state(crtc_st->state, conn, conn_st, i) {30if (conn_st->crtc != crtc_st->crtc)31continue;3233conn_bpc = conn->display_info.bpc ? conn->display_info.bpc : 8;34conn_color_formats &= conn->display_info.color_formats;3536if (conn_bpc < min_bpc)37min_bpc = conn_bpc;38}3940/* connector doesn't config any color_format, use RGB444 as default */41if (!conn_color_formats)42conn_color_formats = DRM_COLOR_FORMAT_RGB444;4344*color_depths = GENMASK(min_bpc, 0);45*color_formats = conn_color_formats;46}4748static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st)49{50u64 pxlclk, aclk;5152if (!kcrtc_st->base.active) {53kcrtc_st->clock_ratio = 0;54return;55}5657pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000ULL;58aclk = komeda_crtc_get_aclk(kcrtc_st);5960kcrtc_st->clock_ratio = div64_u64(aclk << 32, pxlclk);61}6263/**64* komeda_crtc_atomic_check - build display output data flow65* @crtc: DRM crtc66* @state: the crtc state object67*68* crtc_atomic_check is the final check stage, so beside build a display data69* pipeline according to the crtc_state, but still needs to release or disable70* the unclaimed pipeline resources.71*72* RETURNS:73* Zero for success or -errno74*/75static int76komeda_crtc_atomic_check(struct drm_crtc *crtc,77struct drm_atomic_state *state)78{79struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,80crtc);81struct komeda_crtc *kcrtc = to_kcrtc(crtc);82struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc_state);83int err;8485if (drm_atomic_crtc_needs_modeset(crtc_state))86komeda_crtc_update_clock_ratio(kcrtc_st);8788if (crtc_state->active) {89err = komeda_build_display_data_flow(kcrtc, kcrtc_st);90if (err)91return err;92}9394/* release unclaimed pipeline resources */95err = komeda_release_unclaimed_resources(kcrtc->slave, kcrtc_st);96if (err)97return err;9899err = komeda_release_unclaimed_resources(kcrtc->master, kcrtc_st);100if (err)101return err;102103return 0;104}105106/* For active a crtc, mainly need two parts of preparation107* 1. adjust display operation mode.108* 2. enable needed clk109*/110static int111komeda_crtc_prepare(struct komeda_crtc *kcrtc)112{113struct drm_device *drm = kcrtc->base.dev;114struct komeda_dev *mdev = kcrtc->base.dev->dev_private;115struct komeda_pipeline *master = kcrtc->master;116struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(kcrtc->base.state);117struct drm_display_mode *mode = &kcrtc_st->base.adjusted_mode;118u32 new_mode;119int err;120121mutex_lock(&mdev->lock);122123new_mode = mdev->dpmode | BIT(master->id);124if (WARN_ON(new_mode == mdev->dpmode)) {125err = 0;126goto unlock;127}128129err = mdev->funcs->change_opmode(mdev, new_mode);130if (err) {131drm_err(drm, "failed to change opmode: 0x%x -> 0x%x.\n,",132mdev->dpmode, new_mode);133goto unlock;134}135136mdev->dpmode = new_mode;137/* Only need to enable aclk on single display mode, but no need to138* enable aclk it on dual display mode, since the dual mode always139* switch from single display mode, the aclk already enabled, no need140* to enable it again.141*/142if (new_mode != KOMEDA_MODE_DUAL_DISP) {143err = clk_set_rate(mdev->aclk, komeda_crtc_get_aclk(kcrtc_st));144if (err)145drm_err(drm, "failed to set aclk.\n");146err = clk_prepare_enable(mdev->aclk);147if (err)148drm_err(drm, "failed to enable aclk.\n");149}150151err = clk_set_rate(master->pxlclk, mode->crtc_clock * 1000);152if (err)153drm_err(drm, "failed to set pxlclk for pipe%d\n", master->id);154err = clk_prepare_enable(master->pxlclk);155if (err)156drm_err(drm, "failed to enable pxl clk for pipe%d.\n", master->id);157158unlock:159mutex_unlock(&mdev->lock);160161return err;162}163164static int165komeda_crtc_unprepare(struct komeda_crtc *kcrtc)166{167struct drm_device *drm = kcrtc->base.dev;168struct komeda_dev *mdev = kcrtc->base.dev->dev_private;169struct komeda_pipeline *master = kcrtc->master;170u32 new_mode;171int err;172173mutex_lock(&mdev->lock);174175new_mode = mdev->dpmode & (~BIT(master->id));176177if (WARN_ON(new_mode == mdev->dpmode)) {178err = 0;179goto unlock;180}181182err = mdev->funcs->change_opmode(mdev, new_mode);183if (err) {184drm_err(drm, "failed to change opmode: 0x%x -> 0x%x.\n,",185mdev->dpmode, new_mode);186goto unlock;187}188189mdev->dpmode = new_mode;190191clk_disable_unprepare(master->pxlclk);192if (new_mode == KOMEDA_MODE_INACTIVE)193clk_disable_unprepare(mdev->aclk);194195unlock:196mutex_unlock(&mdev->lock);197198return err;199}200201void komeda_crtc_handle_event(struct komeda_crtc *kcrtc,202struct komeda_events *evts)203{204struct drm_device *drm = kcrtc->base.dev;205struct drm_crtc *crtc = &kcrtc->base;206u32 events = evts->pipes[kcrtc->master->id];207208if (events & KOMEDA_EVENT_VSYNC)209drm_crtc_handle_vblank(crtc);210211if (events & KOMEDA_EVENT_EOW) {212struct komeda_wb_connector *wb_conn = kcrtc->wb_conn;213214if (wb_conn)215drm_writeback_signal_completion(&wb_conn->base, 0);216else217drm_warn(drm, "CRTC[%d]: EOW happen but no wb_connector.\n",218drm_crtc_index(&kcrtc->base));219}220/* will handle it together with the write back support */221if (events & KOMEDA_EVENT_EOW)222DRM_DEBUG("EOW.\n");223224if (events & KOMEDA_EVENT_FLIP) {225unsigned long flags;226struct drm_pending_vblank_event *event;227228spin_lock_irqsave(&crtc->dev->event_lock, flags);229if (kcrtc->disable_done) {230complete_all(kcrtc->disable_done);231kcrtc->disable_done = NULL;232} else if (crtc->state->event) {233event = crtc->state->event;234/*235* Consume event before notifying drm core that flip236* happened.237*/238crtc->state->event = NULL;239drm_crtc_send_vblank_event(crtc, event);240} else {241drm_warn(drm, "CRTC[%d]: FLIP happened but no pending commit.\n",242drm_crtc_index(&kcrtc->base));243}244spin_unlock_irqrestore(&crtc->dev->event_lock, flags);245}246}247248static void249komeda_crtc_do_flush(struct drm_crtc *crtc,250struct drm_crtc_state *old)251{252struct komeda_crtc *kcrtc = to_kcrtc(crtc);253struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc->state);254struct komeda_dev *mdev = kcrtc->base.dev->dev_private;255struct komeda_pipeline *master = kcrtc->master;256struct komeda_pipeline *slave = kcrtc->slave;257struct komeda_wb_connector *wb_conn = kcrtc->wb_conn;258struct drm_connector_state *conn_st;259260DRM_DEBUG_ATOMIC("CRTC%d_FLUSH: active_pipes: 0x%x, affected: 0x%x.\n",261drm_crtc_index(crtc),262kcrtc_st->active_pipes, kcrtc_st->affected_pipes);263264/* step 1: update the pipeline/component state to HW */265if (has_bit(master->id, kcrtc_st->affected_pipes))266komeda_pipeline_update(master, old->state);267268if (slave && has_bit(slave->id, kcrtc_st->affected_pipes))269komeda_pipeline_update(slave, old->state);270271conn_st = wb_conn ? wb_conn->base.base.state : NULL;272if (conn_st && conn_st->writeback_job)273drm_writeback_queue_job(&wb_conn->base, conn_st);274275/* step 2: notify the HW to kickoff the update */276mdev->funcs->flush(mdev, master->id, kcrtc_st->active_pipes);277}278279static void280komeda_crtc_atomic_enable(struct drm_crtc *crtc,281struct drm_atomic_state *state)282{283struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state,284crtc);285pm_runtime_get_sync(crtc->dev->dev);286komeda_crtc_prepare(to_kcrtc(crtc));287drm_crtc_vblank_on(crtc);288WARN_ON(drm_crtc_vblank_get(crtc));289komeda_crtc_do_flush(crtc, old);290}291292void293komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc,294struct completion *input_flip_done)295{296struct drm_device *drm = kcrtc->base.dev;297struct komeda_dev *mdev = kcrtc->master->mdev;298struct completion *flip_done;299struct completion temp;300301/* if caller doesn't send a flip_done, use a private flip_done */302if (input_flip_done) {303flip_done = input_flip_done;304} else {305init_completion(&temp);306kcrtc->disable_done = &temp;307flip_done = &temp;308}309310mdev->funcs->flush(mdev, kcrtc->master->id, 0);311312/* wait the flip take affect.*/313if (wait_for_completion_timeout(flip_done, HZ) == 0) {314drm_err(drm, "wait pipe%d flip done timeout\n", kcrtc->master->id);315if (!input_flip_done) {316unsigned long flags;317318spin_lock_irqsave(&drm->event_lock, flags);319kcrtc->disable_done = NULL;320spin_unlock_irqrestore(&drm->event_lock, flags);321}322}323}324325static void326komeda_crtc_atomic_disable(struct drm_crtc *crtc,327struct drm_atomic_state *state)328{329struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state,330crtc);331struct komeda_crtc *kcrtc = to_kcrtc(crtc);332struct komeda_crtc_state *old_st = to_kcrtc_st(old);333struct komeda_pipeline *master = kcrtc->master;334struct komeda_pipeline *slave = kcrtc->slave;335struct completion *disable_done;336bool needs_phase2 = false;337338DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x\n",339drm_crtc_index(crtc),340old_st->active_pipes, old_st->affected_pipes);341342if (slave && has_bit(slave->id, old_st->active_pipes))343komeda_pipeline_disable(slave, old->state);344345if (has_bit(master->id, old_st->active_pipes))346needs_phase2 = komeda_pipeline_disable(master, old->state);347348/* crtc_disable has two scenarios according to the state->active switch.349* 1. active -> inactive350* this commit is a disable commit. and the commit will be finished351* or done after the disable operation. on this case we can directly352* use the crtc->state->event to tracking the HW disable operation.353* 2. active -> active354* the crtc->commit is not for disable, but a modeset operation when355* crtc is active, such commit actually has been completed by 3356* DRM operations:357* crtc_disable, update_planes(crtc_flush), crtc_enable358* so on this case the crtc->commit is for the whole process.359* we can not use it for tracing the disable, we need a temporary360* flip_done for tracing the disable. and crtc->state->event for361* the crtc_enable operation.362* That's also the reason why skip modeset commit in363* komeda_crtc_atomic_flush()364*/365disable_done = (needs_phase2 || crtc->state->active) ?366NULL : &crtc->state->commit->flip_done;367368/* wait phase 1 disable done */369komeda_crtc_flush_and_wait_for_flip_done(kcrtc, disable_done);370371/* phase 2 */372if (needs_phase2) {373komeda_pipeline_disable(kcrtc->master, old->state);374375disable_done = crtc->state->active ?376NULL : &crtc->state->commit->flip_done;377378komeda_crtc_flush_and_wait_for_flip_done(kcrtc, disable_done);379}380381drm_crtc_vblank_put(crtc);382drm_crtc_vblank_off(crtc);383komeda_crtc_unprepare(kcrtc);384pm_runtime_put(crtc->dev->dev);385}386387static void388komeda_crtc_atomic_flush(struct drm_crtc *crtc,389struct drm_atomic_state *state)390{391struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,392crtc);393struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state,394crtc);395/* commit with modeset will be handled in enable/disable */396if (drm_atomic_crtc_needs_modeset(crtc_state))397return;398399komeda_crtc_do_flush(crtc, old);400}401402/* Returns the minimum frequency of the aclk rate (main engine clock) in Hz */403static unsigned long404komeda_calc_min_aclk_rate(struct komeda_crtc *kcrtc,405unsigned long pxlclk)406{407/* Once dual-link one display pipeline drives two display outputs,408* the aclk needs run on the double rate of pxlclk409*/410if (kcrtc->master->dual_link)411return pxlclk * 2;412else413return pxlclk;414}415416/* Get current aclk rate that specified by state */417unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st)418{419struct drm_crtc *crtc = kcrtc_st->base.crtc;420struct komeda_dev *mdev = crtc->dev->dev_private;421unsigned long pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000;422unsigned long min_aclk;423424min_aclk = komeda_calc_min_aclk_rate(to_kcrtc(crtc), pxlclk);425426return clk_round_rate(mdev->aclk, min_aclk);427}428429static enum drm_mode_status430komeda_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *m)431{432struct komeda_dev *mdev = crtc->dev->dev_private;433struct komeda_crtc *kcrtc = to_kcrtc(crtc);434struct komeda_pipeline *master = kcrtc->master;435unsigned long min_pxlclk, min_aclk;436437if (m->flags & DRM_MODE_FLAG_INTERLACE)438return MODE_NO_INTERLACE;439440min_pxlclk = m->clock * 1000;441if (master->dual_link)442min_pxlclk /= 2;443444if (min_pxlclk != clk_round_rate(master->pxlclk, min_pxlclk)) {445DRM_DEBUG_ATOMIC("pxlclk doesn't support %lu Hz\n", min_pxlclk);446447return MODE_NOCLOCK;448}449450min_aclk = komeda_calc_min_aclk_rate(to_kcrtc(crtc), min_pxlclk);451if (clk_round_rate(mdev->aclk, min_aclk) < min_aclk) {452DRM_DEBUG_ATOMIC("engine clk can't satisfy the requirement of %s-clk: %lu.\n",453m->name, min_pxlclk);454455return MODE_CLOCK_HIGH;456}457458return MODE_OK;459}460461static bool komeda_crtc_mode_fixup(struct drm_crtc *crtc,462const struct drm_display_mode *m,463struct drm_display_mode *adjusted_mode)464{465struct komeda_crtc *kcrtc = to_kcrtc(crtc);466unsigned long clk_rate;467468drm_mode_set_crtcinfo(adjusted_mode, 0);469/* In dual link half the horizontal settings */470if (kcrtc->master->dual_link) {471adjusted_mode->crtc_clock /= 2;472adjusted_mode->crtc_hdisplay /= 2;473adjusted_mode->crtc_hsync_start /= 2;474adjusted_mode->crtc_hsync_end /= 2;475adjusted_mode->crtc_htotal /= 2;476}477478clk_rate = adjusted_mode->crtc_clock * 1000;479/* crtc_clock will be used as the komeda output pixel clock */480adjusted_mode->crtc_clock = clk_round_rate(kcrtc->master->pxlclk,481clk_rate) / 1000;482483return true;484}485486static const struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {487.atomic_check = komeda_crtc_atomic_check,488.atomic_flush = komeda_crtc_atomic_flush,489.atomic_enable = komeda_crtc_atomic_enable,490.atomic_disable = komeda_crtc_atomic_disable,491.mode_valid = komeda_crtc_mode_valid,492.mode_fixup = komeda_crtc_mode_fixup,493};494495static void komeda_crtc_reset(struct drm_crtc *crtc)496{497struct komeda_crtc_state *state;498499if (crtc->state)500__drm_atomic_helper_crtc_destroy_state(crtc->state);501502kfree(to_kcrtc_st(crtc->state));503crtc->state = NULL;504505state = kzalloc(sizeof(*state), GFP_KERNEL);506if (state)507__drm_atomic_helper_crtc_reset(crtc, &state->base);508}509510static struct drm_crtc_state *511komeda_crtc_atomic_duplicate_state(struct drm_crtc *crtc)512{513struct komeda_crtc_state *old = to_kcrtc_st(crtc->state);514struct komeda_crtc_state *new;515516new = kzalloc(sizeof(*new), GFP_KERNEL);517if (!new)518return NULL;519520__drm_atomic_helper_crtc_duplicate_state(crtc, &new->base);521522new->affected_pipes = old->active_pipes;523new->clock_ratio = old->clock_ratio;524new->max_slave_zorder = old->max_slave_zorder;525526return &new->base;527}528529static void komeda_crtc_atomic_destroy_state(struct drm_crtc *crtc,530struct drm_crtc_state *state)531{532__drm_atomic_helper_crtc_destroy_state(state);533kfree(to_kcrtc_st(state));534}535536static int komeda_crtc_vblank_enable(struct drm_crtc *crtc)537{538struct komeda_dev *mdev = crtc->dev->dev_private;539struct komeda_crtc *kcrtc = to_kcrtc(crtc);540541mdev->funcs->on_off_vblank(mdev, kcrtc->master->id, true);542return 0;543}544545static void komeda_crtc_vblank_disable(struct drm_crtc *crtc)546{547struct komeda_dev *mdev = crtc->dev->dev_private;548struct komeda_crtc *kcrtc = to_kcrtc(crtc);549550mdev->funcs->on_off_vblank(mdev, kcrtc->master->id, false);551}552553static const struct drm_crtc_funcs komeda_crtc_funcs = {554.destroy = drm_crtc_cleanup,555.set_config = drm_atomic_helper_set_config,556.page_flip = drm_atomic_helper_page_flip,557.reset = komeda_crtc_reset,558.atomic_duplicate_state = komeda_crtc_atomic_duplicate_state,559.atomic_destroy_state = komeda_crtc_atomic_destroy_state,560.enable_vblank = komeda_crtc_vblank_enable,561.disable_vblank = komeda_crtc_vblank_disable,562};563564int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,565struct komeda_dev *mdev)566{567struct drm_device *drm = &kms->base;568struct komeda_crtc *crtc;569struct komeda_pipeline *master;570char str[16];571int i;572573kms->n_crtcs = 0;574575for (i = 0; i < mdev->n_pipelines; i++) {576crtc = &kms->crtcs[kms->n_crtcs];577master = mdev->pipelines[i];578579crtc->master = master;580crtc->slave = komeda_pipeline_get_slave(master);581582if (crtc->slave)583sprintf(str, "pipe-%d", crtc->slave->id);584else585sprintf(str, "None");586587drm_info(drm, "CRTC-%d: master(pipe-%d) slave(%s).\n",588kms->n_crtcs, master->id, str);589590kms->n_crtcs++;591}592593return 0;594}595596static struct drm_plane *597get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)598{599struct komeda_plane *kplane;600struct drm_plane *plane;601602drm_for_each_plane(plane, &kms->base) {603if (plane->type != DRM_PLANE_TYPE_PRIMARY)604continue;605606kplane = to_kplane(plane);607/* only master can be primary */608if (kplane->layer->base.pipeline == crtc->master)609return plane;610}611612return NULL;613}614615static int komeda_attach_bridge(struct device *dev,616struct komeda_pipeline *pipe,617struct drm_encoder *encoder)618{619struct drm_device *drm = encoder->dev;620struct drm_bridge *bridge;621int err;622623bridge = devm_drm_of_get_bridge(dev, pipe->of_node,624KOMEDA_OF_PORT_OUTPUT, 0);625if (IS_ERR(bridge))626return dev_err_probe(dev, PTR_ERR(bridge), "remote bridge not found for pipe: %s\n",627of_node_full_name(pipe->of_node));628629err = drm_bridge_attach(encoder, bridge, NULL, 0);630if (err)631drm_err(drm, "bridge_attach() failed for pipe: %s\n",632of_node_full_name(pipe->of_node));633634return err;635}636637static int komeda_crtc_add(struct komeda_kms_dev *kms,638struct komeda_crtc *kcrtc)639{640struct drm_crtc *crtc = &kcrtc->base;641struct drm_device *base = &kms->base;642struct komeda_pipeline *pipe = kcrtc->master;643struct drm_encoder *encoder = &kcrtc->encoder;644int err;645646err = drm_crtc_init_with_planes(base, crtc,647get_crtc_primary(kms, kcrtc), NULL,648&komeda_crtc_funcs, NULL);649if (err)650return err;651652drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);653654crtc->port = pipe->of_output_port;655656/* Construct an encoder for each pipeline and attach it to the remote657* bridge658*/659kcrtc->encoder.possible_crtcs = drm_crtc_mask(crtc);660err = drm_simple_encoder_init(base, encoder, DRM_MODE_ENCODER_TMDS);661if (err)662return err;663664if (pipe->of_output_links[0]) {665err = komeda_attach_bridge(base->dev, pipe, encoder);666if (err)667return err;668}669670drm_crtc_enable_color_mgmt(crtc, 0, true, KOMEDA_COLOR_LUT_SIZE);671672komeda_pipeline_dump(pipe);673674return 0;675}676677int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)678{679int i, err;680681for (i = 0; i < kms->n_crtcs; i++) {682err = komeda_crtc_add(kms, &kms->crtcs[i]);683if (err)684return err;685}686687return 0;688}689690691