mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2025-04-21 12:27:27 +03:00
[lantiq] move files/ -> files-3.3/
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34060 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
/******************************************************************************
|
||||
**
|
||||
** FILE NAME : ifxmips_fixup_pcie.c
|
||||
** PROJECT : IFX UEIP for VRX200
|
||||
** MODULES : PCIe
|
||||
**
|
||||
** DATE : 02 Mar 2009
|
||||
** AUTHOR : Lei Chuanhua
|
||||
** DESCRIPTION : PCIe Root Complex Driver
|
||||
** COPYRIGHT : Copyright (c) 2009
|
||||
** Infineon Technologies AG
|
||||
** Am Campeon 1-12, 85579 Neubiberg, Germany
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or
|
||||
** (at your option) any later version.
|
||||
** HISTORY
|
||||
** $Version $Date $Author $Comment
|
||||
** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version
|
||||
*******************************************************************************/
|
||||
/*!
|
||||
\file ifxmips_fixup_pcie.c
|
||||
\ingroup IFX_PCIE
|
||||
\brief PCIe Fixup functions source file
|
||||
*/
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_regs.h>
|
||||
#include <linux/pci_ids.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
#include "pcie-lantiq.h"
|
||||
|
||||
#define PCI_VENDOR_ID_INFINEON 0x15D1
|
||||
#define PCI_DEVICE_ID_INFINEON_DANUBE 0x000F
|
||||
#define PCI_DEVICE_ID_INFINEON_PCIE 0x0011
|
||||
#define PCI_VENDOR_ID_LANTIQ 0x1BEF
|
||||
#define PCI_DEVICE_ID_LANTIQ_PCIE 0x0011
|
||||
|
||||
|
||||
|
||||
static void __devinit
|
||||
ifx_pcie_fixup_resource(struct pci_dev *dev)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev));
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s: fixup host controller %s (%04x:%04x)\n",
|
||||
__func__, pci_name(dev), dev->vendor, dev->device);
|
||||
|
||||
/* Setup COMMAND register */
|
||||
reg = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER /* |
|
||||
PCI_COMMAND_INTX_DISABLE */| PCI_COMMAND_SERR;
|
||||
pci_write_config_word(dev, PCI_COMMAND, reg);
|
||||
IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev));
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE, ifx_pcie_fixup_resource);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_VENDOR_ID_LANTIQ, ifx_pcie_fixup_resource);
|
||||
|
||||
static void __devinit
|
||||
ifx_pcie_rc_class_early_fixup(struct pci_dev *dev)
|
||||
{
|
||||
IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev));
|
||||
|
||||
if (dev->devfn == PCI_DEVFN(0, 0) &&
|
||||
(dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
|
||||
|
||||
dev->class = (PCI_CLASS_BRIDGE_PCI << 8) | (dev->class & 0xff);
|
||||
|
||||
printk(KERN_INFO "%s: fixed pcie host bridge to pci-pci bridge\n", __func__);
|
||||
}
|
||||
IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev));
|
||||
}
|
||||
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE,
|
||||
ifx_pcie_rc_class_early_fixup);
|
||||
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_DEVICE_ID_LANTIQ_PCIE,
|
||||
ifx_pcie_rc_class_early_fixup);
|
||||
42
target/linux/lantiq/files-3.3/arch/mips/pci/fixup-lantiq.c
Normal file
42
target/linux/lantiq/files-3.3/arch/mips/pci/fixup-lantiq.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_pci.h>
|
||||
|
||||
int (*ltqpci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin) = NULL;
|
||||
int (*ltqpci_plat_arch_init)(struct pci_dev *dev) = NULL;
|
||||
int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
|
||||
int *ltq_pci_irq_map;
|
||||
|
||||
int pcibios_plat_dev_init(struct pci_dev *dev)
|
||||
{
|
||||
if (ltqpci_plat_arch_init)
|
||||
return ltqpci_plat_arch_init(dev);
|
||||
|
||||
if (ltqpci_plat_dev_init)
|
||||
return ltqpci_plat_dev_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
if (ltqpci_map_irq)
|
||||
return ltqpci_map_irq(dev, slot, pin);
|
||||
if (ltq_pci_irq_map[slot]) {
|
||||
dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, ltq_pci_irq_map[slot]);
|
||||
return ltq_pci_irq_map[slot];
|
||||
}
|
||||
printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n",
|
||||
slot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
399
target/linux/lantiq/files-3.3/arch/mips/pci/pcie-lantiq-msi.c
Normal file
399
target/linux/lantiq/files-3.3/arch/mips/pci/pcie-lantiq-msi.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/******************************************************************************
|
||||
**
|
||||
** FILE NAME : ifxmips_pcie_msi.c
|
||||
** PROJECT : IFX UEIP for VRX200
|
||||
** MODULES : PCI MSI sub module
|
||||
**
|
||||
** DATE : 02 Mar 2009
|
||||
** AUTHOR : Lei Chuanhua
|
||||
** DESCRIPTION : PCIe MSI Driver
|
||||
** COPYRIGHT : Copyright (c) 2009
|
||||
** Infineon Technologies AG
|
||||
** Am Campeon 1-12, 85579 Neubiberg, Germany
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or
|
||||
** (at your option) any later version.
|
||||
** HISTORY
|
||||
** $Date $Author $Comment
|
||||
** 02 Mar,2009 Lei Chuanhua Initial version
|
||||
*******************************************************************************/
|
||||
/*!
|
||||
\defgroup IFX_PCIE_MSI MSI OS APIs
|
||||
\ingroup IFX_PCIE
|
||||
\brief PCIe bus driver OS interface functions
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file ifxmips_pcie_msi.c
|
||||
\ingroup IFX_PCIE
|
||||
\brief PCIe MSI OS interface file
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
#include "pcie-lantiq.h"
|
||||
|
||||
#define IFX_MSI_IRQ_NUM 16
|
||||
#define SM(_v, _f) (((_v) << _f##_S) & (_f))
|
||||
|
||||
#define IFX_MSI_PIC_REG_BASE (KSEG1 | 0x1F700000)
|
||||
#define IFX_PCIE_MSI_IR0 (INT_NUM_IM4_IRL0 + 27)
|
||||
#define IFX_PCIE_MSI_IR1 (INT_NUM_IM4_IRL0 + 28)
|
||||
#define IFX_PCIE_MSI_IR2 (INT_NUM_IM4_IRL0 + 29)
|
||||
#define IFX_PCIE_MSI_IR3 (INT_NUM_IM0_IRL0 + 30)
|
||||
|
||||
#define IFX_MSI_PCI_INT_DISABLE 0x80000000
|
||||
#define IFX_MSI_PIC_INT_LINE 0x30000000
|
||||
#define IFX_MSI_PIC_MSG_ADDR 0x0FFF0000
|
||||
#define IFX_MSI_PIC_MSG_DATA 0x0000FFFF
|
||||
#define IFX_MSI_PIC_BIG_ENDIAN 1
|
||||
#define IFX_MSI_PIC_INT_LINE_S 28
|
||||
#define IFX_MSI_PIC_MSG_ADDR_S 16
|
||||
#define IFX_MSI_PIC_MSG_DATA_S 0x0
|
||||
|
||||
enum {
|
||||
IFX_PCIE_MSI_IDX0 = 0,
|
||||
IFX_PCIE_MSI_IDX1,
|
||||
IFX_PCIE_MSI_IDX2,
|
||||
IFX_PCIE_MSI_IDX3,
|
||||
};
|
||||
|
||||
typedef struct ifx_msi_irq_idx {
|
||||
const int irq;
|
||||
const int idx;
|
||||
}ifx_msi_irq_idx_t;
|
||||
|
||||
struct ifx_msi_pic {
|
||||
volatile u32 pic_table[IFX_MSI_IRQ_NUM];
|
||||
volatile u32 pic_endian; /* 0x40 */
|
||||
};
|
||||
typedef struct ifx_msi_pic *ifx_msi_pic_t;
|
||||
|
||||
typedef struct ifx_msi_irq {
|
||||
const volatile ifx_msi_pic_t msi_pic_p;
|
||||
const u32 msi_phy_base;
|
||||
const ifx_msi_irq_idx_t msi_irq_idx[IFX_MSI_IRQ_NUM];
|
||||
/*
|
||||
* Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
|
||||
* in use.
|
||||
*/
|
||||
u16 msi_free_irq_bitmask;
|
||||
|
||||
/*
|
||||
* Each bit in msi_multiple_irq_bitmask tells that the device using
|
||||
* this bit in msi_free_irq_bitmask is also using the next bit. This
|
||||
* is used so we can disable all of the MSI interrupts when a device
|
||||
* uses multiple.
|
||||
*/
|
||||
u16 msi_multiple_irq_bitmask;
|
||||
}ifx_msi_irq_t;
|
||||
|
||||
static ifx_msi_irq_t msi_irqs[IFX_PCIE_CORE_NR] = {
|
||||
{
|
||||
.msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI_PIC_REG_BASE,
|
||||
.msi_phy_base = PCIE_MSI_PHY_BASE,
|
||||
.msi_irq_idx = {
|
||||
{IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
|
||||
{IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
|
||||
{IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
|
||||
{IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
|
||||
{IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
|
||||
{IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
|
||||
{IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
|
||||
{IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
|
||||
},
|
||||
.msi_free_irq_bitmask = 0,
|
||||
.msi_multiple_irq_bitmask= 0,
|
||||
},
|
||||
#ifdef CONFIG_IFX_PCIE_2ND_CORE
|
||||
{
|
||||
.msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI1_PIC_REG_BASE,
|
||||
.msi_phy_base = PCIE1_MSI_PHY_BASE,
|
||||
.msi_irq_idx = {
|
||||
{IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
|
||||
{IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
|
||||
{IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
|
||||
{IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
|
||||
{IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
|
||||
{IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
|
||||
{IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
|
||||
{IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
|
||||
},
|
||||
.msi_free_irq_bitmask = 0,
|
||||
.msi_multiple_irq_bitmask= 0,
|
||||
|
||||
},
|
||||
#endif /* CONFIG_IFX_PCIE_2ND_CORE */
|
||||
};
|
||||
|
||||
/*
|
||||
* This lock controls updates to msi_free_irq_bitmask,
|
||||
* msi_multiple_irq_bitmask and pic register settting
|
||||
*/
|
||||
static DEFINE_SPINLOCK(ifx_pcie_msi_lock);
|
||||
|
||||
void pcie_msi_pic_init(int pcie_port)
|
||||
{
|
||||
spin_lock(&ifx_pcie_msi_lock);
|
||||
msi_irqs[pcie_port].msi_pic_p->pic_endian = IFX_MSI_PIC_BIG_ENDIAN;
|
||||
spin_unlock(&ifx_pcie_msi_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
|
||||
* \brief Called when a driver request MSI interrupts instead of the
|
||||
* legacy INT A-D. This routine will allocate multiple interrupts
|
||||
* for MSI devices that support them. A device can override this by
|
||||
* programming the MSI control bits [6:4] before calling
|
||||
* pci_enable_msi().
|
||||
*
|
||||
* \param[in] pdev Device requesting MSI interrupts
|
||||
* \param[in] desc MSI descriptor
|
||||
*
|
||||
* \return -EINVAL Invalid pcie root port or invalid msi bit
|
||||
* \return 0 OK
|
||||
* \ingroup IFX_PCIE_MSI
|
||||
*/
|
||||
int
|
||||
arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
|
||||
{
|
||||
int irq, pos;
|
||||
u16 control;
|
||||
int irq_idx;
|
||||
int irq_step;
|
||||
int configured_private_bits;
|
||||
int request_private_bits;
|
||||
struct msi_msg msg;
|
||||
u16 search_mask;
|
||||
struct ifx_pci_controller *ctrl = pdev->bus->sysdata;
|
||||
int pcie_port = ctrl->port;
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s %s enter\n", __func__, pci_name(pdev));
|
||||
|
||||
/* XXX, skip RC MSI itself */
|
||||
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s RC itself doesn't use MSI interrupt\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the MSI config to figure out how many IRQs this device
|
||||
* wants. Most devices only want 1, which will give
|
||||
* configured_private_bits and request_private_bits equal 0.
|
||||
*/
|
||||
pci_read_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &control);
|
||||
|
||||
/*
|
||||
* If the number of private bits has been configured then use
|
||||
* that value instead of the requested number. This gives the
|
||||
* driver the chance to override the number of interrupts
|
||||
* before calling pci_enable_msi().
|
||||
*/
|
||||
configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4;
|
||||
if (configured_private_bits == 0) {
|
||||
/* Nothing is configured, so use the hardware requested size */
|
||||
request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Use the number of configured bits, assuming the
|
||||
* driver wanted to override the hardware request
|
||||
* value.
|
||||
*/
|
||||
request_private_bits = configured_private_bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PCI 2.3 spec mandates that there are at most 32
|
||||
* interrupts. If this device asks for more, only give it one.
|
||||
*/
|
||||
if (request_private_bits > 5) {
|
||||
request_private_bits = 0;
|
||||
}
|
||||
again:
|
||||
/*
|
||||
* The IRQs have to be aligned on a power of two based on the
|
||||
* number being requested.
|
||||
*/
|
||||
irq_step = (1 << request_private_bits);
|
||||
|
||||
/* Mask with one bit for each IRQ */
|
||||
search_mask = (1 << irq_step) - 1;
|
||||
|
||||
/*
|
||||
* We're going to search msi_free_irq_bitmask_lock for zero
|
||||
* bits. This represents an MSI interrupt number that isn't in
|
||||
* use.
|
||||
*/
|
||||
spin_lock(&ifx_pcie_msi_lock);
|
||||
for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos += irq_step) {
|
||||
if ((msi_irqs[pcie_port].msi_free_irq_bitmask & (search_mask << pos)) == 0) {
|
||||
msi_irqs[pcie_port].msi_free_irq_bitmask |= search_mask << pos;
|
||||
msi_irqs[pcie_port].msi_multiple_irq_bitmask |= (search_mask >> 1) << pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ifx_pcie_msi_lock);
|
||||
|
||||
/* Make sure the search for available interrupts didn't fail */
|
||||
if (pos >= IFX_MSI_IRQ_NUM) {
|
||||
if (request_private_bits) {
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s: Unable to find %d free "
|
||||
"interrupts, trying just one", __func__, 1 << request_private_bits);
|
||||
request_private_bits = 0;
|
||||
goto again;
|
||||
}
|
||||
else {
|
||||
printk(KERN_ERR "%s: Unable to find a free MSI interrupt\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
irq = msi_irqs[pcie_port].msi_irq_idx[pos].irq;
|
||||
irq_idx = msi_irqs[pcie_port].msi_irq_idx[pos].idx;
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "pos %d, irq %d irq_idx %d\n", pos, irq, irq_idx);
|
||||
|
||||
/*
|
||||
* Initialize MSI. This has to match the memory-write endianess from the device
|
||||
* Address bits [23:12]
|
||||
*/
|
||||
spin_lock(&ifx_pcie_msi_lock);
|
||||
msi_irqs[pcie_port].msi_pic_p->pic_table[pos] = SM(irq_idx, IFX_MSI_PIC_INT_LINE) |
|
||||
SM((msi_irqs[pcie_port].msi_phy_base >> 12), IFX_MSI_PIC_MSG_ADDR) |
|
||||
SM((1 << pos), IFX_MSI_PIC_MSG_DATA);
|
||||
|
||||
/* Enable this entry */
|
||||
msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~IFX_MSI_PCI_INT_DISABLE;
|
||||
spin_unlock(&ifx_pcie_msi_lock);
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "pic_table[%d]: 0x%08x\n",
|
||||
pos, msi_irqs[pcie_port].msi_pic_p->pic_table[pos]);
|
||||
|
||||
/* Update the number of IRQs the device has available to it */
|
||||
control &= ~PCI_MSI_FLAGS_QSIZE;
|
||||
control |= (request_private_bits << 4);
|
||||
pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, control);
|
||||
|
||||
irq_set_msi_desc(irq, desc);
|
||||
msg.address_hi = 0x0;
|
||||
msg.address_lo = msi_irqs[pcie_port].msi_phy_base;
|
||||
msg.data = SM((1 << pos), IFX_MSI_PIC_MSG_DATA);
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "msi_data: pos %d 0x%08x\n", pos, msg.data);
|
||||
|
||||
write_msi_msg(irq, &msg);
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pcie_msi_irq_to_port(unsigned int irq, int *port)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (irq == IFX_PCIE_MSI_IR0 || irq == IFX_PCIE_MSI_IR1 ||
|
||||
irq == IFX_PCIE_MSI_IR2 || irq == IFX_PCIE_MSI_IR3) {
|
||||
*port = IFX_PCIE_PORT0;
|
||||
}
|
||||
#ifdef CONFIG_IFX_PCIE_2ND_CORE
|
||||
else if (irq == IFX_PCIE1_MSI_IR0 || irq == IFX_PCIE1_MSI_IR1 ||
|
||||
irq == IFX_PCIE1_MSI_IR2 || irq == IFX_PCIE1_MSI_IR3) {
|
||||
*port = IFX_PCIE_PORT1;
|
||||
}
|
||||
#endif /* CONFIG_IFX_PCIE_2ND_CORE */
|
||||
else {
|
||||
printk(KERN_ERR "%s: Attempted to teardown illegal "
|
||||
"MSI interrupt (%d)\n", __func__, irq);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn void arch_teardown_msi_irq(unsigned int irq)
|
||||
* \brief Called when a device no longer needs its MSI interrupts. All
|
||||
* MSI interrupts for the device are freed.
|
||||
*
|
||||
* \param irq The devices first irq number. There may be multple in sequence.
|
||||
* \return none
|
||||
* \ingroup IFX_PCIE_MSI
|
||||
*/
|
||||
void
|
||||
arch_teardown_msi_irq(unsigned int irq)
|
||||
{
|
||||
int pos;
|
||||
int number_irqs;
|
||||
u16 bitmask;
|
||||
int pcie_port;
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s enter\n", __func__);
|
||||
|
||||
BUG_ON(irq > (INT_NUM_IM4_IRL0 + 31));
|
||||
|
||||
if (pcie_msi_irq_to_port(irq, &pcie_port) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Shift the mask to the correct bit location, not always correct
|
||||
* Probally, the first match will be chosen.
|
||||
*/
|
||||
for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos++) {
|
||||
if ((msi_irqs[pcie_port].msi_irq_idx[pos].irq == irq)
|
||||
&& (msi_irqs[pcie_port].msi_free_irq_bitmask & ( 1 << pos))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos >= IFX_MSI_IRQ_NUM) {
|
||||
printk(KERN_ERR "%s: Unable to find a matched MSI interrupt\n", __func__);
|
||||
return;
|
||||
}
|
||||
spin_lock(&ifx_pcie_msi_lock);
|
||||
/* Disable this entry */
|
||||
msi_irqs[pcie_port].msi_pic_p->pic_table[pos] |= IFX_MSI_PCI_INT_DISABLE;
|
||||
msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~(IFX_MSI_PIC_INT_LINE | IFX_MSI_PIC_MSG_ADDR | IFX_MSI_PIC_MSG_DATA);
|
||||
spin_unlock(&ifx_pcie_msi_lock);
|
||||
/*
|
||||
* Count the number of IRQs we need to free by looking at the
|
||||
* msi_multiple_irq_bitmask. Each bit set means that the next
|
||||
* IRQ is also owned by this device.
|
||||
*/
|
||||
number_irqs = 0;
|
||||
while (((pos + number_irqs) < IFX_MSI_IRQ_NUM) &&
|
||||
(msi_irqs[pcie_port].msi_multiple_irq_bitmask & (1 << (pos + number_irqs)))) {
|
||||
number_irqs++;
|
||||
}
|
||||
number_irqs++;
|
||||
|
||||
/* Mask with one bit for each IRQ */
|
||||
bitmask = (1 << number_irqs) - 1;
|
||||
|
||||
bitmask <<= pos;
|
||||
if ((msi_irqs[pcie_port].msi_free_irq_bitmask & bitmask) != bitmask) {
|
||||
printk(KERN_ERR "%s: Attempted to teardown MSI "
|
||||
"interrupt (%d) not in use\n", __func__, irq);
|
||||
return;
|
||||
}
|
||||
/* Checks are done, update the in use bitmask */
|
||||
spin_lock(&ifx_pcie_msi_lock);
|
||||
msi_irqs[pcie_port].msi_free_irq_bitmask &= ~bitmask;
|
||||
msi_irqs[pcie_port].msi_multiple_irq_bitmask &= ~(bitmask >> 1);
|
||||
spin_unlock(&ifx_pcie_msi_lock);
|
||||
IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Chuanhua.Lei@infineon.com");
|
||||
MODULE_SUPPORTED_DEVICE("Infineon PCIe IP builtin MSI PIC module");
|
||||
MODULE_DESCRIPTION("Infineon PCIe IP builtin MSI PIC driver");
|
||||
|
||||
408
target/linux/lantiq/files-3.3/arch/mips/pci/pcie-lantiq-phy.c
Normal file
408
target/linux/lantiq/files-3.3/arch/mips/pci/pcie-lantiq-phy.c
Normal file
@@ -0,0 +1,408 @@
|
||||
/******************************************************************************
|
||||
**
|
||||
** FILE NAME : ifxmips_pcie_phy.c
|
||||
** PROJECT : IFX UEIP for VRX200
|
||||
** MODULES : PCIe PHY sub module
|
||||
**
|
||||
** DATE : 14 May 2009
|
||||
** AUTHOR : Lei Chuanhua
|
||||
** DESCRIPTION : PCIe Root Complex Driver
|
||||
** COPYRIGHT : Copyright (c) 2009
|
||||
** Infineon Technologies AG
|
||||
** Am Campeon 1-12, 85579 Neubiberg, Germany
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or
|
||||
** (at your option) any later version.
|
||||
** HISTORY
|
||||
** $Version $Date $Author $Comment
|
||||
** 0.0.1 14 May,2009 Lei Chuanhua Initial version
|
||||
*******************************************************************************/
|
||||
/*!
|
||||
\file ifxmips_pcie_phy.c
|
||||
\ingroup IFX_PCIE
|
||||
\brief PCIe PHY PLL register programming source file
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/paccess.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "pcie-lantiq.h"
|
||||
|
||||
/* PCIe PDI only supports 16 bit operation */
|
||||
|
||||
#define IFX_PCIE_PHY_REG_WRITE16(__addr, __data) \
|
||||
((*(volatile u16 *) (__addr)) = (__data))
|
||||
|
||||
#define IFX_PCIE_PHY_REG_READ16(__addr) \
|
||||
(*(volatile u16 *) (__addr))
|
||||
|
||||
#define IFX_PCIE_PHY_REG16(__addr) \
|
||||
(*(volatile u16 *) (__addr))
|
||||
|
||||
#define IFX_PCIE_PHY_REG(__reg, __value, __mask) do { \
|
||||
u16 read_data; \
|
||||
u16 write_data; \
|
||||
read_data = IFX_PCIE_PHY_REG_READ16((__reg)); \
|
||||
write_data = (read_data & ((u16)~(__mask))) | (((u16)(__value)) & ((u16)(__mask)));\
|
||||
IFX_PCIE_PHY_REG_WRITE16((__reg), write_data); \
|
||||
} while (0)
|
||||
|
||||
#define IFX_PCIE_PLL_TIMEOUT 1000 /* Tunnable */
|
||||
|
||||
static void
|
||||
pcie_phy_comm_setup(int pcie_port)
|
||||
{
|
||||
/* PLL Setting */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF);
|
||||
|
||||
/* increase the bias reference voltage */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF);
|
||||
|
||||
/* Endcnt */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF);
|
||||
|
||||
/* force */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008);
|
||||
|
||||
/* predrv_ser_en */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF);
|
||||
|
||||
/* ctrl_lim */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF);
|
||||
|
||||
/* ctrl */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00);
|
||||
|
||||
/* predrv_ser_en */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00);
|
||||
|
||||
/* RTERM*/
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF);
|
||||
|
||||
/* Improved 100MHz clock output */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF);
|
||||
|
||||
/* Reduced CDR BW to avoid glitches */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE
|
||||
static void
|
||||
pcie_phy_36mhz_mode_setup(int pcie_port)
|
||||
{
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port);
|
||||
|
||||
/* en_ext_mmd_div_ratio */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002);
|
||||
|
||||
/* ext_mmd_div_ratio*/
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070);
|
||||
|
||||
/* pll_ensdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200);
|
||||
|
||||
/* en_const_sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100);
|
||||
|
||||
/* mmd */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000);
|
||||
|
||||
/* lf_mode */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000);
|
||||
|
||||
/* const_sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF);
|
||||
|
||||
/* const sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF);
|
||||
|
||||
/* pllmod */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF);
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port);
|
||||
}
|
||||
#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */
|
||||
|
||||
#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE
|
||||
static void
|
||||
pcie_phy_36mhz_ssc_mode_setup(int pcie_port)
|
||||
{
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port);
|
||||
|
||||
/* PLL Setting */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF);
|
||||
|
||||
/* Increase the bias reference voltage */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF);
|
||||
|
||||
/* Endcnt */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF);
|
||||
|
||||
/* Force */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008);
|
||||
|
||||
/* Predrv_ser_en */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF);
|
||||
|
||||
/* ctrl_lim */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF);
|
||||
|
||||
/* ctrl */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00);
|
||||
|
||||
/* predrv_ser_en */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00);
|
||||
|
||||
/* RTERM*/
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF);
|
||||
|
||||
/* en_ext_mmd_div_ratio */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002);
|
||||
|
||||
/* ext_mmd_div_ratio*/
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070);
|
||||
|
||||
/* pll_ensdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0400, 0x0400);
|
||||
|
||||
/* en_const_sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200);
|
||||
|
||||
/* mmd */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000);
|
||||
|
||||
/* lf_mode */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000);
|
||||
|
||||
/* const_sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF);
|
||||
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0100);
|
||||
/* const sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF);
|
||||
|
||||
/* pllmod */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1c72, 0xFFFF);
|
||||
|
||||
/* improved 100MHz clock output */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF);
|
||||
|
||||
/* reduced CDR BW to avoid glitches */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF);
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port);
|
||||
}
|
||||
#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE */
|
||||
|
||||
#ifdef CONFIG_IFX_PCIE_PHY_25MHZ_MODE
|
||||
static void
|
||||
pcie_phy_25mhz_mode_setup(int pcie_port)
|
||||
{
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port);
|
||||
/* en_const_sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100);
|
||||
|
||||
/* pll_ensdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0200);
|
||||
|
||||
/* en_ext_mmd_div_ratio*/
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0002, 0x0002);
|
||||
|
||||
/* ext_mmd_div_ratio*/
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0040, 0x0070);
|
||||
|
||||
/* mmd */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x6000, 0xe000);
|
||||
|
||||
/* lf_mode */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x4000, 0x4000);
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port);
|
||||
}
|
||||
#endif /* CONFIG_IFX_PCIE_PHY_25MHZ_MODE */
|
||||
|
||||
#ifdef CONFIG_IFX_PCIE_PHY_100MHZ_MODE
|
||||
static void
|
||||
pcie_phy_100mhz_mode_setup(int pcie_port)
|
||||
{
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port);
|
||||
/* en_ext_mmd_div_ratio */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002);
|
||||
|
||||
/* ext_mmd_div_ratio*/
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070);
|
||||
|
||||
/* pll_ensdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200);
|
||||
|
||||
/* en_const_sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100);
|
||||
|
||||
/* mmd */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000);
|
||||
|
||||
/* lf_mode */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000);
|
||||
|
||||
/* const_sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF);
|
||||
|
||||
/* const sdm */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF);
|
||||
|
||||
/* pllmod */
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF);
|
||||
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port);
|
||||
}
|
||||
#endif /* CONFIG_IFX_PCIE_PHY_100MHZ_MODE */
|
||||
|
||||
static int
|
||||
pcie_phy_wait_startup_ready(int pcie_port)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IFX_PCIE_PLL_TIMEOUT; i++) {
|
||||
if ((IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_STATUS(pcie_port)) & 0x0040) != 0) {
|
||||
break;
|
||||
}
|
||||
udelay(10);
|
||||
}
|
||||
if (i >= IFX_PCIE_PLL_TIMEOUT) {
|
||||
printk(KERN_ERR "%s PLL Link timeout\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pcie_phy_load_enable(int pcie_port, int slice)
|
||||
{
|
||||
/* Set the load_en of tx/rx slice to '1' */
|
||||
switch (slice) {
|
||||
case 1:
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0010, 0x0010);
|
||||
break;
|
||||
case 2:
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0010, 0x0010);
|
||||
break;
|
||||
case 3:
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0002, 0x0002);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pcie_phy_load_disable(int pcie_port, int slice)
|
||||
{
|
||||
/* set the load_en of tx/rx slice to '0' */
|
||||
switch (slice) {
|
||||
case 1:
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0000, 0x0010);
|
||||
break;
|
||||
case 2:
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0000, 0x0010);
|
||||
break;
|
||||
case 3:
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0000, 0x0002);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pcie_phy_load_war(int pcie_port)
|
||||
{
|
||||
int slice;
|
||||
|
||||
for (slice = 1; slice < 4; slice++) {
|
||||
pcie_phy_load_enable(pcie_port, slice);
|
||||
udelay(1);
|
||||
pcie_phy_load_disable(pcie_port, slice);
|
||||
}
|
||||
}
|
||||
|
||||
static void pcie_phy_tx2_modulation(int pcie_port)
|
||||
{
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD1(pcie_port), 0x1FFE, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD2(pcie_port), 0xFFFE, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0601, 0xFFFF);
|
||||
mdelay(1);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0001, 0xFFFF);
|
||||
}
|
||||
|
||||
static void pcie_phy_tx1_modulation(int pcie_port)
|
||||
{
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD1(pcie_port), 0x1FFE, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD2(pcie_port), 0xFFFE, 0xFFFF);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0601, 0xFFFF);
|
||||
mdelay(1);
|
||||
IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0001, 0xFFFF);
|
||||
}
|
||||
|
||||
static void pcie_phy_tx_modulation_war(int pcie_port)
|
||||
{
|
||||
int i;
|
||||
#define PCIE_PHY_MODULATION_NUM 5
|
||||
for (i = 0; i < PCIE_PHY_MODULATION_NUM; i++) {
|
||||
pcie_phy_tx2_modulation(pcie_port);
|
||||
pcie_phy_tx1_modulation(pcie_port);
|
||||
}
|
||||
#undef PCIE_PHY_MODULATION_NUM
|
||||
}
|
||||
|
||||
void pcie_phy_clock_mode_setup(int pcie_port)
|
||||
{
|
||||
pcie_pdi_big_endian(pcie_port);
|
||||
|
||||
/* Enable PDI to access PCIe PHY register */
|
||||
pcie_pdi_pmu_enable(pcie_port);
|
||||
|
||||
/* Configure PLL and PHY clock */
|
||||
pcie_phy_comm_setup(pcie_port);
|
||||
|
||||
#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE
|
||||
pcie_phy_36mhz_mode_setup(pcie_port);
|
||||
#elif defined(CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE)
|
||||
pcie_phy_36mhz_ssc_mode_setup(pcie_port);
|
||||
#elif defined(CONFIG_IFX_PCIE_PHY_25MHZ_MODE)
|
||||
pcie_phy_25mhz_mode_setup(pcie_port);
|
||||
#elif defined (CONFIG_IFX_PCIE_PHY_100MHZ_MODE)
|
||||
pcie_phy_100mhz_mode_setup(pcie_port);
|
||||
#else
|
||||
#error "PCIE PHY Clock Mode must be chosen first!!!!"
|
||||
#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */
|
||||
|
||||
/* Enable PCIe PHY and make PLL setting take effect */
|
||||
pcie_phy_pmu_enable(pcie_port);
|
||||
|
||||
/* Check if we are in startup_ready status */
|
||||
pcie_phy_wait_startup_ready(pcie_port);
|
||||
|
||||
pcie_phy_load_war(pcie_port);
|
||||
|
||||
/* Apply TX modulation workarounds */
|
||||
pcie_phy_tx_modulation_war(pcie_port);
|
||||
|
||||
#ifdef IFX_PCI_PHY_REG_DUMP
|
||||
IFX_PCIE_PRINT(PCIE_MSG_PHY, "Modified PHY register dump\n");
|
||||
pcie_phy_reg_dump(pcie_port);
|
||||
#endif
|
||||
}
|
||||
|
||||
1146
target/linux/lantiq/files-3.3/arch/mips/pci/pcie-lantiq.c
Normal file
1146
target/linux/lantiq/files-3.3/arch/mips/pci/pcie-lantiq.c
Normal file
File diff suppressed because it is too large
Load Diff
1305
target/linux/lantiq/files-3.3/arch/mips/pci/pcie-lantiq.h
Normal file
1305
target/linux/lantiq/files-3.3/arch/mips/pci/pcie-lantiq.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user