summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/bridge/adv7511/adv7511_drv.c')
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c131
1 files changed, 114 insertions, 17 deletions
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 1b2fae915ecc..ff3f73fd4867 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -9,7 +9,9 @@
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_graph.h>
#include <linux/slab.h>
#include <drm/drmP.h>
@@ -365,7 +367,7 @@ static void adv7511_power_on(struct adv7511 *adv7511)
*/
regcache_sync(adv7511->regmap);
- if (adv7511->type == ADV7533)
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
adv7533_dsi_power_on(adv7511);
adv7511->powered = true;
}
@@ -382,7 +384,7 @@ static void __adv7511_power_off(struct adv7511 *adv7511)
static void adv7511_power_off(struct adv7511 *adv7511)
{
__adv7511_power_off(adv7511);
- if (adv7511->type == ADV7533)
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
adv7533_dsi_power_off(adv7511);
adv7511->powered = false;
}
@@ -583,6 +585,8 @@ static int adv7511_get_modes(struct adv7511 *adv7511,
{
struct edid *edid;
unsigned int count;
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ int ret;
/* Reading the EDID only works if the device is powered */
if (!adv7511->powered) {
@@ -611,6 +615,14 @@ static int adv7511_get_modes(struct adv7511 *adv7511,
adv7511_set_config_csc(adv7511, connector, adv7511->rgb);
+ connector->display_info.bus_flags = DRM_BUS_FLAG_DE_LOW |
+ DRM_BUS_FLAG_PIXDATA_NEGEDGE;
+
+ ret = drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+ if (ret)
+ return ret;
+
return count;
}
@@ -744,12 +756,17 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
else
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
- regmap_update_bits(adv7511->regmap, 0xfb,
- 0x6, low_refresh_rate << 1);
+ if (adv7511->type == ADV7535)
+ regmap_update_bits(adv7511->regmap, 0x4a,
+ 0xc, low_refresh_rate << 2);
+ else
+ regmap_update_bits(adv7511->regmap, 0xfb,
+ 0x6, low_refresh_rate << 1);
+
regmap_update_bits(adv7511->regmap, 0x17,
0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
- if (adv7511->type == ADV7533)
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
adv7533_mode_set(adv7511, adj_mode);
drm_mode_copy(&adv7511->curr_mode, adj_mode);
@@ -836,6 +853,18 @@ static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
adv7511_mode_set(adv, mode, adj_mode);
}
+static bool adv7511_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+ if (adv->type == ADV7533 || adv->type == ADV7535)
+ return adv7533_mode_fixup(adv, adjusted_mode);
+
+ return true;
+}
+
static int adv7511_bridge_attach(struct drm_bridge *bridge)
{
struct adv7511 *adv = bridge_to_adv7511(bridge);
@@ -859,7 +888,7 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
&adv7511_connector_helper_funcs);
drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
- if (adv->type == ADV7533)
+ if (adv->type == ADV7533 || adv->type == ADV7535)
ret = adv7533_attach_dsi(adv);
return ret;
@@ -869,6 +898,7 @@ static struct drm_bridge_funcs adv7511_bridge_funcs = {
.enable = adv7511_bridge_enable,
.disable = adv7511_bridge_disable,
.mode_set = adv7511_bridge_mode_set,
+ .mode_fixup = adv7511_bridge_mode_fixup,
.attach = adv7511_bridge_attach,
};
@@ -964,8 +994,15 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
struct adv7511_link_config link_config;
struct adv7511 *adv7511;
struct device *dev = &i2c->dev;
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+ struct device_node *remote_node = NULL, *endpoint = NULL;
+ struct of_changeset ocs;
+ struct property *prop;
+#endif
unsigned int main_i2c_addr = i2c->addr << 1;
unsigned int edid_i2c_addr = main_i2c_addr + 4;
+ unsigned int cec_i2c_addr = main_i2c_addr - 2;
+ unsigned int pkt_i2c_addr = main_i2c_addr - 0xa;
unsigned int val;
int ret;
@@ -993,6 +1030,21 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (ret)
return ret;
+ if (adv7511->addr_cec != 0)
+ cec_i2c_addr = adv7511->addr_cec << 1;
+ else
+ adv7511->addr_cec = cec_i2c_addr >> 1;
+
+ if (adv7511->addr_edid != 0)
+ edid_i2c_addr = adv7511->addr_edid << 1;
+ else
+ adv7511->addr_edid = edid_i2c_addr >> 1;
+
+ if (adv7511->addr_pkt != 0)
+ pkt_i2c_addr = adv7511->addr_pkt << 1;
+ else
+ adv7511->addr_pkt = pkt_i2c_addr >> 1;
+
/*
* The power down GPIO is optional. If present, toggle it from active to
* inactive to wake up the encoder.
@@ -1007,12 +1059,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
}
adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
- if (IS_ERR(adv7511->regmap))
- return PTR_ERR(adv7511->regmap);
+ if (IS_ERR(adv7511->regmap)) {
+ ret = PTR_ERR(adv7511->regmap);
+ goto of_reconfig;
+ }
ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
if (ret)
- return ret;
+ goto of_reconfig;
dev_dbg(dev, "Rev. %d\n", val);
if (adv7511->type == ADV7511)
@@ -1024,11 +1078,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (ret)
return ret;
- regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
+ regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
+ edid_i2c_addr);
regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
- main_i2c_addr - 0xa);
+ pkt_i2c_addr);
regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
- main_i2c_addr - 2);
+ cec_i2c_addr);
adv7511_packet_disable(adv7511, 0xffff);
@@ -1037,7 +1092,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (!adv7511->i2c_edid)
return -ENOMEM;
- if (adv7511->type == ADV7533) {
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535) {
ret = adv7533_init_cec(adv7511);
if (ret)
goto err_i2c_unregister_edid;
@@ -1082,6 +1137,45 @@ err_unregister_cec:
adv7533_uninit_cec(adv7511);
err_i2c_unregister_edid:
i2c_unregister_device(adv7511->i2c_edid);
+of_reconfig:
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (endpoint)
+ remote_node = of_graph_get_remote_port_parent(endpoint);
+
+ if (remote_node) {
+ int num_endpoints = 0;
+
+ /*
+ * Remote node should have two endpoints (input and output: us)
+ * If remote node has more than two endpoints, probably that it
+ * has more outputs, so there is no need to disable it.
+ */
+ endpoint = NULL;
+ while ((endpoint = of_graph_get_next_endpoint(remote_node,
+ endpoint)))
+ num_endpoints++;
+
+ if (num_endpoints > 2) {
+ of_node_put(remote_node);
+ return ret;
+ }
+
+ prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
+ prop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
+ prop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
+ prop->length = 9;
+ of_changeset_init(&ocs);
+ of_changeset_update_property(&ocs, remote_node, prop);
+ ret = of_changeset_apply(&ocs);
+ if (!ret)
+ dev_warn(dev,
+ "Probe failed. Remote port '%s' disabled\n",
+ remote_node->full_name);
+
+ of_node_put(remote_node);
+ };
+#endif
return ret;
}
@@ -1090,16 +1184,17 @@ static int adv7511_remove(struct i2c_client *i2c)
{
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
- if (adv7511->type == ADV7533) {
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535) {
adv7533_detach_dsi(adv7511);
adv7533_uninit_cec(adv7511);
}
drm_bridge_remove(&adv7511->bridge);
- i2c_unregister_device(adv7511->i2c_edid);
-
- kfree(adv7511->edid);
+ if (adv7511->i2c_edid) {
+ i2c_unregister_device(adv7511->i2c_edid);
+ kfree(adv7511->edid);
+ }
return 0;
}
@@ -1110,6 +1205,7 @@ static const struct i2c_device_id adv7511_i2c_ids[] = {
{ "adv7513", ADV7511 },
#ifdef CONFIG_DRM_I2C_ADV7533
{ "adv7533", ADV7533 },
+ { "adv7535", ADV7535 },
#endif
{ }
};
@@ -1121,6 +1217,7 @@ static const struct of_device_id adv7511_of_ids[] = {
{ .compatible = "adi,adv7513", .data = (void *)ADV7511 },
#ifdef CONFIG_DRM_I2C_ADV7533
{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
+ { .compatible = "adi,adv7535", .data = (void *)ADV7535 },
#endif
{ }
};