Merge tag 'u-boot-imx-next-20240324' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx into next
- Add ahab_commit command support. - Add USB support for the imx93-phyboard-segin board. - Add i.MX8MP PCIe support. - Fix netboot environment on phycore_imx8mp.
This commit is contained in:
@@ -1371,6 +1371,12 @@ M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
F: tools/patman/
|
||||
|
||||
PCIe DWC IMX
|
||||
M: Sumit Garg <sumit.garg@linaro.org>
|
||||
S: Maintained
|
||||
F: drivers/pci/pcie_dw_imx.c
|
||||
F: drivers/phy/phy-imx8m-pcie.c
|
||||
|
||||
PCI Endpoint
|
||||
M: Ramon Fried <rfried.dev@gmail.com>
|
||||
S: Maintained
|
||||
|
@@ -121,6 +121,21 @@
|
||||
bootph-some-ram;
|
||||
};
|
||||
|
||||
/*
|
||||
* Remove once USB support is added to imx93-phyboard-segin.dts upstream.
|
||||
*/
|
||||
&usbotg1 {
|
||||
disable-over-current;
|
||||
dr_mode = "otg";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usbotg2 {
|
||||
disable-over-current;
|
||||
dr_mode = "host";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usdhc1 {
|
||||
bootph-pre-ram;
|
||||
bootph-some-ram;
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#define ELE_GET_FW_VERSION_REQ (0x9D)
|
||||
#define ELE_RET_LIFECYCLE_UP_REQ (0xA0)
|
||||
#define ELE_GET_EVENTS_REQ (0xA2)
|
||||
#define ELE_COMMIT_REQ (0xA8)
|
||||
#define ELE_START_RNG (0xA3)
|
||||
#define ELE_GENERATE_DEK_BLOB (0xAF)
|
||||
#define ELE_ENABLE_PATCH_REQ (0xC3)
|
||||
@@ -142,6 +143,7 @@ int ele_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *respon
|
||||
int ele_release_caam(u32 core_did, u32 *response);
|
||||
int ele_get_fw_version(u32 *fw_version, u32 *sha1, u32 *response);
|
||||
int ele_get_events(u32 *events, u32 *events_cnt, u32 *response);
|
||||
int ele_commit(u16 fuse_id, u32 *response, u32 *info_type);
|
||||
int ele_generate_dek_blob(u32 key_id, u32 src_paddr, u32 dst_paddr, u32 max_output_size);
|
||||
int ele_dump_buffer(u32 *buffer, u32 buffer_length);
|
||||
int ele_get_info(struct ele_get_info_data *info, u32 *response);
|
||||
|
@@ -625,6 +625,29 @@ static int do_ahab_return_lifecycle(struct cmd_tbl *cmdtp, int flag, int argc, c
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_ahab_commit(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
u32 index;
|
||||
u32 resp;
|
||||
u32 info_type;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
index = simple_strtoul(argv[1], NULL, 16);
|
||||
printf("Commit index is 0x%x\n", index);
|
||||
|
||||
if (ele_commit(index, &resp, &info_type)) {
|
||||
printf("Error in AHAB commit\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
printf("Ahab commit succeeded. Information type is 0x%x\n", info_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(auth_cntr, CONFIG_SYS_MAXARGS, 1, do_authenticate,
|
||||
"autenticate OS container via AHAB",
|
||||
"addr\n"
|
||||
@@ -657,3 +680,9 @@ U_BOOT_CMD(ahab_return_lifecycle, CONFIG_SYS_MAXARGS, 1, do_ahab_return_lifecycl
|
||||
"addr\n"
|
||||
"addr - Return lifecycle message block signed by OEM SRK\n"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(ahab_commit, CONFIG_SYS_MAXARGS, 1, do_ahab_commit,
|
||||
"commit into the fuses any new SRK revocation and FW version information\n"
|
||||
"that have been found into the NXP (ELE FW) and OEM containers",
|
||||
""
|
||||
);
|
||||
|
@@ -46,17 +46,17 @@ netargs=
|
||||
nfsroot=${serverip}:${nfsroot},v3,tcp
|
||||
netboot=
|
||||
echo Booting from net ...;
|
||||
run netargs;
|
||||
if test ${ip_dyn} = yes; then
|
||||
setenv get_cmd dhcp;
|
||||
else
|
||||
setenv get_cmd tftp;
|
||||
fi;
|
||||
${get_cmd} ${loadaddr} ${image};
|
||||
run netargs;
|
||||
if ${get_cmd} ${fdt_addr} ${fdt_file}; then
|
||||
booti ${loadaddr} - ${fdt_addr};
|
||||
else
|
||||
echo WARN: Cannot load the DT;
|
||||
fi;
|
||||
nfsroot=/nfs
|
||||
nfsroot=/srv/nfs
|
||||
sd_dev=1
|
||||
|
@@ -12,6 +12,7 @@ CONFIG_DEFAULT_DEVICE_TREE="freescale/imx8mp-venice-gw71xx-2x"
|
||||
CONFIG_SPL_TEXT_BASE=0x920000
|
||||
CONFIG_TARGET_IMX8MP_VENICE=y
|
||||
CONFIG_OF_LIBFDT_OVERLAY=y
|
||||
CONFIG_DM_RESET=y
|
||||
CONFIG_SYS_MONITOR_LEN=524288
|
||||
CONFIG_SPL_MMC=y
|
||||
CONFIG_SPL_SERIAL=y
|
||||
@@ -21,6 +22,7 @@ CONFIG_SPL=y
|
||||
CONFIG_ENV_OFFSET_REDUND=0x3f8000
|
||||
CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
|
||||
CONFIG_SYS_LOAD_ADDR=0x40480000
|
||||
CONFIG_PCI=y
|
||||
CONFIG_SYS_MEMTEST_START=0x40000000
|
||||
CONFIG_SYS_MEMTEST_END=0x80000000
|
||||
CONFIG_FIT=y
|
||||
@@ -63,6 +65,7 @@ CONFIG_CMD_FUSE=y
|
||||
CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_I2C=y
|
||||
CONFIG_CMD_MMC=y
|
||||
CONFIG_CMD_PCI=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_SYS_DISABLE_AUTOLOAD=y
|
||||
CONFIG_CMD_CACHE=y
|
||||
@@ -84,6 +87,8 @@ CONFIG_NET_RANDOM_ETHADDR=y
|
||||
CONFIG_IP_DEFRAG=y
|
||||
CONFIG_TFTP_BLOCKSIZE=4096
|
||||
CONFIG_SPL_DM=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_SYSCON=y
|
||||
CONFIG_CLK_COMPOSITE_CCF=y
|
||||
CONFIG_CLK_IMX8MP=y
|
||||
CONFIG_GPIO_HOG=y
|
||||
@@ -112,7 +117,10 @@ CONFIG_FEC_MXC=y
|
||||
CONFIG_KSZ9477=y
|
||||
CONFIG_RGMII=y
|
||||
CONFIG_MII=y
|
||||
CONFIG_NVME_PCI=y
|
||||
CONFIG_PCIE_DW_IMX=y
|
||||
CONFIG_PHY_IMX8MQ_USB=y
|
||||
CONFIG_PHY_IMX8M_PCIE=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_SPL_PINCTRL=y
|
||||
CONFIG_PINCTRL_IMX8M=y
|
||||
|
@@ -67,6 +67,7 @@ CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_I2C=y
|
||||
CONFIG_CMD_MMC=y
|
||||
CONFIG_CMD_POWEROFF=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_SNTP=y
|
||||
CONFIG_CMD_CACHE=y
|
||||
CONFIG_CMD_EFIDEBUG=y
|
||||
@@ -93,6 +94,12 @@ CONFIG_SPL_CLK_IMX93=y
|
||||
CONFIG_CLK_IMX93=y
|
||||
CONFIG_DFU_MMC=y
|
||||
CONFIG_DFU_RAM=y
|
||||
CONFIG_USB_FUNCTION_FASTBOOT=y
|
||||
CONFIG_FASTBOOT_BUF_ADDR=0x82800000
|
||||
CONFIG_FASTBOOT_BUF_SIZE=0x20000000
|
||||
CONFIG_FASTBOOT_FLASH=y
|
||||
CONFIG_FASTBOOT_UUU_SUPPORT=y
|
||||
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
|
||||
CONFIG_GPIO_HOG=y
|
||||
CONFIG_IMX_RGPIO2P=y
|
||||
CONFIG_DM_I2C=y
|
||||
@@ -132,6 +139,13 @@ CONFIG_SPL_SYSRESET=y
|
||||
CONFIG_SYSRESET_WATCHDOG=y
|
||||
CONFIG_DM_THERMAL=y
|
||||
CONFIG_IMX_TMU=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_GADGET=y
|
||||
CONFIG_USB_GADGET_MANUFACTURER="PHYTEC"
|
||||
CONFIG_USB_GADGET_VENDOR_NUM=0x1fc9
|
||||
CONFIG_USB_GADGET_PRODUCT_NUM=0x0152
|
||||
CONFIG_CI_UDC=y
|
||||
CONFIG_ULP_WATCHDOG=y
|
||||
CONFIG_LZO=y
|
||||
CONFIG_BZIP2=y
|
||||
|
@@ -16,6 +16,7 @@ CONFIG_DEFAULT_DEVICE_TREE="imx8mp-verdin-wifi-dev"
|
||||
CONFIG_SPL_TEXT_BASE=0x920000
|
||||
CONFIG_TARGET_VERDIN_IMX8MP=y
|
||||
CONFIG_OF_LIBFDT_OVERLAY=y
|
||||
CONFIG_DM_RESET=y
|
||||
CONFIG_SYS_MONITOR_LEN=524288
|
||||
CONFIG_SPL_MMC=y
|
||||
CONFIG_SPL_SERIAL=y
|
||||
@@ -26,6 +27,7 @@ CONFIG_SPL=y
|
||||
CONFIG_IMX_BOOTAUX=y
|
||||
CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
|
||||
CONFIG_SYS_LOAD_ADDR=0x48200000
|
||||
CONFIG_PCI=y
|
||||
CONFIG_SYS_MEMTEST_START=0x40000000
|
||||
CONFIG_SYS_MEMTEST_END=0x80000000
|
||||
CONFIG_REMAKE_ELF=y
|
||||
@@ -76,6 +78,7 @@ CONFIG_CMD_FUSE=y
|
||||
CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_I2C=y
|
||||
CONFIG_CMD_MMC=y
|
||||
CONFIG_CMD_PCI=y
|
||||
CONFIG_CMD_READ=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_USB_MASS_STORAGE=y
|
||||
@@ -145,8 +148,11 @@ CONFIG_DWC_ETH_QOS_IMX=y
|
||||
CONFIG_FEC_MXC=y
|
||||
CONFIG_RGMII=y
|
||||
CONFIG_MII=y
|
||||
CONFIG_NVME_PCI=y
|
||||
CONFIG_PCIE_DW_IMX=y
|
||||
CONFIG_PHY=y
|
||||
CONFIG_PHY_IMX8MQ_USB=y
|
||||
CONFIG_PHY_IMX8M_PCIE=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_SPL_PINCTRL=y
|
||||
CONFIG_PINCTRL_IMX8M=y
|
||||
|
@@ -62,6 +62,10 @@ static const char *imx8mp_dram_apb_sels[] = {"clock-osc-24m", "sys_pll2_200m", "
|
||||
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
|
||||
"sys_pll2_250m", "audio_pll2_out", };
|
||||
|
||||
static const char * const imx8mp_pcie_aux_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll2_50m",
|
||||
"sys_pll3_out", "sys_pll2_100m", "sys_pll1_80m",
|
||||
"sys_pll1_160m", "sys_pll1_200m", };
|
||||
|
||||
static const char *imx8mp_i2c5_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
|
||||
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
|
||||
"audio_pll2_out", "sys_pll1_133m", };
|
||||
@@ -272,6 +276,7 @@ static int imx8mp_clk_probe(struct udevice *dev)
|
||||
|
||||
clk_dm(IMX8MP_CLK_DRAM_ALT, imx8m_clk_composite("dram_alt", imx8mp_dram_alt_sels, base + 0xa000));
|
||||
clk_dm(IMX8MP_CLK_DRAM_APB, imx8m_clk_composite_critical("dram_apb", imx8mp_dram_apb_sels, base + 0xa080));
|
||||
clk_dm(IMX8MP_CLK_PCIE_AUX, imx8m_clk_composite("pcie_aux", imx8mp_pcie_aux_sels, base + 0xa400));
|
||||
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_QOS, imx8m_clk_composite("enet_qos", imx8mp_enet_qos_sels, base + 0xa880));
|
||||
@@ -322,6 +327,7 @@ 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_PCIE_ROOT, imx_clk_gate4("pcie_root_clk", "pcie_aux", base + 0x4250, 0));
|
||||
clk_dm(IMX8MP_CLK_PWM1_ROOT, imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0));
|
||||
clk_dm(IMX8MP_CLK_PWM2_ROOT, imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0));
|
||||
clk_dm(IMX8MP_CLK_PWM3_ROOT, imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0));
|
||||
|
@@ -528,6 +528,38 @@ int ele_start_rng(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ele_commit(u16 fuse_id, u32 *response, u32 *info_type)
|
||||
{
|
||||
struct udevice *dev = gd->arch.ele_dev;
|
||||
int size = sizeof(struct ele_msg);
|
||||
struct ele_msg msg;
|
||||
int ret = 0;
|
||||
|
||||
if (!dev) {
|
||||
printf("ele dev is not initialized\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
msg.version = ELE_VERSION;
|
||||
msg.tag = ELE_CMD_TAG;
|
||||
msg.size = 2;
|
||||
msg.command = ELE_COMMIT_REQ;
|
||||
msg.data[0] = fuse_id;
|
||||
|
||||
ret = misc_call(dev, false, &msg, size, &msg, size);
|
||||
if (ret)
|
||||
printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n",
|
||||
__func__, ret, fuse_id, msg.data[0]);
|
||||
|
||||
if (response)
|
||||
*response = msg.data[0];
|
||||
|
||||
if (info_type)
|
||||
*info_type = msg.data[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ele_write_secure_fuse(ulong signed_msg_blk, u32 *response)
|
||||
{
|
||||
struct udevice *dev = gd->arch.ele_dev;
|
||||
|
@@ -413,4 +413,15 @@ config PCIE_STARFIVE_JH7110
|
||||
Say Y here if you want to enable PLDA XpressRich PCIe controller
|
||||
support on StarFive JH7110 SoC.
|
||||
|
||||
config PCIE_DW_IMX
|
||||
bool "i.MX DW PCIe controller support"
|
||||
depends on ARCH_IMX8M
|
||||
select PCIE_DW_COMMON
|
||||
select DM_REGULATOR
|
||||
select REGMAP
|
||||
select SYSCON
|
||||
help
|
||||
Say Y here if you want to enable DW PCIe controller support on
|
||||
iMX SoCs.
|
||||
|
||||
endif
|
||||
|
@@ -53,3 +53,4 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie_uniphier.o
|
||||
obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o
|
||||
obj-$(CONFIG_PCIE_PLDA_COMMON) += pcie_plda_common.o
|
||||
obj-$(CONFIG_PCIE_STARFIVE_JH7110) += pcie_starfive_jh7110.o
|
||||
obj-$(CONFIG_PCIE_DW_IMX) += pcie_dw_imx.o
|
||||
|
338
drivers/pci/pcie_dw_imx.c
Normal file
338
drivers/pci/pcie_dw_imx.c
Normal file
@@ -0,0 +1,338 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2024 Linaro Ltd.
|
||||
*
|
||||
* Author: Sumit Garg <sumit.garg@linaro.org>
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm-generic/gpio.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <generic-phy.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <log.h>
|
||||
#include <pci.h>
|
||||
#include <power/regulator.h>
|
||||
#include <regmap.h>
|
||||
#include <reset.h>
|
||||
#include <syscon.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "pcie_dw_common.h"
|
||||
|
||||
#define PCIE_LINK_CAPABILITY 0x7c
|
||||
#define TARGET_LINK_SPEED_MASK 0xf
|
||||
#define LINK_SPEED_GEN_1 0x1
|
||||
#define LINK_SPEED_GEN_2 0x2
|
||||
#define LINK_SPEED_GEN_3 0x3
|
||||
|
||||
#define PCIE_MISC_CONTROL_1_OFF 0x8bc
|
||||
#define PCIE_DBI_RO_WR_EN BIT(0)
|
||||
|
||||
#define PCIE_PORT_DEBUG0 0x728
|
||||
#define PCIE_PORT_DEBUG1 0x72c
|
||||
#define PCIE_PORT_DEBUG1_LINK_UP BIT(4)
|
||||
#define PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29)
|
||||
|
||||
#define PCIE_LINK_UP_TIMEOUT_MS 100
|
||||
|
||||
#define IOMUXC_GPR14_OFFSET 0x38
|
||||
#define IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10)
|
||||
#define IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11)
|
||||
|
||||
struct pcie_dw_imx {
|
||||
/* Must be first member of the struct */
|
||||
struct pcie_dw dw;
|
||||
struct regmap *iomuxc_gpr;
|
||||
struct clk_bulk clks;
|
||||
struct gpio_desc reset_gpio;
|
||||
struct reset_ctl apps_reset;
|
||||
struct phy phy;
|
||||
struct udevice *vpcie;
|
||||
};
|
||||
|
||||
static void pcie_dw_configure(struct pcie_dw_imx *priv, u32 cap_speed)
|
||||
{
|
||||
dw_pcie_dbi_write_enable(&priv->dw, true);
|
||||
|
||||
clrsetbits_le32(priv->dw.dbi_base + PCIE_LINK_CAPABILITY,
|
||||
TARGET_LINK_SPEED_MASK, cap_speed);
|
||||
|
||||
dw_pcie_dbi_write_enable(&priv->dw, false);
|
||||
}
|
||||
|
||||
static void imx_pcie_ltssm_enable(struct pcie_dw_imx *priv)
|
||||
{
|
||||
reset_deassert(&priv->apps_reset);
|
||||
}
|
||||
|
||||
static void imx_pcie_ltssm_disable(struct pcie_dw_imx *priv)
|
||||
{
|
||||
reset_assert(&priv->apps_reset);
|
||||
}
|
||||
|
||||
static bool is_link_up(u32 val)
|
||||
{
|
||||
return ((val & PCIE_PORT_DEBUG1_LINK_UP) &&
|
||||
(!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)));
|
||||
}
|
||||
|
||||
static int wait_link_up(struct pcie_dw_imx *priv)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
return readl_poll_sleep_timeout(priv->dw.dbi_base + PCIE_PORT_DEBUG1,
|
||||
val, is_link_up(val), 10000, 100000);
|
||||
}
|
||||
|
||||
static int pcie_link_up(struct pcie_dw_imx *priv, u32 cap_speed)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* DW pre link configurations */
|
||||
pcie_dw_configure(priv, cap_speed);
|
||||
|
||||
/* Initiate link training */
|
||||
imx_pcie_ltssm_enable(priv);
|
||||
|
||||
/* Check that link was established */
|
||||
ret = wait_link_up(priv);
|
||||
if (ret)
|
||||
imx_pcie_ltssm_disable(priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx_pcie_assert_core_reset(struct pcie_dw_imx *priv)
|
||||
{
|
||||
if (dm_gpio_is_valid(&priv->reset_gpio)) {
|
||||
dm_gpio_set_value(&priv->reset_gpio, 1);
|
||||
mdelay(20);
|
||||
}
|
||||
|
||||
return reset_assert(&priv->apps_reset);
|
||||
}
|
||||
|
||||
static int imx_pcie_clk_enable(struct pcie_dw_imx *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_enable_bulk(&priv->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set the over ride low and enabled make sure that
|
||||
* REF_CLK is turned on.
|
||||
*/
|
||||
regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET,
|
||||
IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE, 0);
|
||||
regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET,
|
||||
IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
|
||||
IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN);
|
||||
|
||||
/* allow the clocks to stabilize */
|
||||
udelay(500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void imx_pcie_deassert_core_reset(struct pcie_dw_imx *priv)
|
||||
{
|
||||
if (!dm_gpio_is_valid(&priv->reset_gpio))
|
||||
return;
|
||||
|
||||
mdelay(100);
|
||||
dm_gpio_set_value(&priv->reset_gpio, 0);
|
||||
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
|
||||
mdelay(100);
|
||||
}
|
||||
|
||||
static int pcie_dw_imx_probe(struct udevice *dev)
|
||||
{
|
||||
struct pcie_dw_imx *priv = dev_get_priv(dev);
|
||||
struct udevice *ctlr = pci_get_controller(dev);
|
||||
struct pci_controller *hose = dev_get_uclass_priv(ctlr);
|
||||
int ret;
|
||||
|
||||
if (priv->vpcie) {
|
||||
ret = regulator_set_enable(priv->vpcie, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable vpcie regulator\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = imx_pcie_assert_core_reset(priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to assert core reset\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = imx_pcie_clk_enable(priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clocks\n");
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = generic_phy_init(&priv->phy);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize PHY\n");
|
||||
goto err_phy_init;
|
||||
}
|
||||
|
||||
ret = generic_phy_power_on(&priv->phy);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to power on PHY\n");
|
||||
goto err_phy_power;
|
||||
}
|
||||
|
||||
imx_pcie_deassert_core_reset(priv);
|
||||
|
||||
priv->dw.first_busno = dev_seq(dev);
|
||||
priv->dw.dev = dev;
|
||||
pcie_dw_setup_host(&priv->dw);
|
||||
|
||||
if (pcie_link_up(priv, LINK_SPEED_GEN_1)) {
|
||||
printf("PCIE-%d: Link down\n", dev_seq(dev));
|
||||
ret = -ENODEV;
|
||||
goto err_link;
|
||||
}
|
||||
|
||||
printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev),
|
||||
pcie_dw_get_link_speed(&priv->dw),
|
||||
pcie_dw_get_link_width(&priv->dw),
|
||||
hose->first_busno);
|
||||
|
||||
pcie_dw_prog_outbound_atu_unroll(&priv->dw, PCIE_ATU_REGION_INDEX0,
|
||||
PCIE_ATU_TYPE_MEM,
|
||||
priv->dw.mem.phys_start,
|
||||
priv->dw.mem.bus_start, priv->dw.mem.size);
|
||||
|
||||
return 0;
|
||||
|
||||
err_link:
|
||||
generic_shutdown_phy(&priv->phy);
|
||||
err_phy_power:
|
||||
generic_phy_exit(&priv->phy);
|
||||
err_phy_init:
|
||||
clk_disable_bulk(&priv->clks);
|
||||
err_clk:
|
||||
imx_pcie_deassert_core_reset(priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcie_dw_imx_remove(struct udevice *dev)
|
||||
{
|
||||
struct pcie_dw_imx *priv = dev_get_priv(dev);
|
||||
|
||||
generic_shutdown_phy(&priv->phy);
|
||||
dm_gpio_free(dev, &priv->reset_gpio);
|
||||
reset_free(&priv->apps_reset);
|
||||
clk_release_bulk(&priv->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcie_dw_imx_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct pcie_dw_imx *priv = dev_get_priv(dev);
|
||||
ofnode gpr;
|
||||
int ret;
|
||||
|
||||
/* Get the controller base address */
|
||||
priv->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbi");
|
||||
if ((fdt_addr_t)priv->dw.dbi_base == FDT_ADDR_T_NONE) {
|
||||
dev_err(dev, "failed to get dbi_base address\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get the config space base address and size */
|
||||
priv->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config",
|
||||
&priv->dw.cfg_size);
|
||||
if ((fdt_addr_t)priv->dw.cfg_base == FDT_ADDR_T_NONE) {
|
||||
dev_err(dev, "failed to get cfg_base address\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_get_bulk(dev, &priv->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get PCIe clks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_get_by_name(dev, "apps", &priv->apps_reset);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to get PCIe apps reset control\n");
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
ret = gpio_request_by_name(dev, "reset-gpio", 0, &priv->reset_gpio,
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to get reset-gpio\n");
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
ret = generic_phy_get_by_name(dev, "pcie-phy", &priv->phy);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get pcie phy\n");
|
||||
goto err_phy;
|
||||
}
|
||||
|
||||
gpr = ofnode_by_compatible(ofnode_null(), "fsl,imx8mp-iomuxc-gpr");
|
||||
if (ofnode_equal(gpr, ofnode_null())) {
|
||||
dev_err(dev, "unable to find GPR node\n");
|
||||
ret = -ENODEV;
|
||||
goto err_phy;
|
||||
}
|
||||
|
||||
priv->iomuxc_gpr = syscon_node_to_regmap(gpr);
|
||||
if (IS_ERR(priv->iomuxc_gpr)) {
|
||||
dev_err(dev, "unable to find iomuxc registers\n");
|
||||
ret = PTR_ERR(priv->iomuxc_gpr);
|
||||
goto err_phy;
|
||||
}
|
||||
|
||||
/* vpcie-supply regulator is optional */
|
||||
device_get_supply_regulator(dev, "vpcie-supply", &priv->vpcie);
|
||||
|
||||
return 0;
|
||||
|
||||
err_phy:
|
||||
dm_gpio_free(dev, &priv->reset_gpio);
|
||||
err_gpio:
|
||||
reset_free(&priv->apps_reset);
|
||||
err_reset:
|
||||
clk_release_bulk(&priv->clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dm_pci_ops pcie_dw_imx_ops = {
|
||||
.read_config = pcie_dw_read_config,
|
||||
.write_config = pcie_dw_write_config,
|
||||
};
|
||||
|
||||
static const struct udevice_id pcie_dw_imx_ids[] = {
|
||||
{ .compatible = "fsl,imx8mp-pcie" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pcie_dw_imx) = {
|
||||
.name = "pcie_dw_imx",
|
||||
.id = UCLASS_PCI,
|
||||
.of_match = pcie_dw_imx_ids,
|
||||
.ops = &pcie_dw_imx_ops,
|
||||
.of_to_plat = pcie_dw_imx_of_to_plat,
|
||||
.probe = pcie_dw_imx_probe,
|
||||
.remove = pcie_dw_imx_remove,
|
||||
.priv_auto = sizeof(struct pcie_dw_imx),
|
||||
};
|
@@ -7,6 +7,14 @@
|
||||
* Based on upstream Linux kernel driver:
|
||||
* pci-imx6.c: Sean Cross <xobs@kosagi.com>
|
||||
* pcie-designware.c: Jingoo Han <jg1.han@samsung.com>
|
||||
*
|
||||
* This is a legacy PCIe iMX driver kept to support older iMX6 SoCs. It is
|
||||
* rather tied to quite old port of pcie-designware driver from Linux which
|
||||
* suffices only iMX6 specific needs. But now we have modern PCIe iMX driver
|
||||
* (drivers/pci/pcie_dw_imx.c) utilizing all the common DWC specific bits from
|
||||
* (drivers/pci/pcie_dw_common.*). So you are encouraged to add any further iMX
|
||||
* SoC support there or even better if you posses older iMX6 SoCs then switch
|
||||
* those too in order to have a single modern PCIe iMX driver.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
@@ -284,6 +284,17 @@ config PHY_IMX8MQ_USB
|
||||
help
|
||||
Support the USB3.0 PHY in NXP i.MX8MQ or i.MX8MP SoC
|
||||
|
||||
config PHY_IMX8M_PCIE
|
||||
bool "NXP i.MX8MM/i.MX8MP PCIe PHY Driver"
|
||||
depends on PHY
|
||||
depends on IMX8MM || IMX8MP
|
||||
select REGMAP
|
||||
select SYSCON
|
||||
help
|
||||
Support the PCIe PHY in NXP i.MX8MM or i.MX8MP SoC
|
||||
|
||||
This PHY is found on i.MX8M devices supporting PCIe.
|
||||
|
||||
config PHY_XILINX_ZYNQMP
|
||||
tristate "Xilinx ZynqMP PHY driver"
|
||||
depends on PHY && ARCH_ZYNQMP
|
||||
|
@@ -38,6 +38,7 @@ obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
|
||||
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
|
||||
obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o
|
||||
obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
|
||||
obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o
|
||||
obj-$(CONFIG_PHY_XILINX_ZYNQMP) += phy-zynqmp.o
|
||||
obj-y += cadence/
|
||||
obj-y += ti/
|
||||
|
283
drivers/phy/phy-imx8m-pcie.c
Normal file
283
drivers/phy/phy-imx8m-pcie.c
Normal file
@@ -0,0 +1,283 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2024 Linaro Ltd.
|
||||
*
|
||||
* Derived from Linux counterpart driver
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <generic-phy.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <syscon.h>
|
||||
#include <regmap.h>
|
||||
#include <reset.h>
|
||||
|
||||
#include <dt-bindings/phy/phy-imx8-pcie.h>
|
||||
|
||||
#define IMX8MM_PCIE_PHY_CMN_REG061 0x184
|
||||
#define ANA_PLL_CLK_OUT_TO_EXT_IO_EN BIT(0)
|
||||
#define IMX8MM_PCIE_PHY_CMN_REG062 0x188
|
||||
#define ANA_PLL_CLK_OUT_TO_EXT_IO_SEL BIT(3)
|
||||
#define IMX8MM_PCIE_PHY_CMN_REG063 0x18C
|
||||
#define AUX_PLL_REFCLK_SEL_SYS_PLL GENMASK(7, 6)
|
||||
#define IMX8MM_PCIE_PHY_CMN_REG064 0x190
|
||||
#define ANA_AUX_RX_TX_SEL_TX BIT(7)
|
||||
#define ANA_AUX_RX_TERM_GND_EN BIT(3)
|
||||
#define ANA_AUX_TX_TERM BIT(2)
|
||||
#define IMX8MM_PCIE_PHY_CMN_REG065 0x194
|
||||
#define ANA_AUX_RX_TERM (BIT(7) | BIT(4))
|
||||
#define ANA_AUX_TX_LVL GENMASK(3, 0)
|
||||
#define IMX8MM_PCIE_PHY_CMN_REG075 0x1D4
|
||||
#define ANA_PLL_DONE 0x3
|
||||
#define PCIE_PHY_TRSV_REG5 0x414
|
||||
#define PCIE_PHY_TRSV_REG6 0x418
|
||||
|
||||
#define IMX8MM_GPR_PCIE_REF_CLK_SEL GENMASK(25, 24)
|
||||
#define IMX8MM_GPR_PCIE_REF_CLK_PLL FIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x3)
|
||||
#define IMX8MM_GPR_PCIE_REF_CLK_EXT FIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x2)
|
||||
#define IMX8MM_GPR_PCIE_AUX_EN BIT(19)
|
||||
#define IMX8MM_GPR_PCIE_CMN_RST BIT(18)
|
||||
#define IMX8MM_GPR_PCIE_POWER_OFF BIT(17)
|
||||
#define IMX8MM_GPR_PCIE_SSC_EN BIT(16)
|
||||
#define IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE BIT(9)
|
||||
|
||||
#define IOMUXC_GPR14_OFFSET 0x38
|
||||
|
||||
enum imx8_pcie_phy_type {
|
||||
IMX8MM,
|
||||
IMX8MP,
|
||||
};
|
||||
|
||||
struct imx8_pcie_phy_drvdata {
|
||||
const char *gpr;
|
||||
enum imx8_pcie_phy_type variant;
|
||||
};
|
||||
|
||||
struct imx8_pcie_phy {
|
||||
ulong base;
|
||||
struct clk hsio_clk;
|
||||
struct regmap *iomuxc_gpr;
|
||||
struct reset_ctl perst;
|
||||
struct reset_ctl reset;
|
||||
u32 refclk_pad_mode;
|
||||
u32 tx_deemph_gen1;
|
||||
u32 tx_deemph_gen2;
|
||||
bool clkreq_unused;
|
||||
const struct imx8_pcie_phy_drvdata *drvdata;
|
||||
};
|
||||
|
||||
static int imx8_pcie_phy_power_on(struct phy *phy)
|
||||
{
|
||||
int ret;
|
||||
u32 val, pad_mode;
|
||||
struct imx8_pcie_phy *imx8_phy = dev_get_priv(phy->dev);
|
||||
|
||||
pad_mode = imx8_phy->refclk_pad_mode;
|
||||
switch (imx8_phy->drvdata->variant) {
|
||||
case IMX8MM:
|
||||
reset_assert(&imx8_phy->reset);
|
||||
|
||||
/* Tune PHY de-emphasis setting to pass PCIe compliance. */
|
||||
if (imx8_phy->tx_deemph_gen1)
|
||||
writel(imx8_phy->tx_deemph_gen1,
|
||||
imx8_phy->base + PCIE_PHY_TRSV_REG5);
|
||||
if (imx8_phy->tx_deemph_gen2)
|
||||
writel(imx8_phy->tx_deemph_gen2,
|
||||
imx8_phy->base + PCIE_PHY_TRSV_REG6);
|
||||
break;
|
||||
case IMX8MP: /* Do nothing. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ||
|
||||
pad_mode == IMX8_PCIE_REFCLK_PAD_UNUSED) {
|
||||
/* Configure the pad as input */
|
||||
val = readl(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
|
||||
writel(val & ~ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
|
||||
} else {
|
||||
/* Configure the PHY to output the refclock via pad */
|
||||
writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
|
||||
}
|
||||
|
||||
if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT ||
|
||||
pad_mode == IMX8_PCIE_REFCLK_PAD_UNUSED) {
|
||||
/* Source clock from SoC internal PLL */
|
||||
writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062);
|
||||
writel(AUX_PLL_REFCLK_SEL_SYS_PLL,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG063);
|
||||
val = ANA_AUX_RX_TX_SEL_TX | ANA_AUX_TX_TERM;
|
||||
writel(val | ANA_AUX_RX_TERM_GND_EN,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG064);
|
||||
writel(ANA_AUX_RX_TERM | ANA_AUX_TX_LVL,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG065);
|
||||
}
|
||||
|
||||
/* Set AUX_EN_OVERRIDE 1'b0, when the CLKREQ# isn't hooked */
|
||||
regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14_OFFSET,
|
||||
IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE,
|
||||
imx8_phy->clkreq_unused ?
|
||||
0 : IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE);
|
||||
regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14_OFFSET,
|
||||
IMX8MM_GPR_PCIE_AUX_EN,
|
||||
IMX8MM_GPR_PCIE_AUX_EN);
|
||||
regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14_OFFSET,
|
||||
IMX8MM_GPR_PCIE_POWER_OFF, 0);
|
||||
regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14_OFFSET,
|
||||
IMX8MM_GPR_PCIE_SSC_EN, 0);
|
||||
|
||||
regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14_OFFSET,
|
||||
IMX8MM_GPR_PCIE_REF_CLK_SEL,
|
||||
pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ?
|
||||
IMX8MM_GPR_PCIE_REF_CLK_EXT :
|
||||
IMX8MM_GPR_PCIE_REF_CLK_PLL);
|
||||
udelay(200);
|
||||
|
||||
/* Do the PHY common block reset */
|
||||
regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14_OFFSET,
|
||||
IMX8MM_GPR_PCIE_CMN_RST,
|
||||
IMX8MM_GPR_PCIE_CMN_RST);
|
||||
|
||||
switch (imx8_phy->drvdata->variant) {
|
||||
case IMX8MP:
|
||||
reset_deassert(&imx8_phy->perst);
|
||||
fallthrough;
|
||||
case IMX8MM:
|
||||
reset_deassert(&imx8_phy->reset);
|
||||
udelay(500);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Polling to check the phy is ready or not. */
|
||||
ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG075,
|
||||
val, val == ANA_PLL_DONE, 20000);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8_pcie_phy_init(struct phy *phy)
|
||||
{
|
||||
struct imx8_pcie_phy *imx8_phy = dev_get_priv(phy->dev);
|
||||
|
||||
return clk_enable(&imx8_phy->hsio_clk);
|
||||
}
|
||||
|
||||
static int imx8_pcie_phy_exit(struct phy *phy)
|
||||
{
|
||||
struct imx8_pcie_phy *imx8_phy = dev_get_priv(phy->dev);
|
||||
|
||||
return clk_disable(&imx8_phy->hsio_clk);
|
||||
}
|
||||
|
||||
static const struct phy_ops imx8_pcie_phy_ops = {
|
||||
.init = imx8_pcie_phy_init,
|
||||
.exit = imx8_pcie_phy_exit,
|
||||
.power_on = imx8_pcie_phy_power_on,
|
||||
};
|
||||
|
||||
static const struct imx8_pcie_phy_drvdata imx8mm_drvdata = {
|
||||
.gpr = "fsl,imx8mm-iomuxc-gpr",
|
||||
.variant = IMX8MM,
|
||||
};
|
||||
|
||||
static const struct imx8_pcie_phy_drvdata imx8mp_drvdata = {
|
||||
.gpr = "fsl,imx8mp-iomuxc-gpr",
|
||||
.variant = IMX8MP,
|
||||
};
|
||||
|
||||
static const struct udevice_id imx8_pcie_phy_of_match[] = {
|
||||
{.compatible = "fsl,imx8mm-pcie-phy", .data = (ulong)&imx8mm_drvdata, },
|
||||
{.compatible = "fsl,imx8mp-pcie-phy", .data = (ulong)&imx8mp_drvdata, },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int imx8_pcie_phy_probe(struct udevice *dev)
|
||||
{
|
||||
struct imx8_pcie_phy *imx8_phy = dev_get_priv(dev);
|
||||
ofnode gpr;
|
||||
int ret = 0;
|
||||
|
||||
imx8_phy->drvdata = (void *)dev_get_driver_data(dev);
|
||||
imx8_phy->base = dev_read_addr(dev);
|
||||
if (!imx8_phy->base)
|
||||
return -EINVAL;
|
||||
|
||||
/* get PHY refclk pad mode */
|
||||
dev_read_u32(dev, "fsl,refclk-pad-mode", &imx8_phy->refclk_pad_mode);
|
||||
|
||||
imx8_phy->tx_deemph_gen1 = dev_read_u32_default(dev,
|
||||
"fsl,tx-deemph-gen1",
|
||||
0);
|
||||
imx8_phy->tx_deemph_gen2 = dev_read_u32_default(dev,
|
||||
"fsl,tx-deemph-gen2",
|
||||
0);
|
||||
imx8_phy->clkreq_unused = dev_read_bool(dev, "fsl,clkreq-unsupported");
|
||||
|
||||
/* Grab GPR config register range */
|
||||
gpr = ofnode_by_compatible(ofnode_null(), imx8_phy->drvdata->gpr);
|
||||
if (ofnode_equal(gpr, ofnode_null())) {
|
||||
dev_err(dev, "unable to find GPR node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
imx8_phy->iomuxc_gpr = syscon_node_to_regmap(gpr);
|
||||
if (IS_ERR(imx8_phy->iomuxc_gpr)) {
|
||||
dev_err(dev, "unable to find iomuxc registers\n");
|
||||
return PTR_ERR(imx8_phy->iomuxc_gpr);
|
||||
}
|
||||
|
||||
ret = clk_get_by_name(dev, "ref", &imx8_phy->hsio_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get PCIEPHY ref clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_get_by_name(dev, "pciephy", &imx8_phy->reset);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get PCIEPHY reset control\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (imx8_phy->drvdata->variant == IMX8MP) {
|
||||
ret = reset_get_by_name(dev, "perst", &imx8_phy->perst);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to get PCIEPHY PHY PERST control\n");
|
||||
goto err_perst;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_perst:
|
||||
reset_free(&imx8_phy->reset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8_pcie_phy_remove(struct udevice *dev)
|
||||
{
|
||||
struct imx8_pcie_phy *imx8_phy = dev_get_priv(dev);
|
||||
|
||||
if (imx8_phy->drvdata->variant == IMX8MP)
|
||||
reset_free(&imx8_phy->perst);
|
||||
|
||||
reset_free(&imx8_phy->reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(nxp_imx8_pcie_phy) = {
|
||||
.name = "nxp_imx8_pcie_phy",
|
||||
.id = UCLASS_PHY,
|
||||
.of_match = imx8_pcie_phy_of_match,
|
||||
.probe = imx8_pcie_phy_probe,
|
||||
.remove = imx8_pcie_phy_remove,
|
||||
.ops = &imx8_pcie_phy_ops,
|
||||
.priv_auto = sizeof(struct imx8_pcie_phy),
|
||||
};
|
@@ -6,9 +6,15 @@
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <clk.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <power-domain-uclass.h>
|
||||
|
||||
#include <dt-bindings/power/imx8mp-power.h>
|
||||
@@ -16,48 +22,94 @@
|
||||
#define GPR_REG0 0x0
|
||||
#define PCIE_CLOCK_MODULE_EN BIT(0)
|
||||
#define USB_CLOCK_MODULE_EN BIT(1)
|
||||
#define PCIE_PHY_APB_RST BIT(4)
|
||||
#define PCIE_PHY_INIT_RST BIT(5)
|
||||
#define GPR_REG1 0x4
|
||||
#define PLL_LOCK BIT(13)
|
||||
#define GPR_REG2 0x8
|
||||
#define P_PLL_MASK GENMASK(5, 0)
|
||||
#define M_PLL_MASK GENMASK(15, 6)
|
||||
#define S_PLL_MASK GENMASK(18, 16)
|
||||
#define GPR_REG3 0xc
|
||||
#define PLL_CKE BIT(17)
|
||||
#define PLL_RST BIT(31)
|
||||
|
||||
struct imx8mp_hsiomix_priv {
|
||||
void __iomem *base;
|
||||
struct clk clk_usb;
|
||||
struct clk clk_pcie;
|
||||
struct power_domain pd_bus;
|
||||
struct power_domain pd_usb;
|
||||
struct power_domain pd_pcie;
|
||||
struct power_domain pd_usb_phy1;
|
||||
struct power_domain pd_usb_phy2;
|
||||
struct power_domain pd_pcie_phy;
|
||||
};
|
||||
|
||||
static int imx8mp_hsiomix_on(struct power_domain *power_domain)
|
||||
static int imx8mp_hsiomix_set(struct power_domain *power_domain, bool power_on)
|
||||
{
|
||||
struct udevice *dev = power_domain->dev;
|
||||
struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev);
|
||||
struct power_domain *domain;
|
||||
struct power_domain *domain = NULL;
|
||||
struct clk *clk = NULL;
|
||||
u32 gpr_reg0_bits = 0;
|
||||
int ret;
|
||||
|
||||
switch (power_domain->id) {
|
||||
case IMX8MP_HSIOBLK_PD_USB:
|
||||
domain = &priv->pd_usb;
|
||||
clk = &priv->clk_usb;
|
||||
gpr_reg0_bits |= USB_CLOCK_MODULE_EN;
|
||||
break;
|
||||
case IMX8MP_HSIOBLK_PD_USB_PHY1:
|
||||
domain = &priv->pd_usb_phy1;
|
||||
break;
|
||||
case IMX8MP_HSIOBLK_PD_USB_PHY2:
|
||||
domain = &priv->pd_usb_phy2;
|
||||
break;
|
||||
case IMX8MP_HSIOBLK_PD_PCIE:
|
||||
domain = &priv->pd_pcie;
|
||||
clk = &priv->clk_pcie;
|
||||
gpr_reg0_bits |= PCIE_CLOCK_MODULE_EN;
|
||||
break;
|
||||
case IMX8MP_HSIOBLK_PD_PCIE_PHY:
|
||||
domain = &priv->pd_pcie_phy;
|
||||
/* Bits to deassert PCIe PHY reset */
|
||||
gpr_reg0_bits |= PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unknown power domain id: %ld\n",
|
||||
power_domain->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (power_on) {
|
||||
ret = power_domain_on(&priv->pd_bus);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) {
|
||||
domain = &priv->pd_usb;
|
||||
} else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY1) {
|
||||
domain = &priv->pd_usb_phy1;
|
||||
} else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY2) {
|
||||
domain = &priv->pd_usb_phy2;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto err_pd;
|
||||
}
|
||||
|
||||
ret = power_domain_on(domain);
|
||||
if (ret)
|
||||
goto err_pd;
|
||||
|
||||
ret = clk_enable(&priv->clk_usb);
|
||||
if (clk) {
|
||||
ret = clk_enable(clk);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
if (power_domain->id == IMX8MP_HSIOBLK_PD_USB)
|
||||
setbits_le32(priv->base + GPR_REG0, USB_CLOCK_MODULE_EN);
|
||||
if (gpr_reg0_bits)
|
||||
setbits_le32(priv->base + GPR_REG0, gpr_reg0_bits);
|
||||
} else {
|
||||
if (gpr_reg0_bits)
|
||||
clrbits_le32(priv->base + GPR_REG0, gpr_reg0_bits);
|
||||
|
||||
if (clk)
|
||||
clk_disable(clk);
|
||||
|
||||
power_domain_off(domain);
|
||||
power_domain_off(&priv->pd_bus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -68,26 +120,14 @@ err_pd:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8mp_hsiomix_on(struct power_domain *power_domain)
|
||||
{
|
||||
return imx8mp_hsiomix_set(power_domain, true);
|
||||
}
|
||||
|
||||
static int imx8mp_hsiomix_off(struct power_domain *power_domain)
|
||||
{
|
||||
struct udevice *dev = power_domain->dev;
|
||||
struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (power_domain->id == IMX8MP_HSIOBLK_PD_USB)
|
||||
clrbits_le32(priv->base + GPR_REG0, USB_CLOCK_MODULE_EN);
|
||||
|
||||
clk_disable(&priv->clk_usb);
|
||||
|
||||
if (power_domain->id == IMX8MP_HSIOBLK_PD_USB)
|
||||
power_domain_off(&priv->pd_usb);
|
||||
else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY1)
|
||||
power_domain_off(&priv->pd_usb_phy1);
|
||||
else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY2)
|
||||
power_domain_off(&priv->pd_usb_phy2);
|
||||
|
||||
power_domain_off(&priv->pd_bus);
|
||||
|
||||
return 0;
|
||||
return imx8mp_hsiomix_set(power_domain, false);
|
||||
}
|
||||
|
||||
static int imx8mp_hsiomix_of_xlate(struct power_domain *power_domain,
|
||||
@@ -98,6 +138,67 @@ static int imx8mp_hsiomix_of_xlate(struct power_domain *power_domain,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hsio_pll_clk_enable(struct clk *clk)
|
||||
{
|
||||
void *base = (void *)dev_get_driver_data(clk->dev);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* Setup HSIO PLL as 100 MHz output clock */
|
||||
clrsetbits_le32(base + GPR_REG2,
|
||||
P_PLL_MASK | M_PLL_MASK | S_PLL_MASK,
|
||||
FIELD_PREP(P_PLL_MASK, 12) |
|
||||
FIELD_PREP(M_PLL_MASK, 800) |
|
||||
FIELD_PREP(S_PLL_MASK, 4));
|
||||
|
||||
/* de-assert PLL reset */
|
||||
setbits_le32(base + GPR_REG3, PLL_RST);
|
||||
|
||||
/* enable PLL */
|
||||
setbits_le32(base + GPR_REG3, PLL_CKE);
|
||||
|
||||
/* Check if PLL is locked */
|
||||
ret = readl_poll_sleep_timeout(base + GPR_REG1, val,
|
||||
val & PLL_LOCK, 10, 100000);
|
||||
if (ret)
|
||||
dev_err(clk->dev, "failed to lock HSIO PLL\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hsio_pll_clk_disable(struct clk *clk)
|
||||
{
|
||||
void *base = (void *)dev_get_driver_data(clk->dev);
|
||||
|
||||
clrbits_le32(base + GPR_REG3, PLL_CKE | PLL_RST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops hsio_pll_clk_ops = {
|
||||
.enable = hsio_pll_clk_enable,
|
||||
.disable = hsio_pll_clk_disable,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(hsio_pll) = {
|
||||
.name = "hsio-pll",
|
||||
.id = UCLASS_CLK,
|
||||
.ops = &hsio_pll_clk_ops,
|
||||
};
|
||||
|
||||
int imx8mp_hsiomix_bind(struct udevice *dev)
|
||||
{
|
||||
struct driver *drv;
|
||||
|
||||
drv = lists_driver_lookup_name("hsio-pll");
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
|
||||
return device_bind_with_driver_data(dev, drv, "hsio-pll",
|
||||
(ulong)dev_read_addr_ptr(dev),
|
||||
dev_ofnode(dev), NULL);
|
||||
}
|
||||
|
||||
static int imx8mp_hsiomix_probe(struct udevice *dev)
|
||||
{
|
||||
struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev);
|
||||
@@ -109,6 +210,10 @@ static int imx8mp_hsiomix_probe(struct udevice *dev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_get_by_name(dev, "pcie", &priv->clk_pcie);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = power_domain_get_by_name(dev, &priv->pd_bus, "bus");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -125,8 +230,20 @@ static int imx8mp_hsiomix_probe(struct udevice *dev)
|
||||
if (ret < 0)
|
||||
goto err_pd_usb_phy2;
|
||||
|
||||
ret = power_domain_get_by_name(dev, &priv->pd_pcie, "pcie");
|
||||
if (ret < 0)
|
||||
goto err_pd_pcie;
|
||||
|
||||
ret = power_domain_get_by_name(dev, &priv->pd_pcie_phy, "pcie-phy");
|
||||
if (ret < 0)
|
||||
goto err_pd_pcie_phy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_pd_pcie_phy:
|
||||
power_domain_free(&priv->pd_pcie);
|
||||
err_pd_pcie:
|
||||
power_domain_free(&priv->pd_usb_phy2);
|
||||
err_pd_usb_phy2:
|
||||
power_domain_free(&priv->pd_usb_phy1);
|
||||
err_pd_usb_phy1:
|
||||
@@ -152,6 +269,7 @@ U_BOOT_DRIVER(imx8mp_hsiomix) = {
|
||||
.id = UCLASS_POWER_DOMAIN,
|
||||
.of_match = imx8mp_hsiomix_ids,
|
||||
.probe = imx8mp_hsiomix_probe,
|
||||
.bind = imx8mp_hsiomix_bind,
|
||||
.priv_auto = sizeof(struct imx8mp_hsiomix_priv),
|
||||
.ops = &imx8mp_hsiomix_ops,
|
||||
};
|
||||
|
@@ -9,12 +9,13 @@
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dt-bindings/reset/imx7-reset.h>
|
||||
#include <dt-bindings/reset/imx8mp-reset.h>
|
||||
#include <dt-bindings/reset/imx8mq-reset.h>
|
||||
#include <reset-uclass.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
struct imx7_reset_priv {
|
||||
struct imx_reset_priv {
|
||||
void __iomem *base;
|
||||
struct reset_ops ops;
|
||||
};
|
||||
@@ -64,9 +65,9 @@ static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = {
|
||||
[IMX7_RESET_DDRC_CORE_RST] = { SRC_DDRC_RCR, BIT(1) },
|
||||
};
|
||||
|
||||
static int imx7_reset_deassert_imx7(struct reset_ctl *rst)
|
||||
static int imx7_reset_deassert(struct reset_ctl *rst)
|
||||
{
|
||||
struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
struct imx_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
const struct imx7_src_signal *sig = imx7_src_signals;
|
||||
u32 val;
|
||||
|
||||
@@ -95,9 +96,9 @@ static int imx7_reset_deassert_imx7(struct reset_ctl *rst)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx7_reset_assert_imx7(struct reset_ctl *rst)
|
||||
static int imx7_reset_assert(struct reset_ctl *rst)
|
||||
{
|
||||
struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
struct imx_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
const struct imx7_src_signal *sig = imx7_src_signals;
|
||||
u32 val;
|
||||
|
||||
@@ -185,9 +186,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
|
||||
[IMX8MQ_RESET_DDRC2_PRST] = { SRC_DDRC2_RCR, BIT(2) },
|
||||
};
|
||||
|
||||
static int imx7_reset_deassert_imx8mq(struct reset_ctl *rst)
|
||||
static int imx8mq_reset_deassert(struct reset_ctl *rst)
|
||||
{
|
||||
struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
struct imx_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
const struct imx7_src_signal *sig = imx8mq_src_signals;
|
||||
u32 val;
|
||||
|
||||
@@ -223,9 +224,9 @@ static int imx7_reset_deassert_imx8mq(struct reset_ctl *rst)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx7_reset_assert_imx8mq(struct reset_ctl *rst)
|
||||
static int imx8mq_reset_assert(struct reset_ctl *rst)
|
||||
{
|
||||
struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
struct imx_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
const struct imx7_src_signal *sig = imx8mq_src_signals;
|
||||
u32 val;
|
||||
|
||||
@@ -252,43 +253,143 @@ static int imx7_reset_assert_imx8mq(struct reset_ctl *rst)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx7_reset_assert(struct reset_ctl *rst)
|
||||
enum imx8mp_src_registers {
|
||||
SRC_SUPERMIX_RCR = 0x0018,
|
||||
SRC_AUDIOMIX_RCR = 0x001c,
|
||||
SRC_MLMIX_RCR = 0x0028,
|
||||
SRC_GPU2D_RCR = 0x0038,
|
||||
SRC_GPU3D_RCR = 0x003c,
|
||||
SRC_VPU_G1_RCR = 0x0048,
|
||||
SRC_VPU_G2_RCR = 0x004c,
|
||||
SRC_VPUVC8KE_RCR = 0x0050,
|
||||
SRC_NOC_RCR = 0x0054,
|
||||
};
|
||||
|
||||
static const struct imx7_src_signal imx8mp_src_signals[IMX8MP_RESET_NUM] = {
|
||||
[IMX8MP_RESET_A53_CORE_POR_RESET0] = { SRC_A53RCR0, BIT(0) },
|
||||
[IMX8MP_RESET_A53_CORE_POR_RESET1] = { SRC_A53RCR0, BIT(1) },
|
||||
[IMX8MP_RESET_A53_CORE_POR_RESET2] = { SRC_A53RCR0, BIT(2) },
|
||||
[IMX8MP_RESET_A53_CORE_POR_RESET3] = { SRC_A53RCR0, BIT(3) },
|
||||
[IMX8MP_RESET_A53_CORE_RESET0] = { SRC_A53RCR0, BIT(4) },
|
||||
[IMX8MP_RESET_A53_CORE_RESET1] = { SRC_A53RCR0, BIT(5) },
|
||||
[IMX8MP_RESET_A53_CORE_RESET2] = { SRC_A53RCR0, BIT(6) },
|
||||
[IMX8MP_RESET_A53_CORE_RESET3] = { SRC_A53RCR0, BIT(7) },
|
||||
[IMX8MP_RESET_A53_DBG_RESET0] = { SRC_A53RCR0, BIT(8) },
|
||||
[IMX8MP_RESET_A53_DBG_RESET1] = { SRC_A53RCR0, BIT(9) },
|
||||
[IMX8MP_RESET_A53_DBG_RESET2] = { SRC_A53RCR0, BIT(10) },
|
||||
[IMX8MP_RESET_A53_DBG_RESET3] = { SRC_A53RCR0, BIT(11) },
|
||||
[IMX8MP_RESET_A53_ETM_RESET0] = { SRC_A53RCR0, BIT(12) },
|
||||
[IMX8MP_RESET_A53_ETM_RESET1] = { SRC_A53RCR0, BIT(13) },
|
||||
[IMX8MP_RESET_A53_ETM_RESET2] = { SRC_A53RCR0, BIT(14) },
|
||||
[IMX8MP_RESET_A53_ETM_RESET3] = { SRC_A53RCR0, BIT(15) },
|
||||
[IMX8MP_RESET_A53_SOC_DBG_RESET] = { SRC_A53RCR0, BIT(20) },
|
||||
[IMX8MP_RESET_A53_L2RESET] = { SRC_A53RCR0, BIT(21) },
|
||||
[IMX8MP_RESET_SW_NON_SCLR_M7C_RST] = { SRC_M4RCR, BIT(0) },
|
||||
[IMX8MP_RESET_OTG1_PHY_RESET] = { SRC_USBOPHY1_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_SUPERMIX_RESET] = { SRC_SUPERMIX_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_AUDIOMIX_RESET] = { SRC_AUDIOMIX_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_MLMIX_RESET] = { SRC_MLMIX_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR, BIT(2) },
|
||||
[IMX8MP_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
|
||||
[IMX8MP_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) },
|
||||
[IMX8MP_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIEPHY_RCR, BIT(11) },
|
||||
[IMX8MP_RESET_HDMI_PHY_APB_RESET] = { SRC_HDMI_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_MEDIA_RESET] = { SRC_DISP_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_GPU2D_RESET] = { SRC_GPU2D_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_GPU3D_RESET] = { SRC_GPU3D_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_GPU_RESET] = { SRC_GPU_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_VPU_RESET] = { SRC_VPU_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_VPU_G1_RESET] = { SRC_VPU_G1_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_VPU_G2_RESET] = { SRC_VPU_G2_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_VPUVC8KE_RESET] = { SRC_VPUVC8KE_RCR, BIT(0) },
|
||||
[IMX8MP_RESET_NOC_RESET] = { SRC_NOC_RCR, BIT(0) },
|
||||
};
|
||||
|
||||
static int imx8mp_reset_set(struct reset_ctl *rst, bool assert)
|
||||
{
|
||||
struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
struct imx_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
unsigned int bit, value;
|
||||
|
||||
if (rst->id >= IMX8MP_RESET_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
bit = imx8mp_src_signals[rst->id].bit;
|
||||
value = assert ? bit : 0;
|
||||
|
||||
switch (rst->id) {
|
||||
case IMX8MP_RESET_PCIEPHY:
|
||||
/*
|
||||
* wait for more than 10us to release phy g_rst and
|
||||
* btnrst
|
||||
*/
|
||||
if (!assert)
|
||||
udelay(10);
|
||||
break;
|
||||
|
||||
case IMX8MP_RESET_PCIE_CTRL_APPS_EN:
|
||||
case IMX8MP_RESET_PCIEPHY_PERST:
|
||||
value = assert ? 0 : bit;
|
||||
break;
|
||||
}
|
||||
|
||||
clrsetbits_le32(priv->base + imx8mp_src_signals[rst->id].offset, bit,
|
||||
value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx8mp_reset_assert(struct reset_ctl *rst)
|
||||
{
|
||||
return imx8mp_reset_set(rst, true);
|
||||
}
|
||||
|
||||
static int imx8mp_reset_deassert(struct reset_ctl *rst)
|
||||
{
|
||||
return imx8mp_reset_set(rst, false);
|
||||
}
|
||||
|
||||
static int imx_reset_assert(struct reset_ctl *rst)
|
||||
{
|
||||
struct imx_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
return priv->ops.rst_assert(rst);
|
||||
}
|
||||
|
||||
static int imx7_reset_deassert(struct reset_ctl *rst)
|
||||
static int imx_reset_deassert(struct reset_ctl *rst)
|
||||
{
|
||||
struct imx7_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
struct imx_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
return priv->ops.rst_deassert(rst);
|
||||
}
|
||||
|
||||
static const struct reset_ops imx7_reset_reset_ops = {
|
||||
.rst_assert = imx7_reset_assert,
|
||||
.rst_deassert = imx7_reset_deassert,
|
||||
.rst_assert = imx_reset_assert,
|
||||
.rst_deassert = imx_reset_deassert,
|
||||
};
|
||||
|
||||
static const struct udevice_id imx7_reset_ids[] = {
|
||||
{ .compatible = "fsl,imx7d-src" },
|
||||
{ .compatible = "fsl,imx8mq-src" },
|
||||
{ .compatible = "fsl,imx8mp-src" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int imx7_reset_probe(struct udevice *dev)
|
||||
{
|
||||
struct imx7_reset_priv *priv = dev_get_priv(dev);
|
||||
struct imx_reset_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->base = dev_remap_addr(dev);
|
||||
if (!priv->base)
|
||||
return -ENOMEM;
|
||||
|
||||
if (device_is_compatible(dev, "fsl,imx8mq-src")) {
|
||||
priv->ops.rst_assert = imx7_reset_assert_imx8mq;
|
||||
priv->ops.rst_deassert = imx7_reset_deassert_imx8mq;
|
||||
priv->ops.rst_assert = imx8mq_reset_assert;
|
||||
priv->ops.rst_deassert = imx8mq_reset_deassert;
|
||||
} else if (device_is_compatible(dev, "fsl,imx7d-src")) {
|
||||
priv->ops.rst_assert = imx7_reset_assert_imx7;
|
||||
priv->ops.rst_deassert = imx7_reset_deassert_imx7;
|
||||
priv->ops.rst_assert = imx7_reset_assert;
|
||||
priv->ops.rst_deassert = imx7_reset_deassert;
|
||||
} else if (device_is_compatible(dev, "fsl,imx8mp-src")) {
|
||||
priv->ops.rst_assert = imx8mp_reset_assert;
|
||||
priv->ops.rst_deassert = imx8mp_reset_deassert;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -300,5 +401,5 @@ U_BOOT_DRIVER(imx7_reset) = {
|
||||
.of_match = imx7_reset_ids,
|
||||
.ops = &imx7_reset_reset_ops,
|
||||
.probe = imx7_reset_probe,
|
||||
.priv_auto = sizeof(struct imx7_reset_priv),
|
||||
.priv_auto = sizeof(struct imx_reset_priv),
|
||||
};
|
||||
|
Reference in New Issue
Block a user