| /** |
| ****************************************************************************** |
| * |
| * @file rwnx_v7.c - Support for v7 platform |
| * |
| * Copyright (C) RivieraWaves 2012-2019 |
| * |
| ****************************************************************************** |
| */ |
| |
| #include "rwnx_v7.h" |
| #include "rwnx_defs.h" |
| #include "rwnx_irqs.h" |
| #include "reg_access.h" |
| #include "hal_desc.h" |
| |
| struct rwnx_v7 { |
| u8 *pci_bar0_vaddr; |
| u8 *pci_bar1_vaddr; |
| }; |
| |
| static int rwnx_v7_platform_enable(struct rwnx_hw *rwnx_hw) |
| { |
| int ret; |
| |
| /* sched_setscheduler on ONESHOT threaded irq handler for BCNs ? */ |
| ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0, |
| "rwnx", rwnx_hw); |
| return ret; |
| } |
| |
| static int rwnx_v7_platform_disable(struct rwnx_hw *rwnx_hw) |
| { |
| free_irq(rwnx_hw->plat->pci_dev->irq, rwnx_hw); |
| return 0; |
| } |
| |
| static void rwnx_v7_platform_deinit(struct rwnx_plat *rwnx_plat) |
| { |
| #ifdef CONFIG_PCI |
| struct rwnx_v7 *rwnx_v7 = (struct rwnx_v7 *)rwnx_plat->priv; |
| |
| pci_disable_device(rwnx_plat->pci_dev); |
| iounmap(rwnx_v7->pci_bar0_vaddr); |
| iounmap(rwnx_v7->pci_bar1_vaddr); |
| pci_release_regions(rwnx_plat->pci_dev); |
| pci_clear_master(rwnx_plat->pci_dev); |
| pci_disable_msi(rwnx_plat->pci_dev); |
| #endif |
| kfree(rwnx_plat); |
| } |
| |
| static u8 *rwnx_v7_get_address(struct rwnx_plat *rwnx_plat, int addr_name, |
| unsigned int offset) |
| { |
| struct rwnx_v7 *rwnx_v7 = (struct rwnx_v7 *)rwnx_plat->priv; |
| |
| if (WARN(addr_name >= RWNX_ADDR_MAX, "Invalid address %d", addr_name)) |
| return NULL; |
| |
| if (addr_name == RWNX_ADDR_CPU) |
| return rwnx_v7->pci_bar0_vaddr + offset; |
| else |
| return rwnx_v7->pci_bar1_vaddr + offset; |
| } |
| |
| static void rwnx_v7_ack_irq(struct rwnx_plat *rwnx_plat) |
| { |
| |
| } |
| |
| static const u32 rwnx_v7_config_reg[] = { |
| NXMAC_DEBUG_PORT_SEL_ADDR, |
| SYSCTRL_DIAG_CONF_ADDR, |
| SYSCTRL_PHYDIAG_CONF_ADDR, |
| SYSCTRL_RIUDIAG_CONF_ADDR, |
| RF_V7_DIAGPORT_CONF1_ADDR, |
| }; |
| |
| static const u32 rwnx_v7_he_config_reg[] = { |
| SYSCTRL_DIAG_CONF0, |
| SYSCTRL_DIAG_CONF1, |
| SYSCTRL_DIAG_CONF2, |
| SYSCTRL_DIAG_CONF3, |
| }; |
| |
| static int rwnx_v7_get_config_reg(struct rwnx_plat *rwnx_plat, const u32 **list) |
| { |
| u32 fpga_sign; |
| |
| if (!list) |
| return 0; |
| |
| fpga_sign = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, SYSCTRL_SIGNATURE_ADDR); |
| if (__FPGA_TYPE(fpga_sign) == 0xc0ca) { |
| *list = rwnx_v7_he_config_reg; |
| return ARRAY_SIZE(rwnx_v7_he_config_reg); |
| } else { |
| *list = rwnx_v7_config_reg; |
| return ARRAY_SIZE(rwnx_v7_config_reg); |
| } |
| } |
| |
| |
| /** |
| * rwnx_v7_platform_init - Initialize the DINI platform |
| * |
| * @pci_dev PCI device |
| * @rwnx_plat Pointer on struct rwnx_stat * to be populated |
| * |
| * @return 0 on success, < 0 otherwise |
| * |
| * Allocate and initialize a rwnx_plat structure for the dini platform. |
| */ |
| int rwnx_v7_platform_init(struct pci_dev *pci_dev, struct rwnx_plat **rwnx_plat) |
| { |
| struct rwnx_v7 *rwnx_v7; |
| u16 pci_cmd; |
| int ret = 0; |
| |
| *rwnx_plat = kzalloc(sizeof(struct rwnx_plat) + sizeof(struct rwnx_v7), |
| GFP_KERNEL); |
| if (!*rwnx_plat) |
| return -ENOMEM; |
| |
| rwnx_v7 = (struct rwnx_v7 *)(*rwnx_plat)->priv; |
| |
| /* Hotplug fixups */ |
| pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd); |
| pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR; |
| pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd); |
| pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2); |
| |
| ret = pci_enable_device(pci_dev); |
| if (ret) { |
| dev_err(&(pci_dev->dev), "pci_enable_device failed\n"); |
| goto out_enable; |
| } |
| |
| pci_set_master(pci_dev); |
| |
| ret = pci_request_regions(pci_dev, KBUILD_MODNAME); |
| if (ret) { |
| dev_err(&(pci_dev->dev), "pci_request_regions failed\n"); |
| goto out_request; |
| } |
| |
| #ifdef CONFIG_PCI |
| if (pci_enable_msi(pci_dev)) { |
| dev_err(&(pci_dev->dev), "pci_enable_msi failed\n"); |
| goto out_msi; |
| |
| } |
| #endif |
| |
| rwnx_v7->pci_bar0_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 0); |
| if (!rwnx_v7->pci_bar0_vaddr) { |
| dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 0); |
| ret = -ENOMEM; |
| goto out_bar0; |
| } |
| rwnx_v7->pci_bar1_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 1); |
| if (!rwnx_v7->pci_bar1_vaddr) { |
| dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 1); |
| ret = -ENOMEM; |
| goto out_bar1; |
| } |
| |
| (*rwnx_plat)->enable = rwnx_v7_platform_enable; |
| (*rwnx_plat)->disable = rwnx_v7_platform_disable; |
| (*rwnx_plat)->deinit = rwnx_v7_platform_deinit; |
| (*rwnx_plat)->get_address = rwnx_v7_get_address; |
| (*rwnx_plat)->ack_irq = rwnx_v7_ack_irq; |
| (*rwnx_plat)->get_config_reg = rwnx_v7_get_config_reg; |
| |
| return 0; |
| |
| out_bar1: |
| iounmap(rwnx_v7->pci_bar0_vaddr); |
| out_bar0: |
| #ifdef CONFIG_PCI |
| pci_disable_msi(pci_dev); |
| out_msi: |
| #endif |
| pci_release_regions(pci_dev); |
| out_request: |
| #ifdef CONFIG_PCI |
| pci_clear_master(pci_dev); |
| #endif |
| pci_disable_device(pci_dev); |
| out_enable: |
| kfree(*rwnx_plat); |
| return ret; |
| } |