Commit 73dc923e authored by Daniel Vetter's avatar Daniel Vetter

Merge tag 'du-next-20210105' of git://linuxtv.org/pinchartl/media into drm-next

- Add default modes for connectors in unknown state
- R-Car DU conversion to DRM-managed API
- R-Car DU miscellaneous fixes
- Miscellaneous bridge and bridge bindings fixes
- Assorted misc driver cleanups
- Constify drm_driver for PCI devices
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/X/P8IOrVXkTpLeCm@pendragon.ideasonboard.com
parents ca765c73 3fc5a284
......@@ -83,9 +83,9 @@ properties:
$ref: /schemas/types.yaml#/definitions/phandle
description:
phandle to the companion LVDS encoder. This property is mandatory
for the first LVDS encoder on D3 and E3 SoCs, and shall point to
the second encoder to be used as a companion in dual-link mode. It
shall not be set for any other LVDS encoder.
for the first LVDS encoder on R-Car D3 and E3, and RZ/G2E SoCs, and shall
point to the second encoder to be used as a companion in dual-link mode.
It shall not be set for any other LVDS encoder.
required:
- compatible
......
......@@ -30,11 +30,17 @@ properties:
This device has four video ports. Their connections are modeled using the
OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.
The device can operate in single-link mode or dual-link mode. In
single-link mode, all pixels are received on port@0, and port@1 shall not
contain any endpoint. In dual-link mode, even-numbered pixels are
received on port@0 and odd-numbered pixels on port@1, and both port@0 and
port@1 shall contain endpoints.
The device can operate in single or dual input and output modes.
When operating in single input mode, all pixels are received on port@0,
and port@1 shall not contain any endpoint. In dual input mode,
even-numbered pixels are received on port@0 and odd-numbered pixels on
port@1, and both port@0 and port@1 shall contain endpoints.
When operating in single output mode all pixels are output from the first
CMOS/TTL port and port@3 shall not contain any endpoint. In dual output
mode pixels are output from both CMOS/TTL ports and both port@2 and
port@3 shall contain endpoints.
properties:
'#address-cells':
......
......@@ -162,15 +162,10 @@ static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = {
.atomic_update = arc_pgu_plane_atomic_update,
};
static void arc_pgu_plane_destroy(struct drm_plane *plane)
{
drm_plane_cleanup(plane);
}
static const struct drm_plane_funcs arc_pgu_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = arc_pgu_plane_destroy,
.destroy = drm_plane_cleanup,
.reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
......@@ -213,7 +208,7 @@ int arc_pgu_setup_crtc(struct drm_device *drm)
ret = drm_crtc_init_with_planes(drm, &arcpgu->crtc, primary, NULL,
&arc_pgu_crtc_funcs, NULL);
if (ret) {
arc_pgu_plane_destroy(primary);
drm_plane_cleanup(primary);
return ret;
}
......
......@@ -145,7 +145,7 @@ static void arcpgu_debugfs_init(struct drm_minor *minor)
}
#endif
static struct drm_driver arcpgu_drm_driver = {
static const struct drm_driver arcpgu_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
.name = "arcpgu",
.desc = "ARC PGU Controller",
......
......@@ -1292,8 +1292,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
err_unregister_cec:
i2c_unregister_device(adv7511->i2c_cec);
if (adv7511->cec_clk)
clk_disable_unprepare(adv7511->cec_clk);
clk_disable_unprepare(adv7511->cec_clk);
err_i2c_unregister_packet:
i2c_unregister_device(adv7511->i2c_packet);
err_i2c_unregister_edid:
......@@ -1311,8 +1310,7 @@ static int adv7511_remove(struct i2c_client *i2c)
if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
adv7533_detach_dsi(adv7511);
i2c_unregister_device(adv7511->i2c_cec);
if (adv7511->cec_clk)
clk_disable_unprepare(adv7511->cec_clk);
clk_disable_unprepare(adv7511->cec_clk);
adv7511_uninit_regulators(adv7511);
......
......@@ -3440,8 +3440,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
err_iahb:
clk_disable_unprepare(hdmi->iahb_clk);
if (hdmi->cec_clk)
clk_disable_unprepare(hdmi->cec_clk);
clk_disable_unprepare(hdmi->cec_clk);
err_isfr:
clk_disable_unprepare(hdmi->isfr_clk);
err_res:
......@@ -3465,8 +3464,7 @@ void dw_hdmi_remove(struct dw_hdmi *hdmi)
clk_disable_unprepare(hdmi->iahb_clk);
clk_disable_unprepare(hdmi->isfr_clk);
if (hdmi->cec_clk)
clk_disable_unprepare(hdmi->cec_clk);
clk_disable_unprepare(hdmi->cec_clk);
if (hdmi->i2c)
i2c_del_adapter(&hdmi->i2c->adap);
......
......@@ -202,7 +202,7 @@ static int thc63_probe(struct platform_device *pdev)
thc63->dev = &pdev->dev;
platform_set_drvdata(pdev, thc63);
thc63->vcc = devm_regulator_get_optional(thc63->dev, "vcc");
thc63->vcc = devm_regulator_get(thc63->dev, "vcc");
if (IS_ERR(thc63->vcc)) {
if (PTR_ERR(thc63->vcc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
......
......@@ -589,11 +589,7 @@ static int drm_dev_init(struct drm_device *dev,
kref_init(&dev->ref);
dev->dev = get_device(parent);
#ifdef CONFIG_DRM_LEGACY
dev->driver = (struct drm_driver *)driver;
#else
dev->driver = driver;
#endif
INIT_LIST_HEAD(&dev->managed.resources);
spin_lock_init(&dev->managed.lock);
......
......@@ -29,6 +29,7 @@
#include <drm/drm_mode.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
/**
* DOC: overview
......@@ -46,9 +47,10 @@
* KMS frame buffers.
*
* To support dumb objects drivers must implement the &drm_driver.dumb_create
* operation. &drm_driver.dumb_destroy defaults to drm_gem_dumb_destroy() if
* not set and &drm_driver.dumb_map_offset defaults to
* drm_gem_dumb_map_offset(). See the callbacks for further details.
* and &drm_driver.dumb_map_offset operations (the latter defaults to
* drm_gem_dumb_map_offset() if not set). Drivers that don't use GEM handles
* additionally need to implement the &drm_driver.dumb_destroy operation. See
* the callbacks for further details.
*
* Note that dumb objects may not be used for gpu acceleration, as has been
* attempted on some ARM embedded platforms. Such drivers really must have
......
......@@ -335,22 +335,12 @@ int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
}
EXPORT_SYMBOL_GPL(drm_gem_dumb_map_offset);
/**
* drm_gem_dumb_destroy - dumb fb callback helper for gem based drivers
* @file: drm file-private structure to remove the dumb handle from
* @dev: corresponding drm_device
* @handle: the dumb handle to remove
*
* This implements the &drm_driver.dumb_destroy kms driver callback for drivers
* which use gem to manage their backing storage.
*/
int drm_gem_dumb_destroy(struct drm_file *file,
struct drm_device *dev,
uint32_t handle)
u32 handle)
{
return drm_gem_handle_delete(file, handle);
}
EXPORT_SYMBOL(drm_gem_dumb_destroy);
/**
* drm_gem_handle_create_tail - internal functions to create a handle
......
......@@ -191,6 +191,9 @@ void drm_gem_unpin(struct drm_gem_object *obj);
int drm_gem_vmap(struct drm_gem_object *obj, struct dma_buf_map *map);
void drm_gem_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map);
int drm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
u32 handle);
/* drm_debugfs.c drm_debugfs_crc.c */
#if defined(CONFIG_DEBUG_FS)
int drm_debugfs_init(struct drm_minor *minor, int minor_id,
......
......@@ -24,6 +24,8 @@
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/slab.h>
......@@ -36,6 +38,9 @@
#include "drm_legacy.h"
#ifdef CONFIG_DRM_LEGACY
/* List of devices hanging off drivers with stealth attach. */
static LIST_HEAD(legacy_dev_list);
static DEFINE_MUTEX(legacy_dev_list_lock);
/**
* drm_pci_alloc - Allocate a PCI consistent memory block, for DMA.
......@@ -196,7 +201,7 @@ static void drm_pci_agp_init(struct drm_device *dev)
static int drm_get_pci_dev(struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver)
const struct drm_driver *driver)
{
struct drm_device *dev;
int ret;
......@@ -225,10 +230,11 @@ static int drm_get_pci_dev(struct pci_dev *pdev,
if (ret)
goto err_agp;
/* No locking needed since shadow-attach is single-threaded since it may
* only be called from the per-driver module init hook. */
if (drm_core_check_feature(dev, DRIVER_LEGACY))
list_add_tail(&dev->legacy_dev_list, &driver->legacy_dev_list);
if (drm_core_check_feature(dev, DRIVER_LEGACY)) {
mutex_lock(&legacy_dev_list_lock);
list_add_tail(&dev->legacy_dev_list, &legacy_dev_list);
mutex_unlock(&legacy_dev_list_lock);
}
return 0;
......@@ -249,7 +255,8 @@ static int drm_get_pci_dev(struct pci_dev *pdev,
*
* Return: 0 on success or a negative error code on failure.
*/
int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
int drm_legacy_pci_init(const struct drm_driver *driver,
struct pci_driver *pdriver)
{
struct pci_dev *pdev = NULL;
const struct pci_device_id *pid;
......@@ -261,7 +268,6 @@ int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
return -EINVAL;
/* If not using KMS, fall back to stealth mode manual scanning. */
INIT_LIST_HEAD(&driver->legacy_dev_list);
for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
pid = &pdriver->id_table[i];
......@@ -295,7 +301,8 @@ EXPORT_SYMBOL(drm_legacy_pci_init);
* Unregister a DRM driver shadow-attached through drm_legacy_pci_init(). This
* is deprecated and only used by dri1 drivers.
*/
void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
void drm_legacy_pci_exit(const struct drm_driver *driver,
struct pci_driver *pdriver)
{
struct drm_device *dev, *tmp;
......@@ -304,11 +311,15 @@ void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
if (!(driver->driver_features & DRIVER_LEGACY)) {
WARN_ON(1);
} else {
list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
mutex_lock(&legacy_dev_list_lock);
list_for_each_entry_safe(dev, tmp, &legacy_dev_list,
legacy_dev_list) {
list_del(&dev->legacy_dev_list);
drm_put_dev(dev);
if (dev->driver == driver) {
list_del(&dev->legacy_dev_list);
drm_put_dev(dev);
}
}
mutex_unlock(&legacy_dev_list_lock);
}
DRM_INFO("Module unloaded\n");
}
......
......@@ -515,7 +515,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
if (count == 0 && connector->status == connector_status_connected)
count = drm_add_override_edid_modes(connector);
if (count == 0 && connector->status == connector_status_connected)
if (count == 0 && (connector->status == connector_status_connected ||
connector->status == connector_status_unknown))
count = drm_add_modes_noedid(connector, 1024, 768);
count += drm_helper_probe_add_cmdline_mode(connector);
if (count == 0)
......
......@@ -400,7 +400,7 @@ static void kmb_irq_reset(struct drm_device *drm)
DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver kmb_driver = {
static const struct drm_driver kmb_driver = {
.driver_features = DRIVER_GEM |
DRIVER_MODESET | DRIVER_ATOMIC,
.irq_handler = kmb_isr,
......
......@@ -122,7 +122,7 @@ int rcar_cmm_enable(struct platform_device *pdev)
{
int ret;
ret = pm_runtime_get_sync(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0)
return ret;
......
......@@ -730,13 +730,10 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
*/
if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index) &&
rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) {
struct rcar_du_encoder *encoder =
rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index];
struct drm_bridge *bridge = rcdu->lvds[rcrtc->index];
const struct drm_display_mode *mode =
&crtc->state->adjusted_mode;
struct drm_bridge *bridge;
bridge = drm_bridge_chain_get_first_bridge(&encoder->base);
rcar_lvds_clk_enable(bridge, mode->clock * 1000);
}
......@@ -764,15 +761,12 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index) &&
rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) {
struct rcar_du_encoder *encoder =
rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index];
struct drm_bridge *bridge;
struct drm_bridge *bridge = rcdu->lvds[rcrtc->index];
/*
* Disable the LVDS clock output, see
* rcar_du_crtc_atomic_enable().
*/
bridge = drm_bridge_chain_get_first_bridge(&encoder->base);
rcar_lvds_clk_disable(bridge);
}
......@@ -1256,7 +1250,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
else
primary = &rgrp->planes[swindex % 2].plane;
ret = drm_crtc_init_with_planes(rcdu->ddev, crtc, primary, NULL,
ret = drm_crtc_init_with_planes(&rcdu->ddev, crtc, primary, NULL,
rcdu->info->gen <= 2 ?
&crtc_funcs_gen2 : &crtc_funcs_gen3,
NULL);
......
......@@ -18,10 +18,11 @@
#include <linux/wait.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include "rcar_du_drv.h"
......@@ -527,14 +528,14 @@ static int rcar_du_pm_suspend(struct device *dev)
{
struct rcar_du_device *rcdu = dev_get_drvdata(dev);
return drm_mode_config_helper_suspend(rcdu->ddev);
return drm_mode_config_helper_suspend(&rcdu->ddev);
}
static int rcar_du_pm_resume(struct device *dev)
{
struct rcar_du_device *rcdu = dev_get_drvdata(dev);
return drm_mode_config_helper_resume(rcdu->ddev);
return drm_mode_config_helper_resume(&rcdu->ddev);
}
#endif
......@@ -549,7 +550,7 @@ static const struct dev_pm_ops rcar_du_pm_ops = {
static int rcar_du_remove(struct platform_device *pdev)
{
struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
struct drm_device *ddev = rcdu->ddev;
struct drm_device *ddev = &rcdu->ddev;
drm_dev_unregister(ddev);
......@@ -563,14 +564,14 @@ static int rcar_du_remove(struct platform_device *pdev)
static int rcar_du_probe(struct platform_device *pdev)
{
struct rcar_du_device *rcdu;
struct drm_device *ddev;
struct resource *mem;
int ret;
/* Allocate and initialize the R-Car device structure. */
rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
if (rcdu == NULL)
return -ENOMEM;
rcdu = devm_drm_dev_alloc(&pdev->dev, &rcar_du_driver,
struct rcar_du_device, ddev);
if (IS_ERR(rcdu))
return PTR_ERR(rcdu);
rcdu->dev = &pdev->dev;
rcdu->info = of_device_get_match_data(rcdu->dev);
......@@ -584,13 +585,6 @@ static int rcar_du_probe(struct platform_device *pdev)
return PTR_ERR(rcdu->mmio);
/* DRM/KMS objects */
ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev);
if (IS_ERR(ddev))
return PTR_ERR(ddev);
rcdu->ddev = ddev;
ddev->dev_private = rcdu;
ret = rcar_du_modeset_init(rcdu);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
......@@ -599,25 +593,24 @@ static int rcar_du_probe(struct platform_device *pdev)
goto error;
}
ddev->irq_enabled = 1;
rcdu->ddev.irq_enabled = 1;
/*
* Register the DRM device with the core and the connectors with
* sysfs.
*/
ret = drm_dev_register(ddev, 0);
ret = drm_dev_register(&rcdu->ddev, 0);
if (ret)
goto error;
DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
drm_fbdev_generic_setup(ddev, 32);
drm_fbdev_generic_setup(&rcdu->ddev, 32);
return 0;
error:
rcar_du_remove(pdev);
drm_kms_helper_poll_fini(&rcdu->ddev);
return ret;
}
......
......@@ -13,6 +13,8 @@
#include <linux/kernel.h>
#include <linux/wait.h>
#include <drm/drm_device.h>
#include "rcar_cmm.h"
#include "rcar_du_crtc.h"
#include "rcar_du_group.h"
......@@ -20,10 +22,9 @@
struct clk;
struct device;
struct drm_device;
struct drm_bridge;
struct drm_property;
struct rcar_du_device;
struct rcar_du_encoder;
#define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK BIT(0) /* Per-CRTC IRQ and clock */
#define RCAR_DU_FEATURE_VSP1_SOURCE BIT(1) /* Has inputs from VSP1 */
......@@ -71,6 +72,7 @@ struct rcar_du_device_info {
#define RCAR_DU_MAX_CRTCS 4
#define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2)
#define RCAR_DU_MAX_VSPS 4
#define RCAR_DU_MAX_LVDS 2
struct rcar_du_device {
struct device *dev;
......@@ -78,16 +80,15 @@ struct rcar_du_device {
void __iomem *mmio;
struct drm_device *ddev;
struct drm_device ddev;
struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS];
unsigned int num_crtcs;
struct rcar_du_encoder *encoders[RCAR_DU_OUTPUT_MAX];
struct rcar_du_group groups[RCAR_DU_MAX_GROUPS];
struct platform_device *cmms[RCAR_DU_MAX_CRTCS];
struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS];
struct drm_bridge *lvds[RCAR_DU_MAX_LVDS];
struct {
struct drm_property *colorkey;
......@@ -98,6 +99,11 @@ struct rcar_du_device {
unsigned int vspd1_sink;
};
static inline struct rcar_du_device *to_rcar_du_device(struct drm_device *dev)
{
return container_of(dev, struct rcar_du_device, ddev);
}
static inline bool rcar_du_has(struct rcar_du_device *rcdu,
unsigned int feature)
{
......
......@@ -8,12 +8,13 @@
*/
#include <linux/export.h>
#include <linux/slab.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_panel.h>
#include <drm/drm_simple_kms_helper.h>
#include "rcar_du_drv.h"
#include "rcar_du_encoder.h"
......@@ -44,26 +45,25 @@ static unsigned int rcar_du_encoder_count_ports(struct device_node *node)
return num_ports;
}
static const struct drm_encoder_funcs rcar_du_encoder_funcs = {
};
static void rcar_du_encoder_release(struct drm_device *dev, void *res)
{
struct rcar_du_encoder *renc = res;
drm_encoder_cleanup(&renc->base);
kfree(renc);
}
int rcar_du_encoder_init(struct rcar_du_device *rcdu,
enum rcar_du_output output,
struct device_node *enc_node)
{
struct rcar_du_encoder *renc;
struct drm_encoder *encoder;
struct drm_bridge *bridge;
int ret;
renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
if (renc == NULL)
return -ENOMEM;
rcdu->encoders[output] = renc;
renc->output = output;
encoder = rcar_encoder_to_drm_encoder(renc);
dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
enc_node, output);
/*
* Locate the DRM bridge from the DT node. For the DPAD outputs, if the
* DT node has a single port, assume that it describes a panel and
......@@ -74,57 +74,57 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
rcar_du_encoder_count_ports(enc_node) == 1) {
struct drm_panel *panel = of_drm_find_panel(enc_node);
if (IS_ERR(panel)) {
ret = PTR_ERR(panel);
goto done;
}
if (IS_ERR(panel))
return PTR_ERR(panel);
bridge = devm_drm_panel_bridge_add_typed(rcdu->dev, panel,
DRM_MODE_CONNECTOR_DPI);
if (IS_ERR(bridge)) {
ret = PTR_ERR(bridge);
goto done;
}
if (IS_ERR(bridge))
return PTR_ERR(bridge);
} else {
bridge = of_drm_find_bridge(enc_node);
if (!bridge) {
ret = -EPROBE_DEFER;
goto done;
}
if (!bridge)
return -EPROBE_DEFER;
if (output == RCAR_DU_OUTPUT_LVDS0 ||
output == RCAR_DU_OUTPUT_LVDS1)
rcdu->lvds[output - RCAR_DU_OUTPUT_LVDS0] = bridge;
}
/*
* On Gen3 skip the LVDS1 output if the LVDS1 encoder is used as a
* companion for LVDS0 in dual-link mode.
* Create and initialize the encoder. On Gen3 skip the LVDS1 output if
* the LVDS1 encoder is used as a companion for LVDS0 in dual-link
* mode.
*/
if (rcdu->info->gen >= 3 && output == RCAR_DU_OUTPUT_LVDS1) {
if (rcar_lvds_dual_link(bridge)) {
ret = -ENOLINK;
goto done;
}
if (rcar_lvds_dual_link(bridge))
return -ENOLINK;
}
ret = drm_simple_encoder_init(rcdu->ddev, encoder,
DRM_MODE_ENCODER_NONE);
if (ret < 0)
goto done;
renc = kzalloc(sizeof(*renc), GFP_KERNEL);
if (renc == NULL)
return -ENOMEM;
/*
* Attach the bridge to the encoder. The bridge will create the
* connector.
*/
ret = drm_bridge_attach(encoder, bridge, NULL, 0);
if (ret) {
drm_encoder_cleanup(encoder);
return ret;
}
renc->output = output;
dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
enc_node, output);
done:
ret = drm_encoder_init(&rcdu->ddev, &renc->base, &rcar_du_encoder_funcs,
DRM_MODE_ENCODER_NONE, NULL);
if (ret < 0) {
if (encoder->name)
encoder->funcs->destroy(encoder);
devm_kfree(rcdu->dev, renc);
kfree(renc);
return ret;
}
return ret;
ret = drmm_add_action_or_reset(&rcdu->ddev, rcar_du_encoder_release,
renc);
if (ret)
return ret;
/*
* Attach the bridge to the encoder. The bridge will create the
* connector.
*/
return drm_bridge_attach(&renc->base, bridge, NULL, 0);
}
......@@ -22,8 +22,6 @@ struct rcar_du_encoder {
#define to_rcar_encoder(e) \
container_of(e, struct rcar_du_encoder, base)
#define rcar_encoder_to_drm_encoder(e) (&(e)->base)
int rcar_du_encoder_init(struct rcar_du_device *rcdu,
enum rcar_du_output output,
struct device_node *enc_node);
......
......@@ -14,6 +14,7 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
......@@ -327,7 +328,7 @@ const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc)
int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
struct rcar_du_device *rcdu = dev->dev_private;
struct rcar_du_device *rcdu = to_rcar_du_device(dev);
unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
unsigned int align;
......@@ -349,7 +350,7 @@ static struct drm_framebuffer *
rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct rcar_du_device *rcdu = dev->dev_private;
struct rcar_du_device *rcdu = to_rcar_du_device(dev);
const struct rcar_du_format_info *format;
unsigned int chroma_pitch;
unsigned int max_pitch;
......@@ -421,7 +422,7 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
static int rcar_du_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
struct rcar_du_device *rcdu = dev->dev_private;
struct rcar_du_device *rcdu = to_rcar_du_device(dev);
int ret;
ret = drm_atomic_helper_check(dev, state);
......@@ -437,7 +438,7 @@ static int rcar_du_atomic_check(struct drm_device *dev,
static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
{
struct drm_device *dev = old_state->dev;
struct rcar_du_device *rcdu = dev->dev_private;
struct rcar_du_device *rcdu = to_rcar_du_device(dev);
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
unsigned int i;
......@@ -583,7 +584,7 @@ static int rcar_du_properties_init(struct rcar_du_device *rcdu)
* or enable source color keying (1).
*/
rcdu->props.colorkey =
drm_property_create_range(rcdu->ddev, 0, "colorkey",
drm_property_create_range(&rcdu->ddev, 0, "colorkey",
0, 0x01ffffff);
if (rcdu->props.colorkey == NULL)
return -ENOMEM;
......@@ -700,10 +701,10 @@ static int rcar_du_cmm_init(struct rcar_du_device *rcdu)
int ret;
cmm = of_parse_phandle(np, "renesas,cmms", i);
if (IS_ERR(cmm)) {
if (!cmm) {
dev_err(rcdu->dev,
"Failed to parse 'renesas,cmms' property\n");
return PTR_ERR(cmm);
return -EINVAL;
}
if (!of_device_is_available(cmm)) {
......@@ -713,10 +714,10 @@ static int rcar_du_cmm_init(struct rcar_du_device *rcdu)
}
pdev = of_find_device_by_node(cmm);
if (IS_ERR(pdev)) {
if (!pdev) {
dev_err(rcdu->dev, "No device found for CMM%u\n", i);
of_node_put(cmm);
return PTR_ERR(pdev);
return -EINVAL;
}
of_node_put(cmm);
......@@ -726,8 +727,12 @@ static int rcar_du_cmm_init(struct rcar_du_device *rcdu)
* disabled: return 0 and let the DU continue probing.
*/
ret = rcar_cmm_init(pdev);
if (ret)
if (ret) {
platform_device_put(pdev);
return ret == -ENODEV ? 0 : ret;
}
rcdu->cmms[i] = pdev;
/*
* Enforce suspend/resume ordering by making the CMM a provider
......@@ -739,20 +744,27 @@ static int rcar_du_cmm_init(struct rcar_du_device *rcdu)
"Failed to create device link to CMM%u\n", i);
return -EINVAL;
}
rcdu->cmms[i] = pdev;
}
return 0;
}
static void rcar_du_modeset_cleanup(struct drm_device *dev, void *res)
{
struct rcar_du_device *rcdu = to_rcar_du_device(dev);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(rcdu->cmms); ++i)
platform_device_put(rcdu->cmms[i]);
}
int rcar_du_modeset_init(struct rcar_du_device *rcdu)
{
static const unsigned int mmio_offsets[] = {
DU0_REG_OFFSET, DU2_REG_OFFSET
};
struct drm_device *dev = rcdu->ddev;
struct drm_device *dev = &rcdu->ddev;
struct drm_encoder *encoder;
unsigned int dpad0_sources;
unsigned int num_encoders;
......@@ -766,6 +778,10 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
if (ret)
return ret;
ret = drmm_add_action(&rcdu->ddev, rcar_du_modeset_cleanup, NULL);
if (ret)
return ret;
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
dev->mode_config.normalize_zpos = true;
......
......@@ -128,7 +128,7 @@ static int rcar_du_plane_hwalloc(struct rcar_du_plane *plane,
int rcar_du_atomic_check_planes(struct drm_device *dev,
struct drm_atomic_state *state)
{
struct rcar_du_device *rcdu = dev->dev_private;
struct rcar_du_device *rcdu = to_rcar_du_device(dev);
unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, };
unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, };
bool needs_realloc = false;
......@@ -773,9 +773,9 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
plane->group = rgrp;
ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
&rcar_du_plane_funcs, formats,
ARRAY_SIZE(formats),
ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane,
crtcs, &rcar_du_plane_funcs,
formats, ARRAY_SIZE(formats),
NULL, type, NULL);
if (ret < 0)
return ret;
......
......@@ -21,6 +21,7 @@
#include <linux/dma-mapping.h>
#include <linux/of_platform.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/vsp1.h>
......@@ -344,6 +345,15 @@ static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
static void rcar_du_vsp_cleanup(struct drm_device *dev, void *res)
{
struct rcar_du_vsp *vsp = res;
unsigned int i;
for (i = 0; i < vsp->num_planes; ++i) {
struct rcar_du_vsp_plane *plane = &vsp->planes[i];
drm_plane_cleanup(&plane->plane);
}
kfree(vsp->planes);
put_device(vsp->vsp);
}
......@@ -354,6 +364,7 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
struct rcar_du_device *rcdu = vsp->dev;
struct platform_device *pdev;
unsigned int num_crtcs = hweight32(crtcs);
unsigned int num_planes;
unsigned int i;
int ret;
......@@ -364,7 +375,7 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
vsp->vsp = &pdev->dev;
ret = drmm_add_action(rcdu->ddev, rcar_du_vsp_cleanup, vsp);
ret = drmm_add_action_or_reset(&rcdu->ddev, rcar_du_vsp_cleanup, vsp);
if (ret < 0)
return ret;
......@@ -376,14 +387,13 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
* The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to
* 4 RPFs.
*/
vsp->num_planes = rcdu->info->gen >= 3 ? 5 : 4;
num_planes = rcdu->info->gen >= 3 ? 5 : 4;
vsp->planes = devm_kcalloc(rcdu->dev, vsp->num_planes,
sizeof(*vsp->planes), GFP_KERNEL);
vsp->planes = kcalloc(num_planes, sizeof(*vsp->planes), GFP_KERNEL);
if (!vsp->planes)
return -ENOMEM;
for (i = 0; i < vsp->num_planes; ++i) {
for (i = 0; i < num_planes; ++i) {
enum drm_plane_type type = i < num_crtcs
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY;
......@@ -392,8 +402,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
plane->vsp = vsp;
plane->index = i;
ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
&rcar_du_vsp_plane_funcs,
ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane,
crtcs, &rcar_du_vsp_plane_funcs,
rcar_du_vsp_formats,
ARRAY_SIZE(rcar_du_vsp_formats),
NULL, type, NULL);
......@@ -409,8 +419,10 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
} else {
drm_plane_create_alpha_property(&plane->plane);
drm_plane_create_zpos_property(&plane->plane, 1, 1,
vsp->num_planes - 1);
num_planes - 1);
}
vsp->num_planes++;
}
return 0;
......
......@@ -204,7 +204,7 @@ int rcar_du_writeback_init(struct rcar_du_device *rcdu,
drm_connector_helper_add(&wb_conn->base,
&rcar_du_wb_conn_helper_funcs);
return drm_writeback_connector_init(rcdu->ddev, wb_conn,
return drm_writeback_connector_init(&rcdu->ddev, wb_conn,
&rcar_du_wb_conn_funcs,
&rcar_du_wb_enc_helper_funcs,
writeback_formats,
......
......@@ -330,13 +330,6 @@ static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
.atomic_disable = sti_cursor_atomic_disable,
};
static void sti_cursor_destroy(struct drm_plane *drm_plane)
{
DRM_DEBUG_DRIVER("\n");
drm_plane_cleanup(drm_plane);
}
static int sti_cursor_late_register(struct drm_plane *drm_plane)
{
struct sti_plane *plane = to_sti_plane(drm_plane);
......@@ -350,7 +343,7 @@ static int sti_cursor_late_register(struct drm_plane *drm_plane)
static const struct drm_plane_funcs sti_cursor_plane_helpers_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = sti_cursor_destroy,
.destroy = drm_plane_cleanup,
.reset = sti_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
......
......@@ -884,13 +884,6 @@ static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
.atomic_disable = sti_gdp_atomic_disable,
};
static void sti_gdp_destroy(struct drm_plane *drm_plane)
{
DRM_DEBUG_DRIVER("\n");
drm_plane_cleanup(drm_plane);
}
static int sti_gdp_late_register(struct drm_plane *drm_plane)
{
struct sti_plane *plane = to_sti_plane(drm_plane);
......@@ -902,7 +895,7 @@ static int sti_gdp_late_register(struct drm_plane *drm_plane)
static const struct drm_plane_funcs sti_gdp_plane_helpers_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = sti_gdp_destroy,
.destroy = drm_plane_cleanup,
.reset = sti_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
......
......@@ -1262,13 +1262,6 @@ static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = {
.atomic_disable = sti_hqvdp_atomic_disable,
};
static void sti_hqvdp_destroy(struct drm_plane *drm_plane)
{
DRM_DEBUG_DRIVER("\n");
drm_plane_cleanup(drm_plane);
}
static int sti_hqvdp_late_register(struct drm_plane *drm_plane)
{
struct sti_plane *plane = to_sti_plane(drm_plane);
......@@ -1282,7 +1275,7 @@ static int sti_hqvdp_late_register(struct drm_plane *drm_plane)
static const struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = sti_hqvdp_destroy,
.destroy = drm_plane_cleanup,
.reset = sti_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
......
......@@ -56,7 +56,7 @@ static const struct file_operations tdfx_driver_fops = {
.llseek = noop_llseek,
};
static struct drm_driver driver = {
static const struct drm_driver driver = {
.driver_features = DRIVER_LEGACY,
.fops = &tdfx_driver_fops,
.name = DRIVER_NAME,
......
......@@ -1268,11 +1268,6 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
.atomic_async_update = vc4_plane_atomic_async_update,
};
static void vc4_plane_destroy(struct drm_plane *plane)
{
drm_plane_cleanup(plane);
}
static bool vc4_format_mod_supported(struct drm_plane *plane,
uint32_t format,
uint64_t modifier)
......@@ -1323,7 +1318,7 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
static const struct drm_plane_funcs vc4_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = vc4_plane_destroy,
.destroy = drm_plane_cleanup,
.set_property = NULL,
.reset = vc4_plane_reset,
.atomic_duplicate_state = vc4_plane_duplicate_state,
......
......@@ -438,15 +438,10 @@ static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
.atomic_disable = zx_plane_atomic_disable,
};
static void zx_plane_destroy(struct drm_plane *plane)
{
drm_plane_cleanup(plane);
}
static const struct drm_plane_funcs zx_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = zx_plane_destroy,
.destroy = drm_plane_cleanup,
.reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
......
......@@ -51,13 +51,6 @@ enum switch_power_state {
* may contain multiple heads.
*/
struct drm_device {
/**
* @legacy_dev_list:
*
* List of devices per driver for stealth attach cleanup
*/
struct list_head legacy_dev_list;
/** @if_version: Highest interface version set */
int if_version;
......@@ -83,11 +76,7 @@ struct drm_device {
} managed;
/** @driver: DRM driver managing the device */
#ifdef CONFIG_DRM_LEGACY
struct drm_driver *driver;
#else
const struct drm_driver *driver;
#endif
/**
* @dev_private:
......@@ -336,6 +325,9 @@ struct drm_device {
/* Everything below here is for legacy driver, never use! */
/* private: */
#if IS_ENABLED(CONFIG_DRM_LEGACY)
/* List of devices per driver for stealth attach cleanup */
struct list_head legacy_dev_list;
/* Context handle management - linked list of context handles */
struct list_head ctxlist;
......
......@@ -499,8 +499,6 @@ struct drm_driver {
/* Everything below here is for legacy driver, never use! */
/* private: */
/* List of devices hanging off this driver with stealth attach. */
struct list_head legacy_dev_list;
int (*firstopen) (struct drm_device *);
void (*preclose) (struct drm_device *, struct drm_file *file_priv);
int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
......
......@@ -416,8 +416,5 @@ int drm_gem_fence_array_add_implicit(struct xarray *fence_array,
bool write);
int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
u32 handle, u64 *offset);
int drm_gem_dumb_destroy(struct drm_file *file,
struct drm_device *dev,
uint32_t handle);
#endif /* __DRM_GEM_H__ */
......@@ -198,8 +198,10 @@ struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size,
size_t align);
void drm_pci_free(struct drm_device *dev, struct drm_dma_handle *dmah);
int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver);
void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver);
int drm_legacy_pci_init(const struct drm_driver *driver,
struct pci_driver *pdriver);
void drm_legacy_pci_exit(const struct drm_driver *driver,
struct pci_driver *pdriver);
#else
......@@ -214,13 +216,13 @@ static inline void drm_pci_free(struct drm_device *dev,
{
}
static inline int drm_legacy_pci_init(struct drm_driver *driver,
static inline int drm_legacy_pci_init(const struct drm_driver *driver,
struct pci_driver *pdriver)
{
return -EINVAL;
}
static inline void drm_legacy_pci_exit(struct drm_driver *driver,
static inline void drm_legacy_pci_exit(const struct drm_driver *driver,
struct pci_driver *pdriver)
{
}
......
......@@ -866,13 +866,19 @@ struct drm_connector_helper_funcs {
* The usual way to implement this is to cache the EDID retrieved in the
* probe callback somewhere in the driver-private connector structure.
* In this function drivers then parse the modes in the EDID and add
* them by calling drm_add_edid_modes(). But connectors that driver a
* them by calling drm_add_edid_modes(). But connectors that drive a
* fixed panel can also manually add specific modes using
* drm_mode_probed_add(). Drivers which manually add modes should also
* make sure that the &drm_connector.display_info,
* &drm_connector.width_mm and &drm_connector.height_mm fields are
* filled in.
*
* Note that the caller function will automatically add standard VESA
* DMT modes up to 1024x768 if the .get_modes() helper operation returns
* no mode and if the connector status is connector_status_connected or
* connector_status_unknown. There is no need to call
* drm_add_modes_noedid() manually in that case.
*
* Virtual drivers that just want some standard VESA mode with a given
* resolution can call drm_add_modes_noedid(), and mark the preferred
* one using drm_set_preferred_mode().
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment