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 #ifndef PCI_VENDOR_ID_ATI
43 #define PCI_VENDOR_ID_ATI 0x1002
46 /* From the xf86-video-ati driver's radeon_reg.h */
47 #define RADEON_LVDS_GEN_CNTL 0x02d0
48 #define RADEON_LVDS_ON (1 << 0)
49 #define RADEON_LVDS_DISPLAY_DIS (1 << 1)
50 #define RADEON_LVDS_PANEL_TYPE (1 << 2)
51 #define RADEON_LVDS_PANEL_FORMAT (1 << 3)
52 #define RADEON_LVDS_RST_FM (1 << 6)
53 #define RADEON_LVDS_EN (1 << 7)
54 #define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8
55 #define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8)
56 #define RADEON_LVDS_BL_MOD_EN (1 << 16)
57 #define RADEON_LVDS_DIGON (1 << 18)
58 #define RADEON_LVDS_BLON (1 << 19)
59 #define RADEON_LVDS_PLL_CNTL 0x02d4
60 #define RADEON_LVDS_PLL_EN (1 << 16)
61 #define RADEON_LVDS_PLL_RESET (1 << 17)
62 #define RADEON_PIXCLKS_CNTL 0x002d
63 #define RADEON_PIXCLK_LVDS_ALWAYS_ONb (1 << 14)
64 #define RADEON_DISP_PWR_MAN 0x0d08
65 #define RADEON_AUTO_PWRUP_EN (1 << 26)
66 #define RADEON_CLOCK_CNTL_DATA 0x000c
67 #define RADEON_CLOCK_CNTL_INDEX 0x0008
68 #define RADEON_PLL_WR_EN (1 << 7)
69 #define RADEON_CRTC_GEN_CNTL 0x0050
72 struct resource
*sc_memr
;
76 static void atibl_identify(driver_t
*driver
, device_t parent
);
77 static int atibl_probe(device_t dev
);
78 static int atibl_attach(device_t dev
);
79 static int atibl_setlevel(struct atibl_softc
*sc
, int newlevel
);
80 static int atibl_getlevel(struct atibl_softc
*sc
);
81 static int atibl_resume(device_t dev
);
82 static int atibl_suspend(device_t dev
);
83 static int atibl_sysctl(SYSCTL_HANDLER_ARGS
);
85 static device_method_t atibl_methods
[] = {
86 /* Device interface */
87 DEVMETHOD(device_identify
, atibl_identify
),
88 DEVMETHOD(device_probe
, atibl_probe
),
89 DEVMETHOD(device_attach
, atibl_attach
),
90 DEVMETHOD(device_suspend
, atibl_suspend
),
91 DEVMETHOD(device_resume
, atibl_resume
),
95 static driver_t atibl_driver
= {
98 sizeof(struct atibl_softc
)
101 DRIVER_MODULE(atibl
, vgapci
, atibl_driver
, 0, 0);
104 atibl_identify(driver_t
*driver
, device_t parent
)
106 if (OF_finddevice("mac-io/backlight") == -1)
108 if (device_find_child(parent
, "backlight", -1) == NULL
)
109 device_add_child(parent
, "backlight", DEVICE_UNIT_ANY
);
113 atibl_probe(device_t dev
)
118 handle
= OF_finddevice("mac-io/backlight");
123 if (OF_getprop(handle
, "backlight-control", &control
, sizeof(control
)) < 0)
126 if (strcmp(control
, "ati") != 0 &&
127 (strcmp(control
, "mnca") != 0 ||
128 pci_get_vendor(device_get_parent(dev
)) != 0x1002))
131 device_set_desc(dev
, "PowerBook backlight for ATI graphics");
137 atibl_attach(device_t dev
)
139 struct atibl_softc
*sc
;
140 struct sysctl_ctx_list
*ctx
;
141 struct sysctl_oid
*tree
;
144 sc
= device_get_softc(dev
);
146 rid
= 0x18; /* BAR[2], for the MMIO register */
147 sc
->sc_memr
= bus_alloc_resource_any(dev
, SYS_RES_MEMORY
, &rid
,
148 RF_ACTIVE
| RF_SHAREABLE
);
149 if (sc
->sc_memr
== NULL
) {
150 device_printf(dev
, "Could not alloc mem resource!\n");
154 ctx
= device_get_sysctl_ctx(dev
);
155 tree
= device_get_sysctl_tree(dev
);
157 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(tree
), OID_AUTO
,
158 "level", CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NEEDGIANT
, sc
, 0,
159 atibl_sysctl
, "I", "Backlight level (0-100)");
164 static uint32_t __inline
165 atibl_pll_rreg(struct atibl_softc
*sc
, uint32_t reg
)
167 uint32_t data
, save
, tmp
;
169 bus_write_1(sc
->sc_memr
, RADEON_CLOCK_CNTL_INDEX
, (reg
& 0x3f));
170 (void)bus_read_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_DATA
);
171 (void)bus_read_4(sc
->sc_memr
, RADEON_CRTC_GEN_CNTL
);
173 data
= bus_read_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_DATA
);
175 /* Only necessary on R300, but won't hurt others. */
176 save
= bus_read_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_INDEX
);
177 tmp
= save
& (~0x3f | RADEON_PLL_WR_EN
);
178 bus_write_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_INDEX
, tmp
);
179 tmp
= bus_read_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_DATA
);
180 bus_write_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_INDEX
, save
);
186 atibl_pll_wreg(struct atibl_softc
*sc
, uint32_t reg
, uint32_t val
)
190 bus_write_1(sc
->sc_memr
, RADEON_CLOCK_CNTL_INDEX
,
191 ((reg
& 0x3f) | RADEON_PLL_WR_EN
));
192 (void)bus_read_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_DATA
);
193 (void)bus_read_4(sc
->sc_memr
, RADEON_CRTC_GEN_CNTL
);
195 bus_write_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_DATA
, val
);
198 /* Only necessary on R300, but won't hurt others. */
199 save
= bus_read_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_INDEX
);
200 tmp
= save
& (~0x3f | RADEON_PLL_WR_EN
);
201 bus_write_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_INDEX
, tmp
);
202 tmp
= bus_read_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_DATA
);
203 bus_write_4(sc
->sc_memr
, RADEON_CLOCK_CNTL_INDEX
, save
);
207 atibl_setlevel(struct atibl_softc
*sc
, int newlevel
)
209 uint32_t lvds_gen_cntl
;
210 uint32_t lvds_pll_cntl
;
211 uint32_t pixclks_cntl
;
212 uint32_t disp_pwr_reg
;
220 lvds_gen_cntl
= bus_read_4(sc
->sc_memr
, RADEON_LVDS_GEN_CNTL
);
223 newlevel
= (newlevel
* 5) / 2 + 5;
224 disp_pwr_reg
= bus_read_4(sc
->sc_memr
, RADEON_DISP_PWR_MAN
);
225 disp_pwr_reg
|= RADEON_AUTO_PWRUP_EN
;
226 bus_write_4(sc
->sc_memr
, RADEON_DISP_PWR_MAN
, disp_pwr_reg
);
227 lvds_pll_cntl
= bus_read_4(sc
->sc_memr
, RADEON_LVDS_PLL_CNTL
);
228 lvds_pll_cntl
|= RADEON_LVDS_PLL_EN
;
229 bus_write_4(sc
->sc_memr
, RADEON_LVDS_PLL_CNTL
, lvds_pll_cntl
);
230 lvds_pll_cntl
&= ~RADEON_LVDS_PLL_RESET
;
231 bus_write_4(sc
->sc_memr
, RADEON_LVDS_PLL_CNTL
, lvds_pll_cntl
);
234 lvds_gen_cntl
&= ~(RADEON_LVDS_DISPLAY_DIS
|
235 RADEON_LVDS_BL_MOD_LEVEL_MASK
);
236 lvds_gen_cntl
|= RADEON_LVDS_ON
| RADEON_LVDS_EN
|
237 RADEON_LVDS_DIGON
| RADEON_LVDS_BLON
;
238 lvds_gen_cntl
|= (newlevel
<< RADEON_LVDS_BL_MOD_LEVEL_SHIFT
) &
239 RADEON_LVDS_BL_MOD_LEVEL_MASK
;
240 lvds_gen_cntl
|= RADEON_LVDS_BL_MOD_EN
;
242 bus_write_4(sc
->sc_memr
, RADEON_LVDS_GEN_CNTL
, lvds_gen_cntl
);
244 pixclks_cntl
= atibl_pll_rreg(sc
, RADEON_PIXCLKS_CNTL
);
245 atibl_pll_wreg(sc
, RADEON_PIXCLKS_CNTL
,
246 pixclks_cntl
& ~RADEON_PIXCLK_LVDS_ALWAYS_ONb
);
247 lvds_gen_cntl
|= RADEON_LVDS_DISPLAY_DIS
;
248 lvds_gen_cntl
&= ~(RADEON_LVDS_BL_MOD_EN
| RADEON_LVDS_BL_MOD_LEVEL_MASK
);
249 bus_write_4(sc
->sc_memr
, RADEON_LVDS_GEN_CNTL
, lvds_gen_cntl
);
250 lvds_gen_cntl
&= ~(RADEON_LVDS_ON
| RADEON_LVDS_EN
);
252 bus_write_4(sc
->sc_memr
, RADEON_LVDS_GEN_CNTL
, lvds_gen_cntl
);
254 atibl_pll_wreg(sc
, RADEON_PIXCLKS_CNTL
, pixclks_cntl
);
262 atibl_getlevel(struct atibl_softc
*sc
)
264 uint32_t lvds_gen_cntl
;
267 lvds_gen_cntl
= bus_read_4(sc
->sc_memr
, RADEON_LVDS_GEN_CNTL
);
269 level
= ((lvds_gen_cntl
& RADEON_LVDS_BL_MOD_LEVEL_MASK
) >>
270 RADEON_LVDS_BL_MOD_LEVEL_SHIFT
);
272 level
= ((level
- 5) * 2) / 5;
278 atibl_suspend(device_t dev
)
280 struct atibl_softc
*sc
;
282 sc
= device_get_softc(dev
);
284 sc
->sc_level
= atibl_getlevel(sc
);
285 atibl_setlevel(sc
, 0);
291 atibl_resume(device_t dev
)
293 struct atibl_softc
*sc
;
295 sc
= device_get_softc(dev
);
297 atibl_setlevel(sc
, sc
->sc_level
);
303 atibl_sysctl(SYSCTL_HANDLER_ARGS
)
305 struct atibl_softc
*sc
;
310 newlevel
= atibl_getlevel(sc
);
312 error
= sysctl_handle_int(oidp
, &newlevel
, 0, req
);
314 if (error
|| !req
->newptr
)
317 return (atibl_setlevel(sc
, newlevel
));