Add support imx6 PCIe controller.

This commit is contained in:
hkenken 2016-11-24 12:06:43 +00:00
parent 713e0a32de
commit 5dbe7c6e5b
6 changed files with 1457 additions and 13 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files.imx6,v 1.7 2016/05/17 06:44:45 ryo Exp $
# $NetBSD: files.imx6,v 1.8 2016/11/24 12:06:43 hkenken Exp $
#
# Configuration info for the Freescale i.MX6
#
@ -26,6 +26,11 @@ device axi { [addr=-1], [size=0], [irq=-1], [irqbase=-1]} : bus_space_generic
attach axi at mainbus
file arch/arm/imx/imx6_axi.c axi
# iMX6 PCIe
device imxpcie: pcibus
attach imxpcie at axi
file arch/arm/imx/imx6_pcie.c imxpcie
# iMX6 Clock Control Module
device imxccm
attach imxccm at axi
@ -101,4 +106,3 @@ device imxsnvs
attach imxsnvs at axi
file arch/arm/imx/imxsnvs.c imxsnvs
file arch/arm/imx/imx6_snvs.c imxsnvs

View File

@ -0,0 +1,942 @@
/* $NetBSD: imx6_pcie.c,v 1.1 2016/11/24 12:06:43 hkenken Exp $ */
/*
* Copyright (c) 2016 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* i.MX6 On-Chip PCI Express Controller
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_pcie.c,v 1.1 2016/11/24 12:06:43 hkenken Exp $");
#include "opt_pci.h"
#include "opt_imx6pcie.h"
#include "pci.h"
#include "imxgpio.h"
#include "locators.h"
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/extent.h>
#include <sys/queue.h>
#include <sys/mutex.h>
#include <sys/kmem.h>
#include <sys/gpio.h>
#include <machine/frame.h>
#include <arm/cpufunc.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pciconf.h>
#include <arm/imx/imxgpioreg.h>
#include <arm/imx/imxgpiovar.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_pciereg.h>
#include <arm/imx/imx6_iomuxreg.h>
#include <arm/imx/imx6_ccmreg.h>
#include <arm/imx/imx6_ccmvar.h>
static int imx6pcie_match(device_t, cfdata_t, void *);
static void imx6pcie_attach(device_t, device_t, void *);
#define IMX6_PCIE_MEM_BASE 0x01000000
#define IMX6_PCIE_MEM_SIZE 0x00f00000 /* 15MB */
#define IMX6_PCIE_ROOT_BASE 0x01f00000
#define IMX6_PCIE_ROOT_SIZE 0x00080000 /* 512KB */
#define IMX6_PCIE_IO_BASE 0x01f80000
#define IMX6_PCIE_IO_SIZE 0x00010000 /* 64KB */
struct imx6pcie_ih {
int (*ih_handler)(void *);
void *ih_arg;
int ih_ipl;
TAILQ_ENTRY(imx6pcie_ih) ih_entry;
};
struct imx6pcie_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_space_handle_t sc_root_ioh;
bus_dma_tag_t sc_dmat;
struct arm32_pci_chipset sc_pc;
TAILQ_HEAD(, imx6pcie_ih) sc_intrs;
void *sc_ih;
kmutex_t sc_lock;
u_int sc_intrgen;
int32_t sc_gpio_reset;
int32_t sc_gpio_reset_active;
int32_t sc_gpio_pwren;
int32_t sc_gpio_pwren_active;
};
#define PCIE_CONF_LOCK(s) (s) = disable_interrupts(I32_bit)
#define PCIE_CONF_UNLOCK(s) restore_interrupts((s))
#define PCIE_READ(sc, reg) \
bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, reg)
#define PCIE_WRITE(sc, reg, val) \
bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, reg, val)
static int imx6pcie_intr(void *);
static void imx6pcie_init(pci_chipset_tag_t, void *);
static void imx6pcie_setup(struct imx6pcie_softc * const);
static void imx6pcie_attach_hook(device_t, device_t,
struct pcibus_attach_args *);
static int imx6pcie_bus_maxdevs(void *, int);
static pcitag_t imx6pcie_make_tag(void *, int, int, int);
static void imx6pcie_decompose_tag(void *, pcitag_t, int *, int *, int *);
static pcireg_t imx6pcie_conf_read(void *, pcitag_t, int);
static void imx6pcie_conf_write(void *, pcitag_t, int, pcireg_t);
#ifdef __HAVE_PCI_CONF_HOOK
static int imx6pcie_conf_hook(void *, int, int, int, pcireg_t);
#endif
static void imx6pcie_conf_interrupt(void *, int, int, int, int, int *);
static int imx6pcie_intr_map(const struct pci_attach_args *,
pci_intr_handle_t *);
static const char *imx6pcie_intr_string(void *, pci_intr_handle_t,
char *, size_t);
const struct evcnt *imx6pcie_intr_evcnt(void *, pci_intr_handle_t);
static void * imx6pcie_intr_establish(void *, pci_intr_handle_t,
int, int (*)(void *), void *);
static void imx6pcie_intr_disestablish(void *, void *);
CFATTACH_DECL_NEW(imxpcie, sizeof(struct imx6pcie_softc),
imx6pcie_match, imx6pcie_attach, NULL, NULL);
static void
imx6pcie_clock_enable(struct imx6pcie_softc *sc)
{
uint32_t v;
v = imx6_ccm_read(CCM_ANALOG_MISC1);
v &= ~CCM_ANALOG_MISC1_LVDS_CLK1_IBEN;
v &= ~CCM_ANALOG_MISC1_LVDS_CLK1_SRC;
v |= CCM_ANALOG_MISC1_LVDS_CLK1_OBEN;
v |= CCM_ANALOG_MISC1_LVDS_CLK1_SRC_SATA;
imx6_ccm_write(CCM_ANALOG_MISC1, v);
/* select PCIe clock source from axi */
v = imx6_ccm_read(CCM_CBCMR);
v &= ~CCM_CBCMR_PCIE_AXI_CLK_SEL;
imx6_ccm_write(CCM_CBCMR, v);
/* AHCISATA clock enable */
v = imx6_ccm_read(CCM_CCGR5);
v |= CCM_CCGR5_100M_CLK_ENABLE(3);
imx6_ccm_write(CCM_CCGR5, v);
/* PCIe clock enable */
v = imx6_ccm_read(CCM_CCGR4);
v |= CCM_CCGR4_125M_ROOT_ENABLE(3);
imx6_ccm_write(CCM_CCGR4, v);
/* PLL power up */
if (imx6_pll_power(CCM_ANALOG_PLL_ENET, 1,
CCM_ANALOG_PLL_ENET_ENABLE_125M |
CCM_ANALOG_PLL_ENET_ENABLE_100M) != 0) {
aprint_error_dev(sc->sc_dev,
"couldn't enable CCM_ANALOG_PLL_ENET\n");
return;
}
}
static int
imx6pcie_init_phy(struct imx6pcie_softc *sc)
{
uint32_t v;
/* initialize IOMUX */
v = iomux_read(IOMUX_GPR12);
v &= ~IOMUX_GPR12_APP_LTSSM_ENABLE;
iomux_write(IOMUX_GPR12, v);
v &= ~IOMUX_GPR12_DEVICE_TYPE;
v |= IOMUX_GPR12_DEVICE_TYPE_PCIE_RC;
iomux_write(IOMUX_GPR12, v);
v &= ~IOMUX_GPR12_LOS_LEVEL;
v |= __SHIFTIN(9, IOMUX_GPR12_LOS_LEVEL);
iomux_write(IOMUX_GPR12, v);
v = 0;
v |= __SHIFTIN(0x7f, IOMUX_GPR8_PCS_TX_SWING_LOW);
v |= __SHIFTIN(0x7f, IOMUX_GPR8_PCS_TX_SWING_FULL);
v |= __SHIFTIN(20, IOMUX_GPR8_PCS_TX_DEEMPH_GEN2_6DB);
v |= __SHIFTIN(0, IOMUX_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB);
v |= __SHIFTIN(0, IOMUX_GPR8_PCS_TX_DEEMPH_GEN1);
iomux_write(IOMUX_GPR8, v);
return 0;
}
static int
imx6pcie_phy_wait_ack(struct imx6pcie_softc *sc, int ack)
{
uint32_t v;
int timeout;
for (timeout = 10; timeout > 0; --timeout) {
v = PCIE_READ(sc, PCIE_PL_PHY_STATUS);
if (!!(v & PCIE_PL_PHY_STATUS_ACK) == !!ack)
return 0;
delay(1);
}
return -1;
}
static int
imx6pcie_phy_addr(struct imx6pcie_softc *sc, uint32_t addr)
{
uint32_t v;
v = __SHIFTIN(addr, PCIE_PL_PHY_CTRL_DATA);
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, v);
v |= PCIE_PL_PHY_CTRL_CAP_ADR;
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, v);
if (imx6pcie_phy_wait_ack(sc, 1))
return -1;
v = __SHIFTIN(addr, PCIE_PL_PHY_CTRL_DATA);
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, v);
if (imx6pcie_phy_wait_ack(sc, 0))
return -1;
return 0;
}
static int
imx6pcie_phy_write(struct imx6pcie_softc *sc, uint32_t addr, uint16_t data)
{
/* write address */
if (imx6pcie_phy_addr(sc, addr) != 0)
return -1;
/* store data */
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, __SHIFTIN(data, PCIE_PL_PHY_CTRL_DATA));
/* assert CAP_DAT and wait ack */
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, __SHIFTIN(data, PCIE_PL_PHY_CTRL_DATA) | PCIE_PL_PHY_CTRL_CAP_DAT);
if (imx6pcie_phy_wait_ack(sc, 1))
return -1;
/* deassert CAP_DAT and wait ack */
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, __SHIFTIN(data, PCIE_PL_PHY_CTRL_DATA));
if (imx6pcie_phy_wait_ack(sc, 0))
return -1;
/* assert WR and wait ack */
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, PCIE_PL_PHY_CTRL_WR);
if (imx6pcie_phy_wait_ack(sc, 1))
return -1;
/* deassert WR and wait ack */
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, __SHIFTIN(data, PCIE_PL_PHY_CTRL_DATA));
if (imx6pcie_phy_wait_ack(sc, 0))
return -1;
/* done */
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, 0);
return 0;
}
static int
imx6pcie_phy_read(struct imx6pcie_softc *sc, uint32_t addr)
{
uint32_t v;
/* write address */
if (imx6pcie_phy_addr(sc, addr) != 0)
return -1;
/* assert RD */
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, PCIE_PL_PHY_CTRL_RD);
if (imx6pcie_phy_wait_ack(sc, 1))
return -1;
/* read data */
v = __SHIFTOUT(PCIE_READ(sc, PCIE_PL_PHY_STATUS),
PCIE_PL_PHY_STATUS_DATA);
/* deassert RD */
PCIE_WRITE(sc, PCIE_PL_PHY_CTRL, 0);
if (imx6pcie_phy_wait_ack(sc, 0))
return -1;
return v;
}
static int
imx6pcie_assert_core_reset(struct imx6pcie_softc *sc)
{
uint32_t gpr1;
uint32_t gpr12;
gpr1 = iomux_read(IOMUX_GPR1);
gpr12 = iomux_read(IOMUX_GPR12);
/* already enabled by bootloader */
if ((gpr1 & IOMUX_GPR1_REF_SSP_EN) &&
(gpr12 & IOMUX_GPR12_APP_LTSSM_ENABLE)) {
uint32_t v = PCIE_READ(sc, PCIE_PL_PFLR);
v &= ~PCIE_PL_PFLR_LINK_STATE;
v |= PCIE_PL_PFLR_FORCE_LINK;
PCIE_WRITE(sc, PCIE_PL_PFLR, v);
gpr12 &= ~IOMUX_GPR12_APP_LTSSM_ENABLE;
iomux_write(IOMUX_GPR12, gpr12);
}
#if defined(IMX6DQP)
gpr1 |= IOMUX_GPR1_PCIE_SW_RST;
iomux_write(IOMUX_GPR1, gpr1);
#endif
gpr1 |= IOMUX_GPR1_TEST_POWERDOWN;
iomux_write(IOMUX_GPR1, gpr1);
gpr1 &= ~IOMUX_GPR1_REF_SSP_EN;
iomux_write(IOMUX_GPR1, gpr1);
return 0;
}
static int
imx6pcie_deassert_core_reset(struct imx6pcie_softc *sc)
{
uint32_t v;
/* Power ON */
#if NIMXGPIO > 0
if (sc->sc_gpio_pwren >= 0) {
gpio_data_write(sc->sc_gpio_pwren, sc->sc_gpio_pwren_active);
delay(100 * 1000);
gpio_data_write(sc->sc_gpio_pwren, !sc->sc_gpio_pwren_active);
}
#endif
imx6pcie_clock_enable(sc);
v = iomux_read(IOMUX_GPR1);
#if defined(IMX6DQP)
v &= ~IOMUX_GPR1_PCIE_SW_RST;
iomux_write(IOMUX_GPR1, v);
#endif
delay(50 * 1000);
v &= ~IOMUX_GPR1_TEST_POWERDOWN;
iomux_write(IOMUX_GPR1, v);
delay(10);
v |= IOMUX_GPR1_REF_SSP_EN;
iomux_write(IOMUX_GPR1, v);
delay(50 * 1000);
/* Reset */
#if NIMXGPIO > 0
if (sc->sc_gpio_reset >= 0) {
gpio_data_write(sc->sc_gpio_reset, sc->sc_gpio_reset_active);
delay(100 * 1000);
gpio_data_write(sc->sc_gpio_reset, !sc->sc_gpio_reset_active);
}
#endif
return 0;
}
static int
imx6pcie_wait_for_link(struct imx6pcie_softc *sc)
{
uint32_t ltssm, valid, v;
uint32_t linkup;
int retry;
#define LINKUP_RETRY 200
for (retry = LINKUP_RETRY; retry > 0; --retry) {
linkup = PCIE_READ(sc, PCIE_PL_DEBUG1);
if ((linkup & PCIE_PL_DEBUG1_XMLH_LINK_UP) &&
!(linkup & PCIE_PL_DEBUG1_XMLH_LINK_IN_TRAINING)) {
delay(100);
continue;
}
valid = imx6pcie_phy_read(sc, PCIE_PHY_RX_ASIC_OUT) &
PCIE_PHY_RX_ASIC_OUT_VALID;
ltssm = __SHIFTOUT(PCIE_READ(sc, PCIE_PL_DEBUG0),
PCIE_PL_DEBUG0_XMLH_LTSSM_STATE);
if ((ltssm == 0x0d) && !valid) {
aprint_normal_dev(sc->sc_dev, "resetting PCIe phy\n");
v = imx6pcie_phy_read(sc, PCIE_PHY_RX_OVRD_IN_LO);
v |= PCIE_PHY_RX_OVRD_IN_LO_RX_PLL_EN_OVRD;
v |= PCIE_PHY_RX_OVRD_IN_LO_RX_DATA_EN_OVRD;
imx6pcie_phy_write(sc, PCIE_PHY_RX_OVRD_IN_LO, v);
delay(3000);
v = imx6pcie_phy_read(sc, PCIE_PHY_RX_OVRD_IN_LO);
v &= ~PCIE_PHY_RX_OVRD_IN_LO_RX_PLL_EN_OVRD;
v &= ~PCIE_PHY_RX_OVRD_IN_LO_RX_DATA_EN_OVRD;
imx6pcie_phy_write(sc, PCIE_PHY_RX_OVRD_IN_LO, v);
}
if (linkup)
return 0;
}
aprint_error_dev(sc->sc_dev, "Link Up failed.\n");
return -1;
}
static int
imx6pcie_wait_for_changespeed(struct imx6pcie_softc *sc)
{
uint32_t v;
int retry;
#define CHANGESPEED_RETRY 200
for (retry = CHANGESPEED_RETRY; retry > 0; --retry) {
v = PCIE_READ(sc, PCIE_PL_G2CR);
if (!(v & PCIE_PL_G2CR_DIRECTED_SPEED_CHANGE))
return 0;
delay(100);
}
aprint_error_dev(sc->sc_dev, "Speed change timeout.\n");
return -1;
}
static void
imx6pcie_linkup(struct imx6pcie_softc *sc)
{
uint32_t v;
int ret;
imx6pcie_assert_core_reset(sc);
imx6pcie_init_phy(sc);
imx6pcie_deassert_core_reset(sc);
imx6pcie_setup(sc);
/* GEN1 Operation */
v = PCIE_READ(sc, PCIE_RC_LCR);
v &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS;
v |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
PCIE_WRITE(sc, PCIE_RC_LCR, v);
/* Link Up */
v = iomux_read(IOMUX_GPR12);
v |= IOMUX_GPR12_APP_LTSSM_ENABLE;
iomux_write(IOMUX_GPR12, v);
ret = imx6pcie_wait_for_link(sc);
if (ret)
goto error;
/* Change speed */
v = PCIE_READ(sc, PCIE_PL_G2CR);
v |= PCIE_PL_G2CR_DIRECTED_SPEED_CHANGE;
PCIE_WRITE(sc, PCIE_PL_G2CR, v);
ret = imx6pcie_wait_for_changespeed(sc);
if (ret)
goto error;
/* Allow Gen2 mode */
v = PCIE_READ(sc, PCIE_RC_LCR);
v &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS;
v |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
PCIE_WRITE(sc, PCIE_RC_LCR, v);
ret = imx6pcie_wait_for_link(sc);
if (ret)
goto error;
v = PCIE_READ(sc, PCIE_RC_LCSR);
aprint_normal_dev(sc->sc_dev, "LinkUp, Gen %d\n",
(int)__SHIFTOUT(v, PCIE_RC_LCSR_LINK_SPEED));
return;
error:
aprint_error_dev(sc->sc_dev,
"PCIE_PL_DEBUG0,1 = %08x, %08x\n",
PCIE_READ(sc, PCIE_PL_DEBUG0),
PCIE_READ(sc, PCIE_PL_DEBUG1));
return;
}
static int
imx6pcie_match(device_t parent, cfdata_t cf, void *aux)
{
struct axi_attach_args * const aa = aux;
/* i.MX6 SoloLite has no PCIe controller */
switch (IMX6_CHIPID_MAJOR(imx6_chip_id())) {
case CHIPID_MAJOR_IMX6SL:
return 0;
default:
break;
}
switch (aa->aa_addr) {
case (IMX6_PCIE_BASE):
return 1;
}
return 0;
}
static void
imx6pcie_attach(device_t parent, device_t self, void *aux)
{
struct imx6pcie_softc * const sc = device_private(self);
struct axi_attach_args * const aa = aux;
struct pcibus_attach_args pba;
sc->sc_dev = self;
sc->sc_iot = aa->aa_iot;
sc->sc_dmat = aa->aa_dmat;
if (aa->aa_size == AXICF_SIZE_DEFAULT)
aa->aa_size = IMX6_PCIE_SIZE;
aprint_naive("\n");
aprint_normal(": PCI Express Controller\n");
if (bus_space_map(sc->sc_iot, aa->aa_addr, aa->aa_size, 0,
&sc->sc_ioh)) {
aprint_error_dev(self, "Cannot map registers\n");
return;
}
if (bus_space_map(sc->sc_iot, IMX6_PCIE_ROOT_BASE,
IMX6_PCIE_ROOT_SIZE, 0, &sc->sc_root_ioh)) {
aprint_error_dev(self, "Cannot map registers\n");
return;
}
imx6_set_gpio(self, "imx6pcie-reset-gpio", &sc->sc_gpio_reset,
&sc->sc_gpio_reset_active, GPIO_DIR_OUT);
imx6_set_gpio(self, "imx6pcie-pwren-gpio", &sc->sc_gpio_pwren,
&sc->sc_gpio_pwren_active, GPIO_DIR_OUT);
imx6pcie_linkup(sc);
TAILQ_INIT(&sc->sc_intrs);
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
sc->sc_ih = intr_establish(aa->aa_irq, IPL_VM, IST_LEVEL,
imx6pcie_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "failed to establish interrupt on %d\n",
aa->aa_irq);
return;
}
aprint_normal_dev(self, "interrupting on %d\n", aa->aa_irq);
imx6pcie_init(&sc->sc_pc, sc);
#ifdef PCI_NETBSD_CONFIGURE
struct extent *ioext, *memext;
int error;
ioext = extent_create("pciio", IMX6_PCIE_IO_BASE,
IMX6_PCIE_IO_BASE + IMX6_PCIE_IO_SIZE - 1,
NULL, 0, EX_NOWAIT);
memext = extent_create("pcimem", IMX6_PCIE_MEM_BASE,
IMX6_PCIE_MEM_BASE + IMX6_PCIE_MEM_SIZE - 1,
NULL, 0, EX_NOWAIT);
error = pci_configure_bus(&sc->sc_pc, ioext, memext, NULL, 0,
arm_dcache_align);
extent_destroy(ioext);
extent_destroy(memext);
if (error) {
aprint_error_dev(self, "configuration failed (%d)\n",
error);
return;
}
#endif
memset(&pba, 0, sizeof(pba));
pba.pba_flags = PCI_FLAGS_MEM_OKAY |
PCI_FLAGS_IO_OKAY;
pba.pba_iot = sc->sc_iot;
pba.pba_memt = sc->sc_iot;
pba.pba_dmat = sc->sc_dmat;
pba.pba_pc = &sc->sc_pc;
pba.pba_bus = 0;
config_found_ia(self, "pcibus", &pba, pcibusprint);
}
static int
imx6pcie_intr(void *priv)
{
struct imx6pcie_softc *sc = priv;
struct imx6pcie_ih *pcie_ih;
int rv = 0;
uint32_t v;
for (int i = 0; i < 8; i++) {
v = PCIE_READ(sc, PCIE_PL_MSICIN_STATUS + i * 0xC);
int bit;
while ((bit = ffs(v) - 1) >= 0) {
PCIE_WRITE(sc, PCIE_PL_MSICIN_STATUS + i * 0xC,
__BIT(bit));
v &= ~__BIT(bit);
}
}
mutex_enter(&sc->sc_lock);
const u_int lastgen = sc->sc_intrgen;
TAILQ_FOREACH(pcie_ih, &sc->sc_intrs, ih_entry) {
int (*callback)(void *) = pcie_ih->ih_handler;
void *arg = pcie_ih->ih_arg;
mutex_exit(&sc->sc_lock);
rv += callback(arg);
mutex_enter(&sc->sc_lock);
if (lastgen != sc->sc_intrgen)
break;
}
mutex_exit(&sc->sc_lock);
return rv;
}
static void
imx6pcie_setup(struct imx6pcie_softc * const sc)
{
uint32_t v;
/* Setup RC */
/* BARs */
PCIE_WRITE(sc, PCI_BAR0, 0x00000004);
PCIE_WRITE(sc, PCI_BAR1, 0x00000000);
/* Interurupt pins */
v = PCIE_READ(sc, PCI_INTERRUPT_REG);
v &= ~(PCI_INTERRUPT_PIN_MASK << PCI_INTERRUPT_PIN_SHIFT);
v |= PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT;
PCIE_WRITE(sc, PCI_INTERRUPT_REG, v);
/* Bus number */
v = PCIE_READ(sc, PCI_BRIDGE_BUS_REG);
v &= ~(PCI_BRIDGE_BUS_EACH_MASK << PCI_BRIDGE_BUS_SUBORDINATE_SHIFT |
PCI_BRIDGE_BUS_EACH_MASK << PCI_BRIDGE_BUS_SECONDARY_SHIFT |
PCI_BRIDGE_BUS_EACH_MASK << PCI_BRIDGE_BUS_PRIMARY_SHIFT);
v |= PCI_BRIDGE_BUS_SUBORDINATE(1);
v |= PCI_BRIDGE_BUS_SECONDARY(1);
v |= PCI_BRIDGE_BUS_PRIMARY(0);
PCIE_WRITE(sc, PCI_BRIDGE_BUS_REG, v);
/* Command register */
v = PCIE_READ(sc, PCI_COMMAND_STATUS_REG);
v |= PCI_COMMAND_IO_ENABLE |
PCI_COMMAND_MEM_ENABLE |
PCI_COMMAND_MASTER_ENABLE;
PCIE_WRITE(sc, PCI_COMMAND_STATUS_REG, v);
PCIE_WRITE(sc, PCI_CLASS_REG,
PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_PCI, PCI_INTERFACE_BRIDGE_PCI_PCI));
PCIE_WRITE(sc, PCIE_PL_IATUVR, 0);
PCIE_WRITE(sc, PCIE_PL_IATURLBA, IMX6_PCIE_ROOT_BASE);
PCIE_WRITE(sc, PCIE_PL_IATURUBA, 0);
PCIE_WRITE(sc, PCIE_PL_IATURLA, IMX6_PCIE_ROOT_BASE + IMX6_PCIE_ROOT_SIZE);
PCIE_WRITE(sc, PCIE_PL_IATURLTA, 0);
PCIE_WRITE(sc, PCIE_PL_IATURUTA, 0);
PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG0);
PCIE_WRITE(sc, PCIE_PL_IATURC2, PCIE_PL_IATURC2_REGION_ENABLE);
}
void
imx6pcie_init(pci_chipset_tag_t pc, void *priv)
{
pc->pc_conf_v = priv;
pc->pc_attach_hook = imx6pcie_attach_hook;
pc->pc_bus_maxdevs = imx6pcie_bus_maxdevs;
pc->pc_make_tag = imx6pcie_make_tag;
pc->pc_decompose_tag = imx6pcie_decompose_tag;
pc->pc_conf_read = imx6pcie_conf_read;
pc->pc_conf_write = imx6pcie_conf_write;
#ifdef __HAVE_PCI_CONF_HOOK
pc->pc_conf_hook = imx6pcie_conf_hook;
#endif
pc->pc_conf_interrupt = imx6pcie_conf_interrupt;
pc->pc_intr_v = priv;
pc->pc_intr_map = imx6pcie_intr_map;
pc->pc_intr_string = imx6pcie_intr_string;
pc->pc_intr_evcnt = imx6pcie_intr_evcnt;
pc->pc_intr_establish = imx6pcie_intr_establish;
pc->pc_intr_disestablish = imx6pcie_intr_disestablish;
}
static void
imx6pcie_attach_hook(device_t parent, device_t self,
struct pcibus_attach_args *pba)
{
/* nothing to do */
}
static int
imx6pcie_bus_maxdevs(void *v, int busno)
{
return 32;
}
static pcitag_t
imx6pcie_make_tag(void *v, int b, int d, int f)
{
return (b << 16) | (d << 11) | (f << 8);
}
static void
imx6pcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
{
if (bp)
*bp = (tag >> 16) & 0xff;
if (dp)
*dp = (tag >> 11) & 0x1f;
if (fp)
*fp = (tag >> 8) & 0x7;
}
/*
* work around.
* If there is no PCIe devices, DABT will be generated by read/write access to
* config area, so replace original DABT handler with sinple jump-back one.
*/
extern u_int data_abort_handler_address;
static bool data_abort_flag;
static void
imx6pcie_data_abort_handler(trapframe_t *tf)
{
data_abort_flag = true;
tf->tf_pc += 0x4;
return;
}
static pcireg_t
imx6pcie_conf_read(void *v, pcitag_t tag, int offset)
{
struct imx6pcie_softc *sc = v;
bus_space_handle_t bsh;
int b, d, f;
pcireg_t ret = -1;
int s;
imx6pcie_decompose_tag(v, tag, &b, &d, &f);
if ((unsigned int)offset >= PCI_EXTCONF_SIZE)
return ret;
if (b <= 1 && d > 0)
return ret;
PCIE_WRITE(sc, PCIE_PL_IATUVR, 0);
if (b < 2)
PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG0);
else
PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG1);
if (b == 0) {
bsh = sc->sc_ioh;
} else {
PCIE_WRITE(sc, PCIE_PL_IATURLTA, tag << 8);
bsh = sc->sc_root_ioh;
}
PCIE_READ(sc, PCIE_PL_IATURC2);
PCIE_CONF_LOCK(s);
u_int saved = data_abort_handler_address;
data_abort_handler_address = (u_int)imx6pcie_data_abort_handler;
data_abort_flag = false;
ret = bus_space_read_4(sc->sc_iot, bsh, offset & ~0x3);
data_abort_handler_address = saved;
PCIE_CONF_UNLOCK(s);
if (data_abort_flag)
ret = -1;
return ret;
}
static void
imx6pcie_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val)
{
struct imx6pcie_softc *sc = v;
bus_space_handle_t bsh;
int b, d, f;
int s;
imx6pcie_decompose_tag(v, tag, &b, &d, &f);
if ((unsigned int)offset >= PCI_EXTCONF_SIZE)
return;
if (b <= 1 && d > 0)
return;
PCIE_WRITE(sc, PCIE_PL_IATUVR, 0);
if (b < 2)
PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG0);
else
PCIE_WRITE(sc, PCIE_PL_IATURC1, PCIE_PL_IATURC1_TYPE_CFG1);
if (b == 0) {
bsh = sc->sc_ioh;
} else {
PCIE_WRITE(sc, PCIE_PL_IATURLTA, tag << 8);
bsh = sc->sc_root_ioh;
}
PCIE_READ(sc, PCIE_PL_IATURC2);
PCIE_CONF_LOCK(s);
u_int saved = data_abort_handler_address;
data_abort_handler_address = (u_int)imx6pcie_data_abort_handler;
bus_space_write_4(sc->sc_iot, bsh, offset & ~0x3, val);
data_abort_handler_address = saved;
PCIE_CONF_UNLOCK(s);
return;
}
#ifdef __HAVE_PCI_CONF_HOOK
static int
imx6pcie_conf_hook(void *v, int b, int d, int f, pcireg_t id)
{
return PCI_CONF_DEFAULT;
}
#endif
static void
imx6pcie_conf_interrupt(void *v, int bus, int dev, int ipin, int swiz,
int *ilinep)
{
/* nothing to do */
}
static int
imx6pcie_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ih)
{
if (pa->pa_intrpin == 0)
return EINVAL;
*ih = pa->pa_intrpin;
return 0;
}
static const char *
imx6pcie_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
{
if (ih == PCI_INTERRUPT_PIN_NONE)
return NULL;
strlcpy(buf, "pci", len);
return buf;
}
const struct evcnt *
imx6pcie_intr_evcnt(void *v, pci_intr_handle_t ih)
{
return NULL;
}
static void *
imx6pcie_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
int (*callback)(void *), void *arg)
{
struct imx6pcie_softc *sc = v;
struct imx6pcie_ih *pcie_ih;
if (ih == 0)
return NULL;
pcie_ih = kmem_alloc(sizeof(*pcie_ih), KM_SLEEP);
pcie_ih->ih_handler = callback;
pcie_ih->ih_arg = arg;
pcie_ih->ih_ipl = ipl;
mutex_enter(&sc->sc_lock);
TAILQ_INSERT_TAIL(&sc->sc_intrs, pcie_ih, ih_entry);
sc->sc_intrgen++;
mutex_exit(&sc->sc_lock);
return pcie_ih;
}
static void
imx6pcie_intr_disestablish(void *v, void *vih)
{
struct imx6pcie_softc *sc = v;
struct imx6pcie_ih *pcie_ih = vih;
mutex_enter(&sc->sc_lock);
TAILQ_REMOVE(&sc->sc_intrs, pcie_ih, ih_entry);
sc->sc_intrgen++;
mutex_exit(&sc->sc_lock);
kmem_free(pcie_ih, sizeof(*pcie_ih));
}

View File

@ -0,0 +1,295 @@
/* $NetBSD: imx6_pciereg.h,v 1.1 2016/11/24 12:06:43 hkenken Exp $ */
/*
* Copyright (c) 2015 Ryo Shimizu <ryo@nerv.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ARM_IMX_IMX6_PCIEREG_H_
#define _ARM_IMX_IMX6_PCIEREG_H_
/* PCIe EP Mode Registers */
#define PCIE_EP_DEVICEID 0x00000000
#define PCIE_EP_COMMAND 0x00000004
#define PCIE_EP_BIST 0x0000000c
#define PCIE_EP_BAR0 0x00000010
#define PCIE_EP_MASK0 0x00000010
#define PCIE_EP_MASK1 0x00000014
#define PCIE_EP_MASK2 0x00000018
#define PCIE_EP_MASK3 0x0000001c
#define PCIE_EP_CISP 0x00000028
#define PCIE_EP_SSID 0x0000002c
#define PCIE_EP_EROMBAR 0x00000030
#define PCIE_EP_EROMMASK 0x00000030
#define PCIE_EP_CAPPR 0x00000034
#define PCIE_EP_ILR 0x0000003c
#define PCIE_EP_AER 0x00000100
#define PCIE_EP_UESR 0x00000104
#define PCIE_EP_UEMR 0x00000108
#define PCIE_EP_UESEVR 0x0000010c
#define PCIE_EP_CESR 0x00000110
#define PCIE_EP_CEMR 0x00000114
#define PCIE_EP_ACCR 0x00000118
#define PCIE_EP_HLR 0x0000011c
#define PCIE_EP_VCECHR 0x00000140
#define PCIE_EP_PVCCR1 0x00000144
#define PCIE_EP_PVCCR2 0x00000148
#define PCIE_EP_PVCCSR 0x0000014c
#define PCIE_EP_VCRCR 0x00000150
#define PCIE_EP_VCRCONR 0x00000154
#define PCIE_EP_VCRSR 0x00000158
/* PCIe RC Mode Registers */
#define PCIE_RC_DEVICEID 0x00000000
#define PCIE_RC_COMMAND 0x00000004
#define PCIE_RC_REVID 0x00000008
#define PCIE_RC_BIST 0x0000000c
#define PCIE_RC_BAR0 0x00000010
#define PCIE_RC_BAR1 0x00000014
#define PCIE_RC_BNR 0x00000018
#define PCIE_RC_IOBLSSR 0x0000001c
#define PCIE_RC_MEM_BLR 0x00000020
#define PCIE_RC_PREF_MEM_BLR 0x00000024
#define PCIE_RC_PREF_BASE_U32 0x00000028
#define PCIE_RC_PREF_LIM_U32 0x0000002c
#define PCIE_RC_IO_BASE_LIM_U16 0x00000030
#define PCIE_RC_CAPPR 0x00000034
#define PCIE_RC_EROMBAR 0x00000038
#define PCIE_RC_EROMMASK 0x00000038
#define PCIE_RC_PMCR 0x00000040
#define PCIE_RC_PMCSR 0x00000044
#define PCIE_RC_CIDR 0x00000070
#define PCIE_RC_DCR 0x00000074
#define PCIE_RC_DCONR 0x00000078
#define PCIE_RC_LCR 0x0000007c
#define PCIE_RC_LCR_MAX_LINK_SPEEDS __BITS(3, 0)
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 __SHIFTIN(0x1, PCIE_RC_LCR_MAX_LINK_SPEEDS)
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 __SHIFTIN(0x2, PCIE_RC_LCR_MAX_LINK_SPEEDS)
#define PCIE_RC_LCSR 0x00000080
#define PCIE_RC_LCSR_LINK_SPEED __BITS(19, 16)
#define PCIE_RC_SCR 0x00000084
#define PCIE_RC_SCSR 0x00000088
#define PCIE_RC_RCCR 0x0000008c
#define PCIE_RC_RSR 0x00000090
#define PCIE_RC_DCR2 0x00000094
#define PCIE_RC_DCSR2 0x00000098
#define PCIE_RC_LCR2 0x0000009c
#define PCIE_RC_LCSR2 0x000000a0
#define PCIE_RC_AER 0x00000100
#define PCIE_RC_UESR 0x00000104
#define PCIE_RC_UEMR 0x00000108
#define PCIE_RC_UESEVR 0x0000010c
#define PCIE_RC_CESR 0x00000110
#define PCIE_RC_CEMR 0x00000114
#define PCIE_RC_ACCR 0x00000118
#define PCIE_RC_HLR 0x0000011c
#define PCIE_RC_RECR 0x0000012c
#define PCIE_RC_RESR 0x00000130
#define PCIE_RC_ESIR 0x00000134
#define PCIE_RC_VCECHR 0x00000140
#define PCIE_RC_PVCCR1 0x00000144
#define PCIE_RC_PVCCR2 0x00000148
#define PCIE_RC_PVCCSR 0x0000014c
#define PCIE_RC_VCRCR 0x00000150
#define PCIE_RC_VCRCONR 0x00000154
#define PCIE_RC_VCRSR 0x00000158
/* PCIe Port Logic Registers */
#define PCIE_PL_ALTRTR 0x00000700
#define PCIE_PL_VSDR 0x00000704
#define PCIE_PL_PFLR 0x00000708
#define PCIE_PL_PFLR_LOW_POWER_ENTRANCE_COUNT __BITS(31, 24)
#define PCIE_PL_PFLR_LINK_STATE __BITS(21, 16)
#define PCIE_PL_PFLR_FORCE_LINK __BIT(15)
#define PCIE_PL_PFLR_LINK_NUMBER __BITS(7, 0)
#define PCIE_PL_AFLACR 0x0000070c
#define PCIE_PL_PLCR 0x00000710
#define PCIE_PL_LSR 0x00000714
#define PCIE_PL_SNR 0x00000718
#define PCIE_PL_STRFM1 0x0000071c
#define PCIE_PL_STRFM2 0x00000720
#define PCIE_PL_AMODNPSR 0x00000724
#define PCIE_PL_DEBUG0 0x00000728
#define PCIE_PL_DEBUG0_XMLH_LTSSM_STATE __BITS(0, 5)
#define PCIE_PL_DEBUG1 0x0000072c
#define PCIE_PL_DEBUG1_XMLH_LINK_UP __BIT(4)
#define PCIE_PL_DEBUG1_XMLH_LINK_IN_TRAINING __BIT(29)
#define PCIE_PL_TPFCSR 0x00000730
#define PCIE_PL_TNFCSR 0x00000734
#define PCIE_PL_TCFCSR 0x00000738
#define PCIE_PL_QSR 0x0000073c
#define PCIE_PL_VCTAR1 0x00000740
#define PCIE_PL_VCTAR2 0x00000744
#define PCIE_PL_VC0PRQC 0x00000748
#define PCIE_PL_VC0NRQC 0x0000074c
#define PCIE_PL_VC0CRQC 0x00000750
#define PCIE_PL_VCNPRQC 0x00000754
#define PCIE_PL_VCNNRQC 0x00000758
#define PCIE_PL_VCNCRQC 0x0000075c
#define PCIE_PL_VC0PBD 0x000007a8
#define PCIE_PL_VC0NPBD 0x000007ac
#define PCIE_PL_VC0CBD 0x000007b0
#define PCIE_PL_VC1PBD 0x000007b4
#define PCIE_PL_VC1NPBD 0x000007b8
#define PCIE_PL_VC1CBD 0x000007bc
#define PCIE_PL_G2CR 0x0000080c
#define PCIE_PL_G2CR_DIRECTED_SPEED_CHANGE __BIT(17)
#define PCIE_PL_PHY_STATUS 0x00000810
#define PCIE_PL_PHY_STATUS_ACK __BIT(16)
#define PCIE_PL_PHY_STATUS_DATA __BITS(0, 15)
#define PCIE_PL_PHY_CTRL 0x00000814
#define PCIE_PL_PHY_CTRL_RD __BIT(19)
#define PCIE_PL_PHY_CTRL_WR __BIT(18)
#define PCIE_PL_PHY_CTRL_CAP_DAT __BIT(17)
#define PCIE_PL_PHY_CTRL_CAP_ADR __BIT(16)
#define PCIE_PL_PHY_CTRL_DATA __BITS(0, 15)
#define PCIE_PL_MRCCR0 0x00000818
#define PCIE_PL_MRCCR1 0x0000081c
#define PCIE_PL_MSICA 0x00000820
#define PCIE_PL_MSICUA 0x00000824
#define PCIE_PL_MSICIN_ENB 0x00000828
#define PCIE_PL_MSICIN_MASK 0x0000082c
#define PCIE_PL_MSICIN_STATUS 0x00000830
#define PCIE_PL_MSICGPIO 0x00000888
// ATU_R_BaseAddress 0x900
#define PCIE_PL_IATUVR 0x00000900
// ATU_VIEWPORT_R (ATU_R_BaseAddress + 0x0)
#define PCIE_PL_IATURC1 0x00000904
// ATU_REGION_CTRL1_R (ATU_R_BaseAddress + 0x4)
#define PCIE_PL_IATURC1_FUNC __BITS(22, 20)
#define PCIE_PL_IATURC1_AT __BITS(17, 16)
#define PCIE_PL_IATURC1_ATTR __BITS(10, 9)
#define PCIE_PL_IATURC1_TD __BIT(8)
#define PCIE_PL_IATURC1_TC __BITS(7, 5)
#define PCIE_PL_IATURC1_TYPE __BITS(4, 0)
#define PCIE_PL_IATURC1_TYPE_IO __SHIFTIN(0, PCIE_PL_IATURC1_TYPE)
#define PCIE_PL_IATURC1_TYPE_MEM __SHIFTIN(2, PCIE_PL_IATURC1_TYPE)
#define PCIE_PL_IATURC1_TYPE_CFG0 __SHIFTIN(4, PCIE_PL_IATURC1_TYPE)
#define PCIE_PL_IATURC1_TYPE_CFG1 __SHIFTIN(5, PCIE_PL_IATURC1_TYPE)
#define PCIE_PL_IATURC2 0x00000908
// ATU_REGION_CTRL2_R (ATU_R_BaseAddress + 0x8)
#define PCIE_PL_IATURC2_REGION_ENABLE __BIT(31)
#define PCIE_PL_IATURLBA 0x0000090c
// ATU_REGION_LOWBASE_R (ATU_R_BaseAddress + 0xC)
#define PCIE_PL_IATURUBA 0x00000910
// ATU_REGION_UPBASE_R (ATU_R_BaseAddress + 0x10)
#define PCIE_PL_IATURLA 0x00000914
// ATU_REGION_LIMIT_ADDR_R (ATU_R_BaseAddress + 0x14)
#define PCIE_PL_IATURLTA 0x00000918
// ATU_REGION_LOW_TRGT_ADDR_R (ATU_R_BaseAddress + 0x18)
#define PCIE_PL_IATURUTA 0x0000091c
// ATU_REGION_UP_TRGT_ADDR_R (ATU_R_BaseAddress + 0x1C)
/* PCIe PHY registers */
#define PCIE_PHY_IDCODE_LO 0x0000
#define PCIE_PHY_IDCODE_HI 0x0001
#define PCIE_PHY_DEBUG 0x0002
#define PCIE_PHY_RTUNE_DEBUG 0x0003
#define PCIE_PHY_RTUNE_STAT 0x0004
#define PCIE_PHY_SS_PHASE 0x0005
#define PCIE_PHY_SS_FREQ 0x0006
#define PCIE_PHY_ATEOVRD 0x0010
#define PCIE_PHY_MPLL_OVRD_IN_LO 0x0011
#define PCIE_PHY_MPLL_OVRD_IN_HI 0x0011
#define PCIE_PHY_SSC_OVRD_IN 0x0013
#define PCIE_PHY_BS_OVRD_IN 0x0014
#define PCIE_PHY_LEVEL_OVRD_IN 0x0015
#define PCIE_PHY_SUP_OVRD_OUT 0x0016
#define PCIE_PHY_MPLL_ASIC_IN 0x0017
#define PCIE_PHY_BS_ASIC_IN 0x0018
#define PCIE_PHY_LEVEL_ASIC_IN 0x0019
#define PCIE_PHY_SSC_ASIC_IN 0x001a
#define PCIE_PHY_SUP_ASIC_OUT 0x001b
#define PCIE_PHY_ATEOVRD_STATUS 0x001c
#define PCIE_PHY_SCOPE_ENABLES 0x0020
#define PCIE_PHY_SCOPE_SAMPLES 0x0021
#define PCIE_PHY_SCOPE_COUNT 0x0022
#define PCIE_PHY_SCOPE_CTL 0x0023
#define PCIE_PHY_SCOPE_MASK_000 0x0024
#define PCIE_PHY_SCOPE_MASK_001 0x0025
#define PCIE_PHY_SCOPE_MASK_010 0x0026
#define PCIE_PHY_SCOPE_MASK_011 0x0027
#define PCIE_PHY_SCOPE_MASK_100 0x0028
#define PCIE_PHY_SCOPE_MASK_101 0x0029
#define PCIE_PHY_SCOPE_MASK_110 0x002a
#define PCIE_PHY_SCOPE_MASK_111 0x002b
#define PCIE_PHY_MPLL_LOOP_CTL 0x0030
#define PCIE_PHY_MPLL_ATB_MEAS2 0x0032
#define PCIE_PHY_MPLL_OVR 0x0033
#define PCIE_PHY_RTUNE_RTUNE_CTRL 0x0034
#define PCIE_PHY_TX_OVRD_IN_LO 0x1000
#define PCIE_PHY_TX_OVRD_IN_HI 0x1001
#define PCIE_PHY_TX_OVRD_DRV_LO 0x1003
#define PCIE_PHY_TX_OVRD_OUT 0x1004
#define PCIE_PHY_RX_OVRD_IN_LO 0x1005
#define PCIE_PHY_RX_OVRD_IN_LO_RX_PLL_EN_OVRD __BIT(3)
#define PCIE_PHY_RX_OVRD_IN_LO_RX_DATA_EN_OVRD __BIT(5)
#define PCIE_PHY_RX_OVRD_IN_HI 0x1006
#define PCIE_PHY_RX_OVRD_OUT 0x1007
#define PCIE_PHY_TX_ASIC_IN 0x1008
#define PCIE_PHY_TX_ASIC_DRV_LO 0x1009
#define PCIE_PHY_TX_ASIC_DRV_HI 0x100a
#define PCIE_PHY_TX_ASIC_OUT 0x100b
#define PCIE_PHY_RX_ASIC_IN 0x100c
#define PCIE_PHY_RX_ASIC_OUT 0x100d
#define PCIE_PHY_RX_ASIC_OUT_LOS __BIT(2)
#define PCIE_PHY_RX_ASIC_OUT_PLL_STATE __BIT(1)
#define PCIE_PHY_RX_ASIC_OUT_VALID __BIT(0)
#define PCIE_PHY_TX_VMD_FSM_TX_VCM_0 0x1011
#define PCIE_PHY_TX_VMD_FSM_TX_VCM_1 0x1012
#define PCIE_PHY_TX_VMD_FSM_TX_VCM_DEBUG_IN 0x1013
#define PCIE_PHY_TX_VMD_FSM_TX_VCM_DEBUG_OUT 0x1014
#define PCIE_PHY_TX_LBERT_CTL 0x1015
#define PCIE_PHY_RX_LBERT_CTL 0x1016
#define PCIE_PHY_RX_LBERT_ERR 0x1017
#define PCIE_PHY_RX_SCOPE_CTL 0x1018
#define PCIE_PHY_RX_SCOPE_PHASE 0x1019
#define PCIE_PHY_RX_DPLL_FREQ 0x101a
#define PCIE_PHY_RX_CDR_CTL 0x101b
#define PCIE_PHY_RX_CDR_CDR_FSM_DEBUG 0x101c
#define PCIE_PHY_RX_CDR_LOCK_VEC_OVRD 0x101d
#define PCIE_PHY_RX_CDR_LOCK_VEC 0x101e
#define PCIE_PHY_RX_CDR_ADAP_FSM 0x101f
#define PCIE_PHY_RX_ATB0 0x1020
#define PCIE_PHY_RX_ATB1 0x1021
#define PCIE_PHY_RX_ENPWR0 0x1022
#define PCIE_PHY_RX_PMIX_PHASE 0x1023
#define PCIE_PHY_RX_ENPWR1 0x1024
#define PCIE_PHY_RX_ENPWR2 0x1025
#define PCIE_PHY_RX_SCOPE 0x1026
#define PCIE_PHY_TX_TXDRV_CNTRL 0x102b
#define PCIE_PHY_TX_POWER_CTL 0x102c
#define PCIE_PHY_TX_ALT_BLOCK 0x102d
#define PCIE_PHY_TX_ALT_AND_LOOPBACK 0x102e
#define PCIE_PHY_TX_TX_ATB_REG 0x102f
#endif /* _ARM_IMX_IMX6_PCIEREG_H_ */

View File

@ -0,0 +1,158 @@
#
# $NetBSD: HUMMINGBOARD,v 1.1 2016/11/24 12:06:44 hkenken Exp $
#
# Hummingboard -- Freescale i.MX6 Eval Board Kernel
#
include "arch/evbarm/conf/std.nitrogen6"
include "arch/evbarm/conf/GENERIC.common"
# Board Type
options EVBARM_BOARDTYPE=hummingboard
#options EVBARM_BOARDTYPE=hummingboard_edge
options HUMMINGBOARD
# CPU options
options CPU_CORTEX
options CPU_CORTEXA9
options IMX6
options MULTIPROCESSOR
# Console options. also need IMXUARTCONSOLE
options CONSDEVNAME="\"imxuart\"",CONADDR=0x02020000
options CONSPEED=115200 # Console speed
options DIAGNOSTIC # internal consistency checks
options DEBUG
#options KGDB
makeoptions DEBUG="-g" # compile full symbol table
makeoptions COPY_SYMTAB=1
# Valid options for BOOT_ARGS:
# single Boot to single user only
# kdb Give control to kernel debugger
# ask Ask for file name to reboot from
# pmapdebug=<n> If PMAP_DEBUG, set pmap_debug_level to <n>
# memorydisk=<n> Set memorydisk size to <n> KB
# quiet Show aprint_naive output
# verbose Show aprint_normal and aprint_verbose output
options BOOT_ARGS="\"verbose\""
# Kernel root file system and dump configuration.
#config netbsd root on ? type ?
config netbsd-wd0 root on wd0 type ffs
#
# Device configuration
#
mainbus0 at root
cpu* at mainbus?
# The MPCore interrupt controller and global timer
armperiph0 at mainbus? # A9 On-Chip Peripherals
armgic0 at armperiph? # ARM Generic Interrupt Controller
arml2cc0 at armperiph? flags 0 # ARM PL310 L2CC
a9tmr0 at armperiph? # A9 Global Timer
#a9wdt0 at armperiph? flags 0 # A9 Watchdog Timer
axi0 at mainbus?
# GPIO
imxgpio0 at axi? addr 0x0209c000 irqbase 256 irq 98
imxgpio1 at axi? addr 0x020a0000 irqbase 288 irq 100
imxgpio2 at axi? addr 0x020a4000 irqbase 320 irq 102
imxgpio3 at axi? addr 0x020a8000 irqbase 352 irq 104
imxgpio4 at axi? addr 0x020ac000 irqbase 384 irq 106
imxgpio5 at axi? addr 0x020b0000 irqbase 416 irq 108
imxgpio6 at axi? addr 0x020b4000 irqbase 448 irq 110
gpio* at imxgpio?
options IMX_GPIO_INTR_SPLIT
# Clock Control
imxccm0 at axi? addr 0x020c4000
# On-Chip OTP Controller
imxocotp0 at axi? addr 0x021bc000
# IOMUX
imxiomux0 at axi? addr 0x020e0000
# WatchDog
imxwdog0 at axi? addr 0x020bc000 irq 112 flags 0
#imxwdog1 at axi? addr 0x020c0000 irq 113 flags 0
# Serial
imxuart0 at axi? addr 0x02020000 irq 58 # UART1
#imxuart1 at axi? addr 0x021e8000 irq 59 # UART2
#imxuart2 at axi? addr 0x021ec000 irq 60 # UART3
#imxuart3 at axi? addr 0x021f0000 irq 61 # UART4
#imxuart4 at axi? addr 0x021f4000 irq 62 # UART5
options IMXUARTCONSOLE
# I2C
imxi2c0 at axi? addr 0x021A0000 irq 68
imxi2c1 at axi? addr 0x021A4000 irq 69
imxi2c2 at axi? addr 0x021A8000 irq 70
# IIC
iic* at imxi2c?
# SATA
ahcisata* at axi? addr 0x02200000 irq 71
atabus* at ahcisata? channel ?
wd* at atabus? drive ? flags 0x0000
# ATAPI bus support
atapibus* at atapi?
# ATAPI devices
# flags have the same meaning as for IDE drives.
cd* at atapibus? drive ? flags 0x0000 # ATAPI CD-ROM drives
sd* at atapibus? drive ? flags 0x0000 # ATAPI disk drives
st* at atapibus? drive ? flags 0x0000 # ATAPI tape drives
uk* at atapibus? drive ? flags 0x0000 # ATAPI unknown
# Network Interfaces
enet0 at axi? addr 0x02188000 irq 150 # iMX6 SoC Ethernet
# MII/PHY support
atphy* at mii? phy ? # Attansic/Atheros PHYs
ukphy* at mii? phy ? # generic unknown PHYs
# SD/MMC
#sdhc0 at axi? addr 0x02190000 irq 54 # uSDHC1
sdhc1 at axi? addr 0x02194000 irq 55 # uSDHC2
#sdhc2 at axi? addr 0x02198000 irq 56 # uSDHC3
#sdhc3 at axi? addr 0x0219c000 irq 57 # uSDHC4
sdmmc* at sdhc?
ld* at sdmmc? # MMC/SD card
#options SDHC_DEBUG
#options SDMMC_DEBUG
# USB
imxusbc0 at axi? addr 0x02184000
ehci0 at imxusbc0 unit 0 irq 75 # OTG
ehci1 at imxusbc0 unit 1 irq 72 # Host1
#ehci2 at imxusbc0 unit 2 irq 73 # Host2
#ehci3 at imxusbc0 unit 3 irq 74 # Host3
usb* at ehci?
# USB device drivers
include "dev/usb/usbdevices.config"
midi* at midibus?
# PCIe
imxpcie0 at axi? addr 0x01ffc000 irq 155 # PCIe
#options PCIVERBOSE
#options PCI_CONFIG_DUMP
pci* at imxpcie0
ppb* at pci? dev ? function ?
pci* at ppb?
iwn* at pci? dev ? function ? # Intel PRO/Wireless 4965AGN
iwm* at pci? dev ? function ? # Intel Centrino 7260

View File

@ -1,4 +1,4 @@
# $NetBSD: std.nitrogen6,v 1.3 2015/07/30 08:09:36 ryo Exp $
# $NetBSD: std.nitrogen6,v 1.4 2016/11/24 12:06:44 hkenken Exp $
#
# standard NetBSD/evbarm options for Nitrogen6X
@ -14,6 +14,7 @@ options ARM_HAS_VBAR
options __HAVE_CPU_COUNTER
options __HAVE_FAST_SOFTINTS # should be in types.h
options TPIDRPRW_IS_CURCPU
options PCI_NETBSD_CONFIGURE
makeoptions CPUFLAGS="-mcpu=cortex-a9"

View File

@ -1,4 +1,4 @@
/* $NetBSD: nitrogen6_iomux.c,v 1.2 2015/12/31 11:53:19 ryo Exp $ */
/* $NetBSD: nitrogen6_iomux.c,v 1.3 2016/11/24 12:06:44 hkenken Exp $ */
/*
* Copyright (c) 2015 Ryo Shimizu <ryo@nerv.org>
@ -26,7 +26,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nitrogen6_iomux.c,v 1.2 2015/12/31 11:53:19 ryo Exp $");
__KERNEL_RCSID(0, "$NetBSD: nitrogen6_iomux.c,v 1.3 2016/11/24 12:06:44 hkenken Exp $");
#include "opt_evbarm_boardtype.h"
#include <sys/bus.h>
@ -52,10 +52,11 @@ static void nitrogen6_mux_config(const struct iomux_conf *);
static void nitrogen6_gpio_config(const struct gpio_conf *);
#define nitrogen6x 1
#define nitrogen6max 2
#define cubox_i 3
#define hummingboard 4
#define nitrogen6x 1
#define nitrogen6max 2
#define cubox_i 3
#define hummingboard 4
#define hummingboard_edge 5
#define PAD_UART \
(PAD_CTL_HYS | PAD_CTL_PUS_100K_PU | PAD_CTL_PULL | \
@ -111,6 +112,10 @@ static void nitrogen6_gpio_config(const struct gpio_conf *);
PAD_CTL_SPEED_100MHZ | PAD_CTL_DSE_40OHM | PAD_CTL_SRE_SLOW)
#define PAD_OUTPUT_40OHM (PAD_CTL_SPEED_100MHZ | PAD_CTL_DSE_40OHM)
#define PAD_PCIE_GPIO \
(PAD_CTL_HYS | PAD_CTL_PUS_22K_PU | PAD_CTL_PULL | \
PAD_CTL_SPEED_50MHZ | PAD_CTL_DSE_40OHM | PAD_CTL_SRE_FAST)
/* iMX6 SoloLite */
static const struct iomux_conf iomux_data_6sl[] = {
@ -176,7 +181,8 @@ static const struct iomux_conf iomux_data_6sdl[] = {
.pad = 0
},
#endif
#if (EVBARM_BOARDTYPE == hummingboard)
#if (EVBARM_BOARDTYPE == hummingboard) || \
(EVBARM_BOARDTYPE == hummingboard_edge)
{
.pin = MUX_PIN(IMX6SDL, GPIO05),
.mux = IOMUX_CONFIG_ALT3, /* CCM_CLKO1 */
@ -184,7 +190,8 @@ static const struct iomux_conf iomux_data_6sdl[] = {
},
#endif
#if (EVBARM_BOARDTYPE == cubox_i) || \
(EVBARM_BOARDTYPE == hummingboard)
(EVBARM_BOARDTYPE == hummingboard) || \
(EVBARM_BOARDTYPE == hummingboard_edge)
{
.pin = MUX_PIN(IMX6SDL, EIM_DATA22),
.mux = IOMUX_CONFIG_ALT5, /* GPIO3_IO22 */
@ -407,15 +414,33 @@ static const struct iomux_conf iomux_data_6dq[] = {
.pad = 0
},
#endif
#if (EVBARM_BOARDTYPE == hummingboard)
#if (EVBARM_BOARDTYPE == hummingboard) || \
(EVBARM_BOARDTYPE == hummingboard_edge)
{
.pin = MUX_PIN(IMX6DQ, GPIO05),
.mux = IOMUX_CONFIG_ALT3, /* CCM_CLKO1 */
.pad = PAD_USB
},
#endif
#if (EVBARM_BOARDTYPE == hummingboard)
/* PCIe */
{
.pin = MUX_PIN(IMX6DQ, EIM_AD04),
.mux = IOMUX_CONFIG_ALT5,
.pad = PAD_PCIE_GPIO
},
#endif
#if (EVBARM_BOARDTYPE == hummingboard_edge)
/* PCIe */
{
.pin = MUX_PIN(IMX6DQ, SD4_DATA3),
.mux = IOMUX_CONFIG_ALT5,
.pad = PAD_PCIE_GPIO
},
#endif
#if (EVBARM_BOARDTYPE == cubox_i) || \
(EVBARM_BOARDTYPE == hummingboard)
(EVBARM_BOARDTYPE == hummingboard) || \
(EVBARM_BOARDTYPE == hummingboard_edge)
{
.pin = MUX_PIN(IMX6DQ, EIM_DATA22),
.mux = IOMUX_CONFIG_ALT5, /* GPIO3_IO22 */
@ -456,6 +481,13 @@ static const struct gpio_conf gpio_data[] = {
{ 3, 22, GPIO_DIR_OUT, 1 }, /* USB OTG */
{ 1, 0, GPIO_DIR_OUT, 1 }, /* USB H1 */
{ 1, 4, GPIO_DIR_IN, 0 }, /* USDHC2 */
{ 3, 4, GPIO_DIR_OUT, 0 }, /* PCIe */
#endif
#if (EVBARM_BOARDTYPE == hummingboard_edge)
{ 3, 22, GPIO_DIR_OUT, 1 }, /* USB OTG */
{ 1, 0, GPIO_DIR_OUT, 1 }, /* USB H1 */
{ 1, 4, GPIO_DIR_IN, 0 }, /* USDHC2 */
{ 2, 11, GPIO_DIR_OUT, 0 }, /* PCIe */
#endif
/* end of table */
@ -553,6 +585,18 @@ nitrogen6_device_register(device_t self, void *aux)
#endif
#if (EVBARM_BOARDTYPE == hummingboard)
prop_dictionary_set_cstring(dict, "usdhc2-cd-gpio", "!1,4");
#endif
#if (EVBARM_BOARDTYPE == hummingboard_edge)
prop_dictionary_set_cstring(dict, "usdhc2-cd-gpio", "!1,4");
#endif
}
if (device_is_a(self, "imxpcie") &&
device_is_a(device_parent(self), "axi")) {
#if (EVBARM_BOARDTYPE == hummingboard)
prop_dictionary_set_cstring(dict, "imx6pcie-reset-gpio", "!3,4");
#endif
#if (EVBARM_BOARDTYPE == hummingboard_edge)
prop_dictionary_set_cstring(dict, "imx6pcie-reset-gpio", "!2,11");
#endif
}
}