1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2022 MediaTek Inc. All rights reserved. 4 * 5 * Author: Weijie Gao <weijie.gao@mediatek.com> 6 */ 7 8#include <image.h> 9#include <malloc.h> 10#include <linux/sizes.h> 11#include <linux/delay.h> 12#include <linux/mtd/rawnand.h> 13#include "mt7621_nand.h" 14 15static struct mt7621_nfc nfc_dev; 16static u8 *buffer; 17static int nand_valid; 18 19static void nand_command_lp(struct mtd_info *mtd, unsigned int command, 20 int column, int page_addr) 21{ 22 register struct nand_chip *chip = mtd_to_nand(mtd); 23 24 /* Command latch cycle */ 25 chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); 26 27 if (column != -1 || page_addr != -1) { 28 int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; 29 30 /* Serially input address */ 31 if (column != -1) { 32 chip->cmd_ctrl(mtd, column, ctrl); 33 ctrl &= ~NAND_CTRL_CHANGE; 34 if (command != NAND_CMD_READID) 35 chip->cmd_ctrl(mtd, column >> 8, ctrl); 36 } 37 if (page_addr != -1) { 38 chip->cmd_ctrl(mtd, page_addr, ctrl); 39 chip->cmd_ctrl(mtd, page_addr >> 8, 40 NAND_NCE | NAND_ALE); 41 if (chip->options & NAND_ROW_ADDR_3) 42 chip->cmd_ctrl(mtd, page_addr >> 16, 43 NAND_NCE | NAND_ALE); 44 } 45 } 46 chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); 47 48 /* 49 * Program and erase have their own busy handlers status, sequential 50 * in and status need no delay. 51 */ 52 switch (command) { 53 case NAND_CMD_STATUS: 54 case NAND_CMD_READID: 55 case NAND_CMD_SET_FEATURES: 56 return; 57 58 case NAND_CMD_READ0: 59 chip->cmd_ctrl(mtd, NAND_CMD_READSTART, 60 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); 61 chip->cmd_ctrl(mtd, NAND_CMD_NONE, 62 NAND_NCE | NAND_CTRL_CHANGE); 63 } 64 65 /* 66 * Apply this short delay always to ensure that we do wait tWB in 67 * any case on any machine. 68 */ 69 ndelay(100); 70 71 nand_wait_ready(mtd); 72} 73 74static int nfc_read_page_hwecc(struct mtd_info *mtd, void *buf, 75 unsigned int page) 76{ 77 struct nand_chip *chip = mtd_to_nand(mtd); 78 int ret; 79 80 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); 81 82 ret = chip->ecc.read_page(mtd, chip, buf, 1, page); 83 if (ret < 0 || ret > chip->ecc.strength) 84 return -1; 85 86 return 0; 87} 88 89static int nfc_read_oob_hwecc(struct mtd_info *mtd, void *buf, u32 len, 90 unsigned int page) 91{ 92 struct nand_chip *chip = mtd_to_nand(mtd); 93 int ret; 94 95 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); 96 97 ret = chip->ecc.read_page(mtd, chip, NULL, 1, page); 98 if (ret < 0) 99 return -1; 100 101 if (len > mtd->oobsize) 102 len = mtd->oobsize; 103 104 memcpy(buf, chip->oob_poi, len); 105 106 return 0; 107} 108 109static int nfc_check_bad_block(struct mtd_info *mtd, unsigned int page) 110{ 111 struct nand_chip *chip = mtd_to_nand(mtd); 112 u32 pages_per_block, i = 0; 113 int ret; 114 u8 bad; 115 116 pages_per_block = 1 << (mtd->erasesize_shift - mtd->writesize_shift); 117 118 /* Read from first/last page(s) if necessary */ 119 if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) { 120 page += pages_per_block - 1; 121 if (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) 122 page--; 123 } 124 125 do { 126 ret = nfc_read_oob_hwecc(mtd, &bad, 1, page); 127 if (ret) 128 return ret; 129 130 ret = bad != 0xFF; 131 132 i++; 133 page++; 134 } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); 135 136 return ret; 137} 138 139int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) 140{ 141 struct mt7621_nfc *nfc = &nfc_dev; 142 struct nand_chip *chip = &nfc->nand; 143 struct mtd_info *mtd = &chip->mtd; 144 u32 addr, col, page, chksz; 145 bool check_bad = true; 146 147 if (!nand_valid) 148 return -ENODEV; 149 150 while (size) { 151 if (check_bad || !(offs & mtd->erasesize_mask)) { 152 addr = offs & (~mtd->erasesize_mask); 153 page = addr >> mtd->writesize_shift; 154 if (nfc_check_bad_block(mtd, page)) { 155 /* Skip bad block */ 156 if (addr >= mtd->size - mtd->erasesize) 157 return -1; 158 159 offs += mtd->erasesize; 160 continue; 161 } 162 163 check_bad = false; 164 } 165 166 col = offs & mtd->writesize_mask; 167 page = offs >> mtd->writesize_shift; 168 chksz = min(mtd->writesize - col, (uint32_t)size); 169 170 if (unlikely(chksz < mtd->writesize)) { 171 /* Not reading a full page */ 172 if (nfc_read_page_hwecc(mtd, buffer, page)) 173 return -1; 174 175 memcpy(dest, buffer + col, chksz); 176 } else { 177 if (nfc_read_page_hwecc(mtd, dest, page)) 178 return -1; 179 } 180 181 dest += chksz; 182 offs += chksz; 183 size -= chksz; 184 } 185 186 return 0; 187} 188 189int nand_default_bbt(struct mtd_info *mtd) 190{ 191 return 0; 192} 193 194unsigned long nand_size(void) 195{ 196 if (!nand_valid) 197 return 0; 198 199 /* Unlikely that NAND size > 2GBytes */ 200 if (nfc_dev.nand.chipsize <= SZ_2G) 201 return nfc_dev.nand.chipsize; 202 203 return SZ_2G; 204} 205 206unsigned int nand_page_size(void) 207{ 208 return nfc_dev.nand.mtd.writesize; 209} 210 211void nand_deselect(void) 212{ 213} 214 215void nand_init(void) 216{ 217 struct mtd_info *mtd; 218 struct nand_chip *chip; 219 220 if (nand_valid) 221 return; 222 223 mt7621_nfc_spl_init(&nfc_dev); 224 225 chip = &nfc_dev.nand; 226 mtd = &chip->mtd; 227 chip->cmdfunc = nand_command_lp; 228 229 if (mt7621_nfc_spl_post_init(&nfc_dev)) 230 return; 231 232 mtd->erasesize_shift = ffs(mtd->erasesize) - 1; 233 mtd->writesize_shift = ffs(mtd->writesize) - 1; 234 mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; 235 mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; 236 237 buffer = malloc(mtd->writesize); 238 if (!buffer) 239 return; 240 241 nand_valid = 1; 242} 243