1/* 2 * gpmc-nand.c 3 * 4 * Copyright (C) 2009 Texas Instruments 5 * Vimal Singh <vimalsingh@ti.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/kernel.h> 13#include <linux/platform_device.h> 14#include <linux/io.h> 15#include <linux/omap-gpmc.h> 16#include <linux/mtd/nand.h> 17#include <linux/platform_data/mtd-nand-omap2.h> 18 19#include <asm/mach/flash.h> 20 21#include "soc.h" 22 23/* minimum size for IO mapping */ 24#define NAND_IO_SIZE 4 25 26static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) 27{ 28 /* platforms which support all ECC schemes */ 29 if (soc_is_am33xx() || soc_is_am43xx() || cpu_is_omap44xx() || 30 soc_is_omap54xx() || soc_is_dra7xx()) 31 return 1; 32 33 if (ecc_opt == OMAP_ECC_BCH4_CODE_HW_DETECTION_SW || 34 ecc_opt == OMAP_ECC_BCH8_CODE_HW_DETECTION_SW) { 35 if (cpu_is_omap24xx()) 36 return 0; 37 else if (cpu_is_omap3630() && (GET_OMAP_REVISION() == 0)) 38 return 0; 39 else 40 return 1; 41 } 42 43 /* OMAP3xxx do not have ELM engine, so cannot support ECC schemes 44 * which require H/W based ECC error detection */ 45 if ((cpu_is_omap34xx() || cpu_is_omap3630()) && 46 ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) || 47 (ecc_opt == OMAP_ECC_BCH8_CODE_HW))) 48 return 0; 49 50 /* legacy platforms support only HAM1 (1-bit Hamming) ECC scheme */ 51 if (ecc_opt == OMAP_ECC_HAM1_CODE_HW || 52 ecc_opt == OMAP_ECC_HAM1_CODE_SW) 53 return 1; 54 else 55 return 0; 56} 57 58/* This function will go away once the device-tree convertion is complete */ 59static void gpmc_set_legacy(struct omap_nand_platform_data *gpmc_nand_data, 60 struct gpmc_settings *s) 61{ 62 /* Enable RD PIN Monitoring Reg */ 63 if (gpmc_nand_data->dev_ready) { 64 s->wait_on_read = true; 65 s->wait_on_write = true; 66 } 67 68 if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) 69 s->device_width = GPMC_DEVWIDTH_16BIT; 70 else 71 s->device_width = GPMC_DEVWIDTH_8BIT; 72} 73 74int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, 75 struct gpmc_timings *gpmc_t) 76{ 77 int err = 0; 78 struct gpmc_settings s; 79 struct platform_device *pdev; 80 struct resource gpmc_nand_res[] = { 81 { .flags = IORESOURCE_MEM, }, 82 { .flags = IORESOURCE_IRQ, }, 83 { .flags = IORESOURCE_IRQ, }, 84 }; 85 86 BUG_ON(gpmc_nand_data->cs >= GPMC_CS_NUM); 87 88 err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, 89 (unsigned long *)&gpmc_nand_res[0].start); 90 if (err < 0) { 91 pr_err("omap2-gpmc: Cannot request GPMC CS %d, error %d\n", 92 gpmc_nand_data->cs, err); 93 return err; 94 } 95 gpmc_nand_res[0].end = gpmc_nand_res[0].start + NAND_IO_SIZE - 1; 96 gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE); 97 gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); 98 99 memset(&s, 0, sizeof(struct gpmc_settings)); 100 if (gpmc_nand_data->of_node) 101 gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); 102 else 103 gpmc_set_legacy(gpmc_nand_data, &s); 104 105 s.device_nand = true; 106 107 if (gpmc_t) { 108 err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t, &s); 109 if (err < 0) { 110 pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", 111 err); 112 return err; 113 } 114 } 115 116 err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s); 117 if (err < 0) 118 goto out_free_cs; 119 120 err = gpmc_configure(GPMC_CONFIG_WP, 0); 121 if (err < 0) 122 goto out_free_cs; 123 124 gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs); 125 126 if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) { 127 pr_err("omap2-nand: Unsupported NAND ECC scheme selected\n"); 128 err = -EINVAL; 129 goto out_free_cs; 130 } 131 132 133 pdev = platform_device_alloc("omap2-nand", gpmc_nand_data->cs); 134 if (pdev) { 135 err = platform_device_add_resources(pdev, gpmc_nand_res, 136 ARRAY_SIZE(gpmc_nand_res)); 137 if (!err) 138 pdev->dev.platform_data = gpmc_nand_data; 139 } else { 140 err = -ENOMEM; 141 } 142 if (err) 143 goto out_free_pdev; 144 145 err = platform_device_add(pdev); 146 if (err) { 147 dev_err(&pdev->dev, "Unable to register NAND device\n"); 148 goto out_free_pdev; 149 } 150 151 return 0; 152 153out_free_pdev: 154 platform_device_put(pdev); 155out_free_cs: 156 gpmc_cs_free(gpmc_nand_data->cs); 157 158 return err; 159} 160