1*923e03b5Sjmcneill /* $NetBSD: nslu2_pci.c,v 1.8 2018/11/18 14:25:17 jmcneill Exp $ */
26f616773Sscw
36f616773Sscw /*-
46f616773Sscw * Copyright (c) 2006 The NetBSD Foundation, Inc.
56f616773Sscw * All rights reserved.
66f616773Sscw *
76f616773Sscw * This code is derived from software contributed to The NetBSD Foundation
86f616773Sscw * by Steve C. Woodford.
96f616773Sscw *
106f616773Sscw * Redistribution and use in source and binary forms, with or without
116f616773Sscw * modification, are permitted provided that the following conditions
126f616773Sscw * are met:
136f616773Sscw * 1. Redistributions of source code must retain the above copyright
146f616773Sscw * notice, this list of conditions and the following disclaimer.
156f616773Sscw * 2. Redistributions in binary form must reproduce the above copyright
166f616773Sscw * notice, this list of conditions and the following disclaimer in the
176f616773Sscw * documentation and/or other materials provided with the distribution.
186f616773Sscw *
196f616773Sscw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
206f616773Sscw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216f616773Sscw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226f616773Sscw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
236f616773Sscw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246f616773Sscw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256f616773Sscw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266f616773Sscw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276f616773Sscw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286f616773Sscw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296f616773Sscw * POSSIBILITY OF SUCH DAMAGE.
306f616773Sscw */
316f616773Sscw /*
326f616773Sscw * Copyright (c) 2003
336f616773Sscw * Ichiro FUKUHARA <ichiro@ichiro.org>.
346f616773Sscw * All rights reserved.
356f616773Sscw *
366f616773Sscw * Redistribution and use in source and binary forms, with or without
376f616773Sscw * modification, are permitted provided that the following conditions
386f616773Sscw * are met:
396f616773Sscw * 1. Redistributions of source code must retain the above copyright
406f616773Sscw * notice, this list of conditions and the following disclaimer.
416f616773Sscw * 2. Redistributions in binary form must reproduce the above copyright
426f616773Sscw * notice, this list of conditions and the following disclaimer in the
436f616773Sscw * documentation and/or other materials provided with the distribution.
446f616773Sscw *
456f616773Sscw * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR
466f616773Sscw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
476f616773Sscw * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
486f616773Sscw * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
496f616773Sscw * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
506f616773Sscw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
516f616773Sscw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
526f616773Sscw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
536f616773Sscw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
546f616773Sscw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
556f616773Sscw * SUCH DAMAGE.
566f616773Sscw */
576f616773Sscw
586f616773Sscw #include <sys/cdefs.h>
59*923e03b5Sjmcneill __KERNEL_RCSID(0, "$NetBSD: nslu2_pci.c,v 1.8 2018/11/18 14:25:17 jmcneill Exp $");
606f616773Sscw
616f616773Sscw /*
626f616773Sscw * Linksys NSLU2 PCI support.
636f616773Sscw */
646f616773Sscw
656f616773Sscw #include <sys/param.h>
666f616773Sscw #include <sys/systm.h>
676f616773Sscw #include <sys/device.h>
686f616773Sscw
696f616773Sscw #include <arm/xscale/ixp425reg.h>
706f616773Sscw #include <arm/xscale/ixp425var.h>
716f616773Sscw
726f616773Sscw #include <dev/pci/pcivar.h>
736f616773Sscw
746f616773Sscw #include <evbarm/nslu2/nslu2reg.h>
756f616773Sscw
766f616773Sscw static int
nslu2_pci_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ihp)77d3e53912Sdyoung nslu2_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
786f616773Sscw {
796f616773Sscw
806f616773Sscw KASSERT(pa->pa_bus == 0 && pa->pa_device == 1);
816f616773Sscw
826f616773Sscw switch (pa->pa_function) {
836f616773Sscw case 0:
846f616773Sscw *ihp = PCI_INT_A;
856f616773Sscw break;
866f616773Sscw
876f616773Sscw case 1:
886f616773Sscw *ihp = PCI_INT_B;
896f616773Sscw break;
906f616773Sscw
916f616773Sscw case 2:
926f616773Sscw *ihp = PCI_INT_C;
936f616773Sscw break;
946f616773Sscw
956f616773Sscw default:
966f616773Sscw return (1);
976f616773Sscw }
986f616773Sscw
996f616773Sscw return (0);
1006f616773Sscw }
1016f616773Sscw
1026f616773Sscw static const char *
nslu2_pci_intr_string(void * v,pci_intr_handle_t ih,char * buf,size_t len)103e58a356cSchristos nslu2_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
1046f616773Sscw {
105e58a356cSchristos char c;
1066f616773Sscw switch (ih) {
1076f616773Sscw case PCI_INT_A:
108e58a356cSchristos c = 'A';
109e58a356cSchristos break;
1106f616773Sscw
1116f616773Sscw case PCI_INT_B:
112e58a356cSchristos c = 'B';
113e58a356cSchristos break;
1146f616773Sscw
1156f616773Sscw case PCI_INT_C:
116e58a356cSchristos c = 'C';
117e58a356cSchristos break;
118e58a356cSchristos default:
119e58a356cSchristos c = '?';
1206f616773Sscw }
121e58a356cSchristos snprintf(buf, len, "PCI%c", c);
1226f616773Sscw
123c264ca3cSozaki-r return buf;
1246f616773Sscw }
1256f616773Sscw
1266f616773Sscw static const struct evcnt *
nslu2_pci_intr_evcnt(void * v,pci_intr_handle_t ih)1276f616773Sscw nslu2_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
1286f616773Sscw {
1296f616773Sscw
1306f616773Sscw return (NULL);
1316f616773Sscw }
1326f616773Sscw
1336f616773Sscw static void *
nslu2_pci_intr_establish(void * v,pci_intr_handle_t ih,int ipl,int (* func)(void *),void * arg,const char * xname)1346f616773Sscw nslu2_pci_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
135*923e03b5Sjmcneill int (*func)(void *), void *arg, const char *xname)
1366f616773Sscw {
1376f616773Sscw
1386f616773Sscw return (ixp425_intr_establish(ih, ipl, func, arg));
1396f616773Sscw }
1406f616773Sscw
1416f616773Sscw static void
nslu2_pci_intr_disestablish(void * v,void * cookie)1426f616773Sscw nslu2_pci_intr_disestablish(void *v, void *cookie)
1436f616773Sscw {
1446f616773Sscw
1456f616773Sscw ixp425_intr_disestablish(cookie);
1466f616773Sscw }
1476f616773Sscw
1486f616773Sscw void
ixp425_md_pci_conf_interrupt(pci_chipset_tag_t pc,int bus,int dev,int pin,int swiz,int * ilinep)1496f616773Sscw ixp425_md_pci_conf_interrupt(pci_chipset_tag_t pc, int bus, int dev, int pin,
1506f616773Sscw int swiz, int *ilinep)
1516f616773Sscw {
1526f616773Sscw
1536f616773Sscw KASSERT(bus == 0 && dev == 1);
1546f616773Sscw
1556f616773Sscw *ilinep = ((swiz + pin - 1) & 3);
1566f616773Sscw }
1576f616773Sscw
1586f616773Sscw void
ixp425_md_pci_init(struct ixp425_softc * sc)1596f616773Sscw ixp425_md_pci_init(struct ixp425_softc *sc)
1606f616773Sscw {
1616f616773Sscw pci_chipset_tag_t pc = &sc->ia_pci_chipset;
16208a4aba7Sskrll uint32_t reg;
1636f616773Sscw
1646f616773Sscw pc->pc_intr_v = sc;
1656f616773Sscw pc->pc_intr_map = nslu2_pci_intr_map;
1666f616773Sscw pc->pc_intr_string = nslu2_pci_intr_string;
1676f616773Sscw pc->pc_intr_evcnt = nslu2_pci_intr_evcnt;
1686f616773Sscw pc->pc_intr_establish = nslu2_pci_intr_establish;
1696f616773Sscw pc->pc_intr_disestablish = nslu2_pci_intr_disestablish;
1706f616773Sscw
1716f616773Sscw /* PCI Reset Assert */
1726f616773Sscw reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOUTR);
1736f616773Sscw reg &= ~(1u << GPIO_PCI_RESET);
1746f616773Sscw GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOUTR, reg);
1756f616773Sscw
1766f616773Sscw /* PCI Clock Disable */
1776f616773Sscw reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPCLKR);
1786f616773Sscw reg &= ~GPCLKR_MUX14;
1796f616773Sscw GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPCLKR, reg);
1806f616773Sscw
1816f616773Sscw /*
1826f616773Sscw * Set GPIO Direction
1836f616773Sscw * Output: PCI_CLK, PCI_RESET
1846f616773Sscw * Input: PCI_INTA, PCI_INTB, PCI_INTC
1856f616773Sscw */
1866f616773Sscw reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER);
1876f616773Sscw reg &= ~((1u << GPIO_PCI_CLK) | (1u << GPIO_PCI_RESET));
1886f616773Sscw reg |= (1u << GPIO_PCI_INTA) | (1u << GPIO_PCI_INTB) |
1896f616773Sscw (1u << GPIO_PCI_INTC);
1906f616773Sscw GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER, reg);
1916f616773Sscw
1926f616773Sscw /*
1936f616773Sscw * Set GPIO interrupt type
1946f616773Sscw * PCI_INT_A, PCI_INTB, PCI_INT_C: Active Low
1956f616773Sscw */
1966f616773Sscw reg = GPIO_CONF_READ_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTA));
1976f616773Sscw reg &= ~GPIO_TYPE(GPIO_PCI_INTA, GPIO_TYPE_MASK);
1986f616773Sscw reg |= GPIO_TYPE(GPIO_PCI_INTA, GPIO_TYPE_ACT_LOW);
1996f616773Sscw GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTA), reg);
2006f616773Sscw
2016f616773Sscw reg = GPIO_CONF_READ_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTB));
2026f616773Sscw reg &= ~GPIO_TYPE(GPIO_PCI_INTB, GPIO_TYPE_MASK);
2036f616773Sscw reg |= GPIO_TYPE(GPIO_PCI_INTB, GPIO_TYPE_ACT_LOW);
2046f616773Sscw GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTB), reg);
2056f616773Sscw
2066f616773Sscw reg = GPIO_CONF_READ_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTC));
2076f616773Sscw reg &= ~GPIO_TYPE(GPIO_PCI_INTC, GPIO_TYPE_MASK);
2086f616773Sscw reg |= GPIO_TYPE(GPIO_PCI_INTC, GPIO_TYPE_ACT_LOW);
2096f616773Sscw GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTC), reg);
2106f616773Sscw
2116f616773Sscw /* Clear ISR */
2126f616773Sscw GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPISR, (1u << GPIO_PCI_INTA) |
2136f616773Sscw (1u << GPIO_PCI_INTB) | (1u << GPIO_PCI_INTC));
2146f616773Sscw
2156f616773Sscw /* Wait 1ms to satisfy "minimum reset assertion time" of the PCI spec */
2166f616773Sscw DELAY(1000);
2176f616773Sscw reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPCLKR);
2186f616773Sscw reg |= (0xf << GPCLKR_CLK0DC_SHIFT) | (0xf << GPCLKR_CLK0TC_SHIFT);
2196f616773Sscw GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPCLKR, reg);
2206f616773Sscw
2216f616773Sscw /* PCI Clock Enable */
2226f616773Sscw reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPCLKR);
2236f616773Sscw reg |= GPCLKR_MUX14;
2246f616773Sscw GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPCLKR, reg);
2256f616773Sscw
2266f616773Sscw /*
2276f616773Sscw * Wait 100us to satisfy "minimum reset assertion time from clock stable
2286f616773Sscw * requirement of the PCI spec
2296f616773Sscw */
2306f616773Sscw DELAY(100);
2316f616773Sscw /* PCI Reset deassert */
2326f616773Sscw reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOUTR);
2336f616773Sscw reg |= 1u << GPIO_PCI_RESET;
2346f616773Sscw GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOUTR, reg);
2356f616773Sscw
2366f616773Sscw /*
2376f616773Sscw * AHB->PCI address translation
2386f616773Sscw * PCI Memory Map allocation in 0x48000000 (64MB)
2396f616773Sscw * see. IXP425_PCI_MEM_HWBASE
2406f616773Sscw */
2416f616773Sscw PCI_CSR_WRITE_4(sc, PCI_PCIMEMBASE, 0x48494a4b);
2426f616773Sscw
2436f616773Sscw /*
2446f616773Sscw * PCI->AHB address translation
2456f616773Sscw * begin at the physical memory start + OFFSET
2466f616773Sscw */
2476f616773Sscw #define AHB_OFFSET 0x10000000UL
2486f616773Sscw reg = (AHB_OFFSET + 0x00000000) >> 0;
2496f616773Sscw reg |= (AHB_OFFSET + 0x01000000) >> 8;
2506f616773Sscw reg |= (AHB_OFFSET + 0x02000000) >> 16;
2516f616773Sscw reg |= (AHB_OFFSET + 0x03000000) >> 24;
2526f616773Sscw PCI_CSR_WRITE_4(sc, PCI_AHBMEMBASE, reg);
2536f616773Sscw
2546f616773Sscw /* Write Mapping registers PCI Configuration Registers */
2556f616773Sscw /* Base Address 0 - 3 */
2566f616773Sscw ixp425_pci_conf_reg_write(sc, PCI_MAPREG_BAR0, AHB_OFFSET + 0x00000000);
2576f616773Sscw ixp425_pci_conf_reg_write(sc, PCI_MAPREG_BAR1, AHB_OFFSET + 0x01000000);
2586f616773Sscw ixp425_pci_conf_reg_write(sc, PCI_MAPREG_BAR2, AHB_OFFSET + 0x02000000);
2596f616773Sscw ixp425_pci_conf_reg_write(sc, PCI_MAPREG_BAR3, AHB_OFFSET + 0x03000000);
2606f616773Sscw
2616f616773Sscw /* Base Address 4 */
2626f616773Sscw ixp425_pci_conf_reg_write(sc, PCI_MAPREG_BAR4, 0xffffffff);
2636f616773Sscw
2646f616773Sscw /* Base Address 5 */
2656f616773Sscw ixp425_pci_conf_reg_write(sc, PCI_MAPREG_BAR5, 0x00000000);
2666f616773Sscw
2676f616773Sscw /* Assert some PCI errors */
2686f616773Sscw PCI_CSR_WRITE_4(sc, PCI_ISR, ISR_AHBE | ISR_PPE | ISR_PFE | ISR_PSE);
2696f616773Sscw
2706f616773Sscw /*
2716f616773Sscw * Set up byte lane swapping between little-endian PCI
2726f616773Sscw * and the big-endian AHB bus
2736f616773Sscw */
2746f616773Sscw PCI_CSR_WRITE_4(sc, PCI_CSR, CSR_IC | CSR_ABE | CSR_PDS);
2756f616773Sscw
2766f616773Sscw /*
2776f616773Sscw * Enable bus mastering and I/O,memory access
2786f616773Sscw */
2796f616773Sscw ixp425_pci_conf_reg_write(sc, PCI_COMMAND_STATUS_REG,
2806f616773Sscw PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
2816f616773Sscw PCI_COMMAND_MASTER_ENABLE);
2826f616773Sscw
2836f616773Sscw /*
2846f616773Sscw * Wait some more to ensure PCI devices have stabilised.
2856f616773Sscw */
2866f616773Sscw DELAY(50000);
2876f616773Sscw }
288