1 /*
2 * Copyright (c) 2023, ithinx GmbH
3 * Copyright (c) 2023, Tonies GmbH
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /*
9 * Based on memc_mcux_flexspi_s27ks0641, which is: Copyright 2021 Basalte bv
10 */
11
12 #define DT_DRV_COMPAT nxp_imx_flexspi_w956a8mbya
13
14 #include <zephyr/logging/log.h>
15 #include <zephyr/sys/util.h>
16
17 #include "memc_mcux_flexspi.h"
18
19
20 LOG_MODULE_REGISTER(memc_flexspi_w956a8mbya, CONFIG_MEMC_LOG_LEVEL);
21
22 enum {
23 READ_DATA,
24 WRITE_DATA,
25 READ_REG,
26 WRITE_REG,
27 };
28
29 struct memc_flexspi_w956a8mbya_config {
30 flexspi_port_t port;
31 flexspi_device_config_t config;
32 };
33
34 /* Device variables used in critical sections should be in this structure */
35 struct memc_flexspi_w956a8mbya_data {
36 const struct device *controller;
37 };
38
39 static const uint32_t memc_flexspi_w956a8mbya_lut[][4] = {
40 /* Read Data */
41 [READ_DATA] = {
42 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0,
43 kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
44 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10,
45 kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x07),
46 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04,
47 kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
48 },
49
50 /* Write Data */
51 [WRITE_DATA] = {
52 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20,
53 kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
54 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10,
55 kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x07),
56 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04,
57 kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
58 },
59
60 /* Read Register */
61 [READ_REG] = {
62 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xE0,
63 kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
64 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10,
65 kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x07),
66 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04,
67 kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
68 },
69
70 /* Write Register */
71 [WRITE_REG] = {
72 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x60,
73 kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
74 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10,
75 kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04),
76 },
77 };
78
memc_flexspi_w956a8mbya_get_vendor_id(const struct device * dev,uint16_t * vendor_id)79 static int memc_flexspi_w956a8mbya_get_vendor_id(const struct device *dev,
80 uint16_t *vendor_id)
81 {
82 const struct memc_flexspi_w956a8mbya_config *config = dev->config;
83 struct memc_flexspi_w956a8mbya_data *data = dev->data;
84 uint32_t buffer = 0;
85 int ret;
86
87 flexspi_transfer_t transfer = {
88 .deviceAddress = 0,
89 .port = config->port,
90 .cmdType = kFLEXSPI_Read,
91 .SeqNumber = 1,
92 .seqIndex = READ_REG,
93 .data = &buffer,
94 .dataSize = 4,
95 };
96
97 LOG_DBG("Reading id");
98
99 ret = memc_flexspi_transfer(data->controller, &transfer);
100 *vendor_id = buffer & 0xffff;
101
102 return ret;
103 }
104
memc_flexspi_w956a8mbya_init(const struct device * dev)105 static int memc_flexspi_w956a8mbya_init(const struct device *dev)
106 {
107 const struct memc_flexspi_w956a8mbya_config *config = dev->config;
108 struct memc_flexspi_w956a8mbya_data *data = dev->data;
109 uint16_t vendor_id;
110
111 if (!device_is_ready(data->controller)) {
112 LOG_ERR("Controller device not ready");
113 return -ENODEV;
114 }
115
116 if (memc_flexspi_set_device_config(data->controller, &config->config,
117 (const uint32_t *) memc_flexspi_w956a8mbya_lut,
118 sizeof(memc_flexspi_w956a8mbya_lut) / MEMC_FLEXSPI_CMD_SIZE,
119 config->port)) {
120 LOG_ERR("Could not set device configuration");
121 return -EINVAL;
122 }
123
124 memc_flexspi_reset(data->controller);
125
126 if (memc_flexspi_w956a8mbya_get_vendor_id(dev, &vendor_id)) {
127 LOG_ERR("Could not read vendor id");
128 return -EIO;
129 }
130 LOG_DBG("Vendor id: 0x%0x", vendor_id);
131
132 return 0;
133 }
134
135 #define CONCAT3(x, y, z) x ## y ## z
136
137 #define CS_INTERVAL_UNIT(unit) \
138 CONCAT3(kFLEXSPI_CsIntervalUnit, unit, SckCycle)
139
140 #define AHB_WRITE_WAIT_UNIT(unit) \
141 CONCAT3(kFLEXSPI_AhbWriteWaitUnit, unit, AhbCycle)
142
143 #define MEMC_FLEXSPI_DEVICE_CONFIG(n) \
144 { \
145 .flexspiRootClk = DT_INST_PROP(n, spi_max_frequency), \
146 .isSck2Enabled = false, \
147 .flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \
148 .CSIntervalUnit = \
149 CS_INTERVAL_UNIT( \
150 DT_INST_PROP(n, cs_interval_unit)), \
151 .CSInterval = DT_INST_PROP(n, cs_interval), \
152 .CSHoldTime = DT_INST_PROP(n, cs_hold_time), \
153 .CSSetupTime = DT_INST_PROP(n, cs_setup_time), \
154 .dataValidTime = DT_INST_PROP(n, data_valid_time), \
155 .columnspace = DT_INST_PROP(n, column_space), \
156 .enableWordAddress = DT_INST_PROP(n, word_addressable), \
157 .AWRSeqIndex = WRITE_DATA, \
158 .AWRSeqNumber = 1, \
159 .ARDSeqIndex = READ_DATA, \
160 .ARDSeqNumber = 1, \
161 .AHBWriteWaitUnit = \
162 AHB_WRITE_WAIT_UNIT( \
163 DT_INST_PROP(n, ahb_write_wait_unit)), \
164 .AHBWriteWaitInterval = \
165 DT_INST_PROP(n, ahb_write_wait_interval), \
166 .enableWriteMask = true, \
167 } \
168
169 #define MEMC_FLEXSPI_W956A8MBYA(n) \
170 static const struct memc_flexspi_w956a8mbya_config \
171 memc_flexspi_w956a8mbya_config_##n = { \
172 .port = DT_INST_REG_ADDR(n), \
173 .config = MEMC_FLEXSPI_DEVICE_CONFIG(n), \
174 }; \
175 \
176 static struct memc_flexspi_w956a8mbya_data \
177 memc_flexspi_w956a8mbya_data_##n = { \
178 .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \
179 }; \
180 \
181 DEVICE_DT_INST_DEFINE(n, \
182 memc_flexspi_w956a8mbya_init, \
183 NULL, \
184 &memc_flexspi_w956a8mbya_data_##n, \
185 &memc_flexspi_w956a8mbya_config_##n, \
186 POST_KERNEL, \
187 CONFIG_MEMC_INIT_PRIORITY, \
188 NULL);
189
190 DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI_W956A8MBYA)
191