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:
Tom Rini
2024-03-24 17:49:42 -04:00
19 changed files with 1051 additions and 61 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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",
""
);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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));

View File

@@ -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;

View File

@@ -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

View File

@@ -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
View 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),
};

View File

@@ -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>

View File

@@ -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

View File

@@ -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/

View 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),
};

View File

@@ -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;
ret = power_domain_on(&priv->pd_bus);
if (ret)
return ret;
if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) {
switch (power_domain->id) {
case IMX8MP_HSIOBLK_PD_USB:
domain = &priv->pd_usb;
} else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY1) {
clk = &priv->clk_usb;
gpr_reg0_bits |= USB_CLOCK_MODULE_EN;
break;
case IMX8MP_HSIOBLK_PD_USB_PHY1:
domain = &priv->pd_usb_phy1;
} else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY2) {
break;
case IMX8MP_HSIOBLK_PD_USB_PHY2:
domain = &priv->pd_usb_phy2;
} else {
ret = -EINVAL;
goto err_pd;
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;
}
ret = power_domain_on(domain);
if (ret)
goto err_pd;
if (power_on) {
ret = power_domain_on(&priv->pd_bus);
if (ret)
return ret;
ret = clk_enable(&priv->clk_usb);
if (ret)
goto err_clk;
ret = power_domain_on(domain);
if (ret)
goto err_pd;
if (power_domain->id == IMX8MP_HSIOBLK_PD_USB)
setbits_le32(priv->base + GPR_REG0, USB_CLOCK_MODULE_EN);
if (clk) {
ret = clk_enable(clk);
if (ret)
goto err_clk;
}
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,
};

View File

@@ -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),
};