openocd: fix SPDX tag format for files .c
[fw/openocd] / src / flash / nand / nuc910.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2010 by Spencer Oliver                                  *
5  *   spen@spen-soft.co.uk                                                  *
6  ***************************************************************************/
7
8 /*
9  * NAND controller interface for Nuvoton NUC910
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include "imp.h"
17 #include "nuc910.h"
18 #include "arm_io.h"
19 #include <target/arm.h>
20
21 struct nuc910_nand_controller {
22         struct arm_nand_data io;
23 };
24
25 static int validate_target_state(struct nand_device *nand)
26 {
27         struct target *target = nand->target;
28
29         if (target->state != TARGET_HALTED) {
30                 LOG_ERROR("Target not halted");
31                 return ERROR_NAND_OPERATION_FAILED;
32         }
33
34         return ERROR_OK;
35 }
36
37 static int nuc910_nand_command(struct nand_device *nand, uint8_t command)
38 {
39         struct target *target = nand->target;
40         int result;
41
42         result = validate_target_state(nand);
43         if (result != ERROR_OK)
44                 return result;
45
46         target_write_u8(target, NUC910_SMCMD, command);
47         return ERROR_OK;
48 }
49
50 static int nuc910_nand_address(struct nand_device *nand, uint8_t address)
51 {
52         struct target *target = nand->target;
53         int result;
54
55         result = validate_target_state(nand);
56         if (result != ERROR_OK)
57                 return result;
58
59         target_write_u32(target, NUC910_SMADDR, ((address & 0xff) | NUC910_SMADDR_EOA));
60         return ERROR_OK;
61 }
62
63 static int nuc910_nand_read(struct nand_device *nand, void *data)
64 {
65         struct target *target = nand->target;
66         int result;
67
68         result = validate_target_state(nand);
69         if (result != ERROR_OK)
70                 return result;
71
72         target_read_u8(target, NUC910_SMDATA, data);
73         return ERROR_OK;
74 }
75
76 static int nuc910_nand_write(struct nand_device *nand, uint16_t data)
77 {
78         struct target *target = nand->target;
79         int result;
80
81         result = validate_target_state(nand);
82         if (result != ERROR_OK)
83                 return result;
84
85         target_write_u8(target, NUC910_SMDATA, data);
86         return ERROR_OK;
87 }
88
89 static int nuc910_nand_read_block_data(struct nand_device *nand,
90                 uint8_t *data, int data_size)
91 {
92         struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
93         int result;
94
95         result = validate_target_state(nand);
96         if (result != ERROR_OK)
97                 return result;
98
99         nuc910_nand->io.chunk_size = nand->page_size;
100
101         /* try the fast way first */
102         result = arm_nandread(&nuc910_nand->io, data, data_size);
103         if (result != ERROR_NAND_NO_BUFFER)
104                 return result;
105
106         /* else do it slowly */
107         while (data_size--)
108                 nuc910_nand_read(nand, data++);
109
110         return ERROR_OK;
111 }
112
113 static int nuc910_nand_write_block_data(struct nand_device *nand,
114                 uint8_t *data, int data_size)
115 {
116         struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
117         int result;
118
119         result = validate_target_state(nand);
120         if (result != ERROR_OK)
121                 return result;
122
123         nuc910_nand->io.chunk_size = nand->page_size;
124
125         /* try the fast way first */
126         result = arm_nandwrite(&nuc910_nand->io, data, data_size);
127         if (result != ERROR_NAND_NO_BUFFER)
128                 return result;
129
130         /* else do it slowly */
131         while (data_size--)
132                 nuc910_nand_write(nand, *data++);
133
134         return ERROR_OK;
135 }
136
137 static int nuc910_nand_reset(struct nand_device *nand)
138 {
139         return nuc910_nand_command(nand, NAND_CMD_RESET);
140 }
141
142 static int nuc910_nand_ready(struct nand_device *nand, int timeout)
143 {
144         struct target *target = nand->target;
145         uint32_t status;
146
147         do {
148                 target_read_u32(target, NUC910_SMISR, &status);
149                 if (status & NUC910_SMISR_RB_)
150                         return 1;
151                 alive_sleep(1);
152         } while (timeout-- > 0);
153
154         return 0;
155 }
156
157 NAND_DEVICE_COMMAND_HANDLER(nuc910_nand_device_command)
158 {
159         struct nuc910_nand_controller *nuc910_nand;
160
161         nuc910_nand = calloc(1, sizeof(struct nuc910_nand_controller));
162         if (!nuc910_nand) {
163                 LOG_ERROR("no memory for nand controller");
164                 return ERROR_NAND_DEVICE_INVALID;
165         }
166
167         nand->controller_priv = nuc910_nand;
168         return ERROR_OK;
169 }
170
171 static int nuc910_nand_init(struct nand_device *nand)
172 {
173         struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
174         struct target *target = nand->target;
175         int bus_width = nand->bus_width ? nand->bus_width : 8;
176         int result;
177
178         result = validate_target_state(nand);
179         if (result != ERROR_OK)
180                 return result;
181
182         /* nuc910 only supports 8bit */
183         if (bus_width != 8) {
184                 LOG_ERROR("nuc910 only supports 8 bit bus width, not %i", bus_width);
185                 return ERROR_NAND_OPERATION_NOT_SUPPORTED;
186         }
187
188         /* inform calling code about selected bus width */
189         nand->bus_width = bus_width;
190
191         nuc910_nand->io.target = target;
192         nuc910_nand->io.data = NUC910_SMDATA;
193         nuc910_nand->io.op = ARM_NAND_NONE;
194
195         /* configure nand controller */
196         target_write_u32(target, NUC910_FMICSR, NUC910_FMICSR_SM_EN);
197         target_write_u32(target, NUC910_SMCSR, 0x010000a8);     /* 2048 page size */
198         target_write_u32(target, NUC910_SMTCR, 0x00010204);
199         target_write_u32(target, NUC910_SMIER, 0x00000000);
200
201         return ERROR_OK;
202 }
203
204 struct nand_flash_controller nuc910_nand_controller = {
205         .name = "nuc910",
206         .command = nuc910_nand_command,
207         .address = nuc910_nand_address,
208         .read_data = nuc910_nand_read,
209         .write_data     = nuc910_nand_write,
210         .write_block_data = nuc910_nand_write_block_data,
211         .read_block_data = nuc910_nand_read_block_data,
212         .nand_ready = nuc910_nand_ready,
213         .reset = nuc910_nand_reset,
214         .nand_device_command = nuc910_nand_device_command,
215         .init = nuc910_nand_init,
216 };