// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#include <zircon/types.h>

__BEGIN_CDECLS

// ask clang format not to mess up the indentation:
// clang-format off


// Base Address Registers are accessed in userspace via the get_bar protocol method. The
// Bar is represented via a pci_bar_t struct which contains a handle pointer to a VMO
// in the case of an MMIO bar, as well as a PIO addr/size pair for the memory region
// to access if a PIO bar. In the latter case, the protocol will acquire the appropriate
// permissions for the process to write to that PIO region on that architecture.
typedef uint32_t zx_pci_bar_types_t;
#define ZX_PCI_BAR_TYPE_UNUSED ((zx_pci_bar_types_t) 0u)
#define ZX_PCI_BAR_TYPE_MMIO ((zx_pci_bar_types_t) 1u)
#define ZX_PCI_BAR_TYPE_PIO ((zx_pci_bar_types_t) 2u)

// TODO(cja): This makes some assumptions that anything in an arch's PIO region
// is going to be defined as a base address and size. This will need to be
// updated to a per-platform structure in the event that doesn't pan out
// in the future.
typedef struct zx_pci_bar {
    uint32_t id;
    uint32_t type;
    size_t size;
    union {
        uintptr_t addr;
        zx_handle_t handle;
    };
} zx_pci_bar_t;

// Defines and structures related to zx_pci_*()
// Info returned to dev manager for PCIe devices when probing.
typedef struct zx_pcie_device_info {
    uint16_t vendor_id;
    uint16_t device_id;

    uint8_t  base_class;
    uint8_t  sub_class;
    uint8_t  program_interface;
    uint8_t  revision_id;

    uint8_t  bus_id;
    uint8_t  dev_id;
    uint8_t  func_id;
} zx_pcie_device_info_t;

#define ZX_PCI_MAX_BUSSES (256u)
#define ZX_PCI_MAX_DEVICES_PER_BUS (32u)
#define ZX_PCI_MAX_FUNCTIONS_PER_DEVICE (8u)
#define ZX_PCI_MAX_FUNCTIONS_PER_BUS (ZX_PCI_MAX_DEVICES_PER_BUS * ZX_PCI_MAX_FUNCTIONS_PER_DEVICE)

#define ZX_PCI_MAX_LEGACY_IRQ_PINS (4u)
#define ZX_PCI_MAX_MSI_IRQS        (32u)
#define ZX_PCI_MAX_MSIX_IRQS       (2048u)

#define ZX_PCI_STANDARD_CONFIG_HDR_SIZE (64u)
#define ZX_PCI_BASE_CONFIG_SIZE         (256u)
#define ZX_PCI_EXTENDED_CONFIG_SIZE     (4096u)
#define ZX_PCI_ECAM_BYTE_PER_BUS (ZX_PCI_EXTENDED_CONFIG_SIZE * ZX_PCI_MAX_FUNCTIONS_PER_BUS)

#define ZX_PCI_BAR_REGS_PER_BRIDGE    (2u)
#define ZX_PCI_BAR_REGS_PER_DEVICE    (6u)
#define ZX_PCI_MAX_BAR_REGS           (6u)

#define ZX_PCI_NO_IRQ_MAPPING UINT32_MAX

// Used for zx_pci_init_arg_t::addr_windows::cfg_space_type
#define PCI_CFG_SPACE_TYPE_PIO     (0u)
#define PCI_CFG_SPACE_TYPE_MMIO    (1u)
#define PCI_CFG_SPACE_TYPE_DW_ROOT (2u)  // Designware Root Bridge ECAM
#define PCI_CFG_SPACE_TYPE_DW_DS   (3u)  // Designware Downstream ECAM

// Dimensions: device id, function id, legacy pin number
// ZX_PCI_NO_IRQ_MAPPING if no mapping specified.
typedef uint32_t zx_pci_irq_swizzle_lut_t[ZX_PCI_MAX_DEVICES_PER_BUS]
                                         [ZX_PCI_MAX_FUNCTIONS_PER_DEVICE]
                                         [ZX_PCI_MAX_LEGACY_IRQ_PINS];

typedef struct zx_pci_init_arg {
    zx_pci_irq_swizzle_lut_t dev_pin_to_global_irq;

    uint32_t num_irqs;
    struct {
        uint32_t global_irq;
        bool level_triggered;
        bool active_high;
    } irqs[64];

    uint32_t addr_window_count;
    struct {
        uint64_t base;
        size_t size;
        uint8_t bus_start;
        uint8_t bus_end;
        uint8_t cfg_space_type;
        bool has_ecam;
    } addr_windows[];
} zx_pci_init_arg_t;

#define ZX_PCI_INIT_ARG_MAX_ECAM_WINDOWS 2
#define ZX_PCI_INIT_ARG_MAX_SIZE (sizeof(((zx_pci_init_arg_t*)NULL)->addr_windows[0]) * \
                                  ZX_PCI_INIT_ARG_MAX_ECAM_WINDOWS + \
                                  sizeof(zx_pci_init_arg_t))

// Enum used to select PCIe IRQ modes
typedef uint32_t zx_pci_irq_mode_t;
#define ZX_PCIE_IRQ_MODE_DISABLED ((zx_pci_irq_mode_t) 0u)
#define ZX_PCIE_IRQ_MODE_LEGACY ((zx_pci_irq_mode_t) 1u)
#define ZX_PCIE_IRQ_MODE_MSI ((zx_pci_irq_mode_t) 2u)
#define ZX_PCIE_IRQ_MODE_MSI_X ((zx_pci_irq_mode_t) 3u)

__END_CDECLS