|
12 | 12 | #include <linux/i2c-mux.h>
|
13 | 13 | #include <linux/io.h>
|
14 | 14 | #include <linux/module.h>
|
| 15 | +#include <linux/pci.h> |
15 | 16 | #include <linux/platform_device.h>
|
16 | 17 | #include <linux/platform_data/i2c-mux-reg.h>
|
17 | 18 | #include <linux/platform_data/mlxreg.h>
|
|
331 | 332 | #define MLXPLAT_I2C_MAIN_BUS_NOTIFIED 0x01
|
332 | 333 | #define MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED 0x02
|
333 | 334 |
|
| 335 | +/* Lattice FPGA PCI configuration */ |
| 336 | +#define PCI_VENDOR_ID_LATTICE 0x1204 |
| 337 | +#define PCI_DEVICE_ID_LATTICE_I2C_BRIDGE 0x9c2f |
| 338 | +#define PCI_DEVICE_ID_LATTICE_JTAG_BRIDGE 0x9c30 |
| 339 | +#define PCI_DEVICE_ID_LATTICE_LPC_BRIDGE 0x9c32 |
| 340 | + |
334 | 341 | /* mlxplat_priv - platform private data
|
335 | 342 | * @pdev_i2c - i2c controller platform device
|
336 | 343 | * @pdev_mux - array of mux platform devices
|
@@ -362,6 +369,7 @@ struct mlxplat_priv {
|
362 | 369 |
|
363 | 370 | static struct platform_device *mlxplat_dev;
|
364 | 371 | static int mlxplat_i2c_main_complition_notify(void *handle, int id);
|
| 372 | +static void __iomem *i2c_bridge_addr, *jtag_bridge_addr; |
365 | 373 |
|
366 | 374 | /* Regions for LPC I2C controller and LPC base register space */
|
367 | 375 | static const struct resource mlxplat_lpc_resources[] = {
|
@@ -5544,6 +5552,9 @@ static struct mlxreg_core_platform_data *mlxplat_fan;
|
5544 | 5552 | static struct mlxreg_core_platform_data
|
5545 | 5553 | *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS];
|
5546 | 5554 | static const struct regmap_config *mlxplat_regmap_config;
|
| 5555 | +static struct pci_dev *lpc_bridge; |
| 5556 | +static struct pci_dev *i2c_bridge; |
| 5557 | +static struct pci_dev *jtag_bridge; |
5547 | 5558 |
|
5548 | 5559 | /* Platform default reset function */
|
5549 | 5560 | static int mlxplat_reboot_notifier(struct notifier_block *nb, unsigned long action, void *unused)
|
@@ -6172,15 +6183,131 @@ static void mlxplat_lpc_cpld_device_exit(void)
|
6172 | 6183 | {
|
6173 | 6184 | }
|
6174 | 6185 |
|
| 6186 | +static int |
| 6187 | +mlxplat_pci_fpga_device_init(unsigned int device, const char *res_name, struct pci_dev **pci_bridge, |
| 6188 | + void __iomem **pci_bridge_addr) |
| 6189 | +{ |
| 6190 | + void __iomem *pci_mem_addr; |
| 6191 | + struct pci_dev *pci_dev; |
| 6192 | + int err; |
| 6193 | + |
| 6194 | + pci_dev = pci_get_device(PCI_VENDOR_ID_LATTICE, device, NULL); |
| 6195 | + if (!pci_dev) |
| 6196 | + return -ENODEV; |
| 6197 | + |
| 6198 | + err = pci_enable_device(pci_dev); |
| 6199 | + if (err) { |
| 6200 | + dev_err(&pci_dev->dev, "pci_enable_device failed with error %d\n", err); |
| 6201 | + goto fail_pci_enable_device; |
| 6202 | + } |
| 6203 | + |
| 6204 | + err = pci_request_region(pci_dev, 0, res_name); |
| 6205 | + if (err) { |
| 6206 | + dev_err(&pci_dev->dev, "pci_request_regions failed with error %d\n", err); |
| 6207 | + goto fail_pci_request_regions; |
| 6208 | + } |
| 6209 | + |
| 6210 | + err = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(64)); |
| 6211 | + if (err) { |
| 6212 | + err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); |
| 6213 | + if (err) { |
| 6214 | + dev_err(&pci_dev->dev, "dma_set_mask failed with error %d\n", err); |
| 6215 | + goto fail_pci_set_dma_mask; |
| 6216 | + } |
| 6217 | + } |
| 6218 | + |
| 6219 | + pci_set_master(pci_dev); |
| 6220 | + |
| 6221 | + pci_mem_addr = devm_ioremap(&pci_dev->dev, pci_resource_start(pci_dev, 0), |
| 6222 | + pci_resource_len(pci_dev, 0)); |
| 6223 | + if (!pci_mem_addr) { |
| 6224 | + dev_err(&mlxplat_dev->dev, "ioremap failed\n"); |
| 6225 | + err = -EIO; |
| 6226 | + goto fail_ioremap; |
| 6227 | + } |
| 6228 | + |
| 6229 | + *pci_bridge = pci_dev; |
| 6230 | + *pci_bridge_addr = pci_mem_addr; |
| 6231 | + |
| 6232 | + return 0; |
| 6233 | + |
| 6234 | +fail_ioremap: |
| 6235 | +fail_pci_set_dma_mask: |
| 6236 | + pci_release_regions(pci_dev); |
| 6237 | +fail_pci_request_regions: |
| 6238 | + pci_disable_device(pci_dev); |
| 6239 | +fail_pci_enable_device: |
| 6240 | + return err; |
| 6241 | +} |
| 6242 | + |
| 6243 | +static void |
| 6244 | +mlxplat_pci_fpga_device_exit(struct pci_dev *pci_bridge, |
| 6245 | + void __iomem *pci_bridge_addr) |
| 6246 | +{ |
| 6247 | + iounmap(pci_bridge_addr); |
| 6248 | + pci_release_regions(pci_bridge); |
| 6249 | + pci_disable_device(pci_bridge); |
| 6250 | +} |
| 6251 | + |
| 6252 | +static int |
| 6253 | +mlxplat_pci_fpga_devices_init(struct resource **hotplug_resources, |
| 6254 | + unsigned int *hotplug_resources_size) |
| 6255 | +{ |
| 6256 | + int err; |
| 6257 | + |
| 6258 | + err = mlxplat_pci_fpga_device_init(PCI_DEVICE_ID_LATTICE_LPC_BRIDGE, |
| 6259 | + "mlxplat_lpc_bridge", &lpc_bridge, |
| 6260 | + &mlxplat_mlxcpld_regmap_ctx.base); |
| 6261 | + if (err) |
| 6262 | + goto mlxplat_pci_fpga_device_init_lpc_fail; |
| 6263 | + |
| 6264 | + err = mlxplat_pci_fpga_device_init(PCI_DEVICE_ID_LATTICE_I2C_BRIDGE, |
| 6265 | + "mlxplat_i2c_bridge", &i2c_bridge, |
| 6266 | + &i2c_bridge_addr); |
| 6267 | + if (err) |
| 6268 | + goto mlxplat_pci_fpga_device_init_i2c_fail; |
| 6269 | + |
| 6270 | + err = mlxplat_pci_fpga_device_init(PCI_DEVICE_ID_LATTICE_JTAG_BRIDGE, |
| 6271 | + "mlxplat_jtag_bridge", &jtag_bridge, |
| 6272 | + &jtag_bridge_addr); |
| 6273 | + if (err) |
| 6274 | + goto mlxplat_pci_fpga_device_init_jtag_fail; |
| 6275 | + |
| 6276 | + return 0; |
| 6277 | + |
| 6278 | +mlxplat_pci_fpga_device_init_jtag_fail: |
| 6279 | + mlxplat_pci_fpga_device_exit(i2c_bridge, i2c_bridge_addr); |
| 6280 | +mlxplat_pci_fpga_device_init_i2c_fail: |
| 6281 | + mlxplat_pci_fpga_device_exit(lpc_bridge, mlxplat_mlxcpld_regmap_ctx.base); |
| 6282 | +mlxplat_pci_fpga_device_init_lpc_fail: |
| 6283 | + return err; |
| 6284 | +} |
| 6285 | + |
| 6286 | +static void mlxplat_pci_fpga_devices_exit(void) |
| 6287 | +{ |
| 6288 | + mlxplat_pci_fpga_device_exit(jtag_bridge, jtag_bridge_addr); |
| 6289 | + mlxplat_pci_fpga_device_exit(i2c_bridge, i2c_bridge_addr); |
| 6290 | + mlxplat_pci_fpga_device_exit(lpc_bridge, mlxplat_mlxcpld_regmap_ctx.base); |
| 6291 | +} |
| 6292 | + |
6175 | 6293 | static int
|
6176 | 6294 | mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size)
|
6177 | 6295 | {
|
6178 |
| - return mlxplat_lpc_cpld_device_init(hotplug_resources, hotplug_resources_size); |
| 6296 | + int err; |
| 6297 | + |
| 6298 | + err = mlxplat_pci_fpga_devices_init(hotplug_resources, hotplug_resources_size); |
| 6299 | + if (err == -ENODEV) |
| 6300 | + return mlxplat_lpc_cpld_device_init(hotplug_resources, hotplug_resources_size); |
| 6301 | + |
| 6302 | + return err; |
6179 | 6303 | }
|
6180 | 6304 |
|
6181 | 6305 | static void mlxplat_post_exit(void)
|
6182 | 6306 | {
|
6183 |
| - mlxplat_lpc_cpld_device_exit(); |
| 6307 | + if (lpc_bridge) |
| 6308 | + mlxplat_pci_fpga_devices_exit(); |
| 6309 | + else |
| 6310 | + mlxplat_lpc_cpld_device_exit(); |
6184 | 6311 | }
|
6185 | 6312 |
|
6186 | 6313 | static int mlxplat_post_init(struct mlxplat_priv *priv)
|
@@ -6366,6 +6493,9 @@ static int mlxplat_i2c_main_init(struct mlxplat_priv *priv)
|
6366 | 6493 | mlxplat_i2c->regmap = priv->regmap;
|
6367 | 6494 | mlxplat_i2c->handle = priv;
|
6368 | 6495 |
|
| 6496 | + /* Set mapped base address of I2C-LPC bridge over PCIe */ |
| 6497 | + if (lpc_bridge) |
| 6498 | + mlxplat_i2c->addr = i2c_bridge_addr; |
6369 | 6499 | priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld",
|
6370 | 6500 | nr, priv->hotplug_resources,
|
6371 | 6501 | priv->hotplug_resources_size,
|
|
0 commit comments