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