brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 9b5bebb Raw
234 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2012 Sascha Hauer, Pengutronix4 * Copyright 2019,2020,2022 NXP5 */6 7#include <linux/export.h>8#include <linux/media-bus-format.h>9#include <linux/mfd/syscon.h>10#include <linux/module.h>11#include <linux/of.h>12#include <linux/regmap.h>13 14#include <drm/drm_bridge.h>15#include <drm/drm_of.h>16#include <drm/drm_print.h>17 18#include "imx-ldb-helper.h"19 20bool ldb_channel_is_single_link(struct ldb_channel *ldb_ch)21{22	return ldb_ch->link_type == LDB_CH_SINGLE_LINK;23}24EXPORT_SYMBOL_GPL(ldb_channel_is_single_link);25 26bool ldb_channel_is_split_link(struct ldb_channel *ldb_ch)27{28	return ldb_ch->link_type == LDB_CH_DUAL_LINK_EVEN_ODD_PIXELS ||29	       ldb_ch->link_type == LDB_CH_DUAL_LINK_ODD_EVEN_PIXELS;30}31EXPORT_SYMBOL_GPL(ldb_channel_is_split_link);32 33int ldb_bridge_atomic_check_helper(struct drm_bridge *bridge,34				   struct drm_bridge_state *bridge_state,35				   struct drm_crtc_state *crtc_state,36				   struct drm_connector_state *conn_state)37{38	struct ldb_channel *ldb_ch = bridge->driver_private;39 40	ldb_ch->in_bus_format = bridge_state->input_bus_cfg.format;41	ldb_ch->out_bus_format = bridge_state->output_bus_cfg.format;42 43	return 0;44}45EXPORT_SYMBOL_GPL(ldb_bridge_atomic_check_helper);46 47void ldb_bridge_mode_set_helper(struct drm_bridge *bridge,48				const struct drm_display_mode *mode,49				const struct drm_display_mode *adjusted_mode)50{51	struct ldb_channel *ldb_ch = bridge->driver_private;52	struct ldb *ldb = ldb_ch->ldb;53	bool is_split = ldb_channel_is_split_link(ldb_ch);54 55	if (is_split)56		ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;57 58	switch (ldb_ch->out_bus_format) {59	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:60		break;61	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:62		if (ldb_ch->chno == 0 || is_split)63			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;64		if (ldb_ch->chno == 1 || is_split)65			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;66		break;67	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:68		if (ldb_ch->chno == 0 || is_split)69			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |70					 LDB_BIT_MAP_CH0_JEIDA;71		if (ldb_ch->chno == 1 || is_split)72			ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |73					 LDB_BIT_MAP_CH1_JEIDA;74		break;75	}76}77EXPORT_SYMBOL_GPL(ldb_bridge_mode_set_helper);78 79void ldb_bridge_enable_helper(struct drm_bridge *bridge)80{81	struct ldb_channel *ldb_ch = bridge->driver_private;82	struct ldb *ldb = ldb_ch->ldb;83 84	/*85	 * Platform specific bridge drivers should set ldb_ctrl properly86	 * for the enablement, so just write the ctrl_reg here.87	 */88	regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);89}90EXPORT_SYMBOL_GPL(ldb_bridge_enable_helper);91 92void ldb_bridge_disable_helper(struct drm_bridge *bridge)93{94	struct ldb_channel *ldb_ch = bridge->driver_private;95	struct ldb *ldb = ldb_ch->ldb;96	bool is_split = ldb_channel_is_split_link(ldb_ch);97 98	if (ldb_ch->chno == 0 || is_split)99		ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;100	if (ldb_ch->chno == 1 || is_split)101		ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;102 103	regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);104}105EXPORT_SYMBOL_GPL(ldb_bridge_disable_helper);106 107int ldb_bridge_attach_helper(struct drm_bridge *bridge,108			     enum drm_bridge_attach_flags flags)109{110	struct ldb_channel *ldb_ch = bridge->driver_private;111	struct ldb *ldb = ldb_ch->ldb;112 113	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {114		DRM_DEV_ERROR(ldb->dev,115			      "do not support creating a drm_connector\n");116		return -EINVAL;117	}118 119	return drm_bridge_attach(bridge->encoder,120				ldb_ch->next_bridge, bridge,121				DRM_BRIDGE_ATTACH_NO_CONNECTOR);122}123EXPORT_SYMBOL_GPL(ldb_bridge_attach_helper);124 125int ldb_init_helper(struct ldb *ldb)126{127	struct device *dev = ldb->dev;128	struct device_node *np = dev->of_node;129	struct device_node *child;130	int ret;131	u32 i;132 133	ldb->regmap = syscon_node_to_regmap(np->parent);134	if (IS_ERR(ldb->regmap)) {135		ret = PTR_ERR(ldb->regmap);136		if (ret != -EPROBE_DEFER)137			DRM_DEV_ERROR(dev, "failed to get regmap: %d\n", ret);138		return ret;139	}140 141	for_each_available_child_of_node(np, child) {142		struct ldb_channel *ldb_ch;143 144		ret = of_property_read_u32(child, "reg", &i);145		if (ret || i > MAX_LDB_CHAN_NUM - 1) {146			ret = -EINVAL;147			DRM_DEV_ERROR(dev,148				      "invalid channel node address: %u\n", i);149			of_node_put(child);150			return ret;151		}152 153		ldb_ch = ldb->channel[i];154		ldb_ch->ldb = ldb;155		ldb_ch->chno = i;156		ldb_ch->is_available = true;157		ldb_ch->np = child;158 159		ldb->available_ch_cnt++;160	}161 162	return 0;163}164EXPORT_SYMBOL_GPL(ldb_init_helper);165 166int ldb_find_next_bridge_helper(struct ldb *ldb)167{168	struct device *dev = ldb->dev;169	struct ldb_channel *ldb_ch;170	int ret, i;171 172	for (i = 0; i < MAX_LDB_CHAN_NUM; i++) {173		ldb_ch = ldb->channel[i];174 175		if (!ldb_ch->is_available)176			continue;177 178		ldb_ch->next_bridge = devm_drm_of_get_bridge(dev, ldb_ch->np,179							     1, 0);180		if (IS_ERR(ldb_ch->next_bridge)) {181			ret = PTR_ERR(ldb_ch->next_bridge);182			if (ret != -EPROBE_DEFER)183				DRM_DEV_ERROR(dev,184					      "failed to get next bridge: %d\n",185					      ret);186			return ret;187		}188	}189 190	return 0;191}192EXPORT_SYMBOL_GPL(ldb_find_next_bridge_helper);193 194void ldb_add_bridge_helper(struct ldb *ldb,195			   const struct drm_bridge_funcs *bridge_funcs)196{197	struct ldb_channel *ldb_ch;198	int i;199 200	for (i = 0; i < MAX_LDB_CHAN_NUM; i++) {201		ldb_ch = ldb->channel[i];202 203		if (!ldb_ch->is_available)204			continue;205 206		ldb_ch->bridge.driver_private = ldb_ch;207		ldb_ch->bridge.funcs = bridge_funcs;208		ldb_ch->bridge.of_node = ldb_ch->np;209 210		drm_bridge_add(&ldb_ch->bridge);211	}212}213EXPORT_SYMBOL_GPL(ldb_add_bridge_helper);214 215void ldb_remove_bridge_helper(struct ldb *ldb)216{217	struct ldb_channel *ldb_ch;218	int i;219 220	for (i = 0; i < MAX_LDB_CHAN_NUM; i++) {221		ldb_ch = ldb->channel[i];222 223		if (!ldb_ch->is_available)224			continue;225 226		drm_bridge_remove(&ldb_ch->bridge);227	}228}229EXPORT_SYMBOL_GPL(ldb_remove_bridge_helper);230 231MODULE_DESCRIPTION("i.MX8 LVDS Display Bridge(LDB)/Pixel Mapper bridge helper");232MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");233MODULE_LICENSE("GPL");234