jcs's openbsd hax
openbsd
1/* $OpenBSD: abl.c,v 1.6 2025/01/23 11:24:34 kettenis Exp $ */
2
3/*
4 * Copyright (c) 2020 Marcus Glocker <mglocker@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * Driver for controlling the screen backlight brightness on Apple machines.
21 */
22#include <sys/param.h>
23#include <sys/systm.h>
24
25#include <dev/acpi/acpivar.h>
26#include <dev/acpi/acpidev.h>
27#include <dev/acpi/amltypes.h>
28#include <dev/acpi/dsdt.h>
29
30#include <dev/pci/pcidevs.h>
31
32#include <dev/wscons/wsconsio.h>
33#include <dev/wscons/wsdisplayvar.h>
34
35#ifdef ABL_DEBUG
36#define DPRINTF(x) printf x
37#else
38#define DPRINTF(x)
39#endif
40
41#define ABL_IO_BASE_INTEL 0xb2
42#define ABL_IO_BASE_NVIDIA 0x52e
43#define ABL_IO_SIZE 2
44#define ABL_IO_LO 0x00
45#define ABL_IO_HI 0x01
46#define ABL_BRIGHTNESS_MIN 0
47#define ABL_BRIGHTNESS_MAX 15
48
49struct abl_softc {
50 struct device sc_dev;
51
52 struct acpi_softc *sc_acpi;
53 struct aml_node *sc_devnode;
54
55 bus_space_tag_t sc_bt;
56 bus_space_handle_t sc_bh;
57
58 bus_addr_t sc_io_base;
59 uint8_t sc_brightness;
60};
61
62int abl_match(struct device *, void *, void *);
63void abl_attach(struct device *, struct device *, void *);
64
65int abl_get_brightness(struct abl_softc *);
66int abl_set_brightness(struct abl_softc *, uint8_t);
67
68/* Hooks for wsconsole brightness control. */
69int abl_get_param(struct wsdisplay_param *);
70int abl_set_param(struct wsdisplay_param *);
71
72const struct cfattach abl_ca = {
73 sizeof(struct abl_softc), abl_match, abl_attach, NULL, NULL
74};
75
76struct cfdriver abl_cd = {
77 NULL, "abl", DV_DULL
78};
79
80const char *abl_hids[] = {
81 "APP0002", NULL
82};
83
84int
85abl_match(struct device *parent, void *match, void *aux)
86{
87 struct acpi_attach_args *aa = aux;
88 struct cfdata *cf = match;
89
90 return acpi_matchhids(aa, abl_hids, cf->cf_driver->cd_name);
91}
92
93void
94abl_attach(struct device *parent, struct device *self, void *aux)
95{
96 struct abl_softc *sc = (struct abl_softc *)self;
97 struct acpi_attach_args *aaa = aux;
98 struct aml_value res;
99 int64_t sta;
100 int reg;
101 pci_chipset_tag_t pc;
102 pcitag_t tag;
103
104 sc->sc_acpi = (struct acpi_softc *)parent;
105 sc->sc_devnode = aaa->aaa_node;
106
107 printf(": %s", sc->sc_devnode->name);
108
109 sta = acpi_getsta(sc->sc_acpi, sc->sc_devnode);
110 if ((sta & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
111 (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) {
112 printf(": not enabled\n");
113 return;
114 }
115
116 if (!(aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CID", 0, NULL, &res)))
117 printf(" (%s)", res.v_string);
118
119 /* Backlight on non-iMacs is already handled differently. */
120 if (strncmp(hw_prod, "iMac", 4)) {
121 printf("\n");
122 return;
123 }
124
125 /*
126 * We need to check on what type of PCI controller we're running on to
127 * access the right I/O space.
128 */
129 pc = pci_lookup_segment(0, 0);
130 tag = pci_make_tag(pc, 0, 0, 0);
131 reg = pci_conf_read(pc, tag, PCI_ID_REG);
132
133 switch (PCI_VENDOR(reg)) {
134 case PCI_VENDOR_INTEL:
135 sc->sc_io_base = ABL_IO_BASE_INTEL;
136 break;
137 case PCI_VENDOR_NVIDIA:
138 sc->sc_io_base = ABL_IO_BASE_NVIDIA;
139 break;
140 default:
141 printf(": pci controller not supported\n");
142 return;
143 }
144
145 /*
146 * Map I/O space. This driver uses the ACPI SMI command port.
147 * This port has already been claimed by the generic ACPI code
148 * so we need to work around that here by calling _bus_space_map().
149 */
150 sc->sc_bt = aaa->aaa_iot;
151 if (_bus_space_map(sc->sc_bt, sc->sc_io_base, ABL_IO_SIZE, 0,
152 &sc->sc_bh)) {
153 printf(": can't map register\n");
154 return;
155 }
156
157 /* Read the current brightness value initially. */
158 sc->sc_brightness = abl_get_brightness(sc);
159
160 /* Map wsconsole hook functions. */
161 ws_get_param = abl_get_param;
162 ws_set_param = abl_set_param;
163
164 printf("\n");
165}
166
167int
168abl_get_brightness(struct abl_softc *sc)
169{
170 uint8_t val;
171
172 bus_space_write_1(sc->sc_bt, sc->sc_bh, ABL_IO_HI, 0x03);
173 bus_space_write_1(sc->sc_bt, sc->sc_bh, ABL_IO_LO, 0xbf);
174 val = bus_space_read_1(sc->sc_bt, sc->sc_bh, ABL_IO_HI);
175
176 return (val >> 4);
177}
178
179int
180abl_set_brightness(struct abl_softc *sc, uint8_t val)
181{
182 bus_space_write_1(sc->sc_bt, sc->sc_bh, ABL_IO_HI, 0x04 | (val << 4));
183 bus_space_write_1(sc->sc_bt, sc->sc_bh, ABL_IO_LO, 0xbf);
184
185 return 0;
186}
187
188int
189abl_get_param(struct wsdisplay_param *dp)
190{
191 struct abl_softc *sc = abl_cd.cd_devs[0];
192
193 if (sc == NULL)
194 return -1;
195
196 switch (dp->param) {
197 case WSDISPLAYIO_PARAM_BRIGHTNESS:
198 DPRINTF(("abl_get_param: sc->sc_brightness = %d\n",
199 sc->sc_brightness));
200 dp->min = ABL_BRIGHTNESS_MIN;
201 dp->max = ABL_BRIGHTNESS_MAX;
202 dp->curval = sc->sc_brightness;
203 return 0;
204 default:
205 return -1;
206 }
207}
208
209int
210abl_set_param(struct wsdisplay_param *dp)
211{
212 struct abl_softc *sc = abl_cd.cd_devs[0];
213
214 if (sc == NULL)
215 return -1;
216
217 switch (dp->param) {
218 case WSDISPLAYIO_PARAM_BRIGHTNESS:
219 DPRINTF(("abl_set_param: curval = %d\n", dp->curval));
220 if (dp->curval < ABL_BRIGHTNESS_MIN)
221 dp->curval = 0;
222 if (dp->curval > ABL_BRIGHTNESS_MAX)
223 dp->curval = ABL_BRIGHTNESS_MAX;
224 abl_set_brightness(sc, dp->curval);
225 sc->sc_brightness = dp->curval;
226 return 0;
227 default:
228 return -1;
229 }
230}