1/* $NetBSD: rmixl_nand.c,v 1.8 2023/05/10 00:07:58 riastradh Exp $ */ 2 3/*- 4 * Copyright (c) 2010 Department of Software Engineering, 5 * University of Szeged, Hungary 6 * Copyright (c) 2010 Adam Hoka <ahoka@NetBSD.org> 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by the Department of Software Engineering, University of Szeged, Hungary 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34/* 35 * Device driver for the RMI XLS NAND controller 36 */ 37 38#include <sys/cdefs.h> 39__KERNEL_RCSID(0, "$NetBSD: rmixl_nand.c,v 1.8 2023/05/10 00:07:58 riastradh Exp $"); 40 41#include "opt_flash.h" 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/cdefs.h> 46#include <sys/device.h> 47#include <sys/endian.h> 48 49#include <sys/bus.h> 50 51#include <mips/rmi/rmixlreg.h> 52#include <mips/rmi/rmixlvar.h> 53#include <mips/rmi/rmixl_iobusvar.h> 54#include <mips/rmi/rmixl_intr.h> 55 56#include <dev/nand/nand.h> 57#include <dev/nand/onfi.h> 58 59 60static int rmixl_nand_match(device_t, cfdata_t, void *); 61static void rmixl_nand_attach(device_t, device_t, void *); 62static int rmixl_nand_detach(device_t, int); 63static void rmixl_nand_command(device_t, uint8_t); 64static void rmixl_nand_address(device_t, uint8_t); 65static void rmixl_nand_busy(device_t); 66static void rmixl_nand_read_1(device_t, uint8_t *); 67static void rmixl_nand_write_1(device_t, uint8_t); 68static void rmixl_nand_read_2(device_t, uint16_t *); 69static void rmixl_nand_write_2(device_t, uint16_t); 70static void rmixl_nand_read_buf(device_t, void *, size_t); 71static void rmixl_nand_write_buf(device_t, const void *, size_t); 72 73 74struct rmixl_nand_softc { 75 device_t sc_dev; 76 device_t sc_nanddev; 77 struct iobus_softc *sc_iobus_sc; 78 79 int sc_cs; /* chip select index */ 80 int sc_buswidth; /* in bytes */ 81 82 struct nand_interface sc_nand_if; 83 84 bus_space_tag_t sc_obio_bst; 85 bus_space_handle_t sc_obio_bsh; 86 u_long sc_cmd_reg; 87 u_long sc_addr_reg; 88 89 bus_addr_t sc_iobus_addr; 90 bus_size_t sc_iobus_size; 91 bus_space_tag_t sc_iobus_bst; 92 bus_space_handle_t sc_iobus_bsh; 93 u_long sc_data_reg; 94 95}; 96 97CFATTACH_DECL_NEW(rmixl_nand, sizeof(struct rmixl_nand_softc), rmixl_nand_match, 98 rmixl_nand_attach, rmixl_nand_detach, NULL); 99 100static int 101rmixl_nand_match(device_t parent, cfdata_t match, void *aux) 102{ 103 struct rmixl_iobus_attach_args *ia = aux; 104 bus_space_handle_t bsh; 105 volatile uint32_t *vaddr; 106 int err; 107 int rv; 108 109 if ((ia->ia_dev_parm & RMIXL_FLASH_CSDEV_NANDEN) == 0) 110 return 0; /* not NAND */ 111 112 if (cpu_rmixlp(mips_options.mips_cpu)) { 113 aprint_error("%s: NAND not yet supported on XLP", __func__); 114 return 0; 115 } 116 117 if (! cpu_rmixls(mips_options.mips_cpu)) { 118 aprint_error("%s: NAND not supported on this processor", 119 __func__); 120 return 0; 121 } 122 123 /* 124 * probe for NAND -- this may be redundant 125 * if the device isn't there, the NANDEN test (above) 126 * should have failed 127 */ 128 err = bus_space_map(ia->ia_iobus_bst, ia->ia_iobus_addr, 129 sizeof(uint32_t), 0, &bsh); 130 if (err != 0) { 131 aprint_debug("%s: bus_space_map err %d, " 132 "iobus space addr %#" PRIxBUSADDR "\n", 133 __func__, err, ia->ia_iobus_addr); 134 return 0; 135 } 136 137 vaddr = bus_space_vaddr(ia->ia_iobus_bst, bsh); 138 rv = rmixl_probe_4(vaddr); 139 if (rv == 0) 140 aprint_debug("%s: rmixl_probe_4 failed, vaddr %p\n", 141 __func__, vaddr); 142 143 bus_space_unmap(ia->ia_iobus_bst, bsh, sizeof(uint32_t)); 144 145 return rv; 146} 147 148static void 149rmixl_nand_attach(device_t parent, device_t self, void *aux) 150{ 151 struct rmixl_nand_softc *sc = device_private(self); 152 sc->sc_iobus_sc = device_private(parent); 153 struct rmixl_iobus_attach_args *ia = aux; 154 uint32_t val; 155 int err; 156 157 aprint_normal("\n"); 158 159 sc->sc_dev = self; 160 sc->sc_obio_bst = ia->ia_obio_bst; 161 sc->sc_obio_bsh = ia->ia_obio_bsh; 162 sc->sc_iobus_bst = ia->ia_iobus_bst; 163 sc->sc_iobus_addr = ia->ia_iobus_addr; 164 sc->sc_iobus_size = sizeof(uint32_t); 165 sc->sc_cs = ia->ia_cs; 166 167 sc->sc_cmd_reg = RMIXL_NAND_CLEn(ia->ia_cs); 168 sc->sc_addr_reg = RMIXL_NAND_ALEn(ia->ia_cs); 169 170 aprint_debug_dev(self, "CS#%d cstime_parma %#x, cstime_parmb %#x\n", 171 ia->ia_cs, 172 bus_space_read_4(sc->sc_obio_bst, sc->sc_obio_bsh, 173 RMIXL_FLASH_CSTIME_PARMAn(ia->ia_cs)), 174 bus_space_read_4(sc->sc_obio_bst, sc->sc_obio_bsh, 175 RMIXL_FLASH_CSTIME_PARMBn(ia->ia_cs))); 176 177 err = bus_space_map(sc->sc_iobus_bst, sc->sc_iobus_addr, 178 sc->sc_iobus_size, 0, &sc->sc_iobus_bsh); 179 if (err != 0) { 180 aprint_error_dev(self, 181 "bus space map err %d, iobus space\n", err); 182 return; 183 } 184 185 /* 186 * determine buswidth 187 */ 188 val = ia->ia_dev_parm; 189 val &= RMIXL_FLASH_CSDEV_DWIDTH; 190 val >>= RMIXL_FLASH_CSDEV_DWIDTH_SHFT; 191 switch(val) { 192 case 0: /* FALLTHROUGH */ 193 case 3: 194 sc->sc_buswidth = 1; /* 8 bit */ 195 break; 196 case 1: 197 sc->sc_buswidth = 2; /* 16 bit */ 198 break; 199 case 2: 200 sc->sc_buswidth = 4; /* 32 bit */ 201 break; 202 } 203 aprint_debug_dev(self, "bus width %d bits\n", 8 * sc->sc_buswidth); 204 205 nand_init_interface(&sc->sc_nand_if); 206 207 sc->sc_nand_if.command = rmixl_nand_command; 208 sc->sc_nand_if.address = rmixl_nand_address; 209 sc->sc_nand_if.read_buf_1 = rmixl_nand_read_buf; 210 sc->sc_nand_if.read_buf_2 = rmixl_nand_read_buf; 211 sc->sc_nand_if.read_1 = rmixl_nand_read_1; 212 sc->sc_nand_if.read_2 = rmixl_nand_read_2; 213 sc->sc_nand_if.write_buf_1 = rmixl_nand_write_buf; 214 sc->sc_nand_if.write_buf_2 = rmixl_nand_write_buf; 215 sc->sc_nand_if.write_1 = rmixl_nand_write_1; 216 sc->sc_nand_if.write_2 = rmixl_nand_write_2; 217 sc->sc_nand_if.busy = rmixl_nand_busy; 218 219 sc->sc_nand_if.ecc.necc_code_size = 3; 220 sc->sc_nand_if.ecc.necc_block_size = 256; 221 222 /* 223 * reset to get NAND into known state 224 */ 225 rmixl_nand_command(self, ONFI_RESET); 226 rmixl_nand_busy(self); 227 228 if (! pmf_device_register1(self, NULL, NULL, NULL)) 229 aprint_error_dev(self, "couldn't establish power handler\n"); 230 231 sc->sc_nanddev = nand_attach_mi(&sc->sc_nand_if, self); 232} 233 234static int 235rmixl_nand_detach(device_t self, int flags) 236{ 237 struct rmixl_nand_softc *sc = device_private(self); 238 int error; 239 240 error = config_detach_children(self, flags); 241 if (error) 242 return error; 243 244 pmf_device_deregister(self); 245 246 bus_space_unmap(sc->sc_iobus_bst, sc->sc_iobus_bsh, sc->sc_iobus_size); 247 248 return 0; 249} 250 251static void 252rmixl_nand_command(device_t self, uint8_t command) 253{ 254 struct rmixl_nand_softc *sc = device_private(self); 255 256 bus_space_write_4(sc->sc_obio_bst, sc->sc_obio_bsh, 257 sc->sc_cmd_reg, command); 258} 259 260static void 261rmixl_nand_address(device_t self, uint8_t address) 262{ 263 struct rmixl_nand_softc *sc = device_private(self); 264 265 bus_space_write_4(sc->sc_obio_bst, sc->sc_obio_bsh, 266 sc->sc_addr_reg, address); 267} 268 269static void 270rmixl_nand_busy(device_t self) 271{ 272 struct rmixl_nand_softc *sc = device_private(self); 273 uint32_t istatus; 274 275 for(u_int count=100000; count--;) { 276 istatus = bus_space_read_4(sc->sc_obio_bst, sc->sc_obio_bsh, 277 RMIXL_FLASH_INT_STATUS); 278 if ((istatus & __BIT(8)) != 0) 279 return; 280 DELAY(1); 281 } 282#ifdef DEBUG 283 printf("%s: timed out, istatus=%#x\n", __func__, istatus); 284#ifdef DDB 285 Debugger(); 286#endif 287#endif 288} 289 290static void 291rmixl_nand_read_1(device_t self, uint8_t *data) 292{ 293 struct rmixl_nand_softc *sc = device_private(self); 294 295 *data = bus_space_read_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0); 296} 297 298static void 299rmixl_nand_write_1(device_t self, uint8_t data) 300{ 301 struct rmixl_nand_softc *sc = device_private(self); 302 303 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, data); 304} 305 306static void 307rmixl_nand_read_2(device_t self, uint16_t *data) 308{ 309 struct rmixl_nand_softc *sc = device_private(self); 310 311 *data = bus_space_read_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0); 312} 313 314static void 315rmixl_nand_write_2(device_t self, uint16_t data) 316{ 317 struct rmixl_nand_softc *sc = device_private(self); 318 319 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, data); 320} 321 322static void 323rmixl_nand_read_buf(device_t self, void *buf, size_t len) 324{ 325 struct rmixl_nand_softc *sc = device_private(self); 326 uintptr_t addr = (uintptr_t)buf; 327 size_t sz; 328 329 /* leading byte alignment */ 330 if ((len >= 1) && ((addr & 1) != 0)) { 331 *((uint8_t *)addr) = bus_space_read_1(sc->sc_iobus_bst, 332 sc->sc_iobus_bsh, 0); 333 addr += 1; 334 len -= 1; 335 } 336 337 /* leading short alignment */ 338 if ((len >= 2) && ((addr & 2) != 0)) { 339 *((uint16_t *)addr) = bus_space_read_2(sc->sc_iobus_bst, 340 sc->sc_iobus_bsh, 0); 341 addr += 2; 342 len -= 2; 343 } 344 345 /* word alignment */ 346 sz = len >> 2; 347 if (sz != 0) { 348 bus_space_read_multi_4(sc->sc_iobus_bst, sc->sc_iobus_bsh, 349 0, (uint32_t *)addr, sz); 350 sz <<= 2; 351 addr += sz; 352 len -= sz; 353 } 354 355 /* trailing short alignment */ 356 if (len >= 2) { 357 *((uint16_t *)addr) = bus_space_read_2(sc->sc_iobus_bst, 358 sc->sc_iobus_bsh, 0); 359 addr += 2; 360 len -= 2; 361 } 362 363 /* trailing byte alignment */ 364 if (len != 0) 365 *((uint8_t *)addr) = bus_space_read_1(sc->sc_iobus_bst, 366 sc->sc_iobus_bsh, 0); 367} 368 369static void 370rmixl_nand_write_buf(device_t self, const void *buf, size_t len) 371{ 372 struct rmixl_nand_softc *sc = device_private(self); 373 uintptr_t addr = (uintptr_t)buf; 374 size_t sz; 375 376 /* leading byte alignment */ 377 if ((len >= 1) && ((addr & 1) != 0)) { 378 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, 379 *((uint8_t *)addr)); 380 addr += 1; 381 len -= 1; 382 } 383 384 /* leading short alignment */ 385 if ((len >= 2) && ((addr & 2) != 0)) { 386 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, 387 *((uint16_t *)addr)); 388 addr += 2; 389 len -= 2; 390 } 391 392 /* word alignment */ 393 sz = len >> 2; 394 if (sz != 0) { 395 bus_space_write_multi_4(sc->sc_iobus_bst, sc->sc_iobus_bsh, 396 0, (uint32_t *)addr, sz); 397 sz <<= 2; 398 addr += sz; 399 len -= sz; 400 } 401 402 /* trailing short alignment */ 403 if (len >= 2) { 404 bus_space_write_2(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, 405 *((uint16_t *)addr)); 406 addr += 2; 407 len -= 2; 408 } 409 410 /* trailing byte alignment */ 411 if (len != 0) 412 bus_space_write_1(sc->sc_iobus_bst, sc->sc_iobus_bsh, 0, 413 *((uint8_t *)addr)); 414} 415