Skip to content

Commit 5cc33d2

Browse files
danieldegrassecarlescufi
authored andcommitted
drivers: mipi: introduce MCUX MIPI DSI 2L driver
Introduce driver for MCUX MIPI DSI 2L. This IP block differs slightly from the existing MCUX MIPI peripheral, and uses a different hardware abstraction layer. For these reasons, a new driver was introduced rather than extending the existing mcux_dsi implementation. Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent b95d5cb commit 5cc33d2

File tree

4 files changed

+330
-1
lines changed

4 files changed

+330
-1
lines changed

drivers/mipi_dsi/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
zephyr_sources_ifdef(CONFIG_MIPI_DSI mipi_dsi.c)
22
zephyr_sources_ifdef(CONFIG_MIPI_DSI_MCUX dsi_mcux.c)
3+
zephyr_sources_ifdef(CONFIG_MIPI_DSI_MCUX_2L dsi_mcux_2l.c)

drivers/mipi_dsi/Kconfig.mcux

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2022, NXP
1+
# Copyright 2022-2023 NXP
22
# SPDX-License-Identifier: Apache-2.0
33

44
config MIPI_DSI_MCUX
@@ -7,3 +7,10 @@ config MIPI_DSI_MCUX
77
depends on DT_HAS_NXP_IMX_MIPI_DSI_ENABLED
88
help
99
NXP MIPI DSI controller driver
10+
11+
config MIPI_DSI_MCUX_2L
12+
bool "NXP MCUX MIPI-DSI 2L Controller"
13+
default y
14+
depends on DT_HAS_NXP_MIPI_DSI_2L_ENABLED
15+
help
16+
NXP MIPI DSI 2L controller driver

drivers/mipi_dsi/dsi_mcux_2l.c

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/*
2+
* Copyright 2023, NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/* Based on dsi_mcux.c, which is (c) 2022 NXP */
8+
9+
#define DT_DRV_COMPAT nxp_mipi_dsi_2l
10+
11+
#include <zephyr/drivers/clock_control.h>
12+
#include <zephyr/drivers/mipi_dsi.h>
13+
#include <fsl_mipi_dsi.h>
14+
#include <fsl_clock.h>
15+
#include <zephyr/logging/log.h>
16+
17+
#include <soc.h>
18+
19+
LOG_MODULE_REGISTER(dsi_mcux_host, CONFIG_MIPI_DSI_LOG_LEVEL);
20+
21+
struct mcux_mipi_dsi_config {
22+
MIPI_DSI_HOST_Type *base;
23+
dsi_dpi_config_t dpi_config;
24+
bool auto_insert_eotp;
25+
const struct device *bit_clk_dev;
26+
clock_control_subsys_t bit_clk_subsys;
27+
const struct device *esc_clk_dev;
28+
clock_control_subsys_t esc_clk_subsys;
29+
const struct device *pixel_clk_dev;
30+
clock_control_subsys_t pixel_clk_subsys;
31+
uint32_t dphy_ref_freq;
32+
};
33+
34+
static int dsi_mcux_attach(const struct device *dev,
35+
uint8_t channel,
36+
const struct mipi_dsi_device *mdev)
37+
{
38+
const struct mcux_mipi_dsi_config *config = dev->config;
39+
dsi_dphy_config_t dphy_config;
40+
dsi_config_t dsi_config;
41+
uint32_t dphy_bit_clk_freq;
42+
uint32_t dphy_esc_clk_freq;
43+
uint32_t dsi_pixel_clk_freq;
44+
uint32_t bit_width;
45+
46+
DSI_GetDefaultConfig(&dsi_config);
47+
dsi_config.numLanes = mdev->data_lanes;
48+
dsi_config.autoInsertEoTp = config->auto_insert_eotp;
49+
50+
/* Init the DSI module. */
51+
DSI_Init(config->base, &dsi_config);
52+
53+
/* Get the DPHY bit clock frequency */
54+
if (clock_control_get_rate(config->bit_clk_dev,
55+
config->bit_clk_subsys,
56+
&dphy_bit_clk_freq)) {
57+
return -EINVAL;
58+
};
59+
/* Get the DPHY ESC clock frequency */
60+
if (clock_control_get_rate(config->esc_clk_dev,
61+
config->esc_clk_subsys,
62+
&dphy_esc_clk_freq)) {
63+
return -EINVAL;
64+
}
65+
/* Get the Pixel clock frequency */
66+
if (clock_control_get_rate(config->pixel_clk_dev,
67+
config->pixel_clk_subsys,
68+
&dsi_pixel_clk_freq)) {
69+
return -EINVAL;
70+
}
71+
72+
switch (config->dpi_config.pixelPacket) {
73+
case kDSI_PixelPacket16Bit:
74+
bit_width = 16;
75+
break;
76+
case kDSI_PixelPacket18Bit:
77+
__fallthrough;
78+
case kDSI_PixelPacket18BitLoosely:
79+
bit_width = 18;
80+
break;
81+
case kDSI_PixelPacket24Bit:
82+
bit_width = 24;
83+
break;
84+
default:
85+
return -EINVAL; /* Invalid bit width enum value? */
86+
}
87+
/* Init DPHY.
88+
*
89+
* The DPHY bit clock must be fast enough to send out the pixels, it should be
90+
* larger than:
91+
*
92+
* (Pixel clock * bit per output pixel) / number of MIPI data lane
93+
*/
94+
if (((dsi_pixel_clk_freq * bit_width) / mdev->data_lanes) > dphy_bit_clk_freq) {
95+
return -EINVAL;
96+
}
97+
98+
DSI_GetDphyDefaultConfig(&dphy_config, dphy_bit_clk_freq, dphy_esc_clk_freq);
99+
100+
if (config->dphy_ref_freq != 0) {
101+
dphy_bit_clk_freq = DSI_InitDphy(config->base,
102+
&dphy_config, config->dphy_ref_freq);
103+
} else {
104+
/* DPHY PLL is not present, ref clock is unused */
105+
DSI_InitDphy(config->base, &dphy_config, 0);
106+
}
107+
108+
/* Init DPI interface. */
109+
DSI_SetDpiConfig(config->base, &config->dpi_config, mdev->data_lanes,
110+
dsi_pixel_clk_freq, dphy_bit_clk_freq);
111+
112+
imxrt_post_init_display_interface();
113+
114+
return 0;
115+
}
116+
117+
static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel,
118+
struct mipi_dsi_msg *msg)
119+
{
120+
const struct mcux_mipi_dsi_config *config = dev->config;
121+
dsi_transfer_t dsi_xfer = {0};
122+
status_t status;
123+
124+
dsi_xfer.virtualChannel = channel;
125+
dsi_xfer.txDataSize = msg->tx_len;
126+
dsi_xfer.txData = msg->tx_buf;
127+
dsi_xfer.rxDataSize = msg->rx_len;
128+
dsi_xfer.rxData = msg->rx_buf;
129+
130+
switch (msg->type) {
131+
case MIPI_DSI_DCS_READ:
132+
LOG_ERR("DCS Read not yet implemented or used");
133+
return -ENOTSUP;
134+
case MIPI_DSI_DCS_SHORT_WRITE:
135+
dsi_xfer.sendDscCmd = true;
136+
dsi_xfer.dscCmd = msg->cmd;
137+
dsi_xfer.txDataType = kDSI_TxDataDcsShortWrNoParam;
138+
break;
139+
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
140+
__fallthrough;
141+
case MIPI_DSI_DCS_LONG_WRITE:
142+
dsi_xfer.sendDscCmd = true;
143+
dsi_xfer.dscCmd = msg->cmd;
144+
dsi_xfer.txDataType = kDSI_TxDataDcsShortWrOneParam;
145+
break;
146+
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
147+
dsi_xfer.txDataType = kDSI_TxDataGenShortWrNoParam;
148+
break;
149+
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
150+
dsi_xfer.txDataType = kDSI_TxDataGenShortWrOneParam;
151+
break;
152+
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
153+
dsi_xfer.txDataType = kDSI_TxDataGenShortWrTwoParam;
154+
break;
155+
case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
156+
__fallthrough;
157+
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
158+
__fallthrough;
159+
case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
160+
LOG_ERR("Generic Read not yet implemented or used");
161+
return -ENOTSUP;
162+
default:
163+
LOG_ERR("Unsupported message type (%d)", msg->type);
164+
return -ENOTSUP;
165+
}
166+
167+
status = DSI_TransferBlocking(config->base, &dsi_xfer);
168+
169+
if (status != kStatus_Success) {
170+
LOG_ERR("Transmission failed");
171+
return -EIO;
172+
}
173+
174+
if (msg->rx_len != 0) {
175+
/* Return rx_len on a read */
176+
return msg->rx_len;
177+
}
178+
179+
/* Return tx_len on a write */
180+
return msg->tx_len;
181+
182+
}
183+
184+
static struct mipi_dsi_driver_api dsi_mcux_api = {
185+
.attach = dsi_mcux_attach,
186+
.transfer = dsi_mcux_transfer,
187+
};
188+
189+
static int mcux_mipi_dsi_init(const struct device *dev)
190+
{
191+
const struct mcux_mipi_dsi_config *config = dev->config;
192+
193+
imxrt_pre_init_display_interface();
194+
195+
if (!device_is_ready(config->bit_clk_dev) ||
196+
!device_is_ready(config->esc_clk_dev) ||
197+
!device_is_ready(config->pixel_clk_dev)) {
198+
return -ENODEV;
199+
}
200+
return 0;
201+
}
202+
203+
#define MCUX_MIPI_DSI_DEVICE(id) \
204+
static const struct mcux_mipi_dsi_config mipi_dsi_config_##id = { \
205+
.base = (MIPI_DSI_HOST_Type *)DT_INST_REG_ADDR(id), \
206+
.dpi_config = { \
207+
.dpiColorCoding = DT_INST_ENUM_IDX(id, dpi_color_coding), \
208+
.pixelPacket = DT_INST_ENUM_IDX(id, dpi_pixel_packet), \
209+
.videoMode = DT_INST_ENUM_IDX(id, dpi_video_mode), \
210+
.bllpMode = DT_INST_ENUM_IDX(id, dpi_bllp_mode), \
211+
.pixelPayloadSize = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, width), \
212+
.panelHeight = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, height), \
213+
.polarityFlags = DT_INST_PROP_BY_PHANDLE_IDX( \
214+
id, nxp_lcdif, id, polarity) & 0x3, \
215+
.hfp = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, hfp), \
216+
.hbp = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, hbp), \
217+
.hsw = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, hsync), \
218+
.vfp = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, vfp), \
219+
.vbp = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, vbp), \
220+
}, \
221+
.auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp), \
222+
.dphy_ref_freq = DT_INST_PROP_OR(id, dphy_ref_frequency, 0), \
223+
.bit_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, dphy)), \
224+
.bit_clk_subsys = \
225+
(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, dphy, name), \
226+
.esc_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, esc)), \
227+
.esc_clk_subsys = \
228+
(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, esc, name), \
229+
.pixel_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, pixel)), \
230+
.pixel_clk_subsys = \
231+
(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, pixel, name), \
232+
}; \
233+
DEVICE_DT_INST_DEFINE(id, \
234+
&mcux_mipi_dsi_init, \
235+
NULL, \
236+
NULL, \
237+
&mipi_dsi_config_##id, \
238+
POST_KERNEL, \
239+
CONFIG_MIPI_DSI_INIT_PRIORITY, \
240+
&dsi_mcux_api);
241+
242+
DT_INST_FOREACH_STATUS_OKAY(MCUX_MIPI_DSI_DEVICE)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#
2+
# Copyright 2023, NXP
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
description: NXP MCUX MIPI DSI 2L
7+
8+
compatible: "nxp,mipi-dsi-2l"
9+
10+
include: mipi-dsi-host.yaml
11+
12+
properties:
13+
interrupts:
14+
required: true
15+
16+
nxp,lcdif:
17+
type: phandle
18+
required: true
19+
description:
20+
Instance of the LCDIF peripheral.
21+
dpi-color-coding:
22+
type: string
23+
enum:
24+
- "16-bit-config-1"
25+
- "16-bit-config-2"
26+
- "16-bit-config-3"
27+
- "18-bit-config-1"
28+
- "18-bit-config-2"
29+
- "24-bit"
30+
description:
31+
MIPI DPI interface color coding. Sets the distribution of RGB bits within
32+
the 24-bit d bus, as specified by the DPI specification.
33+
34+
dpi-pixel-packet:
35+
type: string
36+
enum:
37+
- "16-bit"
38+
- "18-bit"
39+
- "18-bit-loose"
40+
- "24-bit"
41+
description:
42+
MIPI DSI pixel packet type send through DPI interface.
43+
44+
dpi-video-mode:
45+
type: string
46+
enum:
47+
- "non-burst-sync-pulse"
48+
- "non-burst-sync-event"
49+
- "burst"
50+
description:
51+
DPI video mode.
52+
53+
dpi-bllp-mode:
54+
type: string
55+
enum:
56+
- "low-power"
57+
- "blank"
58+
- "null"
59+
description:
60+
Behavior in BLLP (Blanking or Low-Power Interval).
61+
62+
autoinsert-eotp:
63+
type: boolean
64+
description:
65+
Automatically insert an EoTp short packet when switching from HS to LP mode.
66+
67+
dphy-clk-div:
68+
type: int
69+
required: true
70+
description:
71+
MIPI D-PHY clock divider. Must be set to ensure clock frequency is at
72+
least (pixel clock * bits per output pixel) / number of mipi data lanes
73+
74+
dphy-ref-frequency:
75+
type: int
76+
default: 0
77+
description:
78+
Maximum clock speed supported by the device, in Hz. Leave at default
79+
if no DPHY PLL is present

0 commit comments

Comments
 (0)