summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/bridge/samsung-dsim-imx.c
blob: 17e93313745804e727136a355f8ccf1b50c5e952 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// SPDX-License-Identifier: GPL-2.0-only
/*
 * NXP i.MX8M SoC MIPI DSI driver
 *
 * Copyright (C) 2020 Marek Vasut <marex@denx.de>
 */

#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>

#include <drm/bridge/samsung-dsim.h>
#include <drm/drm_bridge.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>

enum {
	DSI_PORT_IN,
	DSI_PORT_OUT
};

struct imx_dsim_priv {
	struct samsung_dsim *dsi;
	struct drm_encoder encoder;
};

static const unsigned int imx8mm_dsim_reg_values[] = {
	[RESET_TYPE] = DSIM_SWRST,
	[PLL_TIMER] = 500,
	[STOP_STATE_CNT] = 0xf,
	[PHYCTRL_ULPS_EXIT] = 0xaf,
	[PHYCTRL_VREG_LP] = 0,
	[PHYCTRL_SLEW_UP] = 0,
	[PHYTIMING_LPX] = 0x06,
	[PHYTIMING_HS_EXIT] = 0x0b,
	[PHYTIMING_CLK_PREPARE] = 0x07,
	[PHYTIMING_CLK_ZERO] = 0x26,
	[PHYTIMING_CLK_POST] = 0x0d,
	[PHYTIMING_CLK_TRAIL] = 0x08,
	[PHYTIMING_HS_PREPARE] = 0x08,
	[PHYTIMING_HS_ZERO] = 0x0d,
	[PHYTIMING_HS_TRAIL] = 0x0b,
};

static bool imx_dsim_mode_fixup(struct device *dev,
				const struct drm_display_mode *mode,
				struct drm_display_mode *adjusted_mode)
{
	/* At least LCDIF + DSIM needs active low sync */
	adjusted_mode->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);
	adjusted_mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);

	return true;
}

static const struct samsung_dsim_host_ops imx_dsim_host_ops = {
	.mode_fixup = imx_dsim_mode_fixup
};

static const struct drm_bridge_timings imx_dsim_timings = {
	.input_bus_flags = DRM_BUS_FLAG_DE_LOW,
};

static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = {
	.reg_ofs = EXYNOS5433_REG_OFS,
	.plltmr_reg = 0xa0,
	.has_clklane_stop = 1,
	.num_clks = 2,
	.max_freq = 2100,
	.wait_for_reset = 0,
	.num_bits_resol = 12,
	.reg_values = imx8mm_dsim_reg_values,
	.host_ops = &imx_dsim_host_ops,
	.bridge_timings = &imx_dsim_timings,
};

static const struct of_device_id imx_dsim_of_match[] = {
	{ .compatible = "fsl,imx8mm-mipi-dsim",
	  .data = &imx8mm_dsi_driver_data },
	{ }
};

static int imx_dsim_probe(struct platform_device *pdev)
{
	struct imx_dsim_priv *dsi;
	struct device *dev = &pdev->dev;

	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
	if (!dsi)
		return -ENOMEM;
	platform_set_drvdata(pdev, dsi);

	dsi->dsi = samsung_dsim_probe(pdev);
	if (IS_ERR(dsi->dsi))
		return PTR_ERR(dsi->dsi);

	pm_runtime_enable(dev);

	return 0;
}

static int imx_dsim_remove(struct platform_device *pdev)
{
	struct imx_dsim_priv *dsi = platform_get_drvdata(pdev);

	pm_runtime_disable(&pdev->dev);

	samsung_dsim_remove(dsi->dsi);

	return 0;
}

static int __maybe_unused imx_dsim_suspend(struct device *dev)
{
	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);

	return samsung_dsim_suspend(dsi->dsi);
}

static int __maybe_unused imx_dsim_resume(struct device *dev)
{
	struct imx_dsim_priv *dsi = dev_get_drvdata(dev);

	return samsung_dsim_resume(dsi->dsi);
}

static const struct dev_pm_ops imx_dsim_pm_ops = {
	SET_RUNTIME_PM_OPS(imx_dsim_suspend, imx_dsim_resume, NULL)
	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
				pm_runtime_force_resume)
};

static struct platform_driver imx_dsim_driver = {
	.probe = imx_dsim_probe,
	.remove = imx_dsim_remove,
	.driver = {
		   .name = "imx-dsim-dsi",
		   .owner = THIS_MODULE,
		   .pm = &imx_dsim_pm_ops,
		   .of_match_table = imx_dsim_of_match,
	},
};

module_platform_driver(imx_dsim_driver);

MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
MODULE_DESCRIPTION("NXP i.MX8M SoC MIPI DSI");
MODULE_LICENSE("GPL v2");