diff --git a/arch/arm/include/asm/arch-qca-common/qpic_nand.h b/arch/arm/include/asm/arch-qca-common/qpic_nand.h index 0c29546e26..fecea1146e 100644 --- a/arch/arm/include/asm/arch-qca-common/qpic_nand.h +++ b/arch/arm/include/asm/arch-qca-common/qpic_nand.h @@ -104,6 +104,7 @@ #define NAND_DEV_CMD_VLD_V1_5_20 NAND_REG(0x70AC) #define NAND_DEV_CMD1_V1_5_20 NAND_REG(0x70A4) +#define NAND_XFR_STEPS_V1_5_20 NAND_REG(0x7070) /* Shift Values */ #define NAND_DEV0_CFG1_WIDE_BUS_SHIFT 1 @@ -269,6 +270,9 @@ #define QPIC_BAM_DATA_FIFO_SIZE 64 #define QPIC_BAM_CMD_FIFO_SIZE 64 +#define QPIC_MAX_ONFI_MODES 4 +#define QPIC_NUM_XFER_STEPS 7 + enum qpic_verion{ QCA_QPIC_V1_4_20, QCA_QPIC_V1_5_20, @@ -435,6 +439,7 @@ struct qpic_nand_dev { unsigned char *pad_oob; unsigned char *zero_page; unsigned char *zero_oob; + uint16_t timing_mode_support; }; void qpic_nand_init(void); diff --git a/drivers/mtd/nand/qpic_nand.c b/drivers/mtd/nand/qpic_nand.c index 58cd88ae91..7245756801 100644 --- a/drivers/mtd/nand/qpic_nand.c +++ b/drivers/mtd/nand/qpic_nand.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2008, Google Inc. * All rights reserved. - * Copyright (c) 2009-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -59,6 +59,30 @@ static const struct udevice_id qpic_ver_ids[] = { { }, }; +static uint32_t +qpic_onfi_mode_to_xfer_steps[QPIC_MAX_ONFI_MODES][QPIC_NUM_XFER_STEPS] = { + /* Mode 0 */ + { + 0x04e00480, 0x59f05998, 0x89e08980, 0xd000d000, + 0xc000c000, 0xc000c000, 0xc000c000, + }, + /* Mode 1 */ + { + 0x00e00080, 0x49f04d99, 0x85e08580, 0xd000d000, + 0xc000c000, 0xc000c000, 0xc000c000, + }, + /* Mode 2 */ + { + 0x00e00080, 0x45f0459a, 0x85e08580, 0xd000d000, + 0xc000c000, 0xc000c000, 0xc000c000, + }, + /* Mode 3 */ + { + 0x00e00080, 0x45f04599, 0x81e08180, 0xd000d000, + 0xc000c000, 0xc000c000, 0xc000c000, + }, +}; + static void qpic_nand_wait_for_cmd_exec(uint32_t num_desc) @@ -517,6 +541,32 @@ qpic_nand_onfi_probe_cleanup(uint32_t vld, uint32_t dev_cmd1) qpic_nand_wait_for_cmd_exec(1); } +static void +qpic_config_timing_parameters(struct mtd_info *mtd) +{ + struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd); + uint32_t xfer_start; + uint32_t i, timing_mode; + + timing_mode = dev->timing_mode_support & + GENMASK(QPIC_MAX_ONFI_MODES - 1, 0); + + /* If ONFI mode is not valid then use the default register values */ + if (!timing_mode) + return; + + timing_mode = fls(timing_mode) - 1; + + if (hw_ver == QCA_QPIC_V1_5_20) + xfer_start = NAND_XFR_STEPS_V1_5_20; + else + xfer_start = NAND_XFR_STEP1; + + for (i = 0; i < QPIC_NUM_XFER_STEPS; i++) + writel(qpic_onfi_mode_to_xfer_steps[timing_mode][i], + xfer_start + 4 * i); +} + static int qpic_nand_onfi_save_params(struct mtd_info *mtd, struct onfi_param_page *param_page) @@ -546,6 +596,7 @@ qpic_nand_onfi_save_params(struct mtd_info *mtd, ecc_bits = param_page->num_bits_ecc_correctability; dev->num_pages_per_blk = param_page->pgs_per_blk; dev->num_pages_per_blk_mask = param_page->pgs_per_blk - 1; + dev->timing_mode_support = param_page->timing_mode_support; if (ecc_bits >= 8) dev->ecc_width = NAND_WITH_8_BIT_ECC; @@ -2239,6 +2290,8 @@ void qpic_nand_init(void) else if (ret > 0) qpic_nand_non_onfi_probe(mtd); + qpic_config_timing_parameters(mtd); + /* Save the RAW and read/write configs */ qpic_nand_save_config(mtd);