summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/powermac/atibl.c
diff options
context:
space:
mode:
authorjhibbits <jhibbits@FreeBSD.org>2014-04-06 21:48:45 +0000
committerjhibbits <jhibbits@FreeBSD.org>2014-04-06 21:48:45 +0000
commit86a9e40e90bca4b0a38d84c5694cf28baa6df54f (patch)
tree38dcbbf77eaa85e87bf89a14a22bb0a7d2808f20 /sys/powerpc/powermac/atibl.c
parent377b2f5b0879a21b53ec4099037aeea7eabb86d0 (diff)
downloadFreeBSD-src-86a9e40e90bca4b0a38d84c5694cf28baa6df54f.zip
FreeBSD-src-86a9e40e90bca4b0a38d84c5694cf28baa6df54f.tar.gz
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. MFC after: 2 weeks
Diffstat (limited to 'sys/powerpc/powermac/atibl.c')
-rw-r--r--sys/powerpc/powermac/atibl.c67
1 files changed, 61 insertions, 6 deletions
diff --git a/sys/powerpc/powermac/atibl.c b/sys/powerpc/powermac/atibl.c
index 5d5b6ac..b49dc69 100644
--- a/sys/powerpc/powermac/atibl.c
+++ b/sys/powerpc/powermac/atibl.c
@@ -57,6 +57,12 @@ __FBSDID("$FreeBSD$");
#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 {
struct resource *sc_memr;
@@ -151,12 +157,56 @@ atibl_attach(device_t dev)
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;
@@ -168,11 +218,15 @@ atibl_setlevel(struct atibl_softc *sc, int newlevel)
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);
@@ -181,20 +235,21 @@ atibl_setlevel(struct atibl_softc *sc, int newlevel)
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(2000);
+ DELAY(2000000);
bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
} else {
- pixclks_cntl = bus_read_4(sc->sc_memr, RADEON_PIXCLKS_CNTL);
- bus_write_4(sc->sc_memr, RADEON_PIXCLKS_CNTL,
+ 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;
+ lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN;
bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN);
- DELAY(2000);
+ DELAY(2000000);
bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
- bus_write_4(sc->sc_memr, RADEON_PIXCLKS_CNTL, pixclks_cntl);
+ atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, pixclks_cntl);
+ DELAY(2000000);
}
return (0);
OpenPOWER on IntegriCloud