Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/powerpc/powermac/atibl.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2012 Justin Hibbits
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
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.
15
*
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
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/bus.h>
31
#include <sys/systm.h>
32
#include <sys/module.h>
33
#include <sys/kernel.h>
34
#include <sys/rman.h>
35
#include <sys/sysctl.h>
36
37
#include <machine/bus.h>
38
39
#include <dev/ofw/openfirm.h>
40
#include <dev/pci/pcivar.h>
41
42
#ifndef PCI_VENDOR_ID_ATI
43
#define PCI_VENDOR_ID_ATI 0x1002
44
#endif
45
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
70
71
struct atibl_softc {
72
struct resource *sc_memr;
73
int sc_level;
74
};
75
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);
84
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),
92
{0, 0},
93
};
94
95
static driver_t atibl_driver = {
96
"backlight",
97
atibl_methods,
98
sizeof(struct atibl_softc)
99
};
100
101
DRIVER_MODULE(atibl, vgapci, atibl_driver, 0, 0);
102
103
static void
104
atibl_identify(driver_t *driver, device_t parent)
105
{
106
if (OF_finddevice("mac-io/backlight") == -1)
107
return;
108
if (device_find_child(parent, "backlight", DEVICE_UNIT_ANY) == NULL)
109
device_add_child(parent, "backlight", DEVICE_UNIT_ANY);
110
}
111
112
static int
113
atibl_probe(device_t dev)
114
{
115
char control[8];
116
phandle_t handle;
117
118
handle = OF_finddevice("mac-io/backlight");
119
120
if (handle == -1)
121
return (ENXIO);
122
123
if (OF_getprop(handle, "backlight-control", &control, sizeof(control)) < 0)
124
return (ENXIO);
125
126
if (strcmp(control, "ati") != 0 &&
127
(strcmp(control, "mnca") != 0 ||
128
pci_get_vendor(device_get_parent(dev)) != 0x1002))
129
return (ENXIO);
130
131
device_set_desc(dev, "PowerBook backlight for ATI graphics");
132
133
return (0);
134
}
135
136
static int
137
atibl_attach(device_t dev)
138
{
139
struct atibl_softc *sc;
140
struct sysctl_ctx_list *ctx;
141
struct sysctl_oid *tree;
142
int rid;
143
144
sc = device_get_softc(dev);
145
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");
151
return (ENXIO);
152
}
153
154
ctx = device_get_sysctl_ctx(dev);
155
tree = device_get_sysctl_tree(dev);
156
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)");
160
161
return (0);
162
}
163
164
static uint32_t __inline
165
atibl_pll_rreg(struct atibl_softc *sc, uint32_t reg)
166
{
167
uint32_t data, save, tmp;
168
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);
172
173
data = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA);
174
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);
181
182
return data;
183
}
184
185
static void __inline
186
atibl_pll_wreg(struct atibl_softc *sc, uint32_t reg, uint32_t val)
187
{
188
uint32_t save, tmp;
189
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);
194
195
bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA, val);
196
DELAY(5000);
197
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);
204
}
205
206
static int
207
atibl_setlevel(struct atibl_softc *sc, int newlevel)
208
{
209
uint32_t lvds_gen_cntl;
210
uint32_t lvds_pll_cntl;
211
uint32_t pixclks_cntl;
212
uint32_t disp_pwr_reg;
213
214
if (newlevel > 100)
215
newlevel = 100;
216
217
if (newlevel < 0)
218
newlevel = 0;
219
220
lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL);
221
222
if (newlevel > 0) {
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);
232
DELAY(1000);
233
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;
241
DELAY(200000);
242
bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
243
} else {
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);
251
DELAY(200000);
252
bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
253
254
atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, pixclks_cntl);
255
DELAY(200000);
256
}
257
258
return (0);
259
}
260
261
static int
262
atibl_getlevel(struct atibl_softc *sc)
263
{
264
uint32_t lvds_gen_cntl;
265
int level;
266
267
lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL);
268
269
level = ((lvds_gen_cntl & RADEON_LVDS_BL_MOD_LEVEL_MASK) >>
270
RADEON_LVDS_BL_MOD_LEVEL_SHIFT);
271
if (level != 0)
272
level = ((level - 5) * 2) / 5;
273
274
return (level);
275
}
276
277
static int
278
atibl_suspend(device_t dev)
279
{
280
struct atibl_softc *sc;
281
282
sc = device_get_softc(dev);
283
284
sc->sc_level = atibl_getlevel(sc);
285
atibl_setlevel(sc, 0);
286
287
return (0);
288
}
289
290
static int
291
atibl_resume(device_t dev)
292
{
293
struct atibl_softc *sc;
294
295
sc = device_get_softc(dev);
296
297
atibl_setlevel(sc, sc->sc_level);
298
299
return (0);
300
}
301
302
static int
303
atibl_sysctl(SYSCTL_HANDLER_ARGS)
304
{
305
struct atibl_softc *sc;
306
int newlevel, error;
307
308
sc = arg1;
309
310
newlevel = atibl_getlevel(sc);
311
312
error = sysctl_handle_int(oidp, &newlevel, 0, req);
313
314
if (error || !req->newptr)
315
return (error);
316
317
return (atibl_setlevel(sc, newlevel));
318
}
319
320