nand_samsung.c revision 1.8 1 /* $NetBSD: nand_samsung.c,v 1.8 2012/11/02 21:38:29 ahoka Exp $ */
2
3 /*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Adam Hoka.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Device specific functions for legacy Samsung NAND chips
34 *
35 * Currently supported:
36 * K9XXG08UXA
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: nand_samsung.c,v 1.8 2012/11/02 21:38:29 ahoka Exp $");
41
42 #include "nand.h"
43 #include "onfi.h"
44
45 enum {
46 NAND_SAMSUNG_PAGEMASK = 0x3,
47 NAND_SAMSUNG_SPAREMASK = 0x1 << 2,
48 NAND_SAMSUNG_BLOCKMASK = 0x3 << 4,
49 NAND_SAMSUNG_BITSMASK = 0x1 << 6
50 };
51
52 enum {
53 NAND_SAMSUNG_PLANENUMMASK = 0x3 << 2,
54 NAND_SAMSUNG_PLANESIZEMASK = 0x7 << 4
55 };
56
57 int
58 nand_read_parameters_samsung(device_t self, struct nand_chip * const chip)
59 {
60 uint8_t mfgrid;
61 uint8_t devid;
62 uint8_t params1;
63 uint8_t params2;
64 uint8_t params3;
65
66 /* Only for Samsung devices, obviously */
67 if (chip->nc_manf_id != NAND_MFR_SAMSUNG) {
68 return 1;
69 }
70
71 nand_select(self, true);
72 nand_command(self, ONFI_READ_ID);
73 nand_address(self, 0x00);
74 nand_read_1(self, &mfgrid);
75 nand_read_1(self, &devid);
76 nand_read_1(self, ¶ms1);
77 nand_read_1(self, ¶ms2);
78 nand_read_1(self, ¶ms3);
79 nand_select(self, false);
80
81 aprint_debug_dev(self,
82 "ID Definition table: 0x%2.x 0x%2.x 0x%2.x 0x%2.x 0x%2.x\n",
83 mfgrid, devid, params1, params2, params3);
84
85 /* K9XXG08UXA */
86 if (devid == 0xdc) {
87 /* From the documentation */
88 chip->nc_addr_cycles_column = 2;
89 chip->nc_addr_cycles_row = 3;
90
91 switch (params2 & NAND_SAMSUNG_PAGEMASK) {
92 case 0x0:
93 chip->nc_page_size = 1024;
94 break;
95 case 0x1:
96 chip->nc_page_size = 2048;
97 break;
98 case 0x2:
99 chip->nc_page_size = 4096;
100 break;
101 case 0x3:
102 chip->nc_page_size = 8192;
103 break;
104 default:
105 KASSERTMSG(false, "ID Data parsing bug detected!");
106 }
107
108 switch ((params2 & NAND_SAMSUNG_BLOCKMASK) >> 4) {
109 case 0x0:
110 chip->nc_block_size = 64 * 1024;
111 break;
112 case 0x1:
113 chip->nc_block_size = 128 * 1024;
114 break;
115 case 0x2:
116 chip->nc_block_size = 256 * 1024;
117 break;
118 case 0x3:
119 chip->nc_block_size = 512 * 1024;
120 break;
121 default:
122 KASSERTMSG(false, "ID Data parsing bug detected!");
123 }
124
125 chip->nc_block_pages = chip->nc_block_size / chip->nc_page_size;
126
127 /* 8/16 bytes per 512 bytes! XXX do i get this right? */
128 switch ((params2 & NAND_SAMSUNG_SPAREMASK) >> 2) {
129 case 0x0:
130 chip->nc_spare_size = 8 * chip->nc_page_size / 512;
131 break;
132 case 0x1:
133 chip->nc_spare_size = 16 * chip->nc_page_size / 512;
134 break;
135 default:
136 KASSERTMSG(false, "ID Data parsing bug detected!");
137 }
138
139 switch ((params2 & NAND_SAMSUNG_BITSMASK) >> 6) {
140 case 0x0:
141 /* its an 8bit chip */
142 break;
143 case 0x1:
144 chip->nc_flags |= NC_BUSWIDTH_16;
145 break;
146 default:
147 KASSERTMSG(false, "ID Data parsing bug detected!");
148 }
149
150 switch ((params3 & NAND_SAMSUNG_PLANENUMMASK) >> 2) {
151 case 0x0:
152 chip->nc_num_luns = 1;
153 break;
154 case 0x1:
155 chip->nc_num_luns = 2;
156 break;
157 case 0x2:
158 chip->nc_num_luns = 4;
159 break;
160 case 0x3:
161 chip->nc_num_luns = 8;
162 break;
163 default:
164 KASSERTMSG(false, "ID Data parsing bug detected!");
165 }
166
167 /* This one reads in megabit for some reason */
168 uint64_t planesize = 0;
169 switch ((params3 & NAND_SAMSUNG_PLANESIZEMASK) >> 4) {
170 case 0x0:
171 planesize = 64 * 1024 * 1024 / 8;
172 break;
173 case 0x1:
174 planesize = 128 * 1024 * 1024 / 8;
175 break;
176 case 0x2:
177 planesize = 256 * 1024 * 1024 / 8;
178 break;
179 case 0x3:
180 planesize = 512 * 1024 * 1024 / 8;
181 break;
182 case 0x4:
183 planesize = 1024 * 1024 * 1024 / 8;
184 break;
185 case 0x5:
186 planesize = 2ul * 1024 * 1024 * 1024 / 8;
187 break;
188 case 0x6:
189 planesize = 4ul * 1024 * 1024 * 1024 / 8;
190 break;
191 case 0x7:
192 planesize = 8ul * 1024 * 1024 * 1024 / 8;
193 break;
194 default:
195 KASSERTMSG(false, "ID Data parsing bug detected!");
196 }
197
198 chip->nc_lun_blocks = planesize / chip->nc_block_size;
199 chip->nc_size = planesize * chip->nc_num_luns;
200
201 aprint_normal_dev(self, "vendor: Samsung, model: K9XXG08UXA\n");
202 } else {
203 return 1;
204 }
205
206 return 0;
207 }
208