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 config->port)) {
118 LOG_ERR("Could not set device configuration");
119 return -EINVAL;
120 }
121
122 if (memc_flexspi_update_lut(data->controller, 0,
123 (const uint32_t *) memc_flexspi_w956a8mbya_lut,
124 sizeof(memc_flexspi_w956a8mbya_lut) / 4)) {
125 LOG_ERR("Could not update lut");
126 return -EINVAL;
127 }
128
129 memc_flexspi_reset(data->controller);
130
131 if (memc_flexspi_w956a8mbya_get_vendor_id(dev, &vendor_id)) {
132 LOG_ERR("Could not read vendor id");
133 return -EIO;
134 }
135 LOG_DBG("Vendor id: 0x%0x", vendor_id);
136
137 return 0;
138 }
139
140 #define CONCAT3(x, y, z) x ## y ## z
141
142 #define CS_INTERVAL_UNIT(unit) \
143 CONCAT3(kFLEXSPI_CsIntervalUnit, unit, SckCycle)
144
145 #define AHB_WRITE_WAIT_UNIT(unit) \
146 CONCAT3(kFLEXSPI_AhbWriteWaitUnit, unit, AhbCycle)
147
148 #define MEMC_FLEXSPI_DEVICE_CONFIG(n) \
149 { \
150 .flexspiRootClk = DT_INST_PROP(n, spi_max_frequency), \
151 .isSck2Enabled = false, \
152 .flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \
153 .CSIntervalUnit = \
154 CS_INTERVAL_UNIT( \
155 DT_INST_PROP(n, cs_interval_unit)), \
156 .CSInterval = DT_INST_PROP(n, cs_interval), \
157 .CSHoldTime = DT_INST_PROP(n, cs_hold_time), \
158 .CSSetupTime = DT_INST_PROP(n, cs_setup_time), \
159 .dataValidTime = DT_INST_PROP(n, data_valid_time), \
160 .columnspace = DT_INST_PROP(n, column_space), \
161 .enableWordAddress = DT_INST_PROP(n, word_addressable), \
162 .AWRSeqIndex = WRITE_DATA, \
163 .AWRSeqNumber = 1, \
164 .ARDSeqIndex = READ_DATA, \
165 .ARDSeqNumber = 1, \
166 .AHBWriteWaitUnit = \
167 AHB_WRITE_WAIT_UNIT( \
168 DT_INST_PROP(n, ahb_write_wait_unit)), \
169 .AHBWriteWaitInterval = \
170 DT_INST_PROP(n, ahb_write_wait_interval), \
171 .enableWriteMask = true, \
172 } \
173
174 #define MEMC_FLEXSPI_W956A8MBYA(n) \
175 static const struct memc_flexspi_w956a8mbya_config \
176 memc_flexspi_w956a8mbya_config_##n = { \
177 .port = DT_INST_REG_ADDR(n), \
178 .config = MEMC_FLEXSPI_DEVICE_CONFIG(n), \
179 }; \
180 \
181 static struct memc_flexspi_w956a8mbya_data \
182 memc_flexspi_w956a8mbya_data_##n = { \
183 .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \
184 }; \
185 \
186 DEVICE_DT_INST_DEFINE(n, \
187 memc_flexspi_w956a8mbya_init, \
188 NULL, \
189 &memc_flexspi_w956a8mbya_data_##n, \
190 &memc_flexspi_w956a8mbya_config_##n, \
191 POST_KERNEL, \
192 CONFIG_MEMC_INIT_PRIORITY, \
193 NULL);
194
195 DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI_W956A8MBYA)
196