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 * $FreeBSD$ 27235537Sgber */ 28235537Sgber 29235537Sgber#include <sys/cdefs.h> 30235537Sgber 31235537Sgber#include <sys/param.h> 32235537Sgber#include <sys/systm.h> 33235537Sgber#include <sys/kernel.h> 34235537Sgber#include <sys/socket.h> 35235537Sgber#include <sys/malloc.h> 36235537Sgber#include <sys/bus.h> 37235537Sgber 38235537Sgber#include <dev/nand/nand.h> 39235537Sgber 40235537Sgber#include "nand_if.h" 41235537Sgber 42235537Sgber#define BBT_PRIMARY_PATTERN 0x01020304 43235537Sgber#define BBT_SECONDARY_PATTERN 0x05060708 44235537Sgber 45235537Sgberenum bbt_place { 46235537Sgber BBT_NONE, 47235537Sgber BBT_PRIMARY, 48235537Sgber BBT_SECONDARY 49235537Sgber}; 50235537Sgber 51235537Sgberstruct nand_bbt { 52235537Sgber struct nand_chip *chip; 53235537Sgber uint32_t primary_map; 54235537Sgber uint32_t secondary_map; 55235537Sgber enum bbt_place active; 56235537Sgber struct bbt_header *hdr; 57235537Sgber uint32_t tab_len; 58235537Sgber uint32_t *table; 59235537Sgber}; 60235537Sgber 61235537Sgberstruct bbt_header { 62235537Sgber uint32_t pattern; 63235537Sgber int32_t seq_nr; 64235537Sgber}; 65235537Sgber 66235537Sgberstatic int nand_bbt_save(struct nand_bbt *); 67235537Sgberstatic int nand_bbt_load_hdr(struct nand_bbt *, struct bbt_header *, int8_t); 68235537Sgberstatic int nand_bbt_load_table(struct nand_bbt *); 69235537Sgberstatic int nand_bbt_prescan(struct nand_bbt *); 70235537Sgber 71235537Sgberint 72235537Sgbernand_init_bbt(struct nand_chip *chip) 73235537Sgber{ 74235537Sgber struct chip_geom *cg; 75235537Sgber struct nand_bbt *bbt; 76235537Sgber int err; 77235537Sgber 78235537Sgber cg = &chip->chip_geom; 79235537Sgber 80235537Sgber bbt = malloc(sizeof(struct nand_bbt), M_NAND, M_ZERO | M_WAITOK); 81235537Sgber if (!bbt) { 82235537Sgber device_printf(chip->dev, 83235537Sgber "Cannot allocate memory for bad block struct"); 84235537Sgber return (ENOMEM); 85235537Sgber } 86235537Sgber 87235537Sgber bbt->chip = chip; 88235537Sgber bbt->active = BBT_NONE; 89235537Sgber bbt->primary_map = cg->chip_size - cg->block_size; 90235537Sgber bbt->secondary_map = cg->chip_size - 2 * cg->block_size; 91235537Sgber bbt->tab_len = cg->blks_per_chip * sizeof(uint32_t); 92235537Sgber bbt->hdr = malloc(sizeof(struct bbt_header) + bbt->tab_len, M_NAND, 93235537Sgber M_WAITOK); 94235537Sgber if (!bbt->hdr) { 95235537Sgber device_printf(chip->dev, "Cannot allocate %d bytes for BB " 96235537Sgber "Table", bbt->tab_len); 97235537Sgber free(bbt, M_NAND); 98235537Sgber return (ENOMEM); 99235537Sgber } 100235537Sgber bbt->hdr->seq_nr = 0; 101235537Sgber bbt->table = (uint32_t *)((uint8_t *)bbt->hdr + 102235537Sgber sizeof(struct bbt_header)); 103235537Sgber 104235537Sgber err = nand_bbt_load_table(bbt); 105235537Sgber if (err) { 106235537Sgber free(bbt->table, M_NAND); 107235537Sgber free(bbt, M_NAND); 108235537Sgber return (err); 109235537Sgber } 110235537Sgber 111235537Sgber chip->bbt = bbt; 112235537Sgber if (bbt->active == BBT_NONE) { 113235537Sgber bbt->active = BBT_PRIMARY; 114235537Sgber memset(bbt->table, 0xff, bbt->tab_len); 115235537Sgber nand_bbt_prescan(bbt); 116235537Sgber nand_bbt_save(bbt); 117235537Sgber } else 118235537Sgber device_printf(chip->dev, "Found BBT table for chip\n"); 119235537Sgber 120235537Sgber return (0); 121235537Sgber} 122235537Sgber 123235537Sgbervoid 124235537Sgbernand_destroy_bbt(struct nand_chip *chip) 125235537Sgber{ 126235537Sgber 127235537Sgber if (chip->bbt) { 128235537Sgber nand_bbt_save(chip->bbt); 129235537Sgber 130235537Sgber free(chip->bbt->hdr, M_NAND); 131235537Sgber free(chip->bbt, M_NAND); 132235537Sgber chip->bbt = NULL; 133235537Sgber } 134235537Sgber} 135235537Sgber 136235537Sgberint 137235537Sgbernand_update_bbt(struct nand_chip *chip) 138235537Sgber{ 139235537Sgber 140235537Sgber nand_bbt_save(chip->bbt); 141235537Sgber 142235537Sgber return (0); 143235537Sgber} 144235537Sgber 145235537Sgberstatic int 146235537Sgbernand_bbt_save(struct nand_bbt *bbt) 147235537Sgber{ 148235537Sgber enum bbt_place next; 149235537Sgber uint32_t addr; 150235537Sgber int32_t err; 151235537Sgber 152235537Sgber if (bbt->active == BBT_PRIMARY) { 153235537Sgber addr = bbt->secondary_map; 154235537Sgber bbt->hdr->pattern = BBT_SECONDARY_PATTERN; 155235537Sgber next = BBT_SECONDARY; 156235537Sgber } else { 157235537Sgber addr = bbt->primary_map; 158235537Sgber bbt->hdr->pattern = BBT_PRIMARY_PATTERN; 159235537Sgber next = BBT_PRIMARY; 160235537Sgber } 161235537Sgber 162235537Sgber err = nand_erase_blocks(bbt->chip, addr, 163235537Sgber bbt->chip->chip_geom.block_size); 164235537Sgber if (err) 165235537Sgber return (err); 166235537Sgber 167235537Sgber bbt->hdr->seq_nr++; 168235537Sgber 169235537Sgber err = nand_prog_pages_raw(bbt->chip, addr, bbt->hdr, 170235537Sgber bbt->tab_len + sizeof(struct bbt_header)); 171235537Sgber if (err) 172235537Sgber return (err); 173235537Sgber 174235537Sgber bbt->active = next; 175235537Sgber return (0); 176235537Sgber} 177235537Sgber 178235537Sgberstatic int 179235537Sgbernand_bbt_load_hdr(struct nand_bbt *bbt, struct bbt_header *hdr, int8_t primary) 180235537Sgber{ 181235537Sgber uint32_t addr; 182235537Sgber 183235537Sgber if (primary) 184235537Sgber addr = bbt->primary_map; 185235537Sgber else 186235537Sgber addr = bbt->secondary_map; 187235537Sgber 188235537Sgber return (nand_read_pages_raw(bbt->chip, addr, hdr, 189235537Sgber sizeof(struct bbt_header))); 190235537Sgber} 191235537Sgber 192235537Sgberstatic int 193235537Sgbernand_bbt_load_table(struct nand_bbt *bbt) 194235537Sgber{ 195235537Sgber struct bbt_header hdr1, hdr2; 196235537Sgber uint32_t address = 0; 197235537Sgber int err = 0; 198235537Sgber 199235537Sgber bzero(&hdr1, sizeof(hdr1)); 200235537Sgber bzero(&hdr2, sizeof(hdr2)); 201235537Sgber 202235537Sgber nand_bbt_load_hdr(bbt, &hdr1, 1); 203235537Sgber if (hdr1.pattern == BBT_PRIMARY_PATTERN) { 204235537Sgber bbt->active = BBT_PRIMARY; 205235537Sgber address = bbt->primary_map; 206235537Sgber } else 207235537Sgber bzero(&hdr1, sizeof(hdr1)); 208235537Sgber 209235537Sgber 210235537Sgber nand_bbt_load_hdr(bbt, &hdr2, 0); 211235537Sgber if ((hdr2.pattern == BBT_SECONDARY_PATTERN) && 212235537Sgber (hdr2.seq_nr > hdr1.seq_nr)) { 213235537Sgber bbt->active = BBT_SECONDARY; 214235537Sgber address = bbt->secondary_map; 215235537Sgber } else 216235537Sgber bzero(&hdr2, sizeof(hdr2)); 217235537Sgber 218235537Sgber if (bbt->active != BBT_NONE) 219235537Sgber err = nand_read_pages_raw(bbt->chip, address, bbt->hdr, 220235537Sgber bbt->tab_len + sizeof(struct bbt_header)); 221235537Sgber 222235537Sgber return (err); 223235537Sgber} 224235537Sgber 225235537Sgberstatic int 226235537Sgbernand_bbt_prescan(struct nand_bbt *bbt) 227235537Sgber{ 228235537Sgber int32_t i; 229235537Sgber uint8_t bad; 230235537Sgber bool printed_hash = 0; 231235537Sgber 232235537Sgber device_printf(bbt->chip->dev, "No BBT found. Prescan chip...\n"); 233235537Sgber for (i = 0; i < bbt->chip->chip_geom.blks_per_chip; i++) { 234235537Sgber if (NAND_IS_BLK_BAD(bbt->chip->dev, i, &bad)) 235235537Sgber return (ENXIO); 236235537Sgber 237235537Sgber if (bad) { 238235537Sgber device_printf(bbt->chip->dev, "Bad block(%d)\n", i); 239235537Sgber bbt->table[i] = 0x0FFFFFFF; 240235537Sgber } 241235537Sgber if (!(i % 100)) { 242235537Sgber printf("#"); 243235537Sgber printed_hash = 1; 244235537Sgber } 245235537Sgber } 246235537Sgber 247235537Sgber if (printed_hash) 248235537Sgber printf("\n"); 249235537Sgber 250235537Sgber return (0); 251235537Sgber} 252235537Sgber 253235537Sgberint 254235537Sgbernand_check_bad_block(struct nand_chip *chip, uint32_t block_number) 255235537Sgber{ 256235537Sgber 257235537Sgber if (!chip || !chip->bbt) 258235537Sgber return (0); 259235537Sgber 260235537Sgber if ((chip->bbt->table[block_number] & 0xF0000000) == 0) 261235537Sgber return (1); 262235537Sgber 263235537Sgber return (0); 264235537Sgber} 265235537Sgber 266235537Sgberint 267235537Sgbernand_mark_bad_block(struct nand_chip *chip, uint32_t block_number) 268235537Sgber{ 269235537Sgber 270235537Sgber chip->bbt->table[block_number] = 0x0FFFFFFF; 271235537Sgber 272235537Sgber return (0); 273235537Sgber} 274