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
dsi_mcux_attach(const struct device * dev,uint8_t channel,const struct mipi_dsi_device * mdev)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
dsi_mcux_transfer(const struct device * dev,uint8_t channel,struct mipi_dsi_msg * msg)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
mcux_mipi_dsi_init(const struct device * dev)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_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \
214 display_timings), vsync_active) ? \
215 kDSI_DpiVsyncActiveHigh : \
216 kDSI_DpiVsyncActiveLow) | \
217 (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \
218 display_timings), hsync_active) ? \
219 kDSI_DpiHsyncActiveHigh : \
220 kDSI_DpiHsyncActiveLow), \
221 .hfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \
222 display_timings), hfront_porch), \
223 .hbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \
224 display_timings), hback_porch), \
225 .hsw = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \
226 display_timings), hsync_len), \
227 .vfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \
228 display_timings), vfront_porch), \
229 .vbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \
230 display_timings), vback_porch), \
231 }, \
232 .auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp), \
233 .dphy_ref_freq = DT_INST_PROP_OR(id, dphy_ref_frequency, 0), \
234 .bit_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, dphy)), \
235 .bit_clk_subsys = \
236 (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, dphy, name), \
237 .esc_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, esc)), \
238 .esc_clk_subsys = \
239 (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, esc, name), \
240 .pixel_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, pixel)), \
241 .pixel_clk_subsys = \
242 (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, pixel, name), \
243 }; \
244 DEVICE_DT_INST_DEFINE(id, \
245 &mcux_mipi_dsi_init, \
246 NULL, \
247 NULL, \
248 &mipi_dsi_config_##id, \
249 POST_KERNEL, \
250 CONFIG_MIPI_DSI_INIT_PRIORITY, \
251 &dsi_mcux_api);
252
253 DT_INST_FOREACH_STATUS_OKAY(MCUX_MIPI_DSI_DEVICE)
254