linux/drivers/gpu/drm/bridge/ti-sn65dsi86.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
 * datasheet: https://www.ti.com/lit/ds/symlink/sn65dsi86.pdf
 */

#include <linux/atomic.h>
#include <linux/auxiliary_bus.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/pm_runtime.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>

#include <asm/unaligned.h>

#include <drm/display/drm_dp_aux_bus.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>

#define SN_DEVICE_REV_REG
#define SN_DPPLL_SRC_REG
#define DPPLL_CLK_SRC_DSICLK
#define REFCLK_FREQ_MASK
#define REFCLK_FREQ(x)
#define DPPLL_SRC_DP_PLL_LOCK
#define SN_PLL_ENABLE_REG
#define SN_DSI_LANES_REG
#define CHA_DSI_LANES_MASK
#define CHA_DSI_LANES(x)
#define SN_DSIA_CLK_FREQ_REG
#define SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG
#define SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG
#define SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG
#define SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG
#define CHA_HSYNC_POLARITY
#define SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG
#define SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG
#define CHA_VSYNC_POLARITY
#define SN_CHA_HORIZONTAL_BACK_PORCH_REG
#define SN_CHA_VERTICAL_BACK_PORCH_REG
#define SN_CHA_HORIZONTAL_FRONT_PORCH_REG
#define SN_CHA_VERTICAL_FRONT_PORCH_REG
#define SN_LN_ASSIGN_REG
#define LN_ASSIGN_WIDTH
#define SN_ENH_FRAME_REG
#define VSTREAM_ENABLE
#define LN_POLRS_OFFSET
#define LN_POLRS_MASK
#define SN_DATA_FORMAT_REG
#define BPP_18_RGB
#define SN_HPD_DISABLE_REG
#define HPD_DISABLE
#define HPD_DEBOUNCED_STATE
#define SN_GPIO_IO_REG
#define SN_GPIO_INPUT_SHIFT
#define SN_GPIO_OUTPUT_SHIFT
#define SN_GPIO_CTRL_REG
#define SN_GPIO_MUX_INPUT
#define SN_GPIO_MUX_OUTPUT
#define SN_GPIO_MUX_SPECIAL
#define SN_GPIO_MUX_MASK
#define SN_AUX_WDATA_REG(x)
#define SN_AUX_ADDR_19_16_REG
#define SN_AUX_ADDR_15_8_REG
#define SN_AUX_ADDR_7_0_REG
#define SN_AUX_ADDR_MASK
#define SN_AUX_LENGTH_REG
#define SN_AUX_CMD_REG
#define AUX_CMD_SEND
#define AUX_CMD_REQ(x)
#define SN_AUX_RDATA_REG(x)
#define SN_SSC_CONFIG_REG
#define DP_NUM_LANES_MASK
#define DP_NUM_LANES(x)
#define SN_DATARATE_CONFIG_REG
#define DP_DATARATE_MASK
#define DP_DATARATE(x)
#define SN_TRAINING_SETTING_REG
#define SCRAMBLE_DISABLE
#define SN_ML_TX_MODE_REG
#define ML_TX_MAIN_LINK_OFF
#define ML_TX_NORMAL_MODE
#define SN_PWM_PRE_DIV_REG
#define SN_BACKLIGHT_SCALE_REG
#define BACKLIGHT_SCALE_MAX
#define SN_BACKLIGHT_REG
#define SN_PWM_EN_INV_REG
#define SN_PWM_INV_MASK
#define SN_PWM_EN_MASK
#define SN_AUX_CMD_STATUS_REG
#define AUX_IRQ_STATUS_AUX_RPLY_TOUT
#define AUX_IRQ_STATUS_AUX_SHORT
#define AUX_IRQ_STATUS_NAT_I2C_FAIL

#define MIN_DSI_CLK_FREQ_MHZ

/* fudge factor required to account for 8b/10b encoding */
#define DP_CLK_FUDGE_NUM
#define DP_CLK_FUDGE_DEN

/* Matches DP_AUX_MAX_PAYLOAD_BYTES (for now) */
#define SN_AUX_MAX_PAYLOAD_BYTES

#define SN_REGULATOR_SUPPLY_NUM

#define SN_MAX_DP_LANES
#define SN_NUM_GPIOS
#define SN_GPIO_PHYSICAL_OFFSET

#define SN_LINK_TRAINING_TRIES

#define SN_PWM_GPIO_IDX

/**
 * struct ti_sn65dsi86 - Platform data for ti-sn65dsi86 driver.
 * @bridge_aux:   AUX-bus sub device for MIPI-to-eDP bridge functionality.
 * @gpio_aux:     AUX-bus sub device for GPIO controller functionality.
 * @aux_aux:      AUX-bus sub device for eDP AUX channel functionality.
 * @pwm_aux:      AUX-bus sub device for PWM controller functionality.
 *
 * @dev:          Pointer to the top level (i2c) device.
 * @regmap:       Regmap for accessing i2c.
 * @aux:          Our aux channel.
 * @bridge:       Our bridge.
 * @connector:    Our connector.
 * @host_node:    Remote DSI node.
 * @dsi:          Our MIPI DSI source.
 * @refclk:       Our reference clock.
 * @next_bridge:  The bridge on the eDP side.
 * @enable_gpio:  The GPIO we toggle to enable the bridge.
 * @supplies:     Data for bulk enabling/disabling our regulators.
 * @dp_lanes:     Count of dp_lanes we're using.
 * @ln_assign:    Value to program to the LN_ASSIGN register.
 * @ln_polrs:     Value for the 4-bit LN_POLRS field of SN_ENH_FRAME_REG.
 * @comms_enabled: If true then communication over the aux channel is enabled.
 * @comms_mutex:   Protects modification of comms_enabled.
 *
 * @gchip:        If we expose our GPIOs, this is used.
 * @gchip_output: A cache of whether we've set GPIOs to output.  This
 *                serves double-duty of keeping track of the direction and
 *                also keeping track of whether we've incremented the
 *                pm_runtime reference count for this pin, which we do
 *                whenever a pin is configured as an output.  This is a
 *                bitmap so we can do atomic ops on it without an extra
 *                lock so concurrent users of our 4 GPIOs don't stomp on
 *                each other's read-modify-write.
 *
 * @pchip:        pwm_chip if the PWM is exposed.
 * @pwm_enabled:  Used to track if the PWM signal is currently enabled.
 * @pwm_pin_busy: Track if GPIO4 is currently requested for GPIO or PWM.
 * @pwm_refclk_freq: Cache for the reference clock input to the PWM.
 */
struct ti_sn65dsi86 {};

static const struct regmap_range ti_sn65dsi86_volatile_ranges[] =;

static const struct regmap_access_table ti_sn_bridge_volatile_table =;

static const struct regmap_config ti_sn65dsi86_regmap_config =;

static int __maybe_unused ti_sn65dsi86_read_u16(struct ti_sn65dsi86 *pdata,
						unsigned int reg, u16 *val)
{}

static void ti_sn65dsi86_write_u16(struct ti_sn65dsi86 *pdata,
				   unsigned int reg, u16 val)
{}

static u32 ti_sn_bridge_get_dsi_freq(struct ti_sn65dsi86 *pdata)
{}

/* clk frequencies supported by bridge in Hz in case derived from REFCLK pin */
static const u32 ti_sn_bridge_refclk_lut[] =;

/* clk frequencies supported by bridge in Hz in case derived from DACP/N pin */
static const u32 ti_sn_bridge_dsiclk_lut[] =;

static void ti_sn_bridge_set_refclk_freq(struct ti_sn65dsi86 *pdata)
{}

static void ti_sn65dsi86_enable_comms(struct ti_sn65dsi86 *pdata)
{}

static void ti_sn65dsi86_disable_comms(struct ti_sn65dsi86 *pdata)
{}

static int __maybe_unused ti_sn65dsi86_resume(struct device *dev)
{}

static int __maybe_unused ti_sn65dsi86_suspend(struct device *dev)
{}

static const struct dev_pm_ops ti_sn65dsi86_pm_ops =;

static int status_show(struct seq_file *s, void *data)
{}

DEFINE_SHOW_ATTRIBUTE();

static void ti_sn65dsi86_debugfs_remove(void *data)
{}

static void ti_sn65dsi86_debugfs_init(struct ti_sn65dsi86 *pdata)
{}

/* -----------------------------------------------------------------------------
 * Auxiliary Devices (*not* AUX)
 */

static void ti_sn65dsi86_uninit_aux(void *data)
{}

static void ti_sn65dsi86_delete_aux(void *data)
{}

static void ti_sn65dsi86_aux_device_release(struct device *dev)
{}

static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
				       struct auxiliary_device **aux_out,
				       const char *name)
{}

/* -----------------------------------------------------------------------------
 * AUX Adapter
 */

static struct ti_sn65dsi86 *aux_to_ti_sn65dsi86(struct drm_dp_aux *aux)
{}

static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux,
				  struct drm_dp_aux_msg *msg)
{}

static int ti_sn_aux_wait_hpd_asserted(struct drm_dp_aux *aux, unsigned long wait_us)
{}

static int ti_sn_aux_probe(struct auxiliary_device *adev,
			   const struct auxiliary_device_id *id)
{}

static const struct auxiliary_device_id ti_sn_aux_id_table[] =;

static struct auxiliary_driver ti_sn_aux_driver =;

/*------------------------------------------------------------------------------
 * DRM Bridge
 */

static struct ti_sn65dsi86 *bridge_to_ti_sn65dsi86(struct drm_bridge *bridge)
{}

static int ti_sn_attach_host(struct auxiliary_device *adev, struct ti_sn65dsi86 *pdata)
{}

static int ti_sn_bridge_attach(struct drm_bridge *bridge,
			       enum drm_bridge_attach_flags flags)
{}

static void ti_sn_bridge_detach(struct drm_bridge *bridge)
{}

static enum drm_mode_status
ti_sn_bridge_mode_valid(struct drm_bridge *bridge,
			const struct drm_display_info *info,
			const struct drm_display_mode *mode)
{}

static void ti_sn_bridge_atomic_disable(struct drm_bridge *bridge,
					struct drm_bridge_state *old_bridge_state)
{}

static void ti_sn_bridge_set_dsi_rate(struct ti_sn65dsi86 *pdata)
{}

static unsigned int ti_sn_bridge_get_bpp(struct drm_connector *connector)
{}

/*
 * LUT index corresponds to register value and
 * LUT values corresponds to dp data rate supported
 * by the bridge in Mbps unit.
 */
static const unsigned int ti_sn_bridge_dp_rate_lut[] =;

static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn65dsi86 *pdata, unsigned int bpp)
{}

static unsigned int ti_sn_bridge_read_valid_rates(struct ti_sn65dsi86 *pdata)
{}

static void ti_sn_bridge_set_video_timings(struct ti_sn65dsi86 *pdata)
{}

static unsigned int ti_sn_get_max_lanes(struct ti_sn65dsi86 *pdata)
{}

static int ti_sn_link_training(struct ti_sn65dsi86 *pdata, int dp_rate_idx,
			       const char **last_err_str)
{}

static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge,
				       struct drm_bridge_state *old_bridge_state)
{}

static void ti_sn_bridge_atomic_pre_enable(struct drm_bridge *bridge,
					   struct drm_bridge_state *old_bridge_state)
{}

static void ti_sn_bridge_atomic_post_disable(struct drm_bridge *bridge,
					     struct drm_bridge_state *old_bridge_state)
{}

static enum drm_connector_status ti_sn_bridge_detect(struct drm_bridge *bridge)
{}

static const struct drm_edid *ti_sn_bridge_edid_read(struct drm_bridge *bridge,
						     struct drm_connector *connector)
{}

static const struct drm_bridge_funcs ti_sn_bridge_funcs =;

static void ti_sn_bridge_parse_lanes(struct ti_sn65dsi86 *pdata,
				     struct device_node *np)
{}

static int ti_sn_bridge_parse_dsi_host(struct ti_sn65dsi86 *pdata)
{}

static int ti_sn_bridge_probe(struct auxiliary_device *adev,
			      const struct auxiliary_device_id *id)
{}

static void ti_sn_bridge_remove(struct auxiliary_device *adev)
{}

static const struct auxiliary_device_id ti_sn_bridge_id_table[] =;

static struct auxiliary_driver ti_sn_bridge_driver =;

/* -----------------------------------------------------------------------------
 * PWM Controller
 */
#if defined(CONFIG_PWM)
static int ti_sn_pwm_pin_request(struct ti_sn65dsi86 *pdata)
{}

static void ti_sn_pwm_pin_release(struct ti_sn65dsi86 *pdata)
{}

static struct ti_sn65dsi86 *pwm_chip_to_ti_sn_bridge(struct pwm_chip *chip)
{}

static int ti_sn_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{}

static void ti_sn_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{}

/*
 * Limitations:
 * - The PWM signal is not driven when the chip is powered down, or in its
 *   reset state and the driver does not implement the "suspend state"
 *   described in the documentation. In order to save power, state->enabled is
 *   interpreted as denoting if the signal is expected to be valid, and is used
 *   to determine if the chip needs to be kept powered.
 * - Changing both period and duty_cycle is not done atomically, neither is the
 *   multi-byte register updates, so the output might briefly be undefined
 *   during update.
 */
static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
			   const struct pwm_state *state)
{}

static int ti_sn_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
			       struct pwm_state *state)
{}

static const struct pwm_ops ti_sn_pwm_ops =;

static int ti_sn_pwm_probe(struct auxiliary_device *adev,
			   const struct auxiliary_device_id *id)
{}

static void ti_sn_pwm_remove(struct auxiliary_device *adev)
{}

static const struct auxiliary_device_id ti_sn_pwm_id_table[] =;

static struct auxiliary_driver ti_sn_pwm_driver =;

static int __init ti_sn_pwm_register(void)
{}

static void ti_sn_pwm_unregister(void)
{}

#else
static inline int ti_sn_pwm_pin_request(struct ti_sn65dsi86 *pdata) { return 0; }
static inline void ti_sn_pwm_pin_release(struct ti_sn65dsi86 *pdata) {}

static inline int ti_sn_pwm_register(void) { return 0; }
static inline void ti_sn_pwm_unregister(void) {}
#endif

/* -----------------------------------------------------------------------------
 * GPIO Controller
 */
#if defined(CONFIG_OF_GPIO)

static int tn_sn_bridge_of_xlate(struct gpio_chip *chip,
				 const struct of_phandle_args *gpiospec,
				 u32 *flags)
{}

static int ti_sn_bridge_gpio_get_direction(struct gpio_chip *chip,
					   unsigned int offset)
{}

static int ti_sn_bridge_gpio_get(struct gpio_chip *chip, unsigned int offset)
{}

static void ti_sn_bridge_gpio_set(struct gpio_chip *chip, unsigned int offset,
				  int val)
{}

static int ti_sn_bridge_gpio_direction_input(struct gpio_chip *chip,
					     unsigned int offset)
{}

static int ti_sn_bridge_gpio_direction_output(struct gpio_chip *chip,
					      unsigned int offset, int val)
{}

static int ti_sn_bridge_gpio_request(struct gpio_chip *chip, unsigned int offset)
{}

static void ti_sn_bridge_gpio_free(struct gpio_chip *chip, unsigned int offset)
{}

static const char * const ti_sn_bridge_gpio_names[SN_NUM_GPIOS] =;

static int ti_sn_gpio_probe(struct auxiliary_device *adev,
			    const struct auxiliary_device_id *id)
{}

static const struct auxiliary_device_id ti_sn_gpio_id_table[] =;

MODULE_DEVICE_TABLE(auxiliary, ti_sn_gpio_id_table);

static struct auxiliary_driver ti_sn_gpio_driver =;

static int __init ti_sn_gpio_register(void)
{}

static void ti_sn_gpio_unregister(void)
{}

#else

static inline int ti_sn_gpio_register(void) { return 0; }
static inline void ti_sn_gpio_unregister(void) {}

#endif

/* -----------------------------------------------------------------------------
 * Probe & Remove
 */

static void ti_sn65dsi86_runtime_disable(void *data)
{}

static int ti_sn65dsi86_parse_regulators(struct ti_sn65dsi86 *pdata)
{}

static int ti_sn65dsi86_probe(struct i2c_client *client)
{}

static struct i2c_device_id ti_sn65dsi86_id[] =;
MODULE_DEVICE_TABLE(i2c, ti_sn65dsi86_id);

static const struct of_device_id ti_sn65dsi86_match_table[] =;
MODULE_DEVICE_TABLE(of, ti_sn65dsi86_match_table);

static struct i2c_driver ti_sn65dsi86_driver =;

static int __init ti_sn65dsi86_init(void)
{}
module_init();

static void __exit ti_sn65dsi86_exit(void)
{}
module_exit(ti_sn65dsi86_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();