diff options
author | Arnd Bergmann <arnd@arndb.de> | 2014-12-30 11:17:07 +0100 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2014-12-30 15:27:20 +0100 |
commit | 7ebdfaa52d15b947503f76474477f92854796d96 (patch) | |
tree | 27cd7acfcd264e8d643db86185f9e3a33a5cf367 /drivers/gpu/drm/rcar-du | |
parent | d6ad36913083d683aad4e02e53580c995f1a6ede (diff) | |
parent | d4b0833a65e8b9fc58d992ba0cc89cad1580db31 (diff) |
Merge tag 'mvebu-fixes-3.19' of git://git.infradead.org/linux-mvebu into fixes
Pull "Fixes for 3.19" from Andrew Lunn:
Jason is taking a back seat this cycle and i'm doing all the patch
wrangling for mvebu.
* tag 'mvebu-fixes-3.19' of git://git.infradead.org/linux-mvebu:
ARM: mvebu: Fix pinctrl configuration for Armada 370 DB
Also update to Linux 3.19-rc1, which this was based on.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/gpu/drm/rcar-du')
-rw-r--r-- | drivers/gpu/drm/rcar-du/Kconfig | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_drv.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_encoder.h | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c | 121 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 151 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h | 35 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_kms.c | 57 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_vgacon.c | 5 |
17 files changed, 438 insertions, 97 deletions
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index c96f6089f8bf..2324a526de65 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -11,10 +11,17 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm. +config DRM_RCAR_HDMI + bool "R-Car DU HDMI Encoder Support" + depends on DRM_RCAR_DU + depends on OF + help + Enable support for external HDMI encoders. + config DRM_RCAR_LVDS bool "R-Car DU LVDS Encoder Support" depends on DRM_RCAR_DU depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST help - Enable support the R-Car Display Unit embedded LVDS encoders - (currently only on R8A7790). + Enable support for the R-Car Display Unit embedded LVDS encoders + (currently only on R8A7790 and R8A7791). diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 12b8d4477835..05de1c4097af 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -7,6 +7,8 @@ rcar-du-drm-y := rcar_du_crtc.o \ rcar_du_plane.o \ rcar_du_vgacon.o +rcar-du-drm-$(CONFIG_DRM_RCAR_HDMI) += rcar_du_hdmicon.o \ + rcar_du_hdmienc.o rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_lvdsenc.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 148b50589181..23cc910951f4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -19,6 +19,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_plane_helper.h> #include "rcar_du_crtc.h" #include "rcar_du_drv.h" @@ -585,7 +586,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) if (irq < 0) { dev_err(rcdu->dev, "no IRQ for CRTC %u\n", index); - return ret; + return irq; } ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index e97ae502dec5..984e6083699f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -15,7 +15,6 @@ #define __RCAR_DU_CRTC_H__ #include <linux/mutex.h> -#include <linux/platform_data/rcar-du.h> #include <drm/drmP.h> #include <drm/drm_crtc.h> @@ -41,6 +40,15 @@ struct rcar_du_crtc { #define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) +enum rcar_du_output { + RCAR_DU_OUTPUT_DPAD0, + RCAR_DU_OUTPUT_DPAD1, + RCAR_DU_OUTPUT_LVDS0, + RCAR_DU_OUTPUT_LVDS1, + RCAR_DU_OUTPUT_TCON, + RCAR_DU_OUTPUT_MAX, +}; + int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index); void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable); void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index d212efa6a495..7bfa09cf18d5 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -146,12 +146,11 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags) { struct platform_device *pdev = dev->platformdev; struct device_node *np = pdev->dev.of_node; - struct rcar_du_platform_data *pdata = pdev->dev.platform_data; struct rcar_du_device *rcdu; struct resource *mem; int ret; - if (pdata == NULL && np == NULL) { + if (np == NULL) { dev_err(dev->dev, "no platform data\n"); return -ENODEV; } @@ -163,7 +162,6 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags) } rcdu->dev = &pdev->dev; - rcdu->pdata = pdata; rcdu->info = np ? of_match_device(rcar_du_of_table, rcdu->dev)->data : (void *)platform_get_device_id(pdev)->driver_data; rcdu->ddev = dev; @@ -330,7 +328,6 @@ static struct platform_driver rcar_du_platform_driver = { .probe = rcar_du_probe, .remove = rcar_du_remove, .driver = { - .owner = THIS_MODULE, .name = "rcar-du", .pm = &rcar_du_pm_ops, .of_match_table = rcar_du_of_table, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 8e494633c3b3..0a724669f02d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -15,7 +15,6 @@ #define __RCAR_DU_DRV_H__ #include <linux/kernel.h> -#include <linux/platform_data/rcar-du.h> #include "rcar_du_crtc.h" #include "rcar_du_group.h" @@ -67,7 +66,6 @@ struct rcar_du_device_info { struct rcar_du_device { struct device *dev; - const struct rcar_du_platform_data *pdata; const struct rcar_du_device_info *info; void __iomem *mmio; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 7c0ec95915ef..34a122a39664 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -19,6 +19,8 @@ #include "rcar_du_drv.h" #include "rcar_du_encoder.h" +#include "rcar_du_hdmicon.h" +#include "rcar_du_hdmienc.h" #include "rcar_du_kms.h" #include "rcar_du_lvdscon.h" #include "rcar_du_lvdsenc.h" @@ -33,7 +35,7 @@ rcar_du_connector_best_encoder(struct drm_connector *connector) { struct rcar_du_connector *rcon = to_rcar_connector(connector); - return &rcon->encoder->encoder; + return rcar_encoder_to_drm_encoder(rcon->encoder); } /* ----------------------------------------------------------------------------- @@ -142,10 +144,11 @@ static const struct drm_encoder_funcs encoder_funcs = { int rcar_du_encoder_init(struct rcar_du_device *rcdu, enum rcar_du_encoder_type type, enum rcar_du_output output, - const struct rcar_du_encoder_data *data, - struct device_node *np) + struct device_node *enc_node, + struct device_node *con_node) { struct rcar_du_encoder *renc; + struct drm_encoder *encoder; unsigned int encoder_type; int ret; @@ -154,6 +157,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, return -ENOMEM; renc->output = output; + encoder = rcar_encoder_to_drm_encoder(renc); switch (output) { case RCAR_DU_OUTPUT_LVDS0: @@ -175,6 +179,9 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, case RCAR_DU_ENCODER_LVDS: encoder_type = DRM_MODE_ENCODER_LVDS; break; + case RCAR_DU_ENCODER_HDMI: + encoder_type = DRM_MODE_ENCODER_TMDS; + break; case RCAR_DU_ENCODER_NONE: default: /* No external encoder, use the internal encoder type. */ @@ -182,23 +189,35 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, break; } - ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs, - encoder_type); - if (ret < 0) - return ret; + if (type == RCAR_DU_ENCODER_HDMI) { + if (renc->lvds) { + dev_err(rcdu->dev, + "Chaining LVDS and HDMI encoders not supported\n"); + return -EINVAL; + } - drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs); + ret = rcar_du_hdmienc_init(rcdu, renc, enc_node); + if (ret < 0) + return ret; + } else { + ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, + encoder_type); + if (ret < 0) + return ret; - switch (encoder_type) { - case DRM_MODE_ENCODER_LVDS: { - const struct rcar_du_panel_data *pdata = - data ? &data->connector.lvds.panel : NULL; - return rcar_du_lvds_connector_init(rcdu, renc, pdata, np); + drm_encoder_helper_add(encoder, &encoder_helper_funcs); } + switch (encoder_type) { + case DRM_MODE_ENCODER_LVDS: + return rcar_du_lvds_connector_init(rcdu, renc, con_node); + case DRM_MODE_ENCODER_DAC: return rcar_du_vga_connector_init(rcdu, renc); + case DRM_MODE_ENCODER_TMDS: + return rcar_du_hdmi_connector_init(rcdu, renc); + default: return -EINVAL; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h index bd624135ef1f..719b6f2a031c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h @@ -14,21 +14,32 @@ #ifndef __RCAR_DU_ENCODER_H__ #define __RCAR_DU_ENCODER_H__ -#include <linux/platform_data/rcar-du.h> - #include <drm/drm_crtc.h> +#include <drm/drm_encoder_slave.h> struct rcar_du_device; +struct rcar_du_hdmienc; struct rcar_du_lvdsenc; +enum rcar_du_encoder_type { + RCAR_DU_ENCODER_UNUSED = 0, + RCAR_DU_ENCODER_NONE, + RCAR_DU_ENCODER_VGA, + RCAR_DU_ENCODER_LVDS, + RCAR_DU_ENCODER_HDMI, +}; + struct rcar_du_encoder { - struct drm_encoder encoder; + struct drm_encoder_slave slave; enum rcar_du_output output; + struct rcar_du_hdmienc *hdmi; struct rcar_du_lvdsenc *lvds; }; #define to_rcar_encoder(e) \ - container_of(e, struct rcar_du_encoder, encoder) + container_of(e, struct rcar_du_encoder, slave.base) + +#define rcar_encoder_to_drm_encoder(e) (&(e)->slave.base) struct rcar_du_connector { struct drm_connector connector; @@ -44,7 +55,7 @@ rcar_du_connector_best_encoder(struct drm_connector *connector); int rcar_du_encoder_init(struct rcar_du_device *rcdu, enum rcar_du_encoder_type type, enum rcar_du_output output, - const struct rcar_du_encoder_data *data, - struct device_node *np); + struct device_node *enc_node, + struct device_node *con_node); #endif /* __RCAR_DU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c new file mode 100644 index 000000000000..4d7d4dd46d26 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c @@ -0,0 +1,121 @@ +/* + * R-Car Display Unit HDMI Connector + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_encoder_slave.h> + +#include "rcar_du_drv.h" +#include "rcar_du_encoder.h" +#include "rcar_du_hdmicon.h" +#include "rcar_du_kms.h" + +#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs) + +static int rcar_du_hdmi_connector_get_modes(struct drm_connector *connector) +{ + struct rcar_du_connector *con = to_rcar_connector(connector); + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder); + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->get_modes == NULL) + return 0; + + return sfuncs->get_modes(encoder, connector); +} + +static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct rcar_du_connector *con = to_rcar_connector(connector); + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder); + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->mode_valid == NULL) + return MODE_OK; + + return sfuncs->mode_valid(encoder, mode); +} + +static const struct drm_connector_helper_funcs connector_helper_funcs = { + .get_modes = rcar_du_hdmi_connector_get_modes, + .mode_valid = rcar_du_hdmi_connector_mode_valid, + .best_encoder = rcar_du_connector_best_encoder, +}; + +static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static enum drm_connector_status +rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force) +{ + struct rcar_du_connector *con = to_rcar_connector(connector); + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder); + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->detect == NULL) + return connector_status_unknown; + + return sfuncs->detect(encoder, connector); +} + +static const struct drm_connector_funcs connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = rcar_du_hdmi_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = rcar_du_hdmi_connector_destroy, +}; + +int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc) +{ + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); + struct rcar_du_connector *rcon; + struct drm_connector *connector; + int ret; + + rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL); + if (rcon == NULL) + return -ENOMEM; + + connector = &rcon->connector; + connector->display_info.width_mm = 0; + connector->display_info.height_mm = 0; + + ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + if (ret < 0) + return ret; + + drm_connector_helper_add(connector, &connector_helper_funcs); + ret = drm_connector_register(connector); + if (ret < 0) + return ret; + + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_object_property_set_value(&connector->base, + rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); + + ret = drm_mode_connector_attach_encoder(connector, encoder); + if (ret < 0) + return ret; + + connector->encoder = encoder; + rcon->encoder = renc; + + return 0; +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h new file mode 100644 index 000000000000..87daa949227f --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h @@ -0,0 +1,31 @@ +/* + * R-Car Display Unit HDMI Connector + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_HDMICON_H__ +#define __RCAR_DU_HDMICON_H__ + +struct rcar_du_device; +struct rcar_du_encoder; + +#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI) +int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc); +#else +static inline int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc) +{ + return -ENOSYS; +} +#endif + +#endif /* __RCAR_DU_HDMICON_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c new file mode 100644 index 000000000000..359bc999a9c8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c @@ -0,0 +1,151 @@ +/* + * R-Car Display Unit HDMI Encoder + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/slab.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_encoder_slave.h> + +#include "rcar_du_drv.h" +#include "rcar_du_encoder.h" +#include "rcar_du_hdmienc.h" + +struct rcar_du_hdmienc { + struct rcar_du_encoder *renc; + struct device *dev; + int dpms; +}; + +#define to_rcar_hdmienc(e) (to_rcar_encoder(e)->hdmi) +#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs) + +static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode) +{ + struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (hdmienc->dpms == mode) + return; + + if (sfuncs->dpms) + sfuncs->dpms(encoder, mode); + + hdmienc->dpms = mode; +} + +static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->mode_fixup == NULL) + return true; + + return sfuncs->mode_fixup(encoder, mode, adjusted_mode); +} + +static void rcar_du_hdmienc_mode_prepare(struct drm_encoder *encoder) +{ + rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void rcar_du_hdmienc_mode_commit(struct drm_encoder *encoder) +{ + rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->mode_set) + sfuncs->mode_set(encoder, mode, adjusted_mode); + + rcar_du_crtc_route_output(encoder->crtc, hdmienc->renc->output); +} + +static const struct drm_encoder_helper_funcs encoder_helper_funcs = { + .dpms = rcar_du_hdmienc_dpms, + .mode_fixup = rcar_du_hdmienc_mode_fixup, + .prepare = rcar_du_hdmienc_mode_prepare, + .commit = rcar_du_hdmienc_mode_commit, + .mode_set = rcar_du_hdmienc_mode_set, +}; + +static void rcar_du_hdmienc_cleanup(struct drm_encoder *encoder) +{ + struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); + + rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF); + + drm_encoder_cleanup(encoder); + put_device(hdmienc->dev); +} + +static const struct drm_encoder_funcs encoder_funcs = { + .destroy = rcar_du_hdmienc_cleanup, +}; + +int rcar_du_hdmienc_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc, struct device_node *np) +{ + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); + struct drm_i2c_encoder_driver *driver; + struct i2c_client *i2c_slave; + struct rcar_du_hdmienc *hdmienc; + int ret; + + hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL); + if (hdmienc == NULL) + return -ENOMEM; + + /* Locate the slave I2C device and driver. */ + i2c_slave = of_find_i2c_device_by_node(np); + if (!i2c_slave || !i2c_get_clientdata(i2c_slave)) + return -EPROBE_DEFER; + + hdmienc->dev = &i2c_slave->dev; + + if (hdmienc->dev->driver == NULL) { + ret = -EPROBE_DEFER; + goto error; + } + + /* Initialize the slave encoder. */ + driver = to_drm_i2c_encoder_driver(to_i2c_driver(hdmienc->dev->driver)); + ret = driver->encoder_init(i2c_slave, rcdu->ddev, &renc->slave); + if (ret < 0) + goto error; + + ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, + DRM_MODE_ENCODER_TMDS); + if (ret < 0) + goto error; + + drm_encoder_helper_add(encoder, &encoder_helper_funcs); + + renc->hdmi = hdmienc; + hdmienc->renc = renc; + + return 0; + +error: + put_device(hdmienc->dev); + return ret; +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h new file mode 100644 index 000000000000..2ff0128ac8e1 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h @@ -0,0 +1,35 @@ +/* + * R-Car Display Unit HDMI Encoder + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_HDMIENC_H__ +#define __RCAR_DU_HDMIENC_H__ + +#include <linux/module.h> + +struct device_node; +struct rcar_du_device; +struct rcar_du_encoder; + +#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI) +int rcar_du_hdmienc_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc, struct device_node *np); +#else +static inline int rcar_du_hdmienc_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc, + struct device_node *np) +{ + return -ENOSYS; +} +#endif + +#endif /* __RCAR_DU_HDMIENC_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 6c24ad7d03ef..0c5ee616b5a3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -126,9 +126,9 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, else align = 16 * args->bpp / 8; - args->pitch = roundup(max(args->pitch, min_pitch), align); + args->pitch = roundup(min_pitch, align); - return drm_gem_cma_dumb_create(file, dev, args); + return drm_gem_cma_dumb_create_internal(file, dev, args); } static struct drm_framebuffer * @@ -190,49 +190,16 @@ static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { .output_poll_changed = rcar_du_output_poll_changed, }; -static int rcar_du_encoders_init_pdata(struct rcar_du_device *rcdu) -{ - unsigned int num_encoders = 0; - unsigned int i; - int ret; - - for (i = 0; i < rcdu->pdata->num_encoders; ++i) { - const struct rcar_du_encoder_data *pdata = - &rcdu->pdata->encoders[i]; - const struct rcar_du_output_routing *route = - &rcdu->info->routes[pdata->output]; - - if (pdata->type == RCAR_DU_ENCODER_UNUSED) - continue; - - if (pdata->output >= RCAR_DU_OUTPUT_MAX || - route->possible_crtcs == 0) { - dev_warn(rcdu->dev, - "encoder %u references unexisting output %u, skipping\n", - i, pdata->output); - continue; - } - - ret = rcar_du_encoder_init(rcdu, pdata->type, pdata->output, - pdata, NULL); - if (ret < 0) - return ret; - - num_encoders++; - } - - return num_encoders; -} - -static int rcar_du_encoders_init_dt_one(struct rcar_du_device *rcdu, - enum rcar_du_output output, - struct of_endpoint *ep) +static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, + enum rcar_du_output output, + struct of_endpoint *ep) { static const struct { const char *compatible; enum rcar_du_encoder_type type; } encoders[] = { { "adi,adv7123", RCAR_DU_ENCODER_VGA }, + { "adi,adv7511w", RCAR_DU_ENCODER_HDMI }, { "thine,thc63lvdm83d", RCAR_DU_ENCODER_LVDS }, }; @@ -323,14 +290,14 @@ static int rcar_du_encoders_init_dt_one(struct rcar_du_device *rcdu, connector = entity; } - ret = rcar_du_encoder_init(rcdu, enc_type, output, NULL, connector); + ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector); of_node_put(encoder); of_node_put(connector); return ret < 0 ? ret : 1; } -static int rcar_du_encoders_init_dt(struct rcar_du_device *rcdu) +static int rcar_du_encoders_init(struct rcar_du_device *rcdu) { struct device_node *np = rcdu->dev->of_node; struct device_node *prev = NULL; @@ -377,7 +344,7 @@ static int rcar_du_encoders_init_dt(struct rcar_du_device *rcdu) } /* Process the output pipeline. */ - ret = rcar_du_encoders_init_dt_one(rcdu, output, &ep); + ret = rcar_du_encoders_init_one(rcdu, output, &ep); if (ret < 0) { of_node_put(ep_node); return ret; @@ -442,11 +409,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) if (ret < 0) return ret; - if (rcdu->pdata) - ret = rcar_du_encoders_init_pdata(rcdu); - else - ret = rcar_du_encoders_init_dt(rcdu); - + ret = rcar_du_encoders_init(rcdu); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c index 115eed20db12..6d9811c052c4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c @@ -27,7 +27,11 @@ struct rcar_du_lvds_connector { struct rcar_du_connector connector; - struct rcar_du_panel_data panel; + struct { + unsigned int width_mm; /* Panel width in mm */ + unsigned int height_mm; /* Panel height in mm */ + struct videomode mode; + } panel; }; #define to_rcar_lvds_connector(c) \ @@ -78,31 +82,26 @@ static const struct drm_connector_funcs connector_funcs = { int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, struct rcar_du_encoder *renc, - const struct rcar_du_panel_data *panel, /* TODO const */ struct device_node *np) { + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); struct rcar_du_lvds_connector *lvdscon; struct drm_connector *connector; + struct display_timing timing; int ret; lvdscon = devm_kzalloc(rcdu->dev, sizeof(*lvdscon), GFP_KERNEL); if (lvdscon == NULL) return -ENOMEM; - if (panel) { - lvdscon->panel = *panel; - } else { - struct display_timing timing; - - ret = of_get_display_timing(np, "panel-timing", &timing); - if (ret < 0) - return ret; + ret = of_get_display_timing(np, "panel-timing", &timing); + if (ret < 0) + return ret; - videomode_from_timing(&timing, &lvdscon->panel.mode); + videomode_from_timing(&timing, &lvdscon->panel.mode); - of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm); - of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm); - } + of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm); + of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm); connector = &lvdscon->connector.connector; connector->display_info.width_mm = lvdscon->panel.width_mm; @@ -122,11 +121,11 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, drm_object_property_set_value(&connector->base, rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); - ret = drm_mode_connector_attach_encoder(connector, &renc->encoder); + ret = drm_mode_connector_attach_encoder(connector, encoder); if (ret < 0) return ret; - connector->encoder = &renc->encoder; + connector->encoder = encoder; lvdscon->connector.encoder = renc; return 0; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h index d11424d537f9..d4881ee0be7e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h @@ -16,11 +16,9 @@ struct rcar_du_device; struct rcar_du_encoder; -struct rcar_du_panel_data; int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, struct rcar_du_encoder *renc, - const struct rcar_du_panel_data *panel, struct device_node *np); #endif /* __RCAR_DU_LVDSCON_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h index 3303a55cec79..f65aabda0796 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h @@ -16,7 +16,6 @@ #include <linux/io.h> #include <linux/module.h> -#include <linux/platform_data/rcar-du.h> struct rcar_drm_crtc; struct rcar_du_lvdsenc; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c index 564a723ede03..752747a5e920 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c @@ -52,6 +52,7 @@ static const struct drm_connector_funcs connector_funcs = { int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, struct rcar_du_encoder *renc) { + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); struct rcar_du_connector *rcon; struct drm_connector *connector; int ret; @@ -78,11 +79,11 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, drm_object_property_set_value(&connector->base, rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); - ret = drm_mode_connector_attach_encoder(connector, &renc->encoder); + ret = drm_mode_connector_attach_encoder(connector, encoder); if (ret < 0) return ret; - connector->encoder = &renc->encoder; + connector->encoder = encoder; rcon->encoder = renc; return 0; |