cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dw_hdmi-imx.c (6851B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
      3 *
      4 * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now)
      5 */
      6
      7#include <linux/component.h>
      8#include <linux/mfd/syscon.h>
      9#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
     10#include <linux/module.h>
     11#include <linux/platform_device.h>
     12#include <linux/regmap.h>
     13
     14#include <video/imx-ipu-v3.h>
     15
     16#include <drm/bridge/dw_hdmi.h>
     17#include <drm/drm_atomic_helper.h>
     18#include <drm/drm_bridge.h>
     19#include <drm/drm_edid.h>
     20#include <drm/drm_encoder.h>
     21#include <drm/drm_managed.h>
     22#include <drm/drm_of.h>
     23#include <drm/drm_simple_kms_helper.h>
     24
     25#include "imx-drm.h"
     26
     27struct imx_hdmi;
     28
     29struct imx_hdmi_encoder {
     30	struct drm_encoder encoder;
     31	struct imx_hdmi *hdmi;
     32};
     33
     34struct imx_hdmi {
     35	struct device *dev;
     36	struct drm_bridge *bridge;
     37	struct dw_hdmi *hdmi;
     38	struct regmap *regmap;
     39};
     40
     41static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e)
     42{
     43	return container_of(e, struct imx_hdmi_encoder, encoder)->hdmi;
     44}
     45
     46static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = {
     47	{
     48		45250000, {
     49			{ 0x01e0, 0x0000 },
     50			{ 0x21e1, 0x0000 },
     51			{ 0x41e2, 0x0000 }
     52		},
     53	}, {
     54		92500000, {
     55			{ 0x0140, 0x0005 },
     56			{ 0x2141, 0x0005 },
     57			{ 0x4142, 0x0005 },
     58	},
     59	}, {
     60		148500000, {
     61			{ 0x00a0, 0x000a },
     62			{ 0x20a1, 0x000a },
     63			{ 0x40a2, 0x000a },
     64		},
     65	}, {
     66		216000000, {
     67			{ 0x00a0, 0x000a },
     68			{ 0x2001, 0x000f },
     69			{ 0x4002, 0x000f },
     70		},
     71	}, {
     72		~0UL, {
     73			{ 0x0000, 0x0000 },
     74			{ 0x0000, 0x0000 },
     75			{ 0x0000, 0x0000 },
     76		},
     77	}
     78};
     79
     80static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
     81	/*      pixelclk     bpp8    bpp10   bpp12 */
     82	{
     83		54000000, { 0x091c, 0x091c, 0x06dc },
     84	}, {
     85		58400000, { 0x091c, 0x06dc, 0x06dc },
     86	}, {
     87		72000000, { 0x06dc, 0x06dc, 0x091c },
     88	}, {
     89		74250000, { 0x06dc, 0x0b5c, 0x091c },
     90	}, {
     91		118800000, { 0x091c, 0x091c, 0x06dc },
     92	}, {
     93		216000000, { 0x06dc, 0x0b5c, 0x091c },
     94	}, {
     95		~0UL, { 0x0000, 0x0000, 0x0000 },
     96	},
     97};
     98
     99/*
    100 * Resistance term 133Ohm Cfg
    101 * PREEMP config 0.00
    102 * TX/CK level 10
    103 */
    104static const struct dw_hdmi_phy_config imx_phy_config[] = {
    105	/*pixelclk   symbol   term   vlev */
    106	{ 216000000, 0x800d, 0x0005, 0x01ad},
    107	{ ~0UL,      0x0000, 0x0000, 0x0000}
    108};
    109
    110static void dw_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
    111{
    112	struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder);
    113	int mux = drm_of_encoder_active_port_id(hdmi->dev->of_node, encoder);
    114
    115	regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
    116			   IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
    117			   mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
    118}
    119
    120static int dw_hdmi_imx_atomic_check(struct drm_encoder *encoder,
    121				    struct drm_crtc_state *crtc_state,
    122				    struct drm_connector_state *conn_state)
    123{
    124	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
    125
    126	imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
    127	imx_crtc_state->di_hsync_pin = 2;
    128	imx_crtc_state->di_vsync_pin = 3;
    129
    130	return 0;
    131}
    132
    133static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
    134	.enable     = dw_hdmi_imx_encoder_enable,
    135	.atomic_check = dw_hdmi_imx_atomic_check,
    136};
    137
    138static enum drm_mode_status
    139imx6q_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data,
    140		      const struct drm_display_info *info,
    141		      const struct drm_display_mode *mode)
    142{
    143	if (mode->clock < 13500)
    144		return MODE_CLOCK_LOW;
    145	/* FIXME: Hardware is capable of 266MHz, but setup data is missing. */
    146	if (mode->clock > 216000)
    147		return MODE_CLOCK_HIGH;
    148
    149	return MODE_OK;
    150}
    151
    152static enum drm_mode_status
    153imx6dl_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data,
    154		       const struct drm_display_info *info,
    155		       const struct drm_display_mode *mode)
    156{
    157	if (mode->clock < 13500)
    158		return MODE_CLOCK_LOW;
    159	/* FIXME: Hardware is capable of 270MHz, but setup data is missing. */
    160	if (mode->clock > 216000)
    161		return MODE_CLOCK_HIGH;
    162
    163	return MODE_OK;
    164}
    165
    166static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
    167	.mpll_cfg   = imx_mpll_cfg,
    168	.cur_ctr    = imx_cur_ctr,
    169	.phy_config = imx_phy_config,
    170	.mode_valid = imx6q_hdmi_mode_valid,
    171};
    172
    173static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
    174	.mpll_cfg = imx_mpll_cfg,
    175	.cur_ctr  = imx_cur_ctr,
    176	.phy_config = imx_phy_config,
    177	.mode_valid = imx6dl_hdmi_mode_valid,
    178};
    179
    180static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
    181	{ .compatible = "fsl,imx6q-hdmi",
    182	  .data = &imx6q_hdmi_drv_data
    183	}, {
    184	  .compatible = "fsl,imx6dl-hdmi",
    185	  .data = &imx6dl_hdmi_drv_data
    186	},
    187	{},
    188};
    189MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
    190
    191static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
    192			    void *data)
    193{
    194	struct drm_device *drm = data;
    195	struct imx_hdmi_encoder *hdmi_encoder;
    196	struct drm_encoder *encoder;
    197	int ret;
    198
    199	hdmi_encoder = drmm_simple_encoder_alloc(drm, struct imx_hdmi_encoder,
    200						 encoder, DRM_MODE_ENCODER_TMDS);
    201	if (IS_ERR(hdmi_encoder))
    202		return PTR_ERR(hdmi_encoder);
    203
    204	hdmi_encoder->hdmi = dev_get_drvdata(dev);
    205	encoder = &hdmi_encoder->encoder;
    206
    207	ret = imx_drm_encoder_parse_of(drm, encoder, dev->of_node);
    208	if (ret)
    209		return ret;
    210
    211	drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
    212
    213	return drm_bridge_attach(encoder, hdmi_encoder->hdmi->bridge, NULL, 0);
    214}
    215
    216static const struct component_ops dw_hdmi_imx_ops = {
    217	.bind	= dw_hdmi_imx_bind,
    218};
    219
    220static int dw_hdmi_imx_probe(struct platform_device *pdev)
    221{
    222	struct device_node *np = pdev->dev.of_node;
    223	const struct of_device_id *match = of_match_node(dw_hdmi_imx_dt_ids, np);
    224	struct imx_hdmi *hdmi;
    225	int ret;
    226
    227	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
    228	if (!hdmi)
    229		return -ENOMEM;
    230
    231	platform_set_drvdata(pdev, hdmi);
    232	hdmi->dev = &pdev->dev;
    233
    234	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
    235	if (IS_ERR(hdmi->regmap)) {
    236		dev_err(hdmi->dev, "Unable to get gpr\n");
    237		return PTR_ERR(hdmi->regmap);
    238	}
    239
    240	hdmi->hdmi = dw_hdmi_probe(pdev, match->data);
    241	if (IS_ERR(hdmi->hdmi))
    242		return PTR_ERR(hdmi->hdmi);
    243
    244	hdmi->bridge = of_drm_find_bridge(np);
    245	if (!hdmi->bridge) {
    246		dev_err(hdmi->dev, "Unable to find bridge\n");
    247		dw_hdmi_remove(hdmi->hdmi);
    248		return -ENODEV;
    249	}
    250
    251	ret = component_add(&pdev->dev, &dw_hdmi_imx_ops);
    252	if (ret)
    253		dw_hdmi_remove(hdmi->hdmi);
    254
    255	return ret;
    256}
    257
    258static int dw_hdmi_imx_remove(struct platform_device *pdev)
    259{
    260	struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
    261
    262	component_del(&pdev->dev, &dw_hdmi_imx_ops);
    263	dw_hdmi_remove(hdmi->hdmi);
    264
    265	return 0;
    266}
    267
    268static struct platform_driver dw_hdmi_imx_platform_driver = {
    269	.probe  = dw_hdmi_imx_probe,
    270	.remove = dw_hdmi_imx_remove,
    271	.driver = {
    272		.name = "dwhdmi-imx",
    273		.of_match_table = dw_hdmi_imx_dt_ids,
    274	},
    275};
    276
    277module_platform_driver(dw_hdmi_imx_platform_driver);
    278
    279MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
    280MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
    281MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
    282MODULE_LICENSE("GPL");
    283MODULE_ALIAS("platform:dwhdmi-imx");