Commit 6189cccb authored by Huang Shijie's avatar Huang Shijie Committed by Brian Norris

mtd: gpmi: add gpmi_devdata{} to simplify the code

More and more chips use the GPMI controller, but these chips may use different
version of the IPs for GPMI and BCH. Different IPs have
 different features, such as the BCH's maximum ECC strength:

     imx23/imx28 -- the BCH's maximum ECC strength is 20
     imx6q       -- the BCH's maximum ECC strength is 40
     imx6sx      -- the BCH's maximum ECC strength is 62

This patch does the following things:

  [1] add a new data structure, gpmi_devdata{}, to store the information for
      each IP. Besides the IP version, we store the following information:
         <1> BCH's maximum ECC strength.
         <2> the maximum chain delay in ns used by the EDO mode.

      but we may add more information in future.

  [2] add the gpmi_devdata_imx{23|28|6q} to replace the gpmi_ids.

  [3] simplify the code by using the ECC strength from gpmi_devdata, such as
      gpmi_check_ecc() and legacy_set_geometry();

  [4] use the maximum chain delay to initialize the EDO mode,
      see gpmi_compute_edo_timing().

  [5] rewrite the macros, such GPMI_IS_MX{23|28|6Q}.
Signed-off-by: default avatarHuang Shijie <b32955@freescale.com>
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
parent 85a3bd97
...@@ -861,7 +861,7 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, ...@@ -861,7 +861,7 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
struct resources *r = &this->resources; struct resources *r = &this->resources;
unsigned long rate = clk_get_rate(r->clock[0]); unsigned long rate = clk_get_rate(r->clock[0]);
int mode = this->timing_mode; int mode = this->timing_mode;
int dll_threshold = 16; /* in ns */ int dll_threshold = this->devdata->max_chain_delay;
unsigned long delay; unsigned long delay;
unsigned long clk_period; unsigned long clk_period;
int t_rea; int t_rea;
...@@ -886,9 +886,6 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this, ...@@ -886,9 +886,6 @@ static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
/* [3] for GPMI_HW_GPMI_CTRL1 */ /* [3] for GPMI_HW_GPMI_CTRL1 */
hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
if (GPMI_IS_MX6Q(this))
dll_threshold = 12;
/* /*
* Enlarge 10 times for the numerator and denominator in {3}. * Enlarge 10 times for the numerator and denominator in {3}.
* This make us to get more accurate result. * This make us to get more accurate result.
......
...@@ -53,6 +53,24 @@ static struct nand_ecclayout gpmi_hw_ecclayout = { ...@@ -53,6 +53,24 @@ static struct nand_ecclayout gpmi_hw_ecclayout = {
.oobfree = { {.offset = 0, .length = 0} } .oobfree = { {.offset = 0, .length = 0} }
}; };
static const struct gpmi_devdata gpmi_devdata_imx23 = {
.type = IS_MX23,
.bch_max_ecc_strength = 20,
.max_chain_delay = 16,
};
static const struct gpmi_devdata gpmi_devdata_imx28 = {
.type = IS_MX28,
.bch_max_ecc_strength = 20,
.max_chain_delay = 16,
};
static const struct gpmi_devdata gpmi_devdata_imx6q = {
.type = IS_MX6Q,
.bch_max_ecc_strength = 40,
.max_chain_delay = 12,
};
static irqreturn_t bch_irq(int irq, void *cookie) static irqreturn_t bch_irq(int irq, void *cookie)
{ {
struct gpmi_nand_data *this = cookie; struct gpmi_nand_data *this = cookie;
...@@ -102,14 +120,8 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this) ...@@ -102,14 +120,8 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
/* The mx23/mx28 only support the GF13. */ /* The mx23/mx28 only support the GF13. */
if (geo->gf_len == 14) if (geo->gf_len == 14)
return false; return false;
if (geo->ecc_strength > MXS_ECC_STRENGTH_MAX)
return false;
} else if (GPMI_IS_MX6Q(this)) {
if (geo->ecc_strength > MX6_ECC_STRENGTH_MAX)
return false;
} }
return true; return geo->ecc_strength <= this->devdata->bch_max_ecc_strength;
} }
/* /*
...@@ -270,8 +282,7 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) ...@@ -270,8 +282,7 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
"We can not support this nand chip." "We can not support this nand chip."
" Its required ecc strength(%d) is beyond our" " Its required ecc strength(%d) is beyond our"
" capability(%d).\n", geo->ecc_strength, " capability(%d).\n", geo->ecc_strength,
(GPMI_IS_MX6Q(this) ? MX6_ECC_STRENGTH_MAX this->devdata->bch_max_ecc_strength);
: MXS_ECC_STRENGTH_MAX));
return -EINVAL; return -EINVAL;
} }
...@@ -1740,23 +1751,16 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) ...@@ -1740,23 +1751,16 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
return ret; return ret;
} }
static const struct platform_device_id gpmi_ids[] = {
{ .name = "imx23-gpmi-nand", .driver_data = IS_MX23, },
{ .name = "imx28-gpmi-nand", .driver_data = IS_MX28, },
{ .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, },
{}
};
static const struct of_device_id gpmi_nand_id_table[] = { static const struct of_device_id gpmi_nand_id_table[] = {
{ {
.compatible = "fsl,imx23-gpmi-nand", .compatible = "fsl,imx23-gpmi-nand",
.data = (void *)&gpmi_ids[IS_MX23], .data = (void *)&gpmi_devdata_imx23,
}, { }, {
.compatible = "fsl,imx28-gpmi-nand", .compatible = "fsl,imx28-gpmi-nand",
.data = (void *)&gpmi_ids[IS_MX28], .data = (void *)&gpmi_devdata_imx28,
}, { }, {
.compatible = "fsl,imx6q-gpmi-nand", .compatible = "fsl,imx6q-gpmi-nand",
.data = (void *)&gpmi_ids[IS_MX6Q], .data = (void *)&gpmi_devdata_imx6q,
}, {} }, {}
}; };
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
...@@ -1767,18 +1771,18 @@ static int gpmi_nand_probe(struct platform_device *pdev) ...@@ -1767,18 +1771,18 @@ static int gpmi_nand_probe(struct platform_device *pdev)
const struct of_device_id *of_id; const struct of_device_id *of_id;
int ret; int ret;
this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
if (!this)
return -ENOMEM;
of_id = of_match_device(gpmi_nand_id_table, &pdev->dev); of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
if (of_id) { if (of_id) {
pdev->id_entry = of_id->data; this->devdata = of_id->data;
} else { } else {
dev_err(&pdev->dev, "Failed to find the right device id.\n"); dev_err(&pdev->dev, "Failed to find the right device id.\n");
return -ENODEV; return -ENODEV;
} }
this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
if (!this)
return -ENOMEM;
platform_set_drvdata(pdev, this); platform_set_drvdata(pdev, this);
this->pdev = pdev; this->pdev = pdev;
this->dev = &pdev->dev; this->dev = &pdev->dev;
...@@ -1823,7 +1827,6 @@ static struct platform_driver gpmi_nand_driver = { ...@@ -1823,7 +1827,6 @@ static struct platform_driver gpmi_nand_driver = {
}, },
.probe = gpmi_nand_probe, .probe = gpmi_nand_probe,
.remove = gpmi_nand_remove, .remove = gpmi_nand_remove,
.id_table = gpmi_ids,
}; };
module_platform_driver(gpmi_nand_driver); module_platform_driver(gpmi_nand_driver);
......
...@@ -119,11 +119,24 @@ struct nand_timing { ...@@ -119,11 +119,24 @@ struct nand_timing {
int8_t tRHOH_in_ns; int8_t tRHOH_in_ns;
}; };
enum gpmi_type {
IS_MX23,
IS_MX28,
IS_MX6Q
};
struct gpmi_devdata {
enum gpmi_type type;
int bch_max_ecc_strength;
int max_chain_delay; /* See the async EDO mode */
};
struct gpmi_nand_data { struct gpmi_nand_data {
/* flags */ /* flags */
#define GPMI_ASYNC_EDO_ENABLED (1 << 0) #define GPMI_ASYNC_EDO_ENABLED (1 << 0)
#define GPMI_TIMING_INIT_OK (1 << 1) #define GPMI_TIMING_INIT_OK (1 << 1)
int flags; int flags;
const struct gpmi_devdata *devdata;
/* System Interface */ /* System Interface */
struct device *dev; struct device *dev;
...@@ -281,15 +294,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *, ...@@ -281,15 +294,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *,
#define STATUS_ERASED 0xff #define STATUS_ERASED 0xff
#define STATUS_UNCORRECTABLE 0xfe #define STATUS_UNCORRECTABLE 0xfe
/* BCH's bit correction capability. */ /* Use the devdata to distinguish different Archs. */
#define MXS_ECC_STRENGTH_MAX 20 /* mx23 and mx28 */ #define GPMI_IS_MX23(x) ((x)->devdata->type == IS_MX23)
#define MX6_ECC_STRENGTH_MAX 40 #define GPMI_IS_MX28(x) ((x)->devdata->type == IS_MX28)
#define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q)
/* Use the platform_id to distinguish different Archs. */
#define IS_MX23 0x0
#define IS_MX28 0x1
#define IS_MX6Q 0x2
#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23)
#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28)
#define GPMI_IS_MX6Q(x) ((x)->pdev->id_entry->driver_data == IS_MX6Q)
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment