1013413cdSMasahiro Yamada // SPDX-License-Identifier: GPL-2.0+ 2013413cdSMasahiro Yamada 3013413cdSMasahiro Yamada /* 4013413cdSMasahiro Yamada * Copyright 2020 NXP 5013413cdSMasahiro Yamada */ 6013413cdSMasahiro Yamada 7013413cdSMasahiro Yamada #include <linux/clk.h> 8013413cdSMasahiro Yamada #include <linux/media-bus-format.h> 9013413cdSMasahiro Yamada #include <linux/mfd/syscon.h> 10013413cdSMasahiro Yamada #include <linux/module.h> 11013413cdSMasahiro Yamada #include <linux/of.h> 12013413cdSMasahiro Yamada #include <linux/of_device.h> 13013413cdSMasahiro Yamada #include <linux/of_graph.h> 14013413cdSMasahiro Yamada #include <linux/phy/phy.h> 15*722d4f06SRob Herring #include <linux/platform_device.h> 16013413cdSMasahiro Yamada #include <linux/pm_runtime.h> 17013413cdSMasahiro Yamada #include <linux/regmap.h> 18013413cdSMasahiro Yamada 19013413cdSMasahiro Yamada #include <drm/drm_atomic_state_helper.h> 20013413cdSMasahiro Yamada #include <drm/drm_bridge.h> 21013413cdSMasahiro Yamada #include <drm/drm_connector.h> 22013413cdSMasahiro Yamada #include <drm/drm_fourcc.h> 23013413cdSMasahiro Yamada #include <drm/drm_of.h> 24013413cdSMasahiro Yamada #include <drm/drm_print.h> 25013413cdSMasahiro Yamada 26013413cdSMasahiro Yamada #include "imx-ldb-helper.h" 27013413cdSMasahiro Yamada 28013413cdSMasahiro Yamada #define LDB_CH_SEL BIT(28) 29013413cdSMasahiro Yamada 30013413cdSMasahiro Yamada #define SS_CTRL 0x20 31013413cdSMasahiro Yamada #define CH_HSYNC_M(id) BIT(0 + ((id) * 2)) 32013413cdSMasahiro Yamada #define CH_VSYNC_M(id) BIT(1 + ((id) * 2)) 33013413cdSMasahiro Yamada #define CH_PHSYNC(id) BIT(0 + ((id) * 2)) 34013413cdSMasahiro Yamada #define CH_PVSYNC(id) BIT(1 + ((id) * 2)) 35013413cdSMasahiro Yamada 36013413cdSMasahiro Yamada #define DRIVER_NAME "imx8qxp-ldb" 37013413cdSMasahiro Yamada 38013413cdSMasahiro Yamada struct imx8qxp_ldb_channel { 39013413cdSMasahiro Yamada struct ldb_channel base; 40013413cdSMasahiro Yamada struct phy *phy; 41013413cdSMasahiro Yamada unsigned int di_id; 42013413cdSMasahiro Yamada }; 43013413cdSMasahiro Yamada 44013413cdSMasahiro Yamada struct imx8qxp_ldb { 45013413cdSMasahiro Yamada struct ldb base; 46013413cdSMasahiro Yamada struct device *dev; 47013413cdSMasahiro Yamada struct imx8qxp_ldb_channel channel[MAX_LDB_CHAN_NUM]; 48013413cdSMasahiro Yamada struct clk *clk_pixel; 49013413cdSMasahiro Yamada struct clk *clk_bypass; 50013413cdSMasahiro Yamada struct drm_bridge *companion; 51013413cdSMasahiro Yamada int active_chno; 52013413cdSMasahiro Yamada }; 53013413cdSMasahiro Yamada 54013413cdSMasahiro Yamada static inline struct imx8qxp_ldb_channel * 55013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(struct ldb_channel *base) 56013413cdSMasahiro Yamada { 57013413cdSMasahiro Yamada return container_of(base, struct imx8qxp_ldb_channel, base); 58013413cdSMasahiro Yamada } 59013413cdSMasahiro Yamada 60013413cdSMasahiro Yamada static inline struct imx8qxp_ldb *base_to_imx8qxp_ldb(struct ldb *base) 61013413cdSMasahiro Yamada { 62013413cdSMasahiro Yamada return container_of(base, struct imx8qxp_ldb, base); 63013413cdSMasahiro Yamada } 64013413cdSMasahiro Yamada 65013413cdSMasahiro Yamada static void imx8qxp_ldb_set_phy_cfg(struct imx8qxp_ldb *imx8qxp_ldb, 66013413cdSMasahiro Yamada unsigned long di_clk, bool is_split, 67013413cdSMasahiro Yamada struct phy_configure_opts_lvds *phy_cfg) 68013413cdSMasahiro Yamada { 69013413cdSMasahiro Yamada phy_cfg->bits_per_lane_and_dclk_cycle = 7; 70013413cdSMasahiro Yamada phy_cfg->lanes = 4; 71013413cdSMasahiro Yamada 72013413cdSMasahiro Yamada if (is_split) { 73013413cdSMasahiro Yamada phy_cfg->differential_clk_rate = di_clk / 2; 74013413cdSMasahiro Yamada phy_cfg->is_slave = !imx8qxp_ldb->companion; 75013413cdSMasahiro Yamada } else { 76013413cdSMasahiro Yamada phy_cfg->differential_clk_rate = di_clk; 77013413cdSMasahiro Yamada phy_cfg->is_slave = false; 78013413cdSMasahiro Yamada } 79013413cdSMasahiro Yamada } 80013413cdSMasahiro Yamada 81013413cdSMasahiro Yamada static int 82013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_check(struct drm_bridge *bridge, 83013413cdSMasahiro Yamada struct drm_bridge_state *bridge_state, 84013413cdSMasahiro Yamada struct drm_crtc_state *crtc_state, 85013413cdSMasahiro Yamada struct drm_connector_state *conn_state) 86013413cdSMasahiro Yamada { 87013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private; 88013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb; 89013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch = 90013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(ldb_ch); 91013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb); 92013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion; 93013413cdSMasahiro Yamada struct drm_display_mode *adj = &crtc_state->adjusted_mode; 94013413cdSMasahiro Yamada unsigned long di_clk = adj->clock * 1000; 95013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch); 96013413cdSMasahiro Yamada union phy_configure_opts opts = { }; 97013413cdSMasahiro Yamada struct phy_configure_opts_lvds *phy_cfg = &opts.lvds; 98013413cdSMasahiro Yamada int ret; 99013413cdSMasahiro Yamada 100013413cdSMasahiro Yamada ret = ldb_bridge_atomic_check_helper(bridge, bridge_state, 101013413cdSMasahiro Yamada crtc_state, conn_state); 102013413cdSMasahiro Yamada if (ret) 103013413cdSMasahiro Yamada return ret; 104013413cdSMasahiro Yamada 105013413cdSMasahiro Yamada imx8qxp_ldb_set_phy_cfg(imx8qxp_ldb, di_clk, is_split, phy_cfg); 106013413cdSMasahiro Yamada ret = phy_validate(imx8qxp_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts); 107013413cdSMasahiro Yamada if (ret < 0) { 108013413cdSMasahiro Yamada DRM_DEV_DEBUG_DRIVER(imx8qxp_ldb->dev, 109013413cdSMasahiro Yamada "failed to validate PHY: %d\n", ret); 110013413cdSMasahiro Yamada return ret; 111013413cdSMasahiro Yamada } 112013413cdSMasahiro Yamada 113013413cdSMasahiro Yamada if (is_split && companion) { 114013413cdSMasahiro Yamada ret = companion->funcs->atomic_check(companion, 115013413cdSMasahiro Yamada bridge_state, crtc_state, conn_state); 116013413cdSMasahiro Yamada if (ret) 117013413cdSMasahiro Yamada return ret; 118013413cdSMasahiro Yamada } 119013413cdSMasahiro Yamada 120013413cdSMasahiro Yamada return ret; 121013413cdSMasahiro Yamada } 122013413cdSMasahiro Yamada 123013413cdSMasahiro Yamada static void 124013413cdSMasahiro Yamada imx8qxp_ldb_bridge_mode_set(struct drm_bridge *bridge, 125013413cdSMasahiro Yamada const struct drm_display_mode *mode, 126013413cdSMasahiro Yamada const struct drm_display_mode *adjusted_mode) 127013413cdSMasahiro Yamada { 128013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private; 129013413cdSMasahiro Yamada struct ldb_channel *companion_ldb_ch; 130013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb; 131013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch = 132013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(ldb_ch); 133013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb); 134013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion; 135013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev; 136013413cdSMasahiro Yamada unsigned long di_clk = adjusted_mode->clock * 1000; 137013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch); 138013413cdSMasahiro Yamada union phy_configure_opts opts = { }; 139013413cdSMasahiro Yamada struct phy_configure_opts_lvds *phy_cfg = &opts.lvds; 140013413cdSMasahiro Yamada u32 chno = ldb_ch->chno; 141013413cdSMasahiro Yamada int ret; 142013413cdSMasahiro Yamada 143013413cdSMasahiro Yamada ret = pm_runtime_get_sync(dev); 144013413cdSMasahiro Yamada if (ret < 0) 145013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to get runtime PM sync: %d\n", ret); 146013413cdSMasahiro Yamada 147013413cdSMasahiro Yamada ret = phy_init(imx8qxp_ldb_ch->phy); 148013413cdSMasahiro Yamada if (ret < 0) 149013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to initialize PHY: %d\n", ret); 150013413cdSMasahiro Yamada 151013413cdSMasahiro Yamada ret = phy_set_mode(imx8qxp_ldb_ch->phy, PHY_MODE_LVDS); 152013413cdSMasahiro Yamada if (ret < 0) 153013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to set PHY mode: %d\n", ret); 154013413cdSMasahiro Yamada 155013413cdSMasahiro Yamada if (is_split && companion) { 156013413cdSMasahiro Yamada companion_ldb_ch = bridge_to_ldb_ch(companion); 157013413cdSMasahiro Yamada 158013413cdSMasahiro Yamada companion_ldb_ch->in_bus_format = ldb_ch->in_bus_format; 159013413cdSMasahiro Yamada companion_ldb_ch->out_bus_format = ldb_ch->out_bus_format; 160013413cdSMasahiro Yamada } 161013413cdSMasahiro Yamada 162013413cdSMasahiro Yamada clk_set_rate(imx8qxp_ldb->clk_bypass, di_clk); 163013413cdSMasahiro Yamada clk_set_rate(imx8qxp_ldb->clk_pixel, di_clk); 164013413cdSMasahiro Yamada 165013413cdSMasahiro Yamada imx8qxp_ldb_set_phy_cfg(imx8qxp_ldb, di_clk, is_split, phy_cfg); 166013413cdSMasahiro Yamada ret = phy_configure(imx8qxp_ldb_ch->phy, &opts); 167013413cdSMasahiro Yamada if (ret < 0) 168013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to configure PHY: %d\n", ret); 169013413cdSMasahiro Yamada 170013413cdSMasahiro Yamada if (chno == 0) 171013413cdSMasahiro Yamada ldb->ldb_ctrl &= ~LDB_CH_SEL; 172013413cdSMasahiro Yamada else 173013413cdSMasahiro Yamada ldb->ldb_ctrl |= LDB_CH_SEL; 174013413cdSMasahiro Yamada 175013413cdSMasahiro Yamada /* input VSYNC signal from pixel link is active low */ 176013413cdSMasahiro Yamada if (imx8qxp_ldb_ch->di_id == 0) 177013413cdSMasahiro Yamada ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW; 178013413cdSMasahiro Yamada else 179013413cdSMasahiro Yamada ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW; 180013413cdSMasahiro Yamada 181013413cdSMasahiro Yamada /* 182013413cdSMasahiro Yamada * For split mode, settle input VSYNC signal polarity and 183013413cdSMasahiro Yamada * channel selection down early. 184013413cdSMasahiro Yamada */ 185013413cdSMasahiro Yamada if (is_split) 186013413cdSMasahiro Yamada regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl); 187013413cdSMasahiro Yamada 188013413cdSMasahiro Yamada ldb_bridge_mode_set_helper(bridge, mode, adjusted_mode); 189013413cdSMasahiro Yamada 190013413cdSMasahiro Yamada if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) 191013413cdSMasahiro Yamada regmap_update_bits(ldb->regmap, SS_CTRL, CH_VSYNC_M(chno), 0); 192013413cdSMasahiro Yamada else if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 193013413cdSMasahiro Yamada regmap_update_bits(ldb->regmap, SS_CTRL, 194013413cdSMasahiro Yamada CH_VSYNC_M(chno), CH_PVSYNC(chno)); 195013413cdSMasahiro Yamada 196013413cdSMasahiro Yamada if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) 197013413cdSMasahiro Yamada regmap_update_bits(ldb->regmap, SS_CTRL, CH_HSYNC_M(chno), 0); 198013413cdSMasahiro Yamada else if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 199013413cdSMasahiro Yamada regmap_update_bits(ldb->regmap, SS_CTRL, 200013413cdSMasahiro Yamada CH_HSYNC_M(chno), CH_PHSYNC(chno)); 201013413cdSMasahiro Yamada 202013413cdSMasahiro Yamada if (is_split && companion) 203013413cdSMasahiro Yamada companion->funcs->mode_set(companion, mode, adjusted_mode); 204013413cdSMasahiro Yamada } 205013413cdSMasahiro Yamada 206013413cdSMasahiro Yamada static void 207013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_pre_enable(struct drm_bridge *bridge, 208013413cdSMasahiro Yamada struct drm_bridge_state *old_bridge_state) 209013413cdSMasahiro Yamada { 210013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private; 211013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb; 212013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb); 213013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion; 214013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch); 215013413cdSMasahiro Yamada 216013413cdSMasahiro Yamada clk_prepare_enable(imx8qxp_ldb->clk_pixel); 217013413cdSMasahiro Yamada clk_prepare_enable(imx8qxp_ldb->clk_bypass); 218013413cdSMasahiro Yamada 219013413cdSMasahiro Yamada if (is_split && companion) 220013413cdSMasahiro Yamada companion->funcs->atomic_pre_enable(companion, old_bridge_state); 221013413cdSMasahiro Yamada } 222013413cdSMasahiro Yamada 223013413cdSMasahiro Yamada static void 224013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_enable(struct drm_bridge *bridge, 225013413cdSMasahiro Yamada struct drm_bridge_state *old_bridge_state) 226013413cdSMasahiro Yamada { 227013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private; 228013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb; 229013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch = 230013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(ldb_ch); 231013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb); 232013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion; 233013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev; 234013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch); 235013413cdSMasahiro Yamada int ret; 236013413cdSMasahiro Yamada 237013413cdSMasahiro Yamada if (ldb_ch->chno == 0 || is_split) { 238013413cdSMasahiro Yamada ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; 239013413cdSMasahiro Yamada ldb->ldb_ctrl |= imx8qxp_ldb_ch->di_id == 0 ? 240013413cdSMasahiro Yamada LDB_CH0_MODE_EN_TO_DI0 : LDB_CH0_MODE_EN_TO_DI1; 241013413cdSMasahiro Yamada } 242013413cdSMasahiro Yamada if (ldb_ch->chno == 1 || is_split) { 243013413cdSMasahiro Yamada ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK; 244013413cdSMasahiro Yamada ldb->ldb_ctrl |= imx8qxp_ldb_ch->di_id == 0 ? 245013413cdSMasahiro Yamada LDB_CH1_MODE_EN_TO_DI0 : LDB_CH1_MODE_EN_TO_DI1; 246013413cdSMasahiro Yamada } 247013413cdSMasahiro Yamada 248013413cdSMasahiro Yamada ldb_bridge_enable_helper(bridge); 249013413cdSMasahiro Yamada 250013413cdSMasahiro Yamada ret = phy_power_on(imx8qxp_ldb_ch->phy); 251013413cdSMasahiro Yamada if (ret) 252013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to power on PHY: %d\n", ret); 253013413cdSMasahiro Yamada 254013413cdSMasahiro Yamada if (is_split && companion) 255013413cdSMasahiro Yamada companion->funcs->atomic_enable(companion, old_bridge_state); 256013413cdSMasahiro Yamada } 257013413cdSMasahiro Yamada 258013413cdSMasahiro Yamada static void 259013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_disable(struct drm_bridge *bridge, 260013413cdSMasahiro Yamada struct drm_bridge_state *old_bridge_state) 261013413cdSMasahiro Yamada { 262013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private; 263013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb; 264013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch = 265013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(ldb_ch); 266013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb); 267013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion; 268013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev; 269013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch); 270013413cdSMasahiro Yamada int ret; 271013413cdSMasahiro Yamada 272013413cdSMasahiro Yamada ret = phy_power_off(imx8qxp_ldb_ch->phy); 273013413cdSMasahiro Yamada if (ret) 274013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to power off PHY: %d\n", ret); 275013413cdSMasahiro Yamada 276013413cdSMasahiro Yamada ret = phy_exit(imx8qxp_ldb_ch->phy); 277013413cdSMasahiro Yamada if (ret < 0) 278013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to teardown PHY: %d\n", ret); 279013413cdSMasahiro Yamada 280013413cdSMasahiro Yamada ldb_bridge_disable_helper(bridge); 281013413cdSMasahiro Yamada 282013413cdSMasahiro Yamada clk_disable_unprepare(imx8qxp_ldb->clk_bypass); 283013413cdSMasahiro Yamada clk_disable_unprepare(imx8qxp_ldb->clk_pixel); 284013413cdSMasahiro Yamada 285013413cdSMasahiro Yamada if (is_split && companion) 286013413cdSMasahiro Yamada companion->funcs->atomic_disable(companion, old_bridge_state); 287013413cdSMasahiro Yamada 288013413cdSMasahiro Yamada ret = pm_runtime_put(dev); 289013413cdSMasahiro Yamada if (ret < 0) 290013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to put runtime PM: %d\n", ret); 291013413cdSMasahiro Yamada } 292013413cdSMasahiro Yamada 293013413cdSMasahiro Yamada static const u32 imx8qxp_ldb_bus_output_fmts[] = { 294013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 295013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 296013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 297013413cdSMasahiro Yamada MEDIA_BUS_FMT_FIXED, 298013413cdSMasahiro Yamada }; 299013413cdSMasahiro Yamada 300013413cdSMasahiro Yamada static bool imx8qxp_ldb_bus_output_fmt_supported(u32 fmt) 301013413cdSMasahiro Yamada { 302013413cdSMasahiro Yamada int i; 303013413cdSMasahiro Yamada 304013413cdSMasahiro Yamada for (i = 0; i < ARRAY_SIZE(imx8qxp_ldb_bus_output_fmts); i++) { 305013413cdSMasahiro Yamada if (imx8qxp_ldb_bus_output_fmts[i] == fmt) 306013413cdSMasahiro Yamada return true; 307013413cdSMasahiro Yamada } 308013413cdSMasahiro Yamada 309013413cdSMasahiro Yamada return false; 310013413cdSMasahiro Yamada } 311013413cdSMasahiro Yamada 312013413cdSMasahiro Yamada static u32 * 313013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, 314013413cdSMasahiro Yamada struct drm_bridge_state *bridge_state, 315013413cdSMasahiro Yamada struct drm_crtc_state *crtc_state, 316013413cdSMasahiro Yamada struct drm_connector_state *conn_state, 317013413cdSMasahiro Yamada u32 output_fmt, 318013413cdSMasahiro Yamada unsigned int *num_input_fmts) 319013413cdSMasahiro Yamada { 320013413cdSMasahiro Yamada struct drm_display_info *di; 321013413cdSMasahiro Yamada const struct drm_format_info *finfo; 322013413cdSMasahiro Yamada u32 *input_fmts; 323013413cdSMasahiro Yamada 324013413cdSMasahiro Yamada if (!imx8qxp_ldb_bus_output_fmt_supported(output_fmt)) 325013413cdSMasahiro Yamada return NULL; 326013413cdSMasahiro Yamada 327013413cdSMasahiro Yamada *num_input_fmts = 1; 328013413cdSMasahiro Yamada 329013413cdSMasahiro Yamada input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL); 330013413cdSMasahiro Yamada if (!input_fmts) 331013413cdSMasahiro Yamada return NULL; 332013413cdSMasahiro Yamada 333013413cdSMasahiro Yamada switch (output_fmt) { 334013413cdSMasahiro Yamada case MEDIA_BUS_FMT_FIXED: 335013413cdSMasahiro Yamada di = &conn_state->connector->display_info; 336013413cdSMasahiro Yamada 337013413cdSMasahiro Yamada /* 338013413cdSMasahiro Yamada * Look at the first bus format to determine input format. 339013413cdSMasahiro Yamada * Default to MEDIA_BUS_FMT_RGB888_1X24, if no match. 340013413cdSMasahiro Yamada */ 341013413cdSMasahiro Yamada if (di->num_bus_formats) { 342013413cdSMasahiro Yamada finfo = drm_format_info(di->bus_formats[0]); 343013413cdSMasahiro Yamada 344013413cdSMasahiro Yamada input_fmts[0] = finfo->depth == 18 ? 345013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB666_1X24_CPADHI : 346013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB888_1X24; 347013413cdSMasahiro Yamada } else { 348013413cdSMasahiro Yamada input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; 349013413cdSMasahiro Yamada } 350013413cdSMasahiro Yamada break; 351013413cdSMasahiro Yamada case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: 352013413cdSMasahiro Yamada input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; 353013413cdSMasahiro Yamada break; 354013413cdSMasahiro Yamada case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: 355013413cdSMasahiro Yamada case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: 356013413cdSMasahiro Yamada input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; 357013413cdSMasahiro Yamada break; 358013413cdSMasahiro Yamada default: 359013413cdSMasahiro Yamada kfree(input_fmts); 360013413cdSMasahiro Yamada input_fmts = NULL; 361013413cdSMasahiro Yamada break; 362013413cdSMasahiro Yamada } 363013413cdSMasahiro Yamada 364013413cdSMasahiro Yamada return input_fmts; 365013413cdSMasahiro Yamada } 366013413cdSMasahiro Yamada 367013413cdSMasahiro Yamada static u32 * 368013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, 369013413cdSMasahiro Yamada struct drm_bridge_state *bridge_state, 370013413cdSMasahiro Yamada struct drm_crtc_state *crtc_state, 371013413cdSMasahiro Yamada struct drm_connector_state *conn_state, 372013413cdSMasahiro Yamada unsigned int *num_output_fmts) 373013413cdSMasahiro Yamada { 374013413cdSMasahiro Yamada *num_output_fmts = ARRAY_SIZE(imx8qxp_ldb_bus_output_fmts); 375013413cdSMasahiro Yamada return kmemdup(imx8qxp_ldb_bus_output_fmts, 376013413cdSMasahiro Yamada sizeof(imx8qxp_ldb_bus_output_fmts), GFP_KERNEL); 377013413cdSMasahiro Yamada } 378013413cdSMasahiro Yamada 379013413cdSMasahiro Yamada static enum drm_mode_status 380013413cdSMasahiro Yamada imx8qxp_ldb_bridge_mode_valid(struct drm_bridge *bridge, 381013413cdSMasahiro Yamada const struct drm_display_info *info, 382013413cdSMasahiro Yamada const struct drm_display_mode *mode) 383013413cdSMasahiro Yamada { 384013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private; 385013413cdSMasahiro Yamada bool is_single = ldb_channel_is_single_link(ldb_ch); 386013413cdSMasahiro Yamada 387013413cdSMasahiro Yamada if (mode->clock > 170000) 388013413cdSMasahiro Yamada return MODE_CLOCK_HIGH; 389013413cdSMasahiro Yamada 390013413cdSMasahiro Yamada if (mode->clock > 150000 && is_single) 391013413cdSMasahiro Yamada return MODE_CLOCK_HIGH; 392013413cdSMasahiro Yamada 393013413cdSMasahiro Yamada return MODE_OK; 394013413cdSMasahiro Yamada } 395013413cdSMasahiro Yamada 396013413cdSMasahiro Yamada static const struct drm_bridge_funcs imx8qxp_ldb_bridge_funcs = { 397013413cdSMasahiro Yamada .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 398013413cdSMasahiro Yamada .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 399013413cdSMasahiro Yamada .atomic_reset = drm_atomic_helper_bridge_reset, 400013413cdSMasahiro Yamada .mode_valid = imx8qxp_ldb_bridge_mode_valid, 401013413cdSMasahiro Yamada .attach = ldb_bridge_attach_helper, 402013413cdSMasahiro Yamada .atomic_check = imx8qxp_ldb_bridge_atomic_check, 403013413cdSMasahiro Yamada .mode_set = imx8qxp_ldb_bridge_mode_set, 404013413cdSMasahiro Yamada .atomic_pre_enable = imx8qxp_ldb_bridge_atomic_pre_enable, 405013413cdSMasahiro Yamada .atomic_enable = imx8qxp_ldb_bridge_atomic_enable, 406013413cdSMasahiro Yamada .atomic_disable = imx8qxp_ldb_bridge_atomic_disable, 407013413cdSMasahiro Yamada .atomic_get_input_bus_fmts = 408013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_get_input_bus_fmts, 409013413cdSMasahiro Yamada .atomic_get_output_bus_fmts = 410013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_get_output_bus_fmts, 411013413cdSMasahiro Yamada }; 412013413cdSMasahiro Yamada 413013413cdSMasahiro Yamada static int imx8qxp_ldb_set_di_id(struct imx8qxp_ldb *imx8qxp_ldb) 414013413cdSMasahiro Yamada { 415013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch = 416013413cdSMasahiro Yamada &imx8qxp_ldb->channel[imx8qxp_ldb->active_chno]; 417013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base; 418013413cdSMasahiro Yamada struct device_node *ep, *remote; 419013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev; 420013413cdSMasahiro Yamada struct of_endpoint endpoint; 421013413cdSMasahiro Yamada int ret; 422013413cdSMasahiro Yamada 423013413cdSMasahiro Yamada ep = of_graph_get_endpoint_by_regs(ldb_ch->np, 0, -1); 424013413cdSMasahiro Yamada if (!ep) { 425013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to get port0 endpoint\n"); 426013413cdSMasahiro Yamada return -EINVAL; 427013413cdSMasahiro Yamada } 428013413cdSMasahiro Yamada 429013413cdSMasahiro Yamada remote = of_graph_get_remote_endpoint(ep); 430013413cdSMasahiro Yamada of_node_put(ep); 431013413cdSMasahiro Yamada if (!remote) { 432013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to get port0 remote endpoint\n"); 433013413cdSMasahiro Yamada return -EINVAL; 434013413cdSMasahiro Yamada } 435013413cdSMasahiro Yamada 436013413cdSMasahiro Yamada ret = of_graph_parse_endpoint(remote, &endpoint); 437013413cdSMasahiro Yamada of_node_put(remote); 438013413cdSMasahiro Yamada if (ret) { 439013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to parse port0 remote endpoint: %d\n", 440013413cdSMasahiro Yamada ret); 441013413cdSMasahiro Yamada return ret; 442013413cdSMasahiro Yamada } 443013413cdSMasahiro Yamada 444013413cdSMasahiro Yamada imx8qxp_ldb_ch->di_id = endpoint.id; 445013413cdSMasahiro Yamada 446013413cdSMasahiro Yamada return 0; 447013413cdSMasahiro Yamada } 448013413cdSMasahiro Yamada 449013413cdSMasahiro Yamada static int 450013413cdSMasahiro Yamada imx8qxp_ldb_check_chno_and_dual_link(struct ldb_channel *ldb_ch, int link) 451013413cdSMasahiro Yamada { 452013413cdSMasahiro Yamada if ((link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS && ldb_ch->chno != 0) || 453013413cdSMasahiro Yamada (link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS && ldb_ch->chno != 1)) 454013413cdSMasahiro Yamada return -EINVAL; 455013413cdSMasahiro Yamada 456013413cdSMasahiro Yamada return 0; 457013413cdSMasahiro Yamada } 458013413cdSMasahiro Yamada 459013413cdSMasahiro Yamada static int imx8qxp_ldb_parse_dt_companion(struct imx8qxp_ldb *imx8qxp_ldb) 460013413cdSMasahiro Yamada { 461013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch = 462013413cdSMasahiro Yamada &imx8qxp_ldb->channel[imx8qxp_ldb->active_chno]; 463013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base; 464013413cdSMasahiro Yamada struct ldb_channel *companion_ldb_ch; 465013413cdSMasahiro Yamada struct device_node *companion; 466013413cdSMasahiro Yamada struct device_node *child; 467013413cdSMasahiro Yamada struct device_node *companion_port = NULL; 468013413cdSMasahiro Yamada struct device_node *port1, *port2; 469013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev; 470013413cdSMasahiro Yamada const struct of_device_id *match; 471013413cdSMasahiro Yamada u32 i; 472013413cdSMasahiro Yamada int dual_link; 473013413cdSMasahiro Yamada int ret; 474013413cdSMasahiro Yamada 475013413cdSMasahiro Yamada /* Locate the companion LDB for dual-link operation, if any. */ 476013413cdSMasahiro Yamada companion = of_parse_phandle(dev->of_node, "fsl,companion-ldb", 0); 477013413cdSMasahiro Yamada if (!companion) 478013413cdSMasahiro Yamada return 0; 479013413cdSMasahiro Yamada 480013413cdSMasahiro Yamada if (!of_device_is_available(companion)) { 481013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "companion LDB is not available\n"); 482013413cdSMasahiro Yamada ret = -ENODEV; 483013413cdSMasahiro Yamada goto out; 484013413cdSMasahiro Yamada } 485013413cdSMasahiro Yamada 486013413cdSMasahiro Yamada /* 487013413cdSMasahiro Yamada * Sanity check: the companion bridge must have the same compatible 488013413cdSMasahiro Yamada * string. 489013413cdSMasahiro Yamada */ 490013413cdSMasahiro Yamada match = of_match_device(dev->driver->of_match_table, dev); 491013413cdSMasahiro Yamada if (!of_device_is_compatible(companion, match->compatible)) { 492013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "companion LDB is incompatible\n"); 493013413cdSMasahiro Yamada ret = -ENXIO; 494013413cdSMasahiro Yamada goto out; 495013413cdSMasahiro Yamada } 496013413cdSMasahiro Yamada 497013413cdSMasahiro Yamada for_each_available_child_of_node(companion, child) { 498013413cdSMasahiro Yamada ret = of_property_read_u32(child, "reg", &i); 499013413cdSMasahiro Yamada if (ret || i > MAX_LDB_CHAN_NUM - 1) { 500013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, 501013413cdSMasahiro Yamada "invalid channel node address: %u\n", i); 502013413cdSMasahiro Yamada ret = -EINVAL; 503013413cdSMasahiro Yamada of_node_put(child); 504013413cdSMasahiro Yamada goto out; 505013413cdSMasahiro Yamada } 506013413cdSMasahiro Yamada 507013413cdSMasahiro Yamada /* 508013413cdSMasahiro Yamada * Channel numbers have to be different, because channel0 509013413cdSMasahiro Yamada * transmits odd pixels and channel1 transmits even pixels. 510013413cdSMasahiro Yamada */ 511013413cdSMasahiro Yamada if (i == (ldb_ch->chno ^ 0x1)) { 512013413cdSMasahiro Yamada companion_port = child; 513013413cdSMasahiro Yamada break; 514013413cdSMasahiro Yamada } 515013413cdSMasahiro Yamada } 516013413cdSMasahiro Yamada 517013413cdSMasahiro Yamada if (!companion_port) { 518013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, 519013413cdSMasahiro Yamada "failed to find companion LDB channel port\n"); 520013413cdSMasahiro Yamada ret = -EINVAL; 521013413cdSMasahiro Yamada goto out; 522013413cdSMasahiro Yamada } 523013413cdSMasahiro Yamada 524013413cdSMasahiro Yamada /* 525013413cdSMasahiro Yamada * We need to work out if the sink is expecting us to function in 526013413cdSMasahiro Yamada * dual-link mode. We do this by looking at the DT port nodes we are 527013413cdSMasahiro Yamada * connected to. If they are marked as expecting odd pixels and 528013413cdSMasahiro Yamada * even pixels than we need to enable LDB split mode. 529013413cdSMasahiro Yamada */ 530013413cdSMasahiro Yamada port1 = of_graph_get_port_by_id(ldb_ch->np, 1); 531013413cdSMasahiro Yamada port2 = of_graph_get_port_by_id(companion_port, 1); 532013413cdSMasahiro Yamada dual_link = drm_of_lvds_get_dual_link_pixel_order(port1, port2); 533013413cdSMasahiro Yamada of_node_put(port1); 534013413cdSMasahiro Yamada of_node_put(port2); 535013413cdSMasahiro Yamada 536013413cdSMasahiro Yamada switch (dual_link) { 537013413cdSMasahiro Yamada case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: 538013413cdSMasahiro Yamada ldb_ch->link_type = LDB_CH_DUAL_LINK_ODD_EVEN_PIXELS; 539013413cdSMasahiro Yamada break; 540013413cdSMasahiro Yamada case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: 541013413cdSMasahiro Yamada ldb_ch->link_type = LDB_CH_DUAL_LINK_EVEN_ODD_PIXELS; 542013413cdSMasahiro Yamada break; 543013413cdSMasahiro Yamada default: 544013413cdSMasahiro Yamada ret = dual_link; 545013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, 546013413cdSMasahiro Yamada "failed to get dual link pixel order: %d\n", ret); 547013413cdSMasahiro Yamada goto out; 548013413cdSMasahiro Yamada } 549013413cdSMasahiro Yamada 550013413cdSMasahiro Yamada ret = imx8qxp_ldb_check_chno_and_dual_link(ldb_ch, dual_link); 551013413cdSMasahiro Yamada if (ret < 0) { 552013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, 553013413cdSMasahiro Yamada "unmatched channel number(%u) vs dual link(%d)\n", 554013413cdSMasahiro Yamada ldb_ch->chno, dual_link); 555013413cdSMasahiro Yamada goto out; 556013413cdSMasahiro Yamada } 557013413cdSMasahiro Yamada 558013413cdSMasahiro Yamada imx8qxp_ldb->companion = of_drm_find_bridge(companion_port); 559013413cdSMasahiro Yamada if (!imx8qxp_ldb->companion) { 560013413cdSMasahiro Yamada ret = -EPROBE_DEFER; 561013413cdSMasahiro Yamada DRM_DEV_DEBUG_DRIVER(dev, 562013413cdSMasahiro Yamada "failed to find bridge for companion bridge: %d\n", 563013413cdSMasahiro Yamada ret); 564013413cdSMasahiro Yamada goto out; 565013413cdSMasahiro Yamada } 566013413cdSMasahiro Yamada 567013413cdSMasahiro Yamada DRM_DEV_DEBUG_DRIVER(dev, 568013413cdSMasahiro Yamada "dual-link configuration detected (companion bridge %pOF)\n", 569013413cdSMasahiro Yamada companion); 570013413cdSMasahiro Yamada 571013413cdSMasahiro Yamada companion_ldb_ch = bridge_to_ldb_ch(imx8qxp_ldb->companion); 572013413cdSMasahiro Yamada companion_ldb_ch->link_type = ldb_ch->link_type; 573013413cdSMasahiro Yamada out: 574013413cdSMasahiro Yamada of_node_put(companion_port); 575013413cdSMasahiro Yamada of_node_put(companion); 576013413cdSMasahiro Yamada return ret; 577013413cdSMasahiro Yamada } 578013413cdSMasahiro Yamada 579013413cdSMasahiro Yamada static int imx8qxp_ldb_probe(struct platform_device *pdev) 580013413cdSMasahiro Yamada { 581013413cdSMasahiro Yamada struct device *dev = &pdev->dev; 582013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb; 583013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch; 584013413cdSMasahiro Yamada struct ldb *ldb; 585013413cdSMasahiro Yamada struct ldb_channel *ldb_ch; 586013413cdSMasahiro Yamada int ret, i; 587013413cdSMasahiro Yamada 588013413cdSMasahiro Yamada imx8qxp_ldb = devm_kzalloc(dev, sizeof(*imx8qxp_ldb), GFP_KERNEL); 589013413cdSMasahiro Yamada if (!imx8qxp_ldb) 590013413cdSMasahiro Yamada return -ENOMEM; 591013413cdSMasahiro Yamada 592013413cdSMasahiro Yamada imx8qxp_ldb->clk_pixel = devm_clk_get(dev, "pixel"); 593013413cdSMasahiro Yamada if (IS_ERR(imx8qxp_ldb->clk_pixel)) { 594013413cdSMasahiro Yamada ret = PTR_ERR(imx8qxp_ldb->clk_pixel); 595013413cdSMasahiro Yamada if (ret != -EPROBE_DEFER) 596013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, 597013413cdSMasahiro Yamada "failed to get pixel clock: %d\n", ret); 598013413cdSMasahiro Yamada return ret; 599013413cdSMasahiro Yamada } 600013413cdSMasahiro Yamada 601013413cdSMasahiro Yamada imx8qxp_ldb->clk_bypass = devm_clk_get(dev, "bypass"); 602013413cdSMasahiro Yamada if (IS_ERR(imx8qxp_ldb->clk_bypass)) { 603013413cdSMasahiro Yamada ret = PTR_ERR(imx8qxp_ldb->clk_bypass); 604013413cdSMasahiro Yamada if (ret != -EPROBE_DEFER) 605013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, 606013413cdSMasahiro Yamada "failed to get bypass clock: %d\n", ret); 607013413cdSMasahiro Yamada return ret; 608013413cdSMasahiro Yamada } 609013413cdSMasahiro Yamada 610013413cdSMasahiro Yamada imx8qxp_ldb->dev = dev; 611013413cdSMasahiro Yamada 612013413cdSMasahiro Yamada ldb = &imx8qxp_ldb->base; 613013413cdSMasahiro Yamada ldb->dev = dev; 614013413cdSMasahiro Yamada ldb->ctrl_reg = 0xe0; 615013413cdSMasahiro Yamada 616013413cdSMasahiro Yamada for (i = 0; i < MAX_LDB_CHAN_NUM; i++) 617013413cdSMasahiro Yamada ldb->channel[i] = &imx8qxp_ldb->channel[i].base; 618013413cdSMasahiro Yamada 619013413cdSMasahiro Yamada ret = ldb_init_helper(ldb); 620013413cdSMasahiro Yamada if (ret) 621013413cdSMasahiro Yamada return ret; 622013413cdSMasahiro Yamada 623013413cdSMasahiro Yamada if (ldb->available_ch_cnt == 0) { 624013413cdSMasahiro Yamada DRM_DEV_DEBUG_DRIVER(dev, "no available channel\n"); 625013413cdSMasahiro Yamada return 0; 626013413cdSMasahiro Yamada } else if (ldb->available_ch_cnt > 1) { 627013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "invalid available channel number(%u)\n", 628013413cdSMasahiro Yamada ldb->available_ch_cnt); 629013413cdSMasahiro Yamada return -EINVAL; 630013413cdSMasahiro Yamada } 631013413cdSMasahiro Yamada 632013413cdSMasahiro Yamada for (i = 0; i < MAX_LDB_CHAN_NUM; i++) { 633013413cdSMasahiro Yamada imx8qxp_ldb_ch = &imx8qxp_ldb->channel[i]; 634013413cdSMasahiro Yamada ldb_ch = &imx8qxp_ldb_ch->base; 635013413cdSMasahiro Yamada 636013413cdSMasahiro Yamada if (ldb_ch->is_available) { 637013413cdSMasahiro Yamada imx8qxp_ldb->active_chno = ldb_ch->chno; 638013413cdSMasahiro Yamada break; 639013413cdSMasahiro Yamada } 640013413cdSMasahiro Yamada } 641013413cdSMasahiro Yamada 642013413cdSMasahiro Yamada imx8qxp_ldb_ch->phy = devm_of_phy_get(dev, ldb_ch->np, "lvds_phy"); 643013413cdSMasahiro Yamada if (IS_ERR(imx8qxp_ldb_ch->phy)) { 644013413cdSMasahiro Yamada ret = PTR_ERR(imx8qxp_ldb_ch->phy); 645013413cdSMasahiro Yamada if (ret != -EPROBE_DEFER) 646013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to get channel%d PHY: %d\n", 647013413cdSMasahiro Yamada imx8qxp_ldb->active_chno, ret); 648013413cdSMasahiro Yamada return ret; 649013413cdSMasahiro Yamada } 650013413cdSMasahiro Yamada 651013413cdSMasahiro Yamada ret = ldb_find_next_bridge_helper(ldb); 652013413cdSMasahiro Yamada if (ret) 653013413cdSMasahiro Yamada return ret; 654013413cdSMasahiro Yamada 655013413cdSMasahiro Yamada ret = imx8qxp_ldb_set_di_id(imx8qxp_ldb); 656013413cdSMasahiro Yamada if (ret) 657013413cdSMasahiro Yamada return ret; 658013413cdSMasahiro Yamada 659013413cdSMasahiro Yamada ret = imx8qxp_ldb_parse_dt_companion(imx8qxp_ldb); 660013413cdSMasahiro Yamada if (ret) 661013413cdSMasahiro Yamada return ret; 662013413cdSMasahiro Yamada 663013413cdSMasahiro Yamada platform_set_drvdata(pdev, imx8qxp_ldb); 664013413cdSMasahiro Yamada pm_runtime_enable(dev); 665013413cdSMasahiro Yamada 666013413cdSMasahiro Yamada ldb_add_bridge_helper(ldb, &imx8qxp_ldb_bridge_funcs); 667013413cdSMasahiro Yamada 668013413cdSMasahiro Yamada return ret; 669013413cdSMasahiro Yamada } 670013413cdSMasahiro Yamada 671013413cdSMasahiro Yamada static void imx8qxp_ldb_remove(struct platform_device *pdev) 672013413cdSMasahiro Yamada { 673013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = platform_get_drvdata(pdev); 674013413cdSMasahiro Yamada struct ldb *ldb = &imx8qxp_ldb->base; 675013413cdSMasahiro Yamada 676013413cdSMasahiro Yamada ldb_remove_bridge_helper(ldb); 677013413cdSMasahiro Yamada 678013413cdSMasahiro Yamada pm_runtime_disable(&pdev->dev); 679013413cdSMasahiro Yamada } 680013413cdSMasahiro Yamada 681013413cdSMasahiro Yamada static int __maybe_unused imx8qxp_ldb_runtime_suspend(struct device *dev) 682013413cdSMasahiro Yamada { 683013413cdSMasahiro Yamada return 0; 684013413cdSMasahiro Yamada } 685013413cdSMasahiro Yamada 686013413cdSMasahiro Yamada static int __maybe_unused imx8qxp_ldb_runtime_resume(struct device *dev) 687013413cdSMasahiro Yamada { 688013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = dev_get_drvdata(dev); 689013413cdSMasahiro Yamada struct ldb *ldb = &imx8qxp_ldb->base; 690013413cdSMasahiro Yamada 691013413cdSMasahiro Yamada /* disable LDB by resetting the control register to POR default */ 692013413cdSMasahiro Yamada regmap_write(ldb->regmap, ldb->ctrl_reg, 0); 693013413cdSMasahiro Yamada 694013413cdSMasahiro Yamada return 0; 695013413cdSMasahiro Yamada } 696013413cdSMasahiro Yamada 697013413cdSMasahiro Yamada static const struct dev_pm_ops imx8qxp_ldb_pm_ops = { 698013413cdSMasahiro Yamada SET_RUNTIME_PM_OPS(imx8qxp_ldb_runtime_suspend, 699013413cdSMasahiro Yamada imx8qxp_ldb_runtime_resume, NULL) 700013413cdSMasahiro Yamada }; 701013413cdSMasahiro Yamada 702013413cdSMasahiro Yamada static const struct of_device_id imx8qxp_ldb_dt_ids[] = { 703013413cdSMasahiro Yamada { .compatible = "fsl,imx8qxp-ldb" }, 704013413cdSMasahiro Yamada { /* sentinel */ } 705013413cdSMasahiro Yamada }; 706013413cdSMasahiro Yamada MODULE_DEVICE_TABLE(of, imx8qxp_ldb_dt_ids); 707013413cdSMasahiro Yamada 708013413cdSMasahiro Yamada static struct platform_driver imx8qxp_ldb_driver = { 709013413cdSMasahiro Yamada .probe = imx8qxp_ldb_probe, 710013413cdSMasahiro Yamada .remove_new = imx8qxp_ldb_remove, 711013413cdSMasahiro Yamada .driver = { 712013413cdSMasahiro Yamada .pm = &imx8qxp_ldb_pm_ops, 713013413cdSMasahiro Yamada .name = DRIVER_NAME, 714013413cdSMasahiro Yamada .of_match_table = imx8qxp_ldb_dt_ids, 715013413cdSMasahiro Yamada }, 716013413cdSMasahiro Yamada }; 717013413cdSMasahiro Yamada module_platform_driver(imx8qxp_ldb_driver); 718013413cdSMasahiro Yamada 719013413cdSMasahiro Yamada MODULE_DESCRIPTION("i.MX8QXP LVDS Display Bridge(LDB)/Pixel Mapper bridge driver"); 720013413cdSMasahiro Yamada MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); 721013413cdSMasahiro Yamada MODULE_LICENSE("GPL v2"); 722013413cdSMasahiro Yamada MODULE_ALIAS("platform:" DRIVER_NAME); 723