From: Rahul Sharma Rahul.Sharma@samsung.com
V2: 1) Rebased on Tomasz Stanislawski at https://lkml.org/lkml/2014/4/8/226.
Adds apb mapped phy support for exynos5420 hdmi. Replace dummy hdmiphy clock with regmap calls.
Based on Inki Dae's exynos-drm-next branch.
Rahul Sharma (3): drm/exynos: remove unnecessary read for phy configuration values drm/exynos: add support for apb mapped phys in hdmi driver drm/exynos: enable support for exynos5420 hdmi device
.../devicetree/bindings/video/exynos_hdmi.txt | 1 + drivers/gpu/drm/exynos/exynos_hdmi.c | 317 ++++++++++++++++---- drivers/gpu/drm/exynos/regs-hdmi.h | 7 + 3 files changed, 262 insertions(+), 63 deletions(-)
From: Rahul Sharma Rahul.Sharma@samsung.com
Cleaning up unnecessary i2c read call after hdmiphy configuration. This check is redundant since check for hdmiphy pll lock status confirms the correct settings for phy.
Signed-off-by: Rahul Sharma Rahul.Sharma@samsung.com Signed-off-by: Daniel Kurtz djkurtz@chromium.org Reviewed-by: Tomasz Figa t.figa@samsung.com --- drivers/gpu/drm/exynos/exynos_hdmi.c | 10 ---------- 1 file changed, 10 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index ef1cdd0..438eeda 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1517,7 +1517,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) const u8 *hdmiphy_data; u8 buffer[32]; u8 operation[2]; - u8 read_buffer[32] = {0, }; int ret; int i;
@@ -1557,15 +1556,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) return; }
- ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32); - if (ret < 0) { - DRM_ERROR("failed to read hdmiphy config\n"); - return; - } - - for (i = 0; i < ret; i++) - DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - " - "recv [0x%02x]\n", i, buffer[i], read_buffer[i]); }
static void hdmi_conf_apply(struct hdmi_context *hdata)
From: Rahul Sharma Rahul.Sharma@samsung.com
Previous SoCs have hdmi phys which are accessible through dedicated i2c lines. Newer SoCs have Apb mapped hdmi phys. Hdmi driver is modified to support apb mapped phys.
Signed-off-by: Rahul Sharma Rahul.Sharma@samsung.com --- drivers/gpu/drm/exynos/exynos_hdmi.c | 142 +++++++++++++++++++++------------- drivers/gpu/drm/exynos/regs-hdmi.h | 7 ++ 2 files changed, 96 insertions(+), 53 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 438eeda..f4566b1 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -33,6 +33,7 @@ #include <linux/regulator/consumer.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/i2c.h> #include <linux/of_gpio.h> #include <linux/hdmi.h> @@ -67,6 +68,8 @@ enum hdmi_type {
struct hdmi_driver_data { unsigned int type; + const struct hdmiphy_config *phy_confs; + unsigned int phy_conf_count; unsigned int is_apb_phy:1; };
@@ -196,6 +199,9 @@ struct hdmi_context { struct hdmi_resources res;
int hpd_gpio; + void __iomem *regs_hdmiphy; + const struct hdmiphy_config *phy_confs; + unsigned int phy_conf_count;
enum hdmi_type type; }; @@ -205,14 +211,6 @@ struct hdmiphy_config { u8 conf[32]; };
-struct hdmi_driver_data exynos4212_hdmi_driver_data = { - .type = HDMI_TYPE14, -}; - -struct hdmi_driver_data exynos5_hdmi_driver_data = { - .type = HDMI_TYPE14, -}; - /* list of phy config settings */ static const struct hdmiphy_config hdmiphy_v13_configs[] = { { @@ -427,6 +425,21 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { }, };
+ +struct hdmi_driver_data exynos4212_hdmi_driver_data = { + .type = HDMI_TYPE14, + .phy_confs = hdmiphy_v14_configs, + .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs), + .is_apb_phy = 0, +}; + +struct hdmi_driver_data exynos5_hdmi_driver_data = { + .type = HDMI_TYPE14, + .phy_confs = hdmiphy_v13_configs, + .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs), + .is_apb_phy = 0, +}; + static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) { return readl(hdata->regs + reg_id); @@ -446,6 +459,48 @@ static inline void hdmi_reg_writemask(struct hdmi_context *hdata, writel(value, hdata->regs + reg_id); }
+static int hdmiphy_reg_writeb(struct hdmi_context *hdata, + u32 reg_offset, u8 value) +{ + if (hdata->hdmiphy_port) { + u8 buffer[2]; + int ret; + + buffer[0] = reg_offset; + buffer[1] = value; + + ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2); + if (ret == 2) + return 0; + return ret; + } else { + writeb(value, hdata->regs_hdmiphy + (reg_offset<<2)); + return 0; + } +} + +static int hdmiphy_reg_write_buf(struct hdmi_context *hdata, + u32 reg_offset, const u8 *buf, u32 len) +{ + if ((reg_offset + len) > 32) + return -EINVAL; + + if (hdata->hdmiphy_port) { + int ret; + + ret = i2c_master_send(hdata->hdmiphy_port, buf, len); + if (ret == len) + return 0; + return ret; + } else { + int i; + for (i = 0; i < len; i++) + writeb(buf[i], hdata->regs_hdmiphy + + ((reg_offset + i)<<2)); + return 0; + } +} + static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix) { #define DUMPREG(reg_id) \ @@ -849,20 +904,10 @@ static int hdmi_get_modes(struct drm_connector *connector)
static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) { - const struct hdmiphy_config *confs; - int count, i; - - if (hdata->type == HDMI_TYPE13) { - confs = hdmiphy_v13_configs; - count = ARRAY_SIZE(hdmiphy_v13_configs); - } else if (hdata->type == HDMI_TYPE14) { - confs = hdmiphy_v14_configs; - count = ARRAY_SIZE(hdmiphy_v14_configs); - } else - return -EINVAL; + int i;
- for (i = 0; i < count; i++) - if (confs[i].pixel_clock == pixel_clock) + for (i = 0; i < hdata->phy_conf_count; i++) + if (hdata->phy_confs[i].pixel_clock == pixel_clock) return i;
DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); @@ -1514,17 +1559,9 @@ static void hdmiphy_poweroff(struct hdmi_context *hdata)
static void hdmiphy_conf_apply(struct hdmi_context *hdata) { - const u8 *hdmiphy_data; - u8 buffer[32]; - u8 operation[2]; int ret; int i;
- if (!hdata->hdmiphy_port) { - DRM_ERROR("hdmiphy is not attached\n"); - return; - } - /* pixel clock */ i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock); if (i < 0) { @@ -1532,26 +1569,17 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) return; }
- if (hdata->type == HDMI_TYPE13) - hdmiphy_data = hdmiphy_v13_configs[i].conf; - else - hdmiphy_data = hdmiphy_v14_configs[i].conf; - - memcpy(buffer, hdmiphy_data, 32); - ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32); - if (ret != 32) { - DRM_ERROR("failed to configure HDMIPHY via I2C\n"); + ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32); + if (ret) { + DRM_ERROR("failed to configure hdmiphy\n"); return; }
usleep_range(10000, 12000);
- /* operation mode */ - operation[0] = 0x1f; - operation[1] = 0x80; - - ret = i2c_master_send(hdata->hdmiphy_port, operation, 2); - if (ret != 2) { + ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, + HDMI_PHY_DISABLE_MODE_SET); + if (ret) { DRM_ERROR("failed to enable hdmiphy\n"); return; } @@ -2070,6 +2098,8 @@ static int hdmi_probe(struct platform_device *pdev)
drv_data = (struct hdmi_driver_data *)match->data; hdata->type = drv_data->type; + hdata->phy_confs = drv_data->phy_confs; + hdata->phy_conf_count = drv_data->phy_conf_count;
hdata->hpd_gpio = pdata->hpd_gpio; hdata->dev = dev; @@ -2103,10 +2133,6 @@ static int hdmi_probe(struct platform_device *pdev) return -ENODEV; }
- /* Not support APB PHY yet. */ - if (drv_data->is_apb_phy) - return -EPERM; - /* hdmiphy i2c driver */ phy_node = of_parse_phandle(dev->of_node, "phy", 0); if (!phy_node) { @@ -2114,11 +2140,21 @@ static int hdmi_probe(struct platform_device *pdev) ret = -ENODEV; goto err_ddc; } - hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node); - if (!hdata->hdmiphy_port) { - DRM_ERROR("Failed to get hdmi phy i2c client from node\n"); - ret = -ENODEV; - goto err_ddc; + + if (drv_data->is_apb_phy) { + hdata->regs_hdmiphy = of_iomap(phy_node, 0); + if (!hdata->regs_hdmiphy) { + DRM_ERROR("failed to ioremap hdmi phy\n"); + ret = -ENOMEM; + goto err_ddc; + } + } else { + hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node); + if (!hdata->hdmiphy_port) { + DRM_ERROR("Failed to get hdmi phy i2c client\n"); + ret = -ENODEV; + goto err_ddc; + } }
hdata->irq = gpio_to_irq(hdata->hpd_gpio); diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h index ef1b3eb..84a69cd 100644 --- a/drivers/gpu/drm/exynos/regs-hdmi.h +++ b/drivers/gpu/drm/exynos/regs-hdmi.h @@ -578,4 +578,11 @@ #define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074) #define HDMI_TG_3D HDMI_TG_BASE(0x00F0)
+/* HDMI PHY Registers Offsets*/ +#define HDMIPHY_MODE_SET_DONE (0x7C >> 2) + +/* HDMI PHY Values */ +#define HDMI_PHY_DISABLE_MODE_SET 0x80 +#define HDMI_PHY_ENABLE_MODE_SET 0x00 + #endif /* SAMSUNG_REGS_HDMI_H */
From: Rahul Sharma Rahul.Sharma@samsung.com
Enable support for hdmi for exynos5420 hdmiphy. Add compatible string in the of_match table. Also added hdmiphy configuration values for exynos5420.
Signed-off-by: Rahul Sharma Rahul.Sharma@samsung.com Signed-off-by: Shirish S s.shirish@samsung.com --- .../devicetree/bindings/video/exynos_hdmi.txt | 1 + drivers/gpu/drm/exynos/exynos_hdmi.c | 165 ++++++++++++++++++++ 2 files changed, 166 insertions(+)
diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt index f9187a2..75ada04 100644 --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt @@ -5,6 +5,7 @@ Required properties: 1) "samsung,exynos5-hdmi" <DEPRECATED> 2) "samsung,exynos4210-hdmi" 3) "samsung,exynos4212-hdmi" + 4) "samsung,exynos5420-hdmi" - reg: physical base address of the hdmi and length of memory mapped region. - interrupts: interrupt number to the cpu. diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index f4566b1..93f48aa 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -425,6 +425,168 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { }, };
+static const struct hdmiphy_config hdmiphy_5420_configs[] = { + { + .pixel_clock = 25200000, + .conf = { + 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8, + 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 27000000, + .conf = { + 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0, + 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 27027000, + .conf = { + 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8, + 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 36000000, + .conf = { + 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8, + 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 40000000, + .conf = { + 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8, + 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 65000000, + .conf = { + 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8, + 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 71000000, + .conf = { + 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8, + 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 73250000, + .conf = { + 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8, + 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 74176000, + .conf = { + 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8, + 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 74250000, + .conf = { + 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08, + 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66, + 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 83500000, + .conf = { + 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8, + 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 88750000, + .conf = { + 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8, + 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 106500000, + .conf = { + 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8, + 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 108000000, + .conf = { + 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8, + 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 115500000, + .conf = { + 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8, + 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 146250000, + .conf = { + 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8, + 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, + 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 148500000, + .conf = { + 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08, + 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66, + 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80, + }, + }, +}; + +struct hdmi_driver_data exynos5420_hdmi_driver_data = { + .type = HDMI_TYPE14, + .phy_confs = hdmiphy_5420_configs, + .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs), + .is_apb_phy = 1, +};
struct hdmi_driver_data exynos4212_hdmi_driver_data = { .type = HDMI_TYPE14, @@ -2062,6 +2224,9 @@ static struct of_device_id hdmi_match_types[] = { .compatible = "samsung,exynos4212-hdmi", .data = &exynos4212_hdmi_driver_data, }, { + .compatible = "samsung,exynos5420-hdmi", + .data = &exynos5420_hdmi_driver_data, + }, { /* end node */ } };
dri-devel@lists.freedesktop.org