1 1.5 thorpej /* $NetBSD: omap2_nand.c,v 1.5 2021/08/07 16:18:46 thorpej Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2010 Department of Software Engineering, 5 1.1 jmcneill * University of Szeged, Hungary 6 1.1 jmcneill * Copyright (c) 2010 Adam Hoka <ahoka (at) NetBSD.org> 7 1.1 jmcneill * All rights reserved. 8 1.1 jmcneill * 9 1.1 jmcneill * This code is derived from software contributed to The NetBSD Foundation 10 1.1 jmcneill * by the Department of Software Engineering, University of Szeged, Hungary 11 1.1 jmcneill * 12 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 13 1.1 jmcneill * modification, are permitted provided that the following conditions 14 1.1 jmcneill * are met: 15 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 16 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 17 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 19 1.1 jmcneill * documentation and/or other materials provided with the distribution. 20 1.1 jmcneill * 21 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 jmcneill * SUCH DAMAGE. 32 1.1 jmcneill */ 33 1.1 jmcneill 34 1.1 jmcneill /* Device driver for the NAND controller found in Texas Instruments OMAP2 35 1.1 jmcneill * and later SOCs. 36 1.1 jmcneill */ 37 1.1 jmcneill 38 1.1 jmcneill #include <sys/cdefs.h> 39 1.5 thorpej __KERNEL_RCSID(0, "$NetBSD: omap2_nand.c,v 1.5 2021/08/07 16:18:46 thorpej Exp $"); 40 1.1 jmcneill 41 1.1 jmcneill /* TODO move to opt_* */ 42 1.1 jmcneill #undef OMAP2_NAND_HARDWARE_ECC 43 1.1 jmcneill 44 1.1 jmcneill #include <sys/param.h> 45 1.1 jmcneill #include <sys/systm.h> 46 1.1 jmcneill #include <sys/cdefs.h> 47 1.1 jmcneill #include <sys/device.h> 48 1.1 jmcneill 49 1.1 jmcneill #include <sys/bus.h> 50 1.1 jmcneill 51 1.1 jmcneill #include <arm/ti/omap2_gpmcreg.h> 52 1.1 jmcneill 53 1.1 jmcneill #include <dev/nand/nand.h> 54 1.1 jmcneill #include <dev/nand/onfi.h> 55 1.1 jmcneill 56 1.1 jmcneill #include <dev/fdt/fdtvar.h> 57 1.1 jmcneill 58 1.1 jmcneill extern struct flash_interface nand_flash_if; 59 1.1 jmcneill extern int flash_print(void *, const char *); 60 1.1 jmcneill 61 1.1 jmcneill /* GPMC_STATUS */ 62 1.1 jmcneill #define WAIT0 __BIT(8) /* active low */ 63 1.1 jmcneill 64 1.1 jmcneill /* GPMC_ECC_CONTROL */ 65 1.1 jmcneill #define ECCCLEAR __BIT(8) 66 1.1 jmcneill #define ECCPOINTER __BITS(3,0) 67 1.1 jmcneill 68 1.1 jmcneill /* GPMC_ECC_CONFIG */ 69 1.1 jmcneill #define ECCALGORITHM __BIT(16) 70 1.1 jmcneill #define ECCCS __BITS(3,1) 71 1.1 jmcneill #define ECC16B __BIT(7) 72 1.1 jmcneill #define ECCENABLE __BIT(0) 73 1.1 jmcneill /* GPMC_ECC_SIZE_CONFIG */ 74 1.1 jmcneill #define ECCSIZE1 __BITS(29,22) 75 1.1 jmcneill 76 1.1 jmcneill /* GPMC_CONFIG1_i */ 77 1.1 jmcneill #define DEVICETYPE __BITS(11,10) 78 1.1 jmcneill #define DEVICESIZE __BITS(13,12) 79 1.1 jmcneill 80 1.1 jmcneill #define MASKEDINT(mask, integer) ((integer) << (ffs(mask) - 1) & mask) 81 1.1 jmcneill 82 1.1 jmcneill /* NAND status register */ 83 1.1 jmcneill #define NAND_WP_BIT __BIT(4) 84 1.1 jmcneill 85 1.1 jmcneill static int omap2_nand_match(device_t, cfdata_t, void *); 86 1.1 jmcneill static void omap2_nand_attach(device_t, device_t, void *); 87 1.1 jmcneill 88 1.1 jmcneill static void omap2_nand_command(device_t self, uint8_t command); 89 1.1 jmcneill static void omap2_nand_address(device_t self, uint8_t address); 90 1.1 jmcneill static void omap2_nand_busy(device_t self); 91 1.1 jmcneill static void omap2_nand_read_1(device_t self, uint8_t *data); 92 1.1 jmcneill static void omap2_nand_write_1(device_t self, uint8_t data); 93 1.1 jmcneill static void omap2_nand_read_2(device_t self, uint16_t *data); 94 1.1 jmcneill static void omap2_nand_write_2(device_t self, uint16_t data); 95 1.1 jmcneill bool omap2_nand_isbusy(device_t self); 96 1.1 jmcneill static void omap2_nand_read_buf_1(device_t self, void *buf, size_t len); 97 1.1 jmcneill static void omap2_nand_read_buf_2(device_t self, void *buf, size_t len); 98 1.1 jmcneill static void omap2_nand_write_buf_1(device_t self, const void *buf, size_t len); 99 1.1 jmcneill static void omap2_nand_write_buf_2(device_t self, const void *buf, size_t len); 100 1.1 jmcneill 101 1.1 jmcneill #ifdef OMAP2_NAND_HARDWARE_ECC 102 1.1 jmcneill static int omap2_nand_ecc_init(device_t self); 103 1.1 jmcneill static int omap2_nand_ecc_prepare(device_t self, int mode); 104 1.1 jmcneill static int omap2_nand_ecc_compute(device_t self, const uint8_t *data, uint8_t *ecc); 105 1.1 jmcneill static int omap2_nand_ecc_correct(device_t self, uint8_t *data, const uint8_t *oldecc, 106 1.1 jmcneill const uint8_t *calcecc); 107 1.1 jmcneill #endif 108 1.1 jmcneill 109 1.1 jmcneill struct omap2_nand_softc { 110 1.1 jmcneill device_t sc_dev; 111 1.1 jmcneill device_t sc_nanddev; 112 1.1 jmcneill 113 1.1 jmcneill int sc_cs; 114 1.1 jmcneill int sc_buswidth; /* 0: 8bit, 1: 16bit */ 115 1.1 jmcneill 116 1.1 jmcneill struct nand_interface sc_nand_if; 117 1.1 jmcneill 118 1.1 jmcneill bus_space_tag_t sc_iot; 119 1.1 jmcneill bus_space_handle_t sc_ioh; 120 1.1 jmcneill bus_space_handle_t sc_gpmc_ioh; 121 1.1 jmcneill 122 1.1 jmcneill bus_size_t sc_cmd_reg; 123 1.1 jmcneill bus_size_t sc_addr_reg; 124 1.1 jmcneill bus_size_t sc_data_reg; 125 1.1 jmcneill }; 126 1.1 jmcneill 127 1.3 thorpej static const struct device_compatible_entry compat_data[] = { 128 1.3 thorpej { .compat = "ti,omap2-nand" }, 129 1.3 thorpej { .compat = "ti,omap2-onenand" }, 130 1.3 thorpej DEVICE_COMPAT_EOL 131 1.1 jmcneill }; 132 1.1 jmcneill 133 1.1 jmcneill CFATTACH_DECL_NEW(omapnand, sizeof(struct omap2_nand_softc), omap2_nand_match, 134 1.1 jmcneill omap2_nand_attach, NULL, NULL); 135 1.1 jmcneill 136 1.1 jmcneill static inline uint32_t 137 1.1 jmcneill gpmc_register_read(struct omap2_nand_softc *sc, bus_size_t reg) 138 1.1 jmcneill { 139 1.1 jmcneill return bus_space_read_4(sc->sc_iot, sc->sc_gpmc_ioh, reg); 140 1.1 jmcneill } 141 1.1 jmcneill 142 1.1 jmcneill static inline void 143 1.1 jmcneill gpmc_register_write(struct omap2_nand_softc *sc, bus_size_t reg, const uint32_t data) 144 1.1 jmcneill { 145 1.1 jmcneill bus_space_write_4(sc->sc_iot, sc->sc_gpmc_ioh, reg, data); 146 1.1 jmcneill } 147 1.1 jmcneill 148 1.1 jmcneill static void 149 1.1 jmcneill omap2_nand_command(device_t self, uint8_t command) 150 1.1 jmcneill { 151 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 152 1.1 jmcneill 153 1.1 jmcneill bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_cmd_reg, command); 154 1.1 jmcneill }; 155 1.1 jmcneill 156 1.1 jmcneill static void 157 1.1 jmcneill omap2_nand_address(device_t self, uint8_t address) 158 1.1 jmcneill { 159 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 160 1.1 jmcneill 161 1.1 jmcneill bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_addr_reg, address); 162 1.1 jmcneill }; 163 1.1 jmcneill 164 1.1 jmcneill bool 165 1.1 jmcneill omap2_nand_isbusy(device_t self) 166 1.1 jmcneill { 167 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 168 1.1 jmcneill uint8_t status; 169 1.1 jmcneill 170 1.1 jmcneill DELAY(1); /* just to be sure we are not early */ 171 1.1 jmcneill 172 1.1 jmcneill bus_space_write_1(sc->sc_iot, sc->sc_ioh, 173 1.1 jmcneill sc->sc_cmd_reg, ONFI_READ_STATUS); 174 1.1 jmcneill 175 1.1 jmcneill DELAY(1); 176 1.1 jmcneill 177 1.1 jmcneill status = bus_space_read_1(sc->sc_iot, 178 1.1 jmcneill sc->sc_ioh, sc->sc_data_reg); 179 1.1 jmcneill 180 1.1 jmcneill return !(status & ONFI_STATUS_RDY); 181 1.1 jmcneill }; 182 1.1 jmcneill 183 1.1 jmcneill static int 184 1.1 jmcneill omap2_nand_match(device_t parent, cfdata_t match, void *aux) 185 1.1 jmcneill { 186 1.1 jmcneill struct fdt_attach_args * const faa = aux; 187 1.1 jmcneill 188 1.3 thorpej return of_compatible_match(faa->faa_phandle, compat_data); 189 1.1 jmcneill } 190 1.1 jmcneill 191 1.1 jmcneill static void 192 1.1 jmcneill omap2_nand_attach(device_t parent, device_t self, void *aux) 193 1.1 jmcneill { 194 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 195 1.1 jmcneill struct fdt_attach_args * const faa = aux; 196 1.1 jmcneill const int phandle = faa->faa_phandle; 197 1.1 jmcneill struct flash_attach_args flash; 198 1.1 jmcneill bus_addr_t addr, part_addr; 199 1.1 jmcneill bus_size_t size, part_size; 200 1.1 jmcneill const u_int *prop; 201 1.1 jmcneill uint32_t val; 202 1.1 jmcneill int len, child; 203 1.1 jmcneill 204 1.1 jmcneill if (fdtbus_get_reg(OF_parent(phandle), 0, &addr, &size) != 0) { 205 1.1 jmcneill aprint_error(": couldn't get registers\n"); 206 1.1 jmcneill return; 207 1.1 jmcneill } 208 1.1 jmcneill 209 1.1 jmcneill sc->sc_iot = faa->faa_bst; 210 1.1 jmcneill sc->sc_dev = self; 211 1.1 jmcneill 212 1.1 jmcneill prop = fdtbus_get_prop(phandle, "reg", &len); 213 1.1 jmcneill if (prop == NULL || len < 4) { 214 1.1 jmcneill aprint_error(": couldn't read reg property\n"); 215 1.1 jmcneill return; 216 1.1 jmcneill } 217 1.1 jmcneill 218 1.1 jmcneill sc->sc_cs = be32toh(prop[0]); 219 1.1 jmcneill 220 1.1 jmcneill /* map i/o space */ 221 1.1 jmcneill if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpmc_ioh) != 0) { 222 1.1 jmcneill aprint_error(": couldn't map registers\n"); 223 1.1 jmcneill return; 224 1.1 jmcneill } 225 1.1 jmcneill if (bus_space_subregion(sc->sc_iot, sc->sc_gpmc_ioh, GPMC_CS_CONFIG(sc->sc_cs), 0x30, &sc->sc_ioh) != 0) { 226 1.1 jmcneill aprint_error(": couldn't map cs registers\n"); 227 1.1 jmcneill return; 228 1.1 jmcneill } 229 1.1 jmcneill 230 1.1 jmcneill aprint_naive("\n"); 231 1.1 jmcneill aprint_normal(": CS%d\n", sc->sc_cs); 232 1.1 jmcneill 233 1.1 jmcneill sc->sc_cmd_reg = GPMC_NAND_COMMAND_0 - GPMC_CONFIG1_0; 234 1.1 jmcneill sc->sc_addr_reg = GPMC_NAND_ADDRESS_0 - GPMC_CONFIG1_0; 235 1.1 jmcneill sc->sc_data_reg = GPMC_NAND_DATA_0 - GPMC_CONFIG1_0; 236 1.1 jmcneill 237 1.1 jmcneill /* turn off write protection if enabled */ 238 1.1 jmcneill val = gpmc_register_read(sc, GPMC_CONFIG); 239 1.1 jmcneill val |= NAND_WP_BIT; 240 1.1 jmcneill gpmc_register_write(sc, GPMC_CONFIG, val); 241 1.1 jmcneill 242 1.1 jmcneill /* 243 1.1 jmcneill * do the reset dance for NAND 244 1.1 jmcneill */ 245 1.1 jmcneill bus_space_write_1(sc->sc_iot, sc->sc_ioh, 246 1.1 jmcneill sc->sc_cmd_reg, ONFI_RESET); 247 1.1 jmcneill 248 1.1 jmcneill omap2_nand_busy(self); 249 1.1 jmcneill 250 1.1 jmcneill /* read GPMC_CONFIG1_i to get buswidth */ 251 1.1 jmcneill val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPMC_CONFIG1_i); 252 1.1 jmcneill 253 1.1 jmcneill if ((val & DEVICESIZE) == MASKEDINT(DEVICESIZE, 0x01)) { 254 1.1 jmcneill /* 16bit */ 255 1.1 jmcneill sc->sc_buswidth = 1; 256 1.1 jmcneill } else if ((val & DEVICESIZE) == MASKEDINT(DEVICESIZE, 0x00)) { 257 1.1 jmcneill /* 8bit */ 258 1.1 jmcneill sc->sc_buswidth = 0; 259 1.1 jmcneill } else { 260 1.1 jmcneill panic("invalid buswidth reported by config1"); 261 1.1 jmcneill } 262 1.1 jmcneill 263 1.1 jmcneill nand_init_interface(&sc->sc_nand_if); 264 1.1 jmcneill 265 1.1 jmcneill sc->sc_nand_if.command = &omap2_nand_command; 266 1.1 jmcneill sc->sc_nand_if.address = &omap2_nand_address; 267 1.1 jmcneill sc->sc_nand_if.read_buf_1 = &omap2_nand_read_buf_1; 268 1.1 jmcneill sc->sc_nand_if.read_buf_2 = &omap2_nand_read_buf_2; 269 1.1 jmcneill sc->sc_nand_if.read_1 = &omap2_nand_read_1; 270 1.1 jmcneill sc->sc_nand_if.read_2 = &omap2_nand_read_2; 271 1.1 jmcneill sc->sc_nand_if.write_buf_1 = &omap2_nand_write_buf_1; 272 1.1 jmcneill sc->sc_nand_if.write_buf_2 = &omap2_nand_write_buf_2; 273 1.1 jmcneill sc->sc_nand_if.write_1 = &omap2_nand_write_1; 274 1.1 jmcneill sc->sc_nand_if.write_2 = &omap2_nand_write_2; 275 1.1 jmcneill sc->sc_nand_if.busy = &omap2_nand_busy; 276 1.1 jmcneill 277 1.1 jmcneill #ifdef OMAP2_NAND_HARDWARE_ECC 278 1.1 jmcneill omap2_nand_ecc_init(self); 279 1.1 jmcneill sc->sc_nand_if.ecc_compute = &omap2_nand_ecc_compute; 280 1.1 jmcneill sc->sc_nand_if.ecc_correct = &omap2_nand_ecc_correct; 281 1.1 jmcneill sc->sc_nand_if.ecc_prepare = &omap2_nand_ecc_prepare; 282 1.1 jmcneill sc->sc_nand_if.ecc.necc_code_size = 3; 283 1.1 jmcneill sc->sc_nand_if.ecc.necc_block_size = 512; 284 1.1 jmcneill sc->sc_nand_if.ecc.necc_type = NAND_ECC_TYPE_HW; 285 1.1 jmcneill #else 286 1.1 jmcneill sc->sc_nand_if.ecc.necc_code_size = 3; 287 1.1 jmcneill sc->sc_nand_if.ecc.necc_block_size = 256; 288 1.1 jmcneill #endif /* OMAP2_NAND_HARDWARE_ECC */ 289 1.1 jmcneill 290 1.1 jmcneill if (!pmf_device_register1(sc->sc_dev, NULL, NULL, NULL)) 291 1.1 jmcneill aprint_error_dev(sc->sc_dev, 292 1.1 jmcneill "couldn't establish power handler\n"); 293 1.1 jmcneill 294 1.1 jmcneill sc->sc_nanddev = nand_attach_mi(&sc->sc_nand_if, sc->sc_dev); 295 1.1 jmcneill if (sc->sc_nanddev == NULL) 296 1.1 jmcneill return; 297 1.1 jmcneill 298 1.1 jmcneill for (child = OF_child(phandle); child; child = OF_peer(child)) { 299 1.1 jmcneill if (!fdtbus_status_okay(child)) 300 1.1 jmcneill continue; 301 1.1 jmcneill 302 1.1 jmcneill if (fdtbus_get_reg(child, 0, &part_addr, &part_size) != 0) { 303 1.1 jmcneill aprint_error_dev(self, "couldn't parse partition %s\n", 304 1.1 jmcneill fdtbus_get_string(child, "name")); 305 1.1 jmcneill continue; 306 1.1 jmcneill } 307 1.1 jmcneill 308 1.1 jmcneill memset(&flash, 0, sizeof(flash)); 309 1.1 jmcneill flash.flash_if = &nand_flash_if; 310 1.1 jmcneill flash.partinfo.part_offset = part_addr; 311 1.1 jmcneill flash.partinfo.part_size = part_size; 312 1.1 jmcneill flash.partinfo.part_flags = 0; 313 1.1 jmcneill flash.partinfo.part_name = fdtbus_get_string(child, "label"); 314 1.1 jmcneill if (flash.partinfo.part_name == NULL) 315 1.1 jmcneill flash.partinfo.part_name = fdtbus_get_string(child, "name"); 316 1.1 jmcneill 317 1.5 thorpej config_found(sc->sc_nanddev, &flash, flash_print, CFARGS_NONE); 318 1.1 jmcneill } 319 1.1 jmcneill } 320 1.1 jmcneill 321 1.1 jmcneill static void 322 1.1 jmcneill omap2_nand_busy(device_t self) 323 1.1 jmcneill { 324 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 325 1.1 jmcneill 326 1.1 jmcneill while (!(gpmc_register_read(sc, GPMC_STATUS) & WAIT0)) { 327 1.1 jmcneill DELAY(1); 328 1.1 jmcneill } 329 1.1 jmcneill } 330 1.1 jmcneill 331 1.1 jmcneill static void 332 1.1 jmcneill omap2_nand_read_1(device_t self, uint8_t *data) 333 1.1 jmcneill { 334 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 335 1.1 jmcneill 336 1.1 jmcneill *data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_data_reg); 337 1.1 jmcneill } 338 1.1 jmcneill 339 1.1 jmcneill static void 340 1.1 jmcneill omap2_nand_write_1(device_t self, uint8_t data) 341 1.1 jmcneill { 342 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 343 1.1 jmcneill 344 1.1 jmcneill bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_data_reg, data); 345 1.1 jmcneill } 346 1.1 jmcneill 347 1.1 jmcneill static void 348 1.1 jmcneill omap2_nand_read_2(device_t self, uint16_t *data) 349 1.1 jmcneill { 350 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 351 1.1 jmcneill 352 1.1 jmcneill *data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, sc->sc_data_reg); 353 1.1 jmcneill } 354 1.1 jmcneill 355 1.1 jmcneill static void 356 1.1 jmcneill omap2_nand_write_2(device_t self, uint16_t data) 357 1.1 jmcneill { 358 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 359 1.1 jmcneill 360 1.1 jmcneill bus_space_write_2(sc->sc_iot, sc->sc_ioh, sc->sc_data_reg, data); 361 1.1 jmcneill } 362 1.1 jmcneill 363 1.1 jmcneill static void 364 1.1 jmcneill omap2_nand_read_buf_1(device_t self, void *buf, size_t len) 365 1.1 jmcneill { 366 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 367 1.1 jmcneill 368 1.1 jmcneill KASSERT(buf != NULL); 369 1.1 jmcneill KASSERT(len >= 1); 370 1.1 jmcneill 371 1.1 jmcneill bus_space_read_multi_1(sc->sc_iot, sc->sc_ioh, 372 1.1 jmcneill sc->sc_data_reg, buf, len); 373 1.1 jmcneill } 374 1.1 jmcneill 375 1.1 jmcneill static void 376 1.1 jmcneill omap2_nand_read_buf_2(device_t self, void *buf, size_t len) 377 1.1 jmcneill { 378 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 379 1.1 jmcneill 380 1.1 jmcneill KASSERT(buf != NULL); 381 1.1 jmcneill KASSERT(len >= 2); 382 1.1 jmcneill KASSERT(!(len & 0x01)); 383 1.1 jmcneill 384 1.1 jmcneill bus_space_read_multi_2(sc->sc_iot, sc->sc_ioh, 385 1.1 jmcneill sc->sc_data_reg, buf, len / 2); 386 1.1 jmcneill } 387 1.1 jmcneill 388 1.1 jmcneill static void 389 1.1 jmcneill omap2_nand_write_buf_1(device_t self, const void *buf, size_t len) 390 1.1 jmcneill { 391 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 392 1.1 jmcneill 393 1.1 jmcneill KASSERT(buf != NULL); 394 1.1 jmcneill KASSERT(len >= 1); 395 1.1 jmcneill 396 1.1 jmcneill bus_space_write_multi_1(sc->sc_iot, sc->sc_ioh, 397 1.1 jmcneill sc->sc_data_reg, buf, len); 398 1.1 jmcneill } 399 1.1 jmcneill 400 1.1 jmcneill static void 401 1.1 jmcneill omap2_nand_write_buf_2(device_t self, const void *buf, size_t len) 402 1.1 jmcneill { 403 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 404 1.1 jmcneill 405 1.1 jmcneill KASSERT(buf != NULL); 406 1.1 jmcneill KASSERT(len >= 2); 407 1.1 jmcneill KASSERT(!(len & 0x01)); 408 1.1 jmcneill 409 1.1 jmcneill bus_space_write_multi_2(sc->sc_iot, sc->sc_ioh, 410 1.1 jmcneill sc->sc_data_reg, buf, len / 2); 411 1.1 jmcneill } 412 1.1 jmcneill 413 1.1 jmcneill #ifdef OMAP2_NAND_HARDWARE_ECC 414 1.1 jmcneill static uint32_t 415 1.1 jmcneill convert_ecc(const uint8_t *ecc) 416 1.1 jmcneill { 417 1.1 jmcneill return ecc[0] | (ecc[1] << 16) | ((ecc[2] & 0xf0) << 20) | 418 1.1 jmcneill ((ecc[2] & 0x0f) << 8); 419 1.1 jmcneill } 420 1.1 jmcneill 421 1.1 jmcneill static int 422 1.1 jmcneill omap2_nand_ecc_init(device_t self) 423 1.1 jmcneill { 424 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 425 1.1 jmcneill uint32_t val; 426 1.1 jmcneill 427 1.1 jmcneill val = gpmc_register_read(sc, GPMC_ECC_CONTROL); 428 1.1 jmcneill /* clear ecc, select ecc register 1 */ 429 1.1 jmcneill val &= ~ECCPOINTER; 430 1.1 jmcneill val |= ECCCLEAR | MASKEDINT(ECCPOINTER, 1); 431 1.1 jmcneill gpmc_register_write(sc, GPMC_ECC_CONTROL, val); 432 1.1 jmcneill 433 1.1 jmcneill /* XXX too many MAGIC */ 434 1.1 jmcneill /* set ecc size to 512, set all regs to eccsize1*/ 435 1.1 jmcneill val = gpmc_register_read(sc, GPMC_ECC_SIZE_CONFIG); 436 1.1 jmcneill val &= ~ECCSIZE1; 437 1.1 jmcneill val |= MASKEDINT(ECCSIZE1, 512) | 0x0f; 438 1.1 jmcneill gpmc_register_write(sc, GPMC_ECC_CONTROL, val); 439 1.1 jmcneill 440 1.1 jmcneill return 0; 441 1.1 jmcneill } 442 1.1 jmcneill 443 1.1 jmcneill static int 444 1.1 jmcneill omap2_nand_ecc_compute(device_t self, const uint8_t *data, uint8_t *ecc) 445 1.1 jmcneill { 446 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 447 1.1 jmcneill uint32_t val; 448 1.1 jmcneill 449 1.1 jmcneill /* read ecc result register */ 450 1.1 jmcneill val = gpmc_register_read(sc, GPMC_ECC1_RESULT); 451 1.1 jmcneill 452 1.1 jmcneill ecc[0] = val & 0xff; 453 1.1 jmcneill ecc[1] = (val >> 16) & 0xff; 454 1.1 jmcneill ecc[2] = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0); 455 1.1 jmcneill 456 1.1 jmcneill /* disable ecc engine */ 457 1.1 jmcneill val = gpmc_register_read(sc, GPMC_ECC_CONFIG); 458 1.1 jmcneill val &= ~ECCENABLE; 459 1.1 jmcneill gpmc_register_write(sc, GPMC_ECC_CONFIG, val); 460 1.1 jmcneill 461 1.1 jmcneill return 0; 462 1.1 jmcneill } 463 1.1 jmcneill 464 1.1 jmcneill static int 465 1.1 jmcneill omap2_nand_ecc_prepare(device_t self, int mode) 466 1.1 jmcneill { 467 1.1 jmcneill struct omap2_nand_softc *sc = device_private(self); 468 1.1 jmcneill uint32_t val; 469 1.1 jmcneill 470 1.1 jmcneill /* same for read/write */ 471 1.1 jmcneill switch (mode) { 472 1.1 jmcneill case NAND_ECC_READ: 473 1.1 jmcneill case NAND_ECC_WRITE: 474 1.1 jmcneill val = gpmc_register_read(sc, GPMC_ECC_CONTROL); 475 1.1 jmcneill /* clear ecc, select ecc register 1 */ 476 1.1 jmcneill val &= ~ECCPOINTER; 477 1.1 jmcneill val |= ECCCLEAR | MASKEDINT(ECCPOINTER, 1); 478 1.1 jmcneill gpmc_register_write(sc, GPMC_ECC_CONTROL, val); 479 1.1 jmcneill 480 1.1 jmcneill val = gpmc_register_read(sc, GPMC_ECC_CONFIG); 481 1.1 jmcneill val &= ~ECCCS; 482 1.1 jmcneill val |= ECCENABLE | MASKEDINT(ECCCS, sc->sc_cs); 483 1.1 jmcneill if (sc->sc_buswidth == 1) 484 1.1 jmcneill val |= ECC16B; 485 1.1 jmcneill else 486 1.1 jmcneill val &= ~ECC16B; 487 1.1 jmcneill gpmc_register_write(sc, GPMC_ECC_CONFIG, val); 488 1.1 jmcneill 489 1.1 jmcneill break; 490 1.1 jmcneill default: 491 1.1 jmcneill aprint_error_dev(self, "invalid i/o mode for ecc prepare\n"); 492 1.1 jmcneill return -1; 493 1.1 jmcneill } 494 1.1 jmcneill 495 1.1 jmcneill return 0; 496 1.1 jmcneill } 497 1.1 jmcneill 498 1.1 jmcneill static int 499 1.1 jmcneill omap2_nand_ecc_correct(device_t self, uint8_t *data, const uint8_t *oldecc, 500 1.1 jmcneill const uint8_t *calcecc) 501 1.1 jmcneill { 502 1.1 jmcneill uint32_t oecc, cecc, xor; 503 1.1 jmcneill uint16_t parity, offset; 504 1.1 jmcneill uint8_t bit; 505 1.1 jmcneill 506 1.1 jmcneill oecc = convert_ecc(oldecc); 507 1.1 jmcneill cecc = convert_ecc(calcecc); 508 1.1 jmcneill 509 1.1 jmcneill /* get the difference */ 510 1.1 jmcneill xor = oecc ^ cecc; 511 1.1 jmcneill 512 1.1 jmcneill /* the data was correct if all bits are zero */ 513 1.1 jmcneill if (xor == 0x00) 514 1.1 jmcneill return NAND_ECC_OK; 515 1.1 jmcneill 516 1.1 jmcneill switch (popcount32(xor)) { 517 1.1 jmcneill case 12: 518 1.1 jmcneill /* single byte error */ 519 1.1 jmcneill parity = xor >> 16; 520 1.1 jmcneill bit = (parity & 0x07); 521 1.1 jmcneill offset = (parity >> 3) & 0x01ff; 522 1.1 jmcneill /* correct bit */ 523 1.1 jmcneill data[offset] ^= (0x01 << bit); 524 1.1 jmcneill return NAND_ECC_CORRECTED; 525 1.1 jmcneill case 1: 526 1.1 jmcneill return NAND_ECC_INVALID; 527 1.1 jmcneill default: 528 1.1 jmcneill /* erased page! */ 529 1.1 jmcneill if ((oecc == 0x0fff0fff) && (cecc == 0x00000000)) 530 1.1 jmcneill return NAND_ECC_OK; 531 1.1 jmcneill 532 1.1 jmcneill return NAND_ECC_TWOBIT; 533 1.1 jmcneill } 534 1.1 jmcneill } 535 1.1 jmcneill #endif /* !OMAP2_NAND_HARDWARE_ECC */ 536