diff options
| author | Tom Rini <[email protected]> | 2022-07-26 10:26:00 -0400 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2022-07-26 10:26:00 -0400 |
| commit | 86feeab3dc71977afb70f595e42060ce324086d0 (patch) | |
| tree | 687b9f2251d55f33eaab2d9d8805071eddf7ca6c /drivers | |
| parent | e5f6fecda4a606acd2417fb537f331e37c757fa5 (diff) | |
| parent | e29303993bad6c94954da7d5cd92b1d36cf2c80b (diff) | |
Merge tag 'u-boot-imx-20220726' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
u-boot-imx-20220726
-------------------
i.MX for 2022.10
- Added i.MX93 architecture
CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/12891
Diffstat (limited to 'drivers')
32 files changed, 1740 insertions, 444 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index d63fd1c04d1..eba9940231f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/ obj-$(CONFIG_$(SPL_)ALTERA_SDRAM) += ddr/altera/ obj-$(CONFIG_ARCH_IMX8M) += ddr/imx/imx8m/ obj-$(CONFIG_IMX8ULP_DRAM) += ddr/imx/imx8ulp/ +obj-$(CONFIG_ARCH_IMX9) += ddr/imx/imx9/ obj-$(CONFIG_SPL_DM_RESET) += reset/ obj-$(CONFIG_SPL_MUSB_NEW) += usb/musb-new/ obj-$(CONFIG_SPL_USB_GADGET) += usb/gadget/ diff --git a/drivers/ddr/imx/Kconfig b/drivers/ddr/imx/Kconfig index 179f34530d7..328fbabb6db 100644 --- a/drivers/ddr/imx/Kconfig +++ b/drivers/ddr/imx/Kconfig @@ -1,2 +1,4 @@ source "drivers/ddr/imx/imx8m/Kconfig" source "drivers/ddr/imx/imx8ulp/Kconfig" +source "drivers/ddr/imx/imx9/Kconfig" +source "drivers/ddr/imx/phy/Kconfig" diff --git a/drivers/ddr/imx/imx8m/Kconfig b/drivers/ddr/imx/imx8m/Kconfig index a90b7db4940..08b6787a543 100644 --- a/drivers/ddr/imx/imx8m/Kconfig +++ b/drivers/ddr/imx/imx8m/Kconfig @@ -3,6 +3,7 @@ menu "i.MX8M DDR controllers" config IMX8M_DRAM bool "imx8m dram" + select IMX_SNPS_DDR_PHY config IMX8M_LPDDR4 bool "imx8m lpddr4" diff --git a/drivers/ddr/imx/imx8m/Makefile b/drivers/ddr/imx/imx8m/Makefile index bd9bcb8d53b..aed91dc23f4 100644 --- a/drivers/ddr/imx/imx8m/Makefile +++ b/drivers/ddr/imx/imx8m/Makefile @@ -5,5 +5,6 @@ # ifdef CONFIG_SPL_BUILD -obj-$(CONFIG_IMX8M_DRAM) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o ddr_init.o +obj-$(CONFIG_IMX8M_DRAM) += ddr_init.o +obj-y += ../phy/ endif diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c index b70bcc383fa..d964184ddc8 100644 --- a/drivers/ddr/imx/imx8m/ddr_init.c +++ b/drivers/ddr/imx/imx8m/ddr_init.c @@ -11,6 +11,11 @@ #include <asm/arch/clock.h> #include <asm/arch/sys_proto.h> +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]; + void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num) { int i = 0; @@ -91,6 +96,215 @@ void __weak board_dram_ecc_scrub(void) { } +void lpddr4_mr_write(unsigned int mr_rank, unsigned int mr_addr, + unsigned int mr_data) +{ + unsigned int tmp; + /* + * 1. Poll MRSTAT.mr_wr_busy until it is 0. + * This checks that there is no outstanding MR transaction. + * No writes should be performed to MRCTRL0 and MRCTRL1 if + * MRSTAT.mr_wr_busy = 1. + */ + do { + tmp = reg32_read(DDRC_MRSTAT(0)); + } while (tmp & 0x1); + /* + * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank and + * (for MRWs) MRCTRL1.mr_data to define the MR transaction. + */ + reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4)); + reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8) | mr_data); + reg32setbit(DDRC_MRCTRL0(0), 31); +} + +unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr) +{ + unsigned int tmp; + + reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x1); + do { + tmp = reg32_read(DDRC_MRSTAT(0)); + } while (tmp & 0x1); + + reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4) | 0x1); + reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8)); + reg32setbit(DDRC_MRCTRL0(0), 31); + do { + tmp = reg32_read(DRC_PERF_MON_MRR0_DAT(0)); + } while ((tmp & 0x8) == 0); + tmp = reg32_read(DRC_PERF_MON_MRR1_DAT(0)); + tmp = tmp & 0xff; + reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x4); + + return tmp; +} + +static 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); + } +} + int ddr_init(struct dram_timing_info *dram_timing) { unsigned int tmp, initial_drate, target_freq; @@ -250,3 +464,8 @@ int ddr_init(struct dram_timing_info *dram_timing) return 0; } + +ulong ddrphy_addr_remap(uint32_t paddr_apb_from_ctlr) +{ + return 4 * paddr_apb_from_ctlr; +} diff --git a/drivers/ddr/imx/imx9/Kconfig b/drivers/ddr/imx/imx9/Kconfig new file mode 100644 index 00000000000..123ad173cfc --- /dev/null +++ b/drivers/ddr/imx/imx9/Kconfig @@ -0,0 +1,27 @@ +menu "i.MX9 DDR controllers" + depends on ARCH_IMX9 + +config IMX9_DRAM + bool "imx9 dram" + select IMX_SNPS_DDR_PHY + +config IMX9_LPDDR4X + bool "imx9 lpddr4 and lpddr4x" + select IMX9_DRAM + help + Select the i.MX9 LPDDR4/4X driver support on i.MX9 SOC. + +config IMX9_DRAM_PM_COUNTER + bool "imx9 DDRC performance monitor counter" + default y + help + Enable DDR controller performance monitor counter for reference events. + +config SAVED_DRAM_TIMING_BASE + hex "Define the base address for saved dram timing" + help + after DRAM is trained, need to save the dram related timming + info into memory for low power use. + default 0x204DC000 + +endmenu diff --git a/drivers/ddr/imx/imx9/Makefile b/drivers/ddr/imx/imx9/Makefile new file mode 100644 index 00000000000..9403f988b32 --- /dev/null +++ b/drivers/ddr/imx/imx9/Makefile @@ -0,0 +1,10 @@ +# +# Copyright 2018 NXP +# +# SPDX-License-Identifier: GPL-2.0+ +# + +ifdef CONFIG_SPL_BUILD +obj-$(CONFIG_IMX9_DRAM) += ddr_init.o +obj-y += ../phy/ +endif diff --git a/drivers/ddr/imx/imx9/ddr_init.c b/drivers/ddr/imx/imx9/ddr_init.c new file mode 100644 index 00000000000..8b8ec7f8de3 --- /dev/null +++ b/drivers/ddr/imx/imx9/ddr_init.c @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022 NXP + */ + +#include <common.h> +#include <errno.h> +#include <log.h> +#include <asm/io.h> +#include <asm/arch/ddr.h> +#include <asm/arch/clock.h> +#include <asm/arch/sys_proto.h> +#include <linux/delay.h> + +void ddrphy_coldreset(void) +{ + /* dramphy_apb_n default 1 , assert -> 0, de_assert -> 1 */ + /* dramphy_reset_n default 0 , assert -> 0, de_assert -> 1 */ + /* dramphy_PwrOKIn default 0 , assert -> 1, de_assert -> 0 */ + + /* src_gen_dphy_apb_sw_rst_de_assert */ + clrbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0)); + /* src_gen_dphy_sw_rst_de_assert */ + clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2)); + /* src_gen_dphy_PwrOKIn_sw_rst_de_assert() */ + setbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(0)); + mdelay(10); + + /* src_gen_dphy_apb_sw_rst_assert */ + setbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0)); + /* src_gen_dphy_sw_rst_assert */ + setbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2)); + mdelay(10); + /* src_gen_dphy_PwrOKIn_sw_rst_assert */ + clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(0)); + mdelay(10); + + /* src_gen_dphy_apb_sw_rst_de_assert */ + clrbits_le32(REG_SRC_DPHY_SW_CTRL, BIT(0)); + /* src_gen_dphy_sw_rst_de_assert() */ + clrbits_le32(REG_SRC_DPHY_SINGLE_RESET_SW_CTRL, BIT(2)); +} + +void check_ddrc_idle(void) +{ + u32 regval; + + do { + regval = readl(REG_DDRDSR_2); + if (regval & BIT(31)) + break; + } while (1); +} + +void check_dfi_init_complete(void) +{ + u32 regval; + + do { + regval = readl(REG_DDRDSR_2); + if (regval & BIT(2)) + break; + } while (1); + setbits_le32(REG_DDRDSR_2, BIT(2)); +} + +void ddrc_config(struct dram_cfg_param *ddrc_config, int num) +{ + int i = 0; + + for (i = 0; i < num; i++) { + writel(ddrc_config->val, (ulong)ddrc_config->reg); + ddrc_config++; + } +} + +void get_trained_CDD(u32 fsp) +{ +} + +int ddr_init(struct dram_timing_info *dram_timing) +{ + unsigned int initial_drate; + int ret; + u32 regval; + + debug("DDRINFO: start DRAM init\n"); + + /* reset ddrphy */ + ddrphy_coldreset(); + + debug("DDRINFO: cfg clk\n"); + + initial_drate = dram_timing->fsp_msg[0].drate; + /* default to the frequency point 0 clock */ + ddrphy_init_set_dfi_clk(initial_drate); + + /* + * Start PHY initialization and training by + * accessing relevant PUB registers + */ + debug("DDRINFO:ddrphy config start\n"); + + ret = ddr_cfg_phy(dram_timing); + if (ret) + return ret; + + debug("DDRINFO: ddrphy config done\n"); + + /* rogram the ddrc registers */ + debug("DDRINFO: ddrc config start\n"); + ddrc_config(dram_timing->ddrc_cfg, dram_timing->ddrc_cfg_num); + debug("DDRINFO: ddrc config done\n"); + +#ifdef CONFIG_IMX9_DRAM_PM_COUNTER + writel(0x200000, REG_DDR_DEBUG_19); +#endif + + check_dfi_init_complete(); + + regval = readl(REG_DDR_SDRAM_CFG); + writel((regval | 0x80000000), REG_DDR_SDRAM_CFG); + + check_ddrc_idle(); + + /* save the dram timing config into memory */ + dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE); + + return 0; +} + +ulong ddrphy_addr_remap(u32 paddr_apb_from_ctlr) +{ + u32 paddr_apb_qual; + u32 paddr_apb_unqual_dec_22_13; + u32 paddr_apb_unqual_dec_19_13; + u32 paddr_apb_unqual_dec_12_1; + u32 paddr_apb_unqual; + u32 paddr_apb_phy; + + paddr_apb_qual = (paddr_apb_from_ctlr << 1); + paddr_apb_unqual_dec_22_13 = ((paddr_apb_qual & 0x7fe000) >> 13); + paddr_apb_unqual_dec_12_1 = ((paddr_apb_qual & 0x1ffe) >> 1); + + switch (paddr_apb_unqual_dec_22_13) { + case 0x000: + paddr_apb_unqual_dec_19_13 = 0x00; + break; + case 0x001: + paddr_apb_unqual_dec_19_13 = 0x01; + break; + case 0x002: + paddr_apb_unqual_dec_19_13 = 0x02; + break; + case 0x003: + paddr_apb_unqual_dec_19_13 = 0x03; + break; + case 0x004: + paddr_apb_unqual_dec_19_13 = 0x04; + break; + case 0x005: + paddr_apb_unqual_dec_19_13 = 0x05; + break; + case 0x006: + paddr_apb_unqual_dec_19_13 = 0x06; + break; + case 0x007: + paddr_apb_unqual_dec_19_13 = 0x07; + break; + case 0x008: + paddr_apb_unqual_dec_19_13 = 0x08; + break; + case 0x009: + paddr_apb_unqual_dec_19_13 = 0x09; + break; + case 0x00a: + paddr_apb_unqual_dec_19_13 = 0x0a; + break; + case 0x00b: + paddr_apb_unqual_dec_19_13 = 0x0b; + break; + case 0x100: + paddr_apb_unqual_dec_19_13 = 0x0c; + break; + case 0x101: + paddr_apb_unqual_dec_19_13 = 0x0d; + break; + case 0x102: + paddr_apb_unqual_dec_19_13 = 0x0e; + break; + case 0x103: + paddr_apb_unqual_dec_19_13 = 0x0f; + break; + case 0x104: + paddr_apb_unqual_dec_19_13 = 0x10; + break; + case 0x105: + paddr_apb_unqual_dec_19_13 = 0x11; + break; + case 0x106: + paddr_apb_unqual_dec_19_13 = 0x12; + break; + case 0x107: + paddr_apb_unqual_dec_19_13 = 0x13; + break; + case 0x108: + paddr_apb_unqual_dec_19_13 = 0x14; + break; + case 0x109: + paddr_apb_unqual_dec_19_13 = 0x15; + break; + case 0x10a: + paddr_apb_unqual_dec_19_13 = 0x16; + break; + case 0x10b: + paddr_apb_unqual_dec_19_13 = 0x17; + break; + case 0x200: + paddr_apb_unqual_dec_19_13 = 0x18; + break; + case 0x201: + paddr_apb_unqual_dec_19_13 = 0x19; + break; + case 0x202: + paddr_apb_unqual_dec_19_13 = 0x1a; + break; + case 0x203: + paddr_apb_unqual_dec_19_13 = 0x1b; + break; + case 0x204: + paddr_apb_unqual_dec_19_13 = 0x1c; + break; + case 0x205: + paddr_apb_unqual_dec_19_13 = 0x1d; + break; + case 0x206: + paddr_apb_unqual_dec_19_13 = 0x1e; + break; + case 0x207: + paddr_apb_unqual_dec_19_13 = 0x1f; + break; + case 0x208: + paddr_apb_unqual_dec_19_13 = 0x20; + break; + case 0x209: + paddr_apb_unqual_dec_19_13 = 0x21; + break; + case 0x20a: + paddr_apb_unqual_dec_19_13 = 0x22; + break; + case 0x20b: + paddr_apb_unqual_dec_19_13 = 0x23; + break; + case 0x300: + paddr_apb_unqual_dec_19_13 = 0x24; + break; + case 0x301: + paddr_apb_unqual_dec_19_13 = 0x25; + break; + case 0x302: + paddr_apb_unqual_dec_19_13 = 0x26; + break; + case 0x303: + paddr_apb_unqual_dec_19_13 = 0x27; + break; + case 0x304: + paddr_apb_unqual_dec_19_13 = 0x28; + break; + case 0x305: + paddr_apb_unqual_dec_19_13 = 0x29; + break; + case 0x306: + paddr_apb_unqual_dec_19_13 = 0x2a; + break; + case 0x307: + paddr_apb_unqual_dec_19_13 = 0x2b; + break; + case 0x308: + paddr_apb_unqual_dec_19_13 = 0x2c; + break; + case 0x309: + paddr_apb_unqual_dec_19_13 = 0x2d; + break; + case 0x30a: + paddr_apb_unqual_dec_19_13 = 0x2e; + break; + case 0x30b: + paddr_apb_unqual_dec_19_13 = 0x2f; + break; + case 0x010: + paddr_apb_unqual_dec_19_13 = 0x30; + break; + case 0x011: + paddr_apb_unqual_dec_19_13 = 0x31; + break; + case 0x012: + paddr_apb_unqual_dec_19_13 = 0x32; + break; + case 0x013: + paddr_apb_unqual_dec_19_13 = 0x33; + break; + case 0x014: + paddr_apb_unqual_dec_19_13 = 0x34; + break; + case 0x015: + paddr_apb_unqual_dec_19_13 = 0x35; + break; + case 0x016: + paddr_apb_unqual_dec_19_13 = 0x36; + break; + case 0x017: + paddr_apb_unqual_dec_19_13 = 0x37; + break; + case 0x018: + paddr_apb_unqual_dec_19_13 = 0x38; + break; + case 0x019: + paddr_apb_unqual_dec_19_13 = 0x39; + break; + case 0x110: + paddr_apb_unqual_dec_19_13 = 0x3a; + break; + case 0x111: + paddr_apb_unqual_dec_19_13 = 0x3b; + break; + case 0x112: + paddr_apb_unqual_dec_19_13 = 0x3c; + break; + case 0x113: + paddr_apb_unqual_dec_19_13 = 0x3d; + break; + case 0x114: + paddr_apb_unqual_dec_19_13 = 0x3e; + break; + case 0x115: + paddr_apb_unqual_dec_19_13 = 0x3f; + break; + case 0x116: + paddr_apb_unqual_dec_19_13 = 0x40; + break; + case 0x117: + paddr_apb_unqual_dec_19_13 = 0x41; + break; + case 0x118: + paddr_apb_unqual_dec_19_13 = 0x42; + break; + case 0x119: + paddr_apb_unqual_dec_19_13 = 0x43; + break; + case 0x210: + paddr_apb_unqual_dec_19_13 = 0x44; + break; + case 0x211: + paddr_apb_unqual_dec_19_13 = 0x45; + break; + case 0x212: + paddr_apb_unqual_dec_19_13 = 0x46; + break; + case 0x213: + paddr_apb_unqual_dec_19_13 = 0x47; + break; + case 0x214: + paddr_apb_unqual_dec_19_13 = 0x48; + break; + case 0x215: + paddr_apb_unqual_dec_19_13 = 0x49; + break; + case 0x216: + paddr_apb_unqual_dec_19_13 = 0x4a; + break; + case 0x217: + paddr_apb_unqual_dec_19_13 = 0x4b; + break; + case 0x218: + paddr_apb_unqual_dec_19_13 = 0x4c; + break; + case 0x219: + paddr_apb_unqual_dec_19_13 = 0x4d; + break; + case 0x310: + paddr_apb_unqual_dec_19_13 = 0x4e; + break; + case 0x311: + paddr_apb_unqual_dec_19_13 = 0x4f; + break; + case 0x312: + paddr_apb_unqual_dec_19_13 = 0x50; + break; + case 0x313: + paddr_apb_unqual_dec_19_13 = 0x51; + break; + case 0x314: + paddr_apb_unqual_dec_19_13 = 0x52; + break; + case 0x315: + paddr_apb_unqual_dec_19_13 = 0x53; + break; + case 0x316: + paddr_apb_unqual_dec_19_13 = 0x54; + break; + case 0x317: + paddr_apb_unqual_dec_19_13 = 0x55; + break; + case 0x318: + paddr_apb_unqual_dec_19_13 = 0x56; + break; + case 0x319: + paddr_apb_unqual_dec_19_13 = 0x57; + break; + case 0x020: + paddr_apb_unqual_dec_19_13 = 0x58; + break; + case 0x120: + paddr_apb_unqual_dec_19_13 = 0x59; + break; + case 0x220: + paddr_apb_unqual_dec_19_13 = 0x5a; + break; + case 0x320: + paddr_apb_unqual_dec_19_13 = 0x5b; + break; + case 0x040: + paddr_apb_unqual_dec_19_13 = 0x5c; + break; + case 0x140: + paddr_apb_unqual_dec_19_13 = 0x5d; + break; + case 0x240: + paddr_apb_unqual_dec_19_13 = 0x5e; + break; + case 0x340: + paddr_apb_unqual_dec_19_13 = 0x5f; + break; + case 0x050: + paddr_apb_unqual_dec_19_13 = 0x60; + break; + case 0x051: + paddr_apb_unqual_dec_19_13 = 0x61; + break; + case 0x052: + paddr_apb_unqual_dec_19_13 = 0x62; + break; + case 0x053: + paddr_apb_unqual_dec_19_13 = 0x63; + break; + case 0x054: + paddr_apb_unqual_dec_19_13 = 0x64; + break; + case 0x055: + paddr_apb_unqual_dec_19_13 = 0x65; + break; + case 0x056: + paddr_apb_unqual_dec_19_13 = 0x66; + break; + case 0x057: + paddr_apb_unqual_dec_19_13 = 0x67; + break; + case 0x070: + paddr_apb_unqual_dec_19_13 = 0x68; + break; + case 0x090: + paddr_apb_unqual_dec_19_13 = 0x69; + break; + case 0x190: + paddr_apb_unqual_dec_19_13 = 0x6a; + break; + case 0x290: + paddr_apb_unqual_dec_19_13 = 0x6b; + break; + case 0x390: + paddr_apb_unqual_dec_19_13 = 0x6c; + break; + case 0x0c0: + paddr_apb_unqual_dec_19_13 = 0x6d; + break; + case 0x0d0: + paddr_apb_unqual_dec_19_13 = 0x6e; + break; + default: + paddr_apb_unqual_dec_19_13 = 0x00; + break; + } + + paddr_apb_unqual = ((paddr_apb_unqual_dec_19_13 << 13) | (paddr_apb_unqual_dec_12_1 << 1)); + + paddr_apb_phy = (paddr_apb_unqual << 1); + + return paddr_apb_phy; +} diff --git a/drivers/ddr/imx/phy/Kconfig b/drivers/ddr/imx/phy/Kconfig new file mode 100644 index 00000000000..d3e589b23c4 --- /dev/null +++ b/drivers/ddr/imx/phy/Kconfig @@ -0,0 +1,4 @@ +config IMX_SNPS_DDR_PHY + bool "i.MX Snopsys DDR PHY" + help + Select the DDR PHY driver support on i.MX8M and i.MX9 SOC. diff --git a/drivers/ddr/imx/phy/Makefile b/drivers/ddr/imx/phy/Makefile new file mode 100644 index 00000000000..bb3d4ee5b74 --- /dev/null +++ b/drivers/ddr/imx/phy/Makefile @@ -0,0 +1,9 @@ +# +# Copyright 2018 NXP +# +# SPDX-License-Identifier: GPL-2.0+ +# + +ifdef CONFIG_SPL_BUILD +obj-$(CONFIG_IMX_SNPS_DDR_PHY) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o +endif diff --git a/drivers/ddr/imx/imx8m/ddrphy_csr.c b/drivers/ddr/imx/phy/ddrphy_csr.c index 67dd4e7059f..67dd4e7059f 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_csr.c +++ b/drivers/ddr/imx/phy/ddrphy_csr.c diff --git a/drivers/ddr/imx/imx8m/ddrphy_train.c b/drivers/ddr/imx/phy/ddrphy_train.c index 08fed6178f3..cd905f952c6 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_train.c +++ b/drivers/ddr/imx/phy/ddrphy_train.c @@ -7,7 +7,6 @@ #include <log.h> #include <linux/kernel.h> #include <asm/arch/ddr.h> -#include <asm/arch/lpddr4_define.h> #include <asm/arch/sys_proto.h> int ddr_cfg_phy(struct dram_timing_info *dram_timing) diff --git a/drivers/ddr/imx/phy/ddrphy_utils.c b/drivers/ddr/imx/phy/ddrphy_utils.c new file mode 100644 index 00000000000..b852c870f90 --- /dev/null +++ b/drivers/ddr/imx/phy/ddrphy_utils.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP + */ + +#include <common.h> +#include <errno.h> +#include <log.h> +#include <asm/io.h> +#include <asm/arch/ddr.h> +#include <asm/arch/clock.h> +#include <asm/arch/ddr.h> +#include <asm/arch/sys_proto.h> + +static inline void poll_pmu_message_ready(void) +{ + unsigned int reg; + + do { + reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0004)); + } while (reg & 0x1); +} + +static inline void ack_pmu_message_receive(void) +{ + unsigned int reg; + + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0031), 0x0); + + do { + reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0004)); + } while (!(reg & 0x1)); + + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0031), 0x1); +} + +static inline unsigned int get_mail(void) +{ + unsigned int reg; + + poll_pmu_message_ready(); + + reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0032)); + + ack_pmu_message_receive(); + + return reg; +} + +static inline unsigned int get_stream_message(void) +{ + unsigned int reg, reg2; + + poll_pmu_message_ready(); + + reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0032)); + + reg2 = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0034)); + + reg2 = (reg2 << 16) | reg; + + ack_pmu_message_receive(); + + return reg2; +} + +static inline void decode_major_message(unsigned int mail) +{ + debug("[PMU Major message = 0x%08x]\n", mail); +} + +static inline void decode_streaming_message(void) +{ + unsigned int string_index, arg __maybe_unused; + int i = 0; + + string_index = get_stream_message(); + debug("PMU String index = 0x%08x\n", string_index); + while (i < (string_index & 0xffff)) { + arg = get_stream_message(); + debug("arg[%d] = 0x%08x\n", i, arg); + i++; + } + + debug("\n"); +} + +int wait_ddrphy_training_complete(void) +{ + unsigned int mail; + + while (1) { + mail = get_mail(); + decode_major_message(mail); + if (mail == 0x08) { + decode_streaming_message(); + } else if (mail == 0x07) { + debug("Training PASS\n"); + return 0; + } else if (mail == 0xff) { + printf("Training FAILED\n"); + return -1; + } + } +} + +void ddrphy_init_set_dfi_clk(unsigned int drate) +{ + switch (drate) { + case 4000: + dram_pll_init(MHZ(1000)); + dram_disable_bypass(); + break; + case 3733: + dram_pll_init(MHZ(933)); + dram_disable_bypass(); + break; + case 3200: + dram_pll_init(MHZ(800)); + dram_disable_bypass(); + break; + case 3000: + dram_pll_init(MHZ(750)); + dram_disable_bypass(); + break; + case 2800: + dram_pll_init(MHZ(700)); + dram_disable_bypass(); + break; + case 2400: + dram_pll_init(MHZ(600)); + dram_disable_bypass(); + break; + case 1866: + dram_pll_init(MHZ(466)); + dram_disable_bypass(); + break; + case 1600: + dram_pll_init(MHZ(400)); + dram_disable_bypass(); + break; + case 1066: + dram_pll_init(MHZ(266)); + dram_disable_bypass(); + break; + case 667: + dram_pll_init(MHZ(167)); + dram_disable_bypass(); + break; + case 400: + dram_enable_bypass(MHZ(400)); + break; + case 333: + dram_enable_bypass(MHZ(333)); + break; + case 200: + dram_enable_bypass(MHZ(200)); + break; + case 100: + dram_enable_bypass(MHZ(100)); + break; + default: + return; + } +} + +void ddrphy_init_read_msg_block(enum fw_type type) +{ +} diff --git a/drivers/ddr/imx/imx8m/helper.c b/drivers/ddr/imx/phy/helper.c index f23904bf712..e9e0294f87d 100644 --- a/drivers/ddr/imx/imx8m/helper.c +++ b/drivers/ddr/imx/phy/helper.c @@ -4,6 +4,7 @@ */ #include <common.h> +#include <binman_sym.h> #include <log.h> #include <spl.h> #include <asm/global_data.h> @@ -12,7 +13,6 @@ #include <asm/io.h> #include <asm/arch/ddr.h> #include <asm/arch/ddr.h> -#include <asm/arch/lpddr4_define.h> #include <asm/sections.h> DECLARE_GLOBAL_DATA_PTR; @@ -25,15 +25,30 @@ DECLARE_GLOBAL_DATA_PTR; #define DMEM_OFFSET_ADDR 0x00054000 #define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0) +binman_sym_declare(ulong, ddr_1d_imem_fw, image_pos); +binman_sym_declare(ulong, ddr_1d_imem_fw, size); + +binman_sym_declare(ulong, ddr_1d_dmem_fw, image_pos); +binman_sym_declare(ulong, ddr_1d_dmem_fw, size); + +#if !IS_ENABLED(CONFIG_IMX8M_DDR3L) +binman_sym_declare(ulong, ddr_2d_imem_fw, image_pos); +binman_sym_declare(ulong, ddr_2d_imem_fw, size); + +binman_sym_declare(ulong, ddr_2d_dmem_fw, image_pos); +binman_sym_declare(ulong, ddr_2d_dmem_fw, size); +#endif + /* We need PHY iMEM PHY is 32KB padded */ void ddr_load_train_firmware(enum fw_type type) { u32 tmp32, i; u32 error = 0; unsigned long pr_to32, pr_from32; - unsigned long fw_offset = type ? IMEM_2D_OFFSET : 0; + uint32_t fw_offset = type ? IMEM_2D_OFFSET : 0; unsigned long imem_start = (unsigned long)&_end + fw_offset; unsigned long dmem_start; + unsigned long imem_len = IMEM_LEN, dmem_len = DMEM_LEN; #ifdef CONFIG_SPL_OF_CONTROL if (gd->fdt_blob && !fdt_check_header(gd->fdt_blob)) { @@ -43,46 +58,68 @@ void ddr_load_train_firmware(enum fw_type type) } #endif - dmem_start = imem_start + IMEM_LEN; + dmem_start = imem_start + imem_len; + + if (BINMAN_SYMS_OK) { + switch (type) { + case FW_1D_IMAGE: + imem_start = binman_sym(ulong, ddr_1d_imem_fw, image_pos); + imem_len = binman_sym(ulong, ddr_1d_imem_fw, size); + dmem_start = binman_sym(ulong, ddr_1d_dmem_fw, image_pos); + dmem_len = binman_sym(ulong, ddr_1d_dmem_fw, size); + break; + case FW_2D_IMAGE: +#if !IS_ENABLED(CONFIG_IMX8M_DDR3L) + imem_start = binman_sym(ulong, ddr_2d_imem_fw, image_pos); + imem_len = binman_sym(ulong, ddr_2d_imem_fw, size); + dmem_start = binman_sym(ulong, ddr_2d_dmem_fw, image_pos); + dmem_len = binman_sym(ulong, ddr_2d_dmem_fw, size); +#endif + break; + } + } pr_from32 = imem_start; - pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * IMEM_OFFSET_ADDR; - for (i = 0x0; i < IMEM_LEN; ) { + pr_to32 = IMEM_OFFSET_ADDR; + for (i = 0x0; i < imem_len; ) { tmp32 = readl(pr_from32); - writew(tmp32 & 0x0000ffff, pr_to32); - pr_to32 += 4; - writew((tmp32 >> 16) & 0x0000ffff, pr_to32); - pr_to32 += 4; + writew(tmp32 & 0x0000ffff, DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)); + pr_to32 += 1; + writew((tmp32 >> 16) & 0x0000ffff, + DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)); + pr_to32 += 1; pr_from32 += 4; i += 4; } pr_from32 = dmem_start; - pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * DMEM_OFFSET_ADDR; - for (i = 0x0; i < DMEM_LEN; ) { + pr_to32 = DMEM_OFFSET_ADDR; + for (i = 0x0; i < dmem_len; ) { tmp32 = readl(pr_from32); - writew(tmp32 & 0x0000ffff, pr_to32); - pr_to32 += 4; - writew((tmp32 >> 16) & 0x0000ffff, pr_to32); - pr_to32 += 4; + writew(tmp32 & 0x0000ffff, DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)); + pr_to32 += 1; + writew((tmp32 >> 16) & 0x0000ffff, + DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)); + pr_to32 += 1; pr_from32 += 4; i += 4; } debug("check ddr_pmu_train_imem code\n"); pr_from32 = imem_start; - pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * IMEM_OFFSET_ADDR; - for (i = 0x0; i < IMEM_LEN; ) { - tmp32 = (readw(pr_to32) & 0x0000ffff); - pr_to32 += 4; - tmp32 += ((readw(pr_to32) & 0x0000ffff) << 16); + pr_to32 = IMEM_OFFSET_ADDR; + for (i = 0x0; i < imem_len; ) { + tmp32 = (readw(DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)) & 0x0000ffff); + pr_to32 += 1; + tmp32 += ((readw(DDR_TRAIN_CODE_BASE_ADDR + + ddrphy_addr_remap(pr_to32)) & 0x0000ffff) << 16); if (tmp32 != readl(pr_from32)) { debug("%lx %lx\n", pr_from32, pr_to32); error++; } pr_from32 += 4; - pr_to32 += 4; + pr_to32 += 1; i += 4; } if (error) @@ -92,17 +129,18 @@ void ddr_load_train_firmware(enum fw_type type) debug("check ddr4_pmu_train_dmem code\n"); pr_from32 = dmem_start; - pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * DMEM_OFFSET_ADDR; - for (i = 0x0; i < DMEM_LEN;) { - tmp32 = (readw(pr_to32) & 0x0000ffff); - pr_to32 += 4; - tmp32 += ((readw(pr_to32) & 0x0000ffff) << 16); + pr_to32 = DMEM_OFFSET_ADDR; + for (i = 0x0; i < dmem_len;) { + tmp32 = (readw(DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)) & 0x0000ffff); + pr_to32 += 1; + tmp32 += ((readw(DDR_TRAIN_CODE_BASE_ADDR + + ddrphy_addr_remap(pr_to32)) & 0x0000ffff) << 16); if (tmp32 != readl(pr_from32)) { debug("%lx %lx\n", pr_from32, pr_to32); error++; } pr_from32 += 4; - pr_to32 += 4; + pr_to32 += 1; i += 4; } diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c index e98e1e56dbc..4654f9e0989 100644 --- a/drivers/gpio/pca953x_gpio.c +++ b/drivers/gpio/pca953x_gpio.c @@ -43,6 +43,8 @@ #define PCA_GPIO_MASK 0x00FF #define PCA_INT 0x0100 +#define PCA_PCAL BIT(9) +#define PCA_LATCH_INT (PCA_PCAL | PCA_INT) #define PCA953X_TYPE 0x1000 #define PCA957X_TYPE 0x2000 #define PCA_TYPE_MASK 0xF000 @@ -393,6 +395,8 @@ static const struct udevice_id pca953x_ids[] = { { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), }, { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), }, + { .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), }, + { .compatible = "maxim,max7310", .data = OF_953X(8, 0), }, { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), }, { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), }, diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index e839c08c191..a6da6e215de 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -350,6 +350,13 @@ config NPCM_OTP To compile this driver as a module, choose M here: the module will be called npcm_otp. +config IMX_SENTINEL + bool "Enable i.MX Sentinel MU driver and API" + depends on MISC && (ARCH_IMX9 || ARCH_IMX8ULP) + help + If you say Y here to enable Message Unit driver to work with + Sentinel core on some NXP i.MX processors. + config NUVOTON_NCT6102D bool "Enable Nuvoton NCT6102D Super I/O driver" help diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 022e54e0650..d494639cd95 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -49,7 +49,7 @@ obj-$(CONFIG_SANDBOX) += irq_sandbox.o irq_sandbox_test.o obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o obj-$(CONFIG_IMX8) += imx8/ -obj-$(CONFIG_IMX8ULP) += imx8ulp/ +obj-$(CONFIG_IMX_SENTINEL) += sentinel/ obj-$(CONFIG_LED_STATUS) += status_led.o obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o diff --git a/drivers/misc/imx8ulp/Makefile b/drivers/misc/sentinel/Makefile index 927cc552163..446154cb201 100644 --- a/drivers/misc/imx8ulp/Makefile +++ b/drivers/misc/sentinel/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-y += s400_api.o imx8ulp_mu.o +obj-y += s400_api.o s4mu.o obj-$(CONFIG_CMD_FUSE) += fuse.o diff --git a/drivers/misc/imx8ulp/fuse.c b/drivers/misc/sentinel/fuse.c index 090e702d9f7..e2b68757664 100644 --- a/drivers/misc/imx8ulp/fuse.c +++ b/drivers/misc/sentinel/fuse.c @@ -10,7 +10,7 @@ #include <asm/arch/sys_proto.h> #include <asm/arch/imx-regs.h> #include <env.h> -#include <asm/arch/s400_api.h> +#include <asm/mach-imx/s400_api.h> #include <asm/global_data.h> DECLARE_GLOBAL_DATA_PTR; @@ -31,6 +31,9 @@ struct s400_map_entry { u32 s400_index; }; +#if defined(CONFIG_IMX8ULP) +#define FSB_OTP_SHADOW 0x800 + struct fsb_map_entry fsb_mapping_table[] = { { 3, 8 }, { 4, 8 }, @@ -65,6 +68,53 @@ struct s400_map_entry s400_api_mapping_table[] = { { 23, 1, 4, 2 }, /* OTFAD */ { 25, 8 }, /* Test config2 */ }; +#elif defined(CONFIG_ARCH_IMX9) +#define FSB_OTP_SHADOW 0x8000 + +struct fsb_map_entry fsb_mapping_table[] = { + { 0, 8 }, + { 1, 8 }, + { 2, 8 }, + { 3, 8 }, + { 4, 8 }, + { 5, 8 }, + { 6, 4 }, + { -1, 260 }, + { 39, 8 }, + { 40, 8 }, + { 41, 8 }, + { 42, 8 }, + { 43, 8 }, + { 44, 8 }, + { 45, 8 }, + { 46, 8 }, + { 47, 8 }, + { 48, 8 }, + { 49, 8 }, + { 50, 8 }, + { 51, 8 }, + { 52, 8 }, + { 53, 8 }, + { 54, 8 }, + { 55, 8 }, + { 56, 8 }, + { 57, 8 }, + { 58, 8 }, + { 59, 8 }, + { 60, 8 }, + { 61, 8 }, + { 62, 8 }, + { 63, 8 }, +}; + +struct s400_map_entry s400_api_mapping_table[] = { + { 7, 1, 7, 63 }, + { 16, 8, }, + { 17, 8, }, + { 22, 1, 6 }, + { 23, 1, 4 }, +}; +#endif static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy) { @@ -74,7 +124,8 @@ static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy) /* map the fuse from ocotp fuse map to FSB*/ for (i = 0; i < size; i++) { if (fsb_mapping_table[i].fuse_bank != -1 && - fsb_mapping_table[i].fuse_bank == bank) { + fsb_mapping_table[i].fuse_bank == bank && + fsb_mapping_table[i].fuse_words > word) { break; } @@ -118,6 +169,7 @@ static s32 map_s400_fuse_index(u32 bank, u32 word) return s400_api_mapping_table[i].fuse_bank * 8 + word; } +#if defined(CONFIG_IMX8ULP) int fuse_sense(u32 bank, u32 word, u32 *val) { s32 word_index; @@ -128,7 +180,7 @@ int fuse_sense(u32 bank, u32 word, u32 *val) word_index = map_fsb_fuse_index(bank, word, &redundancy); if (word_index >= 0) { - *val = readl((ulong)FSB_BASE_ADDR + 0x800 + (word_index << 2)); + *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2)); if (redundancy) *val = (*val >> ((word % 2) * 16)) & 0xFFFF; @@ -170,6 +222,44 @@ int fuse_sense(u32 bank, u32 word, u32 *val) return -ENOENT; } +#elif defined(CONFIG_ARCH_IMX9) +int fuse_sense(u32 bank, u32 word, u32 *val) +{ + s32 word_index; + bool redundancy; + + if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val) + return -EINVAL; + + word_index = map_fsb_fuse_index(bank, word, &redundancy); + if (word_index >= 0) { + *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2)); + if (redundancy) + *val = (*val >> ((word % 2) * 16)) & 0xFFFF; + + return 0; + } + + word_index = map_s400_fuse_index(bank, word); + if (word_index >= 0) { + u32 data; + u32 res, size = 1; + int ret; + + ret = ahab_read_common_fuse(word_index, &data, size, &res); + if (ret) { + printf("ahab read fuse failed %d, 0x%x\n", ret, res); + return ret; + } + + *val = data; + + return 0; + } + + return -ENOENT; +} +#endif int fuse_read(u32 bank, u32 word, u32 *val) { diff --git a/drivers/misc/imx8ulp/s400_api.c b/drivers/misc/sentinel/s400_api.c index 87f5880ccb8..65032f77362 100644 --- a/drivers/misc/imx8ulp/s400_api.c +++ b/drivers/misc/sentinel/s400_api.c @@ -9,16 +9,16 @@ #include <malloc.h> #include <asm/io.h> #include <dm.h> -#include <asm/arch/s400_api.h> +#include <asm/mach-imx/s400_api.h> #include <misc.h> DECLARE_GLOBAL_DATA_PTR; -int ahab_release_rdc(u8 core_id, bool xrdc, u32 *response) +int ahab_release_rdc(u8 core_id, u8 xrdc, u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -30,10 +30,23 @@ int ahab_release_rdc(u8 core_id, bool xrdc, u32 *response) msg.tag = AHAB_CMD_TAG; msg.size = 2; msg.command = AHAB_RELEASE_RDC_REQ_CID; - if (xrdc) - msg.data[0] = (0x78 << 8) | core_id; - else + switch (xrdc) { + case 0: msg.data[0] = (0x74 << 8) | core_id; + break; + case 1: + msg.data[0] = (0x78 << 8) | core_id; + break; + case 2: + msg.data[0] = (0x82 << 8) | core_id; + break; + case 3: + msg.data[0] = (0x86 << 8) | core_id; + break; + default: + printf("Error: wrong xrdc index %u\n", xrdc); + return -EINVAL; + } ret = misc_call(dev, false, &msg, size, &msg, size); if (ret) @@ -49,8 +62,8 @@ int ahab_release_rdc(u8 core_id, bool xrdc, u32 *response) int ahab_auth_oem_ctnr(ulong ctnr_addr, u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -79,8 +92,8 @@ int ahab_auth_oem_ctnr(ulong ctnr_addr, u32 *response) int ahab_release_container(u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -107,8 +120,8 @@ int ahab_release_container(u32 *response) int ahab_verify_image(u32 img_id, u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -136,8 +149,8 @@ int ahab_verify_image(u32 img_id, u32 *response) int ahab_forward_lifecycle(u16 life_cycle, u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -165,8 +178,8 @@ int ahab_forward_lifecycle(u16 life_cycle, u32 *response) int ahab_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -213,8 +226,8 @@ int ahab_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *respo int ahab_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -246,8 +259,8 @@ int ahab_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response) int ahab_release_caam(u32 core_did, u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -275,8 +288,8 @@ int ahab_release_caam(u32 core_did, u32 *response) int ahab_get_fw_version(u32 *fw_version, u32 *sha1, u32 *response) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret; if (!dev) { @@ -316,8 +329,8 @@ int ahab_get_fw_version(u32 *fw_version, u32 *sha1, u32 *response) int ahab_dump_buffer(u32 *buffer, u32 buffer_length) { struct udevice *dev = gd->arch.s400_dev; - int size = sizeof(struct imx8ulp_s400_msg); - struct imx8ulp_s400_msg msg; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; int ret, i = 0; if (!dev) { @@ -346,3 +359,89 @@ int ahab_dump_buffer(u32 *buffer, u32 buffer_length) return i; } + +int ahab_get_info(struct sentinel_get_info_data *info, u32 *response) +{ + struct udevice *dev = gd->arch.s400_dev; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; + int ret; + + if (!dev) { + printf("s400 dev is not initialized\n"); + return -ENODEV; + } + + msg.version = AHAB_VERSION; + msg.tag = AHAB_CMD_TAG; + msg.size = 4; + msg.command = AHAB_GET_INFO_CID; + msg.data[0] = upper_32_bits((ulong)info); + msg.data[1] = lower_32_bits((ulong)info); + msg.data[2] = sizeof(struct sentinel_get_info_data); + + ret = misc_call(dev, false, &msg, size, &msg, size); + if (ret) + printf("Error: %s: ret %d, response 0x%x\n", + __func__, ret, msg.data[0]); + + if (response) + *response = msg.data[0]; + + return ret; +} + +int ahab_get_fw_status(u32 *status, u32 *response) +{ + struct udevice *dev = gd->arch.s400_dev; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; + int ret; + + if (!dev) { + printf("s400 dev is not initialized\n"); + return -ENODEV; + } + + msg.version = AHAB_VERSION; + msg.tag = AHAB_CMD_TAG; + msg.size = 1; + msg.command = AHAB_GET_FW_STATUS_CID; + + ret = misc_call(dev, false, &msg, size, &msg, size); + if (ret) + printf("Error: %s: ret %d, response 0x%x\n", + __func__, ret, msg.data[0]); + + if (response) + *response = msg.data[0]; + + *status = msg.data[1] & 0xF; + + return ret; +} + +int ahab_release_m33_trout(void) +{ + struct udevice *dev = gd->arch.s400_dev; + int size = sizeof(struct sentinel_msg); + struct sentinel_msg msg; + int ret; + + if (!dev) { + printf("s400 dev is not initialized\n"); + return -ENODEV; + } + + msg.version = AHAB_VERSION; + msg.tag = AHAB_CMD_TAG; + msg.size = 1; + msg.command = 0xd3; + + ret = misc_call(dev, false, &msg, size, &msg, size); + if (ret) + printf("Error: %s: ret %d, response 0x%x\n", + __func__, ret, msg.data[0]); + + return ret; +} diff --git a/drivers/misc/imx8ulp/imx8ulp_mu.c b/drivers/misc/sentinel/s4mu.c index 333ebdf5765..794fc40c620 100644 --- a/drivers/misc/imx8ulp/imx8ulp_mu.c +++ b/drivers/misc/sentinel/s4mu.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2020 NXP + * Copyright 2020-2022 NXP */ #include <common.h> @@ -9,7 +9,7 @@ #include <dm/lists.h> #include <dm/root.h> #include <dm/device-internal.h> -#include <asm/arch/s400_api.h> +#include <asm/mach-imx/s400_api.h> #include <asm/arch/imx-regs.h> #include <linux/iopoll.h> #include <misc.h> @@ -85,7 +85,7 @@ int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg) static int imx8ulp_mu_read(struct mu_type *base, void *data) { - struct imx8ulp_s400_msg *msg = (struct imx8ulp_s400_msg *)data; + struct sentinel_msg *msg = (struct sentinel_msg *)data; int ret; u8 count = 0; @@ -118,7 +118,7 @@ static int imx8ulp_mu_read(struct mu_type *base, void *data) static int imx8ulp_mu_write(struct mu_type *base, void *data) { - struct imx8ulp_s400_msg *msg = (struct imx8ulp_s400_msg *)data; + struct sentinel_msg *msg = (struct sentinel_msg *)data; int ret; u8 count = 0; @@ -171,7 +171,7 @@ static int imx8ulp_mu_call(struct udevice *dev, int no_resp, void *tx_msg, return ret; } - result = ((struct imx8ulp_s400_msg *)rx_msg)->data[0]; + result = ((struct sentinel_msg *)rx_msg)->data[0]; if ((result & 0xff) == 0xd6) return 0; @@ -219,6 +219,7 @@ static struct misc_ops imx8ulp_mu_ops = { static const struct udevice_id imx8ulp_mu_ids[] = { { .compatible = "fsl,imx8ulp-mu" }, + { .compatible = "fsl,imx93-mu-s4" }, { } }; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 6e9fcf57510..95d63b62260 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -854,7 +854,7 @@ config FSL_ESDHC_IMX config FSL_USDHC bool "Freescale/NXP i.MX uSDHC controller support" - depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMX8ULP || IMXRT + depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMX8ULP || IMX9 || IMXRT select FSL_ESDHC_IMX help This enables the Ultra Secured Digital Host Controller enhancements diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b671e72580e..5d90a924aab 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -349,7 +349,7 @@ config FEC_MXC_MDIO_BASE config FEC_MXC bool "FEC Ethernet controller" - depends on MX28 || MX5 || MX6 || MX7 || IMX8 || IMX8M || IMX8ULP || VF610 + depends on MX28 || MX5 || MX6 || MX7 || IMX8 || IMX8M || IMX8ULP || IMX93 || VF610 help This driver supports the 10/100 Fast Ethernet controller for NXP i.MX processors. diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 69fb3bbbf7c..9536af11946 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o +obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o obj-$(CONFIG_E1000) += e1000.o obj-$(CONFIG_E1000_SPI) += e1000_spi.o obj-$(CONFIG_EEPRO100) += eepro100.o diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 9d255cf95ff..c1f2391d635 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -51,275 +51,9 @@ #include <asm/arch/clock.h> #include <asm/mach-imx/sys_proto.h> #endif -#include <linux/bitops.h> #include <linux/delay.h> -/* Core registers */ - -#define EQOS_MAC_REGS_BASE 0x000 -struct eqos_mac_regs { - uint32_t configuration; /* 0x000 */ - uint32_t unused_004[(0x070 - 0x004) / 4]; /* 0x004 */ - uint32_t q0_tx_flow_ctrl; /* 0x070 */ - uint32_t unused_070[(0x090 - 0x074) / 4]; /* 0x074 */ - uint32_t rx_flow_ctrl; /* 0x090 */ - uint32_t unused_094; /* 0x094 */ - uint32_t txq_prty_map0; /* 0x098 */ - uint32_t unused_09c; /* 0x09c */ - uint32_t rxq_ctrl0; /* 0x0a0 */ - uint32_t unused_0a4; /* 0x0a4 */ - uint32_t rxq_ctrl2; /* 0x0a8 */ - uint32_t unused_0ac[(0x0dc - 0x0ac) / 4]; /* 0x0ac */ - uint32_t us_tic_counter; /* 0x0dc */ - uint32_t unused_0e0[(0x11c - 0x0e0) / 4]; /* 0x0e0 */ - uint32_t hw_feature0; /* 0x11c */ - uint32_t hw_feature1; /* 0x120 */ - uint32_t hw_feature2; /* 0x124 */ - uint32_t unused_128[(0x200 - 0x128) / 4]; /* 0x128 */ - uint32_t mdio_address; /* 0x200 */ - uint32_t mdio_data; /* 0x204 */ - uint32_t unused_208[(0x300 - 0x208) / 4]; /* 0x208 */ - uint32_t address0_high; /* 0x300 */ - uint32_t address0_low; /* 0x304 */ -}; - -#define EQOS_MAC_CONFIGURATION_GPSLCE BIT(23) -#define EQOS_MAC_CONFIGURATION_CST BIT(21) -#define EQOS_MAC_CONFIGURATION_ACS BIT(20) -#define EQOS_MAC_CONFIGURATION_WD BIT(19) -#define EQOS_MAC_CONFIGURATION_JD BIT(17) -#define EQOS_MAC_CONFIGURATION_JE BIT(16) -#define EQOS_MAC_CONFIGURATION_PS BIT(15) -#define EQOS_MAC_CONFIGURATION_FES BIT(14) -#define EQOS_MAC_CONFIGURATION_DM BIT(13) -#define EQOS_MAC_CONFIGURATION_LM BIT(12) -#define EQOS_MAC_CONFIGURATION_TE BIT(1) -#define EQOS_MAC_CONFIGURATION_RE BIT(0) - -#define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT 16 -#define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_MASK 0xffff -#define EQOS_MAC_Q0_TX_FLOW_CTRL_TFE BIT(1) - -#define EQOS_MAC_RX_FLOW_CTRL_RFE BIT(0) - -#define EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_SHIFT 0 -#define EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK 0xff - -#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT 0 -#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK 3 -#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_NOT_ENABLED 0 -#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB 2 -#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV 1 - -#define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT 0 -#define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK 0xff - -#define EQOS_MAC_HW_FEATURE0_MMCSEL_SHIFT 8 -#define EQOS_MAC_HW_FEATURE0_HDSEL_SHIFT 2 -#define EQOS_MAC_HW_FEATURE0_GMIISEL_SHIFT 1 -#define EQOS_MAC_HW_FEATURE0_MIISEL_SHIFT 0 - -#define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT 6 -#define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK 0x1f -#define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT 0 -#define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK 0x1f - -#define EQOS_MAC_HW_FEATURE3_ASP_SHIFT 28 -#define EQOS_MAC_HW_FEATURE3_ASP_MASK 0x3 - -#define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT 21 -#define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 -#define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 -#define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 -#define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5 -#define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) -#define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT 2 -#define EQOS_MAC_MDIO_ADDRESS_GOC_READ 3 -#define EQOS_MAC_MDIO_ADDRESS_GOC_WRITE 1 -#define EQOS_MAC_MDIO_ADDRESS_C45E BIT(1) -#define EQOS_MAC_MDIO_ADDRESS_GB BIT(0) - -#define EQOS_MAC_MDIO_DATA_GD_MASK 0xffff - -#define EQOS_MTL_REGS_BASE 0xd00 -struct eqos_mtl_regs { - uint32_t txq0_operation_mode; /* 0xd00 */ - uint32_t unused_d04; /* 0xd04 */ - uint32_t txq0_debug; /* 0xd08 */ - uint32_t unused_d0c[(0xd18 - 0xd0c) / 4]; /* 0xd0c */ - uint32_t txq0_quantum_weight; /* 0xd18 */ - uint32_t unused_d1c[(0xd30 - 0xd1c) / 4]; /* 0xd1c */ - uint32_t rxq0_operation_mode; /* 0xd30 */ - uint32_t unused_d34; /* 0xd34 */ - uint32_t rxq0_debug; /* 0xd38 */ -}; - -#define EQOS_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT 16 -#define EQOS_MTL_TXQ0_OPERATION_MODE_TQS_MASK 0x1ff -#define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT 2 -#define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_MASK 3 -#define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_ENABLED 2 -#define EQOS_MTL_TXQ0_OPERATION_MODE_TSF BIT(1) -#define EQOS_MTL_TXQ0_OPERATION_MODE_FTQ BIT(0) - -#define EQOS_MTL_TXQ0_DEBUG_TXQSTS BIT(4) -#define EQOS_MTL_TXQ0_DEBUG_TRCSTS_SHIFT 1 -#define EQOS_MTL_TXQ0_DEBUG_TRCSTS_MASK 3 - -#define EQOS_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT 20 -#define EQOS_MTL_RXQ0_OPERATION_MODE_RQS_MASK 0x3ff -#define EQOS_MTL_RXQ0_OPERATION_MODE_RFD_SHIFT 14 -#define EQOS_MTL_RXQ0_OPERATION_MODE_RFD_MASK 0x3f -#define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_SHIFT 8 -#define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK 0x3f -#define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC BIT(7) -#define EQOS_MTL_RXQ0_OPERATION_MODE_RSF BIT(5) - -#define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT 16 -#define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK 0x7fff -#define EQOS_MTL_RXQ0_DEBUG_RXQSTS_SHIFT 4 -#define EQOS_MTL_RXQ0_DEBUG_RXQSTS_MASK 3 - -#define EQOS_DMA_REGS_BASE 0x1000 -struct eqos_dma_regs { - uint32_t mode; /* 0x1000 */ - uint32_t sysbus_mode; /* 0x1004 */ - uint32_t unused_1008[(0x1100 - 0x1008) / 4]; /* 0x1008 */ - uint32_t ch0_control; /* 0x1100 */ - uint32_t ch0_tx_control; /* 0x1104 */ - uint32_t ch0_rx_control; /* 0x1108 */ - uint32_t unused_110c; /* 0x110c */ - uint32_t ch0_txdesc_list_haddress; /* 0x1110 */ - uint32_t ch0_txdesc_list_address; /* 0x1114 */ - uint32_t ch0_rxdesc_list_haddress; /* 0x1118 */ - uint32_t ch0_rxdesc_list_address; /* 0x111c */ - uint32_t ch0_txdesc_tail_pointer; /* 0x1120 */ - uint32_t unused_1124; /* 0x1124 */ - uint32_t ch0_rxdesc_tail_pointer; /* 0x1128 */ - uint32_t ch0_txdesc_ring_length; /* 0x112c */ - uint32_t ch0_rxdesc_ring_length; /* 0x1130 */ -}; - -#define EQOS_DMA_MODE_SWR BIT(0) - -#define EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT 16 -#define EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK 0xf -#define EQOS_DMA_SYSBUS_MODE_EAME BIT(11) -#define EQOS_DMA_SYSBUS_MODE_BLEN16 BIT(3) -#define EQOS_DMA_SYSBUS_MODE_BLEN8 BIT(2) -#define EQOS_DMA_SYSBUS_MODE_BLEN4 BIT(1) - -#define EQOS_DMA_CH0_CONTROL_DSL_SHIFT 18 -#define EQOS_DMA_CH0_CONTROL_PBLX8 BIT(16) - -#define EQOS_DMA_CH0_TX_CONTROL_TXPBL_SHIFT 16 -#define EQOS_DMA_CH0_TX_CONTROL_TXPBL_MASK 0x3f -#define EQOS_DMA_CH0_TX_CONTROL_OSP BIT(4) -#define EQOS_DMA_CH0_TX_CONTROL_ST BIT(0) - -#define EQOS_DMA_CH0_RX_CONTROL_RXPBL_SHIFT 16 -#define EQOS_DMA_CH0_RX_CONTROL_RXPBL_MASK 0x3f -#define EQOS_DMA_CH0_RX_CONTROL_RBSZ_SHIFT 1 -#define EQOS_DMA_CH0_RX_CONTROL_RBSZ_MASK 0x3fff -#define EQOS_DMA_CH0_RX_CONTROL_SR BIT(0) - -/* These registers are Tegra186-specific */ -#define EQOS_TEGRA186_REGS_BASE 0x8800 -struct eqos_tegra186_regs { - uint32_t sdmemcomppadctrl; /* 0x8800 */ - uint32_t auto_cal_config; /* 0x8804 */ - uint32_t unused_8808; /* 0x8808 */ - uint32_t auto_cal_status; /* 0x880c */ -}; - -#define EQOS_SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31) - -#define EQOS_AUTO_CAL_CONFIG_START BIT(31) -#define EQOS_AUTO_CAL_CONFIG_ENABLE BIT(29) - -#define EQOS_AUTO_CAL_STATUS_ACTIVE BIT(31) - -/* Descriptors */ -#define EQOS_DESCRIPTORS_TX 4 -#define EQOS_DESCRIPTORS_RX 4 -#define EQOS_DESCRIPTORS_NUM (EQOS_DESCRIPTORS_TX + EQOS_DESCRIPTORS_RX) -#define EQOS_BUFFER_ALIGN ARCH_DMA_MINALIGN -#define EQOS_MAX_PACKET_SIZE ALIGN(1568, ARCH_DMA_MINALIGN) -#define EQOS_RX_BUFFER_SIZE (EQOS_DESCRIPTORS_RX * EQOS_MAX_PACKET_SIZE) - -struct eqos_desc { - u32 des0; - u32 des1; - u32 des2; - u32 des3; -}; - -#define EQOS_DESC3_OWN BIT(31) -#define EQOS_DESC3_FD BIT(29) -#define EQOS_DESC3_LD BIT(28) -#define EQOS_DESC3_BUF1V BIT(24) - -#define EQOS_AXI_WIDTH_32 4 -#define EQOS_AXI_WIDTH_64 8 -#define EQOS_AXI_WIDTH_128 16 - -struct eqos_config { - bool reg_access_always_ok; - int mdio_wait; - int swr_wait; - int config_mac; - int config_mac_mdio; - unsigned int axi_bus_width; - phy_interface_t (*interface)(const struct udevice *dev); - struct eqos_ops *ops; -}; - -struct eqos_ops { - void (*eqos_inval_desc)(void *desc); - void (*eqos_flush_desc)(void *desc); - void (*eqos_inval_buffer)(void *buf, size_t size); - void (*eqos_flush_buffer)(void *buf, size_t size); - int (*eqos_probe_resources)(struct udevice *dev); - int (*eqos_remove_resources)(struct udevice *dev); - int (*eqos_stop_resets)(struct udevice *dev); - int (*eqos_start_resets)(struct udevice *dev); - int (*eqos_stop_clks)(struct udevice *dev); - int (*eqos_start_clks)(struct udevice *dev); - int (*eqos_calibrate_pads)(struct udevice *dev); - int (*eqos_disable_calibration)(struct udevice *dev); - int (*eqos_set_tx_clk_speed)(struct udevice *dev); - ulong (*eqos_get_tick_clk_rate)(struct udevice *dev); -}; - -struct eqos_priv { - struct udevice *dev; - const struct eqos_config *config; - fdt_addr_t regs; - struct eqos_mac_regs *mac_regs; - struct eqos_mtl_regs *mtl_regs; - struct eqos_dma_regs *dma_regs; - struct eqos_tegra186_regs *tegra186_regs; - struct reset_ctl reset_ctl; - struct gpio_desc phy_reset_gpio; - struct clk clk_master_bus; - struct clk clk_rx; - struct clk clk_ptp_ref; - struct clk clk_tx; - struct clk clk_ck; - struct clk clk_slave_bus; - struct mii_dev *mii; - struct phy_device *phy; - u32 max_speed; - void *descs; - int tx_desc_idx, rx_desc_idx; - unsigned int desc_size; - void *tx_dma_buf; - void *rx_dma_buf; - void *rx_pkt; - bool started; - bool reg_access_ok; - bool clk_ck_enabled; -}; +#include "dwc_eth_qos.h" /* * TX and RX descriptors are 16 bytes. This causes problems with the cache @@ -359,7 +93,7 @@ static struct eqos_desc *eqos_get_desc(struct eqos_priv *eqos, ((rx ? EQOS_DESCRIPTORS_TX : 0) + num) * eqos->desc_size; } -static void eqos_inval_desc_generic(void *desc) +void eqos_inval_desc_generic(void *desc) { unsigned long start = (unsigned long)desc; unsigned long end = ALIGN(start + sizeof(struct eqos_desc), @@ -368,7 +102,7 @@ static void eqos_inval_desc_generic(void *desc) invalidate_dcache_range(start, end); } -static void eqos_flush_desc_generic(void *desc) +void eqos_flush_desc_generic(void *desc) { unsigned long start = (unsigned long)desc; unsigned long end = ALIGN(start + sizeof(struct eqos_desc), @@ -377,7 +111,7 @@ static void eqos_flush_desc_generic(void *desc) flush_dcache_range(start, end); } -static void eqos_inval_buffer_tegra186(void *buf, size_t size) +void eqos_inval_buffer_tegra186(void *buf, size_t size) { unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); @@ -385,7 +119,7 @@ static void eqos_inval_buffer_tegra186(void *buf, size_t size) invalidate_dcache_range(start, end); } -static void eqos_inval_buffer_generic(void *buf, size_t size) +void eqos_inval_buffer_generic(void *buf, size_t size) { unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); unsigned long end = roundup((unsigned long)buf + size, @@ -399,7 +133,7 @@ static void eqos_flush_buffer_tegra186(void *buf, size_t size) flush_cache((unsigned long)buf, size); } -static void eqos_flush_buffer_generic(void *buf, size_t size) +void eqos_flush_buffer_generic(void *buf, size_t size) { unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); unsigned long end = roundup((unsigned long)buf + size, @@ -772,20 +506,6 @@ static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev) #endif } -__weak u32 imx_get_eqos_csr_clk(void) -{ - return 100 * 1000000; -} -__weak int imx_eqos_txclk_set_rate(unsigned long rate) -{ - return 0; -} - -static ulong eqos_get_tick_clk_rate_imx(struct udevice *dev) -{ - return imx_get_eqos_csr_clk(); -} - static int eqos_set_full_duplex(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -882,38 +602,6 @@ static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) return 0; } -static int eqos_set_tx_clk_speed_imx(struct udevice *dev) -{ - struct eqos_priv *eqos = dev_get_priv(dev); - ulong rate; - int ret; - - debug("%s(dev=%p):\n", __func__, dev); - - switch (eqos->phy->speed) { - case SPEED_1000: - rate = 125 * 1000 * 1000; - break; - case SPEED_100: - rate = 25 * 1000 * 1000; - break; - case SPEED_10: - rate = 2.5 * 1000 * 1000; - break; - default: - pr_err("invalid speed %d", eqos->phy->speed); - return -EINVAL; - } - - ret = imx_eqos_txclk_set_rate(rate); - if (ret < 0) { - pr_err("imx (tx_clk, %lu) failed: %d", rate, ret); - return ret; - } - - return 0; -} - static int eqos_adjust_link(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1024,13 +712,34 @@ static int eqos_write_hwaddr(struct udevice *dev) static int eqos_read_rom_hwaddr(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + ret = eqos->config->ops->eqos_get_enetaddr(dev); + if (ret < 0) + return ret; -#ifdef CONFIG_ARCH_IMX8M - imx_get_mac_from_fuse(dev_seq(dev), pdata->enetaddr); -#endif return !is_valid_ethaddr(pdata->enetaddr); } +static int eqos_get_phy_addr(struct eqos_priv *priv, struct udevice *dev) +{ + struct ofnode_phandle_args phandle_args; + int reg; + + if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, + &phandle_args)) { + debug("Failed to find phy-handle"); + return -ENODEV; + } + + priv->phy_of_node = phandle_args.node; + + reg = ofnode_read_u32_default(phandle_args.node, "reg", 0); + + return reg; +} + static int eqos_start(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1079,9 +788,7 @@ static int eqos_start(struct udevice *dev) */ if (!eqos->phy) { int addr = -1; -#ifdef CONFIG_DM_ETH_PHY - addr = eth_phy_get_addr(dev); -#endif + addr = eqos_get_phy_addr(eqos, dev); #ifdef DWC_NET_PHYADDR addr = DWC_NET_PHYADDR; #endif @@ -1100,6 +807,7 @@ static int eqos_start(struct udevice *dev) } } + eqos->phy->node = eqos->phy_of_node; ret = phy_config(eqos->phy); if (ret < 0) { pr_err("phy_config() failed: %d", ret); @@ -1734,24 +1442,6 @@ static phy_interface_t eqos_get_interface_tegra186(const struct udevice *dev) return PHY_INTERFACE_MODE_MII; } -static int eqos_probe_resources_imx(struct udevice *dev) -{ - struct eqos_priv *eqos = dev_get_priv(dev); - phy_interface_t interface; - - debug("%s(dev=%p):\n", __func__, dev); - - interface = eqos->config->interface(dev); - - if (interface == PHY_INTERFACE_MODE_NA) { - pr_err("Invalid PHY interface\n"); - return -EINVAL; - } - - debug("%s: OK\n", __func__); - return 0; -} - static int eqos_remove_resources_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1774,11 +1464,11 @@ static int eqos_remove_resources_tegra186(struct udevice *dev) static int eqos_remove_resources_stm32(struct udevice *dev) { -#ifdef CONFIG_CLK struct eqos_priv *eqos = dev_get_priv(dev); debug("%s(dev=%p):\n", __func__, dev); +#ifdef CONFIG_CLK clk_free(&eqos->clk_tx); clk_free(&eqos->clk_rx); clk_free(&eqos->clk_master_bus); @@ -1890,7 +1580,7 @@ static int eqos_remove(struct udevice *dev) return 0; } -static int eqos_null_ops(struct udevice *dev) +int eqos_null_ops(struct udevice *dev) { return 0; } @@ -1961,34 +1651,6 @@ static const struct eqos_config __maybe_unused eqos_stm32_config = { .ops = &eqos_stm32_ops }; -static struct eqos_ops eqos_imx_ops = { - .eqos_inval_desc = eqos_inval_desc_generic, - .eqos_flush_desc = eqos_flush_desc_generic, - .eqos_inval_buffer = eqos_inval_buffer_generic, - .eqos_flush_buffer = eqos_flush_buffer_generic, - .eqos_probe_resources = eqos_probe_resources_imx, - .eqos_remove_resources = eqos_null_ops, - .eqos_stop_resets = eqos_null_ops, - .eqos_start_resets = eqos_null_ops, - .eqos_stop_clks = eqos_null_ops, - .eqos_start_clks = eqos_null_ops, - .eqos_calibrate_pads = eqos_null_ops, - .eqos_disable_calibration = eqos_null_ops, - .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_imx, - .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_imx -}; - -struct eqos_config __maybe_unused eqos_imx_config = { - .reg_access_always_ok = false, - .mdio_wait = 10, - .swr_wait = 50, - .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, - .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, - .axi_bus_width = EQOS_AXI_WIDTH_64, - .interface = dev_read_phy_mode, - .ops = &eqos_imx_ops -}; - static const struct udevice_id eqos_ids[] = { #if IS_ENABLED(CONFIG_DWC_ETH_QOS_TEGRA186) { diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h new file mode 100644 index 00000000000..b35e7742634 --- /dev/null +++ b/drivers/net/dwc_eth_qos.h @@ -0,0 +1,284 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2022 NXP + */ + +#include <phy_interface.h> +#include <linux/bitops.h> + +/* Core registers */ + +#define EQOS_MAC_REGS_BASE 0x000 +struct eqos_mac_regs { + u32 configuration; /* 0x000 */ + u32 unused_004[(0x070 - 0x004) / 4]; /* 0x004 */ + u32 q0_tx_flow_ctrl; /* 0x070 */ + u32 unused_070[(0x090 - 0x074) / 4]; /* 0x074 */ + u32 rx_flow_ctrl; /* 0x090 */ + u32 unused_094; /* 0x094 */ + u32 txq_prty_map0; /* 0x098 */ + u32 unused_09c; /* 0x09c */ + u32 rxq_ctrl0; /* 0x0a0 */ + u32 unused_0a4; /* 0x0a4 */ + u32 rxq_ctrl2; /* 0x0a8 */ + u32 unused_0ac[(0x0dc - 0x0ac) / 4]; /* 0x0ac */ + u32 us_tic_counter; /* 0x0dc */ + u32 unused_0e0[(0x11c - 0x0e0) / 4]; /* 0x0e0 */ + u32 hw_feature0; /* 0x11c */ + u32 hw_feature1; /* 0x120 */ + u32 hw_feature2; /* 0x124 */ + u32 unused_128[(0x200 - 0x128) / 4]; /* 0x128 */ + u32 mdio_address; /* 0x200 */ + u32 mdio_data; /* 0x204 */ + u32 unused_208[(0x300 - 0x208) / 4]; /* 0x208 */ + u32 address0_high; /* 0x300 */ + u32 address0_low; /* 0x304 */ +}; + +#define EQOS_MAC_CONFIGURATION_GPSLCE BIT(23) +#define EQOS_MAC_CONFIGURATION_CST BIT(21) +#define EQOS_MAC_CONFIGURATION_ACS BIT(20) +#define EQOS_MAC_CONFIGURATION_WD BIT(19) +#define EQOS_MAC_CONFIGURATION_JD BIT(17) +#define EQOS_MAC_CONFIGURATION_JE BIT(16) +#define EQOS_MAC_CONFIGURATION_PS BIT(15) +#define EQOS_MAC_CONFIGURATION_FES BIT(14) +#define EQOS_MAC_CONFIGURATION_DM BIT(13) +#define EQOS_MAC_CONFIGURATION_LM BIT(12) +#define EQOS_MAC_CONFIGURATION_TE BIT(1) +#define EQOS_MAC_CONFIGURATION_RE BIT(0) + +#define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT 16 +#define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_MASK 0xffff +#define EQOS_MAC_Q0_TX_FLOW_CTRL_TFE BIT(1) + +#define EQOS_MAC_RX_FLOW_CTRL_RFE BIT(0) + +#define EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_SHIFT 0 +#define EQOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK 0xff + +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT 0 +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK 3 +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_NOT_ENABLED 0 +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB 2 +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV 1 + +#define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT 0 +#define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK 0xff + +#define EQOS_MAC_HW_FEATURE0_MMCSEL_SHIFT 8 +#define EQOS_MAC_HW_FEATURE0_HDSEL_SHIFT 2 +#define EQOS_MAC_HW_FEATURE0_GMIISEL_SHIFT 1 +#define EQOS_MAC_HW_FEATURE0_MIISEL_SHIFT 0 + +#define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT 6 +#define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK 0x1f +#define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT 0 +#define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK 0x1f + +#define EQOS_MAC_HW_FEATURE3_ASP_SHIFT 28 +#define EQOS_MAC_HW_FEATURE3_ASP_MASK 0x3 + +#define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT 21 +#define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 +#define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 +#define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 +#define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5 +#define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) +#define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT 2 +#define EQOS_MAC_MDIO_ADDRESS_GOC_READ 3 +#define EQOS_MAC_MDIO_ADDRESS_GOC_WRITE 1 +#define EQOS_MAC_MDIO_ADDRESS_C45E BIT(1) +#define EQOS_MAC_MDIO_ADDRESS_GB BIT(0) + +#define EQOS_MAC_MDIO_DATA_GD_MASK 0xffff + +#define EQOS_MTL_REGS_BASE 0xd00 +struct eqos_mtl_regs { + u32 txq0_operation_mode; /* 0xd00 */ + u32 unused_d04; /* 0xd04 */ + u32 txq0_debug; /* 0xd08 */ + u32 unused_d0c[(0xd18 - 0xd0c) / 4]; /* 0xd0c */ + u32 txq0_quantum_weight; /* 0xd18 */ + u32 unused_d1c[(0xd30 - 0xd1c) / 4]; /* 0xd1c */ + u32 rxq0_operation_mode; /* 0xd30 */ + u32 unused_d34; /* 0xd34 */ + u32 rxq0_debug; /* 0xd38 */ +}; + +#define EQOS_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT 16 +#define EQOS_MTL_TXQ0_OPERATION_MODE_TQS_MASK 0x1ff +#define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT 2 +#define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_MASK 3 +#define EQOS_MTL_TXQ0_OPERATION_MODE_TXQEN_ENABLED 2 +#define EQOS_MTL_TXQ0_OPERATION_MODE_TSF BIT(1) +#define EQOS_MTL_TXQ0_OPERATION_MODE_FTQ BIT(0) + +#define EQOS_MTL_TXQ0_DEBUG_TXQSTS BIT(4) +#define EQOS_MTL_TXQ0_DEBUG_TRCSTS_SHIFT 1 +#define EQOS_MTL_TXQ0_DEBUG_TRCSTS_MASK 3 + +#define EQOS_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT 20 +#define EQOS_MTL_RXQ0_OPERATION_MODE_RQS_MASK 0x3ff +#define EQOS_MTL_RXQ0_OPERATION_MODE_RFD_SHIFT 14 +#define EQOS_MTL_RXQ0_OPERATION_MODE_RFD_MASK 0x3f +#define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_SHIFT 8 +#define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK 0x3f +#define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC BIT(7) +#define EQOS_MTL_RXQ0_OPERATION_MODE_RSF BIT(5) + +#define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT 16 +#define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK 0x7fff +#define EQOS_MTL_RXQ0_DEBUG_RXQSTS_SHIFT 4 +#define EQOS_MTL_RXQ0_DEBUG_RXQSTS_MASK 3 + +#define EQOS_DMA_REGS_BASE 0x1000 +struct eqos_dma_regs { + u32 mode; /* 0x1000 */ + u32 sysbus_mode; /* 0x1004 */ + u32 unused_1008[(0x1100 - 0x1008) / 4]; /* 0x1008 */ + u32 ch0_control; /* 0x1100 */ + u32 ch0_tx_control; /* 0x1104 */ + u32 ch0_rx_control; /* 0x1108 */ + u32 unused_110c; /* 0x110c */ + u32 ch0_txdesc_list_haddress; /* 0x1110 */ + u32 ch0_txdesc_list_address; /* 0x1114 */ + u32 ch0_rxdesc_list_haddress; /* 0x1118 */ + u32 ch0_rxdesc_list_address; /* 0x111c */ + u32 ch0_txdesc_tail_pointer; /* 0x1120 */ + u32 unused_1124; /* 0x1124 */ + u32 ch0_rxdesc_tail_pointer; /* 0x1128 */ + u32 ch0_txdesc_ring_length; /* 0x112c */ + u32 ch0_rxdesc_ring_length; /* 0x1130 */ +}; + +#define EQOS_DMA_MODE_SWR BIT(0) + +#define EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT 16 +#define EQOS_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK 0xf +#define EQOS_DMA_SYSBUS_MODE_EAME BIT(11) +#define EQOS_DMA_SYSBUS_MODE_BLEN16 BIT(3) +#define EQOS_DMA_SYSBUS_MODE_BLEN8 BIT(2) +#define EQOS_DMA_SYSBUS_MODE_BLEN4 BIT(1) + +#define EQOS_DMA_CH0_CONTROL_DSL_SHIFT 18 +#define EQOS_DMA_CH0_CONTROL_PBLX8 BIT(16) + +#define EQOS_DMA_CH0_TX_CONTROL_TXPBL_SHIFT 16 +#define EQOS_DMA_CH0_TX_CONTROL_TXPBL_MASK 0x3f +#define EQOS_DMA_CH0_TX_CONTROL_OSP BIT(4) +#define EQOS_DMA_CH0_TX_CONTROL_ST BIT(0) + +#define EQOS_DMA_CH0_RX_CONTROL_RXPBL_SHIFT 16 +#define EQOS_DMA_CH0_RX_CONTROL_RXPBL_MASK 0x3f +#define EQOS_DMA_CH0_RX_CONTROL_RBSZ_SHIFT 1 +#define EQOS_DMA_CH0_RX_CONTROL_RBSZ_MASK 0x3fff +#define EQOS_DMA_CH0_RX_CONTROL_SR BIT(0) + +/* These registers are Tegra186-specific */ +#define EQOS_TEGRA186_REGS_BASE 0x8800 +struct eqos_tegra186_regs { + u32 sdmemcomppadctrl; /* 0x8800 */ + u32 auto_cal_config; /* 0x8804 */ + u32 unused_8808; /* 0x8808 */ + u32 auto_cal_status; /* 0x880c */ +}; + +#define EQOS_SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31) + +#define EQOS_AUTO_CAL_CONFIG_START BIT(31) +#define EQOS_AUTO_CAL_CONFIG_ENABLE BIT(29) + +#define EQOS_AUTO_CAL_STATUS_ACTIVE BIT(31) + +/* Descriptors */ +#define EQOS_DESCRIPTORS_TX 4 +#define EQOS_DESCRIPTORS_RX 4 +#define EQOS_DESCRIPTORS_NUM (EQOS_DESCRIPTORS_TX + EQOS_DESCRIPTORS_RX) +#define EQOS_BUFFER_ALIGN ARCH_DMA_MINALIGN +#define EQOS_MAX_PACKET_SIZE ALIGN(1568, ARCH_DMA_MINALIGN) +#define EQOS_RX_BUFFER_SIZE (EQOS_DESCRIPTORS_RX * EQOS_MAX_PACKET_SIZE) + +struct eqos_desc { + u32 des0; + u32 des1; + u32 des2; + u32 des3; +}; + +#define EQOS_DESC3_OWN BIT(31) +#define EQOS_DESC3_FD BIT(29) +#define EQOS_DESC3_LD BIT(28) +#define EQOS_DESC3_BUF1V BIT(24) + +#define EQOS_AXI_WIDTH_32 4 +#define EQOS_AXI_WIDTH_64 8 +#define EQOS_AXI_WIDTH_128 16 + +struct eqos_config { + bool reg_access_always_ok; + int mdio_wait; + int swr_wait; + int config_mac; + int config_mac_mdio; + unsigned int axi_bus_width; + phy_interface_t (*interface)(const struct udevice *dev); + struct eqos_ops *ops; +}; + +struct eqos_ops { + void (*eqos_inval_desc)(void *desc); + void (*eqos_flush_desc)(void *desc); + void (*eqos_inval_buffer)(void *buf, size_t size); + void (*eqos_flush_buffer)(void *buf, size_t size); + int (*eqos_probe_resources)(struct udevice *dev); + int (*eqos_remove_resources)(struct udevice *dev); + int (*eqos_stop_resets)(struct udevice *dev); + int (*eqos_start_resets)(struct udevice *dev); + int (*eqos_stop_clks)(struct udevice *dev); + int (*eqos_start_clks)(struct udevice *dev); + int (*eqos_calibrate_pads)(struct udevice *dev); + int (*eqos_disable_calibration)(struct udevice *dev); + int (*eqos_set_tx_clk_speed)(struct udevice *dev); + int (*eqos_get_enetaddr)(struct udevice *dev); + ulong (*eqos_get_tick_clk_rate)(struct udevice *dev); +}; + +struct eqos_priv { + struct udevice *dev; + const struct eqos_config *config; + fdt_addr_t regs; + struct eqos_mac_regs *mac_regs; + struct eqos_mtl_regs *mtl_regs; + struct eqos_dma_regs *dma_regs; + struct eqos_tegra186_regs *tegra186_regs; + struct reset_ctl reset_ctl; + struct gpio_desc phy_reset_gpio; + struct clk clk_master_bus; + struct clk clk_rx; + struct clk clk_ptp_ref; + struct clk clk_tx; + struct clk clk_ck; + struct clk clk_slave_bus; + struct mii_dev *mii; + struct phy_device *phy; + ofnode phy_of_node; + u32 max_speed; + void *descs; + int tx_desc_idx, rx_desc_idx; + unsigned int desc_size; + void *tx_dma_buf; + void *rx_dma_buf; + void *rx_pkt; + bool started; + bool reg_access_ok; + bool clk_ck_enabled; +}; + +void eqos_inval_desc_generic(void *desc); +void eqos_flush_desc_generic(void *desc); +void eqos_inval_buffer_generic(void *buf, size_t size); +void eqos_flush_buffer_generic(void *buf, size_t size); +int eqos_null_ops(struct udevice *dev); + +extern struct eqos_config eqos_imx_config; diff --git a/drivers/net/dwc_eth_qos_imx.c b/drivers/net/dwc_eth_qos_imx.c new file mode 100644 index 00000000000..42cb164ad14 --- /dev/null +++ b/drivers/net/dwc_eth_qos_imx.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2022 NXP + */ + +#include <common.h> +#include <clk.h> +#include <cpu_func.h> +#include <dm.h> +#include <errno.h> +#include <eth_phy.h> +#include <log.h> +#include <malloc.h> +#include <memalign.h> +#include <miiphy.h> +#include <net.h> +#include <netdev.h> +#include <phy.h> +#include <reset.h> +#include <wait_bit.h> +#include <asm/arch/clock.h> +#include <asm/cache.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/mach-imx/sys_proto.h> +#include <linux/delay.h> + +#include "dwc_eth_qos.h" + +__weak u32 imx_get_eqos_csr_clk(void) +{ + return 100 * 1000000; +} + +__weak int imx_eqos_txclk_set_rate(unsigned long rate) +{ + return 0; +} + +static ulong eqos_get_tick_clk_rate_imx(struct udevice *dev) +{ + return imx_get_eqos_csr_clk(); +} + +static int eqos_probe_resources_imx(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + phy_interface_t interface; + + debug("%s(dev=%p):\n", __func__, dev); + + interface = eqos->config->interface(dev); + + if (interface == PHY_INTERFACE_MODE_NA) { + pr_err("Invalid PHY interface\n"); + return -EINVAL; + } + + debug("%s: OK\n", __func__); + return 0; +} + +static int eqos_set_tx_clk_speed_imx(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + ulong rate; + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + switch (eqos->phy->speed) { + case SPEED_1000: + rate = 125 * 1000 * 1000; + break; + case SPEED_100: + rate = 25 * 1000 * 1000; + break; + case SPEED_10: + rate = 2.5 * 1000 * 1000; + break; + default: + pr_err("invalid speed %d", eqos->phy->speed); + return -EINVAL; + } + + ret = imx_eqos_txclk_set_rate(rate); + if (ret < 0) { + pr_err("imx (tx_clk, %lu) failed: %d", rate, ret); + return ret; + } + + return 0; +} + +static int eqos_get_enetaddr_imx(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + + imx_get_mac_from_fuse(dev_seq(dev), pdata->enetaddr); + + return 0; +} + +static struct eqos_ops eqos_imx_ops = { + .eqos_inval_desc = eqos_inval_desc_generic, + .eqos_flush_desc = eqos_flush_desc_generic, + .eqos_inval_buffer = eqos_inval_buffer_generic, + .eqos_flush_buffer = eqos_flush_buffer_generic, + .eqos_probe_resources = eqos_probe_resources_imx, + .eqos_remove_resources = eqos_null_ops, + .eqos_stop_resets = eqos_null_ops, + .eqos_start_resets = eqos_null_ops, + .eqos_stop_clks = eqos_null_ops, + .eqos_start_clks = eqos_null_ops, + .eqos_calibrate_pads = eqos_null_ops, + .eqos_disable_calibration = eqos_null_ops, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_imx, + .eqos_get_enetaddr = eqos_get_enetaddr_imx, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_imx, +}; + +struct eqos_config __maybe_unused eqos_imx_config = { + .reg_access_always_ok = false, + .mdio_wait = 10, + .swr_wait = 50, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, + .axi_bus_width = EQOS_AXI_WIDTH_64, + .interface = dev_read_phy_mode, + .ops = &eqos_imx_ops +}; diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index a623a5c45e4..8bc2b46d403 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -598,7 +598,8 @@ static int fecmxc_init(struct udevice *dev) writel(0x00000000, &fec->eth->gaddr2); /* Do not access reserved register */ - if (!is_mx6ul() && !is_mx6ull() && !is_imx8() && !is_imx8m() && !is_imx8ulp()) { + if (!is_mx6ul() && !is_mx6ull() && !is_imx8() && !is_imx8m() && !is_imx8ulp() && + !is_imx93()) { /* clear MIB RAM */ for (i = mib_ptr; i <= mib_ptr + 0xfc; i += 4) writel(0, i); @@ -1357,6 +1358,7 @@ static const struct udevice_id fecmxc_ids[] = { { .compatible = "fsl,imx53-fec" }, { .compatible = "fsl,imx7d-fec" }, { .compatible = "fsl,mvf600-fec" }, + { .compatible = "fsl,imx93-fec" }, { } }; diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig index 3657e9deb9e..06c26f156f6 100644 --- a/drivers/pinctrl/nxp/Kconfig +++ b/drivers/pinctrl/nxp/Kconfig @@ -102,6 +102,19 @@ config PINCTRL_IMX8M only parses the 'fsl,pins' property and configure related registers. +config PINCTRL_IMX93 + bool "IMX8M pinctrl driver" + depends on ARCH_IMX9 && PINCTRL_FULL + select PINCTRL_IMX + help + Say Y here to enable the imx8m pinctrl driver + + This provides a simple pinctrl driver for i.MX8M SoC familiy. + This feature depends on device tree configuration. This driver + is different from the linux one, this is a simple implementation, + only parses the 'fsl,pins' property and configure related + registers. + config PINCTRL_MXS bool "NXP MXS pinctrl driver" depends on ARCH_MX28 && PINCTRL_FULL diff --git a/drivers/pinctrl/nxp/Makefile b/drivers/pinctrl/nxp/Makefile index f2fe0d8efa6..f10aa6ef188 100644 --- a/drivers/pinctrl/nxp/Makefile +++ b/drivers/pinctrl/nxp/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_PINCTRL_IMX8ULP) += pinctrl-imx8ulp.o obj-$(CONFIG_PINCTRL_IMX_SCU) += pinctrl-scu.o obj-$(CONFIG_PINCTRL_IMX8) += pinctrl-imx8.o obj-$(CONFIG_PINCTRL_IMX8M) += pinctrl-imx8m.o +obj-$(CONFIG_PINCTRL_IMX93) += pinctrl-imx93.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_VYBRID) += pinctrl-vf610.o obj-$(CONFIG_PINCTRL_IMXRT) += pinctrl-imxrt.o diff --git a/drivers/pinctrl/nxp/pinctrl-imx93.c b/drivers/pinctrl/nxp/pinctrl-imx93.c new file mode 100644 index 00000000000..9a5b9de6d75 --- /dev/null +++ b/drivers/pinctrl/nxp/pinctrl-imx93.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022 NXP + */ + +#include <dm/device.h> +#include <dm/pinctrl.h> + +#include "pinctrl-imx.h" + +static struct imx_pinctrl_soc_info imx93_pinctrl_soc_info __section(".data") = { + .flags = ZERO_OFFSET_VALID, +}; + +static int imx93_pinctrl_probe(struct udevice *dev) +{ + struct imx_pinctrl_soc_info *info = + (struct imx_pinctrl_soc_info *)dev_get_driver_data(dev); + + return imx_pinctrl_probe(dev, info); +} + +static const struct udevice_id imx93_pinctrl_match[] = { + { .compatible = "fsl,imx93-iomuxc", .data = (ulong)&imx93_pinctrl_soc_info }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(imx93_pinctrl) = { + .name = "imx93-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(imx93_pinctrl_match), + .probe = imx93_pinctrl_probe, + .remove = imx_pinctrl_remove, + .priv_auto = sizeof(struct imx_pinctrl_priv), + .ops = &imx_pinctrl_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 060b02accc5..e30449b55e4 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -272,12 +272,7 @@ static void usb_oc_config(struct usbnc_regs *usbnc, int index) { void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]); -#if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2 - /* mx6qarm2 seems to required a different setting*/ - clrbits_le32(ctrl, UCTRL_OVER_CUR_POL); -#else setbits_le32(ctrl, UCTRL_OVER_CUR_POL); -#endif setbits_le32(ctrl, UCTRL_OVER_CUR_DIS); |
