> + > +static struct pci_ops brcm_pcie_ops = { > + .read = brcm_pcie_read_config, > + .write = brcm_pcie_write_config, > +}; > + > +static int brcm_pcie_probe(struct platform_device *pdev) { > + struct device_node *dn = pdev->dev.of_node; > + const u32 *log2_scb_sizes, *dma_ranges; > + const struct brcm_pcie_cfg_data *data; > + const struct of_device_id *of_id; > + struct brcm_pcie *pcie; > + void __iomem *base; > + struct resource *r; > + int i, rlen, ret; > + u32 tmp; > + > + pcie = devm_kzalloc(&pdev->dev, sizeof(struct brcm_pcie), > GFP_KERNEL); > + if (!pcie) > + return -ENOMEM; > + > + of_id = of_match_node(brcm_pcie_match, dn); > + if (!of_id) > + return -EINVAL; > + > + data = of_id->data; > + pcie->type = data->type; > + pcie->ops = &data->ops; > + > + platform_set_drvdata(pdev, pcie); > + > + INIT_LIST_HEAD(&pcie->resource); > + > + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + base = devm_ioremap_resource(&pdev->dev, r); > + if (IS_ERR(base)) > + return PTR_ERR(base); > + > + ret = of_alias_get_id(dn, "pcie"); > + if (ret >= 0) > + pcie->num = ret; > + > + pcie->clk = devm_clk_get(&pdev->dev, "pcie"); > + if (IS_ERR(pcie->clk)) { > + dev_err(&pdev->dev, "could not get clock\n"); > + pcie->clk = NULL; > + } > + > + ret = clk_prepare_enable(pcie->clk); > + if (ret) { > + dev_err(&pdev->dev, "could not enable clock\n"); > + return ret; > + } > + > + pcie->dn = dn; > + pcie->base = base; > + pcie->dev = &pdev->dev; > + pcie->dev->of_node = dn; > + pcie->gen = 0; > + > + ret = of_property_read_u32(dn, "brcm,gen", &tmp); > + if (ret == 0) { > + if (tmp > 0 && tmp < 3) > + pcie->gen = (int)tmp; > + else > + dev_warn(pcie->dev, "bad DT value for prop > 'brcm,gen"); > + } else if (ret != -EINVAL) { > + dev_warn(pcie->dev, "error reading DT prop 'brcm,gen"); > + } > + > + pcie->ssc = of_property_read_bool(dn, "brcm,ssc"); > + > + /* Get the value for the log2 of the scb sizes. Subtract 15 from > + * each because the target register field has 0==disabled and 1==6KB. > + */ > + log2_scb_sizes = of_get_property(dn, "brcm,log2-scb-sizes", &rlen); > + if (log2_scb_sizes) { > + for (i = 0; i < rlen / sizeof(u32); i++) { > + pcie->scb_size_vals[i] > + = (int)of_read_number(log2_scb_sizes + i, 1) > + - 15; > + pcie->num_memc++; > + } > + } In your device tree documentation this is required property, what if this property is missing ? > + > + /* Look for the dma-ranges property. If it exists, issue a warning > + * as PCIe drivers may not work. This is because the identity > + * mapping between system memory and PCIe space is not > preserved, > + * and we need Linux to massage the dma_addr_t values it gets > + * from dma memory allocation. This functionality will be added > + * in the near future. > + */ > + dma_ranges = of_get_property(dn, "dma-ranges", &rlen); > + if (dma_ranges != NULL) > + dev_warn(pcie->dev, "no identity map; PCI drivers may fail"); > + > + if (IS_ENABLED(CONFIG_PCI_MSI)) { > + ret = irq_of_parse_and_map(pdev->dev.of_node, 1); > + if (ret == 0) > + dev_warn(pcie->dev, "cannot get msi intr; MSI > disabled\n"); > + else > + pcie->msi_irq = ret; > + } > + > + ret = of_pci_get_host_bridge_resources(dn, 0, 0xff, > + &pcie->resource, NULL); > + if (ret) { > + dev_err(pcie->dev, "ranges parsing failed\n"); > + return ret; > + } > + > + ret = brcm_pcie_setup_early(pcie); > + if (ret) > + goto out_err_clk; > + > + /* If setup bridge fails, it cleans up behind itself */ > + ret = brcm_setup_pcie_bridge(pcie); > + if (ret) > + goto out_err; > + > + pcie->bus = pci_scan_root_bus(pcie->dev, pcie->num, > &brcm_pcie_ops, > + pcie, &pcie->resource); > + if (!pcie->bus) { > + ret = -ENOMEM; > + goto out_err_bus; > + } > + > + if (IS_ENABLED(CONFIG_PCI_MSI)) > + brcm_pcie_msi_chip_set(pcie); > + > + pci_bus_size_bridges(pcie->bus); > + pci_bus_assign_resources(pcie->bus); > + > + pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); > + pci_bus_add_devices(pcie->bus); > + > + return 0; > + > +out_err_bus: > + brcm_pcie_enter_l23(pcie); > + brcm_pcie_turn_off(pcie); > +out_err_clk: > + clk_disable_unprepare(pcie->clk); > +out_err: > + return ret; > +} > + > +static int brcm_pcie_remove(struct platform_device *pdev) { > + return brcm_pcie_suspend(&pdev->dev); > +} > + > +static struct platform_driver brcm_pcie_driver = { > + .probe = brcm_pcie_probe, > + .remove = brcm_pcie_remove, > + .driver = { > + .name = "brcm-pcie", > + .owner = THIS_MODULE, > + .of_match_table = brcm_pcie_match, > + .pm = &brcm_pcie_pm_ops, > + }, > +}; > +module_platform_driver(brcm_pcie_driver); > + > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION("Broadcom STB PCIE RC driver"); > +MODULE_AUTHOR("Broadcom"); > diff --git a/drivers/pci/host/pcie-brcmstb.h b/drivers/pci/host/pcie- > brcmstb.h new file mode 100644 index 000000000000..b4a507423bb0 > --- /dev/null > +++ b/drivers/pci/host/pcie-brcmstb.h > @@ -0,0 +1,160 @@ > +#ifndef __PCIE_BRCMSTB_H > +#define __PCIE_BRCMSTB_H > + > +#include <linux/io.h> > + > +/* Broadcom PCIE Offsets */ > +#define PCIE_RC_CFG_PCIE_LINK_CAPABILITY 0x00b8 > +#define PCIE_RC_CFG_PCIE_LINK_STATUS_CONTROL > 0x00bc > +#define PCIE_RC_CFG_PCIE_ROOT_CAP_CONTROL 0x00c8 > +#define PCIE_RC_CFG_PCIE_LINK_STATUS_CONTROL_2 > 0x00dc > +#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 > 0x0188 > +#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c > +#define PCIE_RC_DL_MDIO_ADDR 0x1100 > +#define PCIE_RC_DL_MDIO_WR_DATA > 0x1104 > +#define PCIE_RC_DL_MDIO_RD_DATA > 0x1108 > +#define PCIE_MISC_MISC_CTRL 0x4008 > +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c > +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 > +#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c > +#define PCIE_MISC_RC_BAR1_CONFIG_HI 0x4030 > +#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 > +#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038 > +#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c > +#define PCIE_MISC_RC_BAR3_CONFIG_HI 0x4040 > +#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 > +#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 > +#define PCIE_MISC_MSI_DATA_CONFIG 0x404c > +#define PCIE_MISC_PCIE_CTRL 0x4064 > +#define PCIE_MISC_PCIE_STATUS 0x4068 > +#define PCIE_MISC_REVISION 0x406c > +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 > +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG > 0x4204 > +#define PCIE_INTR2_CPU_BASE 0x4300 > +#define PCIE_MSI_INTR2_BASE 0x4500 > + > +#define PCIE_RGR1_SW_INIT_1 0x9210 > +#define PCIE_EXT_CFG_INDEX 0x9000 > +#define PCIE_EXT_CFG_DATA 0x9004 > + > +/* BCM7425 specific register offsets */ > +#define BCM7425_PCIE_RGR1_SW_INIT_1 0x8010 > +#define BCM7425_PCIE_EXT_CFG_INDEX 0x8300 > +#define BCM7425_PCIE_EXT_CFG_DATA 0x8304 > + > +#define PCI_BUSNUM_SHIFT 20 > +#define PCI_SLOT_SHIFT 15 > +#define PCI_FUNC_SHIFT 12 > + > +#define BRCM_NUM_PCI_OUT_WINS 4 > +#define BRCM_MAX_SCB 4 > + > +/* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */ > +#define STATUS 0x0 > +#define SET 0x4 > +#define CLR 0x8 > +#define MASK_STATUS 0xc > +#define MASK_SET 0x10 > +#define MASK_CLR 0x14 > + > +enum brcm_pcie_type { > + BCM7425, > + BCM7435, > + GENERIC, > +}; > + > +struct brcm_pcie; > + > +/* Chip-specific PCIe operations (read/write config and reset) */ > +struct brcm_pcie_ll_ops { > + u32 (*read_config)(struct brcm_pcie *pcie, int cfg_idx); > + void (*write_config)(struct brcm_pcie *pcie, int cfg_idx, u32 val); > + void (*rgr1_sw_init)(struct brcm_pcie *pcie, u32 mask, > + int shift, u32 val); > +}; > + > +struct brcm_pcie_cfg_data { > + const enum brcm_pcie_type type; > + const struct brcm_pcie_ll_ops ops; > +}; > + > +struct brcm_msi; > + > +/* Internal Bus Controller Information.*/ struct brcm_pcie { > + void __iomem *base; > + bool suspended; > + struct clk *clk; > + struct device_node *dn; > + bool ssc; > + int gen; > + int scb_size_vals[BRCM_MAX_SCB]; > + struct pci_bus *bus; > + struct device *dev; > + struct list_head resource; > + int msi_irq; > + struct brcm_msi *msi; > + unsigned int rev; > + unsigned int num; > + bool bridge_setup_done; > + enum brcm_pcie_type type; > + const struct brcm_pcie_ll_ops *ops; > + unsigned int num_memc; > +}; > + > +/* Helper functions to access read/write config space and software init > +which > + * are chip-specific > + */ > +static inline u32 brcm_pcie_ll_read_config(struct brcm_pcie *pcie, int > +cfg_idx) { > + return pcie->ops->read_config(pcie, cfg_idx); } > + > +static inline void brcm_pcie_ll_write_config(struct brcm_pcie *pcie, > + int cfg_idx, u32 val) > +{ > + pcie->ops->write_config(pcie, cfg_idx, val); } > + > +static inline void brcm_pcie_rgr1_sw_init(struct brcm_pcie *pcie, u32 mask, > + int shift, u32 val) > +{ > + pcie->ops->rgr1_sw_init(pcie, mask, shift, val); } > + > +/* > + * MIPS endianness is configured by boot strap, which also reverses all > + * bus endianness (i.e., big-endian CPU + big endian bus ==> native > + * endian I/O). > + * > + * Other architectures (e.g., ARM) either do not support big endian, or > + * else leave I/O in little endian mode. > + */ > +static inline u32 bpcie_readl(void __iomem *base) { > + if (IS_ENABLED(CONFIG_MIPS)) > + return __raw_readl(base); > + else > + return readl(base); > +} > + > +static inline void bpcie_writel(u32 val, void __iomem *base) { > + if (IS_ENABLED(CONFIG_MIPS)) > + __raw_writel(val, base); > + else > + writel(val, base); > +} > + > +#ifdef CONFIG_PCIE_BRCMSTB_MSI > +int brcm_pcie_enable_msi(struct brcm_pcie *pcie, int nr); void > +brcm_pcie_msi_chip_set(struct brcm_pcie *pcie); #else static inline int > +brcm_pcie_enable_msi(struct brcm_pcie *pcie, int nr) { > + return 0; > +} > +static inline void brcm_pcie_msi_chip_set(struct brcm_pcie *pcie) { } > +#endif > + > +#endif /* __PCIE_BRCMSTB_H */ > -- > 2.1.0 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-pci" in the > body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at > http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html