1235537Sgber/*- 2235537Sgber * Copyright (C) 2009-2012 Semihalf 3235537Sgber * All rights reserved. 4235537Sgber * 5235537Sgber * Redistribution and use in source and binary forms, with or without 6235537Sgber * modification, are permitted provided that the following conditions 7235537Sgber * are met: 8235537Sgber * 1. Redistributions of source code must retain the above copyright 9235537Sgber * notice, this list of conditions and the following disclaimer. 10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 11235537Sgber * notice, this list of conditions and the following disclaimer in the 12235537Sgber * documentation and/or other materials provided with the distribution. 13235537Sgber * 14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235537Sgber * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235537Sgber * SUCH DAMAGE. 25235537Sgber */ 26235537Sgber 27235537Sgber/* Generic NAND driver */ 28235537Sgber 29235537Sgber#include <sys/cdefs.h> 30235537Sgber__FBSDID("$FreeBSD$"); 31235537Sgber 32235537Sgber#include <sys/param.h> 33235537Sgber#include <sys/systm.h> 34235537Sgber#include <sys/proc.h> 35235537Sgber#include <sys/bus.h> 36235537Sgber#include <sys/conf.h> 37235537Sgber#include <sys/kernel.h> 38235537Sgber#include <sys/module.h> 39235537Sgber#include <sys/rman.h> 40235537Sgber#include <sys/lock.h> 41235537Sgber#include <sys/mutex.h> 42235537Sgber#include <sys/time.h> 43235537Sgber#include <sys/malloc.h> 44235537Sgber 45235537Sgber#include <dev/nand/nand.h> 46235537Sgber#include <dev/nand/nandbus.h> 47235537Sgber#include "nfc_if.h" 48235537Sgber#include "nand_if.h" 49235537Sgber#include "nandbus_if.h" 50235537Sgber 51235537Sgber 52235537Sgberstatic int onfi_nand_probe(device_t dev); 53235537Sgberstatic int large_nand_probe(device_t dev); 54235537Sgberstatic int small_nand_probe(device_t dev); 55235537Sgberstatic int generic_nand_attach(device_t dev); 56235537Sgberstatic int generic_nand_detach(device_t dev); 57235537Sgber 58235537Sgberstatic int generic_erase_block(device_t, uint32_t); 59235537Sgberstatic int generic_erase_block_intlv(device_t, uint32_t); 60235537Sgberstatic int generic_read_page (device_t, uint32_t, void *, uint32_t, uint32_t); 61235537Sgberstatic int generic_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); 62235537Sgberstatic int generic_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); 63235537Sgberstatic int generic_program_page_intlv(device_t, uint32_t, void *, uint32_t, 64235537Sgber uint32_t); 65235537Sgberstatic int generic_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); 66235537Sgberstatic int generic_is_blk_bad(device_t, uint32_t, uint8_t *); 67235537Sgberstatic int generic_get_ecc(device_t, void *, void *, int *); 68235537Sgberstatic int generic_correct_ecc(device_t, void *, void *, void *); 69235537Sgber 70235537Sgberstatic int small_read_page(device_t, uint32_t, void *, uint32_t, uint32_t); 71235537Sgberstatic int small_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); 72235537Sgberstatic int small_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); 73235537Sgberstatic int small_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); 74235537Sgber 75235537Sgberstatic int onfi_is_blk_bad(device_t, uint32_t, uint8_t *); 76235537Sgberstatic int onfi_read_parameter(struct nand_chip *, struct onfi_params *); 77235537Sgber 78235537Sgberstatic int nand_send_address(device_t, int32_t, int32_t, int8_t); 79235537Sgber 80235537Sgberstatic device_method_t onand_methods[] = { 81235537Sgber /* Device interface */ 82235537Sgber DEVMETHOD(device_probe, onfi_nand_probe), 83235537Sgber DEVMETHOD(device_attach, generic_nand_attach), 84235537Sgber DEVMETHOD(device_detach, generic_nand_detach), 85235537Sgber 86235537Sgber DEVMETHOD(nand_read_page, generic_read_page), 87235537Sgber DEVMETHOD(nand_program_page, generic_program_page), 88235537Sgber DEVMETHOD(nand_program_page_intlv, generic_program_page_intlv), 89235537Sgber DEVMETHOD(nand_read_oob, generic_read_oob), 90235537Sgber DEVMETHOD(nand_program_oob, generic_program_oob), 91235537Sgber DEVMETHOD(nand_erase_block, generic_erase_block), 92235537Sgber DEVMETHOD(nand_erase_block_intlv, generic_erase_block_intlv), 93235537Sgber 94235537Sgber DEVMETHOD(nand_is_blk_bad, onfi_is_blk_bad), 95235537Sgber DEVMETHOD(nand_get_ecc, generic_get_ecc), 96235537Sgber DEVMETHOD(nand_correct_ecc, generic_correct_ecc), 97235537Sgber { 0, 0 } 98235537Sgber}; 99235537Sgber 100235537Sgberstatic device_method_t lnand_methods[] = { 101235537Sgber /* Device interface */ 102235537Sgber DEVMETHOD(device_probe, large_nand_probe), 103235537Sgber DEVMETHOD(device_attach, generic_nand_attach), 104235537Sgber DEVMETHOD(device_detach, generic_nand_detach), 105235537Sgber 106235537Sgber DEVMETHOD(nand_read_page, generic_read_page), 107235537Sgber DEVMETHOD(nand_program_page, generic_program_page), 108235537Sgber DEVMETHOD(nand_read_oob, generic_read_oob), 109235537Sgber DEVMETHOD(nand_program_oob, generic_program_oob), 110235537Sgber DEVMETHOD(nand_erase_block, generic_erase_block), 111235537Sgber 112235537Sgber DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), 113235537Sgber DEVMETHOD(nand_get_ecc, generic_get_ecc), 114235537Sgber DEVMETHOD(nand_correct_ecc, generic_correct_ecc), 115235537Sgber { 0, 0 } 116235537Sgber}; 117235537Sgber 118235537Sgberstatic device_method_t snand_methods[] = { 119235537Sgber /* Device interface */ 120235537Sgber DEVMETHOD(device_probe, small_nand_probe), 121235537Sgber DEVMETHOD(device_attach, generic_nand_attach), 122235537Sgber DEVMETHOD(device_detach, generic_nand_detach), 123235537Sgber 124235537Sgber DEVMETHOD(nand_read_page, small_read_page), 125235537Sgber DEVMETHOD(nand_program_page, small_program_page), 126235537Sgber DEVMETHOD(nand_read_oob, small_read_oob), 127235537Sgber DEVMETHOD(nand_program_oob, small_program_oob), 128235537Sgber DEVMETHOD(nand_erase_block, generic_erase_block), 129235537Sgber 130235537Sgber DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), 131235537Sgber DEVMETHOD(nand_get_ecc, generic_get_ecc), 132235537Sgber DEVMETHOD(nand_correct_ecc, generic_correct_ecc), 133235537Sgber { 0, 0 } 134235537Sgber}; 135235537Sgber 136235537Sgberdevclass_t onand_devclass; 137235537Sgberdevclass_t lnand_devclass; 138235537Sgberdevclass_t snand_devclass; 139235537Sgber 140235537Sgberdriver_t onand_driver = { 141235537Sgber "onand", 142235537Sgber onand_methods, 143235537Sgber sizeof(struct nand_chip) 144235537Sgber}; 145235537Sgber 146235537Sgberdriver_t lnand_driver = { 147235537Sgber "lnand", 148235537Sgber lnand_methods, 149235537Sgber sizeof(struct nand_chip) 150235537Sgber}; 151235537Sgber 152235537Sgberdriver_t snand_driver = { 153235537Sgber "snand", 154235537Sgber snand_methods, 155235537Sgber sizeof(struct nand_chip) 156235537Sgber}; 157235537Sgber 158235537SgberDRIVER_MODULE(onand, nandbus, onand_driver, onand_devclass, 0, 0); 159235537SgberDRIVER_MODULE(lnand, nandbus, lnand_driver, lnand_devclass, 0, 0); 160235537SgberDRIVER_MODULE(snand, nandbus, snand_driver, snand_devclass, 0, 0); 161235537Sgber 162235537Sgberstatic int 163235537Sgberonfi_nand_probe(device_t dev) 164235537Sgber{ 165235537Sgber struct nandbus_ivar *ivar; 166235537Sgber 167235537Sgber ivar = device_get_ivars(dev); 168235537Sgber if (ivar && ivar->is_onfi) { 169235537Sgber device_set_desc(dev, "ONFI compliant NAND"); 170235537Sgber return (BUS_PROBE_DEFAULT); 171235537Sgber } 172235537Sgber 173235537Sgber return (ENODEV); 174235537Sgber} 175235537Sgber 176235537Sgberstatic int 177235537Sgberlarge_nand_probe(device_t dev) 178235537Sgber{ 179235537Sgber struct nandbus_ivar *ivar; 180235537Sgber 181235537Sgber ivar = device_get_ivars(dev); 182235537Sgber if (ivar && !ivar->is_onfi && ivar->params->page_size >= 512) { 183235537Sgber device_set_desc(dev, ivar->params->name); 184235537Sgber return (BUS_PROBE_DEFAULT); 185235537Sgber } 186235537Sgber 187235537Sgber return (ENODEV); 188235537Sgber} 189235537Sgber 190235537Sgberstatic int 191235537Sgbersmall_nand_probe(device_t dev) 192235537Sgber{ 193235537Sgber struct nandbus_ivar *ivar; 194235537Sgber 195235537Sgber ivar = device_get_ivars(dev); 196235537Sgber if (ivar && !ivar->is_onfi && ivar->params->page_size == 512) { 197235537Sgber device_set_desc(dev, ivar->params->name); 198235537Sgber return (BUS_PROBE_DEFAULT); 199235537Sgber } 200235537Sgber 201235537Sgber return (ENODEV); 202235537Sgber} 203235537Sgber 204235537Sgberstatic int 205235537Sgbergeneric_nand_attach(device_t dev) 206235537Sgber{ 207235537Sgber struct nand_chip *chip; 208235537Sgber struct nandbus_ivar *ivar; 209235537Sgber struct onfi_params *onfi_params; 210235537Sgber device_t nandbus, nfc; 211235537Sgber int err; 212235537Sgber 213235537Sgber chip = device_get_softc(dev); 214235537Sgber chip->dev = dev; 215235537Sgber 216235537Sgber ivar = device_get_ivars(dev); 217235537Sgber chip->id.man_id = ivar->man_id; 218235537Sgber chip->id.dev_id = ivar->dev_id; 219235537Sgber chip->num = ivar->cs; 220235537Sgber 221235537Sgber /* TODO remove when HW ECC supported */ 222235537Sgber nandbus = device_get_parent(dev); 223235537Sgber nfc = device_get_parent(nandbus); 224235537Sgber 225235537Sgber chip->nand = device_get_softc(nfc); 226235537Sgber 227235537Sgber if (ivar->is_onfi) { 228235537Sgber onfi_params = malloc(sizeof(struct onfi_params), 229235537Sgber M_NAND, M_WAITOK | M_ZERO); 230235537Sgber if (onfi_params == NULL) 231235537Sgber return (ENXIO); 232235537Sgber 233235537Sgber if (onfi_read_parameter(chip, onfi_params)) { 234235537Sgber nand_debug(NDBG_GEN,"Could not read parameter page!\n"); 235235537Sgber free(onfi_params, M_NAND); 236235537Sgber return (ENXIO); 237235537Sgber } 238235537Sgber 239235537Sgber nand_onfi_set_params(chip, onfi_params); 240235537Sgber /* Set proper column and row cycles */ 241235537Sgber ivar->cols = (onfi_params->address_cycles >> 4) & 0xf; 242235537Sgber ivar->rows = onfi_params->address_cycles & 0xf; 243235537Sgber free(onfi_params, M_NAND); 244235537Sgber 245235537Sgber } else { 246235537Sgber 247235537Sgber nand_set_params(chip, ivar->params); 248235537Sgber } 249235537Sgber 250235537Sgber err = nand_init_stat(chip); 251235537Sgber if (err) { 252235537Sgber generic_nand_detach(dev); 253235537Sgber return (err); 254235537Sgber } 255235537Sgber 256235537Sgber err = nand_init_bbt(chip); 257235537Sgber if (err) { 258235537Sgber generic_nand_detach(dev); 259235537Sgber return (err); 260235537Sgber } 261235537Sgber 262235537Sgber err = nand_make_dev(chip); 263235537Sgber if (err) { 264235537Sgber generic_nand_detach(dev); 265235537Sgber return (err); 266235537Sgber } 267235537Sgber 268235537Sgber err = create_geom_disk(chip); 269235537Sgber if (err) { 270235537Sgber generic_nand_detach(dev); 271235537Sgber return (err); 272235537Sgber } 273235537Sgber 274235537Sgber return (0); 275235537Sgber} 276235537Sgber 277235537Sgberstatic int 278235537Sgbergeneric_nand_detach(device_t dev) 279235537Sgber{ 280235537Sgber struct nand_chip *chip; 281235537Sgber 282235537Sgber chip = device_get_softc(dev); 283235537Sgber 284235537Sgber nand_destroy_bbt(chip); 285235537Sgber destroy_geom_disk(chip); 286235537Sgber nand_destroy_dev(chip); 287235537Sgber nand_destroy_stat(chip); 288235537Sgber 289235537Sgber return (0); 290235537Sgber} 291235537Sgber 292235537Sgberstatic int 293235537Sgbercan_write(device_t nandbus) 294235537Sgber{ 295235537Sgber uint8_t status; 296235537Sgber 297235537Sgber if (NANDBUS_WAIT_READY(nandbus, &status)) 298235537Sgber return (0); 299235537Sgber 300235537Sgber if (!(status & NAND_STATUS_WP)) { 301235537Sgber nand_debug(NDBG_GEN,"Chip is write-protected"); 302235537Sgber return (0); 303235537Sgber } 304235537Sgber 305235537Sgber return (1); 306235537Sgber} 307235537Sgber 308235537Sgberstatic int 309235537Sgbercheck_fail(device_t nandbus) 310235537Sgber{ 311235537Sgber uint8_t status; 312235537Sgber 313235537Sgber NANDBUS_WAIT_READY(nandbus, &status); 314235537Sgber if (status & NAND_STATUS_FAIL) { 315235537Sgber nand_debug(NDBG_GEN,"Status failed %x", status); 316235537Sgber return (ENXIO); 317235537Sgber } 318235537Sgber 319235537Sgber return (0); 320235537Sgber} 321235537Sgber 322235537Sgberstatic int 323235537Sgberonfi_read_parameter(struct nand_chip *chip, struct onfi_params *params) 324235537Sgber{ 325235537Sgber device_t nandbus; 326235537Sgber 327235537Sgber nand_debug(NDBG_GEN,"read parameter"); 328235537Sgber 329235537Sgber nandbus = device_get_parent(chip->dev); 330235537Sgber 331235537Sgber NANDBUS_SELECT_CS(nandbus, chip->num); 332235537Sgber 333235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ_PARAMETER)) 334235537Sgber return (ENXIO); 335235537Sgber 336235537Sgber if (nand_send_address(chip->dev, -1, -1, PAGE_PARAMETER_DEF)) 337235537Sgber return (ENXIO); 338235537Sgber 339235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 340235537Sgber return (ENXIO); 341235537Sgber 342235537Sgber NANDBUS_READ_BUFFER(nandbus, params, sizeof(struct onfi_params)); 343235537Sgber 344235537Sgber /* TODO */ 345235537Sgber /* Check for signature */ 346235537Sgber /* Check CRC */ 347235537Sgber /* Use redundant page if necessary */ 348235537Sgber 349235537Sgber return (0); 350235537Sgber} 351235537Sgber 352235537Sgberstatic int 353235537Sgbersend_read_page(device_t nand, uint8_t start_command, uint8_t end_command, 354235537Sgber uint32_t row, uint32_t column) 355235537Sgber{ 356235537Sgber device_t nandbus = device_get_parent(nand); 357235537Sgber 358235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, start_command)) 359235537Sgber return (ENXIO); 360235537Sgber 361235537Sgber if (nand_send_address(nand, row, column, -1)) 362235537Sgber return (ENXIO); 363235537Sgber 364235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, end_command)) 365235537Sgber return (ENXIO); 366235537Sgber 367235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 368235537Sgber return (ENXIO); 369235537Sgber 370235537Sgber return (0); 371235537Sgber} 372235537Sgber 373235537Sgberstatic int 374235537Sgbergeneric_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, 375235537Sgber uint32_t offset) 376235537Sgber{ 377235537Sgber struct nand_chip *chip; 378235537Sgber struct page_stat *pg_stat; 379235537Sgber device_t nandbus; 380235537Sgber uint32_t row; 381235537Sgber 382235537Sgber nand_debug(NDBG_GEN,"%p raw read page %x[%x] at %x", nand, page, len, offset); 383235537Sgber chip = device_get_softc(nand); 384235537Sgber nandbus = device_get_parent(nand); 385235537Sgber 386235537Sgber if (nand_check_page_boundary(chip, page)) 387235537Sgber return (ENXIO); 388235537Sgber 389235537Sgber page_to_row(&chip->chip_geom, page, &row); 390235537Sgber 391235537Sgber if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, 392235537Sgber offset)) 393235537Sgber return (ENXIO); 394235537Sgber 395235537Sgber DELAY(chip->t_r); 396235537Sgber 397235537Sgber NANDBUS_READ_BUFFER(nandbus, buf, len); 398235537Sgber 399235537Sgber if (check_fail(nandbus)) 400235537Sgber return (ENXIO); 401235537Sgber 402235537Sgber pg_stat = &(chip->pg_stat[page]); 403235537Sgber pg_stat->page_raw_read++; 404235537Sgber 405235537Sgber return (0); 406235537Sgber} 407235537Sgber 408235537Sgberstatic int 409235537Sgbergeneric_read_oob(device_t nand, uint32_t page, void* buf, uint32_t len, 410235537Sgber uint32_t offset) 411235537Sgber{ 412235537Sgber struct nand_chip *chip; 413235537Sgber device_t nandbus; 414235537Sgber uint32_t row; 415235537Sgber 416235537Sgber nand_debug(NDBG_GEN,"%p raw read oob %x[%x] at %x", nand, page, len, offset); 417235537Sgber chip = device_get_softc(nand); 418235537Sgber nandbus = device_get_parent(nand); 419235537Sgber 420235537Sgber if (nand_check_page_boundary(chip, page)) { 421235537Sgber nand_debug(NDBG_GEN,"page boundary check failed: %08x\n", page); 422235537Sgber return (ENXIO); 423235537Sgber } 424235537Sgber 425235537Sgber page_to_row(&chip->chip_geom, page, &row); 426235537Sgber 427235537Sgber offset += chip->chip_geom.page_size; 428235537Sgber 429235537Sgber if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, 430235537Sgber offset)) 431235537Sgber return (ENXIO); 432235537Sgber 433235537Sgber DELAY(chip->t_r); 434235537Sgber 435235537Sgber NANDBUS_READ_BUFFER(nandbus, buf, len); 436235537Sgber 437235537Sgber if (check_fail(nandbus)) 438235537Sgber return (ENXIO); 439235537Sgber 440235537Sgber return (0); 441235537Sgber} 442235537Sgber 443235537Sgberstatic int 444235537Sgbersend_start_program_page(device_t nand, uint32_t row, uint32_t column) 445235537Sgber{ 446235537Sgber device_t nandbus = device_get_parent(nand); 447235537Sgber 448235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_PROG)) 449235537Sgber return (ENXIO); 450235537Sgber 451235537Sgber if (nand_send_address(nand, row, column, -1)) 452235537Sgber return (ENXIO); 453235537Sgber 454235537Sgber return (0); 455235537Sgber} 456235537Sgber 457235537Sgberstatic int 458235537Sgbersend_end_program_page(device_t nandbus, uint8_t end_command) 459235537Sgber{ 460235537Sgber 461235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, end_command)) 462235537Sgber return (ENXIO); 463235537Sgber 464235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 465235537Sgber return (ENXIO); 466235537Sgber 467235537Sgber return (0); 468235537Sgber} 469235537Sgber 470235537Sgberstatic int 471235537Sgbergeneric_program_page(device_t nand, uint32_t page, void *buf, uint32_t len, 472235537Sgber uint32_t offset) 473235537Sgber{ 474235537Sgber struct nand_chip *chip; 475235537Sgber struct page_stat *pg_stat; 476235537Sgber device_t nandbus; 477235537Sgber uint32_t row; 478235537Sgber 479235537Sgber nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, 480235537Sgber offset); 481235537Sgber chip = device_get_softc(nand); 482235537Sgber nandbus = device_get_parent(nand); 483235537Sgber 484235537Sgber if (nand_check_page_boundary(chip, page)) 485235537Sgber return (ENXIO); 486235537Sgber 487235537Sgber page_to_row(&chip->chip_geom, page, &row); 488235537Sgber 489235537Sgber if (!can_write(nandbus)) 490235537Sgber return (ENXIO); 491235537Sgber 492235537Sgber if (send_start_program_page(nand, row, offset)) 493235537Sgber return (ENXIO); 494235537Sgber 495235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, len); 496235537Sgber 497235537Sgber if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) 498235537Sgber return (ENXIO); 499235537Sgber 500235537Sgber DELAY(chip->t_prog); 501235537Sgber 502235537Sgber if (check_fail(nandbus)) 503235537Sgber return (ENXIO); 504235537Sgber 505235537Sgber pg_stat = &(chip->pg_stat[page]); 506235537Sgber pg_stat->page_raw_written++; 507235537Sgber 508235537Sgber return (0); 509235537Sgber} 510235537Sgber 511235537Sgberstatic int 512235537Sgbergeneric_program_page_intlv(device_t nand, uint32_t page, void *buf, 513235537Sgber uint32_t len, uint32_t offset) 514235537Sgber{ 515235537Sgber struct nand_chip *chip; 516235537Sgber struct page_stat *pg_stat; 517235537Sgber device_t nandbus; 518235537Sgber uint32_t row; 519235537Sgber 520235537Sgber nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, offset); 521235537Sgber chip = device_get_softc(nand); 522235537Sgber nandbus = device_get_parent(nand); 523235537Sgber 524235537Sgber if (nand_check_page_boundary(chip, page)) 525235537Sgber return (ENXIO); 526235537Sgber 527235537Sgber page_to_row(&chip->chip_geom, page, &row); 528235537Sgber 529235537Sgber if (!can_write(nandbus)) 530235537Sgber return (ENXIO); 531235537Sgber 532235537Sgber if (send_start_program_page(nand, row, offset)) 533235537Sgber return (ENXIO); 534235537Sgber 535235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, len); 536235537Sgber 537235537Sgber if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) 538235537Sgber return (ENXIO); 539235537Sgber 540235537Sgber DELAY(chip->t_prog); 541235537Sgber 542235537Sgber if (check_fail(nandbus)) 543235537Sgber return (ENXIO); 544235537Sgber 545235537Sgber pg_stat = &(chip->pg_stat[page]); 546235537Sgber pg_stat->page_raw_written++; 547235537Sgber 548235537Sgber return (0); 549235537Sgber} 550235537Sgber 551235537Sgberstatic int 552235537Sgbergeneric_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, 553235537Sgber uint32_t offset) 554235537Sgber{ 555235537Sgber struct nand_chip *chip; 556235537Sgber device_t nandbus; 557235537Sgber uint32_t row; 558235537Sgber 559235537Sgber nand_debug(NDBG_GEN,"%p raw prog oob %x[%x] at %x", nand, page, len, 560235537Sgber offset); 561235537Sgber chip = device_get_softc(nand); 562235537Sgber nandbus = device_get_parent(nand); 563235537Sgber 564235537Sgber if (nand_check_page_boundary(chip, page)) 565235537Sgber return (ENXIO); 566235537Sgber 567235537Sgber page_to_row(&chip->chip_geom, page, &row); 568235537Sgber offset += chip->chip_geom.page_size; 569235537Sgber 570235537Sgber if (!can_write(nandbus)) 571235537Sgber return (ENXIO); 572235537Sgber 573235537Sgber if (send_start_program_page(nand, row, offset)) 574235537Sgber return (ENXIO); 575235537Sgber 576235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, len); 577235537Sgber 578235537Sgber if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) 579235537Sgber return (ENXIO); 580235537Sgber 581235537Sgber DELAY(chip->t_prog); 582235537Sgber 583235537Sgber if (check_fail(nandbus)) 584235537Sgber return (ENXIO); 585235537Sgber 586235537Sgber return (0); 587235537Sgber} 588235537Sgber 589235537Sgberstatic int 590235537Sgbersend_erase_block(device_t nand, uint32_t row, uint8_t second_command) 591235537Sgber{ 592235537Sgber device_t nandbus = device_get_parent(nand); 593235537Sgber 594235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_ERASE)) 595235537Sgber return (ENXIO); 596235537Sgber 597235537Sgber if (nand_send_address(nand, row, -1, -1)) 598235537Sgber return (ENXIO); 599235537Sgber 600235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, second_command)) 601235537Sgber return (ENXIO); 602235537Sgber 603235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 604235537Sgber return (ENXIO); 605235537Sgber 606235537Sgber return (0); 607235537Sgber} 608235537Sgber 609235537Sgberstatic int 610235537Sgbergeneric_erase_block(device_t nand, uint32_t block) 611235537Sgber{ 612235537Sgber struct block_stat *blk_stat; 613235537Sgber struct nand_chip *chip; 614235537Sgber device_t nandbus; 615235537Sgber int row; 616235537Sgber 617235537Sgber nand_debug(NDBG_GEN,"%p erase block %x", nand, block); 618235537Sgber nandbus = device_get_parent(nand); 619235537Sgber chip = device_get_softc(nand); 620235537Sgber 621235537Sgber if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) 622235537Sgber return (ENXIO); 623235537Sgber 624235537Sgber row = (block << chip->chip_geom.blk_shift) & 625235537Sgber chip->chip_geom.blk_mask; 626235537Sgber 627235537Sgber nand_debug(NDBG_GEN,"%p erase block row %x", nand, row); 628235537Sgber 629235537Sgber if (!can_write(nandbus)) 630235537Sgber return (ENXIO); 631235537Sgber 632235537Sgber send_erase_block(nand, row, NAND_CMD_ERASE_END); 633235537Sgber 634235537Sgber DELAY(chip->t_bers); 635235537Sgber 636235537Sgber if (check_fail(nandbus)) 637235537Sgber return (ENXIO); 638235537Sgber 639235537Sgber blk_stat = &(chip->blk_stat[block]); 640235537Sgber blk_stat->block_erased++; 641235537Sgber 642235537Sgber return (0); 643235537Sgber} 644235537Sgber 645235537Sgberstatic int 646235537Sgbergeneric_erase_block_intlv(device_t nand, uint32_t block) 647235537Sgber{ 648235537Sgber struct block_stat *blk_stat; 649235537Sgber struct nand_chip *chip; 650235537Sgber device_t nandbus; 651235537Sgber int row; 652235537Sgber 653235537Sgber nand_debug(NDBG_GEN,"%p erase block %x", nand, block); 654235537Sgber nandbus = device_get_parent(nand); 655235537Sgber chip = device_get_softc(nand); 656235537Sgber 657235537Sgber if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) 658235537Sgber return (ENXIO); 659235537Sgber 660235537Sgber row = (block << chip->chip_geom.blk_shift) & 661235537Sgber chip->chip_geom.blk_mask; 662235537Sgber 663235537Sgber if (!can_write(nandbus)) 664235537Sgber return (ENXIO); 665235537Sgber 666235537Sgber send_erase_block(nand, row, NAND_CMD_ERASE_INTLV); 667235537Sgber 668235537Sgber DELAY(chip->t_bers); 669235537Sgber 670235537Sgber if (check_fail(nandbus)) 671235537Sgber return (ENXIO); 672235537Sgber 673235537Sgber blk_stat = &(chip->blk_stat[block]); 674235537Sgber blk_stat->block_erased++; 675235537Sgber 676235537Sgber return (0); 677235537Sgber 678235537Sgber} 679235537Sgber 680235537Sgberstatic int 681235537Sgberonfi_is_blk_bad(device_t device, uint32_t block_number, uint8_t *bad) 682235537Sgber{ 683235537Sgber struct nand_chip *chip; 684235537Sgber int page_number, i, j, err; 685235537Sgber uint8_t *oob; 686235537Sgber 687235537Sgber chip = device_get_softc(device); 688235537Sgber 689235537Sgber oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); 690235537Sgber if (!oob) { 691235537Sgber device_printf(device, "%s: cannot allocate oob\n", __func__); 692235537Sgber return (ENOMEM); 693235537Sgber } 694235537Sgber 695235537Sgber page_number = block_number * chip->chip_geom.pgs_per_blk; 696235537Sgber *bad = 0; 697235537Sgber /* Check OOB of first and last page */ 698235537Sgber for (i = 0; i < 2; i++, page_number+= chip->chip_geom.pgs_per_blk - 1) { 699235537Sgber err = generic_read_oob(device, page_number, oob, 700235537Sgber chip->chip_geom.oob_size, 0); 701235537Sgber if (err) { 702235537Sgber device_printf(device, "%s: cannot allocate oob\n", 703235537Sgber __func__); 704235537Sgber free(oob, M_NAND); 705235537Sgber return (ENOMEM); 706235537Sgber } 707235537Sgber 708235537Sgber for (j = 0; j < chip->chip_geom.oob_size; j++) { 709235537Sgber if (!oob[j]) { 710235537Sgber *bad = 1; 711235537Sgber free(oob, M_NAND); 712235537Sgber return (0); 713235537Sgber } 714235537Sgber } 715235537Sgber } 716235537Sgber 717235537Sgber free(oob, M_NAND); 718235537Sgber 719235537Sgber return (0); 720235537Sgber} 721235537Sgber 722235537Sgberstatic int 723235537Sgbersend_small_read_page(device_t nand, uint8_t start_command, 724235537Sgber uint32_t row, uint32_t column) 725235537Sgber{ 726235537Sgber device_t nandbus = device_get_parent(nand); 727235537Sgber 728235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, start_command)) 729235537Sgber return (ENXIO); 730235537Sgber 731235537Sgber if (nand_send_address(nand, row, column, -1)) 732235537Sgber return (ENXIO); 733235537Sgber 734235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 735235537Sgber return (ENXIO); 736235537Sgber 737235537Sgber return (0); 738235537Sgber} 739235537Sgber 740235537Sgber 741235537Sgberstatic int 742235537Sgbersmall_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, 743235537Sgber uint32_t offset) 744235537Sgber{ 745235537Sgber struct nand_chip *chip; 746235537Sgber struct page_stat *pg_stat; 747235537Sgber device_t nandbus; 748235537Sgber uint32_t row; 749235537Sgber 750235537Sgber nand_debug(NDBG_GEN,"%p small read page %x[%x] at %x", nand, page, len, offset); 751235537Sgber chip = device_get_softc(nand); 752235537Sgber nandbus = device_get_parent(nand); 753235537Sgber 754235537Sgber if (nand_check_page_boundary(chip, page)) 755235537Sgber return (ENXIO); 756235537Sgber 757235537Sgber page_to_row(&chip->chip_geom, page, &row); 758235537Sgber 759235537Sgber if (offset < 256) { 760235537Sgber if (send_small_read_page(nand, NAND_CMD_SMALLA, row, offset)) 761235537Sgber return (ENXIO); 762235537Sgber } else { 763235537Sgber offset -= 256; 764235537Sgber if (send_small_read_page(nandbus, NAND_CMD_SMALLB, row, offset)) 765235537Sgber return (ENXIO); 766235537Sgber } 767235537Sgber 768235537Sgber DELAY(chip->t_r); 769235537Sgber 770235537Sgber NANDBUS_READ_BUFFER(nandbus, buf, len); 771235537Sgber 772235537Sgber if (check_fail(nandbus)) 773235537Sgber return (ENXIO); 774235537Sgber 775235537Sgber pg_stat = &(chip->pg_stat[page]); 776235537Sgber pg_stat->page_raw_read++; 777235537Sgber 778235537Sgber return (0); 779235537Sgber} 780235537Sgber 781235537Sgberstatic int 782235537Sgbersmall_read_oob(device_t nand, uint32_t page, void *buf, uint32_t len, 783235537Sgber uint32_t offset) 784235537Sgber{ 785235537Sgber struct nand_chip *chip; 786235537Sgber struct page_stat *pg_stat; 787235537Sgber device_t nandbus; 788235537Sgber uint32_t row; 789235537Sgber 790235537Sgber nand_debug(NDBG_GEN,"%p small read oob %x[%x] at %x", nand, page, len, offset); 791235537Sgber chip = device_get_softc(nand); 792235537Sgber nandbus = device_get_parent(nand); 793235537Sgber 794235537Sgber if (nand_check_page_boundary(chip, page)) 795235537Sgber return (ENXIO); 796235537Sgber 797235537Sgber page_to_row(&chip->chip_geom, page, &row); 798235537Sgber 799235537Sgber if (send_small_read_page(nand, NAND_CMD_SMALLOOB, row, 0)) 800235537Sgber return (ENXIO); 801235537Sgber 802235537Sgber DELAY(chip->t_r); 803235537Sgber 804235537Sgber NANDBUS_READ_BUFFER(nandbus, buf, len); 805235537Sgber 806235537Sgber if (check_fail(nandbus)) 807235537Sgber return (ENXIO); 808235537Sgber 809235537Sgber pg_stat = &(chip->pg_stat[page]); 810235537Sgber pg_stat->page_raw_read++; 811235537Sgber 812235537Sgber return (0); 813235537Sgber} 814235537Sgber 815235537Sgberstatic int 816235537Sgbersmall_program_page(device_t nand, uint32_t page, void* buf, uint32_t len, 817235537Sgber uint32_t offset) 818235537Sgber{ 819235537Sgber struct nand_chip *chip; 820235537Sgber device_t nandbus; 821235537Sgber uint32_t row; 822235537Sgber 823235537Sgber nand_debug(NDBG_GEN,"%p small prog page %x[%x] at %x", nand, page, len, offset); 824235537Sgber chip = device_get_softc(nand); 825235537Sgber nandbus = device_get_parent(nand); 826235537Sgber 827235537Sgber if (nand_check_page_boundary(chip, page)) 828235537Sgber return (ENXIO); 829235537Sgber 830235537Sgber page_to_row(&chip->chip_geom, page, &row); 831235537Sgber 832235537Sgber if (!can_write(nandbus)) 833235537Sgber return (ENXIO); 834235537Sgber 835235537Sgber if (offset < 256) { 836235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLA)) 837235537Sgber return (ENXIO); 838235537Sgber } else { 839235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLB)) 840235537Sgber return (ENXIO); 841235537Sgber } 842235537Sgber 843235537Sgber if (send_start_program_page(nand, row, offset)) 844235537Sgber return (ENXIO); 845235537Sgber 846235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, len); 847235537Sgber 848235537Sgber if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) 849235537Sgber return (ENXIO); 850235537Sgber 851235537Sgber DELAY(chip->t_prog); 852235537Sgber 853235537Sgber if (check_fail(nandbus)) 854235537Sgber return (ENXIO); 855235537Sgber 856235537Sgber return (0); 857235537Sgber} 858235537Sgber 859235537Sgberstatic int 860235537Sgbersmall_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, 861235537Sgber uint32_t offset) 862235537Sgber{ 863235537Sgber struct nand_chip *chip; 864235537Sgber device_t nandbus; 865235537Sgber uint32_t row; 866235537Sgber 867235537Sgber nand_debug(NDBG_GEN,"%p small prog oob %x[%x] at %x", nand, page, len, offset); 868235537Sgber chip = device_get_softc(nand); 869235537Sgber nandbus = device_get_parent(nand); 870235537Sgber 871235537Sgber if (nand_check_page_boundary(chip, page)) 872235537Sgber return (ENXIO); 873235537Sgber 874235537Sgber page_to_row(&chip->chip_geom, page, &row); 875235537Sgber 876235537Sgber if (!can_write(nandbus)) 877235537Sgber return (ENXIO); 878235537Sgber 879235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLOOB)) 880235537Sgber return (ENXIO); 881235537Sgber 882235537Sgber if (send_start_program_page(nand, row, offset)) 883235537Sgber return (ENXIO); 884235537Sgber 885235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, len); 886235537Sgber 887235537Sgber if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) 888235537Sgber return (ENXIO); 889235537Sgber 890235537Sgber DELAY(chip->t_prog); 891235537Sgber 892235537Sgber if (check_fail(nandbus)) 893235537Sgber return (ENXIO); 894235537Sgber 895235537Sgber return (0); 896235537Sgber} 897235537Sgber 898235537Sgberint 899235537Sgbernand_send_address(device_t nand, int32_t row, int32_t col, int8_t id) 900235537Sgber{ 901235537Sgber struct nandbus_ivar *ivar; 902235537Sgber device_t nandbus; 903235537Sgber uint8_t addr; 904235537Sgber int err = 0; 905235537Sgber int i; 906235537Sgber 907235537Sgber nandbus = device_get_parent(nand); 908235537Sgber ivar = device_get_ivars(nand); 909235537Sgber 910235537Sgber if (id != -1) { 911235537Sgber nand_debug(NDBG_GEN,"send_address: send id %02x", id); 912235537Sgber err = NANDBUS_SEND_ADDRESS(nandbus, id); 913235537Sgber } 914235537Sgber 915235537Sgber if (!err && col != -1) { 916235537Sgber for (i = 0; i < ivar->cols; i++, col >>= 8) { 917235537Sgber addr = (uint8_t)(col & 0xff); 918235537Sgber nand_debug(NDBG_GEN,"send_address: send address column " 919235537Sgber "%02x", addr); 920235537Sgber err = NANDBUS_SEND_ADDRESS(nandbus, addr); 921235537Sgber if (err) 922235537Sgber break; 923235537Sgber } 924235537Sgber } 925235537Sgber 926235537Sgber if (!err && row != -1) { 927235537Sgber for (i = 0; i < ivar->rows; i++, row >>= 8) { 928235537Sgber addr = (uint8_t)(row & 0xff); 929235537Sgber nand_debug(NDBG_GEN,"send_address: send address row " 930235537Sgber "%02x", addr); 931235537Sgber err = NANDBUS_SEND_ADDRESS(nandbus, addr); 932235537Sgber if (err) 933235537Sgber break; 934235537Sgber } 935235537Sgber } 936235537Sgber 937235537Sgber return (err); 938235537Sgber} 939235537Sgber 940235537Sgberstatic int 941235537Sgbergeneric_is_blk_bad(device_t dev, uint32_t block, uint8_t *bad) 942235537Sgber{ 943235537Sgber struct nand_chip *chip; 944235537Sgber int page_number, err, i; 945235537Sgber uint8_t *oob; 946235537Sgber 947235537Sgber chip = device_get_softc(dev); 948235537Sgber 949235537Sgber oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); 950235537Sgber if (!oob) { 951235537Sgber device_printf(dev, "%s: cannot allocate OOB\n", __func__); 952235537Sgber return (ENOMEM); 953235537Sgber } 954235537Sgber 955235537Sgber page_number = block * chip->chip_geom.pgs_per_blk; 956235537Sgber *bad = 0; 957235537Sgber 958235537Sgber /* Check OOB of first and second page */ 959235537Sgber for (i = 0; i < 2; i++) { 960235537Sgber err = NAND_READ_OOB(dev, page_number + i, oob, 961235537Sgber chip->chip_geom.oob_size, 0); 962235537Sgber if (err) { 963235537Sgber device_printf(dev, "%s: cannot allocate OOB\n", 964235537Sgber __func__); 965235537Sgber free(oob, M_NAND); 966235537Sgber return (ENOMEM); 967235537Sgber } 968235537Sgber 969235537Sgber if (!oob[0]) { 970235537Sgber *bad = 1; 971235537Sgber free(oob, M_NAND); 972235537Sgber return (0); 973235537Sgber } 974235537Sgber } 975235537Sgber 976235537Sgber free(oob, M_NAND); 977235537Sgber 978235537Sgber return (0); 979235537Sgber} 980235537Sgber 981235537Sgberstatic int 982235537Sgbergeneric_get_ecc(device_t dev, void *buf, void *ecc, int *needwrite) 983235537Sgber{ 984235537Sgber struct nand_chip *chip = device_get_softc(dev); 985235537Sgber struct chip_geom *cg = &chip->chip_geom; 986235537Sgber 987235537Sgber return (NANDBUS_GET_ECC(device_get_parent(dev), buf, cg->page_size, 988235537Sgber ecc, needwrite)); 989235537Sgber} 990235537Sgber 991235537Sgberstatic int 992235537Sgbergeneric_correct_ecc(device_t dev, void *buf, void *readecc, void *calcecc) 993235537Sgber{ 994235537Sgber struct nand_chip *chip = device_get_softc(dev); 995235537Sgber struct chip_geom *cg = &chip->chip_geom; 996235537Sgber 997235537Sgber return (NANDBUS_CORRECT_ECC(device_get_parent(dev), buf, 998235537Sgber cg->page_size, readecc, calcecc)); 999235537Sgber} 1000235537Sgber 1001235537Sgber 1002235537Sgber#if 0 1003235537Sgberint 1004235537Sgbernand_chng_read_col(device_t nand, uint32_t col, void *buf, size_t len) 1005235537Sgber{ 1006235537Sgber struct nand_chip *chip; 1007235537Sgber device_t nandbus; 1008235537Sgber 1009235537Sgber chip = device_get_softc(nand); 1010235537Sgber nandbus = device_get_parent(nand); 1011235537Sgber 1012235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL)) 1013235537Sgber return (ENXIO); 1014235537Sgber 1015235537Sgber if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) 1016235537Sgber return (ENXIO); 1017235537Sgber 1018235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) 1019235537Sgber return (ENXIO); 1020235537Sgber 1021235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 1022235537Sgber return (ENXIO); 1023235537Sgber 1024235537Sgber if (buf != NULL && len > 0) 1025235537Sgber NANDBUS_READ_BUFFER(nandbus, buf, len); 1026235537Sgber 1027235537Sgber return (0); 1028235537Sgber} 1029235537Sgber 1030235537Sgberint 1031235537Sgbernand_chng_write_col(device_t dev, uint32_t col, void *buf, 1032235537Sgber size_t len) 1033235537Sgber{ 1034235537Sgber struct nand_chip *chip; 1035235537Sgber device_t nandbus; 1036235537Sgber 1037235537Sgber chip = device_get_softc(dev); 1038235537Sgber nandbus = device_get_parent(dev); 1039235537Sgber 1040235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) 1041235537Sgber return (ENXIO); 1042235537Sgber 1043235537Sgber if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) 1044235537Sgber return (ENXIO); 1045235537Sgber 1046235537Sgber if (buf != NULL && len > 0) 1047235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, len); 1048235537Sgber 1049235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) 1050235537Sgber return (ENXIO); 1051235537Sgber 1052235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 1053235537Sgber return (ENXIO); 1054235537Sgber 1055235537Sgber return (0); 1056235537Sgber} 1057235537Sgber 1058235537Sgberint 1059235537Sgbernand_copyback_read(device_t dev, uint32_t page, uint32_t col, 1060235537Sgber void *buf, size_t len) 1061235537Sgber{ 1062235537Sgber struct nand_chip *chip; 1063235537Sgber struct page_stat *pg_stat; 1064235537Sgber device_t nandbus; 1065235537Sgber uint32_t row; 1066235537Sgber 1067235537Sgber nand_debug(NDBG_GEN," raw read page %x[%x] at %x", page, col, len); 1068235537Sgber chip = device_get_softc(dev); 1069235537Sgber nandbus = device_get_parent(dev); 1070235537Sgber 1071235537Sgber if (nand_check_page_boundary(chip, page)) 1072235537Sgber return (ENXIO); 1073235537Sgber 1074235537Sgber page_to_row(&chip->chip_geom, page, &row); 1075235537Sgber 1076235537Sgber if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_CPBK, row, 0)) 1077235537Sgber return (ENXIO); 1078235537Sgber 1079235537Sgber DELAY(chip->t_r); 1080235537Sgber if (check_fail(nandbus)) 1081235537Sgber return (ENXIO); 1082235537Sgber 1083235537Sgber if (buf != NULL && len > 0) 1084235537Sgber NANDBUS_READ_BUFFER(nandbus, buf, len); 1085235537Sgber 1086235537Sgber pg_stat = &(chip->pg_stat[page]); 1087235537Sgber pg_stat->page_raw_read++; 1088235537Sgber 1089235537Sgber return (0); 1090235537Sgber} 1091235537Sgber 1092235537Sgberint 1093235537Sgbernand_copyback_prog(device_t dev, uint32_t page, uint32_t col, 1094235537Sgber void *buf, size_t len) 1095235537Sgber{ 1096235537Sgber struct nand_chip *chip; 1097235537Sgber struct page_stat *pg_stat; 1098235537Sgber device_t nandbus; 1099235537Sgber uint32_t row; 1100235537Sgber 1101235537Sgber nand_debug(NDBG_GEN,"copyback prog page %x[%x]", page, len); 1102235537Sgber chip = device_get_softc(dev); 1103235537Sgber nandbus = device_get_parent(dev); 1104235537Sgber 1105235537Sgber if (nand_check_page_boundary(chip, page)) 1106235537Sgber return (ENXIO); 1107235537Sgber 1108235537Sgber page_to_row(&chip->chip_geom, page, &row); 1109235537Sgber 1110235537Sgber if (!can_write(nandbus)) 1111235537Sgber return (ENXIO); 1112235537Sgber 1113235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) 1114235537Sgber return (ENXIO); 1115235537Sgber 1116235537Sgber if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) 1117235537Sgber return (ENXIO); 1118235537Sgber 1119235537Sgber if (buf != NULL && len > 0) 1120235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, len); 1121235537Sgber 1122235537Sgber if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) 1123235537Sgber return (ENXIO); 1124235537Sgber 1125235537Sgber DELAY(chip->t_prog); 1126235537Sgber 1127235537Sgber if (check_fail(nandbus)) 1128235537Sgber return (ENXIO); 1129235537Sgber 1130235537Sgber pg_stat = &(chip->pg_stat[page]); 1131235537Sgber pg_stat->page_raw_written++; 1132235537Sgber 1133235537Sgber return (0); 1134235537Sgber} 1135235537Sgber 1136235537Sgberint 1137235537Sgbernand_copyback_prog_intlv(device_t dev, uint32_t page) 1138235537Sgber{ 1139235537Sgber struct nand_chip *chip; 1140235537Sgber struct page_stat *pg_stat; 1141235537Sgber device_t nandbus; 1142235537Sgber uint32_t row; 1143235537Sgber 1144235537Sgber nand_debug(NDBG_GEN,"cache prog page %x", page); 1145235537Sgber chip = device_get_softc(dev); 1146235537Sgber nandbus = device_get_parent(dev); 1147235537Sgber 1148235537Sgber if (nand_check_page_boundary(chip, page)) 1149235537Sgber return (ENXIO); 1150235537Sgber 1151235537Sgber page_to_row(&chip->chip_geom, page, &row); 1152235537Sgber 1153235537Sgber if (!can_write(nandbus)) 1154235537Sgber return (ENXIO); 1155235537Sgber 1156235537Sgber if (send_start_program_page(nand, row, 0)) 1157235537Sgber return (ENXIO); 1158235537Sgber 1159235537Sgber if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) 1160235537Sgber return (ENXIO); 1161235537Sgber 1162235537Sgber DELAY(chip->t_prog); 1163235537Sgber 1164235537Sgber if (check_fail(nandbus)) 1165235537Sgber return (ENXIO); 1166235537Sgber 1167235537Sgber pg_stat = &(chip->pg_stat[page]); 1168235537Sgber pg_stat->page_raw_written++; 1169235537Sgber 1170235537Sgber return (0); 1171235537Sgber} 1172235537Sgber 1173235537Sgberint 1174235537Sgbernand_prog_cache(device_t dev, uint32_t page, uint32_t col, 1175235537Sgber void *buf, size_t len, uint8_t end) 1176235537Sgber{ 1177235537Sgber struct nand_chip *chip; 1178235537Sgber struct page_stat *pg_stat; 1179235537Sgber device_t nandbus; 1180235537Sgber uint32_t row; 1181235537Sgber uint8_t command; 1182235537Sgber 1183235537Sgber nand_debug(NDBG_GEN,"cache prog page %x[%x]", page, len); 1184235537Sgber chip = device_get_softc(dev); 1185235537Sgber nandbus = device_get_parent(dev); 1186235537Sgber 1187235537Sgber if (nand_check_page_boundary(chip, page)) 1188235537Sgber return (ENXIO); 1189235537Sgber 1190235537Sgber page_to_row(&chip->chip_geom, page, &row); 1191235537Sgber 1192235537Sgber if (!can_write(nandbus)) 1193235537Sgber return (ENXIO); 1194235537Sgber 1195235537Sgber if (send_start_program_page(dev, row, 0)) 1196235537Sgber return (ENXIO); 1197235537Sgber 1198235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, len); 1199235537Sgber 1200235537Sgber if (end) 1201235537Sgber command = NAND_CMD_PROG_END; 1202235537Sgber else 1203235537Sgber command = NAND_CMD_PROG_CACHE; 1204235537Sgber 1205235537Sgber if (send_end_program_page(nandbus, command)) 1206235537Sgber return (ENXIO); 1207235537Sgber 1208235537Sgber DELAY(chip->t_prog); 1209235537Sgber 1210235537Sgber if (check_fail(nandbus)) 1211235537Sgber return (ENXIO); 1212235537Sgber 1213235537Sgber pg_stat = &(chip->pg_stat[page]); 1214235537Sgber pg_stat->page_raw_written++; 1215235537Sgber 1216235537Sgber return (0); 1217235537Sgber} 1218235537Sgber 1219235537Sgberint 1220235537Sgbernand_read_cache(device_t dev, uint32_t page, uint32_t col, 1221235537Sgber void *buf, size_t len, uint8_t end) 1222235537Sgber{ 1223235537Sgber struct nand_chip *chip; 1224235537Sgber struct page_stat *pg_stat; 1225235537Sgber device_t nandbus; 1226235537Sgber uint32_t row; 1227235537Sgber uint8_t command; 1228235537Sgber 1229235537Sgber nand_debug(NDBG_GEN,"cache read page %x[%x] ", page, len); 1230235537Sgber chip = device_get_softc(dev); 1231235537Sgber nandbus = device_get_parent(dev); 1232235537Sgber 1233235537Sgber if (nand_check_page_boundary(chip, page)) 1234235537Sgber return (ENXIO); 1235235537Sgber 1236235537Sgber page_to_row(&chip->chip_geom, page, &row); 1237235537Sgber 1238235537Sgber if (page != -1) { 1239235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ)) 1240235537Sgber return (ENXIO); 1241235537Sgber 1242235537Sgber if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) 1243235537Sgber return (ENXIO); 1244235537Sgber } 1245235537Sgber 1246235537Sgber if (end) 1247235537Sgber command = NAND_CMD_READ_CACHE_END; 1248235537Sgber else 1249235537Sgber command = NAND_CMD_READ_CACHE; 1250235537Sgber 1251235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, command)) 1252235537Sgber return (ENXIO); 1253235537Sgber 1254235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 1255235537Sgber return (ENXIO); 1256235537Sgber 1257235537Sgber DELAY(chip->t_r); 1258235537Sgber if (check_fail(nandbus)) 1259235537Sgber return (ENXIO); 1260235537Sgber 1261235537Sgber if (buf != NULL && len > 0) 1262235537Sgber NANDBUS_READ_BUFFER(nandbus, buf, len); 1263235537Sgber 1264235537Sgber pg_stat = &(chip->pg_stat[page]); 1265235537Sgber pg_stat->page_raw_read++; 1266235537Sgber 1267235537Sgber return (0); 1268235537Sgber} 1269235537Sgber 1270235537Sgberint 1271235537Sgbernand_get_feature(device_t dev, uint8_t feat, void *buf) 1272235537Sgber{ 1273235537Sgber struct nand_chip *chip; 1274235537Sgber device_t nandbus; 1275235537Sgber 1276235537Sgber nand_debug(NDBG_GEN,"nand get feature"); 1277235537Sgber 1278235537Sgber chip = device_get_softc(dev); 1279235537Sgber nandbus = device_get_parent(dev); 1280235537Sgber 1281235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_GET_FEATURE)) 1282235537Sgber return (ENXIO); 1283235537Sgber 1284235537Sgber if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) 1285235537Sgber return (ENXIO); 1286235537Sgber 1287235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 1288235537Sgber return (ENXIO); 1289235537Sgber 1290235537Sgber DELAY(chip->t_r); 1291235537Sgber NANDBUS_READ_BUFFER(nandbus, buf, 4); 1292235537Sgber 1293235537Sgber return (0); 1294235537Sgber} 1295235537Sgber 1296235537Sgberint 1297235537Sgbernand_set_feature(device_t dev, uint8_t feat, void *buf) 1298235537Sgber{ 1299235537Sgber struct nand_chip *chip; 1300235537Sgber device_t nandbus; 1301235537Sgber 1302235537Sgber nand_debug(NDBG_GEN,"nand set feature"); 1303235537Sgber 1304235537Sgber chip = device_get_softc(dev); 1305235537Sgber nandbus = device_get_parent(dev); 1306235537Sgber 1307235537Sgber if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SET_FEATURE)) 1308235537Sgber return (ENXIO); 1309235537Sgber 1310235537Sgber if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) 1311235537Sgber return (ENXIO); 1312235537Sgber 1313235537Sgber NANDBUS_WRITE_BUFFER(nandbus, buf, 4); 1314235537Sgber 1315235537Sgber if (NANDBUS_START_COMMAND(nandbus)) 1316235537Sgber return (ENXIO); 1317235537Sgber 1318235537Sgber return (0); 1319235537Sgber} 1320235537Sgber#endif 1321