pccbb.c revision 1.155
11.155Sjmcneill/*	$NetBSD: pccbb.c,v 1.155 2007/12/01 05:41:53 jmcneill Exp $	*/
21.2Shaya
31.1Shaya/*
41.21Shaya * Copyright (c) 1998, 1999 and 2000
51.21Shaya *      HAYAKAWA Koichi.  All rights reserved.
61.1Shaya *
71.1Shaya * Redistribution and use in source and binary forms, with or without
81.1Shaya * modification, are permitted provided that the following conditions
91.1Shaya * are met:
101.1Shaya * 1. Redistributions of source code must retain the above copyright
111.1Shaya *    notice, this list of conditions and the following disclaimer.
121.1Shaya * 2. Redistributions in binary form must reproduce the above copyright
131.1Shaya *    notice, this list of conditions and the following disclaimer in the
141.1Shaya *    documentation and/or other materials provided with the distribution.
151.1Shaya * 3. All advertising materials mentioning features or use of this software
161.1Shaya *    must display the following acknowledgement:
171.1Shaya *	This product includes software developed by HAYAKAWA Koichi.
181.1Shaya * 4. The name of the author may not be used to endorse or promote products
191.1Shaya *    derived from this software without specific prior written permission.
201.1Shaya *
211.1Shaya * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
221.1Shaya * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
231.1Shaya * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
241.1Shaya * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
251.1Shaya * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
261.1Shaya * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
271.1Shaya * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
281.1Shaya * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
291.1Shaya * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
301.1Shaya * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
311.1Shaya */
321.71Slukem
331.71Slukem#include <sys/cdefs.h>
341.155Sjmcneill__KERNEL_RCSID(0, "$NetBSD: pccbb.c,v 1.155 2007/12/01 05:41:53 jmcneill Exp $");
351.1Shaya
361.1Shaya/*
371.1Shaya#define CBB_DEBUG
381.1Shaya#define SHOW_REGS
391.1Shaya*/
401.1Shaya
411.1Shaya/*
421.132Schristos * BROKEN!
431.132Schristos#define PCCBB_PCMCIA_POLL
441.1Shaya#define CB_PCMCIA_POLL
451.1Shaya#define CB_PCMCIA_POLL_ONLY
461.1Shaya#define LEVEL2
471.1Shaya*/
481.1Shaya
491.1Shaya#include <sys/param.h>
501.1Shaya#include <sys/systm.h>
511.1Shaya#include <sys/kernel.h>
521.1Shaya#include <sys/errno.h>
531.1Shaya#include <sys/ioctl.h>
541.54Saugustss#include <sys/reboot.h>		/* for bootverbose */
551.1Shaya#include <sys/syslog.h>
561.1Shaya#include <sys/device.h>
571.1Shaya#include <sys/malloc.h>
581.55Shaya#include <sys/proc.h>
591.1Shaya
601.148Sad#include <sys/intr.h>
611.148Sad#include <sys/bus.h>
621.1Shaya
631.1Shaya#include <dev/pci/pcivar.h>
641.1Shaya#include <dev/pci/pcireg.h>
651.1Shaya#include <dev/pci/pcidevs.h>
661.1Shaya
671.1Shaya#include <dev/pci/pccbbreg.h>
681.1Shaya
691.1Shaya#include <dev/cardbus/cardslotvar.h>
701.1Shaya
711.1Shaya#include <dev/cardbus/cardbusvar.h>
721.1Shaya
731.1Shaya#include <dev/pcmcia/pcmciareg.h>
741.1Shaya#include <dev/pcmcia/pcmciavar.h>
751.1Shaya
761.1Shaya#include <dev/ic/i82365reg.h>
771.1Shaya#include <dev/ic/i82365var.h>
781.1Shaya#include <dev/pci/pccbbvar.h>
791.1Shaya
801.1Shaya#include "locators.h"
811.1Shaya
821.1Shaya#ifndef __NetBSD_Version__
831.1Shayastruct cfdriver cbb_cd = {
841.22Schopps	NULL, "cbb", DV_DULL
851.1Shaya};
861.1Shaya#endif
871.1Shaya
881.73Schristos#ifdef CBB_DEBUG
891.1Shaya#define DPRINTF(x) printf x
901.1Shaya#define STATIC
911.1Shaya#else
921.1Shaya#define DPRINTF(x)
931.1Shaya#define STATIC static
941.1Shaya#endif
951.1Shaya
961.151Sdyoungint pccbb_burstup = 1;
971.151Sdyoung
981.55Shaya/*
991.142Sdyoung * delay_ms() is wait in milliseconds.  It should be used instead
1001.140Sdyoung * of delay() if you want to wait more than 1 ms.
1011.55Shaya */
1021.142Sdyoungstatic inline void
1031.142Sdyoungdelay_ms(int millis, void *param)
1041.142Sdyoung{
1051.142Sdyoung	if (cold)
1061.142Sdyoung		delay(millis * 1000);
1071.142Sdyoung	else
1081.142Sdyoung		tsleep(param, PWAIT, "pccbb", MAX(2, hz * millis / 1000));
1091.142Sdyoung}
1101.55Shaya
1111.116Sperryint pcicbbmatch(struct device *, struct cfdata *, void *);
1121.116Sperryvoid pccbbattach(struct device *, struct device *, void *);
1131.116Sperryint pccbbintr(void *);
1141.116Sperrystatic void pci113x_insert(void *);
1151.116Sperrystatic int pccbbintr_function(struct pccbb_softc *);
1161.1Shaya
1171.116Sperrystatic int pccbb_detect_card(struct pccbb_softc *);
1181.1Shaya
1191.116Sperrystatic void pccbb_pcmcia_write(struct pcic_handle *, int, u_int8_t);
1201.116Sperrystatic u_int8_t pccbb_pcmcia_read(struct pcic_handle *, int);
1211.1Shaya#define Pcic_read(ph, reg) ((ph)->ph_read((ph), (reg)))
1221.1Shaya#define Pcic_write(ph, reg, val) ((ph)->ph_write((ph), (reg), (val)))
1231.1Shaya
1241.116SperrySTATIC int cb_reset(struct pccbb_softc *);
1251.116SperrySTATIC int cb_detect_voltage(struct pccbb_softc *);
1261.116SperrySTATIC int cbbprint(void *, const char *);
1271.116Sperry
1281.116Sperrystatic int cb_chipset(u_int32_t, int *);
1291.116SperrySTATIC void pccbb_pcmcia_attach_setup(struct pccbb_softc *,
1301.116Sperry    struct pcmciabus_attach_args *);
1311.1Shaya#if 0
1321.116SperrySTATIC void pccbb_pcmcia_attach_card(struct pcic_handle *);
1331.116SperrySTATIC void pccbb_pcmcia_detach_card(struct pcic_handle *, int);
1341.116SperrySTATIC void pccbb_pcmcia_deactivate_card(struct pcic_handle *);
1351.1Shaya#endif
1361.1Shaya
1371.116SperrySTATIC int pccbb_ctrl(cardbus_chipset_tag_t, int);
1381.116SperrySTATIC int pccbb_power(cardbus_chipset_tag_t, int);
1391.116SperrySTATIC int pccbb_cardenable(struct pccbb_softc * sc, int function);
1401.1Shaya#if !rbus
1411.116Sperrystatic int pccbb_io_open(cardbus_chipset_tag_t, int, u_int32_t, u_int32_t);
1421.116Sperrystatic int pccbb_io_close(cardbus_chipset_tag_t, int);
1431.116Sperrystatic int pccbb_mem_open(cardbus_chipset_tag_t, int, u_int32_t, u_int32_t);
1441.116Sperrystatic int pccbb_mem_close(cardbus_chipset_tag_t, int);
1451.1Shaya#endif /* !rbus */
1461.116Sperrystatic void *pccbb_intr_establish(struct pccbb_softc *, int irq,
1471.116Sperry    int level, int (*ih) (void *), void *sc);
1481.116Sperrystatic void pccbb_intr_disestablish(struct pccbb_softc *, void *ih);
1491.116Sperry
1501.116Sperrystatic void *pccbb_cb_intr_establish(cardbus_chipset_tag_t, int irq,
1511.116Sperry    int level, int (*ih) (void *), void *sc);
1521.116Sperrystatic void pccbb_cb_intr_disestablish(cardbus_chipset_tag_t ct, void *ih);
1531.116Sperry
1541.125Sdrochnerstatic cardbustag_t pccbb_make_tag(cardbus_chipset_tag_t, int, int);
1551.116Sperrystatic void pccbb_free_tag(cardbus_chipset_tag_t, cardbustag_t);
1561.116Sperrystatic cardbusreg_t pccbb_conf_read(cardbus_chipset_tag_t, cardbustag_t, int);
1571.116Sperrystatic void pccbb_conf_write(cardbus_chipset_tag_t, cardbustag_t, int,
1581.116Sperry    cardbusreg_t);
1591.116Sperrystatic void pccbb_chipinit(struct pccbb_softc *);
1601.116Sperry
1611.116SperrySTATIC int pccbb_pcmcia_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
1621.116Sperry    struct pcmcia_mem_handle *);
1631.116SperrySTATIC void pccbb_pcmcia_mem_free(pcmcia_chipset_handle_t,
1641.116Sperry    struct pcmcia_mem_handle *);
1651.116SperrySTATIC int pccbb_pcmcia_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
1661.116Sperry    bus_size_t, struct pcmcia_mem_handle *, bus_addr_t *, int *);
1671.116SperrySTATIC void pccbb_pcmcia_mem_unmap(pcmcia_chipset_handle_t, int);
1681.116SperrySTATIC int pccbb_pcmcia_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
1691.116Sperry    bus_size_t, bus_size_t, struct pcmcia_io_handle *);
1701.116SperrySTATIC void pccbb_pcmcia_io_free(pcmcia_chipset_handle_t,
1711.116Sperry    struct pcmcia_io_handle *);
1721.116SperrySTATIC int pccbb_pcmcia_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
1731.116Sperry    bus_size_t, struct pcmcia_io_handle *, int *);
1741.116SperrySTATIC void pccbb_pcmcia_io_unmap(pcmcia_chipset_handle_t, int);
1751.116SperrySTATIC void *pccbb_pcmcia_intr_establish(pcmcia_chipset_handle_t,
1761.116Sperry    struct pcmcia_function *, int, int (*)(void *), void *);
1771.116SperrySTATIC void pccbb_pcmcia_intr_disestablish(pcmcia_chipset_handle_t, void *);
1781.116SperrySTATIC void pccbb_pcmcia_socket_enable(pcmcia_chipset_handle_t);
1791.116SperrySTATIC void pccbb_pcmcia_socket_disable(pcmcia_chipset_handle_t);
1801.116SperrySTATIC void pccbb_pcmcia_socket_settype(pcmcia_chipset_handle_t, int);
1811.116SperrySTATIC int pccbb_pcmcia_card_detect(pcmcia_chipset_handle_t pch);
1821.116Sperry
1831.116Sperrystatic int pccbb_pcmcia_wait_ready(struct pcic_handle *);
1841.116Sperrystatic void pccbb_pcmcia_delay(struct pcic_handle *, int, const char *);
1851.116Sperry
1861.116Sperrystatic void pccbb_pcmcia_do_io_map(struct pcic_handle *, int);
1871.116Sperrystatic void pccbb_pcmcia_do_mem_map(struct pcic_handle *, int);
1881.116Sperrystatic void pccbb_powerhook(int, void *);
1891.1Shaya
1901.32Senami/* bus-space allocation and deallocation functions */
1911.1Shaya#if rbus
1921.1Shaya
1931.116Sperrystatic int pccbb_rbus_cb_space_alloc(cardbus_chipset_tag_t, rbus_tag_t,
1941.22Schopps    bus_addr_t addr, bus_size_t size, bus_addr_t mask, bus_size_t align,
1951.116Sperry    int flags, bus_addr_t * addrp, bus_space_handle_t * bshp);
1961.116Sperrystatic int pccbb_rbus_cb_space_free(cardbus_chipset_tag_t, rbus_tag_t,
1971.116Sperry    bus_space_handle_t, bus_size_t);
1981.1Shaya
1991.1Shaya#endif /* rbus */
2001.1Shaya
2011.1Shaya#if rbus
2021.1Shaya
2031.116Sperrystatic int pccbb_open_win(struct pccbb_softc *, bus_space_tag_t,
2041.116Sperry    bus_addr_t, bus_size_t, bus_space_handle_t, int flags);
2051.116Sperrystatic int pccbb_close_win(struct pccbb_softc *, bus_space_tag_t,
2061.116Sperry    bus_space_handle_t, bus_size_t);
2071.116Sperrystatic int pccbb_winlist_insert(struct pccbb_win_chain_head *, bus_addr_t,
2081.116Sperry    bus_size_t, bus_space_handle_t, int);
2091.116Sperrystatic int pccbb_winlist_delete(struct pccbb_win_chain_head *,
2101.116Sperry    bus_space_handle_t, bus_size_t);
2111.116Sperrystatic void pccbb_winset(bus_addr_t align, struct pccbb_softc *,
2121.116Sperry    bus_space_tag_t);
2131.1Shayavoid pccbb_winlist_show(struct pccbb_win_chain *);
2141.1Shaya
2151.1Shaya#endif /* rbus */
2161.1Shaya
2171.1Shaya/* for config_defer */
2181.116Sperrystatic void pccbb_pci_callback(struct device *);
2191.1Shaya
2201.1Shaya#if defined SHOW_REGS
2211.116Sperrystatic void cb_show_regs(pci_chipset_tag_t pc, pcitag_t tag,
2221.116Sperry    bus_space_tag_t memt, bus_space_handle_t memh);
2231.1Shaya#endif
2241.1Shaya
2251.79SthorpejCFATTACH_DECL(cbb_pci, sizeof(struct pccbb_softc),
2261.82Sthorpej    pcicbbmatch, pccbbattach, NULL, NULL);
2271.1Shaya
2281.1Shayastatic struct pcmcia_chip_functions pccbb_pcmcia_funcs = {
2291.22Schopps	pccbb_pcmcia_mem_alloc,
2301.22Schopps	pccbb_pcmcia_mem_free,
2311.22Schopps	pccbb_pcmcia_mem_map,
2321.22Schopps	pccbb_pcmcia_mem_unmap,
2331.22Schopps	pccbb_pcmcia_io_alloc,
2341.22Schopps	pccbb_pcmcia_io_free,
2351.22Schopps	pccbb_pcmcia_io_map,
2361.22Schopps	pccbb_pcmcia_io_unmap,
2371.22Schopps	pccbb_pcmcia_intr_establish,
2381.22Schopps	pccbb_pcmcia_intr_disestablish,
2391.22Schopps	pccbb_pcmcia_socket_enable,
2401.22Schopps	pccbb_pcmcia_socket_disable,
2411.101Smycroft	pccbb_pcmcia_socket_settype,
2421.22Schopps	pccbb_pcmcia_card_detect
2431.1Shaya};
2441.1Shaya
2451.1Shaya#if rbus
2461.1Shayastatic struct cardbus_functions pccbb_funcs = {
2471.22Schopps	pccbb_rbus_cb_space_alloc,
2481.22Schopps	pccbb_rbus_cb_space_free,
2491.26Shaya	pccbb_cb_intr_establish,
2501.26Shaya	pccbb_cb_intr_disestablish,
2511.22Schopps	pccbb_ctrl,
2521.22Schopps	pccbb_power,
2531.22Schopps	pccbb_make_tag,
2541.22Schopps	pccbb_free_tag,
2551.22Schopps	pccbb_conf_read,
2561.22Schopps	pccbb_conf_write,
2571.1Shaya};
2581.1Shaya#else
2591.1Shayastatic struct cardbus_functions pccbb_funcs = {
2601.22Schopps	pccbb_ctrl,
2611.22Schopps	pccbb_power,
2621.22Schopps	pccbb_mem_open,
2631.22Schopps	pccbb_mem_close,
2641.22Schopps	pccbb_io_open,
2651.22Schopps	pccbb_io_close,
2661.26Shaya	pccbb_cb_intr_establish,
2671.26Shaya	pccbb_cb_intr_disestablish,
2681.22Schopps	pccbb_make_tag,
2691.22Schopps	pccbb_conf_read,
2701.22Schopps	pccbb_conf_write,
2711.1Shaya};
2721.1Shaya#endif
2731.1Shaya
2741.1Shayaint
2751.143Sdyoungpcicbbmatch(struct device *parent, struct cfdata *match, void *aux)
2761.1Shaya{
2771.22Schopps	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
2781.1Shaya
2791.22Schopps	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
2801.22Schopps	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_CARDBUS &&
2811.22Schopps	    PCI_INTERFACE(pa->pa_class) == 0) {
2821.22Schopps		return 1;
2831.22Schopps	}
2841.1Shaya
2851.22Schopps	return 0;
2861.1Shaya}
2871.1Shaya
2881.1Shaya#define MAKEID(vendor, prod) (((vendor) << PCI_VENDOR_SHIFT) \
2891.1Shaya                              | ((prod) << PCI_PRODUCT_SHIFT))
2901.1Shaya
2911.60Sjdolecekconst struct yenta_chipinfo {
2921.22Schopps	pcireg_t yc_id;		       /* vendor tag | product tag */
2931.22Schopps	int yc_chiptype;
2941.22Schopps	int yc_flags;
2951.1Shaya} yc_chipsets[] = {
2961.22Schopps	/* Texas Instruments chips */
2971.22Schopps	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1130), CB_TI113X,
2981.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
2991.22Schopps	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1131), CB_TI113X,
3001.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3011.96Snakayama	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1250), CB_TI125X,
3021.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3031.22Schopps	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1220), CB_TI12XX,
3041.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3051.22Schopps	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1221), CB_TI12XX,
3061.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3071.22Schopps	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1225), CB_TI12XX,
3081.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3091.96Snakayama	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1251), CB_TI125X,
3101.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3111.96Snakayama	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1251B), CB_TI125X,
3121.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3131.22Schopps	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1211), CB_TI12XX,
3141.64Ssoren	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3151.64Ssoren	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1410), CB_TI12XX,
3161.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3171.151Sdyoung	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1420), CB_TI1420,
3181.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3191.96Snakayama	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1450), CB_TI125X,
3201.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3211.22Schopps	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1451), CB_TI12XX,
3221.84Smartin	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3231.99She	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1520), CB_TI12XX,
3241.99She	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3251.84Smartin	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI4410YENTA), CB_TI12XX,
3261.22Schopps	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3271.99She	{ MAKEID(PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI4520YENTA), CB_TI12XX,
3281.99She	    PCCBB_PCMCIA_IO_RELOC | PCCBB_PCMCIA_MEM_32},
3291.22Schopps
3301.22Schopps	/* Ricoh chips */
3311.22Schopps	{ MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C475), CB_RX5C47X,
3321.22Schopps	    PCCBB_PCMCIA_MEM_32},
3331.22Schopps	{ MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RL5C476), CB_RX5C47X,
3341.22Schopps	    PCCBB_PCMCIA_MEM_32},
3351.22Schopps	{ MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C477), CB_RX5C47X,
3361.22Schopps	    PCCBB_PCMCIA_MEM_32},
3371.22Schopps	{ MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C478), CB_RX5C47X,
3381.22Schopps	    PCCBB_PCMCIA_MEM_32},
3391.22Schopps	{ MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C465), CB_RX5C46X,
3401.22Schopps	    PCCBB_PCMCIA_MEM_32},
3411.22Schopps	{ MAKEID(PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C466), CB_RX5C46X,
3421.22Schopps	    PCCBB_PCMCIA_MEM_32},
3431.22Schopps
3441.22Schopps	/* Toshiba products */
3451.22Schopps	{ MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95),
3461.22Schopps	    CB_TOPIC95, PCCBB_PCMCIA_MEM_32},
3471.22Schopps	{ MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95B),
3481.22Schopps	    CB_TOPIC95B, PCCBB_PCMCIA_MEM_32},
3491.22Schopps	{ MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC97),
3501.22Schopps	    CB_TOPIC97, PCCBB_PCMCIA_MEM_32},
3511.22Schopps	{ MAKEID(PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC100),
3521.22Schopps	    CB_TOPIC97, PCCBB_PCMCIA_MEM_32},
3531.22Schopps
3541.22Schopps	/* Cirrus Logic products */
3551.22Schopps	{ MAKEID(PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_PD6832),
3561.22Schopps	    CB_CIRRUS, PCCBB_PCMCIA_MEM_32},
3571.22Schopps	{ MAKEID(PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_PD6833),
3581.22Schopps	    CB_CIRRUS, PCCBB_PCMCIA_MEM_32},
3591.1Shaya
3601.22Schopps	/* sentinel, or Generic chip */
3611.22Schopps	{ 0 /* null id */ , CB_UNKNOWN, PCCBB_PCMCIA_MEM_32},
3621.1Shaya};
3631.1Shaya
3641.1Shayastatic int
3651.143Sdyoungcb_chipset(u_int32_t pci_id, int *flagp)
3661.1Shaya{
3671.60Sjdolecek	const struct yenta_chipinfo *yc;
3681.1Shaya
3691.35Senami	/* Loop over except the last default entry. */
3701.35Senami	for (yc = yc_chipsets; yc < yc_chipsets +
3711.35Senami	    sizeof(yc_chipsets) / sizeof(yc_chipsets[0]) - 1; yc++)
3721.39Skleink		if (pci_id == yc->yc_id)
3731.35Senami			break;
3741.1Shaya
3751.35Senami	if (flagp != NULL)
3761.35Senami		*flagp = yc->yc_flags;
3771.1Shaya
3781.35Senami	return (yc->yc_chiptype);
3791.1Shaya}
3801.1Shaya
3811.14Sjodastatic void
3821.14Sjodapccbb_shutdown(void *arg)
3831.14Sjoda{
3841.22Schopps	struct pccbb_softc *sc = arg;
3851.22Schopps	pcireg_t command;
3861.22Schopps
3871.22Schopps	DPRINTF(("%s: shutdown\n", sc->sc_dev.dv_xname));
3881.47Shaya
3891.49Shaya	/*
3901.49Shaya	 * turn off power
3911.49Shaya	 *
3921.49Shaya	 * XXX - do not turn off power if chipset is TI 113X because
3931.49Shaya	 * only TI 1130 with PowerMac 2400 hangs in pccbb_power().
3941.49Shaya	 */
3951.49Shaya	if (sc->sc_chipset != CB_TI113X) {
3961.49Shaya		pccbb_power((cardbus_chipset_tag_t)sc,
3971.49Shaya		    CARDBUS_VCC_0V | CARDBUS_VPP_0V);
3981.49Shaya	}
3991.47Shaya
4001.22Schopps	bus_space_write_4(sc->sc_base_memt, sc->sc_base_memh, CB_SOCKET_MASK,
4011.22Schopps	    0);
4021.22Schopps
4031.22Schopps	command = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
4041.22Schopps
4051.22Schopps	command &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
4061.22Schopps	    PCI_COMMAND_MASTER_ENABLE);
4071.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, command);
4081.1Shaya
4091.14Sjoda}
4101.1Shaya
4111.1Shayavoid
4121.137Schristospccbbattach(struct device *parent, struct device *self, void *aux)
4131.22Schopps{
4141.22Schopps	struct pccbb_softc *sc = (void *)self;
4151.22Schopps	struct pci_attach_args *pa = aux;
4161.22Schopps	pci_chipset_tag_t pc = pa->pa_pc;
4171.43Sjhawk	pcireg_t busreg, reg, sock_base;
4181.22Schopps	bus_addr_t sockbase;
4191.22Schopps	char devinfo[256];
4201.22Schopps	int flags;
4211.70Shaya	int pwrmgt_offs;
4221.22Schopps
4231.88Snakayama#ifdef __HAVE_PCCBB_ATTACH_HOOK
4241.88Snakayama	pccbb_attach_hook(parent, self, pa);
4251.88Snakayama#endif
4261.88Snakayama
4271.149Sjoerg	callout_init(&sc->sc_insert_ch, 0);
4281.149Sjoerg	callout_setfunc(&sc->sc_insert_ch, pci113x_insert, sc);
4291.149Sjoerg
4301.22Schopps	sc->sc_chipset = cb_chipset(pa->pa_id, &flags);
4311.22Schopps
4321.155Sjmcneill	aprint_naive("\n");
4331.155Sjmcneill
4341.97Sitojun	pci_devinfo(pa->pa_id, 0, 0, devinfo, sizeof(devinfo));
4351.155Sjmcneill	aprint_normal(": %s (rev. 0x%02x)", devinfo,
4361.155Sjmcneill	    PCI_REVISION(pa->pa_class));
4371.133Schristos	DPRINTF((" (chipflags %x)", flags));
4381.155Sjmcneill	aprint_normal("\n");
4391.1Shaya
4401.27Sthorpej	TAILQ_INIT(&sc->sc_memwindow);
4411.27Sthorpej	TAILQ_INIT(&sc->sc_iowindow);
4421.27Sthorpej
4431.1Shaya#if rbus
4441.22Schopps	sc->sc_rbus_iot = rbus_pccbb_parent_io(pa);
4451.22Schopps	sc->sc_rbus_memt = rbus_pccbb_parent_mem(pa);
4461.65Smcr
4471.65Smcr#if 0
4481.65Smcr	printf("pa->pa_memt: %08x vs rbus_mem->rb_bt: %08x\n",
4491.65Smcr	       pa->pa_memt, sc->sc_rbus_memt->rb_bt);
4501.65Smcr#endif
4511.1Shaya#endif /* rbus */
4521.1Shaya
4531.88Snakayama	sc->sc_flags &= ~CBB_MEMHMAPPED;
4541.1Shaya
4551.70Shaya	/* power management: set D0 state */
4561.70Shaya	sc->sc_pwrmgt_offs = 0;
4571.70Shaya	if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT,
4581.70Shaya	    &pwrmgt_offs, 0)) {
4591.85Stsutsui		reg = pci_conf_read(pc, pa->pa_tag, pwrmgt_offs + PCI_PMCSR);
4601.70Shaya		if ((reg & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_STATE_D0 ||
4611.70Shaya		    reg & 0x100 /* PCI_PMCSR_PME_EN */) {
4621.70Shaya			reg &= ~PCI_PMCSR_STATE_MASK;
4631.70Shaya			reg |= PCI_PMCSR_STATE_D0;
4641.70Shaya			reg &= ~(0x100 /* PCI_PMCSR_PME_EN */);
4651.85Stsutsui			pci_conf_write(pc, pa->pa_tag,
4661.85Stsutsui			    pwrmgt_offs + PCI_PMCSR, reg);
4671.70Shaya		}
4681.70Shaya
4691.70Shaya		sc->sc_pwrmgt_offs = pwrmgt_offs;
4701.70Shaya	}
4711.70Shaya
4721.117Sperry	/*
4731.22Schopps	 * MAP socket registers and ExCA registers on memory-space
4741.22Schopps	 * When no valid address is set on socket base registers (on pci
4751.22Schopps	 * config space), get it not polite way.
4761.22Schopps	 */
4771.22Schopps	sock_base = pci_conf_read(pc, pa->pa_tag, PCI_SOCKBASE);
4781.22Schopps
4791.22Schopps	if (PCI_MAPREG_MEM_ADDR(sock_base) >= 0x100000 &&
4801.22Schopps	    PCI_MAPREG_MEM_ADDR(sock_base) != 0xfffffff0) {
4811.22Schopps		/* The address must be valid. */
4821.22Schopps		if (pci_mapreg_map(pa, PCI_SOCKBASE, PCI_MAPREG_TYPE_MEM, 0,
4831.22Schopps		    &sc->sc_base_memt, &sc->sc_base_memh, &sockbase, NULL)) {
4841.155Sjmcneill			aprint_error("%s: can't map socket base address 0x%lx\n",
4851.94Schristos			    sc->sc_dev.dv_xname, (unsigned long)sock_base);
4861.22Schopps			/*
4871.22Schopps			 * I think it's funny: socket base registers must be
4881.22Schopps			 * mapped on memory space, but ...
4891.22Schopps			 */
4901.22Schopps			if (pci_mapreg_map(pa, PCI_SOCKBASE, PCI_MAPREG_TYPE_IO,
4911.22Schopps			    0, &sc->sc_base_memt, &sc->sc_base_memh, &sockbase,
4921.22Schopps			    NULL)) {
4931.155Sjmcneill				aprint_error("%s: can't map socket base address"
4941.22Schopps				    " 0x%lx: io mode\n", sc->sc_dev.dv_xname,
4951.63Sjmc				    (unsigned long)sockbase);
4961.22Schopps				/* give up... allocate reg space via rbus. */
4971.22Schopps				pci_conf_write(pc, pa->pa_tag, PCI_SOCKBASE, 0);
4981.88Snakayama			} else
4991.88Snakayama				sc->sc_flags |= CBB_MEMHMAPPED;
5001.22Schopps		} else {
5011.22Schopps			DPRINTF(("%s: socket base address 0x%lx\n",
5021.94Schristos			    sc->sc_dev.dv_xname, (unsigned long)sockbase));
5031.88Snakayama			sc->sc_flags |= CBB_MEMHMAPPED;
5041.22Schopps		}
5051.22Schopps	}
5061.1Shaya
5071.22Schopps	sc->sc_mem_start = 0;	       /* XXX */
5081.22Schopps	sc->sc_mem_end = 0xffffffff;   /* XXX */
5091.1Shaya
5101.22Schopps	busreg = pci_conf_read(pc, pa->pa_tag, PCI_BUSNUM);
5111.4Shaya
5121.22Schopps	/* pccbb_machdep.c end */
5131.1Shaya
5141.1Shaya#if defined CBB_DEBUG
5151.22Schopps	{
5161.121Ssekiya		static const char *intrname[] = { "NON", "A", "B", "C", "D" };
5171.23Scgd		printf("%s: intrpin %s, intrtag %d\n", sc->sc_dev.dv_xname,
5181.23Scgd		    intrname[pa->pa_intrpin], pa->pa_intrline);
5191.22Schopps	}
5201.1Shaya#endif
5211.1Shaya
5221.22Schopps	/* setup softc */
5231.22Schopps	sc->sc_pc = pc;
5241.22Schopps	sc->sc_iot = pa->pa_iot;
5251.22Schopps	sc->sc_memt = pa->pa_memt;
5261.22Schopps	sc->sc_dmat = pa->pa_dmat;
5271.22Schopps	sc->sc_tag = pa->pa_tag;
5281.22Schopps	sc->sc_function = pa->pa_function;
5291.58Sminoura	sc->sc_sockbase = sock_base;
5301.58Sminoura	sc->sc_busnum = busreg;
5311.22Schopps
5321.51Ssommerfe	memcpy(&sc->sc_pa, pa, sizeof(*pa));
5331.1Shaya
5341.22Schopps	sc->sc_pcmcia_flags = flags;   /* set PCMCIA facility */
5351.1Shaya
5361.22Schopps	shutdownhook_establish(pccbb_shutdown, sc);
5371.4Shaya
5381.43Sjhawk	/* Disable legacy register mapping. */
5391.43Sjhawk	switch (sc->sc_chipset) {
5401.43Sjhawk	case CB_RX5C46X:	       /* fallthrough */
5411.43Sjhawk#if 0
5421.44Sjhawk	/* The RX5C47X-series requires writes to the PCI_LEGACY register. */
5431.43Sjhawk	case CB_RX5C47X:
5441.43Sjhawk#endif
5451.117Sperry		/*
5461.44Sjhawk		 * The legacy pcic io-port on Ricoh RX5C46X CardBus bridges
5471.44Sjhawk		 * cannot be disabled by substituting 0 into PCI_LEGACY
5481.44Sjhawk		 * register.  Ricoh CardBus bridges have special bits on Bridge
5491.44Sjhawk		 * control reg (addr 0x3e on PCI config space).
5501.43Sjhawk		 */
5511.146Sdyoung		reg = pci_conf_read(pc, pa->pa_tag, PCI_BRIDGE_CONTROL_REG);
5521.43Sjhawk		reg &= ~(CB_BCRI_RL_3E0_ENA | CB_BCRI_RL_3E2_ENA);
5531.146Sdyoung		pci_conf_write(pc, pa->pa_tag, PCI_BRIDGE_CONTROL_REG, reg);
5541.43Sjhawk		break;
5551.43Sjhawk
5561.43Sjhawk	default:
5571.43Sjhawk		/* XXX I don't know proper way to kill legacy I/O. */
5581.43Sjhawk		pci_conf_write(pc, pa->pa_tag, PCI_LEGACY, 0x0);
5591.43Sjhawk		break;
5601.43Sjhawk	}
5611.43Sjhawk
5621.22Schopps	config_defer(self, pccbb_pci_callback);
5631.1Shaya}
5641.1Shaya
5651.26Shaya
5661.26Shaya
5671.26Shaya
5681.26Shaya/*
5691.26Shaya * static void pccbb_pci_callback(struct device *self)
5701.26Shaya *
5711.26Shaya *   The actual attach routine: get memory space for YENTA register
5721.26Shaya *   space, setup YENTA register and route interrupt.
5731.26Shaya *
5741.26Shaya *   This function should be deferred because this device may obtain
5751.26Shaya *   memory space dynamically.  This function must avoid obtaining
5761.43Sjhawk *   memory area which has already kept for another device.
5771.26Shaya */
5781.1Shayastatic void
5791.143Sdyoungpccbb_pci_callback(struct device *self)
5801.1Shaya{
5811.22Schopps	struct pccbb_softc *sc = (void *)self;
5821.22Schopps	pci_chipset_tag_t pc = sc->sc_pc;
5831.22Schopps	pci_intr_handle_t ih;
5841.22Schopps	const char *intrstr = NULL;
5851.22Schopps	bus_addr_t sockbase;
5861.22Schopps	struct cbslot_attach_args cba;
5871.22Schopps	struct pcmciabus_attach_args paa;
5881.22Schopps	struct cardslot_attach_args caa;
5891.22Schopps	struct cardslot_softc *csc;
5901.1Shaya
5911.88Snakayama	if (!(sc->sc_flags & CBB_MEMHMAPPED)) {
5921.22Schopps		/* The socket registers aren't mapped correctly. */
5931.1Shaya#if rbus
5941.22Schopps		if (rbus_space_alloc(sc->sc_rbus_memt, 0, 0x1000, 0x0fff,
5951.22Schopps		    (sc->sc_chipset == CB_RX5C47X
5961.22Schopps		    || sc->sc_chipset == CB_TI113X) ? 0x10000 : 0x1000,
5971.22Schopps		    0, &sockbase, &sc->sc_base_memh)) {
5981.22Schopps			return;
5991.22Schopps		}
6001.22Schopps		sc->sc_base_memt = sc->sc_memt;
6011.22Schopps		pci_conf_write(pc, sc->sc_tag, PCI_SOCKBASE, sockbase);
6021.120Ssekiya		DPRINTF(("%s: CardBus register address 0x%lx -> 0x%lx\n",
6031.94Schristos		    sc->sc_dev.dv_xname, (unsigned long)sockbase,
6041.94Schristos		    (unsigned long)pci_conf_read(pc, sc->sc_tag,
6051.22Schopps		    PCI_SOCKBASE)));
6061.1Shaya#else
6071.22Schopps		sc->sc_base_memt = sc->sc_memt;
6081.1Shaya#if !defined CBB_PCI_BASE
6091.1Shaya#define CBB_PCI_BASE 0x20000000
6101.1Shaya#endif
6111.22Schopps		if (bus_space_alloc(sc->sc_base_memt, CBB_PCI_BASE, 0xffffffff,
6121.22Schopps		    0x1000, 0x1000, 0, 0, &sockbase, &sc->sc_base_memh)) {
6131.22Schopps			/* cannot allocate memory space */
6141.22Schopps			return;
6151.22Schopps		}
6161.22Schopps		pci_conf_write(pc, sc->sc_tag, PCI_SOCKBASE, sockbase);
6171.120Ssekiya		DPRINTF(("%s: CardBus register address 0x%lx -> 0x%lx\n",
6181.94Schristos		    sc->sc_dev.dv_xname, (unsigned long)sock_base,
6191.94Schristos		    (unsigned long)pci_conf_read(pc,
6201.22Schopps		    sc->sc_tag, PCI_SOCKBASE)));
6211.69Shaya		sc->sc_sockbase = sockbase;
6221.1Shaya#endif
6231.88Snakayama		sc->sc_flags |= CBB_MEMHMAPPED;
6241.22Schopps	}
6251.19Shaya
6261.32Senami	/* bus bridge initialization */
6271.22Schopps	pccbb_chipinit(sc);
6281.1Shaya
6291.38Shaya	/* clear data structure for child device interrupt handlers */
6301.80Shaya	LIST_INIT(&sc->sc_pil);
6311.38Shaya	sc->sc_pil_intr_enable = 1;
6321.38Shaya
6331.22Schopps	/* Map and establish the interrupt. */
6341.51Ssommerfe	if (pci_intr_map(&sc->sc_pa, &ih)) {
6351.155Sjmcneill		aprint_error("%s: couldn't map interrupt\n",
6361.155Sjmcneill		    sc->sc_dev.dv_xname);
6371.22Schopps		return;
6381.22Schopps	}
6391.22Schopps	intrstr = pci_intr_string(pc, ih);
6401.41Shaya
6411.41Shaya	/*
6421.41Shaya	 * XXX pccbbintr should be called under the priority lower
6431.118Schristos	 * than any other hard interupts.
6441.41Shaya	 */
6451.22Schopps	sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, pccbbintr, sc);
6461.1Shaya
6471.22Schopps	if (sc->sc_ih == NULL) {
6481.155Sjmcneill		aprint_error("%s: couldn't establish interrupt",
6491.155Sjmcneill		    sc->sc_dev.dv_xname);
6501.22Schopps		if (intrstr != NULL) {
6511.155Sjmcneill			aprint_normal(" at %s", intrstr);
6521.22Schopps		}
6531.155Sjmcneill		aprint_normal("\n");
6541.22Schopps		return;
6551.22Schopps	}
6561.1Shaya
6571.155Sjmcneill	aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
6581.134Sjmcneill	powerhook_establish(sc->sc_dev.dv_xname, pccbb_powerhook, sc);
6591.1Shaya
6601.22Schopps	{
6611.69Shaya		u_int32_t sockstat;
6621.69Shaya
6631.69Shaya		sockstat = bus_space_read_4(sc->sc_base_memt,
6641.69Shaya		    sc->sc_base_memh, CB_SOCKET_STAT);
6651.22Schopps		if (0 == (sockstat & CB_SOCKET_STAT_CD)) {
6661.22Schopps			sc->sc_flags |= CBB_CARDEXIST;
6671.22Schopps		}
6681.22Schopps	}
6691.1Shaya
6701.117Sperry	/*
6711.117Sperry	 * attach cardbus
6721.22Schopps	 */
6731.98Smycroft	{
6741.22Schopps		pcireg_t busreg = pci_conf_read(pc, sc->sc_tag, PCI_BUSNUM);
6751.22Schopps		pcireg_t bhlc = pci_conf_read(pc, sc->sc_tag, PCI_BHLC_REG);
6761.22Schopps
6771.32Senami		/* initialize cbslot_attach */
6781.22Schopps		cba.cba_busname = "cardbus";
6791.22Schopps		cba.cba_iot = sc->sc_iot;
6801.22Schopps		cba.cba_memt = sc->sc_memt;
6811.22Schopps		cba.cba_dmat = sc->sc_dmat;
6821.22Schopps		cba.cba_bus = (busreg >> 8) & 0x0ff;
6831.22Schopps		cba.cba_cc = (void *)sc;
6841.22Schopps		cba.cba_cf = &pccbb_funcs;
6851.51Ssommerfe		cba.cba_intrline = sc->sc_pa.pa_intrline;
6861.1Shaya
6871.1Shaya#if rbus
6881.22Schopps		cba.cba_rbus_iot = sc->sc_rbus_iot;
6891.22Schopps		cba.cba_rbus_memt = sc->sc_rbus_memt;
6901.1Shaya#endif
6911.1Shaya
6921.22Schopps		cba.cba_cacheline = PCI_CACHELINE(bhlc);
6931.151Sdyoung		cba.cba_max_lattimer = PCI_LATTIMER(bhlc);
6941.1Shaya
6951.52Saugustss		if (bootverbose) {
6961.52Saugustss			printf("%s: cacheline 0x%x lattimer 0x%x\n",
6971.52Saugustss			    sc->sc_dev.dv_xname, cba.cba_cacheline,
6981.151Sdyoung			    cba.cba_max_lattimer);
6991.147Sdyoung			printf("%s: bhlc 0x%x\n",
7001.147Sdyoung			    device_xname(&sc->sc_dev), bhlc);
7011.52Saugustss		}
7021.1Shaya#if defined SHOW_REGS
7031.22Schopps		cb_show_regs(sc->sc_pc, sc->sc_tag, sc->sc_base_memt,
7041.22Schopps		    sc->sc_base_memh);
7051.1Shaya#endif
7061.22Schopps	}
7071.1Shaya
7081.22Schopps	pccbb_pcmcia_attach_setup(sc, &paa);
7091.22Schopps	caa.caa_cb_attach = NULL;
7101.98Smycroft	if (cba.cba_bus == 0)
7111.124Swiz		printf("%s: secondary bus number uninitialized; try PCI_BUS_FIXUP\n", sc->sc_dev.dv_xname);
7121.98Smycroft	else
7131.22Schopps		caa.caa_cb_attach = &cba;
7141.22Schopps	caa.caa_16_attach = &paa;
7151.22Schopps	caa.caa_ph = &sc->sc_pcmcia_h;
7161.1Shaya
7171.22Schopps	if (NULL != (csc = (void *)config_found(self, &caa, cbbprint))) {
7181.141Sdyoung		DPRINTF(("%s: found cardslot\n", __func__));
7191.22Schopps		sc->sc_csc = csc;
7201.22Schopps	}
7211.1Shaya
7221.22Schopps	return;
7231.1Shaya}
7241.1Shaya
7251.26Shaya
7261.26Shaya
7271.26Shaya
7281.26Shaya
7291.26Shaya/*
7301.26Shaya * static void pccbb_chipinit(struct pccbb_softc *sc)
7311.26Shaya *
7321.32Senami *   This function initialize YENTA chip registers listed below:
7331.26Shaya *     1) PCI command reg,
7341.26Shaya *     2) PCI and CardBus latency timer,
7351.43Sjhawk *     3) route PCI interrupt,
7361.43Sjhawk *     4) close all memory and io windows.
7371.69Shaya *     5) turn off bus power.
7381.118Schristos *     6) card detect and power cycle interrupts on.
7391.69Shaya *     7) clear interrupt
7401.26Shaya */
7411.1Shayastatic void
7421.143Sdyoungpccbb_chipinit(struct pccbb_softc *sc)
7431.1Shaya{
7441.22Schopps	pci_chipset_tag_t pc = sc->sc_pc;
7451.22Schopps	pcitag_t tag = sc->sc_tag;
7461.69Shaya	bus_space_tag_t bmt = sc->sc_base_memt;
7471.69Shaya	bus_space_handle_t bmh = sc->sc_base_memh;
7481.151Sdyoung	pcireg_t bcr, bhlc, cbctl, csr, lscp, mfunc, mrburst, slotctl, sockctl,
7491.151Sdyoung	    sockmask, sysctrl;
7501.22Schopps
7511.117Sperry	/*
7521.22Schopps	 * Set PCI command reg.
7531.22Schopps	 * Some laptop's BIOSes (i.e. TICO) do not enable CardBus chip.
7541.22Schopps	 */
7551.146Sdyoung	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
7561.30Smycroft	/* I believe it is harmless. */
7571.146Sdyoung	csr |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
7581.30Smycroft	    PCI_COMMAND_MASTER_ENABLE);
7591.151Sdyoung	csr |= (PCI_COMMAND_PARITY_ENABLE|PCI_COMMAND_SERR_ENABLE);
7601.146Sdyoung	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
7611.1Shaya
7621.117Sperry	/*
7631.30Smycroft	 * Set CardBus latency timer.
7641.22Schopps	 */
7651.146Sdyoung	lscp = pci_conf_read(pc, tag, PCI_CB_LSCP_REG);
7661.146Sdyoung	if (PCI_CB_LATENCY(lscp) < 0x20) {
7671.146Sdyoung		lscp &= ~(PCI_CB_LATENCY_MASK << PCI_CB_LATENCY_SHIFT);
7681.146Sdyoung		lscp |= (0x20 << PCI_CB_LATENCY_SHIFT);
7691.146Sdyoung		pci_conf_write(pc, tag, PCI_CB_LSCP_REG, lscp);
7701.22Schopps	}
7711.30Smycroft	DPRINTF(("CardBus latency timer 0x%x (%x)\n",
7721.146Sdyoung	    PCI_CB_LATENCY(lscp), pci_conf_read(pc, tag, PCI_CB_LSCP_REG)));
7731.1Shaya
7741.117Sperry	/*
7751.30Smycroft	 * Set PCI latency timer.
7761.22Schopps	 */
7771.146Sdyoung	bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG);
7781.146Sdyoung	if (PCI_LATTIMER(bhlc) < 0x10) {
7791.146Sdyoung		bhlc &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
7801.146Sdyoung		bhlc |= (0x10 << PCI_LATTIMER_SHIFT);
7811.146Sdyoung		pci_conf_write(pc, tag, PCI_BHLC_REG, bhlc);
7821.22Schopps	}
7831.30Smycroft	DPRINTF(("PCI latency timer 0x%x (%x)\n",
7841.146Sdyoung	    PCI_LATTIMER(bhlc), pci_conf_read(pc, tag, PCI_BHLC_REG)));
7851.1Shaya
7861.1Shaya
7871.30Smycroft	/* Route functional interrupts to PCI. */
7881.146Sdyoung	bcr = pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG);
7891.146Sdyoung	bcr |= CB_BCR_INTR_IREQ_ENABLE;		/* disable PCI Intr */
7901.146Sdyoung	bcr |= CB_BCR_WRITE_POST_ENABLE;	/* enable write post */
7911.146Sdyoung	/* assert reset */
7921.146Sdyoung	bcr |= PCI_BRIDGE_CONTROL_SECBR	<< PCI_BRIDGE_CONTROL_SHIFT;
7931.151Sdyoung        /* Set master abort mode to 1, forward SERR# from secondary
7941.151Sdyoung         * to primary, and detect parity errors on secondary.
7951.151Sdyoung	 */
7961.151Sdyoung	bcr |= PCI_BRIDGE_CONTROL_MABRT	<< PCI_BRIDGE_CONTROL_SHIFT;
7971.151Sdyoung	bcr |= PCI_BRIDGE_CONTROL_SERR << PCI_BRIDGE_CONTROL_SHIFT;
7981.151Sdyoung	bcr |= PCI_BRIDGE_CONTROL_PERE << PCI_BRIDGE_CONTROL_SHIFT;
7991.146Sdyoung	pci_conf_write(pc, tag, PCI_BRIDGE_CONTROL_REG, bcr);
8001.1Shaya
8011.30Smycroft	switch (sc->sc_chipset) {
8021.30Smycroft	case CB_TI113X:
8031.146Sdyoung		cbctl = pci_conf_read(pc, tag, PCI_CBCTRL);
8041.30Smycroft		/* This bit is shared, but may read as 0 on some chips, so set
8051.30Smycroft		   it explicitly on both functions. */
8061.146Sdyoung		cbctl |= PCI113X_CBCTRL_PCI_IRQ_ENA;
8071.22Schopps		/* CSC intr enable */
8081.146Sdyoung		cbctl |= PCI113X_CBCTRL_PCI_CSC;
8091.45Shaya		/* functional intr prohibit | prohibit ISA routing */
8101.146Sdyoung		cbctl &= ~(PCI113X_CBCTRL_PCI_INTR | PCI113X_CBCTRL_INT_MASK);
8111.146Sdyoung		pci_conf_write(pc, tag, PCI_CBCTRL, cbctl);
8121.50Smycroft		break;
8131.50Smycroft
8141.151Sdyoung	case CB_TI1420:
8151.151Sdyoung		sysctrl = pci_conf_read(pc, tag, PCI_SYSCTRL);
8161.151Sdyoung		mrburst = pccbb_burstup
8171.151Sdyoung		    ? PCI1420_SYSCTRL_MRBURST : PCI1420_SYSCTRL_MRBURSTDN;
8181.151Sdyoung		if ((sysctrl & PCI1420_SYSCTRL_MRBURST) == mrburst) {
8191.151Sdyoung			printf("%s: %swrite bursts enabled\n",
8201.151Sdyoung			    device_xname(&sc->sc_dev),
8211.151Sdyoung			    pccbb_burstup ? "read/" : "");
8221.151Sdyoung		} else if (pccbb_burstup) {
8231.151Sdyoung			printf("%s: enabling read/write bursts\n",
8241.151Sdyoung			    device_xname(&sc->sc_dev));
8251.151Sdyoung			sysctrl |= PCI1420_SYSCTRL_MRBURST;
8261.151Sdyoung			pci_conf_write(pc, tag, PCI_SYSCTRL, sysctrl);
8271.151Sdyoung		} else {
8281.151Sdyoung			printf("%s: disabling read bursts, "
8291.151Sdyoung			    "enabling write bursts\n",
8301.151Sdyoung			    device_xname(&sc->sc_dev));
8311.151Sdyoung			sysctrl |= PCI1420_SYSCTRL_MRBURSTDN;
8321.151Sdyoung			sysctrl &= ~PCI1420_SYSCTRL_MRBURSTUP;
8331.151Sdyoung			pci_conf_write(pc, tag, PCI_SYSCTRL, sysctrl);
8341.151Sdyoung		}
8351.151Sdyoung		/*FALLTHROUGH*/
8361.50Smycroft	case CB_TI12XX:
8371.96Snakayama		/*
8381.96Snakayama		 * Some TI 12xx (and [14][45]xx) based pci cards
8391.96Snakayama		 * sometimes have issues with the MFUNC register not
8401.96Snakayama		 * being initialized due to a bad EEPROM on board.
8411.96Snakayama		 * Laptops that this matters on have this register
8421.96Snakayama		 * properly initialized.
8431.96Snakayama		 *
8441.96Snakayama		 * The TI125X parts have a different register.
8451.96Snakayama		 */
8461.146Sdyoung		mfunc = pci_conf_read(pc, tag, PCI12XX_MFUNC);
8471.146Sdyoung		if (mfunc == 0) {
8481.146Sdyoung			mfunc &= ~PCI12XX_MFUNC_PIN0;
8491.146Sdyoung			mfunc |= PCI12XX_MFUNC_PIN0_INTA;
8501.96Snakayama			if ((pci_conf_read(pc, tag, PCI_SYSCTRL) &
8511.96Snakayama			     PCI12XX_SYSCTRL_INTRTIE) == 0) {
8521.146Sdyoung				mfunc &= ~PCI12XX_MFUNC_PIN1;
8531.146Sdyoung				mfunc |= PCI12XX_MFUNC_PIN1_INTB;
8541.96Snakayama			}
8551.146Sdyoung			pci_conf_write(pc, tag, PCI12XX_MFUNC, mfunc);
8561.96Snakayama		}
8571.96Snakayama		/* fallthrough */
8581.96Snakayama
8591.96Snakayama	case CB_TI125X:
8601.96Snakayama		/*
8611.96Snakayama		 * Disable zoom video.  Some machines initialize this
8621.96Snakayama		 * improperly and experience has shown that this helps
8631.96Snakayama		 * prevent strange behavior.
8641.96Snakayama		 */
8651.96Snakayama		pci_conf_write(pc, tag, PCI12XX_MMCTRL, 0);
8661.96Snakayama
8671.146Sdyoung		sysctrl = pci_conf_read(pc, tag, PCI_SYSCTRL);
8681.146Sdyoung		sysctrl |= PCI12XX_SYSCTRL_VCCPROT;
8691.146Sdyoung		pci_conf_write(pc, tag, PCI_SYSCTRL, sysctrl);
8701.146Sdyoung		cbctl = pci_conf_read(pc, tag, PCI_CBCTRL);
8711.146Sdyoung		cbctl |= PCI12XX_CBCTRL_CSC;
8721.146Sdyoung		pci_conf_write(pc, tag, PCI_CBCTRL, cbctl);
8731.30Smycroft		break;
8741.30Smycroft
8751.30Smycroft	case CB_TOPIC95B:
8761.146Sdyoung		sockctl = pci_conf_read(pc, tag, TOPIC_SOCKET_CTRL);
8771.146Sdyoung		sockctl |= TOPIC_SOCKET_CTRL_SCR_IRQSEL;
8781.146Sdyoung		pci_conf_write(pc, tag, TOPIC_SOCKET_CTRL, sockctl);
8791.146Sdyoung		slotctl = pci_conf_read(pc, tag, TOPIC_SLOT_CTRL);
8801.67Shaya		DPRINTF(("%s: topic slot ctrl reg 0x%x -> ",
8811.146Sdyoung		    sc->sc_dev.dv_xname, slotctl));
8821.146Sdyoung		slotctl |= (TOPIC_SLOT_CTRL_SLOTON | TOPIC_SLOT_CTRL_SLOTEN |
8831.67Shaya		    TOPIC_SLOT_CTRL_ID_LOCK | TOPIC_SLOT_CTRL_CARDBUS);
8841.146Sdyoung		slotctl &= ~TOPIC_SLOT_CTRL_SWDETECT;
8851.146Sdyoung		DPRINTF(("0x%x\n", slotctl));
8861.146Sdyoung		pci_conf_write(pc, tag, TOPIC_SLOT_CTRL, slotctl);
8871.67Shaya		break;
8881.22Schopps
8891.67Shaya	case CB_TOPIC97:
8901.146Sdyoung		slotctl = pci_conf_read(pc, tag, TOPIC_SLOT_CTRL);
8911.22Schopps		DPRINTF(("%s: topic slot ctrl reg 0x%x -> ",
8921.146Sdyoung		    sc->sc_dev.dv_xname, slotctl));
8931.146Sdyoung		slotctl |= (TOPIC_SLOT_CTRL_SLOTON | TOPIC_SLOT_CTRL_SLOTEN |
8941.30Smycroft		    TOPIC_SLOT_CTRL_ID_LOCK | TOPIC_SLOT_CTRL_CARDBUS);
8951.146Sdyoung		slotctl &= ~TOPIC_SLOT_CTRL_SWDETECT;
8961.146Sdyoung		slotctl |= TOPIC97_SLOT_CTRL_PCIINT;
8971.146Sdyoung		slotctl &= ~(TOPIC97_SLOT_CTRL_STSIRQP | TOPIC97_SLOT_CTRL_IRQP);
8981.146Sdyoung		DPRINTF(("0x%x\n", slotctl));
8991.146Sdyoung		pci_conf_write(pc, tag, TOPIC_SLOT_CTRL, slotctl);
9001.69Shaya		/* make sure to assert LV card support bits */
9011.69Shaya		bus_space_write_1(sc->sc_base_memt, sc->sc_base_memh,
9021.69Shaya		    0x800 + 0x3e,
9031.69Shaya		    bus_space_read_1(sc->sc_base_memt, sc->sc_base_memh,
9041.69Shaya			0x800 + 0x3e) | 0x03);
9051.30Smycroft		break;
9061.22Schopps	}
9071.1Shaya
9081.30Smycroft	/* Close all memory and I/O windows. */
9091.22Schopps	pci_conf_write(pc, tag, PCI_CB_MEMBASE0, 0xffffffff);
9101.22Schopps	pci_conf_write(pc, tag, PCI_CB_MEMLIMIT0, 0);
9111.22Schopps	pci_conf_write(pc, tag, PCI_CB_MEMBASE1, 0xffffffff);
9121.22Schopps	pci_conf_write(pc, tag, PCI_CB_MEMLIMIT1, 0);
9131.22Schopps	pci_conf_write(pc, tag, PCI_CB_IOBASE0, 0xffffffff);
9141.22Schopps	pci_conf_write(pc, tag, PCI_CB_IOLIMIT0, 0);
9151.22Schopps	pci_conf_write(pc, tag, PCI_CB_IOBASE1, 0xffffffff);
9161.22Schopps	pci_conf_write(pc, tag, PCI_CB_IOLIMIT1, 0);
9171.46Shaya
9181.46Shaya	/* reset 16-bit pcmcia bus */
9191.69Shaya	bus_space_write_1(bmt, bmh, 0x800 + PCIC_INTR,
9201.69Shaya	    bus_space_read_1(bmt, bmh, 0x800 + PCIC_INTR) & ~PCIC_INTR_RESET);
9211.46Shaya
9221.69Shaya	/* turn off power */
9231.46Shaya	pccbb_power((cardbus_chipset_tag_t)sc, CARDBUS_VCC_0V | CARDBUS_VPP_0V);
9241.69Shaya
9251.118Schristos	/* CSC Interrupt: Card detect and power cycle interrupts on */
9261.146Sdyoung	sockmask = bus_space_read_4(bmt, bmh, CB_SOCKET_MASK);
9271.146Sdyoung	sockmask |= CB_SOCKET_MASK_CD | CB_SOCKET_MASK_POWER;
9281.146Sdyoung	bus_space_write_4(bmt, bmh, CB_SOCKET_MASK, sockmask);
9291.69Shaya	/* reset interrupt */
9301.69Shaya	bus_space_write_4(bmt, bmh, CB_SOCKET_EVENT,
9311.69Shaya	    bus_space_read_4(bmt, bmh, CB_SOCKET_EVENT));
9321.1Shaya}
9331.1Shaya
9341.26Shaya
9351.26Shaya
9361.26Shaya
9371.4Shaya/*
9381.26Shaya * STATIC void pccbb_pcmcia_attach_setup(struct pccbb_softc *sc,
9391.26Shaya *					 struct pcmciabus_attach_args *paa)
9401.26Shaya *
9411.26Shaya *   This function attaches 16-bit PCcard bus.
9421.4Shaya */
9431.1ShayaSTATIC void
9441.143Sdyoungpccbb_pcmcia_attach_setup(struct pccbb_softc *sc,
9451.143Sdyoung    struct pcmciabus_attach_args *paa)
9461.1Shaya{
9471.22Schopps	struct pcic_handle *ph = &sc->sc_pcmcia_h;
9481.10Shaya#if rbus
9491.22Schopps	rbus_tag_t rb;
9501.10Shaya#endif
9511.1Shaya
9521.32Senami	/* initialize pcmcia part in pccbb_softc */
9531.22Schopps	ph->ph_parent = (struct device *)sc;
9541.22Schopps	ph->sock = sc->sc_function;
9551.22Schopps	ph->flags = 0;
9561.22Schopps	ph->shutdown = 0;
9571.51Ssommerfe	ph->ih_irq = sc->sc_pa.pa_intrline;
9581.22Schopps	ph->ph_bus_t = sc->sc_base_memt;
9591.22Schopps	ph->ph_bus_h = sc->sc_base_memh;
9601.22Schopps	ph->ph_read = pccbb_pcmcia_read;
9611.22Schopps	ph->ph_write = pccbb_pcmcia_write;
9621.22Schopps	sc->sc_pct = &pccbb_pcmcia_funcs;
9631.22Schopps
9641.31Smycroft	/*
9651.31Smycroft	 * We need to do a few things here:
9661.31Smycroft	 * 1) Disable routing of CSC and functional interrupts to ISA IRQs by
9671.31Smycroft	 *    setting the IRQ numbers to 0.
9681.31Smycroft	 * 2) Set bit 4 of PCIC_INTR, which is needed on some chips to enable
9691.31Smycroft	 *    routing of CSC interrupts (e.g. card removal) to PCI while in
9701.31Smycroft	 *    PCMCIA mode.  We just leave this set all the time.
9711.31Smycroft	 * 3) Enable card insertion/removal interrupts in case the chip also
9721.31Smycroft	 *    needs that while in PCMCIA mode.
9731.31Smycroft	 * 4) Clear any pending CSC interrupt.
9741.31Smycroft	 */
9751.46Shaya	Pcic_write(ph, PCIC_INTR, PCIC_INTR_ENABLE);
9761.45Shaya	if (sc->sc_chipset == CB_TI113X) {
9771.45Shaya		Pcic_write(ph, PCIC_CSC_INTR, 0);
9781.45Shaya	} else {
9791.45Shaya		Pcic_write(ph, PCIC_CSC_INTR, PCIC_CSC_INTR_CD_ENABLE);
9801.45Shaya		Pcic_read(ph, PCIC_CSC);
9811.45Shaya	}
9821.22Schopps
9831.32Senami	/* initialize pcmcia bus attachment */
9841.22Schopps	paa->paa_busname = "pcmcia";
9851.22Schopps	paa->pct = sc->sc_pct;
9861.22Schopps	paa->pch = ph;
9871.22Schopps	paa->iobase = 0;	       /* I don't use them */
9881.22Schopps	paa->iosize = 0;
9891.10Shaya#if rbus
9901.22Schopps	rb = ((struct pccbb_softc *)(ph->ph_parent))->sc_rbus_iot;
9911.22Schopps	paa->iobase = rb->rb_start + rb->rb_offset;
9921.22Schopps	paa->iosize = rb->rb_end - rb->rb_start;
9931.10Shaya#endif
9941.1Shaya
9951.22Schopps	return;
9961.1Shaya}
9971.1Shaya
9981.1Shaya#if 0
9991.1ShayaSTATIC void
10001.143Sdyoungpccbb_pcmcia_attach_card(struct pcic_handle *ph)
10011.1Shaya{
10021.22Schopps	if (ph->flags & PCIC_FLAG_CARDP) {
10031.22Schopps		panic("pccbb_pcmcia_attach_card: already attached");
10041.22Schopps	}
10051.1Shaya
10061.22Schopps	/* call the MI attach function */
10071.22Schopps	pcmcia_card_attach(ph->pcmcia);
10081.1Shaya
10091.22Schopps	ph->flags |= PCIC_FLAG_CARDP;
10101.1Shaya}
10111.1Shaya
10121.1ShayaSTATIC void
10131.143Sdyoungpccbb_pcmcia_detach_card(struct pcic_handle *ph, int flags)
10141.1Shaya{
10151.22Schopps	if (!(ph->flags & PCIC_FLAG_CARDP)) {
10161.22Schopps		panic("pccbb_pcmcia_detach_card: already detached");
10171.22Schopps	}
10181.1Shaya
10191.22Schopps	ph->flags &= ~PCIC_FLAG_CARDP;
10201.1Shaya
10211.22Schopps	/* call the MI detach function */
10221.22Schopps	pcmcia_card_detach(ph->pcmcia, flags);
10231.1Shaya}
10241.1Shaya#endif
10251.1Shaya
10261.4Shaya/*
10271.4Shaya * int pccbbintr(arg)
10281.4Shaya *    void *arg;
10291.4Shaya *   This routine handles the interrupt from Yenta PCI-CardBus bridge
10301.4Shaya *   itself.
10311.4Shaya */
10321.1Shayaint
10331.143Sdyoungpccbbintr(void *arg)
10341.1Shaya{
10351.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)arg;
10361.31Smycroft	u_int32_t sockevent, sockstate;
10371.22Schopps	bus_space_tag_t memt = sc->sc_base_memt;
10381.22Schopps	bus_space_handle_t memh = sc->sc_base_memh;
10391.31Smycroft	struct pcic_handle *ph = &sc->sc_pcmcia_h;
10401.22Schopps
10411.22Schopps	sockevent = bus_space_read_4(memt, memh, CB_SOCKET_EVENT);
10421.31Smycroft	bus_space_write_4(memt, memh, CB_SOCKET_EVENT, sockevent);
10431.31Smycroft	Pcic_read(ph, PCIC_CSC);
10441.31Smycroft
10451.152Sdyoung	if (sockevent != 0) {
10461.152Sdyoung		aprint_debug("%s: enter sockevent %" PRIx32 "\n", __func__,
10471.152Sdyoung		    sockevent);
10481.152Sdyoung	}
10491.152Sdyoung
10501.152Sdyoung	/* Sometimes a change of CSTSCHG# accompanies the first
10511.152Sdyoung	 * interrupt from an Atheros WLAN.  That generates a
10521.152Sdyoung	 * CB_SOCKET_EVENT_CSTS event on the bridge.  The event
10531.152Sdyoung	 * isn't interesting to pccbb(4), so we used to ignore the
10541.152Sdyoung	 * interrupt.  Now, let the child devices try to handle
10551.152Sdyoung	 * the interrupt, instead.  The Atheros NIC produces
10561.152Sdyoung	 * interrupts more reliably, now: used to be that it would
10571.152Sdyoung	 * only interrupt if the driver avoided powering down the
10581.152Sdyoung	 * NIC's cardslot, and then the NIC would only work after
10591.152Sdyoung	 * it was reset a second time.
10601.152Sdyoung	 */
10611.152Sdyoung	if (sockevent == 0 ||
10621.152Sdyoung	    (sockevent & ~(CB_SOCKET_EVENT_POWER|CB_SOCKET_EVENT_CD)) != 0) {
10631.22Schopps		/* This intr is not for me: it may be for my child devices. */
10641.38Shaya		if (sc->sc_pil_intr_enable) {
10651.38Shaya			return pccbbintr_function(sc);
10661.38Shaya		} else {
10671.38Shaya			return 0;
10681.38Shaya		}
10691.22Schopps	}
10701.1Shaya
10711.22Schopps	if (sockevent & CB_SOCKET_EVENT_CD) {
10721.31Smycroft		sockstate = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
10731.90Smsaitoh		if (0x00 != (sockstate & CB_SOCKET_STAT_CD)) {
10741.22Schopps			/* A card should be removed. */
10751.22Schopps			if (sc->sc_flags & CBB_CARDEXIST) {
10761.22Schopps				DPRINTF(("%s: 0x%08x", sc->sc_dev.dv_xname,
10771.22Schopps				    sockevent));
10781.22Schopps				DPRINTF((" card removed, 0x%08x\n", sockstate));
10791.22Schopps				sc->sc_flags &= ~CBB_CARDEXIST;
10801.33Senami				if (sc->sc_csc->sc_status &
10811.33Senami				    CARDSLOT_STATUS_CARD_16) {
10821.1Shaya#if 0
10831.22Schopps					struct pcic_handle *ph =
10841.22Schopps					    &sc->sc_pcmcia_h;
10851.1Shaya
10861.22Schopps					pcmcia_card_deactivate(ph->pcmcia);
10871.22Schopps					pccbb_pcmcia_socket_disable(ph);
10881.22Schopps					pccbb_pcmcia_detach_card(ph,
10891.22Schopps					    DETACH_FORCE);
10901.22Schopps#endif
10911.22Schopps					cardslot_event_throw(sc->sc_csc,
10921.22Schopps					    CARDSLOT_EVENT_REMOVAL_16);
10931.33Senami				} else if (sc->sc_csc->sc_status &
10941.33Senami				    CARDSLOT_STATUS_CARD_CB) {
10951.22Schopps					/* Cardbus intr removed */
10961.22Schopps					cardslot_event_throw(sc->sc_csc,
10971.22Schopps					    CARDSLOT_EVENT_REMOVAL_CB);
10981.22Schopps				}
10991.74Shaya			} else if (sc->sc_flags & CBB_INSERTING) {
11001.74Shaya				sc->sc_flags &= ~CBB_INSERTING;
11011.74Shaya				callout_stop(&sc->sc_insert_ch);
11021.22Schopps			}
11031.34Senami		} else if (0x00 == (sockstate & CB_SOCKET_STAT_CD) &&
11041.34Senami		    /*
11051.34Senami		     * The pccbbintr may called from powerdown hook when
11061.34Senami		     * the system resumed, to detect the card
11071.34Senami		     * insertion/removal during suspension.
11081.34Senami		     */
11091.34Senami		    (sc->sc_flags & CBB_CARDEXIST) == 0) {
11101.22Schopps			if (sc->sc_flags & CBB_INSERTING) {
11111.37Sthorpej				callout_stop(&sc->sc_insert_ch);
11121.22Schopps			}
11131.149Sjoerg			callout_schedule(&sc->sc_insert_ch, hz / 5);
11141.22Schopps			sc->sc_flags |= CBB_INSERTING;
11151.22Schopps		}
11161.22Schopps	}
11171.1Shaya
11181.153Sdyoung	/* XXX sockevent == 9 does occur in the wild.  handle it. */
11191.111Smycroft	if (sockevent & CB_SOCKET_EVENT_POWER) {
11201.132Schristos		DPRINTF(("Powercycling because of socket event\n"));
11211.118Schristos		/* XXX: Does not happen when attaching a 16-bit card */
11221.111Smycroft		sc->sc_pwrcycle++;
11231.111Smycroft		wakeup(&sc->sc_pwrcycle);
11241.111Smycroft	}
11251.111Smycroft
11261.33Senami	return (1);
11271.1Shaya}
11281.1Shaya
11291.21Shaya/*
11301.21Shaya * static int pccbbintr_function(struct pccbb_softc *sc)
11311.21Shaya *
11321.21Shaya *    This function calls each interrupt handler registered at the
11331.32Senami *    bridge.  The interrupt handlers are called in registered order.
11341.21Shaya */
11351.21Shayastatic int
11361.143Sdyoungpccbbintr_function(struct pccbb_softc *sc)
11371.21Shaya{
11381.22Schopps	int retval = 0, val;
11391.22Schopps	struct pccbb_intrhand_list *pil;
11401.138Syamt	int s;
11411.21Shaya
11421.80Shaya	for (pil = LIST_FIRST(&sc->sc_pil); pil != NULL;
11431.80Shaya	     pil = LIST_NEXT(pil, pil_next)) {
11441.138Syamt		s = splraiseipl(pil->pil_icookie);
11451.41Shaya		val = (*pil->pil_func)(pil->pil_arg);
11461.138Syamt		splx(s);
11471.41Shaya
11481.22Schopps		retval = retval == 1 ? 1 :
11491.22Schopps		    retval == 0 ? val : val != 0 ? val : retval;
11501.22Schopps	}
11511.21Shaya
11521.22Schopps	return retval;
11531.21Shaya}
11541.21Shaya
11551.1Shayastatic void
11561.143Sdyoungpci113x_insert(void *arg)
11571.1Shaya{
11581.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)arg;
11591.22Schopps	u_int32_t sockevent, sockstate;
11601.74Shaya
11611.74Shaya	if (!(sc->sc_flags & CBB_INSERTING)) {
11621.74Shaya		/* We add a card only under inserting state. */
11631.74Shaya		return;
11641.74Shaya	}
11651.74Shaya	sc->sc_flags &= ~CBB_INSERTING;
11661.1Shaya
11671.22Schopps	sockevent = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh,
11681.22Schopps	    CB_SOCKET_EVENT);
11691.22Schopps	sockstate = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh,
11701.22Schopps	    CB_SOCKET_STAT);
11711.22Schopps
11721.22Schopps	if (0 == (sockstate & CB_SOCKET_STAT_CD)) {	/* card exist */
11731.22Schopps		DPRINTF(("%s: 0x%08x", sc->sc_dev.dv_xname, sockevent));
11741.22Schopps		DPRINTF((" card inserted, 0x%08x\n", sockstate));
11751.22Schopps		sc->sc_flags |= CBB_CARDEXIST;
11761.32Senami		/* call pccard interrupt handler here */
11771.22Schopps		if (sockstate & CB_SOCKET_STAT_16BIT) {
11781.22Schopps			/* 16-bit card found */
11791.1Shaya/*      pccbb_pcmcia_attach_card(&sc->sc_pcmcia_h); */
11801.22Schopps			cardslot_event_throw(sc->sc_csc,
11811.22Schopps			    CARDSLOT_EVENT_INSERTION_16);
11821.22Schopps		} else if (sockstate & CB_SOCKET_STAT_CB) {
11831.32Senami			/* cardbus card found */
11841.1Shaya/*      cardbus_attach_card(sc->sc_csc); */
11851.22Schopps			cardslot_event_throw(sc->sc_csc,
11861.22Schopps			    CARDSLOT_EVENT_INSERTION_CB);
11871.22Schopps		} else {
11881.22Schopps			/* who are you? */
11891.22Schopps		}
11901.22Schopps	} else {
11911.149Sjoerg		callout_schedule(&sc->sc_insert_ch, hz / 10);
11921.22Schopps	}
11931.1Shaya}
11941.1Shaya
11951.1Shaya#define PCCBB_PCMCIA_OFFSET 0x800
11961.1Shayastatic u_int8_t
11971.143Sdyoungpccbb_pcmcia_read(struct pcic_handle *ph, int reg)
11981.1Shaya{
11991.48Shaya	bus_space_barrier(ph->ph_bus_t, ph->ph_bus_h,
12001.48Shaya	    PCCBB_PCMCIA_OFFSET + reg, 1, BUS_SPACE_BARRIER_READ);
12011.48Shaya
12021.22Schopps	return bus_space_read_1(ph->ph_bus_t, ph->ph_bus_h,
12031.22Schopps	    PCCBB_PCMCIA_OFFSET + reg);
12041.1Shaya}
12051.1Shaya
12061.1Shayastatic void
12071.143Sdyoungpccbb_pcmcia_write(struct pcic_handle *ph, int reg, u_int8_t val)
12081.1Shaya{
12091.22Schopps	bus_space_write_1(ph->ph_bus_t, ph->ph_bus_h, PCCBB_PCMCIA_OFFSET + reg,
12101.22Schopps	    val);
12111.48Shaya
12121.48Shaya	bus_space_barrier(ph->ph_bus_t, ph->ph_bus_h,
12131.48Shaya	    PCCBB_PCMCIA_OFFSET + reg, 1, BUS_SPACE_BARRIER_WRITE);
12141.1Shaya}
12151.1Shaya
12161.4Shaya/*
12171.4Shaya * STATIC int pccbb_ctrl(cardbus_chipset_tag_t, int)
12181.4Shaya */
12191.1ShayaSTATIC int
12201.143Sdyoungpccbb_ctrl(cardbus_chipset_tag_t ct, int command)
12211.1Shaya{
12221.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
12231.1Shaya
12241.22Schopps	switch (command) {
12251.22Schopps	case CARDBUS_CD:
12261.22Schopps		if (2 == pccbb_detect_card(sc)) {
12271.22Schopps			int retval = 0;
12281.22Schopps			int status = cb_detect_voltage(sc);
12291.22Schopps			if (PCCARD_VCC_5V & status) {
12301.22Schopps				retval |= CARDBUS_5V_CARD;
12311.22Schopps			}
12321.22Schopps			if (PCCARD_VCC_3V & status) {
12331.22Schopps				retval |= CARDBUS_3V_CARD;
12341.22Schopps			}
12351.22Schopps			if (PCCARD_VCC_XV & status) {
12361.22Schopps				retval |= CARDBUS_XV_CARD;
12371.22Schopps			}
12381.22Schopps			if (PCCARD_VCC_YV & status) {
12391.22Schopps				retval |= CARDBUS_YV_CARD;
12401.22Schopps			}
12411.22Schopps			return retval;
12421.22Schopps		} else {
12431.22Schopps			return 0;
12441.22Schopps		}
12451.22Schopps	case CARDBUS_RESET:
12461.22Schopps		return cb_reset(sc);
12471.22Schopps	case CARDBUS_IO_ENABLE:       /* fallthrough */
12481.22Schopps	case CARDBUS_IO_DISABLE:      /* fallthrough */
12491.22Schopps	case CARDBUS_MEM_ENABLE:      /* fallthrough */
12501.22Schopps	case CARDBUS_MEM_DISABLE:     /* fallthrough */
12511.22Schopps	case CARDBUS_BM_ENABLE:       /* fallthrough */
12521.22Schopps	case CARDBUS_BM_DISABLE:      /* fallthrough */
12531.69Shaya		/* XXX: I think we don't need to call this function below. */
12541.22Schopps		return pccbb_cardenable(sc, command);
12551.22Schopps	}
12561.1Shaya
12571.22Schopps	return 0;
12581.1Shaya}
12591.1Shaya
12601.4Shaya/*
12611.4Shaya * STATIC int pccbb_power(cardbus_chipset_tag_t, int)
12621.4Shaya *   This function returns true when it succeeds and returns false when
12631.4Shaya *   it fails.
12641.4Shaya */
12651.1ShayaSTATIC int
12661.143Sdyoungpccbb_power(cardbus_chipset_tag_t ct, int command)
12671.1Shaya{
12681.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
12691.144Sdyoung	u_int32_t status, osock_ctrl, sock_ctrl, reg_ctrl;
12701.22Schopps	bus_space_tag_t memt = sc->sc_base_memt;
12711.22Schopps	bus_space_handle_t memh = sc->sc_base_memh;
12721.144Sdyoung	int on = 0, pwrcycle, s, times;
12731.144Sdyoung	struct timeval before, after, diff;
12741.22Schopps
12751.95Schristos	DPRINTF(("pccbb_power: %s and %s [0x%x]\n",
12761.22Schopps	    (command & CARDBUS_VCCMASK) == CARDBUS_VCC_UC ? "CARDBUS_VCC_UC" :
12771.22Schopps	    (command & CARDBUS_VCCMASK) == CARDBUS_VCC_5V ? "CARDBUS_VCC_5V" :
12781.22Schopps	    (command & CARDBUS_VCCMASK) == CARDBUS_VCC_3V ? "CARDBUS_VCC_3V" :
12791.22Schopps	    (command & CARDBUS_VCCMASK) == CARDBUS_VCC_XV ? "CARDBUS_VCC_XV" :
12801.22Schopps	    (command & CARDBUS_VCCMASK) == CARDBUS_VCC_YV ? "CARDBUS_VCC_YV" :
12811.22Schopps	    (command & CARDBUS_VCCMASK) == CARDBUS_VCC_0V ? "CARDBUS_VCC_0V" :
12821.22Schopps	    "UNKNOWN",
12831.22Schopps	    (command & CARDBUS_VPPMASK) == CARDBUS_VPP_UC ? "CARDBUS_VPP_UC" :
12841.22Schopps	    (command & CARDBUS_VPPMASK) == CARDBUS_VPP_12V ? "CARDBUS_VPP_12V" :
12851.22Schopps	    (command & CARDBUS_VPPMASK) == CARDBUS_VPP_VCC ? "CARDBUS_VPP_VCC" :
12861.22Schopps	    (command & CARDBUS_VPPMASK) == CARDBUS_VPP_0V ? "CARDBUS_VPP_0V" :
12871.22Schopps	    "UNKNOWN", command));
12881.22Schopps
12891.22Schopps	status = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
12901.144Sdyoung	osock_ctrl = sock_ctrl = bus_space_read_4(memt, memh, CB_SOCKET_CTRL);
12911.22Schopps
12921.22Schopps	switch (command & CARDBUS_VCCMASK) {
12931.22Schopps	case CARDBUS_VCC_UC:
12941.22Schopps		break;
12951.22Schopps	case CARDBUS_VCC_5V:
12961.111Smycroft		on++;
12971.22Schopps		if (CB_SOCKET_STAT_5VCARD & status) {	/* check 5 V card */
12981.22Schopps			sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK;
12991.22Schopps			sock_ctrl |= CB_SOCKET_CTRL_VCC_5V;
13001.22Schopps		} else {
13011.22Schopps			printf("%s: BAD voltage request: no 5 V card\n",
13021.22Schopps			    sc->sc_dev.dv_xname);
13031.91Sbriggs			return 0;
13041.22Schopps		}
13051.22Schopps		break;
13061.22Schopps	case CARDBUS_VCC_3V:
13071.111Smycroft		on++;
13081.22Schopps		if (CB_SOCKET_STAT_3VCARD & status) {
13091.22Schopps			sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK;
13101.22Schopps			sock_ctrl |= CB_SOCKET_CTRL_VCC_3V;
13111.22Schopps		} else {
13121.22Schopps			printf("%s: BAD voltage request: no 3.3 V card\n",
13131.22Schopps			    sc->sc_dev.dv_xname);
13141.91Sbriggs			return 0;
13151.22Schopps		}
13161.22Schopps		break;
13171.22Schopps	case CARDBUS_VCC_0V:
13181.22Schopps		sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK;
13191.22Schopps		break;
13201.22Schopps	default:
13211.22Schopps		return 0;	       /* power NEVER changed */
13221.22Schopps	}
13231.1Shaya
13241.22Schopps	switch (command & CARDBUS_VPPMASK) {
13251.22Schopps	case CARDBUS_VPP_UC:
13261.22Schopps		break;
13271.22Schopps	case CARDBUS_VPP_0V:
13281.22Schopps		sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK;
13291.22Schopps		break;
13301.22Schopps	case CARDBUS_VPP_VCC:
13311.22Schopps		sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK;
13321.22Schopps		sock_ctrl |= ((sock_ctrl >> 4) & 0x07);
13331.22Schopps		break;
13341.22Schopps	case CARDBUS_VPP_12V:
13351.22Schopps		sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK;
13361.22Schopps		sock_ctrl |= CB_SOCKET_CTRL_VPP_12V;
13371.22Schopps		break;
13381.22Schopps	}
13391.1Shaya
13401.111Smycroft	pwrcycle = sc->sc_pwrcycle;
13411.144Sdyoung	aprint_debug("%s: osock_ctrl %#" PRIx32 " sock_ctrl %#" PRIx32 "\n",
13421.144Sdyoung	    device_xname(&sc->sc_dev), osock_ctrl, sock_ctrl);
13431.111Smycroft
13441.144Sdyoung	microtime(&before);
13451.144Sdyoung	s = splbio();
13461.22Schopps	bus_space_write_4(memt, memh, CB_SOCKET_CTRL, sock_ctrl);
13471.111Smycroft
13481.144Sdyoung	/*
13491.144Sdyoung	 * Wait as long as 200ms for a power-cycle interrupt.  If
13501.144Sdyoung	 * interrupts are enabled, but the socket has already
13511.144Sdyoung	 * changed to the desired status, keep waiting for the
13521.144Sdyoung	 * interrupt.  "Consuming" the interrupt in this way keeps
13531.144Sdyoung	 * the interrupt from prematurely waking some subsequent
13541.144Sdyoung	 * pccbb_power call.
13551.144Sdyoung	 *
13561.144Sdyoung	 * XXX Not every bridge interrupts on the ->OFF transition.
13571.144Sdyoung	 * XXX That's ok, we will time-out after 200ms.
13581.144Sdyoung	 *
13591.144Sdyoung	 * XXX The power cycle event will never happen when attaching
13601.144Sdyoung	 * XXX a 16-bit card.  That's ok, we will time-out after
13611.144Sdyoung	 * XXX 200ms.
13621.144Sdyoung	 */
13631.144Sdyoung	for (times = 5; --times >= 0; ) {
13641.144Sdyoung		if (cold)
13651.144Sdyoung			DELAY(40 * 1000);
13661.144Sdyoung		else {
13671.144Sdyoung			(void)tsleep(&sc->sc_pwrcycle, PWAIT, "pccpwr",
13681.144Sdyoung			    hz / 25);
13691.144Sdyoung			if (pwrcycle == sc->sc_pwrcycle)
13701.144Sdyoung				continue;
13711.118Schristos		}
13721.144Sdyoung		status = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
13731.144Sdyoung		if ((status & CB_SOCKET_STAT_PWRCYCLE) != 0 && on)
13741.144Sdyoung			break;
13751.144Sdyoung		if ((status & CB_SOCKET_STAT_PWRCYCLE) == 0 && !on)
13761.144Sdyoung			break;
13771.144Sdyoung	}
13781.144Sdyoung	splx(s);
13791.144Sdyoung	microtime(&after);
13801.144Sdyoung	timersub(&after, &before, &diff);
13811.144Sdyoung	aprint_debug("%s: wait took%s %ld.%06lds\n", sc->sc_dev.dv_xname,
13821.144Sdyoung	    (on && times < 0) ? " too long" : "", diff.tv_sec, diff.tv_usec);
13831.133Schristos
13841.144Sdyoung	/*
13851.144Sdyoung	 * Ok, wait a bit longer for things to settle.
13861.144Sdyoung	 */
13871.144Sdyoung	if (on && sc->sc_chipset == CB_TOPIC95B)
13881.144Sdyoung		delay_ms(100, sc);
13891.111Smycroft
13901.22Schopps	status = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
13911.1Shaya
13921.132Schristos	if (on && sc->sc_chipset != CB_TOPIC95B) {
13931.111Smycroft		if ((status & CB_SOCKET_STAT_PWRCYCLE) == 0)
13941.111Smycroft			printf("%s: power on failed?\n", sc->sc_dev.dv_xname);
13951.111Smycroft	}
13961.111Smycroft
13971.22Schopps	if (status & CB_SOCKET_STAT_BADVCC) {	/* bad Vcc request */
13981.104Smycroft		printf("%s: bad Vcc request. sock_ctrl 0x%x, sock_status 0x%x\n",
13991.22Schopps		    sc->sc_dev.dv_xname, sock_ctrl, status);
14001.104Smycroft		printf("%s: disabling socket\n", sc->sc_dev.dv_xname);
14011.104Smycroft		sock_ctrl &= ~CB_SOCKET_CTRL_VCCMASK;
14021.104Smycroft		sock_ctrl &= ~CB_SOCKET_CTRL_VPPMASK;
14031.104Smycroft		bus_space_write_4(memt, memh, CB_SOCKET_CTRL, sock_ctrl);
14041.111Smycroft		status &= ~CB_SOCKET_STAT_BADVCC;
14051.145Schristos		bus_space_write_4(memt, memh, CB_SOCKET_FORCE, status);
14061.104Smycroft		printf("new status 0x%x\n", bus_space_read_4(memt, memh,
14071.104Smycroft		    CB_SOCKET_STAT));
14081.22Schopps		return 0;
14091.77Smycroft	}
14101.77Smycroft
14111.77Smycroft	if (sc->sc_chipset == CB_TOPIC97) {
14121.77Smycroft		reg_ctrl = pci_conf_read(sc->sc_pc, sc->sc_tag, TOPIC_REG_CTRL);
14131.77Smycroft		reg_ctrl &= ~TOPIC97_REG_CTRL_TESTMODE;
14141.77Smycroft		if ((command & CARDBUS_VCCMASK) == CARDBUS_VCC_0V)
14151.77Smycroft			reg_ctrl &= ~TOPIC97_REG_CTRL_CLKRUN_ENA;
14161.77Smycroft		else
14171.77Smycroft			reg_ctrl |= TOPIC97_REG_CTRL_CLKRUN_ENA;
14181.77Smycroft		pci_conf_write(sc->sc_pc, sc->sc_tag, TOPIC_REG_CTRL, reg_ctrl);
14191.22Schopps	}
14201.48Shaya
14211.22Schopps	return 1;		       /* power changed correctly */
14221.1Shaya}
14231.1Shaya
14241.1Shaya#if defined CB_PCMCIA_POLL
14251.1Shayastruct cb_poll_str {
14261.22Schopps	void *arg;
14271.116Sperry	int (*func)(void *);
14281.22Schopps	int level;
14291.22Schopps	pccard_chipset_tag_t ct;
14301.22Schopps	int count;
14311.37Sthorpej	struct callout poll_ch;
14321.1Shaya};
14331.1Shaya
14341.1Shayastatic struct cb_poll_str cb_poll[10];
14351.1Shayastatic int cb_poll_n = 0;
14361.1Shaya
14371.116Sperrystatic void cb_pcmcia_poll(void *arg);
14381.1Shaya
14391.1Shayastatic void
14401.143Sdyoungcb_pcmcia_poll(void *arg)
14411.1Shaya{
14421.22Schopps	struct cb_poll_str *poll = arg;
14431.22Schopps	struct cbb_pcmcia_softc *psc = (void *)poll->ct->v;
14441.22Schopps	struct pccbb_softc *sc = psc->cpc_parent;
14451.22Schopps	int s;
14461.22Schopps	u_int32_t spsr;		       /* socket present-state reg */
14471.22Schopps
14481.37Sthorpej	callout_reset(&poll->poll_ch, hz / 10, cb_pcmcia_poll, poll);
14491.22Schopps	switch (poll->level) {
14501.22Schopps	case IPL_NET:
14511.22Schopps		s = splnet();
14521.22Schopps		break;
14531.22Schopps	case IPL_BIO:
14541.22Schopps		s = splbio();
14551.22Schopps		break;
14561.22Schopps	case IPL_TTY:		       /* fallthrough */
14571.22Schopps	default:
14581.22Schopps		s = spltty();
14591.22Schopps		break;
14601.22Schopps	}
14611.22Schopps
14621.22Schopps	spsr =
14631.22Schopps	    bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh,
14641.22Schopps	    CB_SOCKET_STAT);
14651.1Shaya
14661.1Shaya#if defined CB_PCMCIA_POLL_ONLY && defined LEVEL2
14671.22Schopps	if (!(spsr & 0x40)) {	       /* CINT low */
14681.1Shaya#else
14691.22Schopps	if (1) {
14701.1Shaya#endif
14711.22Schopps		if ((*poll->func) (poll->arg) == 1) {
14721.22Schopps			++poll->count;
14731.22Schopps			printf("intr: reported from poller, 0x%x\n", spsr);
14741.1Shaya#if defined LEVEL2
14751.22Schopps		} else {
14761.22Schopps			printf("intr: miss! 0x%x\n", spsr);
14771.1Shaya#endif
14781.22Schopps		}
14791.22Schopps	}
14801.22Schopps	splx(s);
14811.1Shaya}
14821.1Shaya#endif /* defined CB_PCMCIA_POLL */
14831.1Shaya
14841.4Shaya/*
14851.4Shaya * static int pccbb_detect_card(struct pccbb_softc *sc)
14861.4Shaya *   return value:  0 if no card exists.
14871.4Shaya *                  1 if 16-bit card exists.
14881.4Shaya *                  2 if cardbus card exists.
14891.4Shaya */
14901.1Shayastatic int
14911.143Sdyoungpccbb_detect_card(struct pccbb_softc *sc)
14921.1Shaya{
14931.22Schopps	bus_space_handle_t base_memh = sc->sc_base_memh;
14941.22Schopps	bus_space_tag_t base_memt = sc->sc_base_memt;
14951.22Schopps	u_int32_t sockstat =
14961.22Schopps	    bus_space_read_4(base_memt, base_memh, CB_SOCKET_STAT);
14971.22Schopps	int retval = 0;
14981.22Schopps
14991.22Schopps	/* CD1 and CD2 asserted */
15001.22Schopps	if (0x00 == (sockstat & CB_SOCKET_STAT_CD)) {
15011.22Schopps		/* card must be present */
15021.22Schopps		if (!(CB_SOCKET_STAT_NOTCARD & sockstat)) {
15031.22Schopps			/* NOTACARD DEASSERTED */
15041.22Schopps			if (CB_SOCKET_STAT_CB & sockstat) {
15051.22Schopps				/* CardBus mode */
15061.22Schopps				retval = 2;
15071.22Schopps			} else if (CB_SOCKET_STAT_16BIT & sockstat) {
15081.22Schopps				/* 16-bit mode */
15091.22Schopps				retval = 1;
15101.22Schopps			}
15111.22Schopps		}
15121.22Schopps	}
15131.22Schopps	return retval;
15141.1Shaya}
15151.1Shaya
15161.4Shaya/*
15171.4Shaya * STATIC int cb_reset(struct pccbb_softc *sc)
15181.4Shaya *   This function resets CardBus card.
15191.4Shaya */
15201.1ShayaSTATIC int
15211.143Sdyoungcb_reset(struct pccbb_softc *sc)
15221.1Shaya{
15231.117Sperry	/*
15241.117Sperry	 * Reset Assert at least 20 ms
15251.22Schopps	 * Some machines request longer duration.
15261.22Schopps	 */
15271.22Schopps	int reset_duration =
15281.136Sitohy	    (sc->sc_chipset == CB_RX5C47X ? 400 : 50);
15291.146Sdyoung	u_int32_t bcr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_BRIDGE_CONTROL_REG);
15301.153Sdyoung	aprint_debug("%s: enter bcr %" PRIx32 "\n", __func__, bcr);
15311.22Schopps
15321.40Shaya	/* Reset bit Assert (bit 6 at 0x3E) */
15331.153Sdyoung	bcr |= PCI_BRIDGE_CONTROL_SECBR << PCI_BRIDGE_CONTROL_SHIFT;
15341.146Sdyoung	pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BRIDGE_CONTROL_REG, bcr);
15351.153Sdyoung	aprint_debug("%s: wrote bcr %" PRIx32 "\n", __func__, bcr);
15361.142Sdyoung	delay_ms(reset_duration, sc);
15371.22Schopps
15381.22Schopps	if (CBB_CARDEXIST & sc->sc_flags) {	/* A card exists.  Reset it! */
15391.40Shaya		/* Reset bit Deassert (bit 6 at 0x3E) */
15401.153Sdyoung		bcr &= ~(PCI_BRIDGE_CONTROL_SECBR << PCI_BRIDGE_CONTROL_SHIFT);
15411.153Sdyoung		pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BRIDGE_CONTROL_REG,
15421.153Sdyoung		    bcr);
15431.153Sdyoung		aprint_debug("%s: wrote bcr %" PRIx32 "\n", __func__, bcr);
15441.142Sdyoung		delay_ms(reset_duration, sc);
15451.153Sdyoung		aprint_debug("%s: end of delay\n", __func__);
15461.22Schopps	}
15471.22Schopps	/* No card found on the slot. Keep Reset. */
15481.22Schopps	return 1;
15491.1Shaya}
15501.1Shaya
15511.4Shaya/*
15521.4Shaya * STATIC int cb_detect_voltage(struct pccbb_softc *sc)
15531.4Shaya *  This function detect card Voltage.
15541.4Shaya */
15551.1ShayaSTATIC int
15561.143Sdyoungcb_detect_voltage(struct pccbb_softc *sc)
15571.1Shaya{
15581.22Schopps	u_int32_t psr;		       /* socket present-state reg */
15591.22Schopps	bus_space_tag_t iot = sc->sc_base_memt;
15601.22Schopps	bus_space_handle_t ioh = sc->sc_base_memh;
15611.22Schopps	int vol = PCCARD_VCC_UKN;      /* set 0 */
15621.22Schopps
15631.22Schopps	psr = bus_space_read_4(iot, ioh, CB_SOCKET_STAT);
15641.1Shaya
15651.22Schopps	if (0x400u & psr) {
15661.22Schopps		vol |= PCCARD_VCC_5V;
15671.22Schopps	}
15681.22Schopps	if (0x800u & psr) {
15691.22Schopps		vol |= PCCARD_VCC_3V;
15701.22Schopps	}
15711.1Shaya
15721.22Schopps	return vol;
15731.1Shaya}
15741.1Shaya
15751.1ShayaSTATIC int
15761.137Schristoscbbprint(void *aux, const char *pcic)
15771.1Shaya{
15781.135Schristos#if 0
15791.135Schristos	struct cbslot_attach_args *cba = aux;
15801.1Shaya
15811.135Schristos	if (cba->cba_slot >= 0) {
15821.135Schristos		aprint_normal(" slot %d", cba->cba_slot);
15831.135Schristos	}
15841.135Schristos#endif
15851.22Schopps	return UNCONF;
15861.1Shaya}
15871.1Shaya
15881.4Shaya/*
15891.4Shaya * STATIC int pccbb_cardenable(struct pccbb_softc *sc, int function)
15901.4Shaya *   This function enables and disables the card
15911.4Shaya */
15921.1ShayaSTATIC int
15931.143Sdyoungpccbb_cardenable(struct pccbb_softc *sc, int function)
15941.1Shaya{
15951.22Schopps	u_int32_t command =
15961.22Schopps	    pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
15971.1Shaya
15981.22Schopps	DPRINTF(("pccbb_cardenable:"));
15991.22Schopps	switch (function) {
16001.22Schopps	case CARDBUS_IO_ENABLE:
16011.22Schopps		command |= PCI_COMMAND_IO_ENABLE;
16021.22Schopps		break;
16031.22Schopps	case CARDBUS_IO_DISABLE:
16041.22Schopps		command &= ~PCI_COMMAND_IO_ENABLE;
16051.22Schopps		break;
16061.22Schopps	case CARDBUS_MEM_ENABLE:
16071.22Schopps		command |= PCI_COMMAND_MEM_ENABLE;
16081.22Schopps		break;
16091.22Schopps	case CARDBUS_MEM_DISABLE:
16101.22Schopps		command &= ~PCI_COMMAND_MEM_ENABLE;
16111.22Schopps		break;
16121.22Schopps	case CARDBUS_BM_ENABLE:
16131.22Schopps		command |= PCI_COMMAND_MASTER_ENABLE;
16141.22Schopps		break;
16151.22Schopps	case CARDBUS_BM_DISABLE:
16161.22Schopps		command &= ~PCI_COMMAND_MASTER_ENABLE;
16171.22Schopps		break;
16181.22Schopps	default:
16191.22Schopps		return 0;
16201.22Schopps	}
16211.1Shaya
16221.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, command);
16231.22Schopps	DPRINTF((" command reg 0x%x\n", command));
16241.22Schopps	return 1;
16251.1Shaya}
16261.1Shaya
16271.1Shaya#if !rbus
16281.1Shayastatic int
16291.143Sdyoungpccbb_io_open(cardbus_chipset_tag_t ct, int win, uint32_t start, uint32_t end)
16301.22Schopps{
16311.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
16321.22Schopps	int basereg;
16331.22Schopps	int limitreg;
16341.1Shaya
16351.22Schopps	if ((win < 0) || (win > 2)) {
16361.1Shaya#if defined DIAGNOSTIC
16371.22Schopps		printf("cardbus_io_open: window out of range %d\n", win);
16381.1Shaya#endif
16391.22Schopps		return 0;
16401.22Schopps	}
16411.1Shaya
16421.22Schopps	basereg = win * 8 + 0x2c;
16431.22Schopps	limitreg = win * 8 + 0x30;
16441.1Shaya
16451.22Schopps	DPRINTF(("pccbb_io_open: 0x%x[0x%x] - 0x%x[0x%x]\n",
16461.22Schopps	    start, basereg, end, limitreg));
16471.1Shaya
16481.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, start);
16491.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, end);
16501.22Schopps	return 1;
16511.1Shaya}
16521.22Schopps
16531.4Shaya/*
16541.4Shaya * int pccbb_io_close(cardbus_chipset_tag_t, int)
16551.4Shaya */
16561.1Shayastatic int
16571.143Sdyoungpccbb_io_close(cardbus_chipset_tag_t ct, int win)
16581.1Shaya{
16591.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
16601.22Schopps	int basereg;
16611.22Schopps	int limitreg;
16621.1Shaya
16631.22Schopps	if ((win < 0) || (win > 2)) {
16641.1Shaya#if defined DIAGNOSTIC
16651.22Schopps		printf("cardbus_io_close: window out of range %d\n", win);
16661.1Shaya#endif
16671.22Schopps		return 0;
16681.22Schopps	}
16691.1Shaya
16701.22Schopps	basereg = win * 8 + 0x2c;
16711.22Schopps	limitreg = win * 8 + 0x30;
16721.1Shaya
16731.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, 0);
16741.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, 0);
16751.22Schopps	return 1;
16761.1Shaya}
16771.1Shaya
16781.1Shayastatic int
16791.143Sdyoungpccbb_mem_open(cardbus_chipset_tag_t ct, int win, uint32_t start, uint32_t end)
16801.22Schopps{
16811.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
16821.22Schopps	int basereg;
16831.22Schopps	int limitreg;
16841.1Shaya
16851.22Schopps	if ((win < 0) || (win > 2)) {
16861.1Shaya#if defined DIAGNOSTIC
16871.22Schopps		printf("cardbus_mem_open: window out of range %d\n", win);
16881.1Shaya#endif
16891.22Schopps		return 0;
16901.22Schopps	}
16911.1Shaya
16921.22Schopps	basereg = win * 8 + 0x1c;
16931.22Schopps	limitreg = win * 8 + 0x20;
16941.1Shaya
16951.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, start);
16961.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, end);
16971.22Schopps	return 1;
16981.1Shaya}
16991.1Shaya
17001.1Shayastatic int
17011.143Sdyoungpccbb_mem_close(cardbus_chipset_tag_t ct, int win)
17021.1Shaya{
17031.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
17041.22Schopps	int basereg;
17051.22Schopps	int limitreg;
17061.1Shaya
17071.22Schopps	if ((win < 0) || (win > 2)) {
17081.1Shaya#if defined DIAGNOSTIC
17091.22Schopps		printf("cardbus_mem_close: window out of range %d\n", win);
17101.1Shaya#endif
17111.22Schopps		return 0;
17121.22Schopps	}
17131.1Shaya
17141.22Schopps	basereg = win * 8 + 0x1c;
17151.22Schopps	limitreg = win * 8 + 0x20;
17161.1Shaya
17171.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, basereg, 0);
17181.22Schopps	pci_conf_write(sc->sc_pc, sc->sc_tag, limitreg, 0);
17191.22Schopps	return 1;
17201.1Shaya}
17211.1Shaya#endif
17221.1Shaya
17231.21Shaya/*
17241.26Shaya * static void *pccbb_cb_intr_establish(cardbus_chipset_tag_t ct,
17251.26Shaya *					int irq,
17261.26Shaya *					int level,
17271.116Sperry *					int (* func)(void *),
17281.26Shaya *					void *arg)
17291.26Shaya *
17301.26Shaya *   This function registers an interrupt handler at the bridge, in
17311.32Senami *   order not to call the interrupt handlers of child devices when
17321.32Senami *   a card-deletion interrupt occurs.
17331.26Shaya *
17341.26Shaya *   The arguments irq and level are not used.
17351.26Shaya */
17361.26Shayastatic void *
17371.143Sdyoungpccbb_cb_intr_establish(cardbus_chipset_tag_t ct, int irq, int level,
17381.143Sdyoung    int (*func)(void *), void *arg)
17391.26Shaya{
17401.26Shaya	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
17411.26Shaya
17421.26Shaya	return pccbb_intr_establish(sc, irq, level, func, arg);
17431.26Shaya}
17441.26Shaya
17451.26Shaya
17461.26Shaya/*
17471.26Shaya * static void *pccbb_cb_intr_disestablish(cardbus_chipset_tag_t ct,
17481.26Shaya *					   void *ih)
17491.26Shaya *
17501.26Shaya *   This function removes an interrupt handler pointed by ih.
17511.26Shaya */
17521.26Shayastatic void
17531.143Sdyoungpccbb_cb_intr_disestablish(cardbus_chipset_tag_t ct, void *ih)
17541.26Shaya{
17551.26Shaya	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
17561.26Shaya
17571.26Shaya	pccbb_intr_disestablish(sc, ih);
17581.26Shaya}
17591.26Shaya
17601.26Shaya
17611.65Smcrvoid
17621.143Sdyoungpccbb_intr_route(struct pccbb_softc *sc)
17631.65Smcr{
17641.143Sdyoung	pcireg_t bcr, cbctrl;
17651.65Smcr
17661.143Sdyoung	/* initialize bridge intr routing */
17671.146Sdyoung	bcr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_BRIDGE_CONTROL_REG);
17681.143Sdyoung	bcr &= ~CB_BCR_INTR_IREQ_ENABLE;
17691.146Sdyoung	pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BRIDGE_CONTROL_REG, bcr);
17701.143Sdyoung
17711.143Sdyoung	switch (sc->sc_chipset) {
17721.143Sdyoung	case CB_TI113X:
17731.143Sdyoung		cbctrl = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CBCTRL);
17741.143Sdyoung		/* functional intr enabled */
17751.143Sdyoung		cbctrl |= PCI113X_CBCTRL_PCI_INTR;
17761.143Sdyoung		pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CBCTRL, cbctrl);
17771.143Sdyoung		break;
17781.143Sdyoung	default:
17791.143Sdyoung		break;
17801.143Sdyoung	}
17811.65Smcr}
17821.65Smcr
17831.26Shaya/*
17841.26Shaya * static void *pccbb_intr_establish(struct pccbb_softc *sc,
17851.21Shaya *				     int irq,
17861.21Shaya *				     int level,
17871.116Sperry *				     int (* func)(void *),
17881.21Shaya *				     void *arg)
17891.21Shaya *
17901.21Shaya *   This function registers an interrupt handler at the bridge, in
17911.32Senami *   order not to call the interrupt handlers of child devices when
17921.32Senami *   a card-deletion interrupt occurs.
17931.21Shaya *
17941.41Shaya *   The arguments irq is not used because pccbb selects intr vector.
17951.21Shaya */
17961.1Shayastatic void *
17971.137Schristospccbb_intr_establish(struct pccbb_softc *sc, int irq, int level,
17981.135Schristos    int (*func)(void *), void *arg)
17991.22Schopps{
18001.22Schopps	struct pccbb_intrhand_list *pil, *newpil;
18011.22Schopps
18021.81Sonoe	DPRINTF(("pccbb_intr_establish start. %p\n", LIST_FIRST(&sc->sc_pil)));
18031.26Shaya
18041.80Shaya	if (LIST_EMPTY(&sc->sc_pil)) {
18051.80Shaya		pccbb_intr_route(sc);
18061.22Schopps	}
18071.22Schopps
18081.117Sperry	/*
18091.32Senami	 * Allocate a room for interrupt handler structure.
18101.22Schopps	 */
18111.22Schopps	if (NULL == (newpil =
18121.22Schopps	    (struct pccbb_intrhand_list *)malloc(sizeof(struct
18131.22Schopps	    pccbb_intrhand_list), M_DEVBUF, M_WAITOK))) {
18141.22Schopps		return NULL;
18151.22Schopps	}
18161.21Shaya
18171.22Schopps	newpil->pil_func = func;
18181.22Schopps	newpil->pil_arg = arg;
18191.138Syamt	newpil->pil_icookie = makeiplcookie(level);
18201.21Shaya
18211.80Shaya	if (LIST_EMPTY(&sc->sc_pil)) {
18221.80Shaya		LIST_INSERT_HEAD(&sc->sc_pil, newpil, pil_next);
18231.22Schopps	} else {
18241.80Shaya		for (pil = LIST_FIRST(&sc->sc_pil);
18251.80Shaya		     LIST_NEXT(pil, pil_next) != NULL;
18261.80Shaya		     pil = LIST_NEXT(pil, pil_next));
18271.80Shaya		LIST_INSERT_AFTER(pil, newpil, pil_next);
18281.21Shaya	}
18291.1Shaya
18301.81Sonoe	DPRINTF(("pccbb_intr_establish add pil. %p\n",
18311.81Sonoe	    LIST_FIRST(&sc->sc_pil)));
18321.26Shaya
18331.22Schopps	return newpil;
18341.1Shaya}
18351.1Shaya
18361.21Shaya/*
18371.26Shaya * static void *pccbb_intr_disestablish(struct pccbb_softc *sc,
18381.21Shaya *					void *ih)
18391.21Shaya *
18401.80Shaya *	This function removes an interrupt handler pointed by ih.  ih
18411.80Shaya *	should be the value returned by cardbus_intr_establish() or
18421.80Shaya *	NULL.
18431.80Shaya *
18441.80Shaya *	When ih is NULL, this function will do nothing.
18451.21Shaya */
18461.1Shayastatic void
18471.143Sdyoungpccbb_intr_disestablish(struct pccbb_softc *sc, void *ih)
18481.1Shaya{
18491.80Shaya	struct pccbb_intrhand_list *pil;
18501.48Shaya	pcireg_t reg;
18511.21Shaya
18521.81Sonoe	DPRINTF(("pccbb_intr_disestablish start. %p\n",
18531.81Sonoe	    LIST_FIRST(&sc->sc_pil)));
18541.26Shaya
18551.80Shaya	if (ih == NULL) {
18561.80Shaya		/* intr handler is not set */
18571.80Shaya		DPRINTF(("pccbb_intr_disestablish: no ih\n"));
18581.80Shaya		return;
18591.80Shaya	}
18601.22Schopps
18611.80Shaya#ifdef DIAGNOSTIC
18621.80Shaya	for (pil = LIST_FIRST(&sc->sc_pil); pil != NULL;
18631.80Shaya	     pil = LIST_NEXT(pil, pil_next)) {
18641.83Satatat		DPRINTF(("pccbb_intr_disestablish: pil %p\n", pil));
18651.22Schopps		if (pil == ih) {
18661.26Shaya			DPRINTF(("pccbb_intr_disestablish frees one pil\n"));
18671.22Schopps			break;
18681.22Schopps		}
18691.21Shaya	}
18701.80Shaya	if (pil == NULL) {
18711.80Shaya		panic("pccbb_intr_disestablish: %s cannot find pil %p",
18721.80Shaya		    sc->sc_dev.dv_xname, ih);
18731.80Shaya	}
18741.80Shaya#endif
18751.80Shaya
18761.80Shaya	pil = (struct pccbb_intrhand_list *)ih;
18771.80Shaya	LIST_REMOVE(pil, pil_next);
18781.80Shaya	free(pil, M_DEVBUF);
18791.80Shaya	DPRINTF(("pccbb_intr_disestablish frees one pil\n"));
18801.21Shaya
18811.80Shaya	if (LIST_EMPTY(&sc->sc_pil)) {
18821.22Schopps		/* No interrupt handlers */
18831.21Shaya
18841.26Shaya		DPRINTF(("pccbb_intr_disestablish: no interrupt handler\n"));
18851.26Shaya
18861.48Shaya		/* stop routing PCI intr */
18871.146Sdyoung		reg = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_BRIDGE_CONTROL_REG);
18881.48Shaya		reg |= CB_BCR_INTR_IREQ_ENABLE;
18891.146Sdyoung		pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_BRIDGE_CONTROL_REG, reg);
18901.48Shaya
18911.22Schopps		switch (sc->sc_chipset) {
18921.22Schopps		case CB_TI113X:
18931.48Shaya			reg = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CBCTRL);
18941.48Shaya			/* functional intr disabled */
18951.48Shaya			reg &= ~PCI113X_CBCTRL_PCI_INTR;
18961.48Shaya			pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CBCTRL, reg);
18971.48Shaya			break;
18981.22Schopps		default:
18991.22Schopps			break;
19001.22Schopps		}
19011.21Shaya	}
19021.1Shaya}
19031.1Shaya
19041.1Shaya#if defined SHOW_REGS
19051.1Shayastatic void
19061.143Sdyoungcb_show_regs(pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt,
19071.143Sdyoung    bus_space_handle_t memh)
19081.22Schopps{
19091.22Schopps	int i;
19101.22Schopps	printf("PCI config regs:");
19111.22Schopps	for (i = 0; i < 0x50; i += 4) {
19121.143Sdyoung		if (i % 16 == 0)
19131.22Schopps			printf("\n 0x%02x:", i);
19141.22Schopps		printf(" %08x", pci_conf_read(pc, tag, i));
19151.22Schopps	}
19161.22Schopps	for (i = 0x80; i < 0xb0; i += 4) {
19171.143Sdyoung		if (i % 16 == 0)
19181.22Schopps			printf("\n 0x%02x:", i);
19191.22Schopps		printf(" %08x", pci_conf_read(pc, tag, i));
19201.22Schopps	}
19211.1Shaya
19221.22Schopps	if (memh == 0) {
19231.22Schopps		printf("\n");
19241.22Schopps		return;
19251.22Schopps	}
19261.1Shaya
19271.22Schopps	printf("\nsocket regs:");
19281.143Sdyoung	for (i = 0; i <= 0x10; i += 0x04)
19291.22Schopps		printf(" %08x", bus_space_read_4(memt, memh, i));
19301.22Schopps	printf("\nExCA regs:");
19311.143Sdyoung	for (i = 0; i < 0x08; ++i)
19321.22Schopps		printf(" %02x", bus_space_read_1(memt, memh, 0x800 + i));
19331.22Schopps	printf("\n");
19341.22Schopps	return;
19351.1Shaya}
19361.1Shaya#endif
19371.1Shaya
19381.4Shaya/*
19391.4Shaya * static cardbustag_t pccbb_make_tag(cardbus_chipset_tag_t cc,
19401.125Sdrochner *                                    int busno, int function)
19411.4Shaya *   This is the function to make a tag to access config space of
19421.4Shaya *  a CardBus Card.  It works same as pci_conf_read.
19431.4Shaya */
19441.1Shayastatic cardbustag_t
19451.143Sdyoungpccbb_make_tag(cardbus_chipset_tag_t cc, int busno, int function)
19461.1Shaya{
19471.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)cc;
19481.1Shaya
19491.125Sdrochner	return pci_make_tag(sc->sc_pc, busno, 0, function);
19501.1Shaya}
19511.1Shaya
19521.1Shayastatic void
19531.137Schristospccbb_free_tag(cardbus_chipset_tag_t cc, cardbustag_t tag)
19541.1Shaya{
19551.1Shaya}
19561.1Shaya
19571.4Shaya/*
19581.143Sdyoung * pccbb_conf_read
19591.143Sdyoung *
19601.143Sdyoung * This is the function to read the config space of a CardBus card.
19611.143Sdyoung * It works the same as pci_conf_read(9).
19621.4Shaya */
19631.1Shayastatic cardbusreg_t
19641.143Sdyoungpccbb_conf_read(cardbus_chipset_tag_t cc, cardbustag_t tag, int offset)
19651.1Shaya{
19661.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)cc;
19671.1Shaya
19681.22Schopps	return pci_conf_read(sc->sc_pc, tag, offset);
19691.1Shaya}
19701.1Shaya
19711.4Shaya/*
19721.143Sdyoung * pccbb_conf_write
19731.143Sdyoung *
19741.143Sdyoung * This is the function to write the config space of a CardBus
19751.143Sdyoung * card.  It works the same as pci_conf_write(9).
19761.4Shaya */
19771.1Shayastatic void
19781.143Sdyoungpccbb_conf_write(cardbus_chipset_tag_t cc, cardbustag_t tag, int reg,
19791.143Sdyoung    cardbusreg_t val)
19801.1Shaya{
19811.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)cc;
19821.1Shaya
19831.22Schopps	pci_conf_write(sc->sc_pc, tag, reg, val);
19841.1Shaya}
19851.1Shaya
19861.1Shaya#if 0
19871.1ShayaSTATIC int
19881.1Shayapccbb_new_pcmcia_io_alloc(pcmcia_chipset_handle_t pch,
19891.22Schopps    bus_addr_t start, bus_size_t size, bus_size_t align, bus_addr_t mask,
19901.22Schopps    int speed, int flags,
19911.22Schopps    bus_space_handle_t * iohp)
19921.1Shaya#endif
19931.4Shaya/*
19941.4Shaya * STATIC int pccbb_pcmcia_io_alloc(pcmcia_chipset_handle_t pch,
19951.4Shaya *                                  bus_addr_t start, bus_size_t size,
19961.4Shaya *                                  bus_size_t align,
19971.4Shaya *                                  struct pcmcia_io_handle *pcihp
19981.4Shaya *
19991.4Shaya * This function only allocates I/O region for pccard. This function
20001.32Senami * never maps the allocated region to pccard I/O area.
20011.4Shaya *
20021.4Shaya * XXX: The interface of this function is not very good, I believe.
20031.4Shaya */
20041.22SchoppsSTATIC int
20051.143Sdyoungpccbb_pcmcia_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
20061.143Sdyoung    bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp)
20071.22Schopps{
20081.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
20091.22Schopps	bus_addr_t ioaddr;
20101.22Schopps	int flags = 0;
20111.22Schopps	bus_space_tag_t iot;
20121.22Schopps	bus_space_handle_t ioh;
20131.57Shaya	bus_addr_t mask;
20141.1Shaya#if rbus
20151.22Schopps	rbus_tag_t rb;
20161.1Shaya#endif
20171.22Schopps	if (align == 0) {
20181.22Schopps		align = size;	       /* XXX: funny??? */
20191.22Schopps	}
20201.1Shaya
20211.57Shaya	if (start != 0) {
20221.57Shaya		/* XXX: assume all card decode lower 10 bits by its hardware */
20231.57Shaya		mask = 0x3ff;
20241.75Shaya		/* enforce to use only masked address */
20251.75Shaya		start &= mask;
20261.57Shaya	} else {
20271.57Shaya		/*
20281.57Shaya		 * calculate mask:
20291.57Shaya		 *  1. get the most significant bit of size (call it msb).
20301.57Shaya		 *  2. compare msb with the value of size.
20311.57Shaya		 *  3. if size is larger, shift msb left once.
20321.57Shaya		 *  4. obtain mask value to decrement msb.
20331.57Shaya		 */
20341.57Shaya		bus_size_t size_tmp = size;
20351.57Shaya		int shifts = 0;
20361.57Shaya
20371.57Shaya		mask = 1;
20381.57Shaya		while (size_tmp) {
20391.57Shaya			++shifts;
20401.57Shaya			size_tmp >>= 1;
20411.57Shaya		}
20421.57Shaya		mask = (1 << shifts);
20431.57Shaya		if (mask < size) {
20441.57Shaya			mask <<= 1;
20451.57Shaya		}
20461.57Shaya		--mask;
20471.57Shaya	}
20481.57Shaya
20491.117Sperry	/*
20501.22Schopps	 * Allocate some arbitrary I/O space.
20511.22Schopps	 */
20521.1Shaya
20531.22Schopps	iot = ((struct pccbb_softc *)(ph->ph_parent))->sc_iot;
20541.1Shaya
20551.1Shaya#if rbus
20561.22Schopps	rb = ((struct pccbb_softc *)(ph->ph_parent))->sc_rbus_iot;
20571.57Shaya	if (rbus_space_alloc(rb, start, size, mask, align, 0, &ioaddr, &ioh)) {
20581.22Schopps		return 1;
20591.22Schopps	}
20601.95Schristos	DPRINTF(("pccbb_pcmcia_io_alloc alloc port 0x%lx+0x%lx\n",
20611.81Sonoe	    (u_long) ioaddr, (u_long) size));
20621.22Schopps#else
20631.22Schopps	if (start) {
20641.22Schopps		ioaddr = start;
20651.22Schopps		if (bus_space_map(iot, start, size, 0, &ioh)) {
20661.22Schopps			return 1;
20671.22Schopps		}
20681.95Schristos		DPRINTF(("pccbb_pcmcia_io_alloc map port 0x%lx+0x%lx\n",
20691.22Schopps		    (u_long) ioaddr, (u_long) size));
20701.22Schopps	} else {
20711.22Schopps		flags |= PCMCIA_IO_ALLOCATED;
20721.22Schopps		if (bus_space_alloc(iot, 0x700 /* ph->sc->sc_iobase */ ,
20731.22Schopps		    0x800,	/* ph->sc->sc_iobase + ph->sc->sc_iosize */
20741.22Schopps		    size, align, 0, 0, &ioaddr, &ioh)) {
20751.22Schopps			/* No room be able to be get. */
20761.22Schopps			return 1;
20771.22Schopps		}
20781.22Schopps		DPRINTF(("pccbb_pcmmcia_io_alloc alloc port 0x%lx+0x%lx\n",
20791.22Schopps		    (u_long) ioaddr, (u_long) size));
20801.22Schopps	}
20811.1Shaya#endif
20821.1Shaya
20831.22Schopps	pcihp->iot = iot;
20841.22Schopps	pcihp->ioh = ioh;
20851.22Schopps	pcihp->addr = ioaddr;
20861.22Schopps	pcihp->size = size;
20871.22Schopps	pcihp->flags = flags;
20881.1Shaya
20891.22Schopps	return 0;
20901.1Shaya}
20911.1Shaya
20921.4Shaya/*
20931.4Shaya * STATIC int pccbb_pcmcia_io_free(pcmcia_chipset_handle_t pch,
20941.4Shaya *                                 struct pcmcia_io_handle *pcihp)
20951.4Shaya *
20961.4Shaya * This function only frees I/O region for pccard.
20971.4Shaya *
20981.4Shaya * XXX: The interface of this function is not very good, I believe.
20991.4Shaya */
21001.22Schoppsvoid
21011.143Sdyoungpccbb_pcmcia_io_free(pcmcia_chipset_handle_t pch,
21021.143Sdyoung    struct pcmcia_io_handle *pcihp)
21031.1Shaya{
21041.1Shaya#if !rbus
21051.22Schopps	bus_space_tag_t iot = pcihp->iot;
21061.1Shaya#endif
21071.22Schopps	bus_space_handle_t ioh = pcihp->ioh;
21081.22Schopps	bus_size_t size = pcihp->size;
21091.1Shaya
21101.1Shaya#if rbus
21111.22Schopps	struct pccbb_softc *sc =
21121.22Schopps	    (struct pccbb_softc *)((struct pcic_handle *)pch)->ph_parent;
21131.22Schopps	rbus_tag_t rb = sc->sc_rbus_iot;
21141.1Shaya
21151.22Schopps	rbus_space_free(rb, ioh, size, NULL);
21161.1Shaya#else
21171.22Schopps	if (pcihp->flags & PCMCIA_IO_ALLOCATED)
21181.22Schopps		bus_space_free(iot, ioh, size);
21191.22Schopps	else
21201.22Schopps		bus_space_unmap(iot, ioh, size);
21211.1Shaya#endif
21221.1Shaya}
21231.1Shaya
21241.4Shaya/*
21251.4Shaya * STATIC int pccbb_pcmcia_io_map(pcmcia_chipset_handle_t pch, int width,
21261.4Shaya *                                bus_addr_t offset, bus_size_t size,
21271.4Shaya *                                struct pcmcia_io_handle *pcihp,
21281.4Shaya *                                int *windowp)
21291.4Shaya *
21301.4Shaya * This function maps the allocated I/O region to pccard. This function
21311.4Shaya * never allocates any I/O region for pccard I/O area.  I don't
21321.4Shaya * understand why the original authors of pcmciabus separated alloc and
21331.4Shaya * map.  I believe the two must be unite.
21341.4Shaya *
21351.4Shaya * XXX: no wait timing control?
21361.4Shaya */
21371.22Schoppsint
21381.143Sdyoungpccbb_pcmcia_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
21391.143Sdyoung    bus_size_t size, struct pcmcia_io_handle *pcihp, int *windowp)
21401.22Schopps{
21411.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
21421.22Schopps	bus_addr_t ioaddr = pcihp->addr + offset;
21431.22Schopps	int i, win;
21441.1Shaya#if defined CBB_DEBUG
21451.121Ssekiya	static const char *width_names[] = { "dynamic", "io8", "io16" };
21461.1Shaya#endif
21471.1Shaya
21481.22Schopps	/* Sanity check I/O handle. */
21491.1Shaya
21501.22Schopps	if (((struct pccbb_softc *)ph->ph_parent)->sc_iot != pcihp->iot) {
21511.22Schopps		panic("pccbb_pcmcia_io_map iot is bogus");
21521.22Schopps	}
21531.1Shaya
21541.22Schopps	/* XXX Sanity check offset/size. */
21551.1Shaya
21561.22Schopps	win = -1;
21571.22Schopps	for (i = 0; i < PCIC_IO_WINS; i++) {
21581.22Schopps		if ((ph->ioalloc & (1 << i)) == 0) {
21591.22Schopps			win = i;
21601.22Schopps			ph->ioalloc |= (1 << i);
21611.22Schopps			break;
21621.22Schopps		}
21631.22Schopps	}
21641.1Shaya
21651.22Schopps	if (win == -1) {
21661.22Schopps		return 1;
21671.22Schopps	}
21681.1Shaya
21691.22Schopps	*windowp = win;
21701.1Shaya
21711.22Schopps	/* XXX this is pretty gross */
21721.1Shaya
21731.22Schopps	DPRINTF(("pccbb_pcmcia_io_map window %d %s port %lx+%lx\n",
21741.22Schopps	    win, width_names[width], (u_long) ioaddr, (u_long) size));
21751.1Shaya
21761.22Schopps	/* XXX wtf is this doing here? */
21771.1Shaya
21781.1Shaya#if 0
21791.22Schopps	printf(" port 0x%lx", (u_long) ioaddr);
21801.22Schopps	if (size > 1) {
21811.22Schopps		printf("-0x%lx", (u_long) ioaddr + (u_long) size - 1);
21821.22Schopps	}
21831.1Shaya#endif
21841.1Shaya
21851.22Schopps	ph->io[win].addr = ioaddr;
21861.22Schopps	ph->io[win].size = size;
21871.22Schopps	ph->io[win].width = width;
21881.1Shaya
21891.22Schopps	/* actual dirty register-value changing in the function below. */
21901.22Schopps	pccbb_pcmcia_do_io_map(ph, win);
21911.1Shaya
21921.22Schopps	return 0;
21931.1Shaya}
21941.1Shaya
21951.4Shaya/*
21961.4Shaya * STATIC void pccbb_pcmcia_do_io_map(struct pcic_handle *h, int win)
21971.4Shaya *
21981.4Shaya * This function changes register-value to map I/O region for pccard.
21991.4Shaya */
22001.22Schoppsstatic void
22011.143Sdyoungpccbb_pcmcia_do_io_map(struct pcic_handle *ph, int win)
22021.1Shaya{
22031.22Schopps	static u_int8_t pcic_iowidth[3] = {
22041.22Schopps		PCIC_IOCTL_IO0_IOCS16SRC_CARD,
22051.22Schopps		PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE |
22061.22Schopps		    PCIC_IOCTL_IO0_DATASIZE_8BIT,
22071.22Schopps		PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE |
22081.22Schopps		    PCIC_IOCTL_IO0_DATASIZE_16BIT,
22091.22Schopps	};
22101.1Shaya
22111.1Shaya#define PCIC_SIA_START_LOW 0
22121.1Shaya#define PCIC_SIA_START_HIGH 1
22131.1Shaya#define PCIC_SIA_STOP_LOW 2
22141.1Shaya#define PCIC_SIA_STOP_HIGH 3
22151.1Shaya
22161.22Schopps	int regbase_win = 0x8 + win * 0x04;
22171.22Schopps	u_int8_t ioctl, enable;
22181.1Shaya
22191.95Schristos	DPRINTF(("pccbb_pcmcia_do_io_map win %d addr 0x%lx size 0x%lx "
22201.95Schristos	    "width %d\n", win, (unsigned long)ph->io[win].addr,
22211.95Schristos	    (unsigned long)ph->io[win].size, ph->io[win].width * 8));
22221.22Schopps
22231.22Schopps	Pcic_write(ph, regbase_win + PCIC_SIA_START_LOW,
22241.22Schopps	    ph->io[win].addr & 0xff);
22251.22Schopps	Pcic_write(ph, regbase_win + PCIC_SIA_START_HIGH,
22261.22Schopps	    (ph->io[win].addr >> 8) & 0xff);
22271.22Schopps
22281.22Schopps	Pcic_write(ph, regbase_win + PCIC_SIA_STOP_LOW,
22291.22Schopps	    (ph->io[win].addr + ph->io[win].size - 1) & 0xff);
22301.22Schopps	Pcic_write(ph, regbase_win + PCIC_SIA_STOP_HIGH,
22311.22Schopps	    ((ph->io[win].addr + ph->io[win].size - 1) >> 8) & 0xff);
22321.22Schopps
22331.22Schopps	ioctl = Pcic_read(ph, PCIC_IOCTL);
22341.22Schopps	enable = Pcic_read(ph, PCIC_ADDRWIN_ENABLE);
22351.22Schopps	switch (win) {
22361.22Schopps	case 0:
22371.22Schopps		ioctl &= ~(PCIC_IOCTL_IO0_WAITSTATE | PCIC_IOCTL_IO0_ZEROWAIT |
22381.22Schopps		    PCIC_IOCTL_IO0_IOCS16SRC_MASK |
22391.22Schopps		    PCIC_IOCTL_IO0_DATASIZE_MASK);
22401.22Schopps		ioctl |= pcic_iowidth[ph->io[win].width];
22411.22Schopps		enable |= PCIC_ADDRWIN_ENABLE_IO0;
22421.22Schopps		break;
22431.22Schopps	case 1:
22441.22Schopps		ioctl &= ~(PCIC_IOCTL_IO1_WAITSTATE | PCIC_IOCTL_IO1_ZEROWAIT |
22451.22Schopps		    PCIC_IOCTL_IO1_IOCS16SRC_MASK |
22461.22Schopps		    PCIC_IOCTL_IO1_DATASIZE_MASK);
22471.22Schopps		ioctl |= (pcic_iowidth[ph->io[win].width] << 4);
22481.22Schopps		enable |= PCIC_ADDRWIN_ENABLE_IO1;
22491.22Schopps		break;
22501.22Schopps	}
22511.22Schopps	Pcic_write(ph, PCIC_IOCTL, ioctl);
22521.22Schopps	Pcic_write(ph, PCIC_ADDRWIN_ENABLE, enable);
22531.133Schristos#if defined(CBB_DEBUG)
22541.22Schopps	{
22551.22Schopps		u_int8_t start_low =
22561.22Schopps		    Pcic_read(ph, regbase_win + PCIC_SIA_START_LOW);
22571.22Schopps		u_int8_t start_high =
22581.22Schopps		    Pcic_read(ph, regbase_win + PCIC_SIA_START_HIGH);
22591.22Schopps		u_int8_t stop_low =
22601.22Schopps		    Pcic_read(ph, regbase_win + PCIC_SIA_STOP_LOW);
22611.22Schopps		u_int8_t stop_high =
22621.22Schopps		    Pcic_read(ph, regbase_win + PCIC_SIA_STOP_HIGH);
22631.133Schristos		printf("pccbb_pcmcia_do_io_map start %02x %02x, "
22641.133Schristos		    "stop %02x %02x, ioctl %02x enable %02x\n",
22651.22Schopps		    start_low, start_high, stop_low, stop_high, ioctl, enable);
22661.22Schopps	}
22671.1Shaya#endif
22681.1Shaya}
22691.1Shaya
22701.4Shaya/*
22711.4Shaya * STATIC void pccbb_pcmcia_io_unmap(pcmcia_chipset_handle_t *h, int win)
22721.4Shaya *
22731.32Senami * This function unmaps I/O region.  No return value.
22741.4Shaya */
22751.22SchoppsSTATIC void
22761.143Sdyoungpccbb_pcmcia_io_unmap(pcmcia_chipset_handle_t pch, int win)
22771.1Shaya{
22781.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
22791.22Schopps	int reg;
22801.1Shaya
22811.22Schopps	if (win >= PCIC_IO_WINS || win < 0) {
22821.22Schopps		panic("pccbb_pcmcia_io_unmap: window out of range");
22831.22Schopps	}
22841.1Shaya
22851.22Schopps	reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE);
22861.22Schopps	switch (win) {
22871.22Schopps	case 0:
22881.22Schopps		reg &= ~PCIC_ADDRWIN_ENABLE_IO0;
22891.22Schopps		break;
22901.22Schopps	case 1:
22911.22Schopps		reg &= ~PCIC_ADDRWIN_ENABLE_IO1;
22921.22Schopps		break;
22931.22Schopps	}
22941.22Schopps	Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg);
22951.1Shaya
22961.22Schopps	ph->ioalloc &= ~(1 << win);
22971.1Shaya}
22981.1Shaya
22991.91Sbriggsstatic int
23001.143Sdyoungpccbb_pcmcia_wait_ready(struct pcic_handle *ph)
23011.1Shaya{
23021.104Smycroft	u_int8_t stat;
23031.22Schopps	int i;
23041.1Shaya
23051.104Smycroft	/* wait an initial 10ms for quick cards */
23061.104Smycroft	stat = Pcic_read(ph, PCIC_IF_STATUS);
23071.104Smycroft	if (stat & PCIC_IF_STATUS_READY)
23081.104Smycroft		return (0);
23091.104Smycroft	pccbb_pcmcia_delay(ph, 10, "pccwr0");
23101.104Smycroft	for (i = 0; i < 50; i++) {
23111.91Sbriggs		stat = Pcic_read(ph, PCIC_IF_STATUS);
23121.91Sbriggs		if (stat & PCIC_IF_STATUS_READY)
23131.104Smycroft			return (0);
23141.91Sbriggs		if ((stat & PCIC_IF_STATUS_CARDDETECT_MASK) !=
23151.91Sbriggs		    PCIC_IF_STATUS_CARDDETECT_PRESENT)
23161.104Smycroft			return (ENXIO);
23171.104Smycroft		/* wait .1s (100ms) each iteration now */
23181.104Smycroft		pccbb_pcmcia_delay(ph, 100, "pccwr1");
23191.22Schopps	}
23201.1Shaya
23211.104Smycroft	printf("pccbb_pcmcia_wait_ready: ready never happened, status=%02x\n", stat);
23221.104Smycroft	return (EWOULDBLOCK);
23231.104Smycroft}
23241.104Smycroft
23251.104Smycroft/*
23261.143Sdyoung * Perform long (msec order) delay.  timo is in milliseconds.
23271.104Smycroft */
23281.104Smycroftstatic void
23291.143Sdyoungpccbb_pcmcia_delay(struct pcic_handle *ph, int timo, const char *wmesg)
23301.104Smycroft{
23311.1Shaya#ifdef DIAGNOSTIC
23321.104Smycroft	if (timo <= 0)
23331.104Smycroft		panic("pccbb_pcmcia_delay: called with timeout %d", timo);
23341.104Smycroft	if (!curlwp)
23351.104Smycroft		panic("pccbb_pcmcia_delay: called in interrupt context");
23361.104Smycroft#if 0
23371.104Smycroft	if (!ph->event_thread)
23381.104Smycroft		panic("pccbb_pcmcia_delay: no event thread");
23391.104Smycroft#endif
23401.1Shaya#endif
23411.104Smycroft	DPRINTF(("pccbb_pcmcia_delay: \"%s\" %p, sleep %d ms\n",
23421.110Smrg	    wmesg, ph->event_thread, timo));
23431.104Smycroft	tsleep(pccbb_pcmcia_delay, PWAIT, wmesg, roundup(timo * hz, 1000) / 1000);
23441.1Shaya}
23451.1Shaya
23461.4Shaya/*
23471.4Shaya * STATIC void pccbb_pcmcia_socket_enable(pcmcia_chipset_handle_t pch)
23481.4Shaya *
23491.4Shaya * This function enables the card.  All information is stored in
23501.4Shaya * the first argument, pcmcia_chipset_handle_t.
23511.4Shaya */
23521.1ShayaSTATIC void
23531.143Sdyoungpccbb_pcmcia_socket_enable(pcmcia_chipset_handle_t pch)
23541.1Shaya{
23551.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
23561.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
23571.104Smycroft	pcireg_t spsr;
23581.104Smycroft	int voltage;
23591.101Smycroft	int win;
23601.22Schopps	u_int8_t power, intr;
23611.104Smycroft#ifdef DIAGNOSTIC
23621.104Smycroft	int reg;
23631.104Smycroft#endif
23641.1Shaya
23651.22Schopps	/* this bit is mostly stolen from pcic_attach_card */
23661.1Shaya
23671.22Schopps	DPRINTF(("pccbb_pcmcia_socket_enable: "));
23681.1Shaya
23691.22Schopps	/* get card Vcc info */
23701.22Schopps	spsr =
23711.22Schopps	    bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh,
23721.22Schopps	    CB_SOCKET_STAT);
23731.22Schopps	if (spsr & CB_SOCKET_STAT_5VCARD) {
23741.22Schopps		DPRINTF(("5V card\n"));
23751.22Schopps		voltage = CARDBUS_VCC_5V | CARDBUS_VPP_VCC;
23761.22Schopps	} else if (spsr & CB_SOCKET_STAT_3VCARD) {
23771.22Schopps		DPRINTF(("3V card\n"));
23781.22Schopps		voltage = CARDBUS_VCC_3V | CARDBUS_VPP_VCC;
23791.22Schopps	} else {
23801.133Schristos		DPRINTF(("?V card, 0x%x\n", spsr));	/* XXX */
23811.22Schopps		return;
23821.22Schopps	}
23831.1Shaya
23841.108Smycroft	/* disable interrupts; assert RESET */
23851.104Smycroft	intr = Pcic_read(ph, PCIC_INTR);
23861.109Smycroft	intr &= PCIC_INTR_ENABLE;
23871.104Smycroft	Pcic_write(ph, PCIC_INTR, intr);
23881.104Smycroft
23891.104Smycroft	/* zero out the address windows */
23901.104Smycroft	Pcic_write(ph, PCIC_ADDRWIN_ENABLE, 0);
23911.100Smycroft
23921.104Smycroft	/* power down the socket to reset it, clear the card reset pin */
23931.104Smycroft	pccbb_power(sc, CARDBUS_VCC_0V | CARDBUS_VPP_0V);
23941.1Shaya
23951.108Smycroft	/* power off; assert output enable bit */
23961.108Smycroft	power = PCIC_PWRCTL_OE;
23971.108Smycroft	Pcic_write(ph, PCIC_PWRCTL, power);
23981.1Shaya
23991.106Smycroft	/* power up the socket */
24001.104Smycroft	if (pccbb_power(sc, voltage) == 0)
24011.104Smycroft		return;
24021.104Smycroft
24031.112Smycroft	/*
24041.112Smycroft	 * Table 4-18 and figure 4-6 of the PC Card specifiction say:
24051.112Smycroft	 * Vcc Rising Time (Tpr) = 100ms (handled in pccbb_power() above)
24061.112Smycroft	 * RESET Width (Th (Hi-z RESET)) = 1ms
24071.112Smycroft	 * RESET Width (Tw (RESET)) = 10us
24081.132Schristos	 *
24091.132Schristos	 * some machines require some more time to be settled
24101.132Schristos	 * for example old toshiba topic bridges!
24111.132Schristos	 * (100ms is added here).
24121.132Schristos	 */
24131.132Schristos	pccbb_pcmcia_delay(ph, 200 + 1, "pccen1");
24141.112Smycroft
24151.108Smycroft	/* negate RESET */
24161.22Schopps	intr |= PCIC_INTR_RESET;
24171.22Schopps	Pcic_write(ph, PCIC_INTR, intr);
24181.1Shaya
24191.108Smycroft	/*
24201.108Smycroft	 * RESET Setup Time (Tsu (RESET)) = 20ms
24211.108Smycroft	 */
24221.104Smycroft	pccbb_pcmcia_delay(ph, 20, "pccen2");
24231.1Shaya
24241.104Smycroft#ifdef DIAGNOSTIC
24251.104Smycroft	reg = Pcic_read(ph, PCIC_IF_STATUS);
24261.104Smycroft	if ((reg & PCIC_IF_STATUS_POWERACTIVE) == 0)
24271.104Smycroft		printf("pccbb_pcmcia_socket_enable: no power, status=%x\n", reg);
24281.56Sitohy#endif
24291.1Shaya
24301.22Schopps	/* wait for the chip to finish initializing */
24311.104Smycroft	if (pccbb_pcmcia_wait_ready(ph)) {
24321.133Schristos#ifdef DIAGNOSTIC
24331.133Schristos		printf("pccbb_pcmcia_socket_enable: never became ready\n");
24341.133Schristos#endif
24351.104Smycroft		/* XXX return a failure status?? */
24361.91Sbriggs		pccbb_power(sc, CARDBUS_VCC_0V | CARDBUS_VPP_0V);
24371.104Smycroft		Pcic_write(ph, PCIC_PWRCTL, 0);
24381.91Sbriggs		return;
24391.91Sbriggs	}
24401.1Shaya
24411.22Schopps	/* reinstall all the memory and io mappings */
24421.104Smycroft	for (win = 0; win < PCIC_MEM_WINS; ++win)
24431.104Smycroft		if (ph->memalloc & (1 << win))
24441.22Schopps			pccbb_pcmcia_do_mem_map(ph, win);
24451.104Smycroft	for (win = 0; win < PCIC_IO_WINS; ++win)
24461.104Smycroft		if (ph->ioalloc & (1 << win))
24471.22Schopps			pccbb_pcmcia_do_io_map(ph, win);
24481.1Shaya}
24491.1Shaya
24501.4Shaya/*
24511.4Shaya * STATIC void pccbb_pcmcia_socket_disable(pcmcia_chipset_handle_t *ph)
24521.4Shaya *
24531.4Shaya * This function disables the card.  All information is stored in
24541.4Shaya * the first argument, pcmcia_chipset_handle_t.
24551.4Shaya */
24561.1ShayaSTATIC void
24571.143Sdyoungpccbb_pcmcia_socket_disable(pcmcia_chipset_handle_t pch)
24581.1Shaya{
24591.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
24601.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
24611.104Smycroft	u_int8_t intr;
24621.22Schopps
24631.22Schopps	DPRINTF(("pccbb_pcmcia_socket_disable\n"));
24641.22Schopps
24651.108Smycroft	/* disable interrupts; assert RESET */
24661.103Smycroft	intr = Pcic_read(ph, PCIC_INTR);
24671.109Smycroft	intr &= PCIC_INTR_ENABLE;
24681.103Smycroft	Pcic_write(ph, PCIC_INTR, intr);
24691.102Smycroft
24701.102Smycroft	/* zero out the address windows */
24711.102Smycroft	Pcic_write(ph, PCIC_ADDRWIN_ENABLE, 0);
24721.22Schopps
24731.108Smycroft	/* power down the socket to reset it, clear the card reset pin */
24741.108Smycroft	pccbb_power(sc, CARDBUS_VCC_0V | CARDBUS_VPP_0V);
24751.108Smycroft
24761.104Smycroft	/* disable socket: negate output enable bit and power off */
24771.104Smycroft	Pcic_write(ph, PCIC_PWRCTL, 0);
24781.104Smycroft
24791.108Smycroft	/*
24801.108Smycroft	 * Vcc Falling Time (Tpf) = 300ms
24811.108Smycroft	 */
24821.104Smycroft	pccbb_pcmcia_delay(ph, 300, "pccwr1");
24831.101Smycroft}
24841.101Smycroft
24851.101SmycroftSTATIC void
24861.143Sdyoungpccbb_pcmcia_socket_settype(pcmcia_chipset_handle_t pch, int type)
24871.101Smycroft{
24881.101Smycroft	struct pcic_handle *ph = (struct pcic_handle *)pch;
24891.101Smycroft	u_int8_t intr;
24901.101Smycroft
24911.101Smycroft	/* set the card type */
24921.100Smycroft
24931.100Smycroft	intr = Pcic_read(ph, PCIC_INTR);
24941.102Smycroft	intr &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_CARDTYPE_MASK);
24951.101Smycroft	if (type == PCMCIA_IFTYPE_IO)
24961.101Smycroft		intr |= PCIC_INTR_CARDTYPE_IO;
24971.101Smycroft	else
24981.101Smycroft		intr |= PCIC_INTR_CARDTYPE_MEM;
24991.100Smycroft	Pcic_write(ph, PCIC_INTR, intr);
25001.101Smycroft
25011.101Smycroft	DPRINTF(("%s: pccbb_pcmcia_socket_settype %02x type %s %02x\n",
25021.101Smycroft	    ph->ph_parent->dv_xname, ph->sock,
25031.101Smycroft	    ((type == PCMCIA_IFTYPE_IO) ? "io" : "mem"), intr));
25041.1Shaya}
25051.1Shaya
25061.4Shaya/*
25071.1Shaya * STATIC int pccbb_pcmcia_card_detect(pcmcia_chipset_handle_t *ph)
25081.1Shaya *
25091.1Shaya * This function detects whether a card is in the slot or not.
25101.1Shaya * If a card is inserted, return 1.  Otherwise, return 0.
25111.4Shaya */
25121.1ShayaSTATIC int
25131.143Sdyoungpccbb_pcmcia_card_detect(pcmcia_chipset_handle_t pch)
25141.1Shaya{
25151.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
25161.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
25171.22Schopps
25181.22Schopps	DPRINTF(("pccbb_pcmcia_card_detect\n"));
25191.22Schopps	return pccbb_detect_card(sc) == 1 ? 1 : 0;
25201.1Shaya}
25211.1Shaya
25221.1Shaya#if 0
25231.1ShayaSTATIC int
25241.1Shayapccbb_new_pcmcia_mem_alloc(pcmcia_chipset_handle_t pch,
25251.22Schopps    bus_addr_t start, bus_size_t size, bus_size_t align, int speed, int flags,
25261.22Schopps    bus_space_tag_t * memtp bus_space_handle_t * memhp)
25271.1Shaya#endif
25281.4Shaya/*
25291.4Shaya * STATIC int pccbb_pcmcia_mem_alloc(pcmcia_chipset_handle_t pch,
25301.4Shaya *                                   bus_size_t size,
25311.4Shaya *                                   struct pcmcia_mem_handle *pcmhp)
25321.4Shaya *
25331.4Shaya * This function only allocates memory region for pccard. This
25341.32Senami * function never maps the allocated region to pccard memory area.
25351.4Shaya *
25361.4Shaya * XXX: Why the argument of start address is not in?
25371.4Shaya */
25381.22SchoppsSTATIC int
25391.143Sdyoungpccbb_pcmcia_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
25401.143Sdyoung    struct pcmcia_mem_handle *pcmhp)
25411.22Schopps{
25421.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
25431.22Schopps	bus_space_handle_t memh;
25441.22Schopps	bus_addr_t addr;
25451.22Schopps	bus_size_t sizepg;
25461.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
25471.1Shaya#if rbus
25481.22Schopps	rbus_tag_t rb;
25491.1Shaya#endif
25501.1Shaya
25511.91Sbriggs	/* Check that the card is still there. */
25521.91Sbriggs	if ((Pcic_read(ph, PCIC_IF_STATUS) & PCIC_IF_STATUS_CARDDETECT_MASK) !=
25531.91Sbriggs		    PCIC_IF_STATUS_CARDDETECT_PRESENT)
25541.91Sbriggs		return 1;
25551.91Sbriggs
25561.22Schopps	/* out of sc->memh, allocate as many pages as necessary */
25571.1Shaya
25581.22Schopps	/* convert size to PCIC pages */
25591.117Sperry	/*
25601.22Schopps	 * This is not enough; when the requested region is on the page
25611.22Schopps	 * boundaries, this may calculate wrong result.
25621.22Schopps	 */
25631.22Schopps	sizepg = (size + (PCIC_MEM_PAGESIZE - 1)) / PCIC_MEM_PAGESIZE;
25641.1Shaya#if 0
25651.22Schopps	if (sizepg > PCIC_MAX_MEM_PAGES) {
25661.22Schopps		return 1;
25671.22Schopps	}
25681.1Shaya#endif
25691.1Shaya
25701.22Schopps	if (!(sc->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32)) {
25711.22Schopps		return 1;
25721.22Schopps	}
25731.1Shaya
25741.22Schopps	addr = 0;		       /* XXX gcc -Wuninitialized */
25751.1Shaya
25761.1Shaya#if rbus
25771.22Schopps	rb = sc->sc_rbus_memt;
25781.22Schopps	if (rbus_space_alloc(rb, 0, sizepg * PCIC_MEM_PAGESIZE,
25791.22Schopps	    sizepg * PCIC_MEM_PAGESIZE - 1, PCIC_MEM_PAGESIZE, 0,
25801.22Schopps	    &addr, &memh)) {
25811.22Schopps		return 1;
25821.22Schopps	}
25831.1Shaya#else
25841.22Schopps	if (bus_space_alloc(sc->sc_memt, sc->sc_mem_start, sc->sc_mem_end,
25851.22Schopps	    sizepg * PCIC_MEM_PAGESIZE, PCIC_MEM_PAGESIZE,
25861.22Schopps	    0, /* boundary */
25871.22Schopps	    0,	/* flags */
25881.22Schopps	    &addr, &memh)) {
25891.22Schopps		return 1;
25901.22Schopps	}
25911.1Shaya#endif
25921.1Shaya
25931.95Schristos	DPRINTF(("pccbb_pcmcia_alloc_mem: addr 0x%lx size 0x%lx, "
25941.95Schristos	    "realsize 0x%lx\n", (unsigned long)addr, (unsigned long)size,
25951.95Schristos	    (unsigned long)sizepg * PCIC_MEM_PAGESIZE));
25961.22Schopps
25971.22Schopps	pcmhp->memt = sc->sc_memt;
25981.22Schopps	pcmhp->memh = memh;
25991.22Schopps	pcmhp->addr = addr;
26001.22Schopps	pcmhp->size = size;
26011.22Schopps	pcmhp->realsize = sizepg * PCIC_MEM_PAGESIZE;
26021.22Schopps	/* What is mhandle?  I feel it is very dirty and it must go trush. */
26031.22Schopps	pcmhp->mhandle = 0;
26041.22Schopps	/* No offset???  Funny. */
26051.1Shaya
26061.22Schopps	return 0;
26071.1Shaya}
26081.1Shaya
26091.4Shaya/*
26101.4Shaya * STATIC void pccbb_pcmcia_mem_free(pcmcia_chipset_handle_t pch,
26111.4Shaya *                                   struct pcmcia_mem_handle *pcmhp)
26121.4Shaya *
26131.32Senami * This function release the memory space allocated by the function
26141.4Shaya * pccbb_pcmcia_mem_alloc().
26151.4Shaya */
26161.22SchoppsSTATIC void
26171.143Sdyoungpccbb_pcmcia_mem_free(pcmcia_chipset_handle_t pch,
26181.143Sdyoung    struct pcmcia_mem_handle *pcmhp)
26191.1Shaya{
26201.1Shaya#if rbus
26211.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
26221.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
26231.1Shaya
26241.22Schopps	rbus_space_free(sc->sc_rbus_memt, pcmhp->memh, pcmhp->realsize, NULL);
26251.1Shaya#else
26261.22Schopps	bus_space_free(pcmhp->memt, pcmhp->memh, pcmhp->realsize);
26271.1Shaya#endif
26281.1Shaya}
26291.1Shaya
26301.4Shaya/*
26311.4Shaya * STATIC void pccbb_pcmcia_do_mem_map(struct pcic_handle *ph, int win)
26321.4Shaya *
26331.32Senami * This function release the memory space allocated by the function
26341.4Shaya * pccbb_pcmcia_mem_alloc().
26351.4Shaya */
26361.22SchoppsSTATIC void
26371.143Sdyoungpccbb_pcmcia_do_mem_map(struct pcic_handle *ph, int win)
26381.1Shaya{
26391.22Schopps	int regbase_win;
26401.22Schopps	bus_addr_t phys_addr;
26411.22Schopps	bus_addr_t phys_end;
26421.1Shaya
26431.1Shaya#define PCIC_SMM_START_LOW 0
26441.1Shaya#define PCIC_SMM_START_HIGH 1
26451.1Shaya#define PCIC_SMM_STOP_LOW 2
26461.1Shaya#define PCIC_SMM_STOP_HIGH 3
26471.1Shaya#define PCIC_CMA_LOW 4
26481.1Shaya#define PCIC_CMA_HIGH 5
26491.1Shaya
26501.22Schopps	u_int8_t start_low, start_high = 0;
26511.22Schopps	u_int8_t stop_low, stop_high;
26521.22Schopps	u_int8_t off_low, off_high;
26531.22Schopps	u_int8_t mem_window;
26541.22Schopps	int reg;
26551.22Schopps
26561.22Schopps	int kind = ph->mem[win].kind & ~PCMCIA_WIDTH_MEM_MASK;
26571.22Schopps	int mem8 =
26581.24Sthorpej	    (ph->mem[win].kind & PCMCIA_WIDTH_MEM_MASK) == PCMCIA_WIDTH_MEM8
26591.24Sthorpej	    || (kind == PCMCIA_MEM_ATTR);
26601.12Sjoda
26611.22Schopps	regbase_win = 0x10 + win * 0x08;
26621.1Shaya
26631.22Schopps	phys_addr = ph->mem[win].addr;
26641.22Schopps	phys_end = phys_addr + ph->mem[win].size;
26651.1Shaya
26661.22Schopps	DPRINTF(("pccbb_pcmcia_do_mem_map: start 0x%lx end 0x%lx off 0x%lx\n",
26671.95Schristos	    (unsigned long)phys_addr, (unsigned long)phys_end,
26681.95Schristos	    (unsigned long)ph->mem[win].offset));
26691.1Shaya
26701.1Shaya#define PCIC_MEMREG_LSB_SHIFT PCIC_SYSMEM_ADDRX_SHIFT
26711.1Shaya#define PCIC_MEMREG_MSB_SHIFT (PCIC_SYSMEM_ADDRX_SHIFT + 8)
26721.1Shaya#define PCIC_MEMREG_WIN_SHIFT (PCIC_SYSMEM_ADDRX_SHIFT + 12)
26731.1Shaya
26741.22Schopps	/* bit 19:12 */
26751.22Schopps	start_low = (phys_addr >> PCIC_MEMREG_LSB_SHIFT) & 0xff;
26761.22Schopps	/* bit 23:20 and bit 7 on */
26771.22Schopps	start_high = ((phys_addr >> PCIC_MEMREG_MSB_SHIFT) & 0x0f)
26781.22Schopps	    |(mem8 ? 0 : PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT);
26791.22Schopps	/* bit 31:24, for 32-bit address */
26801.22Schopps	mem_window = (phys_addr >> PCIC_MEMREG_WIN_SHIFT) & 0xff;
26811.22Schopps
26821.22Schopps	Pcic_write(ph, regbase_win + PCIC_SMM_START_LOW, start_low);
26831.22Schopps	Pcic_write(ph, regbase_win + PCIC_SMM_START_HIGH, start_high);
26841.22Schopps
26851.22Schopps	if (((struct pccbb_softc *)ph->
26861.22Schopps	    ph_parent)->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) {
26871.22Schopps		Pcic_write(ph, 0x40 + win, mem_window);
26881.22Schopps	}
26891.1Shaya
26901.22Schopps	stop_low = (phys_end >> PCIC_MEMREG_LSB_SHIFT) & 0xff;
26911.22Schopps	stop_high = ((phys_end >> PCIC_MEMREG_MSB_SHIFT) & 0x0f)
26921.22Schopps	    | PCIC_SYSMEM_ADDRX_STOP_MSB_WAIT2;	/* wait 2 cycles */
26931.22Schopps	/* XXX Geee, WAIT2!! Crazy!!  I must rewrite this routine. */
26941.22Schopps
26951.22Schopps	Pcic_write(ph, regbase_win + PCIC_SMM_STOP_LOW, stop_low);
26961.22Schopps	Pcic_write(ph, regbase_win + PCIC_SMM_STOP_HIGH, stop_high);
26971.22Schopps
26981.22Schopps	off_low = (ph->mem[win].offset >> PCIC_CARDMEM_ADDRX_SHIFT) & 0xff;
26991.22Schopps	off_high = ((ph->mem[win].offset >> (PCIC_CARDMEM_ADDRX_SHIFT + 8))
27001.22Schopps	    & PCIC_CARDMEM_ADDRX_MSB_ADDR_MASK)
27011.22Schopps	    | ((kind == PCMCIA_MEM_ATTR) ?
27021.22Schopps	    PCIC_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0);
27031.22Schopps
27041.22Schopps	Pcic_write(ph, regbase_win + PCIC_CMA_LOW, off_low);
27051.22Schopps	Pcic_write(ph, regbase_win + PCIC_CMA_HIGH, off_high);
27061.22Schopps
27071.22Schopps	reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE);
27081.22Schopps	reg |= ((1 << win) | PCIC_ADDRWIN_ENABLE_MEMCS16);
27091.22Schopps	Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg);
27101.1Shaya
27111.133Schristos#if defined(CBB_DEBUG)
27121.22Schopps	{
27131.22Schopps		int r1, r2, r3, r4, r5, r6, r7 = 0;
27141.1Shaya
27151.22Schopps		r1 = Pcic_read(ph, regbase_win + PCIC_SMM_START_LOW);
27161.22Schopps		r2 = Pcic_read(ph, regbase_win + PCIC_SMM_START_HIGH);
27171.22Schopps		r3 = Pcic_read(ph, regbase_win + PCIC_SMM_STOP_LOW);
27181.22Schopps		r4 = Pcic_read(ph, regbase_win + PCIC_SMM_STOP_HIGH);
27191.22Schopps		r5 = Pcic_read(ph, regbase_win + PCIC_CMA_LOW);
27201.22Schopps		r6 = Pcic_read(ph, regbase_win + PCIC_CMA_HIGH);
27211.22Schopps		if (((struct pccbb_softc *)(ph->
27221.22Schopps		    ph_parent))->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) {
27231.22Schopps			r7 = Pcic_read(ph, 0x40 + win);
27241.22Schopps		}
27251.22Schopps
27261.133Schristos		printf("pccbb_pcmcia_do_mem_map window %d: %02x%02x %02x%02x "
27271.133Schristos		    "%02x%02x", win, r1, r2, r3, r4, r5, r6);
27281.22Schopps		if (((struct pccbb_softc *)(ph->
27291.22Schopps		    ph_parent))->sc_pcmcia_flags & PCCBB_PCMCIA_MEM_32) {
27301.133Schristos			printf(" %02x", r7);
27311.22Schopps		}
27321.133Schristos		printf("\n");
27331.22Schopps	}
27341.1Shaya#endif
27351.1Shaya}
27361.1Shaya
27371.4Shaya/*
27381.4Shaya * STATIC int pccbb_pcmcia_mem_map(pcmcia_chipset_handle_t pch, int kind,
27391.4Shaya *                                 bus_addr_t card_addr, bus_size_t size,
27401.4Shaya *                                 struct pcmcia_mem_handle *pcmhp,
27411.4Shaya *                                 bus_addr_t *offsetp, int *windowp)
27421.4Shaya *
27431.32Senami * This function maps memory space allocated by the function
27441.4Shaya * pccbb_pcmcia_mem_alloc().
27451.4Shaya */
27461.22SchoppsSTATIC int
27471.143Sdyoungpccbb_pcmcia_mem_map(pcmcia_chipset_handle_t pch, int kind,
27481.143Sdyoung    bus_addr_t card_addr, bus_size_t size, struct pcmcia_mem_handle *pcmhp,
27491.143Sdyoung    bus_addr_t *offsetp, int *windowp)
27501.22Schopps{
27511.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
27521.22Schopps	bus_addr_t busaddr;
27531.22Schopps	long card_offset;
27541.22Schopps	int win;
27551.91Sbriggs
27561.91Sbriggs	/* Check that the card is still there. */
27571.91Sbriggs	if ((Pcic_read(ph, PCIC_IF_STATUS) & PCIC_IF_STATUS_CARDDETECT_MASK) !=
27581.91Sbriggs		    PCIC_IF_STATUS_CARDDETECT_PRESENT)
27591.91Sbriggs		return 1;
27601.22Schopps
27611.22Schopps	for (win = 0; win < PCIC_MEM_WINS; ++win) {
27621.22Schopps		if ((ph->memalloc & (1 << win)) == 0) {
27631.22Schopps			ph->memalloc |= (1 << win);
27641.22Schopps			break;
27651.22Schopps		}
27661.22Schopps	}
27671.1Shaya
27681.22Schopps	if (win == PCIC_MEM_WINS) {
27691.22Schopps		return 1;
27701.22Schopps	}
27711.1Shaya
27721.22Schopps	*windowp = win;
27731.1Shaya
27741.22Schopps	/* XXX this is pretty gross */
27751.1Shaya
27761.22Schopps	if (((struct pccbb_softc *)ph->ph_parent)->sc_memt != pcmhp->memt) {
27771.22Schopps		panic("pccbb_pcmcia_mem_map memt is bogus");
27781.22Schopps	}
27791.1Shaya
27801.22Schopps	busaddr = pcmhp->addr;
27811.1Shaya
27821.117Sperry	/*
27831.22Schopps	 * compute the address offset to the pcmcia address space for the
27841.22Schopps	 * pcic.  this is intentionally signed.  The masks and shifts below
27851.22Schopps	 * will cause TRT to happen in the pcic registers.  Deal with making
27861.22Schopps	 * sure the address is aligned, and return the alignment offset.
27871.22Schopps	 */
27881.22Schopps
27891.22Schopps	*offsetp = card_addr % PCIC_MEM_PAGESIZE;
27901.22Schopps	card_addr -= *offsetp;
27911.22Schopps
27921.22Schopps	DPRINTF(("pccbb_pcmcia_mem_map window %d bus %lx+%lx+%lx at card addr "
27931.22Schopps	    "%lx\n", win, (u_long) busaddr, (u_long) * offsetp, (u_long) size,
27941.22Schopps	    (u_long) card_addr));
27951.22Schopps
27961.117Sperry	/*
27971.22Schopps	 * include the offset in the size, and decrement size by one, since
27981.22Schopps	 * the hw wants start/stop
27991.22Schopps	 */
28001.22Schopps	size += *offsetp - 1;
28011.22Schopps
28021.22Schopps	card_offset = (((long)card_addr) - ((long)busaddr));
28031.22Schopps
28041.22Schopps	ph->mem[win].addr = busaddr;
28051.22Schopps	ph->mem[win].size = size;
28061.22Schopps	ph->mem[win].offset = card_offset;
28071.22Schopps	ph->mem[win].kind = kind;
28081.1Shaya
28091.22Schopps	pccbb_pcmcia_do_mem_map(ph, win);
28101.1Shaya
28111.22Schopps	return 0;
28121.1Shaya}
28131.1Shaya
28141.4Shaya/*
28151.4Shaya * STATIC int pccbb_pcmcia_mem_unmap(pcmcia_chipset_handle_t pch,
28161.4Shaya *                                   int window)
28171.4Shaya *
28181.32Senami * This function unmaps memory space which mapped by the function
28191.4Shaya * pccbb_pcmcia_mem_map().
28201.4Shaya */
28211.22SchoppsSTATIC void
28221.143Sdyoungpccbb_pcmcia_mem_unmap(pcmcia_chipset_handle_t pch, int window)
28231.1Shaya{
28241.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
28251.22Schopps	int reg;
28261.1Shaya
28271.22Schopps	if (window >= PCIC_MEM_WINS) {
28281.22Schopps		panic("pccbb_pcmcia_mem_unmap: window out of range");
28291.22Schopps	}
28301.1Shaya
28311.22Schopps	reg = Pcic_read(ph, PCIC_ADDRWIN_ENABLE);
28321.22Schopps	reg &= ~(1 << window);
28331.22Schopps	Pcic_write(ph, PCIC_ADDRWIN_ENABLE, reg);
28341.1Shaya
28351.22Schopps	ph->memalloc &= ~(1 << window);
28361.1Shaya}
28371.1Shaya
28381.1Shaya#if defined PCCBB_PCMCIA_POLL
28391.1Shayastruct pccbb_poll_str {
28401.22Schopps	void *arg;
28411.116Sperry	int (*func)(void *);
28421.22Schopps	int level;
28431.22Schopps	struct pcic_handle *ph;
28441.22Schopps	int count;
28451.22Schopps	int num;
28461.37Sthorpej	struct callout poll_ch;
28471.1Shaya};
28481.1Shaya
28491.1Shayastatic struct pccbb_poll_str pccbb_poll[10];
28501.1Shayastatic int pccbb_poll_n = 0;
28511.1Shaya
28521.116Sperrystatic void pccbb_pcmcia_poll(void *arg);
28531.1Shaya
28541.1Shayastatic void
28551.143Sdyoungpccbb_pcmcia_poll(void *arg)
28561.1Shaya{
28571.22Schopps	struct pccbb_poll_str *poll = arg;
28581.22Schopps	struct pcic_handle *ph = poll->ph;
28591.22Schopps	struct pccbb_softc *sc = ph->sc;
28601.22Schopps	int s;
28611.22Schopps	u_int32_t spsr;		       /* socket present-state reg */
28621.22Schopps
28631.37Sthorpej	callout_reset(&poll->poll_ch, hz * 2, pccbb_pcmcia_poll, arg);
28641.22Schopps	switch (poll->level) {
28651.22Schopps	case IPL_NET:
28661.22Schopps		s = splnet();
28671.22Schopps		break;
28681.22Schopps	case IPL_BIO:
28691.22Schopps		s = splbio();
28701.22Schopps		break;
28711.22Schopps	case IPL_TTY:		       /* fallthrough */
28721.22Schopps	default:
28731.22Schopps		s = spltty();
28741.22Schopps		break;
28751.22Schopps	}
28761.22Schopps
28771.145Schristos	spsr = bus_space_read_4(sc->sc_base_memt, sc->sc_base_memh,
28781.22Schopps	    CB_SOCKET_STAT);
28791.1Shaya
28801.1Shaya#if defined PCCBB_PCMCIA_POLL_ONLY && defined LEVEL2
28811.22Schopps	if (!(spsr & 0x40))	       /* CINT low */
28821.1Shaya#else
28831.22Schopps	if (1)
28841.1Shaya#endif
28851.22Schopps	{
28861.22Schopps		if ((*poll->func) (poll->arg) > 0) {
28871.22Schopps			++poll->count;
28881.73Schristos/*      printf("intr: reported from poller, 0x%x\n", spsr); */
28891.1Shaya#if defined LEVEL2
28901.22Schopps		} else {
28911.22Schopps			printf("intr: miss! 0x%x\n", spsr);
28921.1Shaya#endif
28931.22Schopps		}
28941.22Schopps	}
28951.22Schopps	splx(s);
28961.1Shaya}
28971.1Shaya#endif /* defined CB_PCMCIA_POLL */
28981.1Shaya
28991.4Shaya/*
29001.4Shaya * STATIC void *pccbb_pcmcia_intr_establish(pcmcia_chipset_handle_t pch,
29011.4Shaya *                                          struct pcmcia_function *pf,
29021.4Shaya *                                          int ipl,
29031.4Shaya *                                          int (*func)(void *),
29041.4Shaya *                                          void *arg);
29051.4Shaya *
29061.4Shaya * This function enables PC-Card interrupt.  PCCBB uses PCI interrupt line.
29071.4Shaya */
29081.1ShayaSTATIC void *
29091.143Sdyoungpccbb_pcmcia_intr_establish(pcmcia_chipset_handle_t pch,
29101.143Sdyoung    struct pcmcia_function *pf, int ipl, int (*func)(void *), void *arg)
29111.22Schopps{
29121.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
29131.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
29141.22Schopps
29151.22Schopps	if (!(pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)) {
29161.22Schopps		/* what should I do? */
29171.22Schopps		if ((pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)) {
29181.95Schristos			DPRINTF(("%s does not provide edge nor pulse "
29191.95Schristos			    "interrupt\n", sc->sc_dev.dv_xname));
29201.22Schopps			return NULL;
29211.22Schopps		}
29221.117Sperry		/*
29231.22Schopps		 * XXX Noooooo!  The interrupt flag must set properly!!
29241.22Schopps		 * dumb pcmcia driver!!
29251.22Schopps		 */
29261.22Schopps	}
29271.1Shaya
29281.88Snakayama	return pccbb_intr_establish(sc, 0, ipl, func, arg);
29291.1Shaya}
29301.1Shaya
29311.4Shaya/*
29321.4Shaya * STATIC void pccbb_pcmcia_intr_disestablish(pcmcia_chipset_handle_t pch,
29331.4Shaya *                                            void *ih)
29341.4Shaya *
29351.4Shaya * This function disables PC-Card interrupt.
29361.4Shaya */
29371.1ShayaSTATIC void
29381.143Sdyoungpccbb_pcmcia_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
29391.1Shaya{
29401.22Schopps	struct pcic_handle *ph = (struct pcic_handle *)pch;
29411.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ph->ph_parent;
29421.1Shaya
29431.26Shaya	pccbb_intr_disestablish(sc, ih);
29441.1Shaya}
29451.1Shaya
29461.1Shaya#if rbus
29471.4Shaya/*
29481.4Shaya * static int
29491.4Shaya * pccbb_rbus_cb_space_alloc(cardbus_chipset_tag_t ct, rbus_tag_t rb,
29501.4Shaya *			    bus_addr_t addr, bus_size_t size,
29511.4Shaya *			    bus_addr_t mask, bus_size_t align,
29521.4Shaya *			    int flags, bus_addr_t *addrp;
29531.4Shaya *			    bus_space_handle_t *bshp)
29541.4Shaya *
29551.4Shaya *   This function allocates a portion of memory or io space for
29561.4Shaya *   clients.  This function is called from CardBus card drivers.
29571.4Shaya */
29581.1Shayastatic int
29591.143Sdyoungpccbb_rbus_cb_space_alloc(cardbus_chipset_tag_t ct, rbus_tag_t rb,
29601.143Sdyoung    bus_addr_t addr, bus_size_t size, bus_addr_t mask, bus_size_t align,
29611.143Sdyoung    int flags, bus_addr_t *addrp, bus_space_handle_t *bshp)
29621.22Schopps{
29631.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
29641.22Schopps
29651.95Schristos	DPRINTF(("pccbb_rbus_cb_space_alloc: addr 0x%lx, size 0x%lx, "
29661.95Schristos	    "mask 0x%lx, align 0x%lx\n", (unsigned long)addr,
29671.95Schristos	    (unsigned long)size, (unsigned long)mask, (unsigned long)align));
29681.1Shaya
29691.22Schopps	if (align == 0) {
29701.22Schopps		align = size;
29711.22Schopps	}
29721.1Shaya
29731.22Schopps	if (rb->rb_bt == sc->sc_memt) {
29741.22Schopps		if (align < 16) {
29751.22Schopps			return 1;
29761.68Syamt		}
29771.76Shaya		/*
29781.76Shaya		 * XXX: align more than 0x1000 to avoid overwrapping
29791.76Shaya		 * memory windows for two or more devices.  0x1000
29801.76Shaya		 * means memory window's granularity.
29811.76Shaya		 *
29821.76Shaya		 * Two or more devices should be able to share same
29831.76Shaya		 * memory window region.  However, overrapping memory
29841.76Shaya		 * window is not good because some devices, such as
29851.76Shaya		 * 3Com 3C575[BC], have a broken address decoder and
29861.76Shaya		 * intrude other's memory region.
29871.76Shaya		 */
29881.68Syamt		if (align < 0x1000) {
29891.68Syamt			align = 0x1000;
29901.22Schopps		}
29911.22Schopps	} else if (rb->rb_bt == sc->sc_iot) {
29921.22Schopps		if (align < 4) {
29931.22Schopps			return 1;
29941.22Schopps		}
29951.36Shaya		/* XXX: hack for avoiding ISA image */
29961.36Shaya		if (mask < 0x0100) {
29971.36Shaya			mask = 0x3ff;
29981.36Shaya			addr = 0x300;
29991.36Shaya		}
30001.36Shaya
30011.22Schopps	} else {
30021.95Schristos		DPRINTF(("pccbb_rbus_cb_space_alloc: Bus space tag 0x%lx is "
30031.95Schristos		    "NOT used. io: 0x%lx, mem: 0x%lx\n",
30041.95Schristos		    (unsigned long)rb->rb_bt, (unsigned long)sc->sc_iot,
30051.95Schristos		    (unsigned long)sc->sc_memt));
30061.22Schopps		return 1;
30071.22Schopps		/* XXX: panic here? */
30081.22Schopps	}
30091.1Shaya
30101.22Schopps	if (rbus_space_alloc(rb, addr, size, mask, align, flags, addrp, bshp)) {
30111.22Schopps		printf("%s: <rbus> no bus space\n", sc->sc_dev.dv_xname);
30121.22Schopps		return 1;
30131.22Schopps	}
30141.1Shaya
30151.22Schopps	pccbb_open_win(sc, rb->rb_bt, *addrp, size, *bshp, 0);
30161.1Shaya
30171.22Schopps	return 0;
30181.1Shaya}
30191.1Shaya
30201.4Shaya/*
30211.4Shaya * static int
30221.4Shaya * pccbb_rbus_cb_space_free(cardbus_chipset_tag_t *ct, rbus_tag_t rb,
30231.4Shaya *			   bus_space_handle_t *bshp, bus_size_t size);
30241.4Shaya *
30251.4Shaya *   This function is called from CardBus card drivers.
30261.4Shaya */
30271.1Shayastatic int
30281.143Sdyoungpccbb_rbus_cb_space_free(cardbus_chipset_tag_t ct, rbus_tag_t rb,
30291.143Sdyoung    bus_space_handle_t bsh, bus_size_t size)
30301.22Schopps{
30311.22Schopps	struct pccbb_softc *sc = (struct pccbb_softc *)ct;
30321.22Schopps	bus_space_tag_t bt = rb->rb_bt;
30331.22Schopps
30341.22Schopps	pccbb_close_win(sc, bt, bsh, size);
30351.22Schopps
30361.22Schopps	if (bt == sc->sc_memt) {
30371.22Schopps	} else if (bt == sc->sc_iot) {
30381.22Schopps	} else {
30391.22Schopps		return 1;
30401.22Schopps		/* XXX: panic here? */
30411.22Schopps	}
30421.1Shaya
30431.22Schopps	return rbus_space_free(rb, bsh, size, NULL);
30441.1Shaya}
30451.1Shaya#endif /* rbus */
30461.1Shaya
30471.1Shaya#if rbus
30481.1Shaya
30491.1Shayastatic int
30501.143Sdyoungpccbb_open_win(struct pccbb_softc *sc, bus_space_tag_t bst, bus_addr_t addr,
30511.143Sdyoung    bus_size_t size, bus_space_handle_t bsh, int flags)
30521.22Schopps{
30531.27Sthorpej	struct pccbb_win_chain_head *head;
30541.22Schopps	bus_addr_t align;
30551.22Schopps
30561.27Sthorpej	head = &sc->sc_iowindow;
30571.22Schopps	align = 0x04;
30581.22Schopps	if (sc->sc_memt == bst) {
30591.27Sthorpej		head = &sc->sc_memwindow;
30601.22Schopps		align = 0x1000;
30611.95Schristos		DPRINTF(("using memory window, 0x%lx 0x%lx 0x%lx\n\n",
30621.95Schristos		    (unsigned long)sc->sc_iot, (unsigned long)sc->sc_memt,
30631.95Schristos		    (unsigned long)bst));
30641.22Schopps	}
30651.1Shaya
30661.27Sthorpej	if (pccbb_winlist_insert(head, addr, size, bsh, flags)) {
30671.27Sthorpej		printf("%s: pccbb_open_win: %s winlist insert failed\n",
30681.27Sthorpej		    sc->sc_dev.dv_xname,
30691.27Sthorpej		    (head == &sc->sc_memwindow) ? "mem" : "io");
30701.22Schopps	}
30711.22Schopps	pccbb_winset(align, sc, bst);
30721.1Shaya
30731.22Schopps	return 0;
30741.1Shaya}
30751.1Shaya
30761.1Shayastatic int
30771.143Sdyoungpccbb_close_win(struct pccbb_softc *sc, bus_space_tag_t bst,
30781.143Sdyoung    bus_space_handle_t bsh, bus_size_t size)
30791.22Schopps{
30801.27Sthorpej	struct pccbb_win_chain_head *head;
30811.22Schopps	bus_addr_t align;
30821.22Schopps
30831.27Sthorpej	head = &sc->sc_iowindow;
30841.22Schopps	align = 0x04;
30851.22Schopps	if (sc->sc_memt == bst) {
30861.27Sthorpej		head = &sc->sc_memwindow;
30871.22Schopps		align = 0x1000;
30881.22Schopps	}
30891.1Shaya
30901.27Sthorpej	if (pccbb_winlist_delete(head, bsh, size)) {
30911.27Sthorpej		printf("%s: pccbb_close_win: %s winlist delete failed\n",
30921.27Sthorpej		    sc->sc_dev.dv_xname,
30931.27Sthorpej		    (head == &sc->sc_memwindow) ? "mem" : "io");
30941.22Schopps	}
30951.22Schopps	pccbb_winset(align, sc, bst);
30961.1Shaya
30971.22Schopps	return 0;
30981.1Shaya}
30991.1Shaya
31001.1Shayastatic int
31011.143Sdyoungpccbb_winlist_insert(struct pccbb_win_chain_head *head, bus_addr_t start,
31021.143Sdyoung    bus_size_t size, bus_space_handle_t bsh, int flags)
31031.22Schopps{
31041.27Sthorpej	struct pccbb_win_chain *chainp, *elem;
31051.22Schopps
31061.27Sthorpej	if ((elem = malloc(sizeof(struct pccbb_win_chain), M_DEVBUF,
31071.27Sthorpej	    M_NOWAIT)) == NULL)
31081.35Senami		return (1);		/* fail */
31091.1Shaya
31101.27Sthorpej	elem->wc_start = start;
31111.27Sthorpej	elem->wc_end = start + (size - 1);
31121.27Sthorpej	elem->wc_handle = bsh;
31131.27Sthorpej	elem->wc_flags = flags;
31141.1Shaya
31151.154Sdyoung	TAILQ_FOREACH(chainp, head, wc_list) {
31161.154Sdyoung		if (chainp->wc_end >= start)
31171.154Sdyoung			break;
31181.154Sdyoung	}
31191.154Sdyoung	if (chainp != NULL)
31201.27Sthorpej		TAILQ_INSERT_AFTER(head, chainp, elem, wc_list);
31211.154Sdyoung	else
31221.154Sdyoung		TAILQ_INSERT_TAIL(head, elem, wc_list);
31231.35Senami	return (0);
31241.1Shaya}
31251.1Shaya
31261.1Shayastatic int
31271.143Sdyoungpccbb_winlist_delete(struct pccbb_win_chain_head *head, bus_space_handle_t bsh,
31281.143Sdyoung    bus_size_t size)
31291.1Shaya{
31301.27Sthorpej	struct pccbb_win_chain *chainp;
31311.1Shaya
31321.154Sdyoung	TAILQ_FOREACH(chainp, head, wc_list) {
31331.154Sdyoung		if (memcmp(&chainp->wc_handle, &bsh, sizeof(bsh)) == 0)
31341.154Sdyoung			break;
31351.154Sdyoung	}
31361.154Sdyoung	if (chainp == NULL)
31371.154Sdyoung		return 1;	       /* fail: no candidate to remove */
31381.1Shaya
31391.154Sdyoung	if ((chainp->wc_end - chainp->wc_start) != (size - 1)) {
31401.154Sdyoung		printf("pccbb_winlist_delete: window 0x%lx size "
31411.154Sdyoung		    "inconsistent: 0x%lx, 0x%lx\n",
31421.154Sdyoung		    (unsigned long)chainp->wc_start,
31431.154Sdyoung		    (unsigned long)(chainp->wc_end - chainp->wc_start),
31441.154Sdyoung		    (unsigned long)(size - 1));
31451.154Sdyoung		return 1;
31461.154Sdyoung	}
31471.1Shaya
31481.154Sdyoung	TAILQ_REMOVE(head, chainp, wc_list);
31491.154Sdyoung	free(chainp, M_DEVBUF);
31501.1Shaya
31511.154Sdyoung	return 0;
31521.1Shaya}
31531.1Shaya
31541.1Shayastatic void
31551.143Sdyoungpccbb_winset(bus_addr_t align, struct pccbb_softc *sc, bus_space_tag_t bst)
31561.22Schopps{
31571.22Schopps	pci_chipset_tag_t pc;
31581.22Schopps	pcitag_t tag;
31591.22Schopps	bus_addr_t mask = ~(align - 1);
31601.22Schopps	struct {
31611.22Schopps		cardbusreg_t win_start;
31621.22Schopps		cardbusreg_t win_limit;
31631.22Schopps		int win_flags;
31641.22Schopps	} win[2];
31651.22Schopps	struct pccbb_win_chain *chainp;
31661.22Schopps	int offs;
31671.22Schopps
31681.61Senami	win[0].win_start = win[1].win_start = 0xffffffff;
31691.61Senami	win[0].win_limit = win[1].win_limit = 0;
31701.61Senami	win[0].win_flags = win[1].win_flags = 0;
31711.22Schopps
31721.27Sthorpej	chainp = TAILQ_FIRST(&sc->sc_iowindow);
31731.22Schopps	offs = 0x2c;
31741.22Schopps	if (sc->sc_memt == bst) {
31751.27Sthorpej		chainp = TAILQ_FIRST(&sc->sc_memwindow);
31761.22Schopps		offs = 0x1c;
31771.22Schopps	}
31781.1Shaya
31791.27Sthorpej	if (chainp != NULL) {
31801.22Schopps		win[0].win_start = chainp->wc_start & mask;
31811.22Schopps		win[0].win_limit = chainp->wc_end & mask;
31821.22Schopps		win[0].win_flags = chainp->wc_flags;
31831.27Sthorpej		chainp = TAILQ_NEXT(chainp, wc_list);
31841.1Shaya	}
31851.1Shaya
31861.27Sthorpej	for (; chainp != NULL; chainp = TAILQ_NEXT(chainp, wc_list)) {
31871.22Schopps		if (win[1].win_start == 0xffffffff) {
31881.22Schopps			/* window 1 is not used */
31891.22Schopps			if ((win[0].win_flags == chainp->wc_flags) &&
31901.22Schopps			    (win[0].win_limit + align >=
31911.22Schopps			    (chainp->wc_start & mask))) {
31921.27Sthorpej				/* concatenate */
31931.22Schopps				win[0].win_limit = chainp->wc_end & mask;
31941.22Schopps			} else {
31951.22Schopps				/* make new window */
31961.22Schopps				win[1].win_start = chainp->wc_start & mask;
31971.22Schopps				win[1].win_limit = chainp->wc_end & mask;
31981.22Schopps				win[1].win_flags = chainp->wc_flags;
31991.22Schopps			}
32001.22Schopps			continue;
32011.22Schopps		}
32021.22Schopps
32031.32Senami		/* Both windows are engaged. */
32041.22Schopps		if (win[0].win_flags == win[1].win_flags) {
32051.22Schopps			/* same flags */
32061.22Schopps			if (win[0].win_flags == chainp->wc_flags) {
32071.22Schopps				if (win[1].win_start - (win[0].win_limit +
32081.22Schopps				    align) <
32091.22Schopps				    (chainp->wc_start & mask) -
32101.22Schopps				    ((chainp->wc_end & mask) + align)) {
32111.22Schopps					/*
32121.22Schopps					 * merge window 0 and 1, and set win1
32131.22Schopps					 * to chainp
32141.22Schopps					 */
32151.22Schopps					win[0].win_limit = win[1].win_limit;
32161.22Schopps					win[1].win_start =
32171.22Schopps					    chainp->wc_start & mask;
32181.22Schopps					win[1].win_limit =
32191.22Schopps					    chainp->wc_end & mask;
32201.22Schopps				} else {
32211.22Schopps					win[1].win_limit =
32221.22Schopps					    chainp->wc_end & mask;
32231.22Schopps				}
32241.22Schopps			} else {
32251.22Schopps				/* different flags */
32261.22Schopps
32271.27Sthorpej				/* concatenate win0 and win1 */
32281.22Schopps				win[0].win_limit = win[1].win_limit;
32291.22Schopps				/* allocate win[1] to new space */
32301.22Schopps				win[1].win_start = chainp->wc_start & mask;
32311.22Schopps				win[1].win_limit = chainp->wc_end & mask;
32321.22Schopps				win[1].win_flags = chainp->wc_flags;
32331.22Schopps			}
32341.22Schopps		} else {
32351.22Schopps			/* the flags of win[0] and win[1] is different */
32361.22Schopps			if (win[0].win_flags == chainp->wc_flags) {
32371.22Schopps				win[0].win_limit = chainp->wc_end & mask;
32381.22Schopps				/*
32391.22Schopps				 * XXX this creates overlapping windows, so
32401.22Schopps				 * what should the poor bridge do if one is
32411.22Schopps				 * cachable, and the other is not?
32421.22Schopps				 */
32431.22Schopps				printf("%s: overlapping windows\n",
32441.22Schopps				    sc->sc_dev.dv_xname);
32451.22Schopps			} else {
32461.22Schopps				win[1].win_limit = chainp->wc_end & mask;
32471.22Schopps			}
32481.22Schopps		}
32491.22Schopps	}
32501.1Shaya
32511.22Schopps	pc = sc->sc_pc;
32521.22Schopps	tag = sc->sc_tag;
32531.22Schopps	pci_conf_write(pc, tag, offs, win[0].win_start);
32541.22Schopps	pci_conf_write(pc, tag, offs + 4, win[0].win_limit);
32551.22Schopps	pci_conf_write(pc, tag, offs + 8, win[1].win_start);
32561.22Schopps	pci_conf_write(pc, tag, offs + 12, win[1].win_limit);
32571.95Schristos	DPRINTF(("--pccbb_winset: win0 [0x%lx, 0x%lx), win1 [0x%lx, 0x%lx)\n",
32581.95Schristos	    (unsigned long)pci_conf_read(pc, tag, offs),
32591.95Schristos	    (unsigned long)pci_conf_read(pc, tag, offs + 4) + align,
32601.95Schristos	    (unsigned long)pci_conf_read(pc, tag, offs + 8),
32611.95Schristos	    (unsigned long)pci_conf_read(pc, tag, offs + 12) + align));
32621.22Schopps
32631.22Schopps	if (bst == sc->sc_memt) {
32641.146Sdyoung		pcireg_t bcr = pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG);
32651.61Senami
32661.61Senami		bcr &= ~(CB_BCR_PREFETCH_MEMWIN0 | CB_BCR_PREFETCH_MEMWIN1);
32671.61Senami		if (win[0].win_flags & PCCBB_MEM_CACHABLE)
32681.22Schopps			bcr |= CB_BCR_PREFETCH_MEMWIN0;
32691.61Senami		if (win[1].win_flags & PCCBB_MEM_CACHABLE)
32701.22Schopps			bcr |= CB_BCR_PREFETCH_MEMWIN1;
32711.146Sdyoung		pci_conf_write(pc, tag, PCI_BRIDGE_CONTROL_REG, bcr);
32721.22Schopps	}
32731.1Shaya}
32741.1Shaya
32751.1Shaya#endif /* rbus */
32761.25Senami
32771.25Senamistatic void
32781.143Sdyoungpccbb_powerhook(int why, void *arg)
32791.25Senami{
32801.25Senami	struct pccbb_softc *sc = arg;
32811.70Shaya	pcireg_t reg;
32821.25Senami	bus_space_tag_t base_memt = sc->sc_base_memt;	/* socket regs memory */
32831.25Senami	bus_space_handle_t base_memh = sc->sc_base_memh;
32841.25Senami
32851.25Senami	DPRINTF(("%s: power: why %d\n", sc->sc_dev.dv_xname, why));
32861.25Senami
32871.38Shaya	if (why == PWR_SUSPEND || why == PWR_STANDBY) {
32881.95Schristos		DPRINTF(("%s: power: why %d stopping intr\n",
32891.95Schristos		    sc->sc_dev.dv_xname, why));
32901.38Shaya		if (sc->sc_pil_intr_enable) {
32911.38Shaya			(void)pccbbintr_function(sc);
32921.38Shaya		}
32931.38Shaya		sc->sc_pil_intr_enable = 0;
32941.38Shaya
32951.113Sjmcneill		pci_conf_capture(sc->sc_pc, sc->sc_tag, &sc->sc_pciconf);
32961.113Sjmcneill
32971.129Sjmcneill		if (sc->sc_chipset == CB_RX5C47X)
32981.129Sjmcneill			sc->sc_ricoh_misc_ctrl = pci_conf_read(sc->sc_pc,
32991.129Sjmcneill						     sc->sc_tag,
33001.129Sjmcneill						     RICOH_PCI_MISC_CTRL);
33011.129Sjmcneill
33021.38Shaya		/* ToDo: deactivate or suspend child devices */
33031.38Shaya	}
33041.38Shaya
33051.25Senami	if (why == PWR_RESUME) {
33061.70Shaya		if (sc->sc_pwrmgt_offs != 0) {
33071.70Shaya			reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
33081.139Sdyoung			    sc->sc_pwrmgt_offs + PCI_PMCSR);
33091.70Shaya			if ((reg & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_STATE_D0 ||
33101.139Sdyoung			    reg & PCI_PMCSR_PME_EN) {
33111.70Shaya				/* powrstate != D0 */
33121.70Shaya
33131.70Shaya				printf("%s going back to D0 mode\n",
33141.70Shaya				    sc->sc_dev.dv_xname);
33151.70Shaya				reg &= ~PCI_PMCSR_STATE_MASK;
33161.70Shaya				reg |= PCI_PMCSR_STATE_D0;
33171.139Sdyoung				reg &= ~PCI_PMCSR_PME_EN;
33181.70Shaya				pci_conf_write(sc->sc_pc, sc->sc_tag,
33191.139Sdyoung				    sc->sc_pwrmgt_offs + PCI_PMCSR, reg);
33201.70Shaya
33211.70Shaya				pci_conf_write(sc->sc_pc, sc->sc_tag,
33221.70Shaya				    PCI_SOCKBASE, sc->sc_sockbase);
33231.70Shaya				pci_conf_write(sc->sc_pc, sc->sc_tag,
33241.70Shaya				    PCI_BUSNUM, sc->sc_busnum);
33251.70Shaya				pccbb_chipinit(sc);
33261.70Shaya				/* setup memory and io space window for CB */
33271.70Shaya				pccbb_winset(0x1000, sc, sc->sc_memt);
33281.70Shaya				pccbb_winset(0x04, sc, sc->sc_iot);
33291.115Sjmcneill				goto norestore;
33301.70Shaya			}
33311.70Shaya		}
33321.129Sjmcneill
33331.129Sjmcneillnorestore:
33341.113Sjmcneill		pci_conf_restore(sc->sc_pc, sc->sc_tag, &sc->sc_pciconf);
33351.129Sjmcneill		if (sc->sc_chipset == CB_RX5C47X) {
33361.129Sjmcneill			pci_conf_write(sc->sc_pc, sc->sc_tag,
33371.129Sjmcneill			    RICOH_PCI_MISC_CTRL, sc->sc_ricoh_misc_ctrl);
33381.129Sjmcneill		}
33391.113Sjmcneill
33401.59Sminoura		if (pci_conf_read (sc->sc_pc, sc->sc_tag, PCI_SOCKBASE) == 0)
33411.58Sminoura			/* BIOS did not recover this register */
33421.59Sminoura			pci_conf_write (sc->sc_pc, sc->sc_tag,
33431.58Sminoura					PCI_SOCKBASE, sc->sc_sockbase);
33441.59Sminoura		if (pci_conf_read (sc->sc_pc, sc->sc_tag, PCI_BUSNUM) == 0)
33451.58Sminoura			/* BIOS did not recover this register */
33461.59Sminoura			pci_conf_write (sc->sc_pc, sc->sc_tag,
33471.58Sminoura					PCI_BUSNUM, sc->sc_busnum);
33481.25Senami		/* CSC Interrupt: Card detect interrupt on */
33491.25Senami		reg = bus_space_read_4(base_memt, base_memh, CB_SOCKET_MASK);
33501.25Senami		/* Card detect intr is turned on. */
33511.111Smycroft		reg |= CB_SOCKET_MASK_CD | CB_SOCKET_MASK_POWER;
33521.25Senami		bus_space_write_4(base_memt, base_memh, CB_SOCKET_MASK, reg);
33531.25Senami		/* reset interrupt */
33541.25Senami		reg = bus_space_read_4(base_memt, base_memh, CB_SOCKET_EVENT);
33551.25Senami		bus_space_write_4(base_memt, base_memh, CB_SOCKET_EVENT, reg);
33561.25Senami
33571.25Senami		/*
33581.25Senami		 * check for card insertion or removal during suspend period.
33591.35Senami		 * XXX: the code can't cope with card swap (remove then
33601.35Senami		 * insert).  how can we detect such situation?
33611.25Senami		 */
33621.35Senami		(void)pccbbintr(sc);
33631.38Shaya
33641.38Shaya		sc->sc_pil_intr_enable = 1;
33651.95Schristos		DPRINTF(("%s: power: RESUME enabling intr\n",
33661.95Schristos		    sc->sc_dev.dv_xname));
33671.38Shaya
33681.38Shaya		/* ToDo: activate or wakeup child devices */
33691.25Senami	}
33701.25Senami}
3371