1390a3fb7a7c7de92081bcf4f33247887f5448a1
[fw/openocd] / src / flash / s3c2440_nand.c
1 /* src/flash/s3c2440_nand.c\r
2  *\r
3  * S3C2440 OpenOCD NAND Flash controller support.\r
4  *\r
5  * Copyright 2007,2008 Ben Dooks <ben@fluff.org>\r
6  *\r
7  * This program is free software; you can redistribute it and/or modify\r
8  * it under the terms of the GNU General Public License as published by\r
9  * the Free Software Foundation; either version 2 of the License, or\r
10  * (at your option) any later version.\r
11  *\r
12  * Many thanks to Simtec Electronics for sponsoring this work.\r
13  */\r
14 \r
15 #ifdef HAVE_CONFIG_H\r
16 #include "config.h"\r
17 #endif\r
18 \r
19 #include "replacements.h"\r
20 #include "log.h"\r
21 \r
22 #include <stdlib.h>\r
23 #include <string.h>\r
24 \r
25 #include "nand.h"\r
26 #include "s3c24xx_nand.h"\r
27 #include "target.h"\r
28 \r
29 int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);\r
30 int s3c2440_init(struct nand_device_s *device);\r
31 int s3c2440_nand_ready(struct nand_device_s *device, int timeout);\r
32 \r
33 nand_flash_controller_t s3c2440_nand_controller =\r
34 {\r
35         .name                   = "s3c2440",\r
36         .nand_device_command    = s3c2440_nand_device_command,\r
37         .register_commands      = s3c24xx_register_commands,\r
38         .init                   = s3c2440_init,\r
39         .reset                  = s3c24xx_reset,\r
40         .command                = s3c24xx_command,\r
41         .address                = s3c24xx_address,\r
42         .write_data             = s3c24xx_write_data,\r
43         .read_data              = s3c24xx_read_data,\r
44         .write_page             = s3c24xx_write_page,\r
45         .read_page              = s3c24xx_read_page,\r
46         .write_block_data       = s3c2440_write_block_data,\r
47         .read_block_data        = s3c2440_read_block_data,\r
48         .controller_ready       = s3c24xx_controller_ready,\r
49         .nand_ready             = s3c2440_nand_ready,\r
50 };\r
51 \r
52 int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,\r
53                                 char **args, int argc,\r
54                                 struct nand_device_s *device)\r
55 {\r
56         s3c24xx_nand_controller_t *info;\r
57         \r
58         info = s3c24xx_nand_device_command(cmd_ctx, cmd, args, argc, device);\r
59         if (info == NULL) {\r
60                 return ERROR_NAND_DEVICE_INVALID;\r
61         }\r
62 \r
63         /* fill in the address fields for the core device */\r
64         info->cmd = S3C2440_NFCMD;\r
65         info->addr = S3C2440_NFADDR;\r
66         info->data = S3C2440_NFDATA;\r
67         info->nfstat = S3C2440_NFSTAT;\r
68                 \r
69         return ERROR_OK;\r
70 }\r
71 \r
72 int s3c2440_init(struct nand_device_s *device)\r
73 {\r
74         s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;\r
75         target_t *target = s3c24xx_info->target;\r
76         u32 version;\r
77 \r
78         target_write_u32(target, S3C2410_NFCONF,\r
79                          S3C2440_NFCONF_TACLS(3) |\r
80                          S3C2440_NFCONF_TWRPH0(7) |\r
81                          S3C2440_NFCONF_TWRPH1(7));\r
82 \r
83         target_write_u32(target, S3C2440_NFCONT,\r
84                          S3C2440_NFCONT_INITECC | S3C2440_NFCONT_ENABLE);\r
85 \r
86         return ERROR_OK;\r
87 }\r
88 \r
89 int s3c2440_nand_ready(struct nand_device_s *device, int timeout)\r
90 {\r
91         s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;\r
92         target_t *target = s3c24xx_info->target;\r
93         u8 status;\r
94 \r
95         if (target->state != TARGET_HALTED) {\r
96                 ERROR("target must be halted to use S3C24XX NAND flash controller");\r
97                 return ERROR_NAND_OPERATION_FAILED;\r
98         }\r
99         \r
100         do {            \r
101                 target_read_u8(target, s3c24xx_info->nfstat, &status);\r
102                 \r
103                 if (status & S3C2440_NFSTAT_READY)\r
104                         return 1;\r
105 \r
106                 usleep(1000);\r
107         } while (timeout-- > 0);\r
108 \r
109 \r
110         return 0;\r
111 }\r
112 \r
113 /* use the fact we can read/write 4 bytes in one go via a single 32bit op */\r
114 \r
115 int s3c2440_read_block_data(struct nand_device_s *device, u8 *data, int data_size)\r
116 {\r
117         s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;\r
118         target_t *target = s3c24xx_info->target;\r
119         u32 nfdata = s3c24xx_info->data;\r
120         u32 tmp;\r
121 \r
122         INFO("%s: reading data: %p, %p, %d\n", __func__, device, data, data_size);\r
123 \r
124         if (target->state != TARGET_HALTED) {\r
125                 ERROR("target must be halted to use S3C24XX NAND flash controller");\r
126                 return ERROR_NAND_OPERATION_FAILED;\r
127         }\r
128 \r
129         while (data_size >= 4) {          \r
130                 target_read_u32(target, nfdata, &tmp);\r
131 \r
132                 data[0] = tmp;\r
133                 data[1] = tmp >> 8;\r
134                 data[2] = tmp >> 16;\r
135                 data[3] = tmp >> 24;\r
136 \r
137                 data_size -= 4;\r
138                 data += 4;\r
139         }\r
140 \r
141         while (data_size > 0) {\r
142                 target_read_u8(target, nfdata, data);\r
143 \r
144                 data_size -= 1;\r
145                 data += 1;\r
146         }\r
147 \r
148         return ERROR_OK;\r
149 }\r
150 \r
151 int s3c2440_write_block_data(struct nand_device_s *device, u8 *data, int data_size)\r
152 {\r
153         s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;\r
154         target_t *target = s3c24xx_info->target;\r
155         u32 nfdata = s3c24xx_info->data;\r
156         u32 tmp;\r
157 \r
158         if (target->state != TARGET_HALTED) {\r
159                 ERROR("target must be halted to use S3C24XX NAND flash controller");\r
160                 return ERROR_NAND_OPERATION_FAILED;\r
161         }\r
162 \r
163         while (data_size >= 4) {          \r
164                 tmp = le_to_h_u32(data);\r
165                 target_write_u32(target, nfdata, tmp);\r
166 \r
167                 data_size -= 4;\r
168                 data += 4;\r
169         }\r
170 \r
171         while (data_size > 0) {\r
172                 target_write_u8(target, nfdata, *data);\r
173 \r
174                 data_size -= 1;\r
175                 data += 1;\r
176         }\r
177 \r
178         return ERROR_OK;\r
179 }\r