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>; 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..138210f9e8 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", @@ -1203,8 +1205,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 +1222,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) @@ -1440,6 +1434,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/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 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 /*