| 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* |
| 3 | * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. |
| 4 | * Author: James.Qian.Wang <james.qian.wang@arm.com> |
| 5 | * |
| 6 | */ |
| 7 | #ifndef _KOMEDA_KMS_H_ |
| 8 | #define _KOMEDA_KMS_H_ |
| 9 | |
| 10 | #include <linux/list.h> |
| 11 | #include <drm/drm_atomic.h> |
| 12 | #include <drm/drm_atomic_helper.h> |
| 13 | #include <drm/drm_blend.h> |
| 14 | #include <drm/drm_device.h> |
| 15 | #include <drm/drm_writeback.h> |
| 16 | #include <drm/drm_print.h> |
| 17 | |
| 18 | /** |
| 19 | * struct komeda_plane - komeda instance of drm_plane |
| 20 | */ |
| 21 | struct komeda_plane { |
| 22 | /** @base: &drm_plane */ |
| 23 | struct drm_plane base; |
| 24 | /** |
| 25 | * @layer: |
| 26 | * |
| 27 | * represents available layer input pipelines for this plane. |
| 28 | * |
| 29 | * NOTE: |
| 30 | * the layer is not for a specific Layer, but indicate a group of |
| 31 | * Layers with same capabilities. |
| 32 | */ |
| 33 | struct komeda_layer *layer; |
| 34 | }; |
| 35 | |
| 36 | /** |
| 37 | * struct komeda_plane_state |
| 38 | * |
| 39 | * The plane_state can be split into two data flow (left/right) and handled |
| 40 | * by two layers &komeda_plane.layer and &komeda_plane.layer.right |
| 41 | */ |
| 42 | struct komeda_plane_state { |
| 43 | /** @base: &drm_plane_state */ |
| 44 | struct drm_plane_state base; |
| 45 | /** @zlist_node: zorder list node */ |
| 46 | struct list_head zlist_node; |
| 47 | |
| 48 | /** @layer_split: on/off layer_split */ |
| 49 | u8 layer_split : 1; |
| 50 | }; |
| 51 | |
| 52 | /** |
| 53 | * struct komeda_wb_connector |
| 54 | */ |
| 55 | struct komeda_wb_connector { |
| 56 | /** @base: &drm_writeback_connector */ |
| 57 | struct drm_writeback_connector base; |
| 58 | |
| 59 | /** @wb_layer: represents associated writeback pipeline of komeda */ |
| 60 | struct komeda_layer *wb_layer; |
| 61 | }; |
| 62 | |
| 63 | /** |
| 64 | * struct komeda_crtc |
| 65 | */ |
| 66 | struct komeda_crtc { |
| 67 | /** @base: &drm_crtc */ |
| 68 | struct drm_crtc base; |
| 69 | /** @master: only master has display output */ |
| 70 | struct komeda_pipeline *master; |
| 71 | /** |
| 72 | * @slave: optional |
| 73 | * |
| 74 | * Doesn't have its own display output, the handled data flow will |
| 75 | * merge into the master. |
| 76 | */ |
| 77 | struct komeda_pipeline *slave; |
| 78 | |
| 79 | /** @slave_planes: komeda slave planes mask */ |
| 80 | u32 slave_planes; |
| 81 | |
| 82 | /** @wb_conn: komeda write back connector */ |
| 83 | struct komeda_wb_connector *wb_conn; |
| 84 | |
| 85 | /** @disable_done: this flip_done is for tracing the disable */ |
| 86 | struct completion *disable_done; |
| 87 | |
| 88 | /** @encoder: encoder at the end of the pipeline */ |
| 89 | struct drm_encoder encoder; |
| 90 | }; |
| 91 | |
| 92 | /** |
| 93 | * struct komeda_crtc_state |
| 94 | */ |
| 95 | struct komeda_crtc_state { |
| 96 | /** @base: &drm_crtc_state */ |
| 97 | struct drm_crtc_state base; |
| 98 | |
| 99 | /* private properties */ |
| 100 | |
| 101 | /* computed state which are used by validate/check */ |
| 102 | /** |
| 103 | * @affected_pipes: |
| 104 | * the affected pipelines in once display instance |
| 105 | */ |
| 106 | u32 affected_pipes; |
| 107 | /** |
| 108 | * @active_pipes: |
| 109 | * the active pipelines in once display instance |
| 110 | */ |
| 111 | u32 active_pipes; |
| 112 | |
| 113 | /** @clock_ratio: ratio of (aclk << 32)/pxlclk */ |
| 114 | u64 clock_ratio; |
| 115 | |
| 116 | /** @max_slave_zorder: the maximum of slave zorder */ |
| 117 | u32 max_slave_zorder; |
| 118 | }; |
| 119 | |
| 120 | /** struct komeda_kms_dev - for gather KMS related things */ |
| 121 | struct komeda_kms_dev { |
| 122 | /** @base: &drm_device */ |
| 123 | struct drm_device base; |
| 124 | |
| 125 | /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */ |
| 126 | int n_crtcs; |
| 127 | /** @crtcs: crtcs list */ |
| 128 | struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES]; |
| 129 | }; |
| 130 | |
| 131 | #define to_kplane(p) container_of(p, struct komeda_plane, base) |
| 132 | #define to_kplane_st(p) container_of(p, struct komeda_plane_state, base) |
| 133 | #define to_kconn(p) container_of(p, struct komeda_wb_connector, base) |
| 134 | #define to_kcrtc(p) container_of(p, struct komeda_crtc, base) |
| 135 | #define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base) |
| 136 | #define to_kdev(p) container_of(p, struct komeda_kms_dev, base) |
| 137 | #define to_wb_conn(x) container_of(x, struct drm_writeback_connector, base) |
| 138 | |
| 139 | static inline bool is_writeback_only(struct drm_crtc_state *st) |
| 140 | { |
| 141 | struct komeda_wb_connector *wb_conn = to_kcrtc(st->crtc)->wb_conn; |
| 142 | struct drm_connector *conn = wb_conn ? &wb_conn->base.base : NULL; |
| 143 | |
| 144 | return conn && (st->connector_mask == BIT(drm_connector_index(conn))); |
| 145 | } |
| 146 | |
| 147 | static inline bool |
| 148 | is_only_changed_connector(struct drm_crtc_state *st, struct drm_connector *conn) |
| 149 | { |
| 150 | struct drm_crtc_state *old_st; |
| 151 | u32 changed_connectors; |
| 152 | |
| 153 | old_st = drm_atomic_get_old_crtc_state(state: st->state, crtc: st->crtc); |
| 154 | changed_connectors = st->connector_mask ^ old_st->connector_mask; |
| 155 | |
| 156 | return BIT(drm_connector_index(conn)) == changed_connectors; |
| 157 | } |
| 158 | |
| 159 | static inline bool has_flip_h(u32 rot) |
| 160 | { |
| 161 | u32 rotation = drm_rotation_simplify(rotation: rot, |
| 162 | DRM_MODE_ROTATE_0 | |
| 163 | DRM_MODE_ROTATE_90 | |
| 164 | DRM_MODE_REFLECT_MASK); |
| 165 | |
| 166 | if (rotation & DRM_MODE_ROTATE_90) |
| 167 | return !!(rotation & DRM_MODE_REFLECT_Y); |
| 168 | else |
| 169 | return !!(rotation & DRM_MODE_REFLECT_X); |
| 170 | } |
| 171 | |
| 172 | void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st, |
| 173 | u32 *color_depths, u32 *color_formats); |
| 174 | unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st); |
| 175 | |
| 176 | int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev); |
| 177 | |
| 178 | int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev); |
| 179 | int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev); |
| 180 | int komeda_kms_add_private_objs(struct komeda_kms_dev *kms, |
| 181 | struct komeda_dev *mdev); |
| 182 | int komeda_kms_add_wb_connectors(struct komeda_kms_dev *kms, |
| 183 | struct komeda_dev *mdev); |
| 184 | void komeda_kms_cleanup_private_objs(struct komeda_kms_dev *kms); |
| 185 | |
| 186 | void komeda_crtc_handle_event(struct komeda_crtc *kcrtc, |
| 187 | struct komeda_events *evts); |
| 188 | void komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc, |
| 189 | struct completion *input_flip_done); |
| 190 | |
| 191 | struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev); |
| 192 | void komeda_kms_detach(struct komeda_kms_dev *kms); |
| 193 | void komeda_kms_shutdown(struct komeda_kms_dev *kms); |
| 194 | void komeda_pipeline_dump(struct komeda_pipeline *pipe); |
| 195 | |
| 196 | #endif /*_KOMEDA_KMS_H_*/ |
| 197 | |