summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2026-04-13 12:50:53 -0500
committerBjorn Helgaas <bhelgaas@google.com>2026-04-13 12:50:53 -0500
commitb274423c79277a34521a7553d07e3dc25b0b96c6 (patch)
tree308b62354bcc679da7131c661a8bec3f2930b54c /drivers/pci
parentd096bd7d8bf75a09d6d10438449e0c33d5f51081 (diff)
parent8197ec49a2062185f6bd432a19969ce0b3752e94 (diff)
downloadlinux-next-b274423c79277a34521a7553d07e3dc25b0b96c6.tar.gz
linux-next-b274423c79277a34521a7553d07e3dc25b0b96c6.zip
Merge branch 'pci/controller/rzg3s-host'
- Assert (not deassert) resets in probe error path (John Madieu) - Assert resets in suspend path in reverse order they were deasserted during probe (John Madieu) - Rework inbound window algorithm to prevent mapping more than intended region and enforce alignment on size, to prepare for RZ/G3E support (John Madieu) - Fix renesas,r9a08g045s33-pcie 'serr_cor' typo and convert properties from 'description' to 'const' for better validation (John Madieu) - Add RZ/G3E to DT binding and to driver (John Madieu) * pci/controller/rzg3s-host: PCI: rzg3s-host: Add support for RZ/G3E PCIe controller PCI: rzg3s-host: Add PCIe Gen3 (8.0 GT/s) link speed support PCI: rzg3s-host: Explicitly set class code for RZ/G3E compatibility PCI: rzg3s-host: Add SoC-specific configuration and initialization callbacks PCI: rzg3s-host: Make configuration reset lines optional PCI: rzg3s-host: Make SYSC register offsets SoC-specific dt-bindings: PCI: renesas,r9a08g045s33-pcie: Document RZ/G3E SoC dt-bindings: PCI: renesas,r9a08g045s33-pcie: Fix naming properties PCI: rzg3s-host: Rework inbound window algorithm for supporting RZ/G3E SoC PCI: rzg3s-host: Reorder reset assertion during suspend PCI: rzg3s-host: Fix reset handling in probe error path # Conflicts: # drivers/pci/controller/pcie-rzg3s-host.c
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/controller/pcie-rzg3s-host.c365
1 files changed, 285 insertions, 80 deletions
diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 00a11f986117..d86e7516dcc2 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -111,6 +111,15 @@
#define RZG3S_PCI_PERM_CFG_HWINIT_EN BIT(2)
#define RZG3S_PCI_PERM_PIPE_PHY_REG_EN BIT(1)
+#define RZG3S_PCI_RESET 0x310
+#define RZG3S_PCI_RESET_RST_OUT_B BIT(6)
+#define RZG3S_PCI_RESET_RST_PS_B BIT(5)
+#define RZG3S_PCI_RESET_RST_LOAD_B BIT(4)
+#define RZG3S_PCI_RESET_RST_CFG_B BIT(3)
+#define RZG3S_PCI_RESET_RST_RSM_B BIT(2)
+#define RZG3S_PCI_RESET_RST_GP_B BIT(1)
+#define RZG3S_PCI_RESET_RST_B BIT(0)
+
#define RZG3S_PCI_MSIRE(id) (0x600 + (id) * 0x10)
#define RZG3S_PCI_MSIRE_ENA BIT(0)
@@ -159,10 +168,6 @@
#define RZG3S_PCI_CFG_PCIEC 0x60
-/* System controller registers */
-#define RZG3S_SYS_PCIE_RST_RSM_B 0xd74
-#define RZG3S_SYS_PCIE_RST_RSM_B_MASK BIT(0)
-
/* Maximum number of windows */
#define RZG3S_MAX_WINDOWS 8
@@ -175,6 +180,48 @@
#define RZG3S_REQ_ISSUE_TIMEOUT_US 2500
/**
+ * struct rzg3s_sysc_function - System Controller function descriptor
+ * @offset: Register offset from the System Controller base address
+ * @mask: Bit mask for the function within the register
+ */
+struct rzg3s_sysc_function {
+ u32 offset;
+ u32 mask;
+};
+
+/**
+ * enum rzg3s_sysc_func_id - System controller function IDs
+ * @RZG3S_SYSC_FUNC_ID_RST_RSM_B: RST_RSM_B SYSC function ID
+ * @RZG3S_SYSC_FUNC_ID_L1_ALLOW: L1 allow SYSC function ID
+ * @RZG3S_SYSC_FUNC_ID_MODE: Mode SYSC function ID
+ * @RZG3S_SYSC_FUNC_ID_MAX: Max SYSC function ID
+ */
+enum rzg3s_sysc_func_id {
+ RZG3S_SYSC_FUNC_ID_RST_RSM_B,
+ RZG3S_SYSC_FUNC_ID_L1_ALLOW,
+ RZG3S_SYSC_FUNC_ID_MODE,
+ RZG3S_SYSC_FUNC_ID_MAX,
+};
+
+/**
+ * struct rzg3s_sysc_info - RZ/G3S System Controller info
+ * @functions: SYSC function descriptors array
+ */
+struct rzg3s_sysc_info {
+ const struct rzg3s_sysc_function functions[RZG3S_SYSC_FUNC_ID_MAX];
+};
+
+/**
+ * struct rzg3s_sysc - RZ/G3S System Controller descriptor
+ * @regmap: System controller regmap
+ * @info: System controller info
+ */
+struct rzg3s_sysc {
+ struct regmap *regmap;
+ const struct rzg3s_sysc_info *info;
+};
+
+/**
* struct rzg3s_pcie_msi - RZ/G3S PCIe MSI data structure
* @domain: IRQ domain
* @map: bitmap with the allocated MSIs
@@ -199,17 +246,25 @@ struct rzg3s_pcie_host;
/**
* struct rzg3s_pcie_soc_data - SoC specific data
* @init_phy: PHY initialization function
+ * @config_pre_init: Optional callback for SoC-specific pre-configuration
+ * @config_post_init: Callback for SoC-specific post-configuration
+ * @config_deinit: Callback for SoC-specific de-initialization
* @power_resets: array with the resets that need to be de-asserted after
* power-on
* @cfg_resets: array with the resets that need to be de-asserted after
* configuration
+ * @sysc_info: SYSC info
* @num_power_resets: number of power resets
* @num_cfg_resets: number of configuration resets
*/
struct rzg3s_pcie_soc_data {
int (*init_phy)(struct rzg3s_pcie_host *host);
+ void (*config_pre_init)(struct rzg3s_pcie_host *host);
+ int (*config_post_init)(struct rzg3s_pcie_host *host);
+ int (*config_deinit)(struct rzg3s_pcie_host *host);
const char * const *power_resets;
const char * const *cfg_resets;
+ struct rzg3s_sysc_info sysc_info;
u8 num_power_resets;
u8 num_cfg_resets;
};
@@ -233,7 +288,7 @@ struct rzg3s_pcie_port {
* @dev: struct device
* @power_resets: reset control signals that should be set after power up
* @cfg_resets: reset control signals that should be set after configuration
- * @sysc: SYSC regmap
+ * @sysc: SYSC descriptor
* @intx_domain: INTx IRQ domain
* @data: SoC specific data
* @msi: MSI data structure
@@ -248,7 +303,7 @@ struct rzg3s_pcie_host {
struct device *dev;
struct reset_control_bulk_data *power_resets;
struct reset_control_bulk_data *cfg_resets;
- struct regmap *sysc;
+ struct rzg3s_sysc *sysc;
struct irq_domain *intx_domain;
const struct rzg3s_pcie_soc_data *data;
struct rzg3s_pcie_msi msi;
@@ -260,6 +315,23 @@ struct rzg3s_pcie_host {
#define rzg3s_msi_to_host(_msi) container_of(_msi, struct rzg3s_pcie_host, msi)
+static int rzg3s_sysc_config_func(struct rzg3s_sysc *sysc,
+ enum rzg3s_sysc_func_id fid, u32 val)
+{
+ const struct rzg3s_sysc_info *info = sysc->info;
+ const struct rzg3s_sysc_function *functions = info->functions;
+
+ if (fid >= RZG3S_SYSC_FUNC_ID_MAX)
+ return -EINVAL;
+
+ if (!functions[fid].mask)
+ return 0;
+
+ return regmap_update_bits(sysc->regmap, functions[fid].offset,
+ functions[fid].mask,
+ field_prep(functions[fid].mask, val));
+}
+
static void rzg3s_pcie_update_bits(void __iomem *base, u32 offset, u32 mask,
u32 val)
{
@@ -945,8 +1017,9 @@ static int rzg3s_pcie_set_max_link_speed(struct rzg3s_pcie_host *host)
{
u32 remote_supported_link_speeds, max_supported_link_speeds;
u32 cs2, tmp, pcie_cap = RZG3S_PCI_CFG_PCIEC;
- u32 cur_link_speed, link_speed;
+ u32 cur_link_speed, link_speed, hw_max_speed;
u8 ltssm_state_l0 = 0xc;
+ u32 lnkcap;
int ret;
u16 ls;
@@ -966,7 +1039,22 @@ static int rzg3s_pcie_set_max_link_speed(struct rzg3s_pcie_host *host)
ls = readw_relaxed(host->pcie + pcie_cap + PCI_EXP_LNKSTA);
cs2 = readl_relaxed(host->axi + RZG3S_PCI_PCSTAT2);
- switch (pcie_get_link_speed(host->max_link_speed)) {
+ /* Read hardware supported link speed from Link Capabilities Register */
+ lnkcap = readl_relaxed(host->pcie + pcie_cap + PCI_EXP_LNKCAP);
+ hw_max_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, lnkcap);
+
+ /*
+ * Use DT max-link-speed only as a limit. If specified and lower
+ * than hardware capability, cap to that value.
+ */
+ if (host->max_link_speed > 0 && host->max_link_speed < hw_max_speed)
+ hw_max_speed = host->max_link_speed;
+
+ switch (pcie_get_link_speed(hw_max_speed)) {
+ case PCIE_SPEED_8_0GT:
+ max_supported_link_speeds = GENMASK(PCI_EXP_LNKSTA_CLS_8_0GB - 1, 0);
+ link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT;
+ break;
case PCIE_SPEED_5_0GT:
max_supported_link_speeds = GENMASK(PCI_EXP_LNKSTA_CLS_5_0GB - 1, 0);
link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;
@@ -982,10 +1070,10 @@ static int rzg3s_pcie_set_max_link_speed(struct rzg3s_pcie_host *host)
remote_supported_link_speeds &= max_supported_link_speeds;
/*
- * Return if max link speed is already set or the connected device
+ * Return if target link speed is already set or the connected device
* doesn't support it.
*/
- if (cur_link_speed == host->max_link_speed ||
+ if (cur_link_speed == hw_max_speed ||
remote_supported_link_speeds != max_supported_link_speeds)
return 0;
@@ -1022,6 +1110,7 @@ static int rzg3s_pcie_set_max_link_speed(struct rzg3s_pcie_host *host)
static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host)
{
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
+ u32 mask = GENMASK(31, 8);
struct resource_entry *ft;
struct resource *bus;
u8 subordinate_bus;
@@ -1045,6 +1134,13 @@ static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host)
writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
+ /*
+ * Explicitly program class code. RZ/G3E requires this configuration.
+ * Harmless for RZ/G3S where this matches the hardware default.
+ */
+ rzg3s_pcie_update_bits(host->pcie, PCI_CLASS_REVISION, mask,
+ field_prep(mask, PCI_CLASS_BRIDGE_PCI_NORMAL));
+
/* Disable access control to the CFGU */
writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
@@ -1056,6 +1152,57 @@ static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host)
return 0;
}
+static int rzg3s_pcie_config_post_init(struct rzg3s_pcie_host *host)
+{
+ return reset_control_bulk_deassert(host->data->num_cfg_resets,
+ host->cfg_resets);
+}
+
+static int rzg3s_pcie_config_deinit(struct rzg3s_pcie_host *host)
+{
+ return reset_control_bulk_assert(host->data->num_cfg_resets,
+ host->cfg_resets);
+}
+
+static void rzg3e_pcie_config_pre_init(struct rzg3s_pcie_host *host)
+{
+ u32 mask = RZG3S_PCI_RESET_RST_LOAD_B | RZG3S_PCI_RESET_RST_CFG_B;
+
+ /* De-assert LOAD_B and CFG_B */
+ rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_RESET, mask, mask);
+}
+
+static int rzg3e_pcie_config_deinit(struct rzg3s_pcie_host *host)
+{
+ writel_relaxed(0, host->axi + RZG3S_PCI_RESET);
+ return 0;
+}
+
+static int rzg3e_pcie_config_post_init(struct rzg3s_pcie_host *host)
+{
+ u32 mask = RZG3S_PCI_RESET_RST_PS_B | RZG3S_PCI_RESET_RST_GP_B |
+ RZG3S_PCI_RESET_RST_B;
+
+ /* De-assert PS_B, GP_B, RST_B */
+ rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_RESET, mask, mask);
+
+ /* Flush deassert */
+ readl_relaxed(host->axi + RZG3S_PCI_RESET);
+
+ /*
+ * According to the RZ/G3E HW manual (Rev.1.15, Table 6.6-130
+ * Initialization Procedure (RC)), hardware requires >= 500us delay
+ * before final reset deassert.
+ */
+ fsleep(500);
+
+ /* De-assert OUT_B and RSM_B */
+ mask = RZG3S_PCI_RESET_RST_OUT_B | RZG3S_PCI_RESET_RST_RSM_B;
+ rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_RESET, mask, mask);
+
+ return 0;
+}
+
static void rzg3s_pcie_irq_init(struct rzg3s_pcie_host *host)
{
/*
@@ -1135,9 +1282,9 @@ static int rzg3s_pcie_resets_prepare_and_get(struct rzg3s_pcie_host *host)
if (ret)
return ret;
- return devm_reset_control_bulk_get_exclusive(host->dev,
- data->num_cfg_resets,
- host->cfg_resets);
+ return devm_reset_control_bulk_get_optional_exclusive(host->dev,
+ data->num_cfg_resets,
+ host->cfg_resets);
}
static int rzg3s_pcie_host_parse_port(struct rzg3s_pcie_host *host)
@@ -1204,22 +1351,32 @@ static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host)
u32 val;
int ret;
+ /* SoC-specific pre-configuration */
+ if (host->data->config_pre_init)
+ host->data->config_pre_init(host);
+
/* Initialize the PCIe related registers */
ret = rzg3s_pcie_config_init(host);
if (ret)
- return ret;
+ goto config_deinit;
ret = rzg3s_pcie_host_init_port(host);
if (ret)
- return ret;
+ goto config_deinit;
+
+ /* Enable ASPM L1 transition for SoCs that use it */
+ ret = rzg3s_sysc_config_func(host->sysc,
+ RZG3S_SYSC_FUNC_ID_L1_ALLOW, 1);
+ if (ret)
+ goto config_deinit_and_refclk;
/* Initialize the interrupts */
rzg3s_pcie_irq_init(host);
- ret = reset_control_bulk_deassert(host->data->num_cfg_resets,
- host->cfg_resets);
+ /* SoC-specific post-configuration */
+ ret = host->data->config_post_init(host);
if (ret)
- goto disable_port_refclk;
+ goto config_deinit_and_refclk;
/* Wait for link up */
ret = readl_poll_timeout(host->axi + RZG3S_PCI_PCSTAT1, val,
@@ -1228,18 +1385,20 @@ static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host)
PCIE_LINK_WAIT_SLEEP_MS * MILLI *
PCIE_LINK_WAIT_MAX_RETRIES);
if (ret)
- goto cfg_resets_deassert;
+ goto config_deinit_post;
val = readl_relaxed(host->axi + RZG3S_PCI_PCSTAT2);
dev_info(host->dev, "PCIe link status [0x%x]\n", val);
return 0;
-cfg_resets_deassert:
- reset_control_bulk_assert(host->data->num_cfg_resets,
- host->cfg_resets);
-disable_port_refclk:
+config_deinit_post:
+ host->data->config_deinit(host);
+config_deinit_and_refclk:
clk_disable_unprepare(host->port.refclk);
+config_deinit:
+ if (host->data->config_pre_init)
+ host->data->config_deinit(host);
return ret;
}
@@ -1271,50 +1430,55 @@ static int rzg3s_pcie_set_inbound_windows(struct rzg3s_pcie_host *host,
u64 pci_addr = entry->res->start - entry->offset;
u64 cpu_addr = entry->res->start;
u64 cpu_end = entry->res->end;
- u64 size_id = 0;
int id = *index;
u64 size;
- while (cpu_addr < cpu_end) {
+ /*
+ * According to the RZ/G3S HW manual (Rev.1.10, section 34.6.6.7) and
+ * RZ/G3E HW manual (Rev.1.15, section 6.6.7.6):
+ * - Each window must be a single memory size of power of two
+ * - Mask registers must be set to (2^N - 1)
+ * - Bit carry must not occur when adding base and mask registers,
+ * meaning the base address must be aligned to the window size
+ *
+ * Split non-power-of-2 regions into multiple windows to satisfy
+ * these constraints without over-mapping.
+ */
+ while (cpu_addr <= cpu_end) {
+ u64 remaining_size = cpu_end - cpu_addr + 1;
+ u64 align_limit;
+
if (id >= RZG3S_MAX_WINDOWS)
return dev_err_probe(host->dev, -ENOSPC,
"Failed to map inbound window for resource (%s)\n",
entry->res->name);
- size = resource_size(entry->res) - size_id;
-
- /*
- * According to the RZ/G3S HW manual (Rev.1.10,
- * section 34.3.1.71 AXI Window Mask (Lower) Registers) the min
- * size is 4K.
- */
- size = max(size, SZ_4K);
+ /* Start with largest power-of-two that fits in remaining size */
+ size = 1ULL << __fls(remaining_size);
/*
- * According the RZ/G3S HW manual (Rev.1.10, sections:
- * - 34.3.1.69 AXI Window Base (Lower) Registers
- * - 34.3.1.71 AXI Window Mask (Lower) Registers
- * - 34.3.1.73 AXI Destination (Lower) Registers)
- * the CPU addr, PCIe addr, size should be 4K aligned and be a
- * power of 2.
+ * The "no bit carry" rule requires base addresses to be
+ * aligned to the window size. Find the maximum window size
+ * that both addresses can support based on their natural
+ * alignment (lowest set bit).
*/
- size = ALIGN(size, SZ_4K);
- size = roundup_pow_of_two(size);
+ align_limit = min(cpu_addr ? (1ULL << __ffs(cpu_addr)) : ~0ULL,
+ pci_addr ? (1ULL << __ffs(pci_addr)) : ~0ULL);
- cpu_addr = ALIGN(cpu_addr, SZ_4K);
- pci_addr = ALIGN(pci_addr, SZ_4K);
+ size = min(size, align_limit);
/*
- * According to the RZ/G3S HW manual (Rev.1.10, section
- * 34.3.1.71 AXI Window Mask (Lower) Registers) HW expects first
- * 12 LSB bits to be 0xfff. Subtract 1 from size for this.
+ * Minimum window size is 4KB.
+ * See RZ/G3S HW manual (Rev.1.10, section 34.3.1.71) and
+ * RZ/G3E HW manual (Rev.1.15, section 6.6.4.1.3.(74)).
*/
+ size = max(size, SZ_4K);
+
rzg3s_pcie_set_inbound_window(host, cpu_addr, pci_addr,
size - 1, id);
pci_addr += size;
cpu_addr += size;
- size_id = size;
id++;
}
*index = id;
@@ -1517,6 +1681,7 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
struct device_node *sysc_np __free(device_node) =
of_parse_phandle(np, "renesas,sysc", 0);
struct rzg3s_pcie_host *host;
+ struct rzg3s_sysc *sysc;
int ret;
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*host));
@@ -1528,28 +1693,36 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
host->data = device_get_match_data(dev);
platform_set_drvdata(pdev, host);
+ host->sysc = devm_kzalloc(dev, sizeof(*host->sysc), GFP_KERNEL);
+ if (!host->sysc)
+ return -ENOMEM;
+
+ sysc = host->sysc;
+ sysc->info = &host->data->sysc_info;
+
host->axi = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(host->axi))
return PTR_ERR(host->axi);
host->pcie = host->axi + RZG3S_PCI_CFG_BASE;
host->max_link_speed = of_pci_get_max_link_speed(np);
- if (host->max_link_speed < 0)
- host->max_link_speed = 2;
ret = rzg3s_pcie_host_parse_port(host);
if (ret)
return ret;
- host->sysc = syscon_node_to_regmap(sysc_np);
- if (IS_ERR(host->sysc)) {
- ret = PTR_ERR(host->sysc);
+ sysc->regmap = syscon_node_to_regmap(sysc_np);
+ if (IS_ERR(sysc->regmap)) {
+ ret = PTR_ERR(sysc->regmap);
goto port_refclk_put;
}
- ret = regmap_update_bits(host->sysc, RZG3S_SYS_PCIE_RST_RSM_B,
- RZG3S_SYS_PCIE_RST_RSM_B_MASK,
- FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 1));
+ /* Put controller in RC mode */
+ ret = rzg3s_sysc_config_func(sysc, RZG3S_SYSC_FUNC_ID_MODE, 1);
+ if (ret)
+ goto port_refclk_put;
+
+ ret = rzg3s_sysc_config_func(sysc, RZG3S_SYSC_FUNC_ID_RST_RSM_B, 1);
if (ret)
goto port_refclk_put;
@@ -1589,8 +1762,7 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
host_probe_teardown:
rzg3s_pcie_teardown_irqdomain(host);
- reset_control_bulk_deassert(host->data->num_cfg_resets,
- host->cfg_resets);
+ host->data->config_deinit(host);
rpm_put:
pm_runtime_put_sync(dev);
rpm_disable:
@@ -1602,9 +1774,7 @@ sysc_signal_restore:
* SYSC RST_RSM_B signal need to be asserted before turning off the
* power to the PHY.
*/
- regmap_update_bits(host->sysc, RZG3S_SYS_PCIE_RST_RSM_B,
- RZG3S_SYS_PCIE_RST_RSM_B_MASK,
- FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 0));
+ rzg3s_sysc_config_func(sysc, RZG3S_SYSC_FUNC_ID_RST_RSM_B, 0);
port_refclk_put:
clk_put(host->port.refclk);
@@ -1616,7 +1786,7 @@ static int rzg3s_pcie_suspend_noirq(struct device *dev)
struct rzg3s_pcie_host *host = dev_get_drvdata(dev);
const struct rzg3s_pcie_soc_data *data = host->data;
struct rzg3s_pcie_port *port = &host->port;
- struct regmap *sysc = host->sysc;
+ struct rzg3s_sysc *sysc = host->sysc;
int ret;
ret = pm_runtime_put_sync(dev);
@@ -1625,31 +1795,30 @@ static int rzg3s_pcie_suspend_noirq(struct device *dev)
clk_disable_unprepare(port->refclk);
- ret = reset_control_bulk_assert(data->num_power_resets,
- host->power_resets);
+ /* SoC-specific de-initialization */
+ ret = data->config_deinit(host);
if (ret)
goto refclk_restore;
- ret = reset_control_bulk_assert(data->num_cfg_resets,
- host->cfg_resets);
+ ret = reset_control_bulk_assert(data->num_power_resets,
+ host->power_resets);
if (ret)
- goto power_resets_restore;
+ goto config_reinit;
- ret = regmap_update_bits(sysc, RZG3S_SYS_PCIE_RST_RSM_B,
- RZG3S_SYS_PCIE_RST_RSM_B_MASK,
- FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 0));
+ ret = rzg3s_sysc_config_func(sysc, RZG3S_SYSC_FUNC_ID_RST_RSM_B, 0);
if (ret)
- goto cfg_resets_restore;
+ goto power_resets_restore;
return 0;
/* Restore the previous state if any error happens */
-cfg_resets_restore:
- reset_control_bulk_deassert(data->num_cfg_resets,
- host->cfg_resets);
power_resets_restore:
reset_control_bulk_deassert(data->num_power_resets,
host->power_resets);
+config_reinit:
+ if (data->config_pre_init)
+ data->config_pre_init(host);
+ data->config_post_init(host);
refclk_restore:
clk_prepare_enable(port->refclk);
pm_runtime_resume_and_get(dev);
@@ -1660,12 +1829,14 @@ static int rzg3s_pcie_resume_noirq(struct device *dev)
{
struct rzg3s_pcie_host *host = dev_get_drvdata(dev);
const struct rzg3s_pcie_soc_data *data = host->data;
- struct regmap *sysc = host->sysc;
+ struct rzg3s_sysc *sysc = host->sysc;
int ret;
- ret = regmap_update_bits(sysc, RZG3S_SYS_PCIE_RST_RSM_B,
- RZG3S_SYS_PCIE_RST_RSM_B_MASK,
- FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 1));
+ ret = rzg3s_sysc_config_func(sysc, RZG3S_SYSC_FUNC_ID_MODE, 1);
+ if (ret)
+ return ret;
+
+ ret = rzg3s_sysc_config_func(sysc, RZG3S_SYSC_FUNC_ID_RST_RSM_B, 1);
if (ret)
return ret;
@@ -1694,9 +1865,7 @@ assert_power_resets:
reset_control_bulk_assert(data->num_power_resets,
host->power_resets);
assert_rst_rsm_b:
- regmap_update_bits(sysc, RZG3S_SYS_PCIE_RST_RSM_B,
- RZG3S_SYS_PCIE_RST_RSM_B_MASK,
- FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 0));
+ rzg3s_sysc_config_func(sysc, RZG3S_SYSC_FUNC_ID_RST_RSM_B, 0);
return ret;
}
@@ -1718,7 +1887,39 @@ static const struct rzg3s_pcie_soc_data rzg3s_soc_data = {
.num_power_resets = ARRAY_SIZE(rzg3s_soc_power_resets),
.cfg_resets = rzg3s_soc_cfg_resets,
.num_cfg_resets = ARRAY_SIZE(rzg3s_soc_cfg_resets),
+ .config_post_init = rzg3s_pcie_config_post_init,
+ .config_deinit = rzg3s_pcie_config_deinit,
.init_phy = rzg3s_soc_pcie_init_phy,
+ .sysc_info = {
+ .functions = {
+ [RZG3S_SYSC_FUNC_ID_RST_RSM_B] = {
+ .offset = 0xd74,
+ .mask = BIT(0),
+ },
+ },
+ },
+};
+
+static const char * const rzg3e_soc_power_resets[] = { "aresetn" };
+
+static const struct rzg3s_pcie_soc_data rzg3e_soc_data = {
+ .power_resets = rzg3e_soc_power_resets,
+ .num_power_resets = ARRAY_SIZE(rzg3e_soc_power_resets),
+ .config_pre_init = rzg3e_pcie_config_pre_init,
+ .config_post_init = rzg3e_pcie_config_post_init,
+ .config_deinit = rzg3e_pcie_config_deinit,
+ .sysc_info = {
+ .functions = {
+ [RZG3S_SYSC_FUNC_ID_L1_ALLOW] = {
+ .offset = 0x1020,
+ .mask = BIT(0),
+ },
+ [RZG3S_SYSC_FUNC_ID_MODE] = {
+ .offset = 0x1024,
+ .mask = BIT(0),
+ },
+ },
+ },
};
static const struct of_device_id rzg3s_pcie_of_match[] = {
@@ -1726,6 +1927,10 @@ static const struct of_device_id rzg3s_pcie_of_match[] = {
.compatible = "renesas,r9a08g045-pcie",
.data = &rzg3s_soc_data,
},
+ {
+ .compatible = "renesas,r9a09g047-pcie",
+ .data = &rzg3e_soc_data,
+ },
{}
};