Subject: kern/6172: Additions/corrections to PCIC code to better handle CL-67XX
To: None <gnats-bugs@gnats.netbsd.org>
From: Johnny C. Lam <lamj@stat.cmu.edu>
List: netbsd-bugs
Date: 09/17/1998 15:43:30
>Number:         6172
>Category:       kern
>Synopsis:       Additions/corrections to PCIC code to better handle CL-67XX
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Sep 17 12:50:00 1998
>Last-Modified:
>Originator:     Johnny C. Lam
>Organization:
Carnegie Mellon University
>Release:        1.3G
>Environment:
NetBSD 1.3G (MARIPOSA) #14: Mon Aug 24 07:25:44 EST 1998
    kroot@mariposa:/usr/src/sys/arch/i386/compile/MARIPOSA

>Description:
	The CL-67XX PCIC's have extra registers that extend the I82365
	register set.  Below are patches to four files:

	1) sys/dev/ic/i82365.c: More descriptive/correct settings of
	   registers, and additions to better handle the CL-67XX
	   PCIC's.
	2) sys/dev/ic/i82365reg.h: Corrections to register values and
	   additional registers for CL-67XX.
	3) sys/dev/isa/i82365_isasubr.c: More descriptive/correct setting
	   of registers.
	4) sys/dev/pci/pcidevs: Correct product name of CL-PD6729

>How-To-Repeat:

>Fix:
*** src/sys/dev/ic/i82365.c.orig	Thu Sep 17 02:32:22 1998
--- src/sys/dev/ic/i82365.c	Thu Sep 17 02:32:43 1998
***************
*** 53,59 ****
  
  #ifdef PCICDEBUG
  int	pcic_debug = 0;
! #define	DPRINTF(arg) if (pcic_debug) printf arg;
  #else
  #define	DPRINTF(arg)
  #endif
--- 53,59 ----
  
  #ifdef PCICDEBUG
  int	pcic_debug = 0;
! #define	DPRINTF(arg) if (pcic_debug) printf arg
  #else
  #define	DPRINTF(arg)
  #endif
***************
*** 63,68 ****
--- 63,69 ----
  #define	PCIC_VENDOR_I82365SLR1		2
  #define	PCIC_VENDOR_CIRRUS_PD6710	3
  #define	PCIC_VENDOR_CIRRUS_PD672X	4
+ #define	PCIC_VENDOR_CIRRUS_PD6729	5
  
  /*
   * Individual drivers will allocate their own memory and io regions. Memory
***************
*** 123,142 ****
  	    PCIC_CIRRUS_CHIP_INFO_CHIP_ID) {
  		reg = pcic_read(h, -1);
  		if ((reg & PCIC_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
! 			if (reg & PCIC_CIRRUS_CHIP_INFO_SLOTS)
! 				return (PCIC_VENDOR_CIRRUS_PD672X);
! 			else
  				return (PCIC_VENDOR_CIRRUS_PD6710);
  		}
  	}
- 	/* XXX how do I identify the GD6729? */
  
  	reg = pcic_read(h, PCIC_IDENT);
  
! 	if ((reg & PCIC_IDENT_REV_MASK) == PCIC_IDENT_REV_I82365SLR0)
  		return (PCIC_VENDOR_I82365SLR0);
! 	else
  		return (PCIC_VENDOR_I82365SLR1);
  
  	return (PCIC_VENDOR_UNKNOWN);
  }
--- 124,154 ----
  	    PCIC_CIRRUS_CHIP_INFO_CHIP_ID) {
  		reg = pcic_read(h, -1);
  		if ((reg & PCIC_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
! 			switch (reg & PCIC_CIRRUS_CHIP_INFO_SLOTS_MASK) {
! 			case PCIC_CIRRUS_CHIP_INFO_SLOTS_SINGLE:
  				return (PCIC_VENDOR_CIRRUS_PD6710);
+ 			case PCIC_CIRRUS_CHIP_INFO_SLOTS_DUAL:
+ 				pcic_write(h, PCIC_CIRRUS_EXT_INDEX,
+ 				    PCIC_CIRRUS_PROD_ID);
+ 				reg = pcic_read(h, PCIC_CIRRUS_EXT_DATA);
+ 				switch (reg & PCIC_CIRRUS_PROD_ID_FAM_MASK) {
+ 				case PCIC_CIRRUS_PROD_ID_FAM_PD6729:
+ 					return (PCIC_VENDOR_CIRRUS_PD6729);
+ 				default:
+ 					return (PCIC_VENDOR_CIRRUS_PD672X);
+ 				}
+ 			}
  		}
  	}
  
  	reg = pcic_read(h, PCIC_IDENT);
  
! 	switch (reg & PCIC_IDENT_REV_MASK) {
! 	case PCIC_IDENT_REV_I82365SLR0:
  		return (PCIC_VENDOR_I82365SLR0);
! 	case PCIC_IDENT_REV_I82365SLR1:
  		return (PCIC_VENDOR_I82365SLR1);
+ 	}
  
  	return (PCIC_VENDOR_UNKNOWN);
  }
***************
*** 154,159 ****
--- 166,173 ----
  		return ("Cirrus PD6710");
  	case PCIC_VENDOR_CIRRUS_PD672X:
  		return ("Cirrus PD672X");
+ 	case PCIC_VENDOR_CIRRUS_PD6729:
+ 		return ("Cirrus PD6729");
  	}
  
  	return ("Unknown controller");
***************
*** 163,169 ****
  pcic_attach(sc)
  	struct pcic_softc *sc;
  {
! 	int vendor, count, i, reg;
  
  	/* now check for each controller/socket */
  
--- 177,183 ----
  pcic_attach(sc)
  	struct pcic_softc *sc;
  {
! 	int vendor, count, i, reg, one_ctrl;
  
  	/* now check for each controller/socket */
  
***************
*** 198,206 ****
  
  	DPRINTF((" 0x%02x", reg));
  
  	sc->handle[2].sc = sc;
  	sc->handle[2].sock = C1SA;
! 	if (pcic_ident_ok(reg = pcic_read(&sc->handle[2], PCIC_IDENT))) {
  		sc->handle[2].flags = PCIC_FLAG_SOCKETP;
  		count++;
  	} else {
--- 212,233 ----
  
  	DPRINTF((" 0x%02x", reg));
  
+ 	/*
+ 	 * CL-PD6729 has only one controller.  Trying to
+ 	 * read from the second one is undefined, so don't.
+ 	 */
+ 	one_ctrl = 0;
+ 	if (sc->handle[0].flags & PCIC_FLAG_SOCKETP)
+ 		switch (pcic_vendor(&sc->handle[0])) {
+ 		case PCIC_VENDOR_CIRRUS_PD6729:
+ 			one_ctrl = 1;
+ 			break;
+ 		}
+ 
  	sc->handle[2].sc = sc;
  	sc->handle[2].sock = C1SA;
! 	if (pcic_ident_ok(reg = pcic_read(&sc->handle[2], PCIC_IDENT)) &&
! 	    one_ctrl == 0) {
  		sc->handle[2].flags = PCIC_FLAG_SOCKETP;
  		count++;
  	} else {
***************
*** 211,217 ****
  
  	sc->handle[3].sc = sc;
  	sc->handle[3].sock = C1SB;
! 	if (pcic_ident_ok(reg = pcic_read(&sc->handle[3], PCIC_IDENT))) {
  		sc->handle[3].flags = PCIC_FLAG_SOCKETP;
  		count++;
  	} else {
--- 238,245 ----
  
  	sc->handle[3].sc = sc;
  	sc->handle[3].sock = C1SB;
! 	if (pcic_ident_ok(reg = pcic_read(&sc->handle[3], PCIC_IDENT)) &&
! 	    one_ctrl == 0) {
  		sc->handle[3].flags = PCIC_FLAG_SOCKETP;
  		count++;
  	} else {
***************
*** 330,344 ****
  
  	/* set up the card to interrupt on card detect */
  
! 	pcic_write(h, PCIC_CSC_INTR, (h->sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) |
! 	    PCIC_CSC_INTR_CD_ENABLE);
  	pcic_write(h, PCIC_INTR, 0);
  	pcic_read(h, PCIC_CSC);
  
  	/* unsleep the cirrus controller */
  
! 	if ((h->vendor == PCIC_VENDOR_CIRRUS_PD6710) ||
! 	    (h->vendor == PCIC_VENDOR_CIRRUS_PD672X)) {
  		reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_2);
  		if (reg & PCIC_CIRRUS_MISC_CTL_2_SUSPEND) {
  			DPRINTF(("%s: socket %02x was suspended\n",
--- 358,375 ----
  
  	/* set up the card to interrupt on card detect */
  
! 	reg = (h->sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) & PCIC_CSC_INTR_IRQ_MASK;
! 	reg |= PCIC_CSC_INTR_CD_ENABLE;
! 	pcic_write(h, PCIC_CSC_INTR, reg);
  	pcic_write(h, PCIC_INTR, 0);
  	pcic_read(h, PCIC_CSC);
  
  	/* unsleep the cirrus controller */
  
! 	switch (h->vendor) {
! 	case PCIC_VENDOR_CIRRUS_PD6710:
! 	case PCIC_VENDOR_CIRRUS_PD672X:
! 	case PCIC_VENDOR_CIRRUS_PD6729:
  		reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_2);
  		if (reg & PCIC_CIRRUS_MISC_CTL_2_SUSPEND) {
  			DPRINTF(("%s: socket %02x was suspended\n",
***************
*** 346,352 ****
--- 377,411 ----
  			reg &= ~PCIC_CIRRUS_MISC_CTL_2_SUSPEND;
  			pcic_write(h, PCIC_CIRRUS_MISC_CTL_2, reg);
  		}
+ 		break;
  	}
+ 
+ 	/* Set up Low Power Dynamic Mode for the CL-PD67XX */
+ 
+ 	switch (h->vendor) {
+ 	case PCIC_VENDOR_CIRRUS_PD6710:
+ 	case PCIC_VENDOR_CIRRUS_PD672X:
+ 	case PCIC_VENDOR_CIRRUS_PD6729:
+ 		reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_2);
+ 		reg |= PCIC_CIRRUS_MISC_CTL_2_LP_DYNAMIC_MODE;
+ 		pcic_write(h, PCIC_CIRRUS_MISC_CTL_2, reg);
+ 		DPRINTF(("%s: low power dynamic mode enabled on socket %02x\n",
+ 		    h->sc->dev.dv_xname, h->sock));
+ 	}
+ 
+ 	/* Enable the speaker for modem PC cards. */
+ 
+ 	switch (h->vendor) {
+ 	case PCIC_VENDOR_CIRRUS_PD6710:
+ 	case PCIC_VENDOR_CIRRUS_PD672X:
+ 	case PCIC_VENDOR_CIRRUS_PD6729:
+ 		reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1);
+ 		reg |= PCIC_CIRRUS_MISC_CTL_1_SPKR_ENABLE;
+ 		pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg);
+ 		DPRINTF(("%s: speaker enabled on socket %02x\n",
+ 		    h->sc->dev.dv_xname, h->sock));
+ 	}
+ 
  	/* if there's a card there, then attach it. */
  
  	reg = pcic_read(h, PCIC_IF_STATUS);
***************
*** 537,543 ****
  
  	h->flags &= ~PCIC_FLAG_CARDP;
  
! 	/* call the MI attach function */
  
  	pcmcia_card_detach(h->pcmcia);
  
--- 596,602 ----
  
  	h->flags &= ~PCIC_FLAG_CARDP;
  
! 	/* call the MI detach function */
  
  	pcmcia_card_detach(h->pcmcia);
  
***************
*** 1099,1109 ****
  	cardtype = pcmcia_card_gettype(h->pcmcia);
  
  	reg = pcic_read(h, PCIC_INTR);
! 	reg &= ~PCIC_INTR_CARDTYPE_MASK;
  	reg |= ((cardtype == PCMCIA_IFTYPE_IO) ?
  		PCIC_INTR_CARDTYPE_IO :
  		PCIC_INTR_CARDTYPE_MEM);
! 	reg |= h->ih_irq;
  	pcic_write(h, PCIC_INTR, reg);
  
  	DPRINTF(("%s: pcic_chip_socket_enable %02x cardtype %s %02x\n",
--- 1158,1168 ----
  	cardtype = pcmcia_card_gettype(h->pcmcia);
  
  	reg = pcic_read(h, PCIC_INTR);
! 	reg &= ~(PCIC_INTR_CARDTYPE_MASK | PCIC_INTR_IRQ_MASK);
  	reg |= ((cardtype == PCMCIA_IFTYPE_IO) ?
  		PCIC_INTR_CARDTYPE_IO :
  		PCIC_INTR_CARDTYPE_MEM);
! 	reg |= (h->ih_irq << PCIC_INTR_IRQ_SHIFT) & PCIC_INTR_IRQ_MASK;
  	pcic_write(h, PCIC_INTR, reg);
  
  	DPRINTF(("%s: pcic_chip_socket_enable %02x cardtype %s %02x\n",
***************
*** 1128,1133 ****
--- 1187,1203 ----
  	struct pcic_handle *h = (struct pcic_handle *) pch;
  
  	DPRINTF(("pcic_chip_socket_disable\n"));
+ 
+ 	/* flush write FIFO on CL-PD67XX */
+ 
+ 	switch (h->vendor) {
+ 	case PCIC_VENDOR_CIRRUS_PD6710:
+ 	case PCIC_VENDOR_CIRRUS_PD672X:
+ 	case PCIC_VENDOR_CIRRUS_PD6729:
+ 		pcic_write(h, PCIC_CIRRUS_FIFO_CTL,
+ 		    PCIC_CIRRUS_FIFO_CTL_FLUSH);
+ 		break;
+ 	}
  
  	/* power down the socket */
  
*** src/sys/dev/ic/i82365reg.h.orig	Thu Sep 17 02:32:22 1998
--- src/sys/dev/ic/i82365reg.h	Thu Sep 17 02:32:43 1998
***************
*** 32,38 ****
  /*
   * All information is from the intel 82365sl PC Card Interface Controller
   * (PCIC) data sheet, marked "preliminary".  Order number 290423-002, January
!  * 1993.
   */
  
  #define	PCIC_IOSIZE		2
--- 32,39 ----
  /*
   * All information is from the intel 82365sl PC Card Interface Controller
   * (PCIC) data sheet, marked "preliminary".  Order number 290423-002, January
!  * 1993.  Added information from the Cirrus Logic CL-PD6729 PCI-to-PCMCIA
!  * Host Adapter data sheet, marked "preliminary", version 2.0, January 1997.
   */
  
  #define	PCIC_IOSIZE		2
***************
*** 76,83 ****
  #define	PCIC_IF_STATUS_CARDDETECT_PRESENT	0x0C
  #define	PCIC_IF_STATUS_BATTERY_MASK		0x03
  #define	PCIC_IF_STATUS_BATTERY_DEAD1		0x00
! #define	PCIC_IF_STATUS_BATTERY_DEAD2		0x01
! #define	PCIC_IF_STATUS_BATTERY_WARNING		0x02
  #define	PCIC_IF_STATUS_BATTERY_GOOD		0x03
  
  #define	PCIC_PWRCTL				0x02	/* RW */
--- 77,84 ----
  #define	PCIC_IF_STATUS_CARDDETECT_PRESENT	0x0C
  #define	PCIC_IF_STATUS_BATTERY_MASK		0x03
  #define	PCIC_IF_STATUS_BATTERY_DEAD1		0x00
! #define	PCIC_IF_STATUS_BATTERY_WARNING		0x01
! #define	PCIC_IF_STATUS_BATTERY_DEAD2		0x02
  #define	PCIC_IF_STATUS_BATTERY_GOOD		0x03
  
  #define	PCIC_PWRCTL				0x02	/* RW */
***************
*** 98,104 ****
  #define	PCIC_PWRCTL_VPP1_EN0			0x01
  #define	PCIC_PWRCTL_VPP1_ENX			0x00
  
! #define	PCIC_CSC				0x04	/* RW */
  #define	PCIC_CSC_ZERO				0xE0
  #define	PCIC_CSC_GPI				0x10
  #define	PCIC_CSC_CD				0x08 /* Card Detect Change */
--- 99,105 ----
  #define	PCIC_PWRCTL_VPP1_EN0			0x01
  #define	PCIC_PWRCTL_VPP1_ENX			0x00
  
! #define	PCIC_CSC				0x04	/* RO */
  #define	PCIC_CSC_ZERO				0xE0
  #define	PCIC_CSC_GPI				0x10
  #define	PCIC_CSC_CD				0x08 /* Card Detect Change */
***************
*** 323,332 ****
  #define	PCIC_INTEL_GLOBAL_CTL_IRQLEVEL_ENABLE	0x02
  #define	PCIC_INTEL_GLOBAL_CTL_POWERDOWN		0x01
  
! #define	PCIC_CIRRUS_MISC_CTL_2			0x1E
  #define	PCIC_CIRRUS_MISC_CTL_2_SUSPEND		0x04
  
! #define	PCIC_CIRRUS_CHIP_INFO			0x1F
  #define	PCIC_CIRRUS_CHIP_INFO_CHIP_ID		0xC0
! #define	PCIC_CIRRUS_CHIP_INFO_SLOTS		0x20
  #define	PCIC_CIRRUS_CHIP_INFO_REV		0x1F
--- 324,352 ----
  #define	PCIC_INTEL_GLOBAL_CTL_IRQLEVEL_ENABLE	0x02
  #define	PCIC_INTEL_GLOBAL_CTL_POWERDOWN		0x01
  
! #define	PCIC_CIRRUS_MISC_CTL_1			0x16	/* RW */
! #define	PCIC_CIRRUS_MISC_CTL_1_SPKR_ENABLE	0x10
! 
! #define	PCIC_CIRRUS_FIFO_CTL			0x17	/* RW */
! #define	PCIC_CIRRUS_FIFO_CTL_EMPTY		0x80	/* I/O read */
! #define	PCIC_CIRRUS_FIFO_CTL_FLUSH		0x80	/* I/O write */
! 
! #define	PCIC_CIRRUS_MISC_CTL_2			0x1E	/* RW */
  #define	PCIC_CIRRUS_MISC_CTL_2_SUSPEND		0x04
+ #define	PCIC_CIRRUS_MISC_CTL_2_LP_DYNAMIC_MODE	0x02
  
! #define	PCIC_CIRRUS_CHIP_INFO			0x1F	/* RO */
  #define	PCIC_CIRRUS_CHIP_INFO_CHIP_ID		0xC0
! #define	PCIC_CIRRUS_CHIP_INFO_SLOTS_MASK	0x20
! #define	PCIC_CIRRUS_CHIP_INFO_SLOTS_DUAL	0x20
! #define	PCIC_CIRRUS_CHIP_INFO_SLOTS_SINGLE	0x00
  #define	PCIC_CIRRUS_CHIP_INFO_REV		0x1F
+ 
+ #define	PCIC_CIRRUS_EXT_INDEX			0x2E
+ #define	PCIC_CIRRUS_EXT_DATA			0x2F
+ 
+ #define	PCIC_CIRRUS_PROD_ID			0x35	/* RO */
+ #define	PCIC_CIRRUS_PROD_ID_FAM_MASK		0xF0
+ #define	PCIC_CIRRUS_PROD_ID_FAM_PD6729		0x20
+ #define	PCIC_CIRRUS_PROD_ID_PROD_MASK		0x0F
+ #define	PCIC_CIRRUS_PROD_ID_PROD_PD6729		0x00
*** src/sys/dev/isa/i82365_isasubr.c.orig	Thu Sep 17 02:32:23 1998
--- src/sys/dev/isa/i82365_isasubr.c	Thu Sep 17 02:32:43 1998
***************
*** 238,244 ****
  
  	reg = pcic_read(h, PCIC_INTR);
  	reg &= ~PCIC_INTR_IRQ_MASK;
! 	reg |= irq;
  	pcic_write(h, PCIC_INTR, reg);
  
  	h->ih_irq = irq;
--- 238,245 ----
  
  	reg = pcic_read(h, PCIC_INTR);
  	reg &= ~PCIC_INTR_IRQ_MASK;
! 	reg |= (irq << PCIC_INTR_IRQ_SHIFT) & PCIC_INTR_IRQ_MASK;
! 	reg |= PCIC_INTR_ENABLE;
  	pcic_write(h, PCIC_INTR, reg);
  
  	h->ih_irq = irq;
*** src/sys/dev/pci/pcidevs.orig	Thu Sep 17 02:32:24 1998
--- src/sys/dev/pci/pcidevs	Thu Sep 17 02:32:43 1998
***************
*** 656,662 ****
  product CIRRUS CL_GD5434_8	0x00a8	CL-GD5434-8
  product CIRRUS CL_GD5436	0x00ac	CL-GD5436
  product CIRRUS CL_GD5446	0x00b8	CL-GD5446
! product CIRRUS CL_GD6729	0x1100	CL-GD6729
  product CIRRUS CL_GD7542	0x1200	CL-GD7542
  product CIRRUS CL_GD7543	0x1202	CL-GD7543
  product CIRRUS CL_GD7541	0x1204	CL-GD7541
--- 656,662 ----
  product CIRRUS CL_GD5434_8	0x00a8	CL-GD5434-8
  product CIRRUS CL_GD5436	0x00ac	CL-GD5436
  product CIRRUS CL_GD5446	0x00b8	CL-GD5446
! product CIRRUS CL_PD6729	0x1100	CL-PD6729
  product CIRRUS CL_GD7542	0x1200	CL-GD7542
  product CIRRUS CL_GD7543	0x1202	CL-GD7543
  product CIRRUS CL_GD7541	0x1204	CL-GD7541
>Audit-Trail:
>Unformatted: