* [PATCH v7 18/20] mtd: rawnand: Write a compatibility layer
From: Miquel Raynal @ 2020-05-29 0:25 UTC (permalink / raw)
To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus, linux-mtd,
Rob Herring, Mark Rutland, devicetree
Cc: Boris Brezillon, Thomas Petazzoni, Paul Cercueil, Chuanhong Guo,
Weijie Gao, linux-arm-kernel, Mason Yang, Julien Su,
Miquel Raynal
In-Reply-To: <20200529002517.3546-1-miquel.raynal@bootlin.com>
Before moving generic bits from the raw NAND core to the generic NAND
core, let's disociate clearly what is a rawnand legacy property, and
what should be made public to other NAND users.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/nand_base.c | 158 +++++++++++++++++++++----------
include/linux/mtd/rawnand.h | 12 ---
2 files changed, 107 insertions(+), 63 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 1eb478ec1d1c..0ddbae037eaf 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5026,14 +5026,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
return ret;
}
-static const char * const nand_ecc_modes[] = {
- [NAND_ECC_NONE] = "none",
- [NAND_ECC_SOFT] = "soft",
- [NAND_ECC_HW] = "hw",
- [NAND_ECC_HW_SYNDROME] = "hw_syndrome",
- [NAND_ECC_ON_DIE] = "on-die",
-};
-
static const char * const nand_ecc_placement[] = {
[NAND_ECC_PLACEMENT_OOB] = "oob",
[NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
@@ -5042,7 +5034,30 @@ static const char * const nand_ecc_placement[] = {
static enum nand_ecc_engine_type
of_get_nand_ecc_engine_type(struct device_node *np)
{
- enum nand_ecc_mode eng_type;
+ return NAND_ECC_ENGINE_TYPE_INVALID;
+}
+
+static enum nand_ecc_engine_type
+of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
+{
+ enum nand_ecc_legacy_mode {
+ NAND_ECC_INVALID,
+ NAND_ECC_NONE,
+ NAND_ECC_SOFT,
+ NAND_ECC_SOFT_BCH,
+ NAND_ECC_HW,
+ NAND_ECC_HW_SYNDROME,
+ NAND_ECC_ON_DIE,
+ };
+ const char * const nand_ecc_legacy_modes[] = {
+ [NAND_ECC_NONE] = "none",
+ [NAND_ECC_SOFT] = "soft",
+ [NAND_ECC_SOFT_BCH] = "soft_bch",
+ [NAND_ECC_HW] = "hw",
+ [NAND_ECC_HW_SYNDROME] = "hw_syndrome",
+ [NAND_ECC_ON_DIE] = "on-die",
+ };
+ enum nand_ecc_legacy_mode eng_type;
const char *pm;
int err;
@@ -5051,12 +5066,13 @@ of_get_nand_ecc_engine_type(struct device_node *np)
return NAND_ECC_ENGINE_TYPE_INVALID;
for (eng_type = NAND_ECC_NONE;
- eng_type < ARRAY_SIZE(nand_ecc_modes); eng_type++) {
- if (!strcasecmp(pm, nand_ecc_modes[eng_type])) {
+ eng_type < ARRAY_SIZE(nand_ecc_legacy_modes); eng_type++) {
+ if (!strcasecmp(pm, nand_ecc_legacy_modes[eng_type])) {
switch (eng_type) {
case NAND_ECC_NONE:
return NAND_ECC_ENGINE_TYPE_NONE;
case NAND_ECC_SOFT:
+ case NAND_ECC_SOFT_BCH:
return NAND_ECC_ENGINE_TYPE_SOFT;
case NAND_ECC_HW:
case NAND_ECC_HW_SYNDROME:
@@ -5069,14 +5085,6 @@ of_get_nand_ecc_engine_type(struct device_node *np)
}
}
- /*
- * For backward compatibility we support few obsoleted values that don't
- * have their mappings into the nand_ecc_engine_providers enum anymore
- * (they were merged with other enums).
- */
- if (!strcasecmp(pm, "soft_bch"))
- return NAND_ECC_ENGINE_TYPE_SOFT;
-
return NAND_ECC_ENGINE_TYPE_INVALID;
}
@@ -5088,17 +5096,22 @@ enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
err = of_property_read_string(np, "nand-ecc-placement", &pm);
if (!err) {
- for (placement = NAND_ECC_PLACEMENT_INTERLEAVED;
+ for (placement = NAND_ECC_PLACEMENT_OOB;
placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
if (!strcasecmp(pm, nand_ecc_placement[placement]))
return placement;
}
}
- /*
- * For backward compatibility we support few obsoleted values that don't
- * have their mappings into the nand_ecc_placement enum anymore.
- */
+ return NAND_ECC_PLACEMENT_UNKNOWN;
+}
+
+enum nand_ecc_placement
+of_get_rawnand_ecc_placement_legacy(struct device_node *np)
+{
+ const char *pm;
+ int err;
+
err = of_property_read_string(np, "nand-ecc-mode", &pm);
if (!err) {
if (!strcasecmp(pm, "hw_syndrome"))
@@ -5130,10 +5143,14 @@ static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
}
}
- /*
- * For backward compatibility we also read "nand-ecc-mode" checking
- * for some obsoleted values that were specifying ECC algorithm.
- */
+ return NAND_ECC_ALGO_UNKNOWN;
+}
+
+static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
+{
+ const char *pm;
+ int err;
+
err = of_property_read_string(np, "nand-ecc-mode", &pm);
if (!err) {
if (!strcasecmp(pm, "soft"))
@@ -5163,6 +5180,41 @@ static int of_get_nand_ecc_strength(struct device_node *np)
return ret ? ret : val;
}
+static void nand_ecc_read_user_conf(struct nand_chip *chip)
+{
+ struct device_node *dn = nand_get_flash_node(chip);
+ struct nand_device *nand = &chip->base;
+ int strength, size;
+
+ nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
+ nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
+ nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
+
+ strength = of_get_nand_ecc_strength(dn);
+ if (strength >= 0)
+ nand->ecc.user_conf.strength = strength;
+
+ size = of_get_nand_ecc_step_size(dn);
+ if (size >= 0)
+ nand->ecc.user_conf.step_size = size;
+}
+
+static void rawnand_ecc_read_legacy_user_conf(struct nand_chip *chip)
+{
+ struct device_node *dn = nand_get_flash_node(chip);
+ struct nand_device *nand = &chip->base;
+ struct nand_ecc_props *user_conf = &nand->ecc.user_conf;
+
+ if (user_conf->engine_type != NAND_ECC_ENGINE_TYPE_INVALID)
+ user_conf->engine_type = of_get_rawnand_ecc_engine_type_legacy(dn);
+
+ if (user_conf->algo != NAND_ECC_ALGO_UNKNOWN)
+ user_conf->algo = of_get_rawnand_ecc_algo_legacy(dn);
+
+ if (user_conf->placement != NAND_ECC_PLACEMENT_UNKNOWN)
+ user_conf->placement = of_get_rawnand_ecc_placement_legacy(dn);
+}
+
static int of_get_nand_bus_width(struct device_node *np)
{
u32 val;
@@ -5184,12 +5236,10 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np)
return of_property_read_bool(np, "nand-on-flash-bbt");
}
-static int nand_dt_init(struct nand_chip *chip)
+static int rawnand_dt_init(struct nand_chip *chip)
{
+ struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip));
struct device_node *dn = nand_get_flash_node(chip);
- enum nand_ecc_engine_type ecc_type;
- enum nand_ecc_algo ecc_algo;
- int ecc_strength, ecc_step;
if (!dn)
return 0;
@@ -5203,27 +5253,33 @@ static int nand_dt_init(struct nand_chip *chip)
if (of_get_nand_on_flash_bbt(dn))
chip->bbt_options |= NAND_BBT_USE_FLASH;
- ecc_type = of_get_nand_ecc_engine_type(dn);
- ecc_algo = of_get_nand_ecc_algo(dn);
- chip->ecc.placement = of_get_nand_ecc_placement(dn);
- ecc_strength = of_get_nand_ecc_strength(dn);
- ecc_step = of_get_nand_ecc_step_size(dn);
-
- if (ecc_type != NAND_ECC_ENGINE_TYPE_INVALID)
- chip->ecc.engine_type = ecc_type;
-
- if (ecc_algo != NAND_ECC_ALGO_UNKNOWN)
- chip->ecc.algo = ecc_algo;
-
- if (ecc_strength >= 0)
- chip->ecc.strength = ecc_strength;
-
- if (ecc_step > 0)
- chip->ecc.size = ecc_step;
-
if (of_property_read_bool(dn, "nand-ecc-maximize"))
chip->ecc.options |= NAND_ECC_MAXIMIZE;
+ nand_ecc_read_user_conf(chip);
+ rawnand_ecc_read_legacy_user_conf(chip);
+
+ /*
+ * If neither the user nor the NAND controller have requested a specific
+ * ECC engine type, we will default to NAND_ECC_ENGINE_TYPE_ON_HOST.
+ */
+ nand->ecc.defaults.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+
+ /*
+ * Use the user requested engine type, unless there is none, in this
+ * case default to the NAND controller choice, otherwise fallback to
+ * the raw NAND default one.
+ */
+ if (nand->ecc.user_conf.engine_type != NAND_ECC_ENGINE_TYPE_INVALID)
+ chip->ecc.engine_type = nand->ecc.user_conf.engine_type;
+ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_INVALID)
+ chip->ecc.engine_type = nand->ecc.defaults.engine_type;
+
+ chip->ecc.placement = nand->ecc.user_conf.placement;
+ chip->ecc.algo = nand->ecc.user_conf.algo;
+ chip->ecc.strength = nand->ecc.user_conf.strength;
+ chip->ecc.size = nand->ecc.user_conf.step_size;
+
return 0;
}
@@ -5260,7 +5316,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
/* Enforce the right timings for reset/detection */
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
- ret = nand_dt_init(chip);
+ ret = rawnand_dt_init(chip);
if (ret)
return ret;
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 106f3698875d..123d48edce67 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -80,18 +80,6 @@ struct nand_chip;
#define NAND_DATA_IFACE_CHECK_ONLY -1
-/*
- * Constants for ECC_MODES
- */
-enum nand_ecc_mode {
- NAND_ECC_INVALID,
- NAND_ECC_NONE,
- NAND_ECC_SOFT,
- NAND_ECC_HW,
- NAND_ECC_HW_SYNDROME,
- NAND_ECC_ON_DIE,
-};
-
/*
* Constants for Hardware ECC
*/
--
2.20.1
^ permalink raw reply related
* [PATCH v7 20/20] mtd: rawnand: Move the user input parsing bits to the ECC framework
From: Miquel Raynal @ 2020-05-29 0:25 UTC (permalink / raw)
To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus, linux-mtd,
Rob Herring, Mark Rutland, devicetree
Cc: Boris Brezillon, Thomas Petazzoni, Paul Cercueil, Chuanhong Guo,
Weijie Gao, linux-arm-kernel, Mason Yang, Julien Su,
Miquel Raynal
In-Reply-To: <20200529002517.3546-1-miquel.raynal@bootlin.com>
Many helpers are generic to all NAND chips, they should not be
restricted to be only used by raw NAND controller drivers. They might
later be used by generic ECC engines and SPI-NAND devices as well so
move them into a more generic place.
To avoid moving all the raw NAND core "history" into the generic NAND
layer, we already moved certain bits into legacy helpers in the raw
NAND core to ensure backward compatibility.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/ecc.c | 138 +++++++++++++++++
drivers/mtd/nand/raw/atmel/nand-controller.c | 3 +-
drivers/mtd/nand/raw/denali.c | 3 +
drivers/mtd/nand/raw/nand_base.c | 149 ++-----------------
drivers/mtd/nand/raw/sunxi_nand.c | 3 +-
drivers/mtd/nand/raw/tegra_nand.c | 3 +-
include/linux/mtd/nand.h | 7 +
include/linux/mtd/rawnand.h | 1 -
8 files changed, 165 insertions(+), 142 deletions(-)
diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
index b465a296c786..d5004f6b1d33 100644
--- a/drivers/mtd/nand/ecc.c
+++ b/drivers/mtd/nand/ecc.c
@@ -328,6 +328,144 @@ const struct mtd_ooblayout_ops *nand_get_large_page_hamming_layout(void)
}
EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_layout);
+static enum nand_ecc_engine_type
+of_get_nand_ecc_engine_type(struct device_node *np)
+{
+ return NAND_ECC_ENGINE_TYPE_INVALID;
+}
+
+static const char * const nand_ecc_placement[] = {
+ [NAND_ECC_PLACEMENT_OOB] = "oob",
+ [NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
+};
+
+enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
+{
+ enum nand_ecc_placement placement;
+ const char *pm;
+ int err;
+
+ err = of_property_read_string(np, "nand-ecc-placement", &pm);
+ if (!err) {
+ for (placement = NAND_ECC_PLACEMENT_OOB;
+ placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
+ if (!strcasecmp(pm, nand_ecc_placement[placement]))
+ return placement;
+ }
+ }
+
+ return NAND_ECC_PLACEMENT_UNKNOWN;
+}
+
+static const char * const nand_ecc_algos[] = {
+ [NAND_ECC_ALGO_HAMMING] = "hamming",
+ [NAND_ECC_ALGO_BCH] = "bch",
+ [NAND_ECC_ALGO_RS] = "rs",
+};
+
+static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
+{
+ enum nand_ecc_algo ecc_algo;
+ const char *pm;
+ int err;
+
+ err = of_property_read_string(np, "nand-ecc-algo", &pm);
+ if (!err) {
+ for (ecc_algo = NAND_ECC_ALGO_HAMMING;
+ ecc_algo < ARRAY_SIZE(nand_ecc_algos);
+ ecc_algo++) {
+ if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
+ return ecc_algo;
+ }
+ }
+
+ return NAND_ECC_ALGO_UNKNOWN;
+}
+
+static int of_get_nand_ecc_step_size(struct device_node *np)
+{
+ int ret;
+ u32 val;
+
+ ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
+ return ret ? ret : val;
+}
+
+static int of_get_nand_ecc_strength(struct device_node *np)
+{
+ int ret;
+ u32 val;
+
+ ret = of_property_read_u32(np, "nand-ecc-strength", &val);
+ return ret ? ret : val;
+}
+
+static inline bool of_get_nand_ecc_maximize(struct device_node *np)
+{
+ return of_property_read_bool(np, "nand-ecc-maximize");
+}
+
+void nand_ecc_read_user_conf(struct nand_device *nand)
+{
+ struct device_node *dn = nanddev_get_of_node(nand);
+ int strength, size;
+
+ nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
+ nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
+ nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
+
+ strength = of_get_nand_ecc_strength(dn);
+ if (strength >= 0)
+ nand->ecc.user_conf.strength = strength;
+
+ size = of_get_nand_ecc_step_size(dn);
+ if (size >= 0)
+ nand->ecc.user_conf.step_size = size;
+
+ if (of_get_nand_ecc_maximize(dn))
+ nand->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE;
+}
+EXPORT_SYMBOL(nand_ecc_read_user_conf);
+
+/**
+ * nand_ecc_correction_is_enough - Check if the chip configuration meets the
+ * datasheet requirements.
+ *
+ * @nand: Device to check
+ *
+ * If our configuration corrects A bits per B bytes and the minimum
+ * required correction level is X bits per Y bytes, then we must ensure
+ * both of the following are true:
+ *
+ * (1) A / B >= X / Y
+ * (2) A >= X
+ *
+ * Requirement (1) ensures we can correct for the required bitflip density.
+ * Requirement (2) ensures we can correct even when all bitflips are clumped
+ * in the same sector.
+ */
+bool nand_ecc_correction_is_enough(struct nand_device *nand)
+{
+ struct nand_ecc_props *reqs = &nand->ecc.requirements;
+ struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+ int corr, ds_corr;
+
+ if (conf->step_size == 0 || reqs->step_size == 0)
+ /* Not enough information */
+ return true;
+
+ /*
+ * We get the number of corrected bits per page to compare
+ * the correction density.
+ */
+ corr = (mtd->writesize * conf->strength) / conf->step_size;
+ ds_corr = (mtd->writesize * reqs->strength) / reqs->step_size;
+
+ return corr >= ds_corr && conf->strength >= reqs->strength;
+}
+EXPORT_SYMBOL(nand_ecc_correction_is_enough);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
MODULE_DESCRIPTION("Generic ECC engine");
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index ab1c6d058e10..f464a6dd4bca 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -1045,6 +1045,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
{
struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_device *nanddev = mtd_to_nanddev(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
struct atmel_pmecc_user_req req;
@@ -1069,7 +1070,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
chip->ecc.size = val;
}
- if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+ if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE)
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
else if (chip->ecc.strength)
req.ecc.strength = chip->ecc.strength;
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index a6a6464974ec..51bc014ebc0a 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -1181,6 +1181,7 @@ int denali_chip_init(struct denali_controller *denali,
{
struct nand_chip *chip = &dchip->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_device *nanddev = mtd_to_nanddev(mtd);
struct denali_chip *dchip2;
int i, j, ret;
@@ -1248,6 +1249,8 @@ int denali_chip_init(struct denali_controller *denali,
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
+ nanddev->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE;
+
ret = nand_scan(chip, dchip->nsels);
if (ret)
return ret;
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index b9f2c26b87e1..7765dbb9f285 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4851,17 +4851,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
return ret;
}
-static const char * const nand_ecc_placement[] = {
- [NAND_ECC_PLACEMENT_OOB] = "oob",
- [NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
-};
-
-static enum nand_ecc_engine_type
-of_get_nand_ecc_engine_type(struct device_node *np)
-{
- return NAND_ECC_ENGINE_TYPE_INVALID;
-}
-
static enum nand_ecc_engine_type
of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
{
@@ -4913,24 +4902,6 @@ of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
return NAND_ECC_ENGINE_TYPE_INVALID;
}
-enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
-{
- enum nand_ecc_placement placement;
- const char *pm;
- int err;
-
- err = of_property_read_string(np, "nand-ecc-placement", &pm);
- if (!err) {
- for (placement = NAND_ECC_PLACEMENT_OOB;
- placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
- if (!strcasecmp(pm, nand_ecc_placement[placement]))
- return placement;
- }
- }
-
- return NAND_ECC_PLACEMENT_UNKNOWN;
-}
-
enum nand_ecc_placement
of_get_rawnand_ecc_placement_legacy(struct device_node *np)
{
@@ -4946,31 +4917,6 @@ of_get_rawnand_ecc_placement_legacy(struct device_node *np)
return NAND_ECC_PLACEMENT_UNKNOWN;
}
-static const char * const nand_ecc_algos[] = {
- [NAND_ECC_ALGO_HAMMING] = "hamming",
- [NAND_ECC_ALGO_BCH] = "bch",
- [NAND_ECC_ALGO_RS] = "rs",
-};
-
-static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
-{
- enum nand_ecc_algo ecc_algo;
- const char *pm;
- int err;
-
- err = of_property_read_string(np, "nand-ecc-algo", &pm);
- if (!err) {
- for (ecc_algo = NAND_ECC_ALGO_HAMMING;
- ecc_algo < ARRAY_SIZE(nand_ecc_algos);
- ecc_algo++) {
- if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
- return ecc_algo;
- }
- }
-
- return NAND_ECC_ALGO_UNKNOWN;
-}
-
static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
{
const char *pm;
@@ -4987,48 +4933,10 @@ static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
return NAND_ECC_ALGO_UNKNOWN;
}
-static int of_get_nand_ecc_step_size(struct device_node *np)
-{
- int ret;
- u32 val;
-
- ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
- return ret ? ret : val;
-}
-
-static int of_get_nand_ecc_strength(struct device_node *np)
-{
- int ret;
- u32 val;
-
- ret = of_property_read_u32(np, "nand-ecc-strength", &val);
- return ret ? ret : val;
-}
-
-static void nand_ecc_read_user_conf(struct nand_chip *chip)
-{
- struct device_node *dn = nand_get_flash_node(chip);
- struct nand_device *nand = &chip->base;
- int strength, size;
-
- nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
- nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
- nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
-
- strength = of_get_nand_ecc_strength(dn);
- if (strength >= 0)
- nand->ecc.user_conf.strength = strength;
-
- size = of_get_nand_ecc_step_size(dn);
- if (size >= 0)
- nand->ecc.user_conf.step_size = size;
-}
-
static void rawnand_ecc_read_legacy_user_conf(struct nand_chip *chip)
{
struct device_node *dn = nand_get_flash_node(chip);
- struct nand_device *nand = &chip->base;
- struct nand_ecc_props *user_conf = &nand->ecc.user_conf;
+ struct nand_ecc_props *user_conf = &chip->base.ecc.user_conf;
if (user_conf->engine_type != NAND_ECC_ENGINE_TYPE_INVALID)
user_conf->engine_type = of_get_rawnand_ecc_engine_type_legacy(dn);
@@ -5078,10 +4986,7 @@ static int rawnand_dt_init(struct nand_chip *chip)
if (of_get_nand_on_flash_bbt(dn))
chip->bbt_options |= NAND_BBT_USE_FLASH;
- if (of_property_read_bool(dn, "nand-ecc-maximize"))
- chip->ecc.options |= NAND_ECC_MAXIMIZE;
-
- nand_ecc_read_user_conf(chip);
+ nand_ecc_read_user_conf(nand);
rawnand_ecc_read_legacy_user_conf(chip);
/*
@@ -5211,6 +5116,7 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip)
static int nand_set_ecc_soft_ops(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_device *nanddev = mtd_to_nanddev(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
if (WARN_ON(ecc->engine_type != NAND_ECC_ENGINE_TYPE_SOFT))
@@ -5286,7 +5192,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
* used.
*/
if (mtd->ooblayout == nand_get_large_page_layout() &&
- ecc->options & NAND_ECC_MAXIMIZE) {
+ nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE) {
int steps, bytes;
/* Always prefer 1k blocks over 512bytes ones */
@@ -5524,11 +5430,12 @@ nand_maximize_ecc(struct nand_chip *chip,
* @caps: ECC engine caps info structure
* @oobavail: OOB size that the ECC engine can use
*
- * Choose the ECC configuration according to following logic
+ * Choose the ECC configuration according to following logic.
*
* 1. If both ECC step size and ECC strength are already set (usually by DT)
* then check if it is supported by this controller.
- * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
+ * 2. If the user provided the nand-ecc-maximize property, then select maximum
+ * ECC strength.
* 3. Otherwise, try to match the ECC step size and ECC strength closest
* to the chip's requirement. If available OOB size can't fit the chip
* requirement then fallback to the maximum ECC step size and ECC strength.
@@ -5539,6 +5446,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
{
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_device *nanddev = mtd_to_nanddev(mtd);
if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize))
return -EINVAL;
@@ -5546,7 +5454,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
if (chip->ecc.size && chip->ecc.strength)
return nand_check_ecc_caps(chip, caps, oobavail);
- if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+ if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE)
return nand_maximize_ecc(chip, caps, oobavail);
if (!nand_match_ecc_req(chip, caps, oobavail))
@@ -5556,42 +5464,6 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
}
EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
-/*
- * Check if the chip configuration meet the datasheet requirements.
-
- * If our configuration corrects A bits per B bytes and the minimum
- * required correction level is X bits per Y bytes, then we must ensure
- * both of the following are true:
- *
- * (1) A / B >= X / Y
- * (2) A >= X
- *
- * Requirement (1) ensures we can correct for the required bitflip density.
- * Requirement (2) ensures we can correct even when all bitflips are clumped
- * in the same sector.
- */
-static bool nand_ecc_strength_good(struct nand_chip *chip)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
- int corr, ds_corr;
-
- if (ecc->size == 0 || requirements->step_size == 0)
- /* Not enough information */
- return true;
-
- /*
- * We get the number of corrected bits per page to compare
- * the correction density.
- */
- corr = (mtd->writesize * ecc->strength) / ecc->size;
- ds_corr = (mtd->writesize * requirements->strength) /
- requirements->step_size;
-
- return corr >= ds_corr && ecc->strength >= requirements->strength;
-}
-
static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos)
{
struct nand_chip *chip = container_of(nand, struct nand_chip,
@@ -5647,6 +5519,7 @@ static const struct nand_ops rawnand_ops = {
static int nand_scan_tail(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_device *nanddev = mtd_to_nanddev(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i;
@@ -5874,7 +5747,7 @@ static int nand_scan_tail(struct nand_chip *chip)
mtd->oobavail = ret;
/* ECC sanity check: warn if it's too weak */
- if (!nand_ecc_strength_good(chip))
+ if (!nand_ecc_correction_is_enough(nanddev))
pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n",
mtd->name,
chip->base.ecc.ctx.conf.strength,
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index a5eefdf89660..5fc1378fe94e 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1609,12 +1609,13 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
struct mtd_info *mtd = nand_to_mtd(nand);
+ struct nand_device *nanddev = mtd_to_nanddev(mtd);
struct sunxi_nand_hw_ecc *data;
int nsectors;
int ret;
int i;
- if (ecc->options & NAND_ECC_MAXIMIZE) {
+ if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE) {
int bytes;
ecc->size = 1024;
diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c
index 8264bb991d03..d642a1dd2e16 100644
--- a/drivers/mtd/nand/raw/tegra_nand.c
+++ b/drivers/mtd/nand/raw/tegra_nand.c
@@ -840,7 +840,8 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength,
int strength_len, int bits_per_step,
int oobsize)
{
- bool maximize = chip->ecc.options & NAND_ECC_MAXIMIZE;
+ struct nand_device *nanddev = mtd_to_nanddev(nand_to_mtd(chip));
+ bool maximize = nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE;
int i;
/*
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 6039e6dcccde..2cf5cd4d0997 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -182,6 +182,7 @@ enum nand_ecc_algo {
* @algo: ECC algorithm (if relevant)
* @strength: ECC strength
* @step_size: Number of bytes per step
+ * @flags: Misc properties
*/
struct nand_ecc_props {
enum nand_ecc_engine_type engine_type;
@@ -189,10 +190,14 @@ struct nand_ecc_props {
enum nand_ecc_algo algo;
unsigned int strength;
unsigned int step_size;
+ unsigned int flags;
};
#define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) }
+/* NAND ECC misc flags */
+#define NAND_ECC_MAXIMIZE BIT(0)
+
/**
* struct nand_bbt - bad block table object
* @cache: in memory BBT cache
@@ -264,12 +269,14 @@ struct nand_ecc_engine {
struct nand_ecc_engine_ops *ops;
};
+void nand_ecc_read_user_conf(struct nand_device *nand);
int nand_ecc_init_ctx(struct nand_device *nand);
void nand_ecc_cleanup_ctx(struct nand_device *nand);
int nand_ecc_prepare_io_req(struct nand_device *nand,
struct nand_page_io_req *req);
int nand_ecc_finish_io_req(struct nand_device *nand,
struct nand_page_io_req *req);
+bool nand_ecc_correction_is_enough(struct nand_device *nand);
/**
* struct nand_ecc - Information relative to the ECC
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 66f69a1d27a5..9d69fa6608ae 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -98,7 +98,6 @@ struct nand_chip;
* pages and you want to rely on the default implementation.
*/
#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
-#define NAND_ECC_MAXIMIZE BIT(1)
/*
* Option constants for bizarre disfunctionality and real
--
2.20.1
^ permalink raw reply related
* [PATCH v7 19/20] mtd: rawnand: Move generic OOB layouts to the ECC framework
From: Miquel Raynal @ 2020-05-29 0:25 UTC (permalink / raw)
To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus, linux-mtd,
Rob Herring, Mark Rutland, devicetree
Cc: Boris Brezillon, Thomas Petazzoni, Paul Cercueil, Chuanhong Guo,
Weijie Gao, linux-arm-kernel, Mason Yang, Julien Su,
Miquel Raynal
In-Reply-To: <20200529002517.3546-1-miquel.raynal@bootlin.com>
These layouts can be used by any driver, move them to the ECC core.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/ecc.c | 176 ++++++++++++++++++++++++++++++
drivers/mtd/nand/raw/Kconfig | 1 +
drivers/mtd/nand/raw/nand_base.c | 177 +------------------------------
include/linux/mtd/nand.h | 4 +
include/linux/mtd/rawnand.h | 5 +-
5 files changed, 183 insertions(+), 180 deletions(-)
diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
index f7300ba37167..b465a296c786 100644
--- a/drivers/mtd/nand/ecc.c
+++ b/drivers/mtd/nand/ecc.c
@@ -152,6 +152,182 @@ int nand_ecc_finish_io_req(struct nand_device *nand,
}
EXPORT_SYMBOL(nand_ecc_finish_io_req);
+/* Define default oob placement schemes for large and small page devices */
+static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+
+ if (section > 1)
+ return -ERANGE;
+
+ if (!section) {
+ oobregion->offset = 0;
+ if (mtd->oobsize == 16)
+ oobregion->length = 4;
+ else
+ oobregion->length = 3;
+ } else {
+ if (mtd->oobsize == 8)
+ return -ERANGE;
+
+ oobregion->offset = 6;
+ oobregion->length = total_ecc_bytes - 4;
+ }
+
+ return 0;
+}
+
+static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section > 1)
+ return -ERANGE;
+
+ if (mtd->oobsize == 16) {
+ if (section)
+ return -ERANGE;
+
+ oobregion->length = 8;
+ oobregion->offset = 8;
+ } else {
+ oobregion->length = 2;
+ if (!section)
+ oobregion->offset = 3;
+ else
+ oobregion->offset = 6;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
+ .ecc = nand_ooblayout_ecc_sp,
+ .free = nand_ooblayout_free_sp,
+};
+
+const struct mtd_ooblayout_ops *nand_get_small_page_layout(void)
+{
+ return &nand_ooblayout_sp_ops;
+}
+EXPORT_SYMBOL_GPL(nand_get_small_page_layout);
+
+static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+
+ if (section || !total_ecc_bytes)
+ return -ERANGE;
+
+ oobregion->length = total_ecc_bytes;
+ oobregion->offset = mtd->oobsize - oobregion->length;
+
+ return 0;
+}
+
+static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+
+ if (section)
+ return -ERANGE;
+
+ oobregion->length = mtd->oobsize - total_ecc_bytes - 2;
+ oobregion->offset = 2;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
+ .ecc = nand_ooblayout_ecc_lp,
+ .free = nand_ooblayout_free_lp,
+};
+
+const struct mtd_ooblayout_ops *nand_get_large_page_layout(void)
+{
+ return &nand_ooblayout_lp_ops;
+}
+EXPORT_SYMBOL_GPL(nand_get_large_page_layout);
+
+/*
+ * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
+ * are placed at a fixed offset.
+ */
+static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+
+ if (section)
+ return -ERANGE;
+
+ switch (mtd->oobsize) {
+ case 64:
+ oobregion->offset = 40;
+ break;
+ case 128:
+ oobregion->offset = 80;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ oobregion->length = total_ecc_bytes;
+ if (oobregion->offset + oobregion->length > mtd->oobsize)
+ return -ERANGE;
+
+ return 0;
+}
+
+static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+ int ecc_offset = 0;
+
+ if (section < 0 || section > 1)
+ return -ERANGE;
+
+ switch (mtd->oobsize) {
+ case 64:
+ ecc_offset = 40;
+ break;
+ case 128:
+ ecc_offset = 80;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (section == 0) {
+ oobregion->offset = 2;
+ oobregion->length = ecc_offset - 2;
+ } else {
+ oobregion->offset = ecc_offset + total_ecc_bytes;
+ oobregion->length = mtd->oobsize - oobregion->offset;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
+ .ecc = nand_ooblayout_ecc_lp_hamming,
+ .free = nand_ooblayout_free_lp_hamming,
+};
+
+const struct mtd_ooblayout_ops *nand_get_large_page_hamming_layout(void)
+{
+ return &nand_ooblayout_lp_hamming_ops;
+}
+EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_layout);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
MODULE_DESCRIPTION("Generic ECC engine");
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 85280e327bfe..6ab3184ca8eb 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -13,6 +13,7 @@ config MTD_NAND_ECC_SW_HAMMING_SMC
menuconfig MTD_RAW_NAND
tristate "Raw/Parallel NAND Device Support"
select MTD_NAND_CORE
+ select MTD_NAND_ECC
select MTD_NAND_ECC_SW_HAMMING
help
This enables support for accessing all type of raw/parallel
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 0ddbae037eaf..b9f2c26b87e1 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -34,6 +34,7 @@
#include <linux/mm.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/nand_bch.h>
#include <linux/interrupt.h>
@@ -45,182 +46,6 @@
#include "internals.h"
-/* Define default oob placement schemes for large and small page devices */
-static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
-
- if (section > 1)
- return -ERANGE;
-
- if (!section) {
- oobregion->offset = 0;
- if (mtd->oobsize == 16)
- oobregion->length = 4;
- else
- oobregion->length = 3;
- } else {
- if (mtd->oobsize == 8)
- return -ERANGE;
-
- oobregion->offset = 6;
- oobregion->length = ecc->total - 4;
- }
-
- return 0;
-}
-
-static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- if (section > 1)
- return -ERANGE;
-
- if (mtd->oobsize == 16) {
- if (section)
- return -ERANGE;
-
- oobregion->length = 8;
- oobregion->offset = 8;
- } else {
- oobregion->length = 2;
- if (!section)
- oobregion->offset = 3;
- else
- oobregion->offset = 6;
- }
-
- return 0;
-}
-
-static const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
- .ecc = nand_ooblayout_ecc_sp,
- .free = nand_ooblayout_free_sp,
-};
-
-const struct mtd_ooblayout_ops *nand_get_small_page_layout(void)
-{
- return &nand_ooblayout_sp_ops;
-}
-EXPORT_SYMBOL_GPL(nand_get_small_page_layout);
-
-static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
-
- if (section || !ecc->total)
- return -ERANGE;
-
- oobregion->length = ecc->total;
- oobregion->offset = mtd->oobsize - oobregion->length;
-
- return 0;
-}
-
-static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
-
- if (section)
- return -ERANGE;
-
- oobregion->length = mtd->oobsize - ecc->total - 2;
- oobregion->offset = 2;
-
- return 0;
-}
-
-static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
- .ecc = nand_ooblayout_ecc_lp,
- .free = nand_ooblayout_free_lp,
-};
-
-const struct mtd_ooblayout_ops *nand_get_large_page_layout(void)
-{
- return &nand_ooblayout_lp_ops;
-}
-EXPORT_SYMBOL_GPL(nand_get_large_page_layout);
-
-/*
- * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
- * are placed at a fixed offset.
- */
-static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
-
- if (section)
- return -ERANGE;
-
- switch (mtd->oobsize) {
- case 64:
- oobregion->offset = 40;
- break;
- case 128:
- oobregion->offset = 80;
- break;
- default:
- return -EINVAL;
- }
-
- oobregion->length = ecc->total;
- if (oobregion->offset + oobregion->length > mtd->oobsize)
- return -ERANGE;
-
- return 0;
-}
-
-static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- int ecc_offset = 0;
-
- if (section < 0 || section > 1)
- return -ERANGE;
-
- switch (mtd->oobsize) {
- case 64:
- ecc_offset = 40;
- break;
- case 128:
- ecc_offset = 80;
- break;
- default:
- return -EINVAL;
- }
-
- if (section == 0) {
- oobregion->offset = 2;
- oobregion->length = ecc_offset - 2;
- } else {
- oobregion->offset = ecc_offset + ecc->total;
- oobregion->length = mtd->oobsize - oobregion->offset;
- }
-
- return 0;
-}
-
-static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
- .ecc = nand_ooblayout_ecc_lp_hamming,
- .free = nand_ooblayout_free_lp_hamming,
-};
-
-const struct mtd_ooblayout_ops *nand_get_large_page_hamming_layout(void)
-{
- return &nand_ooblayout_lp_hamming_ops;
-}
-EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_layout);
-
static int nand_pairing_dist3_get_info(struct mtd_info *mtd, int page,
struct mtd_pairing_info *info)
{
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 975ddf26ac8c..6039e6dcccde 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -127,6 +127,10 @@ struct nand_page_io_req {
int mode;
};
+const struct mtd_ooblayout_ops *nand_get_small_page_layout(void);
+const struct mtd_ooblayout_ops *nand_get_large_page_layout(void);
+const struct mtd_ooblayout_ops *nand_get_large_page_hamming_layout(void);
+
/**
* enum nand_ecc_engine_type - NAND ECC engine type
* @NAND_ECC_ENGINE_TYPE_INVALID: Invalid value
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 123d48edce67..66f69a1d27a5 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -14,6 +14,7 @@
#define __LINUX_MTD_RAWNAND_H
#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/flashchip.h>
#include <linux/mtd/bbm.h>
#include <linux/mtd/jedec.h>
@@ -1147,10 +1148,6 @@ struct nand_chip {
int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len);
};
-const struct mtd_ooblayout_ops *nand_get_small_page_layout(void);
-const struct mtd_ooblayout_ops *nand_get_large_page_layout(void);
-const struct mtd_ooblayout_ops *nand_get_large_page_hamming_layout(void);
-
static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
{
return container_of(mtd, struct nand_chip, base.mtd);
--
2.20.1
^ permalink raw reply related
* [PATCH v7 16/20] mtd: nand: Convert generic NAND bits to use the ECC framework
From: Miquel Raynal @ 2020-05-29 0:25 UTC (permalink / raw)
To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus, linux-mtd,
Rob Herring, Mark Rutland, devicetree
Cc: Boris Brezillon, Thomas Petazzoni, Paul Cercueil, Chuanhong Guo,
Weijie Gao, linux-arm-kernel, Mason Yang, Julien Su,
Miquel Raynal
In-Reply-To: <20200529002517.3546-1-miquel.raynal@bootlin.com>
Embed a generic NAND ECC high-level object in the nand_device
structure to carry all the ECC engine configuration/data. Adapt the
raw NAND and SPI-NAND cores to fit the change.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/raw/atmel/nand-controller.c | 9 +++--
drivers/mtd/nand/raw/brcmnand/brcmnand.c | 7 ++--
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 12 +++---
drivers/mtd/nand/raw/marvell_nand.c | 7 ++--
drivers/mtd/nand/raw/mtk_nand.c | 4 +-
drivers/mtd/nand/raw/nand_base.c | 25 ++++++------
drivers/mtd/nand/raw/nand_esmt.c | 11 +++---
drivers/mtd/nand/raw/nand_hynix.c | 41 ++++++++++----------
drivers/mtd/nand/raw/nand_jedec.c | 4 +-
drivers/mtd/nand/raw/nand_micron.c | 14 ++++---
drivers/mtd/nand/raw/nand_onfi.c | 8 ++--
drivers/mtd/nand/raw/nand_samsung.c | 19 ++++-----
drivers/mtd/nand/raw/nand_toshiba.c | 11 +++---
drivers/mtd/nand/raw/sunxi_nand.c | 5 ++-
drivers/mtd/nand/raw/tegra_nand.c | 9 +++--
drivers/mtd/nand/spi/core.c | 8 ++--
drivers/mtd/nand/spi/macronix.c | 6 +--
drivers/mtd/nand/spi/toshiba.c | 6 +--
include/linux/mtd/nand.h | 8 ++--
19 files changed, 114 insertions(+), 100 deletions(-)
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index 85cf396731ce..2ebcf3087d8d 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -1043,6 +1043,7 @@ static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip,
static int atmel_nand_pmecc_init(struct nand_chip *chip)
{
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -1072,15 +1073,15 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
else if (chip->ecc.strength)
req.ecc.strength = chip->ecc.strength;
- else if (chip->base.eccreq.strength)
- req.ecc.strength = chip->base.eccreq.strength;
+ else if (requirements->strength)
+ req.ecc.strength = requirements->strength;
else
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
if (chip->ecc.size)
req.ecc.sectorsize = chip->ecc.size;
- else if (chip->base.eccreq.step_size)
- req.ecc.sectorsize = chip->base.eccreq.step_size;
+ else if (requirements->step_size)
+ req.ecc.sectorsize = requirements->step_size;
else
req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 164617b33942..40f6d107ffa2 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -2563,10 +2563,11 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
(!chip->ecc.size || !chip->ecc.strength)) {
- if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
+ if (chip->base.ecc.requirements.step_size &&
+ chip->base.ecc.requirements.strength) {
/* use detected ECC parameters */
- chip->ecc.size = chip->base.eccreq.step_size;
- chip->ecc.strength = chip->base.eccreq.strength;
+ chip->ecc.size = chip->base.ecc.requirements.step_size;
+ chip->ecc.strength = chip->base.ecc.requirements.strength;
dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n",
chip->ecc.size, chip->ecc.strength);
}
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index d1ea6df9fd64..5f56570ce04d 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -272,8 +272,8 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this,
default:
dev_err(this->dev,
"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
- chip->base.eccreq.strength,
- chip->base.eccreq.step_size);
+ chip->base.ecc.requirements.strength,
+ chip->base.ecc.requirements.step_size);
return -EINVAL;
}
geo->ecc_chunk_size = ecc_step;
@@ -517,13 +517,13 @@ static int common_nfc_set_geometry(struct gpmi_nand_data *this)
if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
|| legacy_set_geometry(this)) {
- if (!(chip->base.eccreq.strength > 0 &&
- chip->base.eccreq.step_size > 0))
+ if (!(chip->base.ecc.requirements.strength > 0 &&
+ chip->base.ecc.requirements.step_size > 0))
return -EINVAL;
return set_geometry_by_ecc_info(this,
- chip->base.eccreq.strength,
- chip->base.eccreq.step_size);
+ chip->base.ecc.requirements.strength,
+ chip->base.ecc.requirements.step_size);
}
return 0;
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index f9cc03c11deb..e7a269461a6d 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -2244,14 +2244,15 @@ static int marvell_nand_ecc_init(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc)
{
struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
int ret;
if (ecc->engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
(!ecc->size || !ecc->strength)) {
- if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
- ecc->size = chip->base.eccreq.step_size;
- ecc->strength = chip->base.eccreq.strength;
+ if (requirements->step_size && requirements->strength) {
+ ecc->size = requirements->step_size;
+ ecc->strength = requirements->strength;
} else {
dev_info(nfc->dev,
"No minimum ECC strength, using 1b/512B\n");
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index a0294c9161dd..1f8dbae38286 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -1234,8 +1234,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
/* if optional dt settings not present */
if (!nand->ecc.size || !nand->ecc.strength) {
/* use datasheet requirements */
- nand->ecc.strength = nand->base.eccreq.strength;
- nand->ecc.size = nand->base.eccreq.step_size;
+ nand->ecc.strength = nand->base.ecc.requirements.strength;
+ nand->ecc.size = nand->base.ecc.requirements.step_size;
/*
* align eccstrength and eccsize
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 1ce2cbe72e4c..bc2d5d2e8f4c 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4746,8 +4746,8 @@ static bool find_full_id_nand(struct nand_chip *chip,
memorg->pagesize *
memorg->pages_per_eraseblock);
chip->options |= type->options;
- chip->base.eccreq.strength = NAND_ECC_STRENGTH(type);
- chip->base.eccreq.step_size = NAND_ECC_STEP(type);
+ chip->base.ecc.requirements.strength = NAND_ECC_STRENGTH(type);
+ chip->base.ecc.requirements.step_size = NAND_ECC_STEP(type);
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
@@ -5485,8 +5485,8 @@ nand_match_ecc_req(struct nand_chip *chip,
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
- int req_step = chip->base.eccreq.step_size;
- int req_strength = chip->base.eccreq.strength;
+ int req_step = chip->base.ecc.requirements.step_size;
+ int req_strength = chip->base.ecc.requirements.strength;
int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
int best_step, best_strength, best_ecc_bytes;
int best_ecc_bytes_total = INT_MAX;
@@ -5677,9 +5677,10 @@ static bool nand_ecc_strength_good(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
int corr, ds_corr;
- if (ecc->size == 0 || chip->base.eccreq.step_size == 0)
+ if (ecc->size == 0 || requirements->step_size == 0)
/* Not enough information */
return true;
@@ -5688,10 +5689,10 @@ static bool nand_ecc_strength_good(struct nand_chip *chip)
* the correction density.
*/
corr = (mtd->writesize * ecc->strength) / ecc->size;
- ds_corr = (mtd->writesize * chip->base.eccreq.strength) /
- chip->base.eccreq.step_size;
+ ds_corr = (mtd->writesize * requirements->strength) /
+ requirements->step_size;
- return corr >= ds_corr && ecc->strength >= chip->base.eccreq.strength;
+ return corr >= ds_corr && ecc->strength >= requirements->strength;
}
static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos)
@@ -5977,9 +5978,11 @@ static int nand_scan_tail(struct nand_chip *chip)
/* ECC sanity check: warn if it's too weak */
if (!nand_ecc_strength_good(chip))
pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n",
- mtd->name, chip->ecc.strength, chip->ecc.size,
- chip->base.eccreq.strength,
- chip->base.eccreq.step_size);
+ mtd->name,
+ chip->base.ecc.ctx.conf.strength,
+ chip->base.ecc.ctx.conf.step_size,
+ chip->base.ecc.requirements.strength,
+ chip->base.ecc.requirements.step_size);
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c
index 3338c68aaaf1..11f25ec3e4fc 100644
--- a/drivers/mtd/nand/raw/nand_esmt.c
+++ b/drivers/mtd/nand/raw/nand_esmt.c
@@ -10,24 +10,25 @@
static void esmt_nand_decode_id(struct nand_chip *chip)
{
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
nand_decode_ext_id(chip);
/* Extract ECC requirements from 5th id byte. */
if (chip->id.len >= 5 && nand_is_slc(chip)) {
- chip->base.eccreq.step_size = 512;
+ requirements->step_size = 512;
switch (chip->id.data[4] & 0x3) {
case 0x0:
- chip->base.eccreq.strength = 4;
+ requirements->strength = 4;
break;
case 0x1:
- chip->base.eccreq.strength = 2;
+ requirements->strength = 2;
break;
case 0x2:
- chip->base.eccreq.strength = 1;
+ requirements->strength = 1;
break;
default:
WARN(1, "Could not get ECC info");
- chip->base.eccreq.step_size = 0;
+ requirements->step_size = 0;
break;
}
}
diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c
index 7caedaa5b9e5..bac7732a86e9 100644
--- a/drivers/mtd/nand/raw/nand_hynix.c
+++ b/drivers/mtd/nand/raw/nand_hynix.c
@@ -495,34 +495,35 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
bool valid_jedecid)
{
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
if (valid_jedecid) {
/* Reference: H27UCG8T2E datasheet */
- chip->base.eccreq.step_size = 1024;
+ requirements->step_size = 1024;
switch (ecc_level) {
case 0:
- chip->base.eccreq.step_size = 0;
- chip->base.eccreq.strength = 0;
+ requirements->step_size = 0;
+ requirements->strength = 0;
break;
case 1:
- chip->base.eccreq.strength = 4;
+ requirements->strength = 4;
break;
case 2:
- chip->base.eccreq.strength = 24;
+ requirements->strength = 24;
break;
case 3:
- chip->base.eccreq.strength = 32;
+ requirements->strength = 32;
break;
case 4:
- chip->base.eccreq.strength = 40;
+ requirements->strength = 40;
break;
case 5:
- chip->base.eccreq.strength = 50;
+ requirements->strength = 50;
break;
case 6:
- chip->base.eccreq.strength = 60;
+ requirements->strength = 60;
break;
default:
/*
@@ -543,14 +544,14 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
if (nand_tech < 3) {
/* > 26nm, reference: H27UBG8T2A datasheet */
if (ecc_level < 5) {
- chip->base.eccreq.step_size = 512;
- chip->base.eccreq.strength = 1 << ecc_level;
+ requirements->step_size = 512;
+ requirements->strength = 1 << ecc_level;
} else if (ecc_level < 7) {
if (ecc_level == 5)
- chip->base.eccreq.step_size = 2048;
+ requirements->step_size = 2048;
else
- chip->base.eccreq.step_size = 1024;
- chip->base.eccreq.strength = 24;
+ requirements->step_size = 1024;
+ requirements->strength = 24;
} else {
/*
* We should never reach this case, but if that
@@ -563,14 +564,14 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
} else {
/* <= 26nm, reference: H27UBG8T2B datasheet */
if (!ecc_level) {
- chip->base.eccreq.step_size = 0;
- chip->base.eccreq.strength = 0;
+ requirements->step_size = 0;
+ requirements->strength = 0;
} else if (ecc_level < 5) {
- chip->base.eccreq.step_size = 512;
- chip->base.eccreq.strength = 1 << (ecc_level - 1);
+ requirements->step_size = 512;
+ requirements->strength = 1 << (ecc_level - 1);
} else {
- chip->base.eccreq.step_size = 1024;
- chip->base.eccreq.strength = 24 +
+ requirements->step_size = 1024;
+ requirements->strength = 24 +
(8 * (ecc_level - 5));
}
}
diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c
index b15c42f48755..5ed3656d88dd 100644
--- a/drivers/mtd/nand/raw/nand_jedec.c
+++ b/drivers/mtd/nand/raw/nand_jedec.c
@@ -120,8 +120,8 @@ int nand_jedec_detect(struct nand_chip *chip)
ecc = &p->ecc_info[0];
if (ecc->codeword_size >= 9) {
- chip->base.eccreq.strength = ecc->ecc_bits;
- chip->base.eccreq.step_size = 1 << ecc->codeword_size;
+ chip->base.ecc.requirements.strength = ecc->ecc_bits;
+ chip->base.ecc.requirements.step_size = 1 << ecc->codeword_size;
} else {
pr_warn("Invalid codeword size\n");
}
diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
index c8ebfd8c77a1..d1dc684ecd6c 100644
--- a/drivers/mtd/nand/raw/nand_micron.c
+++ b/drivers/mtd/nand/raw/nand_micron.c
@@ -413,6 +413,7 @@ enum {
*/
static int micron_supports_on_die_ecc(struct nand_chip *chip)
{
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
u8 id[5];
int ret;
@@ -425,7 +426,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
/*
* We only support on-die ECC of 4/512 or 8/512
*/
- if (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8)
+ if (requirements->strength != 4 && requirements->strength != 8)
return MICRON_ON_DIE_UNSUPPORTED;
/* 0x2 means on-die ECC is available. */
@@ -466,7 +467,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
/*
* We only support on-die ECC of 4/512 or 8/512
*/
- if (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8)
+ if (requirements->strength != 4 && requirements->strength != 8)
return MICRON_ON_DIE_UNSUPPORTED;
return MICRON_ON_DIE_SUPPORTED;
@@ -474,6 +475,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
static int micron_nand_init(struct nand_chip *chip)
{
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
struct mtd_info *mtd = nand_to_mtd(chip);
struct micron_nand *micron;
int ondie;
@@ -523,7 +525,7 @@ static int micron_nand_init(struct nand_chip *chip)
* That's not needed for 8-bit ECC, because the status expose
* a better approximation of the number of bitflips in a page.
*/
- if (chip->base.eccreq.strength == 4) {
+ if (requirements->strength == 4) {
micron->ecc.rawbuf = kmalloc(mtd->writesize +
mtd->oobsize,
GFP_KERNEL);
@@ -533,16 +535,16 @@ static int micron_nand_init(struct nand_chip *chip)
}
}
- if (chip->base.eccreq.strength == 4)
+ if (requirements->strength == 4)
mtd_set_ooblayout(mtd,
µn_nand_on_die_4_ooblayout_ops);
else
mtd_set_ooblayout(mtd,
µn_nand_on_die_8_ooblayout_ops);
- chip->ecc.bytes = chip->base.eccreq.strength * 2;
+ chip->ecc.bytes = requirements->strength * 2;
chip->ecc.size = 512;
- chip->ecc.strength = chip->base.eccreq.strength;
+ chip->ecc.strength = requirements->strength;
chip->ecc.algo = NAND_ECC_ALGO_BCH;
chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c
index be3456627288..c9ae29774c1f 100644
--- a/drivers/mtd/nand/raw/nand_onfi.c
+++ b/drivers/mtd/nand/raw/nand_onfi.c
@@ -94,8 +94,8 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
goto ext_out;
}
- chip->base.eccreq.strength = ecc->ecc_bits;
- chip->base.eccreq.step_size = 1 << ecc->codeword_size;
+ chip->base.ecc.requirements.strength = ecc->ecc_bits;
+ chip->base.ecc.requirements.step_size = 1 << ecc->codeword_size;
ret = 0;
ext_out:
@@ -265,8 +265,8 @@ int nand_onfi_detect(struct nand_chip *chip)
chip->options |= NAND_BUSWIDTH_16;
if (p->ecc_bits != 0xff) {
- chip->base.eccreq.strength = p->ecc_bits;
- chip->base.eccreq.step_size = 512;
+ chip->base.ecc.requirements.strength = p->ecc_bits;
+ chip->base.ecc.requirements.step_size = 512;
} else if (onfi_version >= 21 &&
(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c
index 3a4a19e808f6..0ee85e88aeb5 100644
--- a/drivers/mtd/nand/raw/nand_samsung.c
+++ b/drivers/mtd/nand/raw/nand_samsung.c
@@ -10,6 +10,7 @@
static void samsung_nand_decode_id(struct nand_chip *chip)
{
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
@@ -71,23 +72,23 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
/* Extract ECC requirements from 5th id byte*/
extid = (chip->id.data[4] >> 4) & 0x07;
if (extid < 5) {
- chip->base.eccreq.step_size = 512;
- chip->base.eccreq.strength = 1 << extid;
+ requirements->step_size = 512;
+ requirements->strength = 1 << extid;
} else {
- chip->base.eccreq.step_size = 1024;
+ requirements->step_size = 1024;
switch (extid) {
case 5:
- chip->base.eccreq.strength = 24;
+ requirements->strength = 24;
break;
case 6:
- chip->base.eccreq.strength = 40;
+ requirements->strength = 40;
break;
case 7:
- chip->base.eccreq.strength = 60;
+ requirements->strength = 60;
break;
default:
WARN(1, "Could not decode ECC info");
- chip->base.eccreq.step_size = 0;
+ requirements->step_size = 0;
}
}
} else {
@@ -97,8 +98,8 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
switch (chip->id.data[1]) {
/* K9F4G08U0D-S[I|C]B0(T00) */
case 0xDC:
- chip->base.eccreq.step_size = 512;
- chip->base.eccreq.strength = 1;
+ requirements->step_size = 512;
+ requirements->strength = 1;
break;
/* K9F1G08U0E 21nm chips do not support subpage write */
diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c
index 436ed90a90ad..1180068007a9 100644
--- a/drivers/mtd/nand/raw/nand_toshiba.c
+++ b/drivers/mtd/nand/raw/nand_toshiba.c
@@ -145,6 +145,7 @@ static void toshiba_nand_benand_init(struct nand_chip *chip)
static void toshiba_nand_decode_id(struct nand_chip *chip)
{
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
@@ -175,20 +176,20 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
* - 24nm: 8 bit ECC for each 512Byte is required.
*/
if (chip->id.len >= 6 && nand_is_slc(chip)) {
- chip->base.eccreq.step_size = 512;
+ requirements->step_size = 512;
switch (chip->id.data[5] & 0x7) {
case 0x4:
- chip->base.eccreq.strength = 1;
+ requirements->strength = 1;
break;
case 0x5:
- chip->base.eccreq.strength = 4;
+ requirements->strength = 4;
break;
case 0x6:
- chip->base.eccreq.strength = 8;
+ requirements->strength = 8;
break;
default:
WARN(1, "Could not get ECC info");
- chip->base.eccreq.step_size = 0;
+ requirements->step_size = 0;
break;
}
}
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index c6dd2e6d9ef8..a5eefdf89660 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1732,6 +1732,7 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
static int sunxi_nand_attach_chip(struct nand_chip *nand)
{
+ struct nand_ecc_props *requirements = &nand->base.ecc.requirements;
struct nand_ecc_ctrl *ecc = &nand->ecc;
struct device_node *np = nand_get_flash_node(nand);
int ret;
@@ -1745,8 +1746,8 @@ static int sunxi_nand_attach_chip(struct nand_chip *nand)
nand->options |= NAND_SUBPAGE_READ;
if (!ecc->size) {
- ecc->size = nand->base.eccreq.step_size;
- ecc->strength = nand->base.eccreq.strength;
+ ecc->size = requirements->step_size;
+ ecc->strength = requirements->strength;
}
if (!ecc->size || !ecc->strength)
diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c
index 2325b06ccc9a..8264bb991d03 100644
--- a/drivers/mtd/nand/raw/tegra_nand.c
+++ b/drivers/mtd/nand/raw/tegra_nand.c
@@ -855,7 +855,7 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength,
} else {
strength_sel = strength[i];
- if (strength_sel < chip->base.eccreq.strength)
+ if (strength_sel < chip->base.ecc.requirements.strength)
continue;
}
@@ -908,6 +908,7 @@ static int tegra_nand_select_strength(struct nand_chip *chip, int oobsize)
static int tegra_nand_attach_chip(struct nand_chip *chip)
{
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
+ struct nand_ecc_props *requirements = &chip->base.ecc.requirements;
struct tegra_nand_chip *nand = to_tegra_chip(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
int bits_per_step;
@@ -919,9 +920,9 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
chip->ecc.size = 512;
chip->ecc.steps = mtd->writesize / chip->ecc.size;
- if (chip->base.eccreq.step_size != 512) {
+ if (requirements->step_size != 512) {
dev_err(ctrl->dev, "Unsupported step size %d\n",
- chip->base.eccreq.step_size);
+ requirements->step_size);
return -EINVAL;
}
@@ -952,7 +953,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
if (ret < 0) {
dev_err(ctrl->dev,
"No valid strength found, minimum %d\n",
- chip->base.eccreq.strength);
+ requirements->strength);
return ret;
}
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 6f6ec8aa143d..edc8ec2923d5 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -419,7 +419,7 @@ static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
* fixed, so let's return the maximum possible value so that
* wear-leveling layers move the data immediately.
*/
- return nand->eccreq.strength;
+ return nand->ecc.ctx.conf.strength;
case STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
@@ -903,7 +903,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
continue;
nand->memorg = table[i].memorg;
- nand->eccreq = table[i].eccreq;
+ nand->ecc.requirements = table[i].eccreq;
spinand->eccinfo = table[i].eccinfo;
spinand->flags = table[i].flags;
spinand->id.len = 1 + table[i].devid.len;
@@ -1091,8 +1091,8 @@ static int spinand_init(struct spinand_device *spinand)
mtd->oobavail = ret;
/* Propagate ECC information to mtd_info */
- mtd->ecc_strength = nand->eccreq.strength;
- mtd->ecc_step_size = nand->eccreq.step_size;
+ mtd->ecc_strength = nand->ecc.ctx.conf.strength;
+ mtd->ecc_step_size = nand->ecc.ctx.conf.step_size;
return 0;
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 0f900f3aa21a..9db55828a995 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -84,10 +84,10 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
* data around if it's not necessary.
*/
if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
- return nand->eccreq.strength;
+ return nand->ecc.ctx.conf.strength;
- if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
- return nand->eccreq.strength;
+ if (WARN_ON(eccsr > nand->ecc.ctx.conf.strength || !eccsr))
+ return nand->ecc.ctx.conf.strength;
return eccsr;
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index bc801d83343e..c3e5b1a85e3e 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -90,12 +90,12 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
* data around if it's not necessary.
*/
if (spi_mem_exec_op(spinand->spimem, &op))
- return nand->eccreq.strength;
+ return nand->ecc.ctx.conf.strength;
mbf >>= 4;
- if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
- return nand->eccreq.strength;
+ if (WARN_ON(mbf > nand->ecc.ctx.conf.strength || !mbf))
+ return nand->ecc.ctx.conf.strength;
return mbf;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 2f838394b5f7..975ddf26ac8c 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -290,7 +290,7 @@ struct nand_ecc {
* struct nand_device - NAND device
* @mtd: MTD instance attached to the NAND device
* @memorg: memory layout
- * @eccreq: ECC requirements
+ * @ecc: NAND ECC object attached to the NAND device
* @rowconv: position to row address converter
* @bbt: bad block table info
* @ops: NAND operations attached to the NAND device
@@ -298,8 +298,8 @@ struct nand_ecc {
* Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND)
* should declare their own NAND object embedding a nand_device struct (that's
* how inheritance is done).
- * struct_nand_device->memorg and struct_nand_device->eccreq should be filled
- * at device detection time to reflect the NAND device
+ * struct_nand_device->memorg and struct_nand_device->ecc.ctx.conf should
+ * be filled at device detection time to reflect the NAND device
* capabilities/requirements. Once this is done nanddev_init() can be called.
* It will take care of converting NAND information into MTD ones, which means
* the specialized NAND layers should never manually tweak
@@ -308,7 +308,7 @@ struct nand_ecc {
struct nand_device {
struct mtd_info mtd;
struct nand_memory_organization memorg;
- struct nand_ecc_props eccreq;
+ struct nand_ecc ecc;
struct nand_row_converter rowconv;
struct nand_bbt bbt;
const struct nand_ops *ops;
--
2.20.1
^ permalink raw reply related
* Re: [PATCH v6 08/16] soc: mediatek: cmdq: add write_s function
From: Dennis-YC Hsieh @ 2020-05-29 0:53 UTC (permalink / raw)
To: Matthias Brugger
Cc: Rob Herring, Mark Rutland, Jassi Brar, Philipp Zabel,
David Airlie, Daniel Vetter, linux-kernel, linux-mediatek,
devicetree, wsd_upstream, dri-devel, Bibby Hsieh, CK Hu,
Houlong Wei, linux-arm-kernel, HS Liao
In-Reply-To: <086cd50f-1cf5-a87d-9547-7a826e6b6252@gmail.com>
Hi Matthias,
Thanks for your comment.
On Thu, 2020-05-28 at 23:08 +0200, Matthias Brugger wrote:
>
> On 28/05/2020 19:04, Dennis YC Hsieh wrote:
> > add write_s function in cmdq helper functions which
> > writes value contains in internal register to address
> > with large dma access support.
> >
> > Signed-off-by: Dennis YC Hsieh <dennis-yc.hsieh@mediatek.com>
> > ---
> > drivers/soc/mediatek/mtk-cmdq-helper.c | 21 ++++++++++++++++++++-
> > include/linux/mailbox/mtk-cmdq-mailbox.h | 1 +
> > include/linux/soc/mediatek/mtk-cmdq.h | 20 ++++++++++++++++++++
> > 3 files changed, 41 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c
> > index 33153d17c9d9..ee24c0ec0a24 100644
> > --- a/drivers/soc/mediatek/mtk-cmdq-helper.c
> > +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c
> > @@ -18,6 +18,10 @@ struct cmdq_instruction {
> > union {
> > u32 value;
> > u32 mask;
> > + struct {
> > + u16 arg_c;
> > + u16 src_reg;
> > + };
> > };
> > union {
> > u16 offset;
> > @@ -29,7 +33,7 @@ struct cmdq_instruction {
> > struct {
> > u8 sop:5;
> > u8 arg_c_t:1;
> > - u8 arg_b_t:1;
> > + u8 src_t:1;
>
> This should be part of 7/16.
ok, I'll move it
>
> > u8 dst_t:1;
> > };
> > };
> > @@ -222,6 +226,21 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
> > }
> > EXPORT_SYMBOL(cmdq_pkt_write_mask);
> >
> > +int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
> > + u16 addr_low, u16 src_reg_idx)
> > +{
> > + struct cmdq_instruction inst = { {0} };
>
> If you want an empty struct on the stack, I think {}; should be enough, right?
Yes, I'll change the style, thanks
Regards,
Dennis
>
> Regards,
> Matthias
>
> > +
> > + inst.op = CMDQ_CODE_WRITE_S;
> > + inst.src_t = CMDQ_REG_TYPE;
> > + inst.sop = high_addr_reg_idx;
> > + inst.offset = addr_low;
> > + inst.src_reg = src_reg_idx;
> > +
> > + return cmdq_pkt_append_command(pkt, inst);
> > +}
> > +EXPORT_SYMBOL(cmdq_pkt_write_s);
> > +
> > int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event)
> > {
> > struct cmdq_instruction inst = { {0} };
> > diff --git a/include/linux/mailbox/mtk-cmdq-mailbox.h b/include/linux/mailbox/mtk-cmdq-mailbox.h
> > index 121c3bb6d3de..ee67dd3b86f5 100644
> > --- a/include/linux/mailbox/mtk-cmdq-mailbox.h
> > +++ b/include/linux/mailbox/mtk-cmdq-mailbox.h
> > @@ -59,6 +59,7 @@ enum cmdq_code {
> > CMDQ_CODE_JUMP = 0x10,
> > CMDQ_CODE_WFE = 0x20,
> > CMDQ_CODE_EOC = 0x40,
> > + CMDQ_CODE_WRITE_S = 0x90,
> > CMDQ_CODE_LOGIC = 0xa0,
> > };
> >
> > diff --git a/include/linux/soc/mediatek/mtk-cmdq.h b/include/linux/soc/mediatek/mtk-cmdq.h
> > index 83340211e1d3..d623f1aa7814 100644
> > --- a/include/linux/soc/mediatek/mtk-cmdq.h
> > +++ b/include/linux/soc/mediatek/mtk-cmdq.h
> > @@ -12,6 +12,8 @@
> > #include <linux/timer.h>
> >
> > #define CMDQ_NO_TIMEOUT 0xffffffffu
> > +#define CMDQ_ADDR_HIGH(addr) ((u32)(((addr) >> 16) & GENMASK(31, 0)))
> > +#define CMDQ_ADDR_LOW(addr) ((u16)(addr) | BIT(1))
> >
> > struct cmdq_pkt;
> >
> > @@ -102,6 +104,24 @@ int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value);
> > int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
> > u16 offset, u32 value, u32 mask);
> >
> > +/**
> > + * cmdq_pkt_write_s() - append write_s command to the CMDQ packet
> > + * @pkt: the CMDQ packet
> > + * @high_addr_reg_idx: internal register ID which contains high address of pa
> > + * @addr_low: low address of pa
> > + * @src_reg_idx: the CMDQ internal register ID which cache source value
> > + * @mask: the specified target address mask, use U32_MAX if no need
> > + *
> > + * Return: 0 for success; else the error code is returned
> > + *
> > + * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH()
> > + * to get high address and call cmdq_pkt_assign() to assign value into internal
> > + * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when
> > + * call to this function.
> > + */
> > +int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
> > + u16 addr_low, u16 src_reg_idx);
> > +
> > /**
> > * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet
> > * @pkt: the CMDQ packet
> >
^ permalink raw reply
* Re: [PATCH v3 1/5] regulator: Allow regulators to verify enabled during enable()
From: Bjorn Andersson @ 2020-05-29 1:37 UTC (permalink / raw)
To: Sumit Semwal
Cc: agross, lgirdwood, broonie, robh+dt, nishakumari, linux-arm-msm,
linux-kernel, devicetree, kgunda, rnayak
In-Reply-To: <20200528154625.17742-2-sumit.semwal@linaro.org>
On Thu 28 May 08:46 PDT 2020, Sumit Semwal wrote:
> Some regulators might need to verify that they have indeed been enabled
> after the enable() call is made and enable_time delay has passed.
>
> This is implemented by repeatedly checking is_enabled() upto
> poll_enabled_time, waiting for the already calculated enable delay in
> each iteration.
>
> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
> ---
> drivers/regulator/core.c | 28 ++++++++++++++++++++++++++++
> include/linux/regulator/driver.h | 5 +++++
> 2 files changed, 33 insertions(+)
>
> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
> index 7486f6e4e613..06199f182114 100644
> --- a/drivers/regulator/core.c
> +++ b/drivers/regulator/core.c
> @@ -2409,6 +2409,34 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
>
> _regulator_enable_delay(delay);
My interpretation of "enable_time" (i.e. the value of delay) is that it
denotes the maximum time it will take for the regulator to turn on, and
the purpose of this patch is to be able to handle cases where we can
poll the hardware to see if it completed earlier.
So I think you should flip the meaning of your two variables around,
making "delay" the total time to sleep and the newly introduced
"poll_enabled_time" the interval at which you check if the hardware
finished early.
Regards,
Bjorn
>
> + /* If set, poll upto poll_enabled_time uS to see if the regulator
> + * actually got enabled.
> + * For each iteration, wait for the enable_time delay calculated
> + * above already.
> + * If the regulator isn't enabled after poll_enabled_time has
> + * expired, return -ETIMEDOUT.
> + */
> + if (rdev->desc->poll_enabled_time) {
> + unsigned int time_remaining = rdev->desc->poll_enabled_time;
> +
> + while (time_remaining > 0) {
> + /* We've already waited for enable_time above;
> + * so we can start with immediate check of the
> + * status of the regulator.
> + */
> + if (rdev->desc->ops->is_enabled(rdev))
> + break;
> +
> + _regulator_enable_delay(delay);
> + time_remaining -= delay;
> + }
> +
> + if (time_remaining <= 0) {
> + rdev_err(rdev, "Enabled check failed.\n");
> + return -ETIMEDOUT;
> + }
> + }
> +
> trace_regulator_enable_complete(rdev_get_name(rdev));
>
> return 0;
> diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
> index 29d920516e0b..bb50e943010f 100644
> --- a/include/linux/regulator/driver.h
> +++ b/include/linux/regulator/driver.h
> @@ -322,6 +322,9 @@ enum regulator_type {
> * @enable_time: Time taken for initial enable of regulator (in uS).
> * @off_on_delay: guard time (in uS), before re-enabling a regulator
> *
> + * @poll_enabled_time: Maximum time (in uS) to poll if the regulator is
> + * actually enabled, after enable() call
> + *
> * @of_map_mode: Maps a hardware mode defined in a DeviceTree to a standard mode
> */
> struct regulator_desc {
> @@ -389,6 +392,8 @@ struct regulator_desc {
>
> unsigned int off_on_delay;
>
> + unsigned int poll_enabled_time;
> +
> unsigned int (*of_map_mode)(unsigned int mode);
> };
>
> --
> 2.26.2
>
^ permalink raw reply
* Re: [PATCH v3 3/5] arm64: dts: qcom: pmi8998: Add nodes for LAB and IBB regulators
From: Bjorn Andersson @ 2020-05-29 1:43 UTC (permalink / raw)
To: Sumit Semwal
Cc: agross, lgirdwood, broonie, robh+dt, nishakumari, linux-arm-msm,
linux-kernel, devicetree, kgunda, rnayak
In-Reply-To: <20200528154625.17742-4-sumit.semwal@linaro.org>
On Thu 28 May 08:46 PDT 2020, Sumit Semwal wrote:
> From: Nisha Kumari <nishakumari@codeaurora.org>
>
> This patch adds devicetree nodes for LAB and IBB regulators.
>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> Signed-off-by: Nisha Kumari <nishakumari@codeaurora.org>
> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
>
> --
> v2: sumits: updated for better compatible string and names
> v3: sumits: updated interrupt-names as per review comments
>
> ---
> arch/arm64/boot/dts/qcom/pmi8998.dtsi | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
> index 23f9146a161e..1a72fe92f1a6 100644
> --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
> +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
> @@ -25,5 +25,19 @@ pmi8998_lsid1: pmic@3 {
> reg = <0x3 SPMI_USID>;
> #address-cells = <1>;
> #size-cells = <0>;
> +
> + labibb: labibb {
Although I don't see any reason to reference this node as of today, so
it doesn't really need a label.
Regards,
Bjorn
> + compatible = "qcom,pmi8998-lab-ibb";
> +
> + ibb: ibb {
> + interrupts = <0x3 0xdc 0x2 IRQ_TYPE_EDGE_RISING>;
> + interrupt-names = "sc-err";
> + };
> +
> + lab: lab {
> + interrupts = <0x3 0xde 0x0 IRQ_TYPE_EDGE_RISING>;
> + interrupt-names = "sc-err";
> + };
> + };
> };
> };
> --
> 2.26.2
>
^ permalink raw reply
* Re: [PATCH v3 4/5] regulator: qcom: Add labibb driver
From: Bjorn Andersson @ 2020-05-29 2:04 UTC (permalink / raw)
To: Sumit Semwal
Cc: agross, lgirdwood, broonie, robh+dt, nishakumari, linux-arm-msm,
linux-kernel, devicetree, kgunda, rnayak
In-Reply-To: <20200528154625.17742-5-sumit.semwal@linaro.org>
On Thu 28 May 08:46 PDT 2020, Sumit Semwal wrote:
> From: Nisha Kumari <nishakumari@codeaurora.org>
>
> Qualcomm platforms have LAB(LCD AMOLED Boost)/IBB(Inverting Buck Boost)
> regulators, labibb for short, which are used as power supply for
> LCD Mode displays.
>
> This patch adds labibb regulator driver for pmi8998 PMIC, found on
> SDM845 platforms.
>
> Signed-off-by: Nisha Kumari <nishakumari@codeaurora.org>
> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
>
> --
> v2: sumits: reworked the driver for more common code, and addressed
> review comments from v1
> v3: sumits: addressed review comments from v2; moved to use core
> regulator features like enable_time, off_on_delay, and the newly
> added poll_enabled_time. Moved the check_enabled functionality
> to core framework via poll_enabled_time.
>
> ---
> drivers/regulator/Kconfig | 10 +
> drivers/regulator/Makefile | 1 +
> drivers/regulator/qcom-labibb-regulator.c | 224 ++++++++++++++++++++++
> 3 files changed, 235 insertions(+)
> create mode 100644 drivers/regulator/qcom-labibb-regulator.c
>
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index f4b72cb098ef..58704a9fd05d 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -1167,5 +1167,15 @@ config REGULATOR_WM8994
> This driver provides support for the voltage regulators on the
> WM8994 CODEC.
>
> +config REGULATOR_QCOM_LABIBB
> + tristate "QCOM LAB/IBB regulator support"
> + depends on SPMI || COMPILE_TEST
> + help
> + This driver supports Qualcomm's LAB/IBB regulators present on the
> + Qualcomm's PMIC chip pmi8998. QCOM LAB and IBB are SPMI
> + based PMIC implementations. LAB can be used as positive
> + boost regulator and IBB can be used as a negative boost regulator
> + for LCD display panel.
> +
> endif
>
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 6610ee001d9a..5b313786c0e8 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -87,6 +87,7 @@ obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
> obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
> obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
> obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
> +obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o
> obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
> obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
> obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
> diff --git a/drivers/regulator/qcom-labibb-regulator.c b/drivers/regulator/qcom-labibb-regulator.c
> new file mode 100644
> index 000000000000..634d08461c6e
> --- /dev/null
> +++ b/drivers/regulator/qcom-labibb-regulator.c
> @@ -0,0 +1,225 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// Copyright (c) 2020, The Linux Foundation. All rights reserved.
> +
> +#include <linux/module.h>
> +#include <linux/of_irq.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/of_regulator.h>
> +
> +#define REG_PERPH_TYPE 0x04
> +#define QCOM_LAB_TYPE 0x24
> +#define QCOM_IBB_TYPE 0x20
> +
> +#define REG_LABIBB_STATUS1 0x08
> +#define REG_LABIBB_ENABLE_CTL 0x46
> +#define LABIBB_STATUS1_VREG_OK_BIT BIT(7)
> +#define LABIBB_CONTROL_ENABLE BIT(7)
> +
> +#define LAB_ENABLE_CTL_MASK BIT(7)
> +#define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6))
> +
> +#define LABIBB_ENABLE_TIME 1000
> +#define LAB_POLL_ENABLED_TIME (LABIBB_ENABLE_TIME * 2)
> +#define IBB_POLL_ENABLED_TIME (LABIBB_ENABLE_TIME * 10)
> +#define LABIBB_OFF_ON_DELAY (8200)
> +
> +struct labibb_regulator {
> + struct regulator_desc desc;
> + struct device *dev;
> + struct regmap *regmap;
> + struct regulator_dev *rdev;
> + u16 base;
> + u8 type;
> +};
> +
> +struct labibb_regulator_data {
> + u16 base;
> + const char *name;
> + u8 type;
> + unsigned int poll_enabled_time;
> +};
> +
> +static int qcom_labibb_regulator_is_enabled(struct regulator_dev *rdev)
> +{
> + int ret;
> + unsigned int val;
> + struct labibb_regulator *reg = rdev_get_drvdata(rdev);
> +
> + ret = regmap_read(reg->regmap, reg->base + REG_LABIBB_STATUS1, &val);
> + if (ret < 0) {
> + dev_err(reg->dev, "Read register failed ret = %d\n", ret);
> + return ret;
> + }
> + return !!(val & LABIBB_STATUS1_VREG_OK_BIT);
> +}
> +
> +static int qcom_labibb_regulator_enable(struct regulator_dev *rdev)
> +{
> + int ret;
> + struct labibb_regulator *reg = rdev_get_drvdata(rdev);
> +
> + ret = regulator_enable_regmap(rdev);
> + if (ret < 0)
> + dev_err(reg->dev, "Write failed: enable %s regulator\n",
> + reg->desc.name);
If you return a negative value the various callers of
_regulator_do_enable() and _regulator_do_disable() will print an error
message for you.
As such you don't need these wrappers and should be able to just specify
regulator_enable_regmap and regulator_disable_regmap as you enable and
disable functions in qcom_labibb_ops directly.
> +
> + return ret;
> +}
> +
> +static int qcom_labibb_regulator_disable(struct regulator_dev *rdev)
> +{
> + int ret = 0;
> + struct labibb_regulator *reg = rdev_get_drvdata(rdev);
> +
> + ret = regulator_disable_regmap(rdev);
> + if (ret < 0)
> + dev_err(reg->dev, "Disable failed: disable %s\n",
> + reg->desc.name);
> +
> + return ret;
> +}
> +
> +static struct regulator_ops qcom_labibb_ops = {
> + .enable = qcom_labibb_regulator_enable,
> + .disable = qcom_labibb_regulator_disable,
> + .is_enabled = qcom_labibb_regulator_is_enabled,
> +};
> +
> +static int register_labibb_regulator(struct labibb_regulator *reg,
> + const struct labibb_regulator_data *reg_data,
> + struct device_node *of_node)
> +{
> + struct regulator_config cfg = {};
> +
> + reg->base = reg_data->base;
> + reg->type = reg_data->type;
> + reg->desc.enable_reg = reg->base + REG_LABIBB_ENABLE_CTL;
> + reg->desc.enable_val = LABIBB_CONTROL_ENABLE;
> + reg->desc.of_match = reg_data->name;
> + reg->desc.name = reg_data->name;
> + reg->desc.owner = THIS_MODULE;
> + reg->desc.type = REGULATOR_VOLTAGE;
> + reg->desc.ops = &qcom_labibb_ops;
> +
> + reg->desc.enable_time = LABIBB_ENABLE_TIME;
> + reg->desc.poll_enabled_time = reg_data->poll_enabled_time;
> + reg->desc.off_on_delay = LABIBB_OFF_ON_DELAY;
> +
> + cfg.dev = reg->dev;
> + cfg.driver_data = reg;
> + cfg.regmap = reg->regmap;
> + cfg.of_node = of_node;
> +
> + reg->rdev = devm_regulator_register(reg->dev, ®->desc, &cfg);
> + return PTR_ERR_OR_ZERO(reg->rdev);
If you change the return type to struct regulator_dev *, you can clean
this up by just:
return devm_regulator_register()
And then if (IS_ERR()) that in the caller.
> +}
> +
> +static const struct labibb_regulator_data pmi8998_labibb_data[] = {
> + {0xde00, "lab", QCOM_LAB_TYPE, LAB_POLL_ENABLED_TIME},
> + {0xdc00, "ibb", QCOM_IBB_TYPE, IBB_POLL_ENABLED_TIME},
> + { },
> +};
> +
> +static const struct of_device_id qcom_labibb_match[] = {
> + { .compatible = "qcom,pmi8998-lab-ibb", .data = &pmi8998_labibb_data},
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, qcom_labibb_match);
> +
> +static int qcom_labibb_regulator_probe(struct platform_device *pdev)
> +{
> + struct labibb_regulator *labibb_reg;
> + struct device *dev;
> + struct device_node *child;
> + const struct of_device_id *match;
> + const struct labibb_regulator_data *reg_data;
> + struct regmap *reg_regmap;
> + unsigned int type;
> + int ret;
> +
> + reg_regmap = dev_get_regmap(pdev->dev.parent, NULL);
> + if (!reg_regmap) {
> + dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
> + return -ENODEV;
> + }
> +
> + dev = &pdev->dev;
Do this as you declare "dev" above.
> +
> + match = of_match_device(qcom_labibb_match, &pdev->dev);
> + if (!match)
> + return -ENODEV;
> +
> + for (reg_data = match->data; reg_data->name; reg_data++) {
> + child = of_get_child_by_name(pdev->dev.of_node, reg_data->name);
> +
> + /* TODO: This validates if the type of regulator is indeed
> + * what's mentioned in DT.
> + * I'm not sure if this is needed, but we'll keep it for now.
> + */
> + ret = regmap_read(reg_regmap, reg_data->base + REG_PERPH_TYPE,
> + &type);
> + if (ret < 0) {
> + dev_err(dev,
> + "Peripheral type read failed ret=%d\n",
> + ret);
> + return -EINVAL;
> + }
> +
> + if ((type != QCOM_LAB_TYPE) && (type != QCOM_IBB_TYPE)) {
Given that you don't actually validate the information in DT, but rather
just check that the data in the pmi8998_labibb_data is accurate this is
merely a sanity check during development. So I think you should reduce
this to:
if (WARN_ON(type != reg_data->type))
return -EINVAL;
You can thereby remove the TODO comment above as well.
What you should do though is check that "child" is not NULL - to catch
the case where the DT doesn't specify both lab and ibb.
> + dev_err(dev,
> + "qcom_labibb: unknown peripheral type\n");
> + return -EINVAL;
> + } else if (type != reg_data->type) {
> + dev_err(dev,
> + "qcom_labibb: type %x doesn't match DT %x\n",
> + type, reg_data->type);
> + return -EINVAL;
> + }
> +
> + labibb_reg = devm_kzalloc(&pdev->dev, sizeof(*labibb_reg),
> + GFP_KERNEL);
> + if (!labibb_reg)
> + return -ENOMEM;
> +
> + labibb_reg->regmap = reg_regmap;
> + labibb_reg->dev = dev;
> +
> + switch (reg_data->type) {
> + case QCOM_LAB_TYPE:
> + labibb_reg->desc.enable_mask = LAB_ENABLE_CTL_MASK;
All other parts of labibb_reg->desc are filled out inside
register_labibb_regulator(), pass the mask as an argument instead to
consolidate the setup.
> + break;
> +
> + case QCOM_IBB_TYPE:
> + labibb_reg->desc.enable_mask = IBB_ENABLE_CTL_MASK;
> + break;
> + }
> +
> + dev_info(dev, "Registering %s regulator\n", child->full_name);
> +
> + ret = register_labibb_regulator(labibb_reg, reg_data, child);
> + if (ret < 0) {
> + dev_err(dev,
> + "qcom_labibb: error registering %s : %d\n",
> + child->full_name, ret);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static struct platform_driver qcom_labibb_regulator_driver = {
> + .driver = {
> + .name = "qcom-lab-ibb-regulator",
> + .of_match_table = qcom_labibb_match,
> + },
> + .probe = qcom_labibb_regulator_probe,
> +};
I think you should drop the tabs before the various = in this
definition.
Regards,
Bjorn
> +module_platform_driver(qcom_labibb_regulator_driver);
> +
> +MODULE_DESCRIPTION("Qualcomm labibb driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.26.2
>
^ permalink raw reply
* [PATCH V2] dt-bindings: regulator: Convert anatop regulator to json-schema
From: Anson Huang @ 2020-05-29 1:59 UTC (permalink / raw)
To: lgirdwood, broonie, robh+dt, paul.liu, linux-kernel, devicetree; +Cc: Linux-imx
Convert the anatop regulator binding to DT schema format using json-schema.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
Changes since V1:
- remove definition of "regulator-name" which is a standrad property;
- add "unevaluatedProperties: false".
---
.../bindings/regulator/anatop-regulator.txt | 40 ---------
.../bindings/regulator/anatop-regulator.yaml | 94 ++++++++++++++++++++++
2 files changed, 94 insertions(+), 40 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/regulator/anatop-regulator.txt
create mode 100644 Documentation/devicetree/bindings/regulator/anatop-regulator.yaml
diff --git a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
deleted file mode 100644
index a3106c7..0000000
--- a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-Anatop Voltage regulators
-
-Required properties:
-- compatible: Must be "fsl,anatop-regulator"
-- regulator-name: A string used as a descriptive name for regulator outputs
-- anatop-reg-offset: Anatop MFD register offset
-- anatop-vol-bit-shift: Bit shift for the register
-- anatop-vol-bit-width: Number of bits used in the register
-- anatop-min-bit-val: Minimum value of this register
-- anatop-min-voltage: Minimum voltage of this regulator
-- anatop-max-voltage: Maximum voltage of this regulator
-
-Optional properties:
-- anatop-delay-reg-offset: Anatop MFD step time register offset
-- anatop-delay-bit-shift: Bit shift for the step time register
-- anatop-delay-bit-width: Number of bits used in the step time register
-- vin-supply: The supply for this regulator
-- anatop-enable-bit: Regulator enable bit offset
-
-Any property defined as part of the core regulator
-binding, defined in regulator.txt, can also be used.
-
-Example:
-
- regulator-vddpu {
- compatible = "fsl,anatop-regulator";
- regulator-name = "vddpu";
- regulator-min-microvolt = <725000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- anatop-reg-offset = <0x140>;
- anatop-vol-bit-shift = <9>;
- anatop-vol-bit-width = <5>;
- anatop-delay-reg-offset = <0x170>;
- anatop-delay-bit-shift = <24>;
- anatop-delay-bit-width = <2>;
- anatop-min-bit-val = <1>;
- anatop-min-voltage = <725000>;
- anatop-max-voltage = <1300000>;
- };
diff --git a/Documentation/devicetree/bindings/regulator/anatop-regulator.yaml b/Documentation/devicetree/bindings/regulator/anatop-regulator.yaml
new file mode 100644
index 0000000..e7b3abe
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/anatop-regulator.yaml
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/anatop-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale Anatop Voltage Regulators
+
+maintainers:
+ - Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+
+allOf:
+ - $ref: "regulator.yaml#"
+
+properties:
+ compatible:
+ const: fsl,anatop-regulator
+
+ regulator-name: true
+
+ anatop-reg-offset:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the anatop MFD register offset.
+
+ anatop-vol-bit-shift:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the bit shift for the register.
+
+ anatop-vol-bit-width:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the number of bits used in the register.
+
+ anatop-min-bit-val:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the minimum value of this register.
+
+ anatop-min-voltage:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the minimum voltage of this regulator.
+
+ anatop-max-voltage:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the maximum voltage of this regulator.
+
+ anatop-delay-reg-offset:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the anatop MFD step time register offset.
+
+ anatop-delay-bit-shift:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the bit shift for the step time register.
+
+ anatop-delay-bit-width:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing the number of bits used in the step time register.
+
+ anatop-enable-bit:
+ $ref: '/schemas/types.yaml#/definitions/uint32'
+ description: u32 value representing regulator enable bit offset.
+
+ vin-supply:
+ $ref: '/schemas/types.yaml#/definitions/phandle'
+ description: input supply phandle.
+
+required:
+ - compatible
+ - regulator-name
+ - anatop-reg-offset
+ - anatop-vol-bit-shift
+ - anatop-vol-bit-width
+ - anatop-min-bit-val
+ - anatop-min-voltage
+ - anatop-max-voltage
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ regulator-vddpu {
+ compatible = "fsl,anatop-regulator";
+ regulator-name = "vddpu";
+ regulator-min-microvolt = <725000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ anatop-reg-offset = <0x140>;
+ anatop-vol-bit-shift = <9>;
+ anatop-vol-bit-width = <5>;
+ anatop-delay-reg-offset = <0x170>;
+ anatop-delay-bit-shift = <24>;
+ anatop-delay-bit-width = <2>;
+ anatop-min-bit-val = <1>;
+ anatop-min-voltage = <725000>;
+ anatop-max-voltage = <1300000>;
+ };
--
2.7.4
^ permalink raw reply related
* [PATCH V3] dt-bindings: timer: Convert i.MX GPT to json-schema
From: Anson Huang @ 2020-05-29 2:04 UTC (permalink / raw)
To: daniel.lezcano, tglx, robh+dt, shawnguo, s.hauer, kernel,
festevam, linux-kernel, devicetree, linux-arm-kernel
Cc: Linux-imx
Convert the i.MX GPT binding to DT schema format using json-schema.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
Changes since V2:
- in compatible properties, group all the ones with the same
fallback to a single 'items' list using enum for the first entry.
---
.../devicetree/bindings/timer/fsl,imxgpt.txt | 45 --------------
.../devicetree/bindings/timer/fsl,imxgpt.yaml | 72 ++++++++++++++++++++++
2 files changed, 72 insertions(+), 45 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/timer/fsl,imxgpt.txt
create mode 100644 Documentation/devicetree/bindings/timer/fsl,imxgpt.yaml
diff --git a/Documentation/devicetree/bindings/timer/fsl,imxgpt.txt b/Documentation/devicetree/bindings/timer/fsl,imxgpt.txt
deleted file mode 100644
index 5d8fd5b..0000000
--- a/Documentation/devicetree/bindings/timer/fsl,imxgpt.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-Freescale i.MX General Purpose Timer (GPT)
-
-Required properties:
-
-- compatible : should be one of following:
- for i.MX1:
- - "fsl,imx1-gpt";
- for i.MX21:
- - "fsl,imx21-gpt";
- for i.MX27:
- - "fsl,imx27-gpt", "fsl,imx21-gpt";
- for i.MX31:
- - "fsl,imx31-gpt";
- for i.MX25:
- - "fsl,imx25-gpt", "fsl,imx31-gpt";
- for i.MX50:
- - "fsl,imx50-gpt", "fsl,imx31-gpt";
- for i.MX51:
- - "fsl,imx51-gpt", "fsl,imx31-gpt";
- for i.MX53:
- - "fsl,imx53-gpt", "fsl,imx31-gpt";
- for i.MX6Q:
- - "fsl,imx6q-gpt", "fsl,imx31-gpt";
- for i.MX6DL:
- - "fsl,imx6dl-gpt";
- for i.MX6SL:
- - "fsl,imx6sl-gpt", "fsl,imx6dl-gpt";
- for i.MX6SX:
- - "fsl,imx6sx-gpt", "fsl,imx6dl-gpt";
-- reg : specifies base physical address and size of the registers.
-- interrupts : should be the gpt interrupt.
-- clocks : the clocks provided by the SoC to drive the timer, must contain
- an entry for each entry in clock-names.
-- clock-names : must include "ipg" entry first, then "per" entry.
-
-Example:
-
-gpt1: timer@10003000 {
- compatible = "fsl,imx27-gpt", "fsl,imx21-gpt";
- reg = <0x10003000 0x1000>;
- interrupts = <26>;
- clocks = <&clks IMX27_CLK_GPT1_IPG_GATE>,
- <&clks IMX27_CLK_PER1_GATE>;
- clock-names = "ipg", "per";
-};
diff --git a/Documentation/devicetree/bindings/timer/fsl,imxgpt.yaml b/Documentation/devicetree/bindings/timer/fsl,imxgpt.yaml
new file mode 100644
index 0000000..883f7f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,imxgpt.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/fsl,imxgpt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX General Purpose Timer (GPT)
+
+maintainers:
+ - Sascha Hauer <s.hauer@pengutronix.de>
+
+properties:
+ compatible:
+ oneOf:
+ - const: fsl,imx1-gpt
+ - const: fsl,imx21-gpt
+ - items:
+ - const: fsl,imx27-gpt
+ - const: fsl,imx21-gpt
+ - const: fsl,imx31-gpt
+ - items:
+ - enum:
+ - fsl,imx25-gpt
+ - fsl,imx50-gpt
+ - fsl,imx51-gpt
+ - fsl,imx53-gpt
+ - fsl,imx6q-gpt
+ - const: fsl,imx31-gpt
+ - const: fsl,imx6dl-gpt
+ - items:
+ - enum:
+ - fsl,imx6sl-gpt
+ - fsl,imx6sx-gpt
+ - const: fsl,imx6dl-gpt
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: SoC GPT ipg clock
+ - description: SoC GPT per clock
+
+ clock-names:
+ items:
+ - const: ipg
+ - const: per
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx27-clock.h>
+
+ timer@10003000 {
+ compatible = "fsl,imx27-gpt", "fsl,imx21-gpt";
+ reg = <0x10003000 0x1000>;
+ interrupts = <26>;
+ clocks = <&clks IMX27_CLK_GPT1_IPG_GATE>,
+ <&clks IMX27_CLK_PER1_GATE>;
+ clock-names = "ipg", "per";
+ };
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v3 5/5] regulator: qcom: labibb: Add SC interrupt handling
From: Bjorn Andersson @ 2020-05-29 2:28 UTC (permalink / raw)
To: Sumit Semwal
Cc: agross, lgirdwood, broonie, robh+dt, nishakumari, linux-arm-msm,
linux-kernel, devicetree, kgunda, rnayak
In-Reply-To: <20200528154625.17742-6-sumit.semwal@linaro.org>
On Thu 28 May 08:46 PDT 2020, Sumit Semwal wrote:
> From: Nisha Kumari <nishakumari@codeaurora.org>
>
> Add Short circuit interrupt handling and recovery for the lab and
> ibb regulators on qcom platforms.
>
> The client panel drivers need to register for REGULATOR_EVENT_OVER_CURRENT
> notification which will be triggered on short circuit. They should
> try to enable the regulator once, and if it doesn't get enabled,
> handle shutting down the panel accordingly.
>
> Signed-off-by: Nisha Kumari <nishakumari@codeaurora.org>
It would be nice to see a short summary of your changes from the
original patch here, like:
[sumit: Changed this and that]
> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
>
> --
> v2: sumits: reworked handling to user regmap_read_poll_timeout, and handle it
> per-regulator instead of clearing both lab and ibb errors on either irq
> triggering. Also added REGULATOR_EVENT_OVER_CURRENT handling and
> notification to clients.
> v3: sumits: updated as per review comments of v2: removed spurious check for
> irq in handler and some unused variables; inlined some of the code,
> omitted IRQF_TRIGGER_RISING as it's coming from DT.
>
> ---
> drivers/regulator/qcom-labibb-regulator.c | 92 +++++++++++++++++++++++
> 1 file changed, 92 insertions(+)
>
> diff --git a/drivers/regulator/qcom-labibb-regulator.c b/drivers/regulator/qcom-labibb-regulator.c
> index 634d08461c6e..695ffac71e81 100644
> --- a/drivers/regulator/qcom-labibb-regulator.c
> +++ b/drivers/regulator/qcom-labibb-regulator.c
> @@ -1,6 +1,7 @@
> // SPDX-License-Identifier: GPL-2.0-only
> // Copyright (c) 2020, The Linux Foundation. All rights reserved.
>
> +#include <linux/interrupt.h>
> #include <linux/module.h>
> #include <linux/of_irq.h>
> #include <linux/of.h>
> @@ -18,6 +19,7 @@
> #define REG_LABIBB_ENABLE_CTL 0x46
> #define LABIBB_STATUS1_VREG_OK_BIT BIT(7)
> #define LABIBB_CONTROL_ENABLE BIT(7)
> +#define LABIBB_STATUS1_SC_DETECT_BIT BIT(6)
>
> #define LAB_ENABLE_CTL_MASK BIT(7)
> #define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6))
> @@ -27,12 +29,17 @@
> #define IBB_POLL_ENABLED_TIME (LABIBB_ENABLE_TIME * 10)
> #define LABIBB_OFF_ON_DELAY (8200)
>
> +#define POLLING_SCP_DONE_INTERVAL_US 5000
> +#define POLLING_SCP_TIMEOUT 16000
> +
> struct labibb_regulator {
> struct regulator_desc desc;
> struct device *dev;
> struct regmap *regmap;
> struct regulator_dev *rdev;
> u16 base;
> + int sc_irq;
This is now a local variable in register_labibb_regulator().
> + int vreg_enabled;
bool is a better representation of this (and the vreg_ prefix doesn't
really add value).
> u8 type;
> };
>
> @@ -65,6 +72,8 @@ static int qcom_labibb_regulator_enable(struct regulator_dev *rdev)
> if (ret < 0)
> dev_err(reg->dev, "Write failed: enable %s regulator\n",
> reg->desc.name);
> + else
> + reg->vreg_enabled = 1;
No I see why you add these wrappers around the regmap in the previous
patch.
My request to not print an error message on enable/disable errors
remains.
>
> return ret;
> }
> @@ -78,6 +87,8 @@ static int qcom_labibb_regulator_disable(struct regulator_dev *rdev)
> if (ret < 0)
> dev_err(reg->dev, "Disable failed: disable %s\n",
> reg->desc.name);
> + else
> + reg->vreg_enabled = 0;
>
> return ret;
> }
> @@ -88,11 +99,70 @@ static struct regulator_ops qcom_labibb_ops = {
> .is_enabled = qcom_labibb_regulator_is_enabled,
> };
>
> +static irqreturn_t labibb_sc_err_handler(int irq, void *_reg)
> +{
> + int ret;
> + u16 reg;
> + unsigned int val;
> + struct labibb_regulator *labibb_reg = _reg;
> + bool in_sc_err, scp_done = false;
> +
> + ret = regmap_read(labibb_reg->regmap,
> + labibb_reg->base + REG_LABIBB_STATUS1, &val);
> + if (ret < 0) {
> + dev_err(labibb_reg->dev, "sc_err_irq: Read failed, ret=%d\n",
> + ret);
> + return IRQ_HANDLED;
> + }
> +
> + dev_dbg(labibb_reg->dev, "%s SC error triggered! STATUS1 = %d\n",
> + labibb_reg->desc.name, val);
> +
> + in_sc_err = !!(val & LABIBB_STATUS1_SC_DETECT_BIT);
> +
> + /*
> + * The SC(short circuit) fault would trigger PBS(Portable Batch
> + * System) to disable regulators for protection. This would
> + * cause the SC_DETECT status being cleared so that it's not
> + * able to get the SC fault status.
> + * Check if the regulator is enabled in the driver but
> + * disabled in hardware, this means a SC fault had happened
> + * and SCP handling is completed by PBS.
> + */
> + if (!in_sc_err) {
> +
Empty line
Regards,
Bjorn
> + reg = labibb_reg->base + REG_LABIBB_ENABLE_CTL;
> +
> + ret = regmap_read_poll_timeout(labibb_reg->regmap,
> + reg, val,
> + !(val & LABIBB_CONTROL_ENABLE),
> + POLLING_SCP_DONE_INTERVAL_US,
> + POLLING_SCP_TIMEOUT);
> +
> + if (!ret && labibb_reg->vreg_enabled) {
> + dev_dbg(labibb_reg->dev,
> + "%s has been disabled by SCP\n",
> + labibb_reg->desc.name);
> + scp_done = true;
> + }
> + }
> +
> + if (in_sc_err || scp_done) {
> + regulator_lock(labibb_reg->rdev);
> + regulator_notifier_call_chain(labibb_reg->rdev,
> + REGULATOR_EVENT_OVER_CURRENT,
> + NULL);
> + regulator_unlock(labibb_reg->rdev);
> + }
> + return IRQ_HANDLED;
> +}
> +
> static int register_labibb_regulator(struct labibb_regulator *reg,
> const struct labibb_regulator_data *reg_data,
> struct device_node *of_node)
> {
> struct regulator_config cfg = {};
> + int ret;
>
> reg->base = reg_data->base;
> reg->type = reg_data->type;
> @@ -108,6 +178,28 @@ static int register_labibb_regulator(struct labibb_regulator *reg,
> reg->desc.poll_enabled_time = reg_data->poll_enabled_time;
> reg->desc.off_on_delay = LABIBB_OFF_ON_DELAY;
>
> + reg->sc_irq = -EINVAL;
> + ret = of_irq_get_byname(of_node, "sc-err");
> + if (ret < 0) {
> + dev_err(reg->dev, "Unable to get sc-err, ret = %d\n",
> + ret);
> + return ret;
> + } else
> + reg->sc_irq = ret;
> +
> + if (reg->sc_irq > 0) {
> + ret = devm_request_threaded_irq(reg->dev,
> + reg->sc_irq,
> + NULL, labibb_sc_err_handler,
> + IRQF_ONESHOT,
> + "sc-err", reg);
> + if (ret) {
> + dev_err(reg->dev, "Failed to register sc-err irq ret=%d\n",
> + ret);
> + return ret;
> + }
> + }
> +
> cfg.dev = reg->dev;
> cfg.driver_data = reg;
> cfg.regmap = reg->regmap;
> --
> 2.26.2
>
^ permalink raw reply
* Question about "xxx,yyy" style property
From: Kuninori Morimoto @ 2020-05-29 2:41 UTC (permalink / raw)
To: Rob Herring
Cc: Liam Girdwood, Mark Brown, Mark Rutland, devicetree, alsa-devel,
linux-kernel
In-Reply-To: <20200528223916.GA804926@bogus>
The Subject was "Re: [PATCH] ASoC: dt-bindings: simple-card: care missing address #address-cells"
Hi Rob
I'm trying to create v2 of simple-card patch,
And got issue which I can't solve by myself.
I think "xxx,yyy" (= which has "," at the property name)
needs special care, but it is very un-understandable...
Now, I'm give up.
So, can I ask you 2 things about Yaml Doc "xxx,yyy" type property ?
========================
1) reference own definitions from "xxx,yyy"
========================
I guess "xxx,yyy" naming property needs to has "description", right ?
But, it is OK if it references "/schemas/xxxx"
--- OK ------
xxx,yyy:
description: xxx
$ref: /schemas/types.yaml#/definitions/phandle-array
-------------
but, will be error if it references own definitions
--- NG ------
xxx,yyy:
description: xxx
$ref: "#/definitions/mydef"
-------------
This is the related error
-- error(?) --
xxx.yaml: properties:xxx,yyy:\
$ref: '#/definitions/mydef' does not match 'types.yaml#[/]{0,1}definitions/.*'
--------------
# but, there is no problem if it was defined as "patternProperties"
Q. The "xxx,yyy" property can't references own definitions,
or needs some magical extra settings ??
========================
2) phandle for "xxx,yyy"
========================
I noticed that it seems "xxx,yyy" property can't be referenced.
Here, "xxx,yyy" has "type: object" and "additionalProperties: false"
(below didn't happen if it doesn't have "additionalProperties: false")
If "xxx,yyy" has phandle, but not referenced,
This is not a problem.
--- OK ---
...
foo = <&bar>;
...
xxx_yyy: xxx,yyy {
...
};
--------------
But will be error if it is referenced.
--- NG ---
foo = <&xxx_yyy>;
...
xxx_yyy: xxx,yyy {
...
};
------------
The error is
-- error ---
xxx.yaml: xxx.yyy: \
Additional properties are not allowed ('phandle' was unexpected)
------------
Q. The "xxx,yyy" needs magical settings to be referenced, or can't be ?
^ permalink raw reply
* Re: [PATCH 1/9] dt-bindings: clock: Convert i.MX5 clock to json-schema
From: Rob Herring @ 2020-05-29 2:45 UTC (permalink / raw)
To: Anson Huang
Cc: linux-arm-kernel, kernel, shawnguo, shc_work, devicetree,
mturquette, sboyd, festevam, linux-clk, linux-kernel, robh+dt,
Linux-imx, s.trumtrar, s.hauer
In-Reply-To: <1590650879-18288-2-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:51 +0800, Anson Huang wrote:
> Convert the i.MX5 clock binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx5-clock.txt | 28 ----------
> .../devicetree/bindings/clock/imx5-clock.yaml | 63 ++++++++++++++++++++++
> 2 files changed, 63 insertions(+), 28 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx5-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx5-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 2/9] dt-bindings: clock: Convert i.MX35 clock to json-schema
From: Rob Herring @ 2020-05-29 2:48 UTC (permalink / raw)
To: Anson Huang
Cc: shc_work, linux-arm-kernel, sboyd, s.hauer, Linux-imx, robh+dt,
linux-clk, linux-kernel, devicetree, s.trumtrar, kernel, shawnguo,
festevam, mturquette
In-Reply-To: <1590650879-18288-3-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:52 +0800, Anson Huang wrote:
> Convert the i.MX35 clock binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx35-clock.txt | 114 -----------------
> .../devicetree/bindings/clock/imx35-clock.yaml | 137 +++++++++++++++++++++
> 2 files changed, 137 insertions(+), 114 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx35-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx35-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 3/9] dt-bindings: clock: Convert i.MX31 clock to json-schema
From: Rob Herring @ 2020-05-29 2:48 UTC (permalink / raw)
To: Anson Huang
Cc: linux-arm-kernel, linux-kernel, shc_work, s.hauer, shawnguo,
devicetree, robh+dt, festevam, linux-clk, kernel, Linux-imx,
s.trumtrar, mturquette, sboyd
In-Reply-To: <1590650879-18288-4-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:53 +0800, Anson Huang wrote:
> Convert the i.MX31 clock binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx31-clock.txt | 90 ----------------
> .../devicetree/bindings/clock/imx31-clock.yaml | 118 +++++++++++++++++++++
> 2 files changed, 118 insertions(+), 90 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx31-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx31-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 3/4] mailbox: qcom: Add ipq6018 apcs compatible
From: kbuild test robot @ 2020-05-29 2:41 UTC (permalink / raw)
To: Sivaprakash Murugesan, agross, bjorn.andersson, robh+dt,
jassisinghbrar, linux-arm-msm, devicetree, linux-kernel
Cc: kbuild-all, clang-built-linux, Sivaprakash Murugesan
In-Reply-To: <1590583092-24290-4-git-send-email-sivaprak@codeaurora.org>
[-- Attachment #1: Type: text/plain, Size: 2169 bytes --]
Hi Sivaprakash,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v5.7-rc7 next-20200528]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Sivaprakash-Murugesan/Add-ipq6018-apcs-mailbox-driver/20200527-204025
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: x86_64-randconfig-a004-20200528 (attached as .config)
compiler: clang version 11.0.0 (https://github.com/llvm/llvm-project 2d068e534f1671459e1b135852c1b3c10502e929)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64
If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <lkp@intel.com>
All warnings (new ones prefixed by >>, old ones prefixed by <<):
>> drivers/mailbox/qcom-apcs-ipc-mailbox.c:48:34: warning: unused variable 'apcs_clk_match_table' [-Wunused-const-variable]
static const struct of_device_id apcs_clk_match_table[] = {
^
1 warning generated.
vim +/apcs_clk_match_table +48 drivers/mailbox/qcom-apcs-ipc-mailbox.c
47
> 48 static const struct of_device_id apcs_clk_match_table[] = {
49 { .compatible = "qcom,ipq6018-apcs-apps-global", .data = "qcom,apss-ipq6018-clk", },
50 { .compatible = "qcom,msm8916-apcs-kpss-global", .data = "qcom-apcs-msm8916-clk", },
51 { .compatible = "qcom,qcs404-apcs-apps-global", .data = "qcom-apcs-msm8916-clk", },
52 {}
53 };
54
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 41054 bytes --]
^ permalink raw reply
* Re: [PATCH 2/6] arm64: dts: qcom: sm8250: add apps_smmu node
From: Bjorn Andersson @ 2020-05-29 2:48 UTC (permalink / raw)
To: Jonathan Marek
Cc: Sai Prakash Ranjan, linux-arm-msm, Andy Gross, Rob Herring,
devicetree, linux-kernel, linux-arm-msm-owner
In-Reply-To: <8f9a5750-7909-4be7-6780-198d8c242af3@marek.ca>
On Mon 25 May 04:53 PDT 2020, Jonathan Marek wrote:
[..]
> I guess the commit message is ambiguous, that's not what I meant. Is "Now
> that the kernel initializes the iommu, the bypass mappings set by the
> bootloader are cleared. Adding the iommus property is required so that new
> mappings are created for UFS." better?
>
This looks better, but it's actually not a bypass mapping that we
inherit from the bootloader, it's the stream mapping pointing to a
disabled (~ARM_SMMU_SCTLR_M) context bank. So when we wipe the stream
mappings we will fault on the unmatched stream - which secure world
"handles" for us...
As such, I think you should replace "bypass" with "stream".
Regards,
Bjorn
^ permalink raw reply
* Re: [PATCH 4/9] dt-bindings: clock: Convert i.MX28 clock to json-schema
From: Rob Herring @ 2020-05-29 2:51 UTC (permalink / raw)
To: Anson Huang
Cc: mturquette, Linux-imx, robh+dt, shawnguo, shc_work, s.trumtrar,
devicetree, s.hauer, kernel, linux-clk, linux-arm-kernel,
linux-kernel, festevam, sboyd
In-Reply-To: <1590650879-18288-5-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:54 +0800, Anson Huang wrote:
> Convert the i.MX28 clock binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx28-clock.txt | 93 -----------------
> .../devicetree/bindings/clock/imx28-clock.yaml | 113 +++++++++++++++++++++
> 2 files changed, 113 insertions(+), 93 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx28-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx28-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 5/9] dt-bindings: clock: Convert i.MX23 clock to json-schema
From: Rob Herring @ 2020-05-29 2:51 UTC (permalink / raw)
To: Anson Huang
Cc: s.hauer, mturquette, robh+dt, shc_work, linux-kernel, kernel,
linux-arm-kernel, festevam, linux-clk, Linux-imx, sboyd,
devicetree, s.trumtrar, shawnguo
In-Reply-To: <1590650879-18288-6-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:55 +0800, Anson Huang wrote:
> Convert the i.MX23 clock binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx23-clock.txt | 70 -----------------
> .../devicetree/bindings/clock/imx23-clock.yaml | 90 ++++++++++++++++++++++
> 2 files changed, 90 insertions(+), 70 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx23-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx23-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 6/9] dt-bindings: clock: Convert i.MX27 clock to json-schema
From: Rob Herring @ 2020-05-29 2:52 UTC (permalink / raw)
To: Anson Huang
Cc: linux-arm-kernel, devicetree, festevam, robh+dt, sboyd, shawnguo,
Linux-imx, linux-clk, linux-kernel, s.trumtrar, kernel, shc_work,
mturquette, s.hauer
In-Reply-To: <1590650879-18288-7-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:56 +0800, Anson Huang wrote:
> Convert the i.MX27 clock binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx27-clock.txt | 27 -----------
> .../devicetree/bindings/clock/imx27-clock.yaml | 53 ++++++++++++++++++++++
> 2 files changed, 53 insertions(+), 27 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx27-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx27-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 7/9] dt-bindings: clock: Convert i.MX25 clock to json-schema
From: Rob Herring @ 2020-05-29 2:53 UTC (permalink / raw)
To: Anson Huang
Cc: kernel, linux-clk, s.hauer, mturquette, devicetree, linux-kernel,
sboyd, s.trumtrar, linux-arm-kernel, festevam, robh+dt, Linux-imx,
shawnguo, shc_work
In-Reply-To: <1590650879-18288-8-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:57 +0800, Anson Huang wrote:
> Convert the i.MX25 clock binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx25-clock.txt | 160 ------------------
> .../devicetree/bindings/clock/imx25-clock.yaml | 184 +++++++++++++++++++++
> 2 files changed, 184 insertions(+), 160 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx25-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx25-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 8/9] dt-bindings: clock: Convert i.MX21 clock to json-schema
From: Rob Herring @ 2020-05-29 2:53 UTC (permalink / raw)
To: Anson Huang
Cc: s.trumtrar, linux-kernel, sboyd, shawnguo, festevam, linux-clk,
robh+dt, devicetree, Linux-imx, kernel, mturquette, s.hauer,
shc_work, linux-arm-kernel
In-Reply-To: <1590650879-18288-9-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:58 +0800, Anson Huang wrote:
> Convert the i.MX21 clock binding to DT schema format using json-schema,
> can NOT find any CCM interrupt info from reference manual and DT file,
> so interrupts property is removed from original binding doc.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx21-clock.txt | 27 ------------
> .../devicetree/bindings/clock/imx21-clock.yaml | 49 ++++++++++++++++++++++
> 2 files changed, 49 insertions(+), 27 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx21-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx21-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH 1/6] arm64: dts: qcom: sm8150: add apps_smmu node
From: Bjorn Andersson @ 2020-05-29 2:52 UTC (permalink / raw)
To: Jonathan Marek
Cc: linux-arm-msm, Andy Gross, Rob Herring,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list
In-Reply-To: <20200524023815.21789-2-jonathan@marek.ca>
On Sat 23 May 19:38 PDT 2020, Jonathan Marek wrote:
> Add the apps_smmu node for sm8150. Note that adding the iommus field for
> UFS is required because initializing the iommu removes the bypass mapping
> that created by the bootloader.
>
Unrelated to the patch itself; how do you disable the splash screen on
8150? "fastboot oem select-display-panel none" doesn't seem to work for
me on the MTP - and hence this would prevent my device from booting.
Thanks,
Bjorn
> Signed-off-by: Jonathan Marek <jonathan@marek.ca>
> ---
> arch/arm64/boot/dts/qcom/sm8150.dtsi | 91 ++++++++++++++++++++++++++++
> 1 file changed, 91 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi
> index a36512d1f6a1..acb839427b12 100644
> --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi
> @@ -442,6 +442,8 @@ ufs_mem_hc: ufshc@1d84000 {
> resets = <&gcc GCC_UFS_PHY_BCR>;
> reset-names = "rst";
>
> + iommus = <&apps_smmu 0x300 0>;
> +
> clock-names =
> "core_clk",
> "bus_aggr_clk",
> @@ -706,6 +708,7 @@ usb_1_dwc3: dwc3@a600000 {
> compatible = "snps,dwc3";
> reg = <0 0x0a600000 0 0xcd00>;
> interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
> + iommus = <&apps_smmu 0x140 0>;
> snps,dis_u2_susphy_quirk;
> snps,dis_enblslpm_quirk;
> phys = <&usb_1_hsphy>, <&usb_1_ssphy>;
> @@ -742,6 +745,94 @@ spmi_bus: spmi@c440000 {
> cell-index = <0>;
> };
>
> + apps_smmu: iommu@15000000 {
> + compatible = "qcom,sdm845-smmu-500", "arm,mmu-500";
> + reg = <0 0x15000000 0 0x100000>;
> + #iommu-cells = <2>;
> + #global-interrupts = <1>;
> + interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH>;
> + };
> +
> remoteproc_adsp: remoteproc@17300000 {
> compatible = "qcom,sm8150-adsp-pas";
> reg = <0x0 0x17300000 0x0 0x4040>;
> --
> 2.26.1
>
^ permalink raw reply
* Re: [PATCH 9/9] dt-bindings: clock: Convert i.MX1 clock to json-schema
From: Rob Herring @ 2020-05-29 2:54 UTC (permalink / raw)
To: Anson Huang
Cc: shawnguo, kernel, festevam, s.trumtrar, s.hauer, mturquette,
shc_work, linux-kernel, robh+dt, linux-arm-kernel, Linux-imx,
devicetree, sboyd, linux-clk
In-Reply-To: <1590650879-18288-10-git-send-email-Anson.Huang@nxp.com>
On Thu, 28 May 2020 15:27:59 +0800, Anson Huang wrote:
> Convert the i.MX1 clock binding to DT schema format using json-schema.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> .../devicetree/bindings/clock/imx1-clock.txt | 26 ------------
> .../devicetree/bindings/clock/imx1-clock.yaml | 49 ++++++++++++++++++++++
> 2 files changed, 49 insertions(+), 26 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/clock/imx1-clock.txt
> create mode 100644 Documentation/devicetree/bindings/clock/imx1-clock.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH v2] of/fdt: Remove redundant kbasename function call
From: Rob Herring @ 2020-05-29 2:57 UTC (permalink / raw)
To: Qi Zheng; +Cc: devicetree, frowand.list, robh+dt, linux-kernel
In-Reply-To: <20200528132541.463300-1-arch0.zheng@gmail.com>
On Thu, 28 May 2020 21:25:41 +0800, Qi Zheng wrote:
> For version 1 to 3 of the device tree, this is the node full
> path as a zero terminated string, starting with "/". The
> following equation will not hold, since the node name has
> been processed in the fdt_get_name().
>
> *pathp == '/'
>
> For version 16 and later, this is the node unit name only
> (or an empty string for the root node). So the above
> equation will still not hold.
>
> So the kbasename() is redundant, just remove it.
>
> Signed-off-by: Qi Zheng <arch0.zheng@gmail.com>
> ---
>
> Change in v2:
> remove another kbasename() also.
>
> drivers/of/fdt.c | 4 ----
> 1 file changed, 4 deletions(-)
>
Applied, thanks!
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox