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