mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -174,6 +179,48 @@
|
||||
/* Timeouts experimentally determined */
|
||||
#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
|
||||
@@ -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;
|
||||
/* Start with largest power-of-two that fits in remaining size */
|
||||
size = 1ULL << __fls(remaining_size);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* 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).
|
||||
*/
|
||||
align_limit = min(cpu_addr ? (1ULL << __ffs(cpu_addr)) : ~0ULL,
|
||||
pci_addr ? (1ULL << __ffs(pci_addr)) : ~0ULL);
|
||||
|
||||
size = min(size, align_limit);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
size = ALIGN(size, SZ_4K);
|
||||
size = roundup_pow_of_two(size);
|
||||
|
||||
cpu_addr = ALIGN(cpu_addr, SZ_4K);
|
||||
pci_addr = ALIGN(pci_addr, SZ_4K);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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 config_reinit;
|
||||
|
||||
ret = rzg3s_sysc_config_func(sysc, RZG3S_SYSC_FUNC_ID_RST_RSM_B, 0);
|
||||
if (ret)
|
||||
goto power_resets_restore;
|
||||
|
||||
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));
|
||||
if (ret)
|
||||
goto cfg_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,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user