0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/of.h>
0011 #include <linux/of_graph.h>
0012 #include <linux/regulator/consumer.h>
0013
0014 #include <drm/drm_atomic_helper.h>
0015 #include <drm/drm_panel.h>
0016 #include <drm/drm_print.h>
0017 #include <drm/drm_probe_helper.h>
0018 #include <drm/drm_simple_kms_helper.h>
0019
0020 #include <video/of_videomode.h>
0021 #include <video/videomode.h>
0022
0023 #include "exynos_drm_crtc.h"
0024
0025 struct exynos_dpi {
0026 struct drm_encoder encoder;
0027 struct device *dev;
0028 struct device_node *panel_node;
0029
0030 struct drm_panel *panel;
0031 struct drm_connector connector;
0032
0033 struct videomode *vm;
0034 };
0035
0036 #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
0037
0038 static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e)
0039 {
0040 return container_of(e, struct exynos_dpi, encoder);
0041 }
0042
0043 static enum drm_connector_status
0044 exynos_dpi_detect(struct drm_connector *connector, bool force)
0045 {
0046 return connector_status_connected;
0047 }
0048
0049 static void exynos_dpi_connector_destroy(struct drm_connector *connector)
0050 {
0051 drm_connector_unregister(connector);
0052 drm_connector_cleanup(connector);
0053 }
0054
0055 static const struct drm_connector_funcs exynos_dpi_connector_funcs = {
0056 .detect = exynos_dpi_detect,
0057 .fill_modes = drm_helper_probe_single_connector_modes,
0058 .destroy = exynos_dpi_connector_destroy,
0059 .reset = drm_atomic_helper_connector_reset,
0060 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
0061 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
0062 };
0063
0064 static int exynos_dpi_get_modes(struct drm_connector *connector)
0065 {
0066 struct exynos_dpi *ctx = connector_to_dpi(connector);
0067
0068
0069 if (ctx->vm) {
0070 struct drm_display_mode *mode;
0071
0072 mode = drm_mode_create(connector->dev);
0073 if (!mode) {
0074 DRM_DEV_ERROR(ctx->dev,
0075 "failed to create a new display mode\n");
0076 return 0;
0077 }
0078 drm_display_mode_from_videomode(ctx->vm, mode);
0079 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0080 drm_mode_probed_add(connector, mode);
0081 return 1;
0082 }
0083
0084 if (ctx->panel)
0085 return drm_panel_get_modes(ctx->panel, connector);
0086
0087 return 0;
0088 }
0089
0090 static const struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
0091 .get_modes = exynos_dpi_get_modes,
0092 };
0093
0094 static int exynos_dpi_create_connector(struct drm_encoder *encoder)
0095 {
0096 struct exynos_dpi *ctx = encoder_to_dpi(encoder);
0097 struct drm_connector *connector = &ctx->connector;
0098 int ret;
0099
0100 connector->polled = DRM_CONNECTOR_POLL_HPD;
0101
0102 ret = drm_connector_init(encoder->dev, connector,
0103 &exynos_dpi_connector_funcs,
0104 DRM_MODE_CONNECTOR_VGA);
0105 if (ret) {
0106 DRM_DEV_ERROR(ctx->dev,
0107 "failed to initialize connector with drm\n");
0108 return ret;
0109 }
0110
0111 drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs);
0112 drm_connector_attach_encoder(connector, encoder);
0113
0114 return 0;
0115 }
0116
0117 static void exynos_dpi_mode_set(struct drm_encoder *encoder,
0118 struct drm_display_mode *mode,
0119 struct drm_display_mode *adjusted_mode)
0120 {
0121 }
0122
0123 static void exynos_dpi_enable(struct drm_encoder *encoder)
0124 {
0125 struct exynos_dpi *ctx = encoder_to_dpi(encoder);
0126
0127 if (ctx->panel) {
0128 drm_panel_prepare(ctx->panel);
0129 drm_panel_enable(ctx->panel);
0130 }
0131 }
0132
0133 static void exynos_dpi_disable(struct drm_encoder *encoder)
0134 {
0135 struct exynos_dpi *ctx = encoder_to_dpi(encoder);
0136
0137 if (ctx->panel) {
0138 drm_panel_disable(ctx->panel);
0139 drm_panel_unprepare(ctx->panel);
0140 }
0141 }
0142
0143 static const struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
0144 .mode_set = exynos_dpi_mode_set,
0145 .enable = exynos_dpi_enable,
0146 .disable = exynos_dpi_disable,
0147 };
0148
0149 enum {
0150 FIMD_PORT_IN0,
0151 FIMD_PORT_IN1,
0152 FIMD_PORT_IN2,
0153 FIMD_PORT_RGB,
0154 FIMD_PORT_WRB,
0155 };
0156
0157 static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
0158 {
0159 struct device *dev = ctx->dev;
0160 struct device_node *dn = dev->of_node;
0161 struct device_node *np;
0162
0163 ctx->panel_node = of_graph_get_remote_node(dn, FIMD_PORT_RGB, 0);
0164
0165 np = of_get_child_by_name(dn, "display-timings");
0166 if (np) {
0167 struct videomode *vm;
0168 int ret;
0169
0170 of_node_put(np);
0171
0172 vm = devm_kzalloc(dev, sizeof(*ctx->vm), GFP_KERNEL);
0173 if (!vm)
0174 return -ENOMEM;
0175
0176 ret = of_get_videomode(dn, vm, 0);
0177 if (ret < 0) {
0178 devm_kfree(dev, vm);
0179 return ret;
0180 }
0181
0182 ctx->vm = vm;
0183
0184 return 0;
0185 }
0186
0187 if (!ctx->panel_node)
0188 return -EINVAL;
0189
0190 return 0;
0191 }
0192
0193 int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
0194 {
0195 int ret;
0196
0197 drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS);
0198
0199 drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);
0200
0201 ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
0202 if (ret < 0)
0203 return ret;
0204
0205 ret = exynos_dpi_create_connector(encoder);
0206 if (ret) {
0207 DRM_DEV_ERROR(encoder_to_dpi(encoder)->dev,
0208 "failed to create connector ret = %d\n", ret);
0209 drm_encoder_cleanup(encoder);
0210 return ret;
0211 }
0212
0213 return 0;
0214 }
0215
0216 struct drm_encoder *exynos_dpi_probe(struct device *dev)
0217 {
0218 struct exynos_dpi *ctx;
0219 int ret;
0220
0221 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0222 if (!ctx)
0223 return ERR_PTR(-ENOMEM);
0224
0225 ctx->dev = dev;
0226
0227 ret = exynos_dpi_parse_dt(ctx);
0228 if (ret < 0) {
0229 devm_kfree(dev, ctx);
0230 return NULL;
0231 }
0232
0233 if (ctx->panel_node) {
0234 ctx->panel = of_drm_find_panel(ctx->panel_node);
0235 if (IS_ERR(ctx->panel))
0236 return ERR_CAST(ctx->panel);
0237 }
0238
0239 return &ctx->encoder;
0240 }
0241
0242 int exynos_dpi_remove(struct drm_encoder *encoder)
0243 {
0244 struct exynos_dpi *ctx = encoder_to_dpi(encoder);
0245
0246 exynos_dpi_disable(&ctx->encoder);
0247
0248 return 0;
0249 }