Thursday 25 April 2013

Mini210s, nand drivers, 16bit ecc and bootloaders

It's been a while since I last posted anything here, recently I've been helping out with an open source nand driver for the mini210S which you can find here:
https://github.com/Reggi3/210-nand-patch

With some fantastic work from Jkent and some help from me, we've managed to get a stable nand driver working that's pretty faithful to the original drivers.

It basically replaces the friendlyarm binary blob (s5p_nand_mlc.fo) with open source code, which means it should now be relatively simple to add 16bit ecc support into any of the bootloaders that are currently being worked on.

I'm repeating myself a bit here but our driver was tested on a mini210S with 4GB of MLC nand, we tested it with android 4.0.3 and it works with either kernel, 2.6.35 and 3.0.8.


Now we've released our driver we started to look at the bootloaders that were currently available, there is barebox and a pair of uboots, each of them seem to have their own issues, the major issue is that some of them are using older code, so even if you get the nand layout correct, it still won't work because the mtd subsystem and nand base drivers aren't setup to read 5/6 byte ID strings. 

Another issue I found was that barebox wasn't capable of addressing > 2GB in bytes due to using an int32 when it should be using a int64, it also cannot address 640byte oob nor was it capable of addressing 8k pages.


The last issue which is inherent to all of the open source bootloaders is the lack of proper ECC layout for each of the chips, I'll try and address that now.

When we started to write our own nand driver we needed to dump some information from the driver, namely the ecclayout, as you can see here:

https://github.com/Reggi3/210-nand-patch/blob/master/s5p_nand_mlc.c#L104

To get this information we had to edit the s3c_nand.c code, you can use the same code that we did to get the ecc layout for 1GB SLC, 2GB MLC or 4GB MLC nand, look for the print_oob function and make it look like this:

void print_oob(const char *header, struct mtd_info *mtd)
{
 int i;
 struct nand_chip *chip = mtd->priv;

// Reggie modified to dump the nand info from a K9GBGB8U0A 4GB mlc nand chip
 printk(KERN_INFO "%s:\t", header);
  printk("Dumping the nand ecc layout positions\n");
// Work out how many eccbytes we need to read the positions for
  int j = chip->ecc.layout->eccbytes ;

  printk(KERN_INFO "\n");
  for (i = 0; i < j; i++){
     printk("%u, ", chip->ecc.layout->eccpos[i]);
    if(i != 0 && i%8 == 0)
    printk("\n");
  }
  

  printk("\n");
  printk("Dumping the nand ecc layout\n");
  printk(".eccbytes %d \n", chip->ecc.layout->eccbytes);
  printk(".oobfree offset %d \n", chip->ecc.layout->oobfree->offset);
  printk(".oobfree length %d \n", chip->ecc.layout->oobfree->length);
  printk("ecc bytes  %d \n", chip->ecc.bytes);
  printk("ecc size %d \n", chip->ecc.size);
  printk("badblockbits %d \n", chip->badblockbits);
  printk("chip->pagemask %d \n", chip->pagemask);
  printk("mtd->oobsize %d \n", mtd->oobsize);
  printk("chip->ecc.steps %d \n",  chip->ecc.steps);
  printk("mtd->writesize %d \n", mtd->writesize);
  printk("chip->ecc.total %d \n", chip->ecc.total);
}
EXPORT_SYMBOL(print_oob);


You will also have to edit the end of the s3c_nand_probe function:
 print_oob("Nand oob info", s3c_mtd);
 pr_debug("initialized ok\n");

 return 0;

exit_error:
 kfree(s3c_mtd);

 return ret;
}



In fact, it should be relatively simple to use a similar method to get the correct ooblayout from any nand as long as you have access to it's probe functions and even if you don't have access to those, you should be able to find somewhere to poke the mtd driver to give up all of this information anyway.