1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/systm.h> 35 #include <sys/module.h> 36 #include <sys/kernel.h> 37 #include <sys/rman.h> 38 #include <sys/sysctl.h> 39 40 #include <machine/bus.h> 41 42 #include <dev/ofw/openfirm.h> 43 #include <dev/pci/pcivar.h> 44 45 #ifndef PCI_VENDOR_ID_ATI 46 #define PCI_VENDOR_ID_ATI 0x1002 47 #endif 48 49 /* From the xf86-video-ati driver's radeon_reg.h */ 50 #define RADEON_LVDS_GEN_CNTL 0x02d0 51 #define RADEON_LVDS_ON (1 << 0) 52 #define RADEON_LVDS_DISPLAY_DIS (1 << 1) 53 #define RADEON_LVDS_PANEL_TYPE (1 << 2) 54 #define RADEON_LVDS_PANEL_FORMAT (1 << 3) 55 #define RADEON_LVDS_RST_FM (1 << 6) 56 #define RADEON_LVDS_EN (1 << 7) 57 #define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 58 #define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) 59 #define RADEON_LVDS_BL_MOD_EN (1 << 16) 60 #define RADEON_LVDS_DIGON (1 << 18) 61 #define RADEON_LVDS_BLON (1 << 19) 62 #define RADEON_LVDS_PLL_CNTL 0x02d4 63 #define RADEON_LVDS_PLL_EN (1 << 16) 64 #define RADEON_LVDS_PLL_RESET (1 << 17) 65 #define RADEON_PIXCLKS_CNTL 0x002d 66 #define RADEON_PIXCLK_LVDS_ALWAYS_ONb (1 << 14) 67 #define RADEON_DISP_PWR_MAN 0x0d08 68 #define RADEON_AUTO_PWRUP_EN (1 << 26) 69 #define RADEON_CLOCK_CNTL_DATA 0x000c 70 #define RADEON_CLOCK_CNTL_INDEX 0x0008 71 #define RADEON_PLL_WR_EN (1 << 7) 72 #define RADEON_CRTC_GEN_CNTL 0x0050 73 74 struct atibl_softc { 75 struct resource *sc_memr; 76 int sc_level; 77 }; 78 79 static void atibl_identify(driver_t *driver, device_t parent); 80 static int atibl_probe(device_t dev); 81 static int atibl_attach(device_t dev); 82 static int atibl_setlevel(struct atibl_softc *sc, int newlevel); 83 static int atibl_getlevel(struct atibl_softc *sc); 84 static int atibl_resume(device_t dev); 85 static int atibl_suspend(device_t dev); 86 static int atibl_sysctl(SYSCTL_HANDLER_ARGS); 87 88 static device_method_t atibl_methods[] = { 89 /* Device interface */ 90 DEVMETHOD(device_identify, atibl_identify), 91 DEVMETHOD(device_probe, atibl_probe), 92 DEVMETHOD(device_attach, atibl_attach), 93 DEVMETHOD(device_suspend, atibl_suspend), 94 DEVMETHOD(device_resume, atibl_resume), 95 {0, 0}, 96 }; 97 98 static driver_t atibl_driver = { 99 "backlight", 100 atibl_methods, 101 sizeof(struct atibl_softc) 102 }; 103 104 static devclass_t atibl_devclass; 105 106 DRIVER_MODULE(atibl, vgapci, atibl_driver, atibl_devclass, 0, 0); 107 108 static void 109 atibl_identify(driver_t *driver, device_t parent) 110 { 111 if (OF_finddevice("mac-io/backlight") == -1) 112 return; 113 if (device_find_child(parent, "backlight", -1) == NULL) 114 device_add_child(parent, "backlight", -1); 115 } 116 117 static int 118 atibl_probe(device_t dev) 119 { 120 char control[8]; 121 phandle_t handle; 122 123 handle = OF_finddevice("mac-io/backlight"); 124 125 if (handle == -1) 126 return (ENXIO); 127 128 if (OF_getprop(handle, "backlight-control", &control, sizeof(control)) < 0) 129 return (ENXIO); 130 131 if (strcmp(control, "ati") != 0 && 132 (strcmp(control, "mnca") != 0 || 133 pci_get_vendor(device_get_parent(dev)) != 0x1002)) 134 return (ENXIO); 135 136 device_set_desc(dev, "PowerBook backlight for ATI graphics"); 137 138 return (0); 139 } 140 141 static int 142 atibl_attach(device_t dev) 143 { 144 struct atibl_softc *sc; 145 struct sysctl_ctx_list *ctx; 146 struct sysctl_oid *tree; 147 int rid; 148 149 sc = device_get_softc(dev); 150 151 rid = 0x18; /* BAR[2], for the MMIO register */ 152 sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 153 RF_ACTIVE | RF_SHAREABLE); 154 if (sc->sc_memr == NULL) { 155 device_printf(dev, "Could not alloc mem resource!\n"); 156 return (ENXIO); 157 } 158 159 ctx = device_get_sysctl_ctx(dev); 160 tree = device_get_sysctl_tree(dev); 161 162 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 163 "level", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, 164 atibl_sysctl, "I", "Backlight level (0-100)"); 165 166 return (0); 167 } 168 169 static uint32_t __inline 170 atibl_pll_rreg(struct atibl_softc *sc, uint32_t reg) 171 { 172 uint32_t data, save, tmp; 173 174 bus_write_1(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, (reg & 0x3f)); 175 (void)bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 176 (void)bus_read_4(sc->sc_memr, RADEON_CRTC_GEN_CNTL); 177 178 data = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 179 180 /* Only necessary on R300, but won't hurt others. */ 181 save = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX); 182 tmp = save & (~0x3f | RADEON_PLL_WR_EN); 183 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, tmp); 184 tmp = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 185 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, save); 186 187 return data; 188 } 189 190 static void __inline 191 atibl_pll_wreg(struct atibl_softc *sc, uint32_t reg, uint32_t val) 192 { 193 uint32_t save, tmp; 194 195 bus_write_1(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, 196 ((reg & 0x3f) | RADEON_PLL_WR_EN)); 197 (void)bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 198 (void)bus_read_4(sc->sc_memr, RADEON_CRTC_GEN_CNTL); 199 200 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA, val); 201 DELAY(5000); 202 203 /* Only necessary on R300, but won't hurt others. */ 204 save = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX); 205 tmp = save & (~0x3f | RADEON_PLL_WR_EN); 206 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, tmp); 207 tmp = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 208 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, save); 209 } 210 211 static int 212 atibl_setlevel(struct atibl_softc *sc, int newlevel) 213 { 214 uint32_t lvds_gen_cntl; 215 uint32_t lvds_pll_cntl; 216 uint32_t pixclks_cntl; 217 uint32_t disp_pwr_reg; 218 219 if (newlevel > 100) 220 newlevel = 100; 221 222 if (newlevel < 0) 223 newlevel = 0; 224 225 lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL); 226 227 if (newlevel > 0) { 228 newlevel = (newlevel * 5) / 2 + 5; 229 disp_pwr_reg = bus_read_4(sc->sc_memr, RADEON_DISP_PWR_MAN); 230 disp_pwr_reg |= RADEON_AUTO_PWRUP_EN; 231 bus_write_4(sc->sc_memr, RADEON_DISP_PWR_MAN, disp_pwr_reg); 232 lvds_pll_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL); 233 lvds_pll_cntl |= RADEON_LVDS_PLL_EN; 234 bus_write_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 235 lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; 236 bus_write_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 237 DELAY(1000); 238 239 lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS | 240 RADEON_LVDS_BL_MOD_LEVEL_MASK); 241 lvds_gen_cntl |= RADEON_LVDS_ON | RADEON_LVDS_EN | 242 RADEON_LVDS_DIGON | RADEON_LVDS_BLON; 243 lvds_gen_cntl |= (newlevel << RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 244 RADEON_LVDS_BL_MOD_LEVEL_MASK; 245 lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; 246 DELAY(200000); 247 bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 248 } else { 249 pixclks_cntl = atibl_pll_rreg(sc, RADEON_PIXCLKS_CNTL); 250 atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, 251 pixclks_cntl & ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); 252 lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; 253 lvds_gen_cntl &= ~(RADEON_LVDS_BL_MOD_EN | RADEON_LVDS_BL_MOD_LEVEL_MASK); 254 bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 255 lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN); 256 DELAY(200000); 257 bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 258 259 atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, pixclks_cntl); 260 DELAY(200000); 261 } 262 263 return (0); 264 } 265 266 static int 267 atibl_getlevel(struct atibl_softc *sc) 268 { 269 uint32_t lvds_gen_cntl; 270 int level; 271 272 lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL); 273 274 level = ((lvds_gen_cntl & RADEON_LVDS_BL_MOD_LEVEL_MASK) >> 275 RADEON_LVDS_BL_MOD_LEVEL_SHIFT); 276 if (level != 0) 277 level = ((level - 5) * 2) / 5; 278 279 return (level); 280 } 281 282 static int 283 atibl_suspend(device_t dev) 284 { 285 struct atibl_softc *sc; 286 287 sc = device_get_softc(dev); 288 289 sc->sc_level = atibl_getlevel(sc); 290 atibl_setlevel(sc, 0); 291 292 return (0); 293 } 294 295 static int 296 atibl_resume(device_t dev) 297 { 298 struct atibl_softc *sc; 299 300 sc = device_get_softc(dev); 301 302 atibl_setlevel(sc, sc->sc_level); 303 304 return (0); 305 } 306 307 static int 308 atibl_sysctl(SYSCTL_HANDLER_ARGS) 309 { 310 struct atibl_softc *sc; 311 int newlevel, error; 312 313 sc = arg1; 314 315 newlevel = atibl_getlevel(sc); 316 317 error = sysctl_handle_int(oidp, &newlevel, 0, req); 318 319 if (error || !req->newptr) 320 return (error); 321 322 return (atibl_setlevel(sc, newlevel)); 323 } 324