summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/powermac
diff options
context:
space:
mode:
authorjhibbits <jhibbits@FreeBSD.org>2014-09-06 19:38:40 +0000
committerjhibbits <jhibbits@FreeBSD.org>2014-09-06 19:38:40 +0000
commit021e2fad8945e38ad2cdaf5b861426b3c0fba938 (patch)
treebae182593aefee2c6cf281455bbc045dba061cb4 /sys/powerpc/powermac
parentc5202a10e46c0c18090f9970d9eac617287250fc (diff)
downloadFreeBSD-src-021e2fad8945e38ad2cdaf5b861426b3c0fba938.zip
FreeBSD-src-021e2fad8945e38ad2cdaf5b861426b3c0fba938.tar.gz
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)
Diffstat (limited to 'sys/powerpc/powermac')
-rw-r--r--sys/powerpc/powermac/atibl.c145
1 files changed, 131 insertions, 14 deletions
diff --git a/sys/powerpc/powermac/atibl.c b/sys/powerpc/powermac/atibl.c
index f4ac9b0..6a12e2f 100644
--- a/sys/powerpc/powermac/atibl.c
+++ b/sys/powerpc/powermac/atibl.c
@@ -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, int newlevel)
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;
OpenPOWER on IntegriCloud