1232177Sjhibbits/*- 2232177Sjhibbits * Copyright (c) 2012 Justin Hibbits 3232177Sjhibbits * All rights reserved. 4232177Sjhibbits * 5232177Sjhibbits * Redistribution and use in source and binary forms, with or without 6232177Sjhibbits * modification, are permitted provided that the following conditions 7232177Sjhibbits * are met: 8232177Sjhibbits * 1. Redistributions of source code must retain the above copyright 9232177Sjhibbits * notice, this list of conditions and the following disclaimer. 10232177Sjhibbits * 2. Redistributions in binary form must reproduce the above copyright 11232177Sjhibbits * notice, this list of conditions and the following disclaimer in the 12232177Sjhibbits * documentation and/or other materials provided with the distribution. 13232177Sjhibbits * 14232177Sjhibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15232177Sjhibbits * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16232177Sjhibbits * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17232177Sjhibbits * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18232177Sjhibbits * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19232177Sjhibbits * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20232177Sjhibbits * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21232177Sjhibbits * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22232177Sjhibbits * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23232177Sjhibbits * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24232177Sjhibbits * SUCH DAMAGE. 25232177Sjhibbits */ 26232177Sjhibbits 27232177Sjhibbits#include <sys/cdefs.h> 28232177Sjhibbits__FBSDID("$FreeBSD$"); 29232177Sjhibbits 30232177Sjhibbits#include <sys/param.h> 31232177Sjhibbits#include <sys/bus.h> 32232177Sjhibbits#include <sys/systm.h> 33232177Sjhibbits#include <sys/module.h> 34232177Sjhibbits#include <sys/kernel.h> 35232177Sjhibbits#include <sys/rman.h> 36232177Sjhibbits#include <sys/sysctl.h> 37232177Sjhibbits 38232177Sjhibbits#include <machine/bus.h> 39232177Sjhibbits 40232177Sjhibbits#include <dev/ofw/openfirm.h> 41232177Sjhibbits 42232177Sjhibbits/* From the xf86-video-ati driver's radeon_reg.h */ 43232177Sjhibbits#define RADEON_LVDS_GEN_CNTL 0x02d0 44232177Sjhibbits#define RADEON_LVDS_ON (1 << 0) 45232177Sjhibbits#define RADEON_LVDS_DISPLAY_DIS (1 << 1) 46232177Sjhibbits#define RADEON_LVDS_PANEL_TYPE (1 << 2) 47232177Sjhibbits#define RADEON_LVDS_PANEL_FORMAT (1 << 3) 48232177Sjhibbits#define RADEON_LVDS_RST_FM (1 << 6) 49232177Sjhibbits#define RADEON_LVDS_EN (1 << 7) 50232177Sjhibbits#define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 51232177Sjhibbits#define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) 52232177Sjhibbits#define RADEON_LVDS_BL_MOD_EN (1 << 16) 53232177Sjhibbits#define RADEON_LVDS_DIGON (1 << 18) 54232177Sjhibbits#define RADEON_LVDS_BLON (1 << 19) 55271205Sjhibbits#define RADEON_LVDS_PLL_CNTL 0x02d4 56271205Sjhibbits#define RADEON_LVDS_PLL_EN (1 << 16) 57271205Sjhibbits#define RADEON_LVDS_PLL_RESET (1 << 17) 58271205Sjhibbits#define RADEON_PIXCLKS_CNTL 0x002d 59271205Sjhibbits#define RADEON_PIXCLK_LVDS_ALWAYS_ONb (1 << 14) 60271205Sjhibbits#define RADEON_DISP_PWR_MAN 0x0d08 61271205Sjhibbits#define RADEON_AUTO_PWRUP_EN (1 << 26) 62271205Sjhibbits#define RADEON_CLOCK_CNTL_DATA 0x000c 63271205Sjhibbits#define RADEON_CLOCK_CNTL_INDEX 0x0008 64271205Sjhibbits#define RADEON_PLL_WR_EN (1 << 7) 65271205Sjhibbits#define RADEON_CRTC_GEN_CNTL 0x0050 66232177Sjhibbits 67232177Sjhibbitsstruct atibl_softc { 68232177Sjhibbits struct resource *sc_memr; 69271205Sjhibbits int sc_level; 70232177Sjhibbits}; 71232177Sjhibbits 72232177Sjhibbitsstatic void atibl_identify(driver_t *driver, device_t parent); 73232177Sjhibbitsstatic int atibl_probe(device_t dev); 74232177Sjhibbitsstatic int atibl_attach(device_t dev); 75232177Sjhibbitsstatic int atibl_setlevel(struct atibl_softc *sc, int newlevel); 76232177Sjhibbitsstatic int atibl_getlevel(struct atibl_softc *sc); 77271205Sjhibbitsstatic int atibl_resume(device_t dev); 78271205Sjhibbitsstatic int atibl_suspend(device_t dev); 79232177Sjhibbitsstatic int atibl_sysctl(SYSCTL_HANDLER_ARGS); 80232177Sjhibbits 81232177Sjhibbitsstatic device_method_t atibl_methods[] = { 82232177Sjhibbits /* Device interface */ 83271205Sjhibbits DEVMETHOD(device_identify, atibl_identify), 84271205Sjhibbits DEVMETHOD(device_probe, atibl_probe), 85271205Sjhibbits DEVMETHOD(device_attach, atibl_attach), 86271205Sjhibbits DEVMETHOD(device_suspend, atibl_suspend), 87271205Sjhibbits DEVMETHOD(device_resume, atibl_resume), 88232177Sjhibbits {0, 0}, 89232177Sjhibbits}; 90232177Sjhibbits 91232177Sjhibbitsstatic driver_t atibl_driver = { 92232177Sjhibbits "backlight", 93232177Sjhibbits atibl_methods, 94232177Sjhibbits sizeof(struct atibl_softc) 95232177Sjhibbits}; 96232177Sjhibbits 97232177Sjhibbitsstatic devclass_t atibl_devclass; 98232177Sjhibbits 99232177SjhibbitsDRIVER_MODULE(atibl, vgapci, atibl_driver, atibl_devclass, 0, 0); 100232177Sjhibbits 101232177Sjhibbitsstatic void 102232177Sjhibbitsatibl_identify(driver_t *driver, device_t parent) 103232177Sjhibbits{ 104255100Sjhibbits if (OF_finddevice("mac-io/backlight") == -1) 105255100Sjhibbits return; 106232177Sjhibbits if (device_find_child(parent, "backlight", -1) == NULL) 107232177Sjhibbits device_add_child(parent, "backlight", -1); 108232177Sjhibbits} 109232177Sjhibbits 110232177Sjhibbitsstatic int 111232177Sjhibbitsatibl_probe(device_t dev) 112232177Sjhibbits{ 113232177Sjhibbits char control[8]; 114232177Sjhibbits phandle_t handle; 115232177Sjhibbits 116232177Sjhibbits handle = OF_finddevice("mac-io/backlight"); 117232177Sjhibbits 118239548Sjhibbits if (handle == -1) 119232177Sjhibbits return (ENXIO); 120232177Sjhibbits 121232177Sjhibbits if (OF_getprop(handle, "backlight-control", &control, sizeof(control)) < 0) 122232177Sjhibbits return (ENXIO); 123232177Sjhibbits 124232177Sjhibbits if (strcmp(control, "ati") != 0) 125232177Sjhibbits return (ENXIO); 126232177Sjhibbits 127239548Sjhibbits device_set_desc(dev, "PowerBook backlight for ATI graphics"); 128232177Sjhibbits 129232177Sjhibbits return (0); 130232177Sjhibbits} 131232177Sjhibbits 132232177Sjhibbitsstatic int 133232177Sjhibbitsatibl_attach(device_t dev) 134232177Sjhibbits{ 135232177Sjhibbits struct atibl_softc *sc; 136232177Sjhibbits struct sysctl_ctx_list *ctx; 137232177Sjhibbits struct sysctl_oid *tree; 138232177Sjhibbits int rid; 139232177Sjhibbits 140232177Sjhibbits sc = device_get_softc(dev); 141232177Sjhibbits 142232177Sjhibbits rid = 0x18; /* BAR[2], for the MMIO register */ 143232177Sjhibbits sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 144232177Sjhibbits RF_ACTIVE | RF_SHAREABLE); 145232177Sjhibbits if (sc->sc_memr == NULL) { 146232177Sjhibbits device_printf(dev, "Could not alloc mem resource!\n"); 147232177Sjhibbits return (ENXIO); 148232177Sjhibbits } 149232177Sjhibbits 150232177Sjhibbits ctx = device_get_sysctl_ctx(dev); 151232177Sjhibbits tree = device_get_sysctl_tree(dev); 152232177Sjhibbits 153232177Sjhibbits SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 154271205Sjhibbits "level", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 155271205Sjhibbits atibl_sysctl, "I", "Backlight level (0-100)"); 156232177Sjhibbits 157232177Sjhibbits return (0); 158232177Sjhibbits} 159232177Sjhibbits 160271205Sjhibbitsstatic uint32_t __inline 161271205Sjhibbitsatibl_pll_rreg(struct atibl_softc *sc, uint32_t reg) 162271205Sjhibbits{ 163271205Sjhibbits uint32_t data, save, tmp; 164271205Sjhibbits 165271205Sjhibbits bus_write_1(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, 166271205Sjhibbits ((reg & 0x3f) | RADEON_PLL_WR_EN)); 167271205Sjhibbits (void)bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 168271205Sjhibbits (void)bus_read_4(sc->sc_memr, RADEON_CRTC_GEN_CNTL); 169271205Sjhibbits 170271205Sjhibbits data = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 171271205Sjhibbits 172271205Sjhibbits /* Only necessary on R300, bt won't hurt others. */ 173271205Sjhibbits save = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX); 174271205Sjhibbits tmp = save & (~0x3f | RADEON_PLL_WR_EN); 175271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, tmp); 176271205Sjhibbits tmp = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 177271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, save); 178271205Sjhibbits 179271205Sjhibbits return data; 180271205Sjhibbits} 181271205Sjhibbits 182271205Sjhibbitsstatic void __inline 183271205Sjhibbitsatibl_pll_wreg(struct atibl_softc *sc, uint32_t reg, uint32_t val) 184271205Sjhibbits{ 185271205Sjhibbits uint32_t save, tmp; 186271205Sjhibbits 187271205Sjhibbits bus_write_1(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, 188271205Sjhibbits ((reg & 0x3f) | RADEON_PLL_WR_EN)); 189271205Sjhibbits (void)bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 190271205Sjhibbits (void)bus_read_4(sc->sc_memr, RADEON_CRTC_GEN_CNTL); 191271205Sjhibbits 192271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA, val); 193271205Sjhibbits DELAY(5000); 194271205Sjhibbits 195271205Sjhibbits /* Only necessary on R300, bt won't hurt others. */ 196271205Sjhibbits save = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX); 197271205Sjhibbits tmp = save & (~0x3f | RADEON_PLL_WR_EN); 198271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, tmp); 199271205Sjhibbits tmp = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 200271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, save); 201271205Sjhibbits} 202271205Sjhibbits 203232177Sjhibbitsstatic int 204232177Sjhibbitsatibl_setlevel(struct atibl_softc *sc, int newlevel) 205232177Sjhibbits{ 206232177Sjhibbits uint32_t lvds_gen_cntl; 207271205Sjhibbits uint32_t lvds_pll_cntl; 208271205Sjhibbits uint32_t pixclks_cntl; 209271205Sjhibbits uint32_t disp_pwr_reg; 210232177Sjhibbits 211232177Sjhibbits if (newlevel > 100) 212232177Sjhibbits newlevel = 100; 213232177Sjhibbits 214232177Sjhibbits if (newlevel < 0) 215232177Sjhibbits newlevel = 0; 216232177Sjhibbits 217232177Sjhibbits lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL); 218232177Sjhibbits 219271205Sjhibbits if (newlevel > 0) { 220271205Sjhibbits newlevel = (newlevel * 5) / 2 + 5; 221271205Sjhibbits disp_pwr_reg = bus_read_4(sc->sc_memr, RADEON_DISP_PWR_MAN); 222271205Sjhibbits disp_pwr_reg |= RADEON_AUTO_PWRUP_EN; 223271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_DISP_PWR_MAN, disp_pwr_reg); 224271205Sjhibbits lvds_pll_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL); 225271205Sjhibbits lvds_pll_cntl |= RADEON_LVDS_PLL_EN; 226271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 227271205Sjhibbits lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; 228271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 229271205Sjhibbits DELAY(1000); 230271205Sjhibbits 231271205Sjhibbits lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS | 232271205Sjhibbits RADEON_LVDS_BL_MOD_LEVEL_MASK); 233271205Sjhibbits lvds_gen_cntl |= RADEON_LVDS_ON | RADEON_LVDS_EN | 234271205Sjhibbits RADEON_LVDS_DIGON | RADEON_LVDS_BLON; 235271205Sjhibbits lvds_gen_cntl |= (newlevel << RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 236271205Sjhibbits RADEON_LVDS_BL_MOD_LEVEL_MASK; 237271205Sjhibbits lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; 238271205Sjhibbits DELAY(200000); 239271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 240271205Sjhibbits } else { 241271205Sjhibbits pixclks_cntl = atibl_pll_rreg(sc, RADEON_PIXCLKS_CNTL); 242271205Sjhibbits atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, 243271205Sjhibbits pixclks_cntl & ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); 244271205Sjhibbits lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; 245271205Sjhibbits lvds_gen_cntl &= ~(RADEON_LVDS_BL_MOD_EN | RADEON_LVDS_BL_MOD_LEVEL_MASK); 246271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 247271205Sjhibbits lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN); 248271205Sjhibbits DELAY(200000); 249271205Sjhibbits bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 250271205Sjhibbits 251271205Sjhibbits atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, pixclks_cntl); 252271205Sjhibbits DELAY(200000); 253271205Sjhibbits } 254271205Sjhibbits 255232177Sjhibbits return (0); 256232177Sjhibbits} 257232177Sjhibbits 258232177Sjhibbitsstatic int 259232177Sjhibbitsatibl_getlevel(struct atibl_softc *sc) 260232177Sjhibbits{ 261232177Sjhibbits uint32_t lvds_gen_cntl; 262232177Sjhibbits int level; 263232177Sjhibbits 264232177Sjhibbits lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL); 265232177Sjhibbits 266232177Sjhibbits level = ((lvds_gen_cntl & RADEON_LVDS_BL_MOD_LEVEL_MASK) >> 267271205Sjhibbits RADEON_LVDS_BL_MOD_LEVEL_SHIFT); 268271205Sjhibbits if (level != 0) 269271205Sjhibbits level = ((level - 5) * 2) / 5; 270232177Sjhibbits 271232177Sjhibbits return (level); 272232177Sjhibbits} 273232177Sjhibbits 274232177Sjhibbitsstatic int 275271205Sjhibbitsatibl_suspend(device_t dev) 276271205Sjhibbits{ 277271205Sjhibbits struct atibl_softc *sc; 278271205Sjhibbits 279271205Sjhibbits sc = device_get_softc(dev); 280271205Sjhibbits 281271205Sjhibbits sc->sc_level = atibl_getlevel(sc); 282271205Sjhibbits atibl_setlevel(sc, 0); 283271205Sjhibbits 284271205Sjhibbits return (0); 285271205Sjhibbits} 286271205Sjhibbits 287271205Sjhibbitsstatic int 288271205Sjhibbitsatibl_resume(device_t dev) 289271205Sjhibbits{ 290271205Sjhibbits struct atibl_softc *sc; 291271205Sjhibbits 292271205Sjhibbits sc = device_get_softc(dev); 293271205Sjhibbits 294271205Sjhibbits atibl_setlevel(sc, sc->sc_level); 295271205Sjhibbits 296271205Sjhibbits return (0); 297271205Sjhibbits} 298271205Sjhibbits 299271205Sjhibbitsstatic int 300232177Sjhibbitsatibl_sysctl(SYSCTL_HANDLER_ARGS) 301232177Sjhibbits{ 302232177Sjhibbits struct atibl_softc *sc; 303232177Sjhibbits int newlevel, error; 304232177Sjhibbits 305232177Sjhibbits sc = arg1; 306232177Sjhibbits 307232177Sjhibbits newlevel = atibl_getlevel(sc); 308232177Sjhibbits 309232177Sjhibbits error = sysctl_handle_int(oidp, &newlevel, 0, req); 310232177Sjhibbits 311232177Sjhibbits if (error || !req->newptr) 312232177Sjhibbits return (error); 313232177Sjhibbits 314232177Sjhibbits return (atibl_setlevel(sc, newlevel)); 315232177Sjhibbits} 316