From 355c620666c205b55164aeb16f86b775f8c5d1fd Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Wed, 5 Jun 2019 11:26:12 +0800 Subject: driver: ddr: imx: skip ddr_ss_gpr config on imx8mn There is no DDR_SS_GPR0 exits on i.MX8MN, so skip setting this register on i.MX8MN. Signed-off-by: Jacky Bai Signed-off-by: Peng Fan --- drivers/ddr/imx/imx8m/ddr_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c index bbddee6..1c5c7f9 100644 --- a/drivers/ddr/imx/imx8m/ddr_init.c +++ b/drivers/ddr/imx/imx8m/ddr_init.c @@ -74,7 +74,7 @@ int ddr_init(struct dram_timing_info *dram_timing) /* if ddr type is LPDDR4, do it */ tmp = reg32_read(DDRC_MSTR(0)); - if (tmp & (0x1 << 5)) + if (tmp & (0x1 << 5) && !is_imx8mn()) reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */ /* determine the initial boot frequency */ -- cgit v1.1 From 1eb325af16e2a6987f4aa91e563ad6c160f64a5a Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Mon, 10 Feb 2020 18:02:00 +0800 Subject: driver: ddr: imx: correct the pwrctl setting of selfref_en on imx8m The 'selfref_en' should be bit'0', so correct the setting to enable the auto self-refresh. Reviewed-by: Jian Li Reviewed-by: Ye Li Signed-off-by: Jacky Bai Signed-off-by: Peng Fan --- drivers/ddr/imx/imx8m/ddr_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c index 1c5c7f9..de30293 100644 --- a/drivers/ddr/imx/imx8m/ddr_init.c +++ b/drivers/ddr/imx/imx8m/ddr_init.c @@ -163,7 +163,7 @@ int ddr_init(struct dram_timing_info *dram_timing) /* Step26: Set back register in Step4 to the original values if desired */ reg32_write(DDRC_RFSHCTL3(0), 0x0000000); /* enable selfref_en by default */ - setbits_le32(DDRC_PWRCTL(0), 0x1 << 3); + setbits_le32(DDRC_PWRCTL(0), 0x1); /* enable port 0 */ reg32_write(DDRC_PCTRL_0(0), 0x00000001); -- cgit v1.1 From f3acb02386f4d5df6e5b5eb96302f169c28933db Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Mon, 20 Jan 2020 11:13:14 +0800 Subject: drivers: ddr: imx8mp: Add inline ECC feature support the DRAM Controller in i.MX8MP will support a feature called "Inline ECC". This is supported for all 3 supported DRAM technologies (LPDDR4, DDR4 and DDR3L). When this feature is enabled by software, the DRAM Controller reserves 12.5% of DRAM capacity for ECC information, and presents only the non-ECC portion (lower 87.5% of the installed capacity of DRAM) to the rest of the SoC. The DRAM memory can be divided into 8 regions so that if a use case only requires ECC protection on a subset of memory, then only that subset of memory need support inline ECC. If this occurs, then there is no performance penalty accessing the non-ECC-protected memory (no need to access ECC for this portion of the memory map). This is all configured with the DRAM Controller. Signed-off-by: Sherry Sun Signed-off-by: Peng Fan --- drivers/ddr/imx/imx8m/Kconfig | 7 ++++ drivers/ddr/imx/imx8m/ddr_init.c | 72 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) (limited to 'drivers') diff --git a/drivers/ddr/imx/imx8m/Kconfig b/drivers/ddr/imx/imx8m/Kconfig index 5bf61eb..a5f5524 100644 --- a/drivers/ddr/imx/imx8m/Kconfig +++ b/drivers/ddr/imx/imx8m/Kconfig @@ -29,4 +29,11 @@ config SAVED_DRAM_TIMING_BASE info into memory for low power use. OCRAM_S is used for this purpose on i.MX8MM. default 0x180000 + +config IMX8M_DRAM_INLINE_ECC + bool "imx8mp inline ECC" + depends on IMX8MP && IMX8M_LPDDR4 + help + Select this config if you want to use inline ecc feature for + imx8mp-evk board. endmenu diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c index de30293..664966c 100644 --- a/drivers/ddr/imx/imx8m/ddr_init.c +++ b/drivers/ddr/imx/imx8m/ddr_init.c @@ -21,6 +21,76 @@ void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num) } } +#ifdef CONFIG_IMX8M_DRAM_INLINE_ECC +void ddrc_inline_ecc_scrub(unsigned int start_address, + unsigned int range_address) +{ + unsigned int tmp; + + /* Step1: Enable quasi-dynamic programming */ + reg32_write(DDRC_SWCTL(0), 0x00000000); + /* Step2: Set ECCCFG1.ecc_parity_region_lock to 1 */ + reg32setbit(DDRC_ECCCFG1(0), 0x4); + /* Step3: Block the AXI ports from taking the transaction */ + reg32_write(DDRC_PCTRL_0(0), 0x0); + /* Step4: Set scrub start address */ + reg32_write(DDRC_SBRSTART0(0), start_address); + /* Step5: Set scrub range address */ + reg32_write(DDRC_SBRRANGE0(0), range_address); + /* Step6: Set scrub_mode to write */ + reg32_write(DDRC_SBRCTL(0), 0x00000014); + /* Step7: Set the desired pattern through SBRWDATA0 registers */ + reg32_write(DDRC_SBRWDATA0(0), 0x55aa55aa); + /* Step8: Enable the SBR by programming SBRCTL.scrub_en=1 */ + reg32setbit(DDRC_SBRCTL(0), 0x0); + /* Step9: Poll SBRSTAT.scrub_done=1 */ + tmp = reg32_read(DDRC_SBRSTAT(0)); + while (tmp != 0x00000002) + tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x2; + /* Step10: Poll SBRSTAT.scrub_busy=0 */ + tmp = reg32_read(DDRC_SBRSTAT(0)); + while (tmp != 0x0) + tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x1; + /* Step11: Disable SBR by programming SBRCTL.scrub_en=0 */ + clrbits_le32(DDRC_SBRCTL(0), 0x1); + /* Step12: Prepare for normal scrub operation(Read) and set scrub_interval*/ + reg32_write(DDRC_SBRCTL(0), 0x100); + /* Step13: Enable the SBR by programming SBRCTL.scrub_en=1 */ + reg32_write(DDRC_SBRCTL(0), 0x101); + /* Step14: Enable AXI ports by programming */ + reg32_write(DDRC_PCTRL_0(0), 0x1); + /* Step15: Disable quasi-dynamic programming */ + reg32_write(DDRC_SWCTL(0), 0x00000001); +} + +void ddrc_inline_ecc_scrub_end(unsigned int start_address, + unsigned int range_address) +{ + /* Step1: Enable quasi-dynamic programming */ + reg32_write(DDRC_SWCTL(0), 0x00000000); + /* Step2: Block the AXI ports from taking the transaction */ + reg32_write(DDRC_PCTRL_0(0), 0x0); + /* Step3: Set scrub start address */ + reg32_write(DDRC_SBRSTART0(0), start_address); + /* Step4: Set scrub range address */ + reg32_write(DDRC_SBRRANGE0(0), range_address); + /* Step5: Disable SBR by programming SBRCTL.scrub_en=0 */ + clrbits_le32(DDRC_SBRCTL(0), 0x1); + /* Step6: Prepare for normal scrub operation(Read) and set scrub_interval */ + reg32_write(DDRC_SBRCTL(0), 0x100); + /* Step7: Enable the SBR by programming SBRCTL.scrub_en=1 */ + reg32_write(DDRC_SBRCTL(0), 0x101); + /* Step8: Enable AXI ports by programming */ + reg32_write(DDRC_PCTRL_0(0), 0x1); + /* Step9: Disable quasi-dynamic programming */ + reg32_write(DDRC_SWCTL(0), 0x00000001); +} +#endif + +void __weak board_dram_ecc_scrub(void) +{ +} + int ddr_init(struct dram_timing_info *dram_timing) { unsigned int tmp, initial_drate, target_freq; @@ -169,6 +239,8 @@ int ddr_init(struct dram_timing_info *dram_timing) reg32_write(DDRC_PCTRL_0(0), 0x00000001); debug("DDRINFO: ddrmix config done\n"); + board_dram_ecc_scrub(); + /* save the dram timing config into memory */ dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE); -- cgit v1.1 From b335966958a93e49439bf248adadce89e7e2bee3 Mon Sep 17 00:00:00 2001 From: Oliver Chen Date: Tue, 21 Apr 2020 14:48:09 +0800 Subject: drivers: ddr: imx Workaround for i.MX8M DDRPHY rank to rank issue Add logic to automatically update umctl2's setting based on phy training CDD value for rank to rank space issue Acked-by: Ye Li Signed-off-by: Oliver Chen Signed-off-by: Jacky Bai Signed-off-by: Peng Fan --- drivers/ddr/imx/imx8m/ddr_init.c | 3 + drivers/ddr/imx/imx8m/ddrphy_train.c | 7 ++ drivers/ddr/imx/imx8m/ddrphy_utils.c | 164 +++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) (limited to 'drivers') diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c index 664966c..99a67ed 100644 --- a/drivers/ddr/imx/imx8m/ddr_init.c +++ b/drivers/ddr/imx/imx8m/ddr_init.c @@ -190,6 +190,9 @@ int ddr_init(struct dram_timing_info *dram_timing) /* Step15: Set SWCTL.sw_done to 0 */ reg32_write(DDRC_SWCTL(0), 0x00000000); + /* Apply rank-to-rank workaround */ + update_umctl2_rank_space_setting(dram_timing->fsp_msg_num - 1); + /* Step16: Set DFIMISC.dfi_init_start to 1 */ setbits_le32(DDRC_DFIMISC(0), (0x1 << 5)); diff --git a/drivers/ddr/imx/imx8m/ddrphy_train.c b/drivers/ddr/imx/imx8m/ddrphy_train.c index f2a997b..08fed61 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_train.c +++ b/drivers/ddr/imx/imx8m/ddrphy_train.c @@ -8,6 +8,7 @@ #include #include #include +#include int ddr_cfg_phy(struct dram_timing_info *dram_timing) { @@ -71,9 +72,15 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing) /* Read the Message Block results */ dwc_ddrphy_apb_wr(0xd0000, 0x0); + ddrphy_init_read_msg_block(fsp_msg->fw_type); + + if(fsp_msg->fw_type != FW_2D_IMAGE) + get_trained_CDD(i); + dwc_ddrphy_apb_wr(0xd0000, 0x1); + fsp_msg++; } diff --git a/drivers/ddr/imx/imx8m/ddrphy_utils.c b/drivers/ddr/imx/imx8m/ddrphy_utils.c index d5eef53..20ae47b 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_utils.c +++ b/drivers/ddr/imx/imx8m/ddrphy_utils.c @@ -11,6 +11,12 @@ #include #include #include +#include + +static unsigned int g_cdd_rr_max[4]; +static unsigned int g_cdd_rw_max[4]; +static unsigned int g_cdd_wr_max[4]; +static unsigned int g_cdd_ww_max[4]; static inline void poll_pmu_message_ready(void) { @@ -193,3 +199,161 @@ unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr) return tmp; } + +unsigned int look_for_max(unsigned int data[], + unsigned int addr_start, unsigned int addr_end) +{ + unsigned int i, imax = 0; + + for (i = addr_start; i <= addr_end; i++) { + if (((data[i] >> 7) == 0) && (data[i] > imax)) + imax = data[i]; + } + + return imax; +} + +void get_trained_CDD(u32 fsp) +{ + unsigned int i, ddr_type, tmp; + unsigned int cdd_cha[12], cdd_chb[12]; + unsigned int cdd_cha_rr_max, cdd_cha_rw_max, cdd_cha_wr_max, cdd_cha_ww_max; + unsigned int cdd_chb_rr_max, cdd_chb_rw_max, cdd_chb_wr_max, cdd_chb_ww_max; + + ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f; + if (ddr_type == 0x20) { + for (i = 0; i < 6; i++) { + tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54013 + i) * 4); + cdd_cha[i * 2] = tmp & 0xff; + cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff; + } + + for (i = 0; i < 7; i++) { + tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x5402c + i) * 4); + if (i == 0) { + cdd_cha[0] = (tmp >> 8) & 0xff; + } else if (i == 6) { + cdd_cha[11]=tmp & 0xff; + } else { + cdd_chb[ i * 2 - 1] = tmp & 0xff; + cdd_chb[i * 2] = (tmp >> 8) & 0xff; + } + } + + cdd_cha_rr_max = look_for_max(cdd_cha, 0, 1); + cdd_cha_rw_max = look_for_max(cdd_cha, 2, 5); + cdd_cha_wr_max = look_for_max(cdd_cha, 6, 9); + cdd_cha_ww_max = look_for_max(cdd_cha, 10, 11); + cdd_chb_rr_max = look_for_max(cdd_chb, 0, 1); + cdd_chb_rw_max = look_for_max(cdd_chb, 2, 5); + cdd_chb_wr_max = look_for_max(cdd_chb, 6, 9); + cdd_chb_ww_max = look_for_max(cdd_chb, 10, 11); + g_cdd_rr_max[fsp] = cdd_cha_rr_max > cdd_chb_rr_max ? cdd_cha_rr_max : cdd_chb_rr_max; + g_cdd_rw_max[fsp] = cdd_cha_rw_max > cdd_chb_rw_max ? cdd_cha_rw_max : cdd_chb_rw_max; + g_cdd_wr_max[fsp] = cdd_cha_wr_max > cdd_chb_wr_max ? cdd_cha_wr_max : cdd_chb_wr_max; + g_cdd_ww_max[fsp] = cdd_cha_ww_max > cdd_chb_ww_max ? cdd_cha_ww_max : cdd_chb_ww_max; + } else { + unsigned int ddr4_cdd[64]; + for( i = 0; i < 29; i++) { + tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54012 + i) * 4); + ddr4_cdd[i * 2] = tmp & 0xff; + ddr4_cdd[i * 2 + 1] = (tmp >> 8) & 0xff; + } + + g_cdd_rr_max[fsp] = look_for_max(ddr4_cdd, 1, 12); + g_cdd_ww_max[fsp] = look_for_max(ddr4_cdd, 13, 24); + g_cdd_rw_max[fsp] = look_for_max(ddr4_cdd, 25, 40); + g_cdd_wr_max[fsp] = look_for_max(ddr4_cdd, 41, 56); + } +} + +void update_umctl2_rank_space_setting(unsigned int pstat_num) +{ + unsigned int i,ddr_type; + unsigned int addr_slot, rdata, tmp, tmp_t; + unsigned int ddrc_w2r,ddrc_r2w,ddrc_wr_gap,ddrc_rd_gap; + + ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f; + for (i = 0; i < pstat_num; i++) { + addr_slot = i ? (i + 1) * 0x1000 : 0; + if (ddr_type == 0x20) { + /* update r2w:[13:8], w2r:[5:0] */ + rdata=reg32_read(DDRC_DRAMTMG2(0) + addr_slot); + ddrc_w2r = rdata & 0x3f; + if(is_imx8mp()) + tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1); + else + tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1; + ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp; + + ddrc_r2w = (rdata >> 8) & 0x3f; + if (is_imx8mp()) + tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1); + else + tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1; + ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp; + + tmp_t = (rdata & 0xffffc0c0) | (ddrc_r2w << 8) | ddrc_w2r; + reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t); + } else { + /* update w2r:[5:0] */ + rdata=reg32_read(DDRC_DRAMTMG9(0) + addr_slot); + ddrc_w2r = rdata & 0x3f; + if (is_imx8mp()) + tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1); + else + tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1; + ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp; + tmp_t = (rdata & 0xffffffc0) | ddrc_w2r; + reg32_write((DDRC_DRAMTMG9(0) + addr_slot), tmp_t); + + /* update r2w:[13:8] */ + rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot); + ddrc_r2w = (rdata >> 8) & 0x3f; + if(is_imx8mp()) + tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1); + else + tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1; + ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp; + + tmp_t = (rdata & 0xffffc0ff) | (ddrc_r2w << 8); + reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t); + } + + if (!is_imx8mq()) { + /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */ + rdata = reg32_read(DDRC_RANKCTL(0) + addr_slot); + ddrc_wr_gap = (rdata >> 8) & 0xf; + if(is_imx8mp()) + tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1); + else + tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1) + 1; + ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp; + + ddrc_rd_gap = (rdata >> 4) & 0xf; + if (is_imx8mp()) + tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1); + else + tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1) + 1; + ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp; + + tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4); + reg32_write((DDRC_RANKCTL(0) + addr_slot), tmp_t); + } + } + + if(is_imx8mq()) { + /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */ + rdata = reg32_read(DDRC_RANKCTL(0)); + ddrc_wr_gap = (rdata >> 8) & 0xf; + tmp = ddrc_wr_gap + (g_cdd_ww_max[0] >> 1) + 1; + ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp; + + ddrc_rd_gap = (rdata >> 4) & 0xf; + tmp = ddrc_rd_gap + (g_cdd_rr_max[0] >> 1) + 1; + ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp; + + tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4); + reg32_write(DDRC_RANKCTL(0), tmp_t); + } +} -- cgit v1.1 From 58db844fc87749db08224fd536d5b95453f8b456 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 30 May 2020 16:37:39 +0800 Subject: pinctrl: imx7: move soc info to data section The soc info without initialization value should be put into data section. The driver could be used before relocation, with it in BSS section could cause issue, since BSS section is not initializated and it might overwrite other areas that used by others, such as dtb. Signed-off-by: Peng Fan --- drivers/pinctrl/nxp/pinctrl-imx7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nxp/pinctrl-imx7.c b/drivers/pinctrl/nxp/pinctrl-imx7.c index 769d428..66b58ba 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx7.c +++ b/drivers/pinctrl/nxp/pinctrl-imx7.c @@ -9,7 +9,7 @@ #include "pinctrl-imx.h" -static struct imx_pinctrl_soc_info imx7_pinctrl_soc_info; +static struct imx_pinctrl_soc_info imx7_pinctrl_soc_info __attribute__((section(".data"))); static struct imx_pinctrl_soc_info imx7_lpsr_pinctrl_soc_info = { .flags = ZERO_OFFSET_VALID, -- cgit v1.1 From 4b8c6030daa982775c03de26d8cd24310961b618 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 30 May 2020 16:39:14 +0800 Subject: pinctrl: imx8m: move soc info to data section The soc info without initialization value should be put into data section. The driver could be used before relocation, with it in BSS section could cause issue, since BSS section is not initializated and it might overwrite other areas that used by others, such as dtb. Signed-off-by: Peng Fan --- drivers/pinctrl/nxp/pinctrl-imx8m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nxp/pinctrl-imx8m.c b/drivers/pinctrl/nxp/pinctrl-imx8m.c index 5b7cbb6..0626fde 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx8m.c +++ b/drivers/pinctrl/nxp/pinctrl-imx8m.c @@ -8,7 +8,7 @@ #include "pinctrl-imx.h" -static struct imx_pinctrl_soc_info imx8mq_pinctrl_soc_info; +static struct imx_pinctrl_soc_info imx8mq_pinctrl_soc_info __attribute__((section(".data"))); static int imx8mq_pinctrl_probe(struct udevice *dev) { -- cgit v1.1 From 683a91cdbd2b0f6c8676717d28f8a3879beb082a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 30 May 2020 16:43:20 +0800 Subject: pinctrl: imx5: move soc info to data section The soc info without initialization value should be put into data section. The driver could be used before relocation, with it in BSS section could cause issue, since BSS section is not initializated and it might overwrite other areas that used by others, such as dtb. Signed-off-by: Peng Fan --- drivers/pinctrl/nxp/pinctrl-imx5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nxp/pinctrl-imx5.c b/drivers/pinctrl/nxp/pinctrl-imx5.c index 5d17380..9c3423b 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx5.c +++ b/drivers/pinctrl/nxp/pinctrl-imx5.c @@ -10,7 +10,7 @@ #include "pinctrl-imx.h" -static struct imx_pinctrl_soc_info imx5_pinctrl_soc_info; +static struct imx_pinctrl_soc_info imx5_pinctrl_soc_info __attribute__((section(".data"))); static int imx5_pinctrl_probe(struct udevice *dev) { -- cgit v1.1 From c2eaa6eb09f474c4af51443256fe072d2e137719 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 11 May 2020 15:16:07 +0800 Subject: imx8: fuse: use arm_smccc_smc Use arm_smccc_smc to replace call_imx_sip Signed-off-by: Peng Fan --- drivers/misc/imx8/fuse.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/imx8/fuse.c b/drivers/misc/imx8/fuse.c index 4d7f2f5..be18122 100644 --- a/drivers/misc/imx8/fuse.c +++ b/drivers/misc/imx8/fuse.c @@ -9,6 +9,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -36,22 +37,24 @@ int fuse_read(u32 bank, u32 word, u32 *val) int fuse_sense(u32 bank, u32 word, u32 *val) { - unsigned long ret = 0, value = 0; + struct arm_smccc_res res; if (bank != 0) { printf("Invalid bank argument, ONLY bank 0 is supported\n"); return -EINVAL; } - ret = call_imx_sip_ret2(FSL_SIP_OTP_READ, (unsigned long)word, &value, - 0, 0); - *val = (u32)value; + arm_smccc_smc(FSL_SIP_OTP_READ, (unsigned long)word, 0, 0, + 0, 0, 0, 0, &res); + *val = (u32)res.a1; - return ret; + return res.a0; } int fuse_prog(u32 bank, u32 word, u32 val) { + struct arm_smccc_res res; + if (bank != 0) { printf("Invalid bank argument, ONLY bank 0 is supported\n"); return -EINVAL; @@ -78,8 +81,10 @@ int fuse_prog(u32 bank, u32 word, u32 val) } } - return call_imx_sip(FSL_SIP_OTP_WRITE, (unsigned long)word, - (unsigned long)val, 0, 0); + arm_smccc_smc(FSL_SIP_OTP_WRITE, (unsigned long)word, + (unsigned long)val, 0, 0, 0, 0, 0, &res); + + return res.a0; } int fuse_override(u32 bank, u32 word, u32 val) -- cgit v1.1 From 4b8f22de160edfa25fd95cad807471ceeabb1783 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 11 May 2020 15:16:37 +0800 Subject: imx: power-domain: use arm_smccc_smc Use arm_smccc_smc to replace call_imx_sip Signed-off-by: Peng Fan --- drivers/power/domain/imx8m-power-domain.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index 5b6467c..0ef460d 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -13,6 +13,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -30,6 +31,7 @@ static int imx8m_power_domain_on(struct power_domain *power_domain) { struct udevice *dev = power_domain->dev; struct imx8m_power_domain_platdata *pdata; + pdata = dev_get_platdata(dev); if (pdata->resource_id < 0) @@ -38,8 +40,8 @@ static int imx8m_power_domain_on(struct power_domain *power_domain) if (pdata->has_pd) power_domain_on(&pdata->pd); - call_imx_sip(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN, - pdata->resource_id, 1, 0); + arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN, + pdata->resource_id, 1, 0, 0, 0, 0, NULL); return 0; } @@ -53,8 +55,8 @@ static int imx8m_power_domain_off(struct power_domain *power_domain) if (pdata->resource_id < 0) return -EINVAL; - call_imx_sip(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN, - pdata->resource_id, 0, 0); + arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN, + pdata->resource_id, 0, 0, 0, 0, 0, NULL); if (pdata->has_pd) power_domain_off(&pdata->pd); -- cgit v1.1 From 7ddb4ef3e178ddea1ad117b9a14357b13afb6e92 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 27 Jun 2020 15:48:04 +0800 Subject: clk: imx8mm: fix clk set parent Fix clk set parent, so we could still have correct clocks after parent changing. Signed-off-by: Peng Fan --- drivers/clk/imx/clk-imx8mm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 66c9601..d609fad 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -191,7 +191,10 @@ static int imx8mm_clk_set_parent(struct clk *clk, struct clk *parent) if (ret) return ret; - return clk_set_parent(c, cp); + ret = clk_set_parent(c, cp); + c->dev->parent = cp->dev; + + return ret; } static struct clk_ops imx8mm_clk_ops = { -- cgit v1.1 From a65409420d428f46311c5782a62b18e0904f64c9 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 27 Jun 2020 15:49:28 +0800 Subject: clk: imx8mm: Add qspi clock Add qspi clock Signed-off-by: Peng Fan --- drivers/clk/imx/clk-imx8mm.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index d609fad..4743394 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -119,6 +119,9 @@ static const char *imx8mm_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_ static const char *imx8mm_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", }; +static const char *imx8mm_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m", "sys_pll2_500m", + "audio_pll2_out", "sys_pll1_266m", "sys_pll3_out", "sys_pll1_100m", }; + static ulong imx8mm_clk_get_rate(struct clk *clk) { struct clk *c; @@ -373,6 +376,8 @@ static int imx8mm_clk_probe(struct udevice *dev) clk_dm(IMX8MM_CLK_USDHC3, imx8m_clk_composite("usdhc3", imx8mm_usdhc3_sels, base + 0xbc80)); + clk_dm(IMX8MM_CLK_QSPI, + imx8m_clk_composite("qspi", imx8mm_qspi_sels, base + 0xab80)); clk_dm(IMX8MM_CLK_I2C1_ROOT, imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0)); @@ -396,6 +401,8 @@ static int imx8mm_clk_probe(struct udevice *dev) imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0)); clk_dm(IMX8MM_CLK_USDHC3_ROOT, imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0)); + clk_dm(IMX8MM_CLK_QSPI_ROOT, + imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0)); /* clks not needed in SPL stage */ #ifndef CONFIG_SPL_BUILD -- cgit v1.1 From ee1f8b226f1e6e3fdb0dd5fe0f41d1d92bccc690 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Sat, 18 Apr 2020 08:19:12 -0700 Subject: clk: clk-imx8mn: Update clock tree and support set parent Add set clock parent support. Add ENET and flexspi related clocks to support assigned clocks Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/clk/imx/clk-imx8mn.c | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 2d8e373..a11b17f 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -81,6 +81,17 @@ static const char *imx8mn_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_p static const char *imx8mn_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", }; +#ifndef CONFIG_SPL_BUILD +static const char *imx8mn_enet_ref_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m", "sys_pll2_100m", + "sys_pll1_160m", "audio_pll1_out", "video_pll1_out", "clk_ext4", }; + +static const char *imx8mn_enet_timer_sels[] = {"clock-osc-24m", "sys_pll2_100m", "audio_pll1_out", "clk_ext1", "clk_ext2", + "clk_ext3", "clk_ext4", "video_pll1_out", }; + +static const char *imx8mn_enet_phy_sels[] = {"clock-osc-24m", "sys_pll2_50m", "sys_pll2_125m", "sys_pll2_200m", + "sys_pll2_500m", "video_pll1_out", "audio_pll2_out", }; +#endif + static const char *imx8mn_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", }; @@ -108,6 +119,9 @@ static const char *imx8mn_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_ static const char *imx8mn_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", }; +static const char *imx8mn_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m", "sys_pll2_500m", + "audio_pll2_out", "sys_pll1_266m", "sys_pll3_out", "sys_pll1_100m", }; + static ulong imx8mn_clk_get_rate(struct clk *clk) { struct clk *c; @@ -165,11 +179,33 @@ static int imx8mn_clk_enable(struct clk *clk) return __imx8mn_clk_enable(clk, 1); } +static int imx8mn_clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk *c, *cp; + int ret; + + debug("%s(#%lu), parent: %lu\n", __func__, clk->id, parent->id); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + ret = clk_get_by_id(parent->id, &cp); + if (ret) + return ret; + + ret = clk_set_parent(c, cp); + c->dev->parent = cp->dev; + + return ret; +} + static struct clk_ops imx8mn_clk_ops = { .set_rate = imx8mn_clk_set_rate, .get_rate = imx8mn_clk_get_rate, .enable = imx8mn_clk_enable, .disable = imx8mn_clk_disable, + .set_parent = imx8mn_clk_set_parent, }; static int imx8mn_clk_probe(struct udevice *dev) @@ -340,6 +376,8 @@ static int imx8mn_clk_probe(struct udevice *dev) clk_dm(IMX8MN_CLK_USDHC3, imx8m_clk_composite("usdhc3", imx8mn_usdhc3_sels, base + 0xbc80)); + clk_dm(IMX8MN_CLK_QSPI, + imx8m_clk_composite("qspi", imx8mn_qspi_sels, base + 0xab80)); clk_dm(IMX8MN_CLK_I2C1_ROOT, imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0)); @@ -363,6 +401,24 @@ static int imx8mn_clk_probe(struct udevice *dev) imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0)); clk_dm(IMX8MN_CLK_USDHC3_ROOT, imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0)); + clk_dm(IMX8MN_CLK_QSPI_ROOT, + imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0)); + + /* clks not needed in SPL stage */ +#ifndef CONFIG_SPL_BUILD + clk_dm(IMX8MN_CLK_ENET_REF, + imx8m_clk_composite("enet_ref", imx8mn_enet_ref_sels, + base + 0xa980)); + clk_dm(IMX8MN_CLK_ENET_TIMER, + imx8m_clk_composite("enet_timer", imx8mn_enet_timer_sels, + base + 0xaa00)); + clk_dm(IMX8MN_CLK_ENET_PHY_REF, + imx8m_clk_composite("enet_phy", imx8mn_enet_phy_sels, + base + 0xaa80)); + clk_dm(IMX8MN_CLK_ENET1_ROOT, + imx_clk_gate4("enet1_root_clk", "enet_axi", + base + 0x40a0, 0)); +#endif #ifdef CONFIG_SPL_BUILD struct clk *clkp, *clkp1; -- cgit v1.1 From 4b6548d17d065de9c31ce4fc3e476ca16beaa8db Mon Sep 17 00:00:00 2001 From: Ye Li Date: Sun, 19 Apr 2020 02:22:09 -0700 Subject: clk: imx8mm/8mn: Add USB clocks Add USB relevant clocks to support usb clock settings for both DM USB host and gadget drivers Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/clk/imx/clk-imx8mm.c | 17 +++++++++++++++++ drivers/clk/imx/clk-imx8mn.c | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 4743394..85d1757 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -95,6 +95,9 @@ static const char *imx8mm_enet_phy_sels[] = {"clock-osc-24m", "sys_pll2_50m", "s static const char *imx8mm_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", }; +static const char *imx8mm_usb_bus_sels[] = {"clock-osc-24m", "sys_pll2_500m", "sys_pll1_800m", "sys_pll2_100m", + "sys_pll2_200m", "clk_ext2", "clk_ext4", "audio_pll2_out", }; + static const char *imx8mm_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", }; @@ -122,6 +125,12 @@ static const char *imx8mm_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sy static const char *imx8mm_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m", "sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m", "sys_pll3_out", "sys_pll1_100m", }; +static const char *imx8mm_usb_core_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m", + "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mm_usb_phy_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m", + "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", }; + static ulong imx8mm_clk_get_rate(struct clk *clk) { struct clk *c; @@ -355,6 +364,8 @@ static int imx8mm_clk_probe(struct udevice *dev) imx8m_clk_composite_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900)); + clk_dm(IMX8MM_CLK_USB_BUS, + imx8m_clk_composite("usb_bus", imx8mm_usb_bus_sels, base + 0x8b80)); /* IP */ clk_dm(IMX8MM_CLK_USDHC1, @@ -378,6 +389,10 @@ static int imx8mm_clk_probe(struct udevice *dev) base + 0xbc80)); clk_dm(IMX8MM_CLK_QSPI, imx8m_clk_composite("qspi", imx8mm_qspi_sels, base + 0xab80)); + clk_dm(IMX8MM_CLK_USB_CORE_REF, + imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100)); + clk_dm(IMX8MM_CLK_USB_PHY_REF, + imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180)); clk_dm(IMX8MM_CLK_I2C1_ROOT, imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0)); @@ -403,6 +418,8 @@ static int imx8mm_clk_probe(struct udevice *dev) imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0)); clk_dm(IMX8MM_CLK_QSPI_ROOT, imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0)); + clk_dm(IMX8MM_CLK_USB1_CTRL_ROOT, + imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0)); /* clks not needed in SPL stage */ #ifndef CONFIG_SPL_BUILD diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index a11b17f..8bf6061 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -95,6 +95,10 @@ static const char *imx8mn_enet_phy_sels[] = {"clock-osc-24m", "sys_pll2_50m", "s static const char *imx8mn_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", }; +static const char * const imx8mn_usb_bus_sels[] = {"clock-osc-24m", "sys_pll2_500m", "sys_pll1_800m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + static const char *imx8mn_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", }; @@ -122,6 +126,14 @@ static const char *imx8mn_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sy static const char *imx8mn_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m", "sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m", "sys_pll3_out", "sys_pll1_100m", }; +static const char * const imx8mn_usb_core_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char * const imx8mn_usb_phy_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + static ulong imx8mn_clk_get_rate(struct clk *clk) { struct clk *c; @@ -355,6 +367,8 @@ static int imx8mn_clk_probe(struct udevice *dev) imx8m_clk_composite_critical("nand_usdhc_bus", imx8mn_nand_usdhc_sels, base + 0x8900)); + clk_dm(IMX8MN_CLK_USB_BUS, + imx8m_clk_composite("usb_bus", imx8mn_usb_bus_sels, base + 0x8b80)); /* IP */ clk_dm(IMX8MN_CLK_USDHC1, @@ -378,6 +392,10 @@ static int imx8mn_clk_probe(struct udevice *dev) base + 0xbc80)); clk_dm(IMX8MN_CLK_QSPI, imx8m_clk_composite("qspi", imx8mn_qspi_sels, base + 0xab80)); + clk_dm(IMX8MN_CLK_USB_CORE_REF, + imx8m_clk_composite("usb_core_ref", imx8mn_usb_core_sels, base + 0xb100)); + clk_dm(IMX8MN_CLK_USB_PHY_REF, + imx8m_clk_composite("usb_phy_ref", imx8mn_usb_phy_sels, base + 0xb180)); clk_dm(IMX8MN_CLK_I2C1_ROOT, imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0)); @@ -403,6 +421,8 @@ static int imx8mn_clk_probe(struct udevice *dev) imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0)); clk_dm(IMX8MN_CLK_QSPI_ROOT, imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0)); + clk_dm(IMX8MN_CLK_USB1_CTRL_ROOT, + imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0)); /* clks not needed in SPL stage */ #ifndef CONFIG_SPL_BUILD -- cgit v1.1 From ac9a45182816a34a8996c896f7c8ee81be7ea4d6 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 21 Apr 2020 20:19:24 -0700 Subject: clk: imx8mp: Update imx8mp ccf clock driver Add clocks for FEC and flexspi, and add set parent clock callback, so DTS can assign clocks Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/clk/imx/clk-imx8mp.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 124138c..c77500b 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -80,6 +80,10 @@ static const char *imx8mp_main_axi_sels[] = {"clock-osc-24m", "sys_pll2_333m", " "sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "sys_pll1_100m",}; +static const char *imx8mp_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", + "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out", + "video_pll1_out", "sys_pll3_out", }; + static const char *imx8mp_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", }; @@ -160,10 +164,26 @@ static const char *imx8mp_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_ "vpu_pll_out", "sys_pll2_125m", "sys_pll3_out", "sys_pll1_80m", "sys_pll2_166m" }; +static const char *imx8mp_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m", + "sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m", + "sys_pll3_out", "sys_pll1_100m", }; + static const char *imx8mp_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", }; +static const char *imx8mp_enet_ref_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m", + "sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out", + "video_pll1_out", "clk_ext4", }; + +static const char *imx8mp_enet_timer_sels[] = {"clock-osc-24m", "sys_pll2_100m", "audio_pll1_out", + "clk_ext1", "clk_ext2", "clk_ext3", + "clk_ext4", "video_pll1_out", }; + +static const char *imx8mp_enet_phy_ref_sels[] = {"clock-osc-24m", "sys_pll2_50m", "sys_pll2_125m", + "sys_pll2_200m", "sys_pll2_500m", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", }; + static const char *imx8mp_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; @@ -224,11 +244,34 @@ static int imx8mp_clk_enable(struct clk *clk) return __imx8mp_clk_enable(clk, 1); } +static int imx8mp_clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk *c, *cp; + int ret; + + debug("%s(#%lu), parent: %lu\n", __func__, clk->id, parent->id); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + ret = clk_get_by_id(parent->id, &cp); + if (ret) + return ret; + + ret = clk_set_parent(c, cp); + + c->dev->parent = cp->dev; + + return ret; +} + static struct clk_ops imx8mp_clk_ops = { .set_rate = imx8mp_clk_set_rate, .get_rate = imx8mp_clk_get_rate, .enable = imx8mp_clk_enable, .disable = imx8mp_clk_disable, + .set_parent = imx8mp_clk_set_parent, }; static int imx8mp_clk_probe(struct udevice *dev) @@ -290,6 +333,7 @@ static int imx8mp_clk_probe(struct udevice *dev) clk_dm(IMX8MP_CLK_A53_DIV, imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3)); clk_dm(IMX8MP_CLK_MAIN_AXI, imx8m_clk_composite_critical("main_axi", imx8mp_main_axi_sels, base + 0x8800)); + clk_dm(IMX8MP_CLK_ENET_AXI, imx8m_clk_composite_critical("enet_axi", imx8mp_enet_axi_sels, base + 0x8880)); clk_dm(IMX8MP_CLK_NAND_USDHC_BUS, imx8m_clk_composite_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, base + 0x8900)); clk_dm(IMX8MP_CLK_NOC, imx8m_clk_composite_critical("noc", imx8mp_noc_sels, base + 0x8d00)); clk_dm(IMX8MP_CLK_NOC_IO, imx8m_clk_composite_critical("noc_io", imx8mp_noc_io_sels, base + 0x8d80)); @@ -302,6 +346,10 @@ static int imx8mp_clk_probe(struct udevice *dev) clk_dm(IMX8MP_CLK_DRAM_APB, imx8m_clk_composite_critical("dram_apb", imx8mp_dram_apb_sels, base + 0xa080)); clk_dm(IMX8MP_CLK_I2C5, imx8m_clk_composite("i2c5", imx8mp_i2c5_sels, base + 0xa480)); clk_dm(IMX8MP_CLK_I2C6, imx8m_clk_composite("i2c6", imx8mp_i2c6_sels, base + 0xa500)); + clk_dm(IMX8MP_CLK_ENET_REF, imx8m_clk_composite("enet_ref", imx8mp_enet_ref_sels, base + 0xa980)); + clk_dm(IMX8MP_CLK_ENET_TIMER, imx8m_clk_composite("enet_timer", imx8mp_enet_timer_sels, base + 0xaa00)); + clk_dm(IMX8MP_CLK_ENET_PHY_REF, imx8m_clk_composite("enet_phy_ref", imx8mp_enet_phy_ref_sels, base + 0xaa80)); + clk_dm(IMX8MP_CLK_QSPI, imx8m_clk_composite("qspi", imx8mp_qspi_sels, base + 0xab80)); clk_dm(IMX8MP_CLK_USDHC1, imx8m_clk_composite("usdhc1", imx8mp_usdhc1_sels, base + 0xac00)); clk_dm(IMX8MP_CLK_USDHC2, imx8m_clk_composite("usdhc2", imx8mp_usdhc2_sels, base + 0xac80)); clk_dm(IMX8MP_CLK_I2C1, imx8m_clk_composite("i2c1", imx8mp_i2c1_sels, base + 0xad00)); @@ -322,6 +370,8 @@ static int imx8mp_clk_probe(struct udevice *dev) clk_dm(IMX8MP_CLK_DRAM_CORE, imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mp_dram_core_sels, ARRAY_SIZE(imx8mp_dram_core_sels), CLK_IS_CRITICAL)); clk_dm(IMX8MP_CLK_DRAM1_ROOT, imx_clk_gate4_flags("dram1_root_clk", "dram_core_clk", base + 0x4050, 0, CLK_IS_CRITICAL)); + + clk_dm(IMX8MP_CLK_ENET1_ROOT, imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0)); clk_dm(IMX8MP_CLK_GPIO1_ROOT, imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0)); clk_dm(IMX8MP_CLK_GPIO2_ROOT, imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0)); clk_dm(IMX8MP_CLK_GPIO3_ROOT, imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0)); @@ -331,8 +381,10 @@ static int imx8mp_clk_probe(struct udevice *dev) clk_dm(IMX8MP_CLK_I2C2_ROOT, imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0)); clk_dm(IMX8MP_CLK_I2C3_ROOT, imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0)); clk_dm(IMX8MP_CLK_I2C4_ROOT, imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0)); + clk_dm(IMX8MP_CLK_QSPI_ROOT, imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0)); clk_dm(IMX8MP_CLK_I2C5_ROOT, imx_clk_gate2("i2c5_root_clk", "i2c5", base + 0x4330, 0)); clk_dm(IMX8MP_CLK_I2C6_ROOT, imx_clk_gate2("i2c6_root_clk", "i2c6", base + 0x4340, 0)); + clk_dm(IMX8MP_CLK_SIM_ENET_ROOT, imx_clk_gate4("sim_enet_root_clk", "enet_axi", base + 0x4400, 0)); clk_dm(IMX8MP_CLK_UART1_ROOT, imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0)); clk_dm(IMX8MP_CLK_UART2_ROOT, imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0)); clk_dm(IMX8MP_CLK_UART3_ROOT, imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0)); -- cgit v1.1 From ec04ae4217e6f68ad7ccd7740e540d79a3f4e1c1 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 9 Jul 2020 15:36:22 +0800 Subject: clk: imx8m: drop clk settings We use non-dm code to configure the clk settings in order to simplify dm clk driver in future, so remove the duplicated code from clk driver Signed-off-by: Peng Fan --- drivers/clk/imx/clk-imx8mm.c | 34 ---------------------------------- drivers/clk/imx/clk-imx8mn.c | 34 ---------------------------------- 2 files changed, 68 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 85d1757..d32ff84 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -437,40 +437,6 @@ static int imx8mm_clk_probe(struct udevice *dev) base + 0x40a0, 0)); #endif -#ifdef CONFIG_SPL_BUILD - struct clk *clkp, *clkp1; - - clk_get_by_id(IMX8MM_CLK_WDOG1_ROOT, &clkp); - clk_enable(clkp); - clk_get_by_id(IMX8MM_CLK_WDOG2_ROOT, &clkp); - clk_enable(clkp); - clk_get_by_id(IMX8MM_CLK_WDOG3_ROOT, &clkp); - clk_enable(clkp); - - /* Configure SYS_PLL3 to 750MHz */ - clk_get_by_id(IMX8MM_SYS_PLL3, &clkp); - clk_set_rate(clkp, 750000000UL); - clk_enable(clkp); - - /* Configure ARM to sys_pll2_500m */ - clk_get_by_id(IMX8MM_CLK_A53_SRC, &clkp); - clk_get_by_id(IMX8MM_SYS_PLL2_OUT, &clkp1); - clk_enable(clkp1); - clk_get_by_id(IMX8MM_SYS_PLL2_500M, &clkp1); - clk_set_parent(clkp, clkp1); - - /* Configure ARM PLL to 1.2GHz */ - clk_get_by_id(IMX8MM_ARM_PLL, &clkp1); - clk_set_rate(clkp1, 1200000000UL); - clk_get_by_id(IMX8MM_ARM_PLL_OUT, &clkp1); - clk_enable(clkp1); - clk_set_parent(clkp, clkp1); - - /* Configure DIV to 1.2GHz */ - clk_get_by_id(IMX8MM_CLK_A53_DIV, &clkp1); - clk_set_rate(clkp1, 1200000000UL); -#endif - return 0; } diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 8bf6061..e29d902 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -440,40 +440,6 @@ static int imx8mn_clk_probe(struct udevice *dev) base + 0x40a0, 0)); #endif -#ifdef CONFIG_SPL_BUILD - struct clk *clkp, *clkp1; - - clk_get_by_id(IMX8MN_CLK_WDOG1_ROOT, &clkp); - clk_enable(clkp); - clk_get_by_id(IMX8MN_CLK_WDOG2_ROOT, &clkp); - clk_enable(clkp); - clk_get_by_id(IMX8MN_CLK_WDOG3_ROOT, &clkp); - clk_enable(clkp); - - /* Configure SYS_PLL3 to 600MHz */ - clk_get_by_id(IMX8MN_SYS_PLL3, &clkp); - clk_set_rate(clkp, 600000000UL); - clk_enable(clkp); - - /* Configure ARM to sys_pll2_500m */ - clk_get_by_id(IMX8MN_CLK_A53_SRC, &clkp); - clk_get_by_id(IMX8MN_SYS_PLL2_OUT, &clkp1); - clk_enable(clkp1); - clk_get_by_id(IMX8MN_SYS_PLL2_500M, &clkp1); - clk_set_parent(clkp, clkp1); - - /* Configure ARM PLL to 1.2GHz */ - clk_get_by_id(IMX8MN_ARM_PLL, &clkp1); - clk_set_rate(clkp1, 1200000000UL); - clk_get_by_id(IMX8MN_ARM_PLL_OUT, &clkp1); - clk_enable(clkp1); - clk_set_parent(clkp, clkp1); - - /* Configure DIV to 1.2GHz */ - clk_get_by_id(IMX8MN_CLK_A53_DIV, &clkp1); - clk_set_rate(clkp1, 1200000000UL); -#endif - return 0; } -- cgit v1.1 From 93d6c8f7b79786878f186b7e30676a52bba52860 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 9 Jun 2020 00:59:05 -0700 Subject: spi: fsl_qspi: Add support for i.MX7ULP Add compatible string and driver data for i.MX7ULP. Meanwhile, the address set to SFA1AD/SFA2AD/SFB1AD/SFB2AD should align with 1KB, because the lowest 10 bits are reserved by the registers definition. For i.MX7ULP which has only 128Bytes AHB buffer, must align it when setting the registers and selecting cs. Signed-off-by: Ye Li Reviewed-by: Ashish Kumar Reviewed-by: Kuldeep Singh --- drivers/spi/fsl_qspi.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index e715f98..d9f531a 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -231,6 +231,15 @@ static const struct fsl_qspi_devtype_data imx6ul_data = { .little_endian = true, }; +static const struct fsl_qspi_devtype_data imx7ulp_data = { + .rxfifo = SZ_64, + .txfifo = SZ_64, + .ahb_buf_size = SZ_128, + .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK | + QUADSPI_QUIRK_USE_TDH_SETTING, + .little_endian = true, +}; + static const struct fsl_qspi_devtype_data ls1021a_data = { .rxfifo = SZ_128, .txfifo = SZ_64, @@ -485,7 +494,7 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_slave *slave) static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op) { memcpy_fromio(op->data.buf.in, - q->ahb_addr + q->selected * q->devtype_data->ahb_buf_size, + q->ahb_addr + q->selected * ALIGN(q->devtype_data->ahb_buf_size, 0x400), op->data.nbytes); } @@ -589,7 +598,7 @@ static int fsl_qspi_exec_op(struct spi_slave *slave, addr_offset = q->memmap_phy; qspi_writel(q, - q->selected * q->devtype_data->ahb_buf_size + addr_offset, + q->selected * ALIGN(q->devtype_data->ahb_buf_size, 0x400) + addr_offset, base + QUADSPI_SFAR); qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) | @@ -695,13 +704,13 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q) * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD, * SFB2AD accordingly. */ - qspi_writel(q, q->devtype_data->ahb_buf_size + addr_offset, + qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) + addr_offset, base + QUADSPI_SFA1AD); - qspi_writel(q, q->devtype_data->ahb_buf_size * 2 + addr_offset, + qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 2 + addr_offset, base + QUADSPI_SFA2AD); - qspi_writel(q, q->devtype_data->ahb_buf_size * 3 + addr_offset, + qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 3 + addr_offset, base + QUADSPI_SFB1AD); - qspi_writel(q, q->devtype_data->ahb_buf_size * 4 + addr_offset, + qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 4 + addr_offset, base + QUADSPI_SFB2AD); q->selected = -1; @@ -799,6 +808,7 @@ static const struct udevice_id fsl_qspi_ids[] = { { .compatible = "fsl,imx6sx-qspi", .data = (ulong)&imx6sx_data, }, { .compatible = "fsl,imx6ul-qspi", .data = (ulong)&imx6ul_data, }, { .compatible = "fsl,imx7d-qspi", .data = (ulong)&imx7d_data, }, + { .compatible = "fsl,imx7ulp-qspi", .data = (ulong)&imx7ulp_data, }, { .compatible = "fsl,ls1021a-qspi", .data = (ulong)&ls1021a_data, }, { .compatible = "fsl,ls1088a-qspi", .data = (ulong)&ls1088a_data, }, { .compatible = "fsl,ls2080a-qspi", .data = (ulong)&ls2080a_data, }, -- cgit v1.1 From def88bce094e95939abf1e5d02a9b413b3627f6f Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 9 Jun 2020 00:59:06 -0700 Subject: spi: fsl_qspi: Support to use full AHB space on i.MX i.MX platforms provide large AHB mapped space for QSPI, each controller has 256MB. However, current driver only maps small size (AHB buffer size) of AHB space, this implementation causes i.MX failed to boot M4 with QSPI XIP image. Add config CONFIG_FSL_QSPI_AHB_FULL_MAP (default enabled for i.MX) to address above problem. When the config is set: 1. Full AHB space is divided to each CS. 2. A dedicated LUT entry is used for AHB read only. 3. The MODE instruction in LUT is replaced to standard ADDR instruction 4. The address in spi_mem_op is used to SFAR and AHB read Signed-off-by: Ye Li Reviewed-by: Ashish Kumar Reviewed-by: Kuldeep Singh --- drivers/spi/Kconfig | 8 ++++ drivers/spi/fsl_qspi.c | 114 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 98 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3a8add9..30d808d 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -155,6 +155,14 @@ config FSL_QSPI used to access the SPI NOR flash on platforms embedding this Freescale IP core. +config FSL_QSPI_AHB_FULL_MAP + bool "Use full AHB memory map space" + depends on FSL_QSPI + default y if ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP || ARCH_IMX8M + help + Enable the Freescale QSPI driver to use full AHB memory map space for + flash access. + config ICH_SPI bool "Intel ICH SPI driver" help diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index d9f531a..eec968e 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -46,6 +46,7 @@ DECLARE_GLOBAL_DATA_PTR; * read operation, so let's use the last entry (15). */ #define SEQID_LUT 15 +#define SEQID_LUT_AHB 14 /* Registers used by the driver */ #define QUADSPI_MCR 0x00 @@ -122,6 +123,10 @@ DECLARE_GLOBAL_DATA_PTR; #define QUADSPI_LUT_REG(idx) \ (QUADSPI_LUT_BASE + QUADSPI_LUT_OFFSET + (idx) * 4) +#define QUADSPI_AHB_LUT_OFFSET (SEQID_LUT_AHB * 4 * 4) +#define QUADSPI_AHB_LUT_REG(idx) \ + (QUADSPI_LUT_BASE + QUADSPI_AHB_LUT_OFFSET + (idx) * 4) + /* Instruction set for the LUT register */ #define LUT_STOP 0 #define LUT_CMD 1 @@ -189,6 +194,11 @@ DECLARE_GLOBAL_DATA_PTR; */ #define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5) +/* + * Controller only has Two CS on flash A, no flash B port + */ +#define QUADSPI_QUIRK_SINGLE_BUS BIT(6) + struct fsl_qspi_devtype_data { unsigned int rxfifo; unsigned int txfifo; @@ -236,7 +246,7 @@ static const struct fsl_qspi_devtype_data imx7ulp_data = { .txfifo = SZ_64, .ahb_buf_size = SZ_128, .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK | - QUADSPI_QUIRK_USE_TDH_SETTING, + QUADSPI_QUIRK_USE_TDH_SETTING | QUADSPI_QUIRK_SINGLE_BUS, .little_endian = true, }; @@ -269,6 +279,7 @@ struct fsl_qspi { void __iomem *iobase; void __iomem *ahb_addr; u32 memmap_phy; + u32 memmap_size; const struct fsl_qspi_devtype_data *devtype_data; int selected; }; @@ -303,6 +314,11 @@ static inline int needs_tdh_setting(struct fsl_qspi *q) return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING; } +static inline int needs_single_bus(struct fsl_qspi *q) +{ + return q->devtype_data->quirks & QUADSPI_QUIRK_SINGLE_BUS; +} + /* * An IC bug makes it necessary to rearrange the 32-bit data. * Later chips, such as IMX6SLX, have fixed this bug. @@ -405,18 +421,27 @@ static void fsl_qspi_prepare_lut(struct fsl_qspi *q, lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth), op->cmd.opcode); - /* - * For some unknown reason, using LUT_ADDR doesn't work in some - * cases (at least with only one byte long addresses), so - * let's use LUT_MODE to write the address bytes one by one - */ - for (i = 0; i < op->addr.nbytes; i++) { - u8 addrbyte = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); - - lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_MODE, - LUT_PAD(op->addr.buswidth), - addrbyte); - lutidx++; + if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) { + if (op->addr.nbytes) { + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_ADDR, + LUT_PAD(op->addr.buswidth), + (op->addr.nbytes == 4) ? 0x20 : 0x18); + lutidx++; + } + } else { + /* + * For some unknown reason, using LUT_ADDR doesn't work in some + * cases (at least with only one byte long addresses), so + * let's use LUT_MODE to write the address bytes one by one + */ + for (i = 0; i < op->addr.nbytes; i++) { + u8 addrbyte = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); + + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_MODE, + LUT_PAD(op->addr.buswidth), + addrbyte); + lutidx++; + } } if (op->dummy.nbytes) { @@ -449,6 +474,14 @@ static void fsl_qspi_prepare_lut(struct fsl_qspi *q, for (i = 0; i < ARRAY_SIZE(lutval); i++) qspi_writel(q, lutval[i], base + QUADSPI_LUT_REG(i)); + if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) { + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN && + op->addr.nbytes) { + for (i = 0; i < ARRAY_SIZE(lutval); i++) + qspi_writel(q, lutval[i], base + QUADSPI_AHB_LUT_REG(i)); + } + } + /* lock LUT */ qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR); @@ -491,10 +524,29 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_slave *slave) fsl_qspi_invalidate(q); } +static u32 fsl_qspi_memsize_per_cs(struct fsl_qspi *q) +{ + if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) { + if (needs_single_bus(q)) + return q->memmap_size / 2; + else + return q->memmap_size / 4; + } else { + return ALIGN(q->devtype_data->ahb_buf_size, 0x400); + } +} + static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op) { + void __iomem *ahb_read_addr = q->ahb_addr; + + if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) { + if (op->addr.nbytes) + ahb_read_addr += op->addr.val; + } + memcpy_fromio(op->data.buf.in, - q->ahb_addr + q->selected * ALIGN(q->devtype_data->ahb_buf_size, 0x400), + ahb_read_addr + q->selected * fsl_qspi_memsize_per_cs(q), op->data.nbytes); } @@ -597,8 +649,13 @@ static int fsl_qspi_exec_op(struct spi_slave *slave, if (needs_amba_base_offset(q)) addr_offset = q->memmap_phy; + if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) { + if (op->addr.nbytes) + addr_offset += op->addr.val; + } + qspi_writel(q, - q->selected * ALIGN(q->devtype_data->ahb_buf_size, 0x400) + addr_offset, + q->selected * fsl_qspi_memsize_per_cs(q) + addr_offset, base + QUADSPI_SFAR); qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) | @@ -655,7 +712,7 @@ static int fsl_qspi_adjust_op_size(struct spi_slave *slave, static int fsl_qspi_default_setup(struct fsl_qspi *q) { void __iomem *base = q->iobase; - u32 reg, addr_offset = 0; + u32 reg, addr_offset = 0, memsize_cs; /* Reset the module */ qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK, @@ -687,8 +744,13 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q) qspi_writel(q, 0, base + QUADSPI_BUF1IND); qspi_writel(q, 0, base + QUADSPI_BUF2IND); - qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT), - q->iobase + QUADSPI_BFGENCR); + if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) + qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT_AHB), + q->iobase + QUADSPI_BFGENCR); + else + qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT), + q->iobase + QUADSPI_BFGENCR); + qspi_writel(q, QUADSPI_RBCT_WMRK_MASK, base + QUADSPI_RBCT); qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK | QUADSPI_BUF3CR_ADATSZ(q->devtype_data->ahb_buf_size / 8), @@ -704,14 +766,17 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q) * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD, * SFB2AD accordingly. */ - qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) + addr_offset, + memsize_cs = fsl_qspi_memsize_per_cs(q); + qspi_writel(q, memsize_cs + addr_offset, base + QUADSPI_SFA1AD); - qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 2 + addr_offset, + qspi_writel(q, memsize_cs * 2 + addr_offset, base + QUADSPI_SFA2AD); - qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 3 + addr_offset, - base + QUADSPI_SFB1AD); - qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 4 + addr_offset, - base + QUADSPI_SFB2AD); + if (!needs_single_bus(q)) { + qspi_writel(q, memsize_cs * 3 + addr_offset, + base + QUADSPI_SFB1AD); + qspi_writel(q, memsize_cs * 4 + addr_offset, + base + QUADSPI_SFB2AD); + } q->selected = -1; @@ -759,6 +824,7 @@ static int fsl_qspi_probe(struct udevice *bus) q->ahb_addr = map_physmem(res.start, res.end - res.start, MAP_NOCACHE); q->memmap_phy = res.start; + q->memmap_size = res.end - res.start; dm_bus->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 66000000); -- cgit v1.1 From dfbdaa66b7fbc60efb48e228733f7e98b3e6fed5 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 9 Jun 2020 03:34:42 -0700 Subject: misc: scu_api: Add SCFW API to get the index of boot container set Add SCFW API sc_misc_get_boot_container to get current boot container set index. The index value returns 1 for primary container set, 2 for secondary container set. Signed-off-by: Ye Li Reviewed-by: Peng Fan --- drivers/misc/imx8/scu_api.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/imx8/scu_api.c b/drivers/misc/imx8/scu_api.c index 3e38edb..20b74fb 100644 --- a/drivers/misc/imx8/scu_api.c +++ b/drivers/misc/imx8/scu_api.c @@ -374,6 +374,31 @@ void sc_misc_boot_status(sc_ipc_t ipc, sc_misc_boot_status_t status) __func__, status, RPC_R8(&msg)); } +int sc_misc_get_boot_container(sc_ipc_t ipc, u8 *idx) +{ + struct udevice *dev = gd->arch.scu_dev; + int size = sizeof(struct sc_rpc_msg_s); + struct sc_rpc_msg_s msg; + int ret; + + if (!dev) + hang(); + + RPC_VER(&msg) = SC_RPC_VERSION; + RPC_SIZE(&msg) = 1U; + RPC_SVC(&msg) = (u8)SC_RPC_SVC_MISC; + RPC_FUNC(&msg) = (u8)MISC_FUNC_GET_BOOT_CONTAINER; + + ret = misc_call(dev, SC_FALSE, &msg, size, &msg, size); + if (ret < 0) + return ret; + + if (idx) + *idx = (u8)RPC_U8(&msg, 0U); + + return 0; +} + void sc_misc_build_info(sc_ipc_t ipc, u32 *build, u32 *commit) { struct udevice *dev = gd->arch.scu_dev; -- cgit v1.1 From 6103e570cdd0d0e854b071ee17b14589356a82bd Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 9 Jun 2020 20:29:51 -0700 Subject: gpio: mxc_gpio: Improve to use ofdata_to_platdata Current mxc_gpio DM driver allocates the platdata in bind function to handle both OF_CONTROL enabled case and disabled case. This implementation puts the devfdt_get_addr in bind, which introduces much overhead especially in board_f phase. Change the driver to a common way for handling the cases by using ofdata_to_platdata and using DM framework to allocate platdata. Signed-off-by: Ye Li Reviewed-by: Peng Fan --- drivers/gpio/mxc_gpio.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c index 316dcc7..90d36fb 100644 --- a/drivers/gpio/mxc_gpio.c +++ b/drivers/gpio/mxc_gpio.c @@ -295,46 +295,26 @@ static int mxc_gpio_probe(struct udevice *dev) return 0; } -static int mxc_gpio_bind(struct udevice *dev) +static int mxc_gpio_ofdata_to_platdata(struct udevice *dev) { - struct mxc_gpio_plat *plat = dev->platdata; fdt_addr_t addr; - - /* - * If platdata already exsits, directly return. - * Actually only when DT is not supported, platdata - * is statically initialized in U_BOOT_DEVICES.Here - * will return. - */ - if (plat) - return 0; + struct mxc_gpio_plat *plat = dev_get_platdata(dev); addr = devfdt_get_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; - /* - * TODO: - * When every board is converted to driver model and DT is supported, - * this can be done by auto-alloc feature, but not using calloc - * to alloc memory for platdata. - * - * For example mxc_plat below uses platform data rather than device - * tree. - * - * NOTE: DO NOT COPY this code if you are using device tree. - */ - plat = calloc(1, sizeof(*plat)); - if (!plat) - return -ENOMEM; - plat->regs = (struct gpio_regs *)addr; plat->bank_index = dev->req_seq; - dev->platdata = plat; return 0; } +static int mxc_gpio_bind(struct udevice *dev) +{ + return 0; +} + static const struct udevice_id mxc_gpio_ids[] = { { .compatible = "fsl,imx35-gpio" }, { } @@ -345,6 +325,8 @@ U_BOOT_DRIVER(gpio_mxc) = { .id = UCLASS_GPIO, .ops = &gpio_mxc_ops, .probe = mxc_gpio_probe, + .ofdata_to_platdata = mxc_gpio_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct mxc_gpio_plat), .priv_auto_alloc_size = sizeof(struct mxc_bank_info), .of_match = mxc_gpio_ids, .bind = mxc_gpio_bind, -- cgit v1.1 From eefd93e7f88ec919cc335dbf934320fec949bce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Szymanski?= Date: Tue, 30 Jun 2020 15:03:13 +0200 Subject: power: pmic_pca9450: fix PCA9450A I2C address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quoting Ye Li from NXP: "We have confirmed with PMIC team, 0x35 is used only on early chips and not used any more. 0x25 is the final address." Fix it by merging power_pca9450a_init and power_pca9450b_init into one function power_pca9450_init. Signed-off-by: Sébastien Szymanski Reviewed-by: Fabio Estevam Reviewed-by: Ye Li --- drivers/power/pmic/pmic_pca9450.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/power/pmic/pmic_pca9450.c b/drivers/power/pmic/pmic_pca9450.c index 67a9090..d4f2742 100644 --- a/drivers/power/pmic/pmic_pca9450.c +++ b/drivers/power/pmic/pmic_pca9450.c @@ -11,26 +11,7 @@ static const char pca9450_name[] = "PCA9450"; -int power_pca9450a_init(unsigned char bus) -{ - struct pmic *p = pmic_alloc(); - - if (!p) { - printf("%s: POWER allocation error!\n", __func__); - return -ENOMEM; - } - - p->name = pca9450_name; - p->interface = PMIC_I2C; - p->number_of_regs = PCA9450_REG_NUM; - p->hw.i2c.addr = 0x35; - p->hw.i2c.tx_num = 1; - p->bus = bus; - - return 0; -} - -int power_pca9450b_init(unsigned char bus) +int power_pca9450_init(unsigned char bus) { struct pmic *p = pmic_alloc(); -- cgit v1.1 From ee6866e6c773341ad4058d46ff898ad258db1292 Mon Sep 17 00:00:00 2001 From: "Mo, Yuezhang" Date: Wed, 1 Jul 2020 09:15:28 +0000 Subject: watchdog: imx: Support set timeout by wdt command After "4b969deac0 watchdog: imx: Add DM support", the imx watchdog can be started by wdt command. But the imx watchdog driver only support start with the default timeout. This commit adds the support for setting the timeout which pass from the wdt command into the imx watchdog. If the timeout out of the valid range(0.5~128s), start the watchdog with a timeout within the valid range and the timeout is the one which closest to the passed timeout. Signed-off-by: Yuezhang.Mo Reviewed-by: Andy.Wu Reviewed-by: stefano Babic --- drivers/watchdog/imx_watchdog.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c index 01762df..b90c2da 100644 --- a/drivers/watchdog/imx_watchdog.c +++ b/drivers/watchdog/imx_watchdog.c @@ -16,6 +16,10 @@ #include #endif #include +#include + +#define TIMEOUT_MAX 128000 +#define TIMEOUT_MIN 500 static void imx_watchdog_expire_now(struct watchdog_regs *wdog, bool ext_reset) { @@ -57,9 +61,9 @@ static void imx_watchdog_reset(struct watchdog_regs *wdog) #endif /* CONFIG_WATCHDOG_RESET_DISABLE*/ } -static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset) +static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset, + u64 timeout) { - u16 timeout; u16 wcr; /* @@ -70,7 +74,11 @@ static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset) #ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS #define CONFIG_WATCHDOG_TIMEOUT_MSECS 128000 #endif - timeout = (CONFIG_WATCHDOG_TIMEOUT_MSECS / 500) - 1; + + timeout = max_t(u64, timeout, TIMEOUT_MIN); + timeout = min_t(u64, timeout, TIMEOUT_MAX); + timeout = lldiv(timeout, 500) - 1; + #ifdef CONFIG_FSL_LSCH2 wcr = (WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout; #else @@ -95,7 +103,7 @@ void hw_watchdog_init(void) { struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR; - imx_watchdog_init(wdog, true); + imx_watchdog_init(wdog, true, CONFIG_WATCHDOG_TIMEOUT_MSECS); } #else struct imx_wdt_priv { @@ -126,7 +134,7 @@ static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) { struct imx_wdt_priv *priv = dev_get_priv(dev); - imx_watchdog_init(priv->base, priv->ext_reset); + imx_watchdog_init(priv->base, priv->ext_reset, timeout); return 0; } -- cgit v1.1