From 2524444b23c4fca75ed5ec553317776462b64684 Mon Sep 17 00:00:00 2001 From: Xinliang Liu Date: Sun, 15 Feb 2015 21:08:19 +0800 Subject: [PATCH 1/7] gpu/drm: hisilicon: Add hdmi ADV7533 i2c support Signed-off-by: Xinliang Liu --- arch/arm64/boot/dts/hi6220.dtsi | 37 +- arch/arm64/configs/defconfig | 2 +- drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 4 +- drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 24 +- drivers/gpu/drm/i2c/Kconfig | 6 + drivers/gpu/drm/i2c/Makefile | 2 + drivers/gpu/drm/i2c/adv7533.c | 756 +++++++++++++++++++++++ drivers/gpu/drm/i2c/adv7533.h | 223 +++++++ 8 files changed, 1007 insertions(+), 47 deletions(-) create mode 100644 drivers/gpu/drm/i2c/adv7533.c create mode 100644 drivers/gpu/drm/i2c/adv7533.h diff --git a/arch/arm64/boot/dts/hi6220.dtsi b/arch/arm64/boot/dts/hi6220.dtsi index 9cad6be8ee2609..d63af17ca33f12 100644 --- a/arch/arm64/boot/dts/hi6220.dtsi +++ b/arch/arm64/boot/dts/hi6220.dtsi @@ -675,45 +675,15 @@ pinctrl-1 = <&I2C2_SCL_pmx_idle &I2C2_SDA_pmx_idle &I2C2_SCL_cfg_idle &I2C2_SDA_cfg_idle>; status = "ok"; - /* adv7533: adv7533@39 { - compatible = "adi,adv7511"; + compatible = "adi,adv7533"; reg = <0x39>; interrupt-parent = <&gpio1>; interrupts = <1 2>; - - gpio_pd = <&gpio0 4 0>; + pd-gpio = <&gpio0 4 0>; adi,input-depth = <8>; adi,input-colorspace = "rgb"; - adi,input-clock = "1x"; - adi,input-style = <1>; - adi,input-justification = "evenly"; - }; - */ - - packet: adv7533@70 { - compatible = "adv7533,packet"; - reg = <0x38>; - }; - main: adv7533@7a { - compatible = "adv7533,main"; - reg = <0x39>; - has-regulator; - hdmi_vdd-supply = <&ldo15>; - hdmi_v1p2-supply = <&ldo22>; - gpio_int = <&gpio1 1 0>; - gpio_pd = <&gpio0 4 0>; - gpio_dsi_sel = <&gpio0 1 0>; }; - cec_dsi: adv7533@78 { - compatible = "adv7533,cec_dsi"; - reg = <0x3c>; - }; - edid: adv7533@7e { - compatible = "adv7533,edid"; - reg = <0x3f>; - }; - }; display-subsystem { @@ -754,8 +724,7 @@ clock-names = "pclk_dsi"; dsi_bit_clk_rate = <640>; vc = <0>; - //encoder-slave = <&adv7533>; - + encoder-slave = <&adv7533>; }; }; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 300405d5761821..18f16d74cc19d8 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -263,9 +263,9 @@ CONFIG_REGULATOR_HI6220=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_ANALOG_TV_SUPPORT=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set -CONFIG_VIDEO_ADV7533=y CONFIG_DRM=y CONFIG_DRM_HISI=y +CONFIG_DRM_I2C_ADV7533=y CONFIG_FB_ARMCLCD=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c index 987c5302a9a1c1..582bd5eaad008c 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c @@ -97,8 +97,8 @@ static int hisi_drm_load(struct drm_device *drm_dev, unsigned long flags) int ret; struct hisi_drm_private *private; - /* debug setting - drm_debug = DRM_UT_DRIVER|DRM_UT_KMS|DRM_UT_CORE|DRM_UT_PRIME; */ + /* debug setting */ + drm_debug = DRM_UT_DRIVER|DRM_UT_KMS|DRM_UT_CORE|DRM_UT_PRIME; DRM_DEBUG_DRIVER("enter.\n"); private = kzalloc(sizeof(struct hisi_drm_private), GFP_KERNEL); diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c index 1bf2b38f6864e0..71ecf9531db099 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c @@ -571,7 +571,7 @@ int mipi_init(struct hisi_dsi *dsi) * Hline_time = (HSA+HBP+HACT+HFP)*(PCLK period/Clk Lane Byte Period); */ - pixel_clk = dsi->vm.pixelclock / 1000; + pixel_clk = dsi->vm.pixelclock; hsa_time = dsi->vm.hsync_len * phy_register.lane_byte_clk / pixel_clk; hbp_time = dsi->vm.hback_porch * phy_register.lane_byte_clk / pixel_clk; hline_time = (dsi->vm.hsync_len + dsi->vm.hback_porch + @@ -581,6 +581,8 @@ int mipi_init(struct hisi_dsi *dsi) set_MIPIDSI_VID_HBP_TIME(hbp_time); set_MIPIDSI_VID_HLINE_TIME(hline_time); + DRM_INFO("%s,pixcel_clk=%d,dphy_freq=%d,hsa=%d,hbp=%d,hline=%d", __func__, + pixel_clk, dsi->dphy_freq, hsa_time, hbp_time, hline_time); /* * 5. Define the Vertical line configuration: * @@ -750,7 +752,7 @@ static void hisi_drm_encoder_mode_set(struct drm_encoder *encoder, struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder); DRM_DEBUG_DRIVER("enter.\n"); - vm->pixelclock = mode->clock; + vm->pixelclock = mode->clock/1000; vm->hactive = mode->hdisplay; vm->vactive = mode->vdisplay; vm->vfront_porch = mode->vsync_start - mode->vdisplay; @@ -760,6 +762,9 @@ static void hisi_drm_encoder_mode_set(struct drm_encoder *encoder, vm->hback_porch = mode->htotal - mode->hsync_end; vm->hsync_len = mode->hsync_end - mode->hsync_start; + /* laneBitRate >= pixelClk*24/lanes */ + dsi->dphy_freq = vm->pixelclock*24/dsi->lanes; /* + 30; */ + vm->flags = 0; if (mode->flags & DRM_MODE_FLAG_PHSYNC) vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH; @@ -816,7 +821,7 @@ hisi_dsi_detect(struct drm_connector *connector, bool force) status = sfuncs->detect(encoder, connector); DRM_DEBUG_DRIVER("exit success. status=%d\n", status); - return connector_status_connected; + return status; } static void hisi_dsi_connector_destroy(struct drm_connector *connector) @@ -866,13 +871,16 @@ static int hisi_dsi_get_modes(struct drm_connector *connector) struct drm_encoder *encoder = &dsi->base.base; struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder); int count = 0; - +#if 1 DRM_DEBUG_DRIVER("enter.\n"); if (sfuncs && sfuncs->get_modes) count = sfuncs->get_modes(encoder, connector); DRM_DEBUG_DRIVER("exit success. count=%d\n", count); + return count; +#else return hisi_get_default_modes(connector); +#endif } static struct drm_encoder * @@ -912,6 +920,7 @@ static int hisi_drm_encoder_create(struct drm_device *dev, struct hisi_dsi *dsi) { /* int ret; */ struct drm_encoder *encoder = &dsi->base.base; + int ret; DRM_DEBUG_DRIVER("enter.\n"); dsi->dpms = DRM_MODE_DPMS_OFF; @@ -919,7 +928,6 @@ static int hisi_drm_encoder_create(struct drm_device *dev, struct hisi_dsi *dsi) drm_encoder_init(dev, encoder, &hisi_encoder_funcs, DRM_MODE_ENCODER_DSI); drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs); -#if 0 ret = dsi->drm_i2c_driver->encoder_init(dsi->client, dev, &dsi->base); if (ret) { DRM_ERROR("drm_i2c_encoder_init error\n"); @@ -930,7 +938,7 @@ static int hisi_drm_encoder_create(struct drm_device *dev, struct hisi_dsi *dsi) DRM_ERROR("failed check encoder function\n"); return -ENODEV; } -#endif + return 0; DRM_DEBUG_DRIVER("exit success.\n"); } @@ -957,10 +965,8 @@ static int hisi_dsi_probe(struct platform_device *pdev) struct hisi_dsi *dsi; struct resource *res; struct drm_device *dev = dev_get_platdata(&pdev->dev); -#if 0 struct device_node *slave_node; struct device_node *np = pdev->dev.of_node; -#endif DRM_DEBUG_DRIVER("enter.\n"); @@ -992,7 +998,6 @@ static int hisi_dsi_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "failed to get vc"); -#if 0 slave_node = of_parse_phandle(np, "encoder-slave", 0); if (!slave_node) { DRM_ERROR("failed to get slave encoder node\n"); @@ -1012,7 +1017,6 @@ static int hisi_dsi_probe(struct platform_device *pdev) DRM_ERROR("failed initialize encoder driver\n"); return -EPROBE_DEFER; } -#endif dsi->color_mode = DSI_24BITS_1; dsi->date_enable_pol = 0; diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 4d341db462a244..899796d21f4b3b 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -1,6 +1,12 @@ menu "I2C encoder or helper chips" depends on DRM && DRM_KMS_HELPER && I2C +config DRM_I2C_ADV7533 + tristate "ADV7533 encoder" + select REGMAP_I2C + help + Support for the Analog Device ADV7533 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 43aa33baebed8e..f6002059f8b9b2 100644 --- a/drivers/gpu/drm/i2c/Makefile +++ b/drivers/gpu/drm/i2c/Makefile @@ -1,5 +1,7 @@ ccflags-y := -Iinclude/drm +obj-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o + ch7006-y := ch7006_drv.o ch7006_mode.o obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c new file mode 100644 index 00000000000000..955aa3fbbdf6e6 --- /dev/null +++ b/drivers/gpu/drm/i2c/adv7533.c @@ -0,0 +1,756 @@ +/* + * Analog Devices ADV7533 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "adv7533.h" + +struct adv7533 { + struct i2c_client *i2c_main; + struct i2c_client *i2c_edid; + struct i2c_client *i2c_cec; + + struct regmap *regmap_main; + struct regmap *regmap_dsi; + enum drm_connector_status status; + int dpms_mode; + + unsigned int f_tmds; + + unsigned int current_edid_segment; + uint8_t edid_buf[256]; + + wait_queue_head_t wq; + struct drm_encoder *encoder; + + bool embedded_sync; + bool rgb; + + struct edid *edid; + + struct gpio_desc *gpio_pd; + +}; + +/* ADI recommended values for proper operation. */ +static const struct reg_default adv7533_fixed_registers[] = { + { 0x16, 0x20 }, + { 0x9a, 0xe0 }, + { 0xba, 0x70 }, + { 0xde, 0x82 }, + { 0xe4, 0x40 }, + { 0xe5, 0x80 }, +}; + +static const struct reg_default adv7533_cec_fixed_registers[] = { + { 0x15, 0x10 }, + { 0x17, 0xd0 }, + { 0x24, 0x20 }, + { 0x57, 0x11 }, +}; + +static const struct regmap_config adv7533_main_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, +#if 0 + .reg_defaults_raw = adv7533_register_defaults, + .num_reg_defaults_raw = ARRAY_SIZE(adv7533_register_defaults), + + .volatile_reg = adv7533_register_volatile, +#endif +}; + +static const struct regmap_config adv7533_cec_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, +}; + + +static struct adv7533 *encoder_to_adv7533(struct drm_encoder *encoder) +{ + return to_encoder_slave(encoder)->slave_priv; +} + +static const int edid_i2c_addr = 0x7e; +static const int packet_i2c_addr = 0x70; +static const int cec_i2c_addr = 0x78; + +static const struct of_device_id adv7533_of_ids[] = { + { .compatible = "adi,adv7533"}, + { } +}; +MODULE_DEVICE_TABLE(of, adv7533_of_ids); + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ + +static void adv7533_set_colormap(struct adv7533 *adv7533, bool enable, + const uint16_t *coeff, + unsigned int scaling_factor) +{ + unsigned int i; + + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_CSC_UPPER(1), + ADV7533_CSC_UPDATE_MODE, ADV7533_CSC_UPDATE_MODE); + + if (enable) { + for (i = 0; i < 12; ++i) { + regmap_update_bits(adv7533->regmap_main, + ADV7533_REG_CSC_UPPER(i), + 0x1f, coeff[i] >> 8); + regmap_write(adv7533->regmap_main, + ADV7533_REG_CSC_LOWER(i), + coeff[i] & 0xff); + } + } + + if (enable) + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_CSC_UPPER(0), + 0xe0, 0x80 | (scaling_factor << 5)); + else + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_CSC_UPPER(0), + 0x80, 0x00); + + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_CSC_UPPER(1), + ADV7533_CSC_UPDATE_MODE, 0); +} + +static int adv7533_packet_enable(struct adv7533 *adv7533, unsigned int packet) +{ + if (packet & 0xff) + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_PACKET_ENABLE0, + packet, 0xff); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_PACKET_ENABLE1, + packet, 0xff); + } + + return 0; +} + +static int adv7533_packet_disable(struct adv7533 *adv7533, unsigned int packet) +{ + if (packet & 0xff) + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_PACKET_ENABLE0, + packet, 0x00); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_PACKET_ENABLE1, + packet, 0x00); + } + + return 0; +} + +/* Coefficients for adv7533 color space conversion */ +static const uint16_t adv7533_csc_ycbcr_to_rgb[] = { + 0x0734, 0x04ad, 0x0000, 0x1c1b, + 0x1ddc, 0x04ad, 0x1f24, 0x0135, + 0x0000, 0x04ad, 0x087c, 0x1b77, +}; + +static void adv7533_set_config_csc(struct adv7533 *adv7533, + struct drm_connector *connector, + bool rgb) +{ + struct adv7533_video_config config; + bool output_format_422, output_format_ycbcr; + unsigned int mode; + uint8_t infoframe[17]; + + if (adv7533->edid) + config.hdmi_mode = drm_detect_hdmi_monitor(adv7533->edid); + else + config.hdmi_mode = true; /* HDMI as default */ + + 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 = ADV7533_CSC_SCALING_4; + config.csc_coefficents = adv7533_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 = ADV7533_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 = ADV7533_HDMI_CFG_MODE_DVI; + output_format_422 = false; + output_format_ycbcr = false; + } + + DRM_INFO("HDMI: mode=%d,format_422=%d,format_ycbcr=%d\n", mode, output_format_422, output_format_ycbcr); +#if 1 + adv7533_packet_disable(adv7533, ADV7533_PACKET_ENABLE_AVI_INFOFRAME); + + adv7533_set_colormap(adv7533, config.csc_enable, + config.csc_coefficents, + config.csc_scaling_factor); + + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_VIDEO_INPUT_CFG1, + 0x81, (output_format_422 << 7) | output_format_ycbcr); + + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_HDCP_HDMI_CFG, + ADV7533_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(adv7533->regmap_main, ADV7533_REG_AVI_INFOFRAME_VERSION, + infoframe + 1, sizeof(infoframe) - 1); + + adv7533_packet_enable(adv7533, ADV7533_PACKET_ENABLE_AVI_INFOFRAME); +#endif +} + + +/* ----------------------------------------------------------------------------- + * Interrupt and hotplug detection + */ + +static bool adv7533_hpd(struct adv7533 *adv7533) +{ + unsigned int irq0; + int ret; + + ret = regmap_read(adv7533->regmap_main, ADV7533_REG_INT(0), &irq0); + if (ret < 0) + return false; + + if (irq0 & ADV7533_INT0_HDP) { + regmap_write(adv7533->regmap_main, ADV7533_REG_INT(0), + ADV7533_INT0_HDP); + return true; + } + + return false; +} + +static irqreturn_t adv7533_irq_handler(int irq, void *devid) +{ + struct adv7533 *adv7533 = devid; + + if (adv7533->encoder && adv7533_hpd(adv7533)) + drm_helper_hpd_irq_event(adv7533->encoder->dev); + + wake_up_all(&adv7533->wq); + + return IRQ_HANDLED; +} + +static unsigned int adv7533_is_interrupt_pending(struct adv7533 *adv7533, + unsigned int irq) +{ + unsigned int irq0, irq1; + unsigned int pending; + int ret; + + ret = regmap_read(adv7533->regmap_main, ADV7533_REG_INT(0), &irq0); + if (ret < 0) + return 0; + ret = regmap_read(adv7533->regmap_main, ADV7533_REG_INT(1), &irq1); + if (ret < 0) + return 0; + + pending = (irq1 << 8) | irq0; + + return pending & irq; +} + +static int adv7533_wait_for_interrupt(struct adv7533 *adv7533, int irq, + int timeout) +{ + unsigned int pending; + int ret; + + if (adv7533->i2c_main->irq) { + ret = wait_event_interruptible_timeout(adv7533->wq, + adv7533_is_interrupt_pending(adv7533, irq), + msecs_to_jiffies(timeout)); + if (ret <= 0) + return 0; + pending = adv7533_is_interrupt_pending(adv7533, irq); + } else { + if (timeout < 25) + timeout = 25; + do { + pending = adv7533_is_interrupt_pending(adv7533, irq); + if (pending) + break; + msleep(25); + timeout -= 25; + } while (timeout >= 25); + } + + return pending; +} + +/* ----------------------------------------------------------------------------- + * EDID retrieval + */ + +static int adv7533_get_edid_block(void *data, u8 *buf, unsigned int block, + size_t len) +{ + struct adv7533 *adv7533 = data; + struct i2c_msg xfer[2]; + uint8_t offset; + unsigned int i; + int ret; + + if (len > 128) + return -EINVAL; + + if (adv7533->current_edid_segment != block / 2) { + unsigned int status; + + ret = regmap_read(adv7533->regmap_main, ADV7533_REG_DDC_STATUS, + &status); + if (ret < 0) + return ret; + + if (status != 2) { + regmap_write(adv7533->regmap_main, ADV7533_REG_EDID_SEGMENT, + block); + ret = adv7533_wait_for_interrupt(adv7533, + ADV7533_INT0_EDID_READY | + ADV7533_INT0_HDP, 200); + + if (!(ret & ADV7533_INT0_EDID_READY)) + return -EIO; + } + + regmap_write(adv7533->regmap_main, ADV7533_REG_INT(0), + ADV7533_INT0_EDID_READY | ADV7533_INT0_HDP); + + /* Break this apart, hopefully more I2C controllers will + * support 64 byte transfers than 256 byte transfers + */ + + xfer[0].addr = adv7533->i2c_edid->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = &offset; + xfer[1].addr = adv7533->i2c_edid->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 64; + xfer[1].buf = adv7533->edid_buf; + + offset = 0; + + for (i = 0; i < 4; ++i) { + ret = i2c_transfer(adv7533->i2c_edid->adapter, xfer, + ARRAY_SIZE(xfer)); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + + xfer[1].buf += 64; + offset += 64; + } + + adv7533->current_edid_segment = block / 2; + } + + if (block % 2 == 0) + memcpy(buf, adv7533->edid_buf, len); + else + memcpy(buf, adv7533->edid_buf + 128, len); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Encoder operations + */ + +static int adv7533_get_modes(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct adv7533 *adv7533 = encoder_to_adv7533(encoder); + struct edid *edid; + unsigned int count; + + /* Reading the EDID only works if the device is powered */ + if (adv7533->dpms_mode != DRM_MODE_DPMS_ON) { + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER2, + BIT(6), BIT(6)); + regmap_write(adv7533->regmap_main, ADV7533_REG_INT(0), + ADV7533_INT0_EDID_READY | ADV7533_INT0_HDP); + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, 0); + adv7533->current_edid_segment = -1; + } + + edid = drm_get_edid(connector, adv7533->i2c_edid->adapter); + + if (adv7533->dpms_mode != DRM_MODE_DPMS_ON) + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, + ADV7533_POWER_POWER_DOWN); + + adv7533->edid = edid; + adv7533_set_config_csc(adv7533, connector, true); /* adv7533->rgb); */ + if (!edid) + return 0; + + drm_mode_connector_update_edid_property(connector, edid); + count = drm_add_edid_modes(connector, edid); + + kfree(adv7533->edid); + adv7533->edid = NULL; + return count; +} + +static void adv7533_dsi_receiver_dpms(struct adv7533 *adv7533, int mode) +{ + switch (mode) { + case DRM_MODE_DPMS_ON: + regmap_write(adv7533->regmap_dsi, 0x03, 0x89); + regmap_write(adv7533->regmap_dsi, 0x27, 0x0b); /* Timing generator off */ + regmap_write(adv7533->regmap_dsi, 0x1C, 0x30); /* 3 lanes */ + break; + default: + regmap_write(adv7533->regmap_dsi, 0x03, 0x0b); + break; + } +} + +static void adv7533_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct adv7533 *adv7533 = encoder_to_adv7533(encoder); + + switch (mode) { + case DRM_MODE_DPMS_ON: + adv7533->current_edid_segment = -1; + + regmap_write(adv7533->regmap_main, ADV7533_REG_INT(0), + ADV7533_INT0_EDID_READY | ADV7533_INT0_HDP); + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, 0); + /* + * Per spec it is allowed to pulse the HDP signal to indicate + * that the EDID information has changed. Some monitors do this + * when they wakeup from standby or are enabled. When the HDP + * goes low the adv7533 is reset and the outputs are disabled + * which might cause the monitor to go to standby again. To + * avoid this we ignore the HDP pin for the first few seconds + * after enabeling the output. + */ + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER2, + BIT(6), BIT(6)); + /* Most of the registers are reset during power down or + * when HPD is low + */ + regcache_sync(adv7533->regmap_main); + break; + default: + /* TODO: setup additional power down modes */ + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, + ADV7533_POWER_POWER_DOWN); + regcache_mark_dirty(adv7533->regmap_main); + break; + } + + /* dsi receiver dpms */ + adv7533_dsi_receiver_dpms(adv7533, mode); + adv7533->dpms_mode = mode; +} + +static enum drm_connector_status +adv7533_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct adv7533 *adv7533 = encoder_to_adv7533(encoder); + enum drm_connector_status status; + unsigned int val; + bool hpd; + int ret; + + ret = regmap_read(adv7533->regmap_main, ADV7533_REG_STATUS, &val); + if (ret < 0) + return connector_status_disconnected; + + if (val & ADV7533_STATUS_HPD) + status = connector_status_connected; + else + status = connector_status_disconnected; + + hpd = adv7533_hpd(adv7533); + + /* 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 && + adv7533->dpms_mode == DRM_MODE_DPMS_ON) { + regcache_mark_dirty(adv7533->regmap_main); + adv7533_encoder_dpms(encoder, adv7533->dpms_mode); + adv7533_get_modes(encoder, connector); + if (adv7533->status == connector_status_connected) + status = connector_status_disconnected; + } else { + /* Renable HDP sensing */ + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER2, + BIT(6), 0); + } + + DRM_INFO("HDMI: new_status=%d,old_status=%d,hpd=%d,dpms=%d\n", + status, adv7533->status, hpd, adv7533->dpms_mode); + adv7533->status = status; + return status; +} + +static int adv7533_encoder_mode_valid(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + return MODE_NO_INTERLACE; + + return MODE_OK; +} + +static void adv7533_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ +#if 0 + struct adv7533 *adv7533 = encoder_to_adv7533(encoder); + unsigned int low_refresh_rate; +#endif +} + +static struct drm_encoder_slave_funcs adv7533_encoder_funcs = { + .dpms = adv7533_encoder_dpms, + .mode_valid = adv7533_encoder_mode_valid, + .mode_set = adv7533_encoder_mode_set, + .detect = adv7533_encoder_detect, + .get_modes = adv7533_get_modes, +}; + +static int adv7533_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct adv7533 *adv7533; + struct device *dev = &i2c->dev; + unsigned int val; + int ret; + + DRM_DEBUG_DRIVER("enter.\n"); + if (!dev->of_node) + return -EINVAL; + + adv7533 = devm_kzalloc(dev, sizeof(*adv7533), GFP_KERNEL); + if (!adv7533) + return -ENOMEM; + + adv7533->dpms_mode = DRM_MODE_DPMS_OFF; + adv7533->status = connector_status_disconnected; + + /* + * The power down GPIO is optional. If present, toggle it from active to + * inactive to wake up the encoder. + */ + adv7533->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH); + if (IS_ERR(adv7533->gpio_pd)) + return PTR_ERR(adv7533->gpio_pd); + + if (adv7533->gpio_pd) { + mdelay(5); + gpiod_set_value_cansleep(adv7533->gpio_pd, 0); + } + + adv7533->regmap_main = devm_regmap_init_i2c(i2c, &adv7533_main_regmap_config); + if (IS_ERR(adv7533->regmap_main)) + return PTR_ERR(adv7533->regmap_main); + + ret = regmap_read(adv7533->regmap_main, ADV7533_REG_CHIP_REVISION, &val); + if (ret) + return ret; + dev_dbg(dev, "Rev. %d\n", val); + ret = regmap_register_patch(adv7533->regmap_main, adv7533_fixed_registers, + ARRAY_SIZE(adv7533_fixed_registers)); + if (ret) + return ret; + + regmap_write(adv7533->regmap_main, ADV7533_REG_EDID_I2C_ADDR, edid_i2c_addr); + regmap_write(adv7533->regmap_main, ADV7533_REG_PACKET_I2C_ADDR, + packet_i2c_addr); + regmap_write(adv7533->regmap_main, ADV7533_REG_CEC_I2C_ADDR, cec_i2c_addr); + adv7533_packet_disable(adv7533, 0xffff); + + adv7533->i2c_main = i2c; + adv7533->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1); + if (!adv7533->i2c_edid) + return -ENOMEM; + + adv7533->i2c_cec = i2c_new_dummy(i2c->adapter, cec_i2c_addr >> 1); + if (!adv7533->i2c_cec) { + ret = -ENOMEM; + goto err_i2c_unregister_edid; + } + + adv7533->regmap_dsi = devm_regmap_init_i2c(adv7533->i2c_cec, + &adv7533_cec_regmap_config); + if (IS_ERR(adv7533->regmap_dsi)) { + ret = PTR_ERR(adv7533->regmap_dsi); + goto err_i2c_unregister_cec; + } + + ret = regmap_register_patch(adv7533->regmap_main, adv7533_cec_fixed_registers, + ARRAY_SIZE(adv7533_cec_fixed_registers)); + if (ret) + return ret; + + if (i2c->irq) { + init_waitqueue_head(&adv7533->wq); + + ret = devm_request_threaded_irq(dev, i2c->irq, NULL, + adv7533_irq_handler, + IRQF_ONESHOT, dev_name(dev), + adv7533); + if (ret) + goto err_i2c_unregister_cec; + } + + /* CEC is unused for now */ + regmap_write(adv7533->regmap_main, ADV7533_REG_CEC_CTRL, + ADV7533_CEC_CTRL_POWER_DOWN); + + regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER, + ADV7533_POWER_POWER_DOWN, ADV7533_POWER_POWER_DOWN); + + adv7533->current_edid_segment = -1; + + i2c_set_clientdata(i2c, adv7533); + + DRM_DEBUG_DRIVER("exit success.\n"); + return 0; + +err_i2c_unregister_cec: + i2c_unregister_device(adv7533->i2c_cec); +err_i2c_unregister_edid: + i2c_unregister_device(adv7533->i2c_edid); + + return ret; +} + +static int adv7533_remove(struct i2c_client *i2c) +{ + struct adv7533 *adv7533 = i2c_get_clientdata(i2c); + + i2c_unregister_device(adv7533->i2c_cec); + i2c_unregister_device(adv7533->i2c_edid); + + return 0; +} + +static int adv7533_encoder_init(struct i2c_client *i2c, struct drm_device *dev, + struct drm_encoder_slave *encoder) +{ + + struct adv7533 *adv7533 = i2c_get_clientdata(i2c); + + encoder->slave_priv = adv7533; + encoder->slave_funcs = &adv7533_encoder_funcs; + + adv7533->encoder = &encoder->base; + + return 0; +} + +static const struct i2c_device_id adv7533_i2c_ids[] = { + { "adv7533", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, adv7533_i2c_ids); + +static struct drm_i2c_encoder_driver adv7533_driver = { + .i2c_driver = { + .driver = { + .name = "adv7533", + .of_match_table = adv7533_of_ids, + }, + .id_table = adv7533_i2c_ids, + .probe = adv7533_probe, + .remove = adv7533_remove, + }, + + .encoder_init = adv7533_encoder_init, +}; + +static int __init adv7533_init(void) +{ + return drm_i2c_encoder_register(THIS_MODULE, &adv7533_driver); +} +module_init(adv7533_init); + +static void __exit adv7533_exit(void) +{ + drm_i2c_encoder_unregister(&adv7533_driver); +} +module_exit(adv7533_exit); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("ADV7533 HDMI transmitter driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/i2c/adv7533.h b/drivers/gpu/drm/i2c/adv7533.h new file mode 100644 index 00000000000000..90d3e098571aed --- /dev/null +++ b/drivers/gpu/drm/i2c/adv7533.h @@ -0,0 +1,223 @@ +/* + * Analog Devices ADV7533 HDMI transmitter driver + * + * Copyright 2015 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#ifndef __DRM_I2C_ADV7533_H__ +#define __DRM_I2C_ADV7533_H__ + +#include + +#define ADV7533_REG_CHIP_REVISION 0x00 +#define ADV7533_REG_N0 0x01 +#define ADV7533_REG_N1 0x02 +#define ADV7533_REG_N2 0x03 +#define ADV7533_REG_SPDIF_FREQ 0x04 +#define ADV7533_REG_CTS_AUTOMATIC1 0x05 +#define ADV7533_REG_CTS_AUTOMATIC2 0x06 +#define ADV7533_REG_CTS_MANUAL0 0x07 +#define ADV7533_REG_CTS_MANUAL1 0x08 +#define ADV7533_REG_CTS_MANUAL2 0x09 +#define ADV7533_REG_AUDIO_SOURCE 0x0a +#define ADV7533_REG_AUDIO_CONFIG 0x0b +#define ADV7533_REG_I2S_CONFIG 0x0c +#define ADV7533_REG_I2S_WIDTH 0x0d +#define ADV7533_REG_AUDIO_SUB_SRC0 0x0e +#define ADV7533_REG_AUDIO_SUB_SRC1 0x0f +#define ADV7533_REG_AUDIO_SUB_SRC2 0x10 +#define ADV7533_REG_AUDIO_SUB_SRC3 0x11 +#define ADV7533_REG_AUDIO_CFG1 0x12 +#define ADV7533_REG_AUDIO_CFG2 0x13 +#define ADV7533_REG_AUDIO_CFG3 0x14 +#define ADV7533_REG_I2C_FREQ_ID_CFG 0x15 +#define ADV7533_REG_VIDEO_INPUT_CFG1 0x16 +#define ADV7533_REG_CSC_UPPER(x) (0x18 + (x) * 2) +#define ADV7533_REG_CSC_LOWER(x) (0x19 + (x) * 2) +#define ADV7533_REG_SYNC_DECODER(x) (0x30 + (x)) +#define ADV7533_REG_DE_GENERATOR (0x35 + (x)) +#define ADV7533_REG_PIXEL_REPETITION 0x3b +#define ADV7533_REG_VIC_MANUAL 0x3c +#define ADV7533_REG_VIC_SEND 0x3d +#define ADV7533_REG_VIC_DETECTED 0x3e +#define ADV7533_REG_AUX_VIC_DETECTED 0x3f +#define ADV7533_REG_PACKET_ENABLE0 0x40 +#define ADV7533_REG_POWER 0x41 +#define ADV7533_REG_STATUS 0x42 +#define ADV7533_REG_EDID_I2C_ADDR 0x43 +#define ADV7533_REG_PACKET_ENABLE1 0x44 +#define ADV7533_REG_PACKET_I2C_ADDR 0x45 +#define ADV7533_REG_DSD_ENABLE 0x46 +#define ADV7533_REG_VIDEO_INPUT_CFG2 0x48 +#define ADV7533_REG_INFOFRAME_UPDATE 0x4a +#define ADV7533_REG_GC(x) (0x4b + (x)) /* 0x4b - 0x51 */ +#define ADV7533_REG_AVI_INFOFRAME_VERSION 0x52 +#define ADV7533_REG_AVI_INFOFRAME_LENGTH 0x53 +#define ADV7533_REG_AVI_INFOFRAME_CHECKSUM 0x54 +#define ADV7533_REG_AVI_INFOFRAME(x) (0x55 + (x)) /* 0x55 - 0x6f */ +#define ADV7533_REG_AUDIO_INFOFRAME_VERSION 0x70 +#define ADV7533_REG_AUDIO_INFOFRAME_LENGTH 0x71 +#define ADV7533_REG_AUDIO_INFOFRAME_CHECKSUM 0x72 +#define ADV7533_REG_AUDIO_INFOFRAME(x) (0x73 + (x)) /* 0x73 - 0x7c */ +#define ADV7533_REG_INT_ENABLE(x) (0x94 + (x)) +#define ADV7533_REG_INT(x) (0x96 + (x)) +#define ADV7533_REG_INPUT_CLK_DIV 0x9d +#define ADV7533_REG_PLL_STATUS 0x9e +#define ADV7533_REG_HDMI_POWER 0xa1 +#define ADV7533_REG_HDCP_HDMI_CFG 0xaf +#define ADV7533_REG_AN(x) (0xb0 + (x)) /* 0xb0 - 0xb7 */ +#define ADV7533_REG_HDCP_STATUS 0xb8 +#define ADV7533_REG_BCAPS 0xbe +#define ADV7533_REG_BKSV(x) (0xc0 + (x)) /* 0xc0 - 0xc3 */ +#define ADV7533_REG_EDID_SEGMENT 0xc4 +#define ADV7533_REG_DDC_STATUS 0xc8 +#define ADV7533_REG_EDID_READ_CTRL 0xc9 +#define ADV7533_REG_BSTATUS(x) (0xca + (x)) /* 0xca - 0xcb */ +#define ADV7533_REG_TIMING_GEN_SEQ 0xd0 +#define ADV7533_REG_POWER2 0xd6 +#define ADV7533_REG_HSYNC_PLACEMENT_MSB 0xfa + +#define ADV7533_REG_SYNC_ADJUSTMENT(x) (0xd7 + (x)) /* 0xd7 - 0xdc */ +#define ADV7533_REG_TMDS_CLOCK_INV 0xde +#define ADV7533_REG_ARC_CTRL 0xdf +#define ADV7533_REG_CEC_I2C_ADDR 0xe1 +#define ADV7533_REG_CEC_CTRL 0xe2 +#define ADV7533_REG_CHIP_ID_HIGH 0xf5 +#define ADV7533_REG_CHIP_ID_LOW 0xf6 + +#define ADV7533_CSC_ENABLE BIT(7) +#define ADV7533_CSC_UPDATE_MODE BIT(5) + +#define ADV7533_INT0_HDP BIT(7) +#define ADV7533_INT0_VSYNC BIT(5) +#define ADV7533_INT0_AUDIO_FIFO_FULL BIT(4) +#define ADV7533_INT0_EDID_READY BIT(2) +#define ADV7533_INT0_HDCP_AUTHENTICATED BIT(1) + +#define ADV7533_INT1_DDC_ERROR BIT(7) +#define ADV7533_INT1_BKSV BIT(6) +#define ADV7533_INT1_CEC_TX_READY BIT(5) +#define ADV7533_INT1_CEC_TX_ARBIT_LOST BIT(4) +#define ADV7533_INT1_CEC_TX_RETRY_TIMEOUT BIT(3) +#define ADV7533_INT1_CEC_RX_READY3 BIT(2) +#define ADV7533_INT1_CEC_RX_READY2 BIT(1) +#define ADV7533_INT1_CEC_RX_READY1 BIT(0) + +#define ADV7533_ARC_CTRL_POWER_DOWN BIT(0) + +#define ADV7533_CEC_CTRL_POWER_DOWN BIT(0) + +#define ADV7533_POWER_POWER_DOWN BIT(6) + +#define ADV7533_HDMI_CFG_MODE_MASK 0x2 +#define ADV7533_HDMI_CFG_MODE_DVI 0x0 +#define ADV7533_HDMI_CFG_MODE_HDMI 0x2 + +#define ADV7533_AUDIO_SELECT_I2C 0x0 +#define ADV7533_AUDIO_SELECT_SPDIF 0x1 +#define ADV7533_AUDIO_SELECT_DSD 0x2 +#define ADV7533_AUDIO_SELECT_HBR 0x3 +#define ADV7533_AUDIO_SELECT_DST 0x4 + +#define ADV7533_I2S_SAMPLE_LEN_16 0x2 +#define ADV7533_I2S_SAMPLE_LEN_20 0x3 +#define ADV7533_I2S_SAMPLE_LEN_18 0x4 +#define ADV7533_I2S_SAMPLE_LEN_22 0x5 +#define ADV7533_I2S_SAMPLE_LEN_19 0x8 +#define ADV7533_I2S_SAMPLE_LEN_23 0x9 +#define ADV7533_I2S_SAMPLE_LEN_24 0xb +#define ADV7533_I2S_SAMPLE_LEN_17 0xc +#define ADV7533_I2S_SAMPLE_LEN_21 0xd + +#define ADV7533_SAMPLE_FREQ_44100 0x0 +#define ADV7533_SAMPLE_FREQ_48000 0x2 +#define ADV7533_SAMPLE_FREQ_32000 0x3 +#define ADV7533_SAMPLE_FREQ_88200 0x8 +#define ADV7533_SAMPLE_FREQ_96000 0xa +#define ADV7533_SAMPLE_FREQ_176400 0xc +#define ADV7533_SAMPLE_FREQ_192000 0xe + +#define ADV7533_STATUS_POWER_DOWN_POLARITY BIT(7) +#define ADV7533_STATUS_HPD BIT(6) +#define ADV7533_STATUS_MONITOR_SENSE BIT(5) +#define ADV7533_STATUS_I2S_32BIT_MODE BIT(3) + +#define ADV7533_PACKET_ENABLE_N_CTS BIT(8+6) +#define ADV7533_PACKET_ENABLE_AUDIO_SAMPLE BIT(8+5) +#define ADV7533_PACKET_ENABLE_AVI_INFOFRAME BIT(8+4) +#define ADV7533_PACKET_ENABLE_AUDIO_INFOFRAME BIT(8+3) +#define ADV7533_PACKET_ENABLE_GC BIT(7) +#define ADV7533_PACKET_ENABLE_SPD BIT(6) +#define ADV7533_PACKET_ENABLE_MPEG BIT(5) +#define ADV7533_PACKET_ENABLE_ACP BIT(4) +#define ADV7533_PACKET_ENABLE_ISRC BIT(3) +#define ADV7533_PACKET_ENABLE_GM BIT(2) +#define ADV7533_PACKET_ENABLE_SPARE2 BIT(1) +#define ADV7533_PACKET_ENABLE_SPARE1 BIT(0) + +#define ADV7533_REG_POWER2_HDP_SRC_MASK 0xc0 +#define ADV7533_REG_POWER2_HDP_SRC_BOTH 0x00 +#define ADV7533_REG_POWER2_HDP_SRC_HDP 0x40 +#define ADV7533_REG_POWER2_HDP_SRC_CEC 0x80 +#define ADV7533_REG_POWER2_HDP_SRC_NONE 0xc0 +#define ADV7533_REG_POWER2_TDMS_ENABLE BIT(4) +#define ADV7533_REG_POWER2_GATE_INPUT_CLK BIT(0) + +#define ADV7533_LOW_REFRESH_RATE_NONE 0x0 +#define ADV7533_LOW_REFRESH_RATE_24HZ 0x1 +#define ADV7533_LOW_REFRESH_RATE_25HZ 0x2 +#define ADV7533_LOW_REFRESH_RATE_30HZ 0x3 + +#define ADV7533_AUDIO_CFG3_LEN_MASK 0x0f +#define ADV7533_I2C_FREQ_ID_CFG_RATE_MASK 0xf0 + +#define ADV7533_AUDIO_SOURCE_I2S 0 +#define ADV7533_AUDIO_SOURCE_SPDIF 1 + +#define ADV7533_I2S_FORMAT_I2S 0 +#define ADV7533_I2S_FORMAT_RIGHT_J 1 +#define ADV7533_I2S_FORMAT_LEFT_J 2 + +#define ADV7533_PACKET(p, x) ((p) * 0x20 + (x)) +#define ADV7533_PACKET_SDP(x) ADV7533_PACKET(0, x) +#define ADV7533_PACKET_MPEG(x) ADV7533_PACKET(1, x) +#define ADV7533_PACKET_ACP(x) ADV7533_PACKET(2, x) +#define ADV7533_PACKET_ISRC1(x) ADV7533_PACKET(3, x) +#define ADV7533_PACKET_ISRC2(x) ADV7533_PACKET(4, x) +#define ADV7533_PACKET_GM(x) ADV7533_PACKET(5, x) +#define ADV7533_PACKET_SPARE(x) ADV7533_PACKET(6, x) + + +/** + * enum adv7533_csc_scaling - Scaling factor for the ADV7533 CSC + * @ADV7533_CSC_SCALING_1: CSC results are not scaled + * @ADV7533_CSC_SCALING_2: CSC results are scaled by a factor of two + * @ADV7533_CSC_SCALING_4: CSC results are scalled by a factor of four + */ +enum adv7533_csc_scaling { + ADV7533_CSC_SCALING_1 = 0, + ADV7533_CSC_SCALING_2 = 1, + ADV7533_CSC_SCALING_4 = 2, +}; + +/** + * struct adv7533_video_config - Describes adv7533 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 adv7533_video_config { + bool csc_enable; + enum adv7533_csc_scaling csc_scaling_factor; + const uint16_t *csc_coefficents; + + bool hdmi_mode; + struct hdmi_avi_infoframe avi_infoframe; +}; + + +#endif /* __DRM_I2C_ADV7533_H__ */ From 490f56aa5d145f3b6eb46d806f338ec8c1274ce9 Mon Sep 17 00:00:00 2001 From: Xinliang Liu Date: Tue, 3 Mar 2015 10:33:24 +0800 Subject: [PATCH 2/7] gpu/drm: hisilicon: 'USE_DEFAULT_720P_MODE' to config 720p --- arch/arm64/boot/dts/hi6220.dtsi | 1 - drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 18 +++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/hi6220.dtsi b/arch/arm64/boot/dts/hi6220.dtsi index d63af17ca33f12..00ff9b7d80e006 100644 --- a/arch/arm64/boot/dts/hi6220.dtsi +++ b/arch/arm64/boot/dts/hi6220.dtsi @@ -722,7 +722,6 @@ reg = <0x0 0xf4107800 0x0 0x100>; clocks = <&clock_media HI6220_DSI_PCLK>; clock-names = "pclk_dsi"; - dsi_bit_clk_rate = <640>; vc = <0>; encoder-slave = <&adv7533>; }; diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c index 71ecf9531db099..c701a1efff7571 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c @@ -46,6 +46,8 @@ #define DSI_BURST_MODE DSI_NON_BURST_SYNC_PULSES #define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0)) +//#define USE_DEFAULT_720P_MODE 1 + u8 *reg_base_mipi_dsi; @@ -762,8 +764,10 @@ static void hisi_drm_encoder_mode_set(struct drm_encoder *encoder, vm->hback_porch = mode->htotal - mode->hsync_end; vm->hsync_len = mode->hsync_end - mode->hsync_start; +#if USE_DEFAULT_720P_MODE != 1 /* laneBitRate >= pixelClk*24/lanes */ dsi->dphy_freq = vm->pixelclock*24/dsi->lanes; /* + 30; */ +#endif vm->flags = 0; if (mode->flags & DRM_MODE_FLAG_PHSYNC) @@ -840,6 +844,7 @@ static struct drm_connector_funcs hisi_dsi_connector_funcs = { static int hisi_get_default_modes(struct drm_connector *connector) { struct drm_display_mode *mode; + struct hisi_dsi *dsi = connector_to_dsi(connector); DRM_DEBUG_DRIVER("enter.\n"); mode = drm_mode_create(connector->dev); @@ -862,6 +867,7 @@ static int hisi_get_default_modes(struct drm_connector *connector) mode->flags = 0xa; drm_mode_probed_add(connector, mode); + dsi->dphy_freq = 640; /* 640M for 720p */ DRM_DEBUG_DRIVER("exit successfully.\n"); return 1; } @@ -871,12 +877,13 @@ static int hisi_dsi_get_modes(struct drm_connector *connector) struct drm_encoder *encoder = &dsi->base.base; struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder); int count = 0; -#if 1 + DRM_DEBUG_DRIVER("enter.\n"); if (sfuncs && sfuncs->get_modes) count = sfuncs->get_modes(encoder, connector); DRM_DEBUG_DRIVER("exit success. count=%d\n", count); +#if USE_DEFAULT_720P_MODE != 1 return count; #else return hisi_get_default_modes(connector); @@ -902,6 +909,11 @@ static int hisi_drm_connector_mode_valid(struct drm_connector *connector, struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder); int ret = MODE_OK; +#if USE_DEFAULT_720P_MODE + if (mode->vdisplay != 720) + return MODE_ONE_SIZE; +#endif + DRM_DEBUG_DRIVER("enter.\n"); if (sfuncs && sfuncs->mode_valid) ret = sfuncs->mode_valid(encoder, mode); @@ -990,10 +1002,6 @@ static int hisi_dsi_probe(struct platform_device *pdev) ret = PTR_ERR(dsi->reg_base); } - ret = of_property_read_u32(pdev->dev.of_node, "dsi_bit_clk_rate", &dsi->dphy_freq); - if (ret) - dev_err(&pdev->dev, "failed to get dsi_bit_clk_rate"); - ret = of_property_read_u32(pdev->dev.of_node, "vc", &dsi->vc); if (ret) dev_err(&pdev->dev, "failed to get vc"); From 819da2f24c44dbcd232b63a27564fcff82b6da3f Mon Sep 17 00:00:00 2001 From: Xinliang Liu Date: Tue, 3 Mar 2015 15:39:03 +0800 Subject: [PATCH 3/7] gpu/drm: i2c: fix ADV7523 --- drivers/gpu/drm/i2c/adv7533.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c index 955aa3fbbdf6e6..bc25084cb23cf1 100644 --- a/drivers/gpu/drm/i2c/adv7533.c +++ b/drivers/gpu/drm/i2c/adv7533.c @@ -23,7 +23,7 @@ struct adv7533 { struct i2c_client *i2c_main; struct i2c_client *i2c_edid; - struct i2c_client *i2c_cec; + struct i2c_client *i2c_dsi; struct regmap *regmap_main; struct regmap *regmap_dsi; @@ -57,7 +57,7 @@ static const struct reg_default adv7533_fixed_registers[] = { { 0xe5, 0x80 }, }; -static const struct reg_default adv7533_cec_fixed_registers[] = { +static const struct reg_default adv7533_dsi_fixed_registers[] = { { 0x15, 0x10 }, { 0x17, 0xd0 }, { 0x24, 0x20 }, @@ -78,7 +78,7 @@ static const struct regmap_config adv7533_main_regmap_config = { #endif }; -static const struct regmap_config adv7533_cec_regmap_config = { +static const struct regmap_config adv7533_dsi_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -94,7 +94,7 @@ static struct adv7533 *encoder_to_adv7533(struct drm_encoder *encoder) static const int edid_i2c_addr = 0x7e; static const int packet_i2c_addr = 0x70; -static const int cec_i2c_addr = 0x78; +static const int dsi_i2c_addr = 0x78; static const struct of_device_id adv7533_of_ids[] = { { .compatible = "adi,adv7533"}, @@ -235,7 +235,6 @@ static void adv7533_set_config_csc(struct adv7533 *adv7533, } DRM_INFO("HDMI: mode=%d,format_422=%d,format_ycbcr=%d\n", mode, output_format_422, output_format_ycbcr); -#if 1 adv7533_packet_disable(adv7533, ADV7533_PACKET_ENABLE_AVI_INFOFRAME); adv7533_set_colormap(adv7533, config.csc_enable, @@ -256,7 +255,6 @@ static void adv7533_set_config_csc(struct adv7533 *adv7533, infoframe + 1, sizeof(infoframe) - 1); adv7533_packet_enable(adv7533, ADV7533_PACKET_ENABLE_AVI_INFOFRAME); -#endif } @@ -636,7 +634,7 @@ static int adv7533_probe(struct i2c_client *i2c, const struct i2c_device_id *id) regmap_write(adv7533->regmap_main, ADV7533_REG_EDID_I2C_ADDR, edid_i2c_addr); regmap_write(adv7533->regmap_main, ADV7533_REG_PACKET_I2C_ADDR, packet_i2c_addr); - regmap_write(adv7533->regmap_main, ADV7533_REG_CEC_I2C_ADDR, cec_i2c_addr); + regmap_write(adv7533->regmap_main, ADV7533_REG_CEC_I2C_ADDR, dsi_i2c_addr); adv7533_packet_disable(adv7533, 0xffff); adv7533->i2c_main = i2c; @@ -644,21 +642,21 @@ static int adv7533_probe(struct i2c_client *i2c, const struct i2c_device_id *id) if (!adv7533->i2c_edid) return -ENOMEM; - adv7533->i2c_cec = i2c_new_dummy(i2c->adapter, cec_i2c_addr >> 1); - if (!adv7533->i2c_cec) { + adv7533->i2c_dsi = i2c_new_dummy(i2c->adapter, dsi_i2c_addr >> 1); + if (!adv7533->i2c_dsi) { ret = -ENOMEM; goto err_i2c_unregister_edid; } - adv7533->regmap_dsi = devm_regmap_init_i2c(adv7533->i2c_cec, - &adv7533_cec_regmap_config); + adv7533->regmap_dsi = devm_regmap_init_i2c(adv7533->i2c_dsi, + &adv7533_dsi_regmap_config); if (IS_ERR(adv7533->regmap_dsi)) { ret = PTR_ERR(adv7533->regmap_dsi); - goto err_i2c_unregister_cec; + goto err_i2c_unregister_dsi; } - ret = regmap_register_patch(adv7533->regmap_main, adv7533_cec_fixed_registers, - ARRAY_SIZE(adv7533_cec_fixed_registers)); + ret = regmap_register_patch(adv7533->regmap_dsi, adv7533_dsi_fixed_registers, + ARRAY_SIZE(adv7533_dsi_fixed_registers)); if (ret) return ret; @@ -670,7 +668,7 @@ static int adv7533_probe(struct i2c_client *i2c, const struct i2c_device_id *id) IRQF_ONESHOT, dev_name(dev), adv7533); if (ret) - goto err_i2c_unregister_cec; + goto err_i2c_unregister_dsi; } /* CEC is unused for now */ @@ -687,8 +685,8 @@ static int adv7533_probe(struct i2c_client *i2c, const struct i2c_device_id *id) DRM_DEBUG_DRIVER("exit success.\n"); return 0; -err_i2c_unregister_cec: - i2c_unregister_device(adv7533->i2c_cec); +err_i2c_unregister_dsi: + i2c_unregister_device(adv7533->i2c_dsi); err_i2c_unregister_edid: i2c_unregister_device(adv7533->i2c_edid); @@ -699,7 +697,7 @@ static int adv7533_remove(struct i2c_client *i2c) { struct adv7533 *adv7533 = i2c_get_clientdata(i2c); - i2c_unregister_device(adv7533->i2c_cec); + i2c_unregister_device(adv7533->i2c_dsi); i2c_unregister_device(adv7533->i2c_edid); return 0; From 46a3783acd507b7f9cb5068c51ed79bd77d7190f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 27 Apr 2012 11:11:58 +0200 Subject: [PATCH 4/7] gpu/drm: Decouple EDID parsing from I2C adapter The drm_get_edid() function performs direct I2C accesses to read EDID blocks, assuming that the monitor DDC interface is directly connected to the I2C bus. It can't thus be used with HDMI encoders that control the DDC bus and expose EDID blocks through a different interface. Refactor drm_do_get_edid() to take a block read callback function instead of an I2C adapter, and export it for direct use by drivers. As in the general case the DDC bus is accessible by the kernel at the I2C level, drivers must make all reasonable efforts to expose it as an I2C adapter and use drm_get_edid() instead of abusing this function. Signed-off-by: Lars-Peter Clausen Signed-off-by: Laurent Pinchart Reviewed-by: Rob Clark Reviewed-by: Daniel Vetter Conflicts: include/drm/drm_edid.h --- drivers/gpu/drm/drm_edid.c | 43 ++++++++++++++++++++++++++------------ include/drm/drm_edid.h | 5 +++++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3bf999134bcc50..1a77a49d269533 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1125,9 +1125,9 @@ EXPORT_SYMBOL(drm_edid_is_valid); * Return: 0 on success or -1 on failure. */ static int -drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, - int block, int len) +drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len) { + struct i2c_adapter *adapter = data; unsigned char start = block * EDID_LENGTH; unsigned char segment = block >> 1; unsigned char xfers = segment ? 3 : 2; @@ -1184,8 +1184,26 @@ static bool drm_edid_is_zero(u8 *in_edid, int length) return true; } -static u8 * -drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) +/** + * drm_do_get_edid - get EDID data using a custom EDID block read function + * @connector: connector we're probing + * @get_edid_block: EDID block read function + * @data: private data passed to the block read function + * + * When the I2C adapter connected to the DDC bus is hidden behind a device that + * exposes a different interface to read EDID blocks this function can be used + * to get EDID data using a custom block read function. + * + * As in the general case the DDC bus is accessible by the kernel at the I2C + * level, drivers must make all reasonable efforts to expose it as an I2C + * adapter and use drm_get_edid() instead of abusing this function. + * + * Return: Pointer to valid EDID or NULL if we couldn't find any. + */ +struct edid *drm_do_get_edid(struct drm_connector *connector, + int (*get_edid_block)(void *data, u8 *buf, unsigned int block, + size_t len), + void *data) { int i, j = 0, valid_extensions = 0; u8 *block, *new; @@ -1196,7 +1214,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) /* base block fetch */ for (i = 0; i < 4; i++) { - if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) + if (get_edid_block(data, block, 0, EDID_LENGTH)) goto out; if (drm_edid_block_valid(block, 0, print_bad_edid)) break; @@ -1210,7 +1228,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) /* if there's no extensions, we're done */ if (block[0x7e] == 0) - return block; + return (struct edid *)block; new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); if (!new) @@ -1219,7 +1237,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) for (j = 1; j <= block[0x7e]; j++) { for (i = 0; i < 4; i++) { - if (drm_do_probe_ddc_edid(adapter, + if (get_edid_block(data, block + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; @@ -1247,7 +1265,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) block = new; } - return block; + return (struct edid *)block; carp: if (print_bad_edid) { @@ -1260,6 +1278,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) kfree(block); return NULL; } +EXPORT_SYMBOL_GPL(drm_do_get_edid); /** * drm_probe_ddc() - probe DDC presence @@ -1289,12 +1308,10 @@ EXPORT_SYMBOL(drm_probe_ddc); struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { - struct edid *edid = NULL; - - if (drm_probe_ddc(adapter)) - edid = (struct edid *)drm_do_get_edid(connector, adapter); + if (!drm_probe_ddc(adapter)) + return NULL; - return edid; + return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); } EXPORT_SYMBOL(drm_get_edid); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index b96031d947a0c5..c30fa4e48f1467 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -279,4 +279,9 @@ int drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, const struct drm_display_mode *mode); +struct edid *drm_do_get_edid(struct drm_connector *connector, + int (*get_edid_block)(void *data, u8 *buf, unsigned int block, + size_t len), + void *data); + #endif /* __DRM_EDID_H__ */ From f1851edf2f83327a57004e3c216ab819a9f29638 Mon Sep 17 00:00:00 2001 From: Xinliang Liu Date: Wed, 4 Mar 2015 11:02:50 +0800 Subject: [PATCH 5/7] gpu/drm: i2c: update adv7533 use a adv private get_edid_block function --- drivers/gpu/drm/i2c/adv7533.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c index bc25084cb23cf1..328bc10cae2a39 100644 --- a/drivers/gpu/drm/i2c/adv7533.c +++ b/drivers/gpu/drm/i2c/adv7533.c @@ -437,7 +437,8 @@ static int adv7533_get_modes(struct drm_encoder *encoder, adv7533->current_edid_segment = -1; } - edid = drm_get_edid(connector, adv7533->i2c_edid->adapter); + edid = drm_do_get_edid(connector, adv7533_get_edid_block, adv7533); + /* edid = drm_get_edid(connector, adv7533->i2c_edid->adapter); */ if (adv7533->dpms_mode != DRM_MODE_DPMS_ON) regmap_update_bits(adv7533->regmap_main, ADV7533_REG_POWER, From 634790b3ed7e146596d59a66facf95929d4ce96c Mon Sep 17 00:00:00 2001 From: Xinliang Liu Date: Wed, 4 Mar 2015 11:29:20 +0800 Subject: [PATCH 6/7] gpu/drm: hisilicon: Fix display colors --- drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c index b8e9487a5edb84..9316c200a4eb51 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c @@ -368,7 +368,7 @@ static int hisi_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, writel((ADE_RGB_565 << 16) & 0x1f0000, (ade_base + RD_CH_DISP_CTRL_REG)); else if (32 == fb->bits_per_pixel) - writel((ADE_ARGB_8888 << 16) & 0x1f0000, + writel((ADE_ABGR_8888 << 16) & 0x1f0000, (ade_base + RD_CH_DISP_CTRL_REG)); writel(display_addr, (ade_base + RD_CH_DISP_ADDR_REG)); From f7754a05c0e14de91716fb87168f6bf00b2b423c Mon Sep 17 00:00:00 2001 From: Xinliang Liu Date: Wed, 4 Mar 2015 11:32:06 +0800 Subject: [PATCH 7/7] gpu/drm: hisilicon: fix display wrap issue and set 720p as default mode Signed-off-by: Xinliang Liu --- drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 73 ++++++++++++---------- drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 4 +- drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 20 +++--- drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c | 2 +- drivers/gpu/drm/i2c/adv7533.c | 6 +- 5 files changed, 56 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c index 9316c200a4eb51..7548ae2162ed40 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c @@ -101,6 +101,7 @@ struct hisi_drm_ade_crtc { u32 ade_core_rate; u32 media_noc_rate; u32 x , y; + bool first_time; struct drm_device *drm_dev; struct drm_crtc crtc; @@ -340,28 +341,43 @@ static int hisi_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, stride, (u32)obj->paddr, display_addr, fb->width, fb_hight); - /* TOP */ - writel(0, (ade_base + ADE_WDMA2_SRC_CFG_REG)); - writel(0, (ade_base + ADE_SCL3_MUX_CFG_REG)); - writel(0, (ade_base + ADE_SCL1_MUX_CFG_REG)); - writel(0, (ade_base + ADE_ROT_SRC_CFG_REG)); - writel(0, (ade_base + ADE_SCL2_SRC_CFG_REG)); - writel(0, (ade_base + ADE_SEC_OVLY_SRC_CFG_REG)); - writel(0, (ade_base + ADE_WDMA3_SRC_CFG_REG)); - writel(0, (ade_base + ADE_OVLY1_TRANS_CFG_REG)); - writel(0, (ade_base + ADE_CTRAN5_TRANS_CFG_REG)); - writel(0, (ade_base + ADE_OVLY_CTL_REG)); - - writel(0, (ade_base + ADE_SOFT_RST_SEL0_REG)); - writel(0, (ade_base + ADE_SOFT_RST_SEL1_REG)); - set_TOP_SOFT_RST_SEL0_disp_rdma(ade_base, 1); - set_TOP_SOFT_RST_SEL0_ctran5(ade_base, 1); - set_TOP_SOFT_RST_SEL0_ctran6(ade_base, 1); - - writel(0, (ade_base + ADE_RELOAD_DIS0_REG)); - writel(0, (ade_base + ADE_RELOAD_DIS1_REG)); - - writel(TOP_DISP_CH_SRC_RDMA, (ade_base + ADE_DISP_SRC_CFG_REG)); + if (crtc_ade->first_time) { + crtc_ade->first_time = false; + /* TOP */ + writel(0, (ade_base + ADE_WDMA2_SRC_CFG_REG)); + writel(0, (ade_base + ADE_SCL3_MUX_CFG_REG)); + writel(0, (ade_base + ADE_SCL1_MUX_CFG_REG)); + writel(0, (ade_base + ADE_ROT_SRC_CFG_REG)); + writel(0, (ade_base + ADE_SCL2_SRC_CFG_REG)); + writel(0, (ade_base + ADE_SEC_OVLY_SRC_CFG_REG)); + writel(0, (ade_base + ADE_WDMA3_SRC_CFG_REG)); + writel(0, (ade_base + ADE_OVLY1_TRANS_CFG_REG)); + writel(0, (ade_base + ADE_CTRAN5_TRANS_CFG_REG)); + writel(0, (ade_base + ADE_OVLY_CTL_REG)); + + writel(0, (ade_base + ADE_SOFT_RST_SEL0_REG)); + writel(0, (ade_base + ADE_SOFT_RST_SEL1_REG)); + set_TOP_SOFT_RST_SEL0_disp_rdma(ade_base, 1); + set_TOP_SOFT_RST_SEL0_ctran5(ade_base, 1); + set_TOP_SOFT_RST_SEL0_ctran6(ade_base, 1); + + writel(0, (ade_base + ADE_RELOAD_DIS0_REG)); + writel(0, (ade_base + ADE_RELOAD_DIS1_REG)); + + writel(TOP_DISP_CH_SRC_RDMA, (ade_base + ADE_DISP_SRC_CFG_REG)); + + /* ctran5 */ + writel(1, (ade_base + ADE_CTRAN5_DIS_REG)); + writel(fb->width * fb_hight - 1, + (ade_base + ADE_CTRAN5_IMAGE_SIZE_REG)); + writel(1, (ade_base + ADE_CTRAN5_CFG_OK_REG)); + + /* ctran6 */ + writel(1, (ade_base + ADE_CTRAN6_DIS_REG)); + writel(fb->width * fb_hight - 1, + (ade_base + ADE_CTRAN6_IMAGE_SIZE_REG)); + writel(1, (ade_base + ADE_CTRAN6_CFG_OK_REG)); + } /* DISP DMA */ if (16 == fb->bits_per_pixel) @@ -377,18 +393,6 @@ static int hisi_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, writel(fb_hight * stride, (ade_base + RD_CH_DISP_SPACE_REG)); writel(1, (ade_base + RD_CH_DISP_EN_REG)); - /* ctran5 */ - writel(1, (ade_base + ADE_CTRAN5_DIS_REG)); - writel(fb->width * fb_hight - 1, - (ade_base + ADE_CTRAN5_IMAGE_SIZE_REG)); - writel(1, (ade_base + ADE_CTRAN5_CFG_OK_REG)); - - /* ctran6 */ - writel(1, (ade_base + ADE_CTRAN6_DIS_REG)); - writel(fb->width * fb_hight - 1, - (ade_base + ADE_CTRAN6_IMAGE_SIZE_REG)); - writel(1, (ade_base + ADE_CTRAN6_CFG_OK_REG)); - writel(1, (ade_base + ADE_EN_REG)); set_TOP_CTL_frm_end_start(ade_base, 1); set_LDI_CTRL_ldi_en(ade_base, ADE_ENABLE); @@ -442,6 +446,7 @@ static int hisi_drm_crtc_create(struct hisi_drm_ade_crtc *crtc_ade) int ret; crtc_ade->dpms = DRM_MODE_DPMS_OFF; + crtc_ade->first_time = true; ret = drm_crtc_init(crtc_ade->drm_dev, crtc, &crtc_funcs); if (ret < 0) diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c index 582bd5eaad008c..987c5302a9a1c1 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c @@ -97,8 +97,8 @@ static int hisi_drm_load(struct drm_device *drm_dev, unsigned long flags) int ret; struct hisi_drm_private *private; - /* debug setting */ - drm_debug = DRM_UT_DRIVER|DRM_UT_KMS|DRM_UT_CORE|DRM_UT_PRIME; + /* debug setting + drm_debug = DRM_UT_DRIVER|DRM_UT_KMS|DRM_UT_CORE|DRM_UT_PRIME; */ DRM_DEBUG_DRIVER("enter.\n"); private = kzalloc(sizeof(struct hisi_drm_private), GFP_KERNEL); diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c index c701a1efff7571..b66905cca64997 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c @@ -46,7 +46,7 @@ #define DSI_BURST_MODE DSI_NON_BURST_SYNC_PULSES #define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0)) -//#define USE_DEFAULT_720P_MODE 1 +#define USE_DEFAULT_720P_MODE 1 u8 *reg_base_mipi_dsi; @@ -764,10 +764,8 @@ static void hisi_drm_encoder_mode_set(struct drm_encoder *encoder, vm->hback_porch = mode->htotal - mode->hsync_end; vm->hsync_len = mode->hsync_end - mode->hsync_start; -#if USE_DEFAULT_720P_MODE != 1 /* laneBitRate >= pixelClk*24/lanes */ - dsi->dphy_freq = vm->pixelclock*24/dsi->lanes; /* + 30; */ -#endif + dsi->dphy_freq = vm->pixelclock*24/dsi->lanes + 20; vm->flags = 0; if (mode->flags & DRM_MODE_FLAG_PHSYNC) @@ -781,7 +779,8 @@ static void hisi_drm_encoder_mode_set(struct drm_encoder *encoder, if (sfuncs && sfuncs->mode_set) sfuncs->mode_set(encoder, mode, adjusted_mode); - DRM_DEBUG_DRIVER("exit success.\n"); + DRM_DEBUG_DRIVER("exit success: pixelclk=%d,dphy_freq=%d\n", + (u32)vm->pixelclock, dsi->dphy_freq); } static void hisi_drm_encoder_prepare(struct drm_encoder *encoder) @@ -841,10 +840,10 @@ static struct drm_connector_funcs hisi_dsi_connector_funcs = { .destroy = hisi_dsi_connector_destroy }; +#if USE_DEFAULT_720P_MODE static int hisi_get_default_modes(struct drm_connector *connector) { struct drm_display_mode *mode; - struct hisi_dsi *dsi = connector_to_dsi(connector); DRM_DEBUG_DRIVER("enter.\n"); mode = drm_mode_create(connector->dev); @@ -867,10 +866,11 @@ static int hisi_get_default_modes(struct drm_connector *connector) mode->flags = 0xa; drm_mode_probed_add(connector, mode); - dsi->dphy_freq = 640; /* 640M for 720p */ DRM_DEBUG_DRIVER("exit successfully.\n"); return 1; } +#endif + static int hisi_dsi_get_modes(struct drm_connector *connector) { struct hisi_dsi *dsi = connector_to_dsi(connector); @@ -883,10 +883,10 @@ static int hisi_dsi_get_modes(struct drm_connector *connector) count = sfuncs->get_modes(encoder, connector); DRM_DEBUG_DRIVER("exit success. count=%d\n", count); -#if USE_DEFAULT_720P_MODE != 1 - return count; -#else +#if USE_DEFAULT_720P_MODE return hisi_get_default_modes(connector); +#else + return count; #endif } diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c index fe49ae6d1bb11a..35e5ed5ab4a7f4 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c @@ -238,7 +238,7 @@ static int hisi_drm_fbdev_probe(struct drm_fb_helper *helper, mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel; mode_cmd.pixel_format = DRM_FORMAT_RGBA8888; - size = mode_cmd.pitches[0] * mode_cmd.height; + size = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE); obj = drm_gem_cma_create(dev, size); if (IS_ERR(obj)) return -ENOMEM; diff --git a/drivers/gpu/drm/i2c/adv7533.c b/drivers/gpu/drm/i2c/adv7533.c index 328bc10cae2a39..359bf70e8428d8 100644 --- a/drivers/gpu/drm/i2c/adv7533.c +++ b/drivers/gpu/drm/i2c/adv7533.c @@ -447,8 +447,10 @@ static int adv7533_get_modes(struct drm_encoder *encoder, adv7533->edid = edid; adv7533_set_config_csc(adv7533, connector, true); /* adv7533->rgb); */ - if (!edid) + if (!edid) { + DRM_INFO("May has one empty edid block!\n"); return 0; + } drm_mode_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); @@ -508,7 +510,7 @@ static void adv7533_encoder_dpms(struct drm_encoder *encoder, int mode) regcache_mark_dirty(adv7533->regmap_main); break; } - + /* dsi receiver dpms */ adv7533_dsi_receiver_dpms(adv7533, mode); adv7533->dpms_mode = mode;