18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci * datasheet: https://www.ti.com/lit/ds/symlink/sn65dsi86.pdf 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/bits.h> 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of_graph.h> 168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 178c2ecf20Sopenharmony_ci#include <linux/regmap.h> 188c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 218c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 228c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h> 238c2ecf20Sopenharmony_ci#include <drm/drm_dp_helper.h> 248c2ecf20Sopenharmony_ci#include <drm/drm_mipi_dsi.h> 258c2ecf20Sopenharmony_ci#include <drm/drm_of.h> 268c2ecf20Sopenharmony_ci#include <drm/drm_panel.h> 278c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 288c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define SN_DEVICE_REV_REG 0x08 318c2ecf20Sopenharmony_ci#define SN_DPPLL_SRC_REG 0x0A 328c2ecf20Sopenharmony_ci#define DPPLL_CLK_SRC_DSICLK BIT(0) 338c2ecf20Sopenharmony_ci#define REFCLK_FREQ_MASK GENMASK(3, 1) 348c2ecf20Sopenharmony_ci#define REFCLK_FREQ(x) ((x) << 1) 358c2ecf20Sopenharmony_ci#define DPPLL_SRC_DP_PLL_LOCK BIT(7) 368c2ecf20Sopenharmony_ci#define SN_PLL_ENABLE_REG 0x0D 378c2ecf20Sopenharmony_ci#define SN_DSI_LANES_REG 0x10 388c2ecf20Sopenharmony_ci#define CHA_DSI_LANES_MASK GENMASK(4, 3) 398c2ecf20Sopenharmony_ci#define CHA_DSI_LANES(x) ((x) << 3) 408c2ecf20Sopenharmony_ci#define SN_DSIA_CLK_FREQ_REG 0x12 418c2ecf20Sopenharmony_ci#define SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG 0x20 428c2ecf20Sopenharmony_ci#define SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG 0x24 438c2ecf20Sopenharmony_ci#define SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG 0x2C 448c2ecf20Sopenharmony_ci#define SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG 0x2D 458c2ecf20Sopenharmony_ci#define CHA_HSYNC_POLARITY BIT(7) 468c2ecf20Sopenharmony_ci#define SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG 0x30 478c2ecf20Sopenharmony_ci#define SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG 0x31 488c2ecf20Sopenharmony_ci#define CHA_VSYNC_POLARITY BIT(7) 498c2ecf20Sopenharmony_ci#define SN_CHA_HORIZONTAL_BACK_PORCH_REG 0x34 508c2ecf20Sopenharmony_ci#define SN_CHA_VERTICAL_BACK_PORCH_REG 0x36 518c2ecf20Sopenharmony_ci#define SN_CHA_HORIZONTAL_FRONT_PORCH_REG 0x38 528c2ecf20Sopenharmony_ci#define SN_CHA_VERTICAL_FRONT_PORCH_REG 0x3A 538c2ecf20Sopenharmony_ci#define SN_LN_ASSIGN_REG 0x59 548c2ecf20Sopenharmony_ci#define LN_ASSIGN_WIDTH 2 558c2ecf20Sopenharmony_ci#define SN_ENH_FRAME_REG 0x5A 568c2ecf20Sopenharmony_ci#define VSTREAM_ENABLE BIT(3) 578c2ecf20Sopenharmony_ci#define LN_POLRS_OFFSET 4 588c2ecf20Sopenharmony_ci#define LN_POLRS_MASK 0xf0 598c2ecf20Sopenharmony_ci#define SN_DATA_FORMAT_REG 0x5B 608c2ecf20Sopenharmony_ci#define BPP_18_RGB BIT(0) 618c2ecf20Sopenharmony_ci#define SN_HPD_DISABLE_REG 0x5C 628c2ecf20Sopenharmony_ci#define HPD_DISABLE BIT(0) 638c2ecf20Sopenharmony_ci#define SN_GPIO_IO_REG 0x5E 648c2ecf20Sopenharmony_ci#define SN_GPIO_INPUT_SHIFT 4 658c2ecf20Sopenharmony_ci#define SN_GPIO_OUTPUT_SHIFT 0 668c2ecf20Sopenharmony_ci#define SN_GPIO_CTRL_REG 0x5F 678c2ecf20Sopenharmony_ci#define SN_GPIO_MUX_INPUT 0 688c2ecf20Sopenharmony_ci#define SN_GPIO_MUX_OUTPUT 1 698c2ecf20Sopenharmony_ci#define SN_GPIO_MUX_SPECIAL 2 708c2ecf20Sopenharmony_ci#define SN_GPIO_MUX_MASK 0x3 718c2ecf20Sopenharmony_ci#define SN_AUX_WDATA_REG(x) (0x64 + (x)) 728c2ecf20Sopenharmony_ci#define SN_AUX_ADDR_19_16_REG 0x74 738c2ecf20Sopenharmony_ci#define SN_AUX_ADDR_15_8_REG 0x75 748c2ecf20Sopenharmony_ci#define SN_AUX_ADDR_7_0_REG 0x76 758c2ecf20Sopenharmony_ci#define SN_AUX_LENGTH_REG 0x77 768c2ecf20Sopenharmony_ci#define SN_AUX_CMD_REG 0x78 778c2ecf20Sopenharmony_ci#define AUX_CMD_SEND BIT(0) 788c2ecf20Sopenharmony_ci#define AUX_CMD_REQ(x) ((x) << 4) 798c2ecf20Sopenharmony_ci#define SN_AUX_RDATA_REG(x) (0x79 + (x)) 808c2ecf20Sopenharmony_ci#define SN_SSC_CONFIG_REG 0x93 818c2ecf20Sopenharmony_ci#define DP_NUM_LANES_MASK GENMASK(5, 4) 828c2ecf20Sopenharmony_ci#define DP_NUM_LANES(x) ((x) << 4) 838c2ecf20Sopenharmony_ci#define SN_DATARATE_CONFIG_REG 0x94 848c2ecf20Sopenharmony_ci#define DP_DATARATE_MASK GENMASK(7, 5) 858c2ecf20Sopenharmony_ci#define DP_DATARATE(x) ((x) << 5) 868c2ecf20Sopenharmony_ci#define SN_ML_TX_MODE_REG 0x96 878c2ecf20Sopenharmony_ci#define ML_TX_MAIN_LINK_OFF 0 888c2ecf20Sopenharmony_ci#define ML_TX_NORMAL_MODE BIT(0) 898c2ecf20Sopenharmony_ci#define SN_AUX_CMD_STATUS_REG 0xF4 908c2ecf20Sopenharmony_ci#define AUX_IRQ_STATUS_AUX_RPLY_TOUT BIT(3) 918c2ecf20Sopenharmony_ci#define AUX_IRQ_STATUS_AUX_SHORT BIT(5) 928c2ecf20Sopenharmony_ci#define AUX_IRQ_STATUS_NAT_I2C_FAIL BIT(6) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define MIN_DSI_CLK_FREQ_MHZ 40 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* fudge factor required to account for 8b/10b encoding */ 978c2ecf20Sopenharmony_ci#define DP_CLK_FUDGE_NUM 10 988c2ecf20Sopenharmony_ci#define DP_CLK_FUDGE_DEN 8 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* Matches DP_AUX_MAX_PAYLOAD_BYTES (for now) */ 1018c2ecf20Sopenharmony_ci#define SN_AUX_MAX_PAYLOAD_BYTES 16 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define SN_REGULATOR_SUPPLY_NUM 4 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define SN_MAX_DP_LANES 4 1068c2ecf20Sopenharmony_ci#define SN_NUM_GPIOS 4 1078c2ecf20Sopenharmony_ci#define SN_GPIO_PHYSICAL_OFFSET 1 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/** 1108c2ecf20Sopenharmony_ci * struct ti_sn_bridge - Platform data for ti-sn65dsi86 driver. 1118c2ecf20Sopenharmony_ci * @dev: Pointer to our device. 1128c2ecf20Sopenharmony_ci * @regmap: Regmap for accessing i2c. 1138c2ecf20Sopenharmony_ci * @aux: Our aux channel. 1148c2ecf20Sopenharmony_ci * @bridge: Our bridge. 1158c2ecf20Sopenharmony_ci * @connector: Our connector. 1168c2ecf20Sopenharmony_ci * @debugfs: Used for managing our debugfs. 1178c2ecf20Sopenharmony_ci * @host_node: Remote DSI node. 1188c2ecf20Sopenharmony_ci * @dsi: Our MIPI DSI source. 1198c2ecf20Sopenharmony_ci * @refclk: Our reference clock. 1208c2ecf20Sopenharmony_ci * @panel: Our panel. 1218c2ecf20Sopenharmony_ci * @enable_gpio: The GPIO we toggle to enable the bridge. 1228c2ecf20Sopenharmony_ci * @supplies: Data for bulk enabling/disabling our regulators. 1238c2ecf20Sopenharmony_ci * @dp_lanes: Count of dp_lanes we're using. 1248c2ecf20Sopenharmony_ci * @ln_assign: Value to program to the LN_ASSIGN register. 1258c2ecf20Sopenharmony_ci * @ln_polrs: Value for the 4-bit LN_POLRS field of SN_ENH_FRAME_REG. 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * @gchip: If we expose our GPIOs, this is used. 1288c2ecf20Sopenharmony_ci * @gchip_output: A cache of whether we've set GPIOs to output. This 1298c2ecf20Sopenharmony_ci * serves double-duty of keeping track of the direction and 1308c2ecf20Sopenharmony_ci * also keeping track of whether we've incremented the 1318c2ecf20Sopenharmony_ci * pm_runtime reference count for this pin, which we do 1328c2ecf20Sopenharmony_ci * whenever a pin is configured as an output. This is a 1338c2ecf20Sopenharmony_ci * bitmap so we can do atomic ops on it without an extra 1348c2ecf20Sopenharmony_ci * lock so concurrent users of our 4 GPIOs don't stomp on 1358c2ecf20Sopenharmony_ci * each other's read-modify-write. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_cistruct ti_sn_bridge { 1388c2ecf20Sopenharmony_ci struct device *dev; 1398c2ecf20Sopenharmony_ci struct regmap *regmap; 1408c2ecf20Sopenharmony_ci struct drm_dp_aux aux; 1418c2ecf20Sopenharmony_ci struct drm_bridge bridge; 1428c2ecf20Sopenharmony_ci struct drm_connector connector; 1438c2ecf20Sopenharmony_ci struct dentry *debugfs; 1448c2ecf20Sopenharmony_ci struct device_node *host_node; 1458c2ecf20Sopenharmony_ci struct mipi_dsi_device *dsi; 1468c2ecf20Sopenharmony_ci struct clk *refclk; 1478c2ecf20Sopenharmony_ci struct drm_panel *panel; 1488c2ecf20Sopenharmony_ci struct gpio_desc *enable_gpio; 1498c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[SN_REGULATOR_SUPPLY_NUM]; 1508c2ecf20Sopenharmony_ci int dp_lanes; 1518c2ecf20Sopenharmony_ci u8 ln_assign; 1528c2ecf20Sopenharmony_ci u8 ln_polrs; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#if defined(CONFIG_OF_GPIO) 1558c2ecf20Sopenharmony_ci struct gpio_chip gchip; 1568c2ecf20Sopenharmony_ci DECLARE_BITMAP(gchip_output, SN_NUM_GPIOS); 1578c2ecf20Sopenharmony_ci#endif 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic const struct regmap_range ti_sn_bridge_volatile_ranges[] = { 1618c2ecf20Sopenharmony_ci { .range_min = 0, .range_max = 0xFF }, 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic const struct regmap_access_table ti_sn_bridge_volatile_table = { 1658c2ecf20Sopenharmony_ci .yes_ranges = ti_sn_bridge_volatile_ranges, 1668c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(ti_sn_bridge_volatile_ranges), 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic const struct regmap_config ti_sn_bridge_regmap_config = { 1708c2ecf20Sopenharmony_ci .reg_bits = 8, 1718c2ecf20Sopenharmony_ci .val_bits = 8, 1728c2ecf20Sopenharmony_ci .volatile_table = &ti_sn_bridge_volatile_table, 1738c2ecf20Sopenharmony_ci .cache_type = REGCACHE_NONE, 1748c2ecf20Sopenharmony_ci .max_register = 0xFF, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic void ti_sn_bridge_write_u16(struct ti_sn_bridge *pdata, 1788c2ecf20Sopenharmony_ci unsigned int reg, u16 val) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, reg, val & 0xFF); 1818c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, reg + 1, val >> 8); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int __maybe_unused ti_sn_bridge_resume(struct device *dev) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = dev_get_drvdata(dev); 1878c2ecf20Sopenharmony_ci int ret; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies); 1908c2ecf20Sopenharmony_ci if (ret) { 1918c2ecf20Sopenharmony_ci DRM_ERROR("failed to enable supplies %d\n", ret); 1928c2ecf20Sopenharmony_ci return ret; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci gpiod_set_value(pdata->enable_gpio, 1); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return ret; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int __maybe_unused ti_sn_bridge_suspend(struct device *dev) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = dev_get_drvdata(dev); 2038c2ecf20Sopenharmony_ci int ret; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci gpiod_set_value(pdata->enable_gpio, 0); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = regulator_bulk_disable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies); 2088c2ecf20Sopenharmony_ci if (ret) 2098c2ecf20Sopenharmony_ci DRM_ERROR("failed to disable supplies %d\n", ret); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic const struct dev_pm_ops ti_sn_bridge_pm_ops = { 2158c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(ti_sn_bridge_suspend, ti_sn_bridge_resume, NULL) 2168c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 2178c2ecf20Sopenharmony_ci pm_runtime_force_resume) 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int status_show(struct seq_file *s, void *data) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = s->private; 2238c2ecf20Sopenharmony_ci unsigned int reg, val; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci seq_puts(s, "STATUS REGISTERS:\n"); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci pm_runtime_get_sync(pdata->dev); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* IRQ Status Registers, see Table 31 in datasheet */ 2308c2ecf20Sopenharmony_ci for (reg = 0xf0; reg <= 0xf8; reg++) { 2318c2ecf20Sopenharmony_ci regmap_read(pdata->regmap, reg, &val); 2328c2ecf20Sopenharmony_ci seq_printf(s, "[0x%02x] = 0x%08x\n", reg, val); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci pm_runtime_put(pdata->dev); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(status); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void ti_sn_debugfs_init(struct ti_sn_bridge *pdata) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci pdata->debugfs = debugfs_create_dir(dev_name(pdata->dev), NULL); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci debugfs_create_file("status", 0600, pdata->debugfs, pdata, 2478c2ecf20Sopenharmony_ci &status_fops); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void ti_sn_debugfs_remove(struct ti_sn_bridge *pdata) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci debugfs_remove_recursive(pdata->debugfs); 2538c2ecf20Sopenharmony_ci pdata->debugfs = NULL; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* Connector funcs */ 2578c2ecf20Sopenharmony_cistatic struct ti_sn_bridge * 2588c2ecf20Sopenharmony_ciconnector_to_ti_sn_bridge(struct drm_connector *connector) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci return container_of(connector, struct ti_sn_bridge, connector); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int ti_sn_bridge_connector_get_modes(struct drm_connector *connector) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = connector_to_ti_sn_bridge(connector); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return drm_panel_get_modes(pdata->panel, connector); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic enum drm_mode_status 2718c2ecf20Sopenharmony_citi_sn_bridge_connector_mode_valid(struct drm_connector *connector, 2728c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci /* maximum supported resolution is 4K at 60 fps */ 2758c2ecf20Sopenharmony_ci if (mode->clock > 594000) 2768c2ecf20Sopenharmony_ci return MODE_CLOCK_HIGH; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return MODE_OK; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic struct drm_connector_helper_funcs ti_sn_bridge_connector_helper_funcs = { 2828c2ecf20Sopenharmony_ci .get_modes = ti_sn_bridge_connector_get_modes, 2838c2ecf20Sopenharmony_ci .mode_valid = ti_sn_bridge_connector_mode_valid, 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic enum drm_connector_status 2878c2ecf20Sopenharmony_citi_sn_bridge_connector_detect(struct drm_connector *connector, bool force) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci /** 2908c2ecf20Sopenharmony_ci * TODO: Currently if drm_panel is present, then always 2918c2ecf20Sopenharmony_ci * return the status as connected. Need to add support to detect 2928c2ecf20Sopenharmony_ci * device state for hot pluggable scenarios. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci return connector_status_connected; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs ti_sn_bridge_connector_funcs = { 2988c2ecf20Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 2998c2ecf20Sopenharmony_ci .detect = ti_sn_bridge_connector_detect, 3008c2ecf20Sopenharmony_ci .destroy = drm_connector_cleanup, 3018c2ecf20Sopenharmony_ci .reset = drm_atomic_helper_connector_reset, 3028c2ecf20Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 3038c2ecf20Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 3048c2ecf20Sopenharmony_ci}; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic struct ti_sn_bridge *bridge_to_ti_sn_bridge(struct drm_bridge *bridge) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci return container_of(bridge, struct ti_sn_bridge, bridge); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic int ti_sn_bridge_parse_regulators(struct ti_sn_bridge *pdata) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci unsigned int i; 3148c2ecf20Sopenharmony_ci const char * const ti_sn_bridge_supply_names[] = { 3158c2ecf20Sopenharmony_ci "vcca", "vcc", "vccio", "vpll", 3168c2ecf20Sopenharmony_ci }; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci for (i = 0; i < SN_REGULATOR_SUPPLY_NUM; i++) 3198c2ecf20Sopenharmony_ci pdata->supplies[i].supply = ti_sn_bridge_supply_names[i]; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return devm_regulator_bulk_get(pdata->dev, SN_REGULATOR_SUPPLY_NUM, 3228c2ecf20Sopenharmony_ci pdata->supplies); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int ti_sn_bridge_attach(struct drm_bridge *bridge, 3268c2ecf20Sopenharmony_ci enum drm_bridge_attach_flags flags) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci int ret, val; 3298c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); 3308c2ecf20Sopenharmony_ci struct mipi_dsi_host *host; 3318c2ecf20Sopenharmony_ci struct mipi_dsi_device *dsi; 3328c2ecf20Sopenharmony_ci const struct mipi_dsi_device_info info = { .type = "ti_sn_bridge", 3338c2ecf20Sopenharmony_ci .channel = 0, 3348c2ecf20Sopenharmony_ci .node = NULL, 3358c2ecf20Sopenharmony_ci }; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { 3388c2ecf20Sopenharmony_ci DRM_ERROR("Fix bridge driver to make connector optional!"); 3398c2ecf20Sopenharmony_ci return -EINVAL; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ret = drm_connector_init(bridge->dev, &pdata->connector, 3438c2ecf20Sopenharmony_ci &ti_sn_bridge_connector_funcs, 3448c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_eDP); 3458c2ecf20Sopenharmony_ci if (ret) { 3468c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize connector with drm\n"); 3478c2ecf20Sopenharmony_ci return ret; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci drm_connector_helper_add(&pdata->connector, 3518c2ecf20Sopenharmony_ci &ti_sn_bridge_connector_helper_funcs); 3528c2ecf20Sopenharmony_ci drm_connector_attach_encoder(&pdata->connector, bridge->encoder); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * TODO: ideally finding host resource and dsi dev registration needs 3568c2ecf20Sopenharmony_ci * to be done in bridge probe. But some existing DSI host drivers will 3578c2ecf20Sopenharmony_ci * wait for any of the drm_bridge/drm_panel to get added to the global 3588c2ecf20Sopenharmony_ci * bridge/panel list, before completing their probe. So if we do the 3598c2ecf20Sopenharmony_ci * dsi dev registration part in bridge probe, before populating in 3608c2ecf20Sopenharmony_ci * the global bridge list, then it will cause deadlock as dsi host probe 3618c2ecf20Sopenharmony_ci * will never complete, neither our bridge probe. So keeping it here 3628c2ecf20Sopenharmony_ci * will satisfy most of the existing host drivers. Once the host driver 3638c2ecf20Sopenharmony_ci * is fixed we can move the below code to bridge probe safely. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci host = of_find_mipi_dsi_host_by_node(pdata->host_node); 3668c2ecf20Sopenharmony_ci if (!host) { 3678c2ecf20Sopenharmony_ci DRM_ERROR("failed to find dsi host\n"); 3688c2ecf20Sopenharmony_ci ret = -ENODEV; 3698c2ecf20Sopenharmony_ci goto err_dsi_host; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci dsi = mipi_dsi_device_register_full(host, &info); 3738c2ecf20Sopenharmony_ci if (IS_ERR(dsi)) { 3748c2ecf20Sopenharmony_ci DRM_ERROR("failed to create dsi device\n"); 3758c2ecf20Sopenharmony_ci ret = PTR_ERR(dsi); 3768c2ecf20Sopenharmony_ci goto err_dsi_host; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* TODO: setting to 4 MIPI lanes always for now */ 3808c2ecf20Sopenharmony_ci dsi->lanes = 4; 3818c2ecf20Sopenharmony_ci dsi->format = MIPI_DSI_FMT_RGB888; 3828c2ecf20Sopenharmony_ci dsi->mode_flags = MIPI_DSI_MODE_VIDEO; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* check if continuous dsi clock is required or not */ 3858c2ecf20Sopenharmony_ci pm_runtime_get_sync(pdata->dev); 3868c2ecf20Sopenharmony_ci regmap_read(pdata->regmap, SN_DPPLL_SRC_REG, &val); 3878c2ecf20Sopenharmony_ci pm_runtime_put(pdata->dev); 3888c2ecf20Sopenharmony_ci if (!(val & DPPLL_CLK_SRC_DSICLK)) 3898c2ecf20Sopenharmony_ci dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ret = mipi_dsi_attach(dsi); 3928c2ecf20Sopenharmony_ci if (ret < 0) { 3938c2ecf20Sopenharmony_ci DRM_ERROR("failed to attach dsi to host\n"); 3948c2ecf20Sopenharmony_ci goto err_dsi_attach; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci pdata->dsi = dsi; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cierr_dsi_attach: 4018c2ecf20Sopenharmony_ci mipi_dsi_device_unregister(dsi); 4028c2ecf20Sopenharmony_cierr_dsi_host: 4038c2ecf20Sopenharmony_ci drm_connector_cleanup(&pdata->connector); 4048c2ecf20Sopenharmony_ci return ret; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic void ti_sn_bridge_disable(struct drm_bridge *bridge) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci drm_panel_disable(pdata->panel); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* disable video stream */ 4148c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, VSTREAM_ENABLE, 0); 4158c2ecf20Sopenharmony_ci /* semi auto link training mode OFF */ 4168c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0); 4178c2ecf20Sopenharmony_ci /* disable DP PLL */ 4188c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci drm_panel_unprepare(pdata->panel); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic u32 ti_sn_bridge_get_dsi_freq(struct ti_sn_bridge *pdata) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci u32 bit_rate_khz, clk_freq_khz; 4268c2ecf20Sopenharmony_ci struct drm_display_mode *mode = 4278c2ecf20Sopenharmony_ci &pdata->bridge.encoder->crtc->state->adjusted_mode; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci bit_rate_khz = mode->clock * 4308c2ecf20Sopenharmony_ci mipi_dsi_pixel_format_to_bpp(pdata->dsi->format); 4318c2ecf20Sopenharmony_ci clk_freq_khz = bit_rate_khz / (pdata->dsi->lanes * 2); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return clk_freq_khz; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/* clk frequencies supported by bridge in Hz in case derived from REFCLK pin */ 4378c2ecf20Sopenharmony_cistatic const u32 ti_sn_bridge_refclk_lut[] = { 4388c2ecf20Sopenharmony_ci 12000000, 4398c2ecf20Sopenharmony_ci 19200000, 4408c2ecf20Sopenharmony_ci 26000000, 4418c2ecf20Sopenharmony_ci 27000000, 4428c2ecf20Sopenharmony_ci 38400000, 4438c2ecf20Sopenharmony_ci}; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci/* clk frequencies supported by bridge in Hz in case derived from DACP/N pin */ 4468c2ecf20Sopenharmony_cistatic const u32 ti_sn_bridge_dsiclk_lut[] = { 4478c2ecf20Sopenharmony_ci 468000000, 4488c2ecf20Sopenharmony_ci 384000000, 4498c2ecf20Sopenharmony_ci 416000000, 4508c2ecf20Sopenharmony_ci 486000000, 4518c2ecf20Sopenharmony_ci 460800000, 4528c2ecf20Sopenharmony_ci}; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void ti_sn_bridge_set_refclk_freq(struct ti_sn_bridge *pdata) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci int i; 4578c2ecf20Sopenharmony_ci u32 refclk_rate; 4588c2ecf20Sopenharmony_ci const u32 *refclk_lut; 4598c2ecf20Sopenharmony_ci size_t refclk_lut_size; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (pdata->refclk) { 4628c2ecf20Sopenharmony_ci refclk_rate = clk_get_rate(pdata->refclk); 4638c2ecf20Sopenharmony_ci refclk_lut = ti_sn_bridge_refclk_lut; 4648c2ecf20Sopenharmony_ci refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_refclk_lut); 4658c2ecf20Sopenharmony_ci clk_prepare_enable(pdata->refclk); 4668c2ecf20Sopenharmony_ci } else { 4678c2ecf20Sopenharmony_ci refclk_rate = ti_sn_bridge_get_dsi_freq(pdata) * 1000; 4688c2ecf20Sopenharmony_ci refclk_lut = ti_sn_bridge_dsiclk_lut; 4698c2ecf20Sopenharmony_ci refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_dsiclk_lut); 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* for i equals to refclk_lut_size means default frequency */ 4738c2ecf20Sopenharmony_ci for (i = 0; i < refclk_lut_size; i++) 4748c2ecf20Sopenharmony_ci if (refclk_lut[i] == refclk_rate) 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_DPPLL_SRC_REG, REFCLK_FREQ_MASK, 4788c2ecf20Sopenharmony_ci REFCLK_FREQ(i)); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic void ti_sn_bridge_set_dsi_rate(struct ti_sn_bridge *pdata) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci unsigned int bit_rate_mhz, clk_freq_mhz; 4848c2ecf20Sopenharmony_ci unsigned int val; 4858c2ecf20Sopenharmony_ci struct drm_display_mode *mode = 4868c2ecf20Sopenharmony_ci &pdata->bridge.encoder->crtc->state->adjusted_mode; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* set DSIA clk frequency */ 4898c2ecf20Sopenharmony_ci bit_rate_mhz = (mode->clock / 1000) * 4908c2ecf20Sopenharmony_ci mipi_dsi_pixel_format_to_bpp(pdata->dsi->format); 4918c2ecf20Sopenharmony_ci clk_freq_mhz = bit_rate_mhz / (pdata->dsi->lanes * 2); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* for each increment in val, frequency increases by 5MHz */ 4948c2ecf20Sopenharmony_ci val = (MIN_DSI_CLK_FREQ_MHZ / 5) + 4958c2ecf20Sopenharmony_ci (((clk_freq_mhz - MIN_DSI_CLK_FREQ_MHZ) / 5) & 0xFF); 4968c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic unsigned int ti_sn_bridge_get_bpp(struct ti_sn_bridge *pdata) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci if (pdata->connector.display_info.bpc <= 6) 5028c2ecf20Sopenharmony_ci return 18; 5038c2ecf20Sopenharmony_ci else 5048c2ecf20Sopenharmony_ci return 24; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* 5088c2ecf20Sopenharmony_ci * LUT index corresponds to register value and 5098c2ecf20Sopenharmony_ci * LUT values corresponds to dp data rate supported 5108c2ecf20Sopenharmony_ci * by the bridge in Mbps unit. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cistatic const unsigned int ti_sn_bridge_dp_rate_lut[] = { 5138c2ecf20Sopenharmony_ci 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400 5148c2ecf20Sopenharmony_ci}; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci unsigned int bit_rate_khz, dp_rate_mhz; 5198c2ecf20Sopenharmony_ci unsigned int i; 5208c2ecf20Sopenharmony_ci struct drm_display_mode *mode = 5218c2ecf20Sopenharmony_ci &pdata->bridge.encoder->crtc->state->adjusted_mode; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* Calculate minimum bit rate based on our pixel clock. */ 5248c2ecf20Sopenharmony_ci bit_rate_khz = mode->clock * ti_sn_bridge_get_bpp(pdata); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* Calculate minimum DP data rate, taking 80% as per DP spec */ 5278c2ecf20Sopenharmony_ci dp_rate_mhz = DIV_ROUND_UP(bit_rate_khz * DP_CLK_FUDGE_NUM, 5288c2ecf20Sopenharmony_ci 1000 * pdata->dp_lanes * DP_CLK_FUDGE_DEN); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci for (i = 1; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++) 5318c2ecf20Sopenharmony_ci if (ti_sn_bridge_dp_rate_lut[i] >= dp_rate_mhz) 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return i; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata, 5388c2ecf20Sopenharmony_ci bool rate_valid[]) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci unsigned int rate_per_200khz; 5418c2ecf20Sopenharmony_ci unsigned int rate_mhz; 5428c2ecf20Sopenharmony_ci u8 dpcd_val; 5438c2ecf20Sopenharmony_ci int ret; 5448c2ecf20Sopenharmony_ci int i, j; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci ret = drm_dp_dpcd_readb(&pdata->aux, DP_EDP_DPCD_REV, &dpcd_val); 5478c2ecf20Sopenharmony_ci if (ret != 1) { 5488c2ecf20Sopenharmony_ci DRM_DEV_ERROR(pdata->dev, 5498c2ecf20Sopenharmony_ci "Can't read eDP rev (%d), assuming 1.1\n", ret); 5508c2ecf20Sopenharmony_ci dpcd_val = DP_EDP_11; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (dpcd_val >= DP_EDP_14) { 5548c2ecf20Sopenharmony_ci /* eDP 1.4 devices must provide a custom table */ 5558c2ecf20Sopenharmony_ci __le16 sink_rates[DP_MAX_SUPPORTED_RATES]; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci ret = drm_dp_dpcd_read(&pdata->aux, DP_SUPPORTED_LINK_RATES, 5588c2ecf20Sopenharmony_ci sink_rates, sizeof(sink_rates)); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (ret != sizeof(sink_rates)) { 5618c2ecf20Sopenharmony_ci DRM_DEV_ERROR(pdata->dev, 5628c2ecf20Sopenharmony_ci "Can't read supported rate table (%d)\n", ret); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* By zeroing we'll fall back to DP_MAX_LINK_RATE. */ 5658c2ecf20Sopenharmony_ci memset(sink_rates, 0, sizeof(sink_rates)); 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sink_rates); i++) { 5698c2ecf20Sopenharmony_ci rate_per_200khz = le16_to_cpu(sink_rates[i]); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (!rate_per_200khz) 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci rate_mhz = rate_per_200khz * 200 / 1000; 5758c2ecf20Sopenharmony_ci for (j = 0; 5768c2ecf20Sopenharmony_ci j < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); 5778c2ecf20Sopenharmony_ci j++) { 5788c2ecf20Sopenharmony_ci if (ti_sn_bridge_dp_rate_lut[j] == rate_mhz) 5798c2ecf20Sopenharmony_ci rate_valid[j] = true; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); i++) { 5848c2ecf20Sopenharmony_ci if (rate_valid[i]) 5858c2ecf20Sopenharmony_ci return; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci DRM_DEV_ERROR(pdata->dev, 5888c2ecf20Sopenharmony_ci "No matching eDP rates in table; falling back\n"); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* On older versions best we can do is use DP_MAX_LINK_RATE */ 5928c2ecf20Sopenharmony_ci ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &dpcd_val); 5938c2ecf20Sopenharmony_ci if (ret != 1) { 5948c2ecf20Sopenharmony_ci DRM_DEV_ERROR(pdata->dev, 5958c2ecf20Sopenharmony_ci "Can't read max rate (%d); assuming 5.4 GHz\n", 5968c2ecf20Sopenharmony_ci ret); 5978c2ecf20Sopenharmony_ci dpcd_val = DP_LINK_BW_5_4; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci switch (dpcd_val) { 6018c2ecf20Sopenharmony_ci default: 6028c2ecf20Sopenharmony_ci DRM_DEV_ERROR(pdata->dev, 6038c2ecf20Sopenharmony_ci "Unexpected max rate (%#x); assuming 5.4 GHz\n", 6048c2ecf20Sopenharmony_ci (int)dpcd_val); 6058c2ecf20Sopenharmony_ci fallthrough; 6068c2ecf20Sopenharmony_ci case DP_LINK_BW_5_4: 6078c2ecf20Sopenharmony_ci rate_valid[7] = 1; 6088c2ecf20Sopenharmony_ci fallthrough; 6098c2ecf20Sopenharmony_ci case DP_LINK_BW_2_7: 6108c2ecf20Sopenharmony_ci rate_valid[4] = 1; 6118c2ecf20Sopenharmony_ci fallthrough; 6128c2ecf20Sopenharmony_ci case DP_LINK_BW_1_62: 6138c2ecf20Sopenharmony_ci rate_valid[1] = 1; 6148c2ecf20Sopenharmony_ci break; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct drm_display_mode *mode = 6218c2ecf20Sopenharmony_ci &pdata->bridge.encoder->crtc->state->adjusted_mode; 6228c2ecf20Sopenharmony_ci u8 hsync_polarity = 0, vsync_polarity = 0; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NHSYNC) 6258c2ecf20Sopenharmony_ci hsync_polarity = CHA_HSYNC_POLARITY; 6268c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NVSYNC) 6278c2ecf20Sopenharmony_ci vsync_polarity = CHA_VSYNC_POLARITY; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci ti_sn_bridge_write_u16(pdata, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG, 6308c2ecf20Sopenharmony_ci mode->hdisplay); 6318c2ecf20Sopenharmony_ci ti_sn_bridge_write_u16(pdata, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG, 6328c2ecf20Sopenharmony_ci mode->vdisplay); 6338c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG, 6348c2ecf20Sopenharmony_ci (mode->hsync_end - mode->hsync_start) & 0xFF); 6358c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG, 6368c2ecf20Sopenharmony_ci (((mode->hsync_end - mode->hsync_start) >> 8) & 0x7F) | 6378c2ecf20Sopenharmony_ci hsync_polarity); 6388c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG, 6398c2ecf20Sopenharmony_ci (mode->vsync_end - mode->vsync_start) & 0xFF); 6408c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG, 6418c2ecf20Sopenharmony_ci (((mode->vsync_end - mode->vsync_start) >> 8) & 0x7F) | 6428c2ecf20Sopenharmony_ci vsync_polarity); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_CHA_HORIZONTAL_BACK_PORCH_REG, 6458c2ecf20Sopenharmony_ci (mode->htotal - mode->hsync_end) & 0xFF); 6468c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_CHA_VERTICAL_BACK_PORCH_REG, 6478c2ecf20Sopenharmony_ci (mode->vtotal - mode->vsync_end) & 0xFF); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_CHA_HORIZONTAL_FRONT_PORCH_REG, 6508c2ecf20Sopenharmony_ci (mode->hsync_start - mode->hdisplay) & 0xFF); 6518c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_CHA_VERTICAL_FRONT_PORCH_REG, 6528c2ecf20Sopenharmony_ci (mode->vsync_start - mode->vdisplay) & 0xFF); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci usleep_range(10000, 10500); /* 10ms delay recommended by spec */ 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic unsigned int ti_sn_get_max_lanes(struct ti_sn_bridge *pdata) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci u8 data; 6608c2ecf20Sopenharmony_ci int ret; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LANE_COUNT, &data); 6638c2ecf20Sopenharmony_ci if (ret != 1) { 6648c2ecf20Sopenharmony_ci DRM_DEV_ERROR(pdata->dev, 6658c2ecf20Sopenharmony_ci "Can't read lane count (%d); assuming 4\n", ret); 6668c2ecf20Sopenharmony_ci return 4; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return data & DP_LANE_COUNT_MASK; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx, 6738c2ecf20Sopenharmony_ci const char **last_err_str) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci unsigned int val; 6768c2ecf20Sopenharmony_ci int ret; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* set dp clk frequency value */ 6798c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG, 6808c2ecf20Sopenharmony_ci DP_DATARATE_MASK, DP_DATARATE(dp_rate_idx)); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* enable DP PLL */ 6838c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(pdata->regmap, SN_DPPLL_SRC_REG, val, 6868c2ecf20Sopenharmony_ci val & DPPLL_SRC_DP_PLL_LOCK, 1000, 6878c2ecf20Sopenharmony_ci 50 * 1000); 6888c2ecf20Sopenharmony_ci if (ret) { 6898c2ecf20Sopenharmony_ci *last_err_str = "DP_PLL_LOCK polling failed"; 6908c2ecf20Sopenharmony_ci goto exit; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* Semi auto link training mode */ 6948c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A); 6958c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(pdata->regmap, SN_ML_TX_MODE_REG, val, 6968c2ecf20Sopenharmony_ci val == ML_TX_MAIN_LINK_OFF || 6978c2ecf20Sopenharmony_ci val == ML_TX_NORMAL_MODE, 1000, 6988c2ecf20Sopenharmony_ci 500 * 1000); 6998c2ecf20Sopenharmony_ci if (ret) { 7008c2ecf20Sopenharmony_ci *last_err_str = "Training complete polling failed"; 7018c2ecf20Sopenharmony_ci } else if (val == ML_TX_MAIN_LINK_OFF) { 7028c2ecf20Sopenharmony_ci *last_err_str = "Link training failed, link is off"; 7038c2ecf20Sopenharmony_ci ret = -EIO; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ciexit: 7078c2ecf20Sopenharmony_ci /* Disable the PLL if we failed */ 7088c2ecf20Sopenharmony_ci if (ret) 7098c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return ret; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic void ti_sn_bridge_enable(struct drm_bridge *bridge) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); 7178c2ecf20Sopenharmony_ci bool rate_valid[ARRAY_SIZE(ti_sn_bridge_dp_rate_lut)] = { }; 7188c2ecf20Sopenharmony_ci const char *last_err_str = "No supported DP rate"; 7198c2ecf20Sopenharmony_ci int dp_rate_idx; 7208c2ecf20Sopenharmony_ci unsigned int val; 7218c2ecf20Sopenharmony_ci int ret = -EINVAL; 7228c2ecf20Sopenharmony_ci int max_dp_lanes; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci max_dp_lanes = ti_sn_get_max_lanes(pdata); 7258c2ecf20Sopenharmony_ci pdata->dp_lanes = min(pdata->dp_lanes, max_dp_lanes); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* DSI_A lane config */ 7288c2ecf20Sopenharmony_ci val = CHA_DSI_LANES(SN_MAX_DP_LANES - pdata->dsi->lanes); 7298c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG, 7308c2ecf20Sopenharmony_ci CHA_DSI_LANES_MASK, val); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_LN_ASSIGN_REG, pdata->ln_assign); 7338c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, LN_POLRS_MASK, 7348c2ecf20Sopenharmony_ci pdata->ln_polrs << LN_POLRS_OFFSET); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* set dsi clk frequency value */ 7378c2ecf20Sopenharmony_ci ti_sn_bridge_set_dsi_rate(pdata); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /** 7408c2ecf20Sopenharmony_ci * The SN65DSI86 only supports ASSR Display Authentication method and 7418c2ecf20Sopenharmony_ci * this method is enabled by default. An eDP panel must support this 7428c2ecf20Sopenharmony_ci * authentication method. We need to enable this method in the eDP panel 7438c2ecf20Sopenharmony_ci * at DisplayPort address 0x0010A prior to link training. 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_ci drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET, 7468c2ecf20Sopenharmony_ci DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* Set the DP output format (18 bpp or 24 bpp) */ 7498c2ecf20Sopenharmony_ci val = (ti_sn_bridge_get_bpp(pdata) == 18) ? BPP_18_RGB : 0; 7508c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_DATA_FORMAT_REG, BPP_18_RGB, val); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* DP lane config */ 7538c2ecf20Sopenharmony_ci val = DP_NUM_LANES(min(pdata->dp_lanes, 3)); 7548c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK, 7558c2ecf20Sopenharmony_ci val); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ti_sn_bridge_read_valid_rates(pdata, rate_valid); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* Train until we run out of rates */ 7608c2ecf20Sopenharmony_ci for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata); 7618c2ecf20Sopenharmony_ci dp_rate_idx < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); 7628c2ecf20Sopenharmony_ci dp_rate_idx++) { 7638c2ecf20Sopenharmony_ci if (!rate_valid[dp_rate_idx]) 7648c2ecf20Sopenharmony_ci continue; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci ret = ti_sn_link_training(pdata, dp_rate_idx, &last_err_str); 7678c2ecf20Sopenharmony_ci if (!ret) 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci if (ret) { 7718c2ecf20Sopenharmony_ci DRM_DEV_ERROR(pdata->dev, "%s (%d)\n", last_err_str, ret); 7728c2ecf20Sopenharmony_ci return; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* config video parameters */ 7768c2ecf20Sopenharmony_ci ti_sn_bridge_set_video_timings(pdata); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* enable video stream */ 7798c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, VSTREAM_ENABLE, 7808c2ecf20Sopenharmony_ci VSTREAM_ENABLE); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci drm_panel_enable(pdata->panel); 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic void ti_sn_bridge_pre_enable(struct drm_bridge *bridge) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci pm_runtime_get_sync(pdata->dev); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* configure bridge ref_clk */ 7928c2ecf20Sopenharmony_ci ti_sn_bridge_set_refclk_freq(pdata); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* 7958c2ecf20Sopenharmony_ci * HPD on this bridge chip is a bit useless. This is an eDP bridge 7968c2ecf20Sopenharmony_ci * so the HPD is an internal signal that's only there to signal that 7978c2ecf20Sopenharmony_ci * the panel is done powering up. ...but the bridge chip debounces 7988c2ecf20Sopenharmony_ci * this signal by between 100 ms and 400 ms (depending on process, 7998c2ecf20Sopenharmony_ci * voltage, and temperate--I measured it at about 200 ms). One 8008c2ecf20Sopenharmony_ci * particular panel asserted HPD 84 ms after it was powered on meaning 8018c2ecf20Sopenharmony_ci * that we saw HPD 284 ms after power on. ...but the same panel said 8028c2ecf20Sopenharmony_ci * that instead of looking at HPD you could just hardcode a delay of 8038c2ecf20Sopenharmony_ci * 200 ms. We'll assume that the panel driver will have the hardcoded 8048c2ecf20Sopenharmony_ci * delay in its prepare and always disable HPD. 8058c2ecf20Sopenharmony_ci * 8068c2ecf20Sopenharmony_ci * If HPD somehow makes sense on some future panel we'll have to 8078c2ecf20Sopenharmony_ci * change this to be conditional on someone specifying that HPD should 8088c2ecf20Sopenharmony_ci * be used. 8098c2ecf20Sopenharmony_ci */ 8108c2ecf20Sopenharmony_ci regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE, 8118c2ecf20Sopenharmony_ci HPD_DISABLE); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci drm_panel_prepare(pdata->panel); 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic void ti_sn_bridge_post_disable(struct drm_bridge *bridge) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (pdata->refclk) 8218c2ecf20Sopenharmony_ci clk_disable_unprepare(pdata->refclk); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci pm_runtime_put_sync(pdata->dev); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs ti_sn_bridge_funcs = { 8278c2ecf20Sopenharmony_ci .attach = ti_sn_bridge_attach, 8288c2ecf20Sopenharmony_ci .pre_enable = ti_sn_bridge_pre_enable, 8298c2ecf20Sopenharmony_ci .enable = ti_sn_bridge_enable, 8308c2ecf20Sopenharmony_ci .disable = ti_sn_bridge_disable, 8318c2ecf20Sopenharmony_ci .post_disable = ti_sn_bridge_post_disable, 8328c2ecf20Sopenharmony_ci}; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic struct ti_sn_bridge *aux_to_ti_sn_bridge(struct drm_dp_aux *aux) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci return container_of(aux, struct ti_sn_bridge, aux); 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, 8408c2ecf20Sopenharmony_ci struct drm_dp_aux_msg *msg) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = aux_to_ti_sn_bridge(aux); 8438c2ecf20Sopenharmony_ci u32 request = msg->request & ~DP_AUX_I2C_MOT; 8448c2ecf20Sopenharmony_ci u32 request_val = AUX_CMD_REQ(msg->request); 8458c2ecf20Sopenharmony_ci u8 *buf = (u8 *)msg->buffer; 8468c2ecf20Sopenharmony_ci unsigned int val; 8478c2ecf20Sopenharmony_ci int ret, i; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (msg->size > SN_AUX_MAX_PAYLOAD_BYTES) 8508c2ecf20Sopenharmony_ci return -EINVAL; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci switch (request) { 8538c2ecf20Sopenharmony_ci case DP_AUX_NATIVE_WRITE: 8548c2ecf20Sopenharmony_ci case DP_AUX_I2C_WRITE: 8558c2ecf20Sopenharmony_ci case DP_AUX_NATIVE_READ: 8568c2ecf20Sopenharmony_ci case DP_AUX_I2C_READ: 8578c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val); 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci default: 8608c2ecf20Sopenharmony_ci return -EINVAL; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_AUX_ADDR_19_16_REG, 8648c2ecf20Sopenharmony_ci (msg->address >> 16) & 0xF); 8658c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_AUX_ADDR_15_8_REG, 8668c2ecf20Sopenharmony_ci (msg->address >> 8) & 0xFF); 8678c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_AUX_ADDR_7_0_REG, msg->address & 0xFF); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_AUX_LENGTH_REG, msg->size); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE) { 8728c2ecf20Sopenharmony_ci for (i = 0; i < msg->size; i++) 8738c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_AUX_WDATA_REG(i), 8748c2ecf20Sopenharmony_ci buf[i]); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* Clear old status bits before start so we don't get confused */ 8788c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_AUX_CMD_STATUS_REG, 8798c2ecf20Sopenharmony_ci AUX_IRQ_STATUS_NAT_I2C_FAIL | 8808c2ecf20Sopenharmony_ci AUX_IRQ_STATUS_AUX_RPLY_TOUT | 8818c2ecf20Sopenharmony_ci AUX_IRQ_STATUS_AUX_SHORT); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val | AUX_CMD_SEND); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(pdata->regmap, SN_AUX_CMD_REG, val, 8868c2ecf20Sopenharmony_ci !(val & AUX_CMD_SEND), 200, 8878c2ecf20Sopenharmony_ci 50 * 1000); 8888c2ecf20Sopenharmony_ci if (ret) 8898c2ecf20Sopenharmony_ci return ret; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci ret = regmap_read(pdata->regmap, SN_AUX_CMD_STATUS_REG, &val); 8928c2ecf20Sopenharmony_ci if (ret) 8938c2ecf20Sopenharmony_ci return ret; 8948c2ecf20Sopenharmony_ci else if ((val & AUX_IRQ_STATUS_NAT_I2C_FAIL) 8958c2ecf20Sopenharmony_ci || (val & AUX_IRQ_STATUS_AUX_RPLY_TOUT) 8968c2ecf20Sopenharmony_ci || (val & AUX_IRQ_STATUS_AUX_SHORT)) 8978c2ecf20Sopenharmony_ci return -ENXIO; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE) 9008c2ecf20Sopenharmony_ci return msg->size; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci for (i = 0; i < msg->size; i++) { 9038c2ecf20Sopenharmony_ci unsigned int val; 9048c2ecf20Sopenharmony_ci ret = regmap_read(pdata->regmap, SN_AUX_RDATA_REG(i), 9058c2ecf20Sopenharmony_ci &val); 9068c2ecf20Sopenharmony_ci if (ret) 9078c2ecf20Sopenharmony_ci return ret; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci WARN_ON(val & ~0xFF); 9108c2ecf20Sopenharmony_ci buf[i] = (u8)(val & 0xFF); 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return msg->size; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int ti_sn_bridge_parse_dsi_host(struct ti_sn_bridge *pdata) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci struct device_node *np = pdata->dev->of_node; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci pdata->host_node = of_graph_get_remote_node(np, 0, 0); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (!pdata->host_node) { 9238c2ecf20Sopenharmony_ci DRM_ERROR("remote dsi host node not found\n"); 9248c2ecf20Sopenharmony_ci return -ENODEV; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci return 0; 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci#if defined(CONFIG_OF_GPIO) 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic int tn_sn_bridge_of_xlate(struct gpio_chip *chip, 9338c2ecf20Sopenharmony_ci const struct of_phandle_args *gpiospec, 9348c2ecf20Sopenharmony_ci u32 *flags) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci if (WARN_ON(gpiospec->args_count < chip->of_gpio_n_cells)) 9378c2ecf20Sopenharmony_ci return -EINVAL; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (gpiospec->args[0] > chip->ngpio || gpiospec->args[0] < 1) 9408c2ecf20Sopenharmony_ci return -EINVAL; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (flags) 9438c2ecf20Sopenharmony_ci *flags = gpiospec->args[1]; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci return gpiospec->args[0] - SN_GPIO_PHYSICAL_OFFSET; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic int ti_sn_bridge_gpio_get_direction(struct gpio_chip *chip, 9498c2ecf20Sopenharmony_ci unsigned int offset) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = gpiochip_get_data(chip); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* 9548c2ecf20Sopenharmony_ci * We already have to keep track of the direction because we use 9558c2ecf20Sopenharmony_ci * that to figure out whether we've powered the device. We can 9568c2ecf20Sopenharmony_ci * just return that rather than (maybe) powering up the device 9578c2ecf20Sopenharmony_ci * to ask its direction. 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_ci return test_bit(offset, pdata->gchip_output) ? 9608c2ecf20Sopenharmony_ci GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic int ti_sn_bridge_gpio_get(struct gpio_chip *chip, unsigned int offset) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = gpiochip_get_data(chip); 9668c2ecf20Sopenharmony_ci unsigned int val; 9678c2ecf20Sopenharmony_ci int ret; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* 9708c2ecf20Sopenharmony_ci * When the pin is an input we don't forcibly keep the bridge 9718c2ecf20Sopenharmony_ci * powered--we just power it on to read the pin. NOTE: part of 9728c2ecf20Sopenharmony_ci * the reason this works is that the bridge defaults (when 9738c2ecf20Sopenharmony_ci * powered back on) to all 4 GPIOs being configured as GPIO input. 9748c2ecf20Sopenharmony_ci * Also note that if something else is keeping the chip powered the 9758c2ecf20Sopenharmony_ci * pm_runtime functions are lightweight increments of a refcount. 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ci pm_runtime_get_sync(pdata->dev); 9788c2ecf20Sopenharmony_ci ret = regmap_read(pdata->regmap, SN_GPIO_IO_REG, &val); 9798c2ecf20Sopenharmony_ci pm_runtime_put(pdata->dev); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (ret) 9828c2ecf20Sopenharmony_ci return ret; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci return !!(val & BIT(SN_GPIO_INPUT_SHIFT + offset)); 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic void ti_sn_bridge_gpio_set(struct gpio_chip *chip, unsigned int offset, 9888c2ecf20Sopenharmony_ci int val) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = gpiochip_get_data(chip); 9918c2ecf20Sopenharmony_ci int ret; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (!test_bit(offset, pdata->gchip_output)) { 9948c2ecf20Sopenharmony_ci dev_err(pdata->dev, "Ignoring GPIO set while input\n"); 9958c2ecf20Sopenharmony_ci return; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci val &= 1; 9998c2ecf20Sopenharmony_ci ret = regmap_update_bits(pdata->regmap, SN_GPIO_IO_REG, 10008c2ecf20Sopenharmony_ci BIT(SN_GPIO_OUTPUT_SHIFT + offset), 10018c2ecf20Sopenharmony_ci val << (SN_GPIO_OUTPUT_SHIFT + offset)); 10028c2ecf20Sopenharmony_ci if (ret) 10038c2ecf20Sopenharmony_ci dev_warn(pdata->dev, 10048c2ecf20Sopenharmony_ci "Failed to set bridge GPIO %u: %d\n", offset, ret); 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic int ti_sn_bridge_gpio_direction_input(struct gpio_chip *chip, 10088c2ecf20Sopenharmony_ci unsigned int offset) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = gpiochip_get_data(chip); 10118c2ecf20Sopenharmony_ci int shift = offset * 2; 10128c2ecf20Sopenharmony_ci int ret; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (!test_and_clear_bit(offset, pdata->gchip_output)) 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci ret = regmap_update_bits(pdata->regmap, SN_GPIO_CTRL_REG, 10188c2ecf20Sopenharmony_ci SN_GPIO_MUX_MASK << shift, 10198c2ecf20Sopenharmony_ci SN_GPIO_MUX_INPUT << shift); 10208c2ecf20Sopenharmony_ci if (ret) { 10218c2ecf20Sopenharmony_ci set_bit(offset, pdata->gchip_output); 10228c2ecf20Sopenharmony_ci return ret; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* 10268c2ecf20Sopenharmony_ci * NOTE: if nobody else is powering the device this may fully power 10278c2ecf20Sopenharmony_ci * it off and when it comes back it will have lost all state, but 10288c2ecf20Sopenharmony_ci * that's OK because the default is input and we're now an input. 10298c2ecf20Sopenharmony_ci */ 10308c2ecf20Sopenharmony_ci pm_runtime_put(pdata->dev); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic int ti_sn_bridge_gpio_direction_output(struct gpio_chip *chip, 10368c2ecf20Sopenharmony_ci unsigned int offset, int val) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = gpiochip_get_data(chip); 10398c2ecf20Sopenharmony_ci int shift = offset * 2; 10408c2ecf20Sopenharmony_ci int ret; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (test_and_set_bit(offset, pdata->gchip_output)) 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci pm_runtime_get_sync(pdata->dev); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* Set value first to avoid glitching */ 10488c2ecf20Sopenharmony_ci ti_sn_bridge_gpio_set(chip, offset, val); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* Set direction */ 10518c2ecf20Sopenharmony_ci ret = regmap_update_bits(pdata->regmap, SN_GPIO_CTRL_REG, 10528c2ecf20Sopenharmony_ci SN_GPIO_MUX_MASK << shift, 10538c2ecf20Sopenharmony_ci SN_GPIO_MUX_OUTPUT << shift); 10548c2ecf20Sopenharmony_ci if (ret) { 10558c2ecf20Sopenharmony_ci clear_bit(offset, pdata->gchip_output); 10568c2ecf20Sopenharmony_ci pm_runtime_put(pdata->dev); 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci return ret; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic void ti_sn_bridge_gpio_free(struct gpio_chip *chip, unsigned int offset) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci /* We won't keep pm_runtime if we're input, so switch there on free */ 10658c2ecf20Sopenharmony_ci ti_sn_bridge_gpio_direction_input(chip, offset); 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic const char * const ti_sn_bridge_gpio_names[SN_NUM_GPIOS] = { 10698c2ecf20Sopenharmony_ci "GPIO1", "GPIO2", "GPIO3", "GPIO4" 10708c2ecf20Sopenharmony_ci}; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic int ti_sn_setup_gpio_controller(struct ti_sn_bridge *pdata) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci int ret; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci /* Only init if someone is going to use us as a GPIO controller */ 10778c2ecf20Sopenharmony_ci if (!of_property_read_bool(pdata->dev->of_node, "gpio-controller")) 10788c2ecf20Sopenharmony_ci return 0; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci pdata->gchip.label = dev_name(pdata->dev); 10818c2ecf20Sopenharmony_ci pdata->gchip.parent = pdata->dev; 10828c2ecf20Sopenharmony_ci pdata->gchip.owner = THIS_MODULE; 10838c2ecf20Sopenharmony_ci pdata->gchip.of_xlate = tn_sn_bridge_of_xlate; 10848c2ecf20Sopenharmony_ci pdata->gchip.of_gpio_n_cells = 2; 10858c2ecf20Sopenharmony_ci pdata->gchip.free = ti_sn_bridge_gpio_free; 10868c2ecf20Sopenharmony_ci pdata->gchip.get_direction = ti_sn_bridge_gpio_get_direction; 10878c2ecf20Sopenharmony_ci pdata->gchip.direction_input = ti_sn_bridge_gpio_direction_input; 10888c2ecf20Sopenharmony_ci pdata->gchip.direction_output = ti_sn_bridge_gpio_direction_output; 10898c2ecf20Sopenharmony_ci pdata->gchip.get = ti_sn_bridge_gpio_get; 10908c2ecf20Sopenharmony_ci pdata->gchip.set = ti_sn_bridge_gpio_set; 10918c2ecf20Sopenharmony_ci pdata->gchip.can_sleep = true; 10928c2ecf20Sopenharmony_ci pdata->gchip.names = ti_sn_bridge_gpio_names; 10938c2ecf20Sopenharmony_ci pdata->gchip.ngpio = SN_NUM_GPIOS; 10948c2ecf20Sopenharmony_ci pdata->gchip.base = -1; 10958c2ecf20Sopenharmony_ci ret = devm_gpiochip_add_data(pdata->dev, &pdata->gchip, pdata); 10968c2ecf20Sopenharmony_ci if (ret) 10978c2ecf20Sopenharmony_ci dev_err(pdata->dev, "can't add gpio chip\n"); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return ret; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci#else 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic inline int ti_sn_setup_gpio_controller(struct ti_sn_bridge *pdata) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci return 0; 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci#endif 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic void ti_sn_bridge_parse_lanes(struct ti_sn_bridge *pdata, 11128c2ecf20Sopenharmony_ci struct device_node *np) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci u32 lane_assignments[SN_MAX_DP_LANES] = { 0, 1, 2, 3 }; 11158c2ecf20Sopenharmony_ci u32 lane_polarities[SN_MAX_DP_LANES] = { }; 11168c2ecf20Sopenharmony_ci struct device_node *endpoint; 11178c2ecf20Sopenharmony_ci u8 ln_assign = 0; 11188c2ecf20Sopenharmony_ci u8 ln_polrs = 0; 11198c2ecf20Sopenharmony_ci int dp_lanes; 11208c2ecf20Sopenharmony_ci int i; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* 11238c2ecf20Sopenharmony_ci * Read config from the device tree about lane remapping and lane 11248c2ecf20Sopenharmony_ci * polarities. These are optional and we assume identity map and 11258c2ecf20Sopenharmony_ci * normal polarity if nothing is specified. It's OK to specify just 11268c2ecf20Sopenharmony_ci * data-lanes but not lane-polarities but not vice versa. 11278c2ecf20Sopenharmony_ci * 11288c2ecf20Sopenharmony_ci * Error checking is light (we just make sure we don't crash or 11298c2ecf20Sopenharmony_ci * buffer overrun) and we assume dts is well formed and specifying 11308c2ecf20Sopenharmony_ci * mappings that the hardware supports. 11318c2ecf20Sopenharmony_ci */ 11328c2ecf20Sopenharmony_ci endpoint = of_graph_get_endpoint_by_regs(np, 1, -1); 11338c2ecf20Sopenharmony_ci dp_lanes = of_property_count_u32_elems(endpoint, "data-lanes"); 11348c2ecf20Sopenharmony_ci if (dp_lanes > 0 && dp_lanes <= SN_MAX_DP_LANES) { 11358c2ecf20Sopenharmony_ci of_property_read_u32_array(endpoint, "data-lanes", 11368c2ecf20Sopenharmony_ci lane_assignments, dp_lanes); 11378c2ecf20Sopenharmony_ci of_property_read_u32_array(endpoint, "lane-polarities", 11388c2ecf20Sopenharmony_ci lane_polarities, dp_lanes); 11398c2ecf20Sopenharmony_ci } else { 11408c2ecf20Sopenharmony_ci dp_lanes = SN_MAX_DP_LANES; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci of_node_put(endpoint); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* 11458c2ecf20Sopenharmony_ci * Convert into register format. Loop over all lanes even if 11468c2ecf20Sopenharmony_ci * data-lanes had fewer elements so that we nicely initialize 11478c2ecf20Sopenharmony_ci * the LN_ASSIGN register. 11488c2ecf20Sopenharmony_ci */ 11498c2ecf20Sopenharmony_ci for (i = SN_MAX_DP_LANES - 1; i >= 0; i--) { 11508c2ecf20Sopenharmony_ci ln_assign = ln_assign << LN_ASSIGN_WIDTH | lane_assignments[i]; 11518c2ecf20Sopenharmony_ci ln_polrs = ln_polrs << 1 | lane_polarities[i]; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* Stash in our struct for when we power on */ 11558c2ecf20Sopenharmony_ci pdata->dp_lanes = dp_lanes; 11568c2ecf20Sopenharmony_ci pdata->ln_assign = ln_assign; 11578c2ecf20Sopenharmony_ci pdata->ln_polrs = ln_polrs; 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_cistatic int ti_sn_bridge_probe(struct i2c_client *client, 11618c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata; 11648c2ecf20Sopenharmony_ci int ret; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 11678c2ecf20Sopenharmony_ci DRM_ERROR("device doesn't support I2C\n"); 11688c2ecf20Sopenharmony_ci return -ENODEV; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci pdata = devm_kzalloc(&client->dev, sizeof(struct ti_sn_bridge), 11728c2ecf20Sopenharmony_ci GFP_KERNEL); 11738c2ecf20Sopenharmony_ci if (!pdata) 11748c2ecf20Sopenharmony_ci return -ENOMEM; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci pdata->regmap = devm_regmap_init_i2c(client, 11778c2ecf20Sopenharmony_ci &ti_sn_bridge_regmap_config); 11788c2ecf20Sopenharmony_ci if (IS_ERR(pdata->regmap)) { 11798c2ecf20Sopenharmony_ci DRM_ERROR("regmap i2c init failed\n"); 11808c2ecf20Sopenharmony_ci return PTR_ERR(pdata->regmap); 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci pdata->dev = &client->dev; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci ret = drm_of_find_panel_or_bridge(pdata->dev->of_node, 1, 0, 11868c2ecf20Sopenharmony_ci &pdata->panel, NULL); 11878c2ecf20Sopenharmony_ci if (ret) { 11888c2ecf20Sopenharmony_ci DRM_ERROR("could not find any panel node\n"); 11898c2ecf20Sopenharmony_ci return ret; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci dev_set_drvdata(&client->dev, pdata); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci pdata->enable_gpio = devm_gpiod_get(pdata->dev, "enable", 11958c2ecf20Sopenharmony_ci GPIOD_OUT_LOW); 11968c2ecf20Sopenharmony_ci if (IS_ERR(pdata->enable_gpio)) { 11978c2ecf20Sopenharmony_ci DRM_ERROR("failed to get enable gpio from DT\n"); 11988c2ecf20Sopenharmony_ci ret = PTR_ERR(pdata->enable_gpio); 11998c2ecf20Sopenharmony_ci return ret; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci ti_sn_bridge_parse_lanes(pdata, client->dev.of_node); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci ret = ti_sn_bridge_parse_regulators(pdata); 12058c2ecf20Sopenharmony_ci if (ret) { 12068c2ecf20Sopenharmony_ci DRM_ERROR("failed to parse regulators\n"); 12078c2ecf20Sopenharmony_ci return ret; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci pdata->refclk = devm_clk_get(pdata->dev, "refclk"); 12118c2ecf20Sopenharmony_ci if (IS_ERR(pdata->refclk)) { 12128c2ecf20Sopenharmony_ci ret = PTR_ERR(pdata->refclk); 12138c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 12148c2ecf20Sopenharmony_ci return ret; 12158c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("refclk not found\n"); 12168c2ecf20Sopenharmony_ci pdata->refclk = NULL; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci ret = ti_sn_bridge_parse_dsi_host(pdata); 12208c2ecf20Sopenharmony_ci if (ret) 12218c2ecf20Sopenharmony_ci return ret; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci pm_runtime_enable(pdata->dev); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci ret = ti_sn_setup_gpio_controller(pdata); 12268c2ecf20Sopenharmony_ci if (ret) { 12278c2ecf20Sopenharmony_ci pm_runtime_disable(pdata->dev); 12288c2ecf20Sopenharmony_ci return ret; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci i2c_set_clientdata(client, pdata); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci pdata->aux.name = "ti-sn65dsi86-aux"; 12348c2ecf20Sopenharmony_ci pdata->aux.dev = pdata->dev; 12358c2ecf20Sopenharmony_ci pdata->aux.transfer = ti_sn_aux_transfer; 12368c2ecf20Sopenharmony_ci drm_dp_aux_register(&pdata->aux); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci pdata->bridge.funcs = &ti_sn_bridge_funcs; 12398c2ecf20Sopenharmony_ci pdata->bridge.of_node = client->dev.of_node; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci drm_bridge_add(&pdata->bridge); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci ti_sn_debugfs_init(pdata); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return 0; 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cistatic int ti_sn_bridge_remove(struct i2c_client *client) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci struct ti_sn_bridge *pdata = i2c_get_clientdata(client); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (!pdata) 12538c2ecf20Sopenharmony_ci return -EINVAL; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci ti_sn_debugfs_remove(pdata); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci of_node_put(pdata->host_node); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci pm_runtime_disable(pdata->dev); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (pdata->dsi) { 12628c2ecf20Sopenharmony_ci mipi_dsi_detach(pdata->dsi); 12638c2ecf20Sopenharmony_ci mipi_dsi_device_unregister(pdata->dsi); 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci drm_bridge_remove(&pdata->bridge); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci return 0; 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_cistatic struct i2c_device_id ti_sn_bridge_id[] = { 12728c2ecf20Sopenharmony_ci { "ti,sn65dsi86", 0}, 12738c2ecf20Sopenharmony_ci {}, 12748c2ecf20Sopenharmony_ci}; 12758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ti_sn_bridge_id); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cistatic const struct of_device_id ti_sn_bridge_match_table[] = { 12788c2ecf20Sopenharmony_ci {.compatible = "ti,sn65dsi86"}, 12798c2ecf20Sopenharmony_ci {}, 12808c2ecf20Sopenharmony_ci}; 12818c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ti_sn_bridge_match_table); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic struct i2c_driver ti_sn_bridge_driver = { 12848c2ecf20Sopenharmony_ci .driver = { 12858c2ecf20Sopenharmony_ci .name = "ti_sn65dsi86", 12868c2ecf20Sopenharmony_ci .of_match_table = ti_sn_bridge_match_table, 12878c2ecf20Sopenharmony_ci .pm = &ti_sn_bridge_pm_ops, 12888c2ecf20Sopenharmony_ci }, 12898c2ecf20Sopenharmony_ci .probe = ti_sn_bridge_probe, 12908c2ecf20Sopenharmony_ci .remove = ti_sn_bridge_remove, 12918c2ecf20Sopenharmony_ci .id_table = ti_sn_bridge_id, 12928c2ecf20Sopenharmony_ci}; 12938c2ecf20Sopenharmony_cimodule_i2c_driver(ti_sn_bridge_driver); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sandeep Panda <spanda@codeaurora.org>"); 12968c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("sn65dsi86 DSI to eDP bridge driver"); 12978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1298