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