Home | History | Annotate | Line # | Download | only in pci
pcix.c revision 1.2
      1 /*	$NetBSD: pcix.c,v 1.2 2026/06/17 15:08:54 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.2 2026/06/17 15:08:54 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	PCIC_CFGADDR	0
     83 #define	PCIC_CFGDATA	4
     84 
     85 static int	pcix_match(device_t, cfdata_t, void *);
     86 static void	pcix_attach(device_t, device_t, void *);
     87 static int	pcix_print(void *, const char *);
     88 
     89 CFATTACH_DECL_NEW(pcix, 0, pcix_match, pcix_attach, NULL, NULL);
     90 
     91 static pcireg_t	pcix_conf_read(void *, pcitag_t, int);
     92 static void	pcix_conf_write(void *, pcitag_t, int, pcireg_t);
     93 static void	pcix_attach_hook(device_t, device_t,
     94 		    struct pcibus_attach_args *);
     95 static int	pcix_conf_hook(void *, int, int, int, pcireg_t);
     96 
     97 /* CFGADDR/CFGDATA pair */
     98 static struct powerpc_bus_space pcix_cfg_tag = {
     99 	_BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE,
    100 	0x00000000,			/* offset */
    101 	AMCC460EX_PCIX0_CFG_PLBA,	/* extent base */
    102 	AMCC460EX_PCIX0_CFG_PLBA + 8,	/* extent limit */
    103 };
    104 
    105 /* Internal (window) registers */
    106 static struct powerpc_bus_space pcix_reg_tag = {
    107 	_BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE,
    108 	0x00000000,
    109 	AMCC460EX_PCIX0_REGS_PLBA,
    110 	AMCC460EX_PCIX0_REGS_PLBA + 0x100,
    111 };
    112 
    113 /* PCI I/O: bus 0x0000-0xffff -> PLB I/O window */
    114 static struct powerpc_bus_space pcix_io_tag = {
    115 	_BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_IO_TYPE,
    116 	AMCC460EX_PCIX0_IO_PLBA,	/* offset */
    117 	0x00000000,			/* extent base */
    118 	0x00010000,			/* extent limit */
    119 };
    120 
    121 /*
    122  * PCI memory: bus addr = low 32 bits of PLB addr.
    123  */
    124 static struct powerpc_bus_space pcix_mem_tag = {
    125 	_BUS_SPACE_LITTLE_ENDIAN | _BUS_SPACE_MEM_TYPE,
    126 	0x00000000,
    127 	AMCC460EX_PCIX0_MEM_BASE,
    128 	AMCC460EX_PCIX0_PMEM_BASE + AMCC460EX_PCIX0_PMEM_SIZE,
    129 };
    130 
    131 static bus_space_handle_t pcix_cfg_ioh;
    132 static bus_space_handle_t pcix_reg_ioh;
    133 
    134 static struct genppc_pci_chipset pcix_chipset = {
    135 	.pc_conf_v =		NULL,
    136 	.pc_attach_hook =	pcix_attach_hook,
    137 	.pc_bus_maxdevs =	ibm4xx_pci_bus_maxdevs,
    138 	.pc_make_tag =		ibm4xx_pci_make_tag,
    139 	.pc_conf_read =		pcix_conf_read,
    140 	.pc_conf_write =	pcix_conf_write,
    141 
    142 	.pc_intr_v =		&pcix_chipset,
    143 	.pc_intr_map =		genppc_pci_intr_map,
    144 	.pc_intr_string =	genppc_pci_intr_string,
    145 	.pc_intr_evcnt =	genppc_pci_intr_evcnt,
    146 	.pc_intr_establish =	genppc_pci_intr_establish,
    147 	.pc_intr_disestablish =	genppc_pci_intr_disestablish,
    148 	.pc_intr_setattr =	ibm4xx_pci_intr_setattr,
    149 	.pc_intr_type =		genppc_pci_intr_type,
    150 	.pc_intr_alloc =	genppc_pci_intr_alloc,
    151 	.pc_intr_release =	genppc_pci_intr_release,
    152 	.pc_intx_alloc =	genppc_pci_intx_alloc,
    153 
    154 	.pc_msi_v =		&pcix_chipset,
    155 	GENPPC_PCI_MSI_INITIALIZER,
    156 
    157 	.pc_msix_v =		&pcix_chipset,
    158 	GENPPC_PCI_MSIX_INITIALIZER,
    159 
    160 	.pc_conf_interrupt =	ibm4xx_pci_conf_interrupt,
    161 	.pc_decompose_tag =	ibm4xx_pci_decompose_tag,
    162 	.pc_conf_hook =		pcix_conf_hook,
    163 };
    164 
    165 static void
    166 pcix_attach_hook(device_t parent, device_t self,
    167     struct pcibus_attach_args *pba)
    168 {
    169 }
    170 
    171 static int
    172 pcix_conf_hook(void *v, int bus, int dev, int func, pcireg_t id)
    173 {
    174 
    175 	return PCI_CONF_DEFAULT;
    176 }
    177 
    178 /*
    179  * Translate the tag
    180  */
    181 static uint32_t
    182 pcix_cfg_addr(pcitag_t tag, int reg)
    183 {
    184 	uint32_t addr = (tag & 0x00ffff00) | (reg & 0xfc);
    185 
    186 	if (tag & 0x00ff0000)		/* bus number != 0 -> Type 1 */
    187 		addr |= 1;
    188 	return addr;
    189 }
    190 
    191 static pcireg_t
    192 pcix_conf_read(void *v, pcitag_t tag, int reg)
    193 {
    194 	pcireg_t data;
    195 
    196 	if ((unsigned int)reg >= PCI_CONF_SIZE)
    197 		return (pcireg_t) -1;
    198 
    199 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR,
    200 	    pcix_cfg_addr(tag, reg));
    201 	data = bus_space_read_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGDATA);
    202 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR, 0);
    203 	return data;
    204 }
    205 
    206 static void
    207 pcix_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
    208 {
    209 
    210 	if ((unsigned int)reg >= PCI_CONF_SIZE)
    211 		return;
    212 
    213 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR,
    214 	    pcix_cfg_addr(tag, reg));
    215 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGDATA, data);
    216 	bus_space_write_4(&pcix_cfg_tag, pcix_cfg_ioh, PCIC_CFGADDR, 0);
    217 }
    218 
    219 #define	PCIX_REG_WRITE(reg, val) \
    220 	bus_space_write_4(&pcix_reg_tag, pcix_reg_ioh, (reg), (val))
    221 
    222 static void
    223 pcix_setup_windows(void)
    224 {
    225 
    226 	/* POM0: PLB -> PCI memory, 128MB */
    227 	PCIX_REG_WRITE(PCIX0_POM0SA, 0);		/* disable while */
    228 	PCIX_REG_WRITE(PCIX0_POM0LAL, AMCC460EX_PCIX0_MEM_BASE);
    229 	PCIX_REG_WRITE(PCIX0_POM0LAH, AMCC460EX_PCIX0_MEM_PLBA_H);
    230 	PCIX_REG_WRITE(PCIX0_POM0PCIAL, AMCC460EX_PCIX0_MEM_BASE);
    231 	PCIX_REG_WRITE(PCIX0_POM0PCIAH, 0);
    232 	PCIX_REG_WRITE(PCIX0_POM0SA, ~(0x08000000 - 1) | 1);
    233 
    234 	/* POM1: PLB -> PCI prefetchable memory, identity mapped, 256MB */
    235 	PCIX_REG_WRITE(PCIX0_POM1SA, 0);		/* disable while */
    236 	PCIX_REG_WRITE(PCIX0_POM1LAL, AMCC460EX_PCIX0_PMEM_BASE);
    237 	PCIX_REG_WRITE(PCIX0_POM1LAH, AMCC460EX_PCIX0_PMEM_PLBA_H);
    238 	PCIX_REG_WRITE(PCIX0_POM1PCIAL, AMCC460EX_PCIX0_PMEM_BASE);
    239 	PCIX_REG_WRITE(PCIX0_POM1PCIAH, 0);
    240 	PCIX_REG_WRITE(PCIX0_POM1SA, ~(AMCC460EX_PCIX0_PMEM_SIZE - 1) | 1);
    241 
    242 	/* POM2 unused */
    243 	PCIX_REG_WRITE(PCIX0_POM2SA, 0);
    244 
    245 	/* PIM0: PCI 0 -> PLB 0, 2GB (covers all of RAM) */
    246 	PCIX_REG_WRITE(PCIX0_PIM0SAL, 0);		/* disable while */
    247 	PCIX_REG_WRITE(PCIX0_PIM0LAL, 0);
    248 	PCIX_REG_WRITE(PCIX0_PIM0LAH, 0);
    249 	PCIX_REG_WRITE(PCIX0_PIM0SAH, 0xffffffff);
    250 	PCIX_REG_WRITE(PCIX0_PIM0SAL, ~(0x80000000U - 1) | 1);
    251 
    252 	/* PIM1/PIM2 unused */
    253 	PCIX_REG_WRITE(PCIX0_PIM1SA, 0);
    254 	PCIX_REG_WRITE(PCIX0_PIM2SAL, 0);
    255 }
    256 
    257 static int
    258 pcix_match(device_t parent, cfdata_t cf, void *aux)
    259 {
    260 	struct plb_attach_args *paa = aux;
    261 
    262 	if (strcmp(paa->plb_name, cf->cf_name) != 0)
    263 		return 0;
    264 
    265 	return 1;
    266 }
    267 
    268 static void
    269 pcix_attach(device_t parent, device_t self, void *aux)
    270 {
    271 	struct plb_attach_args *paa = aux;
    272 	struct pcibus_attach_args pba;
    273 	pci_chipset_tag_t pc = &pcix_chipset;
    274 
    275 	aprint_normal(": PLB-PCIX host bridge\n");
    276 
    277 	if (bus_space_init(&pcix_cfg_tag, "pcixcfg", NULL, 0) ||
    278 	    bus_space_map(&pcix_cfg_tag, AMCC460EX_PCIX0_CFG_PLBA, 8, 0,
    279 	      &pcix_cfg_ioh))
    280 		panic("pcix_attach: can't map config registers");
    281 	if (bus_space_init(&pcix_reg_tag, "pcixreg", NULL, 0) ||
    282 	    bus_space_map(&pcix_reg_tag, AMCC460EX_PCIX0_REGS_PLBA, 0x100, 0,
    283 	      &pcix_reg_ioh))
    284 		panic("pcix_attach: can't map bridge registers");
    285 	if (bus_space_init(&pcix_io_tag, "pcixio", NULL, 0))
    286 		panic("pcix_attach: can't init IO tag");
    287 	if (bus_space_init(&pcix_mem_tag, "pcixmem", NULL, 0))
    288 		panic("pcix_attach: can't init MEM tag");
    289 
    290 	pcix_setup_windows();
    291 
    292 #ifdef PCI_NETBSD_CONFIGURE
    293 	struct pciconf_resources *pcires = pciconf_resource_init();
    294 
    295 	pciconf_resource_add(pcires, PCICONF_RESOURCE_IO,
    296 	    0x1000, 0x10000 - 0x1000);
    297 	pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM,
    298 	    AMCC460EX_PCIX0_MEM_BASE, AMCC460EX_PCIX0_MEM_SIZE);
    299 	pciconf_resource_add(pcires, PCICONF_RESOURCE_PREFETCHABLE_MEM,
    300 	    AMCC460EX_PCIX0_PMEM_BASE, AMCC460EX_PCIX0_PMEM_SIZE);
    301 
    302 	pci_configure_bus(pc, pcires, 0, 32);
    303 	pciconf_resource_fini(pcires);
    304 #endif
    305 
    306 	pba.pba_iot = &pcix_io_tag;
    307 	pba.pba_memt = &pcix_mem_tag;
    308 	pba.pba_dmat = paa->plb_dmat;
    309 	pba.pba_dmat64 = NULL;
    310 	pba.pba_pc = pc;
    311 	pba.pba_bus = 0;
    312 	pba.pba_bridgetag = NULL;
    313 	pba.pba_flags = PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY;
    314 	config_found(self, &pba, pcix_print, CFARGS_NONE);
    315 }
    316 
    317 static int
    318 pcix_print(void *aux, const char *p)
    319 {
    320 
    321 	if (p == NULL)
    322 		return UNCONF;
    323 	return QUIET;
    324 }
    325