drm/komeda Arm display driver¶
The drm/komeda driver supports the Arm display processor D71 and later products,this document gives a brief overview of driver design: how it works and whydesign it like that.
Overview of D71 like display IPs¶
From D71, Arm display IP begins to adopt a flexible and modularizedarchitecture. A display pipeline is made up of multiple individual andfunctional pipeline stages called components, and every component has somespecific capabilities that can give the flowed pipeline pixel data aparticular processing.
Typical D71 components:
Layer¶
Layer is the first pipeline stage, which prepares the pixel data for the nextstage. It fetches the pixel from memory, decodes it if it’s AFBC, rotates thesource image, unpacks or converts YUV pixels to the device internal RGB pixels,then adjusts the color_space of pixels if needed.
Scaler¶
As its name suggests, scaler takes responsibility for scaling, and D71 alsosupports image enhancements by scaler.The usage of scaler is very flexible and can be connected to layer outputfor layer scaling, or connected to compositor and scale the whole displayframe and then feed the output data into wb_layer which will then write itinto memory.
Compositor (compiz)¶
Compositor blends multiple layers or pixel data flows into one single displayframe. its output frame can be fed into post image processor for showing it onthe monitor or fed into wb_layer and written to memory at the same time.user can also insert a scaler between compositor and wb_layer to down scalethe display frame first and then write to memory.
Writeback Layer (wb_layer)¶
Writeback layer does the opposite things of Layer, which connects to compizand writes the composition result to memory.
Post image processor (improc)¶
Post image processor adjusts frame data like gamma and color space to fit therequirements of the monitor.
Timing controller (timing_ctrlr)¶
Final stage of display pipeline, Timing controller is not for the pixelhandling, but only for controlling the display timing.
Merger¶
D71 scaler mostly only has the half horizontal input/output capabilitiescompared with Layer, like if Layer supports 4K input size, the scaler only cansupport 2K input/output in the same time. To achieve the ful frame scaling, D71introduces Layer Split, which splits the whole image to two half parts and feedsthem to two Layers A and B, and does the scaling independently. After scalingthe result need to be fed to merger to merge two part images together, and thenoutput merged result to compiz.
Splitter¶
Similar to Layer Split, but Splitter is used for writeback, which splits thecompiz result to two parts and then feed them to two scalers.
Possible D71 Pipeline usage¶
Benefitting from the modularized architecture, D71 pipelines can be easilyadjusted to fit different usages. And D71 has two pipelines, which support twotypes of working mode:
Dual display modeTwo pipelines work independently and separately to drive two display outputs.
Single display modeTwo pipelines work together to drive only one display output.
On this mode, pipeline_B doesn’t work indenpendently, but outputs itscomposition result into pipeline_A, and its pixel timing also derived frompipeline_A.timing_ctrlr. The pipeline_B works just like a “slave” ofpipeline_A(master)
Single pipeline data flow¶
Single pipeline data flow
Dual pipeline with Slave enabled¶
Slave pipeline enabled data flow
Sub-pipelines for input and output¶
A complete display pipeline can be easily divided into three sub-pipelinesaccording to the in/out usage.
Display output pipeline¶
display output data flow
In the following section we’ll see these three sub-pipelines will be handledby KMS-plane/wb_conn/crtc respectively.
Komeda Resource abstraction¶
struct komeda_pipeline/component¶
To fully utilize and easily access/configure the HW, the driver side also usesa similar architecture: Pipeline/Component to describe the HW features andcapabilities, and a specific component includes two parts:
- Data flow controlling.
- Specific component capabilities and features.
So the driver defines a common header struct komeda_component to describe thedata flow control and all specific components are a subclass of this basestructure.
- struct
komeda_component¶
Definition
struct komeda_component { struct drm_private_obj obj; struct komeda_pipeline *pipeline; char name[32]; u32 __iomem *reg; u32 id; u32 hw_id; u8 max_active_inputs; u8 max_active_outputs; u32 supported_inputs; u32 supported_outputs; const struct komeda_component_funcs *funcs;};Members
obj- treat component as private obj
pipeline- the komeda pipeline this component belongs to
name- component name
reg- component register base,which is initialized by chip and used by chip only
id- component id
hw_id- component hw id,which is initialized by chip and used by chip only
max_active_inputsmax_active_outputs:
maximum number of inputs/outputs that can be active at the same timeNote:the number isn’t the bit number ofsupported_inputs orsupported_outputs, but may be less than it, since component may notsupport enabling allsupported_inputs/outputs at the same time.
max_active_outputs- maximum number of outputs
supported_inputssupported_outputs:
bitmask of BIT(component->id) for the supported inputs/outputs,describes the possibilities of how a component is linked into apipeline.
supported_outputs- bitmask of supported output componenet ids
funcs- chip functions to access HW
Description
struct komeda_component describe the data flow capabilities for how to link acomponent into the display pipeline.all specified components are subclass of this structure.
- struct
komeda_component_output¶
Definition
struct komeda_component_output { struct komeda_component *component; u8 output_port;};Members
component- indicate which component the data comes from
output_port- the output port of the
komeda_component_output.component
Description
a component has multiple outputs, if want to know where the datacomes from, only know the component is not enough, we still need to knowits output port
- struct
komeda_component_state¶
Definition
struct komeda_component_state { struct drm_private_state obj; struct komeda_component *component; union { struct drm_crtc *crtc; struct drm_plane *plane; struct drm_connector *wb_conn; void *binding_user; }; u16 active_inputs; u16 changed_active_inputs; u16 affected_inputs; struct komeda_component_output inputs[KOMEDA_COMPONENT_N_INPUTS];};Members
obj- tracking component_state by drm_atomic_state
component- backpointer to the component
{unnamed_union}- anonymous
crtc- backpointer for user crtc
plane- backpointer for user plane
wb_conn- backpointer for user wb_connector
binding_usercurrently bound user, the user can becrtc,plane orwb_conn,which is valid decided bycomponent andinputs
- Layer: its user always is plane.
- compiz/improc/timing_ctrlr: the user is crtc.
- wb_layer: wb_conn;
- scaler: plane when input is layer, wb_conn if input is compiz.
active_inputsactive_inputs is bitmask ofinputs index
- active_inputs = changed_active_inputs | unchanged_active_inputs
- affected_inputs = old->active_inputs | new->active_inputs;
- disabling_inputs = affected_inputs ^ active_inputs;
- changed_inputs = disabling_inputs | changed_active_inputs;
NOTE:changed_inputs doesn’t include all active_input but onlychanged_active_inputs, and this bitmask can be used in chiplevel for dirty update.
changed_active_inputs- bitmask of the changedactive_inputs
affected_inputs- bitmask for affectedinputs
inputs- the specific inputs[i] only valid on BIT(i) has been set inactive_inputs, if not the inputs[i] is undefined.
Description
component_state is the data flow configuration of the component, and it’sthe superclass of all specific component_state likekomeda_layer_state,komeda_scaler_state
- struct
komeda_pipeline¶
Definition
struct komeda_pipeline { struct drm_private_obj obj; struct komeda_dev *mdev; struct clk *pxlclk; int id; u32 avail_comps; u32 standalone_disabled_comps; int n_layers; struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS]; int n_scalers; struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS]; struct komeda_compiz *compiz; struct komeda_splitter *splitter; struct komeda_merger *merger; struct komeda_layer *wb_layer; struct komeda_improc *improc; struct komeda_timing_ctrlr *ctrlr; const struct komeda_pipeline_funcs *funcs; struct device_node *of_node; struct device_node *of_output_port; struct device_node *of_output_links[2]; bool dual_link;};Members
obj- link pipeline as private obj of drm_atomic_state
mdev- the parent komeda_dev
pxlclk- pixel clock
id- pipeline id
avail_comps- available components mask of pipeline
standalone_disabled_comps- When disable the pipeline, some components can not be disabledtogether with others, but need a sparated and standalone disable.The standalone_disabled_comps are the components which need to bedisabled standalone, and this concept also introduce concept oftwo phase.phase 1: for disabling the common components.phase 2: for disabling the standalong_disabled_comps.
n_layers- the number of layer onlayers
layers- the pipeline layers
n_scalers- the number of scaler onscalers
scalers- the pipeline scalers
compiz- compositor
splitter- for split the compiz output to two half data flows
merger- merger
wb_layer- writeback layer
improc- post image processor
ctrlr- timing controller
funcs- chip private pipeline functions
of_node- pipeline dt node
of_output_port- pipeline output port
of_output_links- output connector device nodes
dual_link- true if of_output_links[0] and [1] are both valid
Description
Represent a complete display pipeline and hold all functional components.
- struct
komeda_pipeline_state¶
Definition
struct komeda_pipeline_state { struct drm_private_state obj; struct komeda_pipeline *pipe; struct drm_crtc *crtc; u32 active_comps;};Members
obj- tracking pipeline_state by drm_atomic_state
pipe- backpointer to the pipeline
crtc- currently bound crtc
active_comps- bitmask - BIT(component->id) of active components
NOTE
Unlike the pipeline, pipeline_state doesn’t gather any component_stateinto it. It because all component will be managed by drm_atomic_state.
Resource discovery and initialization¶
Pipeline and component are used to describe how to handle the pixel data. Westill need a @struct komeda_dev to describe the whole view of the device, andthe control-abilites of device.
We have &komeda_dev, &komeda_pipeline, &komeda_component. Now fill devices withpipelines. Since komeda is not for D71 only but also intended for later products,of course we’d better share as much as possible between different products. Toachieve this, split the komeda device into two layers: CORE and CHIP.
- CORE: for common features and capabilities handling.
- CHIP: for register programing and HW specific feature (limitation) handling.
CORE can access CHIP by three chip function structures:
- struct komeda_dev_funcs
- struct komeda_pipeline_funcs
- struct komeda_component_funcs
- struct
komeda_dev_funcs¶
Definition
struct komeda_dev_funcs { void (*init_format_table)(struct komeda_dev *mdev); int (*enum_resources)(struct komeda_dev *mdev); void (*cleanup)(struct komeda_dev *mdev); int (*connect_iommu)(struct komeda_dev *mdev); int (*disconnect_iommu)(struct komeda_dev *mdev); irqreturn_t (*irq_handler)(struct komeda_dev *mdev, struct komeda_events *events); int (*enable_irq)(struct komeda_dev *mdev); int (*disable_irq)(struct komeda_dev *mdev); void (*on_off_vblank)(struct komeda_dev *mdev, int master_pipe, bool on); void (*dump_register)(struct komeda_dev *mdev, struct seq_file *seq); int (*change_opmode)(struct komeda_dev *mdev, int new_mode); void (*flush)(struct komeda_dev *mdev, int master_pipe, u32 active_pipes);};Members
init_format_table- initialize
komeda_dev->format_table, this function should be calledbefore theenum_resource enum_resources- for CHIP to report or add pipeline and component resources to CORE
cleanup- call to chip to cleanup komeda_dev->chip data
connect_iommu- Optional, connect to external iommu
disconnect_iommu- Optional, disconnect to external iommu
irq_handler- for CORE to get the HW event from the CHIP when interrupt happened.
enable_irq- enable irq
disable_irq- disable irq
on_off_vblank- notify HW to on/off vblank
dump_register- Optional, dump registers to seq_file
change_opmode- Notify HW to switch to a new display operation mode.
flush- Notify the HW to flush or kickoff the update
Description
Supplied by chip level and returned by the chip entry function xxx_identify,
- struct
komeda_dev¶
Definition
struct komeda_dev { struct device *dev; u32 __iomem *reg_base; struct device_dma_parameters dma_parms; struct komeda_chip_info chip; struct komeda_format_caps_table fmt_tbl; struct clk *aclk; int irq; struct mutex lock; u32 dpmode; int n_pipelines; struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES]; const struct komeda_dev_funcs *funcs; void *chip_data; struct iommu_domain *iommu; struct dentry *debugfs_root; u16 err_verbosity;#define KOMEDA_DEV_PRINT_ERR_EVENTS BIT(0);#define KOMEDA_DEV_PRINT_WARN_EVENTS BIT(1);#define KOMEDA_DEV_PRINT_INFO_EVENTS BIT(2);#define KOMEDA_DEV_PRINT_DUMP_STATE_ON_EVENT BIT(8);#define KOMEDA_DEV_PRINT_DISABLE_RATELIMIT BIT(12);};Members
dev- the base device structure
reg_base- the base address of komeda io space
dma_parms- the dma parameters of komeda
chip- the basic chip information
fmt_tbl- initialized by
komeda_dev_funcs->init_format_table aclk- HW main engine clk
irq- irq number
lock- used to protect dpmode
dpmode- current display mode
n_pipelines- the number of pipe inpipelines
pipelines- the komeda pipelines
funcs- chip funcs to access to HW
chip_data- chip data will be added by
komeda_dev_funcs.enum_resources()anddestroyed bykomeda_dev_funcs.cleanup() iommu- iommu domain
debugfs_root- root directory of komeda debugfs
err_verbositybitmask for how much extra info to print on error
See KOMEDA_DEV_* macros for details. Low byte contains the debuglevel categories, the high byte contains extra debug options.
Description
Pipeline and component are used to describe how to handle the pixel data.komeda_device is for describing the whole view of the device, and thecontrol-abilites of device.
Format handling¶
- struct
komeda_format_caps¶
Definition
struct komeda_format_caps { u32 hw_id; u32 fourcc; u32 supported_layer_types; u32 supported_rots; u32 supported_afbc_layouts; u64 supported_afbc_features;};Members
hw_id- hw format id, hw specific value.
fourcc- drm fourcc format.
supported_layer_types- indicate which layer supports this format
supported_rots- allowed rotations for this format
supported_afbc_layouts- supported afbc layerout
supported_afbc_features- supported afbc features
Description
komeda_format_caps is for describing ARM display specific features andlimitations for a specific format, and format_caps will be linked intokomeda_framebuffer like a extension ofdrm_format_info.
NOTE
one fourcc may has two different format_caps items for fourcc andfourcc+modifier
- struct
komeda_format_caps_table¶ format_caps mananger
Definition
struct komeda_format_caps_table { u32 n_formats; const struct komeda_format_caps *format_caps; bool (*format_mod_supported)(const struct komeda_format_caps *caps, u32 layer_type, u64 modifier, u32 rot);};Members
n_formats- the size of format_caps list.
format_caps- format_caps list.
format_mod_supported- Optional. Some HW may have special requirements orlimitations which can not be described by format_caps, this func supply HWthe ability to do the further HW specific check.
- struct
komeda_fb¶ Entending drm_framebuffer with komeda attribute
Definition
struct komeda_fb { struct drm_framebuffer base; const struct komeda_format_caps *format_caps; bool is_va; u32 aligned_w; u32 aligned_h; u32 afbc_size; u32 offset_payload;};Members
basedrm_framebufferformat_caps- extends drm_format_info for komeda specific information
is_va- if smmu is enabled, it will be true
aligned_w- aligned frame buffer width
aligned_h- aligned frame buffer height
afbc_size- minimum size of afbc
offset_payload- start of afbc body buffer
Attach komeda_dev to DRM-KMS¶
Komeda abstracts resources by pipeline/component, but DRM-KMS usescrtc/plane/connector. One KMS-obj cannot represent only one single component,since the requirements of a single KMS object cannot simply be achieved by asingle component, usually that needs multiple components to fit the requirement.Like set mode, gamma, ctm for KMS all target on CRTC-obj, but komeda needscompiz, improc and timing_ctrlr to work together to fit these requirements.And a KMS-Plane may require multiple komeda resources: layer/scaler/compiz.
So, one KMS-Obj represents a sub-pipeline of komeda resources.
- Plane:Layer(input) pipeline
- Wb_connector:Writeback(output) pipeline
- Crtc:Display output pipeline
So, for komeda, we treat KMS crtc/plane/connector as users of pipeline andcomponent, and at any one time a pipeline/component only can be used by oneuser. And pipeline/component will be treated as private object of DRM-KMS; thestate will be managed by drm_atomic_state as well.
How to map plane to Layer(input) pipeline¶
Komeda has multiple Layer input pipelines, see:-Single pipeline data flow-Dual pipeline with Slave enabled
The easiest way is binding a plane to a fixed Layer pipeline, but consider thekomeda capabilities:
Layer Split, SeeLayer(input) pipeline
Layer_Split is quite complicated feature, which splits a big image into twoparts and handles it by two layers and two scalers individually. But itimports an edge problem or effect in the middle of the image after the split.To avoid such a problem, it needs a complicated Split calculation and somespecial configurations to the layer and scaler. We’d better hide such HWrelated complexity to user mode.
Slave pipeline, SeeDual pipeline with Slave enabled
Since the compiz component doesn’t output alpha value, the slave pipelineonly can be used for bottom layers composition. The komeda driver wants tohide this limitation to the user. The way to do this is to pick a suitableLayer according to plane_state->zpos.
So for komeda, the KMS-plane doesn’t represent a fixed komeda layer pipeline,but multiple Layers with same capabilities. Komeda will select one or moreLayers to fit the requirement of one KMS-plane.
Make component/pipeline to be drm_private_obj¶
Adddrm_private_obj tokomeda_component,komeda_pipeline
structkomeda_component{structdrm_private_objobj;...}structkomeda_pipeline{structdrm_private_objobj;...}
Tracking component_state/pipeline_state by drm_atomic_state¶
Adddrm_private_state and user tokomeda_component_state,komeda_pipeline_state
structkomeda_component_state{structdrm_private_stateobj;void*binding_user;...}structkomeda_pipeline_state{structdrm_private_stateobj;structdrm_crtc*crtc;...}
komeda component validation¶
Komeda has multiple types of components, but the process of validation aresimilar, usually including the following steps:
intkomeda_xxxx_validate(structkomeda_component_xxxxxx_comp,structkomeda_component_output*input_dflow,structdrm_plane/crtc/connector*user,structdrm_plane/crtc/connector_state,*user_state){setup1:checkifcomponentisneeded,likethescalerisoptionaldependingontheuser_state;ifunneeded,justreturn,andthecallerwillputthedataflowintonextstage.Setup2:checkuser_statewithcomponentfeaturesandcapabilitiestoseeifrequirementscanbemet;ifnot,returnfail.Setup3:getcomponent_statefromdrm_atomic_state,andtrysettosetusertocomponent;failifcomponenthasbeenassignedtoanotheruseralready.Setup3:configurethecomponent_state,likesetitsinputcomponent,convertuser_statetocomponentspecificstate.Setup4:adjusttheinput_dflowandprepareitforthenextstage.}
komeda_kms Abstraction¶
- struct
komeda_plane¶ komeda instance of drm_plane
Definition
struct komeda_plane { struct drm_plane base; struct komeda_layer *layer;};Members
basedrm_planelayerrepresents available layer input pipelines for this plane.
NOTE:the layer is not for a specific Layer, but indicate a group ofLayers with same capabilities.
- struct
komeda_plane_state¶
Definition
struct komeda_plane_state { struct drm_plane_state base; struct list_head zlist_node; u8 layer_split : 1;};Members
basedrm_plane_statezlist_node- zorder list node
layer_split- on/off layer_split
Description
The plane_state can be split into two data flow (left/right) and handledby two layerskomeda_plane.layer andkomeda_plane.layer.right
- struct
komeda_wb_connector¶
Definition
struct komeda_wb_connector { struct drm_writeback_connector base; struct komeda_layer *wb_layer;};Members
basedrm_writeback_connectorwb_layer- represents associated writeback pipeline of komeda
- struct
komeda_crtc¶
Definition
struct komeda_crtc { struct drm_crtc base; struct komeda_pipeline *master; struct komeda_pipeline *slave; u32 slave_planes; struct komeda_wb_connector *wb_conn; struct completion *disable_done;};Members
basedrm_crtcmaster- only master has display output
slaveoptional
Doesn’t have its own display output, the handled data flow willmerge into the master.
slave_planes- komeda slave planes mask
wb_conn- komeda write back connector
disable_done- this flip_done is for tracing the disable
- struct
komeda_crtc_state¶
Definition
struct komeda_crtc_state { struct drm_crtc_state base; u32 affected_pipes; u32 active_pipes; u64 clock_ratio; u32 max_slave_zorder;};Members
basedrm_crtc_stateaffected_pipes- the affected pipelines in once display instance
active_pipes- the active pipelines in once display instance
clock_ratio- ratio of (aclk << 32)/pxlclk
max_slave_zorder- the maximum of slave zorder
komde_kms Functions¶
- int
komeda_crtc_atomic_check(structdrm_crtc * crtc, structdrm_crtc_state * state)¶ build display output data flow
Parameters
structdrm_crtc*crtc- DRM crtc
structdrm_crtc_state*state- the crtc state object
Description
crtc_atomic_check is the final check stage, so beside build a display datapipeline according to the crtc_state, but still needs to release or disablethe unclaimed pipeline resources.
Return
Zero for success or -errno
- int
komeda_plane_atomic_check(structdrm_plane * plane, structdrm_plane_state * state)¶ build input data flow
Parameters
structdrm_plane*plane- DRM plane
structdrm_plane_state*state- the plane state object
Return
Zero for success or -errno
Build komeda to be a Linux module driver¶
Now we have two level devices:
- komeda_dev: describes the real display hardware.
- komeda_kms_dev: attachs or connects komeda_dev to DRM-KMS.
All komeda operations are supplied or operated by komeda_dev or komeda_kms_dev,the module driver is only a simple wrapper to pass the Linux command(probe/remove/pm) into komeda_dev or komeda_kms_dev.