mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
Merge branch 'pci/controller/rzg3s-host'
- Add DT binding and driver support for RZ/V2H(P) SoC, which contains two PCIe controllers, configured either as a single x4 link or two independent x2 link controllers (Lad Prabhakar) * pci/controller/rzg3s-host: PCI: rzg3s-host: Add support for RZ/V2H(P) SoC PCI: rzg3s-host: Prepare System Controller handling for multiple controllers PCI: rzg3s-host: Use shared reset controls for power domain resets dt-bindings: PCI: renesas,r9a08g045-pcie: Add RZ/V2H(P) support
This commit is contained in:
@@ -14,7 +14,7 @@ description: |
|
||||
with PCIe Base Specification 4.0 and supports different link speeds
|
||||
depending on the SoC variant:
|
||||
- Gen2 (5 GT/s): RZ/G3S
|
||||
- Gen3 (8 GT/s): RZ/G3E, RZ/V2N
|
||||
- Gen3 (8 GT/s): RZ/G3E, RZ/V2H(P), RZ/V2N
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@@ -22,6 +22,7 @@ properties:
|
||||
- enum:
|
||||
- renesas,r9a08g045-pcie # RZ/G3S
|
||||
- renesas,r9a09g047-pcie # RZ/G3E
|
||||
- renesas,r9a09g057-pcie # RZ/V2H(P)
|
||||
- items:
|
||||
- const: renesas,r9a09g056-pcie # RZ/V2N
|
||||
- const: renesas,r9a09g047-pcie
|
||||
@@ -139,7 +140,13 @@ properties:
|
||||
- clkl1pm clock request state
|
||||
- power off information in L2 state
|
||||
- errors (fatal, non-fatal, correctable)
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- items:
|
||||
- description: Phandle to system controller
|
||||
- description: PCIe controller index
|
||||
enum: [0, 1]
|
||||
minItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^pcie@0,[0-0]$":
|
||||
@@ -220,7 +227,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g047-pcie
|
||||
enum:
|
||||
- renesas,r9a09g047-pcie
|
||||
- renesas,r9a09g057-pcie
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
@@ -235,6 +244,25 @@ allOf:
|
||||
maxItems: 1
|
||||
reset-names:
|
||||
maxItems: 1
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g057-pcie
|
||||
then:
|
||||
properties:
|
||||
num-lanes:
|
||||
enum: [2, 4]
|
||||
renesas,sysc:
|
||||
items:
|
||||
- minItems: 2
|
||||
required:
|
||||
- num-lanes
|
||||
else:
|
||||
properties:
|
||||
renesas,sysc:
|
||||
items:
|
||||
- maxItems: 1
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
||||
@@ -180,6 +180,16 @@
|
||||
/* Timeouts experimentally determined */
|
||||
#define RZG3S_REQ_ISSUE_TIMEOUT_US 2500
|
||||
|
||||
/**
|
||||
* enum rzg3s_sysc_link_mode - PCIe link configuration modes
|
||||
* @RZG3S_SYSC_LINK_MODE_SINGLE_X4: Single port with x4 lanes
|
||||
* @RZG3S_SYSC_LINK_MODE_DUAL_X2: Dual ports with x2 lanes each
|
||||
*/
|
||||
enum rzg3s_sysc_link_mode {
|
||||
RZG3S_SYSC_LINK_MODE_SINGLE_X4 = 1,
|
||||
RZG3S_SYSC_LINK_MODE_DUAL_X2 = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rzg3s_sysc_function - System Controller function descriptor
|
||||
* @offset: Register offset from the System Controller base address
|
||||
@@ -195,12 +205,14 @@ struct rzg3s_sysc_function {
|
||||
* @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_LINK_MASTER: Link master 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_LINK_MASTER,
|
||||
RZG3S_SYSC_FUNC_ID_MAX,
|
||||
};
|
||||
|
||||
@@ -242,6 +254,18 @@ struct rzg3s_pcie_msi {
|
||||
int irq;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum rzg3s_pcie_controller_id - RZ/G3S PCIe controller IDs
|
||||
* @RZG3S_PCIE_CONTROLLER_ID_0: PCIe controller 0
|
||||
* @RZG3S_PCIE_CONTROLLER_ID_1: PCIe controller 1
|
||||
* @RZG3S_PCIE_CONTROLLER_ID_MAX: Max PCIe controllers
|
||||
*/
|
||||
enum rzg3s_pcie_controller_id {
|
||||
RZG3S_PCIE_CONTROLLER_ID_0,
|
||||
RZG3S_PCIE_CONTROLLER_ID_1,
|
||||
RZG3S_PCIE_CONTROLLER_ID_MAX,
|
||||
};
|
||||
|
||||
struct rzg3s_pcie_host;
|
||||
|
||||
/**
|
||||
@@ -250,24 +274,28 @@ struct rzg3s_pcie_host;
|
||||
* @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
|
||||
* @setup_lanes: Callback for setting up the number of lanes
|
||||
* @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
|
||||
* @sysc_info: System Controller info for each controller
|
||||
* @num_power_resets: number of power resets
|
||||
* @num_cfg_resets: number of configuration resets
|
||||
* @num_pcie_controllers: number of PCIe controllers
|
||||
*/
|
||||
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);
|
||||
int (*setup_lanes)(struct rzg3s_pcie_host *host);
|
||||
const char * const *power_resets;
|
||||
const char * const *cfg_resets;
|
||||
struct rzg3s_sysc_info sysc_info;
|
||||
struct rzg3s_sysc_info sysc_info[RZG3S_PCIE_CONTROLLER_ID_MAX];
|
||||
u8 num_power_resets;
|
||||
u8 num_cfg_resets;
|
||||
u8 num_pcie_controllers;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -297,6 +325,8 @@ struct rzg3s_pcie_port {
|
||||
* @hw_lock: lock for access to the HW resources
|
||||
* @intx_irqs: INTx interrupts
|
||||
* @max_link_speed: maximum supported link speed
|
||||
* @controller_id: PCIe controller identifier, used for System Controller access
|
||||
* @num_lanes: The number of lanes
|
||||
*/
|
||||
struct rzg3s_pcie_host {
|
||||
void __iomem *axi;
|
||||
@@ -312,10 +342,24 @@ struct rzg3s_pcie_host {
|
||||
raw_spinlock_t hw_lock;
|
||||
int intx_irqs[PCI_NUM_INTX];
|
||||
int max_link_speed;
|
||||
enum rzg3s_pcie_controller_id controller_id;
|
||||
u8 num_lanes;
|
||||
};
|
||||
|
||||
#define rzg3s_msi_to_host(_msi) container_of(_msi, struct rzg3s_pcie_host, msi)
|
||||
|
||||
/*
|
||||
* RZ/V2H(P) supports a total of 4 lanes shared across two controllers.
|
||||
* rzv2h_lane_lock serialises both the counter update and the SYSC
|
||||
* register write so that concurrent async probes cannot race on the
|
||||
* shared LINK_MASTER register (offset 0x1060).
|
||||
* rzv2h_num_total_lanes tracks global lane usage to prevent
|
||||
* over-allocation or invalid bifurcation modes.
|
||||
*/
|
||||
#define RZV2H_PCIE_MAX_LANES 4
|
||||
static DEFINE_SPINLOCK(rzv2h_lane_lock);
|
||||
static u8 rzv2h_num_total_lanes;
|
||||
|
||||
static int rzg3s_sysc_config_func(struct rzg3s_sysc *sysc,
|
||||
enum rzg3s_sysc_func_id fid, u32 val)
|
||||
{
|
||||
@@ -1142,6 +1186,13 @@ static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host)
|
||||
rzg3s_pcie_update_bits(host->pcie, PCI_CLASS_REVISION, mask,
|
||||
field_prep(mask, PCI_CLASS_BRIDGE_PCI_NORMAL));
|
||||
|
||||
if (host->num_lanes) {
|
||||
rzg3s_pcie_update_bits(host->pcie + RZG3S_PCI_CFG_PCIEC,
|
||||
PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_MLW,
|
||||
FIELD_PREP(PCI_EXP_LNKCAP_MLW,
|
||||
host->num_lanes));
|
||||
}
|
||||
|
||||
/* Disable access control to the CFGU */
|
||||
writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
|
||||
|
||||
@@ -1277,9 +1328,9 @@ static int rzg3s_pcie_resets_prepare_and_get(struct rzg3s_pcie_host *host)
|
||||
for (i = 0; i < data->num_cfg_resets; i++)
|
||||
host->cfg_resets[i].id = data->cfg_resets[i];
|
||||
|
||||
ret = devm_reset_control_bulk_get_exclusive(host->dev,
|
||||
data->num_power_resets,
|
||||
host->power_resets);
|
||||
ret = devm_reset_control_bulk_get_shared(host->dev,
|
||||
data->num_power_resets,
|
||||
host->power_resets);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1674,6 +1725,76 @@ rzg3s_pcie_host_setup(struct rzg3s_pcie_host *host,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rzg3s_pcie_get_controller_id(struct rzg3s_pcie_host *host)
|
||||
{
|
||||
struct device_node *np = host->dev->of_node;
|
||||
struct of_phandle_args sysc_args;
|
||||
int ret;
|
||||
|
||||
if (host->data->num_pcie_controllers == 1)
|
||||
return 0;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(np, "renesas,sysc", 1, 0, &sysc_args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
of_node_put(sysc_args.np);
|
||||
|
||||
if (sysc_args.args[0] >= host->data->num_pcie_controllers ||
|
||||
sysc_args.args[0] >= RZG3S_PCIE_CONTROLLER_ID_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
host->controller_id = sysc_args.args[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzv2h_pcie_setup_lanes(struct rzg3s_pcie_host *host)
|
||||
{
|
||||
struct device_node *np = host->dev->of_node;
|
||||
u32 num_lanes;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "num-lanes", &num_lanes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* RZ/V2H(P) supports up to 4 lanes, but only in single x4 mode
|
||||
* for the first controller. Dual x2 mode is supported with 2
|
||||
* lanes for both controllers.
|
||||
*/
|
||||
if (num_lanes != 4 && num_lanes != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (host->controller_id == RZG3S_PCIE_CONTROLLER_ID_1 && num_lanes > 2)
|
||||
return -EINVAL;
|
||||
|
||||
guard(spinlock)(&rzv2h_lane_lock);
|
||||
if (rzv2h_num_total_lanes + num_lanes > RZV2H_PCIE_MAX_LANES)
|
||||
return -EINVAL;
|
||||
|
||||
ret = rzg3s_sysc_config_func(host->sysc, RZG3S_SYSC_FUNC_ID_LINK_MASTER,
|
||||
num_lanes == 2 ?
|
||||
RZG3S_SYSC_LINK_MODE_DUAL_X2 :
|
||||
RZG3S_SYSC_LINK_MODE_SINGLE_X4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rzv2h_num_total_lanes += num_lanes;
|
||||
host->num_lanes = num_lanes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rzv2h_pcie_release_lanes(void *data)
|
||||
{
|
||||
struct rzg3s_pcie_host *host = data;
|
||||
|
||||
guard(spinlock)(&rzv2h_lane_lock);
|
||||
rzv2h_num_total_lanes -= host->num_lanes;
|
||||
}
|
||||
|
||||
static int rzg3s_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pci_host_bridge *bridge;
|
||||
@@ -1698,8 +1819,12 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
|
||||
if (!host->sysc)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = rzg3s_pcie_get_controller_id(host);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sysc = host->sysc;
|
||||
sysc->info = &host->data->sysc_info;
|
||||
sysc->info = &host->data->sysc_info[host->controller_id];
|
||||
|
||||
host->axi = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(host->axi))
|
||||
@@ -1727,6 +1852,16 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto port_refclk_put;
|
||||
|
||||
if (host->data->setup_lanes) {
|
||||
ret = host->data->setup_lanes(host);
|
||||
if (ret)
|
||||
goto sysc_signal_restore;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, rzv2h_pcie_release_lanes, host);
|
||||
if (ret)
|
||||
goto sysc_signal_restore;
|
||||
}
|
||||
|
||||
ret = rzg3s_pcie_resets_prepare_and_get(host);
|
||||
if (ret)
|
||||
goto sysc_signal_restore;
|
||||
@@ -1841,6 +1976,16 @@ static int rzg3s_pcie_resume_noirq(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (host->num_lanes) {
|
||||
ret = rzg3s_sysc_config_func(host->sysc,
|
||||
RZG3S_SYSC_FUNC_ID_LINK_MASTER,
|
||||
host->num_lanes == 2 ?
|
||||
RZG3S_SYSC_LINK_MODE_DUAL_X2 :
|
||||
RZG3S_SYSC_LINK_MODE_SINGLE_X4);
|
||||
if (ret)
|
||||
goto assert_rst_rsm_b;
|
||||
}
|
||||
|
||||
ret = rzg3s_pcie_power_resets_deassert(host);
|
||||
if (ret)
|
||||
goto assert_rst_rsm_b;
|
||||
@@ -1888,14 +2033,17 @@ 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),
|
||||
.num_pcie_controllers = 1,
|
||||
.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),
|
||||
[RZG3S_PCIE_CONTROLLER_ID_0] = {
|
||||
.functions = {
|
||||
[RZG3S_SYSC_FUNC_ID_RST_RSM_B] = {
|
||||
.offset = 0xd74,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1906,18 +2054,65 @@ 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),
|
||||
.num_pcie_controllers = 1,
|
||||
.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_PCIE_CONTROLLER_ID_0] = {
|
||||
.functions = {
|
||||
[RZG3S_SYSC_FUNC_ID_L1_ALLOW] = {
|
||||
.offset = 0x1020,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
[RZG3S_SYSC_FUNC_ID_MODE] = {
|
||||
.offset = 0x1024,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
},
|
||||
[RZG3S_SYSC_FUNC_ID_MODE] = {
|
||||
.offset = 0x1024,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rzg3s_pcie_soc_data rzv2h_soc_data = {
|
||||
.power_resets = rzg3e_soc_power_resets,
|
||||
.num_power_resets = ARRAY_SIZE(rzg3e_soc_power_resets),
|
||||
.num_pcie_controllers = 2,
|
||||
.config_pre_init = rzg3e_pcie_config_pre_init,
|
||||
.config_post_init = rzg3e_pcie_config_post_init,
|
||||
.config_deinit = rzg3e_pcie_config_deinit,
|
||||
.setup_lanes = rzv2h_pcie_setup_lanes,
|
||||
.sysc_info = {
|
||||
[RZG3S_PCIE_CONTROLLER_ID_0] = {
|
||||
.functions = {
|
||||
[RZG3S_SYSC_FUNC_ID_L1_ALLOW] = {
|
||||
.offset = 0x1020,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
[RZG3S_SYSC_FUNC_ID_MODE] = {
|
||||
.offset = 0x1024,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
[RZG3S_SYSC_FUNC_ID_LINK_MASTER] = {
|
||||
.offset = 0x1060,
|
||||
.mask = GENMASK(9, 8),
|
||||
},
|
||||
},
|
||||
},
|
||||
[RZG3S_PCIE_CONTROLLER_ID_1] = {
|
||||
.functions = {
|
||||
[RZG3S_SYSC_FUNC_ID_L1_ALLOW] = {
|
||||
.offset = 0x1050,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
[RZG3S_SYSC_FUNC_ID_MODE] = {
|
||||
.offset = 0x1054,
|
||||
.mask = BIT(0),
|
||||
},
|
||||
[RZG3S_SYSC_FUNC_ID_LINK_MASTER] = {
|
||||
.offset = 0x1060,
|
||||
.mask = GENMASK(9, 8),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1932,6 +2127,10 @@ static const struct of_device_id rzg3s_pcie_of_match[] = {
|
||||
.compatible = "renesas,r9a09g047-pcie",
|
||||
.data = &rzg3e_soc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,r9a09g057-pcie",
|
||||
.data = &rzv2h_soc_data,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user