From cfe2741550a7c02a89f22537f170bf3405b7481a Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 8 Jun 2016 18:47:27 +0200 Subject: drm/i2c/ch7006: Use helper to turn off CRTC Use shiny new drm_crtc_force_disable() instead of open coding the same. No functional change intended. Cc: Francisco Jerez Signed-off-by: Lukas Wunner Reviewed-by: Francisco Jerez Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/ec7d5c06e2a21dfb8f9fc9413d3e6df86d6aa1fb.1465392124.git.lukas@wunner.de --- drivers/gpu/drm/i2c/ch7006_drv.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i2c') diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 0594c45f7164..e9e8ae2ec06b 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c @@ -361,13 +361,8 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder, /* Disable the crtc to ensure a full modeset is * performed whenever it's turned on again. */ - if (crtc) { - struct drm_mode_set modeset = { - .crtc = crtc, - }; - - drm_mode_set_config_internal(&modeset); - } + if (crtc) + drm_crtc_force_disable(crtc); } return 0; -- cgit v1.2.3 From e12c2f645557708932e15afdf77f5965549cf156 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Sat, 9 Jan 2016 14:24:54 +0530 Subject: drm/i2c: adv7511: Convert to drm_bridge We don't want to use the old i2c slave encoder interface anymore. Remove that and make the i2c driver create a drm_bridge entity instead. Converting to bridges helps because the kms drivers don't need to exract encoder slave ops from this driver and use it within their own encoder/connector ops. The driver now creates its own connector when a kms driver attaches itself to the bridge. Therefore, kms drivers don't need to create their own connectors anymore. The old encoder slave ops are now used by the new bridge and connector entities. The of_node member in drm_bridge is accessible only when CONFIG_OF is enabled. The driver anyway only works only when OF is available. Make the driver depend on OF in its Kconfig. Signed-off-by: Archit Taneja --- drivers/gpu/drm/i2c/Kconfig | 1 + drivers/gpu/drm/i2c/adv7511.c | 213 +++++++++++++++++++++++++++--------------- 2 files changed, 140 insertions(+), 74 deletions(-) (limited to 'drivers/gpu/drm/i2c') diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 22c7ed63a001..8bb06977343a 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -3,6 +3,7 @@ menu "I2C encoder or helper chips" config DRM_I2C_ADV7511 tristate "AV7511 encoder" + depends on OF select REGMAP_I2C help Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders. diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c index a02112ba1c3d..c2642f99865d 100644 --- a/drivers/gpu/drm/i2c/adv7511.c +++ b/drivers/gpu/drm/i2c/adv7511.c @@ -14,9 +14,10 @@ #include #include +#include +#include #include #include -#include #include "adv7511.h" @@ -36,7 +37,8 @@ struct adv7511 { bool edid_read; wait_queue_head_t wq; - struct drm_encoder *encoder; + struct drm_bridge bridge; + struct drm_connector connector; bool embedded_sync; enum adv7511_sync_polarity vsync_polarity; @@ -48,11 +50,6 @@ struct adv7511 { struct gpio_desc *gpio_pd; }; -static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder) -{ - return to_encoder_slave(encoder)->slave_priv; -} - /* ADI recommended values for proper operation. */ static const struct reg_sequence adv7511_fixed_registers[] = { { 0x98, 0x03 }, @@ -446,8 +443,8 @@ static int adv7511_irq_process(struct adv7511 *adv7511) regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0); regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); - if (irq0 & ADV7511_INT0_HPD && adv7511->encoder) - drm_helper_hpd_irq_event(adv7511->encoder->dev); + if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder) + drm_helper_hpd_irq_event(adv7511->connector.dev); if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { adv7511->edid_read = true; @@ -563,13 +560,12 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, } /* ----------------------------------------------------------------------------- - * Encoder operations + * ADV75xx helpers */ -static int adv7511_get_modes(struct drm_encoder *encoder, +static int adv7511_get_modes(struct adv7511 *adv7511, struct drm_connector *connector) { - struct adv7511 *adv7511 = encoder_to_adv7511(encoder); struct edid *edid; unsigned int count; @@ -606,21 +602,9 @@ static int adv7511_get_modes(struct drm_encoder *encoder, return count; } -static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct adv7511 *adv7511 = encoder_to_adv7511(encoder); - - if (mode == DRM_MODE_DPMS_ON) - adv7511_power_on(adv7511); - else - adv7511_power_off(adv7511); -} - static enum drm_connector_status -adv7511_encoder_detect(struct drm_encoder *encoder, - struct drm_connector *connector) +adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) { - struct adv7511 *adv7511 = encoder_to_adv7511(encoder); enum drm_connector_status status; unsigned int val; bool hpd; @@ -644,7 +628,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder, if (status == connector_status_connected && hpd && adv7511->powered) { regcache_mark_dirty(adv7511->regmap); adv7511_power_on(adv7511); - adv7511_get_modes(encoder, connector); + adv7511_get_modes(adv7511, connector); if (adv7511->status == connector_status_connected) status = connector_status_disconnected; } else { @@ -658,8 +642,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder, return status; } -static int adv7511_encoder_mode_valid(struct drm_encoder *encoder, - struct drm_display_mode *mode) +static int adv7511_mode_valid(struct adv7511 *adv7511, + struct drm_display_mode *mode) { if (mode->clock > 165000) return MODE_CLOCK_HIGH; @@ -667,11 +651,10 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder, return MODE_OK; } -static void adv7511_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) +static void adv7511_mode_set(struct adv7511 *adv7511, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) { - struct adv7511 *adv7511 = encoder_to_adv7511(encoder); unsigned int low_refresh_rate; unsigned int hsync_polarity = 0; unsigned int vsync_polarity = 0; @@ -762,12 +745,111 @@ static void adv7511_encoder_mode_set(struct drm_encoder *encoder, adv7511->f_tmds = mode->clock; } -static const struct drm_encoder_slave_funcs adv7511_encoder_funcs = { - .dpms = adv7511_encoder_dpms, - .mode_valid = adv7511_encoder_mode_valid, - .mode_set = adv7511_encoder_mode_set, - .detect = adv7511_encoder_detect, - .get_modes = adv7511_get_modes, +/* Connector funcs */ +static struct adv7511 *connector_to_adv7511(struct drm_connector *connector) +{ + return container_of(connector, struct adv7511, connector); +} + +static int adv7511_connector_get_modes(struct drm_connector *connector) +{ + struct adv7511 *adv = connector_to_adv7511(connector); + + return adv7511_get_modes(adv, connector); +} + +static enum drm_mode_status +adv7511_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct adv7511 *adv = connector_to_adv7511(connector); + + return adv7511_mode_valid(adv, mode); +} + +static struct drm_connector_helper_funcs adv7511_connector_helper_funcs = { + .get_modes = adv7511_connector_get_modes, + .mode_valid = adv7511_connector_mode_valid, +}; + +static enum drm_connector_status +adv7511_connector_detect(struct drm_connector *connector, bool force) +{ + struct adv7511 *adv = connector_to_adv7511(connector); + + return adv7511_detect(adv, connector); +} + +static struct drm_connector_funcs adv7511_connector_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = adv7511_connector_detect, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +/* Bridge funcs */ +static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge) +{ + return container_of(bridge, struct adv7511, bridge); +} + +static void adv7511_bridge_enable(struct drm_bridge *bridge) +{ + struct adv7511 *adv = bridge_to_adv7511(bridge); + + adv7511_power_on(adv); +} + +static void adv7511_bridge_disable(struct drm_bridge *bridge) +{ + struct adv7511 *adv = bridge_to_adv7511(bridge); + + adv7511_power_off(adv); +} + +static void adv7511_bridge_mode_set(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct adv7511 *adv = bridge_to_adv7511(bridge); + + adv7511_mode_set(adv, mode, adj_mode); +} + +static int adv7511_bridge_attach(struct drm_bridge *bridge) +{ + struct adv7511 *adv = bridge_to_adv7511(bridge); + int ret; + + if (!bridge->encoder) { + DRM_ERROR("Parent encoder object not found"); + return -ENODEV; + } + + adv->connector.polled = DRM_CONNECTOR_POLL_HPD; + + ret = drm_connector_init(bridge->dev, &adv->connector, + &adv7511_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + if (ret) { + DRM_ERROR("Failed to initialize connector with drm\n"); + return ret; + } + drm_connector_helper_add(&adv->connector, + &adv7511_connector_helper_funcs); + drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder); + + return ret; +} + +static struct drm_bridge_funcs adv7511_bridge_funcs = { + .enable = adv7511_bridge_enable, + .disable = adv7511_bridge_disable, + .mode_set = adv7511_bridge_mode_set, + .attach = adv7511_bridge_attach, }; /* ----------------------------------------------------------------------------- @@ -944,6 +1026,15 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) adv7511_set_link_config(adv7511, &link_config); + adv7511->bridge.funcs = &adv7511_bridge_funcs; + adv7511->bridge.of_node = dev->of_node; + + ret = drm_bridge_add(&adv7511->bridge); + if (ret) { + dev_err(dev, "failed to add adv7511 bridge\n"); + goto err_i2c_unregister_device; + } + return 0; err_i2c_unregister_device: @@ -956,6 +1047,8 @@ static int adv7511_remove(struct i2c_client *i2c) { struct adv7511 *adv7511 = i2c_get_clientdata(i2c); + drm_bridge_remove(&adv7511->bridge); + i2c_unregister_device(adv7511->i2c_edid); kfree(adv7511->edid); @@ -963,20 +1056,6 @@ static int adv7511_remove(struct i2c_client *i2c) return 0; } -static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev, - struct drm_encoder_slave *encoder) -{ - - struct adv7511 *adv7511 = i2c_get_clientdata(i2c); - - encoder->slave_priv = adv7511; - encoder->slave_funcs = &adv7511_encoder_funcs; - - adv7511->encoder = &encoder->base; - - return 0; -} - static const struct i2c_device_id adv7511_i2c_ids[] = { { "adv7511", 0 }, { "adv7511w", 0 }, @@ -993,31 +1072,17 @@ static const struct of_device_id adv7511_of_ids[] = { }; MODULE_DEVICE_TABLE(of, adv7511_of_ids); -static struct drm_i2c_encoder_driver adv7511_driver = { - .i2c_driver = { - .driver = { - .name = "adv7511", - .of_match_table = adv7511_of_ids, - }, - .id_table = adv7511_i2c_ids, - .probe = adv7511_probe, - .remove = adv7511_remove, +static struct i2c_driver adv7511_driver = { + .driver = { + .name = "adv7511", + .of_match_table = adv7511_of_ids, }, - - .encoder_init = adv7511_encoder_init, + .id_table = adv7511_i2c_ids, + .probe = adv7511_probe, + .remove = adv7511_remove, }; -static int __init adv7511_init(void) -{ - return drm_i2c_encoder_register(THIS_MODULE, &adv7511_driver); -} -module_init(adv7511_init); - -static void __exit adv7511_exit(void) -{ - drm_i2c_encoder_unregister(&adv7511_driver); -} -module_exit(adv7511_exit); +module_i2c_driver(adv7511_driver); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver"); -- cgit v1.2.3 From c582778900425d0cf2a5687a84b0125fee797d32 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 17 Jun 2016 13:30:35 +0530 Subject: drm/i2c: adv7511: Move to bridge folder The driver has been converted to use drm_bridge instead of drm_i2c_slave_encoder. We can now move it to the bridge folder. Create a separate folder since we already have a couple of files and expect more when we support audio and ADV7533. Rename the driver to adv7511_drv.c. This will come in handy later when the driver module will need to be built from multiple object files. Signed-off-by: Archit Taneja --- drivers/gpu/drm/i2c/Kconfig | 7 - drivers/gpu/drm/i2c/Makefile | 2 - drivers/gpu/drm/i2c/adv7511.c | 1089 ----------------------------------------- drivers/gpu/drm/i2c/adv7511.h | 289 ----------- 4 files changed, 1387 deletions(-) delete mode 100644 drivers/gpu/drm/i2c/adv7511.c delete mode 100644 drivers/gpu/drm/i2c/adv7511.h (limited to 'drivers/gpu/drm/i2c') diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 8bb06977343a..4d341db462a2 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -1,13 +1,6 @@ menu "I2C encoder or helper chips" depends on DRM && DRM_KMS_HELPER && I2C -config DRM_I2C_ADV7511 - tristate "AV7511 encoder" - depends on OF - select REGMAP_I2C - help - Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders. - config DRM_I2C_CH7006 tristate "Chrontel ch7006 TV encoder" default m if DRM_NOUVEAU diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile index 2c72eb584ab7..43aa33baebed 100644 --- a/drivers/gpu/drm/i2c/Makefile +++ b/drivers/gpu/drm/i2c/Makefile @@ -1,7 +1,5 @@ ccflags-y := -Iinclude/drm -obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o - ch7006-y := ch7006_drv.o ch7006_mode.o obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c deleted file mode 100644 index c2642f99865d..000000000000 --- a/drivers/gpu/drm/i2c/adv7511.c +++ /dev/null @@ -1,1089 +0,0 @@ -/* - * Analog Devices ADV7511 HDMI transmitter driver - * - * Copyright 2012 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "adv7511.h" - -struct adv7511 { - struct i2c_client *i2c_main; - struct i2c_client *i2c_edid; - - struct regmap *regmap; - struct regmap *packet_memory_regmap; - enum drm_connector_status status; - bool powered; - - unsigned int f_tmds; - - unsigned int current_edid_segment; - uint8_t edid_buf[256]; - bool edid_read; - - wait_queue_head_t wq; - struct drm_bridge bridge; - struct drm_connector connector; - - bool embedded_sync; - enum adv7511_sync_polarity vsync_polarity; - enum adv7511_sync_polarity hsync_polarity; - bool rgb; - - struct edid *edid; - - struct gpio_desc *gpio_pd; -}; - -/* ADI recommended values for proper operation. */ -static const struct reg_sequence adv7511_fixed_registers[] = { - { 0x98, 0x03 }, - { 0x9a, 0xe0 }, - { 0x9c, 0x30 }, - { 0x9d, 0x61 }, - { 0xa2, 0xa4 }, - { 0xa3, 0xa4 }, - { 0xe0, 0xd0 }, - { 0xf9, 0x00 }, - { 0x55, 0x02 }, -}; - -/* ----------------------------------------------------------------------------- - * Register access - */ - -static const uint8_t adv7511_register_defaults[] = { - 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */ - 0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13, - 0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ - 0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84, - 0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */ - 0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */ - 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, - 0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */ - 0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */ - 0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */ - 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */ - 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04, - 0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, - 0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */ - 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static bool adv7511_register_volatile(struct device *dev, unsigned int reg) -{ - switch (reg) { - case ADV7511_REG_CHIP_REVISION: - case ADV7511_REG_SPDIF_FREQ: - case ADV7511_REG_CTS_AUTOMATIC1: - case ADV7511_REG_CTS_AUTOMATIC2: - case ADV7511_REG_VIC_DETECTED: - case ADV7511_REG_VIC_SEND: - case ADV7511_REG_AUX_VIC_DETECTED: - case ADV7511_REG_STATUS: - case ADV7511_REG_GC(1): - case ADV7511_REG_INT(0): - case ADV7511_REG_INT(1): - case ADV7511_REG_PLL_STATUS: - case ADV7511_REG_AN(0): - case ADV7511_REG_AN(1): - case ADV7511_REG_AN(2): - case ADV7511_REG_AN(3): - case ADV7511_REG_AN(4): - case ADV7511_REG_AN(5): - case ADV7511_REG_AN(6): - case ADV7511_REG_AN(7): - case ADV7511_REG_HDCP_STATUS: - case ADV7511_REG_BCAPS: - case ADV7511_REG_BKSV(0): - case ADV7511_REG_BKSV(1): - case ADV7511_REG_BKSV(2): - case ADV7511_REG_BKSV(3): - case ADV7511_REG_BKSV(4): - case ADV7511_REG_DDC_STATUS: - case ADV7511_REG_EDID_READ_CTRL: - case ADV7511_REG_BSTATUS(0): - case ADV7511_REG_BSTATUS(1): - case ADV7511_REG_CHIP_ID_HIGH: - case ADV7511_REG_CHIP_ID_LOW: - return true; - } - - return false; -} - -static const struct regmap_config adv7511_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_RBTREE, - .reg_defaults_raw = adv7511_register_defaults, - .num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults), - - .volatile_reg = adv7511_register_volatile, -}; - -/* ----------------------------------------------------------------------------- - * Hardware configuration - */ - -static void adv7511_set_colormap(struct adv7511 *adv7511, bool enable, - const uint16_t *coeff, - unsigned int scaling_factor) -{ - unsigned int i; - - regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1), - ADV7511_CSC_UPDATE_MODE, ADV7511_CSC_UPDATE_MODE); - - if (enable) { - for (i = 0; i < 12; ++i) { - regmap_update_bits(adv7511->regmap, - ADV7511_REG_CSC_UPPER(i), - 0x1f, coeff[i] >> 8); - regmap_write(adv7511->regmap, - ADV7511_REG_CSC_LOWER(i), - coeff[i] & 0xff); - } - } - - if (enable) - regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0), - 0xe0, 0x80 | (scaling_factor << 5)); - else - regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0), - 0x80, 0x00); - - regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1), - ADV7511_CSC_UPDATE_MODE, 0); -} - -static int adv7511_packet_enable(struct adv7511 *adv7511, unsigned int packet) -{ - if (packet & 0xff) - regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0, - packet, 0xff); - - if (packet & 0xff00) { - packet >>= 8; - regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, - packet, 0xff); - } - - return 0; -} - -static int adv7511_packet_disable(struct adv7511 *adv7511, unsigned int packet) -{ - if (packet & 0xff) - regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0, - packet, 0x00); - - if (packet & 0xff00) { - packet >>= 8; - regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, - packet, 0x00); - } - - return 0; -} - -/* Coefficients for adv7511 color space conversion */ -static const uint16_t adv7511_csc_ycbcr_to_rgb[] = { - 0x0734, 0x04ad, 0x0000, 0x1c1b, - 0x1ddc, 0x04ad, 0x1f24, 0x0135, - 0x0000, 0x04ad, 0x087c, 0x1b77, -}; - -static void adv7511_set_config_csc(struct adv7511 *adv7511, - struct drm_connector *connector, - bool rgb) -{ - struct adv7511_video_config config; - bool output_format_422, output_format_ycbcr; - unsigned int mode; - uint8_t infoframe[17]; - - if (adv7511->edid) - config.hdmi_mode = drm_detect_hdmi_monitor(adv7511->edid); - else - config.hdmi_mode = false; - - hdmi_avi_infoframe_init(&config.avi_infoframe); - - config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN; - - if (rgb) { - config.csc_enable = false; - config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; - } else { - config.csc_scaling_factor = ADV7511_CSC_SCALING_4; - config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; - - if ((connector->display_info.color_formats & - DRM_COLOR_FORMAT_YCRCB422) && - config.hdmi_mode) { - config.csc_enable = false; - config.avi_infoframe.colorspace = - HDMI_COLORSPACE_YUV422; - } else { - config.csc_enable = true; - config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; - } - } - - if (config.hdmi_mode) { - mode = ADV7511_HDMI_CFG_MODE_HDMI; - - switch (config.avi_infoframe.colorspace) { - case HDMI_COLORSPACE_YUV444: - output_format_422 = false; - output_format_ycbcr = true; - break; - case HDMI_COLORSPACE_YUV422: - output_format_422 = true; - output_format_ycbcr = true; - break; - default: - output_format_422 = false; - output_format_ycbcr = false; - break; - } - } else { - mode = ADV7511_HDMI_CFG_MODE_DVI; - output_format_422 = false; - output_format_ycbcr = false; - } - - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); - - adv7511_set_colormap(adv7511, config.csc_enable, - config.csc_coefficents, - config.csc_scaling_factor); - - regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x81, - (output_format_422 << 7) | output_format_ycbcr); - - regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG, - ADV7511_HDMI_CFG_MODE_MASK, mode); - - hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe, - sizeof(infoframe)); - - /* The AVI infoframe id is not configurable */ - regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION, - infoframe + 1, sizeof(infoframe) - 1); - - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); -} - -static void adv7511_set_link_config(struct adv7511 *adv7511, - const struct adv7511_link_config *config) -{ - /* - * The input style values documented in the datasheet don't match the - * hardware register field values :-( - */ - static const unsigned int input_styles[4] = { 0, 2, 1, 3 }; - - unsigned int clock_delay; - unsigned int color_depth; - unsigned int input_id; - - clock_delay = (config->clock_delay + 1200) / 400; - color_depth = config->input_color_depth == 8 ? 3 - : (config->input_color_depth == 10 ? 1 : 2); - - /* TODO Support input ID 6 */ - if (config->input_colorspace != HDMI_COLORSPACE_YUV422) - input_id = config->input_clock == ADV7511_INPUT_CLOCK_DDR - ? 5 : 0; - else if (config->input_clock == ADV7511_INPUT_CLOCK_DDR) - input_id = config->embedded_sync ? 8 : 7; - else if (config->input_clock == ADV7511_INPUT_CLOCK_2X) - input_id = config->embedded_sync ? 4 : 3; - else - input_id = config->embedded_sync ? 2 : 1; - - regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, 0xf, - input_id); - regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x7e, - (color_depth << 4) | - (input_styles[config->input_style] << 2)); - regmap_write(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG2, - config->input_justification << 3); - regmap_write(adv7511->regmap, ADV7511_REG_TIMING_GEN_SEQ, - config->sync_pulse << 2); - - regmap_write(adv7511->regmap, 0xba, clock_delay << 5); - - adv7511->embedded_sync = config->embedded_sync; - adv7511->hsync_polarity = config->hsync_polarity; - adv7511->vsync_polarity = config->vsync_polarity; - adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; -} - -static void adv7511_power_on(struct adv7511 *adv7511) -{ - adv7511->current_edid_segment = -1; - - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, 0); - if (adv7511->i2c_main->irq) { - /* - * Documentation says the INT_ENABLE registers are reset in - * POWER_DOWN mode. My 7511w preserved the bits, however. - * Still, let's be safe and stick to the documentation. - */ - regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0), - ADV7511_INT0_EDID_READY); - regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1), - ADV7511_INT1_DDC_ERROR); - } - - /* - * Per spec it is allowed to pulse the HPD signal to indicate that the - * EDID information has changed. Some monitors do this when they wakeup - * from standby or are enabled. When the HPD goes low the adv7511 is - * reset and the outputs are disabled which might cause the monitor to - * go to standby again. To avoid this we ignore the HPD pin for the - * first few seconds after enabling the output. - */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HPD_SRC_MASK, - ADV7511_REG_POWER2_HPD_SRC_NONE); - - /* - * Most of the registers are reset during power down or when HPD is low. - */ - regcache_sync(adv7511->regmap); - - adv7511->powered = true; -} - -static void adv7511_power_off(struct adv7511 *adv7511) -{ - /* TODO: setup additional power down modes */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, - ADV7511_POWER_POWER_DOWN); - regcache_mark_dirty(adv7511->regmap); - - adv7511->powered = false; -} - -/* ----------------------------------------------------------------------------- - * Interrupt and hotplug detection - */ - -static bool adv7511_hpd(struct adv7511 *adv7511) -{ - unsigned int irq0; - int ret; - - ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); - if (ret < 0) - return false; - - if (irq0 & ADV7511_INT0_HPD) { - regmap_write(adv7511->regmap, ADV7511_REG_INT(0), - ADV7511_INT0_HPD); - return true; - } - - return false; -} - -static int adv7511_irq_process(struct adv7511 *adv7511) -{ - unsigned int irq0, irq1; - int ret; - - ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); - if (ret < 0) - return ret; - - ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1); - if (ret < 0) - return ret; - - regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0); - regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); - - if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder) - drm_helper_hpd_irq_event(adv7511->connector.dev); - - if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { - adv7511->edid_read = true; - - if (adv7511->i2c_main->irq) - wake_up_all(&adv7511->wq); - } - - return 0; -} - -static irqreturn_t adv7511_irq_handler(int irq, void *devid) -{ - struct adv7511 *adv7511 = devid; - int ret; - - ret = adv7511_irq_process(adv7511); - return ret < 0 ? IRQ_NONE : IRQ_HANDLED; -} - -/* ----------------------------------------------------------------------------- - * EDID retrieval - */ - -static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout) -{ - int ret; - - if (adv7511->i2c_main->irq) { - ret = wait_event_interruptible_timeout(adv7511->wq, - adv7511->edid_read, msecs_to_jiffies(timeout)); - } else { - for (; timeout > 0; timeout -= 25) { - ret = adv7511_irq_process(adv7511); - if (ret < 0) - break; - - if (adv7511->edid_read) - break; - - msleep(25); - } - } - - return adv7511->edid_read ? 0 : -EIO; -} - -static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, - size_t len) -{ - struct adv7511 *adv7511 = data; - struct i2c_msg xfer[2]; - uint8_t offset; - unsigned int i; - int ret; - - if (len > 128) - return -EINVAL; - - if (adv7511->current_edid_segment != block / 2) { - unsigned int status; - - ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS, - &status); - if (ret < 0) - return ret; - - if (status != 2) { - adv7511->edid_read = false; - regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT, - block); - ret = adv7511_wait_for_edid(adv7511, 200); - if (ret < 0) - return ret; - } - - /* Break this apart, hopefully more I2C controllers will - * support 64 byte transfers than 256 byte transfers - */ - - xfer[0].addr = adv7511->i2c_edid->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = &offset; - xfer[1].addr = adv7511->i2c_edid->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 64; - xfer[1].buf = adv7511->edid_buf; - - offset = 0; - - for (i = 0; i < 4; ++i) { - ret = i2c_transfer(adv7511->i2c_edid->adapter, xfer, - ARRAY_SIZE(xfer)); - if (ret < 0) - return ret; - else if (ret != 2) - return -EIO; - - xfer[1].buf += 64; - offset += 64; - } - - adv7511->current_edid_segment = block / 2; - } - - if (block % 2 == 0) - memcpy(buf, adv7511->edid_buf, len); - else - memcpy(buf, adv7511->edid_buf + 128, len); - - return 0; -} - -/* ----------------------------------------------------------------------------- - * ADV75xx helpers - */ - -static int adv7511_get_modes(struct adv7511 *adv7511, - struct drm_connector *connector) -{ - struct edid *edid; - unsigned int count; - - /* Reading the EDID only works if the device is powered */ - if (!adv7511->powered) { - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, 0); - if (adv7511->i2c_main->irq) { - regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0), - ADV7511_INT0_EDID_READY); - regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1), - ADV7511_INT1_DDC_ERROR); - } - adv7511->current_edid_segment = -1; - } - - edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); - - if (!adv7511->powered) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, - ADV7511_POWER_POWER_DOWN); - - kfree(adv7511->edid); - adv7511->edid = edid; - if (!edid) - return 0; - - drm_mode_connector_update_edid_property(connector, edid); - count = drm_add_edid_modes(connector, edid); - - adv7511_set_config_csc(adv7511, connector, adv7511->rgb); - - return count; -} - -static enum drm_connector_status -adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) -{ - enum drm_connector_status status; - unsigned int val; - bool hpd; - int ret; - - ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val); - if (ret < 0) - return connector_status_disconnected; - - if (val & ADV7511_STATUS_HPD) - status = connector_status_connected; - else - status = connector_status_disconnected; - - hpd = adv7511_hpd(adv7511); - - /* The chip resets itself when the cable is disconnected, so in case - * there is a pending HPD interrupt and the cable is connected there was - * at least one transition from disconnected to connected and the chip - * has to be reinitialized. */ - if (status == connector_status_connected && hpd && adv7511->powered) { - regcache_mark_dirty(adv7511->regmap); - adv7511_power_on(adv7511); - adv7511_get_modes(adv7511, connector); - if (adv7511->status == connector_status_connected) - status = connector_status_disconnected; - } else { - /* Renable HPD sensing */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HPD_SRC_MASK, - ADV7511_REG_POWER2_HPD_SRC_BOTH); - } - - adv7511->status = status; - return status; -} - -static int adv7511_mode_valid(struct adv7511 *adv7511, - struct drm_display_mode *mode) -{ - if (mode->clock > 165000) - return MODE_CLOCK_HIGH; - - return MODE_OK; -} - -static void adv7511_mode_set(struct adv7511 *adv7511, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) -{ - unsigned int low_refresh_rate; - unsigned int hsync_polarity = 0; - unsigned int vsync_polarity = 0; - - if (adv7511->embedded_sync) { - unsigned int hsync_offset, hsync_len; - unsigned int vsync_offset, vsync_len; - - hsync_offset = adj_mode->crtc_hsync_start - - adj_mode->crtc_hdisplay; - vsync_offset = adj_mode->crtc_vsync_start - - adj_mode->crtc_vdisplay; - hsync_len = adj_mode->crtc_hsync_end - - adj_mode->crtc_hsync_start; - vsync_len = adj_mode->crtc_vsync_end - - adj_mode->crtc_vsync_start; - - /* The hardware vsync generator has a off-by-one bug */ - vsync_offset += 1; - - regmap_write(adv7511->regmap, ADV7511_REG_HSYNC_PLACEMENT_MSB, - ((hsync_offset >> 10) & 0x7) << 5); - regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(0), - (hsync_offset >> 2) & 0xff); - regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(1), - ((hsync_offset & 0x3) << 6) | - ((hsync_len >> 4) & 0x3f)); - regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(2), - ((hsync_len & 0xf) << 4) | - ((vsync_offset >> 6) & 0xf)); - regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(3), - ((vsync_offset & 0x3f) << 2) | - ((vsync_len >> 8) & 0x3)); - regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(4), - vsync_len & 0xff); - - hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC); - vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC); - } else { - enum adv7511_sync_polarity mode_hsync_polarity; - enum adv7511_sync_polarity mode_vsync_polarity; - - /** - * If the input signal is always low or always high we want to - * invert or let it passthrough depending on the polarity of the - * current mode. - **/ - if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC) - mode_hsync_polarity = ADV7511_SYNC_POLARITY_LOW; - else - mode_hsync_polarity = ADV7511_SYNC_POLARITY_HIGH; - - if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC) - mode_vsync_polarity = ADV7511_SYNC_POLARITY_LOW; - else - mode_vsync_polarity = ADV7511_SYNC_POLARITY_HIGH; - - if (adv7511->hsync_polarity != mode_hsync_polarity && - adv7511->hsync_polarity != - ADV7511_SYNC_POLARITY_PASSTHROUGH) - hsync_polarity = 1; - - if (adv7511->vsync_polarity != mode_vsync_polarity && - adv7511->vsync_polarity != - ADV7511_SYNC_POLARITY_PASSTHROUGH) - vsync_polarity = 1; - } - - if (mode->vrefresh <= 24000) - low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ; - else if (mode->vrefresh <= 25000) - low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ; - else if (mode->vrefresh <= 30000) - low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ; - else - low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE; - - regmap_update_bits(adv7511->regmap, 0xfb, - 0x6, low_refresh_rate << 1); - regmap_update_bits(adv7511->regmap, 0x17, - 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); - - /* - * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is - * supposed to give better results. - */ - - adv7511->f_tmds = mode->clock; -} - -/* Connector funcs */ -static struct adv7511 *connector_to_adv7511(struct drm_connector *connector) -{ - return container_of(connector, struct adv7511, connector); -} - -static int adv7511_connector_get_modes(struct drm_connector *connector) -{ - struct adv7511 *adv = connector_to_adv7511(connector); - - return adv7511_get_modes(adv, connector); -} - -static enum drm_mode_status -adv7511_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct adv7511 *adv = connector_to_adv7511(connector); - - return adv7511_mode_valid(adv, mode); -} - -static struct drm_connector_helper_funcs adv7511_connector_helper_funcs = { - .get_modes = adv7511_connector_get_modes, - .mode_valid = adv7511_connector_mode_valid, -}; - -static enum drm_connector_status -adv7511_connector_detect(struct drm_connector *connector, bool force) -{ - struct adv7511 *adv = connector_to_adv7511(connector); - - return adv7511_detect(adv, connector); -} - -static struct drm_connector_funcs adv7511_connector_funcs = { - .dpms = drm_atomic_helper_connector_dpms, - .fill_modes = drm_helper_probe_single_connector_modes, - .detect = adv7511_connector_detect, - .destroy = drm_connector_cleanup, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -/* Bridge funcs */ -static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge) -{ - return container_of(bridge, struct adv7511, bridge); -} - -static void adv7511_bridge_enable(struct drm_bridge *bridge) -{ - struct adv7511 *adv = bridge_to_adv7511(bridge); - - adv7511_power_on(adv); -} - -static void adv7511_bridge_disable(struct drm_bridge *bridge) -{ - struct adv7511 *adv = bridge_to_adv7511(bridge); - - adv7511_power_off(adv); -} - -static void adv7511_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) -{ - struct adv7511 *adv = bridge_to_adv7511(bridge); - - adv7511_mode_set(adv, mode, adj_mode); -} - -static int adv7511_bridge_attach(struct drm_bridge *bridge) -{ - struct adv7511 *adv = bridge_to_adv7511(bridge); - int ret; - - if (!bridge->encoder) { - DRM_ERROR("Parent encoder object not found"); - return -ENODEV; - } - - adv->connector.polled = DRM_CONNECTOR_POLL_HPD; - - ret = drm_connector_init(bridge->dev, &adv->connector, - &adv7511_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); - if (ret) { - DRM_ERROR("Failed to initialize connector with drm\n"); - return ret; - } - drm_connector_helper_add(&adv->connector, - &adv7511_connector_helper_funcs); - drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder); - - return ret; -} - -static struct drm_bridge_funcs adv7511_bridge_funcs = { - .enable = adv7511_bridge_enable, - .disable = adv7511_bridge_disable, - .mode_set = adv7511_bridge_mode_set, - .attach = adv7511_bridge_attach, -}; - -/* ----------------------------------------------------------------------------- - * Probe & remove - */ - -static int adv7511_parse_dt(struct device_node *np, - struct adv7511_link_config *config) -{ - const char *str; - int ret; - - memset(config, 0, sizeof(*config)); - - of_property_read_u32(np, "adi,input-depth", &config->input_color_depth); - if (config->input_color_depth != 8 && config->input_color_depth != 10 && - config->input_color_depth != 12) - return -EINVAL; - - ret = of_property_read_string(np, "adi,input-colorspace", &str); - if (ret < 0) - return ret; - - if (!strcmp(str, "rgb")) - config->input_colorspace = HDMI_COLORSPACE_RGB; - else if (!strcmp(str, "yuv422")) - config->input_colorspace = HDMI_COLORSPACE_YUV422; - else if (!strcmp(str, "yuv444")) - config->input_colorspace = HDMI_COLORSPACE_YUV444; - else - return -EINVAL; - - ret = of_property_read_string(np, "adi,input-clock", &str); - if (ret < 0) - return ret; - - if (!strcmp(str, "1x")) - config->input_clock = ADV7511_INPUT_CLOCK_1X; - else if (!strcmp(str, "2x")) - config->input_clock = ADV7511_INPUT_CLOCK_2X; - else if (!strcmp(str, "ddr")) - config->input_clock = ADV7511_INPUT_CLOCK_DDR; - else - return -EINVAL; - - if (config->input_colorspace == HDMI_COLORSPACE_YUV422 || - config->input_clock != ADV7511_INPUT_CLOCK_1X) { - ret = of_property_read_u32(np, "adi,input-style", - &config->input_style); - if (ret) - return ret; - - if (config->input_style < 1 || config->input_style > 3) - return -EINVAL; - - ret = of_property_read_string(np, "adi,input-justification", - &str); - if (ret < 0) - return ret; - - if (!strcmp(str, "left")) - config->input_justification = - ADV7511_INPUT_JUSTIFICATION_LEFT; - else if (!strcmp(str, "evenly")) - config->input_justification = - ADV7511_INPUT_JUSTIFICATION_EVENLY; - else if (!strcmp(str, "right")) - config->input_justification = - ADV7511_INPUT_JUSTIFICATION_RIGHT; - else - return -EINVAL; - - } else { - config->input_style = 1; - config->input_justification = ADV7511_INPUT_JUSTIFICATION_LEFT; - } - - of_property_read_u32(np, "adi,clock-delay", &config->clock_delay); - if (config->clock_delay < -1200 || config->clock_delay > 1600) - return -EINVAL; - - config->embedded_sync = of_property_read_bool(np, "adi,embedded-sync"); - - /* Hardcode the sync pulse configurations for now. */ - config->sync_pulse = ADV7511_INPUT_SYNC_PULSE_NONE; - config->vsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH; - config->hsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH; - - return 0; -} - -static const int edid_i2c_addr = 0x7e; -static const int packet_i2c_addr = 0x70; -static const int cec_i2c_addr = 0x78; - -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; - unsigned int val; - int ret; - - if (!dev->of_node) - return -EINVAL; - - adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL); - if (!adv7511) - return -ENOMEM; - - adv7511->powered = false; - adv7511->status = connector_status_disconnected; - - ret = adv7511_parse_dt(dev->of_node, &link_config); - if (ret) - return ret; - - /* - * The power down GPIO is optional. If present, toggle it from active to - * inactive to wake up the encoder. - */ - adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH); - if (IS_ERR(adv7511->gpio_pd)) - return PTR_ERR(adv7511->gpio_pd); - - if (adv7511->gpio_pd) { - mdelay(5); - gpiod_set_value_cansleep(adv7511->gpio_pd, 0); - } - - adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config); - if (IS_ERR(adv7511->regmap)) - return PTR_ERR(adv7511->regmap); - - ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val); - if (ret) - return ret; - dev_dbg(dev, "Rev. %d\n", val); - - ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers, - ARRAY_SIZE(adv7511_fixed_registers)); - if (ret) - return ret; - - regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr); - regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR, - packet_i2c_addr); - regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr); - adv7511_packet_disable(adv7511, 0xffff); - - adv7511->i2c_main = i2c; - adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1); - if (!adv7511->i2c_edid) - return -ENOMEM; - - if (i2c->irq) { - init_waitqueue_head(&adv7511->wq); - - ret = devm_request_threaded_irq(dev, i2c->irq, NULL, - adv7511_irq_handler, - IRQF_ONESHOT, dev_name(dev), - adv7511); - if (ret) - goto err_i2c_unregister_device; - } - - /* CEC is unused for now */ - regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, - ADV7511_CEC_CTRL_POWER_DOWN); - - adv7511_power_off(adv7511); - - i2c_set_clientdata(i2c, adv7511); - - adv7511_set_link_config(adv7511, &link_config); - - adv7511->bridge.funcs = &adv7511_bridge_funcs; - adv7511->bridge.of_node = dev->of_node; - - ret = drm_bridge_add(&adv7511->bridge); - if (ret) { - dev_err(dev, "failed to add adv7511 bridge\n"); - goto err_i2c_unregister_device; - } - - return 0; - -err_i2c_unregister_device: - i2c_unregister_device(adv7511->i2c_edid); - - return ret; -} - -static int adv7511_remove(struct i2c_client *i2c) -{ - struct adv7511 *adv7511 = i2c_get_clientdata(i2c); - - drm_bridge_remove(&adv7511->bridge); - - i2c_unregister_device(adv7511->i2c_edid); - - kfree(adv7511->edid); - - return 0; -} - -static const struct i2c_device_id adv7511_i2c_ids[] = { - { "adv7511", 0 }, - { "adv7511w", 0 }, - { "adv7513", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids); - -static const struct of_device_id adv7511_of_ids[] = { - { .compatible = "adi,adv7511", }, - { .compatible = "adi,adv7511w", }, - { .compatible = "adi,adv7513", }, - { } -}; -MODULE_DEVICE_TABLE(of, adv7511_of_ids); - -static struct i2c_driver adv7511_driver = { - .driver = { - .name = "adv7511", - .of_match_table = adv7511_of_ids, - }, - .id_table = adv7511_i2c_ids, - .probe = adv7511_probe, - .remove = adv7511_remove, -}; - -module_i2c_driver(adv7511_driver); - -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h deleted file mode 100644 index 38515b30cedf..000000000000 --- a/drivers/gpu/drm/i2c/adv7511.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Analog Devices ADV7511 HDMI transmitter driver - * - * Copyright 2012 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#ifndef __DRM_I2C_ADV7511_H__ -#define __DRM_I2C_ADV7511_H__ - -#include - -#define ADV7511_REG_CHIP_REVISION 0x00 -#define ADV7511_REG_N0 0x01 -#define ADV7511_REG_N1 0x02 -#define ADV7511_REG_N2 0x03 -#define ADV7511_REG_SPDIF_FREQ 0x04 -#define ADV7511_REG_CTS_AUTOMATIC1 0x05 -#define ADV7511_REG_CTS_AUTOMATIC2 0x06 -#define ADV7511_REG_CTS_MANUAL0 0x07 -#define ADV7511_REG_CTS_MANUAL1 0x08 -#define ADV7511_REG_CTS_MANUAL2 0x09 -#define ADV7511_REG_AUDIO_SOURCE 0x0a -#define ADV7511_REG_AUDIO_CONFIG 0x0b -#define ADV7511_REG_I2S_CONFIG 0x0c -#define ADV7511_REG_I2S_WIDTH 0x0d -#define ADV7511_REG_AUDIO_SUB_SRC0 0x0e -#define ADV7511_REG_AUDIO_SUB_SRC1 0x0f -#define ADV7511_REG_AUDIO_SUB_SRC2 0x10 -#define ADV7511_REG_AUDIO_SUB_SRC3 0x11 -#define ADV7511_REG_AUDIO_CFG1 0x12 -#define ADV7511_REG_AUDIO_CFG2 0x13 -#define ADV7511_REG_AUDIO_CFG3 0x14 -#define ADV7511_REG_I2C_FREQ_ID_CFG 0x15 -#define ADV7511_REG_VIDEO_INPUT_CFG1 0x16 -#define ADV7511_REG_CSC_UPPER(x) (0x18 + (x) * 2) -#define ADV7511_REG_CSC_LOWER(x) (0x19 + (x) * 2) -#define ADV7511_REG_SYNC_DECODER(x) (0x30 + (x)) -#define ADV7511_REG_DE_GENERATOR (0x35 + (x)) -#define ADV7511_REG_PIXEL_REPETITION 0x3b -#define ADV7511_REG_VIC_MANUAL 0x3c -#define ADV7511_REG_VIC_SEND 0x3d -#define ADV7511_REG_VIC_DETECTED 0x3e -#define ADV7511_REG_AUX_VIC_DETECTED 0x3f -#define ADV7511_REG_PACKET_ENABLE0 0x40 -#define ADV7511_REG_POWER 0x41 -#define ADV7511_REG_STATUS 0x42 -#define ADV7511_REG_EDID_I2C_ADDR 0x43 -#define ADV7511_REG_PACKET_ENABLE1 0x44 -#define ADV7511_REG_PACKET_I2C_ADDR 0x45 -#define ADV7511_REG_DSD_ENABLE 0x46 -#define ADV7511_REG_VIDEO_INPUT_CFG2 0x48 -#define ADV7511_REG_INFOFRAME_UPDATE 0x4a -#define ADV7511_REG_GC(x) (0x4b + (x)) /* 0x4b - 0x51 */ -#define ADV7511_REG_AVI_INFOFRAME_VERSION 0x52 -#define ADV7511_REG_AVI_INFOFRAME_LENGTH 0x53 -#define ADV7511_REG_AVI_INFOFRAME_CHECKSUM 0x54 -#define ADV7511_REG_AVI_INFOFRAME(x) (0x55 + (x)) /* 0x55 - 0x6f */ -#define ADV7511_REG_AUDIO_INFOFRAME_VERSION 0x70 -#define ADV7511_REG_AUDIO_INFOFRAME_LENGTH 0x71 -#define ADV7511_REG_AUDIO_INFOFRAME_CHECKSUM 0x72 -#define ADV7511_REG_AUDIO_INFOFRAME(x) (0x73 + (x)) /* 0x73 - 0x7c */ -#define ADV7511_REG_INT_ENABLE(x) (0x94 + (x)) -#define ADV7511_REG_INT(x) (0x96 + (x)) -#define ADV7511_REG_INPUT_CLK_DIV 0x9d -#define ADV7511_REG_PLL_STATUS 0x9e -#define ADV7511_REG_HDMI_POWER 0xa1 -#define ADV7511_REG_HDCP_HDMI_CFG 0xaf -#define ADV7511_REG_AN(x) (0xb0 + (x)) /* 0xb0 - 0xb7 */ -#define ADV7511_REG_HDCP_STATUS 0xb8 -#define ADV7511_REG_BCAPS 0xbe -#define ADV7511_REG_BKSV(x) (0xc0 + (x)) /* 0xc0 - 0xc3 */ -#define ADV7511_REG_EDID_SEGMENT 0xc4 -#define ADV7511_REG_DDC_STATUS 0xc8 -#define ADV7511_REG_EDID_READ_CTRL 0xc9 -#define ADV7511_REG_BSTATUS(x) (0xca + (x)) /* 0xca - 0xcb */ -#define ADV7511_REG_TIMING_GEN_SEQ 0xd0 -#define ADV7511_REG_POWER2 0xd6 -#define ADV7511_REG_HSYNC_PLACEMENT_MSB 0xfa - -#define ADV7511_REG_SYNC_ADJUSTMENT(x) (0xd7 + (x)) /* 0xd7 - 0xdc */ -#define ADV7511_REG_TMDS_CLOCK_INV 0xde -#define ADV7511_REG_ARC_CTRL 0xdf -#define ADV7511_REG_CEC_I2C_ADDR 0xe1 -#define ADV7511_REG_CEC_CTRL 0xe2 -#define ADV7511_REG_CHIP_ID_HIGH 0xf5 -#define ADV7511_REG_CHIP_ID_LOW 0xf6 - -#define ADV7511_CSC_ENABLE BIT(7) -#define ADV7511_CSC_UPDATE_MODE BIT(5) - -#define ADV7511_INT0_HPD BIT(7) -#define ADV7511_INT0_VSYNC BIT(5) -#define ADV7511_INT0_AUDIO_FIFO_FULL BIT(4) -#define ADV7511_INT0_EDID_READY BIT(2) -#define ADV7511_INT0_HDCP_AUTHENTICATED BIT(1) - -#define ADV7511_INT1_DDC_ERROR BIT(7) -#define ADV7511_INT1_BKSV BIT(6) -#define ADV7511_INT1_CEC_TX_READY BIT(5) -#define ADV7511_INT1_CEC_TX_ARBIT_LOST BIT(4) -#define ADV7511_INT1_CEC_TX_RETRY_TIMEOUT BIT(3) -#define ADV7511_INT1_CEC_RX_READY3 BIT(2) -#define ADV7511_INT1_CEC_RX_READY2 BIT(1) -#define ADV7511_INT1_CEC_RX_READY1 BIT(0) - -#define ADV7511_ARC_CTRL_POWER_DOWN BIT(0) - -#define ADV7511_CEC_CTRL_POWER_DOWN BIT(0) - -#define ADV7511_POWER_POWER_DOWN BIT(6) - -#define ADV7511_HDMI_CFG_MODE_MASK 0x2 -#define ADV7511_HDMI_CFG_MODE_DVI 0x0 -#define ADV7511_HDMI_CFG_MODE_HDMI 0x2 - -#define ADV7511_AUDIO_SELECT_I2C 0x0 -#define ADV7511_AUDIO_SELECT_SPDIF 0x1 -#define ADV7511_AUDIO_SELECT_DSD 0x2 -#define ADV7511_AUDIO_SELECT_HBR 0x3 -#define ADV7511_AUDIO_SELECT_DST 0x4 - -#define ADV7511_I2S_SAMPLE_LEN_16 0x2 -#define ADV7511_I2S_SAMPLE_LEN_20 0x3 -#define ADV7511_I2S_SAMPLE_LEN_18 0x4 -#define ADV7511_I2S_SAMPLE_LEN_22 0x5 -#define ADV7511_I2S_SAMPLE_LEN_19 0x8 -#define ADV7511_I2S_SAMPLE_LEN_23 0x9 -#define ADV7511_I2S_SAMPLE_LEN_24 0xb -#define ADV7511_I2S_SAMPLE_LEN_17 0xc -#define ADV7511_I2S_SAMPLE_LEN_21 0xd - -#define ADV7511_SAMPLE_FREQ_44100 0x0 -#define ADV7511_SAMPLE_FREQ_48000 0x2 -#define ADV7511_SAMPLE_FREQ_32000 0x3 -#define ADV7511_SAMPLE_FREQ_88200 0x8 -#define ADV7511_SAMPLE_FREQ_96000 0xa -#define ADV7511_SAMPLE_FREQ_176400 0xc -#define ADV7511_SAMPLE_FREQ_192000 0xe - -#define ADV7511_STATUS_POWER_DOWN_POLARITY BIT(7) -#define ADV7511_STATUS_HPD BIT(6) -#define ADV7511_STATUS_MONITOR_SENSE BIT(5) -#define ADV7511_STATUS_I2S_32BIT_MODE BIT(3) - -#define ADV7511_PACKET_ENABLE_N_CTS BIT(8+6) -#define ADV7511_PACKET_ENABLE_AUDIO_SAMPLE BIT(8+5) -#define ADV7511_PACKET_ENABLE_AVI_INFOFRAME BIT(8+4) -#define ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME BIT(8+3) -#define ADV7511_PACKET_ENABLE_GC BIT(7) -#define ADV7511_PACKET_ENABLE_SPD BIT(6) -#define ADV7511_PACKET_ENABLE_MPEG BIT(5) -#define ADV7511_PACKET_ENABLE_ACP BIT(4) -#define ADV7511_PACKET_ENABLE_ISRC BIT(3) -#define ADV7511_PACKET_ENABLE_GM BIT(2) -#define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) -#define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) - -#define ADV7511_REG_POWER2_HPD_SRC_MASK 0xc0 -#define ADV7511_REG_POWER2_HPD_SRC_BOTH 0x00 -#define ADV7511_REG_POWER2_HPD_SRC_HPD 0x40 -#define ADV7511_REG_POWER2_HPD_SRC_CEC 0x80 -#define ADV7511_REG_POWER2_HPD_SRC_NONE 0xc0 -#define ADV7511_REG_POWER2_TDMS_ENABLE BIT(4) -#define ADV7511_REG_POWER2_GATE_INPUT_CLK BIT(0) - -#define ADV7511_LOW_REFRESH_RATE_NONE 0x0 -#define ADV7511_LOW_REFRESH_RATE_24HZ 0x1 -#define ADV7511_LOW_REFRESH_RATE_25HZ 0x2 -#define ADV7511_LOW_REFRESH_RATE_30HZ 0x3 - -#define ADV7511_AUDIO_CFG3_LEN_MASK 0x0f -#define ADV7511_I2C_FREQ_ID_CFG_RATE_MASK 0xf0 - -#define ADV7511_AUDIO_SOURCE_I2S 0 -#define ADV7511_AUDIO_SOURCE_SPDIF 1 - -#define ADV7511_I2S_FORMAT_I2S 0 -#define ADV7511_I2S_FORMAT_RIGHT_J 1 -#define ADV7511_I2S_FORMAT_LEFT_J 2 - -#define ADV7511_PACKET(p, x) ((p) * 0x20 + (x)) -#define ADV7511_PACKET_SDP(x) ADV7511_PACKET(0, x) -#define ADV7511_PACKET_MPEG(x) ADV7511_PACKET(1, x) -#define ADV7511_PACKET_ACP(x) ADV7511_PACKET(2, x) -#define ADV7511_PACKET_ISRC1(x) ADV7511_PACKET(3, x) -#define ADV7511_PACKET_ISRC2(x) ADV7511_PACKET(4, x) -#define ADV7511_PACKET_GM(x) ADV7511_PACKET(5, x) -#define ADV7511_PACKET_SPARE(x) ADV7511_PACKET(6, x) - -enum adv7511_input_clock { - ADV7511_INPUT_CLOCK_1X, - ADV7511_INPUT_CLOCK_2X, - ADV7511_INPUT_CLOCK_DDR, -}; - -enum adv7511_input_justification { - ADV7511_INPUT_JUSTIFICATION_EVENLY = 0, - ADV7511_INPUT_JUSTIFICATION_RIGHT = 1, - ADV7511_INPUT_JUSTIFICATION_LEFT = 2, -}; - -enum adv7511_input_sync_pulse { - ADV7511_INPUT_SYNC_PULSE_DE = 0, - ADV7511_INPUT_SYNC_PULSE_HSYNC = 1, - ADV7511_INPUT_SYNC_PULSE_VSYNC = 2, - ADV7511_INPUT_SYNC_PULSE_NONE = 3, -}; - -/** - * enum adv7511_sync_polarity - Polarity for the input sync signals - * @ADV7511_SYNC_POLARITY_PASSTHROUGH: Sync polarity matches that of - * the currently configured mode. - * @ADV7511_SYNC_POLARITY_LOW: Sync polarity is low - * @ADV7511_SYNC_POLARITY_HIGH: Sync polarity is high - * - * If the polarity is set to either LOW or HIGH the driver will configure the - * ADV7511 to internally invert the sync signal if required to match the sync - * polarity setting for the currently selected output mode. - * - * If the polarity is set to PASSTHROUGH, the ADV7511 will route the signal - * unchanged. This is used when the upstream graphics core already generates - * the sync signals with the correct polarity. - */ -enum adv7511_sync_polarity { - ADV7511_SYNC_POLARITY_PASSTHROUGH, - ADV7511_SYNC_POLARITY_LOW, - ADV7511_SYNC_POLARITY_HIGH, -}; - -/** - * struct adv7511_link_config - Describes adv7511 hardware configuration - * @input_color_depth: Number of bits per color component (8, 10 or 12) - * @input_colorspace: The input colorspace (RGB, YUV444, YUV422) - * @input_clock: The input video clock style (1x, 2x, DDR) - * @input_style: The input component arrangement variant - * @input_justification: Video input format bit justification - * @clock_delay: Clock delay for the input clock (in ps) - * @embedded_sync: Video input uses BT.656-style embedded sync - * @sync_pulse: Select the sync pulse - * @vsync_polarity: vsync input signal configuration - * @hsync_polarity: hsync input signal configuration - */ -struct adv7511_link_config { - unsigned int input_color_depth; - enum hdmi_colorspace input_colorspace; - enum adv7511_input_clock input_clock; - unsigned int input_style; - enum adv7511_input_justification input_justification; - - int clock_delay; - - bool embedded_sync; - enum adv7511_input_sync_pulse sync_pulse; - enum adv7511_sync_polarity vsync_polarity; - enum adv7511_sync_polarity hsync_polarity; -}; - -/** - * enum adv7511_csc_scaling - Scaling factor for the ADV7511 CSC - * @ADV7511_CSC_SCALING_1: CSC results are not scaled - * @ADV7511_CSC_SCALING_2: CSC results are scaled by a factor of two - * @ADV7511_CSC_SCALING_4: CSC results are scalled by a factor of four - */ -enum adv7511_csc_scaling { - ADV7511_CSC_SCALING_1 = 0, - ADV7511_CSC_SCALING_2 = 1, - ADV7511_CSC_SCALING_4 = 2, -}; - -/** - * struct adv7511_video_config - Describes adv7511 hardware configuration - * @csc_enable: Whether to enable color space conversion - * @csc_scaling_factor: Color space conversion scaling factor - * @csc_coefficents: Color space conversion coefficents - * @hdmi_mode: Whether to use HDMI or DVI output mode - * @avi_infoframe: HDMI infoframe - */ -struct adv7511_video_config { - bool csc_enable; - enum adv7511_csc_scaling csc_scaling_factor; - const uint16_t *csc_coefficents; - - bool hdmi_mode; - struct hdmi_avi_infoframe avi_infoframe; -}; - -#endif /* __DRM_I2C_ADV7511_H__ */ -- cgit v1.2.3 From 90731c24d2db7ec04df43ddbcee9605183d05187 Mon Sep 17 00:00:00 2001 From: Brian Starkey Date: Mon, 24 Oct 2016 15:27:59 +0100 Subject: drm/i2c: tda998x: mali-dp: hdlcd: refactor connector registration Connectors shouldn't be registered until the rest of the whole device is set up, so that consistent state is presented to userspace. As such, remove the calls to drm_connector_register() and drm_connector_unregister() from tda998x, as these are now handled by drm_dev_(un)register() itself. To work with this change, the mali-dp and hdlcd bind and unbind sequences have to be reordered, to ensure that the componentised encoder/connector is bound before drm_dev_register() registers all connectors. Similarly, the device must be unregistered before the component is unbound. Altogether, this allows other drivers using tda998x to be de-midlayered, and to have less racy initialisation of their components. Splitting this commit into three (one per driver) isn't possible without intermediate breakage, so it is all squashed together here. Suggested-by: Russell King Signed-off-by: Brian Starkey Reviewed-by: Liviu Dudau Signed-off-by: Russell King --- drivers/gpu/drm/i2c/tda998x_drv.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/gpu/drm/i2c') diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index f4315bc8d471..6e6fca20ba8b 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1369,7 +1369,6 @@ const struct drm_connector_helper_funcs tda998x_connector_helper_funcs = { static void tda998x_connector_destroy(struct drm_connector *connector) { - drm_connector_unregister(connector); drm_connector_cleanup(connector); } @@ -1441,16 +1440,10 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data) if (ret) goto err_connector; - ret = drm_connector_register(&priv->connector); - if (ret) - goto err_sysfs; - drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder); return 0; -err_sysfs: - drm_connector_cleanup(&priv->connector); err_connector: drm_encoder_cleanup(&priv->encoder); err_encoder: @@ -1463,7 +1456,6 @@ static void tda998x_unbind(struct device *dev, struct device *master, { struct tda998x_priv *priv = dev_get_drvdata(dev); - drm_connector_unregister(&priv->connector); drm_connector_cleanup(&priv->connector); drm_encoder_cleanup(&priv->encoder); tda998x_destroy(priv); -- cgit v1.2.3