Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 BayLibre, SAS
0004  * Author: Neil Armstrong <narmstrong@baylibre.com>
0005  * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
0006  * Copyright (C) 2014 Endless Mobile
0007  *
0008  * Written by:
0009  *     Jasper St. Pierre <jstpierre@mecheye.net>
0010  */
0011 
0012 #include <linux/export.h>
0013 #include <linux/of_graph.h>
0014 
0015 #include <drm/drm_atomic_helper.h>
0016 #include <drm/drm_bridge.h>
0017 #include <drm/drm_bridge_connector.h>
0018 #include <drm/drm_device.h>
0019 #include <drm/drm_edid.h>
0020 #include <drm/drm_probe_helper.h>
0021 #include <drm/drm_simple_kms_helper.h>
0022 
0023 #include "meson_registers.h"
0024 #include "meson_vclk.h"
0025 #include "meson_encoder_cvbs.h"
0026 
0027 /* HHI VDAC Registers */
0028 #define HHI_VDAC_CNTL0      0x2F4 /* 0xbd offset in data sheet */
0029 #define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */
0030 #define HHI_VDAC_CNTL1      0x2F8 /* 0xbe offset in data sheet */
0031 #define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */
0032 
0033 struct meson_encoder_cvbs {
0034     struct drm_encoder  encoder;
0035     struct drm_bridge   bridge;
0036     struct drm_bridge   *next_bridge;
0037     struct meson_drm    *priv;
0038 };
0039 
0040 #define bridge_to_meson_encoder_cvbs(x) \
0041     container_of(x, struct meson_encoder_cvbs, bridge)
0042 
0043 /* Supported Modes */
0044 
0045 struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT] = {
0046     { /* PAL */
0047         .enci = &meson_cvbs_enci_pal,
0048         .mode = {
0049             DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
0050                  720, 732, 795, 864, 0, 576, 580, 586, 625, 0,
0051                  DRM_MODE_FLAG_INTERLACE),
0052             .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3,
0053         },
0054     },
0055     { /* NTSC */
0056         .enci = &meson_cvbs_enci_ntsc,
0057         .mode = {
0058             DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500,
0059                 720, 739, 801, 858, 0, 480, 488, 494, 525, 0,
0060                 DRM_MODE_FLAG_INTERLACE),
0061             .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3,
0062         },
0063     },
0064 };
0065 
0066 static const struct meson_cvbs_mode *
0067 meson_cvbs_get_mode(const struct drm_display_mode *req_mode)
0068 {
0069     int i;
0070 
0071     for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
0072         struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
0073 
0074         if (drm_mode_match(req_mode, &meson_mode->mode,
0075                    DRM_MODE_MATCH_TIMINGS |
0076                    DRM_MODE_MATCH_CLOCK |
0077                    DRM_MODE_MATCH_FLAGS |
0078                    DRM_MODE_MATCH_3D_FLAGS))
0079             return meson_mode;
0080     }
0081 
0082     return NULL;
0083 }
0084 
0085 static int meson_encoder_cvbs_attach(struct drm_bridge *bridge,
0086                      enum drm_bridge_attach_flags flags)
0087 {
0088     struct meson_encoder_cvbs *meson_encoder_cvbs =
0089                     bridge_to_meson_encoder_cvbs(bridge);
0090 
0091     return drm_bridge_attach(bridge->encoder, meson_encoder_cvbs->next_bridge,
0092                  &meson_encoder_cvbs->bridge, flags);
0093 }
0094 
0095 static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
0096                     struct drm_connector *connector)
0097 {
0098     struct meson_encoder_cvbs *meson_encoder_cvbs =
0099                     bridge_to_meson_encoder_cvbs(bridge);
0100     struct meson_drm *priv = meson_encoder_cvbs->priv;
0101     struct drm_display_mode *mode;
0102     int i;
0103 
0104     for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
0105         struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
0106 
0107         mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
0108         if (!mode) {
0109             dev_err(priv->dev, "Failed to create a new display mode\n");
0110             return 0;
0111         }
0112 
0113         drm_mode_probed_add(connector, mode);
0114     }
0115 
0116     return i;
0117 }
0118 
0119 static int meson_encoder_cvbs_mode_valid(struct drm_bridge *bridge,
0120                     const struct drm_display_info *display_info,
0121                     const struct drm_display_mode *mode)
0122 {
0123     if (meson_cvbs_get_mode(mode))
0124         return MODE_OK;
0125 
0126     return MODE_BAD;
0127 }
0128 
0129 static int meson_encoder_cvbs_atomic_check(struct drm_bridge *bridge,
0130                     struct drm_bridge_state *bridge_state,
0131                     struct drm_crtc_state *crtc_state,
0132                     struct drm_connector_state *conn_state)
0133 {
0134     if (meson_cvbs_get_mode(&crtc_state->mode))
0135         return 0;
0136 
0137     return -EINVAL;
0138 }
0139 
0140 static void meson_encoder_cvbs_atomic_enable(struct drm_bridge *bridge,
0141                          struct drm_bridge_state *bridge_state)
0142 {
0143     struct meson_encoder_cvbs *encoder_cvbs = bridge_to_meson_encoder_cvbs(bridge);
0144     struct drm_atomic_state *state = bridge_state->base.state;
0145     struct meson_drm *priv = encoder_cvbs->priv;
0146     const struct meson_cvbs_mode *meson_mode;
0147     struct drm_connector_state *conn_state;
0148     struct drm_crtc_state *crtc_state;
0149     struct drm_connector *connector;
0150 
0151     connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
0152     if (WARN_ON(!connector))
0153         return;
0154 
0155     conn_state = drm_atomic_get_new_connector_state(state, connector);
0156     if (WARN_ON(!conn_state))
0157         return;
0158 
0159     crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
0160     if (WARN_ON(!crtc_state))
0161         return;
0162 
0163     meson_mode = meson_cvbs_get_mode(&crtc_state->adjusted_mode);
0164     if (WARN_ON(!meson_mode))
0165         return;
0166 
0167     meson_venci_cvbs_mode_set(priv, meson_mode->enci);
0168 
0169     /* Setup 27MHz vclk2 for ENCI and VDAC */
0170     meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
0171              MESON_VCLK_CVBS, MESON_VCLK_CVBS,
0172              MESON_VCLK_CVBS, MESON_VCLK_CVBS,
0173              true);
0174 
0175     /* VDAC0 source is not from ATV */
0176     writel_bits_relaxed(VENC_VDAC_SEL_ATV_DMD, 0,
0177                 priv->io_base + _REG(VENC_VDAC_DACSEL0));
0178 
0179     if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
0180         regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1);
0181         regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
0182     } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
0183          meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
0184         regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001);
0185         regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
0186     } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
0187         regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001);
0188         regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
0189     }
0190 }
0191 
0192 static void meson_encoder_cvbs_atomic_disable(struct drm_bridge *bridge,
0193                           struct drm_bridge_state *bridge_state)
0194 {
0195     struct meson_encoder_cvbs *meson_encoder_cvbs =
0196                     bridge_to_meson_encoder_cvbs(bridge);
0197     struct meson_drm *priv = meson_encoder_cvbs->priv;
0198 
0199     /* Disable CVBS VDAC */
0200     if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
0201         regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
0202         regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
0203     } else {
0204         regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
0205         regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
0206     }
0207 }
0208 
0209 static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
0210     .attach = meson_encoder_cvbs_attach,
0211     .mode_valid = meson_encoder_cvbs_mode_valid,
0212     .get_modes = meson_encoder_cvbs_get_modes,
0213     .atomic_enable = meson_encoder_cvbs_atomic_enable,
0214     .atomic_disable = meson_encoder_cvbs_atomic_disable,
0215     .atomic_check = meson_encoder_cvbs_atomic_check,
0216     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
0217     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
0218     .atomic_reset = drm_atomic_helper_bridge_reset,
0219 };
0220 
0221 int meson_encoder_cvbs_init(struct meson_drm *priv)
0222 {
0223     struct drm_device *drm = priv->drm;
0224     struct meson_encoder_cvbs *meson_encoder_cvbs;
0225     struct drm_connector *connector;
0226     struct device_node *remote;
0227     int ret;
0228 
0229     meson_encoder_cvbs = devm_kzalloc(priv->dev, sizeof(*meson_encoder_cvbs), GFP_KERNEL);
0230     if (!meson_encoder_cvbs)
0231         return -ENOMEM;
0232 
0233     /* CVBS Connector Bridge */
0234     remote = of_graph_get_remote_node(priv->dev->of_node, 0, 0);
0235     if (!remote) {
0236         dev_info(drm->dev, "CVBS Output connector not available\n");
0237         return 0;
0238     }
0239 
0240     meson_encoder_cvbs->next_bridge = of_drm_find_bridge(remote);
0241     of_node_put(remote);
0242     if (!meson_encoder_cvbs->next_bridge) {
0243         dev_err(priv->dev, "Failed to find CVBS Connector bridge\n");
0244         return -EPROBE_DEFER;
0245     }
0246 
0247     /* CVBS Encoder Bridge */
0248     meson_encoder_cvbs->bridge.funcs = &meson_encoder_cvbs_bridge_funcs;
0249     meson_encoder_cvbs->bridge.of_node = priv->dev->of_node;
0250     meson_encoder_cvbs->bridge.type = DRM_MODE_CONNECTOR_Composite;
0251     meson_encoder_cvbs->bridge.ops = DRM_BRIDGE_OP_MODES;
0252     meson_encoder_cvbs->bridge.interlace_allowed = true;
0253 
0254     drm_bridge_add(&meson_encoder_cvbs->bridge);
0255 
0256     meson_encoder_cvbs->priv = priv;
0257 
0258     /* Encoder */
0259     ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
0260                       DRM_MODE_ENCODER_TVDAC);
0261     if (ret) {
0262         dev_err(priv->dev, "Failed to init CVBS encoder: %d\n", ret);
0263         return ret;
0264     }
0265 
0266     meson_encoder_cvbs->encoder.possible_crtcs = BIT(0);
0267 
0268     /* Attach CVBS Encoder Bridge to Encoder */
0269     ret = drm_bridge_attach(&meson_encoder_cvbs->encoder, &meson_encoder_cvbs->bridge, NULL,
0270                 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
0271     if (ret) {
0272         dev_err(priv->dev, "Failed to attach bridge: %d\n", ret);
0273         return ret;
0274     }
0275 
0276     /* Initialize & attach Bridge Connector */
0277     connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
0278     if (IS_ERR(connector)) {
0279         dev_err(priv->dev, "Unable to create CVBS bridge connector\n");
0280         return PTR_ERR(connector);
0281     }
0282     drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder);
0283 
0284     return 0;
0285 }