1/*- 2 * Copyright (c) 2012 Justin Hibbits 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2012 Justin Hibbits 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h>
|
28__FBSDID("$FreeBSD: stable/10/sys/powerpc/powermac/atibl.c 255100 2013-08-31 16:31:48Z jhibbits $");
| 28__FBSDID("$FreeBSD: stable/10/sys/powerpc/powermac/atibl.c 271205 2014-09-06 19:38:40Z jhibbits $");
|
29 30#include <sys/param.h> 31#include <sys/bus.h> 32#include <sys/systm.h> 33#include <sys/module.h> 34#include <sys/kernel.h> 35#include <sys/rman.h> 36#include <sys/sysctl.h> 37 38#include <machine/bus.h> 39 40#include <dev/ofw/openfirm.h> 41 42/* From the xf86-video-ati driver's radeon_reg.h */ 43#define RADEON_LVDS_GEN_CNTL 0x02d0 44#define RADEON_LVDS_ON (1 << 0) 45#define RADEON_LVDS_DISPLAY_DIS (1 << 1) 46#define RADEON_LVDS_PANEL_TYPE (1 << 2) 47#define RADEON_LVDS_PANEL_FORMAT (1 << 3) 48#define RADEON_LVDS_RST_FM (1 << 6) 49#define RADEON_LVDS_EN (1 << 7) 50#define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 51#define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) 52#define RADEON_LVDS_BL_MOD_EN (1 << 16) 53#define RADEON_LVDS_DIGON (1 << 18) 54#define RADEON_LVDS_BLON (1 << 19)
| 29 30#include <sys/param.h> 31#include <sys/bus.h> 32#include <sys/systm.h> 33#include <sys/module.h> 34#include <sys/kernel.h> 35#include <sys/rman.h> 36#include <sys/sysctl.h> 37 38#include <machine/bus.h> 39 40#include <dev/ofw/openfirm.h> 41 42/* From the xf86-video-ati driver's radeon_reg.h */ 43#define RADEON_LVDS_GEN_CNTL 0x02d0 44#define RADEON_LVDS_ON (1 << 0) 45#define RADEON_LVDS_DISPLAY_DIS (1 << 1) 46#define RADEON_LVDS_PANEL_TYPE (1 << 2) 47#define RADEON_LVDS_PANEL_FORMAT (1 << 3) 48#define RADEON_LVDS_RST_FM (1 << 6) 49#define RADEON_LVDS_EN (1 << 7) 50#define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 51#define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) 52#define RADEON_LVDS_BL_MOD_EN (1 << 16) 53#define RADEON_LVDS_DIGON (1 << 18) 54#define RADEON_LVDS_BLON (1 << 19)
|
| 55#define RADEON_LVDS_PLL_CNTL 0x02d4 56#define RADEON_LVDS_PLL_EN (1 << 16) 57#define RADEON_LVDS_PLL_RESET (1 << 17) 58#define RADEON_PIXCLKS_CNTL 0x002d 59#define RADEON_PIXCLK_LVDS_ALWAYS_ONb (1 << 14) 60#define RADEON_DISP_PWR_MAN 0x0d08 61#define RADEON_AUTO_PWRUP_EN (1 << 26) 62#define RADEON_CLOCK_CNTL_DATA 0x000c 63#define RADEON_CLOCK_CNTL_INDEX 0x0008 64#define RADEON_PLL_WR_EN (1 << 7) 65#define RADEON_CRTC_GEN_CNTL 0x0050
|
55 56struct atibl_softc {
| 66 67struct atibl_softc {
|
57 device_t dev;
| |
58 struct resource *sc_memr;
| 68 struct resource *sc_memr;
|
| 69 int sc_level;
|
59}; 60 61static void atibl_identify(driver_t *driver, device_t parent); 62static int atibl_probe(device_t dev); 63static int atibl_attach(device_t dev); 64static int atibl_setlevel(struct atibl_softc *sc, int newlevel); 65static int atibl_getlevel(struct atibl_softc *sc);
| 70}; 71 72static void atibl_identify(driver_t *driver, device_t parent); 73static int atibl_probe(device_t dev); 74static int atibl_attach(device_t dev); 75static int atibl_setlevel(struct atibl_softc *sc, int newlevel); 76static int atibl_getlevel(struct atibl_softc *sc);
|
| 77static int atibl_resume(device_t dev); 78static int atibl_suspend(device_t dev);
|
66static int atibl_sysctl(SYSCTL_HANDLER_ARGS); 67 68static device_method_t atibl_methods[] = { 69 /* Device interface */
| 79static int atibl_sysctl(SYSCTL_HANDLER_ARGS); 80 81static device_method_t atibl_methods[] = { 82 /* Device interface */
|
70 DEVMETHOD(device_identify, atibl_identify), 71 DEVMETHOD(device_probe, atibl_probe), 72 DEVMETHOD(device_attach, atibl_attach),
| 83 DEVMETHOD(device_identify, atibl_identify), 84 DEVMETHOD(device_probe, atibl_probe), 85 DEVMETHOD(device_attach, atibl_attach), 86 DEVMETHOD(device_suspend, atibl_suspend), 87 DEVMETHOD(device_resume, atibl_resume),
|
73 {0, 0}, 74}; 75 76static driver_t atibl_driver = { 77 "backlight", 78 atibl_methods, 79 sizeof(struct atibl_softc) 80}; 81 82static devclass_t atibl_devclass; 83 84DRIVER_MODULE(atibl, vgapci, atibl_driver, atibl_devclass, 0, 0); 85 86static void 87atibl_identify(driver_t *driver, device_t parent) 88{ 89 if (OF_finddevice("mac-io/backlight") == -1) 90 return; 91 if (device_find_child(parent, "backlight", -1) == NULL) 92 device_add_child(parent, "backlight", -1); 93} 94 95static int 96atibl_probe(device_t dev) 97{ 98 char control[8]; 99 phandle_t handle; 100 101 handle = OF_finddevice("mac-io/backlight"); 102 103 if (handle == -1) 104 return (ENXIO); 105 106 if (OF_getprop(handle, "backlight-control", &control, sizeof(control)) < 0) 107 return (ENXIO); 108 109 if (strcmp(control, "ati") != 0) 110 return (ENXIO); 111 112 device_set_desc(dev, "PowerBook backlight for ATI graphics"); 113 114 return (0); 115} 116 117static int 118atibl_attach(device_t dev) 119{ 120 struct atibl_softc *sc; 121 struct sysctl_ctx_list *ctx; 122 struct sysctl_oid *tree; 123 int rid; 124 125 sc = device_get_softc(dev); 126 127 rid = 0x18; /* BAR[2], for the MMIO register */ 128 sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 129 RF_ACTIVE | RF_SHAREABLE); 130 if (sc->sc_memr == NULL) { 131 device_printf(dev, "Could not alloc mem resource!\n"); 132 return (ENXIO); 133 } 134 135 ctx = device_get_sysctl_ctx(dev); 136 tree = device_get_sysctl_tree(dev); 137 138 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
| 88 {0, 0}, 89}; 90 91static driver_t atibl_driver = { 92 "backlight", 93 atibl_methods, 94 sizeof(struct atibl_softc) 95}; 96 97static devclass_t atibl_devclass; 98 99DRIVER_MODULE(atibl, vgapci, atibl_driver, atibl_devclass, 0, 0); 100 101static void 102atibl_identify(driver_t *driver, device_t parent) 103{ 104 if (OF_finddevice("mac-io/backlight") == -1) 105 return; 106 if (device_find_child(parent, "backlight", -1) == NULL) 107 device_add_child(parent, "backlight", -1); 108} 109 110static int 111atibl_probe(device_t dev) 112{ 113 char control[8]; 114 phandle_t handle; 115 116 handle = OF_finddevice("mac-io/backlight"); 117 118 if (handle == -1) 119 return (ENXIO); 120 121 if (OF_getprop(handle, "backlight-control", &control, sizeof(control)) < 0) 122 return (ENXIO); 123 124 if (strcmp(control, "ati") != 0) 125 return (ENXIO); 126 127 device_set_desc(dev, "PowerBook backlight for ATI graphics"); 128 129 return (0); 130} 131 132static int 133atibl_attach(device_t dev) 134{ 135 struct atibl_softc *sc; 136 struct sysctl_ctx_list *ctx; 137 struct sysctl_oid *tree; 138 int rid; 139 140 sc = device_get_softc(dev); 141 142 rid = 0x18; /* BAR[2], for the MMIO register */ 143 sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 144 RF_ACTIVE | RF_SHAREABLE); 145 if (sc->sc_memr == NULL) { 146 device_printf(dev, "Could not alloc mem resource!\n"); 147 return (ENXIO); 148 } 149 150 ctx = device_get_sysctl_ctx(dev); 151 tree = device_get_sysctl_tree(dev); 152 153 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
|
139 "level", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 140 atibl_sysctl, "I", "Backlight level (0-100)");
| 154 "level", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 155 atibl_sysctl, "I", "Backlight level (0-100)");
|
141 142 return (0); 143} 144
| 156 157 return (0); 158} 159
|
| 160static uint32_t __inline 161atibl_pll_rreg(struct atibl_softc *sc, uint32_t reg) 162{ 163 uint32_t data, save, tmp; 164 165 bus_write_1(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, 166 ((reg & 0x3f) | RADEON_PLL_WR_EN)); 167 (void)bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 168 (void)bus_read_4(sc->sc_memr, RADEON_CRTC_GEN_CNTL); 169 170 data = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 171 172 /* Only necessary on R300, bt won't hurt others. */ 173 save = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX); 174 tmp = save & (~0x3f | RADEON_PLL_WR_EN); 175 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, tmp); 176 tmp = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 177 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, save); 178 179 return data; 180} 181 182static void __inline 183atibl_pll_wreg(struct atibl_softc *sc, uint32_t reg, uint32_t val) 184{ 185 uint32_t save, tmp; 186 187 bus_write_1(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, 188 ((reg & 0x3f) | RADEON_PLL_WR_EN)); 189 (void)bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 190 (void)bus_read_4(sc->sc_memr, RADEON_CRTC_GEN_CNTL); 191 192 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA, val); 193 DELAY(5000); 194 195 /* Only necessary on R300, bt won't hurt others. */ 196 save = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX); 197 tmp = save & (~0x3f | RADEON_PLL_WR_EN); 198 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, tmp); 199 tmp = bus_read_4(sc->sc_memr, RADEON_CLOCK_CNTL_DATA); 200 bus_write_4(sc->sc_memr, RADEON_CLOCK_CNTL_INDEX, save); 201} 202
|
145static int 146atibl_setlevel(struct atibl_softc *sc, int newlevel) 147{ 148 uint32_t lvds_gen_cntl;
| 203static int 204atibl_setlevel(struct atibl_softc *sc, int newlevel) 205{ 206 uint32_t lvds_gen_cntl;
|
| 207 uint32_t lvds_pll_cntl; 208 uint32_t pixclks_cntl; 209 uint32_t disp_pwr_reg;
|
149 150 if (newlevel > 100) 151 newlevel = 100; 152 153 if (newlevel < 0) 154 newlevel = 0; 155
| 210 211 if (newlevel > 100) 212 newlevel = 100; 213 214 if (newlevel < 0) 215 newlevel = 0; 216
|
156 newlevel = (newlevel * 5) / 2 + 5;
| |
157 lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL);
| 217 lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL);
|
158 lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; 159 lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_LEVEL_MASK; 160 lvds_gen_cntl |= (newlevel << RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 161 RADEON_LVDS_BL_MOD_LEVEL_MASK; 162 bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
| |
163
| 218
|
| 219 if (newlevel > 0) { 220 newlevel = (newlevel * 5) / 2 + 5; 221 disp_pwr_reg = bus_read_4(sc->sc_memr, RADEON_DISP_PWR_MAN); 222 disp_pwr_reg |= RADEON_AUTO_PWRUP_EN; 223 bus_write_4(sc->sc_memr, RADEON_DISP_PWR_MAN, disp_pwr_reg); 224 lvds_pll_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL); 225 lvds_pll_cntl |= RADEON_LVDS_PLL_EN; 226 bus_write_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 227 lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; 228 bus_write_4(sc->sc_memr, RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); 229 DELAY(1000); 230 231 lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS | 232 RADEON_LVDS_BL_MOD_LEVEL_MASK); 233 lvds_gen_cntl |= RADEON_LVDS_ON | RADEON_LVDS_EN | 234 RADEON_LVDS_DIGON | RADEON_LVDS_BLON; 235 lvds_gen_cntl |= (newlevel << RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 236 RADEON_LVDS_BL_MOD_LEVEL_MASK; 237 lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; 238 DELAY(200000); 239 bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 240 } else { 241 pixclks_cntl = atibl_pll_rreg(sc, RADEON_PIXCLKS_CNTL); 242 atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, 243 pixclks_cntl & ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); 244 lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; 245 lvds_gen_cntl &= ~(RADEON_LVDS_BL_MOD_EN | RADEON_LVDS_BL_MOD_LEVEL_MASK); 246 bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 247 lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN); 248 DELAY(200000); 249 bus_write_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); 250 251 atibl_pll_wreg(sc, RADEON_PIXCLKS_CNTL, pixclks_cntl); 252 DELAY(200000); 253 } 254
|
164 return (0); 165} 166 167static int 168atibl_getlevel(struct atibl_softc *sc) 169{ 170 uint32_t lvds_gen_cntl; 171 int level; 172 173 lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL); 174 175 level = ((lvds_gen_cntl & RADEON_LVDS_BL_MOD_LEVEL_MASK) >>
| 255 return (0); 256} 257 258static int 259atibl_getlevel(struct atibl_softc *sc) 260{ 261 uint32_t lvds_gen_cntl; 262 int level; 263 264 lvds_gen_cntl = bus_read_4(sc->sc_memr, RADEON_LVDS_GEN_CNTL); 265 266 level = ((lvds_gen_cntl & RADEON_LVDS_BL_MOD_LEVEL_MASK) >>
|
176 RADEON_LVDS_BL_MOD_LEVEL_SHIFT); 177 level = ((level - 5) * 2) / 5;
| 267 RADEON_LVDS_BL_MOD_LEVEL_SHIFT); 268 if (level != 0) 269 level = ((level - 5) * 2) / 5;
|
178 179 return (level); 180} 181 182static int
| 270 271 return (level); 272} 273 274static int
|
| 275atibl_suspend(device_t dev) 276{ 277 struct atibl_softc *sc; 278 279 sc = device_get_softc(dev); 280 281 sc->sc_level = atibl_getlevel(sc); 282 atibl_setlevel(sc, 0); 283 284 return (0); 285} 286 287static int 288atibl_resume(device_t dev) 289{ 290 struct atibl_softc *sc; 291 292 sc = device_get_softc(dev); 293 294 atibl_setlevel(sc, sc->sc_level); 295 296 return (0); 297} 298 299static int
|
183atibl_sysctl(SYSCTL_HANDLER_ARGS) 184{ 185 struct atibl_softc *sc; 186 int newlevel, error; 187 188 sc = arg1; 189 190 newlevel = atibl_getlevel(sc); 191 192 error = sysctl_handle_int(oidp, &newlevel, 0, req); 193 194 if (error || !req->newptr) 195 return (error); 196 197 return (atibl_setlevel(sc, newlevel)); 198}
| 300atibl_sysctl(SYSCTL_HANDLER_ARGS) 301{ 302 struct atibl_softc *sc; 303 int newlevel, error; 304 305 sc = arg1; 306 307 newlevel = atibl_getlevel(sc); 308 309 error = sysctl_handle_int(oidp, &newlevel, 0, req); 310 311 if (error || !req->newptr) 312 return (error); 313 314 return (atibl_setlevel(sc, newlevel)); 315}
|