2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2012 Justin Hibbits
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/module.h>
33 #include <sys/kernel.h>
35 #include <sys/sysctl.h>
37 #include <machine/bus.h>
39 #include <dev/ofw/openfirm.h>
40 #include <dev/pci/pcivar.h>
42 #define PCI_VENDOR_ID_NVIDIA 0x10de
44 #define NVIDIA_BRIGHT_MIN (0x0ec)
45 #define NVIDIA_BRIGHT_MAX (0x538)
46 #define NVIDIA_BRIGHT_SCALE ((NVIDIA_BRIGHT_MAX - NVIDIA_BRIGHT_MIN)/100)
47 /* nVidia's MMIO registers are at PCI BAR[0] */
48 #define NVIDIA_MMIO_PMC (0x0)
49 #define NVIDIA_PMC_OFF (NVIDIA_MMIO_PMC + 0x10f0)
50 #define NVIDIA_PMC_BL_SHIFT (16)
51 #define NVIDIA_PMC_BL_EN (1U << 31)
55 struct resource
*sc_memr
;
58 static void nvbl_identify(driver_t
*driver
, device_t parent
);
59 static int nvbl_probe(device_t dev
);
60 static int nvbl_attach(device_t dev
);
61 static int nvbl_setlevel(struct nvbl_softc
*sc
, int newlevel
);
62 static int nvbl_getlevel(struct nvbl_softc
*sc
);
63 static int nvbl_sysctl(SYSCTL_HANDLER_ARGS
);
65 static device_method_t nvbl_methods
[] = {
66 /* Device interface */
67 DEVMETHOD(device_identify
, nvbl_identify
),
68 DEVMETHOD(device_probe
, nvbl_probe
),
69 DEVMETHOD(device_attach
, nvbl_attach
),
73 static driver_t nvbl_driver
= {
76 sizeof(struct nvbl_softc
)
79 DRIVER_MODULE(nvbl
, vgapci
, nvbl_driver
, 0, 0);
82 nvbl_identify(driver_t
*driver
, device_t parent
)
84 if (OF_finddevice("mac-io/backlight") == -1)
86 if (device_find_child(parent
, "backlight", -1) == NULL
)
87 device_add_child(parent
, "backlight", DEVICE_UNIT_ANY
);
91 nvbl_probe(device_t dev
)
96 handle
= OF_finddevice("mac-io/backlight");
101 if (OF_getprop(handle
, "backlight-control", &control
, sizeof(control
)) < 0)
104 if ((strcmp(control
, "mnca") != 0) ||
105 pci_get_vendor(device_get_parent(dev
)) != PCI_VENDOR_ID_NVIDIA
)
108 device_set_desc(dev
, "PowerBook backlight for nVidia graphics");
114 nvbl_attach(device_t dev
)
116 struct nvbl_softc
*sc
;
117 struct sysctl_ctx_list
*ctx
;
118 struct sysctl_oid
*tree
;
121 sc
= device_get_softc(dev
);
123 rid
= 0x10; /* BAR[0], for the MMIO register */
124 sc
->sc_memr
= bus_alloc_resource_any(dev
, SYS_RES_MEMORY
, &rid
,
125 RF_ACTIVE
| RF_SHAREABLE
);
126 if (sc
->sc_memr
== NULL
) {
127 device_printf(dev
, "Could not alloc mem resource!\n");
131 /* Turn on big-endian mode */
132 if (!(bus_read_stream_4(sc
->sc_memr
, NVIDIA_MMIO_PMC
+ 4) & 0x01000001)) {
133 bus_write_stream_4(sc
->sc_memr
, NVIDIA_MMIO_PMC
+ 4, 0x01000001);
137 ctx
= device_get_sysctl_ctx(dev
);
138 tree
= device_get_sysctl_tree(dev
);
140 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(tree
), OID_AUTO
,
141 "level", CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NEEDGIANT
, sc
, 0,
142 nvbl_sysctl
, "I", "Backlight level (0-100)");
148 nvbl_setlevel(struct nvbl_softc
*sc
, int newlevel
)
159 newlevel
= (newlevel
* NVIDIA_BRIGHT_SCALE
) + NVIDIA_BRIGHT_MIN
;
161 pmc_reg
= bus_read_stream_4(sc
->sc_memr
, NVIDIA_PMC_OFF
) & 0xffff;
162 pmc_reg
|= NVIDIA_PMC_BL_EN
| (newlevel
<< NVIDIA_PMC_BL_SHIFT
);
163 bus_write_stream_4(sc
->sc_memr
, NVIDIA_PMC_OFF
, pmc_reg
);
169 nvbl_getlevel(struct nvbl_softc
*sc
)
173 level
= bus_read_stream_2(sc
->sc_memr
, NVIDIA_PMC_OFF
) & 0x7fff;
175 if (level
< NVIDIA_BRIGHT_MIN
)
178 level
= (level
- NVIDIA_BRIGHT_MIN
) / NVIDIA_BRIGHT_SCALE
;
184 nvbl_sysctl(SYSCTL_HANDLER_ARGS
)
186 struct nvbl_softc
*sc
;
191 newlevel
= nvbl_getlevel(sc
);
193 error
= sysctl_handle_int(oidp
, &newlevel
, 0, req
);
195 if (error
|| !req
->newptr
)
198 return (nvbl_setlevel(sc
, newlevel
));