svn commit: r271205 - stable/10/sys/powerpc/powermac

Justin Hibbits jhibbits at FreeBSD.org
Sat Sep 6 19:38:41 UTC 2014


Author: jhibbits
Date: Sat Sep  6 19:38:40 2014
New Revision: 271205
URL: http://svnweb.freebsd.org/changeset/base/271205

Log:
  MFC r259657,r264205,r264207:
  
  r259657:
  
  Add suspend/resume capabilities to the ATI backlight ppc driver.
  
  With this, also shut off the display (DPMS-style) and disable the
  clocking when the backlight level is set to 0.  This is taken from the
  radeonkms driver (radeon_legacy_encoders.c) which doesn't yet support
  PowerPC.
  
  r264205,r264207:
  
  Fix the ATI backlight driver off/on handling.  Now this driver works
  correctly with the ATI Radeon 9700 in the PowerBook G4 1.67GHz.
  
  Code shamelessly taken in spirit from the radeonkms driver, which I
  hope will make this driver redundant in the future.
  
  Approved by:	re (marius)
  Relnotes:	yes (not suspend/resume, but the rest)

Modified:
  stable/10/sys/powerpc/powermac/atibl.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/powerpc/powermac/atibl.c
==============================================================================
--- stable/10/sys/powerpc/powermac/atibl.c	Sat Sep  6 19:12:14 2014	(r271204)
+++ stable/10/sys/powerpc/powermac/atibl.c	Sat Sep  6 19:38:40 2014	(r271205)
@@ -52,10 +52,21 @@ __FBSDID("$FreeBSD$");
 #define  RADEON_LVDS_BL_MOD_EN        (1   << 16)
 #define  RADEON_LVDS_DIGON            (1   << 18)
 #define  RADEON_LVDS_BLON             (1   << 19)
+#define RADEON_LVDS_PLL_CNTL         0x02d4
+#define  RADEON_LVDS_PLL_EN           (1   << 16)
+#define  RADEON_LVDS_PLL_RESET        (1   << 17)
+#define RADEON_PIXCLKS_CNTL          0x002d
+#define  RADEON_PIXCLK_LVDS_ALWAYS_ONb (1   << 14)
+#define RADEON_DISP_PWR_MAN          0x0d08
+#define  RADEON_AUTO_PWRUP_EN          (1 << 26)
+#define RADEON_CLOCK_CNTL_DATA       0x000c
+#define RADEON_CLOCK_CNTL_INDEX      0x0008
+#define  RADEON_PLL_WR_EN              (1 << 7)
+#define RADEON_CRTC_GEN_CNTL         0x0050
 
 struct atibl_softc {
-	device_t	 dev;
 	struct resource *sc_memr;
+	int		 sc_level;
 };
 
 static void atibl_identify(driver_t *driver, device_t parent);
@@ -63,13 +74,17 @@ static int atibl_probe(device_t dev);
 static int atibl_attach(device_t dev);
 static int atibl_setlevel(struct atibl_softc *sc, int newlevel);
 static int atibl_getlevel(struct atibl_softc *sc);
+static int atibl_resume(device_t dev);
+static int atibl_suspend(device_t dev);
 static int atibl_sysctl(SYSCTL_HANDLER_ARGS);
 
 static device_method_t atibl_methods[] = {
 	/* Device interface */
-	DEVMETHOD(device_identify, atibl_identify),
-	DEVMETHOD(device_probe, atibl_probe),
-	DEVMETHOD(device_attach, atibl_attach),
+	DEVMETHOD(device_identify,	atibl_identify),
+	DEVMETHOD(device_probe,		atibl_probe),
+	DEVMETHOD(device_attach,	atibl_attach),
+	DEVMETHOD(device_suspend,	atibl_suspend),
+	DEVMETHOD(device_resume,	atibl_resume),
 	{0, 0},
 };
 
@@ -136,16 +151,62 @@ atibl_attach(device_t dev)
 	tree = device_get_sysctl_tree(dev);
 
 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
-			"level", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
-			atibl_sysctl, "I", "Backlight level (0-100)");
+	    "level", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+	    atibl_sysctl, "I", "Backlight level (0-100)");
 
 	return (0);
 }
 
+static uint32_t __inline
+atibl_pll_rreg(struct atibl_softc *sc, uint32_t reg)
+{
+	uint32_t data, save, tmp;
+
+	bus_write_1(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX,
+	    ((reg & 0x3f) | RADEON_PLL_WR_EN));
+	(void)bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA);
+	(void)bus_read_4(sc->sc_memr, RADEON_CRTC_GEN_CNTL);
+
+	data = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA);
+
+	/* Only necessary on R300, bt won't hurt others. */
+	save = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX);
+	tmp = save & (~0x3f | RADEON_PLL_WR_EN);
+	bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, tmp);
+	tmp = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA);
+	bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, save);
+
+	return data;
+}
+
+static void __inline
+atibl_pll_wreg(struct atibl_softc *sc, uint32_t reg, uint32_t val)
+{
+	uint32_t save, tmp;
+
+	bus_write_1(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX,
+	    ((reg & 0x3f) | RADEON_PLL_WR_EN));
+	(void)bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA);
+	(void)bus_read_4(sc->sc_memr, RADEON_CRTC_GEN_CNTL);
+
+	bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA, val);
+	DELAY(5000);
+
+	/* Only necessary on R300, bt won't hurt others. */
+	save = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX);
+	tmp = save & (~0x3f | RADEON_PLL_WR_EN);
+	bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, tmp);
+	tmp = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA);
+	bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, save);
+}
+
 static int
 atibl_setlevel(struct atibl_softc *sc, int newlevel)
 {
 	uint32_t lvds_gen_cntl;
+	uint32_t lvds_pll_cntl;
+	uint32_t pixclks_cntl;
+	uint32_t disp_pwr_reg;
 
 	if (newlevel > 100)
 		newlevel = 100;
@@ -153,13 +214,43 @@ atibl_setlevel(struct atibl_softc *sc, i
 	if (newlevel < 0)
 		newlevel = 0;
 
-	newlevel = (newlevel * 5) / 2 + 5;
 	lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL);
-	lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
-	lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_LEVEL_MASK;
-	lvds_gen_cntl |= (newlevel << RADEON_LVDS_BL_MOD_LEVEL_SHIFT) &
-		RADEON_LVDS_BL_MOD_LEVEL_MASK;
-	bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
+
+	if (newlevel > 0) {
+		newlevel = (newlevel * 5) / 2 + 5;
+		disp_pwr_reg = bus_read_4(sc->sc_memr, RADEON_DISP_PWR_MAN);
+		disp_pwr_reg |= RADEON_AUTO_PWRUP_EN;
+		bus_write_4(sc->sc_memr, RADEON_DISP_PWR_MAN, disp_pwr_reg);
+		lvds_pll_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL);
+		lvds_pll_cntl |= RADEON_LVDS_PLL_EN;
+		bus_write_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
+		lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
+		bus_write_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
+		DELAY(1000);
+
+		lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS | 
+		    RADEON_LVDS_BL_MOD_LEVEL_MASK);
+		lvds_gen_cntl |= RADEON_LVDS_ON | RADEON_LVDS_EN |
+		    RADEON_LVDS_DIGON | RADEON_LVDS_BLON;
+		lvds_gen_cntl |= (newlevel << RADEON_LVDS_BL_MOD_LEVEL_SHIFT) &
+		    RADEON_LVDS_BL_MOD_LEVEL_MASK;
+		lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
+		DELAY(200000);
+		bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
+	} else {
+		pixclks_cntl = atibl_pll_rreg(sc, RADEON_PIXCLKS_CNTL);
+		atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL,
+		    pixclks_cntl & ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
+		lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
+		lvds_gen_cntl &= ~(RADEON_LVDS_BL_MOD_EN | RADEON_LVDS_BL_MOD_LEVEL_MASK);
+		bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
+		lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN);
+		DELAY(200000);
+		bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
+
+		atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, pixclks_cntl);
+		DELAY(200000);
+	}
 
 	return (0);
 }
@@ -173,13 +264,39 @@ atibl_getlevel(struct atibl_softc *sc)
 	lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL);
 
 	level = ((lvds_gen_cntl & RADEON_LVDS_BL_MOD_LEVEL_MASK) >>
-			RADEON_LVDS_BL_MOD_LEVEL_SHIFT);
-	level = ((level - 5) * 2) / 5;
+	    RADEON_LVDS_BL_MOD_LEVEL_SHIFT);
+	if (level != 0)
+		level = ((level - 5) * 2) / 5;
 
 	return (level);
 }
 
 static int
+atibl_suspend(device_t dev)
+{
+	struct atibl_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	sc->sc_level = atibl_getlevel(sc);
+	atibl_setlevel(sc, 0);
+
+	return (0);
+}
+
+static int
+atibl_resume(device_t dev)
+{
+	struct atibl_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	atibl_setlevel(sc, sc->sc_level);
+
+	return (0);
+}
+
+static int
 atibl_sysctl(SYSCTL_HANDLER_ARGS)
 {
 	struct atibl_softc *sc;


More information about the svn-src-all mailing list