1 /*
2  * Copyright (c) 2024 Bootlin
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT st_stm32_fmc_mipi_dbi
8 
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/mipi_dbi.h>
11 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
12 #include <zephyr/sys/barrier.h>
13 #include <zephyr/sys/sys_io.h>
14 #include <zephyr/sys/byteorder.h>
15 
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(mipi_dbi_stm32_fmc, CONFIG_MIPI_DBI_LOG_LEVEL);
18 
19 struct mipi_dbi_stm32_fmc_config {
20 	/* Reset GPIO */
21 	const struct gpio_dt_spec reset;
22 	/* Power GPIO */
23 	const struct gpio_dt_spec power;
24 	mem_addr_t register_addr;
25 	mem_addr_t data_addr;
26 	uint32_t fmc_address_setup_time;
27 	uint32_t fmc_data_setup_time;
28 	uint32_t fmc_memory_width;
29 };
30 
31 struct mipi_dbi_stm32_fmc_data {
32 	const struct mipi_dbi_config *dbi_config;
33 };
34 
mipi_dbi_stm32_fmc_check_config(const struct device * dev,const struct mipi_dbi_config * dbi_config)35 int mipi_dbi_stm32_fmc_check_config(const struct device *dev,
36 				    const struct mipi_dbi_config *dbi_config)
37 {
38 	const struct mipi_dbi_stm32_fmc_config *config = dev->config;
39 	struct mipi_dbi_stm32_fmc_data *data = dev->data;
40 	uint32_t fmc_write_cycles;
41 
42 	if (data->dbi_config == dbi_config) {
43 		return 0;
44 	}
45 
46 	if (dbi_config->mode != MIPI_DBI_MODE_8080_BUS_16_BIT) {
47 		LOG_ERR("Only support Intel 8080 16-bits");
48 		return -ENOTSUP;
49 	}
50 
51 	if (config->fmc_memory_width != FMC_NORSRAM_MEM_BUS_WIDTH_16) {
52 		LOG_ERR("Only supports 16-bit bus width");
53 		return -EINVAL;
54 	}
55 
56 	uint32_t hclk_freq =
57 		STM32_AHB_PRESCALER * DT_PROP(STM32_CLOCK_CONTROL_NODE, clock_frequency);
58 
59 	/* According to the FMC documentation*/
60 	fmc_write_cycles =
61 		((config->fmc_address_setup_time + 1) + (config->fmc_data_setup_time + 1)) * 1;
62 
63 	if (hclk_freq / fmc_write_cycles > dbi_config->config.frequency) {
64 		LOG_ERR("Frequency is too high for the display controller");
65 		return -EINVAL;
66 	}
67 
68 	data->dbi_config = dbi_config;
69 	return 0;
70 }
71 
mipi_dbi_stm32_fmc_command_write(const struct device * dev,const struct mipi_dbi_config * dbi_config,uint8_t cmd,const uint8_t * data_buf,size_t len)72 int mipi_dbi_stm32_fmc_command_write(const struct device *dev,
73 				     const struct mipi_dbi_config *dbi_config, uint8_t cmd,
74 				     const uint8_t *data_buf, size_t len)
75 {
76 	const struct mipi_dbi_stm32_fmc_config *config = dev->config;
77 	int ret;
78 	size_t i;
79 
80 	ret = mipi_dbi_stm32_fmc_check_config(dev, dbi_config);
81 	if (ret < 0) {
82 		return ret;
83 	}
84 
85 	sys_write16(cmd, config->register_addr);
86 	if (IS_ENABLED(CONFIG_MIPI_DBI_STM32_FMC_MEM_BARRIER)) {
87 		barrier_dsync_fence_full();
88 	}
89 
90 	for (i = 0U; i < len; i++) {
91 		sys_write16((uint16_t)data_buf[i], config->data_addr);
92 		if (IS_ENABLED(CONFIG_MIPI_DBI_STM32_FMC_MEM_BARRIER)) {
93 			barrier_dsync_fence_full();
94 		}
95 	}
96 
97 	return 0;
98 }
99 
mipi_dbi_stm32_fmc_write_display(const struct device * dev,const struct mipi_dbi_config * dbi_config,const uint8_t * framebuf,struct display_buffer_descriptor * desc,enum display_pixel_format pixfmt)100 static int mipi_dbi_stm32_fmc_write_display(const struct device *dev,
101 					    const struct mipi_dbi_config *dbi_config,
102 					    const uint8_t *framebuf,
103 					    struct display_buffer_descriptor *desc,
104 					    enum display_pixel_format pixfmt)
105 {
106 	const struct mipi_dbi_stm32_fmc_config *config = dev->config;
107 	size_t i;
108 	int ret;
109 
110 	ret = mipi_dbi_stm32_fmc_check_config(dev, dbi_config);
111 	if (ret < 0) {
112 		return ret;
113 	}
114 
115 	for (i = 0U; i < desc->buf_size; i += 2) {
116 		sys_write16(sys_get_le16(&framebuf[i]), config->data_addr);
117 		if (IS_ENABLED(CONFIG_MIPI_DBI_STM32_FMC_MEM_BARRIER)) {
118 			barrier_dsync_fence_full();
119 		}
120 	}
121 
122 	return 0;
123 }
124 
mipi_dbi_stm32_fmc_reset(const struct device * dev,k_timeout_t delay)125 static int mipi_dbi_stm32_fmc_reset(const struct device *dev, k_timeout_t delay)
126 {
127 	const struct mipi_dbi_stm32_fmc_config *config = dev->config;
128 	int ret;
129 
130 	if (config->reset.port == NULL) {
131 		return -ENOTSUP;
132 	}
133 
134 	ret = gpio_pin_set_dt(&config->reset, 1);
135 	if (ret < 0) {
136 		return ret;
137 	}
138 
139 	k_sleep(delay);
140 
141 	return gpio_pin_set_dt(&config->reset, 0);
142 }
143 
mipi_dbi_stm32_fmc_init(const struct device * dev)144 static int mipi_dbi_stm32_fmc_init(const struct device *dev)
145 {
146 	const struct mipi_dbi_stm32_fmc_config *config = dev->config;
147 
148 	if (config->reset.port) {
149 		if (!gpio_is_ready_dt(&config->reset)) {
150 			LOG_ERR("Reset GPIO device not ready");
151 			return -ENODEV;
152 		}
153 
154 		if (gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE)) {
155 			LOG_ERR("Couldn't configure reset pin");
156 			return -EIO;
157 		}
158 	}
159 
160 	if (config->power.port) {
161 		if (!gpio_is_ready_dt(&config->power)) {
162 			LOG_ERR("Power GPIO device not ready");
163 			return -ENODEV;
164 		}
165 
166 		if (gpio_pin_configure_dt(&config->power, GPIO_OUTPUT)) {
167 			LOG_ERR("Couldn't configure power pin");
168 			return -EIO;
169 		}
170 	}
171 
172 	return 0;
173 }
174 
175 static DEVICE_API(mipi_dbi, mipi_dbi_stm32_fmc_driver_api) = {
176 	.reset = mipi_dbi_stm32_fmc_reset,
177 	.command_write = mipi_dbi_stm32_fmc_command_write,
178 	.write_display = mipi_dbi_stm32_fmc_write_display,
179 };
180 
181 #define MIPI_DBI_FMC_GET_ADDRESS(n) _CONCAT(FMC_BANK1_,                                            \
182 					UTIL_INC(DT_REG_ADDR_RAW(DT_INST_PARENT(n))))
183 
184 #define MIPI_DBI_FMC_GET_DATA_ADDRESS(n)                                                           \
185 	MIPI_DBI_FMC_GET_ADDRESS(n) + (1 << (DT_INST_PROP(n, register_select_pin) + 1))
186 
187 #define MIPI_DBI_STM32_FMC_INIT(n)                                                                 \
188 	static const struct mipi_dbi_stm32_fmc_config mipi_dbi_stm32_fmc_config_##n = {            \
189 		.reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {}),                             \
190 		.power = GPIO_DT_SPEC_INST_GET_OR(n, power_gpios, {}),                             \
191 		.register_addr = MIPI_DBI_FMC_GET_ADDRESS(n),                                      \
192 		.data_addr = MIPI_DBI_FMC_GET_DATA_ADDRESS(n),                                     \
193 		.fmc_address_setup_time = DT_PROP_BY_IDX(DT_INST_PARENT(n), st_timing, 0),         \
194 		.fmc_data_setup_time = DT_PROP_BY_IDX(DT_INST_PARENT(n), st_timing, 2),            \
195 		.fmc_memory_width = DT_PROP_BY_IDX(DT_INST_PARENT(n), st_control, 2),              \
196 	};                                                                                         \
197                                                                                                    \
198 	static struct mipi_dbi_stm32_fmc_data mipi_dbi_stm32_fmc_data_##n;                         \
199                                                                                                    \
200 	DEVICE_DT_INST_DEFINE(n, mipi_dbi_stm32_fmc_init, NULL, &mipi_dbi_stm32_fmc_data_##n,      \
201 			      &mipi_dbi_stm32_fmc_config_##n, POST_KERNEL,                         \
202 			      CONFIG_MIPI_DBI_INIT_PRIORITY, &mipi_dbi_stm32_fmc_driver_api);
203 
204 DT_INST_FOREACH_STATUS_OKAY(MIPI_DBI_STM32_FMC_INIT)
205