···1111 Choose this option if you have an R-Car chipset.1212 If M is selected the module will be called rcar-du-drm.13131414+config DRM_RCAR_HDMI1515+ bool "R-Car DU HDMI Encoder Support"1616+ depends on DRM_RCAR_DU1717+ depends on OF1818+ help1919+ Enable support for external HDMI encoders.2020+1421config DRM_RCAR_LVDS1522 bool "R-Car DU LVDS Encoder Support"1623 depends on DRM_RCAR_DU1724 depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST1825 help1919- Enable support the R-Car Display Unit embedded LVDS encoders2020- (currently only on R8A7790).2626+ Enable support for the R-Car Display Unit embedded LVDS encoders2727+ (currently only on R8A7790 and R8A7791).
···11+/*22+ * R-Car Display Unit HDMI Connector33+ *44+ * Copyright (C) 2014 Renesas Electronics Corporation55+ *66+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License as published by1010+ * the Free Software Foundation; either version 2 of the License, or1111+ * (at your option) any later version.1212+ */1313+1414+#include <drm/drmP.h>1515+#include <drm/drm_crtc.h>1616+#include <drm/drm_crtc_helper.h>1717+#include <drm/drm_encoder_slave.h>1818+1919+#include "rcar_du_drv.h"2020+#include "rcar_du_encoder.h"2121+#include "rcar_du_hdmicon.h"2222+#include "rcar_du_kms.h"2323+2424+#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs)2525+2626+static int rcar_du_hdmi_connector_get_modes(struct drm_connector *connector)2727+{2828+ struct drm_encoder *encoder = connector->encoder;2929+ struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);3030+3131+ if (sfuncs->get_modes == NULL)3232+ return 0;3333+3434+ return sfuncs->get_modes(encoder, connector);3535+}3636+3737+static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector,3838+ struct drm_display_mode *mode)3939+{4040+ struct drm_encoder *encoder = connector->encoder;4141+ struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);4242+4343+ if (sfuncs->mode_valid == NULL)4444+ return MODE_OK;4545+4646+ return sfuncs->mode_valid(encoder, mode);4747+}4848+4949+static const struct drm_connector_helper_funcs connector_helper_funcs = {5050+ .get_modes = rcar_du_hdmi_connector_get_modes,5151+ .mode_valid = rcar_du_hdmi_connector_mode_valid,5252+ .best_encoder = rcar_du_connector_best_encoder,5353+};5454+5555+static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector)5656+{5757+ drm_connector_unregister(connector);5858+ drm_connector_cleanup(connector);5959+}6060+6161+static enum drm_connector_status6262+rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)6363+{6464+ struct drm_encoder *encoder = connector->encoder;6565+ struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);6666+6767+ if (sfuncs->detect == NULL)6868+ return connector_status_unknown;6969+7070+ return sfuncs->detect(encoder, connector);7171+}7272+7373+static const struct drm_connector_funcs connector_funcs = {7474+ .dpms = drm_helper_connector_dpms,7575+ .detect = rcar_du_hdmi_connector_detect,7676+ .fill_modes = drm_helper_probe_single_connector_modes,7777+ .destroy = rcar_du_hdmi_connector_destroy,7878+};7979+8080+int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,8181+ struct rcar_du_encoder *renc)8282+{8383+ struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);8484+ struct rcar_du_connector *rcon;8585+ struct drm_connector *connector;8686+ int ret;8787+8888+ rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL);8989+ if (rcon == NULL)9090+ return -ENOMEM;9191+9292+ connector = &rcon->connector;9393+ connector->display_info.width_mm = 0;9494+ connector->display_info.height_mm = 0;9595+9696+ ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,9797+ DRM_MODE_CONNECTOR_HDMIA);9898+ if (ret < 0)9999+ return ret;100100+101101+ drm_connector_helper_add(connector, &connector_helper_funcs);102102+ ret = drm_connector_register(connector);103103+ if (ret < 0)104104+ return ret;105105+106106+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);107107+ drm_object_property_set_value(&connector->base,108108+ rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);109109+110110+ ret = drm_mode_connector_attach_encoder(connector, encoder);111111+ if (ret < 0)112112+ return ret;113113+114114+ connector->encoder = encoder;115115+ rcon->encoder = renc;116116+117117+ return 0;118118+}
+31
drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h
···11+/*22+ * R-Car Display Unit HDMI Connector33+ *44+ * Copyright (C) 2014 Renesas Electronics Corporation55+ *66+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License as published by1010+ * the Free Software Foundation; either version 2 of the License, or1111+ * (at your option) any later version.1212+ */1313+1414+#ifndef __RCAR_DU_HDMICON_H__1515+#define __RCAR_DU_HDMICON_H__1616+1717+struct rcar_du_device;1818+struct rcar_du_encoder;1919+2020+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)2121+int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,2222+ struct rcar_du_encoder *renc);2323+#else2424+static inline int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,2525+ struct rcar_du_encoder *renc)2626+{2727+ return -ENOSYS;2828+}2929+#endif3030+3131+#endif /* __RCAR_DU_HDMICON_H__ */
+151
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
···11+/*22+ * R-Car Display Unit HDMI Encoder33+ *44+ * Copyright (C) 2014 Renesas Electronics Corporation55+ *66+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License as published by1010+ * the Free Software Foundation; either version 2 of the License, or1111+ * (at your option) any later version.1212+ */1313+1414+#include <linux/slab.h>1515+1616+#include <drm/drmP.h>1717+#include <drm/drm_crtc.h>1818+#include <drm/drm_crtc_helper.h>1919+#include <drm/drm_encoder_slave.h>2020+2121+#include "rcar_du_drv.h"2222+#include "rcar_du_encoder.h"2323+#include "rcar_du_hdmienc.h"2424+2525+struct rcar_du_hdmienc {2626+ struct rcar_du_encoder *renc;2727+ struct device *dev;2828+ int dpms;2929+};3030+3131+#define to_rcar_hdmienc(e) (to_rcar_encoder(e)->hdmi)3232+#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs)3333+3434+static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode)3535+{3636+ struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);3737+ struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);3838+3939+ if (hdmienc->dpms == mode)4040+ return;4141+4242+ if (sfuncs->dpms)4343+ sfuncs->dpms(encoder, mode);4444+4545+ hdmienc->dpms = mode;4646+}4747+4848+static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,4949+ const struct drm_display_mode *mode,5050+ struct drm_display_mode *adjusted_mode)5151+{5252+ struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);5353+5454+ if (sfuncs->mode_fixup == NULL)5555+ return true;5656+5757+ return sfuncs->mode_fixup(encoder, mode, adjusted_mode);5858+}5959+6060+static void rcar_du_hdmienc_mode_prepare(struct drm_encoder *encoder)6161+{6262+ rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF);6363+}6464+6565+static void rcar_du_hdmienc_mode_commit(struct drm_encoder *encoder)6666+{6767+ rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_ON);6868+}6969+7070+static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,7171+ struct drm_display_mode *mode,7272+ struct drm_display_mode *adjusted_mode)7373+{7474+ struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);7575+ struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);7676+7777+ if (sfuncs->mode_set)7878+ sfuncs->mode_set(encoder, mode, adjusted_mode);7979+8080+ rcar_du_crtc_route_output(encoder->crtc, hdmienc->renc->output);8181+}8282+8383+static const struct drm_encoder_helper_funcs encoder_helper_funcs = {8484+ .dpms = rcar_du_hdmienc_dpms,8585+ .mode_fixup = rcar_du_hdmienc_mode_fixup,8686+ .prepare = rcar_du_hdmienc_mode_prepare,8787+ .commit = rcar_du_hdmienc_mode_commit,8888+ .mode_set = rcar_du_hdmienc_mode_set,8989+};9090+9191+static void rcar_du_hdmienc_cleanup(struct drm_encoder *encoder)9292+{9393+ struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);9494+9595+ rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF);9696+9797+ drm_encoder_cleanup(encoder);9898+ put_device(hdmienc->dev);9999+}100100+101101+static const struct drm_encoder_funcs encoder_funcs = {102102+ .destroy = rcar_du_hdmienc_cleanup,103103+};104104+105105+int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,106106+ struct rcar_du_encoder *renc, struct device_node *np)107107+{108108+ struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);109109+ struct drm_i2c_encoder_driver *driver;110110+ struct i2c_client *i2c_slave;111111+ struct rcar_du_hdmienc *hdmienc;112112+ int ret;113113+114114+ hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL);115115+ if (hdmienc == NULL)116116+ return -ENOMEM;117117+118118+ /* Locate the slave I2C device and driver. */119119+ i2c_slave = of_find_i2c_device_by_node(np);120120+ if (!i2c_slave || !i2c_get_clientdata(i2c_slave))121121+ return -EPROBE_DEFER;122122+123123+ hdmienc->dev = &i2c_slave->dev;124124+125125+ if (hdmienc->dev->driver == NULL) {126126+ ret = -EPROBE_DEFER;127127+ goto error;128128+ }129129+130130+ /* Initialize the slave encoder. */131131+ driver = to_drm_i2c_encoder_driver(to_i2c_driver(hdmienc->dev->driver));132132+ ret = driver->encoder_init(i2c_slave, rcdu->ddev, &renc->slave);133133+ if (ret < 0)134134+ goto error;135135+136136+ ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,137137+ DRM_MODE_ENCODER_TMDS);138138+ if (ret < 0)139139+ goto error;140140+141141+ drm_encoder_helper_add(encoder, &encoder_helper_funcs);142142+143143+ renc->hdmi = hdmienc;144144+ hdmienc->renc = renc;145145+146146+ return 0;147147+148148+error:149149+ put_device(hdmienc->dev);150150+ return ret;151151+}
+35
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h
···11+/*22+ * R-Car Display Unit HDMI Encoder33+ *44+ * Copyright (C) 2014 Renesas Electronics Corporation55+ *66+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License as published by1010+ * the Free Software Foundation; either version 2 of the License, or1111+ * (at your option) any later version.1212+ */1313+1414+#ifndef __RCAR_DU_HDMIENC_H__1515+#define __RCAR_DU_HDMIENC_H__1616+1717+#include <linux/module.h>1818+1919+struct device_node;2020+struct rcar_du_device;2121+struct rcar_du_encoder;2222+2323+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)2424+int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,2525+ struct rcar_du_encoder *renc, struct device_node *np);2626+#else2727+static inline int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,2828+ struct rcar_du_encoder *renc,2929+ struct device_node *np)3030+{3131+ return -ENOSYS;3232+}3333+#endif3434+3535+#endif /* __RCAR_DU_HDMIENC_H__ */