1239027Sjhibbits/*- 2239027Sjhibbits * Copyright (c) 2012 Justin Hibbits 3239027Sjhibbits * All rights reserved. 4239027Sjhibbits * 5239027Sjhibbits * Redistribution and use in source and binary forms, with or without 6239027Sjhibbits * modification, are permitted provided that the following conditions 7239027Sjhibbits * are met: 8239027Sjhibbits * 1. Redistributions of source code must retain the above copyright 9239027Sjhibbits * notice, this list of conditions and the following disclaimer. 10239027Sjhibbits * 2. Redistributions in binary form must reproduce the above copyright 11239027Sjhibbits * notice, this list of conditions and the following disclaimer in the 12239027Sjhibbits * documentation and/or other materials provided with the distribution. 13239027Sjhibbits * 14239027Sjhibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15239027Sjhibbits * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16239027Sjhibbits * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17239027Sjhibbits * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18239027Sjhibbits * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19239027Sjhibbits * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20239027Sjhibbits * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21239027Sjhibbits * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22239027Sjhibbits * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23239027Sjhibbits * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24239027Sjhibbits * SUCH DAMAGE. 25239027Sjhibbits */ 26239027Sjhibbits 27239027Sjhibbits#include <sys/cdefs.h> 28239027Sjhibbits__FBSDID("$FreeBSD: releng/11.0/sys/powerpc/powermac/nvbl.c 278945 2015-02-18 07:34:32Z jhibbits $"); 29239027Sjhibbits 30239027Sjhibbits#include <sys/param.h> 31239027Sjhibbits#include <sys/bus.h> 32239027Sjhibbits#include <sys/systm.h> 33239027Sjhibbits#include <sys/module.h> 34239027Sjhibbits#include <sys/kernel.h> 35239027Sjhibbits#include <sys/rman.h> 36239027Sjhibbits#include <sys/sysctl.h> 37239027Sjhibbits 38239027Sjhibbits#include <machine/bus.h> 39239027Sjhibbits 40239027Sjhibbits#include <dev/ofw/openfirm.h> 41278945Sjhibbits#include <dev/pci/pcivar.h> 42239027Sjhibbits 43278945Sjhibbits#define PCI_VENDOR_ID_NVIDIA 0x10de 44278945Sjhibbits 45239027Sjhibbits#define NVIDIA_BRIGHT_MIN (0x0ec) 46239027Sjhibbits#define NVIDIA_BRIGHT_MAX (0x538) 47239027Sjhibbits#define NVIDIA_BRIGHT_SCALE ((NVIDIA_BRIGHT_MAX - NVIDIA_BRIGHT_MIN)/100) 48239027Sjhibbits/* nVidia's MMIO registers are at PCI BAR[0] */ 49239027Sjhibbits#define NVIDIA_MMIO_PMC (0x0) 50239027Sjhibbits#define NVIDIA_PMC_OFF (NVIDIA_MMIO_PMC + 0x10f0) 51239027Sjhibbits#define NVIDIA_PMC_BL_SHIFT (16) 52258780Seadler#define NVIDIA_PMC_BL_EN (1U << 31) 53239027Sjhibbits 54239027Sjhibbits 55239027Sjhibbitsstruct nvbl_softc { 56239027Sjhibbits device_t dev; 57239027Sjhibbits struct resource *sc_memr; 58239027Sjhibbits}; 59239027Sjhibbits 60239027Sjhibbitsstatic void nvbl_identify(driver_t *driver, device_t parent); 61239027Sjhibbitsstatic int nvbl_probe(device_t dev); 62239027Sjhibbitsstatic int nvbl_attach(device_t dev); 63239027Sjhibbitsstatic int nvbl_setlevel(struct nvbl_softc *sc, int newlevel); 64239027Sjhibbitsstatic int nvbl_getlevel(struct nvbl_softc *sc); 65239027Sjhibbitsstatic int nvbl_sysctl(SYSCTL_HANDLER_ARGS); 66239027Sjhibbits 67239027Sjhibbitsstatic device_method_t nvbl_methods[] = { 68239027Sjhibbits /* Device interface */ 69239027Sjhibbits DEVMETHOD(device_identify, nvbl_identify), 70239027Sjhibbits DEVMETHOD(device_probe, nvbl_probe), 71239027Sjhibbits DEVMETHOD(device_attach, nvbl_attach), 72239027Sjhibbits {0, 0}, 73239027Sjhibbits}; 74239027Sjhibbits 75239027Sjhibbitsstatic driver_t nvbl_driver = { 76239027Sjhibbits "backlight", 77239027Sjhibbits nvbl_methods, 78239027Sjhibbits sizeof(struct nvbl_softc) 79239027Sjhibbits}; 80239027Sjhibbits 81239027Sjhibbitsstatic devclass_t nvbl_devclass; 82239027Sjhibbits 83239027SjhibbitsDRIVER_MODULE(nvbl, vgapci, nvbl_driver, nvbl_devclass, 0, 0); 84239027Sjhibbits 85239027Sjhibbitsstatic void 86239027Sjhibbitsnvbl_identify(driver_t *driver, device_t parent) 87239027Sjhibbits{ 88255100Sjhibbits if (OF_finddevice("mac-io/backlight") == -1) 89255100Sjhibbits return; 90239027Sjhibbits if (device_find_child(parent, "backlight", -1) == NULL) 91239027Sjhibbits device_add_child(parent, "backlight", -1); 92239027Sjhibbits} 93239027Sjhibbits 94239027Sjhibbitsstatic int 95239027Sjhibbitsnvbl_probe(device_t dev) 96239027Sjhibbits{ 97239027Sjhibbits char control[8]; 98239027Sjhibbits phandle_t handle; 99239027Sjhibbits 100239027Sjhibbits handle = OF_finddevice("mac-io/backlight"); 101239027Sjhibbits 102239548Sjhibbits if (handle == -1) 103239027Sjhibbits return (ENXIO); 104239027Sjhibbits 105239027Sjhibbits if (OF_getprop(handle, "backlight-control", &control, sizeof(control)) < 0) 106239027Sjhibbits return (ENXIO); 107239027Sjhibbits 108278945Sjhibbits if ((strcmp(control, "mnca") != 0) || 109278945Sjhibbits pci_get_vendor(device_get_parent(dev)) != PCI_VENDOR_ID_NVIDIA) 110239027Sjhibbits return (ENXIO); 111239027Sjhibbits 112239027Sjhibbits device_set_desc(dev, "PowerBook backlight for nVidia graphics"); 113239027Sjhibbits 114239027Sjhibbits return (0); 115239027Sjhibbits} 116239027Sjhibbits 117239027Sjhibbitsstatic int 118239027Sjhibbitsnvbl_attach(device_t dev) 119239027Sjhibbits{ 120239027Sjhibbits struct nvbl_softc *sc; 121239027Sjhibbits struct sysctl_ctx_list *ctx; 122239027Sjhibbits struct sysctl_oid *tree; 123239027Sjhibbits int rid; 124239027Sjhibbits 125239027Sjhibbits sc = device_get_softc(dev); 126239027Sjhibbits 127239027Sjhibbits rid = 0x10; /* BAR[0], for the MMIO register */ 128239027Sjhibbits sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 129239027Sjhibbits RF_ACTIVE | RF_SHAREABLE); 130239027Sjhibbits if (sc->sc_memr == NULL) { 131239027Sjhibbits device_printf(dev, "Could not alloc mem resource!\n"); 132239027Sjhibbits return (ENXIO); 133239027Sjhibbits } 134239027Sjhibbits 135239027Sjhibbits /* Turn on big-endian mode */ 136239027Sjhibbits if (!(bus_read_stream_4(sc->sc_memr, NVIDIA_MMIO_PMC + 4) & 0x01000001)) { 137239027Sjhibbits bus_write_stream_4(sc->sc_memr, NVIDIA_MMIO_PMC + 4, 0x01000001); 138239027Sjhibbits mb(); 139239027Sjhibbits } 140239027Sjhibbits 141239027Sjhibbits ctx = device_get_sysctl_ctx(dev); 142239027Sjhibbits tree = device_get_sysctl_tree(dev); 143239027Sjhibbits 144239027Sjhibbits SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 145239027Sjhibbits "level", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 146239027Sjhibbits nvbl_sysctl, "I", "Backlight level (0-100)"); 147239027Sjhibbits 148239027Sjhibbits return (0); 149239027Sjhibbits} 150239027Sjhibbits 151239027Sjhibbitsstatic int 152239027Sjhibbitsnvbl_setlevel(struct nvbl_softc *sc, int newlevel) 153239027Sjhibbits{ 154239027Sjhibbits uint32_t pmc_reg; 155239027Sjhibbits 156239027Sjhibbits if (newlevel > 100) 157239027Sjhibbits newlevel = 100; 158239027Sjhibbits 159239027Sjhibbits if (newlevel < 0) 160239027Sjhibbits newlevel = 0; 161239027Sjhibbits 162239027Sjhibbits if (newlevel > 0) 163239027Sjhibbits newlevel = (newlevel * NVIDIA_BRIGHT_SCALE) + NVIDIA_BRIGHT_MIN; 164239027Sjhibbits 165239027Sjhibbits pmc_reg = bus_read_stream_4(sc->sc_memr, NVIDIA_PMC_OFF) & 0xffff; 166239027Sjhibbits pmc_reg |= NVIDIA_PMC_BL_EN | (newlevel << NVIDIA_PMC_BL_SHIFT); 167239027Sjhibbits bus_write_stream_4(sc->sc_memr, NVIDIA_PMC_OFF, pmc_reg); 168239027Sjhibbits 169239027Sjhibbits return (0); 170239027Sjhibbits} 171239027Sjhibbits 172239027Sjhibbitsstatic int 173239027Sjhibbitsnvbl_getlevel(struct nvbl_softc *sc) 174239027Sjhibbits{ 175239027Sjhibbits uint16_t level; 176239027Sjhibbits 177239027Sjhibbits level = bus_read_stream_2(sc->sc_memr, NVIDIA_PMC_OFF) & 0x7fff; 178239027Sjhibbits 179239027Sjhibbits if (level < NVIDIA_BRIGHT_MIN) 180239027Sjhibbits return 0; 181239027Sjhibbits 182239027Sjhibbits level = (level - NVIDIA_BRIGHT_MIN) / NVIDIA_BRIGHT_SCALE; 183239027Sjhibbits 184239027Sjhibbits return (level); 185239027Sjhibbits} 186239027Sjhibbits 187239027Sjhibbitsstatic int 188239027Sjhibbitsnvbl_sysctl(SYSCTL_HANDLER_ARGS) 189239027Sjhibbits{ 190239027Sjhibbits struct nvbl_softc *sc; 191239027Sjhibbits int newlevel, error; 192239027Sjhibbits 193239027Sjhibbits sc = arg1; 194239027Sjhibbits 195239027Sjhibbits newlevel = nvbl_getlevel(sc); 196239027Sjhibbits 197239027Sjhibbits error = sysctl_handle_int(oidp, &newlevel, 0, req); 198239027Sjhibbits 199239027Sjhibbits if (error || !req->newptr) 200239027Sjhibbits return (error); 201239027Sjhibbits 202239027Sjhibbits return (nvbl_setlevel(sc, newlevel)); 203239027Sjhibbits} 204