18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 Samsung Electronics Co.Ltd 48c2ecf20Sopenharmony_ci * Authors: 58c2ecf20Sopenharmony_ci * Seung-Woo Kim <sw0312.kim@samsung.com> 68c2ecf20Sopenharmony_ci * Inki Dae <inki.dae@samsung.com> 78c2ecf20Sopenharmony_ci * Joonyoung Shim <jy0922.shim@samsung.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on drivers/media/video/s5p-tv/hdmi_drv.c 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <drm/exynos_drm.h> 138c2ecf20Sopenharmony_ci#include <linux/clk.h> 148c2ecf20Sopenharmony_ci#include <linux/component.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/hdmi.h> 188c2ecf20Sopenharmony_ci#include <linux/i2c.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/io.h> 218c2ecf20Sopenharmony_ci#include <linux/irq.h> 228c2ecf20Sopenharmony_ci#include <linux/kernel.h> 238c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 248c2ecf20Sopenharmony_ci#include <linux/of_address.h> 258c2ecf20Sopenharmony_ci#include <linux/of_device.h> 268c2ecf20Sopenharmony_ci#include <linux/of_graph.h> 278c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 288c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 298c2ecf20Sopenharmony_ci#include <linux/regmap.h> 308c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 318c2ecf20Sopenharmony_ci#include <linux/wait.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <sound/hdmi-codec.h> 348c2ecf20Sopenharmony_ci#include <media/cec-notifier.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 378c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h> 388c2ecf20Sopenharmony_ci#include <drm/drm_edid.h> 398c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 408c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 418c2ecf20Sopenharmony_ci#include <drm/drm_simple_kms_helper.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "exynos_drm_crtc.h" 448c2ecf20Sopenharmony_ci#include "regs-hdmi.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define HOTPLUG_DEBOUNCE_MS 1100 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cienum hdmi_type { 498c2ecf20Sopenharmony_ci HDMI_TYPE13, 508c2ecf20Sopenharmony_ci HDMI_TYPE14, 518c2ecf20Sopenharmony_ci HDMI_TYPE_COUNT 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define HDMI_MAPPED_BASE 0xffff0000 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cienum hdmi_mapped_regs { 578c2ecf20Sopenharmony_ci HDMI_PHY_STATUS = HDMI_MAPPED_BASE, 588c2ecf20Sopenharmony_ci HDMI_PHY_RSTOUT, 598c2ecf20Sopenharmony_ci HDMI_ACR_CON, 608c2ecf20Sopenharmony_ci HDMI_ACR_MCTS0, 618c2ecf20Sopenharmony_ci HDMI_ACR_CTS0, 628c2ecf20Sopenharmony_ci HDMI_ACR_N0 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = { 668c2ecf20Sopenharmony_ci { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 }, 678c2ecf20Sopenharmony_ci { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT }, 688c2ecf20Sopenharmony_ci { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON }, 698c2ecf20Sopenharmony_ci { HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 }, 708c2ecf20Sopenharmony_ci { HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 }, 718c2ecf20Sopenharmony_ci { HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 }, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic const char * const supply[] = { 758c2ecf20Sopenharmony_ci "vdd", 768c2ecf20Sopenharmony_ci "vdd_osc", 778c2ecf20Sopenharmony_ci "vdd_pll", 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistruct hdmiphy_config { 818c2ecf20Sopenharmony_ci int pixel_clock; 828c2ecf20Sopenharmony_ci u8 conf[32]; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct hdmiphy_configs { 868c2ecf20Sopenharmony_ci int count; 878c2ecf20Sopenharmony_ci const struct hdmiphy_config *data; 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct string_array_spec { 918c2ecf20Sopenharmony_ci int count; 928c2ecf20Sopenharmony_ci const char * const *data; 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define INIT_ARRAY_SPEC(a) { .count = ARRAY_SIZE(a), .data = a } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistruct hdmi_driver_data { 988c2ecf20Sopenharmony_ci unsigned int type; 998c2ecf20Sopenharmony_ci unsigned int is_apb_phy:1; 1008c2ecf20Sopenharmony_ci unsigned int has_sysreg:1; 1018c2ecf20Sopenharmony_ci struct hdmiphy_configs phy_confs; 1028c2ecf20Sopenharmony_ci struct string_array_spec clk_gates; 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * Array of triplets (p_off, p_on, clock), where p_off and p_on are 1058c2ecf20Sopenharmony_ci * required parents of clock when HDMI-PHY is respectively off or on. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci struct string_array_spec clk_muxes; 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistruct hdmi_audio { 1118c2ecf20Sopenharmony_ci struct platform_device *pdev; 1128c2ecf20Sopenharmony_ci struct hdmi_audio_infoframe infoframe; 1138c2ecf20Sopenharmony_ci struct hdmi_codec_params params; 1148c2ecf20Sopenharmony_ci bool mute; 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistruct hdmi_context { 1188c2ecf20Sopenharmony_ci struct drm_encoder encoder; 1198c2ecf20Sopenharmony_ci struct device *dev; 1208c2ecf20Sopenharmony_ci struct drm_device *drm_dev; 1218c2ecf20Sopenharmony_ci struct drm_connector connector; 1228c2ecf20Sopenharmony_ci bool dvi_mode; 1238c2ecf20Sopenharmony_ci struct delayed_work hotplug_work; 1248c2ecf20Sopenharmony_ci struct cec_notifier *notifier; 1258c2ecf20Sopenharmony_ci const struct hdmi_driver_data *drv_data; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci void __iomem *regs; 1288c2ecf20Sopenharmony_ci void __iomem *regs_hdmiphy; 1298c2ecf20Sopenharmony_ci struct i2c_client *hdmiphy_port; 1308c2ecf20Sopenharmony_ci struct i2c_adapter *ddc_adpt; 1318c2ecf20Sopenharmony_ci struct gpio_desc *hpd_gpio; 1328c2ecf20Sopenharmony_ci int irq; 1338c2ecf20Sopenharmony_ci struct regmap *pmureg; 1348c2ecf20Sopenharmony_ci struct regmap *sysreg; 1358c2ecf20Sopenharmony_ci struct clk **clk_gates; 1368c2ecf20Sopenharmony_ci struct clk **clk_muxes; 1378c2ecf20Sopenharmony_ci struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; 1388c2ecf20Sopenharmony_ci struct regulator *reg_hdmi_en; 1398c2ecf20Sopenharmony_ci struct exynos_drm_clk phy_clk; 1408c2ecf20Sopenharmony_ci struct drm_bridge *bridge; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* mutex protecting subsequent fields below */ 1438c2ecf20Sopenharmony_ci struct mutex mutex; 1448c2ecf20Sopenharmony_ci struct hdmi_audio audio; 1458c2ecf20Sopenharmony_ci bool powered; 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci return container_of(e, struct hdmi_context, encoder); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci return container_of(c, struct hdmi_context, connector); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct hdmiphy_config hdmiphy_v13_configs[] = { 1598c2ecf20Sopenharmony_ci { 1608c2ecf20Sopenharmony_ci .pixel_clock = 27000000, 1618c2ecf20Sopenharmony_ci .conf = { 1628c2ecf20Sopenharmony_ci 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 1638c2ecf20Sopenharmony_ci 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, 1648c2ecf20Sopenharmony_ci 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, 1658c2ecf20Sopenharmony_ci 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80, 1668c2ecf20Sopenharmony_ci }, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci { 1698c2ecf20Sopenharmony_ci .pixel_clock = 27027000, 1708c2ecf20Sopenharmony_ci .conf = { 1718c2ecf20Sopenharmony_ci 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, 1728c2ecf20Sopenharmony_ci 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, 1738c2ecf20Sopenharmony_ci 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, 1748c2ecf20Sopenharmony_ci 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80, 1758c2ecf20Sopenharmony_ci }, 1768c2ecf20Sopenharmony_ci }, 1778c2ecf20Sopenharmony_ci { 1788c2ecf20Sopenharmony_ci .pixel_clock = 74176000, 1798c2ecf20Sopenharmony_ci .conf = { 1808c2ecf20Sopenharmony_ci 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B, 1818c2ecf20Sopenharmony_ci 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9, 1828c2ecf20Sopenharmony_ci 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, 1838c2ecf20Sopenharmony_ci 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80, 1848c2ecf20Sopenharmony_ci }, 1858c2ecf20Sopenharmony_ci }, 1868c2ecf20Sopenharmony_ci { 1878c2ecf20Sopenharmony_ci .pixel_clock = 74250000, 1888c2ecf20Sopenharmony_ci .conf = { 1898c2ecf20Sopenharmony_ci 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40, 1908c2ecf20Sopenharmony_ci 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba, 1918c2ecf20Sopenharmony_ci 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0, 1928c2ecf20Sopenharmony_ci 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80, 1938c2ecf20Sopenharmony_ci }, 1948c2ecf20Sopenharmony_ci }, 1958c2ecf20Sopenharmony_ci { 1968c2ecf20Sopenharmony_ci .pixel_clock = 148500000, 1978c2ecf20Sopenharmony_ci .conf = { 1988c2ecf20Sopenharmony_ci 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40, 1998c2ecf20Sopenharmony_ci 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba, 2008c2ecf20Sopenharmony_ci 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, 2018c2ecf20Sopenharmony_ci 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80, 2028c2ecf20Sopenharmony_ci }, 2038c2ecf20Sopenharmony_ci }, 2048c2ecf20Sopenharmony_ci}; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic const struct hdmiphy_config hdmiphy_v14_configs[] = { 2078c2ecf20Sopenharmony_ci { 2088c2ecf20Sopenharmony_ci .pixel_clock = 25200000, 2098c2ecf20Sopenharmony_ci .conf = { 2108c2ecf20Sopenharmony_ci 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08, 2118c2ecf20Sopenharmony_ci 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80, 2128c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2138c2ecf20Sopenharmony_ci 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 2148c2ecf20Sopenharmony_ci }, 2158c2ecf20Sopenharmony_ci }, 2168c2ecf20Sopenharmony_ci { 2178c2ecf20Sopenharmony_ci .pixel_clock = 27000000, 2188c2ecf20Sopenharmony_ci .conf = { 2198c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20, 2208c2ecf20Sopenharmony_ci 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80, 2218c2ecf20Sopenharmony_ci 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2228c2ecf20Sopenharmony_ci 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 2238c2ecf20Sopenharmony_ci }, 2248c2ecf20Sopenharmony_ci }, 2258c2ecf20Sopenharmony_ci { 2268c2ecf20Sopenharmony_ci .pixel_clock = 27027000, 2278c2ecf20Sopenharmony_ci .conf = { 2288c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08, 2298c2ecf20Sopenharmony_ci 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, 2308c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2318c2ecf20Sopenharmony_ci 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 2328c2ecf20Sopenharmony_ci }, 2338c2ecf20Sopenharmony_ci }, 2348c2ecf20Sopenharmony_ci { 2358c2ecf20Sopenharmony_ci .pixel_clock = 36000000, 2368c2ecf20Sopenharmony_ci .conf = { 2378c2ecf20Sopenharmony_ci 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08, 2388c2ecf20Sopenharmony_ci 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, 2398c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2408c2ecf20Sopenharmony_ci 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 2418c2ecf20Sopenharmony_ci }, 2428c2ecf20Sopenharmony_ci }, 2438c2ecf20Sopenharmony_ci { 2448c2ecf20Sopenharmony_ci .pixel_clock = 40000000, 2458c2ecf20Sopenharmony_ci .conf = { 2468c2ecf20Sopenharmony_ci 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08, 2478c2ecf20Sopenharmony_ci 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80, 2488c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2498c2ecf20Sopenharmony_ci 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 2508c2ecf20Sopenharmony_ci }, 2518c2ecf20Sopenharmony_ci }, 2528c2ecf20Sopenharmony_ci { 2538c2ecf20Sopenharmony_ci .pixel_clock = 65000000, 2548c2ecf20Sopenharmony_ci .conf = { 2558c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08, 2568c2ecf20Sopenharmony_ci 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80, 2578c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2588c2ecf20Sopenharmony_ci 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 2598c2ecf20Sopenharmony_ci }, 2608c2ecf20Sopenharmony_ci }, 2618c2ecf20Sopenharmony_ci { 2628c2ecf20Sopenharmony_ci .pixel_clock = 71000000, 2638c2ecf20Sopenharmony_ci .conf = { 2648c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08, 2658c2ecf20Sopenharmony_ci 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80, 2668c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2678c2ecf20Sopenharmony_ci 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 2688c2ecf20Sopenharmony_ci }, 2698c2ecf20Sopenharmony_ci }, 2708c2ecf20Sopenharmony_ci { 2718c2ecf20Sopenharmony_ci .pixel_clock = 73250000, 2728c2ecf20Sopenharmony_ci .conf = { 2738c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08, 2748c2ecf20Sopenharmony_ci 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80, 2758c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2768c2ecf20Sopenharmony_ci 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 2778c2ecf20Sopenharmony_ci }, 2788c2ecf20Sopenharmony_ci }, 2798c2ecf20Sopenharmony_ci { 2808c2ecf20Sopenharmony_ci .pixel_clock = 74176000, 2818c2ecf20Sopenharmony_ci .conf = { 2828c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08, 2838c2ecf20Sopenharmony_ci 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80, 2848c2ecf20Sopenharmony_ci 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2858c2ecf20Sopenharmony_ci 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 2868c2ecf20Sopenharmony_ci }, 2878c2ecf20Sopenharmony_ci }, 2888c2ecf20Sopenharmony_ci { 2898c2ecf20Sopenharmony_ci .pixel_clock = 74250000, 2908c2ecf20Sopenharmony_ci .conf = { 2918c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08, 2928c2ecf20Sopenharmony_ci 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 2938c2ecf20Sopenharmony_ci 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 2948c2ecf20Sopenharmony_ci 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 2958c2ecf20Sopenharmony_ci }, 2968c2ecf20Sopenharmony_ci }, 2978c2ecf20Sopenharmony_ci { 2988c2ecf20Sopenharmony_ci .pixel_clock = 83500000, 2998c2ecf20Sopenharmony_ci .conf = { 3008c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08, 3018c2ecf20Sopenharmony_ci 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80, 3028c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 3038c2ecf20Sopenharmony_ci 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 3048c2ecf20Sopenharmony_ci }, 3058c2ecf20Sopenharmony_ci }, 3068c2ecf20Sopenharmony_ci { 3078c2ecf20Sopenharmony_ci .pixel_clock = 85500000, 3088c2ecf20Sopenharmony_ci .conf = { 3098c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x24, 0x11, 0x40, 0x40, 0xd0, 0x08, 3108c2ecf20Sopenharmony_ci 0x84, 0xa0, 0xd6, 0xd8, 0x45, 0xa0, 0xac, 0x80, 3118c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 3128c2ecf20Sopenharmony_ci 0x54, 0x90, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 3138c2ecf20Sopenharmony_ci }, 3148c2ecf20Sopenharmony_ci }, 3158c2ecf20Sopenharmony_ci { 3168c2ecf20Sopenharmony_ci .pixel_clock = 106500000, 3178c2ecf20Sopenharmony_ci .conf = { 3188c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08, 3198c2ecf20Sopenharmony_ci 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80, 3208c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 3218c2ecf20Sopenharmony_ci 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 3228c2ecf20Sopenharmony_ci }, 3238c2ecf20Sopenharmony_ci }, 3248c2ecf20Sopenharmony_ci { 3258c2ecf20Sopenharmony_ci .pixel_clock = 108000000, 3268c2ecf20Sopenharmony_ci .conf = { 3278c2ecf20Sopenharmony_ci 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08, 3288c2ecf20Sopenharmony_ci 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, 3298c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 3308c2ecf20Sopenharmony_ci 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, 3318c2ecf20Sopenharmony_ci }, 3328c2ecf20Sopenharmony_ci }, 3338c2ecf20Sopenharmony_ci { 3348c2ecf20Sopenharmony_ci .pixel_clock = 115500000, 3358c2ecf20Sopenharmony_ci .conf = { 3368c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08, 3378c2ecf20Sopenharmony_ci 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80, 3388c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 3398c2ecf20Sopenharmony_ci 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, 3408c2ecf20Sopenharmony_ci }, 3418c2ecf20Sopenharmony_ci }, 3428c2ecf20Sopenharmony_ci { 3438c2ecf20Sopenharmony_ci .pixel_clock = 119000000, 3448c2ecf20Sopenharmony_ci .conf = { 3458c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08, 3468c2ecf20Sopenharmony_ci 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80, 3478c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 3488c2ecf20Sopenharmony_ci 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, 3498c2ecf20Sopenharmony_ci }, 3508c2ecf20Sopenharmony_ci }, 3518c2ecf20Sopenharmony_ci { 3528c2ecf20Sopenharmony_ci .pixel_clock = 146250000, 3538c2ecf20Sopenharmony_ci .conf = { 3548c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08, 3558c2ecf20Sopenharmony_ci 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80, 3568c2ecf20Sopenharmony_ci 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 3578c2ecf20Sopenharmony_ci 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, 3588c2ecf20Sopenharmony_ci }, 3598c2ecf20Sopenharmony_ci }, 3608c2ecf20Sopenharmony_ci { 3618c2ecf20Sopenharmony_ci .pixel_clock = 148500000, 3628c2ecf20Sopenharmony_ci .conf = { 3638c2ecf20Sopenharmony_ci 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08, 3648c2ecf20Sopenharmony_ci 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 3658c2ecf20Sopenharmony_ci 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, 3668c2ecf20Sopenharmony_ci 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, 3678c2ecf20Sopenharmony_ci }, 3688c2ecf20Sopenharmony_ci }, 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic const struct hdmiphy_config hdmiphy_5420_configs[] = { 3728c2ecf20Sopenharmony_ci { 3738c2ecf20Sopenharmony_ci .pixel_clock = 25200000, 3748c2ecf20Sopenharmony_ci .conf = { 3758c2ecf20Sopenharmony_ci 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8, 3768c2ecf20Sopenharmony_ci 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 3778c2ecf20Sopenharmony_ci 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66, 3788c2ecf20Sopenharmony_ci 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 3798c2ecf20Sopenharmony_ci }, 3808c2ecf20Sopenharmony_ci }, 3818c2ecf20Sopenharmony_ci { 3828c2ecf20Sopenharmony_ci .pixel_clock = 27000000, 3838c2ecf20Sopenharmony_ci .conf = { 3848c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0, 3858c2ecf20Sopenharmony_ci 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 3868c2ecf20Sopenharmony_ci 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 3878c2ecf20Sopenharmony_ci 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 3888c2ecf20Sopenharmony_ci }, 3898c2ecf20Sopenharmony_ci }, 3908c2ecf20Sopenharmony_ci { 3918c2ecf20Sopenharmony_ci .pixel_clock = 27027000, 3928c2ecf20Sopenharmony_ci .conf = { 3938c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8, 3948c2ecf20Sopenharmony_ci 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, 3958c2ecf20Sopenharmony_ci 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 3968c2ecf20Sopenharmony_ci 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 3978c2ecf20Sopenharmony_ci }, 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci { 4008c2ecf20Sopenharmony_ci .pixel_clock = 36000000, 4018c2ecf20Sopenharmony_ci .conf = { 4028c2ecf20Sopenharmony_ci 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8, 4038c2ecf20Sopenharmony_ci 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, 4048c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4058c2ecf20Sopenharmony_ci 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 4068c2ecf20Sopenharmony_ci }, 4078c2ecf20Sopenharmony_ci }, 4088c2ecf20Sopenharmony_ci { 4098c2ecf20Sopenharmony_ci .pixel_clock = 40000000, 4108c2ecf20Sopenharmony_ci .conf = { 4118c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8, 4128c2ecf20Sopenharmony_ci 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 4138c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4148c2ecf20Sopenharmony_ci 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 4158c2ecf20Sopenharmony_ci }, 4168c2ecf20Sopenharmony_ci }, 4178c2ecf20Sopenharmony_ci { 4188c2ecf20Sopenharmony_ci .pixel_clock = 65000000, 4198c2ecf20Sopenharmony_ci .conf = { 4208c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8, 4218c2ecf20Sopenharmony_ci 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80, 4228c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4238c2ecf20Sopenharmony_ci 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 4248c2ecf20Sopenharmony_ci }, 4258c2ecf20Sopenharmony_ci }, 4268c2ecf20Sopenharmony_ci { 4278c2ecf20Sopenharmony_ci .pixel_clock = 71000000, 4288c2ecf20Sopenharmony_ci .conf = { 4298c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8, 4308c2ecf20Sopenharmony_ci 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80, 4318c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4328c2ecf20Sopenharmony_ci 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 4338c2ecf20Sopenharmony_ci }, 4348c2ecf20Sopenharmony_ci }, 4358c2ecf20Sopenharmony_ci { 4368c2ecf20Sopenharmony_ci .pixel_clock = 73250000, 4378c2ecf20Sopenharmony_ci .conf = { 4388c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8, 4398c2ecf20Sopenharmony_ci 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 4408c2ecf20Sopenharmony_ci 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4418c2ecf20Sopenharmony_ci 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 4428c2ecf20Sopenharmony_ci }, 4438c2ecf20Sopenharmony_ci }, 4448c2ecf20Sopenharmony_ci { 4458c2ecf20Sopenharmony_ci .pixel_clock = 74176000, 4468c2ecf20Sopenharmony_ci .conf = { 4478c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8, 4488c2ecf20Sopenharmony_ci 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 4498c2ecf20Sopenharmony_ci 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4508c2ecf20Sopenharmony_ci 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 4518c2ecf20Sopenharmony_ci }, 4528c2ecf20Sopenharmony_ci }, 4538c2ecf20Sopenharmony_ci { 4548c2ecf20Sopenharmony_ci .pixel_clock = 74250000, 4558c2ecf20Sopenharmony_ci .conf = { 4568c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08, 4578c2ecf20Sopenharmony_ci 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 4588c2ecf20Sopenharmony_ci 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66, 4598c2ecf20Sopenharmony_ci 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 4608c2ecf20Sopenharmony_ci }, 4618c2ecf20Sopenharmony_ci }, 4628c2ecf20Sopenharmony_ci { 4638c2ecf20Sopenharmony_ci .pixel_clock = 83500000, 4648c2ecf20Sopenharmony_ci .conf = { 4658c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8, 4668c2ecf20Sopenharmony_ci 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 4678c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4688c2ecf20Sopenharmony_ci 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 4698c2ecf20Sopenharmony_ci }, 4708c2ecf20Sopenharmony_ci }, 4718c2ecf20Sopenharmony_ci { 4728c2ecf20Sopenharmony_ci .pixel_clock = 88750000, 4738c2ecf20Sopenharmony_ci .conf = { 4748c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8, 4758c2ecf20Sopenharmony_ci 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 4768c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4778c2ecf20Sopenharmony_ci 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, 4788c2ecf20Sopenharmony_ci }, 4798c2ecf20Sopenharmony_ci }, 4808c2ecf20Sopenharmony_ci { 4818c2ecf20Sopenharmony_ci .pixel_clock = 106500000, 4828c2ecf20Sopenharmony_ci .conf = { 4838c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8, 4848c2ecf20Sopenharmony_ci 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80, 4858c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4868c2ecf20Sopenharmony_ci 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 4878c2ecf20Sopenharmony_ci }, 4888c2ecf20Sopenharmony_ci }, 4898c2ecf20Sopenharmony_ci { 4908c2ecf20Sopenharmony_ci .pixel_clock = 108000000, 4918c2ecf20Sopenharmony_ci .conf = { 4928c2ecf20Sopenharmony_ci 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8, 4938c2ecf20Sopenharmony_ci 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, 4948c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 4958c2ecf20Sopenharmony_ci 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, 4968c2ecf20Sopenharmony_ci }, 4978c2ecf20Sopenharmony_ci }, 4988c2ecf20Sopenharmony_ci { 4998c2ecf20Sopenharmony_ci .pixel_clock = 115500000, 5008c2ecf20Sopenharmony_ci .conf = { 5018c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8, 5028c2ecf20Sopenharmony_ci 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80, 5038c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 5048c2ecf20Sopenharmony_ci 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 5058c2ecf20Sopenharmony_ci }, 5068c2ecf20Sopenharmony_ci }, 5078c2ecf20Sopenharmony_ci { 5088c2ecf20Sopenharmony_ci .pixel_clock = 146250000, 5098c2ecf20Sopenharmony_ci .conf = { 5108c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8, 5118c2ecf20Sopenharmony_ci 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, 5128c2ecf20Sopenharmony_ci 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66, 5138c2ecf20Sopenharmony_ci 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, 5148c2ecf20Sopenharmony_ci }, 5158c2ecf20Sopenharmony_ci }, 5168c2ecf20Sopenharmony_ci { 5178c2ecf20Sopenharmony_ci .pixel_clock = 148500000, 5188c2ecf20Sopenharmony_ci .conf = { 5198c2ecf20Sopenharmony_ci 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08, 5208c2ecf20Sopenharmony_ci 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, 5218c2ecf20Sopenharmony_ci 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66, 5228c2ecf20Sopenharmony_ci 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80, 5238c2ecf20Sopenharmony_ci }, 5248c2ecf20Sopenharmony_ci }, 5258c2ecf20Sopenharmony_ci}; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic const struct hdmiphy_config hdmiphy_5433_configs[] = { 5288c2ecf20Sopenharmony_ci { 5298c2ecf20Sopenharmony_ci .pixel_clock = 27000000, 5308c2ecf20Sopenharmony_ci .conf = { 5318c2ecf20Sopenharmony_ci 0x01, 0x51, 0x2d, 0x75, 0x01, 0x00, 0x88, 0x02, 5328c2ecf20Sopenharmony_ci 0x72, 0x50, 0x44, 0x8c, 0x27, 0x00, 0x7c, 0xac, 5338c2ecf20Sopenharmony_ci 0xd6, 0x2b, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 5348c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 5358c2ecf20Sopenharmony_ci }, 5368c2ecf20Sopenharmony_ci }, 5378c2ecf20Sopenharmony_ci { 5388c2ecf20Sopenharmony_ci .pixel_clock = 27027000, 5398c2ecf20Sopenharmony_ci .conf = { 5408c2ecf20Sopenharmony_ci 0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3, 5418c2ecf20Sopenharmony_ci 0x71, 0x50, 0x44, 0x8c, 0x27, 0x00, 0x7c, 0xac, 5428c2ecf20Sopenharmony_ci 0xd6, 0x2b, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 5438c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 5448c2ecf20Sopenharmony_ci }, 5458c2ecf20Sopenharmony_ci }, 5468c2ecf20Sopenharmony_ci { 5478c2ecf20Sopenharmony_ci .pixel_clock = 40000000, 5488c2ecf20Sopenharmony_ci .conf = { 5498c2ecf20Sopenharmony_ci 0x01, 0x51, 0x32, 0x55, 0x01, 0x00, 0x88, 0x02, 5508c2ecf20Sopenharmony_ci 0x4d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, 5518c2ecf20Sopenharmony_ci 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 5528c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 5538c2ecf20Sopenharmony_ci }, 5548c2ecf20Sopenharmony_ci }, 5558c2ecf20Sopenharmony_ci { 5568c2ecf20Sopenharmony_ci .pixel_clock = 50000000, 5578c2ecf20Sopenharmony_ci .conf = { 5588c2ecf20Sopenharmony_ci 0x01, 0x51, 0x34, 0x40, 0x64, 0x09, 0x88, 0xc3, 5598c2ecf20Sopenharmony_ci 0x3d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, 5608c2ecf20Sopenharmony_ci 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 5618c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 5628c2ecf20Sopenharmony_ci }, 5638c2ecf20Sopenharmony_ci }, 5648c2ecf20Sopenharmony_ci { 5658c2ecf20Sopenharmony_ci .pixel_clock = 65000000, 5668c2ecf20Sopenharmony_ci .conf = { 5678c2ecf20Sopenharmony_ci 0x01, 0x51, 0x36, 0x31, 0x40, 0x10, 0x04, 0xc6, 5688c2ecf20Sopenharmony_ci 0x2e, 0xe8, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, 5698c2ecf20Sopenharmony_ci 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 5708c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 5718c2ecf20Sopenharmony_ci }, 5728c2ecf20Sopenharmony_ci }, 5738c2ecf20Sopenharmony_ci { 5748c2ecf20Sopenharmony_ci .pixel_clock = 74176000, 5758c2ecf20Sopenharmony_ci .conf = { 5768c2ecf20Sopenharmony_ci 0x01, 0x51, 0x3E, 0x35, 0x5B, 0xDE, 0x88, 0x42, 5778c2ecf20Sopenharmony_ci 0x53, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, 5788c2ecf20Sopenharmony_ci 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 5798c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 5808c2ecf20Sopenharmony_ci }, 5818c2ecf20Sopenharmony_ci }, 5828c2ecf20Sopenharmony_ci { 5838c2ecf20Sopenharmony_ci .pixel_clock = 74250000, 5848c2ecf20Sopenharmony_ci .conf = { 5858c2ecf20Sopenharmony_ci 0x01, 0x51, 0x3E, 0x35, 0x40, 0xF0, 0x88, 0xC2, 5868c2ecf20Sopenharmony_ci 0x52, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, 5878c2ecf20Sopenharmony_ci 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 5888c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 5898c2ecf20Sopenharmony_ci }, 5908c2ecf20Sopenharmony_ci }, 5918c2ecf20Sopenharmony_ci { 5928c2ecf20Sopenharmony_ci .pixel_clock = 108000000, 5938c2ecf20Sopenharmony_ci .conf = { 5948c2ecf20Sopenharmony_ci 0x01, 0x51, 0x2d, 0x15, 0x01, 0x00, 0x88, 0x02, 5958c2ecf20Sopenharmony_ci 0x72, 0x52, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, 5968c2ecf20Sopenharmony_ci 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 5978c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 5988c2ecf20Sopenharmony_ci }, 5998c2ecf20Sopenharmony_ci }, 6008c2ecf20Sopenharmony_ci { 6018c2ecf20Sopenharmony_ci .pixel_clock = 148500000, 6028c2ecf20Sopenharmony_ci .conf = { 6038c2ecf20Sopenharmony_ci 0x01, 0x51, 0x1f, 0x00, 0x40, 0xf8, 0x88, 0xc1, 6048c2ecf20Sopenharmony_ci 0x52, 0x52, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5, 6058c2ecf20Sopenharmony_ci 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30, 6068c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x4a, 0x00, 0x40, 6078c2ecf20Sopenharmony_ci }, 6088c2ecf20Sopenharmony_ci }, 6098c2ecf20Sopenharmony_ci { 6108c2ecf20Sopenharmony_ci .pixel_clock = 297000000, 6118c2ecf20Sopenharmony_ci .conf = { 6128c2ecf20Sopenharmony_ci 0x01, 0x51, 0x3E, 0x05, 0x40, 0xF0, 0x88, 0xC2, 6138c2ecf20Sopenharmony_ci 0x52, 0x53, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, 6148c2ecf20Sopenharmony_ci 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 6158c2ecf20Sopenharmony_ci 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 6168c2ecf20Sopenharmony_ci }, 6178c2ecf20Sopenharmony_ci }, 6188c2ecf20Sopenharmony_ci}; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic const char * const hdmi_clk_gates4[] = { 6218c2ecf20Sopenharmony_ci "hdmi", "sclk_hdmi" 6228c2ecf20Sopenharmony_ci}; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic const char * const hdmi_clk_muxes4[] = { 6258c2ecf20Sopenharmony_ci "sclk_pixel", "sclk_hdmiphy", "mout_hdmi" 6268c2ecf20Sopenharmony_ci}; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic const char * const hdmi_clk_gates5433[] = { 6298c2ecf20Sopenharmony_ci "hdmi_pclk", "hdmi_i_pclk", "i_tmds_clk", "i_pixel_clk", "i_spdif_clk" 6308c2ecf20Sopenharmony_ci}; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic const char * const hdmi_clk_muxes5433[] = { 6338c2ecf20Sopenharmony_ci "oscclk", "tmds_clko", "tmds_clko_user", 6348c2ecf20Sopenharmony_ci "oscclk", "pixel_clko", "pixel_clko_user" 6358c2ecf20Sopenharmony_ci}; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic const struct hdmi_driver_data exynos4210_hdmi_driver_data = { 6388c2ecf20Sopenharmony_ci .type = HDMI_TYPE13, 6398c2ecf20Sopenharmony_ci .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v13_configs), 6408c2ecf20Sopenharmony_ci .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4), 6418c2ecf20Sopenharmony_ci .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4), 6428c2ecf20Sopenharmony_ci}; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic const struct hdmi_driver_data exynos4212_hdmi_driver_data = { 6458c2ecf20Sopenharmony_ci .type = HDMI_TYPE14, 6468c2ecf20Sopenharmony_ci .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v14_configs), 6478c2ecf20Sopenharmony_ci .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4), 6488c2ecf20Sopenharmony_ci .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4), 6498c2ecf20Sopenharmony_ci}; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic const struct hdmi_driver_data exynos5420_hdmi_driver_data = { 6528c2ecf20Sopenharmony_ci .type = HDMI_TYPE14, 6538c2ecf20Sopenharmony_ci .is_apb_phy = 1, 6548c2ecf20Sopenharmony_ci .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5420_configs), 6558c2ecf20Sopenharmony_ci .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4), 6568c2ecf20Sopenharmony_ci .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4), 6578c2ecf20Sopenharmony_ci}; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic const struct hdmi_driver_data exynos5433_hdmi_driver_data = { 6608c2ecf20Sopenharmony_ci .type = HDMI_TYPE14, 6618c2ecf20Sopenharmony_ci .is_apb_phy = 1, 6628c2ecf20Sopenharmony_ci .has_sysreg = 1, 6638c2ecf20Sopenharmony_ci .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5433_configs), 6648c2ecf20Sopenharmony_ci .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates5433), 6658c2ecf20Sopenharmony_ci .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes5433), 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE) 6718c2ecf20Sopenharmony_ci return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type]; 6728c2ecf20Sopenharmony_ci return reg_id; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci return readl(hdata->regs + hdmi_map_reg(hdata, reg_id)); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic inline void hdmi_reg_writeb(struct hdmi_context *hdata, 6818c2ecf20Sopenharmony_ci u32 reg_id, u8 value) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id)); 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id, 6878c2ecf20Sopenharmony_ci int bytes, u32 val) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci reg_id = hdmi_map_reg(hdata, reg_id); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci while (--bytes >= 0) { 6928c2ecf20Sopenharmony_ci writel(val & 0xff, hdata->regs + reg_id); 6938c2ecf20Sopenharmony_ci val >>= 8; 6948c2ecf20Sopenharmony_ci reg_id += 4; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic inline void hdmi_reg_write_buf(struct hdmi_context *hdata, u32 reg_id, 6998c2ecf20Sopenharmony_ci u8 *buf, int size) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci for (reg_id = hdmi_map_reg(hdata, reg_id); size; --size, reg_id += 4) 7028c2ecf20Sopenharmony_ci writel(*buf++, hdata->regs + reg_id); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic inline void hdmi_reg_writemask(struct hdmi_context *hdata, 7068c2ecf20Sopenharmony_ci u32 reg_id, u32 value, u32 mask) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci u32 old; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci reg_id = hdmi_map_reg(hdata, reg_id); 7118c2ecf20Sopenharmony_ci old = readl(hdata->regs + reg_id); 7128c2ecf20Sopenharmony_ci value = (value & mask) | (old & ~mask); 7138c2ecf20Sopenharmony_ci writel(value, hdata->regs + reg_id); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int hdmiphy_reg_write_buf(struct hdmi_context *hdata, 7178c2ecf20Sopenharmony_ci u32 reg_offset, const u8 *buf, u32 len) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci if ((reg_offset + len) > 32) 7208c2ecf20Sopenharmony_ci return -EINVAL; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (hdata->hdmiphy_port) { 7238c2ecf20Sopenharmony_ci int ret; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci ret = i2c_master_send(hdata->hdmiphy_port, buf, len); 7268c2ecf20Sopenharmony_ci if (ret == len) 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci return ret; 7298c2ecf20Sopenharmony_ci } else { 7308c2ecf20Sopenharmony_ci int i; 7318c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 7328c2ecf20Sopenharmony_ci writel(buf[i], hdata->regs_hdmiphy + 7338c2ecf20Sopenharmony_ci ((reg_offset + i)<<2)); 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic int hdmi_clk_enable_gates(struct hdmi_context *hdata) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci int i, ret; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci for (i = 0; i < hdata->drv_data->clk_gates.count; ++i) { 7438c2ecf20Sopenharmony_ci ret = clk_prepare_enable(hdata->clk_gates[i]); 7448c2ecf20Sopenharmony_ci if (!ret) 7458c2ecf20Sopenharmony_ci continue; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci dev_err(hdata->dev, "Cannot enable clock '%s', %d\n", 7488c2ecf20Sopenharmony_ci hdata->drv_data->clk_gates.data[i], ret); 7498c2ecf20Sopenharmony_ci while (i--) 7508c2ecf20Sopenharmony_ci clk_disable_unprepare(hdata->clk_gates[i]); 7518c2ecf20Sopenharmony_ci return ret; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci return 0; 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic void hdmi_clk_disable_gates(struct hdmi_context *hdata) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci int i = hdata->drv_data->clk_gates.count; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci while (i--) 7628c2ecf20Sopenharmony_ci clk_disable_unprepare(hdata->clk_gates[i]); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct device *dev = hdata->dev; 7688c2ecf20Sopenharmony_ci int ret = 0; 7698c2ecf20Sopenharmony_ci int i; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci for (i = 0; i < hdata->drv_data->clk_muxes.count; i += 3) { 7728c2ecf20Sopenharmony_ci struct clk **c = &hdata->clk_muxes[i]; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci ret = clk_set_parent(c[2], c[to_phy]); 7758c2ecf20Sopenharmony_ci if (!ret) 7768c2ecf20Sopenharmony_ci continue; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci dev_err(dev, "Cannot set clock parent of '%s' to '%s', %d\n", 7798c2ecf20Sopenharmony_ci hdata->drv_data->clk_muxes.data[i + 2], 7808c2ecf20Sopenharmony_ci hdata->drv_data->clk_muxes.data[i + to_phy], ret); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return ret; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic int hdmi_audio_infoframe_apply(struct hdmi_context *hdata) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct hdmi_audio_infoframe *infoframe = &hdata->audio.infoframe; 7898c2ecf20Sopenharmony_ci u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)]; 7908c2ecf20Sopenharmony_ci int len; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci len = hdmi_audio_infoframe_pack(infoframe, buf, sizeof(buf)); 7938c2ecf20Sopenharmony_ci if (len < 0) 7948c2ecf20Sopenharmony_ci return len; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_EVERY_VSYNC); 7978c2ecf20Sopenharmony_ci hdmi_reg_write_buf(hdata, HDMI_AUI_HEADER0, buf, len); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic void hdmi_reg_infoframes(struct hdmi_context *hdata) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci struct drm_display_mode *m = &hdata->encoder.crtc->state->mode; 8058c2ecf20Sopenharmony_ci union hdmi_infoframe frm; 8068c2ecf20Sopenharmony_ci u8 buf[25]; 8078c2ecf20Sopenharmony_ci int ret; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (hdata->dvi_mode) { 8108c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_AVI_CON, 8118c2ecf20Sopenharmony_ci HDMI_AVI_CON_DO_NOT_TRANSMIT); 8128c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_VSI_CON, 8138c2ecf20Sopenharmony_ci HDMI_VSI_CON_DO_NOT_TRANSMIT); 8148c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN); 8158c2ecf20Sopenharmony_ci return; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, 8198c2ecf20Sopenharmony_ci &hdata->connector, m); 8208c2ecf20Sopenharmony_ci if (!ret) 8218c2ecf20Sopenharmony_ci ret = hdmi_avi_infoframe_pack(&frm.avi, buf, sizeof(buf)); 8228c2ecf20Sopenharmony_ci if (ret > 0) { 8238c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC); 8248c2ecf20Sopenharmony_ci hdmi_reg_write_buf(hdata, HDMI_AVI_HEADER0, buf, ret); 8258c2ecf20Sopenharmony_ci } else { 8268c2ecf20Sopenharmony_ci DRM_INFO("%s: invalid AVI infoframe (%d)\n", __func__, ret); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci ret = drm_hdmi_vendor_infoframe_from_display_mode(&frm.vendor.hdmi, 8308c2ecf20Sopenharmony_ci &hdata->connector, m); 8318c2ecf20Sopenharmony_ci if (!ret) 8328c2ecf20Sopenharmony_ci ret = hdmi_vendor_infoframe_pack(&frm.vendor.hdmi, buf, 8338c2ecf20Sopenharmony_ci sizeof(buf)); 8348c2ecf20Sopenharmony_ci if (ret > 0) { 8358c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_VSI_CON, HDMI_VSI_CON_EVERY_VSYNC); 8368c2ecf20Sopenharmony_ci hdmi_reg_write_buf(hdata, HDMI_VSI_HEADER0, buf, 3); 8378c2ecf20Sopenharmony_ci hdmi_reg_write_buf(hdata, HDMI_VSI_DATA(0), buf + 3, ret - 3); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci hdmi_audio_infoframe_apply(hdata); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic enum drm_connector_status hdmi_detect(struct drm_connector *connector, 8448c2ecf20Sopenharmony_ci bool force) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct hdmi_context *hdata = connector_to_hdmi(connector); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (gpiod_get_value(hdata->hpd_gpio)) 8498c2ecf20Sopenharmony_ci return connector_status_connected; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci cec_notifier_set_phys_addr(hdata->notifier, CEC_PHYS_ADDR_INVALID); 8528c2ecf20Sopenharmony_ci return connector_status_disconnected; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic void hdmi_connector_destroy(struct drm_connector *connector) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci struct hdmi_context *hdata = connector_to_hdmi(connector); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci cec_notifier_conn_unregister(hdata->notifier); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci drm_connector_unregister(connector); 8628c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs hdmi_connector_funcs = { 8668c2ecf20Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 8678c2ecf20Sopenharmony_ci .detect = hdmi_detect, 8688c2ecf20Sopenharmony_ci .destroy = hdmi_connector_destroy, 8698c2ecf20Sopenharmony_ci .reset = drm_atomic_helper_connector_reset, 8708c2ecf20Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 8718c2ecf20Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 8728c2ecf20Sopenharmony_ci}; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic int hdmi_get_modes(struct drm_connector *connector) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct hdmi_context *hdata = connector_to_hdmi(connector); 8778c2ecf20Sopenharmony_ci struct edid *edid; 8788c2ecf20Sopenharmony_ci int ret; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (!hdata->ddc_adpt) 8818c2ecf20Sopenharmony_ci return -ENODEV; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci edid = drm_get_edid(connector, hdata->ddc_adpt); 8848c2ecf20Sopenharmony_ci if (!edid) 8858c2ecf20Sopenharmony_ci return -ENODEV; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci hdata->dvi_mode = !drm_detect_hdmi_monitor(edid); 8888c2ecf20Sopenharmony_ci DRM_DEV_DEBUG_KMS(hdata->dev, "%s : width[%d] x height[%d]\n", 8898c2ecf20Sopenharmony_ci (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"), 8908c2ecf20Sopenharmony_ci edid->width_cm, edid->height_cm); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci drm_connector_update_edid_property(connector, edid); 8938c2ecf20Sopenharmony_ci cec_notifier_set_phys_addr_from_edid(hdata->notifier, edid); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci ret = drm_add_edid_modes(connector, edid); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci kfree(edid); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci return ret; 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci const struct hdmiphy_configs *confs = &hdata->drv_data->phy_confs; 9058c2ecf20Sopenharmony_ci int i; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci for (i = 0; i < confs->count; i++) 9088c2ecf20Sopenharmony_ci if (confs->data[i].pixel_clock == pixel_clock) 9098c2ecf20Sopenharmony_ci return i; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci DRM_DEV_DEBUG_KMS(hdata->dev, "Could not find phy config for %d\n", 9128c2ecf20Sopenharmony_ci pixel_clock); 9138c2ecf20Sopenharmony_ci return -EINVAL; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int hdmi_mode_valid(struct drm_connector *connector, 9178c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci struct hdmi_context *hdata = connector_to_hdmi(connector); 9208c2ecf20Sopenharmony_ci int ret; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci DRM_DEV_DEBUG_KMS(hdata->dev, 9238c2ecf20Sopenharmony_ci "xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n", 9248c2ecf20Sopenharmony_ci mode->hdisplay, mode->vdisplay, 9258c2ecf20Sopenharmony_ci drm_mode_vrefresh(mode), 9268c2ecf20Sopenharmony_ci (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true : 9278c2ecf20Sopenharmony_ci false, mode->clock * 1000); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci ret = hdmi_find_phy_conf(hdata, mode->clock * 1000); 9308c2ecf20Sopenharmony_ci if (ret < 0) 9318c2ecf20Sopenharmony_ci return MODE_BAD; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci return MODE_OK; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { 9378c2ecf20Sopenharmony_ci .get_modes = hdmi_get_modes, 9388c2ecf20Sopenharmony_ci .mode_valid = hdmi_mode_valid, 9398c2ecf20Sopenharmony_ci}; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic int hdmi_create_connector(struct drm_encoder *encoder) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct hdmi_context *hdata = encoder_to_hdmi(encoder); 9448c2ecf20Sopenharmony_ci struct drm_connector *connector = &hdata->connector; 9458c2ecf20Sopenharmony_ci struct cec_connector_info conn_info; 9468c2ecf20Sopenharmony_ci int ret; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci connector->interlace_allowed = true; 9498c2ecf20Sopenharmony_ci connector->polled = DRM_CONNECTOR_POLL_HPD; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci ret = drm_connector_init_with_ddc(hdata->drm_dev, connector, 9528c2ecf20Sopenharmony_ci &hdmi_connector_funcs, 9538c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_HDMIA, 9548c2ecf20Sopenharmony_ci hdata->ddc_adpt); 9558c2ecf20Sopenharmony_ci if (ret) { 9568c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, 9578c2ecf20Sopenharmony_ci "Failed to initialize connector with drm\n"); 9588c2ecf20Sopenharmony_ci return ret; 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); 9628c2ecf20Sopenharmony_ci drm_connector_attach_encoder(connector, encoder); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (hdata->bridge) { 9658c2ecf20Sopenharmony_ci ret = drm_bridge_attach(encoder, hdata->bridge, NULL, 0); 9668c2ecf20Sopenharmony_ci if (ret) 9678c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, "Failed to attach bridge\n"); 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci cec_fill_conn_info_from_drm(&conn_info, connector); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci hdata->notifier = cec_notifier_conn_register(hdata->dev, NULL, 9738c2ecf20Sopenharmony_ci &conn_info); 9748c2ecf20Sopenharmony_ci if (!hdata->notifier) { 9758c2ecf20Sopenharmony_ci ret = -ENOMEM; 9768c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, "Failed to allocate CEC notifier\n"); 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci return ret; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic bool hdmi_mode_fixup(struct drm_encoder *encoder, 9838c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 9848c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 9878c2ecf20Sopenharmony_ci struct drm_connector *connector; 9888c2ecf20Sopenharmony_ci struct drm_display_mode *m; 9898c2ecf20Sopenharmony_ci struct drm_connector_list_iter conn_iter; 9908c2ecf20Sopenharmony_ci int mode_ok; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci drm_mode_set_crtcinfo(adjusted_mode, 0); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci drm_connector_list_iter_begin(dev, &conn_iter); 9958c2ecf20Sopenharmony_ci drm_for_each_connector_iter(connector, &conn_iter) { 9968c2ecf20Sopenharmony_ci if (connector->encoder == encoder) 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci if (connector) 10008c2ecf20Sopenharmony_ci drm_connector_get(connector); 10018c2ecf20Sopenharmony_ci drm_connector_list_iter_end(&conn_iter); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (!connector) 10048c2ecf20Sopenharmony_ci return true; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci mode_ok = hdmi_mode_valid(connector, adjusted_mode); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (mode_ok == MODE_OK) 10098c2ecf20Sopenharmony_ci goto cleanup; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* 10128c2ecf20Sopenharmony_ci * Find the most suitable mode and copy it to adjusted_mode. 10138c2ecf20Sopenharmony_ci */ 10148c2ecf20Sopenharmony_ci list_for_each_entry(m, &connector->modes, head) { 10158c2ecf20Sopenharmony_ci mode_ok = hdmi_mode_valid(connector, m); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (mode_ok == MODE_OK) { 10188c2ecf20Sopenharmony_ci DRM_INFO("desired mode doesn't exist so\n"); 10198c2ecf20Sopenharmony_ci DRM_INFO("use the most suitable mode among modes.\n"); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci DRM_DEV_DEBUG_KMS(dev->dev, 10228c2ecf20Sopenharmony_ci "Adjusted Mode: [%d]x[%d] [%d]Hz\n", 10238c2ecf20Sopenharmony_ci m->hdisplay, m->vdisplay, 10248c2ecf20Sopenharmony_ci drm_mode_vrefresh(m)); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci drm_mode_copy(adjusted_mode, m); 10278c2ecf20Sopenharmony_ci break; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cicleanup: 10328c2ecf20Sopenharmony_ci drm_connector_put(connector); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci return true; 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci u32 n, cts; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci cts = (freq % 9) ? 27000 : 30000; 10428c2ecf20Sopenharmony_ci n = 128 * freq / (27000000 / cts); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n); 10458c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts); 10468c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts); 10478c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic void hdmi_audio_config(struct hdmi_context *hdata) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci u32 bit_ch = 1; 10538c2ecf20Sopenharmony_ci u32 data_num, val; 10548c2ecf20Sopenharmony_ci int i; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci switch (hdata->audio.params.sample_width) { 10578c2ecf20Sopenharmony_ci case 20: 10588c2ecf20Sopenharmony_ci data_num = 2; 10598c2ecf20Sopenharmony_ci break; 10608c2ecf20Sopenharmony_ci case 24: 10618c2ecf20Sopenharmony_ci data_num = 3; 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci default: 10648c2ecf20Sopenharmony_ci data_num = 1; 10658c2ecf20Sopenharmony_ci bit_ch = 0; 10668c2ecf20Sopenharmony_ci break; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci hdmi_reg_acr(hdata, hdata->audio.params.sample_rate); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE 10728c2ecf20Sopenharmony_ci | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE 10738c2ecf20Sopenharmony_ci | HDMI_I2S_MUX_ENABLE); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN 10768c2ecf20Sopenharmony_ci | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN); 10798c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS); 10808c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01; 10838c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */ 10868c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5) 10878c2ecf20Sopenharmony_ci | HDMI_I2S_SEL_LRCK(6)); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(3) 10908c2ecf20Sopenharmony_ci | HDMI_I2S_SEL_SDATA0(4)); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1) 10938c2ecf20Sopenharmony_ci | HDMI_I2S_SEL_SDATA2(2)); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0)); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* I2S_CON_1 & 2 */ 10988c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE 10998c2ecf20Sopenharmony_ci | HDMI_I2S_L_CH_LOW_POL); 11008c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE 11018c2ecf20Sopenharmony_ci | HDMI_I2S_SET_BIT_CH(bit_ch) 11028c2ecf20Sopenharmony_ci | HDMI_I2S_SET_SDATA_BIT(data_num) 11038c2ecf20Sopenharmony_ci | HDMI_I2S_BASIC_FORMAT); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* Configuration of the audio channel status registers */ 11068c2ecf20Sopenharmony_ci for (i = 0; i < HDMI_I2S_CH_ST_MAXNUM; i++) 11078c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST(i), 11088c2ecf20Sopenharmony_ci hdata->audio.params.iec.status[i]); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD); 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic void hdmi_audio_control(struct hdmi_context *hdata) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci bool enable = !hdata->audio.mute; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (hdata->dvi_mode) 11188c2ecf20Sopenharmony_ci return; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_AUI_CON, enable ? 11218c2ecf20Sopenharmony_ci HDMI_AVI_CON_EVERY_VSYNC : HDMI_AUI_CON_NO_TRAN); 11228c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_CON_0, enable ? 11238c2ecf20Sopenharmony_ci HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK); 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic void hdmi_start(struct hdmi_context *hdata, bool start) 11278c2ecf20Sopenharmony_ci{ 11288c2ecf20Sopenharmony_ci struct drm_display_mode *m = &hdata->encoder.crtc->state->mode; 11298c2ecf20Sopenharmony_ci u32 val = start ? HDMI_TG_EN : 0; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (m->flags & DRM_MODE_FLAG_INTERLACE) 11328c2ecf20Sopenharmony_ci val |= HDMI_FIELD_EN; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN); 11358c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic void hdmi_conf_init(struct hdmi_context *hdata) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci /* disable HPD interrupts from HDMI IP block, use GPIO instead */ 11418c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL | 11428c2ecf20Sopenharmony_ci HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* choose HDMI mode */ 11458c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_MODE_SEL, 11468c2ecf20Sopenharmony_ci HDMI_MODE_HDMI_EN, HDMI_MODE_MASK); 11478c2ecf20Sopenharmony_ci /* apply video pre-amble and guard band in HDMI mode only */ 11488c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_CON_2, 0); 11498c2ecf20Sopenharmony_ci /* disable bluescreen */ 11508c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (hdata->dvi_mode) { 11538c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_MODE_SEL, 11548c2ecf20Sopenharmony_ci HDMI_MODE_DVI_EN, HDMI_MODE_MASK); 11558c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_CON_2, 11568c2ecf20Sopenharmony_ci HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (hdata->drv_data->type == HDMI_TYPE13) { 11608c2ecf20Sopenharmony_ci /* choose bluescreen (fecal) color */ 11618c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12); 11628c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34); 11638c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* enable AVI packet every vsync, fixes purple line problem */ 11668c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02); 11678c2ecf20Sopenharmony_ci /* force RGB, look to CEA-861-D, table 7 for more detail */ 11688c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5); 11698c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02); 11728c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02); 11738c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04); 11748c2ecf20Sopenharmony_ci } else { 11758c2ecf20Sopenharmony_ci hdmi_reg_infoframes(hdata); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* enable AVI packet every vsync, fixes purple line problem */ 11788c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5); 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci} 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic void hdmiphy_wait_for_pll(struct hdmi_context *hdata) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci int tries; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci for (tries = 0; tries < 10; ++tries) { 11878c2ecf20Sopenharmony_ci u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (val & HDMI_PHY_STATUS_READY) { 11908c2ecf20Sopenharmony_ci DRM_DEV_DEBUG_KMS(hdata->dev, 11918c2ecf20Sopenharmony_ci "PLL stabilized after %d tries\n", 11928c2ecf20Sopenharmony_ci tries); 11938c2ecf20Sopenharmony_ci return; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci usleep_range(10, 20); 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, "PLL could not reach steady state\n"); 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic void hdmi_v13_mode_apply(struct hdmi_context *hdata) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci struct drm_display_mode *m = &hdata->encoder.crtc->state->mode; 12048c2ecf20Sopenharmony_ci unsigned int val; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); 12078c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3, 12088c2ecf20Sopenharmony_ci (m->htotal << 12) | m->vtotal); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; 12118c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0; 12148c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci val = (m->hsync_start - m->hdisplay - 2); 12178c2ecf20Sopenharmony_ci val |= ((m->hsync_end - m->hdisplay - 2) << 10); 12188c2ecf20Sopenharmony_ci val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20; 12198c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci /* 12228c2ecf20Sopenharmony_ci * Quirk requirement for exynos HDMI IP design, 12238c2ecf20Sopenharmony_ci * 2 pixels less than the actual calculation for hsync_start 12248c2ecf20Sopenharmony_ci * and end. 12258c2ecf20Sopenharmony_ci */ 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci /* Following values & calculations differ for different type of modes */ 12288c2ecf20Sopenharmony_ci if (m->flags & DRM_MODE_FLAG_INTERLACE) { 12298c2ecf20Sopenharmony_ci val = ((m->vsync_end - m->vdisplay) / 2); 12308c2ecf20Sopenharmony_ci val |= ((m->vsync_start - m->vdisplay) / 2) << 12; 12318c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci val = m->vtotal / 2; 12348c2ecf20Sopenharmony_ci val |= ((m->vtotal - m->vdisplay) / 2) << 11; 12358c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci val = (m->vtotal + 12388c2ecf20Sopenharmony_ci ((m->vsync_end - m->vsync_start) * 4) + 5) / 2; 12398c2ecf20Sopenharmony_ci val |= m->vtotal << 11; 12408c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci val = ((m->vtotal / 2) + 7); 12438c2ecf20Sopenharmony_ci val |= ((m->vtotal / 2) + 2) << 12; 12448c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay)); 12478c2ecf20Sopenharmony_ci val |= ((m->htotal / 2) + 12488c2ecf20Sopenharmony_ci (m->hsync_start - m->hdisplay)) << 12; 12498c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, 12528c2ecf20Sopenharmony_ci (m->vtotal - m->vdisplay) / 2); 12538c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249); 12568c2ecf20Sopenharmony_ci } else { 12578c2ecf20Sopenharmony_ci val = m->vtotal; 12588c2ecf20Sopenharmony_ci val |= (m->vtotal - m->vdisplay) << 11; 12598c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci val = (m->vsync_end - m->vdisplay); 12648c2ecf20Sopenharmony_ci val |= ((m->vsync_start - m->vdisplay) << 12); 12658c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001); 12688c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001); 12698c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, 12708c2ecf20Sopenharmony_ci m->vtotal - m->vdisplay); 12718c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); 12758c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); 12768c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); 12778c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic void hdmi_v14_mode_apply(struct hdmi_context *hdata) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci struct drm_display_mode *m = &hdata->encoder.crtc->state->mode; 12838c2ecf20Sopenharmony_ci struct drm_display_mode *am = 12848c2ecf20Sopenharmony_ci &hdata->encoder.crtc->state->adjusted_mode; 12858c2ecf20Sopenharmony_ci int hquirk = 0; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci /* 12888c2ecf20Sopenharmony_ci * In case video mode coming from CRTC differs from requested one HDMI 12898c2ecf20Sopenharmony_ci * sometimes is able to almost properly perform conversion - only 12908c2ecf20Sopenharmony_ci * first line is distorted. 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_ci if ((m->vdisplay != am->vdisplay) && 12938c2ecf20Sopenharmony_ci (m->hdisplay == 1280 || m->hdisplay == 1024 || m->hdisplay == 1366)) 12948c2ecf20Sopenharmony_ci hquirk = 258; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); 12978c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal); 12988c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal); 12998c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1, 13008c2ecf20Sopenharmony_ci (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); 13018c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, 13028c2ecf20Sopenharmony_ci (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0); 13038c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, 13048c2ecf20Sopenharmony_ci (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* 13078c2ecf20Sopenharmony_ci * Quirk requirement for exynos 5 HDMI IP design, 13088c2ecf20Sopenharmony_ci * 2 pixels less than the actual calculation for hsync_start 13098c2ecf20Sopenharmony_ci * and end. 13108c2ecf20Sopenharmony_ci */ 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* Following values & calculations differ for different type of modes */ 13138c2ecf20Sopenharmony_ci if (m->flags & DRM_MODE_FLAG_INTERLACE) { 13148c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, 13158c2ecf20Sopenharmony_ci (m->vsync_end - m->vdisplay) / 2); 13168c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, 13178c2ecf20Sopenharmony_ci (m->vsync_start - m->vdisplay) / 2); 13188c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2); 13198c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2, 13208c2ecf20Sopenharmony_ci (m->vtotal - m->vdisplay) / 2); 13218c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 13228c2ecf20Sopenharmony_ci m->vtotal - m->vdisplay / 2); 13238c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal); 13248c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 13258c2ecf20Sopenharmony_ci (m->vtotal / 2) + 7); 13268c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 13278c2ecf20Sopenharmony_ci (m->vtotal / 2) + 2); 13288c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 13298c2ecf20Sopenharmony_ci (m->htotal / 2) + (m->hsync_start - m->hdisplay)); 13308c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 13318c2ecf20Sopenharmony_ci (m->htotal / 2) + (m->hsync_start - m->hdisplay)); 13328c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, 13338c2ecf20Sopenharmony_ci (m->vtotal - m->vdisplay) / 2); 13348c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2); 13358c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 13368c2ecf20Sopenharmony_ci m->vtotal - m->vdisplay / 2); 13378c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 13388c2ecf20Sopenharmony_ci (m->vtotal / 2) + 1); 13398c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 13408c2ecf20Sopenharmony_ci (m->vtotal / 2) + 1); 13418c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 13428c2ecf20Sopenharmony_ci (m->vtotal / 2) + 1); 13438c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0); 13448c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0); 13458c2ecf20Sopenharmony_ci } else { 13468c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, 13478c2ecf20Sopenharmony_ci m->vsync_end - m->vdisplay); 13488c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, 13498c2ecf20Sopenharmony_ci m->vsync_start - m->vdisplay); 13508c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal); 13518c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2, 13528c2ecf20Sopenharmony_ci m->vtotal - m->vdisplay); 13538c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff); 13548c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff); 13558c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff); 13568c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff); 13578c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff); 13588c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff); 13598c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, 13608c2ecf20Sopenharmony_ci m->vtotal - m->vdisplay); 13618c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2, 13658c2ecf20Sopenharmony_ci m->hsync_start - m->hdisplay - 2); 13668c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2, 13678c2ecf20Sopenharmony_ci m->hsync_end - m->hdisplay - 2); 13688c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff); 13698c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff); 13708c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff); 13718c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff); 13728c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff); 13738c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff); 13748c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff); 13758c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff); 13768c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff); 13778c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff); 13788c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff); 13798c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff); 13808c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff); 13818c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff); 13828c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff); 13838c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff); 13848c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff); 13858c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); 13888c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, 13898c2ecf20Sopenharmony_ci m->htotal - m->hdisplay - hquirk); 13908c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay + hquirk); 13918c2ecf20Sopenharmony_ci hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); 13928c2ecf20Sopenharmony_ci if (hdata->drv_data == &exynos5433_hdmi_driver_data) 13938c2ecf20Sopenharmony_ci hdmi_reg_writeb(hdata, HDMI_TG_DECON_EN, 1); 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic void hdmi_mode_apply(struct hdmi_context *hdata) 13978c2ecf20Sopenharmony_ci{ 13988c2ecf20Sopenharmony_ci if (hdata->drv_data->type == HDMI_TYPE13) 13998c2ecf20Sopenharmony_ci hdmi_v13_mode_apply(hdata); 14008c2ecf20Sopenharmony_ci else 14018c2ecf20Sopenharmony_ci hdmi_v14_mode_apply(hdata); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci hdmi_start(hdata, true); 14048c2ecf20Sopenharmony_ci} 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_cistatic void hdmiphy_conf_reset(struct hdmi_context *hdata) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, 0, 1); 14098c2ecf20Sopenharmony_ci usleep_range(10000, 12000); 14108c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, ~0, 1); 14118c2ecf20Sopenharmony_ci usleep_range(10000, 12000); 14128c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); 14138c2ecf20Sopenharmony_ci usleep_range(10000, 12000); 14148c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT); 14158c2ecf20Sopenharmony_ci usleep_range(10000, 12000); 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_cistatic void hdmiphy_enable_mode_set(struct hdmi_context *hdata, bool enable) 14198c2ecf20Sopenharmony_ci{ 14208c2ecf20Sopenharmony_ci u8 v = enable ? HDMI_PHY_ENABLE_MODE_SET : HDMI_PHY_DISABLE_MODE_SET; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (hdata->drv_data == &exynos5433_hdmi_driver_data) 14238c2ecf20Sopenharmony_ci writel(v, hdata->regs_hdmiphy + HDMIPHY5433_MODE_SET_DONE); 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_cistatic void hdmiphy_conf_apply(struct hdmi_context *hdata) 14278c2ecf20Sopenharmony_ci{ 14288c2ecf20Sopenharmony_ci struct drm_display_mode *m = &hdata->encoder.crtc->state->mode; 14298c2ecf20Sopenharmony_ci int ret; 14308c2ecf20Sopenharmony_ci const u8 *phy_conf; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci ret = hdmi_find_phy_conf(hdata, m->clock * 1000); 14338c2ecf20Sopenharmony_ci if (ret < 0) { 14348c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, "failed to find hdmiphy conf\n"); 14358c2ecf20Sopenharmony_ci return; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci phy_conf = hdata->drv_data->phy_confs.data[ret].conf; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci hdmi_clk_set_parents(hdata, false); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci hdmiphy_conf_reset(hdata); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci hdmiphy_enable_mode_set(hdata, true); 14448c2ecf20Sopenharmony_ci ret = hdmiphy_reg_write_buf(hdata, 0, phy_conf, 32); 14458c2ecf20Sopenharmony_ci if (ret) { 14468c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, "failed to configure hdmiphy\n"); 14478c2ecf20Sopenharmony_ci return; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci hdmiphy_enable_mode_set(hdata, false); 14508c2ecf20Sopenharmony_ci hdmi_clk_set_parents(hdata, true); 14518c2ecf20Sopenharmony_ci usleep_range(10000, 12000); 14528c2ecf20Sopenharmony_ci hdmiphy_wait_for_pll(hdata); 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci/* Should be called with hdata->mutex mutex held */ 14568c2ecf20Sopenharmony_cistatic void hdmi_conf_apply(struct hdmi_context *hdata) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci hdmi_start(hdata, false); 14598c2ecf20Sopenharmony_ci hdmi_conf_init(hdata); 14608c2ecf20Sopenharmony_ci hdmi_audio_config(hdata); 14618c2ecf20Sopenharmony_ci hdmi_mode_apply(hdata); 14628c2ecf20Sopenharmony_ci hdmi_audio_control(hdata); 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic void hdmi_set_refclk(struct hdmi_context *hdata, bool on) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci if (!hdata->sysreg) 14688c2ecf20Sopenharmony_ci return; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci regmap_update_bits(hdata->sysreg, EXYNOS5433_SYSREG_DISP_HDMI_PHY, 14718c2ecf20Sopenharmony_ci SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0); 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci/* Should be called with hdata->mutex mutex held. */ 14758c2ecf20Sopenharmony_cistatic void hdmiphy_enable(struct hdmi_context *hdata) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci if (hdata->powered) 14788c2ecf20Sopenharmony_ci return; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci pm_runtime_get_sync(hdata->dev); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk)) 14838c2ecf20Sopenharmony_ci DRM_DEV_DEBUG_KMS(hdata->dev, 14848c2ecf20Sopenharmony_ci "failed to enable regulator bulk\n"); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, 14878c2ecf20Sopenharmony_ci PMU_HDMI_PHY_ENABLE_BIT, 1); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci hdmi_set_refclk(hdata, true); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci hdmiphy_conf_apply(hdata); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci hdata->powered = true; 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci/* Should be called with hdata->mutex mutex held. */ 14998c2ecf20Sopenharmony_cistatic void hdmiphy_disable(struct hdmi_context *hdata) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci if (!hdata->powered) 15028c2ecf20Sopenharmony_ci return; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci hdmi_set_refclk(hdata, false); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, 15118c2ecf20Sopenharmony_ci PMU_HDMI_PHY_ENABLE_BIT, 0); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci pm_runtime_put_sync(hdata->dev); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci hdata->powered = false; 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_cistatic void hdmi_enable(struct drm_encoder *encoder) 15218c2ecf20Sopenharmony_ci{ 15228c2ecf20Sopenharmony_ci struct hdmi_context *hdata = encoder_to_hdmi(encoder); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci mutex_lock(&hdata->mutex); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci hdmiphy_enable(hdata); 15278c2ecf20Sopenharmony_ci hdmi_conf_apply(hdata); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci mutex_unlock(&hdata->mutex); 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_cistatic void hdmi_disable(struct drm_encoder *encoder) 15338c2ecf20Sopenharmony_ci{ 15348c2ecf20Sopenharmony_ci struct hdmi_context *hdata = encoder_to_hdmi(encoder); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci mutex_lock(&hdata->mutex); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (hdata->powered) { 15398c2ecf20Sopenharmony_ci /* 15408c2ecf20Sopenharmony_ci * The SFRs of VP and Mixer are updated by Vertical Sync of 15418c2ecf20Sopenharmony_ci * Timing generator which is a part of HDMI so the sequence 15428c2ecf20Sopenharmony_ci * to disable TV Subsystem should be as following, 15438c2ecf20Sopenharmony_ci * VP -> Mixer -> HDMI 15448c2ecf20Sopenharmony_ci * 15458c2ecf20Sopenharmony_ci * To achieve such sequence HDMI is disabled together with 15468c2ecf20Sopenharmony_ci * HDMI PHY, via pipe clock callback. 15478c2ecf20Sopenharmony_ci */ 15488c2ecf20Sopenharmony_ci mutex_unlock(&hdata->mutex); 15498c2ecf20Sopenharmony_ci cancel_delayed_work(&hdata->hotplug_work); 15508c2ecf20Sopenharmony_ci if (hdata->notifier) 15518c2ecf20Sopenharmony_ci cec_notifier_phys_addr_invalidate(hdata->notifier); 15528c2ecf20Sopenharmony_ci return; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci mutex_unlock(&hdata->mutex); 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = { 15598c2ecf20Sopenharmony_ci .mode_fixup = hdmi_mode_fixup, 15608c2ecf20Sopenharmony_ci .enable = hdmi_enable, 15618c2ecf20Sopenharmony_ci .disable = hdmi_disable, 15628c2ecf20Sopenharmony_ci}; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cistatic void hdmi_audio_shutdown(struct device *dev, void *data) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci struct hdmi_context *hdata = dev_get_drvdata(dev); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci mutex_lock(&hdata->mutex); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci hdata->audio.mute = true; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci if (hdata->powered) 15738c2ecf20Sopenharmony_ci hdmi_audio_control(hdata); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci mutex_unlock(&hdata->mutex); 15768c2ecf20Sopenharmony_ci} 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_cistatic int hdmi_audio_hw_params(struct device *dev, void *data, 15798c2ecf20Sopenharmony_ci struct hdmi_codec_daifmt *daifmt, 15808c2ecf20Sopenharmony_ci struct hdmi_codec_params *params) 15818c2ecf20Sopenharmony_ci{ 15828c2ecf20Sopenharmony_ci struct hdmi_context *hdata = dev_get_drvdata(dev); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci if (daifmt->fmt != HDMI_I2S || daifmt->bit_clk_inv || 15858c2ecf20Sopenharmony_ci daifmt->frame_clk_inv || daifmt->bit_clk_master || 15868c2ecf20Sopenharmony_ci daifmt->frame_clk_master) { 15878c2ecf20Sopenharmony_ci dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, 15888c2ecf20Sopenharmony_ci daifmt->bit_clk_inv, daifmt->frame_clk_inv, 15898c2ecf20Sopenharmony_ci daifmt->bit_clk_master, 15908c2ecf20Sopenharmony_ci daifmt->frame_clk_master); 15918c2ecf20Sopenharmony_ci return -EINVAL; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci mutex_lock(&hdata->mutex); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci hdata->audio.params = *params; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (hdata->powered) { 15998c2ecf20Sopenharmony_ci hdmi_audio_config(hdata); 16008c2ecf20Sopenharmony_ci hdmi_audio_infoframe_apply(hdata); 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci mutex_unlock(&hdata->mutex); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci return 0; 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_cistatic int hdmi_audio_mute(struct device *dev, void *data, 16098c2ecf20Sopenharmony_ci bool mute, int direction) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci struct hdmi_context *hdata = dev_get_drvdata(dev); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci mutex_lock(&hdata->mutex); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci hdata->audio.mute = mute; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci if (hdata->powered) 16188c2ecf20Sopenharmony_ci hdmi_audio_control(hdata); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci mutex_unlock(&hdata->mutex); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci return 0; 16238c2ecf20Sopenharmony_ci} 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_cistatic int hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf, 16268c2ecf20Sopenharmony_ci size_t len) 16278c2ecf20Sopenharmony_ci{ 16288c2ecf20Sopenharmony_ci struct hdmi_context *hdata = dev_get_drvdata(dev); 16298c2ecf20Sopenharmony_ci struct drm_connector *connector = &hdata->connector; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci return 0; 16348c2ecf20Sopenharmony_ci} 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_cistatic const struct hdmi_codec_ops audio_codec_ops = { 16378c2ecf20Sopenharmony_ci .hw_params = hdmi_audio_hw_params, 16388c2ecf20Sopenharmony_ci .audio_shutdown = hdmi_audio_shutdown, 16398c2ecf20Sopenharmony_ci .mute_stream = hdmi_audio_mute, 16408c2ecf20Sopenharmony_ci .get_eld = hdmi_audio_get_eld, 16418c2ecf20Sopenharmony_ci .no_capture_mute = 1, 16428c2ecf20Sopenharmony_ci}; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_cistatic int hdmi_register_audio_device(struct hdmi_context *hdata) 16458c2ecf20Sopenharmony_ci{ 16468c2ecf20Sopenharmony_ci struct hdmi_codec_pdata codec_data = { 16478c2ecf20Sopenharmony_ci .ops = &audio_codec_ops, 16488c2ecf20Sopenharmony_ci .max_i2s_channels = 6, 16498c2ecf20Sopenharmony_ci .i2s = 1, 16508c2ecf20Sopenharmony_ci }; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci hdata->audio.pdev = platform_device_register_data( 16538c2ecf20Sopenharmony_ci hdata->dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, 16548c2ecf20Sopenharmony_ci &codec_data, sizeof(codec_data)); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(hdata->audio.pdev); 16578c2ecf20Sopenharmony_ci} 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cistatic void hdmi_hotplug_work_func(struct work_struct *work) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci struct hdmi_context *hdata; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci hdata = container_of(work, struct hdmi_context, hotplug_work.work); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (hdata->drm_dev) 16668c2ecf20Sopenharmony_ci drm_helper_hpd_irq_event(hdata->drm_dev); 16678c2ecf20Sopenharmony_ci} 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_cistatic irqreturn_t hdmi_irq_thread(int irq, void *arg) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci struct hdmi_context *hdata = arg; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci mod_delayed_work(system_wq, &hdata->hotplug_work, 16748c2ecf20Sopenharmony_ci msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci return IRQ_HANDLED; 16778c2ecf20Sopenharmony_ci} 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_cistatic int hdmi_clks_get(struct hdmi_context *hdata, 16808c2ecf20Sopenharmony_ci const struct string_array_spec *names, 16818c2ecf20Sopenharmony_ci struct clk **clks) 16828c2ecf20Sopenharmony_ci{ 16838c2ecf20Sopenharmony_ci struct device *dev = hdata->dev; 16848c2ecf20Sopenharmony_ci int i; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci for (i = 0; i < names->count; ++i) { 16878c2ecf20Sopenharmony_ci struct clk *clk = devm_clk_get(dev, names->data[i]); 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 16908c2ecf20Sopenharmony_ci int ret = PTR_ERR(clk); 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get clock %s, %d\n", 16938c2ecf20Sopenharmony_ci names->data[i], ret); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci return ret; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci clks[i] = clk; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci return 0; 17028c2ecf20Sopenharmony_ci} 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_cistatic int hdmi_clk_init(struct hdmi_context *hdata) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci const struct hdmi_driver_data *drv_data = hdata->drv_data; 17078c2ecf20Sopenharmony_ci int count = drv_data->clk_gates.count + drv_data->clk_muxes.count; 17088c2ecf20Sopenharmony_ci struct device *dev = hdata->dev; 17098c2ecf20Sopenharmony_ci struct clk **clks; 17108c2ecf20Sopenharmony_ci int ret; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (!count) 17138c2ecf20Sopenharmony_ci return 0; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci clks = devm_kcalloc(dev, count, sizeof(*clks), GFP_KERNEL); 17168c2ecf20Sopenharmony_ci if (!clks) 17178c2ecf20Sopenharmony_ci return -ENOMEM; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci hdata->clk_gates = clks; 17208c2ecf20Sopenharmony_ci hdata->clk_muxes = clks + drv_data->clk_gates.count; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci ret = hdmi_clks_get(hdata, &drv_data->clk_gates, hdata->clk_gates); 17238c2ecf20Sopenharmony_ci if (ret) 17248c2ecf20Sopenharmony_ci return ret; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes); 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_cistatic void hdmiphy_clk_enable(struct exynos_drm_clk *clk, bool enable) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct hdmi_context *hdata = container_of(clk, struct hdmi_context, 17338c2ecf20Sopenharmony_ci phy_clk); 17348c2ecf20Sopenharmony_ci mutex_lock(&hdata->mutex); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci if (enable) 17378c2ecf20Sopenharmony_ci hdmiphy_enable(hdata); 17388c2ecf20Sopenharmony_ci else 17398c2ecf20Sopenharmony_ci hdmiphy_disable(hdata); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci mutex_unlock(&hdata->mutex); 17428c2ecf20Sopenharmony_ci} 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cistatic int hdmi_bridge_init(struct hdmi_context *hdata) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci struct device *dev = hdata->dev; 17478c2ecf20Sopenharmony_ci struct device_node *ep, *np; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); 17508c2ecf20Sopenharmony_ci if (!ep) 17518c2ecf20Sopenharmony_ci return 0; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci np = of_graph_get_remote_port_parent(ep); 17548c2ecf20Sopenharmony_ci of_node_put(ep); 17558c2ecf20Sopenharmony_ci if (!np) { 17568c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to get remote port parent"); 17578c2ecf20Sopenharmony_ci return -EINVAL; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci hdata->bridge = of_drm_find_bridge(np); 17618c2ecf20Sopenharmony_ci of_node_put(np); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci if (!hdata->bridge) 17648c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci return 0; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_cistatic int hdmi_resources_init(struct hdmi_context *hdata) 17708c2ecf20Sopenharmony_ci{ 17718c2ecf20Sopenharmony_ci struct device *dev = hdata->dev; 17728c2ecf20Sopenharmony_ci int i, ret; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci DRM_DEV_DEBUG_KMS(dev, "HDMI resource init\n"); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN); 17778c2ecf20Sopenharmony_ci if (IS_ERR(hdata->hpd_gpio)) { 17788c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "cannot get hpd gpio property\n"); 17798c2ecf20Sopenharmony_ci return PTR_ERR(hdata->hpd_gpio); 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci hdata->irq = gpiod_to_irq(hdata->hpd_gpio); 17838c2ecf20Sopenharmony_ci if (hdata->irq < 0) { 17848c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to get GPIO irq\n"); 17858c2ecf20Sopenharmony_ci return hdata->irq; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci ret = hdmi_clk_init(hdata); 17898c2ecf20Sopenharmony_ci if (ret) 17908c2ecf20Sopenharmony_ci return ret; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci ret = hdmi_clk_set_parents(hdata, false); 17938c2ecf20Sopenharmony_ci if (ret) 17948c2ecf20Sopenharmony_ci return ret; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(supply); ++i) 17978c2ecf20Sopenharmony_ci hdata->regul_bulk[i].supply = supply[i]; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk); 18008c2ecf20Sopenharmony_ci if (ret) 18018c2ecf20Sopenharmony_ci return dev_err_probe(dev, ret, "failed to get regulators\n"); 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en"); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV) 18068c2ecf20Sopenharmony_ci if (IS_ERR(hdata->reg_hdmi_en)) 18078c2ecf20Sopenharmony_ci return PTR_ERR(hdata->reg_hdmi_en); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci return hdmi_bridge_init(hdata); 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic const struct of_device_id hdmi_match_types[] = { 18138c2ecf20Sopenharmony_ci { 18148c2ecf20Sopenharmony_ci .compatible = "samsung,exynos4210-hdmi", 18158c2ecf20Sopenharmony_ci .data = &exynos4210_hdmi_driver_data, 18168c2ecf20Sopenharmony_ci }, { 18178c2ecf20Sopenharmony_ci .compatible = "samsung,exynos4212-hdmi", 18188c2ecf20Sopenharmony_ci .data = &exynos4212_hdmi_driver_data, 18198c2ecf20Sopenharmony_ci }, { 18208c2ecf20Sopenharmony_ci .compatible = "samsung,exynos5420-hdmi", 18218c2ecf20Sopenharmony_ci .data = &exynos5420_hdmi_driver_data, 18228c2ecf20Sopenharmony_ci }, { 18238c2ecf20Sopenharmony_ci .compatible = "samsung,exynos5433-hdmi", 18248c2ecf20Sopenharmony_ci .data = &exynos5433_hdmi_driver_data, 18258c2ecf20Sopenharmony_ci }, { 18268c2ecf20Sopenharmony_ci /* end node */ 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci}; 18298c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (of, hdmi_match_types); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic int hdmi_bind(struct device *dev, struct device *master, void *data) 18328c2ecf20Sopenharmony_ci{ 18338c2ecf20Sopenharmony_ci struct drm_device *drm_dev = data; 18348c2ecf20Sopenharmony_ci struct hdmi_context *hdata = dev_get_drvdata(dev); 18358c2ecf20Sopenharmony_ci struct drm_encoder *encoder = &hdata->encoder; 18368c2ecf20Sopenharmony_ci struct exynos_drm_crtc *crtc; 18378c2ecf20Sopenharmony_ci int ret; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci hdata->drm_dev = drm_dev; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci hdata->phy_clk.enable = hdmiphy_clk_enable; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS); 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_HDMI); 18488c2ecf20Sopenharmony_ci if (ret < 0) 18498c2ecf20Sopenharmony_ci return ret; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci crtc = exynos_drm_crtc_get_by_type(drm_dev, EXYNOS_DISPLAY_TYPE_HDMI); 18528c2ecf20Sopenharmony_ci if (IS_ERR(crtc)) 18538c2ecf20Sopenharmony_ci return PTR_ERR(crtc); 18548c2ecf20Sopenharmony_ci crtc->pipe_clk = &hdata->phy_clk; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci ret = hdmi_create_connector(encoder); 18578c2ecf20Sopenharmony_ci if (ret) { 18588c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to create connector ret = %d\n", 18598c2ecf20Sopenharmony_ci ret); 18608c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 18618c2ecf20Sopenharmony_ci return ret; 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci return 0; 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic void hdmi_unbind(struct device *dev, struct device *master, void *data) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci} 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_cistatic const struct component_ops hdmi_component_ops = { 18728c2ecf20Sopenharmony_ci .bind = hdmi_bind, 18738c2ecf20Sopenharmony_ci .unbind = hdmi_unbind, 18748c2ecf20Sopenharmony_ci}; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_cistatic int hdmi_get_ddc_adapter(struct hdmi_context *hdata) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci const char *compatible_str = "samsung,exynos4210-hdmiddc"; 18798c2ecf20Sopenharmony_ci struct device_node *np; 18808c2ecf20Sopenharmony_ci struct i2c_adapter *adpt; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, compatible_str); 18838c2ecf20Sopenharmony_ci if (np) 18848c2ecf20Sopenharmony_ci np = of_get_next_parent(np); 18858c2ecf20Sopenharmony_ci else 18868c2ecf20Sopenharmony_ci np = of_parse_phandle(hdata->dev->of_node, "ddc", 0); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if (!np) { 18898c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, 18908c2ecf20Sopenharmony_ci "Failed to find ddc node in device tree\n"); 18918c2ecf20Sopenharmony_ci return -ENODEV; 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci adpt = of_find_i2c_adapter_by_node(np); 18958c2ecf20Sopenharmony_ci of_node_put(np); 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci if (!adpt) { 18988c2ecf20Sopenharmony_ci DRM_INFO("Failed to get ddc i2c adapter by node\n"); 18998c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci hdata->ddc_adpt = adpt; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci return 0; 19058c2ecf20Sopenharmony_ci} 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_cistatic int hdmi_get_phy_io(struct hdmi_context *hdata) 19088c2ecf20Sopenharmony_ci{ 19098c2ecf20Sopenharmony_ci const char *compatible_str = "samsung,exynos4212-hdmiphy"; 19108c2ecf20Sopenharmony_ci struct device_node *np; 19118c2ecf20Sopenharmony_ci int ret = 0; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, compatible_str); 19148c2ecf20Sopenharmony_ci if (!np) { 19158c2ecf20Sopenharmony_ci np = of_parse_phandle(hdata->dev->of_node, "phy", 0); 19168c2ecf20Sopenharmony_ci if (!np) { 19178c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, 19188c2ecf20Sopenharmony_ci "Failed to find hdmiphy node in device tree\n"); 19198c2ecf20Sopenharmony_ci return -ENODEV; 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (hdata->drv_data->is_apb_phy) { 19248c2ecf20Sopenharmony_ci hdata->regs_hdmiphy = of_iomap(np, 0); 19258c2ecf20Sopenharmony_ci if (!hdata->regs_hdmiphy) { 19268c2ecf20Sopenharmony_ci DRM_DEV_ERROR(hdata->dev, 19278c2ecf20Sopenharmony_ci "failed to ioremap hdmi phy\n"); 19288c2ecf20Sopenharmony_ci ret = -ENOMEM; 19298c2ecf20Sopenharmony_ci goto out; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci } else { 19328c2ecf20Sopenharmony_ci hdata->hdmiphy_port = of_find_i2c_device_by_node(np); 19338c2ecf20Sopenharmony_ci if (!hdata->hdmiphy_port) { 19348c2ecf20Sopenharmony_ci DRM_INFO("Failed to get hdmi phy i2c client\n"); 19358c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 19368c2ecf20Sopenharmony_ci goto out; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ciout: 19418c2ecf20Sopenharmony_ci of_node_put(np); 19428c2ecf20Sopenharmony_ci return ret; 19438c2ecf20Sopenharmony_ci} 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_cistatic int hdmi_probe(struct platform_device *pdev) 19468c2ecf20Sopenharmony_ci{ 19478c2ecf20Sopenharmony_ci struct hdmi_audio_infoframe *audio_infoframe; 19488c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 19498c2ecf20Sopenharmony_ci struct hdmi_context *hdata; 19508c2ecf20Sopenharmony_ci struct resource *res; 19518c2ecf20Sopenharmony_ci int ret; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); 19548c2ecf20Sopenharmony_ci if (!hdata) 19558c2ecf20Sopenharmony_ci return -ENOMEM; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci hdata->drv_data = of_device_get_match_data(dev); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, hdata); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci hdata->dev = dev; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci mutex_init(&hdata->mutex); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci ret = hdmi_resources_init(hdata); 19668c2ecf20Sopenharmony_ci if (ret) { 19678c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 19688c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "hdmi_resources_init failed\n"); 19698c2ecf20Sopenharmony_ci return ret; 19708c2ecf20Sopenharmony_ci } 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 19738c2ecf20Sopenharmony_ci hdata->regs = devm_ioremap_resource(dev, res); 19748c2ecf20Sopenharmony_ci if (IS_ERR(hdata->regs)) { 19758c2ecf20Sopenharmony_ci ret = PTR_ERR(hdata->regs); 19768c2ecf20Sopenharmony_ci return ret; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci ret = hdmi_get_ddc_adapter(hdata); 19808c2ecf20Sopenharmony_ci if (ret) 19818c2ecf20Sopenharmony_ci return ret; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci ret = hdmi_get_phy_io(hdata); 19848c2ecf20Sopenharmony_ci if (ret) 19858c2ecf20Sopenharmony_ci goto err_ddc; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func); 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, hdata->irq, NULL, 19908c2ecf20Sopenharmony_ci hdmi_irq_thread, IRQF_TRIGGER_RISING | 19918c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 19928c2ecf20Sopenharmony_ci "hdmi", hdata); 19938c2ecf20Sopenharmony_ci if (ret) { 19948c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "failed to register hdmi interrupt\n"); 19958c2ecf20Sopenharmony_ci goto err_hdmiphy; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, 19998c2ecf20Sopenharmony_ci "samsung,syscon-phandle"); 20008c2ecf20Sopenharmony_ci if (IS_ERR(hdata->pmureg)) { 20018c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "syscon regmap lookup failed.\n"); 20028c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 20038c2ecf20Sopenharmony_ci goto err_hdmiphy; 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci if (hdata->drv_data->has_sysreg) { 20078c2ecf20Sopenharmony_ci hdata->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, 20088c2ecf20Sopenharmony_ci "samsung,sysreg-phandle"); 20098c2ecf20Sopenharmony_ci if (IS_ERR(hdata->sysreg)) { 20108c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, "sysreg regmap lookup failed.\n"); 20118c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 20128c2ecf20Sopenharmony_ci goto err_hdmiphy; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci if (!IS_ERR(hdata->reg_hdmi_en)) { 20178c2ecf20Sopenharmony_ci ret = regulator_enable(hdata->reg_hdmi_en); 20188c2ecf20Sopenharmony_ci if (ret) { 20198c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev, 20208c2ecf20Sopenharmony_ci "failed to enable hdmi-en regulator\n"); 20218c2ecf20Sopenharmony_ci goto err_hdmiphy; 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci audio_infoframe = &hdata->audio.infoframe; 20288c2ecf20Sopenharmony_ci hdmi_audio_infoframe_init(audio_infoframe); 20298c2ecf20Sopenharmony_ci audio_infoframe->coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; 20308c2ecf20Sopenharmony_ci audio_infoframe->sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; 20318c2ecf20Sopenharmony_ci audio_infoframe->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; 20328c2ecf20Sopenharmony_ci audio_infoframe->channels = 2; 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci ret = hdmi_register_audio_device(hdata); 20358c2ecf20Sopenharmony_ci if (ret) 20368c2ecf20Sopenharmony_ci goto err_rpm_disable; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci ret = component_add(&pdev->dev, &hdmi_component_ops); 20398c2ecf20Sopenharmony_ci if (ret) 20408c2ecf20Sopenharmony_ci goto err_unregister_audio; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci return ret; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_cierr_unregister_audio: 20458c2ecf20Sopenharmony_ci platform_device_unregister(hdata->audio.pdev); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_cierr_rpm_disable: 20488c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 20498c2ecf20Sopenharmony_ci if (!IS_ERR(hdata->reg_hdmi_en)) 20508c2ecf20Sopenharmony_ci regulator_disable(hdata->reg_hdmi_en); 20518c2ecf20Sopenharmony_cierr_hdmiphy: 20528c2ecf20Sopenharmony_ci if (hdata->hdmiphy_port) 20538c2ecf20Sopenharmony_ci put_device(&hdata->hdmiphy_port->dev); 20548c2ecf20Sopenharmony_ci if (hdata->regs_hdmiphy) 20558c2ecf20Sopenharmony_ci iounmap(hdata->regs_hdmiphy); 20568c2ecf20Sopenharmony_cierr_ddc: 20578c2ecf20Sopenharmony_ci put_device(&hdata->ddc_adpt->dev); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci return ret; 20608c2ecf20Sopenharmony_ci} 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_cistatic int hdmi_remove(struct platform_device *pdev) 20638c2ecf20Sopenharmony_ci{ 20648c2ecf20Sopenharmony_ci struct hdmi_context *hdata = platform_get_drvdata(pdev); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&hdata->hotplug_work); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci component_del(&pdev->dev, &hdmi_component_ops); 20698c2ecf20Sopenharmony_ci platform_device_unregister(hdata->audio.pdev); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (!IS_ERR(hdata->reg_hdmi_en)) 20748c2ecf20Sopenharmony_ci regulator_disable(hdata->reg_hdmi_en); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci if (hdata->hdmiphy_port) 20778c2ecf20Sopenharmony_ci put_device(&hdata->hdmiphy_port->dev); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci if (hdata->regs_hdmiphy) 20808c2ecf20Sopenharmony_ci iounmap(hdata->regs_hdmiphy); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci put_device(&hdata->ddc_adpt->dev); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci mutex_destroy(&hdata->mutex); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci return 0; 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_cistatic int __maybe_unused exynos_hdmi_suspend(struct device *dev) 20908c2ecf20Sopenharmony_ci{ 20918c2ecf20Sopenharmony_ci struct hdmi_context *hdata = dev_get_drvdata(dev); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci hdmi_clk_disable_gates(hdata); 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci return 0; 20968c2ecf20Sopenharmony_ci} 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_cistatic int __maybe_unused exynos_hdmi_resume(struct device *dev) 20998c2ecf20Sopenharmony_ci{ 21008c2ecf20Sopenharmony_ci struct hdmi_context *hdata = dev_get_drvdata(dev); 21018c2ecf20Sopenharmony_ci int ret; 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci ret = hdmi_clk_enable_gates(hdata); 21048c2ecf20Sopenharmony_ci if (ret < 0) 21058c2ecf20Sopenharmony_ci return ret; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci return 0; 21088c2ecf20Sopenharmony_ci} 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_cistatic const struct dev_pm_ops exynos_hdmi_pm_ops = { 21118c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL) 21128c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 21138c2ecf20Sopenharmony_ci pm_runtime_force_resume) 21148c2ecf20Sopenharmony_ci}; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_cistruct platform_driver hdmi_driver = { 21178c2ecf20Sopenharmony_ci .probe = hdmi_probe, 21188c2ecf20Sopenharmony_ci .remove = hdmi_remove, 21198c2ecf20Sopenharmony_ci .driver = { 21208c2ecf20Sopenharmony_ci .name = "exynos-hdmi", 21218c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 21228c2ecf20Sopenharmony_ci .pm = &exynos_hdmi_pm_ops, 21238c2ecf20Sopenharmony_ci .of_match_table = hdmi_match_types, 21248c2ecf20Sopenharmony_ci }, 21258c2ecf20Sopenharmony_ci}; 2126