ref: 548a48d1561dd77dbc082dddf0f9a2776ee91914
parent: e39d9249076e9a95e97b33313be1ab2e23095f1d
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jul 3 07:36:50 EDT 2022
imx8: pcie and nvme support
--- a/sys/src/9/imx8/ccm.c
+++ b/sys/src/9/imx8/ccm.c
@@ -1075,6 +1075,90 @@
}
}
+enum {
+ CCM_ANALOG_PLLOUT_MONITOR_CFG = 0x74/4,
+ PLLOUT_MONITOR_CLK_CKE = 1<<4,
+ CCM_ANALOG_FRAC_PLLOUT_DIV_CFG = 0x78/4,
+ CCM_ANALOG_SCCG_PLLOUT_DIV_CFG = 0x7C/4,
+};
+
+static struct {
+ uchar input;
+ uchar reg; /* divider register */
+ uchar shift; /* divider shift */
+} anapllout_input[16] = {
+[0] OSC_25M_REF_CLK,
+[1] OSC_27M_REF_CLK,
+/* [2] HDMI_PHY_27M_CLK */
+/* [3] CLK1_P_N */
+[4] OSC_32K_REF_CLK,
+[5] AUDIO_PLL1_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 0,
+[6] AUDIO_PLL2_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 4,
+[7] GPU_PLL_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 12,
+[8] VPU_PLL_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 16,
+[9] VIDEO_PLL1_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 8,
+[10] ARM_PLL_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 20,
+[11] SYSTEM_PLL1_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 0,
+[12] SYSTEM_PLL2_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 4,
+[13] SYSTEM_PLL3_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 8,
+[14] VIDEO_PLL2_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 16,
+[15] DRAM_PLL1_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 12,
+};
+
+static void
+setanapllout(int input, int freq)
+{
+ int mux, div, reg;
+
+ for(mux = 0; mux < nelem(anapllout_input); mux++)
+ if(anapllout_input[mux].input == input)
+ goto Muxok;
+ panic("setanapllout: bad input clock\n");
+ return;
+Muxok:
+ anatop[CCM_ANALOG_PLLOUT_MONITOR_CFG] = mux;
+ if(freq <= 0)
+ return;
+ div = input_clk_freq[input] / freq;
+ if(div < 1 || div > 8){
+ panic("setanapllout: divider out of range\n");
+ return;
+ }
+ enablepll(input);
+ reg = anapllout_input[mux].reg;
+ if(reg){
+ int shift = anapllout_input[mux].shift;
+ anatop[reg] = (anatop[reg] & ~(7<<shift)) | ((div-1)<<shift);
+ } else if(div != 1){
+ panic("setanapllout: bad frequency\n");
+ return;
+ }
+ anatop[CCM_ANALOG_PLLOUT_MONITOR_CFG] |= PLLOUT_MONITOR_CLK_CKE;
+}
+
+static int
+getanapllout(void)
+{
+ int mux, input, freq, reg, div;
+ u32int cfg = anatop[CCM_ANALOG_PLLOUT_MONITOR_CFG];
+
+ mux = cfg & 0xF;
+ input = anapllout_input[mux].input;
+ if(input == 0)
+ return 0;
+ freq = input_clk_freq[input];
+ if((cfg & PLLOUT_MONITOR_CLK_CKE) == 0)
+ freq = -freq;
+ reg = anapllout_input[mux].reg;
+ if(reg){
+ int shift = anapllout_input[mux].shift;
+ div = ((anatop[reg] >> shift) & 7)+1;
+ } else {
+ div = 1;
+ }
+ return freq / div;
+}
+
static u32int
clkgate(Clock *gate, u32int val)
{
@@ -1330,6 +1414,11 @@
{
int root, input;
+ if(cistrcmp(name, "ccm_analog_pllout") == 0){
+ setanapllout(lookinputclk(source), freq);
+ return;
+ }
+
if((root = lookrootclk(name)) < 0)
panic("setclkrate: clock %s not defined", name);
if(source == nil)
@@ -1345,6 +1434,9 @@
getclkrate(char *name)
{
int root, input;
+
+ if(cistrcmp(name, "ccm_analog_pllout") == 0)
+ return getanapllout();
if((root = lookrootclk(name)) >= 0)
return rootclkgetcfg(root, &input);
--- a/sys/src/9/imx8/fns.h
+++ b/sys/src/9/imx8/fns.h
@@ -159,3 +159,10 @@
#define GPIO_PIN(n, m) ((n)<<5 | (m))
extern void gpioout(uint pin, int set);
extern int gpioin(uint pin);
+
+/* pciimx */
+extern int pcicfgrw8(int tbdf, int rno, int data, int read);
+extern int pcicfgrw16(int tbdf, int rno, int data, int read);
+extern int pcicfgrw32(int tbdf, int rno, int data, int read);
+extern void pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a);
+extern void pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a);
--- a/sys/src/9/imx8/gic.c
+++ b/sys/src/9/imx8/gic.c
@@ -254,6 +254,11 @@
u32int intid;
int cpu, prio;
+ if(BUSTYPE(tbdf) == BusPCI){
+ pciintrenable(tbdf, f, a);
+ return;
+ }
+
if(tbdf != BUSUNKNOWN)
return;
@@ -306,6 +311,10 @@
}
void
-intrdisable(int, void (*)(Ureg*, void*), void *, int, char*)
+intrdisable(int tbdf, void (*f)(Ureg*, void*), void *a, int, char*)
{
+ if(BUSTYPE(tbdf) == BusPCI){
+ pciintrdisable(tbdf, f, a);
+ return;
+ }
}
--- a/sys/src/9/imx8/io.h
+++ b/sys/src/9/imx8/io.h
@@ -28,7 +28,12 @@
IRQsctr0 = SPI+47,
IRQsctr1 = SPI+48,
+ IRQpci2 = SPI+74,
+
IRQenet1 = SPI+118,
+
+ IRQpci1 = SPI+122,
};
#define BUSUNKNOWN (-1)
+#define PCIWADDR(x) PADDR(x)
--- /dev/null
+++ b/sys/src/9/imx8/pciimx.c
@@ -1,0 +1,497 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+
+typedef struct Intvec Intvec;
+struct Intvec
+{
+ Pcidev *p;
+ void (*f)(Ureg*, void*);
+ void *a;
+};
+
+typedef struct Ctlr Ctlr;
+struct Ctlr
+{
+ uvlong mem_base;
+ uvlong mem_size;
+ uvlong cfg_base;
+ uvlong cfg_size;
+ uvlong io_base;
+ uvlong io_size;
+
+ int bno, ubn;
+ int irq;
+
+ u32int *dbi;
+ u32int *cfg;
+ Pcidev *bridge;
+
+ Lock;
+ Intvec vec[32];
+};
+
+static Ctlr ctlrs[2] = {
+ {
+ 0x18000000, 0x7f00000,
+ 0x1ff00000, 0x80000,
+ 0x1ff80000, 0x10000,
+ 0, 127, IRQpci1,
+ (u32int*)(VIRTIO + 0x3800000),
+ },
+ {
+ 0x20000000, 0x7f00000,
+ 0x27f00000, 0x80000,
+ 0x27f80000, 0x10000,
+ 128, 255, IRQpci2,
+ (u32int*)(VIRTIO + 0x3c00000),
+ },
+};
+
+enum {
+ IATU_MAX = 8,
+ IATU_INBOUND = 1<<0,
+ IATU_INDEX_SHIFT = 1,
+
+ IATU_OFFSET = 0x300000/4,
+ IATU_STRIDE = 0x100/4,
+
+ IATU_REGION_CTRL_1 = 0x00/4,
+ CTRL_1_FUNC_NUM_SHIFT = 20,
+ CTRL_1_FUNC_NUM_MASK = 7<<CTRL_1_FUNC_NUM_SHIFT,
+
+ CTRL_1_INCREASE_REGION_SIZ = 1<<13,
+
+ CTRL_1_ATTR_SHIFT = 9,
+ CTRL_1_ATTR_MASK = 3<<CTRL_1_ATTR_SHIFT,
+
+ CTRL_1_TD = 1<<8,
+
+ CTRL_1_TC_SHIFT = 5,
+ CTRL_1_TC_MASK = 7<<CTRL_1_TC_SHIFT,
+
+ CTRL_1_TYPE_SHIFT = 0,
+ CTRL_1_TYPE_MASK = 0x1F<<CTRL_1_TYPE_SHIFT,
+ CTRL_1_TYPE_MEM = 0x0<<CTRL_1_TYPE_SHIFT,
+ CTRL_1_TYPE_IO = 0x2<<CTRL_1_TYPE_SHIFT,
+ CTRL_1_TYPE_CFG0 = 0x4<<CTRL_1_TYPE_SHIFT,
+ CTRL_1_TYPE_CFG1 = 0x5<<CTRL_1_TYPE_SHIFT,
+
+ IATU_REGION_CTRL_2 = 0x04/4,
+ CTRL_2_REGION_EN = 1<<31,
+ CTRL_2_INVERT_MODE = 1<<29,
+ CTRL_2_CFG_SHIFT_MODE = 1<<28,
+ CTRL_2_DMA_BYPASS = 1<<27,
+ CTRL_2_HEADER_SUBSITUTE_EN = 1<<23,
+ CTRL_2_INHIBIT_PAYLOAD = 1<<22,
+ CTRL_2_SNP = 1<<20,
+ CTRL_2_FUNC_BYPASS = 1<<19,
+ CTRL_2_TAG_SUBSTITUTE_EN = 1<<16,
+
+ IATU_LWR_BSAE_ADDR = 0x08/4,
+ IATU_UPPER_BASE_ADDR = 0x0C/4,
+ IATU_LWR_LIMIT_ADDR = 0x10/4,
+ IATU_LWR_TARGET_ADDR = 0x14/4,
+ IATU_UPPER_TARGET_ADDR = 0x18/4,
+ IATU_UPPER_LIMIT_ADDR = 0x20/4, /* undocumented */
+};
+
+/* disable all iATU's */
+static void
+iatuinit(Ctlr *ctlr)
+{
+ u32int *reg;
+ int index;
+
+ for(index=0; index < IATU_MAX; index++){
+ reg = &ctlr->dbi[IATU_OFFSET + IATU_STRIDE*index];
+ reg[IATU_REGION_CTRL_2] &= ~CTRL_2_REGION_EN;
+ }
+}
+
+static void
+iatucfg(Ctlr *ctlr, int index, u32int type, uvlong target, uvlong base, uvlong size)
+{
+ uvlong limit = base + size - 1;
+ u32int *reg;
+
+ assert(size > 0);
+ assert(index < IATU_MAX);
+ assert((index & IATU_INBOUND) == 0);
+
+ reg = &ctlr->dbi[IATU_OFFSET + IATU_STRIDE*index];
+ reg[IATU_REGION_CTRL_2] &= ~CTRL_2_REGION_EN;
+
+ reg[IATU_LWR_BSAE_ADDR] = base;
+ reg[IATU_UPPER_BASE_ADDR] = base >> 32;
+ reg[IATU_LWR_LIMIT_ADDR] = limit;
+ reg[IATU_UPPER_LIMIT_ADDR] = limit >> 32;
+ reg[IATU_LWR_TARGET_ADDR] = target;
+ reg[IATU_UPPER_TARGET_ADDR] = target >> 32;
+
+ type &= CTRL_1_TYPE_MASK;
+ if(((size-1)>>32) != 0)
+ type |= CTRL_1_INCREASE_REGION_SIZ;
+
+ reg[IATU_REGION_CTRL_1] = type;
+ reg[IATU_REGION_CTRL_2] = CTRL_2_REGION_EN;
+
+ while((reg[IATU_REGION_CTRL_2] & CTRL_2_REGION_EN) == 0)
+ microdelay(10);
+}
+
+static Ctlr*
+bus2ctlr(int bno)
+{
+ Ctlr *ctlr;
+
+ for(ctlr = ctlrs; ctlr < &ctlrs[nelem(ctlrs)]; ctlr++)
+ if(bno >= ctlr->bno && bno <= ctlr->ubn)
+ return ctlr;
+ return nil;
+}
+
+static void*
+cfgaddr(int tbdf, int rno)
+{
+ Ctlr *ctlr;
+
+ ctlr = bus2ctlr(BUSBNO(tbdf));
+ if(ctlr == nil)
+ return nil;
+
+ if(pciparentdev == nil){
+ if(BUSDNO(tbdf) != 0 || BUSFNO(tbdf) != 0)
+ return nil;
+ return (uchar*)ctlr->dbi + rno;
+ }
+
+ iatucfg(ctlr, 0<<IATU_INDEX_SHIFT,
+ pciparentdev->parent==nil? CTRL_1_TYPE_CFG0: CTRL_1_TYPE_CFG1,
+ BUSBNO(tbdf)<<24 | BUSDNO(tbdf)<<19 | BUSFNO(tbdf)<<16,
+ ctlr->cfg_base, ctlr->cfg_size);
+
+ return (uchar*)ctlr->cfg + rno;
+}
+
+int
+pcicfgrw32(int tbdf, int rno, int data, int read)
+{
+ u32int *p;
+
+ if((p = cfgaddr(tbdf, rno & ~3)) != nil){
+ if(read)
+ data = *p;
+ else
+ *p = data;
+ } else {
+ data = -1;
+ }
+ return data;
+}
+
+int
+pcicfgrw16(int tbdf, int rno, int data, int read)
+{
+ u16int *p;
+
+ if((p = cfgaddr(tbdf, rno & ~1)) != nil){
+ if(read)
+ data = *p;
+ else
+ *p = data;
+ } else {
+ data = -1;
+ }
+ return data;
+}
+
+int
+pcicfgrw8(int tbdf, int rno, int data, int read)
+{
+ u8int *p;
+
+ if((p = cfgaddr(tbdf, rno)) != nil){
+ if(read)
+ data = *p;
+ else
+ *p = data;
+ } else {
+ data = -1;
+ }
+ return data;
+}
+
+static u16int msimsg;
+#define MSI_TARGET_ADDR PADDR(&msimsg)
+
+enum {
+ MSI_CAP_ID = 0x50/4,
+ PCI_MSI_ENABLE = 1<<16,
+
+ MSI_CTRL_ADDR = 0x820/4,
+ MSI_CTRL_UPPER_ADDR = 0x824/4,
+ MSI_CTRL_INT_0_EN = 0x828/4,
+ MSI_CTRL_INT_0_MASK = 0x82C/4,
+ MSI_CTRL_INT_0_STATUS = 0x830/4,
+
+ MISC_CONTROL_1 = 0x8BC/4,
+ DBI_RO_WR_EN = 1<<0,
+};
+
+static void
+pciinterrupt(Ureg *ureg, void *arg)
+{
+ Ctlr *ctlr = arg;
+ Intvec *vec;
+ u32int status, mask;
+
+ status = ctlr->dbi[MSI_CTRL_INT_0_STATUS];
+ if(status == 0)
+ return;
+ ctlr->dbi[MSI_CTRL_INT_0_STATUS] = status;
+
+ ilock(ctlr);
+ for(vec = ctlr->vec, mask = 1; vec < &ctlr->vec[nelem(ctlr->vec)]; vec++, mask <<= 1){
+ if((status & mask) != 0 && vec->f != nil)
+ (*vec->f)(ureg, vec->a);
+ }
+ iunlock(ctlr);
+}
+
+static void
+pciintrinit(Ctlr *ctlr)
+{
+ ctlr->dbi[MSI_CTRL_INT_0_EN] = 0;
+ ctlr->dbi[MSI_CTRL_INT_0_MASK] = 0;
+ ctlr->dbi[MSI_CTRL_INT_0_STATUS] = -1;
+ ctlr->dbi[MSI_CTRL_ADDR] = MSI_TARGET_ADDR;
+ ctlr->dbi[MSI_CTRL_UPPER_ADDR] = MSI_TARGET_ADDR >> 32;
+
+ intrenable(ctlr->irq+0, pciinterrupt, ctlr, BUSUNKNOWN, "pci");
+ intrenable(ctlr->irq+1, pciinterrupt, ctlr, BUSUNKNOWN, "pci");
+ intrenable(ctlr->irq+2, pciinterrupt, ctlr, BUSUNKNOWN, "pci");
+ intrenable(ctlr->irq+3, pciinterrupt, ctlr, BUSUNKNOWN, "pci");
+
+ ctlr->dbi[MSI_CAP_ID] |= PCI_MSI_ENABLE;
+}
+
+void
+pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a)
+{
+ Ctlr *ctlr;
+ Intvec *vec;
+ Pcidev *p;
+
+ ctlr = bus2ctlr(BUSBNO(tbdf));
+ if(ctlr == nil){
+ print("pciintrenable: %T: unknown controller\n", tbdf);
+ return;
+ }
+
+ if((p = pcimatchtbdf(tbdf)) == nil){
+ print("pciintrenable: %T: unknown device\n", tbdf);
+ return;
+ }
+ if(pcimsidisable(p) < 0){
+ print("pciintrenable: %T: device doesnt support vec\n", tbdf);
+ return;
+ }
+
+ ilock(ctlr);
+ for(vec = ctlr->vec; vec < &ctlr->vec[nelem(ctlr->vec)]; vec++){
+ if(vec->p == p){
+ ctlr->dbi[MSI_CTRL_INT_0_EN] &= ~(1 << (vec - ctlr->vec));
+ vec->p = nil;
+ break;
+ }
+ }
+ for(vec = ctlr->vec; vec < &ctlr->vec[nelem(ctlr->vec)]; vec++){
+ if(vec->p == nil){
+ vec->p = p;
+ vec->a = a;
+ vec->f = f;
+ break;
+ }
+ }
+ iunlock(ctlr);
+
+ if(vec >= &ctlr->vec[nelem(ctlr->vec)]){
+ print("pciintrenable: %T: out of isr slots\n", tbdf);
+ return;
+ }
+ ctlr->dbi[MSI_CTRL_INT_0_EN] |= (1 << (vec - ctlr->vec));
+ pcimsienable(p, MSI_TARGET_ADDR, vec - ctlr->vec);
+}
+
+void
+pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a)
+{
+ Ctlr *ctlr;
+ Intvec *vec;
+
+ ctlr = bus2ctlr(BUSBNO(tbdf));
+ if(ctlr == nil){
+ print("pciintrenable: %T: unknown controller\n", tbdf);
+ return;
+ }
+
+ ilock(ctlr);
+ for(vec = ctlr->vec; vec < &ctlr->vec[nelem(ctlr->vec)]; vec++){
+ if(vec->p == nil)
+ continue;
+ if(vec->p->tbdf == tbdf && vec->f == f && vec->a == a){
+ ctlr->dbi[MSI_CTRL_INT_0_EN] &= ~(1 << (vec - ctlr->vec));
+ vec->f = nil;
+ vec->a = nil;
+ vec->p = nil;
+ break;
+ }
+ }
+ iunlock(ctlr);
+}
+
+static void
+rootinit(Ctlr *ctlr)
+{
+ uvlong base;
+ ulong ioa;
+
+ iatuinit(ctlr);
+
+ ctlr->cfg = vmap(ctlr->cfg_base, ctlr->cfg_size);
+ if(ctlr->cfg == nil)
+ return;
+
+ ctlr->dbi[MISC_CONTROL_1] |= DBI_RO_WR_EN;
+
+ /* bus number */
+ ctlr->dbi[PciPBN/4] &= ~0xFFFFFF;
+ ctlr->dbi[PciPBN/4] |= ctlr->bno | (ctlr->bno+1)<<8 | ctlr->ubn<<16;
+
+ /* command */
+ ctlr->dbi[PciPCR/4] &= ~0xFFFF;
+ ctlr->dbi[PciPCR/4] |= IOen | MEMen | MASen | SErrEn;
+
+ /* device class/subclass */
+ ctlr->dbi[PciRID/4] &= ~0xFFFF0000;
+ ctlr->dbi[PciRID/4] |= 0x06040000;
+
+ ctlr->dbi[PciBAR0/4] = 0;
+ ctlr->dbi[PciBAR1/4] = 0;
+
+ ctlr->dbi[MISC_CONTROL_1] &= ~DBI_RO_WR_EN;
+
+ ctlr->ubn = pciscan(ctlr->bno, &ctlr->bridge, nil);
+ if(ctlr->bridge == nil || ctlr->bridge->bridge == nil)
+ return;
+
+ pciintrinit(ctlr);
+
+ iatucfg(ctlr, 1<<IATU_INDEX_SHIFT, CTRL_1_TYPE_IO, ctlr->io_base, ctlr->io_base, ctlr->io_size);
+ iatucfg(ctlr, 2<<IATU_INDEX_SHIFT, CTRL_1_TYPE_MEM, ctlr->mem_base, ctlr->mem_base, ctlr->mem_size);
+
+ ioa = ctlr->io_base;
+ base = ctlr->mem_base;
+ pcibusmap(ctlr->bridge, &base, &ioa, 1);
+
+ pcihinv(ctlr->bridge);
+}
+
+static void
+pcicfginit(void)
+{
+ fmtinstall('T', tbdffmt);
+ rootinit(&ctlrs[0]);
+ rootinit(&ctlrs[1]);
+}
+
+enum {
+ SRC_PCIEPHY_RCR = 0x2C/4,
+ SRC_PCIE2_RCR = 0x48/4,
+ PCIE_CTRL_APP_XFER_PENDING = 1<<16,
+ PCIE_CTRL_APP_UNLOCK_MSG = 1<<15,
+ PCIE_CTRL_SYS_INT = 1<<14,
+ PCIE_CTRL_CFG_L1_AUX = 1<<12,
+ PCIE_CTRL_APPS_TURNOFF = 1<<11,
+ PCIE_CTRL_APPS_PME = 1<<10,
+ PCIE_CTRL_APPS_EXIT = 1<<9,
+ PCIE_CTRL_APPS_ENTER = 1<<8,
+ PCIE_CTRL_APPS_READY = 1<<7,
+ PCIE_CTRL_APPS_EN = 1<<6,
+ PCIE_CTRL_APPS_RST = 1<<5,
+ PCIE_CTRL_APPS_CLK_REQ = 1<<4,
+ PCIE_PERST = 1<<3,
+ PCIE_BTN = 1<<2,
+ PCIE_G_RST = 1<<1,
+ PCIE_PHY_POWER_ON_RESET_N = 1<<0,
+};
+
+static u32int *resetc = (u32int*)(VIRTIO + 0x390000);
+
+void
+pciimxlink(void)
+{
+ resetc[SRC_PCIEPHY_RCR] |= PCIE_BTN | PCIE_G_RST;
+ resetc[SRC_PCIE2_RCR] |= PCIE_BTN | PCIE_G_RST;
+
+ resetc[SRC_PCIEPHY_RCR] |= PCIE_CTRL_APPS_EN;
+ resetc[SRC_PCIE2_RCR] |= PCIE_CTRL_APPS_EN;
+
+ setclkgate("pcie_clk_rst.auxclk", 0);
+ setclkgate("pcie2_clk_rst.auxclk", 0);
+
+ iomuxpad("pad_ecspi1_mosi", "gpio5_io07", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
+ iomuxpad("pad_sai5_rxd2", "gpio3_io23", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
+
+ gpioout(GPIO_PIN(5, 7), 0);
+ gpioout(GPIO_PIN(3, 23), 0);
+
+ powerup("pcie");
+ powerup("pcie2");
+
+ /* configure monitor CLK2 output internal reference clock for PCIE1 */
+ setclkrate("ccm_analog_pllout", "system_pll1_clk", 100*Mhz);
+ delay(10);
+
+ /* PCIE1_REF_USE_PAD=0 */
+ iomuxgpr(14, 0<<9, 1<<9);
+
+ /* PCIE2_REF_USE_PAD=1 */
+ iomuxgpr(16, 1<<9, 1<<9);
+
+ /* PCIE1_CTRL_DEVICE_TYPE=ROOT, PCIE2_CTRL_DEVICE_TYPE=ROOT */
+ iomuxgpr(12, 4<<12 | 4<<8, 0xF<<12 | 0xF<<8);
+
+ setclkrate("ccm_pcie1_ctrl_clk_root", "system_pll2_div4", 250*Mhz);
+ setclkrate("ccm_pcie2_ctrl_clk_root", "system_pll2_div4", 250*Mhz);
+
+ setclkrate("pcie_clk_rst.auxclk", "system_pll2_div10", 100*Mhz);
+ setclkrate("pcie2_clk_rst.auxclk", "system_pll2_div10", 100*Mhz);
+
+ setclkrate("pcie_phy.ref_alt_clk_p", "system_pll2_div10", 100*Mhz);
+ setclkrate("pcie2_phy.ref_alt_clk_p", "system_pll2_div10", 100*Mhz);
+
+ setclkgate("pcie_clk_rst.auxclk", 1);
+ setclkgate("pcie2_clk_rst.auxclk", 1);
+
+ /* PCIE1_CLKREQ_B_OVERRIDE=0 PCIE1_CLKREQ_B_OVERRIDE_EN=1 */
+ iomuxgpr(14, 1<<10, 3<<10);
+
+ /* PCIE2_CLKREQ_B_OVERRIDE=0 PCIE2_CLKREQ_B_OVERRIDE_EN=1 */
+ iomuxgpr(16, 1<<10, 3<<10);
+
+ delay(100);
+ gpioout(GPIO_PIN(5, 7), 1);
+ gpioout(GPIO_PIN(3, 23), 1);
+ delay(1);
+
+ resetc[SRC_PCIEPHY_RCR] &= ~(PCIE_BTN | PCIE_G_RST);
+ resetc[SRC_PCIE2_RCR] &= ~(PCIE_BTN | PCIE_G_RST);
+
+ pcicfginit();
+}
--- a/sys/src/9/imx8/reform
+++ b/sys/src/9/imx8/reform
@@ -27,6 +27,7 @@
ethermedium
loopbackmedium
i2cimx devi2c
+ pciimx pci
ip
tcp
udp
@@ -44,6 +45,7 @@
uartimx
iomux
sdmmc usdhc
+ sdnvme pci
port
int cpuserver = 0;
bootdir
--- a/sys/src/9/port/pci.c
+++ b/sys/src/9/port/pci.c
@@ -16,6 +16,7 @@
};
int pcimaxdno;
+Pcidev *pciparentdev;
static Lock pcicfglock;
static Pcidev *pcilist, **pcitail;
@@ -113,6 +114,8 @@
int data;
ilock(&pcicfglock);
+ pciparentdev = p->parent;
+
data = pcicfgrw8(p->tbdf, rno, 0, 1);
iunlock(&pcicfglock);
@@ -122,6 +125,8 @@
pcicfgw8(Pcidev* p, int rno, int data)
{
ilock(&pcicfglock);
+ pciparentdev = p->parent;
+
pcicfgrw8(p->tbdf, rno, data, 0);
iunlock(&pcicfglock);
}
@@ -131,6 +136,8 @@
int data;
ilock(&pcicfglock);
+ pciparentdev = p->parent;
+
data = pcicfgrw16(p->tbdf, rno, 0, 1);
iunlock(&pcicfglock);
@@ -140,6 +147,8 @@
pcicfgw16(Pcidev* p, int rno, int data)
{
ilock(&pcicfglock);
+ pciparentdev = p->parent;
+
pcicfgrw16(p->tbdf, rno, data, 0);
iunlock(&pcicfglock);
}
@@ -149,6 +158,8 @@
int data;
ilock(&pcicfglock);
+ pciparentdev = p->parent;
+
data = pcicfgrw32(p->tbdf, rno, 0, 1);
iunlock(&pcicfglock);
@@ -158,6 +169,8 @@
pcicfgw32(Pcidev* p, int rno, int data)
{
ilock(&pcicfglock);
+ pciparentdev = p->parent;
+
pcicfgrw32(p->tbdf, rno, data, 0);
iunlock(&pcicfglock);
}
@@ -169,6 +182,7 @@
int v;
ilock(&pcicfglock);
+ pciparentdev = p->parent;
v = pcicfgrw32(p->tbdf, rno, 0, 1);
pcicfgrw32(p->tbdf, rno, -1, 0);
@@ -206,6 +220,8 @@
pcisetbar(Pcidev *p, int rno, uvlong bar)
{
ilock(&pcicfglock);
+ pciparentdev = p->parent;
+
pcicfgrw32(p->tbdf, rno, bar, 0);
if((bar&7) == 4 && rno >= PciBAR0 && rno < PciBAR0+4*(nelem(p->mem)-1))
pcicfgrw32(p->tbdf, rno+4, bar>>32, 0);
@@ -216,6 +232,8 @@
pcisetwin(Pcidev *p, uvlong base, uvlong limit)
{
ilock(&pcicfglock);
+ pciparentdev = p->parent;
+
if(base & 1){
pcicfgrw16(p->tbdf, PciIBR, (limit & 0xF000)|((base & 0xF000)>>8), 0);
pcicfgrw32(p->tbdf, PciIUBR, (limit & 0xFFFF0000)|(base>>16), 0);
@@ -534,6 +552,8 @@
tbdf = MKBUS(BusPCI, bno, dno, fno);
lock(&pcicfglock);
+ pciparentdev = parent;
+
l = pcicfgrw32(tbdf, PciVID, 0, 1);
unlock(&pcicfglock);
@@ -540,6 +560,7 @@
if(l == 0xFFFFFFFF || l == 0)
continue;
p = pcidevalloc();
+ p->parent = parent;
p->tbdf = tbdf;
p->vid = l;
p->did = l>>16;
@@ -622,7 +643,6 @@
break;
}
- p->parent = parent;
if(head != nil)
*tail = p;
else
--- a/sys/src/9/port/pci.h
+++ b/sys/src/9/port/pci.h
@@ -223,6 +223,7 @@
};
extern int pcimaxdno;
+extern Pcidev *pciparentdev;
extern void pcidevfree(Pcidev* pcidev);