mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
drm/tegra: Changes for v5.10-rc1
This is a handful of patches that add bridge support for Tegra devices and fix a couple of minor issues. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEiOrDCAFJzPfAjcif3SOs138+s6EFAl9ol3oTHHRyZWRpbmdA bnZpZGlhLmNvbQAKCRDdI6zXfz6zoZ9GEACj5op3SIxMvCwQfiAJuXV5JKlAlxa/ cf437ZdWjvgId/afbqh6LX3srOEHdEfpesAthxr/g+KEsy3/Woaq/hNxcut2IAe8 kI1OW2b/bLI9JHC5U61NCcicRpRY/qte/wDON0u6DQ7CS10lhCslTZH3S/iABVM8 rH6nITAf2dnHL0giMM/7ednEJGUB139mpBK/trjzpqaFE+ATUib+fDzVUNxGw6Ju hHo4KUFLkVhqZPeOFdJDEdDdzKax0vTCkHki+eT+JZ1iA2rqRO4P3cTJHVYdxOhH bil6s9RrYaEsmxvuBWZhf0Ku0BlwDN+LZwigvUCWZdJRIrspNrNP36VJWNzKGVIo Niziv71UW8H0Utzoytq1m7MlVYUHn+PNL/58EhRcsbZX2nGqHbS6QVlP1o5tH/7g gD6MaUVt9K55Wh5s6XGoDBT/5xTXiDj64O1zloFd0onAx7/I68zgkwWENNfRKf5x I2c/+hSg273dytat7d4jqWdjWYfvLesb0KgajgBarOHyB4UyZ79V1pfyK3mvxTBS 5mAIoIt/PlLta+kl5zjkSSrYAMfohqVZAhMLqeqqSVoRHw8swwgQMVfn8ICEfrzC pFbyISbfmTYijTWESBXPyz5vzHcvKwuw8U+DuC2dTO2oa7jJVTPKiTpLMjwcQBmo 5IGjsACQROHOeA== =Ojrd -----END PGP SIGNATURE----- Merge tag 'drm/tegra/for-5.10-rc1' of ssh://git.freedesktop.org/git/tegra/linux into drm-next drm/tegra: Changes for v5.10-rc1 This is a handful of patches that add bridge support for Tegra devices and fix a couple of minor issues. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thierry Reding <thierry.reding@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20200921121245.3953659-1-thierry.reding@gmail.com
This commit is contained in:
commit
3e6f73b876
@ -12,6 +12,7 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
@ -116,6 +117,7 @@ struct tegra_output {
|
||||
struct device_node *of_node;
|
||||
struct device *dev;
|
||||
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
struct i2c_adapter *ddc;
|
||||
const struct edid *edid;
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
||||
@ -99,27 +100,38 @@ int tegra_output_probe(struct tegra_output *output)
|
||||
if (!output->of_node)
|
||||
output->of_node = output->dev->of_node;
|
||||
|
||||
err = drm_of_find_panel_or_bridge(output->of_node, -1, -1,
|
||||
&output->panel, &output->bridge);
|
||||
if (err && err != -ENODEV)
|
||||
return err;
|
||||
|
||||
panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
|
||||
if (panel) {
|
||||
/*
|
||||
* Don't mix nvidia,panel phandle with the graph in a
|
||||
* device-tree.
|
||||
*/
|
||||
WARN_ON(output->panel || output->bridge);
|
||||
|
||||
output->panel = of_drm_find_panel(panel);
|
||||
of_node_put(panel);
|
||||
|
||||
if (IS_ERR(output->panel))
|
||||
return PTR_ERR(output->panel);
|
||||
|
||||
of_node_put(panel);
|
||||
}
|
||||
|
||||
output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
|
||||
|
||||
ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
|
||||
if (ddc) {
|
||||
output->ddc = of_find_i2c_adapter_by_node(ddc);
|
||||
output->ddc = of_get_i2c_adapter_by_node(ddc);
|
||||
of_node_put(ddc);
|
||||
|
||||
if (!output->ddc) {
|
||||
err = -EPROBE_DEFER;
|
||||
of_node_put(ddc);
|
||||
return err;
|
||||
}
|
||||
|
||||
of_node_put(ddc);
|
||||
}
|
||||
|
||||
output->hpd_gpio = devm_gpiod_get_from_of_node(output->dev,
|
||||
@ -173,7 +185,7 @@ void tegra_output_remove(struct tegra_output *output)
|
||||
free_irq(output->hpd_irq, output);
|
||||
|
||||
if (output->ddc)
|
||||
put_device(&output->ddc->dev);
|
||||
i2c_put_adapter(output->ddc);
|
||||
}
|
||||
|
||||
int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
||||
#include "drm.h"
|
||||
@ -85,45 +85,13 @@ static void tegra_dc_write_regs(struct tegra_dc *dc,
|
||||
tegra_dc_writel(dc, table[i].value, table[i].offset);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs tegra_rgb_connector_funcs = {
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.detect = tegra_output_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = tegra_output_connector_destroy,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static enum drm_mode_status
|
||||
tegra_rgb_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
/*
|
||||
* FIXME: For now, always assume that the mode is okay. There are
|
||||
* unresolved issues with clk_round_rate(), which doesn't always
|
||||
* reliably report whether a frequency can be set or not.
|
||||
*/
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs tegra_rgb_connector_helper_funcs = {
|
||||
.get_modes = tegra_output_connector_get_modes,
|
||||
.mode_valid = tegra_rgb_connector_mode_valid,
|
||||
};
|
||||
|
||||
static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct tegra_output *output = encoder_to_output(encoder);
|
||||
struct tegra_rgb *rgb = to_rgb(output);
|
||||
|
||||
if (output->panel)
|
||||
drm_panel_disable(output->panel);
|
||||
|
||||
tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
|
||||
tegra_dc_commit(rgb->dc);
|
||||
|
||||
if (output->panel)
|
||||
drm_panel_unprepare(output->panel);
|
||||
}
|
||||
|
||||
static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
|
||||
@ -132,9 +100,6 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
|
||||
struct tegra_rgb *rgb = to_rgb(output);
|
||||
u32 value;
|
||||
|
||||
if (output->panel)
|
||||
drm_panel_prepare(output->panel);
|
||||
|
||||
tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
|
||||
|
||||
value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
|
||||
@ -156,9 +121,6 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
|
||||
tegra_dc_writel(rgb->dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
|
||||
|
||||
tegra_dc_commit(rgb->dc);
|
||||
|
||||
if (output->panel)
|
||||
drm_panel_enable(output->panel);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -267,24 +229,68 @@ int tegra_dc_rgb_remove(struct tegra_dc *dc)
|
||||
int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
|
||||
{
|
||||
struct tegra_output *output = dc->rgb;
|
||||
struct drm_connector *connector;
|
||||
int err;
|
||||
|
||||
if (!dc->rgb)
|
||||
return -ENODEV;
|
||||
|
||||
drm_connector_init(drm, &output->connector, &tegra_rgb_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
drm_connector_helper_add(&output->connector,
|
||||
&tegra_rgb_connector_helper_funcs);
|
||||
output->connector.dpms = DRM_MODE_DPMS_OFF;
|
||||
|
||||
drm_simple_encoder_init(drm, &output->encoder, DRM_MODE_ENCODER_LVDS);
|
||||
drm_encoder_helper_add(&output->encoder,
|
||||
&tegra_rgb_encoder_helper_funcs);
|
||||
|
||||
drm_connector_attach_encoder(&output->connector,
|
||||
&output->encoder);
|
||||
drm_connector_register(&output->connector);
|
||||
/*
|
||||
* Wrap directly-connected panel into DRM bridge in order to let
|
||||
* DRM core to handle panel for us.
|
||||
*/
|
||||
if (output->panel) {
|
||||
output->bridge = devm_drm_panel_bridge_add(output->dev,
|
||||
output->panel);
|
||||
if (IS_ERR(output->bridge)) {
|
||||
dev_err(output->dev,
|
||||
"failed to wrap panel into bridge: %pe\n",
|
||||
output->bridge);
|
||||
return PTR_ERR(output->bridge);
|
||||
}
|
||||
|
||||
output->panel = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tegra devices that have LVDS panel utilize LVDS encoder bridge
|
||||
* for converting up to 28 LCD LVTTL lanes into 5/4 LVDS lanes that
|
||||
* go to display panel's receiver.
|
||||
*
|
||||
* Encoder usually have a power-down control which needs to be enabled
|
||||
* in order to transmit data to the panel. Historically devices that
|
||||
* use an older device-tree version didn't model the bridge, assuming
|
||||
* that encoder is turned ON by default, while today's DRM allows us
|
||||
* to model LVDS encoder properly.
|
||||
*
|
||||
* Newer device-trees utilize LVDS encoder bridge, which provides
|
||||
* us with a connector and handles the display panel.
|
||||
*
|
||||
* For older device-trees we wrapped panel into the panel-bridge.
|
||||
*/
|
||||
if (output->bridge) {
|
||||
err = drm_bridge_attach(&output->encoder, output->bridge,
|
||||
NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (err) {
|
||||
dev_err(output->dev, "failed to attach bridge: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
connector = drm_bridge_connector_init(drm, &output->encoder);
|
||||
if (IS_ERR(connector)) {
|
||||
dev_err(output->dev,
|
||||
"failed to initialize bridge connector: %pe\n",
|
||||
connector);
|
||||
return PTR_ERR(connector);
|
||||
}
|
||||
|
||||
drm_connector_attach_encoder(connector, &output->encoder);
|
||||
}
|
||||
|
||||
err = tegra_output_init(drm, output);
|
||||
if (err < 0) {
|
||||
|
@ -3728,7 +3728,12 @@ static int tegra_sor_probe(struct platform_device *pdev)
|
||||
if (!sor->aux)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
sor->output.ddc = &sor->aux->ddc;
|
||||
if (get_device(&sor->aux->ddc.dev)) {
|
||||
if (try_module_get(sor->aux->ddc.owner))
|
||||
sor->output.ddc = &sor->aux->ddc;
|
||||
else
|
||||
put_device(&sor->aux->ddc.dev);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sor->aux) {
|
||||
|
Loading…
Reference in New Issue
Block a user