Skip to content

Commit e311b38

Browse files
shimodaykwilczynski
authored andcommitted
PCI: rcar-gen4: Add endpoint mode support
Add R-Car Gen4 PCIe controller for endpoint mode. This controller is based on Synopsys DesignWare PCIe. Link: https://lore.kernel.org/linux-pci/[email protected] Signed-off-by: Yoshihiro Shimoda <[email protected]> Signed-off-by: Krzysztof Wilczyński <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]> Reviewed-by: Serge Semin <[email protected]>
1 parent 0d0c551 commit e311b38

File tree

2 files changed

+164
-4
lines changed

2 files changed

+164
-4
lines changed

drivers/pci/controller/dwc/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,17 @@ config PCIE_RCAR_GEN4_HOST
300300
To compile this driver as a module, choose M here: the module will be
301301
called pcie-rcar-gen4.ko. This uses the DesignWare core.
302302

303+
config PCIE_RCAR_GEN4_EP
304+
tristate "Renesas R-Car Gen4 PCIe controller (endpoint mode)"
305+
depends on ARCH_RENESAS || COMPILE_TEST
306+
depends on PCI_ENDPOINT
307+
select PCIE_DW_EP
308+
select PCIE_RCAR_GEN4
309+
help
310+
Say Y here if you want PCIe controller (endpoint mode) on R-Car Gen4
311+
SoCs. To compile this driver as a module, choose M here: the module
312+
will be called pcie-rcar-gen4.ko. This uses the DesignWare core.
313+
303314
config PCIE_ROCKCHIP_DW_HOST
304315
bool "Rockchip DesignWare PCIe controller"
305316
select PCIE_DW

drivers/pci/controller/dwc/pcie-rcar-gen4.c

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
/* PCIe Mode Setting Register 0 */
2222
#define PCIEMSR0 0x0000
2323
#define BIFUR_MOD_SET_ON BIT(0)
24+
#define DEVICE_TYPE_EP 0
2425
#define DEVICE_TYPE_RC BIT(4)
2526

2627
/* PCIe Interrupt Status 0 */
@@ -44,6 +45,9 @@
4445
#define RCAR_NUM_SPEED_CHANGE_RETRIES 10
4546
#define RCAR_MAX_LINK_SPEED 4
4647

48+
#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
49+
#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
50+
4751
struct rcar_gen4_pcie {
4852
struct dw_pcie dw;
4953
void __iomem *base;
@@ -52,6 +56,7 @@ struct rcar_gen4_pcie {
5256
};
5357
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
5458

59+
/* Common */
5560
static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
5661
bool enable)
5762
{
@@ -169,6 +174,8 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
169174
val = readl(rcar->base + PCIEMSR0);
170175
if (rcar->mode == DW_PCIE_RC_TYPE) {
171176
val |= DEVICE_TYPE_RC;
177+
} else if (rcar->mode == DW_PCIE_EP_TYPE) {
178+
val |= DEVICE_TYPE_EP;
172179
} else {
173180
ret = -EINVAL;
174181
goto err_unprepare;
@@ -308,9 +315,11 @@ static int rcar_gen4_add_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
308315
{
309316
struct dw_pcie_rp *pp = &rcar->dw.pp;
310317

318+
if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_HOST))
319+
return -ENODEV;
320+
311321
pp->num_vectors = MAX_MSI_IRQS;
312322
pp->ops = &rcar_gen4_pcie_host_ops;
313-
rcar->mode = DW_PCIE_RC_TYPE;
314323

315324
return dw_pcie_host_init(pp);
316325
}
@@ -320,6 +329,125 @@ static void rcar_gen4_remove_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
320329
dw_pcie_host_deinit(&rcar->dw.pp);
321330
}
322331

332+
/* Endpoint mode */
333+
static void rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep)
334+
{
335+
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
336+
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
337+
int ret;
338+
339+
ret = rcar_gen4_pcie_common_init(rcar);
340+
if (ret)
341+
return;
342+
343+
writel(PCIEDMAINTSTSEN_INIT, rcar->base + PCIEDMAINTSTSEN);
344+
}
345+
346+
static void rcar_gen4_pcie_ep_init(struct dw_pcie_ep *ep)
347+
{
348+
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
349+
enum pci_barno bar;
350+
351+
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
352+
dw_pcie_ep_reset_bar(pci, bar);
353+
}
354+
355+
static void rcar_gen4_pcie_ep_deinit(struct dw_pcie_ep *ep)
356+
{
357+
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
358+
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
359+
360+
writel(0, rcar->base + PCIEDMAINTSTSEN);
361+
rcar_gen4_pcie_common_deinit(rcar);
362+
}
363+
364+
static int rcar_gen4_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
365+
enum pci_epc_irq_type type,
366+
u16 interrupt_num)
367+
{
368+
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
369+
370+
switch (type) {
371+
case PCI_EPC_IRQ_LEGACY:
372+
return dw_pcie_ep_raise_legacy_irq(ep, func_no);
373+
case PCI_EPC_IRQ_MSI:
374+
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
375+
default:
376+
dev_err(dw->dev, "Unknown IRQ type\n");
377+
return -EINVAL;
378+
}
379+
380+
return 0;
381+
}
382+
383+
static const struct pci_epc_features rcar_gen4_pcie_epc_features = {
384+
.linkup_notifier = false,
385+
.msi_capable = true,
386+
.msix_capable = false,
387+
.reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
388+
.align = SZ_1M,
389+
};
390+
391+
static const struct pci_epc_features*
392+
rcar_gen4_pcie_ep_get_features(struct dw_pcie_ep *ep)
393+
{
394+
return &rcar_gen4_pcie_epc_features;
395+
}
396+
397+
static unsigned int rcar_gen4_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
398+
u8 func_no)
399+
{
400+
return func_no * RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET;
401+
}
402+
403+
static unsigned int rcar_gen4_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep,
404+
u8 func_no)
405+
{
406+
return func_no * RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET;
407+
}
408+
409+
static const struct dw_pcie_ep_ops pcie_ep_ops = {
410+
.pre_init = rcar_gen4_pcie_ep_pre_init,
411+
.ep_init = rcar_gen4_pcie_ep_init,
412+
.deinit = rcar_gen4_pcie_ep_deinit,
413+
.raise_irq = rcar_gen4_pcie_ep_raise_irq,
414+
.get_features = rcar_gen4_pcie_ep_get_features,
415+
.func_conf_select = rcar_gen4_pcie_ep_func_conf_select,
416+
.get_dbi2_offset = rcar_gen4_pcie_ep_get_dbi2_offset,
417+
};
418+
419+
static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
420+
{
421+
struct dw_pcie_ep *ep = &rcar->dw.ep;
422+
423+
if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_EP))
424+
return -ENODEV;
425+
426+
ep->ops = &pcie_ep_ops;
427+
428+
return dw_pcie_ep_init(ep);
429+
}
430+
431+
static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
432+
{
433+
dw_pcie_ep_exit(&rcar->dw.ep);
434+
}
435+
436+
/* Common */
437+
static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
438+
{
439+
rcar->mode = (enum dw_pcie_device_mode)of_device_get_match_data(&rcar->pdev->dev);
440+
441+
switch (rcar->mode) {
442+
case DW_PCIE_RC_TYPE:
443+
return rcar_gen4_add_dw_pcie_rp(rcar);
444+
case DW_PCIE_EP_TYPE:
445+
return rcar_gen4_add_dw_pcie_ep(rcar);
446+
default:
447+
return -EINVAL;
448+
}
449+
}
450+
323451
static int rcar_gen4_pcie_probe(struct platform_device *pdev)
324452
{
325453
struct rcar_gen4_pcie *rcar;
@@ -337,7 +465,7 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev)
337465
if (err)
338466
return err;
339467

340-
err = rcar_gen4_add_dw_pcie_rp(rcar);
468+
err = rcar_gen4_add_dw_pcie(rcar);
341469
if (err)
342470
goto err_unprepare;
343471

@@ -349,16 +477,37 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev)
349477
return err;
350478
}
351479

480+
static void rcar_gen4_remove_dw_pcie(struct rcar_gen4_pcie *rcar)
481+
{
482+
switch (rcar->mode) {
483+
case DW_PCIE_RC_TYPE:
484+
rcar_gen4_remove_dw_pcie_rp(rcar);
485+
break;
486+
case DW_PCIE_EP_TYPE:
487+
rcar_gen4_remove_dw_pcie_ep(rcar);
488+
break;
489+
default:
490+
break;
491+
}
492+
}
493+
352494
static void rcar_gen4_pcie_remove(struct platform_device *pdev)
353495
{
354496
struct rcar_gen4_pcie *rcar = platform_get_drvdata(pdev);
355497

356-
rcar_gen4_remove_dw_pcie_rp(rcar);
498+
rcar_gen4_remove_dw_pcie(rcar);
357499
rcar_gen4_pcie_unprepare(rcar);
358500
}
359501

360502
static const struct of_device_id rcar_gen4_pcie_of_match[] = {
361-
{ .compatible = "renesas,rcar-gen4-pcie", },
503+
{
504+
.compatible = "renesas,rcar-gen4-pcie",
505+
.data = (void *)DW_PCIE_RC_TYPE,
506+
},
507+
{
508+
.compatible = "renesas,rcar-gen4-pcie-ep",
509+
.data = (void *)DW_PCIE_EP_TYPE,
510+
},
362511
{},
363512
};
364513
MODULE_DEVICE_TABLE(of, rcar_gen4_pcie_of_match);

0 commit comments

Comments
 (0)