1 /*
2  * Copyright (c) 2020 Teslabs Engineering S.L.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <soc.h>
9 
10 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
11 #include <zephyr/drivers/pinctrl.h>
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(memc_stm32, CONFIG_MEMC_LOG_LEVEL);
15 
16 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_fmc)
17 #define DT_DRV_COMPAT st_stm32_fmc
18 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_fmc)
19 #define DT_DRV_COMPAT st_stm32h7_fmc
20 #else
21 #error "No compatible FMC devicetree node found"
22 #endif
23 
24 /* This symbol takes the value 1 if one of the device instances */
25 /* is configured in dts with a domain clock */
26 #if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
27 #define STM32_FMC_DOMAIN_CLOCK_SUPPORT 1
28 #else
29 #define STM32_FMC_DOMAIN_CLOCK_SUPPORT 0
30 #endif
31 
32 struct memc_stm32_config {
33 	uint32_t fmc;
34 	const struct stm32_pclken *pclken;
35 	size_t pclk_len;
36 	const struct pinctrl_dev_config *pcfg;
37 };
38 
memc_stm32_init(const struct device * dev)39 static int memc_stm32_init(const struct device *dev)
40 {
41 	const struct memc_stm32_config *config = dev->config;
42 
43 	int r;
44 	const struct device *clk;
45 
46 	/* configure pinmux */
47 	r = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
48 	if (r < 0) {
49 		LOG_ERR("FMC pinctrl setup failed (%d)", r);
50 		return r;
51 	}
52 
53 	/* enable FMC peripheral clock */
54 	clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
55 
56 	if (!device_is_ready(clk)) {
57 		LOG_ERR("clock control device not ready");
58 		return -ENODEV;
59 	}
60 
61 	r = clock_control_on(clk, (clock_control_subsys_t)&config->pclken[0]);
62 	if (r < 0) {
63 		LOG_ERR("Could not initialize FMC clock (%d)", r);
64 		return r;
65 	}
66 
67 	if (IS_ENABLED(STM32_FMC_DOMAIN_CLOCK_SUPPORT) && (config->pclk_len > 1)) {
68 		/* Enable FMC clock source */
69 		r = clock_control_configure(clk, (clock_control_subsys_t)&config->pclken[1], NULL);
70 		if (r < 0) {
71 			LOG_ERR("Could not select FMC clock (%d)", r);
72 			return r;
73 		}
74 	}
75 
76 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_fmc)
77 #if (DT_ENUM_IDX(DT_DRV_INST(0), st_mem_swap) == 1)
78 	/* sdram-sram */
79 	MODIFY_REG(FMC_Bank1_R->BTCR[0], FMC_BCR1_BMAP, FMC_BCR1_BMAP_0);
80 #elif (DT_ENUM_IDX(DT_DRV_INST(0), st_mem_swap) == 2)
81 	/* sdramb2 */
82 	MODIFY_REG(FMC_Bank1_R->BTCR[0], FMC_BCR1_BMAP, FMC_BCR1_BMAP_1);
83 #endif
84 #endif
85 
86 	return 0;
87 }
88 
89 PINCTRL_DT_INST_DEFINE(0);
90 
91 static const struct stm32_pclken pclken[] = STM32_DT_INST_CLOCKS(0);
92 
93 static const struct memc_stm32_config config = {
94 	.fmc = DT_INST_REG_ADDR(0),
95 	.pclken = pclken,
96 	.pclk_len = DT_INST_NUM_CLOCKS(0),
97 	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
98 };
99 
100 DEVICE_DT_INST_DEFINE(0, memc_stm32_init, NULL, NULL,
101 	      &config, POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, NULL);
102