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