From 984dfd489813132e82eded2fa10b9800264db22e Mon Sep 17 00:00:00 2001 From: Manikanta Mylavarapu Date: Mon, 22 Jun 2020 09:33:06 +0530 Subject: [PATCH 1/3] ipq5018: db-mp03.1: dts: Add ssphy in usb node This patch will configure ssphy sequence. Signed-off-by: Manikanta Mylavarapu Change-Id: I3fbc22f198daec2fbb691d89d8b12510dabe0dfa --- arch/arm/dts/ipq5018-db-mp03.1.dts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/ipq5018-db-mp03.1.dts b/arch/arm/dts/ipq5018-db-mp03.1.dts index e3fea72e43..1e735f503f 100644 --- a/arch/arm/dts/ipq5018-db-mp03.1.dts +++ b/arch/arm/dts/ipq5018-db-mp03.1.dts @@ -123,7 +123,12 @@ }; }; }; - gmac_cfg { + + usb0: xhci@8a00000 { + ssphy = <1>; + }; + + gmac_cfg { ext_mdio_gpio = <36 37>; gephy_led = <46>; From dc8f02bd66356d5de385058770b7a160637c09b4 Mon Sep 17 00:00:00 2001 From: Manikanta Mylavarapu Date: Mon, 22 Jun 2020 09:02:51 +0530 Subject: [PATCH 2/3] ipq5018: Update usb init sequence This patch tune's usb ssphy into SSC instead of fixed offset.Also It ensures Phy autoload should be done within 30us to 100us after pipe reset. Change-Id: I192da047861a02d0b70d5c5c2f03715af7213c21 Signed-off-by: Manikanta Mylavarapu --- board/qca/arm/ipq5018/ipq5018.c | 22 +++++++--------------- board/qca/arm/ipq5018/ipq5018.h | 9 --------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/board/qca/arm/ipq5018/ipq5018.c b/board/qca/arm/ipq5018/ipq5018.c index c539599743..0488a07c86 100644 --- a/board/qca/arm/ipq5018/ipq5018.c +++ b/board/qca/arm/ipq5018/ipq5018.c @@ -1203,8 +1203,6 @@ static void usb_init_ssphy(void __iomem *phybase) /*set fstep*/ writel(0x1, phybase + SSCG_CTRL_REG_1); writel(0xeb, phybase + SSCG_CTRL_REG_2); - writel((readl(phybase + CDR_CTRL_REG_1) | APB_FIXED_OFFSET), - phybase + CDR_CTRL_REG_1); return; } @@ -1222,27 +1220,21 @@ static void usb_init_phy(int index, int ssphy) /* GCC Reset USB BCR */ set_mdelay_clearbits_le32(usb_bcr, 0x1, 10); - /* GCC_QUSB2_PHY_BCR */ - setbits_le32(qusb2_phy_bcr, 0x1); - - /* GCC_USB0_PHY_BCR */ - if (ssphy) { + if (ssphy) setbits_le32(GCC_USB0_PHY_BCR, 0x1); - mdelay(100); - clrbits_le32(GCC_USB0_PHY_BCR, 0x1); - } - + setbits_le32(qusb2_phy_bcr, 0x1); + udelay(1); /* Config user control register */ writel(0x4004010, USB30_GUCTL); writel(0x4945920, USB30_FLADJ); - - /* GCC_QUSB2_0_PHY_BCR */ + if (ssphy) + clrbits_le32(GCC_USB0_PHY_BCR, 0x1); clrbits_le32(qusb2_phy_bcr, 0x1); - mdelay(10); + udelay(30); - usb_init_hsphy((u32 *)QUSB2PHY_BASE); if (ssphy) usb_init_ssphy((u32 *)USB3PHY_APB_BASE); + usb_init_hsphy((u32 *)QUSB2PHY_BASE); } int ipq_board_usb_init(void) diff --git a/board/qca/arm/ipq5018/ipq5018.h b/board/qca/arm/ipq5018/ipq5018.h index cecf45e9cc..bf62e9b560 100644 --- a/board/qca/arm/ipq5018/ipq5018.h +++ b/board/qca/arm/ipq5018/ipq5018.h @@ -419,15 +419,6 @@ #define SSCG_CTRL_REG_4 0xa8 #define SSCG_CTRL_REG_5 0xac #define SSCG_CTRL_REG_6 0xb0 -#define CDR_CTRL_REG_1 0x80 -#define CDR_CTRL_REG_2 0x84 -#define CDR_CTRL_REG_3 0x88 -#define CDR_CTRL_REG_4 0x8C -#define CDR_CTRL_REG_5 0x90 -#define CDR_CTRL_REG_6 0x94 -#define CDR_CTRL_REG_7 0x98 - -#define APB_FIXED_OFFSET (0x1 << 3) #define USB_PHY_CFG0 0x94 #define USB_PHY_UTMI_CTRL5 0x50 From 07e59f496068812629fc2f4985f2dd7d9f468a25 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Fri, 12 Jun 2020 17:15:16 +0530 Subject: [PATCH 3/3] driver: nand: qpic_nand: Enable config for serial training. This change will enable config for serial training. This change also fix the the logic to get most appropriate phase out of passed phase. This change also add support to read serial training offset from partition table. Also patching freqency value & phase value to kernel. Signed-off-by: Md Sadre Alam Change-Id: Ibb4a5cd80f16605e8e91bdf6a0c6c484edff1735 --- .../include/asm/arch-qca-common/qpic_nand.h | 1 + board/qca/arm/common/fdt_fixup.c | 6 + board/qca/arm/ipq5018/ipq5018.c | 30 ++++ drivers/mtd/nand/qpic_nand.c | 132 ++++++++---------- include/configs/ipq5018.h | 1 + 5 files changed, 94 insertions(+), 76 deletions(-) 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 bb9a8efed7..72e97d433b 100644 --- a/arch/arm/include/asm/arch-qca-common/qpic_nand.h +++ b/arch/arm/include/asm/arch-qca-common/qpic_nand.h @@ -560,6 +560,7 @@ enum qpic_verion{ QCA_QPIC_V2_1_1, }; +extern unsigned int qpic_frequency, qpic_phase; /* result type */ typedef enum { diff --git a/board/qca/arm/common/fdt_fixup.c b/board/qca/arm/common/fdt_fixup.c index c632c8952e..1aac99cd9d 100644 --- a/board/qca/arm/common/fdt_fixup.c +++ b/board/qca/arm/common/fdt_fixup.c @@ -776,6 +776,11 @@ __weak void fdt_fixup_bt_debug(void *blob) return; } +__weak void fdt_fixup_qpic(void *blob) +{ + return; +} + /* * For newer kernel that boot with device tree (3.14+), all of memory is * described in the /memory node, including areas that the kernel should not be @@ -897,6 +902,7 @@ int ft_board_setup(void *blob, bd_t *bd) fdt_fixup_cpr(blob); fdt_fixup_cpus_node(blob); fdt_low_memory_fixup(blob); + fdt_fixup_qpic(blob); s = getenv("dload_warm_reset"); if (s) fdt_fixup_set_dload_warm_reset(blob); diff --git a/board/qca/arm/ipq5018/ipq5018.c b/board/qca/arm/ipq5018/ipq5018.c index c539599743..80b8fcc94c 100644 --- a/board/qca/arm/ipq5018/ipq5018.c +++ b/board/qca/arm/ipq5018/ipq5018.c @@ -48,6 +48,8 @@ struct sdhci_host mmc_host; extern int ipq_spi_init(u16); #endif +unsigned int qpic_frequency = 0, qpic_phase = 0; + const char *rsvd_node = "/reserved-memory"; const char *del_node[] = {"uboot", "sbl", @@ -1440,6 +1442,34 @@ void fdt_fixup_wcss_rproc_for_atf(void *blob) parse_fdt_fixup("/soc/bt@7000000%qcom,nosecure%1", blob); } +void fdt_fixup_qpic(void *blob) +{ + int node_off, ret; + const char *qpic_node = {"/soc/qpic-nand@79b0000"}; + + /* This fixup is for qpic io_macro_clk + * frequency & phase value + */ + node_off = fdt_path_offset(blob, qpic_node); + if (node_off < 0) { + printf("%s: QPIC: unable to find node '%s'\n", + __func__, qpic_node); + return; + } + + ret = fdt_setprop_u32(blob, node_off, "qcom,iomacromax_clk", qpic_frequency); + if (ret) { + printf("%s : Unable to set property 'qcom,iomacromax_clk'\n",__func__); + return; + } + + ret = fdt_setprop_u32(blob, node_off, "qcom,phase", qpic_phase); + if (ret) { + printf("%s : Unable to set property 'qcom,phase'\n",__func__); + return; + } +} + void fdt_fixup_bt_debug(void *blob) { int node, phandle; diff --git a/drivers/mtd/nand/qpic_nand.c b/drivers/mtd/nand/qpic_nand.c index 05a3c5af0a..0047537631 100644 --- a/drivers/mtd/nand/qpic_nand.c +++ b/drivers/mtd/nand/qpic_nand.c @@ -140,7 +140,7 @@ static const unsigned int training_block_128[] = { 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, }; #define TRAINING_PART_OFFSET 0x3c00000 -#define MAXIMUM_ALLOCATED_TRAINING_BLOCK 8 +#define MAXIMUM_ALLOCATED_TRAINING_BLOCK 4 #define TOTAL_NUM_PHASE 7 #endif @@ -4089,77 +4089,40 @@ static void qpic_set_phase(int phase) } } -static int find_element(int val, u8 *phase_table, int index) +static bool IsEven(int num) { - int i; - int ret = 0; - - for (i = 0; i < TOTAL_NUM_PHASE; i++) { - if (phase_table[i] == val) { - ret = i; - break; - } - } - - if ( i > TOTAL_NUM_PHASE) { - printf("%s : wrong array index\n",__func__); - ret = -EIO; - } - - return ret; + return (!(num & 1)); } static int qpic_find_most_appropriate_phase(u8 *phase_table, int phase_count) { - int cnt = 0; - int i, j, new_index = 0, limit; + int cnt = 0, i; int phase = 0x0; - u8 phase_ranges[TOTAL_NUM_PHASE] = {1, 2, 3, 4, 5, 6, 7}; + u8 phase_ranges[TOTAL_NUM_PHASE] = {'\0'}; /*currently we are considering continious 3 phase will * pass and tke the middle one out of passed three phase. * if all 7 phase passed so return middle phase i.e 4 */ - - new_index = find_element(phase_table[0], phase_ranges, 0); - if (new_index < 0) { - printf("%s : Wrong index ..\n",__func__); - return -EIO; + phase_count -= 2; + for (i = 0; i < phase_count; i++) { + if ((phase_table[i] + 1 == phase_table[i + 1]) && + (phase_table[i + 1] + 1 == phase_table[i + 2])) { + phase_ranges[cnt++] = phase_table[i + 1]; + } } - /* best case all phase will passed */ - j = 0; - if (new_index == 0) { - for (i =0; i < TOTAL_NUM_PHASE; i++) { - if ((phase_table[j] == phase_ranges[i])) - cnt++; - j++; - } - - if (cnt == TOTAL_NUM_PHASE) - return 4; + /* filter out middle phase + * if cnt is odd then one middle phase + * if cnt is even then two middile phase + * so select lower one + */ + if (IsEven(cnt)) { + phase = phase_ranges[cnt/2 - 1]; } else { - limit = TOTAL_NUM_PHASE - new_index; - j = 0; - cnt = 0; - for (i = new_index; i <= limit; i++) { - if (phase_table[j] == phase_ranges[i]) { - cnt++; - if (cnt == 3) - break; - } else if (phase_table[j] > phase_ranges[i]) { - - new_index = find_element(phase_table[j], phase_ranges, i); - if (new_index < 0) { - printf("%s : wrong index..\n",__func__); - return -EIO; - } - } - - j++; - } + phase = phase_ranges[cnt/2]; } - phase = phase_ranges[i-1]; + return phase; } @@ -4168,29 +4131,37 @@ static int qpic_execute_serial_training(struct mtd_info *mtd) struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd); struct nand_chip *chip = MTD_NAND_CHIP(mtd); - unsigned int start, training_offset, blk_cnt = 0; + unsigned int start, blk_cnt = 0; unsigned int offset, pageno, curr_freq; - int size = sizeof(training_block_64); - unsigned int io_macro_freq_tbl[] = {100000000, 200000000, 228000000, - 266000000, 320000000}; + int size = sizeof(training_block_128); + unsigned int io_macro_freq_tbl[] = {24000000, 100000000, 200000000, 320000000}; - unsigned char *data_buff, trained_phase[TOTAL_NUM_PHASE]; - int phase, phase_cnt; - int training_seq_cnt = 3; - int index = 4, ret, phase_failed=0; + unsigned char *data_buff, trained_phase[TOTAL_NUM_PHASE] = {'\0'}; + int phase, phase_cnt, clk_src; + int training_seq_cnt = 4; + int index = 3, ret, phase_failed=0; + u32 start_blocks; + u32 size_blocks; + loff_t training_offset; + + ret = smem_getpart("0:TRAINING", &start_blocks, &size_blocks); + if (ret < 0) { + printf("Serial Training part offset not found.\n"); + return -EIO; + } + + training_offset = ((loff_t) mtd->erasesize * start_blocks); - training_offset = TRAINING_PART_OFFSET; - /* write pattern at lower frequency */ start = (training_offset >> chip->phys_erase_shift); offset = (start << chip->phys_erase_shift); - /* erase the all block */ pageno = (offset >> chip->page_shift); + clk_src = GPLL0_CLK_SRC; /* At 50Mhz frequency check the bad blocks, if training * blocks is not bad then only start training else operate * at 50Mhz with bypassing software serial traning. */ - while (qpic_nand_block_isbad(mtd, offset) != 0) { + while (qpic_nand_block_isbad(mtd, offset)) { /* block is bad skip this block and goto next * block */ @@ -4199,6 +4170,8 @@ static int qpic_execute_serial_training(struct mtd_info *mtd) offset = (start << chip->phys_erase_shift); pageno = (offset >> chip->page_shift); blk_cnt++; + if (blk_cnt == MAXIMUM_ALLOCATED_TRAINING_BLOCK) + break; } if (blk_cnt == MAXIMUM_ALLOCATED_TRAINING_BLOCK) { @@ -4220,8 +4193,9 @@ static int qpic_execute_serial_training(struct mtd_info *mtd) ret = -ENOMEM; goto err; } - memset(data_buff, 0, size); - memcpy(data_buff, training_block_64, size); + /* prepare clean buffer */ + memset(data_buff, 0xff, size); + memcpy(data_buff, training_block_128, size); /*write training data to flash */ ret = NANDC_RESULT_SUCCESS; @@ -4250,7 +4224,7 @@ static int qpic_execute_serial_training(struct mtd_info *mtd) /* After write verify the the data with read @ lower frequency * after that only start serial tarining @ higher frequency */ - memset(data_buff, 0, size); + memset(data_buff, 0xff, size); ops.datbuf = (uint8_t *)data_buff; ret = qpic_nand_read_page(mtd, pageno, NAND_CFG, &ops); @@ -4260,7 +4234,7 @@ static int qpic_execute_serial_training(struct mtd_info *mtd) } /* compare original data and read data */ - if (memcmp(data_buff, training_block_64, size)) { + if (memcmp(data_buff, training_block_128, size)) { printf("Training data read failed @ lower frequency\n"); goto err; } @@ -4276,7 +4250,9 @@ rettry: phase_cnt = 0; /* set frequency, start from higer frequency */ - qpic_set_clk_rate(curr_freq, QPIC_IO_MACRO_CLK, GPLL0_CLK_SRC); + if (curr_freq == IO_MACRO_CLK_24MHZ) + clk_src = XO_CLK_SRC; + qpic_set_clk_rate(curr_freq, QPIC_IO_MACRO_CLK, clk_src); do { /* set the phase */ @@ -4291,12 +4267,11 @@ rettry: goto err; } /* compare original data and read data */ - if (memcmp(data_buff, training_block_64, size)) { + if (memcmp(data_buff, training_block_128, size)) { /* wrong data read on one of miso line * change the phase value and try again */ phase_failed++; - continue; } else { /* we got good phase update the good phase list */ @@ -4310,11 +4285,16 @@ rettry: /* Get the appropriate phase */ phase = qpic_find_most_appropriate_phase(trained_phase, phase_cnt); qpic_set_phase(phase); + + /* update freq & phase to patch to the kernel */ + qpic_frequency = curr_freq; + qpic_phase = phase; } else { /* lower the the clock frequency * and try again */ curr_freq = io_macro_freq_tbl[--index]; + printf("Retry with lower frequency @:%d\n",curr_freq); if (--training_seq_cnt) goto rettry; diff --git a/include/configs/ipq5018.h b/include/configs/ipq5018.h index ce1ebeca97..883a7ba83c 100644 --- a/include/configs/ipq5018.h +++ b/include/configs/ipq5018.h @@ -160,6 +160,7 @@ extern loff_t board_env_size; #ifdef CONFIG_QPIC_SERIAL #define CONFIG_PAGE_SCOPE_MULTI_PAGE_READ +#define CONFIG_QSPI_SERIAL_TRAINING #endif /*