0001
0002
0003
0004
0005
0006
0007 #include <linux/dma-fence.h>
0008
0009 #include <drm/drm_atomic.h>
0010 #include <drm/drm_atomic_helper.h>
0011 #include <drm/drm_bridge.h>
0012 #include <drm/drm_crtc_helper.h>
0013 #include <drm/drm_fb_cma_helper.h>
0014 #include <drm/drm_fb_helper.h>
0015 #include <drm/drm_gem_framebuffer_helper.h>
0016 #include <drm/drm_of.h>
0017 #include <drm/drm_panel.h>
0018 #include <drm/drm_vblank.h>
0019
0020 #include "tidss_crtc.h"
0021 #include "tidss_dispc.h"
0022 #include "tidss_drv.h"
0023 #include "tidss_encoder.h"
0024 #include "tidss_kms.h"
0025 #include "tidss_plane.h"
0026
0027 static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state)
0028 {
0029 struct drm_device *ddev = old_state->dev;
0030 struct tidss_device *tidss = to_tidss(ddev);
0031 bool fence_cookie = dma_fence_begin_signalling();
0032
0033 dev_dbg(ddev->dev, "%s\n", __func__);
0034
0035 tidss_runtime_get(tidss);
0036
0037 drm_atomic_helper_commit_modeset_disables(ddev, old_state);
0038 drm_atomic_helper_commit_planes(ddev, old_state, 0);
0039 drm_atomic_helper_commit_modeset_enables(ddev, old_state);
0040
0041 drm_atomic_helper_commit_hw_done(old_state);
0042 dma_fence_end_signalling(fence_cookie);
0043 drm_atomic_helper_wait_for_flip_done(ddev, old_state);
0044
0045 drm_atomic_helper_cleanup_planes(ddev, old_state);
0046
0047 tidss_runtime_put(tidss);
0048 }
0049
0050 static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = {
0051 .atomic_commit_tail = tidss_atomic_commit_tail,
0052 };
0053
0054 static int tidss_atomic_check(struct drm_device *ddev,
0055 struct drm_atomic_state *state)
0056 {
0057 struct drm_plane_state *opstate;
0058 struct drm_plane_state *npstate;
0059 struct drm_plane *plane;
0060 struct drm_crtc_state *cstate;
0061 struct drm_crtc *crtc;
0062 int ret, i;
0063
0064 ret = drm_atomic_helper_check(ddev, state);
0065 if (ret)
0066 return ret;
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 for_each_oldnew_plane_in_state(state, plane, opstate, npstate, i) {
0079 if (!npstate->crtc || !npstate->visible)
0080 continue;
0081
0082 if (!opstate->crtc || opstate->crtc_x != npstate->crtc_x ||
0083 opstate->crtc_y != npstate->crtc_y) {
0084 cstate = drm_atomic_get_crtc_state(state,
0085 npstate->crtc);
0086 if (IS_ERR(cstate))
0087 return PTR_ERR(cstate);
0088 to_tidss_crtc_state(cstate)->plane_pos_changed = true;
0089 }
0090 }
0091
0092 for_each_new_crtc_in_state(state, crtc, cstate, i) {
0093 if (to_tidss_crtc_state(cstate)->plane_pos_changed ||
0094 cstate->zpos_changed) {
0095 ret = drm_atomic_add_affected_planes(state, crtc);
0096 if (ret)
0097 return ret;
0098 }
0099 }
0100
0101 return 0;
0102 }
0103
0104 static const struct drm_mode_config_funcs mode_config_funcs = {
0105 .fb_create = drm_gem_fb_create,
0106 .atomic_check = tidss_atomic_check,
0107 .atomic_commit = drm_atomic_helper_commit,
0108 };
0109
0110 static int tidss_dispc_modeset_init(struct tidss_device *tidss)
0111 {
0112 struct device *dev = tidss->dev;
0113 unsigned int fourccs_len;
0114 const u32 *fourccs = dispc_plane_formats(tidss->dispc, &fourccs_len);
0115 unsigned int i;
0116
0117 struct pipe {
0118 u32 hw_videoport;
0119 struct drm_bridge *bridge;
0120 u32 enc_type;
0121 };
0122
0123 const struct dispc_features *feat = tidss->feat;
0124 u32 max_vps = feat->num_vps;
0125 u32 max_planes = feat->num_planes;
0126
0127 struct pipe pipes[TIDSS_MAX_PORTS];
0128 u32 num_pipes = 0;
0129 u32 crtc_mask;
0130
0131
0132
0133 for (i = 0; i < max_vps; i++) {
0134 struct drm_panel *panel;
0135 struct drm_bridge *bridge;
0136 u32 enc_type = DRM_MODE_ENCODER_NONE;
0137 int ret;
0138
0139 ret = drm_of_find_panel_or_bridge(dev->of_node, i, 0,
0140 &panel, &bridge);
0141 if (ret == -ENODEV) {
0142 dev_dbg(dev, "no panel/bridge for port %d\n", i);
0143 continue;
0144 } else if (ret) {
0145 dev_dbg(dev, "port %d probe returned %d\n", i, ret);
0146 return ret;
0147 }
0148
0149 if (panel) {
0150 u32 conn_type;
0151
0152 dev_dbg(dev, "Setting up panel for port %d\n", i);
0153
0154 switch (feat->vp_bus_type[i]) {
0155 case DISPC_VP_OLDI:
0156 enc_type = DRM_MODE_ENCODER_LVDS;
0157 conn_type = DRM_MODE_CONNECTOR_LVDS;
0158 break;
0159 case DISPC_VP_DPI:
0160 enc_type = DRM_MODE_ENCODER_DPI;
0161 conn_type = DRM_MODE_CONNECTOR_DPI;
0162 break;
0163 default:
0164 WARN_ON(1);
0165 return -EINVAL;
0166 }
0167
0168 if (panel->connector_type != conn_type) {
0169 dev_err(dev,
0170 "%s: Panel %s has incompatible connector type for vp%d (%d != %d)\n",
0171 __func__, dev_name(panel->dev), i,
0172 panel->connector_type, conn_type);
0173 return -EINVAL;
0174 }
0175
0176 bridge = devm_drm_panel_bridge_add(dev, panel);
0177 if (IS_ERR(bridge)) {
0178 dev_err(dev,
0179 "failed to set up panel bridge for port %d\n",
0180 i);
0181 return PTR_ERR(bridge);
0182 }
0183 }
0184
0185 pipes[num_pipes].hw_videoport = i;
0186 pipes[num_pipes].bridge = bridge;
0187 pipes[num_pipes].enc_type = enc_type;
0188 num_pipes++;
0189 }
0190
0191
0192 crtc_mask = (1 << num_pipes) - 1;
0193
0194
0195
0196 for (i = 0; i < num_pipes; ++i) {
0197 struct tidss_plane *tplane;
0198 struct tidss_crtc *tcrtc;
0199 struct drm_encoder *enc;
0200 u32 hw_plane_id = feat->vid_order[tidss->num_planes];
0201 int ret;
0202
0203 tplane = tidss_plane_create(tidss, hw_plane_id,
0204 DRM_PLANE_TYPE_PRIMARY, crtc_mask,
0205 fourccs, fourccs_len);
0206 if (IS_ERR(tplane)) {
0207 dev_err(tidss->dev, "plane create failed\n");
0208 return PTR_ERR(tplane);
0209 }
0210
0211 tidss->planes[tidss->num_planes++] = &tplane->plane;
0212
0213 tcrtc = tidss_crtc_create(tidss, pipes[i].hw_videoport,
0214 &tplane->plane);
0215 if (IS_ERR(tcrtc)) {
0216 dev_err(tidss->dev, "crtc create failed\n");
0217 return PTR_ERR(tcrtc);
0218 }
0219
0220 tidss->crtcs[tidss->num_crtcs++] = &tcrtc->crtc;
0221
0222 enc = tidss_encoder_create(tidss, pipes[i].enc_type,
0223 1 << tcrtc->crtc.index);
0224 if (IS_ERR(enc)) {
0225 dev_err(tidss->dev, "encoder create failed\n");
0226 return PTR_ERR(enc);
0227 }
0228
0229 ret = drm_bridge_attach(enc, pipes[i].bridge, NULL, 0);
0230 if (ret)
0231 return ret;
0232 }
0233
0234
0235
0236 while (tidss->num_planes < max_planes) {
0237 struct tidss_plane *tplane;
0238 u32 hw_plane_id = feat->vid_order[tidss->num_planes];
0239
0240 tplane = tidss_plane_create(tidss, hw_plane_id,
0241 DRM_PLANE_TYPE_OVERLAY, crtc_mask,
0242 fourccs, fourccs_len);
0243
0244 if (IS_ERR(tplane)) {
0245 dev_err(tidss->dev, "plane create failed\n");
0246 return PTR_ERR(tplane);
0247 }
0248
0249 tidss->planes[tidss->num_planes++] = &tplane->plane;
0250 }
0251
0252 return 0;
0253 }
0254
0255 int tidss_modeset_init(struct tidss_device *tidss)
0256 {
0257 struct drm_device *ddev = &tidss->ddev;
0258 int ret;
0259
0260 dev_dbg(tidss->dev, "%s\n", __func__);
0261
0262 ret = drmm_mode_config_init(ddev);
0263 if (ret)
0264 return ret;
0265
0266 ddev->mode_config.min_width = 8;
0267 ddev->mode_config.min_height = 8;
0268 ddev->mode_config.max_width = 8096;
0269 ddev->mode_config.max_height = 8096;
0270 ddev->mode_config.normalize_zpos = true;
0271 ddev->mode_config.funcs = &mode_config_funcs;
0272 ddev->mode_config.helper_private = &mode_config_helper_funcs;
0273
0274 ret = tidss_dispc_modeset_init(tidss);
0275 if (ret)
0276 return ret;
0277
0278 ret = drm_vblank_init(ddev, tidss->num_crtcs);
0279 if (ret)
0280 return ret;
0281
0282 drm_mode_config_reset(ddev);
0283
0284 dev_dbg(tidss->dev, "%s done\n", __func__);
0285
0286 return 0;
0287 }