Home | History | Annotate | Line # | Download | only in pci
      1 /*	$NetBSD: pcix.c,v 1.4 2026/09/28 20:41:01 rkujawa Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2012, 2014, 2024, 2026 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Radoslaw Kujawa.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * IBM PLB-PCIX host bridge, as found on the 440GP/440SPe/460EX
     33  *
     34  * XXX The bridge addresses are currently straight from 460EX include
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: pcix.c,v 1.4 2026/09/28 20:41:01 rkujawa Exp $");
     39 
     40 #ifdef _KERNEL_OPT
     41 #include "opt_pci.h"
     42 #endif
     43 
     44 #include <sys/param.h>
     45 #include <sys/systm.h>
     46 #include <sys/device.h>
     47 #include <sys/extent.h>
     48 #include <sys/bus.h>
     49 
     50 #include <dev/pci/pcivar.h>
     51 #include <dev/pci/pcireg.h>
     52 #include <dev/pci/pciconf.h>
     53 
     54 #include <powerpc/ibm4xx/amcc460ex.h>
     55 #include <powerpc/ibm4xx/cpu.h>
     56 #include <powerpc/ibm4xx/spr.h>
     57 #include <powerpc/ibm4xx/dev/plbvar.h>
     58 #include <powerpc/ibm4xx/pci_machdep.h>
     59 #include <powerpc/pci_machdep.h>
     60 
     61 /* Internal register offsets (relative to the internal register base) */
     62 #define	PCIX0_POM0LAL	0x68
     63 #define	PCIX0_POM0LAH	0x6c
     64 #define	PCIX0_POM0SA	0x70
     65 #define	PCIX0_POM0PCIAL	0x74
     66 #define	PCIX0_POM0PCIAH	0x78
     67 #define	PCIX0_POM1LAL	0x7c
     68 #define	PCIX0_POM1LAH	0x80
     69 #define	PCIX0_POM1SA	0x84
     70 #define	PCIX0_POM1PCIAL	0x88
     71 #define	PCIX0_POM1PCIAH	0x8c
     72 #define	PCIX0_POM2SA	0x90
     73 #define	PCIX0_PIM0SAL	0x98
     74 #define	PCIX0_PIM0LAL	0x9c
     75 #define	PCIX0_PIM0LAH	0xa0
     76 #define	PCIX0_PIM1SA	0xa4
     77 #define	PCIX0_PIM1LAL	0xa8
     78 #define	PCIX0_PIM1LAH	0xac
     79 #define	PCIX0_PIM2SAL	0xb0
     80 #define	PCIX0_PIM0SAH	0xf8
     81 
     82 #define	PIM_SA_ENABLE	0x1
     83 #define	PIM_SA_PREFETCH	0x2		/* inbound read prefetch (bit 1) */
     84 
     85 #define	PCIC_CFGADDR	0
     86 #define	PCIC_CFGDATA	4
     87 
     88 static int	pcix_match(device_t, cfdata_t, void *);
     89 static void	pcix_attach(device_t, device_t, void *);
     90 static int	pcix_print(void *, const char *);
     91 
     92 CFATTACH_DECL_NEW(pcix, 0, pcix_match, pcix_attach, NULL, NULL);
     93 
     94 static pcireg_t	pcix_conf_read(void *, pcitag_t, int);
     95 static void	pcix_conf_write(void *, pcitag_t, int, pcireg_t);
     96 static void	pcix_attach_hook(device_t, device_t,
     97 		    struct pcibus_attach_args *);
     98 static int	pcix_conf_hook(void *, int, int, int, pcireg_t);
     99 
    100 /* CFGADDR/CFGDATA pair */
    101 static struct powerpc_bus_space pcix_cfg_tag = {
    102 	_BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE,
    103 	0x00000000,			/* offset */
    104 	AMCC460EX_PCIX0_CFG_PLBA,	/* extent base */
    105 	AMCC460EX_PCIX0_CFG_PLBA + 8,	/* extent limit */
    106 };
    107 
    108 /* Internal (window) registers */
    109 static struct powerpc_bus_space pcix_reg_tag = {
    110 	_BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE,
    111 	0x00000000,
    112 	AMCC460EX_PCIX0_REGS_PLBA,
    113 	AMCC460EX_PCIX0_REGS_PLBA + 0x100,
    114 };
    115 
    116 /* PCI I/O: bus 0x0000-0xffff -> PLB I/O window */
    117 static struct powerpc_bus_space pcix_io_tag = {
    118 	_BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_IO_TYPE,
    119 	AMCC460EX_PCIX0_IO_PLBA,	/* offset */
    120 	0x00000000,			/* extent base */
    121 	0x00010000,			/* extent limit */
    122 };
    123 
    124 /*
    125  * PCI memory: bus addr = low 32 bits of PLB addr.
    126  */
    127 static struct powerpc_bus_space pcix_mem_tag = {
    128 	_BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE,
    129 	0x00000000,
    130 	AMCC460EX_PCIX0_MEM_BASE,
    131 	AMCC460EX_PCIX0_PMEM_BASE + AMCC460EX_PCIX0_PMEM_SIZE,
    132 };
    133 
    134 static bus_space_handle_t pcix_cfg_ioh;
    135 static bus_space_handle_t pcix_reg_ioh;
    136 
    137 static struct genppc_pci_chipset pcix_chipset = {
    138 	.pc_conf_v =		NULL,
    139 	.pc_attach_hook =	pcix_attach_hook,
    140 	.pc_bus_maxdevs =	ibm4xx_pci_bus_maxdevs,
    141 	.pc_make_tag =		ibm4xx_pci_make_tag,
    142 	.pc_conf_read =		pcix_conf_read,
    143 	.pc_conf_write =	pcix_conf_write,
    144 
    145 	.pc_intr_v =		&pcix_chipset,
    146 	.pc_intr_map =		genppc_pci_intr_map,
    147 	.pc_intr_string =	genppc_pci_intr_string,
    148 	.pc_intr_evcnt =	genppc_pci_intr_evcnt,
    149 	.pc_intr_establish =	genppc_pci_intr_establish,
    150 	.pc_intr_disestablish =	genppc_pci_intr_disestablish,
    151 	.pc_intr_setattr =	ibm4xx_pci_intr_setattr,
    152 	.pc_intr_type =		genppc_pci_intr_type,
    153 	.pc_intr_alloc =	genppc_pci_intr_alloc,
    154 	.pc_intr_release =	genppc_pci_intr_release,
    155 	.pc_intx_alloc =	genppc_pci_intx_alloc,
    156 
    157 	.pc_msi_v =		&pcix_chipset,
    158 	GENPPC_PCI_MSI_INITIALIZER,
    159 
    160 	.pc_msix_v =		&pcix_chipset,
    161 	GENPPC_PCI_MSIX_INITIALIZER,
    162 
    163 	.pc_conf_interrupt =	ibm4xx_pci_conf_interrupt,
    164 	.pc_decompose_tag =	ibm4xx_pci_decompose_tag,
    165 	.pc_conf_hook =		pcix_conf_hook,
    166 };
    167 
    168 static void
    169 pcix_attach_hook(device_t parent, device_t self,
    170     struct pcibus_attach_args *pba)
    171 {
    172 }
    173 
    174 static int
    175 pcix_conf_hook(void *v, int bus, int dev, int func, pcireg_t id)
    176 {
    177 
    178 	return PCI_CONF_DEFAULT;
    179 }
    180 
    181 /*
    182  * Translate the tag
    183  */
    184 static uint32_t
    185 pcix_cfg_addr(pcitag_t tag, int reg)
    186 {
    187 	uint32_t addr = (tag & 0x00ffff00) | (reg & 0xfc);
    188 
    189 	if (tag & 0x00ff0000)		/* bus number != 0 -> Type 1 */
    190 		addr |= 1;
    191 	return addr;
    192 }
    193 
    194 static pcireg_t
    195 pcix_conf_read(void *v, pcitag_t tag, int reg)
    196 {
    197 	pcireg_t data;
    198 
    199 	if ((unsigned int)reg >= PCI_CONF_SIZE)
    200 		return (pcireg_t) -1;
    201 
    202 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR,
    203 	    pcix_cfg_addr(tag, reg));
    204 	data = bus_space_read_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGDATA);
    205 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR, 0);
    206 	return data;
    207 }
    208 
    209 static void
    210 pcix_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
    211 {
    212 
    213 	if ((unsigned int)reg >= PCI_CONF_SIZE)
    214 		return;
    215 
    216 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR,
    217 	    pcix_cfg_addr(tag, reg));
    218 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGDATA, data);
    219 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR, 0);
    220 }
    221 
    222 #define	PCIX_REG_WRITE(reg, val) \
    223 	bus_space_write_4(&pcix_reg_tag, pcix_reg_ioh, (reg), (val))
    224 
    225 static void
    226 pcix_setup_windows(void)
    227 {
    228 
    229 	/* POM0: PLB -> PCI memory, 128MB */
    230 	PCIX_REG_WRITE(PCIX0_POM0SA, 0);		/* disable while */
    231 	PCIX_REG_WRITE(PCIX0_POM0LAL, AMCC460EX_PCIX0_MEM_BASE);
    232 	PCIX_REG_WRITE(PCIX0_POM0LAH, AMCC460EX_PCIX0_MEM_PLBA_H);
    233 	PCIX_REG_WRITE(PCIX0_POM0PCIAL, AMCC460EX_PCIX0_MEM_BASE);
    234 	PCIX_REG_WRITE(PCIX0_POM0PCIAH, 0);
    235 	PCIX_REG_WRITE(PCIX0_POM0SA, ~(0x08000000 - 1) | 1);
    236 
    237 	/* POM1: PLB -> PCI prefetchable memory, identity mapped, 256MB */
    238 	PCIX_REG_WRITE(PCIX0_POM1SA, 0);		/* disable while */
    239 	PCIX_REG_WRITE(PCIX0_POM1LAL, AMCC460EX_PCIX0_PMEM_BASE);
    240 	PCIX_REG_WRITE(PCIX0_POM1LAH, AMCC460EX_PCIX0_PMEM_PLBA_H);
    241 	PCIX_REG_WRITE(PCIX0_POM1PCIAL, AMCC460EX_PCIX0_PMEM_BASE);
    242 	PCIX_REG_WRITE(PCIX0_POM1PCIAH, 0);
    243 	PCIX_REG_WRITE(PCIX0_POM1SA, ~(AMCC460EX_PCIX0_PMEM_SIZE - 1) | 1);
    244 
    245 	/* POM2 unused */
    246 	PCIX_REG_WRITE(PCIX0_POM2SA, 0);
    247 
    248 	/* PIM0: PCI 0 -> PLB 0, 2GB (covers all of RAM) */
    249 	PCIX_REG_WRITE(PCIX0_PIM0SAL, 0);		/* disable while */
    250 	PCIX_REG_WRITE(PCIX0_PIM0LAL, 0);
    251 	PCIX_REG_WRITE(PCIX0_PIM0LAH, 0);
    252 	PCIX_REG_WRITE(PCIX0_PIM0SAH, 0xffffffff);
    253 	/*
    254 	 * Enable inbound read prefetch
    255 	 */
    256 	PCIX_REG_WRITE(PCIX0_PIM0SAL,
    257 	    ~(0x80000000U - 1) | PIM_SA_ENABLE | PIM_SA_PREFETCH);
    258 
    259 	/* PIM1/PIM2 unused */
    260 	PCIX_REG_WRITE(PCIX0_PIM1SA, 0);
    261 	PCIX_REG_WRITE(PCIX0_PIM2SAL, 0);
    262 }
    263 
    264 static int
    265 pcix_match(device_t parent, cfdata_t cf, void *aux)
    266 {
    267 	struct plb_attach_args *paa = aux;
    268 
    269 	if (strcmp(paa->plb_name, cf->cf_name) != 0)
    270 		return 0;
    271 
    272 	return 1;
    273 }
    274 
    275 static void
    276 pcix_attach(device_t parent, device_t self, void *aux)
    277 {
    278 	struct plb_attach_args *paa = aux;
    279 	struct pcibus_attach_args pba;
    280 	pci_chipset_tag_t pc = &pcix_chipset;
    281 
    282 	aprint_normal(": PLB-PCIX host bridge\n");
    283 
    284 	if (bus_space_init(&pcix_cfg_tag, "pcixcfg", NULL, 0) ||
    285 	    bus_space_map(&pcix_cfg_tag, AMCC460EX_PCIX0_CFG_PLBA, 8, 0,
    286 	      &pcix_cfg_ioh))
    287 		panic("pcix_attach: can't map config registers");
    288 	if (bus_space_init(&pcix_reg_tag, "pcixreg", NULL, 0) ||
    289 	    bus_space_map(&pcix_reg_tag, AMCC460EX_PCIX0_REGS_PLBA, 0x100, 0,
    290 	      &pcix_reg_ioh))
    291 		panic("pcix_attach: can't map bridge registers");
    292 	if (bus_space_init(&pcix_io_tag, "pcixio", NULL, 0))
    293 		panic("pcix_attach: can't init IO tag");
    294 	if (bus_space_init(&pcix_mem_tag, "pcixmem", NULL, 0))
    295 		panic("pcix_attach: can't init MEM tag");
    296 
    297 	pcix_setup_windows();
    298 
    299 #ifdef PCI_NETBSD_CONFIGURE
    300 	struct pciconf_resources *pcires = pciconf_resource_init();
    301 
    302 	pciconf_resource_add(pcires, PCICONF_RESOURCE_IO,
    303 	    0x1000, 0x10000 - 0x1000);
    304 	pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM,
    305 	    AMCC460EX_PCIX0_MEM_BASE, AMCC460EX_PCIX0_MEM_SIZE);
    306 	pciconf_resource_add(pcires, PCICONF_RESOURCE_PREFETCHABLE_MEM,
    307 	    AMCC460EX_PCIX0_PMEM_BASE, AMCC460EX_PCIX0_PMEM_MAP);
    308 
    309 	aprint_verbose_dev(self, "mem 0x%08x-0x%08x, prefetchable mem "
    310 	    "0x%08x-0x%08x\n",
    311 	    AMCC460EX_PCIX0_MEM_BASE,
    312 	    AMCC460EX_PCIX0_MEM_BASE + AMCC460EX_PCIX0_MEM_SIZE - 1,
    313 	    AMCC460EX_PCIX0_PMEM_BASE,
    314 	    AMCC460EX_PCIX0_PMEM_BASE + AMCC460EX_PCIX0_PMEM_MAP - 1);
    315 
    316 	pci_configure_bus(pc, pcires, 0, 32);
    317 	pciconf_resource_fini(pcires);
    318 #endif
    319 
    320 	pba.pba_iot = &pcix_io_tag;
    321 	pba.pba_memt = &pcix_mem_tag;
    322 	pba.pba_dmat = paa->plb_dmat;
    323 	pba.pba_dmat64 = NULL;
    324 	pba.pba_pc = pc;
    325 	pba.pba_bus = 0;
    326 	pba.pba_bridgetag = NULL;
    327 	pba.pba_flags = PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY;
    328 	config_found(self, &pba, pcix_print, CFARGS_NONE);
    329 }
    330 
    331 static int
    332 pcix_print(void *aux, const char *p)
    333 {
    334 
    335 	if (p == NULL)
    336 		return UNCONF;
    337 	return QUIET;
    338 }
    339