aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/onenand/samsung.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/onenand/samsung.c')
-rw-r--r--drivers/mtd/onenand/samsung.c145
1 files changed, 134 insertions, 11 deletions
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index 3306b5b..9532cc9 100644
--- a/drivers/mtd/onenand/samsung.c
+++ b/drivers/mtd/onenand/samsung.c
@@ -23,12 +23,16 @@
#include <linux/mtd/partitions.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
+#include <linux/clk.h>
#include <asm/mach/flash.h>
#include <plat/regs-onenand.h>
#include <linux/io.h>
+#include <asm/setup.h>
+#include <linux/string.h>
+
enum soc_type {
TYPE_S3C6400,
TYPE_S3C6410,
@@ -36,6 +40,45 @@ enum soc_type {
TYPE_S5PC110,
};
+struct mtd_partition s3c_partition_info[] = {
+ {
+ .name = "misc",
+ .offset = (768*SZ_1K), /* for bootloader */
+ .size = (256*SZ_1K),
+ .mask_flags = MTD_CAP_NANDFLASH,
+ },
+ {
+ .name = "recovery",
+ .offset = MTDPART_OFS_APPEND,
+ .size = (5*SZ_1M),
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = (5*SZ_1M),
+ },
+ {
+ .name = "ramdisk",
+ .offset = MTDPART_OFS_APPEND,
+ .size = (3*SZ_1M),
+ },
+ {
+ .name = "system",
+ .offset = MTDPART_OFS_APPEND,
+ .size = (90*SZ_1M),
+ },
+ {
+ .name = "cache",
+ .offset = MTDPART_OFS_APPEND,
+ .size = (80*SZ_1M),
+ },
+ {
+ .name = "userdata",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
#define ONENAND_ERASE_STATUS 0x00
#define ONENAND_MULTI_ERASE_SET 0x01
#define ONENAND_ERASE_START 0x03
@@ -193,6 +236,56 @@ static void s3c_dump_reg(void)
}
#endif
+struct slsi_ptbl_entry {
+ char name[16];
+ __u32 offset;
+ __u32 size;
+ __u32 flags;
+};
+
+struct mtd_partition *partitions;
+int num_partitions;
+
+#define MAX_PARTITIONS 12
+#define ATAG_SLSI_PARTITION 0x28247574
+struct mtd_partition slsi_nand_partitions[MAX_PARTITIONS];
+char slsi_nand_names[MAX_PARTITIONS * 16];
+
+static int __init parse_tag_partition(const struct tag *tag)
+{
+ struct mtd_partition *ptn = slsi_nand_partitions;
+ char *name = slsi_nand_names;
+ struct slsi_ptbl_entry *entry = (void *) &tag->u;
+ unsigned count, n;
+
+ count = (tag->hdr.size - 2) /
+ (sizeof(struct slsi_ptbl_entry) / sizeof(__u32));
+
+ if (count > MAX_PARTITIONS)
+ count = MAX_PARTITIONS;
+
+ for (n = 0; n < count; n++) {
+ memcpy(name, entry->name, 15);
+ name[15] = 0;
+ ptn->name = name;
+ ptn->offset = entry->offset;
+ ptn->size = entry->size;
+
+ printk(KERN_INFO "Partition (from atag) %15s -- Offset:0x%08x Size:0x%08x\n",
+ entry->name, entry->offset, entry->size);
+
+ name += 16;
+ entry++;
+ ptn++;
+ }
+
+ num_partitions = count;
+ partitions = slsi_nand_partitions;
+
+ return 0;
+}
+__tagtable(ATAG_SLSI_PARTITION, parse_tag_partition);
+
static unsigned int s3c64xx_cmd_map(unsigned type, unsigned val)
{
return (type << S3C64XX_CMD_MAP_SHIFT) | val;
@@ -916,6 +1009,17 @@ static int s3c_onenand_probe(struct platform_device *pdev)
err = -EFAULT;
goto ioremap_failed;
}
+
+ this->clk = clk_get(&pdev->dev, "onenand");
+
+ if (IS_ERR(this->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ err = PTR_ERR(this->clk);
+ goto clk_failed;
+ }
+
+ clk_enable(this->clk);
+
/* Set onenand_chip also */
this->base = onenand->base;
@@ -1017,6 +1121,27 @@ static int s3c_onenand_probe(struct platform_device *pdev)
if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ)
dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n");
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ err = parse_mtd_partitions(mtd, part_probes, &onenand->parts, 0);
+ if (err > 0)
+ mtd_device_register(mtd, onenand->parts, err);
+ else if (err <= 0 && pdata && pdata->parts)
+ mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
+ else
+#endif
+ if (num_partitions <= 0) {
+ /* default partition table */
+ num_partitions = ARRAY_SIZE(s3c_partition_info); /* pdata->nr_parts */
+ partitions = s3c_partition_info; /* pdata->parts */
+ }
+
+ if (partitions && num_partitions > 0)
+ err = mtd_device_register(mtd, partitions, num_partitions);
+ else
+ err = mtd_device_register(mtd, NULL, 0);
+
+
+/*
err = parse_mtd_partitions(mtd, part_probes, &onenand->parts, 0);
if (err > 0)
mtd_device_register(mtd, onenand->parts, err);
@@ -1024,9 +1149,11 @@ static int s3c_onenand_probe(struct platform_device *pdev)
mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
else
err = mtd_device_register(mtd, NULL, 0);
+*/
platform_set_drvdata(pdev, mtd);
+ clk_disable(this->clk);
return 0;
scan_failed:
@@ -1049,6 +1176,9 @@ ahb_ioremap_failed:
dma_resource_failed:
ahb_resource_failed:
iounmap(onenand->base);
+ clk_disable(this->clk);
+ clk_put(this->clk);
+clk_failed:
ioremap_failed:
if (onenand->base_res)
release_mem_region(onenand->base_res->start,
@@ -1063,6 +1193,7 @@ onenand_fail:
static int __devexit s3c_onenand_remove(struct platform_device *pdev)
{
struct mtd_info *mtd = platform_get_drvdata(pdev);
+ struct onenand_chip *this = mtd->priv;
onenand_release(mtd);
if (onenand->ahb_addr)
@@ -1083,33 +1214,25 @@ static int __devexit s3c_onenand_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
kfree(onenand->oob_buf);
kfree(onenand->page_buf);
+ clk_put(this->clk);
kfree(onenand);
kfree(mtd);
return 0;
}
-static int s3c_pm_ops_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct mtd_info *mtd = platform_get_drvdata(pdev);
- struct onenand_chip *this = mtd->priv;
-
- this->wait(mtd, FL_PM_SUSPENDED);
- return 0;
-}
-
static int s3c_pm_ops_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mtd_info *mtd = platform_get_drvdata(pdev);
struct onenand_chip *this = mtd->priv;
+ clk_enable(this->clk);
this->unlock_all(mtd);
+ clk_disable(this->clk);
return 0;
}
static const struct dev_pm_ops s3c_pm_ops = {
- .suspend = s3c_pm_ops_suspend,
.resume = s3c_pm_ops_resume,
};