atibl.c revision 232177
1234353Sdim/*- 2193323Sed * Copyright (c) 2012 Justin Hibbits 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright 11193323Sed * notice, this list of conditions and the following disclaimer in the 12193323Sed * documentation and/or other materials provided with the distribution. 13193323Sed * 14234353Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15234353Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16193323Sed * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17193323Sed * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18234353Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19193323Sed * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20193323Sed * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21224145Sdim * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22224145Sdim * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23224145Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24193323Sed * SUCH DAMAGE. 25193323Sed */ 26193323Sed 27193323Sed#include <sys/cdefs.h> 28193323Sed__FBSDID("$FreeBSD: head/sys/powerpc/powermac/atibl.c 232177 2012-02-26 13:45:25Z jhibbits $"); 29193323Sed 30193323Sed#include <sys/param.h> 31193323Sed#include <sys/bus.h> 32193323Sed#include <sys/systm.h> 33193323Sed#include <sys/module.h> 34193323Sed#include <sys/kernel.h> 35193323Sed#include <sys/rman.h> 36193323Sed#include <sys/sysctl.h> 37193323Sed 38218893Sdim#include <machine/bus.h> 39193323Sed 40193323Sed#include <dev/ofw/openfirm.h> 41193323Sed 42193323Sed/* From the xf86-video-ati driver's radeon_reg.h */ 43193323Sed#define RADEON_LVDS_GEN_CNTL 0x02d0 44193323Sed#define RADEON_LVDS_ON (1 << 0) 45193323Sed#define RADEON_LVDS_DISPLAY_DIS (1 << 1) 46218893Sdim#define RADEON_LVDS_PANEL_TYPE (1 << 2) 47193323Sed#define RADEON_LVDS_PANEL_FORMAT (1 << 3) 48193323Sed#define RADEON_LVDS_RST_FM (1 << 6) 49193323Sed#define RADEON_LVDS_EN (1 << 7) 50193323Sed#define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 51193323Sed#define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) 52193323Sed#define RADEON_LVDS_BL_MOD_EN (1 << 16) 53193323Sed#define RADEON_LVDS_DIGON (1 << 18) 54193323Sed#define RADEON_LVDS_BLON (1 << 19) 55193323Sed 56193323Sedstruct atibl_softc { 57193323Sed device_t dev; 58193323Sed struct resource *sc_memr; 59193323Sed}; 60193323Sed 61193323Sedstatic void atibl_identify(driver_t *driver, device_t parent); 62193323Sedstatic int atibl_probe(device_t dev); 63193323Sedstatic int atibl_attach(device_t dev); 64218893Sdimstatic int atibl_setlevel(struct atibl_softc *sc, int newlevel); 65218893Sdimstatic int atibl_getlevel(struct atibl_softc *sc); 66218893Sdimstatic int atibl_sysctl(SYSCTL_HANDLER_ARGS); 67224145Sdim 68193323Sedstatic device_method_t atibl_methods[] = { 69193323Sed /* Device interface */ 70193323Sed DEVMETHOD(device_identify, atibl_identify), 71193323Sed DEVMETHOD(device_probe, atibl_probe), 72193323Sed DEVMETHOD(device_attach, atibl_attach), 73193323Sed {0, 0}, 74249423Sdim}; 75249423Sdim 76234353Sdimstatic driver_t atibl_driver = { 77193323Sed "backlight", 78193323Sed atibl_methods, 79249423Sdim sizeof(struct atibl_softc) 80249423Sdim}; 81263508Sdim 82193323Sedstatic devclass_t atibl_devclass; 83193323Sed 84193323SedDRIVER_MODULE(atibl, vgapci, atibl_driver, atibl_devclass, 0, 0); 85193323Sed 86193323Sedstatic void 87193323Sedatibl_identify(driver_t *driver, device_t parent) 88193323Sed{ 89193323Sed if (device_find_child(parent, "backlight", -1) == NULL) 90193323Sed device_add_child(parent, "backlight", -1); 91218893Sdim} 92218893Sdim 93218893Sdimstatic int 94234353Sdimatibl_probe(device_t dev) 95234353Sdim{ 96234353Sdim char control[8]; 97218893Sdim phandle_t handle; 98239462Sdim 99239462Sdim handle = OF_finddevice("mac-io/backlight"); 100239462Sdim 101193323Sed if (handle <= 0) 102193323Sed return (ENXIO); 103193323Sed 104193323Sed if (OF_getprop(handle, "backlight-control", &control, sizeof(control)) < 0) 105193323Sed return (ENXIO); 106193323Sed 107193323Sed if (strcmp(control, "ati") != 0) 108193323Sed return (ENXIO); 109218893Sdim 110218893Sdim device_set_desc(dev, "PowerBook backlight"); 111193323Sed 112193323Sed return (0); 113193323Sed} 114193323Sed 115193323Sedstatic int 116193323Sedatibl_attach(device_t dev) 117193323Sed{ 118193323Sed struct atibl_softc *sc; 119193323Sed struct sysctl_ctx_list *ctx; 120193323Sed struct sysctl_oid *tree; 121193323Sed int rid; 122210299Sed 123210299Sed sc = device_get_softc(dev); 124251662Sdim 125251662Sdim rid = 0x18; /* BAR[2], for the MMIO register */ 126251662Sdim sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 127251662Sdim RF_ACTIVE | RF_SHAREABLE); 128251662Sdim if (sc->sc_memr == NULL) { 129251662Sdim device_printf(dev, "Could not alloc mem resource!\n"); 130251662Sdim return (ENXIO); 131251662Sdim } 132251662Sdim 133251662Sdim ctx = device_get_sysctl_ctx(dev); 134251662Sdim tree = device_get_sysctl_tree(dev); 135210299Sed 136210299Sed SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 137210299Sed "level", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 138210299Sed atibl_sysctl, "I", "Backlight level (0-100)"); 139218893Sdim 140193323Sed return (0); 141193323Sed} 142193323Sed 143208599Srdivackystatic int 144208599Srdivackyatibl_setlevel(struct atibl_softc *sc, int newlevel) 145193323Sed{ 146193323Sed uint32_t lvds_gen_cntl; 147193323Sed 148193323Sed if (newlevel > 100) 149208599Srdivacky newlevel = 100; 150208599Srdivacky 151218893Sdim if (newlevel < 0) 152193323Sed newlevel = 0; 153193323Sed 154218893Sdim newlevel = (newlevel * 5) / 2 + 5; 155251662Sdim lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL); 156251662Sdim lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; 157251662Sdim lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_LEVEL_MASK; 158251662Sdim lvds_gen_cntl |= (newlevel << RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 159251662Sdim RADEON_LVDS_BL_MOD_LEVEL_MASK; 160251662Sdim bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 161251662Sdim 162251662Sdim return (0); 163251662Sdim} 164251662Sdim 165251662Sdimstatic int 166251662Sdimatibl_getlevel(struct atibl_softc *sc) 167251662Sdim{ 168251662Sdim uint32_t lvds_gen_cntl; 169251662Sdim int level; 170251662Sdim 171251662Sdim lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL); 172251662Sdim 173251662Sdim level = ((lvds_gen_cntl & RADEON_LVDS_BL_MOD_LEVEL_MASK) >> 174251662Sdim RADEON_LVDS_BL_MOD_LEVEL_SHIFT); 175251662Sdim level = ((level - 5) * 2) / 5; 176251662Sdim 177251662Sdim return (level); 178251662Sdim} 179251662Sdim 180251662Sdimstatic int 181251662Sdimatibl_sysctl(SYSCTL_HANDLER_ARGS) 182251662Sdim{ 183251662Sdim struct atibl_softc *sc; 184251662Sdim int newlevel, error; 185251662Sdim 186251662Sdim sc = arg1; 187251662Sdim 188251662Sdim newlevel = atibl_getlevel(sc); 189251662Sdim 190251662Sdim error = sysctl_handle_int(oidp, &newlevel, 0, req); 191251662Sdim 192251662Sdim if (error || !req->newptr) 193251662Sdim return (error); 194251662Sdim 195251662Sdim return (atibl_setlevel(sc, newlevel)); 196251662Sdim} 197251662Sdim